6502 simulator passes all tests for regular opcodes

This commit is contained in:
Irmen de Jong 2019-09-09 00:27:06 +02:00
parent fec8db6a75
commit bdcd10512f
11 changed files with 407 additions and 356 deletions

View File

@ -16,6 +16,7 @@
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" /> <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/res" type="java-resource" /> <sourceFolder url="file://$MODULE_DIR$/res" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/test" isTestSource="true" /> <sourceFolder url="file://$MODULE_DIR$/test" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/build" />
</content> </content>
<orderEntry type="jdk" jdkName="openjdk-11" jdkType="JavaSDK" /> <orderEntry type="jdk" jdkName="openjdk-11" jdkType="JavaSDK" />
<orderEntry type="sourceFolder" forTests="false" /> <orderEntry type="sourceFolder" forTests="false" />

View File

@ -1,89 +1,44 @@
package sim65 package sim65
import kotlinx.cli.*
import sim65.components.* import sim65.components.*
import sim65.components.Cpu6502.Companion.hexB import sim65.components.Cpu6502.Companion.RESET_vector
import kotlin.system.exitProcess
fun main(args: Array<String>) { fun main(args: Array<String>) {
printSoftwareHeader2() printSoftwareHeader()
startSimulator2(args) startSimulator(args)
} }
internal fun printSoftwareHeader2() { internal fun printSoftwareHeader() {
val buildVersion = object {}.javaClass.getResource("/version.txt").readText().trim() val buildVersion = object {}.javaClass.getResource("/version.txt").readText().trim()
println("\nSim65 6502 cpu simulator v$buildVersion by Irmen de Jong (irmen@razorvine.net)") 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") 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<String>) { private fun startSimulator(args: Array<String>) {
val bootRom = listOf<UByte>(
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()
// 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) 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() val bus = Bus()
bus.add(cpu) bus.add(cpu)
bus.add(Rom(0xff00, 0xffff, bootRom)) bus.add(parallel)
bus.add(Parallel(0xd000, 0xd001)) bus.add(timer)
bus.add(Timer(0xd100, 0xd103))
val ram = Ram(0, 0xffff)
bus.add(ram) bus.add(ram)
bus.reset() bus.reset()
ram.load("sim65/test/testfiles/ram.bin", 0x8000) cpu.tracing = true
ram.load("sim65/test/testfiles/bcdtest.bin", 0x1000)
//ram.dump(0x8000, 0x802f)
//cpu.disassemble(ram, 0x8000, 0x802f)
try {
while (true) { while (true) {
bus.clock() bus.clock()
} }
} catch(e: InstructionError) {
}
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')}")
}
} }

View File

