diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index aefff04..7c8dd2a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -18,7 +18,7 @@ jobs: run: sudo apt-get update && sudo apt-get install --yes libfreetype6-dev libxrandr-dev libudev-dev libogg-dev libflac-dev libvorbis-dev libopenal-dev freeglut3-dev - name: Install Qt - uses: ouuan/install-qt-action@v2.3.1 + uses: jurplel/install-qt-action@v2 - name: Install the SFML. run: | git clone https://github.com/SFML/SFML -b 2.5.x /tmp/sfml diff --git a/.github/workflows/buildwin.yml b/.github/workflows/buildwin.yml index 25632da..73fe8ab 100644 --- a/.github/workflows/buildwin.yml +++ b/.github/workflows/buildwin.yml @@ -3,10 +3,10 @@ name: Build for windows on: push: branches: - - master + - CI-TEST pull_request: branches: - - master + - CI-TEST jobs: Building: diff --git a/.github/workflows/doc.yml b/.github/workflows/doc.yml index 9da660d..4da3ce2 100644 --- a/.github/workflows/doc.yml +++ b/.github/workflows/doc.yml @@ -15,16 +15,17 @@ jobs: run: sudo apt-get install --yes doxygen graphviz - name: Update the docs run: | - git clone -b gh-pages https://${GITHUB_REPO} docs rm -rf docs/* doxygen Doxyfile cd docs git config --global user.email "${GITHUB_ACTOR}@github.com"; git config --global user.name "${GITHUB_ACTOR}"; + git init git add -A; git commit -m "Deploying the doc"; - git remote set-url --push origin https://${GITHUB_ACTOR}:${GITHUB_TOKEN}@${GITHUB_REPO}; - git push origin gh-pages; + git remote add origin https://${GITHUB_ACTOR}:${GITHUB_TOKEN}@${GITHUB_REPO}; + git checkout -b Documentation + git push --force origin Documentation; env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_REPO: "github.com/AnonymusRaccoon/ComSquare" \ No newline at end of file diff --git a/.gitignore b/.gitignore index 568de19..5468f3d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ .idea/* -cmake-build-debug/* \ No newline at end of file +cmake-build-debug/* +ui/*.h \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index a0b1a63..28b1656 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -103,6 +103,8 @@ add_executable(unit_tests sources/PPU/Background.hpp sources/CPU/DMA/DMA.cpp sources/CPU/DMA/DMA.hpp + tests/CPU/testDMA.cpp + sources/Memory/IMemory.hpp sources/APU/DSP/Voice.cpp sources/APU/DSP/Echo.cpp sources/APU/DSP/Gauss.cpp @@ -115,12 +117,6 @@ add_executable(unit_tests target_link_libraries(unit_tests criterion -lgcov) target_compile_options(unit_tests PUBLIC -fprofile-arcs -ftest-coverage) -if ("${GITBUILD}" STREQUAL true) - include_directories(ComSquare build/include) - link_directories(ComSquare build/lib) - message("Git build is true") -endif () - set(CMAKE_AUTOMOC ON) set(CMAKE_AUTORCC ON) set(CMAKE_AUTOUIC ON) @@ -179,7 +175,7 @@ add_executable(ComSquare sources/Renderer/QtRenderer/QtSFML.hpp sources/Renderer/QtRenderer/QtWidgetSFML.cpp sources/Renderer/QtRenderer/QtWidgetSFML.hpp - ui/cpu.ui + ui/cpuView.ui ui/ramView.ui ui/cartridgeView.ui ui/apuView.ui @@ -229,6 +225,10 @@ add_executable(ComSquare sources/PPU/Background.hpp sources/CPU/DMA/DMA.cpp sources/CPU/DMA/DMA.hpp + ui/registersView.ui + sources/Debugger/RegisterViewer.cpp + sources/Debugger/RegisterViewer.hpp + sources/Memory/IMemory.hpp sources/APU/DSP/Voice.cpp sources/APU/DSP/Echo.cpp sources/APU/DSP/Gauss.cpp diff --git a/Doxyfile b/Doxyfile index fe9687f..962fcf8 100644 --- a/Doxyfile +++ b/Doxyfile @@ -2431,7 +2431,7 @@ DIRECTORY_GRAPH = YES # The default value is: png. # This tag requires that the tag HAVE_DOT is set to YES. -DOT_IMAGE_FORMAT = png +DOT_IMAGE_FORMAT = svg # If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to # enable generation of interactive SVG images that allow zooming and panning. diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 0000000..9a7531b --- /dev/null +++ b/codecov.yml @@ -0,0 +1,6 @@ +coverage: + status: + project: + default: + target: auto + threshold: 5% \ No newline at end of file diff --git a/sources/APU/APU.cpp b/sources/APU/APU.cpp index d4623e6..84d28bb 100644 --- a/sources/APU/APU.cpp +++ b/sources/APU/APU.cpp @@ -19,25 +19,26 @@ namespace ComSquare::APU this->reset(); } - bool APU::isDebugger() + bool APU::isDebugger() const { return false; } - std::string APU::getName() + std::string APU::getName() const { return "APU"; } - Component APU::getComponent() + Component APU::getComponent() const { return Apu; } - uint8_t APU::_internalRead(uint24_t addr) { + uint8_t APU::_internalRead(uint24_t addr) const + { switch (addr) { case 0x0000 ... 0x00EF: - return this->_map->Page0.read_internal(addr); + return this->_map->Page0.read(addr); case 0xF0: return this->_registers.unknown; case 0xF2: @@ -63,9 +64,9 @@ namespace ComSquare::APU case 0xFF: return this->_registers.counter2; case 0x0100 ... 0x01FF: - return this->_map->Page1.read_internal(addr - 0x0100); + return this->_map->Page1.read(addr - 0x0100); case 0x0200 ... 0xFFBF: - return this->_map->Memory.read_internal(addr - 0x200); + return this->_map->Memory.read(addr - 0x200); case 0xFFC0 ... 0xFFFF: return this->_map->IPL.read(addr - 0xFFC0); default: @@ -73,10 +74,11 @@ namespace ComSquare::APU } } - void APU::_internalWrite(uint24_t addr, uint8_t data) { + void APU::_internalWrite(uint24_t addr, uint8_t data) + { switch (addr) { case 0x0000 ... 0x00EF: - this->_map->Page0.write_internal(addr, data); + this->_map->Page0.write(addr, data); break; case 0xF0: this->_registers.unknown = data; @@ -118,10 +120,10 @@ namespace ComSquare::APU this->_registers.timer2 = data; break; case 0x0100 ... 0x01FF: - this->_map->Page1.write_internal(addr - 0x0100, data); + this->_map->Page1.write(addr - 0x0100, data); break; case 0x0200 ... 0xFFBF: - this->_map->Memory.write_internal(addr - 0x200, data); + this->_map->Memory.write(addr - 0x200, data); break; case 0xFFC0 ... 0xFFFF: this->_map->IPL.write(addr - 0xFFC0, data); @@ -131,7 +133,7 @@ namespace ComSquare::APU } } - uint8_t APU::read(uint24_t addr) + uint8_t APU::read(uint24_t addr) const { switch (addr) { case 0x00: @@ -167,6 +169,11 @@ namespace ComSquare::APU } } + uint24_t APU::getSize() const + { + return 0x3; + } + void APU::reset() { this->_registers.port0 = 0x00; diff --git a/sources/APU/APU.hpp b/sources/APU/APU.hpp index e96c647..780ef58 100644 --- a/sources/APU/APU.hpp +++ b/sources/APU/APU.hpp @@ -155,19 +155,14 @@ namespace ComSquare::APU //! @param addr The address to read from. The address 0x0000 should refer to the first byte of the register. //! @throw InvalidAddress will be thrown if the address is more than $FFFF (the number of register). //! @return Return the data. - uint8_t _internalRead(uint24_t addr); + uint8_t _internalRead(uint24_t addr) const; + //! @brief Write data to the APU ram. //! @param addr The address to write to. The address 0x0000 should refer to the first byte of register. //! @param data The new value of the register. //! @throw InvalidAddress will be thrown if the address is more than $FFFF (the number of register). void _internalWrite(uint24_t addr, uint8_t data); - //! @brief Get the name of this accessor (used for debug purpose) - std::string getName() override; - - //! @brief Get the component of this accessor (used for debug purpose) - Component getComponent() override; - //! @brief Current state of APU CPU StateMode _state = Running; @@ -378,16 +373,28 @@ namespace ComSquare::APU APU &operator=(const APU &) = default; ~APU() override = default; - //! @brief Read from the internal APU register. - //! @param addr The address to read from. The address 0x00 should refer to the first byte of the register. - //! @throw InvalidAddress will be thrown if the address is more than $0F (the number of register). - //! @return Return the value of the register. - uint8_t read(uint24_t addr) override; - //! @brief Write data to the internal APU register. - //! @param addr The address to write to. The address 0x00 should refer to the first byte of register. + //! @brief Read from the APU ram. + //! @param addr The address to read from. The address 0x0000 should refer to the first byte of the register. + //! @throw InvalidAddress will be thrown if the address is more than $FFFF (the number of register). + //! @return Return the data. + uint8_t read(uint24_t addr) const override; + + //! @brief Write data to the APU ram. + //! @param addr The address to write to. The address 0x0000 should refer to the first byte of register. //! @param data The new value of the register. - //! @throw InvalidAddress will be thrown if the address is more than $0F (the number of register). + //! @throw InvalidAddress will be thrown if the address is more than $FFFF (the number of register). void write(uint24_t addr, uint8_t data) override; + + //! @brief Get the name of this accessor (used for debug purpose) + std::string getName() const override; + + //! @brief Get the component of this accessor (used for debug purpose) + Component getComponent() const override; + + //! @brief Get the size of the data. This size can be lower than the mapped data. + //! @return The number of bytes inside this memory. + uint24_t getSize() const override; + //! @brief This function execute the instructions received until the maximum number of cycles is reached. //! @return The number of cycles that elapsed. virtual void update(unsigned cycles); @@ -396,7 +403,7 @@ namespace ComSquare::APU void reset(); //! @brief Return true if the CPU is overloaded with debugging features. - virtual bool isDebugger(); + virtual bool isDebugger() const; }; } diff --git a/sources/APU/DSP/DSP.cpp b/sources/APU/DSP/DSP.cpp index 2ca79b9..710d343 100644 --- a/sources/APU/DSP/DSP.cpp +++ b/sources/APU/DSP/DSP.cpp @@ -15,7 +15,7 @@ namespace ComSquare::APU::DSP this->_state.bufferEnd = buffer + size; } - uint8_t DSP::read(uint24_t addr) + uint8_t DSP::read(uint24_t addr) const { switch (addr) { case 0x00: @@ -568,15 +568,14 @@ namespace ComSquare::APU::DSP throw InvalidAddress("DSP Registers write", addr); } } - uint8_t DSP::_readRAM(uint24_t addr) { switch (addr) { case 0x0000 ... 0x00EF: - return this->_map.lock()->Page0.read_internal(addr); + return this->_map.lock()->Page0.read(addr); case 0x0100 ... 0x01FF: - return this->_map.lock()->Page1.read_internal(addr - 0x0100); + return this->_map.lock()->Page1.read(addr - 0x0100); case 0x0200 ... 0xFFBF: - return this->_map.lock()->Memory.read_internal(addr - 0x200); + return this->_map.lock()->Memory.read(addr - 0x200); case 0xFFC0 ... 0xFFFF: return this->_map.lock()->IPL.read(addr - 0xFFC0); default: @@ -587,13 +586,13 @@ namespace ComSquare::APU::DSP void DSP::_writeRAM(uint24_t addr, uint8_t data) { switch (addr) { case 0x0000 ... 0x00EF: - this->_map.lock()->Page0.write_internal(addr, data); + this->_map.lock()->Page0.write(addr, data); break; case 0x0100 ... 0x01FF: - this->_map.lock()->Page1.write_internal(addr - 0x0100, data); + this->_map.lock()->Page1.write(addr - 0x0100, data); break; case 0x0200 ... 0xFFBF: - this->_map.lock()->Memory.write_internal(addr - 0x200, data); + this->_map.lock()->Memory.write(addr - 0x200, data); break; case 0xFFC0 ... 0xFFFF: this->_map.lock()->IPL.write(addr - 0xFFC0, data); @@ -760,33 +759,37 @@ namespace ComSquare::APU::DSP } this->_state.voice = (this->_state.voice + 1) % 32; } + uint24_t DSP::getSize() const + { + return 0x7F; + } - const std::array &DSP::getVoices() + const std::array &DSP::getVoices() const { return this->_voices; } - const Master &DSP::getMaster() + const Master &DSP::getMaster() const { return this->_master; } - const Echo &DSP::getEcho() + const Echo &DSP::getEcho() const { return this->_echo; } - const Noise &DSP::getNoise() + const Noise &DSP::getNoise() const { return this->_noise; } - const BRR &DSP::getBrr() + const BRR &DSP::getBrr() const { return this->_brr; } - const Latch &DSP::getLatch() + const Latch &DSP::getLatch() const { return this->_latch; } diff --git a/sources/APU/DSP/DSP.hpp b/sources/APU/DSP/DSP.hpp index a8fb57e..67cadc0 100644 --- a/sources/APU/DSP/DSP.hpp +++ b/sources/APU/DSP/DSP.hpp @@ -420,27 +420,35 @@ namespace ComSquare::APU::DSP ~DSP() = default; //! @brief Return all 8 voices from DSP - const std::array &getVoices(); - const Master &getMaster(); - const Echo &getEcho(); - const Noise &getNoise(); - const BRR &getBrr(); - const Latch &getLatch(); + const std::array &getVoices() const; + const Master &getMaster() const; + const Echo &getEcho() const; + const Noise &getNoise() const; + const BRR &getBrr() const; + const Latch &getLatch() const; //! @brief Read from the internal DSP 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 $7F (the number of register). //! @return Return the value of the register. - uint8_t read(uint24_t addr); + uint8_t read(uint24_t addr) const; //! @brief Write data to the internal DSP register. //! @param addr The address to write to. The address 0x0 should refer to the first byte of register. //! @param data The new value of the register. //! @throw InvalidAddress will be thrown if the address is more than $7F (the number of register). void write(uint24_t addr, uint8_t data); + //! @brief Get the name of this accessor (used for debug purpose) + std::string getName() const; //! @brief Execute current voice transformation void update(); + //! @brief Get the component of this accessor (used for debug purpose) + Component getComponent() const; + + //! @brief Get the size of the data. This size can be lower than the mapped data. + //! @return The number of bytes inside this memory. + uint24_t getSize() const; //! @brief Return the number of samples written int32_t getSamplesCount() const; }; diff --git a/sources/APU/IPL/IPL.cpp b/sources/APU/IPL/IPL.cpp index 4bbf989..0b90e6a 100644 --- a/sources/APU/IPL/IPL.cpp +++ b/sources/APU/IPL/IPL.cpp @@ -17,7 +17,7 @@ namespace ComSquare::APU::IPL IPL::~IPL() { } - uint8_t IPL::read(uint24_t addr) + uint8_t IPL::read(uint24_t addr) const { if (addr >= this->_size) throw InvalidAddress("IPL read", addr); @@ -31,12 +31,17 @@ namespace ComSquare::APU::IPL this->_data[addr] = data; } - std::string IPL::getName() + uint24_t IPL::getSize() const + { + return this->_size; + } + + std::string IPL::getName() const { return this->_iplName; } - Component IPL::getComponent() + Component IPL::getComponent() const { return this->_iplType; } diff --git a/sources/APU/IPL/IPL.hpp b/sources/APU/IPL/IPL.hpp index 38c3437..0c0c5a3 100644 --- a/sources/APU/IPL/IPL.hpp +++ b/sources/APU/IPL/IPL.hpp @@ -5,7 +5,7 @@ #ifndef COMSQUARE_IPL_HPP #define COMSQUARE_IPL_HPP -#include "../../Memory/ARectangleMemory.hpp" +#include "../../Memory/AMemory.hpp" namespace ComSquare::APU::IPL { @@ -45,7 +45,7 @@ namespace ComSquare::APU::IPL //! @param addr The global 24 bits address. This method is responsible of mapping to the component's read. //! @throw InvalidAddress if the address is not mapped to the component. //! @return Return the data at the address given as parameter. - uint8_t read(uint24_t addr) override; + uint8_t read(uint24_t addr) const override; //! @brief Write data to this component using the same method as the basic IMemory. //! @param addr The global 24 bits address. This method is responsible of mapping to the component's write. @@ -53,11 +53,15 @@ namespace ComSquare::APU::IPL //! @throw InvalidAddress if the address is not mapped to the component. void write(uint24_t addr, uint8_t data) override; + //! @brief Get the size of the data. This size can be lower than the mapped data. + //! @return The number of bytes inside this memory. + uint24_t getSize() const override; + //! @brief Get the name of this accessor (used for debug purpose) - std::string getName() override; + std::string getName() const override; //! @brief Get the component of this accessor (used for debug purpose) - Component getComponent() override; + Component getComponent() const override; }; } diff --git a/sources/CPU/CPU.cpp b/sources/CPU/CPU.cpp index a6dec27..7a45b5a 100644 --- a/sources/CPU/CPU.cpp +++ b/sources/CPU/CPU.cpp @@ -12,12 +12,15 @@ namespace ComSquare::CPU { CPU::CPU(std::shared_ptr bus, Cartridge::Header &cartridgeHeader) - : _bus(std::move(bus)), _cartridgeHeader(cartridgeHeader) + : _bus(std::move(bus)), + _cartridgeHeader(cartridgeHeader) { this->RESB(); + for (DMA &channel : this->_dmaChannels) + channel.setBus(_bus); } - bool CPU::isDebugger() + bool CPU::isDebugger() const { return false; } @@ -28,8 +31,10 @@ namespace ComSquare::CPU } //! @bref The CPU's internal registers starts at $4200 and finish at $421F. - uint8_t CPU::read(uint24_t addr) + uint8_t CPU::read(uint24_t addr) const { + uint8_t tmp = 0; + switch (addr) { case 0x0: return this->_internalRegisters.nmitimen; @@ -54,7 +59,9 @@ namespace ComSquare::CPU case 0xA: return this->_internalRegisters.vtimeh; case 0xB: - return this->_internalRegisters.dmaEnableRegister; + for (int i = 0; i < 8; i++) + tmp |= this->_dmaChannels[i].enabled << i; + return tmp; case 0xC: return this->_internalRegisters.hdmaen; case 0xD: @@ -94,7 +101,7 @@ namespace ComSquare::CPU case 0x100 ... 0x180: return this->_dmaChannels[(addr - 0x100) >> 8u].read(addr & 0xF); default: - throw InvalidAddress("CPU Internal Registers read", addr + this->getStart()); + throw InvalidAddress("CPU Internal Registers read", addr + this->_start); } } @@ -135,7 +142,8 @@ namespace ComSquare::CPU this->_internalRegisters.vtimeh = data; break; case 0xB: - this->_internalRegisters.dmaEnableRegister = data; + for (int i = 0; i < 8; i++) + this->_dmaChannels[i].enabled = data & (0b1 << i); break; case 0xC: this->_internalRegisters.hdmaen = data; @@ -195,10 +203,15 @@ namespace ComSquare::CPU this->_dmaChannels[(addr - 0x100) >> 8u].write(addr & 0xF, data); break; default: - throw InvalidAddress("CPU Internal Registers write", addr + this->getStart()); + throw InvalidAddress("CPU Internal Registers write", addr + this->_start); } } + uint24_t CPU::getSize() const + { + return 0x180; + } + uint8_t CPU::readPC() { uint8_t ret = this->_bus->read(this->_registers.pac); @@ -211,10 +224,10 @@ namespace ComSquare::CPU unsigned cycles = 0; const unsigned maxCycles = 0x0C; - for (int i = 0; i < 8; i++) { - if (!(this->_internalRegisters.dmaEnableRegister & (0xF << i))) + for (DMA &channel : this->_dmaChannels) { + if (!channel.enabled) continue; - cycles += this->_dmaChannels[i].run(maxCycles - cycles); + cycles += channel.run(maxCycles - cycles); } for (unsigned i = 0; i < maxCycles; i++) { if (this->_isStopped) { @@ -341,12 +354,12 @@ namespace ComSquare::CPU return value; } - std::string CPU::getName() + std::string CPU::getName() const { return "CPU"; } - Component CPU::getComponent() + Component CPU::getComponent() const { return Cpu; } diff --git a/sources/CPU/CPU.hpp b/sources/CPU/CPU.hpp index f4af358..7872bbf 100644 --- a/sources/CPU/CPU.hpp +++ b/sources/CPU/CPU.hpp @@ -131,9 +131,6 @@ namespace ComSquare::CPU //! @brief IRQ Timer Registers (Vertical - High) uint8_t vtimeh; - //! @brief DMA Enable Register - uint8_t dmaEnableRegister; - //! @brief HDMA Enable Register uint8_t hdmaen; @@ -202,6 +199,7 @@ namespace ComSquare::CPU //! @brief The cartridge header (stored for interrupt vectors.. Cartridge::Header &_cartridgeHeader; + //! @brief DMA channels witch are mapped to the bus. std::array _dmaChannels; //! @brief True if an addressing mode with an iterator (x, y) has crossed the page. (Used because crossing the page boundary take one more cycle to run certain instructions). @@ -481,7 +479,7 @@ namespace ComSquare::CPU {&CPU::ORA, 3, "ora", AddressingMode::DirectPage, 2}, // 05 {&CPU::ASL, 5, "asl", AddressingMode::DirectPage, 2}, // 06 {&CPU::ORA, 6, "ora", AddressingMode::DirectPageIndirectLong, 2}, // 07 - {&CPU::PHP, 3, "php", AddressingMode::Implied, 3}, // 08 + {&CPU::PHP, 3, "php", AddressingMode::Implied, 1}, // 08 {&CPU::ORA, 2, "ora", AddressingMode::ImmediateForA, 2}, // 09 {&CPU::ASL, 2, "asl", AddressingMode::Implied, 1}, // 0A {&CPU::PHD, 4, "phd", AddressingMode::Implied, 1}, // 0B @@ -743,18 +741,22 @@ namespace ComSquare::CPU //! @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). //! @return Return the value of the register. - uint8_t read(uint24_t addr) override; + uint8_t read(uint24_t addr) const override; //! @brief Write data to the internal CPU register. //! @param addr The address to write to. The address 0x0 should refer to the first byte of register. //! @param data The new value of the register. //! @throw InvalidAddress will be thrown if the address is more than $1F (the number of register). void write(uint24_t addr, uint8_t data) override; + //! @brief Get the size of the data. This size can be lower than the mapped data. + //! @return The number of bytes inside this memory. + uint24_t getSize() const override; + //! @brief Get the name of this accessor (used for debug purpose) - std::string getName() override; + std::string getName() const override; //! @brief Get the component of this accessor (used for debug purpose) - Component getComponent() override; + Component getComponent() const override; //! @brief Reset interrupt - Called on boot and when the reset button is pressed. virtual int RESB(); @@ -767,10 +769,14 @@ namespace ComSquare::CPU bool IsAbortRequested = false; //! @brief Return true if the CPU is overloaded with debugging features. - virtual bool isDebugger(); + virtual bool isDebugger() const; //! @brief Change the memory bus used by the CPU. virtual void setMemoryBus(std::shared_ptr bus); + + #ifdef DEBUGGER_ENABLED + friend Debugger::RegisterViewer; + #endif }; } diff --git a/sources/CPU/DMA/DMA.cpp b/sources/CPU/DMA/DMA.cpp index eda81d6..9c049ca 100644 --- a/sources/CPU/DMA/DMA.cpp +++ b/sources/CPU/DMA/DMA.cpp @@ -2,28 +2,36 @@ // Created by anonymus-raccoon on 5/26/20. // +#include #include "DMA.hpp" #include "../../Exceptions/InvalidAddress.hpp" namespace ComSquare::CPU { - uint8_t DMA::read(uint8_t addr) + DMA::DMA(std::shared_ptr bus) : _bus(std::move(bus)) {} + + void DMA::setBus(std::shared_ptr bus) + { + this->_bus = std::move(bus); + } + + uint8_t DMA::read(uint8_t addr) const { switch (addr) { case 0x0: - return this->controlRegister.raw; + return this->_controlRegister.raw; case 0x1: - return this->port; + return this->_port; case 0x2: - return this->aAddress.bytes[0]; + return this->_aAddress.bytes[0]; case 0x3: - return this->aAddress.bytes[1]; + return this->_aAddress.bytes[1]; case 0x4: - return this->aAddress.bytes[2]; + return this->_aAddress.bytes[2]; case 0x5: - return this->count.bytes[0]; + return this->_count.bytes[0]; case 0x6: - return this->count.bytes[1]; + return this->_count.bytes[1]; default: throw InvalidAddress("DMA read", addr); } @@ -33,33 +41,90 @@ namespace ComSquare::CPU { switch (addr) { case 0x0: - this->controlRegister.raw = data; + this->_controlRegister.raw = data; break; case 0x1: - this->port = data; + this->_port = data; break; case 0x2: - this->aAddress.bytes[0] = data; + this->_aAddress.bytes[0] = data; break; case 0x3: - this->aAddress.bytes[1] = data; + this->_aAddress.bytes[1] = data; break; case 0x4: - this->aAddress.bytes[2] = data; + this->_aAddress.bytes[2] = data; break; case 0x5: - this->count.bytes[0] = data; + this->_count.bytes[0] = data; break; case 0x6: - this->count.bytes[1] = data; + this->_count.bytes[1] = data; break; default: throw InvalidAddress("DMA read", addr); } } - uint8_t DMA::run(unsigned int cycles) + unsigned DMA::_writeOneByte(uint24_t aAddress, uint24_t bAddress) { + // Address $2180 refers to the WRam data register. Write to/Read from this port when the a address is on the vram cause different behaviors. + if (this->_port == 0x80) { + auto accessor = this->_bus->getAccessor(aAddress); + if (accessor && accessor->getComponent() == WRam) { + // WRAM->$2180 The write is not performed but the time is consumed anyway. + if (this->_controlRegister.direction == AtoB) + return 8; + // $2180->WRAM No read is performed (so only 4 master cycles are needed) but the value written is invalid. + this->_bus->write(aAddress, 0xFF); + return 4; + } + } + if (this->_controlRegister.direction == AtoB) { + uint8_t data = this->_bus->read(aAddress); + this->_bus->write(bAddress, data); + } else { + uint8_t data = this->_bus->read(bAddress); + this->_bus->write(aAddress, data); + } + return 8; + } + + unsigned DMA::run(unsigned int maxCycles) + { + unsigned cycles = 8; + int i = 0; + + do { + cycles += this->_writeOneByte(this->_aAddress.raw, 0x2100 | (this->_port + this->_getModeOffset(i))); + if (!this->_controlRegister.fixed) + this->_aAddress.page += this->_controlRegister.increment ? -1 : 1; + this->_count.raw--; + i++; + } while (this->_count.raw > 0 && this->enabled); + this->enabled = false; + return cycles; + } + + int DMA::_getModeOffset(int index) + { + switch (this->_controlRegister.mode) { + case OneToOne: + case TwoToOne: + case TwoToOneBis: + return 0; + + case TwoToTwo: + case TwoToTwoBis: + return index % 2; + + case FourToTwo: + case FourToTwoBis: + return (index & 0b11) > 1; + + case FourToFour: + return (index & 0b11); + } return 0; } } \ No newline at end of file diff --git a/sources/CPU/DMA/DMA.hpp b/sources/CPU/DMA/DMA.hpp index f152757..eef46dc 100644 --- a/sources/CPU/DMA/DMA.hpp +++ b/sources/CPU/DMA/DMA.hpp @@ -6,70 +6,112 @@ #define COMSQUARE_DMA_HPP #include +#include #include "../../Models/Int24.hpp" +#include "../../Memory/MemoryBus.hpp" + +#ifdef DEBUGGER_ENABLED + #include "../../Debugger/RegisterViewer.hpp" +#endif namespace ComSquare::CPU { - //! @brief The first three bytes of the DMA's control register. Used to tell how many bytes/registers there is. - enum DMAMode { - //! @brief 1 byte is transferred to 1 register (write once) - OneToOne = 0b000, - //! @brief 2 byte is transferred to 2 register (write once) - TwoToTwo = 0b001, - //! @brief 2 byte is transferred to 1 register (write twice) - TwoToOne = 0b010, - //! @brief 4 byte is transferred to 2 register (write twice) - FourToTwo = 0b011, - //! @brief 4 byte is transferred to 4 register (write once) - FourToFour = 0b100 - }; - //! @brief Class handling all DMA/HDMA transfers (Direct Memory Access or H-Blank Direct Memory Access) class DMA { public: + //! @brief The first three bytes of the DMA's control register. Used to tell how many bytes/registers there is. + enum DMAMode { + //! @brief 1 byte is transferred to 1 register (write once) + OneToOne = 0b000, + //! @brief 2 byte is transferred to 2 register (write once) + TwoToTwo = 0b001, + //! @brief 2 byte is transferred to 1 register (write twice) + TwoToOne = 0b010, + //! @brief 4 byte is transferred to 2 register (write twice) + FourToTwo = 0b011, + //! @brief 4 byte is transferred to 4 register (write once) + FourToFour = 0b100, + //! @brief Exactly the same as TwoToTwo (not implemented on the SNES so this fallbacks) + TwoToTwoBis = 0b101, + //! @brief Exactly the same as TwoToOne (not implemented on the SNES so this fallbacks) + TwoToOneBis = 0b110, + //! @brief Exactly the same as FourToTwo (not implemented on the SNES so this fallbacks) + FourToTwoBis = 0b111 + }; + + enum Direction { + AtoB, + BtoA + }; + private: + //! @brief Write one byte using the A address, the port and the _direction. Handle special cases where no write occurs. + //! @return The number of cycles used. + unsigned _writeOneByte(uint24_t aAddress, uint24_t bAddress); + //! @brief Get an offset corresponding to the current DMAMode and the index of the currently transferred byte. + int _getModeOffset(int index); + //! @brief DMA Control register (various information about the transfer) union { struct { - //! @brief The direction of the transfer (0: CPU to PPU aka A to B, 1: PPU to CPU aka B to A). - bool direction: 1; - //! @brief Two unused bites. - bool _: 2; - //! @brief if this flag is 0: increment. Else: decrement. (The A address) - bool increment: 1; + //! @brief DMA's mode: how many bytes/registers there is, how many writes... + DMAMode mode: 3; //! @brief If this flag is set, no increment/decrement will be done. bool fixed: 1; - //! @brief DMA's mode: how many bytes/registers there is, how many writes... - enum DMAMode mode: 3; + //! @brief if this flag is 0: increment. Else: decrement. (The A address) + bool increment: 1; + //! @brief Two unused bites. + bool _: 2; + //! @brief The direction of the transfer. + Direction direction: 1; }; uint8_t raw; - } controlRegister; + } _controlRegister; //! @brief If this is 'xx', the register accessed will be $21xx. - uint8_t port; + uint8_t _port; //! @brief The absolute long address of the data from the A bus. union { uint8_t bytes[3]; + struct { + uint16_t page; + uint8_t bank; + }; uint24_t raw: 24; - } aAddress; + } _aAddress; //! @brief The number of bytes to be transferred. union { uint8_t bytes[2]; uint16_t raw; - } count; + } _count; + + //! @brief The memory bus to use for read/write. + std::shared_ptr _bus; + + public: + //! @brief Is this channel set to run? + bool enabled; + + //! @brief Set the memory bus used by this dma channel. + void setBus(std::shared_ptr bus); //! @brief Bus helper to read from this channel. - uint8_t read(uint8_t addr); + uint8_t read(uint8_t addr) const; //! @brief Bus helper to write to this channel. void write(uint8_t addr, uint8_t data); //! @brief Run the DMA for x cycles //! @param cycles The maximum number of cycles this DMA should run. //! @return the number of cycles taken - uint8_t run(unsigned cycles); + unsigned run(unsigned cycles); DMA() = default; + DMA(std::shared_ptr bus); DMA(const DMA &) = default; DMA &operator=(const DMA &) = default; ~DMA() = default; + + #ifdef DEBUGGER_ENABLED + friend Debugger::RegisterViewer; + #endif }; } diff --git a/sources/CPU/Instructions/InternalInstruction.cpp b/sources/CPU/Instructions/InternalInstruction.cpp index 8430522..03fb101 100644 --- a/sources/CPU/Instructions/InternalInstruction.cpp +++ b/sources/CPU/Instructions/InternalInstruction.cpp @@ -82,7 +82,10 @@ namespace ComSquare::CPU int CPU::PHA(uint24_t, AddressingMode) { - this->_push(this->_registers.a); + if (this->_registers.p.m) + this->_push(this->_registers.al); + else + this->_push(this->_registers.a); return !this->_registers.p.m; } diff --git a/sources/Cartridge/Cartridge.cpp b/sources/Cartridge/Cartridge.cpp index 91a8036..ead9363 100644 --- a/sources/Cartridge/Cartridge.cpp +++ b/sources/Cartridge/Cartridge.cpp @@ -3,7 +3,6 @@ // #include -#include #include #include "Cartridge.hpp" #include "../Exceptions/InvalidAddress.hpp" @@ -39,17 +38,13 @@ namespace ComSquare::Cartridge } - uint8_t Cartridge::read_internal(uint24_t addr) + uint8_t Cartridge::read(uint24_t addr) const { - if (addr >= this->_size) - throw InvalidAddress("Cartridge read", addr); - return this->_data[addr + this->_romStart]; + return Ram::read(addr + this->_romStart); } - void Cartridge::write_internal(uint24_t addr, uint8_t data) + void Cartridge::write(uint24_t, uint8_t) { - (void)addr; - (void)data; throw InvalidAction("Witting to the ROM is not allowed."); } @@ -123,7 +118,8 @@ namespace ComSquare::Cartridge if (info.checksum + info.checksumComplement == 0xFFFF && info.checksum != 0 && info.checksumComplement != 0) score += 8; - if (info.emulationInterrupts.reset < 0x8000u) // The reset vector is the first thing called by the SNES so It must execute the code inside the ROM (the rom starts at 0x8000). + // The reset vector is the first thing called by the SNES so It must execute the code inside the ROM (the rom starts at 0x8000). + if (info.emulationInterrupts.reset < 0x8000u) continue; uint8_t resetOpCode = this->_data[info.emulationInterrupts.reset - 0x8000u]; switch (resetOpCode) { diff --git a/sources/Cartridge/Cartridge.hpp b/sources/Cartridge/Cartridge.hpp index 9dc7c73..90562e8 100644 --- a/sources/Cartridge/Cartridge.hpp +++ b/sources/Cartridge/Cartridge.hpp @@ -2,8 +2,7 @@ // Created by anonymus-raccoon on 1/27/20. // -#ifndef COMSQUARE_CARTRIDGE_HPP -#define COMSQUARE_CARTRIDGE_HPP +#pragma once #include #include "../Memory/AMemory.hpp" @@ -99,13 +98,11 @@ namespace ComSquare::Cartridge //! @param addr The address to read from. The address 0x0 should refer to the first byte of the rom's memory. //! @throw InvalidAddress will be thrown if the address is more than the size of the rom's memory. //! @return Return the data at the address. - uint8_t read_internal(uint24_t addr) override; + uint8_t read(uint24_t addr) const override; //! @brief Write data to the rom. //! @param addr The address to write to. The address 0x0 should refer to the first byte of the rom's memory. //! @param data The data to write. //! @throw InvalidAddress will be thrown if the address is more than the size of the rom's memory. - void write_internal(uint24_t addr, uint8_t data) override; + void write(uint24_t addr, uint8_t data) override; }; -} - -#endif //COMSQUARE_CARTRIDGE_HPP +} \ No newline at end of file diff --git a/sources/Debugger/APUDebug.cpp b/sources/Debugger/APUDebug.cpp index 3161ff3..fa768b5 100644 --- a/sources/Debugger/APUDebug.cpp +++ b/sources/Debugger/APUDebug.cpp @@ -535,7 +535,7 @@ namespace ComSquare::Debugger this->_snes.disableAPUDebugging(); } - bool APUDebug::isDebugger() + bool APUDebug::isDebugger() const { return true; } diff --git a/sources/Debugger/APUDebug.hpp b/sources/Debugger/APUDebug.hpp index db7628f..f907208 100644 --- a/sources/Debugger/APUDebug.hpp +++ b/sources/Debugger/APUDebug.hpp @@ -57,7 +57,7 @@ namespace ComSquare::Debugger //! @brief Return true if the CPU is overloaded with debugging features. - bool isDebugger() override; + bool isDebugger() const override; //! @brief Focus the debugger's window. void focus(); diff --git a/sources/Debugger/CPU/CPUDebug.cpp b/sources/Debugger/CPU/CPUDebug.cpp index d677158..b635ba4 100644 --- a/sources/Debugger/CPU/CPUDebug.cpp +++ b/sources/Debugger/CPU/CPUDebug.cpp @@ -8,6 +8,8 @@ #include #include #include +#include +#include using namespace ComSquare::CPU; @@ -58,7 +60,7 @@ namespace ComSquare::Debugger this->_updateDisassembly(this->_registers.pac, 0); } - bool CPUDebug::isDebugger() + bool CPUDebug::isDebugger() const { return true; } @@ -79,6 +81,10 @@ namespace ComSquare::Debugger try { unsigned cycles = 0; + for (auto &channel : this->_dmaChannels) + if (channel.enabled) + cycles += channel.run(INT_MAX); + if (this->_isPaused) return 0xFF; if (this->_isStepping) { @@ -129,11 +135,22 @@ namespace ComSquare::Debugger return ret; } - void CPUDebug::pause() + void CPUDebug::showError(const DebuggableError &error) { + QMessageBox msg; + msg.setIcon(QMessageBox::Critical); + msg.setText("Invalid rom action"); + msg.setInformativeText(error.what()); + msg.exec(); + } + + void CPUDebug::pause(bool forcePause) + { + if (forcePause && this->_isPaused) + return; this->_isPaused = !this->_isPaused; if (this->_isPaused) - this->_ui.actionPause->setText("Resume"); + this->_ui.actionPause->setText("Continue"); else this->_ui.actionPause->setText("Pause"); this->_updateDisassembly(this->_registers.pac); @@ -383,7 +400,9 @@ QSize RowPainter::sizeHint(const QStyleOptionViewItem &, const QModelIndex &) co return QSize(); } -StackModel::StackModel(std::shared_ptr bus, ComSquare::Debugger::CPUDebug &cpu) : _bus(bus), _cpu(cpu) { } +StackModel::StackModel(std::shared_ptr bus, ComSquare::Debugger::CPUDebug &cpu) + : _bus(std::move(bus)), _cpu(cpu) +{ } void StackModel::setMemoryBus(std::shared_ptr bus) { diff --git a/sources/Debugger/CPU/CPUDebug.hpp b/sources/Debugger/CPU/CPUDebug.hpp index db00d37..9120cec 100644 --- a/sources/Debugger/CPU/CPUDebug.hpp +++ b/sources/Debugger/CPU/CPUDebug.hpp @@ -9,7 +9,7 @@ #include "../../CPU/CPU.hpp" #include "../../Renderer/SFRenderer.hpp" #include "../../SNES.hpp" -#include "../../../ui/ui_cpu.h" +#include "../../../ui/ui_cpuView.h" #include "../ClosableWindow.hpp" namespace ComSquare::Debugger @@ -248,8 +248,10 @@ namespace ComSquare::Debugger std::string _getAbsoluteIndirectLongValue(uint24_t pc); public: + //! @brief Show an error dialog related to an exception. + void showError(const DebuggableError &error); //! @brief Pause/Resume the CPU. - void pause(); + void pause(bool forcePause = false); //! @brief Step - Execute a single instruction. void step(); //! @brief Next - Continue running instructions until the next line is reached. @@ -281,7 +283,7 @@ namespace ComSquare::Debugger ~CPUDebug() override = default; //! @brief Return true if the CPU is overloaded with debugging features. - bool isDebugger() override; + bool isDebugger() const override; //! @brief Focus the debugger's window. void focus(); diff --git a/sources/Debugger/CPU/Disassembly.cpp b/sources/Debugger/CPU/Disassembly.cpp index 75aefd2..7df19bb 100644 --- a/sources/Debugger/CPU/Disassembly.cpp +++ b/sources/Debugger/CPU/Disassembly.cpp @@ -251,7 +251,7 @@ namespace ComSquare::Debugger std::string CPUDebug::_getAbsoluteIndirectValue(uint24_t pc) { - uint24_t value = this->_bus->read(pc) + (this->_bus->read(pc + 1, true) << 8u); + uint24_t value = this->_bus->read(pc, true) + (this->_bus->read(pc + 1, true) << 8u); return "(" + Utility::to_hex(value, Utility::HexString::AsmPrefix) + ")"; } @@ -266,7 +266,7 @@ namespace ComSquare::Debugger std::string CPUDebug::_getAbsoluteIndirectIndexedByXValue(uint24_t pc) { - uint24_t value = this->_bus->read(pc) + (this->_bus->read(pc + 1, true) << 8u); + uint24_t value = this->_bus->read(pc, true) + (this->_bus->read(pc + 1, true) << 8u); return "(" + Utility::to_hex(value, Utility::HexString::AsmPrefix) + ", x)"; } } \ No newline at end of file diff --git a/sources/Debugger/MemoryBusDebug.cpp b/sources/Debugger/MemoryBusDebug.cpp index 17d77fc..1977eab 100644 --- a/sources/Debugger/MemoryBusDebug.cpp +++ b/sources/Debugger/MemoryBusDebug.cpp @@ -148,6 +148,13 @@ namespace ComSquare::Debugger return true; } + uint8_t MemoryBusDebug::read(uint24_t addr) + { + if (this->forceSilence) + return MemoryBus::read(addr); + return this->read(addr, false); + } + uint8_t MemoryBusDebug::read(uint24_t addr, bool silence) { if (!silence && !this->forceSilence) { @@ -155,11 +162,11 @@ namespace ComSquare::Debugger if (!accessor) { this->_model.log(BusLog(true, addr, accessor, this->_openBus, this->_openBus)); } else { - uint8_t value = accessor->read(addr - accessor->getStart()); + uint8_t value = accessor->read(accessor->getRelativeAddress(addr)); this->_model.log(BusLog(false, addr, accessor, value, value)); } } - return MemoryBus::read(addr); + return MemoryBus::read(addr, silence); } void MemoryBusDebug::write(uint24_t addr, uint8_t data) @@ -168,7 +175,7 @@ namespace ComSquare::Debugger std::optional value = std::nullopt; try { if (accessor) - value = accessor->read(addr - accessor->getStart()); + value = accessor->read(accessor->getRelativeAddress(addr)); } catch (InvalidAddress &) { value = std::nullopt; } @@ -177,7 +184,7 @@ namespace ComSquare::Debugger MemoryBus::write(addr, data); } - BusLog::BusLog(bool _write, uint24_t _addr, std::shared_ptr &_accessor, std::optional _oldData, uint8_t _newData) : + BusLog::BusLog(bool _write, uint24_t _addr, std::shared_ptr &_accessor, std::optional _oldData, uint8_t _newData) : write(_write), addr(_addr), accessor(std::move(_accessor)), oldData(_oldData), newData(_newData) {} } @@ -206,8 +213,10 @@ QVariant BusLogModel::data(const QModelIndex &index, int role) const return QString(ComSquare::Utility::to_hex(log.addr).c_str()); case 2: return QString(log.accessor ? log.accessor->getName().c_str() : "Bus"); - case 3: - return QString(log.accessor ? log.accessor->getValueName(log.addr - log.accessor->getStart()).c_str() : "Open bus"); + case 3: { + uint24_t addr = log.accessor->getRelativeAddress(log.addr); + return QString(log.accessor ? log.accessor->getValueName(addr).c_str() : "Open bus"); + } case 4: if (!log.oldData) return QString("???"); diff --git a/sources/Debugger/MemoryBusDebug.hpp b/sources/Debugger/MemoryBusDebug.hpp index c477d2d..08fa15c 100644 --- a/sources/Debugger/MemoryBusDebug.hpp +++ b/sources/Debugger/MemoryBusDebug.hpp @@ -17,13 +17,13 @@ namespace ComSquare::Debugger struct BusLog { BusLog(bool write, uint24_t addr, - std::shared_ptr &accessor, + std::shared_ptr &accessor, std::optional oldData, uint8_t newData); bool write; uint24_t addr; - std::shared_ptr accessor; + std::shared_ptr accessor; std::optional oldData; uint8_t newData; }; @@ -127,7 +127,12 @@ namespace ComSquare::Debugger //! @brief Read data at a global address and log it to the debugger. //! @param addr The address to read from. //! @return The value that the component returned for this address. If the address was mapped to ram, it simply returned the value. If the address was mapped to a register the component returned the register. - uint8_t read(uint24_t addr, bool silence = false) override; + uint8_t read(uint24_t addr) override; + + //! @brief Read data at a global address and log it to the debugger. + //! @param addr The address to read from. + //! @return The value that the component returned for this address. If the address was mapped to ram, it simply returned the value. If the address was mapped to a register the component returned the register. + uint8_t read(uint24_t addr, bool silence) override; //! @brief Write a data to a global address and log it to the debugger. //! @param addr The address to write to. diff --git a/sources/Debugger/MemoryViewer.cpp b/sources/Debugger/MemoryViewer.cpp index 2e1b6b4..4273c47 100644 --- a/sources/Debugger/MemoryViewer.cpp +++ b/sources/Debugger/MemoryViewer.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include "MemoryViewer.hpp" #include "../SNES.hpp" #include "../Memory/MemoryShadow.hpp" @@ -35,7 +36,7 @@ QVariant MemoryViewerModel::data(const QModelIndex &index, int role) const if (role != Qt::DisplayRole) return QVariant(); char buf[3]; - snprintf(buf, 3, "%02X", this->_memory->read_internal((index.row() << 4u) + index.column())); + snprintf(buf, 3, "%02X", this->_memory->read((index.row() << 4u) + index.column())); return QString(buf); } @@ -147,33 +148,48 @@ namespace ComSquare::Debugger if (dialogUI.checkBox->isChecked()) { try { value = this->switchToAddrTab(value); - } catch (InvalidAddress &) {} + } catch (const InvalidAddress &) { + QMessageBox msgBox; + msgBox.setIcon(QMessageBox::Critical); + msgBox.setText("This address is not mapped. Reading it will result in OpenBus."); + msgBox.exec(); + return; + } } - QModelIndex index = this->_ui.tableView->model()->index(value >> 4, value & 0x0000000F); + QModelIndex index = this->_ui.tableView->model()->index(value >> 4, value & 0x0F); this->_ui.tableView->scrollTo(index); this->_ui.tableView->selectionModel()->select(index, QItemSelectionModel::ClearAndSelect); + this->_ui.tableView->setCurrentIndex(index); } unsigned MemoryViewer::switchToAddrTab(uint24_t addr) { - std::shared_ptr accessor = this->_bus.getAccessor(addr); + std::shared_ptr accessor = this->_bus.getAccessor(addr); if (!accessor) throw InvalidAddress("Memory viewer switch to address", addr); - Memory::AMemory *ptr; - if (accessor->isMirror()) - ptr = accessor->getMirrored().get(); - else - ptr = accessor.get(); - if (ptr == this->_snes.wram.get()) + switch (accessor->getComponent()) { + case WRam: this->_ui.tabs->setCurrentIndex(0); - else if (ptr == this->_snes.sram.get()) + break; + case SRam: this->_ui.tabs->setCurrentIndex(1); - else if (ptr == this->_snes.cartridge.get()) + break; + case Rom: this->_ui.tabs->setCurrentIndex(2); - else + break; + default: throw InvalidAddress("Memory viewer switch to address", addr); - return addr - accessor->getStart(); + } + addr = accessor->getRelativeAddress(addr); + if (addr > accessor->getSize()) { + QMessageBox msgBox; + msgBox.setIcon(QMessageBox::Critical); + msgBox.setText((std::string("The ") + accessor->getName() + " is too small to contain this address.").c_str()); + msgBox.exec(); + return 0; + } + return addr; } void MemoryViewer::focus() diff --git a/sources/Debugger/RegisterViewer.cpp b/sources/Debugger/RegisterViewer.cpp new file mode 100644 index 0000000..5797773 --- /dev/null +++ b/sources/Debugger/RegisterViewer.cpp @@ -0,0 +1,169 @@ +// +// Created by anonymus-raccoon on 5/28/20. +// + +#include "RegisterViewer.hpp" +#include "../SNES.hpp" +#include "../Utility/Utility.hpp" + +namespace ComSquare::Debugger +{ + RegisterViewer::RegisterViewer(SNES &snes) + : _window(new ClosableWindow(*this, &RegisterViewer::disableDebugger)), + _ui(), + _snes(snes) + { + this->_window->setContextMenuPolicy(Qt::NoContextMenu); + this->_window->setAttribute(Qt::WA_QuitOnClose, false); + this->_window->setAttribute(Qt::WA_DeleteOnClose); + + this->_ui.setupUi(this->_window); + this->_setupUi(); + this->_window->show(); + } + + void RegisterViewer::_setupUi() + { + this->_models.clear(); + + std::array channels = { + this->_ui.dmaChannel1, + this->_ui.dmaChannel2, + this->_ui.dmaChannel3, + this->_ui.dmaChannel4, + this->_ui.dmaChannel5, + this->_ui.dmaChannel6, + this->_ui.dmaChannel7, + this->_ui.dmaChannel8 + }; + for (int i = 0; i < 8; i++) { + RegistersViewerModel *model = new RegistersViewerModel(this->_snes); + model->addRegister(Register(0x420B, std::string(":") + std::to_string(i), "Enabled", [i](SNES &snes) { + return snes.cpu->_dmaChannels[i].enabled; + }, nullptr, Boolean)); + model->addRegister(Register(0x4302 + (i << 4u), "-4", "A address", [i](SNES &snes) { + return snes.cpu->_dmaChannels[i]._aAddress.raw; + }, nullptr, TwentyFourBits)); + model->addRegister(Register(0x4301 + (i << 4u), "", "B address", [i](SNES &snes) { + return 0x2100 | snes.cpu->_dmaChannels[i]._port; + }, nullptr, SixteenBits)); + model->addRegister(Register(0x4305 + (i << 4u), "-6", "Count", [i](SNES &snes) { + return snes.cpu->_dmaChannels[i]._count.raw; + }, nullptr, SixteenBits)); + model->addRegister(Register(0x4300 + (i << 4u), ":7", "B To A", [i](SNES &snes) { + return snes.cpu->_dmaChannels[i]._controlRegister.direction; + }, nullptr, Boolean)); + model->addRegister(Register(0x4300 + (i << 4u), ":3", "Fixed", [i](SNES &snes) { + return snes.cpu->_dmaChannels[i]._controlRegister.fixed; + }, nullptr, Boolean)); + model->addRegister(Register(0x4300 + (i << 4u), ":4", "Decrement", [i](SNES &snes) { + return snes.cpu->_dmaChannels[i]._controlRegister.increment; + }, nullptr, Boolean)); + model->addRegister(Register(0x4300 + (i << 4u), ":0-2", "Mode", [i](SNES &snes) { + return snes.cpu->_dmaChannels[i]._controlRegister.increment; + }, nullptr, EightBits)); + channels[i]->setModel(model); + this->_models.push_back(model); + } + } + + void RegisterViewer::focus() + { + this->_window->activateWindow(); + } + + void RegisterViewer::disableDebugger() + { + this->_snes.disableRegisterDebugging(); + } + + RegisterViewer::~RegisterViewer() + { + for (auto &model : this->_models) + delete model; + } + + Register::Register(uint24_t addr, + const std::string &usedBits, + const std::string ®Name, + const std::function &getValue, + const std::function &setValue, + RegisterType regType) + : address(addr), + bits(usedBits), + name(regName), + get(getValue), + set(setValue), + type(regType) {} +} + +using namespace ComSquare; +using namespace ComSquare::Debugger; + +RegistersViewerModel::RegistersViewerModel(SNES &snes, QObject *parent) : QAbstractTableModel(parent), _snes(snes) { } + + +void RegistersViewerModel::addRegister(Register reg) +{ + int row = this->_registers.size(); + this->beginInsertRows(QModelIndex(), row, row); + this->_registers.push_back(reg); + this->insertRow(row); + this->endInsertRows(); +} + +int RegistersViewerModel::rowCount(const QModelIndex &) const +{ + return this->_registers.size(); +} + +int RegistersViewerModel::columnCount(const QModelIndex &) const +{ + return 3; +} + +QVariant RegistersViewerModel::data(const QModelIndex &index, int role) const +{ + Register reg = this->_registers[index.row()]; + + if (role == Qt::CheckStateRole && reg.type == Boolean && index.column() == 2) + return reg.get(this->_snes) ? Qt::Checked : Qt::Unchecked; + + if (role != Qt::DisplayRole) + return QVariant(); + + switch (index.column()) { + case 0: + return QString((Utility::to_hex(reg.address) + reg.bits).c_str()); + case 1: + return QString(reg.name.c_str()); + case 2: + switch (reg.type) { + case Boolean: + return QString(reg.get(this->_snes) ? "True" : "False"); + case EightBits: + return QString(Utility::to_hex(static_cast(reg.get(this->_snes))).c_str()); + case SixteenBits: + return QString(Utility::to_hex(static_cast(reg.get(this->_snes))).c_str()); + case TwentyFourBits: + return QString(Utility::to_hex(static_cast(reg.get(this->_snes))).c_str()); + } + } + return QVariant(); +} + +QVariant RegistersViewerModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (orientation == Qt::Vertical || role != Qt::DisplayRole) + return QVariant(); + switch (section) { + case 0: + return QString("Address"); + case 1: + return QString("Name"); + case 2: + return QString("Value"); + default: + return QVariant(); + } +} \ No newline at end of file diff --git a/sources/Debugger/RegisterViewer.hpp b/sources/Debugger/RegisterViewer.hpp new file mode 100644 index 0000000..b232c10 --- /dev/null +++ b/sources/Debugger/RegisterViewer.hpp @@ -0,0 +1,118 @@ +// +// Created by anonymus-raccoon on 5/28/20. +// + +#ifndef COMSQUARE_REGISTERVIEWER_HPP +#define COMSQUARE_REGISTERVIEWER_HPP + +#include +#include "ClosableWindow.hpp" +#include "../../ui/ui_registersView.h" +#include "../Models/Int24.hpp" +#include "../Memory/MemoryBus.hpp" + +namespace ComSquare::Debugger +{ + struct Register; +} + +class RegistersViewerModel : public QAbstractTableModel +{ +Q_OBJECT +private: + //! @brief The list of registers to display / update. + std::vector _registers; + //! @brief Reference to the snes to get information from registers. + ComSquare::SNES &_snes; +public: + //! @brief Add a register. + void addRegister(ComSquare::Debugger::Register reg); + + RegistersViewerModel(ComSquare::SNES &snes, QObject *parent = nullptr); + RegistersViewerModel(const RegistersViewerModel &) = delete; + const RegistersViewerModel &operator=(const RegistersViewerModel &) = delete; + ~RegistersViewerModel() override = default; + + //! @brief The number of row the table has. + int rowCount(const QModelIndex &parent) const override; + //! @brief The number of column the table has. + int columnCount(const QModelIndex &parent) const override; + //! @brief Return a data representing the table cell. + QVariant data(const QModelIndex &index, int role) const override; + //! @brief Override the headers to use hex values. + QVariant headerData(int section, Qt::Orientation orientation, int role) const override; +}; + + +namespace ComSquare +{ + class SNES; + + namespace Debugger + { + class RegisterViewer : public QObject { + private: + //! @brief The QT window for this debugger. + ClosableWindow *_window; + //! @brief A widget that contain the whole UI. + Ui::RegistersView _ui; + //! @brief The list of models used by different panels. + std::vector _models; + + //! @brief The snes instance to read/write to. + SNES &_snes; + + //! @brief Set models to the different tables and initialize them. + void _setupUi(); + public: + //! @brief Called when the window is closed. Turn off the debugger. + void disableDebugger(); + + explicit RegisterViewer(SNES &snes); + RegisterViewer( + const RegisterViewer &) = delete; + RegisterViewer &operator=(const RegisterViewer &) = delete; + ~RegisterViewer(); + + //! @brief Focus the debugger's window. + void focus(); + }; + + //! @brief The types of registers + enum RegisterType { + //! @brief This type display a checkbox + Boolean, + //! @brief A 8 bits hexadecimal value. + EightBits, + //! @brief A 16 bits hexadecimal value. + SixteenBits, + //! @brief A 24 bits hexadecimal value. + TwentyFourBits + }; + + //! @brief Struct containing information about a register. + struct Register { + Register(uint24_t addr, + const std::string &usedBits, + const std::string ®Name, + const std::function &getValue, + const std::function &setValue, + RegisterType regType); + + //! @brief Where this register is located on the bus. + uint24_t address; + //! @brief Specify witch bits are concerned if not all bytes are concerned. + std::string bits; + //! @brief The name of this register. + std::string name; + //! @brief How to get this value. + std::function get; + //! @brief How to set this value. + std::function set; + //! @brief How this value should be displayed/asked for input. + RegisterType type; + }; + } +} + +#endif //COMSQUARE_REGISTERVIEWER_HPP diff --git a/sources/Exceptions/DebuggableError.hpp b/sources/Exceptions/DebuggableError.hpp index fcc9180..08c8d8e 100644 --- a/sources/Exceptions/DebuggableError.hpp +++ b/sources/Exceptions/DebuggableError.hpp @@ -2,8 +2,7 @@ // Created by anonymus-raccoon on 3/26/20. // -#ifndef COMSQUARE_DEBUGGABLEERROR_HPP -#define COMSQUARE_DEBUGGABLEERROR_HPP +#pragma once #include @@ -11,5 +10,3 @@ namespace ComSquare { class DebuggableError : public std::exception {}; } - -#endif //COMSQUARE_DEBUGGABLEERROR_HPP diff --git a/sources/Memory/AMemory.cpp b/sources/Memory/AMemory.cpp index ce51b16..70ea7b5 100644 --- a/sources/Memory/AMemory.cpp +++ b/sources/Memory/AMemory.cpp @@ -3,37 +3,36 @@ // #include "AMemory.hpp" -#include namespace ComSquare::Memory { + uint24_t AMemory::getRelativeAddress(uint24_t addr) const + { + return addr - this->_start; + } + void AMemory::setMemoryRegion(uint24_t start, uint24_t end) { this->_start = start; this->_end = end; } - bool AMemory::hasMemoryAt(uint24_t addr) + bool AMemory::hasMemoryAt(uint24_t addr) const { return this->_start <= addr && addr <= this->_end; } - uint32_t AMemory::getStart() - { - return this->_start; - } - - bool AMemory::isMirror() + bool AMemory::isMirror() const { return false; } - std::shared_ptr AMemory::getMirrored() + std::shared_ptr AMemory::getMirrored() const { return nullptr; } - std::string AMemory::getValueName(uint24_t) + std::string AMemory::getValueName(uint24_t) const { return "???"; } diff --git a/sources/Memory/AMemory.hpp b/sources/Memory/AMemory.hpp index 1450261..575226a 100644 --- a/sources/Memory/AMemory.hpp +++ b/sources/Memory/AMemory.hpp @@ -2,9 +2,7 @@ // Created by anonymus-raccoon on 1/23/20. // -#ifndef COMSQUARE_AMEMORY_HPP -#define COMSQUARE_AMEMORY_HPP - +#pragma once #include #include @@ -12,27 +10,23 @@ #include #include "../Models/Int24.hpp" #include "../Models/Components.hpp" +#include "IMemory.hpp" namespace ComSquare::Memory { - //! @brief Common interface implemented by all components mapping memory. - class AMemory { - private: + //! @brief Abstract class representing a continuous block of memory. + class AMemory : public IMemory { + protected: //! @brief The starting address mapped to this component. uint24_t _start = 0; //! @brief The last continuous address mapped to this components. For shadows, see the MemoryShadow class. uint24_t _end = 0; public: - //! @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. - //! @return Return the data at the address given as parameter. - virtual uint8_t read(uint24_t addr) = 0; - //! @brief Write data to this component. - //! @param addr The local address to write data (0x0 should refer to the first byte of this component). - //! @param data The new data to write. - //! @throw This function should thrown an InvalidAddress for address that are not mapped to the component. - virtual void write(uint24_t addr, uint8_t data) = 0; + //! @brief Translate an absolute address to a relative address + //! @param addr The absolute address (in the 24 bit bus) + //! @return The local address (0 refers to the first byte of this component). + //! @throw InvalidAddress is thrown if the address is not mapped by this component. + virtual uint24_t getRelativeAddress(uint24_t addr) const override; //! @brief Change starting and ending points of this mapped memory. //! @param start The first address mapped to this component. //! @param end The last address mapped to this component. @@ -41,26 +35,16 @@ namespace ComSquare::Memory //! @brief Return true if this component has mapped the address. //! @param addr The address to check. //! @return True if this address is mapped to the component. False otherwise. - virtual bool hasMemoryAt(uint24_t addr); - //! @brief Get the first address mapped to this component. - //! @return the _start value. - virtual uint24_t getStart(); + virtual bool hasMemoryAt(uint24_t addr) const override; //! @brief Check if this memory is a mirror or not. //! @return True if this memory is a mirror. False otherwise. - virtual bool isMirror(); - //! @brief Get the name of this accessor (used for debug purpose) - virtual std::string getName() = 0; - //! @brief Get the component of this accessor (used for debug purpose) - virtual Component getComponent() = 0; + virtual bool isMirror() const override; //! @brief Get the name of the data at the address //! @param addr The address (in local space) - virtual std::string getValueName(uint24_t addr); + virtual std::string getValueName(uint24_t addr) const override; //! @brief Return the memory accessor this accessor mirror if any //! @return nullptr if isMirror is false, the source otherwise. - virtual std::shared_ptr getMirrored(); - virtual ~AMemory() = default; + virtual std::shared_ptr getMirrored() const override; + virtual ~AMemory() override = default; }; -}; - - -#endif //COMSQUARE_AMEMORY_HPP +} \ No newline at end of file diff --git a/sources/Memory/ARectangleMemory.cpp b/sources/Memory/ARectangleMemory.cpp index e7e9ff4..4252f74 100644 --- a/sources/Memory/ARectangleMemory.cpp +++ b/sources/Memory/ARectangleMemory.cpp @@ -5,45 +5,25 @@ #include #include "ARectangleMemory.hpp" #include "../Exceptions/InvalidAddress.hpp" -#include "../Utility/Utility.hpp" namespace ComSquare::Memory { - uint8_t ARectangleMemory::read(uint24_t addr) + uint24_t ARectangleMemory::getRelativeAddress(uint24_t addr) const { - addr += this->getStart(); uint8_t bank = addr >> 16u; uint16_t page = addr; unsigned bankCount = bank - this->_startBank; - unsigned pageCount = this->_endPage - this->_startPage; + unsigned pageCount = this->_endPage + 1 - this->_startPage; if (bank < this->_startBank || bank > this->_endBank) - throw InvalidAddress("Rectangle memory read Invalid Bank", addr); + throw InvalidAddress("Rectangle memory: Invalid Bank", addr); if (page < this->_startPage || page > this->_endPage) - throw InvalidAddress("Rectangle memory read Invalid Page", addr); + throw InvalidAddress("Rectangle memory: Invalid Page", addr); page -= this->_startPage; - page += pageCount * bankCount; - return this->read_internal(page); + return pageCount * bankCount + page; } - void ARectangleMemory::write(uint24_t addr, uint8_t data) - { - addr += this->getStart(); - uint8_t bank = addr >> 16u; - uint16_t page = addr; - unsigned bankCount = bank - this->_startBank; - unsigned pageCount = this->_endPage - this->_startPage; - - 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); - } - - bool ARectangleMemory::hasMemoryAt(uint24_t addr) + bool ARectangleMemory::hasMemoryAt(uint24_t addr) const { uint8_t bank = addr >> 16u; uint16_t page = addr; @@ -54,11 +34,6 @@ namespace ComSquare::Memory return false; } - uint24_t ARectangleMemory::getStart() - { - return (this->_startBank << 16u) + this->_startPage; - } - void ARectangleMemory::setMemoryRegion(uint8_t startBank, uint8_t endBank, uint16_t startPage, uint16_t endPage) { this->_startBank = startBank; @@ -66,4 +41,19 @@ namespace ComSquare::Memory this->_startPage = startPage; this->_endPage = endPage; } + + bool ARectangleMemory::isMirror() const + { + return false; + } + + std::shared_ptr ARectangleMemory::getMirrored() const + { + return nullptr; + } + + std::string ARectangleMemory::getValueName(uint24_t) const + { + return "???"; + } } \ No newline at end of file diff --git a/sources/Memory/ARectangleMemory.hpp b/sources/Memory/ARectangleMemory.hpp index 0a8f028..347db58 100644 --- a/sources/Memory/ARectangleMemory.hpp +++ b/sources/Memory/ARectangleMemory.hpp @@ -2,16 +2,14 @@ // Created by anonymus-raccoon on 1/29/20. // -#ifndef COMSQUARE_ARECTANGLEMEMORY_HPP -#define COMSQUARE_ARECTANGLEMEMORY_HPP +#pragma once - -#include "AMemory.hpp" +#include "IMemory.hpp" namespace ComSquare::Memory { - //! @brief Superset of the AMemory to map non continuous rectangle to the memory. (A rectangle that spam across more than one bank but that does not start at 0000 or end at FFFF). - class ARectangleMemory : public AMemory { + //! @brief Base memory class to map non continuous rectangle to the memory. (A rectangle that spam across more than one bank but that does not start at $0000 or end at $FFFF). + class ARectangleMemory : public IMemory { protected: //! @brief The first bank to map to. uint8_t _startBank = 0; @@ -22,33 +20,15 @@ namespace ComSquare::Memory //! @brief The last address of each bank to map. uint16_t _endPage = 0; public: - //! @brief Read data from the component using the same method as the basic AMemory. - //! @param addr The global 24 bits address. This method is responsible of mapping to the component's read. - //! @throw InvalidAddress if the address is not mapped to the component. - //! @return Return the data at the address given as parameter. - uint8_t read(uint24_t addr) override; - //! @brief Write data to this component using the same method as the basic AMemory. - //! @param addr The global 24 bits address. This method is responsible of mapping to the component's write. - //! @param data The new data to write. - //! @throw InvalidAddress if the address is not mapped to the component. - void write(uint24_t addr, uint8_t data) override; - //! @brief Internal component read. Implement this as you would implement a basic AMemory's read. - //! @param addr The local address to read from. 0x0 refer to the first byte of your data and the address is in the component's space. That means that you can consider this address as continuous - //! @throw This function should thrown an InvalidAddress for address that are not mapped to the component. - //! @return Return the data at the address given as parameter. - virtual uint8_t read_internal(uint24_t addr) = 0; - //! @brief Internal component write. Implement this as you would implement a basic AMemory's write. - //! @param addr The local address to write to. 0x0 refer to the first byte of your data and the address is in the component's space. That means that you can consider this address as continuous - //! @param data The new data to write. - //! @throw This function should thrown an InvalidAddress for address that are not mapped to the component. - virtual void write_internal(uint24_t addr, uint8_t data) = 0; + //! @brief Translate an absolute address to a relative address + //! @param addr The absolute address (in the 24 bit bus) + //! @return The local address (0 refers to the first byte of this component). + //! @throw InvalidAddress is thrown if the address is not mapped by this component. + virtual uint24_t getRelativeAddress(uint24_t addr) const override; //! @brief Return true if this component has mapped the address. //! @param addr The address to check. //! @return True if this address is mapped to the component. False otherwise. - bool hasMemoryAt(uint24_t addr) override; - //! @brief Get the first address mapped to this component. - //! @return the _start value. - uint24_t getStart() override; + bool hasMemoryAt(uint24_t addr) const override; //! @brief Change starting and ending points of this mapped memory. //! @param startBank The first bank mapped to this component. //! @param endBank The last bank mapped to this component. @@ -56,7 +36,15 @@ namespace ComSquare::Memory //! @param endPage The end page mapped to this component (every mapped banks will have this pages lower than this mapped) //! @warning The start/end address should be a rectangle. To mirror memory, use the MemoryShadow class and not this one. void setMemoryRegion(uint8_t startBank, uint8_t endBank, uint16_t startPage, uint16_t endPage); + //! @brief Check if this memory is a mirror or not. + //! @return True if this memory is a mirror. False otherwise. + virtual bool isMirror() const override; + //! @brief Get the name of the data at the address + //! @param addr The address (in local space) + virtual std::string getValueName(uint24_t addr) const override; + //! @brief Return the memory accessor this accessor mirror if any + //! @return nullptr if isMirror is false, the source otherwise. + virtual std::shared_ptr getMirrored() const override; + virtual ~ARectangleMemory() override = default; }; -} - -#endif //COMSQUARE_ARECTANGLEMEMORY_HPP +} \ No newline at end of file diff --git a/sources/Memory/IMemory.hpp b/sources/Memory/IMemory.hpp new file mode 100644 index 0000000..fb36045 --- /dev/null +++ b/sources/Memory/IMemory.hpp @@ -0,0 +1,56 @@ +// +// Created by anonymus-raccoon on 1/23/20. +// + +#pragma once + +#include +#include +#include +#include +#include "../Models/Int24.hpp" +#include "../Models/Components.hpp" + +namespace ComSquare::Memory +{ + //! @brief Common interface implemented by all components mapping memory. + class IMemory { + public: + //! @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. + //! @return Return the data at the address given as parameter. + virtual uint8_t read(uint24_t addr) const = 0; + //! @brief Write data to this component. + //! @param addr The local address to write data (0x0 should refer to the first byte of this component). + //! @param data The new data to write. + //! @throw This function should thrown an InvalidAddress for address that are not mapped to the component. + virtual void write(uint24_t addr, uint8_t data) = 0; + //! @brief Return true if this component has mapped the address. + //! @param addr The address to check. + //! @return True if this address is mapped to the component. False otherwise. + virtual bool hasMemoryAt(uint24_t addr) const = 0; + //! @brief Translate an absolute address to a relative address + //! @param addr The absolute address (in the 24 bit bus) + //! @return The local address (0 refers to the first byte of this component). + //! @throw InvalidAddress is thrown if the address is not mapped by this component. + virtual uint24_t getRelativeAddress(uint24_t addr) const = 0; + //! @brief Get the size of the data. This size can be lower than the mapped data. + //! @return The number of bytes inside this memory. + virtual uint24_t getSize() const = 0; + //! @brief Check if this memory is a mirror or not. + //! @return True if this memory is a mirror. False otherwise. + virtual bool isMirror() const = 0; + //! @brief Get the name of this accessor (used for debug purpose) + virtual std::string getName() const = 0; + //! @brief Get the component of this accessor (used for debug purpose) + virtual Component getComponent() const = 0; + //! @brief Get the name of the data at the address + //! @param addr The address (in local space) + virtual std::string getValueName(uint24_t addr) const = 0; + //! @brief Return the memory accessor this accessor mirror if any + //! @return nullptr if isMirror is false, the source otherwise. + virtual std::shared_ptr getMirrored() const = 0; + virtual ~IMemory() = default; + }; +}; \ No newline at end of file diff --git a/sources/Memory/MemoryBus.cpp b/sources/Memory/MemoryBus.cpp index dca92ed..856119b 100644 --- a/sources/Memory/MemoryBus.cpp +++ b/sources/Memory/MemoryBus.cpp @@ -8,12 +8,13 @@ #include "../SNES.hpp" #include "MemoryShadow.hpp" #include "RectangleShadow.hpp" +#include "../Exceptions/InvalidAddress.hpp" namespace ComSquare::Memory { - std::shared_ptr MemoryBus::getAccessor(uint24_t addr) + std::shared_ptr MemoryBus::getAccessor(uint24_t addr) { - auto it = std::find_if(this->_memoryAccessors.begin(), this->_memoryAccessors.end(), [addr](std::shared_ptr &accessor) + auto it = std::find_if(this->_memoryAccessors.begin(), this->_memoryAccessors.end(), [addr](std::shared_ptr &accessor) { return accessor->hasMemoryAt(addr); }); @@ -22,29 +23,43 @@ namespace ComSquare::Memory return *it; } - uint8_t MemoryBus::read(uint24_t addr, bool silence) + uint8_t MemoryBus::read(uint24_t addr) { - std::shared_ptr handler = this->getAccessor(addr); + std::shared_ptr handler = this->getAccessor(addr); if (!handler) { - if (!silence) - std::cout << "Unknown memory accessor for address $" << std::hex << addr << ". Using open bus." << std::endl; + std::cout << "Unknown memory accessor for address $" << std::hex << addr << ". Using open bus." << std::endl; return this->_openBus; } - uint8_t data = handler->read(addr - handler->getStart()); + uint8_t data = handler->read(handler->getRelativeAddress(addr)); this->_openBus = data; return data; } + uint8_t MemoryBus::read(uint24_t addr, bool silence) + { + if (!silence) + return this->read(addr); + std::shared_ptr handler = this->getAccessor(addr); + + if (!handler) + return this->_openBus; + try { + return handler->read(handler->getRelativeAddress(addr)); + } catch (const InvalidAddress &) { + return 0; + } + } + void MemoryBus::write(uint24_t addr, uint8_t data) { - std::shared_ptr handler = this->getAccessor(addr); + std::shared_ptr handler = this->getAccessor(addr); if (!handler) { std::cout << "Unknown memory accessor for address " << std::hex << addr << ". Warning, it was a write." << std::endl; return; } - handler->write(addr - handler->getStart(), data); + handler->write(handler->getRelativeAddress(addr), data); } void MemoryBus::_mirrorComponents(SNES &console, unsigned i) @@ -72,7 +87,6 @@ namespace ComSquare::Memory console.cpu->setMemoryRegion(0x4200, 0x44FF); this->_memoryAccessors.push_back(console.cpu); - // TODO implement DMA & HDMA (4220 to 4300) // TODO implement Joys. // Mirror to the quarter 1. diff --git a/sources/Memory/MemoryBus.hpp b/sources/Memory/MemoryBus.hpp index 044462d..a53e207 100644 --- a/sources/Memory/MemoryBus.hpp +++ b/sources/Memory/MemoryBus.hpp @@ -20,7 +20,7 @@ namespace ComSquare class MemoryBus { private: //! @brief The list of components registered inside the bus. Every components that can read/write to a public address should be in this vector. - std::vector> _memoryAccessors; + std::vector> _memoryAccessors; //! @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. @@ -40,9 +40,14 @@ namespace ComSquare //! @brief Read data at a global address. //! @param addr The address to read from. - //! @param silence Disable login to the memory bus's debugger (if enabled). Should only be used by other debuggers. //! @return The value that the component returned for this address. If the address was mapped to ram, it simply returned the value. If the address was mapped to a register the component returned the register. - virtual uint8_t read(uint24_t addr, bool silence = false); + virtual uint8_t read(uint24_t addr); + + //! @brief Read data at a global address. This form allow read to be silenced. + //! @param addr The address to read from. + //! @param silence Disable login to the memory bus's debugger (if enabled). Should only be used by other debuggers. This also won't affect the open bus. + //! @return The value that the component returned for this address. If the address was mapped to ram, it simply returned the value. If the address was mapped to a register the component returned the register. + virtual uint8_t read(uint24_t addr, bool silence); //! @brief Write a data to a global address. //! @param addr The address to write to. @@ -56,7 +61,7 @@ namespace ComSquare //! @brief Helper function to get the components that is responsible of read/write at an address. //! @param addr The address you want to look for. //! @return The components responsible for the address param or nullptr if none was found. - std::shared_ptr getAccessor(uint24_t addr); + std::shared_ptr getAccessor(uint24_t addr); //! @brief Return true if the Bus is overloaded with debugging features. virtual bool isDebugger(); diff --git a/sources/Memory/MemoryShadow.cpp b/sources/Memory/MemoryShadow.cpp index ecc4b4f..40434db 100644 --- a/sources/Memory/MemoryShadow.cpp +++ b/sources/Memory/MemoryShadow.cpp @@ -8,13 +8,13 @@ namespace ComSquare::Memory { - MemoryShadow::MemoryShadow(std::shared_ptr initial, uint24_t start, uint24_t end) + MemoryShadow::MemoryShadow(std::shared_ptr initial, uint24_t start, uint24_t end) : _initial(std::move(initial)) { this->setMemoryRegion(start, end); } - uint8_t MemoryShadow::read(uint24_t addr) + uint8_t MemoryShadow::read(uint24_t addr) const { return this->_initial->read(addr); } @@ -24,22 +24,27 @@ namespace ComSquare::Memory return this->_initial->write(addr, data); } - bool MemoryShadow::isMirror() + uint24_t MemoryShadow::getSize() const + { + return this->_initial->getSize(); + } + + bool MemoryShadow::isMirror() const { return true; } - std::shared_ptr MemoryShadow::getMirrored() + std::shared_ptr MemoryShadow::getMirrored() const { return this->_initial; } - std::string MemoryShadow::getName() + std::string MemoryShadow::getName() const { return this->_initial->getName(); } - Component MemoryShadow::getComponent() + Component MemoryShadow::getComponent() const { return this->_initial->getComponent(); } diff --git a/sources/Memory/MemoryShadow.hpp b/sources/Memory/MemoryShadow.hpp index 7c33c43..8b2c037 100644 --- a/sources/Memory/MemoryShadow.hpp +++ b/sources/Memory/MemoryShadow.hpp @@ -2,8 +2,7 @@ // Created by anonymus-raccoon on 1/28/20. // -#ifndef COMSQUARE_MEMORYSHADOW_HPP -#define COMSQUARE_MEMORYSHADOW_HPP +#pragma once #include #include "AMemory.hpp" @@ -13,10 +12,10 @@ namespace ComSquare::Memory class MemoryShadow : public AMemory { private: //! @brief Memory to shadow from. - std::shared_ptr _initial; + std::shared_ptr _initial; public: //! @brief Create a shadow for the memory given as parameter. - explicit MemoryShadow(std::shared_ptr initial, uint24_t start, uint24_t end); + MemoryShadow(std::shared_ptr initial, uint24_t start, uint24_t end); MemoryShadow(const MemoryShadow &) = default; MemoryShadow &operator=(const MemoryShadow &) = default; ~MemoryShadow() = default; @@ -25,23 +24,24 @@ namespace ComSquare::Memory //! @param addr The address to read from. The address 0x0 should refer to the first byte of the initial AMemory. //! @throw InvalidAddress will be thrown if the address is more than the size of the initial AMemory. //! @return Return the data at the address. - uint8_t read(uint24_t addr) override; + uint8_t read(uint24_t addr) const override; //! @brief Write data to the ram. //! @param addr The address to write to. The address 0x0 should refer to the first byte of the initial AMemory. //! @param data The data to write. //! @throw InvalidAddress will be thrown if the address is more than the size of the initial AMemory. void write(uint24_t addr, uint8_t data) override; + //! @brief Get the size of the data. This size can be lower than the mapped data. + //! @return The number of bytes inside this memory. + virtual uint24_t getSize() const override; //! @brief Check if this memory is a mirror or not. //! @return True if this memory is a mirror. False otherwise. - bool isMirror() override; + bool isMirror() const override; //! @brief Get the name of this accessor (used for debug purpose) - std::string getName() override; + std::string getName() const override; //! @brief Get the component of this accessor (used for debug purpose) - Component getComponent() override; + Component getComponent() const override; //! @brief Return the memory accessor this accessor mirror if any //! @return nullptr if isMirror is false, the source otherwise. - std::shared_ptr getMirrored() override; + std::shared_ptr getMirrored() const override; }; -} - -#endif //COMSQUARE_MEMORYSHADOW_HPP +} \ No newline at end of file diff --git a/sources/Memory/RectangleShadow.cpp b/sources/Memory/RectangleShadow.cpp index 424724a..325645d 100644 --- a/sources/Memory/RectangleShadow.cpp +++ b/sources/Memory/RectangleShadow.cpp @@ -3,53 +3,64 @@ // #include "RectangleShadow.hpp" -#include "../Utility/Utility.hpp" - #include #include namespace ComSquare::Memory { - RectangleShadow::RectangleShadow(std::shared_ptr initial, uint8_t startBank, uint8_t endBank, uint16_t startPage, uint16_t endPage) + RectangleShadow::RectangleShadow(std::shared_ptr initial, + uint8_t startBank, + uint8_t endBank, + uint16_t startPage, + uint16_t endPage) : _initial(std::move(initial)) { this->setMemoryRegion(startBank, endBank, startPage, endPage); } - uint8_t RectangleShadow::read_internal(uint24_t addr) + uint24_t RectangleShadow::getRelativeAddress(uint24_t addr) const { - addr += this->_bankOffset * (this->_endPage - this->_startPage); - return this->_initial->read_internal(addr); + uint24_t base = ARectangleMemory::getRelativeAddress(addr); + return base + this->_bankOffset * (1 + this->_endPage - this->_startPage); } - void RectangleShadow::write_internal(uint24_t addr, uint8_t data) + uint8_t RectangleShadow::read(uint24_t addr) const { - addr += this->_bankOffset * (this->_endPage - this->_startPage); - this->_initial->write_internal(addr, data); + return this->_initial->read(addr); } - RectangleShadow *RectangleShadow::setBankOffset(uint8_t bankOffset) + void RectangleShadow::write(uint24_t addr, uint8_t data) + { + return this->_initial->write(addr, data); + } + + RectangleShadow *RectangleShadow::setBankOffset(int bankOffset) { this->_bankOffset = bankOffset; return this; } - bool RectangleShadow::isMirror() + uint24_t RectangleShadow::getSize() const + { + return this->_initial->getSize(); + } + + bool RectangleShadow::isMirror() const { return true; } - std::shared_ptr RectangleShadow::getMirrored() + std::shared_ptr RectangleShadow::getMirrored() const { return this->_initial; } - std::string RectangleShadow::getName() + std::string RectangleShadow::getName() const { return this->_initial->getName(); } - Component RectangleShadow::getComponent() + Component RectangleShadow::getComponent() const { return this->_initial->getComponent(); } diff --git a/sources/Memory/RectangleShadow.hpp b/sources/Memory/RectangleShadow.hpp index 365c85f..8873f97 100644 --- a/sources/Memory/RectangleShadow.hpp +++ b/sources/Memory/RectangleShadow.hpp @@ -2,8 +2,7 @@ // Created by anonymus-raccoon on 2/4/20. // -#ifndef COMSQUARE_RECTANGLESHADOW_HPP -#define COMSQUARE_RECTANGLESHADOW_HPP +#pragma once #include #include "ARectangleMemory.hpp" @@ -14,39 +13,46 @@ namespace ComSquare::Memory class RectangleShadow : public ARectangleMemory { private: //! @brief Memory to shadow from. - std::shared_ptr _initial; + std::shared_ptr _initial; //! @brief The number of banks to add to the memory before accessing it from the initial data. - uint8_t _bankOffset = 0; + int _bankOffset = 0; public: //! @brief Create a shadow for the memory given as parameter. - explicit RectangleShadow(std::shared_ptr initial, uint8_t startBank, uint8_t endBank, uint16_t startPage, uint16_t endPage); + explicit RectangleShadow(std::shared_ptr initial, uint8_t startBank, uint8_t endBank, uint16_t startPage, uint16_t endPage); RectangleShadow(const RectangleShadow &) = default; RectangleShadow &operator=(const RectangleShadow &) = default; ~RectangleShadow() override = default; - //! @brief Internal component read. Implement this as you would implement a basic AMemory's read. - //! @param addr The local address to read from. 0x0 refer to the first byte of your data and the address is in the component's space. That means that you can consider this address as continuous - //! @throw This function should thrown an InvalidAddress for address that are not mapped to the component. - //! @return Return the data at the address given as parameter. - uint8_t read_internal(uint24_t addr) override; - //! @brief Internal component write. Implement this as you would implement a basic AMemory's write. - //! @param addr The local address to write to. 0x0 refer to the first byte of your data and the address is in the component's space. That means that you can consider this address as continuous - //! @param data The new data to write. - //! @throw This function should thrown an InvalidAddress for address that are not mapped to the component. - void write_internal(uint24_t addr, uint8_t data) override; + //! @brief Read from the initial AMemory given. + //! @param addr The address to read from. The address 0x0 should refer to the first byte of the initial AMemory. + //! @throw InvalidAddress will be thrown if the address is more than the size of the initial AMemory. + //! @return Return the data at the address. + uint8_t read(uint24_t addr) const override; + //! @brief Write data to the ram. + //! @param addr The address to write to. The address 0x0 should refer to the first byte of the initial AMemory. + //! @param data The data to write. + //! @throw InvalidAddress will be thrown if the address is more than the size of the initial AMemory. + void write(uint24_t addr, uint8_t data) override; + //! @brief Translate an absolute address to a relative address + //! @param addr The absolute address (in the 24 bit bus) + //! @return The local address (0 refers to the first byte of this component). + //! @throw InvalidAddress is thrown if the address is not mapped by this component. + uint24_t getRelativeAddress(uint24_t addr) const override; + //! @brief Get the size of the data. This size can be lower than the mapped data. + //! @return The number of bytes inside this memory. + virtual uint24_t getSize() const override; //! @brief Check if this memory is a mirror or not. //! @return True if this memory is a mirror. False otherwise. - bool isMirror() override; + bool isMirror() const override; //! @brief Get the name of this accessor (used for debug purpose) - std::string getName() override; + std::string getName() const override; //! @brief Get the component of this accessor (used for debug purpose) - Component getComponent() override; + Component getComponent() const override; //! @brief Return the memory accessor this accessor mirror if any //! @return nullptr if isMirror is false, the source otherwise. - std::shared_ptr getMirrored() override; + std::shared_ptr getMirrored() const override; - RectangleShadow *setBankOffset(uint8_t bankOffset); + //! @brief Set the number of bank this component do not shadow. Referring to the first byte of this component will refer to the first byte of the bank at (bankOffset + start of initial memory). + RectangleShadow *setBankOffset(int bankOffset); }; -} - -#endif //COMSQUARE_RECTANGLESHADOW_HPP +} \ No newline at end of file diff --git a/sources/PPU/Backgrounds.cpp b/sources/PPU/Backgrounds.cpp index c7d01dc..5919990 100644 --- a/sources/PPU/Backgrounds.cpp +++ b/sources/PPU/Backgrounds.cpp @@ -2,14 +2,9 @@ // Created by cbihan on 5/14/20. // -#include #include #include "PPU.hpp" #include "PPUUtils.hpp" -#include "../Exceptions/NotImplementedException.hpp" -#include "../Exceptions/InvalidAddress.hpp" -#include "../Ram/Ram.hpp" -#include "../Models/Vector2.hpp" namespace ComSquare::PPU { @@ -50,8 +45,8 @@ namespace ComSquare::PPU union TileMapData tileData; std::vector palette; int index = 0; - uint8_t reference = 0; - uint32_t color = 0; + uint8_t reference; + uint32_t color; tileData.raw = data; graphicAddress = this->getGraphicVramAddress(tileData.posX, tileData.posY, bg, bpp); @@ -106,7 +101,7 @@ namespace ComSquare::PPU uint8_t PPU::getTilePixelReference(uint16_t addr, int bpp, int nb) { - uint8_t reference = this->vram->read_internal(addr); + uint8_t reference = this->vram->read(addr); switch (bpp) { case 8: @@ -123,13 +118,13 @@ namespace ComSquare::PPU void PPU::drawBasicTileMap(uint16_t baseAddress, int bgNumber, int bpp, Vector2 characterSize, Vector2 offset) { - uint16_t tileMapValue = 0; + uint16_t tileMapValue; Vector2 pos(0,0); uint16_t vramAddress = baseAddress; while (vramAddress < 0x800 + baseAddress) { - tileMapValue = this->vram->read_internal(vramAddress); - tileMapValue += this->vram->read_internal(vramAddress + 1) << 8U; + tileMapValue = this->vram->read(vramAddress); + tileMapValue += this->vram->read(vramAddress + 1) << 8U; vramAddress += 2; drawBgTile(tileMapValue, {(pos.x * characterSize.x) + offset.x, (pos.y * characterSize.y) + offset.y}, bgNumber, bpp, characterSize); if (pos.x % 31 == 0 && pos.x) { diff --git a/sources/PPU/PPU.cpp b/sources/PPU/PPU.cpp index c0a5661..731a046 100644 --- a/sources/PPU/PPU.cpp +++ b/sources/PPU/PPU.cpp @@ -5,11 +5,8 @@ #include #include #include "PPU.hpp" -#include "PPUUtils.hpp" #include "../Exceptions/NotImplementedException.hpp" #include "../Exceptions/InvalidAddress.hpp" -#include "../Ram/Ram.hpp" -#include "../Models/Vector2.hpp" namespace ComSquare::PPU { @@ -21,11 +18,11 @@ namespace ComSquare::PPU { this->_registers._isLowByte = true; for (int i = 0; i < 512; i++) { - this->cgram->write_internal(i, random() % 255); + this->cgram->write(i, random() % 255); } } - uint8_t PPU::read(uint24_t addr) + uint8_t PPU::read(uint24_t addr) const { switch (addr) { case ppuRegisters::mpyl: @@ -45,7 +42,7 @@ namespace ComSquare::PPU case ppuRegisters::stat78: return 0; default: - throw InvalidAddress("PPU Internal Registers read ", addr); + throw InvalidAddress("PPU Internal Registers read ", addr + this->_start); } } @@ -69,7 +66,7 @@ namespace ComSquare::PPU //throw InvalidAddress("oamdata", addr); std::cout << "oamdata" << std::endl; // the oamAddress have to be calculated if fblank or not (not implemented) - oamram->write_internal(this->_registers._oamadd.oamAddress, this->_registers._oamdata); + oamram->write(this->_registers._oamadd.oamAddress, this->_registers._oamdata); this->_registers._oamadd.oamAddress++; break; case ppuRegisters::bgmode: @@ -126,7 +123,7 @@ namespace ComSquare::PPU //std::cout << "vmdatal" << std::endl; if (!this->_registers._inidisp.fblank) { this->_registers._vmdata.vmdatal = data; - this->vram->write_internal(getVramAddress(), this->_registers._vmdata.vmdatal); + this->vram->write(this->getVramAddress(), data); } if (!this->_registers._vmain.incrementMode) this->_registers._vmadd.vmadd += this->_registers._incrementAmount; @@ -135,7 +132,7 @@ namespace ComSquare::PPU //std::cout << "vmdatah" << std::endl; if (!this->_registers._inidisp.fblank) { this->_registers._vmdata.vmdatah = data; - this->vram->write_internal(getVramAddress(), this->_registers._vmdata.vmdatah); + this->vram->write(this->getVramAddress() + 1, data); } if (this->_registers._vmain.incrementMode) this->_registers._vmadd.vmadd += this->_registers._incrementAmount; @@ -163,9 +160,9 @@ namespace ComSquare::PPU } else { this->_registers._cgdata.cgdatah = data; - this->cgram->write_internal(this->_registers._cgadd, this->_registers._cgdata.cgdatal); + this->cgram->write(this->_registers._cgadd, this->_registers._cgdata.cgdatal); this->_registers._cgadd++; - this->cgram->write_internal(this->_registers._cgadd, this->_registers._cgdata.cgdatah); + this->cgram->write(this->_registers._cgadd, this->_registers._cgdata.cgdatah); this->_registers._cgadd++; } this->_registers._isLowByte = !this->_registers._isLowByte; @@ -214,14 +211,21 @@ namespace ComSquare::PPU this->_registers._setini.raw = data; break; //TODO adding the rest of the registers. oaf ! + case ppuRegisters::stat77: // some roms write here but it is useless + break; default: - throw InvalidAddress("PPU Internal Registers write", addr); + throw InvalidAddress("PPU Internal Registers write", addr + this->_start); } } + uint24_t PPU::getSize() const + { + return 0x3F; + } + uint16_t PPU::getVramAddress() { - uint16_t vanillaAddress = this->_registers._vmadd.vmadd; + uint16_t vanillaAddress = this->_registers._vmadd.vmadd * 2; switch (this->_registers._vmain.addressRemapping) { case 0b00: @@ -233,6 +237,7 @@ namespace ComSquare::PPU case 0b11: return (vanillaAddress & 0xFC00U) | (vanillaAddress & 0x0380U) >> 7U | (vanillaAddress & 0x7FU) << 3U; } + throw InvalidAddress("Invalid vram address", vanillaAddress); } void PPU::update(unsigned cycles) @@ -242,34 +247,34 @@ namespace ComSquare::PPU uint8_t red; uint8_t green; uint8_t blue; - uint32_t pixelTmp = 0x0; + uint32_t pixelTmp; if (!this->_registers._inidisp.fblank) { - for (int y = 0; y <= 255; y += 2) { - tmp = this->cgram->read_internal(y); - tmp += this->cgram->read_internal(y + 1) << 8; - blue = (tmp & 0x7D00U) >> 10U; - green = (tmp & 0x03E0U) >> 5U; - red = (tmp & 0x001FU); + for (int y = 0; y <= 255; y += 2) { + tmp = this->cgram->read(y); + tmp += this->cgram->read(y + 1) << 8; + blue = (tmp & 0x7D00U) >> 10U; + green = (tmp & 0x03E0U) >> 5U; + red = (tmp & 0x001FU); - pixelTmp = this->_registers._inidisp.brightness * 255U / 15U; - pixelTmp += (red * 255U / 31U) << 24U; - pixelTmp += (green * 255U / 31U) << 16U; - pixelTmp += (blue * 255U / 31U) << 8U; + pixelTmp = this->_registers._inidisp.brightness * 255U / 15U; + pixelTmp += (red * 255U / 31U) << 24U; + pixelTmp += (green * 255U / 31U) << 16U; + pixelTmp += (blue * 255U / 31U) << 8U; - for (int x = 0; x < 100; x++) - this->_renderer.putPixel(x, y, pixelTmp); - } + for (int x = 0; x < 100; x++) + this->_renderer.putPixel(x, y, pixelTmp); + } } this->renderBackground(1, {8, 8}, 4, false); this->_renderer.drawScreen(); } - std::string PPU::getName() + std::string PPU::getName() const { return "PPU"; } - std::string PPU::getValueName(uint24_t addr) + std::string PPU::getValueName(uint24_t addr) const { switch (addr) { case ppuRegisters::inidisp: @@ -405,18 +410,18 @@ namespace ComSquare::PPU } } - Component PPU::getComponent() + Component PPU::getComponent() const { return Ppu; } - bool PPU::isDebugger() + bool PPU::isDebugger() const { return false; } uint16_t PPU::cgramRead(uint16_t addr) { - return this->cgram->read_internal(addr); + return this->cgram->read(addr); } } \ No newline at end of file diff --git a/sources/PPU/PPU.hpp b/sources/PPU/PPU.hpp index 38aceaf..6436f74 100644 --- a/sources/PPU/PPU.hpp +++ b/sources/PPU/PPU.hpp @@ -5,11 +5,10 @@ #ifndef COMSQUARE_PPU_HPP #define COMSQUARE_PPU_HPP -#include +#include #include "../Memory/AMemory.hpp" #include "../Memory/MemoryBus.hpp" #include "../Renderer/IRenderer.hpp" -//#include "../Ram/ExtendedRam.hpp" #include "../Ram/Ram.hpp" #include "../Models/Vector2.hpp" @@ -563,16 +562,19 @@ namespace ComSquare::PPU //! @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. //! @return Return the data at the address given as parameter. - uint8_t read(uint24_t addr) override; + uint8_t read(uint24_t addr) const override; //! @brief Write data to this component. //! @param addr The local address to write data (0x0 should refer to the first byte of this component). //! @param data The new data to write. //! @throw This function should thrown an InvalidAddress for address that are not mapped to the component. void write(uint24_t addr, uint8_t data) override; //! @brief Get the name of this accessor (used for debug purpose) - std::string getName() override; + std::string getName() const override; //! @brief Get the component of this accessor (used for debug purpose) - Component getComponent() override; + Component getComponent() const override; + //! @brief Get the size of the data. This size can be lower than the mapped data. + //! @return The number of bytes inside this memory. + uint24_t getSize() const override; //! @brief Update the PPU of n cycles. //! @param The number of cycles to update. @@ -580,9 +582,9 @@ namespace ComSquare::PPU //! @brief Give the Vram Address with the right Address remapping uint16_t getVramAddress(); //! @brief Give the name of the Address register (used for debug) - std::string getValueName(uint24_t addr); + std::string getValueName(uint24_t addr) const; //! @brief Return true if the CPU is overloaded with debugging features. - virtual bool isDebugger(); + virtual bool isDebugger() const; //! @brief Allow others components to read the CGRAM (Debuggers) uint16_t cgramRead(uint16_t addr); //! @brief Render a background on the screen diff --git a/sources/Ram/Ram.cpp b/sources/Ram/Ram.cpp index 100901d..de8dc98 100644 --- a/sources/Ram/Ram.cpp +++ b/sources/Ram/Ram.cpp @@ -27,40 +27,32 @@ namespace ComSquare::Ram delete[] this->_data; } - uint8_t Ram::read_internal(uint24_t addr) + uint8_t Ram::read(uint24_t addr) const { + // TODO read/write after the size of the rom should noop or behave like a mirror. I don't really know. if (addr >= this->_size) - throw InvalidAddress("Ram read", addr); + throw InvalidAddress(this->getName() + " read", addr); return this->_data[addr]; } - void Ram::write_internal(uint24_t addr, uint8_t data) + void Ram::write(uint24_t addr, uint8_t data) { if (addr >= this->_size) - throw InvalidAddress("Ram write", addr); + throw InvalidAddress(this->getName() + " write", addr); this->_data[addr] = data; } - void Ram::memset(uint24_t start, uint24_t end, uint8_t value) - { - if (end >= this->_size) - throw InvalidAddress("Ram memset end", end); - if (start >= end) - throw InvalidAddress("Ram memset start", start); - std::memset(&this->_data[start], value, sizeof(uint8_t) * (end - start)); - } - - size_t Ram::getSize() + uint24_t Ram::getSize() const { return this->_size; } - std::string Ram::getName() + std::string Ram::getName() const { return this->_ramName; } - Component Ram::getComponent() + Component Ram::getComponent() const { return this->_ramType; } diff --git a/sources/Ram/Ram.hpp b/sources/Ram/Ram.hpp index 2a68e36..d3e4916 100644 --- a/sources/Ram/Ram.hpp +++ b/sources/Ram/Ram.hpp @@ -15,7 +15,7 @@ namespace ComSquare::Ram //! @brief The ram. (Can be used for WRam, SRam, VRam etc) uint8_t *_data; //! @brief The size of the ram (in bytes). - size_t _size; + uint24_t _size; //! @brief An id identifying the type of memory this is (for the debugger) Component _ramType; //! @brief The name of this ram. @@ -29,31 +29,27 @@ namespace ComSquare::Ram Ram &operator=(Ram &) = delete; //! @brief Destructor that free the ram. ~Ram() override; - //! @brief Read from the ram. - //! @param addr The address to read from. The address 0x0 should refer to the first byte of this ram. - //! @throw InvalidAddress will be thrown if the address is more than the size of the ram. - //! @return Return the data at the address. - uint8_t read_internal(uint24_t addr) override; - //! @brief Write data to the ram. - //! @param addr The address to write to. The address 0x0 should refer to the first byte of this ram. - //! @param data The data to write. - //! @throw InvalidAddress will be thrown if the address is more than the size of the ram. - void write_internal(uint24_t addr, uint8_t data) override; - //! @brief replace values between two addresses with a value - //! @param start start address to replace - //! @param end end address to replace - //! @param value replace value - void memset(uint24_t start, uint24_t end, uint8_t value); + //! @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. + //! @return Return the data at the address given as parameter. + uint8_t read(uint24_t addr) const override; + //! @brief Write data to this component. + //! @param addr The local address to write data (0x0 should refer to the first byte of this component). + //! @param data The new data to write. + //! @throw This function should thrown an InvalidAddress for address that are not mapped to the component. + void write(uint24_t addr, uint8_t data) override; + //! @brief Get the name of this accessor (used for debug purpose) - std::string getName() override; + std::string getName() const override; //! @brief Get the component of this accessor (used for debug purpose) - Component getComponent() override; + Component getComponent() const override; //! @brief Get the size of the ram in bytes. - size_t getSize(); + uint24_t getSize() const override; }; } diff --git a/sources/Renderer/QtRenderer/QtSFML.cpp b/sources/Renderer/QtRenderer/QtSFML.cpp index b270f3c..d7baf96 100644 --- a/sources/Renderer/QtRenderer/QtSFML.cpp +++ b/sources/Renderer/QtRenderer/QtSFML.cpp @@ -7,10 +7,8 @@ #include #include #include +#include "../../Exceptions/DebuggableError.hpp" #include "QtSFML.hpp" -#include "../../Exceptions/InvalidOpcode.hpp" -#include "../../Exceptions/InvalidAddress.hpp" -#include "../../Exceptions/InvalidAction.hpp" #ifdef Q_WS_X11 #include @@ -33,7 +31,7 @@ namespace ComSquare::Renderer this->_window.setCentralWidget(this->_sfWidget.get()); QMenu *file = this->_window.menuBar()->addMenu("&File"); - //TODO implement rom openning from this menu. + //TODO implement rom opening from this menu. (void)file; QMenu *game = this->_window.menuBar()->addMenu("&Game"); @@ -41,32 +39,44 @@ namespace ComSquare::Renderer QMainWindow::connect(reset, &QAction::triggered, this->_sfWidget.get(), &QtFullSFML::reset); game->addAction(reset); + + QMenu *debugger = this->_window.menuBar()->addMenu("&Debugger"); QAction *cpuDebugger = new QAction("CPU's Debugger", &this->_window); cpuDebugger->setShortcut(Qt::Key_F1); QMainWindow::connect(cpuDebugger, &QAction::triggered, this->_sfWidget.get(), &QtFullSFML::enableDebugCPU); debugger->addAction(cpuDebugger); + QAction *ramViewer = new QAction("Memory viewer", &this->_window); ramViewer->setShortcut(Qt::Key_F2); QMainWindow::connect(ramViewer, &QAction::triggered, this->_sfWidget.get(), &QtFullSFML::enableRamViewer); debugger->addAction(ramViewer); + QAction *headerViewer = new QAction("Header viewer", &this->_window); headerViewer->setShortcut(Qt::Key_F3); QMainWindow::connect(headerViewer, &QAction::triggered, this->_sfWidget.get(), &QtFullSFML::enableHeaderViewer); debugger->addAction(headerViewer); + QAction *apuDebugger = new QAction("APU's Debugger", &this->_window); apuDebugger->setShortcut(Qt::Key_F4); QMainWindow::connect(apuDebugger, &QAction::triggered, this->_sfWidget.get(), &QtFullSFML::enableDebugAPU); debugger->addAction(apuDebugger); + QAction *busDebugger = new QAction("Memory bus Viewer", &this->_window); busDebugger->setShortcut(Qt::Key_F5); QMainWindow::connect(busDebugger, &QAction::triggered, this->_sfWidget.get(), &QtFullSFML::enableDebugBus); debugger->addAction(busDebugger); + QAction *cgramDebugger = new QAction("Palette Viewer", &this->_window); cgramDebugger->setShortcut(Qt::Key_F6); QMainWindow::connect(cgramDebugger, &QAction::triggered, this->_sfWidget.get(), &QtFullSFML::enableCgramViewer); debugger->addAction(cgramDebugger); + QAction *registerDebugger = new QAction("Registers Viewer", &this->_window); + registerDebugger->setShortcut(Qt::Key_F7); + QMainWindow::connect(registerDebugger, &QAction::triggered, this->_sfWidget.get(), &QtFullSFML::enableRegisterViewer); + debugger->addAction(registerDebugger); + this->_window.show(); } @@ -96,9 +106,9 @@ namespace ComSquare::Renderer { try { this->_snes.update(); - } catch (DebuggableError &e) { + } catch (const DebuggableError &e) { std::cout << "Invalid rom's instruction: " << e.what() << std::endl; - this->_snes.enableCPUDebugging(true); + this->_snes.enableCPUDebuggingWithError(e); } catch (std::exception &e) { std::cerr << "An error occurred: " << e.what() << std::endl; QApplication::quit(); @@ -139,4 +149,9 @@ namespace ComSquare::Renderer { this->_snes.enableCgramDebugging(); } + + void QtFullSFML::enableRegisterViewer() + { + this->_snes.enableRegisterDebugging(); + } } \ No newline at end of file diff --git a/sources/Renderer/QtRenderer/QtSFML.hpp b/sources/Renderer/QtRenderer/QtSFML.hpp index 15afada..7d1791a 100644 --- a/sources/Renderer/QtRenderer/QtSFML.hpp +++ b/sources/Renderer/QtRenderer/QtSFML.hpp @@ -35,8 +35,12 @@ namespace ComSquare::Renderer void enableDebugBus(); //! @brief Action called when clicking on the enable Palette viewer button. void enableCgramViewer(); + //! @brief Action called when clicking on the enable DMA viewer button. + void enableRegisterViewer(); + //! @brief Action called when clicking on the reset button. void reset(); + QtFullSFML(SNES &snes, QWidget* parent, const QPoint& position, const QSize& size, int frameRate = 0); QtFullSFML(const QtFullSFML &) = delete; QtFullSFML &operator=(const QtFullSFML &) = delete; diff --git a/sources/SNES.cpp b/sources/SNES.cpp index ab007b7..3ad1cb4 100644 --- a/sources/SNES.cpp +++ b/sources/SNES.cpp @@ -15,15 +15,15 @@ namespace ComSquare { SNES::SNES(const std::string &romPath, Renderer::IRenderer &renderer) : - _bus(std::make_shared()), + bus(std::make_shared()), cartridge(new Cartridge::Cartridge(romPath)), wram(new Ram::Ram(16384, WRam, "WRam")), sram(new Ram::Ram(this->cartridge->header.sramSize, SRam, "SRam")), - cpu(new CPU::CPU(this->_bus, cartridge->header)), + cpu(new CPU::CPU(this->bus, cartridge->header)), ppu(new PPU::PPU(renderer)), apu(new APU::APU(renderer)) { - this->_bus->mapComponents(*this); + this->bus->mapComponents(*this); } void SNES::update() @@ -33,6 +33,17 @@ namespace ComSquare this->apu->update(cycleCount); } + void SNES::enableCPUDebuggingWithError(const DebuggableError &exception) + { + this->enableCPUDebugging(true); + #ifdef DEBUGGER_ENABLED + auto cpuDebug = std::static_pointer_cast(this->cpu); + cpuDebug->showError(exception); + #else + (void)exception; + #endif + } + void SNES::enableCPUDebugging(bool pause) { #ifdef DEBUGGER_ENABLED @@ -40,10 +51,10 @@ namespace ComSquare auto cpuDebug = std::static_pointer_cast(this->cpu); cpuDebug->focus(); if (pause) - cpuDebug->pause(); + cpuDebug->pause(true); } else { this->cpu = std::make_shared(*this->cpu, *this); - this->_bus->mapComponents(*this); + this->bus->mapComponents(*this); } #else std::cerr << "Debugging features are not enabled. You can't enable the debugger." << std::endl; @@ -54,7 +65,7 @@ namespace ComSquare void SNES::disableCPUDebugging() { this->cpu = std::make_shared(*this->cpu); - this->_bus->mapComponents(*this); + this->bus->mapComponents(*this); } void SNES::enableRamViewer() @@ -63,7 +74,7 @@ namespace ComSquare if (this->_ramViewer) this->_ramViewer->focus(); else - this->_ramViewer = std::make_unique(*this, *this->_bus); + this->_ramViewer = std::make_unique(*this, *this->bus); #endif } @@ -98,7 +109,7 @@ namespace ComSquare std::static_pointer_cast(this->apu)->focus(); else { this->apu = std::make_shared(*this->apu, *this); - this->_bus->mapComponents(*this); + this->bus->mapComponents(*this); } #else std::cerr << "Debugging features are not enabled. You can't enable the debugger." << std::endl; @@ -108,18 +119,18 @@ namespace ComSquare void SNES::disableAPUDebugging() { this->apu = std::make_shared(*this->apu); - this->_bus->mapComponents(*this); + this->bus->mapComponents(*this); } void SNES::enableMemoryBusDebugging() { #ifdef DEBUGGER_ENABLED - if (this->_bus->isDebugger()) - std::static_pointer_cast(this->_bus)->focus(); + if (this->bus->isDebugger()) + std::static_pointer_cast(this->bus)->focus(); else { - this->_bus = std::make_shared(*this, *this->_bus); - this->cpu->setMemoryBus(this->_bus); + this->bus = std::make_shared(*this, *this->bus); + this->cpu->setMemoryBus(this->bus); } #else std::cerr << "Debugging features are not enabled. You can't enable the debugger." << std::endl; @@ -129,8 +140,8 @@ namespace ComSquare void SNES::disableMemoryBusDebugging() { #ifdef DEBUGGER_ENABLED - this->_bus = std::make_shared(*this->_bus); - this->cpu->setMemoryBus(this->_bus); + this->bus = std::make_shared(*this->bus); + this->cpu->setMemoryBus(this->bus); #else std::cerr << "Debugging features are not enabled. You can't enable the debugger." << std::endl; #endif @@ -152,4 +163,21 @@ namespace ComSquare this->_cgramViewer = nullptr; #endif } + + void SNES::disableRegisterDebugging() + { + #ifdef DEBUGGER_ENABLED + this->_registerViewer = nullptr; + #endif + } + + void SNES::enableRegisterDebugging() + { + #ifdef DEBUGGER_ENABLED + if (this->_registerViewer) + this->_registerViewer->focus(); + else + this->_registerViewer = std::make_unique(*this); + #endif + } } diff --git a/sources/SNES.hpp b/sources/SNES.hpp index aba2cfd..4739600 100644 --- a/sources/SNES.hpp +++ b/sources/SNES.hpp @@ -12,11 +12,13 @@ #include "PPU/PPU.hpp" #include "APU/APU.hpp" #include "Renderer/IRenderer.hpp" -#ifdef DEBUGGER_ENABLED -#include "Debugger/MemoryViewer.hpp" -#include "Debugger/HeaderViewer.hpp" -#include "Debugger/CGramDebug.hpp" +#include "Exceptions/DebuggableError.hpp" +#ifdef DEBUGGER_ENABLED + #include "Debugger/MemoryViewer.hpp" + #include "Debugger/HeaderViewer.hpp" + #include "Debugger/CGramDebug.hpp" + #include "Debugger/RegisterViewer.hpp" #endif namespace ComSquare @@ -31,10 +33,13 @@ namespace ComSquare std::unique_ptr _headerViewer; //! @brief The window that allow the user to view the CGRAM. std::unique_ptr _cgramViewer; + //! @brief The window that allow the user to view registers. + std::unique_ptr _registerViewer; #endif - //! @brief The memory bus that map addresses to components. - std::shared_ptr _bus; public: + //! @brief The memory bus that map addresses to components. + std::shared_ptr bus; + //! @brief Cartridge containing instructions (ROM). std::shared_ptr cartridge; //! @brief Work Ram shared by all the components. @@ -55,6 +60,9 @@ namespace ComSquare void disableCPUDebugging(); //! @brief Enable the CPU's debugging window. void enableCPUDebugging(bool pause = false); + //! @brief Enable the CPU's debugger and show an error message related to an exception. + //! @param exception The exception to inform the user about. + void enableCPUDebuggingWithError(const DebuggableError &exception); //! @brief Disable the Ram's debugging window. void disableRamViewer(); //! @brief Enable the Ram's debugging window. @@ -75,6 +83,10 @@ namespace ComSquare void disableCgramDebugging(); //! @brief Enable the Cgram's debugging window. void enableCgramDebugging(); + //! @brief Disable the Register's debugging window. + void disableRegisterDebugging(); + //! @brief Enable the Register's debugging window. + void enableRegisterDebugging(); //! @brief Create all the components using a common memory bus for all of them. SNES(const std::string &ramPath, Renderer::IRenderer &renderer); diff --git a/sources/Utility/Utility.hpp b/sources/Utility/Utility.hpp index 489afc3..78b1ced 100644 --- a/sources/Utility/Utility.hpp +++ b/sources/Utility/Utility.hpp @@ -18,11 +18,11 @@ namespace ComSquare::Utility StandardPrefix }; - std::string to_hex(uint8_t i, HexString prefix = StandardPrefix); + std::string to_hex(uint8_t i, HexString prefix = AsmPrefix); - std::string to_hex(uint16_t i, HexString prefix = StandardPrefix); + std::string to_hex(uint16_t i, HexString prefix = AsmPrefix); - std::string to_hex(uint24_t i, HexString prefix = StandardPrefix); + std::string to_hex(uint24_t i, HexString prefix = AsmPrefix); std::string to_binary(uint8_t i); diff --git a/sources/main.cpp b/sources/main.cpp index 99bbc08..a13903b 100644 --- a/sources/main.cpp +++ b/sources/main.cpp @@ -16,11 +16,12 @@ void usage(char *bin) std::cout << "ComSquare:" << std::endl << "\tUsage: " << bin << " rom_path [options]" << std::endl << "Options:" << std::endl - << "\t-c, --cpu: \tEnable the debugger of the CPU." << std::endl - << "\t-m, --memory: \tEnable the memory viewer panel." << std::endl - << "\t-h, --header: \tShow the header of the cartridge." << std::endl - << "\t-b, --bus: \tShow the memory bus's log." << std::endl - << "\t-g, --cgram: \tShow the palette viewer." << std::endl; + << "\t-c, --cpu: \tEnable the debugger of the CPU." << std::endl + << "\t-m, --memory: \tEnable the memory viewer panel." << std::endl + << "\t-h, --header: \tShow the header of the cartridge." << std::endl + << "\t-b, --bus: \tShow the memory bus's log." << std::endl + << "\t-g, --cgram: \tShow the palette viewer." << std::endl + << "\t-r, --registers: \tShow the registers viewer." << std::endl; } void parseArguments(int argc, char **argv, SNES &snes) @@ -28,16 +29,17 @@ void parseArguments(int argc, char **argv, SNES &snes) while (true) { int option_index = 0; static struct option long_options[] = { - {"cpu", no_argument, 0, 'c'}, - {"apu", no_argument, 0, 'a'}, - {"memory", no_argument, 0, 'm'}, - {"header", no_argument, 0, 'h'}, - {"bus", no_argument, 0, 'b'}, - {"cgram", no_argument, 0, 'g'}, - {0, 0, 0, 0} + {"cpu", no_argument, 0, 'c'}, + {"apu", no_argument, 0, 'a'}, + {"memory", no_argument, 0, 'm'}, + {"header", no_argument, 0, 'h'}, + {"bus", no_argument, 0, 'b'}, + {"cgram", no_argument, 0, 'g'}, + {"registers", no_argument, 0, 'r'}, + {0, 0, 0, 0} }; - int c = getopt_long(argc, argv, "camhbg", long_options, &option_index); + int c = getopt_long(argc, argv, "camhbgr", long_options, &option_index); if (c == -1) break; switch (c) { @@ -62,6 +64,9 @@ void parseArguments(int argc, char **argv, SNES &snes) case 'g': snes.enableCgramDebugging(); break; + case 'r': + snes.enableRegisterDebugging(); + break; default: break; } @@ -70,7 +75,7 @@ void parseArguments(int argc, char **argv, SNES &snes) int main(int argc, char **argv) { - if (argc < 2) { + if (argc < 2 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) { usage(argv[0]); return 1; } diff --git a/tests/CPU/testAddressingMode.cpp b/tests/CPU/testAddressingMode.cpp index f4ed3e4..1fd8371 100644 --- a/tests/CPU/testAddressingMode.cpp +++ b/tests/CPU/testAddressingMode.cpp @@ -13,7 +13,7 @@ using namespace ComSquare; Test(AddrModeInit, LegitBus) { Init() - cr_assert_eq(snes._bus.get(), snes.cpu->_bus.get(), "Warning, the CPU's bus is not the same the SNES's bus. Next tests of the CPU may fail."); + cr_assert_eq(snes.bus.get(), snes.cpu->_bus.get(), "Warning, the CPU's bus is not the same the SNES's bus. Next tests of the CPU may fail."); } Test(AddrMode, Immediate) diff --git a/tests/CPU/testDMA.cpp b/tests/CPU/testDMA.cpp new file mode 100644 index 0000000..e661701 --- /dev/null +++ b/tests/CPU/testDMA.cpp @@ -0,0 +1,139 @@ +// +// Created by anonymus-raccoon on 2/1/21. +// + +#include +#include +#include "../tests.hpp" +using namespace ComSquare; + +Test(DMA, RomToVRAM) +{ + Init() + snes.cartridge->_size = 4000000; + snes.cartridge->_data = new uint8_t[snes.cartridge->_size]; + for (unsigned i = 0; i < 0x400; i++) { + snes.cartridge->_data[0x9be00 + i * 2] = i; + snes.cartridge->_data[0x9be00 + i * 2 + 1] = i >> 8; + } + + // Transferring $800 bytes from ROM ($13BE00) to VRam ($2000) via DMA channel 0 + + // Setting VRam address (since this is an indirect write) + snes.bus->write(0x2115, 0b10000000); + snes.bus->write(0x2117, 0x20); + snes.bus->write(0x2116, 0); + + snes.bus->write(0x4301, 0x18); + cr_assert_eq(snes.cpu->_dmaChannels[0]._port, 0x18, "The dma's b port was $%x but it should have been $18.", snes.cpu->_dmaChannels[0]._port); + snes.bus->write(0x4304, 0x13); + snes.bus->write(0x4303, 0xBE); + snes.bus->write(0x4302, 0x00); + cr_assert_eq(snes.cpu->_dmaChannels[0]._aAddress.raw, 0x13BE00, "The dma's a address was $%x but it should have been $13BE00.", snes.cpu->_dmaChannels[0]._aAddress.raw); + snes.bus->write(0x4306, 0x08); + snes.bus->write(0x4305, 0); + cr_assert_eq(snes.cpu->_dmaChannels[0]._count.raw, 0x0800, "The dma's count was $%x but it should have been $0800.", snes.cpu->_dmaChannels[0]._count.raw); + snes.bus->write(0x4300, 1); + cr_assert_eq(snes.cpu->_dmaChannels[0]._controlRegister.direction, CPU::DMA::AtoB, "Direction should have been 0 (A to B) but it was %x.", snes.cpu->_dmaChannels[0]._controlRegister.direction); + cr_assert_eq(snes.cpu->_dmaChannels[0]._controlRegister._, 0, "The unused byte should be 0."); + cr_assert_eq(snes.cpu->_dmaChannels[0]._controlRegister.increment, 0, "The increment byte should be set to 0."); + cr_assert_eq(snes.cpu->_dmaChannels[0]._controlRegister.fixed, 0, "The increment byte should be set to 0."); + cr_assert_eq(snes.cpu->_dmaChannels[0]._controlRegister.mode, CPU::DMA::TwoToTwo, "The DMA mode should have been TwoToTwo (%%001) but it was) $%x", snes.cpu->_dmaChannels[0]._controlRegister.mode); + cr_assert_eq(snes.cpu->_dmaChannels[0].enabled, false, "The DMA channel should be disabled."); + // Enabling DMA's channel 0 + snes.bus->write(0x420B, 1); + cr_assert_eq(snes.cpu->_dmaChannels[0].enabled, true, "The DMA channel should be enabled."); + // TODO There is an overhead of 12-24 cycles for the whole transfer. How should I know how many cycles there is? + auto cycles = snes.cpu->_dmaChannels[0].run(1000000); + cr_assert_eq(cycles, 8 + 8 * 0x800, "The dma should take $4008 cycles but it took $%x.", cycles); + cr_assert_eq(snes.cpu->_dmaChannels[0]._count.raw, 0, "The dma count should be 0 but it was $%x.", snes.cpu->_dmaChannels[0]._count.raw); + cr_assert_eq(snes.cpu->_dmaChannels[0]._aAddress.raw, 0x13C600, "The dma count should be $13C600 but it was $%x.", snes.cpu->_dmaChannels[0]._aAddress.raw); + cr_assert_eq(snes.cpu->_dmaChannels[0]._port, 0x18, "The dma count should be $18 but it was $%x.", snes.cpu->_dmaChannels[0]._port); + cr_assert_eq(snes.ppu->_registers._vmadd.vmadd, 0x2400, "The vram address should be $2400 but it was %x.", snes.ppu->_registers._vmadd.vmadd); + for(unsigned i = 0; i < 0x400; i++) { + uint16_t value = snes.ppu->vram->_data[0x2000 * 2 + i * 2] | (snes.ppu->vram->_data[0x2000 * 2 + i * 2 + 1] << 8); + cr_assert_eq(value, i, "The memory at %x should be %x but it was %x", 0x2000 + i, i, snes.ppu->vram->_data[i]); + } + cr_assert_eq(snes.cpu->_dmaChannels[0].enabled, false, "The DMA channel should be disabled."); +} + +Test(DMA, VramWrite) +{ + Init() + snes.bus->write(0x2117, 0x20); + snes.bus->write(0x2116, 0x0); + for (unsigned i = 0; i < 0x400; i++) { + snes.bus->write(0x2119, i >> 8); + snes.bus->write(0x2118, i); + cr_assert_eq(snes.ppu->_registers._vmadd.vmadd, 0x2001 + i, "The vram address was %x but it should have been %x", snes.ppu->_registers._vmadd.vmadd, 0x2001 + i); + } + for(unsigned i = 0; i < 0x400; i++) { + uint16_t value = snes.ppu->vram->_data[0x2000 * 2 + i * 2] | (snes.ppu->vram->_data[0x2000 * 2 + i * 2 + 1] << 8); + cr_assert_eq(value, (uint16_t)i, "The memory at %x should be %x but it was %x", 0x2000 + i, (uint16_t)i, value); + } +} + +Test(DMA, VramWriteInvertedOrder) +{ + Init() + snes.bus->write(0x2115, 0b10000000); + snes.bus->write(0x2117, 0x20); + snes.bus->write(0x2116, 0x0); + for (unsigned i = 0; i < 0x400; i++) { + snes.bus->write(0x2118, i); + snes.bus->write(0x2119, i >> 8); + cr_assert_eq(snes.ppu->_registers._vmadd.vmadd, 0x2001 + i, "The vram address was %x but it should have been %x", snes.ppu->_registers._vmadd.vmadd, 0x2001 + i); + } + for(unsigned i = 0; i < 0x400; i++) { + uint16_t value = snes.ppu->vram->_data[0x2000 * 2 + i * 2] | (snes.ppu->vram->_data[0x2000 * 2 + i * 2 + 1] << 8); + cr_assert_eq(value, (uint16_t)i, "The memory at %x should be %x but it was %x", 0x2000 + i, (uint16_t)i, value); + } +} + +Test(DMA, WRamToVRAM) +{ + Init() + for (unsigned i = 0; i < 0x400; i++) { + snes.wram->_data[i * 2] = i; + snes.wram->_data[i * 2 + 1] = i >> 8; + } + + // Transferring $800 bytes from WRAM ($00) to VRam ($2000) via DMA channel 0 + + // Setting VRam address (since this is an indirect write) + snes.bus->write(0x2115, 0b10000000); + snes.bus->write(0x2117, 0); + snes.bus->write(0x2116, 0); + + snes.bus->write(0x4301, 0x18); + cr_assert_eq(snes.cpu->_dmaChannels[0]._port, 0x18, "The dma's b port was $%x but it should have been $18.", snes.cpu->_dmaChannels[0]._port); + snes.bus->write(0x4304, 0x7E); + snes.bus->write(0x4303, 0x00); + snes.bus->write(0x4302, 0x00); + cr_assert_eq(snes.cpu->_dmaChannels[0]._aAddress.raw, 0x7E0000, "The dma's a address was $%x but it should have been $7E0000.", snes.cpu->_dmaChannels[0]._aAddress.raw); + snes.bus->write(0x4306, 0x08); + snes.bus->write(0x4305, 0); + cr_assert_eq(snes.cpu->_dmaChannels[0]._count.raw, 0x0800, "The dma's count was $%x but it should have been $0800.", snes.cpu->_dmaChannels[0]._count.raw); + snes.bus->write(0x4300, 1); + cr_assert_eq(snes.cpu->_dmaChannels[0]._controlRegister.direction, CPU::DMA::AtoB, "Direction should have been 0 (A to B) but it was %x.", snes.cpu->_dmaChannels[0]._controlRegister.direction); + cr_assert_eq(snes.cpu->_dmaChannels[0]._controlRegister._, 0, "The unused byte should be 0."); + cr_assert_eq(snes.cpu->_dmaChannels[0]._controlRegister.increment, 0, "The increment byte should be set to 0."); + cr_assert_eq(snes.cpu->_dmaChannels[0]._controlRegister.fixed, 0, "The increment byte should be set to 0."); + cr_assert_eq(snes.cpu->_dmaChannels[0]._controlRegister.mode, CPU::DMA::TwoToTwo, "The DMA mode should have been TwoToTwo (%%001) but it was) $%x", snes.cpu->_dmaChannels[0]._controlRegister.mode); + cr_assert_eq(snes.cpu->_dmaChannels[0].enabled, false, "The DMA channel should be disabled."); + // Enabling DMA's channel 0 + snes.bus->write(0x420B, 1); + cr_assert_eq(snes.cpu->_dmaChannels[0].enabled, true, "The DMA channel should be enabled."); + // TODO There is an overhead of 12-24 cycles for the whole transfer. How should I know how many cycles there is? + auto cycles = snes.cpu->_dmaChannels[0].run(1000000); + cr_assert_eq(cycles, 8 + 8 * 0x800, "The dma should take $4008 cycles but it took $%x.", cycles); + cr_assert_eq(snes.cpu->_dmaChannels[0]._count.raw, 0, "The dma count should be 0 but it was $%x.", snes.cpu->_dmaChannels[0]._count.raw); + cr_assert_eq(snes.cpu->_dmaChannels[0]._aAddress.raw, 0x7E0800, "The dma count should be $7E0800 but it was $%x.", snes.cpu->_dmaChannels[0]._aAddress.raw); + cr_assert_eq(snes.cpu->_dmaChannels[0]._port, 0x18, "The dma count should be $18 but it was $%x.", snes.cpu->_dmaChannels[0]._port); + cr_assert_eq(snes.ppu->_registers._vmadd.vmadd, 0x0400, "The vram address should be $400 but it was %x.", snes.ppu->_registers._vmadd.vmadd); + for(unsigned i = 0; i < 0x400; i++) { + uint16_t value = snes.ppu->vram->_data[i * 2] | (snes.ppu->vram->_data[i * 2 + 1] << 8); + cr_assert_eq(value, i, "The memory at %x should be %x but it was %x", i, i, snes.ppu->vram->_data[i]); + } + cr_assert_eq(snes.cpu->_dmaChannels[0].enabled, false, "The DMA channel should be disabled."); +} \ No newline at end of file diff --git a/tests/CPU/testInternal.cpp b/tests/CPU/testInternal.cpp index 63f6f5c..a85efbd 100644 --- a/tests/CPU/testInternal.cpp +++ b/tests/CPU/testInternal.cpp @@ -3,13 +3,8 @@ // #include -#include #include #include "../tests.hpp" -#include "../../sources/SNES.hpp" -#include "../../sources/Memory/MemoryBus.hpp" -#include "../../sources/CPU/CPU.hpp" - using namespace ComSquare; Test(SEP, setall) @@ -105,12 +100,24 @@ Test(PHA, basic) Init() snes.cpu->_registers.a = 0xABCD; snes.cpu->_registers.s = 0x02; + snes.cpu->_registers.p.m = false; snes.cpu->PHA(0x0, ComSquare::CPU::AddressingMode::Implied); cr_assert_eq(snes.wram->_data[1], 0xCD, "The second value pushed to the stack should be 0xCD but it was %x", snes.wram->_data[1]); cr_assert_eq(snes.wram->_data[2], 0xAB, "The first value pushed to the stack should be 0xAB but it was %x", snes.wram->_data[2]); cr_assert_eq(snes.cpu->_registers.s, 0x0, "The Stack pointer should be equal to 0x0 but it was %x", snes.cpu->_registers.s); } +Test(PHA, 8bits) +{ + Init() + snes.cpu->_registers.a = 0xCD; + snes.cpu->_registers.s = 0x02; + snes.cpu->_registers.p.m = false; + snes.cpu->PHA(0x0, ComSquare::CPU::AddressingMode::Implied); + cr_assert_eq(snes.wram->_data[1], 0xCD, "The second value pushed to the stack should be 0xCD but it was %x", snes.wram->_data[1]); + cr_assert_eq(snes.cpu->_registers.s, 0x0, "The Stack pointer should be equal to 0x0 but it was %x", snes.cpu->_registers.s); +} + Test(PHB, basic) { Init() @@ -184,8 +191,8 @@ Test(PLA, basic) snes.cpu->PLA(0x0, ComSquare::CPU::AddressingMode::Implied); auto data = snes.cpu->_registers.a; cr_assert_eq(data, 0x7BCD, "The accumulator should be 0x7BCD but it was %x", data); - cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should not be set.", snes.cpu->_registers.p.z); - cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flag should not be set.", snes.cpu->_registers.p.n); + cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should not be set."); + cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flag should not be set."); cr_assert_eq(snes.cpu->_registers.s, 0x2, "The Stack pointer should be equal to 0x2 but it was %x", snes.cpu->_registers.s); } @@ -199,8 +206,8 @@ Test(PLA, zero) snes.cpu->PLA(0x0, ComSquare::CPU::AddressingMode::Implied); auto data = snes.cpu->_registers.a; cr_assert_eq(data, 0x0000, "The accumulator should be 0x0000 but it was %x", data); - cr_assert_eq(snes.cpu->_registers.p.z, true, "The zero flag should be set.", snes.cpu->_registers.p.z); - cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flag should not be set.", snes.cpu->_registers.p.n); + cr_assert_eq(snes.cpu->_registers.p.z, true, "The zero flag should be set."); + cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flag should not be set."); cr_assert_eq(snes.cpu->_registers.s, 0x2, "The Stack pointer should be equal to 0x2 but it was %x", snes.cpu->_registers.s); } @@ -214,8 +221,8 @@ Test(PLA, negative) snes.cpu->PLA(0x0, ComSquare::CPU::AddressingMode::Implied); auto data = snes.cpu->_registers.a; cr_assert_eq(data, 0xA000, "The accumulator should be 0xA000 but it was %x", data); - cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag not should be set.", snes.cpu->_registers.p.z); - cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flag should be set.", snes.cpu->_registers.p.n); + cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag not should be set."); + cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flag should be set."); cr_assert_eq(snes.cpu->_registers.s, 0x2, "The Stack pointer should be equal to 0x2 but it was %x", snes.cpu->_registers.s); } @@ -229,8 +236,8 @@ Test(PLX, basic) snes.cpu->PLX(0x0, ComSquare::CPU::AddressingMode::Implied); auto data = snes.cpu->_registers.x; cr_assert_eq(data, 0x7BCD, "The X register should be 0x7BCD but it was %x", data); - cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should not be set.", snes.cpu->_registers.p.z); - cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flag should not be set.", snes.cpu->_registers.p.n); + cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should not be set."); + cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flag should not be set."); cr_assert_eq(snes.cpu->_registers.s, 0x2, "The Stack pointer should be equal to 0x2 but it was %x", snes.cpu->_registers.s); } @@ -244,8 +251,8 @@ Test(PLX, zero) snes.cpu->PLX(0x0, ComSquare::CPU::AddressingMode::Implied); auto data = snes.cpu->_registers.x; cr_assert_eq(data, 0x0000, "The x register should be 0x0000 but it was %x", data); - cr_assert_eq(snes.cpu->_registers.p.z, true, "The zero flag should be set.", snes.cpu->_registers.p.z); - cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flag should not be set.", snes.cpu->_registers.p.n); + cr_assert_eq(snes.cpu->_registers.p.z, true, "The zero flag should be set."); + cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flag should not be set."); cr_assert_eq(snes.cpu->_registers.s, 0x2, "The Stack pointer should be equal to 0x2 but it was %x", snes.cpu->_registers.s); } @@ -259,8 +266,8 @@ Test(PLX, negative) snes.cpu->PLX(0x0, ComSquare::CPU::AddressingMode::Implied); auto data = snes.cpu->_registers.x; cr_assert_eq(data, 0xA000, "The x register should be 0xA000 but it was %x", data); - cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag not should be set.", snes.cpu->_registers.p.z); - cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flag should be set.", snes.cpu->_registers.p.n); + cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag not should be set."); + cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flag should be set."); cr_assert_eq(snes.cpu->_registers.s, 0x2, "The Stack pointer should be equal to 0x2 but it was %x", snes.cpu->_registers.s); } @@ -274,8 +281,8 @@ Test(PLY, basic) snes.cpu->PLY(0x0, ComSquare::CPU::AddressingMode::Implied); auto data = snes.cpu->_registers.y; cr_assert_eq(data, 0x7BCD, "The Y register should be 0x7BCD but it was %x", data); - cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should not be set.", snes.cpu->_registers.p.z); - cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flag should not be set.", snes.cpu->_registers.p.n); + cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should not be set."); + cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flag should not be set."); cr_assert_eq(snes.cpu->_registers.s, 0x2, "The Stack pointer should be equal to 0x2 but it was %x", snes.cpu->_registers.s); } @@ -289,8 +296,8 @@ Test(PLY, zero) snes.cpu->PLY(0x0, ComSquare::CPU::AddressingMode::Implied); auto data = snes.cpu->_registers.y; cr_assert_eq(data, 0x0000, "The y register should be 0x0000 but it was %x", data); - cr_assert_eq(snes.cpu->_registers.p.z, true, "The zero flag should be set.", snes.cpu->_registers.p.z); - cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flag should not be set.", snes.cpu->_registers.p.n); + cr_assert_eq(snes.cpu->_registers.p.z, true, "The zero flag should be set."); + cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flag should not be set."); cr_assert_eq(snes.cpu->_registers.s, 0x2, "The Stack pointer should be equal to 0x2 but it was %x", snes.cpu->_registers.s); } @@ -304,8 +311,8 @@ Test(PLY, negative) snes.cpu->PLY(0x0, ComSquare::CPU::AddressingMode::Implied); auto data = snes.cpu->_registers.y; cr_assert_eq(data, 0xA000, "The y register should be 0xA000 but it was %x", data); - cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag not should be set.", snes.cpu->_registers.p.z); - cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flag should be set.", snes.cpu->_registers.p.n); + cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag not should be set."); + cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flag should be set."); cr_assert_eq(snes.cpu->_registers.s, 0x2, "The Stack pointer should be equal to 0x2 but it was %x", snes.cpu->_registers.s); } @@ -318,8 +325,8 @@ Test(PLD, basic) snes.cpu->PLD(0x0, ComSquare::CPU::AddressingMode::Implied); auto data = snes.cpu->_registers.d; cr_assert_eq(data, 0x7BCD, "The D register should be 0x7BCD but it was %x", data); - cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should not be set.", snes.cpu->_registers.p.z); - cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flag should not be set.", snes.cpu->_registers.p.n); + cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should not be set."); + cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flag should not be set."); cr_assert_eq(snes.cpu->_registers.s, 0x2, "The Stack pointer should be equal to 0x2 but it was %x", snes.cpu->_registers.s); } @@ -332,8 +339,8 @@ Test(PLD, zero) snes.cpu->PLD(0x0, ComSquare::CPU::AddressingMode::Implied); auto data = snes.cpu->_registers.d; cr_assert_eq(data, 0x0000, "The d register should be 0x0000 but it was %x", data); - cr_assert_eq(snes.cpu->_registers.p.z, true, "The zero flag should be set.", snes.cpu->_registers.p.z); - cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flag should not be set.", snes.cpu->_registers.p.n); + cr_assert_eq(snes.cpu->_registers.p.z, true, "The zero flag should be set."); + cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flag should not be set."); cr_assert_eq(snes.cpu->_registers.s, 0x2, "The Stack pointer should be equal to 0x2 but it was %x", snes.cpu->_registers.s); } @@ -346,8 +353,8 @@ Test(PLD, negative) snes.cpu->PLD(0x0, ComSquare::CPU::AddressingMode::Implied); auto data = snes.cpu->_registers.d; cr_assert_eq(data, 0xA000, "The D register should be 0xA000 but it was %x", data); - cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag not should be set.", snes.cpu->_registers.p.z); - cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flag should be set.", snes.cpu->_registers.p.n); + cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag not should be set."); + cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flag should be set."); cr_assert_eq(snes.cpu->_registers.s, 0x2, "The Stack pointer should be equal to 0x2 but it was %x", snes.cpu->_registers.s); } @@ -359,8 +366,8 @@ Test(PLB, basic) snes.cpu->PLB(0x0, ComSquare::CPU::AddressingMode::Implied); auto data = snes.cpu->_registers.dbr; cr_assert_eq(data, 0x7D, "The DBR should be 0x7D but it was %x", data); - cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should not be set.", snes.cpu->_registers.p.z); - cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flag should not be set.", snes.cpu->_registers.p.n); + cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag should not be set."); + cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flag should not be set."); cr_assert_eq(snes.cpu->_registers.s, 0x1, "The Stack pointer should be equal to 0x1 but it was %x", snes.cpu->_registers.s); } @@ -372,8 +379,8 @@ Test(PLB, zero) snes.cpu->PLB(0x0, ComSquare::CPU::AddressingMode::Implied); auto data = snes.cpu->_registers.dbr; cr_assert_eq(data, 0x00, "The dbr should be 0x00 but it was %x", data); - cr_assert_eq(snes.cpu->_registers.p.z, true, "The zero flag should be set.", snes.cpu->_registers.p.z); - cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flag should not be set.", snes.cpu->_registers.p.n); + cr_assert_eq(snes.cpu->_registers.p.z, true, "The zero flag should be set."); + cr_assert_eq(snes.cpu->_registers.p.n, false, "The negative flag should not be set."); cr_assert_eq(snes.cpu->_registers.s, 0x1, "The Stack pointer should be equal to 0x1 but it was %x", snes.cpu->_registers.s); } @@ -385,8 +392,8 @@ Test(PLB, negative) snes.cpu->PLB(0x0, ComSquare::CPU::AddressingMode::Implied); auto data = snes.cpu->_registers.dbr; cr_assert_eq(data, 0xA0, "The D register should be 0xA0 but it was %x", data); - cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag not should be set.", snes.cpu->_registers.p.z); - cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flag should be set.", snes.cpu->_registers.p.n); + cr_assert_eq(snes.cpu->_registers.p.z, false, "The zero flag not should be set."); + cr_assert_eq(snes.cpu->_registers.p.n, true, "The negative flag should be set."); cr_assert_eq(snes.cpu->_registers.s, 0x1, "The Stack pointer should be equal to 0x1 but it was %x", snes.cpu->_registers.s); } diff --git a/tests/PPU/testPpuWrite.cpp b/tests/PPU/testPpuWrite.cpp index 036d214..3e63c36 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) { Init() - snes._bus->write(0x2100, 0b11111111); + snes.bus->write(0x2100, 0b11111111); cr_assert_eq(snes.ppu->_registers._inidisp.fblank, true); cr_assert_eq(snes.ppu->_registers._inidisp.brightness, 0xF); } @@ -22,7 +22,7 @@ Test(PPU_write, inidisp_data_full_ones) Test(PPU_write, inidisp_data_full_zeros) { Init() - snes._bus->write(0x2100, 0b00000000); + snes.bus->write(0x2100, 0b00000000); cr_assert_eq(snes.ppu->_registers._inidisp.fblank, false); cr_assert_eq(snes.ppu->_registers._inidisp.brightness, 0x0); } @@ -30,7 +30,7 @@ Test(PPU_write, inidisp_data_full_zeros) Test(PPU_write, inidisp_data_fBlank_on_brghtness_off) { Init() - snes._bus->write(0x2100, 0b10000000); + snes.bus->write(0x2100, 0b10000000); cr_assert_eq(snes.ppu->_registers._inidisp.fblank, true); cr_assert_eq(snes.ppu->_registers._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) { Init() - snes._bus->write(0x2100, 0b00001111); + snes.bus->write(0x2100, 0b00001111); cr_assert_eq(snes.ppu->_registers._inidisp.fblank, false); cr_assert_eq(snes.ppu->_registers._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) { Init() - snes._bus->write(0x2100, 0b00000101); + snes.bus->write(0x2100, 0b00000101); cr_assert_eq(snes.ppu->_registers._inidisp.fblank, false); cr_assert_eq(snes.ppu->_registers._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) { Init() - snes._bus->write(0x2101, 0b11100000); + snes.bus->write(0x2101, 0b11100000); cr_assert_eq(snes.ppu->_registers._obsel.objectSize, 0b111); cr_assert_eq(snes.ppu->_registers._obsel.nameSelect, 0b00); cr_assert_eq(snes.ppu->_registers._obsel.nameBaseSelect, 0b000); @@ -63,7 +63,7 @@ Test(PPU_write, obsel_111_object_size_and_all_null) Test(PPU_write, obsel_data_full) { Init() - snes._bus->write(0x2101, 0b11111111); + snes.bus->write(0x2101, 0b11111111); cr_assert_eq(snes.ppu->_registers._obsel.objectSize, 0b111); cr_assert_eq(snes.ppu->_registers._obsel.nameSelect, 0b11); cr_assert_eq(snes.ppu->_registers._obsel.nameBaseSelect, 0b111); @@ -72,7 +72,7 @@ Test(PPU_write, obsel_data_full) Test(PPU_write, obsel_data_full_nameselect) { Init() - snes._bus->write(0x2101, 0b00011000); + snes.bus->write(0x2101, 0b00011000); cr_assert_eq(snes.ppu->_registers._obsel.objectSize, 0b000); cr_assert_eq(snes.ppu->_registers._obsel.nameSelect, 0b11); cr_assert_eq(snes.ppu->_registers._obsel.nameBaseSelect, 0b000); @@ -81,7 +81,7 @@ Test(PPU_write, obsel_data_full_nameselect) Test(PPU_write, obsel_data_full_baseselect) { Init() - snes._bus->write(0x2101, 0b00000111); + snes.bus->write(0x2101, 0b00000111); cr_assert_eq(snes.ppu->_registers._obsel.objectSize, 0b000); cr_assert_eq(snes.ppu->_registers._obsel.nameSelect, 0b00); cr_assert_eq(snes.ppu->_registers._obsel.nameBaseSelect, 0b111); @@ -90,14 +90,14 @@ Test(PPU_write, obsel_data_full_baseselect) Test(PPU_write, oamaddl_data_full) { Init() - snes._bus->write(0x2102, 0b11111111); + snes.bus->write(0x2102, 0b11111111); cr_assert_eq(snes.ppu->_registers._oamadd.oamAddress, 0b011111111); } Test(PPU_write, oamaddh_data_full) { Init() - snes._bus->write(0x2103, 0b11111111); + snes.bus->write(0x2103, 0b11111111); cr_assert_eq(snes.ppu->_registers._oamadd.objPriorityActivationBit, true); cr_assert_eq(snes.ppu->_registers._oamadd.oamAddress, 0b100000000); } @@ -105,8 +105,8 @@ Test(PPU_write, oamaddh_data_full) Test(PPU_write, oamaddlh_data_full) { Init() - snes._bus->write(0x2102, 0b11111111); - snes._bus->write(0x2103, 0b11111111); + snes.bus->write(0x2102, 0b11111111); + snes.bus->write(0x2103, 0b11111111); cr_assert_eq(snes.ppu->_registers._oamadd.objPriorityActivationBit, true); cr_assert_eq(snes.ppu->_registers._oamadd.oamAddress, 0b111111111); } @@ -114,8 +114,8 @@ Test(PPU_write, oamaddlh_data_full) Test(PPU_write, oamaddlh_data_full_priorityBit_off) { Init() - snes._bus->write(0x2102, 0b11111111); - snes._bus->write(0x2103, 0b01111111); + snes.bus->write(0x2102, 0b11111111); + snes.bus->write(0x2103, 0b01111111); cr_assert_eq(snes.ppu->_registers._oamadd.objPriorityActivationBit, false); cr_assert_eq(snes.ppu->_registers._oamadd.oamAddress, 0b111111111); } @@ -123,8 +123,8 @@ Test(PPU_write, oamaddlh_data_full_priorityBit_off) Test(PPU_write, oamaddlh_oamAdress_11_priorityBit_on) { Init() - snes._bus->write(0x2102, 0b00001011); - snes._bus->write(0x2103, 0b10011100); + snes.bus->write(0x2102, 0b00001011); + snes.bus->write(0x2103, 0b10011100); cr_assert_eq(snes.ppu->_registers._oamadd.objPriorityActivationBit, true); cr_assert_eq(snes.ppu->_registers._oamadd.oamAddress, 11); } @@ -132,7 +132,7 @@ Test(PPU_write, oamaddlh_oamAdress_11_priorityBit_on) Test(PPU_write, bgmode_data_full) { Init() - snes._bus->write(0x2105, 0b11111111); + snes.bus->write(0x2105, 0b11111111); cr_assert_eq(snes.ppu->_registers._bgmode.bgMode, 7); cr_assert_eq(snes.ppu->_registers._bgmode.characterSizeBg1, true); cr_assert_eq(snes.ppu->_registers._bgmode.characterSizeBg2, true); @@ -144,7 +144,7 @@ Test(PPU_write, bgmode_data_full) Test(PPU_write, bgmode_bgmode_5_and_bg24_on) { Init() - snes._bus->write(0x2105, 0b10100101); + snes.bus->write(0x2105, 0b10100101); cr_assert_eq(snes.ppu->_registers._bgmode.bgMode, 5); cr_assert_eq(snes.ppu->_registers._bgmode.characterSizeBg1, false); cr_assert_eq(snes.ppu->_registers._bgmode.characterSizeBg2, true); @@ -156,7 +156,7 @@ Test(PPU_write, bgmode_bgmode_5_and_bg24_on) Test(PPU_write, mosaic_data_full) { Init() - snes._bus->write(0x2106, 0b11111111); + snes.bus->write(0x2106, 0b11111111); cr_assert_eq(snes.ppu->_registers._mosaic.affectBg1, true); cr_assert_eq(snes.ppu->_registers._mosaic.affectBg2, true); cr_assert_eq(snes.ppu->_registers._mosaic.affectBg3, true); @@ -167,7 +167,7 @@ Test(PPU_write, mosaic_data_full) Test(PPU_write, mosaic_affectbg23_w_1x1_size) { Init() - snes._bus->write(0x2106, 0b00000110); + snes.bus->write(0x2106, 0b00000110); cr_assert_eq(snes.ppu->_registers._mosaic.affectBg1, false); cr_assert_eq(snes.ppu->_registers._mosaic.affectBg2, true); cr_assert_eq(snes.ppu->_registers._mosaic.affectBg3, true); @@ -178,7 +178,7 @@ Test(PPU_write, mosaic_affectbg23_w_1x1_size) Test(PPU_write, mosaic_affectbg14_w_2x2_size) { Init() - snes._bus->write(0x2106, 0b00101001); + snes.bus->write(0x2106, 0b00101001); cr_assert_eq(snes.ppu->_registers._mosaic.affectBg1, true); cr_assert_eq(snes.ppu->_registers._mosaic.affectBg2, false); cr_assert_eq(snes.ppu->_registers._mosaic.affectBg3, false); @@ -189,7 +189,7 @@ Test(PPU_write, mosaic_affectbg14_w_2x2_size) Test(PPU_write, bg1sc_data_full) { Init() - snes._bus->write(0x2107, 0b11111111); + snes.bus->write(0x2107, 0b11111111); cr_assert_eq(snes.ppu->_registers._bgsc[0].tilemapAddress, 0b111111); cr_assert_eq(snes.ppu->_registers._bgsc[0].tilemapHorizontalMirroring, true); cr_assert_eq(snes.ppu->_registers._bgsc[0].tilemapVerticalMirroring, true); @@ -198,7 +198,7 @@ Test(PPU_write, bg1sc_data_full) Test(PPU_write, bg2sc_data_full) { Init() - snes._bus->write(0x2108, 0b11111111); + snes.bus->write(0x2108, 0b11111111); cr_assert_eq(snes.ppu->_registers._bgsc[1].tilemapAddress, 0b111111); cr_assert_eq(snes.ppu->_registers._bgsc[1].tilemapHorizontalMirroring, true); cr_assert_eq(snes.ppu->_registers._bgsc[1].tilemapVerticalMirroring, true); @@ -207,7 +207,7 @@ Test(PPU_write, bg2sc_data_full) Test(PPU_write, bg3sc_data_full) { Init() - snes._bus->write(0x2109, 0b11111111); + snes.bus->write(0x2109, 0b11111111); cr_assert_eq(snes.ppu->_registers._bgsc[2].tilemapAddress, 0b111111); cr_assert_eq(snes.ppu->_registers._bgsc[2].tilemapHorizontalMirroring, true); cr_assert_eq(snes.ppu->_registers._bgsc[2].tilemapVerticalMirroring, true); @@ -216,7 +216,7 @@ Test(PPU_write, bg3sc_data_full) Test(PPU_write, bg4sc_data_full) { Init() - snes._bus->write(0x210A, 0b11111111); + snes.bus->write(0x210A, 0b11111111); cr_assert_eq(snes.ppu->_registers._bgsc[3].tilemapAddress, 0b111111); cr_assert_eq(snes.ppu->_registers._bgsc[3].tilemapHorizontalMirroring, true); cr_assert_eq(snes.ppu->_registers._bgsc[3].tilemapVerticalMirroring, true); @@ -225,7 +225,7 @@ Test(PPU_write, bg4sc_data_full) Test(PPU_write, bg4sc_data_null) { Init() - snes._bus->write(0x210A, 0b00000000); + snes.bus->write(0x210A, 0b00000000); cr_assert_eq(snes.ppu->_registers._bgsc[3].tilemapAddress, 0); cr_assert_eq(snes.ppu->_registers._bgsc[3].tilemapHorizontalMirroring, false); cr_assert_eq(snes.ppu->_registers._bgsc[3].tilemapVerticalMirroring, false); @@ -234,7 +234,7 @@ Test(PPU_write, bg4sc_data_null) Test(PPU_write, bg4sc_horizontal_off_vertical_on_random_tilemapAdress) { Init() - snes._bus->write(0x210A, 0b11000110); + snes.bus->write(0x210A, 0b11000110); cr_assert_eq(snes.ppu->_registers._bgsc[3].tilemapAddress, 0b110001); cr_assert_eq(snes.ppu->_registers._bgsc[3].tilemapHorizontalMirroring, false); cr_assert_eq(snes.ppu->_registers._bgsc[3].tilemapVerticalMirroring, true); @@ -243,7 +243,7 @@ Test(PPU_write, bg4sc_horizontal_off_vertical_on_random_tilemapAdress) Test(PPU_write, bg12nba_data_full) { Init() - snes._bus->write(0x210B, 0b11111111); + snes.bus->write(0x210B, 0b11111111); cr_assert_eq(snes.ppu->_registers._bgnba[0].baseAddressBg1a3, 0b1111); cr_assert_eq(snes.ppu->_registers._bgnba[0].baseAddressBg2a4, 0b1111); } @@ -251,7 +251,7 @@ Test(PPU_write, bg12nba_data_full) Test(PPU_write, bg34nba_data_full) { Init() - snes._bus->write(0x210C, 0b11111111); + snes.bus->write(0x210C, 0b11111111); cr_assert_eq(snes.ppu->_registers._bgnba[1].baseAddressBg1a3, 0b1111); cr_assert_eq(snes.ppu->_registers._bgnba[1].baseAddressBg2a4, 0b1111); } @@ -259,7 +259,7 @@ Test(PPU_write, bg34nba_data_full) Test(PPU_write, bg12nba_data_random_data) { Init() - snes._bus->write(0x210B, 0b10101010); + snes.bus->write(0x210B, 0b10101010); cr_assert_eq(snes.ppu->_registers._bgnba[0].baseAddressBg1a3, 0b1010); cr_assert_eq(snes.ppu->_registers._bgnba[0].baseAddressBg2a4, 0b1010); } \ No newline at end of file diff --git a/tests/PPU/testPpuWriteFromVmain.cpp b/tests/PPU/testPpuWriteFromVmain.cpp index df4f295..197aed0 100644 --- a/tests/PPU/testPpuWriteFromVmain.cpp +++ b/tests/PPU/testPpuWriteFromVmain.cpp @@ -14,7 +14,7 @@ using namespace ComSquare; Test(PPU_write_2, vmain_data_full) { Init() - snes._bus->write(0x2115, 0b11111111); + snes.bus->write(0x2115, 0b11111111); cr_assert_eq(snes.ppu->_registers._vmain.incrementMode, true); cr_assert_eq(snes.ppu->_registers._vmain.addressRemapping, 0b11); cr_assert_eq(snes.ppu->_registers._vmain.incrementAmount, 0b11); @@ -23,7 +23,7 @@ Test(PPU_write_2, vmain_data_full) Test(PPU_write_2, vmain_incrementmode_off_false_else_full) { Init() - snes._bus->write(0x2115, 0b01111111); + snes.bus->write(0x2115, 0b01111111); cr_assert_eq(snes.ppu->_registers._vmain.incrementMode, false); cr_assert_eq(snes.ppu->_registers._vmain.addressRemapping, 0b11); cr_assert_eq(snes.ppu->_registers._vmain.incrementAmount, 0b11); @@ -32,7 +32,7 @@ Test(PPU_write_2, vmain_incrementmode_off_false_else_full) Test(PPU_write_2, vmain_addressremaping_null_else_full) { Init() - snes._bus->write(0x2115, 0b11110011); + snes.bus->write(0x2115, 0b11110011); cr_assert_eq(snes.ppu->_registers._vmain.incrementMode, true); cr_assert_eq(snes.ppu->_registers._vmain.addressRemapping, 0b00); cr_assert_eq(snes.ppu->_registers._vmain.incrementAmount, 0b11); @@ -41,7 +41,7 @@ Test(PPU_write_2, vmain_addressremaping_null_else_full) Test(PPU_write_2, vmain_incrementamount_null_else_full) { Init() - snes._bus->write(0x2115, 0b11111100); + snes.bus->write(0x2115, 0b11111100); cr_assert_eq(snes.ppu->_registers._vmain.incrementMode, true); cr_assert_eq(snes.ppu->_registers._vmain.addressRemapping, 0b11); cr_assert_eq(snes.ppu->_registers._vmain.incrementAmount, 0b00); @@ -50,39 +50,39 @@ Test(PPU_write_2, vmain_incrementamount_null_else_full) Test(PPU_write_2, vmadd_full_data) { Init() - snes._bus->write(0x2116, 0b11111111); - snes._bus->write(0x2117, 0b11111111); + snes.bus->write(0x2116, 0b11111111); + snes.bus->write(0x2117, 0b11111111); cr_assert_eq(snes.ppu->_registers._vmadd.vmadd, 0b1111111111111111); } Test(PPU_write_2, vmadd_full_high_byte_null) { Init() - snes._bus->write(0x2116, 0b11111111); - snes._bus->write(0x2117, 0b00000000); + snes.bus->write(0x2116, 0b11111111); + snes.bus->write(0x2117, 0b00000000); cr_assert_eq(snes.ppu->_registers._vmadd.vmadd, 0b0000000011111111); } Test(PPU_write_2, vmdata_full_data) { Init() - snes._bus->write(0x2118, 0b11111111); - snes._bus->write(0x2119, 0b11111111); + snes.bus->write(0x2118, 0b11111111); + snes.bus->write(0x2119, 0b11111111); cr_assert_eq(snes.ppu->_registers._vmdata.vmdata, 0b1111111111111111); } Test(PPU_write_2, vmdata_full_high_byte_null) { Init() - snes._bus->write(0x2118, 0b11111111); - snes._bus->write(0x2119, 0b00000000); + snes.bus->write(0x2118, 0b11111111); + snes.bus->write(0x2119, 0b00000000); cr_assert_eq(snes.ppu->_registers._vmdata.vmdata, 0b0000000011111111); } Test(PPU_write_2, cgadd_full_high_byte_null) { Init() - snes._bus->write(0x2121, 0b11111111); + snes.bus->write(0x2121, 0b11111111); cr_assert_eq(snes.ppu->_registers._cgadd, 0b11111111); cr_assert_eq(snes.ppu->_registers._isLowByte, true); } @@ -90,12 +90,12 @@ Test(PPU_write_2, cgadd_full_high_byte_null) Test(PPU_write_2, cgdata_data_full) { Init() - snes._bus->write(0x2121, 0x0); - snes._bus->write(0x2122, 0b11111111); + snes.bus->write(0x2121, 0x0); + snes.bus->write(0x2122, 0b11111111); cr_assert_eq(snes.ppu->_registers._cgdata.cgdatal, 0b11111111); cr_assert_eq(snes.ppu->_registers._isLowByte, false); int address = snes.ppu->_registers._cgadd; - snes._bus->write(0x2122, 0b11111000); + snes.bus->write(0x2122, 0b11111000); cr_assert_eq(snes.ppu->_registers._cgdata.cgdatah, 0b11111000); cr_assert_eq(snes.ppu->_registers._isLowByte, true); cr_assert_eq(snes.ppu->_registers._cgadd, address + 2); @@ -104,7 +104,7 @@ Test(PPU_write_2, cgdata_data_full) Test(PPU_write_2, m7sel_data_full) { Init() - snes._bus->write(0x211A, 0b11111111); + snes.bus->write(0x211A, 0b11111111); cr_assert_eq(snes.ppu->_registers._m7sel.playingFieldSize, true); cr_assert_eq(snes.ppu->_registers._m7sel.emptySpaceFill, true); cr_assert_eq(snes.ppu->_registers._m7sel.horizontalMirroring, true); @@ -114,7 +114,7 @@ Test(PPU_write_2, m7sel_data_full) Test(PPU_write_2, m7sel_data_actual) { Init() - snes._bus->write(0x211A, 0b01111101); + snes.bus->write(0x211A, 0b01111101); cr_assert_eq(snes.ppu->_registers._m7sel.playingFieldSize, false); cr_assert_eq(snes.ppu->_registers._m7sel.emptySpaceFill, true); cr_assert_eq(snes.ppu->_registers._m7sel.horizontalMirroring, true); @@ -124,7 +124,7 @@ Test(PPU_write_2, m7sel_data_actual) Test(PPU_write_2, w12sel_data_full) { Init() - snes._bus->write(0x2123, 0b11111111); + snes.bus->write(0x2123, 0b11111111); cr_assert_eq(snes.ppu->_registers._wsel[0].window1InversionForBg1Bg2Obj, true); cr_assert_eq(snes.ppu->_registers._wsel[0].enableWindow1ForBg1Bg2Obj, true); cr_assert_eq(snes.ppu->_registers._wsel[0].window2InversionForBg1Bg3Obj, true); @@ -138,7 +138,7 @@ Test(PPU_write_2, w12sel_data_full) Test(PPU_write_2, w34sel_data_full) { Init() - snes._bus->write(0x2124, 0b10101010); + snes.bus->write(0x2124, 0b10101010); cr_assert_eq(snes.ppu->_registers._wsel[1].window1InversionForBg1Bg2Obj, true); cr_assert_eq(snes.ppu->_registers._wsel[1].enableWindow1ForBg1Bg2Obj, false); cr_assert_eq(snes.ppu->_registers._wsel[1].window2InversionForBg1Bg3Obj, true); @@ -152,7 +152,7 @@ Test(PPU_write_2, w34sel_data_full) Test(PPU_write_2, wobjsel_data_full) { Init() - snes._bus->write(0x2125, 0b10110001); + snes.bus->write(0x2125, 0b10110001); cr_assert_eq(snes.ppu->_registers._wsel[2].window1InversionForBg1Bg2Obj, true); cr_assert_eq(snes.ppu->_registers._wsel[2].enableWindow1ForBg1Bg2Obj, false); cr_assert_eq(snes.ppu->_registers._wsel[2].window2InversionForBg1Bg3Obj, true); @@ -166,7 +166,7 @@ Test(PPU_write_2, wobjsel_data_full) Test(PPU_write_2, wbglog_data_full) { Init() - snes._bus->write(0x212A, 0b10110001); + snes.bus->write(0x212A, 0b10110001); cr_assert_eq(snes.ppu->_registers._wbglog.maskLogicBg1, 0b10); cr_assert_eq(snes.ppu->_registers._wbglog.maskLogicBg2, 0b11); cr_assert_eq(snes.ppu->_registers._wbglog.maskLogicBg3, 0b00); @@ -176,7 +176,7 @@ Test(PPU_write_2, wbglog_data_full) Test(PPU_write_2, wobjlog_data_full) { Init() - snes._bus->write(0x212B, 0b10110001); + snes.bus->write(0x212B, 0b10110001); cr_assert_eq(snes.ppu->_registers._wobjlog.maskLogicObj, 0b01); cr_assert_eq(snes.ppu->_registers._wobjlog.maskLogicColor, 0b00); } @@ -184,7 +184,7 @@ Test(PPU_write_2, wobjlog_data_full) Test(PPU_write_2, tm_data_full) { Init() - snes._bus->write(0x212C, 0b10110001); + snes.bus->write(0x212C, 0b10110001); cr_assert_eq(snes.ppu->_registers._t[0].enableWindowDisplayBg1, true); cr_assert_eq(snes.ppu->_registers._t[0].enableWindowDisplayBg2, false); cr_assert_eq(snes.ppu->_registers._t[0].enableWindowDisplayBg3, false); @@ -195,7 +195,7 @@ Test(PPU_write_2, tm_data_full) Test(PPU_write_2, ts_data_full) { Init() - snes._bus->write(0x212D, 0b10101110); + snes.bus->write(0x212D, 0b10101110); cr_assert_eq(snes.ppu->_registers._t[1].enableWindowDisplayBg1, false); cr_assert_eq(snes.ppu->_registers._t[1].enableWindowDisplayBg2, true); cr_assert_eq(snes.ppu->_registers._t[1].enableWindowDisplayBg3, true); @@ -206,7 +206,7 @@ Test(PPU_write_2, ts_data_full) Test(PPU_write_2, tmw_data_full) { Init() - snes._bus->write(0x212E, 0b10101110); + snes.bus->write(0x212E, 0b10101110); cr_assert_eq(snes.ppu->_registers._tw[0].enableWindowMaskingBg1, false); cr_assert_eq(snes.ppu->_registers._tw[0].enableWindowMaskingBg2, true); cr_assert_eq(snes.ppu->_registers._tw[0].enableWindowMaskingBg3, true); @@ -217,7 +217,7 @@ Test(PPU_write_2, tmw_data_full) Test(PPU_write_2, tsw_data_full) { Init() - snes._bus->write(0x212F, 0b10100011); + snes.bus->write(0x212F, 0b10100011); cr_assert_eq(snes.ppu->_registers._tw[1].enableWindowMaskingBg1, true); cr_assert_eq(snes.ppu->_registers._tw[1].enableWindowMaskingBg2, true); cr_assert_eq(snes.ppu->_registers._tw[1].enableWindowMaskingBg3, false); @@ -228,7 +228,7 @@ Test(PPU_write_2, tsw_data_full) Test(PPU_write_2, cgwsel_data_full) { Init() - snes._bus->write(0x2130, 0b10111001); + snes.bus->write(0x2130, 0b10111001); cr_assert_eq(snes.ppu->_registers._cgwsel.clipColorToBlackBeforeMath, 0b10); cr_assert_eq(snes.ppu->_registers._cgwsel.preventColorMath, 0b11); cr_assert_eq(snes.ppu->_registers._cgwsel.addSubscreen, false); @@ -238,7 +238,7 @@ Test(PPU_write_2, cgwsel_data_full) Test(PPU_write_2, cgadsub_data_full) { Init() - snes._bus->write(0x2131, 0b10111001); + snes.bus->write(0x2131, 0b10111001); cr_assert_eq(snes.ppu->_registers._cgadsub.addSubtractSelect, true); cr_assert_eq(snes.ppu->_registers._cgadsub.halfColorMath, false); cr_assert_eq(snes.ppu->_registers._cgadsub.enableColorMathBackdrop, true); @@ -252,7 +252,7 @@ Test(PPU_write_2, cgadsub_data_full) Test(PPU_write_2, coldata_data_full) { Init() - snes._bus->write(0x2132, 0b10111001); + snes.bus->write(0x2132, 0b10111001); cr_assert_eq(snes.ppu->_registers._coldata.blue, true); cr_assert_eq(snes.ppu->_registers._coldata.green, false); cr_assert_eq(snes.ppu->_registers._coldata.red, true); @@ -262,7 +262,7 @@ Test(PPU_write_2, coldata_data_full) Test(PPU_write_2, setini_data_full) { Init() - snes._bus->write(0x2133, 0b10111001); + snes.bus->write(0x2133, 0b10111001); cr_assert_eq(snes.ppu->_registers._setini.externalSync, true); cr_assert_eq(snes.ppu->_registers._setini.mode7ExtBg, false); cr_assert_eq(snes.ppu->_registers._setini.enablePseudoHiresMode, true); @@ -274,14 +274,14 @@ Test(PPU_write_2, setini_data_full) Test(PPU_write_2, m7a_data_full) { Init() - snes._bus->write(0x211B, 0b10111001); + snes.bus->write(0x211B, 0b10111001); cr_assert_eq(snes.ppu->_registers._m7[0].m7l, 0b10111001); } Test(PPU_write_2, m7c_data_low_and_high_byte) { Init() - snes._bus->write(0x211D, 0b10111001); - snes._bus->write(0x211D, 0b11111111); + snes.bus->write(0x211D, 0b10111001); + snes.bus->write(0x211D, 0b11111111); cr_assert_eq(snes.ppu->_registers._m7[2].m7, 0b1011100111111111); } \ No newline at end of file diff --git a/tests/testMemoryBus.cpp b/tests/testMemoryBus.cpp index 81600be..cb8c9dc 100644 --- a/tests/testMemoryBus.cpp +++ b/tests/testMemoryBus.cpp @@ -6,13 +6,8 @@ #include #include #include "tests.hpp" -#include "../sources/Memory/MemoryBus.hpp" -#include "../sources/Memory/AMemory.hpp" -#include "../sources/SNES.hpp" -#include "../sources/Renderer/NoRenderer.hpp" #include "../sources/Memory/MemoryShadow.hpp" #include "../sources/Memory/RectangleShadow.hpp" -#include "../sources/PPU/PPU.hpp" #include "../sources/Exceptions/InvalidAction.hpp" @@ -27,27 +22,27 @@ using namespace ComSquare; Test(BusAccessor, GetWramStart) { Init() - std::shared_ptr accessor = nullptr; + std::shared_ptr accessor; - accessor = snes._bus->getAccessor(0x7E0000); + accessor = snes.bus->getAccessor(0x7E0000); cr_assert_eq(accessor.get(), snes.wram.get()); } Test(BusAccessor, GetWramEnd) { Init() - std::shared_ptr accessor = nullptr; + std::shared_ptr accessor; - accessor = snes._bus->getAccessor(0x7FFFFF); + accessor = snes.bus->getAccessor(0x7FFFFF); cr_assert_eq(accessor.get(), snes.wram.get()); } Test(BusAccessor, GetWramMirror) { Init() - std::shared_ptr accessor = nullptr; + std::shared_ptr accessor; - accessor = std::static_pointer_cast(snes._bus->getAccessor(0x2F11FF)); + accessor = std::static_pointer_cast(snes.bus->getAccessor(0x2F11FF)); cr_assert_neq(accessor, nullptr); cr_assert_eq(accessor->_initial.get(), snes.wram.get()); } @@ -55,9 +50,9 @@ Test(BusAccessor, GetWramMirror) Test(BusAccessor, GetWramMirror2) { Init() - std::shared_ptr accessor = nullptr; + std::shared_ptr accessor; - accessor = std::static_pointer_cast(snes._bus->getAccessor(0x100000)); + accessor = std::static_pointer_cast(snes.bus->getAccessor(0x100000)); cr_assert_neq(accessor, nullptr); cr_assert_eq(accessor->_initial.get(), snes.wram.get()); } @@ -65,9 +60,9 @@ Test(BusAccessor, GetWramMirror2) Test(BusAccessor, GetWramMirror3) { Init() - std::shared_ptr accessor = nullptr; + std::shared_ptr accessor; - accessor = std::static_pointer_cast(snes._bus->getAccessor(0x1010)); + accessor = std::static_pointer_cast(snes.bus->getAccessor(0x1010)); cr_assert_neq(accessor, nullptr); cr_assert_eq(accessor->_initial.get(), snes.wram.get()); } @@ -75,187 +70,187 @@ Test(BusAccessor, GetWramMirror3) Test(BusAccessor, GetOpenBus) { Init() - std::shared_ptr accessor = snes._bus->getAccessor(0x897654); + std::shared_ptr accessor = snes.bus->getAccessor(0x897654); cr_assert_eq(accessor.get(), nullptr); } Test(BusAccessor, GetSramStart) { Init() - std::shared_ptr accessor = nullptr; + std::shared_ptr accessor; - accessor = std::static_pointer_cast(snes._bus->getAccessor(0x700000)); + accessor = std::static_pointer_cast(snes.bus->getAccessor(0x700000)); cr_assert_eq(accessor->_initial.get(), snes.sram.get()); } Test(BusAccessor, GetSramEnd) { Init() - std::shared_ptr accessor = nullptr; + std::shared_ptr accessor; - accessor = std::static_pointer_cast(snes._bus->getAccessor(0x7D7FFF)); + accessor = std::static_pointer_cast(snes.bus->getAccessor(0x7D7FFF)); cr_assert_eq(accessor->_initial.get(), snes.sram.get()); } Test(BusAccessor, GetSramMirror) { Init() - std::shared_ptr accessor = nullptr; + std::shared_ptr accessor; - accessor = std::static_pointer_cast(snes._bus->getAccessor(0xF00123)); + accessor = std::static_pointer_cast(snes.bus->getAccessor(0xF00123)); cr_assert_eq(accessor.get(), snes.sram.get()); } Test(BusAccessor, GetAPUStart) { Init() - std::shared_ptr accessor = nullptr; + std::shared_ptr accessor; - accessor = snes._bus->getAccessor(0x002140); + accessor = snes.bus->getAccessor(0x002140); cr_assert_eq(accessor.get(), snes.apu.get()); } Test(BusAccessor, GetAPUEnd) { Init() - std::shared_ptr accessor = nullptr; + std::shared_ptr accessor; - accessor = snes._bus->getAccessor(0x002143); + accessor = snes.bus->getAccessor(0x002143); cr_assert_eq(accessor.get(), snes.apu.get()); } Test(BusAccessor, GetAPUMirror) { Init() - std::shared_ptr accessor = nullptr; + std::shared_ptr accessor; - accessor = std::static_pointer_cast(snes._bus->getAccessor(0xAB2143)); + accessor = std::static_pointer_cast(snes.bus->getAccessor(0xAB2143)); cr_assert_eq(accessor->_initial.get(), snes.apu.get()); } Test(BusAccessor, GetAPUMirrorFirstHalf) { Init() - std::shared_ptr accessor = nullptr; + std::shared_ptr accessor; - accessor = std::static_pointer_cast(snes._bus->getAccessor(0x052143)); + accessor = std::static_pointer_cast(snes.bus->getAccessor(0x052143)); cr_assert_eq(accessor->_initial.get(), snes.apu.get()); } Test(BusAccessor, GetCPUStart) { Init() - std::shared_ptr accessor = nullptr; + std::shared_ptr accessor; - accessor = snes._bus->getAccessor(0x004200); + accessor = snes.bus->getAccessor(0x004200); cr_assert_eq(accessor.get(), snes.cpu.get()); } Test(BusAccessor, GetCPUEnd) { Init() - std::shared_ptr accessor = nullptr; + std::shared_ptr accessor; - accessor = snes._bus->getAccessor(0x00421F); + accessor = snes.bus->getAccessor(0x00421F); cr_assert_eq(accessor.get(), snes.cpu.get()); } Test(BusAccessor, GetPPU1Start) { Init() - std::shared_ptr accessor = nullptr; + std::shared_ptr accessor; - accessor = snes._bus->getAccessor(0x00213E); + accessor = snes.bus->getAccessor(0x00213E); cr_assert_eq(accessor.get(), snes.ppu.get()); } Test(BusAccessor, GetPPU1End) { Init() - std::shared_ptr accessor = nullptr; + std::shared_ptr accessor; - accessor = snes._bus->getAccessor(0x00213F); + accessor = snes.bus->getAccessor(0x00213F); cr_assert_eq(accessor.get(), snes.ppu.get()); } Test(BusAccessor, GetCPU) { Init() - std::shared_ptr accessor = nullptr; + std::shared_ptr accessor; - accessor = snes._bus->getAccessor(0x004212); + accessor = snes.bus->getAccessor(0x004212); cr_assert_eq(accessor.get(), snes.cpu.get()); } Test(BusAccessor, GetPPU1Mirror) { Init() - std::shared_ptr accessor = nullptr; + std::shared_ptr accessor; - accessor = std::static_pointer_cast(snes._bus->getAccessor(0x80213F)); + accessor = std::static_pointer_cast(snes.bus->getAccessor(0x80213F)); cr_assert_eq(accessor->_initial.get(), snes.ppu.get()); } Test(BusAccessor, GetCPU2Mirror) { Init() - std::shared_ptr accessor = nullptr; + std::shared_ptr accessor; - accessor = std::static_pointer_cast(snes._bus->getAccessor(0x804212)); + accessor = std::static_pointer_cast(snes.bus->getAccessor(0x804212)); cr_assert_eq(accessor->_initial.get(), snes.cpu.get()); } Test(BusAccessor, GetRomStart) { Init() - std::shared_ptr accessor = nullptr; + std::shared_ptr accessor; - accessor = snes._bus->getAccessor(0x808000); + accessor = snes.bus->getAccessor(0x808000); cr_assert_eq(accessor.get(), snes.cartridge.get()); } Test(BusAccessor, GetRomEnd) { Init() - std::shared_ptr accessor = nullptr; + std::shared_ptr accessor; - accessor = snes._bus->getAccessor(0xFFFFFF); + accessor = snes.bus->getAccessor(0xFFFFFF); cr_assert_eq(accessor.get(), snes.cartridge.get()); } Test(BusAccessor, GetRomMirror) { Init() - std::shared_ptr accessor = nullptr; + std::shared_ptr accessor; - accessor = std::static_pointer_cast(snes._bus->getAccessor(0x694200)); + accessor = std::static_pointer_cast(snes.bus->getAccessor(0x694200)); cr_assert_eq(accessor->_initial.get(), snes.cartridge.get()); } Test(BusAccessor, GetRomMirror2) { Init() - std::shared_ptr accessor = nullptr; + std::shared_ptr accessor; - accessor = std::static_pointer_cast(snes._bus->getAccessor(0x01FEDC)); + accessor = std::static_pointer_cast(snes.bus->getAccessor(0x01FEDC)); cr_assert_eq(accessor->_initial.get(), snes.cartridge.get()); } Test(BusAccessor, GetRomMirror3) { Init() - std::shared_ptr accessor = nullptr; + std::shared_ptr accessor; - accessor = std::static_pointer_cast(snes._bus->getAccessor(0xDE1248)); + accessor = std::static_pointer_cast(snes.bus->getAccessor(0xDE1248)); cr_assert_eq(accessor->_initial.get(), snes.cartridge.get()); } Test(BusAccessor, Get0x0) { Init() - std::shared_ptr accessor = nullptr; + std::shared_ptr accessor; - accessor = std::static_pointer_cast(snes._bus->getAccessor(0x0)); + accessor = std::static_pointer_cast(snes.bus->getAccessor(0x0)); cr_assert_eq(accessor->_initial.get(), snes.wram.get()); } @@ -271,7 +266,7 @@ Test(BusRead, Read0x0) uint8_t data; snes.wram->_data[0] = 123; - data = snes._bus->read(0x0); + data = snes.bus->read(0x0); cr_assert_eq(data, 123); } @@ -280,8 +275,8 @@ Test(BusRead, ReadOutside, .init = cr_redirect_stdout) Init() uint8_t data; - snes._bus->_openBus = 123; - data = snes._bus->read(0x002000); + snes.bus->_openBus = 123; + data = snes.bus->read(0x002000); cr_assert_eq(data, 123); } @@ -290,8 +285,8 @@ Test(BusRead, ReadOutside2, .init = cr_redirect_stdout) Init() uint8_t data; - snes._bus->_openBus = 123; - data = snes._bus->read(0xBF2FFF); + snes.bus->_openBus = 123; + data = snes.bus->read(0xBF2FFF); cr_assert_eq(data, 123); } @@ -300,8 +295,8 @@ Test(BusRead, ReadOutside3, .init = cr_redirect_stdout) Init() uint8_t data; - snes._bus->_openBus = 123; - data = snes._bus->read(0x127654); + snes.bus->_openBus = 123; + data = snes.bus->read(0x127654); cr_assert_eq(data, 123); } @@ -311,7 +306,7 @@ Test(BusRead, ReadAPU) uint8_t data; snes.apu->_registers.port0 = 123; - data = snes._bus->read(0x002140); + data = snes.bus->read(0x002140); cr_assert_eq(data, 123); } @@ -321,7 +316,7 @@ Test(BusRead, ReadROM) uint8_t data; snes.cartridge->_data[5] = 123; - data = snes._bus->read(0x808005); + data = snes.bus->read(0x808005); cr_assert_eq(data, 123); } @@ -331,7 +326,7 @@ Test(BusRead, ReadROMStart) uint8_t data; snes.cartridge->_data[0] = 123; - data = snes._bus->read(0x808000); + data = snes.bus->read(0x808000); cr_assert_eq(data, 123); } @@ -341,7 +336,7 @@ Test(BusRead, ReadCPU) uint8_t data; snes.cpu->_internalRegisters.wrio = 123; - data = snes._bus->read(0x004201); + data = snes.bus->read(0x004201); cr_assert_eq(data, 123); } @@ -351,7 +346,7 @@ Test(BusRead, ReadPPU) uint8_t data; snes.ppu->_registers._mpy.mpyl = 123; - data = snes._bus->read(0x002134); + data = snes.bus->read(0x002134); cr_assert_eq(data, 123); } @@ -361,7 +356,7 @@ Test(BusRead, ReadSRAM) uint8_t data; snes.sram->_data[7] = 123; - data = snes._bus->read(0x700007); + data = snes.bus->read(0x700007); cr_assert_eq(data, 123); } @@ -371,7 +366,7 @@ Test(BusRead, ReadWRAM) uint8_t data; snes.wram->_data[3] = 123; - data = snes._bus->read(0x7E0003); + data = snes.bus->read(0x7E0003); cr_assert_eq(data, 123); } @@ -381,7 +376,7 @@ Test(BusRead, ReadWRAM2) uint8_t data; snes.wram->_data[0x1010] = 123; - data = snes._bus->read(0x7E1010); + data = snes.bus->read(0x7E1010); cr_assert_eq(data, 123); } @@ -392,7 +387,7 @@ Test(BusRead, ReadWRAMMirror) uint8_t data; snes.wram->_data[0x1010] = 123; - data = snes._bus->read(0x1010); + data = snes.bus->read(0x1010); cr_assert_eq(data, 123); } @@ -407,7 +402,7 @@ Test(BusWrite, Write0x0) Init() try { - snes._bus->write(0x0, 123); + snes.bus->write(0x0, 123); } catch (std::exception &ex) { std::cout << ex.what() << std::endl; } @@ -419,7 +414,7 @@ Test(BusWrite, WriteAPU) { Init() - snes._bus->write(0x002143, 123); + snes.bus->write(0x002143, 123); cr_assert_eq(snes.apu->_registers.port3, 123); } @@ -427,7 +422,7 @@ Test(BusWrite, WritePPU) { Init() - snes._bus->write(0x002106, 123); + snes.bus->write(0x002106, 123); cr_assert_eq(snes.ppu->_registers._mosaic.raw, 123); } @@ -435,7 +430,7 @@ Test(BusWrite, WriteCPU) { Init() - snes._bus->write(0x00420D, 123); + snes.bus->write(0x00420D, 123); cr_assert_eq(snes.cpu->_internalRegisters.memsel, 123); } @@ -443,14 +438,14 @@ Test(BusWrite, WriteROM) { Init() - cr_assert_throw(snes._bus->write(0x808005, 123), InvalidAction); + cr_assert_throw(snes.bus->write(0x808005, 123), InvalidAction); } Test(BusWrite, WriteWRAM) { Init() - snes._bus->write(0x7E0002, 123); + snes.bus->write(0x7E0002, 123); cr_assert_eq(snes.wram->_data[2], 123); } @@ -458,6 +453,6 @@ Test(BusWrite, WriteSRAM) { Init() - snes._bus->write(0x700009, 123); + snes.bus->write(0x700009, 123); cr_assert_eq(snes.sram->_data[9], 123); } \ No newline at end of file diff --git a/tests/testRectangleMemory.cpp b/tests/testRectangleMemory.cpp index 71edf33..69baaab 100644 --- a/tests/testRectangleMemory.cpp +++ b/tests/testRectangleMemory.cpp @@ -5,30 +5,28 @@ #include #include #include "tests.hpp" -#include "../sources/SNES.hpp" -#include "../sources/Renderer/NoRenderer.hpp" -#include "../sources/PPU/PPU.hpp" #include "../sources/Memory/RectangleShadow.hpp" -#include "../sources/Utility/Utility.hpp" using namespace ComSquare; Test(RectangleMemory, HorizontalRamRead) { Ram::Ram ram(0xFF, Component::Rom, "Rom"); - ram.setMemoryRegion(0x00, 0xFF, 0x0000, 0x0001); + ram.setMemoryRegion(0x00, 0xFF, 0x0000, 0x0000); for (int i = 0x00; i < 0xFF; i++) ram._data[i] = i; - for (uint24_t i = 0x000000; i < 0xFF0000; i += 0x010000) - cr_assert_eq(ram.read(i), i >> 16u, "The ram's read returned 0x%x but the internal ram value was: 0x%x (addr: 0x%06x)", ram.read(i), i >> 16, i); + for (uint24_t i = 0x000000; i < 0xFF0000; i += 0x010000) { + uint8_t value = ram.read(ram.getRelativeAddress(i)); + cr_assert_eq(value, i >> 16u, "The ram's read returned 0x%x but the internal ram value was: 0x%x (addr: 0x%06x)", value, i >> 16, i); + } } Test(RectangleMemory, HorizontalRamWrite) { Ram::Ram ram(0xFF, Component::Rom, "Rom"); - ram.setMemoryRegion(0x00, 0xFF, 0x0000, 0x0001); + ram.setMemoryRegion(0x00, 0xFF, 0x0000, 0x0000); for (uint24_t i = 0x000000; i < 0xFF0000; i += 0x010000) - ram.write(i, i >> 16u); + ram.write(ram.getRelativeAddress(i), i >> 16u); for (int i = 0x00; i < 0xFF; i++) cr_assert_eq(ram._data[i], i, "The ram's write put 0x%x but it should had put: 0x%x (addr: 0x%06x)", ram._data[i], i, i << 16u); } @@ -36,37 +34,39 @@ Test(RectangleMemory, HorizontalRamWrite) Test(RectangleMemory, DualLineRamRead) { Ram::Ram ram(0xFF * 2, Component::Rom, "Rom"); - ram.setMemoryRegion(0x00, 0xFF, 0x0000, 0x0002); + ram.setMemoryRegion(0x00, 0xFF, 0x0000, 0x0001); for (int i = 0x00; i < 0xFF * 2; i++) ram._data[i] = i; for (uint24_t i = 0x000000, v = 0; v < 0xFF * 2; i += 0x010000, v += 2) { - cr_assert_eq(ram.read(i), (uint8_t)(v), "The ram's read returned 0x%x but the internal ram value was: 0x%x (addr: 0x%06x)", ram.read(i), (uint8_t)(v), i); - cr_assert_eq(ram.read(i + 1), (uint8_t)(v + 1), "The ram's read returned 0x%x but the internal ram value was: 0x%x (addr: 0x%06x)", ram.read(i + 1), (uint8_t)(v + 1), i + 1); + uint8_t value = ram.read(ram.getRelativeAddress(i)); + cr_assert_eq(value, (uint8_t)(v), "The ram's read returned 0x%x but the internal ram value was: 0x%x (addr: 0x%06x)", value, (uint8_t)(v), i); + value = ram.read(ram.getRelativeAddress(i + 1)); + cr_assert_eq(value, (uint8_t)(v + 1), "The ram's read returned 0x%x but the internal ram value was: 0x%x (addr: 0x%06x)", value, (uint8_t)(v + 1), i + 1); } } Test(RectangleMemory, HorizontalRamShadowRead) { std::shared_ptr ram = std::make_shared(0xFF, Component::Rom, "Rom"); - ram->setMemoryRegion(0x00, 0xFF, 0x0000, 0x0001); - Memory::RectangleShadow shadow(ram, 0x00, 0xFF, 0x8000, 0x8001); + ram->setMemoryRegion(0x00, 0xFF, 0x0000, 0x0000); + Memory::RectangleShadow shadow(ram, 0x00, 0xFF, 0x8000, 0x8000); for (int i = 0x00; i < 0xFF; i++) ram->_data[i] = i; for (uint24_t i = 0x008000; i < 0xFF8000; i += 0x010000) { - uint8_t v = shadow.read(i - shadow.getStart()); + uint8_t v = shadow.read(shadow.getRelativeAddress(i)); cr_assert_eq(v, i >> 16u, "The ram's read returned 0x%x but the internal ram value was: 0x%x (addr: 0x%06x)", v, i >> 16, i); }} Test(RectangleMemory, HorizontalRamShadowReadWithBankOffset) { std::shared_ptr ram = std::make_shared(0xFF, Component::Rom, "Rom"); - ram->setMemoryRegion(0x00, 0xFF, 0x0000, 0x0001); - Memory::RectangleShadow shadow(ram, 0x80, 0xFF, 0x8000, 0x8001); + ram->setMemoryRegion(0x00, 0xFF, 0x0000, 0x0000); + Memory::RectangleShadow shadow(ram, 0x80, 0xFF, 0x8000, 0x8000); for (int i = 0x00; i < 0xFF; i++) ram->_data[i] = i; shadow.setBankOffset(0x80); for (uint24_t i = 0x808000; i < 0xFF8000; i += 0x010000) { - uint8_t v = shadow.read(i - shadow.getStart()); + uint8_t v = shadow.read(shadow.getRelativeAddress(i)); cr_assert_eq(v, i >> 16u, "The ram's read returned 0x%x but the internal ram value was: 0x%x (addr: 0x%06x)", v, i >> 16, i); } } @@ -79,11 +79,11 @@ Test(RectangleMemory, ShadowOffsetCartridge) for (int i = 0x00; i < 0x3fff80; i++) ram->_data[i] = i; shadow.setBankOffset(0x40); - for (uint24_t i = 0xC00000; i < 0xEF7FFF; i += 0x1) { + for (uint24_t i = 0xC00000; i <= 0xEF7FFF; i += 0x1) { if ((uint16_t)i > 0x7FFFu) i += 0x010000 - 0x8000; - uint8_t v = shadow.read(i - shadow.getStart()); - uint8_t r = ram->read(i + 0x8000 - ram->getStart()); + uint8_t v = shadow.read(shadow.getRelativeAddress(i)); + uint8_t r = ram->read(ram->getRelativeAddress(i + 0x8000)); cr_assert_eq(v, r, "The ram's read returned 0x%x but the internal ram value was: 0x%x (addr: 0x%06x)", v, r, i); } } \ No newline at end of file diff --git a/ui/cpu.ui b/ui/cpuView.ui similarity index 100% rename from ui/cpu.ui rename to ui/cpuView.ui diff --git a/ui/registersView.ui b/ui/registersView.ui new file mode 100644 index 0000000..4dd129a --- /dev/null +++ b/ui/registersView.ui @@ -0,0 +1,159 @@ + + + RegistersView + + + + 0 + 0 + 431 + 646 + + + + Registers's Debugger + + + + :/resources/Logo.png:/resources/Logo.png + + + + + + + 0 + + + false + + + false + + + true + + + + CPU + + + + + + + + + + DMA + + + + + + 0 + + + + 1 + + + + + + + + + + 2 + + + + + + + + + + 3 + + + + + + + + + + 4 + + + + + + + + + + 5 + + + + + + + + + + 6 + + + + + + + + + + 7 + + + + + + + + + + 8 + + + + + + + + + + + + + + PPU + + + + + + + + + + + + + + + + + diff --git a/ui/ui_cpu.h b/ui/ui_cpu.h deleted file mode 100644 index 35c8512..0000000 --- a/ui/ui_cpu.h +++ /dev/null @@ -1,457 +0,0 @@ -/******************************************************************************** -** Form generated from reading UI file 'cpu.ui' -** -** Created by: Qt User Interface Compiler version 5.15.2 -** -** WARNING! All changes made in this file will be lost when recompiling UI file! -********************************************************************************/ - -#ifndef UI_CPU_H -#define UI_CPU_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -QT_BEGIN_NAMESPACE - -class Ui_CPUView -{ -public: - QAction *actionPause; - QAction *actionStep; - QAction *actionNext; - QWidget *centralwidget; - QGridLayout *gridLayout_3; - QTableView *disassembly; - QGridLayout *gridLayout_2; - QTableView *stackView; - QLabel *label; - QFormLayout *formLayout; - QLabel *accumulatorLabel; - QLineEdit *accumulatorLineEdit; - QLabel *programBankRegisterLabel; - QLineEdit *programBankRegisterLineEdit; - QLabel *programCounterLabel; - QLineEdit *programCounterLineEdit; - QLabel *directBankLabel; - QLineEdit *directBankLineEdit; - QLabel *directPageLabel; - QLineEdit *directPageLineEdit; - QLabel *stackPointerLabel; - QLineEdit *stackPointerLineEdit; - QLabel *xIndexLabel; - QLineEdit *xIndexLineEdit; - QLabel *yIndexLabel; - QLineEdit *yIndexLineEdit; - QLabel *emulationModeLabel; - QCheckBox *emulationModeCheckBox; - QGridLayout *gridLayout; - QLabel *loggerLabel; - QPushButton *clear; - QTableView *history; - QGroupBox *formGroupBox; - QFormLayout *formLayout_2; - QLabel *negativeLabel; - QCheckBox *mCheckbox; - QLabel *zeroLabel; - QCheckBox *xCheckbox; - QLabel *carryLabel; - QCheckBox *iCheckbox; - QLabel *Overflow; - QCheckBox *vCheckbox; - QLabel *decimalLabel; - QCheckBox *dCheckbox; - QLabel *memoryAccumulatorSelectLabel; - QCheckBox *cCheckbox; - QLabel *indeXSelectLabel; - QLabel *irqDisableLabel; - QCheckBox *nCheckbox; - QCheckBox *zCheckbox; - QLabel *breakBLabel; - QCheckBox *bCheckbox; - QToolBar *toolBar; - - void setupUi(QMainWindow *CPUView) - { - if (CPUView->objectName().isEmpty()) - CPUView->setObjectName(QString::fromUtf8("CPUView")); - CPUView->resize(1058, 673); - QIcon icon; - icon.addFile(QString::fromUtf8(":/resources/Logo.png"), QSize(), QIcon::Normal, QIcon::Off); - CPUView->setWindowIcon(icon); - CPUView->setAutoFillBackground(false); - actionPause = new QAction(CPUView); - actionPause->setObjectName(QString::fromUtf8("actionPause")); - QIcon icon1; - icon1.addFile(QString::fromUtf8(":/resources/icons/play.svg"), QSize(), QIcon::Normal, QIcon::Off); - actionPause->setIcon(icon1); - actionStep = new QAction(CPUView); - actionStep->setObjectName(QString::fromUtf8("actionStep")); - QIcon icon2; - icon2.addFile(QString::fromUtf8(":/resources/icons/step.svg"), QSize(), QIcon::Normal, QIcon::Off); - actionStep->setIcon(icon2); - actionNext = new QAction(CPUView); - actionNext->setObjectName(QString::fromUtf8("actionNext")); - QIcon icon3; - icon3.addFile(QString::fromUtf8(":/resources/icons/continue.svg"), QSize(), QIcon::Normal, QIcon::Off); - actionNext->setIcon(icon3); - centralwidget = new QWidget(CPUView); - centralwidget->setObjectName(QString::fromUtf8("centralwidget")); - gridLayout_3 = new QGridLayout(centralwidget); - gridLayout_3->setObjectName(QString::fromUtf8("gridLayout_3")); - disassembly = new QTableView(centralwidget); - disassembly->setObjectName(QString::fromUtf8("disassembly")); - QSizePolicy sizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); - sizePolicy.setHorizontalStretch(1); - sizePolicy.setVerticalStretch(0); - sizePolicy.setHeightForWidth(disassembly->sizePolicy().hasHeightForWidth()); - disassembly->setSizePolicy(sizePolicy); - disassembly->setStyleSheet(QString::fromUtf8("")); - disassembly->setSelectionMode(QAbstractItemView::ExtendedSelection); - disassembly->setSelectionBehavior(QAbstractItemView::SelectRows); - disassembly->setShowGrid(false); - disassembly->setGridStyle(Qt::NoPen); - disassembly->horizontalHeader()->setVisible(false); - disassembly->horizontalHeader()->setHighlightSections(false); - - gridLayout_3->addWidget(disassembly, 0, 0, 3, 1); - - gridLayout_2 = new QGridLayout(); - gridLayout_2->setObjectName(QString::fromUtf8("gridLayout_2")); - stackView = new QTableView(centralwidget); - stackView->setObjectName(QString::fromUtf8("stackView")); - stackView->horizontalHeader()->setVisible(false); - - gridLayout_2->addWidget(stackView, 1, 0, 1, 1); - - label = new QLabel(centralwidget); - label->setObjectName(QString::fromUtf8("label")); - label->setAlignment(Qt::AlignCenter); - - gridLayout_2->addWidget(label, 0, 0, 1, 1); - - - gridLayout_3->addLayout(gridLayout_2, 0, 1, 1, 1); - - formLayout = new QFormLayout(); - formLayout->setObjectName(QString::fromUtf8("formLayout")); - accumulatorLabel = new QLabel(centralwidget); - accumulatorLabel->setObjectName(QString::fromUtf8("accumulatorLabel")); - - formLayout->setWidget(0, QFormLayout::LabelRole, accumulatorLabel); - - accumulatorLineEdit = new QLineEdit(centralwidget); - accumulatorLineEdit->setObjectName(QString::fromUtf8("accumulatorLineEdit")); - - formLayout->setWidget(0, QFormLayout::FieldRole, accumulatorLineEdit); - - programBankRegisterLabel = new QLabel(centralwidget); - programBankRegisterLabel->setObjectName(QString::fromUtf8("programBankRegisterLabel")); - - formLayout->setWidget(1, QFormLayout::LabelRole, programBankRegisterLabel); - - programBankRegisterLineEdit = new QLineEdit(centralwidget); - programBankRegisterLineEdit->setObjectName(QString::fromUtf8("programBankRegisterLineEdit")); - - formLayout->setWidget(1, QFormLayout::FieldRole, programBankRegisterLineEdit); - - programCounterLabel = new QLabel(centralwidget); - programCounterLabel->setObjectName(QString::fromUtf8("programCounterLabel")); - - formLayout->setWidget(2, QFormLayout::LabelRole, programCounterLabel); - - programCounterLineEdit = new QLineEdit(centralwidget); - programCounterLineEdit->setObjectName(QString::fromUtf8("programCounterLineEdit")); - - formLayout->setWidget(2, QFormLayout::FieldRole, programCounterLineEdit); - - directBankLabel = new QLabel(centralwidget); - directBankLabel->setObjectName(QString::fromUtf8("directBankLabel")); - - formLayout->setWidget(3, QFormLayout::LabelRole, directBankLabel); - - directBankLineEdit = new QLineEdit(centralwidget); - directBankLineEdit->setObjectName(QString::fromUtf8("directBankLineEdit")); - - formLayout->setWidget(3, QFormLayout::FieldRole, directBankLineEdit); - - directPageLabel = new QLabel(centralwidget); - directPageLabel->setObjectName(QString::fromUtf8("directPageLabel")); - - formLayout->setWidget(4, QFormLayout::LabelRole, directPageLabel); - - directPageLineEdit = new QLineEdit(centralwidget); - directPageLineEdit->setObjectName(QString::fromUtf8("directPageLineEdit")); - - formLayout->setWidget(4, QFormLayout::FieldRole, directPageLineEdit); - - stackPointerLabel = new QLabel(centralwidget); - stackPointerLabel->setObjectName(QString::fromUtf8("stackPointerLabel")); - - formLayout->setWidget(5, QFormLayout::LabelRole, stackPointerLabel); - - stackPointerLineEdit = new QLineEdit(centralwidget); - stackPointerLineEdit->setObjectName(QString::fromUtf8("stackPointerLineEdit")); - - formLayout->setWidget(5, QFormLayout::FieldRole, stackPointerLineEdit); - - xIndexLabel = new QLabel(centralwidget); - xIndexLabel->setObjectName(QString::fromUtf8("xIndexLabel")); - - formLayout->setWidget(6, QFormLayout::LabelRole, xIndexLabel); - - xIndexLineEdit = new QLineEdit(centralwidget); - xIndexLineEdit->setObjectName(QString::fromUtf8("xIndexLineEdit")); - - formLayout->setWidget(6, QFormLayout::FieldRole, xIndexLineEdit); - - yIndexLabel = new QLabel(centralwidget); - yIndexLabel->setObjectName(QString::fromUtf8("yIndexLabel")); - - formLayout->setWidget(7, QFormLayout::LabelRole, yIndexLabel); - - yIndexLineEdit = new QLineEdit(centralwidget); - yIndexLineEdit->setObjectName(QString::fromUtf8("yIndexLineEdit")); - - formLayout->setWidget(7, QFormLayout::FieldRole, yIndexLineEdit); - - emulationModeLabel = new QLabel(centralwidget); - emulationModeLabel->setObjectName(QString::fromUtf8("emulationModeLabel")); - - formLayout->setWidget(8, QFormLayout::LabelRole, emulationModeLabel); - - emulationModeCheckBox = new QCheckBox(centralwidget); - emulationModeCheckBox->setObjectName(QString::fromUtf8("emulationModeCheckBox")); - emulationModeCheckBox->setLayoutDirection(Qt::RightToLeft); - emulationModeCheckBox->setCheckable(true); - - formLayout->setWidget(8, QFormLayout::FieldRole, emulationModeCheckBox); - - - gridLayout_3->addLayout(formLayout, 0, 2, 2, 1); - - gridLayout = new QGridLayout(); - gridLayout->setObjectName(QString::fromUtf8("gridLayout")); - loggerLabel = new QLabel(centralwidget); - loggerLabel->setObjectName(QString::fromUtf8("loggerLabel")); - loggerLabel->setAlignment(Qt::AlignCenter); - - gridLayout->addWidget(loggerLabel, 0, 0, 1, 1); - - clear = new QPushButton(centralwidget); - clear->setObjectName(QString::fromUtf8("clear")); - - gridLayout->addWidget(clear, 2, 0, 1, 1); - - history = new QTableView(centralwidget); - history->setObjectName(QString::fromUtf8("history")); - - gridLayout->addWidget(history, 1, 0, 1, 1); - - - gridLayout_3->addLayout(gridLayout, 1, 1, 2, 1); - - formGroupBox = new QGroupBox(centralwidget); - formGroupBox->setObjectName(QString::fromUtf8("formGroupBox")); - formGroupBox->setAlignment(Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter); - formGroupBox->setFlat(false); - formGroupBox->setCheckable(false); - formLayout_2 = new QFormLayout(formGroupBox); - formLayout_2->setObjectName(QString::fromUtf8("formLayout_2")); - formLayout_2->setSizeConstraint(QLayout::SetDefaultConstraint); - formLayout_2->setLabelAlignment(Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter); - formLayout_2->setFormAlignment(Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop); - formLayout_2->setContentsMargins(26, 7, 0, -1); - negativeLabel = new QLabel(formGroupBox); - negativeLabel->setObjectName(QString::fromUtf8("negativeLabel")); - - formLayout_2->setWidget(0, QFormLayout::LabelRole, negativeLabel); - - mCheckbox = new QCheckBox(formGroupBox); - mCheckbox->setObjectName(QString::fromUtf8("mCheckbox")); - mCheckbox->setLayoutDirection(Qt::RightToLeft); - - formLayout_2->setWidget(0, QFormLayout::FieldRole, mCheckbox); - - zeroLabel = new QLabel(formGroupBox); - zeroLabel->setObjectName(QString::fromUtf8("zeroLabel")); - - formLayout_2->setWidget(1, QFormLayout::LabelRole, zeroLabel); - - xCheckbox = new QCheckBox(formGroupBox); - xCheckbox->setObjectName(QString::fromUtf8("xCheckbox")); - xCheckbox->setLayoutDirection(Qt::RightToLeft); - - formLayout_2->setWidget(1, QFormLayout::FieldRole, xCheckbox); - - carryLabel = new QLabel(formGroupBox); - carryLabel->setObjectName(QString::fromUtf8("carryLabel")); - - formLayout_2->setWidget(3, QFormLayout::LabelRole, carryLabel); - - iCheckbox = new QCheckBox(formGroupBox); - iCheckbox->setObjectName(QString::fromUtf8("iCheckbox")); - iCheckbox->setLayoutDirection(Qt::RightToLeft); - - formLayout_2->setWidget(3, QFormLayout::FieldRole, iCheckbox); - - Overflow = new QLabel(formGroupBox); - Overflow->setObjectName(QString::fromUtf8("Overflow")); - - formLayout_2->setWidget(4, QFormLayout::LabelRole, Overflow); - - vCheckbox = new QCheckBox(formGroupBox); - vCheckbox->setObjectName(QString::fromUtf8("vCheckbox")); - vCheckbox->setLayoutDirection(Qt::RightToLeft); - - formLayout_2->setWidget(4, QFormLayout::FieldRole, vCheckbox); - - decimalLabel = new QLabel(formGroupBox); - decimalLabel->setObjectName(QString::fromUtf8("decimalLabel")); - - formLayout_2->setWidget(5, QFormLayout::LabelRole, decimalLabel); - - dCheckbox = new QCheckBox(formGroupBox); - dCheckbox->setObjectName(QString::fromUtf8("dCheckbox")); - dCheckbox->setLayoutDirection(Qt::RightToLeft); - - formLayout_2->setWidget(5, QFormLayout::FieldRole, dCheckbox); - - memoryAccumulatorSelectLabel = new QLabel(formGroupBox); - memoryAccumulatorSelectLabel->setObjectName(QString::fromUtf8("memoryAccumulatorSelectLabel")); - - formLayout_2->setWidget(6, QFormLayout::LabelRole, memoryAccumulatorSelectLabel); - - cCheckbox = new QCheckBox(formGroupBox); - cCheckbox->setObjectName(QString::fromUtf8("cCheckbox")); - cCheckbox->setLayoutDirection(Qt::RightToLeft); - - formLayout_2->setWidget(6, QFormLayout::FieldRole, cCheckbox); - - indeXSelectLabel = new QLabel(formGroupBox); - indeXSelectLabel->setObjectName(QString::fromUtf8("indeXSelectLabel")); - - formLayout_2->setWidget(7, QFormLayout::LabelRole, indeXSelectLabel); - - irqDisableLabel = new QLabel(formGroupBox); - irqDisableLabel->setObjectName(QString::fromUtf8("irqDisableLabel")); - - formLayout_2->setWidget(8, QFormLayout::LabelRole, irqDisableLabel); - - nCheckbox = new QCheckBox(formGroupBox); - nCheckbox->setObjectName(QString::fromUtf8("nCheckbox")); - nCheckbox->setLayoutDirection(Qt::RightToLeft); - - formLayout_2->setWidget(8, QFormLayout::FieldRole, nCheckbox); - - zCheckbox = new QCheckBox(formGroupBox); - zCheckbox->setObjectName(QString::fromUtf8("zCheckbox")); - zCheckbox->setLayoutDirection(Qt::RightToLeft); - - formLayout_2->setWidget(7, QFormLayout::FieldRole, zCheckbox); - - breakBLabel = new QLabel(formGroupBox); - breakBLabel->setObjectName(QString::fromUtf8("breakBLabel")); - - formLayout_2->setWidget(2, QFormLayout::LabelRole, breakBLabel); - - bCheckbox = new QCheckBox(formGroupBox); - bCheckbox->setObjectName(QString::fromUtf8("bCheckbox")); - bCheckbox->setLayoutDirection(Qt::RightToLeft); - - formLayout_2->setWidget(2, QFormLayout::FieldRole, bCheckbox); - - - gridLayout_3->addWidget(formGroupBox, 2, 2, 1, 1); - - CPUView->setCentralWidget(centralwidget); - toolBar = new QToolBar(CPUView); - toolBar->setObjectName(QString::fromUtf8("toolBar")); - toolBar->setMinimumSize(QSize(0, 0)); - toolBar->setMovable(false); - toolBar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); - toolBar->setFloatable(true); - CPUView->addToolBar(Qt::TopToolBarArea, toolBar); - - toolBar->addAction(actionPause); - toolBar->addAction(actionNext); - toolBar->addAction(actionStep); - - retranslateUi(CPUView); - - QMetaObject::connectSlotsByName(CPUView); - } // setupUi - - void retranslateUi(QMainWindow *CPUView) - { - CPUView->setWindowTitle(QCoreApplication::translate("CPUView", "CPU's Debugger", nullptr)); - actionPause->setText(QCoreApplication::translate("CPUView", "Continue", nullptr)); -#if QT_CONFIG(tooltip) - actionPause->setToolTip(QCoreApplication::translate("CPUView", "Pause or Resume instruction execution.", nullptr)); -#endif // QT_CONFIG(tooltip) -#if QT_CONFIG(shortcut) - actionPause->setShortcut(QCoreApplication::translate("CPUView", "C", nullptr)); -#endif // QT_CONFIG(shortcut) - actionStep->setText(QCoreApplication::translate("CPUView", "Step", nullptr)); -#if QT_CONFIG(tooltip) - actionStep->setToolTip(QCoreApplication::translate("CPUView", "Execute a single instruction", nullptr)); -#endif // QT_CONFIG(tooltip) -#if QT_CONFIG(shortcut) - actionStep->setShortcut(QCoreApplication::translate("CPUView", "S", nullptr)); -#endif // QT_CONFIG(shortcut) - actionNext->setText(QCoreApplication::translate("CPUView", "Next", nullptr)); -#if QT_CONFIG(tooltip) - actionNext->setToolTip(QCoreApplication::translate("CPUView", "Continue execution to the next line.", nullptr)); -#endif // QT_CONFIG(tooltip) -#if QT_CONFIG(shortcut) - actionNext->setShortcut(QCoreApplication::translate("CPUView", "N", nullptr)); -#endif // QT_CONFIG(shortcut) - label->setText(QCoreApplication::translate("CPUView", "Stack Viewer", nullptr)); - accumulatorLabel->setText(QCoreApplication::translate("CPUView", "Accumulator", nullptr)); - accumulatorLineEdit->setText(QString()); - programBankRegisterLabel->setText(QCoreApplication::translate("CPUView", "Program Bank", nullptr)); - programCounterLabel->setText(QCoreApplication::translate("CPUView", "Program Counter", nullptr)); - directBankLabel->setText(QCoreApplication::translate("CPUView", "Direct Bank", nullptr)); - directPageLabel->setText(QCoreApplication::translate("CPUView", "Direct Page", nullptr)); - stackPointerLabel->setText(QCoreApplication::translate("CPUView", "Stack Pointer", nullptr)); - xIndexLabel->setText(QCoreApplication::translate("CPUView", "X Index", nullptr)); - yIndexLabel->setText(QCoreApplication::translate("CPUView", "Y Index", nullptr)); - emulationModeLabel->setText(QCoreApplication::translate("CPUView", "Emulation mode", nullptr)); - loggerLabel->setText(QCoreApplication::translate("CPUView", "Instructions History", nullptr)); - clear->setText(QCoreApplication::translate("CPUView", "Clear History", nullptr)); - formGroupBox->setTitle(QCoreApplication::translate("CPUView", "Flags", nullptr)); - negativeLabel->setText(QCoreApplication::translate("CPUView", "Memory Select (M)", nullptr)); - zeroLabel->setText(QCoreApplication::translate("CPUView", "Index Select (X)", nullptr)); - carryLabel->setText(QCoreApplication::translate("CPUView", "Interupt Request Disable (I)", nullptr)); - Overflow->setText(QCoreApplication::translate("CPUView", "Overflow (V)", nullptr)); - decimalLabel->setText(QCoreApplication::translate("CPUView", "Decimal (D)", nullptr)); - memoryAccumulatorSelectLabel->setText(QCoreApplication::translate("CPUView", "Carry (C)", nullptr)); - indeXSelectLabel->setText(QCoreApplication::translate("CPUView", "Zero (Z)", nullptr)); - irqDisableLabel->setText(QCoreApplication::translate("CPUView", "Negative (N)", nullptr)); - breakBLabel->setText(QCoreApplication::translate("CPUView", "Break (B)", nullptr)); - toolBar->setWindowTitle(QCoreApplication::translate("CPUView", "toolBar", nullptr)); - } // retranslateUi - -}; - -namespace Ui { - class CPUView: public Ui_CPUView {}; -} // namespace Ui - -QT_END_NAMESPACE - -#endif // UI_CPU_H