1
0
mirror of https://github.com/irmen/ksim65.git synced 2024-06-01 21:41:31 +00:00

fix disassembly issues, added ehBasic machine

This commit is contained in:
Irmen de Jong 2019-09-19 01:22:11 +02:00
parent ba8946c29c
commit 8aad9795f7
12 changed files with 167 additions and 56 deletions

View File

@ -24,6 +24,12 @@ Properties of this simulator:
- passes several extensive unit test suites that verify instruction and cpu flags behavior - passes several extensive unit test suites that verify instruction and cpu flags behavior
- maximum simulated performance is a 6502 running at ~100 Mhz (on my machine) - maximum simulated performance is a 6502 running at ~100 Mhz (on my machine)
## Virtual machine examples
Two virtual example machines are included.
The default one starts with ``gradle run`` or run the ``ksim64vm`` command.
There's another one ``ehBasicMain`` that is configured to run the "enhanced 6502 basic" ROM.
## Documentation ## Documentation
Still to be written. For now, use the source ;-) Still to be written. For now, use the source ;-)

View File

@ -42,7 +42,7 @@ dependencies {
application { application {
applicationName = "ksim65vm" applicationName = "ksim65vm"
mainClassName = "razorvine.examplemachine.SystemMainKt" mainClassName = "razorvine.examplemachine.MachineMainKt"
} }
tasks.named<Test>("test") { tasks.named<Test>("test") {

View File

@ -1,12 +1,12 @@
package razorvine.examplemachine package razorvine.examplemachine
import razorvine.ksim65.Bus
import razorvine.ksim65.Cpu6502 import razorvine.ksim65.Cpu6502
import java.awt.* import java.awt.*
import java.awt.image.BufferedImage import java.awt.image.BufferedImage
import javax.imageio.ImageIO import javax.imageio.ImageIO
import javax.swing.event.MouseInputListener import javax.swing.event.MouseInputListener
import razorvine.ksim65.IHostInterface import razorvine.ksim65.IHostInterface
import razorvine.ksim65.components.MemoryComponent
import java.awt.event.* import java.awt.event.*
import java.util.* import java.util.*
import javax.swing.* import javax.swing.*
@ -22,7 +22,7 @@ object ScreenDefs {
const val SCREEN_HEIGHT_CHARS = 30 const val SCREEN_HEIGHT_CHARS = 30
const val SCREEN_WIDTH = SCREEN_WIDTH_CHARS * 8 const val SCREEN_WIDTH = SCREEN_WIDTH_CHARS * 8
const val SCREEN_HEIGHT = SCREEN_HEIGHT_CHARS * 16 const val SCREEN_HEIGHT = SCREEN_HEIGHT_CHARS * 16
const val DISPLAY_PIXEL_SCALING: Double = 1.5 const val DISPLAY_PIXEL_SCALING: Double = 1.25
val BG_COLOR = Color(0, 10, 20) val BG_COLOR = Color(0, 10, 20)
val FG_COLOR = Color(200, 255, 230) val FG_COLOR = Color(200, 255, 230)
val BORDER_COLOR = Color(20, 30, 40) val BORDER_COLOR = Color(20, 30, 40)
@ -159,7 +159,6 @@ class DebugWindow(val vm: VirtualMachine) : JFrame("debugger"), ActionListener {
private val pauseBt = JButton("Pause").also { it.actionCommand = "pause" } private val pauseBt = JButton("Pause").also { it.actionCommand = "pause" }
init { init {
isFocusable = true
defaultCloseOperation = EXIT_ON_CLOSE defaultCloseOperation = EXIT_ON_CLOSE
preferredSize = Dimension(350, 600) preferredSize = Dimension(350, 600)
val cpuPanel = JPanel(GridBagLayout()) val cpuPanel = JPanel(GridBagLayout())
@ -222,11 +221,11 @@ class DebugWindow(val vm: VirtualMachine) : JFrame("debugger"), ActionListener {
when(e.actionCommand) { when(e.actionCommand) {
"reset" -> { "reset" -> {
vm.bus.reset() vm.bus.reset()
updateCpu(vm.cpu, vm.ram) updateCpu(vm.cpu, vm.bus)
} }
"step" -> { "step" -> {
vm.stepInstruction() vm.stepInstruction()
updateCpu(vm.cpu, vm.ram) updateCpu(vm.cpu, vm.bus)
} }
"pause" -> { "pause" -> {
vm.paused = true vm.paused = true
@ -246,7 +245,7 @@ class DebugWindow(val vm: VirtualMachine) : JFrame("debugger"), ActionListener {
} }
} }
fun updateCpu(cpu: Cpu6502, mem: MemoryComponent) { fun updateCpu(cpu: Cpu6502, bus: Bus) {
cyclesTf.text = cpu.totalCycles.toString() cyclesTf.text = cpu.totalCycles.toString()
regAtf.text = cpu.hexB(cpu.regA) regAtf.text = cpu.hexB(cpu.regA)
regXtf.text = cpu.hexB(cpu.regX) regXtf.text = cpu.hexB(cpu.regX)
@ -254,7 +253,8 @@ class DebugWindow(val vm: VirtualMachine) : JFrame("debugger"), ActionListener {
regPtf.text = "NV-BDIZC\n" + cpu.regP.asByte().toString(2).padStart(8, '0') regPtf.text = "NV-BDIZC\n" + cpu.regP.asByte().toString(2).padStart(8, '0')
regPCtf.text = cpu.hexW(cpu.regPC) regPCtf.text = cpu.hexW(cpu.regPC)
regSPtf.text = cpu.hexB(cpu.regSP) regSPtf.text = cpu.hexB(cpu.regSP)
disassemTf.text = cpu.disassembleOneInstruction(mem.data, cpu.regPC, mem.startAddress).first.substringAfter(' ').trim() val memory = bus.memoryComponentFor(cpu.regPC)
disassemTf.text = cpu.disassembleOneInstruction(memory.data, cpu.regPC, memory.startAddress).first.substringAfter(' ').trim()
} }
} }
@ -327,6 +327,8 @@ class MainWindow(title: String) : JFrame(title), KeyListener, MouseInputListener
setLocationRelativeTo(null) setLocationRelativeTo(null)
setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, mutableSetOf()) setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, mutableSetOf())
isVisible = true isVisible = true
toFront()
requestFocus()
} }
fun start() { fun start() {

View File

@ -0,0 +1,63 @@
package razorvine.examplemachine
import kotlin.concurrent.scheduleAtFixedRate
import razorvine.ksim65.Bus
import razorvine.ksim65.Cpu6502
import razorvine.ksim65.Version
import razorvine.ksim65.components.*
import javax.swing.ImageIcon
/**
* A virtual computer constructed from the various virtual components,
* running the 6502 Enhanced Basic ROM.
*/
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()) }
private val hostDisplay = MainWindow(title)
private val display = Display(0xd000, 0xd00a, hostDisplay,
ScreenDefs.SCREEN_WIDTH_CHARS, ScreenDefs.SCREEN_HEIGHT_CHARS,
ScreenDefs.SCREEN_WIDTH, ScreenDefs.SCREEN_HEIGHT)
private val keyboard = Keyboard(0xd400, 0xd400, hostDisplay)
init {
hostDisplay.iconImage = ImageIcon(javaClass.getResource("/icon.png")).image
bus += display
bus += keyboard
bus += rom
bus += ram
bus += cpu
bus.reset()
hostDisplay.start()
hostDisplay.requestFocus()
}
var paused = false
fun stepInstruction() {
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) {
if(!paused) {
repeat(500) {
stepInstruction()
}
}
}
}
}
fun main(args: Array<String>) {
val machine = EhBasicMachine("KSim65 demo virtual machine - using ksim65 v${Version.version}")
machine.start()
}

View File

@ -18,8 +18,8 @@ class VirtualMachine(title: String) {
private val rtc = RealTimeClock(0xd100, 0xd108) private val rtc = RealTimeClock(0xd100, 0xd108)
private val timer = Timer(0xd200, 0xd203, cpu) private val timer = Timer(0xd200, 0xd203, cpu)
private val hostDisplay = MainWindow(title)
private val debugWindow = DebugWindow(this) private val debugWindow = DebugWindow(this)
private val hostDisplay = MainWindow(title)
private val display = Display(0xd000, 0xd00a, hostDisplay, private val display = Display(0xd000, 0xd00a, hostDisplay,
ScreenDefs.SCREEN_WIDTH_CHARS, ScreenDefs.SCREEN_HEIGHT_CHARS, ScreenDefs.SCREEN_WIDTH_CHARS, ScreenDefs.SCREEN_HEIGHT_CHARS,
ScreenDefs.SCREEN_WIDTH, ScreenDefs.SCREEN_HEIGHT) ScreenDefs.SCREEN_WIDTH, ScreenDefs.SCREEN_HEIGHT)
@ -47,6 +47,7 @@ class VirtualMachine(title: String) {
debugWindow.setLocation(hostDisplay.location.x+hostDisplay.width, hostDisplay.location.y) debugWindow.setLocation(hostDisplay.location.x+hostDisplay.width, hostDisplay.location.y)
debugWindow.isVisible = true debugWindow.isVisible = true
hostDisplay.requestFocus()
} }
var paused = false var paused = false
@ -62,10 +63,10 @@ class VirtualMachine(title: String) {
val startTime = System.currentTimeMillis() val startTime = System.currentTimeMillis()
timer.scheduleAtFixedRate(1, 1) { timer.scheduleAtFixedRate(1, 1) {
if(!paused) { if(!paused) {
repeat(20) { repeat(50) {
stepInstruction() stepInstruction()
} }
debugWindow.updateCpu(cpu, ram) debugWindow.updateCpu(cpu, bus)
val duration = System.currentTimeMillis() - startTime val duration = System.currentTimeMillis() - startTime
val speedKhz = cpu.totalCycles.toDouble() / duration val speedKhz = cpu.totalCycles.toDouble() / duration
debugWindow.speedKhzTf.text = "%.1f".format(speedKhz) debugWindow.speedKhzTf.text = "%.1f".format(speedKhz)

View File

@ -1,9 +1,6 @@
package razorvine.ksim65 package razorvine.ksim65
import razorvine.ksim65.components.Address import razorvine.ksim65.components.*
import razorvine.ksim65.components.BusComponent
import razorvine.ksim65.components.MemMappedComponent
import razorvine.ksim65.components.UByte
/** /**
* The system bus that connects all other components together. * The system bus that connects all other components together.
@ -73,4 +70,13 @@ class Bus {
it[address] = data it[address] = data
} }
} }
fun memoryComponentFor(address: Address): MemoryComponent {
memComponents.forEach {
if (it is MemoryComponent && address >= it.startAddress && address <= it.endAddress) {
return it
}
}
throw NoSuchElementException()
}
} }

View File

@ -151,116 +151,130 @@ open class Cpu6502(private val stopOnBrk: Boolean = false) : BusComponent() {
disassemble(memory.data, memory.startAddress, from, to) disassemble(memory.data, memory.startAddress, from, to)
fun disassemble(memory: Array<UByte>, baseAddress: Address, from: Address, to: Address): List<String> { fun disassemble(memory: Array<UByte>, baseAddress: Address, from: Address, to: Address): List<String> {
var location = from - baseAddress var location = from
val result = mutableListOf<String>() val result = mutableListOf<String>()
while (location <= (to - baseAddress)) { while (location <= to) {
val dis = disassembleOneInstruction(memory, location, baseAddress) val dis = disassembleOneInstruction(memory, location, baseAddress)
result.add(dis.first) result.add(dis.first)
location = dis.second location += dis.second
} }
return result return result
} }
fun disassembleOneInstruction(memory: Array<UByte>, address: Address, baseAddress: Address): Pair<String, Address> { fun disassembleOneInstruction(memory: Array<UByte>, address: Address, baseAddress: Address): Pair<String, Int> {
val spacing1 = " " val spacing1 = " "
val spacing2 = " " val spacing2 = " "
val spacing3 = " " val spacing3 = " "
var location = address val location = address-baseAddress
val byte = memory[location] val byte = memory[location]
var line = "\$${hexW(location+baseAddress)} ${hexB(byte)} " var line = "\$${hexW(location+baseAddress)} ${hexB(byte)} "
location++
val opcode = instructions[byte.toInt()] val opcode = instructions[byte.toInt()]
when (opcode.mode) { return when (opcode.mode) {
AddrMode.Acc -> { AddrMode.Acc -> {
line += "$spacing1 ${opcode.mnemonic} a" line += "$spacing1 ${opcode.mnemonic} a"
Pair(line, 1)
} }
AddrMode.Imp -> { AddrMode.Imp -> {
line += "$spacing1 ${opcode.mnemonic}" line += "$spacing1 ${opcode.mnemonic}"
Pair(line, 1)
} }
AddrMode.Imm -> { AddrMode.Imm -> {
val value = memory[location++] val value = memory[location+1]
line += "${hexB(value)} $spacing2 ${opcode.mnemonic} #\$${hexB(value)}" line += "${hexB(value)} $spacing2 ${opcode.mnemonic} #\$${hexB(value)}"
Pair(line, 2)
} }
AddrMode.Zp -> { AddrMode.Zp -> {
val zpAddr = memory[location++] val zpAddr = memory[location+1]
line += "${hexB(zpAddr)} $spacing2 ${opcode.mnemonic} \$${hexB(zpAddr)}" line += "${hexB(zpAddr)} $spacing2 ${opcode.mnemonic} \$${hexB(zpAddr)}"
Pair(line, 2)
} }
AddrMode.Zpr -> { AddrMode.Zpr -> {
// addressing mode used by the 65C02, put here for convenience // addressing mode used by the 65C02, put here for convenience
val zpAddr = memory[location++] val zpAddr = memory[location+1]
val rel = memory[location++] val rel = memory[location+2]
val target = val target =
if (rel <= 0x7f) if (rel <= 0x7f)
location + rel + baseAddress location + 3 + rel + baseAddress
else else
location - (256 - rel) + baseAddress location + 3 - (256 - rel) + baseAddress
line += "${hexB(zpAddr)} ${hexB(rel)} $spacing3 ${opcode.mnemonic} \$${hexB(zpAddr)}, \$${hexW(target, true)}" line += "${hexB(zpAddr)} ${hexB(rel)} $spacing3 ${opcode.mnemonic} \$${hexB(zpAddr)}, \$${hexW(target, true)}"
Pair(line, 3)
} }
AddrMode.Izp -> { AddrMode.Izp -> {
// addressing mode used by the 65C02, put here for convenience // addressing mode used by the 65C02, put here for convenience
val zpAddr = memory[location++] val zpAddr = memory[location+1]
line += "${hexB(zpAddr)} $spacing2 ${opcode.mnemonic} \$(${hexB(zpAddr)})" line += "${hexB(zpAddr)} $spacing2 ${opcode.mnemonic} \$(${hexB(zpAddr)})"
Pair(line, 2)
} }
AddrMode.IaX -> { AddrMode.IaX -> {
// addressing mode used by the 65C02, put here for convenience // addressing mode used by the 65C02, put here for convenience
val lo = memory[location++] val lo = memory[location+1]
val hi = memory[location++] val hi = memory[location+2]
val absAddr = lo.toInt() or (hi.toInt() shl 8) val absAddr = lo.toInt() or (hi.toInt() shl 8)
line += "${hexB(lo)} ${hexB(hi)} $spacing3 ${opcode.mnemonic} \$(${hexW(absAddr)},x)" line += "${hexB(lo)} ${hexB(hi)} $spacing3 ${opcode.mnemonic} \$(${hexW(absAddr)},x)"
Pair(line, 3)
} }
AddrMode.ZpX -> { AddrMode.ZpX -> {
val zpAddr = memory[location++] val zpAddr = memory[location+1]
line += "${hexB(zpAddr)} $spacing2 ${opcode.mnemonic} \$${hexB(zpAddr)},x" line += "${hexB(zpAddr)} $spacing2 ${opcode.mnemonic} \$${hexB(zpAddr)},x"
Pair(line, 2)
} }
AddrMode.ZpY -> { AddrMode.ZpY -> {
val zpAddr = memory[location++] val zpAddr = memory[location+1]
line += "${hexB(zpAddr)} $spacing2 ${opcode.mnemonic} \$${hexB(zpAddr)},y" line += "${hexB(zpAddr)} $spacing2 ${opcode.mnemonic} \$${hexB(zpAddr)},y"
Pair(line, 2)
} }
AddrMode.Rel -> { AddrMode.Rel -> {
val rel = memory[location++] val rel = memory[location+1]
val target = val target =
if (rel <= 0x7f) if (rel <= 0x7f)
location + rel + baseAddress location + 2 + rel + baseAddress
else else
location - (256 - rel) + baseAddress location + 2 - (256 - rel) + baseAddress
line += "${hexB(rel)} $spacing2 ${opcode.mnemonic} \$${hexW(target, true)}" line += "${hexB(rel)} $spacing2 ${opcode.mnemonic} \$${hexW(target, true)}"
Pair(line, 2)
} }
AddrMode.Abs -> { AddrMode.Abs -> {
val lo = memory[location++] val lo = memory[location+1]
val hi = memory[location++] val hi = memory[location+2]
val absAddr = lo.toInt() or (hi.toInt() shl 8) val absAddr = lo.toInt() or (hi.toInt() shl 8)
line += "${hexB(lo)} ${hexB(hi)} $spacing3 ${opcode.mnemonic} \$${hexW(absAddr)}" line += "${hexB(lo)} ${hexB(hi)} $spacing3 ${opcode.mnemonic} \$${hexW(absAddr)}"
Pair(line, 3)
} }
AddrMode.AbsX -> { AddrMode.AbsX -> {
val lo = memory[location++] val lo = memory[location+1]
val hi = memory[location++] val hi = memory[location+2]
val absAddr = lo.toInt() or (hi.toInt() shl 8) val absAddr = lo.toInt() or (hi.toInt() shl 8)
line += "${hexB(lo)} ${hexB(hi)} $spacing3 ${opcode.mnemonic} \$${hexW(absAddr)},x" line += "${hexB(lo)} ${hexB(hi)} $spacing3 ${opcode.mnemonic} \$${hexW(absAddr)},x"
Pair(line, 3)
} }
AddrMode.AbsY -> { AddrMode.AbsY -> {
val lo = memory[location++] val lo = memory[location+1]
val hi = memory[location++] val hi = memory[location+2]
val absAddr = lo.toInt() or (hi.toInt() shl 8) val absAddr = lo.toInt() or (hi.toInt() shl 8)
line += "${hexB(lo)} ${hexB(hi)} $spacing3 ${opcode.mnemonic} \$${hexW(absAddr)},y" line += "${hexB(lo)} ${hexB(hi)} $spacing3 ${opcode.mnemonic} \$${hexW(absAddr)},y"
Pair(line, 3)
} }
AddrMode.Ind -> { AddrMode.Ind -> {
val lo = memory[location++] val lo = memory[location+1]
val hi = memory[location++] val hi = memory[location+2]
val indirectAddr = lo.toInt() or (hi.toInt() shl 8) val indirectAddr = lo.toInt() or (hi.toInt() shl 8)
line += "${hexB(lo)} ${hexB(hi)} $spacing3 ${opcode.mnemonic} (\$${hexW(indirectAddr)})" line += "${hexB(lo)} ${hexB(hi)} $spacing3 ${opcode.mnemonic} (\$${hexW(indirectAddr)})"
Pair(line, 3)
} }
AddrMode.IzX -> { AddrMode.IzX -> {
val zpAddr = memory[location++] val zpAddr = memory[location+1]
line += "${hexB(zpAddr)} $spacing2 ${opcode.mnemonic} (\$${hexB(zpAddr)},x)" line += "${hexB(zpAddr)} $spacing2 ${opcode.mnemonic} (\$${hexB(zpAddr)},x)"
Pair(line, 2)
} }
AddrMode.IzY -> { AddrMode.IzY -> {
val zpAddr = memory[location++] val zpAddr = memory[location+1]
line += "${hexB(zpAddr)} $spacing2 ${opcode.mnemonic} (\$${hexB(zpAddr)}),y" line += "${hexB(zpAddr)} $spacing2 ${opcode.mnemonic} (\$${hexB(zpAddr)}),y"
Pair(line, 2)
} }
} }
return Pair(line, location)
} }
/** /**

View File

@ -53,11 +53,6 @@ class Ram(startAddress: Address, endAddress: Address) : MemoryComponent(startAdd
load(bytes, address) load(bytes, address)
} }
fun load(source: URL, address: Address) {
val bytes = source.readBytes()
load(bytes, address)
}
fun load(data: Array<UByte>, address: Address) = fun load(data: Array<UByte>, address: Address) =
data.forEachIndexed { index, byte -> data.forEachIndexed { index, byte ->
val baseAddress = address - startAddress val baseAddress = address - startAddress

View File

@ -1,11 +1,13 @@
package razorvine.ksim65.components package razorvine.ksim65.components
import java.io.File
/** /**
* A ROM chip (read-only memory). * A ROM chip (read-only memory).
*/ */
class Rom(startAddress: Address, endAddress: Address, initialData: Array<UByte>? = null) : MemoryComponent(startAddress, endAddress) { class Rom(startAddress: Address, endAddress: Address, initialData: Array<UByte>? = null) : MemoryComponent(startAddress, endAddress) {
override val data: Array<UByte> = override val data: Array<UByte> =
initialData?.copyOf() ?: Array<UByte>(endAddress - startAddress - 1) { 0 } initialData?.copyOf() ?: Array<UByte>(endAddress - startAddress + 1) { 0 }
init { init {
require(endAddress - startAddress + 1 == data.size) { "rom address range doesn't match size of data bytes" } require(endAddress - startAddress + 1 == data.size) { "rom address range doesn't match size of data bytes" }
@ -15,4 +17,26 @@ class Rom(startAddress: Address, endAddress: Address, initialData: Array<UByte>?
override operator fun set(address: Address, data: UByte) { /* read-only */ } override operator fun set(address: Address, data: UByte) { /* read-only */ }
override fun clock() {} override fun clock() {}
override fun reset() {} override fun reset() {}
/**
* load a binary program at the given address
*/
fun load(filename: String) {
val bytes = File(filename).readBytes()
load(bytes)
}
fun load(data: Array<UByte>) =
data.forEachIndexed { index, byte ->
this.data[index] = byte
}
fun load(data: ByteArray) =
data.forEachIndexed { index, byte ->
this.data[index] =
if (byte >= 0)
byte.toShort()
else
(256 + byte).toShort()
}
} }

Binary file not shown.

View File

@ -116,7 +116,7 @@ class Test6502CpuBasics {
val ram = Ram(0, 0xffff) val ram = Ram(0, 0xffff)
ram[Cpu6502.RESET_vector] = 0x00 ram[Cpu6502.RESET_vector] = 0x00
ram[Cpu6502.RESET_vector +1] = 0x10 ram[Cpu6502.RESET_vector +1] = 0x10
val bytes = javaClass.getResource("bcdtest6502.bin")!! // only works on 6502, not on the 65c02 val bytes = javaClass.getResource("bcdtest6502.bin").readBytes() // only works on 6502, not on the 65c02
ram.load(bytes, 0x1000) ram.load(bytes, 0x1000)
bus.add(ram) bus.add(ram)
bus.reset() bus.reset()

View File

@ -29,7 +29,7 @@ class TestDisassembler {
fun testDisassembleRockwell65C02() { fun testDisassembleRockwell65C02() {
val cpu = Cpu65C02() val cpu = Cpu65C02()
val memory = Ram(0, 0x0fff) val memory = Ram(0, 0x0fff)
val source = javaClass.classLoader.getResource("disassem_r65c02.bin")!! val source = javaClass.classLoader.getResource("disassem_r65c02.bin").readBytes()
memory.load(source, 0x0200) memory.load(source, 0x0200)
val resultLines = cpu.disassemble(memory, 0x0200, 0x0250) val resultLines = cpu.disassemble(memory, 0x0200, 0x0250)
val result = resultLines.joinToString("\n") val result = resultLines.joinToString("\n")
@ -74,7 +74,7 @@ ${'$'}0250 00 brk""", result)
fun testDisassembleWDC65C02() { fun testDisassembleWDC65C02() {
val cpu = Cpu65C02() val cpu = Cpu65C02()
val memory = Ram(0, 0x0fff) val memory = Ram(0, 0x0fff)
val source = javaClass.classLoader.getResource("disassem_wdc65c02.bin")!! val source = javaClass.classLoader.getResource("disassem_wdc65c02.bin").readBytes()
memory.load(source, 0x200) memory.load(source, 0x200)
val resultLines = cpu.disassemble(memory, 0x0200, 0x0215) val resultLines = cpu.disassemble(memory, 0x0200, 0x0215)
val result = resultLines.joinToString("\n") val result = resultLines.joinToString("\n")