@ -12,14 +12,13 @@ abstract class BusComponent {
abstract class MemMappedComponent(val startAddress: Address, val endAddress: Address): BusComponent() { abstract class MemMappedComponent(val startAddress: Address, val endAddress: Address): BusComponent() {
abstract operator fun get(address: Address): UByte abstract operator fun get(address: Address): UByte
abstract operator fun set(address: Address, data: UByte) abstract operator fun set(address: Address, data: UByte)
abstract fun cloneMem(): Array<UByte>
init { init {
require(endAddress>=startAddress) require(endAddress>=startAddress)
require(startAddress>=0 && endAddress <= 0xffff) { "can only have 16-bit address space" } 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 { (from .. to).chunked(16).forEach {
print("\$${it.first().toString(16).padStart(4, '0')} ") print("\$${it.first().toString(16).padStart(4, '0')} ")
val bytes = it.map { address -> get(address) } val bytes = it.map { address -> get(address) }
@ -31,5 +30,8 @@ abstract class MemMappedComponent(val startAddress: Address, val endAddress: Add
println() println()
} }
} }
}
abstract class MemoryComponent(startAddress: Address, endAddress: Address): MemMappedComponent(startAddress, endAddress) {
abstract fun cloneContents(): Array<UByte>
} }

View File

@ -4,8 +4,8 @@ class InstructionError(msg: String) : RuntimeException(msg)
interface ICpu { interface ICpu {
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>
fun disassemble(component: MemMappedComponent, from: Address, to: Address) = fun disassemble(component: MemoryComponent, from: Address, to: Address) =
disassemble(component.cloneMem(), component.startAddress, from, to) disassemble(component.cloneContents(), component.startAddress, from, to)
fun clock() fun clock()
fun reset() fun reset()
@ -16,6 +16,7 @@ interface ICpu {
val totalCycles: Long 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 the optional additional cycles to certain instructions and addressing modes
// TODO: add IRQ and NMI signaling. // TODO: add IRQ and NMI signaling.
// TODO: make a 65c02 variant as well (and re-enable the unit tests for that). // 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 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 { override fun toString(): String {
return "[${hexB(opcode)}: $mnemonic $mode]" return "[${hexB(opcode)}: $mnemonic $mode]"
} }
@ -331,12 +332,12 @@ class Cpu6502(private val stopOnBrk: Boolean) : BusComponent(), ICpu {
} }
private fun amZpx() { 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 fetchedAddress = (readPc() + X) and 0xff
} }
private fun amZpy() { 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 fetchedAddress = (readPc() + Y) and 0xff
} }
@ -420,17 +421,17 @@ class Cpu6502(private val stopOnBrk: Boolean) : BusComponent(), ICpu {
pushStack(status.asByte().toInt()) pushStack(status.asByte().toInt())
} }
internal fun pushStack(data: Int) { private fun pushStack(data: Int) {
write(SP or 0x0100, data) write(SP or 0x0100, data)
SP = (SP - 1) and 0xff SP = (SP - 1) and 0xff
} }
internal fun popStack(): Int { private fun popStack(): Int {
SP = (SP + 1) and 0xff SP = (SP + 1) and 0xff
return read(SP or 0x0100) return read(SP or 0x0100)
} }
internal fun popStackAddr(): Address { private fun popStackAddr(): Address {
val lo = popStack() val lo = popStack()
val hi = popStack() val hi = popStack()
return lo or (hi shl 8) 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 // opcodes table from http://www.oxyron.de/html/opcodes02.html
private val opcodes = listOf( private val opcodes = listOf(
Instruction(0x00, "brk", AddrMode.Imp, 7, true, ::iBrk), Instruction(0x00, "brk", AddrMode.Imp, 7, ::iBrk),
Instruction(0x01, "ora", AddrMode.IzX, 6, true, ::iOra), Instruction(0x01, "ora", AddrMode.IzX, 6, ::iOra),
Instruction(0x02, "???", AddrMode.Imp, 0, false, ::iInvalid), Instruction(0x02, "???", AddrMode.Imp, 0, ::iInvalid),
Instruction(0x03, "slo", AddrMode.IzX, 8, false, ::iSlo), Instruction(0x03, "slo", AddrMode.IzX, 8, ::iSlo),
Instruction(0x04, "nop", AddrMode.Zp, 3, false, ::iNop), Instruction(0x04, "nop", AddrMode.Zp, 3, ::iNop),
Instruction(0x05, "ora", AddrMode.Zp, 3, true, ::iOra), Instruction(0x05, "ora", AddrMode.Zp, 3, ::iOra),
Instruction(0x06, "asl", AddrMode.Zp, 5, true, ::iAsl), Instruction(0x06, "asl", AddrMode.Zp, 5, ::iAsl),
Instruction(0x07, "slo", AddrMode.Zp, 5, false, ::iSlo), Instruction(0x07, "slo", AddrMode.Zp, 5, ::iSlo),
Instruction(0x08, "php", AddrMode.Imp, 3, true, ::iPhp), Instruction(0x08, "php", AddrMode.Imp, 3, ::iPhp),
Instruction(0x09, "ora", AddrMode.Imm, 2, true, ::iOra), Instruction(0x09, "ora", AddrMode.Imm, 2, ::iOra),
Instruction(0x0a, "asl", AddrMode.Acc, 2, true, ::iAsl), Instruction(0x0a, "asl", AddrMode.Acc, 2, ::iAsl),
Instruction(0x0b, "anc", AddrMode.Imm, 2, false, ::iAnc), Instruction(0x0b, "anc", AddrMode.Imm, 2, ::iAnc),
Instruction(0x0c, "nop", AddrMode.Abs, 4, false, ::iNop), Instruction(0x0c, "nop", AddrMode.Abs, 4, ::iNop),
Instruction(0x0d, "ora", AddrMode.Abs, 4, true, ::iOra), Instruction(0x0d, "ora", AddrMode.Abs, 4, ::iOra),
Instruction(0x0e, "asl", AddrMode.Abs, 6, true, ::iAsl), Instruction(0x0e, "asl", AddrMode.Abs, 6, ::iAsl),
Instruction(0x0f, "slo", AddrMode.Abs, 6, false, ::iSlo), Instruction(0x0f, "slo", AddrMode.Abs, 6, ::iSlo),
Instruction(0x10, "bpl", AddrMode.Rel, 2, true, ::iBpl), Instruction(0x10, "bpl", AddrMode.Rel, 2, ::iBpl),
Instruction(0x11, "ora", AddrMode.IzY, 5, true, ::iOra), Instruction(0x11, "ora", AddrMode.IzY, 5, ::iOra),
Instruction(0x12, "???", AddrMode.Imp, 0, false, ::iInvalid), Instruction(0x12, "???", AddrMode.Imp, 0, ::iInvalid),
Instruction(0x13, "slo", AddrMode.IzY, 6, false, ::iSlo), Instruction(0x13, "slo", AddrMode.IzY, 6, ::iSlo),
Instruction(0x14, "nop", AddrMode.ZpX, 4, false, ::iNop), Instruction(0x14, "nop", AddrMode.ZpX, 4, ::iNop),
Instruction(0x15, "ora", AddrMode.ZpX, 4, true, ::iOra), Instruction(0x15, "ora", AddrMode.ZpX, 4, ::iOra),
Instruction(0x16, "asl", AddrMode.ZpX, 6, true, ::iAsl), Instruction(0x16, "asl", AddrMode.ZpX, 6, ::iAsl),
Instruction(0x17, "slo", AddrMode.ZpX, 6, false, ::iSlo), Instruction(0x17, "slo", AddrMode.ZpX, 6, ::iSlo),
Instruction(0x18, "clc", AddrMode.Imp, 2, true, ::iClc), Instruction(0x18, "clc", AddrMode.Imp, 2, ::iClc),
Instruction(0x19, "ora", AddrMode.AbsY, 4, true, ::iOra), Instruction(0x19, "ora", AddrMode.AbsY, 4, ::iOra),
Instruction(0x1a, "nop", AddrMode.Imp, 2, false, ::iNop), Instruction(0x1a, "nop", AddrMode.Imp, 2, ::iNop),
Instruction(0x1b, "slo", AddrMode.AbsY, 7, false, ::iSlo), Instruction(0x1b, "slo", AddrMode.AbsY, 7, ::iSlo),
Instruction(0x1c, "nop", AddrMode.AbsX, 4, false, ::iNop), Instruction(0x1c, "nop", AddrMode.AbsX, 4, ::iNop),
Instruction(0x1d, "ora", AddrMode.AbsX, 4, true, ::iOra), Instruction(0x1d, "ora", AddrMode.AbsX, 4, ::iOra),
Instruction(0x1e, "asl", AddrMode.AbsX, 7, true, ::iAsl), Instruction(0x1e, "asl", AddrMode.AbsX, 7, ::iAsl),
Instruction(0x1f, "slo", AddrMode.AbsX, 7, false, ::iSlo), Instruction(0x1f, "slo", AddrMode.AbsX, 7, ::iSlo),
Instruction(0x20, "jsr", AddrMode.Abs, 6, true, ::iJsr), Instruction(0x20, "jsr", AddrMode.Abs, 6, ::iJsr),
Instruction(0x21, "and", AddrMode.IzX, 6, true, ::iAnd), Instruction(0x21, "and", AddrMode.IzX, 6, ::iAnd),
Instruction(0x22, "???", AddrMode.Imp, 0, false, ::iInvalid), Instruction(0x22, "???", AddrMode.Imp, 0, ::iInvalid),
Instruction(0x23, "rla", AddrMode.IzX, 8, false, ::iRla), Instruction(0x23, "rla", AddrMode.IzX, 8, ::iRla),
Instruction(0x24, "bit", AddrMode.Zp, 3, true, ::iBit), Instruction(0x24, "bit", AddrMode.Zp, 3, ::iBit),
Instruction(0x25, "and", AddrMode.Zp, 3, true, ::iAnd), Instruction(0x25, "and", AddrMode.Zp, 3, ::iAnd),
Instruction(0x26, "rol", AddrMode.Zp, 5, true, ::iRol), Instruction(0x26, "rol", AddrMode.Zp, 5, ::iRol),
Instruction(0x27, "rla", AddrMode.Zp, 5, false, ::iRla), Instruction(0x27, "rla", AddrMode.Zp, 5, ::iRla),
Instruction(0x28, "plp", AddrMode.Imp, 4, true, ::iPlp), Instruction(0x28, "plp", AddrMode.Imp, 4, ::iPlp),
Instruction(0x29, "and", AddrMode.Imm, 2, true, ::iAnd), Instruction(0x29, "and", AddrMode.Imm, 2, ::iAnd),
Instruction(0x2a, "rol", AddrMode.Acc, 2, true, ::iRol), Instruction(0x2a, "rol", AddrMode.Acc, 2, ::iRol),
Instruction(0x2b, "anc", AddrMode.Imm, 2, false, ::iAnc), Instruction(0x2b, "anc", AddrMode.Imm, 2, ::iAnc),
Instruction(0x2c, "bit", AddrMode.Abs, 4, true, ::iBit), Instruction(0x2c, "bit", AddrMode.Abs, 4, ::iBit),
Instruction(0x2d, "and", AddrMode.Abs, 4, true, ::iAnd), Instruction(0x2d, "and", AddrMode.Abs, 4, ::iAnd),
Instruction(0x2e, "rol", AddrMode.Abs, 6, true, ::iRol), Instruction(0x2e, "rol", AddrMode.Abs, 6, ::iRol),
Instruction(0x2f, "rla", AddrMode.Abs, 6, false, ::iRla), Instruction(0x2f, "rla", AddrMode.Abs, 6, ::iRla),
Instruction(0x30, "bmi", AddrMode.Rel, 2, true, ::iBmi), Instruction(0x30, "bmi", AddrMode.Rel, 2, ::iBmi),
Instruction(0x31, "and", AddrMode.IzY, 5, true, ::iAnd), Instruction(0x31, "and", AddrMode.IzY, 5, ::iAnd),
Instruction(0x32, "???", AddrMode.Imp, 0, false, ::iInvalid), Instruction(0x32, "???", AddrMode.Imp, 0, ::iInvalid),
Instruction(0x33, "rla", AddrMode.IzY, 8, false, ::iRla), Instruction(0x33, "rla", AddrMode.IzY, 8, ::iRla),
Instruction(0x34, "nop", AddrMode.ZpX, 4, false, ::iNop), Instruction(0x34, "nop", AddrMode.ZpX, 4, ::iNop),
Instruction(0x35, "and", AddrMode.ZpX, 4, true, ::iAnd), Instruction(0x35, "and", AddrMode.ZpX, 4, ::iAnd),
Instruction(0x36, "rol", AddrMode.ZpX, 6, true, ::iRol), Instruction(0x36, "rol", AddrMode.ZpX, 6, ::iRol),
Instruction(0x37, "rla", AddrMode.ZpX, 6, false, ::iRla), Instruction(0x37, "rla", AddrMode.ZpX, 6, ::iRla),
Instruction(0x38, "sec", AddrMode.Imp, 2, true, ::iSec), Instruction(0x38, "sec", AddrMode.Imp, 2, ::iSec),
Instruction(0x39, "and", AddrMode.AbsY, 4, true, ::iAnd), Instruction(0x39, "and", AddrMode.AbsY, 4, ::iAnd),
Instruction(0x3a, "nop", AddrMode.Imp, 2, false, ::iNop), Instruction(0x3a, "nop", AddrMode.Imp, 2, ::iNop),
Instruction(0x3b, "rla", AddrMode.AbsY, 7, false, ::iRla), Instruction(0x3b, "rla", AddrMode.AbsY, 7, ::iRla),
Instruction(0x3c, "nop", AddrMode.AbsX, 4, false, ::iNop), Instruction(0x3c, "nop", AddrMode.AbsX, 4, ::iNop),
Instruction(0x3d, "and", AddrMode.AbsX, 4, true, ::iAnd), Instruction(0x3d, "and", AddrMode.AbsX, 4, ::iAnd),
Instruction(0x3e, "rol", AddrMode.AbsX, 7, true, ::iRol), Instruction(0x3e, "rol", AddrMode.AbsX, 7, ::iRol),
Instruction(0x3f, "rla", AddrMode.AbsX, 7, false, ::iRla), Instruction(0x3f, "rla", AddrMode.AbsX, 7, ::iRla),
Instruction(0x40, "rti", AddrMode.Imp, 6, true, ::iRti), Instruction(0x40, "rti", AddrMode.Imp, 6, ::iRti),
Instruction(0x41, "eor", AddrMode.IzX, 6, true, ::iEor), Instruction(0x41, "eor", AddrMode.IzX, 6, ::iEor),
Instruction(0x42, "???", AddrMode.Imp, 0, false, ::iInvalid), Instruction(0x42, "???", AddrMode.Imp, 0, ::iInvalid),
Instruction(0x43, "sre", AddrMode.IzX, 8, false, ::iSre), Instruction(0x43, "sre", AddrMode.IzX, 8, ::iSre),
Instruction(0x44, "nop", AddrMode.Zp, 3, false, ::iNop), Instruction(0x44, "nop", AddrMode.Zp, 3, ::iNop),
Instruction(0x45, "eor", AddrMode.Zp, 3, true, ::iEor), Instruction(0x45, "eor", AddrMode.Zp, 3, ::iEor),
Instruction(0x46, "lsr", AddrMode.Zp, 5, true, ::iLsr), Instruction(0x46, "lsr", AddrMode.Zp, 5, ::iLsr),
Instruction(0x47, "sre", AddrMode.Zp, 5, false, ::iSre), Instruction(0x47, "sre", AddrMode.Zp, 5, ::iSre),
Instruction(0x48, "pha", AddrMode.Imp, 3, true, ::iPha), Instruction(0x48, "pha", AddrMode.Imp, 3, ::iPha),
Instruction(0x49, "eor", AddrMode.Imm, 2, true, ::iEor), Instruction(0x49, "eor", AddrMode.Imm, 2, ::iEor),
Instruction(0x4a, "lsr", AddrMode.Acc, 2, true, ::iLsr), Instruction(0x4a, "lsr", AddrMode.Acc, 2, ::iLsr),
Instruction(0x4b, "alr", AddrMode.Imm, 2, false, ::iAlr), Instruction(0x4b, "alr", AddrMode.Imm, 2, ::iAlr),
Instruction(0x4c, "jmp", AddrMode.Abs, 3, true, ::iJmp), Instruction(0x4c, "jmp", AddrMode.Abs, 3, ::iJmp),
Instruction(0x4d, "eor", AddrMode.Abs, 4, true, ::iEor), Instruction(0x4d, "eor", AddrMode.Abs, 4, ::iEor),
Instruction(0x4e, "lsr", AddrMode.Abs, 6, true, ::iLsr), Instruction(0x4e, "lsr", AddrMode.Abs, 6, ::iLsr),
Instruction(0x4f, "sre", AddrMode.Abs, 6, false, ::iSre), Instruction(0x4f, "sre", AddrMode.Abs, 6, ::iSre),
Instruction(0x50, "bvc", AddrMode.Rel, 2, true, ::iBvc), Instruction(0x50, "bvc", AddrMode.Rel, 2, ::iBvc),
Instruction(0x51, "eor", AddrMode.IzY, 5, true, ::iEor), Instruction(0x51, "eor", AddrMode.IzY, 5, ::iEor),
Instruction(0x52, "???", AddrMode.Imp, 0, false, ::iInvalid), Instruction(0x52, "???", AddrMode.Imp, 0, ::iInvalid),
Instruction(0x53, "sre", AddrMode.IzY, 8, false, ::iSre), Instruction(0x53, "sre", AddrMode.IzY, 8, ::iSre),
Instruction(0x54, "nop", AddrMode.ZpX, 4, false, ::iNop), Instruction(0x54, "nop", AddrMode.ZpX, 4, ::iNop),
Instruction(0x55, "eor", AddrMode.ZpX, 4, true, ::iEor), Instruction(0x55, "eor", AddrMode.ZpX, 4, ::iEor),
Instruction(0x56, "lsr", AddrMode.ZpX, 6, true, ::iLsr), Instruction(0x56, "lsr", AddrMode.ZpX, 6, ::iLsr),
Instruction(0x57, "sre", AddrMode.ZpX, 6, false, ::iSre), Instruction(0x57, "sre", AddrMode.ZpX, 6, ::iSre),
Instruction(0x58, "cli", AddrMode.Imp, 2, true, ::iCli), Instruction(0x58, "cli", AddrMode.Imp, 2, ::iCli),
Instruction(0x59, "eor", AddrMode.AbsY, 4, true, ::iEor), Instruction(0x59, "eor", AddrMode.AbsY, 4, ::iEor),
Instruction(0x5a, "nop", AddrMode.Imp, 2, false, ::iNop), Instruction(0x5a, "nop", AddrMode.Imp, 2, ::iNop),
Instruction(0x5b, "sre", AddrMode.AbsY, 7, false, ::iSre), Instruction(0x5b, "sre", AddrMode.AbsY, 7, ::iSre),
Instruction(0x5c, "nop", AddrMode.AbsX, 4, false, ::iNop), Instruction(0x5c, "nop", AddrMode.AbsX, 4, ::iNop),
Instruction(0x5d, "eor", AddrMode.AbsX, 4, true, ::iEor), Instruction(0x5d, "eor", AddrMode.AbsX, 4, ::iEor),
Instruction(0x5e, "lsr", AddrMode.AbsX, 7, true, ::iLsr), Instruction(0x5e, "lsr", AddrMode.AbsX, 7, ::iLsr),
Instruction(0x5f, "sre", AddrMode.AbsX, 7, false, ::iSre), Instruction(0x5f, "sre", AddrMode.AbsX, 7, ::iSre),
Instruction(0x60, "rts", AddrMode.Imp, 6, true, ::iRts), Instruction(0x60, "rts", AddrMode.Imp, 6, ::iRts),
Instruction(0x61, "adc", AddrMode.IzX, 6, true, ::iAdc), Instruction(0x61, "adc", AddrMode.IzX, 6, ::iAdc),
Instruction(0x62, "???", AddrMode.Imp, 0, false, ::iInvalid), Instruction(0x62, "???", AddrMode.Imp, 0, ::iInvalid),
Instruction(0x63, "rra", AddrMode.IzX, 8, false, ::iRra), Instruction(0x63, "rra", AddrMode.IzX, 8, ::iRra),
Instruction(0x64, "nop", AddrMode.Zp, 3, false, ::iNop), Instruction(0x64, "nop", AddrMode.Zp, 3, ::iNop),
Instruction(0x65, "adc", AddrMode.Zp, 3, true, ::iAdc), Instruction(0x65, "adc", AddrMode.Zp, 3, ::iAdc),
Instruction(0x66, "ror", AddrMode.Zp, 5, true, ::iRor), Instruction(0x66, "ror", AddrMode.Zp, 5, ::iRor),
Instruction(0x67, "rra", AddrMode.Zp, 5, false, ::iRra), Instruction(0x67, "rra", AddrMode.Zp, 5, ::iRra),
Instruction(0x68, "pla", AddrMode.Imp, 4, true, ::iPla), Instruction(0x68, "pla", AddrMode.Imp, 4, ::iPla),
Instruction(0x69, "adc", AddrMode.Imm, 2, true, ::iAdc), Instruction(0x69, "adc", AddrMode.Imm, 2, ::iAdc),
Instruction(0x6a, "ror", AddrMode.Acc, 2, true, ::iRor), Instruction(0x6a, "ror", AddrMode.Acc, 2, ::iRor),
Instruction(0x6b, "arr", AddrMode.Imm, 2, false, ::iArr), Instruction(0x6b, "arr", AddrMode.Imm, 2, ::iArr),
Instruction(0x6c, "jmp", AddrMode.Ind, 5, true, ::iJmp), Instruction(0x6c, "jmp", AddrMode.Ind, 5, ::iJmp),
Instruction(0x6d, "adc", AddrMode.Abs, 4, true, ::iAdc), Instruction(0x6d, "adc", AddrMode.Abs, 4, ::iAdc),
Instruction(0x6e, "ror", AddrMode.Abs, 6, true, ::iRor), Instruction(0x6e, "ror", AddrMode.Abs, 6, ::iRor),
Instruction(0x6f, "rra", AddrMode.Abs, 6, false, ::iRra), Instruction(0x6f, "rra", AddrMode.Abs, 6, ::iRra),
Instruction(0x70, "bvs", AddrMode.Rel, 2, true, ::iBvs), Instruction(0x70, "bvs", AddrMode.Rel, 2, ::iBvs),
Instruction(0x71, "adc", AddrMode.IzY, 5, true, ::iAdc), Instruction(0x71, "adc", AddrMode.IzY, 5, ::iAdc),
Instruction(0x72, "???", AddrMode.Imp, 0, false, ::iInvalid), Instruction(0x72, "???", AddrMode.Imp, 0, ::iInvalid),
Instruction(0x73, "rra", AddrMode.IzY, 8, false, ::iRra), Instruction(0x73, "rra", AddrMode.IzY, 8, ::iRra),
Instruction(0x74, "nop", AddrMode.ZpX, 4, false, ::iNop), Instruction(0x74, "nop", AddrMode.ZpX, 4, ::iNop),
Instruction(0x75, "adc", AddrMode.ZpX, 4, true, ::iAdc), Instruction(0x75, "adc", AddrMode.ZpX, 4, ::iAdc),
Instruction(0x76, "ror", AddrMode.ZpX, 6, true, ::iRor), Instruction(0x76, "ror", AddrMode.ZpX, 6, ::iRor),
Instruction(0x77, "rra", AddrMode.ZpX, 6, false, ::iRra), Instruction(0x77, "rra", AddrMode.ZpX, 6, ::iRra),
Instruction(0x78, "sei", AddrMode.Imp, 2, true, ::iSei), Instruction(0x78, "sei", AddrMode.Imp, 2, ::iSei),
Instruction(0x79, "adc", AddrMode.AbsY, 4, true, ::iAdc), Instruction(0x79, "adc", AddrMode.AbsY, 4, ::iAdc),
Instruction(0x7a, "nop", AddrMode.Imp, 2, false, ::iNop), Instruction(0x7a, "nop", AddrMode.Imp, 2, ::iNop),
Instruction(0x7b, "rra", AddrMode.AbsY, 7, false, ::iRra), Instruction(0x7b, "rra", AddrMode.AbsY, 7, ::iRra),
Instruction(0x7c, "nop", AddrMode.AbsX, 4, false, ::iNop), Instruction(0x7c, "nop", AddrMode.AbsX, 4, ::iNop),
Instruction(0x7d, "adc", AddrMode.AbsX, 4, true, ::iAdc), Instruction(0x7d, "adc", AddrMode.AbsX, 4, ::iAdc),
Instruction(0x7e, "ror", AddrMode.AbsX, 7, true, ::iRor), Instruction(0x7e, "ror", AddrMode.AbsX, 7, ::iRor),
Instruction(0x7f, "rra", AddrMode.AbsX, 7, false, ::iRra), Instruction(0x7f, "rra", AddrMode.AbsX, 7, ::iRra),
Instruction(0x80, "nop", AddrMode.Imm, 2, false, ::iNop), Instruction(0x80, "nop", AddrMode.Imm, 2, ::iNop),
Instruction(0x81, "sta", AddrMode.IzX, 6, true, ::iSta), Instruction(0x81, "sta", AddrMode.IzX, 6, ::iSta),
Instruction(0x82, "nop", AddrMode.Imm, 2, false, ::iNop), Instruction(0x82, "nop", AddrMode.Imm, 2, ::iNop),
Instruction(0x83, "sax", AddrMode.IzX, 6, false, ::iSax), Instruction(0x83, "sax", AddrMode.IzX, 6, ::iSax),
Instruction(0x84, "sty", AddrMode.Zp, 3, true, ::iSty), Instruction(0x84, "sty", AddrMode.Zp, 3, ::iSty),
Instruction(0x85, "sta", AddrMode.Zp, 3, true, ::iSta), Instruction(0x85, "sta", AddrMode.Zp, 3, ::iSta),
Instruction(0x86, "stx", AddrMode.Zp, 3, true, ::iStx), Instruction(0x86, "stx", AddrMode.Zp, 3, ::iStx),
Instruction(0x87, "sax", AddrMode.Zp, 3, false, ::iSax), Instruction(0x87, "sax", AddrMode.Zp, 3, ::iSax),
Instruction(0x88, "dey", AddrMode.Imp, 2, true, ::iDey), Instruction(0x88, "dey", AddrMode.Imp, 2, ::iDey),
Instruction(0x89, "nop", AddrMode.Imm, 2, false, ::iNop), Instruction(0x89, "nop", AddrMode.Imm, 2, ::iNop),
Instruction(0x8a, "txa", AddrMode.Imp, 2, true, ::iTxa), Instruction(0x8a, "txa", AddrMode.Imp, 2, ::iTxa),
Instruction(0x8b, "xaa", AddrMode.Imm, 2, false, ::iXaa), Instruction(0x8b, "xaa", AddrMode.Imm, 2, ::iXaa),
Instruction(0x8c, "sty", AddrMode.Abs, 4, true, ::iSty), Instruction(0x8c, "sty", AddrMode.Abs, 4, ::iSty),
Instruction(0x8d, "sta", AddrMode.Abs, 4, true, ::iSta), Instruction(0x8d, "sta", AddrMode.Abs, 4, ::iSta),
Instruction(0x8e, "stx", AddrMode.Abs, 4, true, ::iStx), Instruction(0x8e, "stx", AddrMode.Abs, 4, ::iStx),
Instruction(0x8f, "sax", AddrMode.Abs, 4, true, ::iSax), Instruction(0x8f, "sax", AddrMode.Abs, 4, ::iSax),
Instruction(0x90, "bcc", AddrMode.Rel, 2, true, ::iBcc), Instruction(0x90, "bcc", AddrMode.Rel, 2, ::iBcc),
Instruction(0x91, "sta", AddrMode.IzY, 6, true, ::iSta), Instruction(0x91, "sta", AddrMode.IzY, 6, ::iSta),
Instruction(0x92, "???", AddrMode.Imp, 0, false, ::iInvalid), Instruction(0x92, "???", AddrMode.Imp, 0, ::iInvalid),
Instruction(0x93, "ahx", AddrMode.IzY, 6, false, ::iAhx), Instruction(0x93, "ahx", AddrMode.IzY, 6, ::iAhx),
Instruction(0x94, "sty", AddrMode.ZpX, 4, true, ::iSty), Instruction(0x94, "sty", AddrMode.ZpX, 4, ::iSty),
Instruction(0x95, "sta", AddrMode.ZpX, 4, true, ::iSta), Instruction(0x95, "sta", AddrMode.ZpX, 4, ::iSta),
Instruction(0x96, "stx", AddrMode.ZpY, 4, true, ::iStx), Instruction(0x96, "stx", AddrMode.ZpY, 4, ::iStx),
Instruction(0x97, "sax", AddrMode.ZpY, 4, false, ::iSax), Instruction(0x97, "sax", AddrMode.ZpY, 4, ::iSax),
Instruction(0x98, "tya", AddrMode.Imp, 2, true, ::iTya), Instruction(0x98, "tya", AddrMode.Imp, 2, ::iTya),
Instruction(0x99, "sta", AddrMode.AbsY, 5, true, ::iSta), Instruction(0x99, "sta", AddrMode.AbsY, 5, ::iSta),
Instruction(0x9a, "txs", AddrMode.Imp, 2, true, ::iTxs), Instruction(0x9a, "txs", AddrMode.Imp, 2, ::iTxs),
Instruction(0x9b, "tas", AddrMode.AbsY, 5, false, ::iTas), Instruction(0x9b, "tas", AddrMode.AbsY, 5, ::iTas),
Instruction(0x9c, "shy", AddrMode.AbsX, 5, false, ::iShy), Instruction(0x9c, "shy", AddrMode.AbsX, 5, ::iShy),
Instruction(0x9d, "sta", AddrMode.AbsX, 5, true, ::iSta), Instruction(0x9d, "sta", AddrMode.AbsX, 5, ::iSta),
Instruction(0x9e, "shx", AddrMode.AbsY, 5, false, ::iShx), Instruction(0x9e, "shx", AddrMode.AbsY, 5, ::iShx),
Instruction(0x9f, "ahx", AddrMode.AbsY, 5, false, ::iAhx), Instruction(0x9f, "ahx", AddrMode.AbsY, 5, ::iAhx),
Instruction(0xa0, "ldy", AddrMode.Imm, 2, true, ::iLdy), Instruction(0xa0, "ldy", AddrMode.Imm, 2, ::iLdy),
Instruction(0xa1, "lda", AddrMode.IzX, 6, true, ::iLda), Instruction(0xa1, "lda", AddrMode.IzX, 6, ::iLda),
Instruction(0xa2, "ldx", AddrMode.Imm, 2, true, ::iLdx), Instruction(0xa2, "ldx", AddrMode.Imm, 2, ::iLdx),
Instruction(0xa3, "lax", AddrMode.IzX, 6, false, ::iLax), Instruction(0xa3, "lax", AddrMode.IzX, 6, ::iLax),
Instruction(0xa4, "ldy", AddrMode.Zp, 3, true, ::iLdy), Instruction(0xa4, "ldy", AddrMode.Zp, 3, ::iLdy),
Instruction(0xa5, "lda", AddrMode.Zp, 3, true, ::iLda), Instruction(0xa5, "lda", AddrMode.Zp, 3, ::iLda),
Instruction(0xa6, "ldx", AddrMode.Zp, 3, true, ::iLdx), Instruction(0xa6, "ldx", AddrMode.Zp, 3, ::iLdx),
Instruction(0xa7, "lax", AddrMode.Zp, 3, false, ::iLax), Instruction(0xa7, "lax", AddrMode.Zp, 3, ::iLax),
Instruction(0xa8, "tay", AddrMode.Imp, 2, true, ::iTay), Instruction(0xa8, "tay", AddrMode.Imp, 2, ::iTay),
Instruction(0xa9, "lda", AddrMode.Imm, 2, true, ::iLda), Instruction(0xa9, "lda", AddrMode.Imm, 2, ::iLda),
Instruction(0xaa, "tax", AddrMode.Imp, 2, true, ::iTax), Instruction(0xaa, "tax", AddrMode.Imp, 2, ::iTax),
Instruction(0xab, "lax", AddrMode.Imm, 2, false, ::iLax), Instruction(0xab, "lax", AddrMode.Imm, 2, ::iLax),
Instruction(0xac, "ldy", AddrMode.Abs, 4, true, ::iLdy), Instruction(0xac, "ldy", AddrMode.Abs, 4, ::iLdy),
Instruction(0xad, "lda", AddrMode.Abs, 4, true, ::iLda), Instruction(0xad, "lda", AddrMode.Abs, 4, ::iLda),
Instruction(0xae, "ldx", AddrMode.Abs, 4, true, ::iLdx), Instruction(0xae, "ldx", AddrMode.Abs, 4, ::iLdx),
Instruction(0xaf, "lax", AddrMode.Abs, 4, false, ::iLax), Instruction(0xaf, "lax", AddrMode.Abs, 4, ::iLax),
Instruction(0xb0, "bcs", AddrMode.Rel, 2, true, ::iBcs), Instruction(0xb0, "bcs", AddrMode.Rel, 2, ::iBcs),
Instruction(0xb1, "lda", AddrMode.IzY, 5, true, ::iLda), Instruction(0xb1, "lda", AddrMode.IzY, 5, ::iLda),
Instruction(0xb2, "???", AddrMode.Imp, 0, false, ::iInvalid), Instruction(0xb2, "???", AddrMode.Imp, 0, ::iInvalid),
Instruction(0xb3, "lax", AddrMode.IzY, 5, false, ::iLax), Instruction(0xb3, "lax", AddrMode.IzY, 5, ::iLax),
Instruction(0xb4, "ldy", AddrMode.ZpX, 4, true, ::iLdy), Instruction(0xb4, "ldy", AddrMode.ZpX, 4, ::iLdy),
Instruction(0xb5, "lda", AddrMode.ZpX, 4, true, ::iLda), Instruction(0xb5, "lda", AddrMode.ZpX, 4, ::iLda),
Instruction(0xb6, "ldx", AddrMode.ZpY, 4, true, ::iLdx), Instruction(0xb6, "ldx", AddrMode.ZpY, 4, ::iLdx),
Instruction(0xb7, "lax", AddrMode.ZpY, 4, false, ::iLax), Instruction(0xb7, "lax", AddrMode.ZpY, 4, ::iLax),
Instruction(0xb8, "clv", AddrMode.Imp, 2, true, ::iClv), Instruction(0xb8, "clv", AddrMode.Imp, 2, ::iClv),
Instruction(0xb9, "lda", AddrMode.AbsY, 4, true, ::iLda), Instruction(0xb9, "lda", AddrMode.AbsY, 4, ::iLda),
Instruction(0xba, "tsx", AddrMode.Imp, 2, true, ::iTsx), Instruction(0xba, "tsx", AddrMode.Imp, 2, ::iTsx),
Instruction(0xbb, "las", AddrMode.AbsY, 4, false, ::iLas), Instruction(0xbb, "las", AddrMode.AbsY, 4, ::iLas),
Instruction(0xbc, "ldy", AddrMode.AbsX, 4, true, ::iLdy), Instruction(0xbc, "ldy", AddrMode.AbsX, 4, ::iLdy),
Instruction(0xbd, "lda", AddrMode.AbsX, 4, true, ::iLda), Instruction(0xbd, "lda", AddrMode.AbsX, 4, ::iLda),
Instruction(0xbe, "ldx", AddrMode.AbsY, 4, true, ::iLdx), Instruction(0xbe, "ldx", AddrMode.AbsY, 4, ::iLdx),
Instruction(0xbf, "lax", AddrMode.AbsY, 4, false, ::iLax), Instruction(0xbf, "lax", AddrMode.AbsY, 4, ::iLax),
Instruction(0xc0, "cpy", AddrMode.Imm, 2, true, ::iCpy), Instruction(0xc0, "cpy", AddrMode.Imm, 2, ::iCpy),
Instruction(0xc1, "cmp", AddrMode.IzX, 6, true, ::iCmp), Instruction(0xc1, "cmp", AddrMode.IzX, 6, ::iCmp),
Instruction(0xc2, "nop", AddrMode.Imm, 2, false, ::iNop), Instruction(0xc2, "nop", AddrMode.Imm, 2, ::iNop),
Instruction(0xc3, "dcp", AddrMode.IzX, 8, false, ::iDcp), Instruction(0xc3, "dcp", AddrMode.IzX, 8, ::iDcp),
Instruction(0xc4, "cpy", AddrMode.Zp, 3, true, ::iCpy), Instruction(0xc4, "cpy", AddrMode.Zp, 3, ::iCpy),
Instruction(0xc5, "cmp", AddrMode.Zp, 3, true, ::iCmp), Instruction(0xc5, "cmp", AddrMode.Zp, 3, ::iCmp),
Instruction(0xc6, "dec", AddrMode.Zp, 5, true, ::iDec), Instruction(0xc6, "dec", AddrMode.Zp, 5, ::iDec),
Instruction(0xc7, "dcp", AddrMode.Zp, 5, false, ::iDcp), Instruction(0xc7, "dcp", AddrMode.Zp, 5, ::iDcp),
Instruction(0xc8, "iny", AddrMode.Imp, 2, true, ::iIny), Instruction(0xc8, "iny", AddrMode.Imp, 2, ::iIny),
Instruction(0xc9, "cmp", AddrMode.Imm, 2, true, ::iCmp), Instruction(0xc9, "cmp", AddrMode.Imm, 2, ::iCmp),
Instruction(0xca, "dex", AddrMode.Imp, 2, true, ::iDex), Instruction(0xca, "dex", AddrMode.Imp, 2, ::iDex),
Instruction(0xcb, "axs", AddrMode.Imm, 2, false, ::iAxs), Instruction(0xcb, "axs", AddrMode.Imm, 2, ::iAxs),
Instruction(0xcc, "cpy", AddrMode.Abs, 4, true, ::iCpy), Instruction(0xcc, "cpy", AddrMode.Abs, 4, ::iCpy),
Instruction(0xcd, "cmp", AddrMode.Abs, 4, true, ::iCmp), Instruction(0xcd, "cmp", AddrMode.Abs, 4, ::iCmp),
Instruction(0xce, "dec", AddrMode.Abs, 6, true, ::iDec), Instruction(0xce, "dec", AddrMode.Abs, 6, ::iDec),
Instruction(0xcf, "dcp", AddrMode.Abs, 6, false, ::iDcp), Instruction(0xcf, "dcp", AddrMode.Abs, 6, ::iDcp),
Instruction(0xd0, "bne", AddrMode.Rel, 2, true, ::iBne), Instruction(0xd0, "bne", AddrMode.Rel, 2, ::iBne),
Instruction(0xd1, "cmp", AddrMode.IzY, 5, true, ::iCmp), Instruction(0xd1, "cmp", AddrMode.IzY, 5, ::iCmp),
Instruction(0xd2, "???", AddrMode.Imp, 0, false, ::iInvalid), Instruction(0xd2, "???", AddrMode.Imp, 0, ::iInvalid),
Instruction(0xd3, "dcp", AddrMode.IzY, 8, false, ::iDcp), Instruction(0xd3, "dcp", AddrMode.IzY, 8, ::iDcp),
Instruction(0xd4, "nop", AddrMode.ZpX, 4, false, ::iNop), Instruction(0xd4, "nop", AddrMode.ZpX, 4, ::iNop),
Instruction(0xd5, "cmp", AddrMode.ZpX, 4, true, ::iCmp), Instruction(0xd5, "cmp", AddrMode.ZpX, 4, ::iCmp),
Instruction(0xd6, "dec", AddrMode.ZpX, 6, true, ::iDec), Instruction(0xd6, "dec", AddrMode.ZpX, 6, ::iDec),
Instruction(0xd7, "dcp", AddrMode.ZpX, 6, false, ::iDcp), Instruction(0xd7, "dcp", AddrMode.ZpX, 6, ::iDcp),
Instruction(0xd8, "cld", AddrMode.Imp, 2, true, ::iCld), Instruction(0xd8, "cld", AddrMode.Imp, 2, ::iCld),
Instruction(0xd9, "cmp", AddrMode.AbsY, 4, true, ::iCmp), Instruction(0xd9, "cmp", AddrMode.AbsY, 4, ::iCmp),
Instruction(0xda, "nop", AddrMode.Imp, 2, false, ::iNop), Instruction(0xda, "nop", AddrMode.Imp, 2, ::iNop),
Instruction(0xdb, "dcp", AddrMode.AbsY, 7, false, ::iDcp), Instruction(0xdb, "dcp", AddrMode.AbsY, 7, ::iDcp),
Instruction(0xdc, "nop", AddrMode.AbsX, 4, false, ::iNop), Instruction(0xdc, "nop", AddrMode.AbsX, 4, ::iNop),
Instruction(0xdd, "cmp", AddrMode.AbsX, 4, true, ::iCmp), Instruction(0xdd, "cmp", AddrMode.AbsX, 4, ::iCmp),
Instruction(0xde, "dec", AddrMode.AbsX, 7, true, ::iDec), Instruction(0xde, "dec", AddrMode.AbsX, 7, ::iDec),
Instruction(0xdf, "dcp", AddrMode.AbsX, 7, false, ::iDcp), Instruction(0xdf, "dcp", AddrMode.AbsX, 7, ::iDcp),
Instruction(0xe0, "cpx", AddrMode.Imm, 2, true, ::iCpx), Instruction(0xe0, "cpx", AddrMode.Imm, 2, ::iCpx),
Instruction(0xe1, "sbc", AddrMode.IzX, 6, true, ::iSbc), Instruction(0xe1, "sbc", AddrMode.IzX, 6, ::iSbc),
Instruction(0xe2, "nop", AddrMode.Imm, 2, false, ::iNop), Instruction(0xe2, "nop", AddrMode.Imm, 2, ::iNop),
Instruction(0xe3, "isc", AddrMode.IzX, 8, false, ::iIsc), Instruction(0xe3, "isc", AddrMode.IzX, 8, ::iIsc),
Instruction(0xe4, "cpx", AddrMode.Zp, 3, true, ::iCpx), Instruction(0xe4, "cpx", AddrMode.Zp, 3, ::iCpx),
Instruction(0xe5, "sbc", AddrMode.Zp, 3, true, ::iSbc), Instruction(0xe5, "sbc", AddrMode.Zp, 3, ::iSbc),
Instruction(0xe6, "inc", AddrMode.Zp, 5, true, ::iInc), Instruction(0xe6, "inc", AddrMode.Zp, 5, ::iInc),
Instruction(0xe7, "isc", AddrMode.Zp, 5, false, ::iIsc), Instruction(0xe7, "isc", AddrMode.Zp, 5, ::iIsc),
Instruction(0xe8, "inx", AddrMode.Imp, 2, true, ::iInx), Instruction(0xe8, "inx", AddrMode.Imp, 2, ::iInx),
Instruction(0xe9, "sbc", AddrMode.Imm, 2, true, ::iSbc), Instruction(0xe9, "sbc", AddrMode.Imm, 2, ::iSbc),
Instruction(0xea, "nop", AddrMode.Imp, 2, true, ::iNop), Instruction(0xea, "nop", AddrMode.Imp, 2, ::iNop),
Instruction(0xeb, "sbc", AddrMode.Imm, 2, false, ::iSbc), Instruction(0xeb, "sbc", AddrMode.Imm, 2, ::iSbc),
Instruction(0xec, "cpx", AddrMode.Abs, 4, true, ::iCpx), Instruction(0xec, "cpx", AddrMode.Abs, 4, ::iCpx),
Instruction(0xed, "sbc", AddrMode.Abs, 4, true, ::iSbc), Instruction(0xed, "sbc", AddrMode.Abs, 4, ::iSbc),
Instruction(0xee, "inc", AddrMode.Abs, 6, true, ::iInc), Instruction(0xee, "inc", AddrMode.Abs, 6, ::iInc),
Instruction(0xef, "isc", AddrMode.Abs, 6, true, ::iIsc), Instruction(0xef, "isc", AddrMode.Abs, 6, ::iIsc),
Instruction(0xf0, "beq", AddrMode.Rel, 2, true, ::iBeq), Instruction(0xf0, "beq", AddrMode.Rel, 2, ::iBeq),
Instruction(0xf1, "sbc", AddrMode.IzY, 5, true, ::iSbc), Instruction(0xf1, "sbc", AddrMode.IzY, 5, ::iSbc),
Instruction(0xf2, "???", AddrMode.Imp, 0, false, ::iInvalid), Instruction(0xf2, "???", AddrMode.Imp, 0, ::iInvalid),
Instruction(0xf3, "isc", AddrMode.IzY, 8, false, ::iIsc), Instruction(0xf3, "isc", AddrMode.IzY, 8, ::iIsc),
Instruction(0xf4, "nop", AddrMode.ZpX, 4, false, ::iNop), Instruction(0xf4, "nop", AddrMode.ZpX, 4, ::iNop),
Instruction(0xf5, "sbc", AddrMode.ZpX, 4, true, ::iSbc), Instruction(0xf5, "sbc", AddrMode.ZpX, 4, ::iSbc),
Instruction(0xf6, "inc", AddrMode.ZpX, 6, true, ::iInc), Instruction(0xf6, "inc", AddrMode.ZpX, 6, ::iInc),
Instruction(0xf7, "isc", AddrMode.ZpX, 6, false, ::iIsc), Instruction(0xf7, "isc", AddrMode.ZpX, 6, ::iIsc),
Instruction(0xf8, "sed", AddrMode.Imp, 2, true, ::iSed), Instruction(0xf8, "sed", AddrMode.Imp, 2, ::iSed),
Instruction(0xf9, "sbc", AddrMode.AbsY, 4, true, ::iSbc), Instruction(0xf9, "sbc", AddrMode.AbsY, 4, ::iSbc),
Instruction(0xfa, "nop", AddrMode.Imp, 2, false, ::iNop), Instruction(0xfa, "nop", AddrMode.Imp, 2, ::iNop),
Instruction(0xfb, "isc", AddrMode.AbsY, 7, false, ::iIsc), Instruction(0xfb, "isc", AddrMode.AbsY, 7, ::iIsc),
Instruction(0xfc, "nop", AddrMode.AbsX, 4, false, ::iNop), Instruction(0xfc, "nop", AddrMode.AbsX, 4, ::iNop),
Instruction(0xfd, "sbc", AddrMode.AbsX, 4, true, ::iSbc), Instruction(0xfd, "sbc", AddrMode.AbsX, 4, ::iSbc),
Instruction(0xfe, "inc", AddrMode.AbsX, 7, true, ::iInc), Instruction(0xfe, "inc", AddrMode.AbsX, 7, ::iInc),
Instruction(0xff, "isc", AddrMode.AbsX, 7, false, ::iIsc) Instruction(0xff, "isc", AddrMode.AbsX, 7, ::iIsc)
).toTypedArray() ).toTypedArray()

View File

@ -7,7 +7,7 @@ import sim65.Petscii
* First address = data byte (8 parallel bits) * First address = data byte (8 parallel bits)
* Second address = control byte (bit 0 high = write byte) * 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 private var dataByte: UByte = 0
init { init {
@ -34,6 +34,4 @@ class Parallel(startAddress: Address, endAddress: Address) : MemMappedComponent(
} }
} }
} }
override fun cloneMem(): Array<UByte> = listOf(dataByte, 0).toTypedArray()
} }

