use of com.rox.emu.env.RoxWord 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.env.RoxWord in project emuRox by rossdrew.
the class Mos6502Alu method asl.
/**
* Shift bits left and write a zero into the low order bit, setting the carry to whatever
* is shifted out of the high order bit.
*
* @return the result of <code>ASL byteA</code>
*/
public RoxByte asl(RoxByte byteA) {
final RoxWord result = RoxWord.literalFrom((byteA.getRawValue() << 1));
registers.setFlagTo(Registers.Flag.CARRY, result.getHighByte().isBitSet(0));
return result.getLowByte();
}
use of com.rox.emu.env.RoxWord in project emuRox by rossdrew.
the class Mos6502Alu method adc.
/**
* Return the addition of <code>byteA</code>, <code>byteB</code> and the contents of the {@link Registers} carry
* flag.<br/>
* <br>
* The carry flag is used for multi-byte addition, so it should be cleared at the start of any addition
* that doesn't need to take into account a carry from a previous one.
*
* @return the result of <code>byteA ADD byteB</code>
*/
public RoxByte adc(final RoxByte byteA, final RoxByte byteB) {
int carry = registers.getFlag(Registers.Flag.CARRY) ? 1 : 0;
final RoxWord result = RoxWord.literalFrom(byteA.getRawValue() + byteB.getRawValue() + carry);
registers.setFlagTo(Registers.Flag.CARRY, result.getHighByte().isBitSet(0));
if (isAdcOverflow(byteA, byteB, result))
registers.setFlag(Registers.Flag.OVERFLOW);
return result.getLowByte();
}
use of com.rox.emu.env.RoxWord in project emuRox by rossdrew.
the class Mos6502Alu method rol.
/**
* Shift bits left and write the contents of the carry flag into the low order bit, setting
* the carry to whatever is shifted out of the high order bit.
*
* @return the result of <code>ROL byteA</code>
*/
public RoxByte rol(RoxByte byteA) {
int carry = registers.getFlag(Registers.Flag.CARRY) ? 1 : 0;
final RoxWord result = RoxWord.literalFrom((byteA.getRawValue() << 1) + carry);
registers.setFlagTo(Registers.Flag.CARRY, result.getHighByte().isBitSet(0));
return result.getLowByte();
}