diff --git a/CMakeLists.txt b/CMakeLists.txt index e3da882..02e9f3d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -76,8 +76,12 @@ add_executable(unit_tests 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/DecimalCompensation.cpp + sources/APU/Instructions/MultiplicationDivision.cpp + sources/APU/Instructions/16bitArithmetic.cpp + sources/APU/Instructions/16bitDataTransmission.cpp + sources/APU/Instructions/8bitShiftRotation.cpp +) # include criterion & coverage target_link_libraries(unit_tests criterion -lgcov) @@ -165,7 +169,11 @@ add_executable(ComSquare 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/MultiplicationDivision.cpp + sources/APU/Instructions/16bitArithmetic.cpp + sources/APU/Instructions/16bitDataTransmission.cpp + sources/APU/Instructions/8bitShiftRotation.cpp +) target_compile_definitions(ComSquare PUBLIC DEBUGGER_ENABLED) diff --git a/sources/APU/APU.cpp b/sources/APU/APU.cpp index de68b60..04489be 100644 --- a/sources/APU/APU.cpp +++ b/sources/APU/APU.cpp @@ -170,6 +170,10 @@ namespace ComSquare::APU return this->BBS(this->_getDirectAddr(), 0); 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: @@ -186,6 +190,10 @@ namespace ComSquare::APU return this->BBC(this->_getDirectAddr(), 0); 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 0x1F: return this->JMP(this->_getAbsoluteAddrByX(), true); case 0x20: @@ -198,6 +206,10 @@ namespace ComSquare::APU return this->BBS(this->_getDirectAddr(), 1); 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: @@ -214,6 +226,10 @@ namespace ComSquare::APU return this->BBC(this->_getDirectAddr(), 1); 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 0x3F: return this->CALL(this->_getAbsoluteAddr()); case 0x40: @@ -226,6 +242,10 @@ namespace ComSquare::APU return this->BBS(this->_getDirectAddr(), 2); 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: @@ -242,6 +262,10 @@ namespace ComSquare::APU return this->BBC(this->_getDirectAddr(), 2); 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 0x5F: return this->JMP(this->_getAbsoluteAddr()); case 0x60: @@ -254,6 +278,10 @@ namespace ComSquare::APU return this->BBS(this->_getDirectAddr(), 3); 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: @@ -270,6 +298,10 @@ namespace ComSquare::APU return this->BBC(this->_getDirectAddr(), 3); 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 0x7F: return this->RETI(); case 0x80: @@ -296,6 +328,8 @@ namespace ComSquare::APU return this->SUBW(this->_getDirectAddr()); case 0x9E: return this->DIV(); + case 0x9F: + return this->XCN(); case 0xA0: return this->EI(); case 0xA1: @@ -395,7 +429,5 @@ namespace ComSquare::APU Page1(0x0100), Memory(0xFDC0), IPL(0x0040) - { - - } + { } } diff --git a/sources/APU/APU.hpp b/sources/APU/APU.hpp index d48b283..815b06f 100644 --- a/sources/APU/APU.hpp +++ b/sources/APU/APU.hpp @@ -289,8 +289,19 @@ namespace ComSquare::APU //! @brief Compare YA with a word value. int CMPW(uint24_t addr); - //! @brief Sets a word value equal to another + //! @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(); public: explicit APU(std::shared_ptr &map); APU(const APU &) = default; diff --git a/sources/APU/Instructions/8bitShiftRotation.cpp b/sources/APU/Instructions/8bitShiftRotation.cpp new file mode 100644 index 0000000..4faab34 --- /dev/null +++ b/sources/APU/Instructions/8bitShiftRotation.cpp @@ -0,0 +1,76 @@ +// +// 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->_internalRegisters.n = value & 0x80u; + this->_internalRegisters.z = !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->_internalRegisters.n = result & 0x80u; + this->_internalRegisters.z = !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->_internalRegisters.n = this->_internalRegisters.a & 0x80u; + this->_internalRegisters.z = !this->_internalRegisters.a; + return 5; + } +} \ No newline at end of file diff --git a/tests/APU/testAPUInstructions.cpp b/tests/APU/testAPUInstructions.cpp index 6e87578..c1a6863 100644 --- a/tests/APU/testAPUInstructions.cpp +++ b/tests/APU/testAPUInstructions.cpp @@ -883,4 +883,111 @@ Test(XVIbitDataTransmission, MOVW) cr_assert_eq(apu->_internalRegisters.ya, 0x4433); cr_assert_eq(apu->_internalRegisters.n, false); cr_assert_eq(apu->_internalRegisters.z, false); +} + +////////////////////////////////////// +// // +// (VIII)8-bit Shift Rotation tests // +// // +////////////////////////////////////// + +Test(VIIIShiftRotation, ASL) +{ + auto apu = Init().second.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); + cr_assert_eq(apu->_internalRegisters.n, true); + cr_assert_eq(apu->_internalRegisters.z, 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); + cr_assert_eq(apu->_internalRegisters.n, true); + cr_assert_eq(apu->_internalRegisters.z, false); +} + +Test(VIIIShiftRotation, LSR) +{ + auto apu = Init().second.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); + cr_assert_eq(apu->_internalRegisters.n, true); + cr_assert_eq(apu->_internalRegisters.z, 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); + cr_assert_eq(apu->_internalRegisters.n, false); + cr_assert_eq(apu->_internalRegisters.z, false); +} + +Test(VIIIShiftRotation, ROL) +{ + auto apu = Init().second.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); + cr_assert_eq(apu->_internalRegisters.n, true); + cr_assert_eq(apu->_internalRegisters.z, 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); + cr_assert_eq(apu->_internalRegisters.n, true); + cr_assert_eq(apu->_internalRegisters.z, false); +} + +Test(VIIIShiftRotation, ROR) +{ + auto apu = Init().second.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); + cr_assert_eq(apu->_internalRegisters.n, true); + cr_assert_eq(apu->_internalRegisters.z, 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); + cr_assert_eq(apu->_internalRegisters.n, false); + cr_assert_eq(apu->_internalRegisters.z, false); +} + +Test(VIIIShiftRotation, XCN) +{ + auto apu = Init().second.apu; + int result = 0; + + apu->_internalRegisters.a = 0b10101010; + result = apu->XCN(); + cr_assert_eq(result, 5); + cr_assert_eq(apu->_internalRegisters.a, 0xAA); + cr_assert_eq(apu->_internalRegisters.n, true); + cr_assert_eq(apu->_internalRegisters.z, false); } \ No newline at end of file