View File

@ -2,7 +2,7 @@ package sim65.components
import java.io.File 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) private val memory = ShortArray(endAddress-startAddress+1)
override operator fun get(address: Address): UByte = memory[address-startAddress] 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 memory[address-startAddress] = data
} }
override fun cloneMem(): Array<UByte> = memory.toTypedArray() override fun cloneContents(): Array<UByte> = memory.toTypedArray()
override fun clock() { } override fun clock() { }

View File

@ -1,15 +1,20 @@
package sim65.components package sim65.components
class Rom(startAddress: Address, endAddress: Address, data: Array<UByte>): MemMappedComponent(startAddress, endAddress) { class Rom(startAddress: Address, endAddress: Address, data: Array<UByte>? = null) : MemoryComponent(startAddress, endAddress) {
private val memory = ShortArray(data.size) { index -> data[index] } private val memory =
if (data == null)
ShortArray(endAddress - startAddress - 1)
else
ShortArray(data.size) { index -> data[index] }
init { init {
if (data != null)
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" }
} }
override operator fun get(address: Address): UByte = memory[address - startAddress] override operator fun get(address: Address): UByte = memory[address - startAddress]
override operator fun set(address: Address, data: UByte) {} override operator fun set(address: Address, data: UByte) {}
override fun cloneMem(): Array<UByte> = memory.toTypedArray() override fun cloneContents(): Array<UByte> = memory.toTypedArray()
override fun clock() {} override fun clock() {}
override fun reset() {} override fun reset() {}
} }

