From 1c91baf5e0d2f65227a8102e674004085b5d653a Mon Sep 17 00:00:00 2001 From: Melefo <42809472+Melefo@users.noreply.github.com> Date: Thu, 27 Feb 2020 11:35:20 +0100 Subject: [PATCH] Adding 8-bit Arithmetic Operations --- CMakeLists.txt | 2 + sources/APU/APU.cpp | 85 +++++++++++++++- sources/APU/APU.hpp | 13 +++ sources/APU/Instructions/8bitArithmetic.cpp | 81 +++++++++++++++ tests/APU/testAPUInstructions.cpp | 103 ++++++++++++++++++++ 5 files changed, 283 insertions(+), 1 deletion(-) create mode 100644 sources/APU/Instructions/8bitArithmetic.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index b04334c..e09d2d6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -86,6 +86,7 @@ add_executable(unit_tests sources/APU/Instructions/8bitIncrementDecrement.cpp sources/APU/Instructions/8bitLogical.cpp tests/APU/testOperand.cpp + sources/APU/Instructions/8bitArithmetic.cpp ) # include criterion & coverage @@ -183,6 +184,7 @@ add_executable(ComSquare sources/APU/Instructions/8bitShiftRotation.cpp sources/APU/Instructions/8bitIncrementDecrement.cpp sources/APU/Instructions/8bitLogical.cpp + sources/APU/Instructions/8bitArithmetic.cpp ) target_compile_definitions(ComSquare PUBLIC DEBUGGER_ENABLED) diff --git a/sources/APU/APU.cpp b/sources/APU/APU.cpp index d0d74e1..7103d74 100644 --- a/sources/APU/APU.cpp +++ b/sources/APU/APU.cpp @@ -2,7 +2,6 @@ // Created by Melefo on 27/01/2020. // -#include #include #include "APU.hpp" #include "../Exceptions/NotImplementedException.hpp" @@ -220,6 +219,8 @@ namespace ComSquare::APU 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: @@ -282,6 +283,8 @@ namespace ComSquare::APU 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: @@ -342,6 +345,8 @@ namespace ComSquare::APU return this->LSR(this->_getDirectAddrByX(), 5); case 0x5C: return this->LSR(this->_internalRegisters.a, 2, true); + case 0x5E: + return this->CMPreg(this->_internalRegisters.y, this->_getAbsoluteAddr(), 4); case 0x5F: return this->JMP(this->_getAbsoluteAddr()); case 0x60: @@ -352,6 +357,18 @@ namespace ComSquare::APU 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: @@ -372,12 +389,26 @@ namespace ComSquare::APU 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 0x7E: + return this->CMPreg(this->_internalRegisters.y, this->_getDirectAddr(), 3); case 0x7F: return this->RETI(); case 0x80: @@ -388,6 +419,18 @@ namespace ComSquare::APU 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: @@ -404,6 +447,18 @@ namespace ComSquare::APU 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: @@ -422,12 +477,26 @@ namespace ComSquare::APU 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 0xB0: @@ -438,6 +507,18 @@ namespace ComSquare::APU 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: @@ -454,6 +535,8 @@ namespace ComSquare::APU return this->SET1(this->_getDirectAddr(), 6); case 0xC3: return this->BBS(this->_getDirectAddr(), 6); + case 0xC8: + return this->CMPreg(this->_internalRegisters.x, this->_getImmediateData(), 2); case 0xCA: return this->MOV1(this->_getAbsoluteBit()); case 0xCE: diff --git a/sources/APU/APU.hpp b/sources/APU/APU.hpp index a598074..e5cbeed 100644 --- a/sources/APU/APU.hpp +++ b/sources/APU/APU.hpp @@ -339,6 +339,19 @@ namespace ComSquare::APU 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); public: explicit APU(std::shared_ptr &map); APU(const APU &) = default; 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/tests/APU/testAPUInstructions.cpp b/tests/APU/testAPUInstructions.cpp index f4e7303..cecc59f 100644 --- a/tests/APU/testAPUInstructions.cpp +++ b/tests/APU/testAPUInstructions.cpp @@ -1095,4 +1095,107 @@ Test(VIIILogical, EOR) 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) +{ + auto apu = Init().second.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) +{ + auto apu = Init().second.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) +{ + auto apu = Init().second.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) +{ + auto apu = Init().second.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) +{ + auto apu = Init().second.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) +{ + auto apu = Init().second.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); } \ No newline at end of file