fixed all instructions except BCD arithmetic

This commit is contained in:
Irmen de Jong 2019-09-05 01:26:01 +02:00
parent 42f8e98cab
commit 900c2aea23
4 changed files with 135 additions and 155 deletions

View File

@ -17,8 +17,7 @@ interface ICpu {
} }
// TODO: add additional cycles to certain instructions and addressing modes // TODO: add additional cycles to certain instructions and addressing modes
// TODO: test all opcodes and fix bugs // TODO: fix sbc and adc with BCD arithmetic.
class Cpu6502(private val illegalInstrsAllowed: Boolean) : BusComponent(), ICpu { class Cpu6502(private val illegalInstrsAllowed: Boolean) : BusComponent(), ICpu {
override var tracing: Boolean = false override var tracing: Boolean = false
@ -29,6 +28,7 @@ class Cpu6502(private val illegalInstrsAllowed: Boolean) : BusComponent(), ICpu
const val NMI_vector = 0xfffa const val NMI_vector = 0xfffa
const val RESET_vector = 0xfffc const val RESET_vector = 0xfffc
const val IRQ_vector = 0xfffe const val IRQ_vector = 0xfffe
const val resetCycles = 8
fun hexW(number: Address, allowSingleByte: Boolean = false): String { fun hexW(number: Address, allowSingleByte: Boolean = false): String {
val msb = number ushr 8 val msb = number ushr 8
@ -241,12 +241,12 @@ class Cpu6502(private val illegalInstrsAllowed: Boolean) : BusComponent(), ICpu
Y = 0 Y = 0
Status.C = false Status.C = false
Status.Z = false Status.Z = false
Status.I = false Status.I = true
Status.D = false Status.D = false
Status.B = false Status.B = false
Status.V = false Status.V = false
Status.N = false Status.N = false
instrCycles = 8 instrCycles = resetCycles // a reset takes time as well
currentOpcode = 0 currentOpcode = 0
currentInstruction = opcodes[0] currentInstruction = opcodes[0]
waiting = false waiting = false
@ -276,8 +276,9 @@ class Cpu6502(private val illegalInstrsAllowed: Boolean) : BusComponent(), ICpu
override fun step() { override fun step() {
// step a whole instruction // step a whole instruction
while(instrCycles>0) clock() // instruction subcycles while(instrCycles>0) clock() // remaining instruction subcycles from the previous instruction
clock() // the actual instruction execution cycle clock() // the actual instruction execution cycle
while(instrCycles>0) clock() // instruction subcycles
} }
fun printState() { fun printState() {
@ -324,7 +325,7 @@ class Cpu6502(private val illegalInstrsAllowed: Boolean) : BusComponent(), ICpu
} }
private fun amRel() { private fun amRel() {
val relative = readPc().toByte() val relative = readPc()
fetchedAddress = if (relative >= 0x80) fetchedAddress = if (relative >= 0x80)
PC - (256 - relative) PC - (256 - relative)
else else
@ -368,9 +369,9 @@ class Cpu6502(private val illegalInstrsAllowed: Boolean) : BusComponent(), ICpu
private fun amIzx() { private fun amIzx() {
// note: not able to fetch an adress which crosses the page boundary // note: not able to fetch an adress which crosses the page boundary
fetchedAddress = readPc() + X fetchedAddress = readPc()
val lo = read(fetchedAddress) val lo = read((fetchedAddress + X) and 255)
val hi = read((fetchedAddress + 1) and 255) val hi = read((fetchedAddress + X + 1) and 255)
fetchedAddress = lo or (hi shl 8) fetchedAddress = lo or (hi shl 8)
} }
@ -379,7 +380,16 @@ class Cpu6502(private val illegalInstrsAllowed: Boolean) : BusComponent(), ICpu
fetchedAddress = readPc() fetchedAddress = readPc()
val lo = read(fetchedAddress) val lo = read(fetchedAddress)
val hi = read((fetchedAddress + 1) and 255) val hi = read((fetchedAddress + 1) and 255)
fetchedAddress = Y + (lo or (hi shl 8)) fetchedAddress = (Y + lo or (hi shl 8)) and 65535
}
private fun getFetched(): Int {
return if(currentInstruction.mode==AddrMode.Imm ||
currentInstruction.mode==AddrMode.Acc ||
currentInstruction.mode==AddrMode.Imp)
fetchedData
else
read(fetchedAddress)
} }
private fun readPc(): Int = bus.read(PC++).toInt() private fun readPc(): Int = bus.read(PC++).toInt()
@ -408,7 +418,7 @@ class Cpu6502(private val illegalInstrsAllowed: Boolean) : BusComponent(), ICpu
private fun popStackAddr(): Address { private fun popStackAddr(): Address {
val lo = popStack() val lo = popStack()
val hi = popStack() val hi = popStack()
return lo + hi ushr 8 return lo or (hi shl 8)
} }
private fun read(address: Address): Int = bus.read(address).toInt() private fun read(address: Address): Int = bus.read(address).toInt()
@ -683,11 +693,7 @@ class Cpu6502(private val illegalInstrsAllowed: Boolean) : BusComponent(), ICpu
// official instructions // official instructions
private fun iAdc() { private fun iAdc() {
val operand = if (currentInstruction.mode == AddrMode.Imm) { val operand = getFetched()
fetchedData
} else {
read(fetchedAddress)
}
if (Status.D) { if (Status.D) {
// BCD add // BCD add
var lo = (A and 0x0f) + (operand and 0x0f) + if (Status.C) 1 else 0 var lo = (A and 0x0f) + (operand and 0x0f) + if (Status.C) 1 else 0
@ -712,24 +718,24 @@ class Cpu6502(private val illegalInstrsAllowed: Boolean) : BusComponent(), ICpu
} }
private fun iAnd() { private fun iAnd() {
A = A and fetchedData A = A and getFetched()
Status.Z = A == 0 Status.Z = A == 0
Status.N = (A and 0b10000000) != 0 Status.N = (A and 0b10000000) != 0
} }
private fun iAsl() { private fun iAsl() {
if (currentInstruction.mode == AddrMode.Acc) { if (currentInstruction.mode == AddrMode.Acc) {
Status.C = (A and 0b10000000) == 1 Status.C = (A and 0b10000000) != 0
A = (A shl 1) and 255 A = (A shl 1) and 255
Status.Z = A == 0 Status.Z = A == 0
Status.N = (A and 0b10000000) == 1 Status.N = (A and 0b10000000) != 0
} else { } else {
val data = read(fetchedAddress) val data = read(fetchedAddress)
Status.C = (data and 0b10000000) == 1 Status.C = (data and 0b10000000) != 0
val shifted = (data shl 1) and 255 val shifted = (data shl 1) and 255
write(fetchedAddress, shifted) write(fetchedAddress, shifted)
Status.Z = shifted == 0 Status.Z = shifted == 0
Status.N = (shifted and 0b10000000) == 1 Status.N = (shifted and 0b10000000) != 0
} }
} }
@ -746,9 +752,10 @@ class Cpu6502(private val illegalInstrsAllowed: Boolean) : BusComponent(), ICpu
} }
private fun iBit() { private fun iBit() {
Status.Z = (A and fetchedData) == 0 val operand = getFetched()
Status.V = (fetchedData and 0b01000000) != 0 Status.Z = (A and operand) == 0
Status.N = (fetchedData and 0b10000000) != 0 Status.V = (operand and 0b01000000) != 0
Status.N = (operand and 0b10000000) != 0
} }
private fun iBmi() { private fun iBmi() {
@ -765,11 +772,10 @@ class Cpu6502(private val illegalInstrsAllowed: Boolean) : BusComponent(), ICpu
private fun iBrk() { private fun iBrk() {
PC++ PC++
Status.I = true
Status.B = true
pushStackAddr(PC) pushStackAddr(PC)
Status.B = true
pushStack(Status) pushStack(Status)
Status.B = false Status.I = true
PC = readWord(IRQ_vector) PC = readWord(IRQ_vector)
} }
@ -798,87 +804,68 @@ class Cpu6502(private val illegalInstrsAllowed: Boolean) : BusComponent(), ICpu
} }
private fun iCmp() { private fun iCmp() {
val fetched = val fetched = getFetched()
if (currentInstruction.mode == AddrMode.Imm) {
fetchedData
} else {
read(fetchedAddress)
}
Status.C = A >= fetched Status.C = A >= fetched
Status.Z = A == fetched Status.Z = A == fetched
Status.N = ((A - fetched) and 0b10000000) == 1 Status.N = ((A - fetched) and 0b10000000) != 0
} }
private fun iCpx() { private fun iCpx() {
val fetched = val fetched = getFetched()
if (currentInstruction.mode == AddrMode.Imm) {
fetchedData
} else {
read(fetchedAddress)
}
Status.C = X >= fetched Status.C = X >= fetched
Status.Z = X == fetched Status.Z = X == fetched
Status.N = ((X - fetched) and 0b10000000) == 1 Status.N = ((X - fetched) and 0b10000000) != 0
} }
private fun iCpy() { private fun iCpy() {
val fetched = val fetched = getFetched()
if (currentInstruction.mode == AddrMode.Imm) {
fetchedData
} else {
read(fetchedAddress)
}
Status.C = Y >= fetched Status.C = Y >= fetched
Status.Z = Y == fetched Status.Z = Y == fetched
Status.N = ((Y - fetched) and 0b10000000) == 1 Status.N = ((Y - fetched) and 0b10000000) != 0
} }
private fun iDec() { private fun iDec() {
val data = (read(fetchedAddress) - 1) and 255 val data = (read(fetchedAddress) - 1) and 255
write(fetchedAddress, data) write(fetchedAddress, data)
Status.Z = data == 0 Status.Z = data == 0
Status.N = (data and 0b10000000) == 1 Status.N = (data and 0b10000000) != 0
} }
private fun iDex() { private fun iDex() {
X = (X - 1) and 255 X = (X - 1) and 255
Status.Z = X == 0 Status.Z = X == 0
Status.N = (X and 0b10000000) == 1 Status.N = (X and 0b10000000) != 0
} }
private fun iDey() { private fun iDey() {
Y = (Y - 1) and 255 Y = (Y - 1) and 255
Status.Z = Y == 0 Status.Z = Y == 0
Status.N = (Y and 0b10000000) == 1 Status.N = (Y and 0b10000000) != 0
} }
private fun iEor() { private fun iEor() {
A = if (currentInstruction.mode == AddrMode.Imm) { A = A xor getFetched()
A xor fetchedData
} else {
A xor read(fetchedAddress)
}
Status.Z = A == 0 Status.Z = A == 0
Status.N = (A and 0b10000000) == 1 Status.N = (A and 0b10000000) != 0
} }
private fun iInc() { private fun iInc() {
val data = (read(fetchedAddress) + 1) and 255 val data = (read(fetchedAddress) + 1) and 255
write(fetchedAddress, data) write(fetchedAddress, data)
Status.Z = data == 0 Status.Z = data == 0
Status.N = (data and 0b10000000) == 1 Status.N = (data and 0b10000000) != 0
} }
private fun iInx() { private fun iInx() {
X = (X + 1) and 255 X = (X + 1) and 255
Status.Z = X == 0 Status.Z = X == 0
Status.N = (X and 0b10000000) == 1 Status.N = (X and 0b10000000) != 0
} }
private fun iIny() { private fun iIny() {
Y = (Y + 1) and 255 Y = (Y + 1) and 255
Status.Z = Y == 0 Status.Z = Y == 0
Status.N = (Y and 0b10000000) == 1 Status.N = (Y and 0b10000000) != 0
} }
private fun iJmp() { private fun iJmp() {
@ -886,35 +873,26 @@ class Cpu6502(private val illegalInstrsAllowed: Boolean) : BusComponent(), ICpu
} }
private fun iJsr() { private fun iJsr() {
pushStackAddr(PC) pushStackAddr(PC-1)
PC = fetchedAddress PC = fetchedAddress
} }
private fun iLda() { private fun iLda() {
A = if (currentInstruction.mode == AddrMode.Imm) A = getFetched()
fetchedData
else
read(fetchedAddress)
Status.Z = A == 0 Status.Z = A == 0
Status.N = (A and 0b10000000) == 1 Status.N = (A and 0b10000000) != 0
} }
private fun iLdx() { private fun iLdx() {
X = if (currentInstruction.mode == AddrMode.Imm) X = getFetched()
fetchedData
else
read(fetchedAddress)
Status.Z = X == 0 Status.Z = X == 0
Status.N = (X and 0b10000000) == 1 Status.N = (X and 0b10000000) != 0
} }
private fun iLdy() { private fun iLdy() {
Y = if (currentInstruction.mode == AddrMode.Imm) Y = getFetched()
fetchedData
else
read(fetchedAddress)
Status.Z = Y == 0 Status.Z = Y == 0
Status.N = (Y and 0b10000000) == 1 Status.N = (Y and 0b10000000) != 0
} }
private fun iLsr() { private fun iLsr() {
@ -922,26 +900,23 @@ class Cpu6502(private val illegalInstrsAllowed: Boolean) : BusComponent(), ICpu
Status.C = (A and 1) == 1 Status.C = (A and 1) == 1
A = A ushr 1 A = A ushr 1
Status.Z = A == 0 Status.Z = A == 0
Status.N = (A and 0b10000000) == 1 Status.N = (A and 0b10000000) != 0
} else { } else {
val data = read(fetchedAddress) val data = read(fetchedAddress)
Status.C = (data and 1) == 1 Status.C = (data and 1) == 1
val shifted = data ushr 1 val shifted = data ushr 1
write(fetchedAddress, shifted) write(fetchedAddress, shifted)
Status.Z = shifted == 0 Status.Z = shifted == 0
Status.N = (shifted and 0b10000000) == 1 Status.N = (shifted and 0b10000000) != 0
} }
} }
private fun iNop() {} private fun iNop() {}
private fun iOra() { private fun iOra() {
A = if (currentInstruction.mode == AddrMode.Imm) A = A or getFetched()
A or fetchedData
else
A or read(fetchedAddress)
Status.Z = A == 0 Status.Z = A == 0
Status.N = (A and 0b10000000) == 1 Status.N = (A and 0b10000000) != 0
} }
private fun iPha() { private fun iPha() {
@ -949,33 +924,37 @@ class Cpu6502(private val illegalInstrsAllowed: Boolean) : BusComponent(), ICpu
} }
private fun iPhp() { private fun iPhp() {
val origBreakflag = Status.B
Status.B = true
pushStack(Status) pushStack(Status)
Status.B = origBreakflag
} }
private fun iPla() { private fun iPla() {
A = popStack() A = popStack()
Status.Z = A == 0 Status.Z = A == 0
Status.N = (A and 0b10000000) == 1 Status.N = (A and 0b10000000) != 0
} }
private fun iPlp() { private fun iPlp() {
Status.fromByte(popStack()) Status.fromByte(popStack())
Status.B = true // break is always 1 except when pushing on stack
} }
private fun iRol() { private fun iRol() {
val oldCarry = Status.C val oldCarry = Status.C
if (currentInstruction.mode == AddrMode.Acc) { if (currentInstruction.mode == AddrMode.Acc) {
Status.C = (A and 0b10000000) == 1 Status.C = (A and 0b10000000) != 0
A = (A shl 1) or (if (oldCarry) 1 else 0) A = (A shl 1 and 255) or (if (oldCarry) 1 else 0)
Status.Z = A == 0 Status.Z = A == 0
Status.N = (A and 0b10000000) == 1 Status.N = (A and 0b10000000) != 0
} else { } else {
val data = read(fetchedAddress) val data = read(fetchedAddress)
Status.C = (data and 0b10000000) == 1 Status.C = (data and 0b10000000) != 0
val shifted = (data shl 1) or (if (oldCarry) 1 else 0) and 255 val shifted = (data shl 1 and 255) or (if (oldCarry) 1 else 0)
write(fetchedAddress, shifted) write(fetchedAddress, shifted)
Status.Z = shifted == 0 Status.Z = shifted == 0
Status.N = (shifted and 0b10000000) == 1 Status.N = (shifted and 0b10000000) != 0
} }
} }
@ -985,38 +964,36 @@ class Cpu6502(private val illegalInstrsAllowed: Boolean) : BusComponent(), ICpu
Status.C = (A and 1) == 1 Status.C = (A and 1) == 1
A = (A ushr 1) or (if (oldCarry) 0b10000000 else 0) A = (A ushr 1) or (if (oldCarry) 0b10000000 else 0)
Status.Z = A == 0 Status.Z = A == 0
Status.N = (A and 0b10000000) == 1 Status.N = (A and 0b10000000) != 0
} else { } else {
val data = read(fetchedAddress) val data = read(fetchedAddress)
Status.C = (data and 1) == 1 Status.C = (data and 1) == 1
val shifted = (data ushr 1) or (if (oldCarry) 0b10000000 else 0) val shifted = (data ushr 1) or (if (oldCarry) 0b10000000 else 0)
write(fetchedAddress, shifted) write(fetchedAddress, shifted)
Status.Z = shifted == 0 Status.Z = shifted == 0
Status.N = (shifted and 0b10000000) == 1 Status.N = (shifted and 0b10000000) != 0
} }
} }
private fun iRti() { private fun iRti() {
Status.fromByte(popStack()) Status.fromByte(popStack())
Status.B = true // break is always 1 except when pushing on stack
PC = popStackAddr() PC = popStackAddr()
} }
private fun iRts() { private fun iRts() {
PC = popStackAddr() PC = popStackAddr()
PC = (PC+1) and 0xffff
} }
private fun iSbc() { private fun iSbc() {
val operand = if (currentInstruction.mode == AddrMode.Imm) { val operand = getFetched()
fetchedData
} else {
read(fetchedAddress)
}
if (Status.D) { if (Status.D) {
var lo = (A and 0x0f) - (operand and 0x0f) - if (Status.C) 0 else 1 var lo = (A and 0x0f) - (operand and 0x0f) - if (Status.C) 0 else 1
if (lo and 0x10 != 0) lo -= 6 if (lo and 0x10 != 0) lo -= 6
var h = (A shr 4) - (operand shr 4) - if (lo and 0x10 != 0) 1 else 0 var h = (A shr 4) - (operand shr 4) - if (lo and 0x10 != 0) 1 else 0
if (h and 0x10 != 0) h -= 6 if (h and 0x10 != 0) h -= 6
val result = lo and 0x0f or (h shl 4 and 0xff) val result = lo and 0x0f or ((h shl 4) and 0xff)
Status.C = h and 255 < 15 Status.C = h and 255 < 15
Status.Z = result == 0 Status.Z = result == 0
Status.V = false // BCD never sets overflow flag Status.V = false // BCD never sets overflow flag
@ -1071,7 +1048,7 @@ class Cpu6502(private val illegalInstrsAllowed: Boolean) : BusComponent(), ICpu
} }
private fun iTsx() { private fun iTsx() {
X = Status.asByte().toInt() X = SP
Status.Z = X == 0 Status.Z = X == 0
Status.N = (X and 0b10000000) != 0 Status.N = (X and 0b10000000) != 0
} }
@ -1083,7 +1060,7 @@ class Cpu6502(private val illegalInstrsAllowed: Boolean) : BusComponent(), ICpu
} }
private fun iTxs() { private fun iTxs() {
Status.fromByte(X) SP = X
} }
private fun iTya() { private fun iTya() {

View File

@ -20,6 +20,10 @@ class Ram(startAddress: Address, endAddress: Address): MemMappedComponent(startA
override fun reset() { memory.fill(0) } override fun reset() { memory.fill(0) }
fun fill(data: UByte) {
memory.fill(data)
}
fun load(filename: String, address: Address) { fun load(filename: String, address: Address) {
val bytes = File(filename).readBytes() val bytes = File(filename).readBytes()
bytes.forEachIndexed { index, byte -> bytes.forEachIndexed { index, byte ->

View File

@ -1,5 +1,6 @@
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
import org.junit.jupiter.api.TestInstance import org.junit.jupiter.api.TestInstance
import sim65.components.Cpu6502
import kotlin.test.* import kotlin.test.*
@ -274,7 +275,7 @@ class Test6502 : TestCommon6502() {
writeMem(memory, 0, listOf(0x6c, 0xff, 0x00)) writeMem(memory, 0, listOf(0x6c, 0xff, 0x00))
mpu.step() mpu.step()
assertEquals(0x6c00, mpu.PC) assertEquals(0x6c00, mpu.PC)
assertEquals(5, mpu.totalCycles) assertEquals(5+Cpu6502.resetCycles, mpu.totalCycles)
} }
// ORA Indexed, Indirect (Y) // ORA Indexed, Indirect (Y)

View File

@ -52,7 +52,11 @@ abstract class TestCommon6502 {
init { init {
bus.add(mpu) bus.add(mpu)
bus.add(memory) bus.add(memory)
memory.fill(0xaa)
memory.write(Cpu6502.RESET_vector, 0)
memory.write(Cpu6502.RESET_vector+1, 0)
mpu.reset() mpu.reset()
mpu.Status.I = false // allow interrupts again
} }
companion object { companion object {
@ -79,11 +83,11 @@ abstract class TestCommon6502 {
fun test_reset_sets_registers_to_initial_states() { fun test_reset_sets_registers_to_initial_states() {
mpu.reset() mpu.reset()
assertEquals(0xFF, mpu.SP) assertEquals(0xFD, mpu.SP)
assertEquals(0, mpu.A) assertEquals(0, mpu.A)
assertEquals(0, mpu.X) assertEquals(0, mpu.X)
assertEquals(0, mpu.Y) assertEquals(0, mpu.Y)
assertEquals(Cpu6502.StatusRegister(C = false, Z = false, I = false, D = false, B = true, V = false, N = false), mpu.Status) assertTrue(mpu.Status.I) // the other status flags are undefined after reset
} }
// ADC Absolute // ADC Absolute
@ -1339,11 +1343,10 @@ abstract class TestCommon6502 {
assertTrue(mpu.Status.N) assertTrue(mpu.Status.N)
assertTrue(mpu.Status.V) assertTrue(mpu.Status.V)
assertFalse(mpu.Status.Z) assertFalse(mpu.Status.Z)
// AND (Absolute)
} }
// AND (Absolute)
@Test @Test
fun test_and_absolute_all_zeros_setting_zero_flag() { fun test_and_absolute_all_zeros_setting_zero_flag() {
@ -1371,11 +1374,10 @@ abstract class TestCommon6502 {
assertEquals(0xAA, mpu.A) assertEquals(0xAA, mpu.A)
assertTrue(mpu.Status.N) assertTrue(mpu.Status.N)
assertFalse(mpu.Status.Z) assertFalse(mpu.Status.Z)
// AND (Absolute)
} }
// AND (Absolute)
@Test @Test
fun test_and_zp_all_zeros_setting_zero_flag() { fun test_and_zp_all_zeros_setting_zero_flag() {
@ -1490,7 +1492,6 @@ abstract class TestCommon6502 {
@Test @Test
fun test_and_abs_y_zeros_and_ones_setting_negative_flag() { fun test_and_abs_y_zeros_and_ones_setting_negative_flag() {
mpu.A = 0xFF mpu.A = 0xFF
mpu.Y = 0x03 mpu.Y = 0x03
// $0000 AND $ABCD,X // $0000 AND $ABCD,X
@ -1501,11 +1502,10 @@ abstract class TestCommon6502 {
assertEquals(0xAA, mpu.A) assertEquals(0xAA, mpu.A)
assertTrue(mpu.Status.N) assertTrue(mpu.Status.N)
assertFalse(mpu.Status.Z) assertFalse(mpu.Status.Z)
// AND Indirect, Indexed (X)
} }
// AND Indirect, Indexed (X)
@Test @Test
fun test_and_ind_indexed_x_all_zeros_setting_zero_flag() { fun test_and_ind_indexed_x_all_zeros_setting_zero_flag() {
@ -1950,11 +1950,11 @@ abstract class TestCommon6502 {
mpu.Status.C = false mpu.Status.C = false
mpu.PC = 0x0050 mpu.PC = 0x0050
val rel = (0x06 xor 0xFF + 1) // two's complement of 6 val rel = 256 + (-6) // two's complement of 6
// $0000 BCC -6 // $0000 BCC -6
writeMem(memory, 0x0050, listOf(0x90, rel.toShort())) writeMem(memory, 0x0050, listOf(0x90, rel.toShort()))
mpu.step() mpu.step()
assertEquals(0x0052 + rel, mpu.PC) assertEquals(0x0052 - 6, mpu.PC)
} }
@ -1987,11 +1987,11 @@ abstract class TestCommon6502 {
mpu.Status.C = true mpu.Status.C = true
mpu.PC = 0x0050 mpu.PC = 0x0050
val rel = (0x06 xor 0xFF + 1) // two's complement of 6 val rel = 256 + (-6) // two's complement of 6
// $0000 BCS -6 // $0000 BCS -6
writeMem(memory, 0x0050, listOf(0xB0, rel.toShort())) writeMem(memory, 0x0050, listOf(0xB0, rel.toShort()))
mpu.step() mpu.step()
assertEquals(0x0052 + rel, mpu.PC) assertEquals(0x0052 - 6, mpu.PC)
} }
@ -2024,11 +2024,11 @@ abstract class TestCommon6502 {
mpu.Status.Z = true mpu.Status.Z = true
mpu.PC = 0x0050 mpu.PC = 0x0050
val rel = (0x06 xor 0xFF + 1) // two's complement of 6 val rel = 256 + (-6) // two's complement of 6
// $0000 BEQ -6 // $0000 BEQ -6
writeMem(memory, 0x0050, listOf(0xF0, rel.toShort())) writeMem(memory, 0x0050, listOf(0xF0, rel.toShort()))
mpu.step() mpu.step()
assertEquals(0x0052 + rel, mpu.PC) assertEquals(0x0052 - 6, mpu.PC)
} }
@ -2154,7 +2154,7 @@ abstract class TestCommon6502 {
mpu.A = 0xFF mpu.A = 0xFF
mpu.step() mpu.step()
assertEquals(0x0002, mpu.PC) assertEquals(0x0002, mpu.PC)
assertEquals(3, mpu.totalCycles) assertEquals(3+Cpu6502.resetCycles, mpu.totalCycles)
assertTrue(mpu.Status.N) assertTrue(mpu.Status.N)
} }
@ -2169,7 +2169,7 @@ abstract class TestCommon6502 {
mpu.A = 0xFF mpu.A = 0xFF
mpu.step() mpu.step()
assertEquals(0x0002, mpu.PC) assertEquals(0x0002, mpu.PC)
assertEquals(3, mpu.totalCycles) assertEquals(3+Cpu6502.resetCycles, mpu.totalCycles)
assertFalse(mpu.Status.N) assertFalse(mpu.Status.N)
} }
@ -2184,7 +2184,7 @@ abstract class TestCommon6502 {
mpu.A = 0xFF mpu.A = 0xFF
mpu.step() mpu.step()
assertEquals(0x0002, mpu.PC) assertEquals(0x0002, mpu.PC)
assertEquals(3, mpu.totalCycles) assertEquals(3+Cpu6502.resetCycles, mpu.totalCycles)
assertTrue(mpu.Status.V) assertTrue(mpu.Status.V)
} }
@ -2199,7 +2199,7 @@ abstract class TestCommon6502 {
mpu.A = 0xFF mpu.A = 0xFF
mpu.step() mpu.step()
assertEquals(0x0002, mpu.PC) assertEquals(0x0002, mpu.PC)
assertEquals(3, mpu.totalCycles) assertEquals(3+Cpu6502.resetCycles, mpu.totalCycles)
assertFalse(mpu.Status.V) assertFalse(mpu.Status.V)
} }
@ -2214,7 +2214,7 @@ abstract class TestCommon6502 {
mpu.A = 0x01 mpu.A = 0x01
mpu.step() mpu.step()
assertEquals(0x0002, mpu.PC) assertEquals(0x0002, mpu.PC)
assertEquals(3, mpu.totalCycles) assertEquals(3+Cpu6502.resetCycles, mpu.totalCycles)
assertTrue(mpu.Status.Z) assertTrue(mpu.Status.Z)
assertEquals(0x01, mpu.A) assertEquals(0x01, mpu.A)
assertEquals(0x00, memory[0x0010]) assertEquals(0x00, memory[0x0010])
@ -2231,7 +2231,7 @@ abstract class TestCommon6502 {
mpu.A = 0x01 mpu.A = 0x01
mpu.step() mpu.step()
assertEquals(0x0002, mpu.PC) assertEquals(0x0002, mpu.PC)
assertEquals(3, mpu.totalCycles) assertEquals(3+Cpu6502.resetCycles, mpu.totalCycles)
assertFalse(mpu.Status.Z) // result of AND is non-zero assertFalse(mpu.Status.Z) // result of AND is non-zero
assertEquals(0x01, mpu.A) assertEquals(0x01, mpu.A)
assertEquals(0x01, memory[0x0010]) assertEquals(0x01, memory[0x0010])
@ -2248,7 +2248,7 @@ abstract class TestCommon6502 {
mpu.A = 0x01 mpu.A = 0x01
mpu.step() mpu.step()
assertEquals(0x0002, mpu.PC) assertEquals(0x0002, mpu.PC)
assertEquals(3, mpu.totalCycles) assertEquals(3+Cpu6502.resetCycles, mpu.totalCycles)
assertTrue(mpu.Status.Z) // result of AND is zero assertTrue(mpu.Status.Z) // result of AND is zero
assertEquals(0x01, mpu.A) assertEquals(0x01, mpu.A)
assertEquals(0x00, memory[0x0010]) assertEquals(0x00, memory[0x0010])
@ -2274,10 +2274,10 @@ abstract class TestCommon6502 {
mpu.Status.N = true mpu.Status.N = true
mpu.PC = 0x0050 mpu.PC = 0x0050
// $0000 BMI -6 // $0000 BMI -6
val rel = (0x06 xor 0xFF + 1) // two's complement of 6 val rel = 256 + (-6) // two's complement of 6
writeMem(memory, 0x0050, listOf(0x30, rel.toShort())) writeMem(memory, 0x0050, listOf(0x30, rel.toShort()))
mpu.step() mpu.step()
assertEquals(0x0052 + rel, mpu.PC) assertEquals(0x0052 - 6, mpu.PC)
} }
@ -2311,10 +2311,10 @@ abstract class TestCommon6502 {
mpu.Status.Z = false mpu.Status.Z = false
mpu.PC = 0x0050 mpu.PC = 0x0050
// $0050 BNE -6 // $0050 BNE -6
val rel = (0x06 xor 0xFF + 1) // two's complement of 6 val rel = 256 + (-6) // two's complement of 6
writeMem(memory, 0x0050, listOf(0xD0, rel.toShort())) writeMem(memory, 0x0050, listOf(0xD0, rel.toShort()))
mpu.step() mpu.step()
assertEquals(0x0052 + rel, mpu.PC) assertEquals(0x0052 - 6, mpu.PC)
} }
@ -2348,10 +2348,10 @@ abstract class TestCommon6502 {
mpu.Status.N = false mpu.Status.N = false
mpu.PC = 0x0050 mpu.PC = 0x0050
// $0050 BPL -6 // $0050 BPL -6
val rel = (0x06 xor 0xFF + 1) // two's complement of 6 val rel = 256 + (-6) // two's complement of 6
writeMem(memory, 0x0050, listOf(0x10, rel.toShort())) writeMem(memory, 0x0050, listOf(0x10, rel.toShort()))
mpu.step() mpu.step()
assertEquals(0x0052 + rel, mpu.PC) assertEquals(0x0052 - 6, mpu.PC)
} }
@ -2372,17 +2372,19 @@ abstract class TestCommon6502 {
fun test_brk_pushes_pc_plus_2_and_status_then_sets_pc_to_irq_vector() { fun test_brk_pushes_pc_plus_2_and_status_then_sets_pc_to_irq_vector() {
writeMem(memory, 0xFFFE, listOf(0xCD, 0xAB)) writeMem(memory, 0xFFFE, listOf(0xCD, 0xAB))
mpu.SP = 0xff
mpu.Status.I = false
// $C000 BRK // $C000 BRK
memory[0xC000] = 0x00 memory[0xC000] = 0x00
mpu.PC = 0xC000 mpu.PC = 0xC000
mpu.step() mpu.step()
assertEquals(0xABCD, mpu.PC) assertEquals(0xABCD, mpu.PC)
assertEquals(0xFC, mpu.SP)
assertEquals(0xC0, memory[0x1FF]) // PCH assertEquals(0xC0, memory[0x1FF]) // PCH
assertEquals(0x02, memory[0x1FE]) // PCL assertEquals(0x02, memory[0x1FE]) // PCL
assertEquals(fBREAK or fUNUSED, memory[0x1FD].toInt()) // Status assertEquals(fBREAK or fUNUSED, memory[0x1FD].toInt(), "Status on stack should have no I flag")
assertEquals(0xFC, mpu.SP)
assertEquals(fBREAK or fUNUSED or fINTERRUPT, mpu.Status.asByte().toInt()) assertEquals(fBREAK or fUNUSED or fINTERRUPT, mpu.Status.asByte().toInt())
} }
@ -2401,11 +2403,11 @@ abstract class TestCommon6502 {
fun test_bvc_overflow_clear_branches_relative_backward() { fun test_bvc_overflow_clear_branches_relative_backward() {
mpu.Status.V = false mpu.Status.V = false
mpu.PC = 0x0050 mpu.PC = 0x0050
val rel = (0x06 xor 0xFF + 1) // two's complement of 6 val rel = 256 + (-6) // two's complement of 6
// $0050 BVC -6 // $0050 BVC -6
writeMem(memory, 0x0050, listOf(0x50, rel.toShort())) writeMem(memory, 0x0050, listOf(0x50, rel.toShort()))
mpu.step() mpu.step()
assertEquals(0x0052 + rel, mpu.PC) assertEquals(0x0052 - 6, mpu.PC)
} }
@Test @Test
@ -2433,11 +2435,11 @@ abstract class TestCommon6502 {
mpu.Status.V = true mpu.Status.V = true
mpu.PC = 0x0050 mpu.PC = 0x0050
val rel = (0x06 xor 0xFF + 1) // two's complement of 6 val rel = 256 + (-6) // two's complement of 6
// $0050 BVS -6 // $0050 BVS -6
writeMem(memory, 0x0050, listOf(0x70, rel.toShort())) writeMem(memory, 0x0050, listOf(0x70, rel.toShort()))
mpu.step() mpu.step()
assertEquals(0x0052 + rel, mpu.PC) assertEquals(0x0052 - 6, mpu.PC)
} }
@ -3332,18 +3334,16 @@ abstract class TestCommon6502 {
@Test @Test
fun test_inx_sets_negative_flag_when_incrementing_above_7F() { fun test_inx_sets_negative_flag_when_incrementing_above_7F() {
mpu.X = 0x7f mpu.X = 0x7f
memory[0x0000] = 0xE8 // => INX memory[0x0000] = 0xE8 // => INX
mpu.step() mpu.step()
assertEquals(0x0001, mpu.PC) assertEquals(0x0001, mpu.PC)
assertEquals(0x80, mpu.X) assertEquals(0x80, mpu.X)
assertTrue(mpu.Status.N) assertTrue(mpu.Status.N)
// INY
} }
// INY
@Test @Test
fun test_iny_increments_y() { fun test_iny_increments_y() {
@ -3354,7 +3354,6 @@ abstract class TestCommon6502 {
assertEquals(0x0A, mpu.Y) assertEquals(0x0A, mpu.Y)
assertFalse(mpu.Status.Z) assertFalse(mpu.Status.Z)
assertFalse(mpu.Status.N) assertFalse(mpu.Status.N)
} }
@Test @Test
@ -3412,6 +3411,7 @@ abstract class TestCommon6502 {
fun test_jsr_pushes_pc_plus_2_and_sets_pc() { fun test_jsr_pushes_pc_plus_2_and_sets_pc() {
// $C000 JSR $FFD2 // $C000 JSR $FFD2
mpu.SP = 0xFF
writeMem(memory, 0xC000, listOf(0x20, 0xD2, 0xFF)) writeMem(memory, 0xC000, listOf(0x20, 0xD2, 0xFF))
mpu.PC = 0xC000 mpu.PC = 0xC000
mpu.step() mpu.step()
@ -3419,11 +3419,10 @@ abstract class TestCommon6502 {
assertEquals(0xFD, mpu.SP) assertEquals(0xFD, mpu.SP)
assertEquals(0xC0, memory[0x01FF]) // PCH assertEquals(0xC0, memory[0x01FF]) // PCH
assertEquals(0x02, memory[0x01FE]) // PCL+2 assertEquals(0x02, memory[0x01FE]) // PCL+2
// LDA Absolute
} }
// LDA Absolute
@Test @Test
fun test_lda_absolute_loads_a_sets_n_flag() { fun test_lda_absolute_loads_a_sets_n_flag() {
@ -4604,21 +4603,22 @@ abstract class TestCommon6502 {
mpu.step() mpu.step()
assertEquals(0x0001, mpu.PC) assertEquals(0x0001, mpu.PC)
assertEquals(0xAB, mpu.A) assertEquals(0xAB, mpu.A)
assertEquals(0xAB, memory[0x01FF]) assertEquals(0xFC, mpu.SP)
assertEquals(0xFE, mpu.SP) assertEquals(0xAB, memory[0x01FD])
} }
// PHP // PHP
@Test @Test
fun test_php_pushes_processor_status_and_updates_sp() { fun test_php_pushes_processor_status_and_updates_sp() {
for (flags in 0 until 0x100) { for (flags in 0 until 0x100) {
mpu.reset()
mpu.Status.fromByte(flags or fBREAK or fUNUSED) mpu.Status.fromByte(flags or fBREAK or fUNUSED)
// $0000 PHP // $0000 PHP
memory[0x0000] = 0x08 memory[0x0000] = 0x08
mpu.step() mpu.step()
assertEquals(0x0001, mpu.PC) assertEquals(0x0001, mpu.PC)
assertEquals((flags or fBREAK or fUNUSED), memory[0x1FF].toInt()) assertEquals(0xFC, mpu.SP)
assertEquals(0xFE, mpu.SP) assertEquals((flags or fBREAK or fUNUSED), memory[0x1FD].toInt())
} }
} }
@ -4684,7 +4684,6 @@ abstract class TestCommon6502 {
assertEquals(0x00, mpu.A) assertEquals(0x00, mpu.A)
assertTrue(mpu.Status.Z) assertTrue(mpu.Status.Z)
assertFalse(mpu.Status.N) assertFalse(mpu.Status.N)
} }
@Test @Test
@ -5442,10 +5441,9 @@ abstract class TestCommon6502 {
mpu.SP = 0xFC mpu.SP = 0xFC
mpu.step() mpu.step()
assertEquals(0xC003, mpu.PC)
assertEquals(0xFC, mpu.Status.asByte())
assertEquals(0xFF, mpu.SP) assertEquals(0xFF, mpu.SP)
assertEquals(0xFC, mpu.Status.asByte())
assertEquals(0xC003, mpu.PC)
} }
@Test @Test