diff --git a/CMakeLists.txt b/CMakeLists.txt index 8c2d8c4..6533542 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -93,7 +93,7 @@ add_executable(unit_tests tests/CPU/TransferRegisters.cpp sources/CPU/AddressingModes.cpp sources/Models/Components.hpp -) + sources/CPU/Instruction.hpp sources/Exceptions/DebuggableError.hpp) # include criterion & coverage target_link_libraries(unit_tests criterion -lgcov) @@ -200,7 +200,7 @@ add_executable(ComSquare sources/Debugger/MemoryBusDebug.cpp sources/Debugger/MemoryBusDebug.hpp sources/Debugger/ClosableWindow.hpp - sources/Models/Components.hpp) + sources/Models/Components.hpp sources/CPU/Instruction.hpp sources/Exceptions/DebuggableError.hpp) target_compile_definitions(ComSquare PUBLIC DEBUGGER_ENABLED) diff --git a/sources/CPU/AddressingModes.cpp b/sources/CPU/AddressingModes.cpp index edcb35f..9b78aa2 100644 --- a/sources/CPU/AddressingModes.cpp +++ b/sources/CPU/AddressingModes.cpp @@ -7,6 +7,11 @@ namespace ComSquare::CPU { + uint24_t CPU::_getImmediateAddr8Bits() + { + return this->_registers.pac++; + } + uint24_t CPU::_getImmediateAddrForA() { uint24_t effective = this->_registers.pac++; diff --git a/sources/CPU/CPU.cpp b/sources/CPU/CPU.cpp index afe5d53..8791036 100644 --- a/sources/CPU/CPU.cpp +++ b/sources/CPU/CPU.cpp @@ -206,191 +206,290 @@ namespace ComSquare::CPU unsigned CPU::_executeInstruction(uint8_t opcode) { + Instruction instruction = this->_instructions[opcode]; + this->_hasIndexCrossedPageBoundary = false; - uint24_t addr; - switch (opcode) { - case Instructions::BRK: this->BRK(); return 7 + !this->_isEmulationMode; + uint24_t valueAddr = 0; + int cycles = instruction.cycleCount + !this->_registers.p.m; - case Instructions::COP: this->COP(); return 7 + !this->_isEmulationMode; + switch (instruction.addressingMode) { + case Implied: + break; + case Immediate8bits: + valueAddr = this->_getImmediateAddr8Bits(); + break; + case ImmediateForA: + valueAddr = this->_getImmediateAddrForA(); + break; + case ImmediateForX: + valueAddr = this->_getImmediateAddrForX(); + break; - case Instructions::RTI: this->RTI(); return 6 + !this->_isEmulationMode; + // TODO implement the relative addressing mode + // TODO implement the relative long addressing mode - case Instructions::ADC_IM: this->ADC(this->_getImmediateAddrForA()); return 2 + !this->_registers.p.m; - case Instructions::ADC_ABS: this->ADC(this->_getAbsoluteAddr()); return 4 + !this->_registers.p.m; - case Instructions::ADC_ABSl: this->ADC(this->_getAbsoluteLongAddr()); return 5 + !this->_registers.p.m; - case Instructions::ADC_DP: this->ADC(this->_getDirectAddr()); return 3 + !this->_registers.p.m + this->_registers.dl != 0; - case Instructions::ADC_DPi: this->ADC(this->_getDirectIndirectAddr()); return 5 + !this->_registers.p.m + this->_registers.dl != 0; - case Instructions::ADC_DPil: this->ADC(this->_getDirectIndirectLongAddr()); return 6 + !this->_registers.p.m + this->_registers.dl != 0; - case Instructions::ADC_ABSX: this->ADC(this->_getAbsoluteIndexedByXAddr()); return 4 + !this->_registers.p.m + this->_hasIndexCrossedPageBoundary; - case Instructions::ADC_ABSXl:this->ADC(this->_getAbsoluteIndexedByXLongAddr()); return 5 + !this->_registers.p.m; - case Instructions::ADC_ABSY: this->ADC(this->_getAbsoluteIndexedByYAddr()); return 4 + !this->_registers.p.m + this->_hasIndexCrossedPageBoundary; - case Instructions::ADC_DPX: this->ADC(this->_getDirectIndexedByXAddr()); return 4 + !this->_registers.p.m + this->_registers.dl != 0; - case Instructions::ADC_DPXi: this->ADC(this->_getDirectIndirectIndexedXAddr()); return 6 + !this->_registers.p.m + this->_registers.dl != 0; - case Instructions::ADC_DPYi: this->ADC(this->_getDirectIndirectIndexedYAddr()); return 5 + !this->_registers.p.m + this->_registers.dl != 0 + this->_hasIndexCrossedPageBoundary; - case Instructions::ADC_DPYil:this->ADC(this->_getDirectIndirectIndexedYLongAddr()); return 6 + !this->_registers.p.m + this->_registers.dl != 0; - case Instructions::ADC_SR: this->ADC(this->_getStackRelativeAddr()); return 4 + !this->_registers.p.m; - case Instructions::ADC_SRYi: this->ADC(this->_getStackRelativeIndirectIndexedYAddr()); return 7 + !this->_registers.p.m; + case Absolute: + valueAddr = this->_getAbsoluteAddr(); + break; + case AbsoluteLong: + valueAddr = this->_getAbsoluteLongAddr(); + break; + case AbsoluteIndirect: + valueAddr = this->_getAbsoluteIndirectAddr(); + break; - case Instructions::STA_ABS: this->STA(this->_getAbsoluteAddr()); return 4 + !this->_registers.p.m; - case Instructions::STA_ABSl: this->STA(this->_getAbsoluteLongAddr()); return 5 + !this->_registers.p.m; - case Instructions::STA_DP: this->STA(this->_getDirectAddr()); return 3 + !this->_registers.p.m + this->_registers.dl != 0; - case Instructions::STA_DPi: this->STA(this->_getDirectIndirectAddr()); return 5 + !this->_registers.p.m + this->_registers.dl != 0; - case Instructions::STA_DPil: this->STA(this->_getDirectIndirectLongAddr()); return 6 + !this->_registers.p.m + this->_registers.dl != 0; - case Instructions::STA_ABSX: this->STA(this->_getAbsoluteIndexedByXAddr()); return 5 + !this->_registers.p.m; - case Instructions::STA_ABSXl:this->STA(this->_getAbsoluteIndexedByXLongAddr()); return 5 + !this->_registers.p.m; - case Instructions::STA_ABSY: this->STA(this->_getAbsoluteIndexedByYAddr()); return 5 + !this->_registers.p.m; - case Instructions::STA_DPX: this->STA(this->_getDirectIndexedByXAddr()); return 4 + !this->_registers.p.m + this->_registers.dl != 0; - case Instructions::STA_DPXi: this->STA(this->_getDirectIndirectIndexedXAddr()); return 6 + !this->_registers.p.m + this->_registers.dl != 0; - case Instructions::STA_DPYi: this->STA(this->_getDirectIndirectIndexedYAddr()); return 6 + !this->_registers.p.m + this->_registers.dl != 0; - case Instructions::STA_DPYil:this->STA(this->_getDirectIndirectIndexedYLongAddr()); return 6 + !this->_registers.p.m + this->_registers.dl != 0; - case Instructions::STA_SR: this->STA(this->_getStackRelativeAddr()); return 4 + !this->_registers.p.m; - case Instructions::STA_SRYi: this->STA(this->_getStackRelativeIndirectIndexedYAddr()); return 7 + !this->_registers.p.m; + //TODO implement absolute indirect long addressing mode - case Instructions::STX_ABS: this->STX(this->_getAbsoluteAddr()); return 4 + !this->_registers.p.m; - case Instructions::STX_DP: this->STX(this->_getDirectAddr()); return 3 + !this->_registers.p.m + this->_registers.dl != 0; - case Instructions::STX_DPY: this->STX(this->_getDirectIndexedByYAddr()); return 4 + !this->_registers.p.m + this->_registers.dl != 0; + case DirectPage: + valueAddr = this->_getDirectAddr(); + cycles += this->_registers.dl != 0; + break; + case DirectPageIndirect: + valueAddr = this->_getDirectIndirectAddr(); + cycles += this->_registers.dl != 0; + break; + case DirectPageIndirectLong: + valueAddr = this->_getDirectIndirectLongAddr(); + cycles += this->_registers.dl != 0; + break; - case Instructions::STY_ABS: this->STX(this->_getAbsoluteAddr()); return 4 + !this->_registers.p.m; - case Instructions::STY_DP: this->STX(this->_getDirectAddr()); return 3 + !this->_registers.p.m + this->_registers.dl != 0; - case Instructions::STY_DPX: this->STX(this->_getDirectIndexedByXAddr()); return 4 + !this->_registers.p.m + this->_registers.dl != 0; + case DirectPageIndexedByX: + valueAddr = this->_getDirectIndexedByXAddr(); + cycles += this->_registers.dl != 0; + break; + case DirectPageIndexedByY: + valueAddr = this->_getDirectIndexedByYAddr(); + cycles += this->_registers.dl != 0; + break; + case DirectPageIndirectIndexedByX: + valueAddr = this->_getDirectIndirectIndexedXAddr(); + cycles += this->_registers.dl != 0; + break; + case DirectPageIndirectIndexedByY: + valueAddr = this->_getDirectIndirectIndexedYAddr(); + cycles += this->_registers.dl != 0; + break; + case DirectPageIndirectIndexedByYLong: + valueAddr = this->_getDirectIndirectIndexedYLongAddr(); + cycles += this->_registers.dl != 0 + this->_hasIndexCrossedPageBoundary; + break; - case Instructions::STZ_ABS: this->STX(this->_getAbsoluteAddr()); return 4 + !this->_registers.p.m; - case Instructions::STZ_DP: this->STX(this->_getDirectAddr()); return 3 + !this->_registers.p.m + this->_registers.dl != 0; - case Instructions::STZ_ABSX: this->STX(this->_getAbsoluteIndexedByXAddr()); return 3 + !this->_registers.p.m + this->_registers.dl != 0; - case Instructions::STZ_DPX: this->STX(this->_getDirectIndexedByXAddr()); return 4 + !this->_registers.p.m + this->_registers.dl != 0; + case AbsoluteIndexedByX: + valueAddr = this->_getAbsoluteIndexedByXAddr(); + cycles += this->_hasIndexCrossedPageBoundary; + break; + case AbsoluteIndexedByXLong: + valueAddr = this->_getAbsoluteIndexedByXLongAddr(); + break; + case AbsoluteIndexedByY: + valueAddr = this->_getAbsoluteIndexedByYAddr(); + cycles += this->_hasIndexCrossedPageBoundary; + break; - case Instructions::LDA_IM: this->LDA(this->_getImmediateAddrForA()); return 2 + !this->_registers.p.m; - case Instructions::LDA_ABS: this->LDA(this->_getAbsoluteAddr()); return 4 + !this->_registers.p.m; - case Instructions::LDA_ABSl: this->LDA(this->_getAbsoluteLongAddr()); return 5 + !this->_registers.p.m; - case Instructions::LDA_DP: this->LDA(this->_getDirectAddr()); return 3 + !this->_registers.p.m + this->_registers.dl != 0; - case Instructions::LDA_DPi: this->LDA(this->_getDirectIndirectAddr()); return 5 + !this->_registers.p.m + this->_registers.dl != 0; - case Instructions::LDA_DPil: this->LDA(this->_getDirectIndirectLongAddr()); return 6 + !this->_registers.p.m + this->_registers.dl != 0; - case Instructions::LDA_ABSX: this->LDA(this->_getAbsoluteIndexedByXAddr()); return 4 + !this->_registers.p.m + this->_hasIndexCrossedPageBoundary; - case Instructions::LDA_ABSXl:this->LDA(this->_getAbsoluteIndexedByXLongAddr()); return 5 + !this->_registers.p.m; - case Instructions::LDA_ABSY: this->LDA(this->_getAbsoluteIndexedByYAddr()); return 4 + !this->_registers.p.m + this->_hasIndexCrossedPageBoundary; - case Instructions::LDA_DPX: this->LDA(this->_getDirectIndexedByXAddr()); return 4 + !this->_registers.p.m + this->_registers.dl != 0; - case Instructions::LDA_DPXi: this->LDA(this->_getDirectIndirectIndexedXAddr()); return 6 + !this->_registers.p.m + this->_registers.dl != 0; - case Instructions::LDA_DPYi: this->LDA(this->_getDirectIndirectIndexedYAddr()); return 5 + !this->_registers.p.m + this->_registers.dl != 0 + this->_hasIndexCrossedPageBoundary; - case Instructions::LDA_DPYil:this->LDA(this->_getDirectIndirectIndexedYLongAddr()); return 6 + !this->_registers.p.m + this->_registers.dl != 0; - case Instructions::LDA_SR: this->LDA(this->_getStackRelativeAddr()); return 4 + !this->_registers.p.m; - case Instructions::LDA_SRYi: this->LDA(this->_getStackRelativeIndirectIndexedYAddr()); return 7 + !this->_registers.p.m; + case StackRelative: + valueAddr = this->_getStackRelativeAddr(); + break; + case StackRelativeIndirectIndexedByY: + valueAddr = this->_getStackRelativeIndirectIndexedYAddr(); + break; - case Instructions::LDX_IM: this->LDX(this->_getImmediateAddrForX()); return 2 + !this->_registers.p.m; - case Instructions::LDX_ABS: this->LDX(this->_getAbsoluteAddr()); return 4 + !this->_registers.p.m; - case Instructions::LDX_DP: this->LDX(this->_getDirectAddr()); return 3 + !this->_registers.p.m + this->_registers.dl != 0; - case Instructions::LDX_ABSY: this->LDX(this->_getAbsoluteIndexedByYAddr()); return 4 + !this->_registers.p.m + this->_hasIndexCrossedPageBoundary; - case Instructions::LDX_DPY: this->LDX(this->_getDirectIndexedByYAddr()); return 4 + !this->_registers.p.m + this->_registers.dl != 0; - - case Instructions::LDY_IM: this->LDY(this->_getImmediateAddrForX()); return 2 + !this->_registers.p.m; - case Instructions::LDY_ABS: this->LDY(this->_getAbsoluteAddr()); return 4 + !this->_registers.p.m; - case Instructions::LDY_DP: this->LDY(this->_getDirectAddr()); return 3 + !this->_registers.p.m + this->_registers.dl != 0; - case Instructions::LDY_ABSY: this->LDY(this->_getAbsoluteIndexedByYAddr()); return 4 + !this->_registers.p.m + this->_hasIndexCrossedPageBoundary; - case Instructions::LDY_DPY: this->LDY(this->_getDirectIndexedByYAddr()); return 4 + !this->_registers.p.m + this->_registers.dl != 0; - - case Instructions::SEP: this->SEP(this->_bus->read(this->_registers.pc++)); return 3; - - case Instructions::REP: this->REP(this->_bus->read(this->_registers.pc++)); return 3; - - case Instructions::PHA: this->PHA(); return 3 + !this->_registers.p.m; - case Instructions::PHB: this->PHB(); return 3; - case Instructions::PHD: this->PHD(); return 4; - case Instructions::PHK: this->PHK(); return 3; - case Instructions::PHP: this->PHP(); return 3; - case Instructions::PHX: this->PHX(); return 3 + !this->_registers.p.x_b; - case Instructions::PHY: this->PHY(); return 3 + !this->_registers.p.x_b; - - case Instructions::PLA: this->PLA(); return 4 + !this->_registers.p.m; - case Instructions::PLB: this->PLB(); return 4; - case Instructions::PLD: this->PLD(); return 5; - case Instructions::PLP: this->PLP(); return 4; - case Instructions::PLX: this->PLX(); return 4 + !this->_registers.p.x_b; - case Instructions::PLY: this->PLY(); return 4 + !this->_registers.p.x_b; - - case Instructions::JSR_ABS: this->JSR(this->_getAbsoluteAddr()); return 6; - case Instructions::JSR_ABSXi: this->JSR(this->_getAbsoluteIndirectIndexedByXAddr()); return 8; - - case Instructions::JSL: this->JSL(this->_getAbsoluteLongAddr()); return 8; - - case Instructions::CLC: this->CLC(); return 2; - case Instructions::CLI: this->CLI(); return 2; - case Instructions::CLD: this->CLD(); return 2; - case Instructions::CLV: this->CLV(); return 2; - - case Instructions::SEC: this->SEC(); return 2; - case Instructions::SED: this->SED(); return 2; - case Instructions::SEI: this->SEI(); return 2; - - case Instructions::AND_IM: this->AND(this->_getImmediateAddrForA()); return 2 + !this->_registers.p.m; - case Instructions::AND_ABS: this->AND(this->_getAbsoluteAddr()); return 4 + !this->_registers.p.m; - case Instructions::AND_ABSl: this->AND(this->_getAbsoluteLongAddr()); return 5 + !this->_registers.p.m; - case Instructions::AND_DP: this->AND(this->_getDirectAddr()); return 3 + !this->_registers.p.m + this->_registers.dl != 0; - case Instructions::AND_DPi: this->AND(this->_getDirectIndirectAddr()); return 5 + !this->_registers.p.m + this->_registers.dl != 0; - case Instructions::AND_DPil: this->AND(this->_getDirectIndirectLongAddr()); return 6 + !this->_registers.p.m + this->_registers.dl != 0; - case Instructions::AND_ABSX: this->AND(this->_getAbsoluteIndexedByXAddr()); return 4 + !this->_registers.p.m + this->_hasIndexCrossedPageBoundary; - case Instructions::AND_ABSXl:this->AND(this->_getAbsoluteIndexedByXLongAddr()); return 5 + !this->_registers.p.m; - case Instructions::AND_ABSY: this->AND(this->_getAbsoluteIndexedByYAddr()); return 4 + !this->_registers.p.m + this->_hasIndexCrossedPageBoundary; - case Instructions::AND_DPX: this->AND(this->_getDirectIndexedByXAddr()); return 4 + !this->_registers.p.m + this->_registers.dl != 0; - case Instructions::AND_DPXi: this->AND(this->_getDirectIndirectIndexedXAddr()); return 6 + !this->_registers.p.m + this->_registers.dl != 0; - case Instructions::AND_DPYi: this->AND(this->_getDirectIndirectIndexedYAddr()); return 5 + !this->_registers.p.m + this->_registers.dl != 0 + this->_hasIndexCrossedPageBoundary; - case Instructions::AND_DPYil:this->AND(this->_getDirectIndirectIndexedYLongAddr()); return 6 + !this->_registers.p.m + this->_registers.dl != 0; - case Instructions::AND_SR: this->AND(this->_getStackRelativeAddr()); return 4 + !this->_registers.p.m; - case Instructions::AND_SRYi: this->AND(this->_getStackRelativeIndirectIndexedYAddr()); return 7 + !this->_registers.p.m; - - case Instructions::XCE: this->XCE(); return 2; - - case Instructions::SBC_IM: this->SBC(this->_getImmediateAddrForA()); return 2 + !this->_registers.p.m; - case Instructions::SBC_ABS: this->SBC(this->_getAbsoluteAddr()); return 4 + !this->_registers.p.m; - case Instructions::SBC_ABSl: this->SBC(this->_getAbsoluteLongAddr()); return 5 + !this->_registers.p.m; - case Instructions::SBC_DP: this->SBC(this->_getDirectAddr()); return 3 + !this->_registers.p.m + this->_registers.dl != 0; - case Instructions::SBC_DPi: this->SBC(this->_getDirectIndirectAddr()); return 5 + !this->_registers.p.m + this->_registers.dl != 0; - case Instructions::SBC_DPil: this->SBC(this->_getDirectIndirectLongAddr()); return 6 + !this->_registers.p.m + this->_registers.dl != 0; - case Instructions::SBC_ABSX: this->SBC(this->_getAbsoluteIndexedByXAddr()); return 4 + !this->_registers.p.m + this->_hasIndexCrossedPageBoundary; - case Instructions::SBC_ABSXl:this->SBC(this->_getAbsoluteIndexedByXLongAddr()); return 5 + !this->_registers.p.m; - case Instructions::SBC_ABSY: this->SBC(this->_getAbsoluteIndexedByYAddr()); return 4 + !this->_registers.p.m + this->_hasIndexCrossedPageBoundary; - case Instructions::SBC_DPX: this->SBC(this->_getDirectIndexedByXAddr()); return 4 + !this->_registers.p.m + this->_registers.dl != 0; - case Instructions::SBC_DPXi: this->SBC(this->_getDirectIndirectIndexedXAddr()); return 6 + !this->_registers.p.m + this->_registers.dl != 0; - case Instructions::SBC_DPYi: this->SBC(this->_getDirectIndirectIndexedYAddr()); return 5 + !this->_registers.p.m + this->_registers.dl != 0 + this->_hasIndexCrossedPageBoundary; - case Instructions::SBC_DPYil:this->SBC(this->_getDirectIndirectIndexedYLongAddr()); return 6 + !this->_registers.p.m + this->_registers.dl != 0; - case Instructions::SBC_SR: this->SBC(this->_getStackRelativeAddr()); return 4 + !this->_registers.p.m; - case Instructions::SBC_SRYi: this->SBC(this->_getStackRelativeIndirectIndexedYAddr()); return 7 + !this->_registers.p.m; - - case Instructions::TAX: this->TAX(); return 2; - case Instructions::TAY: this->TAY(); return 2; - case Instructions::TXS: this->TXS(); return 2; - - case Instructions::INX: this->INX(); return 2; - case Instructions::INY: this->INY(); return 2; - - case Instructions::CPX_IM: this->CPX(this->_getImmediateAddrForX()); return 2 + !this->_registers.p.m; - case Instructions::CPX_ABS: this->CPX(this->_getAbsoluteAddr()); return 4 + !this->_registers.p.m; - case Instructions::CPX_DP: this->CPX(this->_getDirectAddr()); return 3 + !this->_registers.p.m + this->_registers.dl != 0; - - case Instructions::CPY_IM: this->CPY(this->_getImmediateAddrForX()); return 2 + !this->_registers.p.m; - case Instructions::CPY_ABS: this->CPY(this->_getAbsoluteAddr()); return 4 + !this->_registers.p.m; - case Instructions::CPY_DP: this->CPY(this->_getDirectAddr()); return 3 + !this->_registers.p.m + this->_registers.dl != 0; - - case Instructions::BCC: return this->BCC(this->_registers.pc++) + 2 + this->_isEmulationMode; - case Instructions::BCS: return this->BCS(this->_registers.pc++) + 2 + this->_isEmulationMode; - case Instructions::BEQ: return this->BEQ(this->_registers.pc++) + 2 + this->_isEmulationMode; - case Instructions::BNE: return this->BNE(this->_registers.pc++) + 2 + this->_isEmulationMode; - case Instructions::BMI: return this->BMI(this->_registers.pc++) + 2 + this->_isEmulationMode; - case Instructions::BPL: return this->BPL(this->_registers.pc++) + 2 + this->_isEmulationMode; - case Instructions::BVC: return this->BVC(this->_registers.pc++) + 2 + this->_isEmulationMode; - case Instructions::BVS: return this->BVS(this->_registers.pc++) + 2 + this->_isEmulationMode; - case Instructions::BRA: this->BRA(this->_registers.pc++); return 3 + this->_isEmulationMode; - case Instructions::BRL: this->BRL(this->_registers.pc); this->_registers.pc += 2; return 4; - - case Instructions::JMP_ABS: addr = this->_getAbsoluteAddr(); this->JMP(addr); return 3; - case Instructions::JMP_ABSi: addr = this->_getAbsoluteIndirectAddr(); this->JMP(addr); return 3; - case Instructions::JMP_ABSXi: addr = this->_getAbsoluteIndexedByXAddr(); this->JMP(addr); return 3; - - case Instructions::JML_ABSl: addr = this->_getAbsoluteLongAddr(); this->JML(addr); return 3; - //case Instructions::JML_ABSil: this->JML(this->_getAbsoluteLong()); return 3; - - default: - throw InvalidOpcode("CPU", opcode); + case ProgramCounterRelative: + valueAddr = this->_getProgramCounterRelativeAddr(); + break; + case ProgramCounterRelativeLong: + valueAddr = this->_getProgramCounterRelativeLongAddr(); + break; + case AbsoluteIndirectIndexedByX: + valueAddr = this->_getAbsoluteIndirectIndexedByXAddr(); + break; } + + return cycles + (this->*instruction.call)(valueAddr); +// uint24_t addr; +// +// switch (opcode) { +// case Instructions::BRK: this->BRK(0x0); return 7 + !this->_isEmulationMode; +// +// case Instructions::COP: this->COP(); return 7 + !this->_isEmulationMode; +// +// case Instructions::RTI: this->RTI(); return 6 + !this->_isEmulationMode; +// +// case Instructions::ADC_IM: this->ADC(this->_getImmediateAddrForA()); return 2 + !this->_registers.p.m; +// case Instructions::ADC_ABS: this->ADC(this->_getAbsoluteAddr()); return 4 + !this->_registers.p.m; +// case Instructions::ADC_ABSl: this->ADC(this->_getAbsoluteLongAddr()); return 5 + !this->_registers.p.m; +// case Instructions::ADC_DP: this->ADC(this->_getDirectAddr()); return 3 + !this->_registers.p.m + this->_registers.dl != 0; +// case Instructions::ADC_DPi: this->ADC(this->_getDirectIndirectAddr()); return 5 + !this->_registers.p.m + this->_registers.dl != 0; +// case Instructions::ADC_DPil: this->ADC(this->_getDirectIndirectLongAddr()); return 6 + !this->_registers.p.m + this->_registers.dl != 0; +// case Instructions::ADC_ABSX: this->ADC(this->_getAbsoluteIndexedByXAddr()); return 4 + !this->_registers.p.m + this->_hasIndexCrossedPageBoundary; +// case Instructions::ADC_ABSXl:this->ADC(this->_getAbsoluteIndexedByXLongAddr()); return 5 + !this->_registers.p.m; +// case Instructions::ADC_ABSY: this->ADC(this->_getAbsoluteIndexedByYAddr()); return 4 + !this->_registers.p.m + this->_hasIndexCrossedPageBoundary; +// case Instructions::ADC_DPX: this->ADC(this->_getDirectIndexedByXAddr()); return 4 + !this->_registers.p.m + this->_registers.dl != 0; +// case Instructions::ADC_DPXi: this->ADC(this->_getDirectIndirectIndexedXAddr()); return 6 + !this->_registers.p.m + this->_registers.dl != 0; +// case Instructions::ADC_DPYi: this->ADC(this->_getDirectIndirectIndexedYAddr()); return 5 + !this->_registers.p.m + this->_registers.dl != 0 + this->_hasIndexCrossedPageBoundary; +// case Instructions::ADC_DPYil:this->ADC(this->_getDirectIndirectIndexedYLongAddr()); return 6 + !this->_registers.p.m + this->_registers.dl != 0; +// case Instructions::ADC_SR: this->ADC(this->_getStackRelativeAddr()); return 4 + !this->_registers.p.m; +// case Instructions::ADC_SRYi: this->ADC(this->_getStackRelativeIndirectIndexedYAddr()); return 7 + !this->_registers.p.m; +// +// case Instructions::STA_ABS: this->STA(this->_getAbsoluteAddr()); return 4 + !this->_registers.p.m; +// case Instructions::STA_ABSl: this->STA(this->_getAbsoluteLongAddr()); return 5 + !this->_registers.p.m; +// case Instructions::STA_DP: this->STA(this->_getDirectAddr()); return 3 + !this->_registers.p.m + this->_registers.dl != 0; +// case Instructions::STA_DPi: this->STA(this->_getDirectIndirectAddr()); return 5 + !this->_registers.p.m + this->_registers.dl != 0; +// case Instructions::STA_DPil: this->STA(this->_getDirectIndirectLongAddr()); return 6 + !this->_registers.p.m + this->_registers.dl != 0; +// case Instructions::STA_ABSX: this->STA(this->_getAbsoluteIndexedByXAddr()); return 5 + !this->_registers.p.m; +// case Instructions::STA_ABSXl:this->STA(this->_getAbsoluteIndexedByXLongAddr()); return 5 + !this->_registers.p.m; +// case Instructions::STA_ABSY: this->STA(this->_getAbsoluteIndexedByYAddr()); return 5 + !this->_registers.p.m; +// case Instructions::STA_DPX: this->STA(this->_getDirectIndexedByXAddr()); return 4 + !this->_registers.p.m + this->_registers.dl != 0; +// case Instructions::STA_DPXi: this->STA(this->_getDirectIndirectIndexedXAddr()); return 6 + !this->_registers.p.m + this->_registers.dl != 0; +// case Instructions::STA_DPYi: this->STA(this->_getDirectIndirectIndexedYAddr()); return 6 + !this->_registers.p.m + this->_registers.dl != 0; +// case Instructions::STA_DPYil:this->STA(this->_getDirectIndirectIndexedYLongAddr()); return 6 + !this->_registers.p.m + this->_registers.dl != 0; +// case Instructions::STA_SR: this->STA(this->_getStackRelativeAddr()); return 4 + !this->_registers.p.m; +// case Instructions::STA_SRYi: this->STA(this->_getStackRelativeIndirectIndexedYAddr()); return 7 + !this->_registers.p.m; +// +// case Instructions::STX_ABS: this->STX(this->_getAbsoluteAddr()); return 4 + !this->_registers.p.m; +// case Instructions::STX_DP: this->STX(this->_getDirectAddr()); return 3 + !this->_registers.p.m + this->_registers.dl != 0; +// case Instructions::STX_DPY: this->STX(this->_getDirectIndexedByYAddr()); return 4 + !this->_registers.p.m + this->_registers.dl != 0; +// +// case Instructions::STY_ABS: this->STX(this->_getAbsoluteAddr()); return 4 + !this->_registers.p.m; +// case Instructions::STY_DP: this->STX(this->_getDirectAddr()); return 3 + !this->_registers.p.m + this->_registers.dl != 0; +// case Instructions::STY_DPX: this->STX(this->_getDirectIndexedByXAddr()); return 4 + !this->_registers.p.m + this->_registers.dl != 0; +// +// case Instructions::STZ_ABS: this->STX(this->_getAbsoluteAddr()); return 4 + !this->_registers.p.m; +// case Instructions::STZ_DP: this->STX(this->_getDirectAddr()); return 3 + !this->_registers.p.m + this->_registers.dl != 0; +// case Instructions::STZ_ABSX: this->STX(this->_getAbsoluteIndexedByXAddr()); return 3 + !this->_registers.p.m + this->_registers.dl != 0; +// case Instructions::STZ_DPX: this->STX(this->_getDirectIndexedByXAddr()); return 4 + !this->_registers.p.m + this->_registers.dl != 0; +// +// case Instructions::LDA_IM: this->LDA(this->_getImmediateAddrForA()); return 2 + !this->_registers.p.m; +// case Instructions::LDA_ABS: this->LDA(this->_getAbsoluteAddr()); return 4 + !this->_registers.p.m; +// case Instructions::LDA_ABSl: this->LDA(this->_getAbsoluteLongAddr()); return 5 + !this->_registers.p.m; +// case Instructions::LDA_DP: this->LDA(this->_getDirectAddr()); return 3 + !this->_registers.p.m + this->_registers.dl != 0; +// case Instructions::LDA_DPi: this->LDA(this->_getDirectIndirectAddr()); return 5 + !this->_registers.p.m + this->_registers.dl != 0; +// case Instructions::LDA_DPil: this->LDA(this->_getDirectIndirectLongAddr()); return 6 + !this->_registers.p.m + this->_registers.dl != 0; +// case Instructions::LDA_ABSX: this->LDA(this->_getAbsoluteIndexedByXAddr()); return 4 + !this->_registers.p.m + this->_hasIndexCrossedPageBoundary; +// case Instructions::LDA_ABSXl:this->LDA(this->_getAbsoluteIndexedByXLongAddr()); return 5 + !this->_registers.p.m; +// case Instructions::LDA_ABSY: this->LDA(this->_getAbsoluteIndexedByYAddr()); return 4 + !this->_registers.p.m + this->_hasIndexCrossedPageBoundary; +// case Instructions::LDA_DPX: this->LDA(this->_getDirectIndexedByXAddr()); return 4 + !this->_registers.p.m + this->_registers.dl != 0; +// case Instructions::LDA_DPXi: this->LDA(this->_getDirectIndirectIndexedXAddr()); return 6 + !this->_registers.p.m + this->_registers.dl != 0; +// case Instructions::LDA_DPYi: this->LDA(this->_getDirectIndirectIndexedYAddr()); return 5 + !this->_registers.p.m + this->_registers.dl != 0 + this->_hasIndexCrossedPageBoundary; +// case Instructions::LDA_DPYil:this->LDA(this->_getDirectIndirectIndexedYLongAddr()); return 6 + !this->_registers.p.m + this->_registers.dl != 0; +// case Instructions::LDA_SR: this->LDA(this->_getStackRelativeAddr()); return 4 + !this->_registers.p.m; +// case Instructions::LDA_SRYi: this->LDA(this->_getStackRelativeIndirectIndexedYAddr()); return 7 + !this->_registers.p.m; +// +// case Instructions::LDX_IM: this->LDX(this->_getImmediateAddrForX()); return 2 + !this->_registers.p.m; +// case Instructions::LDX_ABS: this->LDX(this->_getAbsoluteAddr()); return 4 + !this->_registers.p.m; +// case Instructions::LDX_DP: this->LDX(this->_getDirectAddr()); return 3 + !this->_registers.p.m + this->_registers.dl != 0; +// case Instructions::LDX_ABSY: this->LDX(this->_getAbsoluteIndexedByYAddr()); return 4 + !this->_registers.p.m + this->_hasIndexCrossedPageBoundary; +// case Instructions::LDX_DPY: this->LDX(this->_getDirectIndexedByYAddr()); return 4 + !this->_registers.p.m + this->_registers.dl != 0; +// +// case Instructions::LDY_IM: this->LDY(this->_getImmediateAddrForX()); return 2 + !this->_registers.p.m; +// case Instructions::LDY_ABS: this->LDY(this->_getAbsoluteAddr()); return 4 + !this->_registers.p.m; +// case Instructions::LDY_DP: this->LDY(this->_getDirectAddr()); return 3 + !this->_registers.p.m + this->_registers.dl != 0; +// case Instructions::LDY_ABSY: this->LDY(this->_getAbsoluteIndexedByYAddr()); return 4 + !this->_registers.p.m + this->_hasIndexCrossedPageBoundary; +// case Instructions::LDY_DPY: this->LDY(this->_getDirectIndexedByYAddr()); return 4 + !this->_registers.p.m + this->_registers.dl != 0; +// +// case Instructions::SEP: this->SEP(this->_bus->read(this->_registers.pc++)); return 3; +// +// case Instructions::REP: this->REP(this->_bus->read(this->_registers.pc++)); return 3; +// +// case Instructions::PHA: this->PHA(); return 3 + !this->_registers.p.m; +// case Instructions::PHB: this->PHB(); return 3; +// case Instructions::PHD: this->PHD(); return 4; +// case Instructions::PHK: this->PHK(); return 3; +// case Instructions::PHP: this->PHP(); return 3; +// case Instructions::PHX: this->PHX(); return 3 + !this->_registers.p.x_b; +// case Instructions::PHY: this->PHY(); return 3 + !this->_registers.p.x_b; +// +// case Instructions::PLA: this->PLA(); return 4 + !this->_registers.p.m; +// case Instructions::PLB: this->PLB(); return 4; +// case Instructions::PLD: this->PLD(); return 5; +// case Instructions::PLP: this->PLP(); return 4; +// case Instructions::PLX: this->PLX(); return 4 + !this->_registers.p.x_b; +// case Instructions::PLY: this->PLY(); return 4 + !this->_registers.p.x_b; +// +// case Instructions::JSR_ABS: this->JSR(this->_getAbsoluteAddr()); return 6; +// case Instructions::JSR_ABSXi: this->JSR(this->_getAbsoluteIndirectIndexedByXAddr()); return 8; +// +// case Instructions::JSL: this->JSL(this->_getAbsoluteLongAddr()); return 8; +// +// case Instructions::CLC: this->CLC(); return 2; +// case Instructions::CLI: this->CLI(); return 2; +// case Instructions::CLD: this->CLD(); return 2; +// case Instructions::CLV: this->CLV(); return 2; +// +// case Instructions::SEC: this->SEC(); return 2; +// case Instructions::SED: this->SED(); return 2; +// case Instructions::SEI: this->SEI(); return 2; +// +// case Instructions::AND_IM: this->AND(this->_getImmediateAddrForA()); return 2 + !this->_registers.p.m; +// case Instructions::AND_ABS: this->AND(this->_getAbsoluteAddr()); return 4 + !this->_registers.p.m; +// case Instructions::AND_ABSl: this->AND(this->_getAbsoluteLongAddr()); return 5 + !this->_registers.p.m; +// case Instructions::AND_DP: this->AND(this->_getDirectAddr()); return 3 + !this->_registers.p.m + this->_registers.dl != 0; +// case Instructions::AND_DPi: this->AND(this->_getDirectIndirectAddr()); return 5 + !this->_registers.p.m + this->_registers.dl != 0; +// case Instructions::AND_DPil: this->AND(this->_getDirectIndirectLongAddr()); return 6 + !this->_registers.p.m + this->_registers.dl != 0; +// case Instructions::AND_ABSX: this->AND(this->_getAbsoluteIndexedByXAddr()); return 4 + !this->_registers.p.m + this->_hasIndexCrossedPageBoundary; +// case Instructions::AND_ABSXl:this->AND(this->_getAbsoluteIndexedByXLongAddr()); return 5 + !this->_registers.p.m; +// case Instructions::AND_ABSY: this->AND(this->_getAbsoluteIndexedByYAddr()); return 4 + !this->_registers.p.m + this->_hasIndexCrossedPageBoundary; +// case Instructions::AND_DPX: this->AND(this->_getDirectIndexedByXAddr()); return 4 + !this->_registers.p.m + this->_registers.dl != 0; +// case Instructions::AND_DPXi: this->AND(this->_getDirectIndirectIndexedXAddr()); return 6 + !this->_registers.p.m + this->_registers.dl != 0; +// case Instructions::AND_DPYi: this->AND(this->_getDirectIndirectIndexedYAddr()); return 5 + !this->_registers.p.m + this->_registers.dl != 0 + this->_hasIndexCrossedPageBoundary; +// case Instructions::AND_DPYil:this->AND(this->_getDirectIndirectIndexedYLongAddr()); return 6 + !this->_registers.p.m + this->_registers.dl != 0; +// case Instructions::AND_SR: this->AND(this->_getStackRelativeAddr()); return 4 + !this->_registers.p.m; +// case Instructions::AND_SRYi: this->AND(this->_getStackRelativeIndirectIndexedYAddr()); return 7 + !this->_registers.p.m; +// +// case Instructions::XCE: this->XCE(); return 2; +// +// case Instructions::SBC_IM: this->SBC(this->_getImmediateAddrForA()); return 2 + !this->_registers.p.m; +// case Instructions::SBC_ABS: this->SBC(this->_getAbsoluteAddr()); return 4 + !this->_registers.p.m; +// case Instructions::SBC_ABSl: this->SBC(this->_getAbsoluteLongAddr()); return 5 + !this->_registers.p.m; +// case Instructions::SBC_DP: this->SBC(this->_getDirectAddr()); return 3 + !this->_registers.p.m + this->_registers.dl != 0; +// case Instructions::SBC_DPi: this->SBC(this->_getDirectIndirectAddr()); return 5 + !this->_registers.p.m + this->_registers.dl != 0; +// case Instructions::SBC_DPil: this->SBC(this->_getDirectIndirectLongAddr()); return 6 + !this->_registers.p.m + this->_registers.dl != 0; +// case Instructions::SBC_ABSX: this->SBC(this->_getAbsoluteIndexedByXAddr()); return 4 + !this->_registers.p.m + this->_hasIndexCrossedPageBoundary; +// case Instructions::SBC_ABSXl:this->SBC(this->_getAbsoluteIndexedByXLongAddr()); return 5 + !this->_registers.p.m; +// case Instructions::SBC_ABSY: this->SBC(this->_getAbsoluteIndexedByYAddr()); return 4 + !this->_registers.p.m + this->_hasIndexCrossedPageBoundary; +// case Instructions::SBC_DPX: this->SBC(this->_getDirectIndexedByXAddr()); return 4 + !this->_registers.p.m + this->_registers.dl != 0; +// case Instructions::SBC_DPXi: this->SBC(this->_getDirectIndirectIndexedXAddr()); return 6 + !this->_registers.p.m + this->_registers.dl != 0; +// case Instructions::SBC_DPYi: this->SBC(this->_getDirectIndirectIndexedYAddr()); return 5 + !this->_registers.p.m + this->_registers.dl != 0 + this->_hasIndexCrossedPageBoundary; +// case Instructions::SBC_DPYil:this->SBC(this->_getDirectIndirectIndexedYLongAddr()); return 6 + !this->_registers.p.m + this->_registers.dl != 0; +// case Instructions::SBC_SR: this->SBC(this->_getStackRelativeAddr()); return 4 + !this->_registers.p.m; +// case Instructions::SBC_SRYi: this->SBC(this->_getStackRelativeIndirectIndexedYAddr()); return 7 + !this->_registers.p.m; +// +// case Instructions::TAX: this->TAX(); return 2; +// case Instructions::TAY: this->TAY(); return 2; +// case Instructions::TXS: this->TXS(); return 2; +// +// case Instructions::INX: this->INX(); return 2; +// case Instructions::INY: this->INY(); return 2; +// +// case Instructions::CPX_IM: this->CPX(this->_getImmediateAddrForX()); return 2 + !this->_registers.p.m; +// case Instructions::CPX_ABS: this->CPX(this->_getAbsoluteAddr()); return 4 + !this->_registers.p.m; +// case Instructions::CPX_DP: this->CPX(this->_getDirectAddr()); return 3 + !this->_registers.p.m + this->_registers.dl != 0; +// +// case Instructions::CPY_IM: this->CPY(this->_getImmediateAddrForX()); return 2 + !this->_registers.p.m; +// case Instructions::CPY_ABS: this->CPY(this->_getAbsoluteAddr()); return 4 + !this->_registers.p.m; +// case Instructions::CPY_DP: this->CPY(this->_getDirectAddr()); return 3 + !this->_registers.p.m + this->_registers.dl != 0; +// +// case Instructions::BCC: return this->BCC(this->_registers.pc++) + 2 + this->_isEmulationMode; +// case Instructions::BCS: return this->BCS(this->_registers.pc++) + 2 + this->_isEmulationMode; +// case Instructions::BEQ: return this->BEQ(this->_registers.pc++) + 2 + this->_isEmulationMode; +// case Instructions::BNE: return this->BNE(this->_registers.pc++) + 2 + this->_isEmulationMode; +// case Instructions::BMI: return this->BMI(this->_registers.pc++) + 2 + this->_isEmulationMode; +// case Instructions::BPL: return this->BPL(this->_registers.pc++) + 2 + this->_isEmulationMode; +// case Instructions::BVC: return this->BVC(this->_registers.pc++) + 2 + this->_isEmulationMode; +// case Instructions::BVS: return this->BVS(this->_registers.pc++) + 2 + this->_isEmulationMode; +// case Instructions::BRA: this->BRA(this->_registers.pc++); return 3 + this->_isEmulationMode; +// case Instructions::BRL: this->BRL(this->_registers.pc); this->_registers.pc += 2; return 4; +// +// case Instructions::JMP_ABS: addr = this->_getAbsoluteAddr(); this->JMP(addr); return 3; +// case Instructions::JMP_ABSi: addr = this->_getAbsoluteIndirectAddr(); this->JMP(addr); return 3; +// case Instructions::JMP_ABSXi: addr = this->_getAbsoluteIndexedByXAddr(); this->JMP(addr); return 3; +// +// case Instructions::JML_ABSl: addr = this->_getAbsoluteLongAddr(); this->JML(addr); return 3; +// //case Instructions::JML_ABSil: this->JML(this->_getAbsoluteLong()); return 3; +// +// default: +// throw InvalidOpcode("CPU", opcode); +// } } void CPU::_push(uint8_t data) diff --git a/sources/CPU/CPU.hpp b/sources/CPU/CPU.hpp index 84d613f..a14f2c0 100644 --- a/sources/CPU/CPU.hpp +++ b/sources/CPU/CPU.hpp @@ -10,6 +10,7 @@ #include "../Models/Int24.hpp" #include "../Cartridge/Cartridge.hpp" #include "../Memory/AMemory.hpp" +#include "Instruction.hpp" namespace ComSquare::CPU { @@ -180,189 +181,6 @@ namespace ComSquare::CPU uint8_t joy4h; }; - //! @brief All the instructions opcode of the main CPU. - //! @info The name of the instruction followed by their parameters (after an underscore) if any. - //! @info Addr mode with an i at the end means indirect. - //! @info Addr mode with an l at the end means long. - enum Instructions - { - BRK = 0x00, - COP = 0x02, - RTI = 0x40, - - ADC_DPXi = 0x61, - ADC_SR = 0x63, - ADC_DP = 0x65, - ADC_DPil = 0x67, - ADC_IM = 0x69, - ADC_ABS = 0x6D, - ADC_ABSl = 0x6F, - ADC_DPYi = 0x71, - ADC_DPi = 0x72, - ADC_SRYi = 0x73, - ADC_DPX = 0x75, - ADC_DPYil = 0x77, - ADC_ABSY = 0x79, - ADC_ABSX = 0x7D, - ADC_ABSXl = 0x7F, - - STA_ABS = 0x8D, - STA_ABSl = 0x8F, - STA_DP = 0x85, - STA_DPi = 0x92, - STA_DPil = 0x87, - STA_ABSX = 0x9D, - STA_ABSXl = 0x9F, - STA_ABSY = 0x99, - STA_DPX = 0x95, - STA_DPXi = 0x81, - STA_DPYi = 0x91, - STA_DPYil = 0x97, - STA_SR = 0x83, - STA_SRYi = 0x93, - - STX_ABS = 0x8E, - STX_DP = 0x86, - STX_DPY = 0x96, - - STY_ABS = 0x8C, - STY_DP = 0x84, - STY_DPX = 0x94, - - STZ_ABS = 0x9C, - STZ_DP = 0x64, - STZ_ABSX = 0x9E, - STZ_DPX = 0x74, - - LDA_IM = 0xA9, - LDA_ABS = 0xAD, - LDA_ABSl = 0xAF, - LDA_DP = 0xA5, - LDA_DPi = 0xB2, - LDA_DPil = 0xA7, - LDA_ABSX = 0xBD, - LDA_ABSXl = 0xBF, - LDA_ABSY = 0xB9, - LDA_DPX = 0xB5, - LDA_DPXi = 0xA1, - LDA_DPYi = 0xB1, - LDA_DPYil = 0xB7, - LDA_SR = 0xA3, - LDA_SRYi = 0xB3, - - LDX_IM = 0xA2, - LDX_ABS = 0xAE, - LDX_DP = 0xA6, - LDX_ABSY = 0xBE, - LDX_DPY = 0xB6, - - LDY_IM = 0xA0, - LDY_ABS = 0xAC, - LDY_DP = 0xA4, - LDY_ABSY = 0xBC, - LDY_DPY = 0xB4, - - SEP = 0xE2, - - REP = 0xC2, - - PHA = 0x48, - PHB = 0x8B, - PHD = 0x0B, - PHK = 0x4B, - PHP = 0x08, - PHX = 0xDA, - PHY = 0x5A, - - PLA = 0x68, - PLB = 0xAB, - PLD = 0x2B, - PLP = 0x28, - PLX = 0xFA, - PLY = 0x7A, - - JSR_ABS = 0x20, - JSR_ABSXi = 0xFC, - - JSL = 0x22, - - CLC = 0x18, - CLI = 0x58, - CLD = 0xD8, - CLV = 0xB8, - - SEC = 0x38, - SEI = 0x78, - SED = 0xF8, - - AND_IM = 0x29, - AND_ABS = 0x2D, - AND_ABSl = 0x2F, - AND_DP = 0x25, - AND_DPi = 0x32, - AND_DPil = 0x27, - AND_ABSX = 0x3D, - AND_ABSXl = 0x3F, - AND_ABSY = 0x39, - AND_DPX = 0x35, - AND_DPXi = 0x21, - AND_DPYi = 0x31, - AND_DPYil = 0x37, - AND_SR = 0x23, - AND_SRYi = 0x33, - - XCE = 0xFB, - - SBC_IM = 0xE9, - SBC_ABS = 0xED, - SBC_ABSl = 0xEF, - SBC_DP = 0xE5, - SBC_DPi = 0xF2, - SBC_DPil = 0xE7, - SBC_ABSX = 0xFD, - SBC_ABSXl = 0xFF, - SBC_ABSY = 0xF9, - SBC_DPX = 0xF5, - SBC_DPXi = 0xE1, - SBC_DPYi = 0xF1, - SBC_DPYil = 0xF7, - SBC_SR = 0xE3, - SBC_SRYi = 0xF3, - - TAX = 0xAA, - TAY = 0xA8, - TXS = 0x9A, - - INX = 0xE8, - INY = 0xC8, - - CPX_IM = 0xE0, - CPX_ABS = 0xEC, - CPX_DP = 0xE4, - - CPY_IM = 0xC0, - CPY_ABS = 0xCC, - CPY_DP = 0xC4, - - BCC = 0x90, - BCS = 0xB0, - BEQ = 0xF0, - BNE = 0xD0, - BMI = 0x30, - BPL = 0x10, - BVC = 0x50, - BVS = 0x70, - BRA = 0x80, - BRL = 0x82, - - JMP_ABS = 0x4C, - JMP_ABSi = 0x6C, - JMP_ABSXi = 0x7C, - - JML_ABSl = 0x5C, - JML_ABSil = 0xDC - }; - //! @brief The main CPU class CPU : public Memory::AMemory { protected: @@ -380,6 +198,8 @@ namespace ComSquare::CPU //! @brief True if an addressing mode with an iterator (x, y) has crossed the page. (Used because crossing the page boundary take one more cycle to run certain instructions). bool _hasIndexCrossedPageBoundary = false; + //! @brief Immediate address mode is specified with a value in 8. (This functions returns the 24bit space address of the value). + uint24_t _getImmediateAddr8Bits(); //! @brief Immediate address mode is specified with a value in 8 or 16 bits. The value is 16 bits if the m flag is unset. (This functions returns the 24bit space address of the value). uint24_t _getImmediateAddrForA(); //! @brief Immediate address mode is specified with a value in 8 or 16 bits. The value is 16 bits if the x flag is unset. (This functions returns the 24bit space address of the value). @@ -439,119 +259,382 @@ namespace ComSquare::CPU virtual unsigned _executeInstruction(uint8_t opcode); //! @brief Break instruction - Causes a software break. The PC is loaded from a vector table. - void BRK(); + int BRK(uint24_t); //! @brief Co-Processor Enable instruction - Causes a software break. The PC is loaded from a vector table. - void COP(); + int COP(uint24_t); //! @brief Return from Interrupt - Used to return from a interrupt handler. - void RTI(); + int RTI(uint24_t); //! @brief Add with carry - Adds operand to the Accumulator; adds an additional 1 if carry is set. - void ADC(uint24_t valueAddr); + int ADC(uint24_t valueAddr); //! @brief Store the accumulator to memory. - void STA(uint24_t addr); + int STA(uint24_t addr); //! @brief Store the index register X to memory. - void STX(uint24_t addr); + int STX(uint24_t addr); //! @brief Store the index register Y to memory. - void STY(uint24_t addr); + int STY(uint24_t addr); //! @brief Store zero to the memory. - void STZ(uint24_t addr); + int STZ(uint24_t addr); //! @brief Load the accumulator from memory. - void LDA(uint24_t addr); + int LDA(uint24_t addr); //! @brief Load the X index register from memory. - void LDX(uint24_t addr); + int LDX(uint24_t addr); //! @brief Load the Y index register from memory. - void LDY(uint24_t addr); + int LDY(uint24_t addr); //! @brief Set status bits. - void SEP(uint24_t valueAddr); + int SEP(uint24_t valueAddr); //! @brief Reset status bits. - void REP(uint24_t valueAddr); + int REP(uint24_t valueAddr); //! @brief Jump to subroutine - void JSR(uint24_t addr); + int JSR(uint24_t addr); //! @brief Jump to subroutine (long) - void JSL(uint24_t addr); + int JSL(uint24_t addr); //! @brief Push the accumulator to the stack. - void PHA(); + int PHA(uint24_t); //! @brief Push the data bank register to the stack. - void PHB(); + int PHB(uint24_t); //! @brief Push the direct page register to the stack. - void PHD(); + int PHD(uint24_t); //! @brief Push the program bank register to the stack. - void PHK(); + int PHK(uint24_t); //! @brief Push the processor status register to the stack. - void PHP(); + int PHP(uint24_t); //! @brief Push the x index register to the stack. - void PHX(); + int PHX(uint24_t); //! @brief Push the y index register to the stack. - void PHY(); + int PHY(uint24_t); //! @brief Pull the accumulator to the stack. - void PLA(); + int PLA(uint24_t); //! @brief Pull the data bank register to the stack. - void PLB(); + int PLB(uint24_t); //! @brief Pull the direct page register to the stack. - void PLD(); + int PLD(uint24_t); //! @brief Pull the processor status register to the stack. - void PLP(); + int PLP(uint24_t); //! @brief Pull the x index register to the stack. - void PLX(); + int PLX(uint24_t); //! @brief Pull the y index register to the stack. - void PLY(); + int PLY(uint24_t); //! @brief Clear the carry flag. - void CLC(); + int CLC(uint24_t); //! @brief Clear the Interrupt Disable flag. - void CLI(); + int CLI(uint24_t); //! @brief Clear the decimal flag. - void CLD(); + int CLD(uint24_t); //! @brief Clear the overflow flag. - void CLV(); + int CLV(uint24_t); //! @brief Set the carry Flag. - void SEC(); + int SEC(uint24_t); //! @brief Set the decimal flag. - void SED(); + int SED(uint24_t); //! @brief Set the Interrupt Disable flag. - void SEI(); + int SEI(uint24_t); //! @brief Exchange Carry and Emulation Flags - void XCE(); + int XCE(uint24_t); //! @brief And accumulator with memory. - void AND(uint24_t valueAddr); + int AND(uint24_t valueAddr); //! @brief Subtract with Borrow from Accumulator. - void SBC(uint24_t valueAddr); + int SBC(uint24_t valueAddr); //! @brief Transfer A to X - void TAX(); + int TAX(uint24_t); //! @brief Transfer A to Y - void TAY(); + int TAY(uint24_t); //! @brief Transfer X to SP - void TXS(); + int TXS(uint24_t); //! @brief Increment the X register - void INX(); + int INX(uint24_t); //! @brief Increment the Y register - void INY(); + int INY(uint24_t); //! @brief Compare the X register with the memory - void CPX(uint24_t valueAddr); + int CPX(uint24_t valueAddr); //! @brief Compare the Y register with the memory - void CPY(uint24_t valueAddr); + int CPY(uint24_t valueAddr); //! @brief Branch if carry clear - bool BCC(uint24_t valueAddr); + int BCC(uint24_t valueAddr); //! @brief Branch if carry set - bool BCS(uint24_t valueAddr); + int BCS(uint24_t valueAddr); //! @brief Branch if equal - bool BEQ(uint24_t valueAddr); + int BEQ(uint24_t valueAddr); //! @brief Branch if not equal - bool BNE(uint24_t valueAddr); + int BNE(uint24_t valueAddr); //! @brief Branch if minus - bool BMI(uint24_t valueAddr); + int BMI(uint24_t valueAddr); //! @brief Branch if plus - bool BPL(uint24_t valueAddr); + int BPL(uint24_t valueAddr); //! @brief Branch if Overflow Clear - bool BVC(uint24_t valueAddr); + int BVC(uint24_t valueAddr); //! @brief Branch if Overflow Set - bool BVS(uint24_t valueAddr); + int BVS(uint24_t valueAddr); //! @brief Branch always - bool BRA(uint24_t valueAddr); + int BRA(uint24_t valueAddr); //! @brief Branch always long - bool BRL(uint24_t valueAddr); + int BRL(uint24_t valueAddr); //! @brief Jump. - void JMP(uint24_t valueAddr); + int JMP(uint24_t valueAddr); //! @brief Long jump. - void JML(uint24_t valueAddr); + int JML(uint24_t valueAddr); + //! @brief No OP. + int NOP(uint24_t); + + //! @brief All the instructions of the CPU. + //! @info Instructions are indexed by their opcode + Instruction _instructions[0x100] = { + {&CPU::BRK, 7, "brk", AddressingMode::Implied, 2}, // 00 + {&CPU::BRK, 7, "ora #-#", AddressingMode::Implied, 2}, // 01 + {&CPU::COP, 7, "cop", AddressingMode::Implied, 2}, // 02 + {&CPU::BRK, 7, "ora #-#", AddressingMode::Implied, 2}, // 03 + {&CPU::BRK, 7, "tsb #-#", AddressingMode::Implied, 2}, // 04 + {&CPU::BRK, 7, "ora #-#", AddressingMode::Implied, 2}, // 05 + {&CPU::BRK, 7, "asl #-#", AddressingMode::Implied, 2}, // 06 + {&CPU::BRK, 7, "ora #-#", AddressingMode::Implied, 2}, // 07 + {&CPU::PHP, 3, "php", AddressingMode::Implied, 3}, // 08 + {&CPU::BRK, 7, "ora #-#", AddressingMode::Implied, 2}, // 09 + {&CPU::BRK, 7, "asl #-#", AddressingMode::Implied, 2}, // 0A + {&CPU::PHD, 4, "phd", AddressingMode::Implied, 1}, // 0B + {&CPU::BRK, 7, "tsb #-#", AddressingMode::Implied, 2}, // 0C + {&CPU::BRK, 7, "ora #-#", AddressingMode::Implied, 2}, // 0D + {&CPU::BRK, 7, "asl #-#", AddressingMode::Implied, 2}, // 0E + {&CPU::BRK, 7, "ora #-#", AddressingMode::Implied, 2}, // 0F + {&CPU::BPL, 7, "bpl", AddressingMode::Implied, 2}, // 10 + {&CPU::BRK, 7, "ora #-#", AddressingMode::Implied, 2}, // 11 + {&CPU::BRK, 7, "ora #-#", AddressingMode::Implied, 2}, // 12 + {&CPU::BRK, 7, "ora #-#", AddressingMode::Implied, 2}, // 13 + {&CPU::BRK, 7, "trb #-#", AddressingMode::Implied, 2}, // 14 + {&CPU::BRK, 7, "ora #-#", AddressingMode::Implied, 2}, // 15 + {&CPU::BRK, 7, "asl #-#", AddressingMode::Implied, 2}, // 16 + {&CPU::BRK, 7, "ora #-#", AddressingMode::Implied, 2}, // 17 + {&CPU::CLC, 2, "clc", AddressingMode::Implied, 1}, // 18 + {&CPU::BRK, 7, "ora #-#", AddressingMode::Implied, 2}, // 19 + {&CPU::BRK, 7, "inc #-#", AddressingMode::Implied, 2}, // 1A + {&CPU::BRK, 7, "tcs #-#", AddressingMode::Implied, 2}, // 1B + {&CPU::BRK, 7, "trb #-#", AddressingMode::Implied, 2}, // 1C + {&CPU::BRK, 7, "ora #-#", AddressingMode::Implied, 2}, // 1D + {&CPU::BRK, 7, "asl #-#", AddressingMode::Implied, 2}, // 1E + {&CPU::BRK, 7, "ora #-#", AddressingMode::Implied, 2}, // 1F + {&CPU::JSR, 6, "jsr", AddressingMode::Absolute, 3}, // 20 + {&CPU::BRK, 7, "and #-#", AddressingMode::Implied, 2}, // 21 + {&CPU::JSL, 8, "jsl", AddressingMode::AbsoluteLong, 4}, // 22 + {&CPU::BRK, 7, "and #-#", AddressingMode::Implied, 2}, // 23 + {&CPU::BRK, 7, "bit #-#", AddressingMode::Implied, 2}, // 24 + {&CPU::BRK, 7, "and #-#", AddressingMode::Implied, 2}, // 25 + {&CPU::BRK, 7, "rol #-#", AddressingMode::Implied, 2}, // 26 + {&CPU::BRK, 7, "and #-#", AddressingMode::Implied, 2}, // 27 + {&CPU::PLP, 4, "plp", AddressingMode::Implied, 1}, // 28 + {&CPU::BRK, 7, "and #-#", AddressingMode::Implied, 2}, // 29 + {&CPU::BRK, 7, "rol #-#", AddressingMode::Implied, 2}, // 2A + {&CPU::PLD, 5, "pld", AddressingMode::Implied, 1}, // 2B + {&CPU::BRK, 7, "bit #-#", AddressingMode::Implied, 2}, // 2C + {&CPU::BRK, 7, "and #-#", AddressingMode::Implied, 2}, // 2D + {&CPU::BRK, 7, "rol #-#", AddressingMode::Implied, 2}, // 2E + {&CPU::BRK, 7, "and #-#", AddressingMode::Implied, 2}, // 2F + {&CPU::BMI, 2, "bmi", AddressingMode::Implied, 2}, // 30 + {&CPU::BRK, 7, "and #-#", AddressingMode::Implied, 2}, // 31 + {&CPU::BRK, 7, "and #-#", AddressingMode::Implied, 2}, // 32 + {&CPU::BRK, 7, "and #-#", AddressingMode::Implied, 2}, // 33 + {&CPU::BRK, 7, "bit #-#", AddressingMode::Implied, 2}, // 34 + {&CPU::BRK, 7, "and #-#", AddressingMode::Implied, 2}, // 35 + {&CPU::BRK, 7, "rol #-#", AddressingMode::Implied, 2}, // 36 + {&CPU::BRK, 7, "and #-#", AddressingMode::Implied, 2}, // 37 + {&CPU::SEC, 2, "sec", AddressingMode::Implied, 1}, // 38 + {&CPU::BRK, 7, "and #-#", AddressingMode::Implied, 2}, // 39 + {&CPU::BRK, 7, "dec #-#", AddressingMode::Implied, 2}, // 3A + {&CPU::BRK, 7, "tsc #-#", AddressingMode::Implied, 2}, // 3B + {&CPU::BRK, 7, "bit #-#", AddressingMode::Implied, 2}, // 3C + {&CPU::BRK, 7, "and #-#", AddressingMode::Implied, 2}, // 3D + {&CPU::BRK, 7, "rol #-#", AddressingMode::Implied, 2}, // 3E + {&CPU::BRK, 7, "and #-#", AddressingMode::Implied, 2}, // 3F + {&CPU::RTI, 6, "rti", AddressingMode::Implied, 1}, // 40 + {&CPU::BRK, 7, "eor #-#", AddressingMode::Implied, 2}, // 41 + {&CPU::BRK, 7, "wdm #-#", AddressingMode::Implied, 2}, // 42 + {&CPU::BRK, 7, "eor #-#", AddressingMode::Implied, 2}, // 43 + {&CPU::BRK, 7, "mvp #-#", AddressingMode::Implied, 2}, // 44 + {&CPU::BRK, 7, "eor #-#", AddressingMode::Implied, 2}, // 45 + {&CPU::BRK, 7, "lsr #-#", AddressingMode::Implied, 2}, // 46 + {&CPU::BRK, 7, "eor #-#", AddressingMode::Implied, 2}, // 47 + {&CPU::PHA, 3, "pha", AddressingMode::Implied, 1}, // 48 + {&CPU::BRK, 7, "eor #-#", AddressingMode::Implied, 2}, // 49 + {&CPU::BRK, 7, "lsr #-#", AddressingMode::Implied, 2}, // 4A + {&CPU::PHK, 3, "phk", AddressingMode::Implied, 1}, // 4B + {&CPU::JMP, 3, "jmp", AddressingMode::Absolute, 3}, // 4C + {&CPU::BRK, 7, "eor #-#", AddressingMode::Implied, 2}, // 4D + {&CPU::BRK, 7, "lsr #-#", AddressingMode::Implied, 2}, // 4E + {&CPU::BRK, 7, "eor #-#", AddressingMode::Implied, 2}, // 4F + {&CPU::BVC, 2, "bvc", AddressingMode::Implied, 2}, // 50 + {&CPU::BRK, 7, "eor #-#", AddressingMode::Implied, 2}, // 51 + {&CPU::BRK, 7, "eor #-#", AddressingMode::Implied, 2}, // 52 + {&CPU::BRK, 7, "eor #-#", AddressingMode::Implied, 2}, // 53 + {&CPU::BRK, 7, "mvn #-#", AddressingMode::Implied, 2}, // 54 + {&CPU::BRK, 7, "eor #-#", AddressingMode::Implied, 2}, // 55 + {&CPU::BRK, 7, "lsr #-#", AddressingMode::Implied, 2}, // 56 + {&CPU::BRK, 7, "eor #-#", AddressingMode::Implied, 2}, // 57 + {&CPU::CLI, 2, "cli", AddressingMode::Implied, 1}, // 58 + {&CPU::BRK, 7, "eor #-#", AddressingMode::Implied, 2}, // 59 + {&CPU::PHY, 3, "phy", AddressingMode::Implied, 1}, // 5A + {&CPU::BRK, 7, "tcd #-#", AddressingMode::Implied, 2}, // 5B + {&CPU::JML, 4, "jml", AddressingMode::Implied, 4}, // 5C + {&CPU::BRK, 7, "eor #-#", AddressingMode::Implied, 2}, // 5D + {&CPU::BRK, 7, "lsr #-#", AddressingMode::Implied, 2}, // 5E + {&CPU::BRK, 7, "eor #-#", AddressingMode::Implied, 2}, // 5F + {&CPU::BRK, 7, "rtl #-#", AddressingMode::Implied, 2}, // 60 + {&CPU::ADC, 6, "adc", AddressingMode::DirectPageIndirectIndexedByX, 2}, // 61 + {&CPU::BRK, 7, "per #-#", AddressingMode::Implied, 2}, // 62 + {&CPU::ADC, 4, "adc", AddressingMode::StackRelative, 2}, // 63 + {&CPU::STZ, 3, "stz", AddressingMode::DirectPage, 2}, // 64 + {&CPU::ADC, 3, "adc", AddressingMode::DirectPage, 2}, // 65 + {&CPU::BRK, 7, "ror #-#", AddressingMode::Implied, 2}, // 66 + {&CPU::ADC, 6, "adc", AddressingMode::DirectPageIndirectLong, 2}, // 67 + {&CPU::PLA, 4, "pla", AddressingMode::Implied, 1}, // 68 + {&CPU::ADC, 2, "adc", AddressingMode::ImmediateForA, 2}, // 69 + {&CPU::BRK, 7, "ror #-#", AddressingMode::Implied, 2}, // 6A + {&CPU::BRK, 7, "rts #-#", AddressingMode::Implied, 2}, // 6B + {&CPU::JMP, 5, "jmp", AddressingMode::AbsoluteIndirect, 3}, // 6C + {&CPU::ADC, 4, "adc", AddressingMode::Absolute, 3}, // 6D + {&CPU::BRK, 7, "ror #-#", AddressingMode::Implied, 2}, // 6E + {&CPU::ADC, 5, "adc", AddressingMode::AbsoluteLong, 4}, // 6F + {&CPU::BVS, 2, "bvs", AddressingMode::Implied, 2}, // 70 + {&CPU::ADC, 5, "adc", AddressingMode::DirectPageIndirectIndexedByY, 2}, // 71 + {&CPU::ADC, 5, "adc", AddressingMode::DirectPageIndirect, 2}, // 72 + {&CPU::ADC, 7, "adc", AddressingMode::StackRelativeIndirectIndexedByY, 2}, // 73 + {&CPU::STZ, 4, "stz", AddressingMode::DirectPageIndexedByX, 2}, // 74 + {&CPU::ADC, 4, "adc", AddressingMode::DirectPageIndexedByX, 2}, // 75 + {&CPU::BRK, 7, "ror #-#", AddressingMode::Implied, 2}, // 76 + {&CPU::ADC, 6, "adc", AddressingMode::DirectPageIndirectIndexedByY, 2}, // 77 + {&CPU::SEI, 2, "sei", AddressingMode::Implied, 1}, // 78 + {&CPU::ADC, 4, "adc", AddressingMode::AbsoluteIndexedByY, 2}, // 79 + {&CPU::PLY, 4, "ply", AddressingMode::Implied, 1}, // 7A + {&CPU::BRK, 7, "tdc #-#", AddressingMode::Implied, 2}, // 7B + {&CPU::JMP, 6, "jmp", AddressingMode::AbsoluteIndirectIndexedByX, 3}, // 7C + {&CPU::ADC, 4, "adc", AddressingMode::AbsoluteIndexedByX, 3}, // 7D + {&CPU::BRK, 7, "ror #-#", AddressingMode::Implied, 2}, // 7E + {&CPU::ADC, 5, "adc", AddressingMode::AbsoluteIndexedByXLong, 4}, // 7F + {&CPU::BRA, 3, "bra", AddressingMode::Implied, 2}, // 80 + {&CPU::STA, 6, "sta", AddressingMode::DirectPageIndexedByX, 2}, // 81 + {&CPU::BRL, 4, "brl", AddressingMode::Implied, 3}, // 82 + {&CPU::STA, 4, "sta", AddressingMode::StackRelative, 2}, // 83 + {&CPU::STY, 3, "sty", AddressingMode::DirectPage, 2}, // 84 + {&CPU::STA, 3, "sta", AddressingMode::DirectPage, 2}, // 85 + {&CPU::STX, 3, "stx", AddressingMode::DirectPage, 2}, // 86 + {&CPU::STA, 6, "sta", AddressingMode::DirectPageIndirectLong, 2}, // 87 + {&CPU::BRK, 7, "dey #-#", AddressingMode::Implied, 2}, // 88 + {&CPU::BRK, 7, "bit #-#", AddressingMode::Implied, 2}, // 89 + {&CPU::BRK, 7, "txa #-#", AddressingMode::Implied, 2}, // 8A + {&CPU::PHB, 3, "phb", AddressingMode::Implied, 1}, // 8B + {&CPU::STY, 4, "sty", AddressingMode::Absolute, 3}, // 8C + {&CPU::STA, 4, "sta", AddressingMode::Absolute, 3}, // 8D + {&CPU::STX, 4, "stx", AddressingMode::Absolute, 3}, // 8E + {&CPU::STA, 5, "sta", AddressingMode::AbsoluteLong, 4}, // 8F + {&CPU::BCC, 2, "bcc", AddressingMode::Implied, 2}, // 90 + {&CPU::STA, 6, "sta", AddressingMode::DirectPageIndirectIndexedByY, 2}, // 91 + {&CPU::STA, 5, "sta", AddressingMode::DirectPageIndirect, 2}, // 92 + {&CPU::STA, 7, "sta", AddressingMode::StackRelativeIndirectIndexedByY, 2}, // 93 + {&CPU::STY, 4, "sty", AddressingMode::DirectPageIndirectIndexedByX, 2}, // 94 + {&CPU::STA, 4, "sta", AddressingMode::DirectPageIndexedByX, 2}, // 95 + {&CPU::STX, 4, "stx", AddressingMode::DirectPageIndexedByY, 2}, // 96 + {&CPU::STA, 6, "sta", AddressingMode::DirectPageIndirectIndexedByYLong, 2}, // 97 + {&CPU::BRK, 7, "tya #-#", AddressingMode::Implied, 2}, // 98 + {&CPU::STA, 5, "sta", AddressingMode::AbsoluteIndexedByY, 3}, // 99 + {&CPU::BRK, 7, "txs #-#", AddressingMode::Implied, 2}, // 9A + {&CPU::BRK, 7, "txy #-#", AddressingMode::Implied, 2}, // 9B + {&CPU::STZ, 4, "stz", AddressingMode::Absolute, 3}, // 9C + {&CPU::STA, 5, "sta", AddressingMode::AbsoluteIndexedByX, 3}, // 9D + {&CPU::STZ, 5, "stz", AddressingMode::AbsoluteIndexedByX, 3}, // 9E + {&CPU::STA, 5, "sta", AddressingMode::AbsoluteIndexedByXLong, 4}, // 9F + {&CPU::LDY, 2, "ldy", AddressingMode::ImmediateForX, 2}, // A0 + {&CPU::LDA, 6, "lda", AddressingMode::DirectPageIndirectIndexedByX, 2}, // A1 + {&CPU::LDX, 2, "ldx", AddressingMode::ImmediateForX, 2}, // A2 + {&CPU::LDA, 4, "lda", AddressingMode::StackRelative, 2}, // A3 + {&CPU::LDY, 3, "ldy", AddressingMode::DirectPage, 2}, // A4 + {&CPU::LDA, 3, "lda", AddressingMode::DirectPage, 2}, // A5 + {&CPU::LDX, 3, "ldx", AddressingMode::DirectPage, 2}, // A6 + {&CPU::LDA, 6, "lda", AddressingMode::DirectPageIndirectLong, 2}, // A7 + {&CPU::BRK, 7, "tay #-#", AddressingMode::Implied, 2}, // A8 + {&CPU::LDA, 2, "lda", AddressingMode::ImmediateForA, 2}, // A9 + {&CPU::BRK, 7, "tax #-#", AddressingMode::Implied, 2}, // AA + {&CPU::BRK, 7, "trb #-#", AddressingMode::Implied, 2}, // AB + {&CPU::LDY, 4, "ldy", AddressingMode::Absolute, 4}, // AC + {&CPU::LDA, 4, "lda", AddressingMode::Absolute, 3}, // AD + {&CPU::LDX, 4, "ldx", AddressingMode::Absolute, 3}, // AE + {&CPU::LDA, 5, "lda", AddressingMode::AbsoluteLong, 4}, // AF + {&CPU::BCS, 2, "bcs", AddressingMode::Implied, 2}, // B0 + {&CPU::LDA, 5, "lda", AddressingMode::DirectPageIndirectIndexedByY, 2}, // B1 + {&CPU::LDA, 5, "lda", AddressingMode::DirectPageIndirect, 2}, // B2 + {&CPU::LDA, 7, "lda", AddressingMode::StackRelativeIndirectIndexedByY, 2}, // B3 + {&CPU::LDY, 4, "ldy", AddressingMode::DirectPageIndexedByX, 2}, // B4 + {&CPU::LDA, 4, "lda", AddressingMode::DirectPageIndexedByX, 2}, // B5 + {&CPU::LDX, 4, "ldx", AddressingMode::DirectPageIndexedByY, 2}, // B6 + {&CPU::LDA, 6, "lda", AddressingMode::DirectPageIndirectIndexedByYLong, 2}, // B7 + {&CPU::CLV, 7, "clv", AddressingMode::Implied, 1}, // B8 + {&CPU::LDA, 4, "lda", AddressingMode::AbsoluteIndexedByY, 3}, // B9 + {&CPU::BRK, 7, "mvn #-#", AddressingMode::Implied, 2}, // BA + {&CPU::BRK, 7, "tyx #-#", AddressingMode::Implied, 2}, // BB + {&CPU::LDY, 4, "ldy", AddressingMode::AbsoluteIndexedByX, 3}, // BC + {&CPU::LDA, 4, "lda", AddressingMode::AbsoluteIndexedByX, 3}, // BD + {&CPU::LDX, 4, "ldx", AddressingMode::AbsoluteIndexedByY, 3}, // BE + {&CPU::LDA, 5, "lda", AddressingMode::AbsoluteIndexedByXLong, 4}, // BF + {&CPU::BRK, 7, "cpy #-#", AddressingMode::Implied, 2}, // C0 + {&CPU::BRK, 7, "cmp #-#", AddressingMode::Implied, 2}, // C1 + {&CPU::REP, 3, "rep", AddressingMode::Immediate8bits, 3}, // C2 + {&CPU::BRK, 7, "cmp #-#", AddressingMode::Implied, 2}, // C3 + {&CPU::BRK, 7, "cpy #-#", AddressingMode::Implied, 2}, // C4 + {&CPU::BRK, 7, "cmp #-#", AddressingMode::Implied, 2}, // C5 + {&CPU::BRK, 7, "dec #-#", AddressingMode::Implied, 2}, // C6 + {&CPU::BRK, 7, "cmp #-#", AddressingMode::Implied, 2}, // C7 + {&CPU::BRK, 7, "iny #-#", AddressingMode::Implied, 2}, // C8 + {&CPU::BRK, 7, "cmp #-#", AddressingMode::Implied, 2}, // C9 + {&CPU::BRK, 7, "dex #-#", AddressingMode::Implied, 2}, // CA + {&CPU::BRK, 7, "wai #-#", AddressingMode::Implied, 2}, // CB + {&CPU::BRK, 7, "cpy #-#", AddressingMode::Implied, 2}, // CC + {&CPU::BRK, 7, "cmp #-#", AddressingMode::Implied, 2}, // CD + {&CPU::BRK, 7, "dec #-#", AddressingMode::Implied, 2}, // CE + {&CPU::BRK, 7, "cmp #-#", AddressingMode::Implied, 2}, // CF + {&CPU::BNE, 2, "bne", AddressingMode::Implied, 2}, // D0 + {&CPU::BRK, 7, "cmp #-#", AddressingMode::Implied, 2}, // D1 + {&CPU::BRK, 7, "cmp #-#", AddressingMode::Implied, 2}, // D2 + {&CPU::BRK, 7, "cmp #-#", AddressingMode::Implied, 2}, // D3 + {&CPU::BRK, 7, "pei #-#", AddressingMode::Implied, 2}, // D4 + {&CPU::BRK, 7, "cmp #-#", AddressingMode::Implied, 2}, // D5 + {&CPU::BRK, 7, "dec #-#", AddressingMode::Implied, 2}, // D6 + {&CPU::BRK, 7, "cmp #-#", AddressingMode::Implied, 2}, // D7 + {&CPU::CLD, 27, "cld", AddressingMode::Implied, 2}, // D8 + {&CPU::BRK, 7, "cmp #-#", AddressingMode::Implied, 2}, // D9 + {&CPU::PHX, 3, "phx", AddressingMode::Implied, 1}, // DA + {&CPU::BRK, 7, "stp #-#", AddressingMode::Implied, 2}, // DB + {&CPU::JML, 7, "jml", AddressingMode::AbsoluteIndirectLong, 2}, // DC + {&CPU::BRK, 7, "cmp #-#", AddressingMode::Implied, 2}, // DD + {&CPU::BRK, 7, "dec #-#", AddressingMode::Implied, 2}, // DE + {&CPU::BRK, 7, "cmp #-#", AddressingMode::Implied, 2}, // DF + {&CPU::BRK, 7, "cpx #-#", AddressingMode::Implied, 2}, // E0 + {&CPU::SBC, 6, "sbc", AddressingMode::DirectPageIndirectIndexedByX, 2}, // E1 + {&CPU::SEP, 3, "sep", AddressingMode::Immediate8bits, 2}, // E2 + {&CPU::SBC, 4, "sbc", AddressingMode::StackRelative, 2}, // E3 + {&CPU::BRK, 7, "cpx #-#", AddressingMode::Implied, 2}, // E4 + {&CPU::SBC, 3, "sbc", AddressingMode::DirectPage, 2}, // E5 + {&CPU::BRK, 7, "inc #-#", AddressingMode::Implied, 2}, // E6 + {&CPU::SBC, 6, "sbc", AddressingMode::DirectPageIndirectLong, 2}, // E7 + {&CPU::BRK, 7, "inx #-#", AddressingMode::Implied, 2}, // E8 + {&CPU::SBC, 2, "sbc", AddressingMode::ImmediateForA, 2}, // E9 + {&CPU::NOP, 2, "nop", AddressingMode::Implied, 1}, // EA + {&CPU::BRK, 7, "xba #-#", AddressingMode::Implied, 2}, // EB + {&CPU::BRK, 7, "cpx #-#", AddressingMode::Implied, 2}, // EC + {&CPU::SBC, 4, "sbc", AddressingMode::Absolute, 3}, // ED + {&CPU::BRK, 7, "inc #-#", AddressingMode::Implied, 2}, // EE + {&CPU::SBC, 5, "sbc", AddressingMode::AbsoluteLong, 4}, // EF + {&CPU::BEQ, 2, "beq", AddressingMode::Implied, 2}, // F0 + {&CPU::SBC, 5, "sbc", AddressingMode::DirectPageIndirectIndexedByY, 2}, // F1 + {&CPU::SBC, 5, "sbc", AddressingMode::DirectPageIndirect, 2}, // F2 + {&CPU::SBC, 7, "sbc", AddressingMode::StackRelativeIndirectIndexedByY, 2}, // F3 + {&CPU::BRK, 7, "pea #-#", AddressingMode::Implied, 2}, // F4 + {&CPU::SBC, 4, "sbc", AddressingMode::DirectPageIndexedByX, 2}, // F5 + {&CPU::BRK, 7, "inc #-#", AddressingMode::Implied, 2}, // F6 + {&CPU::SBC, 6, "sbc", AddressingMode::DirectPageIndirectIndexedByYLong, 2}, // F7 + {&CPU::SED, 2, "sed", AddressingMode::Implied, 1}, // F8 + {&CPU::SBC, 4, "sbc", AddressingMode::AbsoluteIndexedByY, 3}, // F9 + {&CPU::PLX, 4, "plx", AddressingMode::Implied, 1}, // FA + {&CPU::XCE, 2, "xce", AddressingMode::Implied, 1}, // FB + {&CPU::JSR, 8, "jsr", AddressingMode::AbsoluteIndirectIndexedByX, 3}, // FC + {&CPU::SBC, 4, "sbc", AddressingMode::AbsoluteIndexedByX, 3}, // FD + {&CPU::BRK, 7, "inc #-#", AddressingMode::Implied, 2}, // FE + {&CPU::SBC, 5, "sbc", AddressingMode::AbsoluteIndexedByXLong, 4}, // FF + }; public: explicit CPU(std::shared_ptr bus, Cartridge::Header &cartridgeHeader); CPU(const CPU &) = default; @@ -578,7 +661,7 @@ namespace ComSquare::CPU Component getComponent() override; //! @brief Reset interrupt - Called on boot and when the reset button is pressed. - virtual void RESB(); + virtual int RESB(uint24_t = 0); //! @brief Return true if the CPU is overloaded with debugging features. virtual bool isDebugger(); diff --git a/sources/CPU/Instruction.hpp b/sources/CPU/Instruction.hpp new file mode 100644 index 0000000..8efd762 --- /dev/null +++ b/sources/CPU/Instruction.hpp @@ -0,0 +1,62 @@ +// +// Created by anonymus-raccoon on 3/25/20. +// + +#ifndef COMSQUARE_INSTRUCTION_HPP +#define COMSQUARE_INSTRUCTION_HPP + +#include +#include "../Models/Int24.hpp" + +namespace ComSquare::CPU +{ + class CPU; + + //! @brief Different addressing modes that instructions can use for the main CPU. + enum AddressingMode { + Implied, + + Immediate8bits, + ImmediateForA, + ImmediateForX, + + Absolute, + AbsoluteLong, + + DirectPage, + DirectPageIndirect, + DirectPageIndirectLong, + + AbsoluteIndexedByX, + AbsoluteIndexedByXLong, + AbsoluteIndexedByY, + + DirectPageIndexedByX, + DirectPageIndexedByY, + DirectPageIndirectIndexedByX, + DirectPageIndirectIndexedByY, + DirectPageIndirectIndexedByYLong, + + StackRelative, + StackRelativeIndirectIndexedByY, + + + ProgramCounterRelative, + ProgramCounterRelativeLong, + + AbsoluteIndirect, + AbsoluteIndirectIndexedByX, + + AbsoluteIndirectLong + }; + + //! @brief Struct containing basic information about instructions. + struct Instruction { + int (CPU::*call)(uint24_t valueAddr); + int cycleCount; + std::string name; + AddressingMode addressingMode; + int size; + }; +} +#endif //COMSQUARE_INSTRUCTION_HPP diff --git a/sources/CPU/Instructions/BitsInstructions.cpp b/sources/CPU/Instructions/BitsInstructions.cpp index 46b2b6a..d048dcd 100644 --- a/sources/CPU/Instructions/BitsInstructions.cpp +++ b/sources/CPU/Instructions/BitsInstructions.cpp @@ -7,7 +7,7 @@ namespace ComSquare::CPU { - void CPU::AND(uint24_t valueAddr) + int CPU::AND(uint24_t valueAddr) { unsigned negativeMask = this->_isEmulationMode ? 0x80u : 0x8000u; unsigned value = this->_bus->read(valueAddr); @@ -17,5 +17,6 @@ namespace ComSquare::CPU this->_registers.a &= value; this->_registers.p.n = this->_registers.a & negativeMask; this->_registers.p.z = this->_registers.a == 0; + return 0; } } \ No newline at end of file diff --git a/sources/CPU/Instructions/InternalInstruction.cpp b/sources/CPU/Instructions/InternalInstruction.cpp index 6c16c0c..921d2a9 100644 --- a/sources/CPU/Instructions/InternalInstruction.cpp +++ b/sources/CPU/Instructions/InternalInstruction.cpp @@ -6,152 +6,176 @@ namespace ComSquare::CPU { - void CPU::SEC() + int CPU::SEC(uint24_t) { this->_registers.p.c = true; + return 0; } - void CPU::SED() + int CPU::SED(uint24_t) { this->_registers.p.d = true; + return 0; } - void CPU::SEI() + int CPU::SEI(uint24_t) { this->_registers.p.i = true; + return 0; } - void CPU::CLC() + int CPU::CLC(uint24_t) { this->_registers.p.c = false; + return 0; } - void CPU::CLI() + int CPU::CLI(uint24_t) { this->_registers.p.i = false; + return 0; } - void CPU::CLD() + int CPU::CLD(uint24_t) { this->_registers.p.d = false; + return 0; } - void CPU::CLV() + int CPU::CLV(uint24_t) { this->_registers.p.v = false; + return 0; } - void CPU::SEP(uint24_t value) + int CPU::SEP(uint24_t value) { this->_registers.p.flags |= value; + return 0; } - void CPU::REP(uint24_t value) + int CPU::REP(uint24_t value) { this->_registers.p.flags &= ~value; if (this->_isEmulationMode) { this->_registers.p.x_b = true; this->_registers.p.m = true; } + return 0; } - void CPU::JSR(uint24_t value) + int CPU::JSR(uint24_t value) { this->_push(--this->_registers.pc); this->_registers.pc = value; + return 0; } - void CPU::JSL(uint24_t value) + int CPU::JSL(uint24_t value) { this->_registers.pac--; this->_push(this->_registers.pbr); this->_push(this->_registers.pc); this->_registers.pac = value; + return 0; } - void CPU::PHA() + int CPU::PHA(uint24_t) { this->_push(this->_registers.a); + return 0; } - void CPU::PHB() + int CPU::PHB(uint24_t) { this->_push(this->_registers.dbr); + return 0; } - void CPU::PHD() + int CPU::PHD(uint24_t) { this->_push(this->_registers.d); + return 0; } - void CPU::PHK() + int CPU::PHK(uint24_t) { this->_push(this->_registers.pbr); + return 0; } - void CPU::PHP() + int CPU::PHP(uint24_t) { this->_push(this->_registers.p.flags); + return 0; } - void CPU::PHX() + int CPU::PHX(uint24_t) { this->_push(this->_registers.x); + return 0; } - void CPU::PHY() + int CPU::PHY(uint24_t) { this->_push(this->_registers.y); + return 0; } - void CPU::PLA() + int CPU::PLA(uint24_t) { // TODO this register should be poped by 8 if the m flag is 1 this->_registers.a = this->_pop16(); this->_registers.p.z = this->_registers.a == 0; this->_registers.p.n = this->_registers.a & 0x8000u; + return 0; } - void CPU::PLB() + int CPU::PLB(uint24_t) { this->_registers.dbr = this->_pop(); this->_registers.p.z = this->_registers.dbr == 0; this->_registers.p.n = this->_registers.dbr & 0x80u; + return 0; } - void CPU::PLD() + int CPU::PLD(uint24_t) { this->_registers.d = this->_pop16(); this->_registers.p.z = this->_registers.d == 0; this->_registers.p.n = this->_registers.d & 0x8000u; + return 0; } - void CPU::PLP() + int CPU::PLP(uint24_t) { this->_registers.p.flags = this->_pop(); if (this->_isEmulationMode) { this->_registers.p.m = true; this->_registers.p.x_b = true; } + return 0; } - void CPU::PLX() + int CPU::PLX(uint24_t) { // TODO this register should be poped by 8 if the x_b is 1 this->_registers.x = this->_pop16(); this->_registers.p.z = this->_registers.x == 0; this->_registers.p.n = this->_registers.x & 0x8000u; + return 0; } - void CPU::PLY() + int CPU::PLY(uint24_t) { // TODO this register should be poped by 8 if the x_b is 1 this->_registers.y = this->_pop16(); this->_registers.p.z = this->_registers.y == 0; this->_registers.p.n = this->_registers.y & 0x8000u; + return 0; } - void CPU::XCE() + int CPU::XCE(uint24_t) { bool oldCarry = this->_registers.p.c; this->_registers.p.c = this->_isEmulationMode; @@ -163,9 +187,10 @@ namespace ComSquare::CPU this->_registers.xh = 0; this->_registers.yh = 0; } + return 0; } - void CPU::INX() + int CPU::INX(uint24_t) { this->_registers.x++; @@ -175,9 +200,10 @@ namespace ComSquare::CPU unsigned negativeFlag = this->_registers.p.x_b ? 0x80u : 0x8000u; this->_registers.p.z = this->_registers.x == 0; this->_registers.p.n = this->_registers.x & negativeFlag; + return 0; } - void CPU::INY() + int CPU::INY(uint24_t) { this->_registers.y++; @@ -187,9 +213,10 @@ namespace ComSquare::CPU unsigned negativeFlag = this->_registers.p.x_b ? 0x80u : 0x8000u; this->_registers.p.z = this->_registers.y == 0; this->_registers.p.n = this->_registers.y & negativeFlag; + return 0; } - void CPU::CPX(uint24_t valueAddr) + int CPU::CPX(uint24_t valueAddr) { unsigned value = this->_bus->read(valueAddr++); @@ -206,9 +233,10 @@ namespace ComSquare::CPU this->_registers.p.n = x & 0x8000u; } this->_registers.p.c = this->_registers.x >= value; + return 0; } - void CPU::CPY(uint24_t valueAddr) + int CPU::CPY(uint24_t valueAddr) { unsigned value = this->_bus->read(valueAddr++); @@ -225,57 +253,58 @@ namespace ComSquare::CPU this->_registers.p.z = y == 0; this->_registers.p.n = y & 0x8000u; } + return 0; } - bool CPU::BCC(uint24_t valueAddr) + int CPU::BCC(uint24_t valueAddr) { if (!this->_registers.p.c) this->_registers.pac += static_cast(this->_bus->read(valueAddr)); return !this->_registers.p.c; } - bool CPU::BCS(uint24_t valueAddr) + int CPU::BCS(uint24_t valueAddr) { if (this->_registers.p.c) this->_registers.pac += static_cast(this->_bus->read(valueAddr)); return this->_registers.p.c; } - bool CPU::BEQ(uint24_t valueAddr) + int CPU::BEQ(uint24_t valueAddr) { if (this->_registers.p.z) this->_registers.pac += static_cast(this->_bus->read(valueAddr)); return this->_registers.p.z; } - bool CPU::BNE(uint24_t valueAddr) + int CPU::BNE(uint24_t valueAddr) { if (!this->_registers.p.z) this->_registers.pac += static_cast(this->_bus->read(valueAddr)); return !this->_registers.p.z; } - bool CPU::BMI(uint24_t valueAddr) + int CPU::BMI(uint24_t valueAddr) { if (this->_registers.p.n) this->_registers.pac += static_cast(this->_bus->read(valueAddr)); return this->_registers.p.n; } - bool CPU::BPL(uint24_t valueAddr) + int CPU::BPL(uint24_t valueAddr) { if (!this->_registers.p.n) this->_registers.pac += static_cast(this->_bus->read(valueAddr)); return !this->_registers.p.n; } - bool CPU::BRA(uint24_t valueAddr) + int CPU::BRA(uint24_t valueAddr) { this->_registers.pac += static_cast(this->_bus->read(valueAddr)); return true; } - bool CPU::BRL(uint24_t valueAddr) + int CPU::BRL(uint24_t valueAddr) { unsigned value = this->_bus->read(valueAddr); value += this->_bus->read(valueAddr + 1) << 8u; @@ -284,27 +313,34 @@ namespace ComSquare::CPU return true; } - bool CPU::BVC(uint24_t valueAddr) + int CPU::BVC(uint24_t valueAddr) { if (!this->_registers.p.v) this->_registers.pac += static_cast(this->_bus->read(valueAddr)); return !this->_registers.p.v; } - bool CPU::BVS(uint24_t valueAddr) + int CPU::BVS(uint24_t valueAddr) { if (this->_registers.p.v) this->_registers.pac += static_cast(this->_bus->read(valueAddr)); return this->_registers.p.v; } - void CPU::JMP(uint24_t value) + int CPU::JMP(uint24_t value) { this->_registers.pc = value; + return 0; } - void CPU::JML(uint24_t value) + int CPU::JML(uint24_t value) { this->_registers.pac = value; + return 0; + } + + int CPU::NOP(uint24_t) + { + return 0; } } \ No newline at end of file diff --git a/sources/CPU/Instructions/Interrupts.cpp b/sources/CPU/Instructions/Interrupts.cpp index 1c5d021..02d54ae 100644 --- a/sources/CPU/Instructions/Interrupts.cpp +++ b/sources/CPU/Instructions/Interrupts.cpp @@ -6,7 +6,7 @@ namespace ComSquare::CPU { - void CPU::RESB() + int CPU::RESB(uint24_t) { this->_registers.p.i = true; this->_registers.p.d = false; @@ -18,9 +18,10 @@ namespace ComSquare::CPU this->_registers.d = 0x0000; this->_registers.sh = 0x01; // the low bit of the stack pointer is undefined on reset. this->_registers.pc = this->_cartridgeHeader.emulationInterrupts.reset; + return 0; } - void CPU::BRK() + int CPU::BRK(uint24_t) { if (this->_isEmulationMode) { this->_registers.pc += 2; @@ -41,9 +42,10 @@ namespace ComSquare::CPU this->_registers.pbr = 0x0; this->_registers.pc = this->_cartridgeHeader.nativeInterrupts.brk; } + return !this->_isEmulationMode; } - void CPU::COP() + int CPU::COP(uint24_t) { if (this->_isEmulationMode) { this->_registers.pc += 2; @@ -63,14 +65,16 @@ namespace ComSquare::CPU this->_registers.pbr = 0x0; this->_registers.pc = this->_cartridgeHeader.nativeInterrupts.cop; } + return !this->_isEmulationMode; } - void CPU::RTI() + int CPU::RTI(uint24_t) { this->_registers.p.flags = this->_pop(); this->_registers.pc = this->_pop16(); if (!this->_isEmulationMode) this->_registers.pbr = this->_pop16(); + return 0; } } \ No newline at end of file diff --git a/sources/CPU/Instructions/MathematicalOperations.cpp b/sources/CPU/Instructions/MathematicalOperations.cpp index 75835ea..60465d9 100644 --- a/sources/CPU/Instructions/MathematicalOperations.cpp +++ b/sources/CPU/Instructions/MathematicalOperations.cpp @@ -7,7 +7,7 @@ namespace ComSquare::CPU { - void CPU::ADC(uint24_t valueAddr) + int CPU::ADC(uint24_t valueAddr) { unsigned value = this->_bus->read(valueAddr) + this->_registers.p.c; if (!this->_registers.p.m) @@ -25,9 +25,10 @@ namespace ComSquare::CPU this->_registers.a %= 0x100; this->_registers.p.z = this->_registers.a == 0; this->_registers.p.n = this->_registers.a & negativeMask; + return 0; } - void CPU::SBC(uint24_t valueAddr) + int CPU::SBC(uint24_t valueAddr) { unsigned negativeMask = this->_isEmulationMode ? 0x80u : 0x8000u; unsigned value = this->_bus->read(valueAddr); @@ -45,5 +46,6 @@ namespace ComSquare::CPU this->_registers.a %= 0x100; this->_registers.p.z = this->_registers.a == 0; this->_registers.p.n = this->_registers.a & negativeMask; + return 0; } } \ No newline at end of file diff --git a/sources/CPU/Instructions/MemoryInstructions.cpp b/sources/CPU/Instructions/MemoryInstructions.cpp index 8a7b310..1e29642 100644 --- a/sources/CPU/Instructions/MemoryInstructions.cpp +++ b/sources/CPU/Instructions/MemoryInstructions.cpp @@ -6,7 +6,7 @@ namespace ComSquare::CPU { - void CPU::STA(uint24_t addr) + int CPU::STA(uint24_t addr) { if (this->_registers.p.m) this->_bus->write(addr, this->_registers.al); @@ -14,9 +14,10 @@ namespace ComSquare::CPU this->_bus->write(addr, this->_registers.al); this->_bus->write(addr + 1, this->_registers.ah); } + return 0; } - void CPU::STX(uint24_t addr) + int CPU::STX(uint24_t addr) { if (this->_registers.p.x_b) this->_bus->write(addr, this->_registers.xl); @@ -24,9 +25,10 @@ namespace ComSquare::CPU this->_bus->write(addr, this->_registers.xl); this->_bus->write(addr + 1, this->_registers.xh); } + return 0; } - void CPU::STY(uint24_t addr) + int CPU::STY(uint24_t addr) { if (this->_registers.p.x_b) this->_bus->write(addr, this->_registers.yl); @@ -34,16 +36,18 @@ namespace ComSquare::CPU this->_bus->write(addr, this->_registers.yl); this->_bus->write(addr + 1, this->_registers.yh); } + return 0; } - void CPU::STZ(uint24_t addr) + int CPU::STZ(uint24_t addr) { this->_bus->write(addr, 0x00); if (!this->_registers.p.m) this->_bus->write(addr + 1, 0x00); + return 0; } - void CPU::LDA(uint24_t addr) + int CPU::LDA(uint24_t addr) { if (this->_registers.p.m) { this->_registers.a = this->_bus->read(addr); @@ -54,9 +58,10 @@ namespace ComSquare::CPU this->_registers.p.n = this->_registers.a & 0xF000u; } this->_registers.p.z = this->_registers.a == 0x0; + return 0; } - void CPU::LDX(uint24_t addr) + int CPU::LDX(uint24_t addr) { if (this->_registers.p.x_b) { this->_registers.x = this->_bus->read(addr); @@ -67,9 +72,10 @@ namespace ComSquare::CPU this->_registers.p.n = this->_registers.x & 0xF000u; } this->_registers.p.z = this->_registers.x == 0x0; + return 0; } - void CPU::LDY(uint24_t addr) + int CPU::LDY(uint24_t addr) { if (this->_registers.p.x_b) { this->_registers.y = this->_bus->read(addr); @@ -80,5 +86,6 @@ namespace ComSquare::CPU this->_registers.p.n = this->_registers.y & 0xF000u; } this->_registers.p.z = this->_registers.y == 0x0; + return 0; } } \ No newline at end of file diff --git a/sources/CPU/Instructions/TransferRegisters.cpp b/sources/CPU/Instructions/TransferRegisters.cpp index 4b95092..3e49685 100644 --- a/sources/CPU/Instructions/TransferRegisters.cpp +++ b/sources/CPU/Instructions/TransferRegisters.cpp @@ -6,7 +6,7 @@ namespace ComSquare::CPU { - void CPU::TAX() + int CPU::TAX(uint24_t) { if (this->_registers.p.x_b) { this->_registers.xl = this->_registers.al; @@ -17,9 +17,10 @@ namespace ComSquare::CPU this->_registers.p.z = this->_registers.x == 0; this->_registers.p.n = this->_registers.x & 0x8000u; } + return 0; } - void CPU::TAY() + int CPU::TAY(uint24_t) { if (this->_registers.p.x_b) { this->_registers.yl = this->_registers.al; @@ -30,9 +31,10 @@ namespace ComSquare::CPU this->_registers.p.z = this->_registers.y == 0; this->_registers.p.n = this->_registers.y & 0x8000u; } + return 0; } - void CPU::TXS() + int CPU::TXS(uint24_t) { if (this->_registers.p.x_b) { this->_registers.sh = 0; @@ -44,5 +46,6 @@ namespace ComSquare::CPU this->_registers.p.z = this->_registers.s == 0; this->_registers.p.n = this->_registers.s & 0x8000u; } + return 0; } } \ No newline at end of file diff --git a/sources/Debugger/CPUDebug.cpp b/sources/Debugger/CPUDebug.cpp index 80a4c07..34e091c 100644 --- a/sources/Debugger/CPUDebug.cpp +++ b/sources/Debugger/CPUDebug.cpp @@ -16,6 +16,7 @@ namespace ComSquare::Debugger : CPU(basicCPU), _window(new ClosableWindow(*this, &CPUDebug::disableDebugger)), _ui(), + _model(*this), _snes(snes) { this->_window->setContextMenuPolicy(Qt::NoContextMenu); @@ -23,6 +24,13 @@ namespace ComSquare::Debugger this->_window->setAttribute(Qt::WA_DeleteOnClose); this->_ui.setupUi(this->_window); + + this->_ui.disasembly->setModel(&this->_model); + this->_ui.disasembly->setShowGrid(false); + this->_ui.disasembly->verticalHeader()->hide(); + this->_ui.disasembly->horizontalHeader()->hide(); + this->_ui.disasembly->horizontalHeader()->setStretchLastSection(true); + QMainWindow::connect(this->_ui.actionPause, &QAction::triggered, this, &CPUDebug::pause); QMainWindow::connect(this->_ui.actionStep, &QAction::triggered, this, &CPUDebug::step); QMainWindow::connect(this->_ui.clear, &QPushButton::released, this, &CPUDebug::clearHistory); @@ -51,12 +59,15 @@ namespace ComSquare::Debugger } catch (InvalidOpcode &e) { if (!this->_isPaused) this->pause(); + std::cout << "Invalid Opcode: " << e.what() << std::endl; return 0xFF; } } unsigned CPUDebug::_executeInstruction(uint8_t opcode) { + if (this->_isPaused) + return 0; if (this->_isStepping) { this->_isStepping = false; this->_isPaused = true; @@ -202,198 +213,37 @@ namespace ComSquare::Debugger std::string CPUDebug::_getInstructionString(uint24_t pc) { uint8_t opcode = this->_bus->read(pc++, true); - - switch (opcode) { - case Instructions::BRK: return "BRK"; - - case Instructions::COP: return "COP"; - - case Instructions::RTI: return "RTI"; - - case Instructions::ADC_IM: return "ADC " + this->_getImmediateValueForA(pc); - case Instructions::ADC_ABS: return "ADC " + this->_getAbsoluteValue(pc); - case Instructions::ADC_ABSl: return "ADC " + this->_getAbsoluteLongValue(pc); - case Instructions::ADC_DP: return "ADC " + this->_getDirectValue(pc); - case Instructions::ADC_DPi: return "ADC"; - case Instructions::ADC_DPil: return "ADC"; - case Instructions::ADC_ABSX: return "ADC"; - case Instructions::ADC_ABSXl:return "ADC"; - case Instructions::ADC_ABSY: return "ADC"; - case Instructions::ADC_DPX: return "ADC " + this->_getDirectIndexedByXValue(pc); - case Instructions::ADC_DPXi: return "ADC"; - case Instructions::ADC_DPYi: return "ADC"; - case Instructions::ADC_DPYil:return "ADC"; - case Instructions::ADC_SR: return "ADC"; - case Instructions::ADC_SRYi: return "ADC"; - - case Instructions::STA_ABS: return "STA " + this->_getAbsoluteValue(pc); - case Instructions::STA_ABSl: return "STA " + this->_getAbsoluteLongValue(pc); - case Instructions::STA_DP: return "STA " + this->_getDirectValue(pc); - case Instructions::STA_DPi: return "STA"; - case Instructions::STA_DPil: return "STA"; - case Instructions::STA_ABSX: return "STA"; - case Instructions::STA_ABSXl:return "STA"; - case Instructions::STA_ABSY: return "STA"; - case Instructions::STA_DPX: return "STA " + this->_getDirectIndexedByXValue(pc); - case Instructions::STA_DPXi: return "STA"; - case Instructions::STA_DPYi: return "STA"; - case Instructions::STA_DPYil:return "STA"; - case Instructions::STA_SR: return "STA"; - case Instructions::STA_SRYi: return "STA"; - - case Instructions::STX_ABS: return "STX " + this->_getAbsoluteValue(pc); - case Instructions::STX_DP: return "STX " + this->_getDirectValue(pc); - case Instructions::STX_DPY: return "STX"; - - case Instructions::STY_ABS: return "STY " + this->_getAbsoluteValue(pc); - case Instructions::STY_DP: return "STY " + this->_getDirectValue(pc); - case Instructions::STY_DPX: return "STY " + this->_getDirectIndexedByXValue(pc); - - case Instructions::STZ_ABS: return "STZ " + this->_getAbsoluteValue(pc); - case Instructions::STZ_DP: return "STZ " + this->_getDirectValue(pc); - case Instructions::STZ_ABSX: return "STZ"; - case Instructions::STZ_DPX: return "STZ " + this->_getDirectIndexedByXValue(pc); - - case Instructions::LDA_IM: return "LDA " + this->_getImmediateValueForA(pc); - case Instructions::LDA_ABS: return "LDA " + this->_getAbsoluteValue(pc); - case Instructions::LDA_ABSl: return "LDA " + this->_getAbsoluteLongValue(pc); - case Instructions::LDA_DP: return "LDA " + this->_getDirectValue(pc); - case Instructions::LDA_DPi: return "LDA"; - case Instructions::LDA_DPil: return "LDA"; - case Instructions::LDA_ABSX: return "LDA"; - case Instructions::LDA_ABSXl:return "LDA"; - case Instructions::LDA_ABSY: return "LDA"; - case Instructions::LDA_DPX: return "LDA " + this->_getDirectIndexedByXValue(pc); - case Instructions::LDA_DPXi: return "LDA"; - case Instructions::LDA_DPYi: return "LDA"; - case Instructions::LDA_DPYil:return "LDA"; - case Instructions::LDA_SR: return "LDA"; - case Instructions::LDA_SRYi: return "LDA"; - - case Instructions::LDX_IM: return "LDX " + this->_getImmediateValueForX(pc); - case Instructions::LDX_ABS: return "LDX " + this->_getAbsoluteValue(pc); - case Instructions::LDX_DP: return "LDX " + this->_getDirectValue(pc); - case Instructions::LDX_ABSY: return "LDX"; - case Instructions::LDX_DPY: return "LDX"; - - case Instructions::LDY_IM: return "LDY " + this->_getImmediateValueForX(pc); - case Instructions::LDY_ABS: return "LDY " + this->_getAbsoluteValue(pc); - case Instructions::LDY_DP: return "LDY " + this->_getDirectValue(pc); - case Instructions::LDY_ABSY: return "LDY"; - case Instructions::LDY_DPY: return "LDY"; - - case Instructions::SEP: return "SEP " + this->_getImmediateValue8Bits(pc); - - case Instructions::REP: return "REP " + this->_getImmediateValue8Bits(pc); - - case Instructions::PHA: return "PHA"; - case Instructions::PHB: return "PHB"; - case Instructions::PHD: return "PHD"; - case Instructions::PHK: return "PHK"; - case Instructions::PHP: return "PHP"; - case Instructions::PHX: return "PHX"; - case Instructions::PHY: return "PHY"; - - case Instructions::PLA: return "PLA"; - case Instructions::PLB: return "PLB"; - case Instructions::PLD: return "PLD"; - case Instructions::PLP: return "PLP"; - case Instructions::PLX: return "PLX"; - case Instructions::PLY: return "PLY"; - - case Instructions::JSR_ABS: return "JSR " + this->_getAbsoluteValue(pc); - case Instructions::JSR_ABSXi: return "JSR"; - - case Instructions::JSL: return "JSL " + this->_getAbsoluteLongValue(pc); - - case Instructions::CLC: return "CLC"; - case Instructions::CLI: return "CLI"; - case Instructions::CLD: return "CLD"; - case Instructions::CLV: return "CLV"; - - case Instructions::SEC: return "SEC"; - case Instructions::SED: return "SED"; - case Instructions::SEI: return "SEI"; - - case Instructions::AND_IM: return "AND " + this->_getImmediateValueForA(pc); - case Instructions::AND_ABS: return "AND " + this->_getAbsoluteValue(pc); - case Instructions::AND_ABSl: return "AND " + this->_getAbsoluteLongValue(pc); - case Instructions::AND_DP: return "AND " + this->_getDirectValue(pc); - case Instructions::AND_DPi: return "AND"; - case Instructions::AND_DPil: return "AND"; - case Instructions::AND_ABSX: return "AND"; - case Instructions::AND_ABSXl:return "AND"; - case Instructions::AND_ABSY: return "AND"; - case Instructions::AND_DPX: return "AND " + this->_getDirectIndexedByXValue(pc); - case Instructions::AND_DPXi: return "AND"; - case Instructions::AND_DPYi: return "AND"; - case Instructions::AND_DPYil:return "AND"; - case Instructions::AND_SR: return "AND"; - case Instructions::AND_SRYi: return "AND"; - - case Instructions::XCE: return "XCE"; - - case Instructions::SBC_IM: return "SBC " + this->_getImmediateValueForA(pc); - case Instructions::SBC_ABS: return "SBC " + this->_getAbsoluteValue(pc); - case Instructions::SBC_ABSl: return "SBC " + this->_getAbsoluteLongValue(pc); - case Instructions::SBC_DP: return "SBC " + this->_getDirectValue(pc); - case Instructions::SBC_DPi: return "SBC"; - case Instructions::SBC_DPil: return "SBC"; - case Instructions::SBC_ABSX: return "SBC"; - case Instructions::SBC_ABSXl:return "SBC"; - case Instructions::SBC_ABSY: return "SBC"; - case Instructions::SBC_DPX: return "SBC " + this->_getDirectIndexedByXValue(pc); - case Instructions::SBC_DPXi: return "SBC"; - case Instructions::SBC_DPYi: return "SBC"; - case Instructions::SBC_DPYil:return "SBC"; - case Instructions::SBC_SR: return "SBC"; - case Instructions::SBC_SRYi: return "SBC"; - - case Instructions::TAX: return "TAX"; - case Instructions::TAY: return "TAY"; - case Instructions::TXS: return "TXS"; - - case Instructions::INX: return "INX"; - case Instructions::INY: return "INY"; - - case Instructions::CPX_IM: return "CPX " + this->_getImmediateValueForX(pc); - case Instructions::CPX_ABS: return "CPX " + this->_getAbsoluteValue(pc); - case Instructions::CPX_DP: return "CPX"; - - case Instructions::CPY_IM: return "CPY " + this->_getImmediateValueForX(pc); - case Instructions::CPY_ABS: return "CPY " + this->_getAbsoluteValue(pc); - case Instructions::CPY_DP: return "CPY"; - - case Instructions::BCC: return "BCC " + this->_getImmediateValue8Bits(pc); - case Instructions::BCS: return "BCS " + this->_getImmediateValue8Bits(pc); - case Instructions::BEQ: return "BEQ " + this->_getImmediateValue8Bits(pc); - case Instructions::BNE: return "BNE " + this->_getImmediateValue8Bits(pc); - case Instructions::BMI: return "BMI " + this->_getImmediateValue8Bits(pc); - case Instructions::BPL: return "BPL " + this->_getImmediateValue8Bits(pc); - case Instructions::BVC: return "BVC " + this->_getImmediateValue8Bits(pc); - case Instructions::BVS: return "BVS " + this->_getImmediateValue8Bits(pc); - case Instructions::BRA: return "BRA " + this->_getImmediateValue8Bits(pc); - case Instructions::BRL: return "BRL " + this->_getImmediateValue16Bits(pc); - - case Instructions::JMP_ABS: return "JMP " + this->_getAbsoluteValue(pc); - case Instructions::JMP_ABSi: return "JMP "; //+ this->_getAbsoluteIndire(pc); - case Instructions::JMP_ABSXi: return "JMP "; //+ this->_getAbsoluteValue(pc); - - case Instructions::JML_ABSl: return "JML"; - case Instructions::JML_ABSil: return "JML"; - - default: return "Unknown"; - } + return this->_instructions[opcode].name; } - void CPUDebug::RESB() + int CPUDebug::RESB(uint24_t) { CPU::RESB(); this->_updateRegistersPanel(); + return (0); } void CPUDebug::focus() { this->_window->activateWindow(); } +} + +DisassemblyModel::DisassemblyModel(ComSquare::Debugger::CPUDebug &cpu) : QAbstractTableModel(), _cpu(cpu){ } + +int DisassemblyModel::columnCount(const QModelIndex &) const +{ + return 4; +} + +int DisassemblyModel::rowCount(const QModelIndex &) const +{ + return 0xFFFFFF; +} + +QVariant DisassemblyModel::data(const QModelIndex &index, int role) const +{ + if (role != Qt::DisplayRole) + return QVariant(); + return QString(); } \ No newline at end of file diff --git a/sources/Debugger/CPUDebug.hpp b/sources/Debugger/CPUDebug.hpp index 15fbb7c..82a57a0 100644 --- a/sources/Debugger/CPUDebug.hpp +++ b/sources/Debugger/CPUDebug.hpp @@ -11,6 +11,31 @@ #include "../../ui/ui_cpu.h" #include "ClosableWindow.hpp" +namespace ComSquare::Debugger +{ + class CPUDebug; +} + +//! @brief The qt model that show the disassembly. +class DisassemblyModel : public QAbstractTableModel +{ +Q_OBJECT +private: + ComSquare::Debugger::CPUDebug &_cpu; +public: + explicit DisassemblyModel(ComSquare::Debugger::CPUDebug &cpu); + DisassemblyModel(const DisassemblyModel &) = delete; + const DisassemblyModel &operator=(const DisassemblyModel &) = delete; + ~DisassemblyModel() override = default; + + //! @brief The number of row the table has. + int rowCount(const QModelIndex &parent) const override; + //! @brief The number of column the table has. + int columnCount(const QModelIndex &parent) const override; + //! @brief Return a data representing the table cell. + QVariant data(const QModelIndex &index, int role) const override; +}; + namespace ComSquare::Debugger { //! @brief A custom CPU with a window that show it's registers and the disassembly. @@ -20,6 +45,8 @@ namespace ComSquare::Debugger ClosableWindow *_window; //! @brief A widget that contain the whole UI. Ui::CPUView _ui; + //! @brief The disassembly viewer's model. + DisassemblyModel _model; //! @brief If this is set to true, the execution of the CPU will be paused. bool _isPaused = true; //! @brief If this is set to true, the CPU will execute one instruction and pause itself. @@ -52,7 +79,7 @@ namespace ComSquare::Debugger //! @brief Return a printable string corresponding to the value of a direct index by x addressing mode. std::string _getDirectIndexedByXValue(uint24_t pc); - public slots: + public: //! @brief Pause/Resume the CPU. void pause(); //! @brief Step - Execute a single instruction. @@ -63,7 +90,7 @@ namespace ComSquare::Debugger void disableDebugger(); public: //! @brief Update the UI when reseting the CPU. - void RESB() override; + int RESB(uint24_t) override; //! @brief Convert a basic CPU to a debugging CPU. explicit CPUDebug(ComSquare::CPU::CPU &cpu, SNES &snes); CPUDebug(const CPUDebug &) = delete; diff --git a/sources/Exceptions/DebuggableError.hpp b/sources/Exceptions/DebuggableError.hpp new file mode 100644 index 0000000..fcc9180 --- /dev/null +++ b/sources/Exceptions/DebuggableError.hpp @@ -0,0 +1,15 @@ +// +// Created by anonymus-raccoon on 3/26/20. +// + +#ifndef COMSQUARE_DEBUGGABLEERROR_HPP +#define COMSQUARE_DEBUGGABLEERROR_HPP + +#include + +namespace ComSquare +{ + class DebuggableError : public std::exception {}; +} + +#endif //COMSQUARE_DEBUGGABLEERROR_HPP diff --git a/sources/Exceptions/InvalidAction.hpp b/sources/Exceptions/InvalidAction.hpp index 8b9c06a..e74d73d 100644 --- a/sources/Exceptions/InvalidAction.hpp +++ b/sources/Exceptions/InvalidAction.hpp @@ -7,11 +7,12 @@ #include #include +#include "DebuggableError.hpp" namespace ComSquare { //! @brief Exception thrown when someone tries to load an invalid rom. - class InvalidAction : public std::exception { + class InvalidAction : public DebuggableError { private: std::string _msg; public: diff --git a/sources/Exceptions/InvalidAddress.hpp b/sources/Exceptions/InvalidAddress.hpp index 09724ae..b91ce6e 100644 --- a/sources/Exceptions/InvalidAddress.hpp +++ b/sources/Exceptions/InvalidAddress.hpp @@ -9,11 +9,12 @@ #include #include #include +#include "DebuggableError.hpp" namespace ComSquare { //! @brief Exception thrown when trying to read/write to an invalid address. - class InvalidAddress : public std::exception { + class InvalidAddress : public DebuggableError { private: std::string _msg; public: diff --git a/sources/Exceptions/InvalidOpcode.hpp b/sources/Exceptions/InvalidOpcode.hpp index 00447c4..57e990d 100644 --- a/sources/Exceptions/InvalidOpcode.hpp +++ b/sources/Exceptions/InvalidOpcode.hpp @@ -8,11 +8,12 @@ #include #include #include +#include "DebuggableError.hpp" namespace ComSquare { //! @brief Exception thrown when someone tries to load an invalid rom. - class InvalidOpcode : public std::exception { + class InvalidOpcode : public DebuggableError { private: std::string _msg; public: diff --git a/sources/Exceptions/InvalidRom.hpp b/sources/Exceptions/InvalidRom.hpp index 433c478..f0f331a 100644 --- a/sources/Exceptions/InvalidRom.hpp +++ b/sources/Exceptions/InvalidRom.hpp @@ -7,11 +7,12 @@ #include #include +#include "DebuggableError.hpp" namespace ComSquare { //! @brief Exception thrown when someone tries to load an invalid rom. - class InvalidRomException : public std::exception { + class InvalidRomException : public DebuggableError { private: std::string _msg; public: diff --git a/sources/Renderer/QtRenderer/QtSFML.cpp b/sources/Renderer/QtRenderer/QtSFML.cpp index 9a333a6..e74a103 100644 --- a/sources/Renderer/QtRenderer/QtSFML.cpp +++ b/sources/Renderer/QtRenderer/QtSFML.cpp @@ -10,6 +10,7 @@ #include "QtSFML.hpp" #include "../../Exceptions/InvalidOpcode.hpp" #include "../../Exceptions/InvalidAddress.hpp" +#include "../../Exceptions/InvalidAction.hpp" #ifdef Q_WS_X11 #include @@ -86,10 +87,9 @@ namespace ComSquare::Renderer { try { this->_snes.update(); - } catch (InvalidOpcode &e) { - this->_snes.enableCPUDebugging(); - } catch (InvalidAddress &e) { - this->_snes.enableCPUDebugging(); + } catch (DebuggableError &e) { + std::cout << "Invalid rom's instruction: " << e.what() << std::endl; + this->_snes.enableCPUDebugging(true); } catch (std::exception &e) { std::cerr << "An error occurred: " << e.what() << std::endl; QApplication::quit(); diff --git a/sources/SNES.cpp b/sources/SNES.cpp index 3dc9674..b6188fe 100644 --- a/sources/SNES.cpp +++ b/sources/SNES.cpp @@ -34,12 +34,14 @@ namespace ComSquare this->apu->update(cycleCount); } - void SNES::enableCPUDebugging() + void SNES::enableCPUDebugging(bool pause) { #ifdef DEBUGGER_ENABLED - if (this->cpu->isDebugger()) - std::static_pointer_cast(this->cpu)->focus(); - else + if (this->cpu->isDebugger()) { + auto cpuDebug = std::static_pointer_cast(this->cpu); + cpuDebug->focus(); + cpuDebug->pause(); + } else this->cpu = std::make_shared(*this->cpu, *this); #else std::cerr << "Debugging features are not enabled. You can't enable the debugger." << std::endl; diff --git a/sources/SNES.hpp b/sources/SNES.hpp index 25fb99e..77c5264 100644 --- a/sources/SNES.hpp +++ b/sources/SNES.hpp @@ -53,7 +53,7 @@ namespace ComSquare //! @brief Disable the CPU's debugging window. void disableCPUDebugging(); //! @brief Enable the CPU's debugging window. - void enableCPUDebugging(); + void enableCPUDebugging(bool pause = false); //! @brief Disable the Ram's debugging window. void disableRamViewer(); //! @brief Enable the Ram's debugging window. diff --git a/tests/CPU/TransferRegisters.cpp b/tests/CPU/TransferRegisters.cpp index 7ee8e76..5bb6c01 100644 --- a/tests/CPU/TransferRegisters.cpp +++ b/tests/CPU/TransferRegisters.cpp @@ -17,7 +17,7 @@ Test(TAX, 16bitsTo16Bits) snes.cpu->_registers.p.m = false; snes.cpu->_registers.x = 0xABCD; snes.cpu->_registers.a = 0xFEDC; - snes.cpu->TAX(); + snes.cpu->TAX(0x0); cr_assert_eq(snes.cpu->_registers.x, 0xFEDC, "The flags should be 0xFEDC but it was %x", snes.cpu->_registers.x); cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flag should be set."); cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should not be set."); @@ -31,7 +31,7 @@ Test(TAX, 16bitsTo8Bits) snes.cpu->_registers.p.m = false; snes.cpu->_registers.x = 0xFEDC; snes.cpu->_registers.a = 0xAB00; - snes.cpu->TAX(); + snes.cpu->TAX(0x0); cr_assert_eq(snes.cpu->_registers.x, 0xFE00, "The flags should be 0xFE00 but it was %x", snes.cpu->_registers.x); cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flag should not be set."); cr_assert_eq(snes.cpu->_registers.p.z, true, "The zero flag should be set."); @@ -45,7 +45,7 @@ Test(TAX, 8bitsTo16Bits) snes.cpu->_registers.p.m = true; snes.cpu->_registers.x = 0xFEDC; snes.cpu->_registers.a = 0xAB; - snes.cpu->TAX(); + snes.cpu->TAX(0x0); cr_assert_eq(snes.cpu->_registers.x, 0x00AB, "The flags should be 0x00AB but it was %x", snes.cpu->_registers.x); cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flag should not be set."); cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should not be set."); @@ -59,7 +59,7 @@ Test(TAX, 8bitsTo8Bits) snes.cpu->_registers.p.m = true; snes.cpu->_registers.x = 0xFE; snes.cpu->_registers.a = 0xAB; - snes.cpu->TAX(); + snes.cpu->TAX(0x0); cr_assert_eq(snes.cpu->_registers.x, 0xAB, "The flags should be 0xAB but it was %x", snes.cpu->_registers.x); cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flag should be set."); cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should be not set."); @@ -74,7 +74,7 @@ Test(TAY, 16bitsTo16Bits) snes.cpu->_registers.p.m = false; snes.cpu->_registers.y = 0xABCD; snes.cpu->_registers.a = 0xFEDC; - snes.cpu->TAY(); + snes.cpu->TAY(0x0); cr_assert_eq(snes.cpu->_registers.y, 0xFEDC, "The y register should be 0xFEDC but it was %x", snes.cpu->_registers.y); cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flag should be set."); cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should not be set."); @@ -88,7 +88,7 @@ Test(TAY, 16bitsTo8Bits) snes.cpu->_registers.p.m = false; snes.cpu->_registers.y = 0xFEDC; snes.cpu->_registers.a = 0xAB00; - snes.cpu->TAY(); + snes.cpu->TAY(0x0); cr_assert_eq(snes.cpu->_registers.y, 0xFE00, "The y register should be 0xFE00 but it was %x", snes.cpu->_registers.y); cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flag should not be set."); cr_assert_eq(snes.cpu->_registers.p.z, true, "The zero flag should be set."); @@ -102,7 +102,7 @@ Test(TAY, 8bitsTo16Bits) snes.cpu->_registers.p.m = true; snes.cpu->_registers.y = 0xFEDC; snes.cpu->_registers.a = 0xAB; - snes.cpu->TAY(); + snes.cpu->TAY(0x0); cr_assert_eq(snes.cpu->_registers.y, 0x00AB, "The y register should be 0x00AB but it was %x", snes.cpu->_registers.y); cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flag should not be set."); cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should not be set."); @@ -116,7 +116,7 @@ Test(TAY, 8bitsTo8Bits) snes.cpu->_registers.p.m = true; snes.cpu->_registers.y = 0xFE; snes.cpu->_registers.a = 0xAB; - snes.cpu->TAY(); + snes.cpu->TAY(0x0); cr_assert_eq(snes.cpu->_registers.y, 0xAB, "The y register should be 0xAB but it was %x", snes.cpu->_registers.y); cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flag should be set."); cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should be not set."); @@ -128,7 +128,7 @@ Test(TXS, 16bitsIndex) snes.cpu->_isEmulationMode = false; snes.cpu->_registers.p.x_b = false; snes.cpu->_registers.x = 0xABCD; - snes.cpu->TXS(); + snes.cpu->TXS(0x0); cr_assert_eq(snes.cpu->_registers.s, 0xABCD, "The stack pointer should be 0xABCD but it was %x", snes.cpu->_registers.s); cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flag should be set."); cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should be not set."); @@ -140,7 +140,7 @@ Test(TXS, 8bitsIndex) snes.cpu->_isEmulationMode = false; snes.cpu->_registers.p.x_b = true; snes.cpu->_registers.x = 0xABCD; - snes.cpu->TXS(); + snes.cpu->TXS(0x0); cr_assert_eq(snes.cpu->_registers.s, 0x00CD, "The stack pointer should be 0x00CD but it was %x", snes.cpu->_registers.s); cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flag should be set."); cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should be not set."); diff --git a/tests/CPU/testInternal.cpp b/tests/CPU/testInternal.cpp index 7caa8ea..fca58c3 100644 --- a/tests/CPU/testInternal.cpp +++ b/tests/CPU/testInternal.cpp @@ -99,7 +99,7 @@ Test(PHA, basic) Init() snes.cpu->_registers.a = 0xABCD; snes.cpu->_registers.s = 0x02; - snes.cpu->PHA(); + snes.cpu->PHA(0x0); cr_assert_eq(snes.wram->_data[1], 0xCD, "The second value pushed to the stack should be 0xCD but it was %x", snes.wram->_data[1]); cr_assert_eq(snes.wram->_data[2], 0xAB, "The first value pushed to the stack should be 0xAB but it was %x", snes.wram->_data[2]); cr_assert_eq(snes.cpu->_registers.s, 0x0, "The Stack pointer should be equal to 0x0 but it was %x", snes.cpu->_registers.s); @@ -110,7 +110,7 @@ Test(PHB, basic) Init() snes.cpu->_registers.dbr = 0xFF; snes.cpu->_registers.s = 0x02; - snes.cpu->PHB(); + snes.cpu->PHB(0x0); cr_assert_eq(snes.wram->_data[2], 0xFF, "The first value pushed to the stack should be 0xFF but it was %x", snes.wram->_data[2]); cr_assert_eq(snes.cpu->_registers.s, 0x1, "The Stack pointer should be equal to 0x1 but it was %x", snes.cpu->_registers.s); } @@ -120,7 +120,7 @@ Test(PHD, basic) Init() snes.cpu->_registers.d = 0xABCD; snes.cpu->_registers.s = 0x02; - snes.cpu->PHD(); + snes.cpu->PHD(0x0); cr_assert_eq(snes.wram->_data[1], 0xCD, "The second value pushed to the stack should be 0xCD but it was %x", snes.wram->_data[1]); cr_assert_eq(snes.wram->_data[2], 0xAB, "The first value pushed to the stack should be 0xAB but it was %x", snes.wram->_data[2]); cr_assert_eq(snes.cpu->_registers.s, 0x0, "The Stack pointer should be equal to 0x0 but it was %x", snes.cpu->_registers.s); @@ -131,7 +131,7 @@ Test(PHK, basic) Init() snes.cpu->_registers.pbr = 0xFF; snes.cpu->_registers.s = 0x02; - snes.cpu->PHK(); + snes.cpu->PHK(0x0); cr_assert_eq(snes.wram->_data[2], 0xFF, "The first value pushed to the stack should be 0xFF but it was %x", snes.wram->_data[2]); cr_assert_eq(snes.cpu->_registers.s, 0x1, "The Stack pointer should be equal to 0x1 but it was %x", snes.cpu->_registers.s); } @@ -141,7 +141,7 @@ Test(PHP, basic) Init() snes.cpu->_registers.p.flags = 0xFF; snes.cpu->_registers.s = 0x02; - snes.cpu->PHP(); + snes.cpu->PHP(0x0); cr_assert_eq(snes.wram->_data[2], 0xFF, "The first value pushed to the stack should be 0xFF but it was %x", snes.wram->_data[2]); cr_assert_eq(snes.cpu->_registers.s, 0x1, "The Stack pointer should be equal to 0x1 but it was %x", snes.cpu->_registers.s); } @@ -151,7 +151,7 @@ Test(PHX, basic) Init() snes.cpu->_registers.x = 0xABCD; snes.cpu->_registers.s = 0x02; - snes.cpu->PHX(); + snes.cpu->PHX(0x0); cr_assert_eq(snes.wram->_data[1], 0xCD, "The second value pushed to the stack should be 0xCD but it was %x", snes.wram->_data[1]); cr_assert_eq(snes.wram->_data[2], 0xAB, "The first value pushed to the stack should be 0xAB but it was %x", snes.wram->_data[2]); cr_assert_eq(snes.cpu->_registers.s, 0x0, "The Stack pointer should be equal to 0x0 but it was %x", snes.cpu->_registers.s); @@ -162,7 +162,7 @@ Test(PHY, basic) Init() snes.cpu->_registers.y = 0xABCD; snes.cpu->_registers.s = 0x02; - snes.cpu->PHY(); + snes.cpu->PHY(0x0); cr_assert_eq(snes.wram->_data[1], 0xCD, "The second value pushed to the stack should be 0xCD but it was %x", snes.wram->_data[1]); cr_assert_eq(snes.wram->_data[2], 0xAB, "The first value pushed to the stack should be 0xAB but it was %x", snes.wram->_data[2]); cr_assert_eq(snes.cpu->_registers.s, 0x0, "The Stack pointer should be equal to 0x0 but it was %x", snes.cpu->_registers.s); @@ -174,7 +174,7 @@ Test(PLA, basic) snes.wram->_data[1] = 0xCD; snes.wram->_data[2] = 0x7B; snes.cpu->_registers.s = 0x00; - snes.cpu->PLA(); + snes.cpu->PLA(0x0); auto data = snes.cpu->_registers.a; cr_assert_eq(data, 0x7BCD, "The accumulator should be 0x7BCD but it was %x", data); cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should not be set.", snes.cpu->_registers.p.z); @@ -188,7 +188,7 @@ Test(PLA, zero) snes.wram->_data[1] = 0x00; snes.wram->_data[2] = 0x00; snes.cpu->_registers.s = 0x00; - snes.cpu->PLA(); + snes.cpu->PLA(0x0); auto data = snes.cpu->_registers.a; cr_assert_eq(data, 0x0000, "The accumulator should be 0x0000 but it was %x", data); cr_assert_eq(snes.cpu->_registers.p.z, true, "The zero flag should be set.", snes.cpu->_registers.p.z); @@ -202,7 +202,7 @@ Test(PLA, negative) snes.wram->_data[1] = 0x00; snes.wram->_data[2] = 0xA0; snes.cpu->_registers.s = 0x00; - snes.cpu->PLA(); + snes.cpu->PLA(0x0); auto data = snes.cpu->_registers.a; cr_assert_eq(data, 0xA000, "The accumulator should be 0xA000 but it was %x", data); cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag not should be set.", snes.cpu->_registers.p.z); @@ -216,7 +216,7 @@ Test(PLX, basic) snes.wram->_data[1] = 0xCD; snes.wram->_data[2] = 0x7B; snes.cpu->_registers.s = 0x00; - snes.cpu->PLX(); + snes.cpu->PLX(0x0); auto data = snes.cpu->_registers.x; cr_assert_eq(data, 0x7BCD, "The X register should be 0x7BCD but it was %x", data); cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should not be set.", snes.cpu->_registers.p.z); @@ -230,7 +230,7 @@ Test(PLX, zero) snes.wram->_data[1] = 0x00; snes.wram->_data[2] = 0x00; snes.cpu->_registers.s = 0x00; - snes.cpu->PLX(); + snes.cpu->PLX(0x0); auto data = snes.cpu->_registers.x; cr_assert_eq(data, 0x0000, "The x register should be 0x0000 but it was %x", data); cr_assert_eq(snes.cpu->_registers.p.z, true, "The zero flag should be set.", snes.cpu->_registers.p.z); @@ -244,7 +244,7 @@ Test(PLX, negative) snes.wram->_data[1] = 0x00; snes.wram->_data[2] = 0xA0; snes.cpu->_registers.s = 0x00; - snes.cpu->PLX(); + snes.cpu->PLX(0x0); auto data = snes.cpu->_registers.x; cr_assert_eq(data, 0xA000, "The x register should be 0xA000 but it was %x", data); cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag not should be set.", snes.cpu->_registers.p.z); @@ -258,7 +258,7 @@ Test(PLY, basic) snes.wram->_data[1] = 0xCD; snes.wram->_data[2] = 0x7B; snes.cpu->_registers.s = 0x00; - snes.cpu->PLY(); + snes.cpu->PLY(0x0); auto data = snes.cpu->_registers.y; cr_assert_eq(data, 0x7BCD, "The Y register should be 0x7BCD but it was %x", data); cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should not be set.", snes.cpu->_registers.p.z); @@ -272,7 +272,7 @@ Test(PLY, zero) snes.wram->_data[1] = 0x00; snes.wram->_data[2] = 0x00; snes.cpu->_registers.s = 0x00; - snes.cpu->PLY(); + snes.cpu->PLY(0x0); auto data = snes.cpu->_registers.y; cr_assert_eq(data, 0x0000, "The y register should be 0x0000 but it was %x", data); cr_assert_eq(snes.cpu->_registers.p.z, true, "The zero flag should be set.", snes.cpu->_registers.p.z); @@ -286,7 +286,7 @@ Test(PLY, negative) snes.wram->_data[1] = 0x00; snes.wram->_data[2] = 0xA0; snes.cpu->_registers.s = 0x00; - snes.cpu->PLY(); + snes.cpu->PLY(0x0); auto data = snes.cpu->_registers.y; cr_assert_eq(data, 0xA000, "The y register should be 0xA000 but it was %x", data); cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag not should be set.", snes.cpu->_registers.p.z); @@ -300,7 +300,7 @@ Test(PLD, basic) snes.wram->_data[1] = 0xCD; snes.wram->_data[2] = 0x7B; snes.cpu->_registers.s = 0x00; - snes.cpu->PLD(); + snes.cpu->PLD(0x0); auto data = snes.cpu->_registers.d; cr_assert_eq(data, 0x7BCD, "The D register should be 0x7BCD but it was %x", data); cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should not be set.", snes.cpu->_registers.p.z); @@ -314,7 +314,7 @@ Test(PLD, zero) snes.wram->_data[1] = 0x00; snes.wram->_data[2] = 0x00; snes.cpu->_registers.s = 0x00; - snes.cpu->PLD(); + snes.cpu->PLD(0x0); auto data = snes.cpu->_registers.d; cr_assert_eq(data, 0x0000, "The d register should be 0x0000 but it was %x", data); cr_assert_eq(snes.cpu->_registers.p.z, true, "The zero flag should be set.", snes.cpu->_registers.p.z); @@ -328,7 +328,7 @@ Test(PLD, negative) snes.wram->_data[1] = 0x00; snes.wram->_data[2] = 0xA0; snes.cpu->_registers.s = 0x00; - snes.cpu->PLD(); + snes.cpu->PLD(0x0); auto data = snes.cpu->_registers.d; cr_assert_eq(data, 0xA000, "The D register should be 0xA000 but it was %x", data); cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag not should be set.", snes.cpu->_registers.p.z); @@ -341,7 +341,7 @@ Test(PLB, basic) Init() snes.wram->_data[1] = 0x7D; snes.cpu->_registers.s = 0x00; - snes.cpu->PLB(); + snes.cpu->PLB(0x0); auto data = snes.cpu->_registers.dbr; cr_assert_eq(data, 0x7D, "The DBR should be 0x7D but it was %x", data); cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should not be set.", snes.cpu->_registers.p.z); @@ -354,7 +354,7 @@ Test(PLB, zero) Init() snes.wram->_data[1] = 0x00; snes.cpu->_registers.s = 0x00; - snes.cpu->PLB(); + snes.cpu->PLB(0x0); auto data = snes.cpu->_registers.dbr; cr_assert_eq(data, 0x00, "The dbr should be 0x00 but it was %x", data); cr_assert_eq(snes.cpu->_registers.p.z, true, "The zero flag should be set.", snes.cpu->_registers.p.z); @@ -367,7 +367,7 @@ Test(PLB, negative) Init() snes.wram->_data[1] = 0xA0; snes.cpu->_registers.s = 0x00; - snes.cpu->PLB(); + snes.cpu->PLB(0x0); auto data = snes.cpu->_registers.dbr; cr_assert_eq(data, 0xA0, "The D register should be 0xA0 but it was %x", data); cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag not should be set.", snes.cpu->_registers.p.z); @@ -381,7 +381,7 @@ Test(PLP, basic) snes.wram->_data[1] = 0x7D; snes.cpu->_registers.s = 0x00; snes.cpu->_isEmulationMode = false; - snes.cpu->PLP(); + snes.cpu->PLP(0x0); auto data = snes.cpu->_registers.p.flags; cr_assert_eq(data, 0x7D, "The flags should be 0x7D but it was %x", data); cr_assert_eq(snes.cpu->_registers.s, 0x1, "The Stack pointer should be equal to 0x1 but it was %x", snes.cpu->_registers.s); @@ -393,7 +393,7 @@ Test(PLP, emulation) snes.wram->_data[1] = 0x00; snes.cpu->_registers.s = 0x00; snes.cpu->_isEmulationMode = true; - snes.cpu->PLP(); + snes.cpu->PLP(0x0); auto data = snes.cpu->_registers.p.flags; cr_assert_eq(data, 0b00110000, "The flags should be 0b00110000 but it was %x", data); cr_assert_eq(snes.cpu->_registers.s, 0x1, "The Stack pointer should be equal to 0x1 but it was %x", snes.cpu->_registers.s); @@ -403,7 +403,7 @@ Test(CLC, clear) { Init() snes.cpu->_registers.p.flags = 0xFF; - snes.cpu->CLC(); + snes.cpu->CLC(0x0); cr_assert_eq(snes.cpu->_registers.p.c, false, "The carry flag should not be set"); } @@ -411,7 +411,7 @@ Test(CLI, clear) { Init() snes.cpu->_registers.p.flags = 0xFF; - snes.cpu->CLI(); + snes.cpu->CLI(0x0); cr_assert_eq(snes.cpu->_registers.p.i, false, "The interrupt flag should not be set"); } @@ -419,7 +419,7 @@ Test(CLD, clear) { Init() snes.cpu->_registers.p.flags = 0xFF; - snes.cpu->CLD(); + snes.cpu->CLD(0x0); cr_assert_eq(snes.cpu->_registers.p.d, false, "The decimal flag should not be set"); } @@ -427,7 +427,7 @@ Test(CLV, clear) { Init() snes.cpu->_registers.p.flags = 0xFF; - snes.cpu->CLV(); + snes.cpu->CLV(0x0); cr_assert_eq(snes.cpu->_registers.p.v, false, "The overflow flag should not be set"); } @@ -435,7 +435,7 @@ Test(SEC, set) { Init() snes.cpu->_registers.p.flags = 0x00; - snes.cpu->SEC(); + snes.cpu->SEC(0x0); cr_assert_eq(snes.cpu->_registers.p.c, true, "The carry flag should be set"); } @@ -443,7 +443,7 @@ Test(SEI, set) { Init() snes.cpu->_registers.p.flags = 0x00; - snes.cpu->SEI(); + snes.cpu->SEI(0x0); cr_assert_eq(snes.cpu->_registers.p.i, true, "The interrupt disabled flag should be set"); } @@ -451,7 +451,7 @@ Test(SED, set) { Init() snes.cpu->_registers.p.flags = 0x00; - snes.cpu->SED(); + snes.cpu->SED(0x0); cr_assert_eq(snes.cpu->_registers.p.d, true, "The decimal flag should be set"); } @@ -463,7 +463,7 @@ Test(XCE, enableEmulation) snes.cpu->_registers.p.c = true; snes.cpu->_registers.xh = 0xFF; snes.cpu->_registers.yh = 0xFF; - snes.cpu->XCE(); + snes.cpu->XCE(0x0); cr_assert_eq(snes.cpu->_isEmulationMode, true, "The e flag should be set"); cr_assert_eq(snes.cpu->_registers.p.c, false, "The carry flag should not be set"); cr_assert_eq(snes.cpu->_registers.p.m, false, "The memory width flag should be untouched (unset)"); @@ -479,7 +479,7 @@ Test(XCE, enableNative) snes.cpu->_registers.p.flags = 0; snes.cpu->_registers.xh = 0xFF; snes.cpu->_registers.yh = 0xFF; - snes.cpu->XCE(); + snes.cpu->XCE(0x0); cr_assert_eq(snes.cpu->_isEmulationMode, false, "The e flag should be not set"); cr_assert_eq(snes.cpu->_registers.p.c, true, "The carry flag should be set"); cr_assert_eq(snes.cpu->_registers.p.m, true, "The memory width flag should be set"); @@ -495,7 +495,7 @@ Test(INX, basic) snes.cpu->_registers.p.flags = 0; snes.cpu->_registers.p.x_b = false; snes.cpu->_registers.x = 0xFF; - snes.cpu->INX(); + snes.cpu->INX(0x0); cr_assert_eq(snes.cpu->_registers.x, 0x0100, "The x register should be equal to 0x0100 but it was 0x%x.", snes.cpu->_registers.x); cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should not be set"); cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flag should not be set"); @@ -508,7 +508,7 @@ Test(INX, 8bits) snes.cpu->_registers.p.flags = 0; snes.cpu->_registers.p.x_b = true; snes.cpu->_registers.x = 0xFF; - snes.cpu->INX(); + snes.cpu->INX(0x0); cr_assert_eq(snes.cpu->_registers.x, 0x00, "The x register should be equal to 0x00 but it was 0x%x.", snes.cpu->_registers.x); cr_assert_eq(snes.cpu->_registers.p.z, true, "The zero flag should be set"); cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flag should not be set"); @@ -521,7 +521,7 @@ Test(INY, basic) snes.cpu->_registers.p.flags = 0; snes.cpu->_registers.p.x_b = false; snes.cpu->_registers.y = 0xFF; - snes.cpu->INY(); + snes.cpu->INY(0x0); cr_assert_eq(snes.cpu->_registers.y, 0x0100, "The y register should be equal to 0x0100 but it was 0x%x.", snes.cpu->_registers.y); cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should not be set"); cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flag should not be set"); @@ -534,7 +534,7 @@ Test(INY, 8bits) snes.cpu->_registers.p.flags = 0; snes.cpu->_registers.p.x_b = true; snes.cpu->_registers.y = 0xFF; - snes.cpu->INY(); + snes.cpu->INY(0x0); cr_assert_eq(snes.cpu->_registers.y, 0x00, "The y register should be equal to 0x00 but it was 0x%x.", snes.cpu->_registers.y); cr_assert_eq(snes.cpu->_registers.p.z, true, "The zero flag should be set"); cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flag should not be set"); diff --git a/tests/CPU/testInterupts.cpp b/tests/CPU/testInterupts.cpp index 9d26dd2..659af73 100644 --- a/tests/CPU/testInterupts.cpp +++ b/tests/CPU/testInterupts.cpp @@ -18,7 +18,7 @@ Test(CPU_emulated, BRK) snes.cpu->_registers.p.flags = 0xF1; snes.cpu->_registers.pc = 0x156u; snes.cpu->_registers.pbr = 0x15; - snes.cpu->BRK(); + snes.cpu->BRK(0x0); cr_assert_eq(snes.cpu->_registers.pc, 0x123u, "The program counter should be 0x123u but it was 0x%X", snes.cpu->_registers.pc); cr_assert_eq(snes.cpu->_registers.pbr, 0x15, "The PBR should be 0x15 but it was 0x%X", snes.cpu->_registers.pbr); cr_assert_eq(snes.cpu->_registers.p.d, false, "The decimal flag should not be set."); @@ -38,7 +38,7 @@ Test(CPU_native, BRK) snes.cpu->_registers.p.flags = 0xF1; snes.cpu->_registers.pc = 0x156u; snes.cpu->_registers.pbr = 0x15; - snes.cpu->BRK(); + snes.cpu->BRK(0x0); cr_assert_eq(snes.cpu->_registers.pc, 0x123u, "The program counter should be 0x123u but it was 0x%X", snes.cpu->_registers.pc); cr_assert_eq(snes.cpu->_registers.pbr, 0x0, "The PBR should be 0x0 but it was 0x%X", snes.cpu->_registers.pbr); cr_assert_eq(snes.cpu->_registers.p.d, false, "The decimal flag should not be set."); @@ -59,7 +59,7 @@ Test(CPU_emulated, COP) snes.cpu->_registers.p.flags = 0x0F; snes.cpu->_registers.pc = 0x156u; snes.cpu->_registers.pbr = 0x15; - snes.cpu->COP(); + snes.cpu->COP(0x0); cr_assert_eq(snes.cpu->_registers.pc, 0x123u, "The program counter should be 0x123u but it was 0x%X", snes.cpu->_registers.pc); cr_assert_eq(snes.cpu->_registers.pbr, 0x15, "The PBR should be 0x15 but it was 0x%X", snes.cpu->_registers.pbr); cr_assert_eq(snes.cpu->_registers.p.d, false, "The decimal flag should not be set."); @@ -79,7 +79,7 @@ Test(CPU_native, COP) snes.cpu->_registers.p.flags = 0xF1; snes.cpu->_registers.pc = 0x156u; snes.cpu->_registers.pbr = 0x15; - snes.cpu->COP(); + snes.cpu->COP(0x0); cr_assert_eq(snes.cpu->_registers.pc, 0x123u, "The program counter should be 0x123u but it was 0x%X", snes.cpu->_registers.pc); cr_assert_eq(snes.cpu->_registers.pbr, 0x0, "The PBR should be 0x0 but it was 0x%X", snes.cpu->_registers.pbr); cr_assert_eq(snes.cpu->_registers.p.d, false, "The decimal flag should not be set."); diff --git a/ui/cpu.ui b/ui/cpu.ui index a3b46d0..280e858 100644 --- a/ui/cpu.ui +++ b/ui/cpu.ui @@ -23,7 +23,7 @@ - + 1