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

View File

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

View File

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

View File

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