Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 792ac61027 | |||
| c7e94301ec | |||
| ba606fd3c8 | |||
| 91bed21747 | |||
| b402df8e1b | |||
| d6dab423cc | |||
| ed74f3355a | |||
| 2c8c4f51a5 | |||
| 18750d7595 |
@@ -11,13 +11,26 @@
|
||||
* Switched to Gradle build system with Kotlin support
|
||||
* Added `--open` command-line option to open a file on start
|
||||
* Added **Keyboard++**: Enhanced keyboard events
|
||||
* **Keyboard++** is still compatible with old keyboard's ASM code, even though it only repeats the last key down until the key is released.
|
||||
* Refactored many classes in Kotlin
|
||||
* A LOT of [optimizations](https://github.com/hykilpikonna/EMARS#optimizations)
|
||||
|
||||
## FAQ
|
||||
|
||||
**How to run:** Install Java JDK >11 and double-click on the jar.
|
||||
**How to compile:** `gradle shadowJar`
|
||||
|
||||
## Modifications needed
|
||||
|
||||
1. To use **Bitmap Display++**, please add the following code at the end of each loop, after render but before sleep:
|
||||
|
||||
```asm
|
||||
# Tell the display to update
|
||||
lw $t8, ADDR_DISPLAY
|
||||
li $t9, 1
|
||||
sw $t9, 0($t8)
|
||||
```
|
||||
|
||||
## Keyboard++
|
||||
|
||||

|
||||
@@ -393,6 +406,25 @@ UNDEFINED = 0x0
|
||||
</details>
|
||||
|
||||
|
||||
## Optimizations
|
||||
|
||||
In MARS, the BitmapDisplay [re-draws the entire canvas](https://github.com/thomasrussellmurphy/MARS_Assembler/blob/c21dd72e8d2e4a51eb24e276c3f39ef1789148f2/mars/tools/BitmapDisplay.java#L496) instead of only the updated pixels whenever any memory address is updated. This makes updating the display very very very slow, taking 12% of all run time.
|
||||
|
||||

|
||||
|
||||
|
||||
For example, if I loop through the display and change every pixel in my assembly code, the original running time of h∗w will now take h2∗w2, making it take around one second for each update.
|
||||
|
||||
Since I can’t easily draw one pixel on update without manual manipulation of AWT Graphics, I changed it so that it treats bit 0 of the memory display as an “update bit,” and only re-draw the screen when the MIPS program sets bit 0 to 1.
|
||||
|
||||
After optimizing for this, it runs faster but still not enough for the animation to be smooth. Then, I discovered that most of the running time is used by the backstepper and notifying observers for changes in registers and memory:
|
||||
|
||||

|
||||
|
||||
|
||||
By default, MARS will store backstep register file copies each time a register is updated, which takes a lot of time since registers are updated very frequently. So I removed backstepping when the execution speed limit is not set. MARS also notifies all memory observers when a program statement instruction is read from memory, which I also removed because nothing uses the notification from reading program statements.
|
||||
|
||||
|
||||
## License
|
||||
[MIT][2]. Chech the [LICENSE][3] file. All the credits go to the original developers.
|
||||
|
||||
|
||||
@@ -6,6 +6,8 @@ plugins {
|
||||
id "com.github.johnrengelman.shadow" version "7.1.2"
|
||||
}
|
||||
|
||||
version="4.7rc3"
|
||||
|
||||
repositories {
|
||||
// Use Maven Central for resolving dependencies.
|
||||
mavenCentral()
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
rootProject.name = 'MARS'
|
||||
rootProject.name = 'EMARS'
|
||||
|
||||
@@ -410,7 +410,7 @@ public class MIPSprogram
|
||||
{
|
||||
steppedExecution = false;
|
||||
Simulator sim = Simulator.getInstance();
|
||||
return sim.simulate(this, RegisterFile.getProgramCounter(), maxSteps, breakPoints, a);
|
||||
return sim.simulate(this, RegisterFile.getPc(), maxSteps, breakPoints, a);
|
||||
}
|
||||
|
||||
|
||||
@@ -426,7 +426,7 @@ public class MIPSprogram
|
||||
{
|
||||
steppedExecution = true;
|
||||
Simulator sim = Simulator.getInstance();
|
||||
boolean done = sim.simulate(this, RegisterFile.getProgramCounter(), 1, null, a);
|
||||
boolean done = sim.simulate(this, RegisterFile.getPc(), 1, null, a);
|
||||
return done;
|
||||
}
|
||||
|
||||
|
||||
@@ -669,7 +669,7 @@ class MarsLaunch(var args: Array<String>)
|
||||
{
|
||||
out.print(reg + "\t")
|
||||
}
|
||||
value = RegisterFile.getUserRegister(reg).value
|
||||
value = RegisterFile.getUserRegister(reg)!!.value
|
||||
out.println(formatIntForDisplay(value))
|
||||
} else
|
||||
{
|
||||
|
||||
@@ -79,7 +79,7 @@ public class ProcessingException extends Exception
|
||||
{
|
||||
errs = new ErrorList();
|
||||
errs.add(new ErrorMessage(ps, "Runtime exception at " +
|
||||
Binary.intToHexString(RegisterFile.getProgramCounter() - Instruction.INSTRUCTION_LENGTH) +
|
||||
Binary.intToHexString(RegisterFile.getPc() - 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
|
||||
|
||||
@@ -2,6 +2,7 @@ package mars;
|
||||
|
||||
import mars.util.Binary;
|
||||
import mars.util.EditorFont;
|
||||
import mars.venus.RunSpeedPanel;
|
||||
import mars.venus.editors.jeditsyntax.SyntaxStyle;
|
||||
import mars.venus.editors.jeditsyntax.SyntaxUtilities;
|
||||
|
||||
@@ -304,6 +305,18 @@ public class Settings extends Observable
|
||||
*/
|
||||
public static final int REGISTER_HIGHLIGHT_FOREGROUND = 11;
|
||||
|
||||
|
||||
/**
|
||||
* Available integer-based settings
|
||||
*/
|
||||
public enum IntegerSetting
|
||||
{
|
||||
UNIT_WIDTH,
|
||||
UNIT_HEIGHT,
|
||||
DISPLAY_WIDTH,
|
||||
DISPLAY_HEIGHT,
|
||||
}
|
||||
|
||||
/* Properties file used to hold default settings. */
|
||||
private static final String settingsFile = "Settings";
|
||||
|
||||
@@ -350,6 +363,8 @@ public class Settings extends Observable
|
||||
*/
|
||||
private static final String[] defaultColorSettingsValues = {"0x00e0e0e0", "0", "0x00ffffff", "0", "0x00ffff99", "0", "0x0033ff00", "0", "0x0099ccff", "0", "0x0099cc55", "0"};
|
||||
|
||||
private static final int[] defaultIntegerSettingsValues = {2, 2, 512, 256};
|
||||
|
||||
private static final String SYNTAX_STYLE_COLOR_PREFIX = "SyntaxStyleColor_";
|
||||
|
||||
private static final String SYNTAX_STYLE_BOLD_PREFIX = "SyntaxStyleBold_";
|
||||
@@ -384,6 +399,8 @@ public class Settings extends Observable
|
||||
|
||||
private final String[] colorSettingsValues;
|
||||
|
||||
private final int[] integerSettingsValues;
|
||||
|
||||
private final Preferences preferences;
|
||||
|
||||
/* **************************************************************************
|
||||
@@ -426,6 +443,7 @@ public class Settings extends Observable
|
||||
fontStyleSettingsValues = new String[fontStyleSettingsKeys.length];
|
||||
fontSizeSettingsValues = new String[fontSizeSettingsKeys.length];
|
||||
colorSettingsValues = new String[colorSettingsKeys.length];
|
||||
integerSettingsValues = new int[IntegerSetting.values().length];
|
||||
// This determines where the values are actually stored. Actual implementation
|
||||
// is platform-dependent. For Windows, they are stored in Registry. To see,
|
||||
// run regedit and browse to: HKEY_CURRENT_USER\Software\JavaSoft\Prefs\mars
|
||||
@@ -448,7 +466,7 @@ public class Settings extends Observable
|
||||
*/
|
||||
public boolean getBackSteppingEnabled()
|
||||
{
|
||||
return (Globals.program != null && Globals.program.getBackStepper() != null && Globals.program.getBackStepper().enabled());
|
||||
return RunSpeedPanel.getInstance().getRunSpeed() != RunSpeedPanel.UNLIMITED_SPEED;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1220,7 +1238,7 @@ public class Settings extends Observable
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Color object for specified settings key. Returns null if key is not found or its value is not a valid color
|
||||
* Get Integer 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
|
||||
@@ -1267,6 +1285,54 @@ public class Settings extends Observable
|
||||
return getColorValueByPosition(position, defaultColorSettingsValues);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get int for specified settings key. Returns null if key is not found or its value is not a valid int
|
||||
* encoding.
|
||||
*
|
||||
* @param key the Setting key
|
||||
* @return corresponding int, or null if key not found or value not valid int
|
||||
*/
|
||||
public int getIntegerSettingByKey(IntegerSetting key)
|
||||
{
|
||||
return getIntegerValueByKey(key, integerSettingsValues);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get default int value for specified settings key. Returns null if key is not found or its value is not a valid
|
||||
* integer encoding.
|
||||
*
|
||||
* @param key the Setting key
|
||||
* @return corresponding default int, or null if key not found or value not valid integer
|
||||
*/
|
||||
public int getDefaultIntegerSettingByKey(IntegerSetting key)
|
||||
{
|
||||
return getIntegerValueByKey(key, defaultIntegerSettingsValues);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get int for specified settings name (a static constant). Returns null if argument invalid or its value
|
||||
* is not a valid integer encoding.
|
||||
*
|
||||
* @param position the Setting name (see list of static constants)
|
||||
* @return corresponding int, or null if argument invalid or value not valid integer
|
||||
*/
|
||||
public int getIntegerSettingByPosition(int position)
|
||||
{
|
||||
return getIntegerValueByPosition(position, integerSettingsValues);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get default int for specified settings name (a static constant). Returns null if argument invalid or its
|
||||
* value is not a valid integer encoding.
|
||||
*
|
||||
* @param position the Setting name (see list of static constants)
|
||||
* @return corresponding default int, or null if argument invalid or value not valid integer
|
||||
*/
|
||||
public int getDefaultIntegerSettingByPosition(int position)
|
||||
{
|
||||
return getIntegerValueByPosition(position, defaultIntegerSettingsValues);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set value of a boolean setting given its id and the value.
|
||||
*
|
||||
@@ -1379,6 +1445,38 @@ public class Settings extends Observable
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set int for specified settings key. Has no effect if key is invalid.
|
||||
*
|
||||
* @param key the Setting key
|
||||
* @param number the integer to save
|
||||
*/
|
||||
public void setIntegerSettingByKey(IntegerSetting key, int number)
|
||||
{
|
||||
for (int i = 0; i < IntegerSetting.values().length; i++)
|
||||
{
|
||||
if (key.equals(IntegerSetting.values()[i]))
|
||||
{
|
||||
setIntegerSettingByPosition(i, number);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set int for specified settings name (a static constant). Has no effect if invalid.
|
||||
*
|
||||
* @param position the Setting name (see list of static constants)
|
||||
* @param number the integer to save
|
||||
*/
|
||||
public void setIntegerSettingByPosition(int position, int number)
|
||||
{
|
||||
if (position >= 0 && position < IntegerSetting.values().length)
|
||||
{
|
||||
setIntegerSetting(position, number);
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PRIVATE HELPER METHODS TO DO THE REAL WORK
|
||||
@@ -1412,6 +1510,7 @@ public class Settings extends Observable
|
||||
fontSizeSettingsValues[i] = defaultFontSizeSettingsValues[i];
|
||||
}
|
||||
System.arraycopy(defaultColorSettingsValues, 0, colorSettingsValues, 0, colorSettingsValues.length);
|
||||
System.arraycopy(defaultIntegerSettingsValues, 0, integerSettingsValues, 0, integerSettingsValues.length);
|
||||
initializeEditorSyntaxStyles();
|
||||
}
|
||||
|
||||
@@ -1474,6 +1573,40 @@ public class Settings extends Observable
|
||||
return color;
|
||||
}
|
||||
|
||||
// Used by setter methods for integer-based settings
|
||||
private void setIntegerSetting(int settingIndex, int number)
|
||||
{
|
||||
integerSettingsValues[settingIndex] = number;
|
||||
saveIntegerSetting(settingIndex);
|
||||
}
|
||||
|
||||
// Get int for this key value. Get it from values array provided as argument (could be either
|
||||
// the current or the default settings array).
|
||||
private int getIntegerValueByKey(IntegerSetting key, int[] values)
|
||||
{
|
||||
int number = 0;
|
||||
for (int i = 0; i < IntegerSetting.values().length; i++)
|
||||
{
|
||||
if (key.equals(IntegerSetting.values()[i]))
|
||||
{
|
||||
return getIntegerValueByPosition(i, values);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Get int for this key array position. Get it from values array provided as argument (could be either
|
||||
// the current or the default settings array).
|
||||
private int getIntegerValueByPosition(int position, int[] values)
|
||||
{
|
||||
int number = 0;
|
||||
if (position >= 0 && position < IntegerSetting.values().length)
|
||||
{
|
||||
number = values[position];
|
||||
}
|
||||
return number;
|
||||
}
|
||||
|
||||
|
||||
// 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.
|
||||
@@ -1554,6 +1687,13 @@ public class Settings extends Observable
|
||||
colorSettingsValues[i] = defaultColorSettingsValues[i] = settingValue;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < IntegerSetting.values().length; i++) {
|
||||
settingValue = Globals.getPropertyEntry(filename, IntegerSetting.values()[i].name());
|
||||
if (settingValue != null)
|
||||
{
|
||||
integerSettingsValues[i] = defaultIntegerSettingsValues[i] = Integer.parseInt(settingValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -1589,6 +1729,11 @@ public class Settings extends Observable
|
||||
{
|
||||
colorSettingsValues[i] = preferences.get(colorSettingsKeys[i], colorSettingsValues[i]);
|
||||
}
|
||||
|
||||
for (int i = 0; i < IntegerSetting.values().length; i++)
|
||||
{
|
||||
integerSettingsValues[i] = preferences.getInt(IntegerSetting.values()[i].name(), integerSettingsValues[i]);
|
||||
}
|
||||
getEditorSyntaxStyleSettingsFromPreferences();
|
||||
}
|
||||
|
||||
@@ -1668,6 +1813,24 @@ public class Settings extends Observable
|
||||
}
|
||||
}
|
||||
|
||||
// Save the key-value pair in the Properties object and assure it is written to persisent storage.
|
||||
private void saveIntegerSetting(int index)
|
||||
{
|
||||
try
|
||||
{
|
||||
preferences.putInt(IntegerSetting.values()[index].name(), integerSettingsValues[index]);
|
||||
preferences.flush();
|
||||
}
|
||||
catch (SecurityException se)
|
||||
{
|
||||
// cannot write to persistent storage for security reasons
|
||||
}
|
||||
catch (BackingStoreException bse)
|
||||
{
|
||||
// unable to communicate with persistent storage (strange days)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Private helper to do the work of converting a string containing Text
|
||||
|
||||
@@ -3,7 +3,6 @@ package mars.mips.hardware;
|
||||
import mars.Globals;
|
||||
import mars.ProgramStatement;
|
||||
import mars.Settings;
|
||||
import mars.mips.instructions.Instruction;
|
||||
import mars.simulator.Exceptions;
|
||||
import mars.util.Binary;
|
||||
|
||||
@@ -571,7 +570,7 @@ public class Memory extends Observable
|
||||
|
||||
if (Globals.getSettings().getBooleanSetting(Settings.SELF_MODIFYING_CODE_ENABLED))
|
||||
{
|
||||
ProgramStatement oldStatement = getStatementNoNotify(address);
|
||||
ProgramStatement oldStatement = getStatement(address);
|
||||
if (oldStatement != null)
|
||||
{
|
||||
oldValue = oldStatement.getBinaryStatement();
|
||||
@@ -650,7 +649,7 @@ public class Memory extends Observable
|
||||
// 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);
|
||||
ProgramStatement oldStatement = getStatement(address);
|
||||
if (oldStatement != null)
|
||||
{
|
||||
oldValue = oldStatement.getBinaryStatement();
|
||||
@@ -861,11 +860,11 @@ public class Memory extends Observable
|
||||
}
|
||||
else if (inTextSegment(address))
|
||||
{
|
||||
// Burch Mod (Jan 2013): replace throw with calls to getStatementNoNotify & getBinaryStatement
|
||||
// Burch Mod (Jan 2013): replace throw with calls to getStatement & 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);
|
||||
ProgramStatement stmt = getStatement(address);
|
||||
value = stmt == null ? 0 : stmt.getBinaryStatement();
|
||||
}
|
||||
else
|
||||
@@ -947,11 +946,11 @@ public class Memory extends Observable
|
||||
}
|
||||
else if (inTextSegment(address))
|
||||
{
|
||||
// Burch Mod (Jan 2013): replace throw with calls to getStatementNoNotify & getBinaryStatement
|
||||
// Burch Mod (Jan 2013): replace throw with calls to getStatement & 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);
|
||||
ProgramStatement stmt = getStatement(address);
|
||||
value = stmt == null ? 0 : stmt.getBinaryStatement();
|
||||
}
|
||||
else
|
||||
@@ -1028,7 +1027,7 @@ public class Memory extends Observable
|
||||
{
|
||||
try
|
||||
{
|
||||
value = (getStatementNoNotify(address) == null) ? null : getStatementNoNotify(address).getBinaryStatement();
|
||||
value = (getStatement(address) == null) ? null : getStatement(address).getBinaryStatement();
|
||||
}
|
||||
catch (AddressErrorException aee)
|
||||
{
|
||||
@@ -1139,68 +1138,12 @@ public class Memory extends Observable
|
||||
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(
|
||||
"fetch address for text segment out of range or not aligned to word boundary ",
|
||||
Exceptions.ADDRESS_EXCEPTION_LOAD, address);
|
||||
}
|
||||
if (inTextSegment(address)) {
|
||||
return readProgramStatement(address, textBaseAddress, textBlockTable, true);
|
||||
}
|
||||
else {
|
||||
return readProgramStatement(address, kernelTextBaseAddress, kernelTextBlockTable,true);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// 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(
|
||||
"fetch address for text segment out of range or not aligned to word boundary ",
|
||||
Exceptions.ADDRESS_EXCEPTION_LOAD, address);
|
||||
}
|
||||
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
|
||||
public ProgramStatement getStatement(int address) throws AddressErrorException
|
||||
{
|
||||
if (!wordAligned(address))
|
||||
{
|
||||
@@ -1217,11 +1160,11 @@ public class Memory extends Observable
|
||||
}
|
||||
if (inTextSegment(address))
|
||||
{
|
||||
return readProgramStatement(address, textBaseAddress, textBlockTable, notify);
|
||||
return readProgramStatement(address, textBaseAddress, textBlockTable);
|
||||
}
|
||||
else if (inKernelTextSegment(address))
|
||||
{
|
||||
return readProgramStatement(address, kernelTextBaseAddress, kernelTextBlockTable, notify);
|
||||
return readProgramStatement(address, kernelTextBaseAddress, kernelTextBlockTable);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1601,7 +1544,7 @@ public class Memory extends Observable
|
||||
// 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)
|
||||
private ProgramStatement readProgramStatement(int address, int baseAddress, ProgramStatement[][] blockTable)
|
||||
{
|
||||
int relative = (address - baseAddress) >> 2; // convert byte address to words
|
||||
int block = relative / TEXT_BLOCK_LENGTH_WORDS;
|
||||
@@ -1611,25 +1554,13 @@ public class Memory extends Observable
|
||||
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];
|
||||
}
|
||||
}
|
||||
if (notify)
|
||||
{
|
||||
notifyAnyObservers(AccessNotice.READ, address, Instruction.INSTRUCTION_LENGTH, 0);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ public class Register extends Observable
|
||||
|
||||
private int resetValue;
|
||||
|
||||
// volatile should be enough to allow safe multi-threaded access
|
||||
// volatile should be enough to allow safe multithreaded 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.
|
||||
@@ -85,19 +85,6 @@ public class Register extends Observable
|
||||
*/
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -136,7 +123,6 @@ public class Register extends Observable
|
||||
{
|
||||
int old = value;
|
||||
value = val;
|
||||
notifyAnyObservers(AccessNotice.WRITE);
|
||||
return old;
|
||||
}
|
||||
|
||||
@@ -157,18 +143,4 @@ public class Register extends Observable
|
||||
{
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,395 +0,0 @@
|
||||
package mars.mips.hardware;
|
||||
|
||||
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
|
||||
|
||||
Developed by Pete Sanderson (psanderson@otterbein.edu)
|
||||
and Kenneth Vollmar (kenvollmar@missouristate.edu)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject
|
||||
to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
(MIT license, http://www.opensource.org/licenses/mit-license.html)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Represents the 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 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("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;
|
||||
}
|
||||
}
|
||||
}
|
||||
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
|
||||
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"))
|
||||
{
|
||||
//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)
|
||||
{
|
||||
return hi.getValue();
|
||||
}
|
||||
else if (num == 34)
|
||||
{
|
||||
return lo.getValue();
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
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()))
|
||||
{
|
||||
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)))
|
||||
{
|
||||
initializeProgramCounter(mainAddr);
|
||||
}
|
||||
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())
|
||||
{
|
||||
Globals.program.getBackStepper().addPCRestore(old);
|
||||
}
|
||||
return old;
|
||||
}
|
||||
|
||||
/**
|
||||
* For returning the program counters value.
|
||||
*
|
||||
* @return The program counters value as an int.
|
||||
**/
|
||||
|
||||
public static int getProgramCounter()
|
||||
{
|
||||
return programCounter.getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Register object for program counter. Use with caution.
|
||||
*
|
||||
* @return program counter's Register object.
|
||||
*/
|
||||
public static Register getProgramCounterRegister()
|
||||
{
|
||||
return programCounter;
|
||||
}
|
||||
|
||||
/**
|
||||
* For returning the program counter's initial (reset) value.
|
||||
*
|
||||
* @return The program counter's initial value
|
||||
**/
|
||||
|
||||
public static int getInitialProgramCounter()
|
||||
{
|
||||
return programCounter.getResetValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to reinitialize the values of the registers.
|
||||
* <b>NOTE:</b> Should <i>not</i> be called from command-mode MARS because this
|
||||
* this method uses global settings from the registry. Command-mode must operate using only the command switches,
|
||||
* not registry settings. It can be called from tools running stand-alone, and this is done in
|
||||
* <code>AbstractMarsToolAndApplication</code>.
|
||||
**/
|
||||
|
||||
public static void resetRegisters()
|
||||
{
|
||||
for (int i = 0; i < regFile.length; i++)
|
||||
{
|
||||
regFile[i].resetValue();
|
||||
}
|
||||
initializeProgramCounter(Globals.getSettings().getStartAtMain());// replaces "programCounter.resetValue()", DPS 3/3/09
|
||||
hi.resetValue();
|
||||
lo.resetValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to increment the Program counter in the general case (not a jump or branch).
|
||||
**/
|
||||
|
||||
public static void incrementPC()
|
||||
{
|
||||
programCounter.setValue(programCounter.getValue() + Instruction.INSTRUCTION_LENGTH);
|
||||
}
|
||||
|
||||
/**
|
||||
* Each individual register is a separate object and Observable. This handy method will add the given Observer to
|
||||
* each one. Currently does not apply to Program Counter.
|
||||
*/
|
||||
public static void addRegistersObserver(Observer observer)
|
||||
{
|
||||
for (int i = 0; i < regFile.length; i++)
|
||||
{
|
||||
regFile[i].addObserver(observer);
|
||||
}
|
||||
hi.addObserver(observer);
|
||||
lo.addObserver(observer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Each individual register is a separate object and Observable. This handy method will delete the given Observer
|
||||
* from each one. Currently does not apply to Program Counter.
|
||||
*/
|
||||
public static void deleteRegistersObserver(Observer observer)
|
||||
{
|
||||
for (int i = 0; i < regFile.length; i++)
|
||||
{
|
||||
regFile[i].deleteObserver(observer);
|
||||
}
|
||||
hi.deleteObserver(observer);
|
||||
lo.deleteObserver(observer);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,310 @@
|
||||
package mars.mips.hardware
|
||||
|
||||
import mars.Globals
|
||||
import mars.assembler.SymbolTable
|
||||
import mars.mips.instructions.Instruction
|
||||
import mars.util.Binary
|
||||
import java.util.*
|
||||
|
||||
/*
|
||||
Copyright (c) 2003-2008, Pete Sanderson and Kenneth Vollmar
|
||||
|
||||
Developed by Pete Sanderson (psanderson@otterbein.edu)
|
||||
and Kenneth Vollmar (kenvollmar@missouristate.edu)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject
|
||||
to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
(MIT license, http://www.opensource.org/licenses/mit-license.html)
|
||||
*/
|
||||
/**
|
||||
* Represents the collection of MIPS registers.
|
||||
*
|
||||
* @author Jason Bumgarner, Jason Shrewsbury
|
||||
* @version June 2003
|
||||
*/
|
||||
object RegisterFile
|
||||
{
|
||||
const val GLOBAL_POINTER_REGISTER = 28
|
||||
const val STACK_POINTER_REGISTER = 29
|
||||
|
||||
/**
|
||||
* For returning the set of registers.
|
||||
*
|
||||
* @return The set of registers.
|
||||
*/
|
||||
@JvmStatic
|
||||
val registers = arrayOf(
|
||||
Register("\$zero", 0, 0), Register("\$at", 1, 0),
|
||||
Register("\$v0", 2, 0), Register("\$v1", 3, 0),
|
||||
Register("\$a0", 4, 0), Register("\$a1", 5, 0),
|
||||
Register("\$a2", 6, 0), Register("\$a3", 7, 0),
|
||||
Register("\$t0", 8, 0), Register("\$t1", 9, 0),
|
||||
Register("\$t2", 10, 0), Register("\$t3", 11, 0),
|
||||
Register("\$t4", 12, 0), Register("\$t5", 13, 0),
|
||||
Register("\$t6", 14, 0), Register("\$t7", 15, 0),
|
||||
Register("\$s0", 16, 0), Register("\$s1", 17, 0),
|
||||
Register("\$s2", 18, 0), Register("\$s3", 19, 0),
|
||||
Register("\$s4", 20, 0), Register("\$s5", 21, 0),
|
||||
Register("\$s6", 22, 0), Register("\$s7", 23, 0),
|
||||
Register("\$t8", 24, 0), Register("\$t9", 25, 0),
|
||||
Register("\$k0", 26, 0), Register("\$k1", 27, 0),
|
||||
Register("\$gp", GLOBAL_POINTER_REGISTER, Memory.globalPointer),
|
||||
Register("\$sp", STACK_POINTER_REGISTER, Memory.stackPointer),
|
||||
Register("\$fp", 30, 0), Register("\$ra", 31, 0), // Internal registers
|
||||
Register("pc", 32, Memory.textBaseAddress),
|
||||
Register("hi", 33, 0),
|
||||
Register("lo", 34, 0)
|
||||
)
|
||||
|
||||
val registerNameIndex = registers.associateBy { it.name }
|
||||
|
||||
@JvmStatic
|
||||
val programCounterRegister = registers[32]
|
||||
@JvmStatic
|
||||
private val HI = registers[33]
|
||||
@JvmStatic
|
||||
private val LO = registers[34]
|
||||
|
||||
val backstep by lazy { Globals.getSettings().backSteppingEnabled }
|
||||
|
||||
/**
|
||||
* Method for displaying the register values for debugging.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun showRegisters()
|
||||
{
|
||||
for (register in registers)
|
||||
{
|
||||
println("Name: " + register.name)
|
||||
println("Number: " + register.number)
|
||||
println("Value: " + register.value)
|
||||
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 value The desired value for the register.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun updateRegister(num: Int, value: Int): Int
|
||||
{
|
||||
val old = 0
|
||||
if (num == 0)
|
||||
{
|
||||
println("You can not change the value of the zero register.")
|
||||
}
|
||||
else
|
||||
{
|
||||
registers[num].value = value
|
||||
}
|
||||
return old
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the register given to the value given.
|
||||
*
|
||||
* @param reg Name of register to set the value of.
|
||||
* @param value The desired value for the register.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun updateRegister(reg: String, value: Int)
|
||||
{
|
||||
registerNameIndex[reg]?.let {
|
||||
updateRegister(it.number, value)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the register who's number is num.
|
||||
*
|
||||
* @param num The register number.
|
||||
* @return The value of the given register.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getValue(num: Int) = registers[num].value
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getNumber(n: String) = registerNameIndex[n]?.number ?: -1
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getUserRegister(Rname: String): Register?
|
||||
{
|
||||
var reg: Register? = null
|
||||
if (Rname[0] == '$')
|
||||
{
|
||||
try
|
||||
{
|
||||
// check for register number 0-31.
|
||||
reg = registers[Binary.stringToInt(Rname.substring(1))] // KENV 1/6/05
|
||||
} catch (e: Exception)
|
||||
{
|
||||
// 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
|
||||
var i = 0
|
||||
while (i < registers.size)
|
||||
{
|
||||
if (Rname == registers[i].name)
|
||||
{
|
||||
reg = registers[i]
|
||||
break
|
||||
}
|
||||
i++
|
||||
}
|
||||
}
|
||||
}
|
||||
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.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun initializeProgramCounter(value: Int)
|
||||
{
|
||||
programCounterRegister.value = 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.
|
||||
*/
|
||||
fun initializeProgramCounter(startAtMain: Boolean)
|
||||
{
|
||||
val mainAddr = Globals.symbolTable.getAddress(SymbolTable.getStartLabel())
|
||||
if (startAtMain && mainAddr != SymbolTable.NOT_FOUND && (Memory.inTextSegment(mainAddr) || Memory.inKernelTextSegment(
|
||||
mainAddr
|
||||
))
|
||||
)
|
||||
{
|
||||
initializeProgramCounter(mainAddr)
|
||||
} else
|
||||
{
|
||||
initializeProgramCounter(programCounterRegister.resetValue)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
@JvmStatic
|
||||
fun setProgramCounter(value: Int): Int
|
||||
{
|
||||
val old = programCounterRegister.value
|
||||
programCounterRegister.value = value
|
||||
if (Globals.getSettings().backSteppingEnabled)
|
||||
{
|
||||
Globals.program.backStepper.addPCRestore(old)
|
||||
}
|
||||
return old
|
||||
}
|
||||
|
||||
/**
|
||||
* For returning the program counters value.
|
||||
*
|
||||
* @return The program counters value as an int.
|
||||
*/
|
||||
@JvmStatic
|
||||
val pc: Int
|
||||
get() = programCounterRegister.value
|
||||
|
||||
/**
|
||||
* For returning the program counter's initial (reset) value.
|
||||
*
|
||||
* @return The program counter's initial value
|
||||
*/
|
||||
val initialProgramCounter: Int
|
||||
get() = programCounterRegister.resetValue
|
||||
|
||||
/**
|
||||
* 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`.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun resetRegisters()
|
||||
{
|
||||
for (i in registers.indices)
|
||||
{
|
||||
registers[i].resetValue()
|
||||
}
|
||||
initializeProgramCounter(Globals.getSettings().startAtMain) // 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).
|
||||
*/
|
||||
@JvmStatic
|
||||
fun incrementPC()
|
||||
{
|
||||
programCounterRegister.value += 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.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun addRegistersObserver(observer: Observer?)
|
||||
{
|
||||
registers.filter { it.number != 32 }.forEach { it.addObserver(observer) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Each individual register is a separate object and Observable. This handy method will delete the given Observer
|
||||
* from each one. Currently does not apply to Program Counter.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun deleteRegistersObserver(observer: Observer?)
|
||||
{
|
||||
registers.filter { it.number != 32 }.forEach { it.deleteObserver(observer) }
|
||||
}
|
||||
}
|
||||
@@ -1239,7 +1239,7 @@ public class InstructionSet
|
||||
{
|
||||
int[] operands = statement.getOperands();
|
||||
processJump(
|
||||
((RegisterFile.getProgramCounter() & 0xF0000000)
|
||||
((RegisterFile.getPc() & 0xF0000000)
|
||||
| (operands[0] << 2)));
|
||||
}
|
||||
}));
|
||||
@@ -1268,7 +1268,7 @@ public class InstructionSet
|
||||
int[] operands = statement.getOperands();
|
||||
processReturnAddress(31);// RegisterFile.updateRegister(31, RegisterFile.getProgramCounter());
|
||||
processJump(
|
||||
(RegisterFile.getProgramCounter() & 0xF0000000)
|
||||
(RegisterFile.getPc() & 0xF0000000)
|
||||
| (operands[0] << 2));
|
||||
}
|
||||
}));
|
||||
@@ -3442,13 +3442,13 @@ public class InstructionSet
|
||||
if (Globals.getSettings().getDelayedBranchingEnabled())
|
||||
{
|
||||
// Register the branch target address (absolute byte address).
|
||||
DelayedBranch.register(RegisterFile.getProgramCounter() + (displacement << 2));
|
||||
DelayedBranch.register(RegisterFile.getPc() + (displacement << 2));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Decrement needed because PC has already been incremented
|
||||
RegisterFile.setProgramCounter(
|
||||
RegisterFile.getProgramCounter()
|
||||
RegisterFile.getPc()
|
||||
+ (displacement << 2)); // - Instruction.INSTRUCTION_LENGTH);
|
||||
}
|
||||
}
|
||||
@@ -3489,7 +3489,7 @@ public class InstructionSet
|
||||
|
||||
private void processReturnAddress(int register)
|
||||
{
|
||||
RegisterFile.updateRegister(register, RegisterFile.getProgramCounter() +
|
||||
RegisterFile.updateRegister(register, RegisterFile.getPc() +
|
||||
((Globals.getSettings().getDelayedBranchingEnabled()) ?
|
||||
Instruction.INSTRUCTION_LENGTH : 0));
|
||||
}
|
||||
|
||||
@@ -222,7 +222,7 @@ public class BackStepper
|
||||
private int pc()
|
||||
{
|
||||
// PC incremented prior to instruction simulation, so need to adjust for that.
|
||||
return RegisterFile.getProgramCounter() - Instruction.INSTRUCTION_LENGTH;
|
||||
return RegisterFile.getPc() - Instruction.INSTRUCTION_LENGTH;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -406,7 +406,7 @@ public class BackStepper
|
||||
// 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);
|
||||
ps = Globals.memory.getStatement(programCounter);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
||||
@@ -88,7 +88,7 @@ public class Exceptions
|
||||
// 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);
|
||||
Coprocessor0.updateRegister(Coprocessor0.EPC, RegisterFile.getPc() - 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));
|
||||
}
|
||||
|
||||
@@ -319,18 +319,18 @@ public class Simulator extends Observable
|
||||
ProgramStatement statement = null;
|
||||
try
|
||||
{
|
||||
statement = Globals.memory.getStatement(RegisterFile.getProgramCounter());
|
||||
statement = Globals.memory.getStatement(RegisterFile.getPc());
|
||||
}
|
||||
catch (AddressErrorException e)
|
||||
{
|
||||
ErrorList el = new ErrorList();
|
||||
el.add(new ErrorMessage((MIPSprogram) null, 0, 0, "invalid program counter value: " + Binary.intToHexString(RegisterFile.getProgramCounter())));
|
||||
el.add(new ErrorMessage((MIPSprogram) null, 0, 0, "invalid program counter value: " + Binary.intToHexString(RegisterFile.getPc())));
|
||||
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());
|
||||
Coprocessor0.updateRegister(Coprocessor0.EPC, RegisterFile.getPc());
|
||||
this.constructReturnReason = EXCEPTION;
|
||||
this.done = true;
|
||||
SystemIO.resetFiles(); // close any files opened in MIPS program
|
||||
@@ -373,7 +373,7 @@ public class Simulator extends Observable
|
||||
|
||||
while (statement != null)
|
||||
{
|
||||
pc = RegisterFile.getProgramCounter(); // added: 7/26/06 (explanation above)
|
||||
pc = RegisterFile.getPc(); // 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
|
||||
@@ -469,7 +469,7 @@ public class Simulator extends Observable
|
||||
}
|
||||
// Return if we've reached a breakpoint.
|
||||
if ((breakPoints != null) &&
|
||||
(Arrays.binarySearch(breakPoints, RegisterFile.getProgramCounter()) >= 0))
|
||||
(Arrays.binarySearch(breakPoints, RegisterFile.getPc()) >= 0))
|
||||
{
|
||||
this.constructReturnReason = BREAKPOINT;
|
||||
this.done = false;
|
||||
@@ -518,18 +518,18 @@ public class Simulator extends Observable
|
||||
|
||||
try
|
||||
{
|
||||
statement = Globals.memory.getStatement(RegisterFile.getProgramCounter());
|
||||
statement = Globals.memory.getStatement(RegisterFile.getPc());
|
||||
}
|
||||
catch (AddressErrorException e)
|
||||
{
|
||||
ErrorList el = new ErrorList();
|
||||
el.add(new ErrorMessage((MIPSprogram) null, 0, 0, "invalid program counter value: " + Binary.intToHexString(RegisterFile.getProgramCounter())));
|
||||
el.add(new ErrorMessage((MIPSprogram) null, 0, 0, "invalid program counter value: " + Binary.intToHexString(RegisterFile.getPc())));
|
||||
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());
|
||||
Coprocessor0.updateRegister(Coprocessor0.EPC, RegisterFile.getPc());
|
||||
this.constructReturnReason = EXCEPTION;
|
||||
this.done = true;
|
||||
SystemIO.resetFiles(); // close any files opened in MIPS program
|
||||
|
||||
@@ -365,7 +365,7 @@ public class BHTSimulator extends AbstractMarsToolAndApplication implements Acti
|
||||
try
|
||||
{
|
||||
// access the statement in the text segment without notifying other tools etc.
|
||||
ProgramStatement stmt = Memory.getInstance().getStatementNoNotify(memAccNotice.getAddress());
|
||||
ProgramStatement stmt = Memory.getInstance().getStatement(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)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package mars.tools
|
||||
|
||||
import mars.Globals
|
||||
import mars.Settings.IntegerSetting.*
|
||||
import mars.detectRadix
|
||||
import mars.mips.hardware.*
|
||||
import mars.toHex
|
||||
@@ -13,7 +14,6 @@ import java.util.*
|
||||
import javax.swing.*
|
||||
import javax.swing.border.EmptyBorder
|
||||
import kotlin.collections.ArrayList
|
||||
import kotlin.collections.HashMap
|
||||
import kotlin.collections.HashSet
|
||||
|
||||
/*
|
||||
@@ -51,10 +51,6 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
class BitmapDisplay : AbstractMarsToolAndApplication
|
||||
{
|
||||
// Major GUI components
|
||||
private lateinit var uiUnitWidthSelector: JComboBox<Int>
|
||||
private lateinit var uiUnitHeightSelector: JComboBox<Int>
|
||||
private lateinit var uiWidthSelector: JComboBox<Int>
|
||||
private lateinit var uiHeightSelector: JComboBox<Int>
|
||||
private lateinit var uiBaseAddressSelector: JComboBox<String>
|
||||
private lateinit var uiKeyboardCheckbox: JCheckBox
|
||||
private lateinit var canvas: JPanel
|
||||
@@ -65,10 +61,10 @@ class BitmapDisplay : AbstractMarsToolAndApplication
|
||||
private val backgroundColor = Color.WHITE
|
||||
|
||||
// Values for display canvas. Note their initialization uses the identifiers just above.
|
||||
private val unitWidth get() = uiUnitWidthSelector.getInt()
|
||||
private val unitHeight get() = uiUnitHeightSelector.getInt()
|
||||
private val displayWidth get() = uiWidthSelector.getInt()
|
||||
private val displayHeight get() = uiHeightSelector.getInt()
|
||||
private var unitWidth: Int = 2
|
||||
private var unitHeight: Int = 2
|
||||
private var displayWidth: Int = 512
|
||||
private var displayHeight: Int = 256
|
||||
private val displayDimension get() = Dimension(displayWidth, displayHeight)
|
||||
|
||||
private val baseAddresses = intArrayOf(Memory.dataSegmentBaseAddress, Memory.globalPointer, Memory.dataBaseAddress,
|
||||
@@ -78,6 +74,8 @@ class BitmapDisplay : AbstractMarsToolAndApplication
|
||||
|
||||
// Keyboard++
|
||||
private var keyboardAddr: UInt = 0xFFFF0010u
|
||||
private var oldKeyboardAddr: UInt = 0xFFFF0000u
|
||||
private var oldKeyboardLastPressed: Char = ' '
|
||||
private var keyboardAttached = false
|
||||
private lateinit var uiKeyboard: JTextField
|
||||
|
||||
@@ -153,7 +151,7 @@ class BitmapDisplay : AbstractMarsToolAndApplication
|
||||
if (ac !is MemoryAccessNotice || ac.accessType != AccessNotice.WRITE) return
|
||||
val addr = ac.address.toUInt()
|
||||
|
||||
// For the keyboard
|
||||
// For the keyboard++
|
||||
if (addr in keyboardAddr..keyboardAddr + 0x30u)
|
||||
{
|
||||
// Offset 0x01 or 0x11 or 0x21 bytes are for telling the keyboard that the events are received
|
||||
@@ -180,7 +178,17 @@ class BitmapDisplay : AbstractMarsToolAndApplication
|
||||
}
|
||||
|
||||
// For the display
|
||||
updateColorForAddress(ac)
|
||||
val value = ac.value
|
||||
val offset = ((addr - baseAddress.toUInt()) / 4u).toInt()
|
||||
try
|
||||
{
|
||||
grid.setElement(offset / grid.cols, offset % grid.cols, value)
|
||||
}
|
||||
catch (e: IndexOutOfBoundsException)
|
||||
{
|
||||
// If address is out of range for display, do nothing.
|
||||
}
|
||||
if (offset == 0) canvas.repaint()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -195,6 +203,24 @@ class BitmapDisplay : AbstractMarsToolAndApplication
|
||||
println("[Keyboard++] ${e.id} '${e.keyChar}' ${e.keyCode}")
|
||||
val queue = pooledKeyEvents[offset]!!
|
||||
|
||||
// Old keyboard compatibility
|
||||
synchronized(Globals.memoryAndRegistersLock)
|
||||
{
|
||||
if (e.id == KeyEvent.KEY_PRESSED)
|
||||
{
|
||||
oldKeyboardLastPressed = e.keyChar
|
||||
Globals.memory.setWord(oldKeyboardAddr.toInt(), 1)
|
||||
Globals.memory.setWord((oldKeyboardAddr + 4u).toInt(), e.keyChar.code)
|
||||
}
|
||||
|
||||
if (e.id == KeyEvent.KEY_RELEASED && e.keyChar == oldKeyboardLastPressed)
|
||||
{
|
||||
oldKeyboardLastPressed = 0.toChar()
|
||||
Globals.memory.setWord(oldKeyboardAddr.toInt(), 0)
|
||||
Globals.memory.setWord((oldKeyboardAddr + 4u).toInt(), 0)
|
||||
}
|
||||
}
|
||||
|
||||
// Check for more than 7 key events queued
|
||||
if (queue.size == 7) return
|
||||
|
||||
@@ -202,11 +228,11 @@ class BitmapDisplay : AbstractMarsToolAndApplication
|
||||
queue.add(e)
|
||||
|
||||
// Add to memory
|
||||
var addr = keyboardAddr + offset
|
||||
println("[Keyboard++] Address ${addr.toHex(8)} set to ${queue.size} | ${addr.toHex(8)} set to ${e.keyCode} (${e.keyChar.toHex()})")
|
||||
synchronized(Globals.memoryAndRegistersLock)
|
||||
{
|
||||
// Change 0x0: Number of events
|
||||
var addr = keyboardAddr + offset
|
||||
println("[Keyboard++] Address ${addr.toHex(8)} set to ${queue.size} | ${addr.toHex(8)} set to ${e.keyCode} (${e.keyChar.toHex()})")
|
||||
Globals.memory.setByte(addr.toInt(), queue.size)
|
||||
|
||||
// Set the keycode
|
||||
@@ -239,17 +265,10 @@ class BitmapDisplay : AbstractMarsToolAndApplication
|
||||
*/
|
||||
override fun reset()
|
||||
{
|
||||
resetCounts()
|
||||
updateDisplay()
|
||||
grid.reset()
|
||||
canvas.repaint()
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
override fun updateDisplay() = canvas.repaint()
|
||||
|
||||
/**
|
||||
* Overrides default method, to provide a Help button for this tool/app.
|
||||
*/
|
||||
@@ -291,51 +310,67 @@ class BitmapDisplay : AbstractMarsToolAndApplication
|
||||
// UI components and layout for left half of GUI, where settings are specified.
|
||||
private fun buildOrganizationArea(): JComponent
|
||||
{
|
||||
uiUnitWidthSelector = JComboBox(arrayOf(1, 2, 4, 8, 16, 32)).apply {
|
||||
unitWidth = Globals.getSettings().getIntegerSettingByKey(UNIT_WIDTH)
|
||||
val unitWidthOptions = arrayOf(1, 2, 4, 8, 16, 32)
|
||||
val uiUnitWidthSelector = JComboBox(arrayOf(1, 2, 4, 8, 16, 32)).apply {
|
||||
isEditable = false
|
||||
background = backgroundColor
|
||||
selectedIndex = 1
|
||||
selectedIndex = unitWidthOptions.indexOf(unitWidth)
|
||||
toolTipText = "Width in pixels of rectangle representing memory word"
|
||||
addActionListener {
|
||||
unitWidth = getInt()
|
||||
Globals.getSettings().setIntegerSettingByKey(UNIT_WIDTH, unitWidth)
|
||||
grid = createNewGrid()
|
||||
updateDisplay()
|
||||
reset()
|
||||
}
|
||||
}
|
||||
|
||||
uiUnitHeightSelector = JComboBox(arrayOf(1, 2, 4, 8, 16, 32)).apply {
|
||||
unitHeight = Globals.getSettings().getIntegerSettingByKey(UNIT_HEIGHT)
|
||||
val unitHeightOptions = arrayOf(1, 2, 4, 8, 16, 32)
|
||||
val uiUnitHeightSelector = JComboBox(unitHeightOptions).apply {
|
||||
isEditable = false
|
||||
background = backgroundColor
|
||||
selectedIndex = 1
|
||||
selectedIndex = unitHeightOptions.indexOf(unitHeight)
|
||||
toolTipText = "Height in pixels of rectangle representing memory word"
|
||||
addActionListener {
|
||||
unitHeight = getInt()
|
||||
Globals.getSettings().setIntegerSettingByKey(UNIT_HEIGHT, unitHeight)
|
||||
grid = createNewGrid()
|
||||
updateDisplay()
|
||||
reset()
|
||||
}
|
||||
}
|
||||
|
||||
uiWidthSelector = JComboBox(arrayOf(64, 128, 256, 512, 1024)).apply {
|
||||
displayWidth = Globals.getSettings().getIntegerSettingByKey(DISPLAY_WIDTH)
|
||||
val displayWidthOptions = arrayOf(64, 128, 256, 512, 1024)
|
||||
val uiWidthSelector = JComboBox(arrayOf(64, 128, 256, 512, 1024)).apply {
|
||||
isEditable = false
|
||||
background = backgroundColor
|
||||
selectedIndex = 3
|
||||
selectedIndex = displayWidthOptions.indexOf(displayWidth)
|
||||
toolTipText = "Total width in pixels of display area"
|
||||
addActionListener {
|
||||
displayWidth = getInt()
|
||||
Globals.getSettings().setIntegerSettingByKey(DISPLAY_WIDTH, displayWidth)
|
||||
canvas.preferredSize = displayDimension
|
||||
canvas.size = displayDimension
|
||||
grid = createNewGrid()
|
||||
updateDisplay()
|
||||
reset()
|
||||
}
|
||||
}
|
||||
|
||||
uiHeightSelector = JComboBox(arrayOf(64, 128, 256, 512, 1024)).apply {
|
||||
displayHeight = Globals.getSettings().getIntegerSettingByKey(DISPLAY_HEIGHT)
|
||||
val displayHeightOptions = arrayOf(64, 128, 256, 512, 1024)
|
||||
val uiHeightSelector = JComboBox(displayHeightOptions).apply {
|
||||
isEditable = false
|
||||
background = backgroundColor
|
||||
selectedIndex = 2
|
||||
selectedIndex = displayHeightOptions.indexOf(displayHeight)
|
||||
toolTipText = "Total height in pixels of display area"
|
||||
addActionListener {
|
||||
displayHeight = getInt()
|
||||
Globals.getSettings().setIntegerSettingByKey(DISPLAY_HEIGHT, displayHeight)
|
||||
canvas.preferredSize = displayDimension
|
||||
canvas.size = displayDimension
|
||||
grid = createNewGrid()
|
||||
updateDisplay()
|
||||
reset()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -358,7 +393,7 @@ class BitmapDisplay : AbstractMarsToolAndApplication
|
||||
addAsObserver()
|
||||
}
|
||||
grid = createNewGrid()
|
||||
updateDisplay()
|
||||
reset()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -467,9 +502,6 @@ class BitmapDisplay : AbstractMarsToolAndApplication
|
||||
return canvas
|
||||
}
|
||||
|
||||
// reset all counters in the Grid.
|
||||
private fun resetCounts() = grid.reset()
|
||||
|
||||
private fun <T> JComboBox<T>.getInt() = selectedItem!!.toString().toInt()
|
||||
|
||||
// Use this for consistent results.
|
||||
@@ -484,22 +516,6 @@ class BitmapDisplay : AbstractMarsToolAndApplication
|
||||
return Grid(rows, columns)
|
||||
}
|
||||
|
||||
// Given memory address, update color for the corresponding grid element.
|
||||
private fun updateColorForAddress(notice: MemoryAccessNotice)
|
||||
{
|
||||
val address = notice.address
|
||||
val value = notice.value
|
||||
val offset = (address - baseAddress) / Memory.WORD_LENGTH_BYTES
|
||||
try
|
||||
{
|
||||
grid.setElement(offset / grid.cols, offset % grid.cols, value)
|
||||
}
|
||||
catch (e: IndexOutOfBoundsException)
|
||||
{
|
||||
// If address is out of range for display, do nothing.
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
// Specialized inner classes for modeling and animation.
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -318,7 +318,7 @@ public class InstructionStatistics extends AbstractMarsToolAndApplication
|
||||
{
|
||||
|
||||
// access the statement in the text segment without notifying other tools etc.
|
||||
ProgramStatement stmt = Memory.getInstance().getStatementNoNotify(memAccNotice.getAddress());
|
||||
ProgramStatement stmt = Memory.getInstance().getStatement(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)
|
||||
|
||||
@@ -838,7 +838,7 @@ public class KeyboardAndDisplaySimulator extends AbstractMarsToolAndApplication
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// This one does the work: update the MMIO Control and optionally the Data register as well
|
||||
// NOTE: last argument TRUE means update only the MMIO Control register; FALSE means update both Control and Data.
|
||||
private synchronized void updateMMIOControlAndData(int controlAddr, int controlValue, int dataAddr, int dataValue, boolean controlOnly)
|
||||
private void updateMMIOControlAndData(int controlAddr, int controlValue, int dataAddr, int dataValue, boolean controlOnly)
|
||||
{
|
||||
if (!this.isBeingUsedAsAMarsTool || connectButton.isConnected())
|
||||
{
|
||||
|
||||
@@ -9,7 +9,6 @@ import mars.mips.hardware.MemoryAccessNotice;
|
||||
import mars.mips.instructions.BasicInstruction;
|
||||
import mars.mips.instructions.BasicInstructionFormat;
|
||||
import mars.venus.RunAssembleAction;
|
||||
import mars.venus.RunBackstepAction;
|
||||
import mars.venus.RunStepAction;
|
||||
import mars.venus.VenusUI;
|
||||
import org.w3c.dom.Document;
|
||||
@@ -313,11 +312,6 @@ public class MipsXray extends AbstractMarsToolAndApplication
|
||||
"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)
|
||||
{
|
||||
|
||||
@@ -117,7 +117,7 @@ public class RegistersWindow extends JPanel implements Observer
|
||||
}
|
||||
tableData[32][0] = "pc";
|
||||
tableData[32][1] = "";//new Integer(32);
|
||||
tableData[32][2] = NumberDisplayBaseChooser.formatUnsignedInteger(RegisterFile.getProgramCounter(), valueBase);
|
||||
tableData[32][2] = NumberDisplayBaseChooser.formatUnsignedInteger(RegisterFile.getPc(), valueBase);
|
||||
|
||||
tableData[33][0] = "hi";
|
||||
tableData[33][1] = "";//new Integer(33);
|
||||
@@ -184,7 +184,7 @@ public class RegistersWindow extends JPanel implements Observer
|
||||
{
|
||||
updateRegisterValue(registers[i].getNumber(), registers[i].getValue(), base);
|
||||
}
|
||||
updateRegisterUnsignedValue(32, RegisterFile.getProgramCounter(), base);
|
||||
updateRegisterUnsignedValue(32, RegisterFile.getPc(), base);
|
||||
updateRegisterValue(33, RegisterFile.getValue(33), base);
|
||||
updateRegisterValue(34, RegisterFile.getValue(34), base);
|
||||
}
|
||||
@@ -227,6 +227,7 @@ public class RegistersWindow extends JPanel implements Observer
|
||||
// or stepped mode.
|
||||
if (notice.getRunSpeed() != RunSpeedPanel.UNLIMITED_SPEED || notice.getMaxSteps() == 1)
|
||||
{
|
||||
System.out.println("Running in timed mode");
|
||||
RegisterFile.addRegistersObserver(this);
|
||||
this.highlighting = true;
|
||||
}
|
||||
|
||||
@@ -75,12 +75,12 @@ public class RunBackstepAction extends GuiAction
|
||||
{
|
||||
boolean inDelaySlot = Globals.program.getBackStepper().inDelaySlot(); // Added 25 June 2007
|
||||
Memory.getInstance().addObserver(executePane.getDataSegmentWindow());
|
||||
RegisterFile.addRegistersObserver(executePane.getRegistersWindow());
|
||||
//RegisterFile.addRegistersObserver(executePane.getRegistersWindow());
|
||||
Coprocessor0.addRegistersObserver(executePane.getCoprocessor0Window());
|
||||
Coprocessor1.addRegistersObserver(executePane.getCoprocessor1Window());
|
||||
Globals.program.getBackStepper().backStep();
|
||||
Memory.getInstance().deleteObserver(executePane.getDataSegmentWindow());
|
||||
RegisterFile.deleteRegistersObserver(executePane.getRegistersWindow());
|
||||
//RegisterFile.deleteRegistersObserver(executePane.getRegistersWindow());
|
||||
executePane.getRegistersWindow().updateRegisters();
|
||||
executePane.getCoprocessor1Window().updateRegisters();
|
||||
executePane.getCoprocessor0Window().updateRegisters();
|
||||
|
||||
@@ -170,7 +170,7 @@ public class RunGoAction extends GuiAction
|
||||
mainUI.getRegistersPane().setSelectedComponent(executePane.getCoprocessor0Window());
|
||||
executePane.getTextSegmentWindow().setCodeHighlighting(true);
|
||||
executePane.getTextSegmentWindow().unhighlightAllSteps();
|
||||
executePane.getTextSegmentWindow().highlightStepAtAddress(RegisterFile.getProgramCounter() - 4);
|
||||
executePane.getTextSegmentWindow().highlightStepAtAddress(RegisterFile.getPc() - 4);
|
||||
}
|
||||
switch (reason)
|
||||
{
|
||||
|
||||
@@ -126,7 +126,7 @@ public class RunStepAction extends GuiAction
|
||||
FileStatus.set(FileStatus.TERMINATED); // should be redundant.
|
||||
executePane.getTextSegmentWindow().setCodeHighlighting(true);
|
||||
executePane.getTextSegmentWindow().unhighlightAllSteps();
|
||||
executePane.getTextSegmentWindow().highlightStepAtAddress(RegisterFile.getProgramCounter() - 4);
|
||||
executePane.getTextSegmentWindow().highlightStepAtAddress(RegisterFile.getPc() - 4);
|
||||
}
|
||||
VenusUI.setReset(false);
|
||||
}
|
||||
|
||||
@@ -577,7 +577,7 @@ public class TextSegmentWindow extends JInternalFrame implements Observer
|
||||
*/
|
||||
public void highlightStepAtPC()
|
||||
{
|
||||
highlightStepAtAddress(RegisterFile.getProgramCounter(), false);
|
||||
highlightStepAtAddress(RegisterFile.getPc(), false);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -589,7 +589,7 @@ public class TextSegmentWindow extends JInternalFrame implements Observer
|
||||
*/
|
||||
public void highlightStepAtPC(boolean inDelaySlot)
|
||||
{
|
||||
highlightStepAtAddress(RegisterFile.getProgramCounter(), inDelaySlot);
|
||||
highlightStepAtAddress(RegisterFile.getPc(), inDelaySlot);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
import mars.Globals
|
||||
import mars.mips.hardware.MemoryConfigurations
|
||||
import kotlin.system.measureTimeMillis
|
||||
|
||||
fun main(args: Array<String>)
|
||||
{
|
||||
Globals.initialize(true)
|
||||
MemoryConfigurations.setCurrentConfiguration(MemoryConfigurations.getDefaultConfiguration())
|
||||
println(measureTimeMillis {
|
||||
for (n in 0..100)
|
||||
for (i in 0..128*256)
|
||||
Globals.memory.getWord(0x10008000 + i * 4)
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user