mirror of
https://github.com/sethm/symon.git
synced 2024-06-07 19:29:27 +00:00
BCD is finally working. I thought that would never happen.
All Immediate Mode and Implied Mode opcodes have been implemented. Next up, zero page!
This commit is contained in:
parent
06ed74e89c
commit
7766e76362
|
@ -381,11 +381,8 @@ public class Cpu implements InstructionTable {
|
|||
case 0x69: // ADC - Add with Carry - Immediate
|
||||
if (decimalModeFlag) {
|
||||
a = adcDecimal(a, operands[0]);
|
||||
clearNegativeFlag(); // All results of BCD math are positive
|
||||
setZeroFlag(a == 0);
|
||||
} else {
|
||||
a = adc(a, operands[0]);
|
||||
setArithmeticFlags(a);
|
||||
}
|
||||
break;
|
||||
case 0x6a: // n/a
|
||||
|
@ -684,14 +681,12 @@ public class Cpu implements InstructionTable {
|
|||
case 0xe9: // SBC - Subtract with Carry (Borrow) - Immediate
|
||||
if (decimalModeFlag) {
|
||||
a = sbcDecimal(a, operands[0]);
|
||||
clearNegativeFlag();
|
||||
setZeroFlag(a == 0);
|
||||
} else {
|
||||
a = sbc(a, operands[0]);
|
||||
setArithmeticFlags(a);
|
||||
}
|
||||
break;
|
||||
case 0xea: // NOP
|
||||
// Does nothing.
|
||||
break;
|
||||
case 0xeb: // n/a
|
||||
break;
|
||||
|
@ -754,33 +749,33 @@ public class Cpu implements InstructionTable {
|
|||
int carry6 = (operand & 0x7f) + (acc & 0x7f) + getCarryBit();
|
||||
setCarryFlag((result & 0x100) != 0);
|
||||
setOverflowFlag(carryFlag ^ ((carry6 & 0x80) != 0));
|
||||
result = result & 0xff;
|
||||
result &= 0xff;
|
||||
setArithmeticFlags(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add with Carry (BCD).
|
||||
*/
|
||||
|
||||
public int adcDecimal(int acc, int operand) {
|
||||
// Thank you to Doug Jones for this beautiful BCD algorithm. From:
|
||||
// http://www.cs.uiowa.edu/~jones/bcd/bcd.html
|
||||
acc += 0x066;
|
||||
int t2 = acc + operand;
|
||||
int t3 = acc ^ operand;
|
||||
int t4 = t2 ^ t3;
|
||||
int t5 = ~t4 & 0x110;
|
||||
int t6 = (t5 >> 2) | (t5 >> 3);
|
||||
int result = t2 - t6;
|
||||
if (result > 0xff) {
|
||||
result &= 0xff;
|
||||
setCarryFlag();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
int l, h, result;
|
||||
l = (acc & 0x0f) + (operand & 0x0f) + getCarryBit();
|
||||
if ((l & 0xff) > 9) l += 6;
|
||||
h = (acc >> 4) + (operand >> 4) + (l > 15 ? 1 : 0);
|
||||
if ((h & 0xff) > 9) h += 6;
|
||||
result = (l & 0x0f) | (h << 4);
|
||||
result &= 0xff;
|
||||
setCarryFlag(h > 15);
|
||||
setZeroFlag(result == 0);
|
||||
setNegativeFlag(false); // BCD is never negative
|
||||
setOverflowFlag(false); // BCD never sets overflow flag
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Common code for Subtract with Carry. Just calls ADC of the
|
||||
* one's complement of the opeerand. This lets the N, V, C, and Z
|
||||
* one's complement of the operand. This lets the N, V, C, and Z
|
||||
* flags work out nicely without any additional logic.
|
||||
*
|
||||
* @param acc
|
||||
|
@ -788,7 +783,10 @@ public class Cpu implements InstructionTable {
|
|||
* @return
|
||||
*/
|
||||
public int sbc(int acc, int operand) {
|
||||
return adc(acc, ~operand);
|
||||
int result;
|
||||
result = adc(acc, ~operand);
|
||||
setArithmeticFlags(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -799,7 +797,17 @@ public class Cpu implements InstructionTable {
|
|||
* @return
|
||||
*/
|
||||
public int sbcDecimal(int acc, int operand) {
|
||||
return adcDecimal(acc, tensComplement(operand));
|
||||
int l, h, result;
|
||||
l = (acc & 0x0f) - (operand & 0x0f) - (carryFlag ? 0 : 1);
|
||||
if ((l & 0x10) != 0) l -= 6;
|
||||
h = (acc >> 4) - (operand >> 4) - ((l & 0x10) != 0 ? 1 : 0);
|
||||
if ((h & 0x10) != 0) h -= 6;
|
||||
result = (l & 0x0f) | (h << 4);
|
||||
setCarryFlag((h & 0xff) < 15);
|
||||
setZeroFlag(result == 0);
|
||||
setNegativeFlag(false); // BCD is never negative
|
||||
setOverflowFlag(false); // BCD never sets overflow flag
|
||||
return (result & 0xff);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1241,19 +1249,4 @@ public class Cpu implements InstructionTable {
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate the 10's Complement of a byte. Used in BCD mode SBC.
|
||||
*/
|
||||
private int tensComplement(int val) {
|
||||
// Thank you to Doug Jones for this truly beautiful and obscure algorithm.
|
||||
// http://www.cs.uiowa.edu/~jones/bcd/bcd.html
|
||||
int t1 = 0xfff - val;
|
||||
int t2 = -val;
|
||||
int t3 = t1 ^ 0x001;
|
||||
int t4 = t2 ^ t3;
|
||||
int t5 = ~t4 & 0x110;
|
||||
int t6 = (t5 >> 2) | (t5 >> 3);
|
||||
return t2 - t6;
|
||||
}
|
||||
|
||||
}
|
|
@ -22,7 +22,32 @@ public class CpuImmediateModeTest extends TestCase {
|
|||
bus.write(0xfffd, (Cpu.DEFAULT_BASE_ADDRESS & 0xff00)>>>8);
|
||||
|
||||
cpu.reset();
|
||||
// Assert initial state
|
||||
assertEquals(0, cpu.getAccumulator());
|
||||
assertEquals(0, cpu.getXRegister());
|
||||
assertEquals(0, cpu.getYRegister());
|
||||
assertEquals(0x200, cpu.getProgramCounter());
|
||||
assertEquals(0xff, cpu.getStackPointer());
|
||||
assertEquals(0x20, cpu.getProcessorStatus());
|
||||
}
|
||||
|
||||
/*
|
||||
* The following opcodes are tested for correctness in this file:
|
||||
*
|
||||
* ORA - $09
|
||||
* AND - $29
|
||||
* EOR - $49
|
||||
* ADC - $69
|
||||
* LDY - $a0
|
||||
*
|
||||
* LDX - $a2
|
||||
* LDA - $a9
|
||||
* CPY - $c0
|
||||
* CMP - $c9
|
||||
* CPX - $e0
|
||||
*
|
||||
* SBC - $e9
|
||||
*/
|
||||
|
||||
/* ORA Immediate Mode Tests - 0x09 */
|
||||
|
||||
|
@ -732,4 +757,98 @@ public class CpuImmediateModeTest extends TestCase {
|
|||
assertFalse(cpu.getCarryFlag());
|
||||
|
||||
}
|
||||
|
||||
public void test_SBC_DecimalMode() {
|
||||
bus.loadProgram(0xf8,
|
||||
0xa9, 0x00,
|
||||
0xe9, 0x01);
|
||||
cpu.step(3);
|
||||
assertEquals(0x98, cpu.getAccumulator());
|
||||
assertFalse(cpu.getCarryFlag()); // borrow = set flag
|
||||
assertFalse(cpu.getNegativeFlag());
|
||||
assertFalse(cpu.getOverflowFlag());
|
||||
assertFalse(cpu.getZeroFlag());
|
||||
assertTrue(cpu.getDecimalModeFlag());
|
||||
|
||||
cpu.reset();
|
||||
|
||||
bus.loadProgram(0xf8,
|
||||
0xa9, 0x99,
|
||||
0xe9, 0x01);
|
||||
cpu.step(3);
|
||||
assertEquals(0x97, cpu.getAccumulator());
|
||||
assertTrue(cpu.getCarryFlag()); // No borrow = clear flag
|
||||
assertFalse(cpu.getNegativeFlag());
|
||||
assertFalse(cpu.getOverflowFlag());
|
||||
assertFalse(cpu.getZeroFlag());
|
||||
assertTrue(cpu.getDecimalModeFlag());
|
||||
|
||||
cpu.reset();
|
||||
|
||||
bus.loadProgram(0xf8,
|
||||
0xa9, 0x50,
|
||||
0xe9, 0x01);
|
||||
cpu.step(3);
|
||||
assertEquals(0x48, cpu.getAccumulator());
|
||||
assertTrue(cpu.getCarryFlag());
|
||||
assertFalse(cpu.getNegativeFlag());
|
||||
assertFalse(cpu.getOverflowFlag());
|
||||
assertFalse(cpu.getZeroFlag());
|
||||
assertTrue(cpu.getDecimalModeFlag());
|
||||
|
||||
|
||||
cpu.reset();
|
||||
|
||||
bus.loadProgram(0xf8, // SED
|
||||
0xa9, 0x02, // LDA #$02
|
||||
0xe9, 0x01); // SBC #$01
|
||||
cpu.step(3);
|
||||
assertEquals(0x00, cpu.getAccumulator());
|
||||
assertTrue(cpu.getCarryFlag());
|
||||
assertFalse(cpu.getNegativeFlag());
|
||||
assertFalse(cpu.getOverflowFlag());
|
||||
assertTrue(cpu.getZeroFlag());
|
||||
assertTrue(cpu.getDecimalModeFlag());
|
||||
|
||||
cpu.reset();
|
||||
|
||||
bus.loadProgram(0xf8, // SED
|
||||
0xa9, 0x10, // LDA #$10
|
||||
0xe9, 0x11); // SBC #$11
|
||||
cpu.step(3);
|
||||
assertEquals(0x98, cpu.getAccumulator());
|
||||
assertFalse(cpu.getCarryFlag());
|
||||
assertFalse(cpu.getNegativeFlag());
|
||||
assertFalse(cpu.getOverflowFlag());
|
||||
assertFalse(cpu.getZeroFlag());
|
||||
assertTrue(cpu.getDecimalModeFlag());
|
||||
|
||||
cpu.reset();
|
||||
|
||||
bus.loadProgram(0x38, // SEC
|
||||
0xf8, // SED
|
||||
0xa9, 0x05, // LDA #$05
|
||||
0xe9, 0x01); // SBC #$01
|
||||
cpu.step(4);
|
||||
assertEquals(0x04, cpu.getAccumulator());
|
||||
assertTrue(cpu.getCarryFlag());
|
||||
assertFalse(cpu.getNegativeFlag());
|
||||
assertFalse(cpu.getOverflowFlag());
|
||||
assertFalse(cpu.getZeroFlag());
|
||||
assertTrue(cpu.getDecimalModeFlag());
|
||||
|
||||
cpu.reset();
|
||||
|
||||
bus.loadProgram(0x38, // SEC
|
||||
0xf8, // SED
|
||||
0xa9, 0x00, // LDA #$00
|
||||
0xe9, 0x01); // SBC #$01
|
||||
cpu.step(4);
|
||||
assertEquals(0x99, cpu.getAccumulator());
|
||||
assertFalse(cpu.getCarryFlag());
|
||||
assertFalse(cpu.getNegativeFlag());
|
||||
assertFalse(cpu.getOverflowFlag());
|
||||
assertFalse(cpu.getZeroFlag());
|
||||
assertTrue(cpu.getDecimalModeFlag());
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user