From 59e557203929a80d59c21f071d46096668127f89 Mon Sep 17 00:00:00 2001 From: sethm Date: Sat, 13 Dec 2008 00:50:14 -0800 Subject: [PATCH] Process Status Register bits have been added. --- src/main/java/com/loomcom/lm6502/Cpu.java | 131 +++++++++++++++++- .../java/com/loomcom/lm6502/Profiler.java | 84 ++++++++++- 2 files changed, 209 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/loomcom/lm6502/Cpu.java b/src/main/java/com/loomcom/lm6502/Cpu.java index e0b4637..f992c93 100644 --- a/src/main/java/com/loomcom/lm6502/Cpu.java +++ b/src/main/java/com/loomcom/lm6502/Cpu.java @@ -1,5 +1,7 @@ package com.loomcom.lm6502; +import java.util.Arrays; + /** * Main 6502 CPU Simulation. */ @@ -22,12 +24,20 @@ public class Cpu implements InstructionTable { private int[] operands = new int[2]; private int addr; // The address the most recent instruction // was fetched from + + /* Status Flag Register bits */ + private boolean carryFlag; + private boolean zeroFlag; + private boolean irqDisableFlag; + private boolean decimalModeFlag; + private boolean breakFlag; + private boolean overflowFlag; + // Note: Zero Flag and Negative Flag are read directly from Accumulator. /** * Construct a new CPU. */ - public Cpu() { - } + public Cpu() {} /** * Set the bus reference for this CPU. @@ -55,6 +65,13 @@ public class Cpu implements InstructionTable { // Clear instruction register. ir = 0; + + // Clear status register bits. + carryFlag = false; + irqDisableFlag = false; + decimalModeFlag = false; + breakFlag = false; + overflowFlag = false; } /** @@ -622,6 +639,113 @@ public class Cpu implements InstructionTable { } } + /** + * @return the negative flag + */ + public boolean getNegativeFlag() { + // True if the most significant bit is '1' + return ((a>>>7)&0xff) == 1; + } + + /** + * @return the carry flag + */ + public boolean getCarryFlag() { + return carryFlag; + } + + /** + * @param carryFlag the carry flag to set + */ + public void setCarryFlag(boolean carryFlag) { + this.carryFlag = carryFlag; + } + + /** + * @return the zero flag + */ + public boolean getZeroFlag() { + return zeroFlag; + } + + /** + * @param zeroFlag the zero flag to set + */ + public void setZeroFlag(boolean zeroFlag) { + this.zeroFlag = zeroFlag; + } + + /** + * @return the irq disable flag + */ + public boolean getIrqDisableFlag() { + return irqDisableFlag; + } + + /** + * @param irqDisableFlag the irq disable flag to set + */ + public void setIrqDisableFlag(boolean irqDisableFlag) { + this.irqDisableFlag = irqDisableFlag; + } + + /** + * @return the decimal mode flag + */ + public boolean getDecimalModeFlag() { + return decimalModeFlag; + } + + /** + * @param decimalModeFlag the decimal mde flag to set + */ + public void setDecimalModeFlag(boolean decimalModeFlag) { + this.decimalModeFlag = decimalModeFlag; + } + + /** + * @return the break flag + */ + public boolean getBreakFlag() { + return breakFlag; + } + + /** + * @param breakFlag the break flag to set + */ + public void setBreakFlag(boolean breakFlag) { + this.breakFlag = breakFlag; + } + + /** + * @return the overflow flag + */ + public boolean getOverflowFlag() { + return overflowFlag; + } + + /** + * @param overflowFlag the overflow flag to set + */ + public void setOverflowFlag(boolean overflowFlag) { + this.overflowFlag = overflowFlag; + } + + /** + * @return A string representing the current status register state. + */ + public String statusRegisterString() { + StringBuffer sb = new StringBuffer(); + sb.append("(N:" + (getNegativeFlag() ? '1' : '0') + ", "); + sb.append("V:" + (getOverflowFlag() ? '1' : '0') + ", "); + sb.append("B:" + (getBreakFlag() ? '1' : '0') + ", "); + sb.append("D:" + (getDecimalModeFlag() ? '1' : '0') + ", "); + sb.append("I:" + (getIrqDisableFlag() ? '1' : '0') + ", "); + sb.append("Z:" + (getZeroFlag() ? '1' : '0') + ", "); + sb.append("C:" + (getCarryFlag() ? '1' : '0') + ")"); + return sb.toString(); + } + /** * Returns a string representing the CPU state. */ @@ -632,7 +756,8 @@ public class Cpu implements InstructionTable { sb.append("A=" + String.format("$%02X", a) + "; "); sb.append("X=" + String.format("$%02X", x) + "; "); sb.append("Y=" + String.format("$%02X", y) + "; "); - sb.append("PC=" + String.format("$%04X", pc)); + sb.append("PC=" + String.format("$%04X", pc)+ "; "); + sb.append("P=" + statusRegisterString()); return sb.toString(); } diff --git a/src/main/java/com/loomcom/lm6502/Profiler.java b/src/main/java/com/loomcom/lm6502/Profiler.java index 156c3f2..e1d257f 100644 --- a/src/main/java/com/loomcom/lm6502/Profiler.java +++ b/src/main/java/com/loomcom/lm6502/Profiler.java @@ -13,8 +13,8 @@ public class Profiler implements InstructionTable { public static void main(String[] args) { // new Profiler().profileMemoryReads(); - - new Profiler().dumpOpCodes(); + // new Profiler().dumpOpCodes(); + new Profiler().profileProgram(); } public void dumpOpCodes() { @@ -32,6 +32,83 @@ public class Profiler implements InstructionTable { } } + public void profileProgram() { + Bus bus = new Bus(0, 65535); + Cpu cpu = new Cpu(); + + bus.addCpu(cpu); + + try { + bus.addDevice(new Memory(0x0000, 0x10000)); + } catch (MemoryRangeException ex) { + System.err.println("Memory Range Exception! " + ex.getMessage()); + return; + } + + // Start at 0x0300 + bus.write(0xfffc, 0x00); + bus.write(0xfffd, 0x03); + + // The program to run, in an infinite loop. + bus.write(0x0300, 0xa9); // LDA #$FF + bus.write(0x0301, 0xff); + bus.write(0x0302, 0xea); // NOP + bus.write(0x0303, 0xea); // NOP + bus.write(0x0304, 0xa0); // LDY #$1A + bus.write(0x0305, 0x1a); + bus.write(0x0306, 0xea); // NOP + bus.write(0x0307, 0xea); // NOP + bus.write(0x0308, 0xa2); // LDX #$03 + bus.write(0x0309, 0x03); + + bus.write(0x030a, 0xa9); // LDA #$00 + bus.write(0x030b, 0x00); + bus.write(0x030c, 0xa2); // LDX #$00 + bus.write(0x030d, 0x00); + bus.write(0x030e, 0xa0); // LDY #$00 + bus.write(0x030f, 0x00); + + bus.write(0x0310, 0x4c); // JMP #$0300 + bus.write(0x0311, 0x00); + bus.write(0x0312, 0x03); + + + long sum = 0; + + // The number of times to run the program + long iters = 1000; + + // The number of steps to take when running the program + long steps = 100000; + + for (int i = 0; i < iters; i++) { + long startTime = System.nanoTime(); + + // Reset the CPU (does not clear memory) + cpu.reset(); + + for (int j = 0; j < steps; j++) { + cpu.step(); + } + + long endTime = System.nanoTime(); + long diff = endTime - startTime; + + sum += diff; + } + + long average = sum / iters; + long totalSteps = steps * iters; + long avgStep = sum / totalSteps; + + System.out.println("Total instructions executed: " + + String.format("%,d", totalSteps)); + System.out.println("Total time taken: " + + String.format("%,d us", sum / 1000)); + System.out.println("Average time per step: " + + avgStep + " ns "); + } + public void profileMemoryReads() { // Create a bus. Bus b = new Bus(0, 65535); @@ -47,7 +124,8 @@ public class Profiler implements InstructionTable { b.addDevice(new Memory(0xc000, 0x2000)); // 8KB @ $c000-$dfff b.addDevice(new Memory(0xe000, 0x2000)); // 8KB @ $e000-$ffff } catch (MemoryRangeException ex) { - System.out.println("Memory Range Exception! " + ex.getMessage()); + System.err.println("Memory Range Exception! " + ex.getMessage()); + return; } // Read memory