Changed CPU static variable to pass by reference -- now possible to have multiple 65c02 instaces at a time.

This commit is contained in:
Brendan Robert 2014-09-17 01:02:38 -05:00
parent e82af529e8
commit b4b95ff88b

View File

@ -31,13 +31,12 @@ import jace.state.Stateful;
* into a core 6502 and a separate extended 65c02 so that undocumented 6502 * into a core 6502 and a separate extended 65c02 so that undocumented 6502
* opcodes could be supported but that's not on the table currently. * opcodes could be supported but that's not on the table currently.
* *
* @author Brendan Robert (BLuRry) brendan.robert@gmail.com * @author Brendan Robert (BLuRry) brendan.robert@gmail.com
*/ */
@Stateful @Stateful
public class MOS65C02 extends CPU { public class MOS65C02 extends CPU {
static public boolean readAddressTriggersEvent = true; public boolean readAddressTriggersEvent = true;
static private MOS65C02 cpu;
static int RESET_VECTOR = 0x00FFFC; static int RESET_VECTOR = 0x00FFFC;
static int INT_VECTOR = 0x00FFFE; static int INT_VECTOR = 0x00FFFE;
@Stateful @Stateful
@ -72,12 +71,13 @@ public class MOS65C02 extends CPU {
private static RAM getMemory() { private static RAM getMemory() {
return Computer.getComputer().getMemory(); return Computer.getComputer().getMemory();
} }
@Override @Override
public void reconfigure() { public void reconfigure() {
} }
public enum OPCODE { public enum OPCODE {
ADC_IMM(0x0069, COMMAND.ADC, MODE.IMMEDIATE, 2), ADC_IMM(0x0069, COMMAND.ADC, MODE.IMMEDIATE, 2),
ADC_ZP(0x0065, COMMAND.ADC, MODE.ZEROPAGE, 3), ADC_ZP(0x0065, COMMAND.ADC, MODE.ZEROPAGE, 3),
ADC_ZP_X(0x0075, COMMAND.ADC, MODE.ZEROPAGE_X, 4), ADC_ZP_X(0x0075, COMMAND.ADC, MODE.ZEROPAGE_X, 4),
@ -316,13 +316,13 @@ public class MOS65C02 extends CPU {
int address = 0; int address = 0;
int value = 0; int value = 0;
private void fetch() { private void fetch(MOS65C02 cpu) {
address = getMode().calculator.calculateAddress(); address = getMode().calculator.calculateAddress(cpu);
value = getMode().calculator.getValue(!command.isStoreOnly()); value = getMode().calculator.getValue(!command.isStoreOnly(), cpu);
} }
public void execute() { public void execute(MOS65C02 cpu) {
command.getProcessor().processCommand(address, value, addressingMode); command.getProcessor().processCommand(address, value, addressingMode, cpu);
} }
private OPCODE(int val, COMMAND c, MODE m, int wait) { private OPCODE(int val, COMMAND c, MODE m, int wait) {
@ -340,64 +340,64 @@ public class MOS65C02 extends CPU {
private static interface AddressCalculator { private static interface AddressCalculator {
abstract int calculateAddress(); abstract int calculateAddress(MOS65C02 cpu);
default int getValue(boolean isRead) { default int getValue(boolean isRead, MOS65C02 cpu) {
int address = calculateAddress(); int address = calculateAddress(cpu);
return (address > -1) ? (0x0ff & getMemory().read(address, TYPE.READ_DATA, isRead, false)) : 0; return (address > -1) ? (0x0ff & getMemory().read(address, TYPE.READ_DATA, isRead, false)) : 0;
} }
} }
private enum MODE { public enum MODE {
IMPLIED(1, "", () -> -1), IMPLIED(1, "", (cpu) -> -1),
// RELATIVE(2, "#$~1 ($R)"), // RELATIVE(2, "#$~1 ($R)"),
RELATIVE(2, "$R", () -> { RELATIVE(2, "$R", (cpu) -> {
int pc = cpu.getProgramCounter(); int pc = cpu.getProgramCounter();
int address = pc + 2 + getMemory().read(pc + 1, TYPE.READ_OPERAND, readAddressTriggersEvent, false); int address = pc + 2 + getMemory().read(pc + 1, TYPE.READ_OPERAND, cpu.readAddressTriggersEvent, false);
// The wait cycles are not added unless the branch actually happens! // The wait cycles are not added unless the branch actually happens!
cpu.setPageBoundaryPenalty((address & 0x00ff00) != (pc & 0x00ff00)); cpu.setPageBoundaryPenalty((address & 0x00ff00) != (pc & 0x00ff00));
return address; return address;
}), }),
IMMEDIATE(2, "#$~1", () -> cpu.getProgramCounter() + 1), IMMEDIATE(2, "#$~1", (cpu) -> cpu.getProgramCounter() + 1),
ZEROPAGE(2, "$~1", () -> getMemory().read(cpu.getProgramCounter() + 1, TYPE.READ_OPERAND, readAddressTriggersEvent, false) & 0x00FF), ZEROPAGE(2, "$~1", (cpu) -> getMemory().read(cpu.getProgramCounter() + 1, TYPE.READ_OPERAND, cpu.readAddressTriggersEvent, false) & 0x00FF),
ZEROPAGE_X(2, "$~1,X", () -> 0x0FF & (getMemory().read(cpu.getProgramCounter() + 1, TYPE.READ_OPERAND, readAddressTriggersEvent, false) + cpu.X)), ZEROPAGE_X(2, "$~1,X", (cpu) -> 0x0FF & (getMemory().read(cpu.getProgramCounter() + 1, TYPE.READ_OPERAND, cpu.readAddressTriggersEvent, false) + cpu.X)),
ZEROPAGE_Y(2, "$~1,Y", () -> 0x0FF & (getMemory().read(cpu.getProgramCounter() + 1, TYPE.READ_OPERAND, readAddressTriggersEvent, false) + cpu.Y)), ZEROPAGE_Y(2, "$~1,Y", (cpu) -> 0x0FF & (getMemory().read(cpu.getProgramCounter() + 1, TYPE.READ_OPERAND, cpu.readAddressTriggersEvent, false) + cpu.Y)),
INDIRECT(3, "$(~2~1)", () -> { INDIRECT(3, "$(~2~1)", (cpu) -> {
int address = getMemory().readWord(cpu.getProgramCounter() + 1, TYPE.READ_OPERAND, readAddressTriggersEvent, false); int address = getMemory().readWord(cpu.getProgramCounter() + 1, TYPE.READ_OPERAND, cpu.readAddressTriggersEvent, false);
return getMemory().readWord(address, TYPE.READ_DATA, true, false); return getMemory().readWord(address, TYPE.READ_DATA, true, false);
}), }),
INDIRECT_X(3, "$(~2~1,X)", () -> { INDIRECT_X(3, "$(~2~1,X)", (cpu) -> {
int address = getMemory().readWord(cpu.getProgramCounter() + 1, TYPE.READ_OPERAND, readAddressTriggersEvent, false) + cpu.X; int address = getMemory().readWord(cpu.getProgramCounter() + 1, TYPE.READ_OPERAND, cpu.readAddressTriggersEvent, false) + cpu.X;
return getMemory().readWord(address & 0x0FFFF, TYPE.READ_DATA, true, false); return getMemory().readWord(address & 0x0FFFF, TYPE.READ_DATA, true, false);
}), }),
INDIRECT_ZP(2, "$(~1)", () -> { INDIRECT_ZP(2, "$(~1)", (cpu) -> {
int address = getMemory().read(cpu.getProgramCounter() + 1, TYPE.READ_OPERAND, readAddressTriggersEvent, false); int address = getMemory().read(cpu.getProgramCounter() + 1, TYPE.READ_OPERAND, cpu.readAddressTriggersEvent, false);
return getMemory().readWord(address & 0x0FF, TYPE.READ_DATA, true, false); return getMemory().readWord(address & 0x0FF, TYPE.READ_DATA, true, false);
}), }),
INDIRECT_ZP_X(2, "$(~1,X)", () -> { INDIRECT_ZP_X(2, "$(~1,X)", (cpu) -> {
int address = getMemory().read(cpu.getProgramCounter() + 1, TYPE.READ_OPERAND, readAddressTriggersEvent, false) + cpu.X; int address = getMemory().read(cpu.getProgramCounter() + 1, TYPE.READ_OPERAND, cpu.readAddressTriggersEvent, false) + cpu.X;
return getMemory().readWord(address & 0x0FF, TYPE.READ_DATA, true, false); return getMemory().readWord(address & 0x0FF, TYPE.READ_DATA, true, false);
}), }),
INDIRECT_ZP_Y(2, "$(~1),Y", () -> { INDIRECT_ZP_Y(2, "$(~1),Y", (cpu) -> {
int address = 0x00FF & getMemory().read(cpu.getProgramCounter() + 1, TYPE.READ_OPERAND, readAddressTriggersEvent, false); int address = 0x00FF & getMemory().read(cpu.getProgramCounter() + 1, TYPE.READ_OPERAND, cpu.readAddressTriggersEvent, false);
address = getMemory().readWord(address, TYPE.READ_DATA, true, false) + cpu.Y; address = getMemory().readWord(address, TYPE.READ_DATA, true, false) + cpu.Y;
if ((address & 0x00ff00) > 0) { if ((address & 0x00ff00) > 0) {
cpu.addWaitCycles(1); cpu.addWaitCycles(1);
} }
return address; return address;
}), }),
ABSOLUTE(3, "$~2~1", () -> getMemory().readWord(cpu.getProgramCounter() + 1, TYPE.READ_OPERAND, readAddressTriggersEvent, false)), ABSOLUTE(3, "$~2~1", (cpu) -> getMemory().readWord(cpu.getProgramCounter() + 1, TYPE.READ_OPERAND, cpu.readAddressTriggersEvent, false)),
ABSOLUTE_X(3, "$~2~1,X", () -> { ABSOLUTE_X(3, "$~2~1,X", (cpu) -> {
int address2 = getMemory().readWord(cpu.getProgramCounter() + 1, TYPE.READ_OPERAND, readAddressTriggersEvent, false); int address2 = getMemory().readWord(cpu.getProgramCounter() + 1, TYPE.READ_OPERAND, cpu.readAddressTriggersEvent, false);
int address = 0x0FFFF & (address2 + cpu.X); int address = 0x0FFFF & (address2 + cpu.X);
if ((address & 0x00FF00) != (address2 & 0x00FF00)) { if ((address & 0x00FF00) != (address2 & 0x00FF00)) {
cpu.addWaitCycles(1); cpu.addWaitCycles(1);
} }
return address; return address;
}), }),
ABSOLUTE_Y(3, "$~2~1,Y", () -> { ABSOLUTE_Y(3, "$~2~1,Y", (cpu) -> {
int address2 = getMemory().readWord(cpu.getProgramCounter() + 1, TYPE.READ_OPERAND, readAddressTriggersEvent, false); int address2 = getMemory().readWord(cpu.getProgramCounter() + 1, TYPE.READ_OPERAND, cpu.readAddressTriggersEvent, false);
int address = 0x0FFFF & (address2 + cpu.Y); int address = 0x0FFFF & (address2 + cpu.Y);
if ((address & 0x00FF00) != (address2 & 0x00FF00)) { if ((address & 0x00FF00) != (address2 & 0x00FF00)) {
cpu.addWaitCycles(1); cpu.addWaitCycles(1);
@ -406,19 +406,19 @@ public class MOS65C02 extends CPU {
}), }),
ZP_REL(2, "$~1,$R", new AddressCalculator() { ZP_REL(2, "$~1,$R", new AddressCalculator() {
@Override @Override
public int calculateAddress() { public int calculateAddress(MOS65C02 cpu) {
// Note: This is two's compliment addition and the getMemory().read() returns a signed 8-bit value // Note: This is two's compliment addition and the getMemory().read() returns a signed 8-bit value
int pc = cpu.getProgramCounter(); int pc = cpu.getProgramCounter();
int address = pc + 2 + getMemory().read(pc + 2, TYPE.READ_OPERAND, readAddressTriggersEvent, false); int address = pc + 2 + getMemory().read(pc + 2, TYPE.READ_OPERAND, cpu.readAddressTriggersEvent, false);
// The wait cycles are not added unless the branch actually happens! // The wait cycles are not added unless the branch actually happens!
cpu.setPageBoundaryPenalty((address & 0x00ff00) != (pc & 0x00ff00)); cpu.setPageBoundaryPenalty((address & 0x00ff00) != (pc & 0x00ff00));
return address; return address;
} }
@Override @Override
public int getValue(boolean isRead) { public int getValue(boolean isRead, MOS65C02 cpu) {
int pc = cpu.getProgramCounter(); int pc = cpu.getProgramCounter();
int address = getMemory().read(pc + 1, TYPE.READ_OPERAND, readAddressTriggersEvent, false); int address = getMemory().read(pc + 1, TYPE.READ_OPERAND, cpu.readAddressTriggersEvent, false);
return getMemory().read(address, TYPE.READ_DATA, true, false); return getMemory().read(address, TYPE.READ_DATA, true, false);
} }
}); });
@ -434,8 +434,8 @@ public class MOS65C02 extends CPU {
// } // }
private AddressCalculator calculator; private AddressCalculator calculator;
public int calcAddress() { public int calcAddress(MOS65C02 cpu) {
return calculator.calculateAddress(); return calculator.calculateAddress(cpu);
} }
private boolean indirect; private boolean indirect;
@ -493,7 +493,7 @@ public class MOS65C02 extends CPU {
private static interface CommandProcessor { private static interface CommandProcessor {
public void processCommand(int address, int value, MODE addressMode); public void processCommand(int address, int value, MODE addressMode, MOS65C02 cpu);
} }
private static class BBRCommand implements CommandProcessor { private static class BBRCommand implements CommandProcessor {
@ -505,7 +505,7 @@ public class MOS65C02 extends CPU {
} }
@Override @Override
public void processCommand(int address, int value, MODE addressMode) { public void processCommand(int address, int value, MODE addressMode, MOS65C02 cpu) {
if (((value >> bit) & 1) != 0) { if (((value >> bit) & 1) != 0) {
return; return;
} }
@ -525,7 +525,7 @@ public class MOS65C02 extends CPU {
} }
@Override @Override
public void processCommand(int address, int value, MODE addressMode) { public void processCommand(int address, int value, MODE addressMode, MOS65C02 cpu) {
if (((value >> bit) & 1) == 0) { if (((value >> bit) & 1) == 0) {
return; return;
} }
@ -545,7 +545,7 @@ public class MOS65C02 extends CPU {
} }
@Override @Override
public void processCommand(int address, int value, MODE addressMode) { public void processCommand(int address, int value, MODE addressMode, MOS65C02 cpu) {
int mask = 0x0ff ^ (1 << bit); int mask = 0x0ff ^ (1 << bit);
value &= mask; value &= mask;
getMemory().write(address, (byte) value, true, false); getMemory().write(address, (byte) value, true, false);
@ -561,16 +561,17 @@ public class MOS65C02 extends CPU {
} }
@Override @Override
public void processCommand(int address, int value, MODE addressMode) { public void processCommand(int address, int value, MODE addressMode, MOS65C02 cpu) {
int mask = 1 << bit; int mask = 1 << bit;
value |= mask; value |= mask;
getMemory().write(address, (byte) value, true, false); getMemory().write(address, (byte) value, true, false);
} }
} }
private enum COMMAND { public enum COMMAND {
ADC((int address, int value, MODE addressMode) -> {
int w = 0; ADC((address, value, addressMode, cpu) -> {
int w;
cpu.V = ((cpu.A ^ value) & 0x080) == 0; cpu.V = ((cpu.A ^ value) & 0x080) == 0;
if (cpu.D) { if (cpu.D) {
// Decimal Mode // Decimal Mode
@ -609,11 +610,11 @@ public class MOS65C02 extends CPU {
cpu.A = w & 0x0ff; cpu.A = w & 0x0ff;
cpu.setNZ(cpu.A); cpu.setNZ(cpu.A);
}), }),
AND((int address, int value, MODE addressMode) -> { AND((address, value, addressMode, cpu) -> {
cpu.A &= value; cpu.A &= value;
cpu.setNZ(cpu.A); cpu.setNZ(cpu.A);
}), }),
ASL((int address, int value, MODE addressMode) -> { ASL((address, value, addressMode, cpu) -> {
cpu.C = ((value & 0x080) != 0) ? 1 : 0; cpu.C = ((value & 0x080) != 0) ? 1 : 0;
value = 0x0FE & (value << 1); value = 0x0FE & (value << 1);
cpu.setNZ(value); cpu.setNZ(value);
@ -622,7 +623,7 @@ public class MOS65C02 extends CPU {
getMemory().write(address, (byte) value, true, false); getMemory().write(address, (byte) value, true, false);
getMemory().write(address, (byte) value, true, false); getMemory().write(address, (byte) value, true, false);
}), }),
ASL_A((int address, int value, MODE addressMode) -> { ASL_A((address, value, addressMode, cpu) -> {
cpu.C = cpu.A >> 7; cpu.C = cpu.A >> 7;
cpu.A = 0x0FE & (cpu.A << 1); cpu.A = 0x0FE & (cpu.A << 1);
cpu.setNZ(cpu.A); cpu.setNZ(cpu.A);
@ -643,25 +644,25 @@ public class MOS65C02 extends CPU {
BBS5(new BBSCommand(5)), BBS5(new BBSCommand(5)),
BBS6(new BBSCommand(6)), BBS6(new BBSCommand(6)),
BBS7(new BBSCommand(7)), BBS7(new BBSCommand(7)),
BCC((int address, int value, MODE addressMode) -> { BCC((address, value, addressMode, cpu) -> {
if (cpu.C == 0) { if (cpu.C == 0) {
cpu.setProgramCounter(address); cpu.setProgramCounter(address);
cpu.addWaitCycles(cpu.pageBoundaryPenalty ? 2 : 1); cpu.addWaitCycles(cpu.pageBoundaryPenalty ? 2 : 1);
} }
}), }),
BCS((int address, int value, MODE addressMode) -> { BCS((address, value, addressMode, cpu) -> {
if (cpu.C != 0) { if (cpu.C != 0) {
cpu.setProgramCounter(address); cpu.setProgramCounter(address);
cpu.addWaitCycles(cpu.pageBoundaryPenalty ? 2 : 1); cpu.addWaitCycles(cpu.pageBoundaryPenalty ? 2 : 1);
} }
}), }),
BEQ((int address, int value, MODE addressMode) -> { BEQ((address, value, addressMode, cpu) -> {
if (cpu.Z) { if (cpu.Z) {
cpu.setProgramCounter(address); cpu.setProgramCounter(address);
cpu.addWaitCycles(cpu.pageBoundaryPenalty ? 2 : 1); cpu.addWaitCycles(cpu.pageBoundaryPenalty ? 2 : 1);
} }
}), }),
BIT((int address, int value, MODE addressMode) -> { BIT((address, value, addressMode, cpu) -> {
int result = (cpu.A & value); int result = (cpu.A & value);
cpu.Z = result == 0; cpu.Z = result == 0;
cpu.N = (value & 0x080) != 0; cpu.N = (value & 0x080) != 0;
@ -670,132 +671,132 @@ public class MOS65C02 extends CPU {
cpu.V = (value & 0x040) != 0; cpu.V = (value & 0x040) != 0;
} }
}), }),
BMI((int address, int value, MODE addressMode) -> { BMI((address, value, addressMode, cpu) -> {
if (cpu.N) { if (cpu.N) {
cpu.setProgramCounter(address); cpu.setProgramCounter(address);
cpu.addWaitCycles(cpu.pageBoundaryPenalty ? 2 : 1); cpu.addWaitCycles(cpu.pageBoundaryPenalty ? 2 : 1);
} }
}), }),
BNE((int address, int value, MODE addressMode) -> { BNE((address, value, addressMode, cpu) -> {
if (!cpu.Z) { if (!cpu.Z) {
cpu.setProgramCounter(address); cpu.setProgramCounter(address);
cpu.addWaitCycles(cpu.pageBoundaryPenalty ? 2 : 1); cpu.addWaitCycles(cpu.pageBoundaryPenalty ? 2 : 1);
} }
}), }),
BPL((int address, int value, MODE addressMode) -> { BPL((address, value, addressMode, cpu) -> {
if (!cpu.N) { if (!cpu.N) {
cpu.setProgramCounter(address); cpu.setProgramCounter(address);
cpu.addWaitCycles(cpu.pageBoundaryPenalty ? 2 : 1); cpu.addWaitCycles(cpu.pageBoundaryPenalty ? 2 : 1);
} }
}), }),
BRA((int address, int value, MODE addressMode) -> { BRA((address, value, addressMode, cpu) -> {
cpu.setProgramCounter(address); cpu.setProgramCounter(address);
cpu.addWaitCycles(cpu.pageBoundaryPenalty ? 1 : 0); cpu.addWaitCycles(cpu.pageBoundaryPenalty ? 1 : 0);
}), }),
BRK((int address, int value, MODE addressMode) -> { BRK((address, value, addressMode, cpu) -> {
cpu.BRK(); cpu.BRK();
}), }),
BVC((int address, int value, MODE addressMode) -> { BVC((address, value, addressMode, cpu) -> {
if (!cpu.V) { if (!cpu.V) {
cpu.setProgramCounter(address); cpu.setProgramCounter(address);
cpu.addWaitCycles(cpu.pageBoundaryPenalty ? 2 : 1); cpu.addWaitCycles(cpu.pageBoundaryPenalty ? 2 : 1);
} }
}), }),
BVS((int address, int value, MODE addressMode) -> { BVS((address, value, addressMode, cpu) -> {
if (cpu.V) { if (cpu.V) {
cpu.setProgramCounter(address); cpu.setProgramCounter(address);
cpu.addWaitCycles(cpu.pageBoundaryPenalty ? 2 : 1); cpu.addWaitCycles(cpu.pageBoundaryPenalty ? 2 : 1);
} }
}), }),
CLC((int address, int value, MODE addressMode) -> { CLC((address, value, addressMode, cpu) -> {
cpu.C = 0; cpu.C = 0;
}), }),
CLD((int address, int value, MODE addressMode) -> { CLD((address, value, addressMode, cpu) -> {
cpu.D = false; cpu.D = false;
}), }),
CLI((int address, int value, MODE addressMode) -> { CLI((address, value, addressMode, cpu) -> {
cpu.I = false; cpu.I = false;
cpu.interruptSignalled = false; cpu.interruptSignalled = false;
}), }),
CLV((int address, int value, MODE addressMode) -> { CLV((address, value, addressMode, cpu) -> {
cpu.V = false; cpu.V = false;
}), }),
CMP((int address, int value, MODE addressMode) -> { CMP((address, value, addressMode, cpu) -> {
int val = cpu.A - value; int val = cpu.A - value;
cpu.C = (val >= 0) ? 1 : 0; cpu.C = (val >= 0) ? 1 : 0;
cpu.setNZ(val); cpu.setNZ(val);
}), }),
CPX((int address, int value, MODE addressMode) -> { CPX((address, value, addressMode, cpu) -> {
int val = cpu.X - value; int val = cpu.X - value;
cpu.C = (val >= 0) ? 1 : 0; cpu.C = (val >= 0) ? 1 : 0;
cpu.setNZ(val); cpu.setNZ(val);
}), }),
CPY((int address, int value, MODE addressMode) -> { CPY((address, value, addressMode, cpu) -> {
int val = cpu.Y - value; int val = cpu.Y - value;
cpu.C = (val >= 0) ? 1 : 0; cpu.C = (val >= 0) ? 1 : 0;
cpu.setNZ(val); cpu.setNZ(val);
}), }),
DEC((int address, int value, MODE addressMode) -> { DEC((address, value, addressMode, cpu) -> {
value = 0x0FF & (value - 1); value = 0x0FF & (value - 1);
getMemory().write(address, (byte) value, true, false); getMemory().write(address, (byte) value, true, false);
getMemory().write(address, (byte) value, true, false); getMemory().write(address, (byte) value, true, false);
cpu.setNZ(value); cpu.setNZ(value);
}), }),
DEA((int address, int value, MODE addressMode) -> { DEA((address, value, addressMode, cpu) -> {
cpu.A = 0x0FF & (cpu.A - 1); cpu.A = 0x0FF & (cpu.A - 1);
cpu.setNZ(cpu.A); cpu.setNZ(cpu.A);
}), }),
DEX((int address, int value, MODE addressMode) -> { DEX((address, value, addressMode, cpu) -> {
cpu.X = 0x0FF & (cpu.X - 1); cpu.X = 0x0FF & (cpu.X - 1);
cpu.setNZ(cpu.X); cpu.setNZ(cpu.X);
}), }),
DEY((int address, int value, MODE addressMode) -> { DEY((address, value, addressMode, cpu) -> {
cpu.Y = 0x0FF & (cpu.Y - 1); cpu.Y = 0x0FF & (cpu.Y - 1);
cpu.setNZ(cpu.Y); cpu.setNZ(cpu.Y);
}), }),
EOR((int address, int value, MODE addressMode) -> { EOR((address, value, addressMode, cpu) -> {
cpu.A = 0x0FF & (cpu.A ^ value); cpu.A = 0x0FF & (cpu.A ^ value);
cpu.setNZ(cpu.A); cpu.setNZ(cpu.A);
}), }),
INC((int address, int value, MODE addressMode) -> { INC((address, value, addressMode, cpu) -> {
value = 0x0ff & (value + 1); value = 0x0ff & (value + 1);
// emulator correct fetch-modify-store behavior // emulator correct fetch-modify-store behavior
getMemory().write(address, (byte) value, true, false); getMemory().write(address, (byte) value, true, false);
getMemory().write(address, (byte) value, true, false); getMemory().write(address, (byte) value, true, false);
cpu.setNZ(value); cpu.setNZ(value);
}), }),
INA((int address, int value, MODE addressMode) -> { INA((address, value, addressMode, cpu) -> {
cpu.A = 0x0FF & (cpu.A + 1); cpu.A = 0x0FF & (cpu.A + 1);
cpu.setNZ(cpu.A); cpu.setNZ(cpu.A);
}), }),
INX((int address, int value, MODE addressMode) -> { INX((address, value, addressMode, cpu) -> {
cpu.X = 0x0FF & (cpu.X + 1); cpu.X = 0x0FF & (cpu.X + 1);
cpu.setNZ(cpu.X); cpu.setNZ(cpu.X);
}), }),
INY((int address, int value, MODE addressMode) -> { INY((address, value, addressMode, cpu) -> {
cpu.Y = 0x0FF & (cpu.Y + 1); cpu.Y = 0x0FF & (cpu.Y + 1);
cpu.setNZ(cpu.Y); cpu.setNZ(cpu.Y);
}), }),
JMP((int address, int value, MODE addressMode) -> { JMP((address, value, addressMode, cpu) -> {
cpu.setProgramCounter(address); cpu.setProgramCounter(address);
}), }),
JSR((int address, int value, MODE addressMode) -> { JSR((address, value, addressMode, cpu) -> {
cpu.pushWord(cpu.getProgramCounter() - 1); cpu.pushWord(cpu.getProgramCounter() - 1);
cpu.setProgramCounter(address); cpu.setProgramCounter(address);
}), }),
LDA((int address, int value, MODE addressMode) -> { LDA((address, value, addressMode, cpu) -> {
cpu.A = value; cpu.A = value;
cpu.setNZ(cpu.A); cpu.setNZ(cpu.A);
}), }),
LDX((int address, int value, MODE addressMode) -> { LDX((address, value, addressMode, cpu) -> {
cpu.X = value; cpu.X = value;
cpu.setNZ(cpu.X); cpu.setNZ(cpu.X);
}), }),
LDY((int address, int value, MODE addressMode) -> { LDY((address, value, addressMode, cpu) -> {
cpu.Y = value; cpu.Y = value;
cpu.setNZ(cpu.Y); cpu.setNZ(cpu.Y);
}), }),
LSR((int address, int value, MODE addressMode) -> { LSR((address, value, addressMode, cpu) -> {
cpu.C = (value & 1); cpu.C = (value & 1);
value = (value >> 1) & 0x07F; value = (value >> 1) & 0x07F;
cpu.setNZ(value); cpu.setNZ(value);
@ -803,40 +804,41 @@ public class MOS65C02 extends CPU {
getMemory().write(address, (byte) value, true, false); getMemory().write(address, (byte) value, true, false);
getMemory().write(address, (byte) value, true, false); getMemory().write(address, (byte) value, true, false);
}), }),
LSR_A((int address, int value, MODE addressMode) -> { LSR_A((address, value, addressMode, cpu) -> {
cpu.C = cpu.A & 1; cpu.C = cpu.A & 1;
cpu.A = (cpu.A >> 1) & 0x07F; cpu.A = (cpu.A >> 1) & 0x07F;
cpu.setNZ(cpu.A); cpu.setNZ(cpu.A);
}), }),
NOP((int address, int value, MODE addressMode) -> {}), NOP((address, value, addressMode, cpu) -> {
ORA((int address, int value, MODE addressMode) -> { }),
ORA((address, value, addressMode, cpu) -> {
cpu.A |= value; cpu.A |= value;
cpu.setNZ(cpu.A); cpu.setNZ(cpu.A);
}), }),
PHA((int address, int value, MODE addressMode) -> { PHA((address, value, addressMode, cpu) -> {
cpu.push((byte) cpu.A); cpu.push((byte) cpu.A);
}), }),
PHP((int address, int value, MODE addressMode) -> { PHP((address, value, addressMode, cpu) -> {
cpu.push((byte) (cpu.getStatus())); cpu.push((byte) (cpu.getStatus()));
}), }),
PHX((int address, int value, MODE addressMode) -> { PHX((address, value, addressMode, cpu) -> {
cpu.push((byte) cpu.X); cpu.push((byte) cpu.X);
}), }),
PHY((int address, int value, MODE addressMode) -> { PHY((address, value, addressMode, cpu) -> {
cpu.push((byte) cpu.Y); cpu.push((byte) cpu.Y);
}), }),
PLA((int address, int value, MODE addressMode) -> { PLA((address, value, addressMode, cpu) -> {
cpu.A = 0x0FF & cpu.pop(); cpu.A = 0x0FF & cpu.pop();
cpu.setNZ(cpu.A); cpu.setNZ(cpu.A);
}), }),
PLP((int address, int value, MODE addressMode) -> { PLP((address, value, addressMode, cpu) -> {
cpu.setStatus(cpu.pop()); cpu.setStatus(cpu.pop());
}), }),
PLX((int address, int value, MODE addressMode) -> { PLX((address, value, addressMode, cpu) -> {
cpu.X = 0x0FF & cpu.pop(); cpu.X = 0x0FF & cpu.pop();
cpu.setNZ(cpu.X); cpu.setNZ(cpu.X);
}), }),
PLY((int address, int value, MODE addressMode) -> { PLY((address, value, addressMode, cpu) -> {
cpu.Y = 0x0FF & cpu.pop(); cpu.Y = 0x0FF & cpu.pop();
cpu.setNZ(cpu.Y); cpu.setNZ(cpu.Y);
}), }),
@ -848,7 +850,7 @@ public class MOS65C02 extends CPU {
RMB5(new RMBCommand(5)), RMB5(new RMBCommand(5)),
RMB6(new RMBCommand(6)), RMB6(new RMBCommand(6)),
RMB7(new RMBCommand(7)), RMB7(new RMBCommand(7)),
ROL((int address, int value, MODE addressMode) -> { ROL((address, value, addressMode, cpu) -> {
int oldC = cpu.C; int oldC = cpu.C;
cpu.C = value >> 7; cpu.C = value >> 7;
value = 0x0ff & ((value << 1) | oldC); value = 0x0ff & ((value << 1) | oldC);
@ -857,13 +859,13 @@ public class MOS65C02 extends CPU {
getMemory().write(address, (byte) value, true, false); getMemory().write(address, (byte) value, true, false);
getMemory().write(address, (byte) value, true, false); getMemory().write(address, (byte) value, true, false);
}), }),
ROL_A((int address, int value, MODE addressMode) -> { ROL_A((address, value, addressMode, cpu) -> {
int oldC = cpu.C; int oldC = cpu.C;
cpu.C = cpu.A >> 7; cpu.C = cpu.A >> 7;
cpu.A = 0x0ff & ((cpu.A << 1) | oldC); cpu.A = 0x0ff & ((cpu.A << 1) | oldC);
cpu.setNZ(cpu.A); cpu.setNZ(cpu.A);
}), }),
ROR((int address, int value, MODE addressMode) -> { ROR((address, value, addressMode, cpu) -> {
int oldC = cpu.C << 7; int oldC = cpu.C << 7;
cpu.C = value & 1; cpu.C = value & 1;
value = 0x0ff & ((value >> 1) | oldC); value = 0x0ff & ((value >> 1) | oldC);
@ -872,21 +874,21 @@ public class MOS65C02 extends CPU {
getMemory().write(address, (byte) value, true, false); getMemory().write(address, (byte) value, true, false);
getMemory().write(address, (byte) value, true, false); getMemory().write(address, (byte) value, true, false);
}), }),
ROR_A((int address, int value, MODE addressMode) -> { ROR_A((address, value, addressMode, cpu) -> {
int oldC = cpu.C << 7; int oldC = cpu.C << 7;
cpu.C = cpu.A & 1; cpu.C = cpu.A & 1;
cpu.A = 0x0ff & ((cpu.A >> 1) | oldC); cpu.A = 0x0ff & ((cpu.A >> 1) | oldC);
cpu.setNZ(cpu.A); cpu.setNZ(cpu.A);
}), }),
RTI((int address, int value, MODE addressMode) -> { RTI((address, value, addressMode, cpu) -> {
cpu.returnFromInterrupt(); cpu.returnFromInterrupt();
}), }),
RTS((int address, int value, MODE addressMode) -> { RTS((address, value, addressMode, cpu) -> {
cpu.setProgramCounter(cpu.popWord() + 1); cpu.setProgramCounter(cpu.popWord() + 1);
}), }),
SBC((int address, int value, MODE addressMode) -> { SBC((address, value, addressMode, cpu) -> {
cpu.V = ((cpu.A ^ value) & 0x080) != 0; cpu.V = ((cpu.A ^ value) & 0x080) != 0;
int w = 0; int w;
if (cpu.D) { if (cpu.D) {
int temp = 0x0f + (cpu.A & 0x0f) - (value & 0x0f) + cpu.C; int temp = 0x0f + (cpu.A & 0x0f) - (value & 0x0f) + cpu.C;
if (temp < 0x10) { if (temp < 0x10) {
@ -927,13 +929,13 @@ public class MOS65C02 extends CPU {
cpu.A = w & 0x0ff; cpu.A = w & 0x0ff;
cpu.setNZ(cpu.A); cpu.setNZ(cpu.A);
}), }),
SEC((int address, int value, MODE addressMode) -> { SEC((address, value, addressMode, cpu) -> {
cpu.C = 1; cpu.C = 1;
}), }),
SED((int address, int value, MODE addressMode) -> { SED((address, value, addressMode, cpu) -> {
cpu.D = true; cpu.D = true;
}), }),
SEI((int address, int value, MODE addressMode) -> { SEI((address, value, addressMode, cpu) -> {
cpu.I = true; cpu.I = true;
}), }),
SMB0(new SMBCommand(0)), SMB0(new SMBCommand(0)),
@ -944,55 +946,55 @@ public class MOS65C02 extends CPU {
SMB5(new SMBCommand(5)), SMB5(new SMBCommand(5)),
SMB6(new SMBCommand(6)), SMB6(new SMBCommand(6)),
SMB7(new SMBCommand(7)), SMB7(new SMBCommand(7)),
STA(true, (int address, int value, MODE addressMode) -> { STA(true, (address, value, addressMode, cpu) -> {
getMemory().write(address, (byte) cpu.A, true, false); getMemory().write(address, (byte) cpu.A, true, false);
}), }),
STP((int address, int value, MODE addressMode) -> { STP((address, value, addressMode, cpu) -> {
cpu.suspend(); cpu.suspend();
}), }),
STX(true, (int address, int value, MODE addressMode) -> { STX(true, (address, value, addressMode, cpu) -> {
getMemory().write(address, (byte) cpu.X, true, false); getMemory().write(address, (byte) cpu.X, true, false);
}), }),
STY(true, (int address, int value, MODE addressMode) -> { STY(true, (address, value, addressMode, cpu) -> {
getMemory().write(address, (byte) cpu.Y, true, false); getMemory().write(address, (byte) cpu.Y, true, false);
}), }),
STZ(true, (int address, int value, MODE addressMode) -> { STZ(true, (address, value, addressMode, cpu) -> {
getMemory().write(address, (byte) 0, true, false); getMemory().write(address, (byte) 0, true, false);
}), }),
TAX((int address, int value, MODE addressMode) -> { TAX((address, value, addressMode, cpu) -> {
cpu.X = cpu.A; cpu.X = cpu.A;
cpu.setNZ(cpu.X); cpu.setNZ(cpu.X);
}), }),
TAY((int address, int value, MODE addressMode) -> { TAY((address, value, addressMode, cpu) -> {
cpu.Y = cpu.A; cpu.Y = cpu.A;
cpu.setNZ(cpu.Y); cpu.setNZ(cpu.Y);
}), }),
TRB((int address, int value, MODE addressMode) -> { TRB((address, value, addressMode, cpu) -> {
cpu.C = (value & cpu.A) != 0 ? 1 : 0; cpu.C = (value & cpu.A) != 0 ? 1 : 0;
value &= ~cpu.A; value &= ~cpu.A;
getMemory().write(address, (byte) value, true, false); getMemory().write(address, (byte) value, true, false);
}), }),
TSB((int address, int value, MODE addressMode) -> { TSB((address, value, addressMode, cpu) -> {
cpu.C = (value & cpu.A) != 0 ? 1 : 0; cpu.C = (value & cpu.A) != 0 ? 1 : 0;
value |= cpu.A; value |= cpu.A;
getMemory().write(address, (byte) value, true, false); getMemory().write(address, (byte) value, true, false);
}), }),
TSX((int address, int value, MODE addressMode) -> { TSX((address, value, addressMode, cpu) -> {
cpu.X = cpu.STACK; cpu.X = cpu.STACK;
cpu.setNZ(cpu.STACK); cpu.setNZ(cpu.STACK);
}), }),
TXA((int address, int value, MODE addressMode) -> { TXA((address, value, addressMode, cpu) -> {
cpu.A = cpu.X; cpu.A = cpu.X;
cpu.setNZ(cpu.X); cpu.setNZ(cpu.X);
}), }),
TXS((int address, int value, MODE addressMode) -> { TXS((address, value, addressMode, cpu) -> {
cpu.STACK = cpu.X; cpu.STACK = cpu.X;
}), }),
TYA((int address, int value, MODE addressMode) -> { TYA((address, value, addressMode, cpu) -> {
cpu.A = cpu.Y; cpu.A = cpu.Y;
cpu.setNZ(cpu.Y); cpu.setNZ(cpu.Y);
}), }),
WAI((int address, int value, MODE addressMode) -> { WAI((address, value, addressMode, cpu) -> {
cpu.waitForInterrupt(); cpu.waitForInterrupt();
}); });
private CommandProcessor processor; private CommandProcessor processor;
@ -1024,13 +1026,6 @@ public class MOS65C02 extends CPU {
} }
} }
/**
* Creates a new instance of MOS65C02
*/
public MOS65C02() {
cpu = this;
}
@Override @Override
protected void executeOpcode() { protected void executeOpcode() {
if (interruptSignalled) { if (interruptSignalled) {
@ -1046,10 +1041,10 @@ public class MOS65C02 extends CPU {
if (isTraceEnabled() || isLogEnabled() || (warnAboutExtendedOpcodes && opcode != null && opcode.isExtendedOpcode)) { if (isTraceEnabled() || isLogEnabled() || (warnAboutExtendedOpcodes && opcode != null && opcode.isExtendedOpcode)) {
String t = getState().toUpperCase() + " " + Integer.toString(pc, 16) + " : " + disassemble(); String t = getState().toUpperCase() + " " + Integer.toString(pc, 16) + " : " + disassemble();
if (warnAboutExtendedOpcodes && opcode != null && opcode.isExtendedOpcode) { if (warnAboutExtendedOpcodes && opcode != null && opcode.isExtendedOpcode) {
System.out.println(">>EXTENDED OPCODE DETECTED "+Integer.toHexString(opcode.code)+"<<"); System.out.println(">>EXTENDED OPCODE DETECTED " + Integer.toHexString(opcode.code) + "<<");
System.out.println(t); System.out.println(t);
if (isLogEnabled()) { if (isLogEnabled()) {
log(">>EXTENDED OPCODE DETECTED "+Integer.toHexString(opcode.code)+"<<"); log(">>EXTENDED OPCODE DETECTED " + Integer.toHexString(opcode.code) + "<<");
log(t); log(t);
} }
} else { } else {
@ -1098,13 +1093,13 @@ public class MOS65C02 extends CPU {
dumpTrace(); dumpTrace();
} }
if (breakOnBadOpcode) { if (breakOnBadOpcode) {
OPCODE.BRK.execute(); OPCODE.BRK.execute(this);
} }
} else { } else {
opcode.fetch(); opcode.fetch(this);
incrementProgramCounter(opcode.getMode().getSize()); incrementProgramCounter(opcode.getMode().getSize());
opcode.execute(); opcode.execute(this);
addWaitCycles(opcode.getWaitCycles()); addWaitCycles(opcode.getWaitCycles());
} }
} }
@ -1206,6 +1201,7 @@ public class MOS65C02 extends CPU {
} }
// Cold/Warm boot procedure // Cold/Warm boot procedure
@Override
public void reset() { public void reset() {
boolean restart = Computer.pause(); boolean restart = Computer.pause();
pushWord(getProgramCounter()); pushWord(getProgramCounter());
@ -1227,6 +1223,7 @@ public class MOS65C02 extends CPU {
} }
} }
@Override
protected String getDeviceName() { protected String getDeviceName() {
return "65C02 Processor"; return "65C02 Processor";
} }
@ -1259,7 +1256,7 @@ public class MOS65C02 extends CPU {
out.append(byte2(X)).append(" "); out.append(byte2(X)).append(" ");
out.append(byte2(Y)).append(" "); out.append(byte2(Y)).append(" ");
// out += "PC:"+wordString(getProgramCounter())+" "; // out += "PC:"+wordString(getProgramCounter())+" ";
out.append("01").append(byte2(STACK)). append(" "); out.append("01").append(byte2(STACK)).append(" ");
out.append(getFlags()); out.append(getFlags());
return out.toString(); return out.toString();
} }
@ -1308,6 +1305,6 @@ public class MOS65C02 extends CPU {
@Override @Override
public void pushPC() { public void pushPC() {
cpu.pushWord(cpu.getProgramCounter() - 1); pushWord(getProgramCounter() - 1);
} }
} }