From d8d1cdb783eb721fa50dd7d7da6fdf400b51d09f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Le=20Bihan?= Date: Thu, 6 Feb 2020 10:36:19 +0100 Subject: [PATCH 01/21] added bg struct --- sources/PPU/PPU.hpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/sources/PPU/PPU.hpp b/sources/PPU/PPU.hpp index 702b7bc..5235a40 100644 --- a/sources/PPU/PPU.hpp +++ b/sources/PPU/PPU.hpp @@ -13,6 +13,16 @@ namespace ComSquare::PPU //! @brief The class containing all the registers the PPU class PPU : public Memory::IMemory { private: + struct { + unsigned int height; + unsigned int width; + bool verticalMirroring; + bool horizontalMirroring; + int verticalOffset; + int horizontalOffset; + unsigned char characterHeight; + unsigned char characterWidth; + } BG[4]; //! @brief INIDISP Register (F-blank and Brightness) union { struct { From 82e0e9f086669d2a6161eb208165d22f2c1c3ae4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Le=20Bihan?= Date: Fri, 7 Feb 2020 18:50:26 +0100 Subject: [PATCH 02/21] starting PPU write V2 --- docs/PPU_8hpp_source.html | 2 +- docs/classComSquare_1_1PPU_1_1PPU.html | 6 +-- docs/latex/classComSquare_1_1PPU_1_1PPU.tex | 6 +-- sources/PPU/PPU.cpp | 28 ++++++++++---- sources/PPU/PPU.hpp | 42 +++++++++++++++++++-- 5 files changed, 66 insertions(+), 18 deletions(-) diff --git a/docs/PPU_8hpp_source.html b/docs/PPU_8hpp_source.html index 6153de7..aa413c7 100644 --- a/docs/PPU_8hpp_source.html +++ b/docs/PPU_8hpp_source.html @@ -504,7 +504,7 @@ $(function() {
bool enableWindowDisplayBg4
Definition: PPU.hpp:281
bool enableColorMathBg1
Definition: PPU.hpp:345
uint8_t objectSize
Definition: PPU.hpp:28
-
union ComSquare::PPU::PPU::@88 m7ofs
M7HOFS Register (Mode 7 BG Horizontal Scroll)
+
union ComSquare::PPU::PPU::@88 m7ofs
M7HOFS Register (Mode 7 _BG Horizontal Scroll)
uint8_t pixelSize
Definition: PPU.hpp:64
bool affectBg3
Definition: PPU.hpp:66
uint8_t clipColorToBlackBeforeMath
Definition: PPU.hpp:327
diff --git a/docs/classComSquare_1_1PPU_1_1PPU.html b/docs/classComSquare_1_1PPU_1_1PPU.html index b80dfdd..cf36417 100644 --- a/docs/classComSquare_1_1PPU_1_1PPU.html +++ b/docs/classComSquare_1_1PPU_1_1PPU.html @@ -328,7 +328,7 @@ Private Attributes    uint8_t   raw   } m7ofs - M7HOFS Register (Mode 7 BG Horizontal Scroll) More...
+ M7HOFS Register (Mode 7 _BG Horizontal Scroll) More...
  union {    struct { @@ -1934,8 +1934,8 @@ Private Attributes
-

M7HOFS Register (Mode 7 BG Horizontal Scroll)

-

M7VOFS Register (Mode 7 BG Vertical Scroll)

+

M7HOFS Register (Mode 7 _BG Horizontal Scroll)

+

M7VOFS Register (Mode 7 _BG Vertical Scroll)

diff --git a/docs/latex/classComSquare_1_1PPU_1_1PPU.tex b/docs/latex/classComSquare_1_1PPU_1_1PPU.tex index 65f37ec..4237964 100644 --- a/docs/latex/classComSquare_1_1PPU_1_1PPU.tex +++ b/docs/latex/classComSquare_1_1PPU_1_1PPU.tex @@ -203,7 +203,7 @@ union \{\\ \>uint8\_t \mbox{\hyperlink{classComSquare_1_1PPU_1_1PPU_a37f1fce3b3a72717fff33803b3c4633a}{raw}}\\ \} \mbox{\hyperlink{classComSquare_1_1PPU_1_1PPU_af6c4596ba682a867608d4587db646774}{m7ofs}}\\ -\end{tabbing}\begin{DoxyCompactList}\small\item\em M7\+H\+O\+FS Register (Mode 7 BG Horizontal Scroll) \end{DoxyCompactList}\item +\end{tabbing}\begin{DoxyCompactList}\small\item\em M7\+H\+O\+FS Register (Mode 7 _BG Horizontal Scroll) \end{DoxyCompactList}\item \begin{tabbing} xx\=xx\=xx\=xx\=xx\=xx\=xx\=xx\=xx\=\kill union \{\\ @@ -1093,9 +1093,9 @@ I\+N\+I\+D\+I\+SP Register (F-\/blank and Brightness) -M7\+H\+O\+FS Register (Mode 7 BG Horizontal Scroll) +M7\+H\+O\+FS Register (Mode 7 _BG Horizontal Scroll) -M7\+V\+O\+FS Register (Mode 7 BG Vertical Scroll) \mbox{\Hypertarget{classComSquare_1_1PPU_1_1PPU_a1915ae2586d7f0e7ad3f0046e98c4082}\label{classComSquare_1_1PPU_1_1PPU_a1915ae2586d7f0e7ad3f0046e98c4082}} +M7\+V\+O\+FS Register (Mode 7 _BG Vertical Scroll) \mbox{\Hypertarget{classComSquare_1_1PPU_1_1PPU_a1915ae2586d7f0e7ad3f0046e98c4082}\label{classComSquare_1_1PPU_1_1PPU_a1915ae2586d7f0e7ad3f0046e98c4082}} \index{ComSquare::PPU::PPU@{ComSquare::PPU::PPU}!m7sel@{m7sel}} \index{m7sel@{m7sel}!ComSquare::PPU::PPU@{ComSquare::PPU::PPU}} \doxysubsubsection{\texorpdfstring{m7sel}{m7sel}} diff --git a/sources/PPU/PPU.cpp b/sources/PPU/PPU.cpp index 32bd47a..ce5f625 100644 --- a/sources/PPU/PPU.cpp +++ b/sources/PPU/PPU.cpp @@ -25,17 +25,29 @@ namespace ComSquare::PPU void PPU::write(uint24_t addr, uint8_t data) { switch (addr) { - case 0x00: - this->inidisp.raw = data; + case 0x00: //! @brief $2100 INIDISP Register (F-blank and Brightness) + //! @brief Take the first bit to set the bool. + this->_fBlank = data >> 7U; + //! @brief Take the 4 last bits representing the brightness. + this->_brightness = data & 0xFU; break; - case 0x01: - this->obsel.raw = data; + case 0x01: //! @brief $2101 OBSEL Register (Object Size and Character Address) + //! @brief The first 3 bits. + this->_objectSize = (data & 0xE0U) >> 5U; + //! @brief The last 3 bits; + this->_baseSelect = data & 0x07U; + //! @brief th 2 center bits. + this->_nameSelect = (data & 0x18U) >> 3U; break; - case 0x02: - this->oamadd.oamaddl = data; + case 0x02: //! @brief $2102 OAMADDL (OAM Address low byte). + //! @brief we recreate the oamAddress with the previous oamAddress because there is one bit missing (given by the register $2103) + this->_oamAddress = (this->_oamAddress & 0x100U) | data; break; - case 0x03: - this->oamadd.oamaddh = data; + case 0x03: //! @brief $2103 OAMADDH (OAM Address high bit and Obj Priority) + //! @brief Same as $2102 we recreate the oamAddress with the previous oamAddress because there are 8 bits missing (given by the register $2102) + this->_oamAddress = (this->_oamAddress & 0xFFU) | ((data & 0x01U) << 8U); + //! @brief The objPriority is given by the first bit of the data + this->_objPriority = (data & 0x80U) >> 7U; break; case 0x04: this->oamdata = data; diff --git a/sources/PPU/PPU.hpp b/sources/PPU/PPU.hpp index 5235a40..a512dc7 100644 --- a/sources/PPU/PPU.hpp +++ b/sources/PPU/PPU.hpp @@ -8,6 +8,10 @@ #include #include "../Memory/IMemory.hpp" +#define max2BitTiles 4096 +#define max4BitTiles 2048 +#define max8BitTiles 1024 + namespace ComSquare::PPU { //! @brief The class containing all the registers the PPU @@ -20,9 +24,41 @@ namespace ComSquare::PPU bool horizontalMirroring; int verticalOffset; int horizontalOffset; + //! @brief A Character is the base unit of the background it can be 16x16 or 8x8 (16x8 under certain circumstances) unsigned char characterHeight; unsigned char characterWidth; - } BG[4]; + } _BG[4]; + struct object { + bool verticalMirroring; + bool horizontalMirroring; + bool priority; + unsigned short graphicAddress; + }; + + //! @brief INIDISP variables (F-blank and Brightness) + bool _fBlank; + unsigned short _brightness; //! @brief F=max, 0="off". + + //! @brief OBSEL variables (Object Size and Character Address) + unsigned char _objectSize; //! @brief "OamMode" this contains the size of the Objects (ex: 8x8 and 16x16) + unsigned char _baseSelect; //! @brief "OamBaseAddress" + unsigned char _nameSelect; //! @brief "OamAddressOffset" + + //! @brief OAMADD variables (OAM Address and Obj Priority) + uint16_t _oamAddress; + bool _objPriority; + + + + + + + + /// OLD to stuff to refactor + + + + //! @brief INIDISP Register (F-blank and Brightness) union { struct { @@ -140,8 +176,8 @@ namespace ComSquare::PPU }; uint16_t raw; } bg1ofs; - //! @brief M7HOFS Register (Mode 7 BG Horizontal Scroll) - //! @brief M7VOFS Register (Mode 7 BG Vertical Scroll) + //! @brief M7HOFS Register (Mode 7 _BG Horizontal Scroll) + //! @brief M7VOFS Register (Mode 7 _BG Vertical Scroll) union { struct { uint8_t _ : 3; From 073a2ae4221a12ab6595806e126087dbe5173548 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Le=20Bihan?= Date: Mon, 10 Feb 2020 15:56:29 +0100 Subject: [PATCH 03/21] adding tests and fix unions --- CMakeLists.txt | 4 +- sources/PPU/PPU.cpp | 42 +++++------- sources/PPU/PPU.hpp | 118 ++++++++++++++++++--------------- tests/PPU/testPpuWrite.cpp | 130 +++++++++++++++++++++++++++++++++++++ tests/testMemoryBus.cpp | 2 +- 5 files changed, 217 insertions(+), 79 deletions(-) create mode 100644 tests/PPU/testPpuWrite.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 74174d5..e4a6865 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -52,7 +52,9 @@ add_executable(unit_tests sources/CPU/Instructions/Interrupts.cpp sources/CPU/Instructions/MathematicalOperations.cpp tests/CPU/testAddressingMode.cpp - tests/tests.cpp) + tests/tests.cpp + tests/PPU/testPpuWrite.cpp +) # include criterion & coverage target_link_libraries(unit_tests criterion -lgcov) diff --git a/sources/PPU/PPU.cpp b/sources/PPU/PPU.cpp index ce5f625..a5db727 100644 --- a/sources/PPU/PPU.cpp +++ b/sources/PPU/PPU.cpp @@ -26,55 +26,47 @@ namespace ComSquare::PPU { switch (addr) { case 0x00: //! @brief $2100 INIDISP Register (F-blank and Brightness) - //! @brief Take the first bit to set the bool. - this->_fBlank = data >> 7U; - //! @brief Take the 4 last bits representing the brightness. - this->_brightness = data & 0xFU; + this->_inidisp.raw = data; break; case 0x01: //! @brief $2101 OBSEL Register (Object Size and Character Address) - //! @brief The first 3 bits. - this->_objectSize = (data & 0xE0U) >> 5U; - //! @brief The last 3 bits; - this->_baseSelect = data & 0x07U; - //! @brief th 2 center bits. - this->_nameSelect = (data & 0x18U) >> 3U; + this->_obsel.raw = data; break; case 0x02: //! @brief $2102 OAMADDL (OAM Address low byte). + this->_oamadd.oamaddl = data; //! @brief we recreate the oamAddress with the previous oamAddress because there is one bit missing (given by the register $2103) - this->_oamAddress = (this->_oamAddress & 0x100U) | data; break; case 0x03: //! @brief $2103 OAMADDH (OAM Address high bit and Obj Priority) + this->_oamadd.oamaddh = data; //! @brief Same as $2102 we recreate the oamAddress with the previous oamAddress because there are 8 bits missing (given by the register $2102) - this->_oamAddress = (this->_oamAddress & 0xFFU) | ((data & 0x01U) << 8U); - //! @brief The objPriority is given by the first bit of the data - this->_objPriority = (data & 0x80U) >> 7U; break; - case 0x04: - this->oamdata = data; + case 0x04: //! @brief $2104 OAMDATA (Data for OAM write). + //! @brief not implemented yet. + // throw InvalidAddress("PPU Internal Registers write", addr); + this->_oamdata = data; break; - case 0x05: - this->bgmode.raw = data; + case 0x05: //! @brief $2105 BGMODE (BG Mode and Character Size). + this->_bgmode.raw = data; break; case 0x06: - this->mosaic.raw = data; + this->_mosaic.raw = data; break; case 0x07: - this->bg1sc.raw = data; + this->_bg1sc.raw = data; break; case 0x08: - this->bg2sc.raw = data; + this->_bg2sc.raw = data; break; case 0x09: - this->bg3sc.raw = data; + this->_bg3sc.raw = data; break; case 0x0A: - this->bg4sc.raw = data; + this->_bg4sc.raw = data; break; case 0x0B: - this->bg12nba.raw = data; + this->_bg12nba.raw = data; break; case 0x0C: - this->bg34nba.raw = data; + this->_bg34nba.raw = data; break; //TODO adding the rest of the registers. oaf ! default: diff --git a/sources/PPU/PPU.hpp b/sources/PPU/PPU.hpp index a512dc7..375b5af 100644 --- a/sources/PPU/PPU.hpp +++ b/sources/PPU/PPU.hpp @@ -17,6 +17,10 @@ namespace ComSquare::PPU //! @brief The class containing all the registers the PPU class PPU : public Memory::IMemory { private: + /* struct _layerInfo { + bool _characterSize; + }; + struct { unsigned int height; unsigned int width; @@ -28,6 +32,7 @@ namespace ComSquare::PPU unsigned char characterHeight; unsigned char characterWidth; } _BG[4]; + struct object { bool verticalMirroring; bool horizontalMirroring; @@ -36,25 +41,34 @@ namespace ComSquare::PPU }; //! @brief INIDISP variables (F-blank and Brightness) - bool _fBlank; - unsigned short _brightness; //! @brief F=max, 0="off". + struct { + bool _fBlank; + //! @brief F=max, 0="off". + unsigned short _brightness; + } _inidisp; //! @brief OBSEL variables (Object Size and Character Address) - unsigned char _objectSize; //! @brief "OamMode" this contains the size of the Objects (ex: 8x8 and 16x16) - unsigned char _baseSelect; //! @brief "OamBaseAddress" - unsigned char _nameSelect; //! @brief "OamAddressOffset" + struct { + //! @brief "OamMode" this contains the size of the Objects (ex: 8x8 and 16x16) + unsigned char _objectSize; + //! @brief "OamBaseAddress" + unsigned char _baseSelect; + //! @brief "OamAddressOffset" + unsigned char _nameSelect; + } _obsel; //! @brief OAMADD variables (OAM Address and Obj Priority) - uint16_t _oamAddress; - bool _objPriority; + struct { + uint16_t _oamAddress; + bool _objPriority; + } _oamadd; - - - - - - - /// OLD to stuff to refactor + //! @brief BGMODE (BG Mode and Character Size) + struct { + unsigned char _bgMode; + bool _mode1Bg3Priority; + _layerInfo layers[4]; + } _bgmode;*/ @@ -62,48 +76,48 @@ namespace ComSquare::PPU //! @brief INIDISP Register (F-blank and Brightness) union { struct { - bool fblank: 1; - bool _: 3; uint8_t brightness: 4; + bool _: 3; + bool fblank: 1; }; uint8_t raw; - } inidisp; + } _inidisp; //! @brief OBSEL Register (Object Size and Character Address) union { struct { - uint8_t objectSize: 3; - bool nameSelect: 2; uint8_t baseSelect: 3; + bool nameSelect: 2; + uint8_t objectSize: 3; }; uint8_t raw; - } obsel; + } _obsel; //! @brief OAMADD Register (OAM Address and Obj Priority) union { struct { - bool objPriorityActivationBit: 1; - uint8_t _: 6; uint32_t oamAddress: 9; + uint8_t _: 6; + bool objPriorityActivationBit: 1; }; struct { - uint8_t oamaddh; uint8_t oamaddl; + uint8_t oamaddh; }; uint32_t raw; - } oamadd; + } _oamadd; //! @brief OAMDATA Register (Data for OAM write) - uint8_t oamdata; + uint8_t _oamdata; //! @brief BGMODE Register (OAM Address and Obj Priority) union { struct { - bool characterSizeBg4: 1; - bool characterSizeBg3: 1; - bool characterSizeBg2: 1; - bool characterSizeBg1: 1; - bool mode1Bg3PriorityBit: 1; uint8_t bgMode: 3; + bool mode1Bg3PriorityBit: 1; + bool characterSizeBg1: 1; + bool characterSizeBg2: 1; + bool characterSizeBg3: 1; + bool characterSizeBg4: 1; }; uint8_t raw; - } bgmode; + } _bgmode; //! @brief MOSAIC Register (Screen Pixelation) union { struct { @@ -114,7 +128,7 @@ namespace ComSquare::PPU bool affectBg1: 1; }; uint8_t raw; - } mosaic; + } _mosaic; //! @brief BG1SC Register (BG1 Tilemap Address and Size) union { struct { @@ -123,7 +137,7 @@ namespace ComSquare::PPU bool tilemapVerticalMirroring: 1; }; uint8_t raw; - } bg1sc; + } _bg1sc; //! @brief BG2SC Register (BG2 Tilemap Address and Size) union { struct { @@ -132,7 +146,7 @@ namespace ComSquare::PPU bool tilemapVerticalMirroring: 1; }; uint8_t raw; - } bg2sc; + } _bg2sc; //! @brief BG3SC Register (BG3 Tilemap Address and Size) union { struct { @@ -141,7 +155,7 @@ namespace ComSquare::PPU bool tilemapVerticalMirroring: 1; }; uint8_t raw; - } bg3sc; + } _bg3sc; //! @brief BG4SC Register (BG4 Tilemap Address and Size) union { struct { @@ -150,7 +164,7 @@ namespace ComSquare::PPU bool tilemapVerticalMirroring: 1; }; uint8_t raw; - } bg4sc; + } _bg4sc; //! @brief BG12NBA Register (BG1 and 2 Chr Address) union { struct { @@ -158,7 +172,7 @@ namespace ComSquare::PPU uint8_t baseAddressBg1a3: 4; }; uint8_t raw; - } bg12nba; + } _bg12nba; //! @brief BG34NBA Register (BG3 and 4 Chr Address) union { struct { @@ -166,7 +180,7 @@ namespace ComSquare::PPU uint8_t baseAddressBg1a3: 4; }; uint8_t raw; - } bg34nba; + } _bg34nba; //! @brief BG1HOFS Register (BG1 Horizontal Scroll) //! @brief BG1VOFS Register (BG1 Vertical Scroll) union { @@ -175,7 +189,7 @@ namespace ComSquare::PPU uint32_t offsetBg: 10; }; uint16_t raw; - } bg1ofs; + } _bg1ofs; //! @brief M7HOFS Register (Mode 7 _BG Horizontal Scroll) //! @brief M7VOFS Register (Mode 7 _BG Vertical Scroll) union { @@ -184,7 +198,7 @@ namespace ComSquare::PPU uint32_t offsetBg : 13; }; uint8_t raw; - } m7ofs; + } _m7ofs; //! @brief BG2HOFS Register (BG2 Horizontal Scroll) //! @brief BG2VOFS Register (BG2 Vertical Scroll) union { @@ -193,7 +207,7 @@ namespace ComSquare::PPU uint32_t offsetBg: 10; }; uint8_t raw; - } bg2ofs; + } _bg2ofs; //! @brief BG3HOFS Register (BG3 Horizontal Scroll) //! @brief BG3VOFS Register (BG3 Vertical Scroll) union { @@ -202,7 +216,7 @@ namespace ComSquare::PPU uint32_t offsetBg: 10; }; uint8_t raw; - } bg3ofs; + } _bg3ofs; //! @brief BG4HOFS Register (BG4 Horizontal Scroll) //! @brief BG4VOFS Register (BG4 Vertical Scroll) union { @@ -211,7 +225,7 @@ namespace ComSquare::PPU uint32_t offsetBg: 10; }; uint8_t raw; - } bg4ofs; + } _bg4ofs; //! @brief VMAIN Register (Video Port Control) union { struct { @@ -221,7 +235,7 @@ namespace ComSquare::PPU uint8_t incrementCount: 2; }; uint8_t raw; - } vmain; + } _vmain; //! @brief VMADD Register (VRAM Address) union { struct { @@ -229,7 +243,7 @@ namespace ComSquare::PPU uint8_t vmaddl; }; uint32_t vmadd; - } vmadd; + } _vmadd; //! @brief VMDATA Register (VRAM Data Write) union { struct { @@ -237,7 +251,7 @@ namespace ComSquare::PPU uint8_t vmdatal; }; uint32_t vmdata; - } vmdata; + } _vmdata; //! @brief M7SEL Register (Mode 7 Settings) union { struct { @@ -248,7 +262,7 @@ namespace ComSquare::PPU bool verticalMirroring: 1; }; uint8_t raw; - } m7sel; + } _m7sel; //! M7A M7B M7C M7D i didn't understand how they works so they will be added later. //! @brief M7X Register (Mode 7 Center X) union { @@ -257,7 +271,7 @@ namespace ComSquare::PPU uint8_t value; }; uint32_t center; - } m7x; + } _m7x; //! @brief M7Y Register (Mode 7 Center Y) union { struct { @@ -265,9 +279,9 @@ namespace ComSquare::PPU uint8_t value; }; uint32_t center; - } m7y; + } _m7y; //! @brief CGADD Register (CGRAM Address) - uint8_t cgadd; + uint8_t _cgadd; //! @brief CGDATA Register (CGRAM Data write) union { struct { @@ -277,7 +291,7 @@ namespace ComSquare::PPU uint8_t red: 5; }; uint16_t raw; - } cgdata; + } _cgdata; //! @brief W12SEL - W34SEL Registers (Window Mask Settings for BGs) and WOBJSEL Register (Window Mask Settings for OBJ and Color Window) union { struct { @@ -291,7 +305,7 @@ namespace ComSquare::PPU bool window1InversionForBg1Bg2Obj: 1; }; uint8_t raw; - } wsel; + } _wsel; //! @brief WH0 Register (CWindow 1 Left Position) uint8_t wh0; //! @brief WH1 Register (CWindow 1 Right Position) diff --git a/tests/PPU/testPpuWrite.cpp b/tests/PPU/testPpuWrite.cpp new file mode 100644 index 0000000..bde5f52 --- /dev/null +++ b/tests/PPU/testPpuWrite.cpp @@ -0,0 +1,130 @@ +// +// Created by cbihan on 2/10/20. +// + +#include +#include +#include +#include "../tests.hpp" +#include "../../sources/SNES.hpp" +#include "../../sources/Memory/MemoryBus.hpp" +#include "../../sources/PPU/PPU.hpp" +using namespace ComSquare; + +Test(PPU_write, inidisp_data_full_ones) +{ + auto pair = Init(); + pair.first.write(0x2100, 0b11111111); + cr_assert_eq(pair.second.ppu->_inidisp.fblank, true); + cr_assert_eq(pair.second.ppu->_inidisp.brightness, 0xF); +} + +Test(PPU_write, inidisp_data_full_zeros) +{ + auto pair = Init(); + pair.first.write(0x2100, 0b00000000); + cr_assert_eq(pair.second.ppu->_inidisp.fblank, false); + cr_assert_eq(pair.second.ppu->_inidisp.brightness, 0x0); +} + +Test(PPU_write, inidisp_data_fBlank_on_brghtness_off) +{ + auto pair = Init(); + pair.first.write(0x2100, 0b10000000); + cr_assert_eq(pair.second.ppu->_inidisp.fblank, true); + cr_assert_eq(pair.second.ppu->_inidisp.brightness, 0x0); +} + +Test(PPU_write, inidisp_data_fBlank_off_brghtness_max) +{ + auto pair = Init(); + pair.first.write(0x2100, 0b00001111); + cr_assert_eq(pair.second.ppu->_inidisp.fblank, false); + cr_assert_eq(pair.second.ppu->_inidisp.brightness, 0xF); +} + +Test(PPU_write, inidisp_data_fBlank_off_brghtness_half) +{ + auto pair = Init(); + pair.first.write(0x2100, 0b00000101); + cr_assert_eq(pair.second.ppu->_inidisp.fblank, false); + cr_assert_eq(pair.second.ppu->_inidisp.brightness, 0x5); +} + +Test(PPU_write, obsel_111_object_size_and_all_null) +{ + auto pair = Init(); + pair.first.write(0x2101, 0b11100000); + cr_assert_eq(pair.second.ppu->_obsel.objectSize, 0b111); + cr_assert_eq(pair.second.ppu->_obsel.nameSelect, 0b00); + cr_assert_eq(pair.second.ppu->_obsel.baseSelect, 0b000); +} + +Test(PPU_write, obsel_data_full) +{ + auto pair = Init(); + pair.first.write(0x2101, 0b11111111); + cr_assert_eq(pair.second.ppu->_obsel.objectSize, 0b111); + cr_assert_eq(pair.second.ppu->_obsel.nameSelect, 0b11); + cr_assert_eq(pair.second.ppu->_obsel.baseSelect, 0b111); +} + +Test(PPU_write, obsel_data_full_nameselect) +{ + auto pair = Init(); + pair.first.write(0x2101, 0b00011000); + cr_assert_eq(pair.second.ppu->_obsel.objectSize, 0b000); + cr_assert_eq(pair.second.ppu->_obsel.nameSelect, 0b11); + cr_assert_eq(pair.second.ppu->_obsel.baseSelect, 0b000); +} + +Test(PPU_write, obsel_data_full_baseselect) +{ + auto pair = Init(); + pair.first.write(0x2101, 0b00000111); + cr_assert_eq(pair.second.ppu->_obsel.objectSize, 0b000); + cr_assert_eq(pair.second.ppu->_obsel.nameSelect, 0b00); + cr_assert_eq(pair.second.ppu->_obsel.baseSelect, 0b111); +} + +Test(PPU_write, oamaddl_data_full) +{ + auto pair = Init(); + pair.first.write(0x2102, 0b11111111); + cr_assert_eq(pair.second.ppu->_oamadd.oamAddress, 0b011111111); +} + +Test(PPU_write, oamaddh_data_full) +{ + auto pair = Init(); + pair.first.write(0x2103, 0b11111111); + cr_assert_eq(pair.second.ppu->_oamadd.objPriorityActivationBit, true); + cr_assert_eq(pair.second.ppu->_oamadd.oamAddress, 0b100000000); +} + +Test(PPU_write, oamaddlh_data_full) +{ + auto pair = Init(); + pair.first.write(0x2102, 0b11111111); + pair.first.write(0x2103, 0b11111111); + cr_assert_eq(pair.second.ppu->_oamadd.objPriorityActivationBit, true); + cr_assert_eq(pair.second.ppu->_oamadd.oamAddress, 0b111111111); +} + +Test(PPU_write, oamaddlh_data_full_priorityBit_off) +{ + auto pair = Init(); + pair.first.write(0x2102, 0b11111111); + pair.first.write(0x2103, 0b01111111); + cr_assert_eq(pair.second.ppu->_oamadd.objPriorityActivationBit, false); + cr_assert_eq(pair.second.ppu->_oamadd.oamAddress, 0b111111111); +} + +Test(PPU_write, oamaddlh_oamAdress_11_priorityBit_on) +{ + auto pair = Init(); + pair.first.write(0x2102, 0b00001011); + pair.first.write(0x2103, 0b10011100); + cr_assert_eq(pair.second.ppu->_oamadd.objPriorityActivationBit, true); + cr_assert_eq(pair.second.ppu->_oamadd.oamAddress, 11); +} \ No newline at end of file diff --git a/tests/testMemoryBus.cpp b/tests/testMemoryBus.cpp index 49805be..bbc0ebe 100644 --- a/tests/testMemoryBus.cpp +++ b/tests/testMemoryBus.cpp @@ -356,7 +356,7 @@ Test(BusWrite, WritePPU) auto pair = Init(); pair.first.write(0x002106, 123); - cr_assert_eq(pair.second.ppu->mosaic.raw, 123); + cr_assert_eq(pair.second.ppu->_mosaic.raw, 123); } Test(BusWrite, WriteCPU) From 6e49730bf5ed201c2608d3e849699f7714ae763c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Le=20Bihan?= Date: Mon, 10 Feb 2020 16:23:57 +0100 Subject: [PATCH 04/21] adding more tests on PPU write --- sources/PPU/PPU.hpp | 8 +++--- tests/PPU/testPpuWrite.cpp | 57 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 4 deletions(-) diff --git a/sources/PPU/PPU.hpp b/sources/PPU/PPU.hpp index 375b5af..e0bcfe9 100644 --- a/sources/PPU/PPU.hpp +++ b/sources/PPU/PPU.hpp @@ -121,11 +121,11 @@ namespace ComSquare::PPU //! @brief MOSAIC Register (Screen Pixelation) union { struct { - uint8_t pixelSize: 4; - bool affectBg4: 1; - bool affectBg3: 1; - bool affectBg2: 1; bool affectBg1: 1; + bool affectBg2: 1; + bool affectBg3: 1; + bool affectBg4: 1; + uint8_t pixelSize: 4; }; uint8_t raw; } _mosaic; diff --git a/tests/PPU/testPpuWrite.cpp b/tests/PPU/testPpuWrite.cpp index bde5f52..6d54b9d 100644 --- a/tests/PPU/testPpuWrite.cpp +++ b/tests/PPU/testPpuWrite.cpp @@ -127,4 +127,61 @@ Test(PPU_write, oamaddlh_oamAdress_11_priorityBit_on) pair.first.write(0x2103, 0b10011100); cr_assert_eq(pair.second.ppu->_oamadd.objPriorityActivationBit, true); cr_assert_eq(pair.second.ppu->_oamadd.oamAddress, 11); +} + +Test(PPU_write, bgmode_data_full) +{ + auto pair = Init(); + pair.first.write(0x2105, 0b11111111); + cr_assert_eq(pair.second.ppu->_bgmode.bgMode, 7); + cr_assert_eq(pair.second.ppu->_bgmode.characterSizeBg1, true); + cr_assert_eq(pair.second.ppu->_bgmode.characterSizeBg2, true); + cr_assert_eq(pair.second.ppu->_bgmode.characterSizeBg3, true); + cr_assert_eq(pair.second.ppu->_bgmode.characterSizeBg4, true); + cr_assert_eq(pair.second.ppu->_bgmode.mode1Bg3PriorityBit, true); +} + +Test(PPU_write, bgmode_bgmode_5_and_bg24_on) +{ + auto pair = Init(); + pair.first.write(0x2105, 0b10100101); + cr_assert_eq(pair.second.ppu->_bgmode.bgMode, 5); + cr_assert_eq(pair.second.ppu->_bgmode.characterSizeBg1, false); + cr_assert_eq(pair.second.ppu->_bgmode.characterSizeBg2, true); + cr_assert_eq(pair.second.ppu->_bgmode.characterSizeBg3, false); + cr_assert_eq(pair.second.ppu->_bgmode.characterSizeBg4, true); + cr_assert_eq(pair.second.ppu->_bgmode.mode1Bg3PriorityBit, false); +} + +Test(PPU_write, mosaic_data_full) +{ +auto pair = Init(); +pair.first.write(0x2106, 0b11111111); +cr_assert_eq(pair.second.ppu->_mosaic.affectBg1, true); +cr_assert_eq(pair.second.ppu->_mosaic.affectBg2, true); +cr_assert_eq(pair.second.ppu->_mosaic.affectBg3, true); +cr_assert_eq(pair.second.ppu->_mosaic.affectBg4, true); +cr_assert_eq(pair.second.ppu->_mosaic.pixelSize, 0xF); +} + +Test(PPU_write, mosaic_affectbg23_w_1x1_size) +{ +auto pair = Init(); +pair.first.write(0x2106, 0b00000110); +cr_assert_eq(pair.second.ppu->_mosaic.affectBg1, false); +cr_assert_eq(pair.second.ppu->_mosaic.affectBg2, true); +cr_assert_eq(pair.second.ppu->_mosaic.affectBg3, true); +cr_assert_eq(pair.second.ppu->_mosaic.affectBg4, false); +cr_assert_eq(pair.second.ppu->_mosaic.pixelSize, 0x0); +} + +Test(PPU_write, mosaic_affectbg14_w_2x2_size) +{ +auto pair = Init(); +pair.first.write(0x2106, 0b00101001); +cr_assert_eq(pair.second.ppu->_mosaic.affectBg1, true); +cr_assert_eq(pair.second.ppu->_mosaic.affectBg2, false); +cr_assert_eq(pair.second.ppu->_mosaic.affectBg3, false); +cr_assert_eq(pair.second.ppu->_mosaic.affectBg4, true); +cr_assert_eq(pair.second.ppu->_mosaic.pixelSize, 0x2); } \ No newline at end of file From 0b442450a5f3fa0a1a573ddef5c042507f97fa97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Le=20Bihan?= Date: Mon, 10 Feb 2020 16:28:57 +0100 Subject: [PATCH 05/21] merge --- CMakeLists.txt | 4 ---- tests/PPU/testPpuWrite.cpp | 44 +++++++++++++++++++------------------- tests/testMemoryBus.cpp | 7 +----- 3 files changed, 23 insertions(+), 32 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5ce3327..ec0caad 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -52,15 +52,11 @@ add_executable(unit_tests sources/CPU/Instructions/CommonInstructions.hpp sources/Exceptions/InvalidOpcode.hpp sources/CPU/Instructions/Interrupts.cpp -<<<<<<< HEAD sources/CPU/Instructions/MathematicalOperations.cpp tests/CPU/testAddressingMode.cpp tests/tests.cpp tests/PPU/testPpuWrite.cpp ) -======= - sources/CPU/Instructions/MathematicalOperations.cpp) ->>>>>>> aeb1e127f381998d0a572712afb43ef657f5024d # include criterion & coverage target_link_libraries(unit_tests criterion -lgcov) diff --git a/tests/PPU/testPpuWrite.cpp b/tests/PPU/testPpuWrite.cpp index 6d54b9d..1b4170d 100644 --- a/tests/PPU/testPpuWrite.cpp +++ b/tests/PPU/testPpuWrite.cpp @@ -14,7 +14,7 @@ using namespace ComSquare; Test(PPU_write, inidisp_data_full_ones) { auto pair = Init(); - pair.first.write(0x2100, 0b11111111); + pair.first->write(0x2100, 0b11111111); cr_assert_eq(pair.second.ppu->_inidisp.fblank, true); cr_assert_eq(pair.second.ppu->_inidisp.brightness, 0xF); } @@ -22,7 +22,7 @@ Test(PPU_write, inidisp_data_full_ones) Test(PPU_write, inidisp_data_full_zeros) { auto pair = Init(); - pair.first.write(0x2100, 0b00000000); + pair.first->write(0x2100, 0b00000000); cr_assert_eq(pair.second.ppu->_inidisp.fblank, false); cr_assert_eq(pair.second.ppu->_inidisp.brightness, 0x0); } @@ -30,7 +30,7 @@ Test(PPU_write, inidisp_data_full_zeros) Test(PPU_write, inidisp_data_fBlank_on_brghtness_off) { auto pair = Init(); - pair.first.write(0x2100, 0b10000000); + pair.first->write(0x2100, 0b10000000); cr_assert_eq(pair.second.ppu->_inidisp.fblank, true); cr_assert_eq(pair.second.ppu->_inidisp.brightness, 0x0); } @@ -38,7 +38,7 @@ Test(PPU_write, inidisp_data_fBlank_on_brghtness_off) Test(PPU_write, inidisp_data_fBlank_off_brghtness_max) { auto pair = Init(); - pair.first.write(0x2100, 0b00001111); + pair.first->write(0x2100, 0b00001111); cr_assert_eq(pair.second.ppu->_inidisp.fblank, false); cr_assert_eq(pair.second.ppu->_inidisp.brightness, 0xF); } @@ -46,7 +46,7 @@ Test(PPU_write, inidisp_data_fBlank_off_brghtness_max) Test(PPU_write, inidisp_data_fBlank_off_brghtness_half) { auto pair = Init(); - pair.first.write(0x2100, 0b00000101); + pair.first->write(0x2100, 0b00000101); cr_assert_eq(pair.second.ppu->_inidisp.fblank, false); cr_assert_eq(pair.second.ppu->_inidisp.brightness, 0x5); } @@ -54,7 +54,7 @@ Test(PPU_write, inidisp_data_fBlank_off_brghtness_half) Test(PPU_write, obsel_111_object_size_and_all_null) { auto pair = Init(); - pair.first.write(0x2101, 0b11100000); + pair.first->write(0x2101, 0b11100000); cr_assert_eq(pair.second.ppu->_obsel.objectSize, 0b111); cr_assert_eq(pair.second.ppu->_obsel.nameSelect, 0b00); cr_assert_eq(pair.second.ppu->_obsel.baseSelect, 0b000); @@ -63,7 +63,7 @@ Test(PPU_write, obsel_111_object_size_and_all_null) Test(PPU_write, obsel_data_full) { auto pair = Init(); - pair.first.write(0x2101, 0b11111111); + pair.first->write(0x2101, 0b11111111); cr_assert_eq(pair.second.ppu->_obsel.objectSize, 0b111); cr_assert_eq(pair.second.ppu->_obsel.nameSelect, 0b11); cr_assert_eq(pair.second.ppu->_obsel.baseSelect, 0b111); @@ -72,7 +72,7 @@ Test(PPU_write, obsel_data_full) Test(PPU_write, obsel_data_full_nameselect) { auto pair = Init(); - pair.first.write(0x2101, 0b00011000); + pair.first->write(0x2101, 0b00011000); cr_assert_eq(pair.second.ppu->_obsel.objectSize, 0b000); cr_assert_eq(pair.second.ppu->_obsel.nameSelect, 0b11); cr_assert_eq(pair.second.ppu->_obsel.baseSelect, 0b000); @@ -81,7 +81,7 @@ Test(PPU_write, obsel_data_full_nameselect) Test(PPU_write, obsel_data_full_baseselect) { auto pair = Init(); - pair.first.write(0x2101, 0b00000111); + pair.first->write(0x2101, 0b00000111); cr_assert_eq(pair.second.ppu->_obsel.objectSize, 0b000); cr_assert_eq(pair.second.ppu->_obsel.nameSelect, 0b00); cr_assert_eq(pair.second.ppu->_obsel.baseSelect, 0b111); @@ -90,14 +90,14 @@ Test(PPU_write, obsel_data_full_baseselect) Test(PPU_write, oamaddl_data_full) { auto pair = Init(); - pair.first.write(0x2102, 0b11111111); + pair.first->write(0x2102, 0b11111111); cr_assert_eq(pair.second.ppu->_oamadd.oamAddress, 0b011111111); } Test(PPU_write, oamaddh_data_full) { auto pair = Init(); - pair.first.write(0x2103, 0b11111111); + pair.first->write(0x2103, 0b11111111); cr_assert_eq(pair.second.ppu->_oamadd.objPriorityActivationBit, true); cr_assert_eq(pair.second.ppu->_oamadd.oamAddress, 0b100000000); } @@ -105,8 +105,8 @@ Test(PPU_write, oamaddh_data_full) Test(PPU_write, oamaddlh_data_full) { auto pair = Init(); - pair.first.write(0x2102, 0b11111111); - pair.first.write(0x2103, 0b11111111); + pair.first->write(0x2102, 0b11111111); + pair.first->write(0x2103, 0b11111111); cr_assert_eq(pair.second.ppu->_oamadd.objPriorityActivationBit, true); cr_assert_eq(pair.second.ppu->_oamadd.oamAddress, 0b111111111); } @@ -114,8 +114,8 @@ Test(PPU_write, oamaddlh_data_full) Test(PPU_write, oamaddlh_data_full_priorityBit_off) { auto pair = Init(); - pair.first.write(0x2102, 0b11111111); - pair.first.write(0x2103, 0b01111111); + pair.first->write(0x2102, 0b11111111); + pair.first->write(0x2103, 0b01111111); cr_assert_eq(pair.second.ppu->_oamadd.objPriorityActivationBit, false); cr_assert_eq(pair.second.ppu->_oamadd.oamAddress, 0b111111111); } @@ -123,8 +123,8 @@ Test(PPU_write, oamaddlh_data_full_priorityBit_off) Test(PPU_write, oamaddlh_oamAdress_11_priorityBit_on) { auto pair = Init(); - pair.first.write(0x2102, 0b00001011); - pair.first.write(0x2103, 0b10011100); + pair.first->write(0x2102, 0b00001011); + pair.first->write(0x2103, 0b10011100); cr_assert_eq(pair.second.ppu->_oamadd.objPriorityActivationBit, true); cr_assert_eq(pair.second.ppu->_oamadd.oamAddress, 11); } @@ -132,7 +132,7 @@ Test(PPU_write, oamaddlh_oamAdress_11_priorityBit_on) Test(PPU_write, bgmode_data_full) { auto pair = Init(); - pair.first.write(0x2105, 0b11111111); + pair.first->write(0x2105, 0b11111111); cr_assert_eq(pair.second.ppu->_bgmode.bgMode, 7); cr_assert_eq(pair.second.ppu->_bgmode.characterSizeBg1, true); cr_assert_eq(pair.second.ppu->_bgmode.characterSizeBg2, true); @@ -144,7 +144,7 @@ Test(PPU_write, bgmode_data_full) Test(PPU_write, bgmode_bgmode_5_and_bg24_on) { auto pair = Init(); - pair.first.write(0x2105, 0b10100101); + pair.first->write(0x2105, 0b10100101); cr_assert_eq(pair.second.ppu->_bgmode.bgMode, 5); cr_assert_eq(pair.second.ppu->_bgmode.characterSizeBg1, false); cr_assert_eq(pair.second.ppu->_bgmode.characterSizeBg2, true); @@ -156,7 +156,7 @@ Test(PPU_write, bgmode_bgmode_5_and_bg24_on) Test(PPU_write, mosaic_data_full) { auto pair = Init(); -pair.first.write(0x2106, 0b11111111); +pair.first->write(0x2106, 0b11111111); cr_assert_eq(pair.second.ppu->_mosaic.affectBg1, true); cr_assert_eq(pair.second.ppu->_mosaic.affectBg2, true); cr_assert_eq(pair.second.ppu->_mosaic.affectBg3, true); @@ -167,7 +167,7 @@ cr_assert_eq(pair.second.ppu->_mosaic.pixelSize, 0xF); Test(PPU_write, mosaic_affectbg23_w_1x1_size) { auto pair = Init(); -pair.first.write(0x2106, 0b00000110); +pair.first->write(0x2106, 0b00000110); cr_assert_eq(pair.second.ppu->_mosaic.affectBg1, false); cr_assert_eq(pair.second.ppu->_mosaic.affectBg2, true); cr_assert_eq(pair.second.ppu->_mosaic.affectBg3, true); @@ -178,7 +178,7 @@ cr_assert_eq(pair.second.ppu->_mosaic.pixelSize, 0x0); Test(PPU_write, mosaic_affectbg14_w_2x2_size) { auto pair = Init(); -pair.first.write(0x2106, 0b00101001); +pair.first->write(0x2106, 0b00101001); cr_assert_eq(pair.second.ppu->_mosaic.affectBg1, true); cr_assert_eq(pair.second.ppu->_mosaic.affectBg2, false); cr_assert_eq(pair.second.ppu->_mosaic.affectBg3, false); diff --git a/tests/testMemoryBus.cpp b/tests/testMemoryBus.cpp index d254155..80b8207 100644 --- a/tests/testMemoryBus.cpp +++ b/tests/testMemoryBus.cpp @@ -355,13 +355,8 @@ Test(BusWrite, WritePPU) { auto pair = Init(); -<<<<<<< HEAD - pair.first.write(0x002106, 123); - cr_assert_eq(pair.second.ppu->_mosaic.raw, 123); -======= pair.first->write(0x002106, 123); - cr_assert_eq(pair.second.ppu->mosaic.raw, 123); ->>>>>>> aeb1e127f381998d0a572712afb43ef657f5024d + cr_assert_eq(pair.second.ppu->_mosaic.raw, 123); } Test(BusWrite, WriteCPU) From b4a0a23069f4eed62832056dfa2f037745f804ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Le=20Bihan?= Date: Mon, 10 Feb 2020 17:49:11 +0100 Subject: [PATCH 06/21] more tests --- sources/PPU/PPU.cpp | 26 +++----- sources/PPU/PPU.hpp | 37 ++---------- tests/PPU/testPpuWrite.cpp | 120 ++++++++++++++++++++++++++++++------- 3 files changed, 113 insertions(+), 70 deletions(-) diff --git a/sources/PPU/PPU.cpp b/sources/PPU/PPU.cpp index a5db727..2cf58d3 100644 --- a/sources/PPU/PPU.cpp +++ b/sources/PPU/PPU.cpp @@ -47,26 +47,18 @@ namespace ComSquare::PPU case 0x05: //! @brief $2105 BGMODE (BG Mode and Character Size). this->_bgmode.raw = data; break; - case 0x06: + case 0x06: //! $2106 MOSAIC (Screen Pixelation) this->_mosaic.raw = data; break; - case 0x07: - this->_bg1sc.raw = data; + case 0x07: // BG1SC (BG1 Tilemap Address and Size) + case 0x08: // BG2SC (BG2 Tilemap Address and Size) + case 0x09: //! @brief BG3SC (BG3 Tilemap Address and Size) + case 0x0A: //! @brief BG4SC (BG4 Tilemap Address and Size) + this->_bgsc[addr - 0x07].raw = data; break; - case 0x08: - this->_bg2sc.raw = data; - break; - case 0x09: - this->_bg3sc.raw = data; - break; - case 0x0A: - this->_bg4sc.raw = data; - break; - case 0x0B: - this->_bg12nba.raw = data; - break; - case 0x0C: - this->_bg34nba.raw = data; + case 0x0B: //! @brief BG12NBA (BG1 and 2 Chr Address) + case 0x0C: //! @brief BG34NBA (BG3 and 4 Chr Address) + this->_bgnba[addr - 0x0B].raw = data; break; //TODO adding the rest of the registers. oaf ! default: diff --git a/sources/PPU/PPU.hpp b/sources/PPU/PPU.hpp index e0bcfe9..f6db2f5 100644 --- a/sources/PPU/PPU.hpp +++ b/sources/PPU/PPU.hpp @@ -129,50 +129,23 @@ namespace ComSquare::PPU }; uint8_t raw; } _mosaic; - //! @brief BG1SC Register (BG1 Tilemap Address and Size) + //! @brief BGSC Registers (BG Tilemap Address and Size) union { struct { - uint8_t tilemapAddress: 6; bool tilemapHorizontalMirroring: 1; bool tilemapVerticalMirroring: 1; - }; - uint8_t raw; - } _bg1sc; - //! @brief BG2SC Register (BG2 Tilemap Address and Size) - union { - struct { uint8_t tilemapAddress: 6; - bool tilemapHorizontalMirroring: 1; - bool tilemapVerticalMirroring: 1; }; uint8_t raw; - } _bg2sc; - //! @brief BG3SC Register (BG3 Tilemap Address and Size) + } _bgsc[4]; + //! @brief BGNBA Registers (BG1/2/3/4 Chr Address) union { struct { - uint8_t tilemapAddress: 6; - bool tilemapHorizontalMirroring: 1; - bool tilemapVerticalMirroring: 1; - }; - uint8_t raw; - } _bg3sc; - //! @brief BG4SC Register (BG4 Tilemap Address and Size) - union { - struct { - uint8_t tilemapAddress: 6; - bool tilemapHorizontalMirroring: 1; - bool tilemapVerticalMirroring: 1; - }; - uint8_t raw; - } _bg4sc; - //! @brief BG12NBA Register (BG1 and 2 Chr Address) - union { - struct { - uint8_t baseAddressBg2a4: 4; uint8_t baseAddressBg1a3: 4; + uint8_t baseAddressBg2a4: 4; }; uint8_t raw; - } _bg12nba; + } _bgnba[2]; //! @brief BG34NBA Register (BG3 and 4 Chr Address) union { struct { diff --git a/tests/PPU/testPpuWrite.cpp b/tests/PPU/testPpuWrite.cpp index 1b4170d..27e3b00 100644 --- a/tests/PPU/testPpuWrite.cpp +++ b/tests/PPU/testPpuWrite.cpp @@ -155,33 +155,111 @@ Test(PPU_write, bgmode_bgmode_5_and_bg24_on) Test(PPU_write, mosaic_data_full) { -auto pair = Init(); -pair.first->write(0x2106, 0b11111111); -cr_assert_eq(pair.second.ppu->_mosaic.affectBg1, true); -cr_assert_eq(pair.second.ppu->_mosaic.affectBg2, true); -cr_assert_eq(pair.second.ppu->_mosaic.affectBg3, true); -cr_assert_eq(pair.second.ppu->_mosaic.affectBg4, true); -cr_assert_eq(pair.second.ppu->_mosaic.pixelSize, 0xF); + auto pair = Init(); + pair.first->write(0x2106, 0b11111111); + cr_assert_eq(pair.second.ppu->_mosaic.affectBg1, true); + cr_assert_eq(pair.second.ppu->_mosaic.affectBg2, true); + cr_assert_eq(pair.second.ppu->_mosaic.affectBg3, true); + cr_assert_eq(pair.second.ppu->_mosaic.affectBg4, true); + cr_assert_eq(pair.second.ppu->_mosaic.pixelSize, 0xF); } Test(PPU_write, mosaic_affectbg23_w_1x1_size) { -auto pair = Init(); -pair.first->write(0x2106, 0b00000110); -cr_assert_eq(pair.second.ppu->_mosaic.affectBg1, false); -cr_assert_eq(pair.second.ppu->_mosaic.affectBg2, true); -cr_assert_eq(pair.second.ppu->_mosaic.affectBg3, true); -cr_assert_eq(pair.second.ppu->_mosaic.affectBg4, false); -cr_assert_eq(pair.second.ppu->_mosaic.pixelSize, 0x0); + auto pair = Init(); + pair.first->write(0x2106, 0b00000110); + cr_assert_eq(pair.second.ppu->_mosaic.affectBg1, false); + cr_assert_eq(pair.second.ppu->_mosaic.affectBg2, true); + cr_assert_eq(pair.second.ppu->_mosaic.affectBg3, true); + cr_assert_eq(pair.second.ppu->_mosaic.affectBg4, false); + cr_assert_eq(pair.second.ppu->_mosaic.pixelSize, 0x0); } Test(PPU_write, mosaic_affectbg14_w_2x2_size) { -auto pair = Init(); -pair.first->write(0x2106, 0b00101001); -cr_assert_eq(pair.second.ppu->_mosaic.affectBg1, true); -cr_assert_eq(pair.second.ppu->_mosaic.affectBg2, false); -cr_assert_eq(pair.second.ppu->_mosaic.affectBg3, false); -cr_assert_eq(pair.second.ppu->_mosaic.affectBg4, true); -cr_assert_eq(pair.second.ppu->_mosaic.pixelSize, 0x2); + auto pair = Init(); + pair.first->write(0x2106, 0b00101001); + cr_assert_eq(pair.second.ppu->_mosaic.affectBg1, true); + cr_assert_eq(pair.second.ppu->_mosaic.affectBg2, false); + cr_assert_eq(pair.second.ppu->_mosaic.affectBg3, false); + cr_assert_eq(pair.second.ppu->_mosaic.affectBg4, true); + cr_assert_eq(pair.second.ppu->_mosaic.pixelSize, 0x2); +} + +Test(PPU_write, bg1sc_data_full) +{ + auto pair = Init(); + pair.first->write(0x2107, 0b11111111); + cr_assert_eq(pair.second.ppu->_bgsc[0].tilemapAddress, 0b111111); + cr_assert_eq(pair.second.ppu->_bgsc[0].tilemapHorizontalMirroring, true); + cr_assert_eq(pair.second.ppu->_bgsc[0].tilemapVerticalMirroring, true); +} + +Test(PPU_write, bg2sc_data_full) +{ + auto pair = Init(); + pair.first->write(0x2108, 0b11111111); + cr_assert_eq(pair.second.ppu->_bgsc[1].tilemapAddress, 0b111111); + cr_assert_eq(pair.second.ppu->_bgsc[1].tilemapHorizontalMirroring, true); + cr_assert_eq(pair.second.ppu->_bgsc[1].tilemapVerticalMirroring, true); +} + +Test(PPU_write, bg3sc_data_full) +{ + auto pair = Init(); + pair.first->write(0x2109, 0b11111111); + cr_assert_eq(pair.second.ppu->_bgsc[2].tilemapAddress, 0b111111); + cr_assert_eq(pair.second.ppu->_bgsc[2].tilemapHorizontalMirroring, true); + cr_assert_eq(pair.second.ppu->_bgsc[2].tilemapVerticalMirroring, true); +} + +Test(PPU_write, bg4sc_data_full) +{ + auto pair = Init(); + pair.first->write(0x210A, 0b11111111); + cr_assert_eq(pair.second.ppu->_bgsc[3].tilemapAddress, 0b111111); + cr_assert_eq(pair.second.ppu->_bgsc[3].tilemapHorizontalMirroring, true); + cr_assert_eq(pair.second.ppu->_bgsc[3].tilemapVerticalMirroring, true); +} + +Test(PPU_write, bg4sc_data_null) +{ + auto pair = Init(); + pair.first->write(0x210A, 0b00000000); + cr_assert_eq(pair.second.ppu->_bgsc[3].tilemapAddress, 0); + cr_assert_eq(pair.second.ppu->_bgsc[3].tilemapHorizontalMirroring, false); + cr_assert_eq(pair.second.ppu->_bgsc[3].tilemapVerticalMirroring, false); +} + +Test(PPU_write, bg4sc_horizontal_off_vertical_on_random_tilemapAdress) +{ + auto pair = Init(); + pair.first->write(0x210A, 0b11000110); + cr_assert_eq(pair.second.ppu->_bgsc[3].tilemapAddress, 0b110001); + cr_assert_eq(pair.second.ppu->_bgsc[3].tilemapHorizontalMirroring, false); + cr_assert_eq(pair.second.ppu->_bgsc[3].tilemapVerticalMirroring, true); +} + +Test(PPU_write, bg12nba_data_full) +{ + auto pair = Init(); + pair.first->write(0x210B, 0b11111111); + cr_assert_eq(pair.second.ppu->_bgnba[0].baseAddressBg1a3, 0b1111); + cr_assert_eq(pair.second.ppu->_bgnba[0].baseAddressBg2a4, 0b1111); +} + +Test(PPU_write, bg34nba_data_full) +{ + auto pair = Init(); + pair.first->write(0x210C, 0b11111111); + cr_assert_eq(pair.second.ppu->_bgnba[1].baseAddressBg1a3, 0b1111); + cr_assert_eq(pair.second.ppu->_bgnba[1].baseAddressBg2a4, 0b1111); +} + +Test(PPU_write, bg12nba_data_random_data) +{ + auto pair = Init(); + pair.first->write(0x210B, 0b10101010); + cr_assert_eq(pair.second.ppu->_bgnba[0].baseAddressBg1a3, 0b1010); + cr_assert_eq(pair.second.ppu->_bgnba[0].baseAddressBg2a4, 0b1010); } \ No newline at end of file From b2a60efb4e5c7aa8a68f56f3b8b0d83932393c89 Mon Sep 17 00:00:00 2001 From: AnonymusRaccoon Date: Tue, 11 Feb 2020 15:53:37 +0100 Subject: [PATCH 07/21] Finishing the ADC --- CMakeLists.txt | 4 +- .../Instructions/MathematicalOperations.cpp | 17 +++- tests/CPU/{testCPU.cpp => testInterupts.cpp} | 0 tests/CPU/testMath.cpp | 82 +++++++++++++++++++ 4 files changed, 99 insertions(+), 4 deletions(-) rename tests/CPU/{testCPU.cpp => testInterupts.cpp} (100%) create mode 100644 tests/CPU/testMath.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 05bc6a6..d8246de 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,7 +11,7 @@ add_compile_options(-W -Wall -Wextra -Wshadow) add_executable(unit_tests tests/CPU/testAddressingMode.cpp tests/tests.cpp - tests/CPU/testCPU.cpp + tests/CPU/testInterupts.cpp tests/testMemoryBus.cpp tests/tests.hpp sources/SNES.cpp @@ -52,7 +52,7 @@ add_executable(unit_tests sources/CPU/Instructions/CommonInstructions.hpp sources/Exceptions/InvalidOpcode.hpp sources/CPU/Instructions/Interrupts.cpp - sources/CPU/Instructions/MathematicalOperations.cpp) + sources/CPU/Instructions/MathematicalOperations.cpp tests/CPU/testMath.cpp) # include criterion & coverage target_link_libraries(unit_tests criterion -lgcov) diff --git a/sources/CPU/Instructions/MathematicalOperations.cpp b/sources/CPU/Instructions/MathematicalOperations.cpp index e1b205c..ee1b6c7 100644 --- a/sources/CPU/Instructions/MathematicalOperations.cpp +++ b/sources/CPU/Instructions/MathematicalOperations.cpp @@ -2,14 +2,27 @@ // Created by anonymus-raccoon on 2/10/20. // +#include #include "../CPU.hpp" namespace ComSquare::CPU { int CPU::ADC(uint24_t valueAddr) { -// this->_registers.a += - (void)valueAddr; + unsigned value = this->_bus->read(valueAddr) + this->_registers.p.c; + unsigned negativeMask = this->_isEmulationMode ? 0xF0u : 0xF000u; + unsigned maxValue = this->_isEmulationMode ? UINT8_MAX : UINT16_MAX; + + this->_registers.p.c = static_cast(this->_registers.a) + value > maxValue; + if ((this->_registers.a & negativeMask) == (value & negativeMask)) + this->_registers.p.v = (this->_registers.a & negativeMask) != ((this->_registers.a + value) & negativeMask); + else + this->_registers.p.v = false; + this->_registers.a += value; + if (this->_isEmulationMode) + this->_registers.a %= 0x100; + this->_registers.p.z = this->_registers.a == 0; + this->_registers.p.n = this->_registers.a & negativeMask; return (0); } } \ No newline at end of file diff --git a/tests/CPU/testCPU.cpp b/tests/CPU/testInterupts.cpp similarity index 100% rename from tests/CPU/testCPU.cpp rename to tests/CPU/testInterupts.cpp diff --git a/tests/CPU/testMath.cpp b/tests/CPU/testMath.cpp new file mode 100644 index 0000000..0a07f97 --- /dev/null +++ b/tests/CPU/testMath.cpp @@ -0,0 +1,82 @@ +// +// Created by anonymus-raccoon on 2/11/20. +// + +#include +#include +#include +#include "../tests.hpp" +#include "../../sources/SNES.hpp" +#include "../../sources/Memory/MemoryBus.hpp" +using namespace ComSquare; + +Test(ADC, addingOne) +{ + auto pair = Init(); + pair.second.cpu->_isEmulationMode = false; + pair.second.cpu->_registers.a = 0; + pair.second.wram->_data[0] = 0x1; + pair.second.cpu->ADC(0x0); + cr_assert_eq(pair.second.cpu->_registers.a, 1, "The accumulator's value should be 0x1 but it was 0x%x.", pair.second.cpu->_registers.a); + cr_assert_eq(pair.second.cpu->_registers.p.c, false, "The carry flags should not be set."); + cr_assert_eq(pair.second.cpu->_registers.p.v, false, "The overflow flags should not be set."); + cr_assert_eq(pair.second.cpu->_registers.p.n, false, "The negative flags should not be set."); + cr_assert_eq(pair.second.cpu->_registers.p.z, false, "The zero flags should not be set."); +} + +Test(ADC, addingOneEmulation) +{ + auto pair = Init(); + pair.second.cpu->_isEmulationMode = true; + pair.second.cpu->_registers.a = 0; + pair.second.wram->_data[0] = 0x1; + pair.second.cpu->ADC(0x0); + cr_assert_eq(pair.second.cpu->_registers.a, 1, "The accumulator's value should be 0x1 but it was 0x%x.", pair.second.cpu->_registers.a); + cr_assert_eq(pair.second.cpu->_registers.p.c, false, "The carry flags should not be set."); + cr_assert_eq(pair.second.cpu->_registers.p.v, false, "The overflow flags should not be set."); + cr_assert_eq(pair.second.cpu->_registers.p.n, false, "The negative flags should not be set."); + cr_assert_eq(pair.second.cpu->_registers.p.z, false, "The zero flags should not be set."); +} + +Test(ADC, overflow) +{ + auto pair = Init(); + pair.second.cpu->_isEmulationMode = false; + pair.second.cpu->_registers.a = 0xFFFF; + pair.second.wram->_data[0] = 0x1; + pair.second.cpu->ADC(0x0); + cr_assert_eq(pair.second.cpu->_registers.a, 0, "The accumulator's value should be 0x0 but it was 0x%x.", pair.second.cpu->_registers.a); + cr_assert_eq(pair.second.cpu->_registers.p.c, true, "The carry flags should be set."); + cr_assert_eq(pair.second.cpu->_registers.p.v, false, "The overflow flags should not be set."); + cr_assert_eq(pair.second.cpu->_registers.p.n, false, "The negative flags should not be set."); + cr_assert_eq(pair.second.cpu->_registers.p.z, true, "The zero flags should be set."); +} + +Test(ADC, overflowEmulation) +{ + auto pair = Init(); + pair.second.cpu->_isEmulationMode = true; + pair.second.cpu->_registers.a = 0xFF; + pair.second.wram->_data[0] = 0x1; + pair.second.cpu->ADC(0x0); + cr_assert_eq(pair.second.cpu->_registers.a, 0, "The accumulator's value should be 0x0 but it was 0x%x.", pair.second.cpu->_registers.a); + cr_assert_eq(pair.second.cpu->_registers.p.c, true, "The carry flags should be set."); + cr_assert_eq(pair.second.cpu->_registers.p.v, false, "The overflow flags should not be set."); + cr_assert_eq(pair.second.cpu->_registers.p.n, false, "The negative flags should not be set."); + cr_assert_eq(pair.second.cpu->_registers.p.z, true, "The zero flags should be set."); +} + + +Test(ADC, signedOverflow) +{ + auto pair = Init(); + pair.second.cpu->_isEmulationMode = false; + pair.second.cpu->_registers.a = 0x0FFF; + pair.second.wram->_data[0] = 0x1; + pair.second.cpu->ADC(0x0); + cr_assert_eq(pair.second.cpu->_registers.a, 0x1000, "The accumulator's value should be 0xF000 but it was 0x%x.", pair.second.cpu->_registers.a); + cr_assert_eq(pair.second.cpu->_registers.p.c, false, "The carry flags should not be set."); + cr_assert_eq(pair.second.cpu->_registers.p.v, true, "The overflow flags should be set."); + cr_assert_eq(pair.second.cpu->_registers.p.n, true, "The negative flags should be set."); + cr_assert_eq(pair.second.cpu->_registers.p.z, false, "The zero flags should not be set."); +} \ No newline at end of file From 45f3debc0f4c330ab78bcd615c27fb1e7fb91959 Mon Sep 17 00:00:00 2001 From: AnonymusRaccoon Date: Tue, 11 Feb 2020 15:55:11 +0100 Subject: [PATCH 08/21] Adding a last test for the ADC --- tests/CPU/testMath.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/CPU/testMath.cpp b/tests/CPU/testMath.cpp index 0a07f97..79d5723 100644 --- a/tests/CPU/testMath.cpp +++ b/tests/CPU/testMath.cpp @@ -79,4 +79,18 @@ Test(ADC, signedOverflow) cr_assert_eq(pair.second.cpu->_registers.p.v, true, "The overflow flags should be set."); cr_assert_eq(pair.second.cpu->_registers.p.n, true, "The negative flags should be set."); cr_assert_eq(pair.second.cpu->_registers.p.z, false, "The zero flags should not be set."); +} + +Test(ADC, signedOverflowEmulated) +{ + auto pair = Init(); + pair.second.cpu->_isEmulationMode = true; + pair.second.cpu->_registers.a = 0x000F; + pair.second.wram->_data[0] = 0x1; + pair.second.cpu->ADC(0x0); + cr_assert_eq(pair.second.cpu->_registers.a, 0x0010, "The accumulator's value should be 0xF000 but it was 0x%x.", pair.second.cpu->_registers.a); + cr_assert_eq(pair.second.cpu->_registers.p.c, false, "The carry flags should not be set."); + cr_assert_eq(pair.second.cpu->_registers.p.v, true, "The overflow flags should be set."); + cr_assert_eq(pair.second.cpu->_registers.p.n, true, "The negative flags should be set."); + cr_assert_eq(pair.second.cpu->_registers.p.z, false, "The zero flags should not be set."); } \ No newline at end of file From d0f639ff4c49bcbb9149e6607d5d75322df18c90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Le=20Bihan?= Date: Tue, 11 Feb 2020 16:20:16 +0100 Subject: [PATCH 09/21] added enum and tests --- sources/PPU/PPU.hpp | 132 ++++++++++++++++++++++++---- tests/PPU/testPpuWriteFromVmain.cpp | 48 ++++++++++ 2 files changed, 163 insertions(+), 17 deletions(-) create mode 100644 tests/PPU/testPpuWriteFromVmain.cpp diff --git a/sources/PPU/PPU.hpp b/sources/PPU/PPU.hpp index 66ba86c..a8e3791 100644 --- a/sources/PPU/PPU.hpp +++ b/sources/PPU/PPU.hpp @@ -8,12 +8,115 @@ #include #include "../Memory/IMemory.hpp" -#define max2BitTiles 4096 -#define max4BitTiles 2048 -#define max8BitTiles 1024 +//#define max2BitTiles 4096 +//#define max4BitTiles 2048 +//#define max8BitTiles 1024 + + namespace ComSquare::PPU { + + enum ppuRegisters { + //! @brief INIDISP Register (F-blank and Brightness) + inidisp = 0x00, + //! @brief OBSEL Register (Object Size and Character Address) + obsel = 0x01, + //! @brief OAMADDL (OAM Address low byte) + oamaddl = 0x02, + //! @brief OAMADDH (OAM Address high bit and Obj Priority) + oamaddh = 0x03, + //! @brief OAMDATA (Data for OAM write) + oamdata = 0x04, + //! @brief BGMODE (BG Mode and Character Size) + bgmode = 0x05, + //! @brief MOSAIC (Screen Pixelation) + mosaic = 0x06, + //! @brief BG1SC (BG1 Tilemap Address and Size) + bg1sc = 0x07, + //! @brief BG2SC (BG2 Tilemap Address and Size) + bg2sc = 0x08, + //! @brief BG3SC (BG3 Tilemap Address and Size) + bg3sc = 0x09, + //! @brief BG4SC (BG4 Tilemap Address and Size) + bg4sc = 0x0A, + //! @brief BG12NBA (BG1 and 2 Chr Address) + bg12nba = 0x0B, + //! @brief BG34NBA (BG3 and 4 Chr Address) + bg34nba = 0x0C, + //! @info When bg mode is 7 the register is used as M7HOFS + bg1hofs = 0x0D, + //! @info When bg mode is 7 the register is used as M7VOFS + bg1vofs = 0x0E, + bg2hofs = 0x0F, + bg2vofs = 0x10, + bg3hofs = 0x11, + bg3vofs = 0x12, + bg4hofs = 0x13, + bg4vofs = 0x14, + vmain = 0x15, + vmaddl = 0x16, + vamddh = 0x17, + vmdatal = 0x18, + vmdatah = 0x19, + m7sel = 0x1A, + m7a = 0x1B, + m7b = 0x1C, + m7c = 0x1D, + m7d = 0x1E, + m7x = 0x1F, + m7y = 0x20, + cgadd = 0x21, + cgdata = 0x22, + w12sel = 0x23, + w34sel = 0x24, + wobjsel = 0x25, + wh0 = 0x26, + wh1 = 0x27, + wh2 = 0x28, + wh3 = 0x29, + wbjlog = 0x2A, + wobjlog = 0x2B, + tm = 0x2C, + ts = 0x2D, + //! @brief TMW (Window Mask Designation for the Main Screen) + tmw = 0x2E, + //! @brief TSW (Window Mask Designation for the Subscreen) + tsw = 0x2F, + //! @brief CGWSEL (Color Addition Select) + cgwsel = 0x30, + //! @brief CGADSUB (Color math designation) + cgadsub = 0x31, + //! @brief COLDATA (Fixed Color Data) + coldata = 0x32, + //! @brief SETINI (Screen Mode/Video Select) + setini = 0x33, + //! @brief MPYL (Multiplication Result low byte) + mpyl = 0x34, + //! @brief MPYM (Multiplication Result middle byte) + mpum = 0x35, + //! @brief MPYH (Multiplication Result high byte) + mpyh = 0x36, + //! @brief SLHV (Software Latch for H/V Counter) + slhv = 0x37, + //! @brief OAMDATAREAD (Data for OAM read) + oamdataread = 0x38, + //! @brief VMDATALREAD (VRAM Data Read low byte) + vmdatalread = 0x39, + //! @brief VMDATAHREAD (VRAM Data Read high byte) + vmdatahread = 0x3A, + //! @brief CGDATAREAD (CGRAM Data read) + cgdataread = 0x3B, + //! @brief OPHCT (Horizontal Scanline Location) + ophct = 0x3C, + //! @brief OPVCT (Vertical Scanline Location) + opcvt = 0x3D, + //! @brief STAT77 (PPU Status Flag and Version) + stat77 = 0x3E, + //! @brief STAT78 (PPU Status Flag and Version) + stat78 = 0x3F + }; + //! @brief The class containing all the registers the PPU class PPU : public Memory::IMemory { private: @@ -146,29 +249,21 @@ namespace ComSquare::PPU }; uint8_t raw; } _bgnba[2]; - //! @brief BG34NBA Register (BG3 and 4 Chr Address) - union { - struct { - uint8_t baseAddressBg2a4: 4; - uint8_t baseAddressBg1a3: 4; - }; - uint8_t raw; - } _bg34nba; //! @brief BG1HOFS Register (BG1 Horizontal Scroll) //! @brief BG1VOFS Register (BG1 Vertical Scroll) union { struct { + uint16_t offsetBg: 10; uint8_t _ : 6; - uint32_t offsetBg: 10; }; uint16_t raw; - } _bg1ofs; + } _bgofs[4]; //! @brief M7HOFS Register (Mode 7 _BG Horizontal Scroll) //! @brief M7VOFS Register (Mode 7 _BG Vertical Scroll) union { struct { + uint16_t offsetBg : 13; uint8_t _ : 3; - uint32_t offsetBg : 13; }; uint8_t raw; } _m7ofs; @@ -199,13 +294,16 @@ namespace ComSquare::PPU }; uint8_t raw; } _bg4ofs; + + // + //! @brief VMAIN Register (Video Port Control) union { struct { - bool address: 1; - uint8_t _ : 3; + uint8_t incrementAmount: 2; uint8_t addressRemapping: 2; - uint8_t incrementCount: 2; + uint8_t _ : 3; + bool incrementMode: 1; }; uint8_t raw; } _vmain; diff --git a/tests/PPU/testPpuWriteFromVmain.cpp b/tests/PPU/testPpuWriteFromVmain.cpp new file mode 100644 index 0000000..571a358 --- /dev/null +++ b/tests/PPU/testPpuWriteFromVmain.cpp @@ -0,0 +1,48 @@ +// +// Created by cbihan on 2/11/20. +// + +#include +#include +#include +#include "../tests.hpp" +#include "../../sources/SNES.hpp" +#include "../../sources/Memory/MemoryBus.hpp" +#include "../../sources/PPU/PPU.hpp" +using namespace ComSquare; + +Test(PPU_write_2, vmain_data_full) +{ + auto pair = Init(); + pair.first->write(0x2115, 0b11111111); + cr_assert_eq(pair.second.ppu->_vmain.incrementMode, true); + cr_assert_eq(pair.second.ppu->_vmain.addressRemapping, 0b11); + cr_assert_eq(pair.second.ppu->_vmain.incrementAmount, 0b11); +} + +Test(PPU_write_2, vmain_incrementmode_off_false_else_full) +{ + auto pair = Init(); + pair.first->write(0x2115, 0b01111111); + cr_assert_eq(pair.second.ppu->_vmain.incrementMode, false); + cr_assert_eq(pair.second.ppu->_vmain.addressRemapping, 0b11); + cr_assert_eq(pair.second.ppu->_vmain.incrementAmount, 0b11); +} + +Test(PPU_write_2, vmain_addressremaping_null_else_full) +{ + auto pair = Init(); + pair.first->write(0x2115, 0b11110011); + cr_assert_eq(pair.second.ppu->_vmain.incrementMode, true); + cr_assert_eq(pair.second.ppu->_vmain.addressRemapping, 0b00); + cr_assert_eq(pair.second.ppu->_vmain.incrementAmount, 0b11); +} + +Test(PPU_write_2, vmain_incrementamount_null_else_full) +{ + auto pair = Init(); + pair.first->write(0x2115, 0b11111100); + cr_assert_eq(pair.second.ppu->_vmain.incrementMode, true); + cr_assert_eq(pair.second.ppu->_vmain.addressRemapping, 0b11); + cr_assert_eq(pair.second.ppu->_vmain.incrementAmount, 0b00); +} \ No newline at end of file From 76395808185f18f94028660eab49f2465a6b6721 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Le=20Bihan?= Date: Tue, 11 Feb 2020 16:29:28 +0100 Subject: [PATCH 10/21] oups --- sources/PPU/PPU.cpp | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/sources/PPU/PPU.cpp b/sources/PPU/PPU.cpp index 4927618..32edeb4 100644 --- a/sources/PPU/PPU.cpp +++ b/sources/PPU/PPU.cpp @@ -25,48 +25,51 @@ namespace ComSquare::PPU void PPU::write(uint24_t addr, uint8_t data) { switch (addr) { - case 0x00: //! @brief $2100 INIDISP Register (F-blank and Brightness) + case ppuRegisters::inidisp: this->_inidisp.raw = data; break; - case 0x01: //! @brief $2101 OBSEL Register (Object Size and Character Address) + case ppuRegisters::obsel: this->_obsel.raw = data; break; - case 0x02: //! @brief $2102 OAMADDL (OAM Address low byte). + case ppuRegisters::oamaddl: this->_oamadd.oamaddl = data; - //! @brief we recreate the oamAddress with the previous oamAddress because there is one bit missing (given by the register $2103) break; - case 0x03: //! @brief $2103 OAMADDH (OAM Address high bit and Obj Priority) + case ppuRegisters::oamaddh: this->_oamadd.oamaddh = data; - //! @brief Same as $2102 we recreate the oamAddress with the previous oamAddress because there are 8 bits missing (given by the register $2102) break; - case 0x04: //! @brief $2104 OAMDATA (Data for OAM write). + case ppuRegisters::oamdata: //! @brief not implemented yet. - // throw InvalidAddress("PPU Internal Registers write", addr); this->_oamdata = data; break; - case 0x05: //! @brief $2105 BGMODE (BG Mode and Character Size). + case ppuRegisters::bgmode: this->_bgmode.raw = data; break; - case 0x06: //! $2106 MOSAIC (Screen Pixelation) + case ppuRegisters::mosaic: this->_mosaic.raw = data; break; - case 0x07: // BG1SC (BG1 Tilemap Address and Size) - case 0x08: // BG2SC (BG2 Tilemap Address and Size) - case 0x09: //! @brief BG3SC (BG3 Tilemap Address and Size) - case 0x0A: //! @brief BG4SC (BG4 Tilemap Address and Size) + case ppuRegisters::bg1sc: + case ppuRegisters::bg2sc: + case ppuRegisters::bg3sc: + case ppuRegisters::bg4sc: this->_bgsc[addr - 0x07].raw = data; break; - case 0x0B: //! @brief BG12NBA (BG1 and 2 Chr Address) - case 0x0C: //! @brief BG34NBA (BG3 and 4 Chr Address) + case ppuRegisters::bg12nba: + case ppuRegisters::bg34nba: this->_bgnba[addr - 0x0B].raw = data; break; + case ppuRegisters::bg1hofs: + this->_bgofs[0].raw = data; + break; + case ppuRegisters::vmain: + this->_vmain.raw = data; + break; //TODO adding the rest of the registers. oaf ! default: throw InvalidAddress("PPU Internal Registers write", addr); } } - void PPU::update(unsigned cycles) + void PPU::update(int cycles) { (void)cycles; } From bc808bd4247e9c1821a4d29fddddf7b42c6d8042 Mon Sep 17 00:00:00 2001 From: AnonymusRaccoon Date: Tue, 11 Feb 2020 16:30:06 +0100 Subject: [PATCH 11/21] Handling the m flag --- CMakeLists.txt | 2 +- sources/CPU/CPU.cpp | 5 ++++- sources/CPU/CPU.hpp | 3 ++- .../Instructions/MathematicalOperations.cpp | 2 ++ tests/CPU/{testMath.cpp => Math/testADC.cpp} | 22 ++++++++++++++++--- tests/CPU/testAddressingMode.cpp | 9 ++++++++ 6 files changed, 37 insertions(+), 6 deletions(-) rename tests/CPU/{testMath.cpp => Math/testADC.cpp} (82%) diff --git a/CMakeLists.txt b/CMakeLists.txt index d8246de..9766372 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -52,7 +52,7 @@ add_executable(unit_tests sources/CPU/Instructions/CommonInstructions.hpp sources/Exceptions/InvalidOpcode.hpp sources/CPU/Instructions/Interrupts.cpp - sources/CPU/Instructions/MathematicalOperations.cpp tests/CPU/testMath.cpp) + sources/CPU/Instructions/MathematicalOperations.cpp tests/CPU/Math/testADC.cpp) # include criterion & coverage target_link_libraries(unit_tests criterion -lgcov) diff --git a/sources/CPU/CPU.cpp b/sources/CPU/CPU.cpp index e40669f..ab07040 100644 --- a/sources/CPU/CPU.cpp +++ b/sources/CPU/CPU.cpp @@ -229,7 +229,10 @@ namespace ComSquare::CPU uint24_t CPU::_getImmediateAddr() { - return this->_registers.pac++; + uint24_t effective = this->_registers.pac++; + if (this->_registers.p.m) + this->_registers.pac++; + return effective; } uint24_t CPU::_getDirectAddr() diff --git a/sources/CPU/CPU.hpp b/sources/CPU/CPU.hpp index 7cd63b2..c28382a 100644 --- a/sources/CPU/CPU.hpp +++ b/sources/CPU/CPU.hpp @@ -187,6 +187,7 @@ namespace ComSquare::CPU enum Instructions { BRK = 0x00, + ADC_DPXi = 0x61, ADC_SR = 0x63, ADC_DP = 0x65, @@ -201,7 +202,7 @@ namespace ComSquare::CPU ADC_DPYil = 0x77, ADC_ABSY = 0x79, ADC_ABSX = 0x7D, - ADC_ABSXl = 0x7F + ADC_ABSXl = 0x7F, }; //! @brief The main CPU diff --git a/sources/CPU/Instructions/MathematicalOperations.cpp b/sources/CPU/Instructions/MathematicalOperations.cpp index ee1b6c7..364d741 100644 --- a/sources/CPU/Instructions/MathematicalOperations.cpp +++ b/sources/CPU/Instructions/MathematicalOperations.cpp @@ -10,6 +10,8 @@ namespace ComSquare::CPU int CPU::ADC(uint24_t valueAddr) { unsigned value = this->_bus->read(valueAddr) + this->_registers.p.c; + if (this->_registers.p.m) + value += this->_bus->read(valueAddr + 1) << 8u; unsigned negativeMask = this->_isEmulationMode ? 0xF0u : 0xF000u; unsigned maxValue = this->_isEmulationMode ? UINT8_MAX : UINT16_MAX; diff --git a/tests/CPU/testMath.cpp b/tests/CPU/Math/testADC.cpp similarity index 82% rename from tests/CPU/testMath.cpp rename to tests/CPU/Math/testADC.cpp index 79d5723..6cef599 100644 --- a/tests/CPU/testMath.cpp +++ b/tests/CPU/Math/testADC.cpp @@ -5,9 +5,9 @@ #include #include #include -#include "../tests.hpp" -#include "../../sources/SNES.hpp" -#include "../../sources/Memory/MemoryBus.hpp" +#include "../../tests.hpp" +#include "../../../sources/SNES.hpp" +#include "../../../sources/Memory/MemoryBus.hpp" using namespace ComSquare; Test(ADC, addingOne) @@ -93,4 +93,20 @@ Test(ADC, signedOverflowEmulated) cr_assert_eq(pair.second.cpu->_registers.p.v, true, "The overflow flags should be set."); cr_assert_eq(pair.second.cpu->_registers.p.n, true, "The negative flags should be set."); cr_assert_eq(pair.second.cpu->_registers.p.z, false, "The zero flags should not be set."); +} + +Test(ADC, memoryTwoBytes) +{ + auto pair = Init(); + pair.second.cpu->_isEmulationMode = false; + pair.second.cpu->_registers.p.m = true; + pair.second.cpu->_registers.a = 0x000F; + pair.second.wram->_data[0] = 0x01; + pair.second.wram->_data[1] = 0x04; + pair.second.cpu->ADC(0x0); + cr_assert_eq(pair.second.cpu->_registers.a, 0x0410, "The accumulator's value should be 0x0410 but it was 0x%x.", pair.second.cpu->_registers.a); + cr_assert_eq(pair.second.cpu->_registers.p.c, false, "The carry flags should not be set."); + cr_assert_eq(pair.second.cpu->_registers.p.v, false, "The overflow flags should not be set."); + cr_assert_eq(pair.second.cpu->_registers.p.n, false, "The negative flags should not be set."); + cr_assert_eq(pair.second.cpu->_registers.p.z, false, "The zero flags should not be set."); } \ No newline at end of file diff --git a/tests/CPU/testAddressingMode.cpp b/tests/CPU/testAddressingMode.cpp index a9c6326..e52b695 100644 --- a/tests/CPU/testAddressingMode.cpp +++ b/tests/CPU/testAddressingMode.cpp @@ -24,6 +24,15 @@ Test(AddrMode, Immediate) cr_assert_eq(pair.second.cpu->_registers.pac, 0x000016); } +Test(AddrMode, ImmediateMemoryFlag) +{ + auto pair = Init(); + pair.second.cpu->_registers.pac = 0x000015; + pair.second.cpu->_registers.p.m = true; + cr_assert_eq(pair.second.cpu->_getImmediateAddr(), 0x000015, "Got %x, Expected 0x000015"); + cr_assert_eq(pair.second.cpu->_registers.pac, 0x000017); +} + Test(AddrMode, ImmediateBankChange) { auto pair = Init(); From d0ddbc804fbba69d9888448c42779066af264f13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Le=20Bihan?= Date: Tue, 11 Feb 2020 16:32:26 +0100 Subject: [PATCH 12/21] oups 2 --- sources/PPU/PPU.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sources/PPU/PPU.cpp b/sources/PPU/PPU.cpp index 32edeb4..d1baa5c 100644 --- a/sources/PPU/PPU.cpp +++ b/sources/PPU/PPU.cpp @@ -69,7 +69,7 @@ namespace ComSquare::PPU } } - void PPU::update(int cycles) + void PPU::update(unsigned cycles) { (void)cycles; } From 8addb2961014d0a2180a0269817c272f93c88144 Mon Sep 17 00:00:00 2001 From: AnonymusRaccoon Date: Tue, 11 Feb 2020 17:39:06 +0100 Subject: [PATCH 13/21] Implementing instructions cycles --- sources/CPU/CPU.cpp | 68 ++++++++++++++----- sources/CPU/CPU.hpp | 14 ++-- sources/CPU/Instructions/Interrupts.cpp | 4 +- .../Instructions/MathematicalOperations.cpp | 4 +- tests/CPU/testInterupts.cpp | 4 +- 5 files changed, 65 insertions(+), 29 deletions(-) diff --git a/sources/CPU/CPU.cpp b/sources/CPU/CPU.cpp index ab07040..0770183 100644 --- a/sources/CPU/CPU.cpp +++ b/sources/CPU/CPU.cpp @@ -194,28 +194,30 @@ namespace ComSquare::CPU return cycles; } - int CPU::executeInstruction() + unsigned CPU::executeInstruction() { uint8_t opcode = this->_bus->read(this->_registers.pc); - switch (opcode) { - case Instructions::BRK: return this->BRK(); + this->_extraMemoryCycles = 0; - case Instructions::ADC_DPXi: return this->ADC(this->_getDirectIndirectIndexedXAddr()); - case Instructions::ADC_SR: return this->ADC(this->_getStackRelativeAddr()); - case Instructions::ADC_DP: return this->ADC(this->_getDirectAddr()); - case Instructions::ADC_DPil: return this->ADC(this->_getDirectIndirectLongAddr()); - case Instructions::ADC_IM: return this->ADC(this->_getImmediateAddr()); - case Instructions::ADC_ABS: return this->ADC(this->_getAbsoluteAddr()); - case Instructions::ADC_ABSl: return this->ADC(this->_getAbsoluteLongAddr()); - case Instructions::ADC_DPYi: return this->ADC(this->_getDirectIndirectIndexedYAddr()); - case Instructions::ADC_DPi: return this->ADC(this->_getDirectIndirectAddr()); - case Instructions::ADC_SRYi: return this->ADC(this->_getStackRelativeIndirectIndexedYAddr()); - case Instructions::ADC_DPX: return this->ADC(this->_getDirectIndexedByXAddr()); - case Instructions::ADC_DPYil:return this->ADC(this->_getDirectIndirectIndexedYLongAddr()); - case Instructions::ADC_ABSY: return this->ADC(this->_getAbsoluteIndexedByYAddr()); - case Instructions::ADC_ABSX: return this->ADC(this->_getAbsoluteIndexedByXAddr()); - case Instructions::ADC_ABSXl:return this->ADC(this->_getAbsoluteIndexedByXLongAddr()); + switch (opcode) { + case Instructions::BRK: return 7 + this->BRK(); + + case Instructions::ADC_IM: return 2 + this->ADC(this->_getImmediateAddr()); + case Instructions::ADC_ABS: return 4 + this->ADC(this->_getAbsoluteAddr()); + case Instructions::ADC_ABSl: return 5 + this->ADC(this->_getAbsoluteLongAddr()); + case Instructions::ADC_DP: return 3 + this->ADC(this->_getDirectAddr()); + case Instructions::ADC_DPi: return 5 + this->ADC(this->_getDirectIndirectAddr()); + case Instructions::ADC_DPil: return 6 + this->ADC(this->_getDirectIndirectLongAddr()); + case Instructions::ADC_ABSX: return 4 + this->ADC(this->_getAbsoluteIndexedByXAddr()); + case Instructions::ADC_ABSXl:return 5 + this->ADC(this->_getAbsoluteIndexedByXLongAddr()); + case Instructions::ADC_ABSY: return 4 + this->ADC(this->_getAbsoluteIndexedByYAddr()); + case Instructions::ADC_DPX: return 4 + this->ADC(this->_getDirectIndexedByXAddr()); + case Instructions::ADC_DPXi: return 6 + this->ADC(this->_getDirectIndirectIndexedXAddr()); + case Instructions::ADC_DPYi: return 5 + this->ADC(this->_getDirectIndirectIndexedYAddr()); + case Instructions::ADC_DPYil:return 6 + this->ADC(this->_getDirectIndirectIndexedYLongAddr()); + case Instructions::ADC_SR: return 4 + this->ADC(this->_getStackRelativeAddr()); + case Instructions::ADC_SRYi: return 7 + this->ADC(this->_getStackRelativeIndirectIndexedYAddr()); default: return 0; @@ -237,6 +239,9 @@ namespace ComSquare::CPU uint24_t CPU::_getDirectAddr() { + if (this->_registers.dl != 0) + this->_extraMemoryCycles++; + uint8_t addr = this->_bus->read(this->_registers.pac++); return this->_registers.d + addr; } @@ -259,15 +264,23 @@ namespace ComSquare::CPU uint24_t CPU::_getDirectIndirectIndexedYAddr() { + if (this->_registers.dl != 0) + this->_extraMemoryCycles++; + uint16_t dp = this->_bus->read(this->_registers.pac++) + this->_registers.d; uint24_t base = this->_bus->read(dp); base += this->_bus->read(dp + 1) << 8u; base += this->_registers.dbr << 16u; + if ((base & 0xF0000000u) == (((base + this->_registers.y) & 0xF0000000u))) + this->_extraMemoryCycles++; return base + this->_registers.y; } uint24_t CPU::_getDirectIndirectIndexedYLongAddr() { + if (this->_registers.dl != 0) + this->_extraMemoryCycles++; + uint16_t dp = this->_bus->read(this->_registers.pac++) + this->_registers.d; uint24_t base = this->_bus->read(dp); base += this->_bus->read(dp + 1) << 8u; @@ -277,6 +290,9 @@ namespace ComSquare::CPU uint24_t CPU::_getDirectIndirectIndexedXAddr() { + if (this->_registers.dl != 0) + this->_extraMemoryCycles++; + uint16_t dp = this->_bus->read(this->_registers.pac++) + this->_registers.d; dp += this->_registers.x; uint24_t base = this->_bus->read(dp); @@ -287,6 +303,9 @@ namespace ComSquare::CPU uint24_t CPU::_getDirectIndexedByXAddr() { + if (this->_registers.dl != 0) + this->_extraMemoryCycles++; + uint16_t dp = this->_bus->read(this->_registers.pac++) + this->_registers.d; dp += this->_registers.x; return dp; @@ -294,6 +313,9 @@ namespace ComSquare::CPU uint24_t CPU::_getDirectIndexedByYAddr() { + if (this->_registers.dl != 0) + this->_extraMemoryCycles++; + uint16_t dp = this->_bus->read(this->_registers.pac++) + this->_registers.d; dp += this->_registers.y; return dp; @@ -304,6 +326,8 @@ namespace ComSquare::CPU uint16_t abs = this->_bus->read(this->_registers.pac++); abs += this->_bus->read(this->_registers.pac++) << 8u; uint24_t effective = abs + (this->_registers.dbr << 16u); + if ((effective & 0xF0000000u) == (((effective + this->_registers.x) & 0xF0000000u))) + this->_extraMemoryCycles++; return effective + this->_registers.x; } @@ -312,6 +336,8 @@ namespace ComSquare::CPU uint16_t abs = this->_bus->read(this->_registers.pac++); abs += this->_bus->read(this->_registers.pac++) << 8u; uint24_t effective = abs + (this->_registers.dbr << 16u); + if ((effective & 0xF0000000u) == (((effective + this->_registers.y) & 0xF0000000u))) + this->_extraMemoryCycles++; return effective + this->_registers.y; } @@ -360,6 +386,9 @@ namespace ComSquare::CPU uint24_t CPU::_getDirectIndirectAddr() { + if (this->_registers.dl != 0) + this->_extraMemoryCycles++; + uint16_t dp = this->_bus->read(this->_registers.pac++) + this->_registers.d; uint24_t effective = this->_bus->read(dp); effective += this->_bus->read(dp + 1) << 8u; @@ -369,6 +398,9 @@ namespace ComSquare::CPU uint24_t CPU::_getDirectIndirectLongAddr() { + if (this->_registers.dl != 0) + this->_extraMemoryCycles++; + uint16_t dp = this->_bus->read(this->_registers.pac++) + this->_registers.d; uint24_t effective = this->_bus->read(dp); effective += this->_bus->read(++dp) << 8u; diff --git a/sources/CPU/CPU.hpp b/sources/CPU/CPU.hpp index c28382a..b50d46e 100644 --- a/sources/CPU/CPU.hpp +++ b/sources/CPU/CPU.hpp @@ -25,7 +25,7 @@ namespace ComSquare::CPU }; //! @brief The Data Bank Register; uint8_t dbr; - //! @brief The Direct register; + //! @brief The Direct Page register; union { struct { uint8_t dh; @@ -202,7 +202,7 @@ namespace ComSquare::CPU ADC_DPYil = 0x77, ADC_ABSY = 0x79, ADC_ABSX = 0x7D, - ADC_ABSXl = 0x7F, + ADC_ABSXl = 0x7F }; //! @brief The main CPU @@ -219,6 +219,9 @@ namespace ComSquare::CPU //! @brief The cartridge header (stored for interrupt vectors.. Cartridge::Header &_cartridgeHeader; + //! @brief An additional number of cycles that the current running instruction took to run. (Used for address modes that take longer to run than others). + unsigned _extraMemoryCycles = 0; + //! @brief Immediate address mode is specified with a value. (This functions returns the 24bit space address of the value). uint24_t _getImmediateAddr(); //! @brief The destination is formed by adding the direct page register with the 8-bit address to form an effective address. (This functions returns the 24bit space address of the value). @@ -263,12 +266,13 @@ namespace ComSquare::CPU //! @brief Execute a single instruction. //! @return The number of CPU cycles that the instruction took. - int executeInstruction(); + unsigned executeInstruction(); //! @brief Break instruction - Causes a software break. The PC is loaded from a vector table. - int BRK(); + unsigned BRK(); //! @brief Add with carry - Adds operand to the Accumulator; adds an additional 1 if carry is set. - int ADC(uint24_t valueAddr); + //! @return The number of extra cycles that this operation took. + unsigned ADC(uint24_t valueAddr); public: explicit CPU(std::shared_ptr bus, Cartridge::Header &cartridgeHeader); //! @brief This function continue to execute the Cartridge code. diff --git a/sources/CPU/Instructions/Interrupts.cpp b/sources/CPU/Instructions/Interrupts.cpp index e07534a..ee29629 100644 --- a/sources/CPU/Instructions/Interrupts.cpp +++ b/sources/CPU/Instructions/Interrupts.cpp @@ -6,7 +6,7 @@ namespace ComSquare::CPU { - int CPU::BRK() + unsigned CPU::BRK() { this->_registers.pc += 2; @@ -16,6 +16,6 @@ namespace ComSquare::CPU else this->_registers.pc = this->_cartridgeHeader.nativeInterrupts.brk; this->_registers.p.d = false; - return 7 + !this->_isEmulationMode; + return !this->_isEmulationMode; } } \ No newline at end of file diff --git a/sources/CPU/Instructions/MathematicalOperations.cpp b/sources/CPU/Instructions/MathematicalOperations.cpp index 364d741..78a8dc1 100644 --- a/sources/CPU/Instructions/MathematicalOperations.cpp +++ b/sources/CPU/Instructions/MathematicalOperations.cpp @@ -7,7 +7,7 @@ namespace ComSquare::CPU { - int CPU::ADC(uint24_t valueAddr) + unsigned CPU::ADC(uint24_t valueAddr) { unsigned value = this->_bus->read(valueAddr) + this->_registers.p.c; if (this->_registers.p.m) @@ -25,6 +25,6 @@ namespace ComSquare::CPU this->_registers.a %= 0x100; this->_registers.p.z = this->_registers.a == 0; this->_registers.p.n = this->_registers.a & negativeMask; - return (0); + return this->_extraMemoryCycles + !this->_registers.p.m; } } \ No newline at end of file diff --git a/tests/CPU/testInterupts.cpp b/tests/CPU/testInterupts.cpp index 5191176..dd6339b 100644 --- a/tests/CPU/testInterupts.cpp +++ b/tests/CPU/testInterupts.cpp @@ -16,7 +16,7 @@ Test(CPU_emulated, BRK) pair.second.cartridge->header.emulationInterrupts.brk = 0x123u; pair.second.cpu->_registers.p.d = true; pair.second.cpu->_registers.pc = 0x156u; - cr_assert_eq(pair.second.cpu->BRK(), 7); + cr_assert_eq(pair.second.cpu->BRK(), 0); cr_assert_eq(pair.second.cpu->_registers.pc, 0x123u); cr_assert_eq(pair.second.cpu->_registers.p.i, 1, "pair.second.cpu->_registers.p.i mmust be equal to 1 but it was %d", pair.second.cpu->_registers.p.i); cr_assert_eq(pair.second.cpu->_registers.p.d, false); @@ -28,7 +28,7 @@ Test(CPU_native, BRK) pair.second.cpu->_isEmulationMode = false; pair.second.cartridge->header.nativeInterrupts.brk = 0x123u; pair.second.cpu->_registers.pc = 0x156u; - cr_assert_eq(pair.second.cpu->BRK(), 8); + cr_assert_eq(pair.second.cpu->BRK(), 1); cr_assert_eq(pair.second.cpu->_registers.pc, 0x123u); cr_assert_eq(pair.second.cpu->_registers.p.i, true); cr_assert_eq(pair.second.cpu->_registers.p.d, false); From 49b540113555441c69c2b29ed9cf18e8a0b748d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Le=20Bihan?= Date: Tue, 11 Feb 2020 23:54:43 +0100 Subject: [PATCH 14/21] added documentation on the ppu's register --- CMakeLists.txt | 1 + sources/PPU/PPU.cpp | 25 +++++++++++++ sources/PPU/PPU.hpp | 55 ++++++++++++++++++++++++----- sources/SNES.cpp | 2 +- tests/PPU/testPpuWriteFromVmain.cpp | 32 +++++++++++++++++ 5 files changed, 106 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ec0caad..9947cdd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -56,6 +56,7 @@ add_executable(unit_tests tests/CPU/testAddressingMode.cpp tests/tests.cpp tests/PPU/testPpuWrite.cpp + tests/PPU/testPpuWriteFromVmain.cpp ) # include criterion & coverage diff --git a/sources/PPU/PPU.cpp b/sources/PPU/PPU.cpp index d1baa5c..37f2ce8 100644 --- a/sources/PPU/PPU.cpp +++ b/sources/PPU/PPU.cpp @@ -58,11 +58,25 @@ namespace ComSquare::PPU this->_bgnba[addr - 0x0B].raw = data; break; case ppuRegisters::bg1hofs: + // Work in progress ! Non functional ! this->_bgofs[0].raw = data; break; case ppuRegisters::vmain: this->_vmain.raw = data; break; + case ppuRegisters::vmaddl: + this->_vmadd.vmaddl = data; + break; + case ppuRegisters::vmaddh: + this->_vmadd.vmaddh = data; + break; + //! @info should must be in vblank for the write (and write it to the screen )? and increment vram address after; + case ppuRegisters::vmdatal: + this->_vmdata.vmdatal = data; + break; + case ppuRegisters::vmdatah: + this->_vmdata.vmdatah = data; + break; //TODO adding the rest of the registers. oaf ! default: throw InvalidAddress("PPU Internal Registers write", addr); @@ -72,5 +86,16 @@ namespace ComSquare::PPU void PPU::update(unsigned cycles) { (void)cycles; + uint32_t pixelTmp = 0xFFFFFF00; + pixelTmp |= this->_inidisp.brightness; + if (!this->_inidisp.fblank) + this->_renderer.putPixel(0, 0,pixelTmp); + this->_renderer.drawScreen(); + } + + PPU::PPU(const std::shared_ptr &bus, Renderer::IRenderer &renderer): + _bus(std::move(bus)), + _renderer(renderer) + { } } \ No newline at end of file diff --git a/sources/PPU/PPU.hpp b/sources/PPU/PPU.hpp index a8e3791..e5b6cde 100644 --- a/sources/PPU/PPU.hpp +++ b/sources/PPU/PPU.hpp @@ -7,6 +7,8 @@ #include #include "../Memory/IMemory.hpp" +#include "../Memory/MemoryBus.hpp" +#include "../Renderer/IRenderer.hpp" //#define max2BitTiles 4096 //#define max4BitTiles 2048 @@ -44,40 +46,75 @@ namespace ComSquare::PPU bg12nba = 0x0B, //! @brief BG34NBA (BG3 and 4 Chr Address) bg34nba = 0x0C, + //! @brief BG1HOFS (BG1 Horizontal Scroll) + //! @brief M7HOFS (Mode 7 BG Horizontal Scroll) //! @info When bg mode is 7 the register is used as M7HOFS bg1hofs = 0x0D, + //! @brief BG1VOFS (BG1 Vertical Scroll) + //! @brief M7VOFS (Mode 7 BG Vertical Scroll) //! @info When bg mode is 7 the register is used as M7VOFS bg1vofs = 0x0E, + //! @brief BG2HOFS (BG2 Horizontal Scroll) bg2hofs = 0x0F, + //! @brief BG2VOFS (BG2 Vertical Scroll) bg2vofs = 0x10, + //! @brief BG3HOFS (BG3 Horizontal Scroll) bg3hofs = 0x11, + //! @brief BG3VOFS (BG3 Vertical Scroll) bg3vofs = 0x12, + //! @brief BG4HOFS (BG4 Horizontal Scroll) bg4hofs = 0x13, + //! @brief BG4VOFS (BG4 Vertical Scroll) bg4vofs = 0x14, + //! @brief VMAIN (Video Port Control) vmain = 0x15, + //! @brief VMADDL (VRAM Address low byte) vmaddl = 0x16, - vamddh = 0x17, + //! @brief VMADDH (VRAM Address high byte) + vmaddh = 0x17, + //! @brief VMDATAL (VRAM Data Write low byte) vmdatal = 0x18, + //! @brief VMDATAH (VRAM Data Write high byte) vmdatah = 0x19, + //! @brief M7SEL (Mode 7 Settings) m7sel = 0x1A, + //! @brief M7A (Mode 7 Matrix A) also used with $2134/6 m7a = 0x1B, + //! @brief M7B (Mode 7 Matrix B) also used with $2134/6 m7b = 0x1C, + //! @brief M7C (Mode 7 Matrix C) m7c = 0x1D, + //! @brief M7D (Mode 7 Matrix D) m7d = 0x1E, + //! @brief M7X (Mode 7 Center X) m7x = 0x1F, + //! @brief M7Y (Mode 7 Center Y) m7y = 0x20, + //! @brief CGADD (CGRAM Address) cgadd = 0x21, + //! @brief CGDATA (CGRAM Data write) cgdata = 0x22, + //! @brief W12SEL (Window Mask Settings for BG1 and BG2) w12sel = 0x23, + //! @brief W34SEL (Window Mask Settings for BG3 and BG4) w34sel = 0x24, + //! @brief WOBJSEL (Window Mask Settings for OBJ and Color Window) wobjsel = 0x25, + //! @brief WH0 (Window 1 Left Position) wh0 = 0x26, + //! @brief WH1 (Window 1 Right Position) wh1 = 0x27, + //! @brief WH2 (Window 2 Left Position) wh2 = 0x28, + //! @brief WH3 (Window 2 Right Position) wh3 = 0x29, + //! @brief WBGLOG (Window mask logic for BGs) wbjlog = 0x2A, + //! @brief WOBJLOG (Window mask logic for OBJs and Color Window) wobjlog = 0x2B, + //! @brief TM (Main Screen Designation) tm = 0x2C, + //! @brief TS (Subscreen Designation) ts = 0x2D, //! @brief TMW (Window Mask Designation for the Main Screen) tmw = 0x2E, @@ -267,7 +304,7 @@ namespace ComSquare::PPU }; uint8_t raw; } _m7ofs; - //! @brief BG2HOFS Register (BG2 Horizontal Scroll) + /* //! @brief BG2HOFS Register (BG2 Horizontal Scroll) //! @brief BG2VOFS Register (BG2 Vertical Scroll) union { struct { @@ -293,7 +330,7 @@ namespace ComSquare::PPU uint32_t offsetBg: 10; }; uint8_t raw; - } _bg4ofs; + } _bg4ofs;*/ // @@ -310,18 +347,18 @@ namespace ComSquare::PPU //! @brief VMADD Register (VRAM Address) union { struct { - uint8_t vmaddh; uint8_t vmaddl; + uint8_t vmaddh; }; - uint32_t vmadd; + uint16_t vmadd; } _vmadd; //! @brief VMDATA Register (VRAM Data Write) union { struct { - uint8_t vmdatah; uint8_t vmdatal; + uint8_t vmdatah; }; - uint32_t vmdata; + uint16_t vmdata; } _vmdata; //! @brief M7SEL Register (Mode 7 Settings) union { @@ -509,8 +546,10 @@ namespace ComSquare::PPU }; uint32_t mpy; } mpy; + Renderer::IRenderer &_renderer; + std::shared_ptr _bus; public: - explicit PPU() = default; + PPU(const std::shared_ptr &bus, Renderer::IRenderer &renderer); //! @brief Read data from the component. //! @param addr The local address to read from (0x0 should refer to the first byte of this component). //! @throw This function should thrown an InvalidAddress for address that are not mapped to the component. diff --git a/sources/SNES.cpp b/sources/SNES.cpp index 87f52b2..e1a793c 100644 --- a/sources/SNES.cpp +++ b/sources/SNES.cpp @@ -11,7 +11,7 @@ namespace ComSquare SNES::SNES(const std::shared_ptr &bus, const std::string &romPath, Renderer::IRenderer &renderer) : cartridge(new Cartridge::Cartridge(romPath)), cpu(new CPU::CPU(bus, cartridge->header)), - ppu(new PPU::PPU()), + ppu(new PPU::PPU(renderer, bus)), apu(new APU::APU()), wram(new Ram::Ram(16384)), sram(new Ram::Ram(this->cartridge->header.sramSize)) diff --git a/tests/PPU/testPpuWriteFromVmain.cpp b/tests/PPU/testPpuWriteFromVmain.cpp index 571a358..db2bf62 100644 --- a/tests/PPU/testPpuWriteFromVmain.cpp +++ b/tests/PPU/testPpuWriteFromVmain.cpp @@ -45,4 +45,36 @@ Test(PPU_write_2, vmain_incrementamount_null_else_full) cr_assert_eq(pair.second.ppu->_vmain.incrementMode, true); cr_assert_eq(pair.second.ppu->_vmain.addressRemapping, 0b11); cr_assert_eq(pair.second.ppu->_vmain.incrementAmount, 0b00); +} + +Test(PPU_write_2, vmadd_full_data) +{ + auto pair = Init(); + pair.first->write(0x2116, 0b11111111); + pair.first->write(0x2117, 0b11111111); + cr_assert_eq(pair.second.ppu->_vmadd.vmadd, 0b1111111111111111); +} + +Test(PPU_write_2, vmadd_full_high_byte_null) +{ + auto pair = Init(); + pair.first->write(0x2116, 0b11111111); + pair.first->write(0x2117, 0b00000000); + cr_assert_eq(pair.second.ppu->_vmadd.vmadd, 0b0000000011111111); +} + +Test(PPU_write_2, vmdata_full_data) +{ + auto pair = Init(); + pair.first->write(0x2118, 0b11111111); + pair.first->write(0x2119, 0b11111111); + cr_assert_eq(pair.second.ppu->_vmdata.vmdata, 0b1111111111111111); +} + +Test(PPU_write_2, vmdata_full_high_byte_null) +{ + auto pair = Init(); + pair.first->write(0x2118, 0b11111111); + pair.first->write(0x2119, 0b00000000); + cr_assert_eq(pair.second.ppu->_vmdata.vmdata, 0b0000000011111111); } \ No newline at end of file From 17c0cb8660a8f0c6dcc9e5409f30efb97b92718e Mon Sep 17 00:00:00 2001 From: AnonymusRaccoon Date: Wed, 12 Feb 2020 16:40:06 +0100 Subject: [PATCH 15/21] Adding the reset --- sources/CPU/CPU.cpp | 26 ++++++++++++++++++++++--- sources/CPU/CPU.hpp | 14 ++++++++++++- sources/CPU/Instructions/Interrupts.cpp | 17 ++++++++++++++++ 3 files changed, 53 insertions(+), 4 deletions(-) diff --git a/sources/CPU/CPU.cpp b/sources/CPU/CPU.cpp index 0770183..f1c3e4f 100644 --- a/sources/CPU/CPU.cpp +++ b/sources/CPU/CPU.cpp @@ -15,7 +15,7 @@ namespace ComSquare::CPU CPU::CPU(std::shared_ptr bus, Cartridge::Header &cartridgeHeader) : _bus(std::move(bus)), _cartridgeHeader(cartridgeHeader) { - this->_registers.pc = this->_cartridgeHeader.emulationInterrupts.reset; + this->RESB(); } //! @bref The CPU's internal registers starts at $4200 and finish at $421F. @@ -220,11 +220,31 @@ namespace ComSquare::CPU case Instructions::ADC_SRYi: return 7 + this->ADC(this->_getStackRelativeIndirectIndexedYAddr()); default: - return 0; - //throw InvalidOpcode("CPU", opcode); + throw InvalidOpcode("CPU", opcode); } } + void CPU::push(uint8_t data) + { + this->_bus->write(this->_registers.s--, data); + } + + void CPU::push(uint16_t data) + { + this->_bus->write(this->_registers.s--, data); + this->_bus->write(this->_registers.s--, data << 8u); + } + + uint8_t CPU::pop() + { + return this->_bus->read(this->_registers.s++); + } + + uint16_t CPU::pop16() + { + return this->_bus->read(this->_registers.s++) + (this->_bus->read(this->_registers.s++) << 8u); + } + //////////////////////////////////////////////////////////////////// /// Addressing modes //////////////////////////////////////////////////////////////////// diff --git a/sources/CPU/CPU.hpp b/sources/CPU/CPU.hpp index b50d46e..c864ee8 100644 --- a/sources/CPU/CPU.hpp +++ b/sources/CPU/CPU.hpp @@ -202,7 +202,7 @@ namespace ComSquare::CPU ADC_DPYil = 0x77, ADC_ABSY = 0x79, ADC_ABSX = 0x7D, - ADC_ABSXl = 0x7F + ADC_ABSXl = 0x7F, }; //! @brief The main CPU @@ -264,10 +264,22 @@ namespace ComSquare::CPU uint24_t _getStackRelativeIndirectIndexedYAddr(); + //! @brief Push 8 bits of data to the stack. + void push(uint8_t data); + //! @brief Push 16 bits of data to the stack. + void push(uint16_t data); + //! @brief Pop 8 bits of data from the stack. + uint8_t pop(); + //! @brief Pop 16 bits of data from the stack. + uint16_t pop16(); + + //! @brief Execute a single instruction. //! @return The number of CPU cycles that the instruction took. unsigned executeInstruction(); + //! @brief Reset interrupt - Called on boot and when the reset button is pressed. + unsigned RESB(); //! @brief Break instruction - Causes a software break. The PC is loaded from a vector table. unsigned BRK(); //! @brief Add with carry - Adds operand to the Accumulator; adds an additional 1 if carry is set. diff --git a/sources/CPU/Instructions/Interrupts.cpp b/sources/CPU/Instructions/Interrupts.cpp index ee29629..8136db9 100644 --- a/sources/CPU/Instructions/Interrupts.cpp +++ b/sources/CPU/Instructions/Interrupts.cpp @@ -6,8 +6,25 @@ namespace ComSquare::CPU { + unsigned CPU::RESB() + { + this->_registers.p.i = true; + this->_registers.p.d = false; + this->_isEmulationMode = true; + this->_registers.p.m = true; + this->_registers.p.x_b = true; + this->_registers.dbr = 0x00; + this->_registers.pbr = 0x00; + this->_registers.d = 0x0000; + this->_registers.sh = 0x01; // the low bit of the stack pointer is undefined on reset. + this->_registers.pc = this->_cartridgeHeader.emulationInterrupts.reset; + return 0; + } + unsigned CPU::BRK() { + // TODO rework this. The PC should be pushed to the stack. + // Info here: http://softpixel.com/~cwright/sianse/docs/65816NFO.HTM at BRK Software Break this->_registers.pc += 2; this->_registers.p.i = true; From b1a2222b559bd1973ffc8d5ea02f14abf3e12bca Mon Sep 17 00:00:00 2001 From: AnonymusRaccoon Date: Wed, 12 Feb 2020 16:51:13 +0100 Subject: [PATCH 16/21] Adding the RTI --- sources/CPU/CPU.cpp | 2 ++ sources/CPU/CPU.hpp | 3 +++ sources/CPU/Instructions/Interrupts.cpp | 12 ++++++++++++ 3 files changed, 17 insertions(+) diff --git a/sources/CPU/CPU.cpp b/sources/CPU/CPU.cpp index f1c3e4f..aeeefa0 100644 --- a/sources/CPU/CPU.cpp +++ b/sources/CPU/CPU.cpp @@ -203,6 +203,8 @@ namespace ComSquare::CPU switch (opcode) { case Instructions::BRK: return 7 + this->BRK(); + case Instructions::RTI: return 6 + this->RTI(); + case Instructions::ADC_IM: return 2 + this->ADC(this->_getImmediateAddr()); case Instructions::ADC_ABS: return 4 + this->ADC(this->_getAbsoluteAddr()); case Instructions::ADC_ABSl: return 5 + this->ADC(this->_getAbsoluteLongAddr()); diff --git a/sources/CPU/CPU.hpp b/sources/CPU/CPU.hpp index c864ee8..960dbae 100644 --- a/sources/CPU/CPU.hpp +++ b/sources/CPU/CPU.hpp @@ -187,6 +187,7 @@ namespace ComSquare::CPU enum Instructions { BRK = 0x00, + RTI = 0x40, ADC_DPXi = 0x61, ADC_SR = 0x63, @@ -282,6 +283,8 @@ namespace ComSquare::CPU unsigned RESB(); //! @brief Break instruction - Causes a software break. The PC is loaded from a vector table. unsigned BRK(); + //! @brief Return from Interrupt - Used to return from a interrupt handler. + unsigned RTI(); //! @brief Add with carry - Adds operand to the Accumulator; adds an additional 1 if carry is set. //! @return The number of extra cycles that this operation took. unsigned ADC(uint24_t valueAddr); diff --git a/sources/CPU/Instructions/Interrupts.cpp b/sources/CPU/Instructions/Interrupts.cpp index 8136db9..b175048 100644 --- a/sources/CPU/Instructions/Interrupts.cpp +++ b/sources/CPU/Instructions/Interrupts.cpp @@ -35,4 +35,16 @@ namespace ComSquare::CPU this->_registers.p.d = false; return !this->_isEmulationMode; } + + unsigned CPU::RTI() + { + this->_registers.p.flags = this->pop(); + this->_registers.pc = this->pop16(); + + if (!this->_isEmulationMode) { + this->_registers.pbr = this->pop16(); + return 1; + } + return 0; + } } \ No newline at end of file From de0c145dd04c18d54ccfa0f1d6690ad5fb259a14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Le=20Bihan?= Date: Wed, 12 Feb 2020 17:38:23 +0100 Subject: [PATCH 17/21] added registers (BGXXOFS) --- sources/PPU/PPU.cpp | 75 ++++++++++++++++++++++++++++++++++++++++----- sources/PPU/PPU.hpp | 59 ++++++++++++----------------------- sources/SNES.cpp | 2 +- 3 files changed, 87 insertions(+), 49 deletions(-) diff --git a/sources/PPU/PPU.cpp b/sources/PPU/PPU.cpp index 37f2ce8..c3b0fa3 100644 --- a/sources/PPU/PPU.cpp +++ b/sources/PPU/PPU.cpp @@ -2,6 +2,7 @@ // Created by cbihan on 1/27/20. // +#include #include "PPU.hpp" #include "../Exceptions/NotImplementedException.hpp" #include "../Exceptions/InvalidAddress.hpp" @@ -58,8 +59,17 @@ namespace ComSquare::PPU this->_bgnba[addr - 0x0B].raw = data; break; case ppuRegisters::bg1hofs: - // Work in progress ! Non functional ! - this->_bgofs[0].raw = data; + case ppuRegisters::bg1vofs: + case ppuRegisters::bg2hofs: + case ppuRegisters::bg2vofs: + case ppuRegisters::bg3hofs: + case ppuRegisters::bg3vofs: + case ppuRegisters::bg4hofs: + case ppuRegisters::bg4vofs: + // Work in progress ! + if (addr == ppuRegisters::bg1hofs || addr == ppuRegisters::bg1vofs) + this->_m7ofs[addr - ppuRegisters::bg1hofs].raw = data; + this->_bgofs[addr - ppuRegisters::bg1hofs].raw = data; break; case ppuRegisters::vmain: this->_vmain.raw = data; @@ -72,10 +82,36 @@ namespace ComSquare::PPU break; //! @info should must be in vblank for the write (and write it to the screen )? and increment vram address after; case ppuRegisters::vmdatal: - this->_vmdata.vmdatal = data; + if (!this->_inidisp.fblank) { + this->_vmdata.vmdatal = data; + this->_vram[getVramAddress()] = this->_vmdata.vmdata; + } + if (!this->_vmain.incrementMode) + this->_vmadd.vmadd += this->_vmain.incrementAmount; break; case ppuRegisters::vmdatah: - this->_vmdata.vmdatah = data; + if (!this->_inidisp.fblank) { + this->_vmdata.vmdatah = data; + this->_vram[getVramAddress()] = this->_vmdata.vmdata; + } + if (this->_vmain.incrementMode) + this->_vmadd.vmadd += this->_vmain.incrementAmount; + break; + case ppuRegisters::cgadd: + this->_cgadd = data; + this->_isLowByte = true; + break; + case ppuRegisters::cgdata: + if (this->_isLowByte) { + this->_cgdata.cgdatal = data; + this->_bus->write(this->_cgadd, this->_cgdata.cgdatal); + } + else { + this->_cgdata.cgdatah = data; + this->_bus->write(this->_cgadd, this->_cgdata.cgdatah); + } + this->_isLowByte = !this->_isLowByte; + this->_cgadd++; break; //TODO adding the rest of the registers. oaf ! default: @@ -83,13 +119,35 @@ namespace ComSquare::PPU } } + uint8_t PPU::getVramAddress() + { + uint16_t vanillaAddress = this->_vmadd.vmadd; + + switch (this->_vmain.addressRemapping) { + case 0b00: + return vanillaAddress; + case 0b01: + return (vanillaAddress & 0xFF00U) | (vanillaAddress & 0x00E0U) >> 5U | (vanillaAddress & 0x001FU) << 3U; + case 0b10: + return (vanillaAddress & 0xFE00U) | (vanillaAddress & 0x01C0U) >> 6U | (vanillaAddress & 0x3FU) << 3U; + case 0b11: + return (vanillaAddress & 0xFC00U) | (vanillaAddress & 0x0380U) >> 7U | (vanillaAddress & 0x7FU) << 3U; + } + } + void PPU::update(unsigned cycles) { (void)cycles; - uint32_t pixelTmp = 0xFFFFFF00; - pixelTmp |= this->_inidisp.brightness; - if (!this->_inidisp.fblank) - this->_renderer.putPixel(0, 0,pixelTmp); + int inc = 0; + uint32_t pixelTmp = 0xFFFFFFFF; + //pixelTmp |= this->_inidisp.brightness; + if (!this->_inidisp.fblank) { + for (int x = 0; x < 448; x++) { + for (int y = 0; y < 512; y++) { + this->_renderer.putPixel(x, y, (uint32_t)_vram[inc++] << 8U + 0xFFU); + } + } + } this->_renderer.drawScreen(); } @@ -97,5 +155,6 @@ namespace ComSquare::PPU _bus(std::move(bus)), _renderer(renderer) { + //_vram = new uint16_t[32000]; } } \ No newline at end of file diff --git a/sources/PPU/PPU.hpp b/sources/PPU/PPU.hpp index e5b6cde..836d017 100644 --- a/sources/PPU/PPU.hpp +++ b/sources/PPU/PPU.hpp @@ -286,54 +286,23 @@ namespace ComSquare::PPU }; uint8_t raw; } _bgnba[2]; - //! @brief BG1HOFS Register (BG1 Horizontal Scroll) - //! @brief BG1VOFS Register (BG1 Vertical Scroll) + //! @brief BGXXOFS Register (BG1/2/3/4 Horizontal and Vertical Scroll) union { struct { uint16_t offsetBg: 10; uint8_t _ : 6; }; uint16_t raw; - } _bgofs[4]; - //! @brief M7HOFS Register (Mode 7 _BG Horizontal Scroll) - //! @brief M7VOFS Register (Mode 7 _BG Vertical Scroll) + } _bgofs[8]; + //! @brief M7HOFS Register (Mode 7 BG Horizontal Scroll) + //! @brief M7VOFS Register (Mode 7 BG Vertical Scroll) union { struct { uint16_t offsetBg : 13; uint8_t _ : 3; }; uint8_t raw; - } _m7ofs; - /* //! @brief BG2HOFS Register (BG2 Horizontal Scroll) - //! @brief BG2VOFS Register (BG2 Vertical Scroll) - union { - struct { - uint8_t _ : 6; - uint32_t offsetBg: 10; - }; - uint8_t raw; - } _bg2ofs; - //! @brief BG3HOFS Register (BG3 Horizontal Scroll) - //! @brief BG3VOFS Register (BG3 Vertical Scroll) - union { - struct { - uint8_t _ : 6; - uint32_t offsetBg: 10; - }; - uint8_t raw; - } _bg3ofs; - //! @brief BG4HOFS Register (BG4 Horizontal Scroll) - //! @brief BG4VOFS Register (BG4 Vertical Scroll) - union { - struct { - uint8_t _ : 3; - uint32_t offsetBg: 10; - }; - uint8_t raw; - } _bg4ofs;*/ - - // - + } _m7ofs[2]; //! @brief VMAIN Register (Video Port Control) union { struct { @@ -360,7 +329,7 @@ namespace ComSquare::PPU }; uint16_t vmdata; } _vmdata; - //! @brief M7SEL Register (Mode 7 Settings) + //! @brief TODO M7SEL Register (Mode 7 Settings) union { struct { bool playingFieldSize: 1; @@ -393,13 +362,20 @@ namespace ComSquare::PPU //! @brief CGDATA Register (CGRAM Data write) union { struct { - bool _: 1; - uint8_t blue: 5; - uint8_t green: 5; uint8_t red: 5; + uint8_t green: 5; + uint8_t blue: 5; + bool _: 1; + }; + struct { + uint8_t cgdatal; + uint8_t cgdatah; }; uint16_t raw; } _cgdata; + //! @brief This bool is used for writing either the low byte of the data (first call) or the high byte of the data (second call) + //! @info This bool is set to True when writing to $2121 (CGADD) + bool _isLowByte; //! @brief W12SEL - W34SEL Registers (Window Mask Settings for BGs) and WOBJSEL Register (Window Mask Settings for OBJ and Color Window) union { struct { @@ -548,6 +524,7 @@ namespace ComSquare::PPU } mpy; Renderer::IRenderer &_renderer; std::shared_ptr _bus; + uint16_t *_vram; public: PPU(const std::shared_ptr &bus, Renderer::IRenderer &renderer); //! @brief Read data from the component. @@ -563,6 +540,8 @@ namespace ComSquare::PPU //! @brief Update the PPU of n cycles. //! @param The number of cycles to update. void update(unsigned cycles); + //! @brief Give the Vram Address with the right Address remapping + uint8_t getVramAddress(); }; } #endif //COMSQUARE_PPU_HPP diff --git a/sources/SNES.cpp b/sources/SNES.cpp index e1a793c..20646a2 100644 --- a/sources/SNES.cpp +++ b/sources/SNES.cpp @@ -11,7 +11,7 @@ namespace ComSquare SNES::SNES(const std::shared_ptr &bus, const std::string &romPath, Renderer::IRenderer &renderer) : cartridge(new Cartridge::Cartridge(romPath)), cpu(new CPU::CPU(bus, cartridge->header)), - ppu(new PPU::PPU(renderer, bus)), + ppu(new PPU::PPU(bus, renderer)), apu(new APU::APU()), wram(new Ram::Ram(16384)), sram(new Ram::Ram(this->cartridge->header.sramSize)) From ad22881b58cc8d45438fccda782ef17a1c3d7fbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Le=20Bihan?= Date: Wed, 12 Feb 2020 17:52:17 +0100 Subject: [PATCH 18/21] mdr jsp --- sources/PPU/PPU.cpp | 6 +++--- sources/PPU/PPU.hpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sources/PPU/PPU.cpp b/sources/PPU/PPU.cpp index c3b0fa3..329fb5f 100644 --- a/sources/PPU/PPU.cpp +++ b/sources/PPU/PPU.cpp @@ -80,7 +80,6 @@ namespace ComSquare::PPU case ppuRegisters::vmaddh: this->_vmadd.vmaddh = data; break; - //! @info should must be in vblank for the write (and write it to the screen )? and increment vram address after; case ppuRegisters::vmdatal: if (!this->_inidisp.fblank) { this->_vmdata.vmdatal = data; @@ -138,13 +137,14 @@ namespace ComSquare::PPU void PPU::update(unsigned cycles) { (void)cycles; - int inc = 0; + int inc = getVramAddress(); uint32_t pixelTmp = 0xFFFFFFFF; //pixelTmp |= this->_inidisp.brightness; if (!this->_inidisp.fblank) { for (int x = 0; x < 448; x++) { for (int y = 0; y < 512; y++) { - this->_renderer.putPixel(x, y, (uint32_t)_vram[inc++] << 8U + 0xFFU); + //this->_renderer.putPixel(x, y, ((uint32_t)_vram[inc++] << 8U) + 0xFFU); + this->_renderer.putPixel(x, y, (uint32_t)this->_bus->read(inc++)); } } } diff --git a/sources/PPU/PPU.hpp b/sources/PPU/PPU.hpp index 836d017..8a8073f 100644 --- a/sources/PPU/PPU.hpp +++ b/sources/PPU/PPU.hpp @@ -286,7 +286,7 @@ namespace ComSquare::PPU }; uint8_t raw; } _bgnba[2]; - //! @brief BGXXOFS Register (BG1/2/3/4 Horizontal and Vertical Scroll) + //! @brief BGXXOFS Register (BG1/2/3/4 Horizontal and Vertical Scrolls) union { struct { uint16_t offsetBg: 10; From 62a36d98b0958b1fa9c14b19f2777f3e10f87ca8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Le=20Bihan?= Date: Thu, 13 Feb 2020 00:10:50 +0100 Subject: [PATCH 19/21] added 0x2123 - 0x212D ppu registers w/ tests --- sources/PPU/PPU.cpp | 35 +++++++- sources/PPU/PPU.hpp | 73 +++++++--------- tests/PPU/testPpuWriteFromVmain.cpp | 124 ++++++++++++++++++++++++++++ 3 files changed, 189 insertions(+), 43 deletions(-) diff --git a/sources/PPU/PPU.cpp b/sources/PPU/PPU.cpp index 329fb5f..6411f68 100644 --- a/sources/PPU/PPU.cpp +++ b/sources/PPU/PPU.cpp @@ -83,7 +83,7 @@ namespace ComSquare::PPU case ppuRegisters::vmdatal: if (!this->_inidisp.fblank) { this->_vmdata.vmdatal = data; - this->_vram[getVramAddress()] = this->_vmdata.vmdata; + //this->_vram[getVramAddress()] = this->_vmdata.vmdata; } if (!this->_vmain.incrementMode) this->_vmadd.vmadd += this->_vmain.incrementAmount; @@ -91,11 +91,14 @@ namespace ComSquare::PPU case ppuRegisters::vmdatah: if (!this->_inidisp.fblank) { this->_vmdata.vmdatah = data; - this->_vram[getVramAddress()] = this->_vmdata.vmdata; + //this->_vram[getVramAddress()] = this->_vmdata.vmdata; } if (this->_vmain.incrementMode) this->_vmadd.vmadd += this->_vmain.incrementAmount; break; + case ppuRegisters::m7sel: + this->_m7sel.raw = data; + break; case ppuRegisters::cgadd: this->_cgadd = data; this->_isLowByte = true; @@ -112,6 +115,33 @@ namespace ComSquare::PPU this->_isLowByte = !this->_isLowByte; this->_cgadd++; break; + case ppuRegisters::w12sel: + case ppuRegisters::w34sel: + case ppuRegisters::wobjsel: + this->_wsel[addr - ppuRegisters::w12sel].raw = data; + break; + case ppuRegisters::wh0: + this->_wh0 = data; + break; + case ppuRegisters::wh1: + this->_wh1 = data; + break; + case ppuRegisters::wh2: + this->_wh2 = data; + break; + case ppuRegisters::wh3: + this->_wh3 = data; + break; + case ppuRegisters::wbjlog: + this->_wbglog.raw = data; + break; + case ppuRegisters::wobjlog: + this->_wobjlog.raw = data; + break; + case ppuRegisters::tm: + case ppuRegisters::ts: + this->_t[addr - ppuRegisters::tm].raw = data; + break; //TODO adding the rest of the registers. oaf ! default: throw InvalidAddress("PPU Internal Registers write", addr); @@ -155,6 +185,7 @@ namespace ComSquare::PPU _bus(std::move(bus)), _renderer(renderer) { + this->_isLowByte = true; //_vram = new uint16_t[32000]; } } \ No newline at end of file diff --git a/sources/PPU/PPU.hpp b/sources/PPU/PPU.hpp index 8a8073f..9651198 100644 --- a/sources/PPU/PPU.hpp +++ b/sources/PPU/PPU.hpp @@ -332,17 +332,20 @@ namespace ComSquare::PPU //! @brief TODO M7SEL Register (Mode 7 Settings) union { struct { - bool playingFieldSize: 1; - bool emptySpaceFill: 1; - uint8_t _: 4; bool horizontalMirroring: 1; bool verticalMirroring: 1; + uint8_t _: 4; + bool emptySpaceFill: 1; + bool playingFieldSize: 1; }; uint8_t raw; } _m7sel; //! M7A M7B M7C M7D i didn't understand how they works so they will be added later. + + // + //! @brief M7X Register (Mode 7 Center X) - union { + union { // Not sure if it is done correctly struct { uint8_t _: 3; uint8_t value; @@ -350,7 +353,7 @@ namespace ComSquare::PPU uint32_t center; } _m7x; //! @brief M7Y Register (Mode 7 Center Y) - union { + union { // Not sure if it is done correctly struct { uint8_t _: 3; uint8_t value; @@ -389,58 +392,46 @@ namespace ComSquare::PPU bool window1InversionForBg1Bg2Obj: 1; }; uint8_t raw; - } _wsel; + } _wsel[3]; //! @brief WH0 Register (CWindow 1 Left Position) - uint8_t wh0; + uint8_t _wh0; //! @brief WH1 Register (CWindow 1 Right Position) - uint8_t wh1; + uint8_t _wh1; //! @brief WH2 Register (CWindow 2 Left Position) - uint8_t wh2; + uint8_t _wh2; //! @brief WH3 Register (CWindow 2 Right Position) - uint8_t wh3; + uint8_t _wh3; //! @brief WBGLOG Register (Window mask logic for BGs) union { struct { - uint8_t maskLogicBg1: 2; - uint8_t maskLogicBg2: 2; - uint8_t maskLogicBg3: 2; uint8_t maskLogicBg4: 2; + uint8_t maskLogicBg3: 2; + uint8_t maskLogicBg2: 2; + uint8_t maskLogicBg1: 2; }; uint8_t raw; - } wbglog; + } _wbglog; //! @brief WOBJLOG Register (Window mask logic for OBJs and Color Window) union { struct { - uint8_t _: 4; uint8_t maskLogicObj: 2; uint8_t maskLogicColor: 2; + uint8_t _: 4; }; uint8_t raw; - } wobjlog; - //! @brief TM Register (Main Screen Designation) + } _wobjlog; + //! @brief TM - TS Registers (Main & Sub Screen Designation) union { struct { - uint8_t _: 3; - bool enableWindowDisplayObj: 1; - bool enableWindowDisplayBg4: 1; - bool enableWindowDisplayBg3: 1; - bool enableWindowDisplayBg2: 1; bool enableWindowDisplayBg1: 1; + bool enableWindowDisplayBg2: 1; + bool enableWindowDisplayBg3: 1; + bool enableWindowDisplayBg4: 1; + bool enableWindowDisplayObj: 1; + uint8_t _: 3; }; uint8_t raw; - } tm; - //! @brief TS Register (Sub Screen Designation) - union { - struct { - uint8_t _: 3; - bool enableWindowDisplayObj: 1; - bool enableWindowDisplayBg4: 1; - bool enableWindowDisplayBg3: 1; - bool enableWindowDisplayBg2: 1; - bool enableWindowDisplayBg1: 1; - }; - uint8_t raw; - } ts; + } _t[2]; //! @brief TMW Register (Window Mask Designation for the Main Screen) union { struct { @@ -452,7 +443,7 @@ namespace ComSquare::PPU bool enableWindowMaskingBg1: 1; }; uint8_t raw; - } tmw; + } _tmw; //! @brief TSW Register (Window Mask Designation for the Sub Screen) union { struct { @@ -464,7 +455,7 @@ namespace ComSquare::PPU bool enableWindowMaskingBg1: 1; }; uint8_t raw; - } tsw; + } _tsw; //! @brief CGWSEL Register (Color Addition Select) union { struct { @@ -475,7 +466,7 @@ namespace ComSquare::PPU bool directColorMode: 1; }; uint8_t raw; - } cgwsel; + } _cgwsel; //! @brief CGADSUB Register (Color Math designation) union { struct { @@ -489,7 +480,7 @@ namespace ComSquare::PPU bool enableColorMathBg1: 1; }; uint8_t raw; - } cgadsub; + } _cgadsub; //! @brief COLDATA Register (Fixed Color Data) union { struct { @@ -499,7 +490,7 @@ namespace ComSquare::PPU uint8_t colorIntensity: 5; }; uint8_t raw; - } coldata; + } _coldata; //! @brief SETINI Register (Screen Mode/Video Select) union { struct { @@ -512,7 +503,7 @@ namespace ComSquare::PPU bool screenInterlace: 1; }; uint8_t raw; - } setini; + } _setini; //! @brief MPYL - MPYM - MPYH Registers (Multiplication Result) union { struct { diff --git a/tests/PPU/testPpuWriteFromVmain.cpp b/tests/PPU/testPpuWriteFromVmain.cpp index db2bf62..1ddbc8b 100644 --- a/tests/PPU/testPpuWriteFromVmain.cpp +++ b/tests/PPU/testPpuWriteFromVmain.cpp @@ -77,4 +77,128 @@ Test(PPU_write_2, vmdata_full_high_byte_null) pair.first->write(0x2118, 0b11111111); pair.first->write(0x2119, 0b00000000); cr_assert_eq(pair.second.ppu->_vmdata.vmdata, 0b0000000011111111); +} + +Test(PPU_write_2, cgadd_full_high_byte_null) +{ + auto pair = Init(); + pair.first->write(0x2121, 0b11111111); + cr_assert_eq(pair.second.ppu->_cgadd, 0b11111111); + cr_assert_eq(pair.second.ppu->_isLowByte, true); +} + +Test(PPU_write_2, cgdata_data_full) +{ + auto pair = Init(); + pair.first->write(0x2121, 0b11111111); + pair.first->write(0x2122, 0b11111111); + cr_assert_eq(pair.second.ppu->_cgdata.cgdatal, 0b11111111); + cr_assert_eq(pair.second.ppu->_isLowByte, false); + int address = pair.second.ppu->_cgadd; + pair.first->write(0x2122, 0b11111000); + cr_assert_eq(pair.second.ppu->_cgdata.cgdatah, 0b11111000); + cr_assert_eq(pair.second.ppu->_isLowByte, true); + cr_assert_eq(pair.second.ppu->_cgadd, address + 1); +} + +Test(PPU_write_2, m7sel_data_full) +{ + auto pair = Init(); + pair.first->write(0x211A, 0b11111111); + cr_assert_eq(pair.second.ppu->_m7sel.playingFieldSize, true); + cr_assert_eq(pair.second.ppu->_m7sel.emptySpaceFill, true); + cr_assert_eq(pair.second.ppu->_m7sel.horizontalMirroring, true); + cr_assert_eq(pair.second.ppu->_m7sel.verticalMirroring, true); +} + +Test(PPU_write_2, m7sel_data_actual) +{ + auto pair = Init(); + pair.first->write(0x211A, 0b01111101); + cr_assert_eq(pair.second.ppu->_m7sel.playingFieldSize, false); + cr_assert_eq(pair.second.ppu->_m7sel.emptySpaceFill, true); + cr_assert_eq(pair.second.ppu->_m7sel.horizontalMirroring, true); + cr_assert_eq(pair.second.ppu->_m7sel.verticalMirroring, false); +} + +Test(PPU_write_2, w12sel_data_full) +{ + auto pair = Init(); + pair.first->write(0x2123, 0b11111111); + cr_assert_eq(pair.second.ppu->_wsel[0].window1InversionForBg1Bg2Obj, true); + cr_assert_eq(pair.second.ppu->_wsel[0].enableWindow1ForBg1Bg2Obj, true); + cr_assert_eq(pair.second.ppu->_wsel[0].window2InversionForBg1Bg3Obj, true); + cr_assert_eq(pair.second.ppu->_wsel[0].enableWindow2ForBg1Bg3Obj, true); + cr_assert_eq(pair.second.ppu->_wsel[0].window1InversionForBg2Bg4Color, true); + cr_assert_eq(pair.second.ppu->_wsel[0].enableWindow1ForBg2Bg4Color, true); + cr_assert_eq(pair.second.ppu->_wsel[0].window2InversionForBg2Bg4Color, true); + cr_assert_eq(pair.second.ppu->_wsel[0].enableWindow2ForBg2Bg4Color, true); +} + +Test(PPU_write_2, w34sel_data_full) +{ + auto pair = Init(); + pair.first->write(0x2124, 0b10101010); + cr_assert_eq(pair.second.ppu->_wsel[1].window1InversionForBg1Bg2Obj, true); + cr_assert_eq(pair.second.ppu->_wsel[1].enableWindow1ForBg1Bg2Obj, false); + cr_assert_eq(pair.second.ppu->_wsel[1].window2InversionForBg1Bg3Obj, true); + cr_assert_eq(pair.second.ppu->_wsel[1].enableWindow2ForBg1Bg3Obj, false); + cr_assert_eq(pair.second.ppu->_wsel[1].window1InversionForBg2Bg4Color, true); + cr_assert_eq(pair.second.ppu->_wsel[1].enableWindow1ForBg2Bg4Color, false); + cr_assert_eq(pair.second.ppu->_wsel[1].window2InversionForBg2Bg4Color, true); + cr_assert_eq(pair.second.ppu->_wsel[1].enableWindow2ForBg2Bg4Color, false); +} + +Test(PPU_write_2, wobjsel_data_full) +{ + auto pair = Init(); + pair.first->write(0x2125, 0b10110001); + cr_assert_eq(pair.second.ppu->_wsel[2].window1InversionForBg1Bg2Obj, true); + cr_assert_eq(pair.second.ppu->_wsel[2].enableWindow1ForBg1Bg2Obj, false); + cr_assert_eq(pair.second.ppu->_wsel[2].window2InversionForBg1Bg3Obj, true); + cr_assert_eq(pair.second.ppu->_wsel[2].enableWindow2ForBg1Bg3Obj, true); + cr_assert_eq(pair.second.ppu->_wsel[2].window1InversionForBg2Bg4Color, false); + cr_assert_eq(pair.second.ppu->_wsel[2].enableWindow1ForBg2Bg4Color, false); + cr_assert_eq(pair.second.ppu->_wsel[2].window2InversionForBg2Bg4Color, false); + cr_assert_eq(pair.second.ppu->_wsel[2].enableWindow2ForBg2Bg4Color, true); +} + +Test(PPU_write_2, wbglog_data_full) +{ + auto pair = Init(); + pair.first->write(0x212A, 0b10110001); + cr_assert_eq(pair.second.ppu->_wbglog.maskLogicBg1, 0b10); + cr_assert_eq(pair.second.ppu->_wbglog.maskLogicBg2, 0b11); + cr_assert_eq(pair.second.ppu->_wbglog.maskLogicBg3, 0b00); + cr_assert_eq(pair.second.ppu->_wbglog.maskLogicBg4, 0b01); +} + +Test(PPU_write_2, wobjlog_data_full) +{ + auto pair = Init(); + pair.first->write(0x212B, 0b10110001); + cr_assert_eq(pair.second.ppu->_wobjlog.maskLogicObj, 0b01); + cr_assert_eq(pair.second.ppu->_wobjlog.maskLogicColor, 0b00); +} + +Test(PPU_write_2, tm_data_full) +{ + auto pair = Init(); + pair.first->write(0x212C, 0b10110001); + cr_assert_eq(pair.second.ppu->_t[0].enableWindowDisplayBg1, true); + cr_assert_eq(pair.second.ppu->_t[0].enableWindowDisplayBg2, false); + cr_assert_eq(pair.second.ppu->_t[0].enableWindowDisplayBg3, false); + cr_assert_eq(pair.second.ppu->_t[0].enableWindowDisplayBg4, false); + cr_assert_eq(pair.second.ppu->_t[0].enableWindowDisplayObj, true); +} + +Test(PPU_write_2, ts_data_full) +{ + auto pair = Init(); + pair.first->write(0x212D, 0b10101110); + cr_assert_eq(pair.second.ppu->_t[1].enableWindowDisplayBg1, false); + cr_assert_eq(pair.second.ppu->_t[1].enableWindowDisplayBg2, true); + cr_assert_eq(pair.second.ppu->_t[1].enableWindowDisplayBg3, true); + cr_assert_eq(pair.second.ppu->_t[1].enableWindowDisplayBg4, true); + cr_assert_eq(pair.second.ppu->_t[1].enableWindowDisplayObj, false); } \ No newline at end of file From a6c3e54f9fab0665dccfb28e17e26541a883e417 Mon Sep 17 00:00:00 2001 From: AnonymusRaccoon Date: Thu, 13 Feb 2020 11:09:18 +0100 Subject: [PATCH 20/21] Fixing a bug with the write in 0x0 --- CMakeLists.txt | 2 +- sources/CPU/CPU.cpp | 11 +++++++ sources/CPU/CPU.hpp | 2 ++ sources/Exceptions/InvalidAction.hpp | 2 +- sources/Exceptions/InvalidAddress.hpp | 20 +++++++++++- sources/Exceptions/InvalidRom.hpp | 2 +- .../Exceptions/NotImplementedException.hpp | 2 +- sources/Memory/IRectangleMemory.cpp | 8 ++--- tests/CPU/testAddressingMode.cpp | 4 +++ tests/CPU/testStore.cpp | 20 ++++++++++++ tests/testMemoryBus.cpp | 32 +++++++++++++++++++ 11 files changed, 96 insertions(+), 9 deletions(-) create mode 100644 tests/CPU/testStore.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 9766372..5ab3a26 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -52,7 +52,7 @@ add_executable(unit_tests sources/CPU/Instructions/CommonInstructions.hpp sources/Exceptions/InvalidOpcode.hpp sources/CPU/Instructions/Interrupts.cpp - sources/CPU/Instructions/MathematicalOperations.cpp tests/CPU/Math/testADC.cpp) + sources/CPU/Instructions/MathematicalOperations.cpp tests/CPU/Math/testADC.cpp tests/CPU/testStore.cpp) # include criterion & coverage target_link_libraries(unit_tests criterion -lgcov) diff --git a/sources/CPU/CPU.cpp b/sources/CPU/CPU.cpp index aeeefa0..40246b7 100644 --- a/sources/CPU/CPU.cpp +++ b/sources/CPU/CPU.cpp @@ -441,4 +441,15 @@ namespace ComSquare::CPU base += this->_registers.dbr << 16u; return base + this->_registers.y; } + + unsigned CPU::STA(uint24_t addr) + { + if (this->_registers.p.m) + this->_bus->write(addr, this->_registers.al); + else { + this->_bus->write(addr, this->_registers.al); + this->_bus->write(addr + 1, this->_registers.ah); + } + return 0; + } } \ No newline at end of file diff --git a/sources/CPU/CPU.hpp b/sources/CPU/CPU.hpp index 960dbae..f74a8bf 100644 --- a/sources/CPU/CPU.hpp +++ b/sources/CPU/CPU.hpp @@ -288,6 +288,8 @@ namespace ComSquare::CPU //! @brief Add with carry - Adds operand to the Accumulator; adds an additional 1 if carry is set. //! @return The number of extra cycles that this operation took. unsigned ADC(uint24_t valueAddr); + //! @brief Store the accumulator to memory. + unsigned STA(uint24_t addr); public: explicit CPU(std::shared_ptr bus, Cartridge::Header &cartridgeHeader); //! @brief This function continue to execute the Cartridge code. diff --git a/sources/Exceptions/InvalidAction.hpp b/sources/Exceptions/InvalidAction.hpp index a7827ea..8b9c06a 100644 --- a/sources/Exceptions/InvalidAction.hpp +++ b/sources/Exceptions/InvalidAction.hpp @@ -11,7 +11,7 @@ namespace ComSquare { //! @brief Exception thrown when someone tries to load an invalid rom. - class InvalidAction : std::exception { + class InvalidAction : public std::exception { private: std::string _msg; public: diff --git a/sources/Exceptions/InvalidAddress.hpp b/sources/Exceptions/InvalidAddress.hpp index beb3d8c..09724ae 100644 --- a/sources/Exceptions/InvalidAddress.hpp +++ b/sources/Exceptions/InvalidAddress.hpp @@ -13,7 +13,7 @@ namespace ComSquare { //! @brief Exception thrown when trying to read/write to an invalid address. - class InvalidAddress : std::exception { + class InvalidAddress : public std::exception { private: std::string _msg; public: @@ -25,6 +25,24 @@ namespace ComSquare } const char *what() const noexcept override { return this->_msg.c_str(); } }; + + //! @brief Exception thrown when trying to read/write to an invalid address in a rectangle memory region. + class InvalidRectangleAddress : public std::exception { + private: + std::string _msg; + public: + InvalidRectangleAddress(std::string where, int32_t addr, int16_t subaddr, int16_t start, int16_t end) + { + std::stringstream stream; + stream << "Could not read/write data at address: 0x" << std::hex << addr << " from " << where; + if (subaddr < start) + stream << " (" << std::hex << subaddr << " < " << start << ")"; + else + stream << " (" << std::hex << subaddr << " > " << end << ")"; + this->_msg = stream.str(); + } + const char *what() const noexcept override { return this->_msg.c_str(); } + }; } #endif //COMSQUARE_INVALIDADDRESS_HPP diff --git a/sources/Exceptions/InvalidRom.hpp b/sources/Exceptions/InvalidRom.hpp index acbf0b3..433c478 100644 --- a/sources/Exceptions/InvalidRom.hpp +++ b/sources/Exceptions/InvalidRom.hpp @@ -11,7 +11,7 @@ namespace ComSquare { //! @brief Exception thrown when someone tries to load an invalid rom. - class InvalidRomException : std::exception { + class InvalidRomException : public std::exception { private: std::string _msg; public: diff --git a/sources/Exceptions/NotImplementedException.hpp b/sources/Exceptions/NotImplementedException.hpp index 762c655..8aba3e6 100644 --- a/sources/Exceptions/NotImplementedException.hpp +++ b/sources/Exceptions/NotImplementedException.hpp @@ -10,7 +10,7 @@ namespace ComSquare { //! @brief When this is thrown, it means that we should work more. - class NotImplementedException : std::exception { + class NotImplementedException : public std::exception { public: explicit NotImplementedException() = default; const char *what() const noexcept override { return "Not implemented yet."; } diff --git a/sources/Memory/IRectangleMemory.cpp b/sources/Memory/IRectangleMemory.cpp index df5e7ef..9340572 100644 --- a/sources/Memory/IRectangleMemory.cpp +++ b/sources/Memory/IRectangleMemory.cpp @@ -31,10 +31,10 @@ namespace ComSquare::Memory unsigned bankCount = bank - this->_startBank; unsigned pageCount = this->_endPage - this->_startPage; - if (bank < this->_startBank || bank >= this->_endBank) - throw InvalidAddress("Rectangle memory write Invalid Bank", addr); - if (page < this->_startPage || page >= this->_endPage) - throw InvalidAddress("Rectangle memory write Invalid Page", addr); + if (bank < this->_startBank || bank > this->_endBank) + throw InvalidRectangleAddress("Rectangle memory write Invalid Bank", addr, bank, this->_startBank, this->_endBank); + if (page < this->_startPage || page > this->_endPage) + throw InvalidRectangleAddress("Rectangle memory write Invalid Page", addr, page, this->_startPage, this->_endPage); page -= this->_startPage; page += pageCount * bankCount; this->write_internal(page, data); diff --git a/tests/CPU/testAddressingMode.cpp b/tests/CPU/testAddressingMode.cpp index e52b695..3d09508 100644 --- a/tests/CPU/testAddressingMode.cpp +++ b/tests/CPU/testAddressingMode.cpp @@ -20,6 +20,8 @@ Test(AddrMode, Immediate) { auto pair = Init(); pair.second.cpu->_registers.pac = 0x000015; + pair.second.cpu->_isEmulationMode = true; + pair.second.cpu->_registers.p.m = false; cr_assert_eq(pair.second.cpu->_getImmediateAddr(), 0x000015, "Got %x, Expected 0x000015"); cr_assert_eq(pair.second.cpu->_registers.pac, 0x000016); } @@ -27,6 +29,7 @@ Test(AddrMode, Immediate) Test(AddrMode, ImmediateMemoryFlag) { auto pair = Init(); + pair.second.cpu->_isEmulationMode = true; pair.second.cpu->_registers.pac = 0x000015; pair.second.cpu->_registers.p.m = true; cr_assert_eq(pair.second.cpu->_getImmediateAddr(), 0x000015, "Got %x, Expected 0x000015"); @@ -37,6 +40,7 @@ Test(AddrMode, ImmediateBankChange) { auto pair = Init(); pair.second.cpu->_registers.pac = 0x00FFFF; + pair.second.cpu->_registers.p.m = false; cr_assert_eq(pair.second.cpu->_getImmediateAddr(), 0x00FFFF); cr_assert_eq(pair.second.cpu->_registers.pac, 0x010000); } diff --git a/tests/CPU/testStore.cpp b/tests/CPU/testStore.cpp new file mode 100644 index 0000000..914ecfc --- /dev/null +++ b/tests/CPU/testStore.cpp @@ -0,0 +1,20 @@ +// +// Created by anonymus-raccoon on 2/12/20. +// + +#include +#include +#include +#include "../tests.hpp" +#include "../../sources/SNES.hpp" +using namespace ComSquare; +// +//Test(STA, 8bits) +//{ +// auto pair = Init(); +// pair.second.cpu->_registers.p.m = false; +// pair.second.cpu->_registers.a = 0x11; +// pair.second.cpu->STA(0x0); +// auto data = pair.second.wram->_data[0]; +// cr_assert_eq(data, 0x11, "The stored value should be 0x11 but it was 0x%x.", data); +//} \ No newline at end of file diff --git a/tests/testMemoryBus.cpp b/tests/testMemoryBus.cpp index ed9488d..b79ca1e 100644 --- a/tests/testMemoryBus.cpp +++ b/tests/testMemoryBus.cpp @@ -261,12 +261,31 @@ Test(BusAccessor, GetRomMirror3) cr_assert_eq(accessor->_initial.get(), pair.second.cartridge.get()); } +Test(BusAccessor, Get0x0) +{ + auto pair = Init(); + std::shared_ptr accessor = nullptr; + + accessor = std::static_pointer_cast(pair.first->getAccessor(0x0)); + cr_assert_eq(accessor->_initial.get(), pair.second.wram.get()); +} + /////////////////////////// // // // MemoryBus::read tests // // // /////////////////////////// +Test(BusRead, Read0x0) +{ + auto pair = Init(); + uint8_t data; + + pair.second.wram->_data[0] = 123; + data = pair.first->read(0x0); + cr_assert_eq(data, 123); +} + Test(BusRead, ReadOutside, .init = cr_redirect_stdout) { auto pair = Init(); @@ -394,6 +413,19 @@ Test(BusRead, ReadWRAMMirror) // // //////////////////////////// +Test(BusWrite, Write0x0) +{ + auto pair = Init(); + + try { + pair.first->write(0x0, 123); + } catch (std::exception &ex) { + std::cout << ex.what() << std::endl; + } + cr_assert_eq(pair.second.wram->_data[0], 123); +} + + Test(BusWrite, WriteAPU) { auto pair = Init(); From c5fa9906c1f523aae3e36ac734e21990e7425135 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Le=20Bihan?= Date: Thu, 13 Feb 2020 11:16:29 +0100 Subject: [PATCH 21/21] all ppu registers write (except write registers to vram cgram & oamram)) --- sources/PPU/PPU.cpp | 18 +++++++- sources/PPU/PPU.hpp | 57 ++++++++++++----------- tests/PPU/testPpuWriteFromVmain.cpp | 70 ++++++++++++++++++++++++++++- 3 files changed, 116 insertions(+), 29 deletions(-) diff --git a/sources/PPU/PPU.cpp b/sources/PPU/PPU.cpp index 6411f68..1e59f57 100644 --- a/sources/PPU/PPU.cpp +++ b/sources/PPU/PPU.cpp @@ -142,6 +142,22 @@ namespace ComSquare::PPU case ppuRegisters::ts: this->_t[addr - ppuRegisters::tm].raw = data; break; + case ppuRegisters::tmw: + case ppuRegisters::tsw: + this->_tw[addr - ppuRegisters::tmw].raw = data; + break; + case ppuRegisters::cgwsel: + this->_cgwsel.raw = data; + break; + case ppuRegisters::cgadsub: + this->_cgadsub.raw = data; + break; + case ppuRegisters::coldata: + this->_coldata.raw = data; + break; + case ppuRegisters::setini: + this->_setini.raw = data; + break; //TODO adding the rest of the registers. oaf ! default: throw InvalidAddress("PPU Internal Registers write", addr); @@ -168,7 +184,7 @@ namespace ComSquare::PPU { (void)cycles; int inc = getVramAddress(); - uint32_t pixelTmp = 0xFFFFFFFF; + //uint32_t pixelTmp = 0xFFFFFFFF; //pixelTmp |= this->_inidisp.brightness; if (!this->_inidisp.fblank) { for (int x = 0; x < 448; x++) { diff --git a/sources/PPU/PPU.hpp b/sources/PPU/PPU.hpp index 9651198..41020da 100644 --- a/sources/PPU/PPU.hpp +++ b/sources/PPU/PPU.hpp @@ -432,18 +432,18 @@ namespace ComSquare::PPU }; uint8_t raw; } _t[2]; - //! @brief TMW Register (Window Mask Designation for the Main Screen) + //! @brief TMW - TSW Registers (Window Mask Designation for the Main/Sub Screen) union { struct { - uint8_t _: 3; - bool enableWindowMaskingObj: 1; - bool enableWindowMaskingBg4: 1; - bool enableWindowMaskingBg3: 1; - bool enableWindowMaskingBg2: 1; bool enableWindowMaskingBg1: 1; + bool enableWindowMaskingBg2: 1; + bool enableWindowMaskingBg3: 1; + bool enableWindowMaskingBg4: 1; + bool enableWindowMaskingObj: 1; + uint8_t _: 3; }; uint8_t raw; - } _tmw; + } _tw[2]; //! @brief TSW Register (Window Mask Designation for the Sub Screen) union { struct { @@ -459,51 +459,54 @@ namespace ComSquare::PPU //! @brief CGWSEL Register (Color Addition Select) union { struct { - uint8_t clipColorToBlackBeforeMath: 2; - uint8_t preventColorMath: 2; - uint8_t _: 2; - bool addSubscreen: 1; bool directColorMode: 1; + bool addSubscreen: 1; + uint8_t _: 2; + uint8_t preventColorMath: 2; + uint8_t clipColorToBlackBeforeMath: 2; }; uint8_t raw; } _cgwsel; //! @brief CGADSUB Register (Color Math designation) union { struct { - bool addSubtractSelect: 1; - bool halfColorMath: 1; - bool enableColorMathBackdrop: 1; - bool enableColorMathObj: 1; - bool enableColorMathBg4: 1; - bool enableColorMathBg3: 1; - bool enableColorMathBg2: 1; bool enableColorMathBg1: 1; + bool enableColorMathBg2: 1; + bool enableColorMathBg3: 1; + bool enableColorMathBg4: 1; + bool enableColorMathObj: 1; + bool enableColorMathBackdrop: 1; + bool halfColorMath: 1; + bool addSubtractSelect: 1; }; uint8_t raw; } _cgadsub; //! @brief COLDATA Register (Fixed Color Data) union { struct { - bool blue: 1; - bool green: 1; - bool red: 1; uint8_t colorIntensity: 5; + bool red: 1; + bool green: 1; + bool blue: 1; }; uint8_t raw; } _coldata; //! @brief SETINI Register (Screen Mode/Video Select) union { struct { - bool externalSync: 1; - bool mode7ExtBg: 1; - uint8_t _: 2; - bool enablePseudoHiresMode: 1; - bool overscanMode: 1; - bool objInterlace: 1; bool screenInterlace: 1; + bool objInterlace: 1; + bool overscanMode: 1; + bool enablePseudoHiresMode: 1; + uint8_t _: 2; + bool mode7ExtBg: 1; + bool externalSync: 1; }; uint8_t raw; } _setini; + + // not in priority + //! @brief MPYL - MPYM - MPYH Registers (Multiplication Result) union { struct { diff --git a/tests/PPU/testPpuWriteFromVmain.cpp b/tests/PPU/testPpuWriteFromVmain.cpp index 1ddbc8b..fe21962 100644 --- a/tests/PPU/testPpuWriteFromVmain.cpp +++ b/tests/PPU/testPpuWriteFromVmain.cpp @@ -90,7 +90,7 @@ Test(PPU_write_2, cgadd_full_high_byte_null) Test(PPU_write_2, cgdata_data_full) { auto pair = Init(); - pair.first->write(0x2121, 0b11111111); + pair.first->write(0x2121, 0x0); pair.first->write(0x2122, 0b11111111); cr_assert_eq(pair.second.ppu->_cgdata.cgdatal, 0b11111111); cr_assert_eq(pair.second.ppu->_isLowByte, false); @@ -201,4 +201,72 @@ Test(PPU_write_2, ts_data_full) cr_assert_eq(pair.second.ppu->_t[1].enableWindowDisplayBg3, true); cr_assert_eq(pair.second.ppu->_t[1].enableWindowDisplayBg4, true); cr_assert_eq(pair.second.ppu->_t[1].enableWindowDisplayObj, false); +} + +Test(PPU_write_2, tmw_data_full) +{ + auto pair = Init(); + pair.first->write(0x212E, 0b10101110); + cr_assert_eq(pair.second.ppu->_tw[0].enableWindowMaskingBg1, false); + cr_assert_eq(pair.second.ppu->_tw[0].enableWindowMaskingBg2, true); + cr_assert_eq(pair.second.ppu->_tw[0].enableWindowMaskingBg3, true); + cr_assert_eq(pair.second.ppu->_tw[0].enableWindowMaskingBg4, true); + cr_assert_eq(pair.second.ppu->_tw[0].enableWindowMaskingObj, false); +} + +Test(PPU_write_2, tsw_data_full) +{ + auto pair = Init(); + pair.first->write(0x212F, 0b10100011); + cr_assert_eq(pair.second.ppu->_tw[1].enableWindowMaskingBg1, true); + cr_assert_eq(pair.second.ppu->_tw[1].enableWindowMaskingBg2, true); + cr_assert_eq(pair.second.ppu->_tw[1].enableWindowMaskingBg3, false); + cr_assert_eq(pair.second.ppu->_tw[1].enableWindowMaskingBg4, false); + cr_assert_eq(pair.second.ppu->_tw[1].enableWindowMaskingObj, false); +} + +Test(PPU_write_2, cgwsel_data_full) +{ + auto pair = Init(); + pair.first->write(0x2130, 0b10111001); + cr_assert_eq(pair.second.ppu->_cgwsel.clipColorToBlackBeforeMath, 0b10); + cr_assert_eq(pair.second.ppu->_cgwsel.preventColorMath, 0b11); + cr_assert_eq(pair.second.ppu->_cgwsel.addSubscreen, false); + cr_assert_eq(pair.second.ppu->_cgwsel.directColorMode, true); +} + +Test(PPU_write_2, cgadsub_data_full) +{ + auto pair = Init(); + pair.first->write(0x2131, 0b10111001); + cr_assert_eq(pair.second.ppu->_cgadsub.addSubtractSelect, true); + cr_assert_eq(pair.second.ppu->_cgadsub.halfColorMath, false); + cr_assert_eq(pair.second.ppu->_cgadsub.enableColorMathBackdrop, true); + cr_assert_eq(pair.second.ppu->_cgadsub.enableColorMathObj, true); + cr_assert_eq(pair.second.ppu->_cgadsub.enableColorMathBg4, true); + cr_assert_eq(pair.second.ppu->_cgadsub.enableColorMathBg3, false); + cr_assert_eq(pair.second.ppu->_cgadsub.enableColorMathBg2, false); + cr_assert_eq(pair.second.ppu->_cgadsub.enableColorMathBg1, true); +} + +Test(PPU_write_2, coldata_data_full) +{ + auto pair = Init(); + pair.first->write(0x2132, 0b10111001); + cr_assert_eq(pair.second.ppu->_coldata.blue, true); + cr_assert_eq(pair.second.ppu->_coldata.green, false); + cr_assert_eq(pair.second.ppu->_coldata.red, true); + cr_assert_eq(pair.second.ppu->_coldata.colorIntensity, 0b11001); +} + +Test(PPU_write_2, setini_data_full) +{ + auto pair = Init(); + pair.first->write(0x2133, 0b10111001); + cr_assert_eq(pair.second.ppu->_setini.externalSync, true); + cr_assert_eq(pair.second.ppu->_setini.mode7ExtBg, false); + cr_assert_eq(pair.second.ppu->_setini.enablePseudoHiresMode, true); + cr_assert_eq(pair.second.ppu->_setini.overscanMode, false); + cr_assert_eq(pair.second.ppu->_setini.objInterlace, false); + cr_assert_eq(pair.second.ppu->_setini.screenInterlace, true); } \ No newline at end of file