mirror of
https://github.com/irmen/prog8.git
synced 2024-11-25 19:31:36 +00:00
fixed bcd (but the bcd test code still fails, strange)
This commit is contained in:
parent
adfddddac6
commit
15710207b2
@ -70,19 +70,29 @@ private fun startSimulator(args: Array<String>) {
|
||||
//ram.dump(0x8000, 0x802f)
|
||||
//cpu.disassemble(ram, 0x8000, 0x802f)
|
||||
|
||||
while(true) {
|
||||
bus.clock()
|
||||
if(cpu.totalCycles > 300)
|
||||
break
|
||||
try {
|
||||
while (true) {
|
||||
bus.clock()
|
||||
}
|
||||
} catch(e: InstructionError) {
|
||||
|
||||
}
|
||||
|
||||
if(ram.read(0x0400)==0.toShort())
|
||||
println("BCD TEST: OK!")
|
||||
else {
|
||||
val code = ram.read(0x0400)
|
||||
val v1 = ram.read(0x0401)
|
||||
val v2 = ram.read(0x0402)
|
||||
println("BCD TEST: FAIL!! value1=${hexB(v1)} value2=${hexB(v2)}")
|
||||
val predictedA = ram.read(0x00fc)
|
||||
val actualA = ram.read(0x00fd)
|
||||
val predictedF = ram.read(0x00fe)
|
||||
val actualF = ram.read(0x00ff)
|
||||
println("BCD TEST: FAIL!! code=${hexB(code)} value1=${hexB(v1)} value2=${hexB(v2)}")
|
||||
println(" predictedA=${hexB(predictedA)}")
|
||||
println(" actualA=${hexB(actualA)}")
|
||||
println(" predictedF=${predictedF.toString(2).padStart(8,'0')}")
|
||||
println(" actualF=${actualF.toString(2).padStart(8,'0')}")
|
||||
}
|
||||
ram.dump(0x0400, 0x0402)
|
||||
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
package sim65.components
|
||||
|
||||
|
||||
class InstructionError(msg: String) : RuntimeException(msg)
|
||||
|
||||
interface ICpu {
|
||||
@ -17,7 +16,6 @@ interface ICpu {
|
||||
}
|
||||
|
||||
// TODO: add the optional additional cycles to certain instructions and addressing modes
|
||||
// TODO: fix sbc and adc with BCD arithmetic.
|
||||
// TODO: add IRQ and NMI signaling.
|
||||
// TODO: make a 65c02 variant as well (and re-enable the unit tests for that).
|
||||
|
||||
@ -699,23 +697,31 @@ class Cpu6502(private val illegalInstrsAllowed: Boolean) : BusComponent(), ICpu
|
||||
val operand = getFetched()
|
||||
if (Status.D) {
|
||||
// BCD add
|
||||
var lo = (A and 0x0f) + (operand and 0x0f) + if (Status.C) 1 else 0
|
||||
if (lo and 0xff > 9) lo += 6
|
||||
var hi = (A shr 4) + (operand shr 4) + if (lo > 15) 1 else 0
|
||||
Status.N = (hi and 8) != 0 // strange... other sources say "BCD is never negative on NMOS 6502 (bug)"
|
||||
Status.V = ((((hi shl 4) xor A) and 0x80) !=0) && ((A xor operand) and 0x80)==0 // strange... other sources say "V is never set in BCD mode"
|
||||
if (hi and 0xff > 9) hi += 6
|
||||
A = lo and 0x0f or (hi shl 4) and 0xff
|
||||
Status.C = hi > 15
|
||||
Status.Z = A == 0
|
||||
// see http://www.6502.org/tutorials/decimal_mode.html
|
||||
// and http://nesdev.com/6502.txt
|
||||
// and https://sourceforge.net/p/vice-emu/code/HEAD/tree/trunk/vice/src/6510core.c#l598
|
||||
// (the implementation below is based on the code used by Vice)
|
||||
var tmp = (A and 0xf) + (operand and 0xf) + (if (Status.C) 1 else 0)
|
||||
if (tmp > 0x9) tmp += 0x6
|
||||
tmp = if (tmp <= 0x0f) {
|
||||
(tmp and 0xf) + (A and 0xf0) + (operand and 0xf0)
|
||||
} else {
|
||||
(tmp and 0xf) + (A and 0xf0) + (operand and 0xf0) + 0x10
|
||||
}
|
||||
Status.Z = ((A + operand + (if (Status.C) 1 else 0)) and 0xff) == 0
|
||||
Status.N = (tmp and 0b10000000) != 0
|
||||
Status.V = ((A xor tmp) and 0x80) != 0 && ((A xor operand) and 0x80) == 0
|
||||
if (tmp > 0x90) tmp += 0x60
|
||||
Status.C = tmp > 0xf0
|
||||
A = tmp and 255
|
||||
} else {
|
||||
// normal add
|
||||
val result = A + operand + if (Status.C) 1 else 0
|
||||
Status.C = result > 255
|
||||
Status.V = (A xor operand).inv() and (A xor result) and 0x0080 != 0
|
||||
A = result and 255
|
||||
Status.N = (A and 0b10000000) != 0
|
||||
Status.Z = A == 0
|
||||
val tmp = operand + A + if (Status.C) 1 else 0
|
||||
Status.N = (tmp and 0b10000000) != 0
|
||||
Status.Z = (tmp and 255) == 0
|
||||
Status.V = ((A xor operand) and 0x80) == 0 && ((A xor tmp) and 0x80) != 0
|
||||
Status.C = tmp > 255
|
||||
A = tmp and 255
|
||||
}
|
||||
}
|
||||
|
||||
@ -989,29 +995,30 @@ class Cpu6502(private val illegalInstrsAllowed: Boolean) : BusComponent(), ICpu
|
||||
}
|
||||
|
||||
private fun iSbc() {
|
||||
val operand = getFetched()
|
||||
val tmp = (A - operand - if (Status.C) 0 else 1) and 65535
|
||||
if (Status.D) {
|
||||
val operand = getFetched()
|
||||
var lo: Int
|
||||
var hi: Int
|
||||
lo = (A and 0x0f) - (operand and 0x0f) - if (Status.C) 0 else 1
|
||||
if (lo and 0x10 != 0) lo -= 6
|
||||
hi = (A shr 4) - (operand shr 4) - if (lo and 0x10 != 0) 1 else 0
|
||||
if (hi and 0x10 != 0) hi -= 6
|
||||
A = lo and 0x0f or (hi shl 4) and 0xff
|
||||
Status.C = hi and 0xff < 15
|
||||
Status.V = false // BCD never sets overflow flag
|
||||
Status.Z = A==0
|
||||
Status.N = (A and 0b10000000) != 0
|
||||
// BCD subtract
|
||||
// see http://www.6502.org/tutorials/decimal_mode.html
|
||||
// and http://nesdev.com/6502.txt
|
||||
// and https://sourceforge.net/p/vice-emu/code/HEAD/tree/trunk/vice/src/6510core.c#l1396
|
||||
// (the implementation below is based on the code used by Vice)
|
||||
var tmpA = ((A and 0xf) - (operand and 0xf) - if (Status.C) 0 else 1) and 65535
|
||||
tmpA = if ((tmpA and 0x10) != 0) {
|
||||
((tmpA - 6) and 0xf) or (A and 0xf0) - (operand and 0xf0) - 0x10
|
||||
} else {
|
||||
(tmpA and 0xf) or (A and 0xf0) - (operand and 0xf0)
|
||||
}
|
||||
if ((tmpA and 0x100) != 0) tmpA -= 0x60
|
||||
A = tmpA and 255
|
||||
} else {
|
||||
// normal sub
|
||||
val invertedOperand = getFetched() xor 255
|
||||
val result = A + invertedOperand + if (Status.C) 1 else 0
|
||||
Status.C = result > 255
|
||||
Status.V = (A xor invertedOperand) and (A xor result) and 0x0080 != 0
|
||||
A = result and 255
|
||||
Status.N = (A and 0b10000000) != 0
|
||||
Status.Z = A == 0
|
||||
// normal subtract
|
||||
A = tmp and 255
|
||||
}
|
||||
Status.C = tmp < 0x100
|
||||
Status.Z = (tmp and 255) == 0
|
||||
Status.N = (tmp and 0b10000000) != 0
|
||||
Status.V = ((A xor tmp) and 0x80) != 0 && ((A xor operand) and 0x80) != 0
|
||||
}
|
||||
|
||||
private fun iSec() {
|
||||
|
@ -19,7 +19,8 @@ class Test6502CpuBasics {
|
||||
assertEquals(0, cpu.X)
|
||||
assertEquals(0, cpu.Y)
|
||||
assertEquals(0, cpu.currentOpcode)
|
||||
assertEquals(Cpu6502.StatusRegister(C = false, Z = false, I = false, D = false, B = false, V = false, N = false), cpu.Status)
|
||||
assertEquals(Cpu6502.StatusRegister(C = false, Z = false, I = true, D = false, B = false, V = false, N = false), cpu.Status)
|
||||
assertEquals(0b00100100, cpu.Status.asByte())
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -507,8 +507,8 @@ abstract class TestCommon6502 {
|
||||
assertEquals(0x80, mpu.A)
|
||||
assertFalse(mpu.Status.C)
|
||||
assertFalse(mpu.Status.Z)
|
||||
assertTrue(mpu.Status.V)
|
||||
assertTrue(mpu.Status.N)
|
||||
assertTrue(mpu.Status.V)
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -534,6 +534,7 @@ abstract class TestCommon6502 {
|
||||
|
||||
mpu.Status.D = true
|
||||
mpu.Status.C = false
|
||||
mpu.Status.N = true
|
||||
mpu.A = 0x9c
|
||||
// $0000 ADC #$9d
|
||||
// $0002 ADC #$9d
|
||||
@ -545,10 +546,10 @@ abstract class TestCommon6502 {
|
||||
mpu.step()
|
||||
assertEquals(0x0004, mpu.PC)
|
||||
assertEquals(0x93, mpu.A)
|
||||
assertFalse(mpu.Status.N)
|
||||
assertFalse(mpu.Status.Z)
|
||||
assertTrue(mpu.Status.C)
|
||||
assertTrue(mpu.Status.V)
|
||||
assertFalse(mpu.Status.N)
|
||||
}
|
||||
|
||||
// ADC Absolute, X-Indexed
|
||||
@ -5696,8 +5697,8 @@ abstract class TestCommon6502 {
|
||||
assertEquals(0x9a, mpu.A)
|
||||
assertFalse(mpu.Status.Z)
|
||||
assertTrue(mpu.Status.C)
|
||||
assertFalse(mpu.Status.V)
|
||||
assertTrue(mpu.Status.N)
|
||||
assertFalse(mpu.Status.V)
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -5714,9 +5715,9 @@ abstract class TestCommon6502 {
|
||||
assertEquals(0x0002, mpu.PC)
|
||||
assertEquals(0x99, mpu.A)
|
||||
assertFalse(mpu.Status.Z)
|
||||
assertFalse(mpu.Status.C)
|
||||
assertFalse(mpu.Status.V)
|
||||
assertTrue(mpu.Status.N)
|
||||
assertFalse(mpu.Status.V)
|
||||
assertFalse(mpu.Status.C)
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -5729,10 +5730,10 @@ abstract class TestCommon6502 {
|
||||
mpu.step()
|
||||
assertEquals(0x0002, mpu.PC)
|
||||
assertEquals(0x1f, mpu.A)
|
||||
assertFalse(mpu.Status.N)
|
||||
assertFalse(mpu.Status.V)
|
||||
assertFalse(mpu.Status.Z)
|
||||
assertTrue(mpu.Status.C)
|
||||
assertFalse(mpu.Status.N)
|
||||
assertFalse(mpu.Status.V)
|
||||
}
|
||||
|
||||
// SBC Absolute, X-Indexed
|
||||
|
Loading…
Reference in New Issue
Block a user