diff --git a/CMakeLists.txt b/CMakeLists.txt index 068a71a..5bdd37c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -95,7 +95,9 @@ add_executable(unit_tests sources/Models/Components.hpp sources/CPU/Instruction.hpp sources/Exceptions/DebuggableError.hpp - tests/CPU/Math/testOthersMath.cpp) + tests/CPU/Math/testOthersMath.cpp + tests/testRectangleMemory.cpp +) # include criterion & coverage target_link_libraries(unit_tests criterion -lgcov) diff --git a/sources/Memory/ARectangleMemory.cpp b/sources/Memory/ARectangleMemory.cpp index b60aa66..e7e9ff4 100644 --- a/sources/Memory/ARectangleMemory.cpp +++ b/sources/Memory/ARectangleMemory.cpp @@ -5,6 +5,7 @@ #include #include "ARectangleMemory.hpp" #include "../Exceptions/InvalidAddress.hpp" +#include "../Utility/Utility.hpp" namespace ComSquare::Memory { diff --git a/sources/Memory/ARectangleMemory.hpp b/sources/Memory/ARectangleMemory.hpp index f3adb8f..0a8f028 100644 --- a/sources/Memory/ARectangleMemory.hpp +++ b/sources/Memory/ARectangleMemory.hpp @@ -12,7 +12,7 @@ namespace ComSquare::Memory { //! @brief Superset of the AMemory to map non continuous rectangle to the memory. (A rectangle that spam across more than one bank but that does not start at 0000 or end at FFFF). class ARectangleMemory : public AMemory { - private: + protected: //! @brief The first bank to map to. uint8_t _startBank = 0; //! @brief The last bank to map to. diff --git a/sources/Memory/RectangleShadow.cpp b/sources/Memory/RectangleShadow.cpp index 9d924d4..424724a 100644 --- a/sources/Memory/RectangleShadow.cpp +++ b/sources/Memory/RectangleShadow.cpp @@ -3,6 +3,7 @@ // #include "RectangleShadow.hpp" +#include "../Utility/Utility.hpp" #include #include @@ -17,13 +18,13 @@ namespace ComSquare::Memory uint8_t RectangleShadow::read_internal(uint24_t addr) { - addr += this->_bankOffset << 16u; + addr += this->_bankOffset * (this->_endPage - this->_startPage); return this->_initial->read_internal(addr); } void RectangleShadow::write_internal(uint24_t addr, uint8_t data) { - addr += this->_bankOffset << 16u; + addr += this->_bankOffset * (this->_endPage - this->_startPage); this->_initial->write_internal(addr, data); } diff --git a/sources/Memory/RectangleShadow.hpp b/sources/Memory/RectangleShadow.hpp index d3130d9..365c85f 100644 --- a/sources/Memory/RectangleShadow.hpp +++ b/sources/Memory/RectangleShadow.hpp @@ -22,7 +22,7 @@ namespace ComSquare::Memory explicit RectangleShadow(std::shared_ptr initial, uint8_t startBank, uint8_t endBank, uint16_t startPage, uint16_t endPage); RectangleShadow(const RectangleShadow &) = default; RectangleShadow &operator=(const RectangleShadow &) = default; - ~RectangleShadow() = default; + ~RectangleShadow() override = default; //! @brief Internal component read. Implement this as you would implement a basic AMemory's read. //! @param addr The local address to read from. 0x0 refer to the first byte of your data and the address is in the component's space. That means that you can consider this address as continuous diff --git a/tests/testRectangleMemory.cpp b/tests/testRectangleMemory.cpp new file mode 100644 index 0000000..71edf33 --- /dev/null +++ b/tests/testRectangleMemory.cpp @@ -0,0 +1,89 @@ +// +// Created by anonymus-raccoon on 4/6/20. +// + +#include +#include +#include "tests.hpp" +#include "../sources/SNES.hpp" +#include "../sources/Renderer/NoRenderer.hpp" +#include "../sources/PPU/PPU.hpp" +#include "../sources/Memory/RectangleShadow.hpp" +#include "../sources/Utility/Utility.hpp" + +using namespace ComSquare; + +Test(RectangleMemory, HorizontalRamRead) +{ + Ram::Ram ram(0xFF, Component::Rom, "Rom"); + ram.setMemoryRegion(0x00, 0xFF, 0x0000, 0x0001); + for (int i = 0x00; i < 0xFF; i++) + ram._data[i] = i; + for (uint24_t i = 0x000000; i < 0xFF0000; i += 0x010000) + cr_assert_eq(ram.read(i), i >> 16u, "The ram's read returned 0x%x but the internal ram value was: 0x%x (addr: 0x%06x)", ram.read(i), i >> 16, i); +} + +Test(RectangleMemory, HorizontalRamWrite) +{ + Ram::Ram ram(0xFF, Component::Rom, "Rom"); + ram.setMemoryRegion(0x00, 0xFF, 0x0000, 0x0001); + for (uint24_t i = 0x000000; i < 0xFF0000; i += 0x010000) + ram.write(i, i >> 16u); + for (int i = 0x00; i < 0xFF; i++) + cr_assert_eq(ram._data[i], i, "The ram's write put 0x%x but it should had put: 0x%x (addr: 0x%06x)", ram._data[i], i, i << 16u); +} + +Test(RectangleMemory, DualLineRamRead) +{ + Ram::Ram ram(0xFF * 2, Component::Rom, "Rom"); + ram.setMemoryRegion(0x00, 0xFF, 0x0000, 0x0002); + for (int i = 0x00; i < 0xFF * 2; i++) + ram._data[i] = i; + for (uint24_t i = 0x000000, v = 0; v < 0xFF * 2; i += 0x010000, v += 2) { + cr_assert_eq(ram.read(i), (uint8_t)(v), "The ram's read returned 0x%x but the internal ram value was: 0x%x (addr: 0x%06x)", ram.read(i), (uint8_t)(v), i); + cr_assert_eq(ram.read(i + 1), (uint8_t)(v + 1), "The ram's read returned 0x%x but the internal ram value was: 0x%x (addr: 0x%06x)", ram.read(i + 1), (uint8_t)(v + 1), i + 1); + } +} + +Test(RectangleMemory, HorizontalRamShadowRead) +{ + std::shared_ptr ram = std::make_shared(0xFF, Component::Rom, "Rom"); + ram->setMemoryRegion(0x00, 0xFF, 0x0000, 0x0001); + Memory::RectangleShadow shadow(ram, 0x00, 0xFF, 0x8000, 0x8001); + for (int i = 0x00; i < 0xFF; i++) + ram->_data[i] = i; + for (uint24_t i = 0x008000; i < 0xFF8000; i += 0x010000) { + uint8_t v = shadow.read(i - shadow.getStart()); + cr_assert_eq(v, i >> 16u, "The ram's read returned 0x%x but the internal ram value was: 0x%x (addr: 0x%06x)", v, i >> 16, i); + }} + +Test(RectangleMemory, HorizontalRamShadowReadWithBankOffset) +{ + std::shared_ptr ram = std::make_shared(0xFF, Component::Rom, "Rom"); + ram->setMemoryRegion(0x00, 0xFF, 0x0000, 0x0001); + Memory::RectangleShadow shadow(ram, 0x80, 0xFF, 0x8000, 0x8001); + for (int i = 0x00; i < 0xFF; i++) + ram->_data[i] = i; + shadow.setBankOffset(0x80); + for (uint24_t i = 0x808000; i < 0xFF8000; i += 0x010000) { + uint8_t v = shadow.read(i - shadow.getStart()); + cr_assert_eq(v, i >> 16u, "The ram's read returned 0x%x but the internal ram value was: 0x%x (addr: 0x%06x)", v, i >> 16, i); + } +} + +Test(RectangleMemory, ShadowOffsetCartridge) +{ + std::shared_ptr ram = std::make_shared(0x3fff80, Component::Rom, "Rom"); + ram->setMemoryRegion(0x80, 0xFF, 0x8000, 0xFFFF); + Memory::RectangleShadow shadow(ram, 0xC0, 0xEF, 0x0000, 0x7FFF); + for (int i = 0x00; i < 0x3fff80; i++) + ram->_data[i] = i; + shadow.setBankOffset(0x40); + for (uint24_t i = 0xC00000; i < 0xEF7FFF; i += 0x1) { + if ((uint16_t)i > 0x7FFFu) + i += 0x010000 - 0x8000; + uint8_t v = shadow.read(i - shadow.getStart()); + uint8_t r = ram->read(i + 0x8000 - ram->getStart()); + cr_assert_eq(v, r, "The ram's read returned 0x%x but the internal ram value was: 0x%x (addr: 0x%06x)", v, r, i); + } +} \ No newline at end of file