fixed bcd (but the bcd test code still fails, strange)

This commit is contained in:
Irmen de Jong 2019-09-05 22:30:00 +02:00
parent adfddddac6
commit 15710207b2
4 changed files with 70 additions and 51 deletions

View File

@ -70,19 +70,29 @@ private fun startSimulator(args: Array<String>) {
//ram.dump(0x8000, 0x802f) //ram.dump(0x8000, 0x802f)
//cpu.disassemble(ram, 0x8000, 0x802f) //cpu.disassemble(ram, 0x8000, 0x802f)
while(true) { try {
while (true) {
bus.clock() bus.clock()
if(cpu.totalCycles > 300) }
break } catch(e: InstructionError) {
} }
if(ram.read(0x0400)==0.toShort()) if(ram.read(0x0400)==0.toShort())
println("BCD TEST: OK!") println("BCD TEST: OK!")
else { else {
val code = ram.read(0x0400)
val v1 = ram.read(0x0401) val v1 = ram.read(0x0401)
val v2 = ram.read(0x0402) 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)
} }

View File

@ -1,6 +1,5 @@
package sim65.components package sim65.components
class InstructionError(msg: String) : RuntimeException(msg) class InstructionError(msg: String) : RuntimeException(msg)
interface ICpu { interface ICpu {
@ -17,7 +16,6 @@ interface ICpu {
} }
// TODO: add the optional additional cycles to certain instructions and addressing modes // 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: add IRQ and NMI signaling.
// TODO: make a 65c02 variant as well (and re-enable the unit tests for that). // 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() val operand = getFetched()
if (Status.D) { if (Status.D) {
// BCD add // BCD add
var lo = (A and 0x0f) + (operand and 0x0f) + if (Status.C) 1 else 0 // see http://www.6502.org/tutorials/decimal_mode.html
if (lo and 0xff > 9) lo += 6 // and http://nesdev.com/6502.txt
var hi = (A shr 4) + (operand shr 4) + if (lo > 15) 1 else 0 // and https://sourceforge.net/p/vice-emu/code/HEAD/tree/trunk/vice/src/6510core.c#l598
Status.N = (hi and 8) != 0 // strange... other sources say "BCD is never negative on NMOS 6502 (bug)" // (the implementation below is based on the code used by Vice)
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" var tmp = (A and 0xf) + (operand and 0xf) + (if (Status.C) 1 else 0)
if (hi and 0xff > 9) hi += 6 if (tmp > 0x9) tmp += 0x6
A = lo and 0x0f or (hi shl 4) and 0xff tmp = if (tmp <= 0x0f) {
Status.C = hi > 15 (tmp and 0xf) + (A and 0xf0) + (operand and 0xf0)
Status.Z = A == 0 } 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 { } else {
// normal add // normal add
val result = A + operand + if (Status.C) 1 else 0 val tmp = operand + A + if (Status.C) 1 else 0
Status.C = result > 255 Status.N = (tmp and 0b10000000) != 0
Status.V = (A xor operand).inv() and (A xor result) and 0x0080 != 0 Status.Z = (tmp and 255) == 0
A = result and 255 Status.V = ((A xor operand) and 0x80) == 0 && ((A xor tmp) and 0x80) != 0
Status.N = (A and 0b10000000) != 0 Status.C = tmp > 255
Status.Z = A == 0 A = tmp and 255
} }
} }
@ -989,29 +995,30 @@ class Cpu6502(private val illegalInstrsAllowed: Boolean) : BusComponent(), ICpu
} }
private fun iSbc() { private fun iSbc() {
if (Status.D) {
val operand = getFetched() val operand = getFetched()
var lo: Int val tmp = (A - operand - if (Status.C) 0 else 1) and 65535
var hi: Int if (Status.D) {
lo = (A and 0x0f) - (operand and 0x0f) - if (Status.C) 0 else 1 // BCD subtract
if (lo and 0x10 != 0) lo -= 6 // see http://www.6502.org/tutorials/decimal_mode.html
hi = (A shr 4) - (operand shr 4) - if (lo and 0x10 != 0) 1 else 0 // and http://nesdev.com/6502.txt
if (hi and 0x10 != 0) hi -= 6 // and https://sourceforge.net/p/vice-emu/code/HEAD/tree/trunk/vice/src/6510core.c#l1396
A = lo and 0x0f or (hi shl 4) and 0xff // (the implementation below is based on the code used by Vice)
Status.C = hi and 0xff < 15 var tmpA = ((A and 0xf) - (operand and 0xf) - if (Status.C) 0 else 1) and 65535
Status.V = false // BCD never sets overflow flag tmpA = if ((tmpA and 0x10) != 0) {
Status.Z = A==0 ((tmpA - 6) and 0xf) or (A and 0xf0) - (operand and 0xf0) - 0x10
Status.N = (A and 0b10000000) != 0
} else { } else {
// normal sub (tmpA and 0xf) or (A and 0xf0) - (operand and 0xf0)
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
} }
if ((tmpA and 0x100) != 0) tmpA -= 0x60
A = tmpA and 255
} else {
// 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() { private fun iSec() {

View File

@ -19,7 +19,8 @@ class Test6502CpuBasics {
assertEquals(0, cpu.X) assertEquals(0, cpu.X)
assertEquals(0, cpu.Y) assertEquals(0, cpu.Y)
assertEquals(0, cpu.currentOpcode) 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())
} }
} }

