mirror of
https://github.com/irmen/prog8.git
synced 2024-11-26 11:49:22 +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)
|
//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)
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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() {
|
||||||
|
@ -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())
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user