Source code of MARS Assembler
First commit of the 4.5 version (latest version available)
This commit is contained in:
Binary file not shown.
@@ -0,0 +1,198 @@
|
||||
package mars;
|
||||
import java.util.*;
|
||||
import java.io.*;
|
||||
/*
|
||||
Copyright (c) 2003-2012, 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)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Maintains list of generated error messages, regardless of source (tokenizing, parsing,
|
||||
* assembly, execution).
|
||||
*
|
||||
* @author Pete Sanderson
|
||||
* @version August 2003
|
||||
**/
|
||||
|
||||
public class ErrorList {
|
||||
private ArrayList messages;
|
||||
private int errorCount;
|
||||
private int warningCount;
|
||||
public static final String ERROR_MESSAGE_PREFIX = "Error";
|
||||
public static final String WARNING_MESSAGE_PREFIX = "Warning";
|
||||
public static final String FILENAME_PREFIX = " in ";
|
||||
public static final String LINE_PREFIX = " line ";
|
||||
public static final String POSITION_PREFIX = " column ";
|
||||
public static final String MESSAGE_SEPARATOR = ": ";
|
||||
|
||||
|
||||
/**
|
||||
* Constructor for ErrorList
|
||||
**/
|
||||
|
||||
public ErrorList() {
|
||||
messages = new ArrayList();
|
||||
errorCount = 0;
|
||||
warningCount = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get ArrayList of error messages.
|
||||
* @return ArrayList of ErrorMessage objects
|
||||
*/
|
||||
public ArrayList getErrorMessages() {
|
||||
return messages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether error has occured or not.
|
||||
* @return <tt>true</tt> if an error has occurred (does not include warnings), <tt>false</tt> otherwise.
|
||||
**/
|
||||
public boolean errorsOccurred() {
|
||||
return (errorCount != 0 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether warning has occured or not.
|
||||
* @return <tt>true</tt> if an warning has occurred, <tt>false</tt> otherwise.
|
||||
**/
|
||||
public boolean warningsOccurred() {
|
||||
return (warningCount != 0 );
|
||||
}
|
||||
|
||||
/** Add new error message to end of list.
|
||||
* @param mess ErrorMessage object to be added to end of error list.
|
||||
**/
|
||||
public void add(ErrorMessage mess){
|
||||
add(mess, messages.size());
|
||||
}
|
||||
|
||||
/** Add new error message at specified index position.
|
||||
* @param mess ErrorMessage object to be added to end of error list.
|
||||
* @param index position in error list
|
||||
**/
|
||||
public void add(ErrorMessage mess, int index) {
|
||||
if (errorCount > getErrorLimit()) {
|
||||
return;
|
||||
}
|
||||
if (errorCount == getErrorLimit()) {
|
||||
messages.add(new ErrorMessage((MIPSprogram)null, mess.getLine(), mess.getPosition(),"Error Limit of "+getErrorLimit()+" exceeded."));
|
||||
errorCount++; // subsequent errors will not be added; see if statement above
|
||||
return;
|
||||
}
|
||||
messages.add(index, mess);
|
||||
if (mess.isWarning()) {
|
||||
warningCount++;
|
||||
}
|
||||
else {
|
||||
errorCount++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Count of number of error messages in list.
|
||||
* @return Number of error messages in list.
|
||||
**/
|
||||
|
||||
public int errorCount() {
|
||||
return this.errorCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Count of number of warning messages in list.
|
||||
* @return Number of warning messages in list.
|
||||
**/
|
||||
|
||||
public int warningCount() {
|
||||
return this.warningCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see if error limit has been exceeded.
|
||||
* @return True if error limit exceeded, false otherwise.
|
||||
**/
|
||||
|
||||
public boolean errorLimitExceeded() {
|
||||
return this.errorCount > getErrorLimit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get limit on number of error messages to be generated
|
||||
* by one assemble operation.
|
||||
* @return error limit.
|
||||
**/
|
||||
|
||||
public int getErrorLimit() {
|
||||
return Globals.maximumErrorMessages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Produce error report.
|
||||
* @return String containing report.
|
||||
**/
|
||||
public String generateErrorReport() {
|
||||
return generateReport(ErrorMessage.ERROR);
|
||||
}
|
||||
|
||||
/**
|
||||
* Produce warning report.
|
||||
* @return String containing report.
|
||||
**/
|
||||
public String generateWarningReport() {
|
||||
return generateReport(ErrorMessage.WARNING);
|
||||
}
|
||||
|
||||
/**
|
||||
* Produce report containing both warnings and errors, warnings first.
|
||||
* @return String containing report.
|
||||
**/
|
||||
public String generateErrorAndWarningReport() {
|
||||
return generateWarningReport()+generateErrorReport();
|
||||
}
|
||||
|
||||
// Produces either error or warning report.
|
||||
private String generateReport(boolean isWarning) {
|
||||
StringBuffer report = new StringBuffer("");
|
||||
String reportLine;
|
||||
for (int i = 0; i < messages.size(); i++) {
|
||||
ErrorMessage m = (ErrorMessage) messages.get(i);
|
||||
if ((isWarning && m.isWarning()) || (!isWarning && !m.isWarning())) {
|
||||
reportLine = ((isWarning) ? WARNING_MESSAGE_PREFIX : ERROR_MESSAGE_PREFIX) + FILENAME_PREFIX;
|
||||
if (m.getFilename().length() > 0)
|
||||
reportLine = reportLine + (new File(m.getFilename()).getPath()); //.getName());
|
||||
if (m.getLine() > 0)
|
||||
reportLine = reportLine + LINE_PREFIX +m.getMacroExpansionHistory()+ m.getLine();
|
||||
if (m.getPosition() > 0)
|
||||
reportLine = reportLine + POSITION_PREFIX + m.getPosition();
|
||||
reportLine = reportLine + MESSAGE_SEPARATOR + m.getMessage() + "\n";
|
||||
report.append(reportLine);
|
||||
}
|
||||
}
|
||||
return report.toString();
|
||||
}
|
||||
} // ErrorList
|
||||
|
||||
Binary file not shown.
@@ -0,0 +1,285 @@
|
||||
package mars;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.ArrayList;
|
||||
/*
|
||||
Copyright (c) 2003-2012, 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)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Represents occurrance of an error detected during tokenizing, assembly or simulation.
|
||||
* @author Pete Sanderson
|
||||
* @version August 2003
|
||||
**/
|
||||
|
||||
public class ErrorMessage {
|
||||
private boolean isWarning; // allow for warnings too (added Nov 2006)
|
||||
private String filename; // name of source file (added Oct 2006)
|
||||
private int line; // line in source code where error detected
|
||||
private int position; // position in source line where error detected
|
||||
private String message;
|
||||
private String macroExpansionHistory;
|
||||
|
||||
/**
|
||||
* Constant to indicate this message is warning not error
|
||||
*/
|
||||
public static final boolean WARNING = true;
|
||||
|
||||
/**
|
||||
* Constant to indicate this message is error not warning
|
||||
*/
|
||||
public static final boolean ERROR = false;
|
||||
|
||||
/**
|
||||
* Constructor for ErrorMessage.
|
||||
* @param filename String containing name of source file in which this error appears.
|
||||
* @param line Line number in source program being processed when error occurred.
|
||||
* @param position Position within line being processed when error occurred. Normally is starting
|
||||
* position of source token.
|
||||
* @param message String containing appropriate error message.
|
||||
* @deprecated Newer constructors replace the String filename parameter with a MIPSprogram parameter to provide more information.
|
||||
**/
|
||||
// Added filename October 2006
|
||||
@Deprecated
|
||||
public ErrorMessage(String filename, int line, int position, String message) {
|
||||
this(ERROR, filename, line, position, message, "");
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for ErrorMessage.
|
||||
* @param filename String containing name of source file in which this error appears.
|
||||
* @param line Line number in source program being processed when error occurred.
|
||||
* @param position Position within line being processed when error occurred. Normally is starting
|
||||
* position of source token.
|
||||
* @param message String containing appropriate error message.
|
||||
* @param macroExpansionHistory
|
||||
* @deprecated Newer constructors replace the String filename parameter with a MIPSprogram parameter to provide more information.
|
||||
**/
|
||||
// Added macroExpansionHistory Dec 2012
|
||||
|
||||
@Deprecated
|
||||
public ErrorMessage(String filename, int line, int position, String message, String macroExpansionHistory) {
|
||||
this(ERROR, filename, line, position, message, macroExpansionHistory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for ErrorMessage.
|
||||
* @param isWarning set to WARNING if message is a warning not error, else set to ERROR or omit.
|
||||
* @param filename String containing name of source file in which this error appears.
|
||||
* @param line Line number in source program being processed when error occurred.
|
||||
* @param position Position within line being processed when error occurred. Normally is starting
|
||||
* position of source token.
|
||||
* @param message String containing appropriate error message.
|
||||
* @param macroExpansionHistory provided so message for macro can include both definition and usage line numbers
|
||||
* @deprecated Newer constructors replace the String filename parameter with a MIPSprogram parameter to provide more information.
|
||||
**/
|
||||
@Deprecated
|
||||
public ErrorMessage(boolean isWarning, String filename, int line, int position, String message, String macroExpansionHistory) {
|
||||
this.isWarning = isWarning;
|
||||
this.filename = filename;
|
||||
this.line = line;
|
||||
this.position = position;
|
||||
this.message = message;
|
||||
this.macroExpansionHistory=macroExpansionHistory;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Constructor for ErrorMessage. Assumes line number is calculated after any .include files expanded, and
|
||||
* if there were, it will adjust filename and line number so message reflects original file and line number.
|
||||
* @param sourceMIPSprogram MIPSprogram object of source file in which this error appears.
|
||||
* @param line Line number in source program being processed when error occurred.
|
||||
* @param position Position within line being processed when error occurred. Normally is starting
|
||||
* position of source token.
|
||||
* @param message String containing appropriate error message.
|
||||
**/
|
||||
|
||||
public ErrorMessage(MIPSprogram sourceMIPSprogram, int line, int position, String message) {
|
||||
this(ERROR, sourceMIPSprogram, line, position, message);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Constructor for ErrorMessage. Assumes line number is calculated after any .include files expanded, and
|
||||
* if there were, it will adjust filename and line number so message reflects original file and line number.
|
||||
* @param isWarning set to WARNING if message is a warning not error, else set to ERROR or omit.
|
||||
* @param sourceMIPSprogram MIPSprogram object of source file in which this error appears.
|
||||
* @param line Line number in source program being processed when error occurred.
|
||||
* @param position Position within line being processed when error occurred. Normally is starting
|
||||
* position of source token.
|
||||
* @param message String containing appropriate error message.
|
||||
**/
|
||||
|
||||
public ErrorMessage(boolean isWarning, MIPSprogram sourceMIPSprogram, int line, int position, String message) {
|
||||
this.isWarning = isWarning;
|
||||
if (sourceMIPSprogram == null) {
|
||||
this.filename = "";
|
||||
this.line = line;
|
||||
}
|
||||
else {
|
||||
if (sourceMIPSprogram.getSourceLineList() == null) {
|
||||
this.filename = sourceMIPSprogram.getFilename();
|
||||
this.line = line;
|
||||
}
|
||||
else {
|
||||
mars.assembler.SourceLine sourceLine = sourceMIPSprogram.getSourceLineList().get(line-1);
|
||||
this.filename = sourceLine.getFilename();
|
||||
this.line = sourceLine.getLineNumber();
|
||||
}
|
||||
}
|
||||
this.position = position;
|
||||
this.message = message;
|
||||
this.macroExpansionHistory = getExpansionHistory(sourceMIPSprogram);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for ErrorMessage, to be used for runtime exceptions.
|
||||
* @param statement The ProgramStatement object for the instruction causing the runtime error
|
||||
* @param message String containing appropriate error message.
|
||||
**/
|
||||
// Added January 2013
|
||||
|
||||
public ErrorMessage(ProgramStatement statement, String message) {
|
||||
this.isWarning = ERROR;
|
||||
this.filename = (statement.getSourceMIPSprogram() == null)
|
||||
? "" : statement.getSourceMIPSprogram().getFilename();
|
||||
this.position = 0;
|
||||
this.message = message;
|
||||
// Somewhere along the way we lose the macro history, but can
|
||||
// normally recreate it here. The line number for macro use (in the
|
||||
// expansion) comes with the ProgramStatement.getSourceLine().
|
||||
// The line number for the macro definition comes embedded in
|
||||
// the source code from ProgramStatement.getSource(), which is
|
||||
// displayed in the Text Segment display. It would previously
|
||||
// have had the macro definition line prepended in brackets,
|
||||
// e.g. "<13> syscall # finished". So I'll extract that
|
||||
// bracketed number here and include it in the error message.
|
||||
// Looks bass-ackwards, but to get the line numbers to display correctly
|
||||
// for runtime error occurring in macro expansion (expansion->definition), need
|
||||
// to assign to the opposite variables.
|
||||
ArrayList<Integer> defineLine = parseMacroHistory(statement.getSource());
|
||||
if (defineLine.size() == 0) {
|
||||
this.line = statement.getSourceLine();
|
||||
this.macroExpansionHistory = "";
|
||||
}
|
||||
else {
|
||||
this.line = defineLine.get(0);
|
||||
this.macroExpansionHistory = ""+statement.getSourceLine();
|
||||
}
|
||||
}
|
||||
|
||||
private ArrayList<Integer> parseMacroHistory(String string) {
|
||||
Pattern pattern = Pattern.compile("<\\d+>");
|
||||
Matcher matcher = pattern.matcher(string);
|
||||
String verify = new String(string).trim();
|
||||
ArrayList<Integer> macroHistory = new ArrayList<Integer>();
|
||||
while (matcher.find()) {
|
||||
String match = matcher.group();
|
||||
if (verify.indexOf(match)==0) {
|
||||
try {
|
||||
int line = Integer.parseInt(match.substring(1,match.length()-1));
|
||||
macroHistory.add(line);
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
break;
|
||||
}
|
||||
verify = verify.substring(match.length()).trim();
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return macroHistory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Produce name of file containing error.
|
||||
* @return Returns String containing name of source file containing the error.
|
||||
*/
|
||||
// Added October 2006
|
||||
|
||||
public String getFilename() {
|
||||
return filename;
|
||||
}
|
||||
|
||||
/**
|
||||
* Produce line number of error.
|
||||
* @return Returns line number in source program where error occurred.
|
||||
*/
|
||||
|
||||
public int getLine() {
|
||||
return line;
|
||||
}
|
||||
|
||||
/**
|
||||
* Produce position within erroneous line.
|
||||
* @return Returns position within line of source program where error occurred.
|
||||
*/
|
||||
|
||||
public int getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
/**
|
||||
* Produce error message.
|
||||
* @return Returns String containing textual error message.
|
||||
*/
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether this message represents error or warning.
|
||||
* @return Returns true if this message reflects warning, false if error.
|
||||
*/
|
||||
// Method added 28 Nov 2006
|
||||
public boolean isWarning() {
|
||||
return this.isWarning;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns string describing macro expansion. Empty string if none.
|
||||
* @return string describing macro expansion
|
||||
*/
|
||||
// Method added by Mohammad Sekavat Dec 2012
|
||||
|
||||
public String getMacroExpansionHistory() {
|
||||
if (macroExpansionHistory==null || macroExpansionHistory.length()==0)
|
||||
return "";
|
||||
return macroExpansionHistory+"->";
|
||||
}
|
||||
|
||||
// Added by Mohammad Sekavat Dec 2012
|
||||
private static String getExpansionHistory(MIPSprogram sourceMIPSprogram) {
|
||||
if (sourceMIPSprogram==null || sourceMIPSprogram.getLocalMacroPool()==null)
|
||||
return "";
|
||||
return sourceMIPSprogram.getLocalMacroPool().getExpansionHistory();
|
||||
}
|
||||
|
||||
} // ErrorMessage
|
||||
Binary file not shown.
@@ -0,0 +1,249 @@
|
||||
package mars;
|
||||
import mars.mips.instructions.syscalls.*;
|
||||
import mars.mips.instructions.*;
|
||||
import mars.mips.hardware.*;
|
||||
import mars.assembler.*;
|
||||
import mars.venus.*;
|
||||
import mars.util.*;
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
/*
|
||||
Copyright (c) 2003-2008, 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)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Collection of globally-available data structures.
|
||||
*
|
||||
* @author Pete Sanderson
|
||||
* @version August 2003
|
||||
*/
|
||||
public class Globals
|
||||
{
|
||||
// List these first because they are referenced by methods called at initialization.
|
||||
private static String configPropertiesFile = "Config";
|
||||
private static String syscallPropertiesFile = "Syscall";
|
||||
|
||||
/** The set of implemented MIPS instructions. **/
|
||||
public static InstructionSet instructionSet;
|
||||
/** the program currently being worked with. Used by GUI only, not command line. **/
|
||||
public static MIPSprogram program;
|
||||
/** Symbol table for file currently being assembled. **/
|
||||
public static SymbolTable symbolTable;
|
||||
/** Simulated MIPS memory component. **/
|
||||
public static Memory memory;
|
||||
/** Lock variable used at head of synchronized block to guard MIPS memory and registers **/
|
||||
public static Object memoryAndRegistersLock = new Object();
|
||||
/** Flag to determine whether or not to produce internal debugging information. **/
|
||||
public static boolean debug = false;
|
||||
/** Object that contains various settings that can be accessed modified internally. **/
|
||||
static Settings settings;
|
||||
/** String to GUI's RunI/O text area when echoing user input from pop-up dialog. */
|
||||
public static String userInputAlert = "**** user input : ";
|
||||
/** Path to folder that contains images */
|
||||
// The leading "/" in filepath prevents package name from being pre-pended.
|
||||
public static final String imagesPath = "/images/";
|
||||
/** Path to folder that contains help text */
|
||||
public static final String helpPath = "/help/";
|
||||
/* Flag that indicates whether or not instructionSet has been initialized. */
|
||||
private static boolean initialized = false;
|
||||
/* The GUI being used (if any) with this simulator. */
|
||||
static VenusUI gui = null;
|
||||
/** The current MARS version number. Can't wait for "initialize()" call to get it. */
|
||||
public static final String version = "4.5";
|
||||
/** List of accepted file extensions for MIPS assembly source files. */
|
||||
public static final ArrayList fileExtensions = getFileExtensions();
|
||||
/** Maximum length of scrolled message window (MARS Messages and Run I/O) */
|
||||
public static final int maximumMessageCharacters = getMessageLimit();
|
||||
/** Maximum number of assembler errors produced by one assemble operation */
|
||||
public static final int maximumErrorMessages = getErrorLimit();
|
||||
/** Maximum number of back-step operations to buffer */
|
||||
public static final int maximumBacksteps = getBackstepLimit();
|
||||
/** MARS copyright years */
|
||||
public static final String copyrightYears = getCopyrightYears();
|
||||
/** MARS copyright holders */
|
||||
public static final String copyrightHolders = getCopyrightHolders();
|
||||
/** Placeholder for non-printable ASCII codes */
|
||||
public static final String ASCII_NON_PRINT = getAsciiNonPrint();
|
||||
/** Array of strings to display for ASCII codes in ASCII display of data segment. ASCII code 0-255 is array index. */
|
||||
public static final String[] ASCII_TABLE = getAsciiStrings();
|
||||
/** MARS exit code -- useful with SYSCALL 17 when running from command line (not GUI) */
|
||||
public static int exitCode = 0;
|
||||
|
||||
public static boolean runSpeedPanelExists = false;
|
||||
|
||||
private static String getCopyrightYears() {
|
||||
return "2003-2014";
|
||||
}
|
||||
private static String getCopyrightHolders() {
|
||||
return "Pete Sanderson and Kenneth Vollmar";
|
||||
}
|
||||
|
||||
public static void setGui(VenusUI g) {
|
||||
gui = g;
|
||||
}
|
||||
public static VenusUI getGui() {
|
||||
return gui;
|
||||
}
|
||||
|
||||
public static Settings getSettings() {
|
||||
return settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method called once upon system initialization to create the global data structures.
|
||||
**/
|
||||
|
||||
public static void initialize(boolean gui) {
|
||||
if (!initialized) {
|
||||
memory = Memory.getInstance(); //clients can use Memory.getInstance instead of Globals.memory
|
||||
instructionSet = new InstructionSet();
|
||||
instructionSet.populate();
|
||||
symbolTable = new SymbolTable("global");
|
||||
settings = new Settings(gui);
|
||||
initialized = true;
|
||||
debug = false;
|
||||
memory.clear(); // will establish memory configuration from setting
|
||||
}
|
||||
}
|
||||
|
||||
// Read byte limit of Run I/O or MARS Messages text to buffer.
|
||||
private static int getMessageLimit() {
|
||||
return getIntegerProperty(configPropertiesFile, "MessageLimit", 1000000);
|
||||
}
|
||||
|
||||
// Read limit on number of error messages produced by one assemble operation.
|
||||
private static int getErrorLimit() {
|
||||
return getIntegerProperty(configPropertiesFile, "ErrorLimit", 200);
|
||||
}
|
||||
|
||||
// Read backstep limit (number of operations to buffer) from properties file.
|
||||
private static int getBackstepLimit() {
|
||||
return getIntegerProperty(configPropertiesFile, "BackstepLimit", 1000);
|
||||
}
|
||||
|
||||
// Read ASCII default display character for non-printing characters, from properties file.
|
||||
public static String getAsciiNonPrint() {
|
||||
String anp = getPropertyEntry(configPropertiesFile, "AsciiNonPrint");
|
||||
return (anp == null) ? "." : ( (anp.equals("space")) ? " " : anp );
|
||||
}
|
||||
|
||||
// Read ASCII strings for codes 0-255, from properties file. If string
|
||||
// value is "null", substitute value of ASCII_NON_PRINT. If string is
|
||||
// "space", substitute string containing one space character.
|
||||
public static String[] getAsciiStrings() {
|
||||
String let = getPropertyEntry(configPropertiesFile,"AsciiTable");
|
||||
String placeHolder = getAsciiNonPrint();
|
||||
String[] lets = let.split(" +");
|
||||
int maxLength = 0;
|
||||
for (int i = 0; i < lets.length; i++) {
|
||||
if (lets[i].equals("null")) lets[i] = placeHolder;
|
||||
if (lets[i].equals("space")) lets[i] = " ";
|
||||
if (lets[i].length() > maxLength) maxLength = lets[i].length();
|
||||
}
|
||||
String padding = " ";
|
||||
maxLength++;
|
||||
for (int i = 0; i < lets.length; i++) {
|
||||
lets[i] = padding.substring(0,maxLength-lets[i].length()) + lets[i];
|
||||
}
|
||||
return lets;
|
||||
}
|
||||
|
||||
// Read and return integer property value for given file and property name.
|
||||
// Default value is returned if property file or name not found.
|
||||
private static int getIntegerProperty(String propertiesFile, String propertyName, int defaultValue) {
|
||||
int limit = defaultValue; // just in case no entry is found
|
||||
Properties properties = PropertiesFile.loadPropertiesFromFile(propertiesFile);
|
||||
try {
|
||||
limit = Integer.parseInt(properties.getProperty(propertyName, Integer.toString(defaultValue)));
|
||||
}
|
||||
catch (NumberFormatException nfe) { } // do nothing, I already have a default
|
||||
return limit;
|
||||
}
|
||||
|
||||
|
||||
// Read assembly language file extensions from properties file. Resulting
|
||||
// string is tokenized into array list (assume StringTokenizer default delimiters).
|
||||
private static ArrayList getFileExtensions() {
|
||||
ArrayList extensionsList = new ArrayList();
|
||||
String extensions = getPropertyEntry(configPropertiesFile,"Extensions");
|
||||
if (extensions != null) {
|
||||
StringTokenizer st = new StringTokenizer(extensions);
|
||||
while (st.hasMoreTokens()) {
|
||||
extensionsList.add(st.nextToken());
|
||||
}
|
||||
}
|
||||
return extensionsList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get list of MarsTools that reside outside the MARS distribution.
|
||||
* Currently this is done by adding the tool's path name to the list
|
||||
* of values for the external_tools property. Use ";" as delimiter!
|
||||
* @return ArrayList. Each item is file path to .class file
|
||||
* of a class that implements MarsTool. If none, returns empty list.
|
||||
*/
|
||||
public static ArrayList getExternalTools() {
|
||||
ArrayList toolsList = new ArrayList();
|
||||
String delimiter = ";";
|
||||
String tools = getPropertyEntry(configPropertiesFile,"ExternalTools");
|
||||
if (tools != null) {
|
||||
StringTokenizer st = new StringTokenizer(tools, delimiter);
|
||||
while (st.hasMoreTokens()) {
|
||||
toolsList.add(st.nextToken());
|
||||
}
|
||||
}
|
||||
return toolsList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read and return property file value (if any) for requested property.
|
||||
* @param propertiesFile name of properties file (do NOT include filename extension,
|
||||
* which is assumed to be ".properties")
|
||||
* @param propertyName String containing desired property name
|
||||
* @return String containing associated value; null if property not found
|
||||
*/
|
||||
public static String getPropertyEntry(String propertiesFile, String propertyName) {
|
||||
return PropertiesFile.loadPropertiesFromFile(propertiesFile).getProperty(propertyName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read any syscall number assignment overrides from config file.
|
||||
* @return ArrayList of SyscallNumberOverride objects
|
||||
*/
|
||||
public ArrayList getSyscallOverrides() {
|
||||
ArrayList overrides = new ArrayList();
|
||||
Properties properties = PropertiesFile.loadPropertiesFromFile(syscallPropertiesFile);
|
||||
Enumeration keys = properties.keys();
|
||||
while (keys.hasMoreElements()) {
|
||||
String key = (String) keys.nextElement();
|
||||
overrides.add(new SyscallNumberOverride(key,properties.getProperty(key)));
|
||||
}
|
||||
return overrides;
|
||||
}
|
||||
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,422 @@
|
||||
package mars;
|
||||
|
||||
import mars.venus.*;
|
||||
import mars.assembler.*;
|
||||
import mars.simulator.*;
|
||||
import mars.mips.hardware.*;
|
||||
|
||||
import java.util.*;
|
||||
import java.io.*;
|
||||
import java.awt.event.*;
|
||||
import javax.swing.*;
|
||||
|
||||
/*
|
||||
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)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Internal representations of MIPS program. Connects source, tokens and machine code. Having
|
||||
* all these structures available facilitates construction of good messages,
|
||||
* debugging, and easy simulation.
|
||||
*
|
||||
* @author Pete Sanderson
|
||||
* @version August 2003
|
||||
**/
|
||||
|
||||
public class MIPSprogram {
|
||||
|
||||
// See explanation of method inSteppedExecution() below.
|
||||
private boolean steppedExecution = false;
|
||||
|
||||
private String filename;
|
||||
private ArrayList sourceList;
|
||||
private ArrayList tokenList;
|
||||
private ArrayList parsedList;
|
||||
private ArrayList machineList;
|
||||
private BackStepper backStepper;
|
||||
private SymbolTable localSymbolTable;
|
||||
private MacroPool macroPool;
|
||||
private ArrayList<SourceLine> sourceLineList;
|
||||
private Tokenizer tokenizer;
|
||||
|
||||
/**
|
||||
* Produces list of source statements that comprise the program.
|
||||
* @return ArrayList of String. Each String is one line of MIPS source code.
|
||||
**/
|
||||
|
||||
public ArrayList getSourceList() {
|
||||
return sourceList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set list of source statements that comprise the program.
|
||||
* @param sourceLineList ArrayList of SourceLine.
|
||||
* Each SourceLine represents one line of MIPS source code.
|
||||
**/
|
||||
|
||||
public void setSourceLineList(ArrayList<SourceLine> sourceLineList) {
|
||||
this.sourceLineList = sourceLineList;
|
||||
sourceList = new ArrayList();
|
||||
for (SourceLine sl : sourceLineList) {
|
||||
sourceList.add(sl.getSource());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve list of source statements that comprise the program.
|
||||
* @return ArrayList of SourceLine.
|
||||
* Each SourceLine represents one line of MIPS source cod
|
||||
**/
|
||||
|
||||
public ArrayList<SourceLine> getSourceLineList() {
|
||||
return this.sourceLineList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Produces name of associated source code file.
|
||||
* @return File name as String.
|
||||
**/
|
||||
|
||||
public String getFilename() {
|
||||
return filename;
|
||||
}
|
||||
|
||||
/**
|
||||
* Produces list of tokens that comprise the program.
|
||||
* @return ArrayList of TokenList. Each TokenList is list of tokens generated by
|
||||
* corresponding line of MIPS source code.
|
||||
* @see TokenList
|
||||
**/
|
||||
|
||||
public ArrayList getTokenList() {
|
||||
return tokenList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves Tokenizer for this program
|
||||
* @return Tokenizer
|
||||
**/
|
||||
|
||||
public Tokenizer getTokenizer() {
|
||||
return tokenizer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Produces new empty list to hold parsed source code statements.
|
||||
* @return ArrayList of ProgramStatement. Each ProgramStatement represents a parsed
|
||||
* MIPS statement.
|
||||
* @see ProgramStatement
|
||||
**/
|
||||
|
||||
public ArrayList createParsedList() {
|
||||
parsedList = new ArrayList();
|
||||
return parsedList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Produces existing list of parsed source code statements.
|
||||
* @return ArrayList of ProgramStatement. Each ProgramStatement represents a parsed
|
||||
* MIPS statement.
|
||||
* @see ProgramStatement
|
||||
**/
|
||||
|
||||
public ArrayList getParsedList() {
|
||||
return parsedList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Produces list of machine statements that are assembled from the program.
|
||||
* @return ArrayList of ProgramStatement. Each ProgramStatement represents an assembled
|
||||
* basic MIPS instruction.
|
||||
* @see ProgramStatement
|
||||
**/
|
||||
|
||||
public ArrayList getMachineList() {
|
||||
return machineList;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns BackStepper associated with this program. It is created upon successful assembly.
|
||||
* @return BackStepper object, null if there is none.
|
||||
**/
|
||||
|
||||
public BackStepper getBackStepper() {
|
||||
return backStepper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns SymbolTable associated with this program. It is created at assembly time,
|
||||
* and stores local labels (those not declared using .globl directive).
|
||||
**/
|
||||
|
||||
public SymbolTable getLocalSymbolTable() {
|
||||
return localSymbolTable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns status of BackStepper associated with this program.
|
||||
* @return true if enabled, false if disabled or non-existant.
|
||||
**/
|
||||
|
||||
public boolean backSteppingEnabled() {
|
||||
return (backStepper!=null && backStepper.enabled());
|
||||
}
|
||||
|
||||
/**
|
||||
* Produces specified line of MIPS source program.
|
||||
* @param i Line number of MIPS source program to get. Line 1 is first line.
|
||||
* @return Returns specified line of MIPS source. If outside the line range,
|
||||
* it returns null. Line 1 is first line.
|
||||
**/
|
||||
|
||||
public String getSourceLine(int i) {
|
||||
if ( (i >= 1) && (i <= sourceList.size()) )
|
||||
return (String) sourceList.get(i-1);
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reads MIPS source code from file into structure. Will always read from file.
|
||||
* It is GUI responsibility to assure that source edits are written to file
|
||||
* when user selects compile or run/step options.
|
||||
*
|
||||
* @param file String containing name of MIPS source code file.
|
||||
* @throws ProcessingException Will throw exception if there is any problem reading the file.
|
||||
**/
|
||||
|
||||
public void readSource(String file) throws ProcessingException {
|
||||
this.filename = file;
|
||||
this.sourceList = new ArrayList();
|
||||
ErrorList errors = null;
|
||||
BufferedReader inputFile;
|
||||
String line;
|
||||
int lengthSoFar = 0;
|
||||
try {
|
||||
inputFile = new BufferedReader(new FileReader(file));
|
||||
line = inputFile.readLine();
|
||||
while (line != null) {
|
||||
sourceList.add(line);
|
||||
line = inputFile.readLine();
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
errors = new ErrorList();
|
||||
errors.add(new ErrorMessage((MIPSprogram)null,0,0,e.toString()));
|
||||
throw new ProcessingException(errors);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tokenizes the MIPS source program. Program must have already been read from file.
|
||||
* @throws ProcessingException Will throw exception if errors occured while tokenizing.
|
||||
**/
|
||||
|
||||
public void tokenize() throws ProcessingException {
|
||||
this.tokenizer = new Tokenizer();
|
||||
this.tokenList = tokenizer.tokenize(this);
|
||||
this.localSymbolTable = new SymbolTable(this.filename); // prepare for assembly
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares the given list of files for assembly. This involves
|
||||
* reading and tokenizing all the source files. There may be only one.
|
||||
* @param filenames ArrayList containing the source file name(s) in no particular order
|
||||
* @param leadFilename String containing name of source file that needs to go first and
|
||||
* will be represented by "this" MIPSprogram object.
|
||||
* @param exceptionHandler String containing name of source file containing exception
|
||||
* handler. This will be assembled first, even ahead of leadFilename, to allow it to
|
||||
* include "startup" instructions loaded beginning at 0x00400000. Specify null or
|
||||
* empty String to indicate there is no such designated exception handler.
|
||||
* @return ArrayList containing one MIPSprogram object for each file to assemble.
|
||||
* objects for any additional files (send ArrayList to assembler)
|
||||
* @throws ProcessingException Will throw exception if errors occured while reading or tokenizing.
|
||||
**/
|
||||
|
||||
public ArrayList prepareFilesForAssembly(ArrayList filenames, String leadFilename, String exceptionHandler) throws ProcessingException {
|
||||
ArrayList MIPSprogramsToAssemble = new ArrayList();
|
||||
int leadFilePosition = 0;
|
||||
if (exceptionHandler != null && exceptionHandler.length() > 0) {
|
||||
filenames.add(0, exceptionHandler);
|
||||
leadFilePosition = 1;
|
||||
}
|
||||
for (int i=0; i<filenames.size(); i++) {
|
||||
String filename = (String) filenames.get(i);
|
||||
MIPSprogram preparee = (filename.equals(leadFilename)) ? this : new MIPSprogram();
|
||||
preparee.readSource(filename);
|
||||
preparee.tokenize();
|
||||
// I want "this" MIPSprogram to be the first in the list...except for exception handler
|
||||
if (preparee == this && MIPSprogramsToAssemble.size()>0) {
|
||||
MIPSprogramsToAssemble.add(leadFilePosition,preparee);
|
||||
}
|
||||
else {
|
||||
MIPSprogramsToAssemble.add(preparee);
|
||||
}
|
||||
}
|
||||
return MIPSprogramsToAssemble;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assembles the MIPS source program. All files comprising the program must have
|
||||
* already been tokenized. Assembler warnings are not considered errors.
|
||||
* @param MIPSprogramsToAssemble ArrayList of MIPSprogram objects, each representing a tokenized source file.
|
||||
* @param extendedAssemblerEnabled A boolean value - true means extended (pseudo) instructions
|
||||
* are permitted in source code and false means they are to be flagged as errors.
|
||||
* @throws ProcessingException Will throw exception if errors occured while assembling.
|
||||
* @return ErrorList containing nothing or only warnings (otherwise would have thrown exception).
|
||||
**/
|
||||
|
||||
public ErrorList assemble(ArrayList MIPSprogramsToAssemble, boolean extendedAssemblerEnabled)
|
||||
throws ProcessingException {
|
||||
return assemble(MIPSprogramsToAssemble, extendedAssemblerEnabled, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assembles the MIPS source program. All files comprising the program must have
|
||||
* already been tokenized.
|
||||
* @param MIPSprogramsToAssemble ArrayList of MIPSprogram objects, each representing a tokenized source file.
|
||||
* @param extendedAssemblerEnabled A boolean value - true means extended (pseudo) instructions
|
||||
* are permitted in source code and false means they are to be flagged as errors
|
||||
* @param warningsAreErrors A boolean value - true means assembler warnings will be considered errors and terminate
|
||||
the assemble; false means the assembler will produce warning message but otherwise ignore warnings.
|
||||
* @throws ProcessingException Will throw exception if errors occured while assembling.
|
||||
* @return ErrorList containing nothing or only warnings (otherwise would have thrown exception).
|
||||
**/
|
||||
|
||||
public ErrorList assemble(ArrayList MIPSprogramsToAssemble, boolean extendedAssemblerEnabled,
|
||||
boolean warningsAreErrors) throws ProcessingException {
|
||||
this.backStepper = null;
|
||||
Assembler asm = new Assembler();
|
||||
this.machineList = asm.assemble(MIPSprogramsToAssemble, extendedAssemblerEnabled, warningsAreErrors);
|
||||
this.backStepper = new BackStepper();
|
||||
return asm.getErrorList();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Simulates execution of the MIPS program. Program must have already been assembled.
|
||||
* Begins simulation at beginning of text segment and continues to completion.
|
||||
* @param breakPoints int array of breakpoints (PC addresses). Can be null.
|
||||
* @return true if execution completed and false otherwise
|
||||
* @throws ProcessingException Will throw exception if errors occured while simulating.
|
||||
**/
|
||||
|
||||
public boolean simulate(int[] breakPoints) throws ProcessingException {
|
||||
return this.simulateFromPC(breakPoints, -1, null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Simulates execution of the MIPS program. Program must have already been assembled.
|
||||
* Begins simulation at beginning of text segment and continues to completion or
|
||||
* until the specified maximum number of steps are simulated.
|
||||
* @param maxSteps maximum number of steps to simulate.
|
||||
* @return true if execution completed and false otherwise
|
||||
* @throws ProcessingException Will throw exception if errors occured while simulating.
|
||||
**/
|
||||
|
||||
public boolean simulate(int maxSteps) throws ProcessingException {
|
||||
return this.simulateFromPC(null, maxSteps, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Simulates execution of the MIPS program. Program must have already been assembled.
|
||||
* Begins simulation at current program counter address and continues until stopped,
|
||||
* paused, maximum steps exceeded, or exception occurs.
|
||||
* @param breakPoints int array of breakpoints (PC addresses). Can be null.
|
||||
* @param maxSteps maximum number of instruction executions. Default -1 means no maximum.
|
||||
* @param a the GUI component responsible for this call (GO normally). set to null if none.
|
||||
* @return true if execution completed and false otherwise
|
||||
* @throws ProcessingException Will throw exception if errors occured while simulating.
|
||||
**/
|
||||
public boolean simulateFromPC(int[] breakPoints, int maxSteps, AbstractAction a) throws ProcessingException {
|
||||
steppedExecution = false;
|
||||
Simulator sim = Simulator.getInstance();
|
||||
return sim.simulate(this, RegisterFile.getProgramCounter(), maxSteps, breakPoints, a);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Simulates execution of the MIPS program. Program must have already been assembled.
|
||||
* Begins simulation at current program counter address and executes one step.
|
||||
* @param a the GUI component responsible for this call (STEP normally). Set to null if none.
|
||||
* @return true if execution completed and false otherwise
|
||||
* @throws ProcessingException Will throw exception if errors occured while simulating.
|
||||
**/
|
||||
public boolean simulateStepAtPC(AbstractAction a) throws ProcessingException {
|
||||
steppedExecution = true;
|
||||
Simulator sim = Simulator.getInstance();
|
||||
boolean done = sim.simulate(this, RegisterFile.getProgramCounter(), 1, null,a);
|
||||
return done;
|
||||
}
|
||||
|
||||
/** Will be true only while in process of simulating a program statement
|
||||
* in step mode (e.g. returning to GUI after each step). This is used to
|
||||
* prevent spurious AccessNotices from being sent from Memory and Register
|
||||
* to observers at other times (e.g. while updating the data and register
|
||||
* displays, while assembling program's data segment, etc).
|
||||
*/
|
||||
public boolean inSteppedExecution() {
|
||||
return steppedExecution;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new {@link MacroPool} and sends reference of this
|
||||
* {@link MIPSprogram} to it
|
||||
*
|
||||
* @return instatiated MacroPool
|
||||
* @author M.H.Sekhavat <sekhavat17@gmail.com>
|
||||
*/
|
||||
public MacroPool createMacroPool() {
|
||||
macroPool = new MacroPool(this);
|
||||
return macroPool;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets local macro pool {@link MacroPool} for this program
|
||||
* @return MacroPool
|
||||
* @author M.H.Sekhavat <sekhavat17@gmail.com>
|
||||
*/
|
||||
public MacroPool getLocalMacroPool() {
|
||||
return macroPool;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets local macro pool {@link MacroPool} for this program
|
||||
* @param macroPool reference to MacroPool
|
||||
* @author M.H.Sekhavat <sekhavat17@gmail.com>
|
||||
*/
|
||||
public void setLocalMacroPool(MacroPool macroPool) {
|
||||
this.macroPool = macroPool;
|
||||
}
|
||||
|
||||
} // MIPSprogram
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,842 @@
|
||||
package mars;
|
||||
import mars.venus.*;
|
||||
import mars.util.*;
|
||||
import mars.mips.dump.*;
|
||||
import mars.mips.hardware.*;
|
||||
import mars.simulator.*;
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.awt.*;
|
||||
import javax.swing.*;
|
||||
import javax.swing.JOptionPane; // KENV 9/8/2004
|
||||
|
||||
/*
|
||||
Copyright (c) 2003-2012, 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)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Launch the Mars application
|
||||
*
|
||||
* @author Pete Sanderson
|
||||
* @version December 2009
|
||||
**/
|
||||
|
||||
public class MarsLaunch {
|
||||
|
||||
/**
|
||||
* Main takes a number of command line arguments.<br>
|
||||
Usage: Mars [options] filename<br>
|
||||
Valid options (not case sensitive, separate by spaces) are:<br>
|
||||
a -- assemble only, do not simulate<br>
|
||||
ad -- both a and d<br>
|
||||
ae<n> -- terminate MARS with integer exit code <n> if an assemble error occurs.<br>
|
||||
ascii -- display memory or register contents interpreted as ASCII
|
||||
b -- brief - do not display register/memory address along with contents<br>
|
||||
d -- print debugging statements<br>
|
||||
da -- both a and d<br>
|
||||
db -- MIPS delayed branching is enabled.<br>
|
||||
dec -- display memory or register contents in decimal.<br>
|
||||
dump -- dump memory contents to file. Option has 3 arguments, e.g. <br>
|
||||
<tt>dump <segment> <format> <file></tt>. Also supports<br>
|
||||
an address range (see <i>m-n</i> below). Current supported <br>
|
||||
segments are <tt>.text</tt> and <tt>.data</tt>. Current supported dump formats <br>
|
||||
are <tt>Binary</tt>, <tt>HexText</tt>, <tt>BinaryText</tt>.<br>
|
||||
h -- display help. Use by itself and with no filename</br>
|
||||
hex -- display memory or register contents in hexadecimal (default)<br>
|
||||
ic -- display count of MIPS basic instructions 'executed'");
|
||||
mc -- set memory configuration. Option has 1 argument, e.g.<br>
|
||||
<tt>mc <config$gt;</tt>, where <config$gt; is <tt>Default</tt><br>
|
||||
for the MARS default 32-bit address space, <tt>CompactDataAtZero</tt> for<br>
|
||||
a 32KB address space with data segment at address 0, or <tt>CompactTextAtZero</tt><br>
|
||||
for a 32KB address space with text segment at address 0.<br>
|
||||
me -- display MARS messages to standard err instead of standard out. Can separate via redirection.</br>
|
||||
nc -- do not display copyright notice (for cleaner redirected/piped output).</br>
|
||||
np -- No Pseudo-instructions allowed ("ne" will work also).<br>
|
||||
p -- Project mode - assemble all files in the same directory as given file.<br>
|
||||
se<n> -- terminate MARS with integer exit code <n> if a simulation (run) error occurs.<br>
|
||||
sm -- Start execution at Main - Execution will start at program statement globally labeled main.<br>
|
||||
smc -- Self Modifying Code - Program can write and branch to either text or data segment<br>
|
||||
we -- assembler Warnings will be considered Errors<br>
|
||||
<n> -- where <n> is an integer maximum count of steps to simulate.<br>
|
||||
If 0, negative or not specified, there is no maximum.<br>
|
||||
$<reg> -- where <reg> is number or name (e.g. 5, t3, f10) of register whose <br>
|
||||
content to display at end of run. Option may be repeated.<br>
|
||||
<reg_name> -- where <reg_name> is name (e.g. t3, f10) of register whose <br>
|
||||
content to display at end of run. Option may be repeated. $ not required.<br>
|
||||
<m>-<n> -- memory address range from <m> to <n> whose contents to<br>
|
||||
display at end of run. <m> and <n> may be hex or decimal,<br>
|
||||
<m> <= <n>, both must be on word boundary. Option may be repeated.<br>
|
||||
pa -- Program Arguments follow in a space-separated list. This<br>
|
||||
option must be placed AFTER ALL FILE NAMES, because everything<br>
|
||||
that follows it is interpreted as a program argument to be<br>
|
||||
made available to the MIPS program at runtime.<br>
|
||||
**/
|
||||
|
||||
|
||||
|
||||
private boolean simulate;
|
||||
private int displayFormat;
|
||||
private boolean verbose; // display register name or address along with contents
|
||||
private boolean assembleProject; // assemble only the given file or all files in its directory
|
||||
private boolean pseudo; // pseudo instructions allowed in source code or not.
|
||||
private boolean delayedBranching; // MIPS delayed branching is enabled.
|
||||
private boolean warningsAreErrors; // Whether assembler warnings should be considered errors.
|
||||
private boolean startAtMain; // Whether to start execution at statement labeled 'main'
|
||||
private boolean countInstructions; // Whether to count and report number of instructions executed
|
||||
private boolean selfModifyingCode; // Whether to allow self-modifying code (e.g. write to text segment)
|
||||
private static final String rangeSeparator = "-";
|
||||
private static final int splashDuration = 2000; // time in MS to show splash screen
|
||||
private static final int memoryWordsPerLine = 4; // display 4 memory words, tab separated, per line
|
||||
private static final int DECIMAL = 0; // memory and register display format
|
||||
private static final int HEXADECIMAL = 1;// memory and register display format
|
||||
private static final int ASCII = 2;// memory and register display format
|
||||
private ArrayList registerDisplayList;
|
||||
private ArrayList memoryDisplayList;
|
||||
private ArrayList filenameList;
|
||||
private MIPSprogram code;
|
||||
private int maxSteps;
|
||||
private int instructionCount;
|
||||
private PrintStream out; // stream for display of command line output
|
||||
private ArrayList dumpTriples = null; // each element holds 3 arguments for dump option
|
||||
private ArrayList programArgumentList; // optional program args for MIPS program (becomes argc, argv)
|
||||
private int assembleErrorExitCode; // MARS command exit code to return if assemble error occurs
|
||||
private int simulateErrorExitCode;// MARS command exit code to return if simulation error occurs
|
||||
|
||||
public MarsLaunch(String[] args) {
|
||||
boolean gui = (args.length == 0);
|
||||
Globals.initialize(gui);
|
||||
if (gui) {
|
||||
launchIDE();
|
||||
}
|
||||
else { // running from command line.
|
||||
// assure command mode works in headless environment (generates exception if not)
|
||||
System.setProperty("java.awt.headless", "true");
|
||||
simulate = true;
|
||||
displayFormat = HEXADECIMAL;
|
||||
verbose = true;
|
||||
assembleProject = false;
|
||||
pseudo = true;
|
||||
delayedBranching = false;
|
||||
warningsAreErrors = false;
|
||||
startAtMain = false;
|
||||
countInstructions = false;
|
||||
selfModifyingCode = false;
|
||||
instructionCount = 0;
|
||||
assembleErrorExitCode = 0;
|
||||
simulateErrorExitCode = 0;
|
||||
registerDisplayList = new ArrayList();
|
||||
memoryDisplayList = new ArrayList();
|
||||
filenameList = new ArrayList();
|
||||
MemoryConfigurations.setCurrentConfiguration(MemoryConfigurations.getDefaultConfiguration());
|
||||
// do NOT use Globals.program for command line MARS -- it triggers 'backstep' log.
|
||||
code = new MIPSprogram();
|
||||
maxSteps = -1;
|
||||
out = System.out;
|
||||
if (parseCommandArgs(args)) {
|
||||
if (runCommand()) {
|
||||
displayMiscellaneousPostMortem();
|
||||
displayRegistersPostMortem();
|
||||
displayMemoryPostMortem();
|
||||
}
|
||||
dumpSegments();
|
||||
}
|
||||
System.exit(Globals.exitCode);
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////
|
||||
// Perform any specified dump operations. See "dump" option.
|
||||
//
|
||||
|
||||
private void dumpSegments() {
|
||||
|
||||
if (dumpTriples == null)
|
||||
return;
|
||||
|
||||
for (int i=0; i<dumpTriples.size(); i++) {
|
||||
String[] triple = (String[])dumpTriples.get(i);
|
||||
File file = new File(triple[2]);
|
||||
Integer[] segInfo = MemoryDump.getSegmentBounds(triple[0]);
|
||||
// If not segment name, see if it is address range instead. DPS 14-July-2008
|
||||
if (segInfo == null) {
|
||||
try {
|
||||
String[] memoryRange = checkMemoryAddressRange(triple[0]);
|
||||
segInfo = new Integer[2];
|
||||
segInfo[0] = new Integer(Binary.stringToInt(memoryRange[0])); // low end of range
|
||||
segInfo[1] = new Integer(Binary.stringToInt(memoryRange[1])); // high end of range
|
||||
}
|
||||
catch (NumberFormatException nfe) {
|
||||
segInfo = null;
|
||||
}
|
||||
catch (NullPointerException npe) {
|
||||
segInfo = null;
|
||||
}
|
||||
}
|
||||
if (segInfo == null) {
|
||||
out.println("Error while attempting to save dump, segment/address-range " + triple[0] + " is invalid!");
|
||||
continue;
|
||||
}
|
||||
DumpFormatLoader loader = new DumpFormatLoader();
|
||||
ArrayList dumpFormats = loader.loadDumpFormats();
|
||||
DumpFormat format = DumpFormatLoader.findDumpFormatGivenCommandDescriptor(dumpFormats, triple[1]);
|
||||
if (format == null) {
|
||||
out.println("Error while attempting to save dump, format " + triple[1] + " was not found!");
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
int highAddress = Globals.memory.getAddressOfFirstNull(segInfo[0].intValue(), segInfo[1].intValue())- Memory.WORD_LENGTH_BYTES;
|
||||
if (highAddress < segInfo[0].intValue()) {
|
||||
out.println("This segment has not been written to, there is nothing to dump.");
|
||||
continue;
|
||||
}
|
||||
format.dumpMemoryRange(file, segInfo[0].intValue(), highAddress);
|
||||
}
|
||||
catch (FileNotFoundException e) {
|
||||
out.println("Error while attempting to save dump, file " + file + " was not found!");
|
||||
continue;
|
||||
}
|
||||
catch (AddressErrorException e) {
|
||||
out.println("Error while attempting to save dump, file " + file + "! Could not access address: " + e.getAddress() + "!");
|
||||
continue;
|
||||
}
|
||||
catch (IOException e) {
|
||||
out.println("Error while attempting to save dump, file " + file + "! Disk IO failed!");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// There are no command arguments, so run in interactive mode by
|
||||
// launching the GUI-fronted integrated development environment.
|
||||
|
||||
private void launchIDE() {
|
||||
// System.setProperty("apple.laf.useScreenMenuBar", "true"); // Puts MARS menu on Mac OS menu bar
|
||||
new MarsSplashScreen(splashDuration).showSplash();
|
||||
SwingUtilities.invokeLater(
|
||||
new Runnable() {
|
||||
public void run() {
|
||||
//Turn off metal's use of bold fonts
|
||||
//UIManager.put("swing.boldMetal", Boolean.FALSE);
|
||||
new VenusUI("MARS "+Globals.version);
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Parse command line arguments. The initial parsing has already been
|
||||
// done, since each space-separated argument is already in a String array
|
||||
// element. Here, we check for validity, set switch variables as appropriate
|
||||
// and build data structures. For help option (h), display the help.
|
||||
// Returns true if command args parse OK, false otherwise.
|
||||
|
||||
private boolean parseCommandArgs(String[] args) {
|
||||
String noCopyrightSwitch = "nc";
|
||||
String displayMessagesToErrSwitch = "me";
|
||||
boolean argsOK = true;
|
||||
boolean inProgramArgumentList = false;
|
||||
programArgumentList = null;
|
||||
if (args.length == 0)
|
||||
return true; // should not get here...
|
||||
// If the option to display MARS messages to standard erro is used,
|
||||
// it must be processed before any others (since messages may be
|
||||
// generated during option parsing).
|
||||
processDisplayMessagesToErrSwitch(args, displayMessagesToErrSwitch);
|
||||
displayCopyright(args, noCopyrightSwitch); // ..or not..
|
||||
if (args.length == 1 && args[0].equals("h")) {
|
||||
displayHelp();
|
||||
return false;
|
||||
}
|
||||
for (int i=0; i<args.length; i++) {
|
||||
// We have seen "pa" switch, so all remaining args are program args
|
||||
// that will become "argc" and "argv" for the MIPS program.
|
||||
if (inProgramArgumentList) {
|
||||
if (programArgumentList == null) {
|
||||
programArgumentList = new ArrayList();
|
||||
}
|
||||
programArgumentList.add(args[i]);
|
||||
continue;
|
||||
}
|
||||
// Once we hit "pa", all remaining command args are assumed
|
||||
// to be program arguments.
|
||||
if (args[i].toLowerCase().equals("pa")) {
|
||||
inProgramArgumentList = true;
|
||||
continue;
|
||||
}
|
||||
// messages-to-standard-error switch already processed, so ignore.
|
||||
if (args[i].toLowerCase().equals(displayMessagesToErrSwitch)) {
|
||||
continue;
|
||||
}
|
||||
// no-copyright switch already processed, so ignore.
|
||||
if (args[i].toLowerCase().equals(noCopyrightSwitch)) {
|
||||
continue;
|
||||
}
|
||||
if (args[i].toLowerCase().equals("dump")) {
|
||||
if (args.length <= (i+3)) {
|
||||
out.println("Dump command line argument requires a segment, format and file name.");
|
||||
argsOK = false;
|
||||
}
|
||||
else {
|
||||
if (dumpTriples == null)
|
||||
dumpTriples = new ArrayList();
|
||||
dumpTriples.add(new String[] {args[++i], args[++i], args[++i]});
|
||||
//simulate = false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (args[i].toLowerCase().equals("mc")) {
|
||||
String configName = args[++i];
|
||||
MemoryConfiguration config = MemoryConfigurations.getConfigurationByName(configName);
|
||||
if (config == null) {
|
||||
out.println("Invalid memory configuration: "+configName);
|
||||
argsOK = false;
|
||||
}
|
||||
else {
|
||||
MemoryConfigurations.setCurrentConfiguration(config);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
// Set MARS exit code for assemble error
|
||||
if (args[i].toLowerCase().indexOf("ae")==0) {
|
||||
String s = args[i].substring(2);
|
||||
try {
|
||||
assembleErrorExitCode = Integer.decode(s).intValue();
|
||||
continue;
|
||||
}
|
||||
catch (NumberFormatException nfe) {
|
||||
// Let it fall thru and get handled by catch-all
|
||||
}
|
||||
}
|
||||
// Set MARS exit code for simulate error
|
||||
if (args[i].toLowerCase().indexOf("se")==0) {
|
||||
String s = args[i].substring(2);
|
||||
try {
|
||||
simulateErrorExitCode = Integer.decode(s).intValue();
|
||||
continue;
|
||||
}
|
||||
catch (NumberFormatException nfe) {
|
||||
// Let it fall thru and get handled by catch-all
|
||||
}
|
||||
}
|
||||
if (args[i].toLowerCase().equals("d")) {
|
||||
Globals.debug = true;
|
||||
continue;
|
||||
}
|
||||
if (args[i].toLowerCase().equals("a")) {
|
||||
simulate = false;
|
||||
continue;
|
||||
}
|
||||
if (args[i].toLowerCase().equals("ad") ||
|
||||
args[i].toLowerCase().equals("da")) {
|
||||
Globals.debug = true;
|
||||
simulate = false;
|
||||
continue;
|
||||
}
|
||||
if (args[i].toLowerCase().equals("p")) {
|
||||
assembleProject = true;
|
||||
continue;
|
||||
}
|
||||
if (args[i].toLowerCase().equals("dec")) {
|
||||
displayFormat = DECIMAL;
|
||||
continue;
|
||||
}
|
||||
if (args[i].toLowerCase().equals("hex")) {
|
||||
displayFormat = HEXADECIMAL;
|
||||
continue;
|
||||
}
|
||||
if (args[i].toLowerCase().equals("ascii")) {
|
||||
displayFormat = ASCII;
|
||||
continue;
|
||||
}
|
||||
if (args[i].toLowerCase().equals("b")) {
|
||||
verbose = false;
|
||||
continue;
|
||||
}
|
||||
if (args[i].toLowerCase().equals("db")) {
|
||||
delayedBranching = true;
|
||||
continue;
|
||||
}
|
||||
if (args[i].toLowerCase().equals("np") || args[i].toLowerCase().equals("ne")) {
|
||||
pseudo = false;
|
||||
continue;
|
||||
}
|
||||
if (args[i].toLowerCase().equals("we")) { // added 14-July-2008 DPS
|
||||
warningsAreErrors = true;
|
||||
continue;
|
||||
}
|
||||
if (args[i].toLowerCase().equals("sm")) { // added 17-Dec-2009 DPS
|
||||
startAtMain = true;
|
||||
continue;
|
||||
}
|
||||
if (args[i].toLowerCase().equals("smc")) { // added 5-Jul-2013 DPS
|
||||
selfModifyingCode = true;
|
||||
continue;
|
||||
}
|
||||
if (args[i].toLowerCase().equals("ic")) { // added 19-Jul-2012 DPS
|
||||
countInstructions = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (args[i].indexOf("$") == 0) {
|
||||
if (RegisterFile.getUserRegister(args[i])==null &&
|
||||
Coprocessor1.getRegister(args[i])==null) {
|
||||
out.println("Invalid Register Name: "+args[i]);
|
||||
}
|
||||
else {
|
||||
registerDisplayList.add(args[i]);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
// check for register name w/o $. added 14-July-2008 DPS
|
||||
if (RegisterFile.getUserRegister("$"+args[i]) != null ||
|
||||
Coprocessor1.getRegister("$"+args[i]) != null) {
|
||||
registerDisplayList.add("$"+args[i]);
|
||||
continue;
|
||||
}
|
||||
if (new File(args[i]).exists()) { // is it a file name?
|
||||
filenameList.add(args[i]);
|
||||
continue;
|
||||
}
|
||||
// Check for stand-alone integer, which is the max execution steps option
|
||||
try {
|
||||
Integer.decode(args[i]);
|
||||
maxSteps = Integer.decode(args[i]).intValue(); // if we got here, it has to be OK
|
||||
continue;
|
||||
}
|
||||
catch (NumberFormatException nfe) {
|
||||
}
|
||||
// Check for integer address range (m-n)
|
||||
try {
|
||||
String[] memoryRange = checkMemoryAddressRange(args[i]);
|
||||
memoryDisplayList.add(memoryRange[0]); // low end of range
|
||||
memoryDisplayList.add(memoryRange[1]); // high end of range
|
||||
continue;
|
||||
}
|
||||
catch (NumberFormatException nfe) {
|
||||
out.println("Invalid/unaligned address or invalid range: "+args[i]);
|
||||
argsOK = false;
|
||||
continue;
|
||||
}
|
||||
catch (NullPointerException npe) {
|
||||
// Do nothing. next statement will handle it
|
||||
}
|
||||
out.println("Invalid Command Argument: "+args[i]);
|
||||
argsOK = false;
|
||||
}
|
||||
return argsOK;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Carry out the mars command: assemble then optionally run
|
||||
// Returns false if no simulation (run) occurs, true otherwise.
|
||||
|
||||
private boolean runCommand() {
|
||||
boolean programRan = false;
|
||||
if (filenameList.size()==0) {
|
||||
return programRan;
|
||||
}
|
||||
try {
|
||||
Globals.getSettings().setBooleanSettingNonPersistent(Settings.DELAYED_BRANCHING_ENABLED, delayedBranching);
|
||||
Globals.getSettings().setBooleanSettingNonPersistent(Settings.SELF_MODIFYING_CODE_ENABLED, selfModifyingCode);
|
||||
File mainFile = new File((String) filenameList.get(0)).getAbsoluteFile();// First file is "main" file
|
||||
ArrayList filesToAssemble;
|
||||
if (assembleProject) {
|
||||
filesToAssemble = FilenameFinder.getFilenameList(mainFile.getParent(), Globals.fileExtensions);
|
||||
if (filenameList.size() > 1) {
|
||||
// Using "p" project option PLUS listing more than one filename on command line.
|
||||
// Add the additional files, avoiding duplicates.
|
||||
filenameList.remove(0); // first one has already been processed
|
||||
ArrayList moreFilesToAssemble = FilenameFinder.getFilenameList(filenameList, FilenameFinder.MATCH_ALL_EXTENSIONS);
|
||||
// Remove any duplicates then merge the two lists.
|
||||
for (int index2 = 0; index2<moreFilesToAssemble.size(); index2++) {
|
||||
for (int index1 = 0; index1<filesToAssemble.size(); index1++) {
|
||||
if (filesToAssemble.get(index1).equals(moreFilesToAssemble.get(index2))) {
|
||||
moreFilesToAssemble.remove(index2);
|
||||
index2--; // adjust for left shift in moreFilesToAssemble...
|
||||
break; // break out of inner loop...
|
||||
}
|
||||
}
|
||||
}
|
||||
filesToAssemble.addAll(moreFilesToAssemble);
|
||||
}
|
||||
}
|
||||
else {
|
||||
filesToAssemble = FilenameFinder.getFilenameList(filenameList, FilenameFinder.MATCH_ALL_EXTENSIONS);
|
||||
}
|
||||
if (Globals.debug) {
|
||||
out.println("-------- TOKENIZING BEGINS -----------");
|
||||
}
|
||||
ArrayList MIPSprogramsToAssemble =
|
||||
code.prepareFilesForAssembly(filesToAssemble, mainFile.getAbsolutePath(), null);
|
||||
if (Globals.debug) {
|
||||
out.println("-------- ASSEMBLY BEGINS -----------");
|
||||
}
|
||||
// Added logic to check for warnings and print if any. DPS 11/28/06
|
||||
ErrorList warnings = code.assemble(MIPSprogramsToAssemble, pseudo, warningsAreErrors);
|
||||
if (warnings != null && warnings.warningsOccurred()) {
|
||||
out.println(warnings.generateWarningReport());
|
||||
}
|
||||
RegisterFile.initializeProgramCounter(startAtMain); // DPS 3/9/09
|
||||
if (simulate) {
|
||||
// store program args (if any) in MIPS memory
|
||||
new ProgramArgumentList(programArgumentList).storeProgramArguments();
|
||||
// establish observer if specified
|
||||
establishObserver();
|
||||
if (Globals.debug) {
|
||||
out.println("-------- SIMULATION BEGINS -----------");
|
||||
}
|
||||
programRan = true;
|
||||
boolean done = code.simulate(maxSteps);
|
||||
if (!done) {
|
||||
out.println("\nProgram terminated when maximum step limit "+maxSteps+" reached.");
|
||||
}
|
||||
}
|
||||
if (Globals.debug) {
|
||||
out.println("\n-------- ALL PROCESSING COMPLETE -----------");
|
||||
}
|
||||
}
|
||||
catch (ProcessingException e) {
|
||||
Globals.exitCode = (programRan) ? simulateErrorExitCode : assembleErrorExitCode;
|
||||
out.println(e.errors().generateErrorAndWarningReport());
|
||||
out.println("Processing terminated due to errors.");
|
||||
}
|
||||
return programRan;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Check for memory address subrange. Has to be two integers separated
|
||||
// by "-"; no embedded spaces. e.g. 0x00400000-0x00400010
|
||||
// If number is not multiple of 4, will be rounded up to next higher.
|
||||
|
||||
private String[] checkMemoryAddressRange(String arg) throws NumberFormatException {
|
||||
String[] memoryRange = null;
|
||||
if (arg.indexOf(rangeSeparator) > 0 &&
|
||||
arg.indexOf(rangeSeparator) < arg.length()-1) {
|
||||
// assume correct format, two numbers separated by -, no embedded spaces.
|
||||
// If that doesn't work it is invalid.
|
||||
memoryRange = new String[2];
|
||||
memoryRange[0] = arg.substring(0,arg.indexOf(rangeSeparator));
|
||||
memoryRange[1] = arg.substring(arg.indexOf(rangeSeparator)+1);
|
||||
// NOTE: I will use homegrown decoder, because Integer.decode will throw
|
||||
// exception on address higher than 0x7FFFFFFF (e.g. sign bit is 1).
|
||||
if (Binary.stringToInt(memoryRange[0]) > Binary.stringToInt(memoryRange[1]) ||
|
||||
!Memory.wordAligned(Binary.stringToInt(memoryRange[0])) ||
|
||||
!Memory.wordAligned(Binary.stringToInt(memoryRange[1]))) {
|
||||
throw new NumberFormatException();
|
||||
}
|
||||
}
|
||||
return memoryRange;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// Required for counting instructions executed, if that option is specified.
|
||||
// DPS 19 July 2012
|
||||
private void establishObserver() {
|
||||
if (countInstructions) {
|
||||
Observer instructionCounter =
|
||||
new Observer() {
|
||||
private int lastAddress = 0;
|
||||
public void update(Observable o, Object obj) {
|
||||
if (obj instanceof AccessNotice) {
|
||||
AccessNotice notice = (AccessNotice) obj;
|
||||
if (!notice.accessIsFromMIPS())
|
||||
return;
|
||||
if (notice.getAccessType() != AccessNotice.READ)
|
||||
return;
|
||||
MemoryAccessNotice m = (MemoryAccessNotice) notice;
|
||||
int a = m.getAddress();
|
||||
if (a == lastAddress)
|
||||
return;
|
||||
lastAddress = a;
|
||||
instructionCount++;
|
||||
}
|
||||
}
|
||||
};
|
||||
try {
|
||||
Globals.memory.addObserver(instructionCounter, Memory.textBaseAddress, Memory.textLimitAddress);
|
||||
}
|
||||
catch (AddressErrorException aee) {
|
||||
out.println("Internal error: MarsLaunch uses incorrect text segment address for instruction observer");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Displays any specified runtime properties. Initially just instruction count
|
||||
// DPS 19 July 2012
|
||||
private void displayMiscellaneousPostMortem() {
|
||||
if (countInstructions) {
|
||||
out.println("\n"+instructionCount);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Displays requested register or registers
|
||||
|
||||
private void displayRegistersPostMortem() {
|
||||
int value; // handy local to use throughout the next couple loops
|
||||
String strValue;
|
||||
// Display requested register contents
|
||||
out.println();
|
||||
Iterator regIter = registerDisplayList.iterator();
|
||||
while (regIter.hasNext()) {
|
||||
String reg = regIter.next().toString();
|
||||
if (RegisterFile.getUserRegister(reg)!=null) {
|
||||
// integer register
|
||||
if (verbose)
|
||||
out.print(reg+"\t");
|
||||
value = RegisterFile.getUserRegister(reg).getValue();
|
||||
out.println( formatIntForDisplay(value) );
|
||||
}
|
||||
else {
|
||||
// floating point register
|
||||
float fvalue = Coprocessor1.getFloatFromRegister(reg);
|
||||
int ivalue = Coprocessor1.getIntFromRegister(reg);
|
||||
double dvalue = Double.NaN;
|
||||
long lvalue = 0;
|
||||
boolean hasDouble = false;
|
||||
try {
|
||||
dvalue = Coprocessor1.getDoubleFromRegisterPair(reg);
|
||||
lvalue = Coprocessor1.getLongFromRegisterPair(reg);
|
||||
hasDouble = true;
|
||||
}
|
||||
catch (InvalidRegisterAccessException irae) { }
|
||||
if (verbose) {
|
||||
out.print(reg+"\t");
|
||||
}
|
||||
if (displayFormat == HEXADECIMAL) {
|
||||
// display float (and double, if applicable) in hex
|
||||
out.print(
|
||||
Binary.binaryStringToHexString(
|
||||
Binary.intToBinaryString(ivalue)));
|
||||
if (hasDouble) {
|
||||
out.println("\t"+
|
||||
Binary.binaryStringToHexString(
|
||||
Binary.longToBinaryString(lvalue)));
|
||||
}
|
||||
else {
|
||||
out.println("");
|
||||
}
|
||||
}
|
||||
else if (displayFormat == DECIMAL) {
|
||||
// display float (and double, if applicable) in decimal
|
||||
out.print(fvalue);
|
||||
if (hasDouble) {
|
||||
out.println("\t"+dvalue);
|
||||
}
|
||||
else {
|
||||
out.println("");
|
||||
}
|
||||
}
|
||||
else { // displayFormat == ASCII
|
||||
out.print(Binary.intToAscii(ivalue));
|
||||
if (hasDouble) {
|
||||
out.println("\t"+
|
||||
Binary.intToAscii(Binary.highOrderLongToInt(lvalue))+
|
||||
Binary.intToAscii(Binary.lowOrderLongToInt(lvalue)));
|
||||
}
|
||||
else {
|
||||
out.println("");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Formats int value for display: decimal, hex, ascii
|
||||
private String formatIntForDisplay(int value) {
|
||||
String strValue;
|
||||
switch (displayFormat) {
|
||||
case DECIMAL :
|
||||
strValue = ""+value;
|
||||
break;
|
||||
case HEXADECIMAL :
|
||||
strValue = Binary.intToHexString(value);
|
||||
break;
|
||||
case ASCII :
|
||||
strValue = Binary.intToAscii(value);
|
||||
break;
|
||||
default :
|
||||
strValue = Binary.intToHexString(value);
|
||||
}
|
||||
return strValue;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Displays requested memory range or ranges
|
||||
|
||||
private void displayMemoryPostMortem() {
|
||||
int value;
|
||||
// Display requested memory range contents
|
||||
Iterator memIter = memoryDisplayList.iterator();
|
||||
int addressStart=0, addressEnd=0;
|
||||
while (memIter.hasNext()) {
|
||||
try { // This will succeed; error would have been caught during command arg parse
|
||||
addressStart = Binary.stringToInt(memIter.next().toString());
|
||||
addressEnd = Binary.stringToInt(memIter.next().toString());
|
||||
}
|
||||
catch (NumberFormatException nfe) {
|
||||
}
|
||||
int valuesDisplayed = 0;
|
||||
for (int addr=addressStart; addr<=addressEnd; addr+=Memory.WORD_LENGTH_BYTES) {
|
||||
if (addr < 0 && addressEnd > 0)
|
||||
break; // happens only if addressEnd is 0x7ffffffc
|
||||
if (valuesDisplayed % memoryWordsPerLine == 0) {
|
||||
out.print( (valuesDisplayed > 0) ? "\n" : "");
|
||||
if (verbose) {
|
||||
out.print("Mem["+Binary.intToHexString(addr)+"]\t");
|
||||
}
|
||||
}
|
||||
try {
|
||||
// Allow display of binary text segment (machine code) DPS 14-July-2008
|
||||
if (Memory.inTextSegment(addr) || Memory.inKernelTextSegment(addr)) {
|
||||
Integer iValue = Globals.memory.getRawWordOrNull(addr);
|
||||
value = (iValue==null) ? 0 : iValue.intValue();
|
||||
}
|
||||
else {
|
||||
value = Globals.memory.getWord(addr);
|
||||
}
|
||||
out.print( formatIntForDisplay(value)+"\t");
|
||||
}
|
||||
catch (AddressErrorException aee) {
|
||||
out.print("Invalid address: "+addr+"\t");
|
||||
}
|
||||
valuesDisplayed++;
|
||||
}
|
||||
out.println();
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// If option to display MARS messages to standard err (System.err) is
|
||||
// present, it must be processed before all others. Since messages may
|
||||
// be output as early as during the command parse.
|
||||
private void processDisplayMessagesToErrSwitch(String[] args, String displayMessagesToErrSwitch) {
|
||||
for (int i=0; i<args.length; i++) {
|
||||
if (args[i].toLowerCase().equals(displayMessagesToErrSwitch)) {
|
||||
out = System.err;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// Decide whether copyright should be displayed, and display
|
||||
// if so.
|
||||
|
||||
private void displayCopyright(String[] args, String noCopyrightSwitch) {
|
||||
boolean print = true;
|
||||
for (int i=0; i<args.length; i++) {
|
||||
if (args[i].toLowerCase().equals(noCopyrightSwitch)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
out.println("MARS "+Globals.version+" Copyright "+Globals.copyrightYears+" "+Globals.copyrightHolders+"\n");
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// Display command line help text
|
||||
|
||||
private void displayHelp() {
|
||||
String[] segmentNames = MemoryDump.getSegmentNames();
|
||||
String segments = "";
|
||||
for (int i=0; i<segmentNames.length; i++) {
|
||||
segments += segmentNames[i];
|
||||
if (i<segmentNames.length-1) {
|
||||
segments += ", ";
|
||||
}
|
||||
}
|
||||
ArrayList dumpFormats = (new DumpFormatLoader()).loadDumpFormats();
|
||||
String formats = "";
|
||||
for (int i=0; i<dumpFormats.size(); i++) {
|
||||
formats += ((DumpFormat) dumpFormats.get(i)).getCommandDescriptor();
|
||||
if (i<dumpFormats.size()-1) {
|
||||
formats += ", ";
|
||||
}
|
||||
}
|
||||
out.println("Usage: Mars [options] filename [additional filenames]");
|
||||
out.println(" Valid options (not case sensitive, separate by spaces) are:");
|
||||
out.println(" a -- assemble only, do not simulate");
|
||||
out.println(" ae<n> -- terminate MARS with integer exit code <n> if an assemble error occurs.");
|
||||
out.println(" ascii -- display memory or register contents interpreted as ASCII codes.");
|
||||
out.println(" b -- brief - do not display register/memory address along with contents");
|
||||
out.println(" d -- display MARS debugging statements");
|
||||
out.println(" db -- MIPS delayed branching is enabled");
|
||||
out.println(" dec -- display memory or register contents in decimal.");
|
||||
out.println(" dump <segment> <format> <file> -- memory dump of specified memory segment");
|
||||
out.println(" in specified format to specified file. Option may be repeated.");
|
||||
out.println(" Dump occurs at the end of simulation unless 'a' option is used.");
|
||||
out.println(" Segment and format are case-sensitive and possible values are:");
|
||||
out.println(" <segment> = "+segments);
|
||||
out.println(" <format> = "+formats);
|
||||
out.println(" h -- display this help. Use by itself with no filename.");
|
||||
out.println(" hex -- display memory or register contents in hexadecimal (default)");
|
||||
out.println(" ic -- display count of MIPS basic instructions 'executed'");
|
||||
out.println(" mc <config> -- set memory configuration. Argument <config> is");
|
||||
out.println(" case-sensitive and possible values are: Default for the default");
|
||||
out.println(" 32-bit address space, CompactDataAtZero for a 32KB memory with");
|
||||
out.println(" data segment at address 0, or CompactTextAtZero for a 32KB");
|
||||
out.println(" memory with text segment at address 0.");
|
||||
out.println(" me -- display MARS messages to standard err instead of standard out. ");
|
||||
out.println(" Can separate messages from program output using redirection");
|
||||
out.println(" nc -- do not display copyright notice (for cleaner redirected/piped output).");
|
||||
out.println(" np -- use of pseudo instructions and formats not permitted");
|
||||
out.println(" p -- Project mode - assemble all files in the same directory as given file.");
|
||||
out.println(" se<n> -- terminate MARS with integer exit code <n> if a simulation (run) error occurs.");
|
||||
out.println(" sm -- start execution at statement with global label main, if defined");
|
||||
out.println(" smc -- Self Modifying Code - Program can write and branch to either text or data segment");
|
||||
out.println(" <n> -- where <n> is an integer maximum count of steps to simulate.");
|
||||
out.println(" If 0, negative or not specified, there is no maximum.");
|
||||
out.println(" $<reg> -- where <reg> is number or name (e.g. 5, t3, f10) of register whose ");
|
||||
out.println(" content to display at end of run. Option may be repeated.");
|
||||
out.println("<reg_name> -- where <reg_name> is name (e.g. t3, f10) of register whose");
|
||||
out.println(" content to display at end of run. Option may be repeated. ");
|
||||
out.println(" The $ is not required.");
|
||||
out.println("<m>-<n> -- memory address range from <m> to <n> whose contents to");
|
||||
out.println(" display at end of run. <m> and <n> may be hex or decimal,");
|
||||
out.println(" must be on word boundary, <m> <= <n>. Option may be repeated.");
|
||||
out.println(" pa -- Program Arguments follow in a space-separated list. This");
|
||||
out.println(" option must be placed AFTER ALL FILE NAMES, because everything");
|
||||
out.println(" that follows it is interpreted as a program argument to be");
|
||||
out.println(" made available to the MIPS program at runtime.");
|
||||
out.println("If more than one filename is listed, the first is assumed to be the main");
|
||||
out.println("unless the global statement label 'main' is defined in one of the files.");
|
||||
out.println("Exception handler not automatically assembled. Add it to the file list.");
|
||||
out.println("Options used here do not affect MARS Settings menu values and vice versa.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,118 @@
|
||||
package mars;
|
||||
import java.awt.*;
|
||||
import javax.swing.*;
|
||||
|
||||
/*
|
||||
Copyright (c) 2003-2010, 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)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Produces MARS splash screen.<br>
|
||||
* Adapted from http://www.java-tips.org/content/view/1267/2/<br>
|
||||
*/
|
||||
|
||||
public class MarsSplashScreen extends JWindow {
|
||||
|
||||
private int duration;
|
||||
|
||||
public MarsSplashScreen(int d) {
|
||||
duration = d;
|
||||
}
|
||||
|
||||
/**
|
||||
* A simple little method to show a title screen in the center
|
||||
* of the screen for the amount of time given in the constructor
|
||||
*/
|
||||
public void showSplash() {
|
||||
ImageBackgroundPanel content = new ImageBackgroundPanel();
|
||||
this.setContentPane(content);
|
||||
|
||||
// Set the window's bounds, centering the window
|
||||
// Wee bit of a hack. I've hardcoded the image dimensions of
|
||||
// MarsSurfacePathfinder.jpg, because obtaining them via
|
||||
// getHeight() and getWidth() is not trival -- it is possible
|
||||
// that at the time of the call the image has not completed
|
||||
// loading so the Image object doesn't know how big it is.
|
||||
// So observers are involved -- see the API.
|
||||
int width = 390;
|
||||
int height =215;
|
||||
Toolkit tk = Toolkit.getDefaultToolkit();
|
||||
Dimension screen = tk.getScreenSize();
|
||||
int x = (screen.width-width)/2;
|
||||
int y = (screen.height-height)/2;
|
||||
setBounds(x,y,width,height);
|
||||
|
||||
// Build the splash screen
|
||||
JLabel title = new JLabel("MARS: Mips Assembler and Runtime Simulator", JLabel.CENTER);
|
||||
JLabel copyrt1 = new JLabel
|
||||
("<html><br><br>Version "+Globals.version+" Copyright (c) "+Globals.copyrightYears+"</html>", JLabel.CENTER);
|
||||
JLabel copyrt2 = new JLabel
|
||||
("<html><br><br>"+Globals.copyrightHolders+"</html>", JLabel.CENTER);
|
||||
title.setFont(new Font("Sans-Serif", Font.BOLD, 16));
|
||||
title.setForeground(Color.black);
|
||||
copyrt1.setFont(new Font("Sans-Serif", Font.BOLD, 14));
|
||||
copyrt2.setFont(new Font("Sans-Serif", Font.BOLD, 14));
|
||||
copyrt1.setForeground(Color.white);
|
||||
copyrt2.setForeground(Color.white);
|
||||
|
||||
content.add(title,BorderLayout.NORTH);
|
||||
content.add(copyrt1,BorderLayout.CENTER);
|
||||
content.add(copyrt2,BorderLayout.SOUTH);
|
||||
|
||||
// Display it
|
||||
setVisible(true);
|
||||
// Wait a little while, maybe while loading resources
|
||||
try { Thread.sleep(duration); }
|
||||
catch (Exception e) {}
|
||||
setVisible(false);
|
||||
}
|
||||
|
||||
class ImageBackgroundPanel extends JPanel
|
||||
{
|
||||
Image image;
|
||||
public ImageBackgroundPanel()
|
||||
{
|
||||
try
|
||||
{
|
||||
image = new ImageIcon(Toolkit.getDefaultToolkit().getImage(this.getClass().getResource(Globals.imagesPath+"MarsSurfacePathfinder.jpg"))).getImage();
|
||||
}
|
||||
catch (Exception e) {System.out.println(e); /*handled in paintComponent()*/ }
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintComponent(Graphics g)
|
||||
{
|
||||
super.paintComponent(g);
|
||||
if (image != null)
|
||||
g.drawImage(image, 0,0,this.getWidth(),this.getHeight(),this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,133 @@
|
||||
package mars;
|
||||
import mars.util.*;
|
||||
import mars.mips.hardware.*;
|
||||
import mars.mips.instructions.Instruction;
|
||||
import mars.simulator.*;
|
||||
|
||||
/*
|
||||
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)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class to represent error that occurs while assembling or running a MIPS program.
|
||||
*
|
||||
* @author Pete Sanderson
|
||||
* @version August 2003
|
||||
**/
|
||||
|
||||
public class ProcessingException extends Exception {
|
||||
private ErrorList errs;
|
||||
|
||||
/**
|
||||
* Constructor for ProcessingException.
|
||||
*
|
||||
* @param e An ErrorList which is an ArrayList of ErrorMessage objects. Each ErrorMessage
|
||||
* represents one processing error.
|
||||
**/
|
||||
public ProcessingException(ErrorList e) {
|
||||
errs = e;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for ProcessingException.
|
||||
*
|
||||
* @param e An ErrorList which is an ArrayList of ErrorMessage objects. Each ErrorMessage
|
||||
* represents one processing error.
|
||||
* @param aee AddressErrorException object containing specialized error message, cause, address
|
||||
**/
|
||||
public ProcessingException(ErrorList e, AddressErrorException aee) {
|
||||
errs = e;
|
||||
Exceptions.setRegisters(aee.getType(), aee.getAddress());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for ProcessingException to handle runtime exceptions
|
||||
*
|
||||
* @param ps a ProgramStatement of statement causing runtime exception
|
||||
* @param m a String containing specialized error message
|
||||
**/
|
||||
public ProcessingException(ProgramStatement ps, String m) {
|
||||
errs = new ErrorList();
|
||||
errs.add(new ErrorMessage(ps, "Runtime exception at "+
|
||||
Binary.intToHexString(RegisterFile.getProgramCounter()-Instruction.INSTRUCTION_LENGTH)+
|
||||
": "+m));
|
||||
// Stopped using ps.getAddress() because of pseudo-instructions. All instructions in
|
||||
// the macro expansion point to the same ProgramStatement, and thus all will return the
|
||||
// same value for getAddress(). But only the first such expanded instruction will
|
||||
// be stored at that address. So now I use the program counter (which has already
|
||||
// been incremented).
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Constructor for ProcessingException to handle runtime exceptions
|
||||
*
|
||||
* @param ps a ProgramStatement of statement causing runtime exception
|
||||
* @param m a String containing specialized error message
|
||||
* @param cause exception cause (see Exceptions class for list)
|
||||
**/
|
||||
public ProcessingException(ProgramStatement ps, String m, int cause) {
|
||||
this(ps,m);
|
||||
Exceptions.setRegisters(cause);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Constructor for ProcessingException to handle address runtime exceptions
|
||||
*
|
||||
* @param ps a ProgramStatement of statement causing runtime exception
|
||||
* @param aee AddressErrorException object containing specialized error message, cause, address
|
||||
**/
|
||||
|
||||
public ProcessingException(ProgramStatement ps, AddressErrorException aee) {
|
||||
this(ps, aee.getMessage());
|
||||
Exceptions.setRegisters(aee.getType(), aee.getAddress());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for ProcessingException.
|
||||
*
|
||||
* No parameter and thus no error list. Use this for normal MIPS
|
||||
* program termination (e.g. syscall 10 for exit).
|
||||
**/
|
||||
public ProcessingException() {
|
||||
errs = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Produce the list of error messages.
|
||||
*
|
||||
* @return Returns ErrorList of error messages.
|
||||
* @see ErrorList
|
||||
* @see ErrorMessage
|
||||
**/
|
||||
|
||||
public ErrorList errors() {
|
||||
return errs;
|
||||
}
|
||||
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,730 @@
|
||||
package mars;
|
||||
import mars.assembler.*;
|
||||
import mars.mips.instructions.*;
|
||||
import mars.mips.hardware.*;
|
||||
import mars.util.*;
|
||||
import java.util.*;
|
||||
|
||||
/*
|
||||
Copyright (c) 2003-2013, 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)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Represents one assembly/machine statement. This represents the "bare machine" level.
|
||||
* Pseudo-instructions have already been processed at this point and each assembly
|
||||
* statement generated by them is one of these.
|
||||
*
|
||||
* @author Pete Sanderson and Jason Bumgarner
|
||||
* @version August 2003
|
||||
*/
|
||||
|
||||
|
||||
public class ProgramStatement {
|
||||
private MIPSprogram sourceMIPSprogram;
|
||||
private String source, basicAssemblyStatement, machineStatement;
|
||||
private TokenList originalTokenList, strippedTokenList;
|
||||
private BasicStatementList basicStatementList;
|
||||
private int[] operands;
|
||||
private int numOperands;
|
||||
private Instruction instruction;
|
||||
private int textAddress;
|
||||
private int sourceLine;
|
||||
private int binaryStatement;
|
||||
private boolean altered;
|
||||
private static final String invalidOperator = "<INVALID>";
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Constructor for ProgramStatement when there are links back to all source and token
|
||||
* information. These can be used by a debugger later on.
|
||||
* @param sourceMIPSprogram The MIPSprogram object that contains this statement
|
||||
* @param source The corresponding MIPS source statement.
|
||||
* @param origTokenList Complete list of Token objects (includes labels, comments, parentheses, etc)
|
||||
* @param strippedTokenList List of Token objects with all but operators and operands removed.
|
||||
* @param inst The Instruction object for this statement's operator.
|
||||
* @param textAddress The Text Segment address in memory where the binary machine code for this statement
|
||||
* is stored.
|
||||
**/
|
||||
public ProgramStatement(MIPSprogram sourceMIPSprogram, String source, TokenList origTokenList, TokenList strippedTokenList,
|
||||
Instruction inst, int textAddress, int sourceLine) {
|
||||
this.sourceMIPSprogram = sourceMIPSprogram;
|
||||
this.source = source;
|
||||
this.originalTokenList = origTokenList;
|
||||
this.strippedTokenList = strippedTokenList;
|
||||
this.operands = new int[4];
|
||||
this.numOperands = 0;
|
||||
this.instruction = inst;
|
||||
this.textAddress = textAddress;
|
||||
this.sourceLine = sourceLine;
|
||||
this.basicAssemblyStatement = null;
|
||||
this.basicStatementList = new BasicStatementList();
|
||||
this.machineStatement = null;
|
||||
this.binaryStatement = 0; // nop, or sll $0, $0, 0 (32 bits of 0's)
|
||||
this.altered = false;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Constructor for ProgramStatement used only for writing a binary machine
|
||||
* instruction with no source code to refer back to. Originally supported
|
||||
* only NOP instruction (all zeroes), but extended in release 4.4 to support
|
||||
* all basic instructions. This was required for the self-modifying code
|
||||
* feature.
|
||||
* @param binaryStatement The 32-bit machine code.
|
||||
* @param textAddress The Text Segment address in memory where the binary machine code for this statement
|
||||
* is stored.
|
||||
**/
|
||||
public ProgramStatement(int binaryStatement, int textAddress) {
|
||||
this.sourceMIPSprogram = null;
|
||||
this.binaryStatement = binaryStatement;
|
||||
this.textAddress = textAddress;
|
||||
this.originalTokenList = this.strippedTokenList = null;
|
||||
this.source = "";
|
||||
this.machineStatement = this.basicAssemblyStatement = null;
|
||||
BasicInstruction instr = Globals.instructionSet.findByBinaryCode(binaryStatement);
|
||||
if (instr == null) {
|
||||
this.operands = null;
|
||||
this.numOperands = 0;
|
||||
this.instruction = (binaryStatement==0) // this is a "nop" statement
|
||||
? (Instruction) Globals.instructionSet.matchOperator("nop").get(0)
|
||||
: null;
|
||||
}
|
||||
else {
|
||||
this.operands = new int[4];
|
||||
this.numOperands = 0;
|
||||
this.instruction = instr;
|
||||
|
||||
String opandCodes = "fst";
|
||||
String fmt = instr.getOperationMask();
|
||||
BasicInstructionFormat instrFormat = instr.getInstructionFormat();
|
||||
int numOps = 0;
|
||||
for (int i = 0; i < opandCodes.length(); i++) {
|
||||
int code = opandCodes.charAt(i);
|
||||
int j = fmt.indexOf(code);
|
||||
if (j >= 0) {
|
||||
int k0 = 31 - fmt.lastIndexOf(code);
|
||||
int k1 = 31 - j;
|
||||
int opand = (binaryStatement >> k0) & ((1 << (k1 - k0 + 1)) - 1);
|
||||
if (instrFormat.equals(BasicInstructionFormat.I_BRANCH_FORMAT) && numOps == 2) {
|
||||
opand = opand << 16 >> 16;
|
||||
}
|
||||
else if (instrFormat.equals(BasicInstructionFormat.J_FORMAT) && numOps == 0) {
|
||||
opand |= (textAddress >> 2) & 0x3C000000;
|
||||
}
|
||||
this.operands[numOps] = opand;
|
||||
numOps++;
|
||||
}
|
||||
}
|
||||
this.numOperands = numOps;
|
||||
}
|
||||
this.altered = false;
|
||||
this.basicStatementList = buildBasicStatementListFromBinaryCode(binaryStatement, instr, operands, numOperands);
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Given specification of BasicInstruction for this operator, build the
|
||||
* corresponding assembly statement in basic assembly format (e.g. substituting
|
||||
* register numbers for register names, replacing labels by values).
|
||||
* @param errors The list of assembly errors encountered so far. May add to it here.
|
||||
**/
|
||||
public void buildBasicStatementFromBasicInstruction(ErrorList errors) {
|
||||
Token token = strippedTokenList.get(0);
|
||||
String basicStatementElement = token.getValue()+" ";;
|
||||
String basic = basicStatementElement;
|
||||
basicStatementList.addString(basicStatementElement); // the operator
|
||||
TokenTypes tokenType, nextTokenType;
|
||||
String tokenValue;
|
||||
int registerNumber;
|
||||
this.numOperands = 0;
|
||||
for (int i=1; i<strippedTokenList.size(); i++) {
|
||||
token = strippedTokenList.get(i);
|
||||
tokenType = token.getType();
|
||||
tokenValue = token.getValue();
|
||||
if (tokenType == TokenTypes.REGISTER_NUMBER) {
|
||||
basicStatementElement = tokenValue;
|
||||
basic += basicStatementElement;
|
||||
basicStatementList.addString(basicStatementElement);
|
||||
try {
|
||||
registerNumber = RegisterFile.getUserRegister(tokenValue).getNumber();
|
||||
}
|
||||
catch (Exception e) {
|
||||
// should never happen; should be caught before now...
|
||||
errors.add(new ErrorMessage(this.sourceMIPSprogram, token.getSourceLine(), token.getStartPos(),"invalid register name"));
|
||||
return;
|
||||
}
|
||||
this.operands[this.numOperands++] = registerNumber;
|
||||
}
|
||||
else if (tokenType == TokenTypes.REGISTER_NAME) {
|
||||
registerNumber = RegisterFile.getNumber(tokenValue);
|
||||
basicStatementElement = "$" + registerNumber;
|
||||
basic += basicStatementElement;
|
||||
basicStatementList.addString(basicStatementElement);
|
||||
if (registerNumber < 0) {
|
||||
// should never happen; should be caught before now...
|
||||
errors.add(new ErrorMessage(this.sourceMIPSprogram, token.getSourceLine(), token.getStartPos(),"invalid register name"));
|
||||
return;
|
||||
}
|
||||
this.operands[this.numOperands++] = registerNumber;
|
||||
}
|
||||
else if (tokenType == TokenTypes.FP_REGISTER_NAME) {
|
||||
registerNumber = Coprocessor1.getRegisterNumber(tokenValue);
|
||||
basicStatementElement = "$f" + registerNumber;
|
||||
basic += basicStatementElement;
|
||||
basicStatementList.addString(basicStatementElement);
|
||||
if (registerNumber < 0) {
|
||||
// should never happen; should be caught before now...
|
||||
errors.add(new ErrorMessage(this.sourceMIPSprogram, token.getSourceLine(), token.getStartPos(),"invalid FPU register name"));
|
||||
return;
|
||||
}
|
||||
this.operands[this.numOperands++] = registerNumber;
|
||||
}
|
||||
else if (tokenType == TokenTypes.IDENTIFIER) {
|
||||
int address = this.sourceMIPSprogram.getLocalSymbolTable().getAddressLocalOrGlobal(tokenValue);
|
||||
if (address == SymbolTable.NOT_FOUND) { // symbol used without being defined
|
||||
errors.add(new ErrorMessage(this.sourceMIPSprogram, token.getSourceLine(), token.getStartPos(),
|
||||
"Symbol \""+tokenValue+"\" not found in symbol table."));
|
||||
return;
|
||||
}
|
||||
boolean absoluteAddress = true; // (used below)
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// added code 12-20-2004. If basic instruction with I_BRANCH format, then translate
|
||||
// address from absolute to relative and shift left 2.
|
||||
//
|
||||
// DPS 14 June 2007: Apply delayed branching if enabled. This adds 4 bytes to the
|
||||
// address used to calculate branch distance in relative words.
|
||||
//
|
||||
// DPS 4 January 2008: Apply the delayed branching 4-byte (instruction length) addition
|
||||
// regardless of whether delayed branching is enabled or not. This was in response to
|
||||
// several people complaining about machine code not matching that from the COD3 example
|
||||
// on p 98-99. In that example, the branch offset reflect delayed branching because
|
||||
// all MIPS machines implement delayed branching. But the topic of delayed branching
|
||||
// is not yet introduced at that point, and instructors want to avoid the messiness
|
||||
// that comes along with it. Our original strategy was to do it like SPIM does, which
|
||||
// the June 2007 mod (shown below as commented-out assignment to address) does.
|
||||
// This mod must be made in conjunction with InstructionSet.java's processBranch()
|
||||
// method. There are some comments there as well.
|
||||
|
||||
if (instruction instanceof BasicInstruction) {
|
||||
BasicInstructionFormat format = ((BasicInstruction)instruction).getInstructionFormat();
|
||||
if (format == BasicInstructionFormat.I_BRANCH_FORMAT) {
|
||||
//address = (address - (this.textAddress+((Globals.getSettings().getDelayedBranchingEnabled())? Instruction.INSTRUCTION_LENGTH : 0))) >> 2;
|
||||
address = (address - (this.textAddress+Instruction.INSTRUCTION_LENGTH)) >> 2;
|
||||
absoluteAddress = false;
|
||||
}
|
||||
}
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
basic += address;
|
||||
if (absoluteAddress) { // record as address if absolute, value if relative
|
||||
basicStatementList.addAddress(address);
|
||||
}
|
||||
else {
|
||||
basicStatementList.addValue(address);
|
||||
}
|
||||
this.operands[this.numOperands++] = address;
|
||||
}
|
||||
else if (tokenType == TokenTypes.INTEGER_5 || tokenType == TokenTypes.INTEGER_16 ||
|
||||
tokenType == TokenTypes.INTEGER_16U || tokenType == TokenTypes.INTEGER_32) {
|
||||
|
||||
int tempNumeric = Binary.stringToInt(tokenValue);
|
||||
|
||||
/***************************************************************************
|
||||
* MODIFICATION AND COMMENT, DPS 3-July-2008
|
||||
*
|
||||
* The modifications of January 2005 documented below are being rescinded.
|
||||
* All hexadecimal immediate values are considered 32 bits in length and
|
||||
* their classification as INTEGER_5, INTEGER_16, INTEGER_16U (new)
|
||||
* or INTEGER_32 depends on their 32 bit value. So 0xFFFF will be
|
||||
* equivalent to 0x0000FFFF instead of 0xFFFFFFFF. This change, along with
|
||||
* the introduction of INTEGER_16U (adopted from Greg Gibeling of Berkeley),
|
||||
* required extensive changes to instruction templates especially for
|
||||
* pseudo-instructions.
|
||||
*
|
||||
* This modification also appears inbuildBasicStatementFromBasicInstruction()
|
||||
* in mars.ProgramStatement.
|
||||
*
|
||||
* ///// Begin modification 1/4/05 KENV ///////////////////////////////////////////
|
||||
* // We have decided to interpret non-signed (no + or -) 16-bit hexadecimal immediate
|
||||
* // operands as signed values in the range -32768 to 32767. So 0xffff will represent
|
||||
* // -1, not 65535 (bit 15 as sign bit), 0x8000 will represent -32768 not 32768.
|
||||
* // NOTE: 32-bit hexadecimal immediate operands whose values fall into this range
|
||||
* // will be likewise affected, but they are used only in pseudo-instructions. The
|
||||
* // code in ExtendedInstruction.java to split this number into upper 16 bits for "lui"
|
||||
* // and lower 16 bits for "ori" works with the original source code token, so it is
|
||||
* // not affected by this tweak. 32-bit immediates in data segment directives
|
||||
* // are also processed elsewhere so are not affected either.
|
||||
* ////////////////////////////////////////////////////////////////////////////////
|
||||
*
|
||||
* if (tokenType != TokenTypes.INTEGER_16U) { // part of the Berkeley mod...
|
||||
* if ( Binary.isHex(tokenValue) &&
|
||||
* (tempNumeric >= 32768) &&
|
||||
* (tempNumeric <= 65535) ) // Range 0x8000 ... 0xffff
|
||||
* {
|
||||
* // Subtract the 0xffff bias, because strings in the
|
||||
* // range "0x8000" ... "0xffff" are used to represent
|
||||
* // 16-bit negative numbers, not positive numbers.
|
||||
* tempNumeric = tempNumeric - 65536;
|
||||
* // Note: no action needed for range 0xffff8000 ... 0xffffffff
|
||||
* }
|
||||
* }
|
||||
************************** END DPS 3-July-2008 COMMENTS *******************************/
|
||||
|
||||
basic += tempNumeric;
|
||||
basicStatementList.addValue(tempNumeric);
|
||||
this.operands[this.numOperands++] = tempNumeric;
|
||||
///// End modification 1/7/05 KENV ///////////////////////////////////////////
|
||||
}
|
||||
else {
|
||||
basicStatementElement = tokenValue;
|
||||
basic += basicStatementElement;
|
||||
basicStatementList.addString(basicStatementElement);
|
||||
}
|
||||
// add separator if not at end of token list AND neither current nor
|
||||
// next token is a parenthesis
|
||||
if ((i < strippedTokenList.size()-1)) {
|
||||
nextTokenType = strippedTokenList.get(i+1).getType();
|
||||
if (tokenType != TokenTypes.LEFT_PAREN && tokenType != TokenTypes.RIGHT_PAREN &&
|
||||
nextTokenType != TokenTypes.LEFT_PAREN && nextTokenType != TokenTypes.RIGHT_PAREN)
|
||||
{
|
||||
basicStatementElement = ",";
|
||||
basic += basicStatementElement;
|
||||
basicStatementList.addString(basicStatementElement);
|
||||
}
|
||||
}
|
||||
}
|
||||
this.basicAssemblyStatement = basic;
|
||||
} //buildBasicStatementFromBasicInstruction()
|
||||
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Given the current statement in Basic Assembly format (see above), build the
|
||||
* 32-bit binary machine code statement.
|
||||
* @param errors The list of assembly errors encountered so far. May add to it here.
|
||||
**/
|
||||
public void buildMachineStatementFromBasicStatement(ErrorList errors) {
|
||||
|
||||
try {
|
||||
//mask indicates bit positions for 'f'irst, 's'econd, 't'hird operand
|
||||
this.machineStatement = ((BasicInstruction)instruction).getOperationMask();
|
||||
} // This means the pseudo-instruction expansion generated another
|
||||
// pseudo-instruction (expansion must be to all basic instructions).
|
||||
// This is an error on the part of the pseudo-instruction author.
|
||||
catch (ClassCastException cce) {
|
||||
errors.add(new ErrorMessage(this.sourceMIPSprogram,this.sourceLine,0,
|
||||
"INTERNAL ERROR: pseudo-instruction expansion contained a pseudo-instruction"));
|
||||
return;
|
||||
}
|
||||
BasicInstructionFormat format = ((BasicInstruction)instruction).getInstructionFormat();
|
||||
|
||||
if (format == BasicInstructionFormat.J_FORMAT) {
|
||||
if ((this.textAddress & 0xF0000000) != (this.operands[0] & 0xF0000000)) {
|
||||
// attempt to jump beyond 28-bit byte (26-bit word) address range.
|
||||
// SPIM flags as warning, I'll flag as error b/c MARS text segment not long enough for it to be OK.
|
||||
errors.add(new ErrorMessage(this.sourceMIPSprogram, this.sourceLine, 0,
|
||||
"Jump target word address beyond 26-bit range"));
|
||||
return;
|
||||
}
|
||||
// Note the bit shift to make this a word address.
|
||||
this.operands[0] = this.operands[0] >>> 2;
|
||||
this.insertBinaryCode(this.operands[0], Instruction.operandMask[0], errors);
|
||||
}
|
||||
else if (format == BasicInstructionFormat.I_BRANCH_FORMAT) {
|
||||
for (int i=0; i<this.numOperands-1; i++) {
|
||||
this.insertBinaryCode(this.operands[i], Instruction.operandMask[i], errors);
|
||||
}
|
||||
this.insertBinaryCode(operands[this.numOperands-1], Instruction.operandMask[this.numOperands-1], errors);
|
||||
}
|
||||
else { // R_FORMAT or I_FORMAT
|
||||
for (int i=0; i<this.numOperands; i++)
|
||||
this.insertBinaryCode(this.operands[i], Instruction.operandMask[i], errors);
|
||||
}
|
||||
this.binaryStatement = Binary.binaryStringToInt(this.machineStatement);
|
||||
return;
|
||||
} // buildMachineStatementFromBasicStatement(
|
||||
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Crude attempt at building String representation of this complex structure.
|
||||
* @return A String representing the ProgramStatement.
|
||||
**/
|
||||
|
||||
public String toString() {
|
||||
// a crude attempt at string formatting. Where's C when you need it?
|
||||
String blanks = " ";
|
||||
String result = "["+this.textAddress+"]";
|
||||
if (this.basicAssemblyStatement != null) {
|
||||
int firstSpace = this.basicAssemblyStatement.indexOf(" ");
|
||||
result += blanks.substring(0, 16-result.length()) + this.basicAssemblyStatement.substring(0,firstSpace);
|
||||
result += blanks.substring(0, 24-result.length()) + this.basicAssemblyStatement.substring(firstSpace+1);;
|
||||
}
|
||||
else {
|
||||
result += blanks.substring(0, 16 - result.length()) + "0x" + Integer.toString(this.binaryStatement, 16);
|
||||
}
|
||||
result += blanks.substring(0, 40-result.length()) + "; "; // this.source;
|
||||
if (operands != null) {
|
||||
for (int i=0; i<this.numOperands; i++)
|
||||
// result += operands[i] + " ";
|
||||
result += Integer.toString(operands[i], 16) + " ";
|
||||
}
|
||||
if (this.machineStatement != null) {
|
||||
result += "["+Binary.binaryStringToHexString(this.machineStatement)+"]";
|
||||
result += " "+this.machineStatement.substring(0,6)+"|" + this.machineStatement.substring(6,11)+"|"+
|
||||
this.machineStatement.substring(11,16)+"|" + this.machineStatement.substring(16,21)+"|"+
|
||||
this.machineStatement.substring(21,26)+"|" + this.machineStatement.substring(26,32);
|
||||
}
|
||||
return result;
|
||||
} // toString()
|
||||
|
||||
/**
|
||||
* Assigns given String to be Basic Assembly statement equivalent to this source line.
|
||||
* @param statement A String containing equivalent Basic Assembly statement.
|
||||
**/
|
||||
|
||||
public void setBasicAssemblyStatement(String statement) {
|
||||
basicAssemblyStatement = statement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns given String to be binary machine code (32 characters, all of them 0 or 1)
|
||||
* equivalent to this source line.
|
||||
* @param statement A String containing equivalent machine code.
|
||||
**/
|
||||
|
||||
public void setMachineStatement(String statement) {
|
||||
machineStatement = statement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns given int to be binary machine code equivalent to this source line.
|
||||
* @param binaryCode An int containing equivalent binary machine code.
|
||||
**/
|
||||
|
||||
public void setBinaryStatement(int binaryCode) {
|
||||
binaryStatement = binaryCode;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* associates MIPS source statement. Used by assembler when generating basic
|
||||
* statements during macro expansion of extended statement.
|
||||
* @param src a MIPS source statement.
|
||||
**/
|
||||
|
||||
public void setSource(String src) {
|
||||
source = src;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Produces MIPSprogram object representing the source file containing this statement.
|
||||
* @return The MIPSprogram object. May be null...
|
||||
**/
|
||||
public MIPSprogram getSourceMIPSprogram() {
|
||||
return sourceMIPSprogram;
|
||||
}
|
||||
|
||||
/**
|
||||
* Produces String name of the source file containing this statement.
|
||||
* @return The file name.
|
||||
**/
|
||||
public String getSourceFile() {
|
||||
return (sourceMIPSprogram == null) ? "" : sourceMIPSprogram.getFilename();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Produces MIPS source statement.
|
||||
* @return The MIPS source statement.
|
||||
**/
|
||||
|
||||
public String getSource() {
|
||||
return source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Produces line number of MIPS source statement.
|
||||
* @return The MIPS source statement line number.
|
||||
**/
|
||||
|
||||
public int getSourceLine() {
|
||||
return sourceLine;
|
||||
}
|
||||
|
||||
/**
|
||||
* Produces Basic Assembly statement for this MIPS source statement.
|
||||
* All numeric values are in decimal.
|
||||
* @return The Basic Assembly statement.
|
||||
**/
|
||||
|
||||
public String getBasicAssemblyStatement() {
|
||||
return basicAssemblyStatement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Produces printable Basic Assembly statement for this MIPS source
|
||||
* statement. This is generated dynamically and any addresses and
|
||||
* values will be rendered in hex or decimal depending on the current
|
||||
* setting.
|
||||
* @return The Basic Assembly statement.
|
||||
**/
|
||||
public String getPrintableBasicAssemblyStatement() {
|
||||
return basicStatementList.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Produces binary machine statement as 32 character string, all '0' and '1' chars.
|
||||
* @return The String version of 32-bit binary machine code.
|
||||
**/
|
||||
|
||||
public String getMachineStatement() {
|
||||
return machineStatement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Produces 32-bit binary machine statement as int.
|
||||
* @return The int version of 32-bit binary machine code.
|
||||
**/
|
||||
public int getBinaryStatement() {
|
||||
return binaryStatement;
|
||||
}
|
||||
/**
|
||||
* Produces token list generated from original source statement.
|
||||
* @return The TokenList of Token objects generated from original source.
|
||||
**/
|
||||
public TokenList getOriginalTokenList() {
|
||||
return originalTokenList;
|
||||
}
|
||||
/**
|
||||
* Produces token list stripped of all but operator and operand tokens.
|
||||
* @return The TokenList of Token objects generated by stripping original list of all
|
||||
* except operator and operand tokens.
|
||||
**/
|
||||
public TokenList getStrippedTokenList() {
|
||||
return strippedTokenList;
|
||||
}
|
||||
/**
|
||||
* Produces Instruction object corresponding to this statement's operator.
|
||||
* @return The Instruction that matches the operator used in this statement.
|
||||
**/
|
||||
public Instruction getInstruction() {
|
||||
return instruction;
|
||||
}
|
||||
/**
|
||||
* Produces Text Segment address where the binary machine statement is stored.
|
||||
* @return address in Text Segment of this binary machine statement.
|
||||
**/
|
||||
public int getAddress() {
|
||||
return textAddress;
|
||||
}
|
||||
/**
|
||||
* Produces int array of operand values for this statement.
|
||||
* @return int array of operand values (if any) required by this statement's operator.
|
||||
**/
|
||||
public int[] getOperands() {
|
||||
return operands;
|
||||
}
|
||||
/**
|
||||
* Produces operand value from given array position (first operand is position 0).
|
||||
*
|
||||
* @param i Operand position in array (first operand is position 0).
|
||||
* @return Operand value at given operand array position. If < 0 or >= numOperands, it returns -1.
|
||||
**/
|
||||
public int getOperand(int i) {
|
||||
if (i >= 0 && i < this.numOperands) {
|
||||
return operands[i];
|
||||
}
|
||||
else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// Given operand (register or integer) and mask character ('f', 's', or 't'),
|
||||
// generate the correct sequence of bits and replace the mask with them.
|
||||
private void insertBinaryCode(int value, char mask, ErrorList errors) {
|
||||
int startPos = this.machineStatement.indexOf(mask);
|
||||
int endPos = this.machineStatement.lastIndexOf(mask);
|
||||
if (startPos == -1 || endPos == -1) { // should NEVER occur
|
||||
errors.add(new ErrorMessage(this.sourceMIPSprogram,this.sourceLine,0,
|
||||
"INTERNAL ERROR: mismatch in number of operands in statement vs mask"));
|
||||
return;
|
||||
}
|
||||
String bitString = Binary.intToBinaryString(value, endPos-startPos+1);
|
||||
String state = this.machineStatement.substring(0, startPos) + bitString;
|
||||
if (endPos < this.machineStatement.length()-1)
|
||||
state = state + this.machineStatement.substring(endPos+1);
|
||||
this.machineStatement = state;
|
||||
return;
|
||||
} // insertBinaryCode()
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/*
|
||||
* Given a model BasicInstruction and the assembled (not source) operand array for a statement,
|
||||
* this method will construct the corresponding basic instruction list. This method is
|
||||
* used by the constructor that is given only the int address and binary code. It is not
|
||||
* intended to be used when source code is available. DPS 11-July-2013
|
||||
*/
|
||||
private BasicStatementList buildBasicStatementListFromBinaryCode(int binary, BasicInstruction instr, int[] operands, int numOperands) {
|
||||
BasicStatementList statementList = new BasicStatementList();
|
||||
int tokenListCounter = 1; // index 0 is operator; operands start at index 1
|
||||
if (instr == null) {
|
||||
statementList.addString(invalidOperator);
|
||||
return statementList;
|
||||
}
|
||||
else {
|
||||
statementList.addString(instr.getName()+" ");
|
||||
}
|
||||
for (int i=0; i<numOperands;i++) {
|
||||
// add separator if not at end of token list AND neither current nor
|
||||
// next token is a parenthesis
|
||||
if (tokenListCounter > 1 && tokenListCounter<instr.getTokenList().size()) {
|
||||
TokenTypes thisTokenType = instr.getTokenList().get(tokenListCounter).getType();
|
||||
if (thisTokenType != TokenTypes.LEFT_PAREN && thisTokenType != TokenTypes.RIGHT_PAREN) {
|
||||
statementList.addString(",");
|
||||
}
|
||||
}
|
||||
boolean notOperand = true;
|
||||
while (notOperand && tokenListCounter<instr.getTokenList().size()) {
|
||||
TokenTypes tokenType = instr.getTokenList().get(tokenListCounter).getType();
|
||||
if (tokenType.equals(TokenTypes.LEFT_PAREN)) {
|
||||
statementList.addString("(");
|
||||
}
|
||||
else if (tokenType.equals(TokenTypes.RIGHT_PAREN)) {
|
||||
statementList.addString(")");
|
||||
}
|
||||
else if (tokenType.toString().contains("REGISTER")) {
|
||||
String marker = (tokenType.toString().contains("FP_REGISTER")) ? "$f" : "$";
|
||||
statementList.addString(marker+operands[i]);
|
||||
notOperand = false;
|
||||
}
|
||||
else {
|
||||
statementList.addValue(operands[i]);
|
||||
notOperand = false;
|
||||
}
|
||||
tokenListCounter++;
|
||||
}
|
||||
}
|
||||
while (tokenListCounter<instr.getTokenList().size()) {
|
||||
TokenTypes tokenType = instr.getTokenList().get(tokenListCounter).getType();
|
||||
if (tokenType.equals(TokenTypes.LEFT_PAREN)) {
|
||||
statementList.addString("(");
|
||||
}
|
||||
else if (tokenType.equals(TokenTypes.RIGHT_PAREN)) {
|
||||
statementList.addString(")");
|
||||
}
|
||||
tokenListCounter++;
|
||||
}
|
||||
return statementList;
|
||||
} // buildBasicStatementListFromBinaryCode()
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////
|
||||
//
|
||||
// Little class to represent basic statement as list
|
||||
// of elements. Each element is either a string, an
|
||||
// address or a value. The toString() method will
|
||||
// return a string representation of the basic statement
|
||||
// in which any addresses or values are rendered in the
|
||||
// current number format (e.g. decimal or hex).
|
||||
//
|
||||
// NOTE: Address operands on Branch instructions are
|
||||
// considered values instead of addresses because they
|
||||
// are relative to the PC.
|
||||
//
|
||||
// DPS 29-July-2010
|
||||
|
||||
private class BasicStatementList {
|
||||
|
||||
private ArrayList list;
|
||||
|
||||
BasicStatementList() {
|
||||
list = new ArrayList();
|
||||
}
|
||||
|
||||
void addString(String string) {
|
||||
list.add(new ListElement(0, string, 0));
|
||||
}
|
||||
|
||||
void addAddress(int address) {
|
||||
list.add(new ListElement(1, null, address));
|
||||
}
|
||||
|
||||
void addValue(int value) {
|
||||
list.add(new ListElement(2, null, value));
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
int addressBase = (Globals.getSettings().getBooleanSetting(Settings.DISPLAY_ADDRESSES_IN_HEX)) ? mars.venus.NumberDisplayBaseChooser.HEXADECIMAL : mars.venus.NumberDisplayBaseChooser.DECIMAL;
|
||||
int valueBase = (Globals.getSettings().getBooleanSetting(Settings.DISPLAY_VALUES_IN_HEX)) ? mars.venus.NumberDisplayBaseChooser.HEXADECIMAL : mars.venus.NumberDisplayBaseChooser.DECIMAL;
|
||||
|
||||
StringBuffer result = new StringBuffer();
|
||||
for (int i=0; i<list.size(); i++) {
|
||||
ListElement e = (ListElement) list.get(i);
|
||||
switch (e.type) {
|
||||
case 0 :
|
||||
result.append(e.sValue);
|
||||
break;
|
||||
case 1 :
|
||||
result.append(mars.venus.NumberDisplayBaseChooser.formatNumber(e.iValue, addressBase));
|
||||
break;
|
||||
case 2 :
|
||||
if (valueBase == mars.venus.NumberDisplayBaseChooser.HEXADECIMAL) {
|
||||
result.append(mars.util.Binary.intToHexString(e.iValue)); // 13-July-2011, was: intToHalfHexString()
|
||||
}
|
||||
else {
|
||||
result.append(mars.venus.NumberDisplayBaseChooser.formatNumber(e.iValue, valueBase));
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
private class ListElement {
|
||||
int type;
|
||||
String sValue;
|
||||
int iValue;
|
||||
ListElement(int type, String sValue, int iValue) {
|
||||
this.type = type;
|
||||
this.sValue = sValue;
|
||||
this.iValue = iValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Binary file not shown.
+1408
File diff suppressed because it is too large
Load Diff
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@@ -0,0 +1,131 @@
|
||||
package mars.assembler;
|
||||
|
||||
/*
|
||||
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)
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Information about MIPS data types.
|
||||
* @author Pete Sanderson
|
||||
* @version August 2003
|
||||
**/
|
||||
|
||||
public final class DataTypes {
|
||||
/** Number of bytes occupied by MIPS double is 8. **/
|
||||
public static final int DOUBLE_SIZE = 8;
|
||||
/** Number of bytes occupied by MIPS float is 4. **/
|
||||
public static final int FLOAT_SIZE = 4;
|
||||
/** Number of bytes occupied by MIPS word is 4. **/
|
||||
public static final int WORD_SIZE = 4;
|
||||
/** Number of bytes occupied by MIPS halfword is 2. **/
|
||||
public static final int HALF_SIZE = 2;
|
||||
/** Number of bytes occupied by MIPS byte is 1. **/
|
||||
public static final int BYTE_SIZE = 1;
|
||||
/** Number of bytes occupied by MIPS character is 1. **/
|
||||
public static final int CHAR_SIZE = 1;
|
||||
/** Maximum value that can be stored in a MIPS word is 2<sup>31</sup>-1 **/
|
||||
public static final int MAX_WORD_VALUE = Integer.MAX_VALUE;
|
||||
/** Lowest value that can be stored in a MIPS word is -2<sup>31</sup> **/
|
||||
public static final int MIN_WORD_VALUE = Integer.MIN_VALUE;
|
||||
/** Maximum value that can be stored in a MIPS halfword is 2<sup>15</sup>-1 **/
|
||||
public static final int MAX_HALF_VALUE = 32767; //(int)Math.pow(2,15) - 1;
|
||||
/** Lowest value that can be stored in a MIPS halfword is -2<sup>15</sup> **/
|
||||
public static final int MIN_HALF_VALUE = -32768; //0 - (int) Math.pow(2,15);
|
||||
/** Maximum value that can be stored in an unsigned MIPS halfword is 2<sup>16</sup>-1 **/
|
||||
public static final int MAX_UHALF_VALUE = 65535;
|
||||
/** Lowest value that can be stored in na unsigned MIPS halfword is 0 **/
|
||||
public static final int MIN_UHALF_VALUE = 0;
|
||||
/** Maximum value that can be stored in a MIPS byte is 2<sup>7</sup>-1 **/
|
||||
public static final int MAX_BYTE_VALUE = Byte.MAX_VALUE;
|
||||
/** Lowest value that can be stored in a MIPS byte is -2<sup>7</sup> **/
|
||||
public static final int MIN_BYTE_VALUE = Byte.MIN_VALUE;
|
||||
/** Maximum positive finite value that can be stored in a MIPS float is same as Java Float **/
|
||||
public static final double MAX_FLOAT_VALUE = Float.MAX_VALUE;
|
||||
/** Largest magnitude negative value that can be stored in a MIPS float (negative of the max) **/
|
||||
public static final double LOW_FLOAT_VALUE = -Float.MAX_VALUE;
|
||||
/** Maximum positive finite value that can be stored in a MIPS double is same as Java Double **/
|
||||
public static final double MAX_DOUBLE_VALUE = Double.MAX_VALUE;
|
||||
/** Largest magnitude negative value that can be stored in a MIPS double(negative of the max) **/
|
||||
public static final double LOW_DOUBLE_VALUE = -Double.MAX_VALUE;
|
||||
|
||||
/**
|
||||
* Get length in bytes for numeric MIPS directives.
|
||||
* @param direct Directive to be measured.
|
||||
* @return Returns length in bytes for values of that type. If type is not numeric
|
||||
* (or not implemented yet), returns 0.
|
||||
**/
|
||||
|
||||
public static int getLengthInBytes(Directives direct) {
|
||||
if (direct == Directives.FLOAT)
|
||||
return FLOAT_SIZE;
|
||||
else if (direct == Directives.DOUBLE)
|
||||
return DOUBLE_SIZE;
|
||||
else if (direct == Directives.WORD)
|
||||
return WORD_SIZE;
|
||||
else if (direct == Directives.HALF)
|
||||
return HALF_SIZE;
|
||||
else if (direct == Directives.BYTE)
|
||||
return BYTE_SIZE;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determines whether given integer value falls within value range for given directive.
|
||||
* @param direct Directive that controls storage allocation for value.
|
||||
* @param value The value to be stored.
|
||||
* @return Returns <tt>true</tt> if value can be stored in the number of bytes allowed
|
||||
* by the given directive (.word, .half, .byte), <tt>false</tt> otherwise.
|
||||
**/
|
||||
public static boolean outOfRange(Directives direct, int value) {
|
||||
if (direct == Directives.HALF && (value < MIN_HALF_VALUE || value > MAX_HALF_VALUE))
|
||||
return true;
|
||||
else if (direct == Directives.BYTE && (value < MIN_BYTE_VALUE || value > MAX_BYTE_VALUE))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether given floating point value falls within value range for given directive.
|
||||
* For float, this refers to range of the data type, not precision. Example: 1.23456789012345
|
||||
* be stored in a float with loss of precision. It's within the range. But 1.23e500 cannot be
|
||||
* stored in a float because the exponent 500 is too large (float allows 8 bits for exponent).
|
||||
* @param direct Directive that controls storage allocation for value.
|
||||
* @param value The value to be stored.
|
||||
* @return Returns <tt>true</tt> if value is within range of
|
||||
* the given directive (.float, .double), <tt>false</tt> otherwise.
|
||||
**/
|
||||
public static boolean outOfRange(Directives direct, double value) {
|
||||
if (direct == Directives.FLOAT && (value < LOW_FLOAT_VALUE || value > MAX_FLOAT_VALUE))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,190 @@
|
||||
package mars.assembler;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/*
|
||||
Copyright (c) 2003-2012, 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)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class representing MIPS assembler directives. If Java had enumerated types, these
|
||||
* would probably be implemented that way. Each directive is represented by a unique object.
|
||||
* The directive name is indicative of the directive it represents. For example, DATA
|
||||
* represents the MIPS .data directive.
|
||||
*
|
||||
* @author Pete Sanderson
|
||||
* @version August 2003
|
||||
**/
|
||||
|
||||
public final class Directives {
|
||||
|
||||
private static ArrayList directiveList = new ArrayList();
|
||||
public static final Directives DATA = new Directives(".data", "Subsequent items stored in Data segment at next available address");
|
||||
public static final Directives TEXT = new Directives(".text", "Subsequent items (instructions) stored in Text segment at next available address");
|
||||
public static final Directives WORD = new Directives(".word", "Store the listed value(s) as 32 bit words on word boundary");
|
||||
public static final Directives ASCII = new Directives(".ascii", "Store the string in the Data segment but do not add null terminator");
|
||||
public static final Directives ASCIIZ = new Directives(".asciiz", "Store the string in the Data segment and add null terminator");
|
||||
public static final Directives BYTE = new Directives(".byte", "Store the listed value(s) as 8 bit bytes");
|
||||
public static final Directives ALIGN = new Directives(".align", "Align next data item on specified byte boundary (0=byte, 1=half, 2=word, 3=double)");
|
||||
public static final Directives HALF = new Directives(".half", "Store the listed value(s) as 16 bit halfwords on halfword boundary");
|
||||
public static final Directives SPACE = new Directives(".space", "Reserve the next specified number of bytes in Data segment");
|
||||
public static final Directives DOUBLE = new Directives(".double", "Store the listed value(s) as double precision floating point");
|
||||
public static final Directives FLOAT = new Directives(".float", "Store the listed value(s) as single precision floating point");
|
||||
public static final Directives EXTERN = new Directives(".extern", "Declare the listed label and byte length to be a global data field");
|
||||
public static final Directives KDATA = new Directives(".kdata", "Subsequent items stored in Kernel Data segment at next available address");
|
||||
public static final Directives KTEXT = new Directives(".ktext", "Subsequent items (instructions) stored in Kernel Text segment at next available address");
|
||||
public static final Directives GLOBL = new Directives(".globl", "Declare the listed label(s) as global to enable referencing from other files");
|
||||
public static final Directives SET = new Directives(".set", "Set assembler variables. Currently ignored but included for SPIM compatability");
|
||||
/* EQV added by DPS 11 July 2012 */
|
||||
public static final Directives EQV = new Directives(".eqv", "Substitute second operand for first. First operand is symbol, second operand is expression (like #define)");
|
||||
/* MACRO and END_MACRO added by Mohammad Sekhavat Oct 2012 */
|
||||
public static final Directives MACRO = new Directives(".macro", "Begin macro definition. See .end_macro");
|
||||
public static final Directives END_MACRO = new Directives(".end_macro", "End macro definition. See .macro");
|
||||
/* INCLUDE added by DPS 11 Jan 2013 */
|
||||
public static final Directives INCLUDE = new Directives(".include", "Insert the contents of the specified file. Put filename in quotes.");
|
||||
|
||||
|
||||
private String descriptor;
|
||||
private String description; // help text
|
||||
|
||||
private Directives() {
|
||||
// private ctor assures no objects can be created other than those above.
|
||||
this.descriptor = "generic";
|
||||
this.description = "";
|
||||
directiveList.add(this);
|
||||
}
|
||||
|
||||
private Directives(String name, String description) {
|
||||
this.descriptor = name;
|
||||
this.description = description;
|
||||
directiveList.add(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find Directive object, if any, which matches the given String.
|
||||
*
|
||||
* @param str A String containing candidate directive name (e.g. ".ascii")
|
||||
* @return If match is found, returns matching Directives object, else returns <tt>null</tt>.
|
||||
**/
|
||||
|
||||
public static Directives matchDirective(String str) {
|
||||
Directives match;
|
||||
for (int i=0; i<directiveList.size(); i++) {
|
||||
match = (Directives) directiveList.get(i);
|
||||
if (str.equalsIgnoreCase(match.descriptor)) {
|
||||
return match;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Find Directive object, if any, which contains the given string as a prefix. For example,
|
||||
* ".a" will match ".ascii", ".asciiz" and ".align"
|
||||
*
|
||||
* @param str A String
|
||||
* @return If match is found, returns ArrayList of matching Directives objects, else returns <tt>null</tt>.
|
||||
**/
|
||||
|
||||
public static ArrayList prefixMatchDirectives(String str) {
|
||||
ArrayList matches = null;
|
||||
for (int i=0; i<directiveList.size(); i++) {
|
||||
if (((Directives) directiveList.get(i)).descriptor.toLowerCase().startsWith(str.toLowerCase())) {
|
||||
if (matches == null) {
|
||||
matches = new ArrayList();
|
||||
}
|
||||
matches.add(directiveList.get(i));
|
||||
}
|
||||
}
|
||||
return matches;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Produces String-ified version of Directive object
|
||||
*
|
||||
* @return String representing Directive: its MIPS name
|
||||
**/
|
||||
|
||||
public String toString() {
|
||||
return this.descriptor;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get name of this Directives object
|
||||
*
|
||||
* @return name of this MIPS directive as a String
|
||||
**/
|
||||
|
||||
public String getName() {
|
||||
return this.descriptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get description of this Directives object
|
||||
*
|
||||
* @return description of this MIPS directive (for help purposes)
|
||||
**/
|
||||
|
||||
public String getDescription() {
|
||||
return this.description;
|
||||
}
|
||||
|
||||
/**
|
||||
* Produces List of Directive objects
|
||||
*
|
||||
* @return MIPS Directive
|
||||
**/
|
||||
public static ArrayList getDirectiveList() {
|
||||
return directiveList;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Lets you know whether given directive is for integer (WORD,HALF,BYTE).
|
||||
*
|
||||
* @param direct a MIPS directive
|
||||
* @return true if given directive is FLOAT or DOUBLE, false otherwise
|
||||
**/
|
||||
public static boolean isIntegerDirective(Directives direct) {
|
||||
return direct == Directives.WORD || direct == Directives.HALF || direct == Directives.BYTE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Lets you know whether given directive is for floating number (FLOAT,DOUBLE).
|
||||
*
|
||||
* @param direct a MIPS directive
|
||||
* @return true if given directive is FLOAT or DOUBLE, false otherwise.
|
||||
**/
|
||||
public static boolean isFloatingDirective(Directives direct) {
|
||||
return direct == Directives.FLOAT || direct == Directives.DOUBLE;
|
||||
}
|
||||
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,254 @@
|
||||
package mars.assembler;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
||||
import mars.ErrorList;
|
||||
import mars.ErrorMessage;
|
||||
import mars.MIPSprogram;
|
||||
import mars.mips.hardware.RegisterFile;
|
||||
import mars.mips.hardware.Coprocessor0;
|
||||
import mars.mips.hardware.Coprocessor1;
|
||||
|
||||
/*
|
||||
Copyright (c) 2013-2014.
|
||||
|
||||
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)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Stores information of a macro definition.
|
||||
*
|
||||
* @author M.H.Sekhavat <sekhavat17@gmail.com>
|
||||
*/
|
||||
public class Macro {
|
||||
private String name;
|
||||
private MIPSprogram program;
|
||||
private ArrayList<String> labels;
|
||||
|
||||
/**
|
||||
* first and last line number of macro definition. first line starts with
|
||||
* .macro directive and last line is .end_macro directive.
|
||||
*/
|
||||
private int fromLine, toLine;
|
||||
private int origFromLine, origToLine;
|
||||
/**
|
||||
* arguments like <code>%arg</code> will be substituted by macro expansion
|
||||
*/
|
||||
private ArrayList<String> args;
|
||||
|
||||
public Macro() {
|
||||
name = "";
|
||||
program = null;
|
||||
fromLine = toLine = 0;
|
||||
origFromLine = origToLine = 0;
|
||||
args = new ArrayList<String>();
|
||||
labels = new ArrayList<String>();
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public MIPSprogram getProgram() {
|
||||
return program;
|
||||
}
|
||||
|
||||
public void setProgram(MIPSprogram program) {
|
||||
this.program = program;
|
||||
}
|
||||
|
||||
public int getFromLine() {
|
||||
return fromLine;
|
||||
}
|
||||
|
||||
public int getOriginalFromLine() {
|
||||
return this.origFromLine;
|
||||
}
|
||||
|
||||
public void setFromLine(int fromLine) {
|
||||
this.fromLine = fromLine;
|
||||
}
|
||||
|
||||
public void setOriginalFromLine(int origFromLine) {
|
||||
this.origFromLine = origFromLine;
|
||||
}
|
||||
|
||||
public int getToLine() {
|
||||
return toLine;
|
||||
}
|
||||
|
||||
public int getOriginalToLine() {
|
||||
return this.origToLine;
|
||||
}
|
||||
|
||||
public void setToLine(int toLine) {
|
||||
this.toLine = toLine;
|
||||
}
|
||||
|
||||
public void setOriginalToLine(int origToLine) {
|
||||
this.origToLine = origToLine;
|
||||
}
|
||||
|
||||
public ArrayList<String> getArgs() {
|
||||
return args;
|
||||
}
|
||||
|
||||
public void setArgs(ArrayList<String> args) {
|
||||
this.args = args;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param obj
|
||||
* {@link Macro} object to check if their name and count of
|
||||
* arguments are same
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof Macro) {
|
||||
Macro macro = (Macro) obj;
|
||||
return macro.getName().equals(name) && (macro.args.size() == args.size());
|
||||
}
|
||||
return super.equals(obj);
|
||||
}
|
||||
|
||||
public void addArg(String value) {
|
||||
args.add(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Substitutes macro arguments in a line of source code inside macro
|
||||
* definition to be parsed after macro expansion. <br>
|
||||
* Also appends "_M#" to all labels defined inside macro body where # is value of <code>counter</code>
|
||||
*
|
||||
* @param line
|
||||
* source line number in macro definition to be substituted
|
||||
* @param args
|
||||
* @param counter
|
||||
* unique macro expansion id
|
||||
* @param errors
|
||||
* @return <code>line</code>-th line of source code, with substituted
|
||||
* arguments
|
||||
*/
|
||||
|
||||
public String getSubstitutedLine(int line, TokenList args, long counter, ErrorList errors) {
|
||||
TokenList tokens = (TokenList) program.getTokenList().get(line - 1);
|
||||
String s = program.getSourceLine(line);
|
||||
|
||||
for (int i = tokens.size() - 1; i >= 0; i--) {
|
||||
Token token = tokens.get(i);
|
||||
if (tokenIsMacroParameter(token.getValue(), true)) {
|
||||
int repl = -1;
|
||||
for (int j = 0; j < this.args.size(); j++) {
|
||||
if (this.args.get(j).equals(token.getValue())) {
|
||||
repl = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
String substitute = token.getValue();
|
||||
if (repl != -1)
|
||||
substitute = args.get(repl + 1).toString();
|
||||
else {
|
||||
errors.add(new ErrorMessage(program, token.getSourceLine(),
|
||||
token.getStartPos(), "Unknown macro parameter"));
|
||||
}
|
||||
s = replaceToken(s, token, substitute);
|
||||
}
|
||||
else if (tokenIsMacroLabel(token.getValue())){
|
||||
String substitute = token.getValue()+"_M"+counter;
|
||||
s=replaceToken(s, token, substitute);
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* returns true if <code>value</code> is name of a label defined in this macro's body.
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
private boolean tokenIsMacroLabel(String value) {
|
||||
return (Collections.binarySearch(labels, value)>=0);
|
||||
}
|
||||
|
||||
/**
|
||||
* replaces token <code>tokenToBeReplaced</code> which is occured in <code>source</code> with <code>substitute</code>.
|
||||
* @param source
|
||||
* @param tokenToBeReplaced
|
||||
* @param substitute
|
||||
* @return
|
||||
*/
|
||||
// Initially the position of the substitute was based on token position but that proved problematic
|
||||
// in that the source string does not always match the token list from which the token comes. The
|
||||
// token list has already had .eqv equivalences applied whereas the source may not. This is because
|
||||
// the source comes from a macro definition? That has proven to be a tough question to answer.
|
||||
// DPS 12-feb-2013
|
||||
private String replaceToken(String source, Token tokenToBeReplaced, String substitute) {
|
||||
String stringToBeReplaced = tokenToBeReplaced.getValue();
|
||||
int pos = source.indexOf(stringToBeReplaced);
|
||||
return (pos < 0) ? source : source.substring(0, pos) + substitute + source.substring(pos+stringToBeReplaced.length());
|
||||
}
|
||||
|
||||
/**
|
||||
* returns whether <code>tokenValue</code> is macro parameter or not
|
||||
* @param tokenValue
|
||||
* @param acceptSpimStyleParameters accepts SPIM-style parameters which begin with '$' if true
|
||||
* @return
|
||||
*/
|
||||
public static boolean tokenIsMacroParameter(String tokenValue, boolean acceptSpimStyleParameters) {
|
||||
if (acceptSpimStyleParameters) {
|
||||
// Bug fix: SPIM accepts parameter names that start with $ instead of %. This can
|
||||
// lead to problems since register names also start with $. This IF condition
|
||||
// should filter out register names. Originally filtered those from regular set but not
|
||||
// from Coprocessor0 or Coprocessor1 register sets. Expanded the condition.
|
||||
// DPS 7-July-2014.
|
||||
if (tokenValue.length() > 0 && tokenValue.charAt(0) == '$' &&
|
||||
RegisterFile.getUserRegister(tokenValue) == null &&
|
||||
Coprocessor0.getRegister(tokenValue) == null && // added 7-July-2014
|
||||
Coprocessor1.getRegister(tokenValue) == null) // added 7-July-2014
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return tokenValue.length() > 1 && tokenValue.charAt(0) == '%';
|
||||
}
|
||||
|
||||
public void addLabel(String value) {
|
||||
labels.add(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Operations to be done on this macro before it is committed in macro pool.
|
||||
*/
|
||||
public void readyForCommit() {
|
||||
Collections.sort(labels);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,202 @@
|
||||
package mars.assembler;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Stack;
|
||||
|
||||
import mars.ErrorList;
|
||||
import mars.MIPSprogram;
|
||||
|
||||
/*
|
||||
Copyright (c) 2013.
|
||||
|
||||
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)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Stores information of macros defined by now. <br>
|
||||
* Will be used in first pass of assembling MIPS source code. When reached
|
||||
* <code>.macro</code> directive, parser calls
|
||||
* {@link MacroPool#BeginMacro(String, int)} and skips source code lines until
|
||||
* reaches <code>.end_macro</code> directive. then calls
|
||||
* {@link MacroPool#CommitMacro(int)} and the macro information stored in a
|
||||
* {@link Macro} instance will be added to {@link #macroList}. <br>
|
||||
* Each {@link MIPSprogram} will have one {@link MacroPool}<br>
|
||||
* NOTE: Forward referencing macros (macro expansion before its definition in
|
||||
* source code) and Nested macro definition (defining a macro inside other macro
|
||||
* definition) are not supported.
|
||||
*
|
||||
* @author M.H.Sekhavat <sekhavat17@gmail.com>
|
||||
*/
|
||||
public class MacroPool {
|
||||
private MIPSprogram program;
|
||||
/**
|
||||
* List of macros defined by now
|
||||
*/
|
||||
private ArrayList<Macro> macroList;
|
||||
/**
|
||||
* @see #BeginMacro(String, int)
|
||||
*/
|
||||
private Macro current;
|
||||
private ArrayList<Integer> callStack;
|
||||
private ArrayList<Integer> callStackOrigLines;
|
||||
/**
|
||||
* @see #getNextCounter()
|
||||
*/
|
||||
private int counter;
|
||||
|
||||
|
||||
/**
|
||||
* Create an empty MacroPool for given program
|
||||
* @param mipsProgram associated MIPS program
|
||||
*/
|
||||
public MacroPool(MIPSprogram mipsProgram) {
|
||||
this.program = mipsProgram;
|
||||
macroList = new ArrayList<Macro>();
|
||||
callStack=new ArrayList<Integer>();
|
||||
callStackOrigLines=new ArrayList<Integer>();
|
||||
current = null;
|
||||
counter = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will be called by parser when reached <code>.macro</code>
|
||||
* directive.<br>
|
||||
* Instantiates a new {@link Macro} object and stores it in {@link #current}
|
||||
* . {@link #current} will be added to {@link #macroList} by
|
||||
* {@link #CommitMacro(int)}
|
||||
*
|
||||
* @param nameToken
|
||||
* Token containing name of macro after <code>.macro</code> directive
|
||||
*/
|
||||
|
||||
public void beginMacro(Token nameToken) {
|
||||
current = new Macro();
|
||||
current.setName(nameToken.getValue());
|
||||
current.setFromLine(nameToken.getSourceLine());
|
||||
current.setOriginalFromLine(nameToken.getOriginalSourceLine());
|
||||
current.setProgram(program);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will be called by parser when reached <code>.end_macro</code>
|
||||
* directive. <br>
|
||||
* Adds/Replaces {@link #current} macro into the {@link #macroList}.
|
||||
*
|
||||
* @param endToken
|
||||
* Token containing <code>.end_macro</code> directive in source code
|
||||
*/
|
||||
|
||||
public void commitMacro(Token endToken) {
|
||||
current.setToLine(endToken.getSourceLine());
|
||||
current.setOriginalToLine(endToken.getOriginalSourceLine());
|
||||
current.readyForCommit();
|
||||
macroList.add(current);
|
||||
current = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Will be called by parser when reaches a macro expansion call
|
||||
*
|
||||
* @param tokens
|
||||
* tokens passed to macro expansion call
|
||||
* @return {@link Macro} object matching the name and argument count of
|
||||
* tokens passed
|
||||
*/
|
||||
public Macro getMatchingMacro(TokenList tokens, int callerLine) {
|
||||
if (tokens.size() < 1)
|
||||
return null;
|
||||
Macro ret = null;
|
||||
Token firstToken = tokens.get(0);
|
||||
for (Macro macro : macroList) {
|
||||
if (macro.getName().equals(firstToken.getValue())
|
||||
&& macro.getArgs().size() + 1 == tokens.size()
|
||||
//&& macro.getToLine() < callerLine // condition removed; doesn't work nicely in conjunction with .include, and does not seem necessary. DPS 8-MAR-2013
|
||||
&& (ret == null || ret.getFromLine() < macro.getFromLine()))
|
||||
ret = macro;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param value
|
||||
* @return true if any macros have been defined with name <code>value</code>
|
||||
* by now, not concerning arguments count.
|
||||
*/
|
||||
public boolean matchesAnyMacroName(String value) {
|
||||
for (Macro macro : macroList)
|
||||
if (macro.getName().equals(value))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public Macro getCurrent() {
|
||||
return current;
|
||||
}
|
||||
|
||||
public void setCurrent(Macro current) {
|
||||
this.current = current;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link #counter} will be set to 0 on construction of this class and will
|
||||
* be incremented by each call. parser calls this method once for every
|
||||
* expansions. it will be a unique id for each expansion of macro in a file
|
||||
*
|
||||
* @return counter value
|
||||
*/
|
||||
public int getNextCounter() {
|
||||
return counter++;
|
||||
}
|
||||
|
||||
|
||||
public ArrayList<Integer> getCallStack() {
|
||||
return callStack;
|
||||
}
|
||||
|
||||
|
||||
public boolean pushOnCallStack(Token token) { //returns true if detected expansion loop
|
||||
int sourceLine = token.getSourceLine();
|
||||
int origSourceLine = token.getOriginalSourceLine();
|
||||
if (callStack.contains(sourceLine))
|
||||
return true;
|
||||
callStack.add(sourceLine);
|
||||
callStackOrigLines.add(origSourceLine);
|
||||
return false;
|
||||
}
|
||||
|
||||
public void popFromCallStack() {
|
||||
callStack.remove(callStack.size()-1);
|
||||
callStackOrigLines.remove(callStackOrigLines.size()-1);
|
||||
}
|
||||
|
||||
|
||||
public String getExpansionHistory() {
|
||||
String ret="";
|
||||
for (int i=0; i<callStackOrigLines.size(); i++){
|
||||
if (i>0)
|
||||
ret+="->";
|
||||
ret+=callStackOrigLines.get(i).toString();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,198 @@
|
||||
package mars.assembler;
|
||||
import mars.*;
|
||||
import mars.util.Binary;
|
||||
import mars.mips.instructions.*;
|
||||
import java.util.*;
|
||||
|
||||
/*
|
||||
Copyright (c) 2003-2008, 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)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Provides utility method related to MIPS operand formats.
|
||||
*
|
||||
* @author Pete Sanderson
|
||||
* @version August 2003
|
||||
*/
|
||||
|
||||
|
||||
public class OperandFormat {
|
||||
|
||||
private OperandFormat() {
|
||||
}
|
||||
|
||||
/*
|
||||
* Syntax test for correct match in both numbers and types of operands.
|
||||
*
|
||||
* @param candidateList List of tokens generated from programmer's MIPS statement.
|
||||
* @param spec The (resumably best matched) MIPS instruction.
|
||||
* @param errors ErrorList into which any error messages generated here will be added.
|
||||
*
|
||||
* @return Returns <tt>true</tt> if the programmer's statement matches the MIPS
|
||||
* specification, else returns <tt>false</tt>.
|
||||
*/
|
||||
|
||||
static boolean tokenOperandMatch(TokenList candidateList, Instruction inst, ErrorList errors) {
|
||||
if (!numOperandsCheck(candidateList, inst, errors))
|
||||
return false;
|
||||
if (!operandTypeCheck(candidateList, inst, errors))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* If candidate operator token matches more than one instruction mnemonic, then select
|
||||
* first such Instruction that has an exact operand match. If none match,
|
||||
* return the first Instruction and let client deal with operand mismatches.
|
||||
*/
|
||||
static Instruction bestOperandMatch(TokenList tokenList, ArrayList instrMatches) {
|
||||
if (instrMatches == null)
|
||||
return null;
|
||||
if (instrMatches.size() == 1)
|
||||
return (Instruction) instrMatches.get(0);
|
||||
for (int i=0; i<instrMatches.size(); i++) {
|
||||
Instruction potentialMatch = (Instruction) instrMatches.get(i);
|
||||
if (tokenOperandMatch(tokenList, potentialMatch, new ErrorList()))
|
||||
return potentialMatch;
|
||||
}
|
||||
return (Instruction) instrMatches.get(0);
|
||||
}
|
||||
|
||||
// Simply check to see if numbers of operands are correct and generate error message if not.
|
||||
private static boolean numOperandsCheck(TokenList cand, Instruction spec, ErrorList errors) {
|
||||
int numOperands = cand.size()-1;
|
||||
int reqNumOperands = spec.getTokenList().size()-1;
|
||||
Token operator = cand.get(0);
|
||||
if (numOperands == reqNumOperands) {
|
||||
return true;
|
||||
}
|
||||
else if (numOperands < reqNumOperands) {
|
||||
String mess = "Too few or incorrectly formatted operands. Expected: "+spec.getExampleFormat();
|
||||
generateMessage(operator, mess, errors);
|
||||
}
|
||||
else {
|
||||
String mess = "Too many or incorrectly formatted operands. Expected: "+spec.getExampleFormat();
|
||||
generateMessage(operator, mess, errors);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Generate error message if operand is not of correct type for this operation & operand position
|
||||
private static boolean operandTypeCheck(TokenList cand, Instruction spec, ErrorList errors) {
|
||||
Token candToken, specToken;
|
||||
TokenTypes candType, specType;
|
||||
for (int i=1; i<spec.getTokenList().size(); i++) {
|
||||
candToken = cand.get(i);
|
||||
specToken = spec.getTokenList().get(i);
|
||||
candType = candToken.getType();
|
||||
specType = specToken.getType();
|
||||
// Type mismatch is error EXCEPT when (1) spec calls for register name and candidate is
|
||||
// register number, (2) spec calls for register number, candidate is register name and
|
||||
// names are permitted, (3)spec calls for integer of specified max bit length and
|
||||
// candidate is integer of smaller bit length.
|
||||
// Type match is error when spec calls for register name, candidate is register name, and
|
||||
// names are not permitted.
|
||||
|
||||
// added 2-July-2010 DPS
|
||||
// Not an error if spec calls for identifier and candidate is operator, since operator names can be used as labels.
|
||||
if (specType == TokenTypes.IDENTIFIER && candType == TokenTypes.OPERATOR) {
|
||||
Token replacement = new Token(TokenTypes.IDENTIFIER, candToken.getValue(), candToken.getSourceMIPSprogram(), candToken.getSourceLine(), candToken.getStartPos());
|
||||
cand.set(i, replacement);
|
||||
continue;
|
||||
}
|
||||
// end 2-July-2010 addition
|
||||
|
||||
if ((specType == TokenTypes.REGISTER_NAME || specType == TokenTypes.REGISTER_NUMBER) &&
|
||||
candType == TokenTypes.REGISTER_NAME) {
|
||||
if (Globals.getSettings().getBareMachineEnabled()) {
|
||||
// On 10-Aug-2010, I noticed this cannot happen since the IDE provides no access
|
||||
// to this setting, whose default value is false.
|
||||
generateMessage(candToken, "Use register number instead of name. See Settings.", errors);
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (specType == TokenTypes.REGISTER_NAME &&
|
||||
candType == TokenTypes.REGISTER_NUMBER)
|
||||
continue;
|
||||
if ((specType == TokenTypes.INTEGER_16 && candType == TokenTypes.INTEGER_5) ||
|
||||
(specType == TokenTypes.INTEGER_16U && candType == TokenTypes.INTEGER_5) ||
|
||||
(specType == TokenTypes.INTEGER_32 && candType == TokenTypes.INTEGER_5) ||
|
||||
(specType == TokenTypes.INTEGER_32 && candType == TokenTypes.INTEGER_16U) ||
|
||||
(specType == TokenTypes.INTEGER_32 && candType == TokenTypes.INTEGER_16))
|
||||
continue;
|
||||
if (candType == TokenTypes.INTEGER_16U || candType == TokenTypes.INTEGER_16) {
|
||||
int temp = Binary.stringToInt(candToken.getValue());
|
||||
if (specType == TokenTypes.INTEGER_16 && candType == TokenTypes.INTEGER_16U &&
|
||||
temp>=DataTypes.MIN_HALF_VALUE && temp<=DataTypes.MAX_HALF_VALUE)
|
||||
continue;
|
||||
if (specType == TokenTypes.INTEGER_16U && candType == TokenTypes.INTEGER_16 &&
|
||||
temp>=DataTypes.MIN_UHALF_VALUE && temp<=DataTypes.MAX_UHALF_VALUE)
|
||||
continue;
|
||||
}
|
||||
if ((specType == TokenTypes.INTEGER_5 && candType == TokenTypes.INTEGER_16) ||
|
||||
(specType == TokenTypes.INTEGER_5 && candType == TokenTypes.INTEGER_16U) ||
|
||||
(specType == TokenTypes.INTEGER_5 && candType == TokenTypes.INTEGER_32) ||
|
||||
(specType == TokenTypes.INTEGER_16 && candType == TokenTypes.INTEGER_16U) ||
|
||||
(specType == TokenTypes.INTEGER_16U && candType == TokenTypes.INTEGER_16) ||
|
||||
(specType == TokenTypes.INTEGER_16U && candType == TokenTypes.INTEGER_32) ||
|
||||
(specType == TokenTypes.INTEGER_16 && candType == TokenTypes.INTEGER_32)) {
|
||||
generateMessage(candToken, "operand is out of range", errors);
|
||||
return false;
|
||||
}
|
||||
if (candType != specType) {
|
||||
generateMessage(candToken, "operand is of incorrect type", errors);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/******** nice little debugging code to see which operand format
|
||||
******** the operands for this source code instruction matched.
|
||||
System.out.print("Candidate: ");
|
||||
for (int i=1; i<spec.size(); i++) {
|
||||
System.out.print(cand.get(i).getValue()+" ");
|
||||
}
|
||||
System.out.print("Matched Spec: ");
|
||||
for (int i=1; i<spec.size(); i++) {
|
||||
System.out.print(spec.get(i).getValue()+" ");
|
||||
}
|
||||
System.out.println();
|
||||
*/
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Handy utility for all parse errors...
|
||||
private static void generateMessage(Token token, String mess, ErrorList errors) {
|
||||
errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token.getSourceLine(), token.getStartPos(),
|
||||
"\""+token.getValue()+"\": "+mess));
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,91 @@
|
||||
package mars.assembler;
|
||||
import mars.*;
|
||||
import java.util.*;
|
||||
|
||||
/*
|
||||
Copyright (c) 2003-2013, 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)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Handy class to represent, for a given line of source code, the code
|
||||
* itself, the program containing it, and its line number within that program.
|
||||
* This is used to separately keep track of the original file/position of
|
||||
* a given line of code. When .include is used, it will migrate to a different
|
||||
* line and possibly different program but the migration should not be visible
|
||||
* to the user.
|
||||
*/
|
||||
public class SourceLine {
|
||||
private String source;
|
||||
private String filename;
|
||||
private MIPSprogram mipsProgram;
|
||||
private int lineNumber;
|
||||
|
||||
/**
|
||||
* SourceLine constructor
|
||||
* @param source The source code itself
|
||||
* @param mipsProgram The program (object representing source file) containing that line
|
||||
* @param lineNumber The line number within that program where source appears.
|
||||
*/
|
||||
public SourceLine(String source, MIPSprogram mipsProgram, int lineNumber) {
|
||||
this.source = source;
|
||||
this.mipsProgram = mipsProgram;
|
||||
if (mipsProgram != null)
|
||||
this.filename = mipsProgram.getFilename();
|
||||
this.lineNumber = lineNumber;
|
||||
}
|
||||
/**
|
||||
* Retrieve source statement itself
|
||||
* @return Source statement as String
|
||||
*/
|
||||
public String getSource() {
|
||||
return source;
|
||||
}
|
||||
|
||||
/** Retrieve name of file containing source statement
|
||||
* @return File name as String
|
||||
*/
|
||||
|
||||
public String getFilename() {
|
||||
return filename;
|
||||
}
|
||||
|
||||
/** Retrieve line number of source statement
|
||||
* @return Line number of source statement
|
||||
*/
|
||||
|
||||
public int getLineNumber() {
|
||||
return lineNumber;
|
||||
}
|
||||
|
||||
/** Retrieve MIPSprogram object containing source statement
|
||||
* @return program as MIPSprogram object
|
||||
*/
|
||||
|
||||
public MIPSprogram getMIPSprogram() {
|
||||
return mipsProgram;
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,94 @@
|
||||
package mars.assembler;
|
||||
|
||||
/*
|
||||
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)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Represents a MIPS program identifier to be stored in the symbol table.
|
||||
* @author Jason Bumgarner, Jason Shrewsbury
|
||||
* @version June 2003
|
||||
**/
|
||||
|
||||
public class Symbol{
|
||||
private String name;
|
||||
private int address;
|
||||
private boolean data; // boolean true if data symbol false if text symbol.
|
||||
public static final boolean TEXT_SYMBOL = false;
|
||||
public static final boolean DATA_SYMBOL = true;
|
||||
|
||||
/**
|
||||
* Basic constructor, creates a symbol object.
|
||||
* @param name The name of the Symbol.
|
||||
* @param address The memroy address that the Symbol refers to.
|
||||
* @param data The type of Symbol that it is.
|
||||
**/
|
||||
|
||||
public Symbol(String name, int address, boolean data){
|
||||
this.name = name;
|
||||
this.address = address;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the address of the the Symbol.
|
||||
* @return The address of the Symbol.
|
||||
**/
|
||||
|
||||
public int getAddress(){
|
||||
return this.address;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the label of the the Symbol.
|
||||
* @return The label of the Symbol.
|
||||
**/
|
||||
|
||||
public String getName(){
|
||||
return this.name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the type of symbol, text or data.
|
||||
* @return The type of the data.
|
||||
**/
|
||||
|
||||
public boolean getType(){
|
||||
return this.data;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets (replaces) the address of the the Symbol.
|
||||
* @param newAddress The revised address of the Symbol.
|
||||
**/
|
||||
|
||||
public void setAddress(int newAddress){
|
||||
this.address = newAddress;
|
||||
return;
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,262 @@
|
||||
package mars.assembler;
|
||||
import mars.*;
|
||||
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)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Creats a table of Symbol objects.
|
||||
* @author Jason Bumgarner, Jason Shrewsbury
|
||||
* @version June 2003
|
||||
**/
|
||||
|
||||
public class SymbolTable {
|
||||
private static String startLabel = "main";
|
||||
private String filename;
|
||||
private ArrayList table;
|
||||
// Note -1 is legal 32 bit address (0xFFFFFFFF) but it is the high address in
|
||||
// kernel address space so highly unlikely that any symbol will have this as
|
||||
// its associated address!
|
||||
public static final int NOT_FOUND = -1;
|
||||
|
||||
/**
|
||||
* Create a new empty symbol table for given file
|
||||
* @param filename name of file this symbol table is associated with. Will be
|
||||
* used only for output/display so it can be any descriptive string.
|
||||
*/
|
||||
public SymbolTable(String filename) {
|
||||
this.filename = filename;
|
||||
this.table = new ArrayList();
|
||||
}
|
||||
/**
|
||||
* Adds a Symbol object into the array of Symbols.
|
||||
* @param token The token representing the Symbol.
|
||||
* @param address The address of the Symbol.
|
||||
* @param b The type of Symbol, true for data, false for text.
|
||||
* @param errors List to which to add any processing errors that occur.
|
||||
**/
|
||||
|
||||
public void addSymbol(Token token, int address, boolean b, ErrorList errors) {
|
||||
String label = token.getValue();
|
||||
if (getSymbol(label) != null) {
|
||||
errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token.getSourceLine(),token.getStartPos(),"label \""+label+"\" already defined"));
|
||||
}
|
||||
else {
|
||||
Symbol s= new Symbol(label, address, b);
|
||||
table.add(s);
|
||||
if (Globals.debug) System.out.println("The symbol " + label + " with address " + address + " has been added to the "+this.filename+" symbol table.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Removes a symbol from the Symbol table. If not found, it does nothing.
|
||||
* This will rarely happen (only when variable is declared .globl after already
|
||||
* being defined in the local symbol table).
|
||||
* @param token The token representing the Symbol.
|
||||
**/
|
||||
|
||||
public void removeSymbol(Token token) {
|
||||
String label = token.getValue();
|
||||
for (int i=0; i < table.size(); i++) {
|
||||
if (((Symbol)(table.get(i))).getName().equals(label)){
|
||||
table.remove(i);
|
||||
if (Globals.debug) System.out.println("The symbol " + label + " has been removed from the "+this.filename+" symbol table.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Method to return the address associated with the given label.
|
||||
* @param s The label.
|
||||
* @return The memory address of the label given, or NOT_FOUND if not found in symbol table.
|
||||
**/
|
||||
public int getAddress(String s){
|
||||
for(int i=0; i < table.size(); i++){
|
||||
if (((Symbol)(table.get(i))).getName().equals(s)){
|
||||
return((Symbol) table.get(i)).getAddress();
|
||||
}
|
||||
}
|
||||
return NOT_FOUND;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to return the address associated with the given label. Look first
|
||||
* in this (local) symbol table then in symbol table of labels declared
|
||||
* global (.globl directive).
|
||||
* @param s The label.
|
||||
* @return The memory address of the label given, or NOT_FOUND if not found in symbol table.
|
||||
**/
|
||||
public int getAddressLocalOrGlobal(String s) {
|
||||
int address = this.getAddress(s);
|
||||
return (address==NOT_FOUND) ? Globals.symbolTable.getAddress(s) : address ;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Produce Symbol object from symbol table that corresponds to given String.
|
||||
* @param s target String
|
||||
* @return Symbol object for requested target, null if not found in symbol table.
|
||||
**/
|
||||
|
||||
public Symbol getSymbol(String s){
|
||||
for(int i=0; i < table.size(); i++){
|
||||
if (((Symbol)(table.get(i))).getName().equals(s)){
|
||||
return (Symbol) table.get(i);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Produce Symbol object from symbol table that has the given address.
|
||||
* @param s String representing address
|
||||
* @return Symbol object having requested address, null if address not found in symbol table.
|
||||
**/
|
||||
|
||||
public Symbol getSymbolGivenAddress(String s){
|
||||
int address = 0;
|
||||
try {
|
||||
address = mars.util.Binary.stringToInt(s);// DPS 2-Aug-2010: was Integer.parseInt(s) but croaked on hex
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
return null;
|
||||
}
|
||||
for(int i=0; i < table.size(); i++){
|
||||
if (((Symbol)(table.get(i))).getAddress() == address){
|
||||
return (Symbol) table.get(i);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Produce Symbol object from either local or global symbol table that has the
|
||||
* given address.
|
||||
* @param s String representing address
|
||||
* @return Symbol object having requested address, null if address not found in symbol table.
|
||||
**/
|
||||
public Symbol getSymbolGivenAddressLocalOrGlobal(String s){
|
||||
Symbol sym = this.getSymbolGivenAddress(s);
|
||||
return (sym==null) ? Globals.symbolTable.getSymbolGivenAddress(s) : sym ;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* For obtaining the Data Symbols.
|
||||
* @return An ArrayList of Symbol objects.
|
||||
**/
|
||||
|
||||
public ArrayList getDataSymbols(){
|
||||
ArrayList list= new ArrayList();
|
||||
for(int i=0; i<table.size(); i++){
|
||||
if(((Symbol)table.get(i)).getType()){
|
||||
list.add(table.get(i));
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* For obtaining the Text Symbols.
|
||||
* @return An ArrayList of Symbol objects.
|
||||
**/
|
||||
|
||||
public ArrayList getTextSymbols(){
|
||||
ArrayList list= new ArrayList();
|
||||
for(int i=0; i<table.size(); i++){
|
||||
if(!((Symbol)table.get(i)).getType()){
|
||||
list.add(table.get(i));
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* For obtaining all the Symbols.
|
||||
* @return An ArrayList of Symbol objects.
|
||||
**/
|
||||
|
||||
public ArrayList getAllSymbols(){
|
||||
ArrayList list= new ArrayList();
|
||||
for(int i=0; i<table.size(); i++){
|
||||
list.add(table.get(i));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the count of entries currently in the table.
|
||||
* @return Number of symbol table entries.
|
||||
**/
|
||||
|
||||
public int getSize(){
|
||||
return table.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a fresh arrayList for a new table.
|
||||
**/
|
||||
|
||||
public void clear(){
|
||||
table= new ArrayList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fix address in symbol table entry. Any and all entries that match the original
|
||||
* address will be modified to contain the replacement address. There is no effect,
|
||||
* if none of the addresses matches.
|
||||
* @param originalAddress Address associated with 0 or more symtab entries.
|
||||
* @param replacementAddress Any entry that has originalAddress will have its
|
||||
* address updated to this value. Does nothing if none do.
|
||||
*/
|
||||
|
||||
public void fixSymbolTableAddress(int originalAddress, int replacementAddress) {
|
||||
Symbol label = getSymbolGivenAddress(Integer.toString(originalAddress));
|
||||
while (label != null) {
|
||||
label.setAddress(replacementAddress);
|
||||
label = getSymbolGivenAddress(Integer.toString(originalAddress));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the text segment label (symbol) which, if declared global, indicates
|
||||
* the starting address for execution.
|
||||
* @return String containing global label whose text segment address is starting address for program execution.
|
||||
**/
|
||||
public static String getStartLabel() {
|
||||
return startLabel;
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,176 @@
|
||||
package mars.assembler;
|
||||
import mars.*;
|
||||
|
||||
/*
|
||||
Copyright (c) 2003-2008, 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)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Represents one token in the input MIPS program. Each Token carries, along with its
|
||||
* type and value, the position (line, column) in which its source appears in the MIPS program.
|
||||
*
|
||||
* @author Pete Sanderson
|
||||
* @version August 2003
|
||||
**/
|
||||
|
||||
public class Token {
|
||||
|
||||
private TokenTypes type;
|
||||
private String value;
|
||||
private MIPSprogram sourceMIPSprogram;
|
||||
private int sourceLine, sourcePos;
|
||||
// original program and line will differ from the above if token was defined in an included file
|
||||
private MIPSprogram originalMIPSprogram;
|
||||
private int originalSourceLine;
|
||||
/**
|
||||
* Constructor for Token class.
|
||||
*
|
||||
* @param type The token type that this token has. (e.g. REGISTER_NAME)
|
||||
* @param value The source value for this token (e.g. $t3)
|
||||
* @param sourceMIPSprogram The MIPSprogram object containing this token
|
||||
* @param line The line number in source program in which this token appears.
|
||||
* @param start The starting position in that line number of this token's source value.
|
||||
* @see TokenTypes
|
||||
**/
|
||||
|
||||
public Token(TokenTypes type, String value, MIPSprogram sourceMIPSprogram, int line, int start) {
|
||||
this.type = type;
|
||||
this.value = value;
|
||||
this.sourceMIPSprogram = sourceMIPSprogram;
|
||||
this.sourceLine = line;
|
||||
this.sourcePos = start;
|
||||
this.originalMIPSprogram = sourceMIPSprogram;
|
||||
this.originalSourceLine = line;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set original program and line number for this token.
|
||||
* Line number or both may change during pre-assembly as a result
|
||||
* of the ".include" directive, and we need to keep the original
|
||||
* for later reference (error messages, text segment display).
|
||||
*
|
||||
* @param origProgram MIPS program containing this token.
|
||||
* @param origSourceLine Line within that program of this token.
|
||||
**/
|
||||
public void setOriginal(MIPSprogram origProgram, int origSourceLine) {
|
||||
this.originalMIPSprogram = origProgram;
|
||||
this.originalSourceLine = origSourceLine;
|
||||
}
|
||||
|
||||
/**
|
||||
* Produces original program containing this token.
|
||||
*
|
||||
* @return MIPSprogram of origin for this token.
|
||||
**/
|
||||
public MIPSprogram getOriginalProgram() {
|
||||
return this.originalMIPSprogram;
|
||||
}
|
||||
|
||||
/**
|
||||
* Produces original line number of this token. It could change as result
|
||||
* of ".include"
|
||||
*
|
||||
* @return original line number of this token.
|
||||
**/
|
||||
public int getOriginalSourceLine() {
|
||||
return this.originalSourceLine;
|
||||
}
|
||||
|
||||
/**
|
||||
* Produces token type of this token.
|
||||
*
|
||||
* @return TokenType of this token.
|
||||
**/
|
||||
public TokenTypes getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set or modify token type. Generally used to note that
|
||||
* an identifier that matches an instruction name is
|
||||
* actually being used as a label.
|
||||
*
|
||||
* @param type new TokenTypes for this token.
|
||||
**/
|
||||
public void setType(TokenTypes type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Produces source code of this token.
|
||||
*
|
||||
* @return String containing source code of this token.
|
||||
**/
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a String representing the token. This method is
|
||||
* equivalent to getValue().
|
||||
*
|
||||
* @return String version of the token.
|
||||
*/
|
||||
|
||||
public String toString() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Produces MIPSprogram object associated with this token.
|
||||
*
|
||||
* @return MIPSprogram object associated with this token.
|
||||
**/
|
||||
|
||||
public MIPSprogram getSourceMIPSprogram() {
|
||||
return sourceMIPSprogram;
|
||||
}
|
||||
|
||||
/**
|
||||
* Produces line number of MIPS program of this token.
|
||||
*
|
||||
* @return line number in source program of this token.
|
||||
**/
|
||||
|
||||
public int getSourceLine() {
|
||||
return sourceLine;
|
||||
}
|
||||
|
||||
/**
|
||||
* Produces position within source line of this token.
|
||||
*
|
||||
* @return first character position within source program line of this token.
|
||||
**/
|
||||
|
||||
public int getStartPos() {
|
||||
return sourcePos;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Binary file not shown.
@@ -0,0 +1,181 @@
|
||||
package mars.assembler;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/*
|
||||
Copyright (c) 2003-2013, 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)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Represents the list of tokens in a single line of MIPS code. It uses, but is not
|
||||
* a subclass of, ArrayList.
|
||||
*
|
||||
* @author Pete Sanderson
|
||||
* @version August 2003
|
||||
*/
|
||||
|
||||
public class TokenList implements Cloneable {
|
||||
|
||||
private ArrayList tokenList;
|
||||
private String processedLine;// DPS 03-Jan-2013
|
||||
|
||||
/**
|
||||
* Constructor for objects of class TokenList
|
||||
*/
|
||||
public TokenList() {
|
||||
tokenList = new ArrayList();
|
||||
processedLine = ""; // DPS 03-Jan-2013
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this to record the source line String for this token list
|
||||
* after possible modification (textual substitution) during
|
||||
* assembly preprocessing. The modified source will be displayed in
|
||||
* the Text Segment Display.
|
||||
* @param line The source line, possibly modified (possibly not)
|
||||
*/
|
||||
// DPS 03-Jan-2013
|
||||
public void setProcessedLine(String line) {
|
||||
processedLine = line;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the source line String associated with this
|
||||
* token list. It may or may not have been modified during
|
||||
* assembly preprocessing.
|
||||
* @return The source line for this token list.
|
||||
*/ // DPS 03-Jan-2013/
|
||||
public String getProcessedLine() {
|
||||
return processedLine;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns requested token given position number (starting at 0).
|
||||
*
|
||||
* @param pos Position in token list.
|
||||
* @return the requested token, or ArrayIndexOutOfBounds exception
|
||||
*/
|
||||
public Token get(int pos) {
|
||||
return (Token) tokenList.get(pos);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces token at position with different one. Will throw
|
||||
* ArrayIndexOutOfBounds exception if position does not exist.
|
||||
*
|
||||
* @param pos Position in token list.
|
||||
* @param replacement Replacement token
|
||||
*/
|
||||
public void set(int pos, Token replacement) {
|
||||
tokenList.set(pos, replacement);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns number of tokens in list.
|
||||
*
|
||||
* @return token count.
|
||||
*/
|
||||
public int size() {
|
||||
return tokenList.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a Token object to the end of the list.
|
||||
*
|
||||
* @param token Token object to be added.
|
||||
*/
|
||||
public void add(Token token) {
|
||||
tokenList.add(token);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes Token object at specified list position. Uses ArrayList remove method.
|
||||
*
|
||||
* @param pos Position in token list. Subsequent Tokens are shifted one position left.
|
||||
* @throws IndexOutOfBoundsException if <tt>pos</tt> is < 0 or >= <tt>size()</tt>
|
||||
*/
|
||||
public void remove(int pos) {
|
||||
tokenList.remove(pos);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns empty/non-empty status of list.
|
||||
*
|
||||
* @return <tt>true</tt> if list has no tokens, else <tt>false</tt>.
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
return tokenList.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a String representing the token list.
|
||||
*
|
||||
* @return String version of the token list
|
||||
* (a blank is inserted after each token).
|
||||
*/
|
||||
|
||||
public String toString() {
|
||||
String stringified = "";
|
||||
for (int i=0; i<tokenList.size(); i++) {
|
||||
stringified += tokenList.get(i).toString()+" ";
|
||||
}
|
||||
return stringified;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get a String representing the sequence of token types for this list.
|
||||
*
|
||||
* @return String version of the token types for this list
|
||||
* (a blank is inserted after each token type).
|
||||
*/
|
||||
|
||||
public String toTypeString() {
|
||||
String stringified = "";
|
||||
for (int i=0; i<tokenList.size(); i++) {
|
||||
stringified += ((Token)tokenList.get(i)).getType().toString()+" ";
|
||||
}
|
||||
return stringified;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes clone (shallow copy) of this token list object.
|
||||
*
|
||||
* @return the cloned list.
|
||||
*/
|
||||
// Clones are a bit tricky. super.clone() handles primitives (e.g. values) correctly
|
||||
// but the ArrayList itself has to be cloned separately -- otherwise clone will have
|
||||
// alias to original token list!!
|
||||
public Object clone() {
|
||||
try {
|
||||
TokenList t = (TokenList) super.clone();
|
||||
t.tokenList = (ArrayList) tokenList.clone();
|
||||
return t;
|
||||
} catch (CloneNotSupportedException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,293 @@
|
||||
package mars.assembler;
|
||||
import mars.*;
|
||||
import mars.util.*;
|
||||
import mars.mips.hardware.*;
|
||||
|
||||
/*
|
||||
Copyright (c) 2003-2008, 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)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Constants to identify the types of tokens found in MIPS programs. If Java had
|
||||
* enumerated types, that's how these would probably be implemented.
|
||||
*
|
||||
* @author Pete Sanderson
|
||||
* @version August 2003
|
||||
**/
|
||||
|
||||
public final class TokenTypes {
|
||||
|
||||
public static final String TOKEN_DELIMITERS = "\t ,()";
|
||||
public static final TokenTypes COMMENT = new TokenTypes("COMMENT");
|
||||
public static final TokenTypes DIRECTIVE = new TokenTypes("DIRECTIVE");
|
||||
public static final TokenTypes OPERATOR = new TokenTypes("OPERATOR");
|
||||
public static final TokenTypes DELIMITER = new TokenTypes("DELIMITER");
|
||||
/** note: REGISTER_NAME is token of form $zero whereas REGISTER_NUMBER is token
|
||||
* of form $0. The former is part of extended assembler, and latter is part
|
||||
* of basic assembler.
|
||||
**/
|
||||
public static final TokenTypes REGISTER_NAME = new TokenTypes("REGISTER_NAME"); // mnemonic
|
||||
public static final TokenTypes REGISTER_NUMBER = new TokenTypes("REGISTER_NUMBER");
|
||||
public static final TokenTypes FP_REGISTER_NAME = new TokenTypes("FP_REGISTER_NAME");
|
||||
public static final TokenTypes IDENTIFIER = new TokenTypes("IDENTIFIER");
|
||||
public static final TokenTypes LEFT_PAREN = new TokenTypes("LEFT_PAREN");
|
||||
public static final TokenTypes RIGHT_PAREN = new TokenTypes("RIGHT_PAREN");
|
||||
//public static final TokenTypes INTEGER = new TokenTypes("INTEGER");
|
||||
public static final TokenTypes INTEGER_5 = new TokenTypes("INTEGER_5");
|
||||
public static final TokenTypes INTEGER_16 = new TokenTypes("INTEGER_16");
|
||||
public static final TokenTypes INTEGER_16U = new TokenTypes("INTEGER_16U");
|
||||
public static final TokenTypes INTEGER_32 = new TokenTypes("INTEGER_32");
|
||||
public static final TokenTypes REAL_NUMBER = new TokenTypes("REAL_NUMBER");
|
||||
public static final TokenTypes QUOTED_STRING = new TokenTypes("QUOTED_STRING");
|
||||
public static final TokenTypes PLUS = new TokenTypes("PLUS");
|
||||
public static final TokenTypes MINUS = new TokenTypes("MINUS");
|
||||
public static final TokenTypes COLON = new TokenTypes("COLON");
|
||||
public static final TokenTypes ERROR = new TokenTypes("ERROR");
|
||||
public static final TokenTypes MACRO_PARAMETER = new TokenTypes("MACRO_PARAMETER");
|
||||
|
||||
private String descriptor;
|
||||
|
||||
private TokenTypes() {
|
||||
// private ctor assures no objects can be created other than those above.
|
||||
descriptor = "generic";
|
||||
}
|
||||
|
||||
private TokenTypes(String name) {
|
||||
descriptor = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Produces String equivalent of this token type, which is its name.
|
||||
*
|
||||
* @return String containing descriptive name for token type.
|
||||
**/
|
||||
public String toString() {
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Classifies the given token into one of the MIPS types.
|
||||
*
|
||||
* @param value String containing candidate language element, extracted from MIPS program.
|
||||
*
|
||||
* @return Returns the corresponding TokenTypes object if the parameter matches a
|
||||
* defined MIPS token type, else returns <tt>null</tt>.
|
||||
**/
|
||||
|
||||
public static TokenTypes matchTokenType(String value)
|
||||
{
|
||||
|
||||
TokenTypes type = null;
|
||||
// If it starts with single quote ('), it is a mal-formed character literal
|
||||
// because a well-formed character literal was converted to string-ified
|
||||
// integer before getting here...
|
||||
if (value.charAt(0) == '\'')
|
||||
return TokenTypes.ERROR;
|
||||
|
||||
// See if it is a comment
|
||||
if (value.charAt(0) == '#')
|
||||
return TokenTypes.COMMENT;
|
||||
|
||||
// See if it is one of the simple tokens
|
||||
if (value.length() == 1) {
|
||||
switch (value.charAt(0)) {
|
||||
case '(' :
|
||||
return TokenTypes.LEFT_PAREN;
|
||||
case ')' :
|
||||
return TokenTypes.RIGHT_PAREN;
|
||||
case ':' :
|
||||
return TokenTypes.COLON;
|
||||
case '+' :
|
||||
return TokenTypes.PLUS;
|
||||
case '-' :
|
||||
return TokenTypes.MINUS;
|
||||
}
|
||||
}
|
||||
|
||||
// See if it is a macro parameter
|
||||
if (Macro.tokenIsMacroParameter(value, false))
|
||||
return TokenTypes.MACRO_PARAMETER;
|
||||
|
||||
// See if it is a register
|
||||
Register reg = RegisterFile.getUserRegister(value);
|
||||
if (reg != null)
|
||||
if (reg.getName().equals(value))
|
||||
return TokenTypes.REGISTER_NAME;
|
||||
else
|
||||
return TokenTypes.REGISTER_NUMBER;
|
||||
|
||||
// See if it is a floating point register
|
||||
|
||||
reg = Coprocessor1.getRegister(value);
|
||||
if (reg != null)
|
||||
return TokenTypes.FP_REGISTER_NAME;
|
||||
|
||||
// See if it is an immediate (constant) integer value
|
||||
// Classify based on # bits needed to represent in binary
|
||||
// This is needed because most immediate operands limited to 16 bits
|
||||
// others limited to 5 bits unsigned (shift amounts) others 32 bits.
|
||||
try {
|
||||
|
||||
int i = Binary.stringToInt(value); // KENV 1/6/05
|
||||
|
||||
/***************************************************************************
|
||||
* MODIFICATION AND COMMENT, DPS 3-July-2008
|
||||
*
|
||||
* The modifications of January 2005 documented below are being rescinded.
|
||||
* All hexadecimal immediate values are considered 32 bits in length and
|
||||
* their classification as INTEGER_5, INTEGER_16, INTEGER_16U (new)
|
||||
* or INTEGER_32 depends on their 32 bit value. So 0xFFFF will be
|
||||
* equivalent to 0x0000FFFF instead of 0xFFFFFFFF. This change, along with
|
||||
* the introduction of INTEGER_16U (adopted from Greg Gibeling of Berkeley),
|
||||
* required extensive changes to instruction templates especially for
|
||||
* pseudo-instructions.
|
||||
*
|
||||
* This modification also appears inbuildBasicStatementFromBasicInstruction()
|
||||
* in mars.ProgramStatement.
|
||||
*
|
||||
* ///// Begin modification 1/4/05 KENV ///////////////////////////////////////////
|
||||
* // We have decided to interpret non-signed (no + or -) 16-bit hexadecimal immediate
|
||||
* // operands as signed values in the range -32768 to 32767. So 0xffff will represent
|
||||
* // -1, not 65535 (bit 15 as sign bit), 0x8000 will represent -32768 not 32768.
|
||||
* // NOTE: 32-bit hexadecimal immediate operands whose values fall into this range
|
||||
* // will be likewise affected, but they are used only in pseudo-instructions. The
|
||||
* // code in ExtendedInstruction.java to split this number into upper 16 bits for "lui"
|
||||
* // and lower 16 bits for "ori" works with the original source code token, so it is
|
||||
* // not affected by this tweak. 32-bit immediates in data segment directives
|
||||
* // are also processed elsewhere so are not affected either.
|
||||
* ////////////////////////////////////////////////////////////////////////////////
|
||||
*
|
||||
* if ( Binary.isHex(value) &&
|
||||
* (i >= 32768) &&
|
||||
* (i <= 65535) ) // Range 0x8000 ... 0xffff
|
||||
* {
|
||||
* // Subtract the 0xffff bias, because strings in the
|
||||
* // range "0x8000" ... "0xffff" are used to represent
|
||||
* // 16-bit negative numbers, not positive numbers.
|
||||
* i = i - 65536;
|
||||
* }
|
||||
* // ------------- END KENV 1/4/05 MODIFICATIONS --------------
|
||||
*
|
||||
************************** END DPS 3-July-2008 COMMENTS *******************************/
|
||||
// shift operands must be in range 0-31
|
||||
if (i>=0 && i<=31) {
|
||||
return TokenTypes.INTEGER_5;
|
||||
}
|
||||
if (i>=DataTypes.MIN_UHALF_VALUE && i<=DataTypes.MAX_UHALF_VALUE) {
|
||||
return TokenTypes.INTEGER_16U;
|
||||
}
|
||||
if (i>=DataTypes.MIN_HALF_VALUE && i<=DataTypes.MAX_HALF_VALUE) {
|
||||
return TokenTypes.INTEGER_16;
|
||||
}
|
||||
return TokenTypes.INTEGER_32; // default when no other type is applicable
|
||||
}
|
||||
catch(NumberFormatException e)
|
||||
{
|
||||
// NO ACTION -- exception suppressed
|
||||
}
|
||||
|
||||
// See if it is a real (fixed or floating point) number. Note that parseDouble()
|
||||
// accepts integer values but if it were an integer literal we wouldn't get this far.
|
||||
try {
|
||||
Double.parseDouble(value);
|
||||
return TokenTypes.REAL_NUMBER;
|
||||
}
|
||||
catch (NumberFormatException e)
|
||||
{
|
||||
// NO ACTION -- exception suppressed
|
||||
}
|
||||
|
||||
// See if it is an instruction operator
|
||||
if (Globals.instructionSet.matchOperator(value) != null)
|
||||
return TokenTypes.OPERATOR;
|
||||
|
||||
// See if it is a directive
|
||||
if (value.charAt(0) == '.' && Directives.matchDirective(value) != null) {
|
||||
return TokenTypes.DIRECTIVE;
|
||||
}
|
||||
|
||||
// See if it is a quoted string
|
||||
if (value.charAt(0) == '"')
|
||||
return TokenTypes.QUOTED_STRING;
|
||||
|
||||
// Test for identifier goes last because I have defined tokens for various
|
||||
// MIPS constructs (such as operators and directives) that also could fit
|
||||
// the lexical specifications of an identifier, and those need to be
|
||||
// recognized first.
|
||||
if (isValidIdentifier(value))
|
||||
return TokenTypes.IDENTIFIER;
|
||||
|
||||
// Matches no MIPS language token.
|
||||
return TokenTypes.ERROR;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Lets you know if given tokentype is for integers (INTGER_5, INTEGER_16, INTEGER_32).
|
||||
*
|
||||
* @param type the TokenType of interest
|
||||
* @return true if type is an integer type, false otherwise.
|
||||
**/
|
||||
public static boolean isIntegerTokenType(TokenTypes type) {
|
||||
return type == TokenTypes.INTEGER_5 || type == TokenTypes.INTEGER_16 ||
|
||||
type == TokenTypes.INTEGER_16U || type == TokenTypes.INTEGER_32;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* Lets you know if given tokentype is for floating point numbers (REAL_NUMBER).
|
||||
*
|
||||
* @param type the TokenType of interest
|
||||
* @return true if type is an floating point type, false otherwise.
|
||||
**/
|
||||
public static boolean isFloatingTokenType(TokenTypes type) {
|
||||
return type == TokenTypes.REAL_NUMBER;
|
||||
}
|
||||
|
||||
|
||||
// COD2, A-51: "Identifiers are a sequence of alphanumeric characters,
|
||||
// underbars (_), and dots (.) that do not begin with a number."
|
||||
// Ideally this would be in a separate Identifier class but I did not see an immediate
|
||||
// need beyond this method (refactoring effort would probably identify other uses
|
||||
// related to symbol table).
|
||||
//
|
||||
// DPS 14-Jul-2008: added '$' as valid symbol. Permits labels to include $.
|
||||
// MIPS-target GCC will produce labels that start with $.
|
||||
public static boolean isValidIdentifier(String value) {
|
||||
boolean result =
|
||||
(Character.isLetter(value.charAt(0)) || value.charAt(0)=='_' || value.charAt(0)=='.' || value.charAt(0)=='$');
|
||||
int index = 1;
|
||||
while (result && index < value.length()) {
|
||||
if (!(Character.isLetterOrDigit(value.charAt(index)) || value.charAt(index)=='_' || value.charAt(index)=='.' || value.charAt(index)=='$'))
|
||||
result = false;
|
||||
index++;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,577 @@
|
||||
package mars.assembler;
|
||||
import mars.*;
|
||||
import java.util.*;
|
||||
import java.io.*;
|
||||
|
||||
/*
|
||||
Copyright (c) 2003-2013, 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)
|
||||
*/
|
||||
|
||||
/**
|
||||
* A tokenizer is capable of tokenizing a complete MIPS program, or a given line from
|
||||
* a MIPS program. Since MIPS is line-oriented, each line defines a complete statement.
|
||||
* Tokenizing is the process of analyzing the input MIPS program for the purpose of
|
||||
* recognizing each MIPS language element. The types of language elements are known as "tokens".
|
||||
* MIPS tokens are defined in the TokenTypes class.<br><br>
|
||||
* Example: <br>
|
||||
* The MIPS statement <tt>here: lw $t3, 8($t4) #load third member of array</tt><br>
|
||||
* generates the following token list<br>
|
||||
* IDENTIFIER, COLON, OPERATOR, REGISTER_NAME, COMMA, INTEGER_5, LEFT_PAREN,
|
||||
* REGISTER_NAME, RIGHT_PAREN, COMMENT<br>
|
||||
*
|
||||
* @author Pete Sanderson
|
||||
* @version August 2003
|
||||
**/
|
||||
|
||||
public class Tokenizer {
|
||||
|
||||
private ErrorList errors;
|
||||
private MIPSprogram sourceMIPSprogram;
|
||||
private HashMap<String,String> equivalents; // DPS 11-July-2012
|
||||
// The 8 escaped characters are: single quote, double quote, backslash, newline (linefeed),
|
||||
// tab, backspace, return, form feed. The characters and their corresponding decimal codes:
|
||||
private static final String escapedCharacters = "'\"\\ntbrf0";
|
||||
private static final String[] escapedCharactersValues = {"39","34","92","10","9","8","13","12","0"};
|
||||
|
||||
/**
|
||||
* Simple constructor. Initializes empty error list.
|
||||
*/
|
||||
|
||||
public Tokenizer() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for use with existing MIPSprogram. Designed to be used with Macro feature.
|
||||
* @param program A previously-existing MIPSprogram object or null if none.
|
||||
*/
|
||||
public Tokenizer(MIPSprogram program){
|
||||
errors = new ErrorList();
|
||||
sourceMIPSprogram = program;
|
||||
}
|
||||
|
||||
/**
|
||||
* Will tokenize a complete MIPS program. MIPS is line oriented (not free format),
|
||||
* so we will be line-oriented too.
|
||||
*
|
||||
* @param p The MIPSprogram to be tokenized.
|
||||
* @return An ArrayList representing the tokenized program. Each list member is a TokenList
|
||||
* that represents a tokenized source statement from the MIPS program.
|
||||
**/
|
||||
|
||||
public ArrayList tokenize(MIPSprogram p) throws ProcessingException {
|
||||
sourceMIPSprogram = p;
|
||||
equivalents = new HashMap<String,String>(); // DPS 11-July-2012
|
||||
ArrayList tokenList = new ArrayList();
|
||||
//ArrayList source = p.getSourceList();
|
||||
ArrayList<SourceLine> source = processIncludes(p, new HashMap<String,String>()); // DPS 9-Jan-2013
|
||||
p.setSourceLineList(source);
|
||||
TokenList currentLineTokens;
|
||||
String sourceLine;
|
||||
for (int i=0; i<source.size(); i++) {
|
||||
sourceLine = source.get(i).getSource();
|
||||
currentLineTokens = this.tokenizeLine(i+1, sourceLine);
|
||||
tokenList.add(currentLineTokens);
|
||||
// DPS 03-Jan-2013. Related to 11-July-2012. If source code substitution was made
|
||||
// based on .eqv directive during tokenizing, the processed line, a String, is
|
||||
// not the same object as the original line. Thus I can use != instead of !equals()
|
||||
// This IF statement will replace original source with source modified by .eqv substitution.
|
||||
// Not needed by assembler, but looks better in the Text Segment Display.
|
||||
if (sourceLine.length() > 0 && sourceLine != currentLineTokens.getProcessedLine()) {
|
||||
source.set(i,new SourceLine(currentLineTokens.getProcessedLine(),source.get(i).getMIPSprogram(), source.get(i).getLineNumber()));
|
||||
}
|
||||
}
|
||||
if (errors.errorsOccurred()) {
|
||||
throw new ProcessingException(errors);
|
||||
}
|
||||
return tokenList;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// pre-pre-processing pass through source code to process any ".include" directives.
|
||||
// When one is encountered, the contents of the included file are inserted at that
|
||||
// point. If no .include statements, the return value is a new array list but
|
||||
// with the same lines of source code. Uses recursion to correctly process included
|
||||
// files that themselves have .include. Plus it will detect and report recursive
|
||||
// includes both direct and indirect.
|
||||
// DPS 11-Jan-2013
|
||||
private ArrayList<SourceLine> processIncludes(MIPSprogram program, Map<String,String> inclFiles) throws ProcessingException {
|
||||
ArrayList source = program.getSourceList();
|
||||
ArrayList<SourceLine> result = new ArrayList<SourceLine>(source.size());
|
||||
for (int i=0; i<source.size(); i++) {
|
||||
String line = (String) source.get(i);
|
||||
TokenList tl = tokenizeLine(program, i+1, line, false);
|
||||
boolean hasInclude = false;
|
||||
for (int ii=0; ii<tl.size(); ii++) {
|
||||
if (tl.get(ii).getValue().equalsIgnoreCase(Directives.INCLUDE.getName())
|
||||
&& (tl.size() > ii+1)
|
||||
&& tl.get(ii+1).getType() == TokenTypes.QUOTED_STRING) {
|
||||
String filename = tl.get(ii+1).getValue();
|
||||
filename = filename.substring(1, filename.length()-1); // get rid of quotes
|
||||
// Handle either absolute or relative pathname for .include file
|
||||
if (!new File(filename).isAbsolute()) {
|
||||
filename = new File(program.getFilename()).getParent()+File.separator+filename;
|
||||
}
|
||||
if (inclFiles.containsKey(filename)) {
|
||||
// This is a recursive include. Generate error message and return immediately.
|
||||
Token t = tl.get(ii+1);
|
||||
errors.add(new ErrorMessage(program, t.getSourceLine(),t.getStartPos(),
|
||||
"Recursive include of file "+filename));
|
||||
throw new ProcessingException(errors);
|
||||
}
|
||||
inclFiles.put(filename, filename);
|
||||
MIPSprogram incl = new MIPSprogram();
|
||||
try {
|
||||
incl.readSource(filename);
|
||||
}
|
||||
catch (ProcessingException p) {
|
||||
Token t = tl.get(ii+1);
|
||||
errors.add(new ErrorMessage(program, t.getSourceLine(),t.getStartPos(),
|
||||
"Error reading include file "+filename));
|
||||
throw new ProcessingException(errors);
|
||||
}
|
||||
ArrayList<SourceLine> allLines = processIncludes(incl, inclFiles);
|
||||
result.addAll(allLines);
|
||||
hasInclude = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!hasInclude){
|
||||
result.add(new SourceLine(line, program, i+1));//line);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used only to create a token list for the example provided with each instruction
|
||||
* specification.
|
||||
*
|
||||
* @param example The example MIPS instruction to be tokenized.
|
||||
*
|
||||
* @return An TokenList representing the tokenized instruction. Each list member is a Token
|
||||
* that represents one language element.
|
||||
*
|
||||
* @throws ProcessingException This occurs only if the instruction specification itself
|
||||
* contains one or more lexical (i.e. token) errors.
|
||||
**/
|
||||
|
||||
public TokenList tokenizeExampleInstruction(String example) throws ProcessingException {
|
||||
TokenList result = new TokenList();
|
||||
result = tokenizeLine(sourceMIPSprogram, 0, example, false);
|
||||
if (errors.errorsOccurred()) {
|
||||
throw new ProcessingException(errors);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Will tokenize one line of source code. If lexical errors are discovered,
|
||||
* they are noted in an ErrorMessage object which is added to the ErrorList.
|
||||
* Will NOT throw an exception yet because we want to persevere beyond first error.
|
||||
*
|
||||
* @param lineNum line number from source code (used in error message)
|
||||
* @param theLine String containing source code
|
||||
* @return the generated token list for that line
|
||||
*
|
||||
**/
|
||||
/*
|
||||
*
|
||||
* Tokenizing is not as easy as it appears at first blush, because the typical
|
||||
* delimiters: space, tab, comma, can all appear inside MIPS quoted ASCII strings!
|
||||
* Also, spaces are not as necessary as they seem, the following line is accepted
|
||||
* and parsed correctly by SPIM: label:lw,$t4,simple#comment
|
||||
* as is this weird variation: label :lw $t4 ,simple , , , # comment
|
||||
*
|
||||
* as is this line: stuff:.asciiz"# ,\n\"","aaaaa" (interestingly, if you put
|
||||
* additional characters after the \", they are ignored!!)
|
||||
*
|
||||
* I also would like to know the starting character position in the line of each
|
||||
* token, for error reporting purposes. StringTokenizer cannot give you this.
|
||||
*
|
||||
* Given all the above, it is just as easy to "roll my own" as to use StringTokenizer
|
||||
*/
|
||||
|
||||
// Modified for release 4.3, to preserve existing API.
|
||||
public TokenList tokenizeLine(int lineNum, String theLine) {
|
||||
return tokenizeLine(sourceMIPSprogram, lineNum, theLine, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Will tokenize one line of source code. If lexical errors are discovered,
|
||||
* they are noted in an ErrorMessage object which is added to the provided ErrorList
|
||||
* instead of the Tokenizer's error list. Will NOT throw an exception.
|
||||
*
|
||||
* @param lineNum line number from source code (used in error message)
|
||||
* @param theLine String containing source code
|
||||
* @param callerErrorList errors will go into this list instead of tokenizer's list.
|
||||
* @return the generated token list for that line
|
||||
*
|
||||
**/
|
||||
public TokenList tokenizeLine(int lineNum, String theLine, ErrorList callerErrorList) {
|
||||
ErrorList saveList = this.errors;
|
||||
this.errors = callerErrorList;
|
||||
TokenList tokens = this.tokenizeLine(lineNum, theLine);
|
||||
this.errors = saveList;
|
||||
return tokens;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Will tokenize one line of source code. If lexical errors are discovered,
|
||||
* they are noted in an ErrorMessage object which is added to the provided ErrorList
|
||||
* instead of the Tokenizer's error list. Will NOT throw an exception.
|
||||
*
|
||||
* @param lineNum line number from source code (used in error message)
|
||||
* @param theLine String containing source code
|
||||
* @param callerErrorList errors will go into this list instead of tokenizer's list.
|
||||
* @param doEqvSubstitutse boolean param set true to perform .eqv substitutions, else false
|
||||
* @return the generated token list for that line
|
||||
*
|
||||
**/
|
||||
public TokenList tokenizeLine(int lineNum, String theLine, ErrorList callerErrorList, boolean doEqvSubstitutes) {
|
||||
ErrorList saveList = this.errors;
|
||||
this.errors = callerErrorList;
|
||||
TokenList tokens = this.tokenizeLine(sourceMIPSprogram, lineNum, theLine,doEqvSubstitutes);
|
||||
this.errors = saveList;
|
||||
return tokens;
|
||||
}
|
||||
|
||||
/**
|
||||
* Will tokenize one line of source code. If lexical errors are discovered,
|
||||
* they are noted in an ErrorMessage object which is added to the provided ErrorList
|
||||
* instead of the Tokenizer's error list. Will NOT throw an exception.
|
||||
*
|
||||
* @param program MIPSprogram containing this line of source
|
||||
* @param lineNum line number from source code (used in error message)
|
||||
* @param theLine String containing source code
|
||||
* @param doEqvSubstitutes boolean param set true to perform .eqv substitutions, else false
|
||||
* @return the generated token list for that line
|
||||
*
|
||||
**/
|
||||
public TokenList tokenizeLine(MIPSprogram program, int lineNum, String theLine, boolean doEqvSubstitutes) {
|
||||
TokenTypes tokenType;
|
||||
TokenList result = new TokenList();
|
||||
if (theLine.length() == 0)
|
||||
return result;
|
||||
// will be faster to work with char arrays instead of strings
|
||||
char c;
|
||||
char[] line = theLine.toCharArray();
|
||||
int linePos = 0;
|
||||
char[] token = new char[line.length];
|
||||
int tokenPos = 0;
|
||||
int tokenStartPos = 1;
|
||||
boolean insideQuotedString = false;
|
||||
if (Globals.debug)
|
||||
System.out.println("source line --->"+theLine+"<---");
|
||||
// Each iteration of this loop processes one character in the source line.
|
||||
while (linePos < line.length) {
|
||||
c = line[linePos];
|
||||
if (insideQuotedString) { // everything goes into token
|
||||
token[tokenPos++] = c;
|
||||
if (c == '"' && token[tokenPos-2] != '\\') { // If quote not preceded by backslash, this is end
|
||||
this.processCandidateToken(token, program, lineNum, theLine, tokenPos, tokenStartPos, result);
|
||||
tokenPos = 0;
|
||||
insideQuotedString = false;
|
||||
}
|
||||
}
|
||||
else { // not inside a quoted string, so be sensitive to delimiters
|
||||
switch(c) {
|
||||
case '#' : // # denotes comment that takes remainder of line
|
||||
if (tokenPos > 0) {
|
||||
this.processCandidateToken(token, program, lineNum, theLine, tokenPos, tokenStartPos, result);
|
||||
tokenPos = 0;
|
||||
}
|
||||
tokenStartPos = linePos+1;
|
||||
tokenPos = line.length-linePos;
|
||||
System.arraycopy(line, linePos, token, 0, tokenPos);
|
||||
this.processCandidateToken(token, program, lineNum, theLine, tokenPos, tokenStartPos, result);
|
||||
linePos = line.length;
|
||||
tokenPos = 0;
|
||||
break;
|
||||
case ' ' :
|
||||
case '\t':
|
||||
case ',' : // space, tab or comma is delimiter
|
||||
if (tokenPos > 0) {
|
||||
this.processCandidateToken(token, program, lineNum, theLine, tokenPos, tokenStartPos, result);
|
||||
tokenPos = 0;
|
||||
}
|
||||
break;
|
||||
// These two guys are special. Will be recognized as unary if and only if two conditions hold:
|
||||
// 1. Immediately followed by a digit (will use look-ahead for this).
|
||||
// 2. Previous token, if any, is _not_ an IDENTIFIER
|
||||
// Otherwise considered binary and thus a separate token. This is a slight hack but reasonable.
|
||||
case '+' :
|
||||
case '-' :
|
||||
// Here's the REAL hack: recognizing signed exponent in E-notation floating point!
|
||||
// (e.g. 1.2e-5) Add the + or - to the token and keep going. DPS 17 Aug 2005
|
||||
if (tokenPos > 0 && line.length >= linePos+2 && Character.isDigit(line[linePos+1]) &&
|
||||
(line[linePos-1]=='e' || line[linePos-1]=='E')) {
|
||||
token[tokenPos++] = c;
|
||||
break;
|
||||
}
|
||||
// End of REAL hack.
|
||||
if (tokenPos > 0) {
|
||||
this.processCandidateToken(token, program, lineNum, theLine, tokenPos, tokenStartPos, result);
|
||||
tokenPos = 0;
|
||||
}
|
||||
tokenStartPos = linePos+1;
|
||||
token[tokenPos++] = c;
|
||||
if ( !((result.isEmpty() || ((Token)result.get(result.size()-1)).getType() != TokenTypes.IDENTIFIER) &&
|
||||
(line.length >= linePos+2 && Character.isDigit(line[linePos+1]))) ) {
|
||||
// treat it as binary.....
|
||||
this.processCandidateToken(token, program, lineNum, theLine, tokenPos, tokenStartPos, result);
|
||||
tokenPos = 0;
|
||||
}
|
||||
break;
|
||||
// these are other single-character tokens
|
||||
case ':' :
|
||||
case '(' :
|
||||
case ')' :
|
||||
if (tokenPos > 0) {
|
||||
this.processCandidateToken(token, program, lineNum, theLine, tokenPos, tokenStartPos, result);
|
||||
tokenPos = 0;
|
||||
}
|
||||
tokenStartPos = linePos+1;
|
||||
token[tokenPos++] = c;
|
||||
this.processCandidateToken(token, program, lineNum, theLine, tokenPos, tokenStartPos, result);
|
||||
tokenPos = 0;
|
||||
break;
|
||||
case '"' : // we're not inside a quoted string, so start a new token...
|
||||
if (tokenPos > 0) {
|
||||
this.processCandidateToken(token, program, lineNum, theLine, tokenPos, tokenStartPos, result);
|
||||
tokenPos = 0;
|
||||
}
|
||||
tokenStartPos = linePos+1;
|
||||
token[tokenPos++] = c;
|
||||
insideQuotedString = true;
|
||||
break;
|
||||
case '\'' : // start of character constant (single quote).
|
||||
if (tokenPos > 0) {
|
||||
this.processCandidateToken(token, program, lineNum, theLine, tokenPos, tokenStartPos, result);
|
||||
tokenPos = 0;
|
||||
}
|
||||
// Our strategy is to process the whole thing right now...
|
||||
tokenStartPos = linePos+1;
|
||||
token[tokenPos++] = c; // Put the quote in token[0]
|
||||
int lookaheadChars = line.length - linePos - 1;
|
||||
// need minimum 2 more characters, 1 for char and 1 for ending quote
|
||||
if (lookaheadChars < 2)
|
||||
break; // gonna be an error
|
||||
c = line[++linePos];
|
||||
token[tokenPos++] = c; // grab second character, put it in token[1]
|
||||
if (c == '\'')
|
||||
break; // gonna be an error: nothing between the quotes
|
||||
c = line[++linePos];
|
||||
token[tokenPos++] = c; // grab third character, put it in token[2]
|
||||
// Process if we've either reached second, non-escaped, quote or end of line.
|
||||
if (c == '\'' && token[1] != '\\' || lookaheadChars==2) {
|
||||
this.processCandidateToken(token, program, lineNum, theLine, tokenPos, tokenStartPos, result);
|
||||
tokenPos = 0;
|
||||
tokenStartPos = linePos+1;
|
||||
break;
|
||||
}
|
||||
// At this point, there is at least one more character on this line. If we're
|
||||
// still here after seeing a second quote, it was escaped. Not done yet;
|
||||
// we either have an escape code, an octal code (also escaped) or invalid.
|
||||
c = line[++linePos];
|
||||
token[tokenPos++] = c; // grab fourth character, put it in token[3]
|
||||
// Process, if this is ending quote for escaped character or if at end of line
|
||||
if (c == '\'' || lookaheadChars==3) {
|
||||
this.processCandidateToken(token, program, lineNum, theLine, tokenPos, tokenStartPos, result);
|
||||
tokenPos = 0;
|
||||
tokenStartPos = linePos+1;
|
||||
break;
|
||||
}
|
||||
// At this point, we've handled all legal possibilities except octal, e.g. '\377'
|
||||
// Proceed, if enough characters remain to finish off octal.
|
||||
if (lookaheadChars >= 5) {
|
||||
c = line[++linePos];
|
||||
token[tokenPos++] = c; // grab fifth character, put it in token[4]
|
||||
if (c != '\'') {
|
||||
// still haven't reached end, last chance for validity!
|
||||
c = line[++linePos];
|
||||
token[tokenPos++] = c; // grab sixth character, put it in token[5]
|
||||
}
|
||||
}
|
||||
// process no matter what...we either have a valid character by now or not
|
||||
this.processCandidateToken(token, program, lineNum, theLine, tokenPos, tokenStartPos, result);
|
||||
tokenPos = 0;
|
||||
tokenStartPos = linePos+1;
|
||||
break;
|
||||
default :
|
||||
if (tokenPos == 0)
|
||||
tokenStartPos = linePos+1;
|
||||
token[tokenPos++] = c;
|
||||
break;
|
||||
} // switch
|
||||
} // if (insideQuotedString)
|
||||
linePos++;
|
||||
} // while
|
||||
if (tokenPos > 0) {
|
||||
this.processCandidateToken(token, program, lineNum, theLine, tokenPos, tokenStartPos, result);
|
||||
tokenPos = 0;
|
||||
}
|
||||
if (doEqvSubstitutes) {
|
||||
result = processEqv(program, lineNum, theLine, result); // DPS 11-July-2012
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Process the .eqv directive, which needs to be applied prior to tokenizing of subsequent statements.
|
||||
// This handles detecting that theLine contains a .eqv directive, in which case it needs
|
||||
// to be added to the HashMap of equivalents. It also handles detecting that theLine
|
||||
// contains a symbol that was previously defined in an .eqv directive, in which case
|
||||
// the substitution needs to be made.
|
||||
// DPS 11-July-2012
|
||||
private TokenList processEqv(MIPSprogram program, int lineNum, String theLine, TokenList tokens) {
|
||||
// See if it is .eqv directive. If so, record it...
|
||||
// Have to assure it is a well-formed statement right now (can't wait for assembler).
|
||||
|
||||
if (tokens.size()>2 && (tokens.get(0).getType() == TokenTypes.DIRECTIVE || tokens.get(2).getType() == TokenTypes.DIRECTIVE)) {
|
||||
// There should not be a label but if there is, the directive is in token position 2 (ident, colon, directive).
|
||||
int dirPos = (tokens.get(0).getType() == TokenTypes.DIRECTIVE) ? 0 : 2;
|
||||
if (Directives.matchDirective(tokens.get(dirPos).getValue()) == Directives.EQV) {
|
||||
// Get position in token list of last non-comment token
|
||||
int tokenPosLastOperand = tokens.size() - ((tokens.get(tokens.size()-1).getType()==TokenTypes.COMMENT)? 2 : 1);
|
||||
// There have to be at least two non-comment tokens beyond the directive
|
||||
if (tokenPosLastOperand < dirPos+2) {
|
||||
errors.add(new ErrorMessage(program, lineNum,tokens.get(dirPos).getStartPos(),
|
||||
"Too few operands for "+Directives.EQV.getName()+" directive"));
|
||||
return tokens;
|
||||
}
|
||||
// Token following the directive has to be IDENTIFIER
|
||||
if (tokens.get(dirPos+1).getType() != TokenTypes.IDENTIFIER) {
|
||||
errors.add(new ErrorMessage(program, lineNum,tokens.get(dirPos).getStartPos(),
|
||||
"Malformed "+Directives.EQV.getName()+" directive"));
|
||||
return tokens;
|
||||
}
|
||||
String symbol = tokens.get(dirPos+1).getValue();
|
||||
// Make sure the symbol is not contained in the expression. Not likely to occur but if left
|
||||
// undetected it will result in infinite recursion. e.g. .eqv ONE, (ONE)
|
||||
for (int i=dirPos+2; i<tokens.size(); i++) {
|
||||
if (tokens.get(i).getValue().equals(symbol)) {
|
||||
errors.add(new ErrorMessage(program, lineNum,tokens.get(dirPos).getStartPos(),
|
||||
"Cannot substitute "+symbol+" for itself in "+Directives.EQV.getName()+" directive"));
|
||||
return tokens;
|
||||
}
|
||||
}
|
||||
// Expected syntax is symbol, expression. I'm allowing the expression to comprise
|
||||
// multiple tokens, so I want to get everything from the IDENTIFIER to either the
|
||||
// COMMENT or to the end.
|
||||
int startExpression = tokens.get(dirPos+2).getStartPos();
|
||||
int endExpression = tokens.get(tokenPosLastOperand).getStartPos() + tokens.get(tokenPosLastOperand).getValue().length();
|
||||
String expression = theLine.substring(startExpression-1,endExpression-1);
|
||||
// Symbol cannot be redefined - the only reason for this is to act like the Gnu .eqv
|
||||
if (equivalents.containsKey(symbol) && !equivalents.get(symbol).equals(expression)) {
|
||||
errors.add(new ErrorMessage(program, lineNum,tokens.get(dirPos+1).getStartPos(),
|
||||
"\""+symbol+"\" is already defined"));
|
||||
return tokens;
|
||||
}
|
||||
equivalents.put(symbol, expression);
|
||||
return tokens;
|
||||
}
|
||||
}
|
||||
// Check if a substitution from defined .eqv is to be made. If so, make one.
|
||||
boolean substitutionMade = false;
|
||||
for (int i=0; i<tokens.size(); i++) {
|
||||
Token token = tokens.get(i);
|
||||
if (token.getType() == TokenTypes.IDENTIFIER && equivalents != null && equivalents.containsKey(token.getValue())) {
|
||||
// do the substitution
|
||||
String sub = equivalents.get(token.getValue());
|
||||
int startPos = token.getStartPos();
|
||||
theLine = theLine.substring(0,startPos-1) + sub + theLine.substring(startPos+token.getValue().length()-1);
|
||||
substitutionMade = true; // one substitution per call. If there are multiple, will catch next one on the recursion
|
||||
break;
|
||||
}
|
||||
}
|
||||
tokens.setProcessedLine(theLine); // DPS 03-Jan-2013. Related to changes of 11-July-2012.
|
||||
|
||||
return (substitutionMade) ? tokenizeLine(lineNum, theLine) : tokens;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Fetch this Tokenizer's error list.
|
||||
*
|
||||
* @return the error list
|
||||
*/
|
||||
public ErrorList getErrors() {
|
||||
return errors;
|
||||
}
|
||||
|
||||
|
||||
// Given candidate token and its position, will classify and record it.
|
||||
private void processCandidateToken(char[] token, MIPSprogram program, int line, String theLine,
|
||||
int tokenPos, int tokenStartPos, TokenList tokenList) {
|
||||
String value = new String(token, 0, tokenPos);
|
||||
if (value.length() > 0 && value.charAt(0)=='\'') value = preprocessCharacterLiteral(value);
|
||||
TokenTypes type = TokenTypes.matchTokenType(value);
|
||||
if (type == TokenTypes.ERROR) {
|
||||
errors.add(new ErrorMessage(program, line, tokenStartPos,
|
||||
theLine+"\nInvalid language element: "+value));
|
||||
}
|
||||
Token toke = new Token(type, value, program, line, tokenStartPos);
|
||||
tokenList.add(toke);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// If passed a candidate character literal, attempt to translate it into integer constant.
|
||||
// If the translation fails, return original value.
|
||||
private String preprocessCharacterLiteral(String value) {
|
||||
// must start and end with quote and have something in between
|
||||
if (value.length() < 3 || value.charAt(0) != '\'' || value.charAt(value.length()-1) != '\'') {
|
||||
return value;
|
||||
}
|
||||
String quotesRemoved = value.substring(1, value.length()-1);
|
||||
// if not escaped, then if one character left return its value else return original.
|
||||
if (quotesRemoved.charAt(0) != '\\') {
|
||||
return (quotesRemoved.length() == 1) ? Integer.toString((int)quotesRemoved.charAt(0)) : value;
|
||||
}
|
||||
// now we know it is escape sequence and have to decode which of the 8: ',",\,n,t,b,r,f
|
||||
if (quotesRemoved.length() == 2) {
|
||||
int escapedCharacterIndex = escapedCharacters.indexOf(quotesRemoved.charAt(1));
|
||||
return (escapedCharacterIndex >= 0) ? escapedCharactersValues[escapedCharacterIndex] : value;
|
||||
}
|
||||
// last valid possibility is 3 digit octal code 000 through 377
|
||||
if (quotesRemoved.length() == 4) {
|
||||
try {
|
||||
int intValue = Integer.parseInt(quotesRemoved.substring(1),8);
|
||||
if (intValue >= 0 && intValue <= 255) {
|
||||
return Integer.toString(intValue);
|
||||
}
|
||||
}
|
||||
catch (NumberFormatException nfe) { } // if not valid octal, will fall through and reject
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,48 @@
|
||||
package mars.assembler;
|
||||
|
||||
/*
|
||||
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 interface is intended for use by ExtendedInstruction objects to define, using
|
||||
* the translate() method, how to translate the extended (pseudo) instruction into
|
||||
* a sequence of one or more basic instructions, which can then be translated into
|
||||
* binary machine code.
|
||||
*
|
||||
* @author Pete Sanderson
|
||||
* @version August 2003
|
||||
*/
|
||||
|
||||
public interface TranslationCode {
|
||||
/**
|
||||
* This is a callback method defined in anonymous class specified as
|
||||
* argument to ExtendedInstruction constructor. It is called when
|
||||
* assembler finds a program statement matching that ExtendedInstruction,
|
||||
*/
|
||||
public void translate();
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,118 @@
|
||||
package mars.mips.dump;
|
||||
|
||||
import mars.mips.hardware.*;
|
||||
import java.io.*;
|
||||
/*
|
||||
Copyright (c) 2003-2008, 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)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Abstract class for memory dump file formats. Provides constructors and
|
||||
* defaults for everything except the dumpMemoryRange method itself.
|
||||
*
|
||||
* @author Pete Sanderson
|
||||
* @version December 2007
|
||||
*/
|
||||
|
||||
|
||||
public abstract class AbstractDumpFormat implements DumpFormat {
|
||||
|
||||
private String name, commandDescriptor, description, extension;
|
||||
|
||||
/**
|
||||
* Typical constructor. Note you cannot creates objects from this
|
||||
* class but subclass constructor can call this one.
|
||||
* @param name Brief descriptive name to be displayed in selection list.
|
||||
* @param commandDescriptor One-word descriptive name to be used by MARS command mode parser and user.
|
||||
* Any spaces in this string will be removed.
|
||||
* @param description Description to go with standard file extension for
|
||||
* display in file save dialog or to be used as tool tip.
|
||||
* @param extension Standard file extension for this format. Null if none.
|
||||
*/
|
||||
public AbstractDumpFormat(String name, String commandDescriptor,
|
||||
String description, String extension) {
|
||||
this.name = name;
|
||||
this.commandDescriptor = (commandDescriptor==null) ? null : commandDescriptor.replaceAll(" ","");
|
||||
this.description = description;
|
||||
this.extension = extension;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the file extension associated with this format.
|
||||
* @return String containing file extension -- without the leading "." -- or
|
||||
* null if there is no standard extension.
|
||||
*/
|
||||
public String getFileExtension() {
|
||||
return extension;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a short description of the format, suitable for displaying along with
|
||||
* the extension, in the file save dialog, or as a tool tip.
|
||||
* @return String containing short description to go with the extension
|
||||
* or for use as tool tip. Possibly null.
|
||||
*/
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
/**
|
||||
* String representing this object.
|
||||
* @return Name given for this object.
|
||||
*
|
||||
*/
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* One-word description of format to be used by MARS command mode parser
|
||||
* and user in conjunction with the "dump" option.
|
||||
* @return One-word String describing the format.
|
||||
*
|
||||
*/
|
||||
public String getCommandDescriptor() {
|
||||
return commandDescriptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write MIPS memory contents according to the
|
||||
* specification for this format.
|
||||
*
|
||||
* @param file File in which to store MIPS memory contents.
|
||||
* @param firstAddress first (lowest) memory address to dump. In bytes but
|
||||
* must be on word boundary.
|
||||
* @param lastAddress last (highest) memory address to dump. In bytes but
|
||||
* must be on word boundary. Will dump the word that starts at this address.
|
||||
* @throws AddressErrorException if firstAddress is invalid or not on a word boundary.
|
||||
* @throws IOException if error occurs during file output.
|
||||
*/
|
||||
public abstract void dumpMemoryRange(File file, int firstAddress, int lastAddress)
|
||||
throws AddressErrorException, IOException;
|
||||
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,92 @@
|
||||
package mars.mips.dump;
|
||||
|
||||
import mars.util.Binary;
|
||||
import mars.Globals;
|
||||
import mars.mips.hardware.*;
|
||||
import java.io.*;
|
||||
/*
|
||||
Copyright (c) 2003-2011, 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)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class that represents the "ASCII text" memory dump format. Memory contents
|
||||
* are interpreted as ASCII codes. The output
|
||||
* is a text file with one word of MIPS memory per line. The word is formatted
|
||||
* to leave three spaces for each character. Non-printing characters
|
||||
* rendered as period (.) as placeholder. Common escaped characters
|
||||
* rendered using backslash and single-character descriptor, e.g. \t for tab.
|
||||
* @author Pete Sanderson
|
||||
* @version December 2010
|
||||
*/
|
||||
|
||||
|
||||
public class AsciiTextDumpFormat extends AbstractDumpFormat {
|
||||
|
||||
/**
|
||||
* Constructor. There is no standard file extension for this format.
|
||||
*/
|
||||
public AsciiTextDumpFormat() {
|
||||
super("ASCII Text", "AsciiText", "Memory contents interpreted as ASCII characters", null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Interpret MIPS memory contents as ASCII characters. Each line of
|
||||
* text contains one memory word written in ASCII characters. Those
|
||||
* corresponding to tab, newline, null, etc are rendered as backslash
|
||||
* followed by single-character code, e.g. \t for tab, \0 for null.
|
||||
* Non-printing character (control code,
|
||||
* values above 127) is rendered as a period (.). Written
|
||||
* using PrintStream's println() method.
|
||||
* Adapted by Pete Sanderson from code written by Greg Gibeling.
|
||||
*
|
||||
* @param file File in which to store MIPS memory contents.
|
||||
* @param firstAddress first (lowest) memory address to dump. In bytes but
|
||||
* must be on word boundary.
|
||||
* @param lastAddress last (highest) memory address to dump. In bytes but
|
||||
* must be on word boundary. Will dump the word that starts at this address.
|
||||
* @throws AddressErrorException if firstAddress is invalid or not on a word boundary.
|
||||
* @throws IOException if error occurs during file output.
|
||||
*/
|
||||
public void dumpMemoryRange(File file, int firstAddress, int lastAddress)
|
||||
throws AddressErrorException, IOException {
|
||||
PrintStream out = new PrintStream(new FileOutputStream(file));
|
||||
String string = null;
|
||||
try {
|
||||
for (int address = firstAddress; address <= lastAddress; address += Memory.WORD_LENGTH_BYTES) {
|
||||
Integer temp = Globals.memory.getRawWordOrNull(address);
|
||||
if (temp == null)
|
||||
break;
|
||||
out.println(Binary.intToAscii(temp.intValue()));
|
||||
}
|
||||
}
|
||||
finally {
|
||||
out.close();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,84 @@
|
||||
package mars.mips.dump;
|
||||
|
||||
import mars.Globals;
|
||||
import mars.mips.hardware.*;
|
||||
import java.io.*;
|
||||
/*
|
||||
Copyright (c) 2003-2008, 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)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class that represents the "binary" memory dump format. The output
|
||||
* is a binary file containing the memory words as a byte stream. Output
|
||||
* is produced using PrintStream's write() method.
|
||||
* @author Pete Sanderson
|
||||
* @version December 2007
|
||||
*/
|
||||
|
||||
|
||||
public class BinaryDumpFormat extends AbstractDumpFormat {
|
||||
|
||||
/**
|
||||
* Constructor. There is no standard file extension for this format.
|
||||
*/
|
||||
public BinaryDumpFormat() {
|
||||
super("Binary", "Binary", "Written as byte stream to binary file", null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Write MIPS memory contents in pure binary format. One byte at a time
|
||||
* using PrintStream's write() method. Adapted by Pete Sanderson from
|
||||
* code written by Greg Gibeling.
|
||||
*
|
||||
* @param file File in which to store MIPS memory contents.
|
||||
* @param firstAddress first (lowest) memory address to dump. In bytes but
|
||||
* must be on word boundary.
|
||||
* @param lastAddress last (highest) memory address to dump. In bytes but
|
||||
* must be on word boundary. Will dump the word that starts at this address.
|
||||
* @throws AddressErrorException if firstAddress is invalid or not on a word boundary.
|
||||
* @throws IOException if error occurs during file output.
|
||||
*/
|
||||
public void dumpMemoryRange(File file, int firstAddress, int lastAddress)
|
||||
throws AddressErrorException, IOException {
|
||||
PrintStream out = new PrintStream(new FileOutputStream(file));
|
||||
try {
|
||||
for (int address = firstAddress; address <= lastAddress; address += Memory.WORD_LENGTH_BYTES) {
|
||||
Integer temp = Globals.memory.getRawWordOrNull(address);
|
||||
if (temp == null)
|
||||
break;
|
||||
int word = temp.intValue();
|
||||
for (int i = 0; i < 4; i++)
|
||||
out.write((word >>> (i << 3)) & 0xFF);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
out.close();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,88 @@
|
||||
package mars.mips.dump;
|
||||
|
||||
import mars.Globals;
|
||||
import mars.mips.hardware.*;
|
||||
import java.io.*;
|
||||
/*
|
||||
Copyright (c) 2003-2008, 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)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class that represents the "binary text" memory dump format. The output
|
||||
* is a text file with one word of MIPS memory per line. The word is formatted
|
||||
* using '0' and '1' characters, e.g. 01110101110000011111110101010011.
|
||||
* @author Pete Sanderson
|
||||
* @version December 2007
|
||||
*/
|
||||
|
||||
|
||||
public class BinaryTextDumpFormat extends AbstractDumpFormat {
|
||||
|
||||
/**
|
||||
* Constructor. There is no standard file extension for this format.
|
||||
*/
|
||||
public BinaryTextDumpFormat() {
|
||||
super("Binary Text", "BinaryText", "Written as '0' and '1' characters to text file", null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Write MIPS memory contents in binary text format. Each line of
|
||||
* text contains one memory word written as 32 '0' and '1' characters. Written
|
||||
* using PrintStream's println() method.
|
||||
* Adapted by Pete Sanderson from code written by Greg Gibeling.
|
||||
*
|
||||
* @param file File in which to store MIPS memory contents.
|
||||
* @param firstAddress first (lowest) memory address to dump. In bytes but
|
||||
* must be on word boundary.
|
||||
* @param lastAddress last (highest) memory address to dump. In bytes but
|
||||
* must be on word boundary. Will dump the word that starts at this address.
|
||||
* @throws AddressErrorException if firstAddress is invalid or not on a word boundary.
|
||||
* @throws IOException if error occurs during file output.
|
||||
*/
|
||||
public void dumpMemoryRange(File file, int firstAddress, int lastAddress)
|
||||
throws AddressErrorException, IOException {
|
||||
PrintStream out = new PrintStream(new FileOutputStream(file));
|
||||
String string = null;
|
||||
try {
|
||||
for (int address = firstAddress; address <= lastAddress; address += Memory.WORD_LENGTH_BYTES) {
|
||||
Integer temp = Globals.memory.getRawWordOrNull(address);
|
||||
if (temp == null)
|
||||
break;
|
||||
string = Integer.toBinaryString(temp.intValue());
|
||||
while (string.length() < 32) {
|
||||
string = '0' + string;
|
||||
}
|
||||
out.println(string);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
out.close();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,92 @@
|
||||
package mars.mips.dump;
|
||||
|
||||
import mars.mips.hardware.*;
|
||||
import java.io.*;
|
||||
/*
|
||||
Copyright (c) 2003-2008, 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)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Interface for memory dump file formats. All MARS needs to be able
|
||||
* to do is save an assembled program or data in the specified manner for
|
||||
* a given format. Formats are specified through classes
|
||||
* that implement this interface.
|
||||
*
|
||||
* @author Pete Sanderson
|
||||
* @version December 2007
|
||||
*/
|
||||
|
||||
|
||||
public interface DumpFormat {
|
||||
|
||||
/**
|
||||
* Get the file extension associated with this format.
|
||||
* @return String containing file extension -- without the leading "." -- or
|
||||
* null if there is no standard extension.
|
||||
*/
|
||||
public String getFileExtension();
|
||||
|
||||
/**
|
||||
* Get a short description of the format, suitable
|
||||
* for displaying along with the extension, if any, in the file
|
||||
* save dialog and also for displaying as a tool tip.
|
||||
* @return String containing short description to go with the extension
|
||||
* or as tool tip when mouse hovers over GUI component representing
|
||||
* this format.
|
||||
*/
|
||||
public String getDescription();
|
||||
|
||||
/**
|
||||
* A short one-word descriptor that will be used by the MARS
|
||||
* command line parser (and the MARS command line user) to specify
|
||||
* that this format is to be used.
|
||||
*/
|
||||
public String getCommandDescriptor();
|
||||
|
||||
/**
|
||||
* Descriptive name for the format.
|
||||
* @return Format name.
|
||||
*
|
||||
*/
|
||||
public String toString();
|
||||
|
||||
/**
|
||||
* Write MIPS memory contents according to the
|
||||
* specification for this format.
|
||||
*
|
||||
* @param file File in which to store MIPS memory contents.
|
||||
* @param firstAddress first (lowest) memory address to dump. In bytes but
|
||||
* must be on word boundary.
|
||||
* @param lastAddress last (highest) memory address to dump. In bytes but
|
||||
* must be on word boundary. Will dump the word that starts at this address.
|
||||
* @throws AddressErrorException if firstAddress is invalid or not on a word boundary.
|
||||
* @throws IOException if error occurs during file output.
|
||||
*/
|
||||
public void dumpMemoryRange(File file, int firstAddress, int lastAddress)
|
||||
throws AddressErrorException, IOException;
|
||||
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,97 @@
|
||||
package mars.mips.dump;
|
||||
import mars.*;
|
||||
import mars.util.*;
|
||||
import java.util.*;
|
||||
import java.lang.reflect.*;
|
||||
|
||||
/*
|
||||
Copyright (c) 2003-2008, 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 memory dump format definitions
|
||||
* into MARS. 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".
|
||||
*/
|
||||
|
||||
public class DumpFormatLoader {
|
||||
|
||||
private static final String CLASS_PREFIX = "mars.mips.dump.";
|
||||
private static final String DUMP_DIRECTORY_PATH = "mars/mips/dump";
|
||||
private static final String SYSCALL_INTERFACE = "DumpFormat.class";
|
||||
private static final String CLASS_EXTENSION = "class";
|
||||
|
||||
private static ArrayList formatList = null;
|
||||
|
||||
/**
|
||||
* Dynamically loads dump formats 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 ToolLoader and SyscallLoader classes elsewhere in MARS.
|
||||
*/
|
||||
|
||||
public ArrayList loadDumpFormats() {
|
||||
// The list will be populated only the first time this method is called.
|
||||
if (formatList == null) {
|
||||
formatList = new ArrayList();
|
||||
// grab all class files in the dump directory
|
||||
ArrayList candidates = FilenameFinder.getFilenameList(this.getClass( ).getClassLoader(),
|
||||
DUMP_DIRECTORY_PATH, CLASS_EXTENSION);
|
||||
for( int i = 0; i < candidates.size(); i++) {
|
||||
String file = (String) candidates.get(i);
|
||||
try {
|
||||
// grab the class, make sure it implements DumpFormat, instantiate, add to list
|
||||
String formatClassName = CLASS_PREFIX+file.substring(0, file.indexOf(CLASS_EXTENSION)-1);
|
||||
Class clas = Class.forName(formatClassName);
|
||||
if (DumpFormat.class.isAssignableFrom(clas) &&
|
||||
!Modifier.isAbstract(clas.getModifiers()) &&
|
||||
!Modifier.isInterface(clas.getModifiers()) ) {
|
||||
formatList.add(clas.newInstance());
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
System.out.println("Error instantiating DumpFormat from file " + file + ": "+e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return formatList;
|
||||
}
|
||||
|
||||
public static DumpFormat findDumpFormatGivenCommandDescriptor(ArrayList formatList, String formatCommandDescriptor) {
|
||||
DumpFormat match = null;
|
||||
for (int i=0; i<formatList.size(); i++) {
|
||||
if (((DumpFormat)formatList.get(i)).getCommandDescriptor().equals(formatCommandDescriptor)) {
|
||||
match = (DumpFormat) formatList.get(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return match;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,88 @@
|
||||
package mars.mips.dump;
|
||||
|
||||
import mars.Globals;
|
||||
import mars.mips.hardware.*;
|
||||
import java.io.*;
|
||||
/*
|
||||
Copyright (c) 2003-2008, 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)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class that represents the "hexadecimal text" memory dump format. The output
|
||||
* is a text file with one word of MIPS memory per line. The word is formatted
|
||||
* using hexadecimal characters, e.g. 3F205A39.
|
||||
* @author Pete Sanderson
|
||||
* @version December 2007
|
||||
*/
|
||||
|
||||
|
||||
public class HexTextDumpFormat extends AbstractDumpFormat {
|
||||
|
||||
/**
|
||||
* Constructor. There is no standard file extension for this format.
|
||||
*/
|
||||
public HexTextDumpFormat() {
|
||||
super("Hexadecimal Text", "HexText", "Written as hex characters to text file", null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Write MIPS memory contents in hexadecimal text format. Each line of
|
||||
* text contains one memory word written in hexadecimal characters. Written
|
||||
* using PrintStream's println() method.
|
||||
* Adapted by Pete Sanderson from code written by Greg Gibeling.
|
||||
*
|
||||
* @param file File in which to store MIPS memory contents.
|
||||
* @param firstAddress first (lowest) memory address to dump. In bytes but
|
||||
* must be on word boundary.
|
||||
* @param lastAddress last (highest) memory address to dump. In bytes but
|
||||
* must be on word boundary. Will dump the word that starts at this address.
|
||||
* @throws AddressErrorException if firstAddress is invalid or not on a word boundary.
|
||||
* @throws IOException if error occurs during file output.
|
||||
*/
|
||||
public void dumpMemoryRange(File file, int firstAddress, int lastAddress)
|
||||
throws AddressErrorException, IOException {
|
||||
PrintStream out = new PrintStream(new FileOutputStream(file));
|
||||
String string = null;
|
||||
try {
|
||||
for (int address = firstAddress; address <= lastAddress; address += Memory.WORD_LENGTH_BYTES) {
|
||||
Integer temp = Globals.memory.getRawWordOrNull(address);
|
||||
if (temp == null)
|
||||
break;
|
||||
string = Integer.toHexString(temp.intValue());
|
||||
while (string.length() < 8) {
|
||||
string = '0' + string;
|
||||
}
|
||||
out.println(string);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
out.close();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,74 @@
|
||||
package mars.mips.dump;
|
||||
|
||||
import mars.Globals;
|
||||
import mars.mips.hardware.*;
|
||||
import java.io.*;
|
||||
|
||||
/**
|
||||
* Intel's Hex memory initialization format
|
||||
* @author Leo Alterman
|
||||
* @version July 2011
|
||||
*/
|
||||
|
||||
public class IntelHexDumpFormat extends AbstractDumpFormat {
|
||||
|
||||
/**
|
||||
* Constructor. File extention is "hex".
|
||||
*/
|
||||
public IntelHexDumpFormat() {
|
||||
super("Intel hex format", "HEX", "Written as Intel Hex Memory File", "hex");
|
||||
}
|
||||
|
||||
/**
|
||||
* Write MIPS memory contents according to the Memory Initialization File
|
||||
* (MIF) specification.
|
||||
*
|
||||
* @param file File in which to store MIPS memory contents.
|
||||
* @param firstAddress first (lowest) memory address to dump. In bytes but
|
||||
* must be on word boundary.
|
||||
* @param lastAddress last (highest) memory address to dump. In bytes but
|
||||
* must be on word boundary. Will dump the word that starts at this address.
|
||||
* @throws AddressErrorException if firstAddress is invalid or not on a word boundary.
|
||||
* @throws IOException if error occurs during file output.
|
||||
*/
|
||||
public void dumpMemoryRange(File file, int firstAddress, int lastAddress)
|
||||
throws AddressErrorException, IOException {
|
||||
PrintStream out = new PrintStream(new FileOutputStream(file));
|
||||
String string = null;
|
||||
try {
|
||||
for (int address = firstAddress; address <= lastAddress; address += Memory.WORD_LENGTH_BYTES) {
|
||||
Integer temp = Globals.memory.getRawWordOrNull(address);
|
||||
if (temp == null)
|
||||
break;
|
||||
string = Integer.toHexString(temp.intValue());
|
||||
while (string.length() < 8) {
|
||||
string = '0' + string;
|
||||
}
|
||||
String addr = Integer.toHexString(address-firstAddress);
|
||||
while (addr.length() < 4) {
|
||||
addr = '0' + addr;
|
||||
}
|
||||
String chksum;
|
||||
int tmp_chksum = 0;
|
||||
tmp_chksum += 4;
|
||||
tmp_chksum += 0xFF & (address-firstAddress);
|
||||
tmp_chksum += 0xFF & ((address-firstAddress)>>8);
|
||||
tmp_chksum += 0xFF & temp.intValue();
|
||||
tmp_chksum += 0xFF & (temp.intValue()>>8);
|
||||
tmp_chksum += 0xFF & (temp.intValue()>>16);
|
||||
tmp_chksum += 0xFF & (temp.intValue()>>24);
|
||||
tmp_chksum = tmp_chksum % 256;
|
||||
tmp_chksum = ~tmp_chksum + 1;
|
||||
chksum = Integer.toHexString(0xFF & tmp_chksum);
|
||||
if(chksum.length()==1) chksum = '0' + chksum;
|
||||
String finalstr = ":04"+addr+"00"+string+chksum;
|
||||
out.println(finalstr.toUpperCase());
|
||||
}
|
||||
out.println(":00000001FF");
|
||||
}
|
||||
finally {
|
||||
out.close();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,71 @@
|
||||
package mars.mips.dump;
|
||||
|
||||
import mars.Globals;
|
||||
import mars.mips.hardware.*;
|
||||
import java.io.*;
|
||||
/*
|
||||
Copyright (c) 2003-2008, 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)
|
||||
*/
|
||||
|
||||
/**
|
||||
* The Memory Initialization File (.mif) VHDL-supported file format
|
||||
* This is documented for the Altera platform at
|
||||
* www.altera.com/support/software/nativelink/quartus2/glossary/def_mif.html.
|
||||
*
|
||||
* @author Pete Sanderson
|
||||
* @version December 2007
|
||||
*/
|
||||
|
||||
// NOT READY FOR PRIME TIME. WHEN IT IS, UNCOMMENT THE "extends" CLAUSE
|
||||
// AND THE SUPERCLASS CONSTRUCTOR CALL SO THE FORMAT LOADER WILL ACCEPT IT
|
||||
// AND IT WILL BE ADDED TO THE LIST.
|
||||
public class MIFDumpFormat { //extends AbstractDumpFormat {
|
||||
|
||||
/**
|
||||
* Constructor. File extention is "mif".
|
||||
*/
|
||||
public MIFDumpFormat() {
|
||||
// super("MIF", "MIF", "Written as Memory Initialization File (Altera)", "mif");
|
||||
}
|
||||
|
||||
/**
|
||||
* Write MIPS memory contents according to the Memory Initialization File
|
||||
* (MIF) specification.
|
||||
*
|
||||
* @param file File in which to store MIPS memory contents.
|
||||
* @param firstAddress first (lowest) memory address to dump. In bytes but
|
||||
* must be on word boundary.
|
||||
* @param lastAddress last (highest) memory address to dump. In bytes but
|
||||
* must be on word boundary. Will dump the word that starts at this address.
|
||||
* @throws AddressErrorException if firstAddress is invalid or not on a word boundary.
|
||||
* @throws IOException if error occurs during file output.
|
||||
*/
|
||||
public void dumpMemoryRange(File file, int firstAddress, int lastAddress)
|
||||
throws AddressErrorException, IOException {
|
||||
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,150 @@
|
||||
package mars.mips.dump;
|
||||
|
||||
import mars.Globals;
|
||||
import mars.ProgramStatement;
|
||||
import mars.util.Binary;
|
||||
import mars.mips.hardware.*;
|
||||
import java.io.*;
|
||||
/*
|
||||
Copyright (c) 2003-2008, 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)
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* Dump MIPS memory contents in Segment Window format. Each line of
|
||||
* text output resembles the Text Segment Window or Data Segment Window
|
||||
* depending on which segment is selected for the dump. Written
|
||||
* using PrintStream's println() method. Each line of Text Segment
|
||||
* Window represents one word of text segment memory. The line
|
||||
* includes (1) address, (2) machine code in hex, (3) basic instruction,
|
||||
* (4) source line. Each line of Data Segment Window represents 8
|
||||
* words of data segment memory. The line includes address of first
|
||||
* word for that line followed by 8 32-bit values.
|
||||
*
|
||||
* In either case, addresses and values are displayed in decimal or
|
||||
* hexadecimal representation according to the corresponding settings.
|
||||
*
|
||||
* @author Pete Sanderson
|
||||
* @version January 2008
|
||||
*/
|
||||
|
||||
|
||||
public class SegmentWindowDumpFormat extends AbstractDumpFormat {
|
||||
|
||||
/**
|
||||
* Constructor. There is no standard file extension for this format.
|
||||
*/
|
||||
public SegmentWindowDumpFormat() {
|
||||
super("Text/Data Segment Window", "SegmentWindow", " Text Segment Window or Data Segment Window format to text file", null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Write MIPS memory contents in Segment Window format. Each line of
|
||||
* text output resembles the Text Segment Window or Data Segment Window
|
||||
* depending on which segment is selected for the dump. Written
|
||||
* using PrintStream's println() method.
|
||||
*
|
||||
* @param file File in which to store MIPS memory contents.
|
||||
* @param firstAddress first (lowest) memory address to dump. In bytes but
|
||||
* must be on word boundary.
|
||||
* @param lastAddress last (highest) memory address to dump. In bytes but
|
||||
* must be on word boundary. Will dump the word that starts at this address.
|
||||
* @throws AddressErrorException if firstAddress is invalid or not on a word boundary.
|
||||
* @throws IOException if error occurs during file output.
|
||||
*/
|
||||
public void dumpMemoryRange(File file, int firstAddress, int lastAddress)
|
||||
throws AddressErrorException, IOException {
|
||||
|
||||
PrintStream out = new PrintStream(new FileOutputStream(file));
|
||||
|
||||
boolean hexAddresses = Globals.getSettings().getDisplayAddressesInHex();
|
||||
|
||||
// If address in data segment, print in same format as Data Segment Window
|
||||
if (Memory.inDataSegment(firstAddress)) {
|
||||
boolean hexValues = Globals.getSettings().getDisplayValuesInHex();
|
||||
int offset = 0;
|
||||
String string="";
|
||||
try {
|
||||
for (int address = firstAddress; address <= lastAddress; address += Memory.WORD_LENGTH_BYTES) {
|
||||
if (offset % 8 == 0) {
|
||||
string = ((hexAddresses) ? Binary.intToHexString(address) : Binary.unsignedIntToIntString(address)) + " ";
|
||||
}
|
||||
offset++;
|
||||
Integer temp = Globals.memory.getRawWordOrNull(address);
|
||||
if (temp == null)
|
||||
break;
|
||||
string += ((hexValues)
|
||||
? Binary.intToHexString(temp.intValue())
|
||||
: (" "+temp).substring(temp.toString().length())
|
||||
) + " ";
|
||||
if (offset % 8 == 0) {
|
||||
out.println(string);
|
||||
string = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
out.close();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Memory.inTextSegment(firstAddress)) {
|
||||
return;
|
||||
}
|
||||
// If address in text segment, print in same format as Text Segment Window
|
||||
out.println(" Address Code Basic Source");
|
||||
// 12345678901234567890123456789012345678901234567890
|
||||
// 1 2 3 4 5
|
||||
out.println();
|
||||
String string = null;
|
||||
try {
|
||||
for (int address = firstAddress; address <= lastAddress; address += Memory.WORD_LENGTH_BYTES) {
|
||||
string = ((hexAddresses) ? Binary.intToHexString(address) : Binary.unsignedIntToIntString(address)) + " ";
|
||||
Integer temp = Globals.memory.getRawWordOrNull(address);
|
||||
if (temp == null)
|
||||
break;
|
||||
string += Binary.intToHexString(temp.intValue()) + " ";
|
||||
try {
|
||||
ProgramStatement ps = Globals.memory.getStatement(address);
|
||||
string += (ps.getPrintableBasicAssemblyStatement()+" ").substring(0,22);
|
||||
string += (((ps.getSource()=="") ? "" : new Integer(ps.getSourceLine()).toString())+" ").substring(0,5);
|
||||
string += ps.getSource();
|
||||
}
|
||||
catch (AddressErrorException aee) {
|
||||
}
|
||||
out.println(string);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
out.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,89 @@
|
||||
package mars.mips.hardware;
|
||||
|
||||
/*
|
||||
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)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Object provided to Observers of runtime access to MIPS memory or registers.
|
||||
* The access types READ and WRITE defined here; use subclasses defined for
|
||||
* MemoryAccessNotice and RegisterAccessNotice. This is abstract class.
|
||||
*
|
||||
* @author Pete Sanderson
|
||||
* @version July 2005
|
||||
*/
|
||||
|
||||
|
||||
public abstract class AccessNotice {
|
||||
/** Indicates the purpose of access was to read. */
|
||||
public static final int READ = 0;
|
||||
/** Indicates the purpose of access was to write. */
|
||||
public static final int WRITE = 1;
|
||||
|
||||
private int accessType;
|
||||
private Thread thread;
|
||||
|
||||
protected AccessNotice(int type) {
|
||||
if (type != READ && type != WRITE) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
accessType = type;
|
||||
thread = Thread.currentThread();
|
||||
}
|
||||
/** Get the access type: READ or WRITE.
|
||||
* @return Access type, either AccessNotice.READ or AccessNotice.WRITE
|
||||
*/
|
||||
public int getAccessType() {
|
||||
return accessType;
|
||||
}
|
||||
|
||||
/** Get reference to thread that created this notice
|
||||
* @return Return reference to the thread that created this notice.
|
||||
*/
|
||||
public Thread getThread() {
|
||||
return thread;
|
||||
}
|
||||
|
||||
/** Query whether the access originated from MARS GUI (AWT event queue)
|
||||
* @return true if this access originated from MARS GUI, false otherwise
|
||||
*/
|
||||
// 'A' is the first character of the main AWT event queue thread name.
|
||||
// "AWT-EventQueue-0"
|
||||
public boolean accessIsFromGUI() {
|
||||
return thread.getName().startsWith("AWT");
|
||||
}
|
||||
|
||||
/** Query whether the access originated from executing MIPS program
|
||||
* @return true if this access originated from executing MIPS program, false otherwise
|
||||
*/
|
||||
// Thread to execute the MIPS program is instantiated in SwingWorker.java.
|
||||
// There it is given the name "MIPS" to replace the default "Thread-x".
|
||||
public boolean accessIsFromMIPS() {
|
||||
return thread.getName().startsWith("MIPS");
|
||||
}
|
||||
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,73 @@
|
||||
package mars.mips.hardware;
|
||||
import mars.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)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Represents MIPS AddressErrorException. This is generated by the assembler when the
|
||||
* source code references a memory address not valid for the context.
|
||||
*
|
||||
* @author Pete Sanderson
|
||||
* @version August 2003
|
||||
**/
|
||||
public class AddressErrorException extends Exception {
|
||||
private int address;
|
||||
private int type; // Exceptions.ADDRESS_EXCEPTION_LOAD,Exceptions.ADDRESS_EXCEPTION_STORE
|
||||
|
||||
|
||||
/**
|
||||
* Constructor for the AddressErrorException class
|
||||
*
|
||||
* @param addr The erroneous memory address.
|
||||
**/
|
||||
|
||||
public AddressErrorException(String message, int exceptType, int addr) {
|
||||
super(message+Binary.intToHexString(addr));
|
||||
address = addr;
|
||||
type = exceptType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the erroneous memory address.
|
||||
*
|
||||
* @return The erroneous memory address.
|
||||
**/
|
||||
public int getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the exception type (load or store).
|
||||
*
|
||||
* @return Exception type: Exceptions.ADDRESS_EXCEPTION_LOAD, Exceptions.ADDRESS_EXCEPTION_STORE
|
||||
**/
|
||||
public int getType() {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,215 @@
|
||||
package mars.mips.hardware;
|
||||
import mars.Globals;
|
||||
import java.util.*;
|
||||
|
||||
/*
|
||||
Copyright (c) 2003-2009, 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)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Represents Coprocessor 0. We will use only its interrupt/exception registers.
|
||||
* @author Pete Sanderson
|
||||
* @version August 2005
|
||||
**/
|
||||
|
||||
public class Coprocessor0 {
|
||||
/** Coprocessor register names
|
||||
*/
|
||||
public static final int VADDR = 8;
|
||||
public static final int STATUS = 12;
|
||||
public static final int CAUSE = 13;
|
||||
public static final int EPC = 14;
|
||||
|
||||
public static final int EXCEPTION_LEVEL = 1; // bit position in STATUS register
|
||||
// bits 8-15 (mask for interrupt levels) all set, bit 4 (user mode) set,
|
||||
// bit 1 (exception level) not set, bit 0 (interrupt enable) set.
|
||||
public static final int DEFAULT_STATUS_VALUE = 0x0000FF11;
|
||||
|
||||
private static Register [] registers =
|
||||
{ new Register("$8 (vaddr)", 8, 0),
|
||||
new Register("$12 (status)", 12, DEFAULT_STATUS_VALUE),
|
||||
new Register("$13 (cause)", 13, 0),
|
||||
new Register("$14 (epc)", 14, 0)
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Method for displaying the register values for debugging.
|
||||
**/
|
||||
|
||||
public static void showRegisters(){
|
||||
for (int i=0; i< registers.length; i++){
|
||||
System.out.println("Name: " + registers[i].getName());
|
||||
System.out.println("Number: " + registers[i].getNumber());
|
||||
System.out.println("Value: " + registers[i].getValue());
|
||||
System.out.println("");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the register given to the value given.
|
||||
* @param n name of register to set the value of ($n, where n is reg number).
|
||||
* @param val The desired value for the register.
|
||||
* @return old value in register prior to update
|
||||
**/
|
||||
|
||||
public static int updateRegister(String n, int val){
|
||||
int oldValue = 0;
|
||||
for (int i=0; i< registers.length; i++){
|
||||
if(("$"+registers[i].getNumber()).equals(n) || registers[i].getName().equals(n)) {
|
||||
oldValue = registers[i].getValue();
|
||||
registers[i].setValue(val);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return oldValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method updates the register value who's number is num.
|
||||
* @param num Number of register to set the value of.
|
||||
* @param val The desired value for the register.
|
||||
* @return old value in register prior to update
|
||||
**/
|
||||
public static int updateRegister(int num, int val){
|
||||
int old = 0;
|
||||
for (int i=0; i< registers.length; i++){
|
||||
if(registers[i].getNumber()== num) {
|
||||
old = (Globals.getSettings().getBackSteppingEnabled())
|
||||
? Globals.program.getBackStepper().addCoprocessor0Restore(num,registers[i].setValue(val))
|
||||
: registers[i].setValue(val);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return old;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the value of the register who's number is num.
|
||||
* @param num The register number.
|
||||
* @return The value of the given register. 0 for non-implemented registers
|
||||
**/
|
||||
|
||||
public static int getValue(int num){
|
||||
for (int i=0; i< registers.length; i++){
|
||||
if(registers[i].getNumber()== num) {
|
||||
return registers[i].getValue();
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* For getting the number representation of the register.
|
||||
* @param n The string formatted register name to look for.
|
||||
* @return The number of the register represented by the string. -1 if no match.
|
||||
**/
|
||||
|
||||
public static int getNumber(String n){
|
||||
for (int i=0; i< registers.length; i++){
|
||||
if(("$"+registers[i].getNumber()).equals(n) || registers[i].getName().equals(n)) {
|
||||
return registers[i].getNumber();
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* For returning the set of registers.
|
||||
* @return The set of registers.
|
||||
**/
|
||||
|
||||
public static Register[] getRegisters(){
|
||||
return registers;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Coprocessor0 implements only selected registers, so the register number
|
||||
* (8, 12, 13, 14) does not correspond to its position in the list of registers
|
||||
* (0, 1, 2, 3).
|
||||
* @param r A coprocessor0 Register
|
||||
* @return the list position of given register, -1 if not found.
|
||||
**/
|
||||
|
||||
public static int getRegisterPosition(Register r){
|
||||
for (int i=0; i< registers.length; i++){
|
||||
if(registers[i]==r) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get register object corresponding to given name. If no match, return null.
|
||||
* @param rname The register name, in $0 format.
|
||||
* @return The register object,or null if not found.
|
||||
**/
|
||||
|
||||
public static Register getRegister(String rname) {
|
||||
for (int i=0; i< registers.length; i++){
|
||||
if(("$"+registers[i].getNumber()).equals(rname) || registers[i].getName().equals(rname)) {
|
||||
return registers[i];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Method to reinitialize the values of the registers.
|
||||
**/
|
||||
|
||||
public static void resetRegisters(){
|
||||
for(int i=0; i< registers.length; i++){
|
||||
registers[i].resetValue();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Each individual register is a separate object and Observable. This handy method
|
||||
* will add the given Observer to each one.
|
||||
*/
|
||||
public static void addRegistersObserver(Observer observer) {
|
||||
for (int i=0; i<registers.length; i++) {
|
||||
registers[i].addObserver(observer);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Each individual register is a separate object and Observable. This handy method
|
||||
* will delete the given Observer from each one.
|
||||
*/
|
||||
public static void deleteRegistersObserver(Observer observer) {
|
||||
for (int i=0; i<registers.length; i++) {
|
||||
registers[i].deleteObserver(observer);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,525 @@
|
||||
package mars.mips.hardware;
|
||||
import mars.util.*;
|
||||
import mars.Globals;
|
||||
import java.util.*;
|
||||
|
||||
/*
|
||||
Copyright (c) 2003-2009, 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)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Represents Coprocessor 1, the Floating Point Unit (FPU)
|
||||
* @author Pete Sanderson
|
||||
* @version July 2005
|
||||
**/
|
||||
|
||||
// Adapted from RegisterFile class developed by Bumgarner et al in 2003.
|
||||
// The FPU registers will be implemented by Register objects. Such objects
|
||||
// can only hold int values, but we can use Float.floatToIntBits() to translate
|
||||
// a 32 bit float value into its equivalent 32-bit int representation, and
|
||||
// Float.intBitsToFloat() to bring it back. More importantly, there are
|
||||
// similar methods Double.doubleToLongBits() and Double.LongBitsToDouble()
|
||||
// which can be used to extend a double value over 2 registers. The resulting
|
||||
// long is split into 2 int values (high order 32 bits, low order 32 bits) for
|
||||
// storing into registers, and reassembled upon retrieval.
|
||||
|
||||
public class Coprocessor1 {
|
||||
private static Register [] registers =
|
||||
{ new Register("$f0", 0, 0), new Register("$f1", 1, 0),
|
||||
new Register("$f2", 2, 0), new Register("$f3", 3, 0),
|
||||
new Register("$f4", 4, 0), new Register("$f5", 5, 0),
|
||||
new Register("$f6", 6, 0), new Register("$f7", 7, 0),
|
||||
new Register("$f8", 8, 0), new Register("$f9", 9, 0),
|
||||
new Register("$f10", 10, 0),new Register("$f11", 11, 0),
|
||||
new Register("$f12", 12, 0),new Register("$f13", 13, 0),
|
||||
new Register("$f14", 14, 0),new Register("$f15", 15, 0),
|
||||
new Register("$f16", 16, 0),new Register("$f17", 17, 0),
|
||||
new Register("$f18", 18, 0),new Register("$f19", 19, 0),
|
||||
new Register("$f20", 20, 0),new Register("$f21", 21, 0),
|
||||
new Register("$f22", 22, 0),new Register("$f23", 23, 0),
|
||||
new Register("$f24", 24, 0),new Register("$f25", 25, 0),
|
||||
new Register("$f26", 26, 0),new Register("$f27", 27, 0),
|
||||
new Register("$f28", 28, 0),new Register("$f29", 29, 0),
|
||||
new Register("$f30", 30, 0),new Register("$f31", 31, 0)
|
||||
};
|
||||
// The 8 condition flags will be stored in bits 0-7 for flags 0-7.
|
||||
private static Register condition = new Register("cf",32, 0);
|
||||
private static int numConditionFlags = 8;
|
||||
|
||||
/**
|
||||
* Method for displaying the register values for debugging.
|
||||
**/
|
||||
|
||||
public static void showRegisters(){
|
||||
for (int i=0; i< registers.length; i++){
|
||||
|
||||
System.out.println("Name: " + registers[i].getName());
|
||||
System.out.println("Number: " + registers[i].getNumber());
|
||||
System.out.println("Value: " + registers[i].getValue());
|
||||
System.out.println("");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the FPU register given to the value given.
|
||||
* @param reg Register to set the value of.
|
||||
* @param val The desired float value for the register.
|
||||
**/
|
||||
|
||||
public static void setRegisterToFloat(String reg, float val){
|
||||
setRegisterToFloat(getRegisterNumber(reg), val);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the value of the FPU register given to the value given.
|
||||
* @param reg Register to set the value of.
|
||||
* @param val The desired float value for the register.
|
||||
**/
|
||||
|
||||
public static void setRegisterToFloat(int reg, float val){
|
||||
if(reg >= 0 && reg < registers.length) {
|
||||
registers[reg].setValue(Float.floatToRawIntBits(val));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the FPU register given to the 32-bit
|
||||
* pattern given by the int parameter.
|
||||
* @param reg Register to set the value of.
|
||||
* @param val The desired int bit pattern for the register.
|
||||
**/
|
||||
|
||||
public static void setRegisterToInt(String reg, int val){
|
||||
setRegisterToInt(getRegisterNumber(reg), val);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the value of the FPU register given to the 32-bit
|
||||
* pattern given by the int parameter.
|
||||
* @param reg Register to set the value of.
|
||||
* @param val The desired int bit pattern for the register.
|
||||
**/
|
||||
|
||||
public static void setRegisterToInt(int reg, int val){
|
||||
if(reg >= 0 && reg < registers.length) {
|
||||
registers[reg].setValue(val);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the value of the FPU register given to the double value given. The register
|
||||
* must be even-numbered, and the low order 32 bits are placed in it. The high order
|
||||
* 32 bits are placed in the (odd numbered) register that follows it.
|
||||
* @param reg Register to set the value of.
|
||||
* @param val The desired double value for the register.
|
||||
* @throws InvalidRegisterAccessException if register ID is invalid or odd-numbered.
|
||||
**/
|
||||
|
||||
public static void setRegisterPairToDouble(int reg, double val)
|
||||
throws InvalidRegisterAccessException {
|
||||
if (reg % 2 != 0) {
|
||||
throw new InvalidRegisterAccessException();
|
||||
}
|
||||
long bits = Double.doubleToRawLongBits(val);
|
||||
registers[reg+1].setValue(Binary.highOrderLongToInt(bits)); // high order 32 bits
|
||||
registers[reg].setValue(Binary.lowOrderLongToInt(bits)); // low order 32 bits
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the value of the FPU register given to the double value given. The register
|
||||
* must be even-numbered, and the low order 32 bits are placed in it. The high order
|
||||
* 32 bits are placed in the (odd numbered) register that follows it.
|
||||
* @param reg Register to set the value of.
|
||||
* @param val The desired double value for the register.
|
||||
* @throws InvalidRegisterAccessException if register ID is invalid or odd-numbered.
|
||||
**/
|
||||
public static void setRegisterPairToDouble(String reg, double val)
|
||||
throws InvalidRegisterAccessException {
|
||||
setRegisterPairToDouble(getRegisterNumber(reg), val);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the value of the FPU register pair given to the long value containing 64 bit pattern
|
||||
* given. The register
|
||||
* must be even-numbered, and the low order 32 bits from the long are placed in it. The high order
|
||||
* 32 bits from the long are placed in the (odd numbered) register that follows it.
|
||||
* @param reg Register to set the value of. Must be even register of even/odd pair.
|
||||
* @param val The desired double value for the register.
|
||||
* @throws InvalidRegisterAccessException if register ID is invalid or odd-numbered.
|
||||
**/
|
||||
|
||||
public static void setRegisterPairToLong(int reg, long val)
|
||||
throws InvalidRegisterAccessException {
|
||||
if (reg % 2 != 0) {
|
||||
throw new InvalidRegisterAccessException();
|
||||
}
|
||||
registers[reg+1].setValue(Binary.highOrderLongToInt(val)); // high order 32 bits
|
||||
registers[reg].setValue(Binary.lowOrderLongToInt(val)); // low order 32 bits
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the value of the FPU register pair given to the long value containing 64 bit pattern
|
||||
* given. The register
|
||||
* must be even-numbered, and the low order 32 bits from the long are placed in it. The high order
|
||||
* 32 bits from the long are placed in the (odd numbered) register that follows it.
|
||||
* @param reg Register to set the value of. Must be even register of even/odd pair.
|
||||
* @param val The desired long value containing the 64 bits for the register pair.
|
||||
* @throws InvalidRegisterAccessException if register ID is invalid or odd-numbered.
|
||||
**/
|
||||
public static void setRegisterPairToLong(String reg, long val)
|
||||
throws InvalidRegisterAccessException {
|
||||
setRegisterPairToLong(getRegisterNumber(reg), val);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Gets the float value stored in the given FPU register.
|
||||
* @param reg Register to get the value of.
|
||||
* @return The float value stored by that register.
|
||||
**/
|
||||
|
||||
public static float getFloatFromRegister(int reg){
|
||||
float result = 0F;
|
||||
if(reg >= 0 && reg < registers.length) {
|
||||
result = Float.intBitsToFloat(registers[reg].getValue());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the float value stored in the given FPU register.
|
||||
* @param reg Register to get the value of.
|
||||
* @return The float value stored by that register.
|
||||
**/
|
||||
|
||||
public static float getFloatFromRegister(String reg) {
|
||||
return getFloatFromRegister(getRegisterNumber(reg));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the 32-bit int bit pattern stored in the given FPU register.
|
||||
* @param reg Register to get the value of.
|
||||
* @return The int bit pattern stored by that register.
|
||||
**/
|
||||
|
||||
public static int getIntFromRegister(int reg){
|
||||
int result = 0;
|
||||
if(reg >= 0 && reg < registers.length) {
|
||||
result = registers[reg].getValue();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the 32-bit int bit pattern stored in the given FPU register.
|
||||
* @param reg Register to get the value of.
|
||||
* @return The int bit pattern stored by that register.
|
||||
**/
|
||||
|
||||
public static int getIntFromRegister(String reg) {
|
||||
return getIntFromRegister(getRegisterNumber(reg));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the double value stored in the given FPU register. The register
|
||||
* must be even-numbered.
|
||||
* @param reg Register to get the value of. Must be even number of even/odd pair.
|
||||
* @throws InvalidRegisterAccessException if register ID is invalid or odd-numbered.
|
||||
**/
|
||||
|
||||
public static double getDoubleFromRegisterPair(int reg)
|
||||
throws InvalidRegisterAccessException {
|
||||
double result = 0.0;
|
||||
if (reg % 2 != 0) {
|
||||
throw new InvalidRegisterAccessException();
|
||||
}
|
||||
long bits = Binary.twoIntsToLong(registers[reg+1].getValue(),registers[reg].getValue());
|
||||
return Double.longBitsToDouble(bits);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the double value stored in the given FPU register. The register
|
||||
* must be even-numbered.
|
||||
* @param reg Register to get the value of. Must be even number of even/odd pair.
|
||||
* @throws InvalidRegisterAccessException if register ID is invalid or odd-numbered.
|
||||
**/
|
||||
|
||||
public static double getDoubleFromRegisterPair(String reg)
|
||||
throws InvalidRegisterAccessException {
|
||||
return getDoubleFromRegisterPair(getRegisterNumber(reg));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets a long representing the double value stored in the given double
|
||||
* precision FPU register.
|
||||
* The register must be even-numbered.
|
||||
* @param reg Register to get the value of. Must be even number of even/odd pair.
|
||||
* @throws InvalidRegisterAccessException if register ID is invalid or odd-numbered.
|
||||
**/
|
||||
|
||||
public static long getLongFromRegisterPair(int reg)
|
||||
throws InvalidRegisterAccessException {
|
||||
double result = 0.0;
|
||||
if (reg % 2 != 0) {
|
||||
throw new InvalidRegisterAccessException();
|
||||
}
|
||||
return Binary.twoIntsToLong(registers[reg+1].getValue(),registers[reg].getValue());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the double value stored in the given FPU register. The register
|
||||
* must be even-numbered.
|
||||
* @param reg Register to get the value of. Must be even number of even/odd pair.
|
||||
* @throws InvalidRegisterAccessException if register ID is invalid or odd-numbered.
|
||||
**/
|
||||
|
||||
public static long getLongFromRegisterPair(String reg)
|
||||
throws InvalidRegisterAccessException {
|
||||
return getLongFromRegisterPair(getRegisterNumber(reg));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method updates the FPU register value who's number is num. Note the
|
||||
* registers themselves hold an int value. There are helper methods available
|
||||
* to which you can give a float or double to store.
|
||||
* @param num FPU register to set the value of.
|
||||
* @param val The desired int value for the register.
|
||||
**/
|
||||
|
||||
public static int updateRegister(int num, int val){
|
||||
int old = 0;
|
||||
for (int i=0; i< registers.length; i++){
|
||||
if(registers[i].getNumber()== num) {
|
||||
old = (Globals.getSettings().getBackSteppingEnabled())
|
||||
? Globals.program.getBackStepper().addCoprocessor1Restore(num,registers[i].setValue(val))
|
||||
: registers[i].setValue(val);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return old;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the FPU register who's number is num. Returns the
|
||||
* raw int value actually stored there. If you need a float, use
|
||||
* Float.intBitsToFloat() to get the equivent float.
|
||||
* @param num The FPU register number.
|
||||
* @return The int value of the given register.
|
||||
**/
|
||||
|
||||
public static int getValue(int num){
|
||||
return registers[num].getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* For getting the number representation of the FPU register.
|
||||
* @param n The string formatted register name to look for.
|
||||
* @return The number of the register represented by the string.
|
||||
**/
|
||||
|
||||
public static int getRegisterNumber(String n){
|
||||
int j=-1;
|
||||
for (int i=0; i< registers.length; i++){
|
||||
if(registers[i].getName().equals(n)) {
|
||||
j= registers[i].getNumber();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return j;
|
||||
}
|
||||
|
||||
/**
|
||||
* For returning the set of registers.
|
||||
* @return The set of registers.
|
||||
**/
|
||||
|
||||
public static Register[] getRegisters(){
|
||||
return registers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get register object corresponding to given name. If no match, return null.
|
||||
* @param rName The FPU register name, must be "$f0" through "$f31".
|
||||
* @return The register object,or null if not found.
|
||||
**/
|
||||
|
||||
public static Register getRegister(String rName) {
|
||||
Register reg = null;
|
||||
if (rName.charAt(0) == '$' && rName.length() > 1 && rName.charAt(1) == 'f') {
|
||||
try {
|
||||
// check for register number 0-31.
|
||||
reg = registers[Binary.stringToInt(rName.substring(2))]; // KENV 1/6/05
|
||||
}
|
||||
catch (Exception e) {
|
||||
// handles both NumberFormat and ArrayIndexOutOfBounds
|
||||
reg = null;
|
||||
}
|
||||
}
|
||||
return reg;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Method to reinitialize the values of the registers.
|
||||
**/
|
||||
|
||||
public static void resetRegisters(){
|
||||
for(int i=0; i < registers.length; i++)
|
||||
registers[i].resetValue();
|
||||
clearConditionFlags();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Each individual register is a separate object and Observable. This handy method
|
||||
* will add the given Observer to each one.
|
||||
*/
|
||||
public static void addRegistersObserver(Observer observer) {
|
||||
for (int i=0; i<registers.length; i++) {
|
||||
registers[i].addObserver(observer);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Each individual register is a separate object and Observable. This handy method
|
||||
* will delete the given Observer from each one.
|
||||
*/
|
||||
public static void deleteRegistersObserver(Observer observer) {
|
||||
for (int i=0; i<registers.length; i++) {
|
||||
registers[i].deleteObserver(observer);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set condition flag to 1 (true).
|
||||
*
|
||||
* @param flag condition flag number (0-7)
|
||||
* @return previous flag setting (0 or 1)
|
||||
*/
|
||||
public static int setConditionFlag(int flag) {
|
||||
int old = 0;
|
||||
if (flag >= 0 && flag < numConditionFlags) {
|
||||
old = getConditionFlag(flag);
|
||||
condition.setValue(Binary.setBit(condition.getValue(),flag));
|
||||
if (Globals.getSettings().getBackSteppingEnabled())
|
||||
if (old==0) {
|
||||
Globals.program.getBackStepper().addConditionFlagClear(flag);
|
||||
}
|
||||
else {
|
||||
Globals.program.getBackStepper().addConditionFlagSet(flag);
|
||||
}
|
||||
}
|
||||
return old;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set condition flag to 0 (false).
|
||||
*
|
||||
* @param flag condition flag number (0-7)
|
||||
* @return previous flag setting (0 or 1)
|
||||
*/
|
||||
public static int clearConditionFlag(int flag) {
|
||||
int old = 0;
|
||||
if (flag >= 0 && flag < numConditionFlags) {
|
||||
old = getConditionFlag(flag);
|
||||
condition.setValue(Binary.clearBit(condition.getValue(),flag));
|
||||
if (Globals.getSettings().getBackSteppingEnabled())
|
||||
if (old==0) {
|
||||
Globals.program.getBackStepper().addConditionFlagClear(flag);
|
||||
}
|
||||
else {
|
||||
Globals.program.getBackStepper().addConditionFlagSet(flag);
|
||||
}
|
||||
}
|
||||
return old;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get value of specified condition flag (0-7).
|
||||
*
|
||||
* @param flag condition flag number (0-7)
|
||||
* @return 0 if condition is false, 1 if condition is true
|
||||
*/
|
||||
public static int getConditionFlag(int flag) {
|
||||
if (flag < 0 || flag >= numConditionFlags)
|
||||
flag = 0;
|
||||
return Binary.bitValue(condition.getValue(), flag);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get array of condition flags (0-7).
|
||||
*
|
||||
* @return array of int condition flags
|
||||
*/
|
||||
public static int getConditionFlags() {
|
||||
return condition.getValue();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Clear all condition flags (0-7).
|
||||
*
|
||||
*/
|
||||
public static void clearConditionFlags() {
|
||||
condition.setValue(0); // sets all 32 bits to 0.
|
||||
}
|
||||
|
||||
/**
|
||||
* Set all condition flags (0-7).
|
||||
*
|
||||
*/
|
||||
public static void setConditionFlags() {
|
||||
condition.setValue(-1); // sets all 32 bits to 1.
|
||||
}
|
||||
|
||||
/**
|
||||
* Get count of condition flags.
|
||||
*
|
||||
* @return number of condition flags
|
||||
*/
|
||||
public static int getConditionFlagCount() {
|
||||
return numConditionFlags;
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,51 @@
|
||||
package mars.mips.hardware;
|
||||
import mars.*;
|
||||
|
||||
/*
|
||||
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)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Represents attempt to access double precision register using an odd
|
||||
* (e.g. $f1, $f23) register name.
|
||||
*
|
||||
* @author Pete Sanderson
|
||||
* @version July 2005
|
||||
**/
|
||||
|
||||
public class InvalidRegisterAccessException extends Exception {
|
||||
private ErrorList errs;
|
||||
|
||||
/**
|
||||
* Constructor for IllegalRegisterException.
|
||||
*
|
||||
**/
|
||||
public InvalidRegisterAccessException() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@@ -0,0 +1,79 @@
|
||||
package mars.mips.hardware;
|
||||
|
||||
/*
|
||||
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)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Object provided to Observers of runtime access to MIPS memory.
|
||||
* Observer can get the access type (R/W), address and length in bytes (4,2,1).
|
||||
*
|
||||
* @author Pete Sanderson
|
||||
* @version July 2005
|
||||
*/
|
||||
|
||||
public class MemoryAccessNotice extends AccessNotice {
|
||||
private int address;
|
||||
private int length;
|
||||
private int value;
|
||||
|
||||
/** Constructor will be called only within this package, so assume
|
||||
* address and length are in valid ranges.
|
||||
*/
|
||||
MemoryAccessNotice(int type, int address, int length, int value) {
|
||||
super(type);
|
||||
this.address = address;
|
||||
this.length = length;
|
||||
this.value = value;
|
||||
}
|
||||
/** Constructor will be called only within this package, so assume
|
||||
* address is in valid range.
|
||||
*/
|
||||
public MemoryAccessNotice(int type, int address, int value) {
|
||||
super(type);
|
||||
this.address = address;
|
||||
this.length = Memory.WORD_LENGTH_BYTES;
|
||||
this.value = value;
|
||||
}
|
||||
/** Fetch the memory address that was accessed. */
|
||||
public int getAddress() {
|
||||
return address;
|
||||
}
|
||||
/** Fetch the length in bytes of the access operation (4,2,1). */
|
||||
public int getLength() {
|
||||
return length;
|
||||
}
|
||||
/** Fetch the value of the access operation (the value read or written). */
|
||||
public int getValue() {
|
||||
return value;
|
||||
}
|
||||
/** String representation indicates access type, address and length in bytes */
|
||||
public String toString() {
|
||||
return ((this.getAccessType()==AccessNotice.READ) ? "R " : "W ") +
|
||||
"Mem " + address + " " + length + "B = "+value;
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,157 @@
|
||||
package mars.mips.hardware;
|
||||
|
||||
/*
|
||||
Copyright (c) 2003-2009, 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)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Models the memory configuration for the simulated MIPS machine.
|
||||
* "configuration" refers to the starting memory addresses for
|
||||
* the various memory segments.
|
||||
* The default configuration is based on SPIM. Starting with MARS 3.7,
|
||||
* the configuration can be changed.
|
||||
*
|
||||
* @author Pete Sanderson
|
||||
* @version August 2009
|
||||
*/
|
||||
|
||||
|
||||
public class MemoryConfiguration {
|
||||
// Identifier is used for saving setting; name is used for display
|
||||
private String configurationIdentifier, configurationName;
|
||||
private String[] configurationItemNames;
|
||||
private int[] configurationItemValues;
|
||||
|
||||
|
||||
public MemoryConfiguration(String ident, String name, String[] items, int[] values) {
|
||||
this.configurationIdentifier = ident;
|
||||
this.configurationName = name;
|
||||
this.configurationItemNames = items;
|
||||
this.configurationItemValues = values;
|
||||
}
|
||||
|
||||
public String getConfigurationIdentifier() {
|
||||
return configurationIdentifier;
|
||||
}
|
||||
|
||||
public String getConfigurationName() {
|
||||
return configurationName;
|
||||
}
|
||||
|
||||
public int[] getConfigurationItemValues() {
|
||||
return configurationItemValues;
|
||||
}
|
||||
|
||||
public String[] getConfigurationItemNames() {
|
||||
return configurationItemNames;
|
||||
}
|
||||
|
||||
public int getTextBaseAddress() {
|
||||
return configurationItemValues[0];
|
||||
}
|
||||
|
||||
public int getDataSegmentBaseAddress() {
|
||||
return configurationItemValues[1];
|
||||
}
|
||||
|
||||
public int getExternBaseAddress() {
|
||||
return configurationItemValues[2];
|
||||
}
|
||||
|
||||
public int getGlobalPointer() {
|
||||
return configurationItemValues[3];
|
||||
}
|
||||
|
||||
public int getDataBaseAddress() {
|
||||
return configurationItemValues[4];
|
||||
}
|
||||
|
||||
public int getHeapBaseAddress() {
|
||||
return configurationItemValues[5];
|
||||
}
|
||||
|
||||
public int getStackPointer() {
|
||||
return configurationItemValues[6];
|
||||
}
|
||||
|
||||
public int getStackBaseAddress() {
|
||||
return configurationItemValues[7];
|
||||
}
|
||||
|
||||
public int getUserHighAddress() {
|
||||
return configurationItemValues[8];
|
||||
}
|
||||
|
||||
public int getKernelBaseAddress() {
|
||||
return configurationItemValues[9];
|
||||
}
|
||||
|
||||
public int getKernelTextBaseAddress() {
|
||||
return configurationItemValues[10];
|
||||
}
|
||||
|
||||
public int getExceptionHandlerAddress() {
|
||||
return configurationItemValues[11];
|
||||
}
|
||||
|
||||
public int getKernelDataBaseAddress() {
|
||||
return configurationItemValues[12];
|
||||
}
|
||||
|
||||
public int getMemoryMapBaseAddress() {
|
||||
return configurationItemValues[13];
|
||||
}
|
||||
|
||||
public int getKernelHighAddress () {
|
||||
return configurationItemValues[14];
|
||||
}
|
||||
|
||||
public int getDataSegmentLimitAddress() {
|
||||
return configurationItemValues[15];
|
||||
}
|
||||
|
||||
public int getTextLimitAddress() {
|
||||
return configurationItemValues[16];
|
||||
}
|
||||
|
||||
public int getKernelDataSegmentLimitAddress() {
|
||||
return configurationItemValues[17];
|
||||
}
|
||||
|
||||
public int getKernelTextLimitAddress() {
|
||||
return configurationItemValues[18];
|
||||
}
|
||||
|
||||
public int getStackLimitAddress() {
|
||||
return configurationItemValues[19];
|
||||
}
|
||||
|
||||
public int getMemoryMapLimitAddress() {
|
||||
return configurationItemValues[20];
|
||||
}
|
||||
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,322 @@
|
||||
package mars.mips.hardware;
|
||||
import mars.Globals;
|
||||
import java.util.*;
|
||||
|
||||
/*
|
||||
Copyright (c) 2003-2009, 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)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Models the collection of MIPS memory configurations.
|
||||
* The default configuration is based on SPIM. Starting with MARS 3.7,
|
||||
* the configuration can be changed.
|
||||
*
|
||||
* @author Pete Sanderson
|
||||
* @version August 2009
|
||||
*/
|
||||
|
||||
|
||||
public class MemoryConfigurations {
|
||||
|
||||
private static ArrayList configurations = null;
|
||||
private static MemoryConfiguration defaultConfiguration;
|
||||
private static MemoryConfiguration currentConfiguration;
|
||||
|
||||
// Be careful, these arrays are parallel and position-sensitive.
|
||||
// The getters in this and in MemoryConfiguration depend on this
|
||||
// sequence. Should be refactored... The order comes from the
|
||||
// original listed order in Memory.java, where most of these were
|
||||
// "final" until Mars 3.7 and changeable memory configurations.
|
||||
private static final String[] configurationItemNames = {
|
||||
".text base address",
|
||||
"data segment base address",
|
||||
".extern base address",
|
||||
"global pointer $gp",
|
||||
".data base address",
|
||||
"heap base address",
|
||||
"stack pointer $sp",
|
||||
"stack base address",
|
||||
"user space high address",
|
||||
"kernel space base address",
|
||||
".ktext base address",
|
||||
"exception handler address",
|
||||
".kdata base address",
|
||||
"MMIO base address",
|
||||
"kernel space high address",
|
||||
"data segment limit address",
|
||||
"text limit address",
|
||||
"kernel data segment limit address",
|
||||
"kernel text limit address",
|
||||
"stack limit address",
|
||||
"memory map limit address"
|
||||
};
|
||||
|
||||
// Default configuration comes from SPIM
|
||||
private static int[] defaultConfigurationItemValues = {
|
||||
0x00400000, // .text Base Address
|
||||
0x10000000, // Data Segment base address
|
||||
0x10000000, // .extern Base Address
|
||||
0x10008000, // Global Pointer $gp)
|
||||
0x10010000, // .data base Address
|
||||
0x10040000, // heap base address
|
||||
0x7fffeffc, // stack pointer $sp (from SPIM not MIPS)
|
||||
0x7ffffffc, // stack base address
|
||||
0x7fffffff, // highest address in user space
|
||||
0x80000000, // lowest address in kernel space
|
||||
0x80000000, // .ktext base address
|
||||
0x80000180, // exception handler address
|
||||
0x90000000, // .kdata base address
|
||||
0xffff0000, // MMIO base address
|
||||
0xffffffff, // highest address in kernel (and memory)
|
||||
0x7fffffff, // data segment limit address
|
||||
0x0ffffffc, // text limit address
|
||||
0xfffeffff, // kernel data segment limit address
|
||||
0x8ffffffc, // kernel text limit address
|
||||
0x10040000, // stack limit address
|
||||
0xffffffff // memory map limit address
|
||||
};
|
||||
|
||||
// Compact allows 16 bit addressing, data segment starts at 0
|
||||
private static int[] dataBasedCompactConfigurationItemValues = {
|
||||
0x00003000, // .text Base Address
|
||||
0x00000000, // Data Segment base address
|
||||
0x00001000, // .extern Base Address
|
||||
0x00001800, // Global Pointer $gp)
|
||||
0x00000000, // .data base Address
|
||||
0x00002000, // heap base address
|
||||
0x00002ffc, // stack pointer $sp
|
||||
0x00002ffc, // stack base address
|
||||
0x00003fff, // highest address in user space
|
||||
0x00004000, // lowest address in kernel space
|
||||
0x00004000, // .ktext base address
|
||||
0x00004180, // exception handler address
|
||||
0x00005000, // .kdata base address
|
||||
0x00007f00, // MMIO base address
|
||||
0x00007fff, // highest address in kernel (and memory)
|
||||
0x00002fff, // data segment limit address
|
||||
0x00003ffc, // text limit address
|
||||
0x00007eff, // kernel data segment limit address
|
||||
0x00004ffc, // kernel text limit address
|
||||
0x00002000, // stack limit address
|
||||
0x00007fff // memory map limit address
|
||||
};
|
||||
|
||||
// Compact allows 16 bit addressing, text segment starts at 0
|
||||
private static int[] textBasedCompactConfigurationItemValues = {
|
||||
0x00000000, // .text Base Address
|
||||
0x00001000, // Data Segment base address
|
||||
0x00001000, // .extern Base Address
|
||||
0x00001800, // Global Pointer $gp)
|
||||
0x00002000, // .data base Address
|
||||
0x00003000, // heap base address
|
||||
0x00003ffc, // stack pointer $sp
|
||||
0x00003ffc, // stack base address
|
||||
0x00003fff, // highest address in user space
|
||||
0x00004000, // lowest address in kernel space
|
||||
0x00004000, // .ktext base address
|
||||
0x00004180, // exception handler address
|
||||
0x00005000, // .kdata base address
|
||||
0x00007f00, // MMIO base address
|
||||
0x00007fff, // highest address in kernel (and memory)
|
||||
0x00003fff, // data segment limit address
|
||||
0x00000ffc, // text limit address
|
||||
0x00007eff, // kernel data segment limit address
|
||||
0x00004ffc, // kernel text limit address
|
||||
0x00003000, // stack limit address
|
||||
0x00007fff // memory map limit address
|
||||
};
|
||||
|
||||
|
||||
|
||||
public MemoryConfigurations() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static void buildConfigurationCollection() {
|
||||
if (configurations == null) {
|
||||
configurations = new ArrayList();
|
||||
configurations.add(new MemoryConfiguration("Default", "Default", configurationItemNames, defaultConfigurationItemValues));
|
||||
configurations.add(new MemoryConfiguration("CompactDataAtZero", "Compact, Data at Address 0", configurationItemNames, dataBasedCompactConfigurationItemValues));
|
||||
configurations.add(new MemoryConfiguration("CompactTextAtZero", "Compact, Text at Address 0", configurationItemNames, textBasedCompactConfigurationItemValues));
|
||||
defaultConfiguration = (MemoryConfiguration) configurations.get(0);
|
||||
currentConfiguration = defaultConfiguration;
|
||||
// Get current config from settings
|
||||
//String currentConfigurationIdentifier = Globals.getSettings().getMemoryConfiguration();
|
||||
setCurrentConfiguration(getConfigurationByName(Globals.getSettings().getMemoryConfiguration()));
|
||||
// Iterator configurationsIterator = getConfigurationsIterator();
|
||||
// while (configurationsIterator.hasNext()) {
|
||||
// MemoryConfiguration config = (MemoryConfiguration)configurationsIterator.next();
|
||||
// if (currentConfigurationIdentifier.equals(config.getConfigurationIdentifier())) {
|
||||
// setCurrentConfiguration(config);
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
public static Iterator getConfigurationsIterator() {
|
||||
if (configurations == null) {
|
||||
buildConfigurationCollection();
|
||||
}
|
||||
return configurations.iterator();
|
||||
|
||||
}
|
||||
|
||||
public static MemoryConfiguration getConfigurationByName(String name) {
|
||||
Iterator configurationsIterator = getConfigurationsIterator();
|
||||
while (configurationsIterator.hasNext()) {
|
||||
MemoryConfiguration config = (MemoryConfiguration)configurationsIterator.next();
|
||||
if (name.equals(config.getConfigurationIdentifier())) {
|
||||
return config;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public static MemoryConfiguration getDefaultConfiguration() {
|
||||
if (defaultConfiguration == null) {
|
||||
buildConfigurationCollection();
|
||||
}
|
||||
return defaultConfiguration;
|
||||
}
|
||||
|
||||
public static MemoryConfiguration getCurrentConfiguration() {
|
||||
if (currentConfiguration == null) {
|
||||
buildConfigurationCollection();
|
||||
}
|
||||
return currentConfiguration;
|
||||
}
|
||||
|
||||
public static boolean setCurrentConfiguration(MemoryConfiguration config) {
|
||||
if (config == null)
|
||||
return false;
|
||||
if (config != currentConfiguration) {
|
||||
currentConfiguration = config;
|
||||
Globals.memory.clear();
|
||||
RegisterFile.getUserRegister("$gp").changeResetValue(config.getGlobalPointer());
|
||||
RegisterFile.getUserRegister("$sp").changeResetValue(config.getStackPointer());
|
||||
RegisterFile.getProgramCounterRegister().changeResetValue(config.getTextBaseAddress());
|
||||
RegisterFile.initializeProgramCounter(config.getTextBaseAddress());
|
||||
RegisterFile.resetRegisters();
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//// Use these to intialize Memory static variables at launch
|
||||
|
||||
public static int getDefaultTextBaseAddress() {
|
||||
return defaultConfigurationItemValues[0];
|
||||
}
|
||||
|
||||
public static int getDefaultDataSegmentBaseAddress() {
|
||||
return defaultConfigurationItemValues[1];
|
||||
}
|
||||
|
||||
public static int getDefaultExternBaseAddress() {
|
||||
return defaultConfigurationItemValues[2];
|
||||
}
|
||||
|
||||
public static int getDefaultGlobalPointer() {
|
||||
return defaultConfigurationItemValues[3];
|
||||
}
|
||||
|
||||
public static int getDefaultDataBaseAddress() {
|
||||
return defaultConfigurationItemValues[4];
|
||||
}
|
||||
|
||||
public static int getDefaultHeapBaseAddress() {
|
||||
return defaultConfigurationItemValues[5];
|
||||
}
|
||||
|
||||
public static int getDefaultStackPointer() {
|
||||
return defaultConfigurationItemValues[6];
|
||||
}
|
||||
|
||||
public static int getDefaultStackBaseAddress() {
|
||||
return defaultConfigurationItemValues[7];
|
||||
}
|
||||
|
||||
public static int getDefaultUserHighAddress() {
|
||||
return defaultConfigurationItemValues[8];
|
||||
}
|
||||
|
||||
public static int getDefaultKernelBaseAddress() {
|
||||
return defaultConfigurationItemValues[9];
|
||||
}
|
||||
|
||||
public static int getDefaultKernelTextBaseAddress() {
|
||||
return defaultConfigurationItemValues[10];
|
||||
}
|
||||
|
||||
public static int getDefaultExceptionHandlerAddress() {
|
||||
return defaultConfigurationItemValues[11];
|
||||
}
|
||||
|
||||
public static int getDefaultKernelDataBaseAddress() {
|
||||
return defaultConfigurationItemValues[12];
|
||||
}
|
||||
|
||||
public static int getDefaultMemoryMapBaseAddress() {
|
||||
return defaultConfigurationItemValues[13];
|
||||
}
|
||||
|
||||
public static int getDefaultKernelHighAddress () {
|
||||
return defaultConfigurationItemValues[14];
|
||||
}
|
||||
|
||||
public int getDefaultDataSegmentLimitAddress() {
|
||||
return defaultConfigurationItemValues[15];
|
||||
}
|
||||
|
||||
public int getDefaultTextLimitAddress() {
|
||||
return defaultConfigurationItemValues[16];
|
||||
}
|
||||
|
||||
public int getDefaultKernelDataSegmentLimitAddress() {
|
||||
return defaultConfigurationItemValues[17];
|
||||
}
|
||||
|
||||
public int getDefaultKernelTextLimitAddress() {
|
||||
return defaultConfigurationItemValues[18];
|
||||
}
|
||||
|
||||
public int getDefaultStackLimitAddress() {
|
||||
return defaultConfigurationItemValues[19];
|
||||
}
|
||||
|
||||
public int getMemoryMapLimitAddress() {
|
||||
return defaultConfigurationItemValues[20];
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,154 @@
|
||||
package mars.mips.hardware;
|
||||
import mars.*;
|
||||
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)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Abstraction to represent a register of a MIPS Assembler.
|
||||
* @author Jason Bumgarner, Jason Shrewsbury, Ben Sherman
|
||||
* @version June 2003
|
||||
**/
|
||||
|
||||
public class Register extends Observable {
|
||||
private String name;
|
||||
private int number, resetValue;
|
||||
// volatile should be enough to allow safe multi-threaded access
|
||||
// w/o the use of synchronized methods. getValue and setValue
|
||||
// are the only methods here used by the register collection
|
||||
// (RegisterFile, Coprocessor0, Coprocessor1) methods.
|
||||
private volatile int value;
|
||||
|
||||
/**
|
||||
* Creates a new register with specified name, number, and value.
|
||||
* @param n The name of the register.
|
||||
* @param num The number of the register.
|
||||
* @param val The inital (and reset) value of the register.
|
||||
*/
|
||||
|
||||
public Register(String n, int num, int val){
|
||||
name= n;
|
||||
number=num;
|
||||
value= val;
|
||||
resetValue = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the Register.
|
||||
* @return name The name of the Register.
|
||||
*/
|
||||
|
||||
public String getName(){
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the Register. Observers are notified
|
||||
* of the READ operation.
|
||||
* @return value The value of the Register.
|
||||
*/
|
||||
|
||||
public synchronized int getValue(){
|
||||
notifyAnyObservers(AccessNotice.READ);
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the value of the Register. Observers are not notified.
|
||||
* Added for release 3.8.
|
||||
* @return value The value of the Register.
|
||||
*/
|
||||
|
||||
public synchronized int getValueNoNotify(){
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the reset value of the Register.
|
||||
* @return The reset (initial) value of the Register.
|
||||
*/
|
||||
|
||||
public int getResetValue(){
|
||||
return resetValue;
|
||||
}
|
||||
/**
|
||||
* Returns the number of the Register.
|
||||
* @return number The number of the Register.
|
||||
*/
|
||||
|
||||
public int getNumber(){
|
||||
return number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the register to the val passed to it.
|
||||
* Observers are notified of the WRITE operation.
|
||||
* @param val Value to set the Register to.
|
||||
* @return previous value of register
|
||||
*/
|
||||
|
||||
public synchronized int setValue(int val){
|
||||
int old = value;
|
||||
value = val;
|
||||
notifyAnyObservers(AccessNotice.WRITE);
|
||||
return old;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the value of the register to the value it was constructed with.
|
||||
* Observers are not notified.
|
||||
*/
|
||||
|
||||
public synchronized void resetValue(){
|
||||
value = resetValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the register's reset value; the value to which it will be
|
||||
* set when <tt>resetValue()</tt> is called.
|
||||
*/
|
||||
|
||||
public synchronized void changeResetValue(int reset) {
|
||||
resetValue = reset;
|
||||
}
|
||||
|
||||
//
|
||||
// Method to notify any observers of register operation that has just occurred.
|
||||
//
|
||||
private void notifyAnyObservers(int type) {
|
||||
if (this.countObservers() > 0){// && Globals.program != null) && Globals.program.inSteppedExecution()) {
|
||||
this.setChanged();
|
||||
this.notifyObservers(new RegisterAccessNotice(type, this.name));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,59 @@
|
||||
package mars.mips.hardware;
|
||||
|
||||
/*
|
||||
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)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Object provided to Observers of runtime access to MIPS register.
|
||||
* Observer can get the access type (R/W) and register number.
|
||||
*
|
||||
* @author Pete Sanderson
|
||||
* @version July 2005
|
||||
*/
|
||||
|
||||
public class RegisterAccessNotice extends AccessNotice {
|
||||
private String registerName;
|
||||
|
||||
/** Constructor will be called only within this package, so assume
|
||||
* register number is in valid range.
|
||||
*/
|
||||
RegisterAccessNotice(int type, String registerName) {
|
||||
super(type);
|
||||
this.registerName = registerName;
|
||||
}
|
||||
/** Fetch the register number of register accessed. */
|
||||
public String getRegisterName() {
|
||||
return registerName;
|
||||
}
|
||||
/** String representation indicates access type and which register */
|
||||
public String toString() {
|
||||
return ((this.getAccessType()==AccessNotice.READ) ? "R " : "W ") +
|
||||
"Reg " + registerName;
|
||||
}
|
||||
|
||||
}
|
||||
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user