1
0
mirror of https://github.com/irmen/ksim65.git synced 2024-06-06 22:29:33 +00:00

implemented rest of the missing 65c02 instructions

This commit is contained in:
Irmen de Jong 2019-09-14 01:10:10 +02:00
parent ed9fd58d3b
commit b4d4d1b381
13 changed files with 314 additions and 135 deletions

View File

@ -7,7 +7,7 @@ package razorvine.ksim65.components
/**
* 6502 cpu simulation (the NMOS version) including the 'illegal' opcodes.
*/
open class Cpu6502(private val stopOnBrk: Boolean) : BusComponent() {
open class Cpu6502(private val stopOnBrk: Boolean = false) : BusComponent() {
var tracing: Boolean = false
var totalCycles: Long = 0
protected set
@ -118,9 +118,7 @@ open class Cpu6502(private val stopOnBrk: Boolean) : BusComponent() {
return if (msb == 0 && allowSingleByte)
hexB(lsb)
else
hexB(msb) + hexB(
lsb
)
hexB(msb) + hexB(lsb)
}
internal fun hexB(number: Short): String = hexB(number.toInt())
@ -144,9 +142,7 @@ open class Cpu6502(private val stopOnBrk: Boolean) : BusComponent() {
while (address <= (to - baseAddress)) {
val byte = memory[address]
var line = "\$${hexW(address)} ${hexB(
byte
)} "
var line = "\$${hexW(address)} ${hexB(byte)} "
address++
val opcode = instructions[byte.toInt()]
when (opcode.mode) {
@ -158,39 +154,42 @@ open class Cpu6502(private val stopOnBrk: Boolean) : BusComponent() {
}
AddrMode.Imm -> {
val value = memory[address++]
line += "${hexB(value)} $spacing2 ${opcode.mnemonic} #\$${hexB(
value
)}"
line += "${hexB(value)} $spacing2 ${opcode.mnemonic} #\$${hexB(value)}"
}
AddrMode.Zp -> {
val zpAddr = memory[address++]
line += "${hexB(zpAddr)} $spacing2 ${opcode.mnemonic} \$${hexB(
zpAddr
)}"
line += "${hexB(zpAddr)} $spacing2 ${opcode.mnemonic} \$${hexB(zpAddr)}"
}
AddrMode.Zpr -> {
// addressing mode used by the 65C02 only
TODO("disassemble ZPR addressing mode")
// addressing mode used by the 65C02, put here for convenience
val zpAddr = memory[address++]
val rel = memory[address++]
val target =
if (rel <= 0x7f)
address + rel
else
address - (256 - rel)
line += "${hexB(zpAddr)} ${hexB(rel)} $spacing3 ${opcode.mnemonic} \$${hexB(zpAddr)}, \$${hexW(target, true)}"
}
AddrMode.Izp -> {
// addressing mode used by the 65C02 only
TODO("disassemble IZP addressing mode")
// addressing mode used by the 65C02, put here for convenience
val zpAddr = memory[address++]
line += "${hexB(zpAddr)} $spacing2 ${opcode.mnemonic} \$(${hexB(zpAddr)})"
}
AddrMode.IaX -> {
// addressing mode used by the 65C02 only
TODO("disassemble IaX addressing mode")
// addressing mode used by the 65C02, put here for convenience
val lo = memory[address++]
val hi = memory[address++]
val absAddr = lo.toInt() or (hi.toInt() shl 8)
line += "${hexB(lo)} ${hexB(hi)} $spacing3 ${opcode.mnemonic} \$(${hexW(absAddr)},x)"
}
AddrMode.ZpX -> {
val zpAddr = memory[address++]
line += "${hexB(zpAddr)} $spacing2 ${opcode.mnemonic} \$${hexB(
zpAddr
)},x"
line += "${hexB(zpAddr)} $spacing2 ${opcode.mnemonic} \$${hexB(zpAddr)},x"
}
AddrMode.ZpY -> {
val zpAddr = memory[address++]
line += "${hexB(zpAddr)} $spacing2 ${opcode.mnemonic} \$${hexB(
zpAddr
)},y"
line += "${hexB(zpAddr)} $spacing2 ${opcode.mnemonic} \$${hexB(zpAddr)},y"
}
AddrMode.Rel -> {
val rel = memory[address++]
@ -199,56 +198,39 @@ open class Cpu6502(private val stopOnBrk: Boolean) : BusComponent() {
address + rel
else
address - (256 - rel)
line += "${hexB(rel)} $spacing2 ${opcode.mnemonic} \$${hexW(
target,
true
)}"
line += "${hexB(rel)} $spacing2 ${opcode.mnemonic} \$${hexW(target, true)}"
}
AddrMode.Abs -> {
val lo = memory[address++]
val hi = memory[address++]
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)}"
}
AddrMode.AbsX -> {
val lo = memory[address++]
val hi = memory[address++]
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"
}
AddrMode.AbsY -> {
val lo = memory[address++]
val hi = memory[address++]
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"
}
AddrMode.Ind -> {
val lo = memory[address++]
val hi = memory[address++]
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)})"
}
AddrMode.IzX -> {
val zpAddr = memory[address++]
line += "${hexB(zpAddr)} $spacing2 ${opcode.mnemonic} (\$${hexB(
zpAddr
)},x)"
line += "${hexB(zpAddr)} $spacing2 ${opcode.mnemonic} (\$${hexB(zpAddr)},x)"
}
AddrMode.IzY -> {
val zpAddr = memory[address++]
line += "${hexB(zpAddr)} $spacing2 ${opcode.mnemonic} (\$${hexB(
zpAddr
)}),y"
line += "${hexB(zpAddr)} $spacing2 ${opcode.mnemonic} (\$${hexB(zpAddr)}),y"
}
}
result.add(line)
@ -300,11 +282,7 @@ open class Cpu6502(private val stopOnBrk: Boolean) : BusComponent() {
}
if (stopOnBrk && currentOpcode == 0) {
throw InstructionError(
"stopped on BRK instruction at ${hexW(
PC
)}"
)
throw InstructionError("stopped on BRK instruction at ${hexW(PC)}")
}
}
@ -1472,9 +1450,7 @@ open class Cpu6502(private val stopOnBrk: Boolean) : BusComponent() {
// invalid instruction (JAM / KIL)
private fun iInvalid() {
throw InstructionError(
"invalid instruction encountered: opcode=${hexB(
currentOpcode
)} instr=${currentInstruction.mnemonic}"
"invalid instruction encountered: opcode=${hexB(currentOpcode)} instr=${currentInstruction.mnemonic}"
)
}
}

