[O] Reformat code
This commit is contained in:
@@ -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
@@ -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
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
|
||||
+890
-716
File diff suppressed because it is too large
Load Diff
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
+534
-310
File diff suppressed because it is too large
Load Diff
+1518
-1295
File diff suppressed because it is too large
Load Diff
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user