1
0
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:
Seth J. Morabito 2008-12-27 01:43:07 -08:00
parent 06ed74e89c
commit 7766e76362
2 changed files with 152 additions and 40 deletions

View File

@ -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;
}
}

View File

@ -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());
}
}