Search in sources :

Example 1 with RoxWord

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;
    }
}
Also used : OpCode(com.rox.emu.processor.mos6502.op.OpCode) RoxWord(com.rox.emu.env.RoxWord)

Example 2 with RoxWord

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();
}
Also used : RoxWord(com.rox.emu.env.RoxWord)

Example 3 with RoxWord

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();
}
Also used : RoxWord(com.rox.emu.env.RoxWord)

Example 4 with RoxWord

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();
}
Also used : RoxWord(com.rox.emu.env.RoxWord)

Aggregations

RoxWord (com.rox.emu.env.RoxWord)4 OpCode (com.rox.emu.processor.mos6502.op.OpCode)1