Mesen-SX/Core/Spc.Instructions.cpp
2020-12-19 23:30:09 +03:00

2951 lines
42 KiB
C++

#include "stdafx.h"
#include "Spc.h"
#include "../Utilities/HexUtilities.h"
void Spc::EndOp()
{
_opStep = SpcOpStep::ReadOpCode;
}
void Spc::EndAddr()
{
_opStep = SpcOpStep::AfterAddressing;
_opSubStep = 0;
}
void Spc::Exec()
{
switch (_opCode)
{
case 0x00: NOP();
break;
case 0x01: TCALL<0>();
break;
case 0x02: Addr_Dir();
SET1<0>();
break;
case 0x03: Addr_Dir();
BBS<0>();
break;
case 0x04: Addr_Dir();
OR_Acc();
break;
case 0x05: Addr_Abs();
OR_Acc();
break;
case 0x06: Addr_IndX();
OR_Acc();
break;
case 0x07: Addr_DirIdxXInd();
OR_Acc();
break;
case 0x08: Addr_Imm();
OR_Imm();
break;
case 0x09: Addr_DirToDir();
OR();
break;
case 0x0A: Addr_AbsBit();
OR1();
break;
case 0x0B: Addr_Dir();
ASL();
break;
case 0x0C: Addr_Abs();
ASL();
break;
case 0x0D: PHP();
break;
case 0x0E: Addr_Abs();
TSET1();
break;
case 0x0F: BRK();
break;
case 0x10: Addr_Rel();
BPL();
break;
case 0x11: TCALL<1>();
break;
case 0x12: Addr_Dir();
CLR1<0>();
break;
case 0x13: Addr_Dir();
BBC<0>();
break;
case 0x14: Addr_DirIdxX();
OR_Acc();
break;
case 0x15: Addr_AbsIdxX();
OR_Acc();
break;
case 0x16: Addr_AbsIdxY();
OR_Acc();
break;
case 0x17: Addr_DirIndIdxY();
OR_Acc();
break;
case 0x18: Addr_DirImm();
OR();
break;
case 0x19: Addr_IndXToIndY();
OR();
break;
case 0x1A: Addr_Dir();
DECW();
break;
case 0x1B: Addr_DirIdxX();
ASL();
break;
case 0x1C: ASL_Acc();
break;
case 0x1D: DEX();
break;
case 0x1E: Addr_Abs();
CPX();
break;
case 0x1F: Addr_AbsIdxXInd();
JMP();
break;
case 0x20: CLRP();
break;
case 0x21: TCALL<2>();
break;
case 0x22: Addr_Dir();
SET1<1>();
break;
case 0x23: Addr_Dir();
BBS<1>();
break;
case 0x24: Addr_Dir();
AND_Acc();
break;
case 0x25: Addr_Abs();
AND_Acc();
break;
case 0x26: Addr_IndX();
AND_Acc();
break;
case 0x27: Addr_DirIdxXInd();
AND_Acc();
break;
case 0x28: Addr_Imm();
AND_Imm();
break;
case 0x29: Addr_DirToDir();
AND();
break;
case 0x2A: Addr_AbsBit();
NOR1();
break;
case 0x2B: Addr_Dir();
ROL();
break;
case 0x2C: Addr_Abs();
ROL();
break;
case 0x2D: PHA();
break;
case 0x2E: Addr_Dir();
CBNE();
break;
case 0x2F: Addr_Rel();
BRA();
break;
case 0x30: Addr_Rel();
BMI();
break;
case 0x31: TCALL<3>();
break;
case 0x32: Addr_Dir();
CLR1<1>();
break;
case 0x33: Addr_Dir();
BBC<1>();
break;
case 0x34: Addr_DirIdxX();
AND_Acc();
break;
case 0x35: Addr_AbsIdxX();
AND_Acc();
break;
case 0x36: Addr_AbsIdxY();
AND_Acc();
break;
case 0x37: Addr_DirIndIdxY();
AND_Acc();
break;
case 0x38: Addr_DirImm();
AND();
break;
case 0x39: Addr_IndXToIndY();
AND();
break;
case 0x3A: Addr_Dir();
INCW();
break;
case 0x3B: Addr_DirIdxX();
ROL();
break;
case 0x3C: ROL_Acc();
break;
case 0x3D: INX();
break;
case 0x3E: Addr_Dir();
CPX();
break;
case 0x3F: Addr_Abs();
JSR();
break;
case 0x40: SETP();
break;
case 0x41: TCALL<4>();
break;
case 0x42: Addr_Dir();
SET1<2>();
break;
case 0x43: Addr_Dir();
BBS<2>();
break;
case 0x44: Addr_Dir();
EOR_Acc();
break;
case 0x45: Addr_Abs();
EOR_Acc();
break;
case 0x46: Addr_IndX();
EOR_Acc();
break;
case 0x47: Addr_DirIdxXInd();
EOR_Acc();
break;
case 0x48: Addr_Imm();
EOR_Imm();
break;
case 0x49: Addr_DirToDir();
EOR();
break;
case 0x4A: Addr_AbsBit();
AND1();
break;
case 0x4B: Addr_Dir();
LSR();
break;
case 0x4C: Addr_Abs();
LSR();
break;
case 0x4D: PHX();
break;
case 0x4E: Addr_Abs();
TCLR1();
break;
case 0x4F: PCALL();
break;
case 0x50: Addr_Rel();
BVC();
break;
case 0x51: TCALL<5>();
break;
case 0x52: Addr_Dir();
CLR1<2>();
break;
case 0x53: Addr_Dir();
BBC<2>();
break;
case 0x54: Addr_DirIdxX();
EOR_Acc();
break;
case 0x55: Addr_AbsIdxX();
EOR_Acc();
break;
case 0x56: Addr_AbsIdxY();
EOR_Acc();
break;
case 0x57: Addr_DirIndIdxY();
EOR_Acc();
break;
case 0x58: Addr_DirImm();
EOR();
break;
case 0x59: Addr_IndXToIndY();
EOR();
break;
case 0x5A: Addr_Dir();
CMPW();
break;
case 0x5B: Addr_DirIdxX();
LSR();
break;
case 0x5C: LSR_Acc();
break;
case 0x5D: TAX();
break;
case 0x5E: Addr_Abs();
CPY();
break;
case 0x5F: Addr_Abs();
JMP();
break;
case 0x60: CLRC();
break;
case 0x61: TCALL<6>();
break;
case 0x62: Addr_Dir();
SET1<3>();
break;
case 0x63: Addr_Dir();
BBS<3>();
break;
case 0x64: Addr_Dir();
CMP_Acc();
break;
case 0x65: Addr_Abs();
CMP_Acc();
break;
case 0x66: Addr_IndX();
CMP_Acc();
break;
case 0x67: Addr_DirIdxXInd();
CMP_Acc();
break;
case 0x68: Addr_Imm();
CMP_Imm();
break;
case 0x69: Addr_DirToDir();
CMP();
break;
case 0x6A: Addr_AbsBit();
NAND1();
break;
case 0x6B: Addr_Dir();
ROR();
break;
case 0x6C: Addr_Abs();
ROR();
break;
case 0x6D: PHY();
break;
case 0x6E: Addr_Dir();
DBNZ();
break;
case 0x6F: RTS();
break;
case 0x70: Addr_Rel();
BVS();
break;
case 0x71: TCALL<7>();
break;
case 0x72: Addr_Dir();
CLR1<3>();
break;
case 0x73: Addr_Dir();
BBC<3>();
break;
case 0x74: Addr_DirIdxX();
CMP_Acc();
break;
case 0x75: Addr_AbsIdxX();
CMP_Acc();
break;
case 0x76: Addr_AbsIdxY();
CMP_Acc();
break;
case 0x77: Addr_DirIndIdxY();
CMP_Acc();
break;
case 0x78: Addr_DirImm();
CMP();
break;
case 0x79: Addr_IndXToIndY();
CMP();
break;
case 0x7A: Addr_Dir();
ADDW();
break;
case 0x7B: Addr_DirIdxX();
ROR();
break;
case 0x7C: ROR_Acc();
break;
case 0x7D: TXA();
break;
case 0x7E: Addr_Dir();
CPY();
break;
case 0x7F: RTI();
break;
case 0x80: SETC();
break;
case 0x81: TCALL<8>();
break;
case 0x82: Addr_Dir();
SET1<4>();
break;
case 0x83: Addr_Dir();
BBS<4>();
break;
case 0x84: Addr_Dir();
ADC_Acc();
break;
case 0x85: Addr_Abs();
ADC_Acc();
break;
case 0x86: Addr_IndX();
ADC_Acc();
break;
case 0x87: Addr_DirIdxXInd();
ADC_Acc();
break;
case 0x88: Addr_Imm();
ADC_Imm();
break;
case 0x89: Addr_DirToDir();
ADC();
break;
case 0x8A: Addr_AbsBit();
EOR1();
break;
case 0x8B: Addr_Dir();
DEC();
break;
case 0x8C: Addr_Abs();
DEC();
break;
case 0x8D: Addr_Imm();
LDY_Imm();
break;
case 0x8E: PLP();
break;
case 0x8F: Addr_DirImm();
MOV_Imm();
break;
case 0x90: Addr_Rel();
BCC();
break;
case 0x91: TCALL<9>();
break;
case 0x92: Addr_Dir();
CLR1<4>();
break;
case 0x93: Addr_Dir();
BBC<4>();
break;
case 0x94: Addr_DirIdxX();
ADC_Acc();
break;
case 0x95: Addr_AbsIdxX();
ADC_Acc();
break;
case 0x96: Addr_AbsIdxY();
ADC_Acc();
break;
case 0x97: Addr_DirIndIdxY();
ADC_Acc();
break;
case 0x98: Addr_DirImm();
ADC();
break;
case 0x99: Addr_IndXToIndY();
ADC();
break;
case 0x9A: Addr_Dir();
SUBW();
break;
case 0x9B: Addr_DirIdxX();
DEC();
break;
case 0x9C: DEC_Acc();
break;
case 0x9D: TSX();
break;
case 0x9E: DIV();
break;
case 0x9F: XCN();
break;
case 0xA0: EI();
break;
case 0xA1: TCALL<10>();
break;
case 0xA2: Addr_Dir();
SET1<5>();
break;
case 0xA3: Addr_Dir();
BBS<5>();
break;
case 0xA4: Addr_Dir();
SBC_Acc();
break;
case 0xA5: Addr_Abs();
SBC_Acc();
break;
case 0xA6: Addr_IndX();
SBC_Acc();
break;
case 0xA7: Addr_DirIdxXInd();
SBC_Acc();
break;
case 0xA8: Addr_Imm();
SBC_Imm();
break;
case 0xA9: Addr_DirToDir();
SBC();
break;
case 0xAA: Addr_AbsBit();
LDC();
break;
case 0xAB: Addr_Dir();
INC();
break;
case 0xAC: Addr_Abs();
INC();
break;
case 0xAD: Addr_Imm();
CPY_Imm();
break;
case 0xAE: PLA();
break;
case 0xAF: Addr_IndX();
STA_AutoIncX();
break;
case 0xB0: Addr_Rel();
BCS();
break;
case 0xB1: TCALL<11>();
break;
case 0xB2: Addr_Dir();
CLR1<5>();
break;
case 0xB3: Addr_Dir();
BBC<5>();
break;
case 0xB4: Addr_DirIdxX();
SBC_Acc();
break;
case 0xB5: Addr_AbsIdxX();
SBC_Acc();
break;
case 0xB6: Addr_AbsIdxY();
SBC_Acc();
break;
case 0xB7: Addr_DirIndIdxY();
SBC_Acc();
break;
case 0xB8: Addr_DirImm();
SBC();
break;
case 0xB9: Addr_IndXToIndY();
SBC();
break;
case 0xBA: Addr_Dir();
LDW();
break;
case 0xBB: Addr_DirIdxX();
INC();
break;
case 0xBC: INC_Acc();
break;
case 0xBD: TXS();
break;
case 0xBE: DAS();
break;
case 0xBF: Addr_IndX();
LDA_AutoIncX();
break;
case 0xC0: DI();
break;
case 0xC1: TCALL<12>();
break;
case 0xC2: Addr_Dir();
SET1<6>();
break;
case 0xC3: Addr_Dir();
BBS<6>();
break;
case 0xC4: Addr_Dir();
STA();
break;
case 0xC5: Addr_Abs();
STA();
break;
case 0xC6: Addr_IndX();
STA();
break;
case 0xC7: Addr_DirIdxXInd();
STA();
break;
case 0xC8: Addr_Imm();
CPX_Imm();
break;
case 0xC9: Addr_Abs();
STX();
break;
case 0xCA: Addr_AbsBit();
STC();
break;
case 0xCB: Addr_Dir();
STY();
break;
case 0xCC: Addr_Abs();
STY();
break;
case 0xCD: Addr_Imm();
LDX_Imm();
break;
case 0xCE: PLX();
break;
case 0xCF: MUL();
break;
case 0xD0: Addr_Rel();
BNE();
break;
case 0xD1: TCALL<13>();
break;
case 0xD2: Addr_Dir();
CLR1<6>();
break;
case 0xD3: Addr_Dir();
BBC<6>();
break;
case 0xD4: Addr_DirIdxX();
STA();
break;
case 0xD5: Addr_AbsIdxX();
STA();
break;
case 0xD6: Addr_AbsIdxY();
STA();
break;
case 0xD7: Addr_DirIndIdxY();
STA();
break;
case 0xD8: Addr_Dir();
STX();
break;
case 0xD9: Addr_DirIdxY();
STX();
break;
case 0xDA: Addr_Dir();
STW();
break;
case 0xDB: Addr_DirIdxX();
STY();
break;
case 0xDC: DEY();
break;
case 0xDD: TYA();
break;
case 0xDE: Addr_DirIdxX();
CBNE();
break;
case 0xDF: DAA();
break;
case 0xE0: CLRV();
break;
case 0xE1: TCALL<14>();
break;
case 0xE2: Addr_Dir();
SET1<7>();
break;
case 0xE3: Addr_Dir();
BBS<7>();
break;
case 0xE4: Addr_Dir();
LDA();
break;
case 0xE5: Addr_Abs();
LDA();
break;
case 0xE6: Addr_IndX();
LDA();
break;
case 0xE7: Addr_DirIdxXInd();
LDA();
break;
case 0xE8: Addr_Imm();
LDA_Imm();
break;
case 0xE9: Addr_Abs();
LDX();
break;
case 0xEA: Addr_AbsBit();
NOT1();
break;
case 0xEB: Addr_Dir();
LDY();
break;
case 0xEC: Addr_Abs();
LDY();
break;
case 0xED: NOTC();
break;
case 0xEE: PLY();
break;
case 0xEF: SLEEP();
break;
case 0xF0: Addr_Rel();
BEQ();
break;
case 0xF1: TCALL<15>();
break;
case 0xF2: Addr_Dir();
CLR1<7>();
break;
case 0xF3: Addr_Dir();
BBC<7>();
break;
case 0xF4: Addr_DirIdxX();
LDA();
break;
case 0xF5: Addr_AbsIdxX();
LDA();
break;
case 0xF6: Addr_AbsIdxY();
LDA();
break;
case 0xF7: Addr_DirIndIdxY();
LDA();
break;
case 0xF8: Addr_Dir();
LDX();
break;
case 0xF9: Addr_DirIdxY();
LDX();
break;
case 0xFA: Addr_DirToDir();
MOV();
break;
case 0xFB: Addr_DirIdxX();
LDY();
break;
case 0xFC: INY();
break;
case 0xFD: TAY();
break;
case 0xFE: DBNZ_Y();
break;
case 0xFF: STOP();
break;
}
if (_opStep == SpcOpStep::AfterAddressing)
{
_opStep = SpcOpStep::Operation;
}
}
//*****************
// ADDRESSING MODES
//*****************
void Spc::Addr_Dir()
{
if (_opStep == SpcOpStep::Addressing)
{
_operandA = GetDirectAddress(ReadOperandByte());
EndAddr();
}
}
void Spc::Addr_DirIdxX()
{
if (_opStep == SpcOpStep::Addressing)
{
switch (_opSubStep++)
{
case 0: _operandA = GetDirectAddress(ReadOperandByte() + _state.X);
break;
case 1: Idle();
EndAddr();
break;
}
}
}
void Spc::Addr_DirIdxY()
{
if (_opStep == SpcOpStep::Addressing)
{
switch (_opSubStep++)
{
case 0: _operandA = GetDirectAddress(ReadOperandByte() + _state.Y);
break;
case 1: Idle();
EndAddr();
break;
}
}
}
void Spc::Addr_DirToDir()
{
if (_opStep == SpcOpStep::Addressing)
{
switch (_opSubStep++)
{
case 0: _tmp1 = GetDirectAddress(ReadOperandByte());
break;
case 1: _operandA = Read(_tmp1);
break;
case 2: _operandB = GetDirectAddress(ReadOperandByte());
EndAddr();
break;
}
}
}
void Spc::Addr_DirImm()
{
if (_opStep == SpcOpStep::Addressing)
{
switch (_opSubStep++)
{
case 0: _operandA = ReadOperandByte();
break;
case 1: _operandB = GetDirectAddress(ReadOperandByte());
EndAddr();
break;
}
}
}
void Spc::Addr_DirIdxXInd()
{
if (_opStep == SpcOpStep::Addressing)
{
switch (_opSubStep++)
{
case 0: _tmp1 = GetDirectAddress(ReadOperandByte() + _state.X);
break;
case 1: Idle();
break;
case 2: _tmp2 = Read(_tmp1);
break;
case 3:
_tmp3 = Read(GetDirectAddress(_tmp1 + 1));
_operandA = (_tmp3 << 8) | _tmp2;
EndAddr();
break;
}
}
}
void Spc::Addr_DirIndIdxY()
{
if (_opStep == SpcOpStep::Addressing)
{
switch (_opSubStep++)
{
case 0: _tmp1 = GetDirectAddress(ReadOperandByte());
break;
case 1: _tmp2 = Read(_tmp1);
break;
case 2: _tmp3 = Read(GetDirectAddress(_tmp1 + 1));
break;
case 4:
Idle();
_operandA = ((_tmp3 << 8) | _tmp2) + _state.Y;
EndAddr();
break;
}
}
}
void Spc::Addr_IndX()
{
if (_opStep == SpcOpStep::Addressing)
{
DummyRead();
_operandA = GetDirectAddress(_state.X);
EndAddr();
}
}
void Spc::Addr_IndXToIndY()
{
if (_opStep == SpcOpStep::Addressing)
{
switch (_opSubStep++)
{
case 0: DummyRead();
break;
case 1:
_operandA = Read(GetDirectAddress(_state.Y));
_operandB = GetDirectAddress(_state.X);
EndAddr();
break;
}
}
}
void Spc::Addr_Abs()
{
if (_opStep == SpcOpStep::Addressing)
{
switch (_opSubStep++)
{
case 0: _tmp1 = ReadOperandByte();
break;
case 1:
_tmp2 = ReadOperandByte();
_operandA = ((_tmp2 << 8) | _tmp1);
EndAddr();
break;
}
}
}
void Spc::Addr_AbsBit()
{
if (_opStep == SpcOpStep::Addressing)
{
switch (_opSubStep++)
{
case 0: _tmp1 = ReadOperandByte();
break;
case 1:
_tmp2 = ReadOperandByte();
_operandA = ((_tmp2 << 8) | _tmp1);
_operandB = _operandA >> 13;
_operandA = _operandA & 0x1FFF;
EndAddr();
break;
}
}
}
void Spc::Addr_AbsIdxX()
{
if (_opStep == SpcOpStep::Addressing)
{
switch (_opSubStep++)
{
case 0: _tmp1 = ReadOperandByte();
break;
case 1:
_tmp2 = ReadOperandByte();
_operandA = ((_tmp2 << 8) | _tmp1);
break;
case 2:
Idle();
_operandA += _state.X;
EndAddr();
break;
}
}
}
void Spc::Addr_AbsIdxY()
{
if (_opStep == SpcOpStep::Addressing)
{
switch (_opSubStep++)
{
case 0: _tmp1 = ReadOperandByte();
break;
case 1:
_tmp2 = ReadOperandByte();
_operandA = ((_tmp2 << 8) | _tmp1);
break;
case 2:
Idle();
_operandA += _state.Y;
EndAddr();
break;
}
}
}
void Spc::Addr_AbsIdxXInd()
{
//Used by JMP only
if (_opStep == SpcOpStep::Addressing)
{
switch (_opSubStep++)
{
case 0: _tmp1 = ReadOperandByte();
break;
case 1: _tmp2 = ReadOperandByte();
break;
case 2: Idle();
break;
case 3:
{
uint16_t addr = ((_tmp2 << 8) | _tmp1);
_tmp1 = Read(addr + _state.X);
_tmp2 = Read(addr + _state.X + 1);
_operandA = (_tmp2 << 8) | _tmp1;
EndAddr();
break;
}
}
}
}
void Spc::Addr_Rel()
{
if (_opStep == SpcOpStep::Addressing)
{
_operandA = ReadOperandByte();
EndAddr();
}
}
void Spc::Addr_Imm()
{
if (_opStep == SpcOpStep::Addressing)
{
_operandA = ReadOperandByte();
EndAddr();
}
}
//*****************
// INSTRUCTIONS
//*****************
void Spc::STA()
{
if (_opStep == SpcOpStep::Operation)
{
switch (_opSubStep++)
{
case 0: Read(_operandA);
break;
case 1: Write(_operandA, _state.A);
EndOp();
break;
}
}
}
void Spc::STX()
{
if (_opStep == SpcOpStep::Operation)
{
switch (_opSubStep++)
{
case 0: Read(_operandA);
break;
case 1: Write(_operandA, _state.X);
EndOp();
break;
}
}
}
void Spc::STY()
{
if (_opStep == SpcOpStep::Operation)
{
switch (_opSubStep++)
{
case 0: Read(_operandA);
break;
case 1: Write(_operandA, _state.Y);
EndOp();
break;
}
}
}
void Spc::STW()
{
if (_opStep == SpcOpStep::Operation)
{
switch (_opSubStep++)
{
case 0: DummyRead(_operandA);
break;
case 1: Write(_operandA, _state.A);
break;
case 2:
uint16_t msbAddress = GetDirectAddress(_operandA + 1);
Write(msbAddress, _state.Y);
EndOp();
break;
}
}
}
void Spc::STA_AutoIncX()
{
if (_opStep == SpcOpStep::Operation)
{
switch (_opSubStep++)
{
case 0: Idle();
break;
case 1:
Write(_operandA, _state.A);
_state.X++;
EndOp();
break;
}
}
}
void Spc::LDA_AutoIncX()
{
if (_opStep == SpcOpStep::Operation)
{
switch (_opSubStep++)
{
case 0:
_state.A = Read(_operandA);
SetZeroNegativeFlags(_state.A);
break;
case 1:
Idle();
_state.X++;
EndOp();
break;
}
}
}
void Spc::LDA()
{
if (_opStep == SpcOpStep::Operation)
{
_state.A = GetByteValue();
SetZeroNegativeFlags(_state.A);
EndOp();
}
}
void Spc::LDA_Imm()
{
if (_opStep == SpcOpStep::AfterAddressing)
{
_state.A = (uint8_t)_operandA;
SetZeroNegativeFlags(_state.A);
EndOp();
}
}
void Spc::LDX()
{
if (_opStep == SpcOpStep::Operation)
{
_state.X = GetByteValue();
SetZeroNegativeFlags(_state.X);
EndOp();
}
}
void Spc::LDX_Imm()
{
if (_opStep == SpcOpStep::AfterAddressing)
{
_state.X = (uint8_t)_operandA;
SetZeroNegativeFlags(_state.X);
EndOp();
}
}
void Spc::LDY()
{
if (_opStep == SpcOpStep::Operation)
{
_state.Y = GetByteValue();
SetZeroNegativeFlags(_state.Y);
EndOp();
}
}
void Spc::LDY_Imm()
{
if (_opStep == SpcOpStep::AfterAddressing)
{
_state.Y = (uint8_t)_operandA;
SetZeroNegativeFlags(_state.Y);
EndOp();
}
}
void Spc::LDW()
{
if (_opStep == SpcOpStep::Operation)
{
switch (_opSubStep++)
{
case 0: _tmp1 = Read(_operandA);
break;
case 1: Idle();
break;
case 2:
uint8_t msb = Read(GetDirectAddress(_operandA + 1));
uint16_t value = (msb << 8) | _tmp1;
_state.A = (uint8_t)value;
_state.Y = (value >> 8);
SetZeroNegativeFlags16(value);
EndOp();
break;
}
}
}
void Spc::Transfer(uint8_t& dst, uint8_t src)
{
DummyRead();
dst = src;
SetZeroNegativeFlags(src);
EndOp();
}
void Spc::TXA()
{
Transfer(_state.A, _state.X);
}
void Spc::TYA()
{
Transfer(_state.A, _state.Y);
}
void Spc::TAX()
{
Transfer(_state.X, _state.A);
}
void Spc::TAY()
{
Transfer(_state.Y, _state.A);
}
void Spc::TSX()
{
Transfer(_state.X, _state.SP);
}
void Spc::TXS()
{
DummyRead();
_state.SP = _state.X;
EndOp();
}
void Spc::MOV()
{
if (_opStep == SpcOpStep::Operation)
{
Write(_operandB, (uint8_t)_operandA);
EndOp();
}
}
void Spc::MOV_Imm()
{
if (_opStep == SpcOpStep::Operation)
{
switch (_opSubStep++)
{
case 0: DummyRead(_operandB);
break;
case 1: Write(_operandB, (uint8_t)_operandA);
EndOp();
break;
}
}
}
uint8_t Spc::Add(uint8_t a, uint8_t b)
{
uint32_t result = a + b + (_state.PS & SpcFlags::Carry);
uint8_t subResult = (a & 0x0F) + (_state.PS & SpcFlags::Carry);
ClearFlags(SpcFlags::Carry | SpcFlags::Negative | SpcFlags::Zero | SpcFlags::Overflow | SpcFlags::HalfCarry);
if (~(a ^ b) & (a ^ result) & 0x80)
{
SetFlags(SpcFlags::Overflow);
}
if (result > 0xFF)
{
SetFlags(SpcFlags::Carry);
}
if (((result & 0x0F) - subResult) & 0x10)
{
SetFlags(SpcFlags::HalfCarry);
}
SetZeroNegativeFlags((uint8_t)result);
return (uint8_t)result;
}
uint8_t Spc::Sub(uint8_t a, uint8_t b)
{
uint32_t carryCalc = a - b - ((_state.PS & SpcFlags::Carry) ^ 0x01);
uint8_t result = Add(a, ~b);
if (carryCalc <= 0xFF)
{
SetFlags(SpcFlags::Carry);
}
else
{
ClearFlags(SpcFlags::Carry);
}
return (uint8_t)result;
}
void Spc::ADC()
{
if (_opStep == SpcOpStep::Operation)
{
switch (_opSubStep++)
{
case 0:
_tmp1 = (uint8_t)_operandA;
_tmp2 = Read(_operandB);
break;
case 1:
Write(_operandB, Add((uint8_t)_tmp2, (uint8_t)_tmp1));
EndOp();
break;
}
}
}
void Spc::ADC_Acc()
{
if (_opStep == SpcOpStep::Operation)
{
_state.A = Add(_state.A, GetByteValue());
EndOp();
}
}
void Spc::ADC_Imm()
{
if (_opStep == SpcOpStep::AfterAddressing)
{
_state.A = Add(_state.A, (uint8_t)_operandA);
EndOp();
}
}
void Spc::ADDW()
{
if (_opStep == SpcOpStep::Operation)
{
switch (_opSubStep++)
{
case 0: _tmp1 = Read(_operandA);
break;
case 1: Idle();
break;
case 2:
uint8_t msb = Read(GetDirectAddress(_operandA + 1));
uint16_t value = ((msb << 8) | _tmp1);
uint8_t lowCarry = (_tmp1 + _state.A) > 0xFF ? 1 : 0;
ClearFlags(SpcFlags::Carry | SpcFlags::HalfCarry | SpcFlags::Overflow);
if (((_state.Y & 0x0F) + (msb & 0x0F) + lowCarry) & 0x10)
{
SetFlags(SpcFlags::HalfCarry);
}
uint16_t ya = (_state.Y << 8) | _state.A;
uint32_t result = ya + value;
if (result > 0xFFFF)
{
SetFlags(SpcFlags::Carry);
}
SetZeroNegativeFlags16(result);
if (~(ya ^ value) & (ya ^ result) & 0x8000)
{
SetFlags(SpcFlags::Overflow);
}
_state.Y = result >> 8;
_state.A = (uint8_t)result;
EndOp();
}
}
}
void Spc::SBC()
{
if (_opStep == SpcOpStep::Operation)
{
switch (_opSubStep++)
{
case 0:
_tmp1 = (uint8_t)_operandA;
_tmp2 = Read(_operandB);
break;
case 1:
Write(_operandB, Sub((uint8_t)_tmp2, (uint8_t)_tmp1));
EndOp();
break;
}
}
}
void Spc::SBC_Acc()
{
if (_opStep == SpcOpStep::Operation)
{
_state.A = Sub(_state.A, GetByteValue());
EndOp();
}
}
void Spc::SBC_Imm()
{
if (_opStep == SpcOpStep::AfterAddressing)
{
_state.A = Sub(_state.A, (uint8_t)_operandA);
EndOp();
}
}
void Spc::SUBW()
{
if (_opStep == SpcOpStep::Operation)
{
switch (_opSubStep++)
{
case 0: _tmp1 = Read(_operandA);
break;
case 1: Idle();
break;
case 2:
uint8_t msb = Read(GetDirectAddress(_operandA + 1));
uint16_t value = ((msb << 8) | _tmp1);
uint16_t ya = (_state.Y << 8) | _state.A;
uint32_t l = _state.A - _tmp1;
uint8_t carry = l > 0xFF ? 1 : 0;
uint32_t h = _state.Y - msb - carry;
ClearFlags(SpcFlags::Carry | SpcFlags::HalfCarry | SpcFlags::Overflow);
if (h <= 0xFF)
{
SetFlags(SpcFlags::Carry);
}
if ((((_state.Y & 0x0F) - (msb & 0x0F) - carry) & 0x10) == 0)
{
SetFlags(SpcFlags::HalfCarry);
}
_state.Y = h;
_state.A = l;
uint16_t result = (_state.Y << 8) | _state.A;
if ((ya ^ value) & (ya ^ result) & 0x8000)
{
SetFlags(SpcFlags::Overflow);
}
SetZeroNegativeFlags16(result);
EndOp();
break;
}
}
}
void Spc::Compare(uint8_t a, uint8_t b)
{
if (a >= b)
{
SetFlags(SpcFlags::Carry);
}
else
{
ClearFlags(SpcFlags::Carry);
}
uint8_t result = a - b;
SetZeroNegativeFlags(result);
}
void Spc::CMP()
{
if (_opStep == SpcOpStep::Operation)
{
switch (_opSubStep++)
{
case 0: Compare(Read(_operandB), (uint8_t)_operandA);
break;
case 1: Idle();
EndOp();
break;
}
}
}
void Spc::CMP_Acc()
{
if (_opStep == SpcOpStep::Operation)
{
Compare(_state.A, GetByteValue());
EndOp();
}
}
void Spc::CMP_Imm()
{
if (_opStep == SpcOpStep::AfterAddressing)
{
Compare(_state.A, (uint8_t)_operandA);
EndOp();
}
}
void Spc::CPX()
{
if (_opStep == SpcOpStep::Operation)
{
Compare(_state.X, GetByteValue());
EndOp();
}
}
void Spc::CPX_Imm()
{
if (_opStep == SpcOpStep::AfterAddressing)
{
Compare(_state.X, (uint8_t)_operandA);
EndOp();
}
}
void Spc::CPY()
{
if (_opStep == SpcOpStep::Operation)
{
Compare(_state.Y, GetByteValue());
EndOp();
}
}
void Spc::CPY_Imm()
{
if (_opStep == SpcOpStep::AfterAddressing)
{
Compare(_state.Y, (uint8_t)_operandA);
EndOp();
}
}
void Spc::CMPW()
{
if (_opStep == SpcOpStep::Operation)
{
switch (_opSubStep++)
{
case 0: _tmp1 = Read(_operandA);
break;
case 1:
uint8_t msb = Read(GetDirectAddress(_operandA + 1));
uint16_t value = ((msb << 8) | _tmp1);
uint16_t ya = (_state.Y << 8) | _state.A;
if (ya >= value)
{
SetFlags(SpcFlags::Carry);
}
else
{
ClearFlags(SpcFlags::Carry);
}
uint16_t result = ya - value;
SetZeroNegativeFlags16(result);
EndOp();
break;
}
}
}
void Spc::INC()
{
if (_opStep == SpcOpStep::Operation)
{
switch (_opSubStep++)
{
case 0: _tmp1 = Read(_operandA) + 1;
break;
case 1:
Write(_operandA, (uint8_t)_tmp1);
SetZeroNegativeFlags((uint8_t)_tmp1);
EndOp();
break;
}
}
}
void Spc::INC_Acc()
{
DummyRead();
_state.A++;
SetZeroNegativeFlags(_state.A);
EndOp();
}
void Spc::INX()
{
DummyRead();
_state.X++;
SetZeroNegativeFlags(_state.X);
EndOp();
}
void Spc::INY()
{
DummyRead();
_state.Y++;
SetZeroNegativeFlags(_state.Y);
EndOp();
}
void Spc::INCW()
{
if (_opStep == SpcOpStep::Operation)
{
switch (_opSubStep++)
{
case 0: _tmp1 = Read(_operandA);
break;
case 1:
Write(_operandA, _tmp1 + 1);
uint16_t msbAddress = GetDirectAddress(_operandA + 1);
uint8_t msb = Read(msbAddress);
uint16_t value = ((msb << 8) | _tmp1) + 1;
Write(msbAddress, value >> 8);
SetZeroNegativeFlags16(value);
EndOp();
break;
}
}
}
void Spc::DEC()
{
if (_opStep == SpcOpStep::Operation)
{
switch (_opSubStep++)
{
case 0: _tmp1 = Read(_operandA) - 1;
break;
case 1:
Write(_operandA, (uint8_t)_tmp1);
SetZeroNegativeFlags((uint8_t)_tmp1);
EndOp();
break;
}
}
}
void Spc::DEC_Acc()
{
DummyRead();
_state.A--;
SetZeroNegativeFlags(_state.A);
EndOp();
}
void Spc::DEX()
{
DummyRead();
_state.X--;
SetZeroNegativeFlags(_state.X);
EndOp();
}
void Spc::DEY()
{
DummyRead();
_state.Y--;
SetZeroNegativeFlags(_state.Y);
EndOp();
}
void Spc::DECW()
{
if (_opStep == SpcOpStep::Operation)
{
switch (_opSubStep++)
{
case 0: _tmp1 = Read(_operandA);
break;
case 1:
Write(_operandA, _tmp1 - 1);
uint16_t msbAddress = GetDirectAddress(_operandA + 1);
uint8_t msb = Read(msbAddress);
uint16_t value = ((msb << 8) | _tmp1) - 1;
Write(msbAddress, value >> 8);
SetZeroNegativeFlags16(value);
EndOp();
break;
}
}
}
void Spc::MUL()
{
switch (_opSubStep++)
{
case 0: DummyRead();
break;
case 1: Idle();
break;
case 2: Idle();
break;
case 3: Idle();
break;
case 4: Idle();
break;
case 5: Idle();
break;
case 6: Idle();
break;
case 7:
Idle();
uint16_t result = _state.Y * _state.A;
_state.Y = result >> 8;
_state.A = (uint8_t)result;
SetZeroNegativeFlags(_state.Y);
EndOp();
break;
}
}
void Spc::DIV()
{
switch (_opSubStep++)
{
case 0: DummyRead();
break;
case 1: Idle();
break;
case 2: Idle();
break;
case 3: Idle();
break;
case 4: Idle();
break;
case 5: Idle();
break;
case 6: Idle();
break;
case 7: Idle();
break;
case 8: Idle();
break;
case 9: Idle();
break;
case 11:
Idle();
uint32_t ya = (_state.Y << 8) | _state.A;
uint32_t sub = _state.X << 9;
for (int i = 0; i < 9; i++)
{
if (ya & 0x10000)
{
ya = ((ya << 1) | 0x01) & 0x1FFFF;
}
else
{
ya = (ya << 1) & 0x1FFFF;
}
if (ya >= sub)
{
ya ^= 0x01;
}
if (ya & 0x01)
{
ya = (ya - sub) & 0x1FFFF;
}
}
if ((_state.Y & 0x0F) >= (_state.X & 0x0F))
{
SetFlags(SpcFlags::HalfCarry);
}
else
{
ClearFlags(SpcFlags::HalfCarry);
}
_state.A = (uint8_t)ya;
_state.Y = ya >> 9;
if (ya & 0x100)
{
SetFlags(SpcFlags::Overflow);
}
else
{
ClearFlags(SpcFlags::Overflow);
}
SetZeroNegativeFlags(_state.A);
EndOp();
break;
}
}
void Spc::DAA()
{
switch (_opSubStep++)
{
case 0: Idle();
break;
case 1:
Idle();
if (CheckFlag(SpcFlags::Carry) || _state.A > 0x99)
{
_state.A += 0x60;
SetFlags(SpcFlags::Carry);
}
if (CheckFlag(SpcFlags::HalfCarry) || ((_state.A & 0x0F) > 9))
{
_state.A += 6;
}
SetZeroNegativeFlags(_state.A);
EndOp();
break;
}
}
void Spc::DAS()
{
switch (_opSubStep++)
{
case 0: Idle();
break;
case 1:
Idle();
if (!CheckFlag(SpcFlags::Carry) || _state.A > 0x99)
{
_state.A -= 0x60;
ClearFlags(SpcFlags::Carry);
}
if (!CheckFlag(SpcFlags::HalfCarry) || ((_state.A & 0x0F) > 9))
{
_state.A -= 6;
}
SetZeroNegativeFlags(_state.A);
EndOp();
break;
}
}
void Spc::AND()
{
if (_opStep == SpcOpStep::Operation)
{
switch (_opSubStep++)
{
case 0: _tmp1 = _operandA & Read(_operandB);
break;
case 1:
Write(_operandB, (uint8_t)_tmp1);
SetZeroNegativeFlags((uint8_t)_tmp1);
EndOp();
break;
}
}
}
void Spc::AND_Acc()
{
if (_opStep == SpcOpStep::Operation)
{
_state.A &= GetByteValue();
SetZeroNegativeFlags(_state.A);
EndOp();
}
}
void Spc::AND_Imm()
{
if (_opStep == SpcOpStep::AfterAddressing)
{
_state.A &= _operandA;
SetZeroNegativeFlags(_state.A);
EndOp();
}
}
void Spc::OR()
{
if (_opStep == SpcOpStep::Operation)
{
switch (_opSubStep++)
{
case 0: _tmp1 = _operandA | Read(_operandB);
break;
case 1:
Write(_operandB, (uint8_t)_tmp1);
SetZeroNegativeFlags((uint8_t)_tmp1);
EndOp();
break;
}
}
}
void Spc::OR_Acc()
{
if (_opStep == SpcOpStep::Operation)
{
_state.A |= GetByteValue();
SetZeroNegativeFlags(_state.A);
EndOp();
}
}
void Spc::OR_Imm()
{
if (_opStep == SpcOpStep::AfterAddressing)
{
_state.A |= _operandA;
SetZeroNegativeFlags(_state.A);
EndOp();
}
}
void Spc::EOR()
{
if (_opStep == SpcOpStep::Operation)
{
switch (_opSubStep++)
{
case 0: _tmp1 = _operandA ^ Read(_operandB);
break;
case 1:
Write(_operandB, (uint8_t)_tmp1);
SetZeroNegativeFlags((uint8_t)_tmp1);
EndOp();
break;
}
}
}
void Spc::EOR_Acc()
{
if (_opStep == SpcOpStep::Operation)
{
_state.A ^= GetByteValue();
SetZeroNegativeFlags(_state.A);
EndOp();
}
}
void Spc::EOR_Imm()
{
if (_opStep == SpcOpStep::AfterAddressing)
{
_state.A ^= _operandA;
SetZeroNegativeFlags(_state.A);
EndOp();
}
}
void Spc::SetCarry(uint8_t carry)
{
_state.PS = (_state.PS & ~SpcFlags::Carry) | carry;
}
void Spc::OR1()
{
if (_opStep == SpcOpStep::Operation)
{
switch (_opSubStep++)
{
case 0:
{
uint8_t carry = _state.PS & SpcFlags::Carry;
carry |= (Read(_operandA) >> _operandB) & 0x01;
SetCarry(carry);
break;
}
case 1:
Idle();
EndOp();
break;
}
}
}
void Spc::NOR1()
{
if (_opStep == SpcOpStep::Operation)
{
switch (_opSubStep++)
{
case 0:
{
uint8_t carry = _state.PS & SpcFlags::Carry;
carry |= ~((Read(_operandA) >> _operandB)) & 0x01;
SetCarry(carry);
break;
}
case 1:
Idle();
EndOp();
break;
}
}
}
void Spc::AND1()
{
if (_opStep == SpcOpStep::Operation)
{
uint8_t carry = _state.PS & SpcFlags::Carry;
carry &= (Read(_operandA) >> _operandB) & 0x01;
SetCarry(carry);
EndOp();
}
}
void Spc::NAND1()
{
if (_opStep == SpcOpStep::Operation)
{
uint8_t carry = _state.PS & SpcFlags::Carry;
carry &= ~((Read(_operandA) >> _operandB)) & 0x01;
SetCarry(carry);
EndOp();
}
}
void Spc::EOR1()
{
if (_opStep == SpcOpStep::Operation)
{
switch (_opSubStep++)
{
case 0:
{
uint8_t carry = _state.PS & SpcFlags::Carry;
carry ^= (Read(_operandA) >> _operandB) & 0x01;
SetCarry(carry);
break;
}
case 1:
Idle();
EndOp();
break;
}
}
}
void Spc::NOT1()
{
if (_opStep == SpcOpStep::Operation)
{
switch (_opSubStep++)
{
case 0: _tmp1 = Read(_operandA);
break;
case 1:
uint8_t mask = (1 << _operandB);
Write(_operandA, _tmp1 ^ mask);
EndOp();
break;
}
}
}
void Spc::STC()
{
if (_opStep == SpcOpStep::Operation)
{
switch (_opSubStep++)
{
case 0: _tmp1 = Read(_operandA);
break;
case 1: Idle();
break;
case 2:
uint8_t mask = (1 << _operandB);
uint8_t carry = (_state.PS & SpcFlags::Carry) << _operandB;
Write(_operandA, (_tmp1 & ~mask) | carry);
EndOp();
break;
}
}
}
void Spc::LDC()
{
if (_opStep == SpcOpStep::Operation)
{
uint8_t carry = (Read(_operandA) >> _operandB) & 0x01;
SetCarry(carry);
EndOp();
}
}
uint8_t Spc::ShiftLeft(uint8_t value)
{
uint8_t result = value << 1;
if (value & (1 << 7))
{
SetFlags(SpcFlags::Carry);
}
else
{
ClearFlags(SpcFlags::Carry);
}
SetZeroNegativeFlags(result);
return result;
}
uint8_t Spc::RollLeft(uint8_t value)
{
uint8_t result = value << 1 | (_state.PS & SpcFlags::Carry);
if (value & (1 << 7))
{
SetFlags(SpcFlags::Carry);
}
else
{
ClearFlags(SpcFlags::Carry);
}
SetZeroNegativeFlags(result);
return result;
}
uint8_t Spc::ShiftRight(uint8_t value)
{
uint8_t result = value >> 1;
if (value & 0x01)
{
SetFlags(SpcFlags::Carry);
}
else
{
ClearFlags(SpcFlags::Carry);
}
SetZeroNegativeFlags(result);
return result;
}
uint8_t Spc::RollRight(uint8_t value)
{
uint8_t result = value >> 1 | ((_state.PS & 0x01) << 7);
if (value & 0x01)
{
SetFlags(SpcFlags::Carry);
}
else
{
ClearFlags(SpcFlags::Carry);
}
SetZeroNegativeFlags(result);
return result;
}
void Spc::ASL()
{
if (_opStep == SpcOpStep::Operation)
{
switch (_opSubStep++)
{
case 0: _tmp1 = ShiftLeft(Read(_operandA));
break;
case 1:
Write(_operandA, (uint8_t)_tmp1);
EndOp();
break;
}
}
}
void Spc::ASL_Acc()
{
DummyRead();
_state.A = ShiftLeft(_state.A);
EndOp();
}
void Spc::LSR()
{
if (_opStep == SpcOpStep::Operation)
{
switch (_opSubStep++)
{
case 0: _tmp1 = ShiftRight(Read(_operandA));
break;
case 1:
Write(_operandA, (uint8_t)_tmp1);
EndOp();
break;
}
}
}
void Spc::LSR_Acc()
{
DummyRead();
_state.A = ShiftRight(_state.A);
EndOp();
}
void Spc::ROL()
{
if (_opStep == SpcOpStep::Operation)
{
switch (_opSubStep++)
{
case 0: _tmp1 = RollLeft(Read(_operandA));
break;
case 1:
Write(_operandA, (uint8_t)_tmp1);
EndOp();
break;
}
}
}
void Spc::ROL_Acc()
{
DummyRead();
_state.A = RollLeft(_state.A);
EndOp();
}
void Spc::ROR()
{
if (_opStep == SpcOpStep::Operation)
{
switch (_opSubStep++)
{
case 0: _tmp1 = RollRight(Read(_operandA));
break;
case 1:
Write(_operandA, (uint8_t)_tmp1);
EndOp();
break;
}
}
}
void Spc::ROR_Acc()
{
DummyRead();
_state.A = RollRight(_state.A);
EndOp();
}
void Spc::XCN()
{
switch (_opSubStep++)
{
case 0: DummyRead();
break;
case 1: Idle();
break;
case 2: Idle();
break;
case 3:
Idle();
_state.A = (_state.A >> 4) | (_state.A << 4);
SetZeroNegativeFlags(_state.A);
EndOp();
break;
}
}
void Spc::Branch()
{
switch (_opSubStep++)
{
case 0: Idle();
break;
case 1:
Idle();
int8_t offset = (int8_t)_operandA;
_state.PC = _state.PC + offset;
EndOp();
break;
}
}
void Spc::BRA()
{
if (_opStep == SpcOpStep::Operation)
{
Branch();
}
}
void Spc::BEQ()
{
if (_opStep == SpcOpStep::Operation)
{
if (CheckFlag(SpcFlags::Zero))
{
Branch();
}
else
{
EndOp();
}
}
}
void Spc::BNE()
{
if (_opStep == SpcOpStep::Operation)
{
if (!CheckFlag(SpcFlags::Zero))
{
Branch();
}
else
{
EndOp();
}
}
}
void Spc::BCS()
{
if (_opStep == SpcOpStep::Operation)
{
if (CheckFlag(SpcFlags::Carry))
{
Branch();
}
else
{
EndOp();
}
}
}
void Spc::BCC()
{
if (_opStep == SpcOpStep::Operation)
{
if (!CheckFlag(SpcFlags::Carry))
{
Branch();
}
else
{
EndOp();
}
}
}
void Spc::BVS()
{
if (_opStep == SpcOpStep::Operation)
{
if (CheckFlag(SpcFlags::Overflow))
{
Branch();
}
else
{
EndOp();
}
}
}
void Spc::BVC()
{
if (_opStep == SpcOpStep::Operation)
{
if (!CheckFlag(SpcFlags::Overflow))
{
Branch();
}
else
{
EndOp();
}
}
}
void Spc::BMI()
{
if (_opStep == SpcOpStep::Operation)
{
if (CheckFlag(SpcFlags::Negative))
{
Branch();
}
else
{
EndOp();
}
}
}
void Spc::BPL()
{
if (_opStep == SpcOpStep::Operation)
{
if (!CheckFlag(SpcFlags::Negative))
{
Branch();
}
else
{
EndOp();
}
}
}
template <uint8_t bit>
void Spc::SET1()
{
if (_opStep == SpcOpStep::Operation)
{
switch (_opSubStep++)
{
case 0: _tmp1 = Read(_operandA);
break;
case 1:
Write(_operandA, _tmp1 | (1 << bit));
EndOp();
break;
}
}
}
template <uint8_t bit>
void Spc::CLR1()
{
if (_opStep == SpcOpStep::Operation)
{
switch (_opSubStep++)
{
case 0: _tmp1 = Read(_operandA);
break;
case 1:
Write(_operandA, _tmp1 & ~(1 << bit));
EndOp();
break;
}
}
}
template <uint8_t bit>
void Spc::BBS()
{
if (_opStep == SpcOpStep::Operation)
{
switch (_opSubStep++)
{
case 0: _tmp1 = Read(_operandA);
break;
case 1: Idle();
break;
case 2:
_tmp2 = ReadOperandByte();
if (!(_tmp1 & (1 << bit)))
{
EndOp();
}
break;
case 3: Idle();
break;
case 4:
Idle();
_state.PC += (int8_t)_tmp2;
EndOp();
break;
}
}
}
template <uint8_t bit>
void Spc::BBC()
{
if (_opStep == SpcOpStep::Operation)
{
switch (_opSubStep++)
{
case 0: _tmp1 = Read(_operandA);
break;
case 1: Idle();
break;
case 2:
_tmp2 = ReadOperandByte();
if (_tmp1 & (1 << bit))
{
EndOp();
}
break;
case 3: Idle();
break;
case 4:
Idle();
_state.PC += (int8_t)_tmp2;
EndOp();
break;
}
}
}
void Spc::CBNE()
{
if (_opStep == SpcOpStep::Operation)
{
switch (_opSubStep++)
{
case 0: _tmp1 = Read(_operandA);
break;
case 1: Idle();
break;
case 2:
_tmp2 = ReadOperandByte();
if (_state.A == _tmp1)
{
EndOp();
}
break;
case 3: Idle();
break;
case 4:
Idle();
_state.PC += (int8_t)_tmp2;
EndOp();
break;
}
}
}
void Spc::DBNZ()
{
if (_opStep == SpcOpStep::Operation)
{
switch (_opSubStep++)
{
case 0: _tmp1 = Read(_operandA) - 1;
break;
case 1: Write(_operandA, (uint8_t)_tmp1);
break;
case 2:
_tmp2 = ReadOperandByte();
if (!_tmp1)
{
EndOp();
}
break;
case 3: Idle();
break;
case 4:
Idle();
_state.PC += (int8_t)_tmp2;
EndOp();
break;
}
}
}
void Spc::DBNZ_Y()
{
switch (_opSubStep++)
{
case 0: DummyRead();
break;
case 1: Idle();
break;
case 2:
_state.Y--;
_tmp2 = ReadOperandByte();
if (!_state.Y)
{
EndOp();
}
break;
case 3: Idle();
break;
case 4:
Idle();
_state.PC += (int8_t)_tmp2;
EndOp();
break;
}
}
void Spc::JMP()
{
if (_opStep == SpcOpStep::AfterAddressing)
{
_state.PC = _operandA;
EndOp();
}
}
void Spc::NOTC()
{
switch (_opSubStep++)
{
case 0: DummyRead();
break;
case 1:
Idle();
if (CheckFlag(SpcFlags::Carry))
{
ClearFlags(SpcFlags::Carry);
}
else
{
SetFlags(SpcFlags::Carry);
}
EndOp();
break;
}
}
void Spc::CLRC()
{
DummyRead();
ClearFlags(SpcFlags::Carry);
EndOp();
}
void Spc::CLRP()
{
DummyRead();
ClearFlags(SpcFlags::DirectPage);
EndOp();
}
void Spc::CLRV()
{
DummyRead();
ClearFlags(SpcFlags::Overflow | SpcFlags::HalfCarry);
EndOp();
}
void Spc::SETC()
{
DummyRead();
SetFlags(SpcFlags::Carry);
EndOp();
}
void Spc::SETP()
{
DummyRead();
SetFlags(SpcFlags::DirectPage);
EndOp();
}
void Spc::EI()
{
switch (_opSubStep++)
{
case 0: DummyRead();
break;
case 1:
SetFlags(SpcFlags::IrqEnable);
Idle();
EndOp();
break;
}
}
void Spc::DI()
{
switch (_opSubStep++)
{
case 0: DummyRead();
break;
case 1:
ClearFlags(SpcFlags::IrqEnable);
Idle();
EndOp();
break;
}
}
void Spc::TSET1()
{
if (_opStep == SpcOpStep::Operation)
{
switch (_opSubStep++)
{
case 0: _tmp1 = Read(_operandA);
break;
case 1: DummyRead(_operandA);
break;
case 2:
Write(_operandA, _tmp1 | _state.A);
SetZeroNegativeFlags(_state.A - _tmp1);
EndOp();
break;
}
}
}
void Spc::TCLR1()
{
if (_opStep == SpcOpStep::Operation)
{
switch (_opSubStep++)
{
case 0: _tmp1 = Read(_operandA);
break;
case 1: DummyRead(_operandA);
break;
case 2:
Write(_operandA, _tmp1 & ~_state.A);
SetZeroNegativeFlags(_state.A - _tmp1);
EndOp();
break;
}
}
}
template <uint8_t offset>
void Spc::TCALL()
{
constexpr uint16_t vectorAddr = 0xFFDE - (offset * 2);
switch (_opSubStep++)
{
case 0: DummyRead();
break;
case 1: Idle();
break;
case 2: Push(_state.PC >> 8);
break;
case 3: Push((uint8_t)_state.PC);
break;
case 4: Idle();
break;
case 5: _tmp1 = Read(vectorAddr);
break;
case 6:
_state.PC = (Read(vectorAddr + 1) << 8) | _tmp1;
EndOp();
break;
}
}
void Spc::PCALL()
{
switch (_opSubStep++)
{
case 0: _tmp1 = ReadOperandByte();
break;
case 1: Idle();
break;
case 2: Push(_state.PC >> 8);
break;
case 3: Push((uint8_t)_state.PC);
break;
case 4:
Idle();
_state.PC = 0xFF00 | _tmp1;
EndOp();
break;
}
}
void Spc::JSR()
{
if (_opStep == SpcOpStep::Operation)
{
switch (_opSubStep++)
{
case 0: Idle();
break;
case 1: Push(_state.PC >> 8);
break;
case 2: Push((uint8_t)_state.PC);
break;
case 3: Idle();
break;
case 4:
Idle();
_state.PC = _operandA;
EndOp();
break;
}
}
}
void Spc::RTS()
{
switch (_opSubStep++)
{
case 0: DummyRead();
break;
case 1: Idle();
break;
case 2: _tmp1 = Pop();
break;
case 3:
_state.PC = (Pop() << 8) | _tmp1;
EndOp();
break;
}
}
void Spc::RTI()
{
switch (_opSubStep++)
{
case 0: DummyRead();
break;
case 1: Idle();
break;
case 2: _state.PS = Pop();
break;
case 3: _tmp1 = Pop();
break;
case 4:
_state.PC = (Pop() << 8) | _tmp1;
EndOp();
break;
}
}
void Spc::BRK()
{
switch (_opSubStep++)
{
case 0: Idle();
break;
case 1: Push(_state.PC >> 8);
break;
case 2: Push((uint8_t)_state.PC);
break;
case 3: Push(_state.PS);
break;
case 4: Idle();
break;
case 5: _tmp1 = Read(0xFFDE);
break;
case 6:
uint8_t msb = Read(0xFFDF);
_state.PC = (msb << 8) | _tmp1;
SetFlags(SpcFlags::Break);
ClearFlags(SpcFlags::IrqEnable);
EndOp();
break;
}
}
void Spc::PushOperation(uint8_t value)
{
switch (_opSubStep++)
{
case 0: DummyRead();
break;
case 1: Push(value);
break;
case 2:
Idle();
EndOp();
break;
}
}
void Spc::PullOperation(uint8_t& dst)
{
switch (_opSubStep++)
{
case 0: DummyRead();
break;
case 1: Idle();
break;
case 2:
dst = Pop();
EndOp();
break;
}
}
void Spc::PHA()
{
PushOperation(_state.A);
}
void Spc::PHX()
{
PushOperation(_state.X);
}
void Spc::PHY()
{
PushOperation(_state.Y);
}
void Spc::PHP()
{
PushOperation(_state.PS);
}
void Spc::PLA()
{
PullOperation(_state.A);
}
void Spc::PLX()
{
PullOperation(_state.X);
}
void Spc::PLY()
{
PullOperation(_state.Y);
}
void Spc::PLP()
{
PullOperation(_state.PS);
}
void Spc::NOP()
{
DummyRead();
EndOp();
}
void Spc::SLEEP()
{
//WAI
_state.StopState = CpuStopState::WaitingForIrq;
EndOp();
}
void Spc::STOP()
{
//STP
_state.StopState = CpuStopState::Stopped;
EndOp();
}