From b1fc2754eb73e5e44b6957711c8d7e7a2c854583 Mon Sep 17 00:00:00 2001 From: Melefo <42809472+Melefo@users.noreply.github.com> Date: Fri, 21 Feb 2020 14:54:31 +0100 Subject: [PATCH] Adding Subroutine operations --- CMakeLists.txt | 2 + sources/APU/APU.cpp | 44 ++++++++++- sources/APU/APU.hpp | 13 ++++ sources/APU/Instructions/Stack.cpp | 4 +- sources/APU/Instructions/Subroutine.cpp | 55 ++++++++++++++ tests/APU/testAPUInstructions.cpp | 99 ++++++++++++++++++++++++- 6 files changed, 212 insertions(+), 5 deletions(-) create mode 100644 sources/APU/Instructions/Subroutine.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index f6d5374..9adb43e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -72,6 +72,7 @@ add_executable(unit_tests sources/Utility/Utility.hpp sources/Utility/Utility.cpp sources/APU/Instructions/Bit.cpp sources/APU/Instructions/Stack.cpp + sources/APU/Instructions/Subroutine.cpp ) # include criterion & coverage @@ -156,6 +157,7 @@ add_executable(ComSquare sources/Debugger/APUDebug.hpp sources/Debugger/APUDebug.cpp sources/APU/Instructions/Stack.cpp + sources/APU/Instructions/Subroutine.cpp ) target_compile_definitions(ComSquare PUBLIC DEBUGGER_ENABLED) diff --git a/sources/APU/APU.cpp b/sources/APU/APU.cpp index 5894c38..8396499 100644 --- a/sources/APU/APU.cpp +++ b/sources/APU/APU.cpp @@ -162,6 +162,8 @@ namespace ComSquare::APU switch (opcode) { case 0x00: return this->NOP(); + case 0x01: + return this->TCALL(0); case 0x02: return this->SET1(this->_getDirectAddr(), 0); case 0x0A: @@ -170,20 +172,32 @@ namespace ComSquare::APU return this->PUSH(this->_internalRegisters.psw); case 0x0E: return this->TSET1(this->_getAbsoluteAddr()); + case 0x0F: + return this->BRK(); + case 0x11: + return this->TCALL(1); case 0x12: return this->CLR1(this->_getDirectAddr(), 0); case 0x20: return this->CLRP(); + case 0x21: + return this->TCALL(2); case 0x22: return this->SET1(this->_getDirectAddr(), 1); case 0x2A: return this->OR1(this->_getAbsoluteBit(), true); case 0x2D: return this->PUSH(this->_internalRegisters.a); + case 0x31: + return this->TCALL(3); case 0x32: return this->CLR1(this->_getDirectAddr(), 1); + case 0x3F: + return this->CALL(this->_getAbsoluteAddr()); case 0x40: return this->SETP(); + case 0x41: + return this->TCALL(4); case 0x42: return this->SET1(this->_getDirectAddr(), 2); case 0x4A: @@ -192,52 +206,80 @@ namespace ComSquare::APU return this->PUSH(this->_internalRegisters.x); case 0x4E: return this->TCLR1(this->_getAbsoluteAddr()); + case 0x4F: + return this->PCALL(); + case 0x51: + return this->TCALL(5); case 0x52: return this->CLR1(this->_getDirectAddr(), 2); case 0x60: return this->CLRC(); + case 0x61: + return this->TCALL(6); case 0x62: return this->SET1(this->_getDirectAddr(), 3); case 0x6A: return this->AND1(this->_getAbsoluteBit(), true); case 0x6D: return this->PUSH(this->_internalRegisters.y); + case 0x6F: + return this->RET(); + case 0x71: + return this->TCALL(7); case 0x72: return this->CLR1(this->_getDirectAddr(), 3); + case 0x7F: + return this->RETI(); case 0x80: return this->SETC(); + case 0x81: + return this->TCALL(8); case 0x82: return this->SET1(this->_getDirectAddr(), 4); case 0x8A: return this->EOR1(this->_getAbsoluteBit()); case 0x8E: return this->POP(this->_internalRegisters.psw); + case 0x91: + return this->TCALL(9); case 0x92: return this->CLR1(this->_getDirectAddr(), 4); case 0xA0: return this->EI(); + case 0xA1: + return this->TCALL(10); case 0xA2: return this->SET1(this->_getDirectAddr(), 5); case 0xAA: return this->MOV1(this->_getAbsoluteBit(), true); case 0xAE: return this->POP(this->_internalRegisters.a); + case 0xB1: + return this->TCALL(11); case 0xB2: return this->CLR1(this->_getDirectAddr(), 5); case 0xC0: return this->DI(); + case 0xC1: + return this->TCALL(12); case 0xC2: return this->SET1(this->_getDirectAddr(), 6); - case 0xC1: + case 0xCA: return this->MOV1(this->_getAbsoluteBit()); case 0xCE: return this->POP(this->_internalRegisters.x); + case 0xD1: + return this->TCALL(13); case 0xD2: return this->CLR1(this->_getDirectAddr(), 6); + case 0xE1: + return this->TCALL(14); case 0xE2: return this->SET1(this->_getDirectAddr(), 7); case 0xEE: return this->POP(this->_internalRegisters.y); + case 0xF1: + return this->TCALL(15); case 0xF2: return this->CLR1(this->_getDirectAddr(), 7); case 0xEA: diff --git a/sources/APU/APU.hpp b/sources/APU/APU.hpp index a7cf1a9..bfe2a48 100644 --- a/sources/APU/APU.hpp +++ b/sources/APU/APU.hpp @@ -219,6 +219,19 @@ namespace ComSquare::APU int PUSH(uint8_t value); //! @brief Increment SP Register and pop a single value from the stack. int POP(uint8_t &destination); + + //! @brief Push PC of the next instruction on the stack, then jump to the address at the specified location. + int CALL(uint24_t abs); + //! @brief Perform a call in the upper page of memory, read PC Register and add 0xFF00 to it. + int PCALL(); + //! @brief Performs a call on one of the 16 vectors in the memory range of $FFC0 to $FFDF. + int TCALL(uint8_t bit); + //! @brief Cause a software interrupt. + int BRK(); + //! @brief Return from subroutine. + int RET(); + //! @brief Return from interrupt. + int RETI(); public: explicit APU(std::shared_ptr &map); APU(const APU &) = default; diff --git a/sources/APU/Instructions/Stack.cpp b/sources/APU/Instructions/Stack.cpp index bd9d5d3..65ab315 100644 --- a/sources/APU/Instructions/Stack.cpp +++ b/sources/APU/Instructions/Stack.cpp @@ -8,13 +8,13 @@ namespace ComSquare::APU { int APU::PUSH(uint8_t value) { - this->_internalWrite(this->_internalRegisters.sp-- | 0x0100u, value); + this->_internalWrite(this->_internalRegisters.sp-- + 0x0100u, value); return 4; } int APU::POP(uint8_t &destination) { - destination = this->_internalRead(++this->_internalRegisters.sp | 0x100u); + destination = this->_internalRead(++this->_internalRegisters.sp + 0x100u); return 4; } } \ No newline at end of file diff --git a/sources/APU/Instructions/Subroutine.cpp b/sources/APU/Instructions/Subroutine.cpp new file mode 100644 index 0000000..34eb031 --- /dev/null +++ b/sources/APU/Instructions/Subroutine.cpp @@ -0,0 +1,55 @@ +// +// Created by Melefo on 21/02/2020. +// + +#include "../APU.hpp" +#include "../../Utility/Utility.hpp" + +namespace ComSquare::APU +{ + int APU::CALL(uint24_t abs) + { + this->PUSH(this->_internalRegisters.pch); + this->PUSH(this->_internalRegisters.pcl); + this->_internalRegisters.pc = abs; + return 8; + } + + int APU::PCALL() + { + this->CALL(0xFF00u + this->_internalRead(this->_internalRegisters.pc++)); + return 6; + } + + int APU::TCALL(uint8_t bit) + { + this->CALL(this->_internalRead(0xFFDE - bit * 2)); + return 8; + } + + int APU::BRK() + { + this->_internalRegisters.b = true; + this->PUSH(this->_internalRegisters.pch); + this->PUSH(this->_internalRegisters.pcl); + this->PUSH(this->_internalRegisters.psw); + this->_internalRegisters.i = false; + this->_internalRegisters.pch = this->_internalRead(0xFFDF); + this->_internalRegisters.pcl = this->_internalRead(0xFFDE); + return 8; + } + + int APU::RET() + { + this->POP(this->_internalRegisters.pch); + this->POP(this->_internalRegisters.pcl); + return 5; + } + + int APU::RETI() + { + this->POP(this->_internalRegisters.psw); + this->RET(); + return 6; + } +} \ No newline at end of file diff --git a/tests/APU/testAPUInstructions.cpp b/tests/APU/testAPUInstructions.cpp index 66533d7..4f920da 100644 --- a/tests/APU/testAPUInstructions.cpp +++ b/tests/APU/testAPUInstructions.cpp @@ -4,9 +4,11 @@ #include #include +#include #include "../tests.hpp" #include "../../sources/SNES.hpp" #include "../../sources/APU/APU.hpp" +#include "../../sources/Utility/Utility.hpp" using namespace ComSquare; @@ -347,7 +349,7 @@ Test(Bit, MOV1_carry) // // ///////////////// -Test(Stack, push) +Test(Stack, PUSH) { auto apu = Init().second.apu; int result = 0; @@ -359,7 +361,7 @@ Test(Stack, push) cr_assert_eq(apu->_internalRead(apu->_internalRegisters.sp | 0x100u), 56); } -Test(Stack, pop) +Test(Stack, POP) { auto apu = Init().second.apu; int result = 0; @@ -369,4 +371,97 @@ Test(Stack, pop) result = apu->POP(apu->_internalRegisters.y); cr_assert_eq(result, 4); cr_assert_eq(apu->_internalRegisters.y, 82); +} + +////////////////////// +// // +// Subroutine tests // +// // +////////////////////// + +Test(Subroutine, CALL) +{ + auto apu = Init().second.apu; + int result = 0; + + apu->_internalWrite(apu->_getAbsoluteAddr(), 23); + apu->_internalRegisters.pc -= 2; + result = apu->CALL(apu->_getAbsoluteAddr()); + cr_assert_eq(result, 8); + cr_assert_eq(apu->_internalRegisters.pc, 23); + cr_assert_eq(apu->_internalRead(++apu->_internalRegisters.sp + 0x0100u), 2); + cr_assert_eq(apu->_internalRead(++apu->_internalRegisters.sp + 0x0100u), 0); +} + +Test(Subroutine, PCALL) +{ + auto apu = Init().second.apu; + int result = 0; + + apu->_internalWrite(apu->_internalRegisters.pc, 123); + result = apu->PCALL(); + cr_assert_eq(result, 6); + cr_assert_eq(apu->_internalRegisters.pc, 65403); +} + +Test(Subroutine, TCALL) +{ + auto apu = Init().second.apu; + int result = 0; + + apu->_internalWrite(0xFFD0, 45); + result = apu->TCALL(7); + cr_assert_eq(result, 8); + cr_assert_eq(apu->_internalRegisters.pc, 45); +} + +Test(Subroutine, BRK) +{ + auto apu = Init().second.apu; + int result = 0; + + apu->_internalRegisters.pch = 0xFF; + apu->_internalRegisters.pcl = 0xEE; + apu->_internalRegisters.psw = 0xDD; + apu->_internalWrite(0xFFDF, 0xAA); + apu->_internalWrite(0xFFDE, 0xBB); + result = apu->BRK(); + apu->_internalRegisters.sp += 3; + cr_assert_eq(result, 8); + cr_assert_eq(apu->_internalRegisters.i, false); + cr_assert_eq(apu->_internalRegisters.b, true); + cr_assert_eq(apu->_internalRegisters.pc, 0xAABB); + cr_assert_eq(apu->_internalRead(apu->_internalRegisters.sp-- | 0x100u), 0xFF); + cr_assert_eq(apu->_internalRead(apu->_internalRegisters.sp-- | 0x100u), 0xEE); + cr_assert_eq(apu->_internalRead(apu->_internalRegisters.sp | 0x100u), 0xDD); +} + +Test(Subroutine, RET) +{ + auto apu = Init().second.apu; + int result = 0; + + apu->_internalWrite(++apu->_internalRegisters.sp | 0x100u, 0x12); + apu->_internalWrite(++apu->_internalRegisters.sp | 0x100u, 0x34); + apu->_internalRegisters.sp -= 2; + result = apu->RET(); + cr_assert_eq(result, 5); + cr_assert_eq(apu->_internalRegisters.pch, 0x12); + cr_assert_eq(apu->_internalRegisters.pcl, 0x34); +} + +Test(Subroutine, RETI) +{ + auto apu = Init().second.apu; + int result = 0; + + apu->_internalWrite(++apu->_internalRegisters.sp | 0x100u, 0x12); + apu->_internalWrite(++apu->_internalRegisters.sp | 0x100u, 0x34); + apu->_internalWrite(++apu->_internalRegisters.sp | 0x100u, 0x56); + apu->_internalRegisters.sp -= 3; + result = apu->RETI(); + cr_assert_eq(result, 6); + cr_assert_eq(apu->_internalRegisters.psw, 0x12); + cr_assert_eq(apu->_internalRegisters.pch, 0x34); + cr_assert_eq(apu->_internalRegisters.pcl, 0x56); } \ No newline at end of file