From c214cc9b431c686d184284d522dac8c4cb6e8d08 Mon Sep 17 00:00:00 2001 From: Seth Morabito Date: Sun, 14 Oct 2012 00:25:03 -0700 Subject: [PATCH] Fixes and enhancements. - Added ability to change inner border width of console window. - Fixed a nasty bug that prevented key press handling. - Reset now clears the accumulator and index registers. --- pom.xml | 2 +- src/main/java/com/loomcom/symon/Cpu.java | 5 + .../java/com/loomcom/symon/Preferences.java | 4 + .../java/com/loomcom/symon/Simulator.java | 30 +- .../java/com/loomcom/symon/ui/Console.java | 67 +- .../loomcom/symon/ui/PreferencesDialog.java | 53 +- .../loomcom/symon/CpuAbsoluteXModeTest.java | 18 + .../loomcom/symon/CpuAbsoluteYModeTest.java | 1425 +++++------ .../loomcom/symon/CpuIndirectXModeTest.java | 1369 +++++----- .../loomcom/symon/CpuZeroPageXModeTest.java | 2213 +++++++++-------- 10 files changed, 2682 insertions(+), 2504 deletions(-) diff --git a/pom.xml b/pom.xml index 9eedcbd..c680e29 100644 --- a/pom.xml +++ b/pom.xml @@ -44,7 +44,7 @@ com.grahamedgecombe.jterminal jterminal - 1.0.2-SNAPSHOT + 1.0.2-loomcom diff --git a/src/main/java/com/loomcom/symon/Cpu.java b/src/main/java/com/loomcom/symon/Cpu.java index 4b557b2..10dee96 100644 --- a/src/main/java/com/loomcom/symon/Cpu.java +++ b/src/main/java/com/loomcom/symon/Cpu.java @@ -118,6 +118,11 @@ public class Cpu implements InstructionTable { // Reset step counter stepCounter = 0L; + + // Reset registers. + a = 0; + x = 0; + y = 0; } public void step(int num) throws MemoryAccessException { diff --git a/src/main/java/com/loomcom/symon/Preferences.java b/src/main/java/com/loomcom/symon/Preferences.java index d0d547d..7e56593 100644 --- a/src/main/java/com/loomcom/symon/Preferences.java +++ b/src/main/java/com/loomcom/symon/Preferences.java @@ -8,11 +8,15 @@ public interface Preferences { public static final int DEFAULT_ACIA_ADDRESS = 0xc000; + public static final int DEFAULT_BORDER_WIDTH = 10; + public JDialog getDialog(); public int getProgramStartAddress(); public int getAciaAddress(); + public int getBorderWidth(); + public void updateUi(); } diff --git a/src/main/java/com/loomcom/symon/Simulator.java b/src/main/java/com/loomcom/symon/Simulator.java index dcfb896..704229a 100644 --- a/src/main/java/com/loomcom/symon/Simulator.java +++ b/src/main/java/com/loomcom/symon/Simulator.java @@ -73,7 +73,7 @@ public class Simulator implements ActionListener, Observer { private JMenuItem loadMenuItem; private JFileChooser fileChooser; - private Preferences preferences; + private PreferencesDialog preferences; public Simulator() throws MemoryRangeException { this.acia = new Acia(ACIA_BASE); @@ -109,6 +109,7 @@ public class Simulator implements ActionListener, Observer { // File Chooser fileChooser = new JFileChooser(); preferences = new PreferencesDialog(mainWindow, true); + preferences.addObserver(this); // Panel for Console and Buttons JPanel controlsContainer = new JPanel(); @@ -203,6 +204,8 @@ public class Simulator implements ActionListener, Observer { } else if (actionEvent.getSource() == stepButton) { handleStep(); } else if (actionEvent.getSource() == runStopButton) { + // Shift focus to the console. + console.requestFocus(); if (runLoop != null && runLoop.isRunning()) { runLoop.requestStop(); runLoop.interrupt(); @@ -327,18 +330,9 @@ public class Simulator implements ActionListener, Observer { // Read from the ACIA and immediately update the console if there's // output ready. if (acia.hasTxChar()) { - try { - SwingUtilities.invokeAndWait(new Runnable() { - public void run() { - console.print(Character.toString((char)acia.txRead())); - console.repaint(); - } - }); - } catch (InvocationTargetException e) { - e.printStackTrace(); - } catch (InterruptedException e) { - e.printStackTrace(); - } + // This is thread-safe + console.print(Character.toString((char)acia.txRead())); + console.repaint(); } // If a key has been pressed, fill the ACIA. @@ -414,8 +408,14 @@ public class Simulator implements ActionListener, Observer { public void update(Observable observable, Object o) { // Instance equality should work here, there is only one instance. if (observable == preferences) { - // TODO: Update system based on state. (i.e., update ACIA address, and raise a dialog if it - // overlaps with anything) + // TODO: Update ACIA base address if it has changed. + + int oldBorderWidth = console.getBorderWidth(); + if (oldBorderWidth != preferences.getBorderWidth()) { + // Resize the main window if the border width has changed. + console.setBorderWidth(preferences.getBorderWidth()); + mainWindow.pack(); + } } } diff --git a/src/main/java/com/loomcom/symon/ui/Console.java b/src/main/java/com/loomcom/symon/ui/Console.java index ce888a0..ecfffc6 100644 --- a/src/main/java/com/loomcom/symon/ui/Console.java +++ b/src/main/java/com/loomcom/symon/ui/Console.java @@ -6,6 +6,7 @@ import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import com.grahamedgecombe.jterminal.JTerminal; +import com.grahamedgecombe.jterminal.vt100.Vt100TerminalModel; import javax.swing.*; import javax.swing.border.BevelBorder; @@ -18,11 +19,20 @@ import javax.swing.border.Border; public class Console extends JTerminal implements KeyListener, MouseListener { + private static final int DEFAULT_COLUMNS = 80; + private static final int DEFAULT_ROWS = 24; + private static final int DEFAULT_BORDER_WIDTH = 10; + private boolean hasInput = false; private char keyBuffer; - public Console() { - super(); + public Console() { + this(DEFAULT_COLUMNS, DEFAULT_ROWS); + } + + public Console(int columns, int rows) { + super(new Vt100TerminalModel(columns, rows)); + setBorderWidth(DEFAULT_BORDER_WIDTH); addKeyListener(this); addMouseListener(this); Border emptyBorder = BorderFactory.createEmptyBorder(5, 5, 5, 0); @@ -31,6 +41,11 @@ public class Console extends JTerminal implements KeyListener, MouseListener { this.setBorder(compoundBorder); } + /** + * Reset the console. This will cause the console to be cleared and the cursor returned to the + * home position. + * + */ public void reset() { getModel().clear(); getModel().setCursorColumn(0); @@ -39,28 +54,50 @@ public class Console extends JTerminal implements KeyListener, MouseListener { this.hasInput = false; } - public void keyTyped(KeyEvent keyEvent) { - keyEvent.consume(); - } - - public void keyPressed(KeyEvent keyEvent) { - keyBuffer = keyEvent.getKeyChar(); - hasInput = true; - - System.out.println("Key Pressed (0x" + Integer.toString((int)keyBuffer, 16) + ") : " + keyBuffer); - - keyEvent.consume(); - } - + /** + * Returns true if a key has been pressed since the last time input was read. + * + * @return + */ public boolean hasInput() { return hasInput; } + /** + * Handle a Key Typed event. + * + * @param keyEvent The key event. + */ + public void keyTyped(KeyEvent keyEvent) { + keyEvent.consume(); + } + + /** + * Handle a Key Press event. + * + * @param keyEvent The key event. + */ + public void keyPressed(KeyEvent keyEvent) { + keyBuffer = keyEvent.getKeyChar(); + hasInput = true; + keyEvent.consume(); + } + + /** + * Read the most recently typed key from the single-char input buffer. + * + * @return The character typed. + */ public char readInputChar() { hasInput = false; return this.keyBuffer; } + /** + * Handle a key release event. + * + * @param keyEvent The key event. + */ public void keyReleased(KeyEvent keyEvent) { keyEvent.consume(); } diff --git a/src/main/java/com/loomcom/symon/ui/PreferencesDialog.java b/src/main/java/com/loomcom/symon/ui/PreferencesDialog.java index 1f9be06..35093f7 100644 --- a/src/main/java/com/loomcom/symon/ui/PreferencesDialog.java +++ b/src/main/java/com/loomcom/symon/ui/PreferencesDialog.java @@ -14,9 +14,11 @@ public class PreferencesDialog extends Observable implements Preferences { private JTextField aciaAddressField; private JTextField programLoadAddressField; + private JTextField borderWidthField; private int programLoadAddress = DEFAULT_PROGRAM_LOAD_ADDRESS; private int aciaAddress = DEFAULT_ACIA_ADDRESS; + private int borderWidth = DEFAULT_BORDER_WIDTH; public PreferencesDialog(Frame parent, boolean modal) { this.dialog = new JDialog(parent, modal); @@ -28,6 +30,9 @@ public class PreferencesDialog extends Observable implements Preferences { return dialog; } + /** + * TODO: Validation of input. + */ private void initComponents() { dialog.setTitle("Preferences"); Container contents = dialog.getContentPane(); @@ -40,12 +45,15 @@ public class PreferencesDialog extends Observable implements Preferences { final JLabel aciaAddressLabel = new JLabel("ACIA Address"); final JLabel programLoadAddressLabel = new JLabel("Program Load Address"); + final JLabel borderWidthLabel = new JLabel("Console Border Width"); aciaAddressField = new JTextField(8); programLoadAddressField = new JTextField(8); + borderWidthField = new JTextField(8); aciaAddressLabel.setLabelFor(aciaAddressField); programLoadAddressLabel.setLabelFor(programLoadAddressField); + borderWidthLabel.setLabelFor(borderWidthField); GridBagConstraints constraints = new GridBagConstraints(); @@ -66,6 +74,13 @@ public class PreferencesDialog extends Observable implements Preferences { constraints.gridx = 1; settingsContainer.add(programLoadAddressField, constraints); + constraints.gridy = 2; + constraints.gridx = 0; + settingsContainer.add(borderWidthLabel, constraints); + + constraints.gridx = 1; + settingsContainer.add(borderWidthField, constraints); + JButton applyButton = new JButton("Apply"); JButton cancelButton = new JButton("Cancel"); @@ -81,8 +96,11 @@ public class PreferencesDialog extends Observable implements Preferences { public void actionPerformed(ActionEvent actionEvent) { programLoadAddress = hexToInt(programLoadAddressField.getText()); aciaAddress = hexToInt(aciaAddressField.getText()); + borderWidth = Integer.parseInt(borderWidthField.getText()); updateUi(); - notifyObservers(); + // TODO: Actually check to see if values have changed, don't assume. + setChanged(); + PreferencesDialog.this.notifyObservers(); dialog.setVisible(false); } }); @@ -96,6 +114,27 @@ public class PreferencesDialog extends Observable implements Preferences { dialog.pack(); } + public int getProgramStartAddress() { + return programLoadAddress; + } + + public int getAciaAddress() { + return aciaAddress; + } + + /** + * @return The width of the console border, in pixels. + */ + public int getBorderWidth() { + return borderWidth; + } + + public void updateUi() { + aciaAddressField.setText(intToHex(aciaAddress)); + programLoadAddressField.setText(intToHex(programLoadAddress)); + borderWidthField.setText(Integer.toString(borderWidth)); + } + private String intToHex(int i) { return String.format("%04x", i); } @@ -109,16 +148,4 @@ public class PreferencesDialog extends Observable implements Preferences { } } - public int getProgramStartAddress() { - return programLoadAddress; - } - - public int getAciaAddress() { - return aciaAddress; - } - - public void updateUi() { - aciaAddressField.setText(intToHex(aciaAddress)); - programLoadAddressField.setText(intToHex(programLoadAddress)); - } } diff --git a/src/test/java/com/loomcom/symon/CpuAbsoluteXModeTest.java b/src/test/java/com/loomcom/symon/CpuAbsoluteXModeTest.java index 1546b4a..06174e6 100644 --- a/src/test/java/com/loomcom/symon/CpuAbsoluteXModeTest.java +++ b/src/test/java/com/loomcom/symon/CpuAbsoluteXModeTest.java @@ -401,6 +401,8 @@ public class CpuAbsoluteXModeTest extends TestCase { assertFalse(cpu.getCarryFlag()); cpu.reset(); + cpu.setXRegister(0x30); + bus.loadProgram(0xa9, 0x7f, // LDA #$7f 0x7d, 0x10, 0xab); // ADC $ab10,X cpu.step(2); @@ -411,6 +413,8 @@ public class CpuAbsoluteXModeTest extends TestCase { assertFalse(cpu.getCarryFlag()); cpu.reset(); + cpu.setXRegister(0x30); + bus.loadProgram(0xa9, 0x80, // LDA #$80 0x7d, 0x10, 0xab); // ADC $ab10,X cpu.step(2); @@ -421,6 +425,8 @@ public class CpuAbsoluteXModeTest extends TestCase { assertFalse(cpu.getCarryFlag()); cpu.reset(); + cpu.setXRegister(0x30); + bus.loadProgram(0xa9, 0xff, // LDA #$ff 0x7d, 0x10, 0xab); // ADC $ab10,X cpu.step(2); @@ -431,6 +437,7 @@ public class CpuAbsoluteXModeTest extends TestCase { assertTrue(cpu.getCarryFlag()); cpu.reset(); + cpu.setXRegister(0x30); bus.loadProgram(0xa9, 0x00, // LDA #$00 0x7d, 0x11, 0xab); // ADC $ab11,X cpu.step(2); @@ -441,6 +448,7 @@ public class CpuAbsoluteXModeTest extends TestCase { assertFalse(cpu.getCarryFlag()); cpu.reset(); + cpu.setXRegister(0x30); bus.loadProgram(0xa9, 0x7f, // LDA #$7f 0x7d, 0x11, 0xab); // ADC $ab11,X cpu.step(2); @@ -451,6 +459,7 @@ public class CpuAbsoluteXModeTest extends TestCase { assertTrue(cpu.getCarryFlag()); cpu.reset(); + cpu.setXRegister(0x30); bus.loadProgram(0xa9, 0x80, // LDA #$80 0x7d, 0x11, 0xab); // ADC $ab11,X cpu.step(2); @@ -461,6 +470,7 @@ public class CpuAbsoluteXModeTest extends TestCase { assertTrue(cpu.getCarryFlag()); cpu.reset(); + cpu.setXRegister(0x30); bus.loadProgram(0xa9, 0xff, // LDA #$ff 0x7d, 0x11, 0xab); // ADC $ab11,X cpu.step(2); @@ -506,6 +516,7 @@ public class CpuAbsoluteXModeTest extends TestCase { assertFalse(cpu.getCarryFlag()); cpu.reset(); + cpu.setXRegister(0x30); bus.loadProgram(0xf8, // SED 0xa9, 0x49, // LDA #$49 0x7d, 0x10, 0xab); // ADC $ab10,X @@ -517,6 +528,7 @@ public class CpuAbsoluteXModeTest extends TestCase { assertFalse(cpu.getCarryFlag()); cpu.reset(); + cpu.setXRegister(0x30); bus.loadProgram(0xf8, // SED 0xa9, 0x50, // LDA #$50 0x7d, 0x10, 0xab); // ADC $ab10,X @@ -528,6 +540,7 @@ public class CpuAbsoluteXModeTest extends TestCase { assertFalse(cpu.getCarryFlag()); cpu.reset(); + cpu.setXRegister(0x30); bus.loadProgram(0xf8, // SED 0xa9, 0x99, // LDA #$99 0x7d, 0x10, 0xab); // ADC $ab10,X @@ -539,6 +552,7 @@ public class CpuAbsoluteXModeTest extends TestCase { assertTrue(cpu.getCarryFlag()); cpu.reset(); + cpu.setXRegister(0x30); bus.loadProgram(0xf8, // SED 0xa9, 0x00, // LDA #$00 0x7d, 0x11, 0xab); // ADC $ab10,X @@ -550,6 +564,7 @@ public class CpuAbsoluteXModeTest extends TestCase { assertFalse(cpu.getCarryFlag()); cpu.reset(); + cpu.setXRegister(0x30); bus.loadProgram(0xf8, // SED 0xa9, 0x49, // LDA #$49 0x7d, 0x11, 0xab); // ADC $ab11,X @@ -561,6 +576,7 @@ public class CpuAbsoluteXModeTest extends TestCase { assertTrue(cpu.getCarryFlag()); cpu.reset(); + cpu.setXRegister(0x30); bus.loadProgram(0xf8, // SED 0xa9, 0x50, // LDA #$59 0x7d, 0x11, 0xab); // ADC $ab11,X @@ -666,6 +682,7 @@ public class CpuAbsoluteXModeTest extends TestCase { assertFalse(cpu.getNegativeFlag()); cpu.reset(); + cpu.setXRegister(0x30); cpu.setAccumulator(0x0f); bus.loadProgram(0x9d, 0x10, 0xab); // STA $ab10,X @@ -675,6 +692,7 @@ public class CpuAbsoluteXModeTest extends TestCase { assertFalse(cpu.getNegativeFlag()); cpu.reset(); + cpu.setXRegister(0x30); cpu.setAccumulator(0x80); bus.loadProgram(0x9d, 0x10, 0xab); // STA $ab10,X diff --git a/src/test/java/com/loomcom/symon/CpuAbsoluteYModeTest.java b/src/test/java/com/loomcom/symon/CpuAbsoluteYModeTest.java index da1b9ec..8ec4ba5 100644 --- a/src/test/java/com/loomcom/symon/CpuAbsoluteYModeTest.java +++ b/src/test/java/com/loomcom/symon/CpuAbsoluteYModeTest.java @@ -7,703 +7,732 @@ import junit.framework.TestCase; public class CpuAbsoluteYModeTest extends TestCase { - protected Cpu cpu; - protected Bus bus; - protected Memory mem; - - protected void setUp() throws Exception { - this.cpu = new Cpu(); - this.bus = new Bus(0x0000, 0xffff); - this.mem = new Memory(0x0000, 0x10000); - bus.addCpu(cpu); - bus.addDevice(mem); - - // Load the reset vector. - bus.write(0xfffc, Cpu.DEFAULT_BASE_ADDRESS & 0x00ff); - 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 - $19 - * AND - $39 - * EOR - $59 - * ADC - $79 - * STA - $99 - * LDA - $b9 - * LDX - $be - * CMP - $d9 - * SBC - $f9 - */ - - /* ORA - Logical Inclusive OR - $19 */ - - public void test_ORA() throws MemoryAccessException { - // Set some initial values in memory - bus.write(0x2c30, 0x00); - bus.write(0x2c32, 0x11); - bus.write(0x2c34, 0x22); - bus.write(0x2c38, 0x44); - bus.write(0x2c40, 0x88); - - // Set offset in Y register. - cpu.setYRegister(0x30); - - bus.loadProgram(0x19, 0x00, 0x2c, // ORA $2c00,Y - 0x19, 0x02, 0x2c, // ORA $2c02,Y - 0x19, 0x04, 0x2c, // ORA $2c04,Y - 0x19, 0x08, 0x2c, // ORA $2c08,Y - 0x19, 0x10, 0x2c); // ORA $2c10,Y - - 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()); - - } - - /* AND - Logical AND - $39 */ - - public void test_AND() throws MemoryAccessException { - bus.write(0x1a30, 0x00); - bus.write(0x1a31, 0x11); - bus.write(0x1a32, 0xff); - bus.write(0x1a33, 0x99); - bus.write(0x1a34, 0x11); - bus.write(0x1a35, 0x0f); - bus.write(0x1a02, 0x11); - - // Set offset in Y register. - cpu.setYRegister(0x30); - - bus.loadProgram(0x39, 0x00, 0x1a, // AND $1a00,Y - 0x39, 0x01, 0x1a, // AND $1a01,Y - 0xa9, 0xaa, // LDA #$aa - 0x39, 0x02, 0x1a, // AND $1a02,Y - 0x39, 0x03, 0x1a, // AND $1a03,Y - 0x39, 0x04, 0x1a, // AND $1a04,Y - 0xa9, 0xff, // LDA #$ff - 0x39, 0x05, 0x1a, // AND $1a05,Y - 0xa9, 0x01, // LDA #$01 - 0x39, 0xd2, 0x19); // AND $19d2,Y - cpu.step(); - assertEquals(0x00, cpu.getAccumulator()); - assertTrue(cpu.getZeroFlag()); - assertFalse(cpu.getNegativeFlag()); - - cpu.step(); - assertEquals(0x00, cpu.getAccumulator()); - assertTrue(cpu.getZeroFlag()); - assertFalse(cpu.getNegativeFlag()); - - cpu.step(2); - assertEquals(0xaa, cpu.getAccumulator()); - assertFalse(cpu.getZeroFlag()); - assertTrue(cpu.getNegativeFlag()); - - cpu.step(); - assertEquals(0x88, cpu.getAccumulator()); - assertFalse(cpu.getZeroFlag()); - assertTrue(cpu.getNegativeFlag()); - - cpu.step(); - assertEquals(0x00, cpu.getAccumulator()); - assertTrue(cpu.getZeroFlag()); - assertFalse(cpu.getNegativeFlag()); - - cpu.step(2); - assertEquals(0x0f, cpu.getAccumulator()); - assertFalse(cpu.getZeroFlag()); - assertFalse(cpu.getNegativeFlag()); - - cpu.step(2); - assertEquals(0x01, cpu.getAccumulator()); - assertFalse(cpu.getZeroFlag()); - assertFalse(cpu.getNegativeFlag()); - } - - /* EOR - Exclusive OR - $59 */ - - public void test_EOR() throws MemoryAccessException { - bus.write(0xab40, 0x00); - bus.write(0xab41, 0xff); - bus.write(0xab42, 0x33); - bus.write(0xab43, 0x44); - - cpu.setYRegister(0x30); - - bus.loadProgram(0xa9, 0x88, // LDA #$88 - 0x59, 0x10, 0xab, // EOR $ab10,Y - 0x59, 0x11, 0xab, // EOR $ab11,Y - 0x59, 0x12, 0xab, // EOR $ab12,Y - 0x59, 0x13, 0xab); // EOR $ab13,Y - cpu.step(2); - assertEquals(0x88, cpu.getAccumulator()); - assertTrue(cpu.getNegativeFlag()); - assertFalse(cpu.getZeroFlag()); - - cpu.step(); - assertEquals(0x77, cpu.getAccumulator()); - assertFalse(cpu.getNegativeFlag()); - assertFalse(cpu.getZeroFlag()); - - cpu.step(); - assertEquals(0x44, cpu.getAccumulator()); - assertFalse(cpu.getNegativeFlag()); - assertFalse(cpu.getZeroFlag()); - - cpu.step(); - assertEquals(0x00, cpu.getAccumulator()); - assertFalse(cpu.getNegativeFlag()); - assertTrue(cpu.getZeroFlag()); - } - - /* ADC - Add with Carry - $79 */ - - public void test_ADC() throws MemoryAccessException { - bus.write(0xab40, 0x01); - bus.write(0xab41, 0xff); - - cpu.setYRegister(0x30); - - bus.loadProgram(0xa9, 0x00, // LDA #$00 - 0x79, 0x10, 0xab); // ADC $ab10,Y - cpu.step(2); - assertEquals(0x01, cpu.getAccumulator()); - assertFalse(cpu.getNegativeFlag()); - assertFalse(cpu.getOverflowFlag()); - assertFalse(cpu.getZeroFlag()); - assertFalse(cpu.getCarryFlag()); - - cpu.reset(); - bus.loadProgram(0xa9, 0x7f, // LDA #$7f - 0x79, 0x10, 0xab); // ADC $ab10,Y - cpu.step(2); - assertEquals(0x80, cpu.getAccumulator()); - assertTrue(cpu.getNegativeFlag()); - assertTrue(cpu.getOverflowFlag()); - assertFalse(cpu.getZeroFlag()); - assertFalse(cpu.getCarryFlag()); - - cpu.reset(); - bus.loadProgram(0xa9, 0x80, // LDA #$80 - 0x79, 0x10, 0xab); // ADC $ab10,Y - cpu.step(2); - assertEquals(0x81, cpu.getAccumulator()); - assertTrue(cpu.getNegativeFlag()); - assertFalse(cpu.getOverflowFlag()); - assertFalse(cpu.getZeroFlag()); - assertFalse(cpu.getCarryFlag()); - - cpu.reset(); - bus.loadProgram(0xa9, 0xff, // LDA #$ff - 0x79, 0x10, 0xab); // ADC $ab10,Y - cpu.step(2); - assertEquals(0x00, cpu.getAccumulator()); - assertFalse(cpu.getNegativeFlag()); - assertFalse(cpu.getOverflowFlag()); - assertTrue(cpu.getZeroFlag()); - assertTrue(cpu.getCarryFlag()); - - cpu.reset(); - bus.loadProgram(0xa9, 0x00, // LDA #$00 - 0x79, 0x11, 0xab); // ADC $ab11,Y - cpu.step(2); - assertEquals(0xff, cpu.getAccumulator()); - assertTrue(cpu.getNegativeFlag()); - assertFalse(cpu.getOverflowFlag()); - assertFalse(cpu.getZeroFlag()); - assertFalse(cpu.getCarryFlag()); - - cpu.reset(); - bus.loadProgram(0xa9, 0x7f, // LDA #$7f - 0x79, 0x11, 0xab); // ADC $ab11,Y - cpu.step(2); - assertEquals(0x7e, cpu.getAccumulator()); - assertFalse(cpu.getNegativeFlag()); - assertFalse(cpu.getOverflowFlag()); - assertFalse(cpu.getZeroFlag()); - assertTrue(cpu.getCarryFlag()); - - cpu.reset(); - bus.loadProgram(0xa9, 0x80, // LDA #$80 - 0x79, 0x11, 0xab); // ADC $ab11,Y - cpu.step(2); - assertEquals(0x7f, cpu.getAccumulator()); - assertFalse(cpu.getNegativeFlag()); - assertTrue(cpu.getOverflowFlag()); - assertFalse(cpu.getZeroFlag()); - assertTrue(cpu.getCarryFlag()); - - cpu.reset(); - bus.loadProgram(0xa9, 0xff, // LDA #$ff - 0x79, 0x11, 0xab); // ADC $ab11,Y - cpu.step(2); - assertEquals(0xfe, cpu.getAccumulator()); - assertTrue(cpu.getNegativeFlag()); - assertFalse(cpu.getOverflowFlag()); - assertFalse(cpu.getZeroFlag()); - assertTrue(cpu.getCarryFlag()); - } - - public void test_ADC_IncludesCarry() throws MemoryAccessException { - bus.write(0xab40, 0x01); - - bus.loadProgram(0xa9, 0x00, // LDA #$00 - 0x38, // SEC - 0x79, 0x10, 0xab); // ADC $ab10,Y - - cpu.setYRegister(0x30); - - cpu.step(3); - assertEquals(0x02, cpu.getAccumulator()); - assertFalse(cpu.getNegativeFlag()); - assertFalse(cpu.getOverflowFlag()); - assertFalse(cpu.getZeroFlag()); - assertFalse(cpu.getCarryFlag()); - } - - public void test_ADC_DecimalMode() throws MemoryAccessException { - bus.write(0xab40, 0x01); - bus.write(0xab41, 0x99); - - bus.loadProgram(0xf8, // SED - 0xa9, 0x01, // LDA #$01 - 0x79, 0x10, 0xab); // ADC $ab10,Y - - cpu.setYRegister(0x30); - - cpu.step(3); - assertEquals(0x02, cpu.getAccumulator()); - assertFalse(cpu.getNegativeFlag()); - assertFalse(cpu.getOverflowFlag()); - assertFalse(cpu.getZeroFlag()); - assertFalse(cpu.getCarryFlag()); - - cpu.reset(); - bus.loadProgram(0xf8, // SED - 0xa9, 0x49, // LDA #$49 - 0x79, 0x10, 0xab); // ADC $ab10,Y - cpu.step(3); - assertEquals(0x50, cpu.getAccumulator()); - assertFalse(cpu.getNegativeFlag()); - assertFalse(cpu.getOverflowFlag()); - assertFalse(cpu.getZeroFlag()); - assertFalse(cpu.getCarryFlag()); - - cpu.reset(); - bus.loadProgram(0xf8, // SED - 0xa9, 0x50, // LDA #$50 - 0x79, 0x10, 0xab); // ADC $ab10,Y - cpu.step(3); - assertEquals(0x51, cpu.getAccumulator()); - assertFalse(cpu.getNegativeFlag()); - assertFalse(cpu.getOverflowFlag()); - assertFalse(cpu.getZeroFlag()); - assertFalse(cpu.getCarryFlag()); - - cpu.reset(); - bus.loadProgram(0xf8, // SED - 0xa9, 0x99, // LDA #$99 - 0x79, 0x10, 0xab); // ADC $ab10,Y - cpu.step(3); - assertEquals(0x00, cpu.getAccumulator()); - assertFalse(cpu.getNegativeFlag()); - assertFalse(cpu.getOverflowFlag()); - assertTrue(cpu.getZeroFlag()); - assertTrue(cpu.getCarryFlag()); - - cpu.reset(); - bus.loadProgram(0xf8, // SED - 0xa9, 0x00, // LDA #$00 - 0x79, 0x11, 0xab); // ADC $ab10,Y - cpu.step(3); - assertEquals(0x99, cpu.getAccumulator()); - assertFalse(cpu.getNegativeFlag()); - assertFalse(cpu.getOverflowFlag()); - assertFalse(cpu.getZeroFlag()); - assertFalse(cpu.getCarryFlag()); - - cpu.reset(); - bus.loadProgram(0xf8, // SED - 0xa9, 0x49, // LDA #$49 - 0x79, 0x11, 0xab); // ADC $ab11,Y - cpu.step(3); - assertEquals(0x48, cpu.getAccumulator()); - assertFalse(cpu.getNegativeFlag()); - assertFalse(cpu.getOverflowFlag()); - assertFalse(cpu.getZeroFlag()); - assertTrue(cpu.getCarryFlag()); - - cpu.reset(); - bus.loadProgram(0xf8, // SED - 0xa9, 0x50, // LDA #$59 - 0x79, 0x11, 0xab); // ADC $ab11,Y - cpu.step(3); - assertEquals(0x49, cpu.getAccumulator()); - assertFalse(cpu.getNegativeFlag()); - assertFalse(cpu.getOverflowFlag()); - assertFalse(cpu.getZeroFlag()); - assertTrue(cpu.getCarryFlag()); - } - - /* STA - Store Accumulator - $99 */ - - public void test_STA() throws MemoryAccessException { - cpu.setYRegister(0x30); - - cpu.setAccumulator(0x00); - bus.loadProgram(0x99, 0x10, 0xab); // STA $ab10,Y - cpu.step(); - assertEquals(0x00, bus.read(0xab40)); - assertTrue(cpu.getZeroFlag()); - assertFalse(cpu.getNegativeFlag()); - - cpu.reset(); - - cpu.setAccumulator(0x0f); - bus.loadProgram(0x99, 0x10, 0xab); // STA $ab10,Y - cpu.step(); - assertEquals(0x0f, bus.read(0xab40)); - assertFalse(cpu.getZeroFlag()); - assertFalse(cpu.getNegativeFlag()); - - cpu.reset(); - - cpu.setAccumulator(0x80); - bus.loadProgram(0x99, 0x10, 0xab); // STA $ab10,Y - cpu.step(); - assertEquals(0x80, bus.read(0xab40)); - assertFalse(cpu.getZeroFlag()); - assertTrue(cpu.getNegativeFlag()); - } - - /* LDX - Load X Register - $be */ - - public void test_LDX() throws MemoryAccessException { - bus.write(0xab45, 0x00); - bus.write(0xab46, 0x0f); - bus.write(0xab47, 0x80); - - bus.loadProgram(0xbe, 0x10, 0xab, // LDX $ab10,Y - 0xbe, 0x11, 0xab, // LDX $ab11,Y - 0xbe, 0x12, 0xab); // LDX $ab12,Y - - cpu.setYRegister(0x35); - - cpu.step(); - assertEquals(0x00, cpu.getXRegister()); - assertTrue(cpu.getZeroFlag()); - assertFalse(cpu.getNegativeFlag()); - - cpu.step(); - assertEquals(0x0f, cpu.getXRegister()); - assertFalse(cpu.getZeroFlag()); - assertFalse(cpu.getNegativeFlag()); - - cpu.step(); - assertEquals(0x80, cpu.getXRegister()); - assertFalse(cpu.getZeroFlag()); - assertTrue(cpu.getNegativeFlag()); - } - - /* LDA - Load Accumulator - $b9 */ - - public void test_LDA() throws MemoryAccessException { - bus.write(0xab42, 0x00); - bus.write(0xab43, 0x0f); - bus.write(0xab44, 0x80); - - bus.loadProgram(0xb9, 0x10, 0xab, // LDA $ab10,Y - 0xb9, 0x11, 0xab, // LDA $ab11,Y - 0xb9, 0x12, 0xab); // LDA $ab12,Y - - cpu.setYRegister(0x32); - - cpu.step(); - assertEquals(0x00, cpu.getAccumulator()); - assertTrue(cpu.getZeroFlag()); - assertFalse(cpu.getNegativeFlag()); - - cpu.step(); - assertEquals(0x0f, cpu.getAccumulator()); - assertFalse(cpu.getZeroFlag()); - assertFalse(cpu.getNegativeFlag()); - - cpu.step(); - assertEquals(0x80, cpu.getAccumulator()); - assertFalse(cpu.getZeroFlag()); - assertTrue(cpu.getNegativeFlag()); - } - - /* CMP - Compare Accumulator - $d9 */ - - public void test_CMP() throws MemoryAccessException { - bus.write(0xab40, 0x00); - bus.write(0xab41, 0x80); - bus.write(0xab42, 0xff); - - cpu.setAccumulator(0x80); - - bus.loadProgram(0xd9, 0x10, 0xab, // CMP $ab10,Y - 0xd9, 0x11, 0xab, // CMP $ab11,Y - 0xd9, 0x12, 0xab); // CMP $ab12,Y - - cpu.setYRegister(0x30); - - cpu.step(); - assertTrue(cpu.getCarryFlag()); // m > y - assertFalse(cpu.getZeroFlag()); - assertTrue(cpu.getNegativeFlag()); // m - y < 0 - - cpu.step(); - assertTrue(cpu.getCarryFlag()); // m = y - assertTrue(cpu.getZeroFlag()); - assertFalse(cpu.getNegativeFlag()); // m - y == 0 - - cpu.step(); - assertFalse(cpu.getCarryFlag()); // m < y - assertFalse(cpu.getZeroFlag()); - assertFalse(cpu.getNegativeFlag()); // m - y > 0 - } - - /* SBC - Subtract with Carry - $f9 */ - - public void test_SBC() throws MemoryAccessException { - bus.write(0xab40, 0x01); - - bus.loadProgram(0xa9, 0x00, // LDA #$00 - 0xf9, 0x10, 0xab); // SBC $ab10,Y - cpu.setYRegister(0x30); - cpu.step(2); - assertEquals(0xfe, cpu.getAccumulator()); - assertTrue(cpu.getNegativeFlag()); - assertFalse(cpu.getOverflowFlag()); - assertFalse(cpu.getZeroFlag()); - assertFalse(cpu.getCarryFlag()); - - cpu.reset(); - bus.loadProgram(0xa9, 0x7f, // LDA #$7f - 0xf9, 0x10, 0xab); // SBC $ab10,Y - cpu.setYRegister(0x30); - cpu.step(2); - assertEquals(0x7d, cpu.getAccumulator()); - assertFalse(cpu.getNegativeFlag()); - assertFalse(cpu.getOverflowFlag()); - assertFalse(cpu.getZeroFlag()); - assertTrue(cpu.getCarryFlag()); - - cpu.reset(); - bus.loadProgram(0xa9, 0x80, // LDA #$80 - 0xf9, 0x10, 0xab); // SBC $ab10,Y - cpu.setYRegister(0x30); - cpu.step(2); - assertEquals(0x7e, cpu.getAccumulator()); - assertFalse(cpu.getNegativeFlag()); - assertTrue(cpu.getOverflowFlag()); - assertFalse(cpu.getZeroFlag()); - assertTrue(cpu.getCarryFlag()); - - cpu.reset(); - bus.loadProgram(0xa9, 0xff, // LDA #$ff - 0xf9, 0x10, 0xab); // SBC $ab10,Y - cpu.setYRegister(0x30); - cpu.step(2); - assertEquals(0xfd, cpu.getAccumulator()); - assertTrue(cpu.getNegativeFlag()); - assertFalse(cpu.getOverflowFlag()); - assertFalse(cpu.getZeroFlag()); - assertTrue(cpu.getCarryFlag()); - - cpu.reset(); - bus.loadProgram(0xa9, 0x02, // LDA #$02 - 0xf9, 0x10, 0xab); // SBC $ab10,Y - cpu.setYRegister(0x30); - cpu.step(2); - assertEquals(0x00, cpu.getAccumulator()); - assertFalse(cpu.getNegativeFlag()); - assertFalse(cpu.getOverflowFlag()); - assertTrue(cpu.getZeroFlag()); - assertTrue(cpu.getCarryFlag()); - } - - public void test_SBC_IncludesNotOfCarry() throws MemoryAccessException { - bus.write(0xab40, 0x01); - - // Subtrace with Carry Flag cleared - bus.loadProgram(0x18, // CLC - 0xa9, 0x05, // LDA #$00 - 0xf9, 0x10, 0xab); // SBC $ab10,Y - cpu.setYRegister(0x30); - cpu.step(3); - assertEquals(0x03, cpu.getAccumulator()); - - cpu.reset(); - - // Subtrace with Carry Flag cleared - bus.loadProgram(0x18, // CLC - 0xa9, 0x00, // LDA #$00 - 0xf9, 0x10, 0xab); // SBC $ab10,Y - cpu.setYRegister(0x30); - cpu.step(3); - assertEquals(0xfe, cpu.getAccumulator()); - - cpu.reset(); - - // Subtract with Carry Flag set - bus.loadProgram(0x38, // SEC - 0xa9, 0x05, // LDA #$00 - 0xf9, 0x10, 0xab); // SBC $ab10,Y - cpu.setYRegister(0x30); - 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 - 0xf9, 0x10, 0xab); // SBC $ab10,Y - cpu.setYRegister(0x30); - cpu.step(3); - assertEquals(0xff, cpu.getAccumulator()); - assertFalse(cpu.getCarryFlag()); - - } - - public void test_SBC_DecimalMode() throws MemoryAccessException { - bus.write(0xab40, 0x01); - bus.write(0xab50, 0x11); - - bus.loadProgram(0xf8, // SED - 0xa9, 0x00, // LDA #$00 - 0xf9, 0x10, 0xab); // SBC $ab10,Y - cpu.setYRegister(0x30); - 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, // SED - 0xa9, 0x99, // LDA #$99 - 0xf9, 0x10, 0xab); // SBC $ab10,Y - cpu.setYRegister(0x30); - 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, // SED - 0xa9, 0x50, // LDA #$50 - 0xf9, 0x10, 0xab); // SBC $ab10,Y - cpu.setYRegister(0x30); - 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 - 0xf9, 0x10, 0xab); // SBC $ab10,Y - cpu.setYRegister(0x30); - 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 - 0xf9, 0x20, 0xab); // SBC $ab20,Y - cpu.setYRegister(0x30); - 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 - 0xf9, 0x10, 0xab); // SBC $ab10,Y - cpu.setYRegister(0x30); - 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 - 0xf9, 0x10, 0xab); // SBC $ab10,Y - cpu.setYRegister(0x30); - cpu.step(4); - assertEquals(0x99, cpu.getAccumulator()); - assertFalse(cpu.getCarryFlag()); - assertFalse(cpu.getNegativeFlag()); - assertFalse(cpu.getOverflowFlag()); - assertFalse(cpu.getZeroFlag()); - assertTrue(cpu.getDecimalModeFlag()); - } + protected Cpu cpu; + protected Bus bus; + protected Memory mem; + + protected void setUp() throws Exception { + this.cpu = new Cpu(); + this.bus = new Bus(0x0000, 0xffff); + this.mem = new Memory(0x0000, 0x10000); + bus.addCpu(cpu); + bus.addDevice(mem); + + // Load the reset vector. + bus.write(0xfffc, Cpu.DEFAULT_BASE_ADDRESS & 0x00ff); + 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 - $19 + * AND - $39 + * EOR - $59 + * ADC - $79 + * STA - $99 + * LDA - $b9 + * LDX - $be + * CMP - $d9 + * SBC - $f9 + */ + + /* ORA - Logical Inclusive OR - $19 */ + + public void test_ORA() throws MemoryAccessException { + // Set some initial values in memory + bus.write(0x2c30, 0x00); + bus.write(0x2c32, 0x11); + bus.write(0x2c34, 0x22); + bus.write(0x2c38, 0x44); + bus.write(0x2c40, 0x88); + + // Set offset in Y register. + cpu.setYRegister(0x30); + + bus.loadProgram(0x19, 0x00, 0x2c, // ORA $2c00,Y + 0x19, 0x02, 0x2c, // ORA $2c02,Y + 0x19, 0x04, 0x2c, // ORA $2c04,Y + 0x19, 0x08, 0x2c, // ORA $2c08,Y + 0x19, 0x10, 0x2c); // ORA $2c10,Y + + 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()); + + } + + /* AND - Logical AND - $39 */ + + public void test_AND() throws MemoryAccessException { + bus.write(0x1a30, 0x00); + bus.write(0x1a31, 0x11); + bus.write(0x1a32, 0xff); + bus.write(0x1a33, 0x99); + bus.write(0x1a34, 0x11); + bus.write(0x1a35, 0x0f); + bus.write(0x1a02, 0x11); + + // Set offset in Y register. + cpu.setYRegister(0x30); + + bus.loadProgram(0x39, 0x00, 0x1a, // AND $1a00,Y + 0x39, 0x01, 0x1a, // AND $1a01,Y + 0xa9, 0xaa, // LDA #$aa + 0x39, 0x02, 0x1a, // AND $1a02,Y + 0x39, 0x03, 0x1a, // AND $1a03,Y + 0x39, 0x04, 0x1a, // AND $1a04,Y + 0xa9, 0xff, // LDA #$ff + 0x39, 0x05, 0x1a, // AND $1a05,Y + 0xa9, 0x01, // LDA #$01 + 0x39, 0xd2, 0x19); // AND $19d2,Y + cpu.step(); + assertEquals(0x00, cpu.getAccumulator()); + assertTrue(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + + cpu.step(); + assertEquals(0x00, cpu.getAccumulator()); + assertTrue(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + + cpu.step(2); + assertEquals(0xaa, cpu.getAccumulator()); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getNegativeFlag()); + + cpu.step(); + assertEquals(0x88, cpu.getAccumulator()); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getNegativeFlag()); + + cpu.step(); + assertEquals(0x00, cpu.getAccumulator()); + assertTrue(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + + cpu.step(2); + assertEquals(0x0f, cpu.getAccumulator()); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + + cpu.step(2); + assertEquals(0x01, cpu.getAccumulator()); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + } + + /* EOR - Exclusive OR - $59 */ + + public void test_EOR() throws MemoryAccessException { + bus.write(0xab40, 0x00); + bus.write(0xab41, 0xff); + bus.write(0xab42, 0x33); + bus.write(0xab43, 0x44); + + cpu.setYRegister(0x30); + + bus.loadProgram(0xa9, 0x88, // LDA #$88 + 0x59, 0x10, 0xab, // EOR $ab10,Y + 0x59, 0x11, 0xab, // EOR $ab11,Y + 0x59, 0x12, 0xab, // EOR $ab12,Y + 0x59, 0x13, 0xab); // EOR $ab13,Y + cpu.step(2); + assertEquals(0x88, cpu.getAccumulator()); + assertTrue(cpu.getNegativeFlag()); + assertFalse(cpu.getZeroFlag()); + + cpu.step(); + assertEquals(0x77, cpu.getAccumulator()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getZeroFlag()); + + cpu.step(); + assertEquals(0x44, cpu.getAccumulator()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getZeroFlag()); + + cpu.step(); + assertEquals(0x00, cpu.getAccumulator()); + assertFalse(cpu.getNegativeFlag()); + assertTrue(cpu.getZeroFlag()); + } + + /* ADC - Add with Carry - $79 */ + + public void test_ADC() throws MemoryAccessException { + bus.write(0xab40, 0x01); + bus.write(0xab41, 0xff); + + cpu.setYRegister(0x30); + + bus.loadProgram(0xa9, 0x00, // LDA #$00 + 0x79, 0x10, 0xab); // ADC $ab10,Y + cpu.step(2); + assertEquals(0x01, cpu.getAccumulator()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.reset(); + cpu.setYRegister(0x30); + + bus.loadProgram(0xa9, 0x7f, // LDA #$7f + 0x79, 0x10, 0xab); // ADC $ab10,Y + cpu.step(2); + assertEquals(0x80, cpu.getAccumulator()); + assertTrue(cpu.getNegativeFlag()); + assertTrue(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.reset(); + cpu.setYRegister(0x30); + + bus.loadProgram(0xa9, 0x80, // LDA #$80 + 0x79, 0x10, 0xab); // ADC $ab10,Y + cpu.step(2); + assertEquals(0x81, cpu.getAccumulator()); + assertTrue(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.reset(); + cpu.setYRegister(0x30); + + bus.loadProgram(0xa9, 0xff, // LDA #$ff + 0x79, 0x10, 0xab); // ADC $ab10,Y + cpu.step(2); + assertEquals(0x00, cpu.getAccumulator()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertTrue(cpu.getZeroFlag()); + assertTrue(cpu.getCarryFlag()); + + cpu.reset(); + cpu.setYRegister(0x30); + + bus.loadProgram(0xa9, 0x00, // LDA #$00 + 0x79, 0x11, 0xab); // ADC $ab11,Y + cpu.step(2); + assertEquals(0xff, cpu.getAccumulator()); + assertTrue(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.reset(); + cpu.setYRegister(0x30); + + bus.loadProgram(0xa9, 0x7f, // LDA #$7f + 0x79, 0x11, 0xab); // ADC $ab11,Y + cpu.step(2); + assertEquals(0x7e, cpu.getAccumulator()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getCarryFlag()); + + cpu.reset(); + cpu.setYRegister(0x30); + + bus.loadProgram(0xa9, 0x80, // LDA #$80 + 0x79, 0x11, 0xab); // ADC $ab11,Y + cpu.step(2); + assertEquals(0x7f, cpu.getAccumulator()); + assertFalse(cpu.getNegativeFlag()); + assertTrue(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getCarryFlag()); + + cpu.reset(); + cpu.setYRegister(0x30); + + bus.loadProgram(0xa9, 0xff, // LDA #$ff + 0x79, 0x11, 0xab); // ADC $ab11,Y + cpu.step(2); + assertEquals(0xfe, cpu.getAccumulator()); + assertTrue(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getCarryFlag()); + } + + public void test_ADC_IncludesCarry() throws MemoryAccessException { + bus.write(0xab40, 0x01); + + bus.loadProgram(0xa9, 0x00, // LDA #$00 + 0x38, // SEC + 0x79, 0x10, 0xab); // ADC $ab10,Y + + cpu.setYRegister(0x30); + + cpu.step(3); + assertEquals(0x02, cpu.getAccumulator()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getCarryFlag()); + } + + public void test_ADC_DecimalMode() throws MemoryAccessException { + bus.write(0xab40, 0x01); + bus.write(0xab41, 0x99); + + bus.loadProgram(0xf8, // SED + 0xa9, 0x01, // LDA #$01 + 0x79, 0x10, 0xab); // ADC $ab10,Y + + cpu.setYRegister(0x30); + + cpu.step(3); + assertEquals(0x02, cpu.getAccumulator()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.reset(); + cpu.setYRegister(0x30); + + bus.loadProgram(0xf8, // SED + 0xa9, 0x49, // LDA #$49 + 0x79, 0x10, 0xab); // ADC $ab10,Y + cpu.step(3); + assertEquals(0x50, cpu.getAccumulator()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.reset(); + cpu.setYRegister(0x30); + + bus.loadProgram(0xf8, // SED + 0xa9, 0x50, // LDA #$50 + 0x79, 0x10, 0xab); // ADC $ab10,Y + cpu.step(3); + assertEquals(0x51, cpu.getAccumulator()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.reset(); + cpu.setYRegister(0x30); + + bus.loadProgram(0xf8, // SED + 0xa9, 0x99, // LDA #$99 + 0x79, 0x10, 0xab); // ADC $ab10,Y + cpu.step(3); + assertEquals(0x00, cpu.getAccumulator()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertTrue(cpu.getZeroFlag()); + assertTrue(cpu.getCarryFlag()); + + cpu.reset(); + cpu.setYRegister(0x30); + + bus.loadProgram(0xf8, // SED + 0xa9, 0x00, // LDA #$00 + 0x79, 0x11, 0xab); // ADC $ab10,Y + cpu.step(3); + assertEquals(0x99, cpu.getAccumulator()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.reset(); + cpu.setYRegister(0x30); + + bus.loadProgram(0xf8, // SED + 0xa9, 0x49, // LDA #$49 + 0x79, 0x11, 0xab); // ADC $ab11,Y + cpu.step(3); + assertEquals(0x48, cpu.getAccumulator()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getCarryFlag()); + + cpu.reset(); + cpu.setYRegister(0x30); + + bus.loadProgram(0xf8, // SED + 0xa9, 0x50, // LDA #$59 + 0x79, 0x11, 0xab); // ADC $ab11,Y + cpu.step(3); + assertEquals(0x49, cpu.getAccumulator()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getCarryFlag()); + } + + /* STA - Store Accumulator - $99 */ + + public void test_STA() throws MemoryAccessException { + cpu.setYRegister(0x30); + + cpu.setAccumulator(0x00); + bus.loadProgram(0x99, 0x10, 0xab); // STA $ab10,Y + cpu.step(); + assertEquals(0x00, bus.read(0xab40)); + assertTrue(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + + cpu.reset(); + cpu.setYRegister(0x30); + + + cpu.setAccumulator(0x0f); + bus.loadProgram(0x99, 0x10, 0xab); // STA $ab10,Y + cpu.step(); + assertEquals(0x0f, bus.read(0xab40)); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + + cpu.reset(); + cpu.setYRegister(0x30); + + cpu.setAccumulator(0x80); + bus.loadProgram(0x99, 0x10, 0xab); // STA $ab10,Y + cpu.step(); + assertEquals(0x80, bus.read(0xab40)); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getNegativeFlag()); + } + + /* LDX - Load X Register - $be */ + + public void test_LDX() throws MemoryAccessException { + bus.write(0xab45, 0x00); + bus.write(0xab46, 0x0f); + bus.write(0xab47, 0x80); + + bus.loadProgram(0xbe, 0x10, 0xab, // LDX $ab10,Y + 0xbe, 0x11, 0xab, // LDX $ab11,Y + 0xbe, 0x12, 0xab); // LDX $ab12,Y + + cpu.setYRegister(0x35); + + cpu.step(); + assertEquals(0x00, cpu.getXRegister()); + assertTrue(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + + cpu.step(); + assertEquals(0x0f, cpu.getXRegister()); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + + cpu.step(); + assertEquals(0x80, cpu.getXRegister()); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getNegativeFlag()); + } + + /* LDA - Load Accumulator - $b9 */ + + public void test_LDA() throws MemoryAccessException { + bus.write(0xab42, 0x00); + bus.write(0xab43, 0x0f); + bus.write(0xab44, 0x80); + + bus.loadProgram(0xb9, 0x10, 0xab, // LDA $ab10,Y + 0xb9, 0x11, 0xab, // LDA $ab11,Y + 0xb9, 0x12, 0xab); // LDA $ab12,Y + + cpu.setYRegister(0x32); + + cpu.step(); + assertEquals(0x00, cpu.getAccumulator()); + assertTrue(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + + cpu.step(); + assertEquals(0x0f, cpu.getAccumulator()); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + + cpu.step(); + assertEquals(0x80, cpu.getAccumulator()); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getNegativeFlag()); + } + + /* CMP - Compare Accumulator - $d9 */ + + public void test_CMP() throws MemoryAccessException { + bus.write(0xab40, 0x00); + bus.write(0xab41, 0x80); + bus.write(0xab42, 0xff); + + cpu.setAccumulator(0x80); + + bus.loadProgram(0xd9, 0x10, 0xab, // CMP $ab10,Y + 0xd9, 0x11, 0xab, // CMP $ab11,Y + 0xd9, 0x12, 0xab); // CMP $ab12,Y + + cpu.setYRegister(0x30); + + cpu.step(); + assertTrue(cpu.getCarryFlag()); // m > y + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getNegativeFlag()); // m - y < 0 + + cpu.step(); + assertTrue(cpu.getCarryFlag()); // m = y + assertTrue(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); // m - y == 0 + + cpu.step(); + assertFalse(cpu.getCarryFlag()); // m < y + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); // m - y > 0 + } + + /* SBC - Subtract with Carry - $f9 */ + + public void test_SBC() throws MemoryAccessException { + bus.write(0xab40, 0x01); + + bus.loadProgram(0xa9, 0x00, // LDA #$00 + 0xf9, 0x10, 0xab); // SBC $ab10,Y + cpu.setYRegister(0x30); + cpu.step(2); + assertEquals(0xfe, cpu.getAccumulator()); + assertTrue(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.reset(); + bus.loadProgram(0xa9, 0x7f, // LDA #$7f + 0xf9, 0x10, 0xab); // SBC $ab10,Y + cpu.setYRegister(0x30); + cpu.step(2); + assertEquals(0x7d, cpu.getAccumulator()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getCarryFlag()); + + cpu.reset(); + bus.loadProgram(0xa9, 0x80, // LDA #$80 + 0xf9, 0x10, 0xab); // SBC $ab10,Y + cpu.setYRegister(0x30); + cpu.step(2); + assertEquals(0x7e, cpu.getAccumulator()); + assertFalse(cpu.getNegativeFlag()); + assertTrue(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getCarryFlag()); + + cpu.reset(); + bus.loadProgram(0xa9, 0xff, // LDA #$ff + 0xf9, 0x10, 0xab); // SBC $ab10,Y + cpu.setYRegister(0x30); + cpu.step(2); + assertEquals(0xfd, cpu.getAccumulator()); + assertTrue(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getCarryFlag()); + + cpu.reset(); + bus.loadProgram(0xa9, 0x02, // LDA #$02 + 0xf9, 0x10, 0xab); // SBC $ab10,Y + cpu.setYRegister(0x30); + cpu.step(2); + assertEquals(0x00, cpu.getAccumulator()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertTrue(cpu.getZeroFlag()); + assertTrue(cpu.getCarryFlag()); + } + + public void test_SBC_IncludesNotOfCarry() throws MemoryAccessException { + bus.write(0xab40, 0x01); + + // Subtrace with Carry Flag cleared + bus.loadProgram(0x18, // CLC + 0xa9, 0x05, // LDA #$00 + 0xf9, 0x10, 0xab); // SBC $ab10,Y + cpu.setYRegister(0x30); + cpu.step(3); + assertEquals(0x03, cpu.getAccumulator()); + + cpu.reset(); + + // Subtrace with Carry Flag cleared + bus.loadProgram(0x18, // CLC + 0xa9, 0x00, // LDA #$00 + 0xf9, 0x10, 0xab); // SBC $ab10,Y + cpu.setYRegister(0x30); + cpu.step(3); + assertEquals(0xfe, cpu.getAccumulator()); + + cpu.reset(); + + // Subtract with Carry Flag set + bus.loadProgram(0x38, // SEC + 0xa9, 0x05, // LDA #$00 + 0xf9, 0x10, 0xab); // SBC $ab10,Y + cpu.setYRegister(0x30); + 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 + 0xf9, 0x10, 0xab); // SBC $ab10,Y + cpu.setYRegister(0x30); + cpu.step(3); + assertEquals(0xff, cpu.getAccumulator()); + assertFalse(cpu.getCarryFlag()); + + } + + public void test_SBC_DecimalMode() throws MemoryAccessException { + bus.write(0xab40, 0x01); + bus.write(0xab50, 0x11); + + bus.loadProgram(0xf8, // SED + 0xa9, 0x00, // LDA #$00 + 0xf9, 0x10, 0xab); // SBC $ab10,Y + cpu.setYRegister(0x30); + 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, // SED + 0xa9, 0x99, // LDA #$99 + 0xf9, 0x10, 0xab); // SBC $ab10,Y + cpu.setYRegister(0x30); + 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, // SED + 0xa9, 0x50, // LDA #$50 + 0xf9, 0x10, 0xab); // SBC $ab10,Y + cpu.setYRegister(0x30); + 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 + 0xf9, 0x10, 0xab); // SBC $ab10,Y + cpu.setYRegister(0x30); + 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 + 0xf9, 0x20, 0xab); // SBC $ab20,Y + cpu.setYRegister(0x30); + 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 + 0xf9, 0x10, 0xab); // SBC $ab10,Y + cpu.setYRegister(0x30); + 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 + 0xf9, 0x10, 0xab); // SBC $ab10,Y + cpu.setYRegister(0x30); + cpu.step(4); + assertEquals(0x99, cpu.getAccumulator()); + assertFalse(cpu.getCarryFlag()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getDecimalModeFlag()); + } } diff --git a/src/test/java/com/loomcom/symon/CpuIndirectXModeTest.java b/src/test/java/com/loomcom/symon/CpuIndirectXModeTest.java index d9bf3c9..89802c7 100644 --- a/src/test/java/com/loomcom/symon/CpuIndirectXModeTest.java +++ b/src/test/java/com/loomcom/symon/CpuIndirectXModeTest.java @@ -6,675 +6,704 @@ import junit.framework.TestCase; public class CpuIndirectXModeTest extends TestCase { - protected Cpu cpu; - protected Bus bus; - protected Memory mem; - - protected void setUp() throws Exception { - this.cpu = new Cpu(); - this.bus = new Bus(0x0000, 0xffff); - this.mem = new Memory(0x0000, 0x10000); - bus.addCpu(cpu); - bus.addDevice(mem); - - // Load the reset vector. - bus.write(0xfffc, Cpu.DEFAULT_BASE_ADDRESS & 0x00ff); - 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 - $01 - * AND - $21 - * EOR - $41 - * ADC - $61 - * STA - $81 - * - * LDA - $a1 - * CMP - $c1 - * SBC - $e1 - * - */ - - /* ORA - Logical Inclusive OR - $1d */ - - public void test_ORA() throws MemoryAccessException { - // Set some initial values in memory - bus.write(0x2c30, 0x00); - bus.write(0x2c32, 0x11); - bus.write(0x2c34, 0x22); - bus.write(0x2c38, 0x44); - bus.write(0x2c40, 0x88); - - // Set offset in X register. - cpu.setXRegister(0x30); - - bus.loadProgram(0x1d, 0x00, 0x2c, // ORA $2c00,X - 0x1d, 0x02, 0x2c, // ORA $2c02,X - 0x1d, 0x04, 0x2c, // ORA $2c04,X - 0x1d, 0x08, 0x2c, // ORA $2c08,X - 0x1d, 0x10, 0x2c); // ORA $2c10,X - - 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()); - - } - - /* AND - Logical AND - $3d */ - - public void test_AND() throws MemoryAccessException { - bus.write(0x1a30, 0x00); - bus.write(0x1a31, 0x11); - bus.write(0x1a32, 0xff); - bus.write(0x1a33, 0x99); - bus.write(0x1a34, 0x11); - bus.write(0x1a35, 0x0f); - bus.write(0x1a02, 0x11); - - // Set offset in X register. - cpu.setXRegister(0x30); - - bus.loadProgram(0x3d, 0x00, 0x1a, // AND $1a00,X - 0x3d, 0x01, 0x1a, // AND $1a01,X - 0xa9, 0xaa, // LDA #$aa - 0x3d, 0x02, 0x1a, // AND $1a02,X - 0x3d, 0x03, 0x1a, // AND $1a03,X - 0x3d, 0x04, 0x1a, // AND $1a04,X - 0xa9, 0xff, // LDA #$ff - 0x3d, 0x05, 0x1a, // AND $1a05,X - 0xa9, 0x01, // LDA #$01 - 0x3d, 0xd2, 0x19); // AND $19d2,X - cpu.step(); - assertEquals(0x00, cpu.getAccumulator()); - assertTrue(cpu.getZeroFlag()); - assertFalse(cpu.getNegativeFlag()); - - cpu.step(); - assertEquals(0x00, cpu.getAccumulator()); - assertTrue(cpu.getZeroFlag()); - assertFalse(cpu.getNegativeFlag()); - - cpu.step(2); - assertEquals(0xaa, cpu.getAccumulator()); - assertFalse(cpu.getZeroFlag()); - assertTrue(cpu.getNegativeFlag()); - - cpu.step(); - assertEquals(0x88, cpu.getAccumulator()); - assertFalse(cpu.getZeroFlag()); - assertTrue(cpu.getNegativeFlag()); - - cpu.step(); - assertEquals(0x00, cpu.getAccumulator()); - assertTrue(cpu.getZeroFlag()); - assertFalse(cpu.getNegativeFlag()); - - cpu.step(2); - assertEquals(0x0f, cpu.getAccumulator()); - assertFalse(cpu.getZeroFlag()); - assertFalse(cpu.getNegativeFlag()); - - cpu.step(2); - assertEquals(0x01, cpu.getAccumulator()); - assertFalse(cpu.getZeroFlag()); - assertFalse(cpu.getNegativeFlag()); - } - - /* EOR - Exclusive OR - $5d */ - - public void test_EOR() throws MemoryAccessException { - bus.write(0xab40, 0x00); - bus.write(0xab41, 0xff); - bus.write(0xab42, 0x33); - bus.write(0xab43, 0x44); - - cpu.setXRegister(0x30); - - bus.loadProgram(0xa9, 0x88, // LDA #$88 - 0x5d, 0x10, 0xab, // EOR $ab10,X - 0x5d, 0x11, 0xab, // EOR $ab11,X - 0x5d, 0x12, 0xab, // EOR $ab12,X - 0x5d, 0x13, 0xab); // EOR $ab13,X - cpu.step(2); - assertEquals(0x88, cpu.getAccumulator()); - assertTrue(cpu.getNegativeFlag()); - assertFalse(cpu.getZeroFlag()); - - cpu.step(); - assertEquals(0x77, cpu.getAccumulator()); - assertFalse(cpu.getNegativeFlag()); - assertFalse(cpu.getZeroFlag()); - - cpu.step(); - assertEquals(0x44, cpu.getAccumulator()); - assertFalse(cpu.getNegativeFlag()); - assertFalse(cpu.getZeroFlag()); - - cpu.step(); - assertEquals(0x00, cpu.getAccumulator()); - assertFalse(cpu.getNegativeFlag()); - assertTrue(cpu.getZeroFlag()); - } - - /* ADC - Add with Carry - $7d */ - - public void test_ADC() throws MemoryAccessException { - bus.write(0xab40, 0x01); - bus.write(0xab41, 0xff); - - cpu.setXRegister(0x30); - - bus.loadProgram(0xa9, 0x00, // LDA #$00 - 0x7d, 0x10, 0xab); // ADC $ab10,X - cpu.step(2); - assertEquals(0x01, cpu.getAccumulator()); - assertFalse(cpu.getNegativeFlag()); - assertFalse(cpu.getOverflowFlag()); - assertFalse(cpu.getZeroFlag()); - assertFalse(cpu.getCarryFlag()); - - cpu.reset(); - bus.loadProgram(0xa9, 0x7f, // LDA #$7f - 0x7d, 0x10, 0xab); // ADC $ab10,X - cpu.step(2); - assertEquals(0x80, cpu.getAccumulator()); - assertTrue(cpu.getNegativeFlag()); - assertTrue(cpu.getOverflowFlag()); - assertFalse(cpu.getZeroFlag()); - assertFalse(cpu.getCarryFlag()); - - cpu.reset(); - bus.loadProgram(0xa9, 0x80, // LDA #$80 - 0x7d, 0x10, 0xab); // ADC $ab10,X - cpu.step(2); - assertEquals(0x81, cpu.getAccumulator()); - assertTrue(cpu.getNegativeFlag()); - assertFalse(cpu.getOverflowFlag()); - assertFalse(cpu.getZeroFlag()); - assertFalse(cpu.getCarryFlag()); - - cpu.reset(); - bus.loadProgram(0xa9, 0xff, // LDA #$ff - 0x7d, 0x10, 0xab); // ADC $ab10,X - cpu.step(2); - assertEquals(0x00, cpu.getAccumulator()); - assertFalse(cpu.getNegativeFlag()); - assertFalse(cpu.getOverflowFlag()); - assertTrue(cpu.getZeroFlag()); - assertTrue(cpu.getCarryFlag()); - - cpu.reset(); - bus.loadProgram(0xa9, 0x00, // LDA #$00 - 0x7d, 0x11, 0xab); // ADC $ab11,X - cpu.step(2); - assertEquals(0xff, cpu.getAccumulator()); - assertTrue(cpu.getNegativeFlag()); - assertFalse(cpu.getOverflowFlag()); - assertFalse(cpu.getZeroFlag()); - assertFalse(cpu.getCarryFlag()); - - cpu.reset(); - bus.loadProgram(0xa9, 0x7f, // LDA #$7f - 0x7d, 0x11, 0xab); // ADC $ab11,X - cpu.step(2); - assertEquals(0x7e, cpu.getAccumulator()); - assertFalse(cpu.getNegativeFlag()); - assertFalse(cpu.getOverflowFlag()); - assertFalse(cpu.getZeroFlag()); - assertTrue(cpu.getCarryFlag()); - - cpu.reset(); - bus.loadProgram(0xa9, 0x80, // LDA #$80 - 0x7d, 0x11, 0xab); // ADC $ab11,X - cpu.step(2); - assertEquals(0x7f, cpu.getAccumulator()); - assertFalse(cpu.getNegativeFlag()); - assertTrue(cpu.getOverflowFlag()); - assertFalse(cpu.getZeroFlag()); - assertTrue(cpu.getCarryFlag()); - - cpu.reset(); - bus.loadProgram(0xa9, 0xff, // LDA #$ff - 0x7d, 0x11, 0xab); // ADC $ab11,X - cpu.step(2); - assertEquals(0xfe, cpu.getAccumulator()); - assertTrue(cpu.getNegativeFlag()); - assertFalse(cpu.getOverflowFlag()); - assertFalse(cpu.getZeroFlag()); - assertTrue(cpu.getCarryFlag()); - } - - public void test_ADC_IncludesCarry() throws MemoryAccessException { - bus.write(0xab40, 0x01); - - bus.loadProgram(0xa9, 0x00, // LDA #$00 - 0x38, // SEC - 0x7d, 0x10, 0xab); // ADC $ab10,X - - cpu.setXRegister(0x30); - - cpu.step(3); - assertEquals(0x02, cpu.getAccumulator()); - assertFalse(cpu.getNegativeFlag()); - assertFalse(cpu.getOverflowFlag()); - assertFalse(cpu.getZeroFlag()); - assertFalse(cpu.getCarryFlag()); - } - - public void test_ADC_DecimalMode() throws MemoryAccessException { - bus.write(0xab40, 0x01); - bus.write(0xab41, 0x99); - - bus.loadProgram(0xf8, // SED - 0xa9, 0x01, // LDA #$01 - 0x7d, 0x10, 0xab); // ADC $ab10,X - - cpu.setXRegister(0x30); - - cpu.step(3); - assertEquals(0x02, cpu.getAccumulator()); - assertFalse(cpu.getNegativeFlag()); - assertFalse(cpu.getOverflowFlag()); - assertFalse(cpu.getZeroFlag()); - assertFalse(cpu.getCarryFlag()); - - cpu.reset(); - bus.loadProgram(0xf8, // SED - 0xa9, 0x49, // LDA #$49 - 0x7d, 0x10, 0xab); // ADC $ab10,X - cpu.step(3); - assertEquals(0x50, cpu.getAccumulator()); - assertFalse(cpu.getNegativeFlag()); - assertFalse(cpu.getOverflowFlag()); - assertFalse(cpu.getZeroFlag()); - assertFalse(cpu.getCarryFlag()); - - cpu.reset(); - bus.loadProgram(0xf8, // SED - 0xa9, 0x50, // LDA #$50 - 0x7d, 0x10, 0xab); // ADC $ab10,X - cpu.step(3); - assertEquals(0x51, cpu.getAccumulator()); - assertFalse(cpu.getNegativeFlag()); - assertFalse(cpu.getOverflowFlag()); - assertFalse(cpu.getZeroFlag()); - assertFalse(cpu.getCarryFlag()); - - cpu.reset(); - bus.loadProgram(0xf8, // SED - 0xa9, 0x99, // LDA #$99 - 0x7d, 0x10, 0xab); // ADC $ab10,X - cpu.step(3); - assertEquals(0x00, cpu.getAccumulator()); - assertFalse(cpu.getNegativeFlag()); - assertFalse(cpu.getOverflowFlag()); - assertTrue(cpu.getZeroFlag()); - assertTrue(cpu.getCarryFlag()); - - cpu.reset(); - bus.loadProgram(0xf8, // SED - 0xa9, 0x00, // LDA #$00 - 0x7d, 0x11, 0xab); // ADC $ab10,X - cpu.step(3); - assertEquals(0x99, cpu.getAccumulator()); - assertFalse(cpu.getNegativeFlag()); - assertFalse(cpu.getOverflowFlag()); - assertFalse(cpu.getZeroFlag()); - assertFalse(cpu.getCarryFlag()); - - cpu.reset(); - bus.loadProgram(0xf8, // SED - 0xa9, 0x49, // LDA #$49 - 0x7d, 0x11, 0xab); // ADC $ab11,X - cpu.step(3); - assertEquals(0x48, cpu.getAccumulator()); - assertFalse(cpu.getNegativeFlag()); - assertFalse(cpu.getOverflowFlag()); - assertFalse(cpu.getZeroFlag()); - assertTrue(cpu.getCarryFlag()); - - cpu.reset(); - bus.loadProgram(0xf8, // SED - 0xa9, 0x50, // LDA #$59 - 0x7d, 0x11, 0xab); // ADC $ab11,X - cpu.step(3); - assertEquals(0x49, cpu.getAccumulator()); - assertFalse(cpu.getNegativeFlag()); - assertFalse(cpu.getOverflowFlag()); - assertFalse(cpu.getZeroFlag()); - assertTrue(cpu.getCarryFlag()); - } - - /* STA - Store Accumulator - $9d */ - - public void test_STA() throws MemoryAccessException { - cpu.setXRegister(0x30); - - cpu.setAccumulator(0x00); - bus.loadProgram(0x9d, 0x10, 0xab); // STA $ab10,X - cpu.step(); - assertEquals(0x00, bus.read(0xab40)); - assertTrue(cpu.getZeroFlag()); - assertFalse(cpu.getNegativeFlag()); - - cpu.reset(); - - cpu.setAccumulator(0x0f); - bus.loadProgram(0x9d, 0x10, 0xab); // STA $ab10,X - cpu.step(); - assertEquals(0x0f, bus.read(0xab40)); - assertFalse(cpu.getZeroFlag()); - assertFalse(cpu.getNegativeFlag()); - - cpu.reset(); - - cpu.setAccumulator(0x80); - bus.loadProgram(0x9d, 0x10, 0xab); // STA $ab10,X - cpu.step(); - assertEquals(0x80, bus.read(0xab40)); - assertFalse(cpu.getZeroFlag()); - assertTrue(cpu.getNegativeFlag()); - } - - /* LDA - Load Accumulator - $bd */ - - public void test_LDA() throws MemoryAccessException { - bus.write(0xab42, 0x00); - bus.write(0xab43, 0x0f); - bus.write(0xab44, 0x80); - - bus.loadProgram(0xbd, 0x10, 0xab, // LDA $ab10,X - 0xbd, 0x11, 0xab, // LDA $ab11,X - 0xbd, 0x12, 0xab); // LDA $ab12,X - - cpu.setXRegister(0x32); - - cpu.step(); - assertEquals(0x00, cpu.getAccumulator()); - assertTrue(cpu.getZeroFlag()); - assertFalse(cpu.getNegativeFlag()); - - cpu.step(); - assertEquals(0x0f, cpu.getAccumulator()); - assertFalse(cpu.getZeroFlag()); - assertFalse(cpu.getNegativeFlag()); - - cpu.step(); - assertEquals(0x80, cpu.getAccumulator()); - assertFalse(cpu.getZeroFlag()); - assertTrue(cpu.getNegativeFlag()); - } - - /* CMP - Compare Accumulator - $dd */ - - public void test_CMP() throws MemoryAccessException { - bus.write(0xab40, 0x00); - bus.write(0xab41, 0x80); - bus.write(0xab42, 0xff); - - cpu.setAccumulator(0x80); - - bus.loadProgram(0xdd, 0x10, 0xab, // CMP $ab10,X - 0xdd, 0x11, 0xab, // CMP $ab11,X - 0xdd, 0x12, 0xab); // CMP $ab12,X - - cpu.setXRegister(0x30); - - cpu.step(); - assertTrue(cpu.getCarryFlag()); // m > y - assertFalse(cpu.getZeroFlag()); - assertTrue(cpu.getNegativeFlag()); // m - y < 0 - - cpu.step(); - assertTrue(cpu.getCarryFlag()); // m = y - assertTrue(cpu.getZeroFlag()); - assertFalse(cpu.getNegativeFlag()); // m - y == 0 - - cpu.step(); - assertFalse(cpu.getCarryFlag()); // m < y - assertFalse(cpu.getZeroFlag()); - assertFalse(cpu.getNegativeFlag()); // m - y > 0 - } - - /* SBC - Subtract with Carry - $fd */ - - public void test_SBC() throws MemoryAccessException { - bus.write(0xab40, 0x01); - - bus.loadProgram(0xa9, 0x00, // LDA #$00 - 0xfd, 0x10, 0xab); // SBC $ab10,X - cpu.setXRegister(0x30); - cpu.step(2); - assertEquals(0xfe, cpu.getAccumulator()); - assertTrue(cpu.getNegativeFlag()); - assertFalse(cpu.getOverflowFlag()); - assertFalse(cpu.getZeroFlag()); - assertFalse(cpu.getCarryFlag()); - - cpu.reset(); - bus.loadProgram(0xa9, 0x7f, // LDA #$7f - 0xfd, 0x10, 0xab); // SBC $ab10,X - cpu.setXRegister(0x30); - cpu.step(2); - assertEquals(0x7d, cpu.getAccumulator()); - assertFalse(cpu.getNegativeFlag()); - assertFalse(cpu.getOverflowFlag()); - assertFalse(cpu.getZeroFlag()); - assertTrue(cpu.getCarryFlag()); - - cpu.reset(); - bus.loadProgram(0xa9, 0x80, // LDA #$80 - 0xfd, 0x10, 0xab); // SBC $ab10,X - cpu.setXRegister(0x30); - cpu.step(2); - assertEquals(0x7e, cpu.getAccumulator()); - assertFalse(cpu.getNegativeFlag()); - assertTrue(cpu.getOverflowFlag()); - assertFalse(cpu.getZeroFlag()); - assertTrue(cpu.getCarryFlag()); - - cpu.reset(); - bus.loadProgram(0xa9, 0xff, // LDA #$ff - 0xfd, 0x10, 0xab); // SBC $ab10,X - cpu.setXRegister(0x30); - cpu.step(2); - assertEquals(0xfd, cpu.getAccumulator()); - assertTrue(cpu.getNegativeFlag()); - assertFalse(cpu.getOverflowFlag()); - assertFalse(cpu.getZeroFlag()); - assertTrue(cpu.getCarryFlag()); - - cpu.reset(); - bus.loadProgram(0xa9, 0x02, // LDA #$02 - 0xfd, 0x10, 0xab); // SBC $ab10,X - cpu.setXRegister(0x30); - cpu.step(2); - assertEquals(0x00, cpu.getAccumulator()); - assertFalse(cpu.getNegativeFlag()); - assertFalse(cpu.getOverflowFlag()); - assertTrue(cpu.getZeroFlag()); - assertTrue(cpu.getCarryFlag()); - } - - public void test_SBC_IncludesNotOfCarry() throws MemoryAccessException { - bus.write(0xab40, 0x01); - - // Subtrace with Carry Flag cleared - bus.loadProgram(0x18, // CLC - 0xa9, 0x05, // LDA #$00 - 0xfd, 0x10, 0xab); // SBC $ab10,X - cpu.setXRegister(0x30); - cpu.step(3); - assertEquals(0x03, cpu.getAccumulator()); - - cpu.reset(); - - // Subtrace with Carry Flag cleared - bus.loadProgram(0x18, // CLC - 0xa9, 0x00, // LDA #$00 - 0xfd, 0x10, 0xab); // SBC $ab10,X - cpu.setXRegister(0x30); - cpu.step(3); - assertEquals(0xfe, cpu.getAccumulator()); - - cpu.reset(); - - // Subtract with Carry Flag set - bus.loadProgram(0x38, // SEC - 0xa9, 0x05, // LDA #$00 - 0xfd, 0x10, 0xab); // SBC $ab10,X - cpu.setXRegister(0x30); - 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 - 0xfd, 0x10, 0xab); // SBC $ab10,X - cpu.setXRegister(0x30); - cpu.step(3); - assertEquals(0xff, cpu.getAccumulator()); - assertFalse(cpu.getCarryFlag()); - - } - - public void test_SBC_DecimalMode() throws MemoryAccessException { - bus.write(0xab40, 0x01); - bus.write(0xab50, 0x11); - - bus.loadProgram(0xf8, // SED - 0xa9, 0x00, // LDA #$00 - 0xfd, 0x10, 0xab); // SBC $ab10,X - cpu.setXRegister(0x30); - 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, // SED - 0xa9, 0x99, // LDA #$99 - 0xfd, 0x10, 0xab); // SBC $ab10,X - cpu.setXRegister(0x30); - 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, // SED - 0xa9, 0x50, // LDA #$50 - 0xfd, 0x10, 0xab); // SBC $ab10,X - cpu.setXRegister(0x30); - 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 - 0xfd, 0x10, 0xab); // SBC $ab10,X - cpu.setXRegister(0x30); - 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 - 0xfd, 0x20, 0xab); // SBC $ab20,X - cpu.setXRegister(0x30); - 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 - 0xfd, 0x10, 0xab); // SBC $ab10,X - cpu.setXRegister(0x30); - 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 - 0xfd, 0x10, 0xab); // SBC $ab10,X - cpu.setXRegister(0x30); - cpu.step(4); - assertEquals(0x99, cpu.getAccumulator()); - assertFalse(cpu.getCarryFlag()); - assertFalse(cpu.getNegativeFlag()); - assertFalse(cpu.getOverflowFlag()); - assertFalse(cpu.getZeroFlag()); - assertTrue(cpu.getDecimalModeFlag()); - } + protected Cpu cpu; + protected Bus bus; + protected Memory mem; + + protected void setUp() throws Exception { + this.cpu = new Cpu(); + this.bus = new Bus(0x0000, 0xffff); + this.mem = new Memory(0x0000, 0x10000); + bus.addCpu(cpu); + bus.addDevice(mem); + + // Load the reset vector. + bus.write(0xfffc, Cpu.DEFAULT_BASE_ADDRESS & 0x00ff); + 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 - $01 + * AND - $21 + * EOR - $41 + * ADC - $61 + * STA - $81 + * + * LDA - $a1 + * CMP - $c1 + * SBC - $e1 + * + */ + + /* ORA - Logical Inclusive OR - $1d */ + + public void test_ORA() throws MemoryAccessException { + // Set some initial values in memory + bus.write(0x2c30, 0x00); + bus.write(0x2c32, 0x11); + bus.write(0x2c34, 0x22); + bus.write(0x2c38, 0x44); + bus.write(0x2c40, 0x88); + + // Set offset in X register. + cpu.setXRegister(0x30); + + bus.loadProgram(0x1d, 0x00, 0x2c, // ORA $2c00,X + 0x1d, 0x02, 0x2c, // ORA $2c02,X + 0x1d, 0x04, 0x2c, // ORA $2c04,X + 0x1d, 0x08, 0x2c, // ORA $2c08,X + 0x1d, 0x10, 0x2c); // ORA $2c10,X + + 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()); + + } + + /* AND - Logical AND - $3d */ + + public void test_AND() throws MemoryAccessException { + bus.write(0x1a30, 0x00); + bus.write(0x1a31, 0x11); + bus.write(0x1a32, 0xff); + bus.write(0x1a33, 0x99); + bus.write(0x1a34, 0x11); + bus.write(0x1a35, 0x0f); + bus.write(0x1a02, 0x11); + + // Set offset in X register. + cpu.setXRegister(0x30); + + bus.loadProgram(0x3d, 0x00, 0x1a, // AND $1a00,X + 0x3d, 0x01, 0x1a, // AND $1a01,X + 0xa9, 0xaa, // LDA #$aa + 0x3d, 0x02, 0x1a, // AND $1a02,X + 0x3d, 0x03, 0x1a, // AND $1a03,X + 0x3d, 0x04, 0x1a, // AND $1a04,X + 0xa9, 0xff, // LDA #$ff + 0x3d, 0x05, 0x1a, // AND $1a05,X + 0xa9, 0x01, // LDA #$01 + 0x3d, 0xd2, 0x19); // AND $19d2,X + cpu.step(); + assertEquals(0x00, cpu.getAccumulator()); + assertTrue(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + + cpu.step(); + assertEquals(0x00, cpu.getAccumulator()); + assertTrue(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + + cpu.step(2); + assertEquals(0xaa, cpu.getAccumulator()); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getNegativeFlag()); + + cpu.step(); + assertEquals(0x88, cpu.getAccumulator()); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getNegativeFlag()); + + cpu.step(); + assertEquals(0x00, cpu.getAccumulator()); + assertTrue(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + + cpu.step(2); + assertEquals(0x0f, cpu.getAccumulator()); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + + cpu.step(2); + assertEquals(0x01, cpu.getAccumulator()); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + } + + /* EOR - Exclusive OR - $5d */ + + public void test_EOR() throws MemoryAccessException { + bus.write(0xab40, 0x00); + bus.write(0xab41, 0xff); + bus.write(0xab42, 0x33); + bus.write(0xab43, 0x44); + + cpu.setXRegister(0x30); + + bus.loadProgram(0xa9, 0x88, // LDA #$88 + 0x5d, 0x10, 0xab, // EOR $ab10,X + 0x5d, 0x11, 0xab, // EOR $ab11,X + 0x5d, 0x12, 0xab, // EOR $ab12,X + 0x5d, 0x13, 0xab); // EOR $ab13,X + cpu.step(2); + assertEquals(0x88, cpu.getAccumulator()); + assertTrue(cpu.getNegativeFlag()); + assertFalse(cpu.getZeroFlag()); + + cpu.step(); + assertEquals(0x77, cpu.getAccumulator()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getZeroFlag()); + + cpu.step(); + assertEquals(0x44, cpu.getAccumulator()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getZeroFlag()); + + cpu.step(); + assertEquals(0x00, cpu.getAccumulator()); + assertFalse(cpu.getNegativeFlag()); + assertTrue(cpu.getZeroFlag()); + } + + /* ADC - Add with Carry - $7d */ + + public void test_ADC() throws MemoryAccessException { + bus.write(0xab40, 0x01); + bus.write(0xab41, 0xff); + + cpu.setXRegister(0x30); + + bus.loadProgram(0xa9, 0x00, // LDA #$00 + 0x7d, 0x10, 0xab); // ADC $ab10,X + cpu.step(2); + assertEquals(0x01, cpu.getAccumulator()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.reset(); + cpu.setXRegister(0x30); + + bus.loadProgram(0xa9, 0x7f, // LDA #$7f + 0x7d, 0x10, 0xab); // ADC $ab10,X + cpu.step(2); + assertEquals(0x80, cpu.getAccumulator()); + assertTrue(cpu.getNegativeFlag()); + assertTrue(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.reset(); + cpu.setXRegister(0x30); + + bus.loadProgram(0xa9, 0x80, // LDA #$80 + 0x7d, 0x10, 0xab); // ADC $ab10,X + cpu.step(2); + assertEquals(0x81, cpu.getAccumulator()); + assertTrue(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.reset(); + cpu.setXRegister(0x30); + + bus.loadProgram(0xa9, 0xff, // LDA #$ff + 0x7d, 0x10, 0xab); // ADC $ab10,X + cpu.step(2); + assertEquals(0x00, cpu.getAccumulator()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertTrue(cpu.getZeroFlag()); + assertTrue(cpu.getCarryFlag()); + + cpu.reset(); + cpu.setXRegister(0x30); + + bus.loadProgram(0xa9, 0x00, // LDA #$00 + 0x7d, 0x11, 0xab); // ADC $ab11,X + cpu.step(2); + assertEquals(0xff, cpu.getAccumulator()); + assertTrue(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.reset(); + cpu.setXRegister(0x30); + + bus.loadProgram(0xa9, 0x7f, // LDA #$7f + 0x7d, 0x11, 0xab); // ADC $ab11,X + cpu.step(2); + assertEquals(0x7e, cpu.getAccumulator()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getCarryFlag()); + + cpu.reset(); + cpu.setXRegister(0x30); + + bus.loadProgram(0xa9, 0x80, // LDA #$80 + 0x7d, 0x11, 0xab); // ADC $ab11,X + cpu.step(2); + assertEquals(0x7f, cpu.getAccumulator()); + assertFalse(cpu.getNegativeFlag()); + assertTrue(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getCarryFlag()); + + cpu.reset(); + cpu.setXRegister(0x30); + + bus.loadProgram(0xa9, 0xff, // LDA #$ff + 0x7d, 0x11, 0xab); // ADC $ab11,X + cpu.step(2); + assertEquals(0xfe, cpu.getAccumulator()); + assertTrue(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getCarryFlag()); + } + + public void test_ADC_IncludesCarry() throws MemoryAccessException { + bus.write(0xab40, 0x01); + + bus.loadProgram(0xa9, 0x00, // LDA #$00 + 0x38, // SEC + 0x7d, 0x10, 0xab); // ADC $ab10,X + + cpu.setXRegister(0x30); + + cpu.step(3); + assertEquals(0x02, cpu.getAccumulator()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getCarryFlag()); + } + + public void test_ADC_DecimalMode() throws MemoryAccessException { + bus.write(0xab40, 0x01); + bus.write(0xab41, 0x99); + + bus.loadProgram(0xf8, // SED + 0xa9, 0x01, // LDA #$01 + 0x7d, 0x10, 0xab); // ADC $ab10,X + + cpu.setXRegister(0x30); + + cpu.step(3); + assertEquals(0x02, cpu.getAccumulator()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.reset(); + cpu.setXRegister(0x30); + + bus.loadProgram(0xf8, // SED + 0xa9, 0x49, // LDA #$49 + 0x7d, 0x10, 0xab); // ADC $ab10,X + cpu.step(3); + assertEquals(0x50, cpu.getAccumulator()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.reset(); + cpu.setXRegister(0x30); + + bus.loadProgram(0xf8, // SED + 0xa9, 0x50, // LDA #$50 + 0x7d, 0x10, 0xab); // ADC $ab10,X + cpu.step(3); + assertEquals(0x51, cpu.getAccumulator()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.reset(); + cpu.setXRegister(0x30); + + bus.loadProgram(0xf8, // SED + 0xa9, 0x99, // LDA #$99 + 0x7d, 0x10, 0xab); // ADC $ab10,X + cpu.step(3); + assertEquals(0x00, cpu.getAccumulator()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertTrue(cpu.getZeroFlag()); + assertTrue(cpu.getCarryFlag()); + + cpu.reset(); + cpu.setXRegister(0x30); + + bus.loadProgram(0xf8, // SED + 0xa9, 0x00, // LDA #$00 + 0x7d, 0x11, 0xab); // ADC $ab10,X + cpu.step(3); + assertEquals(0x99, cpu.getAccumulator()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.reset(); + cpu.setXRegister(0x30); + + bus.loadProgram(0xf8, // SED + 0xa9, 0x49, // LDA #$49 + 0x7d, 0x11, 0xab); // ADC $ab11,X + cpu.step(3); + assertEquals(0x48, cpu.getAccumulator()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getCarryFlag()); + + cpu.reset(); + cpu.setXRegister(0x30); + + bus.loadProgram(0xf8, // SED + 0xa9, 0x50, // LDA #$59 + 0x7d, 0x11, 0xab); // ADC $ab11,X + cpu.step(3); + assertEquals(0x49, cpu.getAccumulator()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getCarryFlag()); + } + + /* STA - Store Accumulator - $9d */ + + public void test_STA() throws MemoryAccessException { + cpu.setXRegister(0x30); + + cpu.setAccumulator(0x00); + bus.loadProgram(0x9d, 0x10, 0xab); // STA $ab10,X + cpu.step(); + assertEquals(0x00, bus.read(0xab40)); + assertTrue(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + + cpu.reset(); + cpu.setXRegister(0x30); + + + cpu.setAccumulator(0x0f); + bus.loadProgram(0x9d, 0x10, 0xab); // STA $ab10,X + cpu.step(); + assertEquals(0x0f, bus.read(0xab40)); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + + cpu.reset(); + cpu.setXRegister(0x30); + + cpu.setAccumulator(0x80); + bus.loadProgram(0x9d, 0x10, 0xab); // STA $ab10,X + cpu.step(); + assertEquals(0x80, bus.read(0xab40)); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getNegativeFlag()); + } + + /* LDA - Load Accumulator - $bd */ + + public void test_LDA() throws MemoryAccessException { + bus.write(0xab42, 0x00); + bus.write(0xab43, 0x0f); + bus.write(0xab44, 0x80); + + bus.loadProgram(0xbd, 0x10, 0xab, // LDA $ab10,X + 0xbd, 0x11, 0xab, // LDA $ab11,X + 0xbd, 0x12, 0xab); // LDA $ab12,X + + cpu.setXRegister(0x32); + + cpu.step(); + assertEquals(0x00, cpu.getAccumulator()); + assertTrue(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + + cpu.step(); + assertEquals(0x0f, cpu.getAccumulator()); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + + cpu.step(); + assertEquals(0x80, cpu.getAccumulator()); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getNegativeFlag()); + } + + /* CMP - Compare Accumulator - $dd */ + + public void test_CMP() throws MemoryAccessException { + bus.write(0xab40, 0x00); + bus.write(0xab41, 0x80); + bus.write(0xab42, 0xff); + + cpu.setAccumulator(0x80); + + bus.loadProgram(0xdd, 0x10, 0xab, // CMP $ab10,X + 0xdd, 0x11, 0xab, // CMP $ab11,X + 0xdd, 0x12, 0xab); // CMP $ab12,X + + cpu.setXRegister(0x30); + + cpu.step(); + assertTrue(cpu.getCarryFlag()); // m > y + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getNegativeFlag()); // m - y < 0 + + cpu.step(); + assertTrue(cpu.getCarryFlag()); // m = y + assertTrue(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); // m - y == 0 + + cpu.step(); + assertFalse(cpu.getCarryFlag()); // m < y + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); // m - y > 0 + } + + /* SBC - Subtract with Carry - $fd */ + + public void test_SBC() throws MemoryAccessException { + bus.write(0xab40, 0x01); + + bus.loadProgram(0xa9, 0x00, // LDA #$00 + 0xfd, 0x10, 0xab); // SBC $ab10,X + cpu.setXRegister(0x30); + cpu.step(2); + assertEquals(0xfe, cpu.getAccumulator()); + assertTrue(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.reset(); + bus.loadProgram(0xa9, 0x7f, // LDA #$7f + 0xfd, 0x10, 0xab); // SBC $ab10,X + cpu.setXRegister(0x30); + cpu.step(2); + assertEquals(0x7d, cpu.getAccumulator()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getCarryFlag()); + + cpu.reset(); + bus.loadProgram(0xa9, 0x80, // LDA #$80 + 0xfd, 0x10, 0xab); // SBC $ab10,X + cpu.setXRegister(0x30); + cpu.step(2); + assertEquals(0x7e, cpu.getAccumulator()); + assertFalse(cpu.getNegativeFlag()); + assertTrue(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getCarryFlag()); + + cpu.reset(); + bus.loadProgram(0xa9, 0xff, // LDA #$ff + 0xfd, 0x10, 0xab); // SBC $ab10,X + cpu.setXRegister(0x30); + cpu.step(2); + assertEquals(0xfd, cpu.getAccumulator()); + assertTrue(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getCarryFlag()); + + cpu.reset(); + bus.loadProgram(0xa9, 0x02, // LDA #$02 + 0xfd, 0x10, 0xab); // SBC $ab10,X + cpu.setXRegister(0x30); + cpu.step(2); + assertEquals(0x00, cpu.getAccumulator()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertTrue(cpu.getZeroFlag()); + assertTrue(cpu.getCarryFlag()); + } + + public void test_SBC_IncludesNotOfCarry() throws MemoryAccessException { + bus.write(0xab40, 0x01); + + // Subtrace with Carry Flag cleared + bus.loadProgram(0x18, // CLC + 0xa9, 0x05, // LDA #$00 + 0xfd, 0x10, 0xab); // SBC $ab10,X + cpu.setXRegister(0x30); + cpu.step(3); + assertEquals(0x03, cpu.getAccumulator()); + + cpu.reset(); + + // Subtrace with Carry Flag cleared + bus.loadProgram(0x18, // CLC + 0xa9, 0x00, // LDA #$00 + 0xfd, 0x10, 0xab); // SBC $ab10,X + cpu.setXRegister(0x30); + cpu.step(3); + assertEquals(0xfe, cpu.getAccumulator()); + + cpu.reset(); + + // Subtract with Carry Flag set + bus.loadProgram(0x38, // SEC + 0xa9, 0x05, // LDA #$00 + 0xfd, 0x10, 0xab); // SBC $ab10,X + cpu.setXRegister(0x30); + 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 + 0xfd, 0x10, 0xab); // SBC $ab10,X + cpu.setXRegister(0x30); + cpu.step(3); + assertEquals(0xff, cpu.getAccumulator()); + assertFalse(cpu.getCarryFlag()); + + } + + public void test_SBC_DecimalMode() throws MemoryAccessException { + bus.write(0xab40, 0x01); + bus.write(0xab50, 0x11); + + bus.loadProgram(0xf8, // SED + 0xa9, 0x00, // LDA #$00 + 0xfd, 0x10, 0xab); // SBC $ab10,X + cpu.setXRegister(0x30); + 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, // SED + 0xa9, 0x99, // LDA #$99 + 0xfd, 0x10, 0xab); // SBC $ab10,X + cpu.setXRegister(0x30); + 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, // SED + 0xa9, 0x50, // LDA #$50 + 0xfd, 0x10, 0xab); // SBC $ab10,X + cpu.setXRegister(0x30); + 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 + 0xfd, 0x10, 0xab); // SBC $ab10,X + cpu.setXRegister(0x30); + 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 + 0xfd, 0x20, 0xab); // SBC $ab20,X + cpu.setXRegister(0x30); + 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 + 0xfd, 0x10, 0xab); // SBC $ab10,X + cpu.setXRegister(0x30); + 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 + 0xfd, 0x10, 0xab); // SBC $ab10,X + cpu.setXRegister(0x30); + cpu.step(4); + assertEquals(0x99, cpu.getAccumulator()); + assertFalse(cpu.getCarryFlag()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getDecimalModeFlag()); + } } diff --git a/src/test/java/com/loomcom/symon/CpuZeroPageXModeTest.java b/src/test/java/com/loomcom/symon/CpuZeroPageXModeTest.java index f8db706..3f37017 100644 --- a/src/test/java/com/loomcom/symon/CpuZeroPageXModeTest.java +++ b/src/test/java/com/loomcom/symon/CpuZeroPageXModeTest.java @@ -7,1097 +7,1126 @@ import junit.framework.TestCase; public class CpuZeroPageXModeTest extends TestCase { - protected Cpu cpu; - protected Bus bus; - protected Memory mem; - - protected void setUp() throws Exception { - this.cpu = new Cpu(); - this.bus = new Bus(0x0000, 0xffff); - this.mem = new Memory(0x0000, 0x10000); - bus.addCpu(cpu); - bus.addDevice(mem); - - // Load the reset vector. - bus.write(0xfffc, Cpu.DEFAULT_BASE_ADDRESS & 0x00ff); - 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 - $15 - * ASL - $16 - * AND - $35 - * ROL - $36 - * EOR - $55 - * - * LSR - $56 - * ADC - $75 - * ROR - $76 - * STY - $94 - * STA - $95 - * - * LDY - $b4 - * LDA - $b5 - * CMP - $d5 - * DEC - $d6 - * SBC - $f5 - * - * INC - $f6 - */ - - /* ORA - Logical Inclusive OR - $15 */ - - public void test_ORA() throws MemoryAccessException { - // Set some initial values in zero page. - bus.write(0x30, 0x00); - bus.write(0x32, 0x11); - bus.write(0x34, 0x22); - bus.write(0x38, 0x44); - bus.write(0x40, 0x88); - bus.write(0x02, 0x88); - - // Set offset in X register. - cpu.setXRegister(0x30); - - bus.loadProgram(0x15, 0x00, // ORA $00,X - 0x15, 0x02, // ORA $02,X - 0x15, 0x04, // ORA $04,X - 0x15, 0x08, // ORA $08,X - 0x15, 0x10, // ORA $10,X - 0xa9, 0x00, // LDA #$00 - 0x15, 0xd2); // ORA $d2,X - should wrap around - - 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()); - - // Should wrap around and ORA with value in 0x02 - cpu.step(2); - assertEquals(0x88, cpu.getAccumulator()); - assertFalse(cpu.getZeroFlag()); - assertTrue(cpu.getNegativeFlag()); - } - - /* ASL - Arithmetic Shift Left - $16 */ - - public void test_ASL() throws MemoryAccessException { - bus.write(0x30, 0x00); - bus.write(0x31, 0x01); - bus.write(0x32, 0x02); - bus.write(0x33, 0x44); - bus.write(0x34, 0x80); - bus.write(0x02, 0x01); - - // Set offset in X register. - cpu.setXRegister(0x30); - - bus.loadProgram(0x16, 0x00, // ASL $00,X - 0x16, 0x01, // ASL $01,X - 0x16, 0x02, // ASL $02,X - 0x16, 0x03, // ASL $03,X - 0x16, 0x04, // ASL $04,X - 0x16, 0xd2); // ASL $d2,X - - cpu.step(); - assertEquals(0x00, bus.read(0x30)); - assertTrue(cpu.getZeroFlag()); - assertFalse(cpu.getNegativeFlag()); - assertFalse(cpu.getCarryFlag()); - - cpu.step(); - assertEquals(0x02, bus.read(0x31)); - assertFalse(cpu.getZeroFlag()); - assertFalse(cpu.getNegativeFlag()); - assertFalse(cpu.getCarryFlag()); - - cpu.step(); - assertEquals(0x04, bus.read(0x32)); - assertFalse(cpu.getZeroFlag()); - assertFalse(cpu.getNegativeFlag()); - assertFalse(cpu.getCarryFlag()); - - cpu.step(); - assertEquals(0x88, bus.read(0x33)); - assertFalse(cpu.getZeroFlag()); - assertTrue(cpu.getNegativeFlag()); - assertFalse(cpu.getCarryFlag()); - - cpu.step(); - assertEquals(0x00, bus.read(0x34)); - assertTrue(cpu.getZeroFlag()); - assertFalse(cpu.getNegativeFlag()); - assertTrue(cpu.getCarryFlag()); - - // Should wrap around, d2 + 30 = 02 - cpu.step(); - assertEquals(0x02, bus.read(0x02)); - assertFalse(cpu.getZeroFlag()); - assertFalse(cpu.getNegativeFlag()); - assertFalse(cpu.getCarryFlag()); - } - - /* AND - Logical AND - $35 */ - - public void test_AND() throws MemoryAccessException { - bus.write(0x30, 0x00); - bus.write(0x31, 0x11); - bus.write(0x32, 0xff); - bus.write(0x33, 0x99); - bus.write(0x34, 0x11); - bus.write(0x35, 0x0f); - bus.write(0x02, 0x11); - - // Set offset in X register. - cpu.setXRegister(0x30); - - bus.loadProgram(0x35, 0x00, // AND $00 - 0x35, 0x01, // AND $01,X - 0xa9, 0xaa, // LDA #$aa - 0x35, 0x02, // AND $02,X - 0x35, 0x03, // AND $03 - 0x35, 0x04, // AND $04,X - 0xa9, 0xff, // LDA #$ff - 0x35, 0x05, // AND $05,X - 0xa9, 0x01, // LDA #$01 - 0x35, 0xd2); // AND $d2,X - cpu.step(); - assertEquals(0x00, cpu.getAccumulator()); - assertTrue(cpu.getZeroFlag()); - assertFalse(cpu.getNegativeFlag()); - - cpu.step(); - assertEquals(0x00, cpu.getAccumulator()); - assertTrue(cpu.getZeroFlag()); - assertFalse(cpu.getNegativeFlag()); - - cpu.step(2); - assertEquals(0xaa, cpu.getAccumulator()); - assertFalse(cpu.getZeroFlag()); - assertTrue(cpu.getNegativeFlag()); - - cpu.step(); - assertEquals(0x88, cpu.getAccumulator()); - assertFalse(cpu.getZeroFlag()); - assertTrue(cpu.getNegativeFlag()); - - cpu.step(); - assertEquals(0x00, cpu.getAccumulator()); - assertTrue(cpu.getZeroFlag()); - assertFalse(cpu.getNegativeFlag()); - - cpu.step(2); - assertEquals(0x0f, cpu.getAccumulator()); - assertFalse(cpu.getZeroFlag()); - assertFalse(cpu.getNegativeFlag()); - - cpu.step(2); - assertEquals(0x01, cpu.getAccumulator()); - assertFalse(cpu.getZeroFlag()); - assertFalse(cpu.getNegativeFlag()); - } - - /* ROL - Rotate Shift Left - $36 */ - - public void test_ROL() throws MemoryAccessException { - - bus.write(0x70, 0x00); - bus.write(0x71, 0x01); - - // Set offset in X register - cpu.setXRegister(0x70); - - bus.loadProgram(0x36, 0x00, // ROL $00,X (m=%00000000, c=0) - 0x36, 0x01, // ROL $01,X (m=%00000010, c=0) - 0x38, // SEC (m=%00000010, c=1) - 0x36, 0x01, // ROL $01,X (m=%00000101, c=0) - 0x36, 0x01, // ROL $01,X (m=%00001010, c=0) - 0x36, 0x01, // ROL $01,X (m=%00010100, c=0) - 0x36, 0x01, // ROL $01,X (m=%00101000, c=0) - 0x36, 0x01, // ROL $01,X (m=%01010000, c=0) - 0x36, 0x01, // ROL $01,X (m=%10100000, c=0) - 0x36, 0x01, // ROL $01,X (m=%01000000, c=1) - 0x36, 0x01); // ROL $01,X (m=%10000001, c=0) - - cpu.step(); - assertEquals(0x00, bus.read(0x70)); - assertTrue(cpu.getZeroFlag()); - assertFalse(cpu.getNegativeFlag()); - assertFalse(cpu.getCarryFlag()); - - cpu.step(); - assertEquals(0x02, bus.read(0x71)); - assertFalse(cpu.getZeroFlag()); - assertFalse(cpu.getNegativeFlag()); - assertFalse(cpu.getCarryFlag()); - - cpu.step(2); - assertEquals(0x05, bus.read(0x71)); - assertFalse(cpu.getZeroFlag()); - assertFalse(cpu.getNegativeFlag()); - assertFalse(cpu.getCarryFlag()); - - cpu.step(); - assertEquals(0x0a, bus.read(0x71)); - assertFalse(cpu.getZeroFlag()); - assertFalse(cpu.getNegativeFlag()); - assertFalse(cpu.getCarryFlag()); - - cpu.step(); - assertEquals(0x14, bus.read(0x71)); - assertFalse(cpu.getZeroFlag()); - assertFalse(cpu.getNegativeFlag()); - assertFalse(cpu.getCarryFlag()); - - cpu.step(); - assertEquals(0x28, bus.read(0x71)); - assertFalse(cpu.getZeroFlag()); - assertFalse(cpu.getNegativeFlag()); - assertFalse(cpu.getCarryFlag()); - - cpu.step(); - assertEquals(0x50, bus.read(0x71)); - assertFalse(cpu.getZeroFlag()); - assertFalse(cpu.getNegativeFlag()); - assertFalse(cpu.getCarryFlag()); - - cpu.step(); - assertEquals(0xa0, bus.read(0x71)); - assertFalse(cpu.getZeroFlag()); - assertTrue(cpu.getNegativeFlag()); - assertFalse(cpu.getCarryFlag()); - - cpu.step(); - assertEquals(0x40, bus.read(0x71)); - assertFalse(cpu.getZeroFlag()); - assertFalse(cpu.getNegativeFlag()); - assertTrue(cpu.getCarryFlag()); - - cpu.step(); - assertEquals(0x81, bus.read(0x71)); - assertFalse(cpu.getZeroFlag()); - assertTrue(cpu.getNegativeFlag()); - assertFalse(cpu.getCarryFlag()); - } - - /* EOR - Exclusive OR - $55 */ - - public void test_EOR() throws MemoryAccessException { - bus.write(0x40, 0x00); - bus.write(0x41, 0xff); - bus.write(0x42, 0x33); - bus.write(0x43, 0x44); - - cpu.setXRegister(0x30); - - bus.loadProgram(0xa9, 0x88, // LDA #$88 - 0x55, 0x10, // EOR $10,X - 0x55, 0x11, // EOR $11,X - 0x55, 0x12, // EOR $12,X - 0x55, 0x13); // EOR $13,X - cpu.step(2); - assertEquals(0x88, cpu.getAccumulator()); - assertTrue(cpu.getNegativeFlag()); - assertFalse(cpu.getZeroFlag()); - - cpu.step(); - assertEquals(0x77, cpu.getAccumulator()); - assertFalse(cpu.getNegativeFlag()); - assertFalse(cpu.getZeroFlag()); - - cpu.step(); - assertEquals(0x44, cpu.getAccumulator()); - assertFalse(cpu.getNegativeFlag()); - assertFalse(cpu.getZeroFlag()); - - cpu.step(); - assertEquals(0x00, cpu.getAccumulator()); - assertFalse(cpu.getNegativeFlag()); - assertTrue(cpu.getZeroFlag()); - } - - /* LSR - Logical Shift Right - $56 */ - - public void test_LSR() throws MemoryAccessException { - bus.write(0x30, 0x00); - bus.write(0x31, 0x01); - bus.write(0x32, 0x02); - bus.write(0x33, 0x44); - bus.write(0x34, 0x80); - bus.write(0x35, 0x02); - - cpu.setXRegister(0x30); - - bus.loadProgram(0x56, 0x00, // LSR $00,X - 0x56, 0x01, // LSR $01,X - 0x56, 0x02, // LSR $02,X - 0x56, 0x03, // LSR $03,X - 0x56, 0x04, // LSR $04,X - 0x38, // SEC - 0x56, 0x05); // LSR $05,X - - cpu.step(); - assertEquals(0x00, bus.read(0x30)); - assertTrue(cpu.getZeroFlag()); - assertFalse(cpu.getNegativeFlag()); - assertFalse(cpu.getCarryFlag()); - - cpu.step(); - assertEquals(0x00, bus.read(0x31)); - assertTrue(cpu.getZeroFlag()); - assertFalse(cpu.getNegativeFlag()); - assertTrue(cpu.getCarryFlag()); - - cpu.step(); - assertEquals(0x01, bus.read(0x32)); - assertFalse(cpu.getZeroFlag()); - assertFalse(cpu.getNegativeFlag()); - assertFalse(cpu.getCarryFlag()); - - cpu.step(); - assertEquals(0x22, bus.read(0x33)); - assertFalse(cpu.getZeroFlag()); - assertFalse(cpu.getNegativeFlag()); - assertFalse(cpu.getCarryFlag()); - - cpu.step(); - assertEquals(0x40, bus.read(0x34)); - assertFalse(cpu.getZeroFlag()); - assertFalse(cpu.getNegativeFlag()); - assertFalse(cpu.getCarryFlag()); - - // Setting Carry should not affect the result. - cpu.step(2); - assertEquals(0x01, bus.read(0x35)); - assertFalse(cpu.getZeroFlag()); - assertFalse(cpu.getNegativeFlag()); - assertFalse(cpu.getCarryFlag()); - } - - /* ADC - Add with Carry - $75 */ - - public void test_ADC() throws MemoryAccessException { - bus.write(0x40, 0x01); - bus.write(0x41, 0xff); - - cpu.setXRegister(0x30); - - bus.loadProgram(0xa9, 0x00, // LDA #$00 - 0x75, 0x10); // ADC $10,X - cpu.step(2); - assertEquals(0x01, cpu.getAccumulator()); - assertFalse(cpu.getNegativeFlag()); - assertFalse(cpu.getOverflowFlag()); - assertFalse(cpu.getZeroFlag()); - assertFalse(cpu.getCarryFlag()); - - cpu.reset(); - bus.loadProgram(0xa9, 0x7f, // LDA #$7f - 0x75, 0x10); // ADC $10,X - cpu.step(2); - assertEquals(0x80, cpu.getAccumulator()); - assertTrue(cpu.getNegativeFlag()); - assertTrue(cpu.getOverflowFlag()); - assertFalse(cpu.getZeroFlag()); - assertFalse(cpu.getCarryFlag()); - - cpu.reset(); - bus.loadProgram(0xa9, 0x80, // LDA #$80 - 0x75, 0x10); // ADC $10,X - cpu.step(2); - assertEquals(0x81, cpu.getAccumulator()); - assertTrue(cpu.getNegativeFlag()); - assertFalse(cpu.getOverflowFlag()); - assertFalse(cpu.getZeroFlag()); - assertFalse(cpu.getCarryFlag()); - - cpu.reset(); - bus.loadProgram(0xa9, 0xff, // LDA #$ff - 0x75, 0x10); // ADC $10,X - cpu.step(2); - assertEquals(0x00, cpu.getAccumulator()); - assertFalse(cpu.getNegativeFlag()); - assertFalse(cpu.getOverflowFlag()); - assertTrue(cpu.getZeroFlag()); - assertTrue(cpu.getCarryFlag()); - - cpu.reset(); - bus.loadProgram(0xa9, 0x00, // LDA #$00 - 0x75, 0x11); // ADC $11,X - cpu.step(2); - assertEquals(0xff, cpu.getAccumulator()); - assertTrue(cpu.getNegativeFlag()); - assertFalse(cpu.getOverflowFlag()); - assertFalse(cpu.getZeroFlag()); - assertFalse(cpu.getCarryFlag()); - - cpu.reset(); - bus.loadProgram(0xa9, 0x7f, // LDA #$7f - 0x75, 0x11); // ADC $11,X - cpu.step(2); - assertEquals(0x7e, cpu.getAccumulator()); - assertFalse(cpu.getNegativeFlag()); - assertFalse(cpu.getOverflowFlag()); - assertFalse(cpu.getZeroFlag()); - assertTrue(cpu.getCarryFlag()); - - cpu.reset(); - bus.loadProgram(0xa9, 0x80, // LDA #$80 - 0x75, 0x11); // ADC $11,X - cpu.step(2); - assertEquals(0x7f, cpu.getAccumulator()); - assertFalse(cpu.getNegativeFlag()); - assertTrue(cpu.getOverflowFlag()); - assertFalse(cpu.getZeroFlag()); - assertTrue(cpu.getCarryFlag()); - - cpu.reset(); - bus.loadProgram(0xa9, 0xff, // LDA #$ff - 0x75, 0x11); // ADC $11,X - cpu.step(2); - assertEquals(0xfe, cpu.getAccumulator()); - assertTrue(cpu.getNegativeFlag()); - assertFalse(cpu.getOverflowFlag()); - assertFalse(cpu.getZeroFlag()); - assertTrue(cpu.getCarryFlag()); - } - - public void test_ADC_IncludesCarry() throws MemoryAccessException { - bus.write(0x40, 0x01); - - bus.loadProgram(0xa9, 0x00, // LDA #$00 - 0x38, // SEC - 0x75, 0x10); // ADC $10,X - - cpu.setXRegister(0x30); - - cpu.step(3); - assertEquals(0x02, cpu.getAccumulator()); - assertFalse(cpu.getNegativeFlag()); - assertFalse(cpu.getOverflowFlag()); - assertFalse(cpu.getZeroFlag()); - assertFalse(cpu.getCarryFlag()); - } - - public void test_ADC_DecimalMode() throws MemoryAccessException { - bus.write(0x40, 0x01); - bus.write(0x41, 0x99); - - bus.loadProgram(0xf8, // SED - 0xa9, 0x01, // LDA #$01 - 0x75, 0x10); // ADC $10,X - - cpu.setXRegister(0x30); - - cpu.step(3); - assertEquals(0x02, cpu.getAccumulator()); - assertFalse(cpu.getNegativeFlag()); - assertFalse(cpu.getOverflowFlag()); - assertFalse(cpu.getZeroFlag()); - assertFalse(cpu.getCarryFlag()); - - cpu.reset(); - bus.loadProgram(0xf8, // SED - 0xa9, 0x49, // LDA #$49 - 0x75, 0x10); // ADC $10,X - cpu.step(3); - assertEquals(0x50, cpu.getAccumulator()); - assertFalse(cpu.getNegativeFlag()); - assertFalse(cpu.getOverflowFlag()); - assertFalse(cpu.getZeroFlag()); - assertFalse(cpu.getCarryFlag()); - - cpu.reset(); - bus.loadProgram(0xf8, // SED - 0xa9, 0x50, // LDA #$50 - 0x75, 0x10); // ADC $10,X - cpu.step(3); - assertEquals(0x51, cpu.getAccumulator()); - assertFalse(cpu.getNegativeFlag()); - assertFalse(cpu.getOverflowFlag()); - assertFalse(cpu.getZeroFlag()); - assertFalse(cpu.getCarryFlag()); - - cpu.reset(); - bus.loadProgram(0xf8, // SED - 0xa9, 0x99, // LDA #$99 - 0x75, 0x10); // ADC $10,X - cpu.step(3); - assertEquals(0x00, cpu.getAccumulator()); - assertFalse(cpu.getNegativeFlag()); - assertFalse(cpu.getOverflowFlag()); - assertTrue(cpu.getZeroFlag()); - assertTrue(cpu.getCarryFlag()); - - cpu.reset(); - bus.loadProgram(0xf8, // SED - 0xa9, 0x00, // LDA #$00 - 0x75, 0x11); // ADC $10,X - cpu.step(3); - assertEquals(0x99, cpu.getAccumulator()); - assertFalse(cpu.getNegativeFlag()); - assertFalse(cpu.getOverflowFlag()); - assertFalse(cpu.getZeroFlag()); - assertFalse(cpu.getCarryFlag()); - - cpu.reset(); - bus.loadProgram(0xf8, // SED - 0xa9, 0x49, // LDA #$49 - 0x75, 0x11); // ADC $11,X - cpu.step(3); - assertEquals(0x48, cpu.getAccumulator()); - assertFalse(cpu.getNegativeFlag()); - assertFalse(cpu.getOverflowFlag()); - assertFalse(cpu.getZeroFlag()); - assertTrue(cpu.getCarryFlag()); - - cpu.reset(); - bus.loadProgram(0xf8, // SED - 0xa9, 0x50, // LDA #$59 - 0x75, 0x11); // ADC $11,X - cpu.step(3); - assertEquals(0x49, cpu.getAccumulator()); - assertFalse(cpu.getNegativeFlag()); - assertFalse(cpu.getOverflowFlag()); - assertFalse(cpu.getZeroFlag()); - assertTrue(cpu.getCarryFlag()); - } - - /* ROR - Rotate Right - $76 */ - - public void test_ROR() throws MemoryAccessException { - - bus.write(0x40, 0x00); - bus.write(0x41, 0x10); - - bus.loadProgram(0x76, 0x10, // ROR $00 (m=%00000000, c=0) - 0x76, 0x11, // ROR $01 (m=%00001000, c=0) - 0x76, 0x11, // ROR $01 (m=%00000100, c=0) - 0x76, 0x11, // ROR $01 (m=%00000010, c=0) - 0x76, 0x11, // ROR $01 (m=%00000001, c=0) - 0x76, 0x11, // ROR $01 (m=%00000000, c=1) - 0x76, 0x11, // ROR $01 (m=%10000000, c=0) - 0x76, 0x11, // ROR $01 (m=%01000000, c=0) - 0x76, 0x11, // ROR $01 (m=%00100000, c=0) - 0x76, 0x11); // ROR $01 (m=%00010000, c=0) - - cpu.setXRegister(0x30); - - cpu.step(); - assertEquals(0x00, bus.read(0x40)); - assertTrue(cpu.getZeroFlag()); - assertFalse(cpu.getNegativeFlag()); - assertFalse(cpu.getCarryFlag()); - - cpu.step(); - assertEquals(0x08, bus.read(0x41)); - assertFalse(cpu.getZeroFlag()); - assertFalse(cpu.getNegativeFlag()); - assertFalse(cpu.getCarryFlag()); - - cpu.step(); - assertEquals(0x04, bus.read(0x41)); - assertFalse(cpu.getZeroFlag()); - assertFalse(cpu.getNegativeFlag()); - assertFalse(cpu.getCarryFlag()); - - cpu.step(); - assertEquals(0x02, bus.read(0x41)); - assertFalse(cpu.getZeroFlag()); - assertFalse(cpu.getNegativeFlag()); - assertFalse(cpu.getCarryFlag()); - - cpu.step(); - assertEquals(0x01, bus.read(0x41)); - assertFalse(cpu.getZeroFlag()); - assertFalse(cpu.getNegativeFlag()); - assertFalse(cpu.getCarryFlag()); - - cpu.step(); - assertEquals(0x00, bus.read(0x41)); - assertTrue(cpu.getZeroFlag()); - assertFalse(cpu.getNegativeFlag()); - assertTrue(cpu.getCarryFlag()); - - cpu.step(); - assertEquals(0x80, bus.read(0x41)); - assertFalse(cpu.getZeroFlag()); - assertTrue(cpu.getNegativeFlag()); - assertFalse(cpu.getCarryFlag()); - - cpu.step(); - assertEquals(0x40, bus.read(0x41)); - assertFalse(cpu.getZeroFlag()); - assertFalse(cpu.getNegativeFlag()); - assertFalse(cpu.getCarryFlag()); - - cpu.step(); - assertEquals(0x20, bus.read(0x41)); - assertFalse(cpu.getZeroFlag()); - assertFalse(cpu.getNegativeFlag()); - assertFalse(cpu.getCarryFlag()); - - cpu.step(); - assertEquals(0x10, bus.read(0x41)); - assertFalse(cpu.getZeroFlag()); - assertFalse(cpu.getNegativeFlag()); - assertFalse(cpu.getCarryFlag()); - } - - /* STY - Store Y Register - $94 */ - - public void test_STY() throws MemoryAccessException { - cpu.setXRegister(0x30); - - cpu.setYRegister(0x00); - bus.loadProgram(0x94, 0x10); // STY $10,X - cpu.step(); - assertEquals(0x00, bus.read(0x40)); - assertTrue(cpu.getZeroFlag()); - assertFalse(cpu.getNegativeFlag()); - - cpu.reset(); - - cpu.setYRegister(0x0f); - bus.loadProgram(0x94, 0x10); // STY $10,X - cpu.step(); - assertEquals(0x0f, bus.read(0x40)); - assertFalse(cpu.getZeroFlag()); - assertFalse(cpu.getNegativeFlag()); - - cpu.reset(); - - cpu.setYRegister(0x80); - bus.loadProgram(0x94, 0x10); // STY $10,X - cpu.step(); - assertEquals(0x80, bus.read(0x40)); - assertFalse(cpu.getZeroFlag()); - assertTrue(cpu.getNegativeFlag()); - } - - /* STA - Store Accumulator - $95 */ - - public void test_STA() throws MemoryAccessException { - cpu.setXRegister(0x30); - - cpu.setAccumulator(0x00); - bus.loadProgram(0x95, 0x10); // STA $10,X - cpu.step(); - assertEquals(0x00, bus.read(0x40)); - assertTrue(cpu.getZeroFlag()); - assertFalse(cpu.getNegativeFlag()); - - cpu.reset(); - - cpu.setAccumulator(0x0f); - bus.loadProgram(0x95, 0x10); // STA $10,X - cpu.step(); - assertEquals(0x0f, bus.read(0x40)); - assertFalse(cpu.getZeroFlag()); - assertFalse(cpu.getNegativeFlag()); - - cpu.reset(); - - cpu.setAccumulator(0x80); - bus.loadProgram(0x95, 0x10); // STA $10,X - cpu.step(); - assertEquals(0x80, bus.read(0x40)); - assertFalse(cpu.getZeroFlag()); - assertTrue(cpu.getNegativeFlag()); - } - - /* LDY - Load Y Register - $b4 */ - - public void test_LDY() throws MemoryAccessException { - bus.write(0x45, 0x00); - bus.write(0x46, 0x0f); - bus.write(0x47, 0x80); - - bus.loadProgram(0xb4, 0x10, // LDY $10,X - 0xb4, 0x11, // LDY $11,X - 0xb4, 0x12); // LDY $12,X - - cpu.setXRegister(0x35); - - cpu.step(); - assertEquals(0x00, cpu.getYRegister()); - assertTrue(cpu.getZeroFlag()); - assertFalse(cpu.getNegativeFlag()); - - cpu.step(); - assertEquals(0x0f, cpu.getYRegister()); - assertFalse(cpu.getZeroFlag()); - assertFalse(cpu.getNegativeFlag()); - - cpu.step(); - assertEquals(0x80, cpu.getYRegister()); - assertFalse(cpu.getZeroFlag()); - assertTrue(cpu.getNegativeFlag()); - } - - /* LDA - Load Accumulator - $b5 */ - - public void test_LDA() throws MemoryAccessException { - bus.write(0x42, 0x00); - bus.write(0x43, 0x0f); - bus.write(0x44, 0x80); - - bus.loadProgram(0xb5, 0x10, // LDA $10,X - 0xb5, 0x11, // LDA $11,X - 0xb5, 0x12); // LDA $12,X - - cpu.setXRegister(0x32); - - cpu.step(); - assertEquals(0x00, cpu.getAccumulator()); - assertTrue(cpu.getZeroFlag()); - assertFalse(cpu.getNegativeFlag()); - - cpu.step(); - assertEquals(0x0f, cpu.getAccumulator()); - assertFalse(cpu.getZeroFlag()); - assertFalse(cpu.getNegativeFlag()); - - cpu.step(); - assertEquals(0x80, cpu.getAccumulator()); - assertFalse(cpu.getZeroFlag()); - assertTrue(cpu.getNegativeFlag()); - } - - /* CMP - Compare Accumulator - $d5 */ - - public void test_CMP() throws MemoryAccessException { - bus.write(0x40, 0x00); - bus.write(0x41, 0x80); - bus.write(0x42, 0xff); - - cpu.setAccumulator(0x80); - - bus.loadProgram(0xd5, 0x10, - 0xd5, 0x11, - 0xd5, 0x12); - - cpu.setXRegister(0x30); - - cpu.step(); - assertTrue(cpu.getCarryFlag()); // m > y - assertFalse(cpu.getZeroFlag()); - assertTrue(cpu.getNegativeFlag()); // m - y < 0 - - cpu.step(); - assertTrue(cpu.getCarryFlag()); // m = y - assertTrue(cpu.getZeroFlag()); - assertFalse(cpu.getNegativeFlag()); // m - y == 0 - - cpu.step(); - assertFalse(cpu.getCarryFlag()); // m < y - assertFalse(cpu.getZeroFlag()); - assertFalse(cpu.getNegativeFlag()); // m - y > 0 - } - - /* DEC - Decrement Memory Location - $d6 */ - - public void test_DEC() throws MemoryAccessException { - bus.write(0x40, 0x00); - bus.write(0x41, 0x01); - bus.write(0x42, 0x80); - bus.write(0x43, 0xff); - - bus.loadProgram(0xd6, 0x10, // DEC $10,X - 0xd6, 0x11, // DEC $11,X - 0xd6, 0x12, // DEC $12,X - 0xd6, 0x13); // DEC $13,X - - cpu.setXRegister(0x30); - - cpu.step(); - assertEquals(0xff, bus.read(0x40)); - assertFalse(cpu.getZeroFlag()); - assertTrue(cpu.getNegativeFlag()); - - cpu.step(); - assertEquals(0x00, bus.read(0x41)); - assertTrue(cpu.getZeroFlag()); - assertFalse(cpu.getNegativeFlag()); - - cpu.step(); - assertEquals(0x7f, bus.read(0x42)); - assertFalse(cpu.getZeroFlag()); - assertFalse(cpu.getNegativeFlag()); - - cpu.step(); - assertEquals(0xfe, bus.read(0x43)); - assertFalse(cpu.getZeroFlag()); - assertTrue(cpu.getNegativeFlag()); - } - - /* SBC - Subtract with Carry - $f5 */ - - public void test_SBC() throws MemoryAccessException { - bus.write(0x40, 0x01); - - bus.loadProgram(0xa9, 0x00, // LDA #$00 - 0xf5, 0x10); // SBC $10,X - cpu.setXRegister(0x30); - cpu.step(2); - assertEquals(0xfe, cpu.getAccumulator()); - assertTrue(cpu.getNegativeFlag()); - assertFalse(cpu.getOverflowFlag()); - assertFalse(cpu.getZeroFlag()); - assertFalse(cpu.getCarryFlag()); - - cpu.reset(); - bus.loadProgram(0xa9, 0x7f, // LDA #$7f - 0xf5, 0x10); // SBC $10,X - cpu.setXRegister(0x30); - cpu.step(2); - assertEquals(0x7d, cpu.getAccumulator()); - assertFalse(cpu.getNegativeFlag()); - assertFalse(cpu.getOverflowFlag()); - assertFalse(cpu.getZeroFlag()); - assertTrue(cpu.getCarryFlag()); - - cpu.reset(); - bus.loadProgram(0xa9, 0x80, // LDA #$80 - 0xf5, 0x10); // SBC $10,X - cpu.setXRegister(0x30); - cpu.step(2); - assertEquals(0x7e, cpu.getAccumulator()); - assertFalse(cpu.getNegativeFlag()); - assertTrue(cpu.getOverflowFlag()); - assertFalse(cpu.getZeroFlag()); - assertTrue(cpu.getCarryFlag()); - - cpu.reset(); - bus.loadProgram(0xa9, 0xff, // LDA #$ff - 0xf5, 0x10); // SBC $10,X - cpu.setXRegister(0x30); - cpu.step(2); - assertEquals(0xfd, cpu.getAccumulator()); - assertTrue(cpu.getNegativeFlag()); - assertFalse(cpu.getOverflowFlag()); - assertFalse(cpu.getZeroFlag()); - assertTrue(cpu.getCarryFlag()); - - cpu.reset(); - bus.loadProgram(0xa9, 0x02, // LDA #$02 - 0xf5, 0x10); // SBC $10,X - cpu.setXRegister(0x30); - cpu.step(2); - assertEquals(0x00, cpu.getAccumulator()); - assertFalse(cpu.getNegativeFlag()); - assertFalse(cpu.getOverflowFlag()); - assertTrue(cpu.getZeroFlag()); - assertTrue(cpu.getCarryFlag()); - } - - public void test_SBC_IncludesNotOfCarry() throws MemoryAccessException { - bus.write(0x40, 0x01); - - // Subtrace with Carry Flag cleared - bus.loadProgram(0x18, // CLC - 0xa9, 0x05, // LDA #$00 - 0xf5, 0x10); // SBC $10,X - cpu.setXRegister(0x30); - cpu.step(3); - assertEquals(0x03, cpu.getAccumulator()); - - cpu.reset(); - - // Subtrace with Carry Flag cleared - bus.loadProgram(0x18, // CLC - 0xa9, 0x00, // LDA #$00 - 0xf5, 0x10); // SBC $10,X - cpu.setXRegister(0x30); - cpu.step(3); - assertEquals(0xfe, cpu.getAccumulator()); - - cpu.reset(); - - // Subtract with Carry Flag set - bus.loadProgram(0x38, // SEC - 0xa9, 0x05, // LDA #$00 - 0xf5, 0x10); // SBC $10,X - cpu.setXRegister(0x30); - 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 - 0xf5, 0x10); // SBC $10,X - cpu.setXRegister(0x30); - cpu.step(3); - assertEquals(0xff, cpu.getAccumulator()); - assertFalse(cpu.getCarryFlag()); - - } - - public void test_SBC_DecimalMode() throws MemoryAccessException { - bus.write(0x40, 0x01); - bus.write(0x50, 0x11); - - bus.loadProgram(0xf8, - 0xa9, 0x00, - 0xf5, 0x10); - cpu.setXRegister(0x30); - 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, - 0xf5, 0x10); - cpu.setXRegister(0x30); - 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, - 0xf5, 0x10); - cpu.setXRegister(0x30); - 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 - 0xf5, 0x10); // SBC $10 - cpu.setXRegister(0x30); - 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 - 0xf5, 0x20); // SBC $20 - cpu.setXRegister(0x30); - 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 - 0xf5, 0x10); // SBC $10 - cpu.setXRegister(0x30); - 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 - 0xf5, 0x10); // SBC $10 - cpu.setXRegister(0x30); - cpu.step(4); - assertEquals(0x99, cpu.getAccumulator()); - assertFalse(cpu.getCarryFlag()); - assertFalse(cpu.getNegativeFlag()); - assertFalse(cpu.getOverflowFlag()); - assertFalse(cpu.getZeroFlag()); - assertTrue(cpu.getDecimalModeFlag()); - } - - /* INC - Increment Memory Location - $f6 */ - - public void test_INC() throws MemoryAccessException { - bus.write(0x30, 0x00); - bus.write(0x31, 0x7f); - bus.write(0x32, 0xff); - - cpu.setXRegister(0x20); - - bus.loadProgram(0xf6, 0x10, // INC $10,X - 0xf6, 0x11, // INC $11,X - 0xf6, 0x12); // INC $12,X - - cpu.step(); - assertEquals(0x01, bus.read(0x30)); - assertFalse(cpu.getZeroFlag()); - assertFalse(cpu.getNegativeFlag()); - - cpu.step(); - assertEquals(0x80, bus.read(0x31)); - assertFalse(cpu.getZeroFlag()); - assertTrue(cpu.getNegativeFlag()); - - cpu.step(); - assertEquals(0x00, bus.read(0x32)); - assertTrue(cpu.getZeroFlag()); - assertFalse(cpu.getNegativeFlag()); - } + protected Cpu cpu; + protected Bus bus; + protected Memory mem; + + protected void setUp() throws Exception { + this.cpu = new Cpu(); + this.bus = new Bus(0x0000, 0xffff); + this.mem = new Memory(0x0000, 0x10000); + bus.addCpu(cpu); + bus.addDevice(mem); + + // Load the reset vector. + bus.write(0xfffc, Cpu.DEFAULT_BASE_ADDRESS & 0x00ff); + 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 - $15 + * ASL - $16 + * AND - $35 + * ROL - $36 + * EOR - $55 + * + * LSR - $56 + * ADC - $75 + * ROR - $76 + * STY - $94 + * STA - $95 + * + * LDY - $b4 + * LDA - $b5 + * CMP - $d5 + * DEC - $d6 + * SBC - $f5 + * + * INC - $f6 + */ + + /* ORA - Logical Inclusive OR - $15 */ + + public void test_ORA() throws MemoryAccessException { + // Set some initial values in zero page. + bus.write(0x30, 0x00); + bus.write(0x32, 0x11); + bus.write(0x34, 0x22); + bus.write(0x38, 0x44); + bus.write(0x40, 0x88); + bus.write(0x02, 0x88); + + // Set offset in X register. + cpu.setXRegister(0x30); + + bus.loadProgram(0x15, 0x00, // ORA $00,X + 0x15, 0x02, // ORA $02,X + 0x15, 0x04, // ORA $04,X + 0x15, 0x08, // ORA $08,X + 0x15, 0x10, // ORA $10,X + 0xa9, 0x00, // LDA #$00 + 0x15, 0xd2); // ORA $d2,X - should wrap around + + 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()); + + // Should wrap around and ORA with value in 0x02 + cpu.step(2); + assertEquals(0x88, cpu.getAccumulator()); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getNegativeFlag()); + } + + /* ASL - Arithmetic Shift Left - $16 */ + + public void test_ASL() throws MemoryAccessException { + bus.write(0x30, 0x00); + bus.write(0x31, 0x01); + bus.write(0x32, 0x02); + bus.write(0x33, 0x44); + bus.write(0x34, 0x80); + bus.write(0x02, 0x01); + + // Set offset in X register. + cpu.setXRegister(0x30); + + bus.loadProgram(0x16, 0x00, // ASL $00,X + 0x16, 0x01, // ASL $01,X + 0x16, 0x02, // ASL $02,X + 0x16, 0x03, // ASL $03,X + 0x16, 0x04, // ASL $04,X + 0x16, 0xd2); // ASL $d2,X + + cpu.step(); + assertEquals(0x00, bus.read(0x30)); + assertTrue(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.step(); + assertEquals(0x02, bus.read(0x31)); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.step(); + assertEquals(0x04, bus.read(0x32)); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.step(); + assertEquals(0x88, bus.read(0x33)); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getNegativeFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.step(); + assertEquals(0x00, bus.read(0x34)); + assertTrue(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + assertTrue(cpu.getCarryFlag()); + + // Should wrap around, d2 + 30 = 02 + cpu.step(); + assertEquals(0x02, bus.read(0x02)); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getCarryFlag()); + } + + /* AND - Logical AND - $35 */ + + public void test_AND() throws MemoryAccessException { + bus.write(0x30, 0x00); + bus.write(0x31, 0x11); + bus.write(0x32, 0xff); + bus.write(0x33, 0x99); + bus.write(0x34, 0x11); + bus.write(0x35, 0x0f); + bus.write(0x02, 0x11); + + // Set offset in X register. + cpu.setXRegister(0x30); + + bus.loadProgram(0x35, 0x00, // AND $00 + 0x35, 0x01, // AND $01,X + 0xa9, 0xaa, // LDA #$aa + 0x35, 0x02, // AND $02,X + 0x35, 0x03, // AND $03 + 0x35, 0x04, // AND $04,X + 0xa9, 0xff, // LDA #$ff + 0x35, 0x05, // AND $05,X + 0xa9, 0x01, // LDA #$01 + 0x35, 0xd2); // AND $d2,X + cpu.step(); + assertEquals(0x00, cpu.getAccumulator()); + assertTrue(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + + cpu.step(); + assertEquals(0x00, cpu.getAccumulator()); + assertTrue(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + + cpu.step(2); + assertEquals(0xaa, cpu.getAccumulator()); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getNegativeFlag()); + + cpu.step(); + assertEquals(0x88, cpu.getAccumulator()); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getNegativeFlag()); + + cpu.step(); + assertEquals(0x00, cpu.getAccumulator()); + assertTrue(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + + cpu.step(2); + assertEquals(0x0f, cpu.getAccumulator()); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + + cpu.step(2); + assertEquals(0x01, cpu.getAccumulator()); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + } + + /* ROL - Rotate Shift Left - $36 */ + + public void test_ROL() throws MemoryAccessException { + + bus.write(0x70, 0x00); + bus.write(0x71, 0x01); + + // Set offset in X register + cpu.setXRegister(0x70); + + bus.loadProgram(0x36, 0x00, // ROL $00,X (m=%00000000, c=0) + 0x36, 0x01, // ROL $01,X (m=%00000010, c=0) + 0x38, // SEC (m=%00000010, c=1) + 0x36, 0x01, // ROL $01,X (m=%00000101, c=0) + 0x36, 0x01, // ROL $01,X (m=%00001010, c=0) + 0x36, 0x01, // ROL $01,X (m=%00010100, c=0) + 0x36, 0x01, // ROL $01,X (m=%00101000, c=0) + 0x36, 0x01, // ROL $01,X (m=%01010000, c=0) + 0x36, 0x01, // ROL $01,X (m=%10100000, c=0) + 0x36, 0x01, // ROL $01,X (m=%01000000, c=1) + 0x36, 0x01); // ROL $01,X (m=%10000001, c=0) + + cpu.step(); + assertEquals(0x00, bus.read(0x70)); + assertTrue(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.step(); + assertEquals(0x02, bus.read(0x71)); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.step(2); + assertEquals(0x05, bus.read(0x71)); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.step(); + assertEquals(0x0a, bus.read(0x71)); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.step(); + assertEquals(0x14, bus.read(0x71)); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.step(); + assertEquals(0x28, bus.read(0x71)); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.step(); + assertEquals(0x50, bus.read(0x71)); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.step(); + assertEquals(0xa0, bus.read(0x71)); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getNegativeFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.step(); + assertEquals(0x40, bus.read(0x71)); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + assertTrue(cpu.getCarryFlag()); + + cpu.step(); + assertEquals(0x81, bus.read(0x71)); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getNegativeFlag()); + assertFalse(cpu.getCarryFlag()); + } + + /* EOR - Exclusive OR - $55 */ + + public void test_EOR() throws MemoryAccessException { + bus.write(0x40, 0x00); + bus.write(0x41, 0xff); + bus.write(0x42, 0x33); + bus.write(0x43, 0x44); + + cpu.setXRegister(0x30); + + bus.loadProgram(0xa9, 0x88, // LDA #$88 + 0x55, 0x10, // EOR $10,X + 0x55, 0x11, // EOR $11,X + 0x55, 0x12, // EOR $12,X + 0x55, 0x13); // EOR $13,X + cpu.step(2); + assertEquals(0x88, cpu.getAccumulator()); + assertTrue(cpu.getNegativeFlag()); + assertFalse(cpu.getZeroFlag()); + + cpu.step(); + assertEquals(0x77, cpu.getAccumulator()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getZeroFlag()); + + cpu.step(); + assertEquals(0x44, cpu.getAccumulator()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getZeroFlag()); + + cpu.step(); + assertEquals(0x00, cpu.getAccumulator()); + assertFalse(cpu.getNegativeFlag()); + assertTrue(cpu.getZeroFlag()); + } + + /* LSR - Logical Shift Right - $56 */ + + public void test_LSR() throws MemoryAccessException { + bus.write(0x30, 0x00); + bus.write(0x31, 0x01); + bus.write(0x32, 0x02); + bus.write(0x33, 0x44); + bus.write(0x34, 0x80); + bus.write(0x35, 0x02); + + cpu.setXRegister(0x30); + + bus.loadProgram(0x56, 0x00, // LSR $00,X + 0x56, 0x01, // LSR $01,X + 0x56, 0x02, // LSR $02,X + 0x56, 0x03, // LSR $03,X + 0x56, 0x04, // LSR $04,X + 0x38, // SEC + 0x56, 0x05); // LSR $05,X + + cpu.step(); + assertEquals(0x00, bus.read(0x30)); + assertTrue(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.step(); + assertEquals(0x00, bus.read(0x31)); + assertTrue(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + assertTrue(cpu.getCarryFlag()); + + cpu.step(); + assertEquals(0x01, bus.read(0x32)); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.step(); + assertEquals(0x22, bus.read(0x33)); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.step(); + assertEquals(0x40, bus.read(0x34)); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getCarryFlag()); + + // Setting Carry should not affect the result. + cpu.step(2); + assertEquals(0x01, bus.read(0x35)); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getCarryFlag()); + } + + /* ADC - Add with Carry - $75 */ + + public void test_ADC() throws MemoryAccessException { + bus.write(0x40, 0x01); + bus.write(0x41, 0xff); + + cpu.setXRegister(0x30); + + bus.loadProgram(0xa9, 0x00, // LDA #$00 + 0x75, 0x10); // ADC $10,X + cpu.step(2); + assertEquals(0x01, cpu.getAccumulator()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.reset(); + cpu.setXRegister(0x30); + + bus.loadProgram(0xa9, 0x7f, // LDA #$7f + 0x75, 0x10); // ADC $10,X + cpu.step(2); + assertEquals(0x80, cpu.getAccumulator()); + assertTrue(cpu.getNegativeFlag()); + assertTrue(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.reset(); + cpu.setXRegister(0x30); + + bus.loadProgram(0xa9, 0x80, // LDA #$80 + 0x75, 0x10); // ADC $10,X + cpu.step(2); + assertEquals(0x81, cpu.getAccumulator()); + assertTrue(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.reset(); + cpu.setXRegister(0x30); + + bus.loadProgram(0xa9, 0xff, // LDA #$ff + 0x75, 0x10); // ADC $10,X + cpu.step(2); + assertEquals(0x00, cpu.getAccumulator()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertTrue(cpu.getZeroFlag()); + assertTrue(cpu.getCarryFlag()); + + cpu.reset(); + cpu.setXRegister(0x30); + + bus.loadProgram(0xa9, 0x00, // LDA #$00 + 0x75, 0x11); // ADC $11,X + cpu.step(2); + assertEquals(0xff, cpu.getAccumulator()); + assertTrue(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.reset(); + cpu.setXRegister(0x30); + + bus.loadProgram(0xa9, 0x7f, // LDA #$7f + 0x75, 0x11); // ADC $11,X + cpu.step(2); + assertEquals(0x7e, cpu.getAccumulator()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getCarryFlag()); + + cpu.reset(); + cpu.setXRegister(0x30); + + bus.loadProgram(0xa9, 0x80, // LDA #$80 + 0x75, 0x11); // ADC $11,X + cpu.step(2); + assertEquals(0x7f, cpu.getAccumulator()); + assertFalse(cpu.getNegativeFlag()); + assertTrue(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getCarryFlag()); + + cpu.reset(); + cpu.setXRegister(0x30); + + bus.loadProgram(0xa9, 0xff, // LDA #$ff + 0x75, 0x11); // ADC $11,X + cpu.step(2); + assertEquals(0xfe, cpu.getAccumulator()); + assertTrue(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getCarryFlag()); + } + + public void test_ADC_IncludesCarry() throws MemoryAccessException { + bus.write(0x40, 0x01); + + bus.loadProgram(0xa9, 0x00, // LDA #$00 + 0x38, // SEC + 0x75, 0x10); // ADC $10,X + + cpu.setXRegister(0x30); + + cpu.step(3); + assertEquals(0x02, cpu.getAccumulator()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getCarryFlag()); + } + + public void test_ADC_DecimalMode() throws MemoryAccessException { + bus.write(0x40, 0x01); + bus.write(0x41, 0x99); + + bus.loadProgram(0xf8, // SED + 0xa9, 0x01, // LDA #$01 + 0x75, 0x10); // ADC $10,X + + cpu.setXRegister(0x30); + + cpu.step(3); + assertEquals(0x02, cpu.getAccumulator()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.reset(); + cpu.setXRegister(0x30); + + bus.loadProgram(0xf8, // SED + 0xa9, 0x49, // LDA #$49 + 0x75, 0x10); // ADC $10,X + cpu.step(3); + assertEquals(0x50, cpu.getAccumulator()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.reset(); + cpu.setXRegister(0x30); + + bus.loadProgram(0xf8, // SED + 0xa9, 0x50, // LDA #$50 + 0x75, 0x10); // ADC $10,X + cpu.step(3); + assertEquals(0x51, cpu.getAccumulator()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.reset(); + cpu.setXRegister(0x30); + + bus.loadProgram(0xf8, // SED + 0xa9, 0x99, // LDA #$99 + 0x75, 0x10); // ADC $10,X + cpu.step(3); + assertEquals(0x00, cpu.getAccumulator()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertTrue(cpu.getZeroFlag()); + assertTrue(cpu.getCarryFlag()); + + cpu.reset(); + cpu.setXRegister(0x30); + + bus.loadProgram(0xf8, // SED + 0xa9, 0x00, // LDA #$00 + 0x75, 0x11); // ADC $10,X + cpu.step(3); + assertEquals(0x99, cpu.getAccumulator()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.reset(); + cpu.setXRegister(0x30); + + bus.loadProgram(0xf8, // SED + 0xa9, 0x49, // LDA #$49 + 0x75, 0x11); // ADC $11,X + cpu.step(3); + assertEquals(0x48, cpu.getAccumulator()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getCarryFlag()); + + cpu.reset(); + cpu.setXRegister(0x30); + + bus.loadProgram(0xf8, // SED + 0xa9, 0x50, // LDA #$59 + 0x75, 0x11); // ADC $11,X + cpu.step(3); + assertEquals(0x49, cpu.getAccumulator()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getCarryFlag()); + } + + /* ROR - Rotate Right - $76 */ + + public void test_ROR() throws MemoryAccessException { + + bus.write(0x40, 0x00); + bus.write(0x41, 0x10); + + bus.loadProgram(0x76, 0x10, // ROR $00 (m=%00000000, c=0) + 0x76, 0x11, // ROR $01 (m=%00001000, c=0) + 0x76, 0x11, // ROR $01 (m=%00000100, c=0) + 0x76, 0x11, // ROR $01 (m=%00000010, c=0) + 0x76, 0x11, // ROR $01 (m=%00000001, c=0) + 0x76, 0x11, // ROR $01 (m=%00000000, c=1) + 0x76, 0x11, // ROR $01 (m=%10000000, c=0) + 0x76, 0x11, // ROR $01 (m=%01000000, c=0) + 0x76, 0x11, // ROR $01 (m=%00100000, c=0) + 0x76, 0x11); // ROR $01 (m=%00010000, c=0) + + cpu.setXRegister(0x30); + + cpu.step(); + assertEquals(0x00, bus.read(0x40)); + assertTrue(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.step(); + assertEquals(0x08, bus.read(0x41)); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.step(); + assertEquals(0x04, bus.read(0x41)); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.step(); + assertEquals(0x02, bus.read(0x41)); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.step(); + assertEquals(0x01, bus.read(0x41)); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.step(); + assertEquals(0x00, bus.read(0x41)); + assertTrue(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + assertTrue(cpu.getCarryFlag()); + + cpu.step(); + assertEquals(0x80, bus.read(0x41)); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getNegativeFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.step(); + assertEquals(0x40, bus.read(0x41)); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.step(); + assertEquals(0x20, bus.read(0x41)); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.step(); + assertEquals(0x10, bus.read(0x41)); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getCarryFlag()); + } + + /* STY - Store Y Register - $94 */ + + public void test_STY() throws MemoryAccessException { + cpu.setXRegister(0x30); + cpu.setYRegister(0x00); + bus.loadProgram(0x94, 0x10); // STY $10,X + cpu.step(); + assertEquals(0x00, bus.read(0x40)); + assertTrue(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + + cpu.reset(); + + cpu.setXRegister(0x30); + cpu.setYRegister(0x0f); + bus.loadProgram(0x94, 0x10); // STY $10,X + cpu.step(); + assertEquals(0x0f, bus.read(0x40)); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + + cpu.reset(); + + cpu.setXRegister(0x30); + cpu.setYRegister(0x80); + bus.loadProgram(0x94, 0x10); // STY $10,X + cpu.step(); + assertEquals(0x80, bus.read(0x40)); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getNegativeFlag()); + } + + /* STA - Store Accumulator - $95 */ + + public void test_STA() throws MemoryAccessException { + cpu.setXRegister(0x30); + + cpu.setAccumulator(0x00); + bus.loadProgram(0x95, 0x10); // STA $10,X + cpu.step(); + assertEquals(0x00, bus.read(0x40)); + assertTrue(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + + cpu.reset(); + cpu.setXRegister(0x30); + + cpu.setAccumulator(0x0f); + bus.loadProgram(0x95, 0x10); // STA $10,X + cpu.step(); + assertEquals(0x0f, bus.read(0x40)); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + + cpu.reset(); + cpu.setXRegister(0x30); + + cpu.setAccumulator(0x80); + bus.loadProgram(0x95, 0x10); // STA $10,X + cpu.step(); + assertEquals(0x80, bus.read(0x40)); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getNegativeFlag()); + } + + /* LDY - Load Y Register - $b4 */ + + public void test_LDY() throws MemoryAccessException { + bus.write(0x45, 0x00); + bus.write(0x46, 0x0f); + bus.write(0x47, 0x80); + + bus.loadProgram(0xb4, 0x10, // LDY $10,X + 0xb4, 0x11, // LDY $11,X + 0xb4, 0x12); // LDY $12,X + + cpu.setXRegister(0x35); + + cpu.step(); + assertEquals(0x00, cpu.getYRegister()); + assertTrue(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + + cpu.step(); + assertEquals(0x0f, cpu.getYRegister()); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + + cpu.step(); + assertEquals(0x80, cpu.getYRegister()); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getNegativeFlag()); + } + + /* LDA - Load Accumulator - $b5 */ + + public void test_LDA() throws MemoryAccessException { + bus.write(0x42, 0x00); + bus.write(0x43, 0x0f); + bus.write(0x44, 0x80); + + bus.loadProgram(0xb5, 0x10, // LDA $10,X + 0xb5, 0x11, // LDA $11,X + 0xb5, 0x12); // LDA $12,X + + cpu.setXRegister(0x32); + + cpu.step(); + assertEquals(0x00, cpu.getAccumulator()); + assertTrue(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + + cpu.step(); + assertEquals(0x0f, cpu.getAccumulator()); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + + cpu.step(); + assertEquals(0x80, cpu.getAccumulator()); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getNegativeFlag()); + } + + /* CMP - Compare Accumulator - $d5 */ + + public void test_CMP() throws MemoryAccessException { + bus.write(0x40, 0x00); + bus.write(0x41, 0x80); + bus.write(0x42, 0xff); + + cpu.setAccumulator(0x80); + + bus.loadProgram(0xd5, 0x10, + 0xd5, 0x11, + 0xd5, 0x12); + + cpu.setXRegister(0x30); + + cpu.step(); + assertTrue(cpu.getCarryFlag()); // m > y + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getNegativeFlag()); // m - y < 0 + + cpu.step(); + assertTrue(cpu.getCarryFlag()); // m = y + assertTrue(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); // m - y == 0 + + cpu.step(); + assertFalse(cpu.getCarryFlag()); // m < y + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); // m - y > 0 + } + + /* DEC - Decrement Memory Location - $d6 */ + + public void test_DEC() throws MemoryAccessException { + bus.write(0x40, 0x00); + bus.write(0x41, 0x01); + bus.write(0x42, 0x80); + bus.write(0x43, 0xff); + + bus.loadProgram(0xd6, 0x10, // DEC $10,X + 0xd6, 0x11, // DEC $11,X + 0xd6, 0x12, // DEC $12,X + 0xd6, 0x13); // DEC $13,X + + cpu.setXRegister(0x30); + + cpu.step(); + assertEquals(0xff, bus.read(0x40)); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getNegativeFlag()); + + cpu.step(); + assertEquals(0x00, bus.read(0x41)); + assertTrue(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + + cpu.step(); + assertEquals(0x7f, bus.read(0x42)); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + + cpu.step(); + assertEquals(0xfe, bus.read(0x43)); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getNegativeFlag()); + } + + /* SBC - Subtract with Carry - $f5 */ + + public void test_SBC() throws MemoryAccessException { + bus.write(0x40, 0x01); + + bus.loadProgram(0xa9, 0x00, // LDA #$00 + 0xf5, 0x10); // SBC $10,X + cpu.setXRegister(0x30); + cpu.step(2); + assertEquals(0xfe, cpu.getAccumulator()); + assertTrue(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.reset(); + bus.loadProgram(0xa9, 0x7f, // LDA #$7f + 0xf5, 0x10); // SBC $10,X + cpu.setXRegister(0x30); + cpu.step(2); + assertEquals(0x7d, cpu.getAccumulator()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getCarryFlag()); + + cpu.reset(); + bus.loadProgram(0xa9, 0x80, // LDA #$80 + 0xf5, 0x10); // SBC $10,X + cpu.setXRegister(0x30); + cpu.step(2); + assertEquals(0x7e, cpu.getAccumulator()); + assertFalse(cpu.getNegativeFlag()); + assertTrue(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getCarryFlag()); + + cpu.reset(); + bus.loadProgram(0xa9, 0xff, // LDA #$ff + 0xf5, 0x10); // SBC $10,X + cpu.setXRegister(0x30); + cpu.step(2); + assertEquals(0xfd, cpu.getAccumulator()); + assertTrue(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getCarryFlag()); + + cpu.reset(); + bus.loadProgram(0xa9, 0x02, // LDA #$02 + 0xf5, 0x10); // SBC $10,X + cpu.setXRegister(0x30); + cpu.step(2); + assertEquals(0x00, cpu.getAccumulator()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertTrue(cpu.getZeroFlag()); + assertTrue(cpu.getCarryFlag()); + } + + public void test_SBC_IncludesNotOfCarry() throws MemoryAccessException { + bus.write(0x40, 0x01); + + // Subtrace with Carry Flag cleared + bus.loadProgram(0x18, // CLC + 0xa9, 0x05, // LDA #$00 + 0xf5, 0x10); // SBC $10,X + cpu.setXRegister(0x30); + cpu.step(3); + assertEquals(0x03, cpu.getAccumulator()); + + cpu.reset(); + + // Subtrace with Carry Flag cleared + bus.loadProgram(0x18, // CLC + 0xa9, 0x00, // LDA #$00 + 0xf5, 0x10); // SBC $10,X + cpu.setXRegister(0x30); + cpu.step(3); + assertEquals(0xfe, cpu.getAccumulator()); + + cpu.reset(); + + // Subtract with Carry Flag set + bus.loadProgram(0x38, // SEC + 0xa9, 0x05, // LDA #$00 + 0xf5, 0x10); // SBC $10,X + cpu.setXRegister(0x30); + 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 + 0xf5, 0x10); // SBC $10,X + cpu.setXRegister(0x30); + cpu.step(3); + assertEquals(0xff, cpu.getAccumulator()); + assertFalse(cpu.getCarryFlag()); + + } + + public void test_SBC_DecimalMode() throws MemoryAccessException { + bus.write(0x40, 0x01); + bus.write(0x50, 0x11); + + bus.loadProgram(0xf8, + 0xa9, 0x00, + 0xf5, 0x10); + cpu.setXRegister(0x30); + 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, + 0xf5, 0x10); + cpu.setXRegister(0x30); + 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, + 0xf5, 0x10); + cpu.setXRegister(0x30); + 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 + 0xf5, 0x10); // SBC $10 + cpu.setXRegister(0x30); + 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 + 0xf5, 0x20); // SBC $20 + cpu.setXRegister(0x30); + 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 + 0xf5, 0x10); // SBC $10 + cpu.setXRegister(0x30); + 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 + 0xf5, 0x10); // SBC $10 + cpu.setXRegister(0x30); + cpu.step(4); + assertEquals(0x99, cpu.getAccumulator()); + assertFalse(cpu.getCarryFlag()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getDecimalModeFlag()); + } + + /* INC - Increment Memory Location - $f6 */ + + public void test_INC() throws MemoryAccessException { + bus.write(0x30, 0x00); + bus.write(0x31, 0x7f); + bus.write(0x32, 0xff); + + cpu.setXRegister(0x20); + + bus.loadProgram(0xf6, 0x10, // INC $10,X + 0xf6, 0x11, // INC $11,X + 0xf6, 0x12); // INC $12,X + + cpu.step(); + assertEquals(0x01, bus.read(0x30)); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + + cpu.step(); + assertEquals(0x80, bus.read(0x31)); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getNegativeFlag()); + + cpu.step(); + assertEquals(0x00, bus.read(0x32)); + assertTrue(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + } }