2113 lines
40 KiB
C++
2113 lines
40 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(_tmp2, _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, _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(_tmp2, _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, _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, _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, _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, _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, _tmp1);
|
|
SetZeroNegativeFlags(_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, _tmp1);
|
|
SetZeroNegativeFlags(_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, _tmp1);
|
|
SetZeroNegativeFlags(_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, _tmp1);
|
|
SetZeroNegativeFlags(_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, _tmp1);
|
|
SetZeroNegativeFlags(_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, _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, _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, _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, _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, _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
|
|
}
|
|
|
|
void Spc::STOP()
|
|
{
|
|
//STP
|
|
}
|