1
0
mirror of https://github.com/sethm/symon.git synced 2024-06-07 19:29:27 +00:00

Started on Zero Page opcodes and tests.

This commit is contained in:
Seth J. Morabito 2008-12-27 13:01:07 -08:00
parent de0742f59f
commit ecde55c6b8
6 changed files with 346 additions and 126 deletions

View File

@ -18,7 +18,7 @@ public class Cpu implements InstructionTable {
// Bit 5 is always '1'
public static final int P_OVERFLOW = 0x40;
public static final int P_NEGATIVE = 0x80;
// NMI vector
public static final int IRQ_VECTOR_L = 0xfffa;
public static final int IRQ_VECTOR_H = 0xfffb;
@ -28,7 +28,7 @@ public class Cpu implements InstructionTable {
// IRQ vector
public static final int NMI_VECTOR_L = 0xfffe;
public static final int NMI_VECTOR_H = 0xffff;
/* The Bus */
private Bus bus;
@ -42,6 +42,11 @@ public class Cpu implements InstructionTable {
private int sp; // Stack Pointer register, offset into page 1
private int ir; // Instruction register
/* Internal scratch space */
private int lo = 0, hi = 0; // Used in address calculation
private int j = 0, k = 0; // Used for temporary storage
/* Operands for the current instruction */
private int[] operands = new int[2];
private int addr; // The address the most recent instruction
@ -83,7 +88,7 @@ public class Cpu implements InstructionTable {
sp = 0xff;
// Set the PC to the address stored in the reset vector
pc = CpuUtils.address(bus.read(RST_VECTOR_L), bus.read(RST_VECTOR_H));
pc = address(bus.read(RST_VECTOR_L), bus.read(RST_VECTOR_H));
// Clear instruction register.
ir = 0;
@ -106,8 +111,6 @@ public class Cpu implements InstructionTable {
* Performs an individual machine cycle.
*/
public void step() {
int lo, hi; // Used in address calculation
// Store the address from which the IR was read, for debugging
addr = pc;
@ -139,7 +142,7 @@ public class Cpu implements InstructionTable {
// Set the Interrupt Disabled flag. RTI will clear it.
setIrqDisableFlag();
// Load interrupt vector address into PC
pc = CpuUtils.address(bus.read(IRQ_VECTOR_L), bus.read(IRQ_VECTOR_H));
pc = address(bus.read(IRQ_VECTOR_L), bus.read(IRQ_VECTOR_H));
}
break;
case 0x01: // n/a
@ -150,9 +153,13 @@ public class Cpu implements InstructionTable {
break;
case 0x04: // n/a
break;
case 0x05: // n/a
case 0x05: // ORA - Logical Inclusive OR - Zero Page
a |= bus.read(operands[0]);
setArithmeticFlags(a);
break;
case 0x06: // n/a
case 0x06: // ASL - Arithmetic Shift Left - Zero Page
bus.write(operands[0], asl(bus.read(operands[0])));
setArithmeticFlags(bus.read(operands[0]));
break;
case 0x07: // n/a
break;
@ -218,7 +225,12 @@ public class Cpu implements InstructionTable {
break;
case 0x23: // n/a
break;
case 0x24: // n/a
case 0x24: // BIT - Bit Test - Zero Page
j = bus.read(operands[0]);
k = a & j;
setZeroFlag(k == 0);
setNegativeFlag((k & 0x80) != 0);
setOverflowFlag((k & 0x40) != 0);
break;
case 0x25: // n/a
break;
@ -284,7 +296,7 @@ public class Cpu implements InstructionTable {
setProcessorStatus(stackPop());
lo = stackPop();
hi = stackPop();
setProgramCounter(CpuUtils.address(lo, hi));
setProgramCounter(address(lo, hi));
break;
case 0x41: // n/a
break;
@ -312,7 +324,7 @@ public class Cpu implements InstructionTable {
case 0x4b: // n/a
break;
case 0x4c: // JMP - Jump - Absolute
pc = CpuUtils.address(operands[0], operands[1]);
pc = address(operands[0], operands[1]);
break;
case 0x4d: // n/a
break;
@ -358,7 +370,7 @@ public class Cpu implements InstructionTable {
case 0x60: // RTS - Return from Subroutine - Implied
lo = stackPop();
hi = stackPop();
setProgramCounter((CpuUtils.address(lo, hi) + 1) & 0xffff);
setProgramCounter((address(lo, hi) + 1) & 0xffff);
break;
case 0x61: // n/a
break;
@ -753,17 +765,17 @@ public class Cpu implements InstructionTable {
setArithmeticFlags(result);
return result;
}
/**
* Add with Carry (BCD).
*/
public int adcDecimal(int acc, int operand) {
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;
if ((h & 0xff) > 9) h += 6;
result = (l & 0x0f) | (h << 4);
result &= 0xff;
setCarryFlag(h > 15);
@ -771,13 +783,13 @@ public class Cpu implements InstructionTable {
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 operand. This lets the N, V, C, and Z
* flags work out nicely without any additional logic.
*
*
* @param acc
* @param operand
* @return
@ -788,10 +800,10 @@ public class Cpu implements InstructionTable {
setArithmeticFlags(result);
return result;
}
/**
* Subtract with Carry, BCD mode.
*
*
* @param acc
* @param operand
* @return
@ -813,7 +825,7 @@ public class Cpu implements InstructionTable {
/**
* Compare two values, and set carry, zero, and negative flags
* appropriately.
*
*
* @param reg
* @param operand
*/
@ -833,7 +845,28 @@ public class Cpu implements InstructionTable {
zeroFlag = (reg == 0);
negativeFlag = (reg & 0x80) != 0;
}
/**
* Shifts the given value left by one bit, and sets the carry
* flag to the high bit of the initial value.
*
* @param m The value to shift left.
* @return the left shifted value (m * 2).
*/
private int asl(int m) {
setCarryFlag((m & 0x80) != 0);
return (m << 1) & 0xff;
}
/**
* Shifts the given value right by one bit, filling with zeros,
* and sets the carry flag to the low bit of the initial value.
*/
private int lsr(int m) {
setCarryFlag((m & 0x01) != 0);
return (m >>> 1) & 0xff;
}
/**
* @return the negative flag
*/
@ -876,7 +909,7 @@ public class Cpu implements InstructionTable {
public boolean getCarryFlag() {
return carryFlag;
}
/**
* @return 1 if the carry flag is set, 0 if it is clear.
*/
@ -946,7 +979,7 @@ public class Cpu implements InstructionTable {
public boolean getIrqDisableFlag() {
return irqDisableFlag;
}
/**
* @return 1 if the interrupt disable flag is set, 0 if it is clear.
*/
@ -1011,7 +1044,7 @@ public class Cpu implements InstructionTable {
public boolean getBreakFlag() {
return breakFlag;
}
/**
* @return 1 if the break flag is set, 0 if it is clear.
*/
@ -1046,7 +1079,7 @@ public class Cpu implements InstructionTable {
public boolean getOverflowFlag() {
return overflowFlag;
}
/**
* @return 1 if the overflow flag is set, 0 if it is clear.
*/
@ -1191,7 +1224,7 @@ public class Cpu implements InstructionTable {
* Returns a string representing the CPU state.
*/
public String toString() {
String opcode = CpuUtils.opcode(ir, operands[0], operands[1]);
String opcode = opcode(ir, operands[0], operands[1]);
StringBuffer sb = new StringBuffer(String.format("$%04X", addr) +
" ");
sb.append(String.format("%-14s", opcode));
@ -1241,7 +1274,7 @@ public class Cpu implements InstructionTable {
/*
* Increment the PC, rolling over if necessary.
*/
protected void incrementPC() {
void incrementPC() {
if (pc == 0xffff) {
pc = 0;
} else {
@ -1249,4 +1282,34 @@ public class Cpu implements InstructionTable {
}
}
/**
* Given two bytes, return an address.
*/
int address(int lowByte, int hiByte) {
return ((hiByte<<8)|lowByte);
}
/**
* Given an opcode and its operands, return a formatted name.
*
* @param opcode
* @param operands
* @return
*/
String opcode(int opcode, int op1, int op2) {
String opcodeName = Cpu.opcodeNames[opcode];
if (opcodeName == null) { return "???"; }
StringBuffer sb = new StringBuffer(opcodeName);
switch (Cpu.instructionModes[opcode]) {
case ABS:
sb.append(String.format(" $%04X", address(op1, op2)));
break;
case IMM:
sb.append(String.format(" #$%02X", op1));
}
return sb.toString();
}
}

View File

@ -1,37 +0,0 @@
package com.loomcom.symon;
import com.loomcom.symon.InstructionTable.Mode;
public class CpuUtils {
/**
* Given two bytes, return an address.
*/
public static int address(int lowByte, int hiByte) {
return ((hiByte<<8)|lowByte);
}
/**
* Given an opcode and its operands, return a formatted name.
*
* @param opcode
* @param operands
* @return
*/
public static String opcode(int opcode, int op1, int op2) {
String opcodeName = Cpu.opcodeNames[opcode];
if (opcodeName == null) { return "???"; }
StringBuffer sb = new StringBuffer(opcodeName);
switch (Cpu.instructionModes[opcode]) {
case ABS:
sb.append(String.format(" $%04X", address(op1, op2)));
break;
case IMM:
sb.append(String.format(" #$%02X", op1));
}
return sb.toString();
}
}

View File

@ -30,7 +30,7 @@ public class CpuImmediateModeTest extends TestCase {
assertEquals(0xff, cpu.getStackPointer());
assertEquals(0x20, cpu.getProcessorStatus());
}
/*
* The following opcodes are tested for correctness in this file:
*
@ -39,19 +39,19 @@ public class CpuImmediateModeTest extends TestCase {
* EOR - $49
* ADC - $69
* LDY - $a0
*
*
* LDX - $a2
* LDA - $a9
* CPY - $c0
* CMP - $c9
* CPX - $e0
*
*
* SBC - $e9
*/
/* ORA Immediate Mode Tests - 0x09 */
public void test_ORA_SetsAccumulator() {
public void test_ORA() {
bus.loadProgram(0x09, 0x00, // ORA #$00
0x09, 0x11, // ORA #$11
0x09, 0x22, // ORA #$22
@ -722,22 +722,22 @@ public class CpuImmediateModeTest extends TestCase {
bus.loadProgram(0x18, // CLC
0xa9, 0x05, // LDA #$00
0xe9, 0x01); // SBC #$01
cpu.step(3);
assertEquals(0x03, cpu.getAccumulator());
cpu.reset();
// Subtrace with Carry Flag cleared
bus.loadProgram(0x18, // CLC
0xa9, 0x00, // LDA #$00
0xe9, 0x01); // SBC #$01
cpu.step(3);
assertEquals(0xfe, cpu.getAccumulator());
cpu.reset();
// Subtract with Carry Flag set
bus.loadProgram(0x38, // SEC
0xa9, 0x05, // LDA #$00
@ -745,9 +745,9 @@ public class CpuImmediateModeTest extends TestCase {
cpu.step(3);
assertEquals(0x04, cpu.getAccumulator());
assertTrue(cpu.getCarryFlag());
cpu.reset();
// Subtract with Carry Flag set
bus.loadProgram(0x38, // SEC
0xa9, 0x00, // LDA #$00
@ -757,7 +757,7 @@ public class CpuImmediateModeTest extends TestCase {
assertFalse(cpu.getCarryFlag());
}
public void test_SBC_DecimalMode() {
bus.loadProgram(0xf8,
0xa9, 0x00,
@ -771,7 +771,7 @@ public class CpuImmediateModeTest extends TestCase {
assertTrue(cpu.getDecimalModeFlag());
cpu.reset();
bus.loadProgram(0xf8,
0xa9, 0x99,
0xe9, 0x01);
@ -784,7 +784,7 @@ public class CpuImmediateModeTest extends TestCase {
assertTrue(cpu.getDecimalModeFlag());
cpu.reset();
bus.loadProgram(0xf8,
0xa9, 0x50,
0xe9, 0x01);
@ -796,9 +796,9 @@ public class CpuImmediateModeTest extends TestCase {
assertFalse(cpu.getZeroFlag());
assertTrue(cpu.getDecimalModeFlag());
cpu.reset();
bus.loadProgram(0xf8, // SED
0xa9, 0x02, // LDA #$02
0xe9, 0x01); // SBC #$01
@ -809,9 +809,9 @@ public class CpuImmediateModeTest extends TestCase {
assertFalse(cpu.getOverflowFlag());
assertTrue(cpu.getZeroFlag());
assertTrue(cpu.getDecimalModeFlag());
cpu.reset();
bus.loadProgram(0xf8, // SED
0xa9, 0x10, // LDA #$10
0xe9, 0x11); // SBC #$11
@ -822,7 +822,7 @@ public class CpuImmediateModeTest extends TestCase {
assertFalse(cpu.getOverflowFlag());
assertFalse(cpu.getZeroFlag());
assertTrue(cpu.getDecimalModeFlag());
cpu.reset();
bus.loadProgram(0x38, // SEC
@ -838,7 +838,7 @@ public class CpuImmediateModeTest extends TestCase {
assertTrue(cpu.getDecimalModeFlag());
cpu.reset();
bus.loadProgram(0x38, // SEC
0xf8, // SED
0xa9, 0x00, // LDA #$00

View File

@ -346,4 +346,13 @@ public class CpuTest extends TestCase {
assertFalse(cpu.getOverflowFlag());
assertFalse(cpu.getNegativeFlag());
}
public void testAddress() {
assertEquals(0xf1ea, cpu.address(0xea, 0xf1));
assertEquals(0x00ea, cpu.address(0xea, 0x00));
assertEquals(0xf100, cpu.address(0x00, 0xf1));
assertEquals(0x1234, cpu.address(0x34, 0x12));
assertEquals(0xffff, cpu.address(0xff, 0xff));
}
}

View File

@ -1,15 +0,0 @@
package com.loomcom.symon;
import junit.framework.TestCase;
public class CpuUtilsTest extends TestCase {
public void testAddress() {
assertEquals(0xf1ea, CpuUtils.address(0xea, 0xf1));
assertEquals(0x00ea, CpuUtils.address(0xea, 0x00));
assertEquals(0xf100, CpuUtils.address(0x00, 0xf1));
assertEquals(0x1234, CpuUtils.address(0x34, 0x12));
assertEquals(0xffff, CpuUtils.address(0xff, 0xff));
}
}

View File

@ -34,41 +34,241 @@ public class CpuZeroPageModeTest extends TestCase {
/*
* The following opcodes are tested for correctness in this file:
*
* ADC - $65
* AND - $25
* ORA - $05
* ASL - $06
* BIT - $24
* CMP - $c5
*
* CPX - $e4
* CPY - $c4
* DEC - $c6
* EOR - $45
* INC - $e6
*
* LDA - $a5
* LDX - $a6
* LDY - $a4
* LSR - $46
* ORA - $05
*
* AND - $25
* ROL - $26
*
* EOR - $45
* LSR - $46
* ADC - $65
* ROR - $66
* SBC - $e5
* STY - $84
*
* STA - $85
* STX - $86
*
* STY - $84
*
* LDY - $a4
* LDA - $a5
* LDX - $a6
*
* CPY - $c4
* CMP - $c5
* DEC - $c6
* CPX - $e4
* SBC - $e5
*
* INC - $e6
*/
/* ADC - Add with Carry - $88 */
public void test_ADC() {
/* ORA - Logical Inclusive OR - $05 */
public void test_ORA() {
// Set some initial values in zero page.
bus.write(0x0000, 0x00);
bus.write(0x0002, 0x11);
bus.write(0x0004, 0x22);
bus.write(0x0008, 0x44);
bus.write(0x0010, 0x88);
bus.loadProgram(0x05, 0x00, // ORA $00
0x05, 0x02, // ORA $02
0x05, 0x04, // ORA $04
0x05, 0x08, // ORA $08
0x05, 0x10); // ORA $10
cpu.step();
assertEquals(0x00, cpu.getAccumulator());
assertTrue(cpu.getZeroFlag());
assertFalse(cpu.getNegativeFlag());
cpu.step();
assertEquals(0x11, cpu.getAccumulator());
assertFalse(cpu.getZeroFlag());
assertFalse(cpu.getNegativeFlag());
cpu.step();
assertEquals(0x33, cpu.getAccumulator());
assertFalse(cpu.getZeroFlag());
assertFalse(cpu.getNegativeFlag());
cpu.step();
assertEquals(0x77, cpu.getAccumulator());
assertFalse(cpu.getZeroFlag());
assertFalse(cpu.getNegativeFlag());
cpu.step();
assertEquals(0xff, cpu.getAccumulator());
assertFalse(cpu.getZeroFlag());
assertTrue(cpu.getNegativeFlag());
}
/* ASL - Arithmetic Shift Left - $06 */
public void test_ASL() {
bus.write(0x0000, 0x00);
bus.write(0x0001, 0x01);
bus.write(0x0002, 0x02);
bus.write(0x0003, 0x44);
bus.write(0x0004, 0x80);
bus.loadProgram(0x06, 0x00,
0x06, 0x01,
0x06, 0x02,
0x06, 0x03,
0x06, 0x04);
cpu.step();
assertEquals(0x00, bus.read(0x0000));
assertTrue(cpu.getZeroFlag());
assertFalse(cpu.getNegativeFlag());
assertFalse(cpu.getCarryFlag());
cpu.step();
assertEquals(0x02, bus.read(0x0001));
assertFalse(cpu.getZeroFlag());
assertFalse(cpu.getNegativeFlag());
assertFalse(cpu.getCarryFlag());
cpu.step();
assertEquals(0x04, bus.read(0x0002));
assertFalse(cpu.getZeroFlag());
assertFalse(cpu.getNegativeFlag());
assertFalse(cpu.getCarryFlag());
cpu.step();
assertEquals(0x88, bus.read(0x0003));
assertFalse(cpu.getZeroFlag());
assertTrue(cpu.getNegativeFlag());
assertFalse(cpu.getCarryFlag());
cpu.step();
assertEquals(0x00, bus.read(0x0004));
assertTrue(cpu.getZeroFlag());
assertFalse(cpu.getNegativeFlag());
assertTrue(cpu.getCarryFlag());
}
/* BIT - Bit Test - $24 */
public void test_BIT() {
bus.write(0x0000, 0xc0);
bus.loadProgram(0xa9, 0x01, // LDA #$01
0x24, 0x00, // BIT $00
0xa9, 0x0f, // LDA #$0f
0x24, 0x00, // BIT $00
0xa9, 0x40, // LDA #$40
0x24, 0x00, // BIT $00
0xa9, 0x80, // LDA #$80
0x24, 0x00, // BIT $00
0xa9, 0xc0, // LDA #$c0
0x24, 0x00, // BIT $00
0xa9, 0xff, // LDA #$ff
0x24, 0x00); // BIT $00
cpu.step(2);
assertTrue(cpu.getZeroFlag());
assertFalse(cpu.getNegativeFlag());
assertFalse(cpu.getOverflowFlag());
cpu.step(2);
assertTrue(cpu.getZeroFlag());
assertFalse(cpu.getNegativeFlag());
assertFalse(cpu.getOverflowFlag());
cpu.step(2);
assertFalse(cpu.getZeroFlag());
assertFalse(cpu.getNegativeFlag());
assertTrue(cpu.getOverflowFlag());
cpu.step(2);
assertFalse(cpu.getZeroFlag());
assertTrue(cpu.getNegativeFlag());
assertFalse(cpu.getOverflowFlag());
cpu.step(2);
assertFalse(cpu.getZeroFlag());
assertTrue(cpu.getNegativeFlag());
assertTrue(cpu.getOverflowFlag());
cpu.step(2);
assertFalse(cpu.getZeroFlag());
assertTrue(cpu.getNegativeFlag());
assertTrue(cpu.getOverflowFlag());
}
/* AND - Logical AND - $25 */
public void test_AND() {
}
/* ROL - Rotate Left - $26 */
public void test_ROL() {
}
/* EOR - Exclusive OR - $45 */
public void test_EOR() {
}
/* LSR - Logical Shift Right - $46 */
public void test_LSR() {
}
/* ADC - Add with Carry - $65 */
public void test_ADC() {
}
/* ROR - Rotate Right - $66 */
public void test_ROR() {
}
/* STY - Store Y Register - $84 */
public void test_STY() {
}
/* STA - Store Accumulator - $85 */
public void test_STA() {
}
/* STX - Store X Register - $86 */
public void test_STX() {
}
/* LDY - Load Y Register - $a4 */
public void test_LDY() {
}
/* LDA - Load Accumulator - $a5 */
public void test_LDA() {
}
/* LDX - Load X Register - $a6 */
public void test_LDX() {
}
/* CPY - Compare Y Register - $c4 */
public void test_CPY() {
}
/* CMP - Compare Accumulator - $c5 */
public void test_CMP() {
}
/* DEC - Decrement Memory Location - $c6 */
public void test_DEC() {
}
/* CPX - Compare X Register - $e4 */
public void test_CPX() {
}
/* SBC - Subtract with Carry - $e5 */
public void test_SBC() {
}
/* INC - Increment Memory Location - $e6 */
public void test_INC() {
}
}