diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3f9e69a..aefff04 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -4,6 +4,9 @@ on: push: branches: - master + pull_request: + branches: + - master jobs: Building: diff --git a/.github/workflows/buildwin.yml b/.github/workflows/buildwin.yml index 0957504..25632da 100644 --- a/.github/workflows/buildwin.yml +++ b/.github/workflows/buildwin.yml @@ -4,6 +4,9 @@ on: push: branches: - master + pull_request: + branches: + - master jobs: Building: diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 8f83b78..5de8a5e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -4,6 +4,12 @@ on: push: branches: - master + - CPU + - PPU + - APU + pull_request: + branches: + - master jobs: Testing: diff --git a/CMakeLists.txt b/CMakeLists.txt index 9589780..8c2d8c4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -75,11 +75,25 @@ add_executable(unit_tests sources/APU/Instructions/Stack.cpp sources/APU/Instructions/Subroutine.cpp sources/APU/Instructions/ProgramFlow.cpp + sources/APU/Operand.cpp + sources/APU/Instructions/DecimalCompensation.cpp + sources/APU/Instructions/MultiplicationDivision.cpp + sources/APU/Instructions/16bitArithmetic.cpp + sources/APU/Instructions/16bitDataTransmission.cpp + sources/APU/Instructions/8bitShiftRotation.cpp + sources/APU/Instructions/8bitIncrementDecrement.cpp + sources/APU/Instructions/8bitLogical.cpp + tests/APU/testOperand.cpp + sources/APU/Instructions/8bitArithmetic.cpp + sources/APU/Instructions/8bitDataTransmission.cpp + sources/APU/IPL/IPL.hpp + sources/APU/IPL/IPL.cpp tests/CPU/Math/testSBC.cpp sources/CPU/Instructions/TransferRegisters.cpp tests/CPU/TransferRegisters.cpp sources/CPU/AddressingModes.cpp - sources/Models/Components.hpp) + sources/Models/Components.hpp +) # include criterion & coverage target_link_libraries(unit_tests criterion -lgcov) @@ -169,6 +183,18 @@ add_executable(ComSquare sources/APU/Instructions/Stack.cpp sources/APU/Instructions/Subroutine.cpp sources/APU/Instructions/ProgramFlow.cpp + sources/APU/Operand.cpp + sources/APU/Instructions/DecimalCompensation.cpp + sources/APU/Instructions/MultiplicationDivision.cpp + sources/APU/Instructions/16bitArithmetic.cpp + sources/APU/Instructions/16bitDataTransmission.cpp + sources/APU/Instructions/8bitShiftRotation.cpp + sources/APU/Instructions/8bitIncrementDecrement.cpp + sources/APU/Instructions/8bitLogical.cpp + sources/APU/Instructions/8bitArithmetic.cpp + sources/APU/Instructions/8bitDataTransmission.cpp + sources/APU/IPL/IPL.hpp + sources/APU/IPL/IPL.cpp sources/CPU/Instructions/TransferRegisters.cpp sources/CPU/AddressingModes.cpp sources/Debugger/MemoryBusDebug.cpp diff --git a/sources/APU/APU.cpp b/sources/APU/APU.cpp index c12542c..c2cacd9 100644 --- a/sources/APU/APU.cpp +++ b/sources/APU/APU.cpp @@ -2,12 +2,12 @@ // Created by Melefo on 27/01/2020. // -#include #include #include "APU.hpp" #include "../Exceptions/NotImplementedException.hpp" #include "../Exceptions/InvalidAddress.hpp" #include "../Exceptions/InvalidOpcode.hpp" +#include "../Utility/Utility.hpp" namespace ComSquare::APU { @@ -66,7 +66,7 @@ namespace ComSquare::APU case 0x0200 ... 0xFFBF: return this->_map->Memory.read_internal(addr - 0x200); case 0xFFC0 ... 0xFFFF: - return this->_map->IPL.read_internal(addr - 0xFFC0); + return this->_map->IPL.read(addr - 0xFFC0); default: throw InvalidAddress("APU Registers read", addr); } @@ -123,7 +123,7 @@ namespace ComSquare::APU this->_map->Memory.write_internal(addr - 0x200, data); break; case 0xFFC0 ... 0xFFFF: - this->_map->IPL.write_internal(addr - 0xFFC0, data); + this->_map->IPL.write(addr - 0xFFC0, data); break; default: throw InvalidAddress("APU Registers write", addr); @@ -168,11 +168,21 @@ namespace ComSquare::APU void APU::reset() { + this->_registers.port0 = 0x00; + this->_registers.port1 = 0x00; + this->_registers.port2 = 0x00; + this->_registers.port3 = 0x00; + + this->_paddingCycles = 0; + this->_internalRegisters.ya = 0x0000; + this->_internalRegisters.x = 0x00; + this->_internalRegisters.sp = 0xEF; + this->_internalRegisters.pc = 0xFFC0; } int APU::_executeInstruction() { - uint8_t opcode = this->_internalRead(this->_internalRegisters.pc); + uint8_t opcode = this->_internalRead(this->_internalRegisters.pc++); switch (opcode) { case 0x00: @@ -181,8 +191,26 @@ namespace ComSquare::APU return this->TCALL(0); case 0x02: return this->SET1(this->_getDirectAddr(), 0); + case 0x03: + return this->BBS(this->_getDirectAddr(), 0); + case 0x04: + return this->ORacc(this->_getDirectAddr(), 3); + case 0x05: + return this->ORacc(this->_getAbsoluteAddr(), 4); + case 0x06: + return this->ORacc(this->_getIndexXAddr(), 3); + case 0x07: + return this->ORacc(this->_getAbsoluteDirectByXAddr(), 6); + case 0x08: + return this->ORacc(this->_getImmediateData(), 2); + case 0x09: + return this->OR(this->_getDirectAddr(), this->_getDirectAddr(), 6); case 0x0A: return this->OR1(this->_getAbsoluteBit()); + case 0x0B: + return this->ASL(this->_getDirectAddr(), 4); + case 0x0C: + return this->ASL(this->_getAbsoluteAddr(), 5); case 0x0D: return this->PUSH(this->_internalRegisters.psw); case 0x0E: @@ -195,16 +223,62 @@ namespace ComSquare::APU return this->TCALL(1); case 0x12: return this->CLR1(this->_getDirectAddr(), 0); + case 0x13: + return this->BBC(this->_getDirectAddr(), 0); + case 0x14: + return this->ORacc(this->_getDirectAddrByX(), 4); + case 0x15: + return this->ORacc(this->_getAbsoluteAddrByX(), 5); + case 0x16: + return this->ORacc(this->_getAbsoluteAddrByY(), 5); + case 0x17: + return this->ORacc(this->_getAbsoluteDirectAddrByY(), 6); + case 0x18: + return this->OR(this->_getDirectAddr(), this->_getImmediateData(), 5); + case 0x19: + return this->OR(this->_getIndexXAddr(), this->_getIndexYAddr(), 5); + case 0x1A: + return this->DECW(this->_getDirectAddr()); + case 0x1B: + return this->ASL(this->_getDirectAddrByX(), 5); + case 0x1C: + return this->ASL(this->_internalRegisters.a, 2, true); + case 0x1D: + return this->DECreg(this->_internalRegisters.x); + case 0x1E: + return this->CMPreg(this->_internalRegisters.x, this->_getAbsoluteAddr(), 4); + case 0x1F: + return this->JMP(this->_getAbsoluteByXAddr(), true); case 0x20: return this->CLRP(); case 0x21: return this->TCALL(2); case 0x22: return this->SET1(this->_getDirectAddr(), 1); + case 0x23: + return this->BBS(this->_getDirectAddr(), 1); + case 0x24: + return this->ANDacc(this->_getDirectAddr(), 3); + case 0x25: + return this->ANDacc(this->_getAbsoluteAddr(), 4); + case 0x26: + return this->ANDacc(this->_getIndexXAddr(), 3); + case 0x27: + return this->ANDacc(this->_getAbsoluteDirectByXAddr(), 6); + case 0x28: + return this->ANDacc(this->_getImmediateData(), 2); + case 0x29: + return this->AND(this->_getDirectAddr(), this->_getDirectAddr(), 6); case 0x2A: return this->OR1(this->_getAbsoluteBit(), true); + case 0x2B: + return this->ROL(this->_getDirectAddr(), 4); + case 0x2C: + return this->ROL(this->_getAbsoluteAddr(), 5); case 0x2D: return this->PUSH(this->_internalRegisters.a); + case 0x2E: + return this->CBNE(this->_getImmediateData()); case 0x2F: return this->BRA(); case 0x30: @@ -213,6 +287,30 @@ namespace ComSquare::APU return this->TCALL(3); case 0x32: return this->CLR1(this->_getDirectAddr(), 1); + case 0x33: + return this->BBC(this->_getDirectAddr(), 1); + case 0x34: + return this->ANDacc(this->_getDirectAddrByX(), 4); + case 0x35: + return this->ANDacc(this->_getAbsoluteAddrByX(), 5); + case 0x36: + return this->ANDacc(this->_getAbsoluteAddrByY(), 5); + case 0x37: + return this->ANDacc(this->_getAbsoluteDirectAddrByY(), 6); + case 0x38: + return this->AND(this->_getDirectAddr(), this->_getImmediateData(), 5); + case 0x39: + return this->AND(this->_getIndexXAddr(), this->_getIndexYAddr(), 5); + case 0x3A: + return this->INCW(this->_getDirectAddr()); + case 0x3B: + return this->ROL(this->_getAbsoluteAddrByX(), 5); + case 0x3C: + return this->ROL(this->_internalRegisters.a, 2, true); + case 0x3D: + return this->INCreg(this->_internalRegisters.x); + case 0x3E: + return this->CMPreg(this->_internalRegisters.x, this->_getDirectAddr(), 3); case 0x3F: return this->CALL(this->_getAbsoluteAddr()); case 0x40: @@ -221,8 +319,26 @@ namespace ComSquare::APU return this->TCALL(4); case 0x42: return this->SET1(this->_getDirectAddr(), 2); + case 0x43: + return this->BBS(this->_getDirectAddr(), 2); + case 0x44: + return this->EORacc(this->_getDirectAddr(), 3); + case 0x45: + return this->EORacc(this->_getAbsoluteAddr(), 4); + case 0x46: + return this->EORacc(this->_getIndexXAddr(), 3); + case 0x47: + return this->EORacc(this->_getAbsoluteDirectByXAddr(), 6); + case 0x48: + return this->EORacc(this->_getImmediateData(), 2); + case 0x49: + return this->EOR(this->_getDirectAddr(), this->_getDirectAddr(), 6); case 0x4A: return this->AND1(this->_getAbsoluteBit()); + case 0x4B: + return this->LSR(this->_getDirectAddr(), 4); + case 0x4C: + return this->LSR(this->_getAbsoluteAddr(), 5); case 0x4D: return this->PUSH(this->_internalRegisters.x); case 0x4E: @@ -235,16 +351,62 @@ namespace ComSquare::APU return this->TCALL(5); case 0x52: return this->CLR1(this->_getDirectAddr(), 2); + case 0x53: + return this->BBC(this->_getDirectAddr(), 2); + case 0x54: + return this->EORacc(this->_getDirectAddrByX(), 4); + case 0x55: + return this->EORacc(this->_getAbsoluteAddrByX(), 5); + case 0x56: + return this->EORacc(this->_getAbsoluteAddrByY(), 5); + case 0x57: + return this->EORacc(this->_getAbsoluteDirectAddrByY(), 6); + case 0x58: + return this->EOR(this->_getDirectAddr(), this->_getImmediateData(), 5); + case 0x59: + return this->EOR(this->_getIndexXAddr(), this->_getIndexYAddr(), 5); + case 0x5A: + return this->CMPW(this->_getDirectAddr()); + case 0x5B: + return this->LSR(this->_getDirectAddrByX(), 5); + case 0x5C: + return this->LSR(this->_internalRegisters.a, 2, true); + case 0x5D: + return this->MOV(this->_internalRegisters.a, this->_internalRegisters.x); + case 0x5E: + return this->CMPreg(this->_internalRegisters.y, this->_getAbsoluteAddr(), 4); + case 0x5F: + return this->JMP(this->_getAbsoluteAddr()); case 0x60: return this->CLRC(); case 0x61: return this->TCALL(6); case 0x62: return this->SET1(this->_getDirectAddr(), 3); + case 0x63: + return this->BBS(this->_getDirectAddr(), 3); + case 0x64: + return this->CMPreg(this->_internalRegisters.a, this->_getDirectAddr(), 3); + case 0x65: + return this->CMPreg(this->_internalRegisters.a, this->_getAbsoluteAddr(), 4); + case 0x66: + return this->CMPreg(this->_internalRegisters.a, this->_getIndexXAddr(), 3); + case 0x67: + return this->CMPreg(this->_internalRegisters.a, this->_getAbsoluteDirectByXAddr(), 6); + case 0x68: + return this->CMPreg(this->_internalRegisters.a, this->_getImmediateData(), 2); + case 0x69: + return this->CMP(this->_getDirectAddr(), this->_getDirectAddr(), 6); case 0x6A: return this->AND1(this->_getAbsoluteBit(), true); + case 0x6B: + return this->ROR(this->_getDirectAddr(), 4); + case 0x6C: + return this->ROR(this->_getAbsoluteAddr(), 5); case 0x6D: return this->PUSH(this->_internalRegisters.y); + case 0x6E: + return this->DBNZ(true); case 0x6F: return this->RET(); case 0x70: @@ -253,6 +415,30 @@ namespace ComSquare::APU return this->TCALL(7); case 0x72: return this->CLR1(this->_getDirectAddr(), 3); + case 0x73: + return this->BBC(this->_getDirectAddr(), 3); + case 0x74: + return this->CMPreg(this->_internalRegisters.a, this->_getDirectAddrByX(), 4); + case 0x75: + return this->CMPreg(this->_internalRegisters.a, this->_getAbsoluteAddrByX(), 5); + case 0x76: + return this->CMPreg(this->_internalRegisters.a, this->_getAbsoluteAddrByY(), 5); + case 0x77: + return this->CMPreg(this->_internalRegisters.a, this->_getAbsoluteDirectAddrByY(), 6); + case 0x78: + return this->CMP(this->_getDirectAddr(), this->_getImmediateData(), 5); + case 0x79: + return this->CMP(this->_getIndexXAddr(), this->_getIndexYAddr(), 5); + case 0x7A: + return this->ADDW(this->_getDirectAddr()); + case 0x7B: + return this->ROR(this->_getDirectAddrByX(), 5); + case 0x7C: + return this->ROR(this->_internalRegisters.a, 2, true); + case 0x7D: + return this->MOV(this->_internalRegisters.x, this->_internalRegisters.a); + case 0x7E: + return this->CMPreg(this->_internalRegisters.y, this->_getDirectAddr(), 3); case 0x7F: return this->RETI(); case 0x80: @@ -261,66 +447,254 @@ namespace ComSquare::APU return this->TCALL(8); case 0x82: return this->SET1(this->_getDirectAddr(), 4); + case 0x83: + return this->BBS(this->_getDirectAddr(), 4); + case 0x84: + return this->ADCacc(this->_getDirectAddr(), 3); + case 0x85: + return this->ADCacc(this->_getAbsoluteAddr(), 5); + case 0x86: + return this->ADCacc(this->_getIndexXAddr(), 3); + case 0x87: + return this->ADCacc(this->_getAbsoluteDirectByXAddr(), 6); + case 0x88: + return this->ADCacc(this->_getImmediateData(), 2); + case 0x89: + return this->ADC(this->_getDirectAddr(), this->_getDirectAddr(), 6); case 0x8A: return this->EOR1(this->_getAbsoluteBit()); + case 0x8B: + return this->DEC(this->_getDirectAddr(), 4); + case 0x8C: + return this->DEC(this->_getAbsoluteAddr(), 5); + case 0x8D: + return this->MOV(this->_getImmediateData(), this->_internalRegisters.y, 2); case 0x8E: return this->POP(this->_internalRegisters.psw); + case 0x8F: + return this->MOV(this->_getImmediateData(), this->_getDirectAddr()); case 0x90: return this->BCC(); case 0x91: return this->TCALL(9); case 0x92: return this->CLR1(this->_getDirectAddr(), 4); + case 0x93: + return this->BBC(this->_getDirectAddr(), 4); + case 0x94: + return this->ADCacc(this->_getDirectAddrByX(), 4); + case 0x95: + return this->ADCacc(this->_getAbsoluteAddrByX(), 5); + case 0x96: + return this->ADCacc(this->_getAbsoluteAddrByY(), 5); + case 0x97: + return this->ADCacc(this->_getAbsoluteDirectAddrByY(), 6); + case 0x98: + return this->ADC(this->_getDirectAddr(), this->_getImmediateData(), 5); + case 0x99: + return this->ADC(this->_getIndexXAddr(), this->_getIndexYAddr(), 3); + case 0x9A: + return this->SUBW(this->_getDirectAddr()); + case 0x9B: + return this->DEC(this->_getDirectAddrByX(), 5); + case 0x9C: + return this->DECreg(this->_internalRegisters.a); + case 0x9D: + return this->MOV(this->_internalRegisters.sp, this->_internalRegisters.x); + case 0x9E: + return this->DIV(); + case 0x9F: + return this->XCN(); case 0xA0: return this->EI(); case 0xA1: return this->TCALL(10); case 0xA2: return this->SET1(this->_getDirectAddr(), 5); + case 0xA3: + return this->BBS(this->_getDirectAddr(), 5); + case 0xA4: + return this->SBCacc(this->_getDirectAddr(), 3); + case 0xA5: + return this->SBCacc(this->_getAbsoluteAddr(), 4); + case 0xA6: + return this->SBCacc(this->_getIndexXAddr(), 3); + case 0xA7: + return this->SBCacc(this->_getAbsoluteDirectByXAddr(), 6); + case 0xA8: + return this->SBCacc(this->_getImmediateData(), 2); + case 0xA9: + return this->SBC(this->_getDirectAddr(), this->_getDirectAddr(), 6); case 0xAA: return this->MOV1(this->_getAbsoluteBit(), true); + case 0xAB: + return this->INC(this->_getDirectAddr(), 4); + case 0xAC: + return this->INC(this->_getAbsoluteAddr(), 5); + case 0xAD: + return this->CMPreg(this->_internalRegisters.y, this->_getImmediateData(), 2); case 0xAE: return this->POP(this->_internalRegisters.a); + case 0xAF: + return this->MOV(this->_internalRegisters.a, this->_getIndexXAddr(), 4, true); case 0xB0: return this->BCS(); case 0xB1: return this->TCALL(11); case 0xB2: return this->CLR1(this->_getDirectAddr(), 5); + case 0xB3: + return this->BBC(this->_getDirectAddr(), 5); + case 0xB4: + return this->SBCacc(this->_getDirectAddrByX(), 4); + case 0xB5: + return this->SBCacc(this->_getAbsoluteAddrByX(), 5); + case 0xB6: + return this->SBCacc(this->_getAbsoluteAddrByY(), 5); + case 0xB7: + return this->SBCacc(this->_getAbsoluteDirectAddrByY(), 6); + case 0xB8: + return this->SBC(this->_getDirectAddr(), this->_getImmediateData(), 5); + case 0xB9: + return this->SBC(this->_getIndexXAddr(), this->_getIndexYAddr(), 5); + case 0xBA: + return this->MOVW(this->_getDirectAddr(), true); + case 0xBB: + return this->INC(this->_getDirectAddrByX(), 5); + case 0xBC: + return this->INCreg(this->_internalRegisters.a); + case 0xBD: + return this->MOV(this->_internalRegisters.x, this->_internalRegisters.sp, false); + case 0xBE: + return this->DAS(); + case 0xBF: + return this->MOV(this->_getIndexXAddr(), this->_internalRegisters.a, 4, true); case 0xC0: return this->DI(); case 0xC1: return this->TCALL(12); case 0xC2: return this->SET1(this->_getDirectAddr(), 6); + case 0xC3: + return this->BBS(this->_getDirectAddr(), 6); + case 0xC4: + return this->MOV(this->_internalRegisters.a, this->_getDirectAddr(), 4); + case 0xC5: + return this->MOV(this->_internalRegisters.a, this->_getAbsoluteAddr()); + case 0xC6: + return this->MOV(this->_internalRegisters.a, this->_getIndexXAddr(), 4); + case 0xC7: + return this->MOV(this->_internalRegisters.a, this->_getAbsoluteDirectByXAddr(), 7); + case 0xC8: + return this->CMPreg(this->_internalRegisters.x, this->_getImmediateData(), 2); + case 0xC9: + return this->MOV(this->_internalRegisters.x, this->_getAbsoluteAddr(), 5); case 0xCA: return this->MOV1(this->_getAbsoluteBit()); + case 0xCB: + return this->MOV(this->_internalRegisters.y, this->_getDirectAddr(), 4); + case 0xCC: + return this->MOV(this->_internalRegisters.y, this->_getAbsoluteAddr(), 5); + case 0xCD: + return this->MOV(this->_getImmediateData(), this->_internalRegisters.x, 2); case 0xCE: return this->POP(this->_internalRegisters.x); + case 0xCF: + return this->MUL(); case 0xD0: return this->BNE(); case 0xD1: return this->TCALL(13); case 0xD2: return this->CLR1(this->_getDirectAddr(), 6); + case 0xD3: + return this->BBC(this->_getDirectAddr(), 6); + case 0xD4: + return this->MOV(this->_internalRegisters.a, this->_getDirectAddrByX(), 5); + case 0xD5: + return this->MOV(this->_internalRegisters.a, this->_getAbsoluteAddrByX(), 6); + case 0xD6: + return this->MOV(this->_internalRegisters.a, this->_getAbsoluteAddrByY(), 6); + case 0xD7: + return this->MOV(this->_internalRegisters.a, this->_getAbsoluteDirectAddrByY(), 7); + case 0xD8: + return this->MOV(this->_internalRegisters.x, this->_getDirectAddr(), 4); + case 0xD9: + return this->MOV(this->_internalRegisters.x, this->_getDirectAddrByY(), 5); + case 0xDA: + return this->MOVW(this->_getDirectAddr()); + case 0xDB: + return this->MOV(this->_internalRegisters.y, this->_getDirectAddrByX(), 5); + case 0xDC: + return this->DECreg(this->_internalRegisters.y); + case 0xDD: + return this->MOV(this->_internalRegisters.y, this->_internalRegisters.a); + case 0xDE: + return this->CBNE(this->_getDirectAddrByX(), true); + case 0xDF: + return this->DAA(); + case 0xE0: + return this->CLRV(); case 0xE1: return this->TCALL(14); case 0xE2: return this->SET1(this->_getDirectAddr(), 7); + case 0xE3: + return this->BBS(this->_getDirectAddr(), 7); + case 0xE4: + return this->MOV(this->_getDirectAddr(), this->_internalRegisters.a, 3); + case 0xE5: + return this->MOV(this->_getAbsoluteAddrByX(), this->_internalRegisters.a, 5); + case 0xE6: + return this->MOV(this->_getIndexXAddr(), this->_internalRegisters.a, 3); + case 0xE7: + return this->MOV(this->_getAbsoluteDirectByXAddr(), this->_internalRegisters.a, 6); + case 0xE8: + return this->MOV(this->_getImmediateData(), this->_internalRegisters.a, 2); + case 0xE9: + return this->MOV(this->_getAbsoluteAddr(), this->_internalRegisters.x, 4); + case 0xEA: + return this->NOT1(this->_getAbsoluteBit()); + case 0xEB: + return this->MOV(this->_getDirectAddr(), this->_internalRegisters.y, 3); + case 0xEC: + return this->MOV(this->_getAbsoluteAddr(), this->_internalRegisters.y, 4); + case 0xED: + return this->NOTC(); case 0xEE: return this->POP(this->_internalRegisters.y); + case 0xEF: + return this->SLEEP(); case 0xF0: return BEQ(); case 0xF1: return this->TCALL(15); case 0xF2: return this->CLR1(this->_getDirectAddr(), 7); - case 0xEA: - return this->NOT1(this->_getAbsoluteBit()); - case 0xED: - return this->NOTC(); - case 0xEF: - return this->SLEEP(); + case 0xF3: + return this->BBC(this->_getDirectAddr(), 7); + case 0xF4: + return this->MOV(this->_getDirectAddrByX(), this->_internalRegisters.a, 4); + case 0xF5: + return this->MOV(this->_getAbsoluteAddrByX(), this->_internalRegisters.a, 5); + case 0xF6: + return this->MOV(this->_getAbsoluteAddrByY(), this->_internalRegisters.a, 5); + case 0xF7: + return this->MOV(this->_getAbsoluteDirectAddrByY(), this->_internalRegisters.a, 6); + case 0xF8: + return this->MOV(this->_getDirectAddr(), this->_internalRegisters.x, 3); + case 0xF9: + return this->MOV(this->_getDirectAddrByY(), this->_internalRegisters.x, 4); + case 0xFA: + return this->MOV(this->_getDirectAddr(), this->_getDirectAddr()); + case 0xFB: + return this->MOV(this->_getDirectAddrByX(), this->_internalRegisters.y, 4); + case 0xFC: + return this->INCreg(this->_internalRegisters.y); + case 0xFD: + return this->MOV(this->_internalRegisters.a, this->_internalRegisters.y); + case 0xFE: + return this->DBNZ(); case 0xFF: return this->STOP(); default: @@ -339,41 +713,16 @@ namespace ComSquare::APU this->_paddingCycles = total - cycles; } - uint24_t APU::_getDirectAddr() + void APU::_setNZflags(uint8_t value) { - uint24_t addr = this->_internalRead(this->_internalRegisters.pc++); - - if (this->_internalRegisters.p) - addr += 0x100; - return addr; - } - - uint24_t APU::_getAbsoluteAddr() - { - uint24_t addr1 = this->_internalRead(this->_internalRegisters.pc++); - uint24_t addr2 = this->_internalRead(this->_internalRegisters.pc++); - - return (addr2 << 8u) | addr1; - } - - std::pair APU::_getAbsoluteBit() - { - uint24_t addr1 = this->_internalRead(this->_internalRegisters.pc++); - uint24_t addr2 = this->_internalRead(this->_internalRegisters.pc++); - - uint24_t operandA = (addr2 << 8u) | addr1; - uint24_t operandB = operandA >> 13u; - - operandA = operandA & 0x1FFFu; - return std::make_pair(operandA, operandB); + this->_internalRegisters.n = value & 0x80u; + this->_internalRegisters.z = !value; } MemoryMap::MemoryMap() : Page0(0x00F0, Apu, "APU's Page 0"), Page1(0x0100, Apu, "APU's Page 1"), Memory(0xFDC0, Apu, "APU's Ram"), - IPL(0x0040, Apu, "IPL Rom") - { - - } -} + IPL(Apu, "IPL Rom") + { } +} \ No newline at end of file diff --git a/sources/APU/APU.hpp b/sources/APU/APU.hpp index 1d22ec3..5dbc43f 100644 --- a/sources/APU/APU.hpp +++ b/sources/APU/APU.hpp @@ -9,6 +9,7 @@ #include "DSP/DSP.hpp" #include "../Memory/AMemory.hpp" #include "../Ram/Ram.hpp" +#include "IPL/IPL.hpp" namespace ComSquare::APU { @@ -123,7 +124,7 @@ namespace ComSquare::APU //! @brief Any-use memory Ram::Ram Memory; //! @brief IPL ROM - Ram::Ram IPL; + IPL::IPL IPL; MemoryMap(); MemoryMap(const MemoryMap &) = delete; @@ -167,13 +168,36 @@ namespace ComSquare::APU //! @brief Keep the number of excess cycles executed to pad the next update unsigned int _paddingCycles = 0; + //! @brief Get value of the Pointer Counter + uint8_t _getImmediateData(); //! @brief Get direct page offset uint24_t _getDirectAddr(); + //! @brief Get Index X offset + uint24_t _getIndexXAddr(); + //! @brief Get Index Y offset + uint24_t _getIndexYAddr(); + //! @brief Get direct page offset and add to it the X Index Flag + uint24_t _getDirectAddrByX(); + //! @brief Get direct page offset and add to it the Y Index Flag + uint24_t _getDirectAddrByY(); //! @brief Get absolute direct page offset uint24_t _getAbsoluteAddr(); + //! @brief _get absolute direct page + X Index offset + uint24_t _getAbsoluteByXAddr(); + //! @brief Get absolute direct page offset and add to it the X Index Flag + uint24_t _getAbsoluteAddrByX(); + //! @brief Get absolute direct page offset and add to it the Y Index Flag + uint24_t _getAbsoluteAddrByY(); + //! @brief Get absolute offset of the direct page added to the X Index Flag + uint24_t _getAbsoluteDirectByXAddr(); + //! @brief Get absolute offset of the direct page and add the Y Index Flag to it + uint24_t _getAbsoluteDirectAddrByY(); //! @brief Get absolute offset and separate its bits std::pair _getAbsoluteBit(); + //! @brief Set Negative and Zero flags with value after an instruction + void _setNZflags(uint8_t value); + //! @brief Execute a single instruction. //! @return The number of cycles that the instruction took. virtual int _executeInstruction(); @@ -241,22 +265,107 @@ namespace ComSquare::APU //! @brief Branch Always, go to the specified location from the next instruction. int BRA(); - //! @brief Branch if Zero Flag is set + //! @brief Branch if Zero Flag is set. int BEQ(); - //! @brief Branch if Zero Flag is clear + //! @brief Branch if Zero Flag is clear. int BNE(); - //! @brief Branch if Carry Flag is set + //! @brief Branch if Carry Flag is set. int BCS(); - //! @brief Branch if Carry Flag is clear + //! @brief Branch if Carry Flag is clear. int BCC(); - //! @brief Branch if Overflow Flag is set + //! @brief Branch if Overflow Flag is set. int BVS(); - //! @brief Branch if Overflow Flag is set + //! @brief Branch if Overflow Flag is set. int BVC(); - //! @brief Branch if Negative Flag is set + //! @brief Branch if Negative Flag is set. int BMI(); - //! @brief Branch if Negative Flag is clear + //! @brief Branch if Negative Flag is clear. int BPL(); + //! @brief Branch if the specified is set in the address, go to the specified location from the next instruction. + int BBS(uint24_t addr, uint8_t bit); + //! @brief Branch if the specified is clear in the address, go to the specified location from the next instruction. + int BBC(uint24_t addr, uint8_t bit); + //! @brief Branch if the value at the specified address is not equal to the Accumulator Flag. + int CBNE(uint24_t addr, bool by_x = false); + //! @brief Decrement a value then branch to the specified location if the value is not zero. + int DBNZ(bool direct_addr = false); + //! @brief Jump to the specified location. + int JMP(uint24_t addr, bool by_x = false); + + //! @brief Decimal adjust A for addition. + int DAA(); + //! @brief Decimal adjust A for subtraction. + int DAS(); + + //! @brief Store the 16-bit value of Y * A into YA + int MUL(); + //! @brief Divide the 16-bit value YA by X, storing the quotient in A and the remainder in Y. + int DIV(); + + //! @brief Increment a word value. + int INCW(uint24_t addr); + //! @brief Decrement a word value. + int DECW(uint24_t addr); + //! @brief Add YA with a word value. + int ADDW(uint24_t addr); + //! @brief Subtract YA with a word value. + int SUBW(uint24_t addr); + //! @brief Compare YA with a word value. + int CMPW(uint24_t addr); + + //! @brief Sets a word value equal to another. + int MOVW(uint24_t addr, bool to_ya = false); + + //! @brief Arithmetic Shift Left. + int ASL(uint24_t operand, int cycles, bool accumulator = false); + //! @brief Logical Shift Right. + int LSR(uint24_t operand, int cycles, bool accumulator = false); + //! @brief Rotate Bits Left. + int ROL(uint24_t operand, int cycles, bool accumulator = false); + //! @brief Rotate Bits Right. + int ROR(uint24_t operand, int cycles, bool accumulator = false); + //! @brief Exchange Nibbles. + int XCN(); + + //! @brief Increment a value at an address. + int INC(uint24_t addr, int cycles); + //! @brief Increment a register. + int INCreg(uint8_t &value); + //! @brief Decrement a value at an address. + int DEC(uint24_t addr, int cycles); + //! @brief Decrement a register. + int DECreg(uint8_t &value); + + //! @brief Perform a bitwise AND. + int AND(uint24_t operand1, uint24_t operand2, int cycles); + //! @brief Perform a bitwise AND on the Accumulator flag. + int ANDacc(uint24_t addr, int cycles); + //! @brief Perform a bitwise OR. + int OR(uint24_t operand1, uint24_t operand2, int cycles); + //! @brief Perform a bitwise OR on the Accumulator flag. + int ORacc(uint24_t addr, int cycles); + //! @brief Perform an Exclusive OR. + int EOR(uint24_t operand1, uint24_t operand2, int cycles); + //! @brief Perform an Exclusive OR on the Accumulator flag. + int EORacc(uint24_t addr, int cycles); + + //! @brief Add operand1 with operand2 and carry. + int ADC(uint24_t operand1, uint24_t operand2, int cycles); + //! !@brief Add Accumulator Flag with value at address and carry. + int ADCacc(uint24_t addr, int cycles); + //! @brief Subtract operand1 with operand2 and carry. + int SBC(uint24_t operand1, uint24_t operand2, int cycles); + //! @brief Subtract Accumulator Flag with address and carry. + int SBCacc(uint24_t addr, int cycles); + //! @brief Compare the two values of the operands and set NZC flags. + int CMP(uint24_t operand1, uint24_t operand2, int cycles); + //! @brief Compare a Register Flag with the value of the operand and set NZC flags. + int CMPreg(uint8_t ®, uint24_t addr, int cycles); + + int MOV(uint8_t ®From, uint8_t ®To, bool setFlags = true); + int MOV(uint24_t memFrom, uint24_t memTo); + int MOV(uint8_t ®From, uint24_t memTo, int cycles, bool incrementX = false); + int MOV(uint24_t memFrom, uint8_t ®To, int cycles, bool incrementX = false); public: explicit APU(std::shared_ptr &map); APU(const APU &) = default; diff --git a/sources/APU/IPL/IPL.cpp b/sources/APU/IPL/IPL.cpp new file mode 100644 index 0000000..4bbf989 --- /dev/null +++ b/sources/APU/IPL/IPL.cpp @@ -0,0 +1,43 @@ +// +// Created by Melefo on 27/02/2020. +// + +#include "IPL.hpp" + +#include +#include "../../Exceptions/InvalidAddress.hpp" + +namespace ComSquare::APU::IPL +{ + IPL::IPL(Component type, std::string iplName) + : _iplType(type), + _iplName(std::move(iplName)) + { } + + IPL::~IPL() + { } + + uint8_t IPL::read(uint24_t addr) + { + if (addr >= this->_size) + throw InvalidAddress("IPL read", addr); + return this->_data[addr]; + } + + void IPL::write(uint24_t addr, uint8_t data) + { + if (addr >= this->_size) + throw InvalidAddress("IPL write", addr); + this->_data[addr] = data; + } + + std::string IPL::getName() + { + return this->_iplName; + } + + Component IPL::getComponent() + { + return this->_iplType; + } +} \ No newline at end of file diff --git a/sources/APU/IPL/IPL.hpp b/sources/APU/IPL/IPL.hpp new file mode 100644 index 0000000..38c3437 --- /dev/null +++ b/sources/APU/IPL/IPL.hpp @@ -0,0 +1,64 @@ +// +// Created by Melefo on 27/02/2020. +// + +#ifndef COMSQUARE_IPL_HPP +#define COMSQUARE_IPL_HPP + +#include "../../Memory/ARectangleMemory.hpp" + +namespace ComSquare::APU::IPL +{ + class IPL : public Memory::AMemory { + protected: + //! @brief The Rom. + std::array _data = { + 0xCD, 0xEF, 0xBD, 0xE8, 0x00, 0xC6, 0x1D, 0xD0, + 0xFC, 0x8F, 0xAA, 0xF4, 0x8F, 0xBB, 0xF5, 0x78, + 0xCC, 0xF4, 0xD0, 0xFB, 0x2F, 0x19, 0xEB, 0xF4, + 0xD0, 0xFC, 0x7E, 0xF4, 0xD0, 0x0B, 0xE4, 0xF5, + 0xCB, 0xF4, 0xD7, 0x00, 0xFC, 0xD0, 0xF3, 0xAB, + 0x01, 0x10, 0xEF, 0x7E, 0xF4, 0x10, 0xEB, 0xBA, + 0xF6, 0xDA, 0x00, 0xBA, 0xF4, 0xC4, 0xF4, 0xDD, + 0x5D, 0xD0, 0xDB, 0x1F, 0x00, 0x00, 0xC0, 0xFF + }; + //! @brief The size of the IPL rom (in bytes). + size_t _size = 64; + //! @brief An id identifying the type of memory this is (for the debugger) + Component _iplType; + //! @brief The name of this ram. + std::string _iplName; + public: + //! @brief Create the rom with its value. + explicit IPL(Component, std::string iplName); + + //! @brief The rom can't be copied. + IPL(const IPL &) = delete; + + //! @brief The rom can't be assigned. + IPL &operator=(IPL &) = delete; + + //! @brief Destructor that free the rom. + ~IPL(); + + //! @brief Read data from the component using the same method as the basic IMemory. + //! @param addr The global 24 bits address. This method is responsible of mapping to the component's read. + //! @throw InvalidAddress if the address is not mapped to the component. + //! @return Return the data at the address given as parameter. + uint8_t read(uint24_t addr) override; + + //! @brief Write data to this component using the same method as the basic IMemory. + //! @param addr The global 24 bits address. This method is responsible of mapping to the component's write. + //! @param data The new data to write. + //! @throw InvalidAddress if the address is not mapped to the component. + void write(uint24_t addr, uint8_t data) override; + + //! @brief Get the name of this accessor (used for debug purpose) + std::string getName() override; + + //! @brief Get the component of this accessor (used for debug purpose) + Component getComponent() override; + }; +} + +#endif //COMSQUARE_IPL_HPP \ No newline at end of file diff --git a/sources/APU/Instructions/16bitArithmetic.cpp b/sources/APU/Instructions/16bitArithmetic.cpp new file mode 100644 index 0000000..9ca5c61 --- /dev/null +++ b/sources/APU/Instructions/16bitArithmetic.cpp @@ -0,0 +1,77 @@ +// +// Created by Melefo on 25/02/2020. +// + +#include "../APU.hpp" + +namespace ComSquare::APU +{ + int APU::INCW(uint24_t addr) + { + uint24_t addr2 = addr + 1 + (this->_internalRegisters.p ? 0x0100 : 0); + uint16_t value = ((this->_internalRead(addr2) << 8u) | this->_internalRead(addr)) + 1u; + + this->_internalWrite(addr, value); + this->_internalWrite(addr2, value >> 8u); + this->_internalRegisters.n = value & 0x8000u; + this->_internalRegisters.z = !value; + return 6; + } + + int APU::DECW(uint24_t addr) + { + uint24_t addr2 = addr + 1 + (this->_internalRegisters.p ? 0x0100 : 0); + uint16_t value = ((this->_internalRead(addr2) << 8u) | this->_internalRead(addr)) - 1u; + + this->_internalWrite(addr, value); + this->_internalWrite(addr2, value >> 8u); + this->_internalRegisters.n = value & 0x8000u; + this->_internalRegisters.z = !value; + return 6; + } + + int APU::ADDW(uint24_t addr) + { + uint24_t addr2 = addr + 1 + (this->_internalRegisters.p ? 0x0100 : 0); + uint16_t value = ((this->_internalRead(addr2) << 8u) | this->_internalRead(addr)); + uint24_t result = this->_internalRegisters.ya + value; + + this->_internalRegisters.v = (~(this->_internalRegisters.ya ^ value) & (this->_internalRegisters.ya ^ result)) & 0x8000u; + this->_internalRegisters.c = result > 0xFFFFu; + this->_internalRegisters.h = ((this->_internalRegisters.ya & 0x0FFFu) + (value & 0x0FFFu)) > 0x0FFFu; + this->_internalRegisters.z = !result; + this->_internalRegisters.n = result & 0x8000u; + this->_internalRegisters.ya = result; + return 5; + } + + int APU::SUBW(uint24_t addr) + { + uint24_t addr2 = addr + 1 + (this->_internalRegisters.p ? 0x0100 : 0); + uint16_t value = ((this->_internalRead(addr2) << 8u) | this->_internalRead(addr)); + uint24_t result = this->_internalRegisters.ya - value; + uint16_t tmp = ((this->_internalRegisters.ya & 0x0F00u) - (value & 0x0F00u)) >> 8u; + + if ((this->_internalRegisters.ya & 0x00FFu) < (value & 0x00FFu)) + tmp--; + this->_internalRegisters.v = ((this->_internalRegisters.ya ^ value) & (this->_internalRegisters.ya ^ result)) & 0x8000u; + this->_internalRegisters.c = result <= 0xFFFFu; + this->_internalRegisters.h = tmp <= 0x000F; + this->_internalRegisters.z = !result; + this->_internalRegisters.n = result & 0x8000u; + this->_internalRegisters.ya = result; + return 5; + } + + int APU::CMPW(uint24_t addr) + { + uint24_t addr2 = addr + 1 + (this->_internalRegisters.p ? 0x0100 : 0); + uint16_t value = ((this->_internalRead(addr2) << 8u) | this->_internalRead(addr)); + uint24_t result = this->_internalRegisters.ya - value; + + this->_internalRegisters.z = !result; + this->_internalRegisters.n = result & 0x8000u; + this->_internalRegisters.c = this->_internalRegisters.ya >= value; + return 4; + } +} \ No newline at end of file diff --git a/sources/APU/Instructions/16bitDataTransmission.cpp b/sources/APU/Instructions/16bitDataTransmission.cpp new file mode 100644 index 0000000..cfa8009 --- /dev/null +++ b/sources/APU/Instructions/16bitDataTransmission.cpp @@ -0,0 +1,25 @@ +// +// Created by Melefo on 25/02/2020. +// + +#include "../APU.hpp" + +namespace ComSquare::APU +{ + int APU::MOVW(uint24_t addr, bool to_ya) + { + uint24_t addr2 = addr + 1 + (this->_internalRegisters.p ? 0x0100 : 0); + + if (to_ya) { + uint16_t value = ((this->_internalRead(addr2) << 8u) | this->_internalRead(addr)); + + this->_internalRegisters.ya = value; + this->_setNZflags(value); + } + else { + this->_internalWrite(addr, this->_internalRegisters.a); + this->_internalWrite(addr2, this->_internalRegisters.y); + } + return 5; + } +} \ No newline at end of file diff --git a/sources/APU/Instructions/8bitArithmetic.cpp b/sources/APU/Instructions/8bitArithmetic.cpp new file mode 100644 index 0000000..c09c58f --- /dev/null +++ b/sources/APU/Instructions/8bitArithmetic.cpp @@ -0,0 +1,81 @@ +// +// Created by Melefo on 27/02/2020. +// + +#include "../APU.hpp" + +namespace ComSquare::APU +{ + int APU::ADC(uint24_t operand1, uint24_t operand2, int cycles) + { + uint8_t data1 = this->_internalRead(operand1); + uint8_t data2 = this->_internalRead(operand2); + uint24_t result = data1 + data2 + this->_internalRegisters.c; + + this->_internalRegisters.v = (~(data1 ^ data2) & (data1 ^ result)) & 0x80u; + this->_internalRegisters.h = ((data1 & 0x0Fu) + (data2 & 0x0Fu) + this->_internalRegisters.c) > 0x0Fu; + this->_internalRegisters.c = result > 0xFF; + this->_setNZflags(result); + this->_internalWrite(operand1, result); + return cycles; + } + + int APU::ADCacc(uint24_t addr, int cycles) + { + uint8_t data = this->_internalRead(addr); + uint24_t result = this->_internalRegisters.a + data + this->_internalRegisters.c; + + this->_internalRegisters.v = (~(this->_internalRegisters.a ^ data) & (this->_internalRegisters.a ^ result)) & 0x80u; + this->_internalRegisters.h = ((this->_internalRegisters.a & 0x0Fu) + (data & 0x0Fu) + this->_internalRegisters.c) > 0x0Fu; + this->_internalRegisters.c = result > 0xFF; + this->_setNZflags(result); + this->_internalRegisters.a = result; + return cycles; + } + + int APU::SBC(uint24_t operand1, uint24_t operand2, int cycles) + { + uint8_t data1 = this->_internalRead(operand1); + uint8_t data2 = this->_internalRead(operand2); + uint24_t result = data1 - data2 - (this->_internalRegisters.c ^ 0x01u); + + this->_internalRegisters.v = ((data1 ^ data2) & (data1 ^ result)) & 0x80u; + this->_internalRegisters.h = ((result & 0x0Fu) - (data1 & 0x0Fu) + this->_internalRegisters.c) > 0x0Fu; + this->_internalRegisters.c = result <= 0xFF; + this->_setNZflags(result); + this->_internalWrite(operand1, result); + return cycles; + } + + int APU::SBCacc(uint24_t addr, int cycles) + { + uint8_t data = this->_internalRead(addr); + uint24_t result = this->_internalRegisters.a - data - (this->_internalRegisters.c ^ 0x01); + + this->_internalRegisters.v = ((this->_internalRegisters.a ^ data) & (this->_internalRegisters.a ^ result)) & 0x80u; + this->_internalRegisters.h = ((result & 0x0Fu) - (this->_internalRegisters.a & 0x0Fu) + this->_internalRegisters.c) > 0x0Fu; + this->_internalRegisters.c = result <= 0xFF; + this->_setNZflags(result); + this->_internalRegisters.a = result; + return cycles; + } + + int APU::CMP(uint24_t operand1, uint24_t operand2, int cycles) + { + uint8_t data1 = this->_internalRead(operand1); + uint8_t data2 = this->_internalRead(operand2); + + this->_internalRegisters.c = data1 >= data2; + this->_setNZflags(data1 - data2); + return cycles; + } + + int APU::CMPreg(uint8_t ®, uint24_t addr, int cycles) + { + uint8_t data = this->_internalRead(addr); + + this->_internalRegisters.c = reg >= data; + this->_setNZflags(reg - data); + return cycles; + } +} \ No newline at end of file diff --git a/sources/APU/Instructions/8bitDataTransmission.cpp b/sources/APU/Instructions/8bitDataTransmission.cpp new file mode 100644 index 0000000..f75e83d --- /dev/null +++ b/sources/APU/Instructions/8bitDataTransmission.cpp @@ -0,0 +1,40 @@ +// +// Created by Melefo on 27/02/2020. +// + +#include "../APU.hpp" +#include "../../Utility/Utility.hpp" + +namespace ComSquare::APU +{ + int APU::MOV(uint24_t memFrom, uint8_t ®To, int cycles, bool incrementX) + { + regTo = memFrom; + if (incrementX) + this->_internalRegisters.x++; + this->_setNZflags(regTo); + return cycles; + } + + int APU::MOV(uint8_t ®From, uint24_t memTo, int cycles, bool incrementX) + { + this->_internalWrite(memTo, regFrom); + if (incrementX) + this->_internalRegisters.x++; + return cycles; + } + + int APU::MOV(uint8_t ®From, uint8_t ®To, bool setFlags) + { + regTo = regFrom; + if (setFlags) + this->_setNZflags(regFrom); + return 2; + } + + int APU::MOV(uint24_t memFrom, uint24_t memTo) + { + this->_internalWrite(memTo, this->_internalRead(memFrom)); + return 5; + } +} \ No newline at end of file diff --git a/sources/APU/Instructions/8bitIncrementDecrement.cpp b/sources/APU/Instructions/8bitIncrementDecrement.cpp new file mode 100644 index 0000000..e4169a8 --- /dev/null +++ b/sources/APU/Instructions/8bitIncrementDecrement.cpp @@ -0,0 +1,40 @@ +// +// Created by Melefo on 26/02/2020. +// + +#include "../APU.hpp" + +namespace ComSquare::APU +{ + int APU::INC(uint24_t addr, int cycles) + { + uint8_t value = this->_internalRead(addr); + + this->_internalWrite(addr, ++value); + this->_setNZflags(value); + return cycles; + } + + int APU::INCreg(uint8_t &value) + { + value++; + this->_setNZflags(value); + return 2; + } + + int APU::DEC(uint24_t addr, int cycles) + { + uint8_t value = this->_internalRead(addr); + + this->_internalWrite(addr, --value); + this->_setNZflags(value); + return cycles; + } + + int APU::DECreg(uint8_t &value) + { + value--; + this->_setNZflags(value); + return 2; + } +} \ No newline at end of file diff --git a/sources/APU/Instructions/8bitLogical.cpp b/sources/APU/Instructions/8bitLogical.cpp new file mode 100644 index 0000000..ed4a9dd --- /dev/null +++ b/sources/APU/Instructions/8bitLogical.cpp @@ -0,0 +1,56 @@ +// +// Created by Melefo on 26/02/2020. +// + +#include "../APU.hpp" + +namespace ComSquare::APU +{ + int APU::AND(uint24_t operand1, uint24_t operand2, int cycles) + { + uint8_t data = this->_internalRead(operand1) & this->_internalRead(operand2); + + this->_internalWrite(operand1, data); + this->_setNZflags(data); + return cycles; + } + + int APU::ANDacc(uint24_t addr, int cycles) + { + this->_internalRegisters.a &= this->_internalRead(addr); + this->_setNZflags(this->_internalRegisters.a); + return cycles; + } + + int APU::OR(uint24_t operand1, uint24_t operand2, int cycles) + { + uint8_t data = this->_internalRead(operand1) | this->_internalRead(operand2); + + this->_internalWrite(operand1, data); + this->_setNZflags(data); + return cycles; + } + + int APU::ORacc(uint24_t addr, int cycles) + { + this->_internalRegisters.a |= this->_internalRead(addr); + this->_setNZflags(this->_internalRegisters.a); + return cycles; + } + + int APU::EOR(uint24_t operand1, uint24_t operand2, int cycles) + { + uint8_t data = this->_internalRead(operand1) ^ this->_internalRead(operand2); + + this->_internalWrite(operand1, data); + this->_setNZflags(data); + return cycles; + } + + int APU::EORacc(uint24_t addr, int cycles) + { + this->_internalRegisters.a ^= this->_internalRead(addr); + this->_setNZflags(this->_internalRegisters.a); + return cycles; + } +} \ No newline at end of file diff --git a/sources/APU/Instructions/8bitShiftRotation.cpp b/sources/APU/Instructions/8bitShiftRotation.cpp new file mode 100644 index 0000000..1aece45 --- /dev/null +++ b/sources/APU/Instructions/8bitShiftRotation.cpp @@ -0,0 +1,73 @@ +// +// Created by Melefo on 25/02/2020. +// + +#include "../APU.hpp" + +namespace ComSquare::APU +{ + int APU::ASL(uint24_t operand, int cycles, bool accumulator) + { + uint8_t value = accumulator ? operand : this->_internalRead(operand); + + this->_internalRegisters.c = value & 0x80u; + value <<= 1u; + if (accumulator) + this->_internalRegisters.a = value; + else + this->_internalWrite(operand, value); + this->_setNZflags(value); + return cycles; + } + + int APU::LSR(uint24_t operand, int cycles, bool accumulator) + { + uint8_t value = accumulator ? operand : this->_internalRead(operand); + + this->_internalRegisters.c = value & 0x01u; + value >>= 1u; + if (accumulator) + this->_internalRegisters.a = value; + else + this->_internalWrite(operand, value); + this->_internalRegisters.n = value & 0x01u; + this->_internalRegisters.z = !value; + return cycles; + } + + int APU::ROL(uint24_t operand, int cycles, bool accumulator) + { + uint8_t value = accumulator ? operand : this->_internalRead(operand); + uint8_t result = (value << 1u) + this->_internalRegisters.c; + + this->_internalRegisters.c = value & 0x80u; + if (accumulator) + this->_internalRegisters.a = result; + else + this->_internalWrite(operand, result); + this->_setNZflags(result); + return cycles; + } + + int APU::ROR(uint24_t operand, int cycles, bool accumulator) + { + uint8_t value = accumulator ? operand : this->_internalRead(operand); + uint8_t result = (value >> 1u) + this->_internalRegisters.c; + + this->_internalRegisters.c = value & 0x01u; + if (accumulator) + this->_internalRegisters.a = result; + else + this->_internalWrite(operand, result); + this->_internalRegisters.n = result & 0x01u; + this->_internalRegisters.z = !result; + return cycles; + } + + int APU::XCN() + { + this->_internalRegisters.a = (this->_internalRegisters.a >> 4u) | (this->_internalRegisters.a << 4u); + this->_setNZflags(this->_internalRegisters.a); + return 5; + } +} \ No newline at end of file diff --git a/sources/APU/Instructions/Bit.cpp b/sources/APU/Instructions/Bit.cpp index 4b8b8ba..74f172a 100644 --- a/sources/APU/Instructions/Bit.cpp +++ b/sources/APU/Instructions/Bit.cpp @@ -28,8 +28,7 @@ namespace ComSquare::APU uint8_t data = this->_internalRead(abs); this->_internalWrite(abs, data | this->_internalRegisters.a); - this->_internalRegisters.n = data & 0x80u; - this->_internalRegisters.z = !data; + this->_setNZflags(data); return 6; } @@ -38,8 +37,7 @@ namespace ComSquare::APU uint8_t data = this->_internalRead(abs); this->_internalWrite(abs, data & ~this->_internalRegisters.a); - this->_internalRegisters.n = data & 0x80u; - this->_internalRegisters.z = !data; + this->_setNZflags(data); return 6; } diff --git a/sources/APU/Instructions/DecimalCompensation.cpp b/sources/APU/Instructions/DecimalCompensation.cpp new file mode 100644 index 0000000..d93e562 --- /dev/null +++ b/sources/APU/Instructions/DecimalCompensation.cpp @@ -0,0 +1,34 @@ +// +// Created by Melefo on 25/02/2020. +// + +#include "../APU.hpp" + +namespace ComSquare::APU +{ + int APU::DAA() + { + if (this->_internalRegisters.c || this->_internalRegisters.a > 0x99) { + this->_internalRegisters.c = true; + this->_internalRegisters.a += 0x60; + } + if (this->_internalRegisters.h || (this->_internalRegisters.a & 0x0Fu) > 0x09) { + this->_internalRegisters.a += 0x06; + } + this->_setNZflags(this->_internalRegisters.a); + return 3; + } + + int APU::DAS() + { + if (!this->_internalRegisters.c || this->_internalRegisters.a > 0x99) { + this->_internalRegisters.c = false; + this->_internalRegisters.a -= 0x60; + } + if (!this->_internalRegisters.h || (this->_internalRegisters.a & 0x0Fu) > 0x09) { + this->_internalRegisters.a -= 0x06; + } + this->_setNZflags(this->_internalRegisters.a); + return 3; + } +} \ No newline at end of file diff --git a/sources/APU/Instructions/MultiplicationDivision.cpp b/sources/APU/Instructions/MultiplicationDivision.cpp new file mode 100644 index 0000000..b43a08c --- /dev/null +++ b/sources/APU/Instructions/MultiplicationDivision.cpp @@ -0,0 +1,34 @@ +// +// Created by Melefo on 25/02/2020. +// + +#include "../APU.hpp" + +namespace ComSquare::APU +{ + int APU::MUL() + { + this->_internalRegisters.ya = this->_internalRegisters.y * this->_internalRegisters.a; + this->_internalRegisters.n = this->_internalRegisters.a & 0x80u; + this->_internalRegisters.z = !this->_internalRegisters.y; + return 9; + } + + int APU::DIV() + { + uint16_t ya = this->_internalRegisters.ya; + + this->_internalRegisters.v = this->_internalRegisters.y >= this->_internalRegisters.x; + this->_internalRegisters.h = (this->_internalRegisters.y & 0x0Fu) >= (this->_internalRegisters.x & 0x0Fu); + if (this->_internalRegisters.y < (this->_internalRegisters.x << 1u)) { + this->_internalRegisters.a = ya / this->_internalRegisters.x; + this->_internalRegisters.y = ya % this->_internalRegisters.x; + } + else { + this->_internalRegisters.a = 0xFF - (ya - (this->_internalRegisters.x << 9u)) / (0x100 - this->_internalRegisters.x); + this->_internalRegisters.y = this->_internalRegisters.x + (ya - (this->_internalRegisters.x << 9u)) % (0x100 - this->_internalRegisters.x); + } + this->_setNZflags(this->_internalRegisters.a); + return 12; + } +} \ No newline at end of file diff --git a/sources/APU/Instructions/ProgramFlow.cpp b/sources/APU/Instructions/ProgramFlow.cpp index bb7cc65..e8b6f39 100644 --- a/sources/APU/Instructions/ProgramFlow.cpp +++ b/sources/APU/Instructions/ProgramFlow.cpp @@ -8,7 +8,7 @@ namespace ComSquare::APU { int APU::BRA() { - int8_t offset = this->_internalRead(this->_internalRegisters.pc++); + int8_t offset = this->_getImmediateData(); this->_internalRegisters.pc += offset; return 4; @@ -77,4 +77,61 @@ namespace ComSquare::APU this->BRA(); return 4; } + + int APU::BBS(uint24_t addr, uint8_t bit) + { + uint8_t data = this->_internalRead(addr); + + if (!(data & (1u << bit))) + return 5; + this->BRA(); + return 7; + } + + int APU::BBC(uint24_t addr, uint8_t bit) + { + uint8_t data = this->_internalRead(addr); + + if (data & (1u << bit)) + return 5; + this->BRA(); + return 7; + } + + int APU::CBNE(uint24_t addr, bool by_x) + { + uint8_t data = this->_internalRead(addr); + + if (this->_internalRegisters.a == data) + return 5 + by_x; + this->BRA(); + return 7 + by_x; + } + + int APU::DBNZ(bool direct_addr) + { + uint8_t data; + + if (direct_addr) { + uint24_t addr = this->_getDirectAddr(); + + data = this->_internalRead(addr); + this->_internalWrite(addr, --data); + } + else + data = --this->_internalRegisters.y; + if (!data) + return 4 + direct_addr; + this->BRA(); + return 6 + direct_addr; + } + + int APU::JMP(uint24_t addr, bool by_x) + { + this->_internalRegisters.pc = addr; + if (by_x) + return 6; + else + return 3; + } } \ No newline at end of file diff --git a/sources/APU/Instructions/Subroutine.cpp b/sources/APU/Instructions/Subroutine.cpp index 34eb031..d35a6b5 100644 --- a/sources/APU/Instructions/Subroutine.cpp +++ b/sources/APU/Instructions/Subroutine.cpp @@ -17,7 +17,7 @@ namespace ComSquare::APU int APU::PCALL() { - this->CALL(0xFF00u + this->_internalRead(this->_internalRegisters.pc++)); + this->CALL(0xFF00u + this->_getImmediateData()); return 6; } diff --git a/sources/APU/Operand.cpp b/sources/APU/Operand.cpp new file mode 100644 index 0000000..4242612 --- /dev/null +++ b/sources/APU/Operand.cpp @@ -0,0 +1,124 @@ +// +// Created by Melefo on 24/02/2020. +// + +#include "../Models/Int24.hpp" +#include "APU.hpp" + +namespace ComSquare::APU +{ + uint8_t APU::_getImmediateData() + { + return this->_internalRead(this->_internalRegisters.pc++); + } + + uint24_t APU::_getDirectAddr() + { + uint24_t addr = this->_getImmediateData(); + + if (this->_internalRegisters.p) + addr += 0x100; + return addr; + } + + uint24_t APU::_getIndexXAddr() + { + uint24_t addr = this->_internalRegisters.x; + + if (this->_internalRegisters.p) + addr += 0x100; + return addr; + } + + uint24_t APU::_getIndexYAddr() + { + uint24_t addr = this->_internalRegisters.y; + + if (this->_internalRegisters.p) + addr += 0x100; + return addr; + } + + uint24_t APU::_getDirectAddrByX() + { + uint24_t addr = this->_getDirectAddr(); + + addr += this->_internalRegisters.x; + return addr; + } + + uint24_t APU::_getDirectAddrByY() + { + uint24_t addr = this->_getDirectAddr(); + + addr += this->_internalRegisters.y; + return addr; + } + + uint24_t APU::_getAbsoluteAddr() + { + uint24_t addr1 = this->_getImmediateData(); + uint24_t addr2 = this->_getImmediateData(); + + return (addr2 << 8u) | addr1; + } + + uint24_t APU::_getAbsoluteByXAddr() + { + uint24_t addr1 = this->_getImmediateData() + this->_internalRegisters.x; + uint24_t addr2 = this->_getImmediateData() + this->_internalRegisters.x++; + + return (addr2 << 8u) | addr1; + } + + uint24_t APU::_getAbsoluteAddrByX() + { + uint24_t addr = _getAbsoluteAddr(); + + return addr + this->_internalRegisters.x; + } + + uint24_t APU::_getAbsoluteAddrByY() + { + uint24_t addr = _getAbsoluteAddr(); + + return addr + this->_internalRegisters.y; + } + + std::pair APU::_getAbsoluteBit() + { + uint24_t addr1 = this->_getImmediateData(); + uint24_t addr2 = this->_getImmediateData(); + + uint24_t operandA = (addr2 << 8u) | addr1; + uint24_t operandB = operandA >> 13u; + + operandA = operandA & 0x1FFFu; + return std::make_pair(operandA, operandB); + } + + uint24_t APU::_getAbsoluteDirectByXAddr() + { + uint24_t DirectIndexX = this->_getDirectAddr() + this->_internalRegisters.x; + + uint24_t low = this->_internalRead(DirectIndexX++); + if (this->_internalRegisters.p) + DirectIndexX += 0x100; + uint24_t high = this->_internalRead(DirectIndexX); + + return (high << 8u) | low; + } + + uint24_t APU::_getAbsoluteDirectAddrByY() + { + uint24_t DirectIndexX = this->_getDirectAddr(); + + uint24_t low = this->_internalRead(DirectIndexX); + DirectIndexX += 1; + if (this->_internalRegisters.p) + DirectIndexX += 0x100; + uint24_t high = this->_internalRead(DirectIndexX); + + return ((high << 8u) | low) + this->_internalRegisters.y; + } +} \ No newline at end of file diff --git a/sources/CPU/CPU.cpp b/sources/CPU/CPU.cpp index cfce0c8..afe5d53 100644 --- a/sources/CPU/CPU.cpp +++ b/sources/CPU/CPU.cpp @@ -411,7 +411,9 @@ namespace ComSquare::CPU uint16_t CPU::_pop16() { - return this->_bus->read(++this->_registers.s) + (this->_bus->read(++this->_registers.s) << 8u); + uint16_t value = this->_bus->read(++this->_registers.s); + value +=this->_bus->read(++this->_registers.s) << 8u; + return value; } std::string CPU::getName() diff --git a/sources/Debugger/APUDebug.cpp b/sources/Debugger/APUDebug.cpp index 6b34b5d..d0521a3 100644 --- a/sources/Debugger/APUDebug.cpp +++ b/sources/Debugger/APUDebug.cpp @@ -1,26 +1,28 @@ -// //! @brief Convert a basic CPU to a debugging CPU. - +// // Created by Melefo on 19/02/2020. // #include "APUDebug.hpp" #include "../Utility/Utility.hpp" +#include "../Exceptions/InvalidOpcode.hpp" using namespace ComSquare::APU; namespace ComSquare::Debugger { APUDebug::APUDebug(APU &apu, SNES &snes) : - APU(apu), - _window(new ClosableWindow(*this, &APUDebug::disableDebugger)), - _ui(), - _snes(snes) + APU(apu), + _window(new ClosableWindow(*this, &APUDebug::disableDebugger)), + _ui(), + _snes(snes) { this->_window->setContextMenuPolicy(Qt::NoContextMenu); this->_window->setAttribute(Qt::WA_QuitOnClose, false); this->_window->setAttribute(Qt::WA_DeleteOnClose); this->_ui.setupUi(this->_window); + QMainWindow::connect(this->_ui.resumeButton, &QPushButton::clicked, this, &APUDebug::pause); + QMainWindow::connect(this->_ui.stepButton, &QPushButton::clicked, this, &APUDebug::step); this->_window->show(); this->_updatePanel(); } @@ -473,6 +475,12 @@ namespace ComSquare::Debugger int APUDebug::_executeInstruction() { + if (this->_isPaused) + return 0xFF; + if (this->_isStepping) { + this->_isStepping = false; + this->_isPaused = true; + } this->_ui.logger->append(APUDebug::_getInstructionString().c_str()); this->_updatePanel(); return APU::_executeInstruction(); @@ -480,9 +488,32 @@ namespace ComSquare::Debugger void APUDebug::update(unsigned cycles) { - return APU::update(cycles); + try { + if (this->_isPaused) + return; + APU::update(cycles); + } catch (InvalidOpcode &e) { + this->pause(); + this->_ui.logger->append(e.what()); + } } + void APUDebug::step() + { + this->_isStepping = true; + this->_isPaused = false; + } + + void APUDebug::pause() + { + this->_isPaused = !this->_isPaused; + if (this->_isPaused) + this->_ui.resumeButton->setText("Resume"); + else + this->_ui.resumeButton->setText("Pause"); + } + + void APUDebug::disableDebugger() { this->_snes.disableAPUDebugging(); diff --git a/sources/Debugger/APUDebug.hpp b/sources/Debugger/APUDebug.hpp index 68a2f30..db7628f 100644 --- a/sources/Debugger/APUDebug.hpp +++ b/sources/Debugger/APUDebug.hpp @@ -11,7 +11,7 @@ namespace ComSquare::Debugger { - class APUDebug : public APU::APU { + class APUDebug : public APU::APU, public QObject { private: //! @brief The QT window for this debugger. ClosableWindow *_window; @@ -19,6 +19,11 @@ namespace ComSquare::Debugger //! @brief A widget that contain the whole UI. Ui::APUView _ui; + //! @brief If this is set to true, the execution of the APU will be paused. + bool _isPaused = true; + //! @brief If this is set to true, the APU will execute one instruction and pause itself. + bool _isStepping = false; + //! @brief A reference to the snes (to disable the debugger). SNES &_snes; @@ -33,8 +38,11 @@ namespace ComSquare::Debugger //! @brief return the mnemonic of the current instruction done. std::string _getInstructionString(); - public slots: + //! @brief Pause/Resume the APU. + void pause(); + //! @brief Step - Execute a single instruction. + void step(); //! @brief Called when the window is closed. Turn off the debugger and revert to a basic APU. void disableDebugger(); public: @@ -47,6 +55,7 @@ namespace ComSquare::Debugger //! @brief Override the apu's update to disable debugging. void update(unsigned cycles) override; + //! @brief Return true if the CPU is overloaded with debugging features. bool isDebugger() override; @@ -55,4 +64,4 @@ namespace ComSquare::Debugger }; } -#endif //COMSQUARE_APUDEBUG_HPP +#endif //COMSQUARE_APUDEBUG_HPP \ No newline at end of file diff --git a/sources/Debugger/CPUDebug.cpp b/sources/Debugger/CPUDebug.cpp index df2108a..80a4c07 100644 --- a/sources/Debugger/CPUDebug.cpp +++ b/sources/Debugger/CPUDebug.cpp @@ -14,7 +14,7 @@ namespace ComSquare::Debugger { CPUDebug::CPUDebug(CPU &basicCPU, SNES &snes) : CPU(basicCPU), - _window(new ClosableWindow(*this, &CPUDebug::disableDebugger)), + _window(new ClosableWindow(*this, &CPUDebug::disableDebugger)), _ui(), _snes(snes) { @@ -175,7 +175,7 @@ namespace ComSquare::Debugger std::string CPUDebug::_getAbsoluteValue(uint24_t pc) { std::stringstream ss; - ss << "$" << std::hex << (this->_bus->read(pc) + (this->_bus->read(pc + 1) << 8u), true); + ss << "$" << std::hex << (this->_bus->read(pc) + (this->_bus->read(pc + 1, true) << 8u)); return ss.str(); } diff --git a/sources/Debugger/HeaderViewer.cpp b/sources/Debugger/HeaderViewer.cpp index 2e77c88..c7a1551 100644 --- a/sources/Debugger/HeaderViewer.cpp +++ b/sources/Debugger/HeaderViewer.cpp @@ -9,7 +9,7 @@ namespace ComSquare::Debugger { HeaderViewer::HeaderViewer(ComSquare::SNES &snes) - : _window(new ClosableWindow(*this, &HeaderViewer::disableDebugger)), + : _window(new ClosableWindow(*this, &HeaderViewer::disableDebugger)), _snes(snes), _cartridge(*snes.cartridge), _ui() diff --git a/sources/Debugger/MemoryBusDebug.cpp b/sources/Debugger/MemoryBusDebug.cpp index 2d520d4..e1548e5 100644 --- a/sources/Debugger/MemoryBusDebug.cpp +++ b/sources/Debugger/MemoryBusDebug.cpp @@ -12,7 +12,7 @@ namespace ComSquare::Debugger { MemoryBusDebug::MemoryBusDebug(SNES &snes, const Memory::MemoryBus &bus) : MemoryBus(bus), - _window(new ClosableWindow(*this, &MemoryBusDebug::disableViewer)), + _window(new ClosableWindow(*this, &MemoryBusDebug::disableViewer)), _snes(snes), _ui(), _model(), diff --git a/sources/Debugger/MemoryViewer.cpp b/sources/Debugger/MemoryViewer.cpp index 1e59b53..f3880fc 100644 --- a/sources/Debugger/MemoryViewer.cpp +++ b/sources/Debugger/MemoryViewer.cpp @@ -8,7 +8,6 @@ #include #include "MemoryViewer.hpp" #include "../SNES.hpp" -#include "../Utility/Utility.hpp" #include "../Memory/MemoryShadow.hpp" #include "../Exceptions/InvalidAddress.hpp" @@ -65,7 +64,7 @@ void MemoryViewerModel::setMemory(std::shared_ptr memory) namespace ComSquare::Debugger { MemoryViewer::MemoryViewer(ComSquare::SNES &snes, Memory::MemoryBus &bus) : - _window(new ClosableWindow(*this, &MemoryViewer::disableViewer)), + _window(new ClosableWindow(*this, &MemoryViewer::disableViewer)), _snes(snes), _bus(bus), _ui(), diff --git a/sources/main.cpp b/sources/main.cpp index 8e5930b..195dedc 100644 --- a/sources/main.cpp +++ b/sources/main.cpp @@ -16,10 +16,10 @@ void usage(char *bin) std::cout << "ComSquare:" << std::endl << "\tUsage: " << bin << " rom_path [options]" << std::endl << "Options:" << std::endl - << "\t-c, --cpu: \tEnable the debugger of the CPU." << std::endl + << "\t-c, --cpu: \tEnable the debugger of the CPU." << std::endl << "\t-m, --memory: \tEnable the memory viewer panel." << std::endl << "\t-h, --header: \tShow the header of the cartridge." << std::endl - << "\t-b, --bus: \tShow the memory bus's log." << std::endl; + << "\t-b, --bus: \tShow the memory bus's log." << std::endl; } void parseArguments(int argc, char **argv, SNES &snes) @@ -28,13 +28,14 @@ void parseArguments(int argc, char **argv, SNES &snes) int option_index = 0; static struct option long_options[] = { {"cpu", no_argument, 0, 'c'}, + {"apu", no_argument, 0, 'a'}, {"memory", no_argument, 0, 'm'}, {"header", no_argument, 0, 'h'}, {"bus", no_argument, 0, 'b'}, {0, 0, 0, 0} }; - int c = getopt_long(argc, argv, "cmh", long_options, &option_index); + int c = getopt_long(argc, argv, "camhb", long_options, &option_index); if (c == -1) break; switch (c) { @@ -44,6 +45,9 @@ void parseArguments(int argc, char **argv, SNES &snes) case 'c': snes.enableCPUDebugging(); break; + case 'a': + snes.enableAPUDebugging(); + break; case 'm': snes.enableRamViewer(); break; diff --git a/tests/APU/testAPUInstructions.cpp b/tests/APU/testAPUInstructions.cpp index e632a3b..4b853eb 100644 --- a/tests/APU/testAPUInstructions.cpp +++ b/tests/APU/testAPUInstructions.cpp @@ -197,8 +197,6 @@ Test(Bit, TSET1) result = apu->TSET1(apu->_getAbsoluteAddr()); apu->_internalRegisters.pc -= 2; cr_assert_eq(apu->_internalRead(apu->_getAbsoluteAddr()), 0x7B); - cr_assert_eq(apu->_internalRegisters.n, false); - cr_assert_eq(apu->_internalRegisters.z, false); cr_assert_eq(result, 6); } @@ -217,8 +215,6 @@ Test(Bit, TCLR1) result = apu->TCLR1(apu->_getAbsoluteAddr()); apu->_internalRegisters.pc -= 2; cr_assert_eq(apu->_internalRead(apu->_getAbsoluteAddr()), 0x00); - cr_assert_eq(apu->_internalRegisters.n, true); - cr_assert_eq(apu->_internalRegisters.z, false); cr_assert_eq(result, 6); } @@ -410,6 +406,7 @@ Test(Subroutine, CALL) auto apu = snes.apu; int result = 0; + apu->_internalRegisters.pc = 0; apu->_internalWrite(apu->_getAbsoluteAddr(), 23); apu->_internalRegisters.pc -= 2; result = apu->CALL(apu->_getAbsoluteAddr()); @@ -497,11 +494,11 @@ Test(Subroutine, RETI) cr_assert_eq(apu->_internalRegisters.pcl, 0x56); } -///////////////////////////// -// // -// Subroutine Program Flow // -// // -///////////////////////////// +//////////////////////// +// // +// Program Flow tests // +// // +//////////////////////// Test(ProgramFlow, BRA) { @@ -646,4 +643,701 @@ Test(ProgramFlow, BPL) result = apu->BPL(); cr_assert_eq(result, 4); cr_assert_eq(apu->_internalRead(apu->_internalRegisters.pc), 101); +} + +Test(ProgramFlow, BBS) +{ + Init() + auto apu = snes.apu; + int result = 0; + + apu->_internalRegisters.pc = 0; + apu->_internalWrite(apu->_internalRegisters.pc, 23); + apu->_internalWrite(23, 0); + result = apu->BBS(apu->_getDirectAddr(), 2); + cr_assert_eq(result, 5); + apu->_internalRegisters.pc = 0; + apu->_internalWrite(apu->_internalRegisters.pc + 1, 10); + apu->_internalWrite(23, 255); + result = apu->BBS(apu->_getDirectAddr(), 2); + cr_assert_eq(result, 7); + cr_assert_eq(apu->_internalRegisters.pc, 12); +} + +Test(ProgramFlow, BBC) +{ + Init() + auto apu = snes.apu; + int result = 0; + + apu->_internalRegisters.pc = 0; + apu->_internalWrite(apu->_internalRegisters.pc, 10); + apu->_internalWrite( 10, 255); + apu->_internalWrite(apu->_internalRegisters.pc + 1, 23); + result = apu->BBC(apu->_getDirectAddr(), 2); + cr_assert_eq(result, 5); + apu->_internalRegisters.pc = 0; + apu->_internalWrite( 10, 0); + result = apu->BBC(apu->_getDirectAddr(), 2); + cr_assert_eq(result, 7); + cr_assert_eq(apu->_internalRegisters.pc, 25); +} + +Test(ProgramFlow, CBNE) +{ + Init() + auto apu = snes.apu; + int result = 0; + + apu->_internalRegisters.pc = 0; + apu->_internalRegisters.a = 4; + apu->_internalWrite(apu->_internalRegisters.pc, 10); + apu->_internalWrite( 10, 4); + apu->_internalWrite(apu->_internalRegisters.pc + 1, 23); + result = apu->CBNE(apu->_getDirectAddr()); + cr_assert_eq(result, 5); + apu->_internalRegisters.pc = 0; + apu->_internalWrite( 10, 0); + result = apu->CBNE(apu->_getDirectAddrByX(), true); + cr_assert_eq(result, 8); + cr_assert_eq(apu->_internalRegisters.pc, 25); +} + +Test(ProgramFlow, DBNZ) +{ + Init() + auto apu = snes.apu; + int result = 0; + + apu->_internalRegisters.pc = 0; + apu->_internalRegisters.y = 1; + result = apu->DBNZ(); + cr_assert_eq(result, 4); + apu->_internalWrite(apu->_internalRegisters.pc, 10); + apu->_internalWrite(apu->_internalRegisters.pc + 1, 23); + apu->_internalWrite( 10, 0); + result = apu->DBNZ(true); + cr_assert_eq(result, 7); + cr_assert_eq(apu->_internalRegisters.pc, 25); +} + +Test(ProgramFlow, JMP) +{ + Init() + auto apu = snes.apu; + int result = 0; + + apu->_internalRegisters.pc = 0x32; + apu->_internalWrite(0x32, 0b00001111); + apu->_internalWrite(0x33, 0b11110000); + result = apu->JMP(apu->_getAbsoluteAddr()); + cr_assert_eq(result, 3); + cr_assert_eq(apu->_internalRegisters.pc, 61455); + apu->_internalRegisters.pc = 0x32; + apu->_internalRegisters.x = 0b000000001; + result = apu->JMP(apu->_getAbsoluteByXAddr(), true); + cr_assert_eq(result, 6); + cr_assert_eq(apu->_internalRegisters.pc, 61712); +} + +//////////////////////////////// +// // +// Decimal Compensation tests // +// // +//////////////////////////////// + +Test(DecimalCompensation, DAA) +{ + Init() + auto apu = snes.apu; + int result = 0; + + apu->_internalRegisters.c = true; + apu->_internalRegisters.h = true; + apu->_internalRegisters.a = 0x1A; + result = apu->DAA(); + cr_assert_eq(result, 3); + cr_assert_eq(apu->_internalRegisters.a, 0x80); +} + +Test(DecimalCompensation, DAS) +{ + Init() + auto apu = snes.apu; + int result = 0; + + apu->_internalRegisters.c = false; + apu->_internalRegisters.h = false; + apu->_internalRegisters.a = 0xFF; + result = apu->DAS(); + cr_assert_eq(result, 3); + cr_assert_eq(apu->_internalRegisters.a, 0x99); +} + +/////////////////////////////////// +// // +// Multiplication Division tests // +// // +/////////////////////////////////// + +Test(MultiplicationDivision, MUL) +{ + Init() + auto apu = snes.apu; + int result = 0; + + apu->_internalRegisters.a = 10; + apu->_internalRegisters.y = 23; + result = apu->MUL(); + cr_assert_eq(result, 9); + cr_assert_eq(apu->_internalRegisters.ya, 230); +} + +Test(MultiplicationDivision, DIV) +{ + Init() + auto apu = snes.apu; + int result = 0; + + apu->_internalRegisters.ya = 235; + apu->_internalRegisters.x = 10; + result = apu->DIV(); + cr_assert_eq(result, 12); + cr_assert_eq(apu->_internalRegisters.y, 5); + cr_assert_eq(apu->_internalRegisters.a, 23); + apu->_internalRegisters.ya = 12345; + apu->_internalRegisters.x = 2; + result = apu->DIV(); + cr_assert_eq(apu->_internalRegisters.y, 147); + cr_assert_eq(apu->_internalRegisters.a, 211); +} + +////////////////////////////////// +// // +// (XVI)16-bit Arithmetic tests // +// // +////////////////////////////////// + +Test(XVIbitArithmetic, INCW) +{ + Init() + auto apu = snes.apu; + int result = 0; + + apu->_internalWrite(apu->_internalRegisters.pc, 0x55); + apu->_internalWrite(0x55, 0xFF); + apu->_internalWrite(0x55 + 1, 0x22); + result = apu->INCW(apu->_getDirectAddr()); + cr_assert_eq(result, 6); + cr_assert_eq(apu->_internalRead(0x55), 0x00); + cr_assert_eq(apu->_internalRead(0x55 + 1), 0x23); +} + +Test(XVIbitArithmetic, DECW) +{ + Init() + auto apu = snes.apu; + int result = 0; + + apu->_internalWrite(apu->_internalRegisters.pc, 0x55); + apu->_internalWrite(0x55, 0x00); + apu->_internalWrite(0x55 + 1, 0x23); + result = apu->DECW(apu->_getDirectAddr()); + cr_assert_eq(result, 6); + cr_assert_eq(apu->_internalRead(0x55), 0xFF); + cr_assert_eq(apu->_internalRead(0x55 + 1), 0x22); +} + +Test(XVIbitArithmetic, ADDW) +{ + Init() + auto apu = snes.apu; + int result = 0; + + apu->_internalRegisters.ya = 0x4321; + apu->_internalWrite(apu->_internalRegisters.pc, 0x55); + apu->_internalWrite(0x55, 0x11); + apu->_internalWrite(0x55 + 1, 0x22); + result = apu->ADDW(apu->_getDirectAddr()); + cr_assert_eq(result, 5); + cr_assert_eq(apu->_internalRegisters.ya, 0x6532); + cr_assert_eq(apu->_internalRegisters.v, false); + cr_assert_eq(apu->_internalRegisters.h, false); + cr_assert_eq(apu->_internalRegisters.c, false); +} + +Test(XVIbitArithmetic, SUBW) +{ + Init() + auto apu = snes.apu; + int result = 0; + + apu->_internalRegisters.ya = 0x4321; + apu->_internalWrite(apu->_internalRegisters.pc, 0x55); + apu->_internalWrite(0x55, 0x11); + apu->_internalWrite(0x55 + 1, 0x22); + result = apu->SUBW(apu->_getDirectAddr()); + cr_assert_eq(result, 5); + cr_assert_eq(apu->_internalRegisters.ya, 0x2110); + cr_assert_eq(apu->_internalRegisters.v, false); + cr_assert_eq(apu->_internalRegisters.h, true); + cr_assert_eq(apu->_internalRegisters.c, true); +} + +Test(XVIbitArithmetic, CMPW) +{ + Init() + auto apu = snes.apu; + int result = 0; + + apu->_internalRegisters.ya = 0x2211; + apu->_internalWrite(apu->_internalRegisters.pc, 0x55); + apu->_internalWrite(0x55, 0x11); + apu->_internalWrite(0x55 + 1, 0x22); + result = apu->CMPW(apu->_getDirectAddr()); + cr_assert_eq(result, 4); + cr_assert_eq(apu->_internalRegisters.c, true); +} + +///////////////////////////////////////// +// // +// (XVI)16-bit Data Transmission tests // +// // +///////////////////////////////////////// + +Test(XVIbitDataTransmission, MOVW) +{ + Init() + auto apu = snes.apu; + int result = 0; + + apu->_internalRegisters.pc = 0; + apu->_internalRegisters.ya = 0x2211; + apu->_internalWrite(apu->_internalRegisters.pc, 0x55); + result = apu->MOVW(apu->_getDirectAddr()); + cr_assert_eq(result, 5); + cr_assert_eq(apu->_internalRead(0x55), 0x11); + cr_assert_eq(apu->_internalRead(0x56), 0x22); + apu->_internalRegisters.ya = 0x0000; + apu->_internalRegisters.pc = 0; + apu->_internalWrite(0x55, 0x33); + apu->_internalWrite(0x55 + 1, 0x44); + apu->MOVW(apu->_getDirectAddr(), true); + cr_assert_eq(apu->_internalRegisters.ya, 0x4433); +} + +////////////////////////////////////// +// // +// (VIII)8-bit Shift Rotation tests // +// // +////////////////////////////////////// + +Test(VIIIbitShiftRotation, ASL) +{ + Init() + auto apu = snes.apu; + int result = 0; + + apu->_internalRegisters.a = 0x66; + result = apu->ASL(apu->_internalRegisters.a, 2, true); + cr_assert_eq(result, 2); + cr_assert_eq(apu->_internalRegisters.a, 0xCC); + cr_assert_eq(apu->_internalRegisters.c, false); + apu->_internalWrite(apu->_internalRegisters.pc, 0x55); + apu->_internalWrite(0x55, 0xDD); + result = apu->ASL(apu->_getDirectAddr(), 5); + cr_assert_eq(result, 5); + cr_assert_eq(apu->_internalRead(0x55), 0xBA); + cr_assert_eq(apu->_internalRegisters.c, true); +} + +Test(VIIIbitShiftRotation, LSR) +{ + Init() + auto apu = snes.apu; + int result = 0; + + apu->_internalRegisters.a = 0x66; + result = apu->LSR(apu->_internalRegisters.a, 2, true); + cr_assert_eq(result, 2); + cr_assert_eq(apu->_internalRegisters.a, 0x33); + cr_assert_eq(apu->_internalRegisters.c, false); + apu->_internalWrite(apu->_internalRegisters.pc, 0x55); + apu->_internalWrite(0x55, 0xDD); + result = apu->LSR(apu->_getDirectAddr(), 5); + cr_assert_eq(result , 5); + cr_assert_eq(apu->_internalRead(0x55), 0x6E); + cr_assert_eq(apu->_internalRegisters.c, true); +} + +Test(VIIIbitShiftRotation, ROL) +{ + Init() + auto apu = snes.apu; + int result = 0; + + apu->_internalRegisters.a = 0x66; + result = apu->ROL(apu->_internalRegisters.a, 2, true); + cr_assert_eq(result, 2); + cr_assert_eq(apu->_internalRegisters.a, 0xCC); + cr_assert_eq(apu->_internalRegisters.c, false); + apu->_internalWrite(apu->_internalRegisters.pc, 0x55); + apu->_internalWrite(0x55, 0xDD); + result = apu->ROL(apu->_getDirectAddr(), 5); + cr_assert_eq(result, 5); + cr_assert_eq(apu->_internalRead(0x55), 0xBA); + cr_assert_eq(apu->_internalRegisters.c, true); +} + +Test(VIIIbitShiftRotation, ROR) +{ + Init() + auto apu = snes.apu; + int result = 0; + + apu->_internalRegisters.a = 0x66; + result = apu->ROR(apu->_internalRegisters.a, 2, true); + cr_assert_eq(result, 2); + cr_assert_eq(apu->_internalRegisters.a, 0x33); + cr_assert_eq(apu->_internalRegisters.c, false); + apu->_internalWrite(apu->_internalRegisters.pc, 0x55); + apu->_internalWrite(0x55, 0xDD); + result = apu->ROR(apu->_getDirectAddr(), 5); + cr_assert_eq(result , 5); + cr_assert_eq(apu->_internalRead(0x55), 0x6E); + cr_assert_eq(apu->_internalRegisters.c, true); +} + +Test(VIIIShiftRotation, XCN) +{ + Init() + auto apu = snes.apu; + int result = 0; + + apu->_internalRegisters.a = 0b10101010; + result = apu->XCN(); + cr_assert_eq(result, 5); + cr_assert_eq(apu->_internalRegisters.a, 0xAA); +} + +/////////////////////////////////////////// +// // +// (VIII)8-bit Increment Decrement tests // +// // +/////////////////////////////////////////// + +Test(VIIIbitIncrementDecrement, INC) +{ + Init() + auto apu = snes.apu; + int result = 0; + + apu->_internalWrite(apu->_internalRegisters.pc, 0x55); + apu->_internalWrite(0x55, 0xDD); + result = apu->INC(apu->_getDirectAddr(), 4); + cr_assert_eq(result, 4); + cr_assert_eq(apu->_internalRead(0x55), 0xDE); +} + +Test(VIIIbitIncrementDecrement, INCreg) +{ + Init() + auto apu = snes.apu; + int result = 0; + + apu->_internalRegisters.a = 0x76; + result = apu->INCreg(apu->_internalRegisters.a); + cr_assert_eq(result, 2); + cr_assert_eq(apu->_internalRegisters.a, 0x77); +} + +Test(VIIIbitIncrementDecrement, DEC) +{ + Init() + auto apu = snes.apu; + int result = 0; + + apu->_internalWrite(apu->_internalRegisters.pc, 0x55); + apu->_internalWrite(0x55, 0xDD); + result = apu->DEC(apu->_getDirectAddr(), 4); + cr_assert_eq(result, 4); + cr_assert_eq(apu->_internalRead(0x55), 0xDC); +} + +Test(VIIIbitIncrementDecrement, DECreg) +{ + Init() + auto apu = snes.apu; + int result = 0; + + apu->_internalRegisters.a = 0x76; + result = apu->DECreg(apu->_internalRegisters.a); + cr_assert_eq(result, 2); + cr_assert_eq(apu->_internalRegisters.a, 0x75); +} + +/////////////////////////////// +// // +// (VIII)8-bit Logical tests // +// // +/////////////////////////////// + +Test(VIIILogical, ANDacc) +{ + Init() + auto apu = snes.apu; + int result = 0; + + apu->_internalRegisters.x = 4; + apu->_internalRegisters.a = 24; + apu->_internalWrite(4, 23); + result = apu->ANDacc(apu->_getIndexXAddr(), 3); + cr_assert_eq(result, 3); + cr_assert_eq(apu->_internalRegisters.a, 16); +} + +Test(VIIILogical, AND) +{ + Init() + auto apu = snes.apu; + int result = 0; + + apu->_internalRegisters.x = 4; + apu->_internalRegisters.y = 7; + apu->_internalWrite(4, 12); + apu->_internalWrite(7, 44); + result = apu->AND(apu->_getIndexXAddr(), apu->_getIndexYAddr(), 5); + cr_assert_eq(result, 5); + cr_assert_eq(apu->_internalRead(4), 12); +} + +Test(VIIILogical, ORacc) +{ + Init() + auto apu = snes.apu; + int result = 0; + + apu->_internalRegisters.x = 4; + apu->_internalRegisters.a = 24; + apu->_internalWrite(4, 23); + result = apu->ORacc(apu->_getIndexXAddr(), 3); + cr_assert_eq(result, 3); + cr_assert_eq(apu->_internalRegisters.a, 31); +} + +Test(VIIILogical, OR) +{ + Init() + auto apu = snes.apu; + int result = 0; + + apu->_internalRegisters.x = 4; + apu->_internalRegisters.y = 7; + apu->_internalWrite(4, 12); + apu->_internalWrite(7, 44); + result = apu->OR(apu->_getIndexXAddr(), apu->_getIndexYAddr(), 5); + cr_assert_eq(result, 5); + cr_assert_eq(apu->_internalRead(4), 44); +} + +Test(VIIILogical, EORacc) +{ + Init() + auto apu = snes.apu; + int result = 0; + + apu->_internalRegisters.x = 4; + apu->_internalRegisters.a = 24; + apu->_internalWrite(4, 23); + result = apu->EORacc(apu->_getIndexXAddr(), 3); + cr_assert_eq(result, 3); + cr_assert_eq(apu->_internalRegisters.a, 15); +} + +Test(VIIILogical, EOR) +{ + Init() + auto apu = snes.apu; + int result = 0; + + apu->_internalRegisters.x = 4; + apu->_internalRegisters.y = 7; + apu->_internalWrite(4, 12); + apu->_internalWrite(7, 44); + result = apu->EOR(apu->_getIndexXAddr(), apu->_getIndexYAddr(), 5); + cr_assert_eq(result, 5); + cr_assert_eq(apu->_internalRead(4), 32); +} + +////////////////////////////////// +// // +// (VIII)8-bit Arithmetic tests // +// // +////////////////////////////////// + +Test(VIIIArithmetic, ADC) +{ + Init() + auto apu = snes.apu; + int result = 0; + + apu->_internalRegisters.x = 4; + apu->_internalRegisters.y = 7; + apu->_internalRegisters.c = true; + apu->_internalWrite(4, 53); + apu->_internalWrite(7, 76); + result = apu->ADC(apu->_getIndexXAddr(), apu->_getIndexYAddr(), 5); + cr_assert_eq(result, 5); + cr_assert_eq(apu->_internalRead(4), 130); + cr_assert_eq(apu->_internalRegisters.c, false); + cr_assert_eq(apu->_internalRegisters.h, true); + cr_assert_eq(apu->_internalRegisters.v, true); +} + +Test(VIIIArithmetic, ADCacc) +{ + Init() + auto apu = snes.apu; + int result = 0; + + apu->_internalRegisters.x = 4; + apu->_internalRegisters.a = 53; + apu->_internalRegisters.c = true; + apu->_internalWrite(4, 76); + result = apu->ADCacc(apu->_getIndexXAddr(), 3); + cr_assert_eq(result, 3); + cr_assert_eq(apu->_internalRegisters.a, 130); + cr_assert_eq(apu->_internalRegisters.c, false); + cr_assert_eq(apu->_internalRegisters.h, true); + cr_assert_eq(apu->_internalRegisters.v, true); +} + +Test(VIIIArithmetic, SBC) +{ + Init() + auto apu = snes.apu; + int result = 0; + + apu->_internalRegisters.x = 4; + apu->_internalRegisters.y = 7; + apu->_internalRegisters.c = true; + apu->_internalWrite(4, 67); + apu->_internalWrite(7, 45); + result = apu->SBC(apu->_getIndexXAddr(), apu->_getIndexYAddr(), 5); + cr_assert_eq(result, 5); + cr_assert_eq(apu->_internalRead(4), 22); + cr_assert_eq(apu->_internalRegisters.c, true); + cr_assert_eq(apu->_internalRegisters.h, false); + cr_assert_eq(apu->_internalRegisters.v, false); +} + +Test(VIIIArithmetic, SBCacc) +{ + Init() + auto apu = snes.apu; + int result = 0; + + apu->_internalRegisters.x = 4; + apu->_internalRegisters.a = 67; + apu->_internalRegisters.c = true; + apu->_internalWrite(4, 45); + result = apu->SBCacc(apu->_getIndexXAddr(), 3); + cr_assert_eq(result, 3); + cr_assert_eq(apu->_internalRegisters.a, 22); + cr_assert_eq(apu->_internalRegisters.c, true); + cr_assert_eq(apu->_internalRegisters.h, false); + cr_assert_eq(apu->_internalRegisters.v, false); +} + +Test(VIIIArithmetic, CMP) +{ + Init() + auto apu = snes.apu; + int result = 0; + + apu->_internalRegisters.x = 4; + apu->_internalRegisters.y = 7; + apu->_internalWrite(4, 67); + apu->_internalWrite(7, 45); + result = apu->CMP(apu->_getIndexXAddr(), apu->_getIndexYAddr(), 5); + cr_assert_eq(result, 5); + cr_assert_eq(apu->_internalRegisters.c, true); +} + +Test(VIIIArithmetic, CMPacc) +{ + Init() + auto apu = snes.apu; + int result = 0; + + apu->_internalRegisters.x = 4; + apu->_internalRegisters.a = 67; + apu->_internalWrite(4, 45); + result = apu->CMPreg(apu->_internalRegisters.a, apu->_getIndexXAddr(), 3); + cr_assert_eq(result, 3); + cr_assert_eq(apu->_internalRegisters.c, true); +} + +///////////////////////////////////////// +// // +// (VIII)8-bit Data Transmission tests // +// // +///////////////////////////////////////// + +Test(VIIIDataTransmission, MovRegToReg) +{ + Init() + auto apu = snes.apu; + int result = 0; + + apu->_internalRegisters.a = 23; + apu->_internalRegisters.x = 45; + result = apu->MOV(apu->_internalRegisters.x, apu->_internalRegisters.a); + cr_assert_eq(result, 2); + cr_assert_eq(apu->_internalRegisters.a, 45); +} + +Test(VIIIDataTransmission, MovMemToMem) +{ + Init() + auto apu = snes.apu; + int result = 0; + + apu->_internalRegisters.pc = 0x23; + apu->_internalWrite(0x23, 0x56); + apu->_internalWrite(0x24, 0x33); + apu->_internalWrite(0x56, 99); + apu->_internalWrite(0x33, 66); + result = apu->MOV(apu->_getDirectAddr(), apu->_getDirectAddr()); + cr_assert_eq(result, 5); + cr_assert_eq(apu->_internalRead(0x56), 66); +} + +Test(VIIIDataTransmission, MovRegToMem) +{ + Init() + auto apu = snes.apu; + int result = 0; + + apu->_internalRegisters.x = 0x23; + apu->_internalRegisters.a = 0x44; + apu->_internalWrite(0x23, 0x56); + result = apu->MOV(apu->_internalRegisters.a, apu->_getIndexXAddr(), 4, true); + cr_assert_eq(result, 4); + cr_assert_eq(apu->_internalRead(0x23), 0x44); + cr_assert_eq(apu->_internalRegisters.x, 0x24); +} + +Test(VIIIDataTransmission, MovMemToReg) +{ + Init() + auto apu = snes.apu; + int result = 0; + + apu->_internalRegisters.x = 0x23; + apu->_internalRegisters.a = 0x44; + result = apu->MOV(apu->_getIndexXAddr(), apu->_internalRegisters.a, 4, true); + cr_assert_eq(result, 4); + cr_assert_eq(apu->_internalRegisters.x, 0x24); + cr_assert_eq(apu->_internalRegisters.a, 0x23); } \ No newline at end of file diff --git a/tests/APU/testOperand.cpp b/tests/APU/testOperand.cpp new file mode 100644 index 0000000..076c60c --- /dev/null +++ b/tests/APU/testOperand.cpp @@ -0,0 +1,164 @@ +// +// Created by Melefo on 26/02/2020. +// + +#include +#include "../tests.hpp" +#include "../../sources/SNES.hpp" +#include "../../sources/APU/APU.hpp" +#include "../../sources/Exceptions/InvalidAddress.hpp" +#include "../../sources/Exceptions/InvalidOpcode.hpp" + +using namespace ComSquare; + +Test(apu_get, immediate) +{ + Init() + auto apu = snes.apu; + + apu->_internalRegisters.pc = 0x32; + apu->_internalWrite(0x32, 0x40); + cr_assert_eq(apu->_getImmediateData(), 0x40); +} + +Test(apu_get, direct) +{ + Init() + auto apu = snes.apu; + + apu->_internalRegisters.pc = 0x32; + apu->_internalRegisters.p = true; + apu->_internalWrite(0x32, 0x40); + cr_assert_eq(apu->_getDirectAddr(), 0x140); +} + +Test(apu_get, X) +{ + Init() + auto apu = snes.apu; + + apu->_internalRegisters.x = 0x32; + apu->_internalRegisters.p = true; + cr_assert_eq(apu->_getIndexXAddr(), 0x132); +} + +Test(apu_get, Y) +{ + Init() + auto apu = snes.apu; + + apu->_internalRegisters.y = 0x32; + apu->_internalRegisters.p = true; + cr_assert_eq(apu->_getIndexYAddr(), 0x132); +} + +Test(apu_get, directbyX) +{ + Init() + auto apu = snes.apu; + + apu->_internalRegisters.pc = 0x32; + apu->_internalRegisters.x = 0x03; + apu->_internalWrite(0x32, 0x40); + cr_assert_eq(apu->_getDirectAddrByX(), 0x43); +} + +Test(apu_get, directbyY) +{ + Init() + auto apu = snes.apu; + + apu->_internalRegisters.pc = 0x32; + apu->_internalRegisters.y = 0x05; + apu->_internalWrite(0x32, 0x40); + cr_assert_eq(apu->_getDirectAddrByY(), 0x45); +} + +Test(apu_get, absolute) +{ + Init() + auto apu = snes.apu; + + apu->_internalRegisters.pc = 0x32; + apu->_internalWrite(0x32, 0b00001111); + apu->_internalWrite(0x33, 0b11110000); + cr_assert_eq(apu->_getAbsoluteAddr(), 61455); +} + +Test(apu_get, absolutebyx) +{ + Init() + auto apu = snes.apu; + + apu->_internalRegisters.pc = 0x32; + apu->_internalRegisters.x = 10; + apu->_internalWrite(0x32, 0b00001111); + apu->_internalWrite(0x33, 0b11110000); + cr_assert_eq(apu->_getAbsoluteByXAddr(), 64025); +} + +Test(apu_get, absoluteaddrbyx) +{ + Init() + auto apu = snes.apu; + + apu->_internalRegisters.pc = 0x32; + apu->_internalRegisters.x = 10; + apu->_internalWrite(0x32, 0b00001111); + apu->_internalWrite(0x33, 0b11110000); + cr_assert_eq(apu->_getAbsoluteAddrByX(), 61465); +} + +Test(apu_get, absoluteaddrbyy) +{ + Init() + auto apu = snes.apu; + + apu->_internalRegisters.pc = 0x32; + apu->_internalRegisters.y = 10; + apu->_internalWrite(0x32, 0b00001111); + apu->_internalWrite(0x33, 0b11110000); + cr_assert_eq(apu->_getAbsoluteAddrByY(), 61465); +} + +Test(apu_get, absolutebit) +{ + Init() + auto apu = snes.apu; + std::pair result; + + apu->_internalRegisters.pc = 0x32; + apu->_internalWrite(0x32, 0b00001111); + apu->_internalWrite(0x33, 0b11110000); + result = apu->_getAbsoluteBit(); + cr_assert_eq(result.first, 4111); + cr_assert_eq(result.second, 7); +} + +Test(apu_get, absolutebyxdirect) +{ + Init() + auto apu = snes.apu; + + apu->_internalRegisters.pc = 0x32; + apu->_internalRegisters.p = true; + apu->_internalRegisters.x = 0x10; + apu->_internalWrite(0x32, 0x42); + apu->_internalWrite(0x152, 0b00001101); + apu->_internalWrite(0x253, 0b01101011); + cr_assert_eq(apu->_getAbsoluteDirectByXAddr(), 0b0110101100001101); +} + +Test(apu_get, absolutedirectbyy) +{ + Init() + auto apu = snes.apu; + + apu->_internalRegisters.pc = 0x32; + apu->_internalRegisters.p = true; + apu->_internalRegisters.y = 0x10; + apu->_internalWrite(0x32, 0x42); + apu->_internalWrite(0x142, 0b00001101); + apu->_internalWrite(0x243, 0b01101011); + cr_assert_eq(apu->_getAbsoluteDirectAddrByY(), 0b0110101100011101); +} \ No newline at end of file diff --git a/ui/apuView.ui b/ui/apuView.ui index 03d2908..71a242d 100644 --- a/ui/apuView.ui +++ b/ui/apuView.ui @@ -31,7 +31,7 @@ QTabWidget::Rounded - 2 + 0 @@ -329,6 +329,45 @@ CPU + + + + + + + Instructions History + + + Qt::AlignCenter + + + + + + + + + Resume + + + + :/resources/icons/play.svg:/resources/icons/play.svg + + + + + + + Step + + + + :/resources/icons/step.svg:/resources/icons/step.svg + + + + + @@ -393,19 +432,6 @@ - - - - Instructions History - - - Qt::AlignCenter - - - - - - @@ -543,7 +569,7 @@ - 7 + 0