diff --git a/sim65/sim65.iml b/sim65/sim65.iml index f439d557d..943f0f026 100644 --- a/sim65/sim65.iml +++ b/sim65/sim65.iml @@ -16,6 +16,7 @@ + diff --git a/sim65/src/Sim65Main.kt b/sim65/src/Sim65Main.kt index b63f6c7f9..8a9b3d349 100644 --- a/sim65/src/Sim65Main.kt +++ b/sim65/src/Sim65Main.kt @@ -1,89 +1,44 @@ package sim65 -import kotlinx.cli.* import sim65.components.* -import sim65.components.Cpu6502.Companion.hexB -import kotlin.system.exitProcess +import sim65.components.Cpu6502.Companion.RESET_vector fun main(args: Array) { - printSoftwareHeader2() - startSimulator2(args) + printSoftwareHeader() + startSimulator(args) } -internal fun printSoftwareHeader2() { +internal fun printSoftwareHeader() { val buildVersion = object {}.javaClass.getResource("/version.txt").readText().trim() println("\nSim65 6502 cpu simulator v$buildVersion by Irmen de Jong (irmen@razorvine.net)") println("This software is licensed under the GNU GPL 3.0, see https://www.gnu.org/licenses/gpl.html\n") } -private fun startSimulator2(args: Array) { - val bootRom = listOf( - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0, - 0x00,0x90, // NMI vector - 0x00,0x10, // RESET vector - 0x00,0xa0 // IRQ vector - ).toTypedArray() +private fun startSimulator(args: Array) { + // create a computer system. + // note that the order in which components are added to the bus, is important: + // it determines the priority of reads and writes. val cpu = Cpu6502(true) - cpu.tracing = true + val ram = Ram(0, 0xffff) + ram[RESET_vector] = 0x00 + ram[RESET_vector + 1] = 0x10 + + val parallel = ParallelPort(0xd000, 0xd001) + val timer = Timer(0xd100, 0xd103) - // create the system bus and add device to it. - // note that the order is relevant w.r.t. where reads and writes are going. val bus = Bus() bus.add(cpu) - bus.add(Rom(0xff00, 0xffff, bootRom)) - bus.add(Parallel(0xd000, 0xd001)) - bus.add(Timer(0xd100, 0xd103)) - val ram = Ram(0, 0xffff) + bus.add(parallel) + bus.add(timer) bus.add(ram) - bus.reset() - ram.load("sim65/test/testfiles/ram.bin", 0x8000) - ram.load("sim65/test/testfiles/bcdtest.bin", 0x1000) - //ram.dump(0x8000, 0x802f) - //cpu.disassemble(ram, 0x8000, 0x802f) - - try { - while (true) { - bus.clock() - } - } catch(e: InstructionError) { + cpu.tracing = true + while (true) { + bus.clock() } - - if(ram[0x0400] ==0.toShort()) - println("BCD TEST: OK!") - else { - val code = ram[0x0400] - val v1 = ram[0x0401] - val v2 = ram[0x0402] - val predictedA = ram[0x00fc] - val actualA = ram[0x00fd] - val predictedF = ram[0x00fe] - val actualF = ram[0x00ff] - println("BCD TEST: FAIL!! code=${hexB(code)} value1=${hexB(v1)} value2=${hexB(v2)}") - println(" predictedA=${hexB(predictedA)}") - println(" actualA=${hexB(actualA)}") - println(" predictedF=${predictedF.toString(2).padStart(8,'0')}") - println(" actualF=${actualF.toString(2).padStart(8,'0')}") - } - } diff --git a/sim65/src/components/Component.kt b/sim65/src/components/Component.kt index 921e946e2..7aa57b796 100644 --- a/sim65/src/components/Component.kt +++ b/sim65/src/components/Component.kt @@ -12,14 +12,13 @@ abstract class BusComponent { abstract class MemMappedComponent(val startAddress: Address, val endAddress: Address): BusComponent() { abstract operator fun get(address: Address): UByte abstract operator fun set(address: Address, data: UByte) - abstract fun cloneMem(): Array init { require(endAddress>=startAddress) require(startAddress>=0 && endAddress <= 0xffff) { "can only have 16-bit address space" } } - fun dump(from: Address, to: Address) { + fun hexDump(from: Address, to: Address) { (from .. to).chunked(16).forEach { print("\$${it.first().toString(16).padStart(4, '0')} ") val bytes = it.map { address -> get(address) } @@ -31,5 +30,8 @@ abstract class MemMappedComponent(val startAddress: Address, val endAddress: Add println() } } - +} + +abstract class MemoryComponent(startAddress: Address, endAddress: Address): MemMappedComponent(startAddress, endAddress) { + abstract fun cloneContents(): Array } diff --git a/sim65/src/components/Cpu6502.kt b/sim65/src/components/Cpu6502.kt index 3517b78d8..eb293810d 100644 --- a/sim65/src/components/Cpu6502.kt +++ b/sim65/src/components/Cpu6502.kt @@ -4,8 +4,8 @@ class InstructionError(msg: String) : RuntimeException(msg) interface ICpu { fun disassemble(memory: Array, baseAddress: Address, from: Address, to: Address): List - fun disassemble(component: MemMappedComponent, from: Address, to: Address) = - disassemble(component.cloneMem(), component.startAddress, from, to) + fun disassemble(component: MemoryComponent, from: Address, to: Address) = + disassemble(component.cloneContents(), component.startAddress, from, to) fun clock() fun reset() @@ -16,6 +16,7 @@ interface ICpu { val totalCycles: Long } +// TODO: implement the illegal opcodes, see http://www.ffd2.com/fridge/docs/6502-NMOS.extra.opcodes // TODO: add the optional additional cycles to certain instructions and addressing modes // TODO: add IRQ and NMI signaling. // TODO: make a 65c02 variant as well (and re-enable the unit tests for that). @@ -68,7 +69,7 @@ class Cpu6502(private val stopOnBrk: Boolean) : BusComponent(), ICpu { IzY } - class Instruction(val opcode: UByte, val mnemonic: String, val mode: AddrMode, val cycles: Int, val official: Boolean, val execute: () -> Unit) { + class Instruction(val opcode: UByte, val mnemonic: String, val mode: AddrMode, val cycles: Int, val execute: () -> Unit) { override fun toString(): String { return "[${hexB(opcode)}: $mnemonic $mode]" } @@ -331,12 +332,12 @@ class Cpu6502(private val stopOnBrk: Boolean) : BusComponent(), ICpu { } private fun amZpx() { - // note: zeropage index will not leave Zp when page boundray is crossed + // note: zeropage index will not leave Zp when page boundary is crossed fetchedAddress = (readPc() + X) and 0xff } private fun amZpy() { - // note: zeropage index will not leave Zp when page boundray is crossed + // note: zeropage index will not leave Zp when page boundary is crossed fetchedAddress = (readPc() + Y) and 0xff } @@ -420,17 +421,17 @@ class Cpu6502(private val stopOnBrk: Boolean) : BusComponent(), ICpu { pushStack(status.asByte().toInt()) } - internal fun pushStack(data: Int) { + private fun pushStack(data: Int) { write(SP or 0x0100, data) SP = (SP - 1) and 0xff } - internal fun popStack(): Int { + private fun popStack(): Int { SP = (SP + 1) and 0xff return read(SP or 0x0100) } - internal fun popStackAddr(): Address { + private fun popStackAddr(): Address { val lo = popStack() val hi = popStack() return lo or (hi shl 8) @@ -442,262 +443,262 @@ class Cpu6502(private val stopOnBrk: Boolean) : BusComponent(), ICpu { // opcodes table from http://www.oxyron.de/html/opcodes02.html private val opcodes = listOf( - Instruction(0x00, "brk", AddrMode.Imp, 7, true, ::iBrk), - Instruction(0x01, "ora", AddrMode.IzX, 6, true, ::iOra), - Instruction(0x02, "???", AddrMode.Imp, 0, false, ::iInvalid), - Instruction(0x03, "slo", AddrMode.IzX, 8, false, ::iSlo), - Instruction(0x04, "nop", AddrMode.Zp, 3, false, ::iNop), - Instruction(0x05, "ora", AddrMode.Zp, 3, true, ::iOra), - Instruction(0x06, "asl", AddrMode.Zp, 5, true, ::iAsl), - Instruction(0x07, "slo", AddrMode.Zp, 5, false, ::iSlo), - Instruction(0x08, "php", AddrMode.Imp, 3, true, ::iPhp), - Instruction(0x09, "ora", AddrMode.Imm, 2, true, ::iOra), - Instruction(0x0a, "asl", AddrMode.Acc, 2, true, ::iAsl), - Instruction(0x0b, "anc", AddrMode.Imm, 2, false, ::iAnc), - Instruction(0x0c, "nop", AddrMode.Abs, 4, false, ::iNop), - Instruction(0x0d, "ora", AddrMode.Abs, 4, true, ::iOra), - Instruction(0x0e, "asl", AddrMode.Abs, 6, true, ::iAsl), - Instruction(0x0f, "slo", AddrMode.Abs, 6, false, ::iSlo), - Instruction(0x10, "bpl", AddrMode.Rel, 2, true, ::iBpl), - Instruction(0x11, "ora", AddrMode.IzY, 5, true, ::iOra), - Instruction(0x12, "???", AddrMode.Imp, 0, false, ::iInvalid), - Instruction(0x13, "slo", AddrMode.IzY, 6, false, ::iSlo), - Instruction(0x14, "nop", AddrMode.ZpX, 4, false, ::iNop), - Instruction(0x15, "ora", AddrMode.ZpX, 4, true, ::iOra), - Instruction(0x16, "asl", AddrMode.ZpX, 6, true, ::iAsl), - Instruction(0x17, "slo", AddrMode.ZpX, 6, false, ::iSlo), - Instruction(0x18, "clc", AddrMode.Imp, 2, true, ::iClc), - Instruction(0x19, "ora", AddrMode.AbsY, 4, true, ::iOra), - Instruction(0x1a, "nop", AddrMode.Imp, 2, false, ::iNop), - Instruction(0x1b, "slo", AddrMode.AbsY, 7, false, ::iSlo), - Instruction(0x1c, "nop", AddrMode.AbsX, 4, false, ::iNop), - Instruction(0x1d, "ora", AddrMode.AbsX, 4, true, ::iOra), - Instruction(0x1e, "asl", AddrMode.AbsX, 7, true, ::iAsl), - Instruction(0x1f, "slo", AddrMode.AbsX, 7, false, ::iSlo), - Instruction(0x20, "jsr", AddrMode.Abs, 6, true, ::iJsr), - Instruction(0x21, "and", AddrMode.IzX, 6, true, ::iAnd), - Instruction(0x22, "???", AddrMode.Imp, 0, false, ::iInvalid), - Instruction(0x23, "rla", AddrMode.IzX, 8, false, ::iRla), - Instruction(0x24, "bit", AddrMode.Zp, 3, true, ::iBit), - Instruction(0x25, "and", AddrMode.Zp, 3, true, ::iAnd), - Instruction(0x26, "rol", AddrMode.Zp, 5, true, ::iRol), - Instruction(0x27, "rla", AddrMode.Zp, 5, false, ::iRla), - Instruction(0x28, "plp", AddrMode.Imp, 4, true, ::iPlp), - Instruction(0x29, "and", AddrMode.Imm, 2, true, ::iAnd), - Instruction(0x2a, "rol", AddrMode.Acc, 2, true, ::iRol), - Instruction(0x2b, "anc", AddrMode.Imm, 2, false, ::iAnc), - Instruction(0x2c, "bit", AddrMode.Abs, 4, true, ::iBit), - Instruction(0x2d, "and", AddrMode.Abs, 4, true, ::iAnd), - Instruction(0x2e, "rol", AddrMode.Abs, 6, true, ::iRol), - Instruction(0x2f, "rla", AddrMode.Abs, 6, false, ::iRla), - Instruction(0x30, "bmi", AddrMode.Rel, 2, true, ::iBmi), - Instruction(0x31, "and", AddrMode.IzY, 5, true, ::iAnd), - Instruction(0x32, "???", AddrMode.Imp, 0, false, ::iInvalid), - Instruction(0x33, "rla", AddrMode.IzY, 8, false, ::iRla), - Instruction(0x34, "nop", AddrMode.ZpX, 4, false, ::iNop), - Instruction(0x35, "and", AddrMode.ZpX, 4, true, ::iAnd), - Instruction(0x36, "rol", AddrMode.ZpX, 6, true, ::iRol), - Instruction(0x37, "rla", AddrMode.ZpX, 6, false, ::iRla), - Instruction(0x38, "sec", AddrMode.Imp, 2, true, ::iSec), - Instruction(0x39, "and", AddrMode.AbsY, 4, true, ::iAnd), - Instruction(0x3a, "nop", AddrMode.Imp, 2, false, ::iNop), - Instruction(0x3b, "rla", AddrMode.AbsY, 7, false, ::iRla), - Instruction(0x3c, "nop", AddrMode.AbsX, 4, false, ::iNop), - Instruction(0x3d, "and", AddrMode.AbsX, 4, true, ::iAnd), - Instruction(0x3e, "rol", AddrMode.AbsX, 7, true, ::iRol), - Instruction(0x3f, "rla", AddrMode.AbsX, 7, false, ::iRla), - Instruction(0x40, "rti", AddrMode.Imp, 6, true, ::iRti), - Instruction(0x41, "eor", AddrMode.IzX, 6, true, ::iEor), - Instruction(0x42, "???", AddrMode.Imp, 0, false, ::iInvalid), - Instruction(0x43, "sre", AddrMode.IzX, 8, false, ::iSre), - Instruction(0x44, "nop", AddrMode.Zp, 3, false, ::iNop), - Instruction(0x45, "eor", AddrMode.Zp, 3, true, ::iEor), - Instruction(0x46, "lsr", AddrMode.Zp, 5, true, ::iLsr), - Instruction(0x47, "sre", AddrMode.Zp, 5, false, ::iSre), - Instruction(0x48, "pha", AddrMode.Imp, 3, true, ::iPha), - Instruction(0x49, "eor", AddrMode.Imm, 2, true, ::iEor), - Instruction(0x4a, "lsr", AddrMode.Acc, 2, true, ::iLsr), - Instruction(0x4b, "alr", AddrMode.Imm, 2, false, ::iAlr), - Instruction(0x4c, "jmp", AddrMode.Abs, 3, true, ::iJmp), - Instruction(0x4d, "eor", AddrMode.Abs, 4, true, ::iEor), - Instruction(0x4e, "lsr", AddrMode.Abs, 6, true, ::iLsr), - Instruction(0x4f, "sre", AddrMode.Abs, 6, false, ::iSre), - Instruction(0x50, "bvc", AddrMode.Rel, 2, true, ::iBvc), - Instruction(0x51, "eor", AddrMode.IzY, 5, true, ::iEor), - Instruction(0x52, "???", AddrMode.Imp, 0, false, ::iInvalid), - Instruction(0x53, "sre", AddrMode.IzY, 8, false, ::iSre), - Instruction(0x54, "nop", AddrMode.ZpX, 4, false, ::iNop), - Instruction(0x55, "eor", AddrMode.ZpX, 4, true, ::iEor), - Instruction(0x56, "lsr", AddrMode.ZpX, 6, true, ::iLsr), - Instruction(0x57, "sre", AddrMode.ZpX, 6, false, ::iSre), - Instruction(0x58, "cli", AddrMode.Imp, 2, true, ::iCli), - Instruction(0x59, "eor", AddrMode.AbsY, 4, true, ::iEor), - Instruction(0x5a, "nop", AddrMode.Imp, 2, false, ::iNop), - Instruction(0x5b, "sre", AddrMode.AbsY, 7, false, ::iSre), - Instruction(0x5c, "nop", AddrMode.AbsX, 4, false, ::iNop), - Instruction(0x5d, "eor", AddrMode.AbsX, 4, true, ::iEor), - Instruction(0x5e, "lsr", AddrMode.AbsX, 7, true, ::iLsr), - Instruction(0x5f, "sre", AddrMode.AbsX, 7, false, ::iSre), - Instruction(0x60, "rts", AddrMode.Imp, 6, true, ::iRts), - Instruction(0x61, "adc", AddrMode.IzX, 6, true, ::iAdc), - Instruction(0x62, "???", AddrMode.Imp, 0, false, ::iInvalid), - Instruction(0x63, "rra", AddrMode.IzX, 8, false, ::iRra), - Instruction(0x64, "nop", AddrMode.Zp, 3, false, ::iNop), - Instruction(0x65, "adc", AddrMode.Zp, 3, true, ::iAdc), - Instruction(0x66, "ror", AddrMode.Zp, 5, true, ::iRor), - Instruction(0x67, "rra", AddrMode.Zp, 5, false, ::iRra), - Instruction(0x68, "pla", AddrMode.Imp, 4, true, ::iPla), - Instruction(0x69, "adc", AddrMode.Imm, 2, true, ::iAdc), - Instruction(0x6a, "ror", AddrMode.Acc, 2, true, ::iRor), - Instruction(0x6b, "arr", AddrMode.Imm, 2, false, ::iArr), - Instruction(0x6c, "jmp", AddrMode.Ind, 5, true, ::iJmp), - Instruction(0x6d, "adc", AddrMode.Abs, 4, true, ::iAdc), - Instruction(0x6e, "ror", AddrMode.Abs, 6, true, ::iRor), - Instruction(0x6f, "rra", AddrMode.Abs, 6, false, ::iRra), - Instruction(0x70, "bvs", AddrMode.Rel, 2, true, ::iBvs), - Instruction(0x71, "adc", AddrMode.IzY, 5, true, ::iAdc), - Instruction(0x72, "???", AddrMode.Imp, 0, false, ::iInvalid), - Instruction(0x73, "rra", AddrMode.IzY, 8, false, ::iRra), - Instruction(0x74, "nop", AddrMode.ZpX, 4, false, ::iNop), - Instruction(0x75, "adc", AddrMode.ZpX, 4, true, ::iAdc), - Instruction(0x76, "ror", AddrMode.ZpX, 6, true, ::iRor), - Instruction(0x77, "rra", AddrMode.ZpX, 6, false, ::iRra), - Instruction(0x78, "sei", AddrMode.Imp, 2, true, ::iSei), - Instruction(0x79, "adc", AddrMode.AbsY, 4, true, ::iAdc), - Instruction(0x7a, "nop", AddrMode.Imp, 2, false, ::iNop), - Instruction(0x7b, "rra", AddrMode.AbsY, 7, false, ::iRra), - Instruction(0x7c, "nop", AddrMode.AbsX, 4, false, ::iNop), - Instruction(0x7d, "adc", AddrMode.AbsX, 4, true, ::iAdc), - Instruction(0x7e, "ror", AddrMode.AbsX, 7, true, ::iRor), - Instruction(0x7f, "rra", AddrMode.AbsX, 7, false, ::iRra), - Instruction(0x80, "nop", AddrMode.Imm, 2, false, ::iNop), - Instruction(0x81, "sta", AddrMode.IzX, 6, true, ::iSta), - Instruction(0x82, "nop", AddrMode.Imm, 2, false, ::iNop), - Instruction(0x83, "sax", AddrMode.IzX, 6, false, ::iSax), - Instruction(0x84, "sty", AddrMode.Zp, 3, true, ::iSty), - Instruction(0x85, "sta", AddrMode.Zp, 3, true, ::iSta), - Instruction(0x86, "stx", AddrMode.Zp, 3, true, ::iStx), - Instruction(0x87, "sax", AddrMode.Zp, 3, false, ::iSax), - Instruction(0x88, "dey", AddrMode.Imp, 2, true, ::iDey), - Instruction(0x89, "nop", AddrMode.Imm, 2, false, ::iNop), - Instruction(0x8a, "txa", AddrMode.Imp, 2, true, ::iTxa), - Instruction(0x8b, "xaa", AddrMode.Imm, 2, false, ::iXaa), - Instruction(0x8c, "sty", AddrMode.Abs, 4, true, ::iSty), - Instruction(0x8d, "sta", AddrMode.Abs, 4, true, ::iSta), - Instruction(0x8e, "stx", AddrMode.Abs, 4, true, ::iStx), - Instruction(0x8f, "sax", AddrMode.Abs, 4, true, ::iSax), - Instruction(0x90, "bcc", AddrMode.Rel, 2, true, ::iBcc), - Instruction(0x91, "sta", AddrMode.IzY, 6, true, ::iSta), - Instruction(0x92, "???", AddrMode.Imp, 0, false, ::iInvalid), - Instruction(0x93, "ahx", AddrMode.IzY, 6, false, ::iAhx), - Instruction(0x94, "sty", AddrMode.ZpX, 4, true, ::iSty), - Instruction(0x95, "sta", AddrMode.ZpX, 4, true, ::iSta), - Instruction(0x96, "stx", AddrMode.ZpY, 4, true, ::iStx), - Instruction(0x97, "sax", AddrMode.ZpY, 4, false, ::iSax), - Instruction(0x98, "tya", AddrMode.Imp, 2, true, ::iTya), - Instruction(0x99, "sta", AddrMode.AbsY, 5, true, ::iSta), - Instruction(0x9a, "txs", AddrMode.Imp, 2, true, ::iTxs), - Instruction(0x9b, "tas", AddrMode.AbsY, 5, false, ::iTas), - Instruction(0x9c, "shy", AddrMode.AbsX, 5, false, ::iShy), - Instruction(0x9d, "sta", AddrMode.AbsX, 5, true, ::iSta), - Instruction(0x9e, "shx", AddrMode.AbsY, 5, false, ::iShx), - Instruction(0x9f, "ahx", AddrMode.AbsY, 5, false, ::iAhx), - Instruction(0xa0, "ldy", AddrMode.Imm, 2, true, ::iLdy), - Instruction(0xa1, "lda", AddrMode.IzX, 6, true, ::iLda), - Instruction(0xa2, "ldx", AddrMode.Imm, 2, true, ::iLdx), - Instruction(0xa3, "lax", AddrMode.IzX, 6, false, ::iLax), - Instruction(0xa4, "ldy", AddrMode.Zp, 3, true, ::iLdy), - Instruction(0xa5, "lda", AddrMode.Zp, 3, true, ::iLda), - Instruction(0xa6, "ldx", AddrMode.Zp, 3, true, ::iLdx), - Instruction(0xa7, "lax", AddrMode.Zp, 3, false, ::iLax), - Instruction(0xa8, "tay", AddrMode.Imp, 2, true, ::iTay), - Instruction(0xa9, "lda", AddrMode.Imm, 2, true, ::iLda), - Instruction(0xaa, "tax", AddrMode.Imp, 2, true, ::iTax), - Instruction(0xab, "lax", AddrMode.Imm, 2, false, ::iLax), - Instruction(0xac, "ldy", AddrMode.Abs, 4, true, ::iLdy), - Instruction(0xad, "lda", AddrMode.Abs, 4, true, ::iLda), - Instruction(0xae, "ldx", AddrMode.Abs, 4, true, ::iLdx), - Instruction(0xaf, "lax", AddrMode.Abs, 4, false, ::iLax), - Instruction(0xb0, "bcs", AddrMode.Rel, 2, true, ::iBcs), - Instruction(0xb1, "lda", AddrMode.IzY, 5, true, ::iLda), - Instruction(0xb2, "???", AddrMode.Imp, 0, false, ::iInvalid), - Instruction(0xb3, "lax", AddrMode.IzY, 5, false, ::iLax), - Instruction(0xb4, "ldy", AddrMode.ZpX, 4, true, ::iLdy), - Instruction(0xb5, "lda", AddrMode.ZpX, 4, true, ::iLda), - Instruction(0xb6, "ldx", AddrMode.ZpY, 4, true, ::iLdx), - Instruction(0xb7, "lax", AddrMode.ZpY, 4, false, ::iLax), - Instruction(0xb8, "clv", AddrMode.Imp, 2, true, ::iClv), - Instruction(0xb9, "lda", AddrMode.AbsY, 4, true, ::iLda), - Instruction(0xba, "tsx", AddrMode.Imp, 2, true, ::iTsx), - Instruction(0xbb, "las", AddrMode.AbsY, 4, false, ::iLas), - Instruction(0xbc, "ldy", AddrMode.AbsX, 4, true, ::iLdy), - Instruction(0xbd, "lda", AddrMode.AbsX, 4, true, ::iLda), - Instruction(0xbe, "ldx", AddrMode.AbsY, 4, true, ::iLdx), - Instruction(0xbf, "lax", AddrMode.AbsY, 4, false, ::iLax), - Instruction(0xc0, "cpy", AddrMode.Imm, 2, true, ::iCpy), - Instruction(0xc1, "cmp", AddrMode.IzX, 6, true, ::iCmp), - Instruction(0xc2, "nop", AddrMode.Imm, 2, false, ::iNop), - Instruction(0xc3, "dcp", AddrMode.IzX, 8, false, ::iDcp), - Instruction(0xc4, "cpy", AddrMode.Zp, 3, true, ::iCpy), - Instruction(0xc5, "cmp", AddrMode.Zp, 3, true, ::iCmp), - Instruction(0xc6, "dec", AddrMode.Zp, 5, true, ::iDec), - Instruction(0xc7, "dcp", AddrMode.Zp, 5, false, ::iDcp), - Instruction(0xc8, "iny", AddrMode.Imp, 2, true, ::iIny), - Instruction(0xc9, "cmp", AddrMode.Imm, 2, true, ::iCmp), - Instruction(0xca, "dex", AddrMode.Imp, 2, true, ::iDex), - Instruction(0xcb, "axs", AddrMode.Imm, 2, false, ::iAxs), - Instruction(0xcc, "cpy", AddrMode.Abs, 4, true, ::iCpy), - Instruction(0xcd, "cmp", AddrMode.Abs, 4, true, ::iCmp), - Instruction(0xce, "dec", AddrMode.Abs, 6, true, ::iDec), - Instruction(0xcf, "dcp", AddrMode.Abs, 6, false, ::iDcp), - Instruction(0xd0, "bne", AddrMode.Rel, 2, true, ::iBne), - Instruction(0xd1, "cmp", AddrMode.IzY, 5, true, ::iCmp), - Instruction(0xd2, "???", AddrMode.Imp, 0, false, ::iInvalid), - Instruction(0xd3, "dcp", AddrMode.IzY, 8, false, ::iDcp), - Instruction(0xd4, "nop", AddrMode.ZpX, 4, false, ::iNop), - Instruction(0xd5, "cmp", AddrMode.ZpX, 4, true, ::iCmp), - Instruction(0xd6, "dec", AddrMode.ZpX, 6, true, ::iDec), - Instruction(0xd7, "dcp", AddrMode.ZpX, 6, false, ::iDcp), - Instruction(0xd8, "cld", AddrMode.Imp, 2, true, ::iCld), - Instruction(0xd9, "cmp", AddrMode.AbsY, 4, true, ::iCmp), - Instruction(0xda, "nop", AddrMode.Imp, 2, false, ::iNop), - Instruction(0xdb, "dcp", AddrMode.AbsY, 7, false, ::iDcp), - Instruction(0xdc, "nop", AddrMode.AbsX, 4, false, ::iNop), - Instruction(0xdd, "cmp", AddrMode.AbsX, 4, true, ::iCmp), - Instruction(0xde, "dec", AddrMode.AbsX, 7, true, ::iDec), - Instruction(0xdf, "dcp", AddrMode.AbsX, 7, false, ::iDcp), - Instruction(0xe0, "cpx", AddrMode.Imm, 2, true, ::iCpx), - Instruction(0xe1, "sbc", AddrMode.IzX, 6, true, ::iSbc), - Instruction(0xe2, "nop", AddrMode.Imm, 2, false, ::iNop), - Instruction(0xe3, "isc", AddrMode.IzX, 8, false, ::iIsc), - Instruction(0xe4, "cpx", AddrMode.Zp, 3, true, ::iCpx), - Instruction(0xe5, "sbc", AddrMode.Zp, 3, true, ::iSbc), - Instruction(0xe6, "inc", AddrMode.Zp, 5, true, ::iInc), - Instruction(0xe7, "isc", AddrMode.Zp, 5, false, ::iIsc), - Instruction(0xe8, "inx", AddrMode.Imp, 2, true, ::iInx), - Instruction(0xe9, "sbc", AddrMode.Imm, 2, true, ::iSbc), - Instruction(0xea, "nop", AddrMode.Imp, 2, true, ::iNop), - Instruction(0xeb, "sbc", AddrMode.Imm, 2, false, ::iSbc), - Instruction(0xec, "cpx", AddrMode.Abs, 4, true, ::iCpx), - Instruction(0xed, "sbc", AddrMode.Abs, 4, true, ::iSbc), - Instruction(0xee, "inc", AddrMode.Abs, 6, true, ::iInc), - Instruction(0xef, "isc", AddrMode.Abs, 6, true, ::iIsc), - Instruction(0xf0, "beq", AddrMode.Rel, 2, true, ::iBeq), - Instruction(0xf1, "sbc", AddrMode.IzY, 5, true, ::iSbc), - Instruction(0xf2, "???", AddrMode.Imp, 0, false, ::iInvalid), - Instruction(0xf3, "isc", AddrMode.IzY, 8, false, ::iIsc), - Instruction(0xf4, "nop", AddrMode.ZpX, 4, false, ::iNop), - Instruction(0xf5, "sbc", AddrMode.ZpX, 4, true, ::iSbc), - Instruction(0xf6, "inc", AddrMode.ZpX, 6, true, ::iInc), - Instruction(0xf7, "isc", AddrMode.ZpX, 6, false, ::iIsc), - Instruction(0xf8, "sed", AddrMode.Imp, 2, true, ::iSed), - Instruction(0xf9, "sbc", AddrMode.AbsY, 4, true, ::iSbc), - Instruction(0xfa, "nop", AddrMode.Imp, 2, false, ::iNop), - Instruction(0xfb, "isc", AddrMode.AbsY, 7, false, ::iIsc), - Instruction(0xfc, "nop", AddrMode.AbsX, 4, false, ::iNop), - Instruction(0xfd, "sbc", AddrMode.AbsX, 4, true, ::iSbc), - Instruction(0xfe, "inc", AddrMode.AbsX, 7, true, ::iInc), - Instruction(0xff, "isc", AddrMode.AbsX, 7, false, ::iIsc) + Instruction(0x00, "brk", AddrMode.Imp, 7, ::iBrk), + Instruction(0x01, "ora", AddrMode.IzX, 6, ::iOra), + Instruction(0x02, "???", AddrMode.Imp, 0, ::iInvalid), + Instruction(0x03, "slo", AddrMode.IzX, 8, ::iSlo), + Instruction(0x04, "nop", AddrMode.Zp, 3, ::iNop), + Instruction(0x05, "ora", AddrMode.Zp, 3, ::iOra), + Instruction(0x06, "asl", AddrMode.Zp, 5, ::iAsl), + Instruction(0x07, "slo", AddrMode.Zp, 5, ::iSlo), + Instruction(0x08, "php", AddrMode.Imp, 3, ::iPhp), + Instruction(0x09, "ora", AddrMode.Imm, 2, ::iOra), + Instruction(0x0a, "asl", AddrMode.Acc, 2, ::iAsl), + Instruction(0x0b, "anc", AddrMode.Imm, 2, ::iAnc), + Instruction(0x0c, "nop", AddrMode.Abs, 4, ::iNop), + Instruction(0x0d, "ora", AddrMode.Abs, 4, ::iOra), + Instruction(0x0e, "asl", AddrMode.Abs, 6, ::iAsl), + Instruction(0x0f, "slo", AddrMode.Abs, 6, ::iSlo), + Instruction(0x10, "bpl", AddrMode.Rel, 2, ::iBpl), + Instruction(0x11, "ora", AddrMode.IzY, 5, ::iOra), + Instruction(0x12, "???", AddrMode.Imp, 0, ::iInvalid), + Instruction(0x13, "slo", AddrMode.IzY, 6, ::iSlo), + Instruction(0x14, "nop", AddrMode.ZpX, 4, ::iNop), + Instruction(0x15, "ora", AddrMode.ZpX, 4, ::iOra), + Instruction(0x16, "asl", AddrMode.ZpX, 6, ::iAsl), + Instruction(0x17, "slo", AddrMode.ZpX, 6, ::iSlo), + Instruction(0x18, "clc", AddrMode.Imp, 2, ::iClc), + Instruction(0x19, "ora", AddrMode.AbsY, 4, ::iOra), + Instruction(0x1a, "nop", AddrMode.Imp, 2, ::iNop), + Instruction(0x1b, "slo", AddrMode.AbsY, 7, ::iSlo), + Instruction(0x1c, "nop", AddrMode.AbsX, 4, ::iNop), + Instruction(0x1d, "ora", AddrMode.AbsX, 4, ::iOra), + Instruction(0x1e, "asl", AddrMode.AbsX, 7, ::iAsl), + Instruction(0x1f, "slo", AddrMode.AbsX, 7, ::iSlo), + Instruction(0x20, "jsr", AddrMode.Abs, 6, ::iJsr), + Instruction(0x21, "and", AddrMode.IzX, 6, ::iAnd), + Instruction(0x22, "???", AddrMode.Imp, 0, ::iInvalid), + Instruction(0x23, "rla", AddrMode.IzX, 8, ::iRla), + Instruction(0x24, "bit", AddrMode.Zp, 3, ::iBit), + Instruction(0x25, "and", AddrMode.Zp, 3, ::iAnd), + Instruction(0x26, "rol", AddrMode.Zp, 5, ::iRol), + Instruction(0x27, "rla", AddrMode.Zp, 5, ::iRla), + Instruction(0x28, "plp", AddrMode.Imp, 4, ::iPlp), + Instruction(0x29, "and", AddrMode.Imm, 2, ::iAnd), + Instruction(0x2a, "rol", AddrMode.Acc, 2, ::iRol), + Instruction(0x2b, "anc", AddrMode.Imm, 2, ::iAnc), + Instruction(0x2c, "bit", AddrMode.Abs, 4, ::iBit), + Instruction(0x2d, "and", AddrMode.Abs, 4, ::iAnd), + Instruction(0x2e, "rol", AddrMode.Abs, 6, ::iRol), + Instruction(0x2f, "rla", AddrMode.Abs, 6, ::iRla), + Instruction(0x30, "bmi", AddrMode.Rel, 2, ::iBmi), + Instruction(0x31, "and", AddrMode.IzY, 5, ::iAnd), + Instruction(0x32, "???", AddrMode.Imp, 0, ::iInvalid), + Instruction(0x33, "rla", AddrMode.IzY, 8, ::iRla), + Instruction(0x34, "nop", AddrMode.ZpX, 4, ::iNop), + Instruction(0x35, "and", AddrMode.ZpX, 4, ::iAnd), + Instruction(0x36, "rol", AddrMode.ZpX, 6, ::iRol), + Instruction(0x37, "rla", AddrMode.ZpX, 6, ::iRla), + Instruction(0x38, "sec", AddrMode.Imp, 2, ::iSec), + Instruction(0x39, "and", AddrMode.AbsY, 4, ::iAnd), + Instruction(0x3a, "nop", AddrMode.Imp, 2, ::iNop), + Instruction(0x3b, "rla", AddrMode.AbsY, 7, ::iRla), + Instruction(0x3c, "nop", AddrMode.AbsX, 4, ::iNop), + Instruction(0x3d, "and", AddrMode.AbsX, 4, ::iAnd), + Instruction(0x3e, "rol", AddrMode.AbsX, 7, ::iRol), + Instruction(0x3f, "rla", AddrMode.AbsX, 7, ::iRla), + Instruction(0x40, "rti", AddrMode.Imp, 6, ::iRti), + Instruction(0x41, "eor", AddrMode.IzX, 6, ::iEor), + Instruction(0x42, "???", AddrMode.Imp, 0, ::iInvalid), + Instruction(0x43, "sre", AddrMode.IzX, 8, ::iSre), + Instruction(0x44, "nop", AddrMode.Zp, 3, ::iNop), + Instruction(0x45, "eor", AddrMode.Zp, 3, ::iEor), + Instruction(0x46, "lsr", AddrMode.Zp, 5, ::iLsr), + Instruction(0x47, "sre", AddrMode.Zp, 5, ::iSre), + Instruction(0x48, "pha", AddrMode.Imp, 3, ::iPha), + Instruction(0x49, "eor", AddrMode.Imm, 2, ::iEor), + Instruction(0x4a, "lsr", AddrMode.Acc, 2, ::iLsr), + Instruction(0x4b, "alr", AddrMode.Imm, 2, ::iAlr), + Instruction(0x4c, "jmp", AddrMode.Abs, 3, ::iJmp), + Instruction(0x4d, "eor", AddrMode.Abs, 4, ::iEor), + Instruction(0x4e, "lsr", AddrMode.Abs, 6, ::iLsr), + Instruction(0x4f, "sre", AddrMode.Abs, 6, ::iSre), + Instruction(0x50, "bvc", AddrMode.Rel, 2, ::iBvc), + Instruction(0x51, "eor", AddrMode.IzY, 5, ::iEor), + Instruction(0x52, "???", AddrMode.Imp, 0, ::iInvalid), + Instruction(0x53, "sre", AddrMode.IzY, 8, ::iSre), + Instruction(0x54, "nop", AddrMode.ZpX, 4, ::iNop), + Instruction(0x55, "eor", AddrMode.ZpX, 4, ::iEor), + Instruction(0x56, "lsr", AddrMode.ZpX, 6, ::iLsr), + Instruction(0x57, "sre", AddrMode.ZpX, 6, ::iSre), + Instruction(0x58, "cli", AddrMode.Imp, 2, ::iCli), + Instruction(0x59, "eor", AddrMode.AbsY, 4, ::iEor), + Instruction(0x5a, "nop", AddrMode.Imp, 2, ::iNop), + Instruction(0x5b, "sre", AddrMode.AbsY, 7, ::iSre), + Instruction(0x5c, "nop", AddrMode.AbsX, 4, ::iNop), + Instruction(0x5d, "eor", AddrMode.AbsX, 4, ::iEor), + Instruction(0x5e, "lsr", AddrMode.AbsX, 7, ::iLsr), + Instruction(0x5f, "sre", AddrMode.AbsX, 7, ::iSre), + Instruction(0x60, "rts", AddrMode.Imp, 6, ::iRts), + Instruction(0x61, "adc", AddrMode.IzX, 6, ::iAdc), + Instruction(0x62, "???", AddrMode.Imp, 0, ::iInvalid), + Instruction(0x63, "rra", AddrMode.IzX, 8, ::iRra), + Instruction(0x64, "nop", AddrMode.Zp, 3, ::iNop), + Instruction(0x65, "adc", AddrMode.Zp, 3, ::iAdc), + Instruction(0x66, "ror", AddrMode.Zp, 5, ::iRor), + Instruction(0x67, "rra", AddrMode.Zp, 5, ::iRra), + Instruction(0x68, "pla", AddrMode.Imp, 4, ::iPla), + Instruction(0x69, "adc", AddrMode.Imm, 2, ::iAdc), + Instruction(0x6a, "ror", AddrMode.Acc, 2, ::iRor), + Instruction(0x6b, "arr", AddrMode.Imm, 2, ::iArr), + Instruction(0x6c, "jmp", AddrMode.Ind, 5, ::iJmp), + Instruction(0x6d, "adc", AddrMode.Abs, 4, ::iAdc), + Instruction(0x6e, "ror", AddrMode.Abs, 6, ::iRor), + Instruction(0x6f, "rra", AddrMode.Abs, 6, ::iRra), + Instruction(0x70, "bvs", AddrMode.Rel, 2, ::iBvs), + Instruction(0x71, "adc", AddrMode.IzY, 5, ::iAdc), + Instruction(0x72, "???", AddrMode.Imp, 0, ::iInvalid), + Instruction(0x73, "rra", AddrMode.IzY, 8, ::iRra), + Instruction(0x74, "nop", AddrMode.ZpX, 4, ::iNop), + Instruction(0x75, "adc", AddrMode.ZpX, 4, ::iAdc), + Instruction(0x76, "ror", AddrMode.ZpX, 6, ::iRor), + Instruction(0x77, "rra", AddrMode.ZpX, 6, ::iRra), + Instruction(0x78, "sei", AddrMode.Imp, 2, ::iSei), + Instruction(0x79, "adc", AddrMode.AbsY, 4, ::iAdc), + Instruction(0x7a, "nop", AddrMode.Imp, 2, ::iNop), + Instruction(0x7b, "rra", AddrMode.AbsY, 7, ::iRra), + Instruction(0x7c, "nop", AddrMode.AbsX, 4, ::iNop), + Instruction(0x7d, "adc", AddrMode.AbsX, 4, ::iAdc), + Instruction(0x7e, "ror", AddrMode.AbsX, 7, ::iRor), + Instruction(0x7f, "rra", AddrMode.AbsX, 7, ::iRra), + Instruction(0x80, "nop", AddrMode.Imm, 2, ::iNop), + Instruction(0x81, "sta", AddrMode.IzX, 6, ::iSta), + Instruction(0x82, "nop", AddrMode.Imm, 2, ::iNop), + Instruction(0x83, "sax", AddrMode.IzX, 6, ::iSax), + Instruction(0x84, "sty", AddrMode.Zp, 3, ::iSty), + Instruction(0x85, "sta", AddrMode.Zp, 3, ::iSta), + Instruction(0x86, "stx", AddrMode.Zp, 3, ::iStx), + Instruction(0x87, "sax", AddrMode.Zp, 3, ::iSax), + Instruction(0x88, "dey", AddrMode.Imp, 2, ::iDey), + Instruction(0x89, "nop", AddrMode.Imm, 2, ::iNop), + Instruction(0x8a, "txa", AddrMode.Imp, 2, ::iTxa), + Instruction(0x8b, "xaa", AddrMode.Imm, 2, ::iXaa), + Instruction(0x8c, "sty", AddrMode.Abs, 4, ::iSty), + Instruction(0x8d, "sta", AddrMode.Abs, 4, ::iSta), + Instruction(0x8e, "stx", AddrMode.Abs, 4, ::iStx), + Instruction(0x8f, "sax", AddrMode.Abs, 4, ::iSax), + Instruction(0x90, "bcc", AddrMode.Rel, 2, ::iBcc), + Instruction(0x91, "sta", AddrMode.IzY, 6, ::iSta), + Instruction(0x92, "???", AddrMode.Imp, 0, ::iInvalid), + Instruction(0x93, "ahx", AddrMode.IzY, 6, ::iAhx), + Instruction(0x94, "sty", AddrMode.ZpX, 4, ::iSty), + Instruction(0x95, "sta", AddrMode.ZpX, 4, ::iSta), + Instruction(0x96, "stx", AddrMode.ZpY, 4, ::iStx), + Instruction(0x97, "sax", AddrMode.ZpY, 4, ::iSax), + Instruction(0x98, "tya", AddrMode.Imp, 2, ::iTya), + Instruction(0x99, "sta", AddrMode.AbsY, 5, ::iSta), + Instruction(0x9a, "txs", AddrMode.Imp, 2, ::iTxs), + Instruction(0x9b, "tas", AddrMode.AbsY, 5, ::iTas), + Instruction(0x9c, "shy", AddrMode.AbsX, 5, ::iShy), + Instruction(0x9d, "sta", AddrMode.AbsX, 5, ::iSta), + Instruction(0x9e, "shx", AddrMode.AbsY, 5, ::iShx), + Instruction(0x9f, "ahx", AddrMode.AbsY, 5, ::iAhx), + Instruction(0xa0, "ldy", AddrMode.Imm, 2, ::iLdy), + Instruction(0xa1, "lda", AddrMode.IzX, 6, ::iLda), + Instruction(0xa2, "ldx", AddrMode.Imm, 2, ::iLdx), + Instruction(0xa3, "lax", AddrMode.IzX, 6, ::iLax), + Instruction(0xa4, "ldy", AddrMode.Zp, 3, ::iLdy), + Instruction(0xa5, "lda", AddrMode.Zp, 3, ::iLda), + Instruction(0xa6, "ldx", AddrMode.Zp, 3, ::iLdx), + Instruction(0xa7, "lax", AddrMode.Zp, 3, ::iLax), + Instruction(0xa8, "tay", AddrMode.Imp, 2, ::iTay), + Instruction(0xa9, "lda", AddrMode.Imm, 2, ::iLda), + Instruction(0xaa, "tax", AddrMode.Imp, 2, ::iTax), + Instruction(0xab, "lax", AddrMode.Imm, 2, ::iLax), + Instruction(0xac, "ldy", AddrMode.Abs, 4, ::iLdy), + Instruction(0xad, "lda", AddrMode.Abs, 4, ::iLda), + Instruction(0xae, "ldx", AddrMode.Abs, 4, ::iLdx), + Instruction(0xaf, "lax", AddrMode.Abs, 4, ::iLax), + Instruction(0xb0, "bcs", AddrMode.Rel, 2, ::iBcs), + Instruction(0xb1, "lda", AddrMode.IzY, 5, ::iLda), + Instruction(0xb2, "???", AddrMode.Imp, 0, ::iInvalid), + Instruction(0xb3, "lax", AddrMode.IzY, 5, ::iLax), + Instruction(0xb4, "ldy", AddrMode.ZpX, 4, ::iLdy), + Instruction(0xb5, "lda", AddrMode.ZpX, 4, ::iLda), + Instruction(0xb6, "ldx", AddrMode.ZpY, 4, ::iLdx), + Instruction(0xb7, "lax", AddrMode.ZpY, 4, ::iLax), + Instruction(0xb8, "clv", AddrMode.Imp, 2, ::iClv), + Instruction(0xb9, "lda", AddrMode.AbsY, 4, ::iLda), + Instruction(0xba, "tsx", AddrMode.Imp, 2, ::iTsx), + Instruction(0xbb, "las", AddrMode.AbsY, 4, ::iLas), + Instruction(0xbc, "ldy", AddrMode.AbsX, 4, ::iLdy), + Instruction(0xbd, "lda", AddrMode.AbsX, 4, ::iLda), + Instruction(0xbe, "ldx", AddrMode.AbsY, 4, ::iLdx), + Instruction(0xbf, "lax", AddrMode.AbsY, 4, ::iLax), + Instruction(0xc0, "cpy", AddrMode.Imm, 2, ::iCpy), + Instruction(0xc1, "cmp", AddrMode.IzX, 6, ::iCmp), + Instruction(0xc2, "nop", AddrMode.Imm, 2, ::iNop), + Instruction(0xc3, "dcp", AddrMode.IzX, 8, ::iDcp), + Instruction(0xc4, "cpy", AddrMode.Zp, 3, ::iCpy), + Instruction(0xc5, "cmp", AddrMode.Zp, 3, ::iCmp), + Instruction(0xc6, "dec", AddrMode.Zp, 5, ::iDec), + Instruction(0xc7, "dcp", AddrMode.Zp, 5, ::iDcp), + Instruction(0xc8, "iny", AddrMode.Imp, 2, ::iIny), + Instruction(0xc9, "cmp", AddrMode.Imm, 2, ::iCmp), + Instruction(0xca, "dex", AddrMode.Imp, 2, ::iDex), + Instruction(0xcb, "axs", AddrMode.Imm, 2, ::iAxs), + Instruction(0xcc, "cpy", AddrMode.Abs, 4, ::iCpy), + Instruction(0xcd, "cmp", AddrMode.Abs, 4, ::iCmp), + Instruction(0xce, "dec", AddrMode.Abs, 6, ::iDec), + Instruction(0xcf, "dcp", AddrMode.Abs, 6, ::iDcp), + Instruction(0xd0, "bne", AddrMode.Rel, 2, ::iBne), + Instruction(0xd1, "cmp", AddrMode.IzY, 5, ::iCmp), + Instruction(0xd2, "???", AddrMode.Imp, 0, ::iInvalid), + Instruction(0xd3, "dcp", AddrMode.IzY, 8, ::iDcp), + Instruction(0xd4, "nop", AddrMode.ZpX, 4, ::iNop), + Instruction(0xd5, "cmp", AddrMode.ZpX, 4, ::iCmp), + Instruction(0xd6, "dec", AddrMode.ZpX, 6, ::iDec), + Instruction(0xd7, "dcp", AddrMode.ZpX, 6, ::iDcp), + Instruction(0xd8, "cld", AddrMode.Imp, 2, ::iCld), + Instruction(0xd9, "cmp", AddrMode.AbsY, 4, ::iCmp), + Instruction(0xda, "nop", AddrMode.Imp, 2, ::iNop), + Instruction(0xdb, "dcp", AddrMode.AbsY, 7, ::iDcp), + Instruction(0xdc, "nop", AddrMode.AbsX, 4, ::iNop), + Instruction(0xdd, "cmp", AddrMode.AbsX, 4, ::iCmp), + Instruction(0xde, "dec", AddrMode.AbsX, 7, ::iDec), + Instruction(0xdf, "dcp", AddrMode.AbsX, 7, ::iDcp), + Instruction(0xe0, "cpx", AddrMode.Imm, 2, ::iCpx), + Instruction(0xe1, "sbc", AddrMode.IzX, 6, ::iSbc), + Instruction(0xe2, "nop", AddrMode.Imm, 2, ::iNop), + Instruction(0xe3, "isc", AddrMode.IzX, 8, ::iIsc), + Instruction(0xe4, "cpx", AddrMode.Zp, 3, ::iCpx), + Instruction(0xe5, "sbc", AddrMode.Zp, 3, ::iSbc), + Instruction(0xe6, "inc", AddrMode.Zp, 5, ::iInc), + Instruction(0xe7, "isc", AddrMode.Zp, 5, ::iIsc), + Instruction(0xe8, "inx", AddrMode.Imp, 2, ::iInx), + Instruction(0xe9, "sbc", AddrMode.Imm, 2, ::iSbc), + Instruction(0xea, "nop", AddrMode.Imp, 2, ::iNop), + Instruction(0xeb, "sbc", AddrMode.Imm, 2, ::iSbc), + Instruction(0xec, "cpx", AddrMode.Abs, 4, ::iCpx), + Instruction(0xed, "sbc", AddrMode.Abs, 4, ::iSbc), + Instruction(0xee, "inc", AddrMode.Abs, 6, ::iInc), + Instruction(0xef, "isc", AddrMode.Abs, 6, ::iIsc), + Instruction(0xf0, "beq", AddrMode.Rel, 2, ::iBeq), + Instruction(0xf1, "sbc", AddrMode.IzY, 5, ::iSbc), + Instruction(0xf2, "???", AddrMode.Imp, 0, ::iInvalid), + Instruction(0xf3, "isc", AddrMode.IzY, 8, ::iIsc), + Instruction(0xf4, "nop", AddrMode.ZpX, 4, ::iNop), + Instruction(0xf5, "sbc", AddrMode.ZpX, 4, ::iSbc), + Instruction(0xf6, "inc", AddrMode.ZpX, 6, ::iInc), + Instruction(0xf7, "isc", AddrMode.ZpX, 6, ::iIsc), + Instruction(0xf8, "sed", AddrMode.Imp, 2, ::iSed), + Instruction(0xf9, "sbc", AddrMode.AbsY, 4, ::iSbc), + Instruction(0xfa, "nop", AddrMode.Imp, 2, ::iNop), + Instruction(0xfb, "isc", AddrMode.AbsY, 7, ::iIsc), + Instruction(0xfc, "nop", AddrMode.AbsX, 4, ::iNop), + Instruction(0xfd, "sbc", AddrMode.AbsX, 4, ::iSbc), + Instruction(0xfe, "inc", AddrMode.AbsX, 7, ::iInc), + Instruction(0xff, "isc", AddrMode.AbsX, 7, ::iIsc) ).toTypedArray() diff --git a/sim65/src/components/Parallel.kt b/sim65/src/components/ParallelPort.kt similarity index 84% rename from sim65/src/components/Parallel.kt rename to sim65/src/components/ParallelPort.kt index 6b063b3a4..e86fe3e8d 100644 --- a/sim65/src/components/Parallel.kt +++ b/sim65/src/components/ParallelPort.kt @@ -7,7 +7,7 @@ import sim65.Petscii * First address = data byte (8 parallel bits) * Second address = control byte (bit 0 high = write byte) */ -class Parallel(startAddress: Address, endAddress: Address) : MemMappedComponent(startAddress, endAddress) { +class ParallelPort(startAddress: Address, endAddress: Address) : MemMappedComponent(startAddress, endAddress) { private var dataByte: UByte = 0 init { @@ -34,6 +34,4 @@ class Parallel(startAddress: Address, endAddress: Address) : MemMappedComponent( } } } - - override fun cloneMem(): Array = listOf(dataByte, 0).toTypedArray() } diff --git a/sim65/src/components/Ram.kt b/sim65/src/components/Ram.kt index 15ce4ad94..43ccdbb96 100644 --- a/sim65/src/components/Ram.kt +++ b/sim65/src/components/Ram.kt @@ -2,7 +2,7 @@ package sim65.components import java.io.File -class Ram(startAddress: Address, endAddress: Address): MemMappedComponent(startAddress, endAddress) { +class Ram(startAddress: Address, endAddress: Address): MemoryComponent(startAddress, endAddress) { private val memory = ShortArray(endAddress-startAddress+1) override operator fun get(address: Address): UByte = memory[address-startAddress] @@ -11,7 +11,7 @@ class Ram(startAddress: Address, endAddress: Address): MemMappedComponent(startA memory[address-startAddress] = data } - override fun cloneMem(): Array = memory.toTypedArray() + override fun cloneContents(): Array = memory.toTypedArray() override fun clock() { } diff --git a/sim65/src/components/Rom.kt b/sim65/src/components/Rom.kt index 54f271031..b9e5c54f7 100644 --- a/sim65/src/components/Rom.kt +++ b/sim65/src/components/Rom.kt @@ -1,15 +1,20 @@ package sim65.components -class Rom(startAddress: Address, endAddress: Address, data: Array): MemMappedComponent(startAddress, endAddress) { - private val memory = ShortArray(data.size) { index -> data[index] } +class Rom(startAddress: Address, endAddress: Address, data: Array? = null) : MemoryComponent(startAddress, endAddress) { + private val memory = + if (data == null) + ShortArray(endAddress - startAddress - 1) + else + ShortArray(data.size) { index -> data[index] } init { - require(endAddress-startAddress+1 == data.size) { "rom address range doesn't match size of data bytes" } + if (data != null) + require(endAddress - startAddress + 1 == data.size) { "rom address range doesn't match size of data bytes" } } - override operator fun get(address: Address): UByte = memory[address-startAddress] - override operator fun set(address: Address, data: UByte) { } - override fun cloneMem(): Array = memory.toTypedArray() - override fun clock() { } - override fun reset() { } + override operator fun get(address: Address): UByte = memory[address - startAddress] + override operator fun set(address: Address, data: UByte) {} + override fun cloneContents(): Array = memory.toTypedArray() + override fun clock() {} + override fun reset() {} } diff --git a/sim65/src/components/Timer.kt b/sim65/src/components/Timer.kt index 044a44ed6..b87d459ac 100644 --- a/sim65/src/components/Timer.kt +++ b/sim65/src/components/Timer.kt @@ -1,29 +1,28 @@ package sim65.components class Timer(startAddress: Address, endAddress: Address): MemMappedComponent(startAddress, endAddress) { - private var cycle: Long = 0 + private var counter: Long = 0 init { require(endAddress - startAddress + 1 == 4) { "timer needs exactly 4 memory bytes" } } override fun clock() { - cycle++ - if (cycle > 0xffffffff) - cycle = 0 + counter++ + if (counter > 0xffffffff) + counter = 0 + println("TIMER CLOCK $counter") } override fun reset() { - cycle = 0 + counter = 0 } override operator fun get(address: Address): UByte { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + TODO("timer read $address") } override operator fun set(address: Address, data: UByte) { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + TODO("timer write $address = $data") } - - override fun cloneMem(): Array = TODO("clonemem timer") } diff --git a/sim65/test/Test6502CpuBasics.kt b/sim65/test/Test6502CpuBasics.kt index 21b8ff4c4..9e538e680 100644 --- a/sim65/test/Test6502CpuBasics.kt +++ b/sim65/test/Test6502CpuBasics.kt @@ -1,6 +1,10 @@ import org.junit.jupiter.api.Test +import org.junit.jupiter.api.fail import sim65.components.Bus import sim65.components.Cpu6502 +import sim65.components.InstructionError +import sim65.components.Ram +import kotlin.system.measureNanoTime import kotlin.test.assertEquals class Test6502CpuBasics { @@ -23,4 +27,75 @@ class Test6502CpuBasics { assertEquals(0b00100100, cpu.Status.asByte()) } + @Test + fun testCpuPerformance() { + val cpu = Cpu6502(true) + val ram = Ram(0x1000, 0x2000) + // load a simple program that loops a few instructions + for(b in listOf(0xa9, 0x63, 0xaa, 0x86, 0x22, 0x8e, 0x22, 0x22, 0x91, 0x22, 0x6d, 0x33, 0x33, 0xcd, 0x55, 0x55, 0xd0, 0xee, 0xf0, 0xec).withIndex()) { + ram[0x1000+b.index] = b.value.toShort() + } + + val bus = Bus() + bus.add(cpu) + bus.add(ram) + cpu.reset() + cpu.PC = 0x1000 + + // warmup + while(cpu.totalCycles<1000000) + cpu.clock() + + // timing + val cycles = 50000000 + val duration = measureNanoTime { + while (cpu.totalCycles < cycles) + cpu.clock() + } + val seconds = duration.toDouble() / 1e9 + val mhz = (cycles.toDouble() / seconds) / 1e6 + println("duration $seconds sec for $cycles = $mhz Mhz") + + } + + @Test + fun testBCD() { + val cpu = Cpu6502(true) + val bus = Bus() + bus.add(cpu) + val ram = Ram(0, 0xffff) + ram[Cpu6502.RESET_vector] = 0x00 + ram[Cpu6502.RESET_vector +1] = 0x10 + ram.load("test/testfiles/bcdtest.bin", 0x1000) + bus.add(ram) + bus.reset() + + try { + while (true) { + bus.clock() + } + } catch(e: InstructionError) { + // do nothing + } + + if(ram[0x0400] ==0.toShort()) { + println("BCD TEST: OK!") + } + else { + val code = ram[0x0400] + val v1 = ram[0x0401] + val v2 = ram[0x0402] + val predictedA = ram[0x00fc] + val actualA = ram[0x00fd] + val predictedF = ram[0x00fe] + val actualF = ram[0x00ff] + println("BCD TEST: FAIL!! code=${Cpu6502.hexB(code)} value1=${Cpu6502.hexB(v1)} value2=${Cpu6502.hexB(v2)}") + println(" predictedA=${Cpu6502.hexB(predictedA)}") + println(" actualA=${Cpu6502.hexB(actualA)}") + println(" predictedF=${predictedF.toString(2).padStart(8,'0')}") + println(" actualF=${actualF.toString(2).padStart(8,'0')}") + fail("BCD test failed") + } + } + } diff --git a/sim65/test/Test6502Functional.kt b/sim65/test/Test6502Functional.kt index 2a41e4189..893aae753 100644 --- a/sim65/test/Test6502Functional.kt +++ b/sim65/test/Test6502Functional.kt @@ -1,11 +1,14 @@ import org.junit.jupiter.api.Test +import org.junit.jupiter.api.fail import sim65.components.Bus import sim65.components.Cpu6502 import sim65.components.Ram -import kotlin.test.assertEquals +import java.lang.Exception class Test6502Functional { + private class SuccessfulTestResult: Exception() + @Test fun testFunctional() { val cpu = Cpu6502(false) @@ -16,14 +19,25 @@ class Test6502Functional { bus.add(ram) cpu.reset() cpu.PC = 0x0400 + cpu.breakpoint(0x3469) { _, _ -> + // reaching this address means successful test result + if(cpu.currentOpcode==0x4c) + throw SuccessfulTestResult() + } - while(cpu.totalCycles < 50000000) { - cpu.clock() + try { + while (cpu.totalCycles < 900000000) { + cpu.clock() + } + } catch (sx: SuccessfulTestResult) { + println("test successful") + return } cpu.printState() val d = cpu.disassemble(ram, cpu.PC-20, cpu.PC+20) println(d.joinToString ("\n")) + fail("test failed") } } diff --git a/sim65/test/Test6502TestSuite.kt b/sim65/test/Test6502TestSuite.kt index 80de88cb0..9d6edf4ce 100644 --- a/sim65/test/Test6502TestSuite.kt +++ b/sim65/test/Test6502TestSuite.kt @@ -8,6 +8,7 @@ import sim65.components.InstructionError import sim65.components.Ram @TestInstance(TestInstance.Lifecycle.PER_METHOD) +@Disabled("this test suite takes a long time") class Test6502TestSuite { val cpu: Cpu6502 = Cpu6502(stopOnBrk = false)