View File

@ -3,7 +3,7 @@ package razorvine.ksim65.components
/**
* 65C02 cpu simulation (the CMOS version of the 6502).
*/
class Cpu65C02(stopOnBrk: Boolean) : Cpu6502(stopOnBrk) {
class Cpu65C02(stopOnBrk: Boolean = false) : Cpu6502(stopOnBrk) {
enum class Wait {
Normal,
@ -53,6 +53,9 @@ class Cpu65C02(stopOnBrk: Boolean) : Cpu6502(stopOnBrk) {
}
}
// branch-relative address fetched by the ZpR addressing mode
private var fetchedAddressZpr: Address = 0
override fun applyAddressingMode(addrMode: AddrMode) {
when (addrMode) {
AddrMode.Imp, AddrMode.Acc, AddrMode.Imm,
@ -62,12 +65,23 @@ class Cpu65C02(stopOnBrk: Boolean) : Cpu6502(stopOnBrk) {
super.applyAddressingMode(addrMode)
}
AddrMode.Ind -> {
// not able to fetch an address which crosses the page boundary (6502, fixed in 65C02)
TODO("IND addrmode fixed for 65c02")
var lo = readPc()
var hi = readPc()
fetchedAddress = lo or (hi shl 8)
// 65c02 doesn't have the page bug of the 6502
lo = read(fetchedAddress)
hi = read(fetchedAddress + 1)
fetchedAddress = lo or (hi shl 8)
}
AddrMode.Zpr -> {
// addressing mode used by the 65C02 only
TODO("ZPR addressing mode")
// combination of zp addresssing + relative branch addressing
fetchedAddress = readPc()
val relative = readPc()
fetchedAddressZpr = if (relative >= 0x80) {
PC - (256 - relative) and 0xffff
} else
PC + relative and 0xffff
}
AddrMode.Izp -> {
// addressing mode used by the 65C02 only
@ -463,7 +477,7 @@ class Cpu65C02(stopOnBrk: Boolean) : Cpu6502(stopOnBrk) {
/* 69 */ Instruction("adc", AddrMode.Imm, 2),
/* 6a */ Instruction("ror", AddrMode.Acc, 2),
/* 6b */ Instruction("nop", AddrMode.Imp, 1),
/* 6c */ Instruction("jmp", AddrMode.Ind, 5),
/* 6c */ Instruction("jmp", AddrMode.Ind, 6),
/* 6d */ Instruction("adc", AddrMode.Abs, 4),
/* 6e */ Instruction("ror", AddrMode.Abs, 6),
/* 6f */ Instruction("bbr6", AddrMode.Zpr, 5),
@ -632,21 +646,19 @@ class Cpu65C02(stopOnBrk: Boolean) : Cpu6502(stopOnBrk) {
pendingInterrupt = null
}
// TODO some opcodes gained a new addressing mode that we have to deal with
override fun iDec() {
if(currentInstruction.mode==AddrMode.Acc) {
TODO("dec A")
// Status.Z = data == 0
// Status.N = (data and 0b10000000) != 0
A = (A - 1) and 0xff
Status.Z = A == 0
Status.N = (A and 0b10000000) != 0
} else super.iDec()
}
override fun iInc() {
if(currentInstruction.mode==AddrMode.Acc) {
TODO("inc A")
// Status.Z = data == 0
// Status.N = (data and 0b10000000) != 0
A = (A + 1) and 0xff
Status.Z = A == 0
Status.N = (A and 0b10000000) != 0
} else super.iInc()
}
@ -656,11 +668,15 @@ class Cpu65C02(stopOnBrk: Boolean) : Cpu6502(stopOnBrk) {
}
private fun iTrb() {
TODO("trb")
val m = read(fetchedAddress)
Status.Z = m and A ==0
write(fetchedAddress, m and A.inv())
}
private fun iTsb() {
TODO("tsb")
val m = read(fetchedAddress)
Status.Z = m and A ==0
write(fetchedAddress, m or A)
}
private fun iStz() {
@ -696,133 +712,178 @@ class Cpu65C02(stopOnBrk: Boolean) : Cpu6502(stopOnBrk) {
}
private fun iBbr0() {
TODO("brr0")
val x = hexB(2)
val y = hexW(2)
val z = hexB(3.toShort())
val data = read(fetchedAddress)
if(data and 1 == 0)
PC = fetchedAddressZpr
}
private fun iBbr1() {
TODO("brr1")
val data = read(fetchedAddress)
if(data and 2 == 0)
PC = fetchedAddressZpr
}
private fun iBbr2() {
TODO("brr2")
val data = read(fetchedAddress)
if(data and 4 == 0)
PC = fetchedAddressZpr
}
private fun iBbr3() {
TODO("brr3")
val data = read(fetchedAddress)
if(data and 8 == 0)
PC = fetchedAddressZpr
}
private fun iBbr4() {
TODO("brr4")
val data = read(fetchedAddress)
if(data and 16 == 0)
PC = fetchedAddressZpr
}
private fun iBbr5() {
TODO("brr5")
val data = read(fetchedAddress)
if(data and 32 == 0)
PC = fetchedAddressZpr
}
private fun iBbr6() {
TODO("brr6")
val data = read(fetchedAddress)
if(data and 64 == 0)
PC = fetchedAddressZpr
}
private fun iBbr7() {
TODO("brr7")
val data = read(fetchedAddress)
if(data and 128 == 0)
PC = fetchedAddressZpr
}
private fun iBbs0() {
TODO("bbs0")
val data = read(fetchedAddress)
if(data and 1 != 0)
PC = fetchedAddressZpr
}
private fun iBbs1() {
TODO("bbs1")
val data = read(fetchedAddress)
if(data and 2 != 0)
PC = fetchedAddressZpr
}
private fun iBbs2() {
TODO("bbs2")
val data = read(fetchedAddress)
if(data and 4 != 0)
PC = fetchedAddressZpr
}
private fun iBbs3() {
TODO("bbs3")
val data = read(fetchedAddress)
if(data and 8 != 0)
PC = fetchedAddressZpr
}
private fun iBbs4() {
TODO("bbs4")
val data = read(fetchedAddress)
if(data and 16 != 0)
PC = fetchedAddressZpr
}
private fun iBbs5() {
TODO("bbs5")
val data = read(fetchedAddress)
if(data and 32 != 0)
PC = fetchedAddressZpr
}
private fun iBbs6() {
TODO("bbs6")
val data = read(fetchedAddress)
if(data and 64 != 0)
PC = fetchedAddressZpr
}
private fun iBbs7() {
TODO("bbs7")
val data = read(fetchedAddress)
if(data and 128 != 0)
PC = fetchedAddressZpr
}
private fun iSmb0() {
TODO("smb0")
val data = read(fetchedAddress)
write(fetchedAddress, data or 1)
}
private fun iSmb1() {
TODO("smb1")
val data = read(fetchedAddress)
write(fetchedAddress, data or 2)
}
private fun iSmb2() {
TODO("smb2")
val data = read(fetchedAddress)
write(fetchedAddress, data or 4)
}
private fun iSmb3() {
TODO("smb3")
val data = read(fetchedAddress)
write(fetchedAddress, data or 8)
}
private fun iSmb4() {
TODO("smb4")
val data = read(fetchedAddress)
write(fetchedAddress, data or 16)
}
private fun iSmb5() {
TODO("smb5")
val data = read(fetchedAddress)
write(fetchedAddress, data or 32)
}
private fun iSmb6() {
TODO("smb6")
val data = read(fetchedAddress)
write(fetchedAddress, data or 64)
}
private fun iSmb7() {
TODO("smb7")
val data = read(fetchedAddress)
write(fetchedAddress, data or 128)
}
private fun iRmb0() {
TODO("rmb0")
val data = read(fetchedAddress)
write(fetchedAddress, data and 0b11111110)
}
private fun iRmb1() {
TODO("rmb1")
val data = read(fetchedAddress)
write(fetchedAddress, data and 0b11111101)
}
private fun iRmb2() {
TODO("rmb2")
val data = read(fetchedAddress)
write(fetchedAddress, data and 0b11111011)
}
private fun iRmb3() {
TODO("rmb3")
val data = read(fetchedAddress)
write(fetchedAddress, data and 0b11110111)
}
private fun iRmb4() {
TODO("rmb4")
val data = read(fetchedAddress)
write(fetchedAddress, data and 0b11101111)
}
private fun iRmb5() {
TODO("rmb5")
val data = read(fetchedAddress)
write(fetchedAddress, data and 0b11011111)
}
private fun iRmb6() {
TODO("rmb6")
val data = read(fetchedAddress)
write(fetchedAddress, data and 0b10111111)
}
private fun iRmb7() {
TODO("rmb7")
val data = read(fetchedAddress)
write(fetchedAddress, data and 0b01111111)
}
}

View File

@ -1,6 +1,7 @@
package razorvine.ksim65.components
import java.io.File
import java.net.URL
class Ram(startAddress: Address, endAddress: Address) : MemoryComponent(startAddress, endAddress) {
private val memory = ShortArray(endAddress - startAddress + 1)
@ -44,12 +45,23 @@ class Ram(startAddress: Address, endAddress: Address) : MemoryComponent(startAdd
*/
fun load(filename: String, address: Address) {
val bytes = File(filename).readBytes()
bytes.forEachIndexed { index, byte ->
load(bytes, address)
}
fun load(source: URL, address: Address) {
val bytes = source.readBytes()
load(bytes, address)
}
fun load(data: Array<UByte>, address: Address) =
data.forEachIndexed { index, byte -> memory[address + index] = byte }
fun load(data: ByteArray, address: Address) =
data.forEachIndexed { index, byte ->
memory[address + index] =
if (byte >= 0)
byte.toShort()
else
(256 + byte).toShort()
}
}
}

View File

@ -65,7 +65,8 @@ class Test6502CpuBasics {
val ram = Ram(0, 0xffff)
ram[Cpu6502.RESET_vector] = 0x00
ram[Cpu6502.RESET_vector +1] = 0x10
ram.load("src/test/kotlin/testfiles/bcdtest.bin", 0x1000)
val bytes = javaClass.getResource("bcdtest.bin")!!
ram.load(bytes, 0x1000)
bus.add(ram)
bus.reset()

View File

@ -7,7 +7,7 @@ import kotlin.test.*
@TestInstance(TestInstance.Lifecycle.PER_METHOD)
@Disabled("this test suite takes a long time")
//@Disabled("this test suite takes a long time")
class Test6502TestSuite {
val cpu: Cpu6502 = Cpu6502(stopOnBrk = false)
@ -46,7 +46,7 @@ class Test6502TestSuite {
}
private fun runTest(testprogram: String) {
ram.loadPrg("test/6502testsuite/$testprogram")
ram.loadPrg("src/test/kotlin/6502testsuite/$testprogram")
bus.reset()
cpu.SP = 0xfd
cpu.Status.fromByte(0b00100100)

View File

@ -797,7 +797,7 @@ class Test65C02 : TestCommon6502() {
memory[0x0043] = 0b11111111
// $0000 RMB0 $43
writeMem(memory, 0x0000, listOf(0x07, 0x43))
val expected = 0b01010101
val expected = 0b01110101
mpu.Status.fromByte(expected)
mpu.step()
assertEquals(expected, mpu.Status.asByte().toInt())
@ -822,7 +822,7 @@ class Test65C02 : TestCommon6502() {
memory[0x0043] = 0b11111111
// $0000 RMB1 $43
writeMem(memory, 0x0000, listOf(0x17, 0x43))
val expected = 0b01010101
val expected = 0b01110101
mpu.Status.fromByte(expected)
mpu.step()
assertEquals(expected, mpu.Status.asByte().toInt())
@ -848,7 +848,7 @@ class Test65C02 : TestCommon6502() {
memory[0x0043] = 0b11111111
// $0000 RMB2 $43
writeMem(memory, 0x0000, listOf(0x27, 0x43))
val expected = 0b01010101
val expected = 0b01110101
mpu.Status.fromByte(expected)
mpu.step()
assertEquals(expected, mpu.Status.asByte().toInt())
@ -873,7 +873,7 @@ class Test65C02 : TestCommon6502() {
memory[0x0043] = 0b11111111
// $0000 RMB3 $43
writeMem(memory, 0x0000, listOf(0x37, 0x43))
val expected = 0b01010101
val expected = 0b01110101
mpu.Status.fromByte(expected)
mpu.step()
assertEquals(expected, mpu.Status.asByte().toInt())
@ -898,7 +898,7 @@ class Test65C02 : TestCommon6502() {
memory[0x0043] = 0b11111111
// $0000 RMB4 $43
writeMem(memory, 0x0000, listOf(0x47, 0x43))
val expected = 0b01010101
val expected = 0b01110101
mpu.Status.fromByte(expected)
mpu.step()
assertEquals(expected, mpu.Status.asByte().toInt())
@ -923,7 +923,7 @@ class Test65C02 : TestCommon6502() {
memory[0x0043] = 0b11111111
// $0000 RMB5 $43
writeMem(memory, 0x0000, listOf(0x57, 0x43))
val expected = 0b01010101
val expected = 0b01110101
mpu.Status.fromByte(expected)
mpu.step()
assertEquals(expected, mpu.Status.asByte().toInt())
@ -948,7 +948,7 @@ class Test65C02 : TestCommon6502() {
memory[0x0043] = 0b11111111
// $0000 RMB6 $43
writeMem(memory, 0x0000, listOf(0x67, 0x43))
val expected = 0b01010101
val expected = 0b01110101
mpu.Status.fromByte(expected)
mpu.step()
assertEquals(expected, mpu.Status.asByte().toInt())
@ -974,7 +974,7 @@ class Test65C02 : TestCommon6502() {
memory[0x0043] = 0b11111111
// $0000 RMB7 $43
writeMem(memory, 0x0000, listOf(0x77, 0x43))
val expected = 0b01010101
val expected = 0b01110101
mpu.Status.fromByte(expected)
mpu.step()
assertEquals(expected, mpu.Status.asByte().toInt())
@ -1027,7 +1027,7 @@ class Test65C02 : TestCommon6502() {
writeMem(memory, 0x0000, listOf(0x87, 0x43))
mpu.step()
assertEquals(0x0002, mpu.PC)
assertEquals(5, mpu.totalCycles.toInt())
assertEquals(5 + Cpu65C02.resetCycles, mpu.totalCycles.toInt())
val expected = 0b00000001
assertEquals(expected, memory[0x0043].toInt())
}
@ -1037,7 +1037,7 @@ class Test65C02 : TestCommon6502() {
memory[0x0043] = 0b00000000
// $0000 SMB0 $43
writeMem(memory, 0x0000, listOf(0x87, 0x43))
val expected = 0b11001100
val expected = 0b11101100
mpu.Status.fromByte(expected)
mpu.step()
assertEquals(expected, mpu.Status.asByte().toInt())
@ -1062,7 +1062,7 @@ class Test65C02 : TestCommon6502() {
memory[0x0043] = 0b00000000
// $0000 SMB1 $43
writeMem(memory, 0x0000, listOf(0x97, 0x43))
val expected = 0b11001100
val expected = 0b11101100
mpu.Status.fromByte(expected)
mpu.step()
assertEquals(expected, mpu.Status.asByte().toInt())
@ -1088,7 +1088,7 @@ class Test65C02 : TestCommon6502() {
memory[0x0043] = 0b00000000
// $0000 SMB2 $43
writeMem(memory, 0x0000, listOf(0xA7, 0x43))
val expected = 0b11001100
val expected = 0b11101100
mpu.Status.fromByte(expected)
mpu.step()
assertEquals(expected, mpu.Status.asByte().toInt())
@ -1114,7 +1114,7 @@ class Test65C02 : TestCommon6502() {
memory[0x0043] = 0b00000000
// $0000 SMB3 $43
writeMem(memory, 0x0000, listOf(0xB7, 0x43))
val expected = 0b11001100
val expected = 0b11101100
mpu.Status.fromByte(expected)
mpu.step()
assertEquals(expected, mpu.Status.asByte().toInt())
@ -1140,7 +1140,7 @@ class Test65C02 : TestCommon6502() {
memory[0x0043] = 0b00000000
// $0000 SMB4 $43
writeMem(memory, 0x0000, listOf(0xC7, 0x43))
val expected = 0b11001100
val expected = 0b11101100
mpu.Status.fromByte(expected)
mpu.step()
assertEquals(expected, mpu.Status.asByte().toInt())
@ -1165,7 +1165,7 @@ class Test65C02 : TestCommon6502() {
memory[0x0043] = 0b00000000
// $0000 SMB5 $43
writeMem(memory, 0x0000, listOf(0xD7, 0x43))
val expected = 0b11001100
val expected = 0b11101100
mpu.Status.fromByte(expected)
mpu.step()
assertEquals(expected, mpu.Status.asByte().toInt())
@ -1190,7 +1190,7 @@ class Test65C02 : TestCommon6502() {
memory[0x0043] = 0b00000000
// $0000 SMB6 $43
writeMem(memory, 0x0000, listOf(0xE7, 0x43))
val expected = 0b11001100
val expected = 0b11101100
mpu.Status.fromByte(expected)
mpu.step()
assertEquals(expected, mpu.Status.asByte().toInt())
@ -1215,7 +1215,7 @@ class Test65C02 : TestCommon6502() {
memory[0x0043] = 0b00000000
// $0000 SMB7 $43
writeMem(memory, 0x0000, listOf(0xF7, 0x43))
val expected = 0b11001100
val expected = 0b11101100
mpu.Status.fromByte(expected)
mpu.step()
assertEquals(expected, mpu.Status.asByte().toInt())
@ -1518,7 +1518,7 @@ class Test65C02 : TestCommon6502() {
writeMem(memory, 0x0000, listOf(0x80, 0x10))
mpu.step()
assertEquals(0x12, mpu.PC)
assertEquals(2 + Cpu65C02.resetCycles, mpu.totalCycles.toInt())
assertEquals(3 + Cpu65C02.resetCycles, mpu.totalCycles.toInt())
}
@Test
@ -1545,4 +1545,63 @@ class Test65C02 : TestCommon6502() {
assertEquals(0x0205, mpu.PC)
assertEquals(3 + Cpu65C02.resetCycles, mpu.totalCycles.toInt())
}
// BBR and BBS
@Test
fun test_bbr_all_set_doesnt_branch() {
mpu as Cpu65C02
mpu.PC = 0
memory[0xfe] = 0xff
writeMem(memory, 0, listOf(0x0f, 0xfe, 0x40,
0x1f, 0xfe, 0x40,
0x2f, 0xfe, 0x40,
0x3f, 0xfe, 0x40,
0x4f, 0xfe, 0x40,
0x5f, 0xfe, 0x40,
0x6f, 0xfe, 0x40,
0x7f, 0xfe, 0x40,
0xea))
repeat(8) { mpu.step() }
assertNotEquals(0x0040, mpu.PC)
assertEquals(0xea, memory[mpu.PC])
}
@Test
fun test_bbr_branches() {
mpu as Cpu65C02
mpu.PC = 0
memory[0xfe] = 0b10111111 // bit 6 cleared
writeMem(memory, 0, listOf(0x6f, 0xfe, 0x40)) // BBR6 $fe, $0040
mpu.step()
assertEquals(0x0043, mpu.PC)
}
@Test
fun test_bbs_all_clear_doesnt_branch() {
mpu as Cpu65C02
mpu.PC = 0
memory[0xfe] = 0
writeMem(memory, 0, listOf(0x8f, 0xfe, 0x40,
0x9f, 0xfe, 0x40,
0xaf, 0xfe, 0x40,
0xbf, 0xfe, 0x40,
0xcf, 0xfe, 0x40,
0xdf, 0xfe, 0x40,
0xef, 0xfe, 0x40,
0xff, 0xfe, 0x40,
0xea))
repeat(8) { mpu.step() }
assertNotEquals(0x0040, mpu.PC)
assertEquals(0xea, memory[mpu.PC])
}
@Test
fun test_bbs_branches() {
mpu as Cpu65C02
mpu.PC = 0
memory[0xfe] = 0b01000000 // bit 6 set
writeMem(memory, 0, listOf(0xef, 0xfe, 0x40)) // BBS6 $fe, $0040
mpu.step()
assertEquals(0x0043, mpu.PC)
}
}

View File

@ -1,21 +1,22 @@
import razorvine.ksim65.components.Cpu6502
import razorvine.ksim65.components.Cpu65C02
import razorvine.ksim65.components.Ram
import java.io.File
import kotlin.test.*
class TestDisassembler {
@Test
fun testDisassembleAllOpcodes() {
val cpu = Cpu6502(true)
fun testDisassembleAll6502Opcodes() {
val cpu = Cpu6502()
val memory = Ram(0, 0xffff)
memory.load("src/test/kotlin/testfiles/disassem_instr_test.prg", 0x1000 - 2)
val binfile = javaClass.classLoader.getResourceAsStream("disassem_instr_test.prg")?.readAllBytes()!!
memory.load(binfile, 0x1000-2)
val result = cpu.disassemble(memory, 0x1000, 0x1221)
assertEquals(256, result.size)
assertEquals("\$1000 69 01 adc #\$01", result[0])
val reference = File("src/test/kotlin/testfiles/disassem_ref_output.txt").readLines()
val reference = javaClass.classLoader.getResource("disassem_ref_output.txt")?.readText()!!.trim().lines()
assertEquals(256, reference.size)
for (line in result.zip(reference)) {
if (line.first != line.second) {
@ -24,6 +25,75 @@ class TestDisassembler {
}
}
@Test
fun testDisassembleRockwell65C02() {
val cpu = Cpu65C02()
val memory = Ram(0, 0x1000)
val source = javaClass.classLoader.getResource("disassem_r65c02.bin")!!
memory.load(source, 0)
val resultLines = cpu.disassemble(memory, 0x0000, 0x0050)
val result = resultLines.joinToString("\n")
assertEquals("""${'$'}0000 07 12 rmb0 ${'$'}12
${'$'}0002 17 12 rmb1 ${'$'}12
${'$'}0004 27 12 rmb2 ${'$'}12
${'$'}0006 37 12 rmb3 ${'$'}12
${'$'}0008 47 12 rmb4 ${'$'}12
${'$'}000a 57 12 rmb5 ${'$'}12
${'$'}000c 67 12 rmb6 ${'$'}12
${'$'}000e 77 12 rmb7 ${'$'}12
${'$'}0010 87 12 smb0 ${'$'}12
${'$'}0012 97 12 smb1 ${'$'}12
${'$'}0014 a7 12 smb2 ${'$'}12
${'$'}0016 b7 12 smb3 ${'$'}12
${'$'}0018 c7 12 smb4 ${'$'}12
${'$'}001a d7 12 smb5 ${'$'}12
${'$'}001c e7 12 smb6 ${'$'}12
${'$'}001e f7 12 smb7 ${'$'}12
${'$'}0020 0f 12 2a bbr0 ${'$'}12, ${'$'}4d
${'$'}0023 1f 12 27 bbr1 ${'$'}12, ${'$'}4d
${'$'}0026 2f 12 24 bbr2 ${'$'}12, ${'$'}4d
${'$'}0029 3f 12 21 bbr3 ${'$'}12, ${'$'}4d
${'$'}002c 4f 12 1e bbr4 ${'$'}12, ${'$'}4d
${'$'}002f 5f 12 1b bbr5 ${'$'}12, ${'$'}4d
${'$'}0032 6f 12 18 bbr6 ${'$'}12, ${'$'}4d
${'$'}0035 8f 12 15 bbs0 ${'$'}12, ${'$'}4d
${'$'}0038 9f 12 12 bbs1 ${'$'}12, ${'$'}4d
${'$'}003b af 12 0f bbs2 ${'$'}12, ${'$'}4d
${'$'}003e bf 12 0c bbs3 ${'$'}12, ${'$'}4d
${'$'}0041 cf 12 09 bbs4 ${'$'}12, ${'$'}4d
${'$'}0044 df 12 06 bbs5 ${'$'}12, ${'$'}4d
${'$'}0047 ef 12 03 bbs6 ${'$'}12, ${'$'}4d
${'$'}004a ff 12 00 bbs7 ${'$'}12, ${'$'}4d
${'$'}004d 00 brk
${'$'}004e 00 brk
${'$'}004f 00 brk
${'$'}0050 00 brk""", result)
}
@Test
fun testDisassembleWDC65C02() {
val cpu = Cpu65C02()
val memory = Ram(0, 0x1000)
val source = javaClass.classLoader.getResource("disassem_wdc65c02.bin")!!
memory.load(source, 0)
val resultLines = cpu.disassemble(memory, 0x0000, 0x0015)
val result = resultLines.joinToString("\n")
assertEquals("""${'$'}0000 cb wai
${'$'}0001 db stp
${'$'}0002 3a dec a
${'$'}0003 1a inc a
${'$'}0004 64 12 stz ${'$'}12
${'$'}0006 14 12 trb ${'$'}12
${'$'}0008 04 12 tsb ${'$'}12
${'$'}000a 72 12 adc ${'$'}(12)
${'$'}000c b2 12 lda ${'$'}(12)
${'$'}000e 92 12 sta ${'$'}(12)
${'$'}0010 7c 00 20 jmp ${'$'}(2000,x)
${'$'}0013 00 brk
${'$'}0014 00 brk
${'$'}0015 00 brk""", result)
}
}

Binary file not shown.

Binary file not shown.

Binary file not shown.