diff --git a/sources/Debugger/MemoryViewer.cpp b/sources/Debugger/MemoryViewer.cpp index 10091fb..632f356 100644 --- a/sources/Debugger/MemoryViewer.cpp +++ b/sources/Debugger/MemoryViewer.cpp @@ -9,6 +9,8 @@ #include "MemoryViewer.hpp" #include "../SNES.hpp" #include "../Utility/Utility.hpp" +#include "../Memory/MemoryShadow.hpp" +#include "../Exceptions/InvalidAddress.hpp" MemoryViewerModel::MemoryViewerModel(std::shared_ptr memory, QObject *parent) : QAbstractTableModel(parent), @@ -62,9 +64,10 @@ void MemoryViewerModel::setMemory(std::shared_ptr memory) namespace ComSquare::Debugger { - MemoryViewer::MemoryViewer(ComSquare::SNES &snes) : + MemoryViewer::MemoryViewer(ComSquare::SNES &snes, Memory::MemoryBus &bus) : QMainWindow(), _snes(snes), + _bus(bus), _ui(), _model(snes.wram) { @@ -128,15 +131,35 @@ namespace ComSquare::Debugger if (dialog.exec() != QDialog::Accepted) return; long value = std::strtol(dialogUI.spinBox->text().toStdString().c_str() + 1, nullptr, 16); - if (dialogUI.checkBox->isChecked()) - this->switchToAddrTab(value); + if (dialogUI.checkBox->isChecked()) { + try { + value = this->switchToAddrTab(value); + } catch (InvalidAddress &) {} + } QModelIndex index = this->_ui.tableView->model()->index(value >> 4, value & 0x0000000F); this->_ui.tableView->scrollTo(index); this->_ui.tableView->selectionModel()->select(index, QItemSelectionModel::ClearAndSelect); } - void MemoryViewer::switchToAddrTab(uint24_t addr) + unsigned MemoryViewer::switchToAddrTab(uint24_t addr) { + std::shared_ptr accessor = this->_bus.getAccessor(addr); + if (!accessor) + throw InvalidAddress("Memory viewer switch to address", addr); + Memory::IMemory *ptr; + if (accessor->isMirror()) + ptr = accessor->getMirrored().get(); + else + ptr = accessor.get(); + if (ptr == this->_snes.wram.get()) + this->_ui.tabs->setCurrentIndex(0); + else if (ptr == this->_snes.sram.get()) + this->_ui.tabs->setCurrentIndex(1); + else if (ptr == this->_snes.cartridge.get()) + this->_ui.tabs->setCurrentIndex(2); + else + throw InvalidAddress("Memory viewer switch to address", addr); + return addr - accessor->getStart(); } } \ No newline at end of file diff --git a/sources/Debugger/MemoryViewer.hpp b/sources/Debugger/MemoryViewer.hpp index 1cd6b5b..cd4c13f 100644 --- a/sources/Debugger/MemoryViewer.hpp +++ b/sources/Debugger/MemoryViewer.hpp @@ -9,6 +9,7 @@ #include "../../ui/ui_ramView.h" #include "../../ui/ui_gotoDialog.h" #include "../Ram/Ram.hpp" +#include "../Memory/MemoryBus.hpp" #include using ComSquare::Ram::Ram; @@ -52,6 +53,8 @@ namespace ComSquare private: //! @brief SNES containing all rams to view. SNES &_snes; + //! @brief The memory bus used to get the view for a given address. + Memory::MemoryBus &_bus; //! @brief The layout of the viewer. Ui::RamView _ui; //! @brief The Ram visualizer model for QT. @@ -60,7 +63,8 @@ namespace ComSquare void _internalGoto(bool isAbsolute); public: //! @brief Select the memory tab corresponding to a 24 bit address (map the address via the bus). - void switchToAddrTab(uint24_t addr); + //! @return The address converted to the new tab's locale space. + unsigned switchToAddrTab(uint24_t addr); //! @brief Callback called when a memory tab is selected. void changeRam(int id); @@ -69,7 +73,7 @@ namespace ComSquare //! @brief Create a popup asking you where you want to jump to with the absolute mode selected. void gotoAbsoluteAddr(); - explicit MemoryViewer(SNES &snes); + explicit MemoryViewer(SNES &snes, Memory::MemoryBus &bus); MemoryViewer(const MemoryViewer &) = delete; MemoryViewer &operator=(const MemoryViewer &) = delete; ~MemoryViewer() override = default; diff --git a/sources/Memory/IMemory.cpp b/sources/Memory/IMemory.cpp index 03b2098..eff2491 100644 --- a/sources/Memory/IMemory.cpp +++ b/sources/Memory/IMemory.cpp @@ -22,4 +22,14 @@ namespace ComSquare::Memory { return this->_start; } + + bool IMemory::isMirror() + { + return false; + } + + std::shared_ptr IMemory::getMirrored() + { + return nullptr; + } } \ No newline at end of file diff --git a/sources/Memory/IMemory.hpp b/sources/Memory/IMemory.hpp index b0a8e64..6f7d33b 100644 --- a/sources/Memory/IMemory.hpp +++ b/sources/Memory/IMemory.hpp @@ -8,6 +8,7 @@ #include #include +#include #include "../Models/Int24.hpp" namespace ComSquare::Memory @@ -42,6 +43,12 @@ namespace ComSquare::Memory //! @brief Get the first address mapped to this component. //! @return the _start value. virtual uint24_t getStart(); + //! @brief Check if this memory is a mirror or not. + //! @return True if this memory is a mirror. False otherwise. + virtual bool isMirror(); + //! @brief Return the memory accessor this accessor mirror if any + //! @return nullptr if isMirror is false, the source otherwise. + virtual std::shared_ptr getMirrored(); }; }; diff --git a/sources/Memory/MemoryBus.hpp b/sources/Memory/MemoryBus.hpp index ce9779f..1bd4844 100644 --- a/sources/Memory/MemoryBus.hpp +++ b/sources/Memory/MemoryBus.hpp @@ -22,11 +22,6 @@ namespace ComSquare //! @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; - //! @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); - //! @brief The last value read via the memory bus. uint8_t _openBus = 0; @@ -54,6 +49,11 @@ namespace ComSquare //! @brief Map components to the address space using the currently loaded cartridge to set the right mapping mode. //! @param console All the components. void mapComponents(SNES &console); + + //! @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); }; } } diff --git a/sources/Memory/MemoryShadow.cpp b/sources/Memory/MemoryShadow.cpp index a80a81e..4256c52 100644 --- a/sources/Memory/MemoryShadow.cpp +++ b/sources/Memory/MemoryShadow.cpp @@ -23,4 +23,14 @@ namespace ComSquare::Memory { return this->_initial->write(addr, data); } + + bool MemoryShadow::isMirror() + { + return true; + } + + std::shared_ptr MemoryShadow::getMirrored() + { + return this->_initial; + } } \ No newline at end of file diff --git a/sources/Memory/MemoryShadow.hpp b/sources/Memory/MemoryShadow.hpp index ce80ef8..0653522 100644 --- a/sources/Memory/MemoryShadow.hpp +++ b/sources/Memory/MemoryShadow.hpp @@ -31,6 +31,12 @@ namespace ComSquare::Memory //! @param data The data to write. //! @throw InvalidAddress will be thrown if the address is more than the size of the initial IMemory. void write(uint24_t addr, uint8_t data) override; + //! @brief Check if this memory is a mirror or not. + //! @return True if this memory is a mirror. False otherwise. + bool isMirror() 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; }; } diff --git a/sources/Memory/RectangleShadow.cpp b/sources/Memory/RectangleShadow.cpp index f336848..09e9a48 100644 --- a/sources/Memory/RectangleShadow.cpp +++ b/sources/Memory/RectangleShadow.cpp @@ -32,4 +32,14 @@ namespace ComSquare::Memory this->_bankOffset = bankOffset; return this; } + + bool RectangleShadow::isMirror() + { + return true; + } + + std::shared_ptr RectangleShadow::getMirrored() + { + return this->_initial; + } } \ No newline at end of file diff --git a/sources/Memory/RectangleShadow.hpp b/sources/Memory/RectangleShadow.hpp index 7f43ad6..e1486e1 100644 --- a/sources/Memory/RectangleShadow.hpp +++ b/sources/Memory/RectangleShadow.hpp @@ -34,7 +34,12 @@ namespace ComSquare::Memory //! @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 Check if this memory is a mirror or not. + //! @return True if this memory is a mirror. False otherwise. + bool isMirror() 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; RectangleShadow *setBankOffset(uint8_t bankOffset); }; diff --git a/sources/SNES.cpp b/sources/SNES.cpp index 10d742c..73d4450 100644 --- a/sources/SNES.cpp +++ b/sources/SNES.cpp @@ -13,6 +13,7 @@ namespace ComSquare { SNES::SNES(const std::shared_ptr &bus, const std::string &romPath, Renderer::IRenderer &renderer) : + _bus(bus), cartridge(new Cartridge::Cartridge(romPath)), wram(new Ram::Ram(16384)), sram(new Ram::Ram(this->cartridge->header.sramSize)), @@ -42,7 +43,7 @@ namespace ComSquare void SNES::enableRamViewer() { #ifdef DEBUGGER_ENABLED - this->_ramViewer = std::make_shared(*this); + this->_ramViewer = std::make_shared(*this, *this->_bus); #endif } diff --git a/sources/SNES.hpp b/sources/SNES.hpp index 282e8d7..5fc5846 100644 --- a/sources/SNES.hpp +++ b/sources/SNES.hpp @@ -22,13 +22,14 @@ namespace ComSquare { //! @brief Container of all the components of the SNES. class SNES { -#ifdef DEBUGGER_ENABLED private: +#ifdef DEBUGGER_ENABLED //! @brief The window that allow the user to view a memory. std::shared_ptr _ramViewer; //! @brief The window that allow the user to view the cartridge's header. std::shared_ptr _headerViewer; #endif + std::shared_ptr _bus; public: //! @brief Cartridge containing instructions (ROM). std::shared_ptr cartridge;