9 Commits

Author SHA1 Message Date
Hykilpikonna 792ac61027 [PR] Merge pull request #1 from youssefsoli/feature/persist-bitmap-display-settings
Added persistence to the bitmap display settings
2022-11-24 12:57:01 -05:00
youssefsoli c7e94301ec Added persistence to the bitmap display settings
This was achieved by using the pre-existing global settings object
and adding functionality for saving and retrieving integer-based
preferences.
2022-11-23 21:29:28 -05:00
Azalea (on HyDEV-Daisy) ba606fd3c8 [F] Fix original MMIO keyboard sync deadlock 2022-11-16 04:39:42 -05:00
Hykilpikonna 91bed21747 [+] 4.7rc3 2022-11-13 00:45:54 -05:00
Hykilpikonna b402df8e1b [+] Old keyboard compatibility 2022-11-13 00:44:00 -05:00
Hykilpikonna d6dab423cc Update README.md 2022-11-12 18:27:33 -05:00
Hykilpikonna ed74f3355a [+] 4.7rc2 2022-11-12 18:26:09 -05:00
Hykilpikonna 2c8c4f51a5 [O] Optimize a lot of things 2022-11-12 17:06:02 -05:00
Hykilpikonna 18750d7595 [+] Gradle version settings 2022-11-11 22:30:57 -05:00
26 changed files with 638 additions and 598 deletions
+32
View File
@@ -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++
![Demo](img/bitmap_display_plus_plus.png)
@@ -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.
![image](https://user-images.githubusercontent.com/22280294/201498543-02a74fb4-9f55-45c8-8eaf-6f1531ab02bd.png)
For example, if I loop through the display and change every pixel in my assembly code, the original running time of hw will now take h2w2, making it take around one second for each update.
Since I cant 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:
![image](https://user-images.githubusercontent.com/22280294/201498548-1e8712ef-79d6-45e9-9d22-096148185c64.png)
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.
+2
View File
@@ -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
View File
@@ -1 +1 @@
rootProject.name = 'MARS'
rootProject.name = 'EMARS'
+2 -2
View File
@@ -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;
}
+1 -1
View File
@@ -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
{
+1 -1
View File
@@ -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
+165 -2
View File
@@ -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
+11 -80
View File
@@ -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;
}
+1 -29
View File
@@ -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)
{
+1 -1
View File
@@ -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));
}
+8 -8
View File
@@ -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
+1 -1
View File
@@ -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)
+70 -54
View File
@@ -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())
{
-6
View File
@@ -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();
+1 -1
View File
@@ -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)
{
+1 -1
View File
@@ -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);
}
/**
+14
View File
@@ -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)
})
}