Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 15880ddb7f | |||
| f89c5de7a4 | |||
| 792ac61027 | |||
| c7e94301ec | |||
| ba606fd3c8 | |||
| 91bed21747 | |||
| b402df8e1b |
@@ -11,6 +11,7 @@
|
||||
* 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)
|
||||
|
||||
@@ -21,13 +22,13 @@
|
||||
|
||||
## Modifications needed
|
||||
|
||||
1. To use **Bitmap Display++**, please add the following code at the end of each render loop:
|
||||
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)
|
||||
sb $t9, 0($t8)
|
||||
```
|
||||
|
||||
## Keyboard++
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@ plugins {
|
||||
id "com.github.johnrengelman.shadow" version "7.1.2"
|
||||
}
|
||||
|
||||
version="4.7rc2"
|
||||
version="4.7"
|
||||
|
||||
repositories {
|
||||
// Use Maven Central for resolving dependencies.
|
||||
|
||||
@@ -305,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";
|
||||
|
||||
@@ -351,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_";
|
||||
@@ -385,6 +399,8 @@ public class Settings extends Observable
|
||||
|
||||
private final String[] colorSettingsValues;
|
||||
|
||||
private final int[] integerSettingsValues;
|
||||
|
||||
private final Preferences preferences;
|
||||
|
||||
/* **************************************************************************
|
||||
@@ -427,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
|
||||
@@ -1221,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
|
||||
@@ -1268,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.
|
||||
*
|
||||
@@ -1380,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
|
||||
@@ -1413,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();
|
||||
}
|
||||
|
||||
@@ -1475,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.
|
||||
@@ -1555,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)
|
||||
{
|
||||
@@ -1590,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();
|
||||
}
|
||||
|
||||
@@ -1669,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
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package mars.tools
|
||||
|
||||
import mars.Globals
|
||||
import mars.Settings.IntegerSetting.*
|
||||
import mars.detectRadix
|
||||
import mars.mips.hardware.*
|
||||
import mars.toHex
|
||||
@@ -73,7 +74,8 @@ class BitmapDisplay : AbstractMarsToolAndApplication
|
||||
|
||||
// Keyboard++
|
||||
private var keyboardAddr: UInt = 0xFFFF0010u
|
||||
private var displayUpdateAddr: UInt = 0xFFFF0008u
|
||||
private var oldKeyboardAddr: UInt = 0xFFFF0000u
|
||||
private var oldKeyboardLastPressed: Char = ' '
|
||||
private var keyboardAttached = false
|
||||
private lateinit var uiKeyboard: JTextField
|
||||
|
||||
@@ -149,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
|
||||
@@ -201,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
|
||||
|
||||
@@ -208,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
|
||||
@@ -290,37 +310,46 @@ class BitmapDisplay : AbstractMarsToolAndApplication
|
||||
// UI components and layout for left half of GUI, where settings are specified.
|
||||
private fun buildOrganizationArea(): JComponent
|
||||
{
|
||||
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()
|
||||
reset()
|
||||
}
|
||||
}
|
||||
|
||||
val 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()
|
||||
reset()
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
@@ -328,13 +357,16 @@ class BitmapDisplay : AbstractMarsToolAndApplication
|
||||
}
|
||||
}
|
||||
|
||||
val 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()
|
||||
|
||||
@@ -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())
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user