View File

@ -1,29 +1,28 @@
package sim65.components package sim65.components
class Timer(startAddress: Address, endAddress: Address): MemMappedComponent(startAddress, endAddress) { class Timer(startAddress: Address, endAddress: Address): MemMappedComponent(startAddress, endAddress) {
private var cycle: Long = 0 private var counter: Long = 0
init { init {
require(endAddress - startAddress + 1 == 4) { "timer needs exactly 4 memory bytes" } require(endAddress - startAddress + 1 == 4) { "timer needs exactly 4 memory bytes" }
} }
override fun clock() { override fun clock() {
cycle++ counter++
if (cycle > 0xffffffff) if (counter > 0xffffffff)
cycle = 0 counter = 0
println("TIMER CLOCK $counter")
} }
override fun reset() { override fun reset() {
cycle = 0 counter = 0
} }
override operator fun get(address: Address): UByte { 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) { 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<UByte> = TODO("clonemem timer")
} }

View File

@ -1,6 +1,10 @@
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
import org.junit.jupiter.api.fail
import sim65.components.Bus import sim65.components.Bus
import sim65.components.Cpu6502 import sim65.components.Cpu6502
import sim65.components.InstructionError
import sim65.components.Ram
import kotlin.system.measureNanoTime
import kotlin.test.assertEquals import kotlin.test.assertEquals
class Test6502CpuBasics { class Test6502CpuBasics {
@ -23,4 +27,75 @@ class Test6502CpuBasics {
assertEquals(0b00100100, cpu.Status.asByte()) 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")
}
}
} }

