mirror of
https://github.com/irmen/prog8.git
synced 2024-11-29 17:50:35 +00:00
fixed all instructions except BCD arithmetic
This commit is contained in:
parent
42f8e98cab
commit
900c2aea23
@ -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() {
|
||||
|
@ -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 ->
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
||||
}
|
||||
|
||||
@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)
|
||||
|
||||
}
|
||||
|
||||
@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)
|
||||
|
||||
}
|
||||
|
||||
@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
|
||||
|
||||
}
|
||||
|
||||
@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
|
||||
|
||||
}
|
||||
|
||||
@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
|
||||
|
Loading…
Reference in New Issue
Block a user