diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..f009303
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,5 @@
+
+# Project exclude paths
+/.
+# Project exclude paths
+/.
\ No newline at end of file
diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml
new file mode 100644
index 0000000..3fd27b3
--- /dev/null
+++ b/.idea/jarRepositories.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/ksim65.iml b/.idea/ksim65.iml
new file mode 100644
index 0000000..78b2cc5
--- /dev/null
+++ b/.idea/ksim65.iml
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/.idea/markdown-navigator-enh.xml b/.idea/markdown-navigator-enh.xml
new file mode 100644
index 0000000..12fb99d
--- /dev/null
+++ b/.idea/markdown-navigator-enh.xml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/markdown-navigator.xml b/.idea/markdown-navigator.xml
new file mode 100644
index 0000000..d6df267
--- /dev/null
+++ b/.idea/markdown-navigator.xml
@@ -0,0 +1,55 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
index 6c9f64a..70064e8 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -1,5 +1,8 @@
+
+
+
\ No newline at end of file
diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml
new file mode 100644
index 0000000..e96534f
--- /dev/null
+++ b/.idea/uiDesigner.xml
@@ -0,0 +1,124 @@
+
+
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+
+
+ -
+
+
+ -
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/kotlin/razorvine/c64emu/c64Main.kt b/src/main/kotlin/razorvine/c64emu/c64Main.kt
index a298c6f..2094a3b 100644
--- a/src/main/kotlin/razorvine/c64emu/c64Main.kt
+++ b/src/main/kotlin/razorvine/c64emu/c64Main.kt
@@ -39,9 +39,9 @@ class C64Machine(title: String) : IVirtualMachine {
val kernalRom = Rom(0xe000, 0xffff).also { it.load(kernalData) }
val cpuIoPort = CpuIoPort(cpu)
+ private val monitor = Monitor(bus, cpu)
private val debugWindow = DebugWindow(this)
private val hostDisplay = MainC64Window(title, chargenData, ram, cpu, cia1)
- private val monitor = Monitor(bus, cpu)
private var paused = false
init {
diff --git a/src/main/kotlin/razorvine/examplemachines/DebugWindow.kt b/src/main/kotlin/razorvine/examplemachines/DebugWindow.kt
new file mode 100644
index 0000000..8c02574
--- /dev/null
+++ b/src/main/kotlin/razorvine/examplemachines/DebugWindow.kt
@@ -0,0 +1,233 @@
+package razorvine.examplemachines
+
+import razorvine.ksim65.*
+import java.awt.*
+import java.awt.event.ActionEvent
+import java.awt.event.ActionListener
+import java.awt.event.WindowEvent
+import java.io.File
+import javax.swing.*
+import javax.swing.text.DefaultCaret
+
+
+class DebugWindow(private val vm: IVirtualMachine) : JFrame("Debugger - ksim65 v${Version.version}"),
+ ActionListener {
+
+ private class UnaliasedTextBox(rows: Int, columns: Int) : JTextArea(rows, columns) {
+ override fun paintComponent(g: Graphics) {
+ g as Graphics2D
+ g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_OFF)
+ g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF)
+ super.paintComponent(g)
+ }
+ }
+
+ private val cyclesTf = JTextField("00000000000000")
+ private val speedKhzTf = JTextField("0000000")
+ private val regAtf = JTextField("000")
+ private val regXtf = JTextField("000")
+ private val regYtf = JTextField("000")
+ private val regPCtf = JTextField("00000")
+ private val regSPtf = JTextField("000")
+ private val regPtf = JTextArea("NV-BDIZC\n000000000")
+ private val disassemTf = JTextField("00 00 00 lda (fffff),x")
+ private val pauseBt = JButton("Pause").also { it.actionCommand = "pause" }
+ private val zeropageTf = UnaliasedTextBox(8, 102).also {
+ it.border = BorderFactory.createEtchedBorder()
+ it.isEnabled = false
+ it.disabledTextColor = Color.DARK_GRAY
+ it.font = Font(Font.MONOSPACED, Font.PLAIN, 12)
+ }
+ private val stackpageTf = UnaliasedTextBox(8, 102).also {
+ it.border = BorderFactory.createEtchedBorder()
+ it.isEnabled = false
+ it.disabledTextColor = Color.DARK_GRAY
+ it.font = Font(Font.MONOSPACED, Font.PLAIN, 12)
+ }
+
+ init {
+ contentPane.layout = GridBagLayout()
+ defaultCloseOperation = EXIT_ON_CLOSE
+ val cpuPanel = JPanel(GridBagLayout())
+ cpuPanel.border = BorderFactory.createTitledBorder("CPU: ${vm.cpu.name}")
+ val gc = GridBagConstraints()
+ gc.insets = Insets(2, 2, 2, 2)
+ gc.anchor = GridBagConstraints.EAST
+ gc.gridx = 0
+ gc.gridy = 0
+ val cyclesLb = JLabel("cycles")
+ val speedKhzLb = JLabel("speed (kHz)")
+ val regAlb = JLabel("A")
+ val regXlb = JLabel("X")
+ val regYlb = JLabel("Y")
+ val regSPlb = JLabel("SP")
+ val regPClb = JLabel("PC")
+ val regPlb = JLabel("Status")
+ val disassemLb = JLabel("Instruction")
+ listOf(cyclesLb, speedKhzLb, regAlb, regXlb, regYlb, regSPlb, regPClb, disassemLb, regPlb).forEach {
+ cpuPanel.add(it, gc)
+ gc.gridy++
+ }
+ gc.anchor = GridBagConstraints.WEST
+ gc.gridx = 1
+ gc.gridy = 0
+ listOf(cyclesTf, speedKhzTf, regAtf, regXtf, regYtf, regSPtf, regPCtf, disassemTf, regPtf).forEach {
+ it.font = Font(Font.MONOSPACED, Font.PLAIN, 14)
+ it.disabledTextColor = Color.DARK_GRAY
+ it.isEnabled = false
+ if (it is JTextField) {
+ it.columns = it.text.length
+ } else if (it is JTextArea) {
+ it.border = BorderFactory.createCompoundBorder(BorderFactory.createLineBorder(Color.LIGHT_GRAY),
+ BorderFactory.createEmptyBorder(2, 2, 2, 2))
+ }
+ cpuPanel.add(it, gc)
+ gc.gridy++
+ }
+
+ val buttonPanel = JPanel(FlowLayout())
+ buttonPanel.border = BorderFactory.createTitledBorder("Control")
+
+ val loadBt = JButton("Inject program").also { it.actionCommand = "inject" }
+ val resetBt = JButton("Reset").also { it.actionCommand = "reset" }
+ val stepBt = JButton("Step").also { it.actionCommand = "step" }
+ val irqBt = JButton("IRQ").also { it.actionCommand = "irq" }
+ val nmiBt = JButton("NMI").also { it.actionCommand = "nmi" }
+ val quitBt = JButton("Quit").also { it.actionCommand = "quit" }
+ listOf(loadBt, resetBt, irqBt, nmiBt, pauseBt, stepBt, quitBt).forEach {
+ it.addActionListener(this)
+ buttonPanel.add(it)
+ }
+
+ val zeropagePanel = JPanel()
+ zeropagePanel.layout = BoxLayout(zeropagePanel, BoxLayout.Y_AXIS)
+ zeropagePanel.border = BorderFactory.createTitledBorder("Zeropage and Stack")
+ val showZp = JCheckBox("show Zero page and Stack dumps", true)
+ showZp.addActionListener {
+ val visible = (it.source as JCheckBox).isSelected
+ zeropageTf.isVisible = visible
+ stackpageTf.isVisible = visible
+ }
+ zeropagePanel.add(showZp)
+ zeropagePanel.add(zeropageTf)
+ zeropagePanel.add(stackpageTf)
+
+ val monitorPanel = JPanel()
+ monitorPanel.layout = BoxLayout(monitorPanel, BoxLayout.Y_AXIS)
+ monitorPanel.border = BorderFactory.createTitledBorder("Built-in Monitor")
+ val output = JTextArea(6, 80)
+ output.font = Font(Font.MONOSPACED, Font.PLAIN, 14)
+ output.isEditable = false
+ val outputScroll = JScrollPane(output)
+ monitorPanel.add(outputScroll)
+ outputScroll.verticalScrollBarPolicy = JScrollPane.VERTICAL_SCROLLBAR_ALWAYS
+ (output.caret as DefaultCaret).updatePolicy = DefaultCaret.ALWAYS_UPDATE
+ val input = JTextField(50)
+ input.border = BorderFactory.createLineBorder(Color.LIGHT_GRAY)
+ input.font = Font(Font.MONOSPACED, Font.PLAIN, 14)
+ input.addActionListener {
+ output.append("\n")
+ val command = input.text.trim()
+ val result = vm.executeMonitorCommand(command)
+ if (result.echo) output.append("> $command\n")
+ output.append(result.output)
+ input.text = result.prompt
+ }
+ monitorPanel.add(input)
+ output.append(vm.executeMonitorCommand("h").output)
+
+ gc.gridx = 0
+ gc.gridy = 0
+ gc.fill = GridBagConstraints.BOTH
+ contentPane.add(cpuPanel, gc)
+ gc.gridy++
+ contentPane.add(zeropagePanel, gc)
+ gc.gridy++
+ contentPane.add(monitorPanel, gc)
+ gc.gridy++
+ contentPane.add(buttonPanel, gc)
+ pack()
+ }
+
+ override fun actionPerformed(e: ActionEvent) {
+ when (e.actionCommand) {
+ "inject" -> {
+ val chooser = JFileChooser()
+ chooser.dialogTitle = "Choose binary program or .prg to load"
+ chooser.currentDirectory = File(".")
+ chooser.isMultiSelectionEnabled = false
+ val result = chooser.showOpenDialog(this)
+ if (result == JFileChooser.APPROVE_OPTION) {
+ if (chooser.selectedFile.extension == "prg") {
+ vm.loadFileInRam(chooser.selectedFile, null)
+ } else {
+ val addressStr = JOptionPane.showInputDialog(this,
+ "The selected file isn't a .prg.\nSpecify memory load address (hexadecimal) manually.",
+ "Load address", JOptionPane.QUESTION_MESSAGE, null, null,
+ "$") as String
+
+ val loadAddress = Integer.parseInt(addressStr.removePrefix("$"), 16)
+ vm.loadFileInRam(chooser.selectedFile, loadAddress)
+ }
+ }
+
+ }
+ "reset" -> {
+ vm.bus.reset()
+ updateCpu(vm.cpu, vm.bus)
+ }
+ "step" -> {
+ vm.step()
+ updateCpu(vm.cpu, vm.bus)
+ }
+ "pause" -> {
+ vm.pause(true)
+ pauseBt.actionCommand = "continue"
+ pauseBt.text = "Continue"
+ }
+ "continue" -> {
+ vm.pause(false)
+ pauseBt.actionCommand = "pause"
+ pauseBt.text = "Pause"
+ }
+ "irq" -> vm.cpu.irq()
+ "nmi" -> vm.cpu.nmi()
+ "quit" -> {
+ dispatchEvent(WindowEvent(this, WindowEvent.WINDOW_CLOSING))
+ }
+ }
+ }
+
+ fun updateCpu(cpu: Cpu6502, bus: Bus) {
+ val state = cpu.snapshot()
+ cyclesTf.text = state.cycles.toString()
+ regAtf.text = hexB(state.A)
+ regXtf.text = hexB(state.X)
+ regYtf.text = hexB(state.Y)
+ regPtf.text = "NV-BDIZC\n"+state.P.asInt().toString(2).padStart(8, '0')
+ regPCtf.text = hexW(state.PC)
+ regSPtf.text = hexB(state.SP)
+ val memory = bus.memoryComponentFor(state.PC)
+ disassemTf.text = cpu.disassembleOneInstruction(memory.data, state.PC, memory.startAddress).first.substringAfter(' ').trim()
+
+ if (zeropageTf.isVisible || stackpageTf.isVisible) {
+ val pages = vm.getZeroAndStackPages()
+ if (pages.isNotEmpty()) {
+ val zpLines = (0..0xff step 32).map { location ->
+ " ${'$'}${location.toString(16).padStart(2, '0')} "+((0..31).joinToString(" ") { lineoffset ->
+ pages[location+lineoffset].toString(16).padStart(2, '0')
+ })
+ }
+ val stackLines = (0x100..0x1ff step 32).map { location ->
+ "${'$'}${location.toString(16).padStart(2, '0')} "+((0..31).joinToString(" ") { lineoffset ->
+ pages[location+lineoffset].toString(16).padStart(2, '0')
+ })
+ }
+ zeropageTf.text = zpLines.joinToString("\n")
+ stackpageTf.text = stackLines.joinToString("\n")
+ }
+ }
+
+ speedKhzTf.text = "%.1f".format(cpu.averageSpeedKhzSinceReset)
+ }
+}
diff --git a/src/main/kotlin/razorvine/examplemachines/GUI.kt b/src/main/kotlin/razorvine/examplemachines/GUI.kt
index f72a181..017a21d 100644
--- a/src/main/kotlin/razorvine/examplemachines/GUI.kt
+++ b/src/main/kotlin/razorvine/examplemachines/GUI.kt
@@ -4,8 +4,6 @@ import razorvine.ksim65.*
import java.awt.*
import java.awt.event.*
import java.awt.image.BufferedImage
-import java.io.File
-import java.lang.Integer.parseInt
import java.util.*
import javax.imageio.ImageIO
import javax.swing.*
@@ -139,221 +137,6 @@ private class BitmapScreenPanel : JPanel() {
}
}
-private class UnaliasedTextBox(rows: Int, columns: Int) : JTextArea(rows, columns) {
- override fun paintComponent(g: Graphics) {
- g as Graphics2D
- g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_OFF)
- g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF)
- super.paintComponent(g)
- }
-}
-
-class DebugWindow(private val vm: IVirtualMachine) : JFrame("Debugger - ksim65 v${Version.version}"), ActionListener {
- private val cyclesTf = JTextField("00000000000000")
- private val speedKhzTf = JTextField("0000000")
- private val regAtf = JTextField("000")
- private val regXtf = JTextField("000")
- private val regYtf = JTextField("000")
- private val regPCtf = JTextField("00000")
- private val regSPtf = JTextField("000")
- private val regPtf = JTextArea("NV-BDIZC\n000000000")
- private val disassemTf = JTextField("00 00 00 lda (fffff),x")
- private val pauseBt = JButton("Pause").also { it.actionCommand = "pause" }
- private val zeropageTf = UnaliasedTextBox(8, 102).also {
- it.border = BorderFactory.createEtchedBorder()
- it.isEnabled = false
- it.disabledTextColor = Color.DARK_GRAY
- it.font = Font(Font.MONOSPACED, Font.PLAIN, 12)
- }
- private val stackpageTf = UnaliasedTextBox(8, 102).also {
- it.border = BorderFactory.createEtchedBorder()
- it.isEnabled = false
- it.disabledTextColor = Color.DARK_GRAY
- it.font = Font(Font.MONOSPACED, Font.PLAIN, 12)
- }
-
- init {
- contentPane.layout = GridBagLayout()
- defaultCloseOperation = EXIT_ON_CLOSE
- val cpuPanel = JPanel(GridBagLayout())
- cpuPanel.border = BorderFactory.createTitledBorder("CPU: ${vm.cpu.name}")
- val gc = GridBagConstraints()
- gc.insets = Insets(2, 2, 2, 2)
- gc.anchor = GridBagConstraints.EAST
- gc.gridx = 0
- gc.gridy = 0
- val cyclesLb = JLabel("cycles")
- val speedKhzLb = JLabel("speed (kHz)")
- val regAlb = JLabel("A")
- val regXlb = JLabel("X")
- val regYlb = JLabel("Y")
- val regSPlb = JLabel("SP")
- val regPClb = JLabel("PC")
- val regPlb = JLabel("Status")
- val disassemLb = JLabel("Instruction")
- listOf(cyclesLb, speedKhzLb, regAlb, regXlb, regYlb, regSPlb, regPClb, disassemLb, regPlb).forEach {
- cpuPanel.add(it, gc)
- gc.gridy++
- }
- gc.anchor = GridBagConstraints.WEST
- gc.gridx = 1
- gc.gridy = 0
- listOf(cyclesTf, speedKhzTf, regAtf, regXtf, regYtf, regSPtf, regPCtf, disassemTf, regPtf).forEach {
- it.font = Font(Font.MONOSPACED, Font.PLAIN, 14)
- it.disabledTextColor = Color.DARK_GRAY
- it.isEnabled = false
- if (it is JTextField) {
- it.columns = it.text.length
- } else if (it is JTextArea) {
- it.border = BorderFactory.createCompoundBorder(BorderFactory.createLineBorder(Color.LIGHT_GRAY),
- BorderFactory.createEmptyBorder(2, 2, 2, 2))
- }
- cpuPanel.add(it, gc)
- gc.gridy++
- }
-
- val buttonPanel = JPanel(FlowLayout())
- buttonPanel.border = BorderFactory.createTitledBorder("Control")
-
- val loadBt = JButton("Inject program").also { it.actionCommand = "inject" }
- val resetBt = JButton("Reset").also { it.actionCommand = "reset" }
- val stepBt = JButton("Step").also { it.actionCommand = "step" }
- val irqBt = JButton("IRQ").also { it.actionCommand = "irq" }
- val nmiBt = JButton("NMI").also { it.actionCommand = "nmi" }
- val quitBt = JButton("Quit").also { it.actionCommand = "quit" }
- listOf(loadBt, resetBt, irqBt, nmiBt, pauseBt, stepBt, quitBt).forEach {
- it.addActionListener(this)
- buttonPanel.add(it)
- }
-
- val zeropagePanel = JPanel()
- zeropagePanel.layout = BoxLayout(zeropagePanel, BoxLayout.Y_AXIS)
- zeropagePanel.border = BorderFactory.createTitledBorder("Zeropage and Stack")
- val showZp = JCheckBox("show Zero page and Stack dumps", true)
- showZp.addActionListener {
- val visible = (it.source as JCheckBox).isSelected
- zeropageTf.isVisible = visible
- stackpageTf.isVisible = visible
- }
- zeropagePanel.add(showZp)
- zeropagePanel.add(zeropageTf)
- zeropagePanel.add(stackpageTf)
-
- val monitorPanel = JPanel()
- monitorPanel.layout = BoxLayout(monitorPanel, BoxLayout.Y_AXIS)
- monitorPanel.border = BorderFactory.createTitledBorder("Built-in Monitor")
- val output = JTextArea(6, 80)
- output.font = Font(Font.MONOSPACED, Font.PLAIN, 14)
- output.isEditable = false
- val outputScroll = JScrollPane(output)
- monitorPanel.add(outputScroll)
- outputScroll.verticalScrollBarPolicy = JScrollPane.VERTICAL_SCROLLBAR_ALWAYS
- val input = JTextField(50)
- input.border = BorderFactory.createLineBorder(Color.LIGHT_GRAY)
- input.font = Font(Font.MONOSPACED, Font.PLAIN, 14)
- input.addActionListener {
- output.append("\n")
- val command = input.text.trim()
- val result = vm.executeMonitorCommand(command)
- if (result.echo) output.append("> $command\n")
- output.append(result.output)
- input.text = result.prompt
- }
- monitorPanel.add(input)
-
- gc.gridx = 0
- gc.gridy = 0
- gc.fill = GridBagConstraints.BOTH
- contentPane.add(cpuPanel, gc)
- gc.gridy++
- contentPane.add(zeropagePanel, gc)
- gc.gridy++
- contentPane.add(monitorPanel, gc)
- gc.gridy++
- contentPane.add(buttonPanel, gc)
- pack()
- }
-
- override fun actionPerformed(e: ActionEvent) {
- when (e.actionCommand) {
- "inject" -> {
- val chooser = JFileChooser()
- chooser.dialogTitle = "Choose binary program or .prg to load"
- chooser.currentDirectory = File(".")
- chooser.isMultiSelectionEnabled = false
- val result = chooser.showOpenDialog(this)
- if (result == JFileChooser.APPROVE_OPTION) {
- if (chooser.selectedFile.extension == "prg") {
- vm.loadFileInRam(chooser.selectedFile, null)
- } else {
- val addressStr = JOptionPane.showInputDialog(this,
- "The selected file isn't a .prg.\nSpecify memory load address (hexadecimal) manually.",
- "Load address", JOptionPane.QUESTION_MESSAGE, null, null,
- "$") as String
-
- val loadAddress = parseInt(addressStr.removePrefix("$"), 16)
- vm.loadFileInRam(chooser.selectedFile, loadAddress)
- }
- }
-
- }
- "reset" -> {
- vm.bus.reset()
- updateCpu(vm.cpu, vm.bus)
- }
- "step" -> {
- vm.step()
- updateCpu(vm.cpu, vm.bus)
- }
- "pause" -> {
- vm.pause(true)
- pauseBt.actionCommand = "continue"
- pauseBt.text = "Continue"
- }
- "continue" -> {
- vm.pause(false)
- pauseBt.actionCommand = "pause"
- pauseBt.text = "Pause"
- }
- "irq" -> vm.cpu.irq()
- "nmi" -> vm.cpu.nmi()
- "quit" -> {
- dispatchEvent(WindowEvent(this, WindowEvent.WINDOW_CLOSING))
- }
- }
- }
-
- fun updateCpu(cpu: Cpu6502, bus: Bus) {
- val state = cpu.snapshot()
- cyclesTf.text = state.cycles.toString()
- regAtf.text = hexB(state.A)
- regXtf.text = hexB(state.X)
- regYtf.text = hexB(state.Y)
- regPtf.text = "NV-BDIZC\n"+state.P.asInt().toString(2).padStart(8, '0')
- regPCtf.text = hexW(state.PC)
- regSPtf.text = hexB(state.SP)
- val memory = bus.memoryComponentFor(state.PC)
- disassemTf.text = cpu.disassembleOneInstruction(memory.data, state.PC, memory.startAddress).first.substringAfter(' ').trim()
- val pages = vm.getZeroAndStackPages()
- if (pages.isNotEmpty()) {
- val zpLines = (0..0xff step 32).map { location ->
- " ${'$'}${location.toString(16).padStart(2, '0')} "+((0..31).joinToString(" ") { lineoffset ->
- pages[location+lineoffset].toString(16).padStart(2, '0')
- })
- }
- val stackLines = (0x100..0x1ff step 32).map { location ->
- "${'$'}${location.toString(16).padStart(2, '0')} "+((0..31).joinToString(" ") { lineoffset ->
- pages[location+lineoffset].toString(16).padStart(2, '0')
- })
- }
- zeropageTf.text = zpLines.joinToString("\n")
- stackpageTf.text = stackLines.joinToString("\n")
- }
-
- speedKhzTf.text = "%.1f".format(cpu.averageSpeedKhzSinceReset)
- }
-}
-
class MainWindow(title: String) : JFrame(title), KeyListener, MouseInputListener, IHostInterface {
private val canvas = BitmapScreenPanel()