diff --git a/main.cpp b/main.cpp index 36cc9e6..d9be8d4 100644 --- a/main.cpp +++ b/main.cpp @@ -4,7 +4,6 @@ #include #include -#include "sources/Renderer/IRenderer.hpp" #include "sources/SNES.hpp" #include "sources/Renderer/SFRenderer.hpp" @@ -16,29 +15,18 @@ int main(int argc, char **argv) std::cout << "ComSquare:" << std::endl << "\tUsage: " << argv[0] << " rom_path" << std::endl; return 1; } - Memory::MemoryBus bus; - Renderer::SFRenderer renderer(600, 800, 60); - SNES snes(std::make_shared(bus), argv[1], renderer); - bus.mapComponents(snes); - int incx = 0; - int incy = 0; - uint32_t pixel = 0x000000FF; + try { + Renderer::SFRenderer renderer(600, 800, 60); + SNES snes(std::make_shared(), argv[1], renderer); + while (!renderer.shouldExit) { + unsigned cycleCount = snes.cpu->update(); + snes.ppu->update(cycleCount); + snes.apu->update(cycleCount); - while (!renderer.shouldExit) { - renderer.putPixel(incy, incx++, pixel); - if (incx >= 800) { - incx = 0; - incy++; + renderer.getEvents(); } - if (incy >= 600) { - incy = 0; - } - if (incx == 0) { - renderer.drawScreen(); - pixel += 0xFF00FF00; - } - renderer.getEvents(); + } catch (std::exception &e) { + std::cerr << "An error occurred: " << e.what() << std::endl; } - return 0; } \ No newline at end of file diff --git a/sources/APU/APU.cpp b/sources/APU/APU.cpp index cdf06f4..e46219e 100644 --- a/sources/APU/APU.cpp +++ b/sources/APU/APU.cpp @@ -47,8 +47,8 @@ namespace ComSquare::APU } } - bool APU::update() + void APU::update(unsigned cycles) { - throw NotImplementedException(); + (void)cycles; } } diff --git a/sources/APU/APU.hpp b/sources/APU/APU.hpp index 6c67a8f..bb903e3 100644 --- a/sources/APU/APU.hpp +++ b/sources/APU/APU.hpp @@ -125,7 +125,7 @@ namespace ComSquare::APU //! @param data The new value of the register. //! @throw InvalidAddress will be thrown if the address is more than $FF (the number of register). void write(uint24_t addr, uint8_t data) override; - bool update(); + void update(unsigned cycles); }; } diff --git a/sources/CPU/CPU.cpp b/sources/CPU/CPU.cpp index b0ed691..e40669f 100644 --- a/sources/CPU/CPU.cpp +++ b/sources/CPU/CPU.cpp @@ -5,6 +5,7 @@ #include "CPU.hpp" #include +#include #include "../Exceptions/NotImplementedException.hpp" #include "../Exceptions/InvalidAddress.hpp" #include "../Exceptions/InvalidOpcode.hpp" @@ -184,9 +185,9 @@ namespace ComSquare::CPU } } - int CPU::update() + unsigned CPU::update() { - int cycles = 0; + unsigned cycles = 0; for (int i = 0; i < 0xFF; i++) cycles += this->executeInstruction(); @@ -198,26 +199,27 @@ namespace ComSquare::CPU uint8_t opcode = this->_bus->read(this->_registers.pc); switch (opcode) { - case 0x0: - return this->BRK(); - case 0x61: - case 0x63: - case 0x65: - case 0x67: - case 0x69: - case 0x6D: - case 0x6F: - case 0x71: - case 0x72: - case 0x73: - case 0x75: - case 0x77: - case 0x79: - case 0x7D: - case 0x7F: - return this->ADC(); + case Instructions::BRK: return this->BRK(); + + 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()); + default: - throw InvalidOpcode("CPU", opcode); + return 0; + //throw InvalidOpcode("CPU", opcode); } } @@ -225,27 +227,161 @@ namespace ComSquare::CPU /// Addressing modes //////////////////////////////////////////////////////////////////// - uint24_t CPU::_GetImmediateAddr() + uint24_t CPU::_getImmediateAddr() { return this->_registers.pac++; } - uint24_t CPU::_GetDirectAddr() + uint24_t CPU::_getDirectAddr() { uint8_t addr = this->_bus->read(this->_registers.pac++); return this->_registers.d + addr; } - uint24_t CPU::_GetAbsoluteAddr() + uint24_t CPU::_getAbsoluteAddr() { uint24_t addr = this->_registers.dbr << 16u; - addr += this->_bus->read(this->_registers.pac++) << 8u; addr += this->_bus->read(this->_registers.pac++); + addr += this->_bus->read(this->_registers.pac++) << 8u; return addr; } - uint24_t CPU::_GetAbsoluteLongAddr() + uint24_t CPU::_getAbsoluteLongAddr() { - return 0; + uint24_t addr = this->_bus->read(this->_registers.pac++); + addr += this->_bus->read(this->_registers.pac++) << 8u; + addr += this->_bus->read(this->_registers.pac++) << 16u; + return addr; + } + + uint24_t CPU::_getDirectIndirectIndexedYAddr() + { + 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; + return base + this->_registers.y; + } + + uint24_t CPU::_getDirectIndirectIndexedYLongAddr() + { + 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->_bus->read(dp + 2) << 16u; + return base; + } + + uint24_t CPU::_getDirectIndirectIndexedXAddr() + { + uint16_t dp = this->_bus->read(this->_registers.pac++) + this->_registers.d; + dp += this->_registers.x; + uint24_t base = this->_bus->read(dp); + base += this->_bus->read(dp + 1) << 8u; + base += this->_registers.dbr << 16u; + return base; + } + + uint24_t CPU::_getDirectIndexedByXAddr() + { + uint16_t dp = this->_bus->read(this->_registers.pac++) + this->_registers.d; + dp += this->_registers.x; + return dp; + } + + uint24_t CPU::_getDirectIndexedByYAddr() + { + uint16_t dp = this->_bus->read(this->_registers.pac++) + this->_registers.d; + dp += this->_registers.y; + return dp; + } + + uint24_t CPU::_getAbsoluteIndexedByXAddr() + { + 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); + return effective + this->_registers.x; + } + + uint24_t CPU::_getAbsoluteIndexedByYAddr() + { + 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); + return effective + this->_registers.y; + } + + uint24_t CPU::_getAbsoluteIndexedByXLongAddr() + { + uint24_t lng = this->_bus->read(this->_registers.pac++); + lng += this->_bus->read(this->_registers.pac++) << 8u; + lng += this->_bus->read(this->_registers.pac++) << 16u; + return lng + this->_registers.x; + } + + uint24_t CPU::_getProgramCounterRelativeAddr() + { + uint24_t pc = this->_registers.pac; + int8_t mod = this->_bus->read(this->_registers.pac++); + return pc + mod; + } + + uint24_t CPU::_getProgramCounterRelativeLongAddr() + { + uint24_t pc = this->_registers.pac; + uint8_t val1 = this->_bus->read(this->_registers.pac++); + uint8_t val2 = this->_bus->read(this->_registers.pac++); + int16_t mod = val2 > 0x7F ? (static_cast(val2) * 256 - val1) : (val1 | val2 << 8u); + return pc + mod; + } + + uint24_t CPU::_getAbsoluteIndirectAddr() + { + uint16_t abs = this->_bus->read(this->_registers.pac++); + abs += this->_bus->read(this->_registers.pac++) << 8u; + uint24_t effective = this->_bus->read(abs); + effective += this->_bus->read(abs + 1) << 8u; + return effective; + } + + uint24_t CPU::_getAbsoluteIndexedIndirectAddr() + { + uint24_t abs = this->_bus->read(this->_registers.pac++); + abs += this->_bus->read(this->_registers.pac++) << 8u; + abs += this->_registers.x; + uint24_t effective = this->_bus->read(abs); + effective += this->_bus->read(abs + 1) << 8u; + return effective; + } + + uint24_t CPU::_getDirectIndirectAddr() + { + 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; + effective += this->_registers.dbr << 16u; + return effective; + } + + uint24_t CPU::_getDirectIndirectLongAddr() + { + 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; + effective += this->_bus->read(++dp) << 16u; + return effective; + } + + uint24_t CPU::_getStackRelativeAddr() + { + return this->_bus->read(this->_registers.pac++) + this->_registers.s; + } + + uint24_t CPU::_getStackRelativeIndirectIndexedYAddr() + { + uint24_t base = this->_bus->read(this->_registers.pac++) + this->_registers.s; + base += this->_registers.dbr << 16u; + return base + this->_registers.y; } } \ No newline at end of file diff --git a/sources/CPU/CPU.hpp b/sources/CPU/CPU.hpp index 13977a6..7cd63b2 100644 --- a/sources/CPU/CPU.hpp +++ b/sources/CPU/CPU.hpp @@ -180,6 +180,30 @@ namespace ComSquare::CPU uint8_t joy4h; }; + //! @brief All the instructions opcode of the main CPI. + //! @info The name of the instruction followed by their parameters (after an underscore) if any. + //! @info Addr mode with an i at the end means indirect. + //! @info Addr mode with an l at the end means long. + enum Instructions + { + BRK = 0x00, + ADC_DPXi = 0x61, + ADC_SR = 0x63, + ADC_DP = 0x65, + ADC_DPil = 0x67, + ADC_IM = 0x69, + ADC_ABS = 0x6D, + ADC_ABSl = 0x6F, + ADC_DPYi = 0x71, + ADC_DPi = 0x72, + ADC_SRYi = 0x73, + ADC_DPX = 0x75, + ADC_DPYil = 0x77, + ADC_ABSY = 0x79, + ADC_ABSX = 0x7D, + ADC_ABSXl = 0x7F + }; + //! @brief The main CPU class CPU : public CommonInstructions, public Memory::IMemory { private: @@ -195,28 +219,60 @@ namespace ComSquare::CPU Cartridge::Header &_cartridgeHeader; //! @brief Immediate address mode is specified with a value. (This functions returns the 24bit space address of the value). - uint24_t _GetImmediateAddr(); + 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). - uint24_t _GetDirectAddr(); + uint24_t _getDirectAddr(); //! @brief The effective address is formed by DBR:<16-bit exp>. (This functions returns the 24bit space address of the value). - uint24_t _GetAbsoluteAddr(); + uint24_t _getAbsoluteAddr(); //! @brief The effective address is the expression. (This functions returns the 24bit space address of the value). - uint24_t _GetAbsoluteLongAddr(); + uint24_t _getAbsoluteLongAddr(); + //! @brief The address is DBR:$(read($($Value + D)) + Y). (This functions returns the 24bit space address of the value). + uint24_t _getDirectIndirectIndexedYAddr(); + //! @brief This mode is like the previous addressing mode, but the difference is that rather than pulling 2 bytes from the DP address, it pulls 3 bytes to form the effective address. + uint24_t _getDirectIndirectIndexedYLongAddr(); + //! @brief The direct page address is calculated and added with x. 2 bytes from the dp address combined with DBR will form the effective address. + uint24_t _getDirectIndirectIndexedXAddr(); + //! @brief The DP address is added to X to form the effective address. The effective address is always in bank 0. + uint24_t _getDirectIndexedByXAddr(); + //! @brief The DP address is added to Y to form the effective address. The effective address is always in bank 0. + uint24_t _getDirectIndexedByYAddr(); + //! @brief The absolute expression is added with X and combined with DBR to form the effective address. + uint24_t _getAbsoluteIndexedByXAddr(); + //! @brief The absolute expression is added with Y and combined with DBR to form the effective address. + uint24_t _getAbsoluteIndexedByYAddr(); + //! @brief The effective address is formed by adding the with X. + uint24_t _getAbsoluteIndexedByXLongAddr(); + //! @brief The <8-bit signed exp> is added to PC (program counter) to form the new location. + uint24_t _getProgramCounterRelativeAddr(); + //! @brief The <16-bit signed exp> is added to PC (program counter) to form the new location. + uint24_t _getProgramCounterRelativeLongAddr(); + //! @brief 2 bytes are pulled from the to form the effective address. + uint24_t _getAbsoluteIndirectAddr(); + //! @brief The is added with X, then 2 bytes are pulled from that address to form the new location. + uint24_t _getAbsoluteIndexedIndirectAddr(); + //! @brief 2 bytes are pulled from the direct page address to form the 16-bit address. It is combined with DBR to form a 24-bit effective address. + uint24_t _getDirectIndirectAddr(); + //! @brief 3 bytes are pulled from the direct page address to form an effective address. + uint24_t _getDirectIndirectLongAddr(); + //! @brief The stack register is added to the <8-bit exp> to form the effective address. + uint24_t _getStackRelativeAddr(); + //! @brief The <8-bit exp> is added to S and combined with DBR to form the base address. Y is added to the base address to form the effective address. + uint24_t _getStackRelativeIndirectIndexedYAddr(); //! @brief Execute a single instruction. //! @return The number of CPU cycles that the instruction took. int executeInstruction(); - //! @brief Break instruction (0x00) - Causes a software break. The PC is loaded from a vector table. + //! @brief Break instruction - Causes a software break. The PC is loaded from a vector table. int BRK(); - //! @brief Add with carry (0x61, 0x63, 0x65, 0x67, 0x69, 0x6D, 0x6F, 0x71, 0x72, 0x73, 0x75, 0x77, 0x79, 0x7D, 0x7F) - Adds operand to the Accumulator; adds an additional 1 if carry is set. - int ADC(); + //! @brief Add with carry - Adds operand to the Accumulator; adds an additional 1 if carry is set. + int ADC(uint24_t valueAddr); public: explicit CPU(std::shared_ptr bus, Cartridge::Header &cartridgeHeader); //! @brief This function continue to execute the Cartridge code. //! @return The number of CPU cycles that elapsed - int update(); + unsigned update(); //! @brief Read from the internal CPU register. //! @param addr The address to read from. The address 0x0 should refer to the first byte of the register. //! @throw InvalidAddress will be thrown if the address is more than $1F (the number of register). diff --git a/sources/CPU/Instructions/MathematicalOperations.cpp b/sources/CPU/Instructions/MathematicalOperations.cpp index fb53ff2..e1b205c 100644 --- a/sources/CPU/Instructions/MathematicalOperations.cpp +++ b/sources/CPU/Instructions/MathematicalOperations.cpp @@ -6,8 +6,10 @@ namespace ComSquare::CPU { - int CPU::ADC() + int CPU::ADC(uint24_t valueAddr) { // this->_registers.a += + (void)valueAddr; + return (0); } } \ No newline at end of file diff --git a/sources/Exceptions/InvalidOpcode.hpp b/sources/Exceptions/InvalidOpcode.hpp index 6b02c29..00447c4 100644 --- a/sources/Exceptions/InvalidOpcode.hpp +++ b/sources/Exceptions/InvalidOpcode.hpp @@ -7,19 +7,19 @@ #include #include -#include +#include namespace ComSquare { //! @brief Exception thrown when someone tries to load an invalid rom. - class InvalidOpcode : std::exception { + class InvalidOpcode : public std::exception { private: std::string _msg; public: explicit InvalidOpcode(const std::string &pu, unsigned opcode) { std::stringstream stream; - stream << "The " + pu + ": 0x" << std::hex << opcode; + stream << "The " + pu + " got an invalid opcode: 0x" << std::hex << opcode; this->_msg = stream.str(); } const char *what() const noexcept override { return this->_msg.c_str(); } diff --git a/sources/Memory/IRectangleMemory.cpp b/sources/Memory/IRectangleMemory.cpp index 2ecb1b3..df5e7ef 100644 --- a/sources/Memory/IRectangleMemory.cpp +++ b/sources/Memory/IRectangleMemory.cpp @@ -2,6 +2,7 @@ // Created by anonymus-raccoon on 1/29/20. // +#include #include "IRectangleMemory.hpp" #include "../Exceptions/InvalidAddress.hpp" @@ -14,9 +15,9 @@ namespace ComSquare::Memory unsigned bankCount = bank - this->_startBank; unsigned pageCount = this->_endPage - this->_startPage; - if (bank < this->_startBank || bank >= this->_endBank) + if (bank < this->_startBank || bank > this->_endBank) throw InvalidAddress("Rectangle memory read Invalid Bank", addr); - if (page < this->_startPage || page >= this->_endPage) + if (page < this->_startPage || page > this->_endPage) throw InvalidAddress("Rectangle memory read Invalid Page", addr); page -= this->_startPage; page += pageCount * bankCount; diff --git a/sources/Memory/MemoryBus.cpp b/sources/Memory/MemoryBus.cpp index ba26e3d..bb9229f 100644 --- a/sources/Memory/MemoryBus.cpp +++ b/sources/Memory/MemoryBus.cpp @@ -46,12 +46,12 @@ namespace ComSquare::Memory handler->write(addr - handler->getStart(), data); } - void MemoryBus::_mirrorComponents(SNES &console, int i) + void MemoryBus::_mirrorComponents(SNES &console, unsigned i) { - this->_memoryAccessors.emplace_back(new Memory::MemoryShadow(console.wram, i, i + 0x1FFF)); - this->_memoryAccessors.emplace_back(new Memory::MemoryShadow(console.ppu, i + 0x2100, i + 0x213F)); - this->_memoryAccessors.emplace_back(new Memory::MemoryShadow(console.apu, i + 0x2140, i + 0x2143)); - this->_memoryAccessors.emplace_back(new Memory::MemoryShadow(console.cpu, i + 0x4200, i + 0x421F)); + this->_memoryAccessors.emplace_back(new Memory::RectangleShadow(console.wram, i, i, 0x0000, 0x1FFF)); + this->_memoryAccessors.emplace_back(new Memory::MemoryShadow(console.ppu, (i << 16u) + 0x2100, (i << 16u) + 0x213F)); + this->_memoryAccessors.emplace_back(new Memory::MemoryShadow(console.apu, (i << 16u) + 0x2140, (i << 16u) + 0x2143)); + this->_memoryAccessors.emplace_back(new Memory::MemoryShadow(console.cpu, (i << 16u) + 0x4200, (i << 16u) + 0x421F)); } void MemoryBus::mapComponents(SNES &console) @@ -73,10 +73,10 @@ namespace ComSquare::Memory // TODO implement Joys. // Mirror to the quarter 1. - for (uint24_t i = 0; i < 0x400000; i += 0x010000) + for (uint8_t i = 0x00; i < 0x40; i += 0x01) this->_mirrorComponents(console, i); // Mirror to the quarter 3. - for (uint24_t i = 0x800000; i < 0xC00000; i += 0x10000) + for (uint8_t i = 0x80; i < 0xC0; i += 0x01) this->_mirrorComponents(console, i); if (console.cartridge->header.mappingMode & Cartridge::LoRom) { diff --git a/sources/Memory/MemoryBus.hpp b/sources/Memory/MemoryBus.hpp index e2af811..b7689eb 100644 --- a/sources/Memory/MemoryBus.hpp +++ b/sources/Memory/MemoryBus.hpp @@ -33,7 +33,7 @@ namespace ComSquare //! @brief WRam, CPU, PPU & APU registers are mirrored to all banks of Q1 & Q3. This function is used for the mirroring. //! @param console All the components. //! @param i Base address for the mirrors. - inline void _mirrorComponents(SNES &console, int i); + inline void _mirrorComponents(SNES &console, unsigned i); public: //! @brief Read data at a global address. diff --git a/sources/Memory/RectangleShadow.cpp b/sources/Memory/RectangleShadow.cpp index 2da6c26..f336848 100644 --- a/sources/Memory/RectangleShadow.cpp +++ b/sources/Memory/RectangleShadow.cpp @@ -5,6 +5,7 @@ #include "RectangleShadow.hpp" #include +#include namespace ComSquare::Memory { diff --git a/sources/PPU/PPU.cpp b/sources/PPU/PPU.cpp index 2cf58d3..4927618 100644 --- a/sources/PPU/PPU.cpp +++ b/sources/PPU/PPU.cpp @@ -66,7 +66,7 @@ namespace ComSquare::PPU } } - void PPU::update(int cycles) + void PPU::update(unsigned cycles) { (void)cycles; } diff --git a/sources/PPU/PPU.hpp b/sources/PPU/PPU.hpp index f6db2f5..66ba86c 100644 --- a/sources/PPU/PPU.hpp +++ b/sources/PPU/PPU.hpp @@ -425,7 +425,7 @@ namespace ComSquare::PPU void write(uint24_t addr, uint8_t data) override; //! @brief Update the PPU of n cycles. //! @param The number of cycles to update. - void update(int cycles); + void update(unsigned cycles); }; } #endif //COMSQUARE_PPU_HPP diff --git a/tests/CPU/testAddressingMode.cpp b/tests/CPU/testAddressingMode.cpp index 250359a..a9c6326 100644 --- a/tests/CPU/testAddressingMode.cpp +++ b/tests/CPU/testAddressingMode.cpp @@ -4,6 +4,7 @@ #include #include +#include #include "../tests.hpp" #include "../../sources/SNES.hpp" using namespace ComSquare; @@ -19,7 +20,7 @@ Test(AddrMode, Immediate) { auto pair = Init(); pair.second.cpu->_registers.pac = 0x000015; - cr_assert_eq(pair.second.cpu->_GetImmediateAddr(), 0x000015, "Got %i, Expected 0x000015"); + cr_assert_eq(pair.second.cpu->_getImmediateAddr(), 0x000015, "Got %x, Expected 0x000015"); cr_assert_eq(pair.second.cpu->_registers.pac, 0x000016); } @@ -27,16 +28,261 @@ Test(AddrMode, ImmediateBankChange) { auto pair = Init(); pair.second.cpu->_registers.pac = 0x00FFFF; - cr_assert_eq(pair.second.cpu->_GetImmediateAddr(), 0x00FFFF); + cr_assert_eq(pair.second.cpu->_getImmediateAddr(), 0x00FFFF); cr_assert_eq(pair.second.cpu->_registers.pac, 0x010000); } -//Test(AddrMode, Direct) -//{ -// auto pair = Init(); -// pair.second.cartridge->_data[0] = 0x15; -// pair.second.cpu->_registers.pac = 0x808000; -// pair.second.cpu->_registers.d = 0x1000; -// cr_assert_eq(pair.second.cpu->_GetDirectAddr(), 0x1015, "Returned address was %i but was expecting 0x1015."); -// cr_assert_eq(pair.second.cpu->_registers.pac, 0x808001); -//} \ No newline at end of file +Test(AddrMode, Direct) +{ + auto pair = Init(); + pair.second.cartridge->_data[0] = 0x15; + pair.second.cpu->_registers.pac = 0x808000; + pair.second.cpu->_registers.d = 0x1000; + cr_assert_eq(pair.second.cpu->_getDirectAddr(), 0x1015, "Returned address was %x but was expecting 0x1015.", pair.second.cpu->_getDirectAddr()); + cr_assert_eq(pair.second.cpu->_registers.pac, 0x808001); +} + +Test(AddrMode, Absolute) +{ + auto pair = Init(); + pair.second.cartridge->_data[0] = 0x1C; + pair.second.cartridge->_data[1] = 0x90; + pair.second.cpu->_registers.pac = 0x808000; + pair.second.cpu->_registers.dbr = 0x88; + cr_assert_eq(pair.second.cpu->_getAbsoluteAddr(), 0x88901C, "Returned address was %x but was expecting 0x88901C.", pair.second.cpu->_getAbsoluteAddr()); + cr_assert_eq(pair.second.cpu->_registers.pac, 0x808002); +} + +Test(AddrMode, AbsoluteLong) +{ + auto pair = Init(); + pair.second.cartridge->_data[0] = 0x1C; + pair.second.cartridge->_data[1] = 0x90; + pair.second.cartridge->_data[2] = 0xFF; + pair.second.cpu->_registers.pac = 0x808000; + pair.second.cpu->_registers.dbr = 0x88; + cr_assert_eq(pair.second.cpu->_getAbsoluteLongAddr(), 0xFF901C, "Returned address was %x but was expecting 0xFF901C.", pair.second.cpu->_getAbsoluteLongAddr()); + cr_assert_eq(pair.second.cpu->_registers.pac, 0x808003); +} + +Test(AddrMode, DirectIndirectIndexed) +{ + auto pair = Init(); + pair.second.cartridge->_data[0] = 0x10; + pair.second.wram->_data[0x1010] = 0x30; + pair.second.wram->_data[0x1011] = 0x40; + pair.second.cpu->_registers.pac = 0x808000; + pair.second.cpu->_registers.dbr = 0x80; + pair.second.cpu->_registers.y = 0x0001; + pair.second.cpu->_registers.d = 0x1000; + cr_assert_eq(pair.second.cpu->_getDirectIndirectIndexedYAddr(), 0x804031, "Returned address was %x but was expecting 0x804031.", + pair.second.cpu->_getDirectIndirectIndexedYAddr()); + cr_assert_eq(pair.second.cpu->_registers.pac, 0x808001); +} + +Test(AddrMode, DirectIndirectIndexedLong) +{ + auto pair = Init(); + pair.second.cpu->_registers.pac = 0x808000; + pair.second.cpu->_registers.d = 0x1000; + pair.second.cartridge->_data[0] = 0x10; + pair.second.wram->_data[0x1010] = 0x30; + pair.second.wram->_data[0x1011] = 0x40; + pair.second.wram->_data[0x1012] = 0x23; + cr_assert_eq(pair.second.cpu->_getDirectIndirectIndexedYLongAddr(), 0x234030, "Returned address was %x but was expecting 0x234030.", + pair.second.cpu->_getDirectIndirectIndexedYLongAddr()); + cr_assert_eq(pair.second.cpu->_registers.pac, 0x808001); +} + +Test(AddrMode, DirectIndexedIndirect) +{ + auto pair = Init(); + pair.second.cartridge->_data[0] = 0x10; + pair.second.cpu->_registers.d = 0x1000; + pair.second.cpu->_registers.x = 0x0002; + pair.second.wram->_data[0x1012] = 0x30; + pair.second.wram->_data[0x1013] = 0x40; + pair.second.cpu->_registers.dbr = 0x80; + pair.second.cpu->_registers.pac = 0x808000; + cr_assert_eq(pair.second.cpu->_getDirectIndirectIndexedXAddr(), 0x804030, "Returned address was %x but was expecting 0x804030.", + pair.second.cpu->_getDirectIndirectIndexedXAddr()); + cr_assert_eq(pair.second.cpu->_registers.pac, 0x808001); +} + +Test(AddrMode, DirectIndexedByX) +{ + auto pair = Init(); + pair.second.cartridge->_data[0] = 0x10; + pair.second.cpu->_registers.d = 0x1000; + pair.second.cpu->_registers.x = 0x0002; + pair.second.cpu->_registers.pac = 0x808000; + cr_assert_eq(pair.second.cpu->_getDirectIndexedByXAddr(), 0x1012, "Returned address was %x but was expecting 0x1012.", pair.second.cpu->_getDirectIndexedByXAddr()); + cr_assert_eq(pair.second.cpu->_registers.pac, 0x808001); +} + +Test(AddrMode, DirectIndexedByY) +{ + auto pair = Init(); + pair.second.cartridge->_data[0] = 0x10; + pair.second.cpu->_registers.d = 0x1000; + pair.second.cpu->_registers.y = 0x0002; + pair.second.cpu->_registers.pac = 0x808000; + cr_assert_eq(pair.second.cpu->_getDirectIndexedByYAddr(), 0x1012, "Returned address was %x but was expecting 0x1012.", pair.second.cpu->_getDirectIndexedByYAddr()); + cr_assert_eq(pair.second.cpu->_registers.pac, 0x808001); +} + +Test(AddrMode, AbsoluteIndexByX) +{ + auto pair = Init(); + pair.second.cpu->_registers.pac = 0x808000; + pair.second.cartridge->_data[0] = 0x10; + pair.second.cartridge->_data[1] = 0xAC; + pair.second.cpu->_registers.dbr = 0xEF; + pair.second.cpu->_registers.x = 0x0005; + cr_assert_eq(pair.second.cpu->_getAbsoluteIndexedByXAddr(), 0xEFAC15, "Returned address was %x but was expecting 0xEFAC15.", pair.second.cpu->_getAbsoluteIndexedByXAddr()); + cr_assert_eq(pair.second.cpu->_registers.pac, 0x808002); +} + +Test(AddrMode, AbsoluteIndexByY) +{ + auto pair = Init(); + pair.second.cpu->_registers.pac = 0x808000; + pair.second.cartridge->_data[0] = 0x10; + pair.second.cartridge->_data[1] = 0xAC; + pair.second.cpu->_registers.dbr = 0xEF; + pair.second.cpu->_registers.y = 0x0005; + cr_assert_eq(pair.second.cpu->_getAbsoluteIndexedByYAddr(), 0xEFAC15, "Returned address was %x but was expecting 0xEFAC15.", pair.second.cpu->_getAbsoluteIndexedByYAddr()); + cr_assert_eq(pair.second.cpu->_registers.pac, 0x808002); +} + +Test(AddrMode, AbsoluteLongIndexByX) +{ + auto pair = Init(); + pair.second.cpu->_registers.pac = 0x808000; + pair.second.cartridge->_data[0] = 0x10; + pair.second.cartridge->_data[1] = 0xAC; + pair.second.cartridge->_data[2] = 0xEF; + pair.second.cpu->_registers.x = 0x0005; + cr_assert_eq(pair.second.cpu->_getAbsoluteIndexedByXLongAddr(), 0xEFAC15, "Returned address was %x but was expecting 0xEFAC15.", + pair.second.cpu->_getAbsoluteIndexedByXLongAddr()); + cr_assert_eq(pair.second.cpu->_registers.pac, 0x808003); +} + +Test(AddrMode, ProgramCounterRelativePositive) +{ + auto pair = Init(); + pair.second.cpu->_registers.pac = 0x808010; + pair.second.cartridge->_data[0x10] = 0x15; + cr_assert_eq(pair.second.cpu->_getProgramCounterRelativeAddr(), 0x808025, "Returned address was %x but was expecting 0x808025.", pair.second.cpu->_getProgramCounterRelativeAddr()); + cr_assert_eq(pair.second.cpu->_registers.pac, 0x808011); +} + +Test(AddrMode, ProgramCounterRelativeNegative) +{ + auto pair = Init(); + pair.second.cpu->_registers.pac = 0x808010; + pair.second.cartridge->_data[0x10] = -0x15; + cr_assert_eq(pair.second.cpu->_getProgramCounterRelativeAddr(), 0x807FFB, "Returned address was %x but was expecting 0x807FFB.", pair.second.cpu->_getProgramCounterRelativeAddr()); + cr_assert_eq(pair.second.cpu->_registers.pac, 0x808011); +} + +Test(AddrMode, ProgramCounterRelativeLongPositive) +{ + auto pair = Init(); + pair.second.cpu->_registers.pac = 0x808010; + pair.second.cartridge->_data[0x10] = 0x15; + pair.second.cartridge->_data[0x11] = 0x10; + auto addr = pair.second.cpu->_getProgramCounterRelativeLongAddr(); + cr_assert_eq(addr, 0x809025, "Returned address was %x but was expecting 0x809025.", addr); + cr_assert_eq(pair.second.cpu->_registers.pac, 0x808012); +} + +Test(AddrMode, ProgramCounterRelativeLongNegative) +{ + auto pair = Init(); + pair.second.cpu->_registers.pac = 0x808010; + pair.second.cartridge->_data[0x10] = 0x10; + pair.second.cartridge->_data[0x11] = -0x15; + auto addr = pair.second.cpu->_getProgramCounterRelativeLongAddr(); + cr_assert_eq(addr, 0x806B00, "Returned address was %x but was expecting 0x806B00.", addr); + cr_assert_eq(pair.second.cpu->_registers.pac, 0x808012); +} + +Test(AddrMode, AbsoluteIndirect) +{ + auto pair = Init(); + pair.second.cpu->_registers.pac = 0x808000; + pair.second.cartridge->_data[0] = 0xAB; + pair.second.cartridge->_data[1] = 0x01; + pair.second.wram->_data[0x01AB] = 0xEF; + pair.second.wram->_data[0x01AC] = 0x01; + auto addr = pair.second.cpu->_getAbsoluteIndirectAddr(); + cr_assert_eq(addr, 0x01EF, "Returned address was %x but was expecting 0x01EF.", addr); + cr_assert_eq(pair.second.cpu->_registers.pac, 0x808002); +} + +Test(AddrMode, AbsoluteIndexedIndirect) +{ + auto pair = Init(); + pair.second.cpu->_registers.pac = 0x808000; + pair.second.cartridge->_data[0] = 0xAB; + pair.second.cartridge->_data[1] = 0x01; + pair.second.cpu->_registers.x = 2; + pair.second.wram->_data[0x01AD] = 0xEF; + pair.second.wram->_data[0x01AE] = 0x01; + auto addr = pair.second.cpu->_getAbsoluteIndexedIndirectAddr(); + cr_assert_eq(addr, 0x01EF, "Returned address was %x but was expecting 0x01EF.", addr); + cr_assert_eq(pair.second.cpu->_registers.pac, 0x808002); +} + +Test(AddrMode, DirectIndirect) +{ + auto pair = Init(); + pair.second.cpu->_registers.pac = 0x808000; + pair.second.cartridge->_data[0] = 0x01; + pair.second.cpu->_registers.d = 0x1010; + pair.second.wram->_data[0x1011] = 0xEF; + pair.second.wram->_data[0x1012] = 0x01; + pair.second.cpu->_registers.dbr = 0x88; + auto addr = pair.second.cpu->_getDirectIndirectAddr(); + cr_assert_eq(addr, 0x8801EF, "Returned address was %x but was expecting 0x8801EF.", addr); + cr_assert_eq(pair.second.cpu->_registers.pac, 0x808001); +} + +Test(AddrMode, DirectIndirectLong) +{ + auto pair = Init(); + pair.second.cpu->_registers.pac = 0x808000; + pair.second.cartridge->_data[0] = 0x06; + pair.second.cpu->_registers.d = 0x1010; + pair.second.wram->_data[0x1016] = 0xEF; + pair.second.wram->_data[0x1017] = 0x01; + pair.second.wram->_data[0x1018] = 0x88; + auto addr = pair.second.cpu->_getDirectIndirectLongAddr(); + cr_assert_eq(addr, 0x8801EF, "Returned address was %x but was expecting 0x8801EF.", addr); + cr_assert_eq(pair.second.cpu->_registers.pac, 0x808001); +} + +Test(AddrMode, StackRelative) +{ + auto pair = Init(); + pair.second.cpu->_registers.pac = 0x808000; + pair.second.cartridge->_data[0] = 0x06; + pair.second.cpu->_registers.s = 0x1010; + auto addr = pair.second.cpu->_getStackRelativeAddr(); + cr_assert_eq(addr, 0x1016, "Returned address was %x but was expecting 0x1016.", addr); + cr_assert_eq(pair.second.cpu->_registers.pac, 0x808001); +} + +Test(AddrMode, StackRelativeIndirectIndexed) +{ + auto pair = Init(); + pair.second.cpu->_registers.pac = 0x808000; + pair.second.cartridge->_data[0] = 0x06; + pair.second.cpu->_registers.s = 0x1010; + pair.second.cpu->_registers.y = 0x5; + pair.second.cpu->_registers.dbr = 0x88; + auto addr = pair.second.cpu->_getStackRelativeIndirectIndexedYAddr(); + cr_assert_eq(addr, 0x88101B, "Returned address was %x but was expecting 0x88101B.", addr); + cr_assert_eq(pair.second.cpu->_registers.pac, 0x808001); +} \ No newline at end of file diff --git a/tests/testMemoryBus.cpp b/tests/testMemoryBus.cpp index 80b8207..7db9b73 100644 --- a/tests/testMemoryBus.cpp +++ b/tests/testMemoryBus.cpp @@ -45,9 +45,30 @@ Test(BusAccessor, GetWramEnd) Test(BusAccessor, GetWramMirror) { auto pair = Init(); - std::shared_ptr accessor = nullptr; + std::shared_ptr accessor = nullptr; - accessor = std::static_pointer_cast(pair.first->getAccessor(0x2F11FF)); + accessor = std::static_pointer_cast(pair.first->getAccessor(0x2F11FF)); + cr_assert_neq(accessor, nullptr); + cr_assert_eq(accessor->_initial.get(), pair.second.wram.get()); +} + +Test(BusAccessor, GetWramMirror2) +{ + auto pair = Init(); + std::shared_ptr accessor = nullptr; + + accessor = std::static_pointer_cast(pair.first->getAccessor(0x100000)); + cr_assert_neq(accessor, nullptr); + cr_assert_eq(accessor->_initial.get(), pair.second.wram.get()); +} + +Test(BusAccessor, GetWramMirror3) +{ + auto pair = Init(); + std::shared_ptr accessor = nullptr; + + accessor = std::static_pointer_cast(pair.first->getAccessor(0x1010)); + cr_assert_neq(accessor, nullptr); cr_assert_eq(accessor->_initial.get(), pair.second.wram.get()); } @@ -123,6 +144,15 @@ Test(BusAccessor, GetAPUMirror) cr_assert_eq(accessor->_initial.get(), pair.second.apu.get()); } +Test(BusAccessor, GetAPUMirrorFirstHalf) +{ + auto pair = Init(); + std::shared_ptr accessor = nullptr; + + accessor = std::static_pointer_cast(pair.first->getAccessor(0x052143)); + cr_assert_eq(accessor->_initial.get(), pair.second.apu.get()); +} + Test(BusAccessor, GetCPUStart) { auto pair = Init(); @@ -337,6 +367,27 @@ Test(BusRead, ReadWRAM) cr_assert_eq(data, 123); } +Test(BusRead, ReadWRAM2) +{ + auto pair = Init(); + uint8_t data; + + pair.second.wram->_data[0x1010] = 123; + data = pair.first->read(0x7E1010); + cr_assert_eq(data, 123); +} + + +Test(BusRead, ReadWRAMMirror) +{ + auto pair = Init(); + uint8_t data; + + pair.second.wram->_data[0x1010] = 123; + data = pair.first->read(0x1010); + cr_assert_eq(data, 123); +} + //////////////////////////// // // // MemoryBus::write tests // diff --git a/tests/tests.cpp b/tests/tests.cpp index f6ff907..c9a3bd7 100644 --- a/tests/tests.cpp +++ b/tests/tests.cpp @@ -19,8 +19,8 @@ std::pair, SNES> Init() snes.cartridge->_size = 100; snes.cartridge->_data = new uint8_t[snes.cartridge->_size]; snes.cartridge->header.mappingMode = Cartridge::LoRom; - snes.sram->_size = 10; + snes.sram->_size = 100; snes.sram->_data = new uint8_t[snes.cartridge->_size]; - bus->mapComponents(snes); +// bus->mapComponents(snes); return std::make_pair(bus, snes); } \ No newline at end of file