[O] Reformat code

This commit is contained in:
Hykilpikonna
2022-11-09 23:49:19 -05:00
parent 13c408bbdd
commit 64d4d49bdb
217 changed files with 53970 additions and 46112 deletions
+4 -2
View File
@@ -33,8 +33,10 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
* @version March 2006
**/
public class Mars {
public static void main(String[] args) {
public class Mars
{
public static void main(String[] args)
{
new mars.MarsLaunch(args);
}
}
+208 -160
View File
@@ -1,6 +1,7 @@
package mars;
import java.util.*;
import java.io.*;
package mars;
import java.io.File;
import java.util.ArrayList;
/*
Copyright (c) 2003-2012, Pete Sanderson and Kenneth Vollmar
@@ -28,171 +29,218 @@ 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).
*
* 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()) {
public class ErrorList
{
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 = ": ";
private final ArrayList messages;
private int errorCount;
private int warningCount;
/**
* 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."));
}
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()) {
}
messages.add(index, mess);
if (mess.isWarning())
{
warningCount++;
}
else {
}
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
}
}
/**
* 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
+286 -238
View File
@@ -1,8 +1,8 @@
package mars;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
import java.util.ArrayList;
package mars;
import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/*
Copyright (c) 2003-2012, Pete Sanderson and Kenneth Vollmar
@@ -33,253 +33,301 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
/**
* 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.
**/
public class ErrorMessage
{
/**
* 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;
private final boolean isWarning; // allow for warnings too (added Nov 2006)
private final String filename; // name of source file (added Oct 2006)
private final int line; // line in source code where error detected
private final int position; // position in source line where error detected
private final String message;
private final String macroExpansionHistory;
/**
* 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.
**/
@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) {
@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();
}
else
{
if (sourceMIPSprogram.getSourceLineList() == null)
{
this.filename = sourceMIPSprogram.getFilename();
this.line = line;
}
}
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) {
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 {
}
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()) {
this.macroExpansionHistory = "" + statement.getSourceLine();
}
}
// Added by Mohammad Sekavat Dec 2012
private static String getExpansionHistory(MIPSprogram sourceMIPSprogram)
{
if (sourceMIPSprogram == null || sourceMIPSprogram.getLocalMacroPool() == null)
{
return "";
}
return sourceMIPSprogram.getLocalMacroPool().getExpansionHistory();
}
private ArrayList<Integer> parseMacroHistory(String string)
{
Pattern pattern = Pattern.compile("<\\d+>");
Matcher matcher = pattern.matcher(string);
String verify = 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;
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();
}
}
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.
*/
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
*/
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)
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
}
return macroExpansionHistory + "->";
}
} // ErrorMessage
+137 -77
View File
@@ -46,114 +46,144 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
* @author Pete Sanderson
* @version August 2003
*/
public class Globals {
public class Globals
{
/**
* 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/";
/**
* The current MARS version number. Can't wait for "initialize()" call to get it.
*/
public static final String version = "4.5";
/**
* MARS copyright years
*/
public static final String copyrightYears = getCopyrightYears();
/**
* MARS copyright holders
*/
public static final String copyrightHolders = getCopyrightHolders();
/**
* 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;
/**
* String to GUI's RunI/O text area when echoing user input from pop-up dialog.
*/
public static String userInputAlert = "**** user input : ";
/**
* MARS exit code -- useful with SYSCALL 17 when running from command line (not GUI)
*/
public static int exitCode = 0;
public static boolean runSpeedPanelExists = false;
/**
* Object that contains various settings that can be accessed modified internally.
**/
static Settings settings;
/* The GUI being used (if any) with this simulator. */
static VenusUI gui = null;
// List these first because they are referenced by methods called at initialization.
private static final String configPropertiesFile = "Config";
/**
* 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();
/**
* 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();
private static final 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;
/**
* String to GUI's RunI/O text area when echoing user input from pop-up dialog.
*/
public static String userInputAlert = "**** user input : ";
/**
* MARS exit code -- useful with SYSCALL 17 when running from command line (not GUI)
*/
public static int exitCode = 0;
public static boolean runSpeedPanelExists = false;
/**
* Object that contains various settings that can be accessed modified internally.
**/
static Settings settings;
/* The GUI being used (if any) with this simulator. */
static VenusUI gui = null;
/* Flag that indicates whether or not instructionSet has been initialized. */
private static boolean initialized = false;
private static String getCopyrightYears() {
private static String getCopyrightYears()
{
return "2003-2014";
}
private static String getCopyrightHolders() {
private static String getCopyrightHolders()
{
return "Pete Sanderson and Kenneth Vollmar";
}
public static VenusUI getGui() {
public static VenusUI getGui()
{
return gui;
}
public static void setGui(VenusUI g) {
public static void setGui(VenusUI g)
{
gui = g;
}
public static Settings getSettings() {
public static Settings getSettings()
{
return settings;
}
@@ -161,8 +191,10 @@ public class Globals {
* Method called once upon system initialization to create the global data structures.
**/
public static void initialize(boolean gui) {
if (!initialized) {
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();
@@ -175,22 +207,26 @@ public class Globals {
}
// Read byte limit of Run I/O or MARS Messages text to buffer.
private static int getMessageLimit() {
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() {
private static int getErrorLimit()
{
return getIntegerProperty(configPropertiesFile, "ErrorLimit", 200);
}
// Read backstep limit (number of operations to buffer) from properties file.
private static int getBackstepLimit() {
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() {
public static String getAsciiNonPrint()
{
String anp = getPropertyEntry(configPropertiesFile, "AsciiNonPrint");
return (anp == null) ? "." : ((anp.equals("space")) ? " " : anp);
}
@@ -198,19 +234,31 @@ public class Globals {
// 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() {
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();
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++) {
for (int i = 0; i < lets.length; i++)
{
lets[i] = padding.substring(0, maxLength - lets[i].length()) + lets[i];
}
return lets;
@@ -218,12 +266,16 @@ public class Globals {
// 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) {
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 {
try
{
limit = Integer.parseInt(properties.getProperty(propertyName, Integer.toString(defaultValue)));
} catch (NumberFormatException nfe) {
}
catch (NumberFormatException nfe)
{
} // do nothing, I already have a default
return limit;
}
@@ -231,12 +283,15 @@ public class Globals {
// Read assembly language file extensions from properties file. Resulting
// string is tokenized into array list (assume StringTokenizer default delimiters).
private static ArrayList getFileExtensions() {
private static ArrayList getFileExtensions()
{
ArrayList extensionsList = new ArrayList();
String extensions = getPropertyEntry(configPropertiesFile, "Extensions");
if (extensions != null) {
if (extensions != null)
{
StringTokenizer st = new StringTokenizer(extensions);
while (st.hasMoreTokens()) {
while (st.hasMoreTokens())
{
extensionsList.add(st.nextToken());
}
}
@@ -244,20 +299,22 @@ public class Globals {
}
/**
* 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!
* 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.
* @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() {
public static ArrayList getExternalTools()
{
ArrayList toolsList = new ArrayList();
String delimiter = ";";
String tools = getPropertyEntry(configPropertiesFile, "ExternalTools");
if (tools != null) {
if (tools != null)
{
StringTokenizer st = new StringTokenizer(tools, delimiter);
while (st.hasMoreTokens()) {
while (st.hasMoreTokens())
{
toolsList.add(st.nextToken());
}
}
@@ -267,12 +324,13 @@ public class Globals {
/**
* 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
* @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) {
public static String getPropertyEntry(String propertiesFile, String propertyName)
{
return PropertiesFile.loadPropertiesFromFile(propertiesFile).getProperty(propertyName);
}
@@ -281,11 +339,13 @@ public class Globals {
*
* @return ArrayList of SyscallNumberOverride objects
*/
public ArrayList getSyscallOverrides() {
public ArrayList getSyscallOverrides()
{
ArrayList overrides = new ArrayList();
Properties properties = PropertiesFile.loadPropertiesFromFile(syscallPropertiesFile);
Enumeration keys = properties.keys();
while (keys.hasMoreElements()) {
while (keys.hasMoreElements())
{
String key = (String) keys.nextElement();
overrides.add(new SyscallNumberOverride(key, properties.getProperty(key)));
}
+433 -377
View File
@@ -1,14 +1,14 @@
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.*;
package mars;
import mars.assembler.*;
import mars.mips.hardware.RegisterFile;
import mars.simulator.BackStepper;
import mars.simulator.Simulator;
import javax.swing.*;
import java.io.BufferedReader;
import java.io.FileReader;
import java.util.ArrayList;
/*
Copyright (c) 2003-2006, Pete Sanderson and Kenneth Vollmar
@@ -39,384 +39,440 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* 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.
*
* 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) {
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;
}
/**
* 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;
}
/**
* 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
}
}
/**
* 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 {
}
}
/**
* 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();
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) {
}
catch (Exception e)
{
errors = new ErrorList();
errors.add(new ErrorMessage((MIPSprogram) null, 0, 0, e.toString()));
throw new ProcessingException(errors);
}
}
/**
* 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
}
/**
* 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);
}
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);
// 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);
}
}
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
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.
* @return ErrorList containing nothing or only warnings (otherwise would have thrown exception).
* @throws ProcessingException Will throw exception if errors occured while assembling.
**/
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.
* @return ErrorList containing nothing or only warnings (otherwise would have thrown exception).
* @throws ProcessingException Will throw exception if errors occured while assembling.
**/
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
File diff suppressed because it is too large Load Diff
+92 -80
View File
@@ -1,6 +1,7 @@
package mars;
import java.awt.*;
import javax.swing.*;
package mars;
import javax.swing.*;
import java.awt.*;
/*
Copyright (c) 2003-2010, Pete Sanderson and Kenneth Vollmar
@@ -31,88 +32,99 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* Produces MARS splash screen.<br>
* Adapted from http://www.java-tips.org/content/view/1267/2/<br>
* 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);
public class MarsSplashScreen extends JWindow
{
content.add(title,BorderLayout.NORTH);
content.add(copyrt1,BorderLayout.CENTER);
content.add(copyrt2,BorderLayout.SOUTH);
private final int duration;
// 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()
{
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();
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);
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);
}
}
}
{
g.drawImage(image, 0, 0, this.getWidth(), this.getHeight(), this);
}
}
}
}
+107 -98
View File
@@ -1,8 +1,10 @@
package mars;
import mars.util.*;
import mars.mips.hardware.*;
import mars.mips.instructions.Instruction;
import mars.simulator.*;
package mars;
import mars.mips.hardware.AddressErrorException;
import mars.mips.hardware.RegisterFile;
import mars.mips.instructions.Instruction;
import mars.simulator.Exceptions;
import mars.util.Binary;
/*
Copyright (c) 2003-2006, Pete Sanderson and Kenneth Vollmar
@@ -34,100 +36,107 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
/**
* 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;
}
}
public class ProcessingException extends Exception
{
private final 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.
* <p>
* 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;
}
}
+306 -184
View File
@@ -1,11 +1,17 @@
package mars;
import mars.assembler.*;
import mars.mips.instructions.*;
import mars.mips.hardware.*;
import mars.util.*;
import mars.assembler.SymbolTable;
import mars.assembler.Token;
import mars.assembler.TokenList;
import mars.assembler.TokenTypes;
import mars.mips.hardware.Coprocessor1;
import mars.mips.hardware.RegisterFile;
import mars.mips.instructions.BasicInstruction;
import mars.mips.instructions.BasicInstructionFormat;
import mars.mips.instructions.Instruction;
import mars.util.Binary;
import java.util.*;
import java.util.ArrayList;
/*
Copyright (c) 2003-2013, Pete Sanderson and Kenneth Vollmar
@@ -36,44 +42,58 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* 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.
* 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;
public class ProgramStatement
{
private static final String invalidOperator = "<INVALID>";
private final MIPSprogram sourceMIPSprogram;
private String source, basicAssemblyStatement, machineStatement;
private final TokenList originalTokenList;
private final TokenList strippedTokenList;
private final BasicStatementList basicStatementList;
private final int[] operands;
private int numOperands;
private final Instruction instruction;
private final int textAddress;
private int sourceLine;
private int binaryStatement;
private final boolean altered;
//////////////////////////////////////////////////////////////////////////////////
/**
* Constructor for ProgramStatement when there are links back to all source and token
* information. These can be used by a debugger later on.
* 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 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.
* @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) {
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;
@@ -94,17 +114,16 @@ public class ProgramStatement {
//////////////////////////////////////////////////////////////////////////////////
/**
* 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.
* 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.
* @param textAddress The Text Segment address in memory where the binary machine code for this statement is
* stored.
**/
public ProgramStatement(int binaryStatement, int textAddress) {
public ProgramStatement(int binaryStatement, int textAddress)
{
this.sourceMIPSprogram = null;
this.binaryStatement = binaryStatement;
this.textAddress = textAddress;
@@ -112,12 +131,15 @@ public class ProgramStatement {
this.source = "";
this.machineStatement = this.basicAssemblyStatement = null;
BasicInstruction instr = Globals.instructionSet.findByBinaryCode(binaryStatement);
if (instr == null) {
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 {
? (Instruction) Globals.instructionSet.matchOperator("nop").get(0) : null;
}
else
{
this.operands = new int[4];
this.numOperands = 0;
this.instruction = instr;
@@ -126,16 +148,21 @@ public class ProgramStatement {
String fmt = instr.getOperationMask();
BasicInstructionFormat instrFormat = instr.getInstructionFormat();
int numOps = 0;
for (int i = 0; i < opandCodes.length(); i++) {
for (int i = 0; i < opandCodes.length(); i++)
{
int code = opandCodes.charAt(i);
int j = fmt.indexOf(code);
if (j >= 0) {
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) {
if (instrFormat.equals(BasicInstructionFormat.I_BRANCH_FORMAT) && numOps == 2)
{
opand = opand << 16 >> 16;
} else if (instrFormat.equals(BasicInstructionFormat.J_FORMAT) && numOps == 0) {
}
else if (instrFormat.equals(BasicInstructionFormat.J_FORMAT) && numOps == 0)
{
opand |= (textAddress >> 2) & 0x3C000000;
}
this.operands[numOps] = opand;
@@ -152,63 +179,76 @@ public class ProgramStatement {
/////////////////////////////////////////////////////////////////////////////
/**
* 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).
* 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) {
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++) {
for (int i = 1; i < strippedTokenList.size(); i++)
{
token = strippedTokenList.get(i);
tokenType = token.getType();
tokenValue = token.getValue();
if (tokenType == TokenTypes.REGISTER_NUMBER) {
if (tokenType == TokenTypes.REGISTER_NUMBER)
{
basicStatementElement = tokenValue;
basic += basicStatementElement;
basicStatementList.addString(basicStatementElement);
try {
try
{
registerNumber = RegisterFile.getUserRegister(tokenValue).getNumber();
} catch (Exception e) {
}
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) {
}
else if (tokenType == TokenTypes.REGISTER_NAME)
{
registerNumber = RegisterFile.getNumber(tokenValue);
basicStatementElement = "$" + registerNumber;
basic += basicStatementElement;
basicStatementList.addString(basicStatementElement);
if (registerNumber < 0) {
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) {
}
else if (tokenType == TokenTypes.FP_REGISTER_NAME)
{
registerNumber = Coprocessor1.getRegisterNumber(tokenValue);
basicStatementElement = "$f" + registerNumber;
basic += basicStatementElement;
basicStatementList.addString(basicStatementElement);
if (registerNumber < 0) {
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) {
}
else if (tokenType == TokenTypes.IDENTIFIER)
{
int address = this.sourceMIPSprogram.getLocalSymbolTable().getAddressLocalOrGlobal(tokenValue);
if (address == SymbolTable.NOT_FOUND) { // symbol used without being defined
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;
}
@@ -231,9 +271,11 @@ public class ProgramStatement {
// This mod must be made in conjunction with InstructionSet.java's processBranch()
// method. There are some comments there as well.
if (instruction instanceof BasicInstruction) {
if (instruction instanceof BasicInstruction)
{
BasicInstructionFormat format = ((BasicInstruction) instruction).getInstructionFormat();
if (format == BasicInstructionFormat.I_BRANCH_FORMAT) {
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;
@@ -241,13 +283,18 @@ public class ProgramStatement {
}
//////////////////////////////////////////////////////////////////////
basic += address;
if (absoluteAddress) { // record as address if absolute, value if relative
if (absoluteAddress)
{ // record as address if absolute, value if relative
basicStatementList.addAddress(address);
} else {
}
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) {
}
else if (tokenType == TokenTypes.INTEGER_5 || tokenType == TokenTypes.INTEGER_16 || tokenType == TokenTypes.INTEGER_16U || tokenType == TokenTypes.INTEGER_32)
{
int tempNumeric = Binary.stringToInt(tokenValue);
@@ -296,16 +343,20 @@ public class ProgramStatement {
basicStatementList.addValue(tempNumeric);
this.operands[this.numOperands++] = tempNumeric;
///// End modification 1/7/05 KENV ///////////////////////////////////////////
} else {
}
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)) {
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) {
if (tokenType != TokenTypes.LEFT_PAREN && tokenType != TokenTypes.RIGHT_PAREN && nextTokenType != TokenTypes.LEFT_PAREN && nextTokenType != TokenTypes.RIGHT_PAREN)
{
basicStatementElement = ",";
basic += basicStatementElement;
basicStatementList.addString(basicStatementElement);
@@ -319,27 +370,32 @@ public class ProgramStatement {
/////////////////////////////////////////////////////////////////////////////
/**
* Given the current statement in Basic Assembly format (see above), build the
* 32-bit binary machine code statement.
* 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) {
public void buildMachineStatementFromBasicStatement(ErrorList errors)
{
try {
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) {
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)) {
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"));
@@ -348,17 +404,23 @@ public class ProgramStatement {
// 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++) {
}
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
}
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(
@@ -370,81 +432,45 @@ public class ProgramStatement {
* @return A String representing the ProgramStatement.
**/
public String toString() {
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) {
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 {
}
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) {
if (operands != null)
{
for (int i = 0; i < this.numOperands; i++)
// result += operands[i] + " ";
// result += operands[i] + " ";
{
result += Integer.toString(operands[i], 16) + " ";
}
}
if (this.machineStatement != null) {
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() {
public MIPSprogram getSourceMIPSprogram()
{
return sourceMIPSprogram;
}
@@ -453,51 +479,75 @@ public class ProgramStatement {
*
* @return The file name.
**/
public String getSourceFile() {
public String getSourceFile()
{
return (sourceMIPSprogram == null) ? "" : sourceMIPSprogram.getFilename();
}
/**
* Produces MIPS source statement.
*
* @return The MIPS source statement.
**/
public String getSource() {
public String getSource()
{
return source;
}
/**
* 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 line number of MIPS source statement.
*
* @return The MIPS source statement line number.
**/
public int getSourceLine() {
public int getSourceLine()
{
return sourceLine;
}
/**
* Produces Basic Assembly statement for this MIPS source statement.
* All numeric values are in decimal.
* Produces Basic Assembly statement for this MIPS source statement. All numeric values are in decimal.
*
* @return The Basic Assembly statement.
**/
public String getBasicAssemblyStatement() {
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.
* 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;
}
/**
* 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() {
public String getPrintableBasicAssemblyStatement()
{
return basicStatementList.toString();
}
@@ -507,35 +557,62 @@ public class ProgramStatement {
* @return The String version of 32-bit binary machine code.
**/
public String getMachineStatement() {
public String getMachineStatement()
{
return machineStatement;
}
/**
* 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;
}
/**
* Produces 32-bit binary machine statement as int.
*
* @return The int version of 32-bit binary machine code.
**/
public int getBinaryStatement() {
public int getBinaryStatement()
{
return binaryStatement;
}
/**
* 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;
}
/**
* Produces token list generated from original source statement.
*
* @return The TokenList of Token objects generated from original source.
**/
public TokenList getOriginalTokenList() {
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.
* @return The TokenList of Token objects generated by stripping original list of all except operator and operand
* tokens.
**/
public TokenList getStrippedTokenList() {
public TokenList getStrippedTokenList()
{
return strippedTokenList;
}
@@ -544,7 +621,8 @@ public class ProgramStatement {
*
* @return The Instruction that matches the operator used in this statement.
**/
public Instruction getInstruction() {
public Instruction getInstruction()
{
return instruction;
}
@@ -553,7 +631,8 @@ public class ProgramStatement {
*
* @return address in Text Segment of this binary machine statement.
**/
public int getAddress() {
public int getAddress()
{
return textAddress;
}
@@ -562,7 +641,8 @@ public class ProgramStatement {
*
* @return int array of operand values (if any) required by this statement's operator.
**/
public int[] getOperands() {
public int[] getOperands()
{
return operands;
}
@@ -572,10 +652,14 @@ public class ProgramStatement {
* @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) {
public int getOperand(int i)
{
if (i >= 0 && i < this.numOperands)
{
return operands[i];
} else {
}
else
{
return -1;
}
}
@@ -584,18 +668,22 @@ public class ProgramStatement {
//////////////////////////////////////////////////////////////////////////////
// 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) {
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
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);
if (endPos < this.machineStatement.length() - 1)
{
state = state + this.machineStatement.substring(endPos + 1);
}
this.machineStatement = state;
return;
} // insertBinaryCode()
@@ -606,47 +694,66 @@ public class ProgramStatement {
* 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) {
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) {
if (instr == null)
{
statementList.addString(invalidOperator);
return statementList;
} else {
}
else
{
statementList.addString(instr.getName() + " ");
}
for (int i = 0; i < numOperands; i++) {
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()) {
if (tokenListCounter > 1 && tokenListCounter < instr.getTokenList().size())
{
TokenTypes thisTokenType = instr.getTokenList().get(tokenListCounter).getType();
if (thisTokenType != TokenTypes.LEFT_PAREN && thisTokenType != TokenTypes.RIGHT_PAREN) {
if (thisTokenType != TokenTypes.LEFT_PAREN && thisTokenType != TokenTypes.RIGHT_PAREN)
{
statementList.addString(",");
}
}
boolean notOperand = true;
while (notOperand && tokenListCounter < instr.getTokenList().size()) {
while (notOperand && tokenListCounter < instr.getTokenList().size())
{
TokenTypes tokenType = instr.getTokenList().get(tokenListCounter).getType();
if (tokenType.equals(TokenTypes.LEFT_PAREN)) {
if (tokenType.equals(TokenTypes.LEFT_PAREN))
{
statementList.addString("(");
} else if (tokenType.equals(TokenTypes.RIGHT_PAREN)) {
}
else if (tokenType.equals(TokenTypes.RIGHT_PAREN))
{
statementList.addString(")");
} else if (tokenType.toString().contains("REGISTER")) {
}
else if (tokenType.toString().contains("REGISTER"))
{
String marker = (tokenType.toString().contains("FP_REGISTER")) ? "$f" : "$";
statementList.addString(marker + operands[i]);
notOperand = false;
} else {
}
else
{
statementList.addValue(operands[i]);
notOperand = false;
}
tokenListCounter++;
}
}
while (tokenListCounter < instr.getTokenList().size()) {
while (tokenListCounter < instr.getTokenList().size())
{
TokenTypes tokenType = instr.getTokenList().get(tokenListCounter).getType();
if (tokenType.equals(TokenTypes.LEFT_PAREN)) {
if (tokenType.equals(TokenTypes.LEFT_PAREN))
{
statementList.addString("(");
} else if (tokenType.equals(TokenTypes.RIGHT_PAREN)) {
}
else if (tokenType.equals(TokenTypes.RIGHT_PAREN))
{
statementList.addString(")");
}
tokenListCounter++;
@@ -670,34 +777,42 @@ public class ProgramStatement {
//
// DPS 29-July-2010
private class BasicStatementList {
private class BasicStatementList
{
private ArrayList list;
private final ArrayList list;
BasicStatementList() {
BasicStatementList()
{
list = new ArrayList();
}
void addString(String string) {
void addString(String string)
{
list.add(new ListElement(0, string, 0));
}
void addAddress(int address) {
void addAddress(int address)
{
list.add(new ListElement(1, null, address));
}
void addValue(int value) {
void addValue(int value)
{
list.add(new ListElement(2, null, value));
}
public String toString() {
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++) {
for (int i = 0; i < list.size(); i++)
{
ListElement e = (ListElement) list.get(i);
switch (e.type) {
switch (e.type)
{
case 0:
result.append(e.sValue);
break;
@@ -705,9 +820,12 @@ public class ProgramStatement {
result.append(mars.venus.NumberDisplayBaseChooser.formatNumber(e.iValue, addressBase));
break;
case 2:
if (valueBase == mars.venus.NumberDisplayBaseChooser.HEXADECIMAL) {
if (valueBase == mars.venus.NumberDisplayBaseChooser.HEXADECIMAL)
{
result.append(mars.util.Binary.intToHexString(e.iValue)); // 13-July-2011, was: intToHalfHexString()
} else {
}
else
{
result.append(mars.venus.NumberDisplayBaseChooser.formatNumber(e.iValue, valueBase));
}
default:
@@ -717,12 +835,16 @@ public class ProgramStatement {
return result.toString();
}
private class ListElement {
private class ListElement
{
int type;
String sValue;
int iValue;
ListElement(int type, String sValue, int iValue) {
ListElement(int type, String sValue, int iValue)
{
this.type = type;
this.sValue = sValue;
this.iValue = iValue;
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+126 -93
View File
@@ -31,101 +31,134 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
/**
* 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;
}
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 return direct == Directives.BYTE && (value < MIN_BYTE_VALUE || value > MAX_BYTE_VALUE);
}
/**
* 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)
{
return direct == Directives.FLOAT && (value < LOW_FLOAT_VALUE || value > MAX_FLOAT_VALUE);
}
}
+183 -152
View File
@@ -1,6 +1,6 @@
package mars.assembler;
package mars.assembler;
import java.util.ArrayList;
import java.util.ArrayList;
/*
Copyright (c) 2003-2012, Pete Sanderson and Kenneth Vollmar
@@ -31,160 +31,191 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* 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.
*
* 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++) {
public final class Directives
{
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 static final ArrayList directiveList = new ArrayList();
private final String descriptor;
private final 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;
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 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;
}
}
}
return matches;
}
/**
* 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;
}
/**
* 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;
}
}
+234 -200
View File
@@ -1,15 +1,14 @@
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;
import mars.mips.hardware.RegisterFile;
import java.util.ArrayList;
import java.util.Collections;
/*
Copyright (c) 2013-2014.
@@ -38,217 +37,252 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
/**
* 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;
public class Macro
{
private String name;
/**
* 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;
private MIPSprogram program;
public Macro() {
name = "";
program = null;
fromLine = toLine = 0;
origFromLine = origToLine = 0;
args = new ArrayList<String>();
labels = new ArrayList<String>();
}
private final ArrayList<String> labels;
public String getName() {
return name;
}
/**
* 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;
public void setName(String name) {
this.name = name;
}
private int origFromLine, origToLine;
public MIPSprogram getProgram() {
return program;
}
/**
* arguments like <code>%arg</code> will be substituted by macro expansion
*/
private ArrayList<String> args;
public void setProgram(MIPSprogram program) {
this.program = program;
}
public Macro()
{
name = "";
program = null;
fromLine = toLine = 0;
origFromLine = origToLine = 0;
args = new ArrayList<String>();
labels = new ArrayList<String>();
}
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;
}
/**
* 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;
}
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;
}
}
return tokenValue.length() > 1 && tokenValue.charAt(0) == '%';
}
public String getName()
{
return name;
}
/**
* 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);
}
public void setName(String name)
{
this.name = name;
}
/**
* 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 MIPSprogram getProgram()
{
return program;
}
public void addLabel(String value) {
labels.add(value);
}
public void setProgram(MIPSprogram program)
{
this.program = program;
}
/**
* Operations to be done on this macro before it is committed in macro pool.
*/
public void readyForCommit() {
Collections.sort(labels);
}
public int getFromLine()
{
return fromLine;
}
public void setFromLine(int fromLine)
{
this.fromLine = fromLine;
}
public int getOriginalFromLine()
{
return this.origFromLine;
}
public void setOriginalFromLine(int origFromLine)
{
this.origFromLine = origFromLine;
}
public int getToLine()
{
return toLine;
}
public void setToLine(int toLine)
{
this.toLine = toLine;
}
public int getOriginalToLine()
{
return this.origToLine;
}
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());
}
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);
}
}
+186 -167
View File
@@ -1,10 +1,8 @@
package mars.assembler;
package mars.assembler;
import java.util.ArrayList;
import java.util.Stack;
import mars.MIPSprogram;
import mars.ErrorList;
import mars.MIPSprogram;
import java.util.ArrayList;
/*
Copyright (c) 2013.
@@ -30,173 +28,194 @@ 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
* 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.
*
* {@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)
public class MacroPool
{
private final MIPSprogram program;
/**
* List of macros defined by now
*/
private final ArrayList<Macro> macroList;
/**
* @see #BeginMacro(String, int)
*/
private Macro current;
private final ArrayList<Integer> callStack;
private final 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) {
}
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)
&& 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;
}
}
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;
}
}
}
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;
}
}
+174 -138
View File
@@ -1,8 +1,12 @@
package mars.assembler;
import mars.*;
import mars.util.Binary;
import mars.mips.instructions.*;
import java.util.*;
package mars.assembler;
import mars.ErrorList;
import mars.ErrorMessage;
import mars.Globals;
import mars.mips.instructions.Instruction;
import mars.util.Binary;
import java.util.ArrayList;
/*
Copyright (c) 2003-2008, Pete Sanderson and Kenneth Vollmar
@@ -34,127 +38,157 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
/**
* Provides utility method related to MIPS operand formats.
*
* @author Pete Sanderson
*
* @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))
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 operandTypeCheck(candidateList, inst, errors);
}
/*
* 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)
}
if (instrMatches.size() == 1)
{
return (Instruction) instrMatches.get(0);
for (int i=0; i<instrMatches.size(); i++) {
}
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) {
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();
}
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();
}
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++) {
}
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;
// 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;
}
// 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.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;
(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) ||
@@ -162,37 +196,39 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
(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;
(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;
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()+" ");
}
/******** 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;
}
}
*/
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));
}
}
+80 -62
View File
@@ -1,6 +1,6 @@
package mars.assembler;
import mars.*;
import java.util.*;
package mars.assembler;
import mars.MIPSprogram;
/*
Copyright (c) 2003-2013, Pete Sanderson and Kenneth Vollmar
@@ -29,63 +29,81 @@ 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)
/**
* 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 final String source;
private String filename;
private final MIPSprogram mipsProgram;
private final 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;
}
}
}
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;
}
}
+78 -64
View File
@@ -27,68 +27,82 @@ 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.
/**
* Represents a MIPS program identifier to be stored in the symbol table.
*
* @author Jason Bumgarner, Jason Shrewsbury
* @version June 2003
**/
public class Symbol
{
public static final boolean TEXT_SYMBOL = false;
public static final boolean DATA_SYMBOL = true;
private final String name;
private int address;
private final boolean data; // boolean true if data symbol false if text symbol.
/**
* 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;
}
}
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;
}
/**
* Sets (replaces) the address of the the Symbol.
*
* @param newAddress The revised address of the Symbol.
**/
public void setAddress(int newAddress)
{
this.address = newAddress;
}
/**
* 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;
}
}
+273 -223
View File
@@ -1,6 +1,10 @@
package mars.assembler;
import mars.*;
import java.util.*;
package mars.assembler;
import mars.ErrorList;
import mars.ErrorMessage;
import mars.Globals;
import java.util.ArrayList;
/*
Copyright (c) 2003-2006, Pete Sanderson and Kenneth Vollmar
@@ -30,233 +34,279 @@ 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
**/
/**
* 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);
public class SymbolTable
{
// 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;
private static final String startLabel = "main";
private final String filename;
private ArrayList table;
/**
* 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();
}
/**
* 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;
}
/**
* 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;
if (Globals.debug)
{
System.out.println("The symbol " + label + " with address " + address + " has been added to the " + this.filename + " symbol table.");
}
}
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();
}
}
/**
* 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 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);
}
}
/**
* 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 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;
}
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);
}
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 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++){
}
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) {
}
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;
}
}
}
}
}
+157 -140
View File
@@ -1,5 +1,6 @@
package mars.assembler;
import mars.*;
package mars.assembler;
import mars.MIPSprogram;
/*
Copyright (c) 2003-2008, Pete Sanderson and Kenneth Vollmar
@@ -30,147 +31,163 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* 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.
*
* 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;
}
public class Token
{
/**
* 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;
}
}
private TokenTypes type;
private final String value;
private final MIPSprogram sourceMIPSprogram;
private final int sourceLine;
private final int 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;
}
}
+133 -117
View File
@@ -1,4 +1,5 @@
package mars.assembler;
import java.util.ArrayList;
/*
@@ -30,151 +31,166 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* Represents the list of tokens in a single line of MIPS code. It uses, but is not
* a subclass of, ArrayList.
*
* @author Pete Sanderson
* 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
public class TokenList implements Cloneable
{
/**
* Constructor for objects of class TokenList
*/
public TokenList() {
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;
}
processedLine = ""; // DPS 03-Jan-2013
}
/**
* 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) {
/**
* 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;
}
/**
* 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;
}
/**
* 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);
/**
* 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() {
/**
* 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) {
/**
* 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) {
/**
* 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() {
/**
* 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 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;
}
/**
* 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).
*/
/**
* 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 {
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) {
}
catch (CloneNotSupportedException e)
{
return null;
}
}
+300 -243
View File
@@ -1,7 +1,10 @@
package mars.assembler;
import mars.*;
import mars.util.*;
import mars.mips.hardware.*;
package mars.assembler;
import mars.Globals;
import mars.mips.hardware.Coprocessor1;
import mars.mips.hardware.Register;
import mars.mips.hardware.RegisterFile;
import mars.util.Binary;
/*
Copyright (c) 2003-2008, Pete Sanderson and Kenneth Vollmar
@@ -30,264 +33,318 @@ 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.
*
* 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;
}
}
public final class TokenTypes
{
// 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;
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 final String descriptor;
private TokenTypes()
{
// private ctor assures no objects can be created other than those above.
descriptor = "generic";
}
private TokenTypes(String name)
{
descriptor = name;
}
/**
* 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.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 {
}
// 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)
/***************************************************************************
* 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)
{
// NO ACTION -- exception suppressed
return TokenTypes.INTEGER_5;
}
// 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 {
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)
{
}
catch (NumberFormatException e)
{
// NO ACTION -- exception suppressed
}
// See if it is an instruction operator
if (Globals.instructionSet.matchOperator(value) != null)
}
// 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) {
}
// 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) == '"')
}
// 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))
}
// 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;
}
}
// Matches no MIPS language token.
return TokenTypes.ERROR;
}
/**
*
* 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;
/**
* 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;
}
}
}
return result;
}
/**
* Produces String equivalent of this token type, which is its name.
*
* @return String containing descriptive name for token type.
**/
public String toString()
{
return descriptor;
}
}
File diff suppressed because it is too large Load Diff
@@ -29,20 +29,19 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* 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.
*
* 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();
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,
*/
void translate();
}
@@ -1,7 +1,9 @@
package mars.mips.dump;
package mars.mips.dump;
import mars.mips.hardware.*;
import java.io.*;
import mars.mips.hardware.AddressErrorException;
import java.io.File;
import java.io.IOException;
/*
Copyright (c) 2003-2008, Pete Sanderson and Kenneth Vollmar
@@ -31,88 +33,99 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* Abstract class for memory dump file formats. Provides constructors and
* defaults for everything except the dumpMemoryRange method itself.
*
* @author Pete Sanderson
* 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;
}
public abstract class AbstractDumpFormat implements DumpFormat
{
private final String name;
private final String commandDescriptor;
private final String description;
private final String 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;
}
@@ -1,9 +1,14 @@
package mars.mips.dump;
package mars.mips.dump;
import mars.util.Binary;
import mars.Globals;
import mars.mips.hardware.*;
import java.io.*;
import mars.Globals;
import mars.mips.hardware.AddressErrorException;
import mars.mips.hardware.Memory;
import mars.util.Binary;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
/*
Copyright (c) 2003-2011, Pete Sanderson and Kenneth Vollmar
@@ -33,60 +38,63 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* 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
* 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()));
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();
}
}
}
}
finally
{
out.close();
}
}
}
@@ -1,8 +1,13 @@
package mars.mips.dump;
package mars.mips.dump;
import mars.Globals;
import mars.mips.hardware.*;
import java.io.*;
import mars.Globals;
import mars.mips.hardware.AddressErrorException;
import mars.mips.hardware.Memory;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
/*
Copyright (c) 2003-2008, Pete Sanderson and Kenneth Vollmar
@@ -32,53 +37,61 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* 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
* 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);
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();
}
}
}
}
finally
{
out.close();
}
}
}
@@ -1,8 +1,13 @@
package mars.mips.dump;
package mars.mips.dump;
import mars.Globals;
import mars.mips.hardware.*;
import java.io.*;
import mars.Globals;
import mars.mips.hardware.AddressErrorException;
import mars.mips.hardware.Memory;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
/*
Copyright (c) 2003-2008, Pete Sanderson and Kenneth Vollmar
@@ -32,57 +37,64 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* 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
* 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);
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();
}
}
}
}
finally
{
out.close();
}
}
}
+54 -57
View File
@@ -1,7 +1,9 @@
package mars.mips.dump;
package mars.mips.dump;
import mars.mips.hardware.*;
import java.io.*;
import mars.mips.hardware.AddressErrorException;
import java.io.File;
import java.io.IOException;
/*
Copyright (c) 2003-2008, Pete Sanderson and Kenneth Vollmar
@@ -31,62 +33,57 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* 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
* 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();
public interface DumpFormat
{
/**
* 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;
}
/**
* Get the file extension associated with this format.
*
* @return String containing file extension -- without the leading "." -- or null if there is no standard extension.
*/
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.
*/
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.
*/
String getCommandDescriptor();
/**
* Descriptive name for the format.
*
* @return Format name.
*/
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.
*/
void dumpMemoryRange(File file, int firstAddress, int lastAddress)
throws AddressErrorException, IOException;
}
@@ -1,8 +1,9 @@
package mars.mips.dump;
import mars.*;
import mars.util.*;
import java.util.*;
import java.lang.reflect.*;
package mars.mips.dump;
import mars.util.FilenameFinder;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
/*
Copyright (c) 2003-2008, Pete Sanderson and Kenneth Vollmar
@@ -32,66 +33,78 @@ 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".
/****************************************************************************/
/* 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;
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;
}
/**
* 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 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) {
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);
}
// 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;
}
}
}
return formatList;
}
}
@@ -1,8 +1,13 @@
package mars.mips.dump;
package mars.mips.dump;
import mars.Globals;
import mars.mips.hardware.*;
import java.io.*;
import mars.Globals;
import mars.mips.hardware.AddressErrorException;
import mars.mips.hardware.Memory;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
/*
Copyright (c) 2003-2008, Pete Sanderson and Kenneth Vollmar
@@ -32,57 +37,64 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* 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
* 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);
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();
}
}
}
}
finally
{
out.close();
}
}
}
@@ -1,74 +1,91 @@
package mars.mips.dump;
package mars.mips.dump;
import mars.Globals;
import mars.mips.hardware.*;
import java.io.*;
import mars.Globals;
import mars.mips.hardware.AddressErrorException;
import mars.mips.hardware.Memory;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
/**
* 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();
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();
}
}
}
+35 -34
View File
@@ -1,8 +1,9 @@
package mars.mips.dump;
package mars.mips.dump;
import mars.Globals;
import mars.mips.hardware.*;
import java.io.*;
import mars.mips.hardware.AddressErrorException;
import java.io.File;
import java.io.IOException;
/*
Copyright (c) 2003-2008, Pete Sanderson and Kenneth Vollmar
@@ -32,40 +33,40 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* The Memory Initialization File (.mif) VHDL-supported file format
* This is documented for the Altera platform at
* 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
*
* @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 {
}
}
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
{
}
}
@@ -1,10 +1,15 @@
package mars.mips.dump;
package mars.mips.dump;
import mars.Globals;
import mars.ProgramStatement;
import mars.util.Binary;
import mars.mips.hardware.*;
import java.io.*;
import mars.Globals;
import mars.ProgramStatement;
import mars.mips.hardware.AddressErrorException;
import mars.mips.hardware.Memory;
import mars.util.Binary;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
/*
Copyright (c) 2003-2008, Pete Sanderson and Kenneth Vollmar
@@ -34,117 +39,129 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* 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.
* <p>
* In either case, addresses and values are displayed in decimal or hexadecimal representation according to the
* corresponding settings.
*
* 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
* @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)) {
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);
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();
}
}
}
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() == "") ? "" : Integer.valueOf(ps.getSourceLine()).toString()) + " ").substring(0, 5);
string += ps.getSource();
}
catch (AddressErrorException aee)
{
}
out.println(string);
}
}
finally
{
out.close();
}
}
}
@@ -29,61 +29,78 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* 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
* 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;
}
public abstract class AccessNotice
{
/** Indicates the purpose of access was to read. */
public static final int READ = 0;
/** 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");
}
}
/** Indicates the purpose of access was to write. */
public static final int WRITE = 1;
private final int accessType;
private final 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");
}
}
@@ -1,5 +1,6 @@
package mars.mips.hardware;
import mars.util.*;
import mars.util.Binary;
/*
Copyright (c) 2003-2006, Pete Sanderson and Kenneth Vollmar
@@ -30,44 +31,49 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* 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
* 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
public class AddressErrorException extends Exception
{
private final int address;
private final 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;
}
/**
* Constructor for the AddressErrorException class
*
* @param addr The erroneous memory address.
**/
/**
* 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;
}
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;
}
}
+217 -175
View File
@@ -1,6 +1,8 @@
package mars.mips.hardware;
import mars.Globals;
import java.util.*;
package mars.mips.hardware;
import mars.Globals;
import java.util.Observer;
/*
Copyright (c) 2003-2009, Pete Sanderson and Kenneth Vollmar
@@ -31,185 +33,225 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* Represents Coprocessor 0. We will use only its interrupt/exception registers.
* @author Pete Sanderson
* @version August 2005
**/
* 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),
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 final 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++){
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;
}
System.out.println("Value: " + registers[i].getValue());
System.out.println();
}
}
/**
* 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;
}
/**
* 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
**/
/**
* 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;
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 -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 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 null;
}
/**
* Method to reinitialize the values of the registers.
**/
public static void resetRegisters(){
for(int i=0; i< registers.length; i++){
}
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);
}
}
}
}
}
/**
* 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);
}
}
}
File diff suppressed because it is too large Load Diff
@@ -1,5 +1,6 @@
package mars.mips.hardware;
import mars.*;
import mars.ErrorList;
/*
Copyright (c) 2003-2006, Pete Sanderson and Kenneth Vollmar
@@ -30,22 +31,21 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* Represents attempt to access double precision register using an odd
* (e.g. $f1, $f23) register name.
*
* 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;
public class InvalidRegisterAccessException extends Exception
{
private ErrorList errs;
/**
* Constructor for IllegalRegisterException.
*
**/
public InvalidRegisterAccessException() {
}
/**
* Constructor for IllegalRegisterException.
**/
public InvalidRegisterAccessException()
{
}
}
}
File diff suppressed because it is too large Load Diff
@@ -29,51 +29,65 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* 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
* 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;
}
}
public class MemoryAccessNotice extends AccessNotice
{
private final int address;
private final int length;
private final 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;
}
}
@@ -1,4 +1,4 @@
package mars.mips.hardware;
package mars.mips.hardware;
/*
Copyright (c) 2003-2009, Pete Sanderson and Kenneth Vollmar
@@ -29,129 +29,158 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* 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
* 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];
}
}
public class MemoryConfiguration
{
// Identifier is used for saving setting; name is used for display
private final String configurationIdentifier;
private final String configurationName;
private final String[] configurationItemNames;
private final 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];
}
}
@@ -1,6 +1,9 @@
package mars.mips.hardware;
import mars.Globals;
import java.util.*;
package mars.mips.hardware;
import mars.Globals;
import java.util.ArrayList;
import java.util.Iterator;
/*
Copyright (c) 2003-2009, Pete Sanderson and Kenneth Vollmar
@@ -31,191 +34,208 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* 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
* 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) {
public class MemoryConfigurations
{
// 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"
};
private static ArrayList configurations = null;
private static MemoryConfiguration defaultConfiguration;
private static MemoryConfiguration currentConfiguration;
// Default configuration comes from SPIM
private static final 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 final 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 final 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();
// 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) {
// 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 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) {
}
return null;
}
public static MemoryConfiguration getDefaultConfiguration()
{
if (defaultConfiguration == null)
{
buildConfigurationCollection();
}
return defaultConfiguration;
}
public static MemoryConfiguration getCurrentConfiguration() {
if (currentConfiguration == null) {
}
return defaultConfiguration;
}
public static MemoryConfiguration getCurrentConfiguration()
{
if (currentConfiguration == null)
{
buildConfigurationCollection();
}
return currentConfiguration;
}
public static boolean setCurrentConfiguration(MemoryConfiguration config) {
if (config == null)
}
return currentConfiguration;
}
public static boolean setCurrentConfiguration(MemoryConfiguration config)
{
if (config == null)
{
return false;
if (config != currentConfiguration) {
}
if (config != currentConfiguration)
{
currentConfiguration = config;
Globals.memory.clear();
RegisterFile.getUserRegister("$gp").changeResetValue(config.getGlobalPointer());
@@ -224,99 +244,120 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
RegisterFile.initializeProgramCounter(config.getTextBaseAddress());
RegisterFile.resetRegisters();
return true;
}
else {
}
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];
}
}
}
}
//// 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];
}
}
+142 -122
View File
@@ -1,6 +1,6 @@
package mars.mips.hardware;
import mars.*;
import java.util.*;
package mars.mips.hardware;
import java.util.Observable;
/*
Copyright (c) 2003-2006, Pete Sanderson and Kenneth Vollmar
@@ -30,125 +30,145 @@ 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;
}
/**
* Abstraction to represent a register of a MIPS Assembler.
*
* @author Jason Bumgarner, Jason Shrewsbury, Ben Sherman
* @version June 2003
**/
/**
* 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()) {
public class Register extends Observable
{
private final String name;
private final int number;
private int 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));
}
}
}
}
}
}
@@ -29,31 +29,37 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* Object provided to Observers of runtime access to MIPS register.
* Observer can get the access type (R/W) and register number.
*
* @author Pete Sanderson
* 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;
public class RegisterAccessNotice extends AccessNotice
{
private final 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;
}
}
/**
* 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;
}
}
+342 -286
View File
@@ -1,11 +1,11 @@
package mars.mips.hardware;
package mars.mips.hardware;
import java.util.Observer;
import mars.Globals;
import mars.assembler.SymbolTable;
import mars.mips.instructions.Instruction;
import mars.util.Binary;
import mars.Globals;
import mars.assembler.SymbolTable;
import mars.mips.instructions.Instruction;
import mars.util.Binary;
import java.util.Observer;
/*
Copyright (c) 2003-2008, Pete Sanderson and Kenneth Vollmar
@@ -36,304 +36,360 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* Represents the collection of MIPS registers.
* @author Jason Bumgarner, Jason Shrewsbury
* @version June 2003
**/
* Represents the collection of MIPS registers.
*
* @author Jason Bumgarner, Jason Shrewsbury
* @version June 2003
**/
public class RegisterFile {
public static final int GLOBAL_POINTER_REGISTER = 28;
public static final int STACK_POINTER_REGISTER = 29;
private static Register [] regFile =
{ new Register("$zero", 0, 0), new Register("$at", 1, 0),
new Register("$v0", 2, 0),new Register("$v1", 3, 0),
new Register("$a0", 4, 0),new Register("$a1", 5, 0),
new Register("$a2", 6, 0),new Register("$a3", 7, 0),
new Register("$t0", 8, 0),new Register("$t1", 9, 0),
new Register("$t2", 10, 0),new Register("$t3", 11, 0),
new Register("$t4", 12, 0),new Register("$t5", 13, 0),
new Register("$t6", 14, 0),new Register("$t7", 15, 0),
new Register("$s0", 16, 0),new Register("$s1", 17, 0),
new Register("$s2", 18, 0),new Register("$s3", 19, 0),
new Register("$s4", 20, 0),new Register("$s5", 21, 0),
new Register("$s6", 22, 0),new Register("$s7", 23, 0),
new Register("$t8", 24, 0),new Register("$t9", 25, 0),
new Register("$k0", 26, 0),new Register("$k1", 27, 0),
new Register("$gp", GLOBAL_POINTER_REGISTER, Memory.globalPointer),
new Register("$sp", STACK_POINTER_REGISTER, Memory.stackPointer),
new Register("$fp", 30, 0),new Register("$ra", 31, 0)
};
private static Register programCounter= new Register("pc", 32, Memory.textBaseAddress);
private static Register hi= new Register("hi", 33, 0);//this is an internal register with arbitrary number
private static Register lo= new Register("lo", 34, 0);// this is an internal register with arbitrary number
/**
* Method for displaying the register values for debugging.
**/
public static void showRegisters(){
for (int i=0; i< regFile.length; i++){
public class RegisterFile
{
public static final int GLOBAL_POINTER_REGISTER = 28;
public static final int STACK_POINTER_REGISTER = 29;
private static final Register[] regFile =
{new Register("$zero", 0, 0), new Register("$at", 1, 0),
new Register("$v0", 2, 0), new Register("$v1", 3, 0),
new Register("$a0", 4, 0), new Register("$a1", 5, 0),
new Register("$a2", 6, 0), new Register("$a3", 7, 0),
new Register("$t0", 8, 0), new Register("$t1", 9, 0),
new Register("$t2", 10, 0), new Register("$t3", 11, 0),
new Register("$t4", 12, 0), new Register("$t5", 13, 0),
new Register("$t6", 14, 0), new Register("$t7", 15, 0),
new Register("$s0", 16, 0), new Register("$s1", 17, 0),
new Register("$s2", 18, 0), new Register("$s3", 19, 0),
new Register("$s4", 20, 0), new Register("$s5", 21, 0),
new Register("$s6", 22, 0), new Register("$s7", 23, 0),
new Register("$t8", 24, 0), new Register("$t9", 25, 0),
new Register("$k0", 26, 0), new Register("$k1", 27, 0),
new Register("$gp", GLOBAL_POINTER_REGISTER, Memory.globalPointer),
new Register("$sp", STACK_POINTER_REGISTER, Memory.stackPointer),
new Register("$fp", 30, 0), new Register("$ra", 31, 0)
};
private static final Register programCounter = new Register("pc", 32, Memory.textBaseAddress);
private static final Register hi = new Register("hi", 33, 0);//this is an internal register with arbitrary number
private static final Register lo = new Register("lo", 34, 0);// this is an internal register with arbitrary number
/**
* Method for displaying the register values for debugging.
**/
public static void showRegisters()
{
for (int i = 0; i < regFile.length; i++)
{
System.out.println("Name: " + regFile[i].getName());
System.out.println("Number: " + regFile[i].getNumber());
System.out.println("Value: " + regFile[i].getValue());
System.out.println("");
}
}
/**
* This method updates the register value who's number is num. Also handles the lo and hi registers
* @param num Register to set the value of.
* @param val The desired value for the register.
**/
public static int updateRegister(int num, int val){
int old = 0;
if(num == 0){
System.out.println("Value: " + regFile[i].getValue());
System.out.println();
}
}
/**
* This method updates the register value who's number is num. Also handles the lo and hi registers
*
* @param num Register to set the value of.
* @param val The desired value for the register.
**/
public static int updateRegister(int num, int val)
{
int old = 0;
if (num == 0)
{
//System.out.println("You can not change the value of the zero register.");
}
else {
for (int i=0; i< regFile.length; i++){
if(regFile[i].getNumber()== num) {
old = (Globals.getSettings().getBackSteppingEnabled())
? Globals.program.getBackStepper().addRegisterFileRestore(num,regFile[i].setValue(val))
: regFile[i].setValue(val);
break;
}
}
else
{
for (int i = 0; i < regFile.length; i++)
{
if (regFile[i].getNumber() == num)
{
old = (Globals.getSettings().getBackSteppingEnabled())
? Globals.program.getBackStepper().addRegisterFileRestore(num, regFile[i].setValue(val))
: regFile[i].setValue(val);
break;
}
}
}
if(num== 33){//updates the hi register
}
if (num == 33)
{//updates the hi register
old = (Globals.getSettings().getBackSteppingEnabled())
? Globals.program.getBackStepper().addRegisterFileRestore(num,hi.setValue(val))
: hi.setValue(val);
}
else if(num== 34){// updates the low register
? Globals.program.getBackStepper().addRegisterFileRestore(num, hi.setValue(val))
: hi.setValue(val);
}
else if (num == 34)
{// updates the low register
old = (Globals.getSettings().getBackSteppingEnabled())
? Globals.program.getBackStepper().addRegisterFileRestore(num,lo.setValue(val))
: lo.setValue(val);
}
return old;
}
/**
* Sets the value of the register given to the value given.
* @param reg Name of register to set the value of.
* @param val The desired value for the register.
**/
public static void updateRegister(String reg, int val){
if(reg.equals("zero")){
? Globals.program.getBackStepper().addRegisterFileRestore(num, lo.setValue(val))
: lo.setValue(val);
}
return old;
}
/**
* Sets the value of the register given to the value given.
*
* @param reg Name of register to set the value of.
* @param val The desired value for the register.
**/
public static void updateRegister(String reg, int val)
{
if (reg.equals("zero"))
{
//System.out.println("You can not change the value of the zero register.");
}
else{
for (int i=0; i< regFile.length; i++){
if(regFile[i].getName().equals(reg)) {
updateRegister(i,val);
break;
}
}}
}
/**
* Returns the value of the register who's number is num.
* @param num The register number.
* @return The value of the given register.
**/
public static int getValue(int num){
if(num==33){
}
else
{
for (int i = 0; i < regFile.length; i++)
{
if (regFile[i].getName().equals(reg))
{
updateRegister(i, val);
break;
}
}
}
}
/**
* Returns the value of the register who's number is num.
*
* @param num The register number.
* @return The value of the given register.
**/
public static int getValue(int num)
{
if (num == 33)
{
return hi.getValue();
}
else if(num==34){
}
else if (num == 34)
{
return lo.getValue();
}
else
}
else
{
return regFile[num].getValue();
}
/**
* 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
* or -1 if no match.
**/
public static int getNumber(String n){
int j=-1;
for (int i=0; i< regFile.length; i++){
if(regFile[i].getName().equals(n)) {
j= regFile[i].getNumber();
break;
}
}
/**
* 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 or -1 if no match.
**/
public static int getNumber(String n)
{
int j = -1;
for (int i = 0; i < regFile.length; i++)
{
if (regFile[i].getName().equals(n))
{
j = regFile[i].getNumber();
break;
}
}
return j;
}
/**
* For returning the set of registers.
* @return The set of registers.
**/
public static Register[] getRegisters(){
return regFile;
}
/**
* Get register object corresponding to given name. If no match, return null.
* @param Rname The register name, either in $0 or $zero format.
* @return The register object,or null if not found.
**/
public static Register getUserRegister(String Rname) {
Register reg = null;
if (Rname.charAt(0) == '$') {
try {
// check for register number 0-31.
reg = regFile[Binary.stringToInt(Rname.substring(1))]; // KENV 1/6/05
}
return j;
}
/**
* For returning the set of registers.
*
* @return The set of registers.
**/
public static Register[] getRegisters()
{
return regFile;
}
/**
* Get register object corresponding to given name. If no match, return null.
*
* @param Rname The register name, either in $0 or $zero format.
* @return The register object,or null if not found.
**/
public static Register getUserRegister(String Rname)
{
Register reg = null;
if (Rname.charAt(0) == '$')
{
try
{
// check for register number 0-31.
reg = regFile[Binary.stringToInt(Rname.substring(1))]; // KENV 1/6/05
}
catch (Exception e) {
// handles both NumberFormat and ArrayIndexOutOfBounds
// check for register mnemonic $zero thru $ra
reg = null; // just to be sure
// just do linear search; there aren't that many registers
for (int i=0; i < regFile.length; i++) {
if (Rname.equals(regFile[i].getName())) {
catch (Exception e)
{
// handles both NumberFormat and ArrayIndexOutOfBounds
// check for register mnemonic $zero thru $ra
reg = null; // just to be sure
// just do linear search; there aren't that many registers
for (int i = 0; i < regFile.length; i++)
{
if (Rname.equals(regFile[i].getName()))
{
reg = regFile[i];
break;
}
}
}
}
return reg;
}
/**
* For initializing the Program Counter. Do not use this to implement jumps and
* branches, as it will NOT record a backstep entry with the restore value.
* If you need backstepping capability, use setProgramCounter instead.
* @param value The value to set the Program Counter to.
**/
public static void initializeProgramCounter(int value){
programCounter.setValue(value);
}
/**
* Will initialize the Program Counter to either the default reset value, or the address
* associated with source program global label "main", if it exists as a text segment label
* and the global setting is set.
* @param startAtMain If true, will set program counter to address of statement labeled
* 'main' (or other defined start label) if defined. If not defined, or if parameter false,
* will set program counter to default reset value.
**/
public static void initializeProgramCounter(boolean startAtMain) {
int mainAddr = Globals.symbolTable.getAddress(SymbolTable.getStartLabel());
if (startAtMain && mainAddr != SymbolTable.NOT_FOUND && (Memory.inTextSegment(mainAddr) || Memory.inKernelTextSegment(mainAddr))) {
}
}
}
}
return reg;
}
/**
* For initializing the Program Counter. Do not use this to implement jumps and branches, as it will NOT record a
* backstep entry with the restore value. If you need backstepping capability, use setProgramCounter instead.
*
* @param value The value to set the Program Counter to.
**/
public static void initializeProgramCounter(int value)
{
programCounter.setValue(value);
}
/**
* Will initialize the Program Counter to either the default reset value, or the address associated with source
* program global label "main", if it exists as a text segment label and the global setting is set.
*
* @param startAtMain If true, will set program counter to address of statement labeled 'main' (or other defined
* start label) if defined. If not defined, or if parameter false, will set program counter to default reset
* value.
**/
public static void initializeProgramCounter(boolean startAtMain)
{
int mainAddr = Globals.symbolTable.getAddress(SymbolTable.getStartLabel());
if (startAtMain && mainAddr != SymbolTable.NOT_FOUND && (Memory.inTextSegment(mainAddr) || Memory.inKernelTextSegment(mainAddr)))
{
initializeProgramCounter(mainAddr);
}
else {
}
else
{
initializeProgramCounter(programCounter.getResetValue());
}
}
/**
* For setting the Program Counter. Note that ordinary PC update should be done using
* incrementPC() method. Use this only when processing jumps and branches.
* @param value The value to set the Program Counter to.
* @return previous PC value
**/
public static int setProgramCounter(int value){
int old = programCounter.getValue();
programCounter.setValue(value);
if (Globals.getSettings().getBackSteppingEnabled()) {
}
}
/**
* For setting the Program Counter. Note that ordinary PC update should be done using incrementPC() method. Use
* this only when processing jumps and branches.
*
* @param value The value to set the Program Counter to.
* @return previous PC value
**/
public static int setProgramCounter(int value)
{
int old = programCounter.getValue();
programCounter.setValue(value);
if (Globals.getSettings().getBackSteppingEnabled())
{
Globals.program.getBackStepper().addPCRestore(old);
}
return old;
}
/**
* For returning the program counters value.
* @return The program counters value as an int.
**/
public static int getProgramCounter(){
return programCounter.getValue();
}
/**
* Returns Register object for program counter. Use with caution.
* @return program counter's Register object.
*/
public static Register getProgramCounterRegister() {
return programCounter;
}
/**
* For returning the program counter's initial (reset) value.
* @return The program counter's initial value
**/
public static int getInitialProgramCounter(){
return programCounter.getResetValue();
}
/**
* Method to reinitialize the values of the registers.
* <b>NOTE:</b> Should <i>not</i> be called from command-mode MARS because this
* this method uses global settings from the registry. Command-mode must operate
* using only the command switches, not registry settings. It can be called
* from tools running stand-alone, and this is done in
* <code>AbstractMarsToolAndApplication</code>.
**/
public static void resetRegisters(){
for(int i=0; i< regFile.length; i++){
}
return old;
}
/**
* For returning the program counters value.
*
* @return The program counters value as an int.
**/
public static int getProgramCounter()
{
return programCounter.getValue();
}
/**
* Returns Register object for program counter. Use with caution.
*
* @return program counter's Register object.
*/
public static Register getProgramCounterRegister()
{
return programCounter;
}
/**
* For returning the program counter's initial (reset) value.
*
* @return The program counter's initial value
**/
public static int getInitialProgramCounter()
{
return programCounter.getResetValue();
}
/**
* Method to reinitialize the values of the registers.
* <b>NOTE:</b> Should <i>not</i> be called from command-mode MARS because this
* this method uses global settings from the registry. Command-mode must operate using only the command switches,
* not registry settings. It can be called from tools running stand-alone, and this is done in
* <code>AbstractMarsToolAndApplication</code>.
**/
public static void resetRegisters()
{
for (int i = 0; i < regFile.length; i++)
{
regFile[i].resetValue();
}
initializeProgramCounter(Globals .getSettings().getStartAtMain());// replaces "programCounter.resetValue()", DPS 3/3/09
hi.resetValue();
lo.resetValue();
}
/**
* Method to increment the Program counter in the general case (not a jump or branch).
**/
public static void incrementPC(){
programCounter.setValue(programCounter.getValue() + Instruction.INSTRUCTION_LENGTH);
}
/**
* Each individual register is a separate object and Observable. This handy method
* will add the given Observer to each one. Currently does not apply to Program
* Counter.
*/
public static void addRegistersObserver(Observer observer) {
for (int i=0; i<regFile.length; i++) {
}
initializeProgramCounter(Globals.getSettings().getStartAtMain());// replaces "programCounter.resetValue()", DPS 3/3/09
hi.resetValue();
lo.resetValue();
}
/**
* Method to increment the Program counter in the general case (not a jump or branch).
**/
public static void incrementPC()
{
programCounter.setValue(programCounter.getValue() + Instruction.INSTRUCTION_LENGTH);
}
/**
* Each individual register is a separate object and Observable. This handy method will add the given Observer to
* each one. Currently does not apply to Program Counter.
*/
public static void addRegistersObserver(Observer observer)
{
for (int i = 0; i < regFile.length; i++)
{
regFile[i].addObserver(observer);
}
hi.addObserver(observer);
lo.addObserver(observer);
}
/**
* Each individual register is a separate object and Observable. This handy method
* will delete the given Observer from each one. Currently does not apply to Program
* Counter.
*/
public static void deleteRegistersObserver(Observer observer) {
for (int i=0; i<regFile.length; i++) {
}
hi.addObserver(observer);
lo.addObserver(observer);
}
/**
* Each individual register is a separate object and Observable. This handy method will delete the given Observer
* from each one. Currently does not apply to Program Counter.
*/
public static void deleteRegistersObserver(Observer observer)
{
for (int i = 0; i < regFile.length; i++)
{
regFile[i].deleteObserver(observer);
}
hi.deleteObserver(observer);
lo.deleteObserver(observer);
}
}
}
hi.deleteObserver(observer);
lo.deleteObserver(observer);
}
}
@@ -29,114 +29,124 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* Class to represent a basic instruction in the MIPS instruction set.
* Basic instruction means it translates directly to a 32-bit binary machine
* instruction.
*
* Class to represent a basic instruction in the MIPS instruction set. Basic instruction means it translates directly to
* a 32-bit binary machine instruction.
*
* @author Pete Sanderson and Ken Vollmar
* @version August 2003
*/
public class BasicInstruction extends Instruction {
public class BasicInstruction extends Instruction
{
private String instructionName;
private BasicInstructionFormat instructionFormat;
private String operationMask;
private SimulationCode simulationCode;
private int opcodeMask; // integer with 1's where constants required (0/1 become 1, f/s/t become 0)
private int opcodeMatch; // integer matching constants required (0/1 become 0/1, f/s/t become 0)
/**
* BasicInstruction constructor.
*
* @param example An example usage of the instruction, as a String.
* @param instrFormat The format is R, I, I-branch or J.
* @param operMask The opcode mask is a 32 character string that contains the opcode in binary in the appropriate bit positions and codes for operand positions ('f', 's', 't') in the remainding positions.
* @param simCode The inline definition of an object and class which anonymously implements the SimulationCode interface.
private final BasicInstructionFormat instructionFormat;
private final String operationMask;
private final SimulationCode simulationCode;
private final int opcodeMask; // integer with 1's where constants required (0/1 become 1, f/s/t become 0)
private final int opcodeMatch; // integer matching constants required (0/1 become 0/1, f/s/t become 0)
/**
* BasicInstruction constructor.
*
* @param example An example usage of the instruction, as a String.
* @param instrFormat The format is R, I, I-branch or J.
* @param operMask The opcode mask is a 32 character string that contains the opcode in binary in the
* appropriate bit positions and codes for operand positions ('f', 's', 't') in the remainding positions.
* @param simCode The inline definition of an object and class which anonymously implements the SimulationCode
* interface.
* @see SimulationCode
**/
/* codes for operand positions are:
* f == First operand
* s == Second operand
* t == Third operand
* example: "add rd,rs,rt" is R format with fields in this order: opcode, rs, rt, rd, shamt, funct.
* Its opcode is 0, shamt is 0, funct is 0x40. Based on operand order, its mask is
* "000000ssssstttttfffff00000100000", split into
* opcode | rs | rt | rd | shamt | funct
* 000000 | sssss | ttttt | fffff | 00000 | 100000
* This mask can be used at code generation time to map the assembly component to its
* correct bit positions in the binary machine instruction.
* It can also be used at runtime to match a binary machine instruction to the correct
* instruction simulator -- it needs to match all and only the 0's and 1's.
*/
public BasicInstruction(String example, String description, BasicInstructionFormat instrFormat,
String operMask, SimulationCode simCode) {
**/
/* codes for operand positions are:
* f == First operand
* s == Second operand
* t == Third operand
* example: "add rd,rs,rt" is R format with fields in this order: opcode, rs, rt, rd, shamt, funct.
* Its opcode is 0, shamt is 0, funct is 0x40. Based on operand order, its mask is
* "000000ssssstttttfffff00000100000", split into
* opcode | rs | rt | rd | shamt | funct
* 000000 | sssss | ttttt | fffff | 00000 | 100000
* This mask can be used at code generation time to map the assembly component to its
* correct bit positions in the binary machine instruction.
* It can also be used at runtime to match a binary machine instruction to the correct
* instruction simulator -- it needs to match all and only the 0's and 1's.
*/
public BasicInstruction(String example, String description, BasicInstructionFormat instrFormat,
String operMask, SimulationCode simCode)
{
this.exampleFormat = example;
this.mnemonic = this.extractOperator(example);
this.description = description;
this.instructionFormat = instrFormat;
this.operationMask = operMask.replaceAll(" ",""); // squeeze out any/all spaces
if (operationMask.length() != Instruction.INSTRUCTION_LENGTH_BITS) {
System.out.println(example+" mask not "+Instruction.INSTRUCTION_LENGTH_BITS+" bits!");
}
this.operationMask = operMask.replaceAll(" ", ""); // squeeze out any/all spaces
if (operationMask.length() != Instruction.INSTRUCTION_LENGTH_BITS)
{
System.out.println(example + " mask not " + Instruction.INSTRUCTION_LENGTH_BITS + " bits!");
}
this.simulationCode = simCode;
this.opcodeMask = (int) Long.parseLong(this.operationMask.replaceAll("[01]", "1").replaceAll("[^01]", "0"), 2);
this.opcodeMatch = (int) Long.parseLong(this.operationMask.replaceAll("[^1]", "0"), 2);
}
// Temporary constructor so that instructions without description yet will compile.
public BasicInstruction(String example, BasicInstructionFormat instrFormat,
String operMask, SimulationCode simCode) {
this(example,"",instrFormat,operMask,simCode);
}
/**
* Gets the 32-character operation mask. Each mask position represents a
* bit position in the 32-bit machine instruction. Operation codes and
* unused bits are represented in the mask by 1's and 0's. Operand codes
* are represented by 'f', 's', and 't' for bits occupied by first, secon
* and third operand, respectively.
*
* @return The 32 bit mask, as a String
*/
public String getOperationMask() {
return operationMask;
}
/**
* Gets the operand format of the instruction. MIPS defines 3 of these
* R-format, I-format, and J-format. R-format is all registers. I-format
* is address formed from register base with immediate offset. J-format
* is for jump destination addresses. I have added one more:
* I-branch-format, for branch destination addresses. These are a variation
* of the I-format in that the computed value is address relative to the
* Program Counter. All four formats are represented by static objects.
*
* @return The machine instruction format, R, I, J or I-branch.
*/
public BasicInstructionFormat getInstructionFormat() {
return instructionFormat;
}
/**
* Gets the SimulationCode object. It is really an object of an anonymous
* class that implements the SimulationCode interface. Such an object has but one
* method: Simulate().
*
* @return the SimulationCode object for this instruction.
* @see SimulationCode
**/
public SimulationCode getSimulationCode() {
return simulationCode;
}
this.opcodeMask = (int) Long.parseLong(this.operationMask.replaceAll("[01]", "1").replaceAll("[^01]", "0"), 2);
this.opcodeMatch = (int) Long.parseLong(this.operationMask.replaceAll("[^1]", "0"), 2);
}
public int getOpcodeMask() {
return this.opcodeMask;
}
// Temporary constructor so that instructions without description yet will compile.
public int getOpcodeMatch() {
return this.opcodeMatch;
}
public BasicInstruction(String example, BasicInstructionFormat instrFormat,
String operMask, SimulationCode simCode)
{
this(example, "", instrFormat, operMask, simCode);
}
/**
* Gets the 32-character operation mask. Each mask position represents a bit position in the 32-bit machine
* instruction. Operation codes and unused bits are represented in the mask by 1's and 0's. Operand codes are
* represented by 'f', 's', and 't' for bits occupied by first, secon and third operand, respectively.
*
* @return The 32 bit mask, as a String
*/
public String getOperationMask()
{
return operationMask;
}
/**
* Gets the operand format of the instruction. MIPS defines 3 of these R-format, I-format, and J-format. R-format
* is all registers. I-format is address formed from register base with immediate offset. J-format is for jump
* destination addresses. I have added one more: I-branch-format, for branch destination addresses. These are a
* variation of the I-format in that the computed value is address relative to the Program Counter. All four
* formats are represented by static objects.
*
* @return The machine instruction format, R, I, J or I-branch.
*/
public BasicInstructionFormat getInstructionFormat()
{
return instructionFormat;
}
/**
* Gets the SimulationCode object. It is really an object of an anonymous class that implements the SimulationCode
* interface. Such an object has but one method: Simulate().
*
* @return the SimulationCode object for this instruction.
* @see SimulationCode
**/
public SimulationCode getSimulationCode()
{
return simulationCode;
}
public int getOpcodeMask()
{
return this.opcodeMask;
}
public int getOpcodeMatch()
{
return this.opcodeMatch;
}
}
@@ -29,23 +29,26 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* These are the MIPS-defined formats of basic machine instructions. The R-format indicates
* the instruction works only with registers. The I-format indicates the instruction
* works with an immediate value (e.g. constant). The J-format indicates this is a Jump
* instruction. The I-branch-format is defined by me, not MIPS, to to indicate this is
* a Branch instruction, specifically to distinguish immediate
* values used as target addresses.
*
* @author Pete Sanderson
* These are the MIPS-defined formats of basic machine instructions. The R-format indicates the instruction works only
* with registers. The I-format indicates the instruction works with an immediate value (e.g. constant). The J-format
* indicates this is a Jump instruction. The I-branch-format is defined by me, not MIPS, to to indicate this is a
* Branch instruction, specifically to distinguish immediate values used as target addresses.
*
* @author Pete Sanderson
* @version August 2003
*/
public class BasicInstructionFormat {
public class BasicInstructionFormat
{
public static final BasicInstructionFormat R_FORMAT = new BasicInstructionFormat();
public static final BasicInstructionFormat I_FORMAT = new BasicInstructionFormat();
public static final BasicInstructionFormat I_BRANCH_FORMAT = new BasicInstructionFormat();
public static final BasicInstructionFormat J_FORMAT = new BasicInstructionFormat();
// private default constructor prevents objects of this class other than those above.
private BasicInstructionFormat() {
private BasicInstructionFormat()
{
}
}
File diff suppressed because it is too large Load Diff
@@ -1,7 +1,10 @@
package mars.mips.instructions;
import mars.assembler.*;
import mars.*;
import java.util.*;
import mars.ProcessingException;
import mars.assembler.TokenList;
import mars.assembler.Tokenizer;
import java.util.StringTokenizer;
/*
Copyright (c) 2003-2006, Pete Sanderson and Kenneth Vollmar
@@ -33,30 +36,37 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
/**
* Base class to represent member of MIPS instruction set.
*
*
* @author Pete Sanderson and Ken Vollmar
* @version August 2003
*/
public abstract class Instruction {
/**
* Length in bytes of a machine instruction. MIPS is a RISC architecture
* so all instructions are the same length. Currently set to 4.
*/
public static final int INSTRUCTION_LENGTH = 4;
public static final int INSTRUCTION_LENGTH_BITS = 32;
/** Characters used in instruction mask to indicate bit positions
* for 'f'irst, 's'econd, and 't'hird operands.
public abstract class Instruction
{
/**
* Length in bytes of a machine instruction. MIPS is a RISC architecture so all instructions are the same length.
* Currently set to 4.
*/
public static final int INSTRUCTION_LENGTH = 4;
public static final int INSTRUCTION_LENGTH_BITS = 32;
/**
* Characters used in instruction mask to indicate bit positions for 'f'irst, 's'econd, and 't'hird operands.
**/
public static char[] operandMask = { 'f', 's', 't'};
public static char[] operandMask = {'f', 's', 't'};
/** The instruction name. **/
protected String mnemonic;
/** Example usage of this instruction. Is provided as subclass constructor argument. **/
protected String exampleFormat;
/** Description of instruction for display to user **/
protected String description;
/** List of tokens generated by tokenizing example usage (see <tt>exampleFormat</tt>). **/
protected TokenList tokenList;
protected String mnemonic;
/** Example usage of this instruction. Is provided as subclass constructor argument. **/
protected String exampleFormat;
/** Description of instruction for display to user **/
protected String description;
/** List of tokens generated by tokenizing example usage (see <tt>exampleFormat</tt>). **/
protected TokenList tokenList;
/**
@@ -64,72 +74,83 @@ public abstract class Instruction {
*
* @return operation mnemonic (e.g. addi, sw)
*/
public String getName() {
public String getName()
{
return mnemonic;
}
/**
* Get string descriptor of instruction's format. This is an example MIPS
* assembler instruction usage which contains the operator and all operands.
* Operands are separated by commas, an operand that begins with a '$'
* represents a register, and an integer operand represents an immediate value
* or address. Here are two examples: "nor $1,$2,$3" and "sw $1,100($2)"
* Get string descriptor of instruction's format. This is an example MIPS assembler instruction usage which
* contains the operator and all operands. Operands are separated by commas, an operand that begins with a '$'
* represents a register, and an integer operand represents an immediate value or address. Here are two examples:
* "nor $1,$2,$3" and "sw $1,100($2)"
*
* @return String representing example instruction format.
*/
public String getExampleFormat() {
public String getExampleFormat()
{
return exampleFormat;
}
/**
* Get string describing the instruction. This is not used internally by
* MARS, but is for display to the user.
* Get string describing the instruction. This is not used internally by MARS, but is for display to the user.
*
* @return String describing the instruction.
*/
public String getDescription() {
public String getDescription()
{
return description;
}
/**
* Get TokenList corresponding to correct instruction syntax.
* For example, the instruction with format "sw $1,100($2)" yields token list
* Get TokenList corresponding to correct instruction syntax. For example, the instruction with format "sw
* $1,100($2)" yields token list
* <operator><register_number><integer><left_paren><register_number><right_parent>
*
* @return TokenList object representing correct instruction usage.
*/
public TokenList getTokenList() {
public TokenList getTokenList()
{
return tokenList;
}
/**
* Get length in bytes that this instruction requires in its binary form.
* Default is 4 (holds for all basic instructions), but can be overridden
* in subclass.
* Get length in bytes that this instruction requires in its binary form. Default is 4 (holds for all basic
* instructions), but can be overridden in subclass.
*
* @return int length in bytes of corresponding binary instruction(s).
*/
public int getInstructionLength() {
public int getInstructionLength()
{
return INSTRUCTION_LENGTH;
}
/** Used by subclass constructors to extract operator mnemonic from the
instruction example. **/
protected String extractOperator(String example) {
/**
* Used by subclass constructors to extract operator mnemonic from the instruction example.
**/
protected String extractOperator(String example)
{
StringTokenizer st = new StringTokenizer(example, " ,\t");
return st.nextToken();
}
/** Used to build a token list from the example instruction
provided as constructor argument. Parser uses this for syntax checking. **/
protected void createExampleTokenList() {
try {
/**
* Used to build a token list from the example instruction provided as constructor argument. Parser uses this for
* syntax checking.
**/
protected void createExampleTokenList()
{
try
{
tokenList = ((new Tokenizer()).tokenizeExampleInstruction(exampleFormat));
} catch (ProcessingException pe) {
System.out.println("CONFIGURATION ERROR: Instruction example \""+exampleFormat+"\" contains invalid token(s).");
}
catch (ProcessingException pe)
{
System.out.println("CONFIGURATION ERROR: Instruction example \"" + exampleFormat + "\" contains invalid token(s).");
}
}
}
File diff suppressed because it is too large Load Diff
@@ -1,5 +1,7 @@
package mars.mips.instructions;
import mars.*;
import mars.ProcessingException;
import mars.ProgramStatement;
/*
Copyright (c) 2003-2006, Pete Sanderson and Kenneth Vollmar
@@ -30,23 +32,22 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* Interface to represent the method for simulating the execution of a specific MIPS basic
* instruction. It will be implemented by the anonymous class created in the last
* argument to the BasicInstruction constructor.
*
* @author Pete Sanderson
* Interface to represent the method for simulating the execution of a specific MIPS basic instruction. It will be
* implemented by the anonymous class created in the last argument to the BasicInstruction constructor.
*
* @author Pete Sanderson
* @version August 2003
*
*/
public interface SimulationCode {
public interface SimulationCode
{
/**
* Method to simulate the execution of a specific MIPS basic instruction.
*
* @param statement A ProgramStatement representing the MIPS instruction to simulate.
*
* @param statement A ProgramStatement representing the MIPS instruction to simulate.
* @throws ProcessingException This is a run-time exception generated during simulation.
**/
public void simulate(ProgramStatement statement) throws ProcessingException;
void simulate(ProgramStatement statement) throws ProcessingException;
}
@@ -1,8 +1,12 @@
package mars.mips.instructions;
import mars.mips.instructions.syscalls.*;
import mars.*;
import mars.util.*;
import java.util.*;
package mars.mips.instructions;
import mars.Globals;
import mars.mips.instructions.syscalls.Syscall;
import mars.mips.instructions.syscalls.SyscallNumberOverride;
import mars.util.FilenameFinder;
import java.util.ArrayList;
import java.util.HashMap;
/*
Copyright (c) 2003-2006, Pete Sanderson and Kenneth Vollmar
@@ -32,138 +36,166 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
(MIT license, http://www.opensource.org/licenses/mit-license.html)
*/
/****************************************************************************/
/* This class provides functionality to bring external Syscall definitions
* into MARS. This permits anyone with knowledge of the Mars public interfaces,
* in particular of the Memory and Register classes, to write custom MIPS syscall
* functions. This is adapted from the ToolLoader class, which is in turn adapted
* from Bret Barker's GameServer class from the book "Developing Games In Java".
/****************************************************************************/
/* This class provides functionality to bring external Syscall definitions
* into MARS. This permits anyone with knowledge of the Mars public interfaces,
* in particular of the Memory and Register classes, to write custom MIPS syscall
* functions. This is adapted from the ToolLoader class, which is in turn adapted
* from Bret Barker's GameServer class from the book "Developing Games In Java".
*/
class SyscallLoader
{
private static final String CLASS_PREFIX = "mars.mips.instructions.syscalls.";
private static final String SYSCALLS_DIRECTORY_PATH = "mars/mips/instructions/syscalls";
private static final String SYSCALL_INTERFACE = "Syscall.class";
private static final String SYSCALL_ABSTRACT = "AbstractSyscall.class";
private static final String CLASS_EXTENSION = "class";
private ArrayList syscallList;
/*
* Dynamically loads Syscalls into an ArrayList. This method is adapted from
* the loadGameControllers() method in Bret Barker's GameServer class.
* Barker (bret@hypefiend.com) is co-author of the book "Developing Games
* in Java". Also see the "loadMarsTools()" method from ToolLoader class.
*/
class SyscallLoader {
private static final String CLASS_PREFIX = "mars.mips.instructions.syscalls.";
private static final String SYSCALLS_DIRECTORY_PATH = "mars/mips/instructions/syscalls";
private static final String SYSCALL_INTERFACE = "Syscall.class";
private static final String SYSCALL_ABSTRACT = "AbstractSyscall.class";
private static final String CLASS_EXTENSION = "class";
private ArrayList syscallList;
/*
* Dynamically loads Syscalls into an ArrayList. This method is adapted from
* the loadGameControllers() method in Bret Barker's GameServer class.
* Barker (bret@hypefiend.com) is co-author of the book "Developing Games
* in Java". Also see the "loadMarsTools()" method from ToolLoader class.
*/
void loadSyscalls() {
syscallList = new ArrayList();
// grab all class files in the same directory as Syscall
ArrayList candidates = FilenameFinder.getFilenameList(this.getClass( ).getClassLoader(),
SYSCALLS_DIRECTORY_PATH, CLASS_EXTENSION);
HashMap syscalls = new HashMap();
for( int i = 0; i < candidates.size(); i++) {
String file = (String) candidates.get(i);
// Do not add class if already encountered (happens if run in MARS development directory)
if (syscalls.containsKey(file)) {
continue;
} else {
syscalls.put(file,file);
}
void loadSyscalls()
{
syscallList = new ArrayList();
// grab all class files in the same directory as Syscall
ArrayList candidates = FilenameFinder.getFilenameList(this.getClass().getClassLoader(),
SYSCALLS_DIRECTORY_PATH, CLASS_EXTENSION);
HashMap syscalls = new HashMap();
for (int i = 0; i < candidates.size(); i++)
{
String file = (String) candidates.get(i);
// Do not add class if already encountered (happens if run in MARS development directory)
if (syscalls.containsKey(file))
{
continue;
}
else
{
syscalls.put(file, file);
}
if ((!file.equals(SYSCALL_INTERFACE)) &&
(!file.equals(SYSCALL_ABSTRACT)) ) {
try {
// grab the class, make sure it implements Syscall, instantiate, add to list
String syscallClassName = CLASS_PREFIX+file.substring(0, file.indexOf(CLASS_EXTENSION)-1);
Class clas = Class.forName(syscallClassName);
if (!Syscall.class.isAssignableFrom(clas)) {
continue;
}
Syscall syscall = (Syscall) clas.newInstance();
if (findSyscall(syscall.getNumber()) == null) {
syscallList.add(syscall);
}
else {
throw new Exception("Duplicate service number: "+syscall.getNumber()+
" already registered to "+
(!file.equals(SYSCALL_ABSTRACT)))
{
try
{
// grab the class, make sure it implements Syscall, instantiate, add to list
String syscallClassName = CLASS_PREFIX + file.substring(0, file.indexOf(CLASS_EXTENSION) - 1);
Class clas = Class.forName(syscallClassName);
if (!Syscall.class.isAssignableFrom(clas))
{
continue;
}
Syscall syscall = (Syscall) clas.newInstance();
if (findSyscall(syscall.getNumber()) == null)
{
syscallList.add(syscall);
}
else
{
throw new Exception("Duplicate service number: " + syscall.getNumber() +
" already registered to " +
findSyscall(syscall.getNumber()).getName());
}
}
catch (Exception e) {
System.out.println("Error instantiating Syscall from file " + file + ": "+e);
System.exit(0);
}
}
}
catch (Exception e)
{
System.out.println("Error instantiating Syscall from file " + file + ": " + e);
System.exit(0);
}
}
}
syscallList = processSyscallNumberOverrides(syscallList);
return;
}
// Will get any syscall number override specifications from MARS config file and
// process them. This will alter syscallList entry for affected names.
private ArrayList processSyscallNumberOverrides(ArrayList syscallList) {
ArrayList overrides = new Globals().getSyscallOverrides();
SyscallNumberOverride override;
Syscall syscall;
for (int index=0; index < overrides.size(); index++) {
}
syscallList = processSyscallNumberOverrides(syscallList);
}
// Will get any syscall number override specifications from MARS config file and
// process them. This will alter syscallList entry for affected names.
private ArrayList processSyscallNumberOverrides(ArrayList syscallList)
{
ArrayList overrides = new Globals().getSyscallOverrides();
SyscallNumberOverride override;
Syscall syscall;
for (int index = 0; index < overrides.size(); index++)
{
override = (SyscallNumberOverride) overrides.get(index);
boolean match = false;
for (int i=0; i < syscallList.size(); i++) {
syscall = (Syscall) syscallList.get(i);
if (override.getName().equals(syscall.getName())) {
// we have a match to service name, assign new number
syscall.setNumber(override.getNumber());
match = true;
}
boolean match = false;
for (int i = 0; i < syscallList.size(); i++)
{
syscall = (Syscall) syscallList.get(i);
if (override.getName().equals(syscall.getName()))
{
// we have a match to service name, assign new number
syscall.setNumber(override.getNumber());
match = true;
}
}
if (!match) {
System.out.println("Error: syscall name '"+override.getName()+
"' in config file does not match any name in syscall list");
System.exit(0);
if (!match)
{
System.out.println("Error: syscall name '" + override.getName() +
"' in config file does not match any name in syscall list");
System.exit(0);
}
}
// Wait until end to check for duplicate numbers. To do so earlier
// would disallow for instance the exchange of numbers between two
// services. This is N-squared operation but N is small.
// This will also detect duplicates that accidently occur from addition
// of a new Syscall subclass to the collection, even if the config file
// does not contain any overrides.
Syscall syscallA, syscallB;
boolean duplicates = false;
for (int i = 0; i < syscallList.size(); i++) {
syscallA = (Syscall)syscallList.get(i);
for (int j = i+1; j < syscallList.size(); j++) {
syscallB = (Syscall)syscallList.get(j);
if ( syscallA.getNumber() == syscallB.getNumber()) {
System.out.println("Error: syscalls "+syscallA.getName()+" and "+
syscallB.getName()+" are both assigned same number "+syscallA.getNumber());
duplicates = true;
}
}
// Wait until end to check for duplicate numbers. To do so earlier
// would disallow for instance the exchange of numbers between two
// services. This is N-squared operation but N is small.
// This will also detect duplicates that accidently occur from addition
// of a new Syscall subclass to the collection, even if the config file
// does not contain any overrides.
Syscall syscallA, syscallB;
boolean duplicates = false;
for (int i = 0; i < syscallList.size(); i++)
{
syscallA = (Syscall) syscallList.get(i);
for (int j = i + 1; j < syscallList.size(); j++)
{
syscallB = (Syscall) syscallList.get(j);
if (syscallA.getNumber() == syscallB.getNumber())
{
System.out.println("Error: syscalls " + syscallA.getName() + " and " +
syscallB.getName() + " are both assigned same number " + syscallA.getNumber());
duplicates = true;
}
}
}
if (duplicates) {
}
if (duplicates)
{
System.exit(0);
}
return syscallList;
}
/*
* Method to find Syscall object associated with given service number.
* Returns null if no associated object found.
*/
Syscall findSyscall(int number) {
// linear search is OK since number of syscalls is small.
Syscall service, match = null;
if (syscallList==null) {
}
return syscallList;
}
/*
* Method to find Syscall object associated with given service number.
* Returns null if no associated object found.
*/
Syscall findSyscall(int number)
{
// linear search is OK since number of syscalls is small.
Syscall service, match = null;
if (syscallList == null)
{
loadSyscalls();
}
for (int index=0; index < syscallList.size(); index++) {
}
for (int index = 0; index < syscallList.size(); index++)
{
service = (Syscall) syscallList.get(index);
if (service.getNumber() == number) {
match = service;
if (service.getNumber() == number)
{
match = service;
}
}
return match;
}
}
}
return match;
}
}
@@ -1,5 +1,7 @@
package mars.mips.instructions.syscalls;
import mars.*;
package mars.mips.instructions.syscalls;
import mars.ProcessingException;
import mars.ProgramStatement;
/*
Copyright (c) 2003-2006, Pete Sanderson and Kenneth Vollmar
@@ -29,66 +31,72 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* Abstract class that a MIPS syscall system service may extend. A qualifying service
* must be a class in the mars.mips.instructions.syscalls package that
* implements the Syscall interface, must be compiled into a .class file,
* and its .class file must be in the same folder as Syscall.class.
* Mars will detect a qualifying syscall upon startup, create an instance
* using its no-argument constructor and add it to its syscall list.
* When its service is invoked at runtime ("syscall" instruction
* with its service number stored in register $v0), its simulate()
* method will be invoked.
*
/**
* Abstract class that a MIPS syscall system service may extend. A qualifying service must be a class in the
* mars.mips.instructions.syscalls package that implements the Syscall interface, must be compiled into a .class file,
* and its .class file must be in the same folder as Syscall.class. Mars will detect a qualifying syscall upon startup,
* create an instance using its no-argument constructor and add it to its syscall list. When its service is invoked at
* runtime ("syscall" instruction with its service number stored in register $v0), its simulate() method will be
* invoked.
*/
public abstract class AbstractSyscall implements Syscall {
private int serviceNumber;
private String serviceName;
/**
* Constructor is provided so subclass may initialize instance variables.
* @param number default assigned service number
* @param name service name which may be used for reference independent of number
*/
public AbstractSyscall(int number, String name) {
serviceNumber = number;
serviceName = name;
}
/**
* Return the name you have chosen for this syscall. This can be used by a MARS
* user to refer to the service when choosing to override its default service
* number in the configuration file.
* @return service name as a string
*/
public String getName() {
return serviceName;
}
/**
* Set the service number. This is provided to allow MARS implementer or user
* to override the default service number.
* @param num specified service number to override the default.
*/
public void setNumber(int num) {
serviceNumber = num;
}
/**
* Return the assigned service number. This is the number the MIPS programmer
* must store into $v0 before issuing the SYSCALL instruction.
* @return assigned service number
*/
public int getNumber() {
return serviceNumber;
}
/**
* Performs syscall function. It will be invoked when the service is invoked
* at simulation time. Service is identified by value stored in $v0.
* @param statement ProgramStatement object for this syscall instruction.
*/
public abstract void simulate(ProgramStatement statement)
throws ProcessingException;
}
public abstract class AbstractSyscall implements Syscall
{
private int serviceNumber;
private final String serviceName;
/**
* Constructor is provided so subclass may initialize instance variables.
*
* @param number default assigned service number
* @param name service name which may be used for reference independent of number
*/
public AbstractSyscall(int number, String name)
{
serviceNumber = number;
serviceName = name;
}
/**
* Return the name you have chosen for this syscall. This can be used by a MARS user to refer to the service when
* choosing to override its default service number in the configuration file.
*
* @return service name as a string
*/
public String getName()
{
return serviceName;
}
/**
* Return the assigned service number. This is the number the MIPS programmer must store into $v0 before issuing
* the SYSCALL instruction.
*
* @return assigned service number
*/
public int getNumber()
{
return serviceNumber;
}
/**
* Set the service number. This is provided to allow MARS implementer or user to override the default service
* number.
*
* @param num specified service number to override the default.
*/
public void setNumber(int num)
{
serviceNumber = num;
}
/**
* Performs syscall function. It will be invoked when the service is invoked at simulation time. Service is
* identified by value stored in $v0.
*
* @param statement ProgramStatement object for this syscall instruction.
*/
public abstract void simulate(ProgramStatement statement)
throws ProcessingException;
}
@@ -1,5 +1,6 @@
package mars.mips.instructions.syscalls;
import java.util.HashMap;
package mars.mips.instructions.syscalls;
import java.util.HashMap;
/*
Copyright (c) 2003-2008, Pete Sanderson and Kenneth Vollmar
@@ -30,14 +31,16 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* This small class serves only to hold a static HashMap for storing
* random number generators for use by all the random number generator
* syscalls.
/**
* This small class serves only to hold a static HashMap for storing random number generators for use by all the random
* number generator syscalls.
*/
public class RandomStreams {
/** Collection of pseudorandom number streams available for use in Rand-type syscalls.
* The streams are by default not seeded. */
static final HashMap randomStreams = new HashMap();
}
public class RandomStreams
{
/**
* Collection of pseudorandom number streams available for use in Rand-type syscalls. The streams are by default not
* seeded.
*/
static final HashMap randomStreams = new HashMap();
}
@@ -1,5 +1,7 @@
package mars.mips.instructions.syscalls;
import mars.*;
package mars.mips.instructions.syscalls;
import mars.ProcessingException;
import mars.ProgramStatement;
/*
Copyright (c) 2003-2006, Pete Sanderson and Kenneth Vollmar
@@ -30,47 +32,47 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* Interface for any MIPS syscall system service. A qualifying service
* must be a class in the mars.mips.instructions.syscalls package that
* implements the Syscall interface, must be compiled into a .class file,
* and its .class file must be in the same folder as Syscall.class.
* Mars will detect a qualifying syscall upon startup, create an instance
* using its no-argument constructor and add it to its syscall list.
* When its service is invoked at runtime ("syscall" instruction
* with its service number stored in register $v0), its simulate()
* method will be invoked.
*
/**
* Interface for any MIPS syscall system service. A qualifying service must be a class in the
* mars.mips.instructions.syscalls package that implements the Syscall interface, must be compiled into a .class file,
* and its .class file must be in the same folder as Syscall.class. Mars will detect a qualifying syscall upon startup,
* create an instance using its no-argument constructor and add it to its syscall list. When its service is invoked at
* runtime ("syscall" instruction with its service number stored in register $v0), its simulate() method will be
* invoked.
*/
public interface Syscall {
/**
* Return a name you have chosen for this syscall. This can be used by a MARS
* user to refer to the service when choosing to override its default service
* number in the configuration file.
* @return service name as a string
*/
public abstract String getName();
/**
* Set the service number. This is provided to allow MARS implementer or user
* to override the default service number.
* @param num specified service number to override the default.
*/
public abstract void setNumber(int num);
/**
* Return the assigned service number. This is the number the MIPS programmer
* must store into $v0 before issuing the SYSCALL instruction.
* @return assigned service number
*/
public abstract int getNumber();
/**
* Performs syscall function. It will be invoked when the service is invoked
* at simulation time. Service is identified by value stored in $v0.
* @param statement ProgramStatement for this syscall statement.
*/
public abstract void simulate(ProgramStatement statement)
throws ProcessingException;
}
public interface Syscall
{
/**
* Return a name you have chosen for this syscall. This can be used by a MARS user to refer to the service when
* choosing to override its default service number in the configuration file.
*
* @return service name as a string
*/
String getName();
/**
* Return the assigned service number. This is the number the MIPS programmer must store into $v0 before issuing
* the SYSCALL instruction.
*
* @return assigned service number
*/
int getNumber();
/**
* Set the service number. This is provided to allow MARS implementer or user to override the default service
* number.
*
* @param num specified service number to override the default.
*/
void setNumber(int num);
/**
* Performs syscall function. It will be invoked when the service is invoked at simulation time. Service is
* identified by value stored in $v0.
*
* @param statement ProgramStatement for this syscall statement.
*/
void simulate(ProgramStatement statement)
throws ProcessingException;
}
@@ -1,7 +1,9 @@
package mars.mips.instructions.syscalls;
import mars.util.*;
import mars.mips.hardware.*;
import mars.*;
package mars.mips.instructions.syscalls;
import mars.ProcessingException;
import mars.ProgramStatement;
import mars.mips.hardware.RegisterFile;
import mars.util.SystemIO;
/*
Copyright (c) 2003-2006, Pete Sanderson and Kenneth Vollmar
@@ -32,24 +34,25 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
/**
* Service to close file descriptor given in $a0.
*
*/
public class SyscallClose extends AbstractSyscall {
/**
* Build an instance of the Close syscall. Default service number
* is 16 and name is "Close".
*/
public SyscallClose() {
super(16, "Close");
}
/**
* Performs syscall function to close file descriptor given in $a0.
*/
public void simulate(ProgramStatement statement) throws ProcessingException {
SystemIO.closeFile(RegisterFile.getValue(4));
}
}
public class SyscallClose extends AbstractSyscall
{
/**
* Build an instance of the Close syscall. Default service number is 16 and name is "Close".
*/
public SyscallClose()
{
super(16, "Close");
}
/**
* Performs syscall function to close file descriptor given in $a0.
*/
public void simulate(ProgramStatement statement) throws ProcessingException
{
SystemIO.closeFile(RegisterFile.getValue(4));
}
}
@@ -1,9 +1,12 @@
package mars.mips.instructions.syscalls;
import mars.util.*;
import mars.mips.hardware.*;
import mars.simulator.*;
import mars.*;
import javax.swing.JOptionPane;
package mars.mips.instructions.syscalls;
import mars.Globals;
import mars.ProcessingException;
import mars.ProgramStatement;
import mars.mips.hardware.AddressErrorException;
import mars.mips.hardware.RegisterFile;
import javax.swing.*;
/*
Copyright (c) 2003-2008, Pete Sanderson and Kenneth Vollmar
@@ -35,52 +38,54 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
/**
* Service to display a message to user.
*
*/
public class SyscallConfirmDialog extends AbstractSyscall {
/**
* Build an instance of the syscall with its default service number and name.
*/
public SyscallConfirmDialog() {
super(50, "ConfirmDialog");
}
public class SyscallConfirmDialog extends AbstractSyscall
{
/**
* Build an instance of the syscall with its default service number and name.
*/
public SyscallConfirmDialog()
{
super(50, "ConfirmDialog");
}
/**
* System call to display a message to user.
*/
public void simulate(ProgramStatement statement) throws ProcessingException {
// Input arguments: $a0 = address of null-terminated string that is the message to user
// Output: $a0 contains value of user-chosen option
// 0: Yes
// 1: No
// 2: Cancel
/**
* System call to display a message to user.
*/
public void simulate(ProgramStatement statement) throws ProcessingException
{
// Input arguments: $a0 = address of null-terminated string that is the message to user
// Output: $a0 contains value of user-chosen option
// 0: Yes
// 1: No
// 2: Cancel
String message = new String(); // = "";
int byteAddress = RegisterFile.getValue(4);
char ch[] = { ' '}; // Need an array to convert to String
try
{
String message = ""; // = "";
int byteAddress = RegisterFile.getValue(4);
char[] ch = {' '}; // Need an array to convert to String
try
{
ch[0] = (char) Globals.memory.getByte(byteAddress);
while (ch[0] != 0) // only uses single location ch[0]
{
message = message.concat(new String(ch)); // parameter to String constructor is a char[] array
byteAddress++;
ch[0] = (char) Globals.memory.getByte(byteAddress);
}
}
catch (AddressErrorException e)
{
throw new ProcessingException(statement, e);
message = message.concat(new String(ch)); // parameter to String constructor is a char[] array
byteAddress++;
ch[0] = (char) Globals.memory.getByte(byteAddress);
}
}
catch (AddressErrorException e)
{
throw new ProcessingException(statement, e);
}
// update register $a0 with the value from showConfirmDialog.
// showConfirmDialog returns an int with one of three possible values:
// 0 ---> meaning Yes
// 1 ---> meaning No
// 2 ---> meaning Cancel
RegisterFile.updateRegister(4, JOptionPane.showConfirmDialog(null, message) );
// update register $a0 with the value from showConfirmDialog.
// showConfirmDialog returns an int with one of three possible values:
// 0 ---> meaning Yes
// 1 ---> meaning No
// 2 ---> meaning Cancel
RegisterFile.updateRegister(4, JOptionPane.showConfirmDialog(null, message));
}
}
}
}
@@ -1,6 +1,7 @@
package mars.mips.instructions.syscalls;
import mars.util.*;
import mars.*;
package mars.mips.instructions.syscalls;
import mars.ProcessingException;
import mars.ProgramStatement;
/*
Copyright (c) 2003-2006, Pete Sanderson and Kenneth Vollmar
@@ -31,24 +32,25 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
/**
* Service to exit the MIPS program.
*
*/
public class SyscallExit extends AbstractSyscall {
/**
* Build an instance of the Exit syscall. Default service number
* is 10 and name is "Exit".
*/
public SyscallExit() {
super(10, "Exit");
}
/**
* Performs syscall function to exit the MIPS program.
*/
public void simulate(ProgramStatement statement) throws ProcessingException {
throw new ProcessingException(); // empty exception list.
}
}
public class SyscallExit extends AbstractSyscall
{
/**
* Build an instance of the Exit syscall. Default service number is 10 and name is "Exit".
*/
public SyscallExit()
{
super(10, "Exit");
}
/**
* Performs syscall function to exit the MIPS program.
*/
public void simulate(ProgramStatement statement) throws ProcessingException
{
throw new ProcessingException(); // empty exception list.
}
}
@@ -1,7 +1,9 @@
package mars.mips.instructions.syscalls;
import mars.util.*;
import mars.*;
import mars.mips.hardware.*;
package mars.mips.instructions.syscalls;
import mars.Globals;
import mars.ProcessingException;
import mars.ProgramStatement;
import mars.mips.hardware.RegisterFile;
/*
Copyright (c) 2003-2006, Pete Sanderson and Kenneth Vollmar
@@ -32,29 +34,30 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
/**
* Service to exit the MIPS program with return value given in $a0. Ignored if running from GUI.
*
*/
public class SyscallExit2 extends AbstractSyscall {
/**
* Build an instance of the Exit2 syscall. Default service number
* is 17 and name is "Exit2".
*/
public SyscallExit2() {
super(17, "Exit2");
}
/**
* Performs syscall function to exit the MIPS program with return value given in $a0.
* If running in command mode, MARS will exit with that value. If running under GUI,
* return value is ignored.
*/
public void simulate(ProgramStatement statement) throws ProcessingException {
if (Globals.getGui()==null) {
public class SyscallExit2 extends AbstractSyscall
{
/**
* Build an instance of the Exit2 syscall. Default service number is 17 and name is "Exit2".
*/
public SyscallExit2()
{
super(17, "Exit2");
}
/**
* Performs syscall function to exit the MIPS program with return value given in $a0. If running in command mode,
* MARS will exit with that value. If running under GUI, return value is ignored.
*/
public void simulate(ProgramStatement statement) throws ProcessingException
{
if (Globals.getGui() == null)
{
Globals.exitCode = RegisterFile.getValue(4);
}
throw new ProcessingException(); // empty error list
}
}
}
throw new ProcessingException(); // empty error list
}
}
@@ -1,9 +1,15 @@
package mars.mips.instructions.syscalls;
import mars.util.*;
import mars.mips.hardware.*;
import mars.simulator.*;
import mars.*;
import javax.swing.JOptionPane;
package mars.mips.instructions.syscalls;
import mars.Globals;
import mars.ProcessingException;
import mars.ProgramStatement;
import mars.mips.hardware.AddressErrorException;
import mars.mips.hardware.Coprocessor1;
import mars.mips.hardware.InvalidRegisterAccessException;
import mars.mips.hardware.RegisterFile;
import mars.simulator.Exceptions;
import javax.swing.*;
/*
Copyright (c) 2003-2008, Pete Sanderson and Kenneth Vollmar
@@ -35,98 +41,100 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
/**
* Service to input data.
*
*/
public class SyscallInputDialogDouble extends AbstractSyscall {
/**
* Build an instance of the syscall with its default service number and name.
*/
public SyscallInputDialogDouble() {
super(53, "InputDialogDouble");
}
public class SyscallInputDialogDouble extends AbstractSyscall
{
/**
* Build an instance of the syscall with its default service number and name.
*/
public SyscallInputDialogDouble()
{
super(53, "InputDialogDouble");
}
/**
* System call to input data.
*/
public void simulate(ProgramStatement statement) throws ProcessingException {
// Input arguments: $a0 = address of null-terminated string that is the message to user
// Outputs:
// $f0 and $f1 contains value of double read. $f1 contains high order word of the double.
// $a1 contains status value
// 0: valid input data, correctly parsed
// -1: input data cannot be correctly parsed
// -2: Cancel was chosen
// -3: OK was chosen but no data had been input into field
/**
* System call to input data.
*/
public void simulate(ProgramStatement statement) throws ProcessingException
{
// Input arguments: $a0 = address of null-terminated string that is the message to user
// Outputs:
// $f0 and $f1 contains value of double read. $f1 contains high order word of the double.
// $a1 contains status value
// 0: valid input data, correctly parsed
// -1: input data cannot be correctly parsed
// -2: Cancel was chosen
// -3: OK was chosen but no data had been input into field
String message = new String(); // = "";
int byteAddress = RegisterFile.getValue(4);
char ch[] = { ' '}; // Need an array to convert to String
try
{
String message = ""; // = "";
int byteAddress = RegisterFile.getValue(4);
char[] ch = {' '}; // Need an array to convert to String
try
{
ch[0] = (char) Globals.memory.getByte(byteAddress);
while (ch[0] != 0) // only uses single location ch[0]
{
message = message.concat(new String(ch)); // parameter to String constructor is a char[] array
byteAddress++;
ch[0] = (char) Globals.memory.getByte(byteAddress);
message = message.concat(new String(ch)); // parameter to String constructor is a char[] array
byteAddress++;
ch[0] = (char) Globals.memory.getByte(byteAddress);
}
}
catch (AddressErrorException e)
}
catch (AddressErrorException e)
{
throw new ProcessingException(statement, e);
}
// Values returned by Java's InputDialog:
// A null return value means that "Cancel" was chosen rather than OK.
// An empty string returned (that is, inputValue.length() of zero)
// means that OK was chosen but no string was input.
String inputValue = null;
inputValue = JOptionPane.showInputDialog(message);
try
{
Coprocessor1.setRegisterPairToDouble(0, 0.0); // set $f0 to zero
if (inputValue == null) // Cancel was chosen
{
throw new ProcessingException(statement, e);
RegisterFile.updateRegister(5, -2); // set $a1 to -2 flag
}
else if (inputValue.length() == 0) // OK was chosen but there was no input
{
RegisterFile.updateRegister(5, -3); // set $a1 to -3 flag
}
else
{
double doubleValue = Double.parseDouble(inputValue);
// Successful parse of valid input data
Coprocessor1.setRegisterPairToDouble(0, doubleValue); // set $f0 to input data
RegisterFile.updateRegister(5, 0); // set $a1 to valid flag
}
// Values returned by Java's InputDialog:
// A null return value means that "Cancel" was chosen rather than OK.
// An empty string returned (that is, inputValue.length() of zero)
// means that OK was chosen but no string was input.
String inputValue = null;
inputValue = JOptionPane.showInputDialog(message);
try
{
Coprocessor1.setRegisterPairToDouble(0, 0.0); // set $f0 to zero
if (inputValue == null) // Cancel was chosen
{
RegisterFile.updateRegister(5, -2 ); // set $a1 to -2 flag
}
else if (inputValue.length() == 0) // OK was chosen but there was no input
{
RegisterFile.updateRegister(5, -3 ); // set $a1 to -3 flag
}
else
{
double doubleValue = Double.parseDouble(inputValue);
} // end try block
// Successful parse of valid input data
Coprocessor1.setRegisterPairToDouble(0, doubleValue); // set $f0 to input data
RegisterFile.updateRegister(5, 0 ); // set $a1 to valid flag
}
catch (InvalidRegisterAccessException e) // register ID error in this method
{
RegisterFile.updateRegister(5, -1); // set $a1 to -1 flag
throw new ProcessingException(statement,
"invalid int reg. access during double input (syscall " + this.getNumber() + ")",
Exceptions.SYSCALL_EXCEPTION);
}
} // end try block
catch (InvalidRegisterAccessException e) // register ID error in this method
{
RegisterFile.updateRegister(5, -1 ); // set $a1 to -1 flag
throw new ProcessingException(statement,
"invalid int reg. access during double input (syscall "+this.getNumber()+")",
Exceptions.SYSCALL_EXCEPTION);
}
catch ( NumberFormatException e) // Unsuccessful parse of input data
{
RegisterFile.updateRegister(5, -1 ); // set $a1 to -1 flag
catch (NumberFormatException e) // Unsuccessful parse of input data
{
RegisterFile.updateRegister(5, -1); // set $a1 to -1 flag
/* Don't throw exception because returning a status flag
throw new ProcessingException(statement,
"invalid float input (syscall "+this.getNumber()+")",
Exceptions.SYSCALL_EXCEPTION);
*/
}
}
}
}
}
}
@@ -1,9 +1,13 @@
package mars.mips.instructions.syscalls;
import mars.util.*;
import mars.mips.hardware.*;
import mars.simulator.*;
import mars.*;
import javax.swing.JOptionPane;
package mars.mips.instructions.syscalls;
import mars.Globals;
import mars.ProcessingException;
import mars.ProgramStatement;
import mars.mips.hardware.AddressErrorException;
import mars.mips.hardware.Coprocessor1;
import mars.mips.hardware.RegisterFile;
import javax.swing.*;
/*
Copyright (c) 2003-2008, Pete Sanderson and Kenneth Vollmar
@@ -35,86 +39,88 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
/**
* Service to input data.
*
*/
public class SyscallInputDialogFloat extends AbstractSyscall {
/**
* Build an instance of the syscall with its default service number and name.
*/
public SyscallInputDialogFloat() {
super(52, "InputDialogFloat");
}
public class SyscallInputDialogFloat extends AbstractSyscall
{
/**
* Build an instance of the syscall with its default service number and name.
*/
public SyscallInputDialogFloat()
{
super(52, "InputDialogFloat");
}
/**
* System call to input data.
*/
public void simulate(ProgramStatement statement) throws ProcessingException {
// Input arguments: $a0 = address of null-terminated string that is the message to user
// Outputs:
// $f0 contains value of float read
// $a1 contains status value
// 0: valid input data, correctly parsed
// -1: input data cannot be correctly parsed
// -2: Cancel was chosen
// -3: OK was chosen but no data had been input into field
/**
* System call to input data.
*/
public void simulate(ProgramStatement statement) throws ProcessingException
{
// Input arguments: $a0 = address of null-terminated string that is the message to user
// Outputs:
// $f0 contains value of float read
// $a1 contains status value
// 0: valid input data, correctly parsed
// -1: input data cannot be correctly parsed
// -2: Cancel was chosen
// -3: OK was chosen but no data had been input into field
String message = new String(); // = "";
int byteAddress = RegisterFile.getValue(4);
char ch[] = { ' '}; // Need an array to convert to String
try
{
String message = ""; // = "";
int byteAddress = RegisterFile.getValue(4);
char[] ch = {' '}; // Need an array to convert to String
try
{
ch[0] = (char) Globals.memory.getByte(byteAddress);
while (ch[0] != 0) // only uses single location ch[0]
{
message = message.concat(new String(ch)); // parameter to String constructor is a char[] array
byteAddress++;
ch[0] = (char) Globals.memory.getByte(byteAddress);
message = message.concat(new String(ch)); // parameter to String constructor is a char[] array
byteAddress++;
ch[0] = (char) Globals.memory.getByte(byteAddress);
}
}
catch (AddressErrorException e)
}
catch (AddressErrorException e)
{
throw new ProcessingException(statement, e);
}
// Values returned by Java's InputDialog:
// A null return value means that "Cancel" was chosen rather than OK.
// An empty string returned (that is, inputValue.length() of zero)
// means that OK was chosen but no string was input.
String inputValue = null;
inputValue = JOptionPane.showInputDialog(message);
try
{
Coprocessor1.setRegisterToFloat(0, (float) 0.0); // set $f0 to zero
if (inputValue == null) // Cancel was chosen
{
throw new ProcessingException(statement, e);
RegisterFile.updateRegister(5, -2); // set $a1 to -2 flag
}
else if (inputValue.length() == 0) // OK was chosen but there was no input
{
RegisterFile.updateRegister(5, -3); // set $a1 to -3 flag
}
else
{
float floatValue = Float.parseFloat(inputValue);
//System.out.println("SyscallInputDialogFloat: floatValue is " + floatValue);
// Successful parse of valid input data
Coprocessor1.setRegisterToFloat(0, floatValue); // set $f0 to input data
RegisterFile.updateRegister(5, 0); // set $a1 to valid flag
}
// Values returned by Java's InputDialog:
// A null return value means that "Cancel" was chosen rather than OK.
// An empty string returned (that is, inputValue.length() of zero)
// means that OK was chosen but no string was input.
String inputValue = null;
inputValue = JOptionPane.showInputDialog(message);
try
{
Coprocessor1.setRegisterToFloat(0, (float)0.0); // set $f0 to zero
if (inputValue == null) // Cancel was chosen
{
RegisterFile.updateRegister(5, -2 ); // set $a1 to -2 flag
}
else if (inputValue.length() == 0) // OK was chosen but there was no input
{
RegisterFile.updateRegister(5, -3 ); // set $a1 to -3 flag
}
else
{
float floatValue = Float.parseFloat(inputValue);
//System.out.println("SyscallInputDialogFloat: floatValue is " + floatValue);
// Successful parse of valid input data
Coprocessor1.setRegisterToFloat(0, floatValue); // set $f0 to input data
RegisterFile.updateRegister(5, 0 ); // set $a1 to valid flag
}
} // end try block
} // end try block
catch ( NumberFormatException e) // Unsuccessful parse of input data
{
RegisterFile.updateRegister(5, -1 ); // set $a1 to -1 flag
catch (NumberFormatException e) // Unsuccessful parse of input data
{
RegisterFile.updateRegister(5, -1); // set $a1 to -1 flag
/* Don't throw exception because returning a status flag
throw new ProcessingException(statement,
@@ -122,9 +128,9 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Exceptions.SYSCALL_EXCEPTION);
*/
}
}
}
}
}
}
@@ -1,9 +1,12 @@
package mars.mips.instructions.syscalls;
import mars.util.*;
import mars.mips.hardware.*;
import mars.simulator.*;
import mars.*;
import javax.swing.JOptionPane;
package mars.mips.instructions.syscalls;
import mars.Globals;
import mars.ProcessingException;
import mars.ProgramStatement;
import mars.mips.hardware.AddressErrorException;
import mars.mips.hardware.RegisterFile;
import javax.swing.*;
/*
Copyright (c) 2003-2008, Pete Sanderson and Kenneth Vollmar
@@ -35,85 +38,87 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
/**
* Service to input data.
*
*/
public class SyscallInputDialogInt extends AbstractSyscall {
/**
* Build an instance of the syscall with its default service number and name.
*/
public SyscallInputDialogInt() {
super(51, "InputDialogInt");
}
public class SyscallInputDialogInt extends AbstractSyscall
{
/**
* Build an instance of the syscall with its default service number and name.
*/
public SyscallInputDialogInt()
{
super(51, "InputDialogInt");
}
/**
* System call to input data.
*/
public void simulate(ProgramStatement statement) throws ProcessingException {
// Input arguments: $a0 = address of null-terminated string that is the message to user
// Outputs:
// $a0 contains value of int read
// $a1 contains status value
// 0: valid input data, correctly parsed
// -1: input data cannot be correctly parsed
// -2: Cancel was chosen
// -3: OK was chosen but no data had been input into field
/**
* System call to input data.
*/
public void simulate(ProgramStatement statement) throws ProcessingException
{
// Input arguments: $a0 = address of null-terminated string that is the message to user
// Outputs:
// $a0 contains value of int read
// $a1 contains status value
// 0: valid input data, correctly parsed
// -1: input data cannot be correctly parsed
// -2: Cancel was chosen
// -3: OK was chosen but no data had been input into field
String message = new String(); // = "";
int byteAddress = RegisterFile.getValue(4);
char ch[] = { ' '}; // Need an array to convert to String
try
{
String message = ""; // = "";
int byteAddress = RegisterFile.getValue(4);
char[] ch = {' '}; // Need an array to convert to String
try
{
ch[0] = (char) Globals.memory.getByte(byteAddress);
while (ch[0] != 0) // only uses single location ch[0]
{
message = message.concat(new String(ch)); // parameter to String constructor is a char[] array
byteAddress++;
ch[0] = (char) Globals.memory.getByte(byteAddress);
message = message.concat(new String(ch)); // parameter to String constructor is a char[] array
byteAddress++;
ch[0] = (char) Globals.memory.getByte(byteAddress);
}
}
catch (AddressErrorException e)
}
catch (AddressErrorException e)
{
throw new ProcessingException(statement, e);
}
// Values returned by Java's InputDialog:
// A null return value means that "Cancel" was chosen rather than OK.
// An empty string returned (that is, inputValue.length() of zero)
// means that OK was chosen but no string was input.
String inputValue = null;
inputValue = JOptionPane.showInputDialog(message);
if (inputValue == null) // Cancel was chosen
{
RegisterFile.updateRegister(4, 0); // set $a0 to zero
RegisterFile.updateRegister(5, -2); // set $a1 to -2 flag
}
else if (inputValue.length() == 0) // OK was chosen but there was no input
{
RegisterFile.updateRegister(4, 0); // set $a0 to zero
RegisterFile.updateRegister(5, -3); // set $a1 to -3 flag
}
else
{
try
{
throw new ProcessingException(statement, e);
int i = Integer.parseInt(inputValue);
// Successful parse of valid input data
RegisterFile.updateRegister(4, i); // set $a0 to the data read
RegisterFile.updateRegister(5, 0); // set $a1 to valid flag
}
catch (NumberFormatException e)
{
// Unsuccessful parse of input data
RegisterFile.updateRegister(4, 0); // set $a0 to zero
RegisterFile.updateRegister(5, -1); // set $a1 to -1 flag
}
// Values returned by Java's InputDialog:
// A null return value means that "Cancel" was chosen rather than OK.
// An empty string returned (that is, inputValue.length() of zero)
// means that OK was chosen but no string was input.
String inputValue = null;
inputValue = JOptionPane.showInputDialog(message);
if (inputValue == null) // Cancel was chosen
{
RegisterFile.updateRegister(4, 0 ); // set $a0 to zero
RegisterFile.updateRegister(5, -2 ); // set $a1 to -2 flag
}
else if (inputValue.length() == 0) // OK was chosen but there was no input
{
RegisterFile.updateRegister(4, 0 ); // set $a0 to zero
RegisterFile.updateRegister(5, -3 ); // set $a1 to -3 flag
}
else
{
try
{
int i = Integer.parseInt(inputValue);
// Successful parse of valid input data
RegisterFile.updateRegister(4, i ); // set $a0 to the data read
RegisterFile.updateRegister(5, 0 ); // set $a1 to valid flag
}
catch ( NumberFormatException e)
{
// Unsuccessful parse of input data
RegisterFile.updateRegister(4, 0 ); // set $a0 to zero
RegisterFile.updateRegister(5, -1 ); // set $a1 to -1 flag
} // end else
}
} // end else
}
}
}
}
@@ -1,9 +1,12 @@
package mars.mips.instructions.syscalls;
import mars.util.*;
import mars.mips.hardware.*;
import mars.simulator.*;
import mars.*;
import javax.swing.JOptionPane;
package mars.mips.instructions.syscalls;
import mars.Globals;
import mars.ProcessingException;
import mars.ProgramStatement;
import mars.mips.hardware.AddressErrorException;
import mars.mips.hardware.RegisterFile;
import javax.swing.*;
/*
Copyright (c) 2003-2008, Pete Sanderson and Kenneth Vollmar
@@ -35,103 +38,105 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
/**
* Service to input data.
*
*/
public class SyscallInputDialogString extends AbstractSyscall {
/**
* Build an instance of the syscall with its default service number and name.
*/
public SyscallInputDialogString() {
super(54, "InputDialogString");
}
/**
* System call to input data.
*/
public void simulate(ProgramStatement statement) throws ProcessingException {
// Input arguments:
// $a0 = address of null-terminated string that is the message to user
// $a1 = address of input buffer for the input string
// $a2 = maximum number of characters to read
// Outputs:
// $a1 contains status value
// 0: valid input data, correctly parsed
// -1: input data cannot be correctly parsed
// -2: Cancel was chosen
// -3: OK was chosen but no data had been input into field
String message = new String(); // = "";
int byteAddress = RegisterFile.getValue(4); // byteAddress of string is in $a0
char ch[] = { ' '}; // Need an array to convert to String
try
{
public class SyscallInputDialogString extends AbstractSyscall
{
/**
* Build an instance of the syscall with its default service number and name.
*/
public SyscallInputDialogString()
{
super(54, "InputDialogString");
}
/**
* System call to input data.
*/
public void simulate(ProgramStatement statement) throws ProcessingException
{
// Input arguments:
// $a0 = address of null-terminated string that is the message to user
// $a1 = address of input buffer for the input string
// $a2 = maximum number of characters to read
// Outputs:
// $a1 contains status value
// 0: valid input data, correctly parsed
// -1: input data cannot be correctly parsed
// -2: Cancel was chosen
// -3: OK was chosen but no data had been input into field
String message = ""; // = "";
int byteAddress = RegisterFile.getValue(4); // byteAddress of string is in $a0
char[] ch = {' '}; // Need an array to convert to String
try
{
ch[0] = (char) Globals.memory.getByte(byteAddress);
while (ch[0] != 0) // only uses single location ch[0]
{
message = message.concat(new String(ch)); // parameter to String constructor is a char[] array
byteAddress++;
ch[0] = (char) Globals.memory.getByte(byteAddress);
message = message.concat(new String(ch)); // parameter to String constructor is a char[] array
byteAddress++;
ch[0] = (char) Globals.memory.getByte(byteAddress);
}
}
catch (AddressErrorException e)
{
throw new ProcessingException(statement, e);
}
// Values returned by Java's InputDialog:
// A null return value means that "Cancel" was chosen rather than OK.
// An empty string returned (that is, inputString.length() of zero)
// means that OK was chosen but no string was input.
String inputString = null;
inputString = JOptionPane.showInputDialog(message);
byteAddress = RegisterFile.getValue(5); // byteAddress of string is in $a1
int maxLength = RegisterFile.getValue(6); // input buffer size for input string is in $a2
try
{
}
catch (AddressErrorException e)
{
throw new ProcessingException(statement, e);
}
// Values returned by Java's InputDialog:
// A null return value means that "Cancel" was chosen rather than OK.
// An empty string returned (that is, inputString.length() of zero)
// means that OK was chosen but no string was input.
String inputString = null;
inputString = JOptionPane.showInputDialog(message);
byteAddress = RegisterFile.getValue(5); // byteAddress of string is in $a1
int maxLength = RegisterFile.getValue(6); // input buffer size for input string is in $a2
try
{
if (inputString == null) // Cancel was chosen
{
RegisterFile.updateRegister(5, -2 ); // set $a1 to -2 flag
RegisterFile.updateRegister(5, -2); // set $a1 to -2 flag
}
else if (inputString.length() == 0) // OK was chosen but there was no input
{
RegisterFile.updateRegister(5, -3 ); // set $a1 to -3 flag
RegisterFile.updateRegister(5, -3); // set $a1 to -3 flag
}
else
{
// The buffer will contain characters, a '\n' character, and the null character
// Copy the input data to buffer as space permits
for (int index = 0; (index < inputString.length()) && (index < maxLength - 1); index++)
{
Globals.memory.setByte(byteAddress + index,
inputString.charAt(index));
}
if (inputString.length() < maxLength-1)
{
Globals.memory.setByte(byteAddress + (int)Math.min(inputString.length(), maxLength-2), '\n'); // newline at string end
}
Globals.memory.setByte(byteAddress + (int)Math.min((inputString.length()+1), maxLength-1), 0); // null char to end string
if (inputString.length() > maxLength - 1)
{
// The buffer will contain characters, a '\n' character, and the null character
// Copy the input data to buffer as space permits
for (int index = 0; (index < inputString.length()) && (index < maxLength - 1); index++)
{
Globals.memory.setByte(byteAddress + index,
inputString.charAt(index));
}
if (inputString.length() < maxLength - 1)
{
Globals.memory.setByte(byteAddress + Math.min(inputString.length(), maxLength - 2), '\n'); // newline at string end
}
Globals.memory.setByte(byteAddress + Math.min((inputString.length() + 1), maxLength - 1), 0); // null char to end string
if (inputString.length() > maxLength - 1)
{
// length of the input string exceeded the specified maximum
RegisterFile.updateRegister(5, -4 ); // set $a1 to -4 flag
}
else
{
RegisterFile.updateRegister(5, 0 ); // set $a1 to 0 flag
}
RegisterFile.updateRegister(5, -4); // set $a1 to -4 flag
}
else
{
RegisterFile.updateRegister(5, 0); // set $a1 to 0 flag
}
} // end else
} // end try
catch (AddressErrorException e)
{
throw new ProcessingException(statement, e);
}
}
}
} // end try
catch (AddressErrorException e)
{
throw new ProcessingException(statement, e);
}
}
}
@@ -1,9 +1,12 @@
package mars.mips.instructions.syscalls;
import mars.util.*;
import mars.mips.hardware.*;
import mars.simulator.*;
import mars.*;
import javax.swing.JOptionPane;
package mars.mips.instructions.syscalls;
import mars.Globals;
import mars.ProcessingException;
import mars.ProgramStatement;
import mars.mips.hardware.AddressErrorException;
import mars.mips.hardware.RegisterFile;
import javax.swing.*;
/*
Copyright (c) 2003-2008, Pete Sanderson and Kenneth Vollmar
@@ -35,56 +38,61 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
/**
* Service to display a message to user.
*
*/
public class SyscallMessageDialog extends AbstractSyscall {
/**
* Build an instance of the syscall with its default service number and name.
*/
public SyscallMessageDialog() {
super(55, "MessageDialog");
}
public class SyscallMessageDialog extends AbstractSyscall
{
/**
* Build an instance of the syscall with its default service number and name.
*/
public SyscallMessageDialog()
{
super(55, "MessageDialog");
}
/**
* System call to display a message to user.
*/
public void simulate(ProgramStatement statement) throws ProcessingException {
// Input arguments:
// $a0 = address of null-terminated string that is the message to user
// $a1 = the type of the message to the user, which is one of:
// 1: error message
// 2: information message
// 3: warning message
// 4: question message
// other: plain message
// Output: none
/**
* System call to display a message to user.
*/
public void simulate(ProgramStatement statement) throws ProcessingException
{
// Input arguments:
// $a0 = address of null-terminated string that is the message to user
// $a1 = the type of the message to the user, which is one of:
// 1: error message
// 2: information message
// 3: warning message
// 4: question message
// other: plain message
// Output: none
String message = new String(); // = "";
int byteAddress = RegisterFile.getValue(4);
char ch[] = { ' '}; // Need an array to convert to String
try
{
String message = ""; // = "";
int byteAddress = RegisterFile.getValue(4);
char[] ch = {' '}; // Need an array to convert to String
try
{
ch[0] = (char) Globals.memory.getByte(byteAddress);
while (ch[0] != 0) // only uses single location ch[0]
{
message = message.concat(new String(ch)); // parameter to String constructor is a char[] array
byteAddress++;
ch[0] = (char) Globals.memory.getByte(byteAddress);
}
}
catch (AddressErrorException e)
{
throw new ProcessingException(statement, e);
message = message.concat(new String(ch)); // parameter to String constructor is a char[] array
byteAddress++;
ch[0] = (char) Globals.memory.getByte(byteAddress);
}
}
catch (AddressErrorException e)
{
throw new ProcessingException(statement, e);
}
// Display the dialog.
int msgType = RegisterFile.getValue(5);
if (msgType < 0 || msgType > 3) msgType = -1; // See values in http://java.sun.com/j2se/1.5.0/docs/api/constant-values.html
JOptionPane.showMessageDialog(null, message, null, msgType );
// Display the dialog.
int msgType = RegisterFile.getValue(5);
if (msgType < 0 || msgType > 3)
{
msgType = -1; // See values in http://java.sun.com/j2se/1.5.0/docs/api/constant-values.html
}
JOptionPane.showMessageDialog(null, message, null, msgType);
}
}
}
}
@@ -1,9 +1,15 @@
package mars.mips.instructions.syscalls;
import mars.util.*;
import mars.mips.hardware.*;
import mars.simulator.*;
import mars.*;
import javax.swing.JOptionPane;
package mars.mips.instructions.syscalls;
import mars.Globals;
import mars.ProcessingException;
import mars.ProgramStatement;
import mars.mips.hardware.AddressErrorException;
import mars.mips.hardware.Coprocessor1;
import mars.mips.hardware.InvalidRegisterAccessException;
import mars.mips.hardware.RegisterFile;
import mars.simulator.Exceptions;
import javax.swing.*;
/*
Copyright (c) 2003-2008, Pete Sanderson and Kenneth Vollmar
@@ -35,62 +41,64 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
/**
* Service to display a message to user.
*
*/
public class SyscallMessageDialogDouble extends AbstractSyscall {
/**
* Build an instance of the syscall with its default service number and name.
*/
public SyscallMessageDialogDouble() {
super(58, "MessageDialogDouble");
}
public class SyscallMessageDialogDouble extends AbstractSyscall
{
/**
* Build an instance of the syscall with its default service number and name.
*/
public SyscallMessageDialogDouble()
{
super(58, "MessageDialogDouble");
}
/**
* System call to display a message to user.
*/
public void simulate(ProgramStatement statement) throws ProcessingException {
// Input arguments:
// $a0 = address of null-terminated string that is an information-type message to user
// $f12 = double value to display in string form after the first message
// Output: none
/**
* System call to display a message to user.
*/
public void simulate(ProgramStatement statement) throws ProcessingException
{
// Input arguments:
// $a0 = address of null-terminated string that is an information-type message to user
// $f12 = double value to display in string form after the first message
// Output: none
String message = new String(); // = "";
int byteAddress = RegisterFile.getValue(4);
char ch[] = { ' '}; // Need an array to convert to String
try
{
String message = ""; // = "";
int byteAddress = RegisterFile.getValue(4);
char[] ch = {' '}; // Need an array to convert to String
try
{
ch[0] = (char) Globals.memory.getByte(byteAddress);
while (ch[0] != 0) // only uses single location ch[0]
{
message = message.concat(new String(ch)); // parameter to String constructor is a char[] array
byteAddress++;
ch[0] = (char) Globals.memory.getByte(byteAddress);
}
}
catch (AddressErrorException e)
{
throw new ProcessingException(statement, e);
message = message.concat(new String(ch)); // parameter to String constructor is a char[] array
byteAddress++;
ch[0] = (char) Globals.memory.getByte(byteAddress);
}
}
catch (AddressErrorException e)
{
throw new ProcessingException(statement, e);
}
// Display the dialog.
try
{
// Display the dialog.
try
{
JOptionPane.showMessageDialog(null,
message + Double.toString( Coprocessor1.getDoubleFromRegisterPair("$f12") ),
null,
JOptionPane.INFORMATION_MESSAGE );
}
catch (InvalidRegisterAccessException e) // register ID error in this method
{
RegisterFile.updateRegister(5, -1 ); // set $a1 to -1 flag
throw new ProcessingException(statement,
"invalid int reg. access during double input (syscall "+this.getNumber()+")",
Exceptions.SYSCALL_EXCEPTION);
}
message + Coprocessor1.getDoubleFromRegisterPair("$f12"),
null,
JOptionPane.INFORMATION_MESSAGE);
}
}
catch (InvalidRegisterAccessException e) // register ID error in this method
{
RegisterFile.updateRegister(5, -1); // set $a1 to -1 flag
throw new ProcessingException(statement,
"invalid int reg. access during double input (syscall " + this.getNumber() + ")",
Exceptions.SYSCALL_EXCEPTION);
}
}
}
}
@@ -1,9 +1,13 @@
package mars.mips.instructions.syscalls;
import mars.util.*;
import mars.mips.hardware.*;
import mars.simulator.*;
import mars.*;
import javax.swing.JOptionPane;
package mars.mips.instructions.syscalls;
import mars.Globals;
import mars.ProcessingException;
import mars.ProgramStatement;
import mars.mips.hardware.AddressErrorException;
import mars.mips.hardware.Coprocessor1;
import mars.mips.hardware.RegisterFile;
import javax.swing.*;
/*
Copyright (c) 2003-2008, Pete Sanderson and Kenneth Vollmar
@@ -35,52 +39,54 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
/**
* Service to display a message to user.
*
*/
public class SyscallMessageDialogFloat extends AbstractSyscall {
/**
* Build an instance of the syscall with its default service number and name.
*/
public SyscallMessageDialogFloat() {
super(57, "MessageDialogFloat");
}
public class SyscallMessageDialogFloat extends AbstractSyscall
{
/**
* Build an instance of the syscall with its default service number and name.
*/
public SyscallMessageDialogFloat()
{
super(57, "MessageDialogFloat");
}
/**
* System call to display a message to user.
*/
public void simulate(ProgramStatement statement) throws ProcessingException {
// Input arguments:
// $a0 = address of null-terminated string that is an information-type message to user
// $f12 = float value to display in string form after the first message
// Output: none
/**
* System call to display a message to user.
*/
public void simulate(ProgramStatement statement) throws ProcessingException
{
// Input arguments:
// $a0 = address of null-terminated string that is an information-type message to user
// $f12 = float value to display in string form after the first message
// Output: none
String message = new String(); // = "";
int byteAddress = RegisterFile.getValue(4);
char ch[] = { ' '}; // Need an array to convert to String
try
{
String message = ""; // = "";
int byteAddress = RegisterFile.getValue(4);
char[] ch = {' '}; // Need an array to convert to String
try
{
ch[0] = (char) Globals.memory.getByte(byteAddress);
while (ch[0] != 0) // only uses single location ch[0]
{
message = message.concat(new String(ch)); // parameter to String constructor is a char[] array
byteAddress++;
ch[0] = (char) Globals.memory.getByte(byteAddress);
}
}
catch (AddressErrorException e)
{
throw new ProcessingException(statement, e);
message = message.concat(new String(ch)); // parameter to String constructor is a char[] array
byteAddress++;
ch[0] = (char) Globals.memory.getByte(byteAddress);
}
}
catch (AddressErrorException e)
{
throw new ProcessingException(statement, e);
}
// Display the dialog.
JOptionPane.showMessageDialog(null,
message + Float.toString( Coprocessor1.getFloatFromRegister("$f12") ),
null,
JOptionPane.INFORMATION_MESSAGE );
// Display the dialog.
JOptionPane.showMessageDialog(null,
message + Coprocessor1.getFloatFromRegister("$f12"),
null,
JOptionPane.INFORMATION_MESSAGE);
}
}
}
}
@@ -1,9 +1,12 @@
package mars.mips.instructions.syscalls;
import mars.util.*;
import mars.mips.hardware.*;
import mars.simulator.*;
import mars.*;
import javax.swing.JOptionPane;
package mars.mips.instructions.syscalls;
import mars.Globals;
import mars.ProcessingException;
import mars.ProgramStatement;
import mars.mips.hardware.AddressErrorException;
import mars.mips.hardware.RegisterFile;
import javax.swing.*;
/*
Copyright (c) 2003-2008, Pete Sanderson and Kenneth Vollmar
@@ -35,52 +38,54 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
/**
* Service to display a message to user.
*
*/
public class SyscallMessageDialogInt extends AbstractSyscall {
/**
* Build an instance of the syscall with its default service number and name.
*/
public SyscallMessageDialogInt() {
super(56, "MessageDialogInt");
}
public class SyscallMessageDialogInt extends AbstractSyscall
{
/**
* Build an instance of the syscall with its default service number and name.
*/
public SyscallMessageDialogInt()
{
super(56, "MessageDialogInt");
}
/**
* System call to display a message to user.
*/
public void simulate(ProgramStatement statement) throws ProcessingException {
// Input arguments:
// $a0 = address of null-terminated string that is an information-type message to user
// $a1 = int value to display in string form after the first message
// Output: none
/**
* System call to display a message to user.
*/
public void simulate(ProgramStatement statement) throws ProcessingException
{
// Input arguments:
// $a0 = address of null-terminated string that is an information-type message to user
// $a1 = int value to display in string form after the first message
// Output: none
String message = new String(); // = "";
int byteAddress = RegisterFile.getValue(4);
char ch[] = { ' '}; // Need an array to convert to String
try
{
String message = ""; // = "";
int byteAddress = RegisterFile.getValue(4);
char[] ch = {' '}; // Need an array to convert to String
try
{
ch[0] = (char) Globals.memory.getByte(byteAddress);
while (ch[0] != 0) // only uses single location ch[0]
{
message = message.concat(new String(ch)); // parameter to String constructor is a char[] array
byteAddress++;
ch[0] = (char) Globals.memory.getByte(byteAddress);
}
}
catch (AddressErrorException e)
{
throw new ProcessingException(statement, e);
message = message.concat(new String(ch)); // parameter to String constructor is a char[] array
byteAddress++;
ch[0] = (char) Globals.memory.getByte(byteAddress);
}
}
catch (AddressErrorException e)
{
throw new ProcessingException(statement, e);
}
// Display the dialog.
JOptionPane.showMessageDialog(null,
message + Integer.toString(RegisterFile.getValue(5)),
null,
JOptionPane.INFORMATION_MESSAGE );
// Display the dialog.
JOptionPane.showMessageDialog(null,
message + RegisterFile.getValue(5),
null,
JOptionPane.INFORMATION_MESSAGE);
}
}
}
}
@@ -1,9 +1,12 @@
package mars.mips.instructions.syscalls;
import mars.util.*;
import mars.mips.hardware.*;
import mars.simulator.*;
import mars.*;
import javax.swing.JOptionPane;
package mars.mips.instructions.syscalls;
import mars.Globals;
import mars.ProcessingException;
import mars.ProgramStatement;
import mars.mips.hardware.AddressErrorException;
import mars.mips.hardware.RegisterFile;
import javax.swing.*;
/*
Copyright (c) 2003-2008, Pete Sanderson and Kenneth Vollmar
@@ -35,70 +38,72 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
/**
* Service to display a message to user.
*
*/
public class SyscallMessageDialogString extends AbstractSyscall {
/**
* Build an instance of the syscall with its default service number and name.
*/
public SyscallMessageDialogString() {
super(59, "MessageDialogString");
}
public class SyscallMessageDialogString extends AbstractSyscall
{
/**
* Build an instance of the syscall with its default service number and name.
*/
public SyscallMessageDialogString()
{
super(59, "MessageDialogString");
}
/**
* System call to display a message to user.
*/
public void simulate(ProgramStatement statement) throws ProcessingException {
// Input arguments:
// $a0 = address of null-terminated string that is an information-type message to user
// $a1 = address of null-terminated string to display after the first message
// Output: none
/**
* System call to display a message to user.
*/
public void simulate(ProgramStatement statement) throws ProcessingException
{
// Input arguments:
// $a0 = address of null-terminated string that is an information-type message to user
// $a1 = address of null-terminated string to display after the first message
// Output: none
String message = new String(); // = "";
int byteAddress = RegisterFile.getValue(4);
char ch[] = { ' '}; // Need an array to convert to String
try
{
String message = ""; // = "";
int byteAddress = RegisterFile.getValue(4);
char[] ch = {' '}; // Need an array to convert to String
try
{
ch[0] = (char) Globals.memory.getByte(byteAddress);
while (ch[0] != 0) // only uses single location ch[0]
{
message = message.concat(new String(ch)); // parameter to String constructor is a char[] array
byteAddress++;
ch[0] = (char) Globals.memory.getByte(byteAddress);
}
}
catch (AddressErrorException e)
{
throw new ProcessingException(statement, e);
message = message.concat(new String(ch)); // parameter to String constructor is a char[] array
byteAddress++;
ch[0] = (char) Globals.memory.getByte(byteAddress);
}
}
catch (AddressErrorException e)
{
throw new ProcessingException(statement, e);
}
String message2 = new String(); // = "";
byteAddress = RegisterFile.getValue(5);
try
{
String message2 = ""; // = "";
byteAddress = RegisterFile.getValue(5);
try
{
ch[0] = (char) Globals.memory.getByte(byteAddress);
while (ch[0] != 0) // only uses single location ch[0]
{
message2 = message2.concat(new String(ch)); // parameter to String constructor is a char[] array
byteAddress++;
ch[0] = (char) Globals.memory.getByte(byteAddress);
}
}
catch (AddressErrorException e)
{
throw new ProcessingException(statement, e);
message2 = message2.concat(new String(ch)); // parameter to String constructor is a char[] array
byteAddress++;
ch[0] = (char) Globals.memory.getByte(byteAddress);
}
}
catch (AddressErrorException e)
{
throw new ProcessingException(statement, e);
}
// Display the dialog.
JOptionPane.showMessageDialog(null,
message + message2,
null,
JOptionPane.INFORMATION_MESSAGE );
// Display the dialog.
JOptionPane.showMessageDialog(null,
message + message2,
null,
JOptionPane.INFORMATION_MESSAGE);
}
}
}
}
@@ -1,9 +1,8 @@
package mars.mips.instructions.syscalls;
import mars.util.*;
import mars.mips.hardware.*;
import mars.simulator.*;
import mars.*;
package mars.mips.instructions.syscalls;
import mars.ProcessingException;
import mars.ProgramStatement;
import mars.mips.hardware.RegisterFile;
/*
@@ -35,49 +34,59 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* Service to output simulated MIDI tone to sound card. The call returns
* immediately upon generating the tone. By contrast, syscall 33
* (MidiOutSync) does not return until tone duration has elapsed.
* Service to output simulated MIDI tone to sound card. The call returns immediately upon generating the tone. By
* contrast, syscall 33 (MidiOutSync) does not return until tone duration has elapsed.
*/
public class SyscallMidiOut extends AbstractSyscall {
public class SyscallMidiOut extends AbstractSyscall
{
// Endpoints of ranges for the three "byte" parameters. The duration
// parameter is limited at the high end only by the int range.
static final int rangeLowEnd = 0;
static final int rangeHighEnd = 127;
/**
* Build an instance of the MIDI (simulated) out syscall. Default service number
* is 31 and name is "MidiOut".
*/
public SyscallMidiOut() {
super(31, "MidiOut");
}
/**
* Performs syscall function to send MIDI output to sound card. This requires
* four arguments in registers $a0 through $a3.<br>
* $a0 - pitch (note). Integer value from 0 to 127, with 60 being middle-C on a piano.<br>
* $a1 - duration. Integer value in milliseconds.<br>
* $a2 - instrument. Integer value from 0 to 127, with 0 being acoustic grand piano.<br>
* $a3 - volume. Integer value from 0 to 127.<br>
* Default values, in case any parameters are outside the above ranges, are $a0=60, $a1=1000,
* $a2=0, $a3=100.<br>
* See MARS documentation elsewhere or www.midi.org for more information. Note that the pitch,
* instrument and volume value ranges 0-127 are from javax.sound.midi; actual MIDI instruments
* use the range 1-128.
*/
public void simulate(ProgramStatement statement) throws ProcessingException {
int pitch = RegisterFile.getValue(4); // $a0
int duration = RegisterFile.getValue(5); // $a1
int instrument = RegisterFile.getValue(6); // $a2
int volume = RegisterFile.getValue(7); // $a3
if (pitch < rangeLowEnd || pitch > rangeHighEnd) pitch = ToneGenerator.DEFAULT_PITCH;
if (duration < 0) duration = ToneGenerator.DEFAULT_DURATION;
if (instrument < rangeLowEnd || instrument > rangeHighEnd) instrument = ToneGenerator.DEFAULT_INSTRUMENT;
if (volume < rangeLowEnd || volume > rangeHighEnd) volume = ToneGenerator.DEFAULT_VOLUME;
new ToneGenerator().generateTone( (byte) pitch, duration, (byte) instrument, (byte) volume);
}
static final int rangeLowEnd = 0;
}
static final int rangeHighEnd = 127;
/**
* Build an instance of the MIDI (simulated) out syscall. Default service number is 31 and name is "MidiOut".
*/
public SyscallMidiOut()
{
super(31, "MidiOut");
}
/**
* Performs syscall function to send MIDI output to sound card. This requires four arguments in registers $a0
* through $a3.<br> $a0 - pitch (note). Integer value from 0 to 127, with 60 being middle-C on a piano.<br> $a1 -
* duration. Integer value in milliseconds.<br> $a2 - instrument. Integer value from 0 to 127, with 0 being
* acoustic grand piano.<br> $a3 - volume. Integer value from 0 to 127.<br> Default values, in case any parameters
* are outside the above ranges, are $a0=60, $a1=1000, $a2=0, $a3=100.<br> See MARS documentation elsewhere or
* www.midi.org for more information. Note that the pitch, instrument and volume value ranges 0-127 are from
* javax.sound.midi; actual MIDI instruments use the range 1-128.
*/
public void simulate(ProgramStatement statement) throws ProcessingException
{
int pitch = RegisterFile.getValue(4); // $a0
int duration = RegisterFile.getValue(5); // $a1
int instrument = RegisterFile.getValue(6); // $a2
int volume = RegisterFile.getValue(7); // $a3
if (pitch < rangeLowEnd || pitch > rangeHighEnd)
{
pitch = ToneGenerator.DEFAULT_PITCH;
}
if (duration < 0)
{
duration = ToneGenerator.DEFAULT_DURATION;
}
if (instrument < rangeLowEnd || instrument > rangeHighEnd)
{
instrument = ToneGenerator.DEFAULT_INSTRUMENT;
}
if (volume < rangeLowEnd || volume > rangeHighEnd)
{
volume = ToneGenerator.DEFAULT_VOLUME;
}
new ToneGenerator().generateTone((byte) pitch, duration, (byte) instrument, (byte) volume);
}
}
@@ -1,9 +1,8 @@
package mars.mips.instructions.syscalls;
import mars.util.*;
import mars.mips.hardware.*;
import mars.simulator.*;
import mars.*;
package mars.mips.instructions.syscalls;
import mars.ProcessingException;
import mars.ProgramStatement;
import mars.mips.hardware.RegisterFile;
/*
Copyright (c) 2003-2007, Pete Sanderson and Kenneth Vollmar
@@ -43,53 +42,62 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* Service to output simulated MIDI tone to sound card. The call does
* not return until the tone duration has elapsed. By contrast, syscall 31
* (MidiOut) returns immediately upon generating the tone.
*
/**
* Service to output simulated MIDI tone to sound card. The call does not return until the tone duration has elapsed.
* By contrast, syscall 31 (MidiOut) returns immediately upon generating the tone.
*/
public class SyscallMidiOutSync extends AbstractSyscall {
public class SyscallMidiOutSync extends AbstractSyscall
{
// Endpoints of ranges for the three "byte" parameters. The duration
// parameter is limited at the high end only by the int range.
static final int rangeLowEnd = 0;
static final int rangeHighEnd = 127;
/**
* Build an instance of the MIDI (simulated) out syscall. Default service number
* is 33 and name is "MidiOutSync".
*/
public SyscallMidiOutSync() {
super(33, "MidiOutSync");
}
/**
* Performs syscall function to send MIDI output to sound card. The syscall does not
* return until after the duration period ($a1) has elapsed. This requires
* four arguments in registers $a0 through $a3.<br>
* $a0 - pitch (note). Integer value from 0 to 127, with 60 being middle-C on a piano.<br>
* $a1 - duration. Integer value in milliseconds.<br>
* $a2 - instrument. Integer value from 0 to 127, with 0 being acoustic grand piano.<br>
* $a3 - volume. Integer value from 0 to 127.<br>
* Default values, in case any parameters are outside the above ranges, are $a0=60, $a1=1000,
* $a2=0, $a3=100.<br>
* See MARS documentation elsewhere or www.midi.org for more information. Note that the pitch,
* instrument and volume value ranges 0-127 are from javax.sound.midi; actual MIDI instruments
* use the range 1-128.
*/
public void simulate(ProgramStatement statement) throws ProcessingException {
int pitch = RegisterFile.getValue(4); // $a0
int duration = RegisterFile.getValue(5); // $a1
int instrument = RegisterFile.getValue(6); // $a2
int volume = RegisterFile.getValue(7); // $a3
if (pitch < rangeLowEnd || pitch > rangeHighEnd) pitch = ToneGenerator.DEFAULT_PITCH;
if (duration < 0) duration = ToneGenerator.DEFAULT_DURATION;
if (instrument < rangeLowEnd || instrument > rangeHighEnd) instrument = ToneGenerator.DEFAULT_INSTRUMENT;
if (volume < rangeLowEnd || volume > rangeHighEnd) volume = ToneGenerator.DEFAULT_VOLUME;
new ToneGenerator().generateToneSynchronously( (byte) pitch, duration, (byte) instrument, (byte) volume);
}
}
static final int rangeLowEnd = 0;
static final int rangeHighEnd = 127;
/**
* Build an instance of the MIDI (simulated) out syscall. Default service number is 33 and name is "MidiOutSync".
*/
public SyscallMidiOutSync()
{
super(33, "MidiOutSync");
}
/**
* Performs syscall function to send MIDI output to sound card. The syscall does not return until after the
* duration period ($a1) has elapsed. This requires four arguments in registers $a0 through $a3.<br> $a0 - pitch
* (note). Integer value from 0 to 127, with 60 being middle-C on a piano.<br> $a1 - duration. Integer value in
* milliseconds.<br> $a2 - instrument. Integer value from 0 to 127, with 0 being acoustic grand piano.<br> $a3 -
* volume. Integer value from 0 to 127.<br> Default values, in case any parameters are outside the above ranges,
* are $a0=60, $a1=1000, $a2=0, $a3=100.<br> See MARS documentation elsewhere or www.midi.org for more information.
* Note that the pitch, instrument and volume value ranges 0-127 are from javax.sound.midi; actual MIDI instruments
* use the range 1-128.
*/
public void simulate(ProgramStatement statement) throws ProcessingException
{
int pitch = RegisterFile.getValue(4); // $a0
int duration = RegisterFile.getValue(5); // $a1
int instrument = RegisterFile.getValue(6); // $a2
int volume = RegisterFile.getValue(7); // $a3
if (pitch < rangeLowEnd || pitch > rangeHighEnd)
{
pitch = ToneGenerator.DEFAULT_PITCH;
}
if (duration < 0)
{
duration = ToneGenerator.DEFAULT_DURATION;
}
if (instrument < rangeLowEnd || instrument > rangeHighEnd)
{
instrument = ToneGenerator.DEFAULT_INSTRUMENT;
}
if (volume < rangeLowEnd || volume > rangeHighEnd)
{
volume = ToneGenerator.DEFAULT_VOLUME;
}
new ToneGenerator().generateToneSynchronously((byte) pitch, duration, (byte) instrument, (byte) volume);
}
}
@@ -1,6 +1,5 @@
package mars.mips.instructions.syscalls;
import java.util.*;
import mars.util.*;
package mars.mips.instructions.syscalls;
/*
Copyright (c) 2003-2006, Pete Sanderson and Kenneth Vollmar
@@ -30,55 +29,62 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* Represents User override of default syscall number assignment.
* Such overrides are specified in the config.txt file read when
* MARS starts up.
* Represents User override of default syscall number assignment. Such overrides are specified in the config.txt file
* read when MARS starts up.
*/
public class SyscallNumberOverride {
private String serviceName;
private int newServiceNumber;
/**
* Constructor is called with two strings: service name and desired
* number. Will throw an exception is number is malformed, but does
* not check validity of the service name or number.
* @param serviceName a String containing syscall service mnemonic.
* @param value a String containing its reassigned syscall service number.
* If this number is previously assigned to a different syscall which does not
* also receive a new number, then an error for duplicate numbers will
* be issued at MARS launch.
*/
public SyscallNumberOverride(String serviceName, String value) {
this.serviceName = serviceName;
try {
public class SyscallNumberOverride
{
private final String serviceName;
private int newServiceNumber;
/**
* Constructor is called with two strings: service name and desired number. Will throw an exception is number is
* malformed, but does not check validity of the service name or number.
*
* @param serviceName a String containing syscall service mnemonic.
* @param value a String containing its reassigned syscall service number. If this number is previously assigned
* to a different syscall which does not also receive a new number, then an error for duplicate numbers will be
* issued at MARS launch.
*/
public SyscallNumberOverride(String serviceName, String value)
{
this.serviceName = serviceName;
try
{
this.newServiceNumber = Integer.parseInt(value.trim());
}
catch (NumberFormatException e) {
System.out.println("Error processing Syscall number override: '"+value.trim()+"' is not a valid integer");
System.exit(0);
}
}
/**
* Get the service name as a String.
* @return the service name
*/
public String getName() {
return serviceName;
}
/**
* Get the new service number as an int.
* @return the service number
*/
public int getNumber() {
return newServiceNumber;
}
}
}
catch (NumberFormatException e)
{
System.out.println("Error processing Syscall number override: '" + value.trim() + "' is not a valid integer");
System.exit(0);
}
}
/**
* Get the service name as a String.
*
* @return the service name
*/
public String getName()
{
return serviceName;
}
/**
* Get the new service number as an int.
*
* @return the service number
*/
public int getNumber()
{
return newServiceNumber;
}
}
@@ -1,8 +1,11 @@
package mars.mips.instructions.syscalls;
import mars.util.*;
import mars.mips.hardware.*;
import mars.simulator.*;
import mars.*;
package mars.mips.instructions.syscalls;
import mars.Globals;
import mars.ProcessingException;
import mars.ProgramStatement;
import mars.mips.hardware.AddressErrorException;
import mars.mips.hardware.RegisterFile;
import mars.util.SystemIO;
/*
Copyright (c) 2003-2006, Pete Sanderson and Kenneth Vollmar
@@ -33,70 +36,69 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* Service to open file name specified by $a0. File descriptor returned in $v0.
* (this was changed from $a0 in MARS 3.7 for SPIM compatibility. The table
* in COD erroneously shows $a0).
*
/**
* Service to open file name specified by $a0. File descriptor returned in $v0. (this was changed from $a0 in MARS 3.7
* for SPIM compatibility. The table in COD erroneously shows $a0).
*/
public class SyscallOpen extends AbstractSyscall {
/**
* Build an instance of the Open file syscall. Default service number
* is 13 and name is "Open".
*/
public SyscallOpen() {
super(13, "Open");
}
/**
* Performs syscall function to open file name specified by $a0. File descriptor returned
* in $v0. Only supported flags ($a1) are read-only (0), write-only (1) and
* write-append (9). write-only flag creates file if it does not exist, so it is technically
* write-create. write-append will start writing at end of existing file.
* Mode ($a2) is ignored.
*/
public void simulate(ProgramStatement statement) throws ProcessingException {
// NOTE: with MARS 3.7, return changed from $a0 to $v0 and the terminology
// of 'flags' and 'mode' was corrected (they had been reversed).
//
// Arguments: $a0 = filename (string), $a1 = flags, $a2 = mode
// Result: file descriptor (in $v0)
// This code implements the flags:
// Read flag = 0
// Write flag = 1
// Read/Write NOT IMPLEMENTED
// Write/append flag = 9
// This code implements the modes:
// NO MODES IMPLEMENTED -- MODE IS IGNORED
// Returns in $v0: a "file descriptor" in the range 0 to SystemIO.SYSCALL_MAXFILES-1,
// or -1 if error
String filename = new String(); // = "";
int byteAddress = RegisterFile.getValue(4);
char ch[] = { ' '}; // Need an array to convert to String
try
{
public class SyscallOpen extends AbstractSyscall
{
/**
* Build an instance of the Open file syscall. Default service number is 13 and name is "Open".
*/
public SyscallOpen()
{
super(13, "Open");
}
/**
* Performs syscall function to open file name specified by $a0. File descriptor returned in $v0. Only supported
* flags ($a1) are read-only (0), write-only (1) and write-append (9). write-only flag creates file if it does not
* exist, so it is technically write-create. write-append will start writing at end of existing file. Mode ($a2) is
* ignored.
*/
public void simulate(ProgramStatement statement) throws ProcessingException
{
// NOTE: with MARS 3.7, return changed from $a0 to $v0 and the terminology
// of 'flags' and 'mode' was corrected (they had been reversed).
//
// Arguments: $a0 = filename (string), $a1 = flags, $a2 = mode
// Result: file descriptor (in $v0)
// This code implements the flags:
// Read flag = 0
// Write flag = 1
// Read/Write NOT IMPLEMENTED
// Write/append flag = 9
// This code implements the modes:
// NO MODES IMPLEMENTED -- MODE IS IGNORED
// Returns in $v0: a "file descriptor" in the range 0 to SystemIO.SYSCALL_MAXFILES-1,
// or -1 if error
String filename = ""; // = "";
int byteAddress = RegisterFile.getValue(4);
char[] ch = {' '}; // Need an array to convert to String
try
{
ch[0] = (char) Globals.memory.getByte(byteAddress);
while (ch[0] != 0) // only uses single location ch[0]
{
filename = filename.concat(new String(ch)); // parameter to String constructor is a char[] array
byteAddress++;
ch[0] = (char) Globals.memory.getByte(
byteAddress);
filename = filename.concat(new String(ch)); // parameter to String constructor is a char[] array
byteAddress++;
ch[0] = (char) Globals.memory.getByte(
byteAddress);
}
}
catch (AddressErrorException e)
{
throw new ProcessingException(statement, e);
}
int retValue = SystemIO.openFile(filename,
RegisterFile.getValue(5));
RegisterFile.updateRegister(2, retValue); // set returned fd value in register
// GETTING RID OF PROCESSING EXCEPTION. IT IS THE RESPONSIBILITY OF THE
// USER PROGRAM TO CHECK FOR BAD FILE OPEN. MARS SHOULD NOT PRE-EMPTIVELY
// TERMINATE MIPS EXECUTION BECAUSE OF IT. Thanks to UCLA student
// Duy Truong for pointing this out. DPS 28-July-2009.
}
catch (AddressErrorException e)
{
throw new ProcessingException(statement, e);
}
int retValue = SystemIO.openFile(filename,
RegisterFile.getValue(5));
RegisterFile.updateRegister(2, retValue); // set returned fd value in register
// GETTING RID OF PROCESSING EXCEPTION. IT IS THE RESPONSIBILITY OF THE
// USER PROGRAM TO CHECK FOR BAD FILE OPEN. MARS SHOULD NOT PRE-EMPTIVELY
// TERMINATE MIPS EXECUTION BECAUSE OF IT. Thanks to UCLA student
// Duy Truong for pointing this out. DPS 28-July-2009.
/*
if (retValue < 0) // some error in opening file
{
@@ -105,5 +107,5 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Exceptions.SYSCALL_EXCEPTION);
}
*/
}
}
}
}
@@ -1,7 +1,9 @@
package mars.mips.instructions.syscalls;
import mars.util.*;
import mars.mips.hardware.*;
import mars.*;
package mars.mips.instructions.syscalls;
import mars.ProcessingException;
import mars.ProgramStatement;
import mars.mips.hardware.RegisterFile;
import mars.util.SystemIO;
/*
Copyright (c) 2003-2006, Pete Sanderson and Kenneth Vollmar
@@ -32,28 +34,29 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
/**
* Service to display character stored in $a0 on the console.
*
*/
public class SyscallPrintChar extends AbstractSyscall {
/**
* Build an instance of the Print Char syscall. Default service number
* is 11 and name is "PrintChar".
*/
public SyscallPrintChar() {
super(11, "PrintChar");
}
/**
* Performs syscall function to print on the console the character stored in $a0.
*/
public void simulate(ProgramStatement statement) throws ProcessingException {
// mask off the lower byte of register $a0.
// Convert to a one-character string and use the string technique.
char t = (char) (RegisterFile.getValue(4) & 0x000000ff);
SystemIO.printString(new Character(t).toString());
}
}
public class SyscallPrintChar extends AbstractSyscall
{
/**
* Build an instance of the Print Char syscall. Default service number is 11 and name is "PrintChar".
*/
public SyscallPrintChar()
{
super(11, "PrintChar");
}
/**
* Performs syscall function to print on the console the character stored in $a0.
*/
public void simulate(ProgramStatement statement) throws ProcessingException
{
// mask off the lower byte of register $a0.
// Convert to a one-character string and use the string technique.
char t = (char) (RegisterFile.getValue(4) & 0x000000ff);
SystemIO.printString(Character.toString(t));
}
}
@@ -1,7 +1,10 @@
package mars.mips.instructions.syscalls;
import mars.util.*;
import mars.mips.hardware.*;
import mars.*;
package mars.mips.instructions.syscalls;
import mars.ProcessingException;
import mars.ProgramStatement;
import mars.mips.hardware.Coprocessor1;
import mars.util.Binary;
import mars.util.SystemIO;
/*
Copyright (c) 2003-2006, Pete Sanderson and Kenneth Vollmar
@@ -32,27 +35,29 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* Service to display double whose bits are stored in $f12 & $f13 onto the console.
* $f13 contains high order word of the double.
/**
* Service to display double whose bits are stored in $f12 & $f13 onto the console. $f13 contains high order word of the
* double.
*/
public class SyscallPrintDouble extends AbstractSyscall {
/**
* Build an instance of the Print Double syscall. Default service number
* is 3 and name is "PrintDouble".
*/
public SyscallPrintDouble() {
super(3, "PrintDouble");
}
/**
* Performs syscall function to print double whose bits are stored in $f12 & $f13.
*/
public void simulate(ProgramStatement statement) throws ProcessingException {
// Note: Higher numbered reg contains high order word so concat 13-12.
SystemIO.printString(new Double(Double.longBitsToDouble(
Binary.twoIntsToLong(Coprocessor1.getValue(13),Coprocessor1.getValue(12))
)).toString());
}
}
public class SyscallPrintDouble extends AbstractSyscall
{
/**
* Build an instance of the Print Double syscall. Default service number is 3 and name is "PrintDouble".
*/
public SyscallPrintDouble()
{
super(3, "PrintDouble");
}
/**
* Performs syscall function to print double whose bits are stored in $f12 & $f13.
*/
public void simulate(ProgramStatement statement) throws ProcessingException
{
// Note: Higher numbered reg contains high order word so concat 13-12.
SystemIO.printString(Double.toString(Double.longBitsToDouble(
Binary.twoIntsToLong(Coprocessor1.getValue(13), Coprocessor1.getValue(12))
)));
}
}
@@ -34,24 +34,26 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
/**
* Service to display on the console float whose bits are stored in $f12
*/
public class SyscallPrintFloat extends AbstractSyscall {
/**
* Build an instance of the Print Float syscall. Default service number
* is 2 and name is "PrintFloat".
*/
public SyscallPrintFloat() {
super(2, "PrintFloat");
}
public class SyscallPrintFloat extends AbstractSyscall
{
/**
* Build an instance of the Print Float syscall. Default service number is 2 and name is "PrintFloat".
*/
public SyscallPrintFloat()
{
super(2, "PrintFloat");
}
/**
* Performs syscall function to display float whose bits are stored in $f12
*/
public void simulate(ProgramStatement statement) throws ProcessingException {
public void simulate(ProgramStatement statement) throws ProcessingException
{
SystemIO.printString(Float.toString(Float.intBitsToFloat(
Coprocessor1.getValue(12))));
Coprocessor1.getValue(12))));
}
}
@@ -34,25 +34,26 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
/**
* Service to display integer stored in $a0 on the console.
*
*/
public class SyscallPrintInt extends AbstractSyscall {
/**
* Build an instance of the Print Integer syscall. Default service number
* is 1 and name is "PrintInt".
*/
public SyscallPrintInt() {
super(1, "PrintInt");
}
/**
* Performs syscall function to print on the console the integer stored in $a0.
*/
public void simulate(ProgramStatement statement) throws ProcessingException {
SystemIO.printString(
Integer.toString(RegisterFile.getValue(4)));
}
}
public class SyscallPrintInt extends AbstractSyscall
{
/**
* Build an instance of the Print Integer syscall. Default service number is 1 and name is "PrintInt".
*/
public SyscallPrintInt()
{
super(1, "PrintInt");
}
/**
* Performs syscall function to print on the console the integer stored in $a0.
*/
public void simulate(ProgramStatement statement) throws ProcessingException
{
SystemIO.printString(
Integer.toString(RegisterFile.getValue(4)));
}
}
@@ -1,7 +1,10 @@
package mars.mips.instructions.syscalls;
import mars.util.*;
import mars.mips.hardware.*;
import mars.*;
package mars.mips.instructions.syscalls;
import mars.ProcessingException;
import mars.ProgramStatement;
import mars.mips.hardware.RegisterFile;
import mars.util.Binary;
import mars.util.SystemIO;
/*
Copyright (c) 2003-2009, Pete Sanderson and Kenneth Vollmar
@@ -32,24 +35,25 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
/**
* Service to display integer stored in $a0 on the console.
*
*/
public class SyscallPrintIntBinary extends AbstractSyscall {
/**
* Build an instance of the Print Integer syscall. Default service number
* is 1 and name is "PrintInt".
*/
public SyscallPrintIntBinary() {
super(35, "PrintIntBinary");
}
/**
* Performs syscall function to print on the console the integer stored in $a0, in hexadecimal format.
*/
public void simulate(ProgramStatement statement) throws ProcessingException {
SystemIO.printString(Binary.intToBinaryString(RegisterFile.getValue(4)));
}
}
public class SyscallPrintIntBinary extends AbstractSyscall
{
/**
* Build an instance of the Print Integer syscall. Default service number is 1 and name is "PrintInt".
*/
public SyscallPrintIntBinary()
{
super(35, "PrintIntBinary");
}
/**
* Performs syscall function to print on the console the integer stored in $a0, in hexadecimal format.
*/
public void simulate(ProgramStatement statement) throws ProcessingException
{
SystemIO.printString(Binary.intToBinaryString(RegisterFile.getValue(4)));
}
}
@@ -1,7 +1,10 @@
package mars.mips.instructions.syscalls;
import mars.util.*;
import mars.mips.hardware.*;
import mars.*;
package mars.mips.instructions.syscalls;
import mars.ProcessingException;
import mars.ProgramStatement;
import mars.mips.hardware.RegisterFile;
import mars.util.Binary;
import mars.util.SystemIO;
/*
Copyright (c) 2003-2009, Pete Sanderson and Kenneth Vollmar
@@ -32,24 +35,25 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
/**
* Service to display integer stored in $a0 on the console.
*
*/
public class SyscallPrintIntHex extends AbstractSyscall {
/**
* Build an instance of the Print Integer syscall. Default service number
* is 1 and name is "PrintInt".
*/
public SyscallPrintIntHex() {
super(34, "PrintIntHex");
}
/**
* Performs syscall function to print on the console the integer stored in $a0, in hexadecimal format.
*/
public void simulate(ProgramStatement statement) throws ProcessingException {
SystemIO.printString(Binary.intToHexString(RegisterFile.getValue(4)));
}
}
public class SyscallPrintIntHex extends AbstractSyscall
{
/**
* Build an instance of the Print Integer syscall. Default service number is 1 and name is "PrintInt".
*/
public SyscallPrintIntHex()
{
super(34, "PrintIntHex");
}
/**
* Performs syscall function to print on the console the integer stored in $a0, in hexadecimal format.
*/
public void simulate(ProgramStatement statement) throws ProcessingException
{
SystemIO.printString(Binary.intToHexString(RegisterFile.getValue(4)));
}
}
@@ -1,7 +1,10 @@
package mars.mips.instructions.syscalls;
import mars.util.*;
import mars.mips.hardware.*;
import mars.*;
package mars.mips.instructions.syscalls;
import mars.ProcessingException;
import mars.ProgramStatement;
import mars.mips.hardware.RegisterFile;
import mars.util.Binary;
import mars.util.SystemIO;
/*
Copyright (c) 2003-2010, Pete Sanderson and Kenneth Vollmar
@@ -32,26 +35,27 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
/**
* Service to display integer stored in $a0 on the console as unsigned decimal.
*
*/
public class SyscallPrintIntUnsigned extends AbstractSyscall {
/**
* Build an instance of the Print Integer Unsigned syscall. Default service number
* is 36 and name is "PrintIntUnsigned".
*/
public SyscallPrintIntUnsigned() {
super(36, "PrintIntUnsigned");
}
/**
* Performs syscall function to print on the console the integer stored in $a0.
* The value is treated as unsigned.
*/
public void simulate(ProgramStatement statement) throws ProcessingException {
SystemIO.printString(
Binary.unsignedIntToIntString(RegisterFile.getValue(4)));
}
}
public class SyscallPrintIntUnsigned extends AbstractSyscall
{
/**
* Build an instance of the Print Integer Unsigned syscall. Default service number is 36 and name is
* "PrintIntUnsigned".
*/
public SyscallPrintIntUnsigned()
{
super(36, "PrintIntUnsigned");
}
/**
* Performs syscall function to print on the console the integer stored in $a0. The value is treated as unsigned.
*/
public void simulate(ProgramStatement statement) throws ProcessingException
{
SystemIO.printString(
Binary.unsignedIntToIntString(RegisterFile.getValue(4)));
}
}
@@ -1,7 +1,11 @@
package mars.mips.instructions.syscalls;
import mars.util.*;
import mars.mips.hardware.*;
import mars.*;
package mars.mips.instructions.syscalls;
import mars.Globals;
import mars.ProcessingException;
import mars.ProgramStatement;
import mars.mips.hardware.AddressErrorException;
import mars.mips.hardware.RegisterFile;
import mars.util.SystemIO;
/*
Copyright (c) 2003-2006, Pete Sanderson and Kenneth Vollmar
@@ -32,39 +36,41 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* Service to display string stored starting at address in $a0 onto the console.
/**
* Service to display string stored starting at address in $a0 onto the console.
*/
public class SyscallPrintString extends AbstractSyscall {
/**
* Build an instance of the Print String syscall. Default service number
* is 4 and name is "PrintString".
*/
public SyscallPrintString() {
super(4, "PrintString");
}
/**
* Performs syscall function to print string stored starting at address in $a0.
*/
public void simulate(ProgramStatement statement) throws ProcessingException {
int byteAddress = RegisterFile.getValue(4);
char ch = 0;
try
{
public class SyscallPrintString extends AbstractSyscall
{
/**
* Build an instance of the Print String syscall. Default service number is 4 and name is "PrintString".
*/
public SyscallPrintString()
{
super(4, "PrintString");
}
/**
* Performs syscall function to print string stored starting at address in $a0.
*/
public void simulate(ProgramStatement statement) throws ProcessingException
{
int byteAddress = RegisterFile.getValue(4);
char ch = 0;
try
{
ch = (char) Globals.memory.getByte(byteAddress);
// won't stop until NULL byte reached!
// won't stop until NULL byte reached!
while (ch != 0)
{
SystemIO.printString(new Character(ch).toString());
byteAddress++;
ch = (char) Globals.memory.getByte(byteAddress);
SystemIO.printString(Character.toString(ch));
byteAddress++;
ch = (char) Globals.memory.getByte(byteAddress);
}
}
catch (AddressErrorException e)
{
throw new ProcessingException(statement, e);
}
}
}
}
catch (AddressErrorException e)
{
throw new ProcessingException(statement, e);
}
}
}
@@ -1,9 +1,13 @@
package mars.mips.instructions.syscalls;
import mars.util.*;
import mars.mips.hardware.*;
import mars.simulator.*;
import mars.*;
import java.util.Random;
package mars.mips.instructions.syscalls;
import mars.ProcessingException;
import mars.ProgramStatement;
import mars.mips.hardware.Coprocessor1;
import mars.mips.hardware.InvalidRegisterAccessException;
import mars.mips.hardware.RegisterFile;
import mars.simulator.Exceptions;
import java.util.Random;
/*
Copyright (c) 2003-2008, Pete Sanderson and Kenneth Vollmar
@@ -36,40 +40,44 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
/**
* Service to return a random floating point value.
*
*/
public class SyscallRandDouble extends AbstractSyscall {
/**
* Build an instance of the syscall with its default service number and name.
*/
public SyscallRandDouble() {
super(44, "RandDouble");
}
/**
* System call to the random number generator.
* Return in $f0 the next pseudorandom, uniformly distributed double value between 0.0 and 1.0
* from this random number generator's sequence.
*/
public void simulate(ProgramStatement statement) throws ProcessingException {
// Input arguments: $a0 = index of pseudorandom number generator
// Return: $f0 = the next pseudorandom, uniformly distributed double value between 0.0 and 1.0
// from this random number generator's sequence.
Integer index = new Integer(RegisterFile.getValue(4));
Random stream = (Random) RandomStreams.randomStreams.get(index);
if (stream == null) {
public class SyscallRandDouble extends AbstractSyscall
{
/**
* Build an instance of the syscall with its default service number and name.
*/
public SyscallRandDouble()
{
super(44, "RandDouble");
}
/**
* System call to the random number generator. Return in $f0 the next pseudorandom, uniformly distributed double
* value between 0.0 and 1.0 from this random number generator's sequence.
*/
public void simulate(ProgramStatement statement) throws ProcessingException
{
// Input arguments: $a0 = index of pseudorandom number generator
// Return: $f0 = the next pseudorandom, uniformly distributed double value between 0.0 and 1.0
// from this random number generator's sequence.
Integer index = Integer.valueOf(RegisterFile.getValue(4));
Random stream = (Random) RandomStreams.randomStreams.get(index);
if (stream == null)
{
stream = new Random(); // create a non-seeded stream
RandomStreams.randomStreams.put(index, stream);
}
try {
Coprocessor1.setRegisterPairToDouble(0, stream.nextDouble( ));
}
catch (InvalidRegisterAccessException e) { // register ID error in this method
throw new ProcessingException(statement,
"Internal error storing double to register (syscall "+this.getNumber()+")",
Exceptions.SYSCALL_EXCEPTION);
}
}
}
}
try
{
Coprocessor1.setRegisterPairToDouble(0, stream.nextDouble());
}
catch (InvalidRegisterAccessException e)
{ // register ID error in this method
throw new ProcessingException(statement,
"Internal error storing double to register (syscall " + this.getNumber() + ")",
Exceptions.SYSCALL_EXCEPTION);
}
}
}
@@ -1,9 +1,11 @@
package mars.mips.instructions.syscalls;
import mars.util.*;
import mars.mips.hardware.*;
import mars.simulator.*;
import mars.*;
import java.util.Random;
package mars.mips.instructions.syscalls;
import mars.ProcessingException;
import mars.ProgramStatement;
import mars.mips.hardware.Coprocessor1;
import mars.mips.hardware.RegisterFile;
import java.util.Random;
/*
Copyright (c) 2003-2008, Pete Sanderson and Kenneth Vollmar
@@ -36,32 +38,34 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
/**
* Service to return a random floating point value.
*
*/
public class SyscallRandFloat extends AbstractSyscall {
/**
* Build an instance of the syscall with its default service number and name.
*/
public SyscallRandFloat() {
super(43, "RandFloat");
}
/**
* System call to the random number generator.
* Return in $f0 the next pseudorandom, uniformly distributed float value between 0.0 and 1.0
* from this random number generator's sequence.
*/
public void simulate(ProgramStatement statement) throws ProcessingException {
// Input arguments: $a0 = index of pseudorandom number generator
// Return: $f0 = the next pseudorandom, uniformly distributed float value between 0.0 and 1.0
// from this random number generator's sequence.
Integer index = new Integer(RegisterFile.getValue(4));
Random stream = (Random) RandomStreams.randomStreams.get(index);
if (stream == null) {
public class SyscallRandFloat extends AbstractSyscall
{
/**
* Build an instance of the syscall with its default service number and name.
*/
public SyscallRandFloat()
{
super(43, "RandFloat");
}
/**
* System call to the random number generator. Return in $f0 the next pseudorandom, uniformly distributed float
* value between 0.0 and 1.0 from this random number generator's sequence.
*/
public void simulate(ProgramStatement statement) throws ProcessingException
{
// Input arguments: $a0 = index of pseudorandom number generator
// Return: $f0 = the next pseudorandom, uniformly distributed float value between 0.0 and 1.0
// from this random number generator's sequence.
Integer index = Integer.valueOf(RegisterFile.getValue(4));
Random stream = (Random) RandomStreams.randomStreams.get(index);
if (stream == null)
{
stream = new Random(); // create a non-seeded stream
RandomStreams.randomStreams.put(index, stream);
}
Coprocessor1.setRegisterToFloat(0, stream.nextFloat( ));
}
}
}
Coprocessor1.setRegisterToFloat(0, stream.nextFloat());
}
}
@@ -1,9 +1,10 @@
package mars.mips.instructions.syscalls;
import mars.util.*;
import mars.mips.hardware.*;
import mars.simulator.*;
import mars.*;
import java.util.Random;
package mars.mips.instructions.syscalls;
import mars.ProcessingException;
import mars.ProgramStatement;
import mars.mips.hardware.RegisterFile;
import java.util.Random;
/*
Copyright (c) 2003-2008, Pete Sanderson and Kenneth Vollmar
@@ -36,32 +37,35 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
/**
* Service to return a random integer.
*
*/
public class SyscallRandInt extends AbstractSyscall {
/**
* Build an instance of the syscall with its default service number and name.
*/
public SyscallRandInt() {
super(41, "RandInt");
}
/**
* System call to the random number generator.
* Return in $a0 the next pseudorandom, uniformly distributed int value from this random number generator's sequence.
*/
public void simulate(ProgramStatement statement) throws ProcessingException {
// Input arguments: $a0 = index of pseudorandom number generator
// Return: $a0 = the next pseudorandom, uniformly distributed int value from this random number generator's sequence.
Integer index = new Integer(RegisterFile.getValue(4));
Random stream = (Random) RandomStreams.randomStreams.get(index);
if (stream == null) {
stream = new Random(); // create a non-seeded stream
RandomStreams.randomStreams.put(index, stream);
}
RegisterFile.updateRegister(4, stream.nextInt() );
}
public class SyscallRandInt extends AbstractSyscall
{
/**
* Build an instance of the syscall with its default service number and name.
*/
public SyscallRandInt()
{
super(41, "RandInt");
}
}
/**
* System call to the random number generator. Return in $a0 the next pseudorandom, uniformly distributed int value
* from this random number generator's sequence.
*/
public void simulate(ProgramStatement statement) throws ProcessingException
{
// Input arguments: $a0 = index of pseudorandom number generator
// Return: $a0 = the next pseudorandom, uniformly distributed int value from this random number generator's sequence.
Integer index = Integer.valueOf(RegisterFile.getValue(4));
Random stream = (Random) RandomStreams.randomStreams.get(index);
if (stream == null)
{
stream = new Random(); // create a non-seeded stream
RandomStreams.randomStreams.put(index, stream);
}
RegisterFile.updateRegister(4, stream.nextInt());
}
}
@@ -1,9 +1,11 @@
package mars.mips.instructions.syscalls;
import mars.util.*;
import mars.mips.hardware.*;
import mars.simulator.*;
import mars.*;
import java.util.Random;
package mars.mips.instructions.syscalls;
import mars.ProcessingException;
import mars.ProgramStatement;
import mars.mips.hardware.RegisterFile;
import mars.simulator.Exceptions;
import java.util.Random;
/*
Copyright (c) 2003-2008, Pete Sanderson and Kenneth Vollmar
@@ -34,44 +36,49 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
/**
* Service to return a random integer in a specified range.
*
*/
public class SyscallRandIntRange extends AbstractSyscall {
/**
* Build an instance of the syscall with its default service number and name.
*/
public SyscallRandIntRange() {
super(42, "RandIntRange");
}
/**
* System call to the random number generator, with an upper range specified.
* Return in $a0 the next pseudorandom, uniformly distributed int value between 0 (inclusive)
* and the specified value (exclusive), drawn from this random number generator's sequence.
*/
public void simulate(ProgramStatement statement) throws ProcessingException {
// Input arguments:
// $a0 = index of pseudorandom number generator
// $a1 = the upper bound of range of returned values.
// Return: $a0 = the next pseudorandom, uniformly distributed int value from this
// random number generator's sequence.
Integer index = new Integer(RegisterFile.getValue(4));
Random stream = (Random) RandomStreams.randomStreams.get(index);
if (stream == null) {
public class SyscallRandIntRange extends AbstractSyscall
{
/**
* Build an instance of the syscall with its default service number and name.
*/
public SyscallRandIntRange()
{
super(42, "RandIntRange");
}
/**
* System call to the random number generator, with an upper range specified. Return in $a0 the next pseudorandom,
* uniformly distributed int value between 0 (inclusive) and the specified value (exclusive), drawn from this random
* number generator's sequence.
*/
public void simulate(ProgramStatement statement) throws ProcessingException
{
// Input arguments:
// $a0 = index of pseudorandom number generator
// $a1 = the upper bound of range of returned values.
// Return: $a0 = the next pseudorandom, uniformly distributed int value from this
// random number generator's sequence.
Integer index = Integer.valueOf(RegisterFile.getValue(4));
Random stream = (Random) RandomStreams.randomStreams.get(index);
if (stream == null)
{
stream = new Random(); // create a non-seeded stream
RandomStreams.randomStreams.put(index, stream);
}
try {
RegisterFile.updateRegister(4, stream.nextInt( RegisterFile.getValue(5) ) );
}
catch (IllegalArgumentException iae) {
throw new ProcessingException(statement,
"Upper bound of range cannot be negative (syscall "+this.getNumber()+")",
Exceptions.SYSCALL_EXCEPTION);
}
}
}
}
try
{
RegisterFile.updateRegister(4, stream.nextInt(RegisterFile.getValue(5)));
}
catch (IllegalArgumentException iae)
{
throw new ProcessingException(statement,
"Upper bound of range cannot be negative (syscall " + this.getNumber() + ")",
Exceptions.SYSCALL_EXCEPTION);
}
}
}
@@ -1,9 +1,10 @@
package mars.mips.instructions.syscalls;
import mars.util.*;
import mars.mips.hardware.*;
import mars.simulator.*;
import mars.*;
import java.util.Random;
package mars.mips.instructions.syscalls;
import mars.ProcessingException;
import mars.ProgramStatement;
import mars.mips.hardware.RegisterFile;
import java.util.Random;
/*
Copyright (c) 2003-2008, Pete Sanderson and Kenneth Vollmar
@@ -34,35 +35,40 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
/**
* Service to set seed for the underlying Java pseudorandom number generator. No values are returned.
*
*/
public class SyscallRandSeed extends AbstractSyscall {
/**
* Build an instance of the syscall with its default service number and name.
*/
public SyscallRandSeed() {
super(40, "RandSeed");
}
/**
* Set the seed of the underlying Java pseudorandom number generator.
*/
public void simulate(ProgramStatement statement) throws ProcessingException {
// Arguments: $a0 = index of pseudorandom number generator
// $a1 = seed for pseudorandom number generator.
// Result: No values are returned. Sets the seed of the underlying Java pseudorandom number generator.
public class SyscallRandSeed extends AbstractSyscall
{
/**
* Build an instance of the syscall with its default service number and name.
*/
public SyscallRandSeed()
{
super(40, "RandSeed");
}
Integer index = new Integer(RegisterFile.getValue(4));
Random stream = (Random) RandomStreams.randomStreams.get(index);
if (stream == null) {
RandomStreams.randomStreams.put(index, new Random(RegisterFile.getValue(5)));
} else {
stream.setSeed(RegisterFile.getValue(5));
}
}
/**
* Set the seed of the underlying Java pseudorandom number generator.
*/
public void simulate(ProgramStatement statement) throws ProcessingException
{
// Arguments: $a0 = index of pseudorandom number generator
// $a1 = seed for pseudorandom number generator.
// Result: No values are returned. Sets the seed of the underlying Java pseudorandom number generator.
}
Integer index = Integer.valueOf(RegisterFile.getValue(4));
Random stream = (Random) RandomStreams.randomStreams.get(index);
if (stream == null)
{
RandomStreams.randomStreams.put(index, new Random(RegisterFile.getValue(5)));
}
else
{
stream.setSeed(RegisterFile.getValue(5));
}
}
}
@@ -1,8 +1,11 @@
package mars.mips.instructions.syscalls;
import mars.util.*;
import mars.mips.hardware.*;
import mars.simulator.*;
import mars.*;
package mars.mips.instructions.syscalls;
import mars.Globals;
import mars.ProcessingException;
import mars.ProgramStatement;
import mars.mips.hardware.AddressErrorException;
import mars.mips.hardware.RegisterFile;
import mars.util.SystemIO;
/*
Copyright (c) 2003-2009, Pete Sanderson and Kenneth Vollmar
@@ -33,42 +36,43 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* Service to read from file descriptor given in $a0. $a1 specifies buffer
* and $a2 specifies length. Number of characters read is returned in $v0.
* (this was changed from $a0 in MARS 3.7 for SPIM compatibility. The table
* in COD erroneously shows $a0). *
/**
* Service to read from file descriptor given in $a0. $a1 specifies buffer and $a2 specifies length. Number of
* characters read is returned in $v0. (this was changed from $a0 in MARS 3.7 for SPIM compatibility. The table in COD
* erroneously shows $a0). *
*/
public class SyscallRead extends AbstractSyscall {
/**
* Build an instance of the Read file syscall. Default service number
* is 14 and name is "Read".
*/
public SyscallRead() {
super(14, "Read");
}
/**
* Performs syscall function to read from file descriptor given in $a0. $a1 specifies buffer
* and $a2 specifies length. Number of characters read is returned in $v0 (starting MARS 3.7).
*/
public void simulate(ProgramStatement statement) throws ProcessingException {
int byteAddress = RegisterFile.getValue(5); // destination of characters read from file
byte b = 0;
int index = 0;
byte myBuffer[] = new byte[RegisterFile.getValue(6)]; // specified length
// Call to SystemIO.xxxx.read(xxx,xxx,xxx) returns actual length
int retLength = SystemIO.readFromFile(
RegisterFile.getValue(4), // fd
myBuffer, // buffer
RegisterFile.getValue(6)); // length
RegisterFile.updateRegister(2, retLength); // set returned value in register
// Getting rid of processing exception. It is the responsibility of the
// user program to check the syscall's return value. MARS should not
// re-emptively terminate MIPS execution because of it. Thanks to
// UCLA student Duy Truong for pointing this out. DPS 28-July-2009
public class SyscallRead extends AbstractSyscall
{
/**
* Build an instance of the Read file syscall. Default service number is 14 and name is "Read".
*/
public SyscallRead()
{
super(14, "Read");
}
/**
* Performs syscall function to read from file descriptor given in $a0. $a1 specifies buffer and $a2 specifies
* length. Number of characters read is returned in $v0 (starting MARS 3.7).
*/
public void simulate(ProgramStatement statement) throws ProcessingException
{
int byteAddress = RegisterFile.getValue(5); // destination of characters read from file
byte b = 0;
int index = 0;
byte[] myBuffer = new byte[RegisterFile.getValue(6)]; // specified length
// Call to SystemIO.xxxx.read(xxx,xxx,xxx) returns actual length
int retLength = SystemIO.readFromFile(
RegisterFile.getValue(4), // fd
myBuffer, // buffer
RegisterFile.getValue(6)); // length
RegisterFile.updateRegister(2, retLength); // set returned value in register
// Getting rid of processing exception. It is the responsibility of the
// user program to check the syscall's return value. MARS should not
// re-emptively terminate MIPS execution because of it. Thanks to
// UCLA student Duy Truong for pointing this out. DPS 28-July-2009
/*
if (retLength < 0) // some error in opening file
{
@@ -76,19 +80,19 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
SystemIO.getFileErrorMessage()+" (syscall 14)",
Exceptions.SYSCALL_EXCEPTION);
}
*/
// copy bytes from returned buffer into MARS memory
try
{
*/
// copy bytes from returned buffer into MARS memory
try
{
while (index < retLength)
{
Globals.memory.setByte(byteAddress++,
myBuffer[index++]);
Globals.memory.setByte(byteAddress++,
myBuffer[index++]);
}
}
catch (AddressErrorException e)
{
throw new ProcessingException(statement, e);
}
}
}
}
catch (AddressErrorException e)
{
throw new ProcessingException(statement, e);
}
}
}
@@ -1,8 +1,10 @@
package mars.mips.instructions.syscalls;
import mars.*;
import mars.util.*;
import mars.mips.hardware.*;
import mars.simulator.*;
package mars.mips.instructions.syscalls;
import mars.ProcessingException;
import mars.ProgramStatement;
import mars.mips.hardware.RegisterFile;
import mars.simulator.Exceptions;
import mars.util.SystemIO;
/*
Copyright (c) 2003-2008, Pete Sanderson and Kenneth Vollmar
@@ -33,37 +35,38 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
/**
* Service to read a character from input console into $a0.
*
*/
public class SyscallReadChar extends AbstractSyscall {
/**
* Build an instance of the Read Char syscall. Default service number
* is 12 and name is "ReadChar".
*/
public SyscallReadChar() {
super(12, "ReadChar");
}
/**
* Performs syscall function to read a character from input console into $a0
*/
public void simulate(ProgramStatement statement) throws ProcessingException {
int value = 0;
try
{
public class SyscallReadChar extends AbstractSyscall
{
/**
* Build an instance of the Read Char syscall. Default service number is 12 and name is "ReadChar".
*/
public SyscallReadChar()
{
super(12, "ReadChar");
}
/**
* Performs syscall function to read a character from input console into $a0
*/
public void simulate(ProgramStatement statement) throws ProcessingException
{
int value = 0;
try
{
value = SystemIO.readChar(this.getNumber());
}
catch (IndexOutOfBoundsException e) // means null input
{
throw new ProcessingException(statement,
"invalid char input (syscall "+this.getNumber()+")",
Exceptions.SYSCALL_EXCEPTION);
}
// DPS 20 June 2008: changed from 4 ($a0) to 2 ($v0)
RegisterFile.updateRegister(2, value);
}
}
}
catch (IndexOutOfBoundsException e) // means null input
{
throw new ProcessingException(statement,
"invalid char input (syscall " + this.getNumber() + ")",
Exceptions.SYSCALL_EXCEPTION);
}
// DPS 20 June 2008: changed from 4 ($a0) to 2 ($v0)
RegisterFile.updateRegister(2, value);
}
}
@@ -1,8 +1,11 @@
package mars.mips.instructions.syscalls;
import mars.util.*;
import mars.simulator.*;
import mars.mips.hardware.*;
import mars.*;
package mars.mips.instructions.syscalls;
import mars.ProcessingException;
import mars.ProgramStatement;
import mars.mips.hardware.Coprocessor1;
import mars.simulator.Exceptions;
import mars.util.Binary;
import mars.util.SystemIO;
/*
Copyright (c) 2003-2006, Pete Sanderson and Kenneth Vollmar
@@ -33,38 +36,39 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* Service to read the bits of console input double into $f0 and $f1.
* $f1 contains high order word of the double.
/**
* Service to read the bits of console input double into $f0 and $f1. $f1 contains high order word of the double.
*/
public class SyscallReadDouble extends AbstractSyscall {
/**
* Build an instance of the Read Double syscall. Default service number
* is 7 and name is "ReadDouble".
*/
public SyscallReadDouble() {
super(7, "ReadDouble");
}
/**
* Performs syscall function to read the bits of input double into $f0 and $f1.
*/
public void simulate(ProgramStatement statement) throws ProcessingException {
// Higher numbered reg contains high order word so order is $f1 - $f0.
double doubleValue = 0;
try
{
public class SyscallReadDouble extends AbstractSyscall
{
/**
* Build an instance of the Read Double syscall. Default service number is 7 and name is "ReadDouble".
*/
public SyscallReadDouble()
{
super(7, "ReadDouble");
}
/**
* Performs syscall function to read the bits of input double into $f0 and $f1.
*/
public void simulate(ProgramStatement statement) throws ProcessingException
{
// Higher numbered reg contains high order word so order is $f1 - $f0.
double doubleValue = 0;
try
{
doubleValue = SystemIO.readDouble(this.getNumber());
}
catch (NumberFormatException e)
{
throw new ProcessingException(statement,
"invalid double input (syscall "+this.getNumber()+")",
Exceptions.SYSCALL_EXCEPTION);
}
long longValue = Double.doubleToRawLongBits(doubleValue);
Coprocessor1.updateRegister(1, Binary.highOrderLongToInt(longValue));
Coprocessor1.updateRegister(0, Binary.lowOrderLongToInt(longValue));
}
}
}
catch (NumberFormatException e)
{
throw new ProcessingException(statement,
"invalid double input (syscall " + this.getNumber() + ")",
Exceptions.SYSCALL_EXCEPTION);
}
long longValue = Double.doubleToRawLongBits(doubleValue);
Coprocessor1.updateRegister(1, Binary.highOrderLongToInt(longValue));
Coprocessor1.updateRegister(0, Binary.lowOrderLongToInt(longValue));
}
}
@@ -1,8 +1,10 @@
package mars.mips.instructions.syscalls;
import mars.util.*;
import mars.simulator.*;
import mars.mips.hardware.*;
import mars.*;
package mars.mips.instructions.syscalls;
import mars.ProcessingException;
import mars.ProgramStatement;
import mars.mips.hardware.Coprocessor1;
import mars.simulator.Exceptions;
import mars.util.SystemIO;
/*
Copyright (c) 2003-2006, Pete Sanderson and Kenneth Vollmar
@@ -33,34 +35,36 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
/**
* Service to read the bits of input float into $f0
*/
public class SyscallReadFloat extends AbstractSyscall {
/**
* Build an instance of the Read Float syscall. Default service number
* is 6 and name is "ReadFloat".
*/
public SyscallReadFloat() {
super(6, "ReadFloat");
}
/**
* Performs syscall function to read the bits of input float into $f0
*/
public void simulate(ProgramStatement statement) throws ProcessingException {
float floatValue = 0;
try
{
public class SyscallReadFloat extends AbstractSyscall
{
/**
* Build an instance of the Read Float syscall. Default service number is 6 and name is "ReadFloat".
*/
public SyscallReadFloat()
{
super(6, "ReadFloat");
}
/**
* Performs syscall function to read the bits of input float into $f0
*/
public void simulate(ProgramStatement statement) throws ProcessingException
{
float floatValue = 0;
try
{
floatValue = SystemIO.readFloat(this.getNumber());
}
catch (NumberFormatException e)
{
throw new ProcessingException(statement,
"invalid float input (syscall "+this.getNumber()+")",
Exceptions.SYSCALL_EXCEPTION);
}
Coprocessor1.updateRegister(0, Float.floatToRawIntBits(floatValue));
}
}
}
catch (NumberFormatException e)
{
throw new ProcessingException(statement,
"invalid float input (syscall " + this.getNumber() + ")",
Exceptions.SYSCALL_EXCEPTION);
}
Coprocessor1.updateRegister(0, Float.floatToRawIntBits(floatValue));
}
}
@@ -1,8 +1,10 @@
package mars.mips.instructions.syscalls;
import mars.*;
import mars.util.*;
import mars.mips.hardware.*;
import mars.simulator.*;
package mars.mips.instructions.syscalls;
import mars.ProcessingException;
import mars.ProgramStatement;
import mars.mips.hardware.RegisterFile;
import mars.simulator.Exceptions;
import mars.util.SystemIO;
/*
Copyright (c) 2003-2006, Pete Sanderson and Kenneth Vollmar
@@ -33,36 +35,37 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
/**
* Service to read an integer from input console into $v0.
*
*/
public class SyscallReadInt extends AbstractSyscall {
/**
* Build an instance of the Read Integer syscall. Default service number
* is 5 and name is "ReadInt".
*/
public SyscallReadInt() {
super(5, "ReadInt");
}
/**
* Performs syscall function to read an integer from input console into $v0
*/
public void simulate(ProgramStatement statement) throws ProcessingException {
int value = 0;
try
{
public class SyscallReadInt extends AbstractSyscall
{
/**
* Build an instance of the Read Integer syscall. Default service number is 5 and name is "ReadInt".
*/
public SyscallReadInt()
{
super(5, "ReadInt");
}
/**
* Performs syscall function to read an integer from input console into $v0
*/
public void simulate(ProgramStatement statement) throws ProcessingException
{
int value = 0;
try
{
value = SystemIO.readInteger(this.getNumber());
}
catch (NumberFormatException e)
{
throw new ProcessingException(statement,
"invalid integer input (syscall "+this.getNumber()+")",
Exceptions.SYSCALL_EXCEPTION);
}
RegisterFile.updateRegister(2, value);
}
}
}
catch (NumberFormatException e)
{
throw new ProcessingException(statement,
"invalid integer input (syscall " + this.getNumber() + ")",
Exceptions.SYSCALL_EXCEPTION);
}
RegisterFile.updateRegister(2, value);
}
}
@@ -1,7 +1,11 @@
package mars.mips.instructions.syscalls;
import mars.util.*;
import mars.mips.hardware.*;
import mars.*;
package mars.mips.instructions.syscalls;
import mars.Globals;
import mars.ProcessingException;
import mars.ProgramStatement;
import mars.mips.hardware.AddressErrorException;
import mars.mips.hardware.RegisterFile;
import mars.util.SystemIO;
/*
Copyright (c) 2003-2006, Pete Sanderson and Kenneth Vollmar
@@ -32,56 +36,60 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* Service to read console input string into buffer starting at address in $a0.
/**
* Service to read console input string into buffer starting at address in $a0.
*/
public class SyscallReadString extends AbstractSyscall {
/**
* Build an instance of the Read String syscall. Default service number
* is 8 and name is "ReadString".
*/
public SyscallReadString() {
super(8, "ReadString");
}
/**
* Performs syscall function to read console input string into buffer starting at address in $a0.
* Follows semantics of UNIX 'fgets'. For specified length n,
* string can be no longer than n-1. If less than that, add
* newline to end. In either case, then pad with null byte.
*/
public void simulate(ProgramStatement statement) throws ProcessingException {
String inputString = "";
int buf = RegisterFile.getValue(4); // buf addr in $a0
int maxLength = RegisterFile.getValue(5) - 1; // $a1
boolean addNullByte = true;
// Guard against negative maxLength. DPS 13-July-2011
if (maxLength < 0)
{
public class SyscallReadString extends AbstractSyscall
{
/**
* Build an instance of the Read String syscall. Default service number is 8 and name is "ReadString".
*/
public SyscallReadString()
{
super(8, "ReadString");
}
/**
* Performs syscall function to read console input string into buffer starting at address in $a0. Follows semantics
* of UNIX 'fgets'. For specified length n, string can be no longer than n-1. If less than that, add newline to
* end. In either case, then pad with null byte.
*/
public void simulate(ProgramStatement statement) throws ProcessingException
{
String inputString = "";
int buf = RegisterFile.getValue(4); // buf addr in $a0
int maxLength = RegisterFile.getValue(5) - 1; // $a1
boolean addNullByte = true;
// Guard against negative maxLength. DPS 13-July-2011
if (maxLength < 0)
{
maxLength = 0;
addNullByte = false;
}
inputString = SystemIO.readString(this.getNumber(), maxLength);
int stringLength = Math.min(maxLength, inputString.length());
try
{
addNullByte = false;
}
inputString = SystemIO.readString(this.getNumber(), maxLength);
int stringLength = Math.min(maxLength, inputString.length());
try
{
for (int index = 0; index < stringLength; index++)
{
Globals.memory.setByte(buf + index,
inputString.charAt(index));
}
Globals.memory.setByte(buf + index,
inputString.charAt(index));
}
if (stringLength < maxLength)
{
Globals.memory.setByte(buf + stringLength, '\n');
stringLength++;
Globals.memory.setByte(buf + stringLength, '\n');
stringLength++;
}
if (addNullByte) Globals.memory.setByte(buf + stringLength, 0);
}
catch (AddressErrorException e)
if (addNullByte)
{
throw new ProcessingException(statement, e);
Globals.memory.setByte(buf + stringLength, 0);
}
}
}
}
catch (AddressErrorException e)
{
throw new ProcessingException(statement, e);
}
}
}
@@ -1,8 +1,10 @@
package mars.mips.instructions.syscalls;
import mars.util.*;
import mars.simulator.*;
import mars.mips.hardware.*;
import mars.*;
package mars.mips.instructions.syscalls;
import mars.Globals;
import mars.ProcessingException;
import mars.ProgramStatement;
import mars.mips.hardware.RegisterFile;
import mars.simulator.Exceptions;
/*
Copyright (c) 2003-2006, Pete Sanderson and Kenneth Vollmar
@@ -33,33 +35,36 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
/**
* Service to allocate amount of heap memory specified in $a0, putting address into $v0.
*
*/
public class SyscallSbrk extends AbstractSyscall {
/**
* Build an instance of the Sbrk syscall. Default service number
* is 9 and name is "Sbrk".
*/
public SyscallSbrk() {
super(9, "Sbrk");
}
/**
* Performs syscall function to allocate amount of heap memory specified in $a0, putting address into $v0.
*/
public void simulate(ProgramStatement statement) throws ProcessingException {
int address = 0;
try {
public class SyscallSbrk extends AbstractSyscall
{
/**
* Build an instance of the Sbrk syscall. Default service number is 9 and name is "Sbrk".
*/
public SyscallSbrk()
{
super(9, "Sbrk");
}
/**
* Performs syscall function to allocate amount of heap memory specified in $a0, putting address into $v0.
*/
public void simulate(ProgramStatement statement) throws ProcessingException
{
int address = 0;
try
{
address = Globals.memory.allocateBytesFromHeap(RegisterFile.getValue(4));
}
catch (IllegalArgumentException iae) {
throw new ProcessingException(statement,
iae.getMessage()+" (syscall "+this.getNumber()+")",
Exceptions.SYSCALL_EXCEPTION);
}
RegisterFile.updateRegister(2, address);
}
}
}
catch (IllegalArgumentException iae)
{
throw new ProcessingException(statement,
iae.getMessage() + " (syscall " + this.getNumber() + ")",
Exceptions.SYSCALL_EXCEPTION);
}
RegisterFile.updateRegister(2, address);
}
}
@@ -1,8 +1,8 @@
package mars.mips.instructions.syscalls;
import mars.util.*;
import mars.mips.hardware.*;
import mars.simulator.*;
import mars.*;
package mars.mips.instructions.syscalls;
import mars.ProcessingException;
import mars.ProgramStatement;
import mars.mips.hardware.RegisterFile;
/*
Copyright (c) 2003-2008, Pete Sanderson and Kenneth Vollmar
@@ -34,34 +34,36 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
/**
* Service to cause the MARS Java thread to sleep for (at least) the specified number of milliseconds.
* This timing will not be precise as the Java implementation will add some overhead.
*
* Service to cause the MARS Java thread to sleep for (at least) the specified number of milliseconds. This timing will
* not be precise as the Java implementation will add some overhead.
*/
public class SyscallSleep extends AbstractSyscall {
/**
* Build an instance of the syscall with its default service number and name.
*/
public SyscallSleep() {
super(32, "Sleep");
}
public class SyscallSleep extends AbstractSyscall
{
/**
* Build an instance of the syscall with its default service number and name.
*/
public SyscallSleep()
{
super(32, "Sleep");
}
/**
* System call to cause the MARS Java thread to sleep for (at least) the specified number of milliseconds.
* This timing will not be precise as the Java implementation will add some overhead.
*/
public void simulate(ProgramStatement statement) throws ProcessingException {
// Input arguments: $a0 is the length of time to sleep in milliseconds.
/**
* System call to cause the MARS Java thread to sleep for (at least) the specified number of milliseconds. This
* timing will not be precise as the Java implementation will add some overhead.
*/
public void simulate(ProgramStatement statement) throws ProcessingException
{
// Input arguments: $a0 is the length of time to sleep in milliseconds.
try
{
Thread.sleep(RegisterFile.getValue(4)); // units of milliseconds 1000 millisec = 1 sec.
}
catch (InterruptedException e)
{
return; // no exception handling
}
}
try
{
Thread.sleep(RegisterFile.getValue(4)); // units of milliseconds 1000 millisec = 1 sec.
}
catch (InterruptedException e)
{
// no exception handling
}
}
}
}
@@ -1,7 +1,9 @@
package mars.mips.instructions.syscalls;
import mars.*;
import mars.util.*;
import mars.mips.hardware.*;
package mars.mips.instructions.syscalls;
import mars.ProcessingException;
import mars.ProgramStatement;
import mars.mips.hardware.RegisterFile;
import mars.util.Binary;
/*
Copyright (c) 2003-2007, Pete Sanderson and Kenneth Vollmar
@@ -32,28 +34,29 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
/**
* Service to read a character from input console into $a0.
*
*/
public class SyscallTime extends AbstractSyscall {
/**
* Build an instance of the Read Char syscall. Default service number
* is 12 and name is "ReadChar".
*/
public SyscallTime() {
super(30, "Time");
}
/**
* Performs syscall function to place current system time into $a0 (low order 32 bits)
* and $a1 (high order 32 bits).
*/
public void simulate(ProgramStatement statement) throws ProcessingException {
long value = new java.util.Date().getTime();
RegisterFile.updateRegister(4, Binary.lowOrderLongToInt(value)); // $a0
RegisterFile.updateRegister(5, Binary.highOrderLongToInt(value)); // $a1
}
}
public class SyscallTime extends AbstractSyscall
{
/**
* Build an instance of the Read Char syscall. Default service number is 12 and name is "ReadChar".
*/
public SyscallTime()
{
super(30, "Time");
}
/**
* Performs syscall function to place current system time into $a0 (low order 32 bits) and $a1 (high order 32
* bits).
*/
public void simulate(ProgramStatement statement) throws ProcessingException
{
long value = new java.util.Date().getTime();
RegisterFile.updateRegister(4, Binary.lowOrderLongToInt(value)); // $a0
RegisterFile.updateRegister(5, Binary.highOrderLongToInt(value)); // $a1
}
}
@@ -1,8 +1,11 @@
package mars.mips.instructions.syscalls;
import mars.util.*;
import mars.mips.hardware.*;
import mars.simulator.*;
import mars.*;
package mars.mips.instructions.syscalls;
import mars.Globals;
import mars.ProcessingException;
import mars.ProgramStatement;
import mars.mips.hardware.AddressErrorException;
import mars.mips.hardware.RegisterFile;
import mars.util.SystemIO;
/*
Copyright (c) 2003-2009, Pete Sanderson and Kenneth Vollmar
@@ -33,60 +36,60 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* Service to write to file descriptor given in $a0. $a1 specifies buffer
* and $a2 specifies length. Number of characters written is returned in $v0
* (this was changed from $a0 in MARS 3.7 for SPIM compatibility. The table
* in COD erroneously shows $a0).
*
/**
* Service to write to file descriptor given in $a0. $a1 specifies buffer and $a2 specifies length. Number of
* characters written is returned in $v0 (this was changed from $a0 in MARS 3.7 for SPIM compatibility. The table in
* COD erroneously shows $a0).
*/
public class SyscallWrite extends AbstractSyscall {
/**
* Build an instance of the Write file syscall. Default service number
* is 15 and name is "Write".
*/
public SyscallWrite() {
super(15, "Write");
}
/**
* Performs syscall function to write to file descriptor given in $a0. $a1 specifies buffer
* and $a2 specifies length. Number of characters written is returned in $v0, starting in MARS 3.7.
*/
public void simulate(ProgramStatement statement) throws ProcessingException {
int byteAddress = RegisterFile.getValue(5); // source of characters to write to file
byte b = 0;
int reqLength = RegisterFile.getValue(6); // user-requested length
int index = 0;
byte myBuffer[] = new byte[RegisterFile.getValue(6) + 1]; // specified length plus null termination
try
{
b = (byte) Globals.memory.getByte(byteAddress);
while (index < reqLength) // Stop at requested length. Null bytes are included.
// while (index < reqLength && b != 0) // Stop at requested length OR null byte
{
myBuffer[index++] = b;
byteAddress++;
b = (byte) Globals.memory.getByte(byteAddress);
}
myBuffer[index] = 0; // Add string termination
} // end try
catch (AddressErrorException e)
{
throw new ProcessingException(statement, e);
}
int retValue = SystemIO.writeToFile(
RegisterFile.getValue(4), // fd
myBuffer, // buffer
RegisterFile.getValue(6)); // length
RegisterFile.updateRegister(2, retValue); // set returned value in register
// Getting rid of processing exception. It is the responsibility of the
// user program to check the syscall's return value. MARS should not
// re-emptively terminate MIPS execution because of it. Thanks to
// UCLA student Duy Truong for pointing this out. DPS 28-July-2009
public class SyscallWrite extends AbstractSyscall
{
/**
* Build an instance of the Write file syscall. Default service number is 15 and name is "Write".
*/
public SyscallWrite()
{
super(15, "Write");
}
/**
* Performs syscall function to write to file descriptor given in $a0. $a1 specifies buffer and $a2 specifies
* length. Number of characters written is returned in $v0, starting in MARS 3.7.
*/
public void simulate(ProgramStatement statement) throws ProcessingException
{
int byteAddress = RegisterFile.getValue(5); // source of characters to write to file
byte b = 0;
int reqLength = RegisterFile.getValue(6); // user-requested length
int index = 0;
byte[] myBuffer = new byte[RegisterFile.getValue(6) + 1]; // specified length plus null termination
try
{
b = (byte) Globals.memory.getByte(byteAddress);
while (index < reqLength) // Stop at requested length. Null bytes are included.
// while (index < reqLength && b != 0) // Stop at requested length OR null byte
{
myBuffer[index++] = b;
byteAddress++;
b = (byte) Globals.memory.getByte(byteAddress);
}
myBuffer[index] = 0; // Add string termination
} // end try
catch (AddressErrorException e)
{
throw new ProcessingException(statement, e);
}
int retValue = SystemIO.writeToFile(
RegisterFile.getValue(4), // fd
myBuffer, // buffer
RegisterFile.getValue(6)); // length
RegisterFile.updateRegister(2, retValue); // set returned value in register
// Getting rid of processing exception. It is the responsibility of the
// user program to check the syscall's return value. MARS should not
// re-emptively terminate MIPS execution because of it. Thanks to
// UCLA student Duy Truong for pointing this out. DPS 28-July-2009
/*
if (retValue < 0) // some error in opening file
{
@@ -94,5 +97,5 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
SystemIO.getFileErrorMessage());
}
*/
}
}
}
}
@@ -1,12 +1,11 @@
package mars.mips.instructions.syscalls;
package mars.mips.instructions.syscalls;
import javax.sound.midi.*;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import javax.sound.midi.*;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/*
Copyright (c) 2003-2007, Pete Sanderson and Kenneth Vollmar
@@ -36,248 +35,261 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
(MIT license, http://www.opensource.org/licenses/mit-license.html)
*/
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
//
// The ToneGenerator and Tone classes were developed by Otterbein College
// student Tony Brock in July 2007. They simulate MIDI output through the
// computers soundcard using classes and methods of the javax.sound.midi
// package.
//
// Max Hailperin <max@gustavus.edu> changed the interface of the
// ToneGenerator class 2009-10-19 in order to
// (1) provide a reliable way to wait for the completion of a
// synchronous tone,
// and while he was at it,
// (2) improve the efficiency of asynchronous tones by using a thread
// pool executor, and
// (3) simplify the interface by removing all the unused versions
// that provided default values for various parameters
/////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
/*
* Creates a Tone object and passes it to a thread to "play" it using MIDI.
*/
class ToneGenerator {
/**
* The default pitch value for the tone: 60 / middle C.
*/
public final static byte DEFAULT_PITCH = 60;
/**
* The default duration of the tone: 1000 milliseconds.
*/
public final static int DEFAULT_DURATION = 1000;
/**
* The default instrument of the tone: 0 / piano.
*/
public final static byte DEFAULT_INSTRUMENT = 0;
/**
* The default volume of the tone: 100 (of 127).
*/
public final static byte DEFAULT_VOLUME = 100;
private static Executor threadPool = Executors.newCachedThreadPool();
/**
* Produces a Tone with the specified pitch, duration, and instrument,
* and volume.
*
* @param pitch the desired pitch in semitones - 0-127 where 60 is
* middle C.
* @param duration the desired duration in milliseconds.
* @param instrument the desired instrument (or patch) represented
* by a positive byte value (0-127). See the <a href=
* http://www.midi.org/about-midi/gm/gm1sound.shtml#instrument>general
* MIDI instrument patch map</a> for more instruments associated with
* each value.
* @param volume the desired volume of the initial attack of the
* Tone (MIDI velocity) represented by a positive byte value (0-127).
*/
public void generateTone(byte pitch, int duration,
byte instrument, byte volume) {
Runnable tone = new Tone(pitch, duration, instrument, volume);
threadPool.execute(tone);
}
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
//
// The ToneGenerator and Tone classes were developed by Otterbein College
// student Tony Brock in July 2007. They simulate MIDI output through the
// computers soundcard using classes and methods of the javax.sound.midi
// package.
//
// Max Hailperin <max@gustavus.edu> changed the interface of the
// ToneGenerator class 2009-10-19 in order to
// (1) provide a reliable way to wait for the completion of a
// synchronous tone,
// and while he was at it,
// (2) improve the efficiency of asynchronous tones by using a thread
// pool executor, and
// (3) simplify the interface by removing all the unused versions
// that provided default values for various parameters
/////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
/**
* Produces a Tone with the specified pitch, duration, and instrument,
* and volume, waiting for it to finish playing.
*
* @param pitch the desired pitch in semitones - 0-127 where 60 is
* middle C.
* @param duration the desired duration in milliseconds.
* @param instrument the desired instrument (or patch) represented
* by a positive byte value (0-127). See the <a href=
* http://www.midi.org/about-midi/gm/gm1sound.shtml#instrument>general
* MIDI instrument patch map</a> for more instruments associated with
* each value.
* @param volume the desired volume of the initial attack of the
* Tone (MIDI velocity) represented by a positive byte value (0-127).
*/
public void generateToneSynchronously(byte pitch, int duration,
byte instrument, byte volume) {
Runnable tone = new Tone(pitch, duration, instrument, volume);
tone.run();
}
}
/**
* Contains important variables for a MIDI Tone: pitch, duration
* instrument (patch), and volume. The tone can be passed to a thread
* and will be played using MIDI.
*/
class Tone implements Runnable {
/**
* Tempo of the tone is in milliseconds: 1000 beats per second.
*/
public final static int TEMPO = 1000;
/**
* The default MIDI channel of the tone: 0 (channel 1).
*/
public final static int DEFAULT_CHANNEL = 0;
private byte pitch;
private int duration;
private byte instrument;
private byte volume;
/**
* Instantiates a new Tone object, initializing the tone's pitch,
* duration, instrument (patch), and volume.
*
* @param pitch the pitch in semitones. Pitch is represented by
* a positive byte value - 0-127 where 60 is middle C.
* @param duration the duration of the tone in milliseconds.
* @param instrument a positive byte value (0-127) which represents
* the instrument (or patch) of the tone. See the <a href=
* http://www.midi.org/about-midi/gm/gm1sound.shtml#instrument>general
* MIDI instrument patch map</a> for more instruments associated with
* each value.
* @param volume a positive byte value (0-127) which represents the
* volume of the initial attack of the note (MIDI velocity). 127 being
* loud, and 0 being silent.
*/
public Tone(byte pitch, int duration, byte instrument, byte volume) {
this.pitch = pitch;
this.duration = duration;
this.instrument = instrument;
this.volume = volume;
}
/**
* Plays the tone.
*/
public void run() {
playTone();
}
/* The following lock and the code which locks and unlocks it
* around the opening of the Sequencer were added 2009-10-19 by
* Max Hailperin <max@gustavus.edu> in order to work around a
* bug in Sun's JDK which causes crashing if two threads race:
* http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6888117 .
* This routinely manifested native-code crashes when tones
* were played asynchronously, on dual-core machines with Sun's
* JDK (but not on one core or with OpenJDK). Even when tones
* were played only synchronously, crashes sometimes occurred.
* This is likely due to the fact that Thread.sleep was used
* for synchronization, a role it cannot reliably serve. In
* any case, this one lock seems to make all the crashes go
* away, and the sleeps are being eliminated (since they can
* cause other, less severe, problems), so that case should be
* double covered. */
private static Lock openLock = new ReentrantLock();
/*
* Creates a Tone object and passes it to a thread to "play" it using MIDI.
*/
class ToneGenerator
{
/**
* The default pitch value for the tone: 60 / middle C.
*/
public final static byte DEFAULT_PITCH = 60;
/**
* The default duration of the tone: 1000 milliseconds.
*/
public final static int DEFAULT_DURATION = 1000;
/**
* The default instrument of the tone: 0 / piano.
*/
public final static byte DEFAULT_INSTRUMENT = 0;
/**
* The default volume of the tone: 100 (of 127).
*/
public final static byte DEFAULT_VOLUME = 100;
private static final Executor threadPool = Executors.newCachedThreadPool();
/**
* Produces a Tone with the specified pitch, duration, and instrument, and volume.
*
* @param pitch the desired pitch in semitones - 0-127 where 60 is middle C.
* @param duration the desired duration in milliseconds.
* @param instrument the desired instrument (or patch) represented by a positive byte value (0-127). See the <a
* href= http://www.midi.org/about-midi/gm/gm1sound.shtml#instrument>general MIDI instrument patch map</a> for
* more instruments associated with each value.
* @param volume the desired volume of the initial attack of the Tone (MIDI velocity) represented by a positive
* byte value (0-127).
*/
public void generateTone(byte pitch, int duration,
byte instrument, byte volume)
{
Runnable tone = new Tone(pitch, duration, instrument, volume);
threadPool.execute(tone);
}
/**
* Produces a Tone with the specified pitch, duration, and instrument, and volume, waiting for it to finish
* playing.
*
* @param pitch the desired pitch in semitones - 0-127 where 60 is middle C.
* @param duration the desired duration in milliseconds.
* @param instrument the desired instrument (or patch) represented by a positive byte value (0-127). See the <a
* href= http://www.midi.org/about-midi/gm/gm1sound.shtml#instrument>general MIDI instrument patch map</a> for
* more instruments associated with each value.
* @param volume the desired volume of the initial attack of the Tone (MIDI velocity) represented by a positive
* byte value (0-127).
*/
public void generateToneSynchronously(byte pitch, int duration,
byte instrument, byte volume)
{
Runnable tone = new Tone(pitch, duration, instrument, volume);
tone.run();
}
}
/**
* Contains important variables for a MIDI Tone: pitch, duration instrument (patch), and volume. The tone can be passed
* to a thread and will be played using MIDI.
*/
class Tone implements Runnable
{
/**
* Tempo of the tone is in milliseconds: 1000 beats per second.
*/
public final static int TEMPO = 1000;
/**
* The default MIDI channel of the tone: 0 (channel 1).
*/
public final static int DEFAULT_CHANNEL = 0;
private static final Lock openLock = new ReentrantLock();
private final byte pitch;
private final int duration;
private final byte instrument;
private final byte volume;
/**
* Instantiates a new Tone object, initializing the tone's pitch, duration, instrument (patch), and volume.
*
* @param pitch the pitch in semitones. Pitch is represented by a positive byte value - 0-127 where 60 is
* middle C.
* @param duration the duration of the tone in milliseconds.
* @param instrument a positive byte value (0-127) which represents the instrument (or patch) of the tone. See
* the <a href= http://www.midi.org/about-midi/gm/gm1sound.shtml#instrument>general MIDI instrument patch
* map</a> for more instruments associated with each value.
* @param volume a positive byte value (0-127) which represents the volume of the initial attack of the note
* (MIDI velocity). 127 being loud, and 0 being silent.
*/
public Tone(byte pitch, int duration, byte instrument, byte volume)
{
this.pitch = pitch;
this.duration = duration;
this.instrument = instrument;
this.volume = volume;
}
/* The following lock and the code which locks and unlocks it
* around the opening of the Sequencer were added 2009-10-19 by
* Max Hailperin <max@gustavus.edu> in order to work around a
* bug in Sun's JDK which causes crashing if two threads race:
* http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6888117 .
* This routinely manifested native-code crashes when tones
* were played asynchronously, on dual-core machines with Sun's
* JDK (but not on one core or with OpenJDK). Even when tones
* were played only synchronously, crashes sometimes occurred.
* This is likely due to the fact that Thread.sleep was used
* for synchronization, a role it cannot reliably serve. In
* any case, this one lock seems to make all the crashes go
* away, and the sleeps are being eliminated (since they can
* cause other, less severe, problems), so that case should be
* double covered. */
/**
* Plays the tone.
*/
public void run()
{
playTone();
}
private void playTone()
{
try
{
Sequencer player = null;
openLock.lock();
try
{
player = MidiSystem.getSequencer();
player.open();
}
finally
{
openLock.unlock();
}
private void playTone() {
try {
Sequencer player = null;
openLock.lock();
try {
player = MidiSystem.getSequencer();
player.open();
} finally {
openLock.unlock();
}
Sequence seq = new Sequence(Sequence.PPQ, 1);
player.setTempoInMPQ(TEMPO);
Track t = seq.createTrack();
Track t = seq.createTrack();
//select instrument
ShortMessage inst = new ShortMessage();
inst.setMessage(ShortMessage.PROGRAM_CHANGE, DEFAULT_CHANNEL, instrument, 0);
MidiEvent instChange = new MidiEvent(inst, 0);
t.add(instChange);
ShortMessage on = new ShortMessage();
on.setMessage(ShortMessage.NOTE_ON, DEFAULT_CHANNEL, pitch, volume);
MidiEvent noteOn = new MidiEvent(on, 0);
t.add(noteOn);
ShortMessage off = new ShortMessage();
off.setMessage(ShortMessage.NOTE_OFF, DEFAULT_CHANNEL, pitch, volume);
MidiEvent noteOff = new MidiEvent(off, duration);
t.add(noteOff);
player.setSequence(seq);
/* The EndOfTrackListener was added 2009-10-19 by Max
* Hailperin <max@gustavus.edu> so that its
* awaitEndOfTrack method could be used as a more reliable
* replacement for Thread.sleep. (Given that the tone
* might not start playing right away, the sleep could end
* before the tone, clipping off the end of the tone.) */
EndOfTrackListener eot = new EndOfTrackListener();
player.addMetaEventListener(eot);
/* The EndOfTrackListener was added 2009-10-19 by Max
* Hailperin <max@gustavus.edu> so that its
* awaitEndOfTrack method could be used as a more reliable
* replacement for Thread.sleep. (Given that the tone
* might not start playing right away, the sleep could end
* before the tone, clipping off the end of the tone.) */
EndOfTrackListener eot = new EndOfTrackListener();
player.addMetaEventListener(eot);
player.start();
try {
eot.awaitEndOfTrack();
}
catch (InterruptedException ex) {
}
finally {
player.close();
try
{
eot.awaitEndOfTrack();
}
}
catch (MidiUnavailableException mue) {
mue.printStackTrace();
}
catch (InvalidMidiDataException imde) {
imde.printStackTrace();
catch (InterruptedException ex)
{
}
finally
{
player.close();
}
}
}
class EndOfTrackListener implements javax.sound.midi.MetaEventListener {
private boolean endedYet = false;
public synchronized void meta(javax.sound.midi.MetaMessage m){
if(m.getType() == 47){
endedYet = true;
notifyAll();
}
}
public synchronized void awaitEndOfTrack() throws InterruptedException {
while(!endedYet){
wait();
}
}
}
catch (MidiUnavailableException mue)
{
mue.printStackTrace();
}
catch (InvalidMidiDataException imde)
{
imde.printStackTrace();
}
}
}
class EndOfTrackListener implements javax.sound.midi.MetaEventListener
{
private boolean endedYet = false;
public synchronized void meta(javax.sound.midi.MetaMessage m)
{
if (m.getType() == 47)
{
endedYet = true;
notifyAll();
}
}
public synchronized void awaitEndOfTrack() throws InterruptedException
{
while (!endedYet)
{
wait();
}
}
}
+463 -389
View File
@@ -1,9 +1,11 @@
package mars.simulator;
import mars.*;
import mars.venus.*;
import mars.mips.hardware.*;
import mars.mips.instructions.*;
import java.util.*;
package mars.simulator;
import mars.Globals;
import mars.ProgramStatement;
import mars.mips.hardware.Coprocessor0;
import mars.mips.hardware.Coprocessor1;
import mars.mips.hardware.RegisterFile;
import mars.mips.instructions.Instruction;
/*
Copyright (c) 2003-2006, Pete Sanderson and Kenneth Vollmar
@@ -35,332 +37,387 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
/**
* Used to "step backward" through execution, undoing each instruction.
*
* @author Pete Sanderson
* @version February 2006
*/
public class BackStepper {
// The types of "undo" actions. Under 1.5, these would be enumerated type.
// These fit better in the BackStep class below but inner classes cannot have static members.
private static final int MEMORY_RESTORE_RAW_WORD = 0;
private static final int MEMORY_RESTORE_WORD = 1;
private static final int MEMORY_RESTORE_HALF = 2;
private static final int MEMORY_RESTORE_BYTE = 3;
private static final int REGISTER_RESTORE = 4;
private static final int PC_RESTORE = 5;
private static final int COPROC0_REGISTER_RESTORE = 6;
private static final int COPROC1_REGISTER_RESTORE = 7;
private static final int COPROC1_CONDITION_CLEAR = 8;
private static final int COPROC1_CONDITION_SET = 9;
private static final int DO_NOTHING = 10; // instruction does not write anything.
// Flag to mark BackStep object as prepresenting specific situation: user manipulates
// memory/register value via GUI after assembling program but before running it.
private static final int NOT_PC_VALUE = -1;
private boolean engaged;
private BackstepStack backSteps;
// One can argue using java.util.Stack, given its clumsy implementation.
// A homegrown linked implementation will be more streamlined, but
// I anticipate that backstepping will only be used during timed
// (currently max 30 instructions/second) or stepped execution, where
// performance is not an issue. Its Vector implementation may result
// in quicker garbage collection than a pure linked list implementation.
/**
* Create a fresh BackStepper. It is enabled, which means all
* subsequent instruction executions will have their "undo" action
* recorded here.
*/
public BackStepper() {
engaged = true;
backSteps = new BackstepStack(Globals.maximumBacksteps);
}
/**
* Determine whether execution "undo" steps are currently being recorded.
* @return true if undo steps being recorded, false if not.
*/
public boolean enabled() {
return engaged;
}
/**
* Set enable status.
* @param state If true, will begin (or continue) recoding "undo" steps. If false, will stop.
*/
public void setEnabled(boolean state) {
engaged = state;
}
/**
* Test whether there are steps that can be undone.
* @return true if there are no steps to be undone, false otherwise.
*/
public boolean empty() {
return backSteps.empty();
}
/**
* Determine whether the next back-step action occurred as the result of
* an instruction that executed in the "delay slot" of a delayed branch.
* @return true if next backstep is instruction that executed in delay slot,
* false otherwise.
*/
// Added 25 June 2007
public boolean inDelaySlot() {
return !empty() && backSteps.peek().inDelaySlot;
}
/**
* Carry out a "back step", which will undo the latest execution step.
* Does nothing if backstepping not enabled or if there are no steps to undo.
*/
// Note that there may be more than one "step" in an instruction execution; for
// instance the multiply, divide, and double-precision floating point operations
// all store their result in register pairs which results in two store operations.
// Both must be undone transparently, so we need to detect that multiple steps happen
// together and carry out all of them here.
// Use a do-while loop based on the backstep's program statement reference.
public void backStep() {
if (engaged && !backSteps.empty()) {
ProgramStatement statement = ((BackStep)backSteps.peek()).ps;
public class BackStepper
{
// The types of "undo" actions. Under 1.5, these would be enumerated type.
// These fit better in the BackStep class below but inner classes cannot have static members.
private static final int MEMORY_RESTORE_RAW_WORD = 0;
private static final int MEMORY_RESTORE_WORD = 1;
private static final int MEMORY_RESTORE_HALF = 2;
private static final int MEMORY_RESTORE_BYTE = 3;
private static final int REGISTER_RESTORE = 4;
private static final int PC_RESTORE = 5;
private static final int COPROC0_REGISTER_RESTORE = 6;
private static final int COPROC1_REGISTER_RESTORE = 7;
private static final int COPROC1_CONDITION_CLEAR = 8;
private static final int COPROC1_CONDITION_SET = 9;
private static final int DO_NOTHING = 10; // instruction does not write anything.
// Flag to mark BackStep object as prepresenting specific situation: user manipulates
// memory/register value via GUI after assembling program but before running it.
private static final int NOT_PC_VALUE = -1;
private boolean engaged;
private final BackstepStack backSteps;
// One can argue using java.util.Stack, given its clumsy implementation.
// A homegrown linked implementation will be more streamlined, but
// I anticipate that backstepping will only be used during timed
// (currently max 30 instructions/second) or stepped execution, where
// performance is not an issue. Its Vector implementation may result
// in quicker garbage collection than a pure linked list implementation.
/**
* Create a fresh BackStepper. It is enabled, which means all subsequent instruction executions will have their
* "undo" action recorded here.
*/
public BackStepper()
{
engaged = true;
backSteps = new BackstepStack(Globals.maximumBacksteps);
}
/**
* Determine whether execution "undo" steps are currently being recorded.
*
* @return true if undo steps being recorded, false if not.
*/
public boolean enabled()
{
return engaged;
}
/**
* Set enable status.
*
* @param state If true, will begin (or continue) recoding "undo" steps. If false, will stop.
*/
public void setEnabled(boolean state)
{
engaged = state;
}
/**
* Test whether there are steps that can be undone.
*
* @return true if there are no steps to be undone, false otherwise.
*/
public boolean empty()
{
return backSteps.empty();
}
/**
* Determine whether the next back-step action occurred as the result of an instruction that executed in the "delay
* slot" of a delayed branch.
*
* @return true if next backstep is instruction that executed in delay slot, false otherwise.
*/
// Added 25 June 2007
public boolean inDelaySlot()
{
return !empty() && backSteps.peek().inDelaySlot;
}
/**
* Carry out a "back step", which will undo the latest execution step. Does nothing if backstepping not enabled or
* if there are no steps to undo.
*/
// Note that there may be more than one "step" in an instruction execution; for
// instance the multiply, divide, and double-precision floating point operations
// all store their result in register pairs which results in two store operations.
// Both must be undone transparently, so we need to detect that multiple steps happen
// together and carry out all of them here.
// Use a do-while loop based on the backstep's program statement reference.
public void backStep()
{
if (engaged && !backSteps.empty())
{
ProgramStatement statement = backSteps.peek().ps;
engaged = false; // GOTTA DO THIS SO METHOD CALL IN SWITCH WILL NOT RESULT IN NEW ACTION ON STACK!
do {
BackStep step = (BackStep) backSteps.pop();
do
{
BackStep step = backSteps.pop();
/*
System.out.println("backstep POP: action "+step.action+" pc "+mars.util.Binary.intToHexString(step.pc)+
" source "+((step.ps==null)? "none":step.ps.getSource())+
" parm1 "+step.param1+" parm2 "+step.param2);
*/
if (step.pc != NOT_PC_VALUE) {
RegisterFile.setProgramCounter(step.pc);
}
try {
switch (step.action) {
case MEMORY_RESTORE_RAW_WORD :
Globals.memory.setRawWord(step.param1, step.param2);
break;
case MEMORY_RESTORE_WORD :
Globals.memory.setWord(step.param1, step.param2);
break;
case MEMORY_RESTORE_HALF :
Globals.memory.setHalf(step.param1, step.param2);
break;
case MEMORY_RESTORE_BYTE :
Globals.memory.setByte(step.param1, step.param2);
break;
case REGISTER_RESTORE :
RegisterFile.updateRegister(step.param1, step.param2);
break;
case PC_RESTORE :
RegisterFile.setProgramCounter(step.param1);
break;
case COPROC0_REGISTER_RESTORE :
Coprocessor0.updateRegister(step.param1, step.param2);
break;
case COPROC1_REGISTER_RESTORE :
Coprocessor1.updateRegister(step.param1, step.param2);
break;
case COPROC1_CONDITION_CLEAR :
Coprocessor1.clearConditionFlag(step.param1);
break;
case COPROC1_CONDITION_SET :
Coprocessor1.setConditionFlag(step.param1);
break;
case DO_NOTHING :
break;
}
}
catch (Exception e) {
// if the original action did not cause an exception this will not either.
System.out.println("Internal MARS error: address exception while back-stepping.");
System.exit(0);
}
} while (!backSteps.empty() && statement == ((BackStep)backSteps.peek()).ps);
if (step.pc != NOT_PC_VALUE)
{
RegisterFile.setProgramCounter(step.pc);
}
try
{
switch (step.action)
{
case MEMORY_RESTORE_RAW_WORD:
Globals.memory.setRawWord(step.param1, step.param2);
break;
case MEMORY_RESTORE_WORD:
Globals.memory.setWord(step.param1, step.param2);
break;
case MEMORY_RESTORE_HALF:
Globals.memory.setHalf(step.param1, step.param2);
break;
case MEMORY_RESTORE_BYTE:
Globals.memory.setByte(step.param1, step.param2);
break;
case REGISTER_RESTORE:
RegisterFile.updateRegister(step.param1, step.param2);
break;
case PC_RESTORE:
RegisterFile.setProgramCounter(step.param1);
break;
case COPROC0_REGISTER_RESTORE:
Coprocessor0.updateRegister(step.param1, step.param2);
break;
case COPROC1_REGISTER_RESTORE:
Coprocessor1.updateRegister(step.param1, step.param2);
break;
case COPROC1_CONDITION_CLEAR:
Coprocessor1.clearConditionFlag(step.param1);
break;
case COPROC1_CONDITION_SET:
Coprocessor1.setConditionFlag(step.param1);
break;
case DO_NOTHING:
break;
}
}
catch (Exception e)
{
// if the original action did not cause an exception this will not either.
System.out.println("Internal MARS error: address exception while back-stepping.");
System.exit(0);
}
}
while (!backSteps.empty() && statement == backSteps.peek().ps);
engaged = true; // RESET IT (was disabled at top of loop -- see comment)
}
}
/* Convenience method called below to get program counter value. If it needs to be
* be modified (e.g. to subtract 4) that can be done here in one place.
*/
private int pc() {
// PC incremented prior to instruction simulation, so need to adjust for that.
return RegisterFile.getProgramCounter()-Instruction.INSTRUCTION_LENGTH;
}
/**
* Add a new "back step" (the undo action) to the stack. The action here
* is to restore a raw memory word value (setRawWord).
* @param address The affected memory address.
* @param value The "restore" value to be stored there.
* @return the argument value
*/
public int addMemoryRestoreRawWord(int address, int value) {
backSteps.push(MEMORY_RESTORE_RAW_WORD, pc(), address, value);
return value;
}
/**
* Add a new "back step" (the undo action) to the stack. The action here
* is to restore a memory word value.
* @param address The affected memory address.
* @param value The "restore" value to be stored there.
* @return the argument value
*/
public int addMemoryRestoreWord(int address, int value) {
backSteps.push(MEMORY_RESTORE_WORD, pc(), address, value);
return value;
}
/**
* Add a new "back step" (the undo action) to the stack. The action here
* is to restore a memory half-word value.
* @param address The affected memory address.
* @param value The "restore" value to be stored there, in low order half.
* @return the argument value
*/
public int addMemoryRestoreHalf(int address, int value) {
backSteps.push(MEMORY_RESTORE_HALF, pc(), address, value);
return value;
}
/**
* Add a new "back step" (the undo action) to the stack. The action here
* is to restore a memory byte value.
* @param address The affected memory address.
* @param value The "restore" value to be stored there, in low order byte.
* @return the argument value
*/
public int addMemoryRestoreByte(int address, int value) {
backSteps.push(MEMORY_RESTORE_BYTE, pc(), address, value);
return value;
}
/**
* Add a new "back step" (the undo action) to the stack. The action here
* is to restore a register file register value.
* @param register The affected register number.
* @param value The "restore" value to be stored there.
* @return the argument value
*/
public int addRegisterFileRestore(int register, int value) {
backSteps.push(REGISTER_RESTORE, pc(), register, value);
return value;
}
/**
* Add a new "back step" (the undo action) to the stack. The action here
* is to restore the program counter.
* @param value The "restore" value to be stored there.
* @return the argument value
*/
public int addPCRestore(int value) {
// adjust for value reflecting incremented PC.
value -= Instruction.INSTRUCTION_LENGTH;
// Use "value" insead of "pc()" for second arg because RegisterFile.getProgramCounter()
// returns branch target address at this point.
backSteps.push(PC_RESTORE, value, value);
return value;
}
/**
* Add a new "back step" (the undo action) to the stack. The action here
* is to restore a coprocessor 0 register value.
* @param register The affected register number.
* @param value The "restore" value to be stored there.
* @return the argument value
*/
public int addCoprocessor0Restore(int register, int value) {
backSteps.push(COPROC0_REGISTER_RESTORE, pc(), register, value);
return value;
}
/**
* Add a new "back step" (the undo action) to the stack. The action here
* is to restore a coprocessor 1 register value.
* @param register The affected register number.
* @param value The "restore" value to be stored there.
* @return the argument value
*/
public int addCoprocessor1Restore(int register, int value) {
backSteps.push(COPROC1_REGISTER_RESTORE, pc(), register, value);
return value;
}
/**
* Add a new "back step" (the undo action) to the stack. The action here
* is to set the given coprocessor 1 condition flag (to 1).
* @param flag The condition flag number.
* @return the argument value
*/
public int addConditionFlagSet(int flag) {
backSteps.push(COPROC1_CONDITION_SET, pc(), flag);
return flag;
}
/**
* Add a new "back step" (the undo action) to the stack. The action here
* is to clear the given coprocessor 1 condition flag (to 0).
* @param flag The condition flag number.
* @return the argument value
*/
public int addConditionFlagClear(int flag) {
backSteps.push(COPROC1_CONDITION_CLEAR, pc(), flag);
return flag;
}
/**
* Add a new "back step" (the undo action) to the stack. The action here
* is to do nothing! This is just a place holder so when user is backstepping
* through the program no instructions will be skipped. Cosmetic. If the top of the
* stack has the same PC counter, the do-nothing action will not be added.
* @return 0
*/
public int addDoNothing(int pc) {
if (backSteps.empty() || backSteps.peek().pc != pc) {
}
}
/* Convenience method called below to get program counter value. If it needs to be
* be modified (e.g. to subtract 4) that can be done here in one place.
*/
private int pc()
{
// PC incremented prior to instruction simulation, so need to adjust for that.
return RegisterFile.getProgramCounter() - Instruction.INSTRUCTION_LENGTH;
}
/**
* Add a new "back step" (the undo action) to the stack. The action here is to restore a raw memory word value
* (setRawWord).
*
* @param address The affected memory address.
* @param value The "restore" value to be stored there.
* @return the argument value
*/
public int addMemoryRestoreRawWord(int address, int value)
{
backSteps.push(MEMORY_RESTORE_RAW_WORD, pc(), address, value);
return value;
}
/**
* Add a new "back step" (the undo action) to the stack. The action here is to restore a memory word value.
*
* @param address The affected memory address.
* @param value The "restore" value to be stored there.
* @return the argument value
*/
public int addMemoryRestoreWord(int address, int value)
{
backSteps.push(MEMORY_RESTORE_WORD, pc(), address, value);
return value;
}
/**
* Add a new "back step" (the undo action) to the stack. The action here is to restore a memory half-word value.
*
* @param address The affected memory address.
* @param value The "restore" value to be stored there, in low order half.
* @return the argument value
*/
public int addMemoryRestoreHalf(int address, int value)
{
backSteps.push(MEMORY_RESTORE_HALF, pc(), address, value);
return value;
}
/**
* Add a new "back step" (the undo action) to the stack. The action here is to restore a memory byte value.
*
* @param address The affected memory address.
* @param value The "restore" value to be stored there, in low order byte.
* @return the argument value
*/
public int addMemoryRestoreByte(int address, int value)
{
backSteps.push(MEMORY_RESTORE_BYTE, pc(), address, value);
return value;
}
/**
* Add a new "back step" (the undo action) to the stack. The action here is to restore a register file register
* value.
*
* @param register The affected register number.
* @param value The "restore" value to be stored there.
* @return the argument value
*/
public int addRegisterFileRestore(int register, int value)
{
backSteps.push(REGISTER_RESTORE, pc(), register, value);
return value;
}
/**
* Add a new "back step" (the undo action) to the stack. The action here is to restore the program counter.
*
* @param value The "restore" value to be stored there.
* @return the argument value
*/
public int addPCRestore(int value)
{
// adjust for value reflecting incremented PC.
value -= Instruction.INSTRUCTION_LENGTH;
// Use "value" insead of "pc()" for second arg because RegisterFile.getProgramCounter()
// returns branch target address at this point.
backSteps.push(PC_RESTORE, value, value);
return value;
}
/**
* Add a new "back step" (the undo action) to the stack. The action here is to restore a coprocessor 0 register
* value.
*
* @param register The affected register number.
* @param value The "restore" value to be stored there.
* @return the argument value
*/
public int addCoprocessor0Restore(int register, int value)
{
backSteps.push(COPROC0_REGISTER_RESTORE, pc(), register, value);
return value;
}
/**
* Add a new "back step" (the undo action) to the stack. The action here is to restore a coprocessor 1 register
* value.
*
* @param register The affected register number.
* @param value The "restore" value to be stored there.
* @return the argument value
*/
public int addCoprocessor1Restore(int register, int value)
{
backSteps.push(COPROC1_REGISTER_RESTORE, pc(), register, value);
return value;
}
/**
* Add a new "back step" (the undo action) to the stack. The action here is to set the given coprocessor 1
* condition flag (to 1).
*
* @param flag The condition flag number.
* @return the argument value
*/
public int addConditionFlagSet(int flag)
{
backSteps.push(COPROC1_CONDITION_SET, pc(), flag);
return flag;
}
/**
* Add a new "back step" (the undo action) to the stack. The action here is to clear the given coprocessor 1
* condition flag (to 0).
*
* @param flag The condition flag number.
* @return the argument value
*/
public int addConditionFlagClear(int flag)
{
backSteps.push(COPROC1_CONDITION_CLEAR, pc(), flag);
return flag;
}
/**
* Add a new "back step" (the undo action) to the stack. The action here is to do nothing! This is just a place
* holder so when user is backstepping through the program no instructions will be skipped. Cosmetic. If the top of
* the stack has the same PC counter, the do-nothing action will not be added.
*
* @return 0
*/
public int addDoNothing(int pc)
{
if (backSteps.empty() || backSteps.peek().pc != pc)
{
backSteps.push(DO_NOTHING, pc);
}
return 0;
}
// Represents a "back step" (undo action) on the stack.
private class BackStep {
private int action; // what do do MEMORY_RESTORE_WORD, etc
private int pc; // program counter value when original step occurred
private ProgramStatement ps; // statement whose action is being "undone" here
private int param1; // first parameter required by that action
private int param2; // optional second parameter required by that action
private boolean inDelaySlot; // true if instruction executed in "delay slot" (delayed branching enabled)
// it is critical that BackStep object get its values by calling this method
// rather than assigning to individual members, because of the technique used
// to set its ps member (and possibly pc).
private void assign(int act, int programCounter, int parm1, int parm2) {
}
return 0;
}
// Represents a "back step" (undo action) on the stack.
private class BackStep
{
private int action; // what do do MEMORY_RESTORE_WORD, etc
private int pc; // program counter value when original step occurred
private ProgramStatement ps; // statement whose action is being "undone" here
private int param1; // first parameter required by that action
private int param2; // optional second parameter required by that action
private boolean inDelaySlot; // true if instruction executed in "delay slot" (delayed branching enabled)
// it is critical that BackStep object get its values by calling this method
// rather than assigning to individual members, because of the technique used
// to set its ps member (and possibly pc).
private void assign(int act, int programCounter, int parm1, int parm2)
{
action = act;
pc = programCounter;
try {
// Client does not have direct access to program statement, and rather than making all
// of them go through the methods below to obtain it, we will do it here.
// Want the program statement but do not want observers notified.
ps = Globals.memory.getStatementNoNotify(programCounter);
}
catch (Exception e) {
pc = programCounter;
try
{
// Client does not have direct access to program statement, and rather than making all
// of them go through the methods below to obtain it, we will do it here.
// Want the program statement but do not want observers notified.
ps = Globals.memory.getStatementNoNotify(programCounter);
}
catch (Exception e)
{
// The only situation causing this so far: user modifies memory or register
// contents through direct manipulation on the GUI, after assembling the program but
// before starting to run it (or after backstepping all the way to the start).
// The action will not be associated with any instruction, but will be carried out
// when popped.
ps = null;
pc = NOT_PC_VALUE; // Backstep method above will see this as flag to not set PC
}
ps = null;
pc = NOT_PC_VALUE; // Backstep method above will see this as flag to not set PC
}
param1 = parm1;
param2 = parm2;
inDelaySlot = Simulator.inDelaySlot(); // ADDED 25 June 2007
@@ -369,92 +426,109 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
" source "+((ps==null)? "none":ps.getSource())+
" parm1 "+param1+" parm2 "+param2);
*/
}
}
// *****************************************************************************
// special purpose stack class for backstepping. You've heard of circular queues
// implemented with an array, right? This is a circular stack! When full, the
// newly-pushed item overwrites the oldest item, with circular top! All operations
// are constant time. It's synchronized too, to be safe (is used by both the
// simulation thread and the GUI thread for the back-step button).
// Upon construction, it is filled with newly-created empty BackStep objects which
// will exist for the life of the stack. Push does not create a BackStep object
// but instead overwrites the contents of the existing one. Thus during MIPS
// program (simulated) execution, BackStep objects are never created or junked
// regardless of how many steps are executed. This will speed things up a bit
// and make life easier for the garbage collector.
private class BackstepStack {
private int capacity;
private int size;
private int top;
private BackStep[] stack;
// Stack is created upon successful assembly or reset. The one-time overhead of
// creating all the BackStep objects will not be noticed by the user, and enhances
// runtime performance by not having to create or recycle them during MIPS
// program execution.
private BackstepStack(int capacity) {
}
}
// *****************************************************************************
// special purpose stack class for backstepping. You've heard of circular queues
// implemented with an array, right? This is a circular stack! When full, the
// newly-pushed item overwrites the oldest item, with circular top! All operations
// are constant time. It's synchronized too, to be safe (is used by both the
// simulation thread and the GUI thread for the back-step button).
// Upon construction, it is filled with newly-created empty BackStep objects which
// will exist for the life of the stack. Push does not create a BackStep object
// but instead overwrites the contents of the existing one. Thus during MIPS
// program (simulated) execution, BackStep objects are never created or junked
// regardless of how many steps are executed. This will speed things up a bit
// and make life easier for the garbage collector.
private class BackstepStack
{
private final int capacity;
private int size;
private int top;
private final BackStep[] stack;
// Stack is created upon successful assembly or reset. The one-time overhead of
// creating all the BackStep objects will not be noticed by the user, and enhances
// runtime performance by not having to create or recycle them during MIPS
// program execution.
private BackstepStack(int capacity)
{
this.capacity = capacity;
this.size = 0;
this.top = -1;
this.stack = new BackStep[capacity];
for (int i=0; i<capacity; i++) {
this.stack[i] = new BackStep();
for (int i = 0; i < capacity; i++)
{
this.stack[i] = new BackStep();
}
}
private synchronized boolean empty() {
return size==0;
}
private synchronized void push(int act, int programCounter, int parm1, int parm2) {
if (size==0) {
top=0;
size++;
}
else if (size < capacity) {
top = (top + 1) % capacity;
size++;
}
else { // size == capacity. The top moves up one, replacing oldest entry (goodbye!)
top = (top + 1) % capacity;
}
private synchronized boolean empty()
{
return size == 0;
}
private synchronized void push(int act, int programCounter, int parm1, int parm2)
{
if (size == 0)
{
top = 0;
size++;
}
// We'll re-use existing objects rather than create/discard each time.
// Must use assign() method rather than series of assignment statements!
else if (size < capacity)
{
top = (top + 1) % capacity;
size++;
}
else
{ // size == capacity. The top moves up one, replacing oldest entry (goodbye!)
top = (top + 1) % capacity;
}
// We'll re-use existing objects rather than create/discard each time.
// Must use assign() method rather than series of assignment statements!
stack[top].assign(act, programCounter, parm1, parm2);
}
private synchronized void push(int act, int programCounter, int parm1) {
}
private synchronized void push(int act, int programCounter, int parm1)
{
push(act, programCounter, parm1, 0);
}
private synchronized void push(int act, int programCounter) {
}
private synchronized void push(int act, int programCounter)
{
push(act, programCounter, 0, 0);
}
// NO PROTECTION. This class is used only within this file so there is no excuse
// for trying to pop from empty stack.
private synchronized BackStep pop() {
}
// NO PROTECTION. This class is used only within this file so there is no excuse
// for trying to pop from empty stack.
private synchronized BackStep pop()
{
BackStep bs;
bs = stack[top];
if (size==1) {
top = -1;
}
else {
top = (top + capacity - 1) % capacity;
if (size == 1)
{
top = -1;
}
else
{
top = (top + capacity - 1) % capacity;
}
size--;
return bs;
}
// NO PROTECTION. This class is used only within this file so there is no excuse
// for trying to peek from empty stack.
private synchronized BackStep peek() {
}
// NO PROTECTION. This class is used only within this file so there is no excuse
// for trying to peek from empty stack.
private synchronized BackStep peek()
{
return stack[top];
}
}
}
}
}
}
+120 -115
View File
@@ -29,131 +29,136 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* Represents a (potential) delayed branch. Note it is necessary only when
* delayed branching is enabled. Here's the protocol for using it:
* Represents a (potential) delayed branch. Note it is necessary only when delayed branching is enabled. Here's the
* protocol for using it:
* <p>
* (1) When a runtime decision to branch is made (by either a branch or jump instruction's simulate() method in
* InstructionSet), then if delayed branching is enabled, the register() method is called with the branch target address
* but the program counter is NOT set to the branch target address.
* <p>
* (2) At the end of that instruction cycle, the simulate() method in Simulator will detect the registered branch, and
* set its trigger. Don't do anything yet because the next instruction cycle is the delay slot and needs to complete.
* <p>
* (3) At the end of the next (delay slot) instruction cycle, the simulate() method in Simulator will detect the
* triggered branch, set the program counter to its target value and clear the delayed branch.
* <p>
* The only interesting situation is when the delay slot itself contains a successful branch! I tried this with SPIM
* (e.g. beq followed by b) and it treats it as if nothing was there and continues the delay slot into the next cycle.
* The eventual branch taken is the original one (as one would hope) but in the meantime the first statement following
* the sequence of successful branches will constitute the delay slot and will be executed!
* <p>
* Since only one pending delayed branch can be taken at a time, everything here is done with statics. The class itself
* represents the potential branch.
*
* (1) When a runtime decision to branch is made (by either a branch or jump
* instruction's simulate() method in InstructionSet), then if delayed branching
* is enabled, the register() method is called with the branch target address but
* the program counter is NOT set to the branch target address.
*
* (2) At the end of that instruction cycle, the simulate() method in Simulator
* will detect the registered branch, and set its trigger. Don't do anything yet
* because the next instruction cycle is the delay slot and needs to complete.
*
* (3) At the end of the next (delay slot) instruction cycle, the simulate()
* method in Simulator will detect the triggered branch, set the program
* counter to its target value and clear the delayed branch.
*
* The only interesting situation is when the delay slot itself contains a
* successful branch! I tried this with SPIM (e.g. beq followed by b)
* and it treats it as if nothing was there and continues the delay slot
* into the next cycle. The eventual branch taken is the original one (as one
* would hope) but in the meantime the first statement following the sequence
* of successful branches will constitute the delay slot and will be executed!
*
* Since only one pending delayed branch can be taken at a time, everything
* here is done with statics. The class itself represents the potential branch.
*
* @author Pete Sanderson
* @version June 2007
**/
public class DelayedBranch {
// Class states.
private static final int CLEARED = 0;
private static final int REGISTERED = 1;
private static final int TRIGGERED = 2;
public class DelayedBranch
{
// Class states.
private static final int CLEARED = 0;
// Initially nothing is happening.
private static int state = CLEARED;
private static int branchTargetAddress = 0;
/**
* Register the fact that a successful branch is to occur. This is called in
* the instruction's simulated execution (its simulate() method in InstructionSet).
* If a branch is registered but not triggered, this registration will be ignored
* (cannot happen if class usage protocol is followed). If a branch is currently
* registered and triggered, reset the state back to registered (but not triggered)
* in order to carry over the delay slot for another execution cycle. This is the
* only public member of the class.
*
* @param targetAddress The address to branch to after executing the next instruction
*/
public static void register(int targetAddress) {
// About as clean as a switch statement can be!
switch (state) {
case CLEARED : branchTargetAddress = targetAddress;
case REGISTERED :
case TRIGGERED : state = REGISTERED;
}
}
private static final int REGISTERED = 1;
/**
* Trigger a registered branch. This is called at the end of the MIPS simulator
* instruction execution cycle (simulate method in Simulator), so a registered
* branch will be triggered right away. The next execution cycle will be the
* delay slot and at the end of THAT cycle, the trigger will be detected and the
* branch carried out. This method has package visibility.
*
* Precondition: DelayedBranch.isRegistered()
*
* Postcondition: DelayedBranch.isTriggered() && !DelayedBranch.isRegistered()
*
*/
static void trigger() {
// About as clean as a switch statement can be!
switch (state) {
case REGISTERED :
case TRIGGERED : state = TRIGGERED;
case CLEARED :
}
}
private static final int TRIGGERED = 2;
/**
* Clear the delayed branch. This must be done immediately after setting the
* program counter to the target address. This method has package visibility.
*/
static void clear() {
state = CLEARED;
branchTargetAddress = 0;
}
// Initially nothing is happening.
/**
* Return registration status. Is false initially, true after register() is called
* but becomes false after trigger() or clear() are called. This method has package
* visibility.
*
* @return true if branch is registered but not triggered, false otherwise.
*/
private static int state = CLEARED;
static boolean isRegistered() {
return state == REGISTERED;
}
/**
* Return trigger status. Is false initially, true after trigger() is called
* but becomes false after clear() is called. This method has package visibility.
*
* @return true if branch is registered but not triggered, false otherwise.
*/
private static int branchTargetAddress = 0;
static boolean isTriggered() {
return state == TRIGGERED;
}
/**
* Register the fact that a successful branch is to occur. This is called in the instruction's simulated execution
* (its simulate() method in InstructionSet). If a branch is registered but not triggered, this registration will be
* ignored (cannot happen if class usage protocol is followed). If a branch is currently registered and triggered,
* reset the state back to registered (but not triggered) in order to carry over the delay slot for another
* execution cycle. This is the only public member of the class.
*
* @param targetAddress The address to branch to after executing the next instruction
*/
public static void register(int targetAddress)
{
// About as clean as a switch statement can be!
switch (state)
{
case CLEARED:
branchTargetAddress = targetAddress;
case REGISTERED:
case TRIGGERED:
state = REGISTERED;
}
}
/**
* Trigger a registered branch. This is called at the end of the MIPS simulator instruction execution cycle
* (simulate method in Simulator), so a registered branch will be triggered right away. The next execution cycle
* will be the delay slot and at the end of THAT cycle, the trigger will be detected and the branch carried out.
* This method has package visibility.
* <p>
* Precondition: DelayedBranch.isRegistered()
* <p>
* Postcondition: DelayedBranch.isTriggered() && !DelayedBranch.isRegistered()
*/
static void trigger()
{
// About as clean as a switch statement can be!
switch (state)
{
case REGISTERED:
case TRIGGERED:
state = TRIGGERED;
case CLEARED:
}
}
/**
* Clear the delayed branch. This must be done immediately after setting the program counter to the target address.
* This method has package visibility.
*/
static void clear()
{
state = CLEARED;
branchTargetAddress = 0;
}
/**
* Return registration status. Is false initially, true after register() is called but becomes false after
* trigger() or clear() are called. This method has package visibility.
*
* @return true if branch is registered but not triggered, false otherwise.
*/
static boolean isRegistered()
{
return state == REGISTERED;
}
/**
* Return trigger status. Is false initially, true after trigger() is called but becomes false after clear() is
* called. This method has package visibility.
*
* @return true if branch is registered but not triggered, false otherwise.
*/
static boolean isTriggered()
{
return state == TRIGGERED;
}
/**
* Return branch target address. This should be retrieved only to set the program
* counter at the end of the delay slot. This method has package visibility.
*
* Precondition: DelayedBranch.isTriggered()
*
* @return Target address of the delayed branch.
*/
static int getBranchTargetAddress() {
return branchTargetAddress;
}
} // DelayedBranch
/**
* Return branch target address. This should be retrieved only to set the program counter at the end of the delay
* slot. This method has package visibility.
* <p>
* Precondition: DelayedBranch.isTriggered()
*
* @return Target address of the delayed branch.
*/
static int getBranchTargetAddress()
{
return branchTargetAddress;
}
} // DelayedBranch
+71 -59
View File
@@ -1,7 +1,9 @@
package mars.simulator;
import mars.mips.hardware.*;
import mars.mips.instructions.*;
import mars.util.*;
import mars.mips.hardware.Coprocessor0;
import mars.mips.hardware.RegisterFile;
import mars.mips.instructions.Instruction;
import mars.util.Binary;
/*
Copyright (c) 2003-2006, Pete Sanderson and Kenneth Vollmar
@@ -33,65 +35,75 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
/**
* Represents an error/interrupt that occurs during execution (simulation).
*
* @author Pete Sanderson
* @version August 2005
**/
public class Exceptions {
/** The exception number is stored in coprocessor 0 cause register ($13)
* Note: the codes for External Interrupts have been modified from MIPS
* specs in order to encode two pieces of information. According
* to spec, there is one External Interrupt code, 0. But then
* how to distinguish keyboard interrupt from display interrupt?
* The Cause register has Interupt Pending bits that can be set.
* Bit 8 represents keyboard, bit 9 represents display. Those
* bits are included into this code, but shifted right two positions
* since the interrupt code will be shifted left two positions
* for inserting cause code into bit positions 2-6 in Cause register.
* DPS 23 July 2008.
*/
public static final int EXTERNAL_INTERRUPT_KEYBOARD = 0x00000040; // see comment above.
public static final int EXTERNAL_INTERRUPT_DISPLAY = 0x00000080; // see comment above.
public static final int ADDRESS_EXCEPTION_LOAD = 4;
public static final int ADDRESS_EXCEPTION_STORE = 5;
public static final int SYSCALL_EXCEPTION = 8;
public static final int BREAKPOINT_EXCEPTION = 9;
public static final int RESERVED_INSTRUCTION_EXCEPTION = 10;
public static final int ARITHMETIC_OVERFLOW_EXCEPTION = 12;
public static final int TRAP_EXCEPTION = 13;
/* the following are from SPIM */
public static final int DIVIDE_BY_ZERO_EXCEPTION = 15;
public static final int FLOATING_POINT_OVERFLOW = 16;
public static final int FLOATING_POINT_UNDERFLOW = 17;
/**
* Given MIPS exception cause code, will place that code into
* coprocessor 0 CAUSE register ($13), set the EPC register to
* "current" program counter, and set Exception Level bit in STATUS register.
*
* @param cause The cause code (see Exceptions for a list)
*/
public static void setRegisters(int cause) {
// Set CAUSE register bits 2 thru 6 to cause value. The "& 0xFFFFFC83" will set bits 2-6 and 8-9 to 0 while
// keeping all the others. Left-shift by 2 to put cause value into position then OR it in. Bits 8-9 used to
// identify devices for External Interrupt (8=keyboard,9=display).
Coprocessor0.updateRegister(Coprocessor0.CAUSE,(Coprocessor0.getValue(Coprocessor0.CAUSE) & 0xFFFFFC83 | (cause << 2)));
// When exception occurred, PC had already been incremented so need to subtract 4 here.
Coprocessor0.updateRegister(Coprocessor0.EPC, RegisterFile.getProgramCounter()-Instruction.INSTRUCTION_LENGTH);
// Set EXL (Exception Level) bit, bit position 1, in STATUS register to 1.
Coprocessor0.updateRegister(Coprocessor0.STATUS, Binary.setBit(Coprocessor0.getValue(Coprocessor0.STATUS), Coprocessor0.EXCEPTION_LEVEL));
}
public class Exceptions
{
/**
* The exception number is stored in coprocessor 0 cause register ($13) Note: the codes for External Interrupts have
* been modified from MIPS specs in order to encode two pieces of information. According to spec, there is one
* External Interrupt code, 0. But then how to distinguish keyboard interrupt from display interrupt? The Cause
* register has Interupt Pending bits that can be set. Bit 8 represents keyboard, bit 9 represents display. Those
* bits are included into this code, but shifted right two positions since the interrupt code will be shifted left
* two positions for inserting cause code into bit positions 2-6 in Cause register. DPS 23 July 2008.
*/
public static final int EXTERNAL_INTERRUPT_KEYBOARD = 0x00000040; // see comment above.
/**
* Given MIPS exception cause code and bad address, place the bad address into VADDR
* register ($8) then call overloaded setRegisters with the cause code to do the rest.
*
* @param cause The cause code (see Exceptions for a list). Should be address exception.
* @param addr The address that caused the exception.
*/
public static void setRegisters(int cause, int addr) {
Coprocessor0.updateRegister(Coprocessor0.VADDR,addr);
setRegisters(cause);
}
public static final int EXTERNAL_INTERRUPT_DISPLAY = 0x00000080; // see comment above.
} // Exceptions
public static final int ADDRESS_EXCEPTION_LOAD = 4;
public static final int ADDRESS_EXCEPTION_STORE = 5;
public static final int SYSCALL_EXCEPTION = 8;
public static final int BREAKPOINT_EXCEPTION = 9;
public static final int RESERVED_INSTRUCTION_EXCEPTION = 10;
public static final int ARITHMETIC_OVERFLOW_EXCEPTION = 12;
public static final int TRAP_EXCEPTION = 13;
/* the following are from SPIM */
public static final int DIVIDE_BY_ZERO_EXCEPTION = 15;
public static final int FLOATING_POINT_OVERFLOW = 16;
public static final int FLOATING_POINT_UNDERFLOW = 17;
/**
* Given MIPS exception cause code, will place that code into coprocessor 0 CAUSE register ($13), set the EPC
* register to "current" program counter, and set Exception Level bit in STATUS register.
*
* @param cause The cause code (see Exceptions for a list)
*/
public static void setRegisters(int cause)
{
// Set CAUSE register bits 2 thru 6 to cause value. The "& 0xFFFFFC83" will set bits 2-6 and 8-9 to 0 while
// keeping all the others. Left-shift by 2 to put cause value into position then OR it in. Bits 8-9 used to
// identify devices for External Interrupt (8=keyboard,9=display).
Coprocessor0.updateRegister(Coprocessor0.CAUSE, (Coprocessor0.getValue(Coprocessor0.CAUSE) & 0xFFFFFC83 | (cause << 2)));
// When exception occurred, PC had already been incremented so need to subtract 4 here.
Coprocessor0.updateRegister(Coprocessor0.EPC, RegisterFile.getProgramCounter() - Instruction.INSTRUCTION_LENGTH);
// Set EXL (Exception Level) bit, bit position 1, in STATUS register to 1.
Coprocessor0.updateRegister(Coprocessor0.STATUS, Binary.setBit(Coprocessor0.getValue(Coprocessor0.STATUS), Coprocessor0.EXCEPTION_LEVEL));
}
/**
* Given MIPS exception cause code and bad address, place the bad address into VADDR register ($8) then call
* overloaded setRegisters with the cause code to do the rest.
*
* @param cause The cause code (see Exceptions for a list). Should be address exception.
* @param addr The address that caused the exception.
*/
public static void setRegisters(int cause, int addr)
{
Coprocessor0.updateRegister(Coprocessor0.VADDR, addr);
setRegisters(cause);
}
} // Exceptions

Some files were not shown because too many files have changed in this diff Show More