Merging origin/master

This commit is contained in:
Melefo
2021-02-05 14:41:25 +01:00
63 changed files with 1606 additions and 1152 deletions
+1 -1
View File
@@ -535,7 +535,7 @@ namespace ComSquare::Debugger
this->_snes.disableAPUDebugging();
}
bool APUDebug::isDebugger()
bool APUDebug::isDebugger() const
{
return true;
}
+1 -1
View File
@@ -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();
+23 -4
View File
@@ -8,6 +8,8 @@
#include <QtEvents>
#include <QPainter>
#include <iostream>
#include <utility>
#include <QMessageBox>
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<ComSquare::Memory::MemoryBus> bus, ComSquare::Debugger::CPUDebug &cpu) : _bus(bus), _cpu(cpu) { }
StackModel::StackModel(std::shared_ptr<ComSquare::Memory::MemoryBus> bus, ComSquare::Debugger::CPUDebug &cpu)
: _bus(std::move(bus)), _cpu(cpu)
{ }
void StackModel::setMemoryBus(std::shared_ptr<ComSquare::Memory::MemoryBus> bus)
{
+5 -3
View File
@@ -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();
+2 -2
View File
@@ -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)";
}
}
+15 -6
View File
@@ -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<uint8_t> 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<Memory::AMemory> &_accessor, std::optional<uint8_t> _oldData, uint8_t _newData) :
BusLog::BusLog(bool _write, uint24_t _addr, std::shared_ptr<Memory::IMemory> &_accessor, std::optional<uint8_t> _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("???");
+8 -3
View File
@@ -17,13 +17,13 @@ namespace ComSquare::Debugger
struct BusLog {
BusLog(bool write,
uint24_t addr,
std::shared_ptr<Memory::AMemory> &accessor,
std::shared_ptr<Memory::IMemory> &accessor,
std::optional<uint8_t> oldData,
uint8_t newData);
bool write;
uint24_t addr;
std::shared_ptr<Memory::AMemory> accessor;
std::shared_ptr<Memory::IMemory> accessor;
std::optional<uint8_t> 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.
+30 -14
View File
@@ -6,6 +6,7 @@
#include <cmath>
#include <QtWidgets/QInputDialog>
#include <QtWidgets/QSpinBox>
#include <QMessageBox>
#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<Memory::AMemory> accessor = this->_bus.getAccessor(addr);
std::shared_ptr<Memory::IMemory> 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()
+169
View File
@@ -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<RegisterViewer>(*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<QTableView *, 8> 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 &regName,
const std::function<unsigned int(SNES &)> &getValue,
const std::function<void(SNES &, unsigned int)> &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<uint8_t>(reg.get(this->_snes))).c_str());
case SixteenBits:
return QString(Utility::to_hex(static_cast<uint16_t>(reg.get(this->_snes))).c_str());
case TwentyFourBits:
return QString(Utility::to_hex(static_cast<uint24_t>(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();
}
}
+118
View File
@@ -0,0 +1,118 @@
//
// Created by anonymus-raccoon on 5/28/20.
//
#ifndef COMSQUARE_REGISTERVIEWER_HPP
#define COMSQUARE_REGISTERVIEWER_HPP
#include <QtCore/QObject>
#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<ComSquare::Debugger::Register> _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<RegisterViewer> *_window;
//! @brief A widget that contain the whole UI.
Ui::RegistersView _ui;
//! @brief The list of models used by different panels.
std::vector<RegistersViewerModel *> _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 &regName,
const std::function<unsigned int(SNES &)> &getValue,
const std::function<void(SNES &, unsigned int)> &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<unsigned(SNES &)> get;
//! @brief How to set this value.
std::function<void(SNES &, unsigned)> set;
//! @brief How this value should be displayed/asked for input.
RegisterType type;
};
}
}
#endif //COMSQUARE_REGISTERVIEWER_HPP