From 91150dfbc1cbe2c70d372c1b97517ba72cd1e394 Mon Sep 17 00:00:00 2001 From: AnonymusRaccoon Date: Thu, 20 Feb 2020 18:32:21 +0100 Subject: [PATCH] Adding the AND instruction --- CMakeLists.txt | 4 +- sources/CPU/CPU.cpp | 16 ++++++ sources/CPU/CPU.hpp | 20 +++++++- sources/CPU/Instructions/BitsInstructions.cpp | 21 ++++++++ tests/CPU/testBits.cpp | 50 +++++++++++++++++++ 5 files changed, 108 insertions(+), 3 deletions(-) create mode 100644 sources/CPU/Instructions/BitsInstructions.cpp create mode 100644 tests/CPU/testBits.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 78787a6..1a27ee5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -63,7 +63,7 @@ add_executable(unit_tests tests/CPU/testInternal.cpp sources/Ram/ExtendedRam.cpp sources/Ram/ExtendedRam.hpp - sources/Utility/Utility.hpp sources/Utility/Utility.cpp) + sources/Utility/Utility.hpp sources/Utility/Utility.cpp sources/CPU/Instructions/BitsInstructions.cpp tests/CPU/testBits.cpp) # include criterion & coverage target_link_libraries(unit_tests criterion -lgcov) @@ -136,7 +136,7 @@ add_executable(ComSquare sources/Utility/Utility.hpp sources/Debugger/MemoryViewer.cpp sources/Debugger/MemoryViewer.hpp - sources/Utility/Utility.cpp sources/Debugger/HeaderViewer.cpp sources/Debugger/HeaderViewer.hpp) + sources/Utility/Utility.cpp sources/Debugger/HeaderViewer.cpp sources/Debugger/HeaderViewer.hpp sources/CPU/Instructions/BitsInstructions.cpp) target_compile_definitions(ComSquare PUBLIC DEBUGGER_ENABLED) diff --git a/sources/CPU/CPU.cpp b/sources/CPU/CPU.cpp index 9fb9e23..96807c0 100644 --- a/sources/CPU/CPU.cpp +++ b/sources/CPU/CPU.cpp @@ -306,6 +306,22 @@ namespace ComSquare::CPU case Instructions::CLD: this->CLD(); return 2; case Instructions::CLV: this->CLV(); return 2; + case Instructions::AND_IM: this->AND(this->_getImmediateAddr()); return 2 + !this->_registers.p.m; + case Instructions::AND_ABS: this->AND(this->_getAbsoluteAddr()); return 4 + !this->_registers.p.m; + case Instructions::AND_ABSl: this->AND(this->_getAbsoluteLongAddr()); return 5 + !this->_registers.p.m; + case Instructions::AND_DP: this->AND(this->_getDirectAddr()); return 3 + !this->_registers.p.m + this->_registers.dl != 0; + case Instructions::AND_DPi: this->AND(this->_getDirectIndirectAddr()); return 5 + !this->_registers.p.m + this->_registers.dl != 0; + case Instructions::AND_DPil: this->AND(this->_getDirectIndirectLongAddr()); return 6 + !this->_registers.p.m + this->_registers.dl != 0; + case Instructions::AND_ABSX: this->AND(this->_getAbsoluteIndexedByXAddr()); return 4 + !this->_registers.p.m + this->_hasIndexCrossedPageBoundary; + case Instructions::AND_ABSXl:this->AND(this->_getAbsoluteIndexedByXLongAddr()); return 5 + !this->_registers.p.m; + case Instructions::AND_ABSY: this->AND(this->_getAbsoluteIndexedByYAddr()); return 4 + !this->_registers.p.m + this->_hasIndexCrossedPageBoundary; + case Instructions::AND_DPX: this->AND(this->_getDirectIndexedByXAddr()); return 4 + !this->_registers.p.m + this->_registers.dl != 0; + case Instructions::AND_DPXi: this->AND(this->_getDirectIndirectIndexedXAddr()); return 6 + !this->_registers.p.m + this->_registers.dl != 0; + case Instructions::AND_DPYi: this->AND(this->_getDirectIndirectIndexedYAddr()); return 5 + !this->_registers.p.m + this->_registers.dl != 0 + this->_hasIndexCrossedPageBoundary; + case Instructions::AND_DPYil:this->AND(this->_getDirectIndirectIndexedYLongAddr()); return 6 + !this->_registers.p.m + this->_registers.dl != 0; + case Instructions::AND_SR: this->AND(this->_getStackRelativeAddr()); return 4 + !this->_registers.p.m; + case Instructions::AND_SRYi: this->AND(this->_getStackRelativeIndirectIndexedYAddr()); return 7 + !this->_registers.p.m; + default: throw InvalidOpcode("CPU", opcode); } diff --git a/sources/CPU/CPU.hpp b/sources/CPU/CPU.hpp index 855e89f..d9def71 100644 --- a/sources/CPU/CPU.hpp +++ b/sources/CPU/CPU.hpp @@ -288,7 +288,23 @@ namespace ComSquare::CPU CLC = 0x18, CLI = 0x58, CLD = 0xD8, - CLV = 0xB8 + CLV = 0xB8, + + AND_IM = 0x29, + AND_ABS = 0x2D, + AND_ABSl = 0x2F, + AND_DP = 0x25, + AND_DPi = 0x32, + AND_DPil = 0x27, + AND_ABSX = 0x3D, + AND_ABSXl = 0x3F, + AND_ABSY = 0x39, + AND_DPX = 0x35, + AND_DPXi = 0x21, + AND_DPYi = 0x31, + AND_DPYil = 0x37, + AND_SR = 0x23, + AND_SRYi = 0x33 }; //! @brief The main CPU @@ -429,6 +445,8 @@ namespace ComSquare::CPU void CLD(); //! @brief Clear the overflow flag. void CLV(); + //! @brief And accumulator with memory. + void AND(uint24_t valueAddr); public: explicit CPU(std::shared_ptr bus, Cartridge::Header &cartridgeHeader); CPU(const CPU &) = default; diff --git a/sources/CPU/Instructions/BitsInstructions.cpp b/sources/CPU/Instructions/BitsInstructions.cpp new file mode 100644 index 0000000..3496f8f --- /dev/null +++ b/sources/CPU/Instructions/BitsInstructions.cpp @@ -0,0 +1,21 @@ +// +// Created by anonymus-raccoon on 2/20/20. +// + +#include "../../Models/Int24.hpp" +#include "../CPU.hpp" + +namespace ComSquare::CPU +{ + void CPU::AND(uint24_t valueAddr) + { + unsigned negativeMask = this->_isEmulationMode ? 0x80u : 0x8000u; + unsigned value = this->_bus->read(valueAddr); + if (this->_registers.p.m) + value += this->_bus->read(valueAddr + 1) << 8u; + + this->_registers.a &= value; + this->_registers.p.n = this->_registers.a & negativeMask; + this->_registers.p.z = this->_registers.a == 0; + } +} \ No newline at end of file diff --git a/tests/CPU/testBits.cpp b/tests/CPU/testBits.cpp new file mode 100644 index 0000000..fc1d0c5 --- /dev/null +++ b/tests/CPU/testBits.cpp @@ -0,0 +1,50 @@ +// +// Created by anonymus-raccoon on 2/20/20. +// + +#include +#include +#include +#include "../tests.hpp" +#include "../../sources/SNES.hpp" +using namespace ComSquare; + +Test(AND, emulation) +{ + auto pair = Init(); + pair.second.wram->_data[0] = 0x00; + pair.second.cpu->_registers.a = 0xFF; + pair.second.cpu->_isEmulationMode = true; + pair.second.cpu->AND(0x0); + cr_assert_eq(pair.second.cpu->_registers.a, 0x00, "The flags should be 0x00 but it was %x", pair.second.cpu->_registers.a); + cr_assert_eq(pair.second.cpu->_registers.p.z, true, "The zero flag should be set."); + cr_assert_eq(pair.second.cpu->_registers.p.n, false, "The negative flag should not be set."); +} + +Test(AND, nativeNegative) +{ + auto pair = Init(); + pair.second.wram->_data[0] = 0xF0; + pair.second.wram->_data[1] = 0xF0; + pair.second.cpu->_registers.p.m = true; + pair.second.cpu->_registers.a = 0xFF00; + pair.second.cpu->_isEmulationMode = false; + pair.second.cpu->AND(0x0); + cr_assert_eq(pair.second.cpu->_registers.a, 0xF000, "The flags should be 0xF000 but it was %x", pair.second.cpu->_registers.a); + cr_assert_eq(pair.second.cpu->_registers.p.z, false, "The zero flag should not be set."); + cr_assert_eq(pair.second.cpu->_registers.p.n, true, "The negative flag should be set."); +} + + +Test(AND, emulationTest) +{ + auto pair = Init(); + pair.second.wram->_data[0] = 0b00110011; + pair.second.cpu->_registers.a = 0b00110111; + pair.second.cpu->_isEmulationMode = true; + pair.second.cpu->AND(0x0); + cr_assert_eq(pair.second.cpu->_registers.a, 0b00110011, "The flags should be 0b00110011 but it was %x", pair.second.cpu->_registers.a); + cr_assert_eq(pair.second.cpu->_registers.p.z, false, "The zero flag should not be set."); + cr_assert_eq(pair.second.cpu->_registers.p.n, false, "The negative flag should not be set."); +} +