5 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
5 changed files with 209 additions and 14 deletions
+2 -1
View File
@@ -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,7 +22,7 @@
## 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
+1 -1
View File
@@ -6,7 +6,7 @@ plugins {
id "com.github.johnrengelman.shadow" version "7.1.2"
}
version="4.7rc2"
version="4.7rc3"
repositories {
// Use Maven Central for resolving dependencies.
+163 -1
View File
@@ -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
+42 -10
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
@@ -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())
{