1118 lines
19 KiB
C
1118 lines
19 KiB
C
void Cpu::PowerOn()
|
|
{
|
|
_state = {};
|
|
_state.PC = GetResetVector();
|
|
_state.SP = 0x1FF;
|
|
_state.PS = ProcFlags::IrqDisable;
|
|
_state.EmulationMode = true;
|
|
_state.NmiFlag = false;
|
|
_state.PrevNmiFlag = false;
|
|
_state.StopState = CpuStopState::Running;
|
|
_state.IrqSource = (uint8_t)IrqSource::None;
|
|
_state.PrevIrqSource = (uint8_t)IrqSource::None;
|
|
SetFlags(ProcFlags::MemoryMode8);
|
|
SetFlags(ProcFlags::IndexMode8);
|
|
}
|
|
|
|
void Cpu::Reset()
|
|
{
|
|
SetFlags(ProcFlags::IrqDisable | ProcFlags::MemoryMode8 | ProcFlags::IndexMode8);
|
|
ClearFlags(ProcFlags::Decimal);
|
|
_state.EmulationMode = true;
|
|
|
|
_state.DBR = 0;
|
|
_state.D = 0;
|
|
_state.K = 0;
|
|
_state.Y &= 0xFF;
|
|
_state.X &= 0xFF;
|
|
_state.CycleCount = 0;
|
|
|
|
_state.PC = GetResetVector();
|
|
SetSP(_state.SP);
|
|
|
|
_state.NmiFlag = false;
|
|
_state.PrevNmiFlag = false;
|
|
_state.StopState = CpuStopState::Running;
|
|
_state.IrqSource = (uint8_t)IrqSource::None;
|
|
_state.PrevIrqSource = (uint8_t)IrqSource::None;
|
|
}
|
|
|
|
void Cpu::RunOp()
|
|
{
|
|
switch (GetOpCode())
|
|
{
|
|
case 0x00: AddrMode_Imm8();
|
|
BRK();
|
|
break;
|
|
case 0x01: AddrMode_DirIdxIndX();
|
|
ORA();
|
|
break;
|
|
case 0x02: AddrMode_Imm8();
|
|
COP();
|
|
break;
|
|
case 0x03: AddrMode_StkRel();
|
|
ORA();
|
|
break;
|
|
case 0x04: AddrMode_Dir();
|
|
TSB();
|
|
break;
|
|
case 0x05: AddrMode_Dir();
|
|
ORA();
|
|
break;
|
|
case 0x06: AddrMode_Dir();
|
|
ASL();
|
|
break;
|
|
case 0x07: AddrMode_DirIndLng();
|
|
ORA();
|
|
break;
|
|
case 0x08: PHP();
|
|
break;
|
|
case 0x09: AddrMode_ImmM();
|
|
ORA();
|
|
break;
|
|
case 0x0A: AddrMode_Acc();
|
|
ASL_Acc();
|
|
break;
|
|
case 0x0B: PHD();
|
|
break;
|
|
case 0x0C: AddrMode_Abs();
|
|
TSB();
|
|
break;
|
|
case 0x0D: AddrMode_Abs();
|
|
ORA();
|
|
break;
|
|
case 0x0E: AddrMode_Abs();
|
|
ASL();
|
|
break;
|
|
case 0x0F: AddrMode_AbsLng();
|
|
ORA();
|
|
break;
|
|
case 0x10: AddrMode_Rel();
|
|
BPL();
|
|
break;
|
|
case 0x11: AddrMode_DirIndIdxY(false);
|
|
ORA();
|
|
break;
|
|
case 0x12: AddrMode_DirInd();
|
|
ORA();
|
|
break;
|
|
case 0x13: AddrMode_StkRelIndIdxY();
|
|
ORA();
|
|
break;
|
|
case 0x14: AddrMode_Dir();
|
|
TRB();
|
|
break;
|
|
case 0x15: AddrMode_DirIdxX();
|
|
ORA();
|
|
break;
|
|
case 0x16: AddrMode_DirIdxX();
|
|
ASL();
|
|
break;
|
|
case 0x17: AddrMode_DirIndLngIdxY();
|
|
ORA();
|
|
break;
|
|
case 0x18: AddrMode_Imp();
|
|
CLC();
|
|
break;
|
|
case 0x19: AddrMode_AbsIdxY(false);
|
|
ORA();
|
|
break;
|
|
case 0x1A: AddrMode_Acc();
|
|
INC_Acc();
|
|
break;
|
|
case 0x1B: AddrMode_Imp();
|
|
TCS();
|
|
break;
|
|
case 0x1C: AddrMode_Abs();
|
|
TRB();
|
|
break;
|
|
case 0x1D: AddrMode_AbsIdxX(false);
|
|
ORA();
|
|
break;
|
|
case 0x1E: AddrMode_AbsIdxX(true);
|
|
ASL();
|
|
break;
|
|
case 0x1F: AddrMode_AbsLngIdxX();
|
|
ORA();
|
|
break;
|
|
case 0x20: AddrMode_AbsJmp();
|
|
Idle();
|
|
JSR();
|
|
break;
|
|
case 0x21: AddrMode_DirIdxIndX();
|
|
AND();
|
|
break;
|
|
case 0x22: AddrMode_AbsLngJmp();
|
|
JSL();
|
|
break;
|
|
case 0x23: AddrMode_StkRel();
|
|
AND();
|
|
break;
|
|
case 0x24: AddrMode_Dir();
|
|
BIT();
|
|
break;
|
|
case 0x25: AddrMode_Dir();
|
|
AND();
|
|
break;
|
|
case 0x26: AddrMode_Dir();
|
|
ROL();
|
|
break;
|
|
case 0x27: AddrMode_DirIndLng();
|
|
AND();
|
|
break;
|
|
case 0x28: PLP();
|
|
break;
|
|
case 0x29: AddrMode_ImmM();
|
|
AND();
|
|
break;
|
|
case 0x2A: AddrMode_Acc();
|
|
ROL_Acc();
|
|
break;
|
|
case 0x2B: PLD();
|
|
break;
|
|
case 0x2C: AddrMode_Abs();
|
|
BIT();
|
|
break;
|
|
case 0x2D: AddrMode_Abs();
|
|
AND();
|
|
break;
|
|
case 0x2E: AddrMode_Abs();
|
|
ROL();
|
|
break;
|
|
case 0x2F: AddrMode_AbsLng();
|
|
AND();
|
|
break;
|
|
case 0x30: AddrMode_Rel();
|
|
BMI();
|
|
break;
|
|
case 0x31: AddrMode_DirIndIdxY(false);
|
|
AND();
|
|
break;
|
|
case 0x32: AddrMode_DirInd();
|
|
AND();
|
|
break;
|
|
case 0x33: AddrMode_StkRelIndIdxY();
|
|
AND();
|
|
break;
|
|
case 0x34: AddrMode_DirIdxX();
|
|
BIT();
|
|
break;
|
|
case 0x35: AddrMode_DirIdxX();
|
|
AND();
|
|
break;
|
|
case 0x36: AddrMode_DirIdxX();
|
|
ROL();
|
|
break;
|
|
case 0x37: AddrMode_DirIndLngIdxY();
|
|
AND();
|
|
break;
|
|
case 0x38: AddrMode_Imp();
|
|
SEC();
|
|
break;
|
|
case 0x39: AddrMode_AbsIdxY(false);
|
|
AND();
|
|
break;
|
|
case 0x3A: AddrMode_Acc();
|
|
DEC_Acc();
|
|
break;
|
|
case 0x3B: AddrMode_Imp();
|
|
TSC();
|
|
break;
|
|
case 0x3C: AddrMode_AbsIdxX(false);
|
|
BIT();
|
|
break;
|
|
case 0x3D: AddrMode_AbsIdxX(false);
|
|
AND();
|
|
break;
|
|
case 0x3E: AddrMode_AbsIdxX(true);
|
|
ROL();
|
|
break;
|
|
case 0x3F: AddrMode_AbsLngIdxX();
|
|
AND();
|
|
break;
|
|
case 0x40: RTI();
|
|
break;
|
|
case 0x41: AddrMode_DirIdxIndX();
|
|
EOR();
|
|
break;
|
|
case 0x42: AddrMode_Imm8();
|
|
WDM();
|
|
break;
|
|
case 0x43: AddrMode_StkRel();
|
|
EOR();
|
|
break;
|
|
case 0x44: AddrMode_BlkMov();
|
|
MVP();
|
|
break;
|
|
case 0x45: AddrMode_Dir();
|
|
EOR();
|
|
break;
|
|
case 0x46: AddrMode_Dir();
|
|
LSR();
|
|
break;
|
|
case 0x47: AddrMode_DirIndLng();
|
|
EOR();
|
|
break;
|
|
case 0x48: PHA();
|
|
break;
|
|
case 0x49: AddrMode_ImmM();
|
|
EOR();
|
|
break;
|
|
case 0x4A: AddrMode_Acc();
|
|
LSR_Acc();
|
|
break;
|
|
case 0x4B: PHK();
|
|
break;
|
|
case 0x4C: AddrMode_AbsJmp();
|
|
JMP();
|
|
break;
|
|
case 0x4D: AddrMode_Abs();
|
|
EOR();
|
|
break;
|
|
case 0x4E: AddrMode_Abs();
|
|
LSR();
|
|
break;
|
|
case 0x4F: AddrMode_AbsLng();
|
|
EOR();
|
|
break;
|
|
case 0x50: AddrMode_Rel();
|
|
BVC();
|
|
break;
|
|
case 0x51: AddrMode_DirIndIdxY(false);
|
|
EOR();
|
|
break;
|
|
case 0x52: AddrMode_DirInd();
|
|
EOR();
|
|
break;
|
|
case 0x53: AddrMode_StkRelIndIdxY();
|
|
EOR();
|
|
break;
|
|
case 0x54: AddrMode_BlkMov();
|
|
MVN();
|
|
break;
|
|
case 0x55: AddrMode_DirIdxX();
|
|
EOR();
|
|
break;
|
|
case 0x56: AddrMode_DirIdxX();
|
|
LSR();
|
|
break;
|
|
case 0x57: AddrMode_DirIndLngIdxY();
|
|
EOR();
|
|
break;
|
|
case 0x58: AddrMode_Imp();
|
|
CLI();
|
|
break;
|
|
case 0x59: AddrMode_AbsIdxY(false);
|
|
EOR();
|
|
break;
|
|
case 0x5A: PHY();
|
|
break;
|
|
case 0x5B: AddrMode_Imp();
|
|
TCD();
|
|
break;
|
|
case 0x5C: AddrMode_AbsLngJmp();
|
|
JML();
|
|
break;
|
|
case 0x5D: AddrMode_AbsIdxX(false);
|
|
EOR();
|
|
break;
|
|
case 0x5E: AddrMode_AbsIdxX(true);
|
|
LSR();
|
|
break;
|
|
case 0x5F: AddrMode_AbsLngIdxX();
|
|
EOR();
|
|
break;
|
|
case 0x60: RTS();
|
|
break;
|
|
case 0x61: AddrMode_DirIdxIndX();
|
|
ADC();
|
|
break;
|
|
case 0x62: AddrMode_RelLng();
|
|
PER();
|
|
break;
|
|
case 0x63: AddrMode_StkRel();
|
|
ADC();
|
|
break;
|
|
case 0x64: AddrMode_Dir();
|
|
STZ();
|
|
break;
|
|
case 0x65: AddrMode_Dir();
|
|
ADC();
|
|
break;
|
|
case 0x66: AddrMode_Dir();
|
|
ROR();
|
|
break;
|
|
case 0x67: AddrMode_DirIndLng();
|
|
ADC();
|
|
break;
|
|
case 0x68: PLA();
|
|
break;
|
|
case 0x69: AddrMode_ImmM();
|
|
ADC();
|
|
break;
|
|
case 0x6A: AddrMode_Acc();
|
|
ROR_Acc();
|
|
break;
|
|
case 0x6B: RTL();
|
|
break;
|
|
case 0x6C: AddrMode_AbsInd();
|
|
JMP();
|
|
break;
|
|
case 0x6D: AddrMode_Abs();
|
|
ADC();
|
|
break;
|
|
case 0x6E: AddrMode_Abs();
|
|
ROR();
|
|
break;
|
|
case 0x6F: AddrMode_AbsLng();
|
|
ADC();
|
|
break;
|
|
case 0x70: AddrMode_Rel();
|
|
BVS();
|
|
break;
|
|
case 0x71: AddrMode_DirIndIdxY(false);
|
|
ADC();
|
|
break;
|
|
case 0x72: AddrMode_DirInd();
|
|
ADC();
|
|
break;
|
|
case 0x73: AddrMode_StkRelIndIdxY();
|
|
ADC();
|
|
break;
|
|
case 0x74: AddrMode_DirIdxX();
|
|
STZ();
|
|
break;
|
|
case 0x75: AddrMode_DirIdxX();
|
|
ADC();
|
|
break;
|
|
case 0x76: AddrMode_DirIdxX();
|
|
ROR();
|
|
break;
|
|
case 0x77: AddrMode_DirIndLngIdxY();
|
|
ADC();
|
|
break;
|
|
case 0x78: AddrMode_Imp();
|
|
SEI();
|
|
break;
|
|
case 0x79: AddrMode_AbsIdxY(false);
|
|
ADC();
|
|
break;
|
|
case 0x7A: PLY();
|
|
break;
|
|
case 0x7B: AddrMode_Imp();
|
|
TDC();
|
|
break;
|
|
case 0x7C: AddrMode_AbsIdxXInd();
|
|
JMP();
|
|
break;
|
|
case 0x7D: AddrMode_AbsIdxX(false);
|
|
ADC();
|
|
break;
|
|
case 0x7E: AddrMode_AbsIdxX(true);
|
|
ROR();
|
|
break;
|
|
case 0x7F: AddrMode_AbsLngIdxX();
|
|
ADC();
|
|
break;
|
|
case 0x80: AddrMode_Rel();
|
|
BRA();
|
|
break;
|
|
case 0x81: AddrMode_DirIdxIndX();
|
|
STA();
|
|
break;
|
|
case 0x82: AddrMode_RelLng();
|
|
BRL();
|
|
break;
|
|
case 0x83: AddrMode_StkRel();
|
|
STA();
|
|
break;
|
|
case 0x84: AddrMode_Dir();
|
|
STY();
|
|
break;
|
|
case 0x85: AddrMode_Dir();
|
|
STA();
|
|
break;
|
|
case 0x86: AddrMode_Dir();
|
|
STX();
|
|
break;
|
|
case 0x87: AddrMode_DirIndLng();
|
|
STA();
|
|
break;
|
|
case 0x88: AddrMode_Imp();
|
|
DEY();
|
|
break;
|
|
case 0x89: AddrMode_ImmM();
|
|
BIT();
|
|
break;
|
|
case 0x8A: AddrMode_Imp();
|
|
TXA();
|
|
break;
|
|
case 0x8B: PHB();
|
|
break;
|
|
case 0x8C: AddrMode_Abs();
|
|
STY();
|
|
break;
|
|
case 0x8D: AddrMode_Abs();
|
|
STA();
|
|
break;
|
|
case 0x8E: AddrMode_Abs();
|
|
STX();
|
|
break;
|
|
case 0x8F: AddrMode_AbsLng();
|
|
STA();
|
|
break;
|
|
case 0x90: AddrMode_Rel();
|
|
BCC();
|
|
break;
|
|
case 0x91: AddrMode_DirIndIdxY(true);
|
|
STA();
|
|
break;
|
|
case 0x92: AddrMode_DirInd();
|
|
STA();
|
|
break;
|
|
case 0x93: AddrMode_StkRelIndIdxY();
|
|
STA();
|
|
break;
|
|
case 0x94: AddrMode_DirIdxX();
|
|
STY();
|
|
break;
|
|
case 0x95: AddrMode_DirIdxX();
|
|
STA();
|
|
break;
|
|
case 0x96: AddrMode_DirIdxY();
|
|
STX();
|
|
break;
|
|
case 0x97: AddrMode_DirIndLngIdxY();
|
|
STA();
|
|
break;
|
|
case 0x98: AddrMode_Imp();
|
|
TYA();
|
|
break;
|
|
case 0x99: AddrMode_AbsIdxY(true);
|
|
STA();
|
|
break;
|
|
case 0x9A: AddrMode_Imp();
|
|
TXS();
|
|
break;
|
|
case 0x9B: AddrMode_Imp();
|
|
TXY();
|
|
break;
|
|
case 0x9C: AddrMode_Abs();
|
|
STZ();
|
|
break;
|
|
case 0x9D: AddrMode_AbsIdxX(true);
|
|
STA();
|
|
break;
|
|
case 0x9E: AddrMode_AbsIdxX(true);
|
|
STZ();
|
|
break;
|
|
case 0x9F: AddrMode_AbsLngIdxX();
|
|
STA();
|
|
break;
|
|
case 0xA0: AddrMode_ImmX();
|
|
LDY();
|
|
break;
|
|
case 0xA1: AddrMode_DirIdxIndX();
|
|
LDA();
|
|
break;
|
|
case 0xA2: AddrMode_ImmX();
|
|
LDX();
|
|
break;
|
|
case 0xA3: AddrMode_StkRel();
|
|
LDA();
|
|
break;
|
|
case 0xA4: AddrMode_Dir();
|
|
LDY();
|
|
break;
|
|
case 0xA5: AddrMode_Dir();
|
|
LDA();
|
|
break;
|
|
case 0xA6: AddrMode_Dir();
|
|
LDX();
|
|
break;
|
|
case 0xA7: AddrMode_DirIndLng();
|
|
LDA();
|
|
break;
|
|
case 0xA8: AddrMode_Imp();
|
|
TAY();
|
|
break;
|
|
case 0xA9: AddrMode_ImmM();
|
|
LDA();
|
|
break;
|
|
case 0xAA: AddrMode_Imp();
|
|
TAX();
|
|
break;
|
|
case 0xAB: PLB();
|
|
break;
|
|
case 0xAC: AddrMode_Abs();
|
|
LDY();
|
|
break;
|
|
case 0xAD: AddrMode_Abs();
|
|
LDA();
|
|
break;
|
|
case 0xAE: AddrMode_Abs();
|
|
LDX();
|
|
break;
|
|
case 0xAF: AddrMode_AbsLng();
|
|
LDA();
|
|
break;
|
|
case 0xB0: AddrMode_Rel();
|
|
BCS();
|
|
break;
|
|
case 0xB1: AddrMode_DirIndIdxY(false);
|
|
LDA();
|
|
break;
|
|
case 0xB2: AddrMode_DirInd();
|
|
LDA();
|
|
break;
|
|
case 0xB3: AddrMode_StkRelIndIdxY();
|
|
LDA();
|
|
break;
|
|
case 0xB4: AddrMode_DirIdxX();
|
|
LDY();
|
|
break;
|
|
case 0xB5: AddrMode_DirIdxX();
|
|
LDA();
|
|
break;
|
|
case 0xB6: AddrMode_DirIdxY();
|
|
LDX();
|
|
break;
|
|
case 0xB7: AddrMode_DirIndLngIdxY();
|
|
LDA();
|
|
break;
|
|
case 0xB8: AddrMode_Imp();
|
|
CLV();
|
|
break;
|
|
case 0xB9: AddrMode_AbsIdxY(false);
|
|
LDA();
|
|
break;
|
|
case 0xBA: AddrMode_Imp();
|
|
TSX();
|
|
break;
|
|
case 0xBB: AddrMode_Imp();
|
|
TYX();
|
|
break;
|
|
case 0xBC: AddrMode_AbsIdxX(false);
|
|
LDY();
|
|
break;
|
|
case 0xBD: AddrMode_AbsIdxX(false);
|
|
LDA();
|
|
break;
|
|
case 0xBE: AddrMode_AbsIdxY(false);
|
|
LDX();
|
|
break;
|
|
case 0xBF: AddrMode_AbsLngIdxX();
|
|
LDA();
|
|
break;
|
|
case 0xC0: AddrMode_ImmX();
|
|
CPY();
|
|
break;
|
|
case 0xC1: AddrMode_DirIdxIndX();
|
|
CMP();
|
|
break;
|
|
case 0xC2: AddrMode_Imm8();
|
|
REP();
|
|
break;
|
|
case 0xC3: AddrMode_StkRel();
|
|
CMP();
|
|
break;
|
|
case 0xC4: AddrMode_Dir();
|
|
CPY();
|
|
break;
|
|
case 0xC5: AddrMode_Dir();
|
|
CMP();
|
|
break;
|
|
case 0xC6: AddrMode_Dir();
|
|
DEC();
|
|
break;
|
|
case 0xC7: AddrMode_DirIndLng();
|
|
CMP();
|
|
break;
|
|
case 0xC8: AddrMode_Imp();
|
|
INY();
|
|
break;
|
|
case 0xC9: AddrMode_ImmM();
|
|
CMP();
|
|
break;
|
|
case 0xCA: AddrMode_Imp();
|
|
DEX();
|
|
break;
|
|
case 0xCB: AddrMode_Imp();
|
|
WAI();
|
|
break;
|
|
case 0xCC: AddrMode_Abs();
|
|
CPY();
|
|
break;
|
|
case 0xCD: AddrMode_Abs();
|
|
CMP();
|
|
break;
|
|
case 0xCE: AddrMode_Abs();
|
|
DEC();
|
|
break;
|
|
case 0xCF: AddrMode_AbsLng();
|
|
CMP();
|
|
break;
|
|
case 0xD0: AddrMode_Rel();
|
|
BNE();
|
|
break;
|
|
case 0xD1: AddrMode_DirIndIdxY(false);
|
|
CMP();
|
|
break;
|
|
case 0xD2: AddrMode_DirInd();
|
|
CMP();
|
|
break;
|
|
case 0xD3: AddrMode_StkRelIndIdxY();
|
|
CMP();
|
|
break;
|
|
case 0xD4: AddrMode_Dir();
|
|
PEI();
|
|
break;
|
|
case 0xD5: AddrMode_DirIdxX();
|
|
CMP();
|
|
break;
|
|
case 0xD6: AddrMode_DirIdxX();
|
|
DEC();
|
|
break;
|
|
case 0xD7: AddrMode_DirIndLngIdxY();
|
|
CMP();
|
|
break;
|
|
case 0xD8: AddrMode_Imp();
|
|
CLD();
|
|
break;
|
|
case 0xD9: AddrMode_AbsIdxY(false);
|
|
CMP();
|
|
break;
|
|
case 0xDA: PHX();
|
|
break;
|
|
case 0xDB: AddrMode_Imp();
|
|
STP();
|
|
break;
|
|
case 0xDC: AddrMode_AbsIndLng();
|
|
JML();
|
|
break;
|
|
case 0xDD: AddrMode_AbsIdxX(false);
|
|
CMP();
|
|
break;
|
|
case 0xDE: AddrMode_AbsIdxX(true);
|
|
DEC();
|
|
break;
|
|
case 0xDF: AddrMode_AbsLngIdxX();
|
|
CMP();
|
|
break;
|
|
case 0xE0: AddrMode_ImmX();
|
|
CPX();
|
|
break;
|
|
case 0xE1: AddrMode_DirIdxIndX();
|
|
SBC();
|
|
break;
|
|
case 0xE2: AddrMode_Imm8();
|
|
SEP();
|
|
break;
|
|
case 0xE3: AddrMode_StkRel();
|
|
SBC();
|
|
break;
|
|
case 0xE4: AddrMode_Dir();
|
|
CPX();
|
|
break;
|
|
case 0xE5: AddrMode_Dir();
|
|
SBC();
|
|
break;
|
|
case 0xE6: AddrMode_Dir();
|
|
INC();
|
|
break;
|
|
case 0xE7: AddrMode_DirIndLng();
|
|
SBC();
|
|
break;
|
|
case 0xE8: AddrMode_Imp();
|
|
INX();
|
|
break;
|
|
case 0xE9: AddrMode_ImmM();
|
|
SBC();
|
|
break;
|
|
case 0xEA: AddrMode_Imp();
|
|
NOP();
|
|
break;
|
|
case 0xEB: AddrMode_Imp();
|
|
XBA();
|
|
break;
|
|
case 0xEC: AddrMode_Abs();
|
|
CPX();
|
|
break;
|
|
case 0xED: AddrMode_Abs();
|
|
SBC();
|
|
break;
|
|
case 0xEE: AddrMode_Abs();
|
|
INC();
|
|
break;
|
|
case 0xEF: AddrMode_AbsLng();
|
|
SBC();
|
|
break;
|
|
case 0xF0: AddrMode_Rel();
|
|
BEQ();
|
|
break;
|
|
case 0xF1: AddrMode_DirIndIdxY(false);
|
|
SBC();
|
|
break;
|
|
case 0xF2: AddrMode_DirInd();
|
|
SBC();
|
|
break;
|
|
case 0xF3: AddrMode_StkRelIndIdxY();
|
|
SBC();
|
|
break;
|
|
case 0xF4: AddrMode_Imm16();
|
|
PEA();
|
|
break;
|
|
case 0xF5: AddrMode_DirIdxX();
|
|
SBC();
|
|
break;
|
|
case 0xF6: AddrMode_DirIdxX();
|
|
INC();
|
|
break;
|
|
case 0xF7: AddrMode_DirIndLngIdxY();
|
|
SBC();
|
|
break;
|
|
case 0xF8: AddrMode_Imp();
|
|
SED();
|
|
break;
|
|
case 0xF9: AddrMode_AbsIdxY(false);
|
|
SBC();
|
|
break;
|
|
case 0xFA: PLX();
|
|
break;
|
|
case 0xFB: AddrMode_Imp();
|
|
XCE();
|
|
break;
|
|
case 0xFC: AddrMode_AbsIdxXInd();
|
|
JSR();
|
|
break;
|
|
case 0xFD: AddrMode_AbsIdxX(false);
|
|
SBC();
|
|
break;
|
|
case 0xFE: AddrMode_AbsIdxX(true);
|
|
INC();
|
|
break;
|
|
case 0xFF: AddrMode_AbsLngIdxX();
|
|
SBC();
|
|
break;
|
|
}
|
|
}
|
|
|
|
CpuState Cpu::GetState()
|
|
{
|
|
return _state;
|
|
}
|
|
|
|
uint64_t Cpu::GetCycleCount()
|
|
{
|
|
return _state.CycleCount;
|
|
}
|
|
|
|
void Cpu::SetNmiFlag(bool nmiFlag)
|
|
{
|
|
_state.NmiFlag = nmiFlag;
|
|
}
|
|
|
|
void Cpu::DetectNmiSignalEdge()
|
|
{
|
|
//"This edge detector polls the status of the NMI line during φ2 of each CPU cycle (i.e., during the
|
|
//second half of each cycle) and raises an internal signal if the input goes from being high during
|
|
//one cycle to being low during the next"
|
|
if (!_state.PrevNmiFlag && _state.NmiFlag)
|
|
{
|
|
_state.NeedNmi = true;
|
|
}
|
|
_state.PrevNmiFlag = _state.NmiFlag;
|
|
}
|
|
|
|
void Cpu::UpdateIrqNmiFlags()
|
|
{
|
|
if (!_state.IrqLock)
|
|
{
|
|
//"The internal signal goes high during φ1 of the cycle that follows the one where the edge is detected,
|
|
//and stays high until the NMI has been handled. "
|
|
_state.PrevNeedNmi = _state.NeedNmi;
|
|
_state.PrevIrqSource = _state.IrqSource && !CheckFlag(ProcFlags::IrqDisable);
|
|
}
|
|
_state.IrqLock = false;
|
|
}
|
|
|
|
void Cpu::SetIrqSource(IrqSource source)
|
|
{
|
|
_state.IrqSource |= (uint8_t)source;
|
|
}
|
|
|
|
bool Cpu::CheckIrqSource(IrqSource source)
|
|
{
|
|
if (_state.IrqSource & (uint8_t)source)
|
|
{
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
void Cpu::ClearIrqSource(IrqSource source)
|
|
{
|
|
_state.IrqSource &= ~(uint8_t)source;
|
|
}
|
|
|
|
uint32_t Cpu::GetProgramAddress(uint16_t addr)
|
|
{
|
|
return (_state.K << 16) | addr;
|
|
}
|
|
|
|
uint32_t Cpu::GetDataAddress(uint16_t addr)
|
|
{
|
|
return (_state.DBR << 16) | addr;
|
|
}
|
|
|
|
uint8_t Cpu::GetOpCode()
|
|
{
|
|
uint8_t opCode = ReadCode(_state.PC, MemoryOperationType::ExecOpCode);
|
|
_state.PC++;
|
|
return opCode;
|
|
}
|
|
|
|
void Cpu::IdleOrRead()
|
|
{
|
|
if (_state.PrevIrqSource)
|
|
{
|
|
ReadCode(_state.PC);
|
|
}
|
|
else
|
|
{
|
|
Idle();
|
|
}
|
|
}
|
|
|
|
uint8_t Cpu::ReadOperandByte()
|
|
{
|
|
uint8_t value = ReadCode(_state.PC, MemoryOperationType::ExecOperand);
|
|
_state.PC++;
|
|
return value;
|
|
}
|
|
|
|
uint16_t Cpu::ReadOperandWord()
|
|
{
|
|
uint8_t lsb = ReadOperandByte();
|
|
uint8_t msb = ReadOperandByte();
|
|
return (msb << 8) | lsb;
|
|
}
|
|
|
|
uint32_t Cpu::ReadOperandLong()
|
|
{
|
|
uint8_t b1 = ReadOperandByte();
|
|
uint8_t b2 = ReadOperandByte();
|
|
uint8_t b3 = ReadOperandByte();
|
|
return (b3 << 16) | (b2 << 8) | b1;
|
|
}
|
|
|
|
uint8_t Cpu::ReadCode(uint16_t addr, MemoryOperationType type)
|
|
{
|
|
return Read((_state.K << 16) | addr, type);
|
|
}
|
|
|
|
uint16_t Cpu::ReadCodeWord(uint16_t addr, MemoryOperationType type)
|
|
{
|
|
uint8_t lsb = ReadCode(addr);
|
|
uint8_t msb = ReadCode(addr + 1);
|
|
return (msb << 8) | lsb;
|
|
}
|
|
|
|
uint8_t Cpu::ReadData(uint32_t addr, MemoryOperationType type)
|
|
{
|
|
return Read(addr & 0xFFFFFF, type);
|
|
}
|
|
|
|
uint16_t Cpu::ReadDataWord(uint32_t addr, MemoryOperationType type)
|
|
{
|
|
uint8_t lsb = ReadData(addr);
|
|
uint8_t msb = ReadData(addr + 1);
|
|
return (msb << 8) | lsb;
|
|
}
|
|
|
|
uint32_t Cpu::ReadDataLong(uint32_t addr, MemoryOperationType type)
|
|
{
|
|
uint8_t b1 = ReadData(addr);
|
|
uint8_t b2 = ReadData(addr + 1);
|
|
uint8_t b3 = ReadData(addr + 2);
|
|
return (b3 << 16) | (b2 << 8) | b1;
|
|
}
|
|
|
|
void Cpu::WriteWord(uint32_t addr, uint16_t value, MemoryOperationType type)
|
|
{
|
|
Write(addr, (uint8_t)value);
|
|
Write((addr + 1) & 0xFFFFFF, (uint8_t)(value >> 8));
|
|
}
|
|
|
|
uint8_t Cpu::GetByteValue()
|
|
{
|
|
if (_immediateMode)
|
|
{
|
|
return (uint8_t)_operand;
|
|
}
|
|
else
|
|
{
|
|
return ReadData(_operand);
|
|
}
|
|
}
|
|
|
|
uint16_t Cpu::GetWordValue()
|
|
{
|
|
if (_immediateMode)
|
|
{
|
|
return (uint16_t)_operand;
|
|
}
|
|
else
|
|
{
|
|
return ReadDataWord(_operand);
|
|
}
|
|
}
|
|
|
|
void Cpu::PushByte(uint8_t value)
|
|
{
|
|
Write(_state.SP, value);
|
|
SetSP(_state.SP - 1);
|
|
}
|
|
|
|
uint8_t Cpu::PopByte()
|
|
{
|
|
SetSP(_state.SP + 1);
|
|
return ReadData(_state.SP);
|
|
}
|
|
|
|
void Cpu::PushWord(uint16_t value)
|
|
{
|
|
PushByte(value >> 8);
|
|
PushByte((uint8_t)value);
|
|
}
|
|
|
|
uint16_t Cpu::PopWord()
|
|
{
|
|
uint8_t lo = PopByte();
|
|
uint8_t hi = PopByte();
|
|
return lo | hi << 8;
|
|
}
|
|
|
|
uint16_t Cpu::GetDirectAddress(uint16_t offset, bool allowEmulationMode)
|
|
{
|
|
if (allowEmulationMode && _state.EmulationMode && (_state.D & 0xFF) == 0)
|
|
{
|
|
//TODO: Check if new instruction or not (PEI)
|
|
return (uint16_t)((_state.D & 0xFF00) | (offset & 0xFF));
|
|
}
|
|
else
|
|
{
|
|
return (uint16_t)(_state.D + offset);
|
|
}
|
|
}
|
|
|
|
uint16_t Cpu::GetDirectAddressIndirectWord(uint16_t offset, bool allowEmulationMode)
|
|
{
|
|
uint8_t lsb = ReadData(GetDirectAddress(offset + 0));
|
|
uint8_t msb = ReadData(GetDirectAddress(offset + 1));
|
|
return (msb << 8) | lsb;
|
|
}
|
|
|
|
uint32_t Cpu::GetDirectAddressIndirectLong(uint16_t offset, bool allowEmulationMode)
|
|
{
|
|
uint8_t b1 = ReadData(GetDirectAddress(offset + 0));
|
|
uint8_t b2 = ReadData(GetDirectAddress(offset + 1));
|
|
uint8_t b3 = ReadData(GetDirectAddress(offset + 2));
|
|
return (b3 << 16) | (b2 << 8) | b1;
|
|
}
|
|
|
|
void Cpu::SetSP(uint16_t sp)
|
|
{
|
|
if (_state.EmulationMode)
|
|
{
|
|
_state.SP = 0x100 | (sp & 0xFF);
|
|
}
|
|
else
|
|
{
|
|
_state.SP = sp;
|
|
}
|
|
}
|
|
|
|
void Cpu::SetPS(uint8_t ps)
|
|
{
|
|
_state.PS = ps;
|
|
if (CheckFlag(ProcFlags::IndexMode8))
|
|
{
|
|
//Truncate X/Y when 8-bit indexes are enabled
|
|
_state.Y &= 0xFF;
|
|
_state.X &= 0xFF;
|
|
}
|
|
}
|
|
|
|
void Cpu::SetRegister(uint8_t& reg, uint8_t value)
|
|
{
|
|
SetZeroNegativeFlags(value);
|
|
reg = value;
|
|
}
|
|
|
|
void Cpu::SetRegister(uint16_t& reg, uint16_t value, bool eightBitMode)
|
|
{
|
|
if (eightBitMode)
|
|
{
|
|
SetZeroNegativeFlags((uint8_t)value);
|
|
reg = (reg & 0xFF00) | (uint8_t)value;
|
|
}
|
|
else
|
|
{
|
|
SetZeroNegativeFlags(value);
|
|
reg = value;
|
|
}
|
|
}
|
|
|
|
void Cpu::SetZeroNegativeFlags(uint16_t value)
|
|
{
|
|
ClearFlags(ProcFlags::Zero | ProcFlags::Negative);
|
|
if (value == 0)
|
|
{
|
|
SetFlags(ProcFlags::Zero);
|
|
}
|
|
else if (value & 0x8000)
|
|
{
|
|
SetFlags(ProcFlags::Negative);
|
|
}
|
|
}
|
|
|
|
void Cpu::SetZeroNegativeFlags(uint8_t value)
|
|
{
|
|
ClearFlags(ProcFlags::Zero | ProcFlags::Negative);
|
|
if (value == 0)
|
|
{
|
|
SetFlags(ProcFlags::Zero);
|
|
}
|
|
else if (value & 0x80)
|
|
{
|
|
SetFlags(ProcFlags::Negative);
|
|
}
|
|
}
|
|
|
|
void Cpu::ClearFlags(uint8_t flags)
|
|
{
|
|
_state.PS &= ~flags;
|
|
}
|
|
|
|
void Cpu::SetFlags(uint8_t flags)
|
|
{
|
|
_state.PS |= flags;
|
|
}
|
|
|
|
bool Cpu::CheckFlag(uint8_t flag)
|
|
{
|
|
return (_state.PS & flag) == flag;
|
|
}
|
|
|
|
void Cpu::Serialize(Serializer& s)
|
|
{
|
|
s.Stream(
|
|
_state.A, _state.CycleCount, _state.D, _state.DBR, _state.EmulationMode, _state.IrqSource, _state.K,
|
|
_state.NmiFlag, _state.PC, _state.PrevIrqSource, _state.PrevNmiFlag, _state.PS, _state.SP, _state.StopState,
|
|
_state.X, _state.Y, _state.IrqLock, _state.NeedNmi, _state.PrevNeedNmi
|
|
);
|
|
}
|