. Option may be repeated.");
+ out.println(" pa -- Program Arguments follow in a space-separated list. This");
+ out.println(" option must be placed AFTER ALL FILE NAMES, because everything");
+ out.println(" that follows it is interpreted as a program argument to be");
+ out.println(" made available to the MIPS program at runtime.");
+ out.println("If more than one filename is listed, the first is assumed to be the main");
+ out.println("unless the global statement label 'main' is defined in one of the files.");
+ out.println("Exception handler not automatically assembled. Add it to the file list.");
+ out.println("Options used here do not affect MARS Settings menu values and vice versa.");
+ }
+
+}
diff --git a/src/main/java/mars/MarsSplashScreen.java b/src/main/java/mars/MarsSplashScreen.java
index fbf7611..66af44b 100644
--- a/src/main/java/mars/MarsSplashScreen.java
+++ b/src/main/java/mars/MarsSplashScreen.java
@@ -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.
- * Adapted from http://www.java-tips.org/content/view/1267/2/
+ * Produces MARS splash screen.
Adapted from http://www.java-tips.org/content/view/1267/2/
*/
- 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
- ("
Version "+Globals.version+" Copyright (c) "+Globals.copyrightYears+"", JLabel.CENTER);
- JLabel copyrt2 = new JLabel
- ("
"+Globals.copyrightHolders+"", 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
+ ("
Version " + Globals.version + " Copyright (c) " + Globals.copyrightYears + "", JLabel.CENTER);
+ JLabel copyrt2 = new JLabel
+ ("
" + Globals.copyrightHolders + "", 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);
+ }
+ }
+ }
+
+
+}
diff --git a/src/main/java/mars/ProcessingException.java b/src/main/java/mars/ProcessingException.java
index 53684cc..2ad8628 100644
--- a/src/main/java/mars/ProcessingException.java
+++ b/src/main/java/mars/ProcessingException.java
@@ -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.
+ *
+ * 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;
+ }
+
+}
diff --git a/src/main/java/mars/ProgramStatement.java b/src/main/java/mars/ProgramStatement.java
index 58325ac..ef536a0 100644
--- a/src/main/java/mars/ProgramStatement.java
+++ b/src/main/java/mars/ProgramStatement.java
@@ -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 = "";
+ 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;
diff --git a/src/main/java/mars/Settings.java b/src/main/java/mars/Settings.java
index 13d6c42..0b72fdb 100644
--- a/src/main/java/mars/Settings.java
+++ b/src/main/java/mars/Settings.java
@@ -53,10 +53,10 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* @author Pete Sanderson
**/
-public class Settings extends Observable {
+public class Settings extends Observable
+{
/**
- * Flag to determine whether a program can write binary code to the text or data segment and
- * execute that code.
+ * Flag to determine whether a program can write binary code to the text or data segment and execute that code.
*/
public static final int SELF_MODIFYING_CODE_ENABLED = 20;
///////////////////////////// PROPERTY ARRAY INDEXES /////////////////////////////
@@ -65,73 +65,82 @@ public class Settings extends Observable {
// BOOLEAN SETTINGS...
/**
- * Flag to determine whether or not program being assembled is limited to
- * basic MIPS instructions and formats.
+ * Flag to determine whether or not program being assembled is limited to basic MIPS instructions and formats.
*/
public static final int EXTENDED_ASSEMBLER_ENABLED = 0;
/**
- * Flag to determine whether or not program being assembled is limited to
- * using register numbers instead of names. NOTE: Its default value is
- * false and the IDE provides no means to change it!
+ * Flag to determine whether or not program being assembled is limited to using register numbers instead of names.
+ * NOTE: Its default value is false and the IDE provides no means to change it!
*/
public static final int BARE_MACHINE_ENABLED = 1;
+
/**
- * Flag to determine whether or not a file is immediately and automatically assembled
- * upon opening. Handy when using externa editor like mipster.
+ * Flag to determine whether or not a file is immediately and automatically assembled upon opening. Handy when using
+ * externa editor like mipster.
*/
public static final int ASSEMBLE_ON_OPEN_ENABLED = 2;
+
/**
- * Flag to determine whether only the current editor source file (enabled false) or
- * all files in its directory (enabled true) will be assembled when assembly is selected.
+ * Flag to determine whether only the current editor source file (enabled false) or all files in its directory
+ * (enabled true) will be assembled when assembly is selected.
*/
public static final int ASSEMBLE_ALL_ENABLED = 3;
+
/**
- * Default visibilty of label window (symbol table). Default only, dynamic status
- * maintained by ExecutePane
+ * Default visibilty of label window (symbol table). Default only, dynamic status maintained by ExecutePane
*/
public static final int LABEL_WINDOW_VISIBILITY = 4;
+
/**
- * Default setting for displaying addresses and values in hexidecimal in the Execute
- * pane.
+ * Default setting for displaying addresses and values in hexidecimal in the Execute pane.
*/
public static final int DISPLAY_ADDRESSES_IN_HEX = 5;
+
public static final int DISPLAY_VALUES_IN_HEX = 6;
+
/**
- * Flag to determine whether the currently selected exception handler source file will
- * be included in each assembly operation.
+ * Flag to determine whether the currently selected exception handler source file will be included in each assembly
+ * operation.
*/
public static final int EXCEPTION_HANDLER_ENABLED = 7;
+
/**
- * Flag to determine whether or not delayed branching is in effect at MIPS execution.
- * This means we simulate the pipeline and statement FOLLOWING a successful branch
- * is executed before branch is taken. DPS 14 June 2007.
+ * Flag to determine whether or not delayed branching is in effect at MIPS execution. This means we simulate the
+ * pipeline and statement FOLLOWING a successful branch is executed before branch is taken. DPS 14 June 2007.
*/
public static final int DELAYED_BRANCHING_ENABLED = 8;
+
/**
* Flag to determine whether or not the editor will display line numbers.
*/
public static final int EDITOR_LINE_NUMBERS_DISPLAYED = 9;
+
/**
* Flag to determine whether or not assembler warnings are considered errors.
*/
public static final int WARNINGS_ARE_ERRORS = 10;
+
/**
* Flag to determine whether or not to display and use program arguments
*/
public static final int PROGRAM_ARGUMENTS = 11;
+
/**
* Flag to control whether or not highlighting is applied to data segment window
*/
public static final int DATA_SEGMENT_HIGHLIGHTING = 12;
+
/**
* Flag to control whether or not highlighting is applied to register windows
*/
public static final int REGISTERS_HIGHLIGHTING = 13;
+
/**
* Flag to control whether or not assembler automatically initializes program counter to 'main's address
*/
public static final int START_AT_MAIN = 14;
+
/**
* Flag to control whether or not editor will highlight the line currently being edited
*/
@@ -156,52 +165,64 @@ public class Settings extends Observable {
* Flag to control whether or not language-aware editor will use auto-indent feature
*/
public static final int AUTO_INDENT = 19;
+
/**
* Current specified exception handler file (a MIPS assembly source file)
*/
public static final int EXCEPTION_HANDLER = 0;
+
/**
* Order of text segment table columns
*/
public static final int TEXT_COLUMN_ORDER = 1;
+
/**
* State for sorting label window display
*/
public static final int LABEL_SORT_STATE = 2;
// STRING SETTINGS. Each array position has associated name.
+
/**
* Identifier of current memory configuration
*/
public static final int MEMORY_CONFIGURATION = 3;
+
/**
* Caret blink rate in milliseconds, 0 means don't blink.
*/
public static final int CARET_BLINK_RATE = 4;
+
/**
* Editor tab size in characters.
*/
public static final int EDITOR_TAB_SIZE = 5;
+
/**
* Number of letters to be matched by editor's instruction guide before popup generated (if popup enabled)
*/
public static final int EDITOR_POPUP_PREFIX_LENGTH = 6;
+
/**
* Font for the text editor
*/
public static final int EDITOR_FONT = 0;
+
/**
* Font for table even row background (text, data, register displays)
*/
public static final int EVEN_ROW_FONT = 1;
+
/**
* Font for table odd row background (text, data, register displays)
*/
public static final int ODD_ROW_FONT = 2;
+
/**
* Font for table odd row foreground (text, data, register displays)
*/
public static final int TEXTSEGMENT_HIGHLIGHT_FONT = 3;
+
/**
* Font for text segment delay slot highlighted background
*/
@@ -209,54 +230,67 @@ public class Settings extends Observable {
// FONT SETTINGS. Each array position has associated name.
+
/**
* Font for text segment highlighted background
*/
public static final int DATASEGMENT_HIGHLIGHT_FONT = 5;
+
/**
* Font for register highlighted background
*/
public static final int REGISTER_HIGHLIGHT_FONT = 6;
+
/**
* RGB color for table even row background (text, data, register displays)
*/
public static final int EVEN_ROW_BACKGROUND = 0;
+
/**
* RGB color for table even row foreground (text, data, register displays)
*/
public static final int EVEN_ROW_FOREGROUND = 1;
+
/**
* RGB color for table odd row background (text, data, register displays)
*/
public static final int ODD_ROW_BACKGROUND = 2;
+
/**
* RGB color for table odd row foreground (text, data, register displays)
*/
public static final int ODD_ROW_FOREGROUND = 3;
+
/**
* RGB color for text segment highlighted background
*/
public static final int TEXTSEGMENT_HIGHLIGHT_BACKGROUND = 4;
+
/**
* RGB color for text segment highlighted foreground
*/
public static final int TEXTSEGMENT_HIGHLIGHT_FOREGROUND = 5;
+
/**
* RGB color for text segment delay slot highlighted background
*/
public static final int TEXTSEGMENT_DELAYSLOT_HIGHLIGHT_BACKGROUND = 6;
+
/**
* RGB color for text segment delay slot highlighted foreground
*/
public static final int TEXTSEGMENT_DELAYSLOT_HIGHLIGHT_FOREGROUND = 7;
+
/**
* RGB color for text segment highlighted background
*/
public static final int DATASEGMENT_HIGHLIGHT_BACKGROUND = 8;
+
/**
* RGB color for text segment highlighted foreground
*/
public static final int DATASEGMENT_HIGHLIGHT_FOREGROUND = 9;
+
/**
* RGB color for register highlighted background
*/
@@ -264,29 +298,37 @@ public class Settings extends Observable {
// COLOR SETTINGS. Each array position has associated name.
+
/**
* RGB color for register highlighted foreground
*/
public static final int REGISTER_HIGHLIGHT_FOREGROUND = 11;
+
/* Properties file used to hold default settings. */
private static final String settingsFile = "Settings";
+
// NOTE: key sequence must match up with labels above which are used for array indexes!
private static final String[] booleanSettingsKeys = {"ExtendedAssembler", "BareMachine", "AssembleOnOpen", "AssembleAll", "LabelWindowVisibility", "DisplayAddressesInHex", "DisplayValuesInHex", "LoadExceptionHandler", "DelayedBranching", "EditorLineNumbersDisplayed", "WarningsAreErrors", "ProgramArguments", "DataSegmentHighlighting", "RegistersHighlighting", "StartAtMain", "EditorCurrentLineHighlighting", "PopupInstructionGuidance", "PopupSyscallInput", "GenericTextEditor", "AutoIndent", "SelfModifyingCode"};
+
// Match the above by position.
private static final String[] stringSettingsKeys = {"ExceptionHandler", "TextColumnOrder", "LabelSortState", "MemoryConfiguration", "CaretBlinkRate", "EditorTabSize", "EditorPopupPrefixLength"};
+
/**
* Last resort default values for String settings; will use only if neither the Preferences nor the properties file
* work. If you wish to change, do so before instantiating the Settings object. Must match key by list position.
*/
private static final String[] defaultStringSettingsValues = {"", "0 1 2 3 4", "0", "", "500", "8", "2"};
+
private static final String[] fontFamilySettingsKeys = {"EditorFontFamily", "EvenRowFontFamily", "OddRowFontFamily", " TextSegmentHighlightFontFamily", "TextSegmentDelayslotHighightFontFamily", "DataSegmentHighlightFontFamily", "RegisterHighlightFontFamily"};
+
private static final String[] fontStyleSettingsKeys = {"EditorFontStyle", "EvenRowFontStyle", "OddRowFontStyle", " TextSegmentHighlightFontStyle", "TextSegmentDelayslotHighightFontStyle", "DataSegmentHighlightFontStyle", "RegisterHighlightFontStyle"};
+
private static final String[] fontSizeSettingsKeys = {"EditorFontSize", "EvenRowFontSize", "OddRowFontSize", " TextSegmentHighlightFontSize", "TextSegmentDelayslotHighightFontSize", "DataSegmentHighlightFontSize", "RegisterHighlightFontSize"};
+
/**
- * Last resort default values for Font settings;
- * will use only if neither the Preferences nor the properties file work.
- * If you wish to change, do so before instantiating the Settings object.
- * Must match key by list position shown above.
+ * Last resort default values for Font settings; will use only if neither the Preferences nor the properties file
+ * work. If you wish to change, do so before instantiating the Settings object. Must match key by list position
+ * shown above.
*/
// DPS 3-Oct-2012
@@ -294,36 +336,56 @@ public class Settings extends Observable {
// correctly rendering the left parenthesis character in the editor or text segment display.
// See http://www.mirthcorp.com/community/issues/browse/MIRTH-1921?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
private static final String[] defaultFontFamilySettingsValues = {"Monospaced", "Monospaced", "Monospaced", "Monospaced", "Monospaced", "Monospaced", "Monospaced"};
+
private static final String[] defaultFontStyleSettingsValues = {"Plain", "Plain", "Plain", "Plain", "Plain", "Plain", "Plain"};
+
private static final String[] defaultFontSizeSettingsValues = {"12", "12", "12", "12", "12", "12", "12",};
+
// Match the above by position.
private static final String[] colorSettingsKeys = {"EvenRowBackground", "EvenRowForeground", "OddRowBackground", "OddRowForeground", "TextSegmentHighlightBackground", "TextSegmentHighlightForeground", "TextSegmentDelaySlotHighlightBackground", "TextSegmentDelaySlotHighlightForeground", "DataSegmentHighlightBackground", "DataSegmentHighlightForeground", "RegisterHighlightBackground", "RegisterHighlightForeground"};
+
/**
* Last resort default values for color settings; will use only if neither the Preferences nor the properties file
* work. If you wish to change, do so before instantiating the Settings object. Must match key by list position.
*/
private static final String[] defaultColorSettingsValues = {"0x00e0e0e0", "0", "0x00ffffff", "0", "0x00ffff99", "0", "0x0033ff00", "0", "0x0099ccff", "0", "0x0099cc55", "0"};
+
private static final String SYNTAX_STYLE_COLOR_PREFIX = "SyntaxStyleColor_";
+
private static final String SYNTAX_STYLE_BOLD_PREFIX = "SyntaxStyleBold_";
+
private static final String SYNTAX_STYLE_ITALIC_PREFIX = "SyntaxStyleItalic_";
+
/**
* Last resort default values for boolean settings; will use only if neither the Preferences nor the properties
* file work. If you wish to change them, do so before instantiating the Settings object. Values are matched to keys
* by list position.
*/
public static boolean[] defaultBooleanSettingsValues = { // match the above list by position
- true, false, false, false, false, true, true, false, false, true, false, false, true, true, false, true, true, false, false, true, false};
+ true, false, false, false, false, true, true, false, false, true, false, false, true, true, false, true, true, false, false, true, false};
+
private static String[] syntaxStyleColorSettingsKeys, syntaxStyleBoldSettingsKeys, syntaxStyleItalicSettingsKeys;
+
private static String[] defaultSyntaxStyleColorSettingsValues;
+
private static boolean[] defaultSyntaxStyleBoldSettingsValues;
+
private static boolean[] defaultSyntaxStyleItalicSettingsValues;
+
private final boolean[] booleanSettingsValues;
+
private final String[] stringSettingsValues;
+
private final String[] fontFamilySettingsValues;
+
private final String[] fontStyleSettingsValues;
+
private final String[] fontSizeSettingsValues;
+
private final String[] colorSettingsValues;
+
private final Preferences preferences;
+
/* **************************************************************************
This section contains all code related to syntax highlighting styles settings.
A style includes 3 components: color, bold (t/f), italic (t/f)
@@ -335,24 +397,29 @@ public class Settings extends Observable {
*/
private String[] syntaxStyleColorSettingsValues;
+
private boolean[] syntaxStyleBoldSettingsValues;
+
private boolean[] syntaxStyleItalicSettingsValues;
/**
* Create Settings object and set to saved values. If saved values not found, will set based on defaults stored in
* Settings.properties file. If file problems, will set based on defaults stored in this class.
*/
- public Settings() {
+ public Settings()
+ {
this(true);
}
+
/**
* Create Settings object and set to saved values. If saved values not found, will set based on defaults stored in
* Settings.properties file. If file problems, will set based on defaults stored in this class.
*
* @param gui true if running the graphical IDE, false if running from command line. Ignored as of release 3.6
- * but retained for compatability.
+ * but retained for compatability.
*/
- public Settings(boolean gui) {
+ public Settings(boolean gui)
+ {
booleanSettingsValues = new boolean[booleanSettingsKeys.length];
stringSettingsValues = new String[stringSettingsKeys.length];
fontFamilySettingsValues = new String[fontFamilySettingsKeys.length];
@@ -374,50 +441,60 @@ public class Settings extends Observable {
}
/**
- * Return whether backstepping is permitted at this time. Backstepping is ability to undo execution
- * steps one at a time. Available only in the IDE. This is not a persistent setting and is not under
- * MARS user control.
+ * Return whether backstepping is permitted at this time. Backstepping is ability to undo execution steps one at a
+ * time. Available only in the IDE. This is not a persistent setting and is not under MARS user control.
*
* @return true if backstepping is permitted, false otherwise.
*/
- public boolean getBackSteppingEnabled() {
+ public boolean getBackSteppingEnabled()
+ {
return (Globals.program != null && Globals.program.getBackStepper() != null && Globals.program.getBackStepper().enabled());
}
/**
* Reset settings to default values, as described in the constructor comments.
*
- * @param gui true if running from GUI IDE and false if running from command mode.
- * Ignored as of release 3.6 but retained for compatibility.
+ * @param gui true if running from GUI IDE and false if running from command mode. Ignored as of release 3.6 but
+ * retained for compatibility.
*/
- public void reset(boolean gui) {
+ public void reset(boolean gui)
+ {
initialize();
}
- public void setEditorSyntaxStyleByPosition(int index, SyntaxStyle syntaxStyle) {
+ public void setEditorSyntaxStyleByPosition(int index, SyntaxStyle syntaxStyle)
+ {
syntaxStyleColorSettingsValues[index] = syntaxStyle.getColorAsHexString();
syntaxStyleItalicSettingsValues[index] = syntaxStyle.isItalic();
syntaxStyleBoldSettingsValues[index] = syntaxStyle.isBold();
saveEditorSyntaxStyle(index);
}
- public SyntaxStyle getEditorSyntaxStyleByPosition(int index) {
+ public SyntaxStyle getEditorSyntaxStyleByPosition(int index)
+ {
return new SyntaxStyle(getColorValueByPosition(index, syntaxStyleColorSettingsValues), syntaxStyleItalicSettingsValues[index], syntaxStyleBoldSettingsValues[index]);
}
- public SyntaxStyle getDefaultEditorSyntaxStyleByPosition(int index) {
+ public SyntaxStyle getDefaultEditorSyntaxStyleByPosition(int index)
+ {
return new SyntaxStyle(getColorValueByPosition(index, defaultSyntaxStyleColorSettingsValues), defaultSyntaxStyleItalicSettingsValues[index], defaultSyntaxStyleBoldSettingsValues[index]);
}
- private void saveEditorSyntaxStyle(int index) {
- try {
+ private void saveEditorSyntaxStyle(int index)
+ {
+ try
+ {
preferences.put(syntaxStyleColorSettingsKeys[index], syntaxStyleColorSettingsValues[index]);
preferences.putBoolean(syntaxStyleBoldSettingsKeys[index], syntaxStyleBoldSettingsValues[index]);
preferences.putBoolean(syntaxStyleItalicSettingsKeys[index], syntaxStyleItalicSettingsValues[index]);
preferences.flush();
- } catch (SecurityException se) {
+ }
+ catch (SecurityException se)
+ {
// cannot write to persistent storage for security reasons
- } catch (BackingStoreException bse) {
+ }
+ catch (BackingStoreException bse)
+ {
// unable to communicate with persistent storage (strange days)
}
}
@@ -430,7 +507,8 @@ public class Settings extends Observable {
// On othe other hand, the first statement of this method causes Color objects
// to be created! It is possible but a real pain in the rear to avoid using
// Color objects totally. Requires new methods for the SyntaxUtilities class.
- private void initializeEditorSyntaxStyles() {
+ private void initializeEditorSyntaxStyles()
+ {
SyntaxStyle[] syntaxStyle = SyntaxUtilities.getDefaultSyntaxStyles();
int tokens = syntaxStyle.length;
syntaxStyleColorSettingsKeys = new String[tokens];
@@ -442,7 +520,8 @@ public class Settings extends Observable {
syntaxStyleColorSettingsValues = new String[tokens];
syntaxStyleBoldSettingsValues = new boolean[tokens];
syntaxStyleItalicSettingsValues = new boolean[tokens];
- for (int i = 0; i < tokens; i++) {
+ for (int i = 0; i < tokens; i++)
+ {
syntaxStyleColorSettingsKeys[i] = SYNTAX_STYLE_COLOR_PREFIX + i;
syntaxStyleBoldSettingsKeys[i] = SYNTAX_STYLE_BOLD_PREFIX + i;
syntaxStyleItalicSettingsKeys[i] = SYNTAX_STYLE_ITALIC_PREFIX + i;
@@ -452,8 +531,10 @@ public class Settings extends Observable {
}
}
- private void getEditorSyntaxStyleSettingsFromPreferences() {
- for (int i = 0; i < syntaxStyleColorSettingsKeys.length; i++) {
+ private void getEditorSyntaxStyleSettingsFromPreferences()
+ {
+ for (int i = 0; i < syntaxStyleColorSettingsKeys.length; i++)
+ {
syntaxStyleColorSettingsValues[i] = preferences.get(syntaxStyleColorSettingsKeys[i], syntaxStyleColorSettingsValues[i]);
syntaxStyleBoldSettingsValues[i] = preferences.getBoolean(syntaxStyleBoldSettingsKeys[i], syntaxStyleBoldSettingsValues[i]);
syntaxStyleItalicSettingsValues[i] = preferences.getBoolean(syntaxStyleItalicSettingsKeys[i], syntaxStyleItalicSettingsValues[i]);
@@ -474,10 +555,14 @@ public class Settings extends Observable {
* @return corresponding boolean setting.
* @throws IllegalArgumentException if identifier is invalid.
*/
- public boolean getBooleanSetting(int id) {
- if (id >= 0 && id < booleanSettingsValues.length) {
+ public boolean getBooleanSetting(int id)
+ {
+ if (id >= 0 && id < booleanSettingsValues.length)
+ {
return booleanSettingsValues[id];
- } else {
+ }
+ else
+ {
throw new IllegalArgumentException("Invalid boolean setting ID");
}
}
@@ -488,10 +573,11 @@ public class Settings extends Observable {
*
* @return true if only bare machine instructions allowed, false otherwise.
* @deprecated Use getBooleanSetting(int id) with the appropriate boolean setting ID (e.g.
- * Settings.BARE_MACHINE_ENABLED)
+ * Settings.BARE_MACHINE_ENABLED)
*/
@Deprecated
- public boolean getBareMachineEnabled() {
+ public boolean getBareMachineEnabled()
+ {
return booleanSettingsValues[BARE_MACHINE_ENABLED];
}
@@ -501,24 +587,25 @@ public class Settings extends Observable {
*
* @return true if pseudo-instructions and formats permitted, false otherwise.
* @deprecated Use getBooleanSetting(int id) with the appropriate boolean setting ID (e.g.
- * Settings.EXTENDED_ASSEMBLER_ENABLED)
+ * Settings.EXTENDED_ASSEMBLER_ENABLED)
*/
@Deprecated
- public boolean getExtendedAssemblerEnabled() {
+ public boolean getExtendedAssemblerEnabled()
+ {
return booleanSettingsValues[EXTENDED_ASSEMBLER_ENABLED];
}
/**
- * Establish setting for whether or not pseudo-instructions and formats are permitted
- * in user programs. User can change this setting via the IDE. If setting changes,
- * new setting will be written to properties file.
+ * Establish setting for whether or not pseudo-instructions and formats are permitted in user programs. User can
+ * change this setting via the IDE. If setting changes, new setting will be written to properties file.
*
* @param value True to permit, false otherwise.
* @deprecated Use setBooleanSetting(int id, boolean value) with the appropriate boolean setting ID
- * (e.g. Settings.EXTENDED_ASSEMBLER_ENABLED)
+ * (e.g. Settings.EXTENDED_ASSEMBLER_ENABLED)
*/
@Deprecated
- public void setExtendedAssemblerEnabled(boolean value) {
+ public void setExtendedAssemblerEnabled(boolean value)
+ {
internalSetBooleanSetting(EXTENDED_ASSEMBLER_ENABLED, value);
}
@@ -528,24 +615,26 @@ public class Settings extends Observable {
*
* @return true if file is to be automatically assembled upon opening and false otherwise.
* @deprecated Use getBooleanSetting(int id) with the appropriate boolean setting ID (e.g.
- * Settings.ASSEMBLE_ON_OPEN_ENABLED)
+ * Settings.ASSEMBLE_ON_OPEN_ENABLED)
*/
@Deprecated
- public boolean getAssembleOnOpenEnabled() {
+ public boolean getAssembleOnOpenEnabled()
+ {
return booleanSettingsValues[ASSEMBLE_ON_OPEN_ENABLED];
}
/**
- * Establish setting for whether a file will be automatically assembled as soon as it
- * is opened. This is handy for those using an external text editor such as Mipster.
- * If setting changes, new setting will be written to properties file.
+ * Establish setting for whether a file will be automatically assembled as soon as it is opened. This is handy for
+ * those using an external text editor such as Mipster. If setting changes, new setting will be written to
+ * properties file.
*
* @param value True to automatically assemble, false otherwise.
* @deprecated Use setBooleanSetting(int id, boolean value) with the appropriate boolean setting ID
- * (e.g. Settings.ASSEMBLE_ON_OPEN_ENABLED)
+ * (e.g. Settings.ASSEMBLE_ON_OPEN_ENABLED)
*/
@Deprecated
- public void setAssembleOnOpenEnabled(boolean value) {
+ public void setAssembleOnOpenEnabled(boolean value)
+ {
internalSetBooleanSetting(ASSEMBLE_ON_OPEN_ENABLED, value);
}
@@ -554,23 +643,24 @@ public class Settings extends Observable {
*
* @return true if addresses are displayed in hexadecimal and false otherwise (decimal).
* @deprecated Use getBooleanSetting(int id) with the appropriate boolean setting ID (e.g.
- * Settings.DISPLAY_ADDRESSES_IN_HEX)
+ * Settings.DISPLAY_ADDRESSES_IN_HEX)
*/
@Deprecated
- public boolean getDisplayAddressesInHex() {
+ public boolean getDisplayAddressesInHex()
+ {
return booleanSettingsValues[DISPLAY_ADDRESSES_IN_HEX];
}
/**
- * Establish setting for whether addresses in the Execute pane will be displayed
- * in hexadecimal format.
+ * Establish setting for whether addresses in the Execute pane will be displayed in hexadecimal format.
*
* @param value True to display addresses in hexadecimal, false for decimal.
* @deprecated Use setBooleanSetting(int id, boolean value) with the appropriate boolean setting ID
- * (e.g. Settings.DISPLAY_ADDRESSES_IN_HEX)
+ * (e.g. Settings.DISPLAY_ADDRESSES_IN_HEX)
*/
@Deprecated
- public void setDisplayAddressesInHex(boolean value) {
+ public void setDisplayAddressesInHex(boolean value)
+ {
internalSetBooleanSetting(DISPLAY_ADDRESSES_IN_HEX, value);
}
@@ -579,114 +669,114 @@ public class Settings extends Observable {
*
* @return true if values are displayed in hexadecimal and false otherwise (decimal).
* @deprecated Use getBooleanSetting(int id) with the appropriate boolean setting ID (e.g.
- * Settings.DISPLAY_VALUES_IN_HEX)
+ * Settings.DISPLAY_VALUES_IN_HEX)
*/
@Deprecated
- public boolean getDisplayValuesInHex() {
+ public boolean getDisplayValuesInHex()
+ {
return booleanSettingsValues[DISPLAY_VALUES_IN_HEX];
}
/**
- * Establish setting for whether values in the Execute pane will be displayed
- * in hexadecimal format.
+ * Establish setting for whether values in the Execute pane will be displayed in hexadecimal format.
*
* @param value True to display values in hexadecimal, false for decimal.
* @deprecated Use setBooleanSetting(int id, boolean value) with the appropriate boolean setting ID
- * (e.g. Settings.DISPLAY_VALUES_IN_HEX)
+ * (e.g. Settings.DISPLAY_VALUES_IN_HEX)
*/
@Deprecated
- public void setDisplayValuesInHex(boolean value) {
+ public void setDisplayValuesInHex(boolean value)
+ {
internalSetBooleanSetting(DISPLAY_VALUES_IN_HEX, value);
}
/**
- * Setting for whether the assemble operation applies only to the file currently open in
- * the editor or whether it applies to all files in that file's directory (primitive project
- * capability). If the "assemble on open" setting is set, this "assemble all" setting will
- * be applied as soon as the file is opened.
+ * Setting for whether the assemble operation applies only to the file currently open in the editor or whether it
+ * applies to all files in that file's directory (primitive project capability). If the "assemble on open" setting
+ * is set, this "assemble all" setting will be applied as soon as the file is opened.
*
* @return true if all files are to be assembled, false if only the file open in editor.
- * @deprecated Use getBooleanSetting(int id) with the appropriate boolean setting ID
- * (e.g. Settings.ASSEMBLE_ALL_ENABLED)
+ * @deprecated Use getBooleanSetting(int id) with the appropriate boolean setting ID (e.g.
+ * Settings.ASSEMBLE_ALL_ENABLED)
*/
@Deprecated
- public boolean getAssembleAllEnabled() {
+ public boolean getAssembleAllEnabled()
+ {
return booleanSettingsValues[ASSEMBLE_ALL_ENABLED];
}
/**
- * Establish setting for whether a file will be assembled by itself (false) or along
- * with all other files in its directory (true). This permits multi-file programs
- * and a primitive "project" capability. If setting changes,
+ * Establish setting for whether a file will be assembled by itself (false) or along with all other files in its
+ * directory (true). This permits multi-file programs and a primitive "project" capability. If setting changes,
* new setting will be written to properties file.
*
* @param value True to assemble all, false otherwise.
* @deprecated Use setBooleanSetting(int id, boolean value) with the appropriate boolean setting ID
- * (e.g. Settings.ASSEMBLE_ALL_ENABLED)
+ * (e.g. Settings.ASSEMBLE_ALL_ENABLED)
*/
@Deprecated
- public void setAssembleAllEnabled(boolean value) {
+ public void setAssembleAllEnabled(boolean value)
+ {
internalSetBooleanSetting(ASSEMBLE_ALL_ENABLED, value);
}
/**
- * Setting for whether the currently selected exception handler
- * (a MIPS source file) will be automatically included in each
- * assemble operation.
+ * Setting for whether the currently selected exception handler (a MIPS source file) will be automatically included
+ * in each assemble operation.
*
* @return true if exception handler is to be included in assemble, false otherwise.
- * @deprecated Use getBooleanSetting(int id) with the appropriate boolean setting ID
- * (e.g. Settings.EXCEPTION_HANDLER_ENABLED)
+ * @deprecated Use getBooleanSetting(int id) with the appropriate boolean setting ID (e.g.
+ * Settings.EXCEPTION_HANDLER_ENABLED)
*/
@Deprecated
- public boolean getExceptionHandlerEnabled() {
+ public boolean getExceptionHandlerEnabled()
+ {
return booleanSettingsValues[EXCEPTION_HANDLER_ENABLED];
}
/**
- * Establish setting for whether the currently selected exception handler
- * (a MIPS source file) will be automatically included in each
- * assemble operation. If setting changes, new setting will be written
- * to properties file.
+ * Establish setting for whether the currently selected exception handler (a MIPS source file) will be automatically
+ * included in each assemble operation. If setting changes, new setting will be written to properties file.
*
* @param value True to assemble exception handler, false otherwise.
* @deprecated Use setBooleanSetting(int id, boolean value) with the appropriate boolean setting ID
- * (e.g. Settings.EXCEPTION_HANDLER_ENABLED)
+ * (e.g. Settings.EXCEPTION_HANDLER_ENABLED)
*/
@Deprecated
- public void setExceptionHandlerEnabled(boolean value) {
+ public void setExceptionHandlerEnabled(boolean value)
+ {
internalSetBooleanSetting(EXCEPTION_HANDLER_ENABLED, value);
}
/**
- * Setting for whether delayed branching will be applied during MIPS
- * program execution. If enabled, the statement following a successful
- * branch will be executed and then the branch is taken! This simulates
- * pipelining and all MIPS processors do it. However it is confusing to
- * assembly language students so is disabled by default. SPIM does same thing.
+ * Setting for whether delayed branching will be applied during MIPS program execution. If enabled, the statement
+ * following a successful branch will be executed and then the branch is taken! This simulates pipelining and all
+ * MIPS processors do it. However it is confusing to assembly language students so is disabled by default. SPIM
+ * does same thing.
*
* @return true if delayed branching is enabled, false otherwise.
- * @deprecated Use getBooleanSetting(int id) with the appropriate boolean setting ID
- * (e.g. Settings.DELAYED_BRANCHING_ENABLED)
+ * @deprecated Use getBooleanSetting(int id) with the appropriate boolean setting ID (e.g.
+ * Settings.DELAYED_BRANCHING_ENABLED)
*/
@Deprecated
- public boolean getDelayedBranchingEnabled() {
+ public boolean getDelayedBranchingEnabled()
+ {
return booleanSettingsValues[DELAYED_BRANCHING_ENABLED];
}
/**
- * Establish setting for whether delayed branching will be applied during
- * MIPS program execution. If enabled, the statement following a successful
- * branch will be executed and then the branch is taken! This simulates
- * pipelining and all MIPS processors do it. However it is confusing to
- * assembly language students so is disabled by default. SPIM does same thing.
+ * Establish setting for whether delayed branching will be applied during MIPS program execution. If enabled, the
+ * statement following a successful branch will be executed and then the branch is taken! This simulates pipelining
+ * and all MIPS processors do it. However it is confusing to assembly language students so is disabled by default.
+ * SPIM does same thing.
*
* @param value True to enable delayed branching, false otherwise.
* @deprecated Use setBooleanSetting(int id, boolean value) with the appropriate boolean setting ID
- * (e.g. Settings.DELAYED_BRANCHING_ENABLED)
+ * (e.g. Settings.DELAYED_BRANCHING_ENABLED)
*/
@Deprecated
- public void setDelayedBranchingEnabled(boolean value) {
+ public void setDelayedBranchingEnabled(boolean value)
+ {
internalSetBooleanSetting(DELAYED_BRANCHING_ENABLED, value);
}
@@ -694,25 +784,26 @@ public class Settings extends Observable {
* Setting concerning whether or not to display the Labels Window -- symbol table.
*
* @return true if label window is to be displayed, false otherwise.
- * @deprecated Use getBooleanSetting(int id) with the appropriate boolean setting ID
- * (e.g. Settings.LABEL_WINDOW_VISIBILITY)
+ * @deprecated Use getBooleanSetting(int id) with the appropriate boolean setting ID (e.g.
+ * Settings.LABEL_WINDOW_VISIBILITY)
*/
@Deprecated
- public boolean getLabelWindowVisibility() {
+ public boolean getLabelWindowVisibility()
+ {
return booleanSettingsValues[LABEL_WINDOW_VISIBILITY];
}
/**
- * Establish setting for whether the labels window (i.e. symbol table) will
- * be displayed as part of the Text Segment display. If setting changes,
- * new setting will be written to properties file.
+ * Establish setting for whether the labels window (i.e. symbol table) will be displayed as part of the Text Segment
+ * display. If setting changes, new setting will be written to properties file.
*
* @param value True to dispay labels window, false otherwise.
* @deprecated Use setBooleanSetting(int id, boolean value) with the appropriate boolean setting ID
- * (e.g. Settings.LABEL_WINDOW_VISIBILITY)
+ * (e.g. Settings.LABEL_WINDOW_VISIBILITY)
*/
@Deprecated
- public void setLabelWindowVisibility(boolean value) {
+ public void setLabelWindowVisibility(boolean value)
+ {
internalSetBooleanSetting(LABEL_WINDOW_VISIBILITY, value);
}
@@ -720,24 +811,25 @@ public class Settings extends Observable {
* Setting concerning whether or not the editor will display line numbers.
*
* @return true if line numbers are to be displayed, false otherwise.
- * @deprecated Use getBooleanSetting(int id) with the appropriate boolean setting ID
- * (e.g. Settings.EDITOR_LINE_NUMBERS_DISPLAYED)
+ * @deprecated Use getBooleanSetting(int id) with the appropriate boolean setting ID (e.g.
+ * Settings.EDITOR_LINE_NUMBERS_DISPLAYED)
*/
@Deprecated
- public boolean getEditorLineNumbersDisplayed() {
+ public boolean getEditorLineNumbersDisplayed()
+ {
return booleanSettingsValues[EDITOR_LINE_NUMBERS_DISPLAYED];
}
/**
- * Establish setting for whether line numbers will be displayed by the
- * text editor.
+ * Establish setting for whether line numbers will be displayed by the text editor.
*
* @param value True to display line numbers, false otherwise.
* @deprecated Use setBooleanSetting(int id, boolean value) with the appropriate boolean setting ID
- * (e.g. Settings.EDITOR_LINE_NUMBERS_DISPLAYED)
+ * (e.g. Settings.EDITOR_LINE_NUMBERS_DISPLAYED)
*/
@Deprecated
- public void setEditorLineNumbersDisplayed(boolean value) {
+ public void setEditorLineNumbersDisplayed(boolean value)
+ {
internalSetBooleanSetting(EDITOR_LINE_NUMBERS_DISPLAYED, value);
}
@@ -745,11 +837,12 @@ public class Settings extends Observable {
* Setting concerning whether or not assembler will consider warnings to be errors.
*
* @return true if warnings are considered errors, false otherwise.
- * @deprecated Use getBooleanSetting(int id) with the appropriate boolean setting ID
- * (e.g. Settings.WARNINGS_ARE_ERRORS)
+ * @deprecated Use getBooleanSetting(int id) with the appropriate boolean setting ID (e.g.
+ * Settings.WARNINGS_ARE_ERRORS)
*/
@Deprecated
- public boolean getWarningsAreErrors() {
+ public boolean getWarningsAreErrors()
+ {
return booleanSettingsValues[WARNINGS_ARE_ERRORS];
}
@@ -758,10 +851,11 @@ public class Settings extends Observable {
*
* @param value True to consider warnings to be errors, false otherwise.
* @deprecated Use setBooleanSetting(int id, boolean value) with the appropriate boolean setting ID
- * (e.g. Settings.WARNINGS_ARE_ERRORS)
+ * (e.g. Settings.WARNINGS_ARE_ERRORS)
*/
@Deprecated
- public void setWarningsAreErrors(boolean value) {
+ public void setWarningsAreErrors(boolean value)
+ {
internalSetBooleanSetting(WARNINGS_ARE_ERRORS, value);
}
@@ -769,11 +863,12 @@ public class Settings extends Observable {
* Setting concerning whether or not program arguments can be entered and used.
*
* @return true if program arguments can be entered/used, false otherwise.
- * @deprecated Use getBooleanSetting(int id) with the appropriate boolean setting ID
- * (e.g. Settings.PROGRAM_ARGUMENTS)
+ * @deprecated Use getBooleanSetting(int id) with the appropriate boolean setting ID (e.g.
+ * Settings.PROGRAM_ARGUMENTS)
*/
@Deprecated
- public boolean getProgramArguments() {
+ public boolean getProgramArguments()
+ {
return booleanSettingsValues[PROGRAM_ARGUMENTS];
}
@@ -782,10 +877,11 @@ public class Settings extends Observable {
*
* @param value True if program arguments can be entered/used, false otherwise.
* @deprecated Use setBooleanSetting(int id, boolean value) with the appropriate boolean setting ID
- * (e.g. Settings.PROGRAM_ARGUMENTS)
+ * (e.g. Settings.PROGRAM_ARGUMENTS)
*/
@Deprecated
- public void setProgramArguments(boolean value) {
+ public void setProgramArguments(boolean value)
+ {
internalSetBooleanSetting(PROGRAM_ARGUMENTS, value);
}
@@ -793,76 +889,79 @@ public class Settings extends Observable {
* Setting concerning whether or not highlighting is applied to Data Segment window.
*
* @return true if highlighting is to be applied, false otherwise.
- * @deprecated Use getBooleanSetting(int id) with the appropriate boolean setting ID
- * (e.g. Settings.DATA_SEGMENT_HIGHLIGHTING)
+ * @deprecated Use getBooleanSetting(int id) with the appropriate boolean setting ID (e.g.
+ * Settings.DATA_SEGMENT_HIGHLIGHTING)
*/
@Deprecated
- public boolean getDataSegmentHighlighting() {
+ public boolean getDataSegmentHighlighting()
+ {
return booleanSettingsValues[DATA_SEGMENT_HIGHLIGHTING];
}
/**
- * Establish setting for whether highlighting is to be applied to
- * Data Segment window.
+ * Establish setting for whether highlighting is to be applied to Data Segment window.
*
* @param value True if highlighting is to be applied, false otherwise.
* @deprecated Use setBooleanSetting(int id, boolean value) with the appropriate boolean setting ID
- * (e.g. Settings.DATA_SEGMENT_HIGHLIGHTING)
+ * (e.g. Settings.DATA_SEGMENT_HIGHLIGHTING)
*/
@Deprecated
- public void setDataSegmentHighlighting(boolean value) {
+ public void setDataSegmentHighlighting(boolean value)
+ {
internalSetBooleanSetting(DATA_SEGMENT_HIGHLIGHTING, value);
}
/**
- * Setting concerning whether or not highlighting is applied to Registers,
- * Coprocessor0, and Coprocessor1 windows.
+ * Setting concerning whether or not highlighting is applied to Registers, Coprocessor0, and Coprocessor1 windows.
*
* @return true if highlighting is to be applied, false otherwise.
- * @deprecated Use getBooleanSetting(int id) with the appropriate boolean setting ID
- * (e.g. Settings.REGISTERS_HIGHLIGHTING)
+ * @deprecated Use getBooleanSetting(int id) with the appropriate boolean setting ID (e.g.
+ * Settings.REGISTERS_HIGHLIGHTING)
*/
@Deprecated
- public boolean getRegistersHighlighting() {
+ public boolean getRegistersHighlighting()
+ {
return booleanSettingsValues[REGISTERS_HIGHLIGHTING];
}
/**
- * Establish setting for whether highlighting is to be applied to
- * Registers, Coprocessor0 and Coprocessor1 windows.
+ * Establish setting for whether highlighting is to be applied to Registers, Coprocessor0 and Coprocessor1 windows.
*
* @param value True if highlighting is to be applied, false otherwise.
* @deprecated Use setBooleanSetting(int id, boolean value) with the appropriate boolean setting ID
- * (e.g. Settings.REGISTERS_HIGHLIGHTING)
+ * (e.g. Settings.REGISTERS_HIGHLIGHTING)
*/
@Deprecated
- public void setRegistersHighlighting(boolean value) {
+ public void setRegistersHighlighting(boolean value)
+ {
internalSetBooleanSetting(REGISTERS_HIGHLIGHTING, value);
}
/**
- * Setting concerning whether or not assembler will automatically initialize
- * the program counter to address of statement labeled 'main' if defined.
+ * Setting concerning whether or not assembler will automatically initialize the program counter to address of
+ * statement labeled 'main' if defined.
*
* @return true if it initializes to 'main', false otherwise.
- * @deprecated Use getBooleanSetting(int id) with the appropriate boolean setting ID
- * (e.g. Settings.START_AT_MAIN)
+ * @deprecated Use getBooleanSetting(int id) with the appropriate boolean setting ID (e.g.
+ * Settings.START_AT_MAIN)
*/
@Deprecated
- public boolean getStartAtMain() {
+ public boolean getStartAtMain()
+ {
return booleanSettingsValues[START_AT_MAIN];
}
/**
- * Establish setting for whether assembler will automatically initialize
- * program counter to address of statement labeled 'main' if defined.
+ * Establish setting for whether assembler will automatically initialize program counter to address of statement
+ * labeled 'main' if defined.
*
* @param value True if PC set to address of 'main', false otherwise.
* @deprecated Use setBooleanSetting(int id, boolean value) with the appropriate boolean setting ID
- * (e.g. Settings.START_AT_MAIN)
+ * (e.g. Settings.START_AT_MAIN)
*/
@Deprecated
- public void setStartAtMain(boolean value) {
+ public void setStartAtMain(boolean value)
+ {
internalSetBooleanSetting(START_AT_MAIN, value);
}
@@ -871,7 +970,8 @@ public class Settings extends Observable {
*
* @return String pathname of current exception handler file, empty if none.
*/
- public String getExceptionHandler() {
+ public String getExceptionHandler()
+ {
return stringSettingsValues[EXCEPTION_HANDLER];
}
@@ -885,7 +985,8 @@ public class Settings extends Observable {
*
* @param newFilename name of exception handler file
*/
- public void setExceptionHandler(String newFilename) {
+ public void setExceptionHandler(String newFilename)
+ {
setStringSetting(EXCEPTION_HANDLER, newFilename);
}
@@ -894,7 +995,8 @@ public class Settings extends Observable {
*
* @return String identifier of current built-in memory configuration, empty if none.
*/
- public String getMemoryConfiguration() {
+ public String getMemoryConfiguration()
+ {
return stringSettingsValues[MEMORY_CONFIGURATION];
}
@@ -904,28 +1006,29 @@ public class Settings extends Observable {
* @param config A string that identifies the current built-in memory configuration
*/
- public void setMemoryConfiguration(String config) {
+ public void setMemoryConfiguration(String config)
+ {
setStringSetting(MEMORY_CONFIGURATION, config);
}
/**
- * Current editor font. Retained for compatibility but replaced
- * by: getFontByPosition(Settings.EDITOR_FONT)
+ * Current editor font. Retained for compatibility but replaced by: getFontByPosition(Settings.EDITOR_FONT)
*
* @return Font object for current editor font.
*/
- public Font getEditorFont() {
+ public Font getEditorFont()
+ {
return getFontByPosition(EDITOR_FONT);
}
/**
- * Set editor font to the specified Font object and write it to persistent storage.
- * This method retained for compatibility but replaced by:
- * setFontByPosition(Settings.EDITOR_FONT, font)
+ * Set editor font to the specified Font object and write it to persistent storage. This method retained for
+ * compatibility but replaced by: setFontByPosition(Settings.EDITOR_FONT, font)
*
* @param font Font object to be used by text editor.
*/
- public void setEditorFont(Font font) {
+ public void setEditorFont(Font font)
+ {
setFontByPosition(EDITOR_FONT, font);
}
@@ -935,10 +1038,14 @@ public class Settings extends Observable {
* @param fontSettingPosition constant that identifies which item
* @return Font object for given item
*/
- public Font getFontByPosition(int fontSettingPosition) {
- if (fontSettingPosition >= 0 && fontSettingPosition < fontFamilySettingsValues.length) {
+ public Font getFontByPosition(int fontSettingPosition)
+ {
+ if (fontSettingPosition >= 0 && fontSettingPosition < fontFamilySettingsValues.length)
+ {
return EditorFont.createFontFromStringValues(fontFamilySettingsValues[fontSettingPosition], fontStyleSettingsValues[fontSettingPosition], fontSizeSettingsValues[fontSettingPosition]);
- } else {
+ }
+ else
+ {
return null;
}
}
@@ -949,10 +1056,14 @@ public class Settings extends Observable {
* @param fontSettingPosition constant that identifies which item
* @return Font object for given item
*/
- public Font getDefaultFontByPosition(int fontSettingPosition) {
- if (fontSettingPosition >= 0 && fontSettingPosition < defaultFontFamilySettingsValues.length) {
+ public Font getDefaultFontByPosition(int fontSettingPosition)
+ {
+ if (fontSettingPosition >= 0 && fontSettingPosition < defaultFontFamilySettingsValues.length)
+ {
return EditorFont.createFontFromStringValues(defaultFontFamilySettingsValues[fontSettingPosition], defaultFontStyleSettingsValues[fontSettingPosition], defaultFontSizeSettingsValues[fontSettingPosition]);
- } else {
+ }
+ else
+ {
return null;
}
}
@@ -962,37 +1073,42 @@ public class Settings extends Observable {
*
* @return Array of int indicating the order. Original order is 0 1 2 3 4.
*/
- public int[] getTextColumnOrder() {
+ public int[] getTextColumnOrder()
+ {
return getTextSegmentColumnOrder(stringSettingsValues[TEXT_COLUMN_ORDER]);
}
/**
- * Store the current order of Text Segment window table columns, so the ordering
- * can be preserved and restored.
+ * Store the current order of Text Segment window table columns, so the ordering can be preserved and restored.
*
* @param columnOrder An array of int indicating column order.
*/
- public void setTextColumnOrder(int[] columnOrder) {
+ public void setTextColumnOrder(int[] columnOrder)
+ {
String stringifiedOrder = "";
- for (int j : columnOrder) {
+ for (int j : columnOrder)
+ {
stringifiedOrder += j + " ";
}
setStringSetting(TEXT_COLUMN_ORDER, stringifiedOrder);
}
/**
- * Retrieve the caret blink rate in milliseconds. Blink rate of 0 means
- * do not blink.
+ * Retrieve the caret blink rate in milliseconds. Blink rate of 0 means do not blink.
*
* @return int blink rate in milliseconds
*/
- public int getCaretBlinkRate() {
+ public int getCaretBlinkRate()
+ {
int rate = 500;
- try {
+ try
+ {
rate = Integer.parseInt(stringSettingsValues[CARET_BLINK_RATE]);
- } catch (NumberFormatException nfe) {
+ }
+ catch (NumberFormatException nfe)
+ {
rate = Integer.parseInt(defaultStringSettingsValues[CARET_BLINK_RATE]);
}
return rate;
@@ -1003,7 +1119,8 @@ public class Settings extends Observable {
*
* @param rate blink rate in milliseconds
*/
- public void setCaretBlinkRate(int rate) {
+ public void setCaretBlinkRate(int rate)
+ {
setStringSetting(CARET_BLINK_RATE, "" + rate);
}
@@ -1012,11 +1129,15 @@ public class Settings extends Observable {
*
* @return tab size in characters.
*/
- public int getEditorTabSize() {
+ public int getEditorTabSize()
+ {
int size = 8;
- try {
+ try
+ {
size = Integer.parseInt(stringSettingsValues[EDITOR_TAB_SIZE]);
- } catch (NumberFormatException nfe) {
+ }
+ catch (NumberFormatException nfe)
+ {
size = getDefaultEditorTabSize();
}
return size;
@@ -1027,22 +1148,27 @@ public class Settings extends Observable {
*
* @param size tab size in characters.
*/
- public void setEditorTabSize(int size) {
+ public void setEditorTabSize(int size)
+ {
setStringSetting(EDITOR_TAB_SIZE, "" + size);
}
/**
* Get number of letters to be matched by editor's instruction guide before popup generated (if popup enabled).
- * Should be 1 or 2. If 1, the popup will be generated after first letter typed, based on all matches; if 2,
- * the popup will be generated after second letter typed.
+ * Should be 1 or 2. If 1, the popup will be generated after first letter typed, based on all matches; if 2, the
+ * popup will be generated after second letter typed.
*
* @return number of letters (should be 1 or 2).
*/
- public int getEditorPopupPrefixLength() {
+ public int getEditorPopupPrefixLength()
+ {
int length = 2;
- try {
+ try
+ {
length = Integer.parseInt(stringSettingsValues[EDITOR_POPUP_PREFIX_LENGTH]);
- } catch (NumberFormatException ignored) {
+ }
+ catch (NumberFormatException ignored)
+ {
}
return length;
@@ -1050,12 +1176,13 @@ public class Settings extends Observable {
/**
* Set number of letters to be matched by editor's instruction guide before popup generated (if popup enabled).
- * Should be 1 or 2. If 1, the popup will be generated after first letter typed, based on all matches; if 2,
- * the popup will be generated after second letter typed.
+ * Should be 1 or 2. If 1, the popup will be generated after first letter typed, based on all matches; if 2, the
+ * popup will be generated after second letter typed.
*
* @param length number of letters (should be 1 or 2).
*/
- public void setEditorPopupPrefixLength(int length) {
+ public void setEditorPopupPrefixLength(int length)
+ {
setStringSetting(EDITOR_POPUP_PREFIX_LENGTH, "" + length);
}
@@ -1064,18 +1191,19 @@ public class Settings extends Observable {
*
* @return tab size in characters
*/
- public int getDefaultEditorTabSize() {
+ public int getDefaultEditorTabSize()
+ {
return Integer.parseInt(defaultStringSettingsValues[EDITOR_TAB_SIZE]);
}
/**
- * Get the saved state of the Labels Window sorting (can sort by either
- * label or address and either ascending or descending order).
- * Default state is 0, by ascending addresses.
+ * Get the saved state of the Labels Window sorting (can sort by either label or address and either ascending or
+ * descending order). Default state is 0, by ascending addresses.
*
* @return State value 0-7, as a String.
*/
- public String getLabelSortState() {
+ public String getLabelSortState()
+ {
return stringSettingsValues[LABEL_SORT_STATE];
}
@@ -1086,97 +1214,109 @@ public class Settings extends Observable {
* @param state The current labels window sorting state, as a String.
*/
- public void setLabelSortState(String state) {
+ public void setLabelSortState(String state)
+ {
setStringSetting(LABEL_SORT_STATE, state);
}
/**
- * Get Color object for specified settings key.
- * Returns null if key is not found or its value is not a valid color encoding.
+ * Get Color object for specified settings key. Returns null if key is not found or its value is not a valid color
+ * encoding.
*
* @param key the Setting key
* @return corresponding Color, or null if key not found or value not valid color
*/
- public Color getColorSettingByKey(String key) {
+ public Color getColorSettingByKey(String key)
+ {
return getColorValueByKey(key, colorSettingsValues);
}
/**
- * Get default Color value for specified settings key.
- * Returns null if key is not found or its value is not a valid color encoding.
+ * Get default Color value for specified settings key. Returns null if key is not found or its value is not a valid
+ * color encoding.
*
* @param key the Setting key
* @return corresponding default Color, or null if key not found or value not valid color
*/
- public Color getDefaultColorSettingByKey(String key) {
+ public Color getDefaultColorSettingByKey(String key)
+ {
return getColorValueByKey(key, defaultColorSettingsValues);
}
/**
- * Get Color object for specified settings name (a static constant).
- * Returns null if argument invalid or its value is not a valid color encoding.
+ * Get Color object for specified settings name (a static constant). Returns null if argument invalid or its value
+ * is not a valid color encoding.
*
* @param position the Setting name (see list of static constants)
* @return corresponding Color, or null if argument invalid or value not valid color
*/
- public Color getColorSettingByPosition(int position) {
+ public Color getColorSettingByPosition(int position)
+ {
return getColorValueByPosition(position, colorSettingsValues);
}
/**
- * Get default Color object for specified settings name (a static constant).
- * Returns null if argument invalid or its value is not a valid color encoding.
+ * Get default Color object for specified settings name (a static constant). Returns null if argument invalid or its
+ * value is not a valid color encoding.
*
* @param position the Setting name (see list of static constants)
* @return corresponding default Color, or null if argument invalid or value not valid color
*/
- public Color getDefaultColorSettingByPosition(int position) {
+ public Color getDefaultColorSettingByPosition(int position)
+ {
return getColorValueByPosition(position, defaultColorSettingsValues);
}
/**
* Set value of a boolean setting given its id and the value.
*
- * @param id int containing the setting's identifier (constants listed above)
+ * @param id int containing the setting's identifier (constants listed above)
* @param value boolean value to store
* @throws IllegalArgumentException if identifier is not valid.
*/
- public void setBooleanSetting(int id, boolean value) {
- if (id >= 0 && id < booleanSettingsValues.length) {
+ public void setBooleanSetting(int id, boolean value)
+ {
+ if (id >= 0 && id < booleanSettingsValues.length)
+ {
internalSetBooleanSetting(id, value);
- } else {
+ }
+ else
+ {
throw new IllegalArgumentException("Invalid boolean setting ID");
}
}
/**
- * Temporarily establish boolean setting. This setting will NOT be written to persisent
- * store! Currently this is used only when running MARS from the command line
+ * Temporarily establish boolean setting. This setting will NOT be written to persisent store! Currently this is
+ * used only when running MARS from the command line
*
- * @param id setting identifier. These are defined for this class as static final int.
+ * @param id setting identifier. These are defined for this class as static final int.
* @param value True to enable the setting, false otherwise.
*/
- public void setBooleanSettingNonPersistent(int id, boolean value) {
- if (id >= 0 && id < booleanSettingsValues.length) {
+ public void setBooleanSettingNonPersistent(int id, boolean value)
+ {
+ if (id >= 0 && id < booleanSettingsValues.length)
+ {
booleanSettingsValues[id] = value;
- } else {
+ }
+ else
+ {
throw new IllegalArgumentException("Invalid boolean setting ID");
}
}
/**
- * Establish setting for whether delayed branching will be applied during
- * MIPS program execution. This setting will NOT be written to persisent
- * store! This method should be called only to temporarily set this
- * setting -- currently this is needed only when running MARS from the
- * command line.
+ * Establish setting for whether delayed branching will be applied during MIPS program execution. This setting will
+ * NOT be written to persisent store! This method should be called only to temporarily set this setting --
+ * currently this is needed only when running MARS from the command line.
*
* @param value True to enabled delayed branching, false otherwise.
- * @deprecated Use setBooleanSettingNonPersistent(int id, boolean value) with the appropriate boolean setting ID
- * (e.g. Settings.DELAYED_BRANCHING_ENABLED)
+ * @deprecated Use setBooleanSettingNonPersistent(int id, boolean value) with the appropriate boolean
+ * setting ID (e.g. Settings.DELAYED_BRANCHING_ENABLED)
*/
@Deprecated
- public void setDelayedBranchingEnabledNonPersistent(boolean value) {
+ public void setDelayedBranchingEnabledNonPersistent(boolean value)
+ {
// Note: Doing assignment to array results in non-persistent
// setting (lost when MARS terminates). For persistent, use
// the internalSetBooleanSetting() method instead.
@@ -1187,10 +1327,12 @@ public class Settings extends Observable {
* Store a Font setting
*
* @param fontSettingPosition Constant that identifies the item the font goes with
- * @param font The font to set that item to
+ * @param font The font to set that item to
*/
- public void setFontByPosition(int fontSettingPosition, Font font) {
- if (fontSettingPosition >= 0 && fontSettingPosition < fontFamilySettingsValues.length) {
+ public void setFontByPosition(int fontSettingPosition, Font font)
+ {
+ if (fontSettingPosition >= 0 && fontSettingPosition < fontFamilySettingsValues.length)
+ {
fontFamilySettingsValues[fontSettingPosition] = font.getFamily();
fontStyleSettingsValues[fontSettingPosition] = EditorFont.styleIntToStyleString(font.getStyle());
fontSizeSettingsValues[fontSettingPosition] = EditorFont.sizeIntToSizeString(font.getSize());
@@ -1198,7 +1340,8 @@ public class Settings extends Observable {
saveFontSetting(fontSettingPosition, fontStyleSettingsKeys, fontStyleSettingsValues);
saveFontSetting(fontSettingPosition, fontSizeSettingsKeys, fontSizeSettingsValues);
}
- if (fontSettingPosition == EDITOR_FONT) {
+ if (fontSettingPosition == EDITOR_FONT)
+ {
setChanged();
notifyObservers();
}
@@ -1207,12 +1350,15 @@ public class Settings extends Observable {
/**
* Set Color object for specified settings key. Has no effect if key is invalid.
*
- * @param key the Setting key
+ * @param key the Setting key
* @param color the Color to save
*/
- public void setColorSettingByKey(String key, Color color) {
- for (int i = 0; i < colorSettingsKeys.length; i++) {
- if (key.equals(colorSettingsKeys[i])) {
+ public void setColorSettingByKey(String key, Color color)
+ {
+ for (int i = 0; i < colorSettingsKeys.length; i++)
+ {
+ if (key.equals(colorSettingsKeys[i]))
+ {
setColorSettingByPosition(i, color);
return;
}
@@ -1223,10 +1369,12 @@ public class Settings extends Observable {
* Set Color object for specified settings name (a static constant). Has no effect if invalid.
*
* @param position the Setting name (see list of static constants)
- * @param color the Color to save
+ * @param color the Color to save
*/
- public void setColorSettingByPosition(int position, Color color) {
- if (position >= 0 && position < colorSettingsKeys.length) {
+ public void setColorSettingByPosition(int position, Color color)
+ {
+ if (position >= 0 && position < colorSettingsKeys.length)
+ {
setColorSetting(position, color);
}
}
@@ -1242,19 +1390,23 @@ public class Settings extends Observable {
// If that fails, set from array.
// In either case, use these values as defaults in call to Preferences.
- private void initialize() {
+ private void initialize()
+ {
applyDefaultSettings();
- if (!readSettingsFromPropertiesFile(settingsFile)) {
+ if (!readSettingsFromPropertiesFile(settingsFile))
+ {
System.out.println("MARS System error: unable to read Settings.properties defaults. Using built-in defaults.");
}
getSettingsFromPreferences();
}
// Default values. Will be replaced if available from property file or Preferences object.
- private void applyDefaultSettings() {
+ private void applyDefaultSettings()
+ {
System.arraycopy(defaultBooleanSettingsValues, 0, booleanSettingsValues, 0, booleanSettingsValues.length);
System.arraycopy(defaultStringSettingsValues, 0, stringSettingsValues, 0, stringSettingsValues.length);
- for (int i = 0; i < fontFamilySettingsValues.length; i++) {
+ for (int i = 0; i < fontFamilySettingsValues.length; i++)
+ {
fontFamilySettingsValues[i] = defaultFontFamilySettingsValues[i];
fontStyleSettingsValues[i] = defaultFontStyleSettingsValues[i];
fontSizeSettingsValues[i] = defaultFontSizeSettingsValues[i];
@@ -1264,8 +1416,10 @@ public class Settings extends Observable {
}
// Used by all the boolean setting "setter" methods.
- private void internalSetBooleanSetting(int settingIndex, boolean value) {
- if (value != booleanSettingsValues[settingIndex]) {
+ private void internalSetBooleanSetting(int settingIndex, boolean value)
+ {
+ if (value != booleanSettingsValues[settingIndex])
+ {
booleanSettingsValues[settingIndex] = value;
saveBooleanSetting(settingIndex);
setChanged();
@@ -1274,23 +1428,28 @@ public class Settings extends Observable {
}
// Used by setter method(s) for string-based settings (initially, only exception handler name)
- private void setStringSetting(int settingIndex, String value) {
+ private void setStringSetting(int settingIndex, String value)
+ {
stringSettingsValues[settingIndex] = value;
saveStringSetting(settingIndex);
}
// Used by setter methods for color-based settings
- private void setColorSetting(int settingIndex, Color color) {
+ private void setColorSetting(int settingIndex, Color color)
+ {
colorSettingsValues[settingIndex] = Binary.intToHexString(color.getRed() << 16 | color.getGreen() << 8 | color.getBlue());
saveColorSetting(settingIndex);
}
// Get Color object for this key value. Get it from values array provided as argument (could be either
// the current or the default settings array).
- private Color getColorValueByKey(String key, String[] values) {
+ private Color getColorValueByKey(String key, String[] values)
+ {
Color color = null;
- for (int i = 0; i < colorSettingsKeys.length; i++) {
- if (key.equals(colorSettingsKeys[i])) {
+ for (int i = 0; i < colorSettingsKeys.length; i++)
+ {
+ if (key.equals(colorSettingsKeys[i]))
+ {
return getColorValueByPosition(i, values);
}
}
@@ -1299,12 +1458,17 @@ public class Settings extends Observable {
// Get Color object for this key array position. Get it from values array provided as argument (could be either
// the current or the default settings array).
- private Color getColorValueByPosition(int position, String[] values) {
+ private Color getColorValueByPosition(int position, String[] values)
+ {
Color color = null;
- if (position >= 0 && position < colorSettingsKeys.length) {
- try {
+ if (position >= 0 && position < colorSettingsKeys.length)
+ {
+ try
+ {
color = Color.decode(values[position]);
- } catch (NumberFormatException ignored) {
+ }
+ catch (NumberFormatException ignored)
+ {
}
}
return color;
@@ -1314,10 +1478,13 @@ public class Settings extends Observable {
// Maybe someday I'll convert the whole shebang to use Maps. In the meantime, we use
// linear search of array. Not a huge deal as settings are little-used.
// Returns index or -1 if not found.
- private int getIndexOfKey(String key, String[] array) {
+ private int getIndexOfKey(String key, String[] array)
+ {
int index = -1;
- for (int i = 0; i < array.length; i++) {
- if (array[i].equals(key)) {
+ for (int i = 0; i < array.length; i++)
+ {
+ if (array[i].equals(key))
+ {
index = i;
break;
}
@@ -1340,33 +1507,56 @@ public class Settings extends Observable {
// In that case, this method will NOT make an assignment to the settings array!
// So consider it a precondition of this method: the settings arrays must already be
// initialized with last-resort default values.
- private boolean readSettingsFromPropertiesFile(String filename) {
+ private boolean readSettingsFromPropertiesFile(String filename)
+ {
String settingValue;
- try {
- for (int i = 0; i < booleanSettingsKeys.length; i++) {
+ try
+ {
+ for (int i = 0; i < booleanSettingsKeys.length; i++)
+ {
settingValue = Globals.getPropertyEntry(filename, booleanSettingsKeys[i]);
- if (settingValue != null) {
+ if (settingValue != null)
+ {
booleanSettingsValues[i] = defaultBooleanSettingsValues[i] = Boolean.parseBoolean(settingValue);
}
}
- for (int i = 0; i < stringSettingsKeys.length; i++) {
+ for (int i = 0; i < stringSettingsKeys.length; i++)
+ {
settingValue = Globals.getPropertyEntry(filename, stringSettingsKeys[i]);
- if (settingValue != null) stringSettingsValues[i] = defaultStringSettingsValues[i] = settingValue;
+ if (settingValue != null)
+ {
+ stringSettingsValues[i] = defaultStringSettingsValues[i] = settingValue;
+ }
}
- for (int i = 0; i < fontFamilySettingsValues.length; i++) {
+ for (int i = 0; i < fontFamilySettingsValues.length; i++)
+ {
settingValue = Globals.getPropertyEntry(filename, fontFamilySettingsKeys[i]);
if (settingValue != null)
+ {
fontFamilySettingsValues[i] = defaultFontFamilySettingsValues[i] = settingValue;
+ }
settingValue = Globals.getPropertyEntry(filename, fontStyleSettingsKeys[i]);
- if (settingValue != null) fontStyleSettingsValues[i] = defaultFontStyleSettingsValues[i] = settingValue;
+ if (settingValue != null)
+ {
+ fontStyleSettingsValues[i] = defaultFontStyleSettingsValues[i] = settingValue;
+ }
settingValue = Globals.getPropertyEntry(filename, fontSizeSettingsKeys[i]);
- if (settingValue != null) fontSizeSettingsValues[i] = defaultFontSizeSettingsValues[i] = settingValue;
+ if (settingValue != null)
+ {
+ fontSizeSettingsValues[i] = defaultFontSizeSettingsValues[i] = settingValue;
+ }
}
- for (int i = 0; i < colorSettingsKeys.length; i++) {
+ for (int i = 0; i < colorSettingsKeys.length; i++)
+ {
settingValue = Globals.getPropertyEntry(filename, colorSettingsKeys[i]);
- if (settingValue != null) colorSettingsValues[i] = defaultColorSettingsValues[i] = settingValue;
+ if (settingValue != null)
+ {
+ colorSettingsValues[i] = defaultColorSettingsValues[i] = settingValue;
+ }
}
- } catch (Exception e) {
+ }
+ catch (Exception e)
+ {
return false;
}
return true;
@@ -1379,19 +1569,24 @@ public class Settings extends Observable {
//
// PRECONDITION: Values arrays have already been initialized to default values from
// Settings.properties file or default value arrays above!
- private void getSettingsFromPreferences() {
- for (int i = 0; i < booleanSettingsKeys.length; i++) {
+ private void getSettingsFromPreferences()
+ {
+ for (int i = 0; i < booleanSettingsKeys.length; i++)
+ {
booleanSettingsValues[i] = preferences.getBoolean(booleanSettingsKeys[i], booleanSettingsValues[i]);
}
- for (int i = 0; i < stringSettingsKeys.length; i++) {
+ for (int i = 0; i < stringSettingsKeys.length; i++)
+ {
stringSettingsValues[i] = preferences.get(stringSettingsKeys[i], stringSettingsValues[i]);
}
- for (int i = 0; i < fontFamilySettingsKeys.length; i++) {
+ for (int i = 0; i < fontFamilySettingsKeys.length; i++)
+ {
fontFamilySettingsValues[i] = preferences.get(fontFamilySettingsKeys[i], fontFamilySettingsValues[i]);
fontStyleSettingsValues[i] = preferences.get(fontStyleSettingsKeys[i], fontStyleSettingsValues[i]);
fontSizeSettingsValues[i] = preferences.get(fontSizeSettingsKeys[i], fontSizeSettingsValues[i]);
}
- for (int i = 0; i < colorSettingsKeys.length; i++) {
+ for (int i = 0; i < colorSettingsKeys.length; i++)
+ {
colorSettingsValues[i] = preferences.get(colorSettingsKeys[i], colorSettingsValues[i]);
}
getEditorSyntaxStyleSettingsFromPreferences();
@@ -1399,52 +1594,76 @@ public class Settings extends Observable {
// Save the key-value pair in the Properties object and assure it is written to persisent storage.
- private void saveBooleanSetting(int index) {
- try {
+ private void saveBooleanSetting(int index)
+ {
+ try
+ {
preferences.putBoolean(booleanSettingsKeys[index], booleanSettingsValues[index]);
preferences.flush();
- } catch (SecurityException se) {
+ }
+ catch (SecurityException se)
+ {
// cannot write to persistent storage for security reasons
- } catch (BackingStoreException bse) {
+ }
+ catch (BackingStoreException bse)
+ {
// unable to communicate with persistent storage (strange days)
}
}
// Save the key-value pair in the Properties object and assure it is written to persisent storage.
- private void saveStringSetting(int index) {
- try {
+ private void saveStringSetting(int index)
+ {
+ try
+ {
preferences.put(stringSettingsKeys[index], stringSettingsValues[index]);
preferences.flush();
- } catch (SecurityException se) {
+ }
+ catch (SecurityException se)
+ {
// cannot write to persistent storage for security reasons
- } catch (BackingStoreException bse) {
+ }
+ catch (BackingStoreException bse)
+ {
// unable to communicate with persistent storage (strange days)
}
}
// Save the key-value pair in the Properties object and assure it is written to persisent storage.
- private void saveFontSetting(int index, String[] settingsKeys, String[] settingsValues) {
- try {
+ private void saveFontSetting(int index, String[] settingsKeys, String[] settingsValues)
+ {
+ try
+ {
preferences.put(settingsKeys[index], settingsValues[index]);
preferences.flush();
- } catch (SecurityException se) {
+ }
+ catch (SecurityException se)
+ {
// cannot write to persistent storage for security reasons
- } catch (BackingStoreException bse) {
+ }
+ catch (BackingStoreException bse)
+ {
// unable to communicate with persistent storage (strange days)
}
}
// Save the key-value pair in the Properties object and assure it is written to persisent storage.
- private void saveColorSetting(int index) {
- try {
+ private void saveColorSetting(int index)
+ {
+ try
+ {
preferences.put(colorSettingsKeys[index], colorSettingsValues[index]);
preferences.flush();
- } catch (SecurityException se) {
+ }
+ catch (SecurityException se)
+ {
// cannot write to persistent storage for security reasons
- } catch (BackingStoreException bse) {
+ }
+ catch (BackingStoreException bse)
+ {
// unable to communicate with persistent storage (strange days)
}
}
@@ -1456,22 +1675,27 @@ public class Settings extends Observable {
* If a problem occurs with the parameter string, will fall back to the
* default defined above.
*/
- private int[] getTextSegmentColumnOrder(String stringOfColumnIndexes) {
+ private int[] getTextSegmentColumnOrder(String stringOfColumnIndexes)
+ {
StringTokenizer st = new StringTokenizer(stringOfColumnIndexes);
int[] list = new int[st.countTokens()];
int index = 0, value;
boolean valuesOK = true;
- while (st.hasMoreTokens()) {
- try {
+ while (st.hasMoreTokens())
+ {
+ try
+ {
value = Integer.parseInt(st.nextToken());
} // could be either NumberFormatException or NoSuchElementException
- catch (Exception e) {
+ catch (Exception e)
+ {
valuesOK = false;
break;
}
list[index++] = value;
}
- if (!valuesOK && !stringOfColumnIndexes.equals(defaultStringSettingsValues[TEXT_COLUMN_ORDER])) {
+ if (!valuesOK && !stringOfColumnIndexes.equals(defaultStringSettingsValues[TEXT_COLUMN_ORDER]))
+ {
return getTextSegmentColumnOrder(defaultStringSettingsValues[TEXT_COLUMN_ORDER]);
}
return list;
diff --git a/src/main/java/mars/assembler/Assembler.java b/src/main/java/mars/assembler/Assembler.java
index 51c54ef..c2c5e53 100644
--- a/src/main/java/mars/assembler/Assembler.java
+++ b/src/main/java/mars/assembler/Assembler.java
@@ -1,22 +1,17 @@
- package mars.assembler;
+package mars.assembler;
- import java.util.ArrayList;
- import java.util.Collections;
- import java.util.Comparator;
+import mars.*;
+import mars.mips.hardware.AddressErrorException;
+import mars.mips.hardware.Memory;
+import mars.mips.instructions.BasicInstruction;
+import mars.mips.instructions.ExtendedInstruction;
+import mars.mips.instructions.Instruction;
+import mars.util.Binary;
+import mars.util.SystemIO;
- import mars.ErrorList;
- import mars.ErrorMessage;
- import mars.Globals;
- import mars.MIPSprogram;
- import mars.ProcessingException;
- import mars.ProgramStatement;
- import mars.mips.hardware.AddressErrorException;
- import mars.mips.hardware.Memory;
- import mars.mips.instructions.BasicInstruction;
- import mars.mips.instructions.ExtendedInstruction;
- import mars.mips.instructions.Instruction;
- import mars.util.Binary;
- import mars.util.SystemIO;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
/*
Copyright (c) 2003-2012, Pete Sanderson and Kenneth Vollmar
@@ -47,1469 +42,1697 @@
*/
/**
- * An Assembler is capable of assembling a MIPS program. It has only one public
- * method, assemble(), which implements a two-pass assembler. It
- * translates MIPS source code into binary machine code.
- *
+ * An Assembler is capable of assembling a MIPS program. It has only one public method, assemble(), which
+ * implements a two-pass assembler. It translates MIPS source code into binary machine code.
+ *
* @author Pete Sanderson
* @version August 2003
**/
- public class Assembler {
- private ArrayList machineList;
- private ErrorList errors;
- private boolean inDataSegment; // status maintained by parser
- private boolean inMacroSegment; // status maintained by parser, true if in
- // macro definition segment
- private int externAddress;
- private boolean autoAlign;
- private Directives currentDirective;
- private Directives dataDirective;
- private MIPSprogram fileCurrentlyBeingAssembled;
- private TokenList globalDeclarationList;
- private UserKernelAddressSpace textAddress;
- private UserKernelAddressSpace dataAddress;
- private DataSegmentForwardReferences currentFileDataSegmentForwardReferences,
- accumulatedDataSegmentForwardReferences;
-
- /**
- * Parse and generate machine code for the given MIPS program. It must have
- * already been tokenized. Warnings are not considered errors.
- *
- * @param p
- * A MIPSprogram object representing the program source.
- * @param extendedAssemblerEnabled
- * A boolean value that if true permits use of extended (pseudo)
- * instructions in the source code. If false, these are flagged
- * as errors.
- * @return An ArrayList representing the assembled program. Each member of
- * the list is a ProgramStatement object containing the source,
- * intermediate, and machine binary representations of a program
- * statement.
- *
- * @see ProgramStatement
- **/
- public ArrayList assemble(MIPSprogram p, boolean extendedAssemblerEnabled)
- throws ProcessingException {
- return assemble(p, extendedAssemblerEnabled, false);
- }
-
- /**
- * Parse and generate machine code for the given MIPS program. It must have
- * already been tokenized.
- *
- * @param p
- * A MIPSprogram object representing the program source.
- * @param extendedAssemblerEnabled
- * A boolean value that if true permits use of extended (pseudo)
- * instructions in the source code. If false, these are 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 An ArrayList representing the assembled program. Each member of
- * the list is a ProgramStatement object containing the source,
- * intermediate, and machine binary representations of a program
- * statement.
- *
- * @see ProgramStatement
- **/
- public ArrayList assemble(MIPSprogram p, boolean extendedAssemblerEnabled,
- boolean warningsAreErrors) throws ProcessingException {
- ArrayList programFiles = new ArrayList();
- programFiles.add(p);
- return this.assemble(programFiles, extendedAssemblerEnabled, warningsAreErrors);
- }
-
- /**
- * Get list of assembler errors and warnings
- *
- * @return ErrorList of any assembler errors and warnings.
- */
- public ErrorList getErrorList() {
- return errors;
- }
-
- /**
- * Parse and generate machine code for the given MIPS program. All source
- * files must have already been tokenized. Warnings will not be considered
- * errors.
- *
- * @param tokenizedProgramFiles
- * An ArrayList of MIPSprogram objects, each produced from a
- * different source code file, representing the program source.
- * @param extendedAssemblerEnabled
- * A boolean value that if true permits use of extended (pseudo)
- * instructions in the source code. If false, these are flagged
- * as errors.
- * @return An ArrayList representing the assembled program. Each member of
- * the list is a ProgramStatement object containing the source,
- * intermediate, and machine binary representations of a program
- * statement. Returns null if incoming array list is null or empty.
- *
- * @see ProgramStatement
- **/
- public ArrayList assemble(ArrayList tokenizedProgramFiles, boolean extendedAssemblerEnabled)
- throws ProcessingException {
- return assemble(tokenizedProgramFiles, extendedAssemblerEnabled, false);
- }
-
- /**
- * Parse and generate machine code for the given MIPS program. All source
- * files must have already been tokenized.
- *
- * @param tokenizedProgramFiles
- * An ArrayList of MIPSprogram objects, each produced from a
- * different source code file, representing the program source.
- * @param extendedAssemblerEnabled
- * A boolean value that if true permits use of extended (pseudo)
- * instructions in the source code. If false, these are 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 An ArrayList representing the assembled program. Each member of
- * the list is a ProgramStatement object containing the source,
- * intermediate, and machine binary representations of a program
- * statement. Returns null if incoming array list is null or empty.
- *
- * @see ProgramStatement
- **/
- public ArrayList assemble(ArrayList tokenizedProgramFiles, boolean extendedAssemblerEnabled,
- boolean warningsAreErrors) throws ProcessingException {
-
- if (tokenizedProgramFiles == null || tokenizedProgramFiles.size() == 0)
+public class Assembler
+{
+ private ArrayList machineList;
+
+ private ErrorList errors;
+
+ private boolean inDataSegment; // status maintained by parser
+
+ private boolean inMacroSegment; // status maintained by parser, true if in
+
+ // macro definition segment
+ private int externAddress;
+
+ private boolean autoAlign;
+
+ private Directives currentDirective;
+
+ private Directives dataDirective;
+
+ private MIPSprogram fileCurrentlyBeingAssembled;
+
+ private TokenList globalDeclarationList;
+
+ private UserKernelAddressSpace textAddress;
+
+ private UserKernelAddressSpace dataAddress;
+
+ private DataSegmentForwardReferences currentFileDataSegmentForwardReferences,
+ accumulatedDataSegmentForwardReferences;
+
+ /**
+ * Parse and generate machine code for the given MIPS program. It must have already been tokenized. Warnings are not
+ * considered errors.
+ *
+ * @param p A MIPSprogram object representing the program source.
+ * @param extendedAssemblerEnabled A boolean value that if true permits use of extended (pseudo) instructions in
+ * the source code. If false, these are flagged as errors.
+ * @return An ArrayList representing the assembled program. Each member of the list is a ProgramStatement object
+ * containing the source, intermediate, and machine binary representations of a program statement.
+ * @see ProgramStatement
+ **/
+ public ArrayList assemble(MIPSprogram p, boolean extendedAssemblerEnabled)
+ throws ProcessingException
+ {
+ return assemble(p, extendedAssemblerEnabled, false);
+ }
+
+ /**
+ * Parse and generate machine code for the given MIPS program. It must have already been tokenized.
+ *
+ * @param p A MIPSprogram object representing the program source.
+ * @param extendedAssemblerEnabled A boolean value that if true permits use of extended (pseudo) instructions in
+ * the source code. If false, these are 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 An ArrayList representing the assembled program. Each member of the list is a ProgramStatement object
+ * containing the source, intermediate, and machine binary representations of a program statement.
+ * @see ProgramStatement
+ **/
+ public ArrayList assemble(MIPSprogram p, boolean extendedAssemblerEnabled,
+ boolean warningsAreErrors) throws ProcessingException
+ {
+ ArrayList programFiles = new ArrayList();
+ programFiles.add(p);
+ return this.assemble(programFiles, extendedAssemblerEnabled, warningsAreErrors);
+ }
+
+ /**
+ * Get list of assembler errors and warnings
+ *
+ * @return ErrorList of any assembler errors and warnings.
+ */
+ public ErrorList getErrorList()
+ {
+ return errors;
+ }
+
+ /**
+ * Parse and generate machine code for the given MIPS program. All source files must have already been tokenized.
+ * Warnings will not be considered errors.
+ *
+ * @param tokenizedProgramFiles An ArrayList of MIPSprogram objects, each produced from a different source code
+ * file, representing the program source.
+ * @param extendedAssemblerEnabled A boolean value that if true permits use of extended (pseudo) instructions in
+ * the source code. If false, these are flagged as errors.
+ * @return An ArrayList representing the assembled program. Each member of the list is a ProgramStatement object
+ * containing the source, intermediate, and machine binary representations of a program statement. Returns null
+ * if incoming array list is null or empty.
+ * @see ProgramStatement
+ **/
+ public ArrayList assemble(ArrayList tokenizedProgramFiles, boolean extendedAssemblerEnabled)
+ throws ProcessingException
+ {
+ return assemble(tokenizedProgramFiles, extendedAssemblerEnabled, false);
+ }
+
+ /**
+ * Parse and generate machine code for the given MIPS program. All source files must have already been tokenized.
+ *
+ * @param tokenizedProgramFiles An ArrayList of MIPSprogram objects, each produced from a different source code
+ * file, representing the program source.
+ * @param extendedAssemblerEnabled A boolean value that if true permits use of extended (pseudo) instructions in
+ * the source code. If false, these are 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 An ArrayList representing the assembled program. Each member of the list is a ProgramStatement object
+ * containing the source, intermediate, and machine binary representations of a program statement. Returns null
+ * if incoming array list is null or empty.
+ * @see ProgramStatement
+ **/
+ public ArrayList assemble(ArrayList tokenizedProgramFiles, boolean extendedAssemblerEnabled,
+ boolean warningsAreErrors) throws ProcessingException
+ {
+
+ if (tokenizedProgramFiles == null || tokenizedProgramFiles.size() == 0)
+ {
return null;
- textAddress = new UserKernelAddressSpace(Memory.textBaseAddress,
+ }
+ textAddress = new UserKernelAddressSpace(Memory.textBaseAddress,
Memory.kernelTextBaseAddress);
- dataAddress = new UserKernelAddressSpace(Memory.dataBaseAddress,
+ dataAddress = new UserKernelAddressSpace(Memory.dataBaseAddress,
Memory.kernelDataBaseAddress);
- externAddress = Memory.externBaseAddress;
- currentFileDataSegmentForwardReferences = new DataSegmentForwardReferences();
- accumulatedDataSegmentForwardReferences = new DataSegmentForwardReferences();
- Globals.symbolTable.clear();
- Globals.memory.clear();
- this.machineList = new ArrayList();
- this.errors = new ErrorList();
- if (Globals.debug)
+ externAddress = Memory.externBaseAddress;
+ currentFileDataSegmentForwardReferences = new DataSegmentForwardReferences();
+ accumulatedDataSegmentForwardReferences = new DataSegmentForwardReferences();
+ Globals.symbolTable.clear();
+ Globals.memory.clear();
+ this.machineList = new ArrayList();
+ this.errors = new ErrorList();
+ if (Globals.debug)
+ {
System.out.println("Assembler first pass begins:");
- // PROCESS THE FIRST ASSEMBLY PASS FOR ALL SOURCE FILES BEFORE PROCEEDING
- // TO SECOND PASS. THIS ASSURES ALL SYMBOL TABLES ARE CORRECTLY BUILT.
- // THERE IS ONE GLOBAL SYMBOL TABLE (for identifiers declared .globl) PLUS
- // ONE LOCAL SYMBOL TABLE FOR EACH SOURCE FILE.
- for (int fileIndex = 0; fileIndex < tokenizedProgramFiles.size(); fileIndex++) {
+ }
+ // PROCESS THE FIRST ASSEMBLY PASS FOR ALL SOURCE FILES BEFORE PROCEEDING
+ // TO SECOND PASS. THIS ASSURES ALL SYMBOL TABLES ARE CORRECTLY BUILT.
+ // THERE IS ONE GLOBAL SYMBOL TABLE (for identifiers declared .globl) PLUS
+ // ONE LOCAL SYMBOL TABLE FOR EACH SOURCE FILE.
+ for (int fileIndex = 0; fileIndex < tokenizedProgramFiles.size(); fileIndex++)
+ {
if (errors.errorLimitExceeded())
- break;
- this.fileCurrentlyBeingAssembled = (MIPSprogram) tokenizedProgramFiles.get(fileIndex);
- // List of labels declared ".globl". new list for each file assembled
+ {
+ break;
+ }
+ this.fileCurrentlyBeingAssembled = (MIPSprogram) tokenizedProgramFiles.get(fileIndex);
+ // List of labels declared ".globl". new list for each file assembled
this.globalDeclarationList = new TokenList();
- // Parser begins by default in text segment until directed otherwise.
+ // Parser begins by default in text segment until directed otherwise.
this.inDataSegment = false;
- // Macro segment will be started by .macro directive
+ // Macro segment will be started by .macro directive
this.inMacroSegment = false;
- // Default is to align data from directives on appropriate boundary (word, half, byte)
- // This can be turned off for remainder of current data segment with ".align 0"
+ // Default is to align data from directives on appropriate boundary (word, half, byte)
+ // This can be turned off for remainder of current data segment with ".align 0"
this.autoAlign = true;
- // Default data directive is .word for 4 byte data items
+ // Default data directive is .word for 4 byte data items
this.dataDirective = Directives.WORD;
- // Clear out (initialize) symbol table related structures.
+ // Clear out (initialize) symbol table related structures.
fileCurrentlyBeingAssembled.getLocalSymbolTable().clear();
currentFileDataSegmentForwardReferences.clear();
- // sourceList is an ArrayList of String objects, one per source line.
- // tokenList is an ArrayList of TokenList objects, one per source line;
- // each ArrayList in tokenList consists of Token objects.
+ // sourceList is an ArrayList of String objects, one per source line.
+ // tokenList is an ArrayList of TokenList objects, one per source line;
+ // each ArrayList in tokenList consists of Token objects.
ArrayList sourceLineList = fileCurrentlyBeingAssembled.getSourceLineList();
ArrayList tokenList = fileCurrentlyBeingAssembled.getTokenList();
ArrayList parsedList = fileCurrentlyBeingAssembled.createParsedList();
- // each file keeps its own macro definitions
+ // each file keeps its own macro definitions
MacroPool macroPool = fileCurrentlyBeingAssembled.createMacroPool();
- // FIRST PASS OF ASSEMBLER VERIFIES SYNTAX, GENERATES SYMBOL TABLE,
- // INITIALIZES DATA SEGMENT
+ // FIRST PASS OF ASSEMBLER VERIFIES SYNTAX, GENERATES SYMBOL TABLE,
+ // INITIALIZES DATA SEGMENT
ArrayList statements;
- for (int i = 0; i < tokenList.size(); i++) {
- if (errors.errorLimitExceeded())
- break;
- for (int z=0; z<((TokenList)tokenList.get(i)).size(); z++) {
- Token t = ((TokenList) tokenList.get(i)).get(z);
- // record this token's original source program and line #. Differs from final, if .include used
- t.setOriginal(sourceLineList.get(i).getMIPSprogram(),sourceLineList.get(i).getLineNumber());
- }
- statements = this.parseLine((TokenList) tokenList.get(i),
- sourceLineList.get(i).getSource(),
- sourceLineList.get(i).getLineNumber(),
- extendedAssemblerEnabled);
- if (statements != null) {
- parsedList.addAll(statements);
- }
+ for (int i = 0; i < tokenList.size(); i++)
+ {
+ if (errors.errorLimitExceeded())
+ {
+ break;
+ }
+ for (int z = 0; z < ((TokenList) tokenList.get(i)).size(); z++)
+ {
+ Token t = ((TokenList) tokenList.get(i)).get(z);
+ // record this token's original source program and line #. Differs from final, if .include used
+ t.setOriginal(sourceLineList.get(i).getMIPSprogram(), sourceLineList.get(i).getLineNumber());
+ }
+ statements = this.parseLine((TokenList) tokenList.get(i),
+ sourceLineList.get(i).getSource(),
+ sourceLineList.get(i).getLineNumber(),
+ extendedAssemblerEnabled);
+ if (statements != null)
+ {
+ parsedList.addAll(statements);
+ }
}
- if (inMacroSegment) {
- errors.add(new ErrorMessage(fileCurrentlyBeingAssembled,
- fileCurrentlyBeingAssembled.getLocalMacroPool().getCurrent().getFromLine(),
- 0, "Macro started but not ended (no .end_macro directive)"));
+ if (inMacroSegment)
+ {
+ errors.add(new ErrorMessage(fileCurrentlyBeingAssembled,
+ fileCurrentlyBeingAssembled.getLocalMacroPool().getCurrent().getFromLine(),
+ 0, "Macro started but not ended (no .end_macro directive)"));
}
- // move ".globl" symbols from local symtab to global
+ // move ".globl" symbols from local symtab to global
this.transferGlobals();
- // Attempt to resolve forward label references that were discovered in operand fields
- // of data segment directives in current file. Those that are not resolved after this
- // call are either references to global labels not seen yet, or are undefined.
- // Cannot determine which until all files are parsed, so copy unresolved entries
- // into accumulated list and clear out this one for re-use with the next source file.
+ // Attempt to resolve forward label references that were discovered in operand fields
+ // of data segment directives in current file. Those that are not resolved after this
+ // call are either references to global labels not seen yet, or are undefined.
+ // Cannot determine which until all files are parsed, so copy unresolved entries
+ // into accumulated list and clear out this one for re-use with the next source file.
currentFileDataSegmentForwardReferences.resolve(fileCurrentlyBeingAssembled
- .getLocalSymbolTable());
+ .getLocalSymbolTable());
accumulatedDataSegmentForwardReferences.add(currentFileDataSegmentForwardReferences);
currentFileDataSegmentForwardReferences.clear();
- } // end of first-pass loop for each MIPSprogram
-
-
-
- // Have processed all source files. Attempt to resolve any remaining forward label
- // references from global symbol table. Those that remain unresolved are undefined
- // and require error message.
- accumulatedDataSegmentForwardReferences.resolve(Globals.symbolTable);
- accumulatedDataSegmentForwardReferences.generateErrorMessages(errors);
-
- // Throw collection of errors accumulated through the first pass.
- if (errors.errorsOccurred()) {
+ } // end of first-pass loop for each MIPSprogram
+
+
+ // Have processed all source files. Attempt to resolve any remaining forward label
+ // references from global symbol table. Those that remain unresolved are undefined
+ // and require error message.
+ accumulatedDataSegmentForwardReferences.resolve(Globals.symbolTable);
+ accumulatedDataSegmentForwardReferences.generateErrorMessages(errors);
+
+ // Throw collection of errors accumulated through the first pass.
+ if (errors.errorsOccurred())
+ {
throw new ProcessingException(errors);
- }
- if (Globals.debug)
+ }
+ if (Globals.debug)
+ {
System.out.println("Assembler second pass begins");
- // SECOND PASS OF ASSEMBLER GENERATES BASIC ASSEMBLER THEN MACHINE CODE.
- // Generates basic assembler statements...
- for (int fileIndex = 0; fileIndex < tokenizedProgramFiles.size(); fileIndex++) {
+ }
+ // SECOND PASS OF ASSEMBLER GENERATES BASIC ASSEMBLER THEN MACHINE CODE.
+ // Generates basic assembler statements...
+ for (int fileIndex = 0; fileIndex < tokenizedProgramFiles.size(); fileIndex++)
+ {
if (errors.errorLimitExceeded())
- break;
+ {
+ break;
+ }
this.fileCurrentlyBeingAssembled = (MIPSprogram) tokenizedProgramFiles.get(fileIndex);
ArrayList parsedList = fileCurrentlyBeingAssembled.getParsedList();
ProgramStatement statement;
- for (int i = 0; i < parsedList.size(); i++) {
- statement = (ProgramStatement) parsedList.get(i);
- statement.buildBasicStatementFromBasicInstruction(errors);
- if (errors.errorsOccurred()) {
- throw new ProcessingException(errors);
- }
- if (statement.getInstruction() instanceof BasicInstruction) {
- this.machineList.add(statement);
- }
- else {
- // It is a pseudo-instruction:
- // 1. Fetch its basic instruction template list
- // 2. For each template in the list,
- // 2a. substitute operands from source statement
- // 2b. tokenize the statement generated by 2a.
- // 2d. call parseLine() to generate basic instrction
- // 2e. add returned programStatement to the list
- // The templates, and the instructions generated by filling
- // in the templates, are specified
- // in basic format (e.g. mnemonic register reference $zero
- // already translated to $0).
- // So the values substituted into the templates need to be
- // in this format. Since those
- // values come from the original source statement, they need
- // to be translated before
- // substituting. The next method call will perform this
- // translation on the original
- // source statement. Despite the fact that the original
- // statement is a pseudo
- // instruction, this method performs the necessary
- // translation correctly.
- ExtendedInstruction inst = (ExtendedInstruction) statement.getInstruction();
- String basicAssembly = statement.getBasicAssemblyStatement();
- int sourceLine = statement.getSourceLine();
- TokenList theTokenList = new Tokenizer().tokenizeLine(sourceLine,
- basicAssembly, errors, false);
-
- // ////////////////////////////////////////////////////////////////////////////
- // If we are using compact memory config and there is a compact expansion, use it
- ArrayList templateList;
- if (compactTranslationCanBeApplied(statement)) {
- templateList = inst.getCompactBasicIntructionTemplateList();
- }
- else {
- templateList = inst.getBasicIntructionTemplateList();
- }
-
- // subsequent ProgramStatement constructor needs the correct text segment address.
- textAddress.set(statement.getAddress());
- // Will generate one basic instruction for each template in the list.
- for (int instrNumber = 0; instrNumber < templateList.size(); instrNumber++) {
- String instruction = ExtendedInstruction.makeTemplateSubstitutions(
- this.fileCurrentlyBeingAssembled,
- (String) templateList.get(instrNumber), theTokenList);
- // 23 Jan 2008 by DPS. Template substitution may result in no instruction.
- // If this is the case, skip remainder of loop iteration. This should only
- // happen if template substitution was for "nop" instruction but delayed branching
- // is disabled so the "nop" is not generated.
- if (instruction == null || instruction == "") {
- continue;
- }
-
- // All substitutions have been made so we have generated
- // a valid basic instruction!
- if (Globals.debug)
- System.out.println("PSEUDO generated: " + instruction);
- // For generated instruction: tokenize, build program
- // statement, add to list.
- TokenList newTokenList = new Tokenizer().tokenizeLine(sourceLine,
- instruction, errors,false);
- ArrayList instrMatches = this.matchInstruction(newTokenList.get(0));
- Instruction instr = OperandFormat.bestOperandMatch(newTokenList,
- instrMatches);
- // Only first generated instruction is linked to original source
- ProgramStatement ps = new ProgramStatement(
- this.fileCurrentlyBeingAssembled,
- (instrNumber == 0) ? statement.getSource() : "", newTokenList,
- newTokenList, instr, textAddress.get(), statement.getSourceLine());
- textAddress.increment(Instruction.INSTRUCTION_LENGTH);
- ps.buildBasicStatementFromBasicInstruction(errors);
- this.machineList.add(ps);
- } // end of FOR loop, repeated for each template in list.
- } // end of ELSE part for extended instruction.
-
+ for (int i = 0; i < parsedList.size(); i++)
+ {
+ statement = (ProgramStatement) parsedList.get(i);
+ statement.buildBasicStatementFromBasicInstruction(errors);
+ if (errors.errorsOccurred())
+ {
+ throw new ProcessingException(errors);
+ }
+ if (statement.getInstruction() instanceof BasicInstruction)
+ {
+ this.machineList.add(statement);
+ }
+ else
+ {
+ // It is a pseudo-instruction:
+ // 1. Fetch its basic instruction template list
+ // 2. For each template in the list,
+ // 2a. substitute operands from source statement
+ // 2b. tokenize the statement generated by 2a.
+ // 2d. call parseLine() to generate basic instrction
+ // 2e. add returned programStatement to the list
+ // The templates, and the instructions generated by filling
+ // in the templates, are specified
+ // in basic format (e.g. mnemonic register reference $zero
+ // already translated to $0).
+ // So the values substituted into the templates need to be
+ // in this format. Since those
+ // values come from the original source statement, they need
+ // to be translated before
+ // substituting. The next method call will perform this
+ // translation on the original
+ // source statement. Despite the fact that the original
+ // statement is a pseudo
+ // instruction, this method performs the necessary
+ // translation correctly.
+ ExtendedInstruction inst = (ExtendedInstruction) statement.getInstruction();
+ String basicAssembly = statement.getBasicAssemblyStatement();
+ int sourceLine = statement.getSourceLine();
+ TokenList theTokenList = new Tokenizer().tokenizeLine(sourceLine,
+ basicAssembly, errors, false);
+
+ // ////////////////////////////////////////////////////////////////////////////
+ // If we are using compact memory config and there is a compact expansion, use it
+ ArrayList templateList;
+ if (compactTranslationCanBeApplied(statement))
+ {
+ templateList = inst.getCompactBasicIntructionTemplateList();
+ }
+ else
+ {
+ templateList = inst.getBasicIntructionTemplateList();
+ }
+
+ // subsequent ProgramStatement constructor needs the correct text segment address.
+ textAddress.set(statement.getAddress());
+ // Will generate one basic instruction for each template in the list.
+ for (int instrNumber = 0; instrNumber < templateList.size(); instrNumber++)
+ {
+ String instruction = ExtendedInstruction.makeTemplateSubstitutions(
+ this.fileCurrentlyBeingAssembled,
+ (String) templateList.get(instrNumber), theTokenList);
+ // 23 Jan 2008 by DPS. Template substitution may result in no instruction.
+ // If this is the case, skip remainder of loop iteration. This should only
+ // happen if template substitution was for "nop" instruction but delayed branching
+ // is disabled so the "nop" is not generated.
+ if (instruction == null || instruction == "")
+ {
+ continue;
+ }
+
+ // All substitutions have been made so we have generated
+ // a valid basic instruction!
+ if (Globals.debug)
+ {
+ System.out.println("PSEUDO generated: " + instruction);
+ }
+ // For generated instruction: tokenize, build program
+ // statement, add to list.
+ TokenList newTokenList = new Tokenizer().tokenizeLine(sourceLine,
+ instruction, errors, false);
+ ArrayList instrMatches = this.matchInstruction(newTokenList.get(0));
+ Instruction instr = OperandFormat.bestOperandMatch(newTokenList,
+ instrMatches);
+ // Only first generated instruction is linked to original source
+ ProgramStatement ps = new ProgramStatement(
+ this.fileCurrentlyBeingAssembled,
+ (instrNumber == 0) ? statement.getSource() : "", newTokenList,
+ newTokenList, instr, textAddress.get(), statement.getSourceLine());
+ textAddress.increment(Instruction.INSTRUCTION_LENGTH);
+ ps.buildBasicStatementFromBasicInstruction(errors);
+ this.machineList.add(ps);
+ } // end of FOR loop, repeated for each template in list.
+ } // end of ELSE part for extended instruction.
+
} // end of assembler second pass.
- }
- if (Globals.debug)
+ }
+ if (Globals.debug)
+ {
System.out.println("Code generation begins");
- ///////////// THIRD MAJOR STEP IS PRODUCE MACHINE CODE FROM ASSEMBLY //////////
- // Generates machine code statements from the list of basic assembler statements
- // and writes the statement to memory.
- ProgramStatement statement;
- for (int i = 0; i < this.machineList.size(); i++) {
+ }
+ ///////////// THIRD MAJOR STEP IS PRODUCE MACHINE CODE FROM ASSEMBLY //////////
+ // Generates machine code statements from the list of basic assembler statements
+ // and writes the statement to memory.
+ ProgramStatement statement;
+ for (int i = 0; i < this.machineList.size(); i++)
+ {
if (errors.errorLimitExceeded())
- break;
+ {
+ break;
+ }
statement = (ProgramStatement) this.machineList.get(i);
statement.buildMachineStatementFromBasicStatement(errors);
if (Globals.debug)
- System.out.println(statement);
- try {
- Globals.memory.setStatement(statement.getAddress(), statement);
- }
- catch (AddressErrorException e) {
- Token t = statement.getOriginalTokenList().get(0);
- errors.add(new ErrorMessage(t.getSourceMIPSprogram(), t.getSourceLine(), t
- .getStartPos(), "Invalid address for text segment: " + e.getAddress()));
- }
- }
- // Aug. 24, 2005 Ken Vollmar
- // Ensure that I/O "file descriptors" are initialized for a new program run
- SystemIO.resetFiles();
- // DPS 6 Dec 2006:
- // We will now sort the ArrayList of ProgramStatements by getAddress() value.
- // This is for display purposes, since they have already been stored to Memory.
- // Use of .ktext and .text with address operands has two implications:
- // (1) the addresses may not be ordered at this point. Requires unsigned int
- // sort because kernel addresses are negative. See special Comparator.
- // (2) It is possible for two instructions to be placed at the same address.
- // Such occurances will be flagged as errors.
- // Yes, I would not have to sort here if I used SortedSet rather than ArrayList
- // but in case of duplicate I like having both statements handy for error message.
- Collections.sort(this.machineList, new ProgramStatementComparator());
- catchDuplicateAddresses(this.machineList, errors);
- if (errors.errorsOccurred() || errors.warningsOccurred() && warningsAreErrors) {
+ {
+ System.out.println(statement);
+ }
+ try
+ {
+ Globals.memory.setStatement(statement.getAddress(), statement);
+ }
+ catch (AddressErrorException e)
+ {
+ Token t = statement.getOriginalTokenList().get(0);
+ errors.add(new ErrorMessage(t.getSourceMIPSprogram(), t.getSourceLine(), t
+ .getStartPos(), "Invalid address for text segment: " + e.getAddress()));
+ }
+ }
+ // Aug. 24, 2005 Ken Vollmar
+ // Ensure that I/O "file descriptors" are initialized for a new program run
+ SystemIO.resetFiles();
+ // DPS 6 Dec 2006:
+ // We will now sort the ArrayList of ProgramStatements by getAddress() value.
+ // This is for display purposes, since they have already been stored to Memory.
+ // Use of .ktext and .text with address operands has two implications:
+ // (1) the addresses may not be ordered at this point. Requires unsigned int
+ // sort because kernel addresses are negative. See special Comparator.
+ // (2) It is possible for two instructions to be placed at the same address.
+ // Such occurances will be flagged as errors.
+ // Yes, I would not have to sort here if I used SortedSet rather than ArrayList
+ // but in case of duplicate I like having both statements handy for error message.
+ Collections.sort(this.machineList, new ProgramStatementComparator());
+ catchDuplicateAddresses(this.machineList, errors);
+ if (errors.errorsOccurred() || errors.warningsOccurred() && warningsAreErrors)
+ {
throw new ProcessingException(errors);
- }
- return this.machineList;
- } // assemble()
-
- // //////////////////////////////////////////////////////////////////////
- // Will check for duplicate text addresses, which can happen inadvertantly when using
- // operand on .text directive. Will generate error message for each one that occurs.
- private void catchDuplicateAddresses(ArrayList instructions, ErrorList errors) {
- for (int i = 0; i < instructions.size() - 1; i++) {
+ }
+ return this.machineList;
+ } // assemble()
+
+ // //////////////////////////////////////////////////////////////////////
+ // Will check for duplicate text addresses, which can happen inadvertantly when using
+ // operand on .text directive. Will generate error message for each one that occurs.
+ private void catchDuplicateAddresses(ArrayList instructions, ErrorList errors)
+ {
+ for (int i = 0; i < instructions.size() - 1; i++)
+ {
ProgramStatement ps1 = (ProgramStatement) instructions.get(i);
ProgramStatement ps2 = (ProgramStatement) instructions.get(i + 1);
- if (ps1.getAddress() == ps2.getAddress()) {
- errors.add(new ErrorMessage(ps2.getSourceMIPSprogram(), ps2.getSourceLine(), 0,
- "Duplicate text segment address: "
- + mars.venus.NumberDisplayBaseChooser.formatUnsignedInteger(ps2
- .getAddress(), (Globals.getSettings()
- .getDisplayAddressesInHex()) ? 16 : 10)
- + " already occupied by " + ps1.getSourceFile() + " line "
- + ps1.getSourceLine() + " (caused by use of "
- + ((Memory.inTextSegment(ps2.getAddress())) ? ".text" : ".ktext")
- + " operand)"));
+ if (ps1.getAddress() == ps2.getAddress())
+ {
+ errors.add(new ErrorMessage(ps2.getSourceMIPSprogram(), ps2.getSourceLine(), 0,
+ "Duplicate text segment address: "
+ + mars.venus.NumberDisplayBaseChooser.formatUnsignedInteger(ps2
+ .getAddress(), (Globals.getSettings()
+ .getDisplayAddressesInHex()) ? 16 : 10)
+ + " already occupied by " + ps1.getSourceFile() + " line "
+ + ps1.getSourceLine() + " (caused by use of "
+ + ((Memory.inTextSegment(ps2.getAddress())) ? ".text" : ".ktext")
+ + " operand)"));
}
- }
- }
-
- /**
- * This method parses one line of MIPS source code. It works with the list
- * of tokens, but original source is also provided. It also carries out
- * directives, which includes initializing the data segment. This method is
- * invoked in the assembler first pass.
- *
- * @param tokenList
- * @param source
- * @param sourceLineNumber
- * @param extendedAssemblerEnabled
- * @return ArrayList of ProgramStatements because parsing a macro expansion
- * request will return a list of ProgramStatements expanded
- */
- private ArrayList parseLine(TokenList tokenList, String source,
- int sourceLineNumber, boolean extendedAssemblerEnabled) {
-
- ArrayList ret = new ArrayList();
-
- ProgramStatement programStatement;
- TokenList tokens = this.stripComment(tokenList);
-
- // Labels should not be processed in macro definition segment.
- MacroPool macroPool = fileCurrentlyBeingAssembled.getLocalMacroPool();
- if (inMacroSegment) {
+ }
+ }
+
+ /**
+ * This method parses one line of MIPS source code. It works with the list of tokens, but original source is also
+ * provided. It also carries out directives, which includes initializing the data segment. This method is invoked in
+ * the assembler first pass.
+ *
+ * @param tokenList
+ * @param source
+ * @param sourceLineNumber
+ * @param extendedAssemblerEnabled
+ * @return ArrayList of ProgramStatements because parsing a macro expansion request will return a list of
+ * ProgramStatements expanded
+ */
+ private ArrayList parseLine(TokenList tokenList, String source,
+ int sourceLineNumber, boolean extendedAssemblerEnabled)
+ {
+
+ ArrayList ret = new ArrayList();
+
+ ProgramStatement programStatement;
+ TokenList tokens = this.stripComment(tokenList);
+
+ // Labels should not be processed in macro definition segment.
+ MacroPool macroPool = fileCurrentlyBeingAssembled.getLocalMacroPool();
+ if (inMacroSegment)
+ {
detectLabels(tokens, macroPool.getCurrent());
- }
- else {
+ }
+ else
+ {
stripLabels(tokens);
- }
- if (tokens.isEmpty())
+ }
+ if (tokens.isEmpty())
+ {
return null;
- // Grab first (operator) token...
- Token token = tokens.get(0);
- TokenTypes tokenType = token.getType();
-
- // Let's handle the directives here...
- if (tokenType == TokenTypes.DIRECTIVE) {
+ }
+ // Grab first (operator) token...
+ Token token = tokens.get(0);
+ TokenTypes tokenType = token.getType();
+
+ // Let's handle the directives here...
+ if (tokenType == TokenTypes.DIRECTIVE)
+ {
this.executeDirective(tokens);
return null;
- }
-
- // don't parse if in macro segment
- if (inMacroSegment)
+ }
+
+ // don't parse if in macro segment
+ if (inMacroSegment)
+ {
return null;
-
- // SPIM-style macro calling:
- TokenList parenFreeTokens = tokens;
- if (tokens.size() > 2 && tokens.get(1).getType() == TokenTypes.LEFT_PAREN
- && tokens.get(tokens.size() - 1).getType() == TokenTypes.RIGHT_PAREN) {
+ }
+
+ // SPIM-style macro calling:
+ TokenList parenFreeTokens = tokens;
+ if (tokens.size() > 2 && tokens.get(1).getType() == TokenTypes.LEFT_PAREN
+ && tokens.get(tokens.size() - 1).getType() == TokenTypes.RIGHT_PAREN)
+ {
parenFreeTokens = (TokenList) tokens.clone();
parenFreeTokens.remove(tokens.size() - 1);
parenFreeTokens.remove(1);
- }
- Macro macro = macroPool.getMatchingMacro(parenFreeTokens, sourceLineNumber);//parenFreeTokens.get(0).getSourceLine());
-
- // expand macro if this line is a macro expansion call
- if (macro != null) {
+ }
+ Macro macro = macroPool.getMatchingMacro(parenFreeTokens, sourceLineNumber);//parenFreeTokens.get(0).getSourceLine());
+
+ // expand macro if this line is a macro expansion call
+ if (macro != null)
+ {
tokens = parenFreeTokens;
- // get unique id for this expansion
+ // get unique id for this expansion
int counter = macroPool.getNextCounter();
- if (macroPool.pushOnCallStack(token)) {
- errors.add(new ErrorMessage(fileCurrentlyBeingAssembled, tokens.get(0)
- .getSourceLine(), 0, "Detected a macro expansion loop (recursive reference). "));
- }
- else {
- // for (int i = macro.getFromLine() + 1; i < macro.getToLine(); i++) {
- // String substituted = macro.getSubstitutedLine(i, tokens, counter, errors);
- // TokenList tokenList2 = fileCurrentlyBeingAssembled.getTokenizer().tokenizeLine(
- // i, substituted, errors);
- // // If token list getProcessedLine() is not empty, then .eqv was performed and it contains the modified source.
- // // Put it into the line to be parsed, so it will be displayed properly in text segment display. DPS 23 Jan 2013
- // if (tokenList2.getProcessedLine().length() > 0)
- // substituted = tokenList2.getProcessedLine();
- // // recursively parse lines of expanded macro
- // ArrayList statements = parseLine(tokenList2, "<" + (i-macro.getFromLine()+macro.getOriginalFromLine()) + "> "
- // + substituted.trim(), sourceLineNumber, extendedAssemblerEnabled);
- // if (statements != null)
- // ret.addAll(statements);
- // }
- for (int i = macro.getFromLine() + 1; i < macro.getToLine(); i++) {
-
- String substituted = macro.getSubstitutedLine(i, tokens, counter, errors);
- TokenList tokenList2 = fileCurrentlyBeingAssembled.getTokenizer().tokenizeLine(
- i, substituted, errors);
-
- // If token list getProcessedLine() is not empty, then .eqv was performed and it contains the modified source.
- // Put it into the line to be parsed, so it will be displayed properly in text segment display. DPS 23 Jan 2013
- if (tokenList2.getProcessedLine().length() > 0)
- substituted = tokenList2.getProcessedLine();
-
- // recursively parse lines of expanded macro
- ArrayList statements = parseLine(tokenList2, "<" + (i-macro.getFromLine()+macro.getOriginalFromLine()) + "> "
- + substituted.trim(), sourceLineNumber, extendedAssemblerEnabled);
- if (statements != null)
- ret.addAll(statements);
- }
- macroPool.popFromCallStack();
+ if (macroPool.pushOnCallStack(token))
+ {
+ errors.add(new ErrorMessage(fileCurrentlyBeingAssembled, tokens.get(0)
+ .getSourceLine(), 0, "Detected a macro expansion loop (recursive reference). "));
+ }
+ else
+ {
+ // for (int i = macro.getFromLine() + 1; i < macro.getToLine(); i++) {
+ // String substituted = macro.getSubstitutedLine(i, tokens, counter, errors);
+ // TokenList tokenList2 = fileCurrentlyBeingAssembled.getTokenizer().tokenizeLine(
+ // i, substituted, errors);
+ // // If token list getProcessedLine() is not empty, then .eqv was performed and it contains the modified source.
+ // // Put it into the line to be parsed, so it will be displayed properly in text segment display. DPS 23 Jan 2013
+ // if (tokenList2.getProcessedLine().length() > 0)
+ // substituted = tokenList2.getProcessedLine();
+ // // recursively parse lines of expanded macro
+ // ArrayList statements = parseLine(tokenList2, "<" + (i-macro.getFromLine()+macro.getOriginalFromLine()) + "> "
+ // + substituted.trim(), sourceLineNumber, extendedAssemblerEnabled);
+ // if (statements != null)
+ // ret.addAll(statements);
+ // }
+ for (int i = macro.getFromLine() + 1; i < macro.getToLine(); i++)
+ {
+
+ String substituted = macro.getSubstitutedLine(i, tokens, counter, errors);
+ TokenList tokenList2 = fileCurrentlyBeingAssembled.getTokenizer().tokenizeLine(
+ i, substituted, errors);
+
+ // If token list getProcessedLine() is not empty, then .eqv was performed and it contains the modified source.
+ // Put it into the line to be parsed, so it will be displayed properly in text segment display. DPS 23 Jan 2013
+ if (tokenList2.getProcessedLine().length() > 0)
+ {
+ substituted = tokenList2.getProcessedLine();
+ }
+
+ // recursively parse lines of expanded macro
+ ArrayList statements = parseLine(tokenList2, "<" + (i - macro.getFromLine() + macro.getOriginalFromLine()) + "> "
+ + substituted.trim(), sourceLineNumber, extendedAssemblerEnabled);
+ if (statements != null)
+ {
+ ret.addAll(statements);
+ }
+ }
+ macroPool.popFromCallStack();
}
return ret;
- }
-
- // DPS 14-July-2008
- // Yet Another Hack: detect unrecognized directive. MARS recognizes the same directives
- // as SPIM but other MIPS assemblers recognize additional directives. Compilers such
- // as MIPS-directed GCC generate assembly code containing these directives. We'd like
- // the opportunity to ignore them and continue. Tokenizer would categorize an unrecognized
- // directive as an TokenTypes.IDENTIFIER because it would not be matched as a directive and
- // MIPS labels can start with '.' NOTE: this can also be handled by including the
- // ignored directive in the Directives.java list. There is already a mechanism in place
- // for generating a warning there. But I cannot anticipate the names of all directives
- // so this will catch anything, including a misspelling of a valid directive (which is
- // a nice thing to do).
- if (tokenType == TokenTypes.IDENTIFIER && token.getValue().charAt(0) == '.') {
+ }
+
+ // DPS 14-July-2008
+ // Yet Another Hack: detect unrecognized directive. MARS recognizes the same directives
+ // as SPIM but other MIPS assemblers recognize additional directives. Compilers such
+ // as MIPS-directed GCC generate assembly code containing these directives. We'd like
+ // the opportunity to ignore them and continue. Tokenizer would categorize an unrecognized
+ // directive as an TokenTypes.IDENTIFIER because it would not be matched as a directive and
+ // MIPS labels can start with '.' NOTE: this can also be handled by including the
+ // ignored directive in the Directives.java list. There is already a mechanism in place
+ // for generating a warning there. But I cannot anticipate the names of all directives
+ // so this will catch anything, including a misspelling of a valid directive (which is
+ // a nice thing to do).
+ if (tokenType == TokenTypes.IDENTIFIER && token.getValue().charAt(0) == '.')
+ {
errors.add(new ErrorMessage(ErrorMessage.WARNING, token.getSourceMIPSprogram(), token
- .getSourceLine(), token.getStartPos(), "MARS does not recognize the "
- + token.getValue() + " directive. Ignored."));
+ .getSourceLine(), token.getStartPos(), "MARS does not recognize the "
+ + token.getValue() + " directive. Ignored."));
return null;
- }
-
- // The directives with lists (.byte, .double, .float, .half, .word, .ascii, .asciiz)
- // should be able to extend the list over several lines. Since this method assembles
- // only one source line, state information must be stored from one invocation to
- // the next, to sense the context of this continuation line. That state information
- // is contained in this.dataDirective (the current data directive).
- //
- if (this.inDataSegment && // 30-Dec-09 DPS Added data segment guard...
- (tokenType == TokenTypes.PLUS
- || // because invalid instructions were being caught...
- tokenType == TokenTypes.MINUS
- || // here and reported as a directive in text segment!
- tokenType == TokenTypes.QUOTED_STRING || tokenType == TokenTypes.IDENTIFIER
- || TokenTypes.isIntegerTokenType(tokenType) || TokenTypes
- .isFloatingTokenType(tokenType))) {
+ }
+
+ // The directives with lists (.byte, .double, .float, .half, .word, .ascii, .asciiz)
+ // should be able to extend the list over several lines. Since this method assembles
+ // only one source line, state information must be stored from one invocation to
+ // the next, to sense the context of this continuation line. That state information
+ // is contained in this.dataDirective (the current data directive).
+ //
+ if (this.inDataSegment && // 30-Dec-09 DPS Added data segment guard...
+ (tokenType == TokenTypes.PLUS
+ || // because invalid instructions were being caught...
+ tokenType == TokenTypes.MINUS
+ || // here and reported as a directive in text segment!
+ tokenType == TokenTypes.QUOTED_STRING || tokenType == TokenTypes.IDENTIFIER
+ || TokenTypes.isIntegerTokenType(tokenType) || TokenTypes
+ .isFloatingTokenType(tokenType)))
+ {
this.executeDirectiveContinuation(tokens);
return null;
- }
-
- // If we are in the text segment, the variable "token" must now refer to
- // an OPERATOR
- // token. If not, it is either a syntax error or the specified operator
- // is not
- // yet implemented.
- if (!this.inDataSegment) {
+ }
+
+ // If we are in the text segment, the variable "token" must now refer to
+ // an OPERATOR
+ // token. If not, it is either a syntax error or the specified operator
+ // is not
+ // yet implemented.
+ if (!this.inDataSegment)
+ {
ArrayList instrMatches = this.matchInstruction(token);
if (instrMatches == null)
- return ret;
- // OK, we've got an operator match, let's check the operands.
+ {
+ return ret;
+ }
+ // OK, we've got an operator match, let's check the operands.
Instruction inst = OperandFormat.bestOperandMatch(tokens, instrMatches);
- // Here's the place to flag use of extended (pseudo) instructions
- // when setting disabled.
- if (inst instanceof ExtendedInstruction && !extendedAssemblerEnabled) {
- errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token.getSourceLine(),
- token.getStartPos(),
- "Extended (pseudo) instruction or format not permitted. See Settings."));
+ // Here's the place to flag use of extended (pseudo) instructions
+ // when setting disabled.
+ if (inst instanceof ExtendedInstruction && !extendedAssemblerEnabled)
+ {
+ errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token.getSourceLine(),
+ token.getStartPos(),
+ "Extended (pseudo) instruction or format not permitted. See Settings."));
}
- if (OperandFormat.tokenOperandMatch(tokens, inst, errors)) {
- programStatement = new ProgramStatement(this.fileCurrentlyBeingAssembled, source,
- tokenList, tokens, inst, textAddress.get(), sourceLineNumber);
- // instruction length is 4 for all basic instruction, varies for extended instruction
- // Modified to permit use of compact expansion if address fits
- // in 15 bits. DPS 4-Aug-2009
- int instLength = inst.getInstructionLength();
- if (compactTranslationCanBeApplied(programStatement)) {
- instLength = ((ExtendedInstruction) inst).getCompactInstructionLength();
- }
- textAddress.increment(instLength);
- ret.add(programStatement);
- return ret;
+ if (OperandFormat.tokenOperandMatch(tokens, inst, errors))
+ {
+ programStatement = new ProgramStatement(this.fileCurrentlyBeingAssembled, source,
+ tokenList, tokens, inst, textAddress.get(), sourceLineNumber);
+ // instruction length is 4 for all basic instruction, varies for extended instruction
+ // Modified to permit use of compact expansion if address fits
+ // in 15 bits. DPS 4-Aug-2009
+ int instLength = inst.getInstructionLength();
+ if (compactTranslationCanBeApplied(programStatement))
+ {
+ instLength = ((ExtendedInstruction) inst).getCompactInstructionLength();
+ }
+ textAddress.increment(instLength);
+ ret.add(programStatement);
+ return ret;
}
- }
- return null;
- } // parseLine()
-
- private void detectLabels(TokenList tokens, Macro current) {
- if (tokenListBeginsWithLabel(tokens))
+ }
+ return null;
+ } // parseLine()
+
+ private void detectLabels(TokenList tokens, Macro current)
+ {
+ if (tokenListBeginsWithLabel(tokens))
+ {
current.addLabel(tokens.get(0).getValue());
- }
-
- // Determine whether or not a compact (16-bit) translation from
- // pseudo-instruction to basic instruction can be applied. If
- // the argument is a basic instruction, obviously not. If an
- // extended instruction, we have to be operating under a 16-bit
- // memory model and the instruction has to have defined an
- // alternate compact translation.
- private boolean compactTranslationCanBeApplied(ProgramStatement statement) {
- return (statement.getInstruction() instanceof ExtendedInstruction
+ }
+ }
+
+ // Determine whether or not a compact (16-bit) translation from
+ // pseudo-instruction to basic instruction can be applied. If
+ // the argument is a basic instruction, obviously not. If an
+ // extended instruction, we have to be operating under a 16-bit
+ // memory model and the instruction has to have defined an
+ // alternate compact translation.
+ private boolean compactTranslationCanBeApplied(ProgramStatement statement)
+ {
+ return (statement.getInstruction() instanceof ExtendedInstruction
&& Globals.memory.usingCompactMemoryConfiguration() && ((ExtendedInstruction) statement
- .getInstruction()).hasCompactTranslation());
- }
-
- // //////////////////////////////////////////////////////////////////////////////////
- // Pre-process the token list for a statement by stripping off any comment.
- // NOTE: the ArrayList parameter is not modified; a new one is cloned and
- // returned.
- private TokenList stripComment(TokenList tokenList) {
- if (tokenList.isEmpty())
+ .getInstruction()).hasCompactTranslation());
+ }
+
+ // //////////////////////////////////////////////////////////////////////////////////
+ // Pre-process the token list for a statement by stripping off any comment.
+ // NOTE: the ArrayList parameter is not modified; a new one is cloned and
+ // returned.
+ private TokenList stripComment(TokenList tokenList)
+ {
+ if (tokenList.isEmpty())
+ {
return tokenList;
- TokenList tokens = (TokenList) tokenList.clone();
- // If there is a comment, strip it off.
- int last = tokens.size() - 1;
- if (tokens.get(last).getType() == TokenTypes.COMMENT) {
+ }
+ TokenList tokens = (TokenList) tokenList.clone();
+ // If there is a comment, strip it off.
+ int last = tokens.size() - 1;
+ if (tokens.get(last).getType() == TokenTypes.COMMENT)
+ {
tokens.remove(last);
- }
- return tokens;
- } // stripComment()
-
- /**
- * Pre-process the token list for a statement by stripping off any label, if
- * either are present. Any label definition will be recorded in the symbol
- * table. NOTE: the ArrayList parameter will be modified.
- */
- private void stripLabels(TokenList tokens) {
- // If there is a label, handle it here and strip it off.
- boolean thereWasLabel = this.parseAndRecordLabel(tokens);
- if (thereWasLabel) {
+ }
+ return tokens;
+ } // stripComment()
+
+ /**
+ * Pre-process the token list for a statement by stripping off any label, if either are present. Any label
+ * definition will be recorded in the symbol table. NOTE: the ArrayList parameter will be modified.
+ */
+ private void stripLabels(TokenList tokens)
+ {
+ // If there is a label, handle it here and strip it off.
+ boolean thereWasLabel = this.parseAndRecordLabel(tokens);
+ if (thereWasLabel)
+ {
tokens.remove(0); // Remove the IDENTIFIER.
tokens.remove(0); // Remove the COLON, shifted to 0 by previous remove
- }
- }
-
- // //////////////////////////////////////////////////////////////////////////////////
- // Parse and record label, if there is one. Note the identifier and its colon are
- // two separate tokens, since they may be separated by spaces in source code.
- private boolean parseAndRecordLabel(TokenList tokens) {
- if (tokens.size() < 2) {
+ }
+ }
+
+ // //////////////////////////////////////////////////////////////////////////////////
+ // Parse and record label, if there is one. Note the identifier and its colon are
+ // two separate tokens, since they may be separated by spaces in source code.
+ private boolean parseAndRecordLabel(TokenList tokens)
+ {
+ if (tokens.size() < 2)
+ {
return false;
- }
- else {
+ }
+ else
+ {
Token token = tokens.get(0);
- if (tokenListBeginsWithLabel(tokens)) {
- if (token.getType() == TokenTypes.OPERATOR) {
- // an instruction name was used as label (e.g. lw:), so change its token type
- token.setType(TokenTypes.IDENTIFIER);
- }
- fileCurrentlyBeingAssembled.getLocalSymbolTable().addSymbol(token,
- (this.inDataSegment) ? dataAddress.get() : textAddress.get(),
- this.inDataSegment, this.errors);
- return true;
- }
- else {
- return false;
+ if (tokenListBeginsWithLabel(tokens))
+ {
+ if (token.getType() == TokenTypes.OPERATOR)
+ {
+ // an instruction name was used as label (e.g. lw:), so change its token type
+ token.setType(TokenTypes.IDENTIFIER);
+ }
+ fileCurrentlyBeingAssembled.getLocalSymbolTable().addSymbol(token,
+ (this.inDataSegment) ? dataAddress.get() : textAddress.get(),
+ this.inDataSegment, this.errors);
+ return true;
}
- }
- } // parseLabel()
-
- private boolean tokenListBeginsWithLabel(TokenList tokens) {
- // 2-July-2010. DPS. Remove prohibition of operator names as labels
- if (tokens.size() < 2)
+ else
+ {
+ return false;
+ }
+ }
+ } // parseLabel()
+
+ private boolean tokenListBeginsWithLabel(TokenList tokens)
+ {
+ // 2-July-2010. DPS. Remove prohibition of operator names as labels
+ if (tokens.size() < 2)
+ {
return false;
- return (tokens.get(0).getType() == TokenTypes.IDENTIFIER || tokens.get(0).getType() == TokenTypes.OPERATOR)
+ }
+ return (tokens.get(0).getType() == TokenTypes.IDENTIFIER || tokens.get(0).getType() == TokenTypes.OPERATOR)
&& tokens.get(1).getType() == TokenTypes.COLON;
- }
-
- // //////////////////////////////////////////////////////////////////////////////////
- // This source code line is a directive, not a MIPS instruction. Let's carry it out.
- private void executeDirective(TokenList tokens) {
- Token token = tokens.get(0);
- Directives direct = Directives.matchDirective(token.getValue());
- if (Globals.debug)
+ }
+
+ // //////////////////////////////////////////////////////////////////////////////////
+ // This source code line is a directive, not a MIPS instruction. Let's carry it out.
+ private void executeDirective(TokenList tokens)
+ {
+ Token token = tokens.get(0);
+ Directives direct = Directives.matchDirective(token.getValue());
+ if (Globals.debug)
+ {
System.out.println("line " + token.getSourceLine() + " is directive " + direct);
- if (direct == null) {
+ }
+ if (direct == null)
+ {
errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token.getSourceLine(), token
- .getStartPos(), "\"" + token.getValue()
- + "\" directive is invalid or not implemented in MARS"));
- return;
- }
- else if (direct == Directives.EQV) { /* EQV added by DPS 11 July 2012 */
+ .getStartPos(), "\"" + token.getValue()
+ + "\" directive is invalid or not implemented in MARS"));
+ }
+ else if (direct == Directives.EQV)
+ { /* EQV added by DPS 11 July 2012 */
// Do nothing. This was vetted and processed during tokenizing.
- }
- else if (direct == Directives.MACRO) {
- if (tokens.size() < 2) {
- errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token.getSourceLine(),
- token.getStartPos(), "\"" + token.getValue()
- + "\" directive requires at least one argument."));
- return;
+ }
+ else if (direct == Directives.MACRO)
+ {
+ if (tokens.size() < 2)
+ {
+ errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token.getSourceLine(),
+ token.getStartPos(), "\"" + token.getValue()
+ + "\" directive requires at least one argument."));
+ return;
}
- if (tokens.get(1).getType() != TokenTypes.IDENTIFIER) {
- errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token.getSourceLine(),
- tokens.get(1).getStartPos(), "Invalid Macro name \""
- + tokens.get(1).getValue() + "\""));
- return;
+ if (tokens.get(1).getType() != TokenTypes.IDENTIFIER)
+ {
+ errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token.getSourceLine(),
+ tokens.get(1).getStartPos(), "Invalid Macro name \""
+ + tokens.get(1).getValue() + "\""));
+ return;
}
- if (inMacroSegment) {
- errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token.getSourceLine(),
- token.getStartPos(), "Nested macros are not allowed"));
- return;
+ if (inMacroSegment)
+ {
+ errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token.getSourceLine(),
+ token.getStartPos(), "Nested macros are not allowed"));
+ return;
}
inMacroSegment = true;
MacroPool pool = fileCurrentlyBeingAssembled.getLocalMacroPool();
pool.beginMacro(tokens.get(1));
- for (int i = 2; i < tokens.size(); i++) {
- Token arg = tokens.get(i);
- if (arg.getType() == TokenTypes.RIGHT_PAREN
- || arg.getType() == TokenTypes.LEFT_PAREN)
- continue;
- if (!Macro.tokenIsMacroParameter(arg.getValue(), true)) {
- errors.add(new ErrorMessage(arg.getSourceMIPSprogram(), arg.getSourceLine(),
- arg.getStartPos(), "Invalid macro argument '" + arg.getValue() + "'"));
- return;
- }
- pool.getCurrent().addArg(arg.getValue());
+ for (int i = 2; i < tokens.size(); i++)
+ {
+ Token arg = tokens.get(i);
+ if (arg.getType() == TokenTypes.RIGHT_PAREN
+ || arg.getType() == TokenTypes.LEFT_PAREN)
+ {
+ continue;
+ }
+ if (!Macro.tokenIsMacroParameter(arg.getValue(), true))
+ {
+ errors.add(new ErrorMessage(arg.getSourceMIPSprogram(), arg.getSourceLine(),
+ arg.getStartPos(), "Invalid macro argument '" + arg.getValue() + "'"));
+ return;
+ }
+ pool.getCurrent().addArg(arg.getValue());
}
- }
- else if (direct == Directives.END_MACRO) {
- if (tokens.size() > 1) {
- errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token.getSourceLine(),
- token.getStartPos(), "invalid text after .END_MACRO"));
- return;
+ }
+ else if (direct == Directives.END_MACRO)
+ {
+ if (tokens.size() > 1)
+ {
+ errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token.getSourceLine(),
+ token.getStartPos(), "invalid text after .END_MACRO"));
+ return;
}
- if (!inMacroSegment) {
- errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token.getSourceLine(),
- token.getStartPos(), ".END_MACRO without .MACRO"));
- return;
+ if (!inMacroSegment)
+ {
+ errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token.getSourceLine(),
+ token.getStartPos(), ".END_MACRO without .MACRO"));
+ return;
}
inMacroSegment = false;
fileCurrentlyBeingAssembled.getLocalMacroPool().commitMacro(token);
- }
- else if (inMacroSegment) {
- // should not parse lines even directives in macro segment
- return;
- }
- else if (direct == Directives.DATA || direct == Directives.KDATA) {
+ }
+ else if (inMacroSegment)
+ {
+ // should not parse lines even directives in macro segment
+ }
+ else if (direct == Directives.DATA || direct == Directives.KDATA)
+ {
this.inDataSegment = true;
this.autoAlign = true;
this.dataAddress.setAddressSpace((direct == Directives.DATA) ? this.dataAddress.USER
- : this.dataAddress.KERNEL);
- if (tokens.size() > 1 && TokenTypes.isIntegerTokenType(tokens.get(1).getType())) {
- this.dataAddress.set(Binary.stringToInt(tokens.get(1).getValue())); // KENV 1/6/05
+ : this.dataAddress.KERNEL);
+ if (tokens.size() > 1 && TokenTypes.isIntegerTokenType(tokens.get(1).getType()))
+ {
+ this.dataAddress.set(Binary.stringToInt(tokens.get(1).getValue())); // KENV 1/6/05
}
- }
- else if (direct == Directives.TEXT || direct == Directives.KTEXT) {
+ }
+ else if (direct == Directives.TEXT || direct == Directives.KTEXT)
+ {
this.inDataSegment = false;
this.textAddress.setAddressSpace((direct == Directives.TEXT) ? this.textAddress.USER
- : this.textAddress.KERNEL);
- if (tokens.size() > 1 && TokenTypes.isIntegerTokenType(tokens.get(1).getType())) {
- this.textAddress.set(Binary.stringToInt(tokens.get(1).getValue())); // KENV 1/6/05
+ : this.textAddress.KERNEL);
+ if (tokens.size() > 1 && TokenTypes.isIntegerTokenType(tokens.get(1).getType()))
+ {
+ this.textAddress.set(Binary.stringToInt(tokens.get(1).getValue())); // KENV 1/6/05
}
- }
- else if (direct == Directives.WORD || direct == Directives.HALF
- || direct == Directives.BYTE || direct == Directives.FLOAT
- || direct == Directives.DOUBLE) {
+ }
+ else if (direct == Directives.WORD || direct == Directives.HALF
+ || direct == Directives.BYTE || direct == Directives.FLOAT
+ || direct == Directives.DOUBLE)
+ {
this.dataDirective = direct;
- if (passesDataSegmentCheck(token) && tokens.size() > 1) { // DPS
- // 11/20/06, added text segment prohibition
- storeNumeric(tokens, direct, errors);
+ if (passesDataSegmentCheck(token) && tokens.size() > 1)
+ { // DPS
+ // 11/20/06, added text segment prohibition
+ storeNumeric(tokens, direct, errors);
}
- }
- else if (direct == Directives.ASCII || direct == Directives.ASCIIZ) {
+ }
+ else if (direct == Directives.ASCII || direct == Directives.ASCIIZ)
+ {
this.dataDirective = direct;
- if (passesDataSegmentCheck(token)) {
- storeStrings(tokens, direct, errors);
+ if (passesDataSegmentCheck(token))
+ {
+ storeStrings(tokens, direct, errors);
}
- }
- else if (direct == Directives.ALIGN) {
- if (passesDataSegmentCheck(token)) {
- if (tokens.size() != 2) {
- errors.add(new ErrorMessage(token.getSourceMIPSprogram(),
- token.getSourceLine(), token.getStartPos(), "\"" + token.getValue()
- + "\" requires one operand"));
- return;
- }
- if (!TokenTypes.isIntegerTokenType(tokens.get(1).getType())
- || Binary.stringToInt(tokens.get(1).getValue()) < 0) {
- errors.add(new ErrorMessage(token.getSourceMIPSprogram(),
- token.getSourceLine(), token.getStartPos(), "\"" + token.getValue()
- + "\" requires a non-negative integer"));
- return;
- }
- int value = Binary.stringToInt(tokens.get(1).getValue()); // KENV 1/6/05
- if (value == 0) {
- this.autoAlign = false;
- }
- else {
- this.dataAddress.set(this.alignToBoundary(this.dataAddress.get(),
- (int) Math.pow(2, value)));
- }
+ }
+ else if (direct == Directives.ALIGN)
+ {
+ if (passesDataSegmentCheck(token))
+ {
+ if (tokens.size() != 2)
+ {
+ errors.add(new ErrorMessage(token.getSourceMIPSprogram(),
+ token.getSourceLine(), token.getStartPos(), "\"" + token.getValue()
+ + "\" requires one operand"));
+ return;
+ }
+ if (!TokenTypes.isIntegerTokenType(tokens.get(1).getType())
+ || Binary.stringToInt(tokens.get(1).getValue()) < 0)
+ {
+ errors.add(new ErrorMessage(token.getSourceMIPSprogram(),
+ token.getSourceLine(), token.getStartPos(), "\"" + token.getValue()
+ + "\" requires a non-negative integer"));
+ return;
+ }
+ int value = Binary.stringToInt(tokens.get(1).getValue()); // KENV 1/6/05
+ if (value == 0)
+ {
+ this.autoAlign = false;
+ }
+ else
+ {
+ this.dataAddress.set(this.alignToBoundary(this.dataAddress.get(),
+ (int) Math.pow(2, value)));
+ }
}
- }
- else if (direct == Directives.SPACE) {
- if (passesDataSegmentCheck(token)) {
- if (tokens.size() != 2) {
- errors.add(new ErrorMessage(token.getSourceMIPSprogram(),
- token.getSourceLine(), token.getStartPos(), "\"" + token.getValue()
- + "\" requires one operand"));
- return;
- }
- if (!TokenTypes.isIntegerTokenType(tokens.get(1).getType())
- || Binary.stringToInt(tokens.get(1).getValue()) < 0) {
- errors.add(new ErrorMessage(token.getSourceMIPSprogram(),
- token.getSourceLine(), token.getStartPos(), "\"" + token.getValue()
- + "\" requires a non-negative integer"));
- return;
- }
- int value = Binary.stringToInt(tokens.get(1).getValue()); // KENV 1/6/05
- this.dataAddress.increment(value);
+ }
+ else if (direct == Directives.SPACE)
+ {
+ if (passesDataSegmentCheck(token))
+ {
+ if (tokens.size() != 2)
+ {
+ errors.add(new ErrorMessage(token.getSourceMIPSprogram(),
+ token.getSourceLine(), token.getStartPos(), "\"" + token.getValue()
+ + "\" requires one operand"));
+ return;
+ }
+ if (!TokenTypes.isIntegerTokenType(tokens.get(1).getType())
+ || Binary.stringToInt(tokens.get(1).getValue()) < 0)
+ {
+ errors.add(new ErrorMessage(token.getSourceMIPSprogram(),
+ token.getSourceLine(), token.getStartPos(), "\"" + token.getValue()
+ + "\" requires a non-negative integer"));
+ return;
+ }
+ int value = Binary.stringToInt(tokens.get(1).getValue()); // KENV 1/6/05
+ this.dataAddress.increment(value);
}
- }
- else if (direct == Directives.EXTERN) {
- if (tokens.size() != 3) {
- errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token.getSourceLine(),
- token.getStartPos(), "\"" + token.getValue()
- + "\" directive requires two operands (label and size)."));
- return;
+ }
+ else if (direct == Directives.EXTERN)
+ {
+ if (tokens.size() != 3)
+ {
+ errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token.getSourceLine(),
+ token.getStartPos(), "\"" + token.getValue()
+ + "\" directive requires two operands (label and size)."));
+ return;
}
if (!TokenTypes.isIntegerTokenType(tokens.get(2).getType())
- || Binary.stringToInt(tokens.get(2).getValue()) < 0) {
- errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token.getSourceLine(),
- token.getStartPos(), "\"" + token.getValue()
- + "\" requires a non-negative integer size"));
- return;
+ || Binary.stringToInt(tokens.get(2).getValue()) < 0)
+ {
+ errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token.getSourceLine(),
+ token.getStartPos(), "\"" + token.getValue()
+ + "\" requires a non-negative integer size"));
+ return;
}
int size = Binary.stringToInt(tokens.get(2).getValue());
- // If label already in global symtab, do nothing. If not, add it right now.
- if (Globals.symbolTable.getAddress(tokens.get(1).getValue()) == SymbolTable.NOT_FOUND) {
- Globals.symbolTable.addSymbol(tokens.get(1), this.externAddress,
- Symbol.DATA_SYMBOL, errors);
- this.externAddress += size;
+ // If label already in global symtab, do nothing. If not, add it right now.
+ if (Globals.symbolTable.getAddress(tokens.get(1).getValue()) == SymbolTable.NOT_FOUND)
+ {
+ Globals.symbolTable.addSymbol(tokens.get(1), this.externAddress,
+ Symbol.DATA_SYMBOL, errors);
+ this.externAddress += size;
}
- }
- else if (direct == Directives.SET) {
+ }
+ else if (direct == Directives.SET)
+ {
errors.add(new ErrorMessage(ErrorMessage.WARNING, token.getSourceMIPSprogram(), token
- .getSourceLine(), token.getStartPos(),
- "MARS currently ignores the .set directive."));
- }
- else if (direct == Directives.GLOBL) {
- if (tokens.size() < 2) {
- errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token.getSourceLine(),
- token.getStartPos(), "\"" + token.getValue()
- + "\" directive requires at least one argument."));
- return;
+ .getSourceLine(), token.getStartPos(),
+ "MARS currently ignores the .set directive."));
+ }
+ else if (direct == Directives.GLOBL)
+ {
+ if (tokens.size() < 2)
+ {
+ errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token.getSourceLine(),
+ token.getStartPos(), "\"" + token.getValue()
+ + "\" directive requires at least one argument."));
+ return;
}
- // SPIM limits .globl list to one label, why not extend it to a list?
- for (int i = 1; i < tokens.size(); i++) {
- // Add it to a list of labels to be processed at the end of the
- // pass. At that point, transfer matching symbol definitions from
- // local symbol table to global symbol table.
- Token label = tokens.get(i);
- if (label.getType() != TokenTypes.IDENTIFIER) {
- errors.add(new ErrorMessage(token.getSourceMIPSprogram(),
- token.getSourceLine(), token.getStartPos(), "\"" + token.getValue()
- + "\" directive argument must be label."));
- return;
- }
- globalDeclarationList.add(label);
+ // SPIM limits .globl list to one label, why not extend it to a list?
+ for (int i = 1; i < tokens.size(); i++)
+ {
+ // Add it to a list of labels to be processed at the end of the
+ // pass. At that point, transfer matching symbol definitions from
+ // local symbol table to global symbol table.
+ Token label = tokens.get(i);
+ if (label.getType() != TokenTypes.IDENTIFIER)
+ {
+ errors.add(new ErrorMessage(token.getSourceMIPSprogram(),
+ token.getSourceLine(), token.getStartPos(), "\"" + token.getValue()
+ + "\" directive argument must be label."));
+ return;
+ }
+ globalDeclarationList.add(label);
}
- }
- else {
+ }
+ else
+ {
errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token.getSourceLine(), token
- .getStartPos(), "\"" + token.getValue()
- + "\" directive recognized but not yet implemented."));
- return;
- }
- } // executeDirective()
-
- // //////////////////////////////////////////////////////////////////////////////
- // Process the list of .globl labels, if any, declared and defined in this file.
- // We'll just move their symbol table entries from local symbol table to global
- // symbol table at the end of the first assembly pass.
- private void transferGlobals() {
- for (int i = 0; i < globalDeclarationList.size(); i++) {
+ .getStartPos(), "\"" + token.getValue()
+ + "\" directive recognized but not yet implemented."));
+ }
+ } // executeDirective()
+
+ // //////////////////////////////////////////////////////////////////////////////
+ // Process the list of .globl labels, if any, declared and defined in this file.
+ // We'll just move their symbol table entries from local symbol table to global
+ // symbol table at the end of the first assembly pass.
+ private void transferGlobals()
+ {
+ for (int i = 0; i < globalDeclarationList.size(); i++)
+ {
Token label = globalDeclarationList.get(i);
Symbol symtabEntry = fileCurrentlyBeingAssembled.getLocalSymbolTable().getSymbol(
- label.getValue());
- if (symtabEntry == null) {
- errors.add(new ErrorMessage(fileCurrentlyBeingAssembled, label.getSourceLine(),
- label.getStartPos(), "\"" + label.getValue()
- + "\" declared global label but not defined."));
- }
- else {
- if (Globals.symbolTable.getAddress(label.getValue()) != SymbolTable.NOT_FOUND) {
- errors.add(new ErrorMessage(fileCurrentlyBeingAssembled, label.getSourceLine(),
- label.getStartPos(), "\"" + label.getValue()
- + "\" already defined as global in a different file."));
- }
- else {
- fileCurrentlyBeingAssembled.getLocalSymbolTable().removeSymbol(label);
- Globals.symbolTable.addSymbol(label, symtabEntry.getAddress(),
- symtabEntry.getType(), errors);
- }
+ label.getValue());
+ if (symtabEntry == null)
+ {
+ errors.add(new ErrorMessage(fileCurrentlyBeingAssembled, label.getSourceLine(),
+ label.getStartPos(), "\"" + label.getValue()
+ + "\" declared global label but not defined."));
}
- }
- }
-
- // //////////////////////////////////////////////////////////////////////////////////
- // This source code line, if syntactically correct, is a continuation of a
- // directive list begun on on previous line.
- private void executeDirectiveContinuation(TokenList tokens) {
- Directives direct = this.dataDirective;
- if (direct == Directives.WORD || direct == Directives.HALF || direct == Directives.BYTE
- || direct == Directives.FLOAT || direct == Directives.DOUBLE) {
- if (tokens.size() > 0) {
- storeNumeric(tokens, direct, errors);
- }
- }
- else if (direct == Directives.ASCII || direct == Directives.ASCIIZ) {
- if (passesDataSegmentCheck(tokens.get(0))) {
- storeStrings(tokens, direct, errors);
- }
- }
- } // executeDirectiveContinuation()
-
- // //////////////////////////////////////////////////////////////////////////////////
- // Given token, find the corresponding Instruction object. If token was not
- // recognized as OPERATOR, there is a problem.
- private ArrayList matchInstruction(Token token) {
- if (token.getType() != TokenTypes.OPERATOR) {
- if (token.getSourceMIPSprogram().getLocalMacroPool()
- .matchesAnyMacroName(token.getValue()))
- this.errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token
- .getSourceLine(), token.getStartPos(), "forward reference or invalid parameters for macro \""
- + token.getValue() + "\""));
else
- this.errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token
- .getSourceLine(), token.getStartPos(), "\"" + token.getValue()
- + "\" is not a recognized operator"));
+ {
+ if (Globals.symbolTable.getAddress(label.getValue()) != SymbolTable.NOT_FOUND)
+ {
+ errors.add(new ErrorMessage(fileCurrentlyBeingAssembled, label.getSourceLine(),
+ label.getStartPos(), "\"" + label.getValue()
+ + "\" already defined as global in a different file."));
+ }
+ else
+ {
+ fileCurrentlyBeingAssembled.getLocalSymbolTable().removeSymbol(label);
+ Globals.symbolTable.addSymbol(label, symtabEntry.getAddress(),
+ symtabEntry.getType(), errors);
+ }
+ }
+ }
+ }
+
+ // //////////////////////////////////////////////////////////////////////////////////
+ // This source code line, if syntactically correct, is a continuation of a
+ // directive list begun on on previous line.
+ private void executeDirectiveContinuation(TokenList tokens)
+ {
+ Directives direct = this.dataDirective;
+ if (direct == Directives.WORD || direct == Directives.HALF || direct == Directives.BYTE
+ || direct == Directives.FLOAT || direct == Directives.DOUBLE)
+ {
+ if (tokens.size() > 0)
+ {
+ storeNumeric(tokens, direct, errors);
+ }
+ }
+ else if (direct == Directives.ASCII || direct == Directives.ASCIIZ)
+ {
+ if (passesDataSegmentCheck(tokens.get(0)))
+ {
+ storeStrings(tokens, direct, errors);
+ }
+ }
+ } // executeDirectiveContinuation()
+
+ // //////////////////////////////////////////////////////////////////////////////////
+ // Given token, find the corresponding Instruction object. If token was not
+ // recognized as OPERATOR, there is a problem.
+ private ArrayList matchInstruction(Token token)
+ {
+ if (token.getType() != TokenTypes.OPERATOR)
+ {
+ if (token.getSourceMIPSprogram().getLocalMacroPool()
+ .matchesAnyMacroName(token.getValue()))
+ {
+ this.errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token
+ .getSourceLine(), token.getStartPos(), "forward reference or invalid parameters for macro \""
+ + token.getValue() + "\""));
+ }
+ else
+ {
+ this.errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token
+ .getSourceLine(), token.getStartPos(), "\"" + token.getValue()
+ + "\" is not a recognized operator"));
+ }
return null;
- }
- ArrayList inst = Globals.instructionSet.matchOperator(token.getValue());
- if (inst == null) { // This should NEVER happen...
+ }
+ ArrayList inst = Globals.instructionSet.matchOperator(token.getValue());
+ if (inst == null)
+ { // This should NEVER happen...
this.errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token.getSourceLine(),
- token.getStartPos(), "Internal Assembler error: \"" + token.getValue()
- + "\" tokenized OPERATOR then not recognized"));
- }
- return inst;
- } // matchInstruction()
-
- // //////////////////////////////////////////////////////////////////////////////////
- // Processes the .word/.half/.byte/.float/.double directive.
- // Can also handle "directive continuations", e.g. second or subsequent line
- // of a multiline list, which does not contain the directive token. Just pass the
- // current directive as argument.
- private void storeNumeric(TokenList tokens, Directives directive, ErrorList errors) {
- Token token = tokens.get(0);
- // A double-check; should have already been caught...removed ".word" exemption 11/20/06
- if (!passesDataSegmentCheck(token))
+ token.getStartPos(), "Internal Assembler error: \"" + token.getValue()
+ + "\" tokenized OPERATOR then not recognized"));
+ }
+ return inst;
+ } // matchInstruction()
+
+ // //////////////////////////////////////////////////////////////////////////////////
+ // Processes the .word/.half/.byte/.float/.double directive.
+ // Can also handle "directive continuations", e.g. second or subsequent line
+ // of a multiline list, which does not contain the directive token. Just pass the
+ // current directive as argument.
+ private void storeNumeric(TokenList tokens, Directives directive, ErrorList errors)
+ {
+ Token token = tokens.get(0);
+ // A double-check; should have already been caught...removed ".word" exemption 11/20/06
+ if (!passesDataSegmentCheck(token))
+ {
return;
- // Correctly handles case where this is a "directive continuation" line.
- int tokenStart = 0;
- if (token.getType() == TokenTypes.DIRECTIVE)
+ }
+ // Correctly handles case where this is a "directive continuation" line.
+ int tokenStart = 0;
+ if (token.getType() == TokenTypes.DIRECTIVE)
+ {
tokenStart = 1;
-
- // Set byte length in memory of each number (e.g. WORD is 4, BYTE is 1, etc)
- int lengthInBytes = DataTypes.getLengthInBytes(directive);
-
- // Handle the "value : n" format, which replicates the value "n" times.
- if (tokens.size() == 4 && tokens.get(2).getType() == TokenTypes.COLON) {
+ }
+
+ // Set byte length in memory of each number (e.g. WORD is 4, BYTE is 1, etc)
+ int lengthInBytes = DataTypes.getLengthInBytes(directive);
+
+ // Handle the "value : n" format, which replicates the value "n" times.
+ if (tokens.size() == 4 && tokens.get(2).getType() == TokenTypes.COLON)
+ {
Token valueToken = tokens.get(1);
Token repetitionsToken = tokens.get(3);
- // DPS 15-jul-08, allow ":" for repetition for all numeric
- // directives (originally just .word)
- // Conditions for correctly-formed replication:
- // (integer directive AND integer value OR floating directive AND
- // (integer value OR floating value))
- // AND integer repetition value
+ // DPS 15-jul-08, allow ":" for repetition for all numeric
+ // directives (originally just .word)
+ // Conditions for correctly-formed replication:
+ // (integer directive AND integer value OR floating directive AND
+ // (integer value OR floating value))
+ // AND integer repetition value
if (!(Directives.isIntegerDirective(directive)
- && TokenTypes.isIntegerTokenType(valueToken.getType()) || Directives
- .isFloatingDirective(directive)
- && (TokenTypes.isIntegerTokenType(valueToken.getType()) || TokenTypes
- .isFloatingTokenType(valueToken.getType())))
- || !TokenTypes.isIntegerTokenType(repetitionsToken.getType())) {
- errors.add(new ErrorMessage(fileCurrentlyBeingAssembled,
- valueToken.getSourceLine(), valueToken.getStartPos(),
- "malformed expression"));
- return;
+ && TokenTypes.isIntegerTokenType(valueToken.getType()) || Directives
+ .isFloatingDirective(directive)
+ && (TokenTypes.isIntegerTokenType(valueToken.getType()) || TokenTypes
+ .isFloatingTokenType(valueToken.getType())))
+ || !TokenTypes.isIntegerTokenType(repetitionsToken.getType()))
+ {
+ errors.add(new ErrorMessage(fileCurrentlyBeingAssembled,
+ valueToken.getSourceLine(), valueToken.getStartPos(),
+ "malformed expression"));
+ return;
}
int repetitions = Binary.stringToInt(repetitionsToken.getValue()); // KENV 1/6/05
- if (repetitions <= 0) {
- errors.add(new ErrorMessage(fileCurrentlyBeingAssembled, repetitionsToken
- .getSourceLine(), repetitionsToken.getStartPos(),
- "repetition factor must be positive"));
- return;
+ if (repetitions <= 0)
+ {
+ errors.add(new ErrorMessage(fileCurrentlyBeingAssembled, repetitionsToken
+ .getSourceLine(), repetitionsToken.getStartPos(),
+ "repetition factor must be positive"));
+ return;
}
- if (this.inDataSegment) {
- if (this.autoAlign) {
- this.dataAddress
- .set(this.alignToBoundary(this.dataAddress.get(), lengthInBytes));
- }
- for (int i = 0; i < repetitions; i++) {
- if (Directives.isIntegerDirective(directive)) {
- storeInteger(valueToken, directive, errors);
- }
- else {
- storeRealNumber(valueToken, directive, errors);
- }
- }
+ if (this.inDataSegment)
+ {
+ if (this.autoAlign)
+ {
+ this.dataAddress
+ .set(this.alignToBoundary(this.dataAddress.get(), lengthInBytes));
+ }
+ for (int i = 0; i < repetitions; i++)
+ {
+ if (Directives.isIntegerDirective(directive))
+ {
+ storeInteger(valueToken, directive, errors);
+ }
+ else
+ {
+ storeRealNumber(valueToken, directive, errors);
+ }
+ }
} // WHAT ABOUT .KDATA SEGMENT?
- /***************************************************************************
- * /****** NOTE of 11/20/06. Below will always throw exception b/c
- * you cannot use Memory.set() with text segment addresses and the
- * "not valid address" produced here is misleading. Added data
- * segment check prior to this point, so this "else" will never be
- * executed. I'm leaving it in just in case MARS in the future adds
- * capability of writing to the text segment (e.g. ability to
- * de-assemble a binary value into its corresponding MIPS
- * instruction)
- *
- * else { // not in data segment...which we assume to mean in text
- * segment. try { for (int i=0; i < repetitions; i++) {
- * Globals.memory.set(this.textAddress.get(),
- * Binary.stringToInt(valueToken.getValue()), lengthInBytes);
- * this.textAddress.increment(lengthInBytes); } } catch
- * (AddressErrorException e) { errors.add(new
- * ErrorMessage(token.getSourceMIPSprogram(), token.getSourceLine(),
- * token.getStartPos(), "\""+this.textAddress.get()+
- * "\" is not a valid text segment address")); } }
- ************************************************************************/
+ /***************************************************************************
+ * /****** NOTE of 11/20/06. Below will always throw exception b/c
+ * you cannot use Memory.set() with text segment addresses and the
+ * "not valid address" produced here is misleading. Added data
+ * segment check prior to this point, so this "else" will never be
+ * executed. I'm leaving it in just in case MARS in the future adds
+ * capability of writing to the text segment (e.g. ability to
+ * de-assemble a binary value into its corresponding MIPS
+ * instruction)
+ *
+ * else { // not in data segment...which we assume to mean in text
+ * segment. try { for (int i=0; i < repetitions; i++) {
+ * Globals.memory.set(this.textAddress.get(),
+ * Binary.stringToInt(valueToken.getValue()), lengthInBytes);
+ * this.textAddress.increment(lengthInBytes); } } catch
+ * (AddressErrorException e) { errors.add(new
+ * ErrorMessage(token.getSourceMIPSprogram(), token.getSourceLine(),
+ * token.getStartPos(), "\""+this.textAddress.get()+
+ * "\" is not a valid text segment address")); } }
+ ************************************************************************/
return;
- }
-
- // if not in ".word w : n" format, must just be list of one or more values.
- for (int i = tokenStart; i < tokens.size(); i++) {
+ }
+
+ // if not in ".word w : n" format, must just be list of one or more values.
+ for (int i = tokenStart; i < tokens.size(); i++)
+ {
token = tokens.get(i);
- if (Directives.isIntegerDirective(directive)) {
- storeInteger(token, directive, errors);
+ if (Directives.isIntegerDirective(directive))
+ {
+ storeInteger(token, directive, errors);
}
- if (Directives.isFloatingDirective(directive)) {
- storeRealNumber(token, directive, errors);
+ if (Directives.isFloatingDirective(directive))
+ {
+ storeRealNumber(token, directive, errors);
}
- }
- return;
- } // storeNumeric()
-
- // //////////////////////////////////////////////////////////////////////////////
- // Store integer value given integer (word, half, byte) directive.
- // Called by storeNumeric()
- // NOTE: The token itself may be a label, in which case the correct action is
- // to store the address of that label (into however many bytes specified).
- private void storeInteger(Token token, Directives directive, ErrorList errors) {
- int lengthInBytes = DataTypes.getLengthInBytes(directive);
- if (TokenTypes.isIntegerTokenType(token.getType())) {
- int value = Binary.stringToInt(token.getValue());
+ }
+ } // storeNumeric()
+
+ // //////////////////////////////////////////////////////////////////////////////
+ // Store integer value given integer (word, half, byte) directive.
+ // Called by storeNumeric()
+ // NOTE: The token itself may be a label, in which case the correct action is
+ // to store the address of that label (into however many bytes specified).
+ private void storeInteger(Token token, Directives directive, ErrorList errors)
+ {
+ int lengthInBytes = DataTypes.getLengthInBytes(directive);
+ if (TokenTypes.isIntegerTokenType(token.getType()))
+ {
+ int value = Binary.stringToInt(token.getValue());
int fullvalue = value;
// DPS 4-Jan-2013. Overriding 6-Jan-2005 KENV changes.
- // If value is out of range for the directive, will simply truncate
- // the leading bits (includes sign bits). This is what SPIM does.
- // But will issue a warning (not error) which SPIM does not do.
- if (directive == Directives.BYTE) {
- value = value & 0x000000FF;
- }
- else if (directive == Directives.HALF) {
- value = value & 0x0000FFFF;
+ // If value is out of range for the directive, will simply truncate
+ // the leading bits (includes sign bits). This is what SPIM does.
+ // But will issue a warning (not error) which SPIM does not do.
+ if (directive == Directives.BYTE)
+ {
+ value = value & 0x000000FF;
}
-
- if (DataTypes.outOfRange(directive, fullvalue)) {
- errors.add(new ErrorMessage(ErrorMessage.WARNING, token.getSourceMIPSprogram(), token.getSourceLine(),
- token.getStartPos(), "\"" + token.getValue()
- + "\" is out-of-range for a signed value and possibly truncated"));
+ else if (directive == Directives.HALF)
+ {
+ value = value & 0x0000FFFF;
}
- if (this.inDataSegment) {
- writeToDataSegment(value, lengthInBytes, token, errors);
+
+ if (DataTypes.outOfRange(directive, fullvalue))
+ {
+ errors.add(new ErrorMessage(ErrorMessage.WARNING, token.getSourceMIPSprogram(), token.getSourceLine(),
+ token.getStartPos(), "\"" + token.getValue()
+ + "\" is out-of-range for a signed value and possibly truncated"));
+ }
+ if (this.inDataSegment)
+ {
+ writeToDataSegment(value, lengthInBytes, token, errors);
}
/******
- * NOTE of 11/20/06. "try" below will always throw exception b/c you
- * cannot use Memory.set() with text segment addresses and the
- * "not valid address" produced here is misleading. Added data
- * segment check prior to this point, so this "else" will never be
- * executed. I'm leaving it in just in case MARS in the future adds
- * capability of writing to the text segment (e.g. ability to
- * de-assemble a binary value into its corresponding MIPS
- * instruction)
- ********/
- else {
- try {
- Globals.memory.set(this.textAddress.get(), value, lengthInBytes);
- }
- catch (AddressErrorException e) {
- errors.add(new ErrorMessage(token.getSourceMIPSprogram(),
+ * NOTE of 11/20/06. "try" below will always throw exception b/c you
+ * cannot use Memory.set() with text segment addresses and the
+ * "not valid address" produced here is misleading. Added data
+ * segment check prior to this point, so this "else" will never be
+ * executed. I'm leaving it in just in case MARS in the future adds
+ * capability of writing to the text segment (e.g. ability to
+ * de-assemble a binary value into its corresponding MIPS
+ * instruction)
+ ********/
+ else
+ {
+ try
+ {
+ Globals.memory.set(this.textAddress.get(), value, lengthInBytes);
+ }
+ catch (AddressErrorException e)
+ {
+ errors.add(new ErrorMessage(token.getSourceMIPSprogram(),
token.getSourceLine(), token.getStartPos(), "\""
- + this.textAddress.get()
- + "\" is not a valid text segment address"));
- return;
- }
- this.textAddress.increment(lengthInBytes);
+ + this.textAddress.get()
+ + "\" is not a valid text segment address"));
+ return;
+ }
+ this.textAddress.increment(lengthInBytes);
}
- } // end of "if integer token type"
- else if (token.getType() == TokenTypes.IDENTIFIER) {
- if (this.inDataSegment) {
- int value = fileCurrentlyBeingAssembled.getLocalSymbolTable()
- .getAddressLocalOrGlobal(token.getValue());
- if (value == SymbolTable.NOT_FOUND) {
- // Record value 0 for now, then set up backpatch entry
- int dataAddress = writeToDataSegment(0, lengthInBytes, token, errors);
- currentFileDataSegmentForwardReferences.add(dataAddress, lengthInBytes, token);
- }
- else { // label already defined, so write its address
- writeToDataSegment(value, lengthInBytes, token, errors);
- }
+ } // end of "if integer token type"
+ else if (token.getType() == TokenTypes.IDENTIFIER)
+ {
+ if (this.inDataSegment)
+ {
+ int value = fileCurrentlyBeingAssembled.getLocalSymbolTable()
+ .getAddressLocalOrGlobal(token.getValue());
+ if (value == SymbolTable.NOT_FOUND)
+ {
+ // Record value 0 for now, then set up backpatch entry
+ int dataAddress = writeToDataSegment(0, lengthInBytes, token, errors);
+ currentFileDataSegmentForwardReferences.add(dataAddress, lengthInBytes, token);
+ }
+ else
+ { // label already defined, so write its address
+ writeToDataSegment(value, lengthInBytes, token, errors);
+ }
} // Data segment check done previously, so this "else" will not be.
// See 11/20/06 note above.
- else {
- errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token.getSourceLine(),
- token.getStartPos(), "\"" + token.getValue()
- + "\" label as directive operand not permitted in text segment"));
+ else
+ {
+ errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token.getSourceLine(),
+ token.getStartPos(), "\"" + token.getValue()
+ + "\" label as directive operand not permitted in text segment"));
}
- } // end of "if label"
- else {
+ } // end of "if label"
+ else
+ {
errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token.getSourceLine(), token
- .getStartPos(), "\"" + token.getValue()
- + "\" is not a valid integer constant or label"));
- }
- }// storeInteger
-
- // //////////////////////////////////////////////////////////////////////////////
- // Store real (fixed or floating point) value given floating (float, double) directive.
- // Called by storeNumeric()
- private void storeRealNumber(Token token, Directives directive, ErrorList errors) {
- int lengthInBytes = DataTypes.getLengthInBytes(directive);
- double value;
-
- if (TokenTypes.isIntegerTokenType(token.getType())
- || TokenTypes.isFloatingTokenType(token.getType())) {
- try {
- value = Double.parseDouble(token.getValue());
- }
- catch (NumberFormatException nfe) {
- errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token.getSourceLine(),
- token.getStartPos(), "\"" + token.getValue()
- + "\" is not a valid floating point constant"));
- return;
- }
- if (DataTypes.outOfRange(directive, value)) {
- errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token.getSourceLine(),
- token.getStartPos(), "\"" + token.getValue()
- + "\" is an out-of-range value"));
- return;
+ .getStartPos(), "\"" + token.getValue()
+ + "\" is not a valid integer constant or label"));
+ }
+ }// storeInteger
+
+ // //////////////////////////////////////////////////////////////////////////////
+ // Store real (fixed or floating point) value given floating (float, double) directive.
+ // Called by storeNumeric()
+ private void storeRealNumber(Token token, Directives directive, ErrorList errors)
+ {
+ int lengthInBytes = DataTypes.getLengthInBytes(directive);
+ double value;
+
+ if (TokenTypes.isIntegerTokenType(token.getType())
+ || TokenTypes.isFloatingTokenType(token.getType()))
+ {
+ try
+ {
+ value = Double.parseDouble(token.getValue());
}
- }
- else {
+ catch (NumberFormatException nfe)
+ {
+ errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token.getSourceLine(),
+ token.getStartPos(), "\"" + token.getValue()
+ + "\" is not a valid floating point constant"));
+ return;
+ }
+ if (DataTypes.outOfRange(directive, value))
+ {
+ errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token.getSourceLine(),
+ token.getStartPos(), "\"" + token.getValue()
+ + "\" is an out-of-range value"));
+ return;
+ }
+ }
+ else
+ {
errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token.getSourceLine(), token
- .getStartPos(), "\"" + token.getValue()
- + "\" is not a valid floating point constant"));
+ .getStartPos(), "\"" + token.getValue()
+ + "\" is not a valid floating point constant"));
return;
- }
-
- // Value has been validated; let's store it.
-
- if (directive == Directives.FLOAT) {
+ }
+
+ // Value has been validated; let's store it.
+
+ if (directive == Directives.FLOAT)
+ {
writeToDataSegment(Float.floatToIntBits((float) value), lengthInBytes, token, errors);
- }
- if (directive == Directives.DOUBLE) {
+ }
+ if (directive == Directives.DOUBLE)
+ {
writeDoubleToDataSegment(value, token, errors);
- }
-
- } // storeRealNumber
-
- // //////////////////////////////////////////////////////////////////////////////////
- // Use directive argument to distinguish between ASCII and ASCIIZ. The
- // latter stores a terminating null byte. Can handle a list of one or more
- // strings on a single line.
- private void storeStrings(TokenList tokens, Directives direct, ErrorList errors) {
- Token token;
- // Correctly handles case where this is a "directive continuation" line.
- int tokenStart = 0;
- if (tokens.get(0).getType() == TokenTypes.DIRECTIVE) {
+ }
+
+ } // storeRealNumber
+
+ // //////////////////////////////////////////////////////////////////////////////////
+ // Use directive argument to distinguish between ASCII and ASCIIZ. The
+ // latter stores a terminating null byte. Can handle a list of one or more
+ // strings on a single line.
+ private void storeStrings(TokenList tokens, Directives direct, ErrorList errors)
+ {
+ Token token;
+ // Correctly handles case where this is a "directive continuation" line.
+ int tokenStart = 0;
+ if (tokens.get(0).getType() == TokenTypes.DIRECTIVE)
+ {
tokenStart = 1;
- }
- for (int i = tokenStart; i < tokens.size(); i++) {
+ }
+ for (int i = tokenStart; i < tokens.size(); i++)
+ {
token = tokens.get(i);
- if (token.getType() != TokenTypes.QUOTED_STRING) {
- errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token.getSourceLine(),
- token.getStartPos(), "\"" + token.getValue()
- + "\" is not a valid character string"));
- }
- else {
- String quote = token.getValue();
- char theChar;
- for (int j = 1; j < quote.length() - 1; j++) {
- theChar = quote.charAt(j);
- if (theChar == '\\') {
- theChar = quote.charAt(++j);
- switch (theChar) {
- case 'n':
- theChar = '\n';
- break;
- case 't':
- theChar = '\t';
- break;
- case 'r':
- theChar = '\r';
- break;
- case '\\':
- theChar = '\\';
- break;
- case '\'':
- theChar = '\'';
- break;
- case '"':
- theChar = '"';
- break;
- case 'b':
- theChar = '\b';
- break;
- case 'f':
- theChar = '\f';
- break;
- case '0':
- theChar = '\0';
- break;
- // Not implemented: \ n = octal character (n is number)
- // \ x n = hex character (n is number)
- // \ u n = unicode character (n is number)
- // There are of course no spaces in these escape
- // codes...
- }
- }
- try {
- Globals.memory.set(this.dataAddress.get(), (int) theChar,
- DataTypes.CHAR_SIZE);
- }
- catch (AddressErrorException e) {
- errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token
- .getSourceLine(), token.getStartPos(), "\""
- + this.dataAddress.get() + "\" is not a valid data segment address"));
- }
- this.dataAddress.increment(DataTypes.CHAR_SIZE);
- }
- if (direct == Directives.ASCIIZ) {
- try {
- Globals.memory.set(this.dataAddress.get(), 0, DataTypes.CHAR_SIZE);
- }
- catch (AddressErrorException e) {
- errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token
- .getSourceLine(), token.getStartPos(), "\""
- + this.dataAddress.get() + "\" is not a valid data segment address"));
- }
- this.dataAddress.increment(DataTypes.CHAR_SIZE);
- }
+ if (token.getType() != TokenTypes.QUOTED_STRING)
+ {
+ errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token.getSourceLine(),
+ token.getStartPos(), "\"" + token.getValue()
+ + "\" is not a valid character string"));
}
- }
- } // storeStrings()
-
- // //////////////////////////////////////////////////////////////////////////////////
- // Simply check to see if we are in data segment. Generate error if not.
- private boolean passesDataSegmentCheck(Token token) {
- if (!this.inDataSegment) {
+ else
+ {
+ String quote = token.getValue();
+ char theChar;
+ for (int j = 1; j < quote.length() - 1; j++)
+ {
+ theChar = quote.charAt(j);
+ if (theChar == '\\')
+ {
+ theChar = quote.charAt(++j);
+ switch (theChar)
+ {
+ case 'n':
+ theChar = '\n';
+ break;
+ case 't':
+ theChar = '\t';
+ break;
+ case 'r':
+ theChar = '\r';
+ break;
+ case '\\':
+ theChar = '\\';
+ break;
+ case '\'':
+ theChar = '\'';
+ break;
+ case '"':
+ theChar = '"';
+ break;
+ case 'b':
+ theChar = '\b';
+ break;
+ case 'f':
+ theChar = '\f';
+ break;
+ case '0':
+ theChar = '\0';
+ break;
+ // Not implemented: \ n = octal character (n is number)
+ // \ x n = hex character (n is number)
+ // \ u n = unicode character (n is number)
+ // There are of course no spaces in these escape
+ // codes...
+ }
+ }
+ try
+ {
+ Globals.memory.set(this.dataAddress.get(), theChar,
+ DataTypes.CHAR_SIZE);
+ }
+ catch (AddressErrorException e)
+ {
+ errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token
+ .getSourceLine(), token.getStartPos(), "\""
+ + this.dataAddress.get() + "\" is not a valid data segment address"));
+ }
+ this.dataAddress.increment(DataTypes.CHAR_SIZE);
+ }
+ if (direct == Directives.ASCIIZ)
+ {
+ try
+ {
+ Globals.memory.set(this.dataAddress.get(), 0, DataTypes.CHAR_SIZE);
+ }
+ catch (AddressErrorException e)
+ {
+ errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token
+ .getSourceLine(), token.getStartPos(), "\""
+ + this.dataAddress.get() + "\" is not a valid data segment address"));
+ }
+ this.dataAddress.increment(DataTypes.CHAR_SIZE);
+ }
+ }
+ }
+ } // storeStrings()
+
+ // //////////////////////////////////////////////////////////////////////////////////
+ // Simply check to see if we are in data segment. Generate error if not.
+ private boolean passesDataSegmentCheck(Token token)
+ {
+ if (!this.inDataSegment)
+ {
errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token.getSourceLine(), token
- .getStartPos(), "\"" + token.getValue()
- + "\" directive cannot appear in text segment"));
+ .getStartPos(), "\"" + token.getValue()
+ + "\" directive cannot appear in text segment"));
return false;
- }
- else {
+ }
+ else
+ {
return true;
- }
- }
-
- // //////////////////////////////////////////////////////////////////////////////////
- // Writes the given int value into current data segment address. Works for
- // all the integer types plus float (caller is responsible for doing floatToIntBits).
- // Returns address at which the value was stored.
- private int writeToDataSegment(int value, int lengthInBytes, Token token, ErrorList errors) {
- if (this.autoAlign) {
+ }
+ }
+
+ // //////////////////////////////////////////////////////////////////////////////////
+ // Writes the given int value into current data segment address. Works for
+ // all the integer types plus float (caller is responsible for doing floatToIntBits).
+ // Returns address at which the value was stored.
+ private int writeToDataSegment(int value, int lengthInBytes, Token token, ErrorList errors)
+ {
+ if (this.autoAlign)
+ {
this.dataAddress.set(this.alignToBoundary(this.dataAddress.get(), lengthInBytes));
- }
- try {
+ }
+ try
+ {
Globals.memory.set(this.dataAddress.get(), value, lengthInBytes);
- }
- catch (AddressErrorException e) {
- errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token.getSourceLine(), token
- .getStartPos(), "\"" + this.dataAddress.get()
- + "\" is not a valid data segment address"));
- return this.dataAddress.get();
- }
- int address = this.dataAddress.get();
- this.dataAddress.increment(lengthInBytes);
- return address;
- }
-
- // //////////////////////////////////////////////////////////////////////////////////
- // Writes the given double value into current data segment address. Works
- // only for DOUBLE floating
- // point values -- Memory class doesn't have method for writing 8 bytes, so
- // use setWord twice.
- private void writeDoubleToDataSegment(double value, Token token, ErrorList errors) {
- int lengthInBytes = DataTypes.DOUBLE_SIZE;
- if (this.autoAlign) {
+ }
+ catch (AddressErrorException e)
+ {
+ errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token.getSourceLine(), token
+ .getStartPos(), "\"" + this.dataAddress.get()
+ + "\" is not a valid data segment address"));
+ return this.dataAddress.get();
+ }
+ int address = this.dataAddress.get();
+ this.dataAddress.increment(lengthInBytes);
+ return address;
+ }
+
+ // //////////////////////////////////////////////////////////////////////////////////
+ // Writes the given double value into current data segment address. Works
+ // only for DOUBLE floating
+ // point values -- Memory class doesn't have method for writing 8 bytes, so
+ // use setWord twice.
+ private void writeDoubleToDataSegment(double value, Token token, ErrorList errors)
+ {
+ int lengthInBytes = DataTypes.DOUBLE_SIZE;
+ if (this.autoAlign)
+ {
this.dataAddress.set(this.alignToBoundary(this.dataAddress.get(), lengthInBytes));
- }
- try {
+ }
+ try
+ {
Globals.memory.setDouble(this.dataAddress.get(), value);
- }
- catch (AddressErrorException e) {
- errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token.getSourceLine(), token
- .getStartPos(), "\"" + this.dataAddress.get()
- + "\" is not a valid data segment address"));
- return;
- }
- this.dataAddress.increment(lengthInBytes);
- }
-
- // //////////////////////////////////////////////////////////////////////////////////
- // If address is multiple of byte boundary, returns address. Otherwise, returns address
- // which is next higher multiple of the byte boundary. Used for aligning data segment.
- // For instance if args are 6 and 4, returns 8 (next multiple of 4 higher than 6).
- // NOTE: it will fix any symbol table entries for this address too. See else part.
- private int alignToBoundary(int address, int byteBoundary) {
- int remainder = address % byteBoundary;
- if (remainder == 0) {
+ }
+ catch (AddressErrorException e)
+ {
+ errors.add(new ErrorMessage(token.getSourceMIPSprogram(), token.getSourceLine(), token
+ .getStartPos(), "\"" + this.dataAddress.get()
+ + "\" is not a valid data segment address"));
+ return;
+ }
+ this.dataAddress.increment(lengthInBytes);
+ }
+
+ // //////////////////////////////////////////////////////////////////////////////////
+ // If address is multiple of byte boundary, returns address. Otherwise, returns address
+ // which is next higher multiple of the byte boundary. Used for aligning data segment.
+ // For instance if args are 6 and 4, returns 8 (next multiple of 4 higher than 6).
+ // NOTE: it will fix any symbol table entries for this address too. See else part.
+ private int alignToBoundary(int address, int byteBoundary)
+ {
+ int remainder = address % byteBoundary;
+ if (remainder == 0)
+ {
return address;
- }
- else {
+ }
+ else
+ {
int alignedAddress = address + byteBoundary - remainder;
fileCurrentlyBeingAssembled.getLocalSymbolTable().fixSymbolTableAddress(address,
- alignedAddress);
+ alignedAddress);
return alignedAddress;
- }
- }
-
- // ///////////////////////////////////////////////////////////////////////////////////
- // Private class used as Comparator to sort the final ArrayList of
- // ProgramStatements.
- // Sorting is based on unsigned integer value of
- // ProgramStatement.getAddress()
- private class ProgramStatementComparator implements Comparator {
- // Will be used to sort the collection. Unsigned int compare, because
- // all kernel 32-bit
- // addresses have 1 in high order bit, which makes the int negative.
- // "Unsigned" compare
- // is needed when signs of the two operands differ.
- public int compare(Object obj1, Object obj2) {
- if (obj1 instanceof ProgramStatement && obj2 instanceof ProgramStatement) {
- int addr1 = ((ProgramStatement) obj1).getAddress();
- int addr2 = ((ProgramStatement) obj2).getAddress();
- return (addr1 < 0 && addr2 >= 0 || addr1 >= 0 && addr2 < 0) ? addr2 : addr1 - addr2;
- }
- else {
- throw new ClassCastException();
+ }
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////
+ // Private class used as Comparator to sort the final ArrayList of
+ // ProgramStatements.
+ // Sorting is based on unsigned integer value of
+ // ProgramStatement.getAddress()
+ private class ProgramStatementComparator implements Comparator
+ {
+ // Will be used to sort the collection. Unsigned int compare, because
+ // all kernel 32-bit
+ // addresses have 1 in high order bit, which makes the int negative.
+ // "Unsigned" compare
+ // is needed when signs of the two operands differ.
+ public int compare(Object obj1, Object obj2)
+ {
+ if (obj1 instanceof ProgramStatement && obj2 instanceof ProgramStatement)
+ {
+ int addr1 = ((ProgramStatement) obj1).getAddress();
+ int addr2 = ((ProgramStatement) obj2).getAddress();
+ return (addr1 < 0 && addr2 >= 0 || addr1 >= 0 && addr2 < 0) ? addr2 : addr1 - addr2;
}
- }
-
- // Take a hard line.
- public boolean equals(Object obj) {
+ else
+ {
+ throw new ClassCastException();
+ }
+ }
+
+ // Take a hard line.
+ public boolean equals(Object obj)
+ {
return this == obj;
- }
- }
-
- // ///////////////////////////////////////////////////////////////////////////////////
- // Private class to simultaneously track addresses in both user and kernel
- // address spaces.
- // Instantiate one for data segment and one for text segment.
- private class UserKernelAddressSpace {
- int[] address;
- int currentAddressSpace;
- private final int USER = 0, KERNEL = 1;
-
- // Initially use user address space, not kernel.
- private UserKernelAddressSpace(int userBase, int kernelBase) {
+ }
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////
+ // Private class to simultaneously track addresses in both user and kernel
+ // address spaces.
+ // Instantiate one for data segment and one for text segment.
+ private class UserKernelAddressSpace
+ {
+ private final int USER = 0, KERNEL = 1;
+
+ int[] address;
+
+ int currentAddressSpace;
+
+ // Initially use user address space, not kernel.
+ private UserKernelAddressSpace(int userBase, int kernelBase)
+ {
address = new int[2];
address[USER] = userBase;
address[KERNEL] = kernelBase;
currentAddressSpace = USER;
- }
-
- private int get() {
+ }
+
+ private int get()
+ {
return address[currentAddressSpace];
- }
-
- private void set(int value) {
+ }
+
+ private void set(int value)
+ {
address[currentAddressSpace] = value;
- }
-
- private void increment(int increment) {
+ }
+
+ private void increment(int increment)
+ {
address[currentAddressSpace] += increment;
- }
-
- private void setAddressSpace(int addressSpace) {
- if (addressSpace == USER || addressSpace == KERNEL) {
- currentAddressSpace = addressSpace;
- }
- else {
- throw new IllegalArgumentException();
+ }
+
+ private void setAddressSpace(int addressSpace)
+ {
+ if (addressSpace == USER || addressSpace == KERNEL)
+ {
+ currentAddressSpace = addressSpace;
}
- }
- }
-
- // //////////////////////////////////////////////////////////////////////////
- // Handy class to handle forward label references appearing as data
- // segment operands. This is needed because the data segment is comletely
- // processed by the end of the first assembly pass, and its directives may
- // contain labels as operands. When this occurs, the label's associated
- // address becomes the operand value. If it is a forward reference, we will
- // save the necessary information in this object for finding and patching in
- // the correct address at the end of the first pass (for this file or for all
- // files if more than one).
- //
- // If such a parsed label refers to a local or global label not defined yet,
- // pertinent information is added to this object:
- // - memory address that needs the label's address,
- // - number of bytes (addresses are 4 bytes but may be used with any of
- // the integer directives: .word, .half, .byte)
- // - the label's token. Normally need only the name but error message needs more.
- private class DataSegmentForwardReferences {
- private ArrayList forwardReferenceList;
-
- private DataSegmentForwardReferences() {
+ else
+ {
+ throw new IllegalArgumentException();
+ }
+ }
+ }
+
+ // //////////////////////////////////////////////////////////////////////////
+ // Handy class to handle forward label references appearing as data
+ // segment operands. This is needed because the data segment is comletely
+ // processed by the end of the first assembly pass, and its directives may
+ // contain labels as operands. When this occurs, the label's associated
+ // address becomes the operand value. If it is a forward reference, we will
+ // save the necessary information in this object for finding and patching in
+ // the correct address at the end of the first pass (for this file or for all
+ // files if more than one).
+ //
+ // If such a parsed label refers to a local or global label not defined yet,
+ // pertinent information is added to this object:
+ // - memory address that needs the label's address,
+ // - number of bytes (addresses are 4 bytes but may be used with any of
+ // the integer directives: .word, .half, .byte)
+ // - the label's token. Normally need only the name but error message needs more.
+ private class DataSegmentForwardReferences
+ {
+ private final ArrayList forwardReferenceList;
+
+ private DataSegmentForwardReferences()
+ {
forwardReferenceList = new ArrayList();
- }
-
- private int size() {
+ }
+
+ private int size()
+ {
return forwardReferenceList.size();
- }
-
- // Add a new forward reference entry. Client must supply the following:
- // - memory address to receive the label's address once resolved
- // - number of address bytes to store (1 for .byte, 2 for .half, 4 for .word)
- // - the label's token. All its information will be needed if error message generated.
- private void add(int patchAddress, int length, Token token) {
+ }
+
+ // Add a new forward reference entry. Client must supply the following:
+ // - memory address to receive the label's address once resolved
+ // - number of address bytes to store (1 for .byte, 2 for .half, 4 for .word)
+ // - the label's token. All its information will be needed if error message generated.
+ private void add(int patchAddress, int length, Token token)
+ {
forwardReferenceList.add(new DataSegmentForwardReference(patchAddress, length, token));
- }
-
- // Add the entries of another DataSegmentForwardReferences object to this one.
- // Can be used at the end of each source file to dump all unresolved references
- // into a common list to be processed after all source files parsed.
- private void add(DataSegmentForwardReferences another) {
+ }
+
+ // Add the entries of another DataSegmentForwardReferences object to this one.
+ // Can be used at the end of each source file to dump all unresolved references
+ // into a common list to be processed after all source files parsed.
+ private void add(DataSegmentForwardReferences another)
+ {
forwardReferenceList.addAll(another.forwardReferenceList);
- }
-
- // Clear out the list. Allows you to re-use it.
- private void clear() {
+ }
+
+ // Clear out the list. Allows you to re-use it.
+ private void clear()
+ {
forwardReferenceList.clear();
- }
-
- // Will traverse the list of forward references, attempting to resolve them.
- // For each entry it will first search the provided local symbol table and
- // failing that, the global one. If passed the global symbol table, it will
- // perform a second, redundant, search. If search is successful, the patch
- // is applied and the forward reference removed. If search is not successful,
- // the forward reference remains (it is either undefined or a global label
- // defined in a file not yet parsed).
- private int resolve(SymbolTable localSymtab) {
+ }
+
+ // Will traverse the list of forward references, attempting to resolve them.
+ // For each entry it will first search the provided local symbol table and
+ // failing that, the global one. If passed the global symbol table, it will
+ // perform a second, redundant, search. If search is successful, the patch
+ // is applied and the forward reference removed. If search is not successful,
+ // the forward reference remains (it is either undefined or a global label
+ // defined in a file not yet parsed).
+ private int resolve(SymbolTable localSymtab)
+ {
int count = 0;
int labelAddress;
DataSegmentForwardReference entry;
- for (int i = 0; i < forwardReferenceList.size(); i++) {
- entry = (DataSegmentForwardReference) forwardReferenceList.get(i);
- labelAddress = localSymtab.getAddressLocalOrGlobal(entry.token.getValue());
- if (labelAddress != SymbolTable.NOT_FOUND) {
- // patch address has to be valid b/c we already stored there...
- try {
- Globals.memory.set(entry.patchAddress, labelAddress, entry.length);
- }
- catch (AddressErrorException aee) {
- }
- forwardReferenceList.remove(i);
- i--; // needed because removal shifted the remaining list indices down
- count++;
- }
+ for (int i = 0; i < forwardReferenceList.size(); i++)
+ {
+ entry = (DataSegmentForwardReference) forwardReferenceList.get(i);
+ labelAddress = localSymtab.getAddressLocalOrGlobal(entry.token.getValue());
+ if (labelAddress != SymbolTable.NOT_FOUND)
+ {
+ // patch address has to be valid b/c we already stored there...
+ try
+ {
+ Globals.memory.set(entry.patchAddress, labelAddress, entry.length);
+ }
+ catch (AddressErrorException aee)
+ {
+ }
+ forwardReferenceList.remove(i);
+ i--; // needed because removal shifted the remaining list indices down
+ count++;
+ }
}
return count;
- }
-
- // Call this when you are confident that remaining list entries are to
- // undefined labels.
- private void generateErrorMessages(ErrorList errors) {
+ }
+
+ // Call this when you are confident that remaining list entries are to
+ // undefined labels.
+ private void generateErrorMessages(ErrorList errors)
+ {
DataSegmentForwardReference entry;
- for (int i = 0; i < forwardReferenceList.size(); i++) {
- entry = (DataSegmentForwardReference) forwardReferenceList.get(i);
- errors.add(new ErrorMessage(entry.token.getSourceMIPSprogram(), entry.token
- .getSourceLine(), entry.token.getStartPos(), "Symbol \""
- + entry.token.getValue() + "\" not found in symbol table."));
+ for (int i = 0; i < forwardReferenceList.size(); i++)
+ {
+ entry = (DataSegmentForwardReference) forwardReferenceList.get(i);
+ errors.add(new ErrorMessage(entry.token.getSourceMIPSprogram(), entry.token
+ .getSourceLine(), entry.token.getStartPos(), "Symbol \""
+ + entry.token.getValue() + "\" not found in symbol table."));
}
- }
-
- // inner-inner class to hold each entry of the forward reference list.
- private class DataSegmentForwardReference {
+ }
+
+ // inner-inner class to hold each entry of the forward reference list.
+ private class DataSegmentForwardReference
+ {
int patchAddress;
+
int length;
+
Token token;
-
- DataSegmentForwardReference(int patchAddress, int length, Token token) {
- this.patchAddress = patchAddress;
- this.length = length;
- this.token = token;
+
+ DataSegmentForwardReference(int patchAddress, int length, Token token)
+ {
+ this.patchAddress = patchAddress;
+ this.length = length;
+ this.token = token;
}
- }
-
- }
- }
+ }
+
+ }
+}
diff --git a/src/main/java/mars/assembler/DataTypes.java b/src/main/java/mars/assembler/DataTypes.java
index 175e393..6937b69 100644
--- a/src/main/java/mars/assembler/DataTypes.java
+++ b/src/main/java/mars/assembler/DataTypes.java
@@ -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 231-1 **/
- public static final int MAX_WORD_VALUE = Integer.MAX_VALUE;
-/** Lowest value that can be stored in a MIPS word is -231 **/
- public static final int MIN_WORD_VALUE = Integer.MIN_VALUE;
-/** Maximum value that can be stored in a MIPS halfword is 215-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 -215 **/
- 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 216-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 27-1 **/
- public static final int MAX_BYTE_VALUE = Byte.MAX_VALUE;
-/** Lowest value that can be stored in a MIPS byte is -27 **/
- 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 true if value can be stored in the number of bytes allowed
- * by the given directive (.word, .half, .byte), false 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 true if value is within range of
- * the given directive (.float, .double), false 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 231-1 **/
+ public static final int MAX_WORD_VALUE = Integer.MAX_VALUE;
+
+ /** Lowest value that can be stored in a MIPS word is -231 **/
+ public static final int MIN_WORD_VALUE = Integer.MIN_VALUE;
+
+ /** Maximum value that can be stored in a MIPS halfword is 215-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 -215 **/
+ 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 216-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 27-1 **/
+ public static final int MAX_BYTE_VALUE = Byte.MAX_VALUE;
+
+ /** Lowest value that can be stored in a MIPS byte is -27 **/
+ 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 true if value can be stored in the number of bytes allowed by the given directive
+ * (.word, .half, .byte), false 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 true if value is within range of the given directive (.float, .double), false
+ * otherwise.
+ **/
+ public static boolean outOfRange(Directives direct, double value)
+ {
+ return direct == Directives.FLOAT && (value < LOW_FLOAT_VALUE || value > MAX_FLOAT_VALUE);
+ }
}
diff --git a/src/main/java/mars/assembler/Directives.java b/src/main/java/mars/assembler/Directives.java
index cc025ac..4817d86 100644
--- a/src/main/java/mars/assembler/Directives.java
+++ b/src/main/java/mars/assembler/Directives.java
@@ -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 null.
- **/
-
- public static Directives matchDirective(String str) {
- Directives match;
- for (int i=0; inull.
+ **/
+
+ 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 null.
- **/
-
- public static ArrayList prefixMatchDirectives(String str) {
- ArrayList matches = null;
- for (int i=0; inull.
+ **/
+
+ 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;
- }
-
- }
\ No newline at end of file
+ }
+ 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;
+ }
+
+}
diff --git a/src/main/java/mars/assembler/Macro.java b/src/main/java/mars/assembler/Macro.java
index 8ae418d..7565d15 100644
--- a/src/main/java/mars/assembler/Macro.java
+++ b/src/main/java/mars/assembler/Macro.java
@@ -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
*/
-public class Macro {
- private String name;
- private MIPSprogram program;
- private ArrayList 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 %arg will be substituted by macro expansion
- */
- private ArrayList args;
+ private MIPSprogram program;
- public Macro() {
- name = "";
- program = null;
- fromLine = toLine = 0;
- origFromLine = origToLine = 0;
- args = new ArrayList();
- labels = new ArrayList();
- }
+ private final ArrayList 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 %arg will be substituted by macro expansion
+ */
+ private ArrayList args;
- public void setProgram(MIPSprogram program) {
- this.program = program;
- }
+ public Macro()
+ {
+ name = "";
+ program = null;
+ fromLine = toLine = 0;
+ origFromLine = origToLine = 0;
+ args = new ArrayList();
+ labels = new ArrayList();
+ }
- 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 getArgs() {
- return args;
- }
-
- public void setArgs(ArrayList 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.
- * Also appends "_M#" to all labels defined inside macro body where # is value of counter
- *
- * @param line
- * source line number in macro definition to be substituted
- * @param args
- * @param counter
- * unique macro expansion id
- * @param errors
- * @return line-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 tokenValue 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 value 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 tokenToBeReplaced which is occured in source with substitute.
- * @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 tokenValue 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 getArgs()
+ {
+ return args;
+ }
+
+ public void setArgs(ArrayList 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.
+ *
Also appends "_M#" to all labels defined inside macro body where # is value of counter
+ *
+ * @param line source line number in macro definition to be substituted
+ * @param args
+ * @param counter unique macro expansion id
+ * @param errors
+ * @return line-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 value 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 tokenToBeReplaced which is occured in source with
+ * substitute.
+ *
+ * @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);
+ }
}
diff --git a/src/main/java/mars/assembler/MacroPool.java b/src/main/java/mars/assembler/MacroPool.java
index a963990..db1cd62 100644
--- a/src/main/java/mars/assembler/MacroPool.java
+++ b/src/main/java/mars/assembler/MacroPool.java
@@ -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.
- * Will be used in first pass of assembling MIPS source code. When reached
+ * Stores information of macros defined by now.
Will be used in first pass of assembling MIPS source code. When
+ * reached
* .macro directive, parser calls
- * {@link MacroPool#BeginMacro(String, int)} and skips source code lines until
- * reaches .end_macro directive. then calls
- * {@link MacroPool#CommitMacro(int)} and the macro information stored in a
- * {@link Macro} instance will be added to {@link #macroList}.
- * Each {@link MIPSprogram} will have one {@link MacroPool}
- * 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 .end_macro
+ * directive. then calls {@link MacroPool#CommitMacro(int)} and the macro information stored in a {@link Macro} instance
+ * will be added to {@link #macroList}.
Each {@link MIPSprogram} will have one {@link MacroPool}
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
*/
- public class MacroPool {
- private MIPSprogram program;
- /**
- * List of macros defined by now
- */
- private ArrayList macroList;
- /**
- * @see #BeginMacro(String, int)
- */
- private Macro current;
- private ArrayList callStack;
- private ArrayList 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();
- callStack=new ArrayList();
- callStackOrigLines=new ArrayList();
- current = null;
- counter = 0;
- }
-
- /**
- * This method will be called by parser when reached .macro
- * directive.
- * 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 .macro 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 .end_macro
- * directive.
- * Adds/Replaces {@link #current} macro into the {@link #macroList}.
- *
- * @param endToken
- * Token containing .end_macro 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 macroList;
+
+ /**
+ * @see #BeginMacro(String, int)
+ */
+ private Macro current;
+
+ private final ArrayList callStack;
+
+ private final ArrayList 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();
+ callStack = new ArrayList();
+ callStackOrigLines = new ArrayList();
+ current = null;
+ counter = 0;
+ }
+
+ /**
+ * This method will be called by parser when reached .macro directive.
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 .macro 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 .end_macro directive.
Adds/Replaces
+ * {@link #current} macro into the {@link #macroList}.
+ *
+ * @param endToken Token containing .end_macro 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 value
- * 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 value 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 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 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; i0)
- 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;
+ }
+}
diff --git a/src/main/java/mars/assembler/OperandFormat.java b/src/main/java/mars/assembler/OperandFormat.java
index 0965edc..f74c3eb 100644
--- a/src/main/java/mars/assembler/OperandFormat.java
+++ b/src/main/java/mars/assembler/OperandFormat.java
@@ -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 true if the programmer's statement matches the MIPS
- * specification, else returns false.
- */
-
- 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 true if the programmer's statement matches the MIPS
+ * specification, else returns false.
+ */
+
+ 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=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; ipos is < 0 or >= size()
- */
- 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 pos is < 0 or >= size()
+ */
+ public void remove(int pos)
+ {
tokenList.remove(pos);
}
- /**
- * Returns empty/non-empty status of list.
- *
- * @return true if list has no tokens, else false.
- */
- public boolean isEmpty() {
+ /**
+ * Returns empty/non-empty status of list.
+ *
+ * @return true if list has no tokens, else false.
+ */
+ 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; inull.
- **/
-
- 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 null.
+ **/
+
+ 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;
+ }
+
+}
diff --git a/src/main/java/mars/assembler/Tokenizer.java b/src/main/java/mars/assembler/Tokenizer.java
index 7186f8d..b4f757c 100644
--- a/src/main/java/mars/assembler/Tokenizer.java
+++ b/src/main/java/mars/assembler/Tokenizer.java
@@ -1,7 +1,11 @@
- package mars.assembler;
- import mars.*;
- import java.util.*;
- import java.io.*;
+package mars.assembler;
+
+import mars.*;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
/*
Copyright (c) 2003-2013, Pete Sanderson and Kenneth Vollmar
@@ -32,546 +36,612 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
- * A tokenizer is capable of tokenizing a complete MIPS program, or a given line from
- * a MIPS program. Since MIPS is line-oriented, each line defines a complete statement.
- * Tokenizing is the process of analyzing the input MIPS program for the purpose of
- * recognizing each MIPS language element. The types of language elements are known as "tokens".
- * MIPS tokens are defined in the TokenTypes class.
- * Example:
- * The MIPS statement here: lw $t3, 8($t4) #load third member of array
- * generates the following token list
- * IDENTIFIER, COLON, OPERATOR, REGISTER_NAME, COMMA, INTEGER_5, LEFT_PAREN,
- * REGISTER_NAME, RIGHT_PAREN, COMMENT
- *
+ * A tokenizer is capable of tokenizing a complete MIPS program, or a given line from a MIPS program. Since MIPS is
+ * line-oriented, each line defines a complete statement. Tokenizing is the process of analyzing the input MIPS program
+ * for the purpose of recognizing each MIPS language element. The types of language elements are known as "tokens".
+ * MIPS tokens are defined in the TokenTypes class.
Example:
The MIPS statement here: lw $t3, 8($t4)
+ * #load third member of array
generates the following token list
IDENTIFIER, COLON, OPERATOR,
+ * REGISTER_NAME, COMMA, INTEGER_5, LEFT_PAREN, REGISTER_NAME, RIGHT_PAREN, COMMENT
+ *
* @author Pete Sanderson
* @version August 2003
**/
- public class Tokenizer {
-
- private ErrorList errors;
- private MIPSprogram sourceMIPSprogram;
- private HashMap equivalents; // DPS 11-July-2012
- // The 8 escaped characters are: single quote, double quote, backslash, newline (linefeed),
- // tab, backspace, return, form feed. The characters and their corresponding decimal codes:
- private static final String escapedCharacters = "'\"\\ntbrf0";
- private static final String[] escapedCharactersValues = {"39","34","92","10","9","8","13","12","0"};
-
- /**
- * Simple constructor. Initializes empty error list.
- */
-
- public Tokenizer() {
- this(null);
- }
-
- /**
- * Constructor for use with existing MIPSprogram. Designed to be used with Macro feature.
- * @param program A previously-existing MIPSprogram object or null if none.
- */
- public Tokenizer(MIPSprogram program){
- errors = new ErrorList();
- sourceMIPSprogram = program;
- }
-
- /**
- * Will tokenize a complete MIPS program. MIPS is line oriented (not free format),
- * so we will be line-oriented too.
- *
- * @param p The MIPSprogram to be tokenized.
- * @return An ArrayList representing the tokenized program. Each list member is a TokenList
- * that represents a tokenized source statement from the MIPS program.
- **/
-
- public ArrayList tokenize(MIPSprogram p) throws ProcessingException {
- sourceMIPSprogram = p;
- equivalents = new HashMap(); // DPS 11-July-2012
- ArrayList tokenList = new ArrayList();
- //ArrayList source = p.getSourceList();
- ArrayList source = processIncludes(p, new HashMap()); // DPS 9-Jan-2013
- p.setSourceLineList(source);
- TokenList currentLineTokens;
- String sourceLine;
- for (int i=0; i equivalents; // DPS 11-July-2012
+
+ /**
+ * Simple constructor. Initializes empty error list.
+ */
+
+ public Tokenizer()
+ {
+ this(null);
+ }
+
+ /**
+ * Constructor for use with existing MIPSprogram. Designed to be used with Macro feature.
+ *
+ * @param program A previously-existing MIPSprogram object or null if none.
+ */
+ public Tokenizer(MIPSprogram program)
+ {
+ errors = new ErrorList();
+ sourceMIPSprogram = program;
+ }
+
+ /**
+ * Will tokenize a complete MIPS program. MIPS is line oriented (not free format), so we will be line-oriented
+ * too.
+ *
+ * @param p The MIPSprogram to be tokenized.
+ * @return An ArrayList representing the tokenized program. Each list member is a TokenList that represents a
+ * tokenized source statement from the MIPS program.
+ **/
+
+ public ArrayList tokenize(MIPSprogram p) throws ProcessingException
+ {
+ sourceMIPSprogram = p;
+ equivalents = new HashMap(); // DPS 11-July-2012
+ ArrayList tokenList = new ArrayList();
+ //ArrayList source = p.getSourceList();
+ ArrayList source = processIncludes(p, new HashMap()); // DPS 9-Jan-2013
+ p.setSourceLineList(source);
+ TokenList currentLineTokens;
+ String sourceLine;
+ for (int i = 0; i < source.size(); i++)
+ {
+ sourceLine = source.get(i).getSource();
+ currentLineTokens = this.tokenizeLine(i + 1, sourceLine);
+ tokenList.add(currentLineTokens);
// DPS 03-Jan-2013. Related to 11-July-2012. If source code substitution was made
- // based on .eqv directive during tokenizing, the processed line, a String, is
- // not the same object as the original line. Thus I can use != instead of !equals()
- // This IF statement will replace original source with source modified by .eqv substitution.
- // Not needed by assembler, but looks better in the Text Segment Display.
- if (sourceLine.length() > 0 && sourceLine != currentLineTokens.getProcessedLine()) {
- source.set(i,new SourceLine(currentLineTokens.getProcessedLine(),source.get(i).getMIPSprogram(), source.get(i).getLineNumber()));
- }
- }
- if (errors.errorsOccurred()) {
+ // based on .eqv directive during tokenizing, the processed line, a String, is
+ // not the same object as the original line. Thus I can use != instead of !equals()
+ // This IF statement will replace original source with source modified by .eqv substitution.
+ // Not needed by assembler, but looks better in the Text Segment Display.
+ if (sourceLine.length() > 0 && sourceLine != currentLineTokens.getProcessedLine())
+ {
+ source.set(i, new SourceLine(currentLineTokens.getProcessedLine(), source.get(i).getMIPSprogram(), source.get(i).getLineNumber()));
+ }
+ }
+ if (errors.errorsOccurred())
+ {
throw new ProcessingException(errors);
- }
- return tokenList;
- }
-
-
-
- // pre-pre-processing pass through source code to process any ".include" directives.
- // When one is encountered, the contents of the included file are inserted at that
- // point. If no .include statements, the return value is a new array list but
- // with the same lines of source code. Uses recursion to correctly process included
- // files that themselves have .include. Plus it will detect and report recursive
- // includes both direct and indirect.
- // DPS 11-Jan-2013
- private ArrayList processIncludes(MIPSprogram program, Map inclFiles) throws ProcessingException {
- ArrayList source = program.getSourceList();
- ArrayList result = new ArrayList(source.size());
- for (int i=0; i processIncludes(MIPSprogram program, Map inclFiles) throws ProcessingException
+ {
+ ArrayList source = program.getSourceList();
+ ArrayList result = new ArrayList(source.size());
+ for (int i = 0; i < source.size(); i++)
+ {
String line = (String) source.get(i);
- TokenList tl = tokenizeLine(program, i+1, line, false);
+ TokenList tl = tokenizeLine(program, i + 1, line, false);
boolean hasInclude = false;
- for (int ii=0; ii ii+1)
- && tl.get(ii+1).getType() == TokenTypes.QUOTED_STRING) {
- String filename = tl.get(ii+1).getValue();
- filename = filename.substring(1, filename.length()-1); // get rid of quotes
- // Handle either absolute or relative pathname for .include file
- if (!new File(filename).isAbsolute()) {
- filename = new File(program.getFilename()).getParent()+File.separator+filename;
- }
- if (inclFiles.containsKey(filename)) {
- // This is a recursive include. Generate error message and return immediately.
- Token t = tl.get(ii+1);
- errors.add(new ErrorMessage(program, t.getSourceLine(),t.getStartPos(),
- "Recursive include of file "+filename));
- throw new ProcessingException(errors);
- }
- inclFiles.put(filename, filename);
- MIPSprogram incl = new MIPSprogram();
- try {
- incl.readSource(filename);
- }
- catch (ProcessingException p) {
- Token t = tl.get(ii+1);
- errors.add(new ErrorMessage(program, t.getSourceLine(),t.getStartPos(),
- "Error reading include file "+filename));
+ for (int ii = 0; ii < tl.size(); ii++)
+ {
+ if (tl.get(ii).getValue().equalsIgnoreCase(Directives.INCLUDE.getName())
+ && (tl.size() > ii + 1)
+ && tl.get(ii + 1).getType() == TokenTypes.QUOTED_STRING)
+ {
+ String filename = tl.get(ii + 1).getValue();
+ filename = filename.substring(1, filename.length() - 1); // get rid of quotes
+ // Handle either absolute or relative pathname for .include file
+ if (!new File(filename).isAbsolute())
+ {
+ filename = new File(program.getFilename()).getParent() + File.separator + filename;
+ }
+ if (inclFiles.containsKey(filename))
+ {
+ // This is a recursive include. Generate error message and return immediately.
+ Token t = tl.get(ii + 1);
+ errors.add(new ErrorMessage(program, t.getSourceLine(), t.getStartPos(),
+ "Recursive include of file " + filename));
throw new ProcessingException(errors);
- }
- ArrayList allLines = processIncludes(incl, inclFiles);
- result.addAll(allLines);
- hasInclude = true;
- break;
- }
+ }
+ inclFiles.put(filename, filename);
+ MIPSprogram incl = new MIPSprogram();
+ try
+ {
+ incl.readSource(filename);
+ }
+ catch (ProcessingException p)
+ {
+ Token t = tl.get(ii + 1);
+ errors.add(new ErrorMessage(program, t.getSourceLine(), t.getStartPos(),
+ "Error reading include file " + filename));
+ throw new ProcessingException(errors);
+ }
+ ArrayList allLines = processIncludes(incl, inclFiles);
+ result.addAll(allLines);
+ hasInclude = true;
+ break;
+ }
}
- if (!hasInclude){
- result.add(new SourceLine(line, program, i+1));//line);
+ if (!hasInclude)
+ {
+ result.add(new SourceLine(line, program, i + 1));//line);
}
- }
- return result;
- }
-
- /**
- * Used only to create a token list for the example provided with each instruction
- * specification.
- *
- * @param example The example MIPS instruction to be tokenized.
- *
- * @return An TokenList representing the tokenized instruction. Each list member is a Token
- * that represents one language element.
- *
- * @throws ProcessingException This occurs only if the instruction specification itself
- * contains one or more lexical (i.e. token) errors.
- **/
-
- public TokenList tokenizeExampleInstruction(String example) throws ProcessingException {
- TokenList result = new TokenList();
- result = tokenizeLine(sourceMIPSprogram, 0, example, false);
- if (errors.errorsOccurred()) {
+ }
+ return result;
+ }
+
+ /**
+ * Used only to create a token list for the example provided with each instruction specification.
+ *
+ * @param example The example MIPS instruction to be tokenized.
+ * @return An TokenList representing the tokenized instruction. Each list member is a Token that represents one
+ * language element.
+ * @throws ProcessingException This occurs only if the instruction specification itself contains one or more
+ * lexical (i.e. token) errors.
+ **/
+
+ public TokenList tokenizeExampleInstruction(String example) throws ProcessingException
+ {
+ TokenList result = new TokenList();
+ result = tokenizeLine(sourceMIPSprogram, 0, example, false);
+ if (errors.errorsOccurred())
+ {
throw new ProcessingException(errors);
- }
- return result;
- }
-
-
- /**
- * Will tokenize one line of source code. If lexical errors are discovered,
- * they are noted in an ErrorMessage object which is added to the ErrorList.
- * Will NOT throw an exception yet because we want to persevere beyond first error.
- *
- * @param lineNum line number from source code (used in error message)
- * @param theLine String containing source code
- * @return the generated token list for that line
- *
- **/
+ }
+ return result;
+ }
+
+
+ /**
+ * Will tokenize one line of source code. If lexical errors are discovered, they are noted in an ErrorMessage
+ * object which is added to the ErrorList. Will NOT throw an exception yet because we want to persevere beyond first
+ * error.
+ *
+ * @param lineNum line number from source code (used in error message)
+ * @param theLine String containing source code
+ * @return the generated token list for that line
+ **/
/*
- *
- * Tokenizing is not as easy as it appears at first blush, because the typical
- * delimiters: space, tab, comma, can all appear inside MIPS quoted ASCII strings!
- * Also, spaces are not as necessary as they seem, the following line is accepted
- * and parsed correctly by SPIM: label:lw,$t4,simple#comment
- * as is this weird variation: label :lw $t4 ,simple , , , # comment
- *
- * as is this line: stuff:.asciiz"# ,\n\"","aaaaa" (interestingly, if you put
- * additional characters after the \", they are ignored!!)
- *
- * I also would like to know the starting character position in the line of each
- * token, for error reporting purposes. StringTokenizer cannot give you this.
- *
- * Given all the above, it is just as easy to "roll my own" as to use StringTokenizer
- */
-
- // Modified for release 4.3, to preserve existing API.
- public TokenList tokenizeLine(int lineNum, String theLine) {
- return tokenizeLine(sourceMIPSprogram, lineNum, theLine, true);
- }
+ *
+ * Tokenizing is not as easy as it appears at first blush, because the typical
+ * delimiters: space, tab, comma, can all appear inside MIPS quoted ASCII strings!
+ * Also, spaces are not as necessary as they seem, the following line is accepted
+ * and parsed correctly by SPIM: label:lw,$t4,simple#comment
+ * as is this weird variation: label :lw $t4 ,simple , , , # comment
+ *
+ * as is this line: stuff:.asciiz"# ,\n\"","aaaaa" (interestingly, if you put
+ * additional characters after the \", they are ignored!!)
+ *
+ * I also would like to know the starting character position in the line of each
+ * token, for error reporting purposes. StringTokenizer cannot give you this.
+ *
+ * Given all the above, it is just as easy to "roll my own" as to use StringTokenizer
+ */
- /**
- * Will tokenize one line of source code. If lexical errors are discovered,
- * they are noted in an ErrorMessage object which is added to the provided ErrorList
- * instead of the Tokenizer's error list. Will NOT throw an exception.
- *
- * @param lineNum line number from source code (used in error message)
- * @param theLine String containing source code
- * @param callerErrorList errors will go into this list instead of tokenizer's list.
- * @return the generated token list for that line
- *
- **/
- public TokenList tokenizeLine(int lineNum, String theLine, ErrorList callerErrorList) {
- ErrorList saveList = this.errors;
- this.errors = callerErrorList;
- TokenList tokens = this.tokenizeLine(lineNum, theLine);
- this.errors = saveList;
- return tokens;
- }
+ // Modified for release 4.3, to preserve existing API.
+ public TokenList tokenizeLine(int lineNum, String theLine)
+ {
+ return tokenizeLine(sourceMIPSprogram, lineNum, theLine, true);
+ }
+
+ /**
+ * Will tokenize one line of source code. If lexical errors are discovered, they are noted in an ErrorMessage
+ * object which is added to the provided ErrorList instead of the Tokenizer's error list. Will NOT throw an
+ * exception.
+ *
+ * @param lineNum line number from source code (used in error message)
+ * @param theLine String containing source code
+ * @param callerErrorList errors will go into this list instead of tokenizer's list.
+ * @return the generated token list for that line
+ **/
+ public TokenList tokenizeLine(int lineNum, String theLine, ErrorList callerErrorList)
+ {
+ ErrorList saveList = this.errors;
+ this.errors = callerErrorList;
+ TokenList tokens = this.tokenizeLine(lineNum, theLine);
+ this.errors = saveList;
+ return tokens;
+ }
- /**
- * Will tokenize one line of source code. If lexical errors are discovered,
- * they are noted in an ErrorMessage object which is added to the provided ErrorList
- * instead of the Tokenizer's error list. Will NOT throw an exception.
- *
- * @param lineNum line number from source code (used in error message)
- * @param theLine String containing source code
- * @param callerErrorList errors will go into this list instead of tokenizer's list.
- * @param doEqvSubstitutse boolean param set true to perform .eqv substitutions, else false
- * @return the generated token list for that line
- *
- **/
- public TokenList tokenizeLine(int lineNum, String theLine, ErrorList callerErrorList, boolean doEqvSubstitutes) {
- ErrorList saveList = this.errors;
- this.errors = callerErrorList;
- TokenList tokens = this.tokenizeLine(sourceMIPSprogram, lineNum, theLine,doEqvSubstitutes);
- this.errors = saveList;
- return tokens;
- }
+ /**
+ * Will tokenize one line of source code. If lexical errors are discovered, they are noted in an ErrorMessage
+ * object which is added to the provided ErrorList instead of the Tokenizer's error list. Will NOT throw an
+ * exception.
+ *
+ * @param lineNum line number from source code (used in error message)
+ * @param theLine String containing source code
+ * @param callerErrorList errors will go into this list instead of tokenizer's list.
+ * @param doEqvSubstitutse boolean param set true to perform .eqv substitutions, else false
+ * @return the generated token list for that line
+ **/
+ public TokenList tokenizeLine(int lineNum, String theLine, ErrorList callerErrorList, boolean doEqvSubstitutes)
+ {
+ ErrorList saveList = this.errors;
+ this.errors = callerErrorList;
+ TokenList tokens = this.tokenizeLine(sourceMIPSprogram, lineNum, theLine, doEqvSubstitutes);
+ this.errors = saveList;
+ return tokens;
+ }
- /**
- * Will tokenize one line of source code. If lexical errors are discovered,
- * they are noted in an ErrorMessage object which is added to the provided ErrorList
- * instead of the Tokenizer's error list. Will NOT throw an exception.
- *
- * @param program MIPSprogram containing this line of source
- * @param lineNum line number from source code (used in error message)
- * @param theLine String containing source code
- * @param doEqvSubstitutes boolean param set true to perform .eqv substitutions, else false
- * @return the generated token list for that line
- *
- **/
- public TokenList tokenizeLine(MIPSprogram program, int lineNum, String theLine, boolean doEqvSubstitutes) {
- TokenTypes tokenType;
- TokenList result = new TokenList();
- if (theLine.length() == 0)
+ /**
+ * Will tokenize one line of source code. If lexical errors are discovered, they are noted in an ErrorMessage
+ * object which is added to the provided ErrorList instead of the Tokenizer's error list. Will NOT throw an
+ * exception.
+ *
+ * @param program MIPSprogram containing this line of source
+ * @param lineNum line number from source code (used in error message)
+ * @param theLine String containing source code
+ * @param doEqvSubstitutes boolean param set true to perform .eqv substitutions, else false
+ * @return the generated token list for that line
+ **/
+ public TokenList tokenizeLine(MIPSprogram program, int lineNum, String theLine, boolean doEqvSubstitutes)
+ {
+ TokenTypes tokenType;
+ TokenList result = new TokenList();
+ if (theLine.length() == 0)
+ {
return result;
- // will be faster to work with char arrays instead of strings
- char c;
- char[] line = theLine.toCharArray();
- int linePos = 0;
- char[] token = new char[line.length];
- int tokenPos = 0;
- int tokenStartPos = 1;
- boolean insideQuotedString = false;
- if (Globals.debug)
- System.out.println("source line --->"+theLine+"<---");
- // Each iteration of this loop processes one character in the source line.
- while (linePos < line.length) {
+ }
+ // will be faster to work with char arrays instead of strings
+ char c;
+ char[] line = theLine.toCharArray();
+ int linePos = 0;
+ char[] token = new char[line.length];
+ int tokenPos = 0;
+ int tokenStartPos = 1;
+ boolean insideQuotedString = false;
+ if (Globals.debug)
+ {
+ System.out.println("source line --->" + theLine + "<---");
+ }
+ // Each iteration of this loop processes one character in the source line.
+ while (linePos < line.length)
+ {
c = line[linePos];
- if (insideQuotedString) { // everything goes into token
- token[tokenPos++] = c;
- if (c == '"' && token[tokenPos-2] != '\\') { // If quote not preceded by backslash, this is end
- this.processCandidateToken(token, program, lineNum, theLine, tokenPos, tokenStartPos, result);
- tokenPos = 0;
- insideQuotedString = false;
- }
- }
- else { // not inside a quoted string, so be sensitive to delimiters
- switch(c) {
- case '#' : // # denotes comment that takes remainder of line
- if (tokenPos > 0) {
+ if (insideQuotedString)
+ { // everything goes into token
+ token[tokenPos++] = c;
+ if (c == '"' && token[tokenPos - 2] != '\\')
+ { // If quote not preceded by backslash, this is end
+ this.processCandidateToken(token, program, lineNum, theLine, tokenPos, tokenStartPos, result);
+ tokenPos = 0;
+ insideQuotedString = false;
+ }
+ }
+ else
+ { // not inside a quoted string, so be sensitive to delimiters
+ switch (c)
+ {
+ case '#': // # denotes comment that takes remainder of line
+ if (tokenPos > 0)
+ {
+ this.processCandidateToken(token, program, lineNum, theLine, tokenPos, tokenStartPos, result);
+ tokenPos = 0;
+ }
+ tokenStartPos = linePos + 1;
+ tokenPos = line.length - linePos;
+ System.arraycopy(line, linePos, token, 0, tokenPos);
+ this.processCandidateToken(token, program, lineNum, theLine, tokenPos, tokenStartPos, result);
+ linePos = line.length;
+ tokenPos = 0;
+ break;
+ case ' ':
+ case '\t':
+ case ',': // space, tab or comma is delimiter
+ if (tokenPos > 0)
+ {
+ this.processCandidateToken(token, program, lineNum, theLine, tokenPos, tokenStartPos, result);
+ tokenPos = 0;
+ }
+ break;
+ // These two guys are special. Will be recognized as unary if and only if two conditions hold:
+ // 1. Immediately followed by a digit (will use look-ahead for this).
+ // 2. Previous token, if any, is _not_ an IDENTIFIER
+ // Otherwise considered binary and thus a separate token. This is a slight hack but reasonable.
+ case '+':
+ case '-':
+ // Here's the REAL hack: recognizing signed exponent in E-notation floating point!
+ // (e.g. 1.2e-5) Add the + or - to the token and keep going. DPS 17 Aug 2005
+ if (tokenPos > 0 && line.length >= linePos + 2 && Character.isDigit(line[linePos + 1]) &&
+ (line[linePos - 1] == 'e' || line[linePos - 1] == 'E'))
+ {
+ token[tokenPos++] = c;
+ break;
+ }
+ // End of REAL hack.
+ if (tokenPos > 0)
+ {
+ this.processCandidateToken(token, program, lineNum, theLine, tokenPos, tokenStartPos, result);
+ tokenPos = 0;
+ }
+ tokenStartPos = linePos + 1;
+ token[tokenPos++] = c;
+ if (!((result.isEmpty() || result.get(result.size() - 1).getType() != TokenTypes.IDENTIFIER) &&
+ (line.length >= linePos + 2 && Character.isDigit(line[linePos + 1]))))
+ {
+ // treat it as binary.....
+ this.processCandidateToken(token, program, lineNum, theLine, tokenPos, tokenStartPos, result);
+ tokenPos = 0;
+ }
+ break;
+ // these are other single-character tokens
+ case ':':
+ case '(':
+ case ')':
+ if (tokenPos > 0)
+ {
+ this.processCandidateToken(token, program, lineNum, theLine, tokenPos, tokenStartPos, result);
+ tokenPos = 0;
+ }
+ tokenStartPos = linePos + 1;
+ token[tokenPos++] = c;
this.processCandidateToken(token, program, lineNum, theLine, tokenPos, tokenStartPos, result);
tokenPos = 0;
- }
- tokenStartPos = linePos+1;
- tokenPos = line.length-linePos;
- System.arraycopy(line, linePos, token, 0, tokenPos);
- this.processCandidateToken(token, program, lineNum, theLine, tokenPos, tokenStartPos, result);
- linePos = line.length;
- tokenPos = 0;
- break;
- case ' ' :
- case '\t':
- case ',' : // space, tab or comma is delimiter
- if (tokenPos > 0) {
+ break;
+ case '"': // we're not inside a quoted string, so start a new token...
+ if (tokenPos > 0)
+ {
+ this.processCandidateToken(token, program, lineNum, theLine, tokenPos, tokenStartPos, result);
+ tokenPos = 0;
+ }
+ tokenStartPos = linePos + 1;
+ token[tokenPos++] = c;
+ insideQuotedString = true;
+ break;
+ case '\'': // start of character constant (single quote).
+ if (tokenPos > 0)
+ {
+ this.processCandidateToken(token, program, lineNum, theLine, tokenPos, tokenStartPos, result);
+ tokenPos = 0;
+ }
+ // Our strategy is to process the whole thing right now...
+ tokenStartPos = linePos + 1;
+ token[tokenPos++] = c; // Put the quote in token[0]
+ int lookaheadChars = line.length - linePos - 1;
+ // need minimum 2 more characters, 1 for char and 1 for ending quote
+ if (lookaheadChars < 2)
+ {
+ break; // gonna be an error
+ }
+ c = line[++linePos];
+ token[tokenPos++] = c; // grab second character, put it in token[1]
+ if (c == '\'')
+ {
+ break; // gonna be an error: nothing between the quotes
+ }
+ c = line[++linePos];
+ token[tokenPos++] = c; // grab third character, put it in token[2]
+ // Process if we've either reached second, non-escaped, quote or end of line.
+ if (c == '\'' && token[1] != '\\' || lookaheadChars == 2)
+ {
+ this.processCandidateToken(token, program, lineNum, theLine, tokenPos, tokenStartPos, result);
+ tokenPos = 0;
+ tokenStartPos = linePos + 1;
+ break;
+ }
+ // At this point, there is at least one more character on this line. If we're
+ // still here after seeing a second quote, it was escaped. Not done yet;
+ // we either have an escape code, an octal code (also escaped) or invalid.
+ c = line[++linePos];
+ token[tokenPos++] = c; // grab fourth character, put it in token[3]
+ // Process, if this is ending quote for escaped character or if at end of line
+ if (c == '\'' || lookaheadChars == 3)
+ {
+ this.processCandidateToken(token, program, lineNum, theLine, tokenPos, tokenStartPos, result);
+ tokenPos = 0;
+ tokenStartPos = linePos + 1;
+ break;
+ }
+ // At this point, we've handled all legal possibilities except octal, e.g. '\377'
+ // Proceed, if enough characters remain to finish off octal.
+ if (lookaheadChars >= 5)
+ {
+ c = line[++linePos];
+ token[tokenPos++] = c; // grab fifth character, put it in token[4]
+ if (c != '\'')
+ {
+ // still haven't reached end, last chance for validity!
+ c = line[++linePos];
+ token[tokenPos++] = c; // grab sixth character, put it in token[5]
+ }
+ }
+ // process no matter what...we either have a valid character by now or not
this.processCandidateToken(token, program, lineNum, theLine, tokenPos, tokenStartPos, result);
tokenPos = 0;
- }
- break;
- // These two guys are special. Will be recognized as unary if and only if two conditions hold:
- // 1. Immediately followed by a digit (will use look-ahead for this).
- // 2. Previous token, if any, is _not_ an IDENTIFIER
- // Otherwise considered binary and thus a separate token. This is a slight hack but reasonable.
- case '+' :
- case '-' :
- // Here's the REAL hack: recognizing signed exponent in E-notation floating point!
- // (e.g. 1.2e-5) Add the + or - to the token and keep going. DPS 17 Aug 2005
- if (tokenPos > 0 && line.length >= linePos+2 && Character.isDigit(line[linePos+1]) &&
- (line[linePos-1]=='e' || line[linePos-1]=='E')) {
+ tokenStartPos = linePos + 1;
+ break;
+ default:
+ if (tokenPos == 0)
+ {
+ tokenStartPos = linePos + 1;
+ }
token[tokenPos++] = c;
break;
- }
- // End of REAL hack.
- if (tokenPos > 0) {
- this.processCandidateToken(token, program, lineNum, theLine, tokenPos, tokenStartPos, result);
- tokenPos = 0;
- }
- tokenStartPos = linePos+1;
- token[tokenPos++] = c;
- if ( !((result.isEmpty() || ((Token)result.get(result.size()-1)).getType() != TokenTypes.IDENTIFIER) &&
- (line.length >= linePos+2 && Character.isDigit(line[linePos+1]))) ) {
- // treat it as binary.....
- this.processCandidateToken(token, program, lineNum, theLine, tokenPos, tokenStartPos, result);
- tokenPos = 0;
- }
- break;
- // these are other single-character tokens
- case ':' :
- case '(' :
- case ')' :
- if (tokenPos > 0) {
- this.processCandidateToken(token, program, lineNum, theLine, tokenPos, tokenStartPos, result);
- tokenPos = 0;
- }
- tokenStartPos = linePos+1;
- token[tokenPos++] = c;
- this.processCandidateToken(token, program, lineNum, theLine, tokenPos, tokenStartPos, result);
- tokenPos = 0;
- break;
- case '"' : // we're not inside a quoted string, so start a new token...
- if (tokenPos > 0) {
- this.processCandidateToken(token, program, lineNum, theLine, tokenPos, tokenStartPos, result);
- tokenPos = 0;
- }
- tokenStartPos = linePos+1;
- token[tokenPos++] = c;
- insideQuotedString = true;
- break;
- case '\'' : // start of character constant (single quote).
- if (tokenPos > 0) {
- this.processCandidateToken(token, program, lineNum, theLine, tokenPos, tokenStartPos, result);
- tokenPos = 0;
- }
- // Our strategy is to process the whole thing right now...
- tokenStartPos = linePos+1;
- token[tokenPos++] = c; // Put the quote in token[0]
- int lookaheadChars = line.length - linePos - 1;
- // need minimum 2 more characters, 1 for char and 1 for ending quote
- if (lookaheadChars < 2)
- break; // gonna be an error
- c = line[++linePos];
- token[tokenPos++] = c; // grab second character, put it in token[1]
- if (c == '\'')
- break; // gonna be an error: nothing between the quotes
- c = line[++linePos];
- token[tokenPos++] = c; // grab third character, put it in token[2]
- // Process if we've either reached second, non-escaped, quote or end of line.
- if (c == '\'' && token[1] != '\\' || lookaheadChars==2) {
- this.processCandidateToken(token, program, lineNum, theLine, tokenPos, tokenStartPos, result);
- tokenPos = 0;
- tokenStartPos = linePos+1;
- break;
- }
- // At this point, there is at least one more character on this line. If we're
- // still here after seeing a second quote, it was escaped. Not done yet;
- // we either have an escape code, an octal code (also escaped) or invalid.
- c = line[++linePos];
- token[tokenPos++] = c; // grab fourth character, put it in token[3]
- // Process, if this is ending quote for escaped character or if at end of line
- if (c == '\'' || lookaheadChars==3) {
- this.processCandidateToken(token, program, lineNum, theLine, tokenPos, tokenStartPos, result);
- tokenPos = 0;
- tokenStartPos = linePos+1;
- break;
- }
- // At this point, we've handled all legal possibilities except octal, e.g. '\377'
- // Proceed, if enough characters remain to finish off octal.
- if (lookaheadChars >= 5) {
- c = line[++linePos];
- token[tokenPos++] = c; // grab fifth character, put it in token[4]
- if (c != '\'') {
- // still haven't reached end, last chance for validity!
- c = line[++linePos];
- token[tokenPos++] = c; // grab sixth character, put it in token[5]
- }
- }
- // process no matter what...we either have a valid character by now or not
- this.processCandidateToken(token, program, lineNum, theLine, tokenPos, tokenStartPos, result);
- tokenPos = 0;
- tokenStartPos = linePos+1;
- break;
- default :
- if (tokenPos == 0)
- tokenStartPos = linePos+1;
- token[tokenPos++] = c;
- break;
- } // switch
+ } // switch
} // if (insideQuotedString)
linePos++;
- } // while
- if (tokenPos > 0) {
+ } // while
+ if (tokenPos > 0)
+ {
this.processCandidateToken(token, program, lineNum, theLine, tokenPos, tokenStartPos, result);
tokenPos = 0;
- }
- if (doEqvSubstitutes) {
+ }
+ if (doEqvSubstitutes)
+ {
result = processEqv(program, lineNum, theLine, result); // DPS 11-July-2012
- }
- return result;
- }
-
- // Process the .eqv directive, which needs to be applied prior to tokenizing of subsequent statements.
- // This handles detecting that theLine contains a .eqv directive, in which case it needs
- // to be added to the HashMap of equivalents. It also handles detecting that theLine
- // contains a symbol that was previously defined in an .eqv directive, in which case
- // the substitution needs to be made.
- // DPS 11-July-2012
- private TokenList processEqv(MIPSprogram program, int lineNum, String theLine, TokenList tokens) {
- // See if it is .eqv directive. If so, record it...
- // Have to assure it is a well-formed statement right now (can't wait for assembler).
-
- if (tokens.size()>2 && (tokens.get(0).getType() == TokenTypes.DIRECTIVE || tokens.get(2).getType() == TokenTypes.DIRECTIVE)) {
+ }
+ return result;
+ }
+
+ // Process the .eqv directive, which needs to be applied prior to tokenizing of subsequent statements.
+ // This handles detecting that theLine contains a .eqv directive, in which case it needs
+ // to be added to the HashMap of equivalents. It also handles detecting that theLine
+ // contains a symbol that was previously defined in an .eqv directive, in which case
+ // the substitution needs to be made.
+ // DPS 11-July-2012
+ private TokenList processEqv(MIPSprogram program, int lineNum, String theLine, TokenList tokens)
+ {
+ // See if it is .eqv directive. If so, record it...
+ // Have to assure it is a well-formed statement right now (can't wait for assembler).
+
+ if (tokens.size() > 2 && (tokens.get(0).getType() == TokenTypes.DIRECTIVE || tokens.get(2).getType() == TokenTypes.DIRECTIVE))
+ {
// There should not be a label but if there is, the directive is in token position 2 (ident, colon, directive).
- int dirPos = (tokens.get(0).getType() == TokenTypes.DIRECTIVE) ? 0 : 2;
- if (Directives.matchDirective(tokens.get(dirPos).getValue()) == Directives.EQV) {
- // Get position in token list of last non-comment token
- int tokenPosLastOperand = tokens.size() - ((tokens.get(tokens.size()-1).getType()==TokenTypes.COMMENT)? 2 : 1);
- // There have to be at least two non-comment tokens beyond the directive
- if (tokenPosLastOperand < dirPos+2) {
- errors.add(new ErrorMessage(program, lineNum,tokens.get(dirPos).getStartPos(),
- "Too few operands for "+Directives.EQV.getName()+" directive"));
- return tokens;
- }
- // Token following the directive has to be IDENTIFIER
- if (tokens.get(dirPos+1).getType() != TokenTypes.IDENTIFIER) {
- errors.add(new ErrorMessage(program, lineNum,tokens.get(dirPos).getStartPos(),
- "Malformed "+Directives.EQV.getName()+" directive"));
- return tokens;
- }
- String symbol = tokens.get(dirPos+1).getValue();
- // Make sure the symbol is not contained in the expression. Not likely to occur but if left
- // undetected it will result in infinite recursion. e.g. .eqv ONE, (ONE)
- for (int i=dirPos+2; i 0 && value.charAt(0)=='\'') value = preprocessCharacterLiteral(value);
- TokenTypes type = TokenTypes.matchTokenType(value);
- if (type == TokenTypes.ERROR) {
- errors.add(new ErrorMessage(program, line, tokenStartPos,
- theLine+"\nInvalid language element: "+value));
- }
- Token toke = new Token(type, value, program, line, tokenStartPos);
- tokenList.add(toke);
- return;
- }
-
-
-
- // If passed a candidate character literal, attempt to translate it into integer constant.
- // If the translation fails, return original value.
- private String preprocessCharacterLiteral(String value) {
- // must start and end with quote and have something in between
- if (value.length() < 3 || value.charAt(0) != '\'' || value.charAt(value.length()-1) != '\'') {
- return value;
- }
- String quotesRemoved = value.substring(1, value.length()-1);
- // if not escaped, then if one character left return its value else return original.
- if (quotesRemoved.charAt(0) != '\\') {
- return (quotesRemoved.length() == 1) ? Integer.toString((int)quotesRemoved.charAt(0)) : value;
- }
- // now we know it is escape sequence and have to decode which of the 8: ',",\,n,t,b,r,f
- if (quotesRemoved.length() == 2) {
+ }
+ tokens.setProcessedLine(theLine); // DPS 03-Jan-2013. Related to changes of 11-July-2012.
+
+ return (substitutionMade) ? tokenizeLine(lineNum, theLine) : tokens;
+ }
+
+
+ /**
+ * Fetch this Tokenizer's error list.
+ *
+ * @return the error list
+ */
+ public ErrorList getErrors()
+ {
+ return errors;
+ }
+
+
+ // Given candidate token and its position, will classify and record it.
+ private void processCandidateToken(char[] token, MIPSprogram program, int line, String theLine,
+ int tokenPos, int tokenStartPos, TokenList tokenList)
+ {
+ String value = new String(token, 0, tokenPos);
+ if (value.length() > 0 && value.charAt(0) == '\'')
+ {
+ value = preprocessCharacterLiteral(value);
+ }
+ TokenTypes type = TokenTypes.matchTokenType(value);
+ if (type == TokenTypes.ERROR)
+ {
+ errors.add(new ErrorMessage(program, line, tokenStartPos,
+ theLine + "\nInvalid language element: " + value));
+ }
+ Token toke = new Token(type, value, program, line, tokenStartPos);
+ tokenList.add(toke);
+ }
+
+
+ // If passed a candidate character literal, attempt to translate it into integer constant.
+ // If the translation fails, return original value.
+ private String preprocessCharacterLiteral(String value)
+ {
+ // must start and end with quote and have something in between
+ if (value.length() < 3 || value.charAt(0) != '\'' || value.charAt(value.length() - 1) != '\'')
+ {
+ return value;
+ }
+ String quotesRemoved = value.substring(1, value.length() - 1);
+ // if not escaped, then if one character left return its value else return original.
+ if (quotesRemoved.charAt(0) != '\\')
+ {
+ return (quotesRemoved.length() == 1) ? Integer.toString(quotesRemoved.charAt(0)) : value;
+ }
+ // now we know it is escape sequence and have to decode which of the 8: ',",\,n,t,b,r,f
+ if (quotesRemoved.length() == 2)
+ {
int escapedCharacterIndex = escapedCharacters.indexOf(quotesRemoved.charAt(1));
- return (escapedCharacterIndex >= 0) ? escapedCharactersValues[escapedCharacterIndex] : value;
- }
- // last valid possibility is 3 digit octal code 000 through 377
- if (quotesRemoved.length() == 4) {
- try {
- int intValue = Integer.parseInt(quotesRemoved.substring(1),8);
- if (intValue >= 0 && intValue <= 255) {
- return Integer.toString(intValue);
- }
- }
- catch (NumberFormatException nfe) { } // if not valid octal, will fall through and reject
- }
- return value;
- }
- }
+ return (escapedCharacterIndex >= 0) ? escapedCharactersValues[escapedCharacterIndex] : value;
+ }
+ // last valid possibility is 3 digit octal code 000 through 377
+ if (quotesRemoved.length() == 4)
+ {
+ try
+ {
+ int intValue = Integer.parseInt(quotesRemoved.substring(1), 8);
+ if (intValue >= 0 && intValue <= 255)
+ {
+ return Integer.toString(intValue);
+ }
+ }
+ catch (NumberFormatException nfe)
+ {
+ } // if not valid octal, will fall through and reject
+ }
+ return value;
+ }
+}
diff --git a/src/main/java/mars/assembler/TranslationCode.java b/src/main/java/mars/assembler/TranslationCode.java
index d7cf5c8..6ac5a22 100644
--- a/src/main/java/mars/assembler/TranslationCode.java
+++ b/src/main/java/mars/assembler/TranslationCode.java
@@ -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();
}
diff --git a/src/main/java/mars/mips/dump/AbstractDumpFormat.java b/src/main/java/mars/mips/dump/AbstractDumpFormat.java
index 1efdadc..aa62c43 100644
--- a/src/main/java/mars/mips/dump/AbstractDumpFormat.java
+++ b/src/main/java/mars/mips/dump/AbstractDumpFormat.java
@@ -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;
-
- }
\ No newline at end of file
+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;
+
+}
diff --git a/src/main/java/mars/mips/dump/AsciiTextDumpFormat.java b/src/main/java/mars/mips/dump/AsciiTextDumpFormat.java
index f59cf69..de5a878 100644
--- a/src/main/java/mars/mips/dump/AsciiTextDumpFormat.java
+++ b/src/main/java/mars/mips/dump/AsciiTextDumpFormat.java
@@ -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();
- }
- }
-
- }
\ No newline at end of file
+ }
+ finally
+ {
+ out.close();
+ }
+ }
+
+}
diff --git a/src/main/java/mars/mips/dump/BinaryDumpFormat.java b/src/main/java/mars/mips/dump/BinaryDumpFormat.java
index 8e37355..35be73b 100644
--- a/src/main/java/mars/mips/dump/BinaryDumpFormat.java
+++ b/src/main/java/mars/mips/dump/BinaryDumpFormat.java
@@ -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();
- }
- }
-
- }
\ No newline at end of file
+ }
+ finally
+ {
+ out.close();
+ }
+ }
+
+}
diff --git a/src/main/java/mars/mips/dump/BinaryTextDumpFormat.java b/src/main/java/mars/mips/dump/BinaryTextDumpFormat.java
index 6747c6c..b1e7ad3 100644
--- a/src/main/java/mars/mips/dump/BinaryTextDumpFormat.java
+++ b/src/main/java/mars/mips/dump/BinaryTextDumpFormat.java
@@ -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();
- }
- }
-
- }
\ No newline at end of file
+ }
+ finally
+ {
+ out.close();
+ }
+ }
+
+}
diff --git a/src/main/java/mars/mips/dump/DumpFormat.java b/src/main/java/mars/mips/dump/DumpFormat.java
index a1d649b..46ecafb 100644
--- a/src/main/java/mars/mips/dump/DumpFormat.java
+++ b/src/main/java/mars/mips/dump/DumpFormat.java
@@ -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;
-
- }
\ No newline at end of file
+ /**
+ * 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;
+
+}
diff --git a/src/main/java/mars/mips/dump/DumpFormatLoader.java b/src/main/java/mars/mips/dump/DumpFormatLoader.java
index 4059b35..dca14df 100644
--- a/src/main/java/mars/mips/dump/DumpFormatLoader.java
+++ b/src/main/java/mars/mips/dump/DumpFormatLoader.java
@@ -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>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();
+ }
+
+ }
+}
diff --git a/src/main/java/mars/mips/dump/MIFDumpFormat.java b/src/main/java/mars/mips/dump/MIFDumpFormat.java
index e21c026..3994223 100644
--- a/src/main/java/mars/mips/dump/MIFDumpFormat.java
+++ b/src/main/java/mars/mips/dump/MIFDumpFormat.java
@@ -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 {
-
- }
- }
\ No newline at end of file
+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
+ {
+
+ }
+}
diff --git a/src/main/java/mars/mips/dump/SegmentWindowDumpFormat.java b/src/main/java/mars/mips/dump/SegmentWindowDumpFormat.java
index 23ea15c..ee72770 100644
--- a/src/main/java/mars/mips/dump/SegmentWindowDumpFormat.java
+++ b/src/main/java/mars/mips/dump/SegmentWindowDumpFormat.java
@@ -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.
+ *
+ * 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();
- }
- }
-
-
- }
\ No newline at end of file
+ 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();
+ }
+ }
+
+
+}
diff --git a/src/main/java/mars/mips/hardware/AccessNotice.java b/src/main/java/mars/mips/hardware/AccessNotice.java
index ac05d0b..680e29c 100644
--- a/src/main/java/mars/mips/hardware/AccessNotice.java
+++ b/src/main/java/mars/mips/hardware/AccessNotice.java
@@ -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");
- }
-
-}
\ No newline at end of file
+ /** 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");
+ }
+
+}
diff --git a/src/main/java/mars/mips/hardware/AddressErrorException.java b/src/main/java/mars/mips/hardware/AddressErrorException.java
index 948e654..a4c31c3 100644
--- a/src/main/java/mars/mips/hardware/AddressErrorException.java
+++ b/src/main/java/mars/mips/hardware/AddressErrorException.java
@@ -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;
+ }
}
diff --git a/src/main/java/mars/mips/hardware/Coprocessor0.java b/src/main/java/mars/mips/hardware/Coprocessor0.java
index eeb8b18..a90df6d 100644
--- a/src/main/java/mars/mips/hardware/Coprocessor0.java
+++ b/src/main/java/mars/mips/hardware/Coprocessor0.java
@@ -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= 0 && reg < registers.length) {
- registers[reg].setValue(Float.floatToRawIntBits(val));
- }
- }
-
- /**
- * Sets the value of the FPU register given to the 32-bit
- * pattern given by the int parameter.
- * @param reg Register to set the value of.
- * @param val The desired int bit pattern for the register.
- **/
-
- public static void setRegisterToInt(String reg, int val){
- setRegisterToInt(getRegisterNumber(reg), val);
- }
-
-
- /**
- * Sets the value of the FPU register given to the 32-bit
- * pattern given by the int parameter.
- * @param reg Register to set the value of.
- * @param val The desired int bit pattern for the register.
- **/
-
- public static void setRegisterToInt(int reg, int val){
- if(reg >= 0 && reg < registers.length) {
- registers[reg].setValue(val);
- }
- }
-
-
- /**
- * Sets the value of the FPU register given to the double value given. The register
- * must be even-numbered, and the low order 32 bits are placed in it. The high order
- * 32 bits are placed in the (odd numbered) register that follows it.
- * @param reg Register to set the value of.
- * @param val The desired double value for the register.
- * @throws InvalidRegisterAccessException if register ID is invalid or odd-numbered.
- **/
-
- public static void setRegisterPairToDouble(int reg, double val)
- throws InvalidRegisterAccessException {
- if (reg % 2 != 0) {
- throw new InvalidRegisterAccessException();
- }
- long bits = Double.doubleToRawLongBits(val);
- registers[reg+1].setValue(Binary.highOrderLongToInt(bits)); // high order 32 bits
- registers[reg].setValue(Binary.lowOrderLongToInt(bits)); // low order 32 bits
- }
-
-
- /**
- * Sets the value of the FPU register given to the double value given. The register
- * must be even-numbered, and the low order 32 bits are placed in it. The high order
- * 32 bits are placed in the (odd numbered) register that follows it.
- * @param reg Register to set the value of.
- * @param val The desired double value for the register.
- * @throws InvalidRegisterAccessException if register ID is invalid or odd-numbered.
- **/
- public static void setRegisterPairToDouble(String reg, double val)
- throws InvalidRegisterAccessException {
- setRegisterPairToDouble(getRegisterNumber(reg), val);
- }
-
-
- /**
- * Sets the value of the FPU register pair given to the long value containing 64 bit pattern
- * given. The register
- * must be even-numbered, and the low order 32 bits from the long are placed in it. The high order
- * 32 bits from the long are placed in the (odd numbered) register that follows it.
- * @param reg Register to set the value of. Must be even register of even/odd pair.
- * @param val The desired double value for the register.
- * @throws InvalidRegisterAccessException if register ID is invalid or odd-numbered.
- **/
-
- public static void setRegisterPairToLong(int reg, long val)
- throws InvalidRegisterAccessException {
- if (reg % 2 != 0) {
- throw new InvalidRegisterAccessException();
- }
- registers[reg+1].setValue(Binary.highOrderLongToInt(val)); // high order 32 bits
- registers[reg].setValue(Binary.lowOrderLongToInt(val)); // low order 32 bits
- }
-
-
- /**
- * Sets the value of the FPU register pair given to the long value containing 64 bit pattern
- * given. The register
- * must be even-numbered, and the low order 32 bits from the long are placed in it. The high order
- * 32 bits from the long are placed in the (odd numbered) register that follows it.
- * @param reg Register to set the value of. Must be even register of even/odd pair.
- * @param val The desired long value containing the 64 bits for the register pair.
- * @throws InvalidRegisterAccessException if register ID is invalid or odd-numbered.
- **/
- public static void setRegisterPairToLong(String reg, long val)
- throws InvalidRegisterAccessException {
- setRegisterPairToLong(getRegisterNumber(reg), val);
- }
-
-
-
- /**
- * Gets the float value stored in the given FPU register.
- * @param reg Register to get the value of.
- * @return The float value stored by that register.
- **/
-
- public static float getFloatFromRegister(int reg){
- float result = 0F;
- if(reg >= 0 && reg < registers.length) {
- result = Float.intBitsToFloat(registers[reg].getValue());
- }
- return result;
- }
-
-
- /**
- * Gets the float value stored in the given FPU register.
- * @param reg Register to get the value of.
- * @return The float value stored by that register.
- **/
-
- public static float getFloatFromRegister(String reg) {
- return getFloatFromRegister(getRegisterNumber(reg));
- }
-
-
- /**
- * Gets the 32-bit int bit pattern stored in the given FPU register.
- * @param reg Register to get the value of.
- * @return The int bit pattern stored by that register.
- **/
-
- public static int getIntFromRegister(int reg){
- int result = 0;
- if(reg >= 0 && reg < registers.length) {
- result = registers[reg].getValue();
- }
- return result;
- }
-
-
- /**
- * Gets the 32-bit int bit pattern stored in the given FPU register.
- * @param reg Register to get the value of.
- * @return The int bit pattern stored by that register.
- **/
-
- public static int getIntFromRegister(String reg) {
- return getIntFromRegister(getRegisterNumber(reg));
- }
-
-
- /**
- * Gets the double value stored in the given FPU register. The register
- * must be even-numbered.
- * @param reg Register to get the value of. Must be even number of even/odd pair.
- * @throws InvalidRegisterAccessException if register ID is invalid or odd-numbered.
- **/
-
- public static double getDoubleFromRegisterPair(int reg)
- throws InvalidRegisterAccessException {
- double result = 0.0;
- if (reg % 2 != 0) {
- throw new InvalidRegisterAccessException();
- }
- long bits = Binary.twoIntsToLong(registers[reg+1].getValue(),registers[reg].getValue());
- return Double.longBitsToDouble(bits);
- }
-
-
- /**
- * Gets the double value stored in the given FPU register. The register
- * must be even-numbered.
- * @param reg Register to get the value of. Must be even number of even/odd pair.
- * @throws InvalidRegisterAccessException if register ID is invalid or odd-numbered.
- **/
-
- public static double getDoubleFromRegisterPair(String reg)
- throws InvalidRegisterAccessException {
- return getDoubleFromRegisterPair(getRegisterNumber(reg));
- }
-
-
- /**
- * Gets a long representing the double value stored in the given double
- * precision FPU register.
- * The register must be even-numbered.
- * @param reg Register to get the value of. Must be even number of even/odd pair.
- * @throws InvalidRegisterAccessException if register ID is invalid or odd-numbered.
- **/
-
- public static long getLongFromRegisterPair(int reg)
- throws InvalidRegisterAccessException {
- double result = 0.0;
- if (reg % 2 != 0) {
- throw new InvalidRegisterAccessException();
- }
- return Binary.twoIntsToLong(registers[reg+1].getValue(),registers[reg].getValue());
- }
-
-
- /**
- * Gets the double value stored in the given FPU register. The register
- * must be even-numbered.
- * @param reg Register to get the value of. Must be even number of even/odd pair.
- * @throws InvalidRegisterAccessException if register ID is invalid or odd-numbered.
- **/
-
- public static long getLongFromRegisterPair(String reg)
- throws InvalidRegisterAccessException {
- return getLongFromRegisterPair(getRegisterNumber(reg));
- }
-
-
- /**
- * This method updates the FPU register value who's number is num. Note the
- * registers themselves hold an int value. There are helper methods available
- * to which you can give a float or double to store.
- * @param num FPU register to set the value of.
- * @param val The desired int value for the register.
- **/
-
- public static int updateRegister(int num, int val){
- int old = 0;
- for (int i=0; i< registers.length; i++){
- if(registers[i].getNumber()== num) {
- old = (Globals.getSettings().getBackSteppingEnabled())
- ? Globals.program.getBackStepper().addCoprocessor1Restore(num,registers[i].setValue(val))
- : registers[i].setValue(val);
- break;
- }
- }
- return old;
- }
-
- /**
- * Returns the value of the FPU register who's number is num. Returns the
- * raw int value actually stored there. If you need a float, use
- * Float.intBitsToFloat() to get the equivent float.
- * @param num The FPU register number.
- * @return The int value of the given register.
- **/
-
- public static int getValue(int num){
- return registers[num].getValue();
- }
-
- /**
- * For getting the number representation of the FPU register.
- * @param n The string formatted register name to look for.
- * @return The number of the register represented by the string.
- **/
-
- public static int getRegisterNumber(String n){
- int j=-1;
- for (int i=0; i< registers.length; i++){
- if(registers[i].getName().equals(n)) {
- j= registers[i].getNumber();
- break;
- }
- }
- return j;
- }
-
- /**
- * For returning the set of registers.
- * @return The set of registers.
- **/
-
- public static Register[] getRegisters(){
- return registers;
- }
-
- /**
- * Get register object corresponding to given name. If no match, return null.
- * @param rName The FPU register name, must be "$f0" through "$f31".
- * @return The register object,or null if not found.
- **/
-
- public static Register getRegister(String rName) {
- Register reg = null;
- if (rName.charAt(0) == '$' && rName.length() > 1 && rName.charAt(1) == 'f') {
- try {
- // check for register number 0-31.
- reg = registers[Binary.stringToInt(rName.substring(2))]; // KENV 1/6/05
- }
- catch (Exception e) {
- // handles both NumberFormat and ArrayIndexOutOfBounds
- reg = null;
- }
- }
- return reg;
- }
-
-
- /**
- * Method to reinitialize the values of the registers.
- **/
-
- public static void resetRegisters(){
- for(int i=0; i < registers.length; i++)
- registers[i].resetValue();
- clearConditionFlags();
- }
-
-
- /**
- * Each individual register is a separate object and Observable. This handy method
- * will add the given Observer to each one.
- */
- public static void addRegistersObserver(Observer observer) {
- for (int i=0; i= 0 && reg < registers.length)
+ {
+ registers[reg].setValue(Float.floatToRawIntBits(val));
+ }
+ }
+
+ /**
+ * Sets the value of the FPU register given to the 32-bit pattern given by the int parameter.
+ *
+ * @param reg Register to set the value of.
+ * @param val The desired int bit pattern for the register.
+ **/
+
+ public static void setRegisterToInt(String reg, int val)
+ {
+ setRegisterToInt(getRegisterNumber(reg), val);
+ }
+
+
+ /**
+ * Sets the value of the FPU register given to the 32-bit pattern given by the int parameter.
+ *
+ * @param reg Register to set the value of.
+ * @param val The desired int bit pattern for the register.
+ **/
+
+ public static void setRegisterToInt(int reg, int val)
+ {
+ if (reg >= 0 && reg < registers.length)
+ {
+ registers[reg].setValue(val);
+ }
+ }
+
+
+ /**
+ * Sets the value of the FPU register given to the double value given. The register must be even-numbered, and the
+ * low order 32 bits are placed in it. The high order 32 bits are placed in the (odd numbered) register that
+ * follows it.
+ *
+ * @param reg Register to set the value of.
+ * @param val The desired double value for the register.
+ * @throws InvalidRegisterAccessException if register ID is invalid or odd-numbered.
+ **/
+
+ public static void setRegisterPairToDouble(int reg, double val)
+ throws InvalidRegisterAccessException
+ {
+ if (reg % 2 != 0)
+ {
+ throw new InvalidRegisterAccessException();
+ }
+ long bits = Double.doubleToRawLongBits(val);
+ registers[reg + 1].setValue(Binary.highOrderLongToInt(bits)); // high order 32 bits
+ registers[reg].setValue(Binary.lowOrderLongToInt(bits)); // low order 32 bits
+ }
+
+
+ /**
+ * Sets the value of the FPU register given to the double value given. The register must be even-numbered, and the
+ * low order 32 bits are placed in it. The high order 32 bits are placed in the (odd numbered) register that
+ * follows it.
+ *
+ * @param reg Register to set the value of.
+ * @param val The desired double value for the register.
+ * @throws InvalidRegisterAccessException if register ID is invalid or odd-numbered.
+ **/
+ public static void setRegisterPairToDouble(String reg, double val)
+ throws InvalidRegisterAccessException
+ {
+ setRegisterPairToDouble(getRegisterNumber(reg), val);
+ }
+
+
+ /**
+ * Sets the value of the FPU register pair given to the long value containing 64 bit pattern given. The register
+ * must be even-numbered, and the low order 32 bits from the long are placed in it. The high order 32 bits from the
+ * long are placed in the (odd numbered) register that follows it.
+ *
+ * @param reg Register to set the value of. Must be even register of even/odd pair.
+ * @param val The desired double value for the register.
+ * @throws InvalidRegisterAccessException if register ID is invalid or odd-numbered.
+ **/
+
+ public static void setRegisterPairToLong(int reg, long val)
+ throws InvalidRegisterAccessException
+ {
+ if (reg % 2 != 0)
+ {
+ throw new InvalidRegisterAccessException();
+ }
+ registers[reg + 1].setValue(Binary.highOrderLongToInt(val)); // high order 32 bits
+ registers[reg].setValue(Binary.lowOrderLongToInt(val)); // low order 32 bits
+ }
+
+
+ /**
+ * Sets the value of the FPU register pair given to the long value containing 64 bit pattern given. The register
+ * must be even-numbered, and the low order 32 bits from the long are placed in it. The high order 32 bits from the
+ * long are placed in the (odd numbered) register that follows it.
+ *
+ * @param reg Register to set the value of. Must be even register of even/odd pair.
+ * @param val The desired long value containing the 64 bits for the register pair.
+ * @throws InvalidRegisterAccessException if register ID is invalid or odd-numbered.
+ **/
+ public static void setRegisterPairToLong(String reg, long val)
+ throws InvalidRegisterAccessException
+ {
+ setRegisterPairToLong(getRegisterNumber(reg), val);
+ }
+
+
+ /**
+ * Gets the float value stored in the given FPU register.
+ *
+ * @param reg Register to get the value of.
+ * @return The float value stored by that register.
+ **/
+
+ public static float getFloatFromRegister(int reg)
+ {
+ float result = 0F;
+ if (reg >= 0 && reg < registers.length)
+ {
+ result = Float.intBitsToFloat(registers[reg].getValue());
+ }
+ return result;
+ }
+
+
+ /**
+ * Gets the float value stored in the given FPU register.
+ *
+ * @param reg Register to get the value of.
+ * @return The float value stored by that register.
+ **/
+
+ public static float getFloatFromRegister(String reg)
+ {
+ return getFloatFromRegister(getRegisterNumber(reg));
+ }
+
+
+ /**
+ * Gets the 32-bit int bit pattern stored in the given FPU register.
+ *
+ * @param reg Register to get the value of.
+ * @return The int bit pattern stored by that register.
+ **/
+
+ public static int getIntFromRegister(int reg)
+ {
+ int result = 0;
+ if (reg >= 0 && reg < registers.length)
+ {
+ result = registers[reg].getValue();
+ }
+ return result;
+ }
+
+
+ /**
+ * Gets the 32-bit int bit pattern stored in the given FPU register.
+ *
+ * @param reg Register to get the value of.
+ * @return The int bit pattern stored by that register.
+ **/
+
+ public static int getIntFromRegister(String reg)
+ {
+ return getIntFromRegister(getRegisterNumber(reg));
+ }
+
+
+ /**
+ * Gets the double value stored in the given FPU register. The register must be even-numbered.
+ *
+ * @param reg Register to get the value of. Must be even number of even/odd pair.
+ * @throws InvalidRegisterAccessException if register ID is invalid or odd-numbered.
+ **/
+
+ public static double getDoubleFromRegisterPair(int reg)
+ throws InvalidRegisterAccessException
+ {
+ double result = 0.0;
+ if (reg % 2 != 0)
+ {
+ throw new InvalidRegisterAccessException();
+ }
+ long bits = Binary.twoIntsToLong(registers[reg + 1].getValue(), registers[reg].getValue());
+ return Double.longBitsToDouble(bits);
+ }
+
+
+ /**
+ * Gets the double value stored in the given FPU register. The register must be even-numbered.
+ *
+ * @param reg Register to get the value of. Must be even number of even/odd pair.
+ * @throws InvalidRegisterAccessException if register ID is invalid or odd-numbered.
+ **/
+
+ public static double getDoubleFromRegisterPair(String reg)
+ throws InvalidRegisterAccessException
+ {
+ return getDoubleFromRegisterPair(getRegisterNumber(reg));
+ }
+
+
+ /**
+ * Gets a long representing the double value stored in the given double precision FPU register. The register must be
+ * even-numbered.
+ *
+ * @param reg Register to get the value of. Must be even number of even/odd pair.
+ * @throws InvalidRegisterAccessException if register ID is invalid or odd-numbered.
+ **/
+
+ public static long getLongFromRegisterPair(int reg)
+ throws InvalidRegisterAccessException
+ {
+ double result = 0.0;
+ if (reg % 2 != 0)
+ {
+ throw new InvalidRegisterAccessException();
+ }
+ return Binary.twoIntsToLong(registers[reg + 1].getValue(), registers[reg].getValue());
+ }
+
+
+ /**
+ * Gets the double value stored in the given FPU register. The register must be even-numbered.
+ *
+ * @param reg Register to get the value of. Must be even number of even/odd pair.
+ * @throws InvalidRegisterAccessException if register ID is invalid or odd-numbered.
+ **/
+
+ public static long getLongFromRegisterPair(String reg)
+ throws InvalidRegisterAccessException
+ {
+ return getLongFromRegisterPair(getRegisterNumber(reg));
+ }
+
+
+ /**
+ * This method updates the FPU register value who's number is num. Note the registers themselves hold an int value.
+ * There are helper methods available to which you can give a float or double to store.
+ *
+ * @param num FPU register to set the value of.
+ * @param val The desired int value for the register.
+ **/
+
+ public static int updateRegister(int num, int val)
+ {
+ int old = 0;
+ for (int i = 0; i < registers.length; i++)
+ {
+ if (registers[i].getNumber() == num)
+ {
+ old = (Globals.getSettings().getBackSteppingEnabled())
+ ? Globals.program.getBackStepper().addCoprocessor1Restore(num, registers[i].setValue(val))
+ : registers[i].setValue(val);
+ break;
+ }
+ }
+ return old;
+ }
+
+ /**
+ * Returns the value of the FPU register who's number is num. Returns the raw int value actually stored there. If
+ * you need a float, use Float.intBitsToFloat() to get the equivent float.
+ *
+ * @param num The FPU register number.
+ * @return The int value of the given register.
+ **/
+
+ public static int getValue(int num)
+ {
+ return registers[num].getValue();
+ }
+
+ /**
+ * For getting the number representation of the FPU register.
+ *
+ * @param n The string formatted register name to look for.
+ * @return The number of the register represented by the string.
+ **/
+
+ public static int getRegisterNumber(String n)
+ {
+ int j = -1;
+ for (int i = 0; i < registers.length; i++)
+ {
+ if (registers[i].getName().equals(n))
+ {
+ j = registers[i].getNumber();
+ break;
+ }
+ }
+ return j;
+ }
+
+ /**
+ * For returning the set of registers.
+ *
+ * @return The set of registers.
+ **/
+
+ public static Register[] getRegisters()
+ {
+ return registers;
+ }
+
+ /**
+ * Get register object corresponding to given name. If no match, return null.
+ *
+ * @param rName The FPU register name, must be "$f0" through "$f31".
+ * @return The register object,or null if not found.
+ **/
+
+ public static Register getRegister(String rName)
+ {
+ Register reg = null;
+ if (rName.charAt(0) == '$' && rName.length() > 1 && rName.charAt(1) == 'f')
+ {
+ try
+ {
+ // check for register number 0-31.
+ reg = registers[Binary.stringToInt(rName.substring(2))]; // KENV 1/6/05
+ }
+ catch (Exception e)
+ {
+ // handles both NumberFormat and ArrayIndexOutOfBounds
+ reg = null;
+ }
+ }
+ return reg;
+ }
+
+
+ /**
+ * Method to reinitialize the values of the registers.
+ **/
+
+ public static void resetRegisters()
+ {
+ for (int i = 0; i < registers.length; i++)
+ {
+ registers[i].resetValue();
+ }
+ clearConditionFlags();
+ }
+
+
+ /**
+ * Each individual register is a separate object and Observable. This handy method will add the given Observer to
+ * each one.
+ */
+ public static void addRegistersObserver(Observer observer)
+ {
+ for (int i = 0; i < registers.length; i++)
+ {
+ registers[i].addObserver(observer);
+ }
+ }
+
+
+ /**
+ * Each individual register is a separate object and Observable. This handy method will delete the given Observer
+ * from each one.
+ */
+ public static void deleteRegistersObserver(Observer observer)
+ {
+ for (int i = 0; i < registers.length; i++)
+ {
registers[i].deleteObserver(observer);
- }
- }
-
- /**
- * Set condition flag to 1 (true).
- *
- * @param flag condition flag number (0-7)
- * @return previous flag setting (0 or 1)
- */
- public static int setConditionFlag(int flag) {
- int old = 0;
- if (flag >= 0 && flag < numConditionFlags) {
+ }
+ }
+
+ /**
+ * Set condition flag to 1 (true).
+ *
+ * @param flag condition flag number (0-7)
+ * @return previous flag setting (0 or 1)
+ */
+ public static int setConditionFlag(int flag)
+ {
+ int old = 0;
+ if (flag >= 0 && flag < numConditionFlags)
+ {
old = getConditionFlag(flag);
- condition.setValue(Binary.setBit(condition.getValue(),flag));
+ condition.setValue(Binary.setBit(condition.getValue(), flag));
if (Globals.getSettings().getBackSteppingEnabled())
- if (old==0) {
- Globals.program.getBackStepper().addConditionFlagClear(flag);
- }
- else {
- Globals.program.getBackStepper().addConditionFlagSet(flag);
- }
- }
- return old;
- }
-
- /**
- * Set condition flag to 0 (false).
- *
- * @param flag condition flag number (0-7)
- * @return previous flag setting (0 or 1)
- */
- public static int clearConditionFlag(int flag) {
- int old = 0;
- if (flag >= 0 && flag < numConditionFlags) {
+ {
+ if (old == 0)
+ {
+ Globals.program.getBackStepper().addConditionFlagClear(flag);
+ }
+ else
+ {
+ Globals.program.getBackStepper().addConditionFlagSet(flag);
+ }
+ }
+ }
+ return old;
+ }
+
+ /**
+ * Set condition flag to 0 (false).
+ *
+ * @param flag condition flag number (0-7)
+ * @return previous flag setting (0 or 1)
+ */
+ public static int clearConditionFlag(int flag)
+ {
+ int old = 0;
+ if (flag >= 0 && flag < numConditionFlags)
+ {
old = getConditionFlag(flag);
- condition.setValue(Binary.clearBit(condition.getValue(),flag));
+ condition.setValue(Binary.clearBit(condition.getValue(), flag));
if (Globals.getSettings().getBackSteppingEnabled())
- if (old==0) {
- Globals.program.getBackStepper().addConditionFlagClear(flag);
- }
- else {
- Globals.program.getBackStepper().addConditionFlagSet(flag);
- }
- }
- return old;
- }
-
-
- /**
- * Get value of specified condition flag (0-7).
- *
- * @param flag condition flag number (0-7)
- * @return 0 if condition is false, 1 if condition is true
- */
- public static int getConditionFlag(int flag) {
- if (flag < 0 || flag >= numConditionFlags)
+ {
+ if (old == 0)
+ {
+ Globals.program.getBackStepper().addConditionFlagClear(flag);
+ }
+ else
+ {
+ Globals.program.getBackStepper().addConditionFlagSet(flag);
+ }
+ }
+ }
+ return old;
+ }
+
+
+ /**
+ * Get value of specified condition flag (0-7).
+ *
+ * @param flag condition flag number (0-7)
+ * @return 0 if condition is false, 1 if condition is true
+ */
+ public static int getConditionFlag(int flag)
+ {
+ if (flag < 0 || flag >= numConditionFlags)
+ {
flag = 0;
- return Binary.bitValue(condition.getValue(), flag);
- }
-
-
- /**
- * Get array of condition flags (0-7).
- *
- * @return array of int condition flags
- */
- public static int getConditionFlags() {
- return condition.getValue();
- }
-
-
- /**
- * Clear all condition flags (0-7).
- *
- */
- public static void clearConditionFlags() {
- condition.setValue(0); // sets all 32 bits to 0.
- }
-
- /**
- * Set all condition flags (0-7).
- *
- */
- public static void setConditionFlags() {
- condition.setValue(-1); // sets all 32 bits to 1.
- }
-
- /**
- * Get count of condition flags.
- *
- * @return number of condition flags
- */
- public static int getConditionFlagCount() {
- return numConditionFlags;
- }
- }
+ }
+ return Binary.bitValue(condition.getValue(), flag);
+ }
+
+
+ /**
+ * Get array of condition flags (0-7).
+ *
+ * @return array of int condition flags
+ */
+ public static int getConditionFlags()
+ {
+ return condition.getValue();
+ }
+
+
+ /**
+ * Clear all condition flags (0-7).
+ */
+ public static void clearConditionFlags()
+ {
+ condition.setValue(0); // sets all 32 bits to 0.
+ }
+
+ /**
+ * Set all condition flags (0-7).
+ */
+ public static void setConditionFlags()
+ {
+ condition.setValue(-1); // sets all 32 bits to 1.
+ }
+
+ /**
+ * Get count of condition flags.
+ *
+ * @return number of condition flags
+ */
+ public static int getConditionFlagCount()
+ {
+ return numConditionFlags;
+ }
+}
diff --git a/src/main/java/mars/mips/hardware/InvalidRegisterAccessException.java b/src/main/java/mars/mips/hardware/InvalidRegisterAccessException.java
index 138a4d9..8167743 100644
--- a/src/main/java/mars/mips/hardware/InvalidRegisterAccessException.java
+++ b/src/main/java/mars/mips/hardware/InvalidRegisterAccessException.java
@@ -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()
+ {
+ }
- }
-
\ No newline at end of file
+}
diff --git a/src/main/java/mars/mips/hardware/Memory.java b/src/main/java/mars/mips/hardware/Memory.java
index eed800e..c56a095 100644
--- a/src/main/java/mars/mips/hardware/Memory.java
+++ b/src/main/java/mars/mips/hardware/Memory.java
@@ -39,8 +39,8 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
/**
* Represents MIPS memory. Different segments are represented by different data structs.
- *
- * @author Pete Sanderson
+ *
+ * @author Pete Sanderson
* @version August 2003
*/
@@ -48,53 +48,77 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// NOTE: This implementation is purely big-endian. MIPS can handle either one.
/////////////////////////////////////////////////////////////////////
- public class Memory extends Observable {
-
- /** base address for (user) text segment: 0x00400000 **/
- public static int textBaseAddress = MemoryConfigurations.getDefaultTextBaseAddress(); //0x00400000;
- /** base address for (user) data segment: 0x10000000 **/
- public static int dataSegmentBaseAddress = MemoryConfigurations.getDefaultDataSegmentBaseAddress(); //0x10000000;
- /** base address for .extern directive: 0x10000000 **/
- public static int externBaseAddress = MemoryConfigurations.getDefaultExternBaseAddress(); //0x10000000;
- /** base address for storing globals **/
- public static int globalPointer = MemoryConfigurations.getDefaultGlobalPointer(); //0x10008000;
- /** base address for storage of non-global static data in data segment: 0x10010000 (from SPIM) **/
- public static int dataBaseAddress = MemoryConfigurations.getDefaultDataBaseAddress(); //0x10010000; // from SPIM not MIPS
- /** base address for heap: 0x10040000 (I think from SPIM not MIPS) **/
- public static int heapBaseAddress = MemoryConfigurations.getDefaultHeapBaseAddress(); //0x10040000; // I think from SPIM not MIPS
- /** starting address for stack: 0x7fffeffc (this is from SPIM not MIPS) **/
- public static int stackPointer = MemoryConfigurations.getDefaultStackPointer(); //0x7fffeffc;
- /** base address for stack: 0x7ffffffc (this is mine - start of highest word below kernel space) **/
- public static int stackBaseAddress = MemoryConfigurations.getDefaultStackBaseAddress(); //0x7ffffffc;
- /** highest address accessible in user (not kernel) mode. **/
- public static int userHighAddress = MemoryConfigurations.getDefaultUserHighAddress(); //0x7fffffff;
- /** kernel boundary. Only OS can access this or higher address **/
- public static int kernelBaseAddress = MemoryConfigurations.getDefaultKernelBaseAddress(); //0x80000000;
- /** base address for kernel text segment: 0x80000000 **/
- public static int kernelTextBaseAddress = MemoryConfigurations.getDefaultKernelTextBaseAddress(); //0x80000000;
- /** starting address for exception handlers: 0x80000180 **/
- public static int exceptionHandlerAddress = MemoryConfigurations.getDefaultExceptionHandlerAddress(); //0x80000180;
- /** base address for kernel data segment: 0x90000000 **/
- public static int kernelDataBaseAddress = MemoryConfigurations.getDefaultKernelDataBaseAddress(); //0x90000000;
- /** starting address for memory mapped I/O: 0xffff0000 (-65536) **/
- public static int memoryMapBaseAddress = MemoryConfigurations.getDefaultMemoryMapBaseAddress(); //0xffff0000;
- /** highest address acessible in kernel mode. **/
- public static int kernelHighAddress = MemoryConfigurations.getDefaultKernelHighAddress(); //0xffffffff;
-
+public class Memory extends Observable
+{
+
/** MIPS word length in bytes. **/
// NOTE: Much of the code is hardwired for 4 byte words. Refactoring this is low priority.
- public static final int WORD_LENGTH_BYTES = 4;
- /** Constant representing byte order of each memory word. Little-endian means lowest
- numbered byte is right most [3][2][1][0]. */
- public static final boolean LITTLE_ENDIAN = true;
- /** Constant representing byte order of each memory word. Big-endian means lowest
- numbered byte is left most [0][1][2][3]. */
- public static final boolean BIG_ENDIAN = false;
- /** Current setting for endian (default LITTLE_ENDIAN) **/
- private static boolean byteOrder = LITTLE_ENDIAN;
-
- public static int heapAddress;
-
+ public static final int WORD_LENGTH_BYTES = 4;
+
+ /**
+ * Constant representing byte order of each memory word. Little-endian means lowest numbered byte is right most
+ * [3][2][1][0].
+ */
+ public static final boolean LITTLE_ENDIAN = true;
+
+ /**
+ * Constant representing byte order of each memory word. Big-endian means lowest numbered byte is left most
+ * [0][1][2][3].
+ */
+ public static final boolean BIG_ENDIAN = false;
+
+ private static final int BLOCK_LENGTH_WORDS = 1024; // allocated blocksize 1024 ints == 4K bytes
+
+ private static final int BLOCK_TABLE_LENGTH = 1024; // Each entry of table points to a block.
+
+ private static final int MMIO_TABLE_LENGTH = 16; // Each entry of table points to a 4K block.
+
+ private static final int TEXT_BLOCK_LENGTH_WORDS = 1024; // allocated blocksize 1024 ints == 4K bytes
+
+ private static final int TEXT_BLOCK_TABLE_LENGTH = 1024; // Each entry of table points to a block.
+
+ ////////////////////////////////////////////////////////////////////////////////
+ //
+ // Helper method to store 1, 2 or 4 byte value in table that represents MIPS
+ // memory. Originally used just for data segment, but now also used for stack.
+ // Both use different tables but same storage method and same table size
+ // and block size.
+ // Modified 29 Dec 2005 to return old value of replaced bytes.
+ //
+ private static final boolean STORE = true;
+
+ private static final boolean FETCH = false;
+
+ /** base address for (user) text segment: 0x00400000 **/
+ public static int textBaseAddress = MemoryConfigurations.getDefaultTextBaseAddress(); //0x00400000;
+
+ /** base address for (user) data segment: 0x10000000 **/
+ public static int dataSegmentBaseAddress = MemoryConfigurations.getDefaultDataSegmentBaseAddress(); //0x10000000;
+
+ /** base address for .extern directive: 0x10000000 **/
+ public static int externBaseAddress = MemoryConfigurations.getDefaultExternBaseAddress(); //0x10000000;
+
+ /** base address for storing globals **/
+ public static int globalPointer = MemoryConfigurations.getDefaultGlobalPointer(); //0x10008000;
+
+ /** base address for storage of non-global static data in data segment: 0x10010000 (from SPIM) **/
+ public static int dataBaseAddress = MemoryConfigurations.getDefaultDataBaseAddress(); //0x10010000; // from SPIM not MIPS
+
+ /** base address for heap: 0x10040000 (I think from SPIM not MIPS) **/
+ public static int heapBaseAddress = MemoryConfigurations.getDefaultHeapBaseAddress(); //0x10040000; // I think from SPIM not MIPS
+
+ /** starting address for stack: 0x7fffeffc (this is from SPIM not MIPS) **/
+ public static int stackPointer = MemoryConfigurations.getDefaultStackPointer(); //0x7fffeffc;
+
+ /** base address for stack: 0x7ffffffc (this is mine - start of highest word below kernel space) **/
+ public static int stackBaseAddress = MemoryConfigurations.getDefaultStackBaseAddress(); //0x7ffffffc;
+
+ /** highest address accessible in user (not kernel) mode. **/
+ public static int userHighAddress = MemoryConfigurations.getDefaultUserHighAddress(); //0x7fffffff;
+
+ /** kernel boundary. Only OS can access this or higher address **/
+ public static int kernelBaseAddress = MemoryConfigurations.getDefaultKernelBaseAddress(); //0x80000000;
+
// Memory will maintain a collection of observables. Each one is associated
// with a specific memory address or address range, and each will have at least
// one observer registered with it. When memory access is made, make sure only
@@ -106,9 +130,10 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// key for insertion into the tree would be based on Comparable using both low
// and high end of address range, but retrieval from the tree has to be based
// on target address being ANYWHERE IN THE RANGE (not an exact key match).
-
- Collection observables = getNewMemoryObserversCollection();
-
+
+ /** base address for kernel text segment: 0x80000000 **/
+ public static int kernelTextBaseAddress = MemoryConfigurations.getDefaultKernelTextBaseAddress(); //0x80000000;
+
// The data segment is allocated in blocks of 1024 ints (4096 bytes). Each block is
// referenced by a "block table" entry, and the table has 1024 entries. The capacity
// is thus 1024 entries * 4096 bytes = 4 MB. Should be enough to cover most
@@ -132,12 +157,19 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// (I don't have a reference for that offhand...) Using my scheme, 0x10040000 falls at
// the start of the 65'th block -- table entry 64. That leaves (1024-64) * 4096 = 3,932,160
// bytes of space available without going indirect.
-
- private static final int BLOCK_LENGTH_WORDS = 1024; // allocated blocksize 1024 ints == 4K bytes
- private static final int BLOCK_TABLE_LENGTH = 1024; // Each entry of table points to a block.
- private int[][] dataBlockTable;
- private int[][] kernelDataBlockTable;
-
+
+ /** starting address for exception handlers: 0x80000180 **/
+ public static int exceptionHandlerAddress = MemoryConfigurations.getDefaultExceptionHandlerAddress(); //0x80000180;
+
+ /** base address for kernel data segment: 0x90000000 **/
+ public static int kernelDataBaseAddress = MemoryConfigurations.getDefaultKernelDataBaseAddress(); //0x90000000;
+
+ /** starting address for memory mapped I/O: 0xffff0000 (-65536) **/
+ public static int memoryMapBaseAddress = MemoryConfigurations.getDefaultMemoryMapBaseAddress(); //0xffff0000;
+
+ /** highest address acessible in kernel mode. **/
+ public static int kernelHighAddress = MemoryConfigurations.getDefaultKernelHighAddress(); //0xffffffff;
+
// The stack is modeled similarly to the data segment. It cannot share the same
// data structure because the stack base address is very large. To store it in the
// same data structure would require implementation of indirect blocks, which has not
@@ -152,9 +184,9 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// from desired address). Thus as the address gets smaller the offset gets larger.
// Everything else works the same, so it shares some private helper methods with
// data segment algorithms.
-
- private int[][] stackBlockTable;
-
+
+ public static int heapAddress;
+
// Memory mapped I/O is simulated with a separate table using the same structure and
// logic as data segment. Memory is allocated in 4K byte blocks. But since MMIO
// address range is limited to 0xffff0000 to 0xfffffffc, there are only 64K bytes
@@ -164,109 +196,115 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// MMIO addresses are interpreted by Java as negative numbers since it does not
// have unsigned types. As long as the absolute address is correctly translated
// into a table offset, this is of no concern.
-
- private static final int MMIO_TABLE_LENGTH = 16; // Each entry of table points to a 4K block.
- private int[][] memoryMapBlockTable;
-
+
+ public static int dataSegmentLimitAddress = dataSegmentBaseAddress +
+ BLOCK_LENGTH_WORDS * BLOCK_TABLE_LENGTH * WORD_LENGTH_BYTES;
+
+ public static int textLimitAddress = textBaseAddress +
+ TEXT_BLOCK_LENGTH_WORDS * TEXT_BLOCK_TABLE_LENGTH * WORD_LENGTH_BYTES;
+
// I use a similar scheme for storing instructions. MIPS text segment ranges from
// 0x00400000 all the way to data segment (0x10000000) a range of about 250 MB! So
// I'll provide table of blocks with similar capacity. This differs from data segment
// somewhat in that the block entries do not contain int's, but instead contain
// references to ProgramStatement objects.
-
- private static final int TEXT_BLOCK_LENGTH_WORDS = 1024; // allocated blocksize 1024 ints == 4K bytes
- private static final int TEXT_BLOCK_TABLE_LENGTH = 1024; // Each entry of table points to a block.
- private ProgramStatement[][] textBlockTable;
- private ProgramStatement[][] kernelTextBlockTable;
-
+
+ public static int kernelDataSegmentLimitAddress = kernelDataBaseAddress +
+ BLOCK_LENGTH_WORDS * BLOCK_TABLE_LENGTH * WORD_LENGTH_BYTES;
+
+ public static int kernelTextLimitAddress = kernelTextBaseAddress +
+ TEXT_BLOCK_LENGTH_WORDS * TEXT_BLOCK_TABLE_LENGTH * WORD_LENGTH_BYTES;
+
+ public static int stackLimitAddress = stackBaseAddress -
+ BLOCK_LENGTH_WORDS * BLOCK_TABLE_LENGTH * WORD_LENGTH_BYTES;
+
+ public static int memoryMapLimitAddress = memoryMapBaseAddress +
+ BLOCK_LENGTH_WORDS * MMIO_TABLE_LENGTH * WORD_LENGTH_BYTES;
+
// Set "top" address boundary to go with each "base" address. This determines permissable
// address range for user program. Currently limit is 4MB, or 1024 * 1024 * 4 bytes based
// on the table structures described above (except memory mapped IO, limited to 64KB by range).
-
- public static int dataSegmentLimitAddress = dataSegmentBaseAddress +
- BLOCK_LENGTH_WORDS * BLOCK_TABLE_LENGTH * WORD_LENGTH_BYTES;
- public static int textLimitAddress = textBaseAddress +
- TEXT_BLOCK_LENGTH_WORDS * TEXT_BLOCK_TABLE_LENGTH * WORD_LENGTH_BYTES;
- public static int kernelDataSegmentLimitAddress = kernelDataBaseAddress +
- BLOCK_LENGTH_WORDS * BLOCK_TABLE_LENGTH * WORD_LENGTH_BYTES;
- public static int kernelTextLimitAddress = kernelTextBaseAddress +
- TEXT_BLOCK_LENGTH_WORDS * TEXT_BLOCK_TABLE_LENGTH * WORD_LENGTH_BYTES;
- public static int stackLimitAddress = stackBaseAddress -
- BLOCK_LENGTH_WORDS * BLOCK_TABLE_LENGTH * WORD_LENGTH_BYTES;
- public static int memoryMapLimitAddress = memoryMapBaseAddress +
- BLOCK_LENGTH_WORDS * MMIO_TABLE_LENGTH * WORD_LENGTH_BYTES;
+
+ /** Current setting for endian (default LITTLE_ENDIAN) **/
+ private static boolean byteOrder = LITTLE_ENDIAN;
+
+ private static final Memory uniqueMemoryInstance = new Memory();
+
+ Collection observables = getNewMemoryObserversCollection();
+
+ private int[][] dataBlockTable;
+
+ private int[][] kernelDataBlockTable;
+
+ private int[][] stackBlockTable;
// This will be a Singleton class, only one instance is ever created. Since I know the
// Memory object is always needed, I'll go ahead and create it at the time of class loading.
// (greedy rather than lazy instantiation). The constructor is private and getInstance()
// always returns this instance.
-
- private static Memory uniqueMemoryInstance = new Memory();
-
-
+
+ private int[][] memoryMapBlockTable;
+
+ private ProgramStatement[][] textBlockTable;
+
+ private ProgramStatement[][] kernelTextBlockTable;
+
/*
- * Private constructor for Memory. Separate data structures for text and data segments.
+ * Private constructor for Memory. Separate data structures for text and data segments.
**/
- private Memory() {
- initialize();
- }
-
- /**
- * Returns the unique Memory instance, which becomes in essence global.
- */
-
- public static Memory getInstance() {
- return uniqueMemoryInstance;
- }
-
- /**
- * Explicitly clear the contents of memory. Typically done at start of assembly.
- */
-
- public void clear() {
- setConfiguration();
- initialize();
- }
-
- /**
- * Sets current memory configuration for simulated MIPS. Configuration is
- * collection of memory segment addresses. e.g. text segment starting at
- * address 0x00400000. Configuration can be modified starting with MARS 3.7.
+ private Memory()
+ {
+ initialize();
+ }
+
+ /**
+ * Returns the unique Memory instance, which becomes in essence global.
*/
-
- public static void setConfiguration() {
- textBaseAddress = MemoryConfigurations.getCurrentConfiguration().getTextBaseAddress(); //0x00400000;
- dataSegmentBaseAddress = MemoryConfigurations.getCurrentConfiguration().getDataSegmentBaseAddress(); //0x10000000;
- externBaseAddress = MemoryConfigurations.getCurrentConfiguration().getExternBaseAddress(); //0x10000000;
- globalPointer = MemoryConfigurations.getCurrentConfiguration().getGlobalPointer(); //0x10008000;
- dataBaseAddress = MemoryConfigurations.getCurrentConfiguration().getDataBaseAddress(); //0x10010000; // from SPIM not MIPS
- heapBaseAddress = MemoryConfigurations.getCurrentConfiguration().getHeapBaseAddress(); //0x10040000; // I think from SPIM not MIPS
- stackPointer = MemoryConfigurations.getCurrentConfiguration().getStackPointer(); //0x7fffeffc;
- stackBaseAddress = MemoryConfigurations.getCurrentConfiguration().getStackBaseAddress(); //0x7ffffffc;
- userHighAddress = MemoryConfigurations.getCurrentConfiguration().getUserHighAddress(); //0x7fffffff;
- kernelBaseAddress = MemoryConfigurations.getCurrentConfiguration().getKernelBaseAddress(); //0x80000000;
- kernelTextBaseAddress = MemoryConfigurations.getCurrentConfiguration().getKernelTextBaseAddress(); //0x80000000;
- exceptionHandlerAddress = MemoryConfigurations.getCurrentConfiguration().getExceptionHandlerAddress(); //0x80000180;
- kernelDataBaseAddress = MemoryConfigurations.getCurrentConfiguration().getKernelDataBaseAddress(); //0x90000000;
- memoryMapBaseAddress = MemoryConfigurations.getCurrentConfiguration().getMemoryMapBaseAddress(); //0xffff0000;
- kernelHighAddress = MemoryConfigurations.getCurrentConfiguration().getKernelHighAddress(); //0xffffffff;
- dataSegmentLimitAddress = Math.min(MemoryConfigurations.getCurrentConfiguration().getDataSegmentLimitAddress(),
- dataSegmentBaseAddress +
- BLOCK_LENGTH_WORDS * BLOCK_TABLE_LENGTH * WORD_LENGTH_BYTES);
- textLimitAddress = Math.min(MemoryConfigurations.getCurrentConfiguration().getTextLimitAddress(),
- textBaseAddress +
- TEXT_BLOCK_LENGTH_WORDS * TEXT_BLOCK_TABLE_LENGTH * WORD_LENGTH_BYTES);
- kernelDataSegmentLimitAddress = Math.min(MemoryConfigurations.getCurrentConfiguration().getKernelDataSegmentLimitAddress(),
- kernelDataBaseAddress +
- BLOCK_LENGTH_WORDS * BLOCK_TABLE_LENGTH * WORD_LENGTH_BYTES);
- kernelTextLimitAddress = Math.min(MemoryConfigurations.getCurrentConfiguration().getKernelTextLimitAddress(),
- kernelTextBaseAddress +
- TEXT_BLOCK_LENGTH_WORDS * TEXT_BLOCK_TABLE_LENGTH * WORD_LENGTH_BYTES);
- stackLimitAddress = Math.max(MemoryConfigurations.getCurrentConfiguration().getStackLimitAddress(),
- stackBaseAddress -
- BLOCK_LENGTH_WORDS * BLOCK_TABLE_LENGTH * WORD_LENGTH_BYTES);
- memoryMapLimitAddress = Math.min(MemoryConfigurations.getCurrentConfiguration().getMemoryMapLimitAddress(),
- memoryMapBaseAddress +
- BLOCK_LENGTH_WORDS * MMIO_TABLE_LENGTH * WORD_LENGTH_BYTES);
+
+ public static Memory getInstance()
+ {
+ return uniqueMemoryInstance;
+ }
+
+ /**
+ * Sets current memory configuration for simulated MIPS. Configuration is collection of memory segment addresses.
+ * e.g. text segment starting at address 0x00400000. Configuration can be modified starting with MARS 3.7.
+ */
+
+ public static void setConfiguration()
+ {
+ textBaseAddress = MemoryConfigurations.getCurrentConfiguration().getTextBaseAddress(); //0x00400000;
+ dataSegmentBaseAddress = MemoryConfigurations.getCurrentConfiguration().getDataSegmentBaseAddress(); //0x10000000;
+ externBaseAddress = MemoryConfigurations.getCurrentConfiguration().getExternBaseAddress(); //0x10000000;
+ globalPointer = MemoryConfigurations.getCurrentConfiguration().getGlobalPointer(); //0x10008000;
+ dataBaseAddress = MemoryConfigurations.getCurrentConfiguration().getDataBaseAddress(); //0x10010000; // from SPIM not MIPS
+ heapBaseAddress = MemoryConfigurations.getCurrentConfiguration().getHeapBaseAddress(); //0x10040000; // I think from SPIM not MIPS
+ stackPointer = MemoryConfigurations.getCurrentConfiguration().getStackPointer(); //0x7fffeffc;
+ stackBaseAddress = MemoryConfigurations.getCurrentConfiguration().getStackBaseAddress(); //0x7ffffffc;
+ userHighAddress = MemoryConfigurations.getCurrentConfiguration().getUserHighAddress(); //0x7fffffff;
+ kernelBaseAddress = MemoryConfigurations.getCurrentConfiguration().getKernelBaseAddress(); //0x80000000;
+ kernelTextBaseAddress = MemoryConfigurations.getCurrentConfiguration().getKernelTextBaseAddress(); //0x80000000;
+ exceptionHandlerAddress = MemoryConfigurations.getCurrentConfiguration().getExceptionHandlerAddress(); //0x80000180;
+ kernelDataBaseAddress = MemoryConfigurations.getCurrentConfiguration().getKernelDataBaseAddress(); //0x90000000;
+ memoryMapBaseAddress = MemoryConfigurations.getCurrentConfiguration().getMemoryMapBaseAddress(); //0xffff0000;
+ kernelHighAddress = MemoryConfigurations.getCurrentConfiguration().getKernelHighAddress(); //0xffffffff;
+ dataSegmentLimitAddress = Math.min(MemoryConfigurations.getCurrentConfiguration().getDataSegmentLimitAddress(),
+ dataSegmentBaseAddress +
+ BLOCK_LENGTH_WORDS * BLOCK_TABLE_LENGTH * WORD_LENGTH_BYTES);
+ textLimitAddress = Math.min(MemoryConfigurations.getCurrentConfiguration().getTextLimitAddress(),
+ textBaseAddress +
+ TEXT_BLOCK_LENGTH_WORDS * TEXT_BLOCK_TABLE_LENGTH * WORD_LENGTH_BYTES);
+ kernelDataSegmentLimitAddress = Math.min(MemoryConfigurations.getCurrentConfiguration().getKernelDataSegmentLimitAddress(),
+ kernelDataBaseAddress +
+ BLOCK_LENGTH_WORDS * BLOCK_TABLE_LENGTH * WORD_LENGTH_BYTES);
+ kernelTextLimitAddress = Math.min(MemoryConfigurations.getCurrentConfiguration().getKernelTextLimitAddress(),
+ kernelTextBaseAddress +
+ TEXT_BLOCK_LENGTH_WORDS * TEXT_BLOCK_TABLE_LENGTH * WORD_LENGTH_BYTES);
+ stackLimitAddress = Math.max(MemoryConfigurations.getCurrentConfiguration().getStackLimitAddress(),
+ stackBaseAddress -
+ BLOCK_LENGTH_WORDS * BLOCK_TABLE_LENGTH * WORD_LENGTH_BYTES);
+ memoryMapLimitAddress = Math.min(MemoryConfigurations.getCurrentConfiguration().getMemoryMapLimitAddress(),
+ memoryMapBaseAddress +
+ BLOCK_LENGTH_WORDS * MMIO_TABLE_LENGTH * WORD_LENGTH_BYTES);
/* System.out.println("dataSegmentLimitAddress "+Binary.intToHexString(dataSegmentLimitAddress));
System.out.println("textLimitAddress "+Binary.intToHexString(textLimitAddress));
System.out.println("kernelDataSegmentLimitAddress "+Binary.intToHexString(kernelDataSegmentLimitAddress));
@@ -274,623 +312,845 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
System.out.println("stackLimitAddress "+Binary.intToHexString(stackLimitAddress));
System.out.println("memoryMapLimitAddress "+Binary.intToHexString(memoryMapLimitAddress));
*/
- }
-
-
+ }
+
/**
- * Determine whether the current memory configuration has a maximum address that can be stored
- * in 16 bits.
- * @return true if maximum address can be stored in 16 bits or less, false otherwise
- */
- public boolean usingCompactMemoryConfiguration() {
- return (kernelHighAddress & 0x00007fff) == kernelHighAddress;
- }
-
-
-
- private void initialize() {
- heapAddress = heapBaseAddress;
- textBlockTable = new ProgramStatement[TEXT_BLOCK_TABLE_LENGTH][];
- dataBlockTable = new int[BLOCK_TABLE_LENGTH][]; // array of null int[] references
- kernelTextBlockTable = new ProgramStatement[TEXT_BLOCK_TABLE_LENGTH][];
- kernelDataBlockTable = new int[BLOCK_TABLE_LENGTH][];
- stackBlockTable = new int[BLOCK_TABLE_LENGTH][];
- memoryMapBlockTable = new int[MMIO_TABLE_LENGTH][];
- System.gc(); // call garbage collector on any Table memory just deallocated.
- }
-
- /**
- * Returns the next available word-aligned heap address. There is no recycling and
- * no heap management! There is however nearly 4MB of heap space available in Mars.
- *
- * @param numBytes Number of bytes requested. Should be multiple of 4, otherwise next higher multiple of 4 allocated.
- * @return address of allocated heap storage.
- * @throws IllegalArgumentException if number of requested bytes is negative or exceeds available heap storage
- */
- public int allocateBytesFromHeap(int numBytes) throws IllegalArgumentException {
- int result = heapAddress;
- if (numBytes < 0) {
- throw new IllegalArgumentException("request ("+numBytes+") is negative heap amount");
- }
- int newHeapAddress = heapAddress + numBytes;
- if (newHeapAddress % 4 != 0) {
- newHeapAddress = newHeapAddress + (4 - newHeapAddress % 4) ; // next higher multiple of 4
- }
- if (newHeapAddress >= dataSegmentLimitAddress) {
- throw new IllegalArgumentException("request ("+numBytes+") exceeds available heap storage");
- }
- heapAddress = newHeapAddress;
- return result;
- }
-
-
- /**
- * Set byte order to either LITTLE_ENDIAN or BIG_ENDIAN. Default is LITTLE_ENDIAN.
- *
- * @param order either LITTLE_ENDIAN or BIG_ENDIAN
- */
- public void setByteOrder(boolean order) {
- byteOrder = order;
- }
-
- /**
- * Retrieve memory byte order. Default is LITTLE_ENDIAN (like PCs).
- *
- * @return either LITTLE_ENDIAN or BIG_ENDIAN
- */
- public boolean getByteOrder() {
- return byteOrder;
- }
-
-
- /* ******************************* THE SETTER METHODS ******************************/
-
-
+ * Utility to determine if given address is word-aligned.
+ *
+ * @param address the address to check
+ * @return true if address is word-aligned, false otherwise
+ */
+ public static boolean wordAligned(int address)
+ {
+ return (address % WORD_LENGTH_BYTES == 0);
+ }
+
+ /**
+ * Utility to determine if given address is doubleword-aligned.
+ *
+ * @param address the address to check
+ * @return true if address is doubleword-aligned, false otherwise
+ */
+ public static boolean doublewordAligned(int address)
+ {
+ return (address % (WORD_LENGTH_BYTES + WORD_LENGTH_BYTES) == 0);
+ }
+
+ /**
+ * Utility method to align given address to next full word boundary, if not already aligned.
+ *
+ * @param address a memory address (any int value is potentially valid)
+ * @return address aligned to next word boundary (divisible by 4)
+ */
+ public static int alignToWordBoundary(int address)
+ {
+ if (!wordAligned(address))
+ {
+ if (address > 0)
+ {
+ address += (4 - (address % WORD_LENGTH_BYTES));
+ }
+ else
+ {
+ address -= (4 - (address % WORD_LENGTH_BYTES));
+ }
+ }
+ return address;
+ }
+
+ /**
+ * Handy little utility to find out if given address is in MARS text segment (starts at Memory.textBaseAddress).
+ * Note that MARS does not implement the entire MIPS text segment space, but it does implement enough for hundreds
+ * of thousands of lines of code.
+ *
+ * @param address integer memory address
+ * @return true if that address is within MARS-defined text segment, false otherwise.
+ */
+ public static boolean inTextSegment(int address)
+ {
+ return address >= textBaseAddress && address < textLimitAddress;
+ }
+
+
+ /* ******************************* THE SETTER METHODS ******************************/
+
+
///////////////////////////////////////////////////////////////////////////////////////
- /**
- * Starting at the given address, write the given value over the given number of bytes.
- * This one does not check for word boundaries, and copies one byte at a time.
- * If length == 1, takes value from low order byte. If 2, takes from low order half-word.
- *
- * @param address Starting address of Memory address to be set.
- * @param value Value to be stored starting at that address.
- * @param length Number of bytes to be written.
- * @return old value that was replaced by the set operation
- **/
-
- // Allocates blocks if necessary.
- public int set(int address, int value, int length) throws AddressErrorException {
- int oldValue = 0;
- if (Globals.debug) System.out.println("memory["+address+"] set to "+value+"("+length+" bytes)");
- int relativeByteAddress;
- if (inDataSegment(address)) {
- // in data segment. Will write one byte at a time, w/o regard to boundaries.
+
+ /**
+ * Handy little utility to find out if given address is in MARS kernel text segment (starts at
+ * Memory.kernelTextBaseAddress).
+ *
+ * @param address integer memory address
+ * @return true if that address is within MARS-defined kernel text segment, false otherwise.
+ */
+ public static boolean inKernelTextSegment(int address)
+ {
+ return address >= kernelTextBaseAddress && address < kernelTextLimitAddress;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Handy little utility to find out if given address is in MARS data segment (starts at
+ * Memory.dataSegmentBaseAddress). Note that MARS does not implement the entire MIPS data segment space, but it does
+ * support at least 4MB.
+ *
+ * @param address integer memory address
+ * @return true if that address is within MARS-defined data segment, false otherwise.
+ */
+ public static boolean inDataSegment(int address)
+ {
+ return address >= dataSegmentBaseAddress && address < dataSegmentLimitAddress;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Handy little utility to find out if given address is in MARS kernel data segment (starts at
+ * Memory.kernelDataSegmentBaseAddress).
+ *
+ * @param address integer memory address
+ * @return true if that address is within MARS-defined kernel data segment, false otherwise.
+ */
+ public static boolean inKernelDataSegment(int address)
+ {
+ return address >= kernelDataBaseAddress && address < kernelDataSegmentLimitAddress;
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Handy little utility to find out if given address is in the Memory Map area starts at
+ * Memory.memoryMapBaseAddress, range 0xffff0000 to 0xffffffff.
+ *
+ * @param address integer memory address
+ * @return true if that address is within MARS-defined memory map (MMIO) area, false otherwise.
+ */
+ public static boolean inMemoryMapSegment(int address)
+ {
+ return address >= memoryMapBaseAddress && address < kernelHighAddress;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Explicitly clear the contents of memory. Typically done at start of assembly.
+ */
+
+ public void clear()
+ {
+ setConfiguration();
+ initialize();
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Determine whether the current memory configuration has a maximum address that can be stored in 16 bits.
+ *
+ * @return true if maximum address can be stored in 16 bits or less, false otherwise
+ */
+ public boolean usingCompactMemoryConfiguration()
+ {
+ return (kernelHighAddress & 0x00007fff) == kernelHighAddress;
+ }
+
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+ private void initialize()
+ {
+ heapAddress = heapBaseAddress;
+ textBlockTable = new ProgramStatement[TEXT_BLOCK_TABLE_LENGTH][];
+ dataBlockTable = new int[BLOCK_TABLE_LENGTH][]; // array of null int[] references
+ kernelTextBlockTable = new ProgramStatement[TEXT_BLOCK_TABLE_LENGTH][];
+ kernelDataBlockTable = new int[BLOCK_TABLE_LENGTH][];
+ stackBlockTable = new int[BLOCK_TABLE_LENGTH][];
+ memoryMapBlockTable = new int[MMIO_TABLE_LENGTH][];
+ System.gc(); // call garbage collector on any Table memory just deallocated.
+ }
+
+
+ /******************************** THE GETTER METHODS ******************************/
+
+ //////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Returns the next available word-aligned heap address. There is no recycling and no heap management! There is
+ * however nearly 4MB of heap space available in Mars.
+ *
+ * @param numBytes Number of bytes requested. Should be multiple of 4, otherwise next higher multiple of 4
+ * allocated.
+ * @return address of allocated heap storage.
+ * @throws IllegalArgumentException if number of requested bytes is negative or exceeds available heap storage
+ */
+ public int allocateBytesFromHeap(int numBytes) throws IllegalArgumentException
+ {
+ int result = heapAddress;
+ if (numBytes < 0)
+ {
+ throw new IllegalArgumentException("request (" + numBytes + ") is negative heap amount");
+ }
+ int newHeapAddress = heapAddress + numBytes;
+ if (newHeapAddress % 4 != 0)
+ {
+ newHeapAddress = newHeapAddress + (4 - newHeapAddress % 4); // next higher multiple of 4
+ }
+ if (newHeapAddress >= dataSegmentLimitAddress)
+ {
+ throw new IllegalArgumentException("request (" + numBytes + ") exceeds available heap storage");
+ }
+ heapAddress = newHeapAddress;
+ return result;
+ }
+
+ /**
+ * Retrieve memory byte order. Default is LITTLE_ENDIAN (like PCs).
+ *
+ * @return either LITTLE_ENDIAN or BIG_ENDIAN
+ */
+ public boolean getByteOrder()
+ {
+ return byteOrder;
+ }
+
+
+ /////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Set byte order to either LITTLE_ENDIAN or BIG_ENDIAN. Default is LITTLE_ENDIAN.
+ *
+ * @param order either LITTLE_ENDIAN or BIG_ENDIAN
+ */
+ public void setByteOrder(boolean order)
+ {
+ byteOrder = order;
+ }
+
+ /////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Starting at the given address, write the given value over the given number of bytes. This one does not check for
+ * word boundaries, and copies one byte at a time. If length == 1, takes value from low order byte. If 2, takes
+ * from low order half-word.
+ *
+ * @param address Starting address of Memory address to be set.
+ * @param value Value to be stored starting at that address.
+ * @param length Number of bytes to be written.
+ * @return old value that was replaced by the set operation
+ **/
+
+ // Allocates blocks if necessary.
+ public int set(int address, int value, int length) throws AddressErrorException
+ {
+ int oldValue = 0;
+ if (Globals.debug)
+ {
+ System.out.println("memory[" + address + "] set to " + value + "(" + length + " bytes)");
+ }
+ int relativeByteAddress;
+ if (inDataSegment(address))
+ {
+ // in data segment. Will write one byte at a time, w/o regard to boundaries.
relativeByteAddress = address - dataSegmentBaseAddress; // relative to data segment start, in bytes
oldValue = storeBytesInTable(dataBlockTable, relativeByteAddress, length, value);
- }
- else if (address > stackLimitAddress && address <= stackBaseAddress) {
- // in stack. Handle similarly to data segment write, except relative byte
- // address calculated "backward" because stack addresses grow down from base.
- relativeByteAddress = stackBaseAddress - address;
+ }
+ else if (address > stackLimitAddress && address <= stackBaseAddress)
+ {
+ // in stack. Handle similarly to data segment write, except relative byte
+ // address calculated "backward" because stack addresses grow down from base.
+ relativeByteAddress = stackBaseAddress - address;
oldValue = storeBytesInTable(stackBlockTable, relativeByteAddress, length, value);
- }
- else if (inTextSegment(address)) {
- // Burch Mod (Jan 2013): replace throw with call to setStatement
- // DPS adaptation 5-Jul-2013: either throw or call, depending on setting
-
- if (Globals.getSettings().getBooleanSetting(Settings.SELF_MODIFYING_CODE_ENABLED)) {
- ProgramStatement oldStatement = getStatementNoNotify(address);
- if (oldStatement != null) {
- oldValue = oldStatement.getBinaryStatement();
- }
- setStatement(address, new ProgramStatement(value, address));
- }
- else {
- throw new AddressErrorException(
- "Cannot write directly to text segment!",
- Exceptions.ADDRESS_EXCEPTION_STORE, address);
+ }
+ else if (inTextSegment(address))
+ {
+ // Burch Mod (Jan 2013): replace throw with call to setStatement
+ // DPS adaptation 5-Jul-2013: either throw or call, depending on setting
+
+ if (Globals.getSettings().getBooleanSetting(Settings.SELF_MODIFYING_CODE_ENABLED))
+ {
+ ProgramStatement oldStatement = getStatementNoNotify(address);
+ if (oldStatement != null)
+ {
+ oldValue = oldStatement.getBinaryStatement();
+ }
+ setStatement(address, new ProgramStatement(value, address));
}
- }
- else if (address >= memoryMapBaseAddress && address < memoryMapLimitAddress) {
- // memory mapped I/O.
+ else
+ {
+ throw new AddressErrorException(
+ "Cannot write directly to text segment!",
+ Exceptions.ADDRESS_EXCEPTION_STORE, address);
+ }
+ }
+ else if (address >= memoryMapBaseAddress && address < memoryMapLimitAddress)
+ {
+ // memory mapped I/O.
relativeByteAddress = address - memoryMapBaseAddress;
oldValue = storeBytesInTable(memoryMapBlockTable, relativeByteAddress, length, value);
- }
- else if (inKernelDataSegment(address)) {
- // in kernel data segment. Will write one byte at a time, w/o regard to boundaries.
+ }
+ else if (inKernelDataSegment(address))
+ {
+ // in kernel data segment. Will write one byte at a time, w/o regard to boundaries.
relativeByteAddress = address - kernelDataBaseAddress; // relative to data segment start, in bytes
oldValue = storeBytesInTable(kernelDataBlockTable, relativeByteAddress, length, value);
- }
- else if (inKernelTextSegment(address)) {
- // DEVELOPER: PLEASE USE setStatement() TO WRITE TO KERNEL TEXT SEGMENT...
+ }
+ else if (inKernelTextSegment(address))
+ {
+ // DEVELOPER: PLEASE USE setStatement() TO WRITE TO KERNEL TEXT SEGMENT...
throw new AddressErrorException(
- "DEVELOPER: You must use setStatement() to write to kernel text segment!",
- Exceptions.ADDRESS_EXCEPTION_STORE, address);
- }
- else {
- // falls outside Mars addressing range
+ "DEVELOPER: You must use setStatement() to write to kernel text segment!",
+ Exceptions.ADDRESS_EXCEPTION_STORE, address);
+ }
+ else
+ {
+ // falls outside Mars addressing range
throw new AddressErrorException("address out of range ",
- Exceptions.ADDRESS_EXCEPTION_STORE, address);
- }
- notifyAnyObservers(AccessNotice.WRITE, address, length, value);
- return oldValue;
- }
-
- ///////////////////////////////////////////////////////////////////////////////////////
- /**
- * Starting at the given word address, write the given value over 4 bytes (a word).
- * It must be written as is, without adjusting for byte order (little vs big endian).
- * Address must be word-aligned.
- *
+ Exceptions.ADDRESS_EXCEPTION_STORE, address);
+ }
+ notifyAnyObservers(AccessNotice.WRITE, address, length, value);
+ return oldValue;
+ }
+
+ /**
+ * Starting at the given word address, write the given value over 4 bytes (a word). It must be written as is,
+ * without adjusting for byte order (little vs big endian). Address must be word-aligned.
+ *
* @param address Starting address of Memory address to be set.
* @param value Value to be stored starting at that address.
* @return old value that was replaced by the set operation.
* @throws AddressErrorException If address is not on word boundary.
- **/
- public int setRawWord(int address, int value) throws AddressErrorException {
- int relative, oldValue=0;
- if (address % WORD_LENGTH_BYTES != 0) {
+ **/
+ public int setRawWord(int address, int value) throws AddressErrorException
+ {
+ int relative, oldValue = 0;
+ if (address % WORD_LENGTH_BYTES != 0)
+ {
throw new AddressErrorException("store address not aligned on word boundary ",
- Exceptions.ADDRESS_EXCEPTION_STORE, address);
- }
- if (inDataSegment(address)) {
- // in data segment
+ Exceptions.ADDRESS_EXCEPTION_STORE, address);
+ }
+ if (inDataSegment(address))
+ {
+ // in data segment
relative = (address - dataSegmentBaseAddress) >> 2; // convert byte address to words
oldValue = storeWordInTable(dataBlockTable, relative, value);
- }
- else if (address > stackLimitAddress && address <= stackBaseAddress) {
- // in stack. Handle similarly to data segment write, except relative
- // address calculated "backward" because stack addresses grow down from base.
+ }
+ else if (address > stackLimitAddress && address <= stackBaseAddress)
+ {
+ // in stack. Handle similarly to data segment write, except relative
+ // address calculated "backward" because stack addresses grow down from base.
relative = (stackBaseAddress - address) >> 2; // convert byte address to words
oldValue = storeWordInTable(stackBlockTable, relative, value);
- }
- else if (inTextSegment(address)) {
- // Burch Mod (Jan 2013): replace throw with call to setStatement
- // DPS adaptation 5-Jul-2013: either throw or call, depending on setting
- if (Globals.getSettings().getBooleanSetting(Settings.SELF_MODIFYING_CODE_ENABLED)) {
- ProgramStatement oldStatement = getStatementNoNotify(address);
- if (oldStatement != null) {
- oldValue = oldStatement.getBinaryStatement();
- }
- setStatement(address, new ProgramStatement(value, address));
- }
- else {
- throw new AddressErrorException(
- "Cannot write directly to text segment!",
- Exceptions.ADDRESS_EXCEPTION_STORE, address);
+ }
+ else if (inTextSegment(address))
+ {
+ // Burch Mod (Jan 2013): replace throw with call to setStatement
+ // DPS adaptation 5-Jul-2013: either throw or call, depending on setting
+ if (Globals.getSettings().getBooleanSetting(Settings.SELF_MODIFYING_CODE_ENABLED))
+ {
+ ProgramStatement oldStatement = getStatementNoNotify(address);
+ if (oldStatement != null)
+ {
+ oldValue = oldStatement.getBinaryStatement();
+ }
+ setStatement(address, new ProgramStatement(value, address));
}
- }
- else if (address >= memoryMapBaseAddress && address < memoryMapLimitAddress) {
- // memory mapped I/O.
+ else
+ {
+ throw new AddressErrorException(
+ "Cannot write directly to text segment!",
+ Exceptions.ADDRESS_EXCEPTION_STORE, address);
+ }
+ }
+ else if (address >= memoryMapBaseAddress && address < memoryMapLimitAddress)
+ {
+ // memory mapped I/O.
relative = (address - memoryMapBaseAddress) >> 2; // convert byte address to word
oldValue = storeWordInTable(memoryMapBlockTable, relative, value);
- }
- else if (inKernelDataSegment(address)) {
- // in data segment
+ }
+ else if (inKernelDataSegment(address))
+ {
+ // in data segment
relative = (address - kernelDataBaseAddress) >> 2; // convert byte address to words
oldValue = storeWordInTable(kernelDataBlockTable, relative, value);
- }
- else if (inKernelTextSegment(address)) {
- // DEVELOPER: PLEASE USE setStatement() TO WRITE TO KERNEL TEXT SEGMENT...
+ }
+ else if (inKernelTextSegment(address))
+ {
+ // DEVELOPER: PLEASE USE setStatement() TO WRITE TO KERNEL TEXT SEGMENT...
throw new AddressErrorException(
- "DEVELOPER: You must use setStatement() to write to kernel text segment!",
- Exceptions.ADDRESS_EXCEPTION_STORE, address);
- }
- else {
- // falls outside Mars addressing range
+ "DEVELOPER: You must use setStatement() to write to kernel text segment!",
+ Exceptions.ADDRESS_EXCEPTION_STORE, address);
+ }
+ else
+ {
+ // falls outside Mars addressing range
throw new AddressErrorException("store address out of range ",
- Exceptions.ADDRESS_EXCEPTION_STORE, address);
- }
- notifyAnyObservers(AccessNotice.WRITE, address, WORD_LENGTH_BYTES, value);
- if (Globals.getSettings().getBackSteppingEnabled()) {
- Globals.program.getBackStepper().addMemoryRestoreRawWord(address,oldValue);
- }
- return oldValue;
- }
-
+ Exceptions.ADDRESS_EXCEPTION_STORE, address);
+ }
+ notifyAnyObservers(AccessNotice.WRITE, address, WORD_LENGTH_BYTES, value);
+ if (Globals.getSettings().getBackSteppingEnabled())
+ {
+ Globals.program.getBackStepper().addMemoryRestoreRawWord(address, oldValue);
+ }
+ return oldValue;
+ }
+
+
///////////////////////////////////////////////////////////////////////////////////////
- /**
- * Starting at the given word address, write the given value over 4 bytes (a word).
- * The address must be word-aligned.
- *
+
+ /**
+ * Starting at the given word address, write the given value over 4 bytes (a word). The address must be
+ * word-aligned.
+ *
* @param address Starting address of Memory address to be set.
* @param value Value to be stored starting at that address.
* @return old value that was replaced by setWord operation.
* @throws AddressErrorException If address is not on word boundary.
- **/
- public int setWord(int address, int value) throws AddressErrorException {
- if (address % WORD_LENGTH_BYTES != 0) {
+ **/
+ public int setWord(int address, int value) throws AddressErrorException
+ {
+ if (address % WORD_LENGTH_BYTES != 0)
+ {
throw new AddressErrorException(
- "store address not aligned on word boundary ",
- Exceptions.ADDRESS_EXCEPTION_STORE,address);
- }
- return (Globals.getSettings().getBackSteppingEnabled())
- ? Globals.program.getBackStepper().addMemoryRestoreWord(address,set(address, value, WORD_LENGTH_BYTES))
+ "store address not aligned on word boundary ",
+ Exceptions.ADDRESS_EXCEPTION_STORE, address);
+ }
+ return (Globals.getSettings().getBackSteppingEnabled())
+ ? Globals.program.getBackStepper().addMemoryRestoreWord(address, set(address, value, WORD_LENGTH_BYTES))
: set(address, value, WORD_LENGTH_BYTES);
- }
-
-
+ }
+
///////////////////////////////////////////////////////////////////////////////////////
- /**
- * Starting at the given halfword address, write the lower 16 bits of given value
- * into 2 bytes (a halfword).
- *
+
+ /**
+ * Starting at the given halfword address, write the lower 16 bits of given value into 2 bytes (a halfword).
+ *
* @param address Starting address of Memory address to be set.
* @param value Value to be stored starting at that address. Only low order 16 bits used.
* @return old value that was replaced by setHalf operation.
* @throws AddressErrorException If address is not on halfword boundary.
- **/
- public int setHalf(int address, int value) throws AddressErrorException {
- if (address % 2 != 0) {
+ **/
+ public int setHalf(int address, int value) throws AddressErrorException
+ {
+ if (address % 2 != 0)
+ {
throw new AddressErrorException("store address not aligned on halfword boundary ",
- Exceptions.ADDRESS_EXCEPTION_STORE, address);
- }
- return (Globals.getSettings().getBackSteppingEnabled())
- ? Globals.program.getBackStepper().addMemoryRestoreHalf(address,set(address,value,2))
+ Exceptions.ADDRESS_EXCEPTION_STORE, address);
+ }
+ return (Globals.getSettings().getBackSteppingEnabled())
+ ? Globals.program.getBackStepper().addMemoryRestoreHalf(address, set(address, value, 2))
: set(address, value, 2);
- }
-
+ }
+
+
///////////////////////////////////////////////////////////////////////////////////////
- /**
- * Writes low order 8 bits of given value into specified Memory byte.
- *
+
+ /**
+ * Writes low order 8 bits of given value into specified Memory byte.
+ *
* @param address Address of Memory byte to be set.
* @param value Value to be stored at that address. Only low order 8 bits used.
* @return old value that was replaced by setByte operation.
**/
-
- public int setByte(int address, int value) throws AddressErrorException {
- return (Globals.getSettings().getBackSteppingEnabled())
- ? Globals.program.getBackStepper().addMemoryRestoreByte(address,set(address,value,1))
+
+ public int setByte(int address, int value) throws AddressErrorException
+ {
+ return (Globals.getSettings().getBackSteppingEnabled())
+ ? Globals.program.getBackStepper().addMemoryRestoreByte(address, set(address, value, 1))
: set(address, value, 1);
- }
-
+ }
+
+
///////////////////////////////////////////////////////////////////////////////////////
- /**
- * Writes 64 bit double value starting at specified Memory address. Note that
- * high-order 32 bits are stored in higher (second) memory word regardless
- * of "endianness".
- *
+
+ /**
+ * Writes 64 bit double value starting at specified Memory address. Note that high-order 32 bits are stored in
+ * higher (second) memory word regardless of "endianness".
+ *
* @param address Starting address of Memory address to be set.
- * @param value Value to be stored at that address.
+ * @param value Value to be stored at that address.
* @return old value that was replaced by setDouble operation.
- **/
- public double setDouble(int address, double value) throws AddressErrorException {
- int oldHighOrder, oldLowOrder;
- long longValue = Double.doubleToLongBits(value);
- oldHighOrder = set(address+4, Binary.highOrderLongToInt(longValue),4);
- oldLowOrder = set(address, Binary.lowOrderLongToInt(longValue),4);
- return Double.longBitsToDouble(Binary.twoIntsToLong(oldHighOrder, oldLowOrder));
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- /**
- * Stores ProgramStatement in Text Segment.
- * @param address Starting address of Memory address to be set. Must be word boundary.
- * @param statement Machine code to be stored starting at that address -- for simulation
- * purposes, actually stores reference to ProgramStatement instead of 32-bit machine code.
- * @throws AddressErrorException If address is not on word boundary or is outside Text Segment.
- * @see ProgramStatement
- **/
-
- public void setStatement(int address, ProgramStatement statement) throws AddressErrorException {
- if (address % 4 != 0 || !(inTextSegment(address) || inKernelTextSegment(address))) {
+ **/
+ public double setDouble(int address, double value) throws AddressErrorException
+ {
+ int oldHighOrder, oldLowOrder;
+ long longValue = Double.doubleToLongBits(value);
+ oldHighOrder = set(address + 4, Binary.highOrderLongToInt(longValue), 4);
+ oldLowOrder = set(address, Binary.lowOrderLongToInt(longValue), 4);
+ return Double.longBitsToDouble(Binary.twoIntsToLong(oldHighOrder, oldLowOrder));
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Stores ProgramStatement in Text Segment.
+ *
+ * @param address Starting address of Memory address to be set. Must be word boundary.
+ * @param statement Machine code to be stored starting at that address -- for simulation purposes, actually
+ * stores reference to ProgramStatement instead of 32-bit machine code.
+ * @throws AddressErrorException If address is not on word boundary or is outside Text Segment.
+ * @see ProgramStatement
+ **/
+
+ public void setStatement(int address, ProgramStatement statement) throws AddressErrorException
+ {
+ if (address % 4 != 0 || !(inTextSegment(address) || inKernelTextSegment(address)))
+ {
throw new AddressErrorException(
- "store address to text segment out of range or not aligned to word boundary ",
- Exceptions.ADDRESS_EXCEPTION_STORE, address);
- }
- if (Globals.debug) System.out.println("memory["+address+"] set to "+statement.getBinaryStatement());
- if (inTextSegment(address)) {
+ "store address to text segment out of range or not aligned to word boundary ",
+ Exceptions.ADDRESS_EXCEPTION_STORE, address);
+ }
+ if (Globals.debug)
+ {
+ System.out.println("memory[" + address + "] set to " + statement.getBinaryStatement());
+ }
+ if (inTextSegment(address))
+ {
storeProgramStatement(address, statement, textBaseAddress, textBlockTable);
- }
- else {
+ }
+ else
+ {
storeProgramStatement(address, statement, kernelTextBaseAddress, kernelTextBlockTable);
- }
- }
-
-
-
- /******************************** THE GETTER METHODS ******************************/
-
- //////////////////////////////////////////////////////////////////////////////////////////
- /**
- * Starting at the given word address, read the given number of bytes (max 4).
- * This one does not check for word boundaries, and copies one byte at a time.
- * If length == 1, puts value in low order byte. If 2, puts into low order half-word.
- * @param address Starting address of Memory address to be read.
- * @param length Number of bytes to be read.
- * @return Value stored starting at that address.
- **/
-
- public int get(int address, int length) throws AddressErrorException {
- return get(address, length, true);
- }
-
- // Does the real work, but includes option to NOT notify observers.
- private int get(int address, int length, boolean notify) throws AddressErrorException {
- int value = 0;
- int relativeByteAddress;
- if (inDataSegment(address)) {
- // in data segment. Will read one byte at a time, w/o regard to boundaries.
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Starting at the given word address, read the given number of bytes (max 4). This one does not check for word
+ * boundaries, and copies one byte at a time. If length == 1, puts value in low order byte. If 2, puts into low
+ * order half-word.
+ *
+ * @param address Starting address of Memory address to be read.
+ * @param length Number of bytes to be read.
+ * @return Value stored starting at that address.
+ **/
+
+ public int get(int address, int length) throws AddressErrorException
+ {
+ return get(address, length, true);
+ }
+
+ //////////
+
+ // Does the real work, but includes option to NOT notify observers.
+ private int get(int address, int length, boolean notify) throws AddressErrorException
+ {
+ int value = 0;
+ int relativeByteAddress;
+ if (inDataSegment(address))
+ {
+ // in data segment. Will read one byte at a time, w/o regard to boundaries.
relativeByteAddress = address - dataSegmentBaseAddress; // relative to data segment start, in bytes
value = fetchBytesFromTable(dataBlockTable, relativeByteAddress, length);
- }
- else if (address > stackLimitAddress && address <= stackBaseAddress) {
- // in stack. Similar to data, except relative address computed "backward"
+ }
+ else if (address > stackLimitAddress && address <= stackBaseAddress)
+ {
+ // in stack. Similar to data, except relative address computed "backward"
relativeByteAddress = stackBaseAddress - address;
value = fetchBytesFromTable(stackBlockTable, relativeByteAddress, length);
- }
-
- else if (address >= memoryMapBaseAddress && address < memoryMapLimitAddress) {
- // memory mapped I/O.
+ }
+
+ else if (address >= memoryMapBaseAddress && address < memoryMapLimitAddress)
+ {
+ // memory mapped I/O.
relativeByteAddress = address - memoryMapBaseAddress;
value = fetchBytesFromTable(memoryMapBlockTable, relativeByteAddress, length);
- }
- else if (inTextSegment(address)) {
- // Burch Mod (Jan 2013): replace throw with calls to getStatementNoNotify & getBinaryStatement
- // DPS adaptation 5-Jul-2013: either throw or call, depending on setting
- if (Globals.getSettings().getBooleanSetting(Settings.SELF_MODIFYING_CODE_ENABLED)) {
- ProgramStatement stmt = getStatementNoNotify(address);
- value = stmt == null ? 0 : stmt.getBinaryStatement();
- }
- else {
- throw new AddressErrorException(
- "Cannot read directly from text segment!",
- Exceptions.ADDRESS_EXCEPTION_LOAD, address);
+ }
+ else if (inTextSegment(address))
+ {
+ // Burch Mod (Jan 2013): replace throw with calls to getStatementNoNotify & getBinaryStatement
+ // DPS adaptation 5-Jul-2013: either throw or call, depending on setting
+ if (Globals.getSettings().getBooleanSetting(Settings.SELF_MODIFYING_CODE_ENABLED))
+ {
+ ProgramStatement stmt = getStatementNoNotify(address);
+ value = stmt == null ? 0 : stmt.getBinaryStatement();
}
- }
- else if (inKernelDataSegment(address)) {
- // in kernel data segment. Will read one byte at a time, w/o regard to boundaries.
+ else
+ {
+ throw new AddressErrorException(
+ "Cannot read directly from text segment!",
+ Exceptions.ADDRESS_EXCEPTION_LOAD, address);
+ }
+ }
+ else if (inKernelDataSegment(address))
+ {
+ // in kernel data segment. Will read one byte at a time, w/o regard to boundaries.
relativeByteAddress = address - kernelDataBaseAddress; // relative to data segment start, in bytes
value = fetchBytesFromTable(kernelDataBlockTable, relativeByteAddress, length);
- }
- else if (inKernelTextSegment(address)) {
- // DEVELOPER: PLEASE USE getStatement() TO READ FROM KERNEL TEXT SEGMENT...
+ }
+ else if (inKernelTextSegment(address))
+ {
+ // DEVELOPER: PLEASE USE getStatement() TO READ FROM KERNEL TEXT SEGMENT...
throw new AddressErrorException(
- "DEVELOPER: You must use getStatement() to read from kernel text segment!",
- Exceptions.ADDRESS_EXCEPTION_LOAD, address);
- }
- else {
- // falls outside Mars addressing range
+ "DEVELOPER: You must use getStatement() to read from kernel text segment!",
+ Exceptions.ADDRESS_EXCEPTION_LOAD, address);
+ }
+ else
+ {
+ // falls outside Mars addressing range
throw new AddressErrorException("address out of range ",
- Exceptions.ADDRESS_EXCEPTION_LOAD, address);
- }
- if (notify) notifyAnyObservers(AccessNotice.READ, address, length, value);
- return value;
- }
-
-
- /////////////////////////////////////////////////////////////////////////
- /**
- * Starting at the given word address, read a 4 byte word as an int.
- * It transfers the 32 bit value "raw" as stored in memory, and does not adjust
- * for byte order (big or little endian). Address must be word-aligned.
- *
+ Exceptions.ADDRESS_EXCEPTION_LOAD, address);
+ }
+ if (notify)
+ {
+ notifyAnyObservers(AccessNotice.READ, address, length, value);
+ }
+ return value;
+ }
+
+
+ /********************************* THE UTILITIES *************************************/
+
+ /**
+ * Starting at the given word address, read a 4 byte word as an int. It transfers the 32 bit value "raw" as stored
+ * in memory, and does not adjust for byte order (big or little endian). Address must be word-aligned.
+ *
* @param address Starting address of word to be read.
- * @return Word (4-byte value) stored starting at that address.
+ * @return Word (4-byte value) stored starting at that address.
* @throws AddressErrorException If address is not on word boundary.
- **/
-
+ **/
+
// Note: the logic here is repeated in getRawWordOrNull() below. Logic is
- // simplified by having this method just call getRawWordOrNull() then
+ // simplified by having this method just call getRawWordOrNull() then
// return either the int of its return value, or 0 if it returns null.
// Doing so would be detrimental to simulation runtime performance, so
// I decided to keep the duplicate logic.
- public int getRawWord(int address) throws AddressErrorException {
- int value = 0;
- int relative;
- if (address % WORD_LENGTH_BYTES != 0) {
+ public int getRawWord(int address) throws AddressErrorException
+ {
+ int value = 0;
+ int relative;
+ if (address % WORD_LENGTH_BYTES != 0)
+ {
throw new AddressErrorException("address for fetch not aligned on word boundary",
- Exceptions.ADDRESS_EXCEPTION_LOAD, address);
- }
- if (inDataSegment(address)) {
- // in data segment
+ Exceptions.ADDRESS_EXCEPTION_LOAD, address);
+ }
+ if (inDataSegment(address))
+ {
+ // in data segment
relative = (address - dataSegmentBaseAddress) >> 2; // convert byte address to words
value = fetchWordFromTable(dataBlockTable, relative);
- }
- else if (address > stackLimitAddress && address <= stackBaseAddress) {
- // in stack. Similar to data, except relative address computed "backward"
+ }
+ else if (address > stackLimitAddress && address <= stackBaseAddress)
+ {
+ // in stack. Similar to data, except relative address computed "backward"
relative = (stackBaseAddress - address) >> 2; // convert byte address to words
value = fetchWordFromTable(stackBlockTable, relative);
- }
- else if (address >= memoryMapBaseAddress && address < memoryMapLimitAddress) {
- // memory mapped I/O.
+ }
+ else if (address >= memoryMapBaseAddress && address < memoryMapLimitAddress)
+ {
+ // memory mapped I/O.
relative = (address - memoryMapBaseAddress) >> 2;
value = fetchWordFromTable(memoryMapBlockTable, relative);
- }
- else if (inTextSegment(address)) {
- // Burch Mod (Jan 2013): replace throw with calls to getStatementNoNotify & getBinaryStatement
- // DPS adaptation 5-Jul-2013: either throw or call, depending on setting
- if (Globals.getSettings().getBooleanSetting(Settings.SELF_MODIFYING_CODE_ENABLED)) {
- ProgramStatement stmt = getStatementNoNotify(address);
- value = stmt == null ? 0 : stmt.getBinaryStatement();
- }
- else {
- throw new AddressErrorException(
- "Cannot read directly from text segment!",
- Exceptions.ADDRESS_EXCEPTION_LOAD, address);
+ }
+ else if (inTextSegment(address))
+ {
+ // Burch Mod (Jan 2013): replace throw with calls to getStatementNoNotify & getBinaryStatement
+ // DPS adaptation 5-Jul-2013: either throw or call, depending on setting
+ if (Globals.getSettings().getBooleanSetting(Settings.SELF_MODIFYING_CODE_ENABLED))
+ {
+ ProgramStatement stmt = getStatementNoNotify(address);
+ value = stmt == null ? 0 : stmt.getBinaryStatement();
}
- }
- else if (inKernelDataSegment(address)) {
- // in kernel data segment
+ else
+ {
+ throw new AddressErrorException(
+ "Cannot read directly from text segment!",
+ Exceptions.ADDRESS_EXCEPTION_LOAD, address);
+ }
+ }
+ else if (inKernelDataSegment(address))
+ {
+ // in kernel data segment
relative = (address - kernelDataBaseAddress) >> 2; // convert byte address to words
value = fetchWordFromTable(kernelDataBlockTable, relative);
- }
- else if (inKernelTextSegment(address)) {
- // DEVELOPER: PLEASE USE getStatement() TO READ FROM KERNEL TEXT SEGMENT...
+ }
+ else if (inKernelTextSegment(address))
+ {
+ // DEVELOPER: PLEASE USE getStatement() TO READ FROM KERNEL TEXT SEGMENT...
throw new AddressErrorException(
- "DEVELOPER: You must use getStatement() to read from kernel text segment!",
- Exceptions.ADDRESS_EXCEPTION_LOAD, address);
- }
- else {
- // falls outside Mars addressing range
- throw new AddressErrorException("address out of range ",
- Exceptions.ADDRESS_EXCEPTION_LOAD, address);
- }
- notifyAnyObservers(AccessNotice.READ, address, Memory.WORD_LENGTH_BYTES,value);
- return value;
- }
-
- /////////////////////////////////////////////////////////////////////////
- /**
- * Starting at the given word address, read a 4 byte word as an int and return Integer.
- * It transfers the 32 bit value "raw" as stored in memory, and does not adjust
- * for byte order (big or little endian). Address must be word-aligned.
- *
- * Returns null if reading from text segment and there is no instruction at the
- * requested address. Returns null if reading from data segment and this is the
- * first reference to the MARS 4K memory allocation block (i.e., an array to
- * hold the memory has not been allocated).
- *
- * This method was developed by Greg Giberling of UC Berkeley to support the memory
- * dump feature that he implemented in Fall 2007.
- *
- * @param address Starting address of word to be read.
- * @return Word (4-byte value) stored starting at that address as an Integer. Conditions
- * that cause return value null are described above.
- * @throws AddressErrorException If address is not on word boundary.
- **/
-
- // See note above, with getRawWord(), concerning duplicated logic.
-
- public Integer getRawWordOrNull(int address) throws AddressErrorException {
- Integer value = null;
- int relative;
- if (address % WORD_LENGTH_BYTES != 0) {
+ "DEVELOPER: You must use getStatement() to read from kernel text segment!",
+ Exceptions.ADDRESS_EXCEPTION_LOAD, address);
+ }
+ else
+ {
+ // falls outside Mars addressing range
+ throw new AddressErrorException("address out of range ",
+ Exceptions.ADDRESS_EXCEPTION_LOAD, address);
+ }
+ notifyAnyObservers(AccessNotice.READ, address, Memory.WORD_LENGTH_BYTES, value);
+ return value;
+ }
+
+ /**
+ * Starting at the given word address, read a 4 byte word as an int and return Integer. It transfers the 32 bit
+ * value "raw" as stored in memory, and does not adjust for byte order (big or little endian). Address must be
+ * word-aligned.
+ *
+ * Returns null if reading from text segment and there is no instruction at the requested address. Returns null if
+ * reading from data segment and this is the first reference to the MARS 4K memory allocation block (i.e., an array
+ * to hold the memory has not been allocated).
+ *
+ * This method was developed by Greg Giberling of UC Berkeley to support the memory dump feature that he implemented
+ * in Fall 2007.
+ *
+ * @param address Starting address of word to be read.
+ * @return Word (4-byte value) stored starting at that address as an Integer. Conditions that cause return value
+ * null are described above.
+ * @throws AddressErrorException If address is not on word boundary.
+ **/
+
+ // See note above, with getRawWord(), concerning duplicated logic.
+ public Integer getRawWordOrNull(int address) throws AddressErrorException
+ {
+ Integer value = null;
+ int relative;
+ if (address % WORD_LENGTH_BYTES != 0)
+ {
throw new AddressErrorException("address for fetch not aligned on word boundary",
- Exceptions.ADDRESS_EXCEPTION_LOAD, address);
- }
- if (inDataSegment(address)) {
- // in data segment
+ Exceptions.ADDRESS_EXCEPTION_LOAD, address);
+ }
+ if (inDataSegment(address))
+ {
+ // in data segment
relative = (address - dataSegmentBaseAddress) >> 2; // convert byte address to words
value = fetchWordOrNullFromTable(dataBlockTable, relative);
- }
- else if (address > stackLimitAddress && address <= stackBaseAddress) {
- // in stack. Similar to data, except relative address computed "backward"
+ }
+ else if (address > stackLimitAddress && address <= stackBaseAddress)
+ {
+ // in stack. Similar to data, except relative address computed "backward"
relative = (stackBaseAddress - address) >> 2; // convert byte address to words
value = fetchWordOrNullFromTable(stackBlockTable, relative);
- }
- else if (inTextSegment(address) || inKernelTextSegment(address)) {
- try {
- value = (getStatementNoNotify(address) == null) ? null : getStatementNoNotify(address).getBinaryStatement();
- } catch (AddressErrorException aee) {
- value = null;
- }
- }
- else if (inKernelDataSegment(address)) {
- // in kernel data segment
+ }
+ else if (inTextSegment(address) || inKernelTextSegment(address))
+ {
+ try
+ {
+ value = (getStatementNoNotify(address) == null) ? null : getStatementNoNotify(address).getBinaryStatement();
+ }
+ catch (AddressErrorException aee)
+ {
+ value = null;
+ }
+ }
+ else if (inKernelDataSegment(address))
+ {
+ // in kernel data segment
relative = (address - kernelDataBaseAddress) >> 2; // convert byte address to words
value = fetchWordOrNullFromTable(kernelDataBlockTable, relative);
- }
- else {
- // falls outside Mars addressing range
+ }
+ else
+ {
+ // falls outside Mars addressing range
throw new AddressErrorException("address out of range ", Exceptions.ADDRESS_EXCEPTION_LOAD, address);
- }
- // Do not notify observers. This read operation is initiated by the
- // dump feature, not the executing MIPS program.
- return value;
- }
-
- /**
- * Look for first "null" memory value in an address range. For text segment (binary code), this
- * represents a word that does not contain an instruction. Normally use this to find the end of
- * the program. For data segment, this represents the first block of simulated memory (block length
- * currently 4K words) that has not been referenced by an assembled/executing program.
- *
- * @param baseAddress lowest MIPS address to be searched; the starting point
- * @param limitAddress highest MIPS address to be searched
- * @return lowest address within specified range that contains "null" value as described above.
- * @throws AddressErrorException if the base address is not on a word boundary
- */
- public int getAddressOfFirstNull(int baseAddress, int limitAddress) throws AddressErrorException {
- int address = baseAddress;
- for (; address < limitAddress; address += Memory.WORD_LENGTH_BYTES) {
- if (getRawWordOrNull(address) == null) {
- break;
+ }
+ // Do not notify observers. This read operation is initiated by the
+ // dump feature, not the executing MIPS program.
+ return value;
+ }
+
+ /**
+ * Look for first "null" memory value in an address range. For text segment (binary code), this represents a word
+ * that does not contain an instruction. Normally use this to find the end of the program. For data segment, this
+ * represents the first block of simulated memory (block length currently 4K words) that has not been referenced by
+ * an assembled/executing program.
+ *
+ * @param baseAddress lowest MIPS address to be searched; the starting point
+ * @param limitAddress highest MIPS address to be searched
+ * @return lowest address within specified range that contains "null" value as described above.
+ * @throws AddressErrorException if the base address is not on a word boundary
+ */
+ public int getAddressOfFirstNull(int baseAddress, int limitAddress) throws AddressErrorException
+ {
+ int address = baseAddress;
+ for (; address < limitAddress; address += Memory.WORD_LENGTH_BYTES)
+ {
+ if (getRawWordOrNull(address) == null)
+ {
+ break;
}
- }
- return address;
- }
-
-
- ///////////////////////////////////////////////////////////////////////////////////////
- /**
- * Starting at the given word address, read a 4 byte word as an int.
- * Does not use "get()"; we can do it faster here knowing we're working only
- * with full words.
- *
+ }
+ return address;
+ }
+
+ /**
+ * Starting at the given word address, read a 4 byte word as an int. Does not use "get()"; we can do it faster here
+ * knowing we're working only with full words.
+ *
* @param address Starting address of word to be read.
- * @return Word (4-byte value) stored starting at that address.
+ * @return Word (4-byte value) stored starting at that address.
* @throws AddressErrorException If address is not on word boundary.
- **/
- public int getWord(int address) throws AddressErrorException {
- if (address % WORD_LENGTH_BYTES != 0) {
+ **/
+ public int getWord(int address) throws AddressErrorException
+ {
+ if (address % WORD_LENGTH_BYTES != 0)
+ {
throw new AddressErrorException("fetch address not aligned on word boundary ",
- Exceptions.ADDRESS_EXCEPTION_LOAD, address);
- }
- return get(address, WORD_LENGTH_BYTES, true);
- }
-
- ///////////////////////////////////////////////////////////////////////////////////////
- /**
- * Starting at the given word address, read a 4 byte word as an int.
- * Does not use "get()"; we can do it faster here knowing we're working only
- * with full words. Observers are NOT notified.
- *
+ Exceptions.ADDRESS_EXCEPTION_LOAD, address);
+ }
+ return get(address, WORD_LENGTH_BYTES, true);
+ }
+
+ /**
+ * Starting at the given word address, read a 4 byte word as an int. Does not use "get()"; we can do it faster here
+ * knowing we're working only with full words. Observers are NOT notified.
+ *
* @param address Starting address of word to be read.
- * @return Word (4-byte value) stored starting at that address.
+ * @return Word (4-byte value) stored starting at that address.
* @throws AddressErrorException If address is not on word boundary.
- **/
- public int getWordNoNotify(int address) throws AddressErrorException {
- if (address % WORD_LENGTH_BYTES != 0) {
+ **/
+ public int getWordNoNotify(int address) throws AddressErrorException
+ {
+ if (address % WORD_LENGTH_BYTES != 0)
+ {
throw new AddressErrorException("fetch address not aligned on word boundary ",
- Exceptions.ADDRESS_EXCEPTION_LOAD, address);
- }
- return get(address, WORD_LENGTH_BYTES, false);
- }
-
-
-
- ///////////////////////////////////////////////////////////////////////////////////////
- /**
- * Starting at the given word address, read a 2 byte word into lower 16 bits of int.
- *
+ Exceptions.ADDRESS_EXCEPTION_LOAD, address);
+ }
+ return get(address, WORD_LENGTH_BYTES, false);
+ }
+
+ /**
+ * Starting at the given word address, read a 2 byte word into lower 16 bits of int.
+ *
* @param address Starting address of word to be read.
- * @return Halfword (2-byte value) stored starting at that address, stored in lower 16 bits.
+ * @return Halfword (2-byte value) stored starting at that address, stored in lower 16 bits.
* @throws AddressErrorException If address is not on halfword boundary.
- **/
- public int getHalf(int address) throws AddressErrorException {
- if (address % 2 != 0) {
+ **/
+ public int getHalf(int address) throws AddressErrorException
+ {
+ if (address % 2 != 0)
+ {
throw new AddressErrorException("fetch address not aligned on halfword boundary ",
- Exceptions.ADDRESS_EXCEPTION_LOAD, address);
- }
- return get(address, 2);
- }
-
-
- ///////////////////////////////////////////////////////////////////////////////////////
- /**
- * Reads specified Memory byte into low order 8 bits of int.
- *
+ Exceptions.ADDRESS_EXCEPTION_LOAD, address);
+ }
+ return get(address, 2);
+ }
+
+ /**
+ * Reads specified Memory byte into low order 8 bits of int.
+ *
* @param address Address of Memory byte to be read.
* @return Value stored at that address. Only low order 8 bits used.
**/
- public int getByte(int address) throws AddressErrorException {
- return get(address, 1);
- }
-
- ////////////////////////////////////////////////////////////////////////////////
- /**
- * Gets ProgramStatement from Text Segment.
- * @param address Starting address of Memory address to be read. Must be word boundary.
- * @return reference to ProgramStatement object associated with that address, or null if none.
- * @throws AddressErrorException If address is not on word boundary or is outside Text Segment.
- * @see ProgramStatement
- **/
-
- public ProgramStatement getStatement(int address) throws AddressErrorException {
- return getStatement(address, true);
+ public int getByte(int address) throws AddressErrorException
+ {
+ return get(address, 1);
+ }
+
+ /**
+ * Gets ProgramStatement from Text Segment.
+ *
+ * @param address Starting address of Memory address to be read. Must be word boundary.
+ * @return reference to ProgramStatement object associated with that address, or null if none.
+ * @throws AddressErrorException If address is not on word boundary or is outside Text Segment.
+ * @see ProgramStatement
+ **/
+
+ public ProgramStatement getStatement(int address) throws AddressErrorException
+ {
+ return getStatement(address, true);
/*
if (address % 4 != 0 || !(inTextSegment(address) || inKernelTextSegment(address))) {
throw new AddressErrorException(
@@ -899,24 +1159,32 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
}
if (inTextSegment(address)) {
return readProgramStatement(address, textBaseAddress, textBlockTable, true);
- }
+ }
else {
return readProgramStatement(address, kernelTextBaseAddress, kernelTextBlockTable,true);
}
*/
- }
-
- ////////////////////////////////////////////////////////////////////////////////
- /**
- * Gets ProgramStatement from Text Segment without notifying observers.
- * @param address Starting address of Memory address to be read. Must be word boundary.
- * @return reference to ProgramStatement object associated with that address, or null if none.
- * @throws AddressErrorException If address is not on word boundary or is outside Text Segment.
- * @see ProgramStatement
- **/
-
- public ProgramStatement getStatementNoNotify(int address) throws AddressErrorException {
- return getStatement(address, false);
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////
+ // ALL THE OBSERVABLE STUFF GOES HERE. FOR COMPATIBILITY, Memory IS STILL
+ // EXTENDING OBSERVABLE, BUT WILL NOT USE INHERITED METHODS. WILL INSTEAD
+ // USE A COLLECTION OF MemoryObserver OBJECTS, EACH OF WHICH IS COMBINATION
+ // OF AN OBSERVER WITH AN ADDRESS RANGE.
+
+ /**
+ * Gets ProgramStatement from Text Segment without notifying observers.
+ *
+ * @param address Starting address of Memory address to be read. Must be word boundary.
+ * @return reference to ProgramStatement object associated with that address, or null if none.
+ * @throws AddressErrorException If address is not on word boundary or is outside Text Segment.
+ * @see ProgramStatement
+ **/
+
+ public ProgramStatement getStatementNoNotify(int address) throws AddressErrorException
+ {
+ return getStatement(address, false);
/*
if (address % 4 != 0 || !(inTextSegment(address) || inKernelTextSegment(address))) {
throw new AddressErrorException(
@@ -925,535 +1193,492 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
}
if (inTextSegment(address)) {
return readProgramStatement(address, textBaseAddress, textBlockTable, false);
- }
+ }
else {
return readProgramStatement(address, kernelTextBaseAddress, kernelTextBlockTable, false);
}
*/
- }
-
- //////////
-
- private ProgramStatement getStatement(int address, boolean notify) throws AddressErrorException {
- if (!wordAligned(address)) {
+ }
+
+ private ProgramStatement getStatement(int address, boolean notify) throws AddressErrorException
+ {
+ if (!wordAligned(address))
+ {
throw new AddressErrorException(
- "fetch address for text segment not aligned to word boundary ",
- Exceptions.ADDRESS_EXCEPTION_LOAD, address);
- }
- if (!Globals.getSettings().getBooleanSetting(Settings.SELF_MODIFYING_CODE_ENABLED)
- && !(inTextSegment(address) || inKernelTextSegment(address))) {
+ "fetch address for text segment not aligned to word boundary ",
+ Exceptions.ADDRESS_EXCEPTION_LOAD, address);
+ }
+ if (!Globals.getSettings().getBooleanSetting(Settings.SELF_MODIFYING_CODE_ENABLED)
+ && !(inTextSegment(address) || inKernelTextSegment(address)))
+ {
throw new AddressErrorException(
- "fetch address for text segment out of range ",
- Exceptions.ADDRESS_EXCEPTION_LOAD, address);
- }
- if (inTextSegment(address))
+ "fetch address for text segment out of range ",
+ Exceptions.ADDRESS_EXCEPTION_LOAD, address);
+ }
+ if (inTextSegment(address))
+ {
return readProgramStatement(address, textBaseAddress, textBlockTable, notify);
- else if (inKernelTextSegment(address))
+ }
+ else if (inKernelTextSegment(address))
+ {
return readProgramStatement(address, kernelTextBaseAddress, kernelTextBlockTable, notify);
- else
+ }
+ else
+ {
return new ProgramStatement(get(address, WORD_LENGTH_BYTES), address);
- }
-
-
- /********************************* THE UTILITIES *************************************/
-
- /**
- * Utility to determine if given address is word-aligned.
- * @param address the address to check
- * @return true if address is word-aligned, false otherwise
- */
- public static boolean wordAligned(int address) {
- return (address % WORD_LENGTH_BYTES == 0);
- }
-
- /**
- * Utility to determine if given address is doubleword-aligned.
- * @param address the address to check
- * @return true if address is doubleword-aligned, false otherwise
- */
- public static boolean doublewordAligned(int address) {
- return (address % (WORD_LENGTH_BYTES+WORD_LENGTH_BYTES) == 0);
- }
-
- /**
- * Utility method to align given address to next full word boundary, if not already
- * aligned.
- * @param address a memory address (any int value is potentially valid)
- * @return address aligned to next word boundary (divisible by 4)
- */
- public static int alignToWordBoundary(int address) {
- if (!wordAligned(address)) {
- if (address > 0)
- address += (4-(address % WORD_LENGTH_BYTES));
- else
- address -= (4-(address % WORD_LENGTH_BYTES));
- }
- return address;
- }
-
- /**
- * Handy little utility to find out if given address is in MARS text
- * segment (starts at Memory.textBaseAddress).
- * Note that MARS does not implement the entire MIPS text segment space,
- * but it does implement enough for hundreds of thousands of lines
- * of code.
- * @param address integer memory address
- * @return true if that address is within MARS-defined text segment,
- * false otherwise.
- */
- public static boolean inTextSegment(int address) {
- return address >= textBaseAddress && address < textLimitAddress;
- }
-
- /**
- * Handy little utility to find out if given address is in MARS kernel
- * text segment (starts at Memory.kernelTextBaseAddress).
- * @param address integer memory address
- * @return true if that address is within MARS-defined kernel text segment,
- * false otherwise.
- */
- public static boolean inKernelTextSegment(int address) {
- return address >= kernelTextBaseAddress && address < kernelTextLimitAddress;
- }
-
+ }
+ }
+
/**
- * Handy little utility to find out if given address is in MARS data
- * segment (starts at Memory.dataSegmentBaseAddress).
- * Note that MARS does not implement the entire MIPS data segment space,
- * but it does support at least 4MB.
- * @param address integer memory address
- * @return true if that address is within MARS-defined data segment,
- * false otherwise.
- */
- public static boolean inDataSegment(int address) {
- return address >= dataSegmentBaseAddress && address < dataSegmentLimitAddress;
- }
-
- /**
- * Handy little utility to find out if given address is in MARS kernel data
- * segment (starts at Memory.kernelDataSegmentBaseAddress).
- * @param address integer memory address
- * @return true if that address is within MARS-defined kernel data segment,
- * false otherwise.
- */
- public static boolean inKernelDataSegment(int address) {
- return address >= kernelDataBaseAddress && address < kernelDataSegmentLimitAddress;
- }
-
-
- /**
- * Handy little utility to find out if given address is in the Memory Map area
- * starts at Memory.memoryMapBaseAddress, range 0xffff0000 to 0xffffffff.
- * @param address integer memory address
- * @return true if that address is within MARS-defined memory map (MMIO) area,
- * false otherwise.
- */
- public static boolean inMemoryMapSegment(int address) {
- return address >= memoryMapBaseAddress && address < kernelHighAddress;
- }
-
-
-
-
-
- ///////////////////////////////////////////////////////////////////////////
- // ALL THE OBSERVABLE STUFF GOES HERE. FOR COMPATIBILITY, Memory IS STILL
- // EXTENDING OBSERVABLE, BUT WILL NOT USE INHERITED METHODS. WILL INSTEAD
- // USE A COLLECTION OF MemoryObserver OBJECTS, EACH OF WHICH IS COMBINATION
- // OF AN OBSERVER WITH AN ADDRESS RANGE.
-
- /**
- * Method to accept registration from observer for any memory address. Overrides
- * inherited method. Note to observers: this class delegates Observable operations
- * so notices will come from the delegate, not the memory object.
- * @param obs the observer
- */
-
- public void addObserver(Observer obs) {
- try { // split so start address always >= end address
+ * Method to accept registration from observer for any memory address. Overrides inherited method. Note to
+ * observers: this class delegates Observable operations so notices will come from the delegate, not the memory
+ * object.
+ *
+ * @param obs the observer
+ */
+
+ public void addObserver(Observer obs)
+ {
+ try
+ { // split so start address always >= end address
this.addObserver(obs, 0, 0x7ffffffc);
- this.addObserver(obs,0x80000000,0xfffffffc);
- }
- catch (AddressErrorException aee) {
- System.out.println("Internal Error in Memory.addObserver: "+aee);
- }
- }
-
- /**
- * Method to accept registration from observer for specific address. This includes
- * the memory word starting at the given address. Note to observers: this class delegates Observable operations
- * so notices will come from the delegate, not the memory object.
- *
- * @param obs the observer
- * @param addr the memory address which must be on word boundary
- */
-
- public void addObserver(Observer obs, int addr) throws AddressErrorException {
- this.addObserver(obs, addr, addr);
- }
-
-
- /**
- * Method to accept registration from observer for specific address range. The
- * last byte included in the address range is the last byte of the word specified
- * by the ending address. Note to observers: this class delegates Observable operations
- * so notices will come from the delegate, not the memory object.
- *
- * @param obs the observer
- * @param startAddr the low end of memory address range, must be on word boundary
- * @param endAddr the high end of memory address range, must be on word boundary
- */
- public void addObserver(Observer obs, int startAddr, int endAddr) throws AddressErrorException {
- if (startAddr % WORD_LENGTH_BYTES != 0) {
+ this.addObserver(obs, 0x80000000, 0xfffffffc);
+ }
+ catch (AddressErrorException aee)
+ {
+ System.out.println("Internal Error in Memory.addObserver: " + aee);
+ }
+ }
+
+ /**
+ * Method to accept registration from observer for specific address. This includes the memory word starting at the
+ * given address. Note to observers: this class delegates Observable operations so notices will come from the
+ * delegate, not the memory object.
+ *
+ * @param obs the observer
+ * @param addr the memory address which must be on word boundary
+ */
+
+ public void addObserver(Observer obs, int addr) throws AddressErrorException
+ {
+ this.addObserver(obs, addr, addr);
+ }
+
+ /**
+ * Method to accept registration from observer for specific address range. The last byte included in the address
+ * range is the last byte of the word specified by the ending address. Note to observers: this class delegates
+ * Observable operations so notices will come from the delegate, not the memory object.
+ *
+ * @param obs the observer
+ * @param startAddr the low end of memory address range, must be on word boundary
+ * @param endAddr the high end of memory address range, must be on word boundary
+ */
+ public void addObserver(Observer obs, int startAddr, int endAddr) throws AddressErrorException
+ {
+ if (startAddr % WORD_LENGTH_BYTES != 0)
+ {
throw new AddressErrorException("address not aligned on word boundary ",
- Exceptions.ADDRESS_EXCEPTION_LOAD, startAddr);
- }
- if (endAddr!=startAddr && endAddr % WORD_LENGTH_BYTES != 0) {
+ Exceptions.ADDRESS_EXCEPTION_LOAD, startAddr);
+ }
+ if (endAddr != startAddr && endAddr % WORD_LENGTH_BYTES != 0)
+ {
throw new AddressErrorException("address not aligned on word boundary ",
- Exceptions.ADDRESS_EXCEPTION_LOAD, startAddr);
- }
- // upper half of address space (above 0x7fffffff) has sign bit 1 thus is seen as
- // negative.
- if (startAddr>=0 && endAddr<0) {
+ Exceptions.ADDRESS_EXCEPTION_LOAD, startAddr);
+ }
+ // upper half of address space (above 0x7fffffff) has sign bit 1 thus is seen as
+ // negative.
+ if (startAddr >= 0 && endAddr < 0)
+ {
throw new AddressErrorException("range cannot cross 0x8000000; please split it up",
- Exceptions.ADDRESS_EXCEPTION_LOAD, startAddr);
- }
- if (endAddr= lowAddress && address <= highAddress-1+WORD_LENGTH_BYTES);
- }
-
- public void notifyObserver(MemoryAccessNotice notice) {
- this.setChanged();
- this.notifyObservers(notice);
- }
-
- // Useful to have for future refactoring, if it actually becomes worthwhile to sort
- // these or put 'em in a tree (rather than sequential search through list).
- public int compareTo(Object obj) {
- if (!(obj instanceof MemoryObservable)) {
- throw new ClassCastException();
- }
- MemoryObservable mo = (MemoryObservable) obj;
- if (this.lowAddress < mo.lowAddress || this.lowAddress==mo.lowAddress && this.highAddress < mo.highAddress) {
- return -1;
- }
- if (this.lowAddress > mo.lowAddress || this.lowAddress==mo.lowAddress && this.highAddress > mo.highAddress) {
- return -1;
- }
- return 0; // they have to be equal at this point.
- }
- }
-
-
- /********************************* THE HELPERS *************************************/
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // Method to notify any observers of memory operation that has just occurred.
- //
- // The "|| Globals.getGui()==null" is a hack added 19 July 2012 DPS. IF MIPS simulation
- // is from command mode, Globals.program is null but still want ability to observe.
- private void notifyAnyObservers(int type, int address, int length, int value) {
- if ((Globals.program != null || Globals.getGui()==null) && this.observables.size() > 0) {
+ Exceptions.ADDRESS_EXCEPTION_LOAD, startAddr);
+ }
+ observables.add(new MemoryObservable(obs, startAddr, endAddr));
+ }
+
+ /**
+ * Return number of observers
+ */
+ public int countObservers()
+ {
+ return observables.size();
+ }
+
+ /**
+ * Remove specified memory observers
+ *
+ * @param obs Observer to be removed
+ */
+ public void deleteObserver(Observer obs)
+ {
+ Iterator it = observables.iterator();
+ while (it.hasNext())
+ {
+ ((MemoryObservable) it.next()).deleteObserver(obs);
+ }
+ }
+
+ /**
+ * Remove all memory observers
+ */
+ public void deleteObservers()
+ {
+ // just drop the collection
+ observables = getNewMemoryObserversCollection();
+ }
+
+ /**
+ * Overridden to be unavailable. The notice that an Observer receives does not come from the memory object itself,
+ * but instead from a delegate.
+ *
+ * @throws UnsupportedOperationException
+ */
+ public void notifyObservers()
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Overridden to be unavailable. The notice that an Observer receives does not come from the memory object itself,
+ * but instead from a delegate.
+ *
+ * @throws UnsupportedOperationException
+ */
+ public void notifyObservers(Object obj)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ private Collection getNewMemoryObserversCollection()
+ {
+ return new Vector(); // Vectors are thread-safe
+ }
+
+ /********************************* THE HELPERS *************************************/
+
+
+ ////////////////////////////////////////////////////////////////////////////////
+ //
+ // Method to notify any observers of memory operation that has just occurred.
+ //
+ // The "|| Globals.getGui()==null" is a hack added 19 July 2012 DPS. IF MIPS simulation
+ // is from command mode, Globals.program is null but still want ability to observe.
+ private void notifyAnyObservers(int type, int address, int length, int value)
+ {
+ if ((Globals.program != null || Globals.getGui() == null) && this.observables.size() > 0)
+ {
Iterator it = this.observables.iterator();
MemoryObservable mo;
- while (it.hasNext()) {
- mo = (MemoryObservable)it.next();
- if (mo.match(address)) {
- mo.notifyObserver(new MemoryAccessNotice(type, address, length, value));
- }
+ while (it.hasNext())
+ {
+ mo = (MemoryObservable) it.next();
+ if (mo.match(address))
+ {
+ mo.notifyObserver(new MemoryAccessNotice(type, address, length, value));
+ }
}
- }
- }
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // Helper method to store 1, 2 or 4 byte value in table that represents MIPS
- // memory. Originally used just for data segment, but now also used for stack.
- // Both use different tables but same storage method and same table size
- // and block size.
- // Modified 29 Dec 2005 to return old value of replaced bytes.
- //
- private static final boolean STORE = true;
- private static final boolean FETCH = false;
-
- private int storeBytesInTable(int [][] blockTable,
- int relativeByteAddress, int length, int value) {
- return storeOrFetchBytesInTable(blockTable, relativeByteAddress, length, value, STORE);
- }
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // Helper method to fetch 1, 2 or 4 byte value from table that represents MIPS
- // memory. Originally used just for data segment, but now also used for stack.
- // Both use different tables but same storage method and same table size
- // and block size.
- //
-
- private int fetchBytesFromTable(int[][] blockTable, int relativeByteAddress, int length) {
- return storeOrFetchBytesInTable(blockTable, relativeByteAddress, length, 0, FETCH);
- }
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // The helper's helper. Works for either storing or fetching, little or big endian.
- // When storing/fetching bytes, most of the work is calculating the correct array element(s)
- // and element byte(s). This method performs either store or fetch, as directed by its
- // client using STORE or FETCH in last arg.
- // Modified 29 Dec 2005 to return old value of replaced bytes, for STORE.
- //
- private synchronized int storeOrFetchBytesInTable(int [][] blockTable,
- int relativeByteAddress, int length, int value, boolean op) {
- int relativeWordAddress, block, offset, bytePositionInMemory, bytePositionInValue;
- int oldValue = 0; // for STORE, return old values of replaced bytes
- int loopStopper = 3-length;
- // IF added DPS 22-Dec-2008. NOTE: has NOT been tested with Big-Endian.
- // Fix provided by Saul Spatz; comments that follow are his.
- // If address in stack segment is 4k + m, with 0 < m < 4, then the
- // relativeByteAddress we want is stackBaseAddress - 4k + m, but the
- // address actually passed in is stackBaseAddress - (4k + m), so we
- // need to add 2m. Because of the change in sign, we get the
- // expression 4-delta below in place of m.
- if (blockTable == stackBlockTable) {
+ }
+ }
+
+ private int storeBytesInTable(int[][] blockTable,
+ int relativeByteAddress, int length, int value)
+ {
+ return storeOrFetchBytesInTable(blockTable, relativeByteAddress, length, value, STORE);
+ }
+
+ private int fetchBytesFromTable(int[][] blockTable, int relativeByteAddress, int length)
+ {
+ return storeOrFetchBytesInTable(blockTable, relativeByteAddress, length, 0, FETCH);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ //
+ // Helper method to fetch 1, 2 or 4 byte value from table that represents MIPS
+ // memory. Originally used just for data segment, but now also used for stack.
+ // Both use different tables but same storage method and same table size
+ // and block size.
+ //
+
+ ////////////////////////////////////////////////////////////////////////////////
+ //
+ // The helper's helper. Works for either storing or fetching, little or big endian.
+ // When storing/fetching bytes, most of the work is calculating the correct array element(s)
+ // and element byte(s). This method performs either store or fetch, as directed by its
+ // client using STORE or FETCH in last arg.
+ // Modified 29 Dec 2005 to return old value of replaced bytes, for STORE.
+ //
+ private synchronized int storeOrFetchBytesInTable(int[][] blockTable,
+ int relativeByteAddress, int length, int value, boolean op)
+ {
+ int relativeWordAddress, block, offset, bytePositionInMemory, bytePositionInValue;
+ int oldValue = 0; // for STORE, return old values of replaced bytes
+ int loopStopper = 3 - length;
+ // IF added DPS 22-Dec-2008. NOTE: has NOT been tested with Big-Endian.
+ // Fix provided by Saul Spatz; comments that follow are his.
+ // If address in stack segment is 4k + m, with 0 < m < 4, then the
+ // relativeByteAddress we want is stackBaseAddress - 4k + m, but the
+ // address actually passed in is stackBaseAddress - (4k + m), so we
+ // need to add 2m. Because of the change in sign, we get the
+ // expression 4-delta below in place of m.
+ if (blockTable == stackBlockTable)
+ {
int delta = relativeByteAddress % 4;
- if (delta != 0) {
- relativeByteAddress += ( 4 - delta ) << 1;
+ if (delta != 0)
+ {
+ relativeByteAddress += (4 - delta) << 1;
}
- }
- for (bytePositionInValue = 3; bytePositionInValue > loopStopper; bytePositionInValue--) {
+ }
+ for (bytePositionInValue = 3; bytePositionInValue > loopStopper; bytePositionInValue--)
+ {
bytePositionInMemory = relativeByteAddress % 4;
relativeWordAddress = relativeByteAddress >> 2;
block = relativeWordAddress / BLOCK_LENGTH_WORDS; // Block number
offset = relativeWordAddress % BLOCK_LENGTH_WORDS; // Word within that block
- if (blockTable[block] == null) {
- if (op==STORE)
- blockTable[block] = new int[BLOCK_LENGTH_WORDS];
- else
- return 0;
+ if (blockTable[block] == null)
+ {
+ if (op == STORE)
+ {
+ blockTable[block] = new int[BLOCK_LENGTH_WORDS];
+ }
+ else
+ {
+ return 0;
+ }
}
- if (byteOrder == LITTLE_ENDIAN) bytePositionInMemory = 3 - bytePositionInMemory;
- if (op == STORE) {
- oldValue = replaceByte(blockTable[block][offset], bytePositionInMemory,
- oldValue, bytePositionInValue);
- blockTable[block][offset] = replaceByte(value, bytePositionInValue,
- blockTable[block][offset], bytePositionInMemory);
- }
- else {// op == FETCH
- value = replaceByte(blockTable[block][offset], bytePositionInMemory,
- value, bytePositionInValue);
+ if (byteOrder == LITTLE_ENDIAN)
+ {
+ bytePositionInMemory = 3 - bytePositionInMemory;
+ }
+ if (op == STORE)
+ {
+ oldValue = replaceByte(blockTable[block][offset], bytePositionInMemory,
+ oldValue, bytePositionInValue);
+ blockTable[block][offset] = replaceByte(value, bytePositionInValue,
+ blockTable[block][offset], bytePositionInMemory);
+ }
+ else
+ {// op == FETCH
+ value = replaceByte(blockTable[block][offset], bytePositionInMemory,
+ value, bytePositionInValue);
}
relativeByteAddress++;
- }
- return (op == STORE) ? oldValue : value;
- }
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // Helper method to store 4 byte value in table that represents MIPS memory.
- // Originally used just for data segment, but now also used for stack.
- // Both use different tables but same storage method and same table size
- // and block size. Assumes address is word aligned, no endian processing.
- // Modified 29 Dec 2005 to return overwritten value.
-
- private synchronized int storeWordInTable(int[][] blockTable, int relative, int value) {
- int block, offset, oldValue;
- block = relative / BLOCK_LENGTH_WORDS;
- offset = relative % BLOCK_LENGTH_WORDS;
- if (blockTable[block] == null) {
- // First time writing to this block, so allocate the space.
+ }
+ return (op == STORE) ? oldValue : value;
+ }
+
+ private synchronized int storeWordInTable(int[][] blockTable, int relative, int value)
+ {
+ int block, offset, oldValue;
+ block = relative / BLOCK_LENGTH_WORDS;
+ offset = relative % BLOCK_LENGTH_WORDS;
+ if (blockTable[block] == null)
+ {
+ // First time writing to this block, so allocate the space.
blockTable[block] = new int[BLOCK_LENGTH_WORDS];
- }
- oldValue = blockTable[block][offset];
- blockTable[block][offset] = value;
- return oldValue;
- }
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // Helper method to fetch 4 byte value from table that represents MIPS memory.
- // Originally used just for data segment, but now also used for stack.
- // Both use different tables but same storage method and same table size
- // and block size. Assumes word alignment, no endian processing.
- //
-
- private synchronized int fetchWordFromTable(int[][] blockTable, int relative) {
- int value = 0;
- int block, offset;
- block = relative / BLOCK_LENGTH_WORDS;
- offset = relative % BLOCK_LENGTH_WORDS;
- if (blockTable[block] == null) {
- // first reference to an address in this block. Assume initialized to 0.
+ }
+ oldValue = blockTable[block][offset];
+ blockTable[block][offset] = value;
+ return oldValue;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ //
+ // Helper method to store 4 byte value in table that represents MIPS memory.
+ // Originally used just for data segment, but now also used for stack.
+ // Both use different tables but same storage method and same table size
+ // and block size. Assumes address is word aligned, no endian processing.
+ // Modified 29 Dec 2005 to return overwritten value.
+
+ private synchronized int fetchWordFromTable(int[][] blockTable, int relative)
+ {
+ int value = 0;
+ int block, offset;
+ block = relative / BLOCK_LENGTH_WORDS;
+ offset = relative % BLOCK_LENGTH_WORDS;
+ if (blockTable[block] == null)
+ {
+ // first reference to an address in this block. Assume initialized to 0.
value = 0;
- }
- else {
+ }
+ else
+ {
value = blockTable[block][offset];
- }
- return value;
- }
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // Helper method to fetch 4 byte value from table that represents MIPS memory.
- // Originally used just for data segment, but now also used for stack.
- // Both use different tables but same storage method and same table size
- // and block size. Assumes word alignment, no endian processing.
- //
- // This differs from "fetchWordFromTable()" in that it returns an Integer and
- // returns null instead of 0 if the 4K table has not been allocated. Developed
- // by Greg Gibeling of UC Berkeley, fall 2007.
- //
-
- private synchronized Integer fetchWordOrNullFromTable(int[][] blockTable, int relative) {
- int value = 0;
- int block, offset;
- block = relative / BLOCK_LENGTH_WORDS;
- offset = relative % BLOCK_LENGTH_WORDS;
- if (blockTable[block] == null) {
- // first reference to an address in this block. Assume initialized to 0.
+ }
+ return value;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ //
+ // Helper method to fetch 4 byte value from table that represents MIPS memory.
+ // Originally used just for data segment, but now also used for stack.
+ // Both use different tables but same storage method and same table size
+ // and block size. Assumes word alignment, no endian processing.
+ //
+
+ private synchronized Integer fetchWordOrNullFromTable(int[][] blockTable, int relative)
+ {
+ int value = 0;
+ int block, offset;
+ block = relative / BLOCK_LENGTH_WORDS;
+ offset = relative % BLOCK_LENGTH_WORDS;
+ if (blockTable[block] == null)
+ {
+ // first reference to an address in this block. Assume initialized to 0.
return null;
- }
- else {
+ }
+ else
+ {
value = blockTable[block][offset];
- }
- return value;
- }
-
- ////////////////////////////////////////////////////////////////////////////////////
- // Returns result of substituting specified byte of source value into specified byte
- // of destination value. Byte positions are 0-1-2-3, listed from most to least
- // significant. No endian issues. This is a private helper method used by get() & set().
- private int replaceByte(int sourceValue, int bytePosInSource, int destValue, int bytePosInDest) {
- return
+ }
+ return value;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ //
+ // Helper method to fetch 4 byte value from table that represents MIPS memory.
+ // Originally used just for data segment, but now also used for stack.
+ // Both use different tables but same storage method and same table size
+ // and block size. Assumes word alignment, no endian processing.
+ //
+ // This differs from "fetchWordFromTable()" in that it returns an Integer and
+ // returns null instead of 0 if the 4K table has not been allocated. Developed
+ // by Greg Gibeling of UC Berkeley, fall 2007.
+ //
+
+ ////////////////////////////////////////////////////////////////////////////////////
+ // Returns result of substituting specified byte of source value into specified byte
+ // of destination value. Byte positions are 0-1-2-3, listed from most to least
+ // significant. No endian issues. This is a private helper method used by get() & set().
+ private int replaceByte(int sourceValue, int bytePosInSource, int destValue, int bytePosInDest)
+ {
+ return
// Set source byte value into destination byte position; set other 24 bits to 0's...
- ((sourceValue >> (24 - (bytePosInSource << 3)) & 0xFF)
- << (24 - (bytePosInDest << 3)))
- // and bitwise-OR it with...
- |
- // Set 8 bits in destination byte position to 0's, other 24 bits are unchanged.
- (destValue & ~(0xFF << (24 - (bytePosInDest << 3))));
- }
-
- ///////////////////////////////////////////////////////////////////////
- // Reverses byte sequence of given value. Can use to convert between big and
- // little endian if needed.
- private int reverseBytes(int source) {
- return (source >> 24 & 0x000000FF) |
- (source >> 8 & 0x0000FF00) |
- (source << 8 & 0x00FF0000) |
- (source << 24);
- }
-
- ///////////////////////////////////////////////////////////////////////
- // Store a program statement at the given address. Address has already been verified
- // as valid. It may be either in user or kernel text segment, as specified by arguments.
- private void storeProgramStatement(int address, ProgramStatement statement,
- int baseAddress, ProgramStatement[][] blockTable) {
- int relative = (address - baseAddress) >> 2; // convert byte address to words
- int block = relative / BLOCK_LENGTH_WORDS;
- int offset = relative % BLOCK_LENGTH_WORDS;
- if (block < TEXT_BLOCK_TABLE_LENGTH) {
- if (blockTable[block] == null) {
- // No instructions are stored in this block, so allocate the block.
- blockTable[block] = new ProgramStatement[BLOCK_LENGTH_WORDS];
+ ((sourceValue >> (24 - (bytePosInSource << 3)) & 0xFF)
+ << (24 - (bytePosInDest << 3)))
+ // and bitwise-OR it with...
+ |
+ // Set 8 bits in destination byte position to 0's, other 24 bits are unchanged.
+ (destValue & ~(0xFF << (24 - (bytePosInDest << 3))));
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+ // Reverses byte sequence of given value. Can use to convert between big and
+ // little endian if needed.
+ private int reverseBytes(int source)
+ {
+ return (source >> 24 & 0x000000FF) |
+ (source >> 8 & 0x0000FF00) |
+ (source << 8 & 0x00FF0000) |
+ (source << 24);
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+ // Store a program statement at the given address. Address has already been verified
+ // as valid. It may be either in user or kernel text segment, as specified by arguments.
+ private void storeProgramStatement(int address, ProgramStatement statement,
+ int baseAddress, ProgramStatement[][] blockTable)
+ {
+ int relative = (address - baseAddress) >> 2; // convert byte address to words
+ int block = relative / BLOCK_LENGTH_WORDS;
+ int offset = relative % BLOCK_LENGTH_WORDS;
+ if (block < TEXT_BLOCK_TABLE_LENGTH)
+ {
+ if (blockTable[block] == null)
+ {
+ // No instructions are stored in this block, so allocate the block.
+ blockTable[block] = new ProgramStatement[BLOCK_LENGTH_WORDS];
}
blockTable[block][offset] = statement;
- }
- }
-
-
- ///////////////////////////////////////////////////////////////////////
- // Read a program statement from the given address. Address has already been verified
- // as valid. It may be either in user or kernel text segment, as specified by arguments.
- // Returns associated ProgramStatement or null if none.
- // Last parameter controls whether or not observers will be notified.
- private ProgramStatement readProgramStatement(int address, int baseAddress, ProgramStatement[][] blockTable, boolean notify) {
- int relative = (address - baseAddress) >> 2; // convert byte address to words
- int block = relative / TEXT_BLOCK_LENGTH_WORDS;
- int offset = relative % TEXT_BLOCK_LENGTH_WORDS;
- if (block < TEXT_BLOCK_TABLE_LENGTH) {
- if (blockTable[block] == null || blockTable[block][offset] == null) {
- // No instructions are stored in this block or offset.
- if (notify) notifyAnyObservers(AccessNotice.READ, address, Instruction.INSTRUCTION_LENGTH,0);
- return null;
- }
- else {
- if (notify) notifyAnyObservers(AccessNotice.READ, address, Instruction.INSTRUCTION_LENGTH, blockTable[block][offset].getBinaryStatement());
- return blockTable[block][offset];
+ }
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+ // Read a program statement from the given address. Address has already been verified
+ // as valid. It may be either in user or kernel text segment, as specified by arguments.
+ // Returns associated ProgramStatement or null if none.
+ // Last parameter controls whether or not observers will be notified.
+ private ProgramStatement readProgramStatement(int address, int baseAddress, ProgramStatement[][] blockTable, boolean notify)
+ {
+ int relative = (address - baseAddress) >> 2; // convert byte address to words
+ int block = relative / TEXT_BLOCK_LENGTH_WORDS;
+ int offset = relative % TEXT_BLOCK_LENGTH_WORDS;
+ if (block < TEXT_BLOCK_TABLE_LENGTH)
+ {
+ if (blockTable[block] == null || blockTable[block][offset] == null)
+ {
+ // No instructions are stored in this block or offset.
+ if (notify)
+ {
+ notifyAnyObservers(AccessNotice.READ, address, Instruction.INSTRUCTION_LENGTH, 0);
+ }
+ return null;
}
- }
- if (notify) notifyAnyObservers(AccessNotice.READ, address, Instruction.INSTRUCTION_LENGTH,0);
- return null;
- }
-
- }
+ else
+ {
+ if (notify)
+ {
+ notifyAnyObservers(AccessNotice.READ, address, Instruction.INSTRUCTION_LENGTH, blockTable[block][offset].getBinaryStatement());
+ }
+ return blockTable[block][offset];
+ }
+ }
+ if (notify)
+ {
+ notifyAnyObservers(AccessNotice.READ, address, Instruction.INSTRUCTION_LENGTH, 0);
+ }
+ return null;
+ }
+
+ /////////////////////////////////////////////////////////////////////////
+ // Private class whose objects will represent an observable-observer pair
+ // for a given memory address or range.
+ private class MemoryObservable extends Observable implements Comparable
+ {
+ private final int lowAddress;
+
+ private final int highAddress;
+
+ public MemoryObservable(Observer obs, int startAddr, int endAddr)
+ {
+ lowAddress = startAddr;
+ highAddress = endAddr;
+ this.addObserver(obs);
+ }
+
+ public boolean match(int address)
+ {
+ return (address >= lowAddress && address <= highAddress - 1 + WORD_LENGTH_BYTES);
+ }
+
+ public void notifyObserver(MemoryAccessNotice notice)
+ {
+ this.setChanged();
+ this.notifyObservers(notice);
+ }
+
+ // Useful to have for future refactoring, if it actually becomes worthwhile to sort
+ // these or put 'em in a tree (rather than sequential search through list).
+ public int compareTo(Object obj)
+ {
+ if (!(obj instanceof MemoryObservable))
+ {
+ throw new ClassCastException();
+ }
+ MemoryObservable mo = (MemoryObservable) obj;
+ if (this.lowAddress < mo.lowAddress || this.lowAddress == mo.lowAddress && this.highAddress < mo.highAddress)
+ {
+ return -1;
+ }
+ if (this.lowAddress > mo.lowAddress || this.lowAddress == mo.lowAddress && this.highAddress > mo.highAddress)
+ {
+ return -1;
+ }
+ return 0; // they have to be equal at this point.
+ }
+ }
+
+}
diff --git a/src/main/java/mars/mips/hardware/MemoryAccessNotice.java b/src/main/java/mars/mips/hardware/MemoryAccessNotice.java
index 13e6cc5..9051937 100644
--- a/src/main/java/mars/mips/hardware/MemoryAccessNotice.java
+++ b/src/main/java/mars/mips/hardware/MemoryAccessNotice.java
@@ -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;
- }
-}
\ No newline at end of file
+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;
+ }
+}
diff --git a/src/main/java/mars/mips/hardware/MemoryConfiguration.java b/src/main/java/mars/mips/hardware/MemoryConfiguration.java
index b942702..15d5085 100644
--- a/src/main/java/mars/mips/hardware/MemoryConfiguration.java
+++ b/src/main/java/mars/mips/hardware/MemoryConfiguration.java
@@ -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];
- }
-
- }
\ No newline at end of file
+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];
+ }
+
+}
diff --git a/src/main/java/mars/mips/hardware/MemoryConfigurations.java b/src/main/java/mars/mips/hardware/MemoryConfigurations.java
index d16f11f..ccf8bb1 100644
--- a/src/main/java/mars/mips/hardware/MemoryConfigurations.java
+++ b/src/main/java/mars/mips/hardware/MemoryConfigurations.java
@@ -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];
- }
-
-
-
- }
\ No newline at end of file
+ }
+ }
+
+
+ //// 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];
+ }
+
+
+}
diff --git a/src/main/java/mars/mips/hardware/Register.java b/src/main/java/mars/mips/hardware/Register.java
index 0f38707..80588ba 100644
--- a/src/main/java/mars/mips/hardware/Register.java
+++ b/src/main/java/mars/mips/hardware/Register.java
@@ -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 resetValue() 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 resetValue() 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));
- }
- }
-
-
- }
+ }
+ }
+
+
+}
diff --git a/src/main/java/mars/mips/hardware/RegisterAccessNotice.java b/src/main/java/mars/mips/hardware/RegisterAccessNotice.java
index ff8f4c6..15b6225 100644
--- a/src/main/java/mars/mips/hardware/RegisterAccessNotice.java
+++ b/src/main/java/mars/mips/hardware/RegisterAccessNotice.java
@@ -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;
- }
-
-}
\ No newline at end of file
+ /**
+ * 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;
+ }
+
+}
diff --git a/src/main/java/mars/mips/hardware/RegisterFile.java b/src/main/java/mars/mips/hardware/RegisterFile.java
index cf2f837..54bf135 100644
--- a/src/main/java/mars/mips/hardware/RegisterFile.java
+++ b/src/main/java/mars/mips/hardware/RegisterFile.java
@@ -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.
- * NOTE: Should not 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
- * AbstractMarsToolAndApplication.
- **/
-
- 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.
+ * NOTE: Should not 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
+ * AbstractMarsToolAndApplication.
+ **/
+
+ 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
+ * The presence of an alternative "compact translation" can optimize code generation by assuming that data label
+ * addresses are 16 bits instead of 32
**/
-
- public ExtendedInstruction(String example, String translation, String compactTranslation, String description) {
- this.exampleFormat = example;
- this.description = description;
- this.mnemonic = this.extractOperator(example);
- this.createExampleTokenList();
- this.translationStrings = buildTranslationList(translation);
- this.compactTranslationStrings = buildTranslationList(compactTranslation);
- }
-
+
+ public ExtendedInstruction(String example, String translation, String compactTranslation, String description)
+ {
+ this.exampleFormat = example;
+ this.description = description;
+ this.mnemonic = this.extractOperator(example);
+ this.createExampleTokenList();
+ this.translationStrings = buildTranslationList(translation);
+ this.compactTranslationStrings = buildTranslationList(compactTranslation);
+ }
+
/**
* Constructor for ExtendedInstruction. No compact translation is provided.
- *
+ *
* @param example A String containing example use of the MIPS extended instruction.
- * @param translation Specifications for translating this instruction into a sequence
- * of one or more MIPS basic instructions.
+ * @param translation Specifications for translating this instruction into a sequence of one or more MIPS basic
+ * instructions.
* @param description a helpful description to be included on help requests
**/
-
- public ExtendedInstruction(String example, String translation, String description) {
- this.exampleFormat = example;
- this.description = description;
- this.mnemonic = this.extractOperator(example);
- this.createExampleTokenList();
- this.translationStrings = buildTranslationList(translation);
- this.compactTranslationStrings = null;
- }
-
- /**
- * Constructor for ExtendedInstruction, where no instruction description or
- * compact translation is provided.
- *
+
+ public ExtendedInstruction(String example, String translation, String description)
+ {
+ this.exampleFormat = example;
+ this.description = description;
+ this.mnemonic = this.extractOperator(example);
+ this.createExampleTokenList();
+ this.translationStrings = buildTranslationList(translation);
+ this.compactTranslationStrings = null;
+ }
+
+ /**
+ * Constructor for ExtendedInstruction, where no instruction description or compact translation is provided.
+ *
* @param example A String containing example use of the MIPS extended instruction.
- * @param translation Specifications for translating this instruction into a sequence
- * of one or more MIPS basic instructions.
+ * @param translation Specifications for translating this instruction into a sequence of one or more MIPS basic
+ * instructions.
**/
-
- public ExtendedInstruction(String example, String translation) {
- this(example, translation, "");
- }
-
- /**
- * Get length in bytes that this extended instruction requires in its
- * binary form. The answer depends on how many basic instructions it
- * expands to. This may vary, if expansion includes a nop, depending on
- * whether or not delayed branches are enabled. Each requires 4 bytes.
- * @return int length in bytes of corresponding binary instruction(s).
- */
-
- public int getInstructionLength() {
- return getInstructionLength(translationStrings);
- }
-
- /**
- * Get ArrayList of Strings that represent list of templates for
- * basic instructions generated by this extended instruction.
- * @return ArrayList of Strings.
- */
-
- public ArrayList getBasicIntructionTemplateList() {
- return translationStrings;
- }
-
- /**
- * Get length in bytes that this extended instruction requires in its
- * binary form if it includes an alternative expansion for compact
- * memory (16 bit addressing) configuration. The answer depends on
- * how many basic instructions it expands to. This may vary, if
- * expansion includes a nop, depending on whether or not delayed
- * branches are enabled. Each requires 4 bytes.
- * @return int length in bytes of corresponding binary instruction(s).
- * Returns 0 if an alternative expansion is not defined for this
- * instruction.
- */
-
- public int getCompactInstructionLength() {
- return getInstructionLength(compactTranslationStrings);
- }
-
-
- /**
- * Determine whether or not this pseudo-instruction has a second
- * translation optimized for 16 bit address space: a compact version.
- */
- public boolean hasCompactTranslation() {
- return compactTranslationStrings != null;
- }
+ public ExtendedInstruction(String example, String translation)
+ {
+ this(example, translation, "");
+ }
-
/**
- * Get ArrayList of Strings that represent list of templates for
- * basic instructions generated by the "compact" or 16-bit version
- * of this extended instruction.
- * @return ArrayList of Strings. Returns null if the instruction does not
- * have a compact alternative.
+ * Given a basic instruction template and the list of tokens from an extended instruction statement, substitute
+ * operands from the token list appropriately into the template to generate the basic statement. Assumes the
+ * extended instruction statement has been translated from source form to basic assembly form (e.g. register
+ * mnemonics translated to corresponding register numbers). Operand format of source statement is already verified
+ * correct. Assume the template has correct number and positions of operands. Template is String with special
+ * markers. In the list below, n represents token position (1,2,3,etc) in source statement (operator is token 0,
+ * parentheses count but commas don't):
+ *
+ * - RGn means substitute register found in n'th token of source statement
+ *
- NRn means substitute next higher register than the one in n'th token of source code
+ *
- OPn means substitute n'th token of source code as is
+ *
- LLn means substitute low order 16 bits from label address in source token n.
+ *
- LLnU means substitute low order 16 bits (unsigned) from label address in source token n.
+ *
- LLnPm (m=1,2,3,4) means substitute low order 16 bits from label address in source token n, after adding m.
+ *
- LHn means substitute high order 16 bits from label address in source token n. Must add 1 if address bit 15 is
+ * 1.
+ *
- LHnPm (m=1,2,3,4) means substitute high order 16 bits from label address in source token n, after adding m.
+ * Must then add 1 if bit 15 is 1.
+ *
- VLn means substitute low order 16 bits from 32 bit value in source token n.
+ *
- VLnU means substitute low order 16 bits (unsigned) from 32 bit value in source token n.
+ *
- VLnPm (m=1,2,3,4) means substitute low order 16 bits from 32 bit value in source token n, after adding m to
+ * value.
+ *
- VLnPmU (m=1,2,3,4) means substitute low order 16 bits (unsigned) from 32 bit value in source token n, after
+ * adding m to value.
+ *
- VHLn means substitute high order 16 bits from 32 bit value in source token n. Use this if later combined
+ * with low order 16 bits using "ori $1,$1,VLn". See logical and branch operations.
+ *
- VHn means substitute high order 16 bits from 32 bit value in source token n, then add 1 if value's bit 15 is
+ * 1. Use this only if later instruction uses VLn($1) to calculate 32 bit address. See loads and stores.
+ *
- VHLnPm (m=1,2,3,4) means substitute high order 16 bits from 32 bit value in source token n, after adding m.
+ * See VHLn.
+ *
- VHnPm (m=1,2,3,4) means substitute high order 16 bits from 32 bit value in source token n, after adding m.
+ * Must then add 1 if bit 15 is 1. See VHn.
+ *
- LLP is similar to LLn, but is needed for "label+100000" address offset. Immediate is added before taking low
+ * order 16.
+ *
- LLPU is similar to LLnU, but is needed for "label+100000" address offset. Immediate is added before taking
+ * low order 16 (unsigned).
+ *
- LLPPm (m=1,2,3,4) is similar to LLP except m is added along with mmediate before taking low order 16.
+ *
- LHPA is similar to LHn, but is needed for "label+100000" address offset. Immediate is added before taking
+ * high order 16.
+ *
- LHPN is similar to LHPA, used only by "la" instruction. Address resolved by "ori" so do not add 1 if bit 15
+ * is 1.
+ *
- LHPAPm (m=1,2,3,4) is similar to LHPA except value m is added along with immediate before taking high order
+ * 16.
+ *
- LHL means substitute high order 16 bits from label address in token 2 of "la" (load address) source
+ * statement.
+ *
- LAB means substitute textual label from last token of source statement. Used for various branches.
+ *
- S32 means substitute the result of subtracting the constant value in last token from 32. Used by "ror",
+ * "rol".
+ *
- DBNOP means Delayed Branching NOP - generate a "nop" instruction but only if delayed branching is enabled.
+ * Added in 3.4.1 release.
+ *
- BROFFnm means substitute n if delayed branching is NOT enabled otherwise substitute m. n and m are single
+ * digit numbers indicating constant branch offset (in words). Added in 3.4.1 release.
+ *
+ *
+ * @param template a String containing template for basic statement.
+ * @param tokenList a TokenList containing tokens from extended instruction.
+ * @return String representing basic assembler statement.
*/
-
- public ArrayList getCompactBasicIntructionTemplateList() {
- return compactTranslationStrings;
- }
-
- /**
- * Given a basic instruction template and the list of tokens from an extended
- * instruction statement, substitute operands from the token list appropriately into the
- * template to generate the basic statement. Assumes the extended instruction statement has
- * been translated from source form to basic assembly form (e.g. register mnemonics
- * translated to corresponding register numbers).
- * Operand format of source statement is already verified correct.
- * Assume the template has correct number and positions of operands.
- * Template is String with special markers. In the list below, n represents token position (1,2,3,etc)
- * in source statement (operator is token 0, parentheses count but commas don't):
- *
- * - RGn means substitute register found in n'th token of source statement
- *
- NRn means substitute next higher register than the one in n'th token of source code
- *
- OPn means substitute n'th token of source code as is
- *
- LLn means substitute low order 16 bits from label address in source token n.
- *
- LLnU means substitute low order 16 bits (unsigned) from label address in source token n.
- *
- LLnPm (m=1,2,3,4) means substitute low order 16 bits from label address in source token n, after adding m.
- *
- LHn means substitute high order 16 bits from label address in source token n. Must add 1 if address bit 15 is 1.
- *
- LHnPm (m=1,2,3,4) means substitute high order 16 bits from label address in source token n, after adding m. Must then add 1 if bit 15 is 1.
- *
- VLn means substitute low order 16 bits from 32 bit value in source token n.
- *
- VLnU means substitute low order 16 bits (unsigned) from 32 bit value in source token n.
- *
- VLnPm (m=1,2,3,4) means substitute low order 16 bits from 32 bit value in source token n, after adding m to value.
- *
- VLnPmU (m=1,2,3,4) means substitute low order 16 bits (unsigned) from 32 bit value in source token n, after adding m to value.
- *
- VHLn means substitute high order 16 bits from 32 bit value in source token n. Use this if later combined with low order 16 bits using "ori $1,$1,VLn". See logical and branch operations.
- *
- VHn means substitute high order 16 bits from 32 bit value in source token n, then add 1 if value's bit 15 is 1. Use this only if later instruction uses VLn($1) to calculate 32 bit address. See loads and stores.
- *
- VHLnPm (m=1,2,3,4) means substitute high order 16 bits from 32 bit value in source token n, after adding m. See VHLn.
- *
- VHnPm (m=1,2,3,4) means substitute high order 16 bits from 32 bit value in source token n, after adding m. Must then add 1 if bit 15 is 1. See VHn.
- *
- LLP is similar to LLn, but is needed for "label+100000" address offset. Immediate is added before taking low order 16.
- *
- LLPU is similar to LLnU, but is needed for "label+100000" address offset. Immediate is added before taking low order 16 (unsigned).
- *
- LLPPm (m=1,2,3,4) is similar to LLP except m is added along with mmediate before taking low order 16.
- *
- LHPA is similar to LHn, but is needed for "label+100000" address offset. Immediate is added before taking high order 16.
- *
- LHPN is similar to LHPA, used only by "la" instruction. Address resolved by "ori" so do not add 1 if bit 15 is 1.
- *
- LHPAPm (m=1,2,3,4) is similar to LHPA except value m is added along with immediate before taking high order 16.
- *
- LHL means substitute high order 16 bits from label address in token 2 of "la" (load address) source statement.
- *
- LAB means substitute textual label from last token of source statement. Used for various branches.
- *
- S32 means substitute the result of subtracting the constant value in last token from 32. Used by "ror", "rol".
- *
- DBNOP means Delayed Branching NOP - generate a "nop" instruction but only if delayed branching is enabled. Added in 3.4.1 release.
- *
- BROFFnm means substitute n if delayed branching is NOT enabled otherwise substitute m. n and m are single digit numbers indicating constant branch offset (in words). Added in 3.4.1 release.
- *
- * @param template a String containing template for basic statement.
- * @param tokenList a TokenList containing tokens from extended instruction.
- * @return String representing basic assembler statement.
- */
-
- public static String makeTemplateSubstitutions(MIPSprogram program, String template, TokenList theTokenList) {
- String instruction = template;
- int index;
- // Added 22 Jan 2008 by DPS. The DBNOP template means to generate a "nop" instruction if delayed branching
- // is enabled and generate no instruction otherwise.
-
- //This is the goal, but it leads to a cascade of
- // additional changes, so for now I will generate "nop" in either case, then come back to it for the
- // next major release.
- if (instruction.indexOf("DBNOP")>=0) {
+
+ public static String makeTemplateSubstitutions(MIPSprogram program, String template, TokenList theTokenList)
+ {
+ String instruction = template;
+ int index;
+ // Added 22 Jan 2008 by DPS. The DBNOP template means to generate a "nop" instruction if delayed branching
+ // is enabled and generate no instruction otherwise.
+
+ //This is the goal, but it leads to a cascade of
+ // additional changes, so for now I will generate "nop" in either case, then come back to it for the
+ // next major release.
+ if (instruction.indexOf("DBNOP") >= 0)
+ {
return Globals.getSettings().getDelayedBranchingEnabled() ? "nop" : "";
- }
- // substitute first operand token for template's RG1 or OP1, second for RG2 or OP2, etc
- for (int op=1; op=0) {
- // Label, last operand, has already been translated to address by symtab lookup
- String label = theTokenList.get(op).getValue();
- int addr = 0;
- int add = instruction.charAt(index+4)-48; // extract the digit following P
- try {
- addr = Binary.stringToInt(label) + add; // KENV 1/6/05
- }
- catch (NumberFormatException e) {
- // this won't happen...
- }
- // If bit 15 is 1, that means lower 16 bits will become a negative offset! To
- // compensate if that is the case, we need to add 1 to the high 16 bits.
- int extra = Binary.bitValue(addr,15);
- instruction = substitute(instruction,"LH"+op+"P"+add,String.valueOf((addr >> 16)+extra));
+ }
+ // substitute first operand token for template's RG1 or OP1, second for RG2 or OP2, etc
+ for (int op = 1; op < theTokenList.size(); op++)
+ {
+ instruction = substitute(instruction, "RG" + op, theTokenList.get(op).getValue());
+ instruction = substitute(instruction, "OP" + op, theTokenList.get(op).getValue());
+ // substitute upper 16 bits of label address, after adding singe digit constant following P
+ if ((index = instruction.indexOf("LH" + op + "P")) >= 0)
+ {
+ // Label, last operand, has already been translated to address by symtab lookup
+ String label = theTokenList.get(op).getValue();
+ int addr = 0;
+ int add = instruction.charAt(index + 4) - 48; // extract the digit following P
+ try
+ {
+ addr = Binary.stringToInt(label) + add; // KENV 1/6/05
+ }
+ catch (NumberFormatException e)
+ {
+ // this won't happen...
+ }
+ // If bit 15 is 1, that means lower 16 bits will become a negative offset! To
+ // compensate if that is the case, we need to add 1 to the high 16 bits.
+ int extra = Binary.bitValue(addr, 15);
+ instruction = substitute(instruction, "LH" + op + "P" + add, String.valueOf((addr >> 16) + extra));
}
- // substitute upper 16 bits of label address
- // NOTE: form LHnPm will not match here since it is discovered and substituted above.
- if (instruction.indexOf("LH"+op)>=0) {
- // Label, last operand, has already been translated to address by symtab lookup
- String label = theTokenList.get(op).getValue();
- int addr = 0;
- try {
- addr = Binary.stringToInt(label); // KENV 1/6/05
- }
- catch (NumberFormatException e) {
- // this won't happen...
- }
- // If bit 15 is 1, that means lower 16 bits will become a negative offset! To
- // compensate if that is the case, we need to add 1 to the high 16 bits.
- int extra = Binary.bitValue(addr,15);
- instruction = substitute(instruction,"LH"+op,String.valueOf((addr >> 16)+extra));
+ // substitute upper 16 bits of label address
+ // NOTE: form LHnPm will not match here since it is discovered and substituted above.
+ if (instruction.indexOf("LH" + op) >= 0)
+ {
+ // Label, last operand, has already been translated to address by symtab lookup
+ String label = theTokenList.get(op).getValue();
+ int addr = 0;
+ try
+ {
+ addr = Binary.stringToInt(label); // KENV 1/6/05
+ }
+ catch (NumberFormatException e)
+ {
+ // this won't happen...
+ }
+ // If bit 15 is 1, that means lower 16 bits will become a negative offset! To
+ // compensate if that is the case, we need to add 1 to the high 16 bits.
+ int extra = Binary.bitValue(addr, 15);
+ instruction = substitute(instruction, "LH" + op, String.valueOf((addr >> 16) + extra));
}
- // substitute lower 16 bits of label address, after adding single digit that follows P
- if ((index=instruction.indexOf("LL"+op+"P"))>=0) {
- // label has already been translated to address by symtab lookup.
- String label = theTokenList.get(op).getValue();
- int addr = 0;
- int add = instruction.charAt(index+4)-48; // digit that follows P
- try {
- addr = Binary.stringToInt(label) + add; // KENV 1/6/05
- }
- catch (NumberFormatException e) {
- // this won't happen...
- }
- instruction = substitute(instruction,"LL"+op+"P"+add,String.valueOf(addr << 16 >> 16));//addr & 0xffff));
- }
- // substitute lower 16 bits of label address.
- // NOTE: form LLnPm will not match here since it is discovered and substituted above.
- if ((index=instruction.indexOf("LL"+op))>=0) {
- // label has already been translated to address by symtab lookup.
- String label = theTokenList.get(op).getValue();
- int addr = 0;
- try {
- addr = Binary.stringToInt(label); // KENV 1/6/05
- }
- catch (NumberFormatException e) {
- // this won't happen...
- }
- if ((instruction.length() > index+3) && (instruction.charAt(index+3) == 'U')) {
- instruction = substitute(instruction,"LL"+op+"U",String.valueOf(addr & 0xffff));
- }
- else {
- instruction = substitute(instruction,"LL"+op,String.valueOf(addr << 16 >> 16));//addr & 0xffff));
- }
+ // substitute lower 16 bits of label address, after adding single digit that follows P
+ if ((index = instruction.indexOf("LL" + op + "P")) >= 0)
+ {
+ // label has already been translated to address by symtab lookup.
+ String label = theTokenList.get(op).getValue();
+ int addr = 0;
+ int add = instruction.charAt(index + 4) - 48; // digit that follows P
+ try
+ {
+ addr = Binary.stringToInt(label) + add; // KENV 1/6/05
+ }
+ catch (NumberFormatException e)
+ {
+ // this won't happen...
+ }
+ instruction = substitute(instruction, "LL" + op + "P" + add, String.valueOf(addr << 16 >> 16));//addr & 0xffff));
}
- // Substitute upper 16 bits of value after adding 1,2,3,4, (any single digit)
- // Added by DPS on 22 Jan 2008 to fix "ble" and "bgt" bug [do not adjust for bit 15==1]
- if ((index=instruction.indexOf("VHL"+op+"P"))>=0) {
- String value = theTokenList.get(op).getValue();
- int val = 0;
- int add = instruction.charAt(index+5)-'0'; // amount to add: 1,2,3,4 (any single digit)
- try { // KENV 1/6/05
- val = Binary.stringToInt(value) + add;
- }
- catch (NumberFormatException e) {
- // this won't happen...
- }
- instruction = substitute(instruction,"VHL"+op+"P"+add,String.valueOf(val >> 16));
- }
- // substitute upper 16 bits of value after adding 1,2,3,4, then adjust
- // if necessary, if resulting bit 15 is 1 (see "extra" below)
- if ((index=instruction.indexOf("VH"+op+"P"))>=0) {
- String value = theTokenList.get(op).getValue();
- int val = 0;
- int add = instruction.charAt(index+4)-'0'; // amount to add: 1,2,3,4 (any single digit)
- try { // KENV 1/6/05
- val = Binary.stringToInt(value) + add;
- }
- catch (NumberFormatException e) {
- // this won't happen...
- }
- // If bit 15 is 1, that means lower 16 bits will become a negative offset! To
- // compensate if that is the case, we need to add 1 to the high 16 bits.
- int extra = Binary.bitValue(val,15);
- instruction = substitute(instruction,"VH"+op+"P"+add,String.valueOf((val >> 16)+extra));
+ // substitute lower 16 bits of label address.
+ // NOTE: form LLnPm will not match here since it is discovered and substituted above.
+ if ((index = instruction.indexOf("LL" + op)) >= 0)
+ {
+ // label has already been translated to address by symtab lookup.
+ String label = theTokenList.get(op).getValue();
+ int addr = 0;
+ try
+ {
+ addr = Binary.stringToInt(label); // KENV 1/6/05
+ }
+ catch (NumberFormatException e)
+ {
+ // this won't happen...
+ }
+ if ((instruction.length() > index + 3) && (instruction.charAt(index + 3) == 'U'))
+ {
+ instruction = substitute(instruction, "LL" + op + "U", String.valueOf(addr & 0xffff));
+ }
+ else
+ {
+ instruction = substitute(instruction, "LL" + op, String.valueOf(addr << 16 >> 16));//addr & 0xffff));
+ }
}
- // substitute upper 16 bits of value, adjusted if necessary (see "extra" below)
- // NOTE: if VHnPm appears it will not match here; already substituted by code above
- if (instruction.indexOf("VH"+op)>=0) {
- String value = theTokenList.get(op).getValue();
- int val = 0;
- try {
- val = Binary.stringToInt(value); // KENV 1/6/05
- }
- catch (NumberFormatException e) {
- // this won't happen...
- }
- // If bit 15 is 1, that means lower 16 bits will become a negative offset! To
- // compensate if that is the case, we need to add 1 to the high 16 bits.
- int extra = Binary.bitValue(val,15);
- instruction = substitute(instruction,"VH"+op,String.valueOf((val >> 16)+extra));
- }
- // substitute lower 16 bits of value after adding specified amount (1,2,3,4)
- if ((index=instruction.indexOf("VL"+op+"P"))>=0) {
- String value = theTokenList.get(op).getValue();
- int val = 0;
- int add = instruction.charAt(index+4)-'0'; // P is followed by 1,2,3,4(any single digit OK)
- try { // KENV 1/6/05
- val = Binary.stringToInt(value) + add;
- }
- catch (NumberFormatException e) {
- // this won't happen...
- }
- if ((instruction.length() > index+5) && (instruction.charAt(index+5) == 'U')) {
- instruction = substitute(instruction,"VL"+op+"P"+add+"U",String.valueOf(val & 0xffff));
- }
- else {
- instruction = substitute(instruction,"VL"+op+"P"+add,String.valueOf(val << 16 >> 16));//val & 0xffff));
- }
+ // Substitute upper 16 bits of value after adding 1,2,3,4, (any single digit)
+ // Added by DPS on 22 Jan 2008 to fix "ble" and "bgt" bug [do not adjust for bit 15==1]
+ if ((index = instruction.indexOf("VHL" + op + "P")) >= 0)
+ {
+ String value = theTokenList.get(op).getValue();
+ int val = 0;
+ int add = instruction.charAt(index + 5) - '0'; // amount to add: 1,2,3,4 (any single digit)
+ try
+ { // KENV 1/6/05
+ val = Binary.stringToInt(value) + add;
+ }
+ catch (NumberFormatException e)
+ {
+ // this won't happen...
+ }
+ instruction = substitute(instruction, "VHL" + op + "P" + add, String.valueOf(val >> 16));
}
- // substitute lower 16 bits of value. NOTE: VLnPm already substituted by above code.
- if ((index=instruction.indexOf("VL"+op))>=0) {
- String value = theTokenList.get(op).getValue();
- int val = 0;
- try {
- val = Binary.stringToInt(value); // KENV 1/6/05
- }
- catch (NumberFormatException e) {
- // this won't happen...
- }
- if ((instruction.length() > index+3) && (instruction.charAt(index+3) == 'U')) {
- instruction = substitute(instruction,"VL"+op+"U",String.valueOf(val & 0xffff));
- }
- else {
- instruction = substitute(instruction,"VL"+op,String.valueOf(val << 16 >> 16));//val & 0xffff));
- }
+ // substitute upper 16 bits of value after adding 1,2,3,4, then adjust
+ // if necessary, if resulting bit 15 is 1 (see "extra" below)
+ if ((index = instruction.indexOf("VH" + op + "P")) >= 0)
+ {
+ String value = theTokenList.get(op).getValue();
+ int val = 0;
+ int add = instruction.charAt(index + 4) - '0'; // amount to add: 1,2,3,4 (any single digit)
+ try
+ { // KENV 1/6/05
+ val = Binary.stringToInt(value) + add;
+ }
+ catch (NumberFormatException e)
+ {
+ // this won't happen...
+ }
+ // If bit 15 is 1, that means lower 16 bits will become a negative offset! To
+ // compensate if that is the case, we need to add 1 to the high 16 bits.
+ int extra = Binary.bitValue(val, 15);
+ instruction = substitute(instruction, "VH" + op + "P" + add, String.valueOf((val >> 16) + extra));
}
- // substitute upper 16 bits of 32 bit value
- if (instruction.indexOf("VHL"+op)>=0) {
- // value has to be second operand token.
- String value = theTokenList.get(op).getValue(); // has to be token 2 position
- int val = 0;
- try {
- val = Binary.stringToInt(value); // KENV 1/6/05
- }
- catch (NumberFormatException e) {
- // this won't happen...
- }
- instruction = substitute(instruction,"VHL"+op,String.valueOf(val >> 16));
+ // substitute upper 16 bits of value, adjusted if necessary (see "extra" below)
+ // NOTE: if VHnPm appears it will not match here; already substituted by code above
+ if (instruction.indexOf("VH" + op) >= 0)
+ {
+ String value = theTokenList.get(op).getValue();
+ int val = 0;
+ try
+ {
+ val = Binary.stringToInt(value); // KENV 1/6/05
+ }
+ catch (NumberFormatException e)
+ {
+ // this won't happen...
+ }
+ // If bit 15 is 1, that means lower 16 bits will become a negative offset! To
+ // compensate if that is the case, we need to add 1 to the high 16 bits.
+ int extra = Binary.bitValue(val, 15);
+ instruction = substitute(instruction, "VH" + op, String.valueOf((val >> 16) + extra));
}
- }
- // substitute upper 16 bits of label address for "la"
- if (instruction.indexOf("LHL")>=0) {
+ // substitute lower 16 bits of value after adding specified amount (1,2,3,4)
+ if ((index = instruction.indexOf("VL" + op + "P")) >= 0)
+ {
+ String value = theTokenList.get(op).getValue();
+ int val = 0;
+ int add = instruction.charAt(index + 4) - '0'; // P is followed by 1,2,3,4(any single digit OK)
+ try
+ { // KENV 1/6/05
+ val = Binary.stringToInt(value) + add;
+ }
+ catch (NumberFormatException e)
+ {
+ // this won't happen...
+ }
+ if ((instruction.length() > index + 5) && (instruction.charAt(index + 5) == 'U'))
+ {
+ instruction = substitute(instruction, "VL" + op + "P" + add + "U", String.valueOf(val & 0xffff));
+ }
+ else
+ {
+ instruction = substitute(instruction, "VL" + op + "P" + add, String.valueOf(val << 16 >> 16));//val & 0xffff));
+ }
+ }
+ // substitute lower 16 bits of value. NOTE: VLnPm already substituted by above code.
+ if ((index = instruction.indexOf("VL" + op)) >= 0)
+ {
+ String value = theTokenList.get(op).getValue();
+ int val = 0;
+ try
+ {
+ val = Binary.stringToInt(value); // KENV 1/6/05
+ }
+ catch (NumberFormatException e)
+ {
+ // this won't happen...
+ }
+ if ((instruction.length() > index + 3) && (instruction.charAt(index + 3) == 'U'))
+ {
+ instruction = substitute(instruction, "VL" + op + "U", String.valueOf(val & 0xffff));
+ }
+ else
+ {
+ instruction = substitute(instruction, "VL" + op, String.valueOf(val << 16 >> 16));//val & 0xffff));
+ }
+ }
+ // substitute upper 16 bits of 32 bit value
+ if (instruction.indexOf("VHL" + op) >= 0)
+ {
+ // value has to be second operand token.
+ String value = theTokenList.get(op).getValue(); // has to be token 2 position
+ int val = 0;
+ try
+ {
+ val = Binary.stringToInt(value); // KENV 1/6/05
+ }
+ catch (NumberFormatException e)
+ {
+ // this won't happen...
+ }
+ instruction = substitute(instruction, "VHL" + op, String.valueOf(val >> 16));
+ }
+ }
+ // substitute upper 16 bits of label address for "la"
+ if (instruction.indexOf("LHL") >= 0)
+ {
// Label has already been translated to address by symtab lookup
String label = theTokenList.get(2).getValue(); // has to be token 2 position
int addr = 0;
- try {
- addr = Binary.stringToInt(label); // KENV 1/6/05
- }
- catch (NumberFormatException e) {
- // this won't happen...
- }
- instruction = substitute(instruction,"LHL",String.valueOf(addr >> 16));
- }
-
- // substitute upper 16 bits of label address after adding the digit that follows "P" and
- // also adding the immediate e.g. here+44($s0)
- // Address will be resolved using addition, so need to add 1 to upper half if bit 15 is 1.
- if ((index=instruction.indexOf("LHPAP"))>=0) {
- // Label has already been translated to address by symtab lookup
- String label = theTokenList.get(2).getValue(); // 2 is only possible token position
- String addend= theTokenList.get(4).getValue(); // 4 is only possible token position
- int addr = 0;
- int add = instruction.charAt(index+5)-48; // extract digit following P
- try {
- addr = Binary.stringToInt(label) + // KENV 1/6/05
- Binary.stringToInt(addend) + add;
- }
- catch (NumberFormatException e) {
- // this won't happen...
- }
- // If bit 15 is 1, that means lower 16 bits will become a negative offset! To
- // compensate if that is the case, we need to add 1 to the high 16 bits.
- int extra = Binary.bitValue(addr,15);
- instruction = substitute(instruction,"LHPAP"+add,String.valueOf((addr >> 16) + extra));
- }
- // substitute upper 16 bits of label address after adding constant e.g. here+4($s0)
- // Address will be resolved using addition, so need to add 1 to upper half if bit 15 is 1.
- // NOTE: format LHPAPm is recognized and substituted by the code above.
- if (instruction.indexOf("LHPA")>=0) {
- // Label has already been translated to address by symtab lookup
- String label = theTokenList.get(2).getValue(); // 2 is only possible token position
- String addend= theTokenList.get(4).getValue(); // 4 is only possible token position
- int addr = 0;
- try {
- addr = Binary.stringToInt(label) + // KENV 1/6/05
- Binary.stringToInt(addend);
- }
- catch (NumberFormatException e) {
- // this won't happen...
- }
- // If bit 15 is 1, that means lower 16 bits will become a negative offset! To
- // compensate if that is the case, we need to add 1 to the high 16 bits.
- int extra = Binary.bitValue(addr,15);
- instruction = substitute(instruction,"LHPA",String.valueOf((addr >> 16) + extra));
- }
- // substitute upper 16 bits of label address after adding constant e.g. here+4($s0)
- // Address will be resolved using "ori", so DO NOT adjust upper 16 if bit 15 is 1.
- // This only happens in the "la" (load address) instruction.
- if (instruction.indexOf("LHPN")>=0) {
- // Label has already been translated to address by symtab lookup
- String label = theTokenList.get(2).getValue(); // 2 is only possible token position
- String addend= theTokenList.get(4).getValue(); // 4 is only possible token position
- int addr = 0;
- try {
- addr = Binary.stringToInt(label) + // KENV 1/6/05
- Binary.stringToInt(addend);
- }
- catch (NumberFormatException e) {
- // this won't happen...
- }
- instruction = substitute(instruction,"LHPN",String.valueOf(addr >> 16));
- }
- // substitute lower 16 bits of label address after adding immediate value e.g. here+44($s0)
- // and also adding the digit following LLPP in the spec.
- if ((index=instruction.indexOf("LLPP"))>=0) {
- // label has already been translated to address by symtab lookup.
- String label = theTokenList.get(2).getValue(); // 2 is only possible token position
- String addend= theTokenList.get(4).getValue(); // 4 is only possible token position
- int addr = 0;
- int add = instruction.charAt(index+4)-48; // extract digit following P
- try {
- addr = Binary.stringToInt(label) + // KENV 1/6/05
- Binary.stringToInt(addend) + add;
-
- }
- catch (NumberFormatException e) {
- // this won't happen...
- }
- instruction = substitute(instruction,"LLPP"+add,String.valueOf(addr << 16 >> 16));//addr & 0xffff));
- }
- // substitute lower 16 bits of label address after adding immediate value e.g. here+44($s0)
- // NOTE: format LLPPm is recognized and substituted by the code above
- if ((index=instruction.indexOf("LLP"))>=0) {
- // label has already been translated to address by symtab lookup.
- String label = theTokenList.get(2).getValue(); // 2 is only possible token position
- String addend= theTokenList.get(4).getValue(); // 4 is only possible token position
- int addr = 0;
- try {
- addr = Binary.stringToInt(label) + // KENV 1/6/05
- Binary.stringToInt(addend);
-
- }
- catch (NumberFormatException e) {
- // this won't happen...
- }
- if ((instruction.length() > index+3) && (instruction.charAt(index+3) == 'U')) {
- instruction = substitute(instruction,"LLPU",String.valueOf(addr & 0xffff));
+ try
+ {
+ addr = Binary.stringToInt(label); // KENV 1/6/05
}
- else {
- instruction = substitute(instruction,"LLP",String.valueOf(addr << 16 >> 16));//addr & 0xffff));
+ catch (NumberFormatException e)
+ {
+ // this won't happen...
}
- }
- // 23-Jan-2008 DPS. Substitute correct constant branch offset depending on whether or not
- // delayed branching is enabled. BROFF is followed by 2 digits. The first is branch offset
- // to substitute if delayed branching is DISABLED, second is offset if ENABLED.
- if ((index=instruction.indexOf("BROFF"))>=0) {
- try {
- String disabled = instruction.substring(index+5, index+6);
- String enabled = instruction.substring(index+6, index+7);
- instruction = substitute(instruction,"BROFF"+disabled+enabled,
- Globals.getSettings().getDelayedBranchingEnabled() ? enabled : disabled );
- }
- catch (IndexOutOfBoundsException iooe) {
- instruction = substitute(instruction,"BROFF", "BAD_PSEUDO_OP_SPEC");
- }
- }
- // substitute Next higher Register for registers in token list (for "mfc1.d","mtc1.d")
- if (instruction.indexOf("NR")>=0) {
- for (int op=1; op=0) {
- instruction = substitute(instruction, "NR"+op,"$"+(regNumber+1));
- }
- }
- catch (NullPointerException e) { // not in RegisterFile, must be Coprocessor1 register
- regNumber = Coprocessor1.getRegisterNumber(token);
- if (regNumber>=0) {
- instruction = substitute(instruction, "NR"+op,"$f"+(regNumber+1));
- }
- }
- }
- }
-
- // substitute result of subtracting last token from 32 (rol and ror constant rotate amount)
- if (instruction.indexOf("S32")>=0) {
- String value = theTokenList.get(theTokenList.size()-1).getValue();
- int val = 0;
- try {
- val = Binary.stringToInt(value); // KENV 1/6/05
- }
- catch (NumberFormatException e) {
- // this won't happen...
- }
- instruction = substitute(instruction,"S32",Integer.toString(32-val));
- }
+ instruction = substitute(instruction, "LHL", String.valueOf(addr >> 16));
+ }
- // substitute label if necessary
- if (instruction.indexOf("LAB")>=0) {
- // label has to be last token. It has already been translated to address
- // by symtab lookup, so I need to get the text label back so parseLine() won't puke.
- String label = theTokenList.get(theTokenList.size()-1).getValue();
- Symbol sym = program.getLocalSymbolTable().getSymbolGivenAddressLocalOrGlobal(label);
- if (sym!=null) {
- // should never be null, since there would not be an address if label were not in symtab!
- // DPS 9 Dec 2007: The "substitute()" method will substitute for ALL matches. Here
- // we want to substitute only for the first match, for two reasons: (1) a statement
- // can only contain one label reference, its last operand, and (2) If the user's label
- // contains the substring "LAB", then substitute() will go into an infinite loop because
- // it will keep matching the substituted string!
- instruction = substituteFirst(instruction,"LAB",sym.getName());
+ // substitute upper 16 bits of label address after adding the digit that follows "P" and
+ // also adding the immediate e.g. here+44($s0)
+ // Address will be resolved using addition, so need to add 1 to upper half if bit 15 is 1.
+ if ((index = instruction.indexOf("LHPAP")) >= 0)
+ {
+ // Label has already been translated to address by symtab lookup
+ String label = theTokenList.get(2).getValue(); // 2 is only possible token position
+ String addend = theTokenList.get(4).getValue(); // 4 is only possible token position
+ int addr = 0;
+ int add = instruction.charAt(index + 5) - 48; // extract digit following P
+ try
+ {
+ addr = Binary.stringToInt(label) + // KENV 1/6/05
+ Binary.stringToInt(addend) + add;
}
- }
- return instruction;
- }
-
- // Performs a String substitution. Java 1.5 adds an overloaded String.replace method to
- // do this directly but I wanted to stay 1.4 compatible.
- // Modified 12 July 2006 to "substitute all occurances", not just the first.
- private static String substitute(String original, String find, String replacement) {
- if (original.indexOf(find)<0 || find.equals(replacement)) {
+ catch (NumberFormatException e)
+ {
+ // this won't happen...
+ }
+ // If bit 15 is 1, that means lower 16 bits will become a negative offset! To
+ // compensate if that is the case, we need to add 1 to the high 16 bits.
+ int extra = Binary.bitValue(addr, 15);
+ instruction = substitute(instruction, "LHPAP" + add, String.valueOf((addr >> 16) + extra));
+ }
+ // substitute upper 16 bits of label address after adding constant e.g. here+4($s0)
+ // Address will be resolved using addition, so need to add 1 to upper half if bit 15 is 1.
+ // NOTE: format LHPAPm is recognized and substituted by the code above.
+ if (instruction.indexOf("LHPA") >= 0)
+ {
+ // Label has already been translated to address by symtab lookup
+ String label = theTokenList.get(2).getValue(); // 2 is only possible token position
+ String addend = theTokenList.get(4).getValue(); // 4 is only possible token position
+ int addr = 0;
+ try
+ {
+ addr = Binary.stringToInt(label) + // KENV 1/6/05
+ Binary.stringToInt(addend);
+ }
+ catch (NumberFormatException e)
+ {
+ // this won't happen...
+ }
+ // If bit 15 is 1, that means lower 16 bits will become a negative offset! To
+ // compensate if that is the case, we need to add 1 to the high 16 bits.
+ int extra = Binary.bitValue(addr, 15);
+ instruction = substitute(instruction, "LHPA", String.valueOf((addr >> 16) + extra));
+ }
+ // substitute upper 16 bits of label address after adding constant e.g. here+4($s0)
+ // Address will be resolved using "ori", so DO NOT adjust upper 16 if bit 15 is 1.
+ // This only happens in the "la" (load address) instruction.
+ if (instruction.indexOf("LHPN") >= 0)
+ {
+ // Label has already been translated to address by symtab lookup
+ String label = theTokenList.get(2).getValue(); // 2 is only possible token position
+ String addend = theTokenList.get(4).getValue(); // 4 is only possible token position
+ int addr = 0;
+ try
+ {
+ addr = Binary.stringToInt(label) + // KENV 1/6/05
+ Binary.stringToInt(addend);
+ }
+ catch (NumberFormatException e)
+ {
+ // this won't happen...
+ }
+ instruction = substitute(instruction, "LHPN", String.valueOf(addr >> 16));
+ }
+ // substitute lower 16 bits of label address after adding immediate value e.g. here+44($s0)
+ // and also adding the digit following LLPP in the spec.
+ if ((index = instruction.indexOf("LLPP")) >= 0)
+ {
+ // label has already been translated to address by symtab lookup.
+ String label = theTokenList.get(2).getValue(); // 2 is only possible token position
+ String addend = theTokenList.get(4).getValue(); // 4 is only possible token position
+ int addr = 0;
+ int add = instruction.charAt(index + 4) - 48; // extract digit following P
+ try
+ {
+ addr = Binary.stringToInt(label) + // KENV 1/6/05
+ Binary.stringToInt(addend) + add;
+
+ }
+ catch (NumberFormatException e)
+ {
+ // this won't happen...
+ }
+ instruction = substitute(instruction, "LLPP" + add, String.valueOf(addr << 16 >> 16));//addr & 0xffff));
+ }
+ // substitute lower 16 bits of label address after adding immediate value e.g. here+44($s0)
+ // NOTE: format LLPPm is recognized and substituted by the code above
+ if ((index = instruction.indexOf("LLP")) >= 0)
+ {
+ // label has already been translated to address by symtab lookup.
+ String label = theTokenList.get(2).getValue(); // 2 is only possible token position
+ String addend = theTokenList.get(4).getValue(); // 4 is only possible token position
+ int addr = 0;
+ try
+ {
+ addr = Binary.stringToInt(label) + // KENV 1/6/05
+ Binary.stringToInt(addend);
+
+ }
+ catch (NumberFormatException e)
+ {
+ // this won't happen...
+ }
+ if ((instruction.length() > index + 3) && (instruction.charAt(index + 3) == 'U'))
+ {
+ instruction = substitute(instruction, "LLPU", String.valueOf(addr & 0xffff));
+ }
+ else
+ {
+ instruction = substitute(instruction, "LLP", String.valueOf(addr << 16 >> 16));//addr & 0xffff));
+ }
+ }
+ // 23-Jan-2008 DPS. Substitute correct constant branch offset depending on whether or not
+ // delayed branching is enabled. BROFF is followed by 2 digits. The first is branch offset
+ // to substitute if delayed branching is DISABLED, second is offset if ENABLED.
+ if ((index = instruction.indexOf("BROFF")) >= 0)
+ {
+ try
+ {
+ String disabled = instruction.substring(index + 5, index + 6);
+ String enabled = instruction.substring(index + 6, index + 7);
+ instruction = substitute(instruction, "BROFF" + disabled + enabled,
+ Globals.getSettings().getDelayedBranchingEnabled() ? enabled : disabled);
+ }
+ catch (IndexOutOfBoundsException iooe)
+ {
+ instruction = substitute(instruction, "BROFF", "BAD_PSEUDO_OP_SPEC");
+ }
+ }
+ // substitute Next higher Register for registers in token list (for "mfc1.d","mtc1.d")
+ if (instruction.indexOf("NR") >= 0)
+ {
+ for (int op = 1; op < theTokenList.size(); op++)
+ {
+ String token = theTokenList.get(op).getValue();
+ int regNumber;
+ try
+ { // if token is a RegisterFile register, substitute next higher register
+ regNumber = RegisterFile.getUserRegister(token).getNumber();
+ if (regNumber >= 0)
+ {
+ instruction = substitute(instruction, "NR" + op, "$" + (regNumber + 1));
+ }
+ }
+ catch (NullPointerException e)
+ { // not in RegisterFile, must be Coprocessor1 register
+ regNumber = Coprocessor1.getRegisterNumber(token);
+ if (regNumber >= 0)
+ {
+ instruction = substitute(instruction, "NR" + op, "$f" + (regNumber + 1));
+ }
+ }
+ }
+ }
+
+ // substitute result of subtracting last token from 32 (rol and ror constant rotate amount)
+ if (instruction.indexOf("S32") >= 0)
+ {
+ String value = theTokenList.get(theTokenList.size() - 1).getValue();
+ int val = 0;
+ try
+ {
+ val = Binary.stringToInt(value); // KENV 1/6/05
+ }
+ catch (NumberFormatException e)
+ {
+ // this won't happen...
+ }
+ instruction = substitute(instruction, "S32", Integer.toString(32 - val));
+ }
+
+ // substitute label if necessary
+ if (instruction.indexOf("LAB") >= 0)
+ {
+ // label has to be last token. It has already been translated to address
+ // by symtab lookup, so I need to get the text label back so parseLine() won't puke.
+ String label = theTokenList.get(theTokenList.size() - 1).getValue();
+ Symbol sym = program.getLocalSymbolTable().getSymbolGivenAddressLocalOrGlobal(label);
+ if (sym != null)
+ {
+ // should never be null, since there would not be an address if label were not in symtab!
+ // DPS 9 Dec 2007: The "substitute()" method will substitute for ALL matches. Here
+ // we want to substitute only for the first match, for two reasons: (1) a statement
+ // can only contain one label reference, its last operand, and (2) If the user's label
+ // contains the substring "LAB", then substitute() will go into an infinite loop because
+ // it will keep matching the substituted string!
+ instruction = substituteFirst(instruction, "LAB", sym.getName());
+ }
+ }
+ return instruction;
+ }
+
+ // Performs a String substitution. Java 1.5 adds an overloaded String.replace method to
+ // do this directly but I wanted to stay 1.4 compatible.
+ // Modified 12 July 2006 to "substitute all occurances", not just the first.
+ private static String substitute(String original, String find, String replacement)
+ {
+ if (original.indexOf(find) < 0 || find.equals(replacement))
+ {
return original; // second condition prevents infinite loop below
- }
- int i;
- String modified = original;
- while ((i=modified.indexOf(find))>=0) {
+ }
+ int i;
+ String modified = original;
+ while ((i = modified.indexOf(find)) >= 0)
+ {
modified = modified.substring(0, i) + replacement + modified.substring(i + find.length());
- }
- return modified;
- }
-
- // Performs a String substitution, but will only substitute for the first match.
- // Java 1.5 adds an overloaded String.replace method to do this directly but I
- // wanted to stay 1.4 compatible.
- private static String substituteFirst(String original, String find, String replacement) {
- if (original.indexOf(find)<0 || find.equals(replacement)) {
+ }
+ return modified;
+ }
+
+ // Performs a String substitution, but will only substitute for the first match.
+ // Java 1.5 adds an overloaded String.replace method to do this directly but I
+ // wanted to stay 1.4 compatible.
+ private static String substituteFirst(String original, String find, String replacement)
+ {
+ if (original.indexOf(find) < 0 || find.equals(replacement))
+ {
return original; // second condition prevents infinite loop below
- }
- int i;
- String modified = original;
- if ((i=modified.indexOf(find))>=0) {
+ }
+ int i;
+ String modified = original;
+ if ((i = modified.indexOf(find)) >= 0)
+ {
modified = modified.substring(0, i) + replacement + modified.substring(i + find.length());
- }
- return modified;
- }
-
-
+ }
+ return modified;
+ }
+
+ /**
+ * Get length in bytes that this extended instruction requires in its binary form. The answer depends on how many
+ * basic instructions it expands to. This may vary, if expansion includes a nop, depending on whether or not
+ * delayed branches are enabled. Each requires 4 bytes.
+ *
+ * @return int length in bytes of corresponding binary instruction(s).
+ */
+
+ public int getInstructionLength()
+ {
+ return getInstructionLength(translationStrings);
+ }
+
+ /**
+ * Get ArrayList of Strings that represent list of templates for basic instructions generated by this extended
+ * instruction.
+ *
+ * @return ArrayList of Strings.
+ */
+
+ public ArrayList getBasicIntructionTemplateList()
+ {
+ return translationStrings;
+ }
+
+ /**
+ * Get length in bytes that this extended instruction requires in its binary form if it includes an alternative
+ * expansion for compact memory (16 bit addressing) configuration. The answer depends on how many basic instructions
+ * it expands to. This may vary, if expansion includes a nop, depending on whether or not delayed branches are
+ * enabled. Each requires 4 bytes.
+ *
+ * @return int length in bytes of corresponding binary instruction(s). Returns 0 if an alternative expansion is not
+ * defined for this instruction.
+ */
+
+ public int getCompactInstructionLength()
+ {
+ return getInstructionLength(compactTranslationStrings);
+ }
+
+ /**
+ * Determine whether or not this pseudo-instruction has a second translation optimized for 16 bit address space: a
+ * compact version.
+ */
+ public boolean hasCompactTranslation()
+ {
+ return compactTranslationStrings != null;
+ }
+
+ /**
+ * Get ArrayList of Strings that represent list of templates for basic instructions generated by the "compact" or
+ * 16-bit version of this extended instruction.
+ *
+ * @return ArrayList of Strings. Returns null if the instruction does not have a compact alternative.
+ */
+
+ public ArrayList getCompactBasicIntructionTemplateList()
+ {
+ return compactTranslationStrings;
+ }
+
+
// Takes list of basic instructions that this extended instruction
// expands to, which is a string, and breaks out into separate
// instructions. They are separated by '\n' character.
-
- private ArrayList buildTranslationList(String translation) {
- if (translation == null || translation.length() == 0) {
+
+ private ArrayList buildTranslationList(String translation)
+ {
+ if (translation == null || translation.length() == 0)
+ {
return null;
- }
- ArrayList translationList = new ArrayList();
- StringTokenizer st = new StringTokenizer(translation,"\n");
- while (st.hasMoreTokens()) {
+ }
+ ArrayList translationList = new ArrayList();
+ StringTokenizer st = new StringTokenizer(translation, "\n");
+ while (st.hasMoreTokens())
+ {
translationList.add(st.nextToken());
- }
- return translationList;
- }
-
-
-
+ }
+ return translationList;
+ }
+
+
/*
- * Get length in bytes that this extended instruction requires in its
- * binary form. The answer depends on how many basic instructions it
+ * Get length in bytes that this extended instruction requires in its
+ * binary form. The answer depends on how many basic instructions it
* expands to. This may vary, if expansion includes a nop, depending on
* whether or not delayed branches are enabled. Each requires 4 bytes.
* Returns length in bytes of corresponding binary instruction(s).
* Returns 0 if the ArrayList is null or empty.
- */
- private int getInstructionLength(ArrayList translationList) {
- if (translationList == null || translationList.size() == 0) {
+ */
+ private int getInstructionLength(ArrayList translationList)
+ {
+ if (translationList == null || translationList.size() == 0)
+ {
return 0;
- }
- // If instruction template is DBNOP, that means generate a "nop" instruction but only
- // if Delayed branching is enabled. Otherwise generate nothing. If generating nothing,
- // then don't count the nop in the instruction length. DPS 23-Jan-2008
- int instructionCount = 0;
- for (int i=0; i=0 && !Globals.getSettings().getDelayedBranchingEnabled())
- continue;
+ }
+ // If instruction template is DBNOP, that means generate a "nop" instruction but only
+ // if Delayed branching is enabled. Otherwise generate nothing. If generating nothing,
+ // then don't count the nop in the instruction length. DPS 23-Jan-2008
+ int instructionCount = 0;
+ for (int i = 0; i < translationList.size(); i++)
+ {
+ if (((String) translationList.get(i)).indexOf("DBNOP") >= 0 && !Globals.getSettings().getDelayedBranchingEnabled())
+ {
+ continue;
+ }
instructionCount++;
- }
- return 4 * instructionCount;
- }
-
- }
\ No newline at end of file
+ }
+ return 4 * instructionCount;
+ }
+
+}
diff --git a/src/main/java/mars/mips/instructions/Instruction.java b/src/main/java/mars/mips/instructions/Instruction.java
index b73d41f..d6b69e3 100644
--- a/src/main/java/mars/mips/instructions/Instruction.java
+++ b/src/main/java/mars/mips/instructions/Instruction.java
@@ -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 exampleFormat). **/
- 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 exampleFormat). **/
+ 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
*
*
* @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).");
}
}
}
diff --git a/src/main/java/mars/mips/instructions/InstructionSet.java b/src/main/java/mars/mips/instructions/InstructionSet.java
index 5b186a4..19b62f7 100644
--- a/src/main/java/mars/mips/instructions/InstructionSet.java
+++ b/src/main/java/mars/mips/instructions/InstructionSet.java
@@ -3,10 +3,7 @@ package mars.mips.instructions;
import mars.Globals;
import mars.ProcessingException;
import mars.ProgramStatement;
-import mars.mips.hardware.AddressErrorException;
-import mars.mips.hardware.Coprocessor0;
-import mars.mips.hardware.Coprocessor1;
-import mars.mips.hardware.RegisterFile;
+import mars.mips.hardware.*;
import mars.mips.instructions.syscalls.Syscall;
import mars.simulator.DelayedBranch;
import mars.simulator.Exceptions;
@@ -50,3315 +47,3497 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
- * The list of Instruction objects, each of which represents a MIPS instruction.
- * The instruction may either be basic (translates into binary machine code) or
- * extended (translates into sequence of one or more basic instructions).
+ * The list of Instruction objects, each of which represents a MIPS instruction. The instruction may either be basic
+ * (translates into binary machine code) or extended (translates into sequence of one or more basic instructions).
*
* @author Pete Sanderson and Ken Vollmar
* @version August 2003-5
*/
- public class InstructionSet
- {
- private ArrayList instructionList;
- private ArrayList opcodeMatchMaps;
- private SyscallLoader syscallLoader;
+public class InstructionSet
+{
+ private final ArrayList instructionList;
+
+ private ArrayList opcodeMatchMaps;
+
+ private SyscallLoader syscallLoader;
+
/**
* Creates a new InstructionSet object.
*/
- public InstructionSet()
- {
- instructionList = new ArrayList();
-
- }
+ public InstructionSet()
+ {
+ instructionList = new ArrayList();
+
+ }
+
/**
* Retrieve the current instruction set.
*/
- public ArrayList getInstructionList()
- {
- return instructionList;
-
- }
+ public ArrayList getInstructionList()
+ {
+ return instructionList;
+
+ }
+
/**
- * Adds all instructions to the set. A given extended instruction may have
- * more than one Instruction object, depending on how many formats it can have.
+ * Adds all instructions to the set. A given extended instruction may have more than one Instruction object,
+ * depending on how many formats it can have.
+ *
* @see Instruction
* @see BasicInstruction
* @see ExtendedInstruction
*/
- public void populate()
- {
+ public void populate()
+ {
/* Here is where the parade begins. Every instruction is added to the set here.*/
-
+
// //////////////////////////////////// BASIC INSTRUCTIONS START HERE ////////////////////////////////
-
- instructionList.add(
- new BasicInstruction("nop",
- "Null operation : machine code is all zeroes",
+
+ instructionList.add(
+ new BasicInstruction("nop",
+ "Null operation : machine code is all zeroes",
BasicInstructionFormat.R_FORMAT,
"000000 00000 00000 00000 00000 000000",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- // Hey I like this so far!
- }
- }));
- instructionList.add(
- new BasicInstruction("add $t1,$t2,$t3",
- "Addition with overflow : set $t1 to ($t2 plus $t3)",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ // Hey I like this so far!
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("add $t1,$t2,$t3",
+ "Addition with overflow : set $t1 to ($t2 plus $t3)",
BasicInstructionFormat.R_FORMAT,
"000000 sssss ttttt fffff 00000 100000",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- int add1 = RegisterFile.getValue(operands[1]);
- int add2 = RegisterFile.getValue(operands[2]);
- int sum = add1 + add2;
- // overflow on A+B detected when A and B have same sign and A+B has other sign.
- if ((add1 >= 0 && add2 >= 0 && sum < 0)
- || (add1 < 0 && add2 < 0 && sum >= 0))
- {
- throw new ProcessingException(statement,
- "arithmetic overflow",Exceptions.ARITHMETIC_OVERFLOW_EXCEPTION);
- }
- RegisterFile.updateRegister(operands[0], sum);
- }
- }));
- instructionList.add(
- new BasicInstruction("sub $t1,$t2,$t3",
- "Subtraction with overflow : set $t1 to ($t2 minus $t3)",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ int add1 = RegisterFile.getValue(operands[1]);
+ int add2 = RegisterFile.getValue(operands[2]);
+ int sum = add1 + add2;
+ // overflow on A+B detected when A and B have same sign and A+B has other sign.
+ if ((add1 >= 0 && add2 >= 0 && sum < 0)
+ || (add1 < 0 && add2 < 0 && sum >= 0))
+ {
+ throw new ProcessingException(statement,
+ "arithmetic overflow", Exceptions.ARITHMETIC_OVERFLOW_EXCEPTION);
+ }
+ RegisterFile.updateRegister(operands[0], sum);
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("sub $t1,$t2,$t3",
+ "Subtraction with overflow : set $t1 to ($t2 minus $t3)",
BasicInstructionFormat.R_FORMAT,
"000000 sssss ttttt fffff 00000 100010",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- int sub1 = RegisterFile.getValue(operands[1]);
- int sub2 = RegisterFile.getValue(operands[2]);
- int dif = sub1 - sub2;
- // overflow on A-B detected when A and B have opposite signs and A-B has B's sign
- if ((sub1 >= 0 && sub2 < 0 && dif < 0)
- || (sub1 < 0 && sub2 >= 0 && dif >= 0))
- {
- throw new ProcessingException(statement,
- "arithmetic overflow",Exceptions.ARITHMETIC_OVERFLOW_EXCEPTION);
- }
- RegisterFile.updateRegister(operands[0], dif);
- }
- }));
- instructionList.add(
- new BasicInstruction("addi $t1,$t2,-100",
- "Addition immediate with overflow : set $t1 to ($t2 plus signed 16-bit immediate)",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ int sub1 = RegisterFile.getValue(operands[1]);
+ int sub2 = RegisterFile.getValue(operands[2]);
+ int dif = sub1 - sub2;
+ // overflow on A-B detected when A and B have opposite signs and A-B has B's sign
+ if ((sub1 >= 0 && sub2 < 0 && dif < 0)
+ || (sub1 < 0 && sub2 >= 0 && dif >= 0))
+ {
+ throw new ProcessingException(statement,
+ "arithmetic overflow", Exceptions.ARITHMETIC_OVERFLOW_EXCEPTION);
+ }
+ RegisterFile.updateRegister(operands[0], dif);
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("addi $t1,$t2,-100",
+ "Addition immediate with overflow : set $t1 to ($t2 plus signed 16-bit immediate)",
BasicInstructionFormat.I_FORMAT,
"001000 sssss fffff tttttttttttttttt",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- int add1 = RegisterFile.getValue(operands[1]);
- int add2 = operands[2] << 16 >> 16;
- int sum = add1 + add2;
- // overflow on A+B detected when A and B have same sign and A+B has other sign.
- if ((add1 >= 0 && add2 >= 0 && sum < 0)
- || (add1 < 0 && add2 < 0 && sum >= 0))
- {
- throw new ProcessingException(statement,
- "arithmetic overflow",Exceptions.ARITHMETIC_OVERFLOW_EXCEPTION);
- }
- RegisterFile.updateRegister(operands[0], sum);
- }
- }));
- instructionList.add(
- new BasicInstruction("addu $t1,$t2,$t3",
- "Addition unsigned without overflow : set $t1 to ($t2 plus $t3), no overflow",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ int add1 = RegisterFile.getValue(operands[1]);
+ int add2 = operands[2] << 16 >> 16;
+ int sum = add1 + add2;
+ // overflow on A+B detected when A and B have same sign and A+B has other sign.
+ if ((add1 >= 0 && add2 >= 0 && sum < 0)
+ || (add1 < 0 && add2 < 0 && sum >= 0))
+ {
+ throw new ProcessingException(statement,
+ "arithmetic overflow", Exceptions.ARITHMETIC_OVERFLOW_EXCEPTION);
+ }
+ RegisterFile.updateRegister(operands[0], sum);
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("addu $t1,$t2,$t3",
+ "Addition unsigned without overflow : set $t1 to ($t2 plus $t3), no overflow",
BasicInstructionFormat.R_FORMAT,
"000000 sssss ttttt fffff 00000 100001",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- RegisterFile.updateRegister(operands[0],
- RegisterFile.getValue(operands[1])
- + RegisterFile.getValue(operands[2]));
- }
- }));
- instructionList.add(
- new BasicInstruction("subu $t1,$t2,$t3",
- "Subtraction unsigned without overflow : set $t1 to ($t2 minus $t3), no overflow",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ RegisterFile.updateRegister(operands[0],
+ RegisterFile.getValue(operands[1])
+ + RegisterFile.getValue(operands[2]));
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("subu $t1,$t2,$t3",
+ "Subtraction unsigned without overflow : set $t1 to ($t2 minus $t3), no overflow",
BasicInstructionFormat.R_FORMAT,
"000000 sssss ttttt fffff 00000 100011",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- RegisterFile.updateRegister(operands[0],
- RegisterFile.getValue(operands[1])
- - RegisterFile.getValue(operands[2]));
- }
- }));
- instructionList.add(
- new BasicInstruction("addiu $t1,$t2,-100",
- "Addition immediate unsigned without overflow : set $t1 to ($t2 plus signed 16-bit immediate), no overflow",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ RegisterFile.updateRegister(operands[0],
+ RegisterFile.getValue(operands[1])
+ - RegisterFile.getValue(operands[2]));
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("addiu $t1,$t2,-100",
+ "Addition immediate unsigned without overflow : set $t1 to ($t2 plus signed 16-bit immediate), no overflow",
BasicInstructionFormat.I_FORMAT,
"001001 sssss fffff tttttttttttttttt",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- RegisterFile.updateRegister(operands[0],
- RegisterFile.getValue(operands[1])
- + (operands[2] << 16 >> 16));
- }
- }));
- instructionList.add(
- new BasicInstruction("mult $t1,$t2",
- "Multiplication : Set hi to high-order 32 bits, lo to low-order 32 bits of the product of $t1 and $t2 (use mfhi to access hi, mflo to access lo)",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ RegisterFile.updateRegister(operands[0],
+ RegisterFile.getValue(operands[1])
+ + (operands[2] << 16 >> 16));
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("mult $t1,$t2",
+ "Multiplication : Set hi to high-order 32 bits, lo to low-order 32 bits of the product of $t1 and $t2 (use mfhi to access hi, mflo to access lo)",
BasicInstructionFormat.R_FORMAT,
"000000 fffff sssss 00000 00000 011000",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- long product = (long) RegisterFile.getValue(operands[0])
- * (long) RegisterFile.getValue(operands[1]);
- // Register 33 is HIGH and 34 is LOW
- RegisterFile.updateRegister(33, (int) (product >> 32));
- RegisterFile.updateRegister(34, (int) ((product << 32) >> 32));
- }
- }));
- instructionList.add(
- new BasicInstruction("multu $t1,$t2",
- "Multiplication unsigned : Set HI to high-order 32 bits, LO to low-order 32 bits of the product of unsigned $t1 and $t2 (use mfhi to access HI, mflo to access LO)",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ long product = (long) RegisterFile.getValue(operands[0])
+ * (long) RegisterFile.getValue(operands[1]);
+ // Register 33 is HIGH and 34 is LOW
+ RegisterFile.updateRegister(33, (int) (product >> 32));
+ RegisterFile.updateRegister(34, (int) ((product << 32) >> 32));
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("multu $t1,$t2",
+ "Multiplication unsigned : Set HI to high-order 32 bits, LO to low-order 32 bits of the product of unsigned $t1 and $t2 (use mfhi to access HI, mflo to access LO)",
BasicInstructionFormat.R_FORMAT,
"000000 fffff sssss 00000 00000 011001",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- long product = (((long) RegisterFile.getValue(operands[0]))<<32>>>32)
- * (((long) RegisterFile.getValue(operands[1]))<<32>>>32);
- // Register 33 is HIGH and 34 is LOW
- RegisterFile.updateRegister(33, (int) (product >> 32));
- RegisterFile.updateRegister(34, (int) ((product << 32) >> 32));
- }
- }));
- instructionList.add(
- new BasicInstruction("mul $t1,$t2,$t3",
- "Multiplication without overflow : Set HI to high-order 32 bits, LO and $t1 to low-order 32 bits of the product of $t2 and $t3 (use mfhi to access HI, mflo to access LO)",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ long product = (((long) RegisterFile.getValue(operands[0])) << 32 >>> 32)
+ * (((long) RegisterFile.getValue(operands[1])) << 32 >>> 32);
+ // Register 33 is HIGH and 34 is LOW
+ RegisterFile.updateRegister(33, (int) (product >> 32));
+ RegisterFile.updateRegister(34, (int) ((product << 32) >> 32));
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("mul $t1,$t2,$t3",
+ "Multiplication without overflow : Set HI to high-order 32 bits, LO and $t1 to low-order 32 bits of the product of $t2 and $t3 (use mfhi to access HI, mflo to access LO)",
BasicInstructionFormat.R_FORMAT,
"011100 sssss ttttt fffff 00000 000010",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- long product = (long) RegisterFile.getValue(operands[1])
- * (long) RegisterFile.getValue(operands[2]);
- RegisterFile.updateRegister(operands[0],
- (int) ((product << 32) >> 32));
- // Register 33 is HIGH and 34 is LOW. Not required by MIPS; SPIM does it.
- RegisterFile.updateRegister(33, (int) (product >> 32));
- RegisterFile.updateRegister(34, (int) ((product << 32) >> 32));
- }
- }));
- instructionList.add(
- new BasicInstruction("madd $t1,$t2",
- "Multiply add : Multiply $t1 by $t2 then increment HI by high-order 32 bits of product, increment LO by low-order 32 bits of product (use mfhi to access HI, mflo to access LO)",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ long product = (long) RegisterFile.getValue(operands[1])
+ * (long) RegisterFile.getValue(operands[2]);
+ RegisterFile.updateRegister(operands[0],
+ (int) ((product << 32) >> 32));
+ // Register 33 is HIGH and 34 is LOW. Not required by MIPS; SPIM does it.
+ RegisterFile.updateRegister(33, (int) (product >> 32));
+ RegisterFile.updateRegister(34, (int) ((product << 32) >> 32));
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("madd $t1,$t2",
+ "Multiply add : Multiply $t1 by $t2 then increment HI by high-order 32 bits of product, increment LO by low-order 32 bits of product (use mfhi to access HI, mflo to access LO)",
BasicInstructionFormat.R_FORMAT,
"011100 fffff sssss 00000 00000 000000",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- long product = (long) RegisterFile.getValue(operands[0])
- * (long) RegisterFile.getValue(operands[1]);
- // Register 33 is HIGH and 34 is LOW.
- long contentsHiLo = Binary.twoIntsToLong(
- RegisterFile.getValue(33), RegisterFile.getValue(34));
- long sum = contentsHiLo + product;
- RegisterFile.updateRegister(33, Binary.highOrderLongToInt(sum));
- RegisterFile.updateRegister(34, Binary.lowOrderLongToInt(sum));
- }
- }));
- instructionList.add(
- new BasicInstruction("maddu $t1,$t2",
- "Multiply add unsigned : Multiply $t1 by $t2 then increment HI by high-order 32 bits of product, increment LO by low-order 32 bits of product, unsigned (use mfhi to access HI, mflo to access LO)",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ long product = (long) RegisterFile.getValue(operands[0])
+ * (long) RegisterFile.getValue(operands[1]);
+ // Register 33 is HIGH and 34 is LOW.
+ long contentsHiLo = Binary.twoIntsToLong(
+ RegisterFile.getValue(33), RegisterFile.getValue(34));
+ long sum = contentsHiLo + product;
+ RegisterFile.updateRegister(33, Binary.highOrderLongToInt(sum));
+ RegisterFile.updateRegister(34, Binary.lowOrderLongToInt(sum));
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("maddu $t1,$t2",
+ "Multiply add unsigned : Multiply $t1 by $t2 then increment HI by high-order 32 bits of product, increment LO by low-order 32 bits of product, unsigned (use mfhi to access HI, mflo to access LO)",
BasicInstructionFormat.R_FORMAT,
"011100 fffff sssss 00000 00000 000001",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- long product = (((long) RegisterFile.getValue(operands[0]))<<32>>>32)
- * (((long) RegisterFile.getValue(operands[1]))<<32>>>32);
- // Register 33 is HIGH and 34 is LOW.
- long contentsHiLo = Binary.twoIntsToLong(
- RegisterFile.getValue(33), RegisterFile.getValue(34));
- long sum = contentsHiLo + product;
- RegisterFile.updateRegister(33, Binary.highOrderLongToInt(sum));
- RegisterFile.updateRegister(34, Binary.lowOrderLongToInt(sum));
- }
- }));
- instructionList.add(
- new BasicInstruction("msub $t1,$t2",
- "Multiply subtract : Multiply $t1 by $t2 then decrement HI by high-order 32 bits of product, decrement LO by low-order 32 bits of product (use mfhi to access HI, mflo to access LO)",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ long product = (((long) RegisterFile.getValue(operands[0])) << 32 >>> 32)
+ * (((long) RegisterFile.getValue(operands[1])) << 32 >>> 32);
+ // Register 33 is HIGH and 34 is LOW.
+ long contentsHiLo = Binary.twoIntsToLong(
+ RegisterFile.getValue(33), RegisterFile.getValue(34));
+ long sum = contentsHiLo + product;
+ RegisterFile.updateRegister(33, Binary.highOrderLongToInt(sum));
+ RegisterFile.updateRegister(34, Binary.lowOrderLongToInt(sum));
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("msub $t1,$t2",
+ "Multiply subtract : Multiply $t1 by $t2 then decrement HI by high-order 32 bits of product, decrement LO by low-order 32 bits of product (use mfhi to access HI, mflo to access LO)",
BasicInstructionFormat.R_FORMAT,
"011100 fffff sssss 00000 00000 000100",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- long product = (long) RegisterFile.getValue(operands[0])
- * (long) RegisterFile.getValue(operands[1]);
- // Register 33 is HIGH and 34 is LOW.
- long contentsHiLo = Binary.twoIntsToLong(
- RegisterFile.getValue(33), RegisterFile.getValue(34));
- long diff = contentsHiLo - product;
- RegisterFile.updateRegister(33, Binary.highOrderLongToInt(diff));
- RegisterFile.updateRegister(34, Binary.lowOrderLongToInt(diff));
- }
- }));
- instructionList.add(
- new BasicInstruction("msubu $t1,$t2",
- "Multiply subtract unsigned : Multiply $t1 by $t2 then decrement HI by high-order 32 bits of product, decement LO by low-order 32 bits of product, unsigned (use mfhi to access HI, mflo to access LO)",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ long product = (long) RegisterFile.getValue(operands[0])
+ * (long) RegisterFile.getValue(operands[1]);
+ // Register 33 is HIGH and 34 is LOW.
+ long contentsHiLo = Binary.twoIntsToLong(
+ RegisterFile.getValue(33), RegisterFile.getValue(34));
+ long diff = contentsHiLo - product;
+ RegisterFile.updateRegister(33, Binary.highOrderLongToInt(diff));
+ RegisterFile.updateRegister(34, Binary.lowOrderLongToInt(diff));
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("msubu $t1,$t2",
+ "Multiply subtract unsigned : Multiply $t1 by $t2 then decrement HI by high-order 32 bits of product, decement LO by low-order 32 bits of product, unsigned (use mfhi to access HI, mflo to access LO)",
BasicInstructionFormat.R_FORMAT,
"011100 fffff sssss 00000 00000 000101",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- long product = (((long) RegisterFile.getValue(operands[0]))<<32>>>32)
- * (((long) RegisterFile.getValue(operands[1]))<<32>>>32);
- // Register 33 is HIGH and 34 is LOW.
- long contentsHiLo = Binary.twoIntsToLong(
- RegisterFile.getValue(33), RegisterFile.getValue(34));
- long diff = contentsHiLo - product;
- RegisterFile.updateRegister(33, Binary.highOrderLongToInt(diff));
- RegisterFile.updateRegister(34, Binary.lowOrderLongToInt(diff));
- }
- }));
- instructionList.add(
- new BasicInstruction("div $t1,$t2",
- "Division with overflow : Divide $t1 by $t2 then set LO to quotient and HI to remainder (use mfhi to access HI, mflo to access LO)",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ long product = (((long) RegisterFile.getValue(operands[0])) << 32 >>> 32)
+ * (((long) RegisterFile.getValue(operands[1])) << 32 >>> 32);
+ // Register 33 is HIGH and 34 is LOW.
+ long contentsHiLo = Binary.twoIntsToLong(
+ RegisterFile.getValue(33), RegisterFile.getValue(34));
+ long diff = contentsHiLo - product;
+ RegisterFile.updateRegister(33, Binary.highOrderLongToInt(diff));
+ RegisterFile.updateRegister(34, Binary.lowOrderLongToInt(diff));
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("div $t1,$t2",
+ "Division with overflow : Divide $t1 by $t2 then set LO to quotient and HI to remainder (use mfhi to access HI, mflo to access LO)",
BasicInstructionFormat.R_FORMAT,
"000000 fffff sssss 00000 00000 011010",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- if (RegisterFile.getValue(operands[1]) == 0)
- {
- // Note: no exceptions and undefined results for zero div
- // COD3 Appendix A says "with overflow" but MIPS 32 instruction set
- // specification says "no arithmetic exception under any circumstances".
- return;
- }
-
- // Register 33 is HIGH and 34 is LOW
- RegisterFile.updateRegister(33,
- RegisterFile.getValue(operands[0])
- % RegisterFile.getValue(operands[1]));
- RegisterFile.updateRegister(34,
- RegisterFile.getValue(operands[0])
- / RegisterFile.getValue(operands[1]));
- }
- }));
- instructionList.add(
- new BasicInstruction("divu $t1,$t2",
- "Division unsigned without overflow : Divide unsigned $t1 by $t2 then set LO to quotient and HI to remainder (use mfhi to access HI, mflo to access LO)",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ if (RegisterFile.getValue(operands[1]) == 0)
+ {
+ // Note: no exceptions and undefined results for zero div
+ // COD3 Appendix A says "with overflow" but MIPS 32 instruction set
+ // specification says "no arithmetic exception under any circumstances".
+ return;
+ }
+
+ // Register 33 is HIGH and 34 is LOW
+ RegisterFile.updateRegister(33,
+ RegisterFile.getValue(operands[0])
+ % RegisterFile.getValue(operands[1]));
+ RegisterFile.updateRegister(34,
+ RegisterFile.getValue(operands[0])
+ / RegisterFile.getValue(operands[1]));
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("divu $t1,$t2",
+ "Division unsigned without overflow : Divide unsigned $t1 by $t2 then set LO to quotient and HI to remainder (use mfhi to access HI, mflo to access LO)",
BasicInstructionFormat.R_FORMAT,
"000000 fffff sssss 00000 00000 011011",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- if (RegisterFile.getValue(operands[1]) == 0)
- {
- // Note: no exceptions, and undefined results for zero divide
- return;
- }
- long oper1 = ((long)RegisterFile.getValue(operands[0])) << 32 >>> 32;
- long oper2 = ((long)RegisterFile.getValue(operands[1])) << 32 >>> 32;
- // Register 33 is HIGH and 34 is LOW
- RegisterFile.updateRegister(33,
- (int) (((oper1 % oper2) << 32) >> 32));
- RegisterFile.updateRegister(34,
- (int) (((oper1 / oper2) << 32) >> 32));
- }
- }));
- instructionList.add(
- new BasicInstruction("mfhi $t1",
- "Move from HI register : Set $t1 to contents of HI (see multiply and divide operations)",
- BasicInstructionFormat.R_FORMAT,
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ if (RegisterFile.getValue(operands[1]) == 0)
+ {
+ // Note: no exceptions, and undefined results for zero divide
+ return;
+ }
+ long oper1 = ((long) RegisterFile.getValue(operands[0])) << 32 >>> 32;
+ long oper2 = ((long) RegisterFile.getValue(operands[1])) << 32 >>> 32;
+ // Register 33 is HIGH and 34 is LOW
+ RegisterFile.updateRegister(33,
+ (int) (((oper1 % oper2) << 32) >> 32));
+ RegisterFile.updateRegister(34,
+ (int) (((oper1 / oper2) << 32) >> 32));
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("mfhi $t1",
+ "Move from HI register : Set $t1 to contents of HI (see multiply and divide operations)",
+ BasicInstructionFormat.R_FORMAT,
"000000 00000 00000 fffff 00000 010000",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- RegisterFile.updateRegister(operands[0],
- RegisterFile.getValue(33));
- }
- }));
- instructionList.add(
- new BasicInstruction("mflo $t1",
- "Move from LO register : Set $t1 to contents of LO (see multiply and divide operations)",
- BasicInstructionFormat.R_FORMAT,
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ RegisterFile.updateRegister(operands[0],
+ RegisterFile.getValue(33));
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("mflo $t1",
+ "Move from LO register : Set $t1 to contents of LO (see multiply and divide operations)",
+ BasicInstructionFormat.R_FORMAT,
"000000 00000 00000 fffff 00000 010010",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- RegisterFile.updateRegister(operands[0],
- RegisterFile.getValue(34));
- }
- }));
- instructionList.add(
- new BasicInstruction("mthi $t1",
- "Move to HI registerr : Set HI to contents of $t1 (see multiply and divide operations)",
- BasicInstructionFormat.R_FORMAT,
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ RegisterFile.updateRegister(operands[0],
+ RegisterFile.getValue(34));
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("mthi $t1",
+ "Move to HI registerr : Set HI to contents of $t1 (see multiply and divide operations)",
+ BasicInstructionFormat.R_FORMAT,
"000000 fffff 00000 00000 00000 010001",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- RegisterFile.updateRegister(33,
- RegisterFile.getValue(operands[0]));
- }
- }));
- instructionList.add(
- new BasicInstruction("mtlo $t1",
- "Move to LO register : Set LO to contents of $t1 (see multiply and divide operations)",
- BasicInstructionFormat.R_FORMAT,
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ RegisterFile.updateRegister(33,
+ RegisterFile.getValue(operands[0]));
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("mtlo $t1",
+ "Move to LO register : Set LO to contents of $t1 (see multiply and divide operations)",
+ BasicInstructionFormat.R_FORMAT,
"000000 fffff 00000 00000 00000 010011",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- RegisterFile.updateRegister(34,
- RegisterFile.getValue(operands[0]));
- }
- }));
- instructionList.add(
- new BasicInstruction("and $t1,$t2,$t3",
- "Bitwise AND : Set $t1 to bitwise AND of $t2 and $t3",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ RegisterFile.updateRegister(34,
+ RegisterFile.getValue(operands[0]));
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("and $t1,$t2,$t3",
+ "Bitwise AND : Set $t1 to bitwise AND of $t2 and $t3",
BasicInstructionFormat.R_FORMAT,
"000000 sssss ttttt fffff 00000 100100",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- RegisterFile.updateRegister(operands[0],
- RegisterFile.getValue(operands[1])
- & RegisterFile.getValue(operands[2]));
- }
- }));
- instructionList.add(
- new BasicInstruction("or $t1,$t2,$t3",
- "Bitwise OR : Set $t1 to bitwise OR of $t2 and $t3",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ RegisterFile.updateRegister(operands[0],
+ RegisterFile.getValue(operands[1])
+ & RegisterFile.getValue(operands[2]));
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("or $t1,$t2,$t3",
+ "Bitwise OR : Set $t1 to bitwise OR of $t2 and $t3",
BasicInstructionFormat.R_FORMAT,
"000000 sssss ttttt fffff 00000 100101",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- RegisterFile.updateRegister(operands[0],
- RegisterFile.getValue(operands[1])
- | RegisterFile.getValue(operands[2]));
- }
- }));
- instructionList.add(
- new BasicInstruction("andi $t1,$t2,100",
- "Bitwise AND immediate : Set $t1 to bitwise AND of $t2 and zero-extended 16-bit immediate",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ RegisterFile.updateRegister(operands[0],
+ RegisterFile.getValue(operands[1])
+ | RegisterFile.getValue(operands[2]));
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("andi $t1,$t2,100",
+ "Bitwise AND immediate : Set $t1 to bitwise AND of $t2 and zero-extended 16-bit immediate",
BasicInstructionFormat.I_FORMAT,
"001100 sssss fffff tttttttttttttttt",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- // ANDing with 0x0000FFFF zero-extends the immediate (high 16 bits always 0).
- RegisterFile.updateRegister(operands[0],
- RegisterFile.getValue(operands[1])
- & (operands[2] & 0x0000FFFF));
- }
- }));
- instructionList.add(
- new BasicInstruction("ori $t1,$t2,100",
- "Bitwise OR immediate : Set $t1 to bitwise OR of $t2 and zero-extended 16-bit immediate",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ // ANDing with 0x0000FFFF zero-extends the immediate (high 16 bits always 0).
+ RegisterFile.updateRegister(operands[0],
+ RegisterFile.getValue(operands[1])
+ & (operands[2] & 0x0000FFFF));
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("ori $t1,$t2,100",
+ "Bitwise OR immediate : Set $t1 to bitwise OR of $t2 and zero-extended 16-bit immediate",
BasicInstructionFormat.I_FORMAT,
"001101 sssss fffff tttttttttttttttt",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- // ANDing with 0x0000FFFF zero-extends the immediate (high 16 bits always 0).
- RegisterFile.updateRegister(operands[0],
- RegisterFile.getValue(operands[1])
- | (operands[2] & 0x0000FFFF));
- }
- }));
- instructionList.add(
- new BasicInstruction("nor $t1,$t2,$t3",
- "Bitwise NOR : Set $t1 to bitwise NOR of $t2 and $t3",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ // ANDing with 0x0000FFFF zero-extends the immediate (high 16 bits always 0).
+ RegisterFile.updateRegister(operands[0],
+ RegisterFile.getValue(operands[1])
+ | (operands[2] & 0x0000FFFF));
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("nor $t1,$t2,$t3",
+ "Bitwise NOR : Set $t1 to bitwise NOR of $t2 and $t3",
BasicInstructionFormat.R_FORMAT,
"000000 sssss ttttt fffff 00000 100111",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- RegisterFile.updateRegister(operands[0],
- ~(RegisterFile.getValue(operands[1])
- | RegisterFile.getValue(operands[2])));
- }
- }));
- instructionList.add(
- new BasicInstruction("xor $t1,$t2,$t3",
- "Bitwise XOR (exclusive OR) : Set $t1 to bitwise XOR of $t2 and $t3",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ RegisterFile.updateRegister(operands[0],
+ ~(RegisterFile.getValue(operands[1])
+ | RegisterFile.getValue(operands[2])));
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("xor $t1,$t2,$t3",
+ "Bitwise XOR (exclusive OR) : Set $t1 to bitwise XOR of $t2 and $t3",
BasicInstructionFormat.R_FORMAT,
"000000 sssss ttttt fffff 00000 100110",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- RegisterFile.updateRegister(operands[0],
- RegisterFile.getValue(operands[1])
- ^ RegisterFile.getValue(operands[2]));
- }
- }));
- instructionList.add(
- new BasicInstruction("xori $t1,$t2,100",
- "Bitwise XOR immediate : Set $t1 to bitwise XOR of $t2 and zero-extended 16-bit immediate",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ RegisterFile.updateRegister(operands[0],
+ RegisterFile.getValue(operands[1])
+ ^ RegisterFile.getValue(operands[2]));
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("xori $t1,$t2,100",
+ "Bitwise XOR immediate : Set $t1 to bitwise XOR of $t2 and zero-extended 16-bit immediate",
BasicInstructionFormat.I_FORMAT,
"001110 sssss fffff tttttttttttttttt",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- // ANDing with 0x0000FFFF zero-extends the immediate (high 16 bits always 0).
- RegisterFile.updateRegister(operands[0],
- RegisterFile.getValue(operands[1])
- ^ (operands[2] & 0x0000FFFF));
- }
- }));
- instructionList.add(
- new BasicInstruction("sll $t1,$t2,10",
- "Shift left logical : Set $t1 to result of shifting $t2 left by number of bits specified by immediate",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ // ANDing with 0x0000FFFF zero-extends the immediate (high 16 bits always 0).
+ RegisterFile.updateRegister(operands[0],
+ RegisterFile.getValue(operands[1])
+ ^ (operands[2] & 0x0000FFFF));
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("sll $t1,$t2,10",
+ "Shift left logical : Set $t1 to result of shifting $t2 left by number of bits specified by immediate",
BasicInstructionFormat.R_FORMAT,
"000000 00000 sssss fffff ttttt 000000",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- RegisterFile.updateRegister(operands[0],
- RegisterFile.getValue(operands[1]) << operands[2]);
- }
- }));
- instructionList.add(
- new BasicInstruction("sllv $t1,$t2,$t3",
- "Shift left logical variable : Set $t1 to result of shifting $t2 left by number of bits specified by value in low-order 5 bits of $t3",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ RegisterFile.updateRegister(operands[0],
+ RegisterFile.getValue(operands[1]) << operands[2]);
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("sllv $t1,$t2,$t3",
+ "Shift left logical variable : Set $t1 to result of shifting $t2 left by number of bits specified by value in low-order 5 bits of $t3",
BasicInstructionFormat.R_FORMAT,
"000000 ttttt sssss fffff 00000 000100",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- // Mask all but low 5 bits of register containing shamt.
- RegisterFile.updateRegister(operands[0],
- RegisterFile.getValue(operands[1]) <<
- (RegisterFile.getValue(operands[2]) & 0x0000001F));
- }
- }));
- instructionList.add(
- new BasicInstruction("srl $t1,$t2,10",
- "Shift right logical : Set $t1 to result of shifting $t2 right by number of bits specified by immediate",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ // Mask all but low 5 bits of register containing shamt.
+ RegisterFile.updateRegister(operands[0],
+ RegisterFile.getValue(operands[1]) <<
+ (RegisterFile.getValue(operands[2]) & 0x0000001F));
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("srl $t1,$t2,10",
+ "Shift right logical : Set $t1 to result of shifting $t2 right by number of bits specified by immediate",
BasicInstructionFormat.R_FORMAT,
"000000 00000 sssss fffff ttttt 000010",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- // must zero-fill, so use ">>>" instead of ">>".
- RegisterFile.updateRegister(operands[0],
- RegisterFile.getValue(operands[1]) >>> operands[2]);
- }
- }));
- instructionList.add(
- new BasicInstruction("sra $t1,$t2,10",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ // must zero-fill, so use ">>>" instead of ">>".
+ RegisterFile.updateRegister(operands[0],
+ RegisterFile.getValue(operands[1]) >>> operands[2]);
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("sra $t1,$t2,10",
"Shift right arithmetic : Set $t1 to result of sign-extended shifting $t2 right by number of bits specified by immediate",
- BasicInstructionFormat.R_FORMAT,
+ BasicInstructionFormat.R_FORMAT,
"000000 00000 sssss fffff ttttt 000011",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- // must sign-fill, so use ">>".
- RegisterFile.updateRegister(operands[0],
- RegisterFile.getValue(operands[1]) >> operands[2]);
- }
- }));
- instructionList.add(
- new BasicInstruction("srav $t1,$t2,$t3",
- "Shift right arithmetic variable : Set $t1 to result of sign-extended shifting $t2 right by number of bits specified by value in low-order 5 bits of $t3",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ // must sign-fill, so use ">>".
+ RegisterFile.updateRegister(operands[0],
+ RegisterFile.getValue(operands[1]) >> operands[2]);
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("srav $t1,$t2,$t3",
+ "Shift right arithmetic variable : Set $t1 to result of sign-extended shifting $t2 right by number of bits specified by value in low-order 5 bits of $t3",
BasicInstructionFormat.R_FORMAT,
"000000 ttttt sssss fffff 00000 000111",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- // Mask all but low 5 bits of register containing shamt.Use ">>" to sign-fill.
- RegisterFile.updateRegister(operands[0],
- RegisterFile.getValue(operands[1]) >>
- (RegisterFile.getValue(operands[2]) & 0x0000001F));
- }
- }));
- instructionList.add(
- new BasicInstruction("srlv $t1,$t2,$t3",
- "Shift right logical variable : Set $t1 to result of shifting $t2 right by number of bits specified by value in low-order 5 bits of $t3",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ // Mask all but low 5 bits of register containing shamt.Use ">>" to sign-fill.
+ RegisterFile.updateRegister(operands[0],
+ RegisterFile.getValue(operands[1]) >>
+ (RegisterFile.getValue(operands[2]) & 0x0000001F));
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("srlv $t1,$t2,$t3",
+ "Shift right logical variable : Set $t1 to result of shifting $t2 right by number of bits specified by value in low-order 5 bits of $t3",
BasicInstructionFormat.R_FORMAT,
"000000 ttttt sssss fffff 00000 000110",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- // Mask all but low 5 bits of register containing shamt.Use ">>>" to zero-fill.
- RegisterFile.updateRegister(operands[0],
- RegisterFile.getValue(operands[1]) >>>
- (RegisterFile.getValue(operands[2]) & 0x0000001F));
- }
- }));
- instructionList.add(
- new BasicInstruction("lw $t1,-100($t2)",
- "Load word : Set $t1 to contents of effective memory word address",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ // Mask all but low 5 bits of register containing shamt.Use ">>>" to zero-fill.
+ RegisterFile.updateRegister(operands[0],
+ RegisterFile.getValue(operands[1]) >>>
+ (RegisterFile.getValue(operands[2]) & 0x0000001F));
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("lw $t1,-100($t2)",
+ "Load word : Set $t1 to contents of effective memory word address",
BasicInstructionFormat.I_FORMAT,
"100011 ttttt fffff ssssssssssssssss",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- try
- {
- RegisterFile.updateRegister(operands[0],
- Globals.memory.getWord(
- RegisterFile.getValue(operands[2]) + operands[1]));
- }
- catch (AddressErrorException e)
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ try
{
- throw new ProcessingException(statement, e);
+ RegisterFile.updateRegister(operands[0],
+ Globals.memory.getWord(
+ RegisterFile.getValue(operands[2]) + operands[1]));
}
- }
- }));
- instructionList.add(
- new BasicInstruction("ll $t1,-100($t2)",
+ catch (AddressErrorException e)
+ {
+ throw new ProcessingException(statement, e);
+ }
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("ll $t1,-100($t2)",
"Load linked : Paired with Store Conditional (sc) to perform atomic read-modify-write. Treated as equivalent to Load Word (lw) because MARS does not simulate multiple processors.",
- BasicInstructionFormat.I_FORMAT,
+ BasicInstructionFormat.I_FORMAT,
"110000 ttttt fffff ssssssssssssssss",
- // The ll (load link) command is supposed to be the front end of an atomic
- // operation completed by sc (store conditional), with success or failure
- // of the store depending on whether the memory block containing the
- // loaded word is modified in the meantime by a different processor.
- // Since MARS, like SPIM simulates only a single processor, the store
- // conditional will always succeed so there is no need to do anything
- // special here. In that case, ll is same as lw. And sc does the same
- // thing as sw except in addition it writes 1 into the source register.
+ // The ll (load link) command is supposed to be the front end of an atomic
+ // operation completed by sc (store conditional), with success or failure
+ // of the store depending on whether the memory block containing the
+ // loaded word is modified in the meantime by a different processor.
+ // Since MARS, like SPIM simulates only a single processor, the store
+ // conditional will always succeed so there is no need to do anything
+ // special here. In that case, ll is same as lw. And sc does the same
+ // thing as sw except in addition it writes 1 into the source register.
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- try
- {
- RegisterFile.updateRegister(operands[0],
- Globals.memory.getWord(
- RegisterFile.getValue(operands[2]) + operands[1]));
- }
- catch (AddressErrorException e)
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ try
{
- throw new ProcessingException(statement, e);
+ RegisterFile.updateRegister(operands[0],
+ Globals.memory.getWord(
+ RegisterFile.getValue(operands[2]) + operands[1]));
}
- }
- }));
- instructionList.add(
- new BasicInstruction("lwl $t1,-100($t2)",
+ catch (AddressErrorException e)
+ {
+ throw new ProcessingException(statement, e);
+ }
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("lwl $t1,-100($t2)",
"Load word left : Load from 1 to 4 bytes left-justified into $t1, starting with effective memory byte address and continuing through the low-order byte of its word",
- BasicInstructionFormat.I_FORMAT,
+ BasicInstructionFormat.I_FORMAT,
"100010 ttttt fffff ssssssssssssssss",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- try
- {
- int address = RegisterFile.getValue(operands[2]) + operands[1];
- int result = RegisterFile.getValue(operands[0]);
- for (int i=0; i<=address % Globals.memory.WORD_LENGTH_BYTES; i++) {
- result = Binary.setByte(result,3-i,Globals.memory.getByte(address-i));
- }
- RegisterFile.updateRegister(operands[0], result);
- }
- catch (AddressErrorException e)
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ try
{
- throw new ProcessingException(statement, e);
+ int address = RegisterFile.getValue(operands[2]) + operands[1];
+ int result = RegisterFile.getValue(operands[0]);
+ for (int i = 0; i <= address % Memory.WORD_LENGTH_BYTES; i++)
+ {
+ result = Binary.setByte(result, 3 - i, Globals.memory.getByte(address - i));
+ }
+ RegisterFile.updateRegister(operands[0], result);
}
- }
- }));
- instructionList.add(
- new BasicInstruction("lwr $t1,-100($t2)",
+ catch (AddressErrorException e)
+ {
+ throw new ProcessingException(statement, e);
+ }
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("lwr $t1,-100($t2)",
"Load word right : Load from 1 to 4 bytes right-justified into $t1, starting with effective memory byte address and continuing through the high-order byte of its word",
- BasicInstructionFormat.I_FORMAT,
+ BasicInstructionFormat.I_FORMAT,
"100110 ttttt fffff ssssssssssssssss",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- try
- {
- int address = RegisterFile.getValue(operands[2]) + operands[1];
- int result = RegisterFile.getValue(operands[0]);
- for (int i=0; i<=3-(address % Globals.memory.WORD_LENGTH_BYTES); i++) {
- result = Binary.setByte(result,i,Globals.memory.getByte(address+i));
- }
- RegisterFile.updateRegister(operands[0], result);
- }
- catch (AddressErrorException e)
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ try
{
- throw new ProcessingException(statement, e);
+ int address = RegisterFile.getValue(operands[2]) + operands[1];
+ int result = RegisterFile.getValue(operands[0]);
+ for (int i = 0; i <= 3 - (address % Memory.WORD_LENGTH_BYTES); i++)
+ {
+ result = Binary.setByte(result, i, Globals.memory.getByte(address + i));
+ }
+ RegisterFile.updateRegister(operands[0], result);
}
- }
- }));
- instructionList.add(
- new BasicInstruction("sw $t1,-100($t2)",
+ catch (AddressErrorException e)
+ {
+ throw new ProcessingException(statement, e);
+ }
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("sw $t1,-100($t2)",
"Store word : Store contents of $t1 into effective memory word address",
- BasicInstructionFormat.I_FORMAT,
+ BasicInstructionFormat.I_FORMAT,
"101011 ttttt fffff ssssssssssssssss",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- try
- {
- Globals.memory.setWord(
- RegisterFile.getValue(operands[2]) + operands[1],
- RegisterFile.getValue(operands[0]));
- }
- catch (AddressErrorException e)
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ try
{
- throw new ProcessingException(statement, e);
+ Globals.memory.setWord(
+ RegisterFile.getValue(operands[2]) + operands[1],
+ RegisterFile.getValue(operands[0]));
}
- }
- }));
- instructionList.add(
- new BasicInstruction("sc $t1,-100($t2)",
+ catch (AddressErrorException e)
+ {
+ throw new ProcessingException(statement, e);
+ }
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("sc $t1,-100($t2)",
"Store conditional : Paired with Load Linked (ll) to perform atomic read-modify-write. Stores $t1 value into effective address, then sets $t1 to 1 for success. Always succeeds because MARS does not simulate multiple processors.",
- BasicInstructionFormat.I_FORMAT,
+ BasicInstructionFormat.I_FORMAT,
"111000 ttttt fffff ssssssssssssssss",
- // See comments with "ll" instruction above. "sc" is implemented
- // like "sw", except that 1 is placed in the source register.
+ // See comments with "ll" instruction above. "sc" is implemented
+ // like "sw", except that 1 is placed in the source register.
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- try
- {
- Globals.memory.setWord(
- RegisterFile.getValue(operands[2]) + operands[1],
- RegisterFile.getValue(operands[0]));
- }
- catch (AddressErrorException e)
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ try
{
- throw new ProcessingException(statement, e);
+ Globals.memory.setWord(
+ RegisterFile.getValue(operands[2]) + operands[1],
+ RegisterFile.getValue(operands[0]));
}
- RegisterFile.updateRegister(operands[0],1); // always succeeds
- }
- }));
- instructionList.add(
- new BasicInstruction("swl $t1,-100($t2)",
+ catch (AddressErrorException e)
+ {
+ throw new ProcessingException(statement, e);
+ }
+ RegisterFile.updateRegister(operands[0], 1); // always succeeds
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("swl $t1,-100($t2)",
"Store word left : Store high-order 1 to 4 bytes of $t1 into memory, starting with effective byte address and continuing through the low-order byte of its word",
- BasicInstructionFormat.I_FORMAT,
+ BasicInstructionFormat.I_FORMAT,
"101010 ttttt fffff ssssssssssssssss",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- try
- {
- int address = RegisterFile.getValue(operands[2]) + operands[1];
- int source = RegisterFile.getValue(operands[0]);
- for (int i=0; i<=address % Globals.memory.WORD_LENGTH_BYTES; i++) {
- Globals.memory.setByte(address-i,Binary.getByte(source,3-i));
- }
- }
- catch (AddressErrorException e)
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ try
{
- throw new ProcessingException(statement, e);
+ int address = RegisterFile.getValue(operands[2]) + operands[1];
+ int source = RegisterFile.getValue(operands[0]);
+ for (int i = 0; i <= address % Memory.WORD_LENGTH_BYTES; i++)
+ {
+ Globals.memory.setByte(address - i, Binary.getByte(source, 3 - i));
+ }
}
- }
- }));
- instructionList.add(
- new BasicInstruction("swr $t1,-100($t2)",
+ catch (AddressErrorException e)
+ {
+ throw new ProcessingException(statement, e);
+ }
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("swr $t1,-100($t2)",
"Store word right : Store low-order 1 to 4 bytes of $t1 into memory, starting with high-order byte of word containing effective byte address and continuing through that byte address",
- BasicInstructionFormat.I_FORMAT,
+ BasicInstructionFormat.I_FORMAT,
"101110 ttttt fffff ssssssssssssssss",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- try
- {
- int address = RegisterFile.getValue(operands[2]) + operands[1];
- int source = RegisterFile.getValue(operands[0]);
- for (int i=0; i<=3-(address % Globals.memory.WORD_LENGTH_BYTES); i++) {
- Globals.memory.setByte(address+i,Binary.getByte(source,i));
- }
- }
- catch (AddressErrorException e)
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ try
{
- throw new ProcessingException(statement, e);
+ int address = RegisterFile.getValue(operands[2]) + operands[1];
+ int source = RegisterFile.getValue(operands[0]);
+ for (int i = 0; i <= 3 - (address % Memory.WORD_LENGTH_BYTES); i++)
+ {
+ Globals.memory.setByte(address + i, Binary.getByte(source, i));
+ }
}
- }
- }));
- instructionList.add(
- new BasicInstruction("lui $t1,100",
+ catch (AddressErrorException e)
+ {
+ throw new ProcessingException(statement, e);
+ }
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("lui $t1,100",
"Load upper immediate : Set high-order 16 bits of $t1 to 16-bit immediate and low-order 16 bits to 0",
- BasicInstructionFormat.I_FORMAT,
+ BasicInstructionFormat.I_FORMAT,
"001111 00000 fffff ssssssssssssssss",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- RegisterFile.updateRegister(operands[0], operands[1] << 16);
- }
- }));
- instructionList.add(
- new BasicInstruction("beq $t1,$t2,label",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ RegisterFile.updateRegister(operands[0], operands[1] << 16);
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("beq $t1,$t2,label",
"Branch if equal : Branch to statement at label's address if $t1 and $t2 are equal",
- BasicInstructionFormat.I_BRANCH_FORMAT,
+ BasicInstructionFormat.I_BRANCH_FORMAT,
"000100 fffff sssss tttttttttttttttt",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
-
- if (RegisterFile.getValue(operands[0])
- == RegisterFile.getValue(operands[1]))
- {
- processBranch(operands[2]);
- }
- }
- }));
- instructionList.add(
- new BasicInstruction("bne $t1,$t2,label",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+
+ if (RegisterFile.getValue(operands[0])
+ == RegisterFile.getValue(operands[1]))
+ {
+ processBranch(operands[2]);
+ }
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("bne $t1,$t2,label",
"Branch if not equal : Branch to statement at label's address if $t1 and $t2 are not equal",
- BasicInstructionFormat.I_BRANCH_FORMAT,
+ BasicInstructionFormat.I_BRANCH_FORMAT,
"000101 fffff sssss tttttttttttttttt",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- if (RegisterFile.getValue(operands[0])
- != RegisterFile.getValue(operands[1]))
- {
- processBranch(operands[2]);
- }
- }
- }));
- instructionList.add(
- new BasicInstruction("bgez $t1,label",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ if (RegisterFile.getValue(operands[0])
+ != RegisterFile.getValue(operands[1]))
+ {
+ processBranch(operands[2]);
+ }
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("bgez $t1,label",
"Branch if greater than or equal to zero : Branch to statement at label's address if $t1 is greater than or equal to zero",
- BasicInstructionFormat.I_BRANCH_FORMAT,
+ BasicInstructionFormat.I_BRANCH_FORMAT,
"000001 fffff 00001 ssssssssssssssss",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- if (RegisterFile.getValue(operands[0]) >= 0)
- {
- processBranch(operands[1]);
- }
- }
- }));
- instructionList.add(
- new BasicInstruction("bgezal $t1,label",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ if (RegisterFile.getValue(operands[0]) >= 0)
+ {
+ processBranch(operands[1]);
+ }
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("bgezal $t1,label",
"Branch if greater then or equal to zero and link : If $t1 is greater than or equal to zero, then set $ra to the Program Counter and branch to statement at label's address",
- BasicInstructionFormat.I_BRANCH_FORMAT,
+ BasicInstructionFormat.I_BRANCH_FORMAT,
"000001 fffff 10001 ssssssssssssssss",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- if (RegisterFile.getValue(operands[0]) >= 0)
- { // the "and link" part
- processReturnAddress(31);//RegisterFile.updateRegister("$ra",RegisterFile.getProgramCounter());
- processBranch(operands[1]);
- }
- }
- }));
- instructionList.add(
- new BasicInstruction("bgtz $t1,label",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ if (RegisterFile.getValue(operands[0]) >= 0)
+ { // the "and link" part
+ processReturnAddress(31);//RegisterFile.updateRegister("$ra",RegisterFile.getProgramCounter());
+ processBranch(operands[1]);
+ }
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("bgtz $t1,label",
"Branch if greater than zero : Branch to statement at label's address if $t1 is greater than zero",
- BasicInstructionFormat.I_BRANCH_FORMAT,
+ BasicInstructionFormat.I_BRANCH_FORMAT,
"000111 fffff 00000 ssssssssssssssss",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- if (RegisterFile.getValue(operands[0]) > 0)
- {
- processBranch(operands[1]);
- }
- }
- }));
- instructionList.add(
- new BasicInstruction("blez $t1,label",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ if (RegisterFile.getValue(operands[0]) > 0)
+ {
+ processBranch(operands[1]);
+ }
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("blez $t1,label",
"Branch if less than or equal to zero : Branch to statement at label's address if $t1 is less than or equal to zero",
- BasicInstructionFormat.I_BRANCH_FORMAT,
+ BasicInstructionFormat.I_BRANCH_FORMAT,
"000110 fffff 00000 ssssssssssssssss",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- if (RegisterFile.getValue(operands[0]) <= 0)
- {
- processBranch(operands[1]);
- }
- }
- }));
- instructionList.add(
- new BasicInstruction("bltz $t1,label",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ if (RegisterFile.getValue(operands[0]) <= 0)
+ {
+ processBranch(operands[1]);
+ }
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("bltz $t1,label",
"Branch if less than zero : Branch to statement at label's address if $t1 is less than zero",
- BasicInstructionFormat.I_BRANCH_FORMAT,
+ BasicInstructionFormat.I_BRANCH_FORMAT,
"000001 fffff 00000 ssssssssssssssss",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- if (RegisterFile.getValue(operands[0]) < 0)
- {
- processBranch(operands[1]);
- }
- }
- }));
- instructionList.add(
- new BasicInstruction("bltzal $t1,label",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ if (RegisterFile.getValue(operands[0]) < 0)
+ {
+ processBranch(operands[1]);
+ }
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("bltzal $t1,label",
"Branch if less than zero and link : If $t1 is less than or equal to zero, then set $ra to the Program Counter and branch to statement at label's address",
- BasicInstructionFormat.I_BRANCH_FORMAT,
+ BasicInstructionFormat.I_BRANCH_FORMAT,
"000001 fffff 10000 ssssssssssssssss",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- if (RegisterFile.getValue(operands[0]) < 0)
- { // the "and link" part
- processReturnAddress(31);//RegisterFile.updateRegister("$ra",RegisterFile.getProgramCounter());
- processBranch(operands[1]);
- }
- }
- }));
- instructionList.add(
- new BasicInstruction("slt $t1,$t2,$t3",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ if (RegisterFile.getValue(operands[0]) < 0)
+ { // the "and link" part
+ processReturnAddress(31);//RegisterFile.updateRegister("$ra",RegisterFile.getProgramCounter());
+ processBranch(operands[1]);
+ }
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("slt $t1,$t2,$t3",
"Set less than : If $t2 is less than $t3, then set $t1 to 1 else set $t1 to 0",
- BasicInstructionFormat.R_FORMAT,
+ BasicInstructionFormat.R_FORMAT,
"000000 sssss ttttt fffff 00000 101010",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- RegisterFile.updateRegister(operands[0],
- (RegisterFile.getValue(operands[1])
- < RegisterFile.getValue(operands[2]))
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ RegisterFile.updateRegister(operands[0],
+ (RegisterFile.getValue(operands[1])
+ < RegisterFile.getValue(operands[2]))
? 1
: 0);
- }
- }));
- instructionList.add(
- new BasicInstruction("sltu $t1,$t2,$t3",
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("sltu $t1,$t2,$t3",
"Set less than unsigned : If $t2 is less than $t3 using unsigned comparision, then set $t1 to 1 else set $t1 to 0",
- BasicInstructionFormat.R_FORMAT,
+ BasicInstructionFormat.R_FORMAT,
"000000 sssss ttttt fffff 00000 101011",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- int first = RegisterFile.getValue(operands[1]);
- int second = RegisterFile.getValue(operands[2]);
- if (first >= 0 && second >= 0 || first < 0 && second < 0)
- {
- RegisterFile.updateRegister(operands[0],
- (first < second) ? 1 : 0);
- }
- else
- {
- RegisterFile.updateRegister(operands[0],
- (first >= 0) ? 1 : 0);
- }
- }
- }));
- instructionList.add(
- new BasicInstruction("slti $t1,$t2,-100",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ int first = RegisterFile.getValue(operands[1]);
+ int second = RegisterFile.getValue(operands[2]);
+ if (first >= 0 && second >= 0 || first < 0 && second < 0)
+ {
+ RegisterFile.updateRegister(operands[0],
+ (first < second) ? 1 : 0);
+ }
+ else
+ {
+ RegisterFile.updateRegister(operands[0],
+ (first >= 0) ? 1 : 0);
+ }
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("slti $t1,$t2,-100",
"Set less than immediate : If $t2 is less than sign-extended 16-bit immediate, then set $t1 to 1 else set $t1 to 0",
- BasicInstructionFormat.I_FORMAT,
+ BasicInstructionFormat.I_FORMAT,
"001010 sssss fffff tttttttttttttttt",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- // 16 bit immediate value in operands[2] is sign-extended
- RegisterFile.updateRegister(operands[0],
- (RegisterFile.getValue(operands[1])
- < (operands[2] << 16 >> 16))
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ // 16 bit immediate value in operands[2] is sign-extended
+ RegisterFile.updateRegister(operands[0],
+ (RegisterFile.getValue(operands[1])
+ < (operands[2] << 16 >> 16))
? 1
: 0);
- }
- }));
- instructionList.add(
- new BasicInstruction("sltiu $t1,$t2,-100",
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("sltiu $t1,$t2,-100",
"Set less than immediate unsigned : If $t2 is less than sign-extended 16-bit immediate using unsigned comparison, then set $t1 to 1 else set $t1 to 0",
- BasicInstructionFormat.I_FORMAT,
+ BasicInstructionFormat.I_FORMAT,
"001011 sssss fffff tttttttttttttttt",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- int first = RegisterFile.getValue(operands[1]);
- // 16 bit immediate value in operands[2] is sign-extended
- int second = operands[2] << 16 >> 16;
- if (first >= 0 && second >= 0 || first < 0 && second < 0)
- {
- RegisterFile.updateRegister(operands[0],
- (first < second) ? 1 : 0);
- }
- else
- {
- RegisterFile.updateRegister(operands[0],
- (first >= 0) ? 1 : 0);
- }
- }
- }));
- instructionList.add(
- new BasicInstruction("movn $t1,$t2,$t3",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ int first = RegisterFile.getValue(operands[1]);
+ // 16 bit immediate value in operands[2] is sign-extended
+ int second = operands[2] << 16 >> 16;
+ if (first >= 0 && second >= 0 || first < 0 && second < 0)
+ {
+ RegisterFile.updateRegister(operands[0],
+ (first < second) ? 1 : 0);
+ }
+ else
+ {
+ RegisterFile.updateRegister(operands[0],
+ (first >= 0) ? 1 : 0);
+ }
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("movn $t1,$t2,$t3",
"Move conditional not zero : Set $t1 to $t2 if $t3 is not zero",
- BasicInstructionFormat.R_FORMAT,
+ BasicInstructionFormat.R_FORMAT,
"000000 sssss ttttt fffff 00000 001011",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- if (RegisterFile.getValue(operands[2])!=0)
- RegisterFile.updateRegister(operands[0], RegisterFile.getValue(operands[1]));
- }
- }));
- instructionList.add(
- new BasicInstruction("movz $t1,$t2,$t3",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ if (RegisterFile.getValue(operands[2]) != 0)
+ {
+ RegisterFile.updateRegister(operands[0], RegisterFile.getValue(operands[1]));
+ }
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("movz $t1,$t2,$t3",
"Move conditional zero : Set $t1 to $t2 if $t3 is zero",
- BasicInstructionFormat.R_FORMAT,
+ BasicInstructionFormat.R_FORMAT,
"000000 sssss ttttt fffff 00000 001010",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- if (RegisterFile.getValue(operands[2])==0)
- RegisterFile.updateRegister(operands[0], RegisterFile.getValue(operands[1]));
- }
- }));
- instructionList.add(
- new BasicInstruction("movf $t1,$t2",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ if (RegisterFile.getValue(operands[2]) == 0)
+ {
+ RegisterFile.updateRegister(operands[0], RegisterFile.getValue(operands[1]));
+ }
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("movf $t1,$t2",
"Move if FP condition flag 0 false : Set $t1 to $t2 if FPU (Coprocessor 1) condition flag 0 is false (zero)",
- BasicInstructionFormat.R_FORMAT,
+ BasicInstructionFormat.R_FORMAT,
"000000 sssss 000 00 fffff 00000 000001",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- if (Coprocessor1.getConditionFlag(0)==0)
- RegisterFile.updateRegister(operands[0], RegisterFile.getValue(operands[1]));
- }
- }));
- instructionList.add(
- new BasicInstruction("movf $t1,$t2,1",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ if (Coprocessor1.getConditionFlag(0) == 0)
+ {
+ RegisterFile.updateRegister(operands[0], RegisterFile.getValue(operands[1]));
+ }
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("movf $t1,$t2,1",
"Move if specified FP condition flag false : Set $t1 to $t2 if FPU (Coprocessor 1) condition flag specified by the immediate is false (zero)",
- BasicInstructionFormat.R_FORMAT,
+ BasicInstructionFormat.R_FORMAT,
"000000 sssss ttt 00 fffff 00000 000001",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- if (Coprocessor1.getConditionFlag(operands[2])==0)
- RegisterFile.updateRegister(operands[0], RegisterFile.getValue(operands[1]));
- }
- }));
- instructionList.add(
- new BasicInstruction("movt $t1,$t2",
- "Move if FP condition flag 0 true : Set $t1 to $t2 if FPU (Coprocessor 1) condition flag 0 is true (one)",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ if (Coprocessor1.getConditionFlag(operands[2]) == 0)
+ {
+ RegisterFile.updateRegister(operands[0], RegisterFile.getValue(operands[1]));
+ }
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("movt $t1,$t2",
+ "Move if FP condition flag 0 true : Set $t1 to $t2 if FPU (Coprocessor 1) condition flag 0 is true (one)",
BasicInstructionFormat.R_FORMAT,
"000000 sssss 000 01 fffff 00000 000001",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- if (Coprocessor1.getConditionFlag(0)==1)
- RegisterFile.updateRegister(operands[0], RegisterFile.getValue(operands[1]));
- }
- }));
- instructionList.add(
- new BasicInstruction("movt $t1,$t2,1",
- "Move if specfied FP condition flag true : Set $t1 to $t2 if FPU (Coprocessor 1) condition flag specified by the immediate is true (one)",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ if (Coprocessor1.getConditionFlag(0) == 1)
+ {
+ RegisterFile.updateRegister(operands[0], RegisterFile.getValue(operands[1]));
+ }
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("movt $t1,$t2,1",
+ "Move if specfied FP condition flag true : Set $t1 to $t2 if FPU (Coprocessor 1) condition flag specified by the immediate is true (one)",
BasicInstructionFormat.R_FORMAT,
"000000 sssss ttt 01 fffff 00000 000001",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- if (Coprocessor1.getConditionFlag(operands[2])==1)
- RegisterFile.updateRegister(operands[0], RegisterFile.getValue(operands[1]));
- }
- }));
- instructionList.add(
- new BasicInstruction("break 100",
- "Break execution with code : Terminate program execution with specified exception code",
- BasicInstructionFormat.R_FORMAT,
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ if (Coprocessor1.getConditionFlag(operands[2]) == 1)
+ {
+ RegisterFile.updateRegister(operands[0], RegisterFile.getValue(operands[1]));
+ }
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("break 100",
+ "Break execution with code : Terminate program execution with specified exception code",
+ BasicInstructionFormat.R_FORMAT,
"000000 ffffffffffffffffffff 001101",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- { // At this time I don't have exception processing or trap handlers
- // so will just halt execution with a message.
- int[] operands = statement.getOperands();
- throw new ProcessingException(statement, "break instruction executed; code = "+
- operands[0]+".", Exceptions.BREAKPOINT_EXCEPTION);
- }
- }));
- instructionList.add(
- new BasicInstruction("break",
- "Break execution : Terminate program execution with exception",
- BasicInstructionFormat.R_FORMAT,
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ { // At this time I don't have exception processing or trap handlers
+ // so will just halt execution with a message.
+ int[] operands = statement.getOperands();
+ throw new ProcessingException(statement, "break instruction executed; code = " +
+ operands[0] + ".", Exceptions.BREAKPOINT_EXCEPTION);
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("break",
+ "Break execution : Terminate program execution with exception",
+ BasicInstructionFormat.R_FORMAT,
"000000 00000 00000 00000 00000 001101",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- { // At this time I don't have exception processing or trap handlers
- // so will just halt execution with a message.
- throw new ProcessingException(statement, "break instruction executed; no code given.",
- Exceptions.BREAKPOINT_EXCEPTION);
- }
- }));
- instructionList.add(
- new BasicInstruction("syscall",
- "Issue a system call : Execute the system call specified by value in $v0",
- BasicInstructionFormat.R_FORMAT,
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ { // At this time I don't have exception processing or trap handlers
+ // so will just halt execution with a message.
+ throw new ProcessingException(statement, "break instruction executed; no code given.",
+ Exceptions.BREAKPOINT_EXCEPTION);
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("syscall",
+ "Issue a system call : Execute the system call specified by value in $v0",
+ BasicInstructionFormat.R_FORMAT,
"000000 00000 00000 00000 00000 001100",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- findAndSimulateSyscall(RegisterFile.getValue(2),statement);
- }
- }));
- instructionList.add(
- new BasicInstruction("j target",
- "Jump unconditionally : Jump to statement at target address",
- BasicInstructionFormat.J_FORMAT,
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ findAndSimulateSyscall(RegisterFile.getValue(2), statement);
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("j target",
+ "Jump unconditionally : Jump to statement at target address",
+ BasicInstructionFormat.J_FORMAT,
"000010 ffffffffffffffffffffffffff",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- processJump(
- ((RegisterFile.getProgramCounter() & 0xF0000000)
- | (operands[0] << 2)));
- }
- }));
- instructionList.add(
- new BasicInstruction("jr $t1",
- "Jump register unconditionally : Jump to statement whose address is in $t1",
- BasicInstructionFormat.R_FORMAT,
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ processJump(
+ ((RegisterFile.getProgramCounter() & 0xF0000000)
+ | (operands[0] << 2)));
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("jr $t1",
+ "Jump register unconditionally : Jump to statement whose address is in $t1",
+ BasicInstructionFormat.R_FORMAT,
"000000 fffff 00000 00000 00000 001000",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- processJump(RegisterFile.getValue(operands[0]));
- }
- }));
- instructionList.add(
- new BasicInstruction("jal target",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ processJump(RegisterFile.getValue(operands[0]));
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("jal target",
"Jump and link : Set $ra to Program Counter (return address) then jump to statement at target address",
- BasicInstructionFormat.J_FORMAT,
+ BasicInstructionFormat.J_FORMAT,
"000011 ffffffffffffffffffffffffff",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- processReturnAddress(31);// RegisterFile.updateRegister(31, RegisterFile.getProgramCounter());
- processJump(
- (RegisterFile.getProgramCounter() & 0xF0000000)
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ processReturnAddress(31);// RegisterFile.updateRegister(31, RegisterFile.getProgramCounter());
+ processJump(
+ (RegisterFile.getProgramCounter() & 0xF0000000)
| (operands[0] << 2));
- }
- }));
- instructionList.add(
- new BasicInstruction("jalr $t1,$t2",
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("jalr $t1,$t2",
"Jump and link register : Set $t1 to Program Counter (return address) then jump to statement whose address is in $t2",
- BasicInstructionFormat.R_FORMAT,
+ BasicInstructionFormat.R_FORMAT,
"000000 sssss 00000 fffff 00000 001001",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- processReturnAddress(operands[0]);//RegisterFile.updateRegister(operands[0], RegisterFile.getProgramCounter());
- processJump(RegisterFile.getValue(operands[1]));
- }
- }));
- instructionList.add(
- new BasicInstruction("jalr $t1",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ processReturnAddress(operands[0]);//RegisterFile.updateRegister(operands[0], RegisterFile.getProgramCounter());
+ processJump(RegisterFile.getValue(operands[1]));
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("jalr $t1",
"Jump and link register : Set $ra to Program Counter (return address) then jump to statement whose address is in $t1",
- BasicInstructionFormat.R_FORMAT,
+ BasicInstructionFormat.R_FORMAT,
"000000 fffff 00000 11111 00000 001001",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- processReturnAddress(31);//RegisterFile.updateRegister(31, RegisterFile.getProgramCounter());
- processJump(RegisterFile.getValue(operands[0]));
- }
- }));
- instructionList.add(
- new BasicInstruction("lb $t1,-100($t2)",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ processReturnAddress(31);//RegisterFile.updateRegister(31, RegisterFile.getProgramCounter());
+ processJump(RegisterFile.getValue(operands[0]));
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("lb $t1,-100($t2)",
"Load byte : Set $t1 to sign-extended 8-bit value from effective memory byte address",
- BasicInstructionFormat.I_FORMAT,
+ BasicInstructionFormat.I_FORMAT,
"100000 ttttt fffff ssssssssssssssss",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- try
- {
- RegisterFile.updateRegister(operands[0],
- Globals.memory.getByte(
- RegisterFile.getValue(operands[2])
- + (operands[1] << 16 >> 16))
- << 24
- >> 24);
- }
- catch (AddressErrorException e)
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ try
{
- throw new ProcessingException(statement, e);
+ RegisterFile.updateRegister(operands[0],
+ Globals.memory.getByte(
+ RegisterFile.getValue(operands[2])
+ + (operands[1] << 16 >> 16))
+ << 24
+ >> 24);
}
- }
- }));
- instructionList.add(
- new BasicInstruction("lh $t1,-100($t2)",
+ catch (AddressErrorException e)
+ {
+ throw new ProcessingException(statement, e);
+ }
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("lh $t1,-100($t2)",
"Load halfword : Set $t1 to sign-extended 16-bit value from effective memory halfword address",
- BasicInstructionFormat.I_FORMAT,
+ BasicInstructionFormat.I_FORMAT,
"100001 ttttt fffff ssssssssssssssss",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- try
- {
- RegisterFile.updateRegister(operands[0],
- Globals.memory.getHalf(
- RegisterFile.getValue(operands[2])
- + (operands[1] << 16 >> 16))
- << 16
- >> 16);
- }
- catch (AddressErrorException e)
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ try
{
- throw new ProcessingException(statement, e);
+ RegisterFile.updateRegister(operands[0],
+ Globals.memory.getHalf(
+ RegisterFile.getValue(operands[2])
+ + (operands[1] << 16 >> 16))
+ << 16
+ >> 16);
}
- }
- }));
- instructionList.add(
- new BasicInstruction("lhu $t1,-100($t2)",
+ catch (AddressErrorException e)
+ {
+ throw new ProcessingException(statement, e);
+ }
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("lhu $t1,-100($t2)",
"Load halfword unsigned : Set $t1 to zero-extended 16-bit value from effective memory halfword address",
- BasicInstructionFormat.I_FORMAT,
+ BasicInstructionFormat.I_FORMAT,
"100101 ttttt fffff ssssssssssssssss",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- try
- {
- // offset is sign-extended and loaded halfword value is zero-extended
- RegisterFile.updateRegister(operands[0],
- Globals.memory.getHalf(
- RegisterFile.getValue(operands[2])
- + (operands[1] << 16 >> 16))
- & 0x0000ffff);
- }
- catch (AddressErrorException e)
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ try
{
- throw new ProcessingException(statement, e);
+ // offset is sign-extended and loaded halfword value is zero-extended
+ RegisterFile.updateRegister(operands[0],
+ Globals.memory.getHalf(
+ RegisterFile.getValue(operands[2])
+ + (operands[1] << 16 >> 16))
+ & 0x0000ffff);
}
- }
- }));
- instructionList.add(
- new BasicInstruction("lbu $t1,-100($t2)",
+ catch (AddressErrorException e)
+ {
+ throw new ProcessingException(statement, e);
+ }
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("lbu $t1,-100($t2)",
"Load byte unsigned : Set $t1 to zero-extended 8-bit value from effective memory byte address",
- BasicInstructionFormat.I_FORMAT,
+ BasicInstructionFormat.I_FORMAT,
"100100 ttttt fffff ssssssssssssssss",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- try
- {
- RegisterFile.updateRegister(operands[0],
- Globals.memory.getByte(
- RegisterFile.getValue(operands[2])
- + (operands[1] << 16 >> 16))
- & 0x000000ff);
- }
- catch (AddressErrorException e)
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ try
{
- throw new ProcessingException(statement, e);
+ RegisterFile.updateRegister(operands[0],
+ Globals.memory.getByte(
+ RegisterFile.getValue(operands[2])
+ + (operands[1] << 16 >> 16))
+ & 0x000000ff);
}
- }
- }));
- instructionList.add(
- new BasicInstruction("sb $t1,-100($t2)",
+ catch (AddressErrorException e)
+ {
+ throw new ProcessingException(statement, e);
+ }
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("sb $t1,-100($t2)",
"Store byte : Store the low-order 8 bits of $t1 into the effective memory byte address",
- BasicInstructionFormat.I_FORMAT,
+ BasicInstructionFormat.I_FORMAT,
"101000 ttttt fffff ssssssssssssssss",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- try
- {
- Globals.memory.setByte(
- RegisterFile.getValue(operands[2])
- + (operands[1] << 16 >> 16),
- RegisterFile.getValue(operands[0])
- & 0x000000ff);
- }
- catch (AddressErrorException e)
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ try
{
- throw new ProcessingException(statement, e);
+ Globals.memory.setByte(
+ RegisterFile.getValue(operands[2])
+ + (operands[1] << 16 >> 16),
+ RegisterFile.getValue(operands[0])
+ & 0x000000ff);
}
- }
- }));
- instructionList.add(
- new BasicInstruction("sh $t1,-100($t2)",
+ catch (AddressErrorException e)
+ {
+ throw new ProcessingException(statement, e);
+ }
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("sh $t1,-100($t2)",
"Store halfword : Store the low-order 16 bits of $t1 into the effective memory halfword address",
- BasicInstructionFormat.I_FORMAT,
+ BasicInstructionFormat.I_FORMAT,
"101001 ttttt fffff ssssssssssssssss",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- try
- {
- Globals.memory.setHalf(
- RegisterFile.getValue(operands[2])
- + (operands[1] << 16 >> 16),
- RegisterFile.getValue(operands[0])
- & 0x0000ffff);
- }
- catch (AddressErrorException e)
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ try
{
- throw new ProcessingException(statement, e);
+ Globals.memory.setHalf(
+ RegisterFile.getValue(operands[2])
+ + (operands[1] << 16 >> 16),
+ RegisterFile.getValue(operands[0])
+ & 0x0000ffff);
}
- }
- }));
- instructionList.add(
- new BasicInstruction("clo $t1,$t2",
- "Count number of leading ones : Set $t1 to the count of leading one bits in $t2 starting at most significant bit position",
- BasicInstructionFormat.R_FORMAT,
- // MIPS32 requires rd (first) operand to appear twice in machine code.
- // It has to be same as rt (third) operand in machine code, but the
- // source statement does not have or permit third operand.
- // In the machine code, rd and rt are adjacent, but my mask
- // substitution cannot handle adjacent placement of the same source
- // operand (e.g. "... sssss fffff fffff ...") because it would interpret
- // the mask to be the total length of both (10 bits). I could code it
- // to have 3 operands then define a pseudo-instruction of two operands
- // to translate into this, but then both would show up in instruction set
- // list and I don't want that. So I will use the convention of Computer
- // Organization and Design 3rd Edition, Appendix A, and code the rt bits
- // as 0's. The generated code does not match SPIM and would not run
- // on a real MIPS machine but since I am providing no means of storing
- // the binary code that is not really an issue.
+ catch (AddressErrorException e)
+ {
+ throw new ProcessingException(statement, e);
+ }
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("clo $t1,$t2",
+ "Count number of leading ones : Set $t1 to the count of leading one bits in $t2 starting at most significant bit position",
+ BasicInstructionFormat.R_FORMAT,
+ // MIPS32 requires rd (first) operand to appear twice in machine code.
+ // It has to be same as rt (third) operand in machine code, but the
+ // source statement does not have or permit third operand.
+ // In the machine code, rd and rt are adjacent, but my mask
+ // substitution cannot handle adjacent placement of the same source
+ // operand (e.g. "... sssss fffff fffff ...") because it would interpret
+ // the mask to be the total length of both (10 bits). I could code it
+ // to have 3 operands then define a pseudo-instruction of two operands
+ // to translate into this, but then both would show up in instruction set
+ // list and I don't want that. So I will use the convention of Computer
+ // Organization and Design 3rd Edition, Appendix A, and code the rt bits
+ // as 0's. The generated code does not match SPIM and would not run
+ // on a real MIPS machine but since I am providing no means of storing
+ // the binary code that is not really an issue.
"011100 sssss 00000 fffff 00000 100001",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- int value = RegisterFile.getValue(operands[1]);
- int leadingOnes = 0;
- int bitPosition = 31;
- while (Binary.bitValue(value,bitPosition)==1 && bitPosition>=0) {
- leadingOnes++;
- bitPosition--;
- }
- RegisterFile.updateRegister(operands[0], leadingOnes);
- }
- }));
- instructionList.add(
- new BasicInstruction("clz $t1,$t2",
- "Count number of leading zeroes : Set $t1 to the count of leading zero bits in $t2 starting at most significant bit positio",
- BasicInstructionFormat.R_FORMAT,
- // See comments for "clo" instruction above. They apply here too.
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ int value = RegisterFile.getValue(operands[1]);
+ int leadingOnes = 0;
+ int bitPosition = 31;
+ while (Binary.bitValue(value, bitPosition) == 1 && bitPosition >= 0)
+ {
+ leadingOnes++;
+ bitPosition--;
+ }
+ RegisterFile.updateRegister(operands[0], leadingOnes);
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("clz $t1,$t2",
+ "Count number of leading zeroes : Set $t1 to the count of leading zero bits in $t2 starting at most significant bit positio",
+ BasicInstructionFormat.R_FORMAT,
+ // See comments for "clo" instruction above. They apply here too.
"011100 sssss 00000 fffff 00000 100000",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- int value = RegisterFile.getValue(operands[1]);
- int leadingZeros = 0;
- int bitPosition = 31;
- while (Binary.bitValue(value,bitPosition)==0 && bitPosition>=0) {
- leadingZeros++;
- bitPosition--;
- }
- RegisterFile.updateRegister(operands[0], leadingZeros);
- }
- }));
- instructionList.add(
- new BasicInstruction("mfc0 $t1,$8",
- "Move from Coprocessor 0 : Set $t1 to the value stored in Coprocessor 0 register $8",
- BasicInstructionFormat.R_FORMAT,
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ int value = RegisterFile.getValue(operands[1]);
+ int leadingZeros = 0;
+ int bitPosition = 31;
+ while (Binary.bitValue(value, bitPosition) == 0 && bitPosition >= 0)
+ {
+ leadingZeros++;
+ bitPosition--;
+ }
+ RegisterFile.updateRegister(operands[0], leadingZeros);
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("mfc0 $t1,$8",
+ "Move from Coprocessor 0 : Set $t1 to the value stored in Coprocessor 0 register $8",
+ BasicInstructionFormat.R_FORMAT,
"010000 00000 fffff sssss 00000 000000",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- RegisterFile.updateRegister(operands[0],
- Coprocessor0.getValue(operands[1]));
- }
- }));
- instructionList.add(
- new BasicInstruction("mtc0 $t1,$8",
- "Move to Coprocessor 0 : Set Coprocessor 0 register $8 to value stored in $t1",
- BasicInstructionFormat.R_FORMAT,
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ RegisterFile.updateRegister(operands[0],
+ Coprocessor0.getValue(operands[1]));
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("mtc0 $t1,$8",
+ "Move to Coprocessor 0 : Set Coprocessor 0 register $8 to value stored in $t1",
+ BasicInstructionFormat.R_FORMAT,
"010000 00100 fffff sssss 00000 000000",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- Coprocessor0.updateRegister(operands[1],
- RegisterFile.getValue(operands[0]));
- }
- }));
-
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ Coprocessor0.updateRegister(operands[1],
+ RegisterFile.getValue(operands[0]));
+ }
+ }));
+
/////////////////////// Floating Point Instructions Start Here ////////////////
- instructionList.add(
- new BasicInstruction("add.s $f0,$f1,$f3",
- "Floating point addition single precision : Set $f0 to single-precision floating point value of $f1 plus $f3",
- BasicInstructionFormat.R_FORMAT,
+ instructionList.add(
+ new BasicInstruction("add.s $f0,$f1,$f3",
+ "Floating point addition single precision : Set $f0 to single-precision floating point value of $f1 plus $f3",
+ BasicInstructionFormat.R_FORMAT,
"010001 10000 ttttt sssss fffff 000000",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- float add1 = Float.intBitsToFloat(Coprocessor1.getValue(operands[1]));
- float add2 = Float.intBitsToFloat(Coprocessor1.getValue(operands[2]));
- float sum = add1 + add2;
- // overflow detected when sum is positive or negative infinity.
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ float add1 = Float.intBitsToFloat(Coprocessor1.getValue(operands[1]));
+ float add2 = Float.intBitsToFloat(Coprocessor1.getValue(operands[2]));
+ float sum = add1 + add2;
+ // overflow detected when sum is positive or negative infinity.
/*
if (sum == Float.NEGATIVE_INFINITY || sum == Float.POSITIVE_INFINITY) {
throw new ProcessingException(statement,"arithmetic overflow");
}
*/
- Coprocessor1.updateRegister(operands[0], Float.floatToIntBits(sum));
- }
- }));
- instructionList.add(
- new BasicInstruction("sub.s $f0,$f1,$f3",
+ Coprocessor1.updateRegister(operands[0], Float.floatToIntBits(sum));
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("sub.s $f0,$f1,$f3",
"Floating point subtraction single precision : Set $f0 to single-precision floating point value of $f1 minus $f3",
- BasicInstructionFormat.R_FORMAT,
+ BasicInstructionFormat.R_FORMAT,
"010001 10000 ttttt sssss fffff 000001",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- float sub1 = Float.intBitsToFloat(Coprocessor1.getValue(operands[1]));
- float sub2 = Float.intBitsToFloat(Coprocessor1.getValue(operands[2]));
- float diff = sub1 - sub2;
- Coprocessor1.updateRegister(operands[0], Float.floatToIntBits(diff));
- }
- }));
- instructionList.add(
- new BasicInstruction("mul.s $f0,$f1,$f3",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ float sub1 = Float.intBitsToFloat(Coprocessor1.getValue(operands[1]));
+ float sub2 = Float.intBitsToFloat(Coprocessor1.getValue(operands[2]));
+ float diff = sub1 - sub2;
+ Coprocessor1.updateRegister(operands[0], Float.floatToIntBits(diff));
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("mul.s $f0,$f1,$f3",
"Floating point multiplication single precision : Set $f0 to single-precision floating point value of $f1 times $f3",
- BasicInstructionFormat.R_FORMAT,
+ BasicInstructionFormat.R_FORMAT,
"010001 10000 ttttt sssss fffff 000010",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- float mul1 = Float.intBitsToFloat(Coprocessor1.getValue(operands[1]));
- float mul2 = Float.intBitsToFloat(Coprocessor1.getValue(operands[2]));
- float prod = mul1 * mul2;
- Coprocessor1.updateRegister(operands[0], Float.floatToIntBits(prod));
- }
- }));
- instructionList.add(
- new BasicInstruction("div.s $f0,$f1,$f3",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ float mul1 = Float.intBitsToFloat(Coprocessor1.getValue(operands[1]));
+ float mul2 = Float.intBitsToFloat(Coprocessor1.getValue(operands[2]));
+ float prod = mul1 * mul2;
+ Coprocessor1.updateRegister(operands[0], Float.floatToIntBits(prod));
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("div.s $f0,$f1,$f3",
"Floating point division single precision : Set $f0 to single-precision floating point value of $f1 divided by $f3",
- BasicInstructionFormat.R_FORMAT,
+ BasicInstructionFormat.R_FORMAT,
"010001 10000 ttttt sssss fffff 000011",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- float div1 = Float.intBitsToFloat(Coprocessor1.getValue(operands[1]));
- float div2 = Float.intBitsToFloat(Coprocessor1.getValue(operands[2]));
- float quot = div1 / div2;
- Coprocessor1.updateRegister(operands[0], Float.floatToIntBits(quot));
- }
- }));
- instructionList.add(
- new BasicInstruction("sqrt.s $f0,$f1",
- "Square root single precision : Set $f0 to single-precision floating point square root of $f1",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ float div1 = Float.intBitsToFloat(Coprocessor1.getValue(operands[1]));
+ float div2 = Float.intBitsToFloat(Coprocessor1.getValue(operands[2]));
+ float quot = div1 / div2;
+ Coprocessor1.updateRegister(operands[0], Float.floatToIntBits(quot));
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("sqrt.s $f0,$f1",
+ "Square root single precision : Set $f0 to single-precision floating point square root of $f1",
BasicInstructionFormat.R_FORMAT,
"010001 10000 00000 sssss fffff 000100",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- float value = Float.intBitsToFloat(Coprocessor1.getValue(operands[1]));
- int floatSqrt = 0;
- if (value < 0.0f) {
- // This is subject to refinement later. Release 4.0 defines floor, ceil, trunc, round
- // to act silently rather than raise Invalid Operation exception, so sqrt should do the
- // same. An intermediate step would be to define a setting for FCSR Invalid Operation
- // flag, but the best solution is to simulate the FCSR register itself.
- // FCSR = Floating point unit Control and Status Register. DPS 10-Aug-2010
- floatSqrt = Float.floatToIntBits( Float.NaN);
- //throw new ProcessingException(statement, "Invalid Operation: sqrt of negative number");
- }
- else {
- floatSqrt = Float.floatToIntBits( (float) Math.sqrt(value));
- }
- Coprocessor1.updateRegister(operands[0], floatSqrt);
- }
- }));
- instructionList.add(
- new BasicInstruction("floor.w.s $f0,$f1",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ float value = Float.intBitsToFloat(Coprocessor1.getValue(operands[1]));
+ int floatSqrt = 0;
+ if (value < 0.0f)
+ {
+ // This is subject to refinement later. Release 4.0 defines floor, ceil, trunc, round
+ // to act silently rather than raise Invalid Operation exception, so sqrt should do the
+ // same. An intermediate step would be to define a setting for FCSR Invalid Operation
+ // flag, but the best solution is to simulate the FCSR register itself.
+ // FCSR = Floating point unit Control and Status Register. DPS 10-Aug-2010
+ floatSqrt = Float.floatToIntBits(Float.NaN);
+ //throw new ProcessingException(statement, "Invalid Operation: sqrt of negative number");
+ }
+ else
+ {
+ floatSqrt = Float.floatToIntBits((float) Math.sqrt(value));
+ }
+ Coprocessor1.updateRegister(operands[0], floatSqrt);
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("floor.w.s $f0,$f1",
"Floor single precision to word : Set $f0 to 32-bit integer floor of single-precision float in $f1",
- BasicInstructionFormat.R_FORMAT,
+ BasicInstructionFormat.R_FORMAT,
"010001 10000 00000 sssss fffff 001111",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- float floatValue = Float.intBitsToFloat(Coprocessor1.getValue(operands[1]));
- int floor = (int) Math.floor(floatValue);
- // DPS 28-July-2010: Since MARS does not simulate the FSCR, I will take the default
- // action of setting the result to 2^31-1, if the value is outside the 32 bit range.
- if ( Float.isNaN(floatValue)
- || Float.isInfinite(floatValue)
- || floatValue < (float) Integer.MIN_VALUE
- || floatValue > (float) Integer.MAX_VALUE ) {
- floor = Integer.MAX_VALUE;
- }
- Coprocessor1.updateRegister(operands[0], floor);
- }
- }));
- instructionList.add(
- new BasicInstruction("ceil.w.s $f0,$f1",
- "Ceiling single precision to word : Set $f0 to 32-bit integer ceiling of single-precision float in $f1",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ float floatValue = Float.intBitsToFloat(Coprocessor1.getValue(operands[1]));
+ int floor = (int) Math.floor(floatValue);
+ // DPS 28-July-2010: Since MARS does not simulate the FSCR, I will take the default
+ // action of setting the result to 2^31-1, if the value is outside the 32 bit range.
+ if (Float.isNaN(floatValue)
+ || Float.isInfinite(floatValue)
+ || floatValue < (float) Integer.MIN_VALUE
+ || floatValue > (float) Integer.MAX_VALUE)
+ {
+ floor = Integer.MAX_VALUE;
+ }
+ Coprocessor1.updateRegister(operands[0], floor);
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("ceil.w.s $f0,$f1",
+ "Ceiling single precision to word : Set $f0 to 32-bit integer ceiling of single-precision float in $f1",
BasicInstructionFormat.R_FORMAT,
"010001 10000 00000 sssss fffff 001110",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- float floatValue = Float.intBitsToFloat(Coprocessor1.getValue(operands[1]));
- int ceiling = (int) Math.ceil(floatValue);
- // DPS 28-July-2010: Since MARS does not simulate the FSCR, I will take the default
- // action of setting the result to 2^31-1, if the value is outside the 32 bit range.
- if ( Float.isNaN(floatValue)
- || Float.isInfinite(floatValue)
- || floatValue < (float) Integer.MIN_VALUE
- || floatValue > (float) Integer.MAX_VALUE ) {
- ceiling = Integer.MAX_VALUE;
- }
- Coprocessor1.updateRegister(operands[0], ceiling);
- }
- }));
- instructionList.add(
- new BasicInstruction("round.w.s $f0,$f1",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ float floatValue = Float.intBitsToFloat(Coprocessor1.getValue(operands[1]));
+ int ceiling = (int) Math.ceil(floatValue);
+ // DPS 28-July-2010: Since MARS does not simulate the FSCR, I will take the default
+ // action of setting the result to 2^31-1, if the value is outside the 32 bit range.
+ if (Float.isNaN(floatValue)
+ || Float.isInfinite(floatValue)
+ || floatValue < (float) Integer.MIN_VALUE
+ || floatValue > (float) Integer.MAX_VALUE)
+ {
+ ceiling = Integer.MAX_VALUE;
+ }
+ Coprocessor1.updateRegister(operands[0], ceiling);
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("round.w.s $f0,$f1",
"Round single precision to word : Set $f0 to 32-bit integer round of single-precision float in $f1",
- BasicInstructionFormat.R_FORMAT,
+ BasicInstructionFormat.R_FORMAT,
"010001 10000 00000 sssss fffff 001100",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- { // MIPS32 documentation (and IEEE 754) states that round rounds to the nearest but when
- // both are equally near it rounds to the even one! SPIM rounds -4.5, -5.5,
- // 4.5 and 5.5 to (-4, -5, 5, 6). Curiously, it rounds -5.1 to -4 and -5.6 to -5.
- // Until MARS 3.5, I used Math.round, which rounds to nearest but when both are
- // equal it rounds toward positive infinity. With Release 3.5, I painstakingly
- // carry out the MIPS and IEEE 754 standard.
- int[] operands = statement.getOperands();
- float floatValue = Float.intBitsToFloat(Coprocessor1.getValue(operands[1]));
- int below=0, above=0, round = Math.round(floatValue);
- // According to MIPS32 spec, if any of these conditions is true, set
- // Invalid Operation in the FCSR (Floating point Control/Status Register) and
- // set result to be 2^31-1. MARS does not implement this register (as of release 3.4.1).
- // It also mentions the "Invalid Operation Enable bit" in FCSR, that, if set, results
- // in immediate exception instead of default value.
- if ( Float.isNaN(floatValue)
- || Float.isInfinite(floatValue)
- || floatValue < (float) Integer.MIN_VALUE
- || floatValue > (float) Integer.MAX_VALUE ) {
- round = Integer.MAX_VALUE;
- }
- else {
- Float floatObj = floatValue;
- // If we are EXACTLY in the middle, then round to even! To determine this,
- // find next higher integer and next lower integer, then see if distances
- // are exactly equal.
- if (floatValue < 0.0F) {
- above = floatObj.intValue(); // truncates
- below = above - 1;
- }
- else {
- below = floatObj.intValue(); // truncates
- above = below + 1;
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ { // MIPS32 documentation (and IEEE 754) states that round rounds to the nearest but when
+ // both are equally near it rounds to the even one! SPIM rounds -4.5, -5.5,
+ // 4.5 and 5.5 to (-4, -5, 5, 6). Curiously, it rounds -5.1 to -4 and -5.6 to -5.
+ // Until MARS 3.5, I used Math.round, which rounds to nearest but when both are
+ // equal it rounds toward positive infinity. With Release 3.5, I painstakingly
+ // carry out the MIPS and IEEE 754 standard.
+ int[] operands = statement.getOperands();
+ float floatValue = Float.intBitsToFloat(Coprocessor1.getValue(operands[1]));
+ int below = 0, above = 0, round = Math.round(floatValue);
+ // According to MIPS32 spec, if any of these conditions is true, set
+ // Invalid Operation in the FCSR (Floating point Control/Status Register) and
+ // set result to be 2^31-1. MARS does not implement this register (as of release 3.4.1).
+ // It also mentions the "Invalid Operation Enable bit" in FCSR, that, if set, results
+ // in immediate exception instead of default value.
+ if (Float.isNaN(floatValue)
+ || Float.isInfinite(floatValue)
+ || floatValue < (float) Integer.MIN_VALUE
+ || floatValue > (float) Integer.MAX_VALUE)
+ {
+ round = Integer.MAX_VALUE;
}
- if (floatValue - below == above - floatValue) { // exactly in the middle?
- round = (above%2 == 0) ? above : below;
+ else
+ {
+ Float floatObj = floatValue;
+ // If we are EXACTLY in the middle, then round to even! To determine this,
+ // find next higher integer and next lower integer, then see if distances
+ // are exactly equal.
+ if (floatValue < 0.0F)
+ {
+ above = floatObj.intValue(); // truncates
+ below = above - 1;
+ }
+ else
+ {
+ below = floatObj.intValue(); // truncates
+ above = below + 1;
+ }
+ if (floatValue - below == above - floatValue)
+ { // exactly in the middle?
+ round = (above % 2 == 0) ? above : below;
+ }
}
- }
- Coprocessor1.updateRegister(operands[0], round);
- }
- }));
- instructionList.add(
- new BasicInstruction("trunc.w.s $f0,$f1",
+ Coprocessor1.updateRegister(operands[0], round);
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("trunc.w.s $f0,$f1",
"Truncate single precision to word : Set $f0 to 32-bit integer truncation of single-precision float in $f1",
- BasicInstructionFormat.R_FORMAT,
+ BasicInstructionFormat.R_FORMAT,
"010001 10000 00000 sssss fffff 001101",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- float floatValue = Float.intBitsToFloat(Coprocessor1.getValue(operands[1]));
- int truncate = (int) floatValue;// Typecasting will round toward zero, the correct action
- // DPS 28-July-2010: Since MARS does not simulate the FSCR, I will take the default
- // action of setting the result to 2^31-1, if the value is outside the 32 bit range.
- if ( Float.isNaN(floatValue)
- || Float.isInfinite(floatValue)
- || floatValue < (float) Integer.MIN_VALUE
- || floatValue > (float) Integer.MAX_VALUE ) {
- truncate = Integer.MAX_VALUE;
- }
- Coprocessor1.updateRegister(operands[0], truncate);
- }
- }));
- instructionList.add(
- new BasicInstruction("add.d $f2,$f4,$f6",
- "Floating point addition double precision : Set $f2 to double-precision floating point value of $f4 plus $f6",
- BasicInstructionFormat.R_FORMAT,
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ float floatValue = Float.intBitsToFloat(Coprocessor1.getValue(operands[1]));
+ int truncate = (int) floatValue;// Typecasting will round toward zero, the correct action
+ // DPS 28-July-2010: Since MARS does not simulate the FSCR, I will take the default
+ // action of setting the result to 2^31-1, if the value is outside the 32 bit range.
+ if (Float.isNaN(floatValue)
+ || Float.isInfinite(floatValue)
+ || floatValue < (float) Integer.MIN_VALUE
+ || floatValue > (float) Integer.MAX_VALUE)
+ {
+ truncate = Integer.MAX_VALUE;
+ }
+ Coprocessor1.updateRegister(operands[0], truncate);
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("add.d $f2,$f4,$f6",
+ "Floating point addition double precision : Set $f2 to double-precision floating point value of $f4 plus $f6",
+ BasicInstructionFormat.R_FORMAT,
"010001 10001 ttttt sssss fffff 000000",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- if (operands[0]%2==1 || operands[1]%2==1 || operands[2]%2==1) {
- throw new ProcessingException(statement, "all registers must be even-numbered");
- }
- double add1 = Double.longBitsToDouble(Binary.twoIntsToLong(
- Coprocessor1.getValue(operands[1]+1),Coprocessor1.getValue(operands[1])));
- double add2 = Double.longBitsToDouble(Binary.twoIntsToLong(
- Coprocessor1.getValue(operands[2]+1),Coprocessor1.getValue(operands[2])));
- double sum = add1 + add2;
- long longSum = Double.doubleToLongBits(sum);
- Coprocessor1.updateRegister(operands[0]+1, Binary.highOrderLongToInt(longSum));
- Coprocessor1.updateRegister(operands[0], Binary.lowOrderLongToInt(longSum));
- }
- }));
- instructionList.add(
- new BasicInstruction("sub.d $f2,$f4,$f6",
- "Floating point subtraction double precision : Set $f2 to double-precision floating point value of $f4 minus $f6",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ if (operands[0] % 2 == 1 || operands[1] % 2 == 1 || operands[2] % 2 == 1)
+ {
+ throw new ProcessingException(statement, "all registers must be even-numbered");
+ }
+ double add1 = Double.longBitsToDouble(Binary.twoIntsToLong(
+ Coprocessor1.getValue(operands[1] + 1), Coprocessor1.getValue(operands[1])));
+ double add2 = Double.longBitsToDouble(Binary.twoIntsToLong(
+ Coprocessor1.getValue(operands[2] + 1), Coprocessor1.getValue(operands[2])));
+ double sum = add1 + add2;
+ long longSum = Double.doubleToLongBits(sum);
+ Coprocessor1.updateRegister(operands[0] + 1, Binary.highOrderLongToInt(longSum));
+ Coprocessor1.updateRegister(operands[0], Binary.lowOrderLongToInt(longSum));
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("sub.d $f2,$f4,$f6",
+ "Floating point subtraction double precision : Set $f2 to double-precision floating point value of $f4 minus $f6",
BasicInstructionFormat.R_FORMAT,
"010001 10001 ttttt sssss fffff 000001",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- if (operands[0]%2==1 || operands[1]%2==1 || operands[2]%2==1) {
- throw new ProcessingException(statement, "all registers must be even-numbered");
- }
- double sub1 = Double.longBitsToDouble(Binary.twoIntsToLong(
- Coprocessor1.getValue(operands[1]+1),Coprocessor1.getValue(operands[1])));
- double sub2 = Double.longBitsToDouble(Binary.twoIntsToLong(
- Coprocessor1.getValue(operands[2]+1),Coprocessor1.getValue(operands[2])));
- double diff = sub1 - sub2;
- long longDiff = Double.doubleToLongBits(diff);
- Coprocessor1.updateRegister(operands[0]+1, Binary.highOrderLongToInt(longDiff));
- Coprocessor1.updateRegister(operands[0], Binary.lowOrderLongToInt(longDiff));
- }
- }));
- instructionList.add(
- new BasicInstruction("mul.d $f2,$f4,$f6",
- "Floating point multiplication double precision : Set $f2 to double-precision floating point value of $f4 times $f6",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ if (operands[0] % 2 == 1 || operands[1] % 2 == 1 || operands[2] % 2 == 1)
+ {
+ throw new ProcessingException(statement, "all registers must be even-numbered");
+ }
+ double sub1 = Double.longBitsToDouble(Binary.twoIntsToLong(
+ Coprocessor1.getValue(operands[1] + 1), Coprocessor1.getValue(operands[1])));
+ double sub2 = Double.longBitsToDouble(Binary.twoIntsToLong(
+ Coprocessor1.getValue(operands[2] + 1), Coprocessor1.getValue(operands[2])));
+ double diff = sub1 - sub2;
+ long longDiff = Double.doubleToLongBits(diff);
+ Coprocessor1.updateRegister(operands[0] + 1, Binary.highOrderLongToInt(longDiff));
+ Coprocessor1.updateRegister(operands[0], Binary.lowOrderLongToInt(longDiff));
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("mul.d $f2,$f4,$f6",
+ "Floating point multiplication double precision : Set $f2 to double-precision floating point value of $f4 times $f6",
BasicInstructionFormat.R_FORMAT,
"010001 10001 ttttt sssss fffff 000010",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- if (operands[0]%2==1 || operands[1]%2==1 || operands[2]%2==1) {
- throw new ProcessingException(statement, "all registers must be even-numbered");
- }
- double mul1 = Double.longBitsToDouble(Binary.twoIntsToLong(
- Coprocessor1.getValue(operands[1]+1),Coprocessor1.getValue(operands[1])));
- double mul2 = Double.longBitsToDouble(Binary.twoIntsToLong(
- Coprocessor1.getValue(operands[2]+1),Coprocessor1.getValue(operands[2])));
- double prod = mul1 * mul2;
- long longProd = Double.doubleToLongBits(prod);
- Coprocessor1.updateRegister(operands[0]+1, Binary.highOrderLongToInt(longProd));
- Coprocessor1.updateRegister(operands[0], Binary.lowOrderLongToInt(longProd));
- }
- }));
- instructionList.add(
- new BasicInstruction("div.d $f2,$f4,$f6",
- "Floating point division double precision : Set $f2 to double-precision floating point value of $f4 divided by $f6",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ if (operands[0] % 2 == 1 || operands[1] % 2 == 1 || operands[2] % 2 == 1)
+ {
+ throw new ProcessingException(statement, "all registers must be even-numbered");
+ }
+ double mul1 = Double.longBitsToDouble(Binary.twoIntsToLong(
+ Coprocessor1.getValue(operands[1] + 1), Coprocessor1.getValue(operands[1])));
+ double mul2 = Double.longBitsToDouble(Binary.twoIntsToLong(
+ Coprocessor1.getValue(operands[2] + 1), Coprocessor1.getValue(operands[2])));
+ double prod = mul1 * mul2;
+ long longProd = Double.doubleToLongBits(prod);
+ Coprocessor1.updateRegister(operands[0] + 1, Binary.highOrderLongToInt(longProd));
+ Coprocessor1.updateRegister(operands[0], Binary.lowOrderLongToInt(longProd));
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("div.d $f2,$f4,$f6",
+ "Floating point division double precision : Set $f2 to double-precision floating point value of $f4 divided by $f6",
BasicInstructionFormat.R_FORMAT,
"010001 10001 ttttt sssss fffff 000011",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- if (operands[0]%2==1 || operands[1]%2==1 || operands[2]%2==1) {
- throw new ProcessingException(statement, "all registers must be even-numbered");
- }
- double div1 = Double.longBitsToDouble(Binary.twoIntsToLong(
- Coprocessor1.getValue(operands[1]+1),Coprocessor1.getValue(operands[1])));
- double div2 = Double.longBitsToDouble(Binary.twoIntsToLong(
- Coprocessor1.getValue(operands[2]+1),Coprocessor1.getValue(operands[2])));
- double quot = div1 / div2;
- long longQuot = Double.doubleToLongBits(quot);
- Coprocessor1.updateRegister(operands[0]+1, Binary.highOrderLongToInt(longQuot));
- Coprocessor1.updateRegister(operands[0], Binary.lowOrderLongToInt(longQuot));
- }
- }));
- instructionList.add(
- new BasicInstruction("sqrt.d $f2,$f4",
- "Square root double precision : Set $f2 to double-precision floating point square root of $f4",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ if (operands[0] % 2 == 1 || operands[1] % 2 == 1 || operands[2] % 2 == 1)
+ {
+ throw new ProcessingException(statement, "all registers must be even-numbered");
+ }
+ double div1 = Double.longBitsToDouble(Binary.twoIntsToLong(
+ Coprocessor1.getValue(operands[1] + 1), Coprocessor1.getValue(operands[1])));
+ double div2 = Double.longBitsToDouble(Binary.twoIntsToLong(
+ Coprocessor1.getValue(operands[2] + 1), Coprocessor1.getValue(operands[2])));
+ double quot = div1 / div2;
+ long longQuot = Double.doubleToLongBits(quot);
+ Coprocessor1.updateRegister(operands[0] + 1, Binary.highOrderLongToInt(longQuot));
+ Coprocessor1.updateRegister(operands[0], Binary.lowOrderLongToInt(longQuot));
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("sqrt.d $f2,$f4",
+ "Square root double precision : Set $f2 to double-precision floating point square root of $f4",
BasicInstructionFormat.R_FORMAT,
"010001 10001 00000 sssss fffff 000100",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- if (operands[0]%2==1 || operands[1]%2==1 || operands[2]%2==1) {
- throw new ProcessingException(statement, "both registers must be even-numbered");
- }
- double value = Double.longBitsToDouble(Binary.twoIntsToLong(
- Coprocessor1.getValue(operands[1]+1),Coprocessor1.getValue(operands[1])));
- long longSqrt = 0;
- if (value < 0.0) {
- // This is subject to refinement later. Release 4.0 defines floor, ceil, trunc, round
- // to act silently rather than raise Invalid Operation exception, so sqrt should do the
- // same. An intermediate step would be to define a setting for FCSR Invalid Operation
- // flag, but the best solution is to simulate the FCSR register itself.
- // FCSR = Floating point unit Control and Status Register. DPS 10-Aug-2010
- longSqrt = Double.doubleToLongBits(Double.NaN);
- //throw new ProcessingException(statement, "Invalid Operation: sqrt of negative number");
- }
- else {
- longSqrt = Double.doubleToLongBits(Math.sqrt(value));
- }
- Coprocessor1.updateRegister(operands[0]+1, Binary.highOrderLongToInt(longSqrt));
- Coprocessor1.updateRegister(operands[0], Binary.lowOrderLongToInt(longSqrt));
- }
- }));
- instructionList.add(
- new BasicInstruction("floor.w.d $f1,$f2",
- "Floor double precision to word : Set $f1 to 32-bit integer floor of double-precision float in $f2",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ if (operands[0] % 2 == 1 || operands[1] % 2 == 1 || operands[2] % 2 == 1)
+ {
+ throw new ProcessingException(statement, "both registers must be even-numbered");
+ }
+ double value = Double.longBitsToDouble(Binary.twoIntsToLong(
+ Coprocessor1.getValue(operands[1] + 1), Coprocessor1.getValue(operands[1])));
+ long longSqrt = 0;
+ if (value < 0.0)
+ {
+ // This is subject to refinement later. Release 4.0 defines floor, ceil, trunc, round
+ // to act silently rather than raise Invalid Operation exception, so sqrt should do the
+ // same. An intermediate step would be to define a setting for FCSR Invalid Operation
+ // flag, but the best solution is to simulate the FCSR register itself.
+ // FCSR = Floating point unit Control and Status Register. DPS 10-Aug-2010
+ longSqrt = Double.doubleToLongBits(Double.NaN);
+ //throw new ProcessingException(statement, "Invalid Operation: sqrt of negative number");
+ }
+ else
+ {
+ longSqrt = Double.doubleToLongBits(Math.sqrt(value));
+ }
+ Coprocessor1.updateRegister(operands[0] + 1, Binary.highOrderLongToInt(longSqrt));
+ Coprocessor1.updateRegister(operands[0], Binary.lowOrderLongToInt(longSqrt));
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("floor.w.d $f1,$f2",
+ "Floor double precision to word : Set $f1 to 32-bit integer floor of double-precision float in $f2",
BasicInstructionFormat.R_FORMAT,
"010001 10001 00000 sssss fffff 001111",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- if (operands[1]%2==1) {
- throw new ProcessingException(statement, "second register must be even-numbered");
- }
- double doubleValue = Double.longBitsToDouble(Binary.twoIntsToLong(
- Coprocessor1.getValue(operands[1]+1),Coprocessor1.getValue(operands[1])));
- // DPS 27-July-2010: Since MARS does not simulate the FSCR, I will take the default
- // action of setting the result to 2^31-1, if the value is outside the 32 bit range.
- int floor = (int) Math.floor(doubleValue);
- if ( Double.isNaN(doubleValue)
- || Double.isInfinite(doubleValue)
- || doubleValue < (double) Integer.MIN_VALUE
- || doubleValue > (double) Integer.MAX_VALUE ) {
- floor = Integer.MAX_VALUE;
- }
- Coprocessor1.updateRegister(operands[0], floor);
- }
- }));
- instructionList.add(
- new BasicInstruction("ceil.w.d $f1,$f2",
- "Ceiling double precision to word : Set $f1 to 32-bit integer ceiling of double-precision float in $f2",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ if (operands[1] % 2 == 1)
+ {
+ throw new ProcessingException(statement, "second register must be even-numbered");
+ }
+ double doubleValue = Double.longBitsToDouble(Binary.twoIntsToLong(
+ Coprocessor1.getValue(operands[1] + 1), Coprocessor1.getValue(operands[1])));
+ // DPS 27-July-2010: Since MARS does not simulate the FSCR, I will take the default
+ // action of setting the result to 2^31-1, if the value is outside the 32 bit range.
+ int floor = (int) Math.floor(doubleValue);
+ if (Double.isNaN(doubleValue)
+ || Double.isInfinite(doubleValue)
+ || doubleValue < (double) Integer.MIN_VALUE
+ || doubleValue > (double) Integer.MAX_VALUE)
+ {
+ floor = Integer.MAX_VALUE;
+ }
+ Coprocessor1.updateRegister(operands[0], floor);
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("ceil.w.d $f1,$f2",
+ "Ceiling double precision to word : Set $f1 to 32-bit integer ceiling of double-precision float in $f2",
BasicInstructionFormat.R_FORMAT,
"010001 10001 00000 sssss fffff 001110",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- if (operands[1]%2==1) {
- throw new ProcessingException(statement, "second register must be even-numbered");
- }
- double doubleValue = Double.longBitsToDouble(Binary.twoIntsToLong(
- Coprocessor1.getValue(operands[1]+1),Coprocessor1.getValue(operands[1])));
- // DPS 27-July-2010: Since MARS does not simulate the FSCR, I will take the default
- // action of setting the result to 2^31-1, if the value is outside the 32 bit range.
- int ceiling = (int) Math.ceil(doubleValue);
- if ( Double.isNaN(doubleValue)
- || Double.isInfinite(doubleValue)
- || doubleValue < (double) Integer.MIN_VALUE
- || doubleValue > (double) Integer.MAX_VALUE ) {
- ceiling = Integer.MAX_VALUE;
- }
- Coprocessor1.updateRegister(operands[0], ceiling);
- }
- }));
- instructionList.add(
- new BasicInstruction("round.w.d $f1,$f2",
- "Round double precision to word : Set $f1 to 32-bit integer round of double-precision float in $f2",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ if (operands[1] % 2 == 1)
+ {
+ throw new ProcessingException(statement, "second register must be even-numbered");
+ }
+ double doubleValue = Double.longBitsToDouble(Binary.twoIntsToLong(
+ Coprocessor1.getValue(operands[1] + 1), Coprocessor1.getValue(operands[1])));
+ // DPS 27-July-2010: Since MARS does not simulate the FSCR, I will take the default
+ // action of setting the result to 2^31-1, if the value is outside the 32 bit range.
+ int ceiling = (int) Math.ceil(doubleValue);
+ if (Double.isNaN(doubleValue)
+ || Double.isInfinite(doubleValue)
+ || doubleValue < (double) Integer.MIN_VALUE
+ || doubleValue > (double) Integer.MAX_VALUE)
+ {
+ ceiling = Integer.MAX_VALUE;
+ }
+ Coprocessor1.updateRegister(operands[0], ceiling);
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("round.w.d $f1,$f2",
+ "Round double precision to word : Set $f1 to 32-bit integer round of double-precision float in $f2",
BasicInstructionFormat.R_FORMAT,
"010001 10001 00000 sssss fffff 001100",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- { // See comments in round.w.s above, concerning MIPS and IEEE 754 standard.
- // Until MARS 3.5, I used Math.round, which rounds to nearest but when both are
- // equal it rounds toward positive infinity. With Release 3.5, I painstakingly
- // carry out the MIPS and IEEE 754 standard (round to nearest/even).
- int[] operands = statement.getOperands();
- if (operands[1]%2==1) {
- throw new ProcessingException(statement, "second register must be even-numbered");
- }
- double doubleValue = Double.longBitsToDouble(Binary.twoIntsToLong(
- Coprocessor1.getValue(operands[1]+1),Coprocessor1.getValue(operands[1])));
- int below=0, above=0;
- int round = (int) Math.round(doubleValue);
- // See comments in round.w.s above concerning FSCR...
- if ( Double.isNaN(doubleValue)
- || Double.isInfinite(doubleValue)
- || doubleValue < (double) Integer.MIN_VALUE
- || doubleValue > (double) Integer.MAX_VALUE ) {
- round = Integer.MAX_VALUE;
- }
- else {
- Double doubleObj = doubleValue;
- // If we are EXACTLY in the middle, then round to even! To determine this,
- // find next higher integer and next lower integer, then see if distances
- // are exactly equal.
- if (doubleValue < 0.0) {
- above = doubleObj.intValue(); // truncates
- below = above - 1;
- }
- else {
- below = doubleObj.intValue(); // truncates
- above = below + 1;
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ { // See comments in round.w.s above, concerning MIPS and IEEE 754 standard.
+ // Until MARS 3.5, I used Math.round, which rounds to nearest but when both are
+ // equal it rounds toward positive infinity. With Release 3.5, I painstakingly
+ // carry out the MIPS and IEEE 754 standard (round to nearest/even).
+ int[] operands = statement.getOperands();
+ if (operands[1] % 2 == 1)
+ {
+ throw new ProcessingException(statement, "second register must be even-numbered");
}
- if (doubleValue - below == above - doubleValue) { // exactly in the middle?
- round = (above%2 == 0) ? above : below;
+ double doubleValue = Double.longBitsToDouble(Binary.twoIntsToLong(
+ Coprocessor1.getValue(operands[1] + 1), Coprocessor1.getValue(operands[1])));
+ int below = 0, above = 0;
+ int round = (int) Math.round(doubleValue);
+ // See comments in round.w.s above concerning FSCR...
+ if (Double.isNaN(doubleValue)
+ || Double.isInfinite(doubleValue)
+ || doubleValue < (double) Integer.MIN_VALUE
+ || doubleValue > (double) Integer.MAX_VALUE)
+ {
+ round = Integer.MAX_VALUE;
}
- }
- Coprocessor1.updateRegister(operands[0], round);
- }
- }));
- instructionList.add(
- new BasicInstruction("trunc.w.d $f1,$f2",
- "Truncate double precision to word : Set $f1 to 32-bit integer truncation of double-precision float in $f2",
+ else
+ {
+ Double doubleObj = doubleValue;
+ // If we are EXACTLY in the middle, then round to even! To determine this,
+ // find next higher integer and next lower integer, then see if distances
+ // are exactly equal.
+ if (doubleValue < 0.0)
+ {
+ above = doubleObj.intValue(); // truncates
+ below = above - 1;
+ }
+ else
+ {
+ below = doubleObj.intValue(); // truncates
+ above = below + 1;
+ }
+ if (doubleValue - below == above - doubleValue)
+ { // exactly in the middle?
+ round = (above % 2 == 0) ? above : below;
+ }
+ }
+ Coprocessor1.updateRegister(operands[0], round);
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("trunc.w.d $f1,$f2",
+ "Truncate double precision to word : Set $f1 to 32-bit integer truncation of double-precision float in $f2",
BasicInstructionFormat.R_FORMAT,
"010001 10001 00000 sssss fffff 001101",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- if (operands[1]%2==1) {
- throw new ProcessingException(statement, "second register must be even-numbered");
- }
- double doubleValue = Double.longBitsToDouble(Binary.twoIntsToLong(
- Coprocessor1.getValue(operands[1]+1),Coprocessor1.getValue(operands[1])));
- // DPS 27-July-2010: Since MARS does not simulate the FSCR, I will take the default
- // action of setting the result to 2^31-1, if the value is outside the 32 bit range.
- int truncate = (int) doubleValue; // Typecasting will round toward zero, the correct action.
- if ( Double.isNaN(doubleValue)
- || Double.isInfinite(doubleValue)
- || doubleValue < (double) Integer.MIN_VALUE
- || doubleValue > (double) Integer.MAX_VALUE ) {
- truncate = Integer.MAX_VALUE;
- }
- Coprocessor1.updateRegister(operands[0], truncate);
- }
- }));
- instructionList.add(
- new BasicInstruction("bc1t label",
- "Branch if FP condition flag 0 true (BC1T, not BCLT) : If Coprocessor 1 condition flag 0 is true (one) then branch to statement at label's address",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ if (operands[1] % 2 == 1)
+ {
+ throw new ProcessingException(statement, "second register must be even-numbered");
+ }
+ double doubleValue = Double.longBitsToDouble(Binary.twoIntsToLong(
+ Coprocessor1.getValue(operands[1] + 1), Coprocessor1.getValue(operands[1])));
+ // DPS 27-July-2010: Since MARS does not simulate the FSCR, I will take the default
+ // action of setting the result to 2^31-1, if the value is outside the 32 bit range.
+ int truncate = (int) doubleValue; // Typecasting will round toward zero, the correct action.
+ if (Double.isNaN(doubleValue)
+ || Double.isInfinite(doubleValue)
+ || doubleValue < (double) Integer.MIN_VALUE
+ || doubleValue > (double) Integer.MAX_VALUE)
+ {
+ truncate = Integer.MAX_VALUE;
+ }
+ Coprocessor1.updateRegister(operands[0], truncate);
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("bc1t label",
+ "Branch if FP condition flag 0 true (BC1T, not BCLT) : If Coprocessor 1 condition flag 0 is true (one) then branch to statement at label's address",
BasicInstructionFormat.I_BRANCH_FORMAT,
"010001 01000 00001 ffffffffffffffff",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- if (Coprocessor1.getConditionFlag(0)==1)
- {
- processBranch(operands[0]);
- }
- }
- }));
- instructionList.add(
- new BasicInstruction("bc1t 1,label",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ if (Coprocessor1.getConditionFlag(0) == 1)
+ {
+ processBranch(operands[0]);
+ }
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("bc1t 1,label",
"Branch if specified FP condition flag true (BC1T, not BCLT) : If Coprocessor 1 condition flag specified by immediate is true (one) then branch to statement at label's address",
- BasicInstructionFormat.I_BRANCH_FORMAT,
+ BasicInstructionFormat.I_BRANCH_FORMAT,
"010001 01000 fff 01 ssssssssssssssss",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- if (Coprocessor1.getConditionFlag(operands[0])==1)
- {
- processBranch(operands[1]);
- }
- }
- }));
- instructionList.add(
- new BasicInstruction("bc1f label",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ if (Coprocessor1.getConditionFlag(operands[0]) == 1)
+ {
+ processBranch(operands[1]);
+ }
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("bc1f label",
"Branch if FP condition flag 0 false (BC1F, not BCLF) : If Coprocessor 1 condition flag 0 is false (zero) then branch to statement at label's address",
- BasicInstructionFormat.I_BRANCH_FORMAT,
+ BasicInstructionFormat.I_BRANCH_FORMAT,
"010001 01000 00000 ffffffffffffffff",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- if (Coprocessor1.getConditionFlag(0)==0)
- {
- processBranch(operands[0]);
- }
-
- }
- }));
- instructionList.add(
- new BasicInstruction("bc1f 1,label",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ if (Coprocessor1.getConditionFlag(0) == 0)
+ {
+ processBranch(operands[0]);
+ }
+
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("bc1f 1,label",
"Branch if specified FP condition flag false (BC1F, not BCLF) : If Coprocessor 1 condition flag specified by immediate is false (zero) then branch to statement at label's address",
- BasicInstructionFormat.I_BRANCH_FORMAT,
+ BasicInstructionFormat.I_BRANCH_FORMAT,
"010001 01000 fff 00 ssssssssssssssss",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- if (Coprocessor1.getConditionFlag(operands[0])==0)
- {
- processBranch(operands[1]);
- }
-
- }
- }));
- instructionList.add(
- new BasicInstruction("c.eq.s $f0,$f1",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ if (Coprocessor1.getConditionFlag(operands[0]) == 0)
+ {
+ processBranch(operands[1]);
+ }
+
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("c.eq.s $f0,$f1",
"Compare equal single precision : If $f0 is equal to $f1, set Coprocessor 1 condition flag 0 true else set it false",
- BasicInstructionFormat.R_FORMAT,
+ BasicInstructionFormat.R_FORMAT,
"010001 10000 sssss fffff 00000 110010",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- float op1 = Float.intBitsToFloat(Coprocessor1.getValue(operands[0]));
- float op2 = Float.intBitsToFloat(Coprocessor1.getValue(operands[1]));
- if (op1 == op2)
- Coprocessor1.setConditionFlag(0);
- else
- Coprocessor1.clearConditionFlag(0);
- }
- }));
- instructionList.add(
- new BasicInstruction("c.eq.s 1,$f0,$f1",
- "Compare equal single precision : If $f0 is equal to $f1, set Coprocessor 1 condition flag specied by immediate to true else set it to false",
- BasicInstructionFormat.R_FORMAT,
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ float op1 = Float.intBitsToFloat(Coprocessor1.getValue(operands[0]));
+ float op2 = Float.intBitsToFloat(Coprocessor1.getValue(operands[1]));
+ if (op1 == op2)
+ {
+ Coprocessor1.setConditionFlag(0);
+ }
+ else
+ {
+ Coprocessor1.clearConditionFlag(0);
+ }
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("c.eq.s 1,$f0,$f1",
+ "Compare equal single precision : If $f0 is equal to $f1, set Coprocessor 1 condition flag specied by immediate to true else set it to false",
+ BasicInstructionFormat.R_FORMAT,
"010001 10000 ttttt sssss fff 00 11 0010",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- float op1 = Float.intBitsToFloat(Coprocessor1.getValue(operands[1]));
- float op2 = Float.intBitsToFloat(Coprocessor1.getValue(operands[2]));
- if (op1 == op2)
- Coprocessor1.setConditionFlag(operands[0]);
- else
- Coprocessor1.clearConditionFlag(operands[0]);
- }
- }));
- instructionList.add(
- new BasicInstruction("c.le.s $f0,$f1",
- "Compare less or equal single precision : If $f0 is less than or equal to $f1, set Coprocessor 1 condition flag 0 true else set it false",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ float op1 = Float.intBitsToFloat(Coprocessor1.getValue(operands[1]));
+ float op2 = Float.intBitsToFloat(Coprocessor1.getValue(operands[2]));
+ if (op1 == op2)
+ {
+ Coprocessor1.setConditionFlag(operands[0]);
+ }
+ else
+ {
+ Coprocessor1.clearConditionFlag(operands[0]);
+ }
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("c.le.s $f0,$f1",
+ "Compare less or equal single precision : If $f0 is less than or equal to $f1, set Coprocessor 1 condition flag 0 true else set it false",
BasicInstructionFormat.R_FORMAT,
"010001 10000 sssss fffff 00000 111110",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- float op1 = Float.intBitsToFloat(Coprocessor1.getValue(operands[0]));
- float op2 = Float.intBitsToFloat(Coprocessor1.getValue(operands[1]));
- if (op1 <= op2)
- Coprocessor1.setConditionFlag(0);
- else
- Coprocessor1.clearConditionFlag(0);
- }
- }));
- instructionList.add(
- new BasicInstruction("c.le.s 1,$f0,$f1",
- "Compare less or equal single precision : If $f0 is less than or equal to $f1, set Coprocessor 1 condition flag specified by immediate to true else set it to false",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ float op1 = Float.intBitsToFloat(Coprocessor1.getValue(operands[0]));
+ float op2 = Float.intBitsToFloat(Coprocessor1.getValue(operands[1]));
+ if (op1 <= op2)
+ {
+ Coprocessor1.setConditionFlag(0);
+ }
+ else
+ {
+ Coprocessor1.clearConditionFlag(0);
+ }
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("c.le.s 1,$f0,$f1",
+ "Compare less or equal single precision : If $f0 is less than or equal to $f1, set Coprocessor 1 condition flag specified by immediate to true else set it to false",
BasicInstructionFormat.R_FORMAT,
"010001 10000 ttttt sssss fff 00 111110",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- float op1 = Float.intBitsToFloat(Coprocessor1.getValue(operands[1]));
- float op2 = Float.intBitsToFloat(Coprocessor1.getValue(operands[2]));
- if (op1 <= op2)
- Coprocessor1.setConditionFlag(operands[0]);
- else
- Coprocessor1.clearConditionFlag(operands[0]);
- }
- }));
- instructionList.add(
- new BasicInstruction("c.lt.s $f0,$f1",
- "Compare less than single precision : If $f0 is less than $f1, set Coprocessor 1 condition flag 0 true else set it false",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ float op1 = Float.intBitsToFloat(Coprocessor1.getValue(operands[1]));
+ float op2 = Float.intBitsToFloat(Coprocessor1.getValue(operands[2]));
+ if (op1 <= op2)
+ {
+ Coprocessor1.setConditionFlag(operands[0]);
+ }
+ else
+ {
+ Coprocessor1.clearConditionFlag(operands[0]);
+ }
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("c.lt.s $f0,$f1",
+ "Compare less than single precision : If $f0 is less than $f1, set Coprocessor 1 condition flag 0 true else set it false",
BasicInstructionFormat.R_FORMAT,
"010001 10000 sssss fffff 00000 111100",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- float op1 = Float.intBitsToFloat(Coprocessor1.getValue(operands[0]));
- float op2 = Float.intBitsToFloat(Coprocessor1.getValue(operands[1]));
- if (op1 < op2)
- Coprocessor1.setConditionFlag(0);
- else
- Coprocessor1.clearConditionFlag(0);
- }
- }));
- instructionList.add(
- new BasicInstruction("c.lt.s 1,$f0,$f1",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ float op1 = Float.intBitsToFloat(Coprocessor1.getValue(operands[0]));
+ float op2 = Float.intBitsToFloat(Coprocessor1.getValue(operands[1]));
+ if (op1 < op2)
+ {
+ Coprocessor1.setConditionFlag(0);
+ }
+ else
+ {
+ Coprocessor1.clearConditionFlag(0);
+ }
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("c.lt.s 1,$f0,$f1",
"Compare less than single precision : If $f0 is less than $f1, set Coprocessor 1 condition flag specified by immediate to true else set it to false",
- BasicInstructionFormat.R_FORMAT,
+ BasicInstructionFormat.R_FORMAT,
"010001 10000 ttttt sssss fff 00 111100",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- float op1 = Float.intBitsToFloat(Coprocessor1.getValue(operands[1]));
- float op2 = Float.intBitsToFloat(Coprocessor1.getValue(operands[2]));
- if (op1 < op2)
- Coprocessor1.setConditionFlag(operands[0]);
- else
- Coprocessor1.clearConditionFlag(operands[0]);
- }
- }));
- instructionList.add(
- new BasicInstruction("c.eq.d $f2,$f4",
- "Compare equal double precision : If $f2 is equal to $f4 (double-precision), set Coprocessor 1 condition flag 0 true else set it false",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ float op1 = Float.intBitsToFloat(Coprocessor1.getValue(operands[1]));
+ float op2 = Float.intBitsToFloat(Coprocessor1.getValue(operands[2]));
+ if (op1 < op2)
+ {
+ Coprocessor1.setConditionFlag(operands[0]);
+ }
+ else
+ {
+ Coprocessor1.clearConditionFlag(operands[0]);
+ }
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("c.eq.d $f2,$f4",
+ "Compare equal double precision : If $f2 is equal to $f4 (double-precision), set Coprocessor 1 condition flag 0 true else set it false",
BasicInstructionFormat.R_FORMAT,
"010001 10001 sssss fffff 00000 110010",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- if (operands[0]%2==1 || operands[1]%2==1) {
- throw new ProcessingException(statement, "both registers must be even-numbered");
- }
- double op1 = Double.longBitsToDouble(Binary.twoIntsToLong(
- Coprocessor1.getValue(operands[0]+1),Coprocessor1.getValue(operands[0])));
- double op2 = Double.longBitsToDouble(Binary.twoIntsToLong(
- Coprocessor1.getValue(operands[1]+1),Coprocessor1.getValue(operands[1])));
- if (op1 == op2)
- Coprocessor1.setConditionFlag(0);
- else
- Coprocessor1.clearConditionFlag(0);
- }
- }));
- instructionList.add(
- new BasicInstruction("c.eq.d 1,$f2,$f4",
- "Compare equal double precision : If $f2 is equal to $f4 (double-precision), set Coprocessor 1 condition flag specified by immediate to true else set it to false",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ if (operands[0] % 2 == 1 || operands[1] % 2 == 1)
+ {
+ throw new ProcessingException(statement, "both registers must be even-numbered");
+ }
+ double op1 = Double.longBitsToDouble(Binary.twoIntsToLong(
+ Coprocessor1.getValue(operands[0] + 1), Coprocessor1.getValue(operands[0])));
+ double op2 = Double.longBitsToDouble(Binary.twoIntsToLong(
+ Coprocessor1.getValue(operands[1] + 1), Coprocessor1.getValue(operands[1])));
+ if (op1 == op2)
+ {
+ Coprocessor1.setConditionFlag(0);
+ }
+ else
+ {
+ Coprocessor1.clearConditionFlag(0);
+ }
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("c.eq.d 1,$f2,$f4",
+ "Compare equal double precision : If $f2 is equal to $f4 (double-precision), set Coprocessor 1 condition flag specified by immediate to true else set it to false",
BasicInstructionFormat.R_FORMAT,
"010001 10001 ttttt sssss fff 00 110010",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- if (operands[1]%2==1 || operands[2]%2==1) {
- throw new ProcessingException(statement, "both registers must be even-numbered");
- }
- double op1 = Double.longBitsToDouble(Binary.twoIntsToLong(
- Coprocessor1.getValue(operands[1]+1),Coprocessor1.getValue(operands[1])));
- double op2 = Double.longBitsToDouble(Binary.twoIntsToLong(
- Coprocessor1.getValue(operands[2]+1),Coprocessor1.getValue(operands[2])));
- if (op1 == op2)
- Coprocessor1.setConditionFlag(operands[0]);
- else
- Coprocessor1.clearConditionFlag(operands[0]);
- }
- }));
- instructionList.add(
- new BasicInstruction("c.le.d $f2,$f4",
- "Compare less or equal double precision : If $f2 is less than or equal to $f4 (double-precision), set Coprocessor 1 condition flag 0 true else set it false",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ if (operands[1] % 2 == 1 || operands[2] % 2 == 1)
+ {
+ throw new ProcessingException(statement, "both registers must be even-numbered");
+ }
+ double op1 = Double.longBitsToDouble(Binary.twoIntsToLong(
+ Coprocessor1.getValue(operands[1] + 1), Coprocessor1.getValue(operands[1])));
+ double op2 = Double.longBitsToDouble(Binary.twoIntsToLong(
+ Coprocessor1.getValue(operands[2] + 1), Coprocessor1.getValue(operands[2])));
+ if (op1 == op2)
+ {
+ Coprocessor1.setConditionFlag(operands[0]);
+ }
+ else
+ {
+ Coprocessor1.clearConditionFlag(operands[0]);
+ }
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("c.le.d $f2,$f4",
+ "Compare less or equal double precision : If $f2 is less than or equal to $f4 (double-precision), set Coprocessor 1 condition flag 0 true else set it false",
BasicInstructionFormat.R_FORMAT,
"010001 10001 sssss fffff 00000 111110",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- if (operands[0]%2==1 || operands[1]%2==1) {
- throw new ProcessingException(statement, "both registers must be even-numbered");
- }
- double op1 = Double.longBitsToDouble(Binary.twoIntsToLong(
- Coprocessor1.getValue(operands[0]+1),Coprocessor1.getValue(operands[0])));
- double op2 = Double.longBitsToDouble(Binary.twoIntsToLong(
- Coprocessor1.getValue(operands[1]+1),Coprocessor1.getValue(operands[1])));
- if (op1 <= op2)
- Coprocessor1.setConditionFlag(0);
- else
- Coprocessor1.clearConditionFlag(0);
- }
- }));
- instructionList.add(
- new BasicInstruction("c.le.d 1,$f2,$f4",
- "Compare less or equal double precision : If $f2 is less than or equal to $f4 (double-precision), set Coprocessor 1 condition flag specfied by immediate true else set it false",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ if (operands[0] % 2 == 1 || operands[1] % 2 == 1)
+ {
+ throw new ProcessingException(statement, "both registers must be even-numbered");
+ }
+ double op1 = Double.longBitsToDouble(Binary.twoIntsToLong(
+ Coprocessor1.getValue(operands[0] + 1), Coprocessor1.getValue(operands[0])));
+ double op2 = Double.longBitsToDouble(Binary.twoIntsToLong(
+ Coprocessor1.getValue(operands[1] + 1), Coprocessor1.getValue(operands[1])));
+ if (op1 <= op2)
+ {
+ Coprocessor1.setConditionFlag(0);
+ }
+ else
+ {
+ Coprocessor1.clearConditionFlag(0);
+ }
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("c.le.d 1,$f2,$f4",
+ "Compare less or equal double precision : If $f2 is less than or equal to $f4 (double-precision), set Coprocessor 1 condition flag specfied by immediate true else set it false",
BasicInstructionFormat.R_FORMAT,
"010001 10001 ttttt sssss fff 00 111110",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- if (operands[1]%2==1 || operands[2]%2==1) {
- throw new ProcessingException(statement, "both registers must be even-numbered");
- }
- double op1 = Double.longBitsToDouble(Binary.twoIntsToLong(
- Coprocessor1.getValue(operands[1]+1),Coprocessor1.getValue(operands[1])));
- double op2 = Double.longBitsToDouble(Binary.twoIntsToLong(
- Coprocessor1.getValue(operands[2]+1),Coprocessor1.getValue(operands[2])));
- if (op1 <= op2)
- Coprocessor1.setConditionFlag(operands[0]);
- else
- Coprocessor1.clearConditionFlag(operands[0]);
- }
- }));
- instructionList.add(
- new BasicInstruction("c.lt.d $f2,$f4",
- "Compare less than double precision : If $f2 is less than $f4 (double-precision), set Coprocessor 1 condition flag 0 true else set it false",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ if (operands[1] % 2 == 1 || operands[2] % 2 == 1)
+ {
+ throw new ProcessingException(statement, "both registers must be even-numbered");
+ }
+ double op1 = Double.longBitsToDouble(Binary.twoIntsToLong(
+ Coprocessor1.getValue(operands[1] + 1), Coprocessor1.getValue(operands[1])));
+ double op2 = Double.longBitsToDouble(Binary.twoIntsToLong(
+ Coprocessor1.getValue(operands[2] + 1), Coprocessor1.getValue(operands[2])));
+ if (op1 <= op2)
+ {
+ Coprocessor1.setConditionFlag(operands[0]);
+ }
+ else
+ {
+ Coprocessor1.clearConditionFlag(operands[0]);
+ }
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("c.lt.d $f2,$f4",
+ "Compare less than double precision : If $f2 is less than $f4 (double-precision), set Coprocessor 1 condition flag 0 true else set it false",
BasicInstructionFormat.R_FORMAT,
"010001 10001 sssss fffff 00000 111100",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- if (operands[0]%2==1 || operands[1]%2==1) {
- throw new ProcessingException(statement, "both registers must be even-numbered");
- }
- double op1 = Double.longBitsToDouble(Binary.twoIntsToLong(
- Coprocessor1.getValue(operands[0]+1),Coprocessor1.getValue(operands[0])));
- double op2 = Double.longBitsToDouble(Binary.twoIntsToLong(
- Coprocessor1.getValue(operands[1]+1),Coprocessor1.getValue(operands[1])));
- if (op1 < op2)
- Coprocessor1.setConditionFlag(0);
- else
- Coprocessor1.clearConditionFlag(0);
- }
- }));
- instructionList.add(
- new BasicInstruction("c.lt.d 1,$f2,$f4",
- "Compare less than double precision : If $f2 is less than $f4 (double-precision), set Coprocessor 1 condition flag specified by immediate to true else set it to false",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ if (operands[0] % 2 == 1 || operands[1] % 2 == 1)
+ {
+ throw new ProcessingException(statement, "both registers must be even-numbered");
+ }
+ double op1 = Double.longBitsToDouble(Binary.twoIntsToLong(
+ Coprocessor1.getValue(operands[0] + 1), Coprocessor1.getValue(operands[0])));
+ double op2 = Double.longBitsToDouble(Binary.twoIntsToLong(
+ Coprocessor1.getValue(operands[1] + 1), Coprocessor1.getValue(operands[1])));
+ if (op1 < op2)
+ {
+ Coprocessor1.setConditionFlag(0);
+ }
+ else
+ {
+ Coprocessor1.clearConditionFlag(0);
+ }
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("c.lt.d 1,$f2,$f4",
+ "Compare less than double precision : If $f2 is less than $f4 (double-precision), set Coprocessor 1 condition flag specified by immediate to true else set it to false",
BasicInstructionFormat.R_FORMAT,
"010001 10001 ttttt sssss fff 00 111100",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- if (operands[1]%2==1 || operands[2]%2==1) {
- throw new ProcessingException(statement, "both registers must be even-numbered");
- }
- double op1 = Double.longBitsToDouble(Binary.twoIntsToLong(
- Coprocessor1.getValue(operands[1]+1),Coprocessor1.getValue(operands[1])));
- double op2 = Double.longBitsToDouble(Binary.twoIntsToLong(
- Coprocessor1.getValue(operands[2]+1),Coprocessor1.getValue(operands[2])));
- if (op1 < op2)
- Coprocessor1.setConditionFlag(operands[0]);
- else
- Coprocessor1.clearConditionFlag(operands[0]);
- }
- }));
- instructionList.add(
- new BasicInstruction("abs.s $f0,$f1",
- "Floating point absolute value single precision : Set $f0 to absolute value of $f1, single precision",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ if (operands[1] % 2 == 1 || operands[2] % 2 == 1)
+ {
+ throw new ProcessingException(statement, "both registers must be even-numbered");
+ }
+ double op1 = Double.longBitsToDouble(Binary.twoIntsToLong(
+ Coprocessor1.getValue(operands[1] + 1), Coprocessor1.getValue(operands[1])));
+ double op2 = Double.longBitsToDouble(Binary.twoIntsToLong(
+ Coprocessor1.getValue(operands[2] + 1), Coprocessor1.getValue(operands[2])));
+ if (op1 < op2)
+ {
+ Coprocessor1.setConditionFlag(operands[0]);
+ }
+ else
+ {
+ Coprocessor1.clearConditionFlag(operands[0]);
+ }
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("abs.s $f0,$f1",
+ "Floating point absolute value single precision : Set $f0 to absolute value of $f1, single precision",
BasicInstructionFormat.R_FORMAT,
"010001 10000 00000 sssss fffff 000101",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- // I need only clear the high order bit!
- Coprocessor1.updateRegister(operands[0],
- Coprocessor1.getValue(operands[1]) & Integer.MAX_VALUE);
- }
- }));
- instructionList.add(
- new BasicInstruction("abs.d $f2,$f4",
- "Floating point absolute value double precision : Set $f2 to absolute value of $f4, double precision",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ // I need only clear the high order bit!
+ Coprocessor1.updateRegister(operands[0],
+ Coprocessor1.getValue(operands[1]) & Integer.MAX_VALUE);
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("abs.d $f2,$f4",
+ "Floating point absolute value double precision : Set $f2 to absolute value of $f4, double precision",
BasicInstructionFormat.R_FORMAT,
"010001 10001 00000 sssss fffff 000101",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- if (operands[0]%2==1 || operands[1]%2==1) {
- throw new ProcessingException(statement, "both registers must be even-numbered");
- }
- // I need only clear the high order bit of high word register!
- Coprocessor1.updateRegister(operands[0]+1,
- Coprocessor1.getValue(operands[1]+1) & Integer.MAX_VALUE);
- Coprocessor1.updateRegister(operands[0],
- Coprocessor1.getValue(operands[1]));
- }
- }));
- instructionList.add(
- new BasicInstruction("cvt.d.s $f2,$f1",
- "Convert from single precision to double precision : Set $f2 to double precision equivalent of single precision value in $f1",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ if (operands[0] % 2 == 1 || operands[1] % 2 == 1)
+ {
+ throw new ProcessingException(statement, "both registers must be even-numbered");
+ }
+ // I need only clear the high order bit of high word register!
+ Coprocessor1.updateRegister(operands[0] + 1,
+ Coprocessor1.getValue(operands[1] + 1) & Integer.MAX_VALUE);
+ Coprocessor1.updateRegister(operands[0],
+ Coprocessor1.getValue(operands[1]));
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("cvt.d.s $f2,$f1",
+ "Convert from single precision to double precision : Set $f2 to double precision equivalent of single precision value in $f1",
BasicInstructionFormat.R_FORMAT,
"010001 10000 00000 sssss fffff 100001",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- if (operands[0]%2==1) {
- throw new ProcessingException(statement, "first register must be even-numbered");
- }
- // convert single precision in $f1 to double stored in $f2
- long result = Double.doubleToLongBits(
- (double)Float.intBitsToFloat(Coprocessor1.getValue(operands[1])));
- Coprocessor1.updateRegister(operands[0]+1, Binary.highOrderLongToInt(result));
- Coprocessor1.updateRegister(operands[0], Binary.lowOrderLongToInt(result));
- }
- }));
- instructionList.add(
- new BasicInstruction("cvt.d.w $f2,$f1",
- "Convert from word to double precision : Set $f2 to double precision equivalent of 32-bit integer value in $f1",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ if (operands[0] % 2 == 1)
+ {
+ throw new ProcessingException(statement, "first register must be even-numbered");
+ }
+ // convert single precision in $f1 to double stored in $f2
+ long result = Double.doubleToLongBits(
+ Float.intBitsToFloat(Coprocessor1.getValue(operands[1])));
+ Coprocessor1.updateRegister(operands[0] + 1, Binary.highOrderLongToInt(result));
+ Coprocessor1.updateRegister(operands[0], Binary.lowOrderLongToInt(result));
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("cvt.d.w $f2,$f1",
+ "Convert from word to double precision : Set $f2 to double precision equivalent of 32-bit integer value in $f1",
BasicInstructionFormat.R_FORMAT,
"010001 10100 00000 sssss fffff 100001",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- if (operands[0]%2==1) {
- throw new ProcessingException(statement, "first register must be even-numbered");
- }
- // convert integer to double (interpret $f1 value as int?)
- long result = Double.doubleToLongBits(
- (double)Coprocessor1.getValue(operands[1]));
- Coprocessor1.updateRegister(operands[0]+1, Binary.highOrderLongToInt(result));
- Coprocessor1.updateRegister(operands[0], Binary.lowOrderLongToInt(result));
- }
- }));
- instructionList.add(
- new BasicInstruction("cvt.s.d $f1,$f2",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ if (operands[0] % 2 == 1)
+ {
+ throw new ProcessingException(statement, "first register must be even-numbered");
+ }
+ // convert integer to double (interpret $f1 value as int?)
+ long result = Double.doubleToLongBits(
+ Coprocessor1.getValue(operands[1]));
+ Coprocessor1.updateRegister(operands[0] + 1, Binary.highOrderLongToInt(result));
+ Coprocessor1.updateRegister(operands[0], Binary.lowOrderLongToInt(result));
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("cvt.s.d $f1,$f2",
"Convert from double precision to single precision : Set $f1 to single precision equivalent of double precision value in $f2",
- BasicInstructionFormat.R_FORMAT,
+ BasicInstructionFormat.R_FORMAT,
"010001 10001 00000 sssss fffff 100000",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- // convert double precision in $f2 to single stored in $f1
- if (operands[1]%2==1) {
- throw new ProcessingException(statement, "second register must be even-numbered");
- }
- double val = Double.longBitsToDouble(Binary.twoIntsToLong(
- Coprocessor1.getValue(operands[1]+1),Coprocessor1.getValue(operands[1])));
- Coprocessor1.updateRegister(operands[0], Float.floatToIntBits((float)val));
- }
- }));
- instructionList.add(
- new BasicInstruction("cvt.s.w $f0,$f1",
- "Convert from word to single precision : Set $f0 to single precision equivalent of 32-bit integer value in $f2",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ // convert double precision in $f2 to single stored in $f1
+ if (operands[1] % 2 == 1)
+ {
+ throw new ProcessingException(statement, "second register must be even-numbered");
+ }
+ double val = Double.longBitsToDouble(Binary.twoIntsToLong(
+ Coprocessor1.getValue(operands[1] + 1), Coprocessor1.getValue(operands[1])));
+ Coprocessor1.updateRegister(operands[0], Float.floatToIntBits((float) val));
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("cvt.s.w $f0,$f1",
+ "Convert from word to single precision : Set $f0 to single precision equivalent of 32-bit integer value in $f2",
BasicInstructionFormat.R_FORMAT,
"010001 10100 00000 sssss fffff 100000",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- // convert integer to single (interpret $f1 value as int?)
- Coprocessor1.updateRegister(operands[0],
- Float.floatToIntBits((float)Coprocessor1.getValue(operands[1])));
- }
- }));
- instructionList.add(
- new BasicInstruction("cvt.w.d $f1,$f2",
- "Convert from double precision to word : Set $f1 to 32-bit integer equivalent of double precision value in $f2",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ // convert integer to single (interpret $f1 value as int?)
+ Coprocessor1.updateRegister(operands[0],
+ Float.floatToIntBits((float) Coprocessor1.getValue(operands[1])));
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("cvt.w.d $f1,$f2",
+ "Convert from double precision to word : Set $f1 to 32-bit integer equivalent of double precision value in $f2",
BasicInstructionFormat.R_FORMAT,
"010001 10001 00000 sssss fffff 100100",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- // convert double precision in $f2 to integer stored in $f1
- if (operands[1]%2==1) {
- throw new ProcessingException(statement, "second register must be even-numbered");
- }
- double val = Double.longBitsToDouble(Binary.twoIntsToLong(
- Coprocessor1.getValue(operands[1]+1),Coprocessor1.getValue(operands[1])));
- Coprocessor1.updateRegister(operands[0], (int) val);
- }
- }));
- instructionList.add(
- new BasicInstruction("cvt.w.s $f0,$f1",
- "Convert from single precision to word : Set $f0 to 32-bit integer equivalent of single precision value in $f1",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ // convert double precision in $f2 to integer stored in $f1
+ if (operands[1] % 2 == 1)
+ {
+ throw new ProcessingException(statement, "second register must be even-numbered");
+ }
+ double val = Double.longBitsToDouble(Binary.twoIntsToLong(
+ Coprocessor1.getValue(operands[1] + 1), Coprocessor1.getValue(operands[1])));
+ Coprocessor1.updateRegister(operands[0], (int) val);
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("cvt.w.s $f0,$f1",
+ "Convert from single precision to word : Set $f0 to 32-bit integer equivalent of single precision value in $f1",
BasicInstructionFormat.R_FORMAT,
"010001 10000 00000 sssss fffff 100100",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- // convert single precision in $f1 to integer stored in $f0
- Coprocessor1.updateRegister(operands[0],
- (int)Float.intBitsToFloat(Coprocessor1.getValue(operands[1])));
- }
- }));
- instructionList.add(
- new BasicInstruction("mov.d $f2,$f4",
- "Move floating point double precision : Set double precision $f2 to double precision value in $f4",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ // convert single precision in $f1 to integer stored in $f0
+ Coprocessor1.updateRegister(operands[0],
+ (int) Float.intBitsToFloat(Coprocessor1.getValue(operands[1])));
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("mov.d $f2,$f4",
+ "Move floating point double precision : Set double precision $f2 to double precision value in $f4",
BasicInstructionFormat.R_FORMAT,
"010001 10001 00000 sssss fffff 000110",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- if (operands[0]%2==1 || operands[1]%2==1) {
- throw new ProcessingException(statement, "both registers must be even-numbered");
- }
- Coprocessor1.updateRegister(operands[0], Coprocessor1.getValue(operands[1]));
- Coprocessor1.updateRegister(operands[0]+1, Coprocessor1.getValue(operands[1]+1));
- }
- }));
- instructionList.add(
- new BasicInstruction("movf.d $f2,$f4",
- "Move floating point double precision : If condition flag 0 false, set double precision $f2 to double precision value in $f4",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ if (operands[0] % 2 == 1 || operands[1] % 2 == 1)
+ {
+ throw new ProcessingException(statement, "both registers must be even-numbered");
+ }
+ Coprocessor1.updateRegister(operands[0], Coprocessor1.getValue(operands[1]));
+ Coprocessor1.updateRegister(operands[0] + 1, Coprocessor1.getValue(operands[1] + 1));
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("movf.d $f2,$f4",
+ "Move floating point double precision : If condition flag 0 false, set double precision $f2 to double precision value in $f4",
BasicInstructionFormat.R_FORMAT,
"010001 10001 000 00 sssss fffff 010001",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- if (operands[0]%2==1 || operands[1]%2==1) {
- throw new ProcessingException(statement, "both registers must be even-numbered");
- }
- if (Coprocessor1.getConditionFlag(0)==0) {
- Coprocessor1.updateRegister(operands[0], Coprocessor1.getValue(operands[1]));
- Coprocessor1.updateRegister(operands[0]+1, Coprocessor1.getValue(operands[1]+1));
- }
- }
- }));
- instructionList.add(
- new BasicInstruction("movf.d $f2,$f4,1",
- "Move floating point double precision : If condition flag specified by immediate is false, set double precision $f2 to double precision value in $f4",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ if (operands[0] % 2 == 1 || operands[1] % 2 == 1)
+ {
+ throw new ProcessingException(statement, "both registers must be even-numbered");
+ }
+ if (Coprocessor1.getConditionFlag(0) == 0)
+ {
+ Coprocessor1.updateRegister(operands[0], Coprocessor1.getValue(operands[1]));
+ Coprocessor1.updateRegister(operands[0] + 1, Coprocessor1.getValue(operands[1] + 1));
+ }
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("movf.d $f2,$f4,1",
+ "Move floating point double precision : If condition flag specified by immediate is false, set double precision $f2 to double precision value in $f4",
BasicInstructionFormat.R_FORMAT,
"010001 10001 ttt 00 sssss fffff 010001",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- if (operands[0]%2==1 || operands[1]%2==1) {
- throw new ProcessingException(statement, "both registers must be even-numbered");
- }
- if (Coprocessor1.getConditionFlag(operands[2])==0) {
- Coprocessor1.updateRegister(operands[0], Coprocessor1.getValue(operands[1]));
- Coprocessor1.updateRegister(operands[0]+1, Coprocessor1.getValue(operands[1]+1));
- }
- }
- }));
- instructionList.add(
- new BasicInstruction("movt.d $f2,$f4",
- "Move floating point double precision : If condition flag 0 true, set double precision $f2 to double precision value in $f4",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ if (operands[0] % 2 == 1 || operands[1] % 2 == 1)
+ {
+ throw new ProcessingException(statement, "both registers must be even-numbered");
+ }
+ if (Coprocessor1.getConditionFlag(operands[2]) == 0)
+ {
+ Coprocessor1.updateRegister(operands[0], Coprocessor1.getValue(operands[1]));
+ Coprocessor1.updateRegister(operands[0] + 1, Coprocessor1.getValue(operands[1] + 1));
+ }
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("movt.d $f2,$f4",
+ "Move floating point double precision : If condition flag 0 true, set double precision $f2 to double precision value in $f4",
BasicInstructionFormat.R_FORMAT,
"010001 10001 000 01 sssss fffff 010001",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- if (operands[0]%2==1 || operands[1]%2==1) {
- throw new ProcessingException(statement, "both registers must be even-numbered");
- }
- if (Coprocessor1.getConditionFlag(0)==1) {
- Coprocessor1.updateRegister(operands[0], Coprocessor1.getValue(operands[1]));
- Coprocessor1.updateRegister(operands[0]+1, Coprocessor1.getValue(operands[1]+1));
- }
- }
- }));
- instructionList.add(
- new BasicInstruction("movt.d $f2,$f4,1",
- "Move floating point double precision : If condition flag specified by immediate is true, set double precision $f2 to double precision value in $f4e",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ if (operands[0] % 2 == 1 || operands[1] % 2 == 1)
+ {
+ throw new ProcessingException(statement, "both registers must be even-numbered");
+ }
+ if (Coprocessor1.getConditionFlag(0) == 1)
+ {
+ Coprocessor1.updateRegister(operands[0], Coprocessor1.getValue(operands[1]));
+ Coprocessor1.updateRegister(operands[0] + 1, Coprocessor1.getValue(operands[1] + 1));
+ }
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("movt.d $f2,$f4,1",
+ "Move floating point double precision : If condition flag specified by immediate is true, set double precision $f2 to double precision value in $f4e",
BasicInstructionFormat.R_FORMAT,
"010001 10001 ttt 01 sssss fffff 010001",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- if (operands[0]%2==1 || operands[1]%2==1) {
- throw new ProcessingException(statement, "both registers must be even-numbered");
- }
- if (Coprocessor1.getConditionFlag(operands[2])==1) {
- Coprocessor1.updateRegister(operands[0], Coprocessor1.getValue(operands[1]));
- Coprocessor1.updateRegister(operands[0]+1, Coprocessor1.getValue(operands[1]+1));
- }
- }
- }));
- instructionList.add(
- new BasicInstruction("movn.d $f2,$f4,$t3",
- "Move floating point double precision : If $t3 is not zero, set double precision $f2 to double precision value in $f4",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ if (operands[0] % 2 == 1 || operands[1] % 2 == 1)
+ {
+ throw new ProcessingException(statement, "both registers must be even-numbered");
+ }
+ if (Coprocessor1.getConditionFlag(operands[2]) == 1)
+ {
+ Coprocessor1.updateRegister(operands[0], Coprocessor1.getValue(operands[1]));
+ Coprocessor1.updateRegister(operands[0] + 1, Coprocessor1.getValue(operands[1] + 1));
+ }
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("movn.d $f2,$f4,$t3",
+ "Move floating point double precision : If $t3 is not zero, set double precision $f2 to double precision value in $f4",
BasicInstructionFormat.R_FORMAT,
"010001 10001 ttttt sssss fffff 010011",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- if (operands[0]%2==1 || operands[1]%2==1) {
- throw new ProcessingException(statement, "both registers must be even-numbered");
- }
- if (RegisterFile.getValue(operands[2])!=0) {
- Coprocessor1.updateRegister(operands[0], Coprocessor1.getValue(operands[1]));
- Coprocessor1.updateRegister(operands[0]+1, Coprocessor1.getValue(operands[1]+1));
- }
- }
- }));
- instructionList.add(
- new BasicInstruction("movz.d $f2,$f4,$t3",
- "Move floating point double precision : If $t3 is zero, set double precision $f2 to double precision value in $f4",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ if (operands[0] % 2 == 1 || operands[1] % 2 == 1)
+ {
+ throw new ProcessingException(statement, "both registers must be even-numbered");
+ }
+ if (RegisterFile.getValue(operands[2]) != 0)
+ {
+ Coprocessor1.updateRegister(operands[0], Coprocessor1.getValue(operands[1]));
+ Coprocessor1.updateRegister(operands[0] + 1, Coprocessor1.getValue(operands[1] + 1));
+ }
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("movz.d $f2,$f4,$t3",
+ "Move floating point double precision : If $t3 is zero, set double precision $f2 to double precision value in $f4",
BasicInstructionFormat.R_FORMAT,
"010001 10001 ttttt sssss fffff 010010",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- if (operands[0]%2==1 || operands[1]%2==1) {
- throw new ProcessingException(statement, "both registers must be even-numbered");
- }
- if (RegisterFile.getValue(operands[2])==0) {
- Coprocessor1.updateRegister(operands[0], Coprocessor1.getValue(operands[1]));
- Coprocessor1.updateRegister(operands[0]+1, Coprocessor1.getValue(operands[1]+1));
- }
- }
- }));
- instructionList.add(
- new BasicInstruction("mov.s $f0,$f1",
- "Move floating point single precision : Set single precision $f0 to single precision value in $f1",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ if (operands[0] % 2 == 1 || operands[1] % 2 == 1)
+ {
+ throw new ProcessingException(statement, "both registers must be even-numbered");
+ }
+ if (RegisterFile.getValue(operands[2]) == 0)
+ {
+ Coprocessor1.updateRegister(operands[0], Coprocessor1.getValue(operands[1]));
+ Coprocessor1.updateRegister(operands[0] + 1, Coprocessor1.getValue(operands[1] + 1));
+ }
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("mov.s $f0,$f1",
+ "Move floating point single precision : Set single precision $f0 to single precision value in $f1",
BasicInstructionFormat.R_FORMAT,
"010001 10000 00000 sssss fffff 000110",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- Coprocessor1.updateRegister(operands[0], Coprocessor1.getValue(operands[1]));
- }
- }));
- instructionList.add(
- new BasicInstruction("movf.s $f0,$f1",
- "Move floating point single precision : If condition flag 0 is false, set single precision $f0 to single precision value in $f1",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ Coprocessor1.updateRegister(operands[0], Coprocessor1.getValue(operands[1]));
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("movf.s $f0,$f1",
+ "Move floating point single precision : If condition flag 0 is false, set single precision $f0 to single precision value in $f1",
BasicInstructionFormat.R_FORMAT,
"010001 10000 000 00 sssss fffff 010001",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- if (Coprocessor1.getConditionFlag(0)==0)
- Coprocessor1.updateRegister(operands[0], Coprocessor1.getValue(operands[1]));
- }
- }));
- instructionList.add(
- new BasicInstruction("movf.s $f0,$f1,1",
- "Move floating point single precision : If condition flag specified by immediate is false, set single precision $f0 to single precision value in $f1e",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ if (Coprocessor1.getConditionFlag(0) == 0)
+ {
+ Coprocessor1.updateRegister(operands[0], Coprocessor1.getValue(operands[1]));
+ }
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("movf.s $f0,$f1,1",
+ "Move floating point single precision : If condition flag specified by immediate is false, set single precision $f0 to single precision value in $f1e",
BasicInstructionFormat.R_FORMAT,
"010001 10000 ttt 00 sssss fffff 010001",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- if (Coprocessor1.getConditionFlag(operands[2])==0)
- Coprocessor1.updateRegister(operands[0], Coprocessor1.getValue(operands[1]));
- }
- }));
- instructionList.add(
- new BasicInstruction("movt.s $f0,$f1",
- "Move floating point single precision : If condition flag 0 is true, set single precision $f0 to single precision value in $f1e",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ if (Coprocessor1.getConditionFlag(operands[2]) == 0)
+ {
+ Coprocessor1.updateRegister(operands[0], Coprocessor1.getValue(operands[1]));
+ }
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("movt.s $f0,$f1",
+ "Move floating point single precision : If condition flag 0 is true, set single precision $f0 to single precision value in $f1e",
BasicInstructionFormat.R_FORMAT,
"010001 10000 000 01 sssss fffff 010001",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- if (Coprocessor1.getConditionFlag(0)==1)
- Coprocessor1.updateRegister(operands[0], Coprocessor1.getValue(operands[1]));
- }
- }));
- instructionList.add(
- new BasicInstruction("movt.s $f0,$f1,1",
- "Move floating point single precision : If condition flag specified by immediate is true, set single precision $f0 to single precision value in $f1e",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ if (Coprocessor1.getConditionFlag(0) == 1)
+ {
+ Coprocessor1.updateRegister(operands[0], Coprocessor1.getValue(operands[1]));
+ }
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("movt.s $f0,$f1,1",
+ "Move floating point single precision : If condition flag specified by immediate is true, set single precision $f0 to single precision value in $f1e",
BasicInstructionFormat.R_FORMAT,
"010001 10000 ttt 01 sssss fffff 010001",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- if (Coprocessor1.getConditionFlag(operands[2])==1)
- Coprocessor1.updateRegister(operands[0], Coprocessor1.getValue(operands[1]));
- }
- }));
- instructionList.add(
- new BasicInstruction("movn.s $f0,$f1,$t3",
- "Move floating point single precision : If $t3 is not zero, set single precision $f0 to single precision value in $f1",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ if (Coprocessor1.getConditionFlag(operands[2]) == 1)
+ {
+ Coprocessor1.updateRegister(operands[0], Coprocessor1.getValue(operands[1]));
+ }
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("movn.s $f0,$f1,$t3",
+ "Move floating point single precision : If $t3 is not zero, set single precision $f0 to single precision value in $f1",
BasicInstructionFormat.R_FORMAT,
"010001 10000 ttttt sssss fffff 010011",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- if (RegisterFile.getValue(operands[2])!=0)
- Coprocessor1.updateRegister(operands[0], Coprocessor1.getValue(operands[1]));
- }
- }));
- instructionList.add(
- new BasicInstruction("movz.s $f0,$f1,$t3",
- "Move floating point single precision : If $t3 is zero, set single precision $f0 to single precision value in $f1",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ if (RegisterFile.getValue(operands[2]) != 0)
+ {
+ Coprocessor1.updateRegister(operands[0], Coprocessor1.getValue(operands[1]));
+ }
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("movz.s $f0,$f1,$t3",
+ "Move floating point single precision : If $t3 is zero, set single precision $f0 to single precision value in $f1",
BasicInstructionFormat.R_FORMAT,
"010001 10000 ttttt sssss fffff 010010",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- if (RegisterFile.getValue(operands[2])==0)
- Coprocessor1.updateRegister(operands[0], Coprocessor1.getValue(operands[1]));
- }
- }));
- instructionList.add(
- new BasicInstruction("mfc1 $t1,$f1",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ if (RegisterFile.getValue(operands[2]) == 0)
+ {
+ Coprocessor1.updateRegister(operands[0], Coprocessor1.getValue(operands[1]));
+ }
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("mfc1 $t1,$f1",
"Move from Coprocessor 1 (FPU) : Set $t1 to value in Coprocessor 1 register $f1",
- BasicInstructionFormat.R_FORMAT,
- "010001 00000 fffff sssss 00000 000000",
+ BasicInstructionFormat.R_FORMAT,
+ "010001 00000 fffff sssss 00000 000000",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- RegisterFile.updateRegister(operands[0], Coprocessor1.getValue(operands[1]));
- }
- }));
- instructionList.add(
- new BasicInstruction("mtc1 $t1,$f1",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ RegisterFile.updateRegister(operands[0], Coprocessor1.getValue(operands[1]));
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("mtc1 $t1,$f1",
"Move to Coprocessor 1 (FPU) : Set Coprocessor 1 register $f1 to value in $t1",
- BasicInstructionFormat.R_FORMAT,
+ BasicInstructionFormat.R_FORMAT,
"010001 00100 fffff sssss 00000 000000",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- Coprocessor1.updateRegister(operands[1], RegisterFile.getValue(operands[0]));
- }
- }));
- instructionList.add(
- new BasicInstruction("neg.d $f2,$f4",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ Coprocessor1.updateRegister(operands[1], RegisterFile.getValue(operands[0]));
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("neg.d $f2,$f4",
"Floating point negate double precision : Set double precision $f2 to negation of double precision value in $f4",
- BasicInstructionFormat.R_FORMAT,
+ BasicInstructionFormat.R_FORMAT,
"010001 10001 00000 sssss fffff 000111",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- if (operands[0]%2==1 || operands[1]%2==1) {
- throw new ProcessingException(statement, "both registers must be even-numbered");
- }
- // flip the sign bit of the second register (high order word) of the pair
- int value = Coprocessor1.getValue(operands[1]+1);
- Coprocessor1.updateRegister(operands[0]+1,
- ((value < 0) ? (value & Integer.MAX_VALUE) : (value | Integer.MIN_VALUE)));
- Coprocessor1.updateRegister(operands[0], Coprocessor1.getValue(operands[1]));
- }
- }));
- instructionList.add(
- new BasicInstruction("neg.s $f0,$f1",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ if (operands[0] % 2 == 1 || operands[1] % 2 == 1)
+ {
+ throw new ProcessingException(statement, "both registers must be even-numbered");
+ }
+ // flip the sign bit of the second register (high order word) of the pair
+ int value = Coprocessor1.getValue(operands[1] + 1);
+ Coprocessor1.updateRegister(operands[0] + 1,
+ ((value < 0) ? (value & Integer.MAX_VALUE) : (value | Integer.MIN_VALUE)));
+ Coprocessor1.updateRegister(operands[0], Coprocessor1.getValue(operands[1]));
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("neg.s $f0,$f1",
"Floating point negate single precision : Set single precision $f0 to negation of single precision value in $f1",
- BasicInstructionFormat.R_FORMAT,
+ BasicInstructionFormat.R_FORMAT,
"010001 10000 00000 sssss fffff 000111",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- int value = Coprocessor1.getValue(operands[1]);
- // flip the sign bit
- Coprocessor1.updateRegister(operands[0],
- ((value < 0) ? (value & Integer.MAX_VALUE) : (value | Integer.MIN_VALUE)));
- }
- }));
- instructionList.add(
- new BasicInstruction("lwc1 $f1,-100($t2)",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ int value = Coprocessor1.getValue(operands[1]);
+ // flip the sign bit
+ Coprocessor1.updateRegister(operands[0],
+ ((value < 0) ? (value & Integer.MAX_VALUE) : (value | Integer.MIN_VALUE)));
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("lwc1 $f1,-100($t2)",
"Load word into Coprocessor 1 (FPU) : Set $f1 to 32-bit value from effective memory word address",
- BasicInstructionFormat.I_FORMAT,
+ BasicInstructionFormat.I_FORMAT,
"110001 ttttt fffff ssssssssssssssss",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- try
- {
- Coprocessor1.updateRegister(operands[0],
- Globals.memory.getWord(
- RegisterFile.getValue(operands[2]) + operands[1]));
- }
- catch (AddressErrorException e)
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ try
{
- throw new ProcessingException(statement, e);
+ Coprocessor1.updateRegister(operands[0],
+ Globals.memory.getWord(
+ RegisterFile.getValue(operands[2]) + operands[1]));
}
- }
- }));
- instructionList.add(// no printed reference, got opcode from SPIM
- new BasicInstruction("ldc1 $f2,-100($t2)",
- "Load double word Coprocessor 1 (FPU)) : Set $f2 to 64-bit value from effective memory doubleword address",
+ catch (AddressErrorException e)
+ {
+ throw new ProcessingException(statement, e);
+ }
+ }
+ }));
+ instructionList.add(// no printed reference, got opcode from SPIM
+ new BasicInstruction("ldc1 $f2,-100($t2)",
+ "Load double word Coprocessor 1 (FPU)) : Set $f2 to 64-bit value from effective memory doubleword address",
BasicInstructionFormat.I_FORMAT,
"110101 ttttt fffff ssssssssssssssss",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- if (operands[0]%2==1) {
- throw new ProcessingException(statement, "first register must be even-numbered");
- }
- // IF statement added by DPS 13-July-2011.
- if (!Globals.memory.doublewordAligned(RegisterFile.getValue(operands[2]) + operands[1])) {
- throw new ProcessingException(statement,
- new AddressErrorException("address not aligned on doubleword boundary ",
- Exceptions.ADDRESS_EXCEPTION_LOAD, RegisterFile.getValue(operands[2]) + operands[1]));
- }
-
- try
- {
- Coprocessor1.updateRegister(operands[0],
- Globals.memory.getWord(
- RegisterFile.getValue(operands[2]) + operands[1]));
- Coprocessor1.updateRegister(operands[0]+1,
- Globals.memory.getWord(
- RegisterFile.getValue(operands[2]) + operands[1] + 4));
- }
- catch (AddressErrorException e)
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ if (operands[0] % 2 == 1)
{
- throw new ProcessingException(statement, e);
+ throw new ProcessingException(statement, "first register must be even-numbered");
}
- }
- }));
- instructionList.add(
- new BasicInstruction("swc1 $f1,-100($t2)",
- "Store word from Coprocesor 1 (FPU) : Store 32 bit value in $f1 to effective memory word address",
+ // IF statement added by DPS 13-July-2011.
+ if (!Memory.doublewordAligned(RegisterFile.getValue(operands[2]) + operands[1]))
+ {
+ throw new ProcessingException(statement,
+ new AddressErrorException("address not aligned on doubleword boundary ",
+ Exceptions.ADDRESS_EXCEPTION_LOAD, RegisterFile.getValue(operands[2]) + operands[1]));
+ }
+
+ try
+ {
+ Coprocessor1.updateRegister(operands[0],
+ Globals.memory.getWord(
+ RegisterFile.getValue(operands[2]) + operands[1]));
+ Coprocessor1.updateRegister(operands[0] + 1,
+ Globals.memory.getWord(
+ RegisterFile.getValue(operands[2]) + operands[1] + 4));
+ }
+ catch (AddressErrorException e)
+ {
+ throw new ProcessingException(statement, e);
+ }
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("swc1 $f1,-100($t2)",
+ "Store word from Coprocesor 1 (FPU) : Store 32 bit value in $f1 to effective memory word address",
BasicInstructionFormat.I_FORMAT,
"111001 ttttt fffff ssssssssssssssss",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- try
- {
- Globals.memory.setWord(
- RegisterFile.getValue(operands[2]) + operands[1],
- Coprocessor1.getValue(operands[0]));
- }
- catch (AddressErrorException e)
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ try
{
- throw new ProcessingException(statement, e);
+ Globals.memory.setWord(
+ RegisterFile.getValue(operands[2]) + operands[1],
+ Coprocessor1.getValue(operands[0]));
}
- }
- }));
- instructionList.add( // no printed reference, got opcode from SPIM
- new BasicInstruction("sdc1 $f2,-100($t2)",
- "Store double word from Coprocessor 1 (FPU)) : Store 64 bit value in $f2 to effective memory doubleword address",
+ catch (AddressErrorException e)
+ {
+ throw new ProcessingException(statement, e);
+ }
+ }
+ }));
+ instructionList.add( // no printed reference, got opcode from SPIM
+ new BasicInstruction("sdc1 $f2,-100($t2)",
+ "Store double word from Coprocessor 1 (FPU)) : Store 64 bit value in $f2 to effective memory doubleword address",
BasicInstructionFormat.I_FORMAT,
"111101 ttttt fffff ssssssssssssssss",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- if (operands[0]%2==1) {
- throw new ProcessingException(statement, "first register must be even-numbered");
- }
- // IF statement added by DPS 13-July-2011.
- if (!Globals.memory.doublewordAligned(RegisterFile.getValue(operands[2]) + operands[1])) {
- throw new ProcessingException(statement,
- new AddressErrorException("address not aligned on doubleword boundary ",
- Exceptions.ADDRESS_EXCEPTION_STORE, RegisterFile.getValue(operands[2]) + operands[1]));
- }
- try
- {
- Globals.memory.setWord(
- RegisterFile.getValue(operands[2]) + operands[1],
- Coprocessor1.getValue(operands[0]));
- Globals.memory.setWord(
- RegisterFile.getValue(operands[2]) + operands[1] + 4,
- Coprocessor1.getValue(operands[0]+1));
- }
- catch (AddressErrorException e)
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ if (operands[0] % 2 == 1)
{
- throw new ProcessingException(statement, e);
+ throw new ProcessingException(statement, "first register must be even-numbered");
}
- }
- }));
- //////////////////////////// THE TRAP INSTRUCTIONS & ERET ////////////////////////////
- instructionList.add(
- new BasicInstruction("teq $t1,$t2",
+ // IF statement added by DPS 13-July-2011.
+ if (!Memory.doublewordAligned(RegisterFile.getValue(operands[2]) + operands[1]))
+ {
+ throw new ProcessingException(statement,
+ new AddressErrorException("address not aligned on doubleword boundary ",
+ Exceptions.ADDRESS_EXCEPTION_STORE, RegisterFile.getValue(operands[2]) + operands[1]));
+ }
+ try
+ {
+ Globals.memory.setWord(
+ RegisterFile.getValue(operands[2]) + operands[1],
+ Coprocessor1.getValue(operands[0]));
+ Globals.memory.setWord(
+ RegisterFile.getValue(operands[2]) + operands[1] + 4,
+ Coprocessor1.getValue(operands[0] + 1));
+ }
+ catch (AddressErrorException e)
+ {
+ throw new ProcessingException(statement, e);
+ }
+ }
+ }));
+ //////////////////////////// THE TRAP INSTRUCTIONS & ERET ////////////////////////////
+ instructionList.add(
+ new BasicInstruction("teq $t1,$t2",
"Trap if equal : Trap if $t1 is equal to $t2",
- BasicInstructionFormat.R_FORMAT,
+ BasicInstructionFormat.R_FORMAT,
"000000 fffff sssss 00000 00000 110100",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- if (RegisterFile.getValue(operands[0]) == RegisterFile.getValue(operands[1]))
- {
- throw new ProcessingException(statement,
- "trap",Exceptions.TRAP_EXCEPTION);
- }
- }
- }));
- instructionList.add(
- new BasicInstruction("teqi $t1,-100",
- "Trap if equal to immediate : Trap if $t1 is equal to sign-extended 16 bit immediate",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ if (RegisterFile.getValue(operands[0]) == RegisterFile.getValue(operands[1]))
+ {
+ throw new ProcessingException(statement,
+ "trap", Exceptions.TRAP_EXCEPTION);
+ }
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("teqi $t1,-100",
+ "Trap if equal to immediate : Trap if $t1 is equal to sign-extended 16 bit immediate",
BasicInstructionFormat.I_FORMAT,
"000001 fffff 01100 ssssssssssssssss",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- if (RegisterFile.getValue(operands[0]) == (operands[1] << 16 >> 16))
- {
- throw new ProcessingException(statement,
- "trap",Exceptions.TRAP_EXCEPTION);
- }
- }
- }));
- instructionList.add(
- new BasicInstruction("tne $t1,$t2",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ if (RegisterFile.getValue(operands[0]) == (operands[1] << 16 >> 16))
+ {
+ throw new ProcessingException(statement,
+ "trap", Exceptions.TRAP_EXCEPTION);
+ }
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("tne $t1,$t2",
"Trap if not equal : Trap if $t1 is not equal to $t2",
- BasicInstructionFormat.R_FORMAT,
+ BasicInstructionFormat.R_FORMAT,
"000000 fffff sssss 00000 00000 110110",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- if (RegisterFile.getValue(operands[0]) != RegisterFile.getValue(operands[1]))
- {
- throw new ProcessingException(statement,
- "trap",Exceptions.TRAP_EXCEPTION);
- }
- }
- }));
- instructionList.add(
- new BasicInstruction("tnei $t1,-100",
- "Trap if not equal to immediate : Trap if $t1 is not equal to sign-extended 16 bit immediate",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ if (RegisterFile.getValue(operands[0]) != RegisterFile.getValue(operands[1]))
+ {
+ throw new ProcessingException(statement,
+ "trap", Exceptions.TRAP_EXCEPTION);
+ }
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("tnei $t1,-100",
+ "Trap if not equal to immediate : Trap if $t1 is not equal to sign-extended 16 bit immediate",
BasicInstructionFormat.I_FORMAT,
"000001 fffff 01110 ssssssssssssssss",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- if (RegisterFile.getValue(operands[0]) != (operands[1] << 16 >> 16))
- {
- throw new ProcessingException(statement,
- "trap",Exceptions.TRAP_EXCEPTION);
- }
- }
- }));
- instructionList.add(
- new BasicInstruction("tge $t1,$t2",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ if (RegisterFile.getValue(operands[0]) != (operands[1] << 16 >> 16))
+ {
+ throw new ProcessingException(statement,
+ "trap", Exceptions.TRAP_EXCEPTION);
+ }
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("tge $t1,$t2",
"Trap if greater or equal : Trap if $t1 is greater than or equal to $t2",
- BasicInstructionFormat.R_FORMAT,
+ BasicInstructionFormat.R_FORMAT,
"000000 fffff sssss 00000 00000 110000",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- if (RegisterFile.getValue(operands[0]) >= RegisterFile.getValue(operands[1]))
- {
- throw new ProcessingException(statement,
- "trap",Exceptions.TRAP_EXCEPTION);
- }
- }
- }));
- instructionList.add(
- new BasicInstruction("tgeu $t1,$t2",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ if (RegisterFile.getValue(operands[0]) >= RegisterFile.getValue(operands[1]))
+ {
+ throw new ProcessingException(statement,
+ "trap", Exceptions.TRAP_EXCEPTION);
+ }
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("tgeu $t1,$t2",
"Trap if greater or equal unsigned : Trap if $t1 is greater than or equal to $t2 using unsigned comparision",
- BasicInstructionFormat.R_FORMAT,
+ BasicInstructionFormat.R_FORMAT,
"000000 fffff sssss 00000 00000 110001",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- int first = RegisterFile.getValue(operands[0]);
- int second = RegisterFile.getValue(operands[1]);
- // if signs same, do straight compare; if signs differ & first negative then first greater else second
- if ((first >= 0 && second >= 0 || first < 0 && second < 0) ? (first >= second) : (first < 0) )
- {
- throw new ProcessingException(statement,
- "trap",Exceptions.TRAP_EXCEPTION);
- }
- }
- }));
- instructionList.add(
- new BasicInstruction("tgei $t1,-100",
- "Trap if greater than or equal to immediate : Trap if $t1 greater than or equal to sign-extended 16 bit immediate",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ int first = RegisterFile.getValue(operands[0]);
+ int second = RegisterFile.getValue(operands[1]);
+ // if signs same, do straight compare; if signs differ & first negative then first greater else second
+ if ((first >= 0 && second >= 0 || first < 0 && second < 0) ? (first >= second) : (first < 0))
+ {
+ throw new ProcessingException(statement,
+ "trap", Exceptions.TRAP_EXCEPTION);
+ }
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("tgei $t1,-100",
+ "Trap if greater than or equal to immediate : Trap if $t1 greater than or equal to sign-extended 16 bit immediate",
BasicInstructionFormat.I_FORMAT,
"000001 fffff 01000 ssssssssssssssss",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- if (RegisterFile.getValue(operands[0]) >= (operands[1] << 16 >> 16))
- {
- throw new ProcessingException(statement,
- "trap",Exceptions.TRAP_EXCEPTION);
- }
- }
- }));
- instructionList.add(
- new BasicInstruction("tgeiu $t1,-100",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ if (RegisterFile.getValue(operands[0]) >= (operands[1] << 16 >> 16))
+ {
+ throw new ProcessingException(statement,
+ "trap", Exceptions.TRAP_EXCEPTION);
+ }
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("tgeiu $t1,-100",
"Trap if greater or equal to immediate unsigned : Trap if $t1 greater than or equal to sign-extended 16 bit immediate, unsigned comparison",
- BasicInstructionFormat.I_FORMAT,
+ BasicInstructionFormat.I_FORMAT,
"000001 fffff 01001 ssssssssssssssss",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- int first = RegisterFile.getValue(operands[0]);
- // 16 bit immediate value in operands[1] is sign-extended
- int second = operands[1] << 16 >> 16;
- // if signs same, do straight compare; if signs differ & first negative then first greater else second
- if ((first >= 0 && second >= 0 || first < 0 && second < 0) ? (first >= second) : (first < 0) )
- {
- throw new ProcessingException(statement,
- "trap",Exceptions.TRAP_EXCEPTION);
- }
- }
- }));
- instructionList.add(
- new BasicInstruction("tlt $t1,$t2",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ int first = RegisterFile.getValue(operands[0]);
+ // 16 bit immediate value in operands[1] is sign-extended
+ int second = operands[1] << 16 >> 16;
+ // if signs same, do straight compare; if signs differ & first negative then first greater else second
+ if ((first >= 0 && second >= 0 || first < 0 && second < 0) ? (first >= second) : (first < 0))
+ {
+ throw new ProcessingException(statement,
+ "trap", Exceptions.TRAP_EXCEPTION);
+ }
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("tlt $t1,$t2",
"Trap if less than: Trap if $t1 less than $t2",
- BasicInstructionFormat.R_FORMAT,
+ BasicInstructionFormat.R_FORMAT,
"000000 fffff sssss 00000 00000 110010",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- if (RegisterFile.getValue(operands[0]) < RegisterFile.getValue(operands[1]))
- {
- throw new ProcessingException(statement,
- "trap",Exceptions.TRAP_EXCEPTION);
- }
- }
- }));
- instructionList.add(
- new BasicInstruction("tltu $t1,$t2",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ if (RegisterFile.getValue(operands[0]) < RegisterFile.getValue(operands[1]))
+ {
+ throw new ProcessingException(statement,
+ "trap", Exceptions.TRAP_EXCEPTION);
+ }
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("tltu $t1,$t2",
"Trap if less than unsigned : Trap if $t1 less than $t2, unsigned comparison",
- BasicInstructionFormat.R_FORMAT,
+ BasicInstructionFormat.R_FORMAT,
"000000 fffff sssss 00000 00000 110011",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- int first = RegisterFile.getValue(operands[0]);
- int second = RegisterFile.getValue(operands[1]);
- // if signs same, do straight compare; if signs differ & first positive then first is less else second
- if ((first >= 0 && second >= 0 || first < 0 && second < 0) ? (first < second) : (first >= 0) )
- {
- throw new ProcessingException(statement,
- "trap",Exceptions.TRAP_EXCEPTION);
- }
- }
- }));
- instructionList.add(
- new BasicInstruction("tlti $t1,-100",
- "Trap if less than immediate : Trap if $t1 less than sign-extended 16-bit immediate",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ int first = RegisterFile.getValue(operands[0]);
+ int second = RegisterFile.getValue(operands[1]);
+ // if signs same, do straight compare; if signs differ & first positive then first is less else second
+ if ((first >= 0 && second >= 0 || first < 0 && second < 0) ? (first < second) : (first >= 0))
+ {
+ throw new ProcessingException(statement,
+ "trap", Exceptions.TRAP_EXCEPTION);
+ }
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("tlti $t1,-100",
+ "Trap if less than immediate : Trap if $t1 less than sign-extended 16-bit immediate",
BasicInstructionFormat.I_FORMAT,
"000001 fffff 01010 ssssssssssssssss",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- if (RegisterFile.getValue(operands[0]) < (operands[1] << 16 >> 16))
- {
- throw new ProcessingException(statement,
- "trap",Exceptions.TRAP_EXCEPTION);
- }
- }
- }));
- instructionList.add(
- new BasicInstruction("tltiu $t1,-100",
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ if (RegisterFile.getValue(operands[0]) < (operands[1] << 16 >> 16))
+ {
+ throw new ProcessingException(statement,
+ "trap", Exceptions.TRAP_EXCEPTION);
+ }
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("tltiu $t1,-100",
"Trap if less than immediate unsigned : Trap if $t1 less than sign-extended 16-bit immediate, unsigned comparison",
- BasicInstructionFormat.I_FORMAT,
+ BasicInstructionFormat.I_FORMAT,
"000001 fffff 01011 ssssssssssssssss",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- int[] operands = statement.getOperands();
- int first = RegisterFile.getValue(operands[0]);
- // 16 bit immediate value in operands[1] is sign-extended
- int second = operands[1] << 16 >> 16;
- // if signs same, do straight compare; if signs differ & first positive then first is less else second
- if ((first >= 0 && second >= 0 || first < 0 && second < 0) ? (first < second) : (first >= 0) )
- {
- throw new ProcessingException(statement,
- "trap",Exceptions.TRAP_EXCEPTION);
- }
- }
- }));
- instructionList.add(
- new BasicInstruction("eret",
- "Exception return : Set Program Counter to Coprocessor 0 EPC register value, set Coprocessor Status register bit 1 (exception level) to zero",
- BasicInstructionFormat.R_FORMAT,
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ int[] operands = statement.getOperands();
+ int first = RegisterFile.getValue(operands[0]);
+ // 16 bit immediate value in operands[1] is sign-extended
+ int second = operands[1] << 16 >> 16;
+ // if signs same, do straight compare; if signs differ & first positive then first is less else second
+ if ((first >= 0 && second >= 0 || first < 0 && second < 0) ? (first < second) : (first >= 0))
+ {
+ throw new ProcessingException(statement,
+ "trap", Exceptions.TRAP_EXCEPTION);
+ }
+ }
+ }));
+ instructionList.add(
+ new BasicInstruction("eret",
+ "Exception return : Set Program Counter to Coprocessor 0 EPC register value, set Coprocessor Status register bit 1 (exception level) to zero",
+ BasicInstructionFormat.R_FORMAT,
"010000 1 0000000000000000000 011000",
new SimulationCode()
- {
- public void simulate(ProgramStatement statement) throws ProcessingException
- {
- // set EXL bit (bit 1) in Status register to 0 and set PC to EPC
- Coprocessor0.updateRegister(Coprocessor0.STATUS,
- Binary.clearBit(Coprocessor0.getValue(Coprocessor0.STATUS), Coprocessor0.EXCEPTION_LEVEL));
- RegisterFile.setProgramCounter(Coprocessor0.getValue(Coprocessor0.EPC));
- }
- }));
-
+ {
+ public void simulate(ProgramStatement statement) throws ProcessingException
+ {
+ // set EXL bit (bit 1) in Status register to 0 and set PC to EPC
+ Coprocessor0.updateRegister(Coprocessor0.STATUS,
+ Binary.clearBit(Coprocessor0.getValue(Coprocessor0.STATUS), Coprocessor0.EXCEPTION_LEVEL));
+ RegisterFile.setProgramCounter(Coprocessor0.getValue(Coprocessor0.EPC));
+ }
+ }));
+
////////////// READ PSEUDO-INSTRUCTION SPECS FROM DATA FILE AND ADD //////////////////////
- addPseudoInstructions();
-
+ addPseudoInstructions();
+
////////////// GET AND CREATE LIST OF SYSCALL FUNCTION OBJECTS ////////////////////
- syscallLoader = new SyscallLoader();
- syscallLoader.loadSyscalls();
-
+ syscallLoader = new SyscallLoader();
+ syscallLoader.loadSyscalls();
+
// Initialization step. Create token list for each instruction example. This is
// used by parser to determine user program correct syntax.
- for (int i = 0; i < instructionList.size(); i++)
- {
+ for (int i = 0; i < instructionList.size(); i++)
+ {
Instruction inst = (Instruction) instructionList.get(i);
inst.createExampleTokenList();
- }
+ }
- HashMap maskMap = new HashMap();
- ArrayList matchMaps = new ArrayList();
- for (int i = 0; i < instructionList.size(); i++) {
- Object rawInstr = instructionList.get(i);
- if (rawInstr instanceof BasicInstruction) {
- BasicInstruction basic = (BasicInstruction) rawInstr;
- Integer mask = Integer.valueOf(basic.getOpcodeMask());
- Integer match = Integer.valueOf(basic.getOpcodeMatch());
- HashMap matchMap = (HashMap) maskMap.get(mask);
- if (matchMap == null) {
- matchMap = new HashMap();
- maskMap.put(mask, matchMap);
- matchMaps.add(new MatchMap(mask, matchMap));
- }
- matchMap.put(match, basic);
- }
- }
- Collections.sort(matchMaps);
- this.opcodeMatchMaps = matchMaps;
- }
+ HashMap maskMap = new HashMap();
+ ArrayList matchMaps = new ArrayList();
+ for (int i = 0; i < instructionList.size(); i++)
+ {
+ Object rawInstr = instructionList.get(i);
+ if (rawInstr instanceof BasicInstruction)
+ {
+ BasicInstruction basic = (BasicInstruction) rawInstr;
+ Integer mask = Integer.valueOf(basic.getOpcodeMask());
+ Integer match = Integer.valueOf(basic.getOpcodeMatch());
+ HashMap matchMap = (HashMap) maskMap.get(mask);
+ if (matchMap == null)
+ {
+ matchMap = new HashMap();
+ maskMap.put(mask, matchMap);
+ matchMaps.add(new MatchMap(mask, matchMap));
+ }
+ matchMap.put(match, basic);
+ }
+ }
+ Collections.sort(matchMaps);
+ this.opcodeMatchMaps = matchMaps;
+ }
+
+ public BasicInstruction findByBinaryCode(int binaryInstr)
+ {
+ ArrayList matchMaps = this.opcodeMatchMaps;
+ for (int i = 0; i < matchMaps.size(); i++)
+ {
+ MatchMap map = (MatchMap) matchMaps.get(i);
+ BasicInstruction ret = map.find(binaryInstr);
+ if (ret != null)
+ {
+ return ret;
+ }
+ }
+ return null;
+ }
- public BasicInstruction findByBinaryCode(int binaryInstr) {
- ArrayList matchMaps = this.opcodeMatchMaps;
- for (int i = 0; i < matchMaps.size(); i++) {
- MatchMap map = (MatchMap) matchMaps.get(i);
- BasicInstruction ret = map.find(binaryInstr);
- if (ret != null) return ret;
- }
- return null;
- }
-
/* METHOD TO ADD PSEUDO-INSTRUCTIONS
- */
-
- private void addPseudoInstructions()
- {
- InputStream is = null;
- BufferedReader in = null;
- try
- {
+ */
+
+ private void addPseudoInstructions()
+ {
+ InputStream is = null;
+ BufferedReader in = null;
+ try
+ {
// leading "/" prevents package name being prepended to filepath.
is = this.getClass().getResourceAsStream("/PseudoOps.txt");
in = new BufferedReader(new InputStreamReader(is));
- }
- catch (NullPointerException e)
- {
- System.out.println(
- "Error: MIPS pseudo-instruction file PseudoOps.txt not found.");
- System.exit(0);
- }
- try
- {
+ }
+ catch (NullPointerException e)
+ {
+ System.out.println(
+ "Error: MIPS pseudo-instruction file PseudoOps.txt not found.");
+ System.exit(0);
+ }
+ try
+ {
String line, pseudoOp, template, firstTemplate, token;
String description;
StringTokenizer tokenizer;
- while ((line = in.readLine()) != null) {
+ while ((line = in.readLine()) != null)
+ {
// skip over: comment lines, empty lines, lines starting with blank.
- if (!line.startsWith("#") && !line.startsWith(" ")
- && line.length() > 0) {
- description = "";
- tokenizer = new StringTokenizer(line, "\t");
- pseudoOp = tokenizer.nextToken();
- template = "";
- firstTemplate = null;
- while (tokenizer.hasMoreTokens()) {
- token = tokenizer.nextToken();
- if (token.startsWith("#")) {
- // Optional description must be last token in the line.
- description = token.substring(1);
- break;
- }
- if (token.startsWith("COMPACT")) {
- // has second template for Compact (16-bit) memory config -- added DPS 3 Aug 2009
- firstTemplate = template;
- template = "";
- continue;
- }
- template = template + token;
- if (tokenizer.hasMoreTokens()) {
- template = template + "\n";
- }
- }
- ExtendedInstruction inst = (firstTemplate == null)
- ? new ExtendedInstruction(pseudoOp, template, description)
- : new ExtendedInstruction(pseudoOp, firstTemplate, template, description);
- instructionList.add(inst);
- //if (firstTemplate != null) System.out.println("\npseudoOp: "+pseudoOp+"\ndefault template:\n"+firstTemplate+"\ncompact template:\n"+template);
- }
+ if (!line.startsWith("#") && !line.startsWith(" ")
+ && line.length() > 0)
+ {
+ description = "";
+ tokenizer = new StringTokenizer(line, "\t");
+ pseudoOp = tokenizer.nextToken();
+ template = "";
+ firstTemplate = null;
+ while (tokenizer.hasMoreTokens())
+ {
+ token = tokenizer.nextToken();
+ if (token.startsWith("#"))
+ {
+ // Optional description must be last token in the line.
+ description = token.substring(1);
+ break;
+ }
+ if (token.startsWith("COMPACT"))
+ {
+ // has second template for Compact (16-bit) memory config -- added DPS 3 Aug 2009
+ firstTemplate = template;
+ template = "";
+ continue;
+ }
+ template = template + token;
+ if (tokenizer.hasMoreTokens())
+ {
+ template = template + "\n";
+ }
+ }
+ ExtendedInstruction inst = (firstTemplate == null)
+ ? new ExtendedInstruction(pseudoOp, template, description)
+ : new ExtendedInstruction(pseudoOp, firstTemplate, template, description);
+ instructionList.add(inst);
+ //if (firstTemplate != null) System.out.println("\npseudoOp: "+pseudoOp+"\ndefault template:\n"+firstTemplate+"\ncompact template:\n"+template);
+ }
}
in.close();
- }
- catch (IOException ioe)
- {
- System.out.println(
- "Internal Error: MIPS pseudo-instructions could not be loaded.");
- System.exit(0);
- }
- catch (Exception ioe)
- {
- System.out.println(
- "Error: Invalid MIPS pseudo-instruction specification.");
- System.exit(0);
- }
-
- }
-
+ }
+ catch (IOException ioe)
+ {
+ System.out.println(
+ "Internal Error: MIPS pseudo-instructions could not be loaded.");
+ System.exit(0);
+ }
+ catch (Exception ioe)
+ {
+ System.out.println(
+ "Error: Invalid MIPS pseudo-instruction specification.");
+ System.exit(0);
+ }
+
+ }
+
/**
- * Given an operator mnemonic, will return the corresponding Instruction object(s)
- * from the instruction set. Uses straight linear search technique.
- * @param name operator mnemonic (e.g. addi, sw,...)
- * @return list of corresponding Instruction object(s), or null if not found.
+ * Given an operator mnemonic, will return the corresponding Instruction object(s) from the instruction set. Uses
+ * straight linear search technique.
+ *
+ * @param name operator mnemonic (e.g. addi, sw,...)
+ * @return list of corresponding Instruction object(s), or null if not found.
*/
- public ArrayList matchOperator(String name)
- {
- ArrayList matchingInstructions = null;
+ public ArrayList matchOperator(String name)
+ {
+ ArrayList matchingInstructions = null;
// Linear search for now....
- for (int i = 0; i < instructionList.size(); i++)
- {
+ for (int i = 0; i < instructionList.size(); i++)
+ {
if (((Instruction) instructionList.get(i)).getName().equalsIgnoreCase(name))
{
- if (matchingInstructions == null)
- matchingInstructions = new ArrayList();
- matchingInstructions.add(instructionList.get(i));
+ if (matchingInstructions == null)
+ {
+ matchingInstructions = new ArrayList();
+ }
+ matchingInstructions.add(instructionList.get(i));
}
- }
- return matchingInstructions;
- }
-
-
+ }
+ return matchingInstructions;
+ }
+
+
/**
- * Given a string, will return the Instruction object(s) from the instruction
- * set whose operator mnemonic prefix matches it. Case-insensitive. For example
- * "s" will match "sw", "sh", "sb", etc. Uses straight linear search technique.
- * @param name a string
- * @return list of matching Instruction object(s), or null if none match.
+ * Given a string, will return the Instruction object(s) from the instruction set whose operator mnemonic prefix
+ * matches it. Case-insensitive. For example "s" will match "sw", "sh", "sb", etc. Uses straight linear search
+ * technique.
+ *
+ * @param name a string
+ * @return list of matching Instruction object(s), or null if none match.
*/
- public ArrayList prefixMatchOperator(String name)
- {
- ArrayList matchingInstructions = null;
+ public ArrayList prefixMatchOperator(String name)
+ {
+ ArrayList matchingInstructions = null;
// Linear search for now....
- if (name != null) {
+ if (name != null)
+ {
for (int i = 0; i < instructionList.size(); i++)
{
- if (((Instruction) instructionList.get(i)).getName().toLowerCase().startsWith(name.toLowerCase()))
- {
- if (matchingInstructions == null)
- matchingInstructions = new ArrayList();
- matchingInstructions.add(instructionList.get(i));
- }
+ if (((Instruction) instructionList.get(i)).getName().toLowerCase().startsWith(name.toLowerCase()))
+ {
+ if (matchingInstructions == null)
+ {
+ matchingInstructions = new ArrayList();
+ }
+ matchingInstructions.add(instructionList.get(i));
+ }
}
- }
- return matchingInstructions;
- }
-
- /*
- * Method to find and invoke a syscall given its service number. Each syscall
- * function is represented by an object in an array list. Each object is of
- * a class that implements Syscall or extends AbstractSyscall.
- */
-
- private void findAndSimulateSyscall(int number, ProgramStatement statement)
- throws ProcessingException {
- Syscall service = syscallLoader.findSyscall(number);
- if (service != null) {
+ }
+ return matchingInstructions;
+ }
+
+ /*
+ * Method to find and invoke a syscall given its service number. Each syscall
+ * function is represented by an object in an array list. Each object is of
+ * a class that implements Syscall or extends AbstractSyscall.
+ */
+
+ private void findAndSimulateSyscall(int number, ProgramStatement statement)
+ throws ProcessingException
+ {
+ Syscall service = syscallLoader.findSyscall(number);
+ if (service != null)
+ {
service.simulate(statement);
return;
- }
- throw new ProcessingException(statement,
- "invalid or unimplemented syscall service: " +
- number + " ", Exceptions.SYSCALL_EXCEPTION);
- }
-
- /*
- * Method to process a successful branch condition. DO NOT USE WITH JUMP
- * INSTRUCTIONS! The branch operand is a relative displacement in words
- * whereas the jump operand is an absolute address in bytes.
- *
- * The parameter is displacement operand from instruction.
- *
- * Handles delayed branching if that setting is enabled.
- */
- // 4 January 2008 DPS: The subtraction of 4 bytes (instruction length) after
- // the shift has been removed. It is left in as commented-out code below.
- // This has the effect of always branching as if delayed branching is enabled,
- // even if it isn't. This mod must work in conjunction with
- // ProgramStatement.java, buildBasicStatementFromBasicInstruction() method near
- // the bottom (currently line 194, heavily commented).
-
- private void processBranch(int displacement) {
- if (Globals.getSettings().getDelayedBranchingEnabled()) {
+ }
+ throw new ProcessingException(statement,
+ "invalid or unimplemented syscall service: " +
+ number + " ", Exceptions.SYSCALL_EXCEPTION);
+ }
+
+ /*
+ * Method to process a successful branch condition. DO NOT USE WITH JUMP
+ * INSTRUCTIONS! The branch operand is a relative displacement in words
+ * whereas the jump operand is an absolute address in bytes.
+ *
+ * The parameter is displacement operand from instruction.
+ *
+ * Handles delayed branching if that setting is enabled.
+ */
+ // 4 January 2008 DPS: The subtraction of 4 bytes (instruction length) after
+ // the shift has been removed. It is left in as commented-out code below.
+ // This has the effect of always branching as if delayed branching is enabled,
+ // even if it isn't. This mod must work in conjunction with
+ // ProgramStatement.java, buildBasicStatementFromBasicInstruction() method near
+ // the bottom (currently line 194, heavily commented).
+
+ private void processBranch(int displacement)
+ {
+ if (Globals.getSettings().getDelayedBranchingEnabled())
+ {
// Register the branch target address (absolute byte address).
DelayedBranch.register(RegisterFile.getProgramCounter() + (displacement << 2));
- }
- else {
+ }
+ else
+ {
// Decrement needed because PC has already been incremented
RegisterFile.setProgramCounter(
RegisterFile.getProgramCounter()
- + (displacement << 2)); // - Instruction.INSTRUCTION_LENGTH);
- }
- }
-
- /*
- * Method to process a jump. DO NOT USE WITH BRANCH INSTRUCTIONS!
- * The branch operand is a relative displacement in words
- * whereas the jump operand is an absolute address in bytes.
- *
- * The parameter is jump target absolute byte address.
- *
- * Handles delayed branching if that setting is enabled.
- */
-
- private void processJump(int targetAddress) {
- if (Globals.getSettings().getDelayedBranchingEnabled()) {
+ + (displacement << 2)); // - Instruction.INSTRUCTION_LENGTH);
+ }
+ }
+
+ /*
+ * Method to process a jump. DO NOT USE WITH BRANCH INSTRUCTIONS!
+ * The branch operand is a relative displacement in words
+ * whereas the jump operand is an absolute address in bytes.
+ *
+ * The parameter is jump target absolute byte address.
+ *
+ * Handles delayed branching if that setting is enabled.
+ */
+
+ private void processJump(int targetAddress)
+ {
+ if (Globals.getSettings().getDelayedBranchingEnabled())
+ {
DelayedBranch.register(targetAddress);
- }
- else {
+ }
+ else
+ {
RegisterFile.setProgramCounter(targetAddress);
- }
- }
-
- /*
- * Method to process storing of a return address in the given
- * register. This is used only by the "and link"
- * instructions: jal, jalr, bltzal, bgezal. If delayed branching
- * setting is off, the return address is the address of the
- * next instruction (e.g. the current PC value). If on, the
- * return address is the instruction following that, to skip over
- * the delay slot.
- *
- * The parameter is register number to receive the return address.
- */
-
- private void processReturnAddress(int register) {
- RegisterFile.updateRegister(register, RegisterFile.getProgramCounter() +
- ((Globals.getSettings().getDelayedBranchingEnabled()) ?
- Instruction.INSTRUCTION_LENGTH : 0) );
- }
+ }
+ }
- private static class MatchMap implements Comparable {
- private int mask;
- private int maskLength; // number of 1 bits in mask
- private HashMap matchMap;
+ /*
+ * Method to process storing of a return address in the given
+ * register. This is used only by the "and link"
+ * instructions: jal, jalr, bltzal, bgezal. If delayed branching
+ * setting is off, the return address is the address of the
+ * next instruction (e.g. the current PC value). If on, the
+ * return address is the instruction following that, to skip over
+ * the delay slot.
+ *
+ * The parameter is register number to receive the return address.
+ */
- public MatchMap(int mask, HashMap matchMap) {
- this.mask = mask;
- this.matchMap = matchMap;
+ private void processReturnAddress(int register)
+ {
+ RegisterFile.updateRegister(register, RegisterFile.getProgramCounter() +
+ ((Globals.getSettings().getDelayedBranchingEnabled()) ?
+ Instruction.INSTRUCTION_LENGTH : 0));
+ }
- int k = 0;
- int n = mask;
- while (n != 0) {
- k++;
- n &= n - 1;
- }
- this.maskLength = k;
- }
+ private static class MatchMap implements Comparable
+ {
+ private final int mask;
- public boolean equals(Object o) {
- return o instanceof MatchMap && mask == ((MatchMap) o).mask;
- }
+ private final int maskLength; // number of 1 bits in mask
- public int compareTo(Object other) {
- MatchMap o = (MatchMap) other;
- int d = o.maskLength - this.maskLength;
- if (d == 0) d = this.mask - o.mask;
- return d;
- }
+ private final HashMap matchMap;
- public BasicInstruction find(int instr) {
- int match = Integer.valueOf(instr & mask);
- return (BasicInstruction) matchMap.get(match);
- }
- }
- }
+ public MatchMap(int mask, HashMap matchMap)
+ {
+ this.mask = mask;
+ this.matchMap = matchMap;
+
+ int k = 0;
+ int n = mask;
+ while (n != 0)
+ {
+ k++;
+ n &= n - 1;
+ }
+ this.maskLength = k;
+ }
+
+ public boolean equals(Object o)
+ {
+ return o instanceof MatchMap && mask == ((MatchMap) o).mask;
+ }
+
+ public int compareTo(Object other)
+ {
+ MatchMap o = (MatchMap) other;
+ int d = o.maskLength - this.maskLength;
+ if (d == 0)
+ {
+ d = this.mask - o.mask;
+ }
+ return d;
+ }
+
+ public BasicInstruction find(int instr)
+ {
+ int match = Integer.valueOf(instr & mask);
+ return (BasicInstruction) matchMap.get(match);
+ }
+ }
+}
diff --git a/src/main/java/mars/mips/instructions/SimulationCode.java b/src/main/java/mars/mips/instructions/SimulationCode.java
index 9e2646c..4be4644 100644
--- a/src/main/java/mars/mips/instructions/SimulationCode.java
+++ b/src/main/java/mars/mips/instructions/SimulationCode.java
@@ -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;
}
diff --git a/src/main/java/mars/mips/instructions/SyscallLoader.java b/src/main/java/mars/mips/instructions/SyscallLoader.java
index e9d30f4..a6e7b3d 100644
--- a/src/main/java/mars/mips/instructions/SyscallLoader.java
+++ b/src/main/java/mars/mips/instructions/SyscallLoader.java
@@ -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;
+ }
+}
diff --git a/src/main/java/mars/mips/instructions/syscalls/AbstractSyscall.java b/src/main/java/mars/mips/instructions/syscalls/AbstractSyscall.java
index 9090e8e..52c739c 100644
--- a/src/main/java/mars/mips/instructions/syscalls/AbstractSyscall.java
+++ b/src/main/java/mars/mips/instructions/syscalls/AbstractSyscall.java
@@ -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;
- }
\ No newline at end of file
+
+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;
+}
diff --git a/src/main/java/mars/mips/instructions/syscalls/RandomStreams.java b/src/main/java/mars/mips/instructions/syscalls/RandomStreams.java
index a127081..a9dbab6 100644
--- a/src/main/java/mars/mips/instructions/syscalls/RandomStreams.java
+++ b/src/main/java/mars/mips/instructions/syscalls/RandomStreams.java
@@ -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();
- }
\ No newline at end of file
+
+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();
+}
diff --git a/src/main/java/mars/mips/instructions/syscalls/Syscall.java b/src/main/java/mars/mips/instructions/syscalls/Syscall.java
index b8beaab..aba8cb8 100644
--- a/src/main/java/mars/mips/instructions/syscalls/Syscall.java
+++ b/src/main/java/mars/mips/instructions/syscalls/Syscall.java
@@ -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;
- }
\ No newline at end of file
+
+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;
+}
diff --git a/src/main/java/mars/mips/instructions/syscalls/SyscallClose.java b/src/main/java/mars/mips/instructions/syscalls/SyscallClose.java
index f751f12..20b4d17 100644
--- a/src/main/java/mars/mips/instructions/syscalls/SyscallClose.java
+++ b/src/main/java/mars/mips/instructions/syscalls/SyscallClose.java
@@ -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));
- }
- }
\ No newline at end of file
+
+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));
+ }
+}
diff --git a/src/main/java/mars/mips/instructions/syscalls/SyscallConfirmDialog.java b/src/main/java/mars/mips/instructions/syscalls/SyscallConfirmDialog.java
index ef615b1..b670e91 100644
--- a/src/main/java/mars/mips/instructions/syscalls/SyscallConfirmDialog.java
+++ b/src/main/java/mars/mips/instructions/syscalls/SyscallConfirmDialog.java
@@ -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));
- }
+ }
- }
+}
diff --git a/src/main/java/mars/mips/instructions/syscalls/SyscallExit.java b/src/main/java/mars/mips/instructions/syscalls/SyscallExit.java
index 2f50240..761b549 100644
--- a/src/main/java/mars/mips/instructions/syscalls/SyscallExit.java
+++ b/src/main/java/mars/mips/instructions/syscalls/SyscallExit.java
@@ -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.
- }
- }
\ No newline at end of file
+
+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.
+ }
+}
diff --git a/src/main/java/mars/mips/instructions/syscalls/SyscallExit2.java b/src/main/java/mars/mips/instructions/syscalls/SyscallExit2.java
index caa684c..57a2086 100644
--- a/src/main/java/mars/mips/instructions/syscalls/SyscallExit2.java
+++ b/src/main/java/mars/mips/instructions/syscalls/SyscallExit2.java
@@ -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
- }
- }
\ No newline at end of file
+ }
+ throw new ProcessingException(); // empty error list
+ }
+}
diff --git a/src/main/java/mars/mips/instructions/syscalls/SyscallInputDialogDouble.java b/src/main/java/mars/mips/instructions/syscalls/SyscallInputDialogDouble.java
index 1ab950e..4b267ea 100644
--- a/src/main/java/mars/mips/instructions/syscalls/SyscallInputDialogDouble.java
+++ b/src/main/java/mars/mips/instructions/syscalls/SyscallInputDialogDouble.java
@@ -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);
*/
- }
+ }
- }
+ }
- }
+}
diff --git a/src/main/java/mars/mips/instructions/syscalls/SyscallInputDialogFloat.java b/src/main/java/mars/mips/instructions/syscalls/SyscallInputDialogFloat.java
index 8904605..f68e575 100644
--- a/src/main/java/mars/mips/instructions/syscalls/SyscallInputDialogFloat.java
+++ b/src/main/java/mars/mips/instructions/syscalls/SyscallInputDialogFloat.java
@@ -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);
*/
- }
+ }
- }
+ }
- }
+}
diff --git a/src/main/java/mars/mips/instructions/syscalls/SyscallInputDialogInt.java b/src/main/java/mars/mips/instructions/syscalls/SyscallInputDialogInt.java
index 605d149..f7a1490 100644
--- a/src/main/java/mars/mips/instructions/syscalls/SyscallInputDialogInt.java
+++ b/src/main/java/mars/mips/instructions/syscalls/SyscallInputDialogInt.java
@@ -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
+ }
- }
-
- }
+}
diff --git a/src/main/java/mars/mips/instructions/syscalls/SyscallInputDialogString.java b/src/main/java/mars/mips/instructions/syscalls/SyscallInputDialogString.java
index 566ef63..6f287d7 100644
--- a/src/main/java/mars/mips/instructions/syscalls/SyscallInputDialogString.java
+++ b/src/main/java/mars/mips/instructions/syscalls/SyscallInputDialogString.java
@@ -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);
+ }
+
+
+ }
+
+}
diff --git a/src/main/java/mars/mips/instructions/syscalls/SyscallMessageDialog.java b/src/main/java/mars/mips/instructions/syscalls/SyscallMessageDialog.java
index e93e203..8deb804 100644
--- a/src/main/java/mars/mips/instructions/syscalls/SyscallMessageDialog.java
+++ b/src/main/java/mars/mips/instructions/syscalls/SyscallMessageDialog.java
@@ -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);
- }
- }
+ }
+
+}
diff --git a/src/main/java/mars/mips/instructions/syscalls/SyscallMessageDialogDouble.java b/src/main/java/mars/mips/instructions/syscalls/SyscallMessageDialogDouble.java
index 8f30655..9c06159 100644
--- a/src/main/java/mars/mips/instructions/syscalls/SyscallMessageDialogDouble.java
+++ b/src/main/java/mars/mips/instructions/syscalls/SyscallMessageDialogDouble.java
@@ -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);
+ }
- }
+ }
+
+}
diff --git a/src/main/java/mars/mips/instructions/syscalls/SyscallMessageDialogFloat.java b/src/main/java/mars/mips/instructions/syscalls/SyscallMessageDialogFloat.java
index 68ea05c..7cf0353 100644
--- a/src/main/java/mars/mips/instructions/syscalls/SyscallMessageDialogFloat.java
+++ b/src/main/java/mars/mips/instructions/syscalls/SyscallMessageDialogFloat.java
@@ -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);
- }
- }
+ }
+
+}
diff --git a/src/main/java/mars/mips/instructions/syscalls/SyscallMessageDialogInt.java b/src/main/java/mars/mips/instructions/syscalls/SyscallMessageDialogInt.java
index 9159448..e504e14 100644
--- a/src/main/java/mars/mips/instructions/syscalls/SyscallMessageDialogInt.java
+++ b/src/main/java/mars/mips/instructions/syscalls/SyscallMessageDialogInt.java
@@ -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);
- }
- }
+ }
+
+}
diff --git a/src/main/java/mars/mips/instructions/syscalls/SyscallMessageDialogString.java b/src/main/java/mars/mips/instructions/syscalls/SyscallMessageDialogString.java
index 5262126..51429f2 100644
--- a/src/main/java/mars/mips/instructions/syscalls/SyscallMessageDialogString.java
+++ b/src/main/java/mars/mips/instructions/syscalls/SyscallMessageDialogString.java
@@ -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);
- }
- }
+ }
+
+}
diff --git a/src/main/java/mars/mips/instructions/syscalls/SyscallMidiOut.java b/src/main/java/mars/mips/instructions/syscalls/SyscallMidiOut.java
index 8d01f3e..9b2b7fb 100644
--- a/src/main/java/mars/mips/instructions/syscalls/SyscallMidiOut.java
+++ b/src/main/java/mars/mips/instructions/syscalls/SyscallMidiOut.java
@@ -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.
- * $a0 - pitch (note). Integer value from 0 to 127, with 60 being middle-C on a piano.
- * $a1 - duration. Integer value in milliseconds.
- * $a2 - instrument. Integer value from 0 to 127, with 0 being acoustic grand piano.
- * $a3 - volume. Integer value from 0 to 127.
- * Default values, in case any parameters are outside the above ranges, are $a0=60, $a1=1000,
- * $a2=0, $a3=100.
- * 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.
$a0 - pitch (note). Integer value from 0 to 127, with 60 being middle-C on a piano.
$a1 -
+ * duration. Integer value in milliseconds.
$a2 - instrument. Integer value from 0 to 127, with 0 being
+ * acoustic grand piano.
$a3 - volume. Integer value from 0 to 127.
Default values, in case any parameters
+ * are outside the above ranges, are $a0=60, $a1=1000, $a2=0, $a3=100.
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);
+ }
+
+}
diff --git a/src/main/java/mars/mips/instructions/syscalls/SyscallMidiOutSync.java b/src/main/java/mars/mips/instructions/syscalls/SyscallMidiOutSync.java
index 28d350b..5ea4907 100644
--- a/src/main/java/mars/mips/instructions/syscalls/SyscallMidiOutSync.java
+++ b/src/main/java/mars/mips/instructions/syscalls/SyscallMidiOutSync.java
@@ -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.
- * $a0 - pitch (note). Integer value from 0 to 127, with 60 being middle-C on a piano.
- * $a1 - duration. Integer value in milliseconds.
- * $a2 - instrument. Integer value from 0 to 127, with 0 being acoustic grand piano.
- * $a3 - volume. Integer value from 0 to 127.
- * Default values, in case any parameters are outside the above ranges, are $a0=60, $a1=1000,
- * $a2=0, $a3=100.
- * 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.
$a0 - pitch
+ * (note). Integer value from 0 to 127, with 60 being middle-C on a piano.
$a1 - duration. Integer value in
+ * milliseconds.
$a2 - instrument. Integer value from 0 to 127, with 0 being acoustic grand piano.
$a3 -
+ * volume. Integer value from 0 to 127.
Default values, in case any parameters are outside the above ranges,
+ * are $a0=60, $a1=1000, $a2=0, $a3=100.
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);
+ }
+
+}
diff --git a/src/main/java/mars/mips/instructions/syscalls/SyscallNumberOverride.java b/src/main/java/mars/mips/instructions/syscalls/SyscallNumberOverride.java
index 8a13ad8..d34a539 100644
--- a/src/main/java/mars/mips/instructions/syscalls/SyscallNumberOverride.java
+++ b/src/main/java/mars/mips/instructions/syscalls/SyscallNumberOverride.java
@@ -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;
+ }
+
+}
diff --git a/src/main/java/mars/mips/instructions/syscalls/SyscallOpen.java b/src/main/java/mars/mips/instructions/syscalls/SyscallOpen.java
index febafec..24fe5c3 100644
--- a/src/main/java/mars/mips/instructions/syscalls/SyscallOpen.java
+++ b/src/main/java/mars/mips/instructions/syscalls/SyscallOpen.java
@@ -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);
}
*/
- }
- }
\ No newline at end of file
+ }
+}
diff --git a/src/main/java/mars/mips/instructions/syscalls/SyscallPrintChar.java b/src/main/java/mars/mips/instructions/syscalls/SyscallPrintChar.java
index 5420a51..ceb4e97 100644
--- a/src/main/java/mars/mips/instructions/syscalls/SyscallPrintChar.java
+++ b/src/main/java/mars/mips/instructions/syscalls/SyscallPrintChar.java
@@ -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());
- }
-
- }
\ No newline at end of file
+
+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));
+ }
+
+}
diff --git a/src/main/java/mars/mips/instructions/syscalls/SyscallPrintDouble.java b/src/main/java/mars/mips/instructions/syscalls/SyscallPrintDouble.java
index 144c73f..931ebc4 100644
--- a/src/main/java/mars/mips/instructions/syscalls/SyscallPrintDouble.java
+++ b/src/main/java/mars/mips/instructions/syscalls/SyscallPrintDouble.java
@@ -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());
- }
- }
\ No newline at end of file
+
+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))
+ )));
+ }
+}
diff --git a/src/main/java/mars/mips/instructions/syscalls/SyscallPrintFloat.java b/src/main/java/mars/mips/instructions/syscalls/SyscallPrintFloat.java
index 3c527bb..f347860 100644
--- a/src/main/java/mars/mips/instructions/syscalls/SyscallPrintFloat.java
+++ b/src/main/java/mars/mips/instructions/syscalls/SyscallPrintFloat.java
@@ -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))));
}
}
diff --git a/src/main/java/mars/mips/instructions/syscalls/SyscallPrintInt.java b/src/main/java/mars/mips/instructions/syscalls/SyscallPrintInt.java
index 58a34b2..93a2a20 100644
--- a/src/main/java/mars/mips/instructions/syscalls/SyscallPrintInt.java
+++ b/src/main/java/mars/mips/instructions/syscalls/SyscallPrintInt.java
@@ -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)));
+ }
+}
diff --git a/src/main/java/mars/mips/instructions/syscalls/SyscallPrintIntBinary.java b/src/main/java/mars/mips/instructions/syscalls/SyscallPrintIntBinary.java
index b28dc4e..a00cec9 100644
--- a/src/main/java/mars/mips/instructions/syscalls/SyscallPrintIntBinary.java
+++ b/src/main/java/mars/mips/instructions/syscalls/SyscallPrintIntBinary.java
@@ -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)));
- }
- }
\ No newline at end of file
+
+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)));
+ }
+}
diff --git a/src/main/java/mars/mips/instructions/syscalls/SyscallPrintIntHex.java b/src/main/java/mars/mips/instructions/syscalls/SyscallPrintIntHex.java
index d738b18..c5033fc 100644
--- a/src/main/java/mars/mips/instructions/syscalls/SyscallPrintIntHex.java
+++ b/src/main/java/mars/mips/instructions/syscalls/SyscallPrintIntHex.java
@@ -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)));
- }
- }
\ No newline at end of file
+
+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)));
+ }
+}
diff --git a/src/main/java/mars/mips/instructions/syscalls/SyscallPrintIntUnsigned.java b/src/main/java/mars/mips/instructions/syscalls/SyscallPrintIntUnsigned.java
index f26d4cd..7ee2fa2 100644
--- a/src/main/java/mars/mips/instructions/syscalls/SyscallPrintIntUnsigned.java
+++ b/src/main/java/mars/mips/instructions/syscalls/SyscallPrintIntUnsigned.java
@@ -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)));
- }
- }
\ No newline at end of file
+
+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)));
+ }
+}
diff --git a/src/main/java/mars/mips/instructions/syscalls/SyscallPrintString.java b/src/main/java/mars/mips/instructions/syscalls/SyscallPrintString.java
index 076377c..f625ed3 100644
--- a/src/main/java/mars/mips/instructions/syscalls/SyscallPrintString.java
+++ b/src/main/java/mars/mips/instructions/syscalls/SyscallPrintString.java
@@ -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);
- }
- }
- }
\ No newline at end of file
+ }
+ catch (AddressErrorException e)
+ {
+ throw new ProcessingException(statement, e);
+ }
+ }
+}
diff --git a/src/main/java/mars/mips/instructions/syscalls/SyscallRandDouble.java b/src/main/java/mars/mips/instructions/syscalls/SyscallRandDouble.java
index f2e144c..627c632 100644
--- a/src/main/java/mars/mips/instructions/syscalls/SyscallRandDouble.java
+++ b/src/main/java/mars/mips/instructions/syscalls/SyscallRandDouble.java
@@ -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);
+ }
+ }
+
+}
diff --git a/src/main/java/mars/mips/instructions/syscalls/SyscallRandFloat.java b/src/main/java/mars/mips/instructions/syscalls/SyscallRandFloat.java
index d8d28a4..b0f7100 100644
--- a/src/main/java/mars/mips/instructions/syscalls/SyscallRandFloat.java
+++ b/src/main/java/mars/mips/instructions/syscalls/SyscallRandFloat.java
@@ -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( ));
- }
- }
\ No newline at end of file
+ }
+ Coprocessor1.setRegisterToFloat(0, stream.nextFloat());
+ }
+}
diff --git a/src/main/java/mars/mips/instructions/syscalls/SyscallRandInt.java b/src/main/java/mars/mips/instructions/syscalls/SyscallRandInt.java
index 6a7c6b9..a23bda1 100644
--- a/src/main/java/mars/mips/instructions/syscalls/SyscallRandInt.java
+++ b/src/main/java/mars/mips/instructions/syscalls/SyscallRandInt.java
@@ -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());
+ }
+
+}
diff --git a/src/main/java/mars/mips/instructions/syscalls/SyscallRandIntRange.java b/src/main/java/mars/mips/instructions/syscalls/SyscallRandIntRange.java
index 5b89816..3f2c494 100644
--- a/src/main/java/mars/mips/instructions/syscalls/SyscallRandIntRange.java
+++ b/src/main/java/mars/mips/instructions/syscalls/SyscallRandIntRange.java
@@ -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);
+ }
+ }
+
+}
diff --git a/src/main/java/mars/mips/instructions/syscalls/SyscallRandSeed.java b/src/main/java/mars/mips/instructions/syscalls/SyscallRandSeed.java
index 2fc7673..f6ad849 100644
--- a/src/main/java/mars/mips/instructions/syscalls/SyscallRandSeed.java
+++ b/src/main/java/mars/mips/instructions/syscalls/SyscallRandSeed.java
@@ -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));
+ }
+ }
+
+}
diff --git a/src/main/java/mars/mips/instructions/syscalls/SyscallRead.java b/src/main/java/mars/mips/instructions/syscalls/SyscallRead.java
index 837fc43..78aa359 100644
--- a/src/main/java/mars/mips/instructions/syscalls/SyscallRead.java
+++ b/src/main/java/mars/mips/instructions/syscalls/SyscallRead.java
@@ -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);
- }
- }
- }
\ No newline at end of file
+ }
+ catch (AddressErrorException e)
+ {
+ throw new ProcessingException(statement, e);
+ }
+ }
+}
diff --git a/src/main/java/mars/mips/instructions/syscalls/SyscallReadChar.java b/src/main/java/mars/mips/instructions/syscalls/SyscallReadChar.java
index b8b1281..41b265c 100644
--- a/src/main/java/mars/mips/instructions/syscalls/SyscallReadChar.java
+++ b/src/main/java/mars/mips/instructions/syscalls/SyscallReadChar.java
@@ -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);
- }
-
- }
\ No newline at end of file
+ }
+ 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);
+ }
+
+}
diff --git a/src/main/java/mars/mips/instructions/syscalls/SyscallReadDouble.java b/src/main/java/mars/mips/instructions/syscalls/SyscallReadDouble.java
index 6af57aa..fc9e6d3 100644
--- a/src/main/java/mars/mips/instructions/syscalls/SyscallReadDouble.java
+++ b/src/main/java/mars/mips/instructions/syscalls/SyscallReadDouble.java
@@ -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));
- }
- }
\ No newline at end of file
+ }
+ 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));
+ }
+}
diff --git a/src/main/java/mars/mips/instructions/syscalls/SyscallReadFloat.java b/src/main/java/mars/mips/instructions/syscalls/SyscallReadFloat.java
index d7cc0a0..f4a83ef 100644
--- a/src/main/java/mars/mips/instructions/syscalls/SyscallReadFloat.java
+++ b/src/main/java/mars/mips/instructions/syscalls/SyscallReadFloat.java
@@ -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));
- }
- }
\ No newline at end of file
+ }
+ catch (NumberFormatException e)
+ {
+ throw new ProcessingException(statement,
+ "invalid float input (syscall " + this.getNumber() + ")",
+ Exceptions.SYSCALL_EXCEPTION);
+ }
+ Coprocessor1.updateRegister(0, Float.floatToRawIntBits(floatValue));
+ }
+}
diff --git a/src/main/java/mars/mips/instructions/syscalls/SyscallReadInt.java b/src/main/java/mars/mips/instructions/syscalls/SyscallReadInt.java
index cebdef3..2bf0c54 100644
--- a/src/main/java/mars/mips/instructions/syscalls/SyscallReadInt.java
+++ b/src/main/java/mars/mips/instructions/syscalls/SyscallReadInt.java
@@ -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);
- }
-
- }
\ No newline at end of file
+ }
+ catch (NumberFormatException e)
+ {
+ throw new ProcessingException(statement,
+ "invalid integer input (syscall " + this.getNumber() + ")",
+ Exceptions.SYSCALL_EXCEPTION);
+ }
+ RegisterFile.updateRegister(2, value);
+ }
+
+}
diff --git a/src/main/java/mars/mips/instructions/syscalls/SyscallReadString.java b/src/main/java/mars/mips/instructions/syscalls/SyscallReadString.java
index 0c7e773..2e63b45 100644
--- a/src/main/java/mars/mips/instructions/syscalls/SyscallReadString.java
+++ b/src/main/java/mars/mips/instructions/syscalls/SyscallReadString.java
@@ -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);
}
- }
- }
\ No newline at end of file
+ }
+ catch (AddressErrorException e)
+ {
+ throw new ProcessingException(statement, e);
+ }
+ }
+}
diff --git a/src/main/java/mars/mips/instructions/syscalls/SyscallSbrk.java b/src/main/java/mars/mips/instructions/syscalls/SyscallSbrk.java
index 6152f66..a70020a 100644
--- a/src/main/java/mars/mips/instructions/syscalls/SyscallSbrk.java
+++ b/src/main/java/mars/mips/instructions/syscalls/SyscallSbrk.java
@@ -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);
- }
- }
\ No newline at end of file
+ }
+ catch (IllegalArgumentException iae)
+ {
+ throw new ProcessingException(statement,
+ iae.getMessage() + " (syscall " + this.getNumber() + ")",
+ Exceptions.SYSCALL_EXCEPTION);
+ }
+ RegisterFile.updateRegister(2, address);
+ }
+}
diff --git a/src/main/java/mars/mips/instructions/syscalls/SyscallSleep.java b/src/main/java/mars/mips/instructions/syscalls/SyscallSleep.java
index 2bc832f..49874b2 100644
--- a/src/main/java/mars/mips/instructions/syscalls/SyscallSleep.java
+++ b/src/main/java/mars/mips/instructions/syscalls/SyscallSleep.java
@@ -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
+ }
+ }
- }
+}
diff --git a/src/main/java/mars/mips/instructions/syscalls/SyscallTime.java b/src/main/java/mars/mips/instructions/syscalls/SyscallTime.java
index 0f091dd..da486bc 100644
--- a/src/main/java/mars/mips/instructions/syscalls/SyscallTime.java
+++ b/src/main/java/mars/mips/instructions/syscalls/SyscallTime.java
@@ -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
- }
-
- }
\ No newline at end of file
+
+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
+ }
+
+}
diff --git a/src/main/java/mars/mips/instructions/syscalls/SyscallWrite.java b/src/main/java/mars/mips/instructions/syscalls/SyscallWrite.java
index 69e4519..f81a1ac 100644
--- a/src/main/java/mars/mips/instructions/syscalls/SyscallWrite.java
+++ b/src/main/java/mars/mips/instructions/syscalls/SyscallWrite.java
@@ -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());
}
*/
- }
- }
\ No newline at end of file
+ }
+}
diff --git a/src/main/java/mars/mips/instructions/syscalls/ToneGenerator.java b/src/main/java/mars/mips/instructions/syscalls/ToneGenerator.java
index 75dcd69..93f4df3 100644
--- a/src/main/java/mars/mips/instructions/syscalls/ToneGenerator.java
+++ b/src/main/java/mars/mips/instructions/syscalls/ToneGenerator.java
@@ -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 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 general
- * MIDI instrument patch map 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 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 general
- * MIDI instrument patch map 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 general
- * MIDI instrument patch map 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 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 general MIDI instrument patch map 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 general MIDI instrument patch map 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 general MIDI instrument patch
+ * map 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 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 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 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();
+ }
+ }
}
diff --git a/src/main/java/mars/simulator/BackStepper.java b/src/main/java/mars/simulator/BackStepper.java
index c75756d..8104f07 100644
--- a/src/main/java/mars/simulator/BackStepper.java
+++ b/src/main/java/mars/simulator/BackStepper.java
@@ -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
+ * (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.
*
- * (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.
+ *
+ * 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:
+ }
+ }
+
+ /**
+ * 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
\ No newline at end of file
+ /**
+ * 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
diff --git a/src/main/java/mars/simulator/Exceptions.java b/src/main/java/mars/simulator/Exceptions.java
index f127a0e..4676508 100644
--- a/src/main/java/mars/simulator/Exceptions.java
+++ b/src/main/java/mars/simulator/Exceptions.java
@@ -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
\ No newline at end of file
+ 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
diff --git a/src/main/java/mars/simulator/ProgramArgumentList.java b/src/main/java/mars/simulator/ProgramArgumentList.java
index bf6126a..460498f 100644
--- a/src/main/java/mars/simulator/ProgramArgumentList.java
+++ b/src/main/java/mars/simulator/ProgramArgumentList.java
@@ -1,12 +1,14 @@
- package mars.simulator;
- import mars.*;
- import mars.venus.*;
- import mars.util.*;
- import mars.mips.hardware.*;
- import mars.mips.instructions.*;
- import java.util.*;
- import javax.swing.*;
- import java.awt.event.*;
+package mars.simulator;
+
+import mars.Globals;
+import mars.mips.hardware.AddressErrorException;
+import mars.mips.hardware.Memory;
+import mars.mips.hardware.Register;
+import mars.mips.hardware.RegisterFile;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.StringTokenizer;
/*
Copyright (c) 2003-2008, Pete Sanderson and Kenneth Vollmar
@@ -35,173 +37,185 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
(MIT license, http://www.opensource.org/licenses/mit-license.html)
*/
-
+
/**
- * Models Program Arguments, one or more strings provided to the MIPS
- * program at runtime. Equivalent to C's main(int argc, char **argv) or
- * Java's main(String[] args).
+ * Models Program Arguments, one or more strings provided to the MIPS program at runtime. Equivalent to C's main(int
+ * argc, char **argv) or Java's main(String[] args).
+ *
* @author Pete Sanderson
* @version July 2008
**/
- public class ProgramArgumentList {
-
- ArrayList programArgumentList;
-
+public class ProgramArgumentList
+{
+
+ ArrayList programArgumentList;
+
/**
- * Constructor that parses string to produce list. Delimiters
- * are the default Java StringTokenizer delimiters (space, tab,
- * newline, return, formfeed)
+ * Constructor that parses string to produce list. Delimiters are the default Java StringTokenizer delimiters
+ * (space, tab, newline, return, formfeed)
*
- * @param args String containing delimiter-separated arguments
+ * @param args String containing delimiter-separated arguments
*/
- public ProgramArgumentList(String args) {
- StringTokenizer st = new StringTokenizer(args);
- programArgumentList = new ArrayList(st.countTokens());
- while (st.hasMoreTokens()) {
+ public ProgramArgumentList(String args)
+ {
+ StringTokenizer st = new StringTokenizer(args);
+ programArgumentList = new ArrayList(st.countTokens());
+ while (st.hasMoreTokens())
+ {
programArgumentList.add(st.nextToken());
- }
- }
-
+ }
+ }
+
/**
- * Constructor that gets list from String array, one argument per element.
+ * Constructor that gets list from String array, one argument per element.
*
- * @param list Array of String, each element containing one argument
- */
- public ProgramArgumentList(String[] list) {
- this(list, 0);
- }
-
- /**
- * Constructor that gets list from section of String array, one
- * argument per element.
- *
- * @param args Array of String, each element containing one argument
- * @param startPosition Index of array element containing the first argument; all remaining
- * elements are assumed to contain an argument.
- */
- public ProgramArgumentList(String[] list, int startPosition) {
- programArgumentList = new ArrayList(list.length-startPosition);
- for (int i=startPosition; i= 0; j--) {
- Globals.memory.set(highAddress, programArgument.charAt(j), 1);
- highAddress--;
- }
- argStartAddress[i] = highAddress+1;
+ }
+ // Runtime stack initialization from stack top-down (each is 4 bytes) :
+ // programArgumentList.size()
+ // address of first character of first program argument
+ // address of first character of second program argument
+ // ....repeat for all program arguments
+ // 0x00000000 (null terminator for list of string pointers)
+ // $sp will be set to the address holding the arg list size
+ // $a0 will be set to the arg list size (argc)
+ // $a1 will be set to stack address just "below" arg list size (argv)
+ //
+ // Each of the arguments themselves will be stored starting at
+ // Memory.stackBaseAddress (0x7ffffffc) and working down from there:
+ // 0x7ffffffc will contain null terminator for first arg
+ // 0x7ffffffb will contain last character of first arg
+ // 0x7ffffffa will contain next-to-last character of first arg
+ // Etc down to first character of first arg.
+ // Previous address will contain null terminator for second arg
+ // Previous-to-that contains last character of second arg
+ // Etc down to first character of second arg.
+ // Follow this pattern for all remaining arguments.
+
+
+ int highAddress = Memory.stackBaseAddress; // highest non-kernel address, sits "under" stack
+ String programArgument;
+ int[] argStartAddress = new int[programArgumentList.size()];
+ try
+ { // needed for all memory writes
+ for (int i = 0; i < programArgumentList.size(); i++)
+ {
+ programArgument = (String) programArgumentList.get(i);
+ Globals.memory.set(highAddress, 0, 1); // trailing null byte for each argument
+ highAddress--;
+ for (int j = programArgument.length() - 1; j >= 0; j--)
+ {
+ Globals.memory.set(highAddress, programArgument.charAt(j), 1);
+ highAddress--;
+ }
+ argStartAddress[i] = highAddress + 1;
}
// now place a null word, the arg starting addresses, and arg count onto stack.
int stackAddress = Memory.stackPointer; // base address for runtime stack.
- if (highAddress < Memory.stackPointer) {
- // Based on current values for stackBaseAddress and stackPointer, this will
- // only happen if the combined lengths of program arguments is greater than
- // 0x7ffffffc - 0x7fffeffc = 0x00001000 = 4096 bytes. In this case, set
- // stackAddress to next lower word boundary minus 4 for clearance (since every
- // byte from highAddress+1 is filled).
- stackAddress = highAddress - (highAddress % Memory.WORD_LENGTH_BYTES) - Memory.WORD_LENGTH_BYTES;
+ if (highAddress < Memory.stackPointer)
+ {
+ // Based on current values for stackBaseAddress and stackPointer, this will
+ // only happen if the combined lengths of program arguments is greater than
+ // 0x7ffffffc - 0x7fffeffc = 0x00001000 = 4096 bytes. In this case, set
+ // stackAddress to next lower word boundary minus 4 for clearance (since every
+ // byte from highAddress+1 is filled).
+ stackAddress = highAddress - (highAddress % Memory.WORD_LENGTH_BYTES) - Memory.WORD_LENGTH_BYTES;
}
Globals.memory.set(stackAddress, 0, Memory.WORD_LENGTH_BYTES); // null word for end of argv array
stackAddress -= Memory.WORD_LENGTH_BYTES;
- for (int i=argStartAddress.length-1; i >= 0; i--) {
- Globals.memory.set(stackAddress, argStartAddress[i], Memory.WORD_LENGTH_BYTES);
- stackAddress -= Memory.WORD_LENGTH_BYTES;
+ for (int i = argStartAddress.length - 1; i >= 0; i--)
+ {
+ Globals.memory.set(stackAddress, argStartAddress[i], Memory.WORD_LENGTH_BYTES);
+ stackAddress -= Memory.WORD_LENGTH_BYTES;
}
Globals.memory.set(stackAddress, argStartAddress.length, Memory.WORD_LENGTH_BYTES); // argc
stackAddress -= Memory.WORD_LENGTH_BYTES;
-
+
// Need to set $sp register to stack address, $a0 to argc, $a1 to argv
- // Need to by-pass the backstepping mechanism so go directly to Register instead of RegisterFile
+ // Need to by-pass the backstepping mechanism so go directly to Register instead of RegisterFile
Register[] registers = RegisterFile.getRegisters();
- RegisterFile.getUserRegister("$sp").setValue(stackAddress+Memory.WORD_LENGTH_BYTES);
+ RegisterFile.getUserRegister("$sp").setValue(stackAddress + Memory.WORD_LENGTH_BYTES);
RegisterFile.getUserRegister("$a0").setValue(argStartAddress.length); // argc
- RegisterFile.getUserRegister("$a1").setValue(stackAddress+Memory.WORD_LENGTH_BYTES+Memory.WORD_LENGTH_BYTES); // argv
- //RegisterFile.updateRegister("$sp",stackAddress+Memory.WORD_LENGTH_BYTES);
- //RegisterFile.updateRegister("$a0",argStartAddress.length); // argc
- //RegisterFile.updateRegister("$a1",stackAddress+Memory.WORD_LENGTH_BYTES+Memory.WORD_LENGTH_BYTES); // argv
- }
- catch (AddressErrorException aee) {
- System.out.println("Internal Error: Memory write error occurred while storing program arguments! "+aee);
- System.exit(0);
- }
- return;
- }
-
-
-
- }
+ RegisterFile.getUserRegister("$a1").setValue(stackAddress + Memory.WORD_LENGTH_BYTES + Memory.WORD_LENGTH_BYTES); // argv
+ //RegisterFile.updateRegister("$sp",stackAddress+Memory.WORD_LENGTH_BYTES);
+ //RegisterFile.updateRegister("$a0",argStartAddress.length); // argc
+ //RegisterFile.updateRegister("$a1",stackAddress+Memory.WORD_LENGTH_BYTES+Memory.WORD_LENGTH_BYTES); // argv
+ }
+ catch (AddressErrorException aee)
+ {
+ System.out.println("Internal Error: Memory write error occurred while storing program arguments! " + aee);
+ System.exit(0);
+ }
+ }
+
+
+}
diff --git a/src/main/java/mars/simulator/Simulator.java b/src/main/java/mars/simulator/Simulator.java
index 9d5097b..e790912 100644
--- a/src/main/java/mars/simulator/Simulator.java
+++ b/src/main/java/mars/simulator/Simulator.java
@@ -1,12 +1,21 @@
- package mars.simulator;
- import mars.*;
- import mars.venus.*;
- import mars.util.*;
- import mars.mips.hardware.*;
- import mars.mips.instructions.*;
- import java.util.*;
- import javax.swing.*;
- import java.awt.event.*;
+package mars.simulator;
+
+import mars.*;
+import mars.mips.hardware.AddressErrorException;
+import mars.mips.hardware.Coprocessor0;
+import mars.mips.hardware.Memory;
+import mars.mips.hardware.RegisterFile;
+import mars.mips.instructions.BasicInstruction;
+import mars.util.Binary;
+import mars.util.SystemIO;
+import mars.venus.RunGoAction;
+import mars.venus.RunSpeedPanel;
+import mars.venus.RunStepAction;
+
+import javax.swing.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Observable;
/*
Copyright (c) 2003-2010, Pete Sanderson and Kenneth Vollmar
@@ -35,191 +44,227 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
(MIT license, http://www.opensource.org/licenses/mit-license.html)
*/
-
+
/**
* Used to simulate the execution of an assembled MIPS program.
+ *
* @author Pete Sanderson
* @version August 2005
**/
- public class Simulator extends Observable {
- private SimThread simulatorThread;
- private static Simulator simulator = null; // Singleton object
- private static Runnable interactiveGUIUpdater = null;
- // Others can set this true to indicate external interrupt. Initially used
- // to simulate keyboard and display interrupts. The device is identified
- // by the address of its MMIO control register. keyboard 0xFFFF0000 and
- // display 0xFFFF0008. DPS 23 July 2008.
- public static final int NO_DEVICE = 0;
- public static volatile int externalInterruptingDevice = NO_DEVICE;
- /** various reasons for simulate to end... */
- public static final int BREAKPOINT = 1;
- public static final int EXCEPTION = 2;
- public static final int MAX_STEPS = 3; // includes step mode (where maxSteps is 1)
- public static final int NORMAL_TERMINATION = 4;
- public static final int CLIFF_TERMINATION = 5; // run off bottom of program
- public static final int PAUSE_OR_STOP = 6;
-
- /**
- * Returns the Simulator object
- *
- * @return the Simulator object in use
- */
- public static Simulator getInstance() {
- // Do NOT change this to create the Simulator at load time (in declaration above)!
- // Its constructor looks for the GUI, which at load time is not created yet,
- // and incorrectly leaves interactiveGUIUpdater null! This causes runtime
- // exceptions while running in timed mode.
- if (simulator==null) {
- simulator = new Simulator();
- }
- return simulator;
- }
-
- private Simulator() {
- simulatorThread = null;
- if (Globals.getGui() != null) {
+public class Simulator extends Observable
+{
+ // Others can set this true to indicate external interrupt. Initially used
+ // to simulate keyboard and display interrupts. The device is identified
+ // by the address of its MMIO control register. keyboard 0xFFFF0000 and
+ // display 0xFFFF0008. DPS 23 July 2008.
+ public static final int NO_DEVICE = 0;
+
+ /** various reasons for simulate to end... */
+ public static final int BREAKPOINT = 1;
+
+ public static final int EXCEPTION = 2;
+
+ public static final int MAX_STEPS = 3; // includes step mode (where maxSteps is 1)
+
+ public static final int NORMAL_TERMINATION = 4;
+
+ public static final int CLIFF_TERMINATION = 5; // run off bottom of program
+
+ public static final int PAUSE_OR_STOP = 6;
+
+ public static volatile int externalInterruptingDevice = NO_DEVICE;
+
+ private static Simulator simulator = null; // Singleton object
+
+ private static Runnable interactiveGUIUpdater = null;
+
+ private SimThread simulatorThread;
+
+ private final ArrayList stopListeners = new ArrayList(1);
+
+ private Simulator()
+ {
+ simulatorThread = null;
+ if (Globals.getGui() != null)
+ {
interactiveGUIUpdater = new UpdateGUI();
- }
- }
-
-
-
- /**
- * Determine whether or not the next instruction to be executed is in a
- * "delay slot". This means delayed branching is enabled, the branch
- * condition has evaluated true, and the next instruction executed will
- * be the one following the branch. It is said to occupy the "delay slot."
- * Normally programmers put a nop instruction here but it can be anything.
- *
- * @return true if next instruction is in delay slot, false otherwise.
- */
-
- public static boolean inDelaySlot() {
- return DelayedBranch.isTriggered();
- }
-
-
- /**
- * Simulate execution of given MIPS program. It must have already been assembled.
- * @param p The MIPSprogram to be simulated.
- * @param pc address of first instruction to simulate; this goes into program counter
- * @param maxSteps maximum number of steps to perform before returning false (0 or less means no max)
- * @param breakPoints array of breakpoint program counter values, use null if none
- * @param actor the GUI component responsible for this call, usually GO or STEP. null if none.
- * @return true if execution completed, false otherwise
- * @throws ProcessingException Throws exception if run-time exception occurs.
- **/
-
- public boolean simulate(MIPSprogram p, int pc, int maxSteps, int[] breakPoints, AbstractAction actor) throws ProcessingException {
- simulatorThread = new SimThread(p,pc,maxSteps,breakPoints,actor);
- simulatorThread.start();
-
- // Condition should only be true if run from command-line instead of GUI.
- // If so, just stick around until execution thread is finished.
- if (actor == null) {
+ }
+ }
+
+ /**
+ * Returns the Simulator object
+ *
+ * @return the Simulator object in use
+ */
+ public static Simulator getInstance()
+ {
+ // Do NOT change this to create the Simulator at load time (in declaration above)!
+ // Its constructor looks for the GUI, which at load time is not created yet,
+ // and incorrectly leaves interactiveGUIUpdater null! This causes runtime
+ // exceptions while running in timed mode.
+ if (simulator == null)
+ {
+ simulator = new Simulator();
+ }
+ return simulator;
+ }
+
+ /**
+ * Determine whether or not the next instruction to be executed is in a "delay slot". This means delayed branching
+ * is enabled, the branch condition has evaluated true, and the next instruction executed will be the one following
+ * the branch. It is said to occupy the "delay slot." Normally programmers put a nop instruction here but it can be
+ * anything.
+ *
+ * @return true if next instruction is in delay slot, false otherwise.
+ */
+
+ public static boolean inDelaySlot()
+ {
+ return DelayedBranch.isTriggered();
+ }
+
+ /**
+ * Simulate execution of given MIPS program. It must have already been assembled.
+ *
+ * @param p The MIPSprogram to be simulated.
+ * @param pc address of first instruction to simulate; this goes into program counter
+ * @param maxSteps maximum number of steps to perform before returning false (0 or less means no max)
+ * @param breakPoints array of breakpoint program counter values, use null if none
+ * @param actor the GUI component responsible for this call, usually GO or STEP. null if none.
+ * @return true if execution completed, false otherwise
+ * @throws ProcessingException Throws exception if run-time exception occurs.
+ **/
+
+ public boolean simulate(MIPSprogram p, int pc, int maxSteps, int[] breakPoints, AbstractAction actor) throws ProcessingException
+ {
+ simulatorThread = new SimThread(p, pc, maxSteps, breakPoints, actor);
+ simulatorThread.start();
+
+ // Condition should only be true if run from command-line instead of GUI.
+ // If so, just stick around until execution thread is finished.
+ if (actor == null)
+ {
Object dun = simulatorThread.get(); // this should emulate join()
ProcessingException pe = simulatorThread.pe;
boolean done = simulatorThread.done;
- if (done) SystemIO.resetFiles(); // close any files opened in MIPS progra
+ if (done)
+ {
+ SystemIO.resetFiles(); // close any files opened in MIPS progra
+ }
this.simulatorThread = null;
- if (pe != null) {
- throw pe;
+ if (pe != null)
+ {
+ throw pe;
}
return done;
- }
- return true;
- }
-
-
- /**
- * Set the volatile stop boolean variable checked by the execution
- * thread at the end of each MIPS instruction execution. If variable
- * is found to be true, the execution thread will depart
- * gracefully so the main thread handling the GUI can take over.
- * This is used by both STOP and PAUSE features.
- */
- public void stopExecution(AbstractAction actor) {
-
- if (simulatorThread != null) {
+ }
+ return true;
+ }
+
+ /**
+ * Set the volatile stop boolean variable checked by the execution thread at the end of each MIPS instruction
+ * execution. If variable is found to be true, the execution thread will depart gracefully so the main thread
+ * handling the GUI can take over. This is used by both STOP and PAUSE features.
+ */
+ public void stopExecution(AbstractAction actor)
+ {
+
+ if (simulatorThread != null)
+ {
simulatorThread.setStop(actor);
- for (StopListener l : stopListeners) {
- l.stopped(this);
+ for (StopListener l : stopListeners)
+ {
+ l.stopped(this);
}
simulatorThread = null;
- }
- }
-
- /* This interface is required by the Asker class in MassagesPane
- * to be notified about the fact that the user has requested to
- * stop the execution. When that happens, it must unblock the
- * simulator thread. */
- public interface StopListener {
- void stopped(Simulator s);
- }
-
- private ArrayList stopListeners = new ArrayList(1);
- public void addStopListener(StopListener l) {
- stopListeners.add(l);
- }
-
- public void removeStopListener(StopListener l) {
- stopListeners.remove(l);
- }
-
- // The Simthread object will call this method when it enters and returns from
- // its construct() method. These signal start and stop, respectively, of
- // simulation execution. The observer can then adjust its own state depending
- // on the execution state. Note that "stop" and "done" are not the same thing.
- // "stop" just means it is leaving execution state; this could be triggered
- // by Stop button, by Pause button, by Step button, by runtime exception, by
- // instruction count limit, by breakpoint, or by end of simulation (truly done).
- private void notifyObserversOfExecutionStart(int maxSteps, int programCounter) {
- this.setChanged();
- this.notifyObservers(new SimulatorNotice(SimulatorNotice.SIMULATOR_START,
- maxSteps, RunSpeedPanel.getInstance().getRunSpeed(), programCounter) );
- }
-
- private void notifyObserversOfExecutionStop(int maxSteps, int programCounter) {
- this.setChanged();
- this.notifyObservers(new SimulatorNotice(SimulatorNotice.SIMULATOR_STOP,
- maxSteps, RunSpeedPanel.getInstance().getRunSpeed(), programCounter) );
- }
-
-
- /**
- * SwingWorker subclass to perform the simulated execution in background thread.
- * It is "interrupted" when main thread sets the "stop" variable to true.
- * The variable is tested before the next MIPS instruction is simulated. Thus
- * interruption occurs in a tightly controlled fashion.
- *
- * See SwingWorker.java for more details on its functionality and usage. It is
- * provided by Sun Microsystems for download and is not part of the Swing library.
- */
-
- class SimThread extends SwingWorker {
- private MIPSprogram p;
- private int pc, maxSteps;
- private int[] breakPoints;
- private boolean done;
- private ProcessingException pe;
- private volatile boolean stop = false;
- private volatile AbstractAction stopper;
- private AbstractAction starter;
- private int constructReturnReason;
-
-
- /**
- * SimThread constructor. Receives all the information it needs to simulate execution.
- *
- * @param p the MIPSprogram to be simulated
- * @param pc address in text segment of first instruction to simulate
- * @param maxSteps maximum number of instruction steps to simulate. Default of -1 means no maximum
- * @param breakPoints array of breakpoints (instruction addresses) specified by user
- * @param starter the GUI component responsible for this call, usually GO or STEP. null if none.
- */
- SimThread(MIPSprogram p, int pc, int maxSteps, int[] breakPoints, AbstractAction starter) {
- super(Globals.getGui()!=null);
+ }
+ }
+
+ public void addStopListener(StopListener l)
+ {
+ stopListeners.add(l);
+ }
+
+ public void removeStopListener(StopListener l)
+ {
+ stopListeners.remove(l);
+ }
+
+ // The Simthread object will call this method when it enters and returns from
+ // its construct() method. These signal start and stop, respectively, of
+ // simulation execution. The observer can then adjust its own state depending
+ // on the execution state. Note that "stop" and "done" are not the same thing.
+ // "stop" just means it is leaving execution state; this could be triggered
+ // by Stop button, by Pause button, by Step button, by runtime exception, by
+ // instruction count limit, by breakpoint, or by end of simulation (truly done).
+ private void notifyObserversOfExecutionStart(int maxSteps, int programCounter)
+ {
+ this.setChanged();
+ this.notifyObservers(new SimulatorNotice(SimulatorNotice.SIMULATOR_START,
+ maxSteps, RunSpeedPanel.getInstance().getRunSpeed(), programCounter));
+ }
+
+ private void notifyObserversOfExecutionStop(int maxSteps, int programCounter)
+ {
+ this.setChanged();
+ this.notifyObservers(new SimulatorNotice(SimulatorNotice.SIMULATOR_STOP,
+ maxSteps, RunSpeedPanel.getInstance().getRunSpeed(), programCounter));
+ }
+
+ /* This interface is required by the Asker class in MassagesPane
+ * to be notified about the fact that the user has requested to
+ * stop the execution. When that happens, it must unblock the
+ * simulator thread. */
+ public interface StopListener
+ {
+ void stopped(Simulator s);
+ }
+
+ /**
+ * SwingWorker subclass to perform the simulated execution in background thread. It is "interrupted" when main
+ * thread sets the "stop" variable to true. The variable is tested before the next MIPS instruction is simulated.
+ * Thus interruption occurs in a tightly controlled fashion.
+ *
+ * See SwingWorker.java for more details on its functionality and usage. It is provided by Sun Microsystems for
+ * download and is not part of the Swing library.
+ */
+
+ class SimThread extends SwingWorker
+ {
+ private final MIPSprogram p;
+
+ private final int pc;
+
+ private final int maxSteps;
+
+ private int[] breakPoints;
+
+ private boolean done;
+
+ private ProcessingException pe;
+
+ private volatile boolean stop = false;
+
+ private volatile AbstractAction stopper;
+
+ private final AbstractAction starter;
+
+ private int constructReturnReason;
+
+
+ /**
+ * SimThread constructor. Receives all the information it needs to simulate execution.
+ *
+ * @param p the MIPSprogram to be simulated
+ * @param pc address in text segment of first instruction to simulate
+ * @param maxSteps maximum number of instruction steps to simulate. Default of -1 means no maximum
+ * @param breakPoints array of breakpoints (instruction addresses) specified by user
+ * @param starter the GUI component responsible for this call, usually GO or STEP. null if none.
+ */
+ SimThread(MIPSprogram p, int pc, int maxSteps, int[] breakPoints, AbstractAction starter)
+ {
+ super(Globals.getGui() != null);
this.p = p;
this.pc = pc;
this.maxSteps = maxSteps;
@@ -228,309 +273,354 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
this.pe = null;
this.starter = starter;
this.stopper = null;
- }
-
- /**
- * Sets to "true" the volatile boolean variable that is tested after each
- * MIPS instruction is executed. After calling this method, the next test
- * will yield "true" and "construct" will return.
- *
- * @param actor the Swing component responsible for this call.
- */
- public void setStop(AbstractAction actor) {
+ }
+
+ /**
+ * Sets to "true" the volatile boolean variable that is tested after each MIPS instruction is executed. After
+ * calling this method, the next test will yield "true" and "construct" will return.
+ *
+ * @param actor the Swing component responsible for this call.
+ */
+ public void setStop(AbstractAction actor)
+ {
stop = true;
stopper = actor;
- }
-
-
- /**
- * This is comparable to the Runnable "run" method (it is called by
- * SwingWorker's "run" method). It simulates the program
- * execution in the backgorund.
- *
- * @return boolean value true if execution done, false otherwise
- */
-
- public Object construct() {
+ }
+
+
+ /**
+ * This is comparable to the Runnable "run" method (it is called by SwingWorker's "run" method). It simulates
+ * the program execution in the backgorund.
+ *
+ * @return boolean value true if execution done, false otherwise
+ */
+
+ public Object construct()
+ {
// The next two statements are necessary for GUI to be consistently updated
- // before the simulation gets underway. Without them, this happens only intermittently,
- // with a consequence that some simulations are interruptable using PAUSE/STOP and others
- // are not (because one or the other or both is not yet enabled).
- Thread.currentThread().setPriority(Thread.NORM_PRIORITY-1);
+ // before the simulation gets underway. Without them, this happens only intermittently,
+ // with a consequence that some simulations are interruptable using PAUSE/STOP and others
+ // are not (because one or the other or both is not yet enabled).
+ Thread.currentThread().setPriority(Thread.NORM_PRIORITY - 1);
Thread.yield(); // let the main thread run a bit to finish updating the GUI
-
- if (breakPoints == null || breakPoints.length == 0) {
- breakPoints = null;
- }
- else {
- Arrays.sort(breakPoints); // must be pre-sorted for binary search
+
+ if (breakPoints == null || breakPoints.length == 0)
+ {
+ breakPoints = null;
}
-
+ else
+ {
+ Arrays.sort(breakPoints); // must be pre-sorted for binary search
+ }
+
Simulator.getInstance().notifyObserversOfExecutionStart(maxSteps, pc);
-
+
RegisterFile.initializeProgramCounter(pc);
ProgramStatement statement = null;
- try {
- statement = Globals.memory.getStatement(RegisterFile.getProgramCounter());
- }
- catch (AddressErrorException e) {
- ErrorList el = new ErrorList();
- el.add(new ErrorMessage((MIPSprogram)null,0,0,"invalid program counter value: "+Binary.intToHexString(RegisterFile.getProgramCounter())));
- this.pe = new ProcessingException(el, e);
- // Next statement is a hack. Previous statement sets EPC register to ProgramCounter-4
- // because it assumes the bad address comes from an operand so the ProgramCounter has already been
- // incremented. In this case, bad address is the instruction fetch itself so Program Counter has
- // not yet been incremented. We'll set the EPC directly here. DPS 8-July-2013
- Coprocessor0.updateRegister(Coprocessor0.EPC, RegisterFile.getProgramCounter());
- this.constructReturnReason = EXCEPTION;
- this.done = true;
- SystemIO.resetFiles(); // close any files opened in MIPS program
- Simulator.getInstance().notifyObserversOfExecutionStop(maxSteps, pc);
- return new Boolean(done);
- }
+ try
+ {
+ statement = Globals.memory.getStatement(RegisterFile.getProgramCounter());
+ }
+ catch (AddressErrorException e)
+ {
+ ErrorList el = new ErrorList();
+ el.add(new ErrorMessage((MIPSprogram) null, 0, 0, "invalid program counter value: " + Binary.intToHexString(RegisterFile.getProgramCounter())));
+ this.pe = new ProcessingException(el, e);
+ // Next statement is a hack. Previous statement sets EPC register to ProgramCounter-4
+ // because it assumes the bad address comes from an operand so the ProgramCounter has already been
+ // incremented. In this case, bad address is the instruction fetch itself so Program Counter has
+ // not yet been incremented. We'll set the EPC directly here. DPS 8-July-2013
+ Coprocessor0.updateRegister(Coprocessor0.EPC, RegisterFile.getProgramCounter());
+ this.constructReturnReason = EXCEPTION;
+ this.done = true;
+ SystemIO.resetFiles(); // close any files opened in MIPS program
+ Simulator.getInstance().notifyObserversOfExecutionStop(maxSteps, pc);
+ return Boolean.valueOf(done);
+ }
int steps = 0;
-
- // ******************* PS addition 26 July 2006 **********************
- // A couple statements below were added for the purpose of assuring that when
- // "back stepping" is enabled, every instruction will have at least one entry
- // on the back-stepping stack. Most instructions will because they write either
- // to a register or memory. But "nop" and branches not taken do not. When the
- // user is stepping backward through the program, the stack is popped and if
- // an instruction has no entry it will be skipped over in the process. This has
- // no effect on the correctness of the mechanism but the visual jerkiness when
- // instruction highlighting skips such instrutions is disruptive. Current solution
- // is to add a "do nothing" stack entry for instructions that do no write anything.
- // To keep this invisible to the "simulate()" method writer, we
- // will push such an entry onto the stack here if there is none for this instruction
- // by the time it has completed simulating. This is done by the IF statement
- // just after the call to the simulate method itself. The BackStepper method does
- // the aforementioned check and decides whether to push or not. The result
- // is a a smoother interaction experience. But it comes at the cost of slowing
- // simulation speed for flat-out runs, for every MIPS instruction executed even
- // though very few will require the "do nothing" stack entry. For stepped or
- // timed execution the slower execution speed is not noticeable.
- //
- // To avoid this cost I tried a different technique: back-fill with "do nothings"
- // during the backstepping itself when this situation is recognized. Problem
- // was in recognizing all possible situations in which the stack contained such
- // a "gap". It became a morass of special cases and it seemed every weird test
- // case revealed another one. In addition, when a program
- // begins with one or more such instructions ("nop" and branches not taken),
- // the backstep button is not enabled until a "real" instruction is executed.
- // This is noticeable in stepped mode.
- // *********************************************************************
-
+
+ // ******************* PS addition 26 July 2006 **********************
+ // A couple statements below were added for the purpose of assuring that when
+ // "back stepping" is enabled, every instruction will have at least one entry
+ // on the back-stepping stack. Most instructions will because they write either
+ // to a register or memory. But "nop" and branches not taken do not. When the
+ // user is stepping backward through the program, the stack is popped and if
+ // an instruction has no entry it will be skipped over in the process. This has
+ // no effect on the correctness of the mechanism but the visual jerkiness when
+ // instruction highlighting skips such instrutions is disruptive. Current solution
+ // is to add a "do nothing" stack entry for instructions that do no write anything.
+ // To keep this invisible to the "simulate()" method writer, we
+ // will push such an entry onto the stack here if there is none for this instruction
+ // by the time it has completed simulating. This is done by the IF statement
+ // just after the call to the simulate method itself. The BackStepper method does
+ // the aforementioned check and decides whether to push or not. The result
+ // is a a smoother interaction experience. But it comes at the cost of slowing
+ // simulation speed for flat-out runs, for every MIPS instruction executed even
+ // though very few will require the "do nothing" stack entry. For stepped or
+ // timed execution the slower execution speed is not noticeable.
+ //
+ // To avoid this cost I tried a different technique: back-fill with "do nothings"
+ // during the backstepping itself when this situation is recognized. Problem
+ // was in recognizing all possible situations in which the stack contained such
+ // a "gap". It became a morass of special cases and it seemed every weird test
+ // case revealed another one. In addition, when a program
+ // begins with one or more such instructions ("nop" and branches not taken),
+ // the backstep button is not enabled until a "real" instruction is executed.
+ // This is noticeable in stepped mode.
+ // *********************************************************************
+
int pc = 0; // added: 7/26/06 (explanation above)
-
- while (statement != null) {
- pc = RegisterFile.getProgramCounter(); // added: 7/26/06 (explanation above)
- RegisterFile.incrementPC();
- // Perform the MIPS instruction in synchronized block. If external threads agree
- // to access MIPS memory and registers only through synchronized blocks on same
- // lock variable, then full (albeit heavy-handed) protection of MIPS memory and
- // registers is assured. Not as critical for reading from those resources.
- synchronized (Globals.memoryAndRegistersLock) {
- try {
- if (Simulator.externalInterruptingDevice != NO_DEVICE) {
- int deviceInterruptCode = externalInterruptingDevice;
- Simulator.externalInterruptingDevice = NO_DEVICE;
- throw new ProcessingException(statement, "External Interrupt", deviceInterruptCode);
- }
- BasicInstruction instruction = (BasicInstruction)statement.getInstruction();
- if (instruction == null) {
- throw new ProcessingException(statement,
- "undefined instruction ("+Binary.intToHexString(statement.getBinaryStatement())+")",
- Exceptions.RESERVED_INSTRUCTION_EXCEPTION);
- }
- // THIS IS WHERE THE INSTRUCTION EXECUTION IS ACTUALLY SIMULATED!
- instruction.getSimulationCode().simulate(statement);
-
- // IF statement added 7/26/06 (explanation above)
- if (Globals.getSettings().getBackSteppingEnabled()) {
- Globals.program.getBackStepper().addDoNothing(pc);
- }
- }
- catch (ProcessingException pe) {
- if (pe.errors() == null) {
- this.constructReturnReason = NORMAL_TERMINATION;
- this.done = true;
- SystemIO.resetFiles(); // close any files opened in MIPS program
- Simulator.getInstance().notifyObserversOfExecutionStop(maxSteps, pc);
- return new Boolean(done); // execution completed without error.
- }
- else {
- // See if an exception handler is present. Assume this is the case
- // if and only if memory location Memory.exceptionHandlerAddress
- // (e.g. 0x80000180) contains an instruction. If so, then set the
- // program counter there and continue. Otherwise terminate the
- // MIPS program with appropriate error message.
- ProgramStatement exceptionHandler = null;
- try {
- exceptionHandler = Globals.memory.getStatement(Memory.exceptionHandlerAddress);
- }
- catch (AddressErrorException aee) { } // will not occur with this well-known addres
- if (exceptionHandler != null) {
- RegisterFile.setProgramCounter(Memory.exceptionHandlerAddress);
- }
- else {
- this.constructReturnReason = EXCEPTION;
- this.pe = pe;
- this.done = true;
- SystemIO.resetFiles(); // close any files opened in MIPS program
- Simulator.getInstance().notifyObserversOfExecutionStop(maxSteps, pc);
- return new Boolean(done);
- }
+
+ while (statement != null)
+ {
+ pc = RegisterFile.getProgramCounter(); // added: 7/26/06 (explanation above)
+ RegisterFile.incrementPC();
+ // Perform the MIPS instruction in synchronized block. If external threads agree
+ // to access MIPS memory and registers only through synchronized blocks on same
+ // lock variable, then full (albeit heavy-handed) protection of MIPS memory and
+ // registers is assured. Not as critical for reading from those resources.
+ synchronized (Globals.memoryAndRegistersLock)
+ {
+ try
+ {
+ if (Simulator.externalInterruptingDevice != NO_DEVICE)
+ {
+ int deviceInterruptCode = externalInterruptingDevice;
+ Simulator.externalInterruptingDevice = NO_DEVICE;
+ throw new ProcessingException(statement, "External Interrupt", deviceInterruptCode);
}
- }
- }// end synchronized block
-
- ///////// DPS 15 June 2007. Handle delayed branching if it occurs./////
- if (DelayedBranch.isTriggered()) {
- RegisterFile.setProgramCounter(DelayedBranch.getBranchTargetAddress());
- DelayedBranch.clear();
- }
- else if (DelayedBranch.isRegistered()) {
- DelayedBranch.trigger();
- }//////////////////////////////////////////////////////////////////////
-
- // Volatile variable initialized false but can be set true by the main thread.
- // Used to stop or pause a running MIPS program. See stopSimulation() above.
- if (stop == true) {
- this.constructReturnReason = PAUSE_OR_STOP;
- this.done = false;
- Simulator.getInstance().notifyObserversOfExecutionStop(maxSteps, pc);
- return new Boolean(done);
- }
- // Return if we've reached a breakpoint.
- if((breakPoints != null) &&
- (Arrays.binarySearch(breakPoints,RegisterFile.getProgramCounter()) >= 0)) {
- this.constructReturnReason = BREAKPOINT;
- this.done = false;
- Simulator.getInstance().notifyObserversOfExecutionStop(maxSteps, pc);
- return new Boolean(done); // false;
- }
- // Check number of MIPS instructions executed. Return if at limit (-1 is no limit).
- if (maxSteps > 0) {
- steps++;
- if (steps >= maxSteps) {
- this.constructReturnReason = MAX_STEPS;
- this.done = false;
- Simulator.getInstance().notifyObserversOfExecutionStop(maxSteps, pc);
- return new Boolean(done);// false;
- }
- }
-
- // schedule GUI update only if: there is in fact a GUI! AND
- // using Run, not Step (maxSteps > 1) AND
- // running slowly enough for GUI to keep up
- //if (Globals.getGui() != null && maxSteps != 1 &&
- if (interactiveGUIUpdater != null && maxSteps != 1 &&
- RunSpeedPanel.getInstance().getRunSpeed() < RunSpeedPanel.UNLIMITED_SPEED) {
- SwingUtilities.invokeLater(interactiveGUIUpdater);
- }
- if (Globals.getGui() != null || Globals.runSpeedPanelExists) { // OR added by DPS 24 July 2008 to enable speed control by stand-alone tool
- if (maxSteps != 1 &&
- RunSpeedPanel.getInstance().getRunSpeed() < RunSpeedPanel.UNLIMITED_SPEED) {
- try { Thread.sleep((int)(1000/RunSpeedPanel.getInstance().getRunSpeed())); // make sure it's never zero!
- }
- catch (InterruptedException e) {}
- }
- }
-
-
- // Get next instruction in preparation for next iteration.
-
- try {
- statement = Globals.memory.getStatement(RegisterFile.getProgramCounter());
- }
- catch (AddressErrorException e) {
- ErrorList el = new ErrorList();
- el.add(new ErrorMessage((MIPSprogram)null,0,0,"invalid program counter value: "+Binary.intToHexString(RegisterFile.getProgramCounter())));
- this.pe = new ProcessingException(el,e);
- // Next statement is a hack. Previous statement sets EPC register to ProgramCounter-4
- // because it assumes the bad address comes from an operand so the ProgramCounter has already been
- // incremented. In this case, bad address is the instruction fetch itself so Program Counter has
- // not yet been incremented. We'll set the EPC directly here. DPS 8-July-2013
- Coprocessor0.updateRegister(Coprocessor0.EPC, RegisterFile.getProgramCounter());
- this.constructReturnReason = EXCEPTION;
- this.done = true;
- SystemIO.resetFiles(); // close any files opened in MIPS program
- Simulator.getInstance().notifyObserversOfExecutionStop(maxSteps, pc);
- return new Boolean(done);
- }
+ BasicInstruction instruction = (BasicInstruction) statement.getInstruction();
+ if (instruction == null)
+ {
+ throw new ProcessingException(statement,
+ "undefined instruction (" + Binary.intToHexString(statement.getBinaryStatement()) + ")",
+ Exceptions.RESERVED_INSTRUCTION_EXCEPTION);
+ }
+ // THIS IS WHERE THE INSTRUCTION EXECUTION IS ACTUALLY SIMULATED!
+ instruction.getSimulationCode().simulate(statement);
+
+ // IF statement added 7/26/06 (explanation above)
+ if (Globals.getSettings().getBackSteppingEnabled())
+ {
+ Globals.program.getBackStepper().addDoNothing(pc);
+ }
+ }
+ catch (ProcessingException pe)
+ {
+ if (pe.errors() == null)
+ {
+ this.constructReturnReason = NORMAL_TERMINATION;
+ this.done = true;
+ SystemIO.resetFiles(); // close any files opened in MIPS program
+ Simulator.getInstance().notifyObserversOfExecutionStop(maxSteps, pc);
+ return Boolean.valueOf(done); // execution completed without error.
+ }
+ else
+ {
+ // See if an exception handler is present. Assume this is the case
+ // if and only if memory location Memory.exceptionHandlerAddress
+ // (e.g. 0x80000180) contains an instruction. If so, then set the
+ // program counter there and continue. Otherwise terminate the
+ // MIPS program with appropriate error message.
+ ProgramStatement exceptionHandler = null;
+ try
+ {
+ exceptionHandler = Globals.memory.getStatement(Memory.exceptionHandlerAddress);
+ }
+ catch (AddressErrorException aee)
+ {
+ } // will not occur with this well-known addres
+ if (exceptionHandler != null)
+ {
+ RegisterFile.setProgramCounter(Memory.exceptionHandlerAddress);
+ }
+ else
+ {
+ this.constructReturnReason = EXCEPTION;
+ this.pe = pe;
+ this.done = true;
+ SystemIO.resetFiles(); // close any files opened in MIPS program
+ Simulator.getInstance().notifyObserversOfExecutionStop(maxSteps, pc);
+ return Boolean.valueOf(done);
+ }
+ }
+ }
+ }// end synchronized block
+
+ ///////// DPS 15 June 2007. Handle delayed branching if it occurs./////
+ if (DelayedBranch.isTriggered())
+ {
+ RegisterFile.setProgramCounter(DelayedBranch.getBranchTargetAddress());
+ DelayedBranch.clear();
+ }
+ else if (DelayedBranch.isRegistered())
+ {
+ DelayedBranch.trigger();
+ }//////////////////////////////////////////////////////////////////////
+
+ // Volatile variable initialized false but can be set true by the main thread.
+ // Used to stop or pause a running MIPS program. See stopSimulation() above.
+ if (stop)
+ {
+ this.constructReturnReason = PAUSE_OR_STOP;
+ this.done = false;
+ Simulator.getInstance().notifyObserversOfExecutionStop(maxSteps, pc);
+ return Boolean.valueOf(done);
+ }
+ // Return if we've reached a breakpoint.
+ if ((breakPoints != null) &&
+ (Arrays.binarySearch(breakPoints, RegisterFile.getProgramCounter()) >= 0))
+ {
+ this.constructReturnReason = BREAKPOINT;
+ this.done = false;
+ Simulator.getInstance().notifyObserversOfExecutionStop(maxSteps, pc);
+ return Boolean.valueOf(done); // false;
+ }
+ // Check number of MIPS instructions executed. Return if at limit (-1 is no limit).
+ if (maxSteps > 0)
+ {
+ steps++;
+ if (steps >= maxSteps)
+ {
+ this.constructReturnReason = MAX_STEPS;
+ this.done = false;
+ Simulator.getInstance().notifyObserversOfExecutionStop(maxSteps, pc);
+ return Boolean.valueOf(done);// false;
+ }
+ }
+
+ // schedule GUI update only if: there is in fact a GUI! AND
+ // using Run, not Step (maxSteps > 1) AND
+ // running slowly enough for GUI to keep up
+ //if (Globals.getGui() != null && maxSteps != 1 &&
+ if (interactiveGUIUpdater != null && maxSteps != 1 &&
+ RunSpeedPanel.getInstance().getRunSpeed() < RunSpeedPanel.UNLIMITED_SPEED)
+ {
+ SwingUtilities.invokeLater(interactiveGUIUpdater);
+ }
+ if (Globals.getGui() != null || Globals.runSpeedPanelExists)
+ { // OR added by DPS 24 July 2008 to enable speed control by stand-alone tool
+ if (maxSteps != 1 &&
+ RunSpeedPanel.getInstance().getRunSpeed() < RunSpeedPanel.UNLIMITED_SPEED)
+ {
+ try
+ {
+ Thread.sleep((int) (1000 / RunSpeedPanel.getInstance().getRunSpeed())); // make sure it's never zero!
+ }
+ catch (InterruptedException e)
+ {
+ }
+ }
+ }
+
+
+ // Get next instruction in preparation for next iteration.
+
+ try
+ {
+ statement = Globals.memory.getStatement(RegisterFile.getProgramCounter());
+ }
+ catch (AddressErrorException e)
+ {
+ ErrorList el = new ErrorList();
+ el.add(new ErrorMessage((MIPSprogram) null, 0, 0, "invalid program counter value: " + Binary.intToHexString(RegisterFile.getProgramCounter())));
+ this.pe = new ProcessingException(el, e);
+ // Next statement is a hack. Previous statement sets EPC register to ProgramCounter-4
+ // because it assumes the bad address comes from an operand so the ProgramCounter has already been
+ // incremented. In this case, bad address is the instruction fetch itself so Program Counter has
+ // not yet been incremented. We'll set the EPC directly here. DPS 8-July-2013
+ Coprocessor0.updateRegister(Coprocessor0.EPC, RegisterFile.getProgramCounter());
+ this.constructReturnReason = EXCEPTION;
+ this.done = true;
+ SystemIO.resetFiles(); // close any files opened in MIPS program
+ Simulator.getInstance().notifyObserversOfExecutionStop(maxSteps, pc);
+ return Boolean.valueOf(done);
+ }
}
// DPS July 2007. This "if" statement is needed for correct program
- // termination if delayed branching on and last statement in
- // program is a branch/jump. Program will terminate rather than branch,
- // because that's what MARS does when execution drops off the bottom.
- if (DelayedBranch.isTriggered() || DelayedBranch.isRegistered()) {
- DelayedBranch.clear();
+ // termination if delayed branching on and last statement in
+ // program is a branch/jump. Program will terminate rather than branch,
+ // because that's what MARS does when execution drops off the bottom.
+ if (DelayedBranch.isTriggered() || DelayedBranch.isRegistered())
+ {
+ DelayedBranch.clear();
}
- // If we got here it was due to null statement, which means program
- // counter "fell off the end" of the program. NOTE: Assumes the
- // "while" loop contains no "break;" statements.
+ // If we got here it was due to null statement, which means program
+ // counter "fell off the end" of the program. NOTE: Assumes the
+ // "while" loop contains no "break;" statements.
this.constructReturnReason = CLIFF_TERMINATION;
this.done = true;
SystemIO.resetFiles(); // close any files opened in MIPS program
Simulator.getInstance().notifyObserversOfExecutionStop(maxSteps, pc);
- return new Boolean(done); // true; // execution completed
- }
-
-
- /**
- * This method is invoked by the SwingWorker when the "construct" method returns.
- * It will update the GUI appropriately. According to Sun's documentation, it
- * is run in the main thread so should work OK with Swing components (which are
- * not thread-safe).
- *
- * Its action depends on what caused the return from construct() and what
- * action led to the call of construct() in the first place.
- */
-
- public void finished() {
- // If running from the command-line, then there is no GUI to update.
- if (Globals.getGui() == null) {
- return;
+ return Boolean.valueOf(done); // true; // execution completed
+ }
+
+
+ /**
+ * This method is invoked by the SwingWorker when the "construct" method returns. It will update the GUI
+ * appropriately. According to Sun's documentation, it is run in the main thread so should work OK with Swing
+ * components (which are not thread-safe).
+ *
+ * Its action depends on what caused the return from construct() and what action led to the call of construct()
+ * in the first place.
+ */
+
+ public void finished()
+ {
+ // If running from the command-line, then there is no GUI to update.
+ if (Globals.getGui() == null)
+ {
+ return;
}
String starterName = (String) starter.getValue(AbstractAction.NAME);
- if (starterName.equals("Step")) {
- ((RunStepAction)starter).stepped(done,constructReturnReason,pe);
- }
- if (starterName.equals("Go")) {
- if (done) {
- ((RunGoAction)starter).stopped(pe,constructReturnReason);
- }
- else if (constructReturnReason == BREAKPOINT) {
- ((RunGoAction)starter).paused(done,constructReturnReason,pe);
- }
- else {
- String stopperName = (String) stopper.getValue(AbstractAction.NAME);
- if ("Pause".equals(stopperName)) {
- ((RunGoAction)starter).paused(done,constructReturnReason,pe);
- }
- else if ("Stop".equals(stopperName)) {
- ((RunGoAction)starter).stopped(pe,constructReturnReason);
- }
- }
+ if (starterName.equals("Step"))
+ {
+ ((RunStepAction) starter).stepped(done, constructReturnReason, pe);
}
- return;
- }
-
- }
-
- private class UpdateGUI implements Runnable {
- public void run() {
- if (Globals.getGui().getRegistersPane().getSelectedComponent() ==
- Globals.getGui().getMainPane().getExecutePane().getRegistersWindow()) {
- Globals.getGui().getMainPane().getExecutePane().getRegistersWindow().updateRegisters();
- }
- else {
- Globals.getGui().getMainPane().getExecutePane().getCoprocessor1Window().updateRegisters();
+ if (starterName.equals("Go"))
+ {
+ if (done)
+ {
+ ((RunGoAction) starter).stopped(pe, constructReturnReason);
+ }
+ else if (constructReturnReason == BREAKPOINT)
+ {
+ ((RunGoAction) starter).paused(done, constructReturnReason, pe);
+ }
+ else
+ {
+ String stopperName = (String) stopper.getValue(AbstractAction.NAME);
+ if ("Pause".equals(stopperName))
+ {
+ ((RunGoAction) starter).paused(done, constructReturnReason, pe);
+ }
+ else if ("Stop".equals(stopperName))
+ {
+ ((RunGoAction) starter).stopped(pe, constructReturnReason);
+ }
+ }
+ }
+ }
+
+ }
+
+ private class UpdateGUI implements Runnable
+ {
+ public void run()
+ {
+ if (Globals.getGui().getRegistersPane().getSelectedComponent() ==
+ Globals.getGui().getMainPane().getExecutePane().getRegistersWindow())
+ {
+ Globals.getGui().getMainPane().getExecutePane().getRegistersWindow().updateRegisters();
+ }
+ else
+ {
+ Globals.getGui().getMainPane().getExecutePane().getCoprocessor1Window().updateRegisters();
}
Globals.getGui().getMainPane().getExecutePane().getDataSegmentWindow().updateValues();
Globals.getGui().getMainPane().getExecutePane().getTextSegmentWindow().setCodeHighlighting(true);
- Globals.getGui().getMainPane().getExecutePane().getTextSegmentWindow().highlightStepAtPC();
- }
- }
-
- }
+ Globals.getGui().getMainPane().getExecutePane().getTextSegmentWindow().highlightStepAtPC();
+ }
+ }
+
+}
diff --git a/src/main/java/mars/simulator/SimulatorNotice.java b/src/main/java/mars/simulator/SimulatorNotice.java
index 9732b64..501b0e9 100644
--- a/src/main/java/mars/simulator/SimulatorNotice.java
+++ b/src/main/java/mars/simulator/SimulatorNotice.java
@@ -29,54 +29,68 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
- * Object provided to Observers of the Simulator.
- * They are notified at important phases of the runtime simulator,
- * such as start and stop of simulation.
- *
- * @author Pete Sanderson
+ * Object provided to Observers of the Simulator. They are notified at important phases of the runtime simulator, such
+ * as start and stop of simulation.
+ *
+ * @author Pete Sanderson
* @version January 2009
*/
-
-public class SimulatorNotice {
- private int action;
- private int maxSteps;
- private double runSpeed;
- private int programCounter;
- public static final int SIMULATOR_START = 0;
- public static final int SIMULATOR_STOP = 1;
- /** Constructor will be called only within this package, so assume
- * address and length are in valid ranges.
- */
- public SimulatorNotice(int action, int maxSteps, double runSpeed, int programCounter) {
- this.action = action;
- this.maxSteps = maxSteps;
- this.runSpeed = runSpeed;
- this.programCounter = programCounter;
- }
+public class SimulatorNotice
+{
+ public static final int SIMULATOR_START = 0;
- /** Fetch the memory address that was accessed. */
- public int getAction() {
- return this.action;
- }
- /** Fetch the length in bytes of the access operation (4,2,1). */
- public int getMaxSteps() {
- return this.maxSteps;
- }
- /** Fetch the value of the access operation (the value read or written). */
- public double getRunSpeed() {
- return this.runSpeed;
- }
-
- /** Fetch the value of the access operation (the value read or written). */
- public int getProgramCounter() {
- return this.programCounter;
- }
- /** String representation indicates access type, address and length in bytes */
- public String toString() {
- return ((this.getAction()==SIMULATOR_START) ? "START " : "STOP ") +
- "Max Steps " + this.maxSteps + " " +
- "Speed "+ ((this.runSpeed==mars.venus.RunSpeedPanel.UNLIMITED_SPEED)? "unlimited " : ""+this.runSpeed+" inst/sec") +
- "Prog Ctr "+this.programCounter;
- }
-}
\ No newline at end of file
+ public static final int SIMULATOR_STOP = 1;
+
+ private final int action;
+
+ private final int maxSteps;
+
+ private final double runSpeed;
+
+ private final int programCounter;
+
+ /**
+ * Constructor will be called only within this package, so assume address and length are in valid ranges.
+ */
+ public SimulatorNotice(int action, int maxSteps, double runSpeed, int programCounter)
+ {
+ this.action = action;
+ this.maxSteps = maxSteps;
+ this.runSpeed = runSpeed;
+ this.programCounter = programCounter;
+ }
+
+ /** Fetch the memory address that was accessed. */
+ public int getAction()
+ {
+ return this.action;
+ }
+
+ /** Fetch the length in bytes of the access operation (4,2,1). */
+ public int getMaxSteps()
+ {
+ return this.maxSteps;
+ }
+
+ /** Fetch the value of the access operation (the value read or written). */
+ public double getRunSpeed()
+ {
+ return this.runSpeed;
+ }
+
+ /** Fetch the value of the access operation (the value read or written). */
+ public int getProgramCounter()
+ {
+ return this.programCounter;
+ }
+
+ /** String representation indicates access type, address and length in bytes */
+ public String toString()
+ {
+ return ((this.getAction() == SIMULATOR_START) ? "START " : "STOP ") +
+ "Max Steps " + this.maxSteps + " " +
+ "Speed " + ((this.runSpeed == mars.venus.RunSpeedPanel.UNLIMITED_SPEED) ? "unlimited " : "" + this.runSpeed + " inst/sec") +
+ "Prog Ctr " + this.programCounter;
+ }
+}
diff --git a/src/main/java/mars/simulator/SwingWorker.java b/src/main/java/mars/simulator/SwingWorker.java
index babbb93..ea039b0 100644
--- a/src/main/java/mars/simulator/SwingWorker.java
+++ b/src/main/java/mars/simulator/SwingWorker.java
@@ -1,143 +1,177 @@
package mars.simulator;
-import javax.swing.SwingUtilities;
+
+import javax.swing.*;
/*-----------------------------------------------------
* This file downloaded from the Sun Microsystems URL given below.
*
- * I will subclass it to create worker thread for running
+ * I will subclass it to create worker thread for running
* MIPS simulated execution.
*/
/**
- * This is the 3rd version of SwingWorker (also known as
- * SwingWorker 3), an abstract class that you subclass to
- * perform GUI-related work in a dedicated thread. For
- * instructions on and examples of using this class, see:
- *
+ * This is the 3rd version of SwingWorker (also known as SwingWorker 3), an abstract class that you subclass to perform
+ * GUI-related work in a dedicated thread. For instructions on and examples of using this class, see:
+ *
* http://java.sun.com/docs/books/tutorial/uiswing/misc/threads.html
- *
- * Note that the API changed slightly in the 3rd version:
- * You must now invoke start() on the SwingWorker after
- * creating it.
+ *
+ * Note that the API changed slightly in the 3rd version: You must now invoke start() on the SwingWorker after creating
+ * it.
*/
-public abstract class SwingWorker {
+public abstract class SwingWorker
+{
private Object value; // see getValue(), setValue()
- /**
- * Class to maintain reference to current worker thread
- * under separate synchronization control.
+ private final ThreadVar threadVar;
+
+ /**
+ * Start a thread that will call the construct method and then exit.
+ *
+ * @param useSwing Set true if MARS is running from GUI, false otherwise.
*/
- private static class ThreadVar {
- private Thread thread;
- ThreadVar(Thread t) { thread = t; }
- synchronized Thread get() { return thread; }
- synchronized void clear() { thread = null; }
+ public SwingWorker(final boolean useSwing)
+ {
+ final Runnable doFinished = new Runnable()
+ {
+ public void run()
+ {
+ finished();
+ }
+ };
+
+ Runnable doConstruct = new Runnable()
+ {
+ public void run()
+ {
+ try
+ {
+ setValue(construct());
+ }
+ finally
+ {
+ threadVar.clear();
+ }
+
+ if (useSwing)
+ {
+ SwingUtilities.invokeLater(doFinished);
+ }
+ else
+ {
+ doFinished.run();
+ }
+ }
+ };
+
+ // Thread that represents executing MIPS program...
+ Thread t = new Thread(doConstruct, "MIPS");
+
+ //t.setPriority(Thread.NORM_PRIORITY-1);//******************
+
+ threadVar = new ThreadVar(t);
}
- private ThreadVar threadVar;
-
- /**
- * Get the value produced by the worker thread, or null if it
- * hasn't been constructed yet.
+ /**
+ * Get the value produced by the worker thread, or null if it hasn't been constructed yet.
*/
- protected synchronized Object getValue() {
- return value;
+ protected synchronized Object getValue()
+ {
+ return value;
}
- /**
- * Set the value produced by worker thread
+ /**
+ * Set the value produced by worker thread
*/
- private synchronized void setValue(Object x) {
- value = x;
+ private synchronized void setValue(Object x)
+ {
+ value = x;
}
- /**
- * Compute the value to be returned by the get method.
+ /**
+ * Compute the value to be returned by the get method.
*/
public abstract Object construct();
/**
- * Called on the event dispatching thread (not on the worker thread)
- * after the construct method has returned.
+ * Called on the event dispatching thread (not on the worker thread) after the construct method has
+ * returned.
*/
- public void finished() {
+ public void finished()
+ {
}
/**
- * A new method that interrupts the worker thread. Call this method
- * to force the worker to stop what it's doing.
+ * A new method that interrupts the worker thread. Call this method to force the worker to stop what it's doing.
*/
- public void interrupt() {
+ public void interrupt()
+ {
Thread t = threadVar.get();
- if (t != null) {
+ if (t != null)
+ {
t.interrupt();
}
threadVar.clear();
}
/**
- * Return the value created by the construct method.
- * Returns null if either the constructing thread or the current
- * thread was interrupted before a value was produced.
- *
+ * Return the value created by the construct method. Returns null if either the constructing thread or
+ * the current thread was interrupted before a value was produced.
+ *
* @return the value created by the construct method
*/
- public Object get() {
- while (true) {
+ public Object get()
+ {
+ while (true)
+ {
Thread t = threadVar.get();
- if (t == null) {
+ if (t == null)
+ {
return getValue();
}
- try {
+ try
+ {
t.join();
}
- catch (InterruptedException e) {
+ catch (InterruptedException e)
+ {
Thread.currentThread().interrupt(); // propagate
return null;
}
}
}
-
- /**
- * Start a thread that will call the construct method
- * and then exit.
- * @param useSwing Set true if MARS is running from GUI, false otherwise.
- */
- public SwingWorker(final boolean useSwing) {
- final Runnable doFinished = new Runnable() {
- public void run() { finished(); }
- };
-
- Runnable doConstruct = new Runnable() {
- public void run() {
- try {
- setValue(construct());
- }
- finally {
- threadVar.clear();
- }
-
- if (useSwing) SwingUtilities.invokeLater(doFinished);
- else doFinished.run();
- }
- };
-
- // Thread that represents executing MIPS program...
- Thread t = new Thread(doConstruct, "MIPS");
-
- //t.setPriority(Thread.NORM_PRIORITY-1);//******************
-
- threadVar = new ThreadVar(t);
- }
-
/**
* Start the worker thread.
*/
- public void start() {
+ public void start()
+ {
Thread t = threadVar.get();
- if (t != null) {
+ if (t != null)
+ {
t.start();
}
}
+
+ /**
+ * Class to maintain reference to current worker thread under separate synchronization control.
+ */
+ private static class ThreadVar
+ {
+ private Thread thread;
+
+ ThreadVar(Thread t)
+ {
+ thread = t;
+ }
+
+ synchronized Thread get()
+ {
+ return thread;
+ }
+
+ synchronized void clear()
+ {
+ thread = null;
+ }
+ }
}
diff --git a/src/main/java/mars/tools/AbstractMarsToolAndApplication.java b/src/main/java/mars/tools/AbstractMarsToolAndApplication.java
index 41d2ae9..b575eba 100644
--- a/src/main/java/mars/tools/AbstractMarsToolAndApplication.java
+++ b/src/main/java/mars/tools/AbstractMarsToolAndApplication.java
@@ -1,15 +1,21 @@
- package mars.tools;
- import javax.swing.*;
- import javax.swing.border.*;
- import javax.swing.filechooser.FileFilter;
- import java.awt.*;
- import java.awt.event.*;
- import java.util.*;
- import java.io.*;
- import mars.*;
- import mars.util.*;
- import mars.tools.*;
- import mars.mips.hardware.*;
+package mars.tools;
+
+import mars.Globals;
+import mars.MIPSprogram;
+import mars.mips.hardware.*;
+import mars.util.FilenameFinder;
+
+import javax.swing.*;
+import javax.swing.border.EmptyBorder;
+import javax.swing.border.TitledBorder;
+import javax.swing.filechooser.FileFilter;
+import java.awt.*;
+import java.awt.event.*;
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Observable;
+import java.util.Observer;
/*
Copyright (c) 2003-2008, Pete Sanderson and Kenneth Vollmar
@@ -38,782 +44,876 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
(MIT license, http://www.opensource.org/licenses/mit-license.html)
*/
-
- /**
- * An abstract class that provides generic components to facilitate implementation of
- * a MarsTool and/or stand-alone Mars-based application. Provides default definitions
- * of both the action() method required to implement MarsTool and the go() method
- * conventionally used to launch a Mars-based stand-alone application. It also provides
- * generic definitions for interactively controlling the application. The generic controls
- * for MarsTools are 3 buttons: connect/disconnect to MIPS resource (memory and/or
- * registers), reset, and close (exit). The generic controls for stand-alone Mars apps
- * include: button that triggers a file open dialog, a text field to display status
- * messages, the run-speed slider to control execution rate when running a MIPS program,
- * a button that assembles and runs the current MIPS program, a button to interrupt
- * the running MIPS program, a reset button, and an exit button.
- * Pete Sanderson, 14 November 2006.
- */
- public abstract class AbstractMarsToolAndApplication extends JFrame implements MarsTool, Observer {
- protected boolean isBeingUsedAsAMarsTool = false; // can use to determine whether invoked as MarsTool or stand-alone.
- protected AbstractMarsToolAndApplication thisMarsApp;
- private JDialog dialog; // used only for MarsTool use. This is the pop-up dialog that appears when menu item selected.
- protected Window theWindow; // highest level GUI component (a JFrame for app, a JDialog for MarsTool)
-
- // Major GUI components
- JLabel headingLabel;
- private String title; // descriptive title for title bar provided to constructor.
- private String heading; // Text to be displayed in the top portion of the main window.
-
- // Some GUI settings
- private EmptyBorder emptyBorder = new EmptyBorder(4,4,4,4);
- private Color backgroundColor = Color.WHITE;
-
-
- private int lowMemoryAddress = Memory.dataSegmentBaseAddress;
- private int highMemoryAddress = Memory.stackBaseAddress;
- // For MarsTool, is set true when "Connect" clicked, false when "Disconnect" clicked.
- // For app, is set true when "Assemble and Run" clicked, false when program terminates.
- private volatile boolean observing = false;
-
- // Several structures required for stand-alone use only (not MarsTool use)
- private File mostRecentlyOpenedFile = null;
- private Runnable interactiveGUIUpdater = new GUIUpdater();
- private MessageField operationStatusMessages;
- private JButton openFileButton, assembleRunButton, stopButton;
- private boolean multiFileAssemble = false;
-
- // Structure required for MarsTool use only (not stand-alone use). Want subclasses to have access.
- protected ConnectButton connectButton;
-
-
- /**
- * Simple constructor
- * @param title String containing title bar text
- */
- protected AbstractMarsToolAndApplication(String title,String heading) {
- thisMarsApp = this;
- this.title = title;
- this.heading = heading;
- }
-
- //////////////////////////////////////////////////////////////////////////////////////
- ////////////////////////////// ABSTRACT METHODS ///////////////////////////
- //////////////////////////////////////////////////////////////////////////////////////
-
- /**
- * Required MarsTool method to return Tool name. Must be defined by subclass.
- * @return Tool name. MARS will display this in menu item.
- */
- public abstract String getName();
-
- /**
- * Abstract method that must be instantiated by subclass to build the main display area
- * of the GUI. It will be placed in the CENTER area of a BorderLayout. The title
- * is in the NORTH area, and the controls are in the SOUTH area.
- */
- protected abstract JComponent buildMainDisplayArea();
-
- //////////////////////////////////////////////////////////////////////////////////////
- ///////////////////////////// METHODS WITH DEFAULT IMPLEMENTATIONS //////////////////
- //////////////////////////////////////////////////////////////////////////////////////
-
- /**
- * Run the simulator as stand-alone application. For this default implementation,
- * the user-defined main display of the user interface is identical for both stand-alone
- * and MARS Tools menu use, but the control buttons are different because the stand-alone
- * must include a mechansim for controlling the opening, assembling, and executing of
- * an underlying MIPS program. The generic controls include: a button that triggers a
- * file open dialog, a text field to display status messages, the run-speed slider
- * to control execution rate when running a MIPS program, a button that assembles and
- * runs the current MIPS program, a reset button, and an exit button.
- * This method calls 3 methods that can be defined/overriden in the subclass: initializePreGUI()
- * for any special initialization that must be completed before building the user
- * interface (e.g. data structures whose properties determine default GUI settings),
- * initializePostGUI() for any special initialization that cannot be
- * completed until after the building the user interface (e.g. data structure whose
- * properties are determined by default GUI settings), and buildMainDisplayArea()
- * to contain application-specific displays of parameters and results.
- */
- public void go() {
- theWindow = this;
- this.isBeingUsedAsAMarsTool = false;
- thisMarsApp.setTitle(this.title);
- mars.Globals.initialize(true);
- // assure the dialog goes away if user clicks the X
- thisMarsApp.addWindowListener(
- new WindowAdapter() {
- public void windowClosing(WindowEvent e) {
- performAppClosingDuties();
- }
- });
- initializePreGUI();
-
- JPanel contentPane = new JPanel(new BorderLayout(5,5));
- contentPane.setBorder(emptyBorder);
- contentPane.setOpaque(true);
- contentPane.add(buildHeadingArea(), BorderLayout.NORTH);
- contentPane.add(buildMainDisplayArea(), BorderLayout.CENTER);
- contentPane.add(buildButtonAreaStandAlone(), BorderLayout.SOUTH);
-
- thisMarsApp.setContentPane(contentPane);
- thisMarsApp.pack();
- thisMarsApp.setLocationRelativeTo(null); // center on screen
- thisMarsApp.setVisible(true);
- initializePostGUI();
- }
-
-
- /**
- * Required MarsTool method to carry out Tool functions. It is invoked when MARS
- * user selects this tool from the Tools menu. This default implementation provides
- * generic definitions for interactively controlling the tool. The generic controls
- * for MarsTools are 3 buttons: connect/disconnect to MIPS resource (memory and/or
- * registers), reset, and close (exit). Like "go()" above, this default version
- * calls 3 methods that can be defined/overriden in the subclass: initializePreGUI()
- * for any special initialization that must be completed before building the user
- * interface (e.g. data structures whose properties determine default GUI settings),
- * initializePostGUI() for any special initialization that cannot be
- * completed until after the building the user interface (e.g. data structure whose
- * properties are determined by default GUI settings), and buildMainDisplayArea()
- * to contain application-specific displays of parameters and results.
- */
-
- public void action() {
- this.isBeingUsedAsAMarsTool = true;
- dialog = new JDialog(Globals.getGui(), this.title);
- // assure the dialog goes away if user clicks the X
- dialog.addWindowListener(
- new WindowAdapter() {
- public void windowClosing(WindowEvent e) {
- performToolClosingDuties();
- }
- });
- theWindow = dialog;
- initializePreGUI();
- JPanel contentPane = new JPanel(new BorderLayout(5,5));
- contentPane.setBorder(emptyBorder);
- contentPane.setOpaque(true);
- contentPane.add(buildHeadingArea(), BorderLayout.NORTH);
- contentPane.add(buildMainDisplayArea(),BorderLayout.CENTER);
- contentPane.add(buildButtonAreaMarsTool(), BorderLayout.SOUTH);
- initializePostGUI();
- dialog.setContentPane(contentPane);
- dialog.pack();
- dialog.setLocationRelativeTo(Globals.getGui());
- dialog.setVisible(true);
- }
-
-
- /**
- * Method that will be called once just before the GUI is constructed in the go() and action()
- * methods. Use it to initialize any data structures needed for the application whose values
- * will be needed to determine the initial state of GUI components. By default it does nothing.
- */
- protected void initializePreGUI() {
- }
-
- /**
- * Method that will be called once just after the GUI is constructed in the go() and action()
- * methods. Use it to initialize data structures needed for the application whose values
- * may depend on the initial state of GUI components. By default it does nothing.
- */
- protected void initializePostGUI() {
- }
-
- /**
- * Method that will be called each time the default Reset button is clicked.
- * Use it to reset any data structures and/or GUI components. By default it does nothing.
- */
- protected void reset() {
- }
-
-
- /**
- * Constructs GUI header as label with default positioning and font. May be overridden.
- */
- protected JComponent buildHeadingArea() {
- // OVERALL STRUCTURE OF MESSAGE (TOP)
- headingLabel = new JLabel();
- Box headingPanel = Box.createHorizontalBox();//new JPanel(new BorderLayout());
- headingPanel.add(Box.createHorizontalGlue());
- headingPanel.add(headingLabel);
- headingPanel.add(Box.createHorizontalGlue());
- // Details for heading area (top)
- headingLabel.setText(heading);
- headingLabel.setHorizontalTextPosition(JLabel.CENTER);
- headingLabel.setFont(new Font(headingLabel.getFont().getFontName(),Font.PLAIN,18));
- return headingPanel;
- }
-
-
-
- /**
- * The MarsTool default set of controls has one row of 3 buttons. It includes a dual-purpose button to
- * attach or detach simulator to MIPS memory, a button to reset the cache, and one to close the tool.
- */
- protected JComponent buildButtonAreaMarsTool() {
- Box buttonArea = Box.createHorizontalBox();
- TitledBorder tc =new TitledBorder("Tool Control");
- tc.setTitleJustification(TitledBorder.CENTER);
- buttonArea.setBorder(tc);
- connectButton = new ConnectButton();
- connectButton.setToolTipText("Control whether tool will respond to running MIPS program");
- connectButton.addActionListener(
- new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- if (connectButton.isConnected()) {
+
+/**
+ * An abstract class that provides generic components to facilitate implementation of a MarsTool and/or stand-alone
+ * Mars-based application. Provides default definitions of both the action() method required to implement MarsTool and
+ * the go() method conventionally used to launch a Mars-based stand-alone application. It also provides generic
+ * definitions for interactively controlling the application. The generic controls for MarsTools are 3 buttons:
+ * connect/disconnect to MIPS resource (memory and/or registers), reset, and close (exit). The generic controls for
+ * stand-alone Mars apps include: button that triggers a file open dialog, a text field to display status messages, the
+ * run-speed slider to control execution rate when running a MIPS program, a button that assembles and runs the current
+ * MIPS program, a button to interrupt the running MIPS program, a reset button, and an exit button. Pete Sanderson, 14
+ * November 2006.
+ */
+public abstract class AbstractMarsToolAndApplication extends JFrame implements MarsTool, Observer
+{
+ protected boolean isBeingUsedAsAMarsTool = false; // can use to determine whether invoked as MarsTool or stand-alone.
+
+ protected AbstractMarsToolAndApplication thisMarsApp;
+
+ protected Window theWindow; // highest level GUI component (a JFrame for app, a JDialog for MarsTool)
+
+ // Structure required for MarsTool use only (not stand-alone use). Want subclasses to have access.
+ protected ConnectButton connectButton;
+
+ // Major GUI components
+ JLabel headingLabel;
+
+ private JDialog dialog; // used only for MarsTool use. This is the pop-up dialog that appears when menu item selected.
+
+ private final String title; // descriptive title for title bar provided to constructor.
+
+ private final String heading; // Text to be displayed in the top portion of the main window.
+
+ // Some GUI settings
+ private final EmptyBorder emptyBorder = new EmptyBorder(4, 4, 4, 4);
+
+ private final Color backgroundColor = Color.WHITE;
+
+ private final int lowMemoryAddress = Memory.dataSegmentBaseAddress;
+
+ private final int highMemoryAddress = Memory.stackBaseAddress;
+
+ // For MarsTool, is set true when "Connect" clicked, false when "Disconnect" clicked.
+ // For app, is set true when "Assemble and Run" clicked, false when program terminates.
+ private volatile boolean observing = false;
+
+ // Several structures required for stand-alone use only (not MarsTool use)
+ private File mostRecentlyOpenedFile = null;
+
+ private final Runnable interactiveGUIUpdater = new GUIUpdater();
+
+ private MessageField operationStatusMessages;
+
+ private JButton openFileButton, assembleRunButton, stopButton;
+
+ private boolean multiFileAssemble = false;
+
+
+ /**
+ * Simple constructor
+ *
+ * @param title String containing title bar text
+ */
+ protected AbstractMarsToolAndApplication(String title, String heading)
+ {
+ thisMarsApp = this;
+ this.title = title;
+ this.heading = heading;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////// ABSTRACT METHODS ///////////////////////////
+ //////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Required MarsTool method to return Tool name. Must be defined by subclass.
+ *
+ * @return Tool name. MARS will display this in menu item.
+ */
+ public abstract String getName();
+
+ /**
+ * Abstract method that must be instantiated by subclass to build the main display area of the GUI. It will be
+ * placed in the CENTER area of a BorderLayout. The title is in the NORTH area, and the controls are in the SOUTH
+ * area.
+ */
+ protected abstract JComponent buildMainDisplayArea();
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ ///////////////////////////// METHODS WITH DEFAULT IMPLEMENTATIONS //////////////////
+ //////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Run the simulator as stand-alone application. For this default implementation, the user-defined main display of
+ * the user interface is identical for both stand-alone and MARS Tools menu use, but the control buttons are
+ * different because the stand-alone must include a mechansim for controlling the opening, assembling, and executing
+ * of an underlying MIPS program. The generic controls include: a button that triggers a file open dialog, a text
+ * field to display status messages, the run-speed slider to control execution rate when running a MIPS program, a
+ * button that assembles and runs the current MIPS program, a reset button, and an exit button. This method calls 3
+ * methods that can be defined/overriden in the subclass: initializePreGUI() for any special initialization that
+ * must be completed before building the user interface (e.g. data structures whose properties determine default GUI
+ * settings), initializePostGUI() for any special initialization that cannot be completed until after the building
+ * the user interface (e.g. data structure whose properties are determined by default GUI settings), and
+ * buildMainDisplayArea() to contain application-specific displays of parameters and results.
+ */
+ public void go()
+ {
+ theWindow = this;
+ this.isBeingUsedAsAMarsTool = false;
+ thisMarsApp.setTitle(this.title);
+ mars.Globals.initialize(true);
+ // assure the dialog goes away if user clicks the X
+ thisMarsApp.addWindowListener(
+ new WindowAdapter()
+ {
+ public void windowClosing(WindowEvent e)
+ {
+ performAppClosingDuties();
+ }
+ });
+ initializePreGUI();
+
+ JPanel contentPane = new JPanel(new BorderLayout(5, 5));
+ contentPane.setBorder(emptyBorder);
+ contentPane.setOpaque(true);
+ contentPane.add(buildHeadingArea(), BorderLayout.NORTH);
+ contentPane.add(buildMainDisplayArea(), BorderLayout.CENTER);
+ contentPane.add(buildButtonAreaStandAlone(), BorderLayout.SOUTH);
+
+ thisMarsApp.setContentPane(contentPane);
+ thisMarsApp.pack();
+ thisMarsApp.setLocationRelativeTo(null); // center on screen
+ thisMarsApp.setVisible(true);
+ initializePostGUI();
+ }
+
+
+ /**
+ * Required MarsTool method to carry out Tool functions. It is invoked when MARS user selects this tool from the
+ * Tools menu. This default implementation provides generic definitions for interactively controlling the tool.
+ * The generic controls for MarsTools are 3 buttons: connect/disconnect to MIPS resource (memory and/or registers),
+ * reset, and close (exit). Like "go()" above, this default version calls 3 methods that can be defined/overriden
+ * in the subclass: initializePreGUI() for any special initialization that must be completed before building the
+ * user interface (e.g. data structures whose properties determine default GUI settings), initializePostGUI() for
+ * any special initialization that cannot be completed until after the building the user interface (e.g. data
+ * structure whose properties are determined by default GUI settings), and buildMainDisplayArea() to contain
+ * application-specific displays of parameters and results.
+ */
+
+ public void action()
+ {
+ this.isBeingUsedAsAMarsTool = true;
+ dialog = new JDialog(Globals.getGui(), this.title);
+ // assure the dialog goes away if user clicks the X
+ dialog.addWindowListener(
+ new WindowAdapter()
+ {
+ public void windowClosing(WindowEvent e)
+ {
+ performToolClosingDuties();
+ }
+ });
+ theWindow = dialog;
+ initializePreGUI();
+ JPanel contentPane = new JPanel(new BorderLayout(5, 5));
+ contentPane.setBorder(emptyBorder);
+ contentPane.setOpaque(true);
+ contentPane.add(buildHeadingArea(), BorderLayout.NORTH);
+ contentPane.add(buildMainDisplayArea(), BorderLayout.CENTER);
+ contentPane.add(buildButtonAreaMarsTool(), BorderLayout.SOUTH);
+ initializePostGUI();
+ dialog.setContentPane(contentPane);
+ dialog.pack();
+ dialog.setLocationRelativeTo(Globals.getGui());
+ dialog.setVisible(true);
+ }
+
+
+ /**
+ * Method that will be called once just before the GUI is constructed in the go() and action() methods. Use it to
+ * initialize any data structures needed for the application whose values will be needed to determine the initial
+ * state of GUI components. By default it does nothing.
+ */
+ protected void initializePreGUI()
+ {
+ }
+
+ /**
+ * Method that will be called once just after the GUI is constructed in the go() and action() methods. Use it to
+ * initialize data structures needed for the application whose values may depend on the initial state of GUI
+ * components. By default it does nothing.
+ */
+ protected void initializePostGUI()
+ {
+ }
+
+ /**
+ * Method that will be called each time the default Reset button is clicked. Use it to reset any data structures
+ * and/or GUI components. By default it does nothing.
+ */
+ protected void reset()
+ {
+ }
+
+
+ /**
+ * Constructs GUI header as label with default positioning and font. May be overridden.
+ */
+ protected JComponent buildHeadingArea()
+ {
+ // OVERALL STRUCTURE OF MESSAGE (TOP)
+ headingLabel = new JLabel();
+ Box headingPanel = Box.createHorizontalBox();//new JPanel(new BorderLayout());
+ headingPanel.add(Box.createHorizontalGlue());
+ headingPanel.add(headingLabel);
+ headingPanel.add(Box.createHorizontalGlue());
+ // Details for heading area (top)
+ headingLabel.setText(heading);
+ headingLabel.setHorizontalTextPosition(JLabel.CENTER);
+ headingLabel.setFont(new Font(headingLabel.getFont().getFontName(), Font.PLAIN, 18));
+ return headingPanel;
+ }
+
+
+ /**
+ * The MarsTool default set of controls has one row of 3 buttons. It includes a dual-purpose button to attach or
+ * detach simulator to MIPS memory, a button to reset the cache, and one to close the tool.
+ */
+ protected JComponent buildButtonAreaMarsTool()
+ {
+ Box buttonArea = Box.createHorizontalBox();
+ TitledBorder tc = new TitledBorder("Tool Control");
+ tc.setTitleJustification(TitledBorder.CENTER);
+ buttonArea.setBorder(tc);
+ connectButton = new ConnectButton();
+ connectButton.setToolTipText("Control whether tool will respond to running MIPS program");
+ connectButton.addActionListener(
+ new ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ if (connectButton.isConnected())
+ {
connectButton.disconnect();
- }
- else {
+ }
+ else
+ {
connectButton.connect();
- }
- }
- });
- connectButton.addKeyListener(new EnterKeyListener(connectButton));
-
- JButton resetButton = new JButton("Reset");
- resetButton.setToolTipText("Reset all counters and other structures");
- resetButton.addActionListener(
- new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- reset();
- }
- });
- resetButton.addKeyListener(new EnterKeyListener(resetButton));
-
- JButton closeButton = new JButton("Close");
- closeButton.setToolTipText("Close (exit) this tool");
- closeButton.addActionListener(
- new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- performToolClosingDuties();
- }
- });
- closeButton.addKeyListener(new EnterKeyListener(closeButton));
-
- // Add all the buttons...
- buttonArea.add(connectButton);
- buttonArea.add(Box.createHorizontalGlue());
- buttonArea.add(resetButton);
- buttonArea.add(Box.createHorizontalGlue());
- JComponent helpComponent = getHelpComponent();
- if (helpComponent != null) {
+ }
+ }
+ });
+ connectButton.addKeyListener(new EnterKeyListener(connectButton));
+
+ JButton resetButton = new JButton("Reset");
+ resetButton.setToolTipText("Reset all counters and other structures");
+ resetButton.addActionListener(
+ new ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ reset();
+ }
+ });
+ resetButton.addKeyListener(new EnterKeyListener(resetButton));
+
+ JButton closeButton = new JButton("Close");
+ closeButton.setToolTipText("Close (exit) this tool");
+ closeButton.addActionListener(
+ new ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ performToolClosingDuties();
+ }
+ });
+ closeButton.addKeyListener(new EnterKeyListener(closeButton));
+
+ // Add all the buttons...
+ buttonArea.add(connectButton);
+ buttonArea.add(Box.createHorizontalGlue());
+ buttonArea.add(resetButton);
+ buttonArea.add(Box.createHorizontalGlue());
+ JComponent helpComponent = getHelpComponent();
+ if (helpComponent != null)
+ {
buttonArea.add(helpComponent);
buttonArea.add(Box.createHorizontalGlue());
- }
- buttonArea.add(closeButton);
- return buttonArea;
- }
-
- /**
- * The Mars stand-alone app default set of controls has two rows of controls. It includes a text field for
- * displaying status messages, a button to trigger an open file dialog, the MARS run speed slider
- * to control timed execution, a button to assemble and run the program, a reset button
- * whose action is determined by the subclass reset() method, and an exit button.
- */
-
- protected JComponent buildButtonAreaStandAlone() {
- // Overall structure of control area (two rows).
- Box operationArea = Box.createVerticalBox();
- Box fileControlArea = Box.createHorizontalBox();
- Box buttonArea = Box.createHorizontalBox();
- operationArea.add(fileControlArea);
- operationArea.add(Box.createVerticalStrut(5));
- operationArea.add(buttonArea);
- TitledBorder ac =new TitledBorder("Application Control");
- ac.setTitleJustification(TitledBorder.CENTER);
- operationArea.setBorder(ac);
-
- // Top row of controls consists of button to launch file open operation,
- // text field to show filename, and run speed slider.
- openFileButton = new JButton("Open MIPS program...");
- openFileButton.setToolTipText("Select MIPS program file to assemble and run");
- openFileButton.addActionListener(
- new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- JFileChooser fileChooser = new JFileChooser();
- JCheckBox multiFileAssembleChoose = new JCheckBox("Assemble all in selected file's directory",multiFileAssemble);
- multiFileAssembleChoose.setToolTipText("If checked, selected file will be assembled first and all other assembly files in directory will be assembled also.");
- fileChooser.setAccessory(multiFileAssembleChoose);
- if (mostRecentlyOpenedFile != null) {
+ }
+ buttonArea.add(closeButton);
+ return buttonArea;
+ }
+
+ /**
+ * The Mars stand-alone app default set of controls has two rows of controls. It includes a text field for
+ * displaying status messages, a button to trigger an open file dialog, the MARS run speed slider to control timed
+ * execution, a button to assemble and run the program, a reset button whose action is determined by the subclass
+ * reset() method, and an exit button.
+ */
+
+ protected JComponent buildButtonAreaStandAlone()
+ {
+ // Overall structure of control area (two rows).
+ Box operationArea = Box.createVerticalBox();
+ Box fileControlArea = Box.createHorizontalBox();
+ Box buttonArea = Box.createHorizontalBox();
+ operationArea.add(fileControlArea);
+ operationArea.add(Box.createVerticalStrut(5));
+ operationArea.add(buttonArea);
+ TitledBorder ac = new TitledBorder("Application Control");
+ ac.setTitleJustification(TitledBorder.CENTER);
+ operationArea.setBorder(ac);
+
+ // Top row of controls consists of button to launch file open operation,
+ // text field to show filename, and run speed slider.
+ openFileButton = new JButton("Open MIPS program...");
+ openFileButton.setToolTipText("Select MIPS program file to assemble and run");
+ openFileButton.addActionListener(
+ new ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ JFileChooser fileChooser = new JFileChooser();
+ JCheckBox multiFileAssembleChoose = new JCheckBox("Assemble all in selected file's directory", multiFileAssemble);
+ multiFileAssembleChoose.setToolTipText("If checked, selected file will be assembled first and all other assembly files in directory will be assembled also.");
+ fileChooser.setAccessory(multiFileAssembleChoose);
+ if (mostRecentlyOpenedFile != null)
+ {
fileChooser.setSelectedFile(mostRecentlyOpenedFile);
- }
- // DPS 13 June 2007. The next 4 lines add file filter to file chooser.
- FileFilter defaultFileFilter = FilenameFinder.getFileFilter(Globals.fileExtensions, "Assembler Files", true);
- fileChooser.addChoosableFileFilter(defaultFileFilter);
- fileChooser.addChoosableFileFilter(fileChooser.getAcceptAllFileFilter());
- fileChooser.setFileFilter(defaultFileFilter);
-
- if (fileChooser.showOpenDialog(thisMarsApp) == JFileChooser.APPROVE_OPTION) {
+ }
+ // DPS 13 June 2007. The next 4 lines add file filter to file chooser.
+ FileFilter defaultFileFilter = FilenameFinder.getFileFilter(Globals.fileExtensions, "Assembler Files", true);
+ fileChooser.addChoosableFileFilter(defaultFileFilter);
+ fileChooser.addChoosableFileFilter(fileChooser.getAcceptAllFileFilter());
+ fileChooser.setFileFilter(defaultFileFilter);
+
+ if (fileChooser.showOpenDialog(thisMarsApp) == JFileChooser.APPROVE_OPTION)
+ {
multiFileAssemble = multiFileAssembleChoose.isSelected();
File theFile = fileChooser.getSelectedFile();
- try {
- theFile = theFile.getCanonicalFile();
- }
- catch (IOException ioe) {
- // nothing to do, theFile will keep current value
- }
+ try
+ {
+ theFile = theFile.getCanonicalFile();
+ }
+ catch (IOException ioe)
+ {
+ // nothing to do, theFile will keep current value
+ }
String currentFilePath = theFile.getPath();
mostRecentlyOpenedFile = theFile;
- operationStatusMessages.setText("File: "+currentFilePath);
+ operationStatusMessages.setText("File: " + currentFilePath);
operationStatusMessages.setCaretPosition(0);
assembleRunButton.setEnabled(true);
- }
- }
- });
- openFileButton.addKeyListener(new EnterKeyListener(openFileButton));
-
- operationStatusMessages = new MessageField("No file open.");
- operationStatusMessages.setColumns(40);
- operationStatusMessages.setMargin(new Insets(0, 3, 0, 3)); //(top, left, bottom, right)
- operationStatusMessages.setBackground(backgroundColor);
- operationStatusMessages.setFocusable(false);
- operationStatusMessages.setToolTipText("Display operation status messages");
-
- mars.venus.RunSpeedPanel speed = mars.venus.RunSpeedPanel.getInstance();
-
- // Bottom row of controls consists of the three buttons defined here.
- assembleRunButton = new JButton("Assemble and Run");
- assembleRunButton.setToolTipText("Assemble and run the currently selected MIPS program");
- assembleRunButton.setEnabled(false);
- assembleRunButton.addActionListener(
- new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- assembleRunButton.setEnabled(false);
- openFileButton.setEnabled(false);
- stopButton.setEnabled(true);
- new Thread(new CreateAssembleRunMIPSprogram()).start();
- }
- });
- assembleRunButton.addKeyListener(new EnterKeyListener(assembleRunButton));
-
- stopButton = new JButton("Stop");
- stopButton.setToolTipText("Terminate MIPS program execution");
- stopButton.setEnabled(false);
- stopButton.addActionListener(
- new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- mars.simulator.Simulator.getInstance().stopExecution(null);
- }
- });
- stopButton.addKeyListener(new EnterKeyListener(stopButton));
-
- JButton resetButton = new JButton("Reset");
- resetButton.setToolTipText("Reset all counters and other structures");
- resetButton.addActionListener(
- new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- reset();
- }
- });
- resetButton.addKeyListener(new EnterKeyListener(resetButton));
-
- JButton closeButton = new JButton("Exit");
- closeButton.setToolTipText("Exit this application");
- closeButton.addActionListener(
- new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- performAppClosingDuties();
- }
- });
- closeButton.addKeyListener(new EnterKeyListener(closeButton));
-
-
- // Add top row of controls...
- //fileControlArea.add(Box.createHorizontalStrut(5));
-
- Box fileDisplayBox = Box.createVerticalBox();
- fileDisplayBox.add(Box.createVerticalStrut(8));
- fileDisplayBox.add(operationStatusMessages);
- fileDisplayBox.add(Box.createVerticalStrut(8));
- fileControlArea.add(fileDisplayBox);
-
- fileControlArea.add(Box.createHorizontalGlue());
- fileControlArea.add(speed);
-
- // Add bottom row of buttons...
-
- buttonArea.add(openFileButton);
- buttonArea.add(Box.createHorizontalGlue());
- buttonArea.add(assembleRunButton);
- buttonArea.add(Box.createHorizontalGlue());
- buttonArea.add(stopButton);
- buttonArea.add(Box.createHorizontalGlue());
- buttonArea.add(resetButton);
- buttonArea.add(Box.createHorizontalGlue());
- JComponent helpComponent = getHelpComponent();
- if (helpComponent != null) {
+ }
+ }
+ });
+ openFileButton.addKeyListener(new EnterKeyListener(openFileButton));
+
+ operationStatusMessages = new MessageField("No file open.");
+ operationStatusMessages.setColumns(40);
+ operationStatusMessages.setMargin(new Insets(0, 3, 0, 3)); //(top, left, bottom, right)
+ operationStatusMessages.setBackground(backgroundColor);
+ operationStatusMessages.setFocusable(false);
+ operationStatusMessages.setToolTipText("Display operation status messages");
+
+ mars.venus.RunSpeedPanel speed = mars.venus.RunSpeedPanel.getInstance();
+
+ // Bottom row of controls consists of the three buttons defined here.
+ assembleRunButton = new JButton("Assemble and Run");
+ assembleRunButton.setToolTipText("Assemble and run the currently selected MIPS program");
+ assembleRunButton.setEnabled(false);
+ assembleRunButton.addActionListener(
+ new ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ assembleRunButton.setEnabled(false);
+ openFileButton.setEnabled(false);
+ stopButton.setEnabled(true);
+ new Thread(new CreateAssembleRunMIPSprogram()).start();
+ }
+ });
+ assembleRunButton.addKeyListener(new EnterKeyListener(assembleRunButton));
+
+ stopButton = new JButton("Stop");
+ stopButton.setToolTipText("Terminate MIPS program execution");
+ stopButton.setEnabled(false);
+ stopButton.addActionListener(
+ new ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ mars.simulator.Simulator.getInstance().stopExecution(null);
+ }
+ });
+ stopButton.addKeyListener(new EnterKeyListener(stopButton));
+
+ JButton resetButton = new JButton("Reset");
+ resetButton.setToolTipText("Reset all counters and other structures");
+ resetButton.addActionListener(
+ new ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ reset();
+ }
+ });
+ resetButton.addKeyListener(new EnterKeyListener(resetButton));
+
+ JButton closeButton = new JButton("Exit");
+ closeButton.setToolTipText("Exit this application");
+ closeButton.addActionListener(
+ new ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ performAppClosingDuties();
+ }
+ });
+ closeButton.addKeyListener(new EnterKeyListener(closeButton));
+
+
+ // Add top row of controls...
+ //fileControlArea.add(Box.createHorizontalStrut(5));
+
+ Box fileDisplayBox = Box.createVerticalBox();
+ fileDisplayBox.add(Box.createVerticalStrut(8));
+ fileDisplayBox.add(operationStatusMessages);
+ fileDisplayBox.add(Box.createVerticalStrut(8));
+ fileControlArea.add(fileDisplayBox);
+
+ fileControlArea.add(Box.createHorizontalGlue());
+ fileControlArea.add(speed);
+
+ // Add bottom row of buttons...
+
+ buttonArea.add(openFileButton);
+ buttonArea.add(Box.createHorizontalGlue());
+ buttonArea.add(assembleRunButton);
+ buttonArea.add(Box.createHorizontalGlue());
+ buttonArea.add(stopButton);
+ buttonArea.add(Box.createHorizontalGlue());
+ buttonArea.add(resetButton);
+ buttonArea.add(Box.createHorizontalGlue());
+ JComponent helpComponent = getHelpComponent();
+ if (helpComponent != null)
+ {
buttonArea.add(helpComponent);
buttonArea.add(Box.createHorizontalGlue());
- }
- buttonArea.add(closeButton);
- return operationArea;
- }
-
- //////////////////////////////////////////////////////////////////////////////////////
- // Rest of the methods. Some are used by stand-alone (JFrame-based) only, some are
- // used by MarsTool (JDialog-based) only, others are used by both.
- //////////////////////////////////////////////////////////////////////////////////////
-
- /**
- * Called when receiving notice of access to MIPS memory or registers. Default
- * implementation of method required by Observer interface. This method will filter out
- * notices originating from the MARS GUI or from direct user editing of memory or register
- * displays. Only notices arising from MIPS program access are allowed in.
- * It then calls two methods to be overridden by the subclass (since they do
- * nothing by default): processMIPSUpdate() then updateDisplay().
- * @param resource the attached MIPS resource
- * @param accessNotice AccessNotice information provided by the resource
- */
- public void update(Observable resource, Object accessNotice) {
- if (((AccessNotice)accessNotice).accessIsFromMIPS()) {
- processMIPSUpdate(resource, (AccessNotice)accessNotice);
+ }
+ buttonArea.add(closeButton);
+ return operationArea;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Rest of the methods. Some are used by stand-alone (JFrame-based) only, some are
+ // used by MarsTool (JDialog-based) only, others are used by both.
+ //////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Called when receiving notice of access to MIPS memory or registers. Default implementation of method required by
+ * Observer interface. This method will filter out notices originating from the MARS GUI or from direct user
+ * editing of memory or register displays. Only notices arising from MIPS program access are allowed in. It then
+ * calls two methods to be overridden by the subclass (since they do nothing by default): processMIPSUpdate() then
+ * updateDisplay().
+ *
+ * @param resource the attached MIPS resource
+ * @param accessNotice AccessNotice information provided by the resource
+ */
+ public void update(Observable resource, Object accessNotice)
+ {
+ if (((AccessNotice) accessNotice).accessIsFromMIPS())
+ {
+ processMIPSUpdate(resource, (AccessNotice) accessNotice);
updateDisplay();
- }
- }
-
- /**
- * Override this method to process a received notice from MIPS Observable (memory or register)
- * It will only be called if the notice was generated as the result of MIPS instruction execution.
- * By default it does nothing. After this method is complete, the updateDisplay() method will be
- * invoked automatically.
- */
- protected void processMIPSUpdate(Observable resource, AccessNotice notice) {
- }
-
- /**
- * This method is called when tool/app is exited either through the close/exit button or the window's X box.
- * Override it to perform any special housecleaning needed. By default it does nothing.
- */
- protected void performSpecialClosingDuties() {
- }
-
-
- /**
- * Add this app/tool as an Observer of desired MIPS Observables (memory and registers).
- * By default, will add as an Observer of the entire Data Segment in memory.
- * Override if you want something different. Note that the Memory methods to add an
- * Observer to memory are flexible (you can register for a range of addresses) but
- * may throw an AddressErrorException that you need to catch.
- * This method is called whenever the default "Connect" button on a MarsTool or the
- * default "Assemble and run" on a stand-alone Mars app is selected. The corresponding
- * NOTE: if you do not want to register as an Observer of the entire data segment
- * (starts at address 0x10000000) then override this to either do some alternative
- * or nothing at all. This method is also overloaded to allow arbitrary memory
- * subrange.
- */
-
- protected void addAsObserver() {
- addAsObserver(lowMemoryAddress, highMemoryAddress);
- }
-
- /**
- * Add this app/tool as an Observer of the specified subrange of MIPS memory. Note
- * that this method is not invoked automatically like the no-argument version, but
- * if you use this method, you can still take advantage of provided default deleteAsObserver()
- * since it will remove the app as a memory observer regardless of the subrange
- * or number of subranges it is registered for.
- * @param lowEnd low end of memory address range.
- * @param highEnd high end of memory address range; must be >= lowEnd
- */
-
- protected void addAsObserver(int lowEnd, int highEnd) {
- String errorMessage = "Error connecting to MIPS memory";
- try {
- Globals.memory.addObserver(thisMarsApp,lowEnd, highEnd);
- }
- catch (AddressErrorException aee) {
- if (this.isBeingUsedAsAMarsTool) {
- headingLabel.setText(errorMessage);
- }
- else {
- operationStatusMessages.displayTerminatingMessage(errorMessage);
- }
- }
- }
-
- /**
- * Add this app/tool as an Observer of the specified MIPS register.
- */
- protected void addAsObserver(Register reg) {
- if (reg != null) {
+ }
+ }
+
+ /**
+ * Override this method to process a received notice from MIPS Observable (memory or register) It will only be
+ * called if the notice was generated as the result of MIPS instruction execution. By default it does nothing. After
+ * this method is complete, the updateDisplay() method will be invoked automatically.
+ */
+ protected void processMIPSUpdate(Observable resource, AccessNotice notice)
+ {
+ }
+
+ /**
+ * This method is called when tool/app is exited either through the close/exit button or the window's X box.
+ * Override it to perform any special housecleaning needed. By default it does nothing.
+ */
+ protected void performSpecialClosingDuties()
+ {
+ }
+
+
+ /**
+ * Add this app/tool as an Observer of desired MIPS Observables (memory and registers). By default, will add as an
+ * Observer of the entire Data Segment in memory. Override if you want something different. Note that the Memory
+ * methods to add an Observer to memory are flexible (you can register for a range of addresses) but may throw an
+ * AddressErrorException that you need to catch. This method is called whenever the default "Connect" button on a
+ * MarsTool or the default "Assemble and run" on a stand-alone Mars app is selected. The corresponding NOTE: if you
+ * do not want to register as an Observer of the entire data segment (starts at address 0x10000000) then override
+ * this to either do some alternative or nothing at all. This method is also overloaded to allow arbitrary memory
+ * subrange.
+ */
+
+ protected void addAsObserver()
+ {
+ addAsObserver(lowMemoryAddress, highMemoryAddress);
+ }
+
+ /**
+ * Add this app/tool as an Observer of the specified subrange of MIPS memory. Note that this method is not invoked
+ * automatically like the no-argument version, but if you use this method, you can still take advantage of provided
+ * default deleteAsObserver() since it will remove the app as a memory observer regardless of the subrange or number
+ * of subranges it is registered for.
+ *
+ * @param lowEnd low end of memory address range.
+ * @param highEnd high end of memory address range; must be >= lowEnd
+ */
+
+ protected void addAsObserver(int lowEnd, int highEnd)
+ {
+ String errorMessage = "Error connecting to MIPS memory";
+ try
+ {
+ Globals.memory.addObserver(thisMarsApp, lowEnd, highEnd);
+ }
+ catch (AddressErrorException aee)
+ {
+ if (this.isBeingUsedAsAMarsTool)
+ {
+ headingLabel.setText(errorMessage);
+ }
+ else
+ {
+ operationStatusMessages.displayTerminatingMessage(errorMessage);
+ }
+ }
+ }
+
+ /**
+ * Add this app/tool as an Observer of the specified MIPS register.
+ */
+ protected void addAsObserver(Register reg)
+ {
+ if (reg != null)
+ {
reg.addObserver(thisMarsApp);
- }
- }
-
-
- /**
- * Delete this app/tool as an Observer of MIPS Observables (memory and registers).
- * By default, will delete as an Observer of memory.
- * Override if you want something different.
- * This method is called when the default "Disconnect" button on a MarsTool is selected or
- * when the MIPS program execution triggered by the default "Assemble and run" on a stand-alone
- * Mars app terminates (e.g. when the button is re-enabled).
- */
-
- protected void deleteAsObserver() {
- Globals.memory.deleteObserver(thisMarsApp);
- }
-
- /**
- * Delete this app/tool as an Observer of the specified MIPS register
- */
-
- protected void deleteAsObserver(Register reg) {
- if (reg != null) {
+ }
+ }
+
+
+ /**
+ * Delete this app/tool as an Observer of MIPS Observables (memory and registers). By default, will delete as an
+ * Observer of memory. Override if you want something different. This method is called when the default "Disconnect"
+ * button on a MarsTool is selected or when the MIPS program execution triggered by the default "Assemble and run"
+ * on a stand-alone Mars app terminates (e.g. when the button is re-enabled).
+ */
+
+ protected void deleteAsObserver()
+ {
+ Globals.memory.deleteObserver(thisMarsApp);
+ }
+
+ /**
+ * Delete this app/tool as an Observer of the specified MIPS register
+ */
+
+ protected void deleteAsObserver(Register reg)
+ {
+ if (reg != null)
+ {
reg.deleteObserver(thisMarsApp);
- }
- }
-
- /**
- * Query method to let you know if the tool/app is (or could be) currently
- * "observing" any MIPS resources. When running as a MarsTool, this
- * will be true by default after clicking the "Connect to MIPS" button until "Disconnect
- * from MIPS" is clicked. When running as a stand-alone app, this will be
- * true by default after clicking the "Assemble and Run" button until until
- * program execution has terminated either normally or by clicking the "Stop"
- * button. The phrase "or could be" was added above because depending on how
- * the tool/app operates, it may be possible to run the MIPS program without
- * first registering as an Observer -- i.e. addAsObserver() is overridden and
- * takes no action.
- * @return true if tool/app is (or could be) currently active as an Observer.
- */
-
- protected boolean isObserving() {
- return observing;
- }
-
- /**
- * Override this method to implement updating of GUI after each MIPS instruction is executed,
- * while running in "timed" mode (user specifies execution speed on the slider control).
- * Does nothing by default.
- */
- protected void updateDisplay() {
- }
-
- /**
- * Override this method to provide a JComponent (probably a JButton) of your choice
- * to be placed just left of the Close/Exit button. Its anticipated use is for a
- * "help" button that launches a help message or dialog. But it can be any valid
- * JComponent that doesn't mind co-existing among a bunch of JButtons.
- */
- protected JComponent getHelpComponent() {
- return null;
- }
-
- //////////////////////////////////////////////////////////////////////////////////
- //////////////////// PRIVATE HELPER METHODS //////////////////////////////////
- //////////////////////////////////////////////////////////////////////////////////
-
- // Closing duties for MarsTool only.
- private void performToolClosingDuties() {
- performSpecialClosingDuties();
- if (connectButton.isConnected()) {
+ }
+ }
+
+ /**
+ * Query method to let you know if the tool/app is (or could be) currently "observing" any MIPS resources. When
+ * running as a MarsTool, this will be true by default after clicking the "Connect to MIPS" button until "Disconnect
+ * from MIPS" is clicked. When running as a stand-alone app, this will be true by default after clicking the
+ * "Assemble and Run" button until until program execution has terminated either normally or by clicking the "Stop"
+ * button. The phrase "or could be" was added above because depending on how the tool/app operates, it may be
+ * possible to run the MIPS program without first registering as an Observer -- i.e. addAsObserver() is overridden
+ * and takes no action.
+ *
+ * @return true if tool/app is (or could be) currently active as an Observer.
+ */
+
+ protected boolean isObserving()
+ {
+ return observing;
+ }
+
+ /**
+ * Override this method to implement updating of GUI after each MIPS instruction is executed, while running in
+ * "timed" mode (user specifies execution speed on the slider control). Does nothing by default.
+ */
+ protected void updateDisplay()
+ {
+ }
+
+ /**
+ * Override this method to provide a JComponent (probably a JButton) of your choice to be placed just left of the
+ * Close/Exit button. Its anticipated use is for a "help" button that launches a help message or dialog. But it
+ * can be any valid JComponent that doesn't mind co-existing among a bunch of JButtons.
+ */
+ protected JComponent getHelpComponent()
+ {
+ return null;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////
+ //////////////////// PRIVATE HELPER METHODS //////////////////////////////////
+ //////////////////////////////////////////////////////////////////////////////////
+
+ // Closing duties for MarsTool only.
+ private void performToolClosingDuties()
+ {
+ performSpecialClosingDuties();
+ if (connectButton.isConnected())
+ {
connectButton.disconnect();
- }
- dialog.setVisible(false);
- dialog.dispose();
- }
-
- // Closing duties for stand-alone application only.
- private void performAppClosingDuties() {
- performSpecialClosingDuties();
- thisMarsApp.setVisible(false);
- System.exit(0);
- }
-
-
- //////////////////////////////////////////////////////////////////////////////////
- //////////////////// PRIVATE HELPER CLASSES //////////////////////////////////
- // Specialized inner classes. Either used by stand-alone (JFrame-based) only //
- // or used by MarsTool (JDialog-based) only. //
- //////////////////////////////////////////////////////////////////////////////////
-
- //////////////////////////////////////////////////////////////////////
- // Little class for this dual-purpose button. It is used only by the MarsTool
- // (not by the stand-alone app).
- protected class ConnectButton extends JButton {
- private static final String connectText = "Connect to MIPS";
- private static final String disconnectText = "Disconnect from MIPS";
-
- public ConnectButton() {
+ }
+ dialog.setVisible(false);
+ dialog.dispose();
+ }
+
+ // Closing duties for stand-alone application only.
+ private void performAppClosingDuties()
+ {
+ performSpecialClosingDuties();
+ thisMarsApp.setVisible(false);
+ System.exit(0);
+ }
+
+
+ //////////////////////////////////////////////////////////////////////////////////
+ //////////////////// PRIVATE HELPER CLASSES //////////////////////////////////
+ // Specialized inner classes. Either used by stand-alone (JFrame-based) only //
+ // or used by MarsTool (JDialog-based) only. //
+ //////////////////////////////////////////////////////////////////////////////////
+
+ //////////////////////////////////////////////////////////////////////
+ // Little class for this dual-purpose button. It is used only by the MarsTool
+ // (not by the stand-alone app).
+ protected class ConnectButton extends JButton
+ {
+ private static final String connectText = "Connect to MIPS";
+
+ private static final String disconnectText = "Disconnect from MIPS";
+
+ public ConnectButton()
+ {
super();
disconnect();
- }
-
- public void connect() {
+ }
+
+ public void connect()
+ {
observing = true;
- synchronized (Globals.memoryAndRegistersLock) {// DPS 23 July 2008
- addAsObserver();
+ synchronized (Globals.memoryAndRegistersLock)
+ {// DPS 23 July 2008
+ addAsObserver();
}
setText(disconnectText);
- }
-
- public void disconnect() {
- synchronized (Globals.memoryAndRegistersLock) {// DPS 23 July 2008
- deleteAsObserver();
+ }
+
+ public void disconnect()
+ {
+ synchronized (Globals.memoryAndRegistersLock)
+ {// DPS 23 July 2008
+ deleteAsObserver();
}
observing = false;
setText(connectText);
- }
-
- public boolean isConnected() {
+ }
+
+ public boolean isConnected()
+ {
return observing;
- }
- }
-
-
- ///////////////////////////////////////////////////////////////////////
- // Every control button will get one of these so when it has focus
- // the Enter key can be used instead of a mouse click to perform
- // its associated action. It will do nothing if no action listeners
- // are attached to the button at the time of the call. Otherwise,
- // it will call actionPerformed for the first action listener in the
- // button's list.
- protected class EnterKeyListener extends KeyAdapter {
- AbstractButton myButton;
- public EnterKeyListener(AbstractButton who) {
+ }
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////
+ // Every control button will get one of these so when it has focus
+ // the Enter key can be used instead of a mouse click to perform
+ // its associated action. It will do nothing if no action listeners
+ // are attached to the button at the time of the call. Otherwise,
+ // it will call actionPerformed for the first action listener in the
+ // button's list.
+ protected class EnterKeyListener extends KeyAdapter
+ {
+ AbstractButton myButton;
+
+ public EnterKeyListener(AbstractButton who)
+ {
myButton = who;
- }
- public void keyPressed(KeyEvent e) {
- if (e.getKeyChar()== KeyEvent.VK_ENTER) {
- e.consume();
- try {
- myButton.getActionListeners()[0].actionPerformed(new ActionEvent(myButton, 0, myButton.getText()));
- }
- catch (ArrayIndexOutOfBoundsException oob) {
- // do nothing, since there is no action listener.
- }
+ }
+
+ public void keyPressed(KeyEvent e)
+ {
+ if (e.getKeyChar() == KeyEvent.VK_ENTER)
+ {
+ e.consume();
+ try
+ {
+ myButton.getActionListeners()[0].actionPerformed(new ActionEvent(myButton, 0, myButton.getText()));
+ }
+ catch (ArrayIndexOutOfBoundsException oob)
+ {
+ // do nothing, since there is no action listener.
+ }
}
- }
- }
-
- /////////////////////////////////////////////////////////////////////////////////
- // called when the Assemble and Run button is pressed. Used only by stand-alone app.
- private class CreateAssembleRunMIPSprogram implements Runnable {
- public void run() {
+ }
+ }
+
+ /////////////////////////////////////////////////////////////////////////////////
+ // called when the Assemble and Run button is pressed. Used only by stand-alone app.
+ private class CreateAssembleRunMIPSprogram implements Runnable
+ {
+ public void run()
+ {
String noSupportForExceptionHandler = null; // no auto-loaded exception handlers.
- // boolean extendedAssemblerEnabled = true; // In this context, no reason to constrain.
- // boolean warningsAreErrors = false; // Ditto.
-
+ // boolean extendedAssemblerEnabled = true; // In this context, no reason to constrain.
+ // boolean warningsAreErrors = false; // Ditto.
+
String exceptionHandler = null;
if (Globals.getSettings().getExceptionHandlerEnabled() &&
- Globals.getSettings().getExceptionHandler() != null &&
- Globals.getSettings().getExceptionHandler().length() > 0) {
- exceptionHandler = Globals.getSettings().getExceptionHandler();
+ Globals.getSettings().getExceptionHandler() != null &&
+ Globals.getSettings().getExceptionHandler().length() > 0)
+ {
+ exceptionHandler = Globals.getSettings().getExceptionHandler();
}
-
- Thread.currentThread().setPriority(Thread.NORM_PRIORITY-1);
+
+ Thread.currentThread().setPriority(Thread.NORM_PRIORITY - 1);
Thread.yield();
MIPSprogram program = new MIPSprogram();
mars.Globals.program = program; // Shouldn't have to do this...
String fileToAssemble = mostRecentlyOpenedFile.getPath();
ArrayList filesToAssemble = null;
- if (multiFileAssemble) {// setting (check box in file open dialog) calls for multiple file assembly
- filesToAssemble = FilenameFinder.getFilenameList(
- new File(fileToAssemble).getParent(), Globals.fileExtensions);
- }
- else {
- filesToAssemble = new ArrayList();
- filesToAssemble.add(fileToAssemble);
+ if (multiFileAssemble)
+ {// setting (check box in file open dialog) calls for multiple file assembly
+ filesToAssemble = FilenameFinder.getFilenameList(
+ new File(fileToAssemble).getParent(), Globals.fileExtensions);
+ }
+ else
+ {
+ filesToAssemble = new ArrayList();
+ filesToAssemble.add(fileToAssemble);
}
ArrayList programsToAssemble = null;
- try {
- operationStatusMessages.displayNonTerminatingMessage("Assembling "+fileToAssemble);
- programsToAssemble = program.prepareFilesForAssembly(filesToAssemble, fileToAssemble, exceptionHandler);
- }
- catch (mars.ProcessingException pe) {
- operationStatusMessages.displayTerminatingMessage("Error reading file(s): "+fileToAssemble);
- return;
- }
-
- try {
- program.assemble(programsToAssemble, Globals.getSettings().getExtendedAssemblerEnabled(), Globals.getSettings().getWarningsAreErrors());
+ try
+ {
+ operationStatusMessages.displayNonTerminatingMessage("Assembling " + fileToAssemble);
+ programsToAssemble = program.prepareFilesForAssembly(filesToAssemble, fileToAssemble, exceptionHandler);
}
- catch (mars.ProcessingException pe) {
- operationStatusMessages.displayTerminatingMessage("Assembly Error: "+fileToAssemble);
- return;
- }
- // Moved these three register resets from before the try block to after it. 17-Dec-09 DPS.
+ catch (mars.ProcessingException pe)
+ {
+ operationStatusMessages.displayTerminatingMessage("Error reading file(s): " + fileToAssemble);
+ return;
+ }
+
+ try
+ {
+ program.assemble(programsToAssemble, Globals.getSettings().getExtendedAssemblerEnabled(), Globals.getSettings().getWarningsAreErrors());
+ }
+ catch (mars.ProcessingException pe)
+ {
+ operationStatusMessages.displayTerminatingMessage("Assembly Error: " + fileToAssemble);
+ return;
+ }
+ // Moved these three register resets from before the try block to after it. 17-Dec-09 DPS.
RegisterFile.resetRegisters();
Coprocessor1.resetRegisters();
Coprocessor0.resetRegisters();
-
+
addAsObserver();
observing = true;
String terminatingMessage = "Normal termination: ";
- try {
- operationStatusMessages.displayNonTerminatingMessage("Running "+fileToAssemble);
- program.simulate(-1); // unlimited steps
+ try
+ {
+ operationStatusMessages.displayNonTerminatingMessage("Running " + fileToAssemble);
+ program.simulate(-1); // unlimited steps
}
- catch (NullPointerException npe) {
- // This will occur if program execution is interrupted by Stop button.
- terminatingMessage = "User interrupt: ";
- }
- catch (mars.ProcessingException pe) {
- terminatingMessage = "Runtime error: ";
- }
- finally {
- deleteAsObserver();
- observing = false;
- operationStatusMessages.displayTerminatingMessage(terminatingMessage+fileToAssemble);
- }
- return;
- }
- }
-
-
- //////////////////////////////////////////////////////////////////////////
- // Class for text message field used to update operation status when
- // assembling and running MIPS programs.
- private class MessageField extends JTextField {
-
- public MessageField(String text) {
+ catch (NullPointerException npe)
+ {
+ // This will occur if program execution is interrupted by Stop button.
+ terminatingMessage = "User interrupt: ";
+ }
+ catch (mars.ProcessingException pe)
+ {
+ terminatingMessage = "Runtime error: ";
+ }
+ finally
+ {
+ deleteAsObserver();
+ observing = false;
+ operationStatusMessages.displayTerminatingMessage(terminatingMessage + fileToAssemble);
+ }
+ }
+ }
+
+
+ //////////////////////////////////////////////////////////////////////////
+ // Class for text message field used to update operation status when
+ // assembling and running MIPS programs.
+ private class MessageField extends JTextField
+ {
+
+ public MessageField(String text)
+ {
super(text);
- }
-
- private void displayTerminatingMessage(String text) {
+ }
+
+ private void displayTerminatingMessage(String text)
+ {
displayMessage(text, true);
- }
-
- private void displayNonTerminatingMessage(String text) {
+ }
+
+ private void displayNonTerminatingMessage(String text)
+ {
displayMessage(text, false);
- }
-
- private void displayMessage(String text, boolean terminating) {
- SwingUtilities.invokeLater(new MessageWriter(text, terminating));
- }
-
- /////////////////////////////////////////////////////////////////////////////////
- // Little inner-inner class to display processing error message on AWT thread.
- // Used only by stand-alone app.
- private class MessageWriter implements Runnable {
- private String text;
- private boolean terminatingMessage;
- public MessageWriter(String text, boolean terminating) {
- this.text = text;
- this.terminatingMessage = terminating;
+ }
+
+ private void displayMessage(String text, boolean terminating)
+ {
+ SwingUtilities.invokeLater(new MessageWriter(text, terminating));
+ }
+
+ /////////////////////////////////////////////////////////////////////////////////
+ // Little inner-inner class to display processing error message on AWT thread.
+ // Used only by stand-alone app.
+ private class MessageWriter implements Runnable
+ {
+ private final String text;
+
+ private final boolean terminatingMessage;
+
+ public MessageWriter(String text, boolean terminating)
+ {
+ this.text = text;
+ this.terminatingMessage = terminating;
}
- public void run() {
- if (text!=null) {
- operationStatusMessages.setText(text);
- operationStatusMessages.setCaretPosition(0);
- }
- if (terminatingMessage) {
- assembleRunButton.setEnabled(true);
- openFileButton.setEnabled(true);
- stopButton.setEnabled(false);
- }
+
+ public void run()
+ {
+ if (text != null)
+ {
+ operationStatusMessages.setText(text);
+ operationStatusMessages.setCaretPosition(0);
+ }
+ if (terminatingMessage)
+ {
+ assembleRunButton.setEnabled(true);
+ openFileButton.setEnabled(true);
+ stopButton.setEnabled(false);
+ }
}
- }
- }
-
- //////////////////////////////////////////////////////////////////////
- // For scheduling GUI update on timed runs...used only by stand-alone app.
- private class GUIUpdater implements Runnable {
- public void run() {
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ // For scheduling GUI update on timed runs...used only by stand-alone app.
+ private class GUIUpdater implements Runnable
+ {
+ public void run()
+ {
updateDisplay();
- }
- }
-
- }
\ No newline at end of file
+ }
+ }
+
+}
diff --git a/src/main/java/mars/tools/BHTEntry.java b/src/main/java/mars/tools/BHTEntry.java
index 36401b1..5098429 100644
--- a/src/main/java/mars/tools/BHTEntry.java
+++ b/src/main/java/mars/tools/BHTEntry.java
@@ -30,158 +30,182 @@ package mars.tools;//.bhtsim;
/**
* Represents a single entry of the Branch History Table.
*
- * The entry holds the information about former branch predictions and outcomes.
- * The number of past branch outcomes can be configured and is called the history.
- * The semantics of the history of size n is as follows.
- * The entry will change its prediction, if it mispredicts the branch n times in series.
- * The prediction of the entry can be obtained by the {@link BHTEntry#getPrediction()} method.
- * Feedback of taken or not taken branches is provided to the entry via the {@link BHTEntry#updatePrediction(boolean)} method.
- * This causes the history and the prediction to be updated.
+ * The entry holds the information about former branch predictions and outcomes. The number of past branch outcomes can
+ * be configured and is called the history. The semantics of the history of size n is as follows. The entry will
+ * change its prediction, if it mispredicts the branch n times in series. The prediction of the entry can be
+ * obtained by the {@link BHTEntry#getPrediction()} method. Feedback of taken or not taken branches is provided to the
+ * entry via the {@link BHTEntry#updatePrediction(boolean)} method. This causes the history and the prediction to be
+ * updated.
*
- * Additionally the entry keeps track about how many times the prediction was correct or incorrect.
- * The statistics can be obtained by the methods {@link BHTEntry#getStatsPredCorrect()}, {@link BHTEntry#getStatsPredIncorrect()} and {@link BHTEntry#getStatsPredPrecision()}.
- *
+ * Additionally the entry keeps track about how many times the prediction was correct or incorrect. The statistics can
+ * be obtained by the methods {@link BHTEntry#getStatsPredCorrect()}, {@link BHTEntry#getStatsPredIncorrect()} and
+ * {@link BHTEntry#getStatsPredPrecision()}.
+ *
* @author ingo.kofler@itec.uni-klu.ac.at
*/
-public class BHTEntry {
-
- /** the history of the BHT entry. Each boolean value signals if the branch was taken or not. The value at index n-1 represents the most recent branch outcome. */
- private boolean m_history[];
+public class BHTEntry
+{
- /** the current prediction */
- private boolean m_prediction;
-
- /** absolute number of incorrect predictions */
- private int m_incorrect;
-
- /** absolute number of correct predictions */
- private int m_correct;
-
-
- /**
- * Constructs a BHT entry with a given history size.
- *
- * The size of the history can only be set via the constructor and cannot be changed afterwards.
- *
- * @param historySize number of past branch outcomes to remember
- * @param initVal the initial value of the entry (take or do not take)
- */
- public BHTEntry(int historySize, boolean initVal) {
- m_prediction = initVal;
- m_history = new boolean[historySize];
-
- for (int i=0; i < historySize; i++) {
- m_history[i] = initVal;
- }
- m_correct = m_incorrect = 0;
- }
-
-
- /**
- * Returns the branch prediction based on the history.
- *
- * @return true if prediction is to take the branch, false otherwise
- */
- public boolean getPrediction() {
- return m_prediction;
- }
-
-
- /**
- * Updates the entry's history and prediction.
- * This method provides feedback for a prediction.
- * The history and the statistics are updated accordingly.
- * Based on the updated history a new prediction is calculated
- *
- * @param branchTaken signals if the branch was taken (true) or not (false)
- */
- public void updatePrediction(boolean branchTaken) {
-
- // update history
- for (int i=0; i < m_history.length-1; i++) {
- m_history[i] = m_history[i+1];
- }
- m_history[m_history.length-1] = branchTaken;
-
-
- // if the prediction was correct, update stats and keep prediction
- if (branchTaken == m_prediction) {
- m_correct ++;
- }
- else {
- m_incorrect ++;
-
- // check if the prediction should change
- boolean changePrediction = true;
-
- for (int i=0; i < m_history.length; i++) {
- if (m_history[i] != branchTaken)
- changePrediction = false;
- }
-
- if (changePrediction)
- m_prediction = !m_prediction;
-
- }
- }
-
-
- /**
- * Get the absolute number of mispredictions.
- *
- * @return number of incorrect predictions (mispredictions)
- */
- public int getStatsPredIncorrect() {
- return m_incorrect;
- }
-
-
- /**
- * Get the absolute number of correct predictions.
- *
- * @return number of correct predictions
- */
- public int getStatsPredCorrect() {
- return m_correct;
- }
-
-
- /**
- * Get the percentage of correct predictions.
- *
- * @return the percentage of correct predictions
- */
- public double getStatsPredPrecision() {
- int sum = m_incorrect + m_correct;
- return (sum==0) ? 0 : m_correct * 100.0 / sum;
- }
-
-
- /***
- * Builds a string representation of the BHT entry's history.
- * The history is a sequence of flags that signal if the branch was taken (T) or not taken (NT).
- *
- * @return a string representation of the BHT entry's history
- */
- public String getHistoryAsStr() {
- String result = "";
-
- for (int i=0; i0) result = result + ", ";
- result += m_history[i] ? "T" : "NT";
- }
- return result;
- }
-
-
- /***
- * Returns a string representation of the BHT entry's current prediction.
- * The prediction can be either to TAKE or do NOT TAKE the branch.
- *
- * @return a string representation of the BHT entry's current prediction
- */
- public String getPredictionAsStr() {
- return m_prediction ? "TAKE" : "NOT TAKE";
- }
+ /**
+ * the history of the BHT entry. Each boolean value signals if the branch was taken or not. The value at index n-1
+ * represents the most recent branch outcome.
+ */
+ private final boolean[] m_history;
+
+ /** the current prediction */
+ private boolean m_prediction;
+
+ /** absolute number of incorrect predictions */
+ private int m_incorrect;
+
+ /** absolute number of correct predictions */
+ private int m_correct;
+
+
+ /**
+ * Constructs a BHT entry with a given history size.
+ *
+ * The size of the history can only be set via the constructor and cannot be changed afterwards.
+ *
+ * @param historySize number of past branch outcomes to remember
+ * @param initVal the initial value of the entry (take or do not take)
+ */
+ public BHTEntry(int historySize, boolean initVal)
+ {
+ m_prediction = initVal;
+ m_history = new boolean[historySize];
+
+ for (int i = 0; i < historySize; i++)
+ {
+ m_history[i] = initVal;
+ }
+ m_correct = m_incorrect = 0;
+ }
+
+
+ /**
+ * Returns the branch prediction based on the history.
+ *
+ * @return true if prediction is to take the branch, false otherwise
+ */
+ public boolean getPrediction()
+ {
+ return m_prediction;
+ }
+
+
+ /**
+ * Updates the entry's history and prediction. This method provides feedback for a prediction. The history and the
+ * statistics are updated accordingly. Based on the updated history a new prediction is calculated
+ *
+ * @param branchTaken signals if the branch was taken (true) or not (false)
+ */
+ public void updatePrediction(boolean branchTaken)
+ {
+
+ // update history
+ for (int i = 0; i < m_history.length - 1; i++)
+ {
+ m_history[i] = m_history[i + 1];
+ }
+ m_history[m_history.length - 1] = branchTaken;
+
+
+ // if the prediction was correct, update stats and keep prediction
+ if (branchTaken == m_prediction)
+ {
+ m_correct++;
+ }
+ else
+ {
+ m_incorrect++;
+
+ // check if the prediction should change
+ boolean changePrediction = true;
+
+ for (int i = 0; i < m_history.length; i++)
+ {
+ if (m_history[i] != branchTaken)
+ {
+ changePrediction = false;
+ break;
+ }
+ }
+
+ if (changePrediction)
+ {
+ m_prediction = !m_prediction;
+ }
+
+ }
+ }
+
+
+ /**
+ * Get the absolute number of mispredictions.
+ *
+ * @return number of incorrect predictions (mispredictions)
+ */
+ public int getStatsPredIncorrect()
+ {
+ return m_incorrect;
+ }
+
+
+ /**
+ * Get the absolute number of correct predictions.
+ *
+ * @return number of correct predictions
+ */
+ public int getStatsPredCorrect()
+ {
+ return m_correct;
+ }
+
+
+ /**
+ * Get the percentage of correct predictions.
+ *
+ * @return the percentage of correct predictions
+ */
+ public double getStatsPredPrecision()
+ {
+ int sum = m_incorrect + m_correct;
+ return (sum == 0) ? 0 : m_correct * 100.0 / sum;
+ }
+
+
+ /***
+ * Builds a string representation of the BHT entry's history.
+ * The history is a sequence of flags that signal if the branch was taken (T) or not taken (NT).
+ *
+ * @return a string representation of the BHT entry's history
+ */
+ public String getHistoryAsStr()
+ {
+ String result = "";
+
+ for (int i = 0; i < m_history.length; i++)
+ {
+ if (i > 0)
+ {
+ result = result + ", ";
+ }
+ result += m_history[i] ? "T" : "NT";
+ }
+ return result;
+ }
+
+
+ /***
+ * Returns a string representation of the BHT entry's current prediction.
+ * The prediction can be either to TAKE or do NOT TAKE the branch.
+ *
+ * @return a string representation of the BHT entry's current prediction
+ */
+ public String getPredictionAsStr()
+ {
+ return m_prediction ? "TAKE" : "NOT TAKE";
+ }
}
diff --git a/src/main/java/mars/tools/BHTSimGUI.java b/src/main/java/mars/tools/BHTSimGUI.java
index 5b0e4aa..0cf3f61 100644
--- a/src/main/java/mars/tools/BHTSimGUI.java
+++ b/src/main/java/mars/tools/BHTSimGUI.java
@@ -27,29 +27,16 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package mars.tools;//.bhtsim;
-import java.awt.BorderLayout;
-import java.awt.Color;
-import java.awt.GridBagConstraints;
-import java.awt.GridBagLayout;
-import java.awt.Insets;
+import javax.swing.*;
+import javax.swing.table.DefaultTableCellRenderer;
+import java.awt.*;
import java.text.DecimalFormat;
import java.util.Vector;
-import javax.swing.JComboBox;
-import javax.swing.JLabel;
-import javax.swing.JPanel;
-import javax.swing.JScrollPane;
-import javax.swing.JTable;
-import javax.swing.JTextArea;
-import javax.swing.JTextField;
-import javax.swing.ListSelectionModel;
-import javax.swing.SwingConstants;
-import javax.swing.table.DefaultTableCellRenderer;
-
/**
* Represents the GUI of the BHT Simulator Tool.
*
- *
+ *
* The GUI consists of mainly four parts:
*
* - A configuration panel to select the number of entries and the history size
@@ -57,289 +44,304 @@ import javax.swing.table.DefaultTableCellRenderer;
*
- A table representing the BHT with all entries and their internal state and statistics
*
- A log panel that summarizes the predictions in a textual form
*
- *
+ *
* @author ingo.kofler@itec.uni-klu.ac.at
*/
//@SuppressWarnings("serial")
-public class BHTSimGUI extends JPanel {
-
- /** text field presenting the most recent branch instruction */
- private JTextField m_tfInstruction;
-
- /** text field representing the address of the most recent branch instruction */
- private JTextField m_tfAddress;
-
- /** text field representing the resulting BHT index of the branch instruction */
- private JTextField m_tfIndex;
+public class BHTSimGUI extends JPanel
+{
- /** combo box for selecting the number of BHT entries */
- private JComboBox m_cbBHTentries;
-
- /** combo box for selecting the history size */
- private JComboBox m_cbBHThistory;
-
- /** combo box for selecting the initial value */
- private JComboBox m_cbBHTinitVal;
-
- /** the table representing the BHT */
- private JTable m_tabBHT;
-
- /** text field for log output */
- private JTextArea m_taLog;
-
- /** constant for the color that highlights the current BHT entry */
- public final static Color COLOR_PREPREDICTION = Color.yellow;
-
- /** constant for the color to signal a correct prediction */
- public final static Color COLOR_PREDICTION_CORRECT = Color.green;
-
- /** constant for the color to signal a misprediction */
- public final static Color COLOR_PREDICTION_INCORRECT = Color.red;
-
- /** constant for the String representing "take the branch" */
- public final static String BHT_TAKE_BRANCH = "TAKE";
-
- /** constant for the String representing "do not take the branch" */
- public final static String BHT_DO_NOT_TAKE_BRANCH = "NOT TAKE";
-
-
-
- /**
- * Creates the GUI components of the BHT Simulator
- * The GUI is a subclass of JPanel which is integrated in the GUI of the MARS tool
- */
- public BHTSimGUI() {
- BorderLayout layout = new BorderLayout();
- layout.setVgap(10);
- layout.setHgap(10);
- setLayout(layout);
-
- m_tabBHT = createAndInitTable();
-
- add(buildConfigPanel(), BorderLayout.NORTH);
- add(buildInfoPanel(), BorderLayout.WEST);
- add(new JScrollPane(m_tabBHT), BorderLayout.CENTER);
- add(buildLogPanel(), BorderLayout.SOUTH);
- }
-
- /**
- * Creates and initializes the JTable representing the BHT.
- *
- * @return the JTable representing the BHT
- */
- private JTable createAndInitTable() {
- // create the table
- JTable theTable = new JTable();
-
- // create a default renderer for double values (percentage)
- DefaultTableCellRenderer doubleRenderer = new DefaultTableCellRenderer() {
- private DecimalFormat formatter = new DecimalFormat("##0.00");
-
- public void setValue(Object value) {
- setText((value == null) ? "" : formatter.format(value));
- }
- };
- doubleRenderer.setHorizontalAlignment(SwingConstants.CENTER);
-
- // create a default renderer for all other values with center alignment
- DefaultTableCellRenderer defRenderer = new DefaultTableCellRenderer();
- defRenderer.setHorizontalAlignment(SwingConstants.CENTER);
-
- theTable.setDefaultRenderer(Double.class, doubleRenderer);
- theTable.setDefaultRenderer(Integer.class, defRenderer);
- theTable.setDefaultRenderer(String.class, defRenderer);
-
- theTable.setSelectionBackground(BHTSimGUI.COLOR_PREPREDICTION);
- theTable.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
-
- return theTable;
+ /** constant for the color that highlights the current BHT entry */
+ public final static Color COLOR_PREPREDICTION = Color.yellow;
- }
-
-
- /**
- * Creates and initializes the panel holding the instruction, address and index text fields.
- *
- * @return the info panel
- */
- private JPanel buildInfoPanel() {
- m_tfInstruction = new JTextField();
- m_tfAddress = new JTextField();
- m_tfIndex = new JTextField();
-
- m_tfInstruction.setColumns(10);
- m_tfInstruction.setEditable(false);
- m_tfInstruction.setHorizontalAlignment(JTextField.CENTER);
- m_tfAddress.setColumns(10);
- m_tfAddress.setEditable(false);
- m_tfAddress.setHorizontalAlignment(JTextField.CENTER);
- m_tfIndex.setColumns(10);
- m_tfIndex.setEditable(false);
- m_tfIndex.setHorizontalAlignment(JTextField.CENTER);
-
- JPanel panel = new JPanel();
- JPanel outerPanel = new JPanel();
- outerPanel.setLayout(new BorderLayout());
-
- GridBagLayout gbl = new GridBagLayout();
- panel.setLayout(gbl);
-
- GridBagConstraints c = new GridBagConstraints();
-
- c.insets = new Insets(5, 5, 2, 5);
- c.gridx = 1;
- c.gridy = 1;
-
- panel.add(new JLabel("Instruction"), c);
- c.gridy++;
- panel.add(m_tfInstruction, c);
- c.gridy++;
- panel.add(new JLabel("@ Address"), c);
- c.gridy++;
- panel.add(m_tfAddress, c);
- c.gridy++;
- panel.add(new JLabel("-> Index"), c);
- c.gridy++;
- panel.add(m_tfIndex, c);
-
- outerPanel.add(panel, BorderLayout.NORTH);
- return outerPanel;
- }
-
-
- /**
- * Creates and initializes the panel for the configuration of the tool
- * The panel contains two combo boxes for selecting the number of BHT entries and the history size.
- *
- * @return a panel for the configuration
- */
- private JPanel buildConfigPanel() {
- JPanel panel = new JPanel();
-
- Vector sizes = new Vector();
- sizes.add(new Integer(8));
- sizes.add(new Integer(16));
- sizes.add(new Integer(32));
-
- Vector bits = new Vector();
- bits.add(new Integer(1));
- bits.add(new Integer(2));
-
- Vector initVals = new Vector();
- initVals.add(BHTSimGUI.BHT_DO_NOT_TAKE_BRANCH);
- initVals.add(BHTSimGUI.BHT_TAKE_BRANCH);
-
- m_cbBHTentries = new JComboBox(sizes);
- m_cbBHThistory = new JComboBox(bits);
- m_cbBHTinitVal = new JComboBox(initVals);
-
- panel.add(new JLabel("# of BHT entries"));
- panel.add(m_cbBHTentries);
- panel.add(new JLabel("BHT history size"));
- panel.add(m_cbBHThistory);
- panel.add(new JLabel("Initial value"));
- panel.add(m_cbBHTinitVal);
-
- return panel;
- }
-
-
- /**
- * Creates and initializes the panel containing the log text area.
- *
- * @return the panel for the logging output
- */
- private JPanel buildLogPanel() {
- JPanel panel = new JPanel();
- panel.setLayout(new BorderLayout());
- m_taLog = new JTextArea();
- m_taLog.setRows(6);
- m_taLog.setEditable(false);
+ /** constant for the color to signal a correct prediction */
+ public final static Color COLOR_PREDICTION_CORRECT = Color.green;
- panel.add(new JLabel("Log"), BorderLayout.NORTH);
- panel.add(new JScrollPane(m_taLog), BorderLayout.CENTER);
-
- return panel;
- }
-
+ /** constant for the color to signal a misprediction */
+ public final static Color COLOR_PREDICTION_INCORRECT = Color.red;
- /***
- * Returns the combo box for selecting the number of BHT entries.
- *
- * @return the reference to the combo box
- */
- public JComboBox getCbBHTentries() {
- return m_cbBHTentries;
- }
-
-
- /***
- * Returns the combo box for selecting the size of the BHT history.
- *
- * @return the reference to the combo box
- */
- public JComboBox getCbBHThistory() {
- return m_cbBHThistory;
- }
+ /** constant for the String representing "take the branch" */
+ public final static String BHT_TAKE_BRANCH = "TAKE";
-
- /***
- * Returns the combo box for selecting the initial value of the BHT
- *
- * @return the reference to the combo box
- */
- public JComboBox getCbBHTinitVal() {
- return m_cbBHTinitVal;
- }
-
- /***
- * Returns the table representing the BHT.
- *
- * @return the reference to the table
- */
- public JTable getTabBHT() {
- return m_tabBHT;
- }
+ /** constant for the String representing "do not take the branch" */
+ public final static String BHT_DO_NOT_TAKE_BRANCH = "NOT TAKE";
-
- /***
- * Returns the text area for log purposes.
- *
- * @return the reference to the text area
- */
- public JTextArea getTaLog() {
- return m_taLog;
- }
-
-
- /***
- * Returns the text field for displaying the most recent branch instruction
- *
- * @return the reference to the text field
- */
- public JTextField getTfInstruction() {
- return m_tfInstruction;
- }
-
-
- /***
- * Returns the text field for displaying the address of the most recent branch instruction
- *
- * @return the reference to the text field
- */
- public JTextField getTfAddress() {
- return m_tfAddress;
- }
-
-
- /***
- * Returns the text field for displaying the corresponding index into the BHT
- *
- * @return the reference to the text field
- */
- public JTextField getTfIndex() {
- return m_tfIndex;
- }
+ /** text field presenting the most recent branch instruction */
+ private JTextField m_tfInstruction;
+
+ /** text field representing the address of the most recent branch instruction */
+ private JTextField m_tfAddress;
+
+ /** text field representing the resulting BHT index of the branch instruction */
+ private JTextField m_tfIndex;
+
+ /** combo box for selecting the number of BHT entries */
+ private JComboBox m_cbBHTentries;
+
+ /** combo box for selecting the history size */
+ private JComboBox m_cbBHThistory;
+
+ /** combo box for selecting the initial value */
+ private JComboBox m_cbBHTinitVal;
+
+ /** the table representing the BHT */
+ private final JTable m_tabBHT;
+
+ /** text field for log output */
+ private JTextArea m_taLog;
+
+
+ /**
+ * Creates the GUI components of the BHT Simulator The GUI is a subclass of JPanel which is integrated in the GUI of
+ * the MARS tool
+ */
+ public BHTSimGUI()
+ {
+ BorderLayout layout = new BorderLayout();
+ layout.setVgap(10);
+ layout.setHgap(10);
+ setLayout(layout);
+
+ m_tabBHT = createAndInitTable();
+
+ add(buildConfigPanel(), BorderLayout.NORTH);
+ add(buildInfoPanel(), BorderLayout.WEST);
+ add(new JScrollPane(m_tabBHT), BorderLayout.CENTER);
+ add(buildLogPanel(), BorderLayout.SOUTH);
+ }
+
+ /**
+ * Creates and initializes the JTable representing the BHT.
+ *
+ * @return the JTable representing the BHT
+ */
+ private JTable createAndInitTable()
+ {
+ // create the table
+ JTable theTable = new JTable();
+
+ // create a default renderer for double values (percentage)
+ DefaultTableCellRenderer doubleRenderer = new DefaultTableCellRenderer()
+ {
+ private final DecimalFormat formatter = new DecimalFormat("##0.00");
+
+ public void setValue(Object value)
+ {
+ setText((value == null) ? "" : formatter.format(value));
+ }
+ };
+ doubleRenderer.setHorizontalAlignment(SwingConstants.CENTER);
+
+ // create a default renderer for all other values with center alignment
+ DefaultTableCellRenderer defRenderer = new DefaultTableCellRenderer();
+ defRenderer.setHorizontalAlignment(SwingConstants.CENTER);
+
+ theTable.setDefaultRenderer(Double.class, doubleRenderer);
+ theTable.setDefaultRenderer(Integer.class, defRenderer);
+ theTable.setDefaultRenderer(String.class, defRenderer);
+
+ theTable.setSelectionBackground(BHTSimGUI.COLOR_PREPREDICTION);
+ theTable.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
+
+ return theTable;
+
+ }
+
+
+ /**
+ * Creates and initializes the panel holding the instruction, address and index text fields.
+ *
+ * @return the info panel
+ */
+ private JPanel buildInfoPanel()
+ {
+ m_tfInstruction = new JTextField();
+ m_tfAddress = new JTextField();
+ m_tfIndex = new JTextField();
+
+ m_tfInstruction.setColumns(10);
+ m_tfInstruction.setEditable(false);
+ m_tfInstruction.setHorizontalAlignment(JTextField.CENTER);
+ m_tfAddress.setColumns(10);
+ m_tfAddress.setEditable(false);
+ m_tfAddress.setHorizontalAlignment(JTextField.CENTER);
+ m_tfIndex.setColumns(10);
+ m_tfIndex.setEditable(false);
+ m_tfIndex.setHorizontalAlignment(JTextField.CENTER);
+
+ JPanel panel = new JPanel();
+ JPanel outerPanel = new JPanel();
+ outerPanel.setLayout(new BorderLayout());
+
+ GridBagLayout gbl = new GridBagLayout();
+ panel.setLayout(gbl);
+
+ GridBagConstraints c = new GridBagConstraints();
+
+ c.insets = new Insets(5, 5, 2, 5);
+ c.gridx = 1;
+ c.gridy = 1;
+
+ panel.add(new JLabel("Instruction"), c);
+ c.gridy++;
+ panel.add(m_tfInstruction, c);
+ c.gridy++;
+ panel.add(new JLabel("@ Address"), c);
+ c.gridy++;
+ panel.add(m_tfAddress, c);
+ c.gridy++;
+ panel.add(new JLabel("-> Index"), c);
+ c.gridy++;
+ panel.add(m_tfIndex, c);
+
+ outerPanel.add(panel, BorderLayout.NORTH);
+ return outerPanel;
+ }
+
+
+ /**
+ * Creates and initializes the panel for the configuration of the tool The panel contains two combo boxes for
+ * selecting the number of BHT entries and the history size.
+ *
+ * @return a panel for the configuration
+ */
+ private JPanel buildConfigPanel()
+ {
+ JPanel panel = new JPanel();
+
+ Vector sizes = new Vector();
+ sizes.add(Integer.valueOf(8));
+ sizes.add(Integer.valueOf(16));
+ sizes.add(Integer.valueOf(32));
+
+ Vector bits = new Vector();
+ bits.add(Integer.valueOf(1));
+ bits.add(Integer.valueOf(2));
+
+ Vector initVals = new Vector();
+ initVals.add(BHTSimGUI.BHT_DO_NOT_TAKE_BRANCH);
+ initVals.add(BHTSimGUI.BHT_TAKE_BRANCH);
+
+ m_cbBHTentries = new JComboBox(sizes);
+ m_cbBHThistory = new JComboBox(bits);
+ m_cbBHTinitVal = new JComboBox(initVals);
+
+ panel.add(new JLabel("# of BHT entries"));
+ panel.add(m_cbBHTentries);
+ panel.add(new JLabel("BHT history size"));
+ panel.add(m_cbBHThistory);
+ panel.add(new JLabel("Initial value"));
+ panel.add(m_cbBHTinitVal);
+
+ return panel;
+ }
+
+
+ /**
+ * Creates and initializes the panel containing the log text area.
+ *
+ * @return the panel for the logging output
+ */
+ private JPanel buildLogPanel()
+ {
+ JPanel panel = new JPanel();
+ panel.setLayout(new BorderLayout());
+ m_taLog = new JTextArea();
+ m_taLog.setRows(6);
+ m_taLog.setEditable(false);
+
+ panel.add(new JLabel("Log"), BorderLayout.NORTH);
+ panel.add(new JScrollPane(m_taLog), BorderLayout.CENTER);
+
+ return panel;
+ }
+
+
+ /***
+ * Returns the combo box for selecting the number of BHT entries.
+ *
+ * @return the reference to the combo box
+ */
+ public JComboBox getCbBHTentries()
+ {
+ return m_cbBHTentries;
+ }
+
+
+ /***
+ * Returns the combo box for selecting the size of the BHT history.
+ *
+ * @return the reference to the combo box
+ */
+ public JComboBox getCbBHThistory()
+ {
+ return m_cbBHThistory;
+ }
+
+
+ /***
+ * Returns the combo box for selecting the initial value of the BHT
+ *
+ * @return the reference to the combo box
+ */
+ public JComboBox getCbBHTinitVal()
+ {
+ return m_cbBHTinitVal;
+ }
+
+ /***
+ * Returns the table representing the BHT.
+ *
+ * @return the reference to the table
+ */
+ public JTable getTabBHT()
+ {
+ return m_tabBHT;
+ }
+
+
+ /***
+ * Returns the text area for log purposes.
+ *
+ * @return the reference to the text area
+ */
+ public JTextArea getTaLog()
+ {
+ return m_taLog;
+ }
+
+
+ /***
+ * Returns the text field for displaying the most recent branch instruction
+ *
+ * @return the reference to the text field
+ */
+ public JTextField getTfInstruction()
+ {
+ return m_tfInstruction;
+ }
+
+
+ /***
+ * Returns the text field for displaying the address of the most recent branch instruction
+ *
+ * @return the reference to the text field
+ */
+ public JTextField getTfAddress()
+ {
+ return m_tfAddress;
+ }
+
+
+ /***
+ * Returns the text field for displaying the corresponding index into the BHT
+ *
+ * @return the reference to the text field
+ */
+ public JTextField getTfIndex()
+ {
+ return m_tfIndex;
+ }
}
diff --git a/src/main/java/mars/tools/BHTSimulator.java b/src/main/java/mars/tools/BHTSimulator.java
index 9130a0f..f702b7a 100644
--- a/src/main/java/mars/tools/BHTSimulator.java
+++ b/src/main/java/mars/tools/BHTSimulator.java
@@ -27,18 +27,13 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package mars.tools;
+import mars.ProgramStatement;
+import mars.mips.hardware.*;
+
+import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Observable;
-
-import javax.swing.JComponent;
-
-import mars.ProgramStatement;
-import mars.mips.hardware.AccessNotice;
-import mars.mips.hardware.AddressErrorException;
-import mars.mips.hardware.Memory;
-import mars.mips.hardware.MemoryAccessNotice;
-import mars.mips.hardware.RegisterFile;
//import mars.tools.bhtsim.BHTSimGUI;
//import mars.tools.bhtsim.BHTableModel;
@@ -46,342 +41,382 @@ import mars.mips.hardware.RegisterFile;
/**
* A MARS tool for simulating branch prediction with a Branch History Table (BHT)
*
- * The simulation is based on observing the access to the instruction memory area (text segment).
- * If a branch instruction is encountered, a prediction based on a BHT is performed.
- * The outcome of the branch is compared with the prediction and the prediction is updated accordingly.
- * Statistics about the correct and incorrect number of predictions can be obtained for each BHT entry.
- * The number of entries in the BHT and the history that is considered for each prediction can be configured interactively.
- * A change of the configuration however causes a re-initialization of the BHT.
+ * The simulation is based on observing the access to the instruction memory area (text segment). If a branch
+ * instruction is encountered, a prediction based on a BHT is performed. The outcome of the branch is compared with the
+ * prediction and the prediction is updated accordingly. Statistics about the correct and incorrect number of
+ * predictions can be obtained for each BHT entry. The number of entries in the BHT and the history that is considered
+ * for each prediction can be configured interactively. A change of the configuration however causes a re-initialization
+ * of the BHT.
*
- * The tool can be used to show how branch prediction works in case of loops and how effective such simple methods are.
+ * The tool can be used to show how branch prediction works in case of loops and how effective such simple methods are.
* In case of nested loops the difference of BHT with 1 or 2 Bit history can be explored and visualized.
- *
+ *
* @author ingo.kofler@itec.uni-klu.ac.at
*/
//@SuppressWarnings("serial")
-public class BHTSimulator extends AbstractMarsToolAndApplication implements ActionListener {
-
-
- /** constant for the default size of the BHT */
- public static final int BHT_DEFAULT_SIZE = 16;
-
- /** constant for the default history size */
- public static final int BHT_DEFAULT_HISTORY = 1;
-
- /** constant for the default inital value */
- public static final boolean BHT_DEFAULT_INITVAL = false;
-
- /** the name of the tool */
- public static final String BHT_NAME = "BHT Simulator";
-
- /** the version of the tool */
- public static final String BHT_VERSION = "Version 1.0 (Ingo Kofler)";
-
- /** the heading of the tool */
- public static final String BHT_HEADING = "Branch History Table Simulator";
-
- /** the GUI of the BHT simulator */
- private BHTSimGUI m_gui;
-
- /** the model of the BHT */
- private BHTableModel m_bhtModel;
-
- /** state variable that indicates that the last instruction was a branch instruction (if address != 0) or not (address == 0) */
- private int m_pendingBranchInstAddress;
-
- /** state variable that signals if the last branch was taken */
- private boolean m_lastBranchTaken;
-
-
- /**
- * Creates a BHT Simulator with given name and heading.
- */
- public BHTSimulator() {
- super(BHTSimulator.BHT_NAME+", "+BHTSimulator.BHT_VERSION, BHTSimulator.BHT_HEADING);
- }
-
-
- /**
- * Adds BHTSimulator as observer of the text segment.
- */
- protected void addAsObserver() {
- addAsObserver(Memory.textBaseAddress, Memory.textLimitAddress);
- addAsObserver(RegisterFile.getProgramCounterRegister());
- }
-
-
- /**
- * Creates a GUI and initialize the GUI with the default values.
- */
- protected JComponent buildMainDisplayArea() {
-
- m_gui = new BHTSimGUI();
- m_bhtModel = new BHTableModel(BHTSimulator.BHT_DEFAULT_SIZE, BHTSimulator.BHT_DEFAULT_HISTORY, BHT_DEFAULT_INITVAL);
-
- m_gui.getTabBHT().setModel(m_bhtModel);
- m_gui.getCbBHThistory().setSelectedItem(new Integer(BHTSimulator.BHT_DEFAULT_HISTORY));
- m_gui.getCbBHTentries().setSelectedItem(new Integer(BHTSimulator.BHT_DEFAULT_SIZE));
-
- m_gui.getCbBHTentries().addActionListener(this);
- m_gui.getCbBHThistory().addActionListener(this);
- m_gui.getCbBHTinitVal().addActionListener(this);
-
- return m_gui;
- }
-
-
- /**
- * Returns the name of the tool.
- * @return the tool's name as String
- */
- public String getName() {
- return BHTSimulator.BHT_NAME;
- }
+public class BHTSimulator extends AbstractMarsToolAndApplication implements ActionListener
+{
- /**
- * Performs a reset of the simulator.
- * This causes the BHT to be reseted and the log messages to be cleared.
- */
- protected void reset() {
- resetSimulator();
- }
-
-
- /**
- * Handles the actions when selecting another value in one of the two combo boxes.
- * Selecting a different BHT size or history causes a reset of the simulator.
- */
- public void actionPerformed(ActionEvent event) {
- // change of the BHT size or BHT bit configuration
- // resets the simulator
- if (event.getSource() == m_gui.getCbBHTentries() || event.getSource() == m_gui.getCbBHThistory() || event.getSource() == m_gui.getCbBHTinitVal()) {
- resetSimulator();
- }
- }
-
-
- /**
- * Resets the simulator by clearing the GUI elements and resetting the BHT.
- */
- protected void resetSimulator() {
- m_gui.getTfInstruction().setText("");
- m_gui.getTfAddress().setText("");
- m_gui.getTfIndex().setText("");
- m_gui.getTaLog().setText("");
- m_bhtModel.initBHT(((Integer)m_gui.getCbBHTentries().getSelectedItem()).intValue(),
- ((Integer)m_gui.getCbBHThistory().getSelectedItem()).intValue(),
- ((String)m_gui.getCbBHTinitVal().getSelectedItem()).equals(BHTSimGUI.BHT_TAKE_BRANCH));
-
- m_pendingBranchInstAddress = 0;
- m_lastBranchTaken = false;
- }
-
-
- /**
- * Handles the execution branch instruction.
- * This method is called each time a branch instruction is executed.
- * Based on the address of the instruction the corresponding index into the BHT is calculated.
- * The prediction is obtained from the BHT at the calculated index and is visualized appropriately.
- *
- * @param stmt the branch statement that is executed
- */
- protected void handlePreBranchInst(ProgramStatement stmt) {
-
- String strStmt = stmt.getBasicAssemblyStatement();
- int address = stmt.getAddress();
- int idx = m_bhtModel.getIdxForAddress(address);
-
- // update the GUI
- m_gui.getTfInstruction().setText(strStmt);
- m_gui.getTfAddress().setText("0x" + Integer.toHexString(address));
- m_gui.getTfIndex().setText("" + idx);
-
- // mark the affected BHT row
- m_gui.getTabBHT().setSelectionBackground(BHTSimGUI.COLOR_PREPREDICTION);
- m_gui.getTabBHT().addRowSelectionInterval(idx, idx);
-
- // add output to log
- m_gui.getTaLog().append("instruction " + strStmt + " at address 0x" + Integer.toHexString(address) + ", maps to index " + idx + "\n");
- m_gui.getTaLog().append("branches to address 0x" + BHTSimulator.extractBranchAddress(stmt) + "\n");
- m_gui.getTaLog().append("prediction is: " + (m_bhtModel.getPredictionAtIdx(idx) ? "take" : "do not take") + "...\n");
- m_gui.getTaLog().setCaretPosition(m_gui.getTaLog().getDocument().getLength());
-
- }
-
-
- /**
- * Handles the execution of the branch instruction.
- * The correctness of the prediction is visualized in both the table and the log message area.
- * The BHT is updated based on the information if the branch instruction was taken or not.
- *
- * @param branchInstAddr the address of the branch instruction
- * @param branchTaken the information if the branch is taken or not (determined in a step before)
- */
- protected void handleExecBranchInst(int branchInstAddr, boolean branchTaken) {
-
- // determine the index in the BHT for the branch instruction
- int idx = m_bhtModel.getIdxForAddress(branchInstAddr);
-
- // check if the prediction is correct
- boolean correctPrediction = m_bhtModel.getPredictionAtIdx(idx) == branchTaken;
-
- m_gui.getTabBHT().setSelectionBackground(correctPrediction ? BHTSimGUI.COLOR_PREDICTION_CORRECT: BHTSimGUI.COLOR_PREDICTION_INCORRECT);
-
- // add some output at the log
- m_gui.getTaLog().append("branch " + (branchTaken ? "taken" : "not taken") + ", prediction was " + ( correctPrediction ? "correct" : "incorrect") + "\n\n");
- m_gui.getTaLog().setCaretPosition(m_gui.getTaLog().getDocument().getLength());
-
- // update the BHT -> causes refresh of the table
- m_bhtModel.updatePredictionAtIdx(idx, branchTaken);
- }
-
-
- /**
- * Determines if the instruction is a branch instruction or not.
- *
- * @param stmt the statement to investigate
- * @return true, if stmt is a branch instruction, otherwise false
- */
- protected static boolean isBranchInstruction(ProgramStatement stmt) {
-
- int opCode = stmt.getBinaryStatement() >>> (32-6);
- int funct = stmt.getBinaryStatement() & 0x1F;
-
- if (opCode == 0x01) {
- if (0x00 <= funct && funct <= 0x07) return true; // bltz, bgez, bltzl, bgezl
- if (0x10 <= funct && funct <= 0x13) return true; // bltzal, bgezal, bltzall, bgczall
- }
+ /** constant for the default size of the BHT */
+ public static final int BHT_DEFAULT_SIZE = 16;
- if (0x04 <= opCode && opCode <= 0x07) return true; // beq, bne, blez, bgtz
- if (0x14 <= opCode && opCode <= 0x17) return true; // beql, bnel, blezl, bgtzl
-
- return false;
- }
-
-
- /**
- * Checks if the branch instruction delivered as parameter will branch or not.
- *
- * @param stmt the branch instruction to be investigated
- * @return true if the branch will be taken, otherwise false
- */
- protected static boolean willBranch(ProgramStatement stmt) {
- int opCode = stmt.getBinaryStatement() >>> (32-6);
- int funct = stmt.getBinaryStatement() & 0x1F;
- int rs = stmt.getBinaryStatement() >>> (32-6-5) & 0x1F;
- int rt = stmt.getBinaryStatement() >>> (32-6-5-5) & 0x1F;
-
- int valRS = RegisterFile.getRegisters()[rs].getValue();
- int valRT = RegisterFile.getRegisters()[rt].getValue();
-
-
- if (opCode == 0x01) {
- switch (funct) {
- case 0x00: return valRS < 0; // bltz
- case 0x01: return valRS >= 0; // bgez
- case 0x02: return valRS < 0; // bltzl
- case 0x03: return valRS >= 0; // bgezl
- }
- }
+ /** constant for the default history size */
+ public static final int BHT_DEFAULT_HISTORY = 1;
- switch (opCode) {
- case 0x04: return valRS == valRT;
- case 0x05: return valRS != valRT;
- case 0x06: return valRS <= 0;
- case 0x07: return valRS >= 0;
- case 0x14: return valRS == valRT;
- case 0x15: return valRS != valRT;
- case 0x16: return valRS <= 0;
- case 0x17: return valRS >= 0;
- }
-
- return true;
- }
-
-
- /**
- * Extracts the target address of the branch.
- *
- * In MIPS the target address is encoded as 16-bit value.
- * The target address is encoded relative to the address of the instruction after the branch instruction
- *
- * @param stmt the branch instruction
- * @return the address of the instruction that is executed if the branch is taken
- */
- protected static int extractBranchAddress(ProgramStatement stmt) {
- short offset = (short)(stmt.getBinaryStatement() & 0xFFFF);
- return stmt.getAddress() + (offset<<2) + 4;
- }
-
-
- /**
- * Callback for text segment access by the MIPS simulator.
- *
- * The method is called each time the text segment is accessed to fetch the next instruction.
- * If the next instruction to execute was a branch instruction, the branch prediction is performed and visualized.
- * In case the last instruction was a branch instruction, the outcome of the branch prediction is analyzed and visualized.
- *
- * @param resource the observed resource
- * @param notice signals the type of access (memory, register etc.)
- */
- protected void processMIPSUpdate(Observable resource, AccessNotice notice) {
-
- if (!notice.accessIsFromMIPS()) return;
-
-
- if (notice.getAccessType() == AccessNotice.READ && notice instanceof MemoryAccessNotice) {
-
- // now it is safe to make a cast of the notice
- MemoryAccessNotice memAccNotice = (MemoryAccessNotice) notice;
-
- try {
- // access the statement in the text segment without notifying other tools etc.
- ProgramStatement stmt = Memory.getInstance().getStatementNoNotify(memAccNotice.getAddress());
-
- // necessary to handle possible null pointers at the end of the program
- // (e.g., if the simulator tries to execute the next instruction after the last instruction in the text segment)
- if (stmt != null) {
-
- boolean clearTextFields = true;
-
- // first, check if there's a pending branch to handle
- if (m_pendingBranchInstAddress != 0) {
- handleExecBranchInst(m_pendingBranchInstAddress, m_lastBranchTaken);
- clearTextFields = false;
- m_pendingBranchInstAddress = 0;
- }
-
-
- // if current instruction is branch instruction
- if (BHTSimulator.isBranchInstruction(stmt)) {
- handlePreBranchInst(stmt);
- m_lastBranchTaken = willBranch(stmt);
- m_pendingBranchInstAddress = stmt.getAddress();
- clearTextFields = false;
- }
+ /** constant for the default inital value */
+ public static final boolean BHT_DEFAULT_INITVAL = false;
-
- // clear text fields and selection
- if (clearTextFields) {
- m_gui.getTfInstruction().setText("");
- m_gui.getTfAddress().setText("");
- m_gui.getTfIndex().setText("");
- m_gui.getTabBHT().clearSelection();
- }
- }
- else {
- // check if there's a pending branch to handle
- if (m_pendingBranchInstAddress != 0) {
- handleExecBranchInst(m_pendingBranchInstAddress, m_lastBranchTaken);
- m_pendingBranchInstAddress = 0;
- }
- }
- }
- catch (AddressErrorException e) {
- // silently ignore these exceptions
- }
-
- }
- }
+ /** the name of the tool */
+ public static final String BHT_NAME = "BHT Simulator";
+
+ /** the version of the tool */
+ public static final String BHT_VERSION = "Version 1.0 (Ingo Kofler)";
+
+ /** the heading of the tool */
+ public static final String BHT_HEADING = "Branch History Table Simulator";
+
+ /** the GUI of the BHT simulator */
+ private BHTSimGUI m_gui;
+
+ /** the model of the BHT */
+ private BHTableModel m_bhtModel;
+
+ /**
+ * state variable that indicates that the last instruction was a branch instruction (if address != 0) or not
+ * (address == 0)
+ */
+ private int m_pendingBranchInstAddress;
+
+ /** state variable that signals if the last branch was taken */
+ private boolean m_lastBranchTaken;
+
+
+ /**
+ * Creates a BHT Simulator with given name and heading.
+ */
+ public BHTSimulator()
+ {
+ super(BHTSimulator.BHT_NAME + ", " + BHTSimulator.BHT_VERSION, BHTSimulator.BHT_HEADING);
+ }
+
+ /**
+ * Determines if the instruction is a branch instruction or not.
+ *
+ * @param stmt the statement to investigate
+ * @return true, if stmt is a branch instruction, otherwise false
+ */
+ protected static boolean isBranchInstruction(ProgramStatement stmt)
+ {
+
+ int opCode = stmt.getBinaryStatement() >>> (32 - 6);
+ int funct = stmt.getBinaryStatement() & 0x1F;
+
+ if (opCode == 0x01)
+ {
+ if (0x00 <= funct && funct <= 0x07)
+ {
+ return true; // bltz, bgez, bltzl, bgezl
+ }
+ if (0x10 <= funct && funct <= 0x13)
+ {
+ return true; // bltzal, bgezal, bltzall, bgczall
+ }
+ }
+
+ if (0x04 <= opCode && opCode <= 0x07)
+ {
+ return true; // beq, bne, blez, bgtz
+ }
+ return 0x14 <= opCode && opCode <= 0x17; // beql, bnel, blezl, bgtzl
+ }
+
+ /**
+ * Checks if the branch instruction delivered as parameter will branch or not.
+ *
+ * @param stmt the branch instruction to be investigated
+ * @return true if the branch will be taken, otherwise false
+ */
+ protected static boolean willBranch(ProgramStatement stmt)
+ {
+ int opCode = stmt.getBinaryStatement() >>> (32 - 6);
+ int funct = stmt.getBinaryStatement() & 0x1F;
+ int rs = stmt.getBinaryStatement() >>> (32 - 6 - 5) & 0x1F;
+ int rt = stmt.getBinaryStatement() >>> (32 - 6 - 5 - 5) & 0x1F;
+
+ int valRS = RegisterFile.getRegisters()[rs].getValue();
+ int valRT = RegisterFile.getRegisters()[rt].getValue();
+
+
+ if (opCode == 0x01)
+ {
+ switch (funct)
+ {
+ case 0x00:
+ return valRS < 0; // bltz
+ case 0x01:
+ return valRS >= 0; // bgez
+ case 0x02:
+ return valRS < 0; // bltzl
+ case 0x03:
+ return valRS >= 0; // bgezl
+ }
+ }
+
+ switch (opCode)
+ {
+ case 0x04:
+ return valRS == valRT;
+ case 0x05:
+ return valRS != valRT;
+ case 0x06:
+ return valRS <= 0;
+ case 0x07:
+ return valRS >= 0;
+ case 0x14:
+ return valRS == valRT;
+ case 0x15:
+ return valRS != valRT;
+ case 0x16:
+ return valRS <= 0;
+ case 0x17:
+ return valRS >= 0;
+ }
+
+ return true;
+ }
+
+ /**
+ * Extracts the target address of the branch.
+ *
+ * In MIPS the target address is encoded as 16-bit value. The target address is encoded relative to the address of
+ * the instruction after the branch instruction
+ *
+ * @param stmt the branch instruction
+ * @return the address of the instruction that is executed if the branch is taken
+ */
+ protected static int extractBranchAddress(ProgramStatement stmt)
+ {
+ short offset = (short) (stmt.getBinaryStatement() & 0xFFFF);
+ return stmt.getAddress() + (offset << 2) + 4;
+ }
+
+ /**
+ * Adds BHTSimulator as observer of the text segment.
+ */
+ protected void addAsObserver()
+ {
+ addAsObserver(Memory.textBaseAddress, Memory.textLimitAddress);
+ addAsObserver(RegisterFile.getProgramCounterRegister());
+ }
+
+ /**
+ * Creates a GUI and initialize the GUI with the default values.
+ */
+ protected JComponent buildMainDisplayArea()
+ {
+
+ m_gui = new BHTSimGUI();
+ m_bhtModel = new BHTableModel(BHTSimulator.BHT_DEFAULT_SIZE, BHTSimulator.BHT_DEFAULT_HISTORY, BHT_DEFAULT_INITVAL);
+
+ m_gui.getTabBHT().setModel(m_bhtModel);
+ m_gui.getCbBHThistory().setSelectedItem(Integer.valueOf(BHTSimulator.BHT_DEFAULT_HISTORY));
+ m_gui.getCbBHTentries().setSelectedItem(Integer.valueOf(BHTSimulator.BHT_DEFAULT_SIZE));
+
+ m_gui.getCbBHTentries().addActionListener(this);
+ m_gui.getCbBHThistory().addActionListener(this);
+ m_gui.getCbBHTinitVal().addActionListener(this);
+
+ return m_gui;
+ }
+
+ /**
+ * Returns the name of the tool.
+ *
+ * @return the tool's name as String
+ */
+ public String getName()
+ {
+ return BHTSimulator.BHT_NAME;
+ }
+
+ /**
+ * Performs a reset of the simulator. This causes the BHT to be reseted and the log messages to be cleared.
+ */
+ protected void reset()
+ {
+ resetSimulator();
+ }
+
+ /**
+ * Handles the actions when selecting another value in one of the two combo boxes. Selecting a different BHT size or
+ * history causes a reset of the simulator.
+ */
+ public void actionPerformed(ActionEvent event)
+ {
+ // change of the BHT size or BHT bit configuration
+ // resets the simulator
+ if (event.getSource() == m_gui.getCbBHTentries() || event.getSource() == m_gui.getCbBHThistory() || event.getSource() == m_gui.getCbBHTinitVal())
+ {
+ resetSimulator();
+ }
+ }
+
+ /**
+ * Resets the simulator by clearing the GUI elements and resetting the BHT.
+ */
+ protected void resetSimulator()
+ {
+ m_gui.getTfInstruction().setText("");
+ m_gui.getTfAddress().setText("");
+ m_gui.getTfIndex().setText("");
+ m_gui.getTaLog().setText("");
+ m_bhtModel.initBHT(((Integer) m_gui.getCbBHTentries().getSelectedItem()).intValue(),
+ ((Integer) m_gui.getCbBHThistory().getSelectedItem()).intValue(),
+ m_gui.getCbBHTinitVal().getSelectedItem().equals(BHTSimGUI.BHT_TAKE_BRANCH));
+
+ m_pendingBranchInstAddress = 0;
+ m_lastBranchTaken = false;
+ }
+
+ /**
+ * Handles the execution branch instruction. This method is called each time a branch instruction is executed. Based
+ * on the address of the instruction the corresponding index into the BHT is calculated. The prediction is obtained
+ * from the BHT at the calculated index and is visualized appropriately.
+ *
+ * @param stmt the branch statement that is executed
+ */
+ protected void handlePreBranchInst(ProgramStatement stmt)
+ {
+
+ String strStmt = stmt.getBasicAssemblyStatement();
+ int address = stmt.getAddress();
+ int idx = m_bhtModel.getIdxForAddress(address);
+
+ // update the GUI
+ m_gui.getTfInstruction().setText(strStmt);
+ m_gui.getTfAddress().setText("0x" + Integer.toHexString(address));
+ m_gui.getTfIndex().setText("" + idx);
+
+ // mark the affected BHT row
+ m_gui.getTabBHT().setSelectionBackground(BHTSimGUI.COLOR_PREPREDICTION);
+ m_gui.getTabBHT().addRowSelectionInterval(idx, idx);
+
+ // add output to log
+ m_gui.getTaLog().append("instruction " + strStmt + " at address 0x" + Integer.toHexString(address) + ", maps to index " + idx + "\n");
+ m_gui.getTaLog().append("branches to address 0x" + BHTSimulator.extractBranchAddress(stmt) + "\n");
+ m_gui.getTaLog().append("prediction is: " + (m_bhtModel.getPredictionAtIdx(idx) ? "take" : "do not take") + "...\n");
+ m_gui.getTaLog().setCaretPosition(m_gui.getTaLog().getDocument().getLength());
+
+ }
+
+ /**
+ * Handles the execution of the branch instruction. The correctness of the prediction is visualized in both the
+ * table and the log message area. The BHT is updated based on the information if the branch instruction was taken
+ * or not.
+ *
+ * @param branchInstAddr the address of the branch instruction
+ * @param branchTaken the information if the branch is taken or not (determined in a step before)
+ */
+ protected void handleExecBranchInst(int branchInstAddr, boolean branchTaken)
+ {
+
+ // determine the index in the BHT for the branch instruction
+ int idx = m_bhtModel.getIdxForAddress(branchInstAddr);
+
+ // check if the prediction is correct
+ boolean correctPrediction = m_bhtModel.getPredictionAtIdx(idx) == branchTaken;
+
+ m_gui.getTabBHT().setSelectionBackground(correctPrediction ? BHTSimGUI.COLOR_PREDICTION_CORRECT : BHTSimGUI.COLOR_PREDICTION_INCORRECT);
+
+ // add some output at the log
+ m_gui.getTaLog().append("branch " + (branchTaken ? "taken" : "not taken") + ", prediction was " + (correctPrediction ? "correct" : "incorrect") + "\n\n");
+ m_gui.getTaLog().setCaretPosition(m_gui.getTaLog().getDocument().getLength());
+
+ // update the BHT -> causes refresh of the table
+ m_bhtModel.updatePredictionAtIdx(idx, branchTaken);
+ }
+
+ /**
+ * Callback for text segment access by the MIPS simulator.
+ *
+ * The method is called each time the text segment is accessed to fetch the next instruction. If the next
+ * instruction to execute was a branch instruction, the branch prediction is performed and visualized. In case the
+ * last instruction was a branch instruction, the outcome of the branch prediction is analyzed and visualized.
+ *
+ * @param resource the observed resource
+ * @param notice signals the type of access (memory, register etc.)
+ */
+ protected void processMIPSUpdate(Observable resource, AccessNotice notice)
+ {
+
+ if (!notice.accessIsFromMIPS())
+ {
+ return;
+ }
+
+
+ if (notice.getAccessType() == AccessNotice.READ && notice instanceof MemoryAccessNotice)
+ {
+
+ // now it is safe to make a cast of the notice
+ MemoryAccessNotice memAccNotice = (MemoryAccessNotice) notice;
+
+ try
+ {
+ // access the statement in the text segment without notifying other tools etc.
+ ProgramStatement stmt = Memory.getInstance().getStatementNoNotify(memAccNotice.getAddress());
+
+ // necessary to handle possible null pointers at the end of the program
+ // (e.g., if the simulator tries to execute the next instruction after the last instruction in the text segment)
+ if (stmt != null)
+ {
+
+ boolean clearTextFields = true;
+
+ // first, check if there's a pending branch to handle
+ if (m_pendingBranchInstAddress != 0)
+ {
+ handleExecBranchInst(m_pendingBranchInstAddress, m_lastBranchTaken);
+ clearTextFields = false;
+ m_pendingBranchInstAddress = 0;
+ }
+
+
+ // if current instruction is branch instruction
+ if (BHTSimulator.isBranchInstruction(stmt))
+ {
+ handlePreBranchInst(stmt);
+ m_lastBranchTaken = willBranch(stmt);
+ m_pendingBranchInstAddress = stmt.getAddress();
+ clearTextFields = false;
+ }
+
+
+ // clear text fields and selection
+ if (clearTextFields)
+ {
+ m_gui.getTfInstruction().setText("");
+ m_gui.getTfAddress().setText("");
+ m_gui.getTfIndex().setText("");
+ m_gui.getTabBHT().clearSelection();
+ }
+ }
+ else
+ {
+ // check if there's a pending branch to handle
+ if (m_pendingBranchInstAddress != 0)
+ {
+ handleExecBranchInst(m_pendingBranchInstAddress, m_lastBranchTaken);
+ m_pendingBranchInstAddress = 0;
+ }
+ }
+ }
+ catch (AddressErrorException e)
+ {
+ // silently ignore these exceptions
+ }
+
+ }
+ }
}
diff --git a/src/main/java/mars/tools/BHTableModel.java b/src/main/java/mars/tools/BHTableModel.java
index 6e9b818..f9a24f9 100644
--- a/src/main/java/mars/tools/BHTableModel.java
+++ b/src/main/java/mars/tools/BHTableModel.java
@@ -27,18 +27,16 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package mars.tools;//.bhtsim;
-import java.util.Vector;
-
import javax.swing.table.AbstractTableModel;
+import java.util.Vector;
/**
* Simulates the actual functionality of a Branch History Table (BHT).
*
- * The BHT consists of a number of BHT entries which are used to perform branch prediction.
- * The entries of the BHT are stored as a Vector of BHTEntry objects.
- * The number of entries is configurable but has to be a power of 2.
- * The history kept by each BHT entry is also configurable during run-time.
- * A change of the configuration however causes a complete reset of the BHT.
+ * The BHT consists of a number of BHT entries which are used to perform branch prediction. The entries of the BHT are
+ * stored as a Vector of BHTEntry objects. The number of entries is configurable but has to be a power of 2. The history
+ * kept by each BHT entry is also configurable during run-time. A change of the configuration however causes a complete
+ * reset of the BHT.
*
* The typical interaction is as follows:
*
@@ -49,190 +47,230 @@ import javax.swing.table.AbstractTableModel;
*
*
* Additionally it serves as TableModel that can be directly used to render the state of the BHT in a JTable.
- * Feedback provided to the BHT causes a change of the internal state and a repaint of the table(s) associated to this model.
- *
+ * Feedback provided to the BHT causes a change of the internal state and a repaint of the table(s) associated to this model.
+ *
* @author ingo.kofler@itec.uni-klu.ac.at
*/
//@SuppressWarnings("serial")
-public class BHTableModel extends AbstractTableModel {
+public class BHTableModel extends AbstractTableModel
+{
- /** vector holding the entries of the BHT */
- private Vector m_entries;
-
- /** number of entries in the BHT */
- private int m_entryCnt;
-
- /** number of past branch events to remember */
- private int m_historySize;
-
- /** name of the table columns */
- private String m_columnNames[] = { "Index", "History", "Prediction", "Correct", "Incorrect", "Precision"};
-
- /** type of the table columns */
- //@SuppressWarnings("unchecked")
- private Class m_columnClasses[] = { Integer.class, String.class, String.class, Integer.class, Integer.class, Double.class};
+ /** vector holding the entries of the BHT */
+ private Vector m_entries;
+
+ /** number of entries in the BHT */
+ private int m_entryCnt;
+
+ /** number of past branch events to remember */
+ private int m_historySize;
+
+ /** name of the table columns */
+ private final String[] m_columnNames = {"Index", "History", "Prediction", "Correct", "Incorrect", "Precision"};
+
+ /** type of the table columns */
+ //@SuppressWarnings("unchecked")
+ private final Class[] m_columnClasses = {Integer.class, String.class, String.class, Integer.class, Integer.class, Double.class};
+
+
+ /**
+ * Constructs a new BHT with given number of entries and history size.
+ *
+ * @param numEntries number of entries in the BHT
+ * @param historySize size of the history (in bits/number of past branches)
+ */
+ public BHTableModel(int numEntries, int historySize, boolean initVal)
+ {
+ initBHT(numEntries, historySize, initVal);
+ }
+
+
+ /**
+ * Returns the name of the i-th column of the table. Required by the TableModel interface.
+ *
+ * @param i the index of the column
+ * @return name of the i-th column
+ */
+ public String getColumnName(int i)
+ {
+ if (i < 0 || i > m_columnNames.length)
+ {
+ throw new IllegalArgumentException("Illegal column index " + i + " (must be in range 0.." + (m_columnNames.length - 1) + ")");
+ }
-
- /**
- * Constructs a new BHT with given number of entries and history size.
- *
- * @param numEntries number of entries in the BHT
- * @param historySize size of the history (in bits/number of past branches)
- */
- public BHTableModel (int numEntries, int historySize, boolean initVal) {
- initBHT(numEntries, historySize, initVal);
- }
-
-
- /**
- * Returns the name of the i-th column of the table.
- * Required by the TableModel interface.
- *
- * @param i the index of the column
- * @return name of the i-th column
- */
- public String getColumnName(int i) {
- if (i < 0 || i > m_columnNames.length)
- throw new IllegalArgumentException("Illegal column index " + i + " (must be in range 0.." + (m_columnNames.length-1) + ")");
-
return m_columnNames[i];
}
-
-
- /**
- * Returns the class/type of the i-th column of the table.
- * Required by the TableModel interface.
- *
- * @param i the index of the column
- * @return class representing the type of the i-th column
- */
- public Class getColumnClass(int i) {
- if (i < 0 || i > m_columnClasses.length)
- throw new IllegalArgumentException("Illegal column index " + i + " (must be in range 0.." + (m_columnClasses.length-1) + ")");
-
- return m_columnClasses[i];
- }
-
-
- /**
- * Returns the number of columns.
- * Required by the TableModel interface.
- *
- * @return currently the constant 6
- */
- public int getColumnCount() {
- return 6;
- }
-
- /**
- * Returns the number of entries of the BHT.
- * Required by the TableModel interface.
- *
- * @return number of rows / entries of the BHT
- */
- public int getRowCount() {
- return m_entryCnt;
- }
-
- /**
- * Returns the value of the cell at the given row and column
- * Required by the TableModel interface.
- *
- * @param row the row index
- * @param col the column index
- * @return the value of the cell
- */
- public Object getValueAt(int row, int col) {
-
- BHTEntry e = (BHTEntry) m_entries.elementAt(row);
- if (e==null) return "";
-
- if (col==0) return new Integer(row);
- if (col==1) return e.getHistoryAsStr();
- if (col==2) return e.getPredictionAsStr();
- if (col==3) return new Integer(e.getStatsPredCorrect());
- if (col==4) return new Integer(e.getStatsPredIncorrect());
- if (col==5) return new Double(e.getStatsPredPrecision());
-
- return "";
- }
-
-
- /**
- * Initializes the BHT with the given size and history.
- * All previous data like the BHT entries' history and statistics will get lost.
- * A refresh of the table that use this BHT as model will be triggered.
- *
- * @param numEntries number of entries in the BHT (has to be a power of 2)
- * @param historySize size of the history to consider
- * @param initVal initial value for each entry (true means take branch, false do not take branch)
- */
- public void initBHT(int numEntries, int historySize, boolean initVal) {
-
- if (numEntries <= 0 || (numEntries & (numEntries-1)) != 0)
- throw new IllegalArgumentException("Number of entries must be a positive power of 2.");
- if (historySize < 1 || historySize > 2)
- throw new IllegalArgumentException("Only history sizes of 1 or 2 supported.");
-
- m_entryCnt = numEntries;
- m_historySize = historySize;
-
- m_entries = new Vector();
-
- for (int i=0; i < m_entryCnt; i++) {
- m_entries.add(new BHTEntry(m_historySize, initVal));
- }
+ /**
+ * Returns the class/type of the i-th column of the table. Required by the TableModel interface.
+ *
+ * @param i the index of the column
+ * @return class representing the type of the i-th column
+ */
+ public Class getColumnClass(int i)
+ {
+ if (i < 0 || i > m_columnClasses.length)
+ {
+ throw new IllegalArgumentException("Illegal column index " + i + " (must be in range 0.." + (m_columnClasses.length - 1) + ")");
+ }
- // refresh the table(s)
- fireTableStructureChanged();
- }
-
-
- /**
- * Returns the index into the BHT for a given branch instruction address.
- * A simple direct mapping is used.
- *
- * @param address the address of the branch instruction
- * @return the index into the BHT
- */
- public int getIdxForAddress(int address) {
- if (address < 0)
- throw new IllegalArgumentException("No negative addresses supported");
-
- return (address >> 2) % m_entryCnt;
- }
-
-
- /**
- * Retrieve the prediction for the i-th BHT entry.
- *
- * @param index the index of the entry in the BHT
- * @return the prediction to take (true) or do not take (false) the branch
- */
- public boolean getPredictionAtIdx(int index) {
- if (index < 0 || index > m_entryCnt)
- throw new IllegalArgumentException("Only indexes in the range 0 to " + (m_entryCnt-1) + " allowed");
-
- return ((BHTEntry) m_entries.elementAt(index)).getPrediction();
- }
-
-
- /**
- * Updates the BHT entry with the outcome of the branch instruction.
- * This causes a change in the model and signals to update the connected table(s).
- *
- * @param index the index of the entry in the BHT
- * @param branchTaken
- */
- public void updatePredictionAtIdx(int index, boolean branchTaken) {
- if (index < 0 || index > m_entryCnt)
- throw new IllegalArgumentException("Only indexes in the range 0 to " + (m_entryCnt-1) + " allowed");
-
- ((BHTEntry) m_entries.elementAt(index)).updatePrediction(branchTaken);
- fireTableRowsUpdated(index, index);
- }
+ return m_columnClasses[i];
+ }
+
+
+ /**
+ * Returns the number of columns. Required by the TableModel interface.
+ *
+ * @return currently the constant 6
+ */
+ public int getColumnCount()
+ {
+ return 6;
+ }
+
+
+ /**
+ * Returns the number of entries of the BHT. Required by the TableModel interface.
+ *
+ * @return number of rows / entries of the BHT
+ */
+ public int getRowCount()
+ {
+ return m_entryCnt;
+ }
+
+
+ /**
+ * Returns the value of the cell at the given row and column Required by the TableModel interface.
+ *
+ * @param row the row index
+ * @param col the column index
+ * @return the value of the cell
+ */
+ public Object getValueAt(int row, int col)
+ {
+
+ BHTEntry e = (BHTEntry) m_entries.elementAt(row);
+ if (e == null)
+ {
+ return "";
+ }
+
+ if (col == 0)
+ {
+ return Integer.valueOf(row);
+ }
+ if (col == 1)
+ {
+ return e.getHistoryAsStr();
+ }
+ if (col == 2)
+ {
+ return e.getPredictionAsStr();
+ }
+ if (col == 3)
+ {
+ return Integer.valueOf(e.getStatsPredCorrect());
+ }
+ if (col == 4)
+ {
+ return Integer.valueOf(e.getStatsPredIncorrect());
+ }
+ if (col == 5)
+ {
+ return new Double(e.getStatsPredPrecision());
+ }
+
+ return "";
+ }
+
+
+ /**
+ * Initializes the BHT with the given size and history. All previous data like the BHT entries' history and
+ * statistics will get lost. A refresh of the table that use this BHT as model will be triggered.
+ *
+ * @param numEntries number of entries in the BHT (has to be a power of 2)
+ * @param historySize size of the history to consider
+ * @param initVal initial value for each entry (true means take branch, false do not take branch)
+ */
+ public void initBHT(int numEntries, int historySize, boolean initVal)
+ {
+
+ if (numEntries <= 0 || (numEntries & (numEntries - 1)) != 0)
+ {
+ throw new IllegalArgumentException("Number of entries must be a positive power of 2.");
+ }
+ if (historySize < 1 || historySize > 2)
+ {
+ throw new IllegalArgumentException("Only history sizes of 1 or 2 supported.");
+ }
+
+ m_entryCnt = numEntries;
+ m_historySize = historySize;
+
+ m_entries = new Vector();
+
+ for (int i = 0; i < m_entryCnt; i++)
+ {
+ m_entries.add(new BHTEntry(m_historySize, initVal));
+ }
+
+ // refresh the table(s)
+ fireTableStructureChanged();
+ }
+
+
+ /**
+ * Returns the index into the BHT for a given branch instruction address. A simple direct mapping is used.
+ *
+ * @param address the address of the branch instruction
+ * @return the index into the BHT
+ */
+ public int getIdxForAddress(int address)
+ {
+ if (address < 0)
+ {
+ throw new IllegalArgumentException("No negative addresses supported");
+ }
+
+ return (address >> 2) % m_entryCnt;
+ }
+
+
+ /**
+ * Retrieve the prediction for the i-th BHT entry.
+ *
+ * @param index the index of the entry in the BHT
+ * @return the prediction to take (true) or do not take (false) the branch
+ */
+ public boolean getPredictionAtIdx(int index)
+ {
+ if (index < 0 || index > m_entryCnt)
+ {
+ throw new IllegalArgumentException("Only indexes in the range 0 to " + (m_entryCnt - 1) + " allowed");
+ }
+
+ return ((BHTEntry) m_entries.elementAt(index)).getPrediction();
+ }
+
+
+ /**
+ * Updates the BHT entry with the outcome of the branch instruction. This causes a change in the model and signals
+ * to update the connected table(s).
+ *
+ * @param index the index of the entry in the BHT
+ * @param branchTaken
+ */
+ public void updatePredictionAtIdx(int index, boolean branchTaken)
+ {
+ if (index < 0 || index > m_entryCnt)
+ {
+ throw new IllegalArgumentException("Only indexes in the range 0 to " + (m_entryCnt - 1) + " allowed");
+ }
+
+ ((BHTEntry) m_entries.elementAt(index)).updatePrediction(branchTaken);
+ fireTableRowsUpdated(index, index);
+ }
}
diff --git a/src/main/java/mars/tools/BitmapDisplay.java b/src/main/java/mars/tools/BitmapDisplay.java
index 9272c72..5415793 100644
--- a/src/main/java/mars/tools/BitmapDisplay.java
+++ b/src/main/java/mars/tools/BitmapDisplay.java
@@ -1,12 +1,15 @@
- package mars.tools;
- import javax.swing.*;
- import javax.swing.border.*;
- import javax.swing.event.*;
- import java.awt.*;
- import java.awt.event.*;
- import java.util.*;
- import mars.tools.*;
- import mars.mips.hardware.*;
+package mars.tools;
+
+import mars.mips.hardware.AccessNotice;
+import mars.mips.hardware.Memory;
+import mars.mips.hardware.MemoryAccessNotice;
+
+import javax.swing.*;
+import javax.swing.border.EmptyBorder;
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.Observable;
/*
Copyright (c) 2010-2011, Pete Sanderson and Kenneth Vollmar
@@ -35,387 +38,438 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
(MIT license, http://www.opensource.org/licenses/mit-license.html)
*/
-
- /**
- * Bitmapp display simulator. It can be run either as a stand-alone Java application having
- * access to the mars package, or through MARS as an item in its Tools menu. It makes
- * maximum use of methods inherited from its abstract superclass AbstractMarsToolAndApplication.
- * Pete Sanderson, verison 1.0, 23 December 2010.
- */
- public class BitmapDisplay extends AbstractMarsToolAndApplication {
-
- private static String version = "Version 1.0";
- private static String heading = "Bitmap Display";
-
- // Major GUI components
- private JComboBox visualizationUnitPixelWidthSelector, visualizationUnitPixelHeightSelector,
- visualizationPixelWidthSelector, visualizationPixelHeightSelector, displayBaseAddressSelector;
- private Graphics drawingArea;
- private JPanel canvas;
- private JPanel results;
-
- // Some GUI settings
- private EmptyBorder emptyBorder = new EmptyBorder(4,4,4,4);
- private Font countFonts = new Font("Times", Font.BOLD,12);
- private Color backgroundColor = Color.WHITE;
-
- // Values for Combo Boxes
-
- private final String[] visualizationUnitPixelWidthChoices = {"1","2","4","8","16","32"};
- private final int defaultVisualizationUnitPixelWidthIndex = 0;
- private final String[] visualizationUnitPixelHeightChoices = {"1","2","4","8","16","32"};
- private final int defaultVisualizationUnitPixelHeightIndex = 0;
- private final String[] displayAreaPixelWidthChoices = {"64","128","256","512","1024"};
- private final int defaultDisplayWidthIndex = 3;
- private final String[] displayAreaPixelHeightChoices = {"64","128","256","512","1024"};
- private final int defaultDisplayHeightIndex = 2;
-
- // Values for display canvas. Note their initialization uses the identifiers just above.
-
- private int unitPixelWidth = Integer.parseInt(visualizationUnitPixelWidthChoices[defaultVisualizationUnitPixelWidthIndex]);
- private int unitPixelHeight = Integer.parseInt(visualizationUnitPixelHeightChoices[defaultVisualizationUnitPixelHeightIndex]);
- private int displayAreaWidthInPixels = Integer.parseInt(displayAreaPixelWidthChoices[defaultDisplayWidthIndex]);
- private int displayAreaHeightInPixels = Integer.parseInt(displayAreaPixelHeightChoices[defaultDisplayHeightIndex]);
-
-
- // The next four are initialized dynamically in initializeDisplayBaseChoices()
- private String[] displayBaseAddressChoices;
- private int[] displayBaseAddresses;
- private int defaultBaseAddressIndex;
- private int baseAddress;
-
- private Grid theGrid;
-
- /**
- * Simple constructor, likely used to run a stand-alone bitmap display tool.
- * @param title String containing title for title bar
- * @param heading String containing text for heading shown in upper part of window.
- */
- public BitmapDisplay(String title, String heading) {
- super(title,heading);
- }
-
- /**
- * Simple constructor, likely used by the MARS Tools menu mechanism
- */
- public BitmapDisplay() {
- super ("Bitmap Display, "+version, heading);
- }
-
-
- /**
- * Main provided for pure stand-alone use. Recommended stand-alone use is to write a
- * driver program that instantiates a Bitmap object then invokes its go() method.
- * "stand-alone" means it is not invoked from the MARS Tools menu. "Pure" means there
- * is no driver program to invoke the application.
- */
- public static void main(String[] args) {
- new BitmapDisplay("Bitmap Display stand-alone, "+version,heading).go();
- }
-
-
- /**
- * Required MarsTool method to return Tool name.
- * @return Tool name. MARS will display this in menu item.
- */
- public String getName() {
- return "Bitmap Display";
- }
-
-
- /**
- * Override the inherited method, which registers us as an Observer over the static data segment
- * (starting address 0x10010000) only. This version will register us as observer over the
- * the memory range as selected by the base address combo box and capacity of the visualization display
- * (number of visualization elements times the number of memory words each one represents).
- * It does so by calling the inherited 2-parameter overload of this method.
- * If you use the inherited GUI buttons, this
- * method is invoked when you click "Connect" button on MarsTool or the
- * "Assemble and Run" button on a Mars-based app.
- */
- protected void addAsObserver() {
- int highAddress = baseAddress+theGrid.getRows()*theGrid.getColumns()*Memory.WORD_LENGTH_BYTES;
- // Special case: baseAddress<0 means we're in kernel memory (0x80000000 and up) and most likely
- // in memory map address space (0xffff0000 and up). In this case, we need to make sure the high address
- // does not drop off the high end of 32 bit address space. Highest allowable word address is 0xfffffffc,
- // which is interpreted in Java int as -4.
- if (baseAddress < 0 && highAddress > -4) {
+
+/**
+ * Bitmapp display simulator. It can be run either as a stand-alone Java application having access to the mars package,
+ * or through MARS as an item in its Tools menu. It makes maximum use of methods inherited from its abstract superclass
+ * AbstractMarsToolAndApplication. Pete Sanderson, verison 1.0, 23 December 2010.
+ */
+public class BitmapDisplay extends AbstractMarsToolAndApplication
+{
+
+ private static final String version = "Version 1.0";
+
+ private static final String heading = "Bitmap Display";
+
+ private final String[] visualizationUnitPixelWidthChoices = {"1", "2", "4", "8", "16", "32"};
+
+ private final int defaultVisualizationUnitPixelWidthIndex = 0;
+
+ private final String[] visualizationUnitPixelHeightChoices = {"1", "2", "4", "8", "16", "32"};
+
+ private final int defaultVisualizationUnitPixelHeightIndex = 0;
+
+ private final String[] displayAreaPixelWidthChoices = {"64", "128", "256", "512", "1024"};
+
+ private final int defaultDisplayWidthIndex = 3;
+
+ private final String[] displayAreaPixelHeightChoices = {"64", "128", "256", "512", "1024"};
+
+ // Values for Combo Boxes
+
+ private final int defaultDisplayHeightIndex = 2;
+
+ // Major GUI components
+ private JComboBox visualizationUnitPixelWidthSelector, visualizationUnitPixelHeightSelector,
+ visualizationPixelWidthSelector, visualizationPixelHeightSelector, displayBaseAddressSelector;
+
+ private Graphics drawingArea;
+
+ private JPanel canvas;
+
+ private JPanel results;
+
+ // Some GUI settings
+ private final EmptyBorder emptyBorder = new EmptyBorder(4, 4, 4, 4);
+
+ private final Font countFonts = new Font("Times", Font.BOLD, 12);
+
+ private final Color backgroundColor = Color.WHITE;
+
+ // Values for display canvas. Note their initialization uses the identifiers just above.
+
+ private int unitPixelWidth = Integer.parseInt(visualizationUnitPixelWidthChoices[defaultVisualizationUnitPixelWidthIndex]);
+
+ private int unitPixelHeight = Integer.parseInt(visualizationUnitPixelHeightChoices[defaultVisualizationUnitPixelHeightIndex]);
+
+ private int displayAreaWidthInPixels = Integer.parseInt(displayAreaPixelWidthChoices[defaultDisplayWidthIndex]);
+
+ private int displayAreaHeightInPixels = Integer.parseInt(displayAreaPixelHeightChoices[defaultDisplayHeightIndex]);
+
+
+ // The next four are initialized dynamically in initializeDisplayBaseChoices()
+ private String[] displayBaseAddressChoices;
+
+ private int[] displayBaseAddresses;
+
+ private int defaultBaseAddressIndex;
+
+ private int baseAddress;
+
+ private Grid theGrid;
+
+ /**
+ * Simple constructor, likely used to run a stand-alone bitmap display tool.
+ *
+ * @param title String containing title for title bar
+ * @param heading String containing text for heading shown in upper part of window.
+ */
+ public BitmapDisplay(String title, String heading)
+ {
+ super(title, heading);
+ }
+
+ /**
+ * Simple constructor, likely used by the MARS Tools menu mechanism
+ */
+ public BitmapDisplay()
+ {
+ super("Bitmap Display, " + version, heading);
+ }
+
+
+ /**
+ * Main provided for pure stand-alone use. Recommended stand-alone use is to write a driver program that
+ * instantiates a Bitmap object then invokes its go() method. "stand-alone" means it is not invoked from the MARS
+ * Tools menu. "Pure" means there is no driver program to invoke the application.
+ */
+ public static void main(String[] args)
+ {
+ new BitmapDisplay("Bitmap Display stand-alone, " + version, heading).go();
+ }
+
+
+ /**
+ * Required MarsTool method to return Tool name.
+ *
+ * @return Tool name. MARS will display this in menu item.
+ */
+ public String getName()
+ {
+ return "Bitmap Display";
+ }
+
+
+ /**
+ * Override the inherited method, which registers us as an Observer over the static data segment (starting address
+ * 0x10010000) only. This version will register us as observer over the the memory range as selected by the base
+ * address combo box and capacity of the visualization display (number of visualization elements times the number of
+ * memory words each one represents). It does so by calling the inherited 2-parameter overload of this method. If
+ * you use the inherited GUI buttons, this method is invoked when you click "Connect" button on MarsTool or the
+ * "Assemble and Run" button on a Mars-based app.
+ */
+ protected void addAsObserver()
+ {
+ int highAddress = baseAddress + theGrid.getRows() * theGrid.getColumns() * Memory.WORD_LENGTH_BYTES;
+ // Special case: baseAddress<0 means we're in kernel memory (0x80000000 and up) and most likely
+ // in memory map address space (0xffff0000 and up). In this case, we need to make sure the high address
+ // does not drop off the high end of 32 bit address space. Highest allowable word address is 0xfffffffc,
+ // which is interpreted in Java int as -4.
+ if (baseAddress < 0 && highAddress > -4)
+ {
highAddress = -4;
- }
- addAsObserver(baseAddress, highAddress);
- }
-
-
- /**
- * Method that constructs the main display area. It is organized vertically
- * into two major components: the display configuration which an be modified
- * using combo boxes, and the visualization display which is updated as the
- * attached MIPS program executes.
- * @return the GUI component containing these two areas
- */
- protected JComponent buildMainDisplayArea() {
- results = new JPanel();
- results.add(buildOrganizationArea());
- results.add(buildVisualizationArea());
- return results;
- }
-
-
- //////////////////////////////////////////////////////////////////////////////////////
- // Rest of the protected methods. These override do-nothing methods inherited from
- // the abstract superclass.
- //////////////////////////////////////////////////////////////////////////////////////
-
- /**
- * Update display when connected MIPS program accesses (data) memory.
- * @param memory the attached memory
- * @param accessNotice information provided by memory in MemoryAccessNotice object
- */
- protected void processMIPSUpdate(Observable memory, AccessNotice accessNotice) {
- if (accessNotice.getAccessType() == AccessNotice.WRITE) {
- updateColorForAddress((MemoryAccessNotice)accessNotice);
- }
- }
-
-
- /**
- * Initialize all JComboBox choice structures not already initialized at declaration.
- * Overrides inherited method that does nothing.
- */
- protected void initializePreGUI() {
- initializeDisplayBaseChoices();
- // NOTE: Can't call "createNewGrid()" here because it uses settings from
- // several combo boxes that have not been created yet. But a default grid
- // needs to be allocated for initial canvas display.
- theGrid = new Grid(displayAreaHeightInPixels/unitPixelHeight,
- displayAreaWidthInPixels/unitPixelWidth);
- }
-
-
- /**
- * The only post-GUI initialization is to create the initial Grid object based on the default settings
- * of the various combo boxes. Overrides inherited method that does nothing.
- */
-
- protected void initializePostGUI() {
- theGrid = createNewGrid();
- updateBaseAddress();
- }
-
-
- /**
- * Method to reset counters and display when the Reset button selected.
- * Overrides inherited method that does nothing.
- */
- protected void reset() {
- resetCounts();
- updateDisplay();
- }
-
- /**
- * Updates display immediately after each update (AccessNotice) is processed, after
- * display configuration changes as needed, and after each execution step when Mars
- * is running in timed mode. Overrides inherited method that does nothing.
- */
- protected void updateDisplay() {
- canvas.repaint();
- }
-
-
- /**
- * Overrides default method, to provide a Help button for this tool/app.
- */
- protected JComponent getHelpComponent() {
- final String helpContent =
- "Use this program to simulate a basic bitmap display where\n"+
- "each memory word in a specified address space corresponds to\n"+
- "one display pixel in row-major order starting at the upper left\n"+
- "corner of the display. This tool may be run either from the\n"+
- "MARS Tools menu or as a stand-alone application.\n"+
- "\n"+
- "You can easily learn to use this small program by playing with\n"+
- "it! Each rectangular unit on the display represents one memory\n"+
- "word in a contiguous address space starting with the specified\n"+
- "base address. The value stored in that word will be interpreted\n"+
- "as a 24-bit RGB color value with the red component in bits 16-23,\n"+
- "the green component in bits 8-15, and the blue component in bits 0-7.\n"+
- "Each time a memory word within the display address space is written\n"+
- "by the MIPS program, its position in the display will be rendered\n"+
- "in the color that its value represents.\n"+
- "\n"+
- "Version 1.0 is very basic and was constructed from the Memory\n"+
- "Reference Visualization tool's code. Feel free to improve it and\n"+
- "send me your code for consideration in the next MARS release.\n"+
- "\n"+
- "Contact Pete Sanderson at psanderson@otterbein.edu with\n"+
- "questions or comments.\n";
- JButton help = new JButton("Help");
- help.addActionListener(
- new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- JOptionPane.showMessageDialog(theWindow, helpContent);
- }
- });
- return help;
- }
-
- //////////////////////////////////////////////////////////////////////////////////////
- // Private methods defined to support the above.
- //////////////////////////////////////////////////////////////////////////////////////
-
- // UI components and layout for left half of GUI, where settings are specified.
- private JComponent buildOrganizationArea() {
- JPanel organization = new JPanel(new GridLayout(8,1));
-
- visualizationUnitPixelWidthSelector = new JComboBox(visualizationUnitPixelWidthChoices);
- visualizationUnitPixelWidthSelector.setEditable(false);
- visualizationUnitPixelWidthSelector.setBackground(backgroundColor);
- visualizationUnitPixelWidthSelector.setSelectedIndex(defaultVisualizationUnitPixelWidthIndex);
- visualizationUnitPixelWidthSelector.setToolTipText("Width in pixels of rectangle representing memory word");
- visualizationUnitPixelWidthSelector.addActionListener(
- new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- unitPixelWidth = getIntComboBoxSelection(visualizationUnitPixelWidthSelector);
- theGrid = createNewGrid();
- updateDisplay();
- }
- });
- visualizationUnitPixelHeightSelector = new JComboBox(visualizationUnitPixelHeightChoices);
- visualizationUnitPixelHeightSelector.setEditable(false);
- visualizationUnitPixelHeightSelector.setBackground(backgroundColor);
- visualizationUnitPixelHeightSelector.setSelectedIndex(defaultVisualizationUnitPixelHeightIndex);
- visualizationUnitPixelHeightSelector.setToolTipText("Height in pixels of rectangle representing memory word");
- visualizationUnitPixelHeightSelector.addActionListener(
- new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- unitPixelHeight = getIntComboBoxSelection(visualizationUnitPixelHeightSelector);
- theGrid = createNewGrid();
- updateDisplay();
- }
- });
- visualizationPixelWidthSelector = new JComboBox(displayAreaPixelWidthChoices);
- visualizationPixelWidthSelector.setEditable(false);
- visualizationPixelWidthSelector.setBackground(backgroundColor);
- visualizationPixelWidthSelector.setSelectedIndex(defaultDisplayWidthIndex);
- visualizationPixelWidthSelector.setToolTipText("Total width in pixels of display area");
- visualizationPixelWidthSelector.addActionListener(
- new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- displayAreaWidthInPixels = getIntComboBoxSelection(visualizationPixelWidthSelector);
- canvas.setPreferredSize(getDisplayAreaDimension());
- canvas.setSize(getDisplayAreaDimension());
- theGrid = createNewGrid();
- updateDisplay();
- }
- });
- visualizationPixelHeightSelector = new JComboBox(displayAreaPixelHeightChoices);
- visualizationPixelHeightSelector.setEditable(false);
- visualizationPixelHeightSelector.setBackground(backgroundColor);
- visualizationPixelHeightSelector.setSelectedIndex(defaultDisplayHeightIndex);
- visualizationPixelHeightSelector.setToolTipText("Total height in pixels of display area");
- visualizationPixelHeightSelector.addActionListener(
- new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- displayAreaHeightInPixels = getIntComboBoxSelection(visualizationPixelHeightSelector);
- canvas.setPreferredSize(getDisplayAreaDimension());
- canvas.setSize(getDisplayAreaDimension());
- theGrid = createNewGrid();
- updateDisplay();
- }
- });
- displayBaseAddressSelector = new JComboBox(displayBaseAddressChoices);
- displayBaseAddressSelector.setEditable(false);
- displayBaseAddressSelector.setBackground(backgroundColor);
- displayBaseAddressSelector.setSelectedIndex(defaultBaseAddressIndex);
- displayBaseAddressSelector.setToolTipText("Base address for display area (upper left corner)");
- displayBaseAddressSelector.addActionListener(
- new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- // This may also affect what address range we should be registered as an Observer
- // for. The default (inherited) address range is the MIPS static data segment
- // starting at 0x10010000. To change this requires override of
- // AbstractMarsToolAndApplication.addAsObserver(). The no-argument version of
- // that method is called automatically when "Connect" button is clicked for MarsTool
- // and when "Assemble and Run" button is clicked for Mars application.
- updateBaseAddress();
- // If display base address is changed while connected to MIPS (this can only occur
- // when being used as a MarsTool), we have to delete ourselves as an observer and re-register.
- if (connectButton != null && connectButton.isConnected()) {
+ }
+ addAsObserver(baseAddress, highAddress);
+ }
+
+
+ /**
+ * Method that constructs the main display area. It is organized vertically into two major components: the display
+ * configuration which an be modified using combo boxes, and the visualization display which is updated as the
+ * attached MIPS program executes.
+ *
+ * @return the GUI component containing these two areas
+ */
+ protected JComponent buildMainDisplayArea()
+ {
+ results = new JPanel();
+ results.add(buildOrganizationArea());
+ results.add(buildVisualizationArea());
+ return results;
+ }
+
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Rest of the protected methods. These override do-nothing methods inherited from
+ // the abstract superclass.
+ //////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Update display when connected MIPS program accesses (data) memory.
+ *
+ * @param memory the attached memory
+ * @param accessNotice information provided by memory in MemoryAccessNotice object
+ */
+ protected void processMIPSUpdate(Observable memory, AccessNotice accessNotice)
+ {
+ if (accessNotice.getAccessType() == AccessNotice.WRITE)
+ {
+ updateColorForAddress((MemoryAccessNotice) accessNotice);
+ }
+ }
+
+
+ /**
+ * Initialize all JComboBox choice structures not already initialized at declaration. Overrides inherited method
+ * that does nothing.
+ */
+ protected void initializePreGUI()
+ {
+ initializeDisplayBaseChoices();
+ // NOTE: Can't call "createNewGrid()" here because it uses settings from
+ // several combo boxes that have not been created yet. But a default grid
+ // needs to be allocated for initial canvas display.
+ theGrid = new Grid(displayAreaHeightInPixels / unitPixelHeight,
+ displayAreaWidthInPixels / unitPixelWidth);
+ }
+
+
+ /**
+ * The only post-GUI initialization is to create the initial Grid object based on the default settings of the
+ * various combo boxes. Overrides inherited method that does nothing.
+ */
+
+ protected void initializePostGUI()
+ {
+ theGrid = createNewGrid();
+ updateBaseAddress();
+ }
+
+
+ /**
+ * Method to reset counters and display when the Reset button selected. Overrides inherited method that does
+ * nothing.
+ */
+ protected void reset()
+ {
+ resetCounts();
+ updateDisplay();
+ }
+
+ /**
+ * Updates display immediately after each update (AccessNotice) is processed, after display configuration changes as
+ * needed, and after each execution step when Mars is running in timed mode. Overrides inherited method that does
+ * nothing.
+ */
+ protected void updateDisplay()
+ {
+ canvas.repaint();
+ }
+
+
+ /**
+ * Overrides default method, to provide a Help button for this tool/app.
+ */
+ protected JComponent getHelpComponent()
+ {
+ final String helpContent =
+ "Use this program to simulate a basic bitmap display where\n" +
+ "each memory word in a specified address space corresponds to\n" +
+ "one display pixel in row-major order starting at the upper left\n" +
+ "corner of the display. This tool may be run either from the\n" +
+ "MARS Tools menu or as a stand-alone application.\n" +
+ "\n" +
+ "You can easily learn to use this small program by playing with\n" +
+ "it! Each rectangular unit on the display represents one memory\n" +
+ "word in a contiguous address space starting with the specified\n" +
+ "base address. The value stored in that word will be interpreted\n" +
+ "as a 24-bit RGB color value with the red component in bits 16-23,\n" +
+ "the green component in bits 8-15, and the blue component in bits 0-7.\n" +
+ "Each time a memory word within the display address space is written\n" +
+ "by the MIPS program, its position in the display will be rendered\n" +
+ "in the color that its value represents.\n" +
+ "\n" +
+ "Version 1.0 is very basic and was constructed from the Memory\n" +
+ "Reference Visualization tool's code. Feel free to improve it and\n" +
+ "send me your code for consideration in the next MARS release.\n" +
+ "\n" +
+ "Contact Pete Sanderson at psanderson@otterbein.edu with\n" +
+ "questions or comments.\n";
+ JButton help = new JButton("Help");
+ help.addActionListener(
+ new ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ JOptionPane.showMessageDialog(theWindow, helpContent);
+ }
+ });
+ return help;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Private methods defined to support the above.
+ //////////////////////////////////////////////////////////////////////////////////////
+
+ // UI components and layout for left half of GUI, where settings are specified.
+ private JComponent buildOrganizationArea()
+ {
+ JPanel organization = new JPanel(new GridLayout(8, 1));
+
+ visualizationUnitPixelWidthSelector = new JComboBox(visualizationUnitPixelWidthChoices);
+ visualizationUnitPixelWidthSelector.setEditable(false);
+ visualizationUnitPixelWidthSelector.setBackground(backgroundColor);
+ visualizationUnitPixelWidthSelector.setSelectedIndex(defaultVisualizationUnitPixelWidthIndex);
+ visualizationUnitPixelWidthSelector.setToolTipText("Width in pixels of rectangle representing memory word");
+ visualizationUnitPixelWidthSelector.addActionListener(
+ new ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ unitPixelWidth = getIntComboBoxSelection(visualizationUnitPixelWidthSelector);
+ theGrid = createNewGrid();
+ updateDisplay();
+ }
+ });
+ visualizationUnitPixelHeightSelector = new JComboBox(visualizationUnitPixelHeightChoices);
+ visualizationUnitPixelHeightSelector.setEditable(false);
+ visualizationUnitPixelHeightSelector.setBackground(backgroundColor);
+ visualizationUnitPixelHeightSelector.setSelectedIndex(defaultVisualizationUnitPixelHeightIndex);
+ visualizationUnitPixelHeightSelector.setToolTipText("Height in pixels of rectangle representing memory word");
+ visualizationUnitPixelHeightSelector.addActionListener(
+ new ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ unitPixelHeight = getIntComboBoxSelection(visualizationUnitPixelHeightSelector);
+ theGrid = createNewGrid();
+ updateDisplay();
+ }
+ });
+ visualizationPixelWidthSelector = new JComboBox(displayAreaPixelWidthChoices);
+ visualizationPixelWidthSelector.setEditable(false);
+ visualizationPixelWidthSelector.setBackground(backgroundColor);
+ visualizationPixelWidthSelector.setSelectedIndex(defaultDisplayWidthIndex);
+ visualizationPixelWidthSelector.setToolTipText("Total width in pixels of display area");
+ visualizationPixelWidthSelector.addActionListener(
+ new ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ displayAreaWidthInPixels = getIntComboBoxSelection(visualizationPixelWidthSelector);
+ canvas.setPreferredSize(getDisplayAreaDimension());
+ canvas.setSize(getDisplayAreaDimension());
+ theGrid = createNewGrid();
+ updateDisplay();
+ }
+ });
+ visualizationPixelHeightSelector = new JComboBox(displayAreaPixelHeightChoices);
+ visualizationPixelHeightSelector.setEditable(false);
+ visualizationPixelHeightSelector.setBackground(backgroundColor);
+ visualizationPixelHeightSelector.setSelectedIndex(defaultDisplayHeightIndex);
+ visualizationPixelHeightSelector.setToolTipText("Total height in pixels of display area");
+ visualizationPixelHeightSelector.addActionListener(
+ new ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ displayAreaHeightInPixels = getIntComboBoxSelection(visualizationPixelHeightSelector);
+ canvas.setPreferredSize(getDisplayAreaDimension());
+ canvas.setSize(getDisplayAreaDimension());
+ theGrid = createNewGrid();
+ updateDisplay();
+ }
+ });
+ displayBaseAddressSelector = new JComboBox(displayBaseAddressChoices);
+ displayBaseAddressSelector.setEditable(false);
+ displayBaseAddressSelector.setBackground(backgroundColor);
+ displayBaseAddressSelector.setSelectedIndex(defaultBaseAddressIndex);
+ displayBaseAddressSelector.setToolTipText("Base address for display area (upper left corner)");
+ displayBaseAddressSelector.addActionListener(
+ new ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ // This may also affect what address range we should be registered as an Observer
+ // for. The default (inherited) address range is the MIPS static data segment
+ // starting at 0x10010000. To change this requires override of
+ // AbstractMarsToolAndApplication.addAsObserver(). The no-argument version of
+ // that method is called automatically when "Connect" button is clicked for MarsTool
+ // and when "Assemble and Run" button is clicked for Mars application.
+ updateBaseAddress();
+ // If display base address is changed while connected to MIPS (this can only occur
+ // when being used as a MarsTool), we have to delete ourselves as an observer and re-register.
+ if (connectButton != null && connectButton.isConnected())
+ {
deleteAsObserver();
addAsObserver();
- }
- theGrid = createNewGrid();
- updateDisplay();
- }
- });
-
- // ALL COMPONENTS FOR "ORGANIZATION" SECTION
-
- JPanel unitWidthInPixelsRow = getPanelWithBorderLayout();
- unitWidthInPixelsRow.setBorder(emptyBorder);
- unitWidthInPixelsRow.add(new JLabel("Unit Width in Pixels "),BorderLayout.WEST);
- unitWidthInPixelsRow.add(visualizationUnitPixelWidthSelector, BorderLayout.EAST);
-
- JPanel unitHeightInPixelsRow = getPanelWithBorderLayout();
- unitHeightInPixelsRow.setBorder(emptyBorder);
- unitHeightInPixelsRow.add(new JLabel("Unit Height in Pixels "),BorderLayout.WEST);
- unitHeightInPixelsRow.add(visualizationUnitPixelHeightSelector,BorderLayout.EAST);
-
- JPanel widthInPixelsRow = getPanelWithBorderLayout();
- widthInPixelsRow.setBorder(emptyBorder);
- widthInPixelsRow.add(new JLabel("Display Width in Pixels "),BorderLayout.WEST);
- widthInPixelsRow.add(visualizationPixelWidthSelector, BorderLayout.EAST);
-
- JPanel heightInPixelsRow = getPanelWithBorderLayout();
- heightInPixelsRow.setBorder(emptyBorder);
- heightInPixelsRow.add(new JLabel("Display Height in Pixels "),BorderLayout.WEST);
- heightInPixelsRow.add(visualizationPixelHeightSelector,BorderLayout.EAST);
-
- JPanel baseAddressRow = getPanelWithBorderLayout();
- baseAddressRow.setBorder(emptyBorder);
- baseAddressRow.add(new JLabel("Base address for display "),BorderLayout.WEST);
- baseAddressRow.add(displayBaseAddressSelector,BorderLayout.EAST);
-
-
- // Lay 'em out in the grid...
- organization.add(unitWidthInPixelsRow);
- organization.add(unitHeightInPixelsRow);
- organization.add(widthInPixelsRow);
- organization.add(heightInPixelsRow);
- organization.add(baseAddressRow);
- return organization;
- }
-
- // UI components and layout for right half of GUI, the visualization display area.
- private JComponent buildVisualizationArea() {
- canvas = new GraphicsPanel();
- canvas.setPreferredSize(getDisplayAreaDimension());
- canvas.setToolTipText("Bitmap display area");
- return canvas;
- }
-
- // For greatest flexibility, initialize the display base choices directly from
- // the constants defined in the Memory class. This method called prior to
- // building the GUI. Here are current values from Memory.java:
- //dataSegmentBaseAddress=0x10000000, globalPointer=0x10008000
- //dataBaseAddress=0x10010000, heapBaseAddress=0x10040000, memoryMapBaseAddress=0xffff0000
- private void initializeDisplayBaseChoices() {
- int[] displayBaseAddressArray = {Memory.dataSegmentBaseAddress, Memory.globalPointer, Memory.dataBaseAddress,
- Memory.heapBaseAddress, Memory.memoryMapBaseAddress };
- // Must agree with above in number and order...
- String[] descriptions = { " (global data)", " ($gp)", " (static data)", " (heap)", " (memory map)" };
- displayBaseAddresses = displayBaseAddressArray;
- displayBaseAddressChoices = new String[displayBaseAddressArray.length];
- for (int i=0; i 10 characters long, slice off the first
10 and apply Integer.parseInt() to it to get custom base address.
*/
- }
-
- // Returns Dimension object with current width and height of display area as determined
- // by current settings of respective combo boxes.
- private Dimension getDisplayAreaDimension() {
- return new Dimension(displayAreaWidthInPixels, displayAreaHeightInPixels);
- }
-
- // reset all counters in the Grid.
- private void resetCounts() {
- theGrid.reset();
- }
-
- // Will return int equivalent of specified combo box's current selection.
- // The selection must be a String that parses to an int.
- private int getIntComboBoxSelection(JComboBox comboBox) {
- try {
- return Integer.parseInt((String)comboBox.getSelectedItem());
- }
- catch (NumberFormatException nfe) {
- // Can occur only if initialization list contains badly formatted numbers. This
- // is a developer's error, not a user error, and better be caught before release.
- return 1;
- }
- }
-
- // Use this for consistent results.
- private JPanel getPanelWithBorderLayout() {
- return new JPanel(new BorderLayout(2,2));
- }
-
- // Method to determine grid dimensions based on current control settings.
- // Each grid element corresponds to one visualization unit.
- private Grid createNewGrid() {
- int rows = displayAreaHeightInPixels/unitPixelHeight;
- int columns = displayAreaWidthInPixels/unitPixelWidth;
- return new Grid(rows,columns);
- }
-
- // Given memory address, update color for the corresponding grid element.
- private void updateColorForAddress(MemoryAccessNotice notice) {
- int address = notice.getAddress();
- int value = notice.getValue();
- int offset = (address - baseAddress)/Memory.WORD_LENGTH_BYTES;
- try {
+ }
+
+ // Returns Dimension object with current width and height of display area as determined
+ // by current settings of respective combo boxes.
+ private Dimension getDisplayAreaDimension()
+ {
+ return new Dimension(displayAreaWidthInPixels, displayAreaHeightInPixels);
+ }
+
+ // reset all counters in the Grid.
+ private void resetCounts()
+ {
+ theGrid.reset();
+ }
+
+ // Will return int equivalent of specified combo box's current selection.
+ // The selection must be a String that parses to an int.
+ private int getIntComboBoxSelection(JComboBox comboBox)
+ {
+ try
+ {
+ return Integer.parseInt((String) comboBox.getSelectedItem());
+ }
+ catch (NumberFormatException nfe)
+ {
+ // Can occur only if initialization list contains badly formatted numbers. This
+ // is a developer's error, not a user error, and better be caught before release.
+ return 1;
+ }
+ }
+
+ // Use this for consistent results.
+ private JPanel getPanelWithBorderLayout()
+ {
+ return new JPanel(new BorderLayout(2, 2));
+ }
+
+ // Method to determine grid dimensions based on current control settings.
+ // Each grid element corresponds to one visualization unit.
+ private Grid createNewGrid()
+ {
+ int rows = displayAreaHeightInPixels / unitPixelHeight;
+ int columns = displayAreaWidthInPixels / unitPixelWidth;
+ return new Grid(rows, columns);
+ }
+
+ // Given memory address, update color for the corresponding grid element.
+ private void updateColorForAddress(MemoryAccessNotice notice)
+ {
+ int address = notice.getAddress();
+ int value = notice.getValue();
+ int offset = (address - baseAddress) / Memory.WORD_LENGTH_BYTES;
+ try
+ {
theGrid.setElement(offset / theGrid.getColumns(), offset % theGrid.getColumns(), value);
- }
- catch (IndexOutOfBoundsException e) {
- // If address is out of range for display, do nothing.
- }
- }
-
-
- //////////////////////////////////////////////////////////////////////////////////////
- // Specialized inner classes for modeling and animation.
- //////////////////////////////////////////////////////////////////////////////////////
-
-
- /////////////////////////////////////////////////////////////////////////////
- // Class that represents the panel for visualizing and animating memory reference
- // patterns.
- private class GraphicsPanel extends JPanel {
-
- // override default paint method to assure display updated correctly every time
- // the panel is repainted.
- public void paint(Graphics g) {
- paintGrid(g, theGrid);
- }
-
- // Paint the color codes.
- private void paintGrid(Graphics g, Grid grid) {
+ }
+ catch (IndexOutOfBoundsException e)
+ {
+ // If address is out of range for display, do nothing.
+ }
+ }
+
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Specialized inner classes for modeling and animation.
+ //////////////////////////////////////////////////////////////////////////////////////
+
+
+ /////////////////////////////////////////////////////////////////////////////
+ // Class that represents the panel for visualizing and animating memory reference
+ // patterns.
+ private class GraphicsPanel extends JPanel
+ {
+
+ // override default paint method to assure display updated correctly every time
+ // the panel is repainted.
+ public void paint(Graphics g)
+ {
+ paintGrid(g, theGrid);
+ }
+
+ // Paint the color codes.
+ private void paintGrid(Graphics g, Grid grid)
+ {
int upperLeftX = 0, upperLeftY = 0;
- for (int i=0; i=0 && row<=rows && column>=0 && column<=columns) ? grid[row][column] : null;
- }
-
- // Returns value in given grid element without doing any row/column index checking.
- // Is faster than getElement but will throw array index out of bounds exception if
- // parameter values are outside the bounds of the grid.
- private Color getElementFast(int row, int column) {
- return grid[row][column];
- }
-
- // Set the grid element.
- private void setElement(int row, int column, int color) {
+ }
+
+ // Returns value in given grid element; null if row or column is out of range.
+ private Color getElement(int row, int column)
+ {
+ return (row >= 0 && row <= rows && column >= 0 && column <= columns) ? grid[row][column] : null;
+ }
+
+ // Returns value in given grid element without doing any row/column index checking.
+ // Is faster than getElement but will throw array index out of bounds exception if
+ // parameter values are outside the bounds of the grid.
+ private Color getElementFast(int row, int column)
+ {
+ return grid[row][column];
+ }
+
+ // Set the grid element.
+ private void setElement(int row, int column, int color)
+ {
grid[row][column] = new Color(color);
- }
-
- // Set the grid element.
- private void setElement(int row, int column, Color color) {
+ }
+
+ // Set the grid element.
+ private void setElement(int row, int column, Color color)
+ {
grid[row][column] = color;
- }
-
- // Just set all grid elements to black.
- private void reset() {
- for (int i=0; iVersion 1.2 fixes a bug in the hit/miss animator under full or N-way set associative. It was
- * animating the block of initial access (first block of set). Now it animates the block
- * of final access (where address found or stored). Also added log display to GUI (previously System.out).
- */
- public class CacheSimulator extends AbstractMarsToolAndApplication {
- private static boolean debug = false; // controls display of debugging info
- private static String version = "Version 1.2";
- private static String heading = "Simulate and illustrate data cache performance";
- // Major GUI components
- private JComboBox cacheBlockSizeSelector, cacheBlockCountSelector,
- cachePlacementSelector, cacheReplacementSelector,
- cacheSetSizeSelector;
- private JTextField memoryAccessCountDisplay, cacheHitCountDisplay, cacheMissCountDisplay,
- replacementPolicyDisplay,cachableAddressesDisplay,
- cacheSizeDisplay;
- private JProgressBar cacheHitRateDisplay;
- private Animation animations;
-
- private JPanel logPanel;
- private JScrollPane logScroll;
- private JTextArea logText;
- private JCheckBox logShow;
-
- // Some GUI settings
- private EmptyBorder emptyBorder = new EmptyBorder(4,4,4,4);
- private Font countFonts = new Font("Times", Font.BOLD,12);
- private Color backgroundColor = Color.WHITE;
-
- // Values for Combo Boxes
- private int[] cacheBlockSizeChoicesInt, cacheBlockCountChoicesInt;
- private String[] cacheBlockSizeChoices = {"1","2","4","8","16","32","64","128","256","512","1024","2048"};
- private String[] cacheBlockCountChoices = {"1","2","4","8","16","32","64","128","256","512","1024","2048"};
- private String[] placementPolicyChoices = {"Direct Mapping", "Fully Associative", "N-way Set Associative" };
- private final int DIRECT = 0, FULL = 1, SET = 2; // NOTE: these have to match placementPolicyChoices order!
- private String[] replacementPolicyChoices = {"LRU","Random"};
- private final int LRU = 0, RANDOM = 1; // NOTE: these have to match replacementPolicyChoices order!
- private String[] cacheSetSizeChoices; // will change dynamically based on the other selections
- private int defaultCacheBlockSizeIndex = 2;
- private int defaultCacheBlockCountIndex = 3;
- private int defaultPlacementPolicyIndex = DIRECT;
- private int defaultReplacementPolicyIndex = LRU;
- private int defaultCacheSetSizeIndex = 0;
-
- // Cache-related data structures
- private AbstractCache theCache;
- private int memoryAccessCount, cacheHitCount, cacheMissCount;
- private double cacheHitRate;
-
- // RNG used for random replacement policy. For testing, set seed for reproducible stream
- private Random randu = new Random(0);
-
- /**
- * Simple constructor, likely used to run a stand-alone cache simulator.
- * @param title String containing title for title bar
- * @param heading String containing text for heading shown in upper part of window.
- */
- public CacheSimulator(String title, String heading) {
- super(title,heading);
- }
-
- /**
- * Simple constructor, likely used by the MARS Tools menu mechanism
- */
- public CacheSimulator() {
- super ("Data Cache Simulation Tool, "+version, heading);
- }
-
-
- /**
- * Main provided for pure stand-alone use. Recommended stand-alone use is to write a
- * driver program that instantiates a CacheSimulator object then invokes its go() method.
- * "stand-alone" means it is not invoked from the MARS Tools menu. "Pure" means there
- * is no driver program to invoke the Cache Simulator.
- */
- public static void main(String[] args) {
- new CacheSimulator("Data Cache Simulator stand-alone, "+version,heading).go();
- }
-
-
- /**
- * Required MarsTool method to return Tool name.
- * @return Tool name. MARS will display this in menu item.
- */
- public String getName() {
- return "Data Cache Simulator";
- }
-
-
- /**
- * Method that constructs the main cache simulator display area. It is organized vertically
- * into three major components: the cache configuration which an be modified
- * using combo boxes, the cache performance which is updated as the
- * attached MIPS program executes, and the runtime log which is optionally used
- * to display log of each cache access.
- * @return the GUI component containing these three areas
- */
- protected JComponent buildMainDisplayArea() {
- // OVERALL STRUCTURE OF MAIN UI (CENTER)
- Box results = Box.createVerticalBox();
- results.add(buildOrganizationArea());
- results.add(buildPerformanceArea());
- results.add(buildLogArea());
- return results;
- }
-
- ////////////////////////////////////////////////////////////////////////////
- private JComponent buildLogArea() {
- logPanel = new JPanel();
- TitledBorder ltb =new TitledBorder("Runtime Log");
- ltb.setTitleJustification(TitledBorder.CENTER);
- logPanel.setBorder(ltb);
- logShow = new JCheckBox("Enabled",debug);
- logShow.addItemListener(
- new ItemListener() {
- public void itemStateChanged(ItemEvent e) {
- debug = e.getStateChange() == ItemEvent.SELECTED;
- resetLogDisplay();
- logText.setEnabled(debug);
- logText.setBackground( debug ? Color.WHITE : logPanel.getBackground() );
- }
- });
- logPanel.add(logShow);
- logText = new JTextArea(5,70);
- logText.setEnabled(debug);
- logText.setBackground( debug ? Color.WHITE : logPanel.getBackground() );
- logText.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 12));
- logText.setToolTipText("Displays cache activity log if enabled");
- logScroll = new JScrollPane(logText,JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
- logPanel.add(logScroll);
- return logPanel;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////
- private JComponent buildOrganizationArea() {
- JPanel organization = new JPanel(new GridLayout(3,2));
- TitledBorder otb =new TitledBorder("Cache Organization");
- otb.setTitleJustification(TitledBorder.CENTER);
- organization.setBorder(otb);
- cachePlacementSelector = new JComboBox(placementPolicyChoices);
- cachePlacementSelector.setEditable(false);
- cachePlacementSelector.setBackground(backgroundColor);
- cachePlacementSelector.setSelectedIndex(defaultPlacementPolicyIndex);
- cachePlacementSelector.addActionListener(
- new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- updateCacheSetSizeSelector();
- reset();
- }
- });
-
- cacheReplacementSelector = new JComboBox(replacementPolicyChoices);
- cacheReplacementSelector.setEditable(false);
- cacheReplacementSelector.setBackground(backgroundColor);
- cacheReplacementSelector.setSelectedIndex(defaultReplacementPolicyIndex);
-
- cacheBlockSizeSelector = new JComboBox(cacheBlockSizeChoices);
- cacheBlockSizeSelector.setEditable(false);
- cacheBlockSizeSelector.setBackground(backgroundColor);
- cacheBlockSizeSelector.setSelectedIndex(defaultCacheBlockSizeIndex);
- cacheBlockSizeSelector.addActionListener(
- new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- updateCacheSizeDisplay();
- reset();
- }
- });
- cacheBlockCountSelector = new JComboBox(cacheBlockCountChoices);
- cacheBlockCountSelector.setEditable(false);
- cacheBlockCountSelector.setBackground(backgroundColor);
- cacheBlockCountSelector.setSelectedIndex(defaultCacheBlockCountIndex);
- cacheBlockCountSelector.addActionListener(
- new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- updateCacheSetSizeSelector();
- theCache = createNewCache();
- resetCounts();
- updateDisplay();
- updateCacheSizeDisplay();
- animations.fillAnimationBoxWithCacheBlocks();
- }
- });
-
- cacheSetSizeSelector = new JComboBox(cacheSetSizeChoices);
- cacheSetSizeSelector.setEditable(false);
- cacheSetSizeSelector.setBackground(backgroundColor);
- cacheSetSizeSelector.setSelectedIndex(defaultCacheSetSizeIndex);
- cacheSetSizeSelector.addActionListener(
- new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- reset();
- }
- });
-
- // ALL COMPONENTS FOR "CACHE ORGANIZATION" SECTION
- JPanel placementPolicyRow = getPanelWithBorderLayout();
- placementPolicyRow.setBorder(emptyBorder);
- placementPolicyRow.add(new JLabel("Placement Policy "),BorderLayout.WEST);
- placementPolicyRow.add(cachePlacementSelector,BorderLayout.EAST);
-
- JPanel replacementPolicyRow = getPanelWithBorderLayout();
- replacementPolicyRow.setBorder(emptyBorder);
- replacementPolicyRow.add(new JLabel("Block Replacement Policy "),BorderLayout.WEST);
+
+/**
+ * A data cache simulator. It can be run either as a stand-alone Java application having access to the mars package, or
+ * through MARS as an item in its Tools menu. It makes maximum use of methods inherited from its abstract superclass
+ * AbstractMarsToolOrApp. Pete Sanderson, v 1.0: 16-18 October 2006, v 1.1: 7 November 2006. v 1.2: 23 December 2010.
+ * Version 1.2 fixes a bug in the hit/miss animator under full or N-way set associative. It was
+ * animating the block of initial access (first block of set). Now it animates the block of final access (where address
+ * found or stored). Also added log display to GUI (previously System.out).
+ */
+public class CacheSimulator extends AbstractMarsToolAndApplication
+{
+ private static boolean debug = false; // controls display of debugging info
+
+ private static final String version = "Version 1.2";
+
+ private static final String heading = "Simulate and illustrate data cache performance";
+
+ private final int DIRECT = 0, FULL = 1, SET = 2; // NOTE: these have to match placementPolicyChoices order!
+
+ private final int LRU = 0, RANDOM = 1; // NOTE: these have to match replacementPolicyChoices order!
+
+ // Major GUI components
+ private JComboBox cacheBlockSizeSelector, cacheBlockCountSelector,
+ cachePlacementSelector, cacheReplacementSelector,
+ cacheSetSizeSelector;
+
+ private JTextField memoryAccessCountDisplay, cacheHitCountDisplay, cacheMissCountDisplay,
+ replacementPolicyDisplay, cachableAddressesDisplay,
+ cacheSizeDisplay;
+
+ private JProgressBar cacheHitRateDisplay;
+
+ private Animation animations;
+
+ private JPanel logPanel;
+
+ private JScrollPane logScroll;
+
+ private JTextArea logText;
+
+ private JCheckBox logShow;
+
+ // Some GUI settings
+ private final EmptyBorder emptyBorder = new EmptyBorder(4, 4, 4, 4);
+
+ private final Font countFonts = new Font("Times", Font.BOLD, 12);
+
+ private final Color backgroundColor = Color.WHITE;
+
+ // Values for Combo Boxes
+ private int[] cacheBlockSizeChoicesInt, cacheBlockCountChoicesInt;
+
+ private final String[] cacheBlockSizeChoices = {"1", "2", "4", "8", "16", "32", "64", "128", "256", "512", "1024", "2048"};
+
+ private final String[] cacheBlockCountChoices = {"1", "2", "4", "8", "16", "32", "64", "128", "256", "512", "1024", "2048"};
+
+ private final String[] placementPolicyChoices = {"Direct Mapping", "Fully Associative", "N-way Set Associative"};
+
+ private final String[] replacementPolicyChoices = {"LRU", "Random"};
+
+ private String[] cacheSetSizeChoices; // will change dynamically based on the other selections
+
+ private final int defaultCacheBlockSizeIndex = 2;
+
+ private final int defaultCacheBlockCountIndex = 3;
+
+ private final int defaultPlacementPolicyIndex = DIRECT;
+
+ private final int defaultReplacementPolicyIndex = LRU;
+
+ private final int defaultCacheSetSizeIndex = 0;
+
+ // Cache-related data structures
+ private AbstractCache theCache;
+
+ private int memoryAccessCount, cacheHitCount, cacheMissCount;
+
+ private double cacheHitRate;
+
+ // RNG used for random replacement policy. For testing, set seed for reproducible stream
+ private final Random randu = new Random(0);
+
+ /**
+ * Simple constructor, likely used to run a stand-alone cache simulator.
+ *
+ * @param title String containing title for title bar
+ * @param heading String containing text for heading shown in upper part of window.
+ */
+ public CacheSimulator(String title, String heading)
+ {
+ super(title, heading);
+ }
+
+ /**
+ * Simple constructor, likely used by the MARS Tools menu mechanism
+ */
+ public CacheSimulator()
+ {
+ super("Data Cache Simulation Tool, " + version, heading);
+ }
+
+
+ /**
+ * Main provided for pure stand-alone use. Recommended stand-alone use is to write a driver program that
+ * instantiates a CacheSimulator object then invokes its go() method. "stand-alone" means it is not invoked from the
+ * MARS Tools menu. "Pure" means there is no driver program to invoke the Cache Simulator.
+ */
+ public static void main(String[] args)
+ {
+ new CacheSimulator("Data Cache Simulator stand-alone, " + version, heading).go();
+ }
+
+
+ /**
+ * Required MarsTool method to return Tool name.
+ *
+ * @return Tool name. MARS will display this in menu item.
+ */
+ public String getName()
+ {
+ return "Data Cache Simulator";
+ }
+
+
+ /**
+ * Method that constructs the main cache simulator display area. It is organized vertically into three major
+ * components: the cache configuration which an be modified using combo boxes, the cache performance which is
+ * updated as the attached MIPS program executes, and the runtime log which is optionally used to display log of
+ * each cache access.
+ *
+ * @return the GUI component containing these three areas
+ */
+ protected JComponent buildMainDisplayArea()
+ {
+ // OVERALL STRUCTURE OF MAIN UI (CENTER)
+ Box results = Box.createVerticalBox();
+ results.add(buildOrganizationArea());
+ results.add(buildPerformanceArea());
+ results.add(buildLogArea());
+ return results;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ private JComponent buildLogArea()
+ {
+ logPanel = new JPanel();
+ TitledBorder ltb = new TitledBorder("Runtime Log");
+ ltb.setTitleJustification(TitledBorder.CENTER);
+ logPanel.setBorder(ltb);
+ logShow = new JCheckBox("Enabled", debug);
+ logShow.addItemListener(
+ new ItemListener()
+ {
+ public void itemStateChanged(ItemEvent e)
+ {
+ debug = e.getStateChange() == ItemEvent.SELECTED;
+ resetLogDisplay();
+ logText.setEnabled(debug);
+ logText.setBackground(debug ? Color.WHITE : logPanel.getBackground());
+ }
+ });
+ logPanel.add(logShow);
+ logText = new JTextArea(5, 70);
+ logText.setEnabled(debug);
+ logText.setBackground(debug ? Color.WHITE : logPanel.getBackground());
+ logText.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 12));
+ logText.setToolTipText("Displays cache activity log if enabled");
+ logScroll = new JScrollPane(logText, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
+ logPanel.add(logScroll);
+ return logPanel;
+ }
+
+
+ ////////////////////////////////////////////////////////////////////////////
+ private JComponent buildOrganizationArea()
+ {
+ JPanel organization = new JPanel(new GridLayout(3, 2));
+ TitledBorder otb = new TitledBorder("Cache Organization");
+ otb.setTitleJustification(TitledBorder.CENTER);
+ organization.setBorder(otb);
+ cachePlacementSelector = new JComboBox(placementPolicyChoices);
+ cachePlacementSelector.setEditable(false);
+ cachePlacementSelector.setBackground(backgroundColor);
+ cachePlacementSelector.setSelectedIndex(defaultPlacementPolicyIndex);
+ cachePlacementSelector.addActionListener(
+ new ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ updateCacheSetSizeSelector();
+ reset();
+ }
+ });
+
+ cacheReplacementSelector = new JComboBox(replacementPolicyChoices);
+ cacheReplacementSelector.setEditable(false);
+ cacheReplacementSelector.setBackground(backgroundColor);
+ cacheReplacementSelector.setSelectedIndex(defaultReplacementPolicyIndex);
+
+ cacheBlockSizeSelector = new JComboBox(cacheBlockSizeChoices);
+ cacheBlockSizeSelector.setEditable(false);
+ cacheBlockSizeSelector.setBackground(backgroundColor);
+ cacheBlockSizeSelector.setSelectedIndex(defaultCacheBlockSizeIndex);
+ cacheBlockSizeSelector.addActionListener(
+ new ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ updateCacheSizeDisplay();
+ reset();
+ }
+ });
+ cacheBlockCountSelector = new JComboBox(cacheBlockCountChoices);
+ cacheBlockCountSelector.setEditable(false);
+ cacheBlockCountSelector.setBackground(backgroundColor);
+ cacheBlockCountSelector.setSelectedIndex(defaultCacheBlockCountIndex);
+ cacheBlockCountSelector.addActionListener(
+ new ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ updateCacheSetSizeSelector();
+ theCache = createNewCache();
+ resetCounts();
+ updateDisplay();
+ updateCacheSizeDisplay();
+ animations.fillAnimationBoxWithCacheBlocks();
+ }
+ });
+
+ cacheSetSizeSelector = new JComboBox(cacheSetSizeChoices);
+ cacheSetSizeSelector.setEditable(false);
+ cacheSetSizeSelector.setBackground(backgroundColor);
+ cacheSetSizeSelector.setSelectedIndex(defaultCacheSetSizeIndex);
+ cacheSetSizeSelector.addActionListener(
+ new ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ reset();
+ }
+ });
+
+ // ALL COMPONENTS FOR "CACHE ORGANIZATION" SECTION
+ JPanel placementPolicyRow = getPanelWithBorderLayout();
+ placementPolicyRow.setBorder(emptyBorder);
+ placementPolicyRow.add(new JLabel("Placement Policy "), BorderLayout.WEST);
+ placementPolicyRow.add(cachePlacementSelector, BorderLayout.EAST);
+
+ JPanel replacementPolicyRow = getPanelWithBorderLayout();
+ replacementPolicyRow.setBorder(emptyBorder);
+ replacementPolicyRow.add(new JLabel("Block Replacement Policy "), BorderLayout.WEST);
/* replacementPolicyDisplay = new JTextField("N/A",6);
replacementPolicyDisplay.setEditable(false);
replacementPolicyDisplay.setBackground(backgroundColor);
replacementPolicyDisplay.setHorizontalAlignment(JTextField.RIGHT); */
- replacementPolicyRow.add(cacheReplacementSelector, BorderLayout.EAST);
-
- JPanel cacheSetSizeRow = getPanelWithBorderLayout();
- cacheSetSizeRow.setBorder(emptyBorder);
- cacheSetSizeRow.add(new JLabel("Set size (blocks) "),BorderLayout.WEST);
- cacheSetSizeRow.add(cacheSetSizeSelector,BorderLayout.EAST);
-
- // Cachable address range "selection" removed for now...
+ replacementPolicyRow.add(cacheReplacementSelector, BorderLayout.EAST);
+
+ JPanel cacheSetSizeRow = getPanelWithBorderLayout();
+ cacheSetSizeRow.setBorder(emptyBorder);
+ cacheSetSizeRow.add(new JLabel("Set size (blocks) "), BorderLayout.WEST);
+ cacheSetSizeRow.add(cacheSetSizeSelector, BorderLayout.EAST);
+
+ // Cachable address range "selection" removed for now...
/*
JPanel cachableAddressesRow = getPanelWithBorderLayout();
cachableAddressesRow.setBorder(emptyBorder);
@@ -266,639 +317,746 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
cachableAddressesDisplay.setHorizontalAlignment(JTextField.RIGHT);
cachableAddressesRow.add(cachableAddressesDisplay, BorderLayout.EAST);
*/
- JPanel cacheNumberBlocksRow = getPanelWithBorderLayout();
- cacheNumberBlocksRow.setBorder(emptyBorder);
- cacheNumberBlocksRow.add(new JLabel("Number of blocks "), BorderLayout.WEST);
- cacheNumberBlocksRow.add(cacheBlockCountSelector, BorderLayout.EAST);
-
- JPanel cacheBlockSizeRow = getPanelWithBorderLayout();
- cacheBlockSizeRow.setBorder(emptyBorder);
- cacheBlockSizeRow.add(new JLabel("Cache block size (words) "), BorderLayout.WEST);
- cacheBlockSizeRow.add(cacheBlockSizeSelector, BorderLayout.EAST);
-
- JPanel cacheTotalSizeRow = getPanelWithBorderLayout();
- cacheTotalSizeRow.setBorder(emptyBorder);
- cacheTotalSizeRow.add(new JLabel("Cache size (bytes) "), BorderLayout.WEST);
- cacheSizeDisplay = new JTextField(8);
- cacheSizeDisplay.setHorizontalAlignment(JTextField.RIGHT);
- cacheSizeDisplay.setEditable(false);
- cacheSizeDisplay.setBackground(backgroundColor);
- cacheSizeDisplay.setFont(countFonts);
- cacheTotalSizeRow.add(cacheSizeDisplay, BorderLayout.EAST);
- updateCacheSizeDisplay();
-
- // Lay 'em out in the grid...
- organization.add(placementPolicyRow);
- organization.add(cacheNumberBlocksRow);
- organization.add(replacementPolicyRow);
- organization.add(cacheBlockSizeRow);
- //organization.add(cachableAddressesRow);
- organization.add(cacheSetSizeRow);
- organization.add(cacheTotalSizeRow);
- return organization;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////
- private JComponent buildPerformanceArea() {
- JPanel performance = new JPanel(new GridLayout(1,2));
- TitledBorder ptb =new TitledBorder("Cache Performance");
- ptb.setTitleJustification(TitledBorder.CENTER);
- performance.setBorder(ptb);
- JPanel memoryAccessCountRow = getPanelWithBorderLayout();
- memoryAccessCountRow.setBorder(emptyBorder);
- memoryAccessCountRow.add(new JLabel("Memory Access Count "), BorderLayout.WEST);
- memoryAccessCountDisplay = new JTextField(10);
- memoryAccessCountDisplay.setHorizontalAlignment(JTextField.RIGHT);
- memoryAccessCountDisplay.setEditable(false);
- memoryAccessCountDisplay.setBackground(backgroundColor);
- memoryAccessCountDisplay.setFont(countFonts);
- memoryAccessCountRow.add(memoryAccessCountDisplay, BorderLayout.EAST);
-
- JPanel cacheHitCountRow = getPanelWithBorderLayout();
- cacheHitCountRow.setBorder(emptyBorder);
- cacheHitCountRow.add(new JLabel("Cache Hit Count "), BorderLayout.WEST);
- cacheHitCountDisplay = new JTextField(10);
- cacheHitCountDisplay.setHorizontalAlignment(JTextField.RIGHT);
- cacheHitCountDisplay.setEditable(false);
- cacheHitCountDisplay.setBackground(backgroundColor);
- cacheHitCountDisplay.setFont(countFonts);
- cacheHitCountRow.add(cacheHitCountDisplay, BorderLayout.EAST);
-
- JPanel cacheMissCountRow = getPanelWithBorderLayout();
- cacheMissCountRow.setBorder(emptyBorder);
- cacheMissCountRow.add(new JLabel("Cache Miss Count "), BorderLayout.WEST);
- cacheMissCountDisplay = new JTextField(10);
- cacheMissCountDisplay.setHorizontalAlignment(JTextField.RIGHT);
- cacheMissCountDisplay.setEditable(false);
- cacheMissCountDisplay.setBackground(backgroundColor);
- cacheMissCountDisplay.setFont(countFonts);
- cacheMissCountRow.add(cacheMissCountDisplay, BorderLayout.EAST);
-
- JPanel cacheHitRateRow = getPanelWithBorderLayout();
- cacheHitRateRow.setBorder(emptyBorder);
- cacheHitRateRow.add(new JLabel("Cache Hit Rate "), BorderLayout.WEST);
- cacheHitRateDisplay = new JProgressBar(JProgressBar.HORIZONTAL, 0, 100);
- cacheHitRateDisplay.setStringPainted(true);
- cacheHitRateDisplay.setForeground(Color.BLUE);
- cacheHitRateDisplay.setBackground(backgroundColor);
- cacheHitRateDisplay.setFont(countFonts);
- cacheHitRateRow.add(cacheHitRateDisplay, BorderLayout.EAST);
-
- resetCounts();
- updateDisplay();
-
- // Vertically align these 4 measures in a grid, then add to left column of main grid.
- JPanel performanceMeasures = new JPanel(new GridLayout(4,1));
- performanceMeasures.add(memoryAccessCountRow);
- performanceMeasures.add(cacheHitCountRow);
- performanceMeasures.add(cacheMissCountRow);
- performanceMeasures.add(cacheHitRateRow);
- performance.add(performanceMeasures);
-
- // LET'S TRY SOME ANIMATION ON THE RIGHT SIDE...
- animations = new Animation();
- animations.fillAnimationBoxWithCacheBlocks();
- JPanel animationsPanel = new JPanel(new GridLayout(1,2));
- Box animationsLabel = Box.createVerticalBox();
- JPanel tableTitle1 = new JPanel(new FlowLayout(FlowLayout.LEFT));
- JPanel tableTitle2 = new JPanel(new FlowLayout(FlowLayout.LEFT));
- tableTitle1.add(new JLabel("Cache Block Table"));
- tableTitle2.add(new JLabel("(block 0 at top)"));
- animationsLabel.add(tableTitle1);
- animationsLabel.add(tableTitle2);
- Dimension colorKeyBoxSize = new Dimension(8,8);
-
- JPanel emptyKey = new JPanel(new FlowLayout(FlowLayout.LEFT));
- JPanel emptyBox = new JPanel();
- emptyBox.setSize(colorKeyBoxSize);
- emptyBox.setBackground(animations.defaultColor);
- emptyBox.setBorder(BorderFactory.createLineBorder(Color.BLACK));
- emptyKey.add(emptyBox);
- emptyKey.add(new JLabel(" = empty"));
-
- JPanel missBox = new JPanel();
- JPanel missKey = new JPanel(new FlowLayout(FlowLayout.LEFT));
- missBox.setSize(colorKeyBoxSize);
- missBox.setBackground(animations.missColor);
- missBox.setBorder(BorderFactory.createLineBorder(Color.BLACK));
- missKey.add(missBox);
- missKey.add(new JLabel(" = miss"));
-
- JPanel hitKey = new JPanel(new FlowLayout(FlowLayout.LEFT));
- JPanel hitBox = new JPanel();
- hitBox.setSize(colorKeyBoxSize);
- hitBox.setBackground(animations.hitColor);
- hitBox.setBorder(BorderFactory.createLineBorder(Color.BLACK));
- hitKey.add(hitBox);
- hitKey.add(new JLabel(" = hit"));
-
- animationsLabel.add(emptyKey);
- animationsLabel.add(hitKey);
- animationsLabel.add(missKey);
- animationsLabel.add(Box.createVerticalGlue());
- animationsPanel.add(animationsLabel);
- animationsPanel.add(animations.getAnimationBox());
-
- performance.add(animationsPanel);
- return performance;
- }
-
-
-
- //////////////////////////////////////////////////////////////////////////////////////
- // Rest of the protected methods. These override do-nothing methods inherited from
- // the abstract superclass.
- //////////////////////////////////////////////////////////////////////////////////////
-
- /**
- * Apply caching policies and update display when connected MIPS program accesses (data) memory.
- * @param memory the attached memory
- * @param accessNotice information provided by memory in MemoryAccessNotice object
- */
- protected void processMIPSUpdate(Observable memory, AccessNotice accessNotice) {
- MemoryAccessNotice notice = (MemoryAccessNotice) accessNotice;
- memoryAccessCount++;
- CacheAccessResult cacheAccessResult = theCache.isItAHitThenReadOnMiss(notice.getAddress());
- if (cacheAccessResult.isHit()) {
+ JPanel cacheNumberBlocksRow = getPanelWithBorderLayout();
+ cacheNumberBlocksRow.setBorder(emptyBorder);
+ cacheNumberBlocksRow.add(new JLabel("Number of blocks "), BorderLayout.WEST);
+ cacheNumberBlocksRow.add(cacheBlockCountSelector, BorderLayout.EAST);
+
+ JPanel cacheBlockSizeRow = getPanelWithBorderLayout();
+ cacheBlockSizeRow.setBorder(emptyBorder);
+ cacheBlockSizeRow.add(new JLabel("Cache block size (words) "), BorderLayout.WEST);
+ cacheBlockSizeRow.add(cacheBlockSizeSelector, BorderLayout.EAST);
+
+ JPanel cacheTotalSizeRow = getPanelWithBorderLayout();
+ cacheTotalSizeRow.setBorder(emptyBorder);
+ cacheTotalSizeRow.add(new JLabel("Cache size (bytes) "), BorderLayout.WEST);
+ cacheSizeDisplay = new JTextField(8);
+ cacheSizeDisplay.setHorizontalAlignment(JTextField.RIGHT);
+ cacheSizeDisplay.setEditable(false);
+ cacheSizeDisplay.setBackground(backgroundColor);
+ cacheSizeDisplay.setFont(countFonts);
+ cacheTotalSizeRow.add(cacheSizeDisplay, BorderLayout.EAST);
+ updateCacheSizeDisplay();
+
+ // Lay 'em out in the grid...
+ organization.add(placementPolicyRow);
+ organization.add(cacheNumberBlocksRow);
+ organization.add(replacementPolicyRow);
+ organization.add(cacheBlockSizeRow);
+ //organization.add(cachableAddressesRow);
+ organization.add(cacheSetSizeRow);
+ organization.add(cacheTotalSizeRow);
+ return organization;
+ }
+
+
+ ////////////////////////////////////////////////////////////////////////////
+ private JComponent buildPerformanceArea()
+ {
+ JPanel performance = new JPanel(new GridLayout(1, 2));
+ TitledBorder ptb = new TitledBorder("Cache Performance");
+ ptb.setTitleJustification(TitledBorder.CENTER);
+ performance.setBorder(ptb);
+ JPanel memoryAccessCountRow = getPanelWithBorderLayout();
+ memoryAccessCountRow.setBorder(emptyBorder);
+ memoryAccessCountRow.add(new JLabel("Memory Access Count "), BorderLayout.WEST);
+ memoryAccessCountDisplay = new JTextField(10);
+ memoryAccessCountDisplay.setHorizontalAlignment(JTextField.RIGHT);
+ memoryAccessCountDisplay.setEditable(false);
+ memoryAccessCountDisplay.setBackground(backgroundColor);
+ memoryAccessCountDisplay.setFont(countFonts);
+ memoryAccessCountRow.add(memoryAccessCountDisplay, BorderLayout.EAST);
+
+ JPanel cacheHitCountRow = getPanelWithBorderLayout();
+ cacheHitCountRow.setBorder(emptyBorder);
+ cacheHitCountRow.add(new JLabel("Cache Hit Count "), BorderLayout.WEST);
+ cacheHitCountDisplay = new JTextField(10);
+ cacheHitCountDisplay.setHorizontalAlignment(JTextField.RIGHT);
+ cacheHitCountDisplay.setEditable(false);
+ cacheHitCountDisplay.setBackground(backgroundColor);
+ cacheHitCountDisplay.setFont(countFonts);
+ cacheHitCountRow.add(cacheHitCountDisplay, BorderLayout.EAST);
+
+ JPanel cacheMissCountRow = getPanelWithBorderLayout();
+ cacheMissCountRow.setBorder(emptyBorder);
+ cacheMissCountRow.add(new JLabel("Cache Miss Count "), BorderLayout.WEST);
+ cacheMissCountDisplay = new JTextField(10);
+ cacheMissCountDisplay.setHorizontalAlignment(JTextField.RIGHT);
+ cacheMissCountDisplay.setEditable(false);
+ cacheMissCountDisplay.setBackground(backgroundColor);
+ cacheMissCountDisplay.setFont(countFonts);
+ cacheMissCountRow.add(cacheMissCountDisplay, BorderLayout.EAST);
+
+ JPanel cacheHitRateRow = getPanelWithBorderLayout();
+ cacheHitRateRow.setBorder(emptyBorder);
+ cacheHitRateRow.add(new JLabel("Cache Hit Rate "), BorderLayout.WEST);
+ cacheHitRateDisplay = new JProgressBar(JProgressBar.HORIZONTAL, 0, 100);
+ cacheHitRateDisplay.setStringPainted(true);
+ cacheHitRateDisplay.setForeground(Color.BLUE);
+ cacheHitRateDisplay.setBackground(backgroundColor);
+ cacheHitRateDisplay.setFont(countFonts);
+ cacheHitRateRow.add(cacheHitRateDisplay, BorderLayout.EAST);
+
+ resetCounts();
+ updateDisplay();
+
+ // Vertically align these 4 measures in a grid, then add to left column of main grid.
+ JPanel performanceMeasures = new JPanel(new GridLayout(4, 1));
+ performanceMeasures.add(memoryAccessCountRow);
+ performanceMeasures.add(cacheHitCountRow);
+ performanceMeasures.add(cacheMissCountRow);
+ performanceMeasures.add(cacheHitRateRow);
+ performance.add(performanceMeasures);
+
+ // LET'S TRY SOME ANIMATION ON THE RIGHT SIDE...
+ animations = new Animation();
+ animations.fillAnimationBoxWithCacheBlocks();
+ JPanel animationsPanel = new JPanel(new GridLayout(1, 2));
+ Box animationsLabel = Box.createVerticalBox();
+ JPanel tableTitle1 = new JPanel(new FlowLayout(FlowLayout.LEFT));
+ JPanel tableTitle2 = new JPanel(new FlowLayout(FlowLayout.LEFT));
+ tableTitle1.add(new JLabel("Cache Block Table"));
+ tableTitle2.add(new JLabel("(block 0 at top)"));
+ animationsLabel.add(tableTitle1);
+ animationsLabel.add(tableTitle2);
+ Dimension colorKeyBoxSize = new Dimension(8, 8);
+
+ JPanel emptyKey = new JPanel(new FlowLayout(FlowLayout.LEFT));
+ JPanel emptyBox = new JPanel();
+ emptyBox.setSize(colorKeyBoxSize);
+ emptyBox.setBackground(animations.defaultColor);
+ emptyBox.setBorder(BorderFactory.createLineBorder(Color.BLACK));
+ emptyKey.add(emptyBox);
+ emptyKey.add(new JLabel(" = empty"));
+
+ JPanel missBox = new JPanel();
+ JPanel missKey = new JPanel(new FlowLayout(FlowLayout.LEFT));
+ missBox.setSize(colorKeyBoxSize);
+ missBox.setBackground(animations.missColor);
+ missBox.setBorder(BorderFactory.createLineBorder(Color.BLACK));
+ missKey.add(missBox);
+ missKey.add(new JLabel(" = miss"));
+
+ JPanel hitKey = new JPanel(new FlowLayout(FlowLayout.LEFT));
+ JPanel hitBox = new JPanel();
+ hitBox.setSize(colorKeyBoxSize);
+ hitBox.setBackground(animations.hitColor);
+ hitBox.setBorder(BorderFactory.createLineBorder(Color.BLACK));
+ hitKey.add(hitBox);
+ hitKey.add(new JLabel(" = hit"));
+
+ animationsLabel.add(emptyKey);
+ animationsLabel.add(hitKey);
+ animationsLabel.add(missKey);
+ animationsLabel.add(Box.createVerticalGlue());
+ animationsPanel.add(animationsLabel);
+ animationsPanel.add(animations.getAnimationBox());
+
+ performance.add(animationsPanel);
+ return performance;
+ }
+
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Rest of the protected methods. These override do-nothing methods inherited from
+ // the abstract superclass.
+ //////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Apply caching policies and update display when connected MIPS program accesses (data) memory.
+ *
+ * @param memory the attached memory
+ * @param accessNotice information provided by memory in MemoryAccessNotice object
+ */
+ protected void processMIPSUpdate(Observable memory, AccessNotice accessNotice)
+ {
+ MemoryAccessNotice notice = (MemoryAccessNotice) accessNotice;
+ memoryAccessCount++;
+ CacheAccessResult cacheAccessResult = theCache.isItAHitThenReadOnMiss(notice.getAddress());
+ if (cacheAccessResult.isHit())
+ {
cacheHitCount++;
animations.showHit(cacheAccessResult.getBlock());
- }
- else {
+ }
+ else
+ {
cacheMissCount++;
animations.showMiss(cacheAccessResult.getBlock());
- }
- cacheHitRate = cacheHitCount / (double)memoryAccessCount;
- }
-
-
- /**
- * Initialize all JComboBox choice structures not already initialized at declaration.
- * Also creates initial default cache object. Overrides inherited method that does nothing.
- */
- protected void initializePreGUI() {
- cacheBlockSizeChoicesInt = new int[cacheBlockSizeChoices.length];
- for (int i=0; itotalVerticalPixels)? 1 : totalVerticalPixels/numberOfBlocks;
+ int blockPixelHeight = (numberOfBlocks > totalVerticalPixels) ? 1 : totalVerticalPixels / numberOfBlocks;
int blockPixelWidth = 40;
Dimension blockDimension = new Dimension(blockPixelWidth, blockPixelHeight);
blocks = new JTextField[numberOfBlocks];
- for (int i=0; i0){
- CounterValue--;
- }
- else{
- CounterValue=CounterValueMax;
- if((Coprocessor0.getValue(Coprocessor0.STATUS) & 2)==0){
- mars.simulator.Simulator.externalInterruptingDevice = /*Exceptions.*/EXTERNAL_INTERRUPT_TIMER;
- }
- }
- }
- protected void reset(){
- sevenSegPanel.resetSevenSegment();
- hexaKeyPanel.resetHexaKeyboard();
- SecondCounter.resetOneSecondCounter();
+
+ public DigitalLabSim()
+ {
+ super(heading + ", " + version, heading);
}
- protected JComponent buildMainDisplayArea() {
- panelTools=new JPanel(new GridLayout(1,2));
- sevenSegPanel=new SevenSegmentPanel();
- panelTools.add(sevenSegPanel);
- hexaKeyPanel = new HexaKeyboard();
- panelTools.add(hexaKeyPanel);
- SecondCounter= new OneSecondCounter();
- return panelTools;
+
+ public static void main(String[] args)
+ {
+ new DigitalLabSim(heading + ", " + version, heading).go();
}
- private synchronized void updateMMIOControlAndData(int dataAddr, int dataValue) {
- if (!this.isBeingUsedAsAMarsTool || (this.isBeingUsedAsAMarsTool && connectButton.isConnected())) {
- synchronized (Globals.memoryAndRegistersLock) {
- try {
- Globals.memory.setByte(dataAddr, dataValue);
- }
- catch (AddressErrorException aee) {
- System.out.println("Tool author specified incorrect MMIO address!"+aee);
- System.exit(0);
- }
- }
- if (Globals.getGui() != null && Globals.getGui().getMainPane().getExecutePane().getTextSegmentWindow().getCodeHighlighting() ) {
- Globals.getGui().getMainPane().getExecutePane().getDataSegmentWindow().updateValues();
- }
+
+ public String getName()
+ {
+ return "Digital Lab Sim";
+ }
+
+ protected void addAsObserver()
+ {
+ addAsObserver(IN_ADRESS_DISPLAY_1, IN_ADRESS_DISPLAY_1);
+ addAsObserver(Memory.textBaseAddress, Memory.textLimitAddress);
+ }
+
+ public void update(Observable ressource, Object accessNotice)
+ {
+ MemoryAccessNotice notice = (MemoryAccessNotice) accessNotice;
+ int address = notice.getAddress();
+ char value = (char) notice.getValue();
+ if (address == IN_ADRESS_DISPLAY_1)
+ {
+ updateSevenSegment(1, value);
}
- }
- protected JComponent getHelpComponent() {
- final String helpContent =
- " This tool is composed of 3 parts : two seven-segment displays, an hexadecimal keyboard and counter \n"+
- "Seven segment display\n"+
- " Byte value at address 0xFFFF0010 : command right seven segment display \n "+
- " Byte value at address 0xFFFF0011 : command left seven segment display \n "+
- " Each bit of these two bytes are connected to segments (bit 0 for a segment, 1 for b segment and 7 for point \n \n"+
- "Hexadecimal keyboard\n"+
- " Byte value at address 0xFFFF0012 : command row number of hexadecimal keyboard (bit 0 to 3) and enable keyboard interrupt (bit 7) \n" +
- " Byte value at address 0xFFFF0014 : receive row and column of the key pressed, 0 if not key pressed \n"+
- " The mips program have to scan, one by one, each row (send 1,2,4,8...)"+
- " and then observe if a key is pressed (that mean byte value at adresse 0xFFFF0014 is different from zero). "+
- " This byte value is composed of row number (4 left bits) and column number (4 right bits)"+
- " Here you'll find the code for each key : 0x11,0x21,0x41,0x81,0x12,0x22,0x42,0x82,0x14,0x24,0x44,0x84,0x18,0x28,0x48,0x88. \n"+
- " For exemple key number 2 return 0x41, that mean the key is on column 3 and row 1. \n"+
- " If keyboard interruption is enable, an exception is started, with cause register bit number 11 set.\n \n"+
- "Counter\n"+
- " Byte value at address 0xFFFF0013 : If one bit of this byte is set, the counter interruption is enable.\n"+
- " If counter interruption is enable, every 30 instructions, an exception is started with cause register bit number 10.\n" +
- " (contributed by Didier Teifreto, dteifreto@lifc.univ-fcomte.fr)"
- ;
+ else if (address == IN_ADRESS_DISPLAY_2)
+ {
+ updateSevenSegment(0, value);
+ }
+ else if (address == IN_ADRESS_HEXA_KEYBOARD)
+ {
+ updateHexaKeyboard(value);
+ }
+ else if (address == IN_ADRESS_COUNTER)
+ {
+ updateOneSecondCounter(value);
+ }
+ if (CounterInterruptOnOff)
+ {
+ if (CounterValue > 0)
+ {
+ CounterValue--;
+ }
+ else
+ {
+ CounterValue = CounterValueMax;
+ if ((Coprocessor0.getValue(Coprocessor0.STATUS) & 2) == 0)
+ {
+ mars.simulator.Simulator.externalInterruptingDevice = /*Exceptions.*/EXTERNAL_INTERRUPT_TIMER;
+ }
+ }
+ }
+ }
+
+ protected void reset()
+ {
+ sevenSegPanel.resetSevenSegment();
+ hexaKeyPanel.resetHexaKeyboard();
+ SecondCounter.resetOneSecondCounter();
+ }
+
+ protected JComponent buildMainDisplayArea()
+ {
+ panelTools = new JPanel(new GridLayout(1, 2));
+ sevenSegPanel = new SevenSegmentPanel();
+ panelTools.add(sevenSegPanel);
+ hexaKeyPanel = new HexaKeyboard();
+ panelTools.add(hexaKeyPanel);
+ SecondCounter = new OneSecondCounter();
+ return panelTools;
+ }
+
+ private synchronized void updateMMIOControlAndData(int dataAddr, int dataValue)
+ {
+ if (!this.isBeingUsedAsAMarsTool || (this.isBeingUsedAsAMarsTool && connectButton.isConnected()))
+ {
+ synchronized (Globals.memoryAndRegistersLock)
+ {
+ try
+ {
+ Globals.memory.setByte(dataAddr, dataValue);
+ }
+ catch (AddressErrorException aee)
+ {
+ System.out.println("Tool author specified incorrect MMIO address!" + aee);
+ System.exit(0);
+ }
+ }
+ if (Globals.getGui() != null && Globals.getGui().getMainPane().getExecutePane().getTextSegmentWindow().getCodeHighlighting())
+ {
+ Globals.getGui().getMainPane().getExecutePane().getDataSegmentWindow().updateValues();
+ }
+ }
+ }
+
+ protected JComponent getHelpComponent()
+ {
+ final String helpContent =
+ " This tool is composed of 3 parts : two seven-segment displays, an hexadecimal keyboard and counter \n" +
+ "Seven segment display\n" +
+ " Byte value at address 0xFFFF0010 : command right seven segment display \n " +
+ " Byte value at address 0xFFFF0011 : command left seven segment display \n " +
+ " Each bit of these two bytes are connected to segments (bit 0 for a segment, 1 for b segment and 7 for point \n \n" +
+ "Hexadecimal keyboard\n" +
+ " Byte value at address 0xFFFF0012 : command row number of hexadecimal keyboard (bit 0 to 3) and enable keyboard interrupt (bit 7) \n" +
+ " Byte value at address 0xFFFF0014 : receive row and column of the key pressed, 0 if not key pressed \n" +
+ " The mips program have to scan, one by one, each row (send 1,2,4,8...)" +
+ " and then observe if a key is pressed (that mean byte value at adresse 0xFFFF0014 is different from zero). " +
+ " This byte value is composed of row number (4 left bits) and column number (4 right bits)" +
+ " Here you'll find the code for each key : 0x11,0x21,0x41,0x81,0x12,0x22,0x42,0x82,0x14,0x24,0x44,0x84,0x18,0x28,0x48,0x88. \n" +
+ " For exemple key number 2 return 0x41, that mean the key is on column 3 and row 1. \n" +
+ " If keyboard interruption is enable, an exception is started, with cause register bit number 11 set.\n \n" +
+ "Counter\n" +
+ " Byte value at address 0xFFFF0013 : If one bit of this byte is set, the counter interruption is enable.\n" +
+ " If counter interruption is enable, every 30 instructions, an exception is started with cause register bit number 10.\n" +
+ " (contributed by Didier Teifreto, dteifreto@lifc.univ-fcomte.fr)";
JButton help = new JButton("Help");
help.addActionListener(
- new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- JTextArea ja = new JTextArea(helpContent);
- ja.setRows(20);
- ja.setColumns(60);
- ja.setLineWrap(true);
- ja.setWrapStyleWord(true);
- JOptionPane.showMessageDialog(theWindow, new JScrollPane(ja),
+ new ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ JTextArea ja = new JTextArea(helpContent);
+ ja.setRows(20);
+ ja.setColumns(60);
+ ja.setLineWrap(true);
+ ja.setWrapStyleWord(true);
+ JOptionPane.showMessageDialog(theWindow, new JScrollPane(ja),
"Simulating the Hexa Keyboard and Seven segment display", JOptionPane.INFORMATION_MESSAGE);
- }
- });
- return help;
+ }
+ });
+ return help;
}/* ....................Seven Segment display start here................................... */
- /* ...........................Seven segment display start here ..............................*/
- public void updateSevenSegment(int number,char value) {
- sevenSegPanel.display[number].modifyDisplay(value);
+
+ /* ...........................Seven segment display start here ..............................*/
+ public void updateSevenSegment(int number, char value)
+ {
+ sevenSegPanel.display[number].modifyDisplay(value);
}
- public class SevenSegmentDisplay extends JComponent {
- public char aff;
- public SevenSegmentDisplay(char aff){
- this.aff=aff;
- this.setPreferredSize(new Dimension(60,80));
- }
- public void modifyDisplay(char val){
- aff=val;
- this.repaint();
- }
- public void SwitchSegment(Graphics g,char segment){
- switch(segment){
- case 'a': //a segment
- int[]pxa1={12,9,12};
- int[]pxa2={36,39,36};
- int[]pya={5,8,11};
- g.fillPolygon(pxa1,pya, 3);
- g.fillPolygon(pxa2,pya, 3);
- g.fillRect(12,5,24,6);
- break;
- case 'b': //b segment
- int[]pxb={37,40,43};
- int[]pyb1={12,9,12};
- int[]pyb2={36,39,36};
- g.fillPolygon(pxb,pyb1, 3);
- g.fillPolygon(pxb,pyb2, 3);
- g.fillRect(37,12,6,24);
- break;
- case 'c': // c segment
- int[]pxc={37,40,43};
- int[]pyc1={44,41,44};
- int[]pyc2={68,71,68};
- g.fillPolygon(pxc,pyc1, 3);
- g.fillPolygon(pxc,pyc2, 3);
- g.fillRect(37,44,6,24);
- break;
- case 'd': // d segment
- int[]pxd1={12,9,12};
- int[]pxd2={36,39,36};
- int[]pyd={69,72,75};
- g.fillPolygon(pxd1,pyd, 3);
- g.fillPolygon(pxd2,pyd, 3);
- g.fillRect(12,69,24,6);
- break;
- case 'e': // e segment
- int[]pxe={5,8,11};
- int[]pye1={44,41,44};
- int[]pye2={68,71,68};
- g.fillPolygon(pxe,pye1, 3);
- g.fillPolygon(pxe,pye2, 3);
- g.fillRect(5,44,6,24);
- break;
- case 'f': // f segment
- int[]pxf={5,8,11};
- int[]pyf1={12,9,12};
- int[]pyf2={36,39,36};
- g.fillPolygon(pxf,pyf1, 3);
- g.fillPolygon(pxf,pyf2, 3);
- g.fillRect(5,12,6,24);
- break;
- case 'g': // g segment
- int[]pxg1={12,9,12};
- int[]pxg2={36,39,36};
- int[]pyg={37,40,43};
- g.fillPolygon(pxg1,pyg, 3);
- g.fillPolygon(pxg2,pyg, 3);
- g.fillRect(12,37,24,6);
- break;
- case 'h': // decimal point
- g.fillOval(49,68,8,8);
- break;
- }
- }
- public void paint(Graphics g) {
- char c='a';
- while(c<='h'){
- if ((aff & 0x1) == 1)
- g.setColor(Color.RED);
- else
- g.setColor(Color.LIGHT_GRAY);
- SwitchSegment(g,c);
- aff = (char)(aff >>>1);
- c++;
- }
- }
+
+ /* ...........................Seven segment display end here ..............................*/
+ /* ....................Hexa Keyboard start here................................... */
+ public void updateHexaKeyboard(char row)
+ {
+ int key = KeyBoardValueButtonClick;
+ if ((key != -1) && ((1 << (key / 4)) == (row & 0xF)))
+ {
+ updateMMIOControlAndData(OUT_ADRESS_HEXA_KEYBOARD,
+ (char) (1 << (key / 4)) | (1 << (4 + (key % 4))));
+ }
+ else
+ {
+ updateMMIOControlAndData(OUT_ADRESS_HEXA_KEYBOARD, 0);
+ }
+ KeyboardInterruptOnOff = (row & 0xF0) != 0;
}
- public class SevenSegmentPanel extends JPanel {
- public SevenSegmentDisplay[] display;
- public SevenSegmentPanel(){
- int i;
- FlowLayout fl= new FlowLayout();
- this.setLayout(fl);
- display= new SevenSegmentDisplay[2];
- for (i=0;i<2;i++){
- display[i]= new SevenSegmentDisplay((char)(0));
- this.add(display[i]);
- }
- }
- public void modifyDisplay(int num,char val){
- display[num].modifyDisplay(val);
- display[num].repaint();
- }
- public void resetSevenSegment() {
- int i;
- for (i=0;i<2;i++)
- modifyDisplay(i, (char)0);
- }
+
+ /* ....................Hexa Keyboard end here................................... */
+ /* ....................Timer start here................................... */
+ public void updateOneSecondCounter(char value)
+ {
+ if (value != 0)
+ {
+ CounterInterruptOnOff = true;
+ CounterValue = CounterValueMax;
+ }
+ else
+ {
+ CounterInterruptOnOff = false;
+ }
}
- /* ...........................Seven segment display end here ..............................*/
-/* ....................Hexa Keyboard start here................................... */
- public void updateHexaKeyboard(char row) {
- int key = KeyBoardValueButtonClick;
- if ((key !=-1)&& ((1 << (key / 4))==(row & 0xF))){
- updateMMIOControlAndData(OUT_ADRESS_HEXA_KEYBOARD,
- (char)(1 << (key / 4)) | (1 << (4+(key%4))));
- }
- else{
- updateMMIOControlAndData(OUT_ADRESS_HEXA_KEYBOARD, 0);
- }
- if ((row & 0xF0) != 0)
- KeyboardInterruptOnOff = true;
- else
- KeyboardInterruptOnOff = false;
+
+ public class SevenSegmentDisplay extends JComponent
+ {
+ public char aff;
+
+ public SevenSegmentDisplay(char aff)
+ {
+ this.aff = aff;
+ this.setPreferredSize(new Dimension(60, 80));
+ }
+
+ public void modifyDisplay(char val)
+ {
+ aff = val;
+ this.repaint();
+ }
+
+ public void SwitchSegment(Graphics g, char segment)
+ {
+ switch (segment)
+ {
+ case 'a': //a segment
+ int[] pxa1 = {12, 9, 12};
+ int[] pxa2 = {36, 39, 36};
+ int[] pya = {5, 8, 11};
+ g.fillPolygon(pxa1, pya, 3);
+ g.fillPolygon(pxa2, pya, 3);
+ g.fillRect(12, 5, 24, 6);
+ break;
+ case 'b': //b segment
+ int[] pxb = {37, 40, 43};
+ int[] pyb1 = {12, 9, 12};
+ int[] pyb2 = {36, 39, 36};
+ g.fillPolygon(pxb, pyb1, 3);
+ g.fillPolygon(pxb, pyb2, 3);
+ g.fillRect(37, 12, 6, 24);
+ break;
+ case 'c': // c segment
+ int[] pxc = {37, 40, 43};
+ int[] pyc1 = {44, 41, 44};
+ int[] pyc2 = {68, 71, 68};
+ g.fillPolygon(pxc, pyc1, 3);
+ g.fillPolygon(pxc, pyc2, 3);
+ g.fillRect(37, 44, 6, 24);
+ break;
+ case 'd': // d segment
+ int[] pxd1 = {12, 9, 12};
+ int[] pxd2 = {36, 39, 36};
+ int[] pyd = {69, 72, 75};
+ g.fillPolygon(pxd1, pyd, 3);
+ g.fillPolygon(pxd2, pyd, 3);
+ g.fillRect(12, 69, 24, 6);
+ break;
+ case 'e': // e segment
+ int[] pxe = {5, 8, 11};
+ int[] pye1 = {44, 41, 44};
+ int[] pye2 = {68, 71, 68};
+ g.fillPolygon(pxe, pye1, 3);
+ g.fillPolygon(pxe, pye2, 3);
+ g.fillRect(5, 44, 6, 24);
+ break;
+ case 'f': // f segment
+ int[] pxf = {5, 8, 11};
+ int[] pyf1 = {12, 9, 12};
+ int[] pyf2 = {36, 39, 36};
+ g.fillPolygon(pxf, pyf1, 3);
+ g.fillPolygon(pxf, pyf2, 3);
+ g.fillRect(5, 12, 6, 24);
+ break;
+ case 'g': // g segment
+ int[] pxg1 = {12, 9, 12};
+ int[] pxg2 = {36, 39, 36};
+ int[] pyg = {37, 40, 43};
+ g.fillPolygon(pxg1, pyg, 3);
+ g.fillPolygon(pxg2, pyg, 3);
+ g.fillRect(12, 37, 24, 6);
+ break;
+ case 'h': // decimal point
+ g.fillOval(49, 68, 8, 8);
+ break;
+ }
+ }
+
+ public void paint(Graphics g)
+ {
+ char c = 'a';
+ while (c <= 'h')
+ {
+ if ((aff & 0x1) == 1)
+ {
+ g.setColor(Color.RED);
+ }
+ else
+ {
+ g.setColor(Color.LIGHT_GRAY);
+ }
+ SwitchSegment(g, c);
+ aff = (char) (aff >>> 1);
+ c++;
+ }
+ }
}
- public class HexaKeyboard extends JPanel{
- public JButton[] button;
- public HexaKeyboard(){
- int i;
- GridLayout layout = new GridLayout(4,4);
- this.setLayout(layout);
- button = new JButton[16];
- for (i=0;i<16;i++){
- button[i]= new JButton(Integer.toHexString(i));
- button[i].setBackground(Color.WHITE);
- button[i].setMargin(new Insets(10,10,10,10));
- button[i].addMouseListener(new EcouteurClick(i));
- this.add(button[i]);
- }
- }
- public void resetHexaKeyboard(){
- int i;
- KeyBoardValueButtonClick=-1;
- for(i=0;i<16;i++){
- button[i].setBackground(Color.WHITE);
- }
- }
- public class EcouteurClick implements MouseListener{
- private int buttonValue;
- public EcouteurClick(int val){
- buttonValue=val;
- }
- public void mouseEntered(MouseEvent arg0) { }
- public void mouseExited(MouseEvent arg0) {}
- public void mousePressed(MouseEvent arg0) {}
- public void mouseReleased(MouseEvent arg0) {}
- public void mouseClicked(MouseEvent arg0) {
- int i;
- if(KeyBoardValueButtonClick!=-1){//Button already pressed -> now realease
- KeyBoardValueButtonClick = -1;
- updateMMIOControlAndData(OUT_ADRESS_HEXA_KEYBOARD,0);
- for(i=0;i<16;i++)
- button[i].setBackground(Color.WHITE);
- }
- else{ // new button pressed
- KeyBoardValueButtonClick = buttonValue;
- button[KeyBoardValueButtonClick].setBackground(Color.GREEN);
- if( KeyboardInterruptOnOff && (Coprocessor0.getValue(Coprocessor0.STATUS) & 2)==0){
- mars.simulator.Simulator.externalInterruptingDevice = /*Exceptions.*/EXTERNAL_INTERRUPT_HEXA_KEYBOARD;
- }
- }
- }
- }
+
+ public class SevenSegmentPanel extends JPanel
+ {
+ public SevenSegmentDisplay[] display;
+
+ public SevenSegmentPanel()
+ {
+ int i;
+ FlowLayout fl = new FlowLayout();
+ this.setLayout(fl);
+ display = new SevenSegmentDisplay[2];
+ for (i = 0; i < 2; i++)
+ {
+ display[i] = new SevenSegmentDisplay((char) (0));
+ this.add(display[i]);
+ }
+ }
+
+ public void modifyDisplay(int num, char val)
+ {
+ display[num].modifyDisplay(val);
+ display[num].repaint();
+ }
+
+ public void resetSevenSegment()
+ {
+ int i;
+ for (i = 0; i < 2; i++)
+ {
+ modifyDisplay(i, (char) 0);
+ }
+ }
}
-/* ....................Hexa Keyboard end here................................... */
-/* ....................Timer start here................................... */
- public void updateOneSecondCounter(char value) {
- if (value !=0){
- CounterInterruptOnOff=true;
- CounterValue=CounterValueMax;
- }
- else{
- CounterInterruptOnOff=false;
- }
+
+ public class HexaKeyboard extends JPanel
+ {
+ public JButton[] button;
+
+ public HexaKeyboard()
+ {
+ int i;
+ GridLayout layout = new GridLayout(4, 4);
+ this.setLayout(layout);
+ button = new JButton[16];
+ for (i = 0; i < 16; i++)
+ {
+ button[i] = new JButton(Integer.toHexString(i));
+ button[i].setBackground(Color.WHITE);
+ button[i].setMargin(new Insets(10, 10, 10, 10));
+ button[i].addMouseListener(new EcouteurClick(i));
+ this.add(button[i]);
+ }
+ }
+
+ public void resetHexaKeyboard()
+ {
+ int i;
+ KeyBoardValueButtonClick = -1;
+ for (i = 0; i < 16; i++)
+ {
+ button[i].setBackground(Color.WHITE);
+ }
+ }
+
+ public class EcouteurClick implements MouseListener
+ {
+ private final int buttonValue;
+
+ public EcouteurClick(int val)
+ {
+ buttonValue = val;
+ }
+
+ public void mouseEntered(MouseEvent arg0)
+ {
+ }
+
+ public void mouseExited(MouseEvent arg0)
+ {
+ }
+
+ public void mousePressed(MouseEvent arg0)
+ {
+ }
+
+ public void mouseReleased(MouseEvent arg0)
+ {
+ }
+
+ public void mouseClicked(MouseEvent arg0)
+ {
+ int i;
+ if (KeyBoardValueButtonClick != -1)
+ {//Button already pressed -> now realease
+ KeyBoardValueButtonClick = -1;
+ updateMMIOControlAndData(OUT_ADRESS_HEXA_KEYBOARD, 0);
+ for (i = 0; i < 16; i++)
+ {
+ button[i].setBackground(Color.WHITE);
+ }
+ }
+ else
+ { // new button pressed
+ KeyBoardValueButtonClick = buttonValue;
+ button[KeyBoardValueButtonClick].setBackground(Color.GREEN);
+ if (KeyboardInterruptOnOff && (Coprocessor0.getValue(Coprocessor0.STATUS) & 2) == 0)
+ {
+ mars.simulator.Simulator.externalInterruptingDevice = /*Exceptions.*/EXTERNAL_INTERRUPT_HEXA_KEYBOARD;
+ }
+ }
+ }
+ }
}
- public class OneSecondCounter{
- public OneSecondCounter(){
- CounterInterruptOnOff=false;
- }
- public void resetOneSecondCounter(){
- CounterInterruptOnOff=false;
- CounterValue=CounterValueMax;
- }
+
+ public class OneSecondCounter
+ {
+ public OneSecondCounter()
+ {
+ CounterInterruptOnOff = false;
+ }
+
+ public void resetOneSecondCounter()
+ {
+ CounterInterruptOnOff = false;
+ CounterValue = CounterValueMax;
+ }
}
}
diff --git a/src/main/java/mars/tools/FloatRepresentation.java b/src/main/java/mars/tools/FloatRepresentation.java
index 6283b96..ecdf184 100644
--- a/src/main/java/mars/tools/FloatRepresentation.java
+++ b/src/main/java/mars/tools/FloatRepresentation.java
@@ -1,17 +1,19 @@
- package mars.tools;
- import mars.*;
- import mars.util.*;
- import mars.assembler.*;
- import mars.mips.instructions.*;
- import mars.mips.hardware.*;
- import java.util.*;
- import java.io.*;
- import java.awt.*;
- import java.awt.event.*;
- import javax.swing.*;
- import javax.swing.event.*;
- import javax.swing.border.*;
- import javax.swing.text.html.*;
+package mars.tools;
+
+import mars.Globals;
+import mars.mips.hardware.AccessNotice;
+import mars.mips.hardware.Coprocessor1;
+import mars.mips.hardware.Register;
+import mars.util.Binary;
+
+import javax.swing.*;
+import javax.swing.border.TitledBorder;
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.KeyAdapter;
+import java.awt.event.KeyEvent;
+import java.util.Observable;
/*
Copyright (c) 2003-2006, Pete Sanderson and Kenneth Vollmar
@@ -40,868 +42,1035 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
(MIT license, http://www.opensource.org/licenses/mit-license.html)
*/
-
+
+/**
+ * Tool to help students learn about IEEE 754 representation of 32 bit floating point values. This representation is
+ * used by MIPS "float" directive and instructions and also the Java (and most other languages) "float" data type. As
+ * written, it can ALMOST be adapted to 64 bit by changing a few constants.
+ */
+public class FloatRepresentation extends AbstractMarsToolAndApplication
+{
+ private static final String title = "Floating Point Representation, ";
+
+ private static final String defaultHex = "00000000";
+
+ private static final String defaultDecimal = "0.0";
+
+ private static final String defaultBinarySign = "0";
+
+ private static final String defaultBinaryExponent = "00000000";
+
+ private static final String defaultBinaryFraction = "00000000000000000000000";
+
+ private static final int maxLengthHex = 8;
+
+ private static final int maxLengthBinarySign = 1;
+
+ private static final int maxLengthBinaryExponent = 8;
+
+ private static final int maxLengthBinaryFraction = 23;
+
+ private static final int maxLengthBinaryTotal = maxLengthBinarySign + maxLengthBinaryExponent + maxLengthBinaryFraction;
+
+ private static final int maxLengthDecimal = 20;
+
+ private static final String denormalizedLabel = " significand (denormalized - no 'hidden bit')";
+
+ private static final String normalizedLabel = " significand ('hidden bit' underlined) ";
+
+ private static final Font instructionsFont = new Font("Arial", Font.PLAIN, 14);
+
+ private static final Font hexDisplayFont = new Font("Courier", Font.PLAIN, 32);
+
+ private static final Font binaryDisplayFont = new Font("Courier", Font.PLAIN, 18);
+
+ private static final Font decimalDisplayFont = new Font("Courier", Font.PLAIN, 18);
+
+ private static final Color hexDisplayColor = Color.red;
+
+ private static final Color binaryDisplayColor = Color.black;
+
+ private static final Color decimalDisplayColor = Color.blue;
+
+ private static final String expansionFontTag = "";
+
+ private static final String instructionFontTag = "";
+
+ private static final int exponentBias = 127; // 32 bit floating point exponent bias
+
+ //Put here because inner class cannot have static members.
+ private static final String zeroes =
+ "0000000000000000000000000000000000000000000000000000000000000000"; //64
+
+ private static final String HTMLspaces = " ";
+
+ private static final String version = "Version 1.1";
+
+ private static final String heading = "32-bit IEEE 754 Floating Point Representation";
+
+ private Register attachedRegister = null;
+
+ private Register[] fpRegisters;
+
+ private final FloatRepresentation thisFloatTool;
+
+ // Panels to hold binary displays and decorations (labels, arrows)
+ private JPanel binarySignDecoratedDisplay,
+ binaryExponentDecoratedDisplay, binaryFractionDecoratedDisplay;
+
+ // Editable fields for the hex, binary and decimal representations.
+ private JTextField hexDisplay, decimalDisplay,
+ binarySignDisplay, binaryExponentDisplay, binaryFractionDisplay;
+
+ // Non-editable fields to display formula translating binary to decimal.
+ private JLabel expansionDisplay;
+
+ private final JLabel significandLabel = new JLabel(denormalizedLabel, JLabel.CENTER);
+
+ private BinaryToDecimalFormulaGraphic binaryToDecimalFormulaGraphic;
+
+ // Non-editable field to display instructions
+ private InstructionsPane instructions;
+
+ private final String defaultInstructions = "Modify any value then press the Enter key to update all values.";
+
/**
- * Tool to help students learn about IEEE 754 representation of 32 bit
- * floating point values. This representation is used by MIPS "float"
- * directive and instructions and also the Java (and most other languages)
- * "float" data type. As written, it can ALMOST be adapted to 64 bit by
- * changing a few constants.
- */
- public class FloatRepresentation extends AbstractMarsToolAndApplication {
- private static String version = "Version 1.1";
- private static String heading = "32-bit IEEE 754 Floating Point Representation";
- private static final String title = "Floating Point Representation, ";
-
- private static final String defaultHex = "00000000";
- private static final String defaultDecimal = "0.0";
- private static final String defaultBinarySign = "0";
- private static final String defaultBinaryExponent = "00000000";
- private static final String defaultBinaryFraction = "00000000000000000000000";
- private static final int maxLengthHex = 8;
- private static final int maxLengthBinarySign = 1;
- private static final int maxLengthBinaryExponent = 8;
- private static final int maxLengthBinaryFraction = 23;
- private static final int maxLengthBinaryTotal = maxLengthBinarySign+maxLengthBinaryExponent+maxLengthBinaryFraction;
- private static final int maxLengthDecimal = 20;
- private static final String denormalizedLabel = " significand (denormalized - no 'hidden bit')";
- private static final String normalizedLabel = " significand ('hidden bit' underlined) ";
- private static final Font instructionsFont = new Font("Arial",Font.PLAIN,14);
- private static final Font hexDisplayFont = new Font("Courier",Font.PLAIN,32);
- private static final Font binaryDisplayFont = new Font("Courier",Font.PLAIN,18);
- private static final Font decimalDisplayFont = new Font("Courier",Font.PLAIN,18);
- private static final Color hexDisplayColor = Color.red;
- private static final Color binaryDisplayColor = Color.black;
- private static final Color decimalDisplayColor = Color.blue;
- private static final String expansionFontTag = "";
- private static final String instructionFontTag = "";
- private static final int exponentBias = 127; // 32 bit floating point exponent bias
-
- private Register attachedRegister = null;
- private Register[] fpRegisters;
- private FloatRepresentation thisFloatTool;
- // Panels to hold binary displays and decorations (labels, arrows)
- private JPanel binarySignDecoratedDisplay,
- binaryExponentDecoratedDisplay, binaryFractionDecoratedDisplay;
- // Editable fields for the hex, binary and decimal representations.
- private JTextField hexDisplay, decimalDisplay,
- binarySignDisplay, binaryExponentDisplay, binaryFractionDisplay;
- // Non-editable fields to display formula translating binary to decimal.
- private JLabel expansionDisplay;
- private JLabel significandLabel = new JLabel(denormalizedLabel, JLabel.CENTER);
- private BinaryToDecimalFormulaGraphic binaryToDecimalFormulaGraphic;
- // Non-editable field to display instructions
- private InstructionsPane instructions;
- private String defaultInstructions = "Modify any value then press the Enter key to update all values.";
-
- /**
- * Simple constructor, likely used to run a stand-alone memory reference visualizer.
- * @param title String containing title for title bar
- * @param heading String containing text for heading shown in upper part of window.
- */
- public FloatRepresentation(String title, String heading) {
- super(title,heading);
- thisFloatTool = this;
- }
-
- /**
- * Simple constructor, likely used by the MARS Tools menu mechanism
- */
- public FloatRepresentation() {
- this(title+version, heading);
- }
-
- /**
- * Main provided for pure stand-alone use. Recommended stand-alone use is to write a
- * driver program that instantiates a FloatRepresentation object then invokes its go() method.
- * "stand-alone" means it is not invoked from the MARS Tools menu. "Pure" means there
- * is no driver program to invoke the application.
- */
- public static void main(String[] args) {
- new FloatRepresentation(title+version,heading).go();
- }
-
- /**
- * Fetch tool name (for display in MARS Tools menu)
- * @return String containing tool name
- */
- public String getName() {
- return "Floating Point Representation";
- }
-
- /**
- * Override the inherited method, which registers us as an Observer over the static data segment
- * (starting address 0x10010000) only. This version will register us as observer over the selected
- * floating point register, if any. If no register is selected, it will not do anything.
- * If you use the inherited GUI buttons, this method is invoked when you click "Connect" button
- * on MarsTool or the "Assemble and Run" button on a Mars-based app.
- */
- protected void addAsObserver() {
- addAsObserver(attachedRegister);
- }
-
- /**
- * Delete this app/tool as an Observer of the attached register. This overrides
- * the inherited version which deletes only as an Observer of memory.
- * This method is called when the default "Disconnect" button on a MarsTool is selected or
- * when the MIPS program execution triggered by the default "Assemble and run" on a stand-alone
- * Mars app terminates (e.g. when the button is re-enabled).
- */
- protected void deleteAsObserver() {
- deleteAsObserver(attachedRegister);
- }
-
- /**
- * Method that constructs the main display area. This will be vertically sandwiched between
- * the standard heading area at the top and the control area at the bottom.
- * @return the GUI component containing the application/tool-specific part of the user interface
- */
- protected JComponent buildMainDisplayArea() {
- return buildDisplayArea();
- }
-
- /**
- * Override inherited update() to update display when "attached" register is modified
- * either by MIPS program or by user editing it on the MARS user interface.
- * The latter is the reason for overriding the inherited update() method.
- * The inherited method will filter out notices triggered by the MARS GUI or the user.
- * @param register the attached register
- * @param accessNotice information provided by register in RegisterAccessNotice object
- */
- public void update(Observable register, Object accessNotice) {
- if (((AccessNotice)accessNotice).getAccessType()==AccessNotice.WRITE) {
+ * Simple constructor, likely used to run a stand-alone memory reference visualizer.
+ *
+ * @param title String containing title for title bar
+ * @param heading String containing text for heading shown in upper part of window.
+ */
+ public FloatRepresentation(String title, String heading)
+ {
+ super(title, heading);
+ thisFloatTool = this;
+ }
+
+ /**
+ * Simple constructor, likely used by the MARS Tools menu mechanism
+ */
+ public FloatRepresentation()
+ {
+ this(title + version, heading);
+ }
+
+ /**
+ * Main provided for pure stand-alone use. Recommended stand-alone use is to write a driver program that
+ * instantiates a FloatRepresentation object then invokes its go() method. "stand-alone" means it is not invoked
+ * from the MARS Tools menu. "Pure" means there is no driver program to invoke the application.
+ */
+ public static void main(String[] args)
+ {
+ new FloatRepresentation(title + version, heading).go();
+ }
+
+ /**
+ * Fetch tool name (for display in MARS Tools menu)
+ *
+ * @return String containing tool name
+ */
+ public String getName()
+ {
+ return "Floating Point Representation";
+ }
+
+ /**
+ * Override the inherited method, which registers us as an Observer over the static data segment (starting address
+ * 0x10010000) only. This version will register us as observer over the selected floating point register, if any.
+ * If no register is selected, it will not do anything. If you use the inherited GUI buttons, this method is invoked
+ * when you click "Connect" button on MarsTool or the "Assemble and Run" button on a Mars-based app.
+ */
+ protected void addAsObserver()
+ {
+ addAsObserver(attachedRegister);
+ }
+
+ /**
+ * Delete this app/tool as an Observer of the attached register. This overrides the inherited version which deletes
+ * only as an Observer of memory. This method is called when the default "Disconnect" button on a MarsTool is
+ * selected or when the MIPS program execution triggered by the default "Assemble and run" on a stand-alone Mars app
+ * terminates (e.g. when the button is re-enabled).
+ */
+ protected void deleteAsObserver()
+ {
+ deleteAsObserver(attachedRegister);
+ }
+
+ /**
+ * Method that constructs the main display area. This will be vertically sandwiched between the standard heading
+ * area at the top and the control area at the bottom.
+ *
+ * @return the GUI component containing the application/tool-specific part of the user interface
+ */
+ protected JComponent buildMainDisplayArea()
+ {
+ return buildDisplayArea();
+ }
+
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Private methods defined to support the above.
+
+ /**
+ * Override inherited update() to update display when "attached" register is modified either by MIPS program or by
+ * user editing it on the MARS user interface. The latter is the reason for overriding the inherited update()
+ * method. The inherited method will filter out notices triggered by the MARS GUI or the user.
+ *
+ * @param register the attached register
+ * @param accessNotice information provided by register in RegisterAccessNotice object
+ */
+ public void update(Observable register, Object accessNotice)
+ {
+ if (((AccessNotice) accessNotice).getAccessType() == AccessNotice.WRITE)
+ {
updateDisplays(new FlavorsOfFloat().buildOneFromInt(attachedRegister.getValue()));
- }
- }
-
- /**
- * Method to reset display values to 0 when the Reset button selected.
- * If attached to a MIPS register at the time, the register will be reset as well.
- * Overrides inherited method that does nothing.
- */
- protected void reset() {
- instructions.setText(defaultInstructions);
- updateDisplaysAndRegister(new FlavorsOfFloat());
- }
-
-
- //////////////////////////////////////////////////////////////////////////////////////
- // Private methods defined to support the above.
-
- protected JComponent buildDisplayArea() {
- // Panel to hold all floating point dislay and editing components
- Box mainPanel = Box.createVerticalBox();
- JPanel leftPanel = new JPanel(new GridLayout(5,1,0,0));
- JPanel rightPanel = new JPanel(new GridLayout(5,1,0,0));
- Box subMainPanel = Box.createHorizontalBox();
- subMainPanel.add(leftPanel);
- subMainPanel.add(rightPanel);
- mainPanel.add(subMainPanel);
-
- // Editable display for hexadecimal version of the float value
- hexDisplay = new JTextField(defaultHex, maxLengthHex+1);
- hexDisplay.setFont(hexDisplayFont);
- hexDisplay.setForeground(hexDisplayColor);
- hexDisplay.setHorizontalAlignment(JTextField.RIGHT);
- hexDisplay.setToolTipText(""+maxLengthHex+"-digit hexadecimal (base 16) display");
- hexDisplay.setEditable(true);
- hexDisplay.revalidate();
- hexDisplay.addKeyListener(new HexDisplayKeystrokeListener(8));
-
- JPanel hexPanel = new JPanel();
- hexPanel.add(hexDisplay);
- //################ Grid Row : Hexadecimal ##################################
- leftPanel.add(hexPanel);
-
- HexToBinaryGraphicPanel hexToBinaryGraphic = new HexToBinaryGraphicPanel();
- //################ Grid Row : Hex-to-binary graphic ########################
- leftPanel.add(hexToBinaryGraphic);
-
- // Editable display for binary version of float value.
- // It is split into 3 separately editable components (sign,exponent,fraction)
-
- binarySignDisplay = new JTextField(defaultBinarySign, maxLengthBinarySign+1);
- binarySignDisplay.setFont(binaryDisplayFont);
- binarySignDisplay.setForeground(binaryDisplayColor);
- binarySignDisplay.setHorizontalAlignment(JTextField.RIGHT);
- binarySignDisplay.setToolTipText("The sign bit");
- binarySignDisplay.setEditable(true);
- binarySignDisplay.revalidate();
-
- binaryExponentDisplay = new JTextField(defaultBinaryExponent, maxLengthBinaryExponent+1);
- binaryExponentDisplay.setFont(binaryDisplayFont);
- binaryExponentDisplay.setForeground(binaryDisplayColor);
- binaryExponentDisplay.setHorizontalAlignment(JTextField.RIGHT);
- binaryExponentDisplay.setToolTipText(""+maxLengthBinaryExponent+"-bit exponent");
- binaryExponentDisplay.setEditable(true);
- binaryExponentDisplay.revalidate();
-
- binaryFractionDisplay = new BinaryFractionDisplayTextField(defaultBinaryFraction, maxLengthBinaryFraction+1);
- binaryFractionDisplay.setFont(binaryDisplayFont);
- binaryFractionDisplay.setForeground(binaryDisplayColor);
- binaryFractionDisplay.setHorizontalAlignment(JTextField.RIGHT);
- binaryFractionDisplay.setToolTipText(""+maxLengthBinaryFraction+"-bit fraction");
- binaryFractionDisplay.setEditable(true);
- binaryFractionDisplay.revalidate();
-
- binarySignDisplay.addKeyListener(new BinaryDisplayKeystrokeListener(maxLengthBinarySign));
- binaryExponentDisplay.addKeyListener(new BinaryDisplayKeystrokeListener(maxLengthBinaryExponent));
- binaryFractionDisplay.addKeyListener(new BinaryDisplayKeystrokeListener(maxLengthBinaryFraction));
- JPanel binaryPanel = new JPanel();
-
- binarySignDecoratedDisplay = new JPanel(new BorderLayout());
- binaryExponentDecoratedDisplay = new JPanel(new BorderLayout());
- binaryFractionDecoratedDisplay = new JPanel(new BorderLayout());
- binarySignDecoratedDisplay.add(binarySignDisplay,BorderLayout.CENTER);
- binarySignDecoratedDisplay.add(new JLabel("sign",JLabel.CENTER),BorderLayout.SOUTH);
- binaryExponentDecoratedDisplay.add(binaryExponentDisplay,BorderLayout.CENTER);
- binaryExponentDecoratedDisplay.add(new JLabel("exponent",JLabel.CENTER),BorderLayout.SOUTH);
- binaryFractionDecoratedDisplay.add(binaryFractionDisplay,BorderLayout.CENTER);
- binaryFractionDecoratedDisplay.add(new JLabel("fraction",JLabel.CENTER),BorderLayout.SOUTH);
-
- binaryPanel.add(binarySignDecoratedDisplay);
- binaryPanel.add(binaryExponentDecoratedDisplay);
- binaryPanel.add(binaryFractionDecoratedDisplay);
-
- //################ Grid Row : Binary ##################################
- leftPanel.add(binaryPanel);
-
- //################ Grid Row : Binary to decimal formula arrows ##########
- binaryToDecimalFormulaGraphic = new BinaryToDecimalFormulaGraphic();
- binaryToDecimalFormulaGraphic.setBackground(leftPanel.getBackground());
- leftPanel.add(binaryToDecimalFormulaGraphic);
-
- // Non-Editable display for expansion of binary representation
-
- expansionDisplay = new JLabel(new FlavorsOfFloat().expansionString);
- expansionDisplay.setFont(new Font("Monospaced",Font.PLAIN,12));
- expansionDisplay.setFocusable(false); // causes it to be skipped in "tab sequence".
- expansionDisplay.setBackground(leftPanel.getBackground());
- JPanel expansionDisplayBox = new JPanel(new GridLayout(2,1));
- expansionDisplayBox.add(expansionDisplay);
- expansionDisplayBox.add(significandLabel); // initialized at top
- //################ Grid Row : Formula mapping binary to decimal ########
- leftPanel.add(expansionDisplayBox);
-
- // Editable display for decimal version of float value.
- decimalDisplay = new JTextField(defaultDecimal, maxLengthDecimal+1);
- decimalDisplay.setFont(decimalDisplayFont);
- decimalDisplay.setForeground(decimalDisplayColor);
- decimalDisplay.setHorizontalAlignment(JTextField.RIGHT);
- decimalDisplay.setToolTipText("Decimal floating point value");
- decimalDisplay.setMargin(new Insets(0,0,0,0));
- decimalDisplay.setEditable(true);
- decimalDisplay.revalidate();
- decimalDisplay.addKeyListener(new DecimalDisplayKeystokeListenter());
- Box decimalDisplayBox = Box.createVerticalBox();
- decimalDisplayBox.add(Box.createVerticalStrut(5));
- decimalDisplayBox.add(decimalDisplay);
- decimalDisplayBox.add(Box.createVerticalStrut(15));
-
- FlowLayout rightPanelLayout = new FlowLayout(FlowLayout.LEFT);
- JPanel place1 = new JPanel(rightPanelLayout);
- JPanel place2 = new JPanel(rightPanelLayout);
- JPanel place3 = new JPanel(rightPanelLayout);
- JPanel place4 = new JPanel(rightPanelLayout);
-
- JEditorPane hexExplain = new JEditorPane("text/html",expansionFontTag+"< Hexadecimal representation"+"");
- hexExplain.setEditable(false);
- hexExplain.setFocusable(false);
- hexExplain.setForeground(Color.black);
- hexExplain.setBackground(place1.getBackground());
- JEditorPane hexToBinExplain = new JEditorPane("text/html",expansionFontTag+"< Each hex digit represents 4 bits"+"");
- hexToBinExplain.setEditable(false);
- hexToBinExplain.setFocusable(false);
- hexToBinExplain.setBackground(place2.getBackground());
- JEditorPane binExplain = new JEditorPane("text/html",expansionFontTag+"< Binary representation"+"");
- binExplain.setEditable(false);
- binExplain.setFocusable(false);
- binExplain.setBackground(place3.getBackground());
- JEditorPane binToDecExplain = new JEditorPane("text/html",expansionFontTag+"< Binary-to-decimal conversion"+"");
- binToDecExplain.setEditable(false);
- binToDecExplain.setFocusable(false);
- binToDecExplain.setBackground(place4.getBackground());
- place1.add(hexExplain);
- place2.add(hexToBinExplain);
- place3.add(binExplain);
- place4.add(binToDecExplain);
- //################ 4 Grid Rows : Explanations #########################
- rightPanel.add(place1);
- rightPanel.add(place2);
- rightPanel.add(place3);
- rightPanel.add(place4);
- //################ Grid Row : Decimal ##################################
- rightPanel.add(decimalDisplayBox);
-
- //######## mainPanel is vertical box, instructions get a row #################
- JPanel instructionsPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
- instructions = new InstructionsPane(instructionsPanel);
- instructionsPanel.add(instructions);
- instructionsPanel.setBorder(new TitledBorder("Instructions"));
- mainPanel.add(instructionsPanel);
-
- // Means of selecting and deselecting an attached floating point register
-
- fpRegisters = Coprocessor1.getRegisters();
- String[] registerList = new String[fpRegisters.length+1];
- registerList[0] = "None";
- for (int i=0; i");
+ hexExplain.setEditable(false);
+ hexExplain.setFocusable(false);
+ hexExplain.setForeground(Color.black);
+ hexExplain.setBackground(place1.getBackground());
+ JEditorPane hexToBinExplain = new JEditorPane("text/html", expansionFontTag + "< Each hex digit represents 4 bits" + "");
+ hexToBinExplain.setEditable(false);
+ hexToBinExplain.setFocusable(false);
+ hexToBinExplain.setBackground(place2.getBackground());
+ JEditorPane binExplain = new JEditorPane("text/html", expansionFontTag + "< Binary representation" + "");
+ binExplain.setEditable(false);
+ binExplain.setFocusable(false);
+ binExplain.setBackground(place3.getBackground());
+ JEditorPane binToDecExplain = new JEditorPane("text/html", expansionFontTag + "< Binary-to-decimal conversion" + "");
+ binToDecExplain.setEditable(false);
+ binToDecExplain.setFocusable(false);
+ binToDecExplain.setBackground(place4.getBackground());
+ place1.add(hexExplain);
+ place2.add(hexToBinExplain);
+ place3.add(binExplain);
+ place4.add(binToDecExplain);
+ //################ 4 Grid Rows : Explanations #########################
+ rightPanel.add(place1);
+ rightPanel.add(place2);
+ rightPanel.add(place3);
+ rightPanel.add(place4);
+ //################ Grid Row : Decimal ##################################
+ rightPanel.add(decimalDisplayBox);
+
+ //######## mainPanel is vertical box, instructions get a row #################
+ JPanel instructionsPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
+ instructions = new InstructionsPane(instructionsPanel);
+ instructionsPanel.add(instructions);
+ instructionsPanel.setBorder(new TitledBorder("Instructions"));
+ mainPanel.add(instructionsPanel);
+
+ // Means of selecting and deselecting an attached floating point register
+
+ fpRegisters = Coprocessor1.getRegisters();
+ String[] registerList = new String[fpRegisters.length + 1];
+ registerList[0] = "None";
+ for (int i = 0; i < fpRegisters.length; i++)
+ {
+ registerList[i + 1] = fpRegisters[i].getName();
+ }
+ JComboBox registerSelect = new JComboBox(registerList);
+ registerSelect.setSelectedIndex(0); // No register attached
+ registerSelect.setToolTipText("Attach to selected FP register");
+ registerSelect.addActionListener(
+ new ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ JComboBox cb = (JComboBox) e.getSource();
+ int selectedIndex = cb.getSelectedIndex();
+ if (isObserving())
+ {
deleteAsObserver();
- }
- if (selectedIndex==0) {
+ }
+ if (selectedIndex == 0)
+ {
attachedRegister = null;
updateDisplays(new FlavorsOfFloat());
instructions.setText("The program is not attached to any MIPS floating point registers.");
- }
- else {
- attachedRegister = fpRegisters[selectedIndex-1];
+ }
+ else
+ {
+ attachedRegister = fpRegisters[selectedIndex - 1];
updateDisplays(new FlavorsOfFloat().buildOneFromInt(attachedRegister.getValue()));
- if (isObserving()) {
- addAsObserver();
+ if (isObserving())
+ {
+ addAsObserver();
}
- instructions.setText("The program and register "+attachedRegister.getName()+" will respond to each other when MIPS program connected or running.");
- }
- }
- });
-
- JPanel registerPanel = new JPanel(new BorderLayout(5,5));
- JPanel registerAndLabel = new JPanel();
- registerAndLabel.add(new JLabel("MIPS floating point Register of interest: "));
- registerAndLabel.add(registerSelect);
- registerPanel.add(registerAndLabel,BorderLayout.WEST);
- registerPanel.add(new JLabel(" "),BorderLayout.NORTH); // just for padding
- mainPanel.add(registerPanel);
- return mainPanel;
- } // end of buildDisplayArea()
-
-
- // If display is attached to a register then update the register value.
- private synchronized void updateAnyAttachedRegister(int intValue) {
- if (attachedRegister != null) {
- synchronized (Globals.memoryAndRegistersLock) {
- attachedRegister.setValue(intValue);
+ instructions.setText("The program and register " + attachedRegister.getName() + " will respond to each other when MIPS program connected or running.");
+ }
+ }
+ });
+
+ JPanel registerPanel = new JPanel(new BorderLayout(5, 5));
+ JPanel registerAndLabel = new JPanel();
+ registerAndLabel.add(new JLabel("MIPS floating point Register of interest: "));
+ registerAndLabel.add(registerSelect);
+ registerPanel.add(registerAndLabel, BorderLayout.WEST);
+ registerPanel.add(new JLabel(" "), BorderLayout.NORTH); // just for padding
+ mainPanel.add(registerPanel);
+ return mainPanel;
+ } // end of buildDisplayArea()
+
+ // If display is attached to a register then update the register value.
+ private synchronized void updateAnyAttachedRegister(int intValue)
+ {
+ if (attachedRegister != null)
+ {
+ synchronized (Globals.memoryAndRegistersLock)
+ {
+ attachedRegister.setValue(intValue);
}
- // HERE'S A HACK!! Want to immediately display the updated register value in MARS
- // but that code was not written for event-driven update (e.g. Observer) --
- // it was written to poll the registers for their values. So we force it to do so.
- if (Globals.getGui() != null) {
- Globals.getGui().getRegistersPane().getCoprocessor1Window().updateRegisters();
+ // HERE'S A HACK!! Want to immediately display the updated register value in MARS
+ // but that code was not written for event-driven update (e.g. Observer) --
+ // it was written to poll the registers for their values. So we force it to do so.
+ if (Globals.getGui() != null)
+ {
+ Globals.getGui().getRegistersPane().getCoprocessor1Window().updateRegisters();
}
- }
- }
-
- // Updates all components displaying various representations of the 32 bit
- // floating point value.
- private void updateDisplays(FlavorsOfFloat flavors) {
- int hexIndex = (flavors.hexString.charAt(0)=='0' && (flavors.hexString.charAt(1)=='x'||flavors.hexString.charAt(1)=='X')) ? 2 : 0;
- hexDisplay.setText(flavors.hexString.substring(hexIndex).toUpperCase()); // lop off leading "Ox" if present
- binarySignDisplay.setText(flavors.binaryString.substring(0, maxLengthBinarySign));
- binaryExponentDisplay.setText(flavors.binaryString.substring(maxLengthBinarySign, maxLengthBinarySign+maxLengthBinaryExponent));
- binaryFractionDisplay.setText(flavors.binaryString.substring(maxLengthBinarySign+maxLengthBinaryExponent, maxLengthBinaryTotal));
- decimalDisplay.setText(flavors.decimalString);
- binaryToDecimalFormulaGraphic.drawSubtractLabel(Binary.binaryStringToInt((flavors.binaryString.substring(maxLengthBinarySign, maxLengthBinarySign+maxLengthBinaryExponent))));
- expansionDisplay.setText(flavors.expansionString);
- updateSignificandLabel(flavors);
- }
-
- // Should be called only by those who know a register should be changed due to
- // user action (reset button or Enter key on one of the input fields). Note
- // this will not update the register unless we are an active Observer.
- private void updateDisplaysAndRegister(FlavorsOfFloat flavors) {
- updateDisplays(flavors);
- if (isObserving()) {
+ }
+ }
+
+ // Updates all components displaying various representations of the 32 bit
+ // floating point value.
+ private void updateDisplays(FlavorsOfFloat flavors)
+ {
+ int hexIndex = (flavors.hexString.charAt(0) == '0' && (flavors.hexString.charAt(1) == 'x' || flavors.hexString.charAt(1) == 'X')) ? 2 : 0;
+ hexDisplay.setText(flavors.hexString.substring(hexIndex).toUpperCase()); // lop off leading "Ox" if present
+ binarySignDisplay.setText(flavors.binaryString.substring(0, maxLengthBinarySign));
+ binaryExponentDisplay.setText(flavors.binaryString.substring(maxLengthBinarySign, maxLengthBinarySign + maxLengthBinaryExponent));
+ binaryFractionDisplay.setText(flavors.binaryString.substring(maxLengthBinarySign + maxLengthBinaryExponent, maxLengthBinaryTotal));
+ decimalDisplay.setText(flavors.decimalString);
+ binaryToDecimalFormulaGraphic.drawSubtractLabel(Binary.binaryStringToInt((flavors.binaryString.substring(maxLengthBinarySign, maxLengthBinarySign + maxLengthBinaryExponent))));
+ expansionDisplay.setText(flavors.expansionString);
+ updateSignificandLabel(flavors);
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////
+ ///////
+ /////// THE REST OF THE TOOL CONSISTS OF LITTLE PRIVATE CLASSES THAT MAKE
+ /////// LIFE EASIER FOR THE ABOVE CODE.
+ ///////
+ ///////////////////////////////////////////////////////////////////////////////
+
+ // Should be called only by those who know a register should be changed due to
+ // user action (reset button or Enter key on one of the input fields). Note
+ // this will not update the register unless we are an active Observer.
+ private void updateDisplaysAndRegister(FlavorsOfFloat flavors)
+ {
+ updateDisplays(flavors);
+ if (isObserving())
+ {
updateAnyAttachedRegister(flavors.intValue);
- }
- }
-
- // Called by updateDisplays() to determine whether or not the significand label needs
- // to be changed and if so to change it. The label explains presence/absence of
- // normalizing "hidden bit".
- private void updateSignificandLabel(FlavorsOfFloat flavors) {
- // Will change significandLabel text only if it needs to be changed...
- if (flavors.binaryString.substring(maxLengthBinarySign, maxLengthBinarySign+maxLengthBinaryExponent)
- .equals(zeroes.substring(maxLengthBinarySign, maxLengthBinarySign+maxLengthBinaryExponent))) {
- // Will change text only if it truly is changing....
- if (significandLabel.getText().indexOf("deno")<0) {
- significandLabel.setText(denormalizedLabel);
+ }
+ }
+
+ // Called by updateDisplays() to determine whether or not the significand label needs
+ // to be changed and if so to change it. The label explains presence/absence of
+ // normalizing "hidden bit".
+ private void updateSignificandLabel(FlavorsOfFloat flavors)
+ {
+ // Will change significandLabel text only if it needs to be changed...
+ if (flavors.binaryString.substring(maxLengthBinarySign, maxLengthBinarySign + maxLengthBinaryExponent)
+ .equals(zeroes.substring(maxLengthBinarySign, maxLengthBinarySign + maxLengthBinaryExponent)))
+ {
+ // Will change text only if it truly is changing....
+ if (significandLabel.getText().indexOf("deno") < 0)
+ {
+ significandLabel.setText(denormalizedLabel);
}
- }
- else {
- if (significandLabel.getText().indexOf("unde")<0) {
- significandLabel.setText(normalizedLabel);
+ }
+ else
+ {
+ if (significandLabel.getText().indexOf("unde") < 0)
+ {
+ significandLabel.setText(normalizedLabel);
}
- }
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- ///////
- /////// THE REST OF THE TOOL CONSISTS OF LITTLE PRIVATE CLASSES THAT MAKE
- /////// LIFE EASIER FOR THE ABOVE CODE.
- ///////
- ///////////////////////////////////////////////////////////////////////////////
-
- ////////////////////////////////////////////////////////////////////////////
- //
- // Class of objects that encapsulats 5 different representations of a 32 bit
- // floating point value:
- // string with hexadecimal value.
- // String with binary value. 32 characters long.
- // String with decimal float value. variable length.
- // int with 32 bit representation of float value ("int bits").
- // String for display only, showing formula for expanding bits to decimal.
- //
- private class FlavorsOfFloat {
- String hexString;
- String binaryString;
- String decimalString;
- String expansionString;
- int intValue;
-
- // Default object
- private FlavorsOfFloat() {
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Class of objects that encapsulats 5 different representations of a 32 bit
+ // floating point value:
+ // string with hexadecimal value.
+ // String with binary value. 32 characters long.
+ // String with decimal float value. variable length.
+ // int with 32 bit representation of float value ("int bits").
+ // String for display only, showing formula for expanding bits to decimal.
+ //
+ private class FlavorsOfFloat
+ {
+ String hexString;
+
+ String binaryString;
+
+ String decimalString;
+
+ String expansionString;
+
+ int intValue;
+
+ // Default object
+ private FlavorsOfFloat()
+ {
hexString = defaultHex;
- decimalString = defaultDecimal;
- binaryString = defaultBinarySign+defaultBinaryExponent+defaultBinaryFraction;
+ decimalString = defaultDecimal;
+ binaryString = defaultBinarySign + defaultBinaryExponent + defaultBinaryFraction;
expansionString = buildExpansionFromBinaryString(binaryString);
intValue = Float.floatToIntBits(Float.parseFloat(decimalString));
- }
-
- // Assign all fields given a string representing 32 bit hex value.
- public FlavorsOfFloat buildOneFromHexString(String hexString) {
+ }
+
+ // Assign all fields given a string representing 32 bit hex value.
+ public FlavorsOfFloat buildOneFromHexString(String hexString)
+ {
this.hexString = "0x" + addLeadingZeroes(
- ((hexString.indexOf("0X")==0 || hexString.indexOf("0x")==0)
- ? hexString.substring(2) : hexString), maxLengthHex);
- this.binaryString = Binary.hexStringToBinaryString(this.hexString);
- this.decimalString = new Float(Float.intBitsToFloat(Binary.binaryStringToInt(this.binaryString))).toString();
+ ((hexString.indexOf("0X") == 0 || hexString.indexOf("0x") == 0)
+ ? hexString.substring(2) : hexString), maxLengthHex);
+ this.binaryString = Binary.hexStringToBinaryString(this.hexString);
+ this.decimalString = Float.toString(Float.intBitsToFloat(Binary.binaryStringToInt(this.binaryString)));
this.expansionString = buildExpansionFromBinaryString(this.binaryString);
this.intValue = Binary.binaryStringToInt(this.binaryString);
return this;
- }
-
- // Assign all fields given a string representing 32 bit binary value
- private FlavorsOfFloat buildOneFromBinaryString() {
+ }
+
+ // Assign all fields given a string representing 32 bit binary value
+ private FlavorsOfFloat buildOneFromBinaryString()
+ {
this.binaryString = getFullBinaryStringFromDisplays();
this.hexString = Binary.binaryStringToHexString(binaryString);
- this.decimalString = new Float(Float.intBitsToFloat(Binary.binaryStringToInt(this.binaryString))).toString();
+ this.decimalString = Float.toString(Float.intBitsToFloat(Binary.binaryStringToInt(this.binaryString)));
this.expansionString = buildExpansionFromBinaryString(this.binaryString);
this.intValue = Binary.binaryStringToInt(this.binaryString);
return this;
- }
-
- // Assign all fields given string representing floating point decimal value.
- private FlavorsOfFloat buildOneFromDecimalString(String decimalString) {
+ }
+
+ // Assign all fields given string representing floating point decimal value.
+ private FlavorsOfFloat buildOneFromDecimalString(String decimalString)
+ {
float floatValue;
- try {
- floatValue = Float.parseFloat(decimalString);
- }
- catch (NumberFormatException nfe) {
- return null;
- }
- this.decimalString = new Float(floatValue).toString();
+ try
+ {
+ floatValue = Float.parseFloat(decimalString);
+ }
+ catch (NumberFormatException nfe)
+ {
+ return null;
+ }
+ this.decimalString = Float.toString(floatValue);
this.intValue = Float.floatToIntBits(floatValue);// use floatToRawIntBits?
this.binaryString = Binary.intToBinaryString(this.intValue);
this.hexString = Binary.binaryStringToHexString(this.binaryString);
this.expansionString = buildExpansionFromBinaryString(this.binaryString);
return this;
- }
-
- // Assign all fields given int representing 32 bit representation of float value
- private FlavorsOfFloat buildOneFromInt(int intValue) {
+ }
+
+ // Assign all fields given int representing 32 bit representation of float value
+ private FlavorsOfFloat buildOneFromInt(int intValue)
+ {
this.intValue = intValue;
this.binaryString = Binary.intToBinaryString(intValue);
this.hexString = Binary.binaryStringToHexString(this.binaryString);
- this.decimalString = new Float(Float.intBitsToFloat(Binary.binaryStringToInt(this.binaryString))).toString();
+ this.decimalString = Float.toString(Float.intBitsToFloat(Binary.binaryStringToInt(this.binaryString)));
this.expansionString = buildExpansionFromBinaryString(this.binaryString);
return this;
- }
-
- // Build binary expansion formula for display -- will not be editable.
- public String buildExpansionFromBinaryString(String binaryString) {
+ }
+
+ // Build binary expansion formula for display -- will not be editable.
+ public String buildExpansionFromBinaryString(String binaryString)
+ {
int biasedExponent = Binary.binaryStringToInt(
- binaryString.substring(maxLengthBinarySign,maxLengthBinarySign+maxLengthBinaryExponent));
- String stringExponent = Integer.toString(biasedExponent - exponentBias);
- // stringExponent length will range from 1 to 4 (e.g. "0" to "-128") characters.
- // Right-pad with HTML spaces (" ") to total length 5 displayed characters.
- return ""+expansionFontTag
- + "-1"+binaryString.substring(0,maxLengthBinarySign)+" * 2"
- + stringExponent + HTMLspaces.substring(0, (5-stringExponent.length())*6)
- + " * "
- + ((biasedExponent==0) ? " ." : "1.")
- + binaryString.substring(maxLengthBinarySign+maxLengthBinaryExponent, maxLengthBinaryTotal)
- + " =";
- }
-
- // Handy utility to concatentate the binary field values into one 32 character string
- // Left-pad each field with zeroes as needed to reach its full length.
- private String getFullBinaryStringFromDisplays() {
+ binaryString.substring(maxLengthBinarySign, maxLengthBinarySign + maxLengthBinaryExponent));
+ String stringExponent = Integer.toString(biasedExponent - exponentBias);
+ // stringExponent length will range from 1 to 4 (e.g. "0" to "-128") characters.
+ // Right-pad with HTML spaces (" ") to total length 5 displayed characters.
+ return "" + expansionFontTag
+ + "-1" + binaryString.charAt(0) + " * 2"
+ + stringExponent + HTMLspaces.substring(0, (5 - stringExponent.length()) * 6)
+ + " * "
+ + ((biasedExponent == 0) ? " ." : "1.")
+ + binaryString.substring(maxLengthBinarySign + maxLengthBinaryExponent, maxLengthBinaryTotal)
+ + " =";
+ }
+
+ // Handy utility to concatentate the binary field values into one 32 character string
+ // Left-pad each field with zeroes as needed to reach its full length.
+ private String getFullBinaryStringFromDisplays()
+ {
return addLeadingZeroes(binarySignDisplay.getText(), maxLengthBinarySign) +
addLeadingZeroes(binaryExponentDisplay.getText(), maxLengthBinaryExponent) +
addLeadingZeroes(binaryFractionDisplay.getText(), maxLengthBinaryFraction);
- }
-
- // Handy utility. Pads with leading zeroes to specified length, maximum 64 of 'em.
- private String addLeadingZeroes(String str, int length) {
- return (str.length() < length)
- ? zeroes.substring(0,Math.min(zeroes.length(),length-str.length()))+str
- : str;
- }
-
- }
- //Put here because inner class cannot have static members.
- private static final String zeroes =
- "0000000000000000000000000000000000000000000000000000000000000000"; //64
- private static final String HTMLspaces = " ";
-
-
- // NOTE: It would be nice to use InputVerifier class to verify user input
- // but I want keystroke-level monitoring to assure that no invalid
- // keystrokes are echoed and that maximum string length is not exceeded.
-
-
-
-
- //////////////////////////////////////////////////////////////////
- //
- // Class to handle input keystrokes for hexadecimal field
- //
- private class HexDisplayKeystrokeListener extends KeyAdapter {
-
- private int digitLength; // maximum number of digits long
-
- public HexDisplayKeystrokeListener(int length) {
+ }
+
+ // Handy utility. Pads with leading zeroes to specified length, maximum 64 of 'em.
+ private String addLeadingZeroes(String str, int length)
+ {
+ return (str.length() < length)
+ ? zeroes.substring(0, Math.min(zeroes.length(), length - str.length())) + str
+ : str;
+ }
+
+ }
+
+
+ // NOTE: It would be nice to use InputVerifier class to verify user input
+ // but I want keystroke-level monitoring to assure that no invalid
+ // keystrokes are echoed and that maximum string length is not exceeded.
+
+ //////////////////////////////////////////////////////////////////
+ //
+ // Class to handle input keystrokes for hexadecimal field
+ //
+ private class HexDisplayKeystrokeListener extends KeyAdapter
+ {
+
+ private final int digitLength; // maximum number of digits long
+
+ public HexDisplayKeystrokeListener(int length)
+ {
digitLength = length;
- }
-
-
- // Process user keystroke. If not valid for the context, this
- // will consume the stroke and beep.
- public void keyTyped(KeyEvent e) {
+ }
+
+
+ // Process user keystroke. If not valid for the context, this
+ // will consume the stroke and beep.
+ public void keyTyped(KeyEvent e)
+ {
JTextField source = (JTextField) e.getComponent();
- if (e.getKeyChar()== KeyEvent.VK_BACK_SPACE || e.getKeyChar()== KeyEvent.VK_TAB )
- return;
- if (!isHexDigit(e.getKeyChar()) ||
- source.getText().length()==digitLength && source.getSelectedText()==null) {
- if (e.getKeyChar()!= KeyEvent.VK_ENTER && e.getKeyChar() != KeyEvent.VK_TAB) {
- Toolkit.getDefaultToolkit().beep();
- if (source.getText().length()==digitLength && source.getSelectedText()==null) {
- instructions.setText("Maximum length of this field is "+digitLength+".");
- }
- else {
- instructions.setText("Only digits and A-F (or a-f) are accepted in hexadecimal field.");
- }
- }
- e.consume();
- }
- }
-
- // Enter key is echoed on component after keyPressed but before keyTyped?
- // Consuming the VK_ENTER event in keyTyped does not suppress it but this will.
- public void keyPressed(KeyEvent e) {
- if (e.getKeyChar()== KeyEvent.VK_ENTER || e.getKeyChar()== KeyEvent.VK_TAB) {
- updateDisplaysAndRegister(new FlavorsOfFloat().buildOneFromHexString(((JTextField)e.getSource()).getText()));
- instructions.setText(defaultInstructions);
- e.consume();
+ if (e.getKeyChar() == KeyEvent.VK_BACK_SPACE || e.getKeyChar() == KeyEvent.VK_TAB)
+ {
+ return;
}
- }
-
- // handy utility.
- private boolean isHexDigit(char digit) {
+ if (!isHexDigit(e.getKeyChar()) ||
+ source.getText().length() == digitLength && source.getSelectedText() == null)
+ {
+ if (e.getKeyChar() != KeyEvent.VK_ENTER && e.getKeyChar() != KeyEvent.VK_TAB)
+ {
+ Toolkit.getDefaultToolkit().beep();
+ if (source.getText().length() == digitLength && source.getSelectedText() == null)
+ {
+ instructions.setText("Maximum length of this field is " + digitLength + ".");
+ }
+ else
+ {
+ instructions.setText("Only digits and A-F (or a-f) are accepted in hexadecimal field.");
+ }
+ }
+ e.consume();
+ }
+ }
+
+ // Enter key is echoed on component after keyPressed but before keyTyped?
+ // Consuming the VK_ENTER event in keyTyped does not suppress it but this will.
+ public void keyPressed(KeyEvent e)
+ {
+ if (e.getKeyChar() == KeyEvent.VK_ENTER || e.getKeyChar() == KeyEvent.VK_TAB)
+ {
+ updateDisplaysAndRegister(new FlavorsOfFloat().buildOneFromHexString(((JTextField) e.getSource()).getText()));
+ instructions.setText(defaultInstructions);
+ e.consume();
+ }
+ }
+
+ // handy utility.
+ private boolean isHexDigit(char digit)
+ {
boolean result = false;
- switch (digit) {
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
- case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
- result = true;
+ switch (digit)
+ {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ case 'a':
+ case 'b':
+ case 'c':
+ case 'd':
+ case 'e':
+ case 'f':
+ case 'A':
+ case 'B':
+ case 'C':
+ case 'D':
+ case 'E':
+ case 'F':
+ result = true;
}
- return result;
- }
- }
-
- //////////////////////////////////////////////////////////////////
- //
- // Class to handle input keystrokes for binary field
- //
- private class BinaryDisplayKeystrokeListener extends KeyAdapter {
-
- private int bitLength; // maximum number of bits permitted
-
- public BinaryDisplayKeystrokeListener(int length) {
+ return result;
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////
+ //
+ // Class to handle input keystrokes for binary field
+ //
+ private class BinaryDisplayKeystrokeListener extends KeyAdapter
+ {
+
+ private final int bitLength; // maximum number of bits permitted
+
+ public BinaryDisplayKeystrokeListener(int length)
+ {
bitLength = length;
- }
-
- // Process user keystroke. If not valid for the context, this
- // will consume the stroke and beep.
- public void keyTyped(KeyEvent e) {
+ }
+
+ // Process user keystroke. If not valid for the context, this
+ // will consume the stroke and beep.
+ public void keyTyped(KeyEvent e)
+ {
JTextField source = (JTextField) e.getComponent();
- if (e.getKeyChar()== KeyEvent.VK_BACK_SPACE)
- return;
+ if (e.getKeyChar() == KeyEvent.VK_BACK_SPACE)
+ {
+ return;
+ }
if (!isBinaryDigit(e.getKeyChar()) ||
- e.getKeyChar() == KeyEvent.VK_ENTER ||
- source.getText().length()==bitLength && source.getSelectedText()==null) {
- if (e.getKeyChar()!= KeyEvent.VK_ENTER) {
- Toolkit.getDefaultToolkit().beep();
- if (source.getText().length()==bitLength && source.getSelectedText()==null) {
- instructions.setText("Maximum length of this field is "+bitLength+".");
- }
- else {
- instructions.setText("Only 0 and 1 are accepted in binary field.");
- }
- }
- e.consume();
- }
- }
-
- // Enter key is echoed on component after keyPressed but before keyTyped?
- // Consuming the VK_ENTER event in keyTyped does not suppress it but this will.
- public void keyPressed(KeyEvent e) {
- if (e.getKeyChar()== KeyEvent.VK_ENTER) {
- updateDisplaysAndRegister(new FlavorsOfFloat().buildOneFromBinaryString());
- instructions.setText(defaultInstructions);
- e.consume();
+ e.getKeyChar() == KeyEvent.VK_ENTER ||
+ source.getText().length() == bitLength && source.getSelectedText() == null)
+ {
+ if (e.getKeyChar() != KeyEvent.VK_ENTER)
+ {
+ Toolkit.getDefaultToolkit().beep();
+ if (source.getText().length() == bitLength && source.getSelectedText() == null)
+ {
+ instructions.setText("Maximum length of this field is " + bitLength + ".");
+ }
+ else
+ {
+ instructions.setText("Only 0 and 1 are accepted in binary field.");
+ }
+ }
+ e.consume();
}
- }
-
- // handy utility
- private boolean isBinaryDigit(char digit) {
+ }
+
+ // Enter key is echoed on component after keyPressed but before keyTyped?
+ // Consuming the VK_ENTER event in keyTyped does not suppress it but this will.
+ public void keyPressed(KeyEvent e)
+ {
+ if (e.getKeyChar() == KeyEvent.VK_ENTER)
+ {
+ updateDisplaysAndRegister(new FlavorsOfFloat().buildOneFromBinaryString());
+ instructions.setText(defaultInstructions);
+ e.consume();
+ }
+ }
+
+ // handy utility
+ private boolean isBinaryDigit(char digit)
+ {
boolean result = false;
- switch (digit) {
- case '0': case '1':
- result = true;
+ switch (digit)
+ {
+ case '0':
+ case '1':
+ result = true;
}
- return result;
- }
-
- }
-
-
- //////////////////////////////////////////////////////////////////
- //
- // Class to handle input keystrokes for decimal field
- //
- private class DecimalDisplayKeystokeListenter extends KeyAdapter {
-
- // Process user keystroke. If not valid for the context, this
- // will consume the stroke and beep.
- public void keyTyped(KeyEvent e) {
+ return result;
+ }
+
+ }
+
+
+ //////////////////////////////////////////////////////////////////
+ //
+ // Class to handle input keystrokes for decimal field
+ //
+ private class DecimalDisplayKeystokeListenter extends KeyAdapter
+ {
+
+ // Process user keystroke. If not valid for the context, this
+ // will consume the stroke and beep.
+ public void keyTyped(KeyEvent e)
+ {
JTextField source = (JTextField) e.getComponent();
- if (e.getKeyChar()== KeyEvent.VK_BACK_SPACE)
- return;
- if (!isDecimalFloatDigit(e.getKeyChar())) {
- if (e.getKeyChar()!= KeyEvent.VK_ENTER) {
- instructions.setText("Only digits, period, signs and E (or e) are accepted in decimal field.");
- Toolkit.getDefaultToolkit().beep();
- }
- e.consume();
- }
- }
-
- // Enter key is echoed on component after keyPressed but before keyTyped?
- // Consuming the VK_ENTER event in keyTyped does not suppress it but this will.
- public void keyPressed(KeyEvent e) {
- if (e.getKeyChar()== KeyEvent.VK_ENTER) {
- FlavorsOfFloat fof = new FlavorsOfFloat().buildOneFromDecimalString(((JTextField)e.getSource()).getText());
- if (fof==null) {
- Toolkit.getDefaultToolkit().beep();
- instructions.setText("'"+((JTextField)e.getSource()).getText()+"' is not a valid floating point number.");
- }
- else {
- updateDisplaysAndRegister(fof);
- instructions.setText(defaultInstructions);
- }
- e.consume();
+ if (e.getKeyChar() == KeyEvent.VK_BACK_SPACE)
+ {
+ return;
}
- }
-
- // handy utility
- private boolean isDecimalFloatDigit(char digit) {
+ if (!isDecimalFloatDigit(e.getKeyChar()))
+ {
+ if (e.getKeyChar() != KeyEvent.VK_ENTER)
+ {
+ instructions.setText("Only digits, period, signs and E (or e) are accepted in decimal field.");
+ Toolkit.getDefaultToolkit().beep();
+ }
+ e.consume();
+ }
+ }
+
+ // Enter key is echoed on component after keyPressed but before keyTyped?
+ // Consuming the VK_ENTER event in keyTyped does not suppress it but this will.
+ public void keyPressed(KeyEvent e)
+ {
+ if (e.getKeyChar() == KeyEvent.VK_ENTER)
+ {
+ FlavorsOfFloat fof = new FlavorsOfFloat().buildOneFromDecimalString(((JTextField) e.getSource()).getText());
+ if (fof == null)
+ {
+ Toolkit.getDefaultToolkit().beep();
+ instructions.setText("'" + ((JTextField) e.getSource()).getText() + "' is not a valid floating point number.");
+ }
+ else
+ {
+ updateDisplaysAndRegister(fof);
+ instructions.setText(defaultInstructions);
+ }
+ e.consume();
+ }
+ }
+
+ // handy utility
+ private boolean isDecimalFloatDigit(char digit)
+ {
boolean result = false;
- switch (digit) {
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- case '-': case '+': case '.': case 'e': case 'E':
- result = true;
+ switch (digit)
+ {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ case '-':
+ case '+':
+ case '.':
+ case 'e':
+ case 'E':
+ result = true;
}
- return result;
- }
-
- }
-
- ////////////////////////////////////////////////////////////////////////////
- //
- // Use this to draw graphics visually relating the hexadecimal values
- // displayed above) to the binary values (displayed below).
- //
- class HexToBinaryGraphicPanel extends JPanel {
-
+ return result;
+ }
+
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Use this to draw graphics visually relating the hexadecimal values
+ // displayed above) to the binary values (displayed below).
+ //
+ class HexToBinaryGraphicPanel extends JPanel
+ {
+
// This overrides inherited JPanel method. Override is necessary to
// assure my drawn graphics get painted immediately after painting the
// underlying JPanel (see first statement).
- public void paintComponent(Graphics g) {
+ public void paintComponent(Graphics g)
+ {
super.paintComponent(g);
- g.setColor(Color.red);
+ g.setColor(Color.red);
//FontMetrics fontMetrics = hexDisplay.getGraphics().getFontMetrics();
int upperY = 0;
int lowerY = 60;
- int hexColumnWidth = hexDisplay.getWidth()/hexDisplay.getColumns();
- // assume all 3 binary displays use same geometry, so column width same for all.
- int binaryColumnWidth = binaryFractionDisplay.getWidth()/binaryFractionDisplay.getColumns();
+ int hexColumnWidth = hexDisplay.getWidth() / hexDisplay.getColumns();
+ // assume all 3 binary displays use same geometry, so column width same for all.
+ int binaryColumnWidth = binaryFractionDisplay.getWidth() / binaryFractionDisplay.getColumns();
Polygon p;
// loop will handle the lower order 5 "nibbles" (hex digits)
- for (int i=1; i<6; i++) {
- p = new Polygon();
- p.addPoint(hexDisplay.getX()+hexColumnWidth*(hexDisplay.getColumns()-i)+hexColumnWidth/2, upperY);
- p.addPoint(binaryFractionDecoratedDisplay.getX()+binaryColumnWidth*(binaryFractionDisplay.getColumns()-((i*5)-i)), lowerY);
- p.addPoint(binaryFractionDecoratedDisplay.getX()+binaryColumnWidth*(binaryFractionDisplay.getColumns()-(((i*5)-i)-4)), lowerY);
- g.fillPolygon(p);
+ for (int i = 1; i < 6; i++)
+ {
+ p = new Polygon();
+ p.addPoint(hexDisplay.getX() + hexColumnWidth * (hexDisplay.getColumns() - i) + hexColumnWidth / 2, upperY);
+ p.addPoint(binaryFractionDecoratedDisplay.getX() + binaryColumnWidth * (binaryFractionDisplay.getColumns() - ((i * 5) - i)), lowerY);
+ p.addPoint(binaryFractionDecoratedDisplay.getX() + binaryColumnWidth * (binaryFractionDisplay.getColumns() - (((i * 5) - i) - 4)), lowerY);
+ g.fillPolygon(p);
}
// Nibble 5 straddles binary display of exponent and fraction.
p = new Polygon();
- p.addPoint(hexDisplay.getX()+hexColumnWidth*(hexDisplay.getColumns()-6)+hexColumnWidth/2, upperY);
- p.addPoint(binaryFractionDecoratedDisplay.getX()+binaryColumnWidth*(binaryFractionDisplay.getColumns()-20), lowerY);
- p.addPoint(binaryExponentDecoratedDisplay.getX()+binaryColumnWidth*(binaryExponentDisplay.getColumns()-1), lowerY);
+ p.addPoint(hexDisplay.getX() + hexColumnWidth * (hexDisplay.getColumns() - 6) + hexColumnWidth / 2, upperY);
+ p.addPoint(binaryFractionDecoratedDisplay.getX() + binaryColumnWidth * (binaryFractionDisplay.getColumns() - 20), lowerY);
+ p.addPoint(binaryExponentDecoratedDisplay.getX() + binaryColumnWidth * (binaryExponentDisplay.getColumns() - 1), lowerY);
g.fillPolygon(p);
- // Nibble 6 maps to binary display of exponent.
+ // Nibble 6 maps to binary display of exponent.
p = new Polygon();
- p.addPoint(hexDisplay.getX()+hexColumnWidth*(hexDisplay.getColumns()-7)+hexColumnWidth/2, upperY);
- p.addPoint(binaryExponentDecoratedDisplay.getX()+binaryColumnWidth*(binaryExponentDisplay.getColumns()-1), lowerY);
- p.addPoint(binaryExponentDecoratedDisplay.getX()+binaryColumnWidth*(binaryExponentDisplay.getColumns()-5), lowerY);
+ p.addPoint(hexDisplay.getX() + hexColumnWidth * (hexDisplay.getColumns() - 7) + hexColumnWidth / 2, upperY);
+ p.addPoint(binaryExponentDecoratedDisplay.getX() + binaryColumnWidth * (binaryExponentDisplay.getColumns() - 1), lowerY);
+ p.addPoint(binaryExponentDecoratedDisplay.getX() + binaryColumnWidth * (binaryExponentDisplay.getColumns() - 5), lowerY);
g.fillPolygon(p);
- // Nibble 7 straddles binary display of sign and exponent.
+ // Nibble 7 straddles binary display of sign and exponent.
p = new Polygon();
- p.addPoint(hexDisplay.getX()+hexColumnWidth*(hexDisplay.getColumns()-8)+hexColumnWidth/2, upperY);
- p.addPoint(binaryExponentDecoratedDisplay.getX()+binaryColumnWidth*(binaryExponentDisplay.getColumns()-5), lowerY);
+ p.addPoint(hexDisplay.getX() + hexColumnWidth * (hexDisplay.getColumns() - 8) + hexColumnWidth / 2, upperY);
+ p.addPoint(binaryExponentDecoratedDisplay.getX() + binaryColumnWidth * (binaryExponentDisplay.getColumns() - 5), lowerY);
p.addPoint(binarySignDecoratedDisplay.getX(), lowerY);
g.fillPolygon(p);
- }
-
- }
-
- //////////////////////////////////////////////////////////////////////
- //
- // Panel to hold arrows explaining transformation of binary represntation
- // into formula for calculating decimal value.
- //
- class BinaryToDecimalFormulaGraphic extends JPanel {
- final String subtractLabelTrailer = " - 127";
- final int arrowHeadOffset = 5;
- final int lowerY = 0;
- final int upperY = 50;
- int centerX, exponentCenterX;
- int subtractLabelWidth, subtractLabelHeight;
- int centerY = (upperY-lowerY)/2;
- int upperYArrowHead = upperY-arrowHeadOffset;
- int currentExponent = Binary.binaryStringToInt(defaultBinaryExponent);
- public void paintComponent(Graphics g) {
- super.paintComponent(g);
- // Arrow down from binary sign field
- centerX = binarySignDecoratedDisplay.getX()+binarySignDecoratedDisplay.getWidth()/2;
- g.drawLine(centerX,lowerY,centerX,upperY);
- g.drawLine(centerX-arrowHeadOffset,upperYArrowHead,centerX,upperY);
- g.drawLine(centerX+arrowHeadOffset,upperYArrowHead,centerX,upperY);
- // Arrow down from binary exponent field
- centerX = binaryExponentDecoratedDisplay.getX()+binaryExponentDecoratedDisplay.getWidth()/2;
- g.drawLine(centerX,lowerY,centerX,upperY);
- g.drawLine(centerX-arrowHeadOffset,upperYArrowHead,centerX,upperY);
- g.drawLine(centerX+arrowHeadOffset,upperYArrowHead,centerX,upperY);
- // Label on exponent arrow. The two assignments serve to initialize two
- // instance variables that are used by drawSubtractLabel(). They are
- // initialized here because they cannot be initialized sooner AND because
- // the drawSubtractLabel() method will later be called by updateDisplays(),
- // an outsider which has no other access to that information. Once set they
- // do not change so it does no harm that they are "re-initialized" each time
- // this method is called (which occurs only upon startup and when this portion
- // of the GUI needs to be repainted).
- exponentCenterX = centerX;
+ }
+
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ //
+ // Panel to hold arrows explaining transformation of binary represntation
+ // into formula for calculating decimal value.
+ //
+ class BinaryToDecimalFormulaGraphic extends JPanel
+ {
+ final String subtractLabelTrailer = " - 127";
+
+ final int arrowHeadOffset = 5;
+
+ final int lowerY = 0;
+
+ final int upperY = 50;
+
+ int centerX, exponentCenterX;
+
+ int subtractLabelWidth, subtractLabelHeight;
+
+ int centerY = (upperY - lowerY) / 2;
+
+ int upperYArrowHead = upperY - arrowHeadOffset;
+
+ int currentExponent = Binary.binaryStringToInt(defaultBinaryExponent);
+
+ public void paintComponent(Graphics g)
+ {
+ super.paintComponent(g);
+ // Arrow down from binary sign field
+ centerX = binarySignDecoratedDisplay.getX() + binarySignDecoratedDisplay.getWidth() / 2;
+ g.drawLine(centerX, lowerY, centerX, upperY);
+ g.drawLine(centerX - arrowHeadOffset, upperYArrowHead, centerX, upperY);
+ g.drawLine(centerX + arrowHeadOffset, upperYArrowHead, centerX, upperY);
+ // Arrow down from binary exponent field
+ centerX = binaryExponentDecoratedDisplay.getX() + binaryExponentDecoratedDisplay.getWidth() / 2;
+ g.drawLine(centerX, lowerY, centerX, upperY);
+ g.drawLine(centerX - arrowHeadOffset, upperYArrowHead, centerX, upperY);
+ g.drawLine(centerX + arrowHeadOffset, upperYArrowHead, centerX, upperY);
+ // Label on exponent arrow. The two assignments serve to initialize two
+ // instance variables that are used by drawSubtractLabel(). They are
+ // initialized here because they cannot be initialized sooner AND because
+ // the drawSubtractLabel() method will later be called by updateDisplays(),
+ // an outsider which has no other access to that information. Once set they
+ // do not change so it does no harm that they are "re-initialized" each time
+ // this method is called (which occurs only upon startup and when this portion
+ // of the GUI needs to be repainted).
+ exponentCenterX = centerX;
subtractLabelHeight = g.getFontMetrics().getHeight();
drawSubtractLabel(g, buildSubtractLabel(currentExponent));
- // Arrow down from binary fraction field
- centerX = binaryFractionDecoratedDisplay.getX()+binaryFractionDecoratedDisplay.getWidth()/2;
- g.drawLine(centerX,lowerY,centerX,upperY);
- g.drawLine(centerX-arrowHeadOffset,upperYArrowHead,centerX,upperY);
- g.drawLine(centerX+arrowHeadOffset,upperYArrowHead,centerX,upperY);
- }
-
- // To be used only by "outsiders" to update the display of the exponent and bias.
- public void drawSubtractLabel(int exponent) {
- if (exponent != currentExponent) { // no need to redraw if it hasn't changed...
- currentExponent = exponent;
- drawSubtractLabel(getGraphics(), buildSubtractLabel(exponent));
+ // Arrow down from binary fraction field
+ centerX = binaryFractionDecoratedDisplay.getX() + binaryFractionDecoratedDisplay.getWidth() / 2;
+ g.drawLine(centerX, lowerY, centerX, upperY);
+ g.drawLine(centerX - arrowHeadOffset, upperYArrowHead, centerX, upperY);
+ g.drawLine(centerX + arrowHeadOffset, upperYArrowHead, centerX, upperY);
+ }
+
+ // To be used only by "outsiders" to update the display of the exponent and bias.
+ public void drawSubtractLabel(int exponent)
+ {
+ if (exponent != currentExponent)
+ { // no need to redraw if it hasn't changed...
+ currentExponent = exponent;
+ drawSubtractLabel(getGraphics(), buildSubtractLabel(exponent));
}
- }
-
+ }
+
// Is called by both drawSubtractLabel() just above and by paintComponent().
- private void drawSubtractLabel(Graphics g, String label) {
+ private void drawSubtractLabel(Graphics g, String label)
+ {
// Clear the existing subtract label. The "+2" overwrites the arrow at initial paint when label width is 0.
- // Originally used "clearRect()" but changed to "fillRect()" with background color, because when running
- // as a MarsTool it would clear with a different color.
+ // Originally used "clearRect()" but changed to "fillRect()" with background color, because when running
+ // as a MarsTool it would clear with a different color.
Color saved = g.getColor();
g.setColor(binaryToDecimalFormulaGraphic.getBackground());
- g.fillRect(exponentCenterX-subtractLabelWidth/2,centerY-subtractLabelHeight/2,subtractLabelWidth+2,subtractLabelHeight);
+ g.fillRect(exponentCenterX - subtractLabelWidth / 2, centerY - subtractLabelHeight / 2, subtractLabelWidth + 2, subtractLabelHeight);
g.setColor(saved);
subtractLabelWidth = g.getFontMetrics().stringWidth(label);
- g.drawString(label,exponentCenterX-subtractLabelWidth/2,centerY+subtractLabelHeight/2-3); // -3 makes it more visually appealing
- }
-
- // format the label for a given integer exponent value...
- private String buildSubtractLabel(int value) {
- return Integer.toString(value) + subtractLabelTrailer;
- }
-
- }
-
-
- /////////////////////////////////////////////////////////////////////////
- //
- // Handly little class defined only to allow client to use "setText()" without
- // needing to know how/whether the text needs to be formatted. This one is
- // used to display instructions.
-
- class InstructionsPane extends JLabel {
-
- InstructionsPane(Component parent) {
+ g.drawString(label, exponentCenterX - subtractLabelWidth / 2, centerY + subtractLabelHeight / 2 - 3); // -3 makes it more visually appealing
+ }
+
+ // format the label for a given integer exponent value...
+ private String buildSubtractLabel(int value)
+ {
+ return value + subtractLabelTrailer;
+ }
+
+ }
+
+
+ /////////////////////////////////////////////////////////////////////////
+ //
+ // Handly little class defined only to allow client to use "setText()" without
+ // needing to know how/whether the text needs to be formatted. This one is
+ // used to display instructions.
+
+ class InstructionsPane extends JLabel
+ {
+
+ InstructionsPane(Component parent)
+ {
super(defaultInstructions);
this.setFont(instructionsFont);
this.setBackground(parent.getBackground());
- }
-
- public void setText(String text) {
+ }
+
+ public void setText(String text)
+ {
super.setText(text);
- }
- }
-
-
- ////////////////////////////////////////////////////////////////////////////
- //
- // Use this to draw custom background in the binary fraction display.
- //
- class BinaryFractionDisplayTextField extends JTextField {
-
- public BinaryFractionDisplayTextField(String value, int columns) {
- super(value,columns);
- }
-
+ }
+ }
+
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Use this to draw custom background in the binary fraction display.
+ //
+ class BinaryFractionDisplayTextField extends JTextField
+ {
+
+ public BinaryFractionDisplayTextField(String value, int columns)
+ {
+ super(value, columns);
+ }
+
// This overrides inherited JPanel method. Override is necessary to
// assure my drawn graphics get painted immediately after painting the
// underlying JPanel (see first statement).
- public void paintComponent(Graphics g) {
- super.paintComponent(g);
- // The code below is commented out because I decided to abandon
- // my effort to provide "striped" background that alternates colors
- // for every 4 characters (bits) of the display. This would make
- // the correspondence between bits and hex digits very clear.
- // NOTE: this is the only reason for subclassing JTextField.
+ public void paintComponent(Graphics g)
+ {
+ super.paintComponent(g);
+ // The code below is commented out because I decided to abandon
+ // my effort to provide "striped" background that alternates colors
+ // for every 4 characters (bits) of the display. This would make
+ // the correspondence between bits and hex digits very clear.
+ // NOTE: this is the only reason for subclassing JTextField.
/*
int columnWidth = getWidth()/getColumns();
@@ -943,7 +1112,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
p.addPoint(binarySignDisplay.getX(), lowerY);
g.fillPolygon(p);
*/
- }
- }
-
- }
\ No newline at end of file
+ }
+ }
+
+}
diff --git a/src/main/java/mars/tools/FunctionUnitVisualization.java b/src/main/java/mars/tools/FunctionUnitVisualization.java
index 377cf89..a5a6687 100644
--- a/src/main/java/mars/tools/FunctionUnitVisualization.java
+++ b/src/main/java/mars/tools/FunctionUnitVisualization.java
@@ -1,66 +1,79 @@
package mars.tools;
-import java.awt.BorderLayout;
-import java.awt.EventQueue;
-
-import javax.swing.JFrame;
-import javax.swing.JPanel;
+import javax.swing.*;
import javax.swing.border.EmptyBorder;
+import java.awt.*;
-public class FunctionUnitVisualization extends JFrame {
+public class FunctionUnitVisualization extends JFrame
+{
- private JPanel contentPane;
- private String instruction;
- private int register = 1;
- private int control = 2;
- private int aluControl = 3;
- private int alu = 4;
- private int currentUnit;
+ private final JPanel contentPane;
- /**
- * Launch the application.
- */
+ private final String instruction;
+
+ private final int register = 1;
+
+ private final int control = 2;
+
+ private final int aluControl = 3;
+
+ private final int alu = 4;
+
+ private int currentUnit;
+
+ /**
+ * Launch the application.
+ */
- /**
- * Create the frame.
- */
- public FunctionUnitVisualization(String instruction, int functionalUnit) {
- this.instruction = instruction;
- //setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
- setBounds(100, 100, 840, 575);
- contentPane = new JPanel();
- contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
- contentPane.setLayout(new BorderLayout(0, 0));
- setContentPane(contentPane);
- if(functionalUnit == register){
- currentUnit = register;
- UnitAnimation reg = new UnitAnimation(instruction, register);
- contentPane.add(reg);
- reg.startAnimation(instruction);
- }
- else if(functionalUnit == control){
- currentUnit = control;
- UnitAnimation reg = new UnitAnimation(instruction, control);
- contentPane.add(reg);
- reg.startAnimation(instruction);
- }
-
- else if(functionalUnit == aluControl){
- currentUnit = aluControl;
- UnitAnimation reg = new UnitAnimation(instruction, aluControl);
- contentPane.add(reg);
- reg.startAnimation(instruction);
- }
-
- }
- public void run() {
- try {
- FunctionUnitVisualization frame = new FunctionUnitVisualization(instruction, currentUnit);
- frame.setVisible(true);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
+ /**
+ * Create the frame.
+ */
+ public FunctionUnitVisualization(String instruction, int functionalUnit)
+ {
+ this.instruction = instruction;
+ //setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ setBounds(100, 100, 840, 575);
+ contentPane = new JPanel();
+ contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
+ contentPane.setLayout(new BorderLayout(0, 0));
+ setContentPane(contentPane);
+ if (functionalUnit == register)
+ {
+ currentUnit = register;
+ UnitAnimation reg = new UnitAnimation(instruction, register);
+ contentPane.add(reg);
+ reg.startAnimation(instruction);
+ }
+ else if (functionalUnit == control)
+ {
+ currentUnit = control;
+ UnitAnimation reg = new UnitAnimation(instruction, control);
+ contentPane.add(reg);
+ reg.startAnimation(instruction);
+ }
+
+ else if (functionalUnit == aluControl)
+ {
+ currentUnit = aluControl;
+ UnitAnimation reg = new UnitAnimation(instruction, aluControl);
+ contentPane.add(reg);
+ reg.startAnimation(instruction);
+ }
+
+ }
+
+ public void run()
+ {
+ try
+ {
+ FunctionUnitVisualization frame = new FunctionUnitVisualization(instruction, currentUnit);
+ frame.setVisible(true);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
}
diff --git a/src/main/java/mars/tools/InstructionCounter.java b/src/main/java/mars/tools/InstructionCounter.java
index e54f5a9..b1596eb 100644
--- a/src/main/java/mars/tools/InstructionCounter.java
+++ b/src/main/java/mars/tools/InstructionCounter.java
@@ -26,17 +26,6 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package mars.tools;
-import java.awt.GridBagConstraints;
-import java.awt.GridBagLayout;
-import java.awt.Insets;
-import java.util.Observable;
-
-import javax.swing.JComponent;
-import javax.swing.JLabel;
-import javax.swing.JPanel;
-import javax.swing.JProgressBar;
-import javax.swing.JTextField;
-
import mars.ProgramStatement;
import mars.mips.hardware.AccessNotice;
import mars.mips.hardware.AddressErrorException;
@@ -45,226 +34,266 @@ import mars.mips.hardware.MemoryAccessNotice;
import mars.mips.instructions.BasicInstruction;
import mars.mips.instructions.BasicInstructionFormat;
+import javax.swing.*;
+import java.awt.*;
+import java.util.Observable;
+
/**
- *
- * Instruction counter tool. Can be used to know how many instructions
- * were executed to complete a given program.
- *
+ * Instruction counter tool. Can be used to know how many instructions were executed to complete a given program.
+ *
* Code slightly based on MemoryReferenceVisualization.
- *
- * @author Felipe Lessa
*
+ * @author Felipe Lessa
*/
//@SuppressWarnings("serial")
-public class InstructionCounter extends AbstractMarsToolAndApplication {
- private static String name = "Instruction Counter";
- private static String version = "Version 1.0 (Felipe Lessa)";
- private static String heading = "Counting the number of instructions executed";
-
+public class InstructionCounter extends AbstractMarsToolAndApplication
+{
+ private static final String name = "Instruction Counter";
+
+ private static final String version = "Version 1.0 (Felipe Lessa)";
+
+ private static final String heading = "Counting the number of instructions executed";
+
/**
* Number of instructions executed until now.
*/
protected int counter = 0;
- private JTextField counterField;
-
+
/**
* Number of instructions of type R.
*/
protected int counterR = 0;
- private JTextField counterRField;
- private JProgressBar progressbarR;
-
+
/**
* Number of instructions of type I.
*/
protected int counterI = 0;
- private JTextField counterIField;
- private JProgressBar progressbarI;
-
+
/**
* Number of instructions of type J.
*/
protected int counterJ = 0;
- private JTextField counterJField;
- private JProgressBar progressbarJ;
-
-
+
/**
- * The last address we saw. We ignore it because the only way for a
- * program to execute twice the same instruction is to enter an infinite
- * loop, which is not insteresting in the POV of counting instructions.
+ * The last address we saw. We ignore it because the only way for a program to execute twice the same instruction is
+ * to enter an infinite loop, which is not insteresting in the POV of counting instructions.
*/
protected int lastAddress = -1;
-
- /**
- * Simple constructor, likely used to run a stand-alone memory reference visualizer.
- * @param title String containing title for title bar
- * @param heading String containing text for heading shown in upper part of window.
- */
- public InstructionCounter(String title, String heading) {
- super(title,heading);
+
+ private JTextField counterField;
+
+ private JTextField counterRField;
+
+ private JProgressBar progressbarR;
+
+ private JTextField counterIField;
+
+ private JProgressBar progressbarI;
+
+ private JTextField counterJField;
+
+ private JProgressBar progressbarJ;
+
+ /**
+ * Simple constructor, likely used to run a stand-alone memory reference visualizer.
+ *
+ * @param title String containing title for title bar
+ * @param heading String containing text for heading shown in upper part of window.
+ */
+ public InstructionCounter(String title, String heading)
+ {
+ super(title, heading);
}
-
+
/**
* Simple construction, likely used by the MARS Tools menu mechanism.
*/
- public InstructionCounter() {
- super(name + ", " + version, heading);
+ public InstructionCounter()
+ {
+ super(name + ", " + version, heading);
}
-// @Override
- public String getName() {
- return name;
- }
-
-// @Override
- protected JComponent buildMainDisplayArea() {
- // Create everything
- JPanel panel = new JPanel(new GridBagLayout());
+ // @Override
+ public String getName()
+ {
+ return name;
+ }
- counterField = new JTextField("0", 10);
- counterField.setEditable(false);
-
- counterRField = new JTextField("0", 10);
- counterRField.setEditable(false);
- progressbarR = new JProgressBar(JProgressBar.HORIZONTAL);
- progressbarR.setStringPainted(true);
-
- counterIField = new JTextField("0", 10);
- counterIField.setEditable(false);
- progressbarI = new JProgressBar(JProgressBar.HORIZONTAL);
- progressbarI.setStringPainted(true);
-
- counterJField = new JTextField("0", 10);
- counterJField.setEditable(false);
- progressbarJ = new JProgressBar(JProgressBar.HORIZONTAL);
- progressbarJ.setStringPainted(true);
-
- // Add them to the panel
-
- // Fields
- GridBagConstraints c = new GridBagConstraints();
- c.anchor = GridBagConstraints.LINE_START;
- c.gridheight = c.gridwidth = 1;
- c.gridx = 3;
- c.gridy = 1;
- c.insets = new Insets(0, 0, 17, 0);
- panel.add(counterField, c);
+ // @Override
+ protected JComponent buildMainDisplayArea()
+ {
+ // Create everything
+ JPanel panel = new JPanel(new GridBagLayout());
- c.insets = new Insets(0, 0, 0, 0);
- c.gridy++;
- panel.add(counterRField, c);
-
- c.gridy++;
- panel.add(counterIField, c);
-
- c.gridy++;
- panel.add(counterJField, c);
-
- // Labels
- c.anchor = GridBagConstraints.LINE_END;
- c.gridx = 1;
- c.gridwidth = 2;
- c.gridy = 1;
- c.insets = new Insets(0, 0, 17, 0);
- panel.add(new JLabel("Instructions so far: "), c);
+ counterField = new JTextField("0", 10);
+ counterField.setEditable(false);
- c.insets = new Insets(0, 0, 0, 0);
- c.gridx = 2;
- c.gridwidth = 1;
- c.gridy++;
- panel.add(new JLabel("R-type: "), c);
-
- c.gridy++;
- panel.add(new JLabel("I-type: "), c);
-
- c.gridy++;
- panel.add(new JLabel("J-type: "), c);
-
- // Progress bars
- c.insets = new Insets(3, 3, 3, 3);
- c.gridx = 4;
- c.gridy = 2;
- panel.add(progressbarR, c);
-
- c.gridy++;
- panel.add(progressbarI, c);
-
- c.gridy++;
- panel.add(progressbarJ, c);
-
- return panel;
- }
-
-// @Override
- protected void addAsObserver() {
- addAsObserver(Memory.textBaseAddress, Memory.textLimitAddress);
- }
+ counterRField = new JTextField("0", 10);
+ counterRField.setEditable(false);
+ progressbarR = new JProgressBar(JProgressBar.HORIZONTAL);
+ progressbarR.setStringPainted(true);
-// @Override
- protected void processMIPSUpdate(Observable resource, AccessNotice notice) {
- if (!notice.accessIsFromMIPS()) return;
- if (notice.getAccessType() != AccessNotice.READ) return;
- MemoryAccessNotice m = (MemoryAccessNotice) notice;
- int a = m.getAddress();
- if (a == lastAddress) return;
- lastAddress = a;
- counter++;
- try {
- ProgramStatement stmt = Memory.getInstance().getStatement(a);
- BasicInstruction instr = (BasicInstruction) stmt.getInstruction();
- BasicInstructionFormat format = instr.getInstructionFormat();
- if (format == BasicInstructionFormat.R_FORMAT)
- counterR++;
- else if (format == BasicInstructionFormat.I_FORMAT
- || format == BasicInstructionFormat.I_BRANCH_FORMAT)
- counterI++;
- else if (format == BasicInstructionFormat.J_FORMAT)
- counterJ++;
- } catch (AddressErrorException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- updateDisplay();
- }
-
-// @Override
- protected void initializePreGUI() {
- counter = counterR = counterI = counterJ = 0;
- lastAddress = -1;
- }
-
-// @Override
- protected void reset() {
- counter = counterR = counterI = counterJ = 0;
- lastAddress = -1;
- updateDisplay();
- }
-
-// @Override
- protected void updateDisplay() {
- counterField.setText(String.valueOf(counter));
-
- counterRField.setText(String.valueOf(counterR));
- progressbarR.setMaximum(counter);
- progressbarR.setValue(counterR);
-
- counterIField.setText(String.valueOf(counterI));
- progressbarI.setMaximum(counter);
- progressbarI.setValue(counterI);
-
- counterJField.setText(String.valueOf(counterJ));
- progressbarJ.setMaximum(counter);
- progressbarJ.setValue(counterJ);
-
- if (counter == 0) {
- progressbarR.setString("0%");
- progressbarI.setString("0%");
- progressbarJ.setString("0%");
- } else {
- progressbarR.setString((counterR * 100)/counter + "%");
- progressbarI.setString((counterI * 100)/counter + "%");
- progressbarJ.setString((counterJ * 100)/counter + "%");
- }
- }
+ counterIField = new JTextField("0", 10);
+ counterIField.setEditable(false);
+ progressbarI = new JProgressBar(JProgressBar.HORIZONTAL);
+ progressbarI.setStringPainted(true);
+
+ counterJField = new JTextField("0", 10);
+ counterJField.setEditable(false);
+ progressbarJ = new JProgressBar(JProgressBar.HORIZONTAL);
+ progressbarJ.setStringPainted(true);
+
+ // Add them to the panel
+
+ // Fields
+ GridBagConstraints c = new GridBagConstraints();
+ c.anchor = GridBagConstraints.LINE_START;
+ c.gridheight = c.gridwidth = 1;
+ c.gridx = 3;
+ c.gridy = 1;
+ c.insets = new Insets(0, 0, 17, 0);
+ panel.add(counterField, c);
+
+ c.insets = new Insets(0, 0, 0, 0);
+ c.gridy++;
+ panel.add(counterRField, c);
+
+ c.gridy++;
+ panel.add(counterIField, c);
+
+ c.gridy++;
+ panel.add(counterJField, c);
+
+ // Labels
+ c.anchor = GridBagConstraints.LINE_END;
+ c.gridx = 1;
+ c.gridwidth = 2;
+ c.gridy = 1;
+ c.insets = new Insets(0, 0, 17, 0);
+ panel.add(new JLabel("Instructions so far: "), c);
+
+ c.insets = new Insets(0, 0, 0, 0);
+ c.gridx = 2;
+ c.gridwidth = 1;
+ c.gridy++;
+ panel.add(new JLabel("R-type: "), c);
+
+ c.gridy++;
+ panel.add(new JLabel("I-type: "), c);
+
+ c.gridy++;
+ panel.add(new JLabel("J-type: "), c);
+
+ // Progress bars
+ c.insets = new Insets(3, 3, 3, 3);
+ c.gridx = 4;
+ c.gridy = 2;
+ panel.add(progressbarR, c);
+
+ c.gridy++;
+ panel.add(progressbarI, c);
+
+ c.gridy++;
+ panel.add(progressbarJ, c);
+
+ return panel;
+ }
+
+ // @Override
+ protected void addAsObserver()
+ {
+ addAsObserver(Memory.textBaseAddress, Memory.textLimitAddress);
+ }
+
+ // @Override
+ protected void processMIPSUpdate(Observable resource, AccessNotice notice)
+ {
+ if (!notice.accessIsFromMIPS())
+ {
+ return;
+ }
+ if (notice.getAccessType() != AccessNotice.READ)
+ {
+ return;
+ }
+ MemoryAccessNotice m = (MemoryAccessNotice) notice;
+ int a = m.getAddress();
+ if (a == lastAddress)
+ {
+ return;
+ }
+ lastAddress = a;
+ counter++;
+ try
+ {
+ ProgramStatement stmt = Memory.getInstance().getStatement(a);
+ BasicInstruction instr = (BasicInstruction) stmt.getInstruction();
+ BasicInstructionFormat format = instr.getInstructionFormat();
+ if (format == BasicInstructionFormat.R_FORMAT)
+ {
+ counterR++;
+ }
+ else if (format == BasicInstructionFormat.I_FORMAT
+ || format == BasicInstructionFormat.I_BRANCH_FORMAT)
+ {
+ counterI++;
+ }
+ else if (format == BasicInstructionFormat.J_FORMAT)
+ {
+ counterJ++;
+ }
+ }
+ catch (AddressErrorException e)
+ {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ updateDisplay();
+ }
+
+ // @Override
+ protected void initializePreGUI()
+ {
+ counter = counterR = counterI = counterJ = 0;
+ lastAddress = -1;
+ }
+
+ // @Override
+ protected void reset()
+ {
+ counter = counterR = counterI = counterJ = 0;
+ lastAddress = -1;
+ updateDisplay();
+ }
+
+ // @Override
+ protected void updateDisplay()
+ {
+ counterField.setText(String.valueOf(counter));
+
+ counterRField.setText(String.valueOf(counterR));
+ progressbarR.setMaximum(counter);
+ progressbarR.setValue(counterR);
+
+ counterIField.setText(String.valueOf(counterI));
+ progressbarI.setMaximum(counter);
+ progressbarI.setValue(counterI);
+
+ counterJField.setText(String.valueOf(counterJ));
+ progressbarJ.setMaximum(counter);
+ progressbarJ.setValue(counterJ);
+
+ if (counter == 0)
+ {
+ progressbarR.setString("0%");
+ progressbarI.setString("0%");
+ progressbarJ.setString("0%");
+ }
+ else
+ {
+ progressbarR.setString((counterR * 100) / counter + "%");
+ progressbarI.setString((counterI * 100) / counter + "%");
+ progressbarJ.setString((counterJ * 100) / counter + "%");
+ }
+ }
}
diff --git a/src/main/java/mars/tools/InstructionStatistics.java b/src/main/java/mars/tools/InstructionStatistics.java
index bc3021a..cff3073 100644
--- a/src/main/java/mars/tools/InstructionStatistics.java
+++ b/src/main/java/mars/tools/InstructionStatistics.java
@@ -25,327 +25,361 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
(MIT license, http://www.opensource.org/licenses/mit-license.html)
*/
- package mars.tools;
+package mars.tools;
- import java.awt.GridBagConstraints;
- import java.awt.GridBagLayout;
- import java.awt.Insets;
- import java.util.Observable;
+import mars.ProgramStatement;
+import mars.mips.hardware.AccessNotice;
+import mars.mips.hardware.AddressErrorException;
+import mars.mips.hardware.Memory;
+import mars.mips.hardware.MemoryAccessNotice;
- import javax.swing.JComponent;
- import javax.swing.JLabel;
- import javax.swing.JPanel;
- import javax.swing.JProgressBar;
- import javax.swing.JTextField;
-
- import mars.ProgramStatement;
- import mars.mips.hardware.AccessNotice;
- import mars.mips.hardware.AddressErrorException;
- import mars.mips.hardware.Memory;
- import mars.mips.hardware.MemoryAccessNotice;
+import javax.swing.*;
+import java.awt.*;
+import java.util.Observable;
/**
- *
- * A MARS tool for obtaining instruction statistics by instruction category.
- *
- * The code of this tools is initially based on the Instruction counter tool by Felipe Lassa.
- *
- * @author Ingo Kofler
+ * A MARS tool for obtaining instruction statistics by instruction category.
+ *
+ * The code of this tools is initially based on the Instruction counter tool by Felipe Lassa.
*
+ * @author Ingo Kofler
*/
- // @SuppressWarnings("serial")
- public class InstructionStatistics extends AbstractMarsToolAndApplication {
-
- /** name of the tool */
- private static String NAME = "Instruction Statistics";
-
- /** version and author information of the tool */
- private static String VERSION = "Version 1.0 (Ingo Kofler)";
-
- /** heading of the tool */
- private static String HEADING = "";
-
-
-
+// @SuppressWarnings("serial")
+public class InstructionStatistics extends AbstractMarsToolAndApplication
+{
+
/** number of instruction categories used by this tool */
- private static final int MAX_CATEGORY = 5;
-
+ private static final int MAX_CATEGORY = 5;
+
/** constant for ALU instructions category */
- private static final int CATEGORY_ALU = 0;
-
+ private static final int CATEGORY_ALU = 0;
+
/** constant for jump instructions category */
- private static final int CATEGORY_JUMP = 1;
-
+ private static final int CATEGORY_JUMP = 1;
+
/** constant for branch instructions category */
- private static final int CATEGORY_BRANCH = 2;
-
+ private static final int CATEGORY_BRANCH = 2;
+
/** constant for memory instructions category */
- private static final int CATEGORY_MEM = 3;
-
+ private static final int CATEGORY_MEM = 3;
+
/** constant for any other instruction category */
- private static final int CATEGORY_OTHER = 4;
-
-
-
-
+ private static final int CATEGORY_OTHER = 4;
+
+ /** name of the tool */
+ private static final String NAME = "Instruction Statistics";
+
+ /** version and author information of the tool */
+ private static final String VERSION = "Version 1.0 (Ingo Kofler)";
+
+ /** heading of the tool */
+ private static final String HEADING = "";
+
+ /**
+ * The last address we saw. We ignore it because the only way for a program to execute twice the same instruction is
+ * to enter an infinite loop, which is not insteresting in the POV of counting instructions.
+ */
+ protected int lastAddress = -1;
+
/** text field for visualizing the total number of instructions processed */
- private JTextField m_tfTotalCounter;
-
- /** array of text field - one for each instruction category */
- private JTextField m_tfCounters[];
-
+ private JTextField m_tfTotalCounter;
+
+ /** array of text field - one for each instruction category */
+ private JTextField[] m_tfCounters;
+
/** array of progress pars - one for each instruction category */
- private JProgressBar m_pbCounters[];
-
-
+ private JProgressBar[] m_pbCounters;
+
/** counter for the total number of instructions processed */
- private int m_totalCounter = 0;
-
+ private int m_totalCounter = 0;
+
/** array of counter variables - one for each instruction category */
- private int m_counters[] = new int[MAX_CATEGORY];
-
- /** names of the instruction categories as array */
- private String m_categoryLabels[] = { "ALU", "Jump", "Branch", "Memory", "Other" };
-
-
+ private final int[] m_counters = new int[MAX_CATEGORY];
+
+
// From Felipe Lessa's instruction counter. Prevent double-counting of instructions
// which happens because 2 read events are generated.
+
+ /** names of the instruction categories as array */
+ private final String[] m_categoryLabels = {"ALU", "Jump", "Branch", "Memory", "Other"};
+
/**
- * The last address we saw. We ignore it because the only way for a
- * program to execute twice the same instruction is to enter an infinite
- * loop, which is not insteresting in the POV of counting instructions.
+ * Simple constructor, likely used to run a stand-alone enhanced instruction counter.
+ *
+ * @param title String containing title for title bar
+ * @param heading String containing text for heading shown in upper part of window.
*/
- protected int lastAddress = -1;
-
- /**
- * Simple constructor, likely used to run a stand-alone enhanced instruction counter.
- * @param title String containing title for title bar
- * @param heading String containing text for heading shown in upper part of window.
- */
- public InstructionStatistics(String title, String heading) {
- super(title, heading);
- }
-
-
+ public InstructionStatistics(String title, String heading)
+ {
+ super(title, heading);
+ }
+
+
/**
* Simple construction, likely used by the MARS Tools menu mechanism.
*/
- public InstructionStatistics() {
- super(InstructionStatistics.NAME + ", " + InstructionStatistics.VERSION, InstructionStatistics.HEADING);
- }
-
-
+ public InstructionStatistics()
+ {
+ super(InstructionStatistics.NAME + ", " + InstructionStatistics.VERSION, InstructionStatistics.HEADING);
+ }
+
+
/**
* returns the name of the tool
- *
+ *
* @return the tools's name
*/
- public String getName() {
- return NAME;
- }
-
-
- /**
- * creates the display area for the tool as required by the API
- *
- * @return a panel that holds the GUI of the tool
- */
- protected JComponent buildMainDisplayArea() {
-
- // Create GUI elements for the tool
- JPanel panel = new JPanel(new GridBagLayout());
-
- m_tfTotalCounter = new JTextField("0", 10);
- m_tfTotalCounter.setEditable(false);
-
- m_tfCounters = new JTextField[MAX_CATEGORY];
- m_pbCounters = new JProgressBar[MAX_CATEGORY];
-
- // for each category a text field and a progress bar is created
- for (int i=0; i < InstructionStatistics.MAX_CATEGORY; i++) {
+ public String getName()
+ {
+ return NAME;
+ }
+
+
+ /**
+ * creates the display area for the tool as required by the API
+ *
+ * @return a panel that holds the GUI of the tool
+ */
+ protected JComponent buildMainDisplayArea()
+ {
+
+ // Create GUI elements for the tool
+ JPanel panel = new JPanel(new GridBagLayout());
+
+ m_tfTotalCounter = new JTextField("0", 10);
+ m_tfTotalCounter.setEditable(false);
+
+ m_tfCounters = new JTextField[MAX_CATEGORY];
+ m_pbCounters = new JProgressBar[MAX_CATEGORY];
+
+ // for each category a text field and a progress bar is created
+ for (int i = 0; i < InstructionStatistics.MAX_CATEGORY; i++)
+ {
m_tfCounters[i] = new JTextField("0", 10);
m_tfCounters[i].setEditable(false);
m_pbCounters[i] = new JProgressBar(JProgressBar.HORIZONTAL);
m_pbCounters[i].setStringPainted(true);
- }
-
- GridBagConstraints c = new GridBagConstraints();
- c.anchor = GridBagConstraints.LINE_START;
- c.gridheight = c.gridwidth = 1;
-
- // create the label and text field for the total instruction counter
- c.gridx = 2;
- c.gridy = 1;
- c.insets = new Insets(0, 0, 17, 0);
- panel.add(new JLabel("Total: "), c);
- c.gridx = 3;
- panel.add(m_tfTotalCounter, c);
-
- c.insets = new Insets(3, 3, 3, 3);
-
- // create label, text field and progress bar for each category
- for (int i=0; i < InstructionStatistics.MAX_CATEGORY; i++) {
+ }
+
+ GridBagConstraints c = new GridBagConstraints();
+ c.anchor = GridBagConstraints.LINE_START;
+ c.gridheight = c.gridwidth = 1;
+
+ // create the label and text field for the total instruction counter
+ c.gridx = 2;
+ c.gridy = 1;
+ c.insets = new Insets(0, 0, 17, 0);
+ panel.add(new JLabel("Total: "), c);
+ c.gridx = 3;
+ panel.add(m_tfTotalCounter, c);
+
+ c.insets = new Insets(3, 3, 3, 3);
+
+ // create label, text field and progress bar for each category
+ for (int i = 0; i < InstructionStatistics.MAX_CATEGORY; i++)
+ {
c.gridy++;
- c.gridx=2;
+ c.gridx = 2;
panel.add(new JLabel(m_categoryLabels[i] + ": "), c);
- c.gridx=3;
+ c.gridx = 3;
panel.add(m_tfCounters[i], c);
- c.gridx=4;
- panel.add(m_pbCounters[i], c);
- }
-
- return panel;
- }
-
-
- /**
- * registers the tool as observer for the text segment of the MIPS program
- *
- */
- protected void addAsObserver() {
- addAsObserver(Memory.textBaseAddress, Memory.textLimitAddress);
- }
-
-
- /**
- * decodes the instruction and determines the category of the instruction.
- *
- * The instruction is decoded by extracting the operation and function code of the 32-bit instruction.
- * Only the most relevant instructions are decoded and categorized.
- *
- * @param stmt the instruction to decode
- * @return the category of the instruction
- * @see InstructionStatistics#CATEGORY_ALU
- * @see InstructionStatistics#CATEGORY_JUMP
- * @see InstructionStatistics#CATEGORY_BRANCH
- * @see InstructionStatistics#CATEGORY_MEM
- * @see InstructionStatistics#CATEGORY_OTHER
- */
- protected int getInstructionCategory(ProgramStatement stmt) {
-
- int opCode = stmt.getBinaryStatement() >>> (32-6);
- int funct = stmt.getBinaryStatement() & 0x1F;
-
- if (opCode == 0x00) {
- if (funct == 0x00 )
- return InstructionStatistics.CATEGORY_ALU; // sll
- if (0x02 <= funct && funct <= 0x07)
- return InstructionStatistics.CATEGORY_ALU; // srl, sra, sllv, srlv, srav
- if (funct == 0x08 || funct == 0x09)
- return InstructionStatistics.CATEGORY_JUMP; // jr, jalr
- if (0x10 <= funct && funct <= 0x2F)
- return InstructionStatistics.CATEGORY_ALU; // mfhi, mthi, mflo, mtlo, mult, multu, div, divu, add, addu, sub, subu, and, or, xor, nor, slt, sltu
- return InstructionStatistics.CATEGORY_OTHER;
- }
- if (opCode == 0x01) {
- if (0x00 <= funct && funct <= 0x07)
- return InstructionStatistics.CATEGORY_BRANCH; // bltz, bgez, bltzl, bgezl
- if (0x10 <= funct && funct <= 0x13)
- return InstructionStatistics.CATEGORY_BRANCH; // bltzal, bgezal, bltzall, bgczall
+ c.gridx = 4;
+ panel.add(m_pbCounters[i], c);
+ }
+
+ return panel;
+ }
+
+
+ /**
+ * registers the tool as observer for the text segment of the MIPS program
+ */
+ protected void addAsObserver()
+ {
+ addAsObserver(Memory.textBaseAddress, Memory.textLimitAddress);
+ }
+
+
+ /**
+ * decodes the instruction and determines the category of the instruction.
+ *
+ * The instruction is decoded by extracting the operation and function code of the 32-bit instruction. Only the most
+ * relevant instructions are decoded and categorized.
+ *
+ * @param stmt the instruction to decode
+ * @return the category of the instruction
+ * @see InstructionStatistics#CATEGORY_ALU
+ * @see InstructionStatistics#CATEGORY_JUMP
+ * @see InstructionStatistics#CATEGORY_BRANCH
+ * @see InstructionStatistics#CATEGORY_MEM
+ * @see InstructionStatistics#CATEGORY_OTHER
+ */
+ protected int getInstructionCategory(ProgramStatement stmt)
+ {
+
+ int opCode = stmt.getBinaryStatement() >>> (32 - 6);
+ int funct = stmt.getBinaryStatement() & 0x1F;
+
+ if (opCode == 0x00)
+ {
+ if (funct == 0x00)
+ {
+ return InstructionStatistics.CATEGORY_ALU; // sll
+ }
+ if (0x02 <= funct && funct <= 0x07)
+ {
+ return InstructionStatistics.CATEGORY_ALU; // srl, sra, sllv, srlv, srav
+ }
+ if (funct == 0x08 || funct == 0x09)
+ {
+ return InstructionStatistics.CATEGORY_JUMP; // jr, jalr
+ }
+ if (0x10 <= funct && funct <= 0x2F)
+ {
+ return InstructionStatistics.CATEGORY_ALU; // mfhi, mthi, mflo, mtlo, mult, multu, div, divu, add, addu, sub, subu, and, or, xor, nor, slt, sltu
+ }
return InstructionStatistics.CATEGORY_OTHER;
- }
- if (opCode == 0x02 || opCode == 0x03)
+ }
+ if (opCode == 0x01)
+ {
+ if (0x00 <= funct && funct <= 0x07)
+ {
+ return InstructionStatistics.CATEGORY_BRANCH; // bltz, bgez, bltzl, bgezl
+ }
+ if (0x10 <= funct && funct <= 0x13)
+ {
+ return InstructionStatistics.CATEGORY_BRANCH; // bltzal, bgezal, bltzall, bgczall
+ }
+ return InstructionStatistics.CATEGORY_OTHER;
+ }
+ if (opCode == 0x02 || opCode == 0x03)
+ {
return InstructionStatistics.CATEGORY_JUMP; // j, jal
- if (0x04 <= opCode && opCode <= 0x07)
+ }
+ if (0x04 <= opCode && opCode <= 0x07)
+ {
return InstructionStatistics.CATEGORY_BRANCH; // beq, bne, blez, bgtz
- if (0x08 <= opCode && opCode <= 0x0F)
+ }
+ if (0x08 <= opCode && opCode <= 0x0F)
+ {
return InstructionStatistics.CATEGORY_ALU; // addi, addiu, slti, sltiu, andi, ori, xori, lui
- if (0x14 <= opCode && opCode <= 0x17)
+ }
+ if (0x14 <= opCode && opCode <= 0x17)
+ {
return InstructionStatistics.CATEGORY_BRANCH; // beql, bnel, blezl, bgtzl
- if (0x20 <= opCode && opCode <= 0x26)
+ }
+ if (0x20 <= opCode && opCode <= 0x26)
+ {
return InstructionStatistics.CATEGORY_MEM; // lb, lh, lwl, lw, lbu, lhu, lwr
- if (0x28 <= opCode && opCode <= 0x2E)
+ }
+ if (0x28 <= opCode && opCode <= 0x2E)
+ {
return InstructionStatistics.CATEGORY_MEM; // sb, sh, swl, sw, swr
-
- return InstructionStatistics.CATEGORY_OTHER;
- }
-
-
- /**
- * method that is called each time the MIPS simulator accesses the text segment.
- * Before an instruction is executed by the simulator, the instruction is fetched from the program memory.
- * This memory access is observed and the corresponding instruction is decoded and categorized by the tool.
- * According to the category the counter values are increased and the display gets updated.
- *
- * @param resource the observed resource
- * @param notice signals the type of access (memory, register etc.)
- */
- protected void processMIPSUpdate(Observable resource, AccessNotice notice) {
-
- if (!notice.accessIsFromMIPS())
- return;
-
- // check for a read access in the text segment
- if (notice.getAccessType() == AccessNotice.READ && notice instanceof MemoryAccessNotice) {
-
- // now it is safe to make a cast of the notice
- MemoryAccessNotice memAccNotice = (MemoryAccessNotice) notice;
-
- // The next three statments are from Felipe Lessa's instruction counter. Prevents double-counting.
+ }
+
+ return InstructionStatistics.CATEGORY_OTHER;
+ }
+
+
+ /**
+ * method that is called each time the MIPS simulator accesses the text segment. Before an instruction is executed
+ * by the simulator, the instruction is fetched from the program memory. This memory access is observed and the
+ * corresponding instruction is decoded and categorized by the tool. According to the category the counter values
+ * are increased and the display gets updated.
+ *
+ * @param resource the observed resource
+ * @param notice signals the type of access (memory, register etc.)
+ */
+ protected void processMIPSUpdate(Observable resource, AccessNotice notice)
+ {
+
+ if (!notice.accessIsFromMIPS())
+ {
+ return;
+ }
+
+ // check for a read access in the text segment
+ if (notice.getAccessType() == AccessNotice.READ && notice instanceof MemoryAccessNotice)
+ {
+
+ // now it is safe to make a cast of the notice
+ MemoryAccessNotice memAccNotice = (MemoryAccessNotice) notice;
+
+ // The next three statments are from Felipe Lessa's instruction counter. Prevents double-counting.
int a = memAccNotice.getAddress();
- if (a == lastAddress)
- return;
+ if (a == lastAddress)
+ {
+ return;
+ }
lastAddress = a;
-
- try {
-
- // access the statement in the text segment without notifying other tools etc.
- ProgramStatement stmt = Memory.getInstance().getStatementNoNotify(memAccNotice.getAddress());
-
- // necessary to handle possible null pointers at the end of the program
- // (e.g., if the simulator tries to execute the next instruction after the last instruction in the text segment)
- if (stmt != null) {
- int category = getInstructionCategory(stmt);
-
- m_totalCounter ++;
- m_counters[category] ++;
- updateDisplay();
- }
- }
- catch (AddressErrorException e) {
- // silently ignore these exceptions
- }
- }
- }
-
-
- /**
- * performs initialization tasks of the counters before the GUI is created.
- *
- */
- protected void initializePreGUI() {
- m_totalCounter = 0;
- lastAddress = -1; // from Felipe Lessa's instruction counter tool
- for (int i=0; i < InstructionStatistics.MAX_CATEGORY; i++)
- m_counters[i] = 0;
- }
-
-
- /**
- * resets the counter values of the tool and updates the display.
- *
- */
- protected void reset() {
- m_totalCounter = 0;
- lastAddress = -1; // from Felipe Lessa's instruction counter tool
- for (int i=0; i < InstructionStatistics.MAX_CATEGORY; i++)
- m_counters[i] = 0;
- updateDisplay();
- }
-
-
- /**
- * updates the text fields and progress bars according to the current counter values.
- *
- */
- protected void updateDisplay() {
- m_tfTotalCounter.setText(String.valueOf(m_totalCounter));
-
- for (int i=0; i < InstructionStatistics.MAX_CATEGORY; i++) {
+
+ try
+ {
+
+ // access the statement in the text segment without notifying other tools etc.
+ ProgramStatement stmt = Memory.getInstance().getStatementNoNotify(memAccNotice.getAddress());
+
+ // necessary to handle possible null pointers at the end of the program
+ // (e.g., if the simulator tries to execute the next instruction after the last instruction in the text segment)
+ if (stmt != null)
+ {
+ int category = getInstructionCategory(stmt);
+
+ m_totalCounter++;
+ m_counters[category]++;
+ updateDisplay();
+ }
+ }
+ catch (AddressErrorException e)
+ {
+ // silently ignore these exceptions
+ }
+ }
+ }
+
+
+ /**
+ * performs initialization tasks of the counters before the GUI is created.
+ */
+ protected void initializePreGUI()
+ {
+ m_totalCounter = 0;
+ lastAddress = -1; // from Felipe Lessa's instruction counter tool
+ for (int i = 0; i < InstructionStatistics.MAX_CATEGORY; i++)
+ {
+ m_counters[i] = 0;
+ }
+ }
+
+
+ /**
+ * resets the counter values of the tool and updates the display.
+ */
+ protected void reset()
+ {
+ m_totalCounter = 0;
+ lastAddress = -1; // from Felipe Lessa's instruction counter tool
+ for (int i = 0; i < InstructionStatistics.MAX_CATEGORY; i++)
+ {
+ m_counters[i] = 0;
+ }
+ updateDisplay();
+ }
+
+
+ /**
+ * updates the text fields and progress bars according to the current counter values.
+ */
+ protected void updateDisplay()
+ {
+ m_tfTotalCounter.setText(String.valueOf(m_totalCounter));
+
+ for (int i = 0; i < InstructionStatistics.MAX_CATEGORY; i++)
+ {
m_tfCounters[i].setText(String.valueOf(m_counters[i]));
m_pbCounters[i].setMaximum(m_totalCounter);
m_pbCounters[i].setValue(m_counters[i]);
- }
- }
- }
+ }
+ }
+}
diff --git a/src/main/java/mars/tools/IntroToTools.java b/src/main/java/mars/tools/IntroToTools.java
index 440e893..444d1fc 100644
--- a/src/main/java/mars/tools/IntroToTools.java
+++ b/src/main/java/mars/tools/IntroToTools.java
@@ -1,8 +1,7 @@
- package mars.tools;
- import javax.swing.*;
- import java.awt.*;
- import java.awt.event.*;
- import mars.*;
+package mars.tools;
+
+import javax.swing.*;
+import java.awt.*;
/*
@@ -32,127 +31,133 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
(MIT license, http://www.opensource.org/licenses/mit-license.html)
*/
-
- /**
- * The "hello world" of MarsTools!
- */
- public class IntroToTools extends AbstractMarsToolAndApplication {
-
- private static String heading = "Introduction to MARS Tools and Applications";
- private static String version = " Version 1.0";
-
- /**
- * Simple constructor, likely used to run a stand-alone memory reference visualizer.
- * @param title String containing title for title bar
- * @param heading String containing text for heading shown in upper part of window.
- */
- public IntroToTools(String title, String heading) {
- super(title,heading);
- }
-
- /**
- * Simple constructor, likely used by the MARS Tools menu mechanism
- */
- public IntroToTools() {
- super (heading+", "+version, heading);
- }
-
-
- /**
- * Main provided for pure stand-alone use. Recommended stand-alone use is to write a
- * driver program that instantiates a MemoryReferenceVisualization object then invokes its go() method.
- * "stand-alone" means it is not invoked from the MARS Tools menu. "Pure" means there
- * is no driver program to invoke the application.
- */
- public static void main(String[] args) {
- new IntroToTools(heading+", "+version,heading).go();
- }
-
-
- /**
- * Required method to return Tool name.
- * @return Tool name. MARS will display this in menu item.
- */
- public String getName() {
- return "Introduction to Tools";
- }
-
- /**
- * Implementation of the inherited abstract method to build the main
- * display area of the GUI. It will be placed in the CENTER area of a
- * BorderLayout. The title is in the NORTH area, and the controls are
- * in the SOUTH area.
- */
- protected JComponent buildMainDisplayArea() {
- JTextArea message = new JTextArea();
- message.setEditable(false);
- message.setLineWrap(true);
- message.setWrapStyleWord(true);
- message.setFont(new Font("Ariel",Font.PLAIN,12));
- message.setText(
- "Hello! This Tool does not do anything but you may use its "+
- "source code as a starting point to build your own MARS Tool "+
- "or Application."+
- "\n\n"+
- "A MARS Tool is a program listed in the MARS Tools menu. It is launched "+
- "when you select its menu item and typically interacts with executing MIPS "+
- "programs to do something exciting and informative or at least interesting."+
- "\n\n"+
- "A MARS Application is a stand-alone program for similarly interacting with "+
- "executing MIPS programs. It uses MARS' MIPS assembler and "+
- "runtime simulator in the background to control MIPS execution."+
- "\n\n"+
- "The basic requirements for building a MARS Tool are:"+
- "\n"+
- " 1. It must be a class that implements the MarsTool interface. "+
- "This has only two methods: 'String getName()' to return the "+
- "name to be displayed in its Tools menu item, and "+
- "'void action()' which is invoked when that menu item "+
- "is selected by the MARS user."+
- "\n"+
- " 2. It must be stored in the mars.tools package (in folder "+
- "mars/tools)"+
- "\n"+
- " 3. It must be successfully compiled in that package. This "+
- "normally means the MARS distribution needs to be extracted from the "+
- "JAR file before you can develop your Tool."+
- "\n\n"+
- "If these requirements are met, MARS will recognize and load "+
- "your Tool into its Tools menu the next time it runs."+
- "\n\n"+
- "There are no fixed requirements for building a MARS Application, a "+
- "stand-alone program that utilizes the MARS API."+
- "\n\n"+
- "You can build a program that may be run as either a MARS Tool or an Application. "+
- "The easiest way is to extend an abstract class provided in the MARS distribution: "+
- "mars.tools.AbstractMarsToolAndApplication. "+
- "\n"+
- " 1. It defines a suite of methods and provides default definitions for "+
- "all but two: getName() and buildMainDisplayArea()."+
- "\n"+
- " 2. String getName() was introduced above."+
- "\n"+
- " 3. JComponent buildMainDisplayArea() returns the JComponent to be placed in the "+
- "BorderLayout.CENTER region of the tool/app's user interface. The NORTH and "+
- "SOUTH are defined to contain a heading and a set of button controls, respectively. "+
- "\n"+
- " 4. It defines a default 'void go()' method to launch the application."+
- "\n"+
- " 5. Conventional usage is to define your application as a subclass then launch it "+
- "by invoking its go() method."+
- "\n\n"+
- "The frame/dialog you are reading right now is an example of an "+
- "AbstractMarsToolAndApplication subclass. If you run it as an application, you "+
- "will notice the set of controls at the bottom of the window differ from those "+
- "you get when running it from MARS' Tools menu. It includes additional controls "+
- "to load and control the execution of pre-existing MIPS programs."+
- "\n\n"+
- "See the mars.tools.AbstractMarsToolAndApplication API or the source code of "+
- "existing tool/apps for further information."+
- "\n"
- );
- message.setCaretPosition(0); // Assure first line is visible and at top of scroll pane.
- return new JScrollPane(message);
- }
-
- }
\ No newline at end of file
+
+/**
+ * The "hello world" of MarsTools!
+ */
+public class IntroToTools extends AbstractMarsToolAndApplication
+{
+
+ private static final String heading = "Introduction to MARS Tools and Applications";
+
+ private static final String version = " Version 1.0";
+
+ /**
+ * Simple constructor, likely used to run a stand-alone memory reference visualizer.
+ *
+ * @param title String containing title for title bar
+ * @param heading String containing text for heading shown in upper part of window.
+ */
+ public IntroToTools(String title, String heading)
+ {
+ super(title, heading);
+ }
+
+ /**
+ * Simple constructor, likely used by the MARS Tools menu mechanism
+ */
+ public IntroToTools()
+ {
+ super(heading + ", " + version, heading);
+ }
+
+
+ /**
+ * Main provided for pure stand-alone use. Recommended stand-alone use is to write a driver program that
+ * instantiates a MemoryReferenceVisualization object then invokes its go() method. "stand-alone" means it is not
+ * invoked from the MARS Tools menu. "Pure" means there is no driver program to invoke the application.
+ */
+ public static void main(String[] args)
+ {
+ new IntroToTools(heading + ", " + version, heading).go();
+ }
+
+
+ /**
+ * Required method to return Tool name.
+ *
+ * @return Tool name. MARS will display this in menu item.
+ */
+ public String getName()
+ {
+ return "Introduction to Tools";
+ }
+
+ /**
+ * Implementation of the inherited abstract method to build the main display area of the GUI. It will be placed in
+ * the CENTER area of a BorderLayout. The title is in the NORTH area, and the controls are in the SOUTH area.
+ */
+ protected JComponent buildMainDisplayArea()
+ {
+ JTextArea message = new JTextArea();
+ message.setEditable(false);
+ message.setLineWrap(true);
+ message.setWrapStyleWord(true);
+ message.setFont(new Font("Ariel", Font.PLAIN, 12));
+ message.setText(
+ "Hello! This Tool does not do anything but you may use its " +
+ "source code as a starting point to build your own MARS Tool " +
+ "or Application." +
+ "\n\n" +
+ "A MARS Tool is a program listed in the MARS Tools menu. It is launched " +
+ "when you select its menu item and typically interacts with executing MIPS " +
+ "programs to do something exciting and informative or at least interesting." +
+ "\n\n" +
+ "A MARS Application is a stand-alone program for similarly interacting with " +
+ "executing MIPS programs. It uses MARS' MIPS assembler and " +
+ "runtime simulator in the background to control MIPS execution." +
+ "\n\n" +
+ "The basic requirements for building a MARS Tool are:" +
+ "\n" +
+ " 1. It must be a class that implements the MarsTool interface. " +
+ "This has only two methods: 'String getName()' to return the " +
+ "name to be displayed in its Tools menu item, and " +
+ "'void action()' which is invoked when that menu item " +
+ "is selected by the MARS user." +
+ "\n" +
+ " 2. It must be stored in the mars.tools package (in folder " +
+ "mars/tools)" +
+ "\n" +
+ " 3. It must be successfully compiled in that package. This " +
+ "normally means the MARS distribution needs to be extracted from the " +
+ "JAR file before you can develop your Tool." +
+ "\n\n" +
+ "If these requirements are met, MARS will recognize and load " +
+ "your Tool into its Tools menu the next time it runs." +
+ "\n\n" +
+ "There are no fixed requirements for building a MARS Application, a " +
+ "stand-alone program that utilizes the MARS API." +
+ "\n\n" +
+ "You can build a program that may be run as either a MARS Tool or an Application. " +
+ "The easiest way is to extend an abstract class provided in the MARS distribution: " +
+ "mars.tools.AbstractMarsToolAndApplication. " +
+ "\n" +
+ " 1. It defines a suite of methods and provides default definitions for " +
+ "all but two: getName() and buildMainDisplayArea()." +
+ "\n" +
+ " 2. String getName() was introduced above." +
+ "\n" +
+ " 3. JComponent buildMainDisplayArea() returns the JComponent to be placed in the " +
+ "BorderLayout.CENTER region of the tool/app's user interface. The NORTH and " +
+ "SOUTH are defined to contain a heading and a set of button controls, respectively. " +
+ "\n" +
+ " 4. It defines a default 'void go()' method to launch the application." +
+ "\n" +
+ " 5. Conventional usage is to define your application as a subclass then launch it " +
+ "by invoking its go() method." +
+ "\n\n" +
+ "The frame/dialog you are reading right now is an example of an " +
+ "AbstractMarsToolAndApplication subclass. If you run it as an application, you " +
+ "will notice the set of controls at the bottom of the window differ from those " +
+ "you get when running it from MARS' Tools menu. It includes additional controls " +
+ "to load and control the execution of pre-existing MIPS programs." +
+ "\n\n" +
+ "See the mars.tools.AbstractMarsToolAndApplication API or the source code of " +
+ "existing tool/apps for further information." +
+ "\n"
+ );
+ message.setCaretPosition(0); // Assure first line is visible and at top of scroll pane.
+ return new JScrollPane(message);
+ }
+
+}
diff --git a/src/main/java/mars/tools/KeyboardAndDisplaySimulator.java b/src/main/java/mars/tools/KeyboardAndDisplaySimulator.java
index 9ecec36..cb6c68b 100644
--- a/src/main/java/mars/tools/KeyboardAndDisplaySimulator.java
+++ b/src/main/java/mars/tools/KeyboardAndDisplaySimulator.java
@@ -1,17 +1,23 @@
- package mars.tools;
- import mars.util.Binary;
- import mars.venus.*;
- import javax.swing.*;
- import javax.swing.border.*;
- import javax.swing.event.*;
- import java.awt.*;
- import java.awt.event.*;
- import java.util.*;
- import mars.Globals;
- import mars.venus.RunSpeedPanel;
- import mars.mips.hardware.*;
- import mars.simulator.Exceptions;
- import javax.swing.text.DefaultCaret;
+package mars.tools;
+
+import mars.Globals;
+import mars.mips.hardware.*;
+import mars.simulator.Exceptions;
+import mars.util.Binary;
+import mars.venus.AbstractFontSettingDialog;
+
+import javax.swing.*;
+import javax.swing.border.TitledBorder;
+import javax.swing.event.CaretEvent;
+import javax.swing.event.CaretListener;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import javax.swing.text.DefaultCaret;
+import java.awt.*;
+import java.awt.event.*;
+import java.util.Arrays;
+import java.util.Observable;
+import java.util.Random;
/*
@@ -42,172 +48,266 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
(MIT license, http://www.opensource.org/licenses/mit-license.html)
*/
- /**
- * Keyboard and Display Simulator. It can be run either as a stand-alone Java application having
- * access to the mars package, or through MARS as an item in its Tools menu. It makes
- * maximum use of methods inherited from its abstract superclass AbstractMarsToolAndApplication.
- * Pete Sanderson
- * Version 1.0, 24 July 2008.
- * Version 1.1, 24 November 2008 corrects two omissions: (1) the tool failed to register as an observer
- * of kernel text memory when counting instruction executions for transmitter ready bit
- * reset delay, and (2) the tool failed to test the Status register's Exception Level bit before
- * raising the exception that results in the interrupt (if the Exception Level bit is 1, that
- * means an interrupt is being processed, so disable further interrupts).
- *
- * Version 1.2, August 2009, soft-codes the MMIO register locations for new memory configuration
- * feature of MARS 3.7. Previously memory segment addresses were fixed and final. Now they
- * can be modified dynamically so the tool has to get its values dynamically as well.
- *
- * Version 1.3, August 2011, corrects bug to enable Display window to scroll when needed.
- *
- * Version 1.4, August 2014, adds two features: (1) ASCII control character 12 (form feed) when
- * transmitted will clear the Display window. (2) ASCII control character 7 (bell) when
- * transmitted with properly coded (X,Y) values will reposition the cursor to the specified
- * position of a virtual text-based terminal. X represents column, Y represents row.
- */
-
- public class KeyboardAndDisplaySimulator extends AbstractMarsToolAndApplication {
-
- private static String version = "Version 1.4";
- private static String heading = "Keyboard and Display MMIO Simulator";
- private static String displayPanelTitle, keyboardPanelTitle;
- private static char VT_FILL = ' '; // fill character for virtual terminal (random access mode)
-
- public static Dimension preferredTextAreaDimension = new Dimension(400,200);
- private static Insets textAreaInsets = new Insets(4,4,4,4);
-
- // Time delay to process Transmitter Data is simulated by counting instruction executions.
- // After this many executions, the Transmitter Controller Ready bit set to 1.
- private final TransmitterDelayTechnique[] delayTechniques = {
- new FixedLengthDelay(),
- new UniformlyDistributedDelay(),
- new NormallyDistributedDelay()
- };
- public static int RECEIVER_CONTROL; // keyboard Ready in low-order bit
- public static int RECEIVER_DATA; // keyboard character in low-order byte
- public static int TRANSMITTER_CONTROL; // display Ready in low-order bit
- public static int TRANSMITTER_DATA; // display character in low-order byte
- // These are used to track instruction counts to simulate driver delay of Transmitter Data
- private boolean countingInstructions;
- private int instructionCount;
- private int transmitDelayInstructionCountLimit;
- private int currentDelayInstructionLimit;
-
- // Should the transmitted character be displayed before the transmitter delay period?
- // If not, hold onto it and print at the end of delay period.
- private int intWithCharacterToDisplay;
- private boolean displayAfterDelay = true;
-
- // Whether or not display position is sequential (JTextArea append)
- // or random access (row, column). Supports new random access feature. DPS 17-July-2014
- private boolean displayRandomAccessMode = false;
- private int rows, columns;
- private DisplayResizeAdapter updateDisplayBorder;
- private KeyboardAndDisplaySimulator simulator;
-
- // Major GUI components
- private JPanel keyboardAndDisplay;
- private JScrollPane displayScrollPane;
- private JTextArea display;
- private JPanel displayPanel, displayOptions;
- private JComboBox delayTechniqueChooser;
- private DelayLengthPanel delayLengthPanel;
- private JSlider delayLengthSlider;
- private JCheckBox displayAfterDelayCheckBox;
- private JPanel keyboardPanel;
- private JScrollPane keyAccepterScrollPane;
- private JTextArea keyEventAccepter;
- private JButton fontButton;
- private Font defaultFont = new Font(Font.MONOSPACED, Font.PLAIN, 12);
- /**
- * Simple constructor, likely used to run a stand-alone keyboard/display simulator.
- * @param title String containing title for title bar
- * @param heading String containing text for heading shown in upper part of window.
- */
- public KeyboardAndDisplaySimulator(String title, String heading) {
- super(title,heading);
- simulator = this;
- }
-
- /**
- * Simple constructor, likely used by the MARS Tools menu mechanism
- */
- public KeyboardAndDisplaySimulator() {
- super(heading + ", " + version, heading);
- simulator = this;
- }
-
-
- /**
- * Main provided for pure stand-alone use. Recommended stand-alone use is to write a
- * driver program that instantiates a KeyboardAndDisplaySimulator object then invokes its go() method.
- * "stand-alone" means it is not invoked from the MARS Tools menu. "Pure" means there
- * is no driver program to invoke the application.
- */
- public static void main(String[] args) {
- new KeyboardAndDisplaySimulator(heading+" stand-alone, "+version,heading).go();
- }
-
-
- /**
- * Required MarsTool method to return Tool name.
- * @return Tool name. MARS will display this in menu item.
- */
- public String getName() {
- return heading;
- }
-
- // Set the MMIO addresses. Prior to MARS 3.7 these were final because
- // MIPS address space was final as well. Now we will get MMIO base address
- // each time to reflect possible change in memory configuration. DPS 6-Aug-09
- protected void initializePreGUI() {
- RECEIVER_CONTROL = Memory.memoryMapBaseAddress; //0xffff0000; // keyboard Ready in low-order bit
- RECEIVER_DATA = Memory.memoryMapBaseAddress + 4; //0xffff0004; // keyboard character in low-order byte
- TRANSMITTER_CONTROL = Memory.memoryMapBaseAddress + 8; //0xffff0008; // display Ready in low-order bit
- TRANSMITTER_DATA = Memory.memoryMapBaseAddress + 12; //0xffff000c; // display character in low-order byte
- displayPanelTitle = "DISPLAY: Store to Transmitter Data "+Binary.intToHexString(TRANSMITTER_DATA);
- keyboardPanelTitle = "KEYBOARD: Characters typed here are stored to Receiver Data "+Binary.intToHexString(RECEIVER_DATA);
-
- }
-
-
- /**
- * Override the inherited method, which registers us as an Observer over the static data segment
- * (starting address 0x10010000) only.
- *
- * When user enters keystroke, set RECEIVER_CONTROL and RECEIVER_DATA using the action listener.
- * When user loads word (lw) from RECEIVER_DATA (we are notified of the read), then clear RECEIVER_CONTROL.
- * When user stores word (sw) to TRANSMITTER_DATA (we are notified of the write), then clear TRANSMITTER_CONTROL, read TRANSMITTER_DATA,
- * echo the character to display, wait for delay period, then set TRANSMITTER_CONTROL.
- *
- * If you use the inherited GUI buttons, this method is invoked when you click "Connect" button on MarsTool or the
- * "Assemble and Run" button on a Mars-based app.
- */
- protected void addAsObserver() {
- // Set transmitter Control ready bit to 1, means we're ready to accept display character.
- updateMMIOControl(TRANSMITTER_CONTROL, readyBitSet(TRANSMITTER_CONTROL));
- // We want to be an observer only of MIPS reads from RECEIVER_DATA and writes to TRANSMITTER_DATA.
- // Use the Globals.memory.addObserver() methods instead of inherited method to achieve this.
- addAsObserver(RECEIVER_DATA,RECEIVER_DATA);
- addAsObserver(TRANSMITTER_DATA, TRANSMITTER_DATA);
- // We want to be notified of each instruction execution, because instruction count is the
- // basis for delay in re-setting (literally) the TRANSMITTER_CONTROL register. SPIM does
- // this too. This simulates the time required for the display unit to process the
- // TRANSMITTER_DATA.
- addAsObserver(Memory.textBaseAddress, Memory.textLimitAddress);
- addAsObserver(Memory.kernelTextBaseAddress, Memory.kernelTextLimitAddress);
- }
-
-
- /**
- * Method that constructs the main display area. It is organized vertically
- * into two major components: the display and the keyboard. The display itself
- * is a JTextArea and it echoes characters placed into the low order byte of
- * the Transmitter Data location, 0xffff000c. They keyboard is also a JTextArea
- * places each typed character into the Receive Data location 0xffff0004.
- * @return the GUI component containing these two areas
- */
- protected JComponent buildMainDisplayArea() {
+/**
+ * Keyboard and Display Simulator. It can be run either as a stand-alone Java application having access to the mars
+ * package, or through MARS as an item in its Tools menu. It makes maximum use of methods inherited from its abstract
+ * superclass AbstractMarsToolAndApplication. Pete Sanderson
Version 1.0, 24 July 2008.
Version 1.1, 24 November
+ * 2008 corrects two omissions: (1) the tool failed to register as an observer of kernel text memory when counting
+ * instruction executions for transmitter ready bit reset delay, and (2) the tool failed to test the Status register's
+ * Exception Level bit before raising the exception that results in the interrupt (if the Exception Level bit is 1, that
+ * means an interrupt is being processed, so disable further interrupts).
+ *
+ * Version 1.2, August 2009, soft-codes the MMIO register locations for new memory configuration feature of MARS 3.7.
+ * Previously memory segment addresses were fixed and final. Now they can be modified dynamically so the tool has to
+ * get its values dynamically as well.
+ *
+ * Version 1.3, August 2011, corrects bug to enable Display window to scroll when needed.
+ *
+ * Version 1.4, August 2014, adds two features: (1) ASCII control character 12 (form feed) when transmitted will clear
+ * the Display window. (2) ASCII control character 7 (bell) when transmitted with properly coded (X,Y) values will
+ * reposition the cursor to the specified position of a virtual text-based terminal. X represents column, Y represents
+ * row.
+ */
+
+public class KeyboardAndDisplaySimulator extends AbstractMarsToolAndApplication
+{
+
+ private static final char CLEAR_SCREEN = 12; // ASCII Form Feed
+
+ private static final char SET_CURSOR_X_Y = 7; // ASCII Bell (ding ding!)
+
+ public static Dimension preferredTextAreaDimension = new Dimension(400, 200);
+
+ public static int RECEIVER_CONTROL; // keyboard Ready in low-order bit
+
+ public static int RECEIVER_DATA; // keyboard character in low-order byte
+
+ public static int TRANSMITTER_CONTROL; // display Ready in low-order bit
+
+ public static int TRANSMITTER_DATA; // display character in low-order byte
+
+ private static final String version = "Version 1.4";
+
+ private static final String heading = "Keyboard and Display MMIO Simulator";
+
+ private static String displayPanelTitle, keyboardPanelTitle;
+
+ private static final char VT_FILL = ' '; // fill character for virtual terminal (random access mode)
+
+ private static final Insets textAreaInsets = new Insets(4, 4, 4, 4);
+
+ // Time delay to process Transmitter Data is simulated by counting instruction executions.
+ // After this many executions, the Transmitter Controller Ready bit set to 1.
+ private final TransmitterDelayTechnique[] delayTechniques = {
+ new FixedLengthDelay(),
+ new UniformlyDistributedDelay(),
+ new NormallyDistributedDelay()
+ };
+
+ // These are used to track instruction counts to simulate driver delay of Transmitter Data
+ private boolean countingInstructions;
+
+ private int instructionCount;
+
+ private int transmitDelayInstructionCountLimit;
+
+ private int currentDelayInstructionLimit;
+
+ // Should the transmitted character be displayed before the transmitter delay period?
+ // If not, hold onto it and print at the end of delay period.
+ private int intWithCharacterToDisplay;
+
+ private boolean displayAfterDelay = true;
+
+ // Whether or not display position is sequential (JTextArea append)
+ // or random access (row, column). Supports new random access feature. DPS 17-July-2014
+ private boolean displayRandomAccessMode = false;
+
+ private int rows, columns;
+
+ private DisplayResizeAdapter updateDisplayBorder;
+
+ private final KeyboardAndDisplaySimulator simulator;
+
+ // Major GUI components
+ private JPanel keyboardAndDisplay;
+
+ private JScrollPane displayScrollPane;
+
+ private JTextArea display;
+
+ private JPanel displayPanel, displayOptions;
+
+ private JComboBox delayTechniqueChooser;
+
+ private DelayLengthPanel delayLengthPanel;
+
+ private JSlider delayLengthSlider;
+
+ private JCheckBox displayAfterDelayCheckBox;
+
+ private JPanel keyboardPanel;
+
+ private JScrollPane keyAccepterScrollPane;
+
+ private JTextArea keyEventAccepter;
+
+ private JButton fontButton;
+
+ private final Font defaultFont = new Font(Font.MONOSPACED, Font.PLAIN, 12);
+
+
+ /**
+ * Simple constructor, likely used to run a stand-alone keyboard/display simulator.
+ *
+ * @param title String containing title for title bar
+ * @param heading String containing text for heading shown in upper part of window.
+ */
+ public KeyboardAndDisplaySimulator(String title, String heading)
+ {
+ super(title, heading);
+ simulator = this;
+ }
+
+
+ /**
+ * Simple constructor, likely used by the MARS Tools menu mechanism
+ */
+ public KeyboardAndDisplaySimulator()
+ {
+ super(heading + ", " + version, heading);
+ simulator = this;
+ }
+
+ /**
+ * Main provided for pure stand-alone use. Recommended stand-alone use is to write a driver program that
+ * instantiates a KeyboardAndDisplaySimulator object then invokes its go() method. "stand-alone" means it is not
+ * invoked from the MARS Tools menu. "Pure" means there is no driver program to invoke the application.
+ */
+ public static void main(String[] args)
+ {
+ new KeyboardAndDisplaySimulator(heading + " stand-alone, " + version, heading).go();
+ }
+
+ /////////////////////////////////////////////////////////////////////
+ // Return value of the given MMIO control register after ready (low order) bit set (to 1).
+ // Have to preserve the value of Interrupt Enable bit (bit 1)
+ private static boolean isReadyBitSet(int mmioControlRegister)
+ {
+ try
+ {
+ return (Globals.memory.get(mmioControlRegister, Memory.WORD_LENGTH_BYTES) & 1) == 1;
+ }
+ catch (AddressErrorException aee)
+ {
+ System.out.println("Tool author specified incorrect MMIO address!" + aee);
+ System.exit(0);
+ }
+ return false; // to satisfy the compiler -- this will never happen.
+ }
+
+ /////////////////////////////////////////////////////////////////////
+ // Return value of the given MMIO control register after ready (low order) bit set (to 1).
+ // Have to preserve the value of Interrupt Enable bit (bit 1)
+ private static int readyBitSet(int mmioControlRegister)
+ {
+ try
+ {
+ return Globals.memory.get(mmioControlRegister, Memory.WORD_LENGTH_BYTES) | 1;
+ }
+ catch (AddressErrorException aee)
+ {
+ System.out.println("Tool author specified incorrect MMIO address!" + aee);
+ System.exit(0);
+ }
+ return 1; // to satisfy the compiler -- this will never happen.
+ }
+
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Rest of the protected methods. These all override do-nothing methods inherited from
+ // the abstract superclass.
+ //////////////////////////////////////////////////////////////////////////////////////
+
+ /////////////////////////////////////////////////////////////////////
+ // Return value of the given MMIO control register after ready (low order) bit cleared (to 0).
+ // Have to preserve the value of Interrupt Enable bit (bit 1). Bits 2 and higher don't matter.
+ private static int readyBitCleared(int mmioControlRegister)
+ {
+ try
+ {
+ return Globals.memory.get(mmioControlRegister, Memory.WORD_LENGTH_BYTES) & 2;
+ }
+ catch (AddressErrorException aee)
+ {
+ System.out.println("Tool author specified incorrect MMIO address!" + aee);
+ System.exit(0);
+ }
+ return 0; // to satisfy the compiler -- this will never happen.
+ }
+
+ /**
+ * Required MarsTool method to return Tool name.
+ *
+ * @return Tool name. MARS will display this in menu item.
+ */
+ public String getName()
+ {
+ return heading;
+ }
+
+ // Set the MMIO addresses. Prior to MARS 3.7 these were final because
+ // MIPS address space was final as well. Now we will get MMIO base address
+ // each time to reflect possible change in memory configuration. DPS 6-Aug-09
+ protected void initializePreGUI()
+ {
+ RECEIVER_CONTROL = Memory.memoryMapBaseAddress; //0xffff0000; // keyboard Ready in low-order bit
+ RECEIVER_DATA = Memory.memoryMapBaseAddress + 4; //0xffff0004; // keyboard character in low-order byte
+ TRANSMITTER_CONTROL = Memory.memoryMapBaseAddress + 8; //0xffff0008; // display Ready in low-order bit
+ TRANSMITTER_DATA = Memory.memoryMapBaseAddress + 12; //0xffff000c; // display character in low-order byte
+ displayPanelTitle = "DISPLAY: Store to Transmitter Data " + Binary.intToHexString(TRANSMITTER_DATA);
+ keyboardPanelTitle = "KEYBOARD: Characters typed here are stored to Receiver Data " + Binary.intToHexString(RECEIVER_DATA);
+
+ }
+
+ /**
+ * Override the inherited method, which registers us as an Observer over the static data segment (starting address
+ * 0x10010000) only.
+ *
+ * When user enters keystroke, set RECEIVER_CONTROL and RECEIVER_DATA using the action listener. When user loads
+ * word (lw) from RECEIVER_DATA (we are notified of the read), then clear RECEIVER_CONTROL. When user stores word
+ * (sw) to TRANSMITTER_DATA (we are notified of the write), then clear TRANSMITTER_CONTROL, read TRANSMITTER_DATA,
+ * echo the character to display, wait for delay period, then set TRANSMITTER_CONTROL.
+ *
+ * If you use the inherited GUI buttons, this method is invoked when you click "Connect" button on MarsTool or the
+ * "Assemble and Run" button on a Mars-based app.
+ */
+ protected void addAsObserver()
+ {
+ // Set transmitter Control ready bit to 1, means we're ready to accept display character.
+ updateMMIOControl(TRANSMITTER_CONTROL, readyBitSet(TRANSMITTER_CONTROL));
+ // We want to be an observer only of MIPS reads from RECEIVER_DATA and writes to TRANSMITTER_DATA.
+ // Use the Globals.memory.addObserver() methods instead of inherited method to achieve this.
+ addAsObserver(RECEIVER_DATA, RECEIVER_DATA);
+ addAsObserver(TRANSMITTER_DATA, TRANSMITTER_DATA);
+ // We want to be notified of each instruction execution, because instruction count is the
+ // basis for delay in re-setting (literally) the TRANSMITTER_CONTROL register. SPIM does
+ // this too. This simulates the time required for the display unit to process the
+ // TRANSMITTER_DATA.
+ addAsObserver(Memory.textBaseAddress, Memory.textLimitAddress);
+ addAsObserver(Memory.kernelTextBaseAddress, Memory.kernelTextLimitAddress);
+ }
+
+ /**
+ * Method that constructs the main display area. It is organized vertically into two major components: the display
+ * and the keyboard. The display itself is a JTextArea and it echoes characters placed into the low order byte of
+ * the Transmitter Data location, 0xffff000c. They keyboard is also a JTextArea places each typed character into
+ * the Receive Data location 0xffff0004.
+ *
+ * @return the GUI component containing these two areas
+ */
+ protected JComponent buildMainDisplayArea()
+ {
// Changed arrangement of the display and keyboard panels from GridLayout(2,1)
// to BorderLayout to hold a JSplitPane containing both panels. This permits user
// to apportion the relative sizes of the display and keyboard panels within
@@ -215,173 +315,201 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// display positioning feature. Previously, both the display and the keyboard
// text areas were equal in size and there was no way for the user to change that.
// DPS 17-July-2014
- keyboardAndDisplay = new JPanel(new BorderLayout());
- JSplitPane both = new JSplitPane(JSplitPane.VERTICAL_SPLIT, buildDisplay(),buildKeyboard());
- both.setResizeWeight(0.5);
- keyboardAndDisplay.add(both);
- return keyboardAndDisplay;
- }
-
-
- //////////////////////////////////////////////////////////////////////////////////////
- // Rest of the protected methods. These all override do-nothing methods inherited from
- // the abstract superclass.
- //////////////////////////////////////////////////////////////////////////////////////
-
- /**
- * Update display when connected MIPS program accesses (data) memory.
- * @param memory the attached memory
- * @param accessNotice information provided by memory in MemoryAccessNotice object
- */
- protected void processMIPSUpdate(Observable memory, AccessNotice accessNotice) {
- MemoryAccessNotice notice = (MemoryAccessNotice) accessNotice;
- // If MIPS program has just read (loaded) the receiver (keyboard) data register,
- // then clear the Ready bit to indicate there is no longer a keystroke available.
- // If Ready bit was initially clear, they'll get the old keystroke -- serves 'em right
- // for not checking!
- if (notice.getAddress()==RECEIVER_DATA && notice.getAccessType()==AccessNotice.READ) {
+ keyboardAndDisplay = new JPanel(new BorderLayout());
+ JSplitPane both = new JSplitPane(JSplitPane.VERTICAL_SPLIT, buildDisplay(), buildKeyboard());
+ both.setResizeWeight(0.5);
+ keyboardAndDisplay.add(both);
+ return keyboardAndDisplay;
+ }
+
+ /**
+ * Update display when connected MIPS program accesses (data) memory.
+ *
+ * @param memory the attached memory
+ * @param accessNotice information provided by memory in MemoryAccessNotice object
+ */
+ protected void processMIPSUpdate(Observable memory, AccessNotice accessNotice)
+ {
+ MemoryAccessNotice notice = (MemoryAccessNotice) accessNotice;
+ // If MIPS program has just read (loaded) the receiver (keyboard) data register,
+ // then clear the Ready bit to indicate there is no longer a keystroke available.
+ // If Ready bit was initially clear, they'll get the old keystroke -- serves 'em right
+ // for not checking!
+ if (notice.getAddress() == RECEIVER_DATA && notice.getAccessType() == AccessNotice.READ)
+ {
updateMMIOControl(RECEIVER_CONTROL, readyBitCleared(RECEIVER_CONTROL));
- }
- // MIPS program has just written (stored) the transmitter (display) data register. If transmitter
- // Ready bit is clear, device is not ready yet so ignore this event -- serves 'em right for not checking!
- // If transmitter Ready bit is set, then clear it to indicate the display device is processing the character.
- // Also start an intruction counter that will simulate the delay of the slower
- // display device processing the character.
- if (isReadyBitSet(TRANSMITTER_CONTROL) && notice.getAddress()==TRANSMITTER_DATA && notice.getAccessType()==AccessNotice.WRITE) {
+ }
+ // MIPS program has just written (stored) the transmitter (display) data register. If transmitter
+ // Ready bit is clear, device is not ready yet so ignore this event -- serves 'em right for not checking!
+ // If transmitter Ready bit is set, then clear it to indicate the display device is processing the character.
+ // Also start an intruction counter that will simulate the delay of the slower
+ // display device processing the character.
+ if (isReadyBitSet(TRANSMITTER_CONTROL) && notice.getAddress() == TRANSMITTER_DATA && notice.getAccessType() == AccessNotice.WRITE)
+ {
updateMMIOControl(TRANSMITTER_CONTROL, readyBitCleared(TRANSMITTER_CONTROL));
intWithCharacterToDisplay = notice.getValue();
- if (!displayAfterDelay) displayCharacter(intWithCharacterToDisplay);
+ if (!displayAfterDelay)
+ {
+ displayCharacter(intWithCharacterToDisplay);
+ }
this.countingInstructions = true;
this.instructionCount = 0;
this.transmitDelayInstructionCountLimit = generateDelay();
- }
- // We have been notified of a MIPS instruction execution.
- // If we are in transmit delay period, increment instruction count and if limit
- // has been reached, set the transmitter Ready flag to indicate the MIPS program
- // can write another character to the transmitter data register. If the Interrupt-Enabled
- // bit had been set by the MIPS program, generate an interrupt!
- if ( this.countingInstructions &&
- notice.getAccessType()==AccessNotice.READ &&
- (Memory.inTextSegment(notice.getAddress()) || Memory.inKernelTextSegment(notice.getAddress()))) {
+ }
+ // We have been notified of a MIPS instruction execution.
+ // If we are in transmit delay period, increment instruction count and if limit
+ // has been reached, set the transmitter Ready flag to indicate the MIPS program
+ // can write another character to the transmitter data register. If the Interrupt-Enabled
+ // bit had been set by the MIPS program, generate an interrupt!
+ if (this.countingInstructions &&
+ notice.getAccessType() == AccessNotice.READ &&
+ (Memory.inTextSegment(notice.getAddress()) || Memory.inKernelTextSegment(notice.getAddress())))
+ {
this.instructionCount++;
- if (this.instructionCount >= this.transmitDelayInstructionCountLimit) {
- if (displayAfterDelay) displayCharacter(intWithCharacterToDisplay);
- this.countingInstructions = false;
- int updatedTransmitterControl = readyBitSet(TRANSMITTER_CONTROL);
- updateMMIOControl(TRANSMITTER_CONTROL, updatedTransmitterControl);
- if (updatedTransmitterControl != 1
- && (Coprocessor0.getValue(Coprocessor0.STATUS) & 2)==0 // Added by Carl Hauser Nov 2008
- && (Coprocessor0.getValue(Coprocessor0.STATUS) & 1)==1) {
- // interrupt-enabled bit is set in both Tranmitter Control and in
- // Coprocessor0 Status register, and Interrupt Level Bit is 0, so trigger external interrupt.
- mars.simulator.Simulator.externalInterruptingDevice = Exceptions.EXTERNAL_INTERRUPT_DISPLAY;
- }
+ if (this.instructionCount >= this.transmitDelayInstructionCountLimit)
+ {
+ if (displayAfterDelay)
+ {
+ displayCharacter(intWithCharacterToDisplay);
+ }
+ this.countingInstructions = false;
+ int updatedTransmitterControl = readyBitSet(TRANSMITTER_CONTROL);
+ updateMMIOControl(TRANSMITTER_CONTROL, updatedTransmitterControl);
+ if (updatedTransmitterControl != 1
+ && (Coprocessor0.getValue(Coprocessor0.STATUS) & 2) == 0 // Added by Carl Hauser Nov 2008
+ && (Coprocessor0.getValue(Coprocessor0.STATUS) & 1) == 1)
+ {
+ // interrupt-enabled bit is set in both Tranmitter Control and in
+ // Coprocessor0 Status register, and Interrupt Level Bit is 0, so trigger external interrupt.
+ mars.simulator.Simulator.externalInterruptingDevice = Exceptions.EXTERNAL_INTERRUPT_DISPLAY;
+ }
}
- }
- }
-
- private static final char CLEAR_SCREEN = 12; // ASCII Form Feed
- private static final char SET_CURSOR_X_Y = 7; // ASCII Bell (ding ding!)
-
- // Method to display the character stored in the low-order byte of
- // the parameter. We also recognize two non-printing characters:
- // Decimal 12 (Ascii Form Feed) to clear the display
- // Decimal 7 (Ascii Bell) to place the cursor at a specified (X,Y) position.
- // of a virtual text terminal. The position is specified in the high
- // order 24 bits of the transmitter word (X in 20-31, Y in 8-19).
- // Thus the parameter is the entire word, not just the low-order byte.
- // Once the latter is performed, the display mode changes to random
- // access, which has repercussions for the implementation of character display.
- private void displayCharacter(int intWithCharacterToDisplay) {
- char characterToDisplay = (char) (intWithCharacterToDisplay & 0x000000FF);
- if (characterToDisplay == CLEAR_SCREEN) {
+ }
+ }
+
+ // Method to display the character stored in the low-order byte of
+ // the parameter. We also recognize two non-printing characters:
+ // Decimal 12 (Ascii Form Feed) to clear the display
+ // Decimal 7 (Ascii Bell) to place the cursor at a specified (X,Y) position.
+ // of a virtual text terminal. The position is specified in the high
+ // order 24 bits of the transmitter word (X in 20-31, Y in 8-19).
+ // Thus the parameter is the entire word, not just the low-order byte.
+ // Once the latter is performed, the display mode changes to random
+ // access, which has repercussions for the implementation of character display.
+ private void displayCharacter(int intWithCharacterToDisplay)
+ {
+ char characterToDisplay = (char) (intWithCharacterToDisplay & 0x000000FF);
+ if (characterToDisplay == CLEAR_SCREEN)
+ {
initializeDisplay(displayRandomAccessMode);
- }
- else if (characterToDisplay == SET_CURSOR_X_Y) {
- // First call will activate random access mode.
- // We're using JTextArea, where caret has to be within text.
- // So initialize text to all spaces to fill the JTextArea to its
- // current capacity. Then set caret. Subsequent character
- // displays will replace, not append, in the text.
- if (!displayRandomAccessMode) {
- displayRandomAccessMode = true;
- initializeDisplay(displayRandomAccessMode);
+ }
+ else if (characterToDisplay == SET_CURSOR_X_Y)
+ {
+ // First call will activate random access mode.
+ // We're using JTextArea, where caret has to be within text.
+ // So initialize text to all spaces to fill the JTextArea to its
+ // current capacity. Then set caret. Subsequent character
+ // displays will replace, not append, in the text.
+ if (!displayRandomAccessMode)
+ {
+ displayRandomAccessMode = true;
+ initializeDisplay(displayRandomAccessMode);
}
- // For SET_CURSOR_X_Y, we need data from the rest of the word.
- // High order 3 bytes are split in half to store (X,Y) value.
- // High 12 bits contain X value, next 12 bits contain Y value.
+ // For SET_CURSOR_X_Y, we need data from the rest of the word.
+ // High order 3 bytes are split in half to store (X,Y) value.
+ // High 12 bits contain X value, next 12 bits contain Y value.
int x = (intWithCharacterToDisplay & 0xFFF00000) >>> 20;
- int y = (intWithCharacterToDisplay & 0x000FFF00) >>> 8;
- // If X or Y values are outside current range, set to range limit.
- if (x<0) x=0;
- if (x>=columns) x=columns-1;
- if (y<0) y=0;
- if (y>=rows) y=rows-1;
- // display is a JTextArea whose character positioning in the text is linear.
- // Converting (row,column) to linear position requires knowing how many columns
- // are in each row. I add one because each row except the last ends with '\n' that
- // does not count as a column but occupies a position in the text string.
- // The values of rows and columns is set in initializeDisplay().
- display.setCaretPosition( y*(columns+1) + x);
- }
- else {
- if (displayRandomAccessMode) {
- try {
- int caretPosition = display.getCaretPosition();
- // if caret is positioned at the end of a line (at the '\n'), skip over the '\n'
- if ( (caretPosition+1) % (columns+1) == 0) {
- caretPosition++;
- display.setCaretPosition(caretPosition);
- }
- display.replaceRange(""+characterToDisplay, caretPosition, caretPosition+1);
- }
- catch (IllegalArgumentException e) {
- // tried to write off the end of the defined grid.
- display.setCaretPosition(display.getCaretPosition()-1);
- display.replaceRange(""+characterToDisplay,display.getCaretPosition(),display.getCaretPosition()+1);
- }
- }
- else {
- display.append(""+characterToDisplay);
+ int y = (intWithCharacterToDisplay & 0x000FFF00) >>> 8;
+ // If X or Y values are outside current range, set to range limit.
+ if (x < 0)
+ {
+ x = 0;
}
- }
- }
-
- /**
- * Initialization code to be executed after the GUI is configured. Overrides inherited default.
- */
-
- protected void initializePostGUI() {
- initializeTransmitDelaySimulator();
- keyEventAccepter.requestFocusInWindow();
- }
-
-
- /**
- * Method to reset counters and display when the Reset button selected.
- * Overrides inherited method that does nothing.
- */
- protected void reset() {
- displayRandomAccessMode = false;
- initializeTransmitDelaySimulator();
- initializeDisplay(displayRandomAccessMode);
- keyEventAccepter.setText("");
- ((TitledBorder)displayPanel.getBorder()).setTitle(displayPanelTitle);
- displayPanel.repaint();
- keyEventAccepter.requestFocusInWindow();
- updateMMIOControl(TRANSMITTER_CONTROL, readyBitSet(TRANSMITTER_CONTROL));
- }
-
-
- // The display JTextArea (top half) is initialized either to the empty
- // string, or to a string filled with lines of spaces. It will do the
- // latter only if the MIPS program has sent the BELL character (Ascii 7) to
- // the transmitter. This sets the caret (cursor) to a specific (x,y) position
- // on a text-based virtual display. The lines of spaces is necessary because
- // the caret can only be placed at a position within the current text string.
- private void initializeDisplay(boolean randomAccess) {
- String initialText = "";
- if (randomAccess) {
+ if (x >= columns)
+ {
+ x = columns - 1;
+ }
+ if (y < 0)
+ {
+ y = 0;
+ }
+ if (y >= rows)
+ {
+ y = rows - 1;
+ }
+ // display is a JTextArea whose character positioning in the text is linear.
+ // Converting (row,column) to linear position requires knowing how many columns
+ // are in each row. I add one because each row except the last ends with '\n' that
+ // does not count as a column but occupies a position in the text string.
+ // The values of rows and columns is set in initializeDisplay().
+ display.setCaretPosition(y * (columns + 1) + x);
+ }
+ else
+ {
+ if (displayRandomAccessMode)
+ {
+ try
+ {
+ int caretPosition = display.getCaretPosition();
+ // if caret is positioned at the end of a line (at the '\n'), skip over the '\n'
+ if ((caretPosition + 1) % (columns + 1) == 0)
+ {
+ caretPosition++;
+ display.setCaretPosition(caretPosition);
+ }
+ display.replaceRange("" + characterToDisplay, caretPosition, caretPosition + 1);
+ }
+ catch (IllegalArgumentException e)
+ {
+ // tried to write off the end of the defined grid.
+ display.setCaretPosition(display.getCaretPosition() - 1);
+ display.replaceRange("" + characterToDisplay, display.getCaretPosition(), display.getCaretPosition() + 1);
+ }
+ }
+ else
+ {
+ display.append("" + characterToDisplay);
+ }
+ }
+ }
+
+ /**
+ * Initialization code to be executed after the GUI is configured. Overrides inherited default.
+ */
+
+ protected void initializePostGUI()
+ {
+ initializeTransmitDelaySimulator();
+ keyEventAccepter.requestFocusInWindow();
+ }
+
+ /**
+ * Method to reset counters and display when the Reset button selected. Overrides inherited method that does
+ * nothing.
+ */
+ protected void reset()
+ {
+ displayRandomAccessMode = false;
+ initializeTransmitDelaySimulator();
+ initializeDisplay(displayRandomAccessMode);
+ keyEventAccepter.setText("");
+ ((TitledBorder) displayPanel.getBorder()).setTitle(displayPanelTitle);
+ displayPanel.repaint();
+ keyEventAccepter.requestFocusInWindow();
+ updateMMIOControl(TRANSMITTER_CONTROL, readyBitSet(TRANSMITTER_CONTROL));
+ }
+
+ // The display JTextArea (top half) is initialized either to the empty
+ // string, or to a string filled with lines of spaces. It will do the
+ // latter only if the MIPS program has sent the BELL character (Ascii 7) to
+ // the transmitter. This sets the caret (cursor) to a specific (x,y) position
+ // on a text-based virtual display. The lines of spaces is necessary because
+ // the caret can only be placed at a position within the current text string.
+ private void initializeDisplay(boolean randomAccess)
+ {
+ String initialText = "";
+ if (randomAccess)
+ {
Dimension textDimensions = getDisplayPanelTextDimensions();
columns = (int) textDimensions.getWidth();
rows = (int) textDimensions.getHeight();
@@ -390,458 +518,463 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Arrays.fill(charArray, VT_FILL);
String row = new String(charArray);
StringBuffer str = new StringBuffer(row);
- for (int i=1; i North (up), 90 --> East (right), etc.
- private boolean MarsBotLeaveTrack = false; // true --> leave track when moving, false --> do not ...
- private double MarsBotXPosition = 0; // X pixel position of MarsBot
- private double MarsBotYPosition = 0; // Y pixel position of MarsBot
- private boolean MarsBotMoving = false; // true --> MarsBot is moving, false --> MarsBot not moving
-
+public class MarsBot implements Observer, MarsTool
+{
+ private static final int GRAPHIC_WIDTH = 512;
+
+ private static final int GRAPHIC_HEIGHT = 512;
+
+ private static final int ADDR_HEADING = 0xffff8010;
+
+ private static final int ADDR_LEAVETRACK = 0xffff8020;
+
+ private static final int ADDR_WHEREAREWEX = 0xffff8030;
+
+ private static final int ADDR_WHEREAREWEY = 0xffff8040;
+
+ private static final int ADDR_MOVE = 0xffff8050;
+
// The begin and end points of a "track" segment are kept in neighboring pairs
// of elements of the array. arrayOfTrack[i] is the start pt, arrayOfTrack[i+1] is
// the end point of a path that should leave a track.
- private final int trackPts = 256; // TBD Hardcoded. Array contains start-end points for segments in track.
- private Point[] arrayOfTrack = new Point[trackPts];
- private int trackIndex = 0;
-
+ private final int trackPts = 256; // TBD Hardcoded. Array contains start-end points for segments in track.
+
+ private MarsBotDisplay graphicArea;
+
+ private int MarsBotHeading = 0; // 0 --> North (up), 90 --> East (right), etc.
+
+ private boolean MarsBotLeaveTrack = false; // true --> leave track when moving, false --> do not ...
+
+ private double MarsBotXPosition = 0; // X pixel position of MarsBot
+
+ private double MarsBotYPosition = 0; // Y pixel position of MarsBot
+
+ private boolean MarsBotMoving = false; // true --> MarsBot is moving, false --> MarsBot not moving
+
+ private final Point[] arrayOfTrack = new Point[trackPts];
+
+ private int trackIndex = 0;
+
+ public String getName()
+ {
+ return "Mars Bot";
+ }
+
+ /*
+ * This will set up the Bot's GUI. Invoked when Bot menu item selected.
+ */
+ public void action()
+ {
+ BotRunnable br1 = new BotRunnable();
+ Thread t1 = new Thread(br1);
+ t1.start();
+ // New: DPS 27 Feb 2006. Register observer for memory subrange.
+ try
+ {
+ Globals.memory.addObserver(this, 0xffff8000, 0xffff8060);
+ }
+ catch (AddressErrorException aee)
+ {
+ System.out.println(aee);
+ }
+ }
+
+ /* ------------------------------------------------------------------------- */
+
+ /*
+ * This method observes MIPS program directives to modify Bot activity (that is,
+ * MIPS program write to MMIO) and updates instance variables to reflect that
+ * directive.
+ */
+ public void update(Observable o, Object arg)
+ {
+ MemoryAccessNotice notice;
+ int address;
+ if (arg instanceof MemoryAccessNotice)
+ {
+ notice = (MemoryAccessNotice) arg;
+ address = notice.getAddress();
+ if (address < 0 && notice.getAccessType() == AccessNotice.WRITE)
+ {
+ String message = "";
+ if (address == ADDR_HEADING)
+ {
+ message = "MarsBot.update: got move heading value: ";
+ MarsBotHeading = notice.getValue();
+ //System.out.println(message + notice.getValue() );
+ }
+ else if (address == ADDR_LEAVETRACK)
+ {
+ message = "MarsBot.update: got leave track directive value ";
+
+ // If we HAD NOT been leaving a track, but we should NOW leave
+ // a track, put start point into array.
+ if (!MarsBotLeaveTrack && notice.getValue() == 1)
+ {
+ MarsBotLeaveTrack = true;
+ arrayOfTrack[trackIndex] = new Point((int) MarsBotXPosition, (int) MarsBotYPosition);
+ trackIndex++; // the index of the end point
+ }
+ // If we HAD NOT been leaving a track, and get another directive
+ // to NOT leave a track, do nothing (nothing to do).
+ else if (!MarsBotLeaveTrack && notice.getValue() == 0)
+ {
+ // NO ACTION
+ }
+ // If we HAD been leaving a track, and get another directive
+ // to LEAVE a track, do nothing (nothing to do).
+ else if (MarsBotLeaveTrack && notice.getValue() == 1)
+ {
+ // NO ACTION
+ }
+ // If we HAD been leaving a track, and get another directive
+ // to NOT leave a track, put end point into array.
+ else if (MarsBotLeaveTrack && notice.getValue() == 0)
+ {
+ MarsBotLeaveTrack = false;
+ arrayOfTrack[trackIndex] = new Point((int) MarsBotXPosition, (int) MarsBotYPosition);
+ trackIndex++; // the index of the next start point
+ }
+
+ //System.out.println("MarsBotDisplay.paintComponent: putting point in track array at " + trackIndex);
+
+ //System.out.println(message + notice.getValue() );
+ }
+ else if (address == ADDR_MOVE)
+ {
+ message = "MarsBot.update: got move control value: ";
+ MarsBotMoving = notice.getValue() != 0;
+ //System.out.println(message + notice.getValue() );
+ }
+ else if (address == ADDR_WHEREAREWEX ||
+ address == ADDR_WHEREAREWEY)
+ {
+ // Ignore these memory writes, because the writes originated within
+ // this tool. This tool is being notified of the writes in the usual
+ // manner, but the writes are already known to this tool.
+ // NO ACTION
+ }
+ else
+ {
+ //message = "MarsBot.update: HEY!!! unknown address of " + Integer.toString(address) + ", value: ";
+ //System.out.println(message + notice.getValue() );
+ }
+
+ }
+ }
+
+ }
+
// private inner class
- private class BotRunnable implements Runnable
- {
- JPanel panel;
- public BotRunnable() // constructor
- {
+ private class BotRunnable implements Runnable
+ {
+ JPanel panel;
+
+ public BotRunnable() // constructor
+ {
final JFrame frame = new JFrame("Bot");
panel = new JPanel(new BorderLayout());
graphicArea = new MarsBotDisplay(GRAPHIC_WIDTH, GRAPHIC_HEIGHT);
JPanel buttonPanel = new JPanel();
JButton clearButton = new JButton("Clear");
clearButton.addActionListener(
- new ActionListener()
- {
- public void actionPerformed(ActionEvent e)
- {
+ new ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
graphicArea.clear();
MarsBotLeaveTrack = false; // true --> leave track when moving, false --> do not ...
MarsBotXPosition = 0; // X pixel position of MarsBot
MarsBotYPosition = 0; // Y pixel position of MarsBot
MarsBotMoving = false; // true --> MarsBot is moving, false --> MarsBot not moving
-
+
trackIndex = 0;
-
- }
-
- });
+
+ }
+
+ });
buttonPanel.add(clearButton);
JButton closeButton = new JButton("Close");
closeButton.addActionListener(
- new ActionListener()
- {
- public void actionPerformed(ActionEvent e)
- {
+ new ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
frame.setVisible(false);
-
- }
-
- });
+
+ }
+
+ });
buttonPanel.add(closeButton);
panel.add(graphicArea, BorderLayout.CENTER);
panel.add(buttonPanel, BorderLayout.SOUTH);
@@ -82,19 +213,19 @@
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); // changed 12/12/09 DPS (was EXIT)
frame.setSize(GRAPHIC_WIDTH + 200, GRAPHIC_HEIGHT + 100); // TBD SIZE
frame.setVisible(true); // show();
-
- } // end BotRunnable() constructor
-
- public void run()
- {
-
+
+ } // end BotRunnable() constructor
+
+ public void run()
+ {
+
double tempAngle;
// infinite loop: move the bot according to the current directives
// (which may be to NOT move)
do
{
- if (MarsBotMoving)
- {
+ if (MarsBotMoving)
+ {
//System.out.println("BotRunnable.run: bot IS moving.");
// TBD This is an arbitrary distance for bot movement. This could just
// as easily be a random distance to simulate terrain, etc.
@@ -102,99 +233,102 @@
// The "mathematical angle" is zero at east, 90 at north, etc.
// The "heading" is 0 at north, 90 at east, etc.
// Conversion: MathAngle = [(360 - heading) + 90] mod 360
- tempAngle = ((360 - MarsBotHeading) + 90) % 360;
- MarsBotXPosition += Math.cos(Math.toRadians(tempAngle)); // Math.cos parameter unit is radians
- MarsBotYPosition += -Math.sin(Math.toRadians(tempAngle)); // Negate value because Y coord grows down
-
+ tempAngle = ((360 - MarsBotHeading) + 90) % 360;
+ MarsBotXPosition += Math.cos(Math.toRadians(tempAngle)); // Math.cos parameter unit is radians
+ MarsBotYPosition += -Math.sin(Math.toRadians(tempAngle)); // Negate value because Y coord grows down
+
// Write this new information to MARS memory area
- try
- {
- Globals.memory.setWord(ADDR_WHEREAREWEX, (int) MarsBotXPosition);
- Globals.memory.setWord(ADDR_WHEREAREWEY, (int) MarsBotYPosition);
-
- }
- catch ( AddressErrorException e)
- {
+ try
+ {
+ Globals.memory.setWord(ADDR_WHEREAREWEX, (int) MarsBotXPosition);
+ Globals.memory.setWord(ADDR_WHEREAREWEY, (int) MarsBotYPosition);
+
+ }
+ catch (AddressErrorException e)
+ {
// TBD TBD TBD No action
- }
-
+ }
+
//System.out.println(" ------- Heading is " + MarsBotHeading + ", angle is " + tempAngle);
//System.out.println(" ------- New X,Y is (" + MarsBotXPosition + "," + MarsBotYPosition + ")" );
-
+
// Whether or not we're leaving a track, write the current point to the
// current position in the array.
// -- If we are not leaving a track now, we will need the current point to
// start a future track, and that goes into the array.
// -- If we are leaving a track now, the current point may end the track,
// and that goes into the array.
- arrayOfTrack[trackIndex] = new Point((int)MarsBotXPosition, (int)MarsBotYPosition);
-
- }
- else
- {
+ arrayOfTrack[trackIndex] = new Point((int) MarsBotXPosition, (int) MarsBotYPosition);
+
+ }
+ else
+ {
// Action for if the MarsBot isn't moving
// System.out.println("BotRunnable.run: bot is not moving.");
- }
-
+ }
+
// TBD Pause whether the bot is or is not moving. This gives the MIPS program
// opportunity to consider results of movement, or to make the bot move.
// ??? What is relationship of robot speed to MARS's
// execution time for a single instruction? Does the robot speed have to
// be slow enough to allow a MARS busy loop to detect the bot position
// at a specific pixel?
- try
- {
+ try
+ {
//System.out.println(" Hello from the bot runner");
- Thread.sleep(40);
- }
- catch (InterruptedException exception)
- {// no action
- }
-
- panel.repaint(); // show new bot position
- } while (true);
-
- } // end run method of BotRunnable class
-
- } // end BotRunnable class
-
+ Thread.sleep(40);
+ }
+ catch (InterruptedException exception)
+ {// no action
+ }
+
+ panel.repaint(); // show new bot position
+ }
+ while (true);
+
+ } // end run method of BotRunnable class
+
+ } // end BotRunnable class
+
/* ------------------------------------------------------------------------- */
- private class MarsBotDisplay extends JPanel
- {
- private int width;
- private int height;
- private boolean clearTheDisplay = true;
-
-
- public MarsBotDisplay(int tw, int th)
- {
+ private class MarsBotDisplay extends JPanel
+ {
+ private final int width;
+
+ private final int height;
+
+ private boolean clearTheDisplay = true;
+
+
+ public MarsBotDisplay(int tw, int th)
+ {
width = tw;
height = th;
-
- }
-
- public void redraw()
- {
+
+ }
+
+ public void redraw()
+ {
repaint();
- }
-
- public void clear()
- {
+ }
+
+ public void clear()
+ {
// clear the graphic display
clearTheDisplay = true;
//System.out.println("MarsBotDisplay.clear: called to clear the display");
repaint();
- }
-
- public void paintComponent(Graphics g)
- {
+ }
+
+ public void paintComponent(Graphics g)
+ {
long tempN;
// System.out.println("MarsBotDisplay.paintComponent: I'm painting! n is " + n);
-
-
+
+
// Recover Graphics2D
Graphics2D g2 = (Graphics2D) g;
-
+
/*
if (clearTheDisplay)
{
@@ -203,30 +337,30 @@
clearTheDisplay = false;
}
*/
-
+
// Draw the track left behind, for each segment of the path
g2.setColor(Color.blue);
for (int i = 1; i <= trackIndex; i += 2) // Index grows by two (begin-end pair)
{
- //System.out.print(".");
- try
- {
- g2.drawLine((int)arrayOfTrack[i-1].getX(), (int)arrayOfTrack[i-1].getY(),
- (int)arrayOfTrack[i].getX(), (int)arrayOfTrack[i].getY() );
- }
- catch (ArrayIndexOutOfBoundsException e)
- {
- // No action TBD sloppy
- }
- catch (NullPointerException e)
- {
- // No action TBD sloppy
- }
+ //System.out.print(".");
+ try
+ {
+ g2.drawLine((int) arrayOfTrack[i - 1].getX(), (int) arrayOfTrack[i - 1].getY(),
+ (int) arrayOfTrack[i].getX(), (int) arrayOfTrack[i].getY());
+ }
+ catch (ArrayIndexOutOfBoundsException e)
+ {
+ // No action TBD sloppy
+ }
+ catch (NullPointerException e)
+ {
+ // No action TBD sloppy
+ }
}
-
+
g2.setColor(Color.black);
g2.fillRect((int) MarsBotXPosition, (int) MarsBotYPosition, 20, 20); // Draw bot at its current position
-
+
/*
g2.setColor(Color.blue);
g2.setFont(new Font(g2.getFont().getName(), g2.getFont().getStyle(), 20) ); // same font and style in larger size
@@ -236,121 +370,11 @@
60);
g2.drawString(" " + n, width/2, height/2);
*/
-
-
- }
-
- } // end private inner class MarsBotDisplay
-
- /* ------------------------------------------------------------------------- */
-
-
- public String getName()
- {
- return "Mars Bot";
- }
-
- /*
- * This will set up the Bot's GUI. Invoked when Bot menu item selected.
- */
- public void action()
- {
- BotRunnable br1 = new BotRunnable();
- Thread t1 = new Thread(br1);
- t1.start();
- // New: DPS 27 Feb 2006. Register observer for memory subrange.
- try {
- Globals.memory.addObserver(this,0xffff8000,0xffff8060);
- }
- catch (AddressErrorException aee) {
- System.out.println(aee);
- }
- }
-
- /*
- * This method observes MIPS program directives to modify Bot activity (that is,
- * MIPS program write to MMIO) and updates instance variables to reflect that
- * directive.
- */
- public void update(Observable o, Object arg)
- {
- MemoryAccessNotice notice;
- int address;
- if (arg instanceof MemoryAccessNotice)
- {
- notice = (MemoryAccessNotice) arg;
- address = notice.getAddress();
- if (address < 0 && notice.getAccessType() == AccessNotice.WRITE)
- {
- String message = "";
- if (address == ADDR_HEADING)
- {
- message = "MarsBot.update: got move heading value: ";
- MarsBotHeading = notice.getValue();
- //System.out.println(message + notice.getValue() );
- }
- else if (address == ADDR_LEAVETRACK)
- {
- message = "MarsBot.update: got leave track directive value ";
-
- // If we HAD NOT been leaving a track, but we should NOW leave
- // a track, put start point into array.
- if (MarsBotLeaveTrack == false && notice.getValue() == 1)
- {
- MarsBotLeaveTrack = true;
- arrayOfTrack[trackIndex] = new Point((int) MarsBotXPosition, (int) MarsBotYPosition);
- trackIndex++; // the index of the end point
- }
- // If we HAD NOT been leaving a track, and get another directive
- // to NOT leave a track, do nothing (nothing to do).
- else if (MarsBotLeaveTrack == false && notice.getValue() == 0)
- {
- // NO ACTION
- }
- // If we HAD been leaving a track, and get another directive
- // to LEAVE a track, do nothing (nothing to do).
- else if (MarsBotLeaveTrack == true && notice.getValue() == 1)
- {
- // NO ACTION
- }
- // If we HAD been leaving a track, and get another directive
- // to NOT leave a track, put end point into array.
- else if (MarsBotLeaveTrack == true && notice.getValue() == 0)
- {
- MarsBotLeaveTrack = false;
- arrayOfTrack[trackIndex] = new Point((int) MarsBotXPosition, (int) MarsBotYPosition);
- trackIndex++; // the index of the next start point
- }
-
- //System.out.println("MarsBotDisplay.paintComponent: putting point in track array at " + trackIndex);
-
- //System.out.println(message + notice.getValue() );
- }
- else if (address == ADDR_MOVE)
- {
- message = "MarsBot.update: got move control value: ";
- if (notice.getValue() == 0) MarsBotMoving = false;
- else MarsBotMoving = true;
- //System.out.println(message + notice.getValue() );
- }
- else if (address == ADDR_WHEREAREWEX ||
- address == ADDR_WHEREAREWEY)
- {
- // Ignore these memory writes, because the writes originated within
- // this tool. This tool is being notified of the writes in the usual
- // manner, but the writes are already known to this tool.
- // NO ACTION
- }
- else
- {
- //message = "MarsBot.update: HEY!!! unknown address of " + Integer.toString(address) + ", value: ";
- //System.out.println(message + notice.getValue() );
- }
-
- }
- }
-
- }
-
- }
+
+
+ }
+
+ } // end private inner class MarsBotDisplay
+
+}
diff --git a/src/main/java/mars/tools/MarsTool.java b/src/main/java/mars/tools/MarsTool.java
index 46a758d..3c4ab86 100644
--- a/src/main/java/mars/tools/MarsTool.java
+++ b/src/main/java/mars/tools/MarsTool.java
@@ -29,37 +29,30 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
-/**
- * Interface for any tool that interacts with an executing MIPS program.
- * A qualifying tool must be a class in the Tools package that
- * implements the MarsTool interface, must be compiled into a .class file,
- * and its .class file must be in the same Tools folder as MarsTool.class.
- * Mars will detect a qualifying tool upon startup, create an instance
- * using its no-argument constructor and add it to its Tools menu.
- * When its menu item is selected, the action() method will be invoked.
+/**
+ * Interface for any tool that interacts with an executing MIPS program. A qualifying tool must be a class in the Tools
+ * package that implements the MarsTool interface, must be compiled into a .class file, and its .class file must be in
+ * the same Tools folder as MarsTool.class. Mars will detect a qualifying tool upon startup, create an instance using
+ * its no-argument constructor and add it to its Tools menu. When its menu item is selected, the action() method will be
+ * invoked.
*
* A tool may receive communication from MIPS system resources
- * (registers or memory) by registering as an Observer with
- * Mars.Memory and/or Mars.Register objects.
- *
- * It may also
- * communicate directly with those resources through their
- * published methods PROVIDED any such communication is
- * wrapped inside a block synchronized on the
- * Mars.Globals.memoryAndRegistersLock object.
+ * (registers or memory) by registering as an Observer with Mars.Memory and/or Mars.Register objects.
+ *
+ * It may also communicate directly with those resources through their published methods PROVIDED any such communication
+ * is wrapped inside a block synchronized on the Mars.Globals.memoryAndRegistersLock object.
*/
-
-public interface MarsTool {
- /**
- * Return a name you have chosen for this tool. It will appear as the
- * menu item.
- */
- public abstract String getName();
-
- /**
- * Performs tool functions. It will be invoked when the tool is selected
- * from the Tools menu.
- */
-
- public abstract void action();
-}
\ No newline at end of file
+
+public interface MarsTool
+{
+ /**
+ * Return a name you have chosen for this tool. It will appear as the menu item.
+ */
+ String getName();
+
+ /**
+ * Performs tool functions. It will be invoked when the tool is selected from the Tools menu.
+ */
+
+ void action();
+}
diff --git a/src/main/java/mars/tools/MemoryReferenceVisualization.java b/src/main/java/mars/tools/MemoryReferenceVisualization.java
index dbba176..b97740c 100644
--- a/src/main/java/mars/tools/MemoryReferenceVisualization.java
+++ b/src/main/java/mars/tools/MemoryReferenceVisualization.java
@@ -1,12 +1,18 @@
- package mars.tools;
- import javax.swing.*;
- import javax.swing.border.*;
- import javax.swing.event.*;
- import java.awt.*;
- import java.awt.event.*;
- import java.util.*;
- import mars.tools.*;
- import mars.mips.hardware.*;
+package mars.tools;
+
+import mars.mips.hardware.AccessNotice;
+import mars.mips.hardware.Memory;
+import mars.mips.hardware.MemoryAccessNotice;
+
+import javax.swing.*;
+import javax.swing.border.EmptyBorder;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.Arrays;
+import java.util.Observable;
/*
Copyright (c) 2003-2006, Pete Sanderson and Kenneth Vollmar
@@ -35,451 +41,513 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
(MIT license, http://www.opensource.org/licenses/mit-license.html)
*/
-
- /**
- * Memory reference visualization. It can be run either as a stand-alone Java application having
- * access to the mars package, or through MARS as an item in its Tools menu. It makes
- * maximum use of methods inherited from its abstract superclass AbstractMarsToolAndApplication.
- * Pete Sanderson, verison 1.0, 14 November 2006.
- */
- public class MemoryReferenceVisualization extends AbstractMarsToolAndApplication {
-
- private static String version = "Version 1.0";
- private static String heading = "Visualizing memory reference patterns";
-
- // Major GUI components
- private JComboBox wordsPerUnitSelector, visualizationUnitPixelWidthSelector, visualizationUnitPixelHeightSelector,
- visualizationPixelWidthSelector, visualizationPixelHeightSelector, displayBaseAddressSelector;
- private JCheckBox drawHashMarksSelector;
- private Graphics drawingArea;
- private JPanel canvas;
- private JPanel results;
-
- // Some GUI settings
- private EmptyBorder emptyBorder = new EmptyBorder(4,4,4,4);
- private Font countFonts = new Font("Times", Font.BOLD,12);
- private Color backgroundColor = Color.WHITE;
-
- // Values for Combo Boxes
-
- private final String[] wordsPerUnitChoices = {"1","2","4","8","16","32","64","128","256","512","1024","2048"};
- private final int defaultWordsPerUnitIndex = 0;
- private final String[] visualizationUnitPixelWidthChoices = {"1","2","4","8","16","32"};
- private final int defaultVisualizationUnitPixelWidthIndex = 4;
- private final String[] visualizationUnitPixelHeightChoices = {"1","2","4","8","16","32"};
- private final int defaultVisualizationUnitPixelHeightIndex = 4;
- private final String[] displayAreaPixelWidthChoices = {"64","128","256","512","1024"};
- private final int defaultDisplayWidthIndex = 2;
- private final String[] displayAreaPixelHeightChoices = {"64","128","256","512","1024"};
- private final int defaultDisplayHeightIndex = 2;
- private final boolean defaultDrawHashMarks = true;
-
- // Values for display canvas. Note their initialization uses the identifiers just above.
-
- private int unitPixelWidth = Integer.parseInt(visualizationUnitPixelWidthChoices[defaultVisualizationUnitPixelWidthIndex]);
- private int unitPixelHeight = Integer.parseInt(visualizationUnitPixelHeightChoices[defaultVisualizationUnitPixelHeightIndex]);
- private int wordsPerUnit = Integer.parseInt(wordsPerUnitChoices[defaultWordsPerUnitIndex]);
- private int visualizationAreaWidthInPixels = Integer.parseInt(displayAreaPixelWidthChoices[defaultDisplayWidthIndex]);
- private int visualizationAreaHeightInPixels = Integer.parseInt(displayAreaPixelHeightChoices[defaultDisplayHeightIndex]);
-
- //`Values for mapping of reference counts to colors for display.
-
- // This array of (count,color) pairs must be kept sorted! count is low end of subrange.
- // This array will grow if user adds colors at additional counter points (see below).
- private CounterColor[] defaultCounterColors =
- { new CounterColor(0, Color.black),
- new CounterColor(1, Color.blue),
- new CounterColor(2, Color.green),
- new CounterColor(3, Color.yellow),
- new CounterColor(5, Color.orange),
- new CounterColor(10, Color.red)
- };
- /* Values for reference count color slider. These are all possible counter values for which
- * colors can be assigned. As you can see just above, not all these values are assigned
- * a default color.
- */
- private int[] countTable = {
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, // 0-10
- 20, 30, 40, 50, 100, 200, 300, 400, 500, 1000, // 11-20
- 2000, 3000, 4000, 5000, 10000, 50000, 100000, 500000, 1000000 // 21-29
- };
- private final int COUNT_INDEX_INIT = 10; // array element #10, arbitrary starting point
-
- // The next four are initialized dynamically in initializeDisplayBaseChoices()
- private String[] displayBaseAddressChoices;
- private int[] displayBaseAddresses;
- private int defaultBaseAddressIndex;
- private int baseAddress;
-
- private Grid theGrid;
- private CounterColorScale counterColorScale;
-
- /**
- * Simple constructor, likely used to run a stand-alone memory reference visualizer.
- * @param title String containing title for title bar
- * @param heading String containing text for heading shown in upper part of window.
- */
- public MemoryReferenceVisualization(String title, String heading) {
- super(title,heading);
- }
-
- /**
- * Simple constructor, likely used by the MARS Tools menu mechanism
- */
- public MemoryReferenceVisualization() {
- super ("Memory Reference Visualization, "+version, heading);
- }
-
-
- /**
- * Main provided for pure stand-alone use. Recommended stand-alone use is to write a
- * driver program that instantiates a MemoryReferenceVisualization object then invokes its go() method.
- * "stand-alone" means it is not invoked from the MARS Tools menu. "Pure" means there
- * is no driver program to invoke the application.
- */
- public static void main(String[] args) {
- new MemoryReferenceVisualization("Memory Reference Visualization stand-alone, "+version,heading).go();
- }
-
-
- /**
- * Required MarsTool method to return Tool name.
- * @return Tool name. MARS will display this in menu item.
- */
- public String getName() {
- return "Memory Reference Visualization";
- }
-
-
- /**
- * Override the inherited method, which registers us as an Observer over the static data segment
- * (starting address 0x10010000) only. This version will register us as observer over the
- * the memory range as selected by the base address combo box and capacity of the visualization display
- * (number of visualization elements times the number of memory words each one represents).
- * It does so by calling the inherited 2-parameter overload of this method.
- * If you use the inherited GUI buttons, this
- * method is invoked when you click "Connect" button on MarsTool or the
- * "Assemble and Run" button on a Mars-based app.
- */
- protected void addAsObserver() {
- int highAddress = baseAddress+theGrid.getRows()*theGrid.getColumns()*Memory.WORD_LENGTH_BYTES*wordsPerUnit;
- // Special case: baseAddress<0 means we're in kernel memory (0x80000000 and up) and most likely
- // in memory map address space (0xffff0000 and up). In this case, we need to make sure the high address
- // does not drop off the high end of 32 bit address space. Highest allowable word address is 0xfffffffc,
- // which is interpreted in Java int as -4.
- if (baseAddress < 0 && highAddress > -4) {
+
+/**
+ * Memory reference visualization. It can be run either as a stand-alone Java application having access to the mars
+ * package, or through MARS as an item in its Tools menu. It makes maximum use of methods inherited from its abstract
+ * superclass AbstractMarsToolAndApplication. Pete Sanderson, verison 1.0, 14 November 2006.
+ */
+public class MemoryReferenceVisualization extends AbstractMarsToolAndApplication
+{
+
+ private static final String version = "Version 1.0";
+
+ private static final String heading = "Visualizing memory reference patterns";
+
+ private final String[] wordsPerUnitChoices = {"1", "2", "4", "8", "16", "32", "64", "128", "256", "512", "1024", "2048"};
+
+ private final int defaultWordsPerUnitIndex = 0;
+
+ private final String[] visualizationUnitPixelWidthChoices = {"1", "2", "4", "8", "16", "32"};
+
+ private final int defaultVisualizationUnitPixelWidthIndex = 4;
+
+ private final String[] visualizationUnitPixelHeightChoices = {"1", "2", "4", "8", "16", "32"};
+
+ private final int defaultVisualizationUnitPixelHeightIndex = 4;
+
+ private final String[] displayAreaPixelWidthChoices = {"64", "128", "256", "512", "1024"};
+
+ private final int defaultDisplayWidthIndex = 2;
+
+ // Values for Combo Boxes
+
+ private final String[] displayAreaPixelHeightChoices = {"64", "128", "256", "512", "1024"};
+
+ private final int defaultDisplayHeightIndex = 2;
+
+ private final boolean defaultDrawHashMarks = true;
+
+ private final int COUNT_INDEX_INIT = 10; // array element #10, arbitrary starting point
+
+ // Major GUI components
+ private JComboBox wordsPerUnitSelector, visualizationUnitPixelWidthSelector, visualizationUnitPixelHeightSelector,
+ visualizationPixelWidthSelector, visualizationPixelHeightSelector, displayBaseAddressSelector;
+
+ private JCheckBox drawHashMarksSelector;
+
+ private Graphics drawingArea;
+
+ private JPanel canvas;
+
+ private JPanel results;
+
+ // Some GUI settings
+ private final EmptyBorder emptyBorder = new EmptyBorder(4, 4, 4, 4);
+
+ private final Font countFonts = new Font("Times", Font.BOLD, 12);
+
+ // Values for display canvas. Note their initialization uses the identifiers just above.
+
+ private final Color backgroundColor = Color.WHITE;
+
+ private int unitPixelWidth = Integer.parseInt(visualizationUnitPixelWidthChoices[defaultVisualizationUnitPixelWidthIndex]);
+
+ private int unitPixelHeight = Integer.parseInt(visualizationUnitPixelHeightChoices[defaultVisualizationUnitPixelHeightIndex]);
+
+ private int wordsPerUnit = Integer.parseInt(wordsPerUnitChoices[defaultWordsPerUnitIndex]);
+
+ private int visualizationAreaWidthInPixels = Integer.parseInt(displayAreaPixelWidthChoices[defaultDisplayWidthIndex]);
+
+ //`Values for mapping of reference counts to colors for display.
+
+ private int visualizationAreaHeightInPixels = Integer.parseInt(displayAreaPixelHeightChoices[defaultDisplayHeightIndex]);
+
+ // This array of (count,color) pairs must be kept sorted! count is low end of subrange.
+ // This array will grow if user adds colors at additional counter points (see below).
+ private final CounterColor[] defaultCounterColors =
+ {new CounterColor(0, Color.black),
+ new CounterColor(1, Color.blue),
+ new CounterColor(2, Color.green),
+ new CounterColor(3, Color.yellow),
+ new CounterColor(5, Color.orange),
+ new CounterColor(10, Color.red)
+ };
+
+ /* Values for reference count color slider. These are all possible counter values for which
+ * colors can be assigned. As you can see just above, not all these values are assigned
+ * a default color.
+ */
+ private final int[] countTable = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, // 0-10
+ 20, 30, 40, 50, 100, 200, 300, 400, 500, 1000, // 11-20
+ 2000, 3000, 4000, 5000, 10000, 50000, 100000, 500000, 1000000 // 21-29
+ };
+
+ // The next four are initialized dynamically in initializeDisplayBaseChoices()
+ private String[] displayBaseAddressChoices;
+
+ private int[] displayBaseAddresses;
+
+ private int defaultBaseAddressIndex;
+
+ private int baseAddress;
+
+ private Grid theGrid;
+
+ private CounterColorScale counterColorScale;
+
+ /**
+ * Simple constructor, likely used to run a stand-alone memory reference visualizer.
+ *
+ * @param title String containing title for title bar
+ * @param heading String containing text for heading shown in upper part of window.
+ */
+ public MemoryReferenceVisualization(String title, String heading)
+ {
+ super(title, heading);
+ }
+
+ /**
+ * Simple constructor, likely used by the MARS Tools menu mechanism
+ */
+ public MemoryReferenceVisualization()
+ {
+ super("Memory Reference Visualization, " + version, heading);
+ }
+
+
+ /**
+ * Main provided for pure stand-alone use. Recommended stand-alone use is to write a driver program that
+ * instantiates a MemoryReferenceVisualization object then invokes its go() method. "stand-alone" means it is not
+ * invoked from the MARS Tools menu. "Pure" means there is no driver program to invoke the application.
+ */
+ public static void main(String[] args)
+ {
+ new MemoryReferenceVisualization("Memory Reference Visualization stand-alone, " + version, heading).go();
+ }
+
+
+ /**
+ * Required MarsTool method to return Tool name.
+ *
+ * @return Tool name. MARS will display this in menu item.
+ */
+ public String getName()
+ {
+ return "Memory Reference Visualization";
+ }
+
+
+ /**
+ * Override the inherited method, which registers us as an Observer over the static data segment (starting address
+ * 0x10010000) only. This version will register us as observer over the the memory range as selected by the base
+ * address combo box and capacity of the visualization display (number of visualization elements times the number of
+ * memory words each one represents). It does so by calling the inherited 2-parameter overload of this method. If
+ * you use the inherited GUI buttons, this method is invoked when you click "Connect" button on MarsTool or the
+ * "Assemble and Run" button on a Mars-based app.
+ */
+ protected void addAsObserver()
+ {
+ int highAddress = baseAddress + theGrid.getRows() * theGrid.getColumns() * Memory.WORD_LENGTH_BYTES * wordsPerUnit;
+ // Special case: baseAddress<0 means we're in kernel memory (0x80000000 and up) and most likely
+ // in memory map address space (0xffff0000 and up). In this case, we need to make sure the high address
+ // does not drop off the high end of 32 bit address space. Highest allowable word address is 0xfffffffc,
+ // which is interpreted in Java int as -4.
+ if (baseAddress < 0 && highAddress > -4)
+ {
highAddress = -4;
- }
- addAsObserver(baseAddress, highAddress);
- }
-
-
- /**
- * Method that constructs the main display area. It is organized vertically
- * into two major components: the display configuration which an be modified
- * using combo boxes, and the visualization display which is updated as the
- * attached MIPS program executes.
- * @return the GUI component containing these two areas
- */
- protected JComponent buildMainDisplayArea() {
- results = new JPanel();
- results.add(buildOrganizationArea());
- results.add(buildVisualizationArea());
- return results;
- }
-
-
- //////////////////////////////////////////////////////////////////////////////////////
- // Rest of the protected methods. These override do-nothing methods inherited from
- // the abstract superclass.
- //////////////////////////////////////////////////////////////////////////////////////
-
- /**
- * Update display when connected MIPS program accesses (data) memory.
- * @param memory the attached memory
- * @param accessNotice information provided by memory in MemoryAccessNotice object
- */
- protected void processMIPSUpdate(Observable memory, AccessNotice accessNotice) {
- incrementReferenceCountForAddress(((MemoryAccessNotice)accessNotice).getAddress());
- updateDisplay();
- }
-
-
- /**
- * Initialize all JComboBox choice structures not already initialized at declaration.
- * Overrides inherited method that does nothing.
- */
- protected void initializePreGUI() {
- initializeDisplayBaseChoices();
- counterColorScale = new CounterColorScale(defaultCounterColors);
- // NOTE: Can't call "createNewGrid()" here because it uses settings from
- // several combo boxes that have not been created yet. But a default grid
- // needs to be allocated for initial canvas display.
- theGrid = new Grid(visualizationAreaHeightInPixels/unitPixelHeight,
- visualizationAreaWidthInPixels/unitPixelWidth);
- }
-
-
- /**
- * The only post-GUI initialization is to create the initial Grid object based on the default settings
- * of the various combo boxes. Overrides inherited method that does nothing.
- */
-
- protected void initializePostGUI() {
- wordsPerUnit = getIntComboBoxSelection(wordsPerUnitSelector);
- theGrid = createNewGrid();
- updateBaseAddress();
- }
-
-
- /**
- * Method to reset counters and display when the Reset button selected.
- * Overrides inherited method that does nothing.
- */
- protected void reset() {
- resetCounts();
- updateDisplay();
- }
-
- /**
- * Updates display immediately after each update (AccessNotice) is processed, after
- * display configuration changes as needed, and after each execution step when Mars
- * is running in timed mode. Overrides inherited method that does nothing.
- */
- protected void updateDisplay() {
- canvas.repaint();
- }
-
-
- /**
- * Overrides default method, to provide a Help button for this tool/app.
- */
- protected JComponent getHelpComponent() {
- final String helpContent =
- "Use this program to visualize dynamic memory reference\n"+
- "patterns in MIPS assembly programs. It may be run either\n"+
- "from MARS' Tools menu or as a stand-alone application. For\n"+
- "the latter, simply write a small driver to instantiate a\n"+
- "MemoryReferenceVisualization object and invoke its go() method.\n"+
- "\n"+
- "You can easily learn to use this small program by playing with\n"+
- "it! For the best animation, set the MIPS program to run in\n"+
- "timed mode using the Run Speed slider. Each rectangular unit\n"+
- "on the display represents one or more memory words (default 1)\n"+
- "and each time a memory word is accessed by the MIPS program,\n"+
- "its reference count is incremented then rendered in the color\n"+
- "assigned to the count value. You can change the count-color\n"+
- "assignments using the count slider and color patch. Select a\n"+
- "counter value then click on the color patch to change the color.\n"+
- "This color will apply beginning at the selected count and\n"+
- "extending up to the next slider-provided count.\n"+
- "\n"+
- "Contact Pete Sanderson at psanderson@otterbein.edu with\n"+
- "questions or comments.\n";
- JButton help = new JButton("Help");
- help.addActionListener(
- new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- JOptionPane.showMessageDialog(theWindow, helpContent);
- }
- });
- return help;
- }
-
- //////////////////////////////////////////////////////////////////////////////////////
- // Private methods defined to support the above.
- //////////////////////////////////////////////////////////////////////////////////////
-
- // UI components and layout for left half of GUI, where settings are specified.
- private JComponent buildOrganizationArea() {
- JPanel organization = new JPanel(new GridLayout(9,1));
-
- drawHashMarksSelector = new JCheckBox();
- drawHashMarksSelector.setSelected(defaultDrawHashMarks);
- drawHashMarksSelector.addActionListener(
- new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- updateDisplay();
- }
- });
- wordsPerUnitSelector = new JComboBox(wordsPerUnitChoices);
- wordsPerUnitSelector.setEditable(false);
- wordsPerUnitSelector.setBackground(backgroundColor);
- wordsPerUnitSelector.setSelectedIndex(defaultWordsPerUnitIndex);
- wordsPerUnitSelector.setToolTipText("Number of memory words represented by one visualization element (rectangle)");
- wordsPerUnitSelector.addActionListener(
- new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- wordsPerUnit = getIntComboBoxSelection(wordsPerUnitSelector);
- reset();
- }
- });
- visualizationUnitPixelWidthSelector = new JComboBox(visualizationUnitPixelWidthChoices);
- visualizationUnitPixelWidthSelector.setEditable(false);
- visualizationUnitPixelWidthSelector.setBackground(backgroundColor);
- visualizationUnitPixelWidthSelector.setSelectedIndex(defaultVisualizationUnitPixelWidthIndex);
- visualizationUnitPixelWidthSelector.setToolTipText("Width in pixels of rectangle representing memory access");
- visualizationUnitPixelWidthSelector.addActionListener(
- new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- unitPixelWidth = getIntComboBoxSelection(visualizationUnitPixelWidthSelector);
- theGrid = createNewGrid();
- updateDisplay();
- }
- });
- visualizationUnitPixelHeightSelector = new JComboBox(visualizationUnitPixelHeightChoices);
- visualizationUnitPixelHeightSelector.setEditable(false);
- visualizationUnitPixelHeightSelector.setBackground(backgroundColor);
- visualizationUnitPixelHeightSelector.setSelectedIndex(defaultVisualizationUnitPixelHeightIndex);
- visualizationUnitPixelHeightSelector.setToolTipText("Height in pixels of rectangle representing memory access");
- visualizationUnitPixelHeightSelector.addActionListener(
- new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- unitPixelHeight = getIntComboBoxSelection(visualizationUnitPixelHeightSelector);
- theGrid = createNewGrid();
- updateDisplay();
- }
- });
- visualizationPixelWidthSelector = new JComboBox(displayAreaPixelWidthChoices);
- visualizationPixelWidthSelector.setEditable(false);
- visualizationPixelWidthSelector.setBackground(backgroundColor);
- visualizationPixelWidthSelector.setSelectedIndex(defaultDisplayWidthIndex);
- visualizationPixelWidthSelector.setToolTipText("Total width in pixels of visualization area");
- visualizationPixelWidthSelector.addActionListener(
- new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- visualizationAreaWidthInPixels = getIntComboBoxSelection(visualizationPixelWidthSelector);
- canvas.setPreferredSize(getDisplayAreaDimension());
- canvas.setSize(getDisplayAreaDimension());
- theGrid = createNewGrid();
- canvas.repaint();
- updateDisplay();
- }
- });
- visualizationPixelHeightSelector = new JComboBox(displayAreaPixelHeightChoices);
- visualizationPixelHeightSelector.setEditable(false);
- visualizationPixelHeightSelector.setBackground(backgroundColor);
- visualizationPixelHeightSelector.setSelectedIndex(defaultDisplayHeightIndex);
- visualizationPixelHeightSelector.setToolTipText("Total height in pixels of visualization area");
- visualizationPixelHeightSelector.addActionListener(
- new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- visualizationAreaHeightInPixels = getIntComboBoxSelection(visualizationPixelHeightSelector);
- canvas.setPreferredSize(getDisplayAreaDimension());
- canvas.setSize(getDisplayAreaDimension());
- theGrid = createNewGrid();
- canvas.repaint();
- updateDisplay();
- }
- });
- displayBaseAddressSelector = new JComboBox(displayBaseAddressChoices);
- displayBaseAddressSelector.setEditable(false);
- displayBaseAddressSelector.setBackground(backgroundColor);
- displayBaseAddressSelector.setSelectedIndex(defaultBaseAddressIndex);
- displayBaseAddressSelector.setToolTipText("Base address for visualization area (upper left corner)");
- displayBaseAddressSelector.addActionListener(
- new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- // This may also affect what address range we should be registered as an Observer
- // for. The default (inherited) address range is the MIPS static data segment
- // starting at 0x10010000. To change this requires override of
- // AbstractMarsToolAndApplication.addAsObserver(). The no-argument version of
- // that method is called automatically when "Connect" button is clicked for MarsTool
- // and when "Assemble and Run" button is clicked for Mars application.
- updateBaseAddress();
- // If display base address is changed while connected to MIPS (this can only occur
- // when being used as a MarsTool), we have to delete ourselves as an observer and re-register.
- if (connectButton != null && connectButton.isConnected()) {
+ }
+ addAsObserver(baseAddress, highAddress);
+ }
+
+
+ /**
+ * Method that constructs the main display area. It is organized vertically into two major components: the display
+ * configuration which an be modified using combo boxes, and the visualization display which is updated as the
+ * attached MIPS program executes.
+ *
+ * @return the GUI component containing these two areas
+ */
+ protected JComponent buildMainDisplayArea()
+ {
+ results = new JPanel();
+ results.add(buildOrganizationArea());
+ results.add(buildVisualizationArea());
+ return results;
+ }
+
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Rest of the protected methods. These override do-nothing methods inherited from
+ // the abstract superclass.
+ //////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Update display when connected MIPS program accesses (data) memory.
+ *
+ * @param memory the attached memory
+ * @param accessNotice information provided by memory in MemoryAccessNotice object
+ */
+ protected void processMIPSUpdate(Observable memory, AccessNotice accessNotice)
+ {
+ incrementReferenceCountForAddress(((MemoryAccessNotice) accessNotice).getAddress());
+ updateDisplay();
+ }
+
+
+ /**
+ * Initialize all JComboBox choice structures not already initialized at declaration. Overrides inherited method
+ * that does nothing.
+ */
+ protected void initializePreGUI()
+ {
+ initializeDisplayBaseChoices();
+ counterColorScale = new CounterColorScale(defaultCounterColors);
+ // NOTE: Can't call "createNewGrid()" here because it uses settings from
+ // several combo boxes that have not been created yet. But a default grid
+ // needs to be allocated for initial canvas display.
+ theGrid = new Grid(visualizationAreaHeightInPixels / unitPixelHeight,
+ visualizationAreaWidthInPixels / unitPixelWidth);
+ }
+
+
+ /**
+ * The only post-GUI initialization is to create the initial Grid object based on the default settings of the
+ * various combo boxes. Overrides inherited method that does nothing.
+ */
+
+ protected void initializePostGUI()
+ {
+ wordsPerUnit = getIntComboBoxSelection(wordsPerUnitSelector);
+ theGrid = createNewGrid();
+ updateBaseAddress();
+ }
+
+
+ /**
+ * Method to reset counters and display when the Reset button selected. Overrides inherited method that does
+ * nothing.
+ */
+ protected void reset()
+ {
+ resetCounts();
+ updateDisplay();
+ }
+
+ /**
+ * Updates display immediately after each update (AccessNotice) is processed, after display configuration changes as
+ * needed, and after each execution step when Mars is running in timed mode. Overrides inherited method that does
+ * nothing.
+ */
+ protected void updateDisplay()
+ {
+ canvas.repaint();
+ }
+
+
+ /**
+ * Overrides default method, to provide a Help button for this tool/app.
+ */
+ protected JComponent getHelpComponent()
+ {
+ final String helpContent =
+ "Use this program to visualize dynamic memory reference\n" +
+ "patterns in MIPS assembly programs. It may be run either\n" +
+ "from MARS' Tools menu or as a stand-alone application. For\n" +
+ "the latter, simply write a small driver to instantiate a\n" +
+ "MemoryReferenceVisualization object and invoke its go() method.\n" +
+ "\n" +
+ "You can easily learn to use this small program by playing with\n" +
+ "it! For the best animation, set the MIPS program to run in\n" +
+ "timed mode using the Run Speed slider. Each rectangular unit\n" +
+ "on the display represents one or more memory words (default 1)\n" +
+ "and each time a memory word is accessed by the MIPS program,\n" +
+ "its reference count is incremented then rendered in the color\n" +
+ "assigned to the count value. You can change the count-color\n" +
+ "assignments using the count slider and color patch. Select a\n" +
+ "counter value then click on the color patch to change the color.\n" +
+ "This color will apply beginning at the selected count and\n" +
+ "extending up to the next slider-provided count.\n" +
+ "\n" +
+ "Contact Pete Sanderson at psanderson@otterbein.edu with\n" +
+ "questions or comments.\n";
+ JButton help = new JButton("Help");
+ help.addActionListener(
+ new ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ JOptionPane.showMessageDialog(theWindow, helpContent);
+ }
+ });
+ return help;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Private methods defined to support the above.
+ //////////////////////////////////////////////////////////////////////////////////////
+
+ // UI components and layout for left half of GUI, where settings are specified.
+ private JComponent buildOrganizationArea()
+ {
+ JPanel organization = new JPanel(new GridLayout(9, 1));
+
+ drawHashMarksSelector = new JCheckBox();
+ drawHashMarksSelector.setSelected(defaultDrawHashMarks);
+ drawHashMarksSelector.addActionListener(
+ new ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ updateDisplay();
+ }
+ });
+ wordsPerUnitSelector = new JComboBox(wordsPerUnitChoices);
+ wordsPerUnitSelector.setEditable(false);
+ wordsPerUnitSelector.setBackground(backgroundColor);
+ wordsPerUnitSelector.setSelectedIndex(defaultWordsPerUnitIndex);
+ wordsPerUnitSelector.setToolTipText("Number of memory words represented by one visualization element (rectangle)");
+ wordsPerUnitSelector.addActionListener(
+ new ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ wordsPerUnit = getIntComboBoxSelection(wordsPerUnitSelector);
+ reset();
+ }
+ });
+ visualizationUnitPixelWidthSelector = new JComboBox(visualizationUnitPixelWidthChoices);
+ visualizationUnitPixelWidthSelector.setEditable(false);
+ visualizationUnitPixelWidthSelector.setBackground(backgroundColor);
+ visualizationUnitPixelWidthSelector.setSelectedIndex(defaultVisualizationUnitPixelWidthIndex);
+ visualizationUnitPixelWidthSelector.setToolTipText("Width in pixels of rectangle representing memory access");
+ visualizationUnitPixelWidthSelector.addActionListener(
+ new ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ unitPixelWidth = getIntComboBoxSelection(visualizationUnitPixelWidthSelector);
+ theGrid = createNewGrid();
+ updateDisplay();
+ }
+ });
+ visualizationUnitPixelHeightSelector = new JComboBox(visualizationUnitPixelHeightChoices);
+ visualizationUnitPixelHeightSelector.setEditable(false);
+ visualizationUnitPixelHeightSelector.setBackground(backgroundColor);
+ visualizationUnitPixelHeightSelector.setSelectedIndex(defaultVisualizationUnitPixelHeightIndex);
+ visualizationUnitPixelHeightSelector.setToolTipText("Height in pixels of rectangle representing memory access");
+ visualizationUnitPixelHeightSelector.addActionListener(
+ new ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ unitPixelHeight = getIntComboBoxSelection(visualizationUnitPixelHeightSelector);
+ theGrid = createNewGrid();
+ updateDisplay();
+ }
+ });
+ visualizationPixelWidthSelector = new JComboBox(displayAreaPixelWidthChoices);
+ visualizationPixelWidthSelector.setEditable(false);
+ visualizationPixelWidthSelector.setBackground(backgroundColor);
+ visualizationPixelWidthSelector.setSelectedIndex(defaultDisplayWidthIndex);
+ visualizationPixelWidthSelector.setToolTipText("Total width in pixels of visualization area");
+ visualizationPixelWidthSelector.addActionListener(
+ new ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ visualizationAreaWidthInPixels = getIntComboBoxSelection(visualizationPixelWidthSelector);
+ canvas.setPreferredSize(getDisplayAreaDimension());
+ canvas.setSize(getDisplayAreaDimension());
+ theGrid = createNewGrid();
+ canvas.repaint();
+ updateDisplay();
+ }
+ });
+ visualizationPixelHeightSelector = new JComboBox(displayAreaPixelHeightChoices);
+ visualizationPixelHeightSelector.setEditable(false);
+ visualizationPixelHeightSelector.setBackground(backgroundColor);
+ visualizationPixelHeightSelector.setSelectedIndex(defaultDisplayHeightIndex);
+ visualizationPixelHeightSelector.setToolTipText("Total height in pixels of visualization area");
+ visualizationPixelHeightSelector.addActionListener(
+ new ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ visualizationAreaHeightInPixels = getIntComboBoxSelection(visualizationPixelHeightSelector);
+ canvas.setPreferredSize(getDisplayAreaDimension());
+ canvas.setSize(getDisplayAreaDimension());
+ theGrid = createNewGrid();
+ canvas.repaint();
+ updateDisplay();
+ }
+ });
+ displayBaseAddressSelector = new JComboBox(displayBaseAddressChoices);
+ displayBaseAddressSelector.setEditable(false);
+ displayBaseAddressSelector.setBackground(backgroundColor);
+ displayBaseAddressSelector.setSelectedIndex(defaultBaseAddressIndex);
+ displayBaseAddressSelector.setToolTipText("Base address for visualization area (upper left corner)");
+ displayBaseAddressSelector.addActionListener(
+ new ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ // This may also affect what address range we should be registered as an Observer
+ // for. The default (inherited) address range is the MIPS static data segment
+ // starting at 0x10010000. To change this requires override of
+ // AbstractMarsToolAndApplication.addAsObserver(). The no-argument version of
+ // that method is called automatically when "Connect" button is clicked for MarsTool
+ // and when "Assemble and Run" button is clicked for Mars application.
+ updateBaseAddress();
+ // If display base address is changed while connected to MIPS (this can only occur
+ // when being used as a MarsTool), we have to delete ourselves as an observer and re-register.
+ if (connectButton != null && connectButton.isConnected())
+ {
deleteAsObserver();
addAsObserver();
- }
- theGrid = createNewGrid();
- updateDisplay();
- }
- });
-
- // ALL COMPONENTS FOR "ORGANIZATION" SECTION
-
- JPanel hashMarksRow = getPanelWithBorderLayout();
- hashMarksRow.setBorder(emptyBorder);
- hashMarksRow.add(new JLabel("Show unit boundaries (grid marks)"), BorderLayout.WEST);
- hashMarksRow.add(drawHashMarksSelector, BorderLayout.EAST);
-
- JPanel wordsPerUnitRow = getPanelWithBorderLayout();
- wordsPerUnitRow.setBorder(emptyBorder);
- wordsPerUnitRow.add(new JLabel("Memory Words per Unit "),BorderLayout.WEST);
- wordsPerUnitRow.add(wordsPerUnitSelector,BorderLayout.EAST);
-
- JPanel unitWidthInPixelsRow = getPanelWithBorderLayout();
- unitWidthInPixelsRow.setBorder(emptyBorder);
- unitWidthInPixelsRow.add(new JLabel("Unit Width in Pixels "),BorderLayout.WEST);
- unitWidthInPixelsRow.add(visualizationUnitPixelWidthSelector, BorderLayout.EAST);
-
- JPanel unitHeightInPixelsRow = getPanelWithBorderLayout();
- unitHeightInPixelsRow.setBorder(emptyBorder);
- unitHeightInPixelsRow.add(new JLabel("Unit Height in Pixels "),BorderLayout.WEST);
- unitHeightInPixelsRow.add(visualizationUnitPixelHeightSelector,BorderLayout.EAST);
-
- JPanel widthInPixelsRow = getPanelWithBorderLayout();
- widthInPixelsRow.setBorder(emptyBorder);
- widthInPixelsRow.add(new JLabel("Display Width in Pixels "),BorderLayout.WEST);
- widthInPixelsRow.add(visualizationPixelWidthSelector, BorderLayout.EAST);
-
- JPanel heightInPixelsRow = getPanelWithBorderLayout();
- heightInPixelsRow.setBorder(emptyBorder);
- heightInPixelsRow.add(new JLabel("Display Height in Pixels "),BorderLayout.WEST);
- heightInPixelsRow.add(visualizationPixelHeightSelector,BorderLayout.EAST);
-
- JPanel baseAddressRow = getPanelWithBorderLayout();
- baseAddressRow.setBorder(emptyBorder);
- baseAddressRow.add(new JLabel("Base address for display "),BorderLayout.WEST);
- baseAddressRow.add(displayBaseAddressSelector,BorderLayout.EAST);
-
- ColorChooserControls colorChooserControls = new ColorChooserControls();
-
- // Lay 'em out in the grid...
- organization.add(hashMarksRow);
- organization.add(wordsPerUnitRow);
- organization.add(unitWidthInPixelsRow);
- organization.add(unitHeightInPixelsRow);
- organization.add(widthInPixelsRow);
- organization.add(heightInPixelsRow);
- organization.add(baseAddressRow);
- organization.add(colorChooserControls.colorChooserRow);
- organization.add(colorChooserControls.countDisplayRow);
- return organization;
- }
-
- // UI components and layout for right half of GUI, the visualization display area.
- private JComponent buildVisualizationArea() {
- canvas = new GraphicsPanel();
- canvas.setPreferredSize(getDisplayAreaDimension());
- canvas.setToolTipText("Memory reference count visualization area");
- return canvas;
- }
-
- // For greatest flexibility, initialize the display base choices directly from
- // the constants defined in the Memory class. This method called prior to
- // building the GUI. Here are current values from Memory.java:
- //textBaseAddress=0x00400000, dataSegmentBaseAddress=0x10000000, globalPointer=0x10008000
- //dataBaseAddress=0x10010000, heapBaseAddress=0x10040000, memoryMapBaseAddress=0xffff0000
- private void initializeDisplayBaseChoices() {
- int[] displayBaseAddressArray = {Memory.textBaseAddress, Memory.dataSegmentBaseAddress, Memory.globalPointer, Memory.dataBaseAddress,
- Memory.heapBaseAddress, Memory.memoryMapBaseAddress };
- // Must agree with above in number and order...
- String[] descriptions = { " (text)", " (global data)", " ($gp)", " (static data)", " (heap)", " (memory map)" };
- displayBaseAddresses = displayBaseAddressArray;
- displayBaseAddressChoices = new String[displayBaseAddressArray.length];
- for (int i=0; i 10 characters long, slice off the first
10 and apply Integer.parseInt() to it to get custom base address.
*/
- }
-
- // Returns Dimension object with current width and height of display area as determined
- // by current settings of respective combo boxes.
- private Dimension getDisplayAreaDimension() {
- return new Dimension(visualizationAreaWidthInPixels, visualizationAreaHeightInPixels);
- }
-
- // reset all counters in the Grid.
- private void resetCounts() {
- theGrid.reset();
- }
-
- // Will return int equivalent of specified combo box's current selection.
- // The selection must be a String that parses to an int.
- private int getIntComboBoxSelection(JComboBox comboBox) {
- try {
- return Integer.parseInt((String)comboBox.getSelectedItem());
- }
- catch (NumberFormatException nfe) {
- // Can occur only if initialization list contains badly formatted numbers. This
- // is a developer's error, not a user error, and better be caught before release.
- return 1;
- }
- }
-
- // Use this for consistent results.
- private JPanel getPanelWithBorderLayout() {
- return new JPanel(new BorderLayout(2,2));
- }
-
- // Method to determine grid dimensions based on durrent control settings.
- // Each grid element corresponds to one visualization unit.
- private Grid createNewGrid() {
- int rows = visualizationAreaHeightInPixels/unitPixelHeight;
- int columns = visualizationAreaWidthInPixels/unitPixelWidth;
- return new Grid(rows,columns);
- }
-
- // Given memory address, increment the counter for the corresponding grid element.
- // Need to consider words per unit (number of memory words that each visual element represents).
- // If address maps to invalid grid element (e.g. is outside the current bounds based on all
- // display settings) then nothing happens.
- private void incrementReferenceCountForAddress(int address) {
- int offset = (address - baseAddress)/Memory.WORD_LENGTH_BYTES/wordsPerUnit;
- // If you care to do anything with it, the following will return -1 if the address
- // maps outside the dimensions of the grid (e.g. below the base address or beyond end).
- theGrid.incrementElement(offset / theGrid.getColumns(), offset % theGrid.getColumns());
- }
-
-
- //////////////////////////////////////////////////////////////////////////////////////
- // Specialized inner classes for modeling and animation.
- //////////////////////////////////////////////////////////////////////////////////////
-
-
- /////////////////////////////////////////////////////////////////////////////
- // Class that represents the panel for visualizing and animating memory reference
- // patterns.
- private class GraphicsPanel extends JPanel {
- // override default paint method to assure visualized reference pattern is produced every time
- // the panel is repainted.
- public void paint(Graphics g) {
+ }
+
+ // Returns Dimension object with current width and height of display area as determined
+ // by current settings of respective combo boxes.
+ private Dimension getDisplayAreaDimension()
+ {
+ return new Dimension(visualizationAreaWidthInPixels, visualizationAreaHeightInPixels);
+ }
+
+ // reset all counters in the Grid.
+ private void resetCounts()
+ {
+ theGrid.reset();
+ }
+
+ // Will return int equivalent of specified combo box's current selection.
+ // The selection must be a String that parses to an int.
+ private int getIntComboBoxSelection(JComboBox comboBox)
+ {
+ try
+ {
+ return Integer.parseInt((String) comboBox.getSelectedItem());
+ }
+ catch (NumberFormatException nfe)
+ {
+ // Can occur only if initialization list contains badly formatted numbers. This
+ // is a developer's error, not a user error, and better be caught before release.
+ return 1;
+ }
+ }
+
+ // Use this for consistent results.
+ private JPanel getPanelWithBorderLayout()
+ {
+ return new JPanel(new BorderLayout(2, 2));
+ }
+
+ // Method to determine grid dimensions based on durrent control settings.
+ // Each grid element corresponds to one visualization unit.
+ private Grid createNewGrid()
+ {
+ int rows = visualizationAreaHeightInPixels / unitPixelHeight;
+ int columns = visualizationAreaWidthInPixels / unitPixelWidth;
+ return new Grid(rows, columns);
+ }
+
+ // Given memory address, increment the counter for the corresponding grid element.
+ // Need to consider words per unit (number of memory words that each visual element represents).
+ // If address maps to invalid grid element (e.g. is outside the current bounds based on all
+ // display settings) then nothing happens.
+ private void incrementReferenceCountForAddress(int address)
+ {
+ int offset = (address - baseAddress) / Memory.WORD_LENGTH_BYTES / wordsPerUnit;
+ // If you care to do anything with it, the following will return -1 if the address
+ // maps outside the dimensions of the grid (e.g. below the base address or beyond end).
+ theGrid.incrementElement(offset / theGrid.getColumns(), offset % theGrid.getColumns());
+ }
+
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Specialized inner classes for modeling and animation.
+ //////////////////////////////////////////////////////////////////////////////////////
+
+
+ /////////////////////////////////////////////////////////////////////////////
+ // Class that represents the panel for visualizing and animating memory reference
+ // patterns.
+ private class GraphicsPanel extends JPanel
+ {
+ // override default paint method to assure visualized reference pattern is produced every time
+ // the panel is repainted.
+ public void paint(Graphics g)
+ {
paintGrid(g, theGrid);
- if (drawHashMarksSelector.isSelected()) {
- paintHashMarks(g, theGrid);
+ if (drawHashMarksSelector.isSelected())
+ {
+ paintHashMarks(g, theGrid);
}
- }
-
- // Paint (ash marks on the grid. Their color is chosef to be in
- // "contrast" to the current color for reference count of zero.
- private void paintHashMarks(Graphics g, Grid grid) {
+ }
+
+ // Paint (ash marks on the grid. Their color is chosef to be in
+ // "contrast" to the current color for reference count of zero.
+ private void paintHashMarks(Graphics g, Grid grid)
+ {
g.setColor(getContrastingColor(counterColorScale.getColor(0)));
- int leftX=0;
- int rightX=visualizationAreaWidthInPixels;
- int upperY=0;
- int lowerY=visualizationAreaHeightInPixels;
+ int leftX = 0;
+ int rightX = visualizationAreaWidthInPixels;
+ int upperY = 0;
+ int lowerY = visualizationAreaHeightInPixels;
// draw vertical hash marks
- for (int j=0; j= 10) {
- spaces = " ";
- }
- else if (value >=100) {
- spaces = "";
+ if (value >= 10)
+ {
+ spaces = " ";
}
- return "Counter value "+spaces+value;
- }
-
- // Listener that both revises label as user slides and updates current index when sliding stops.
- private class ColorChooserListener implements ChangeListener {
- public void stateChanged(ChangeEvent e) {
- JSlider source = (JSlider)e.getSource();
- if (!source.getValueIsAdjusting()) {
- counterIndex = (int)source.getValue();
- }
- else {
- int count = countTable[(int)source.getValue()];
- sliderLabel.setText(setLabel(count));
- currentColorButton.setBackground(counterColorScale.getColor(count));
- }
- }
- }
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- // Object that represents mapping from counter value to color it is displayed as.
- //
- private class CounterColorScale {
- CounterColor[] counterColors;
-
- CounterColorScale(CounterColor[] colors) {
+ else if (value >= 100)
+ {
+ spaces = "";
+ }
+ return "Counter value " + spaces + value;
+ }
+
+ // Listener that both revises label as user slides and updates current index when sliding stops.
+ private class ColorChooserListener implements ChangeListener
+ {
+ public void stateChanged(ChangeEvent e)
+ {
+ JSlider source = (JSlider) e.getSource();
+ if (!source.getValueIsAdjusting())
+ {
+ counterIndex = source.getValue();
+ }
+ else
+ {
+ int count = countTable[source.getValue()];
+ sliderLabel.setText(setLabel(count));
+ currentColorButton.setBackground(counterColorScale.getColor(count));
+ }
+ }
+ }
+ }
+
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // Object that represents mapping from counter value to color it is displayed as.
+ //
+ private class CounterColorScale
+ {
+ CounterColor[] counterColors;
+
+ CounterColorScale(CounterColor[] colors)
+ {
counterColors = colors;
- }
-
- // return color associated with specified counter value
- private Color getColor(int count) {
+ }
+
+ // return color associated with specified counter value
+ private Color getColor(int count)
+ {
Color result = counterColors[0].associatedColor;
- int index=0;
- while (index < counterColors.length && count >= counterColors[index].colorRangeStart) {
- result = counterColors[index].associatedColor;
- index++;
+ int index = 0;
+ while (index < counterColors.length && count >= counterColors[index].colorRangeStart)
+ {
+ result = counterColors[index].associatedColor;
+ index++;
}
return result;
- }
-
- // For a given counter value, return the counter value at the high end of the range of
- // counter values having the same color.
- private int getHighEndOfRange(int count) {
+ }
+
+ // For a given counter value, return the counter value at the high end of the range of
+ // counter values having the same color.
+ private int getHighEndOfRange(int count)
+ {
int highEnd = Integer.MAX_VALUE;
- if (count < counterColors[counterColors.length-1].colorRangeStart) {
- int index=0;
- while (index < counterColors.length-1 && count >= counterColors[index].colorRangeStart) {
- highEnd = counterColors[index+1].colorRangeStart - 1;
- index++;
- }
+ if (count < counterColors[counterColors.length - 1].colorRangeStart)
+ {
+ int index = 0;
+ while (index < counterColors.length - 1 && count >= counterColors[index].colorRangeStart)
+ {
+ highEnd = counterColors[index + 1].colorRangeStart - 1;
+ index++;
+ }
}
return highEnd;
- }
-
- // The given entry should either be inserted into the the scale or replace an existing
- // element. The latter occurs if the new CounterColor has same starting counter value
- // as an existing one.
- private void insertOrReplace(CounterColor newColor) {
+ }
+
+ // The given entry should either be inserted into the the scale or replace an existing
+ // element. The latter occurs if the new CounterColor has same starting counter value
+ // as an existing one.
+ private void insertOrReplace(CounterColor newColor)
+ {
int index = Arrays.binarySearch(counterColors, newColor);
- if (index >= 0) { // found, so replace
- counterColors[index] = newColor;
- }
- else { // not found, so insert
- int insertIndex = -index-1;
- CounterColor[] newSortedArray = new CounterColor[counterColors.length+1];
- System.arraycopy(counterColors, 0, newSortedArray, 0, insertIndex);
- System.arraycopy(counterColors, insertIndex, newSortedArray, insertIndex+1, counterColors.length-insertIndex);
- newSortedArray[insertIndex] = newColor;
- counterColors = newSortedArray;
+ if (index >= 0)
+ { // found, so replace
+ counterColors[index] = newColor;
}
- }
- }
-
-
- ///////////////////////////////////////////////////////////////////////////////////////
- // Each object represents beginning of a counter value range (non-negative integer) and
- // color for rendering the range. High end of the range is defined as low end of the
- // next range minus 1. For last range, high end is Integer.MAX_VALUE.
- private class CounterColor implements Comparable {
- private int colorRangeStart;
- private Color associatedColor;
- public CounterColor(int start, Color color) {
+ else
+ { // not found, so insert
+ int insertIndex = -index - 1;
+ CounterColor[] newSortedArray = new CounterColor[counterColors.length + 1];
+ System.arraycopy(counterColors, 0, newSortedArray, 0, insertIndex);
+ System.arraycopy(counterColors, insertIndex, newSortedArray, insertIndex + 1, counterColors.length - insertIndex);
+ newSortedArray[insertIndex] = newColor;
+ counterColors = newSortedArray;
+ }
+ }
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////
+ // Each object represents beginning of a counter value range (non-negative integer) and
+ // color for rendering the range. High end of the range is defined as low end of the
+ // next range minus 1. For last range, high end is Integer.MAX_VALUE.
+ private class CounterColor implements Comparable
+ {
+ private final int colorRangeStart;
+
+ private final Color associatedColor;
+
+ public CounterColor(int start, Color color)
+ {
this.colorRangeStart = start;
this.associatedColor = color;
- }
-
- // Necessary for sorting in ascending order of range low end.
- public int compareTo(Object other) {
- if (other instanceof CounterColor) {
- return this.colorRangeStart - ((CounterColor)other).colorRangeStart;
- }
- else {
- throw new ClassCastException();
+ }
+
+ // Necessary for sorting in ascending order of range low end.
+ public int compareTo(Object other)
+ {
+ if (other instanceof CounterColor)
+ {
+ return this.colorRangeStart - ((CounterColor) other).colorRangeStart;
}
- }
- }
-
-
- ////////////////////////////////////////////////////////////////////////
- // Represents grid of memory access counts
- private class Grid {
-
- int[][] grid;
- int rows, columns;
-
- private Grid(int rows, int columns) {
+ else
+ {
+ throw new ClassCastException();
+ }
+ }
+ }
+
+
+ ////////////////////////////////////////////////////////////////////////
+ // Represents grid of memory access counts
+ private class Grid
+ {
+
+ int[][] grid;
+
+ int rows, columns;
+
+ private Grid(int rows, int columns)
+ {
grid = new int[rows][columns];
this.rows = rows;
this.columns = columns;
- // automatically initialized to 0, so I won't bother to....
- }
-
- private int getRows() {
+ // automatically initialized to 0, so I won't bother to....
+ }
+
+ private int getRows()
+ {
return rows;
- }
-
- private int getColumns() {
+ }
+
+ private int getColumns()
+ {
return columns;
- }
-
- // Returns value in given grid element; -1 if row or column is out of range.
- private int getElement(int row, int column) {
- return (row>=0 && row<=rows && column>=0 && column<=columns) ? grid[row][column] : -1;
- }
-
- // Returns value in given grid element without doing any row/column index checking.
- // Is faster than getElement but will throw array index out of bounds exception if
- // parameter values are outside the bounds of the grid.
- private int getElementFast(int row, int column) {
- return grid[row][column];
- }
-
- // Increment the given grid element and return incremented value.
- // Returns -1 if row or column is out of range.
- private int incrementElement(int row, int column) {
- return (row>=0 && row<=rows && column>=0 && column<=columns) ? ++grid[row][column] : -1;
- }
-
- // Just set all grid elements to 0.
- private void reset() {
- for (int i=0; i= 0 && row <= rows && column >= 0 && column <= columns) ? grid[row][column] : -1;
+ }
+
+ // Returns value in given grid element without doing any row/column index checking.
+ // Is faster than getElement but will throw array index out of bounds exception if
+ // parameter values are outside the bounds of the grid.
+ private int getElementFast(int row, int column)
+ {
+ return grid[row][column];
+ }
+
+ // Increment the given grid element and return incremented value.
+ // Returns -1 if row or column is out of range.
+ private int incrementElement(int row, int column)
+ {
+ return (row >= 0 && row <= rows && column >= 0 && column <= columns) ? ++grid[row][column] : -1;
+ }
+
+ // Just set all grid elements to 0.
+ private void reset()
+ {
+ for (int i = 0; i < rows; i++)
+ {
+ for (int j = 0; j < columns; j++)
+ {
+ grid[i][j] = 0;
+ }
}
- }
- }
-
- }
\ No newline at end of file
+ }
+ }
+
+}
diff --git a/src/main/java/mars/tools/MipsXray.java b/src/main/java/mars/tools/MipsXray.java
index 01e2f52..a78f4d3 100644
--- a/src/main/java/mars/tools/MipsXray.java
+++ b/src/main/java/mars/tools/MipsXray.java
@@ -32,1428 +32,1721 @@ import java.util.HashMap;
import java.util.Observable;
import java.util.Vector;
-public class MipsXray extends AbstractMarsToolAndApplication{
- private static final long serialVersionUID = -1L;
- private static String heading = "MIPS X-Ray - Animation of MIPS Datapath";
- private static String version = " Version 2.0";
-
- protected Graphics g;
- protected int lastAddress = -1; //address of instruction in memory
- protected JLabel label;
- private Container painel = this.getContentPane();
- private DatapathAnimation datapathAnimation; //class panel that runs datapath animation.
+public class MipsXray extends AbstractMarsToolAndApplication
+{
+ private static final long serialVersionUID = -1L;
+
+ private static final String heading = "MIPS X-Ray - Animation of MIPS Datapath";
+
+ private static final String version = " Version 2.0";
+
+ protected Graphics g;
+
+ protected int lastAddress = -1; //address of instruction in memory
+
+ protected JLabel label;
+
+ private final Container painel = this.getContentPane();
+
+ private DatapathAnimation datapathAnimation; //class panel that runs datapath animation.
private GraphicsConfiguration gc;
+
private BufferedImage datapath;
- private String instructionBinary;
-
+
+ private String instructionBinary;
+
//Components to add menu bar in the plugin window.
- private JButton Assemble, Step, runBackStep;
+ private JButton Assemble, Step, runBackStep;
+
private Action runAssembleAction, runStepAction, runBackstepAction;
-
+
private VenusUI mainUI;
+
private JToolBar toolbar;
+
private Timer time;
-
- public MipsXray(String title, String heading) {
- super(title,heading);
- }
-
- /**
- * Simple constructor, likely used by the MipsXray menu mechanism
- */
- public MipsXray() {
- super (heading+", "+version, heading);
- }
-
-
- /**
- * Required method to return Tool name.
- * @return Tool name. MARS will display this in menu item.
- */
- public String getName() {
- return "MIPS X-Ray";
- }
- /**
- * Overrides default method, to provide a Help button for this tool/app.
- */
- protected JComponent getHelpComponent() {
- final String helpContent =
- "This plugin is used to visualizate the behavior of mips processor using the default datapath. \n" +
- "It reads the source code instruction and generates an animation representing the inputs and \n" +
- "outputs of functional blocks and the interconnection between them. The basic signals \n" +
- "represented are, control signals, opcode bits and data of functional blocks.\n" +
- "\n" +
- "Besides the datapath representation, information for each instruction is displayed below\n" +
- "the datapath. That display includes opcode value, with the correspondent colors used to\n" +
- "represent the signals in datapath, mnemonic of the instruction processed at the moment, registers\n" +
- "used in the instruction and a label that indicates the color code used to represent control signals\n" +
- "\n" +
- "To see the datapath of register bank and control units click inside the functional unit.\n\n" +
- "Version 2.0\n" +
- "Developed by Márcio Roberto, Guilherme Sales, FabrÃcio Vivas, Flávio Cardeal and Fábio Lúcio\n" +
- "Contact Marcio Roberto at marcio.rdaraujo@gmail.com with questions or comments.\n";
- JButton help = new JButton("Help");
- help.addActionListener(
- new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- JOptionPane.showMessageDialog(theWindow, helpContent);
- }
- });
- return help;
- }
- /**
- * Implementation of the inherited abstract method to build the main
- * display area of the GUI. It will be placed in the CENTER area of a
- * BorderLayout. The title is in the NORTH area, and the controls are
- * in the SOUTH area.
- */
- protected JComponent buildAnimationSequence(){
- JPanel image = new JPanel(new GridBagLayout());
- return image;
- }
-
- // Insert image in the panel and configure the parameters to run animation.
- protected JComponent buildMainDisplayArea() {
- mainUI = Globals.getGui();
- this.createActionObjects();
- toolbar= this.setUpToolBar();
-
-// JPanel jp = new JPanel(new FlowLayout(FlowLayout.LEFT));
- GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
- gc = ge.getDefaultScreenDevice().getDefaultConfiguration();
- try {
- BufferedImage im = ImageIO.read(
- getClass().getResource(Globals.imagesPath+"datapath.png") );
-
- int transparency = im.getColorModel().getTransparency();
- datapath = gc.createCompatibleImage( im.getWidth(), im.getHeight(),
- transparency );
-
- Graphics2D g2d = datapath.createGraphics(); // graphics context
- g2d.drawImage(im,0,0,null);
- g2d.dispose();
-
- }
- catch(IOException e) {
- System.out.println("Load Image error for " +
- getClass().getResource(Globals.imagesPath+"datapath.png") + ":\n" + e);
- e.printStackTrace();
- }
- System.setProperty("sun.java2d.translaccel", "true");
- ImageIcon icon = new ImageIcon(getClass().getResource(Globals.imagesPath+"datapath.png"));
- Image im = icon.getImage();
- icon = new ImageIcon(im);
-
- JLabel label = new JLabel(icon);
- painel.add(label, BorderLayout.WEST);
- painel.add(toolbar, BorderLayout.NORTH);
- this.setResizable(false);
- return (JComponent) painel;
+ public MipsXray(String title, String heading)
+ {
+ super(title, heading);
}
-
- protected JComponent buildMainDisplayArea(String figure) {
- mainUI = Globals.getGui();
- this.createActionObjects();
- toolbar= this.setUpToolBar();
-
-// JPanel jp = new JPanel(new FlowLayout(FlowLayout.LEFT));
- GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
- gc = ge.getDefaultScreenDevice().getDefaultConfiguration();
- try {
- BufferedImage im = ImageIO.read(
- getClass().getResource(Globals.imagesPath+figure) );
-
- int transparency = im.getColorModel().getTransparency();
- datapath = gc.createCompatibleImage( im.getWidth(), im.getHeight(),
- transparency );
-
- Graphics2D g2d = datapath.createGraphics(); // graphics context
- g2d.drawImage(im,0,0,null);
- g2d.dispose();
-
- }
- catch(IOException e) {
- System.out.println("Load Image error for " +
- getClass().getResource(Globals.imagesPath+figure) + ":\n" + e);
- e.printStackTrace();
- }
- System.setProperty("sun.java2d.translaccel", "true");
- ImageIcon icon = new ImageIcon(getClass().getResource(Globals.imagesPath+figure));
- Image im = icon.getImage();
- icon = new ImageIcon(im);
-
- JLabel label = new JLabel(icon);
- painel.add(label, BorderLayout.WEST);
- painel.add(toolbar, BorderLayout.NORTH);
- this.setResizable(false);
- return (JComponent) painel;
- }
-
- protected void addAsObserver() {
- addAsObserver(Memory.textBaseAddress, Memory.textLimitAddress);
- }
-
- //Function that gets the current instruction in memory and start animation with the selected instruction.
- protected void processMIPSUpdate(Observable resource, AccessNotice notice) {
- if (!notice.accessIsFromMIPS()) return;
- if (notice.getAccessType() != AccessNotice.READ) return;
- MemoryAccessNotice man = (MemoryAccessNotice) notice;
- int currentAdress = man.getAddress();
-
- if (currentAdress == lastAddress) return;
- lastAddress = currentAdress;
- ProgramStatement stmt;
-
- try {
- BasicInstruction instr = null;
- stmt = Memory.getInstance().getStatement(currentAdress);
- if(stmt == null){
- return;
- }
-
- instr = (BasicInstruction) stmt.getInstruction();
- instructionBinary = stmt.getMachineStatement();
- BasicInstructionFormat format = instr.getInstructionFormat();
-
- painel.removeAll();
- datapathAnimation = new DatapathAnimation(instructionBinary);
- this.createActionObjects();
- toolbar= this.setUpToolBar();
- painel.add(toolbar, BorderLayout.NORTH);
- painel.add(datapathAnimation, BorderLayout.WEST);
- datapathAnimation.startAnimation(instructionBinary );
-
- } catch (AddressErrorException e) {
- e.printStackTrace();
- }
-
-
- }
-
- public void updateDisplay(){
- this.repaint();
- }
-
- //set the tool bar that controls the step in a time instruction running.
- private JToolBar setUpToolBar() {
- JToolBar toolBar = new JToolBar();
- Assemble = new JButton(runAssembleAction);
- Assemble.setText("");
- runBackStep = new JButton(runBackstepAction);
- runBackStep.setText("");
-
- Step = new JButton(runStepAction);
- Step.setText("");
- toolBar.add(Assemble);
- toolBar.add(Step);
-
- return toolBar;
- }
-
- //set action in the menu bar.
- private void createActionObjects() {
- Toolkit tk = Toolkit.getDefaultToolkit();
- Class cs = this.getClass();
- try{
- runAssembleAction = new RunAssembleAction("Assemble",
- new ImageIcon(tk.getImage(cs.getResource(Globals.imagesPath+"Assemble22.png"))),
- "Assemble the current file and clear breakpoints", new Integer(KeyEvent.VK_A),
- KeyStroke.getKeyStroke( KeyEvent.VK_F3, 0),
- mainUI);
-
- runStepAction = new RunStepAction("Step",
- new ImageIcon(tk.getImage(cs.getResource(Globals.imagesPath+"StepForward22.png"))),
- "Run one step at a time", new Integer(KeyEvent.VK_T),
- KeyStroke.getKeyStroke( KeyEvent.VK_F7, 0),
- mainUI);
- runBackstepAction = new RunBackstepAction("Backstep",
- new ImageIcon(tk.getImage(cs.getResource(Globals.imagesPath+"StepBack22.png"))),
- "Undo the last step", new Integer(KeyEvent.VK_B),
- KeyStroke.getKeyStroke( KeyEvent.VK_F8, 0),
- mainUI);
- }
- catch(Exception e){
- System.out.println("Internal Error: images folder not found, or other null pointer exception while creating Action objects");
- e.printStackTrace();
- System.exit(0);
- }
- }
+ /**
+ * Simple constructor, likely used by the MipsXray menu mechanism
+ */
+ public MipsXray()
+ {
+ super(heading + ", " + version, heading);
+ }
-class Vertex {
- private int numIndex;
- private int init;
- private int end;
- private int current;
- private String name;
- public static final int movingUpside = 1;
- public static final int movingDownside = 2;
- public static final int movingLeft = 3;
- public static final int movingRight = 4;
- public int direction;
- public int oppositeAxis;
- private boolean isMovingXaxis;
- private Color color;
- private boolean first_interaction;
- private boolean active;
- private boolean isText;
- private ArrayList targetVertex;
-
- public Vertex(int index, int init, int end, String name, int oppositeAxis, boolean isMovingXaxis,
- String listOfColors, String listTargetVertex, boolean isText){
- this.numIndex = index;
- this.init = init;
- this.current = this.init;
- this.end = end;
- this.name = name;
- this.oppositeAxis = oppositeAxis;
- this.isMovingXaxis = isMovingXaxis;
- this.first_interaction = true;
- this.active = false;
- this.isText = isText;
- this.color = new Color(0,153,0);
- if(isMovingXaxis == true){
- if( init < end)
- direction = movingLeft;
- else
- direction = movingRight;
-
- }
- else{
- if( init < end)
- direction = movingUpside;
- else
- direction = movingDownside;
- }
- String[] list = listTargetVertex.split("#");
- targetVertex = new ArrayList();
- for(int i = 0; i < list.length; i++){
- targetVertex.add(Integer.parseInt(list[i]));
- // System.out.println("Adding " + i + " " + Integer.parseInt(list[i])+ " in target");
- }
- String[] listColor = listOfColors.split("#");
- this.color = new Color(Integer.parseInt(listColor[0]) , Integer.parseInt(listColor[1]), Integer.parseInt(listColor[2]) );
- }
-
- public int getDirection(){
- return direction;
- }
-
- public boolean isText(){
- return this.isText;
- }
+ /**
+ * Required method to return Tool name.
+ *
+ * @return Tool name. MARS will display this in menu item.
+ */
+ public String getName()
+ {
+ return "MIPS X-Ray";
+ }
+
+ /**
+ * Overrides default method, to provide a Help button for this tool/app.
+ */
+ protected JComponent getHelpComponent()
+ {
+ final String helpContent =
+ "This plugin is used to visualizate the behavior of mips processor using the default datapath. \n" +
+ "It reads the source code instruction and generates an animation representing the inputs and \n" +
+ "outputs of functional blocks and the interconnection between them. The basic signals \n" +
+ "represented are, control signals, opcode bits and data of functional blocks.\n" +
+ "\n" +
+ "Besides the datapath representation, information for each instruction is displayed below\n" +
+ "the datapath. That display includes opcode value, with the correspondent colors used to\n" +
+ "represent the signals in datapath, mnemonic of the instruction processed at the moment, registers\n" +
+ "used in the instruction and a label that indicates the color code used to represent control signals\n" +
+ "\n" +
+ "To see the datapath of register bank and control units click inside the functional unit.\n\n" +
+ "Version 2.0\n" +
+ "Developed by Márcio Roberto, Guilherme Sales, FabrÃcio Vivas, Flávio Cardeal and Fábio Lúcio\n" +
+ "Contact Marcio Roberto at marcio.rdaraujo@gmail.com with questions or comments.\n";
+ JButton help = new JButton("Help");
+ help.addActionListener(
+ new ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ JOptionPane.showMessageDialog(theWindow, helpContent);
+ }
+ });
+ return help;
+ }
+
+ /**
+ * Implementation of the inherited abstract method to build the main display area of the GUI. It will be placed in
+ * the CENTER area of a BorderLayout. The title is in the NORTH area, and the controls are in the SOUTH area.
+ */
+ protected JComponent buildAnimationSequence()
+ {
+ JPanel image = new JPanel(new GridBagLayout());
+ return image;
+ }
+
+ // Insert image in the panel and configure the parameters to run animation.
+ protected JComponent buildMainDisplayArea()
+ {
+ mainUI = Globals.getGui();
+ this.createActionObjects();
+ toolbar = this.setUpToolBar();
+
+ // JPanel jp = new JPanel(new FlowLayout(FlowLayout.LEFT));
+ GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
+ gc = ge.getDefaultScreenDevice().getDefaultConfiguration();
+ try
+ {
+ BufferedImage im = ImageIO.read(
+ getClass().getResource(Globals.imagesPath + "datapath.png"));
+
+ int transparency = im.getColorModel().getTransparency();
+ datapath = gc.createCompatibleImage(im.getWidth(), im.getHeight(),
+ transparency);
+
+ Graphics2D g2d = datapath.createGraphics(); // graphics context
+ g2d.drawImage(im, 0, 0, null);
+ g2d.dispose();
+
+ }
+ catch (IOException e)
+ {
+ System.out.println("Load Image error for " +
+ getClass().getResource(Globals.imagesPath + "datapath.png") + ":\n" + e);
+ e.printStackTrace();
+ }
+ System.setProperty("sun.java2d.translaccel", "true");
+ ImageIcon icon = new ImageIcon(getClass().getResource(Globals.imagesPath + "datapath.png"));
+ Image im = icon.getImage();
+ icon = new ImageIcon(im);
+
+ JLabel label = new JLabel(icon);
+ painel.add(label, BorderLayout.WEST);
+ painel.add(toolbar, BorderLayout.NORTH);
+ this.setResizable(false);
+ return (JComponent) painel;
+ }
+
+ protected JComponent buildMainDisplayArea(String figure)
+ {
+ mainUI = Globals.getGui();
+ this.createActionObjects();
+ toolbar = this.setUpToolBar();
+
+ // JPanel jp = new JPanel(new FlowLayout(FlowLayout.LEFT));
+ GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
+ gc = ge.getDefaultScreenDevice().getDefaultConfiguration();
+ try
+ {
+ BufferedImage im = ImageIO.read(
+ getClass().getResource(Globals.imagesPath + figure));
+
+ int transparency = im.getColorModel().getTransparency();
+ datapath = gc.createCompatibleImage(im.getWidth(), im.getHeight(),
+ transparency);
+
+ Graphics2D g2d = datapath.createGraphics(); // graphics context
+ g2d.drawImage(im, 0, 0, null);
+ g2d.dispose();
+
+ }
+ catch (IOException e)
+ {
+ System.out.println("Load Image error for " +
+ getClass().getResource(Globals.imagesPath + figure) + ":\n" + e);
+ e.printStackTrace();
+ }
+ System.setProperty("sun.java2d.translaccel", "true");
+ ImageIcon icon = new ImageIcon(getClass().getResource(Globals.imagesPath + figure));
+ Image im = icon.getImage();
+ icon = new ImageIcon(im);
+
+ JLabel label = new JLabel(icon);
+ painel.add(label, BorderLayout.WEST);
+ painel.add(toolbar, BorderLayout.NORTH);
+ this.setResizable(false);
+ return (JComponent) painel;
+ }
+
+ protected void addAsObserver()
+ {
+ addAsObserver(Memory.textBaseAddress, Memory.textLimitAddress);
+ }
+
+ //Function that gets the current instruction in memory and start animation with the selected instruction.
+ protected void processMIPSUpdate(Observable resource, AccessNotice notice)
+ {
+
+ if (!notice.accessIsFromMIPS())
+ {
+ return;
+ }
+ if (notice.getAccessType() != AccessNotice.READ)
+ {
+ return;
+ }
+ MemoryAccessNotice man = (MemoryAccessNotice) notice;
+ int currentAdress = man.getAddress();
+
+ if (currentAdress == lastAddress)
+ {
+ return;
+ }
+ lastAddress = currentAdress;
+ ProgramStatement stmt;
+
+ try
+ {
+ BasicInstruction instr = null;
+ stmt = Memory.getInstance().getStatement(currentAdress);
+ if (stmt == null)
+ {
+ return;
+ }
+
+ instr = (BasicInstruction) stmt.getInstruction();
+ instructionBinary = stmt.getMachineStatement();
+ BasicInstructionFormat format = instr.getInstructionFormat();
+
+ painel.removeAll();
+ datapathAnimation = new DatapathAnimation(instructionBinary);
+ this.createActionObjects();
+ toolbar = this.setUpToolBar();
+ painel.add(toolbar, BorderLayout.NORTH);
+ painel.add(datapathAnimation, BorderLayout.WEST);
+ datapathAnimation.startAnimation(instructionBinary);
+
+ }
+ catch (AddressErrorException e)
+ {
+ e.printStackTrace();
+ }
- public ArrayList getTargetVertex() {
- return targetVertex;
- }
+ }
- public int getNumIndex() {
- return numIndex;
- }
- public void setNumIndex(int numIndex) {
- this.numIndex = numIndex;
- }
- public int getInit() {
- return init;
- }
- public void setInit(int init) {
- this.init = init;
- }
- public int getEnd() {
- return end;
- }
- public void setEnd(int end) {
- this.end = end;
- }
- public int getCurrent() {
- return current;
- }
- public void setCurrent(int current) {
- this.current = current;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public int getOppositeAxis() {
- return oppositeAxis;
- }
- public void setOppositeAxis(int oppositeAxis) {
- this.oppositeAxis = oppositeAxis;
- }
- public boolean isMovingXaxis() {
- return isMovingXaxis;
- }
- public void setMovingXaxis(boolean isMovingXaxis) {
- this.isMovingXaxis = isMovingXaxis;
- }
- public Color getColor() {
- return color;
- }
- public void setColor(Color color) {
- this.color = color;
- }
- public boolean isFirst_interaction() {
- return first_interaction;
- }
- public void setFirst_interaction(boolean first_interaction) {
- this.first_interaction = first_interaction;
- }
- public boolean isActive() {
- return active;
- }
- public void setActive(boolean active) {
- this.active = active;
- }
-}
-
-
-//Internal class that set the parameters value, control the basic behavior of the animation , and execute the animation of the
-//selected instruction in memory.
-class DatapathAnimation extends JPanel
- implements ActionListener, MouseListener {
- /**
- *
- */
- private static final long serialVersionUID = -2681757800180958534L;
-
- //config variables
- private int PERIOD = 5; // velocity of frames in ms
- private static final int PWIDTH = 1000; // size of this panel
- private static final int PHEIGHT = 574;
- private GraphicsConfiguration gc;
- private GraphicsDevice gd; // for reporting accl. memory usage
- private int accelMemory;
- private DecimalFormat df;
-
- private int counter; //verify then remove.
- private boolean justStarted; //flag to start movement
-
-
- private int indexX; //counter of screen position
- private int indexY;
- private boolean xIsMoving, yIsMoving; //flag for mouse movement.
-
-
-
-// private Vertex[][] inputGraph;
- private Vector> outputGraph;
- private ArrayList vertexList;
- private ArrayList vertexTraversed;
- //Screen Label variables
-
- private HashMap opcodeEquivalenceTable;
- private HashMap functionEquivalenceTable;
- private HashMap registerEquivalenceTable;
-
- private String instructionCode;
-
- private int countRegLabel;
- private int countALULabel;
- private int countPCLabel;
-
- //Colors variables
- private Color green1 = new Color(0,153,0);
- private Color green2 = new Color( 0,77,0);
- private Color yellow2 = new Color(185,182,42);
- private Color orange1 = new Color(255,102,0);
- private Color orange = new Color(119,34,34);
- private Color blue2 = new Color(0,153,255);
-
- private int register = 1;
- private int control = 2;
- private int aluControl = 3;
- private int alu = 4;
- private int currentUnit;
- private Graphics2D g2d;
-
-
- private BufferedImage datapath;
-
- public void mousePressed(MouseEvent e) {
- PointerInfo a = MouseInfo.getPointerInfo();
- // System.out.println("olha, capturado x=" + a.getLocation().getX() + " y = " + a.getLocation().getY());
- }
-
- public DatapathAnimation(String instructionBinary)
- {
- df = new DecimalFormat("0.0"); // 1 dp
- GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
- gd = ge.getDefaultScreenDevice();
- gc = ge.getDefaultScreenDevice().getDefaultConfiguration();
-
- accelMemory = gd.getAvailableAcceleratedMemory(); // in bytes
- setBackground(Color.white);
- setPreferredSize( new Dimension(PWIDTH, PHEIGHT) );
-
- // load and initialise the images
- initImages();
-
- vertexList = new ArrayList();
- counter = 0;
- justStarted = true;
- instructionCode = instructionBinary;
-
- //declaration of labels definition.
- opcodeEquivalenceTable = new HashMap();
- functionEquivalenceTable = new HashMap();
- registerEquivalenceTable = new HashMap();
-
- countRegLabel = 400;
- countALULabel = 380;
- countPCLabel = 380;
- loadHashMapValues();
- addMouseListener(this);
-
-
-
- } // end of ImagesTests()
-
- //set the binnary opcode value of the basic instructions of MIPS instruction set
- public void loadHashMapValues(){
- importXmlStringData("/MipsXRayOpcode.xml",opcodeEquivalenceTable, "equivalence", "bits", "mnemonic");
- importXmlStringData("/MipsXRayOpcode.xml", functionEquivalenceTable, "function_equivalence", "bits", "mnemonic");
- importXmlStringData("/MipsXRayOpcode.xml", registerEquivalenceTable, "register_equivalence", "bits", "mnemonic");
- importXmlDatapathMap("/MipsXRayOpcode.xml", "datapath_map");
- }
-
- //import the list of opcodes of mips set of instructions
- public void importXmlStringData(String xmlName, HashMap table, String elementTree, String tagId, String tagData){
- DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
- dbf.setNamespaceAware(false);
- DocumentBuilder docBuilder;
- try {
- //System.out.println();
- docBuilder = dbf.newDocumentBuilder();
- Document doc = docBuilder.parse(getClass().getResource(xmlName).toString());
- Element root = doc.getDocumentElement();
- Element equivalenceItem;
- NodeList bitsList, mnemonic;
- NodeList equivalenceList = root.getElementsByTagName(elementTree);
- for(int i = 0; i < equivalenceList.getLength(); i++){
- equivalenceItem = (Element)equivalenceList.item(i);
- bitsList = equivalenceItem.getElementsByTagName(tagId);
- mnemonic = equivalenceItem.getElementsByTagName(tagData);
- for(int j= 0; j < bitsList.getLength(); j++){
- table.put(bitsList.item(j).getTextContent(),mnemonic.item(j).getTextContent());
- }
- }
- }
- catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- //import the parameters of the animation on datapath
- public void importXmlDatapathMap(String xmlName, String elementTree){
- DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
- dbf.setNamespaceAware(false);
- DocumentBuilder docBuilder;
- try {
- docBuilder = dbf.newDocumentBuilder();
- Document doc = docBuilder.parse(getClass().getResource(xmlName).toString());
- Element root = doc.getDocumentElement();
- Element datapath_mapItem;
- NodeList index_vertex, name, init, end,color, other_axis, isMovingXaxis, targetVertex, sourceVertex, isText ;
- NodeList datapath_mapList = root.getElementsByTagName(elementTree);
- for(int i = 0; i < datapath_mapList.getLength(); i++){ //extract the vertex of the xml input and encapsulate into the vertex object
- datapath_mapItem = (Element)datapath_mapList.item(i);
- index_vertex = datapath_mapItem.getElementsByTagName("num_vertex");
- name = datapath_mapItem.getElementsByTagName("name");
- init = datapath_mapItem.getElementsByTagName("init");
- end = datapath_mapItem.getElementsByTagName("end");
- //definition of colors line
- if(instructionCode.substring(0,6).equals("000000")){//R-type instructions
- color = datapath_mapItem.getElementsByTagName("color_Rtype");
- //System.out.println("rtype");
- }
- else if(instructionCode.substring(0,6).matches("00001[0-1]")){ //J-type instructions
- color = datapath_mapItem.getElementsByTagName("color_Jtype");
- //System.out.println("jtype");
- }
- else if(instructionCode.substring(0,6).matches("100[0-1][0-1][0-1]")){ //LOAD type instructions
- color = datapath_mapItem.getElementsByTagName("color_LOADtype");
- //System.out.println("load type");
- }
- else if(instructionCode.substring(0,6).matches("101[0-1][0-1][0-1]")){ //LOAD type instructions
- color = datapath_mapItem.getElementsByTagName("color_STOREtype");
- //System.out.println("store type");
- }
- else if(instructionCode.substring(0,6).matches("0001[0-1][0-1]")){ //BRANCH type instructions
- color = datapath_mapItem.getElementsByTagName("color_BRANCHtype");
- //System.out.println("branch type");
- }
- else{ //BRANCH type instructions
- color = datapath_mapItem.getElementsByTagName("color_Itype");
- //System.out.println("immediate type");
- }
-
- other_axis = datapath_mapItem.getElementsByTagName("other_axis");
- isMovingXaxis = datapath_mapItem.getElementsByTagName("isMovingXaxis");
- targetVertex = datapath_mapItem.getElementsByTagName("target_vertex");
- isText = datapath_mapItem.getElementsByTagName("is_text");
-
- for(int j= 0; j < index_vertex.getLength(); j++){
- Vertex vert = new Vertex(Integer.parseInt(index_vertex.item(j).getTextContent()), Integer.parseInt(init.item(j).getTextContent()),
- Integer.parseInt(end.item(j).getTextContent()), name.item(j).getTextContent(), Integer.parseInt(other_axis.item(j).getTextContent()),
- Boolean.parseBoolean(isMovingXaxis.item(j).getTextContent()), color.item(j).getTextContent(), targetVertex.item(j).getTextContent(), Boolean.parseBoolean(isText.item(j).getTextContent()));
- vertexList.add(vert);
- }
- }
- //loading matrix of control of vertex.
- outputGraph = new Vector>();
- vertexTraversed = new ArrayList();
- int size = vertexList.size();
- Vertex vertex;
- ArrayList targetList;
- for(int i = 0; i < vertexList.size(); i++){
- vertex = vertexList.get(i);
- targetList = vertex.getTargetVertex();
- Vector vertexOfTargets = new Vector();
- for(int k = 0; k < targetList.size(); k++){
- vertexOfTargets.add(vertexList.get(targetList.get(k)));
- }
- outputGraph.add(vertexOfTargets);
- }
- for(int i=0; i< outputGraph.size(); i++){
- Vector vert = outputGraph.get(i);
- }
-
- vertexList.get(0).setActive(true);
- vertexTraversed.add(vertexList.get(0));
- }
- catch (Exception e) {
- e.printStackTrace();
- }
-
- }
-
- //Set up the information showed in the screen of the current instruction.
- public void setUpInstructionInfo( Graphics2D g2d){
-
- FontRenderContext frc = g2d.getFontRenderContext();
- Font font = new Font("Digital-7", Font.PLAIN, 15);
- Font fontTitle = new Font("Verdana", Font.PLAIN, 10);
-
- TextLayout textVariable;
- if(instructionCode.substring(0,6).equals("000000")){ //R-type instructions description on screen definition.
- textVariable = new TextLayout("REGISTER TYPE INSTRUCTION", new Font("Arial", Font.BOLD, 25), frc);
- g2d.setColor(Color.black);
- textVariable.draw(g2d, 280, 30);
- //opcode label
- textVariable = new TextLayout("opcode", fontTitle, frc);
- g2d.setColor(Color.red);
- textVariable.draw(g2d, 25, 530);
-
- //initialize of opcode
- textVariable = new TextLayout(instructionCode.substring(0,6), font, frc);
- g2d.setColor(Color.magenta);
- textVariable.draw(g2d, 25, 550);
-
- //rs label
- textVariable = new TextLayout("rs", fontTitle, frc);
- g2d.setColor(Color.red);
- textVariable.draw(g2d, 90, 530);
-
- //initialize of rs
- textVariable = new TextLayout(instructionCode.substring(6,11), font, frc);
- g2d.setColor(Color.green);
- textVariable.draw(g2d, 90, 550);
-
- //rt label
- textVariable = new TextLayout("rt", fontTitle, frc);
- g2d.setColor(Color.red);
- textVariable.draw(g2d, 150, 530);
-
- //initialize of rt
- textVariable = new TextLayout(instructionCode.substring(11,16), font, frc);
- g2d.setColor(Color.blue);
- textVariable.draw(g2d, 150, 550);
-
- // rd label
- textVariable = new TextLayout("rd", fontTitle, frc);
- g2d.setColor(Color.red);
- textVariable.draw(g2d, 210, 530);
-
- //initialize of rd
- textVariable = new TextLayout(instructionCode.substring(16,21), font, frc);
- g2d.setColor(Color.cyan);
- textVariable.draw(g2d, 210, 550);
-
- //shamt label
- textVariable = new TextLayout("shamt", fontTitle, frc);
- g2d.setColor(Color.red);
- textVariable.draw(g2d, 270, 530);
-
- //initialize of shamt
- textVariable = new TextLayout(instructionCode.substring(21,26), font, frc);
- g2d.setColor(Color.black);
- textVariable.draw(g2d, 270, 550);
-
- //function label
- textVariable = new TextLayout("function", fontTitle, frc);
- g2d.setColor(Color.red);
- textVariable.draw(g2d, 330, 530);
-
- //initialize of function
- textVariable = new TextLayout(instructionCode.substring(26,32), font, frc);
- g2d.setColor(orange1);
- textVariable.draw(g2d, 330, 550);
-
-
- //instruction mnemonic
- textVariable = new TextLayout("Instruction", fontTitle, frc);
- g2d.setColor(Color.red);
- textVariable.draw(g2d, 25, 480);
-
- //instruction name
- textVariable = new TextLayout(functionEquivalenceTable.get(instructionCode.substring(26,32)), font, frc);
- g2d.setColor(Color.BLACK);
- textVariable.draw(g2d, 25, 500);
-
- //register in RS
- textVariable = new TextLayout(registerEquivalenceTable.get(instructionCode.substring(6,11)), font, frc);
- g2d.setColor(Color.BLACK);
- textVariable.draw(g2d, 65, 500);
-
- //register in RT
- textVariable = new TextLayout(registerEquivalenceTable.get(instructionCode.substring(16,21)), font, frc);
- g2d.setColor(Color.BLACK);
- textVariable.draw(g2d, 105, 500);
-
- //register in RD
- textVariable = new TextLayout(registerEquivalenceTable.get(instructionCode.substring(11,16)), font, frc);
- g2d.setColor(Color.BLACK);
- textVariable.draw(g2d, 145, 500);
- }
-
- else if(instructionCode.substring(0,6).matches("00001[0-1]")){ //jump intructions
- textVariable = new TextLayout("JUMP TYPE INSTRUCTION", new Font("Verdana", Font.BOLD, 25), frc); //description of instruction code type for jump.
- g2d.setColor(Color.black);
- textVariable.draw(g2d, 280, 30);
-
- // label opcode
- textVariable = new TextLayout("opcode", fontTitle, frc);
- g2d.setColor(Color.red);
- textVariable.draw(g2d, 25, 530);
-
- //initialize of opcode
- textVariable = new TextLayout(instructionCode.substring(0,6), font, frc);
- g2d.setColor(Color.magenta);
- textVariable.draw(g2d, 25, 550);
-
- //label address
- textVariable = new TextLayout("address", fontTitle, frc);
- g2d.setColor(Color.red);
- textVariable.draw(g2d, 95, 530);
-
- textVariable = new TextLayout("Instruction", fontTitle, frc);
- g2d.setColor(Color.red);
- textVariable.draw(g2d, 25, 480);
-
- //initialize of adress
- textVariable = new TextLayout(instructionCode.substring(6,32), font, frc);
- g2d.setColor(Color.orange);
- textVariable.draw(g2d, 95, 550);
-
- //instruction mnemonic
- textVariable= new TextLayout(opcodeEquivalenceTable.get(instructionCode.substring(0,6)), font, frc);
- g2d.setColor(Color.cyan);
- textVariable.draw(g2d, 65, 500);
-
- //instruction immediate
- textVariable = new TextLayout("LABEL", font, frc);
- g2d.setColor(Color.cyan);
- textVariable.draw(g2d, 105, 500);
- }
-
- else if(instructionCode.substring(0,6).matches("100[0-1][0-1][0-1]")){//load instruction
- textVariable = new TextLayout("LOAD TYPE INSTRUCTION", new Font("Verdana", Font.BOLD, 25), frc); //description of instruction code type for load.
- g2d.setColor(Color.black);
- textVariable.draw(g2d, 280, 30);
- //opcode label
- textVariable = new TextLayout("opcode", fontTitle, frc);
- g2d.setColor(Color.red);
- textVariable.draw(g2d, 25, 530);
-
- //initialize of opcode
- textVariable = new TextLayout(instructionCode.substring(0,6), font, frc);
- g2d.setColor(Color.magenta);
- textVariable.draw(g2d, 25, 550);
-
- //rs label
- textVariable = new TextLayout("rs", fontTitle, frc);
- g2d.setColor(Color.red);
- textVariable.draw(g2d, 90, 530);
-
- //initialize of rs
- textVariable = new TextLayout(instructionCode.substring(6,11), font, frc);
- g2d.setColor(Color.green);
- textVariable.draw(g2d, 90, 550);
-
- //rt label
- textVariable = new TextLayout("rt", fontTitle, frc);
- g2d.setColor(Color.red);
- textVariable.draw(g2d, 145, 530);
-
- //initialize of rt
- textVariable = new TextLayout(instructionCode.substring(11,16), font, frc);
- g2d.setColor(Color.blue);
- textVariable.draw(g2d, 145, 550);
-
- // rd label
- textVariable = new TextLayout("Immediate", fontTitle, frc);
- g2d.setColor(Color.red);
- textVariable.draw(g2d, 200, 530);
-
- //initialize of rd
- textVariable = new TextLayout(instructionCode.substring(16,32), font, frc);
- g2d.setColor(orange1);
- textVariable.draw(g2d, 200, 550);
-
- //instruction mnemonic
- textVariable = new TextLayout("Instruction", fontTitle, frc);
- g2d.setColor(Color.red);
- textVariable.draw(g2d, 25, 480);
-
- textVariable = new TextLayout(opcodeEquivalenceTable.get(instructionCode.substring(0,6)), font, frc);
- g2d.setColor(Color.BLACK);
- textVariable.draw(g2d, 25, 500);
-
- textVariable = new TextLayout(registerEquivalenceTable.get(instructionCode.substring(6,11)), font, frc);
- g2d.setColor(Color.BLACK);
- textVariable.draw(g2d, 65, 500);
-
- textVariable = new TextLayout("M[ "+ registerEquivalenceTable.get(instructionCode.substring(16,21)) + " + " + parseBinToInt(instructionCode.substring(6,32))+ " ]", font, frc);
- g2d.setColor(Color.BLACK);
- textVariable.draw(g2d, 105, 500);
-
- //implement co-processors instruction
- }
-
- else if(instructionCode.substring(0,6).matches("101[0-1][0-1][0-1]")){//store instruction
- textVariable = new TextLayout("STORE TYPE INSTRUCTION", new Font("Verdana", Font.BOLD, 25), frc);
- g2d.setColor(Color.black);
- textVariable.draw(g2d, 280, 30);
- //opcode label
- textVariable = new TextLayout("opcode", fontTitle, frc);
- g2d.setColor(Color.red);
- textVariable.draw(g2d, 25, 530);
-
- //initialize of opcode
- textVariable = new TextLayout(instructionCode.substring(0,6), font, frc);
- g2d.setColor(Color.magenta);
- textVariable.draw(g2d, 25, 550);
-
- //rs label
- textVariable = new TextLayout("rs", fontTitle, frc);
- g2d.setColor(Color.red);
- textVariable.draw(g2d, 90, 530);
-
- //initialize of rs
- textVariable = new TextLayout(instructionCode.substring(6,11), font, frc);
- g2d.setColor(Color.green);
- textVariable.draw(g2d, 90, 550);
-
- //rt label
- textVariable = new TextLayout("rt", fontTitle, frc);
- g2d.setColor(Color.red);
- textVariable.draw(g2d, 145, 530);
-
- //initialize of rt
- textVariable = new TextLayout(instructionCode.substring(11,16), font, frc);
- g2d.setColor(Color.blue);
- textVariable.draw(g2d, 145, 550);
-
- // rd label
- textVariable = new TextLayout("Immediate", fontTitle, frc);
- g2d.setColor(Color.red);
- textVariable.draw(g2d, 200, 530);
-
- //initialize of rd
- textVariable = new TextLayout(instructionCode.substring(16,32), font, frc);
- g2d.setColor(orange1);
- textVariable.draw(g2d, 200, 550);
-
- //instruction mnemonic
- textVariable= new TextLayout("Instruction", fontTitle, frc);
- g2d.setColor(Color.red);
- textVariable.draw(g2d, 25, 480);
-
- textVariable = new TextLayout(opcodeEquivalenceTable.get(instructionCode.substring(0,6)), font, frc);
- g2d.setColor(Color.BLACK);
- textVariable.draw(g2d, 25, 500);
-
- textVariable = new TextLayout(registerEquivalenceTable.get(instructionCode.substring(6,11)), font, frc);
- g2d.setColor(Color.BLACK);
- textVariable.draw(g2d, 65, 500);
-
- textVariable = new TextLayout("M[ "+ registerEquivalenceTable.get(instructionCode.substring(16,21)) + " + " + parseBinToInt(instructionCode.substring(6,32))+ " ]", font, frc);
- g2d.setColor(Color.BLACK);
- textVariable.draw(g2d, 105, 500);
-
- }
-
- else if(instructionCode.substring(0,6).matches("0100[0-1][0-1]")){
- //implement co-processors instruction
- }
-
- else if(instructionCode.substring(0,6).matches("0001[0-1][0-1]")){ //branch instruction
- textVariable = new TextLayout("BRANCH TYPE INSTRUCTION",new Font("Verdana", Font.BOLD, 25), frc);
- g2d.setColor(Color.black);
- textVariable.draw(g2d, 250, 30);
-
- //label opcode
- textVariable = new TextLayout("opcode", fontTitle, frc);
- g2d.setColor(Color.red);
- textVariable.draw(g2d, 25, 440);
-
- textVariable = new TextLayout("opcode", fontTitle, frc);
- g2d.setColor(Color.red);
- textVariable.draw(g2d, 25, 530);
-
- //initialize of opcode
- textVariable = new TextLayout(instructionCode.substring(0,6), font, frc);
- g2d.setColor(Color.magenta);
- textVariable.draw(g2d, 25, 550);
-
- //rs label
- textVariable = new TextLayout("rs", fontTitle, frc);
- g2d.setColor(Color.red);
- textVariable.draw(g2d, 90, 530);
-
- //initialize of rs
- textVariable = new TextLayout(instructionCode.substring(6,11), font, frc);
- g2d.setColor(Color.green);
- textVariable.draw(g2d, 90, 550);
-
- //rt label
- textVariable = new TextLayout("rt", fontTitle, frc);
- g2d.setColor(Color.red);
- textVariable.draw(g2d, 145, 530);
-
- //initialize of rt
- textVariable = new TextLayout(instructionCode.substring(11,16), font, frc);
- g2d.setColor(Color.blue);
- textVariable.draw(g2d, 145, 550);
-
- // rd label
- textVariable = new TextLayout("Immediate", fontTitle, frc);
- g2d.setColor(Color.red);
- textVariable.draw(g2d, 200, 530);
-
-
- //initialize of immediate
- textVariable= new TextLayout(instructionCode.substring(16,32), font, frc);
- g2d.setColor(Color.cyan);
- textVariable.draw(g2d, 200, 550);
-
- //instruction mnemonic
- textVariable = new TextLayout("Instruction", fontTitle, frc);
- g2d.setColor(Color.red);
- textVariable.draw(g2d, 25, 480);
-
- textVariable = new TextLayout(opcodeEquivalenceTable.get(instructionCode.substring(0,6)), font, frc);
- g2d.setColor(Color.black);
- textVariable.draw(g2d, 25, 500);
-
- textVariable = new TextLayout(registerEquivalenceTable.get(instructionCode.substring(6,11)), font, frc);
- g2d.setColor(Color.black);
- textVariable.draw(g2d, 105, 500);
-
- textVariable = new TextLayout(registerEquivalenceTable.get(instructionCode.substring(11,16)), font, frc);
- g2d.setColor(Color.black);
- textVariable.draw(g2d, 65, 500);
-
- textVariable = new TextLayout(parseBinToInt(instructionCode.substring(16,32)), font, frc);
- g2d.setColor(Color.black);
- textVariable.draw(g2d, 155, 500);
- }
- else{ //imediate instructions
- textVariable = new TextLayout("IMMEDIATE TYPE INSTRUCTION",new Font("Verdana", Font.BOLD, 25), frc);
- g2d.setColor(Color.black);
- textVariable.draw(g2d, 250, 30);
-
- //label opcode
- textVariable = new TextLayout("opcode", fontTitle, frc);
- g2d.setColor(Color.red);
- textVariable.draw(g2d, 25, 530);
-
- //initialize of opcode
- textVariable = new TextLayout(instructionCode.substring(0,6), font, frc);
- g2d.setColor(Color.magenta);
- textVariable.draw(g2d, 25, 550);
-
- //rs label
- textVariable = new TextLayout("rs", fontTitle, frc);
- g2d.setColor(Color.red);
- textVariable.draw(g2d, 90, 530);
-
- //initialize of rs
- textVariable = new TextLayout(instructionCode.substring(6,11), font, frc);
- g2d.setColor(Color.green);
- textVariable.draw(g2d, 90, 550);
-
- //rt label
- textVariable = new TextLayout("rt", fontTitle, frc);
- g2d.setColor(Color.red);
- textVariable.draw(g2d, 145, 530);
-
- //initialize of rt
- textVariable = new TextLayout(instructionCode.substring(11,16), font, frc);
- g2d.setColor(Color.blue);
- textVariable.draw(g2d, 145, 550);
-
- // rd label
- textVariable = new TextLayout("Immediate", fontTitle, frc);
- g2d.setColor(Color.red);
- textVariable.draw(g2d, 200, 530);
-
- //initialize of immediate
- textVariable= new TextLayout(instructionCode.substring(16,32), font, frc);
- g2d.setColor(Color.cyan);
- textVariable.draw(g2d, 200, 550);
-
- //instruction mnemonic
- textVariable = new TextLayout("Instruction", fontTitle, frc);
- g2d.setColor(Color.red);
- textVariable.draw(g2d, 25, 480);
- textVariable = new TextLayout(opcodeEquivalenceTable.get(instructionCode.substring(0,6)), font, frc);
- g2d.setColor(Color.black);
- textVariable.draw(g2d, 25, 500);
-
- textVariable = new TextLayout(registerEquivalenceTable.get(instructionCode.substring(6,11)), font, frc);
- g2d.setColor(Color.black);
- textVariable.draw(g2d, 105, 500);
-
- textVariable = new TextLayout(registerEquivalenceTable.get(instructionCode.substring(11,16)), font, frc);
- g2d.setColor(Color.black);
- textVariable.draw(g2d, 65, 500);
-
- textVariable = new TextLayout(parseBinToInt(instructionCode.substring(16,32)), font, frc);
- g2d.setColor(Color.black);
- textVariable.draw(g2d, 155, 500);
- }
-
- //Type of control signal labels
- textVariable = new TextLayout("Control Signals", fontTitle, frc);
- g2d.setColor(Color.red);
- textVariable.draw(g2d, 25, 440);
-
- textVariable = new TextLayout("Active", font, frc);
- g2d.setColor(Color.red);
- textVariable.draw(g2d, 25, 455);
-
- textVariable = new TextLayout("Inactive", font, frc);
- g2d.setColor(Color.gray);
- textVariable.draw(g2d, 75, 455);
-
- textVariable = new TextLayout("To see details of control units and register bank click inside the functional block", font, frc);
- g2d.setColor(Color.black);
- textVariable.draw(g2d, 400, 550);
- }
- //end of instruction subtitle...
-
-
- //set the initial state of the variables that controls the animation, and start the timer that triggers the animation.
- public void startAnimation(String codeInstruction){
- instructionCode = codeInstruction;
- time = new Timer(PERIOD, this); // start timer
- time.start();
- // this.repaint();
- }
-
- //initialize the image of datapath.
- private void initImages(){
- try {
- BufferedImage im = ImageIO.read(
- getClass().getResource(Globals.imagesPath+"datapath.png") );
-
- int transparency = im.getColorModel().getTransparency();
- datapath = gc.createCompatibleImage(
- im.getWidth(), im.getHeight(),
- transparency );
- g2d = datapath.createGraphics();
- g2d.drawImage(im,0,0,null);
- g2d.dispose();
- }
- catch(IOException e) {
- System.out.println("Load Image error for " +
- getClass().getResource(Globals.imagesPath+"datapath.png") + ":\n" + e);
- }
- }
-
-
- public void actionPerformed(ActionEvent e)
- // triggered by the timer: update, repaint
- {
- if (justStarted)
- justStarted = false;
- if(xIsMoving)
- indexX++;
- if(yIsMoving)
- indexY--;
- repaint();
- }
-
-
- public void paintComponent(Graphics g)
- {
- super.paintComponent(g);
- g2d = (Graphics2D)g;
- // use antialiasing
- g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
- RenderingHints.VALUE_ANTIALIAS_ON);
- // smoother (and slower) image transformations (e.g. for resizing)
- g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
- RenderingHints.VALUE_INTERPOLATION_BILINEAR);
- g2d = (Graphics2D)g;
- drawImage(g2d, datapath, 0,0,null);
- executeAnimation(g);
- counter = (counter + 1)% 100;
- g2d.dispose();
-
- }
-
- private void drawImage(Graphics2D g2d, BufferedImage im, int x, int y,Color c){
- if (im == null) {
- g2d.setColor(c);
- g2d.fillOval(x, y, 20, 20);
- g2d.setColor(Color.black);
- g2d.drawString(" ", x, y);
- }
- else
- g2d.drawImage(im, x, y, this);
- }
-
- //draw lines.
- //method to draw the lines that run from left to right.
- public void printTrackLtoR(Vertex v){
- int size;
- int[] track;
- size = v.getEnd() - v.getInit();
- track = new int[size];
- for(int i = 0; i < size; i++)
- track[i] = v.getInit()+i;
- if(v.isActive() == true){
- v.setFirst_interaction(false);
- for(int i = 0; i < size; i++){
- if(track[i] <= v.getCurrent()){
- g2d.setColor(v.getColor());
- g2d.fillRect(track[i], v.getOppositeAxis(), 3, 3);
- }
- }
- if (v.getCurrent() == track[size-1])
- v.setActive(false);
- v.setCurrent(v.getCurrent()+1);
- }
- else if(v.isFirst_interaction() == false){
- for(int i = 0; i < size ; i++){
- g2d.setColor(v.getColor());
- g2d.fillRect(track[i],v.getOppositeAxis(), 3, 3);
- }
- }
-
- }
-
- //method to draw the lines that run from right to left.
- //public boolean printTrackRtoL(int init, int end ,int currentIndex, Graphics2D g2d, Color color, int otherAxis,
- // boolean active, boolean firstInteraction){
- public void printTrackRtoL(Vertex v){
- int size;
- int[] track;
- size = v.getInit() - v.getEnd();
- track = new int[size];
-
- for(int i = 0; i < size; i++)
- track[i] = v.getInit()-i;
-
- if(v.isActive() == true){
- v.setFirst_interaction(false);
- for(int i = 0; i < size; i++){
- if(track[i] >= v.getCurrent()){
- g2d.setColor(v.getColor());
- g2d.fillRect(track[i], v.getOppositeAxis(), 3, 3);
- }
- }
- if (v.getCurrent() == track[size-1])
- v.setActive(false);
-
- v.setCurrent(v.getCurrent()-1);
- }
- else if(v.isFirst_interaction() == false){
- for(int i = 0; i < size ; i++){
- g2d.setColor(v.getColor());
- g2d.fillRect(track[i],v.getOppositeAxis(), 3, 3);
- }
- }
- }
-
- //method to draw the lines that run from down to top.
- // public boolean printTrackDtoU(int init, int end ,int currentIndex, Graphics2D g2d, Color color, int otherAxis,
- // boolean active, boolean firstInteraction){
- public void printTrackDtoU(Vertex v){
- int size;
- int[] track;
-
- if(v.getInit() > v.getEnd()){
- size = v.getInit() - v.getEnd();
- track = new int[size];
- for(int i = 0; i < size; i++)
- track[i] = v.getInit()-i;
- }
- else{
- size = v.getEnd() - v.getInit();
- track = new int[size];
- for(int i = 0; i < size; i++)
- track[i] = v.getInit()+i;
- }
-
- if(v.isActive() == true){
- v.setFirst_interaction(false);
- for(int i = 0; i < size; i++){
- if(track[i] >= v.getCurrent()){
- g2d.setColor(v.getColor());
- g2d.fillRect(v.getOppositeAxis(), track[i], 3, 3);
- }
- }
- if (v.getCurrent() == track[size-1])
- v.setActive(false);
- v.setCurrent(v.getCurrent()-1);
-
- }
- else if(v.isFirst_interaction() == false){
- for(int i = 0; i < size; i++){
- g2d.setColor(v.getColor());
- g2d.fillRect(v.getOppositeAxis(), track[i], 3, 3);
- }
- }
- }
- //method to draw the lines that run from top to down.
- // public boolean printTrackUtoD(int init, int end ,int currentIndex, Graphics2D g2d, Color color, int otherAxis,
- // boolean active, boolean firstInteraction){
- public void printTrackUtoD(Vertex v){
-
- int size;
- int[] track;
- size = v.getEnd() - v.getInit();
- track = new int[size];
-
- for(int i = 0; i < size; i++)
- track[i] = v.getInit()+i;
-
- if(v.isActive() == true){
- v.setFirst_interaction(false);
- for(int i = 0; i < size; i++){
- if(track[i] <= v.getCurrent()){
- g2d.setColor(v.getColor());
- g2d.fillRect(v.getOppositeAxis(), track[i], 3, 3);
- }
-
- }
- if (v.getCurrent() == track[size-1])
- v.setActive(false);
- v.setCurrent(v.getCurrent()+1);
- }
- else if(v.isFirst_interaction() == false){
- for(int i = 0; i < size; i++){
- g2d.setColor(v.getColor());
- g2d.fillRect(v.getOppositeAxis(), track[i], 3, 3);
- }
- }
- }
-
- public void printTextDtoU(Vertex v){
- int size;
- int[] track;
- FontRenderContext frc = g2d.getFontRenderContext();
-
- TextLayout actionInFunctionalBlock = new TextLayout(v.getName(), new Font("Verdana", Font.BOLD, 13), frc);
- g2d.setColor(Color.RED);
-
- if(instructionCode.substring(0,6).matches("101[0-1][0-1][0-1]")
- &&!instructionCode.substring(0,6).matches("0001[0-1][0-1]")
- &&!instructionCode.substring(0,6).matches("00001[0-1]")){//load instruction
- actionInFunctionalBlock = new TextLayout(" ", new Font("Verdana", Font.BOLD, 13), frc);
- }
- if(v.getName().equals("ALUVALUE")){
- if( instructionCode.substring(0,6).equals("000000"))//R-type instruction
- actionInFunctionalBlock = new TextLayout(functionEquivalenceTable.get(instructionCode.substring(26,32)), new Font("Verdana", Font.BOLD, 13), frc);
- else //other instructions
- actionInFunctionalBlock = new TextLayout(opcodeEquivalenceTable.get(instructionCode.substring(0,6)), new Font("Verdana", Font.BOLD, 13), frc);
- }
-
- if(instructionCode.substring(0,6).matches("0001[0-1][0-1]")&& v.getName().equals("CP+4")) //branch code
- actionInFunctionalBlock = new TextLayout("PC+OFFSET", new Font("Verdana", Font.BOLD, 13), frc);
-
- if(v.getName().equals("WRITING")){
- if(!instructionCode.substring(0,6).matches("100[0-1][0-1][0-1]"))
- actionInFunctionalBlock = new TextLayout(" ", new Font("Verdana", Font.BOLD, 13), frc);
- }
- if(v.isActive() == true){
- v.setFirst_interaction(false);
- actionInFunctionalBlock.draw(g2d, v.getOppositeAxis(), v.getCurrent());
- if (v.getCurrent() == v.getEnd())
- v.setActive(false);
- v.setCurrent(v.getCurrent()-1);
- }
-
-
- }
-
- //convert binnary value to integer.
- public String parseBinToInt(String code){
- int value = 0;
-
- for(int i =code.length()-1; i >= 0; i--){
- if("1".equals(code.substring(i,i+1))){
- value = value + (int)Math.pow(2,code.length()-i-1);
- }
- }
-
- return Integer.toString(value);
- }
-
- //set and execute the information about the current position of each line of information in the animation,
- //verifies the previous status of the animation and increment the position of each line that interconnect the unit function.
- private void executeAnimation(Graphics g){
- g2d = (Graphics2D)g;
- setUpInstructionInfo(g2d);
- Vertex vert;
- for(int i = 0; i < vertexTraversed.size(); i++){
- vert = vertexTraversed.get(i);
- if(vert.isMovingXaxis == true){
- if(vert.getDirection() == vert.movingLeft){
- printTrackLtoR(vert);
- if(vert.isActive() == false){
- int j = vert.getTargetVertex().size();
- Vertex tempVertex;
- for(int k = 0; k < j; k++){
- tempVertex = outputGraph.get(vert.getNumIndex()).get(k);
- Boolean hasThisVertex = false;
- for(int m = 0 ; m < vertexTraversed.size(); m++){
- if(tempVertex.getNumIndex() == vertexTraversed.get(m).getNumIndex())
- hasThisVertex = true;
- }
- if(hasThisVertex == false){
- outputGraph.get(vert.getNumIndex()).get(k).setActive(true);
- vertexTraversed.add( outputGraph.get(vert.getNumIndex()).get(k));
- }
- }
- }
- }
- else{
- printTrackRtoL(vert);
- if(vert.isActive() == false){
- int j = vert.getTargetVertex().size();
- Vertex tempVertex;
- for(int k = 0; k < j; k++){
- tempVertex = outputGraph.get(vert.getNumIndex()).get(k);
- Boolean hasThisVertex = false;
- for(int m = 0 ; m < vertexTraversed.size(); m++){
- if(tempVertex.getNumIndex() == vertexTraversed.get(m).getNumIndex())
- hasThisVertex = true;
- }
- if(hasThisVertex == false){
- outputGraph.get(vert.getNumIndex()).get(k).setActive(true);
- vertexTraversed.add( outputGraph.get(vert.getNumIndex()).get(k));
- }
- }
- }
- }
- } //end of condition of X axis
- else{
- if(vert.getDirection() == vert.movingDownside){
- if(vert.isText == true)
- printTextDtoU(vert);
- else
- printTrackDtoU(vert);
-
- if(vert.isActive() == false){
- int j = vert.getTargetVertex().size();
- Vertex tempVertex;
- for(int k = 0; k < j; k++){
- tempVertex = outputGraph.get(vert.getNumIndex()).get(k);
- Boolean hasThisVertex = false;
- for(int m = 0 ; m < vertexTraversed.size(); m++){
- if(tempVertex.getNumIndex() == vertexTraversed.get(m).getNumIndex())
- hasThisVertex = true;
- }
- if(hasThisVertex == false){
- outputGraph.get(vert.getNumIndex()).get(k).setActive(true);
- vertexTraversed.add( outputGraph.get(vert.getNumIndex()).get(k));
- }
- }
- }
-
- }
- else{
-
- printTrackUtoD(vert);
- if(vert.isActive() == false){
- int j = vert.getTargetVertex().size();
- Vertex tempVertex;
- for(int k = 0; k < j; k++){
- tempVertex = outputGraph.get(vert.getNumIndex()).get(k);
- Boolean hasThisVertex = false;
- for(int m = 0 ; m < vertexTraversed.size(); m++){
- if(tempVertex.getNumIndex() == vertexTraversed.get(m).getNumIndex())
- hasThisVertex = true;
- }
- if(hasThisVertex == false){
- outputGraph.get(vert.getNumIndex()).get(k).setActive(true);
- vertexTraversed.add( outputGraph.get(vert.getNumIndex()).get(k));
- }
- }
- }
- }
- }
- }
- }
-
- @Override
- public void mouseClicked(MouseEvent e) {
-
- PointerInfo a = MouseInfo.getPointerInfo();
- //limpar a imagem do painel e iniciar o detalhe da unidade funcional.
-
-
- if(e.getPoint().getX() > 425 && e.getPoint().getX() < 520 && e.getPoint().getY() > 300 && e.getPoint().getY() < 425){
- buildMainDisplayArea("register.png");
- FunctionUnitVisualization fu = new FunctionUnitVisualization(instructionBinary, register);
- fu.run();
- }
-
- if(e.getPoint().getX() > 355 && e.getPoint().getX() < 415 && e.getPoint().getY() > 180 && e.getPoint().getY() < 280){
- buildMainDisplayArea("control.png");
- FunctionUnitVisualization fu = new FunctionUnitVisualization(instructionBinary, control);
- fu.run();
- }
-
- if(e.getPoint().getX() > 560 && e.getPoint().getX() < 620 && e.getPoint().getY() > 450 && e.getPoint().getY() < 520){
- buildMainDisplayArea("ALUcontrol.png");
- FunctionUnitVisualization fu = new FunctionUnitVisualization(instructionBinary, aluControl);
- fu.run();
- }
-
- }
-
- @Override
- public void mouseEntered(MouseEvent e) {
- }
-
- @Override
- public void mouseExited(MouseEvent e) {
- }
-
- @Override
- public void mouseReleased(MouseEvent e) {
- }
- }
+ public void updateDisplay()
+ {
+ this.repaint();
+ }
+
+ //set the tool bar that controls the step in a time instruction running.
+ private JToolBar setUpToolBar()
+ {
+ JToolBar toolBar = new JToolBar();
+ Assemble = new JButton(runAssembleAction);
+ Assemble.setText("");
+ runBackStep = new JButton(runBackstepAction);
+ runBackStep.setText("");
+
+ Step = new JButton(runStepAction);
+ Step.setText("");
+ toolBar.add(Assemble);
+ toolBar.add(Step);
+
+ return toolBar;
+ }
+
+ //set action in the menu bar.
+ private void createActionObjects()
+ {
+ Toolkit tk = Toolkit.getDefaultToolkit();
+ Class cs = this.getClass();
+ try
+ {
+ runAssembleAction = new RunAssembleAction("Assemble",
+ new ImageIcon(tk.getImage(cs.getResource(Globals.imagesPath + "Assemble22.png"))),
+ "Assemble the current file and clear breakpoints", Integer.valueOf(KeyEvent.VK_A),
+ KeyStroke.getKeyStroke(KeyEvent.VK_F3, 0),
+ mainUI);
+
+ runStepAction = new RunStepAction("Step",
+ new ImageIcon(tk.getImage(cs.getResource(Globals.imagesPath + "StepForward22.png"))),
+ "Run one step at a time", Integer.valueOf(KeyEvent.VK_T),
+ KeyStroke.getKeyStroke(KeyEvent.VK_F7, 0),
+ mainUI);
+ runBackstepAction = new RunBackstepAction("Backstep",
+ new ImageIcon(tk.getImage(cs.getResource(Globals.imagesPath + "StepBack22.png"))),
+ "Undo the last step", Integer.valueOf(KeyEvent.VK_B),
+ KeyStroke.getKeyStroke(KeyEvent.VK_F8, 0),
+ mainUI);
+ }
+ catch (Exception e)
+ {
+ System.out.println("Internal Error: images folder not found, or other null pointer exception while creating Action objects");
+ e.printStackTrace();
+ System.exit(0);
+ }
+ }
+
+
+ class Vertex
+ {
+ public static final int movingUpside = 1;
+
+ public static final int movingDownside = 2;
+
+ public static final int movingLeft = 3;
+
+ public static final int movingRight = 4;
+
+ public int direction;
+
+ public int oppositeAxis;
+
+ private int numIndex;
+
+ private int init;
+
+ private int end;
+
+ private int current;
+
+ private String name;
+
+ private boolean isMovingXaxis;
+
+ private Color color;
+
+ private boolean first_interaction;
+
+ private boolean active;
+
+ private final boolean isText;
+
+ private final ArrayList targetVertex;
+
+ public Vertex(int index, int init, int end, String name, int oppositeAxis, boolean isMovingXaxis,
+ String listOfColors, String listTargetVertex, boolean isText)
+ {
+ this.numIndex = index;
+ this.init = init;
+ this.current = this.init;
+ this.end = end;
+ this.name = name;
+ this.oppositeAxis = oppositeAxis;
+ this.isMovingXaxis = isMovingXaxis;
+ this.first_interaction = true;
+ this.active = false;
+ this.isText = isText;
+ this.color = new Color(0, 153, 0);
+ if (isMovingXaxis)
+ {
+ if (init < end)
+ {
+ direction = movingLeft;
+ }
+ else
+ {
+ direction = movingRight;
+ }
+
+ }
+ else
+ {
+ if (init < end)
+ {
+ direction = movingUpside;
+ }
+ else
+ {
+ direction = movingDownside;
+ }
+ }
+ String[] list = listTargetVertex.split("#");
+ targetVertex = new ArrayList();
+ for (int i = 0; i < list.length; i++)
+ {
+ targetVertex.add(Integer.parseInt(list[i]));
+ // System.out.println("Adding " + i + " " + Integer.parseInt(list[i])+ " in target");
+ }
+ String[] listColor = listOfColors.split("#");
+ this.color = new Color(Integer.parseInt(listColor[0]), Integer.parseInt(listColor[1]), Integer.parseInt(listColor[2]));
+ }
+
+ public int getDirection()
+ {
+ return direction;
+ }
+
+ public boolean isText()
+ {
+ return this.isText;
+ }
+
+
+ public ArrayList getTargetVertex()
+ {
+ return targetVertex;
+ }
+
+ public int getNumIndex()
+ {
+ return numIndex;
+ }
+
+ public void setNumIndex(int numIndex)
+ {
+ this.numIndex = numIndex;
+ }
+
+ public int getInit()
+ {
+ return init;
+ }
+
+ public void setInit(int init)
+ {
+ this.init = init;
+ }
+
+ public int getEnd()
+ {
+ return end;
+ }
+
+ public void setEnd(int end)
+ {
+ this.end = end;
+ }
+
+ public int getCurrent()
+ {
+ return current;
+ }
+
+ public void setCurrent(int current)
+ {
+ this.current = current;
+ }
+
+ public String getName()
+ {
+ return name;
+ }
+
+ public void setName(String name)
+ {
+ this.name = name;
+ }
+
+ public int getOppositeAxis()
+ {
+ return oppositeAxis;
+ }
+
+ public void setOppositeAxis(int oppositeAxis)
+ {
+ this.oppositeAxis = oppositeAxis;
+ }
+
+ public boolean isMovingXaxis()
+ {
+ return isMovingXaxis;
+ }
+
+ public void setMovingXaxis(boolean isMovingXaxis)
+ {
+ this.isMovingXaxis = isMovingXaxis;
+ }
+
+ public Color getColor()
+ {
+ return color;
+ }
+
+ public void setColor(Color color)
+ {
+ this.color = color;
+ }
+
+ public boolean isFirst_interaction()
+ {
+ return first_interaction;
+ }
+
+ public void setFirst_interaction(boolean first_interaction)
+ {
+ this.first_interaction = first_interaction;
+ }
+
+ public boolean isActive()
+ {
+ return active;
+ }
+
+ public void setActive(boolean active)
+ {
+ this.active = active;
+ }
+ }
+
+
+ //Internal class that set the parameters value, control the basic behavior of the animation , and execute the animation of the
+ //selected instruction in memory.
+ class DatapathAnimation extends JPanel
+ implements ActionListener, MouseListener
+ {
+ /**
+ *
+ */
+ private static final long serialVersionUID = -2681757800180958534L;
+
+ private static final int PWIDTH = 1000; // size of this panel
+
+ private static final int PHEIGHT = 574;
+
+ //config variables
+ private final int PERIOD = 5; // velocity of frames in ms
+
+ private final GraphicsConfiguration gc;
+
+ private final GraphicsDevice gd; // for reporting accl. memory usage
+
+ private final int accelMemory;
+
+ private final DecimalFormat df;
+
+ private int counter; //verify then remove.
+
+ private boolean justStarted; //flag to start movement
+
+
+ private int indexX; //counter of screen position
+
+ private int indexY;
+
+ private boolean xIsMoving, yIsMoving; //flag for mouse movement.
+
+
+ // private Vertex[][] inputGraph;
+ private Vector> outputGraph;
+
+ private final ArrayList vertexList;
+
+ private ArrayList vertexTraversed;
+ //Screen Label variables
+
+ private final HashMap opcodeEquivalenceTable;
+
+ private final HashMap functionEquivalenceTable;
+
+ private final HashMap registerEquivalenceTable;
+
+ private String instructionCode;
+
+ private final int countRegLabel;
+
+ private final int countALULabel;
+
+ private final int countPCLabel;
+
+ //Colors variables
+ private final Color green1 = new Color(0, 153, 0);
+
+ private final Color green2 = new Color(0, 77, 0);
+
+ private final Color yellow2 = new Color(185, 182, 42);
+
+ private final Color orange1 = new Color(255, 102, 0);
+
+ private final Color orange = new Color(119, 34, 34);
+
+ private final Color blue2 = new Color(0, 153, 255);
+
+ private final int register = 1;
+
+ private final int control = 2;
+
+ private final int aluControl = 3;
+
+ private final int alu = 4;
+
+ private int currentUnit;
+
+ private Graphics2D g2d;
+
+
+ private BufferedImage datapath;
+
+ public DatapathAnimation(String instructionBinary)
+ {
+ df = new DecimalFormat("0.0"); // 1 dp
+ GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
+ gd = ge.getDefaultScreenDevice();
+ gc = ge.getDefaultScreenDevice().getDefaultConfiguration();
+
+ accelMemory = gd.getAvailableAcceleratedMemory(); // in bytes
+ setBackground(Color.white);
+ setPreferredSize(new Dimension(PWIDTH, PHEIGHT));
+
+ // load and initialise the images
+ initImages();
+
+ vertexList = new ArrayList();
+ counter = 0;
+ justStarted = true;
+ instructionCode = instructionBinary;
+
+ //declaration of labels definition.
+ opcodeEquivalenceTable = new HashMap();
+ functionEquivalenceTable = new HashMap