mirror of
https://github.com/irmen/ksim65.git
synced 2024-06-01 06:41:34 +00:00
fixed the 65c02 differences in bcd mode, all tests now pass
This commit is contained in:
parent
b4d4d1b381
commit
655e106a1d
|
@ -1,11 +1,10 @@
|
|||
package razorvine.ksim65.components
|
||||
|
||||
// TODO: implement the illegal opcodes, see http://www.ffd2.com/fridge/docs/6502-NMOS.extra.opcodes
|
||||
// TODO: add the optional additional cycles to certain instructions and addressing modes
|
||||
// TODO: add 6510 behavior mode (is there even a difference to be simulated here?)
|
||||
|
||||
/**
|
||||
* 6502 cpu simulation (the NMOS version) including the 'illegal' opcodes.
|
||||
* TODO: actually implement the illegal opcodes, see http://www.ffd2.com/fridge/docs/6502-NMOS.extra.opcodes
|
||||
* TODO: add the optional additional cycles to certain instructions and addressing modes
|
||||
*/
|
||||
open class Cpu6502(private val stopOnBrk: Boolean = false) : BusComponent() {
|
||||
var tracing: Boolean = false
|
||||
|
@ -330,7 +329,7 @@ open class Cpu6502(private val stopOnBrk: Boolean = false) : BusComponent() {
|
|||
)
|
||||
}
|
||||
|
||||
private fun getFetched() =
|
||||
protected fun getFetched() =
|
||||
if (currentInstruction.mode == AddrMode.Imm ||
|
||||
currentInstruction.mode == AddrMode.Acc ||
|
||||
currentInstruction.mode == AddrMode.Imp
|
||||
|
@ -978,7 +977,7 @@ open class Cpu6502(private val stopOnBrk: Boolean = false) : BusComponent() {
|
|||
|
||||
// official instructions
|
||||
|
||||
protected fun iAdc() {
|
||||
protected open fun iAdc() {
|
||||
val operand = getFetched()
|
||||
if (Status.D) {
|
||||
// BCD add
|
||||
|
@ -1044,7 +1043,7 @@ open class Cpu6502(private val stopOnBrk: Boolean = false) : BusComponent() {
|
|||
if (Status.Z) PC = fetchedAddress
|
||||
}
|
||||
|
||||
protected fun iBit() {
|
||||
protected open fun iBit() {
|
||||
val operand = getFetched()
|
||||
Status.Z = (A and operand) == 0
|
||||
Status.V = (operand and 0b01000000) != 0
|
||||
|
@ -1288,7 +1287,7 @@ open class Cpu6502(private val stopOnBrk: Boolean = false) : BusComponent() {
|
|||
PC = (PC + 1) and 0xffff
|
||||
}
|
||||
|
||||
protected fun iSbc() {
|
||||
protected open fun iSbc() {
|
||||
val operand = getFetched()
|
||||
val tmp = (A - operand - if (Status.C) 0 else 1) and 0xffff
|
||||
Status.V = (A xor operand) and (A xor tmp) and 0b10000000 != 0
|
||||
|
|
|
@ -2,6 +2,7 @@ package razorvine.ksim65.components
|
|||
|
||||
/**
|
||||
* 65C02 cpu simulation (the CMOS version of the 6502).
|
||||
* TODO: add the optional additional cycles to certain instructions and addressing modes
|
||||
*/
|
||||
class Cpu65C02(stopOnBrk: Boolean = false) : Cpu6502(stopOnBrk) {
|
||||
|
||||
|
@ -366,7 +367,6 @@ class Cpu65C02(stopOnBrk: Boolean = false) : Cpu6502(stopOnBrk) {
|
|||
}
|
||||
|
||||
// opcode list: http://www.oxyron.de/html/opcodesc02.html
|
||||
// TODO add optional additional cycles
|
||||
override val instructions: Array<Instruction> by lazy {
|
||||
listOf(
|
||||
/* 00 */ Instruction("brk", AddrMode.Imp, 7),
|
||||
|
@ -646,8 +646,66 @@ class Cpu65C02(stopOnBrk: Boolean = false) : Cpu6502(stopOnBrk) {
|
|||
pendingInterrupt = null
|
||||
}
|
||||
|
||||
override fun iBit() {
|
||||
val data = getFetched()
|
||||
Status.Z = (A and data) == 0
|
||||
if (currentInstruction.mode != AddrMode.Imm) {
|
||||
Status.V = (data and 0b01000000) != 0
|
||||
Status.N = (data and 0b10000000) != 0
|
||||
}
|
||||
}
|
||||
|
||||
override fun iAdc() {
|
||||
val value = getFetched()
|
||||
if (Status.D) {
|
||||
// BCD add
|
||||
// see http://www.6502.org/tutorials/decimal_mode.html
|
||||
// and https://sourceforge.net/p/vice-emu/code/HEAD/tree/trunk/vice/src/65c02core.c#l542
|
||||
// (the implementation below is based on the code used by Vice)
|
||||
var tmp = (A and 0x0f) + (value and 0x0f) + if (Status.C) 1 else 0
|
||||
var tmp2 = (A and 0xf0) + (value and 0xf0)
|
||||
if (tmp > 9) {
|
||||
tmp2 += 0x10
|
||||
tmp += 6
|
||||
}
|
||||
Status.V = (A xor value).inv() and (A xor tmp2) and 0b10000000 != 0
|
||||
if (tmp2 > 0x90) tmp2 += 0x60
|
||||
Status.C = tmp2 >= 0x100
|
||||
tmp = (tmp and 0x0f) + (tmp2 and 0xf0)
|
||||
Status.N = (tmp and 0b10000000) != 0
|
||||
Status.Z = tmp == 0
|
||||
A = tmp and 0xff
|
||||
} else {
|
||||
// normal add (identical to 6502)
|
||||
val tmp = value + A + if (Status.C) 1 else 0
|
||||
Status.N = (tmp and 0b10000000) != 0
|
||||
Status.Z = (tmp and 0xff) == 0
|
||||
Status.V = (A xor value).inv() and (A xor tmp) and 0b10000000 != 0
|
||||
Status.C = tmp > 0xff
|
||||
A = tmp and 0xff
|
||||
}
|
||||
}
|
||||
|
||||
override fun iSbc() {
|
||||
// see http://www.6502.org/tutorials/decimal_mode.html
|
||||
// and https://sourceforge.net/p/vice-emu/code/HEAD/tree/trunk/vice/src/65c02core.c#l1205
|
||||
// (the implementation below is based on the code used by Vice)
|
||||
val value = getFetched()
|
||||
var tmp = (A - value - if (Status.C) 0 else 1) and 0xffff
|
||||
Status.V = (A xor tmp) and (A xor value) and 0b10000000 != 0
|
||||
if (Status.D) {
|
||||
if (tmp > 0xff) tmp = (tmp - 0x60) and 0xffff
|
||||
val tmp2 = ((A and 0x0f) - (value and 0x0f) - if (Status.C) 0 else 1) and 0xffff
|
||||
if (tmp2 > 0xff) tmp -= 6
|
||||
}
|
||||
Status.C = (A - if (Status.C) 0 else 1) >= value
|
||||
Status.Z = (tmp and 0xff) == 0
|
||||
Status.N = (tmp and 0b10000000) != 0
|
||||
A = tmp and 0xff
|
||||
}
|
||||
|
||||
override fun iDec() {
|
||||
if(currentInstruction.mode==AddrMode.Acc) {
|
||||
if (currentInstruction.mode == AddrMode.Acc) {
|
||||
A = (A - 1) and 0xff
|
||||
Status.Z = A == 0
|
||||
Status.N = (A and 0b10000000) != 0
|
||||
|
@ -655,7 +713,7 @@ class Cpu65C02(stopOnBrk: Boolean = false) : Cpu6502(stopOnBrk) {
|
|||
}
|
||||
|
||||
override fun iInc() {
|
||||
if(currentInstruction.mode==AddrMode.Acc) {
|
||||
if (currentInstruction.mode == AddrMode.Acc) {
|
||||
A = (A + 1) and 0xff
|
||||
Status.Z = A == 0
|
||||
Status.N = (A and 0b10000000) != 0
|
||||
|
@ -668,15 +726,15 @@ class Cpu65C02(stopOnBrk: Boolean = false) : Cpu6502(stopOnBrk) {
|
|||
}
|
||||
|
||||
private fun iTrb() {
|
||||
val m = read(fetchedAddress)
|
||||
Status.Z = m and A ==0
|
||||
write(fetchedAddress, m and A.inv())
|
||||
val data = getFetched()
|
||||
Status.Z = data and A == 0
|
||||
write(fetchedAddress, data and A.inv())
|
||||
}
|
||||
|
||||
private fun iTsb() {
|
||||
val m = read(fetchedAddress)
|
||||
Status.Z = m and A ==0
|
||||
write(fetchedAddress, m or A)
|
||||
val data = getFetched()
|
||||
Status.Z = data and A == 0
|
||||
write(fetchedAddress, data or A)
|
||||
}
|
||||
|
||||
private fun iStz() {
|
||||
|
@ -712,178 +770,178 @@ class Cpu65C02(stopOnBrk: Boolean = false) : Cpu6502(stopOnBrk) {
|
|||
}
|
||||
|
||||
private fun iBbr0() {
|
||||
val data = read(fetchedAddress)
|
||||
if(data and 1 == 0)
|
||||
val data = getFetched()
|
||||
if (data and 1 == 0)
|
||||
PC = fetchedAddressZpr
|
||||
}
|
||||
|
||||
private fun iBbr1() {
|
||||
val data = read(fetchedAddress)
|
||||
if(data and 2 == 0)
|
||||
val data = getFetched()
|
||||
if (data and 2 == 0)
|
||||
PC = fetchedAddressZpr
|
||||
}
|
||||
|
||||
private fun iBbr2() {
|
||||
val data = read(fetchedAddress)
|
||||
if(data and 4 == 0)
|
||||
val data = getFetched()
|
||||
if (data and 4 == 0)
|
||||
PC = fetchedAddressZpr
|
||||
}
|
||||
|
||||
private fun iBbr3() {
|
||||
val data = read(fetchedAddress)
|
||||
if(data and 8 == 0)
|
||||
val data = getFetched()
|
||||
if (data and 8 == 0)
|
||||
PC = fetchedAddressZpr
|
||||
}
|
||||
|
||||
private fun iBbr4() {
|
||||
val data = read(fetchedAddress)
|
||||
if(data and 16 == 0)
|
||||
val data = getFetched()
|
||||
if (data and 16 == 0)
|
||||
PC = fetchedAddressZpr
|
||||
}
|
||||
|
||||
private fun iBbr5() {
|
||||
val data = read(fetchedAddress)
|
||||
if(data and 32 == 0)
|
||||
val data = getFetched()
|
||||
if (data and 32 == 0)
|
||||
PC = fetchedAddressZpr
|
||||
}
|
||||
|
||||
private fun iBbr6() {
|
||||
val data = read(fetchedAddress)
|
||||
if(data and 64 == 0)
|
||||
val data = getFetched()
|
||||
if (data and 64 == 0)
|
||||
PC = fetchedAddressZpr
|
||||
}
|
||||
|
||||
private fun iBbr7() {
|
||||
val data = read(fetchedAddress)
|
||||
if(data and 128 == 0)
|
||||
val data = getFetched()
|
||||
if (data and 128 == 0)
|
||||
PC = fetchedAddressZpr
|
||||
}
|
||||
|
||||
private fun iBbs0() {
|
||||
val data = read(fetchedAddress)
|
||||
if(data and 1 != 0)
|
||||
val data = getFetched()
|
||||
if (data and 1 != 0)
|
||||
PC = fetchedAddressZpr
|
||||
}
|
||||
|
||||
private fun iBbs1() {
|
||||
val data = read(fetchedAddress)
|
||||
if(data and 2 != 0)
|
||||
val data = getFetched()
|
||||
if (data and 2 != 0)
|
||||
PC = fetchedAddressZpr
|
||||
}
|
||||
|
||||
private fun iBbs2() {
|
||||
val data = read(fetchedAddress)
|
||||
if(data and 4 != 0)
|
||||
val data = getFetched()
|
||||
if (data and 4 != 0)
|
||||
PC = fetchedAddressZpr
|
||||
}
|
||||
|
||||
private fun iBbs3() {
|
||||
val data = read(fetchedAddress)
|
||||
if(data and 8 != 0)
|
||||
val data = getFetched()
|
||||
if (data and 8 != 0)
|
||||
PC = fetchedAddressZpr
|
||||
}
|
||||
|
||||
private fun iBbs4() {
|
||||
val data = read(fetchedAddress)
|
||||
if(data and 16 != 0)
|
||||
val data = getFetched()
|
||||
if (data and 16 != 0)
|
||||
PC = fetchedAddressZpr
|
||||
}
|
||||
|
||||
private fun iBbs5() {
|
||||
val data = read(fetchedAddress)
|
||||
if(data and 32 != 0)
|
||||
val data = getFetched()
|
||||
if (data and 32 != 0)
|
||||
PC = fetchedAddressZpr
|
||||
}
|
||||
|
||||
private fun iBbs6() {
|
||||
val data = read(fetchedAddress)
|
||||
if(data and 64 != 0)
|
||||
val data = getFetched()
|
||||
if (data and 64 != 0)
|
||||
PC = fetchedAddressZpr
|
||||
}
|
||||
|
||||
private fun iBbs7() {
|
||||
val data = read(fetchedAddress)
|
||||
if(data and 128 != 0)
|
||||
val data = getFetched()
|
||||
if (data and 128 != 0)
|
||||
PC = fetchedAddressZpr
|
||||
}
|
||||
|
||||
private fun iSmb0() {
|
||||
val data = read(fetchedAddress)
|
||||
val data = getFetched()
|
||||
write(fetchedAddress, data or 1)
|
||||
}
|
||||
|
||||
private fun iSmb1() {
|
||||
val data = read(fetchedAddress)
|
||||
val data = getFetched()
|
||||
write(fetchedAddress, data or 2)
|
||||
}
|
||||
|
||||
private fun iSmb2() {
|
||||
val data = read(fetchedAddress)
|
||||
val data = getFetched()
|
||||
write(fetchedAddress, data or 4)
|
||||
}
|
||||
|
||||
private fun iSmb3() {
|
||||
val data = read(fetchedAddress)
|
||||
val data = getFetched()
|
||||
write(fetchedAddress, data or 8)
|
||||
}
|
||||
|
||||
private fun iSmb4() {
|
||||
val data = read(fetchedAddress)
|
||||
val data = getFetched()
|
||||
write(fetchedAddress, data or 16)
|
||||
}
|
||||
|
||||
private fun iSmb5() {
|
||||
val data = read(fetchedAddress)
|
||||
val data = getFetched()
|
||||
write(fetchedAddress, data or 32)
|
||||
}
|
||||
|
||||
private fun iSmb6() {
|
||||
val data = read(fetchedAddress)
|
||||
val data = getFetched()
|
||||
write(fetchedAddress, data or 64)
|
||||
}
|
||||
|
||||
private fun iSmb7() {
|
||||
val data = read(fetchedAddress)
|
||||
val data = getFetched()
|
||||
write(fetchedAddress, data or 128)
|
||||
}
|
||||
|
||||
private fun iRmb0() {
|
||||
val data = read(fetchedAddress)
|
||||
val data = getFetched()
|
||||
write(fetchedAddress, data and 0b11111110)
|
||||
}
|
||||
|
||||
private fun iRmb1() {
|
||||
val data = read(fetchedAddress)
|
||||
val data = getFetched()
|
||||
write(fetchedAddress, data and 0b11111101)
|
||||
}
|
||||
|
||||
private fun iRmb2() {
|
||||
val data = read(fetchedAddress)
|
||||
val data = getFetched()
|
||||
write(fetchedAddress, data and 0b11111011)
|
||||
}
|
||||
|
||||
private fun iRmb3() {
|
||||
val data = read(fetchedAddress)
|
||||
val data = getFetched()
|
||||
write(fetchedAddress, data and 0b11110111)
|
||||
}
|
||||
|
||||
private fun iRmb4() {
|
||||
val data = read(fetchedAddress)
|
||||
val data = getFetched()
|
||||
write(fetchedAddress, data and 0b11101111)
|
||||
}
|
||||
|
||||
private fun iRmb5() {
|
||||
val data = read(fetchedAddress)
|
||||
val data = getFetched()
|
||||
write(fetchedAddress, data and 0b11011111)
|
||||
}
|
||||
|
||||
private fun iRmb6() {
|
||||
val data = read(fetchedAddress)
|
||||
val data = getFetched()
|
||||
write(fetchedAddress, data and 0b10111111)
|
||||
}
|
||||
|
||||
private fun iRmb7() {
|
||||
val data = read(fetchedAddress)
|
||||
val data = getFetched()
|
||||
write(fetchedAddress, data and 0b01111111)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
#include <stdio.h>
|
||||
|
||||
/*
|
||||
testing 6502/6510 core ADC and SBC from Vice
|
||||
*/
|
||||
|
||||
static int flag_Z;
|
||||
static int flag_C;
|
||||
static int flag_N;
|
||||
|
@ -60,13 +64,13 @@ unsigned int SBC(unsigned int A, unsigned int value, unsigned int bcd_mode)
|
|||
flag_Z = (tmp&0xff)==0;
|
||||
flag_N = (tmp&0x80)!=0;
|
||||
flag_V = ((A ^ tmp) & 0x80) && ((A ^ src) & 0x80);
|
||||
return tmp_a && 255;
|
||||
return tmp_a & 0xff;
|
||||
} else {
|
||||
flag_Z = (tmp&0xff)==0;
|
||||
flag_N = (tmp&0x80)!=0;
|
||||
flag_C = tmp < 0x100;
|
||||
flag_V = ((A ^ tmp) & 0x80) && ((A ^ src) & 0x80);
|
||||
return tmp && 255;
|
||||
return tmp & 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -81,6 +85,8 @@ void print_result(int result) {
|
|||
}
|
||||
|
||||
int main(char* argv) {
|
||||
printf("6502 adc/sbc simulation\n");
|
||||
|
||||
flag_C = flag_N = flag_V = flag_Z = 0;
|
||||
|
||||
for(unsigned int A=0; A<256; ++A) {
|
151
src/test/c/bcd_vice_sim_65c02.c
Normal file
151
src/test/c/bcd_vice_sim_65c02.c
Normal file
|
@ -0,0 +1,151 @@
|
|||
#include <stdio.h>
|
||||
|
||||
/*
|
||||
testing 65c02 core ADC and SBC from Vice
|
||||
*/
|
||||
|
||||
static int flag_Z;
|
||||
static int flag_C;
|
||||
static int flag_N;
|
||||
static int flag_V;
|
||||
|
||||
unsigned int ADC(unsigned int A, unsigned int value, unsigned int bcd_mode)
|
||||
{
|
||||
unsigned int tmp, tmp2;
|
||||
unsigned int tmp_value = value;
|
||||
|
||||
if (bcd_mode) {
|
||||
tmp = (A & 0xf) + (tmp_value & 0xf) + flag_C;
|
||||
tmp2 = (A & 0xf0) + (tmp_value & 0xf0);
|
||||
if (tmp > 9) {
|
||||
tmp2 += 0x10;
|
||||
tmp += 6;
|
||||
}
|
||||
flag_V = ~(A ^ tmp_value) & (A ^ tmp2) & 0x80;
|
||||
if (tmp2 > 0x90) {
|
||||
tmp2 += 0x60;
|
||||
}
|
||||
flag_C = (tmp2 & 0xff00)!=0;
|
||||
tmp = (tmp & 0xf) + (tmp2 & 0xf0);
|
||||
flag_Z = tmp==0;
|
||||
flag_N = tmp&0x80!=0;
|
||||
} else {
|
||||
tmp = tmp_value + A + flag_C;
|
||||
flag_Z = (tmp&0xff)==0;
|
||||
flag_N = (tmp&0x80)!=0;
|
||||
flag_V = !((A ^ tmp_value) & 0x80) && ((A ^ tmp) & 0x80);
|
||||
flag_C = tmp > 0xff;
|
||||
}
|
||||
return tmp & 0xff;
|
||||
}
|
||||
|
||||
unsigned int SBC(unsigned int A, unsigned int value, unsigned int bcd_mode)
|
||||
{
|
||||
unsigned int src = value;
|
||||
unsigned int tmp = A - src + flag_C - 1;
|
||||
flag_V = (((A ^ tmp) & 0x80) && ((A ^ src) & 0x80));
|
||||
if (bcd_mode) {
|
||||
if (tmp > 0xff) {
|
||||
tmp -= 0x60;
|
||||
}
|
||||
unsigned int tmp2 = (A & 0xf) - (src & 0xf) + flag_C - 1;
|
||||
if (tmp2 > 0xff) {
|
||||
tmp -= 6;
|
||||
}
|
||||
}
|
||||
flag_C = (A + flag_C - 1 >= src);
|
||||
flag_Z = (tmp&0xff)==0;
|
||||
flag_N = (tmp&0x80)!=0;
|
||||
return tmp & 0xff;
|
||||
}
|
||||
|
||||
|
||||
void print_result(int result) {
|
||||
printf(" %02x", result);
|
||||
printf(" N=%d", flag_N? 1:0);
|
||||
printf(" V=%d", flag_V? 1:0);
|
||||
printf(" Z=%d", flag_Z? 1:0);
|
||||
printf(" C=%d", flag_C? 1:0);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
int main(char* argv) {
|
||||
printf("65c02 adc/sbc simulation\n");
|
||||
|
||||
flag_C = flag_N = flag_V = flag_Z = 0;
|
||||
|
||||
for(unsigned int A=0; A<256; ++A) {
|
||||
for(unsigned int v=0; v<256; ++v) {
|
||||
flag_C = 0;
|
||||
printf("adc,normal,carry0: %02x + %02x = ", A, v);
|
||||
unsigned int result = ADC(A, v, 0);
|
||||
print_result(result);
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
for(unsigned int A=0; A<256; ++A) {
|
||||
for(unsigned int v=0; v<256; ++v) {
|
||||
flag_C = 1;
|
||||
printf("adc,normal,carry1: %02x + %02x = ", A, v);
|
||||
unsigned int result = ADC(A, v, 0);
|
||||
print_result(result);
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
for(unsigned int A=0; A<256; ++A) {
|
||||
for(unsigned int v=0; v<256; ++v) {
|
||||
flag_C = 0;
|
||||
printf("adc,bcd,carry0: %02x + %02x = ", A, v);
|
||||
unsigned int result = ADC(A, v, 1);
|
||||
print_result(result);
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
for(unsigned int A=0; A<256; ++A) {
|
||||
for(unsigned int v=0; v<256; ++v) {
|
||||
flag_C = 1;
|
||||
printf("adc,bcd,carry1: %02x + %02x = ", A, v);
|
||||
unsigned int result = ADC(A, v, 1);
|
||||
print_result(result);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
for(unsigned int A=0; A<256; ++A) {
|
||||
for(unsigned int v=0; v<256; ++v) {
|
||||
flag_C = 0;
|
||||
printf("sbc,normal,carry0: %02x - %02x = ", A, v);
|
||||
unsigned int result = SBC(A, v, 0);
|
||||
print_result(result);
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
for(unsigned int A=0; A<256; ++A) {
|
||||
for(unsigned int v=0; v<256; ++v) {
|
||||
flag_C = 1;
|
||||
printf("sbc,normal,carry1: %02x - %02x = ", A, v);
|
||||
unsigned int result = SBC(A, v, 0);
|
||||
print_result(result);
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
for(unsigned int A=0; A<256; ++A) {
|
||||
for(unsigned int v=0; v<256; ++v) {
|
||||
flag_C = 0;
|
||||
printf("sbc,bcd,carry0: %02x - %02x = ", A, v);
|
||||
unsigned int result = SBC(A, v, 1);
|
||||
print_result(result);
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
for(unsigned int A=0; A<256; ++A) {
|
||||
for(unsigned int v=0; v<256; ++v) {
|
||||
flag_C = 1;
|
||||
printf("sbc,bcd,carry1: %02x - %02x = ", A, v);
|
||||
unsigned int result = SBC(A, v, 1);
|
||||
print_result(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -320,4 +320,42 @@ class Test6502 : TestCommon6502() {
|
|||
mpu.step()
|
||||
assertEquals(0x3f, mpu.A)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun test_sbc_bcd_on_immediate_20_minus_0a_carry_unset() {
|
||||
mpu.Status.D = true
|
||||
mpu.Status.C = false
|
||||
mpu.A = 0x20
|
||||
// $0000 SBC #$0a
|
||||
writeMem(memory, 0x0000, listOf(0xe9, 0x0a))
|
||||
mpu.step()
|
||||
assertEquals(0x0002, mpu.PC)
|
||||
assertEquals(0x1f, mpu.A) // 0x1f on 6502, 0x0f on 65c02
|
||||
assertFalse(mpu.Status.Z)
|
||||
assertTrue(mpu.Status.C)
|
||||
assertFalse(mpu.Status.N)
|
||||
assertFalse(mpu.Status.V)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun test_adc_bcd_on_immediate_9c_plus_9d() {
|
||||
mpu.Status.D = true
|
||||
mpu.Status.C = false
|
||||
mpu.Status.N = true
|
||||
mpu.A = 0x9c
|
||||
// $0000 ADC #$9d
|
||||
// $0002 ADC #$9d
|
||||
writeMem(memory, 0x0000, listOf(0x69, 0x9d))
|
||||
writeMem(memory, 0x0002, listOf(0x69, 0x9d))
|
||||
mpu.step()
|
||||
assertEquals(0x9f, mpu.A)
|
||||
assertTrue(mpu.Status.C)
|
||||
mpu.step()
|
||||
assertEquals(0x0004, mpu.PC)
|
||||
assertEquals(0x93, mpu.A)
|
||||
assertFalse(mpu.Status.Z)
|
||||
assertTrue(mpu.Status.C)
|
||||
assertTrue(mpu.Status.V)
|
||||
assertFalse(mpu.Status.N) // False on 6502, True on 65C02
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import razorvine.ksim65.components.Bus
|
||||
import razorvine.ksim65.components.Ram
|
||||
import razorvine.ksim65.components.Cpu6502
|
||||
import razorvine.ksim65.components.Cpu65C02
|
||||
import java.lang.Exception
|
||||
import kotlin.test.*
|
||||
|
||||
|
@ -10,7 +11,7 @@ class Test6502Functional {
|
|||
private class SuccessfulTestResult: Exception()
|
||||
|
||||
@Test
|
||||
fun testFunctional() {
|
||||
fun testFunctional6502() {
|
||||
val cpu = Cpu6502(false)
|
||||
val bus = Bus()
|
||||
val ram = Ram(0, 0xffff)
|
||||
|
@ -26,7 +27,38 @@ class Test6502Functional {
|
|||
}
|
||||
|
||||
try {
|
||||
while (cpu.totalCycles < 900000000) {
|
||||
while (cpu.totalCycles < 100000000) {
|
||||
cpu.clock()
|
||||
}
|
||||
} catch (sx: SuccessfulTestResult) {
|
||||
println("test successful ${cpu.totalCycles}")
|
||||
return
|
||||
}
|
||||
|
||||
cpu.printState()
|
||||
val d = cpu.disassemble(ram, cpu.PC-20, cpu.PC+20)
|
||||
println(d.joinToString ("\n"))
|
||||
fail("test failed")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testFunctional65C02() {
|
||||
val cpu = Cpu65C02(false)
|
||||
val bus = Bus()
|
||||
val ram = Ram(0, 0xffff)
|
||||
ram.load("src/test/kotlin/6502_functional_tests/bin_files/65C02_extended_opcodes_test.bin", 0)
|
||||
bus.add(cpu)
|
||||
bus.add(ram)
|
||||
cpu.reset()
|
||||
cpu.PC = 0x0400
|
||||
cpu.breakpoint(0x24f1) { _, _ ->
|
||||
// reaching this address means successful test result
|
||||
if(cpu.currentOpcode==0x4c)
|
||||
throw SuccessfulTestResult()
|
||||
}
|
||||
|
||||
try {
|
||||
while (cpu.totalCycles < 100000000) {
|
||||
cpu.clock()
|
||||
}
|
||||
} catch (sx: SuccessfulTestResult) {
|
||||
|
|
|
@ -7,7 +7,7 @@ import kotlin.test.*
|
|||
|
||||
|
||||
@TestInstance(TestInstance.Lifecycle.PER_METHOD)
|
||||
//@Disabled("this test suite takes a long time")
|
||||
@Disabled("this test suite takes a long time")
|
||||
class Test6502TestSuite {
|
||||
|
||||
val cpu: Cpu6502 = Cpu6502(stopOnBrk = false)
|
||||
|
|
|
@ -1604,4 +1604,42 @@ class Test65C02 : TestCommon6502() {
|
|||
mpu.step()
|
||||
assertEquals(0x0043, mpu.PC)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun test_sbc_bcd_on_immediate_20_minus_0a_carry_unset() {
|
||||
mpu.Status.D = true
|
||||
mpu.Status.C = false
|
||||
mpu.A = 0x20
|
||||
// $0000 SBC #$0a
|
||||
writeMem(memory, 0x0000, listOf(0xe9, 0x0a))
|
||||
mpu.step()
|
||||
assertEquals(0x0002, mpu.PC)
|
||||
assertEquals(0x0f, mpu.A) // 0x1f on 6502, 0x0f on 65c02
|
||||
assertFalse(mpu.Status.Z)
|
||||
assertTrue(mpu.Status.C)
|
||||
assertFalse(mpu.Status.N)
|
||||
assertFalse(mpu.Status.V)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun test_adc_bcd_on_immediate_9c_plus_9d() {
|
||||
mpu.Status.D = true
|
||||
mpu.Status.C = false
|
||||
mpu.Status.N = true
|
||||
mpu.A = 0x9c
|
||||
// $0000 ADC #$9d
|
||||
// $0002 ADC #$9d
|
||||
writeMem(memory, 0x0000, listOf(0x69, 0x9d))
|
||||
writeMem(memory, 0x0002, listOf(0x69, 0x9d))
|
||||
mpu.step()
|
||||
assertEquals(0x9f, mpu.A)
|
||||
assertTrue(mpu.Status.C)
|
||||
mpu.step()
|
||||
assertEquals(0x0004, mpu.PC)
|
||||
assertEquals(0x93, mpu.A)
|
||||
assertFalse(mpu.Status.Z)
|
||||
assertTrue(mpu.Status.C)
|
||||
assertTrue(mpu.Status.V)
|
||||
assertTrue(mpu.Status.N) // False on 6502, True on 65C02
|
||||
}
|
||||
}
|
||||
|
|
|
@ -491,28 +491,6 @@ abstract class TestCommon6502 {
|
|||
assertFalse(mpu.Status.C)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun test_adc_bcd_on_immediate_9c_plus_9d() {
|
||||
mpu.Status.D = true
|
||||
mpu.Status.C = false
|
||||
mpu.Status.N = true
|
||||
mpu.A = 0x9c
|
||||
// $0000 ADC #$9d
|
||||
// $0002 ADC #$9d
|
||||
writeMem(memory, 0x0000, listOf(0x69, 0x9d))
|
||||
writeMem(memory, 0x0002, listOf(0x69, 0x9d))
|
||||
mpu.step()
|
||||
assertEquals(0x9f, mpu.A)
|
||||
assertTrue(mpu.Status.C)
|
||||
mpu.step()
|
||||
assertEquals(0x0004, mpu.PC)
|
||||
assertEquals(0x93, mpu.A)
|
||||
assertFalse(mpu.Status.Z)
|
||||
assertTrue(mpu.Status.C)
|
||||
assertTrue(mpu.Status.V)
|
||||
assertFalse(mpu.Status.N)
|
||||
}
|
||||
|
||||
// ADC Absolute, X-Indexed
|
||||
|
||||
@Test
|
||||
|
@ -5142,22 +5120,6 @@ abstract class TestCommon6502 {
|
|||
assertFalse(mpu.Status.C)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun test_sbc_bcd_on_immediate_20_minus_0a_carry_unset() {
|
||||
mpu.Status.D = true
|
||||
mpu.Status.C = false
|
||||
mpu.A = 0x20
|
||||
// $0000 SBC #$0a
|
||||
writeMem(memory, 0x0000, listOf(0xe9, 0x0a))
|
||||
mpu.step()
|
||||
assertEquals(0x0002, mpu.PC)
|
||||
assertEquals(0x1f, mpu.A)
|
||||
assertFalse(mpu.Status.Z)
|
||||
assertTrue(mpu.Status.C)
|
||||
assertFalse(mpu.Status.N)
|
||||
assertFalse(mpu.Status.V)
|
||||
}
|
||||
|
||||
// SBC Absolute, X-Indexed
|
||||
|
||||
@Test
|
||||
|
|
Loading…
Reference in New Issue
Block a user