diff --git a/README.md b/README.md index 1c0179e..dc53b96 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,8 @@ java --enable-preview -jar emulator-awt/target/emulator-awt-1.0-SNAPSHOT-jar-wit To emulate **SuperCHIP-8**: +Select `SuperCHIP-8` from the VM menu or start the emulator with: + ```bash java --enable-preview -jar emulator-awt/target/emulator-awt-1.0-SNAPSHOT-jar-with-dependencies.jar --superchip8 ``` @@ -142,7 +144,7 @@ interpreter.load(0x200, program) interpreter.tick(); } ``` - +__ ## Further direction - Add VM save and load snapshot feature - save game support for all kinds of programs. diff --git a/chipsekiz/docs/chipsekiz.png b/chipsekiz/docs/chipsekiz.png index 7e612b2..2944835 100644 Binary files a/chipsekiz/docs/chipsekiz.png and b/chipsekiz/docs/chipsekiz.png differ diff --git a/emulator-awt/src/main/java/dev/krk/chipsekiz/emulator/App.java b/emulator-awt/src/main/java/dev/krk/chipsekiz/emulator/App.java index 40566ec..1746518 100644 --- a/emulator-awt/src/main/java/dev/krk/chipsekiz/emulator/App.java +++ b/emulator-awt/src/main/java/dev/krk/chipsekiz/emulator/App.java @@ -4,9 +4,6 @@ import javax.sound.sampled.LineUnavailableException; -import java.util.Timer; -import java.util.TimerTask; - public class App { public static void main(String[] args) throws LineUnavailableException { EmulatorOptions options = new EmulatorOptions(true); @@ -26,30 +23,7 @@ public static void main(String[] args) throws LineUnavailableException { } } - runEmulator(factory, options, resolution); - } - - private static void runEmulator(IEmulatableFactory factory, EmulatorOptions options, - Resolution resolution) throws LineUnavailableException { - final Tone tone = new Tone(1600); - - IEmulatable e = factory.create(options, tone); - IEmulatorController controller = e.getController(); - EmulatorWindow win = new EmulatorWindow(e.getCanvas(), controller, resolution); - - Timer timer = new Timer(); - timer.scheduleAtFixedRate(new TimerTask() { - @Override public void run() { - win.setTitle( - String.format("chipsekiz emulator - %d Hz", controller.getActualFrequency())); - } - }, 0, 100); - - if (!e.hasDemoProgram()) { - controller.pause(); - } - controller.run(); - - tone.close(); + EmulatorWindow win = new EmulatorWindow(factory, options, resolution); + win.run(); } } diff --git a/emulator-awt/src/main/java/dev/krk/chipsekiz/emulator/EmulatorController.java b/emulator-awt/src/main/java/dev/krk/chipsekiz/emulator/EmulatorController.java index 8cfae0d..a2a8042 100644 --- a/emulator-awt/src/main/java/dev/krk/chipsekiz/emulator/EmulatorController.java +++ b/emulator-awt/src/main/java/dev/krk/chipsekiz/emulator/EmulatorController.java @@ -74,6 +74,9 @@ public EmulatorController(Emulator emulator, IInterpreter interpreter, IDebugger @Override public void stop() { emulator.stop(); + if (debugger != null) { + debugger.closeDebuggerWindow(); + } } @Override public void pause() { diff --git a/emulator-awt/src/main/java/dev/krk/chipsekiz/emulator/EmulatorWindow.java b/emulator-awt/src/main/java/dev/krk/chipsekiz/emulator/EmulatorWindow.java index ea7e51c..25b634c 100644 --- a/emulator-awt/src/main/java/dev/krk/chipsekiz/emulator/EmulatorWindow.java +++ b/emulator-awt/src/main/java/dev/krk/chipsekiz/emulator/EmulatorWindow.java @@ -3,6 +3,7 @@ import com.google.common.io.Files; import dev.krk.chipsekiz.superchip.interpreter.Resolution; +import javax.sound.sampled.LineUnavailableException; import javax.swing.ButtonGroup; import javax.swing.JFileChooser; import javax.swing.JFrame; @@ -15,19 +16,25 @@ import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.io.IOException; +import java.util.Timer; +import java.util.TimerTask; public class EmulatorWindow extends JFrame implements KeyListener { - private final IEmulatorController controller; - - EmulatorWindow(EmulatorCanvas canvas, IEmulatorController controller, Resolution resolution) { + private IEmulatable emulatable; + private EmulatorCanvas canvas; + private IEmulatorController controller; + private final Tone tone; + private String vmName = "CHIP-8"; + + EmulatorWindow(IEmulatableFactory factory, EmulatorOptions options, Resolution resolution) + throws LineUnavailableException { super("chipsekiz emulator"); - this.controller = controller; setDefaultCloseOperation(EXIT_ON_CLOSE); - setSize((resolution == Resolution.High ? 128 : 64) * 12, - (resolution == Resolution.High ? 64 : 32) * 12 + 88); - add(canvas); + tone = new Tone(1600); + + loadEmulator(factory, options, resolution); addKeyListener(this); @@ -73,6 +80,31 @@ public class EmulatorWindow extends JFrame implements KeyListener { menuBar.add(menu); + menu = new JMenu("VM"); + menu.setMnemonic('v'); + + ButtonGroup vmGroup = new ButtonGroup(); + + JRadioButtonMenuItem vm = new JRadioButtonMenuItem("CHIP-8", true); + vm.setMnemonic(KeyEvent.VK_0); + menu.add(vm); + vm.addActionListener(e -> { + loadEmulator(new Chip8EmulatableFactory(), options, Resolution.Low); + vmName = "CHIP-8"; + runAsync(); + }); + vmGroup.add(vm); + + vm = new JRadioButtonMenuItem("Super CHIP-8", false); + menu.add(vm); + vm.addActionListener(e -> { + loadEmulator(new SuperChip8EmulatableFactory(), options, Resolution.High); + vmName = "SuperCHIP-8"; + runAsync(); + }); + vmGroup.add(vm); + menuBar.add(menu); + // Sound menu menu = new JMenu("Sound"); menu.setMnemonic('u'); @@ -141,7 +173,7 @@ public class EmulatorWindow extends JFrame implements KeyListener { scale.addActionListener(scaleSetter); scaleGroup.add(scale); - scale = new JRadioButtonMenuItem("3x3", true); + scale = new JRadioButtonMenuItem("3x3", false); scale.setMnemonic(KeyEvent.VK_3); scale.setActionCommand("3"); menu.add(scale); @@ -237,6 +269,25 @@ public class EmulatorWindow extends JFrame implements KeyListener { setJMenuBar(menuBar); setVisible(true); + + Timer timer = new Timer(); + timer.scheduleAtFixedRate(new TimerTask() { + @Override public void run() { + setTitle(String.format("chipsekiz %s emulator - %d Hz", vmName, + controller.getActualFrequency())); + } + }, 0, 100); + } + + public void run() { + if (!emulatable.hasDemoProgram()) { + controller.pause(); + } + controller.run(); + } + + private void runAsync() { + new Thread(this::run).start(); } private void loadROM() throws IOException { @@ -250,6 +301,29 @@ private void loadROM() throws IOException { } } + private void loadEmulator(IEmulatableFactory factory, EmulatorOptions options, + Resolution resolution) { + + emulatable = factory.create(options, tone); + EmulatorCanvas canvas = emulatable.getCanvas(); + IEmulatorController controller = emulatable.getController(); + + if (this.controller != null) { + this.controller.stop(); + } + + setSize((resolution == Resolution.High ? 128 : 64) * 12, + (resolution == Resolution.High ? 64 : 32) * 12 + 88); + + if (this.canvas != null) { + remove(this.canvas); + } + add(canvas); + + this.canvas = canvas; + this.controller = controller; + } + @Override public void keyTyped(KeyEvent e) { // NOOP. } @@ -261,4 +335,10 @@ private void loadROM() throws IOException { @Override public void keyReleased(KeyEvent e) { controller.keyUp(); } + + @Override public void dispose() { + super.dispose(); + + tone.close(); + } }