diff --git a/sources/APU/APU.cpp b/sources/APU/APU.cpp index 95ebb8f..6dec86b 100644 --- a/sources/APU/APU.cpp +++ b/sources/APU/APU.cpp @@ -163,51 +163,69 @@ namespace ComSquare::APU case 0x00: return this->NOP(); case 0x02: - return this->SET1(_getDirectAddr(), 0); + return this->SET1(this->_getDirectAddr(), 0); + case 0x0A: + return this->OR1(this->_getAbsoluteBit()); case 0x0E: - return this->TSET1(_getAbsoluteAddr()); + return this->TSET1(this->_getAbsoluteAddr()); case 0x12: - return this->CLR1(_getDirectAddr(), 0); + return this->CLR1(this->_getDirectAddr(), 0); case 0x20: return this->CLRP(); case 0x22: - return this->SET1(_getDirectAddr(), 1); + return this->SET1(this->_getDirectAddr(), 1); + case 0x2A: + return this->OR1(this->_getAbsoluteBit(), true); case 0x32: - return this->CLR1(_getDirectAddr(), 1); + return this->CLR1(this->_getDirectAddr(), 1); case 0x40: return this->SETP(); case 0x42: - return this->SET1(_getDirectAddr(), 2); + return this->SET1(this->_getDirectAddr(), 2); + case 0x4A: + return this->AND1(this->_getAbsoluteBit()); + case 0x4E: + return this->TCLR1(this->_getAbsoluteAddr()); case 0x52: - return this->CLR1(_getDirectAddr(), 2); + return this->CLR1(this->_getDirectAddr(), 2); case 0x60: return this->CLRC(); case 0x62: - return this->SET1(_getDirectAddr(), 3); + return this->SET1(this->_getDirectAddr(), 3); + case 0x6A: + return this->AND1(this->_getAbsoluteBit(), true); case 0x72: - return this->CLR1(_getDirectAddr(), 3); + return this->CLR1(this->_getDirectAddr(), 3); case 0x80: return this->SETC(); case 0x82: - return this->SET1(_getDirectAddr(), 4); + return this->SET1(this->_getDirectAddr(), 4); + case 0x8A: + return this->EOR1(this->_getAbsoluteBit()); case 0x92: - return this->CLR1(_getDirectAddr(), 4); + return this->CLR1(this->_getDirectAddr(), 4); case 0xA0: return this->EI(); case 0xA2: - return this->SET1(_getDirectAddr(), 5); + return this->SET1(this->_getDirectAddr(), 5); + case 0xAA: + return this->MOV1(this->_getAbsoluteBit(), true); case 0xB2: - return this->CLR1(_getDirectAddr(), 5); + return this->CLR1(this->_getDirectAddr(), 5); case 0xC0: return this->DI(); case 0xC2: - return this->SET1(_getDirectAddr(), 6); + return this->SET1(this->_getDirectAddr(), 6); + case 0xC1: + return this->MOV1(this->_getAbsoluteBit()); case 0xD2: - return this->CLR1(_getDirectAddr(), 6); + return this->CLR1(this->_getDirectAddr(), 6); case 0xE2: - return this->SET1(_getDirectAddr(), 7); + return this->SET1(this->_getDirectAddr(), 7); case 0xF2: - return this->CLR1(_getDirectAddr(), 7); + return this->CLR1(this->_getDirectAddr(), 7); + case 0xEA: + return this->NOT1(this->_getAbsoluteBit()); case 0xED: return this->NOTC(); case 0xEF: @@ -247,6 +265,18 @@ namespace ComSquare::APU 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); + } + MemoryMap::MemoryMap() : Page0(0x00F0), Page1(0x0100), diff --git a/sources/APU/APU.hpp b/sources/APU/APU.hpp index 3d6d4f8..05ffc13 100644 --- a/sources/APU/APU.hpp +++ b/sources/APU/APU.hpp @@ -165,6 +165,8 @@ namespace ComSquare::APU uint24_t _getDirectAddr(); //! @brief Get absolute direct page offset uint24_t _getAbsoluteAddr(); + //! @brief Get absolute offset and separate its bits + std::pair _getAbsoluteBit(); //! @brief Execute a single instruction. //! @return The number of cycles that the instruction took. @@ -200,6 +202,18 @@ namespace ComSquare::APU int CLR1(uint24_t dp, uint8_t bit); //! @brief test set 1-bit instruction, Test and set bits with absolute address int TSET1(uint24_t abs); + //! @brief test clear 1-bit instruction, Test and clear bits with absolute address + int TCLR1(uint24_t abs); + //! @brief Performs a bitwise AND on the value or inverse value of the specified bit with Carry flag and stores the result in the Carry flag. + int AND1(std::pair operand, bool invert = false); + //! @brief Performs a bitwise OR on the value or inverse value of the specified bit with Carry flag and stores the result in the Carry flag. + int OR1(std::pair operand, bool invert = false); + //! @brief Performs a exclusive OR on the value of the bit specified with Carry flag and stores the result in the Carry flag. + int EOR1(std::pair operand); + //! @brief Performs a logical NOT on the value of the specified bit and stores the result. + int NOT1(std::pair operand); + //! @brief Either moves the specified bit into carry or moves carry into the specified bit. + int MOV1(std::pair operand, bool to_carry = false); public: explicit APU(std::shared_ptr &map); APU(const APU &) = default; diff --git a/sources/APU/Instructions/Bit.cpp b/sources/APU/Instructions/Bit.cpp index 6051711..4b8b8ba 100644 --- a/sources/APU/Instructions/Bit.cpp +++ b/sources/APU/Instructions/Bit.cpp @@ -3,6 +3,7 @@ // #include "../APU.hpp" +#include "../../Utility/Utility.hpp" namespace ComSquare::APU { @@ -31,4 +32,61 @@ namespace ComSquare::APU this->_internalRegisters.z = !data; return 6; } + + int APU::TCLR1(uint24_t abs) + { + uint8_t data = this->_internalRead(abs); + + this->_internalWrite(abs, data & ~this->_internalRegisters.a); + this->_internalRegisters.n = data & 0x80u; + this->_internalRegisters.z = !data; + return 6; + } + + int APU::AND1(std::pair operand, bool invert) + { + if (invert) + this->_internalRegisters.c &= ~this->_internalRead(operand.first) & (1u << operand.second); + else + this->_internalRegisters.c &= this->_internalRead(operand.first) & (1u << operand.second); + return 4; + } + + int APU::OR1(std::pair operand, bool invert) + { + if (invert) + this->_internalRegisters.c |= ~this->_internalRead(operand.first) & (1u << operand.second); + else + this->_internalRegisters.c |= this->_internalRead(operand.first) & (1u << operand.second); + return 5; + } + + int APU::EOR1(std::pair operand) + { + this->_internalRegisters.c ^= this->_internalRead(operand.first) & (1u << operand.second); + return 5; + } + + int APU::NOT1(std::pair operand) + { + this->_internalWrite(operand.first, this->_internalRead(operand.first) ^ (1u << operand.second)); + return 5; + } + + int APU::MOV1(std::pair operand, bool to_carry) + { + if (to_carry) { + this->_internalRegisters.c = this->_internalRead(operand.first) & (1u << operand.second); + return 4; + } + else { + uint24_t mask = (1u << operand.second); + + if (this->_internalRegisters.c) + this->_internalWrite(operand.first, this->_internalRead(operand.first) | mask); + else + this->_internalWrite(operand.first, this->_internalRead(operand.first) & ~mask); + return 6; + } + } } \ No newline at end of file diff --git a/tests/APU/testAPU.cpp b/tests/APU/testAPU.cpp index 2187296..7357cc9 100644 --- a/tests/APU/testAPU.cpp +++ b/tests/APU/testAPU.cpp @@ -183,7 +183,7 @@ Test(executeInstruction, Valid) uint8_t result = 0; apu->_internalRegisters.pc = 0x00; - result = apu->executeInstruction(); + result = apu->_executeInstruction(); cr_assert_eq(result, 2); } @@ -192,7 +192,7 @@ Test(executeInstruction, Invalid) auto apu = Init().second.apu; apu->_internalRegisters.pc = 0xFFFF; - cr_assert_throw(apu->executeInstruction(), InvalidOpcode); + cr_assert_throw(apu->_executeInstruction(), InvalidOpcode); } /////////////////////// diff --git a/tests/APU/testAPUInstructions.cpp b/tests/APU/testAPUInstructions.cpp index 0aaaa2e..b3a762f 100644 --- a/tests/APU/testAPUInstructions.cpp +++ b/tests/APU/testAPUInstructions.cpp @@ -184,4 +184,159 @@ Test(Bit, TSET1) cr_assert_eq(apu->_internalRegisters.n, false); cr_assert_eq(apu->_internalRegisters.z, false); cr_assert_eq(result, 6); +} + +Test(Bit, TCLR1) +{ + auto apu = Init().second.apu; + int result = 0; + + apu->_internalRegisters.a = 0x80; + apu->_internalRegisters.pc = 0x32; + apu->_internalWrite(0x32, 0b00001111); + apu->_internalWrite(0x33, 0b11110000); + apu->_internalWrite(apu->_getAbsoluteAddr(), 0x80); + apu->_internalRegisters.pc -= 2; + 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); +} + +Test(Bit, AND1) +{ + auto apu = Init().second.apu; + int result = 0; + + apu->_internalRegisters.a = 42; + apu->_internalRegisters.pc = 0x32; + apu->_internalWrite(0x32, 0b00001111); + apu->_internalWrite(0x33, 0b11110000); + apu->_internalWrite(apu->_getAbsoluteAddr() & 0x1FFFu, 123); + apu->_internalRegisters.pc -= 2; + result = apu->AND1(apu->_getAbsoluteBit()); + apu->_internalRegisters.pc -= 2; + cr_assert_eq(apu->_internalRegisters.c, false); + cr_assert_eq(result, 4); +} + +Test(Bit, AND1_invert) +{ + auto apu = Init().second.apu; + int result = 0; + + apu->_internalRegisters.a = 42; + apu->_internalRegisters.pc = 0x32; + apu->_internalWrite(0x32, 0b00001111); + apu->_internalWrite(0x33, 0b11110000); + apu->_internalWrite(apu->_getAbsoluteAddr() & 0x1FFFu, 123); + apu->_internalRegisters.pc -= 2; + result = apu->AND1(apu->_getAbsoluteBit(), true); + apu->_internalRegisters.pc -= 2; + cr_assert_eq(apu->_internalRegisters.c, false); + cr_assert_eq(result, 4); +} + +Test(Bit, OR1) +{ + auto apu = Init().second.apu; + int result = 0; + + apu->_internalRegisters.a = 42; + apu->_internalRegisters.pc = 0x32; + apu->_internalWrite(0x32, 0b00001111); + apu->_internalWrite(0x33, 0b11110000); + apu->_internalWrite(apu->_getAbsoluteAddr() & 0x1FFFu, 123); + apu->_internalRegisters.pc -= 2; + result = apu->OR1(apu->_getAbsoluteBit()); + apu->_internalRegisters.pc -= 2; + cr_assert_eq(apu->_internalRegisters.c, false); + cr_assert_eq(result, 5); +} + +Test(Bit, OR1_invert) +{ + auto apu = Init().second.apu; + int result = 0; + + apu->_internalRegisters.a = 42; + apu->_internalRegisters.pc = 0x32; + apu->_internalWrite(0x32, 0b00001111); + apu->_internalWrite(0x33, 0b11110000); + apu->_internalWrite(apu->_getAbsoluteAddr() & 0x1FFFu, 123); + apu->_internalRegisters.pc -= 2; + result = apu->OR1(apu->_getAbsoluteBit(), true); + apu->_internalRegisters.pc -= 2; + cr_assert_eq(apu->_internalRegisters.c, true); + cr_assert_eq(result, 5); +} + +Test(Bit, EOR1) +{ + auto apu = Init().second.apu; + int result = 0; + + apu->_internalRegisters.a = 42; + apu->_internalRegisters.pc = 0x32; + apu->_internalWrite(0x32, 0b00001111); + apu->_internalWrite(0x33, 0b11110000); + apu->_internalWrite(apu->_getAbsoluteAddr() & 0x1FFFu, 123); + apu->_internalRegisters.pc -= 2; + result = apu->EOR1(apu->_getAbsoluteBit()); + apu->_internalRegisters.pc -= 2; + cr_assert_eq(apu->_internalRegisters.c, false); + cr_assert_eq(result, 5); +} + +Test(Bit, NOT1) +{ + auto apu = Init().second.apu; + int result = 0; + + apu->_internalRegisters.a = 42; + apu->_internalRegisters.pc = 0x32; + apu->_internalWrite(0x32, 0b00001111); + apu->_internalWrite(0x33, 0b11110000); + apu->_internalWrite(apu->_getAbsoluteAddr() & 0x1FFFu, 123); + apu->_internalRegisters.pc -= 2; + result = apu->NOT1(apu->_getAbsoluteBit()); + apu->_internalRegisters.pc -= 2; + cr_assert_eq(apu->_internalRegisters.c, false); + cr_assert_eq(result, 5); +} + +Test(Bit, MOV1) +{ + auto apu = Init().second.apu; + int result = 0; + + apu->_internalRegisters.a = 42; + apu->_internalRegisters.pc = 0x32; + apu->_internalWrite(0x32, 0b00001111); + apu->_internalWrite(0x33, 0b11110000); + apu->_internalWrite(apu->_getAbsoluteAddr() & 0x1FFFu, 123); + apu->_internalRegisters.pc -= 2; + result = apu->MOV1(apu->_getAbsoluteBit()); + apu->_internalRegisters.pc -= 2; + cr_assert_eq(apu->_internalRead(apu->_getAbsoluteAddr() & 0x1FFFu), 123); + cr_assert_eq(result, 6); +} + +Test(Bit, MOV1_carry) +{ + auto apu = Init().second.apu; + int result = 0; + + apu->_internalRegisters.a = 42; + apu->_internalRegisters.pc = 0x32; + apu->_internalWrite(0x32, 0b00001111); + apu->_internalWrite(0x33, 0b11110000); + apu->_internalWrite(apu->_getAbsoluteAddr() & 0x1FFFu, 123); + apu->_internalRegisters.pc -= 2; + result = apu->MOV1(apu->_getAbsoluteBit(), true); + apu->_internalRegisters.pc -= 2; + cr_assert_eq(apu->_internalRegisters.c, false); + cr_assert_eq(result, 4); } \ No newline at end of file