From 6267d1d77769ce499ef7faadda0ddfe0f69d3599 Mon Sep 17 00:00:00 2001 From: Seth Morabito Date: Wed, 30 Dec 2015 10:56:03 -0800 Subject: [PATCH] Allow runtime selection of CPU speed --- src/main/java/com/loomcom/symon/Cpu.java | 23 ++++++- .../java/com/loomcom/symon/Simulator.java | 63 +++++++++++++++++-- 2 files changed, 77 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/loomcom/symon/Cpu.java b/src/main/java/com/loomcom/symon/Cpu.java index b49ff44..04e303d 100644 --- a/src/main/java/com/loomcom/symon/Cpu.java +++ b/src/main/java/com/loomcom/symon/Cpu.java @@ -58,8 +58,10 @@ public class Cpu implements InstructionTable { public static final int IRQ_VECTOR_L = 0xfffe; public static final int IRQ_VECTOR_H = 0xffff; - // Simulated speed is 1 MHz - private static final long CLOCK_IN_NS = 1000; + public static final long DEFAULT_CLOCK_PERIOD_IN_NS = 1000; + + /* Simulated clock speed (default is 1MHz) */ + private long clockPeriodInNs = DEFAULT_CLOCK_PERIOD_IN_NS; /* Simulated behavior */ private CpuBehavior behavior; @@ -901,6 +903,21 @@ public class Cpu implements InstructionTable { return result; } + /** + * @param clockPeriodInNs The simulated clock period, in nanoseconds + */ + public void setClockPeriodInNs(long clockPeriodInNs) { + logger.debug("Setting simulated clock period to {} ns.", clockPeriodInNs); + this.clockPeriodInNs = clockPeriodInNs; + } + + /** + * @return The simulated clock period, in nanoseconds + */ + public long getClockPeriodInNs() { + return clockPeriodInNs; + } + /** * Return the current Cpu State. * @@ -1344,7 +1361,7 @@ public class Cpu implements InstructionTable { return; } - long interval = clockSteps * CLOCK_IN_NS; + long interval = clockSteps * clockPeriodInNs; long end; do { diff --git a/src/main/java/com/loomcom/symon/Simulator.java b/src/main/java/com/loomcom/symon/Simulator.java index c8b18f8..a9cfccf 100644 --- a/src/main/java/com/loomcom/symon/Simulator.java +++ b/src/main/java/com/loomcom/symon/Simulator.java @@ -57,6 +57,9 @@ public class Simulator { private static final Font DEFAULT_FONT = new Font(Font.MONOSPACED, Font.PLAIN, DEFAULT_FONT_SIZE); private static final int CONSOLE_BORDER_WIDTH = 10; + // Clock periods, in NS, for each speed. 0MHz, 1MHz, 2MHz, 3MHz, 4MHz, 5MHz, 6MHz, 7MHz, 8MHz. + private static final long[] CLOCK_PERIODS = {0, 1000, 500, 333, 250, 200, 167, 143, 125}; + // Since it is very expensive to update the UI with Swing's Event Dispatch Thread, we can't afford // to refresh the status view on every simulated clock cycle. Instead, we will only refresh the status view // after this number of steps when running normally. @@ -597,7 +600,7 @@ public class Simulator { public SetFontAction(int size) { super(Integer.toString(size) + " pt", null); this.size = size; - putValue(SHORT_DESCRIPTION, "Set font to " + Integer.toString(size) + "pt."); + putValue(SHORT_DESCRIPTION, "Set font to " + size + "pt."); } public void actionPerformed(ActionEvent actionEvent) { @@ -608,6 +611,25 @@ public class Simulator { } } + class SetSpeedAction extends AbstractAction { + private int speed; + + public SetSpeedAction(int speed) { + super(Integer.toString(speed) + " MHz", null); + this.speed = speed; + putValue(SHORT_DESCRIPTION, "Set simulated speed to " + speed + " MHz."); + } + + @Override + public void actionPerformed(ActionEvent actionEvent) { + if (speed < 1 || speed > CLOCK_PERIODS.length - 1) { + return; + } + + machine.getCpu().setClockPeriodInNs(CLOCK_PERIODS[speed]); + } + } + class ToggleTraceWindowAction extends AbstractAction { public ToggleTraceWindowAction() { super("Trace Log", null); @@ -712,9 +734,6 @@ public class Simulator { JMenuItem prefsItem = new JMenuItem(new ShowPrefsAction()); fileMenu.add(prefsItem); - JMenuItem selectMachineItem = new JMenuItem(new SelectMachineAction()); - fileMenu.add(selectMachineItem); - JMenuItem quitItem = new JMenuItem(new QuitAction()); fileMenu.add(quitItem); @@ -772,14 +791,46 @@ public class Simulator { } add(viewMenu); + + /* + * Simulator Menu + */ + JMenu simulatorMenu = new JMenu("Simulator"); + JMenu speedSubMenu = new JMenu("Clock Speed"); + ButtonGroup speedGroup = new ButtonGroup(); + + makeSpeedMenuItem(1, speedSubMenu, speedGroup); + makeSpeedMenuItem(2, speedSubMenu, speedGroup); + makeSpeedMenuItem(4, speedSubMenu, speedGroup); + makeSpeedMenuItem(8, speedSubMenu, speedGroup); + + simulatorMenu.add(speedSubMenu); + + JMenuItem selectMachineItem = new JMenuItem(new SelectMachineAction()); + simulatorMenu.add(selectMachineItem); + + add(simulatorMenu); } - private void makeFontSizeMenuItem(int size, JMenu fontSubMenu, ButtonGroup group) { + private void makeFontSizeMenuItem(int size, JMenu subMenu, ButtonGroup group) { Action action = new SetFontAction(size); JCheckBoxMenuItem item = new JCheckBoxMenuItem(action); item.setSelected(size == DEFAULT_FONT_SIZE); - fontSubMenu.add(item); + subMenu.add(item); + group.add(item); + } + + private void makeSpeedMenuItem(int speed, JMenu subMenu, ButtonGroup group) { + if (speed < 1 || speed > CLOCK_PERIODS.length - 1) { + return; + } + + Action action = new SetSpeedAction(speed); + + JCheckBoxMenuItem item = new JCheckBoxMenuItem(action); + item.setSelected(CLOCK_PERIODS[speed] == Cpu.DEFAULT_CLOCK_PERIOD_IN_NS); + subMenu.add(item); group.add(item); } }