View File

@ -507,8 +507,8 @@ abstract class TestCommon6502 {
assertEquals(0x80, mpu.A) assertEquals(0x80, mpu.A)
assertFalse(mpu.Status.C) assertFalse(mpu.Status.C)
assertFalse(mpu.Status.Z) assertFalse(mpu.Status.Z)
assertTrue(mpu.Status.V)
assertTrue(mpu.Status.N) assertTrue(mpu.Status.N)
assertTrue(mpu.Status.V)
} }
@Test @Test
@ -534,6 +534,7 @@ abstract class TestCommon6502 {
mpu.Status.D = true mpu.Status.D = true
mpu.Status.C = false mpu.Status.C = false
mpu.Status.N = true
mpu.A = 0x9c mpu.A = 0x9c
// $0000 ADC #$9d // $0000 ADC #$9d
// $0002 ADC #$9d // $0002 ADC #$9d
@ -545,10 +546,10 @@ abstract class TestCommon6502 {
mpu.step() mpu.step()
assertEquals(0x0004, mpu.PC) assertEquals(0x0004, mpu.PC)
assertEquals(0x93, mpu.A) assertEquals(0x93, mpu.A)
assertFalse(mpu.Status.N)
assertFalse(mpu.Status.Z) assertFalse(mpu.Status.Z)
assertTrue(mpu.Status.C) assertTrue(mpu.Status.C)
assertTrue(mpu.Status.V) assertTrue(mpu.Status.V)
assertFalse(mpu.Status.N)
} }
// ADC Absolute, X-Indexed // ADC Absolute, X-Indexed
@ -5696,8 +5697,8 @@ abstract class TestCommon6502 {
assertEquals(0x9a, mpu.A) assertEquals(0x9a, mpu.A)
assertFalse(mpu.Status.Z) assertFalse(mpu.Status.Z)
assertTrue(mpu.Status.C) assertTrue(mpu.Status.C)
assertFalse(mpu.Status.V)
assertTrue(mpu.Status.N) assertTrue(mpu.Status.N)
assertFalse(mpu.Status.V)
} }
@Test @Test
@ -5714,9 +5715,9 @@ abstract class TestCommon6502 {
assertEquals(0x0002, mpu.PC) assertEquals(0x0002, mpu.PC)
assertEquals(0x99, mpu.A) assertEquals(0x99, mpu.A)
assertFalse(mpu.Status.Z) assertFalse(mpu.Status.Z)
assertFalse(mpu.Status.C)
assertFalse(mpu.Status.V)
assertTrue(mpu.Status.N) assertTrue(mpu.Status.N)
assertFalse(mpu.Status.V)
assertFalse(mpu.Status.C)
} }
@Test @Test
@ -5729,10 +5730,10 @@ abstract class TestCommon6502 {
mpu.step() mpu.step()
assertEquals(0x0002, mpu.PC) assertEquals(0x0002, mpu.PC)
assertEquals(0x1f, mpu.A) assertEquals(0x1f, mpu.A)
assertFalse(mpu.Status.N)
assertFalse(mpu.Status.V)
assertFalse(mpu.Status.Z) assertFalse(mpu.Status.Z)
assertTrue(mpu.Status.C) assertTrue(mpu.Status.C)
assertFalse(mpu.Status.N)
assertFalse(mpu.Status.V)
} }
// SBC Absolute, X-Indexed // SBC Absolute, X-Indexed