Source code of MARS Assembler
First commit of the 4.5 version (latest version available)
This commit is contained in:
@@ -0,0 +1,169 @@
|
||||
package mars.mips.instructions;
|
||||
import mars.mips.instructions.syscalls.*;
|
||||
import mars.*;
|
||||
import mars.util.*;
|
||||
import java.util.*;
|
||||
|
||||
/*
|
||||
Copyright (c) 2003-2006, Pete Sanderson and Kenneth Vollmar
|
||||
|
||||
Developed by Pete Sanderson (psanderson@otterbein.edu)
|
||||
and Kenneth Vollmar (kenvollmar@missouristate.edu)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject
|
||||
to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
(MIT license, http://www.opensource.org/licenses/mit-license.html)
|
||||
*/
|
||||
|
||||
|
||||
/****************************************************************************/
|
||||
/* This class provides functionality to bring external Syscall definitions
|
||||
* into MARS. This permits anyone with knowledge of the Mars public interfaces,
|
||||
* in particular of the Memory and Register classes, to write custom MIPS syscall
|
||||
* functions. This is adapted from the ToolLoader class, which is in turn adapted
|
||||
* from Bret Barker's GameServer class from the book "Developing Games In Java".
|
||||
*/
|
||||
|
||||
class SyscallLoader {
|
||||
|
||||
private static final String CLASS_PREFIX = "mars.mips.instructions.syscalls.";
|
||||
private static final String SYSCALLS_DIRECTORY_PATH = "mars/mips/instructions/syscalls";
|
||||
private static final String SYSCALL_INTERFACE = "Syscall.class";
|
||||
private static final String SYSCALL_ABSTRACT = "AbstractSyscall.class";
|
||||
private static final String CLASS_EXTENSION = "class";
|
||||
|
||||
private ArrayList syscallList;
|
||||
|
||||
/*
|
||||
* Dynamically loads Syscalls into an ArrayList. This method is adapted from
|
||||
* the loadGameControllers() method in Bret Barker's GameServer class.
|
||||
* Barker (bret@hypefiend.com) is co-author of the book "Developing Games
|
||||
* in Java". Also see the "loadMarsTools()" method from ToolLoader class.
|
||||
*/
|
||||
void loadSyscalls() {
|
||||
syscallList = new ArrayList();
|
||||
// grab all class files in the same directory as Syscall
|
||||
ArrayList candidates = FilenameFinder.getFilenameList(this.getClass( ).getClassLoader(),
|
||||
SYSCALLS_DIRECTORY_PATH, CLASS_EXTENSION);
|
||||
HashMap syscalls = new HashMap();
|
||||
for( int i = 0; i < candidates.size(); i++) {
|
||||
String file = (String) candidates.get(i);
|
||||
// Do not add class if already encountered (happens if run in MARS development directory)
|
||||
if (syscalls.containsKey(file)) {
|
||||
continue;
|
||||
} else {
|
||||
syscalls.put(file,file);
|
||||
}
|
||||
if ((!file.equals(SYSCALL_INTERFACE)) &&
|
||||
(!file.equals(SYSCALL_ABSTRACT)) ) {
|
||||
try {
|
||||
// grab the class, make sure it implements Syscall, instantiate, add to list
|
||||
String syscallClassName = CLASS_PREFIX+file.substring(0, file.indexOf(CLASS_EXTENSION)-1);
|
||||
Class clas = Class.forName(syscallClassName);
|
||||
if (!Syscall.class.isAssignableFrom(clas)) {
|
||||
continue;
|
||||
}
|
||||
Syscall syscall = (Syscall) clas.newInstance();
|
||||
if (findSyscall(syscall.getNumber()) == null) {
|
||||
syscallList.add(syscall);
|
||||
}
|
||||
else {
|
||||
throw new Exception("Duplicate service number: "+syscall.getNumber()+
|
||||
" already registered to "+
|
||||
findSyscall(syscall.getNumber()).getName());
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
System.out.println("Error instantiating Syscall from file " + file + ": "+e);
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
syscallList = processSyscallNumberOverrides(syscallList);
|
||||
return;
|
||||
}
|
||||
|
||||
// Will get any syscall number override specifications from MARS config file and
|
||||
// process them. This will alter syscallList entry for affected names.
|
||||
private ArrayList processSyscallNumberOverrides(ArrayList syscallList) {
|
||||
ArrayList overrides = new Globals().getSyscallOverrides();
|
||||
SyscallNumberOverride override;
|
||||
Syscall syscall;
|
||||
for (int index=0; index < overrides.size(); index++) {
|
||||
override = (SyscallNumberOverride) overrides.get(index);
|
||||
boolean match = false;
|
||||
for (int i=0; i < syscallList.size(); i++) {
|
||||
syscall = (Syscall) syscallList.get(i);
|
||||
if (override.getName().equals(syscall.getName())) {
|
||||
// we have a match to service name, assign new number
|
||||
syscall.setNumber(override.getNumber());
|
||||
match = true;
|
||||
}
|
||||
}
|
||||
if (!match) {
|
||||
System.out.println("Error: syscall name '"+override.getName()+
|
||||
"' in config file does not match any name in syscall list");
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
// Wait until end to check for duplicate numbers. To do so earlier
|
||||
// would disallow for instance the exchange of numbers between two
|
||||
// services. This is N-squared operation but N is small.
|
||||
// This will also detect duplicates that accidently occur from addition
|
||||
// of a new Syscall subclass to the collection, even if the config file
|
||||
// does not contain any overrides.
|
||||
Syscall syscallA, syscallB;
|
||||
boolean duplicates = false;
|
||||
for (int i = 0; i < syscallList.size(); i++) {
|
||||
syscallA = (Syscall)syscallList.get(i);
|
||||
for (int j = i+1; j < syscallList.size(); j++) {
|
||||
syscallB = (Syscall)syscallList.get(j);
|
||||
if ( syscallA.getNumber() == syscallB.getNumber()) {
|
||||
System.out.println("Error: syscalls "+syscallA.getName()+" and "+
|
||||
syscallB.getName()+" are both assigned same number "+syscallA.getNumber());
|
||||
duplicates = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (duplicates) {
|
||||
System.exit(0);
|
||||
}
|
||||
return syscallList;
|
||||
}
|
||||
|
||||
/*
|
||||
* Method to find Syscall object associated with given service number.
|
||||
* Returns null if no associated object found.
|
||||
*/
|
||||
Syscall findSyscall(int number) {
|
||||
// linear search is OK since number of syscalls is small.
|
||||
Syscall service, match = null;
|
||||
if (syscallList==null) {
|
||||
loadSyscalls();
|
||||
}
|
||||
for (int index=0; index < syscallList.size(); index++) {
|
||||
service = (Syscall) syscallList.get(index);
|
||||
if (service.getNumber() == number) {
|
||||
match = service;
|
||||
}
|
||||
}
|
||||
return match;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user