View File

@ -1,11 +1,14 @@
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
import org.junit.jupiter.api.fail
import sim65.components.Bus import sim65.components.Bus
import sim65.components.Cpu6502 import sim65.components.Cpu6502
import sim65.components.Ram import sim65.components.Ram
import kotlin.test.assertEquals import java.lang.Exception
class Test6502Functional { class Test6502Functional {
private class SuccessfulTestResult: Exception()
@Test @Test
fun testFunctional() { fun testFunctional() {
val cpu = Cpu6502(false) val cpu = Cpu6502(false)
@ -16,14 +19,25 @@ class Test6502Functional {
bus.add(ram) bus.add(ram)
cpu.reset() cpu.reset()
cpu.PC = 0x0400 cpu.PC = 0x0400
cpu.breakpoint(0x3469) { _, _ ->
// reaching this address means successful test result
if(cpu.currentOpcode==0x4c)
throw SuccessfulTestResult()
}
while(cpu.totalCycles < 50000000) { try {
while (cpu.totalCycles < 900000000) {
cpu.clock() cpu.clock()
} }
} catch (sx: SuccessfulTestResult) {
println("test successful")
return
}
cpu.printState() cpu.printState()
val d = cpu.disassemble(ram, cpu.PC-20, cpu.PC+20) val d = cpu.disassemble(ram, cpu.PC-20, cpu.PC+20)
println(d.joinToString ("\n")) println(d.joinToString ("\n"))
fail("test failed")
} }
} }

View File

@ -8,6 +8,7 @@ import sim65.components.InstructionError
import sim65.components.Ram import sim65.components.Ram
@TestInstance(TestInstance.Lifecycle.PER_METHOD) @TestInstance(TestInstance.Lifecycle.PER_METHOD)
@Disabled("this test suite takes a long time")
class Test6502TestSuite { class Test6502TestSuite {
val cpu: Cpu6502 = Cpu6502(stopOnBrk = false) val cpu: Cpu6502 = Cpu6502(stopOnBrk = false)