mirror of
https://github.com/irmen/ksim65.git
synced 2024-06-01 21:41:31 +00:00
added zeropage and stack to debugger
This commit is contained in:
parent
dfec693ba0
commit
b8cea02ee0
|
@ -129,7 +129,7 @@ private class BitmapScreenPanel(val chargenData: ByteArray, val ram: MemoryCompo
|
|||
}
|
||||
}
|
||||
|
||||
class MainWindow(title: String, chargenData: ByteArray, val ram: MemoryComponent) : JFrame(title), KeyListener {
|
||||
class MainC64Window(title: String, chargenData: ByteArray, val ram: MemoryComponent) : JFrame(title), KeyListener {
|
||||
private val canvas = BitmapScreenPanel(chargenData, ram)
|
||||
private val keyboardBuffer = ArrayDeque<KeyEvent>()
|
||||
private var borderTop: JPanel
|
||||
|
@ -192,6 +192,7 @@ class MainWindow(title: String, chargenData: ByteArray, val ram: MemoryComponent
|
|||
addKeyListener(this)
|
||||
pack()
|
||||
setLocationRelativeTo(null)
|
||||
location = Point(location.x/2, location.y)
|
||||
setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, mutableSetOf())
|
||||
setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, mutableSetOf())
|
||||
requestFocusInWindow()
|
||||
|
|
|
@ -15,7 +15,6 @@ import javax.swing.ImageIcon
|
|||
* The virtual representation of the Commodore-64
|
||||
*/
|
||||
class C64Machine(title: String) : IVirtualMachine {
|
||||
|
||||
private val romsPath = Paths.get(expandUser("~/.vice/C64"))
|
||||
private val chargenData = romsPath.resolve("chargen").toFile().readBytes()
|
||||
private val basicData = romsPath.resolve("basic").toFile().readBytes()
|
||||
|
@ -29,7 +28,7 @@ class C64Machine(title: String) : IVirtualMachine {
|
|||
val kernalRom = Rom(0xe000, 0xffff).also { it.load(kernalData) }
|
||||
|
||||
private val debugWindow = DebugWindow(this)
|
||||
private val hostDisplay = MainWindow(title, chargenData, ram)
|
||||
private val hostDisplay = MainC64Window(title, chargenData, ram)
|
||||
private var paused = false
|
||||
|
||||
init {
|
||||
|
@ -58,6 +57,8 @@ class C64Machine(title: String) : IVirtualMachine {
|
|||
}
|
||||
|
||||
|
||||
override fun getZeroAndStackPages(): Array<UByte> = ram.getPages(0, 2)
|
||||
|
||||
override fun pause(paused: Boolean) {
|
||||
this.paused = paused
|
||||
}
|
||||
|
@ -70,9 +71,11 @@ class C64Machine(title: String) : IVirtualMachine {
|
|||
}
|
||||
|
||||
fun start() {
|
||||
val timer = java.util.Timer("clock", true)
|
||||
val startTime = System.currentTimeMillis()
|
||||
timer.scheduleAtFixedRate(1, 1) {
|
||||
javax.swing.Timer(10) {
|
||||
debugWindow.updateCpu(cpu, bus)
|
||||
}.start()
|
||||
|
||||
java.util.Timer("cpu-clock", true).scheduleAtFixedRate(1, 1) {
|
||||
if(!paused) {
|
||||
repeat(400) {
|
||||
step()
|
||||
|
@ -82,10 +85,6 @@ class C64Machine(title: String) : IVirtualMachine {
|
|||
cpu.irq()
|
||||
}
|
||||
}
|
||||
debugWindow.updateCpu(cpu, bus)
|
||||
val duration = System.currentTimeMillis() - startTime
|
||||
val speedKhz = cpu.totalCycles.toDouble() / duration
|
||||
debugWindow.speedKhzTf.text = "%.1f".format(speedKhz)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -149,7 +149,7 @@ private class BitmapScreenPanel : JPanel() {
|
|||
|
||||
class DebugWindow(private val vm: IVirtualMachine) : JFrame("debugger"), ActionListener {
|
||||
private val cyclesTf = JTextField("00000000000000")
|
||||
internal val speedKhzTf = JTextField("0000000")
|
||||
private val speedKhzTf = JTextField("0000000")
|
||||
private val regAtf = JTextField("000")
|
||||
private val regXtf = JTextField("000")
|
||||
private val regYtf = JTextField("000")
|
||||
|
@ -158,14 +158,27 @@ class DebugWindow(private val vm: IVirtualMachine) : JFrame("debugger"), ActionL
|
|||
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 = JTextArea(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 = JTextArea(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 startTime = System.currentTimeMillis()
|
||||
|
||||
init {
|
||||
contentPane.layout = GridBagLayout()
|
||||
defaultCloseOperation = EXIT_ON_CLOSE
|
||||
preferredSize = Dimension(350, 500)
|
||||
val cpuPanel = JPanel(GridBagLayout())
|
||||
cpuPanel.border = BorderFactory.createTitledBorder("CPU: ${vm.cpu.name}")
|
||||
val gc = GridBagConstraints()
|
||||
gc.insets = Insets(4, 4, 4, 4)
|
||||
gc.insets = Insets(2, 2, 2, 2)
|
||||
gc.anchor = GridBagConstraints.EAST
|
||||
gc.gridx = 0
|
||||
gc.gridy = 0
|
||||
|
@ -178,42 +191,54 @@ class DebugWindow(private val vm: IVirtualMachine) : JFrame("debugger"), ActionL
|
|||
val regPClb = JLabel("PC")
|
||||
val regPlb = JLabel("Status")
|
||||
val disassemLb = JLabel("Instruction")
|
||||
listOf(cyclesLb, speedKhzLb, regAlb, regXlb, regYlb, regSPlb, regPClb, regPlb, disassemLb).forEach {
|
||||
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, regPtf, disassemTf).forEach {
|
||||
listOf(cyclesTf, speedKhzTf, regAtf, regXtf, regYtf, regSPtf, regPCtf, disassemTf, regPtf).forEach {
|
||||
it.font = Font(Font.MONOSPACED, Font.PLAIN, 14)
|
||||
it.isEditable = false
|
||||
it.disabledTextColor = Color.DARK_GRAY
|
||||
it.isEnabled = false
|
||||
if(it is JTextField) {
|
||||
it.columns = it.text.length
|
||||
} else if(it is JTextArea) {
|
||||
it.background = this.background
|
||||
it.border = BorderFactory.createCompoundBorder(BorderFactory.createLineBorder(Color.LIGHT_GRAY),
|
||||
BorderFactory.createEmptyBorder(2,2,2,2))
|
||||
}
|
||||
cpuPanel.add(it, gc)
|
||||
gc.gridy++
|
||||
}
|
||||
add(cpuPanel, BorderLayout.NORTH)
|
||||
|
||||
val buttonPanel = JPanel(FlowLayout())
|
||||
buttonPanel.border = BorderFactory.createTitledBorder("Control")
|
||||
|
||||
val resetBt = JButton("Reset").also { it.actionCommand = "reset" }
|
||||
val cycleBt = JButton("Step").also { it.actionCommand = "step" }
|
||||
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(resetBt, cycleBt, irqBt, nmiBt, pauseBt, quitBt).forEach {
|
||||
listOf(resetBt, irqBt, nmiBt, pauseBt, stepBt, quitBt).forEach {
|
||||
it.addActionListener(this)
|
||||
buttonPanel.add(it)
|
||||
}
|
||||
|
||||
add(buttonPanel, BorderLayout.CENTER)
|
||||
val zeropagePanel = JPanel()
|
||||
zeropagePanel.layout = BoxLayout(zeropagePanel, BoxLayout.Y_AXIS)
|
||||
zeropagePanel.border = BorderFactory.createTitledBorder("Zeropage and Stack")
|
||||
zeropagePanel.add(zeropageTf)
|
||||
zeropagePanel.add(stackpageTf)
|
||||
|
||||
gc.gridx=0
|
||||
gc.gridy=0
|
||||
gc.fill=GridBagConstraints.BOTH
|
||||
contentPane.add(cpuPanel, gc)
|
||||
gc.gridy++
|
||||
contentPane.add(zeropagePanel, gc)
|
||||
gc.gridy++
|
||||
contentPane.add(buttonPanel, gc)
|
||||
|
||||
pack()
|
||||
}
|
||||
|
@ -231,7 +256,7 @@ class DebugWindow(private val vm: IVirtualMachine) : JFrame("debugger"), ActionL
|
|||
"pause" -> {
|
||||
vm.pause(true)
|
||||
pauseBt.actionCommand = "continue"
|
||||
pauseBt.text = "Cont."
|
||||
pauseBt.text = "Continue"
|
||||
}
|
||||
"continue" -> {
|
||||
vm.pause(false)
|
||||
|
@ -256,6 +281,27 @@ class DebugWindow(private val vm: IVirtualMachine) : JFrame("debugger"), ActionL
|
|||
regSPtf.text = cpu.hexB(cpu.regSP)
|
||||
val memory = bus.memoryComponentFor(cpu.regPC)
|
||||
disassemTf.text = cpu.disassembleOneInstruction(memory.data, cpu.regPC, 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")
|
||||
}
|
||||
|
||||
val spentTime = System.currentTimeMillis() - startTime
|
||||
val speedKhz = cpu.totalCycles.toDouble() / spentTime
|
||||
speedKhzTf.text = "%.1f".format(speedKhz)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -323,9 +369,10 @@ class MainWindow(title: String) : JFrame(title), KeyListener, MouseInputListener
|
|||
addKeyListener(this)
|
||||
addMouseMotionListener(this)
|
||||
addMouseListener(this)
|
||||
setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, mutableSetOf())
|
||||
pack()
|
||||
setLocationRelativeTo(null)
|
||||
setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, mutableSetOf())
|
||||
location = Point(location.x/2, location.y)
|
||||
requestFocusInWindow()
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@ package razorvine.examplemachines
|
|||
import kotlin.concurrent.scheduleAtFixedRate
|
||||
import razorvine.ksim65.Bus
|
||||
import razorvine.ksim65.Cpu6502
|
||||
import razorvine.ksim65.IVirtualMachine
|
||||
import razorvine.ksim65.Version
|
||||
import razorvine.ksim65.components.*
|
||||
import javax.swing.ImageIcon
|
||||
|
@ -12,9 +11,9 @@ import javax.swing.ImageIcon
|
|||
* A virtual computer constructed from the various virtual components,
|
||||
* running the 6502 Enhanced Basic ROM.
|
||||
*/
|
||||
class EhBasicMachine(title: String): IVirtualMachine {
|
||||
override val bus = Bus()
|
||||
override val cpu = Cpu6502(false)
|
||||
class EhBasicMachine(title: String) {
|
||||
val bus = Bus()
|
||||
val cpu = Cpu6502(false)
|
||||
val ram = Ram(0x0000, 0xbfff)
|
||||
val rom = Rom(0xc000, 0xffff).also { it.load(javaClass.getResourceAsStream("/ehbasic_C000.bin").readAllBytes()) }
|
||||
|
||||
|
@ -39,23 +38,15 @@ class EhBasicMachine(title: String): IVirtualMachine {
|
|||
hostDisplay.start()
|
||||
}
|
||||
|
||||
override fun pause(paused: Boolean) {
|
||||
this.paused = paused
|
||||
}
|
||||
|
||||
override fun step() {
|
||||
// step a full single instruction
|
||||
while (cpu.instrCycles > 0) bus.clock()
|
||||
bus.clock()
|
||||
while (cpu.instrCycles > 0) bus.clock()
|
||||
}
|
||||
|
||||
fun start() {
|
||||
val timer = java.util.Timer("clock", true)
|
||||
timer.scheduleAtFixedRate(1, 1) {
|
||||
val cpuTimer = java.util.Timer("cpu-clock", true)
|
||||
cpuTimer.scheduleAtFixedRate(1, 1) {
|
||||
if(!paused) {
|
||||
repeat(500) {
|
||||
step()
|
||||
// step a full single instruction
|
||||
while (cpu.instrCycles > 0) bus.clock()
|
||||
bus.clock()
|
||||
while (cpu.instrCycles > 0) bus.clock()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,6 +51,8 @@ class VirtualMachine(title: String) : IVirtualMachine {
|
|||
hostDisplay.start()
|
||||
}
|
||||
|
||||
override fun getZeroAndStackPages(): Array<UByte> = ram.getPages(0, 2)
|
||||
|
||||
override fun pause(paused: Boolean) {
|
||||
this.paused = paused
|
||||
}
|
||||
|
@ -63,17 +65,14 @@ class VirtualMachine(title: String) : IVirtualMachine {
|
|||
}
|
||||
|
||||
fun start() {
|
||||
val timer = java.util.Timer("clock", true)
|
||||
val startTime = System.currentTimeMillis()
|
||||
timer.scheduleAtFixedRate(1, 1) {
|
||||
javax.swing.Timer(10) {
|
||||
debugWindow.updateCpu(cpu, bus)
|
||||
}.start()
|
||||
java.util.Timer("cpu-clock", true).scheduleAtFixedRate(1, 1) {
|
||||
if(!paused) {
|
||||
repeat(50) {
|
||||
step()
|
||||
}
|
||||
debugWindow.updateCpu(cpu, bus)
|
||||
val duration = System.currentTimeMillis() - startTime
|
||||
val speedKhz = cpu.totalCycles.toDouble() / duration
|
||||
debugWindow.speedKhzTf.text = "%.1f".format(speedKhz)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
package razorvine.ksim65
|
||||
|
||||
import razorvine.ksim65.components.UByte
|
||||
|
||||
interface IVirtualMachine {
|
||||
fun step()
|
||||
fun pause(paused: Boolean)
|
||||
fun getZeroAndStackPages(): Array<UByte>
|
||||
|
||||
val cpu: Cpu6502
|
||||
val bus: Bus
|
||||
|
|
|
@ -65,4 +65,6 @@ abstract class MemoryComponent(startAddress: Address, endAddress: Address) :
|
|||
init {
|
||||
require(startAddress and 0xff == 0 && endAddress and 0xff == 0xff) {"address range must span complete page(s)"}
|
||||
}
|
||||
|
||||
fun getPages(page: Int, numPages: Int): Array<UByte> = data.copyOfRange(page*256, (page+numPages)*256)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user