use of com.rox.emu.processor.mos6502.util.Program in project emuRox by rossdrew.
the class Mos6502Test method testSED.
@Test
public void testSED() {
Program program = new Program().with(SED);
memory.setBlock(0, program.getProgramAsByteArray());
Registers registers = processor.getRegisters();
// Load status, push to stack then clear it and pull it from stack
registers.setRegister(Registers.Register.STATUS_FLAGS, 0b11110111);
processor.step(1);
assertEquals(program.getLength(), registers.getPC());
assertEquals(0b11111111, registers.getRegister(Registers.Register.STATUS_FLAGS));
}
use of com.rox.emu.processor.mos6502.util.Program in project emuRox by rossdrew.
the class Mos6502Test method testTAY.
@Test
public void testTAY() {
Program program = new Program().with(LDA_I, 0x0F, TAY);
memory.setBlock(0, program.getProgramAsByteArray());
Registers registers = processor.getRegisters();
processor.step(2);
assertEquals(program.getLength(), registers.getPC());
assertEquals(0x0F, registers.getRegister(Registers.Register.ACCUMULATOR));
assertEquals(0x0F, registers.getRegister(Registers.Register.Y_INDEX));
}
use of com.rox.emu.processor.mos6502.util.Program in project emuRox by rossdrew.
the class Mos6502 method step.
/**
* Execute the next program instruction as per {@link Registers#getNextProgramCounter()}
*/
public void step() {
log.debug("STEP >>>");
final OpCode opCode = OpCode.from(nextProgramByte());
// Execute the opcode
log.debug("Instruction: {}...", opCode.getOpCodeName());
switch(opCode) {
case ASL_A:
withRegister(Register.ACCUMULATOR, this::performASL);
break;
case ASL_Z:
withByteAt(nextProgramByte(), this::performASL);
break;
case ASL_Z_IX:
withByteXIndexedAt(nextProgramByte(), this::performASL);
break;
case ASL_ABS_IX:
withByteXIndexedAt(nextProgramWord(), this::performASL);
break;
case ASL_ABS:
withByteAt(nextProgramWord(), this::performASL);
break;
case LSR_A:
withRegister(Register.ACCUMULATOR, this::performLSR);
break;
case LSR_Z:
withByteAt(nextProgramByte(), this::performLSR);
break;
case LSR_Z_IX:
withByteXIndexedAt(nextProgramByte(), this::performLSR);
break;
case LSR_ABS:
withByteAt(nextProgramWord(), this::performLSR);
break;
case LSR_ABS_IX:
withByteXIndexedAt(nextProgramWord(), this::performLSR);
break;
case ROL_A:
withRegister(Register.ACCUMULATOR, this::performROL);
break;
case ROL_Z:
withByteAt(nextProgramByte(), this::performROL);
break;
case ROL_Z_IX:
withByteXIndexedAt(nextProgramByte(), this::performROL);
break;
case ROL_ABS:
withByteAt(nextProgramWord(), this::performROL);
break;
case ROL_ABS_IX:
withByteXIndexedAt(nextProgramWord(), this::performROL);
break;
case ROR_A:
withRegister(Register.ACCUMULATOR, this::performROR);
break;
case SEC:
registers.setFlag(Flag.CARRY);
break;
case CLC:
registers.clearFlag(Flag.CARRY);
break;
case CLV:
registers.clearFlag(Flag.OVERFLOW);
break;
case INC_Z:
withByteAt(nextProgramByte(), this::performINC);
break;
case INC_Z_IX:
withByteXIndexedAt(nextProgramByte(), this::performINC);
break;
case INC_ABS:
withByteAt(nextProgramWord(), this::performINC);
break;
case INC_ABS_IX:
withByteXIndexedAt(nextProgramWord(), this::performINC);
break;
case DEC_Z:
withByteAt(nextProgramByte(), this::performDEC);
break;
case DEC_Z_IX:
withByteXIndexedAt(nextProgramByte(), this::performDEC);
break;
case DEC_ABS:
withByteAt(nextProgramWord(), this::performDEC);
break;
case DEC_ABS_IX:
withByteXIndexedAt(nextProgramWord(), this::performDEC);
break;
case INX:
withRegister(Register.X_INDEX, this::performINC);
break;
case DEX:
withRegister(Register.X_INDEX, this::performDEC);
break;
case INY:
withRegister(Register.Y_INDEX, this::performINC);
break;
case DEY:
withRegister(Register.Y_INDEX, this::performDEC);
break;
case LDX_I:
registers.setRegisterAndFlags(Register.X_INDEX, nextProgramByte());
break;
case LDX_Z:
registers.setRegisterAndFlags(Register.X_INDEX, getByteOfMemoryAt(nextProgramByte()));
break;
case LDX_Z_IY:
registers.setRegisterAndFlags(Register.X_INDEX, getByteOfMemoryYIndexedAt(nextProgramByte()));
break;
case LDX_ABS:
registers.setRegisterAndFlags(Register.X_INDEX, getByteOfMemoryAt(nextProgramWord()));
break;
case LDX_ABS_IY:
registers.setRegisterAndFlags(Register.X_INDEX, getByteOfMemoryYIndexedAt(nextProgramWord()));
break;
case LDY_I:
registers.setRegisterAndFlags(Register.Y_INDEX, nextProgramByte());
break;
case LDY_Z:
registers.setRegisterAndFlags(Register.Y_INDEX, getByteOfMemoryAt(nextProgramByte()));
break;
case LDY_Z_IX:
registers.setRegisterAndFlags(Register.Y_INDEX, getByteOfMemoryXIndexedAt(nextProgramByte()));
break;
case LDY_ABS:
registers.setRegisterAndFlags(Register.Y_INDEX, getByteOfMemoryAt(nextProgramWord()));
break;
case LDY_ABS_IX:
registers.setRegisterAndFlags(Register.Y_INDEX, getByteOfMemoryXIndexedAt(nextProgramWord()));
break;
case LDA_I:
registers.setRegisterAndFlags(Register.ACCUMULATOR, nextProgramByte());
break;
case LDA_Z:
registers.setRegisterAndFlags(Register.ACCUMULATOR, getByteOfMemoryAt(nextProgramByte()));
break;
case LDA_Z_IX:
registers.setRegisterAndFlags(Register.ACCUMULATOR, getByteOfMemoryXIndexedAt(nextProgramByte()));
break;
case LDA_ABS:
registers.setRegisterAndFlags(Register.ACCUMULATOR, getByteOfMemoryAt(nextProgramWord()));
break;
case LDA_ABS_IY:
registers.setRegisterAndFlags(Register.ACCUMULATOR, getByteOfMemoryYIndexedAt(nextProgramWord()));
break;
case LDA_ABS_IX:
registers.setRegisterAndFlags(Register.ACCUMULATOR, getByteOfMemoryXIndexedAt(nextProgramWord()));
break;
case LDA_IND_IX:
// XXX this needs to be wrappable for zero page addressing
registers.setRegisterAndFlags(Register.ACCUMULATOR, getByteOfMemoryAt(getWordOfMemoryXIndexedAt(nextProgramByte())));
break;
case LDA_IND_IY:
registers.setRegisterAndFlags(Register.ACCUMULATOR, getByteOfMemoryAt(getIndirectYPointer()));
break;
case AND_Z:
withRegisterAndByteAt(Register.ACCUMULATOR, nextProgramByte(), this::performAND);
break;
case AND_ABS:
withRegisterAndByteAt(Register.ACCUMULATOR, nextProgramWord(), this::performAND);
break;
case AND_I:
withRegisterAndByte(Register.ACCUMULATOR, nextProgramByte(), this::performAND);
break;
case AND_Z_IX:
withRegisterAndByteXIndexedAt(Register.ACCUMULATOR, nextProgramByte(), this::performAND);
break;
case AND_ABS_IX:
withRegisterAndByteXIndexedAt(Register.ACCUMULATOR, nextProgramWord(), this::performAND);
break;
case AND_ABS_IY:
withRegisterAndByteYIndexedAt(Register.ACCUMULATOR, nextProgramWord(), this::performAND);
break;
case AND_IND_IX:
withRegisterAndByteAt(Register.ACCUMULATOR, getWordOfMemoryXIndexedAt(nextProgramByte()), this::performAND);
break;
case AND_IND_IY:
withRegisterAndByteAt(Register.ACCUMULATOR, getIndirectYPointer(), this::performAND);
break;
case BIT_Z:
performBIT(getByteOfMemoryAt(nextProgramByte()));
break;
case BIT_ABS:
performBIT(getByteOfMemoryAt(nextProgramWord()));
break;
case ORA_I:
withRegisterAndByte(Register.ACCUMULATOR, nextProgramByte(), this::performORA);
break;
case ORA_Z:
withRegisterAndByteAt(Register.ACCUMULATOR, nextProgramByte(), this::performORA);
break;
case ORA_Z_IX:
withRegisterAndByteXIndexedAt(Register.ACCUMULATOR, nextProgramByte(), this::performORA);
break;
case ORA_ABS:
withRegisterAndByteAt(Register.ACCUMULATOR, nextProgramWord(), this::performORA);
break;
case ORA_ABS_IX:
withRegisterAndByteXIndexedAt(Register.ACCUMULATOR, nextProgramWord(), this::performORA);
break;
case ORA_ABS_IY:
withRegisterAndByteYIndexedAt(Register.ACCUMULATOR, nextProgramWord(), this::performORA);
break;
case ORA_IND_IX:
withRegisterAndByteAt(Register.ACCUMULATOR, getWordOfMemoryXIndexedAt(nextProgramByte()), this::performORA);
break;
case ORA_IND_IY:
withRegisterAndByteAt(Register.ACCUMULATOR, getIndirectYPointer(), this::performORA);
break;
case EOR_I:
withRegisterAndByte(Register.ACCUMULATOR, nextProgramByte(), this::performEOR);
break;
case EOR_Z:
withRegisterAndByteAt(Register.ACCUMULATOR, nextProgramByte(), this::performEOR);
break;
case EOR_Z_IX:
withRegisterAndByteXIndexedAt(Register.ACCUMULATOR, nextProgramByte(), this::performEOR);
break;
case EOR_ABS:
withRegisterAndByteAt(Register.ACCUMULATOR, nextProgramWord(), this::performEOR);
break;
case EOR_ABS_IX:
withRegisterAndByteXIndexedAt(Register.ACCUMULATOR, nextProgramWord(), this::performEOR);
break;
case EOR_ABS_IY:
withRegisterAndByteYIndexedAt(Register.ACCUMULATOR, nextProgramWord(), this::performEOR);
break;
case EOR_IND_IX:
withRegisterAndByteAt(Register.ACCUMULATOR, getWordOfMemoryXIndexedAt(nextProgramByte()), this::performEOR);
break;
case EOR_IND_IY:
withRegisterAndByteAt(Register.ACCUMULATOR, getIndirectYPointer(), this::performEOR);
break;
case ADC_Z:
withRegisterAndByteAt(Register.ACCUMULATOR, nextProgramByte(), this::performADC);
break;
case ADC_I:
withRegisterAndByte(Register.ACCUMULATOR, nextProgramByte(), this::performADC);
break;
case ADC_ABS:
withRegisterAndByteAt(Register.ACCUMULATOR, nextProgramWord(), this::performADC);
break;
case ADC_ABS_IX:
withRegisterAndByteXIndexedAt(Register.ACCUMULATOR, nextProgramWord(), this::performADC);
break;
case ADC_ABS_IY:
withRegisterAndByteYIndexedAt(Register.ACCUMULATOR, nextProgramWord(), this::performADC);
break;
case ADC_Z_IX:
withRegisterAndByteXIndexedAt(Register.ACCUMULATOR, nextProgramByte(), this::performADC);
break;
case ADC_IND_IX:
withRegisterAndByteAt(Register.ACCUMULATOR, getWordOfMemoryXIndexedAt(nextProgramByte()), this::performADC);
break;
case ADC_IND_IY:
withRegisterAndByteAt(Register.ACCUMULATOR, getIndirectYPointer(), this::performADC);
break;
case CMP_I:
performCMP(nextProgramByte(), Register.ACCUMULATOR);
break;
case CMP_Z:
performCMP(getByteOfMemoryAt(nextProgramByte()), Register.ACCUMULATOR);
break;
case CMP_Z_IX:
performCMP(getByteOfMemoryXIndexedAt(nextProgramByte()), Register.ACCUMULATOR);
break;
case CMP_ABS:
performCMP(getByteOfMemoryAt(nextProgramWord()), Register.ACCUMULATOR);
break;
case CMP_ABS_IX:
performCMP(getByteOfMemoryXIndexedAt(nextProgramWord()), Register.ACCUMULATOR);
break;
case CMP_ABS_IY:
performCMP(getByteOfMemoryYIndexedAt(nextProgramWord()), Register.ACCUMULATOR);
break;
case CMP_IND_IX:
performCMP(getByteOfMemoryAt(getWordOfMemoryXIndexedAt(nextProgramByte())), Register.ACCUMULATOR);
break;
case CMP_IND_IY:
performCMP(getByteOfMemoryAt(getIndirectYPointer()), Register.ACCUMULATOR);
break;
case CPX_I:
performCMP(nextProgramByte(), Register.X_INDEX);
break;
case CPX_Z:
performCMP(getByteOfMemoryAt(nextProgramByte()), Register.X_INDEX);
break;
case CPX_ABS:
performCMP(getByteOfMemoryAt(nextProgramWord()), Register.X_INDEX);
break;
case CPY_I:
performCMP(nextProgramByte(), Register.Y_INDEX);
break;
case CPY_Z:
performCMP(getByteOfMemoryAt(nextProgramByte()), Register.Y_INDEX);
break;
case CPY_ABS:
performCMP(getByteOfMemoryAt(nextProgramWord()), Register.Y_INDEX);
break;
case SBC_I:
withRegisterAndByte(Register.ACCUMULATOR, nextProgramByte(), this::performSBC);
break;
case SBC_Z:
withRegisterAndByteAt(Register.ACCUMULATOR, nextProgramByte(), this::performSBC);
break;
case SBC_Z_IX:
withRegisterAndByteXIndexedAt(Register.ACCUMULATOR, nextProgramByte(), this::performSBC);
break;
case SBC_ABS:
withRegisterAndByteAt(Register.ACCUMULATOR, nextProgramWord(), this::performSBC);
break;
case SBC_ABS_IX:
withRegisterAndByteXIndexedAt(Register.ACCUMULATOR, nextProgramWord(), this::performSBC);
break;
case SBC_ABS_IY:
withRegisterAndByteYIndexedAt(Register.ACCUMULATOR, nextProgramWord(), this::performSBC);
break;
case SBC_IND_IX:
withRegisterAndByteAt(Register.ACCUMULATOR, getWordOfMemoryXIndexedAt(nextProgramByte()), this::performSBC);
break;
case SBC_IND_IY:
withRegisterAndByteAt(Register.ACCUMULATOR, getIndirectYPointer(), this::performSBC);
break;
case STY_Z:
setByteOfMemoryAt(nextProgramByte(), getRegisterValue(Register.Y_INDEX));
break;
case STY_ABS:
setByteOfMemoryAt(nextProgramWord(), getRegisterValue(Register.Y_INDEX));
break;
case STY_Z_IX:
setByteOfMemoryXIndexedAt(nextProgramByte(), getRegisterValue(Register.Y_INDEX));
break;
case STA_Z:
setByteOfMemoryAt(nextProgramByte(), getRegisterValue(Register.ACCUMULATOR));
break;
case STA_ABS:
setByteOfMemoryAt(nextProgramWord(), getRegisterValue(Register.ACCUMULATOR));
break;
case STA_Z_IX:
setByteOfMemoryXIndexedAt(nextProgramByte(), getRegisterValue(Register.ACCUMULATOR));
break;
case STA_ABS_IX:
setByteOfMemoryXIndexedAt(nextProgramWord(), getRegisterValue(Register.ACCUMULATOR));
break;
case STA_ABS_IY:
setByteOfMemoryYIndexedAt(nextProgramWord(), getRegisterValue(Register.ACCUMULATOR));
break;
case STA_IND_IX:
setByteOfMemoryAt(getWordOfMemoryXIndexedAt(nextProgramByte()), getRegisterValue(Register.ACCUMULATOR));
break;
case STA_IND_IY:
setByteOfMemoryAt(getIndirectYPointer(), getRegisterValue(Register.ACCUMULATOR));
break;
case STX_Z:
setByteOfMemoryAt(nextProgramByte(), getRegisterValue(Register.X_INDEX));
break;
case STX_Z_IY:
setByteOfMemoryYIndexedAt(nextProgramByte(), getRegisterValue(Register.X_INDEX));
break;
case STX_ABS:
setByteOfMemoryAt(nextProgramWord(), getRegisterValue(Register.X_INDEX));
break;
case PHA:
pushRegister(Register.ACCUMULATOR);
break;
case PLA:
registers.setRegisterAndFlags(Register.ACCUMULATOR, pop());
break;
case PHP:
pushRegister(Register.STATUS_FLAGS);
break;
case PLP:
registers.setRegister(Register.STATUS_FLAGS, pop());
break;
case JMP_ABS:
final RoxWord absoluteAddress = RoxWord.literalFrom(nextProgramWord());
setRegisterValue(Register.PROGRAM_COUNTER_HI, absoluteAddress.getHighByte().getAsInt());
setRegisterValue(Register.PROGRAM_COUNTER_LOW, absoluteAddress.getLowByte().getAsInt());
break;
case JMP_IND:
final RoxWord indirectAddress = RoxWord.literalFrom(nextProgramWord());
// XXX Why does't this work by just using nextProgramWord
registers.setPC(getWordOfMemoryAt(indirectAddress.getAsInt()));
break;
case BCS:
branchIf(registers.getFlag(Flag.CARRY));
break;
case BCC:
branchIf(!registers.getFlag(Flag.CARRY));
break;
case BEQ:
branchIf(registers.getFlag(Flag.ZERO));
break;
case BNE:
branchIf(!registers.getFlag(Flag.ZERO));
break;
case BMI:
branchIf(registers.getFlag(Flag.NEGATIVE));
break;
case JSR:
int hi = nextProgramByte();
int lo = nextProgramByte();
pushRegister(Register.PROGRAM_COUNTER_HI);
pushRegister(Register.PROGRAM_COUNTER_LOW);
setRegisterValue(Register.PROGRAM_COUNTER_HI, hi);
setRegisterValue(Register.PROGRAM_COUNTER_LOW, lo);
break;
case BPL:
branchIf(!registers.getFlag(Flag.NEGATIVE));
break;
case BVS:
branchIf(registers.getFlag(Flag.OVERFLOW));
break;
case BVC:
branchIf(!registers.getFlag(Flag.OVERFLOW));
break;
case TAX:
setRegisterValue(Register.X_INDEX, getRegisterValue(Register.ACCUMULATOR));
break;
case TAY:
setRegisterValue(Register.Y_INDEX, getRegisterValue(Register.ACCUMULATOR));
break;
case TYA:
setRegisterValue(Register.ACCUMULATOR, getRegisterValue(Register.Y_INDEX));
break;
case TXA:
setRegisterValue(Register.ACCUMULATOR, getRegisterValue(Register.X_INDEX));
break;
case TXS:
setRegisterValue(Register.STACK_POINTER_HI, getRegisterValue(Register.X_INDEX));
break;
case TSX:
setRegisterValue(Register.X_INDEX, getRegisterValue(Register.STACK_POINTER_HI));
registers.setFlagsBasedOn(getRegisterValue(Register.X_INDEX));
break;
case NOP:
// Do nothing
break;
case SEI:
registers.setFlag(Flag.IRQ_DISABLE);
break;
case CLI:
registers.clearFlag(Flag.IRQ_DISABLE);
break;
case SED:
registers.setFlag(Flag.DECIMAL_MODE);
break;
case CLD:
registers.clearFlag(Flag.DECIMAL_MODE);
break;
case RTS:
setRegisterValue(Register.PROGRAM_COUNTER_LOW, pop());
setRegisterValue(Register.PROGRAM_COUNTER_HI, pop());
break;
case RTI:
setRegisterValue(Register.STATUS_FLAGS, pop());
setRegisterValue(Register.PROGRAM_COUNTER_LOW, pop());
setRegisterValue(Register.PROGRAM_COUNTER_HI, pop());
break;
case BRK:
default:
// XXX Why do we do this at all? A program of [BRK] will push 0x03 as the PC...why is that right?
registers.setPC(performSilently(this::performADC, registers.getPC(), 2, false));
push(registers.getRegister(Register.PROGRAM_COUNTER_HI));
push(registers.getRegister(Register.PROGRAM_COUNTER_LOW));
push(registers.getRegister(Register.STATUS_FLAGS) | Flag.BREAK.getPlaceValue());
registers.setRegister(Register.PROGRAM_COUNTER_HI, getByteOfMemoryAt(0xFFFE));
registers.setRegister(Register.PROGRAM_COUNTER_LOW, getByteOfMemoryAt(0xFFFF));
break;
}
}
use of com.rox.emu.processor.mos6502.util.Program in project emuRox by rossdrew.
the class DebuggerWindow method compile.
public void compile(String programText) {
final Mos6502Compiler compiler = new Mos6502Compiler(programText);
try {
final Program program = compiler.compileProgram();
final int[] programAsByteArray = program.getProgramAsByteArray();
loadProgram(programAsByteArray);
} catch (UnknownOpCodeException e) {
JOptionPane.showMessageDialog(this, e.getMessage());
}
}
use of com.rox.emu.processor.mos6502.util.Program in project emuRox by rossdrew.
the class DebuggerWindow method getProgram.
private int[] getProgram() {
int data_offset = 0x32;
int MPD = data_offset + 0x10;
int MPR = data_offset + 0x11;
int TMP = data_offset + 0x20;
int RESAD_0 = data_offset + 0x30;
int RESAD_1 = data_offset + 0x31;
int valMPD = 7;
int valMPR = 4;
// Program countToTenProgram = new Program().with( OpCode.LDX_I, 10,
// OpCode.LDA_I, 0,
// OpCode.CLC,
// OpCode.ADC_I, 0x01,
// OpCode.DEX,
// OpCode.CPX_I, 0,
// OpCode.BNE, 0b11110111);
Program multiplicationProgram = new Program().with(OpCode.LDA_I, valMPD, OpCode.STA_Z, MPD, OpCode.LDA_I, valMPR, OpCode.STA_Z, MPR, // <---- start
OpCode.LDA_I, // <---- start
0, // Clear
OpCode.STA_Z, // Clear
TMP, // ...
OpCode.STA_Z, // ...
RESAD_0, // ...
OpCode.STA_Z, // ...
RESAD_1, // X counts each bit
OpCode.LDX_I, // X counts each bit
8, // LSR(MPR)
OpCode.LSR_Z, // LSR(MPR)
MPR, // Test carry and jump (forward 13) to NOADD
OpCode.BCC, // Test carry and jump (forward 13) to NOADD
13, // RESAD -> A
OpCode.LDA_Z, // RESAD -> A
RESAD_0, // Prepare to add
OpCode.CLC, // +MPD
OpCode.ADC_Z, // +MPD
MPD, // Save result
OpCode.STA_Z, // Save result
RESAD_0, // RESAD+1 -> A
OpCode.LDA_Z, // RESAD+1 -> A
RESAD_1, // +TMP
OpCode.ADC_Z, // +TMP
TMP, // RESAD+1 <- A
OpCode.STA_Z, // RESAD+1 <- A
RESAD_1, // ASL(MPD)
OpCode.ASL_Z, // ASL(MPD)
MPD, // Save bit from MPD
OpCode.ROL_Z, // Save bit from MPD
TMP, // --X
OpCode.DEX, // Test equal and jump (back 24) to MULT
OpCode.BNE, // Test equal and jump (back 24) to MULT
0b11100111);
return multiplicationProgram.getProgramAsByteArray();
}
Aggregations