diff --git a/CMakeLists.txt b/CMakeLists.txt index 9adb43e..51c3181 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -73,6 +73,7 @@ add_executable(unit_tests sources/APU/Instructions/Bit.cpp sources/APU/Instructions/Stack.cpp sources/APU/Instructions/Subroutine.cpp + sources/APU/Instructions/ProgramFlow.cpp ) # include criterion & coverage @@ -158,6 +159,7 @@ add_executable(ComSquare sources/Debugger/APUDebug.cpp sources/APU/Instructions/Stack.cpp sources/APU/Instructions/Subroutine.cpp + sources/APU/Instructions/ProgramFlow.cpp ) target_compile_definitions(ComSquare PUBLIC DEBUGGER_ENABLED) diff --git a/sources/APU/APU.cpp b/sources/APU/APU.cpp index 8396499..f8804c1 100644 --- a/sources/APU/APU.cpp +++ b/sources/APU/APU.cpp @@ -174,6 +174,8 @@ namespace ComSquare::APU return this->TSET1(this->_getAbsoluteAddr()); case 0x0F: return this->BRK(); + case 0x10: + return this->BPL(); case 0x11: return this->TCALL(1); case 0x12: @@ -188,6 +190,10 @@ namespace ComSquare::APU return this->OR1(this->_getAbsoluteBit(), true); case 0x2D: return this->PUSH(this->_internalRegisters.a); + case 0x2F: + return this->BRA(); + case 0x30: + return this->BMI(); case 0x31: return this->TCALL(3); case 0x32: @@ -208,6 +214,8 @@ namespace ComSquare::APU return this->TCLR1(this->_getAbsoluteAddr()); case 0x4F: return this->PCALL(); + case 0x50: + return this->BVC(); case 0x51: return this->TCALL(5); case 0x52: @@ -224,6 +232,8 @@ namespace ComSquare::APU return this->PUSH(this->_internalRegisters.y); case 0x6F: return this->RET(); + case 0x70: + return this->BVS(); case 0x71: return this->TCALL(7); case 0x72: @@ -240,6 +250,8 @@ namespace ComSquare::APU return this->EOR1(this->_getAbsoluteBit()); case 0x8E: return this->POP(this->_internalRegisters.psw); + case 0x90: + return this->BCC(); case 0x91: return this->TCALL(9); case 0x92: @@ -254,6 +266,8 @@ namespace ComSquare::APU return this->MOV1(this->_getAbsoluteBit(), true); case 0xAE: return this->POP(this->_internalRegisters.a); + case 0xB0: + return this->BCS(); case 0xB1: return this->TCALL(11); case 0xB2: @@ -268,6 +282,8 @@ namespace ComSquare::APU return this->MOV1(this->_getAbsoluteBit()); case 0xCE: return this->POP(this->_internalRegisters.x); + case 0xD0: + return this->BNE(); case 0xD1: return this->TCALL(13); case 0xD2: @@ -278,6 +294,8 @@ namespace ComSquare::APU return this->SET1(this->_getDirectAddr(), 7); case 0xEE: return this->POP(this->_internalRegisters.y); + case 0xF0: + return BEQ(); case 0xF1: return this->TCALL(15); case 0xF2: diff --git a/sources/APU/APU.hpp b/sources/APU/APU.hpp index bfe2a48..5006316 100644 --- a/sources/APU/APU.hpp +++ b/sources/APU/APU.hpp @@ -232,6 +232,25 @@ namespace ComSquare::APU int RET(); //! @brief Return from interrupt. int RETI(); + + //! @brief Branch Always, go to the specified location from the next instruction. + int BRA(); + //! @brief Branch if Zero Flag is set + int BEQ(); + //! @brief Branch if Zero Flag is clear + int BNE(); + //! @brief Branch if Carry Flag is set + int BCS(); + //! @brief Branch if Carry Flag is clear + int BCC(); + //! @brief Branch if Overflow Flag is set + int BVS(); + //! @brief Branch if Overflow Flag is set + int BVC(); + //! @brief Branch if Negative Flag is set + int BMI(); + //! @brief Branch if Negative Flag is clear + int BPL(); public: explicit APU(std::shared_ptr &map); APU(const APU &) = default; diff --git a/sources/APU/Instructions/ProgramFlow.cpp b/sources/APU/Instructions/ProgramFlow.cpp new file mode 100644 index 0000000..bb7cc65 --- /dev/null +++ b/sources/APU/Instructions/ProgramFlow.cpp @@ -0,0 +1,80 @@ +// +// Created by Melefo on 21/02/2020. +// + +#include "../APU.hpp" + +namespace ComSquare::APU +{ + int APU::BRA() + { + int8_t offset = this->_internalRead(this->_internalRegisters.pc++); + + this->_internalRegisters.pc += offset; + return 4; + } + + int APU::BEQ() + { + if (!this->_internalRegisters.z) + return 2; + this->BRA(); + return 4; + } + + int APU::BNE() + { + if (this->_internalRegisters.z) + return 2; + this->BRA(); + return 4; + } + + int APU::BCS() + { + if (!this->_internalRegisters.c) + return 2; + this->BRA(); + return 4; + } + + int APU::BCC() + { + if (this->_internalRegisters.c) + return 2; + this->BRA(); + return 4; + } + + int APU::BVS() + { + if (!this->_internalRegisters.v) + return 2; + this->BRA(); + return 4; + } + + int APU::BVC() + { + if (this->_internalRegisters.v) + return 2; + this->BRA(); + return 4; + } + + int APU::BMI() + { + if (!this->_internalRegisters.n) + return 2; + this->BRA(); + return 4; + } + + int APU::BPL() + { + if (this->_internalRegisters.n) + return 2; + this->BRA(); + return 4; + } +} \ No newline at end of file diff --git a/tests/APU/testAPUInstructions.cpp b/tests/APU/testAPUInstructions.cpp index 4f920da..cf3b5c4 100644 --- a/tests/APU/testAPUInstructions.cpp +++ b/tests/APU/testAPUInstructions.cpp @@ -464,4 +464,146 @@ Test(Subroutine, RETI) cr_assert_eq(apu->_internalRegisters.psw, 0x12); cr_assert_eq(apu->_internalRegisters.pch, 0x34); cr_assert_eq(apu->_internalRegisters.pcl, 0x56); +} + +///////////////////////////// +// // +// Subroutine Program Flow // +// // +///////////////////////////// + +Test(ProgramFlow, BRA) +{ + auto apu = Init().second.apu; + int result = 0; + + apu->_internalWrite(apu->_internalRegisters.pc, 23); + apu->_internalWrite(apu->_internalRegisters.pc + 24, 101); + result = apu->BRA(); + cr_assert_eq(result, 4); + cr_assert_eq(apu->_internalRead(apu->_internalRegisters.pc), 101); +} + +Test(ProgramFlow, BEQ) +{ + auto apu = Init().second.apu; + int result = 0; + + apu->_internalWrite(apu->_internalRegisters.pc, 23); + apu->_internalWrite(apu->_internalRegisters.pc + 24, 101); + result = apu->BEQ(); + cr_assert_eq(result, 2); + apu->_internalRegisters.z = true; + result = apu->BEQ(); + cr_assert_eq(result, 4); + cr_assert_eq(apu->_internalRead(apu->_internalRegisters.pc), 101); +} + +Test(ProgramFlow, BNE) +{ + auto apu = Init().second.apu; + int result = 0; + + apu->_internalWrite(apu->_internalRegisters.pc, 23); + apu->_internalWrite(apu->_internalRegisters.pc + 24, 101); + apu->_internalRegisters.z = true; + result = apu->BNE(); + cr_assert_eq(result, 2); + apu->_internalRegisters.z = false; + result = apu->BNE(); + cr_assert_eq(result, 4); + cr_assert_eq(apu->_internalRead(apu->_internalRegisters.pc), 101); +} + +Test(ProgramFlow, BCS) +{ + auto apu = Init().second.apu; + int result = 0; + + apu->_internalWrite(apu->_internalRegisters.pc, 23); + apu->_internalWrite(apu->_internalRegisters.pc + 24, 101); + result = apu->BCS(); + cr_assert_eq(result, 2); + apu->_internalRegisters.c = true; + result = apu->BCS(); + cr_assert_eq(result, 4); + cr_assert_eq(apu->_internalRead(apu->_internalRegisters.pc), 101); +} + +Test(ProgramFlow, BCC) +{ + auto apu = Init().second.apu; + int result = 0; + + apu->_internalWrite(apu->_internalRegisters.pc, 23); + apu->_internalWrite(apu->_internalRegisters.pc + 24, 101); + apu->_internalRegisters.c = true; + result = apu->BCC(); + cr_assert_eq(result, 2); + apu->_internalRegisters.c = false; + result = apu->BCC(); + cr_assert_eq(result, 4); + cr_assert_eq(apu->_internalRead(apu->_internalRegisters.pc), 101); +} + +Test(ProgramFlow, BVS) +{ + auto apu = Init().second.apu; + int result = 0; + + apu->_internalWrite(apu->_internalRegisters.pc, 23); + apu->_internalWrite(apu->_internalRegisters.pc + 24, 101); + result = apu->BVS(); + cr_assert_eq(result, 2); + apu->_internalRegisters.v = true; + result = apu->BVS(); + cr_assert_eq(result, 4); + cr_assert_eq(apu->_internalRead(apu->_internalRegisters.pc), 101); +} + +Test(ProgramFlow, BVC) +{ + auto apu = Init().second.apu; + int result = 0; + + apu->_internalWrite(apu->_internalRegisters.pc, 23); + apu->_internalWrite(apu->_internalRegisters.pc + 24, 101); + apu->_internalRegisters.v = true; + result = apu->BVC(); + cr_assert_eq(result, 2); + apu->_internalRegisters.v = false; + result = apu->BVC(); + cr_assert_eq(result, 4); + cr_assert_eq(apu->_internalRead(apu->_internalRegisters.pc), 101); +} + +Test(ProgramFlow, BMI) +{ + auto apu = Init().second.apu; + int result = 0; + + apu->_internalWrite(apu->_internalRegisters.pc, 23); + apu->_internalWrite(apu->_internalRegisters.pc + 24, 101); + result = apu->BMI(); + cr_assert_eq(result, 2); + apu->_internalRegisters.n = true; + result = apu->BMI(); + cr_assert_eq(result, 4); + cr_assert_eq(apu->_internalRead(apu->_internalRegisters.pc), 101); +} + +Test(ProgramFlow, BPL) +{ + auto apu = Init().second.apu; + int result = 0; + + apu->_internalWrite(apu->_internalRegisters.pc, 23); + apu->_internalWrite(apu->_internalRegisters.pc + 24, 101); + apu->_internalRegisters.n = true; + result = apu->BPL(); + cr_assert_eq(result, 2); + apu->_internalRegisters.n = false; + result = apu->BPL(); + cr_assert_eq(result, 4); + cr_assert_eq(apu->_internalRead(apu->_internalRegisters.pc), 101); } \ No newline at end of file