Implementing missing addressings modes inside the debugger

This commit is contained in:
Anonymus Raccoon
2020-04-03 14:32:18 +02:00
parent b090a7d036
commit 7407c3cfaa
11 changed files with 659 additions and 231 deletions
@@ -3,9 +3,9 @@
//
#include "CPUDebug.hpp"
#include "../Utility/Utility.hpp"
#include "../Exceptions/InvalidOpcode.hpp"
#include "../CPU/CPU.hpp"
#include "../../Utility/Utility.hpp"
#include "../../Exceptions/InvalidOpcode.hpp"
#include "../../CPU/CPU.hpp"
#include <QtEvents>
#include <QPainter>
#include <iostream>
@@ -221,133 +221,6 @@ namespace ComSquare::Debugger
return {this->_registers.p.m, this->_registers.p.x_b, false};
}
std::vector<DisassembledInstruction> CPUDebug::_disassemble(uint24_t pc, uint24_t length, DisassemblyContext &ctx)
{
std::vector<DisassembledInstruction> map;
uint24_t endAddr = pc + length;
while (pc < endAddr) {
DisassembledInstruction instruction = this->_parseInstruction(pc, ctx);
instruction.level = ctx.level;
map.push_back(instruction);
pc += instruction.size;
if (instruction.addressingMode == ImmediateForA && !ctx.mFlag)
pc++;
if (instruction.addressingMode == ImmediateForX && !ctx.xFlag)
pc++;
if (instruction.opcode == 0x40 && ctx.isEmulationMode) { // RTI
ctx.mFlag = true;
ctx.xFlag = true;
}
if (instruction.opcode == 0xC2) { // REP
if (ctx.isEmulationMode) {
ctx.mFlag = true;
ctx.xFlag = true;
} else {
uint8_t m = this->_bus->read(pc - 1);
ctx.mFlag &= ~m & 0b00100000u;
ctx.xFlag &= ~m & 0b00010000u;
}
}
if (instruction.opcode == 0xE2) { // SEP
uint8_t m = this->_bus->read(pc - 1);
ctx.mFlag |= m & 0b00100000u;
ctx.xFlag |= m & 0b00010000u;
}
if (instruction.opcode == 0x28) { // PLP
if (ctx.isEmulationMode) {
ctx.mFlag = true;
ctx.xFlag = true;
} else
ctx.level = Compromised;
}
if (instruction.opcode == 0xFB) {// XCE
ctx.level = Unsafe;
ctx.isEmulationMode = false; // The most common use of the XCE is to enable native mode at the start of the ROM so we guess that it has done that.
}
}
return map;
}
DisassembledInstruction CPUDebug::_parseInstruction(uint24_t pc, DisassemblyContext &ctx)
{
uint24_t opcode = this->_bus->read(pc, true);
Instruction instruction = this->_instructions[opcode];
std::string argument = this->_getInstructionParameter(instruction, pc + 1, ctx);
return DisassembledInstruction(instruction, pc, argument, opcode);
}
std::string CPUDebug::_getInstructionParameter(Instruction &instruction, uint24_t pc, DisassemblyContext &ctx)
{
switch (instruction.addressingMode) {
case Implied:
return "";
case ImmediateForA:
return this->_getImmediateValue(pc, !ctx.mFlag);
case ImmediateForX:
return this->_getImmediateValue(pc, !ctx.xFlag);
case Immediate8bits:
return this->_getImmediateValue(pc, false);
case Absolute:
return this->_getAbsoluteValue(pc);
case AbsoluteLong:
return this->_getAbsoluteLongValue(pc);
case DirectPage:
return this->_getDirectValue(pc);
case DirectPageIndexedByX:
return this->_getDirectIndexedByXValue(pc);
default:
return "???";
}
}
std::string CPUDebug::_getImmediateValue(uint24_t pc, bool dual)
{
unsigned value = this->_bus->read(pc, true);
if (dual)
value += this->_bus->read(pc + 1, true) << 8u;
std::stringstream ss;
ss << "#$" << std::hex << value;
return ss.str();
}
std::string CPUDebug::_getDirectValue(uint24_t pc)
{
std::stringstream ss;
ss << "$" << std::hex << static_cast<int>(this->_bus->read(pc, true));
return ss.str();
}
std::string CPUDebug::_getAbsoluteValue(uint24_t pc)
{
std::stringstream ss;
ss << "$" << std::hex << (this->_bus->read(pc) + (this->_bus->read(pc + 1, true) << 8u));
return ss.str();
}
std::string CPUDebug::_getAbsoluteLongValue(uint24_t pc)
{
unsigned value = this->_bus->read(pc++, true);
value += this->_bus->read(pc++, true) << 8u;
value += this->_bus->read(pc, true) << 16u;
std::stringstream ss;
ss << "$" << std::hex << value;
return ss.str();
}
std::string CPUDebug::_getDirectIndexedByXValue(uint24_t pc)
{
unsigned value = this->_bus->read(pc, true);
std::stringstream ss;
ss << "$" << std::hex << value << ", x";
return ss.str();
}
int CPUDebug::RESB()
{
CPU::RESB();
@@ -366,14 +239,6 @@ namespace ComSquare::Debugger
{
return this->_registers.pac;
}
DisassembledInstruction::DisassembledInstruction(const CPU::Instruction &instruction, uint24_t addr, std::string arg, uint8_t op)
: CPU::Instruction(instruction), address(addr), argument(std::move(arg)), opcode(op), level(Safe) {}
std::string DisassembledInstruction::toString()
{
return this->name + " " + this->argument;
}
}
DisassemblyModel::DisassemblyModel(ComSquare::Debugger::CPUDebug &cpu) : QAbstractTableModel(), _cpu(cpu){ }
@@ -420,17 +285,6 @@ QVariant DisassemblyModel::headerData(int section, Qt::Orientation orientation,
return QString(ComSquare::Utility::to_hex(instruction.address, ComSquare::Utility::HexString::NoPrefix).c_str());
}
void DisassemblyModel::beginReset()
{
this->beginResetModel();
}
void DisassemblyModel::endReset()
{
this->endResetModel();
emit this->dataChanged(this->index(0, 0), this->index(this->_cpu.disassembledInstructions.size(), this->columnCount(QModelIndex())));
}
RowPainter::RowPainter(ComSquare::Debugger::CPUDebug &cpu, QObject *parent) : QStyledItemDelegate(parent), _cpu(cpu) { }
void RowPainter::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
@@ -6,11 +6,11 @@
#define COMSQUARE_CPUDEBUG_HPP
#include <QtWidgets/QStyledItemDelegate>
#include "../CPU/CPU.hpp"
#include "../Renderer/SFRenderer.hpp"
#include "../SNES.hpp"
#include "../../ui/ui_cpu.h"
#include "ClosableWindow.hpp"
#include "../../CPU/CPU.hpp"
#include "../../Renderer/SFRenderer.hpp"
#include "../../SNES.hpp"
#include "../../../ui/ui_cpu.h"
#include "../ClosableWindow.hpp"
namespace ComSquare::Debugger
{
@@ -37,9 +37,6 @@ 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;
void beginReset();
void endReset();
};
//! @brief The qt class that highlight breakpoints and the PC's position
@@ -144,14 +141,42 @@ namespace ComSquare::Debugger
//! @brief Return a printable string corresponding to the value of a 8 or 16 bits immediate addressing mode.
//! @param dual Set this to true if the instruction take 16bits and not 8. (used for the immediate by a when the flag m is not set or the immediate by x if the flag x is not set).
std::string _getImmediateValue(uint24_t pc, bool dual);
//! @brief Return a printable string corresponding to the value of a direct addressing mode.
std::string _getDirectValue(uint24_t pc);
//! @brief Return a printable string corresponding to the value of an absolute addressing mode.
std::string _getAbsoluteValue(uint24_t pc);
//! @brief Return a printable string corresponding to the value of an absolute long addressing mode.
std::string _getAbsoluteLongValue(uint24_t pc);
//! @brief Return a printable string corresponding to the value of a direct addressing mode.
std::string _getDirectValue(uint24_t pc);
//! @brief Return a printable string corresponding to the value of a direct indirect addressing mode.
std::string _getDirectIndirectValue(uint24_t pc);
//! @brief Return a printable string corresponding to the value of a direct indirect long addressing mode.
std::string _getDirectIndirectLongValue(uint24_t pc);
//! @brief Return a printable string corresponding to the value of a absolute indexed by x addressing mode.
std::string _getAbsoluteIndexByXValue(uint24_t pc);
//! @brief Return a printable string corresponding to the value of a absolute indexed by x long addressing mode.
std::string _getAbsoluteIndexByXLongValue(uint24_t pc);
//! @brief Return a printable string corresponding to the value of a absolute indexed by y addressing mode.
std::string _getAbsoluteIndexByYValue(uint24_t pc);
//! @brief Return a printable string corresponding to the value of a direct index by x addressing mode.
std::string _getDirectIndexedByXValue(uint24_t pc);
//! @brief Return a printable string corresponding to the value of a direct index by y addressing mode.
std::string _getDirectIndexedByYValue(uint24_t pc);
//! @brief Return a printable string corresponding to the value of a direct indirect index by x addressing mode.
std::string _getDirectIndexedByXIndirectValue(uint24_t pc);
//! @brief Return a printable string corresponding to the value of a direct indirect index by y addressing mode.
std::string _getDirectIndirectIndexedByYValue(uint24_t pc);
//! @brief Return a printable string corresponding to the value of a direct indirect index by y long addressing mode.
std::string _getDirectIndirectIndexedByYLongValue(uint24_t pc);
//! @brief Return a printable string corresponding to the value of a stack relative addressing mode.
std::string _getStackRelativeValue(uint24_t pc);
//! @brief Return a printable string corresponding to the value of a stack relative indirect indexed by y addressing mode.
std::string _getStackRelativeIndiretIndexdeByYValue(uint24_t pc);
//! @brief Return a printable string corresponding to the value of a absolute indirect addressing mode.
std::string _getAbsoluteIndirectValue(uint24_t pc);
//! @brief Return a printable string corresponding to the value of a absolute indirect indexed by x addressing mode.
std::string _getAbsoluteIndirectIndexedByXValue(uint24_t pc);
//! @brief Return a printable string corresponding to the value of a absolute indirect long addressing mode.
std::string _getAbsoluteIndirectLongValue(uint24_t pc);
public:
//! @brief Pause/Resume the CPU.
+272
View File
@@ -0,0 +1,272 @@
//
// Created by anonymus-raccoon on 4/3/20.
//
#include <sstream>
#include "CPUDebug.hpp"
#include "../../Utility/Utility.hpp"
using namespace ComSquare::CPU;
namespace ComSquare::Debugger
{
DisassembledInstruction::DisassembledInstruction(const CPU::Instruction &instruction, uint24_t addr, std::string arg, uint8_t op)
: CPU::Instruction(instruction), address(addr), argument(std::move(arg)), opcode(op), level(Safe) {}
std::string DisassembledInstruction::toString()
{
return this->name + " " + this->argument;
}
std::vector<DisassembledInstruction> CPUDebug::_disassemble(uint24_t pc, uint24_t length, DisassemblyContext &ctx)
{
std::vector<DisassembledInstruction> map;
uint24_t endAddr = pc + length;
while (pc < endAddr) {
DisassembledInstruction instruction = this->_parseInstruction(pc, ctx);
instruction.level = ctx.level;
map.push_back(instruction);
pc += instruction.size;
if (instruction.addressingMode == ImmediateForA && !ctx.mFlag)
pc++;
if (instruction.addressingMode == ImmediateForX && !ctx.xFlag)
pc++;
if (instruction.opcode == 0x40 && ctx.isEmulationMode) { // RTI
ctx.mFlag = true;
ctx.xFlag = true;
}
if (instruction.opcode == 0xC2) { // REP
if (ctx.isEmulationMode) {
ctx.mFlag = true;
ctx.xFlag = true;
} else {
uint8_t m = this->_bus->read(pc - 1);
ctx.mFlag &= ~m & 0b00100000u;
ctx.xFlag &= ~m & 0b00010000u;
}
}
if (instruction.opcode == 0xE2) { // SEP
uint8_t m = this->_bus->read(pc - 1);
ctx.mFlag |= m & 0b00100000u;
ctx.xFlag |= m & 0b00010000u;
}
if (instruction.opcode == 0x28) { // PLP
if (ctx.isEmulationMode) {
ctx.mFlag = true;
ctx.xFlag = true;
} else
ctx.level = Compromised;
}
if (instruction.opcode == 0xFB) {// XCE
ctx.level = Unsafe;
ctx.isEmulationMode = false; // The most common use of the XCE is to enable native mode at the start of the ROM so we guess that it has done that.
}
}
return map;
}
DisassembledInstruction CPUDebug::_parseInstruction(uint24_t pc, DisassemblyContext &ctx)
{
uint24_t opcode = this->_bus->read(pc, true);
Instruction instruction = this->_instructions[opcode];
std::string argument = this->_getInstructionParameter(instruction, pc + 1, ctx);
return DisassembledInstruction(instruction, pc, argument, opcode);
}
std::string CPUDebug::_getInstructionParameter(Instruction &instruction, uint24_t pc, DisassemblyContext &ctx)
{
switch (instruction.addressingMode) {
case Implied:
return "";
case Immediate8bits:
return this->_getImmediateValue(pc, false);
case ImmediateForA:
return this->_getImmediateValue(pc, !ctx.mFlag);
case ImmediateForX:
return this->_getImmediateValue(pc, !ctx.xFlag);
case Absolute:
return this->_getAbsoluteValue(pc);
case AbsoluteLong:
return this->_getAbsoluteLongValue(pc);
case DirectPage:
return this->_getDirectValue(pc);
case DirectPageIndexedByX:
return this->_getDirectIndexedByXValue(pc);
case DirectPageIndirect:
return this->_getDirectIndirectValue(pc);
case DirectPageIndirectLong:
return this->_getDirectIndirectLongValue(pc);
case AbsoluteIndexedByX:
return this->_getAbsoluteIndexByXValue(pc);
case AbsoluteIndexedByXLong:
return this->_getAbsoluteIndexByXLongValue(pc);
case AbsoluteIndexedByY:
return this->_getAbsoluteIndexByYValue(pc);
case DirectPageIndexedByY:
return this->_getDirectIndexedByYValue(pc);
case DirectPageIndirectIndexedByX:
return this->_getDirectIndexedByXIndirectValue(pc);
case DirectPageIndirectIndexedByY:
return this->_getDirectIndirectIndexedByYValue(pc);
case DirectPageIndirectIndexedByYLong:
return this->_getDirectIndirectIndexedByYLongValue(pc);
case StackRelative:
return this->_getStackRelativeValue(pc);
case StackRelativeIndirectIndexedByY:
return this->_getStackRelativeIndiretIndexdeByYValue(pc);
case AbsoluteIndirect:
return this->_getAbsoluteIndirectValue(pc);
case AbsoluteIndirectIndexedByX:
return this->_getAbsoluteIndirectIndexedByXValue(pc);
case AbsoluteIndirectLong:
return this->_getAbsoluteIndirectLongValue(pc);
default:
return "???";
}
}
std::string CPUDebug::_getImmediateValue(uint24_t pc, bool dual)
{
unsigned value = this->_bus->read(pc, true);
if (dual)
value += this->_bus->read(pc + 1, true) << 8u;
std::stringstream ss;
ss << "#$" << std::hex << value;
return ss.str();
}
std::string CPUDebug::_getDirectValue(uint24_t pc)
{
return Utility::to_hex(this->_bus->read(pc, true), Utility::HexString::AsmPrefix);
}
std::string CPUDebug::_getAbsoluteValue(uint24_t pc)
{
uint24_t value = this->_bus->read(pc) + (this->_bus->read(pc + 1, true) << 8u);
return Utility::to_hex(value, Utility::HexString::AsmPrefix);
}
std::string CPUDebug::_getAbsoluteLongValue(uint24_t pc)
{
unsigned value = this->_bus->read(pc++, true);
value += this->_bus->read(pc++, true) << 8u;
value += this->_bus->read(pc, true) << 16u;
return Utility::to_hex(value, Utility::HexString::AsmPrefix);
}
std::string CPUDebug::_getDirectIndexedByXValue(uint24_t pc)
{
unsigned value = this->_bus->read(pc, true);
std::stringstream ss;
ss << "$" << std::hex << value << ", x";
return ss.str();
}
std::string CPUDebug::_getDirectIndexedByYValue(uint24_t pc)
{
unsigned value = this->_bus->read(pc, true);
std::stringstream ss;
ss << "$" << std::hex << value << ", y";
return ss.str();
}
std::string CPUDebug::_getDirectIndirectValue(uint24_t pc)
{
return "(" + Utility::to_hex(this->_bus->read(pc, true), Utility::AsmPrefix) + ")";
}
std::string CPUDebug::_getDirectIndirectLongValue(uint24_t pc)
{
return "[" + Utility::to_hex(this->_bus->read(pc, true), Utility::AsmPrefix) + "]";
}
std::string CPUDebug::_getAbsoluteIndexByXValue(uint24_t pc)
{
uint24_t value = this->_bus->read(pc) + (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);
return Utility::to_hex(value, Utility::HexString::AsmPrefix) + ", y";
}
std::string CPUDebug::_getAbsoluteIndexByXLongValue(uint24_t pc)
{
unsigned value = this->_bus->read(pc++, true);
value += this->_bus->read(pc++, true) << 8u;
value += this->_bus->read(pc, true) << 16u;
return Utility::to_hex(value, Utility::HexString::AsmPrefix) + ", x";
}
std::string CPUDebug::_getDirectIndexedByXIndirectValue(uint24_t pc)
{
unsigned value = this->_bus->read(pc, true);
std::stringstream ss;
ss << "($" << std::hex << value << ", x)";
return ss.str();
}
std::string CPUDebug::_getDirectIndirectIndexedByYValue(uint24_t pc)
{
unsigned value = this->_bus->read(pc, true);
std::stringstream ss;
ss << "($" << std::hex << value << "), y";
return ss.str();
}
std::string CPUDebug::_getDirectIndirectIndexedByYLongValue(uint24_t pc)
{
unsigned value = this->_bus->read(pc, true);
std::stringstream ss;
ss << "[$" << std::hex << value << "], y";
return ss.str();
}
std::string CPUDebug::_getStackRelativeValue(uint24_t pc)
{
return Utility::to_hex(this->_bus->read(pc, true), Utility::AsmPrefix) + ", s";
}
std::string CPUDebug::_getStackRelativeIndiretIndexdeByYValue(uint24_t pc)
{
return "(" + Utility::to_hex(this->_bus->read(pc, true), Utility::AsmPrefix) + ", s), y";
}
std::string CPUDebug::_getAbsoluteIndirectValue(uint24_t pc)
{
uint24_t value = this->_bus->read(pc) + (this->_bus->read(pc + 1, true) << 8u);
return "(" + Utility::to_hex(value, Utility::HexString::AsmPrefix) + ")";
}
std::string CPUDebug::_getAbsoluteIndirectLongValue(uint24_t pc)
{
unsigned value = this->_bus->read(pc++, true);
value += this->_bus->read(pc++, true) << 8u;
value += this->_bus->read(pc, true) << 16u;
return "(" + Utility::to_hex(value, Utility::HexString::AsmPrefix) + ")";
}
std::string CPUDebug::_getAbsoluteIndirectIndexedByXValue(uint24_t pc)
{
uint24_t value = this->_bus->read(pc) + (this->_bus->read(pc + 1, true) << 8u);
return "(" + Utility::to_hex(value, Utility::HexString::AsmPrefix) + ", x)";
}
}