From c6e4cd1702689962a9a3b60100a814ee6565ab9e Mon Sep 17 00:00:00 2001
From: Anonymus Raccoon
Date: Thu, 14 May 2020 15:51:48 +0200
Subject: [PATCH 1/4] Fixing a segfault with the bus & cpu's debugger together
---
sources/CPU/CPU.cpp | 2 --
sources/CPU/CPU.hpp | 2 +-
sources/Debugger/CPU/CPUDebug.cpp | 19 ++++++++++++++-----
sources/Debugger/CPU/CPUDebug.hpp | 10 ++++++++--
ui/ui_cpu.h | 2 +-
5 files changed, 24 insertions(+), 11 deletions(-)
diff --git a/sources/CPU/CPU.cpp b/sources/CPU/CPU.cpp
index 8116408..cd9ddca 100644
--- a/sources/CPU/CPU.cpp
+++ b/sources/CPU/CPU.cpp
@@ -6,9 +6,7 @@
#include
#include
-#include "../Exceptions/NotImplementedException.hpp"
#include "../Exceptions/InvalidAddress.hpp"
-#include "../Exceptions/InvalidOpcode.hpp"
namespace ComSquare::CPU
{
diff --git a/sources/CPU/CPU.hpp b/sources/CPU/CPU.hpp
index 26dde23..f127d41 100644
--- a/sources/CPU/CPU.hpp
+++ b/sources/CPU/CPU.hpp
@@ -713,7 +713,7 @@ namespace ComSquare::CPU
virtual bool isDebugger();
//! @brief Change the memory bus used by the CPU.
- void setMemoryBus(std::shared_ptr bus);
+ virtual void setMemoryBus(std::shared_ptr bus);
};
}
diff --git a/sources/Debugger/CPU/CPUDebug.cpp b/sources/Debugger/CPU/CPUDebug.cpp
index 5be3734..6bcb800 100644
--- a/sources/Debugger/CPU/CPUDebug.cpp
+++ b/sources/Debugger/CPU/CPUDebug.cpp
@@ -5,11 +5,9 @@
#include "CPUDebug.hpp"
#include "../../Utility/Utility.hpp"
#include "../../Exceptions/InvalidOpcode.hpp"
-#include "../../CPU/CPU.hpp"
#include
#include
#include
-#include
using namespace ComSquare::CPU;
@@ -21,7 +19,7 @@ namespace ComSquare::Debugger
_ui(),
_model(*this),
_painter(*this),
- _stackModel(*this->_bus, *this),
+ _stackModel(this->_bus, *this),
_snes(snes)
{
this->_window->setContextMenuPolicy(Qt::NoContextMenu);
@@ -70,6 +68,12 @@ namespace ComSquare::Debugger
this->_snes.disableCPUDebugging();
}
+ void CPUDebug::setMemoryBus(std::shared_ptr bus)
+ {
+ this->_stackModel.setMemoryBus(bus);
+ CPU::setMemoryBus(bus);
+ }
+
unsigned CPUDebug::update()
{
try {
@@ -379,7 +383,12 @@ QSize RowPainter::sizeHint(const QStyleOptionViewItem &, const QModelIndex &) co
return QSize();
}
-StackModel::StackModel(ComSquare::Memory::MemoryBus &bus, ComSquare::Debugger::CPUDebug &cpu) : _bus(bus), _cpu(cpu) { }
+StackModel::StackModel(std::shared_ptr bus, ComSquare::Debugger::CPUDebug &cpu) : _bus(bus), _cpu(cpu) { }
+
+void StackModel::setMemoryBus(std::shared_ptr bus)
+{
+ this->_bus = std::move(bus);
+}
int StackModel::rowCount(const QModelIndex &) const
{
@@ -405,7 +414,7 @@ QVariant StackModel::data(const QModelIndex &index, int role) const
return QVariant();
uint16_t addr = index.row() * 2 + index.column();
try {
- uint8_t value = this->_bus.read(addr);
+ uint8_t value = this->_bus->read(addr);
return (ComSquare::Utility::to_hex(value, ComSquare::Utility::NoPrefix).c_str());
} catch (std::exception &) {
return "??";
diff --git a/sources/Debugger/CPU/CPUDebug.hpp b/sources/Debugger/CPU/CPUDebug.hpp
index ab596d0..db00d37 100644
--- a/sources/Debugger/CPU/CPUDebug.hpp
+++ b/sources/Debugger/CPU/CPUDebug.hpp
@@ -34,10 +34,10 @@ class StackModel : public QAbstractTableModel
{
Q_OBJECT
private:
- ComSquare::Memory::MemoryBus &_bus;
+ std::shared_ptr _bus;
ComSquare::Debugger::CPUDebug &_cpu;
public:
- explicit StackModel(ComSquare::Memory::MemoryBus &bus, ComSquare::Debugger::CPUDebug &cpu);
+ explicit StackModel(std::shared_ptr bus, ComSquare::Debugger::CPUDebug &cpu);
StackModel(const StackModel &) = delete;
const StackModel &operator=(const StackModel &) = delete;
~StackModel() override = default;
@@ -50,6 +50,9 @@ public:
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;
+
+ //! @brief Change the memory bus used by the view.
+ void setMemoryBus(std::shared_ptr bus);
};
//! @brief The qt model that show the history.
@@ -285,6 +288,9 @@ namespace ComSquare::Debugger
//! @brief Override the basic cpu's update to allow pausing of the CPU only.
unsigned update() override;
+
+ //! @brief Change the memory bus used by the CPU.
+ void setMemoryBus(std::shared_ptr bus) override;
};
}
diff --git a/ui/ui_cpu.h b/ui/ui_cpu.h
index 97769dd..b7aafd0 100644
--- a/ui/ui_cpu.h
+++ b/ui/ui_cpu.h
@@ -1,7 +1,7 @@
/********************************************************************************
** Form generated from reading UI file 'cpu.ui'
**
-** Created by: Qt User Interface Compiler version 5.14.1
+** Created by: Qt User Interface Compiler version 5.14.2
**
** WARNING! All changes made in this file will be lost when recompiling UI file!
********************************************************************************/
From 5f0ed5f5614f1f36b7552a4317ad19a41ae98253 Mon Sep 17 00:00:00 2001
From: Anonymus Raccoon
Date: Thu, 14 May 2020 17:37:06 +0200
Subject: [PATCH 2/4] Adding the WAI and handling NMI & IRQ interrupts
---
sources/CPU/CPU.cpp | 35 ++++++++++++++++++++---
sources/CPU/CPU.hpp | 24 ++++++++++++++--
sources/CPU/Instructions/Interrupts.cpp | 38 ++++++++++++-------------
3 files changed, 71 insertions(+), 26 deletions(-)
diff --git a/sources/CPU/CPU.cpp b/sources/CPU/CPU.cpp
index 4f2a727..88ce592 100644
--- a/sources/CPU/CPU.cpp
+++ b/sources/CPU/CPU.cpp
@@ -205,13 +205,40 @@ namespace ComSquare::CPU
{
unsigned cycles = 0;
- if (this->_isStopped)
- return 0xFF;
- for (int i = 0; i < 0xFF; i++)
- cycles += this->_executeInstruction(this->readPC());
+ for (int i = 0; i < 0xFF; i++) {
+ if (this->_isStopped) {
+ cycles += 1;
+ continue;
+ }
+
+ this->_checkInterrupts();
+
+ if (!this->_isWaitingForInterrupt)
+ cycles += this->_executeInstruction(this->readPC());
+ }
return cycles;
}
+ void CPU::_checkInterrupts()
+ {
+ if (!this->IsNMIRequested && !this->IsIRQRequested && !this->IsAbortRequested)
+ return;
+ this->_isWaitingForInterrupt = false;
+
+ if (this->IsNMIRequested) {
+ this->_runInterrupt(
+ this->_cartridgeHeader.nativeInterrupts.nmi,
+ this->_cartridgeHeader.emulationInterrupts.nmi);
+ return;
+ }
+ if (this->IsIRQRequested && !this->_registers.p.i) {
+ this->_runInterrupt(
+ this->_cartridgeHeader.nativeInterrupts.irq,
+ this->_cartridgeHeader.emulationInterrupts.irq);
+ return;
+ }
+ }
+
uint24_t CPU::_getValueAddr(Instruction &instruction)
{
switch (instruction.addressingMode) {
diff --git a/sources/CPU/CPU.hpp b/sources/CPU/CPU.hpp
index 2b95861..808796b 100644
--- a/sources/CPU/CPU.hpp
+++ b/sources/CPU/CPU.hpp
@@ -186,12 +186,16 @@ namespace ComSquare::CPU
protected:
//! @brief All the registers of the CPU
Registers _registers{};
+ //! @brief Internal registers of the CPU (accessible from the bus via addr $4200 to $421F).
+ InternalRegisters _internalRegisters{};
+
//! @brief Is the CPU running in emulation mode (in 8bits)
bool _isEmulationMode = true;
//! @brief If the processor is stopped (using an STP instruction), the clock is stopped and no instruction will be run until a manual reset.
bool _isStopped = false;
- //! @brief Internal registers of the CPU (accessible from the bus via addr $4200 to $421F).
- InternalRegisters _internalRegisters{};
+ //! @brief Is the processor waiting for an interrupt (if true, instructions are not run until an interrupt is requested).
+ bool _isWaitingForInterrupt = false;
+
//! @brief The memory bus to use for read/write.
std::shared_ptr _bus;
//! @brief The cartridge header (stored for interrupt vectors..
@@ -258,6 +262,11 @@ namespace ComSquare::CPU
//! @brief Return the data at the program bank concatenated with the program counter. It also increment the program counter (the program bank is not incremented on overflows).
uint8_t readPC();
+ //! @brief Check if an interrupt is requested and handle it.
+ void _checkInterrupts();
+ //! @brief Run an interrupt (save state of the processor and jump to the interrupt handler)
+ void _runInterrupt(uint24_t nativeHandler, uint24_t emulationHandler);
+
//! @brief Execute a single instruction.
//! @return The number of CPU cycles that the instruction took.
virtual unsigned _executeInstruction(uint8_t opcode);
@@ -443,6 +452,8 @@ namespace ComSquare::CPU
int PEA(uint24_t, AddressingMode);
//! @brief Stop the processor
int STP(uint24_t, AddressingMode);
+ //! @brief Wait for Interrupt
+ int WAI(uint24_t, AddressingMode);
//! @brief WDM Reserved for Future Expansion (used as a code breakpoint)
int WDM(uint24_t, AddressingMode);
//! @brief Block Move Next. This instruction is special: it takes parameter in the registers
@@ -662,7 +673,7 @@ namespace ComSquare::CPU
{&CPU::INY, 2, "iny", AddressingMode::Implied, 1}, // C8
{&CPU::CMP, 2, "cmp", AddressingMode::ImmediateForA, 2}, // C9
{&CPU::DEX, 2, "dex", AddressingMode::Implied, 1}, // CA
- {&CPU::BRK, 7, "wai #-#", AddressingMode::Implied, 2}, // CB
+ {&CPU::WAI, 3, "wai", AddressingMode::Implied, 1}, // CB
{&CPU::CPY, 4, "cpy", AddressingMode::Absolute, 3}, // CC
{&CPU::CMP, 4, "cmp", AddressingMode::Absolute, 3}, // CD
{&CPU::DEC, 6, "dec", AddressingMode::Absolute, 3}, // CE
@@ -744,6 +755,13 @@ namespace ComSquare::CPU
//! @brief Reset interrupt - Called on boot and when the reset button is pressed.
virtual int RESB();
+ //! @brief Is an NMI (non-maskable interrupt) requested.
+ bool IsNMIRequested = false;
+ //! @brief Is an interrupt (maskable) requested.
+ bool IsIRQRequested = false;
+ //! @brief Is an abort requested
+ bool IsAbortRequested = false;
+
//! @brief Return true if the CPU is overloaded with debugging features.
virtual bool isDebugger();
diff --git a/sources/CPU/Instructions/Interrupts.cpp b/sources/CPU/Instructions/Interrupts.cpp
index 8f8d515..f084ce0 100644
--- a/sources/CPU/Instructions/Interrupts.cpp
+++ b/sources/CPU/Instructions/Interrupts.cpp
@@ -22,7 +22,7 @@ namespace ComSquare::CPU
return 0;
}
- int CPU::BRK(uint24_t, AddressingMode)
+ void CPU::_runInterrupt(uint24_t nativeHandler, uint24_t emulationHandler)
{
if (this->_isEmulationMode) {
this->_push(this->_registers.pc);
@@ -30,7 +30,7 @@ namespace ComSquare::CPU
this->_registers.p.i = true;
this->_registers.p.d = false;
this->_registers.pbr = 0x0;
- this->_registers.pc = this->_cartridgeHeader.emulationInterrupts.brk;
+ this->_registers.pc = emulationHandler;
} else {
this->_push(this->_registers.pbr);
this->_push(this->_registers.pc);
@@ -38,29 +38,23 @@ namespace ComSquare::CPU
this->_registers.p.i = true;
this->_registers.p.d = false;
this->_registers.pbr = 0x0;
- this->_registers.pc = this->_cartridgeHeader.nativeInterrupts.brk;
+ this->_registers.pc = nativeHandler;
}
+ }
+
+ int CPU::BRK(uint24_t, AddressingMode)
+ {
+ this->_runInterrupt(
+ this->_cartridgeHeader.nativeInterrupts.brk,
+ this->_cartridgeHeader.emulationInterrupts.brk);
return !this->_isEmulationMode;
}
int CPU::COP(uint24_t, AddressingMode)
{
- if (this->_isEmulationMode) {
- this->_push(this->_registers.pc);
- this->_push(this->_registers.p.flags);
- this->_registers.p.i = true;
- this->_registers.p.d = false;
- this->_registers.pbr = 0x0;
- this->_registers.pc = this->_cartridgeHeader.emulationInterrupts.cop;
- } else {
- this->_push(this->_registers.pbr);
- this->_push(this->_registers.pc);
- this->_push(this->_registers.p.flags);
- this->_registers.p.i = true;
- this->_registers.p.d = false;
- this->_registers.pbr = 0x0;
- this->_registers.pc = this->_cartridgeHeader.nativeInterrupts.cop;
- }
+ this->_runInterrupt(
+ this->_cartridgeHeader.nativeInterrupts.cop,
+ this->_cartridgeHeader.emulationInterrupts.cop);
return !this->_isEmulationMode;
}
@@ -73,4 +67,10 @@ namespace ComSquare::CPU
this->_registers.pbr = this->_pop16();
return !this->_isEmulationMode;
}
+
+ int CPU::WAI(uint24_t, AddressingMode)
+ {
+ this->_isWaitingForInterrupt = true;
+ return 0;
+ }
}
\ No newline at end of file
From efbf009f218b1366d29733d35b00fbca3fc177dd Mon Sep 17 00:00:00 2001
From: Anonymus Raccoon
Date: Thu, 14 May 2020 17:58:47 +0200
Subject: [PATCH 3/4] Oups
---
sources/CPU/CPU.cpp | 1 +
1 file changed, 1 insertion(+)
diff --git a/sources/CPU/CPU.cpp b/sources/CPU/CPU.cpp
index 3c4c248..88ce592 100644
--- a/sources/CPU/CPU.cpp
+++ b/sources/CPU/CPU.cpp
@@ -7,6 +7,7 @@
#include
#include
#include "../Exceptions/InvalidAddress.hpp"
+#include "../Exceptions/InvalidOpcode.hpp"
namespace ComSquare::CPU
{
From 24bcafeea3896022704904815d263f69f22e5096 Mon Sep 17 00:00:00 2001
From: Anonymus Raccoon
Date: Thu, 14 May 2020 18:12:29 +0200
Subject: [PATCH 4/4] Removing unintended logs to the bus's debugger
---
sources/Debugger/CPU/CPUDebug.cpp | 2 +-
sources/Debugger/CPU/Disassembly.cpp | 10 +++++-----
sources/Debugger/MemoryBusDebug.cpp | 2 +-
sources/SNES.cpp | 1 -
4 files changed, 7 insertions(+), 8 deletions(-)
diff --git a/sources/Debugger/CPU/CPUDebug.cpp b/sources/Debugger/CPU/CPUDebug.cpp
index 6bcb800..d677158 100644
--- a/sources/Debugger/CPU/CPUDebug.cpp
+++ b/sources/Debugger/CPU/CPUDebug.cpp
@@ -414,7 +414,7 @@ QVariant StackModel::data(const QModelIndex &index, int role) const
return QVariant();
uint16_t addr = index.row() * 2 + index.column();
try {
- uint8_t value = this->_bus->read(addr);
+ uint8_t value = this->_bus->read(addr, true);
return (ComSquare::Utility::to_hex(value, ComSquare::Utility::NoPrefix).c_str());
} catch (std::exception &) {
return "??";
diff --git a/sources/Debugger/CPU/Disassembly.cpp b/sources/Debugger/CPU/Disassembly.cpp
index 7541dd7..75aefd2 100644
--- a/sources/Debugger/CPU/Disassembly.cpp
+++ b/sources/Debugger/CPU/Disassembly.cpp
@@ -42,13 +42,13 @@ namespace ComSquare::Debugger
ctx.mFlag = true;
ctx.xFlag = true;
} else {
- uint8_t m = this->_bus->read(pc - 1);
+ uint8_t m = this->_bus->read(pc - 1, true);
ctx.mFlag &= ~m & 0b00100000u;
ctx.xFlag &= ~m & 0b00010000u;
}
}
if (instruction.opcode == 0xE2) { // SEP
- uint8_t m = this->_bus->read(pc - 1);
+ uint8_t m = this->_bus->read(pc - 1, true);
ctx.mFlag |= m & 0b00100000u;
ctx.xFlag |= m & 0b00010000u;
}
@@ -150,7 +150,7 @@ namespace ComSquare::Debugger
std::string CPUDebug::_getAbsoluteValue(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);
}
@@ -193,13 +193,13 @@ namespace ComSquare::Debugger
std::string CPUDebug::_getAbsoluteIndexByXValue(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";
}
std::string CPUDebug::_getAbsoluteIndexByYValue(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) + ", y";
}
diff --git a/sources/Debugger/MemoryBusDebug.cpp b/sources/Debugger/MemoryBusDebug.cpp
index 670f484..51bbc4c 100644
--- a/sources/Debugger/MemoryBusDebug.cpp
+++ b/sources/Debugger/MemoryBusDebug.cpp
@@ -150,7 +150,7 @@ namespace ComSquare::Debugger
uint8_t MemoryBusDebug::read(uint24_t addr, bool silence)
{
- if (!silence && !forceSilence) {
+ if (!silence && !this->forceSilence) {
auto accessor = this->getAccessor(addr);
if (!accessor) {
this->_model.log(BusLog(true, addr, accessor, this->_openBus, this->_openBus));
diff --git a/sources/SNES.cpp b/sources/SNES.cpp
index a57cd5a..bb6d7aa 100644
--- a/sources/SNES.cpp
+++ b/sources/SNES.cpp
@@ -3,7 +3,6 @@
//
#include
-#include
#include "SNES.hpp"
#ifdef DEBUGGER_ENABLED
#include "Debugger/CPU/CPUDebug.hpp"