Execution Trace Log

Introduces an execution trace window that will keep track of the most
recent 10000 execution steps. I'm not entirely happy with the
implementation, yet.
This commit is contained in:
Seth Morabito committed 2012-12-09 17:04:31 -08:00
1 parent 38a4458aff
commit bc3de80892
11 files changed
+1268 -1256

No files matched your search

File diff suppressed because it is too large. Load diff
+34 -3
View File
@@ -33,6 +33,7 @@ import com.loomcom.symon.exceptions.SymonException;
import com.loomcom.symon.ui.Console; import com.loomcom.symon.ui.Console;
import com.loomcom.symon.ui.PreferencesDialog; import com.loomcom.symon.ui.PreferencesDialog;
import com.loomcom.symon.ui.StatusPanel; import com.loomcom.symon.ui.StatusPanel;
import com.loomcom.symon.ui.TraceLog;
import javax.swing.*; import javax.swing.*;
import javax.swing.border.EmptyBorder; import javax.swing.border.EmptyBorder;
@@ -118,7 +119,7 @@ public class Simulator implements Observer {
/** /**
* The Trace Window shows the most recent 50,000 CPU states. * The Trace Window shows the most recent 50,000 CPU states.
*/ */
private JFrame traceWindow; private TraceLog traceLog;
/** /**
* The Zero Page Window shows the contents of page 0. * The Zero Page Window shows the contents of page 0.
@@ -229,6 +230,9 @@ public class Simulator implements Observer {
} }
}); });
// Prepare the log window
traceLog = new TraceLog();
mainWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); mainWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
console.requestFocus(); console.requestFocus();
@@ -264,8 +268,9 @@ public class Simulator implements Observer {
statusPane.updateState(cpu); statusPane.updateState(cpu);
} }
}); });
if (traceLog.isVisible()) {
// TODO: Write to Log window, if frame is visible. traceLog.refresh();
}
// TODO: Update memory window, if frame is visible. // TODO: Update memory window, if frame is visible.
} }
@@ -317,6 +322,11 @@ public class Simulator implements Observer {
private void step() throws MemoryAccessException { private void step() throws MemoryAccessException {
cpu.step(); cpu.step();
// TODO: We need to profile this for performance. Possibly allow
// a flag to turn trace on/off
synchronized(traceLog) {
traceLog.append(cpu.getCpuState());
}
// Read from the ACIA and immediately update the console if there's // Read from the ACIA and immediately update the console if there's
// output ready. // output ready.
@@ -607,6 +617,24 @@ public class Simulator implements Observer {
} }
} }
class ToggleTraceWindowAction extends AbstractAction {
public ToggleTraceWindowAction() {
super("Trace Log", null);
putValue(SHORT_DESCRIPTION, "Show or Hide the Trace Log Window");
}
public void actionPerformed(ActionEvent actionEvent) {
synchronized(traceLog) {
if (traceLog.isVisible()) {
traceLog.setVisible(false);
} else {
traceLog.refresh();
traceLog.setVisible(true);
}
}
}
}
class SimulatorMenu extends JMenuBar { class SimulatorMenu extends JMenuBar {
// Menu Items // Menu Items
private JMenuItem loadProgramItem; private JMenuItem loadProgramItem;
@@ -675,6 +703,9 @@ public class Simulator implements Observer {
makeFontSizeMenuItem(20, fontSubMenu, group); makeFontSizeMenuItem(20, fontSubMenu, group);
viewMenu.add(fontSubMenu); viewMenu.add(fontSubMenu);
JMenuItem showTraceLog = new JMenuItem(new ToggleTraceWindowAction());
viewMenu.add(showTraceLog);
add(viewMenu); add(viewMenu);
} }
@@ -177,19 +177,21 @@ public class StatusPanel extends JPanel {
* @param cpu The simulated 6502 CPU. * @param cpu The simulated 6502 CPU.
*/ */
public void updateState(Cpu cpu) { public void updateState(Cpu cpu) {
// Update the Processor Status Flag display Cpu.CpuState cpuState = cpu.getCpuState();
int state = cpu.getProcessorStatus();
carryFlagLabel.setIcon(iconForFlag(state, 0)); // Update the Processor Status Flag display
zeroFlagLabel.setIcon(iconForFlag(state, 1)); int status = cpu.getCpuState().getStatusFlag();
irqDisableFlagLabel.setIcon(iconForFlag(state, 2));
decimalModeFlagLabel.setIcon(iconForFlag(state, 3)); carryFlagLabel.setIcon(iconForFlag(status, 0));
breakFlagLabel.setIcon(iconForFlag(state, 4)); zeroFlagLabel.setIcon(iconForFlag(status, 1));
overflowFlagLabel.setIcon(iconForFlag(state, 6)); irqDisableFlagLabel.setIcon(iconForFlag(status, 2));
negativeFlagLabel.setIcon(iconForFlag(state, 7)); decimalModeFlagLabel.setIcon(iconForFlag(status, 3));
breakFlagLabel.setIcon(iconForFlag(status, 4));
overflowFlagLabel.setIcon(iconForFlag(status, 6));
negativeFlagLabel.setIcon(iconForFlag(status, 7));
// Update the register and address displays // Update the register and address displays
opcodeField.setText(cpu.getOpcodeStatus()); opcodeField.setText(cpu.getCpuState().disassembleOp());
pcField.setText(cpu.getProgramCounterStatus()); pcField.setText(cpu.getProgramCounterStatus());
spField.setText(cpu.getStackPointerStatus()); spField.setText(cpu.getStackPointerStatus());
aField.setText(cpu.getAccumulatorStatus()); aField.setText(cpu.getAccumulatorStatus());
@@ -24,17 +24,61 @@
package com.loomcom.symon.ui; package com.loomcom.symon.ui;
import com.loomcom.symon.Cpu;
import com.loomcom.symon.util.FifoRingBuffer; import com.loomcom.symon.util.FifoRingBuffer;
import javax.swing.*; import javax.swing.*;
import java.awt.*;
/** /**
* This frame displays a trace of CPU execution. The most recent TRACE_LENGTH lines * This frame displays a trace of CPU execution. The most recent TRACE_LENGTH lines
* are captured in a buffer and rendered to the JFrame's main text area upon request. * are captured in a buffer and rendered to the JFrame's main text area upon request.
*/ */
public class TraceLog extends JFrame { public class TraceLog {
private FifoRingBuffer<String> traceLog; private FifoRingBuffer<Cpu.CpuState> traceLog;
private JFrame traceLogWindow;
private JTextArea logArea;
private static final Dimension SIZE = new Dimension(640, 480);
private static final int MAX_LOG_LENGTH = 10000;
public TraceLog() {
traceLog = new FifoRingBuffer<Cpu.CpuState>(MAX_LOG_LENGTH);
traceLogWindow = new JFrame();
traceLogWindow.setPreferredSize(SIZE);
traceLogWindow.setResizable(true);
traceLogWindow.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
logArea = new JTextArea();
logArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 12));
JScrollPane scrollableView = new JScrollPane(logArea);
traceLogWindow.getContentPane().add(scrollableView);
traceLogWindow.pack();
// Don't show the frame. That action is controlled by the Simulator.
}
public void refresh() {
StringBuilder logString = new StringBuilder();
for (Cpu.CpuState state : traceLog) {
logString.append(state.toString());
logString.append("\n");
}
logArea.setText(logString.toString());
}
public void append(Cpu.CpuState state) {
traceLog.push(new Cpu.CpuState(state));
}
public boolean isVisible() {
return traceLogWindow.isVisible();
}
public void setVisible(boolean b) {
traceLogWindow.setVisible(b);
}
} }
@@ -26,8 +26,8 @@ public class CpuAccumulatorModeTest extends TestCase {
// Assert initial state // Assert initial state
assertEquals(0, cpu.getAccumulator()); assertEquals(0, cpu.getAccumulator());
assertEquals(0, cpu.getXRegister()); assertEquals(0, cpu.getXRegister());
assertEquals(0, cpu.getYRegister()); assertEquals(0, cpu.getYRegister());
assertEquals(0x200, cpu.getProgramCounter()); assertEquals(0x200, cpu.getProgramCounter());
assertEquals(0xff, cpu.getStackPointer()); assertEquals(0xff, cpu.getStackPointer());
assertEquals(0x20, cpu.getProcessorStatus()); assertEquals(0x20, cpu.getProcessorStatus());
@@ -7,31 +7,31 @@ import junit.framework.*;
public class CpuImpliedModeTest extends TestCase { public class CpuImpliedModeTest extends TestCase {
protected Cpu cpu; protected Cpu cpu;
protected Bus bus; protected Bus bus;
protected Memory mem; protected Memory mem;
public void setUp() throws MemoryRangeException, MemoryAccessException { public void setUp() throws MemoryRangeException, MemoryAccessException {
this.cpu = new Cpu(); this.cpu = new Cpu();
this.bus = new Bus(0x0000, 0xffff); this.bus = new Bus(0x0000, 0xffff);
this.mem = new Memory(0x0000, 0x10000); this.mem = new Memory(0x0000, 0x10000);
bus.addCpu(cpu); bus.addCpu(cpu);
bus.addDevice(mem); bus.addDevice(mem);
// Load the reset vector. // Load the reset vector.
bus.write(0xfffc, Bus.DEFAULT_LOAD_ADDRESS & 0x00ff); bus.write(0xfffc, Bus.DEFAULT_LOAD_ADDRESS & 0x00ff);
bus.write(0xfffd, (Bus.DEFAULT_LOAD_ADDRESS & 0xff00)>>>8); bus.write(0xfffd, (Bus.DEFAULT_LOAD_ADDRESS & 0xff00) >>> 8);
cpu.reset(); cpu.reset();
// Assert initial state // Assert initial state
assertEquals(0, cpu.getAccumulator()); assertEquals(0, cpu.getAccumulator());
assertEquals(0, cpu.getXRegister()); assertEquals(0, cpu.getXRegister());
assertEquals(0, cpu.getYRegister()); assertEquals(0, cpu.getYRegister());
assertEquals(0x200, cpu.getProgramCounter()); assertEquals(0x200, cpu.getProgramCounter());
assertEquals(0xff, cpu.getStackPointer()); assertEquals(0xff, cpu.getStackPointer());
assertEquals(0x20, cpu.getProcessorStatus()); assertEquals(0x20, cpu.getProcessorStatus());
} }
/* /*
* The following opcodes are tested for correctness in this file: * The following opcodes are tested for correctness in this file:
@@ -69,529 +69,529 @@ public class CpuImpliedModeTest extends TestCase {
/* BRK Tests - 0x00 */ /* BRK Tests - 0x00 */
public void test_BRK() throws MemoryAccessException { public void test_BRK() throws MemoryAccessException {
cpu.setCarryFlag(); cpu.setCarryFlag();
cpu.setOverflowFlag(); cpu.setOverflowFlag();
assertEquals(0x20|Cpu.P_CARRY|Cpu.P_OVERFLOW, assertEquals(0x20 | Cpu.P_CARRY | Cpu.P_OVERFLOW,
cpu.getProcessorStatus()); cpu.getProcessorStatus());
assertEquals(0x00, cpu.stackPeek()); assertEquals(0x00, cpu.stackPeek());
assertFalse(cpu.getBreakFlag()); assertFalse(cpu.getBreakFlag());
assertEquals(0x0200, cpu.getProgramCounter()); assertEquals(0x0200, cpu.getProgramCounter());
assertEquals(0xff, cpu.getStackPointer()); assertEquals(0xff, cpu.getStackPointer());
// Set the IRQ vector // Set the IRQ vector
bus.write(Cpu.IRQ_VECTOR_H, 0x12); bus.write(Cpu.IRQ_VECTOR_H, 0x12);
bus.write(Cpu.IRQ_VECTOR_L, 0x34); bus.write(Cpu.IRQ_VECTOR_L, 0x34);
bus.loadProgram(0xea, bus.loadProgram(0xea,
0xea, 0xea,
0xea, 0xea,
0x00, 0x00,
0xea, 0xea,
0xea); 0xea);
cpu.step(3); // Three NOP instructions cpu.step(3); // Three NOP instructions
assertEquals(0x203, cpu.getProgramCounter()); assertEquals(0x203, cpu.getProgramCounter());
cpu.step(); // Triggers the BRK cpu.step(); // Triggers the BRK
// Was at PC = 0x204. PC+2 should now be on the stack // Was at PC = 0x204. PC+2 should now be on the stack
assertEquals(0x02, bus.read(0x1ff)); // PC high byte assertEquals(0x02, bus.read(0x1ff)); // PC high byte
assertEquals(0x06, bus.read(0x1fe)); // PC low byte assertEquals(0x06, bus.read(0x1fe)); // PC low byte
assertEquals(0x20|Cpu.P_CARRY|Cpu.P_OVERFLOW|Cpu.P_BREAK, assertEquals(0x20 | Cpu.P_CARRY | Cpu.P_OVERFLOW | Cpu.P_BREAK,
bus.read(0x1fd)); // Processor Status, with B set bus.read(0x1fd)); // Processor Status, with B set
// Interrupt vector held 0x1234, so we should be there. // Interrupt vector held 0x1234, so we should be there.
assertEquals(0x1234, cpu.getProgramCounter()); assertEquals(0x1234, cpu.getProgramCounter());
assertEquals(0xfc, cpu.getStackPointer()); assertEquals(0xfc, cpu.getStackPointer());
// B and I flags should have been set on P // B and I flags should have been set on P
assertEquals(0x20|Cpu.P_CARRY|Cpu.P_OVERFLOW|Cpu.P_BREAK| assertEquals(0x20 | Cpu.P_CARRY | Cpu.P_OVERFLOW | Cpu.P_BREAK |
Cpu.P_IRQ_DISABLE, Cpu.P_IRQ_DISABLE,
cpu.getProcessorStatus()); cpu.getProcessorStatus());
} }
public void test_BRK_HonorsIrqDisableFlag() throws MemoryAccessException { public void test_BRK_HonorsIrqDisableFlag() throws MemoryAccessException {
cpu.setIrqDisableFlag(); cpu.setIrqDisableFlag();
bus.loadProgram(0xea, bus.loadProgram(0xea,
0xea, 0xea,
0xea, 0xea,
0x00, 0x00,
0xea, 0xea,
0xea); 0xea);
cpu.step(3); // Three NOP instructions cpu.step(3); // Three NOP instructions
assertEquals(0x203, cpu.getProgramCounter()); assertEquals(0x203, cpu.getProgramCounter());
// Triggers the BRK, which should do nothing because // Triggers the BRK, which should do nothing because
// of the Interrupt Disable flag // of the Interrupt Disable flag
cpu.step(); cpu.step();
// Reset to original contents of PC // Reset to original contents of PC
assertEquals(0x0204, cpu.getProgramCounter()); assertEquals(0x0204, cpu.getProgramCounter());
// Empty stack // Empty stack
assertEquals(0xff, cpu.getStackPointer()); assertEquals(0xff, cpu.getStackPointer());
cpu.step(2); // Two more NOPs cpu.step(2); // Two more NOPs
// Reset to original contents of PC // Reset to original contents of PC
assertEquals(0x0206, cpu.getProgramCounter()); assertEquals(0x0206, cpu.getProgramCounter());
// Empty stack // Empty stack
assertEquals(0xff, cpu.getStackPointer()); assertEquals(0xff, cpu.getStackPointer());
} }
/* CLC - Clear Carry Flag - $18 */ /* CLC - Clear Carry Flag - $18 */
public void test_CLC() throws MemoryAccessException { public void test_CLC() throws MemoryAccessException {
cpu.setCarryFlag(); cpu.setCarryFlag();
assertTrue(cpu.getCarryFlag()); assertTrue(cpu.getCarryFlag());
bus.loadProgram(0x18); bus.loadProgram(0x18);
cpu.step(); cpu.step();
assertFalse(cpu.getCarryFlag()); assertFalse(cpu.getCarryFlag());
} }
/* CLD - Clear Decimal Mode Flag - $d8 */ /* CLD - Clear Decimal Mode Flag - $d8 */
public void test_CLD() throws MemoryAccessException { public void test_CLD() throws MemoryAccessException {
cpu.setDecimalModeFlag(); cpu.setDecimalModeFlag();
assertTrue(cpu.getDecimalModeFlag()); assertTrue(cpu.getDecimalModeFlag());
bus.loadProgram(0xd8); bus.loadProgram(0xd8);
cpu.step(); cpu.step();
assertFalse(cpu.getDecimalModeFlag()); assertFalse(cpu.getDecimalModeFlag());
} }
/* CLI - Clear Interrupt Disabled Flag - $58 */ /* CLI - Clear Interrupt Disabled Flag - $58 */
public void test_CLI() throws MemoryAccessException { public void test_CLI() throws MemoryAccessException {
cpu.setIrqDisableFlag(); cpu.setIrqDisableFlag();
assertTrue(cpu.getIrqDisableFlag()); assertTrue(cpu.getIrqDisableFlag());
bus.loadProgram(0x58); bus.loadProgram(0x58);
cpu.step(); cpu.step();
assertFalse(cpu.getIrqDisableFlag()); assertFalse(cpu.getIrqDisableFlag());
} }
/* CLV - Clear Overflow Flag - $b8 */ /* CLV - Clear Overflow Flag - $b8 */
public void test_CLV() throws MemoryAccessException { public void test_CLV() throws MemoryAccessException {
cpu.setOverflowFlag(); cpu.setOverflowFlag();
assertTrue(cpu.getOverflowFlag()); assertTrue(cpu.getOverflowFlag());
bus.loadProgram(0xb8); bus.loadProgram(0xb8);
cpu.step(); cpu.step();
assertFalse(cpu.getOverflowFlag()); assertFalse(cpu.getOverflowFlag());
} }
/* DEX - Decrement the X register - $ca */ /* DEX - Decrement the X register - $ca */
public void test_DEX() throws MemoryAccessException { public void test_DEX() throws MemoryAccessException {
bus.loadProgram(0xca); bus.loadProgram(0xca);
cpu.setXRegister(0x02); cpu.setXRegister(0x02);
cpu.step(); cpu.step();
assertEquals(0x01, cpu.getXRegister()); assertEquals(0x01, cpu.getXRegister());
assertFalse(cpu.getZeroFlag()); assertFalse(cpu.getZeroFlag());
assertFalse(cpu.getNegativeFlag()); assertFalse(cpu.getNegativeFlag());
} }
public void test_DEX_SetsZeroFlagWhenZero() throws MemoryAccessException { public void test_DEX_SetsZeroFlagWhenZero() throws MemoryAccessException {
bus.loadProgram(0xca); bus.loadProgram(0xca);
cpu.setXRegister(0x01); cpu.setXRegister(0x01);
cpu.step(); cpu.step();
assertEquals(0x00, cpu.getXRegister()); assertEquals(0x00, cpu.getXRegister());
assertTrue(cpu.getZeroFlag()); assertTrue(cpu.getZeroFlag());
assertFalse(cpu.getNegativeFlag()); assertFalse(cpu.getNegativeFlag());
} }
public void test_DEX_SetsNegativeFlagWhen() throws MemoryAccessException { public void test_DEX_SetsNegativeFlagWhen() throws MemoryAccessException {
bus.loadProgram(0xca); bus.loadProgram(0xca);
cpu.step(); cpu.step();
assertEquals(0xff, cpu.getXRegister()); assertEquals(0xff, cpu.getXRegister());
assertFalse(cpu.getZeroFlag()); assertFalse(cpu.getZeroFlag());
assertTrue(cpu.getNegativeFlag()); assertTrue(cpu.getNegativeFlag());
} }
/* DEY - Decrement the Y register - $88 */ /* DEY - Decrement the Y register - $88 */
public void test_DEY() throws MemoryAccessException { public void test_DEY() throws MemoryAccessException {
bus.loadProgram(0x88); bus.loadProgram(0x88);
cpu.setYRegister(0x02); cpu.setYRegister(0x02);
cpu.step(); cpu.step();
assertEquals(0x01, cpu.getYRegister()); assertEquals(0x01, cpu.getYRegister());
assertFalse(cpu.getZeroFlag()); assertFalse(cpu.getZeroFlag());
assertFalse(cpu.getNegativeFlag()); assertFalse(cpu.getNegativeFlag());
} }
public void test_DEY_SetsZeroFlagWhenZero() throws MemoryAccessException { public void test_DEY_SetsZeroFlagWhenZero() throws MemoryAccessException {
bus.loadProgram(0x88); bus.loadProgram(0x88);
cpu.setYRegister(0x01); cpu.setYRegister(0x01);
cpu.step(); cpu.step();
assertEquals(0x00, cpu.getYRegister()); assertEquals(0x00, cpu.getYRegister());
assertTrue(cpu.getZeroFlag()); assertTrue(cpu.getZeroFlag());
assertFalse(cpu.getNegativeFlag()); assertFalse(cpu.getNegativeFlag());
} }
public void test_DEY_SetsNegativeFlagWhen() throws MemoryAccessException { public void test_DEY_SetsNegativeFlagWhen() throws MemoryAccessException {
bus.loadProgram(0x88); bus.loadProgram(0x88);
cpu.step(); cpu.step();
assertEquals(0xff, cpu.getYRegister()); assertEquals(0xff, cpu.getYRegister());
assertFalse(cpu.getZeroFlag()); assertFalse(cpu.getZeroFlag());
assertTrue(cpu.getNegativeFlag()); assertTrue(cpu.getNegativeFlag());
} }
/* INX - Increment the X register - $e8 */ /* INX - Increment the X register - $e8 */
public void test_INX() throws MemoryAccessException { public void test_INX() throws MemoryAccessException {
bus.loadProgram(0xe8); bus.loadProgram(0xe8);
cpu.step(); cpu.step();
assertEquals(0x01, cpu.getXRegister()); assertEquals(0x01, cpu.getXRegister());
assertFalse(cpu.getZeroFlag()); assertFalse(cpu.getZeroFlag());
assertFalse(cpu.getNegativeFlag()); assertFalse(cpu.getNegativeFlag());
} }
public void test_INX_SetsNegativeFlagWhenNegative() throws MemoryAccessException { public void test_INX_SetsNegativeFlagWhenNegative() throws MemoryAccessException {
bus.loadProgram(0xe8); bus.loadProgram(0xe8);
cpu.setXRegister(0x7f); cpu.setXRegister(0x7f);
cpu.step(); cpu.step();
assertEquals(0x80, cpu.getXRegister()); assertEquals(0x80, cpu.getXRegister());
assertFalse(cpu.getZeroFlag()); assertFalse(cpu.getZeroFlag());
assertTrue(cpu.getNegativeFlag()); assertTrue(cpu.getNegativeFlag());
} }
public void test_INX_SetsZeroFlagWhenZero() throws MemoryAccessException { public void test_INX_SetsZeroFlagWhenZero() throws MemoryAccessException {
bus.loadProgram(0xe8); bus.loadProgram(0xe8);
cpu.setXRegister(0xff); cpu.setXRegister(0xff);
cpu.step(); cpu.step();
assertEquals(0x00, cpu.getXRegister()); assertEquals(0x00, cpu.getXRegister());
assertTrue(cpu.getZeroFlag()); assertTrue(cpu.getZeroFlag());
assertFalse(cpu.getNegativeFlag()); assertFalse(cpu.getNegativeFlag());
} }
/* INY - Increment the Y register - $c8 */ /* INY - Increment the Y register - $c8 */
public void test_INY() throws MemoryAccessException { public void test_INY() throws MemoryAccessException {
bus.loadProgram(0xc8); bus.loadProgram(0xc8);
cpu.step(); cpu.step();
assertEquals(0x01, cpu.getYRegister()); assertEquals(0x01, cpu.getYRegister());
assertFalse(cpu.getZeroFlag()); assertFalse(cpu.getZeroFlag());
assertFalse(cpu.getNegativeFlag()); assertFalse(cpu.getNegativeFlag());
} }
public void test_INY_SetsNegativeFlagWhenNegative() throws MemoryAccessException { public void test_INY_SetsNegativeFlagWhenNegative() throws MemoryAccessException {
bus.loadProgram(0xc8); bus.loadProgram(0xc8);
cpu.setYRegister(0x7f); cpu.setYRegister(0x7f);
cpu.step(); cpu.step();
assertEquals(0x80, cpu.getYRegister()); assertEquals(0x80, cpu.getYRegister());
assertFalse(cpu.getZeroFlag()); assertFalse(cpu.getZeroFlag());
assertTrue(cpu.getNegativeFlag()); assertTrue(cpu.getNegativeFlag());
} }
public void test_INY_SetsZeroFlagWhenZero() throws MemoryAccessException { public void test_INY_SetsZeroFlagWhenZero() throws MemoryAccessException {
bus.loadProgram(0xc8); bus.loadProgram(0xc8);
cpu.setYRegister(0xff); cpu.setYRegister(0xff);
cpu.step(); cpu.step();
assertEquals(0x00, cpu.getYRegister()); assertEquals(0x00, cpu.getYRegister());
assertTrue(cpu.getZeroFlag()); assertTrue(cpu.getZeroFlag());
assertFalse(cpu.getNegativeFlag()); assertFalse(cpu.getNegativeFlag());
} }
/* NOP - No Operation - $ea */ /* NOP - No Operation - $ea */
public void test_NOP() throws MemoryAccessException { public void test_NOP() throws MemoryAccessException {
bus.loadProgram(0xea); bus.loadProgram(0xea);
cpu.step(); cpu.step();
// Should just not change anything except PC // Should just not change anything except PC
assertEquals(0, cpu.getAccumulator()); assertEquals(0, cpu.getAccumulator());
assertEquals(0, cpu.getXRegister()); assertEquals(0, cpu.getXRegister());
assertEquals(0, cpu.getYRegister()); assertEquals(0, cpu.getYRegister());
assertEquals(0x201, cpu.getProgramCounter()); assertEquals(0x201, cpu.getProgramCounter());
assertEquals(0xff, cpu.getStackPointer()); assertEquals(0xff, cpu.getStackPointer());
assertEquals(0x20, cpu.getProcessorStatus()); assertEquals(0x20, cpu.getProcessorStatus());
} }
/* PHA - Push Accumulator - $48 */ /* PHA - Push Accumulator - $48 */
public void test_PHA() throws MemoryAccessException { public void test_PHA() throws MemoryAccessException {
bus.loadProgram(0x48); bus.loadProgram(0x48);
cpu.setAccumulator(0x3a); cpu.setAccumulator(0x3a);
cpu.step(); cpu.step();
assertEquals(0xfe, cpu.getStackPointer()); assertEquals(0xfe, cpu.getStackPointer());
assertEquals(0x3a, cpu.stackPeek()); assertEquals(0x3a, cpu.stackPeek());
} }
/* PHP - Push Processor Status - $08 */ /* PHP - Push Processor Status - $08 */
public void test_PHP() throws MemoryAccessException { public void test_PHP() throws MemoryAccessException {
bus.loadProgram(0x08); bus.loadProgram(0x08);
cpu.setProcessorStatus(0x27); cpu.setProcessorStatus(0x27);
cpu.step(); cpu.step();
assertEquals(0xfe, cpu.getStackPointer()); assertEquals(0xfe, cpu.getStackPointer());
assertEquals(0x27, cpu.stackPeek()); assertEquals(0x27, cpu.stackPeek());
} }
/* PLA - Pul Accumulator - $68 */ /* PLA - Pul Accumulator - $68 */
public void test_PLA() throws MemoryAccessException { public void test_PLA() throws MemoryAccessException {
cpu.stackPush(0x32); cpu.stackPush(0x32);
bus.loadProgram(0x68); bus.loadProgram(0x68);
cpu.step(); cpu.step();
assertEquals(0x32, cpu.getAccumulator()); assertEquals(0x32, cpu.getAccumulator());
assertFalse(cpu.getNegativeFlag()); assertFalse(cpu.getNegativeFlag());
assertFalse(cpu.getZeroFlag()); assertFalse(cpu.getZeroFlag());
} }
public void test_PLA_SetsZeroIfAccumulatorIsZero() throws MemoryAccessException { public void test_PLA_SetsZeroIfAccumulatorIsZero() throws MemoryAccessException {
cpu.stackPush(0x00); cpu.stackPush(0x00);
bus.loadProgram(0x68); bus.loadProgram(0x68);
cpu.step(); cpu.step();
assertEquals(0x00, cpu.getAccumulator()); assertEquals(0x00, cpu.getAccumulator());
assertFalse(cpu.getNegativeFlag()); assertFalse(cpu.getNegativeFlag());
assertTrue(cpu.getZeroFlag()); assertTrue(cpu.getZeroFlag());
} }
public void test_PLA_SetsNegativeIfAccumulatorIsNegative() throws MemoryAccessException { public void test_PLA_SetsNegativeIfAccumulatorIsNegative() throws MemoryAccessException {
cpu.stackPush(0xff); cpu.stackPush(0xff);
bus.loadProgram(0x68); bus.loadProgram(0x68);
cpu.step(); cpu.step();
assertEquals(0xff, cpu.getAccumulator()); assertEquals(0xff, cpu.getAccumulator());
assertTrue(cpu.getNegativeFlag()); assertTrue(cpu.getNegativeFlag());
assertFalse(cpu.getZeroFlag()); assertFalse(cpu.getZeroFlag());
} }
/* PLP - Pull Processor Status - $28 */ /* PLP - Pull Processor Status - $28 */
public void test_PLP() throws MemoryAccessException { public void test_PLP() throws MemoryAccessException {
cpu.stackPush(0x2f); cpu.stackPush(0x2f);
bus.loadProgram(0x28); bus.loadProgram(0x28);
cpu.step(); cpu.step();
assertEquals(0x2f, cpu.getProcessorStatus()); assertEquals(0x2f, cpu.getProcessorStatus());
} }
/* RTI - Return from Interrupt - $40 */ /* RTI - Return from Interrupt - $40 */
public void test_RTI() throws MemoryAccessException { public void test_RTI() throws MemoryAccessException {
cpu.stackPush(0x0f); // PC hi cpu.stackPush(0x0f); // PC hi
cpu.stackPush(0x11); // PC lo cpu.stackPush(0x11); // PC lo
cpu.stackPush(0x29); // status cpu.stackPush(0x29); // status
bus.loadProgram(0x40); bus.loadProgram(0x40);
cpu.step(); cpu.step();
assertEquals(0x0f11, cpu.getProgramCounter()); assertEquals(0x0f11, cpu.getProgramCounter());
assertEquals(0x29, cpu.getProcessorStatus()); assertEquals(0x29, cpu.getProcessorStatus());
} }
/* RTS - Return from Subroutine - $60 */ /* RTS - Return from Subroutine - $60 */
public void test_RTS() throws MemoryAccessException { public void test_RTS() throws MemoryAccessException {
cpu.stackPush(0x0f); // PC hi cpu.stackPush(0x0f); // PC hi
cpu.stackPush(0x11); // PC lo cpu.stackPush(0x11); // PC lo
bus.loadProgram(0x60); bus.loadProgram(0x60);
cpu.step(); cpu.step();
assertEquals(0x0f12, cpu.getProgramCounter()); assertEquals(0x0f12, cpu.getProgramCounter());
assertEquals(0x20, cpu.getProcessorStatus()); assertEquals(0x20, cpu.getProcessorStatus());
} }
/* SEC - Set Carry Flag - $38 */ /* SEC - Set Carry Flag - $38 */
public void test_SEC() throws MemoryAccessException { public void test_SEC() throws MemoryAccessException {
bus.loadProgram(0x38); bus.loadProgram(0x38);
cpu.step(); cpu.step();
assertTrue(cpu.getCarryFlag()); assertTrue(cpu.getCarryFlag());
} }
/* SED - Set Decimal Mode Flag - $f8 */ /* SED - Set Decimal Mode Flag - $f8 */
public void test_SED() throws MemoryAccessException { public void test_SED() throws MemoryAccessException {
bus.loadProgram(0xf8); bus.loadProgram(0xf8);
cpu.step(); cpu.step();
assertTrue(cpu.getDecimalModeFlag()); assertTrue(cpu.getDecimalModeFlag());
} }
/* SEI - Set Interrupt Disable Flag - $78 */ /* SEI - Set Interrupt Disable Flag - $78 */
public void test_SEI() throws MemoryAccessException { public void test_SEI() throws MemoryAccessException {
bus.loadProgram(0x78); bus.loadProgram(0x78);
cpu.step(); cpu.step();
assertTrue(cpu.getIrqDisableFlag()); assertTrue(cpu.getIrqDisableFlag());
} }
/* TAX - Transfer Accumulator to X Register - $aa */ /* TAX - Transfer Accumulator to X Register - $aa */
public void test_TAX() throws MemoryAccessException { public void test_TAX() throws MemoryAccessException {
cpu.setAccumulator(0x32); cpu.setAccumulator(0x32);
bus.loadProgram(0xaa); bus.loadProgram(0xaa);
cpu.step(); cpu.step();
assertEquals(0x32, cpu.getXRegister()); assertEquals(0x32, cpu.getXRegister());
assertFalse(cpu.getZeroFlag()); assertFalse(cpu.getZeroFlag());
assertFalse(cpu.getNegativeFlag()); assertFalse(cpu.getNegativeFlag());
} }
public void test_TAX_SetsZeroFlagIfXIsZero() throws MemoryAccessException { public void test_TAX_SetsZeroFlagIfXIsZero() throws MemoryAccessException {
cpu.setAccumulator(0x00); cpu.setAccumulator(0x00);
bus.loadProgram(0xaa); bus.loadProgram(0xaa);
cpu.step(); cpu.step();
assertEquals(0x00, cpu.getXRegister()); assertEquals(0x00, cpu.getXRegister());
assertTrue(cpu.getZeroFlag()); assertTrue(cpu.getZeroFlag());
assertFalse(cpu.getNegativeFlag()); assertFalse(cpu.getNegativeFlag());
} }
public void test_TAX_SetsNegativeFlagIfXIsNegative() throws MemoryAccessException { public void test_TAX_SetsNegativeFlagIfXIsNegative() throws MemoryAccessException {
cpu.setAccumulator(0xff); cpu.setAccumulator(0xff);
bus.loadProgram(0xaa); bus.loadProgram(0xaa);
cpu.step(); cpu.step();
assertEquals(0xff, cpu.getXRegister()); assertEquals(0xff, cpu.getXRegister());
assertFalse(cpu.getZeroFlag()); assertFalse(cpu.getZeroFlag());
assertTrue(cpu.getNegativeFlag()); assertTrue(cpu.getNegativeFlag());
} }
/* TAY - Transfer Accumulator to Y Register - $a8 */ /* TAY - Transfer Accumulator to Y Register - $a8 */
public void test_TAY() throws MemoryAccessException { public void test_TAY() throws MemoryAccessException {
cpu.setAccumulator(0x32); cpu.setAccumulator(0x32);
bus.loadProgram(0xa8); bus.loadProgram(0xa8);
cpu.step(); cpu.step();
assertEquals(0x32, cpu.getYRegister()); assertEquals(0x32, cpu.getYRegister());
assertFalse(cpu.getZeroFlag()); assertFalse(cpu.getZeroFlag());
assertFalse(cpu.getNegativeFlag()); assertFalse(cpu.getNegativeFlag());
} }
public void test_TAY_SetsZeroFlagIfYIsZero() throws MemoryAccessException { public void test_TAY_SetsZeroFlagIfYIsZero() throws MemoryAccessException {
cpu.setAccumulator(0x00); cpu.setAccumulator(0x00);
bus.loadProgram(0xa8); bus.loadProgram(0xa8);
cpu.step(); cpu.step();
assertEquals(0x00, cpu.getYRegister()); assertEquals(0x00, cpu.getYRegister());
assertTrue(cpu.getZeroFlag()); assertTrue(cpu.getZeroFlag());
assertFalse(cpu.getNegativeFlag()); assertFalse(cpu.getNegativeFlag());
} }
public void test_TAY_SetsNegativeFlagIfYIsNegative() throws MemoryAccessException { public void test_TAY_SetsNegativeFlagIfYIsNegative() throws MemoryAccessException {
cpu.setAccumulator(0xff); cpu.setAccumulator(0xff);
bus.loadProgram(0xa8); bus.loadProgram(0xa8);
cpu.step(); cpu.step();
assertEquals(0xff, cpu.getYRegister()); assertEquals(0xff, cpu.getYRegister());
assertFalse(cpu.getZeroFlag()); assertFalse(cpu.getZeroFlag());
assertTrue(cpu.getNegativeFlag()); assertTrue(cpu.getNegativeFlag());
} }
/* TSX - Transfer Stack Pointer to X Register - $ba */ /* TSX - Transfer Stack Pointer to X Register - $ba */
public void test_TSX() throws MemoryAccessException { public void test_TSX() throws MemoryAccessException {
cpu.setStackPointer(0x32); cpu.setStackPointer(0x32);
bus.loadProgram(0xba); bus.loadProgram(0xba);
cpu.step(); cpu.step();
assertEquals(0x32, cpu.getXRegister()); assertEquals(0x32, cpu.getXRegister());
assertFalse(cpu.getZeroFlag()); assertFalse(cpu.getZeroFlag());
assertFalse(cpu.getNegativeFlag()); assertFalse(cpu.getNegativeFlag());
} }
public void test_TSX_SetsZeroFlagIfXIsZero() throws MemoryAccessException { public void test_TSX_SetsZeroFlagIfXIsZero() throws MemoryAccessException {
cpu.setStackPointer(0x00); cpu.setStackPointer(0x00);
bus.loadProgram(0xba); bus.loadProgram(0xba);
cpu.step(); cpu.step();
assertEquals(0x00, cpu.getXRegister()); assertEquals(0x00, cpu.getXRegister());
assertTrue(cpu.getZeroFlag()); assertTrue(cpu.getZeroFlag());
assertFalse(cpu.getNegativeFlag()); assertFalse(cpu.getNegativeFlag());
} }
public void test_TSX_SetsNegativeFlagIfXIsNegative() throws MemoryAccessException { public void test_TSX_SetsNegativeFlagIfXIsNegative() throws MemoryAccessException {
cpu.setStackPointer(0xff); cpu.setStackPointer(0xff);
bus.loadProgram(0xba); bus.loadProgram(0xba);
cpu.step(); cpu.step();
assertEquals(0xff, cpu.getXRegister()); assertEquals(0xff, cpu.getXRegister());
assertFalse(cpu.getZeroFlag()); assertFalse(cpu.getZeroFlag());
assertTrue(cpu.getNegativeFlag()); assertTrue(cpu.getNegativeFlag());
} }
/* TXA - Transfer X Register to Accumulator - $8a */ /* TXA - Transfer X Register to Accumulator - $8a */
public void test_TXA() throws MemoryAccessException { public void test_TXA() throws MemoryAccessException {
cpu.setXRegister(0x32); cpu.setXRegister(0x32);
bus.loadProgram(0x8a); bus.loadProgram(0x8a);
cpu.step(); cpu.step();
assertEquals(0x32, cpu.getAccumulator()); assertEquals(0x32, cpu.getAccumulator());
assertFalse(cpu.getZeroFlag()); assertFalse(cpu.getZeroFlag());
assertFalse(cpu.getNegativeFlag()); assertFalse(cpu.getNegativeFlag());
} }
public void test_TXA_SetsZeroFlagIfAccumulatorIsZero() throws MemoryAccessException { public void test_TXA_SetsZeroFlagIfAccumulatorIsZero() throws MemoryAccessException {
cpu.setXRegister(0x00); cpu.setXRegister(0x00);
bus.loadProgram(0x8a); bus.loadProgram(0x8a);
cpu.step(); cpu.step();
assertEquals(0x00, cpu.getAccumulator()); assertEquals(0x00, cpu.getAccumulator());
assertTrue(cpu.getZeroFlag()); assertTrue(cpu.getZeroFlag());
assertFalse(cpu.getNegativeFlag()); assertFalse(cpu.getNegativeFlag());
} }
public void test_TXA_SetsNegativeFlagIfAccumulatorIsNegative() throws MemoryAccessException { public void test_TXA_SetsNegativeFlagIfAccumulatorIsNegative() throws MemoryAccessException {
cpu.setXRegister(0xff); cpu.setXRegister(0xff);
bus.loadProgram(0x8a); bus.loadProgram(0x8a);
cpu.step(); cpu.step();
assertEquals(0xff, cpu.getAccumulator()); assertEquals(0xff, cpu.getAccumulator());
assertFalse(cpu.getZeroFlag()); assertFalse(cpu.getZeroFlag());
assertTrue(cpu.getNegativeFlag()); assertTrue(cpu.getNegativeFlag());
} }
/* TXS - Transfer X Register to Stack Pointer - $9a */ /* TXS - Transfer X Register to Stack Pointer - $9a */
public void test_TXS() throws MemoryAccessException { public void test_TXS() throws MemoryAccessException {
cpu.setXRegister(0x32); cpu.setXRegister(0x32);
bus.loadProgram(0x9a); bus.loadProgram(0x9a);
cpu.step(); cpu.step();
assertEquals(0x32, cpu.getStackPointer()); assertEquals(0x32, cpu.getStackPointer());
assertFalse(cpu.getZeroFlag()); assertFalse(cpu.getZeroFlag());
assertFalse(cpu.getNegativeFlag()); assertFalse(cpu.getNegativeFlag());
} }
public void test_TXS_DoesNotAffectProcessorStatus() throws MemoryAccessException { public void test_TXS_DoesNotAffectProcessorStatus() throws MemoryAccessException {
cpu.setXRegister(0x00); cpu.setXRegister(0x00);
bus.loadProgram(0x9a); bus.loadProgram(0x9a);
cpu.step(); cpu.step();
assertEquals(0x00, cpu.getStackPointer()); assertEquals(0x00, cpu.getStackPointer());
assertFalse(cpu.getZeroFlag()); assertFalse(cpu.getZeroFlag());
assertFalse(cpu.getNegativeFlag()); assertFalse(cpu.getNegativeFlag());
cpu.setXRegister(0x80); cpu.setXRegister(0x80);
bus.loadProgram(0x9a); bus.loadProgram(0x9a);
cpu.step(); cpu.step();
assertEquals(0x80, cpu.getStackPointer()); assertEquals(0x80, cpu.getStackPointer());
assertFalse(cpu.getZeroFlag()); assertFalse(cpu.getZeroFlag());
assertFalse(cpu.getNegativeFlag()); assertFalse(cpu.getNegativeFlag());
} }
/* TYA - Transfer Y Register to Accumulator - $98 */ /* TYA - Transfer Y Register to Accumulator - $98 */
public void test_TYA() throws MemoryAccessException { public void test_TYA() throws MemoryAccessException {
cpu.setYRegister(0x32); cpu.setYRegister(0x32);
bus.loadProgram(0x98); bus.loadProgram(0x98);
cpu.step(); cpu.step();
assertEquals(0x32, cpu.getAccumulator()); assertEquals(0x32, cpu.getAccumulator());
assertFalse(cpu.getZeroFlag()); assertFalse(cpu.getZeroFlag());
assertFalse(cpu.getNegativeFlag()); assertFalse(cpu.getNegativeFlag());
} }
public void test_TYA_SetsZeroFlagIfAccumulatorIsZero() throws MemoryAccessException { public void test_TYA_SetsZeroFlagIfAccumulatorIsZero() throws MemoryAccessException {
cpu.setYRegister(0x00); cpu.setYRegister(0x00);
bus.loadProgram(0x98); bus.loadProgram(0x98);
cpu.step(); cpu.step();
assertEquals(0x00, cpu.getAccumulator()); assertEquals(0x00, cpu.getAccumulator());
assertTrue(cpu.getZeroFlag()); assertTrue(cpu.getZeroFlag());
assertFalse(cpu.getNegativeFlag()); assertFalse(cpu.getNegativeFlag());
} }
public void test_TYA_SetsNegativeFlagIfAccumulatorIsNegative() throws MemoryAccessException { public void test_TYA_SetsNegativeFlagIfAccumulatorIsNegative() throws MemoryAccessException {
cpu.setYRegister(0xff); cpu.setYRegister(0xff);
bus.loadProgram(0x98); bus.loadProgram(0x98);
cpu.step(); cpu.step();
assertEquals(0xff, cpu.getAccumulator()); assertEquals(0xff, cpu.getAccumulator());
assertFalse(cpu.getZeroFlag()); assertFalse(cpu.getZeroFlag());
assertTrue(cpu.getNegativeFlag()); assertTrue(cpu.getNegativeFlag());
} }
} }
@@ -3,79 +3,80 @@ package com.loomcom.symon;
import com.loomcom.symon.devices.Memory; import com.loomcom.symon.devices.Memory;
import org.junit.*; import org.junit.*;
import static org.junit.Assert.*; import static org.junit.Assert.*;
public class CpuIndexedIndirectModeTest { public class CpuIndexedIndirectModeTest {
protected Cpu cpu; protected Cpu cpu;
protected Bus bus; protected Bus bus;
protected Memory mem; protected Memory mem;
@Before @Before
public void runBeforeEveryTest() throws Exception { public void runBeforeEveryTest() throws Exception {
this.cpu = new Cpu(); this.cpu = new Cpu();
this.bus = new Bus(0x0000, 0xffff); this.bus = new Bus(0x0000, 0xffff);
this.mem = new Memory(0x0000, 0x10000); this.mem = new Memory(0x0000, 0x10000);
bus.addCpu(cpu); bus.addCpu(cpu);
bus.addDevice(mem); bus.addDevice(mem);
// Load the reset vector. // Load the reset vector.
bus.write(0xfffc, Bus.DEFAULT_LOAD_ADDRESS & 0x00ff); bus.write(0xfffc, Bus.DEFAULT_LOAD_ADDRESS & 0x00ff);
bus.write(0xfffd, (Bus.DEFAULT_LOAD_ADDRESS & 0xff00)>>>8); bus.write(0xfffd, (Bus.DEFAULT_LOAD_ADDRESS & 0xff00) >>> 8);
cpu.reset(); cpu.reset();
// Assert initial state // Assert initial state
assertEquals(0, cpu.getAccumulator()); assertEquals(0, cpu.getAccumulator());
assertEquals(0, cpu.getXRegister()); assertEquals(0, cpu.getXRegister());
assertEquals(0, cpu.getYRegister()); assertEquals(0, cpu.getYRegister());
assertEquals(0x200, cpu.getProgramCounter()); assertEquals(0x200, cpu.getProgramCounter());
assertEquals(0xff, cpu.getStackPointer()); assertEquals(0xff, cpu.getStackPointer());
assertEquals(0x20, cpu.getProcessorStatus()); assertEquals(0x20, cpu.getProcessorStatus());
} }
@Test @Test
public void test_LDA() throws Exception { public void test_LDA() throws Exception {
bus.write(0x008c, 0x3f); bus.write(0x008c, 0x3f);
bus.write(0x008d, 0xc4); bus.write(0x008d, 0xc4);
bus.write(0xc43f, 0x45); bus.write(0xc43f, 0x45);
cpu.setXRegister(0x0c); cpu.setXRegister(0x0c);
bus.loadProgram(0xa1, 0x80); // LDA ($80,X) bus.loadProgram(0xa1, 0x80); // LDA ($80,X)
cpu.step(1); cpu.step(1);
assertEquals(0x45, cpu.getAccumulator()); assertEquals(0x45, cpu.getAccumulator());
} }
@Test @Test
public void test_ORA() throws Exception { public void test_ORA() throws Exception {
bus.write(0x0012, 0x1f); bus.write(0x0012, 0x1f);
bus.write(0x0013, 0xc5); bus.write(0x0013, 0xc5);
bus.write(0xc51f, 0x31); bus.write(0xc51f, 0x31);
cpu.setXRegister(0x02); cpu.setXRegister(0x02);
cpu.setAccumulator(0x15); cpu.setAccumulator(0x15);
bus.loadProgram(0x01, 0x10); // ORA ($10,X) bus.loadProgram(0x01, 0x10); // ORA ($10,X)
cpu.step(1); cpu.step(1);
assertEquals(0x35, cpu.getAccumulator()); assertEquals(0x35, cpu.getAccumulator());
assertEquals(0x31, bus.read(0xc51f)); assertEquals(0x31, bus.read(0xc51f));
} }
@Test @Test
public void test_AND() throws Exception { public void test_AND() throws Exception {
bus.write(0x0012, 0x1f); bus.write(0x0012, 0x1f);
bus.write(0x0013, 0xc5); bus.write(0x0013, 0xc5);
bus.write(0xc51f, 0x31); bus.write(0xc51f, 0x31);
cpu.setXRegister(0x02); cpu.setXRegister(0x02);
cpu.setAccumulator(0x15); cpu.setAccumulator(0x15);
bus.loadProgram(0x21, 0x10); // AND ($10,X) bus.loadProgram(0x21, 0x10); // AND ($10,X)
cpu.step(1); cpu.step(1);
assertEquals(0x11, cpu.getAccumulator()); assertEquals(0x11, cpu.getAccumulator());
assertEquals(0x31, bus.read(0xc51f)); assertEquals(0x31, bus.read(0xc51f));
} }
} }
@@ -3,81 +3,82 @@ package com.loomcom.symon;
import com.loomcom.symon.devices.Memory; import com.loomcom.symon.devices.Memory;
import org.junit.*; import org.junit.*;
import static org.junit.Assert.*; import static org.junit.Assert.*;
public class CpuIndirectIndexedModeTest { public class CpuIndirectIndexedModeTest {
protected Cpu cpu; protected Cpu cpu;
protected Bus bus; protected Bus bus;
protected Memory mem; protected Memory mem;
@Before @Before
public void runBeforeEveryTest() throws Exception { public void runBeforeEveryTest() throws Exception {
this.cpu = new Cpu(); this.cpu = new Cpu();
this.bus = new Bus(0x0000, 0xffff); this.bus = new Bus(0x0000, 0xffff);
this.mem = new Memory(0x0000, 0x10000); this.mem = new Memory(0x0000, 0x10000);
bus.addCpu(cpu); bus.addCpu(cpu);
bus.addDevice(mem); bus.addDevice(mem);
// Load the reset vector. // Load the reset vector.
bus.write(0xfffc, Bus.DEFAULT_LOAD_ADDRESS & 0x00ff); bus.write(0xfffc, Bus.DEFAULT_LOAD_ADDRESS & 0x00ff);
bus.write(0xfffd, (Bus.DEFAULT_LOAD_ADDRESS & 0xff00)>>>8); bus.write(0xfffd, (Bus.DEFAULT_LOAD_ADDRESS & 0xff00) >>> 8);
cpu.reset(); cpu.reset();
// Assert initial state // Assert initial state
assertEquals(0, cpu.getAccumulator()); assertEquals(0, cpu.getAccumulator());
assertEquals(0, cpu.getXRegister()); assertEquals(0, cpu.getXRegister());
assertEquals(0, cpu.getYRegister()); assertEquals(0, cpu.getYRegister());
assertEquals(0x200, cpu.getProgramCounter()); assertEquals(0x200, cpu.getProgramCounter());
assertEquals(0xff, cpu.getStackPointer()); assertEquals(0xff, cpu.getStackPointer());
assertEquals(0x20, cpu.getProcessorStatus()); assertEquals(0x20, cpu.getProcessorStatus());
} }
@Test @Test
public void test_LDA() throws Exception { public void test_LDA() throws Exception {
assertEquals(cpu.toString(), 0x00, cpu.getAccumulator()); assertEquals(cpu.toString(), 0x00, cpu.getAccumulator());
bus.write(0x0014, 0x00); bus.write(0x0014, 0x00);
bus.write(0x0015, 0xd8); bus.write(0x0015, 0xd8);
bus.write(0xd828, 0x03); bus.write(0xd828, 0x03);
cpu.setYRegister(0x28); cpu.setYRegister(0x28);
bus.loadProgram(0xb1, 0x14); // LDA ($14),Y bus.loadProgram(0xb1, 0x14); // LDA ($14),Y
cpu.step(1); cpu.step(1);
assertEquals(0x03, cpu.getAccumulator()); assertEquals(0x03, cpu.getAccumulator());
} }
@Test @Test
public void test_ORA() throws Exception { public void test_ORA() throws Exception {
bus.write(0x0014, 0x00); bus.write(0x0014, 0x00);
bus.write(0x0015, 0xd8); bus.write(0x0015, 0xd8);
bus.write(0xd828, 0xe3); bus.write(0xd828, 0xe3);
cpu.setYRegister(0x28); cpu.setYRegister(0x28);
cpu.setAccumulator(0x32); cpu.setAccumulator(0x32);
bus.loadProgram(0x11, 0x14); // ORA ($14),Y bus.loadProgram(0x11, 0x14); // ORA ($14),Y
cpu.step(1); cpu.step(1);
assertEquals(0xf3, cpu.getAccumulator()); assertEquals(0xf3, cpu.getAccumulator());
assertEquals(0xe3, bus.read(0xd828)); assertEquals(0xe3, bus.read(0xd828));
} }
@Test @Test
public void test_AND() throws Exception { public void test_AND() throws Exception {
bus.write(0x0014, 0x00); bus.write(0x0014, 0x00);
bus.write(0x0015, 0xd8); bus.write(0x0015, 0xd8);
bus.write(0xd828, 0xe3); bus.write(0xd828, 0xe3);
cpu.setYRegister(0x28); cpu.setYRegister(0x28);
cpu.setAccumulator(0x32); cpu.setAccumulator(0x32);
bus.loadProgram(0x31, 0x14); // AND ($14),Y bus.loadProgram(0x31, 0x14); // AND ($14),Y
cpu.step(1); cpu.step(1);
assertEquals(0x22, cpu.getAccumulator()); assertEquals(0x22, cpu.getAccumulator());
assertEquals(0xe3, bus.read(0xd828)); assertEquals(0xe3, bus.read(0xd828));
} }
} }
@@ -2,7 +2,6 @@ package com.loomcom.symon;
import com.loomcom.symon.devices.Memory; import com.loomcom.symon.devices.Memory;
import com.loomcom.symon.exceptions.MemoryAccessException; import com.loomcom.symon.exceptions.MemoryAccessException;
import com.loomcom.symon.InstructionTable;
import junit.framework.TestCase; import junit.framework.TestCase;
@@ -7,30 +7,30 @@ import junit.framework.TestCase;
public class CpuRelativeModeTest extends TestCase { public class CpuRelativeModeTest extends TestCase {
protected Cpu cpu; protected Cpu cpu;
protected Bus bus; protected Bus bus;
protected Memory mem; protected Memory mem;
protected void setUp() throws Exception { protected void setUp() throws Exception {
this.cpu = new Cpu(); this.cpu = new Cpu();
this.bus = new Bus(0x0000, 0xffff); this.bus = new Bus(0x0000, 0xffff);
this.mem = new Memory(0x0000, 0x10000); this.mem = new Memory(0x0000, 0x10000);
bus.addCpu(cpu); bus.addCpu(cpu);
bus.addDevice(mem); bus.addDevice(mem);
// Load the reset vector. // Load the reset vector.
bus.write(0xfffc, Bus.DEFAULT_LOAD_ADDRESS & 0x00ff); bus.write(0xfffc, Bus.DEFAULT_LOAD_ADDRESS & 0x00ff);
bus.write(0xfffd, (Bus.DEFAULT_LOAD_ADDRESS & 0xff00)>>>8); bus.write(0xfffd, (Bus.DEFAULT_LOAD_ADDRESS & 0xff00) >>> 8);
cpu.reset(); cpu.reset();
// Assert initial state // Assert initial state
assertEquals(0, cpu.getAccumulator()); assertEquals(0, cpu.getAccumulator());
assertEquals(0, cpu.getXRegister()); assertEquals(0, cpu.getXRegister());
assertEquals(0, cpu.getYRegister()); assertEquals(0, cpu.getYRegister());
assertEquals(0x200, cpu.getProgramCounter()); assertEquals(0x200, cpu.getProgramCounter());
assertEquals(0xff, cpu.getStackPointer()); assertEquals(0xff, cpu.getStackPointer());
assertEquals(0x20, cpu.getProcessorStatus()); assertEquals(0x20, cpu.getProcessorStatus());
} }
/* /*
* The following opcodes are tested for correctness in this file: * The following opcodes are tested for correctness in this file:
@@ -48,234 +48,234 @@ public class CpuRelativeModeTest extends TestCase {
/* BPL - Branch if Positive - 0x10 */ /* BPL - Branch if Positive - 0x10 */
public void test_BPL() throws MemoryAccessException { public void test_BPL() throws MemoryAccessException {
// Positive Offset // Positive Offset
bus.loadProgram(0x10, 0x05); // BPL $05 ; *=$0202+$05 ($0207) bus.loadProgram(0x10, 0x05); // BPL $05 ; *=$0202+$05 ($0207)
cpu.setNegativeFlag(); cpu.setNegativeFlag();
cpu.step(); cpu.step();
assertEquals(0x202, cpu.getProgramCounter()); assertEquals(0x202, cpu.getProgramCounter());
cpu.reset(); cpu.reset();
bus.loadProgram(0x10, 0x05); // BPL $05 ; *=$0202+$05 ($0207) bus.loadProgram(0x10, 0x05); // BPL $05 ; *=$0202+$05 ($0207)
cpu.clearNegativeFlag(); cpu.clearNegativeFlag();
cpu.step(); cpu.step();
assertEquals(0x207, cpu.getProgramCounter()); assertEquals(0x207, cpu.getProgramCounter());
// Negative Offset // Negative Offset
cpu.reset(); cpu.reset();
bus.loadProgram(0x10, 0xfb); // BPL $fb ; *=$0202-$05 ($01fd) bus.loadProgram(0x10, 0xfb); // BPL $fb ; *=$0202-$05 ($01fd)
cpu.setNegativeFlag(); cpu.setNegativeFlag();
cpu.step(); cpu.step();
assertEquals(0x202, cpu.getProgramCounter()); assertEquals(0x202, cpu.getProgramCounter());
cpu.reset(); cpu.reset();
bus.loadProgram(0x10, 0xfb); // BPL $fb ; *=$0202-$05 ($01fd) bus.loadProgram(0x10, 0xfb); // BPL $fb ; *=$0202-$05 ($01fd)
cpu.clearNegativeFlag(); cpu.clearNegativeFlag();
cpu.step(); cpu.step();
assertEquals(0x1fd, cpu.getProgramCounter()); assertEquals(0x1fd, cpu.getProgramCounter());
} }
/* BMI - Branch if Minus - 0x30 */ /* BMI - Branch if Minus - 0x30 */
public void test_BMI() throws MemoryAccessException { public void test_BMI() throws MemoryAccessException {
// Positive Offset // Positive Offset
bus.loadProgram(0x30, 0x05); // BMI $05 ; *=$0202+$05 ($0207) bus.loadProgram(0x30, 0x05); // BMI $05 ; *=$0202+$05 ($0207)
cpu.setNegativeFlag(); cpu.setNegativeFlag();
cpu.step(); cpu.step();
assertEquals(0x207, cpu.getProgramCounter()); assertEquals(0x207, cpu.getProgramCounter());
cpu.reset(); cpu.reset();
bus.loadProgram(0x30, 0x05); // BMI $05 ; *=$0202+$05 ($0207) bus.loadProgram(0x30, 0x05); // BMI $05 ; *=$0202+$05 ($0207)
cpu.clearNegativeFlag(); cpu.clearNegativeFlag();
cpu.step(); cpu.step();
assertEquals(0x202, cpu.getProgramCounter()); assertEquals(0x202, cpu.getProgramCounter());
// Negative Offset // Negative Offset
cpu.reset(); cpu.reset();
bus.loadProgram(0x30, 0xfb); // BMI $fb ; *=$0202-$05 ($01fd) bus.loadProgram(0x30, 0xfb); // BMI $fb ; *=$0202-$05 ($01fd)
cpu.setNegativeFlag(); cpu.setNegativeFlag();
cpu.step(); cpu.step();
assertEquals(0x1fd, cpu.getProgramCounter()); assertEquals(0x1fd, cpu.getProgramCounter());
cpu.reset(); cpu.reset();
bus.loadProgram(0x30, 0xfb); // BMI $fb ; *=$0202-$05 ($01fd) bus.loadProgram(0x30, 0xfb); // BMI $fb ; *=$0202-$05 ($01fd)
cpu.clearNegativeFlag(); cpu.clearNegativeFlag();
cpu.step(); cpu.step();
assertEquals(0x202, cpu.getProgramCounter()); assertEquals(0x202, cpu.getProgramCounter());
} }
/* BVC - Branch if Overflow Clear - 0x50 */ /* BVC - Branch if Overflow Clear - 0x50 */
public void test_BVC() throws MemoryAccessException { public void test_BVC() throws MemoryAccessException {
// Positive Offset // Positive Offset
bus.loadProgram(0x50, 0x05); // BVC $05 ; *=$0202+$05 ($0207) bus.loadProgram(0x50, 0x05); // BVC $05 ; *=$0202+$05 ($0207)
cpu.setOverflowFlag(); cpu.setOverflowFlag();
cpu.step(); cpu.step();
assertEquals(0x202, cpu.getProgramCounter()); assertEquals(0x202, cpu.getProgramCounter());
cpu.reset(); cpu.reset();
bus.loadProgram(0x50, 0x05); // BVC $05 ; *=$0202+$05 ($0207) bus.loadProgram(0x50, 0x05); // BVC $05 ; *=$0202+$05 ($0207)
cpu.clearOverflowFlag(); cpu.clearOverflowFlag();
cpu.step(); cpu.step();
assertEquals(0x207, cpu.getProgramCounter()); assertEquals(0x207, cpu.getProgramCounter());
// Negative Offset // Negative Offset
cpu.reset(); cpu.reset();
bus.loadProgram(0x50, 0xfb); // BVC $fb ; *=$0202-$05 ($01fd) bus.loadProgram(0x50, 0xfb); // BVC $fb ; *=$0202-$05 ($01fd)
cpu.setOverflowFlag(); cpu.setOverflowFlag();
cpu.step(); cpu.step();
assertEquals(0x202, cpu.getProgramCounter()); assertEquals(0x202, cpu.getProgramCounter());
cpu.reset(); cpu.reset();
bus.loadProgram(0x50, 0xfb); // BVC $fb ; *=$0202-$05 ($01fd) bus.loadProgram(0x50, 0xfb); // BVC $fb ; *=$0202-$05 ($01fd)
cpu.clearOverflowFlag(); cpu.clearOverflowFlag();
cpu.step(); cpu.step();
assertEquals(0x1fd, cpu.getProgramCounter()); assertEquals(0x1fd, cpu.getProgramCounter());
} }
/* BVS - Branch if Overflow Set - 0x70 */ /* BVS - Branch if Overflow Set - 0x70 */
public void test_BVS() throws MemoryAccessException { public void test_BVS() throws MemoryAccessException {
// Positive Offset // Positive Offset
bus.loadProgram(0x70, 0x05); // BVS $05 ; *=$0202+$05 ($0207) bus.loadProgram(0x70, 0x05); // BVS $05 ; *=$0202+$05 ($0207)
cpu.setOverflowFlag(); cpu.setOverflowFlag();
cpu.step(); cpu.step();
assertEquals(0x207, cpu.getProgramCounter()); assertEquals(0x207, cpu.getProgramCounter());
cpu.reset(); cpu.reset();
bus.loadProgram(0x70, 0x05); // BVS $05 ; *=$0202+$05 ($0207) bus.loadProgram(0x70, 0x05); // BVS $05 ; *=$0202+$05 ($0207)
cpu.clearOverflowFlag(); cpu.clearOverflowFlag();
cpu.step(); cpu.step();
assertEquals(0x202, cpu.getProgramCounter()); assertEquals(0x202, cpu.getProgramCounter());
// Negative Offset // Negative Offset
cpu.reset(); cpu.reset();
bus.loadProgram(0x70, 0xfb); // BVS $fb ; *=$0202-$05 ($01fd) bus.loadProgram(0x70, 0xfb); // BVS $fb ; *=$0202-$05 ($01fd)
cpu.setOverflowFlag(); cpu.setOverflowFlag();
cpu.step(); cpu.step();
assertEquals(0x1fd, cpu.getProgramCounter()); assertEquals(0x1fd, cpu.getProgramCounter());
cpu.reset(); cpu.reset();
bus.loadProgram(0x70, 0xfb); // BVS $fb ; *=$0202-$05 ($01fd) bus.loadProgram(0x70, 0xfb); // BVS $fb ; *=$0202-$05 ($01fd)
cpu.clearOverflowFlag(); cpu.clearOverflowFlag();
cpu.step(); cpu.step();
assertEquals(0x202, cpu.getProgramCounter()); assertEquals(0x202, cpu.getProgramCounter());
} }
/* BCC - Branch if Carry Clear - 0x90 */ /* BCC - Branch if Carry Clear - 0x90 */
public void test_BCC() throws MemoryAccessException { public void test_BCC() throws MemoryAccessException {
// Positive Offset // Positive Offset
bus.loadProgram(0x90, 0x05); // BCC $05 ; *=$0202+$05 ($0207) bus.loadProgram(0x90, 0x05); // BCC $05 ; *=$0202+$05 ($0207)
cpu.setCarryFlag(); cpu.setCarryFlag();
cpu.step(); cpu.step();
assertEquals(0x202, cpu.getProgramCounter()); assertEquals(0x202, cpu.getProgramCounter());
cpu.reset(); cpu.reset();
bus.loadProgram(0x90, 0x05); // BCC $05 ; *=$0202+$05 ($0207) bus.loadProgram(0x90, 0x05); // BCC $05 ; *=$0202+$05 ($0207)
cpu.clearCarryFlag(); cpu.clearCarryFlag();
cpu.step(); cpu.step();
assertEquals(0x207, cpu.getProgramCounter()); assertEquals(0x207, cpu.getProgramCounter());
// Negative Offset // Negative Offset
cpu.reset(); cpu.reset();
bus.loadProgram(0x90, 0xfb); // BCC $fb ; *=$0202-$05 ($01fd) bus.loadProgram(0x90, 0xfb); // BCC $fb ; *=$0202-$05 ($01fd)
cpu.setCarryFlag(); cpu.setCarryFlag();
cpu.step(); cpu.step();
assertEquals(0x202, cpu.getProgramCounter()); assertEquals(0x202, cpu.getProgramCounter());
cpu.reset(); cpu.reset();
bus.loadProgram(0x90, 0xfb); // BCC $fb ; *=$0202-$05 ($01fd) bus.loadProgram(0x90, 0xfb); // BCC $fb ; *=$0202-$05 ($01fd)
cpu.clearCarryFlag(); cpu.clearCarryFlag();
cpu.step(); cpu.step();
assertEquals(0x1fd, cpu.getProgramCounter()); assertEquals(0x1fd, cpu.getProgramCounter());
} }
/* BCS - Branch if Carry Set - 0xb0 */ /* BCS - Branch if Carry Set - 0xb0 */
public void test_BCS() throws MemoryAccessException { public void test_BCS() throws MemoryAccessException {
// Positive Offset // Positive Offset
bus.loadProgram(0xb0, 0x05); // BCS $05 ; *=$0202+$05 ($0207) bus.loadProgram(0xb0, 0x05); // BCS $05 ; *=$0202+$05 ($0207)
cpu.setCarryFlag(); cpu.setCarryFlag();
cpu.step(); cpu.step();
assertEquals(0x207, cpu.getProgramCounter()); assertEquals(0x207, cpu.getProgramCounter());
cpu.reset(); cpu.reset();
bus.loadProgram(0xb0, 0x05); // BCS $05 ; *=$0202+$05 ($0207) bus.loadProgram(0xb0, 0x05); // BCS $05 ; *=$0202+$05 ($0207)
cpu.clearCarryFlag(); cpu.clearCarryFlag();
cpu.step(); cpu.step();
assertEquals(0x202, cpu.getProgramCounter()); assertEquals(0x202, cpu.getProgramCounter());
// Negative Offset // Negative Offset
cpu.reset(); cpu.reset();
bus.loadProgram(0xb0, 0xfb); // BCS $fb ; *=$0202-$05 ($01fd) bus.loadProgram(0xb0, 0xfb); // BCS $fb ; *=$0202-$05 ($01fd)
cpu.setCarryFlag(); cpu.setCarryFlag();
cpu.step(); cpu.step();
assertEquals(0x1fd, cpu.getProgramCounter()); assertEquals(0x1fd, cpu.getProgramCounter());
cpu.reset(); cpu.reset();
bus.loadProgram(0xb0, 0xfb); // BCS $fb ; *=$0202-$05 ($01fd) bus.loadProgram(0xb0, 0xfb); // BCS $fb ; *=$0202-$05 ($01fd)
cpu.clearCarryFlag(); cpu.clearCarryFlag();
cpu.step(); cpu.step();
assertEquals(0x202, cpu.getProgramCounter()); assertEquals(0x202, cpu.getProgramCounter());
} }
/* BNE - Branch if Not Equal to Zero - 0xd0 */ /* BNE - Branch if Not Equal to Zero - 0xd0 */
public void test_BNE() throws MemoryAccessException { public void test_BNE() throws MemoryAccessException {
// Positive Offset // Positive Offset
bus.loadProgram(0xd0, 0x05); // BNE $05 ; *=$0202+$05 ($0207) bus.loadProgram(0xd0, 0x05); // BNE $05 ; *=$0202+$05 ($0207)
cpu.setZeroFlag(); cpu.setZeroFlag();
cpu.step(); cpu.step();
assertEquals(0x202, cpu.getProgramCounter()); assertEquals(0x202, cpu.getProgramCounter());
cpu.reset(); cpu.reset();
bus.loadProgram(0xd0, 0x05); // BNE $05 ; *=$0202+$05 ($0207) bus.loadProgram(0xd0, 0x05); // BNE $05 ; *=$0202+$05 ($0207)
cpu.clearZeroFlag(); cpu.clearZeroFlag();
cpu.step(); cpu.step();
assertEquals(0x207, cpu.getProgramCounter()); assertEquals(0x207, cpu.getProgramCounter());
// Negative Offset // Negative Offset
cpu.reset(); cpu.reset();
bus.loadProgram(0xd0, 0xfb); // BNE $fb ; *=$0202-$05 ($01fd) bus.loadProgram(0xd0, 0xfb); // BNE $fb ; *=$0202-$05 ($01fd)
cpu.setZeroFlag(); cpu.setZeroFlag();
cpu.step(); cpu.step();
assertEquals(0x202, cpu.getProgramCounter()); assertEquals(0x202, cpu.getProgramCounter());
cpu.reset(); cpu.reset();
bus.loadProgram(0xd0, 0xfb); // BNE $fb ; *=$0202-$05 ($01fd) bus.loadProgram(0xd0, 0xfb); // BNE $fb ; *=$0202-$05 ($01fd)
cpu.clearZeroFlag(); cpu.clearZeroFlag();
cpu.step(); cpu.step();
assertEquals(0x1fd, cpu.getProgramCounter()); assertEquals(0x1fd, cpu.getProgramCounter());
} }
/* BEQ - Branch if Equal to Zero - 0xf0 */ /* BEQ - Branch if Equal to Zero - 0xf0 */
public void test_BEQ() throws MemoryAccessException { public void test_BEQ() throws MemoryAccessException {
// Positive Offset // Positive Offset
bus.loadProgram(0xf0, 0x05); // BEQ $05 ; *=$0202+$05 ($0207) bus.loadProgram(0xf0, 0x05); // BEQ $05 ; *=$0202+$05 ($0207)
cpu.setZeroFlag(); cpu.setZeroFlag();
cpu.step(); cpu.step();
assertEquals(0x207, cpu.getProgramCounter()); assertEquals(0x207, cpu.getProgramCounter());
cpu.reset(); cpu.reset();
bus.loadProgram(0xf0, 0x05); // BEQ $05 ; *=$0202+$05 ($0207) bus.loadProgram(0xf0, 0x05); // BEQ $05 ; *=$0202+$05 ($0207)
cpu.clearZeroFlag(); cpu.clearZeroFlag();
cpu.step(); cpu.step();
assertEquals(0x202, cpu.getProgramCounter()); assertEquals(0x202, cpu.getProgramCounter());
// Negative Offset // Negative Offset
cpu.reset(); cpu.reset();
bus.loadProgram(0xf0, 0xfb); // BEQ $fb ; *=$0202-$05 ($01fd) bus.loadProgram(0xf0, 0xfb); // BEQ $fb ; *=$0202-$05 ($01fd)
cpu.setZeroFlag(); cpu.setZeroFlag();
cpu.step(); cpu.step();
assertEquals(0x1fd, cpu.getProgramCounter()); assertEquals(0x1fd, cpu.getProgramCounter());
cpu.reset(); cpu.reset();
bus.loadProgram(0xf0, 0xfb); // BEQ $fb ; *=$0202-$05 ($01fd) bus.loadProgram(0xf0, 0xfb); // BEQ $fb ; *=$0202-$05 ($01fd)
cpu.clearZeroFlag(); cpu.clearZeroFlag();
cpu.step(); cpu.step();
assertEquals(0x202, cpu.getProgramCounter()); assertEquals(0x202, cpu.getProgramCounter());
} }
} }
@@ -392,27 +392,4 @@ public class CpuTest extends TestCase {
cpu.setYRegister(0x95); cpu.setYRegister(0x95);
assertEquals(0x15, cpu.zpyAddress(0x80)); assertEquals(0x15, cpu.zpyAddress(0x80));
} }
public void testPcStatus() {
cpu.setProgramCounter(0x03fa);
assertEquals("$03FA", cpu.getProgramCounterStatus());
}
public void testOpcodeStatus() throws MemoryAccessException {
// LDA (immediate)
bus.write(0x0200, 0xa9);
bus.write(0x0201, 0xef);
cpu.step();
assertEquals("LDA #$EF", cpu.getOpcodeStatus());
// BRK instruction
bus.write(0x0202, 0x00);
cpu.step();
assertEquals("BRK", cpu.getOpcodeStatus());
// Illegal opcode
cpu.step();
assertEquals("BRK", cpu.getOpcodeStatus());
}
} }