Process Status Register bits have been added.
This commit is contained in:
1 parent
7e36444193
commit
59e5572039
2 files changed
+209
-6
No files matched your search
@@ -1,5 +1,7 @@
|
|||||||
package com.loomcom.lm6502;
|
package com.loomcom.lm6502;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Main 6502 CPU Simulation.
|
* Main 6502 CPU Simulation.
|
||||||
*/
|
*/
|
||||||
@@ -22,12 +24,20 @@ public class Cpu implements InstructionTable {
|
|||||||
private int[] operands = new int[2];
|
private int[] operands = new int[2];
|
||||||
private int addr; // The address the most recent instruction
|
private int addr; // The address the most recent instruction
|
||||||
// was fetched from
|
// 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.
|
* Construct a new CPU.
|
||||||
*/
|
*/
|
||||||
public Cpu() {
|
public Cpu() {}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the bus reference for this CPU.
|
* Set the bus reference for this CPU.
|
||||||
@@ -55,6 +65,13 @@ public class Cpu implements InstructionTable {
|
|||||||
|
|
||||||
// Clear instruction register.
|
// Clear instruction register.
|
||||||
ir = 0;
|
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.
|
* 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("A=" + String.format("$%02X", a) + "; ");
|
||||||
sb.append("X=" + String.format("$%02X", x) + "; ");
|
sb.append("X=" + String.format("$%02X", x) + "; ");
|
||||||
sb.append("Y=" + String.format("$%02X", y) + "; ");
|
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();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ public class Profiler implements InstructionTable {
|
|||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
// new Profiler().profileMemoryReads();
|
// new Profiler().profileMemoryReads();
|
||||||
|
// new Profiler().dumpOpCodes();
|
||||||
new Profiler().dumpOpCodes();
|
new Profiler().profileProgram();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void dumpOpCodes() {
|
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() {
|
public void profileMemoryReads() {
|
||||||
// Create a bus.
|
// Create a bus.
|
||||||
Bus b = new Bus(0, 65535);
|
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(0xc000, 0x2000)); // 8KB @ $c000-$dfff
|
||||||
b.addDevice(new Memory(0xe000, 0x2000)); // 8KB @ $e000-$ffff
|
b.addDevice(new Memory(0xe000, 0x2000)); // 8KB @ $e000-$ffff
|
||||||
} catch (MemoryRangeException ex) {
|
} catch (MemoryRangeException ex) {
|
||||||
System.out.println("Memory Range Exception! " + ex.getMessage());
|
System.err.println("Memory Range Exception! " + ex.getMessage());
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read memory
|
// Read memory
|
||||||
|
|||||||
Reference in new issue
Block a user