// // Created by anonymus-raccoon on 2/14/20. // #pragma once #include "Debugger/ClosableWindow.hpp" #include "Exceptions/DebuggableError.hpp" #include "ui/ui_cpuView.h" #include "Models/Ints.hpp" #include "Memory/MemoryBus.hpp" #include "CPU/Instruction.hpp" #include #include #include #include namespace ComSquare { class SNES; namespace CPU { class CPU; } namespace Debugger::CPU { class CPUDebug; //! @brief An instruction that has already been executed. Used for the history viewer struct ExecutedInstruction { //! @brief Opcode of the instruction uint8_t opcode; //! @brief The name of the instruction std::string name; //! @brief Readable parameters (disassembly style) std::string params; //! @brief The address to read from after processing the parameter. std::string proceededParams; }; //! @brief The qt model that show the stack. class StackModel : public QAbstractTableModel { Q_OBJECT private: Memory::IMemoryBus &_bus; CPUDebug &_cpu; public: explicit StackModel(Memory::IMemoryBus &bus, CPUDebug &cpu); StackModel(const StackModel &) = delete; const StackModel &operator=(const StackModel &) = delete; ~StackModel() override = default; //! @brief The number of row the table has. [[nodiscard]] int rowCount(const QModelIndex &parent) const override; //! @brief The number of column the table has. [[nodiscard]] int columnCount(const QModelIndex &parent) const override; //! @brief Return a data representing the table cell. [[nodiscard]] QVariant data(const QModelIndex &index, int role) const override; //! @brief Override the headers to use hex values. [[nodiscard]] QVariant headerData(int section, Qt::Orientation orientation, int role) const override; }; //! @brief The qt model that show the history. class HistoryModel : public QAbstractTableModel { Q_OBJECT private: std::vector _instructions = {}; public: HistoryModel(); HistoryModel(const HistoryModel &) = delete; const HistoryModel &operator=(const HistoryModel &) = delete; ~HistoryModel() override = default; //! @brief Log a new instruction void log(const ExecutedInstruction &); //! @brief Remove every instructions of the history. void clear(); //! @brief The number of row the table has. [[nodiscard]] int rowCount(const QModelIndex &parent) const override; //! @brief The number of column the table has. [[nodiscard]] int columnCount(const QModelIndex &parent) const override; //! @brief Return a data representing the table cell. [[nodiscard]] QVariant data(const QModelIndex &index, int role) const override; //! @brief Override the headers to use hex values. [[nodiscard]] QVariant headerData(int section, Qt::Orientation orientation, int role) const override; }; //! @brief The qt model that show the disassembly. class DisassemblyModel : public QAbstractTableModel { Q_OBJECT private: CPUDebug &_cpu; public: explicit DisassemblyModel(CPUDebug &cpu); DisassemblyModel(const DisassemblyModel &) = delete; const DisassemblyModel &operator=(const DisassemblyModel &) = delete; ~DisassemblyModel() override = default; //! @brief The number of row the table has. [[nodiscard]] int rowCount(const QModelIndex &parent) const override; //! @brief The number of column the table has. [[nodiscard]] int columnCount(const QModelIndex &parent) const override; //! @brief Return a data representing the table cell. [[nodiscard]] QVariant data(const QModelIndex &index, int role) const override; //! @brief Override the headers to use hex values. [[nodiscard]] QVariant headerData(int section, Qt::Orientation orientation, int role) const override; }; //! @brief The qt class that highlight breakpoints and the PC's position class RowPainter : public QStyledItemDelegate { Q_OBJECT private: //! @brief The CPU to get PC and breakpoints from. CPUDebug &_cpu; public: explicit RowPainter(CPUDebug &cpu, QObject *parent = nullptr); RowPainter &operator=(const RowPainter &) = delete; ~RowPainter() override = default; protected: [[nodiscard]] QSize sizeHint(const QStyleOptionViewItem &options, const QModelIndex &index) const override; void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override; }; enum TrustLevel { Safe, Unsafe, Compromised }; //! @brief Struct used to emulate the state of the processor during the disassembly since instructions take a different amount of space depending on some flags. struct DisassemblyContext { //! @brief The accumulator and Memory width flag (in native mode only) - 0 = 16 bits mode, 1 = 8 bits mode. //! @info If this flag is set to false, instructions that have the ImmediateByA addressing mode take 1 more bit of space. bool mFlag = true; //! @brief The indeX register width flag (in native mode only) - 0 = 16 bits mode, 1 = 8 bits mode OR the Break flag (in emulation mode only) //! @info If this flag is set to false, instructions that have the ImmediateByX addressing mode take 1 more bit of space. bool xFlag = true; //! @brief Is the CPU emulating a 6502? If yes, some instructions don't change flags the same way. bool isEmulationMode = true; //! @brief Sometimes, the flags can't be tracked correctly after an instruction so the next instructions may not be correctly disassembled. TrustLevel level = Safe; }; //! @brief Struct representing an instruction in an human readable way (created by disassembling the rom). struct DisassembledInstruction : public ComSquare::CPU::Instruction { //! @brief The address of the instruction uint24_t address; //! @brief A string representing the argument with the right addressing mode. std::string argument; //! @brief The opcode of the instruction uint8_t opcode; //! @brief Are we sure that this instruction has been correctly disassembled? TrustLevel level; DisassembledInstruction(const ComSquare::CPU::Instruction &instruction, uint24_t address, std::string argument, uint8_t opcode); DisassembledInstruction(const DisassembledInstruction &) = default; DisassembledInstruction &operator=(const DisassembledInstruction &) = default; ~DisassembledInstruction() = default; }; //! @brief Struct representing a breakpoint set by the user or by the app struct Breakpoint { //! @brief The address of the breakpoint uint24_t address; //! @brief If this is true, the breakpoint will be deleted on first hit and won't be shown on the disassembly view. bool oneTime; }; //! @brief Struct representing a label. struct Label { //! @brief The address of this label uint24_t address; //! @brief The name of this label std::string name; //! @brief The size of the definition related to this label std::optional size; }; //! @brief A window that show registers and the disassembly of a CPU. class CPUDebug : public QObject { Q_OBJECT private: //! @brief The basic CPU to debug. ComSquare::CPU::CPU &_cpu; //! @brief The QT window for this debugger. ClosableWindow *_window; //! @brief Internal timer used for update intervals. QTimer _timer; //! @brief A widget that contain the whole UI. Ui::CPUView _ui; //! @brief The disassembly viewer's model. DisassemblyModel _model; //! @brief A custom painter that highlight breakpoints and the PC's position. RowPainter _painter; //! @brief The stack viewer's model. StackModel _stackModel; //! @brief The history model. HistoryModel _historyModel; //! @brief If this is set to true, the execution of the CPU will be paused. bool _isPaused = true; //! @brief If this is set to true, the CPU will execute one instruction and pause itself. bool _isStepping = false; //! @brief A reference to the snes (to disable the debugger). SNES &_snes; //! @brief A list of labels and their size. std::vector