2951 lines
42 KiB
C++
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();
|
|
}
|