Skip to content
7 changes: 2 additions & 5 deletions ares/component/processor/arm7tdmi/instruction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,8 @@ auto ARM7TDMI::armInitialize() -> void {
opcode.bit( 0, 3), /* m */ \
opcode.bit(12,15), /* d */ \
opcode.bit(16,19) /* field */
for(n4 m : range(16))
for(n2 _ : range(4))
for(n4 d : range(16))
for(n4 field : range(16)) {
auto opcode = pattern(".... 0001 0010 ???? ???? ---- 0??1 ????") | m << 0 | _ << 5 | d << 12 | field << 16;
for(n2 _ : range(4)) {
auto opcode = pattern(".... 0001 0010 ???? ???? ---- 0??1 ????") | _ << 5;
bind(opcode, BranchExchangeRegister);
}
#undef arguments
Expand Down
12 changes: 12 additions & 0 deletions ares/component/processor/sh2/exceptions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ auto SH2::interrupt(u8 level, u8 vector) -> void {
}

auto SH2::addressErrorCPU() -> void {
if (GDB::server.hasActiveClient) {
GDB::server.reportSignal(GDB::Signal::BUS, PC - 4);
}
static constexpr u8 vector = 0x09;
SP &= ~3; //not accurate; but prevents infinite recursion
push(SR);
Expand All @@ -48,6 +51,9 @@ auto SH2::addressErrorCPU() -> void {
}

auto SH2::addressErrorDMA() -> void {
if (GDB::server.hasActiveClient) {
GDB::server.reportSignal(GDB::Signal::BUS, PC - 4);
}
static constexpr u8 vector = 0x0a;
SP &= ~3; //not accurate; but prevents infinite recursion
push(SR);
Expand All @@ -57,6 +63,9 @@ auto SH2::addressErrorDMA() -> void {

auto SH2::illegalInstruction() -> void {
if(inDelaySlot()) return illegalSlotInstruction();
if (GDB::server.hasActiveClient) {
GDB::server.reportSignal(GDB::Signal::ILL, PC - 4);
}
debug(unusual, "[SH2] illegal instruction: 0x", hex(busReadWord(PC - 4), 4L), " @ 0x", hex(PC - 4));
static constexpr u8 vector = 0x04;
push(SR);
Expand All @@ -65,6 +74,9 @@ auto SH2::illegalInstruction() -> void {
}

auto SH2::illegalSlotInstruction() -> void {
if (GDB::server.hasActiveClient) {
GDB::server.reportSignal(GDB::Signal::ILL, PC - 4);
}
debug(unusual, "[SH2] illegal slot instruction: 0x", hex(busReadWord(PC - 4), 4L));
static constexpr u8 vector = 0x06;
push(SR);
Expand Down
1 change: 1 addition & 0 deletions ares/component/processor/sh2/sh2.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#include <nall/recompiler/generic/generic.hpp>
#include <nall/gdb/server.hpp>

//Hitachi SH-2

Expand Down
92 changes: 92 additions & 0 deletions ares/md/m32x/m32x.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ auto M32X::load(Node::Object parent) -> void {
vectors.allocate(fp->size() >> 1);
for(auto address : range(vectors.size())) vectors.program(address, fp->readm(2L));
}

initDebugHooks();
}

auto M32X::unload() -> void {
Expand Down Expand Up @@ -92,4 +94,94 @@ auto M32X::hblank(bool line) -> void {
}
}

auto M32X::initDebugHooks() -> void {

// See: https://sourceware.org/gdb/onlinedocs/gdb/Target-Description-Format.html#Target-Description-Format
GDB::server.hooks.targetXML = []() -> string {
return "<target version=\"1.0\">"
"<architecture>sh2</architecture>"
"</target>";
};

GDB::server.hooks.normalizeAddress = [](u64 address) -> u64 {
return address & 0x00FFFFFF;
};

GDB::server.hooks.read = [](u64 address, u32 byteCount) -> string {
address = (s32)address;

string res{};
res.resize(byteCount * 2);
char* resPtr = res.begin();

for(u32 i : range(byteCount)) {
auto val = m32x.shm.readByte(address++);
hexByte(resPtr, val);
resPtr += 2;
}

return res;
};

GDB::server.hooks.regRead = [this](u32 regIdx) {
if(regIdx < 16) {
return hex(shm.regs.R[regIdx], 8, '0');
}

switch (regIdx)
{
case 16: return hex(shm.regs.PC - 4, 8, '0');
case 17: return hex(shm.regs.PR, 8, '0');
case 18: return hex(shm.regs.GBR, 8, '0');
case 19: return hex(shm.regs.VBR, 8, '0');
case 20: return hex(shm.regs.MACH, 8, '0');
case 21: return hex(shm.regs.MACL, 8, '0');
case 22: return hex((u32)shm.regs.SR, 8, '0');
}

return string{"00000000"};
};

GDB::server.hooks.regWrite = [this](u32 regIdx, u64 regValue) -> bool {
if(regIdx < 16) {
shm.regs.R[regIdx] = (u32)regValue; return true;
}

switch (regIdx)
{
case 16: shm.regs.PC = (u32)regValue; return true;
case 17: shm.regs.PR = (u32)regValue; return true;
case 18: shm.regs.GBR = (u32)regValue; return true;
case 19: shm.regs.VBR = (u32)regValue; return true;
case 20: shm.regs.MACH = (u32)regValue; return true;
case 21: shm.regs.MACL = (u32)regValue; return true;
case 22: shm.regs.SR = (u32)regValue; return true;
}

return false;
};

GDB::server.hooks.regReadGeneral = []() {
string res{};
for(auto i : range(23)) {
res.append(GDB::server.hooks.regRead(i));
}
return res;
};

GDB::server.hooks.regWriteGeneral = [](const string &regData) {
u32 regIdx{0};
for(auto i=0; i<regData.size(); i+=8) {
GDB::server.hooks.regWrite(regIdx, regData.slice(i, 8).hex());
++regIdx;
}
};

if constexpr(SH2::Accuracy::Recompiler) {
GDB::server.hooks.emuCacheInvalidate = [](u64 address) {
m32x.shm.recompiler.invalidate(address, 4);
};
}
}

}
3 changes: 3 additions & 0 deletions ares/md/m32x/m32x.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ struct M32X {
s32 cyclesUntilM68kSync = 0;
s32 minCyclesBetweenSh2Syncs = 0;
s32 minCyclesBetweenM68kSyncs = 0;
s32 updateLoopCounter;
};

struct VDP {
Expand Down Expand Up @@ -188,6 +189,8 @@ struct M32X {
auto vblank(bool) -> void;
auto hblank(bool) -> void;

auto initDebugHooks() -> void;

//bus-internal.cpp
auto readInternal(n1 upper, n1 lower, n32 address, n16 data = 0) -> n16;
auto writeInternal(n1 upper, n1 lower, n32 address, n16 data) -> void;
Expand Down
34 changes: 34 additions & 0 deletions ares/md/m32x/sh7604.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,21 @@ auto M32X::SH7604::unload() -> void {
}

auto M32X::SH7604::main() -> void {
if (GDB::server.hasActiveClient && m32x.shm.active()) {
updateLoopCounter--;

if (!GDB::server.reportDelayedPC(regs.PC)) {
if (!updateLoopCounter) {
GDB::server.updateLoop();
updateLoopCounter = 23000000 / 60 / 240;
}
return;
} else if (!updateLoopCounter) {
GDB::server.updateLoop();
updateLoopCounter = 23000000 / 60;
}
}

if(!m32x.io.adapterReset) return step(1000);

if(!regs.ID) {
Expand Down Expand Up @@ -93,6 +108,7 @@ auto M32X::SH7604::power(bool reset) -> void {
SH2::power(reset);
irq = {};
irq.vres.enable = 1;
updateLoopCounter = 23000000 / 60;
}

auto M32X::SH7604::restart() -> void {
Expand Down Expand Up @@ -134,6 +150,9 @@ auto M32X::SH7604::syncM68k(bool force) -> void {
}

auto M32X::SH7604::busReadByte(u32 address) -> u32 {
if (GDB::server.hasActiveClient && m32x.shm.active()) {
GDB::server.reportMemRead(address, 1);
}
if(address & 1) {
return m32x.readInternal(0, 1, address & ~1).byte(0);
} else {
Expand All @@ -142,15 +161,24 @@ auto M32X::SH7604::busReadByte(u32 address) -> u32 {
}

auto M32X::SH7604::busReadWord(u32 address) -> u32 {
if (GDB::server.hasActiveClient && m32x.shm.active()) {
GDB::server.reportMemRead(address, 2);
}
return m32x.readInternal(1, 1, address & ~1);
}

auto M32X::SH7604::busReadLong(u32 address) -> u32 {
if (GDB::server.hasActiveClient && m32x.shm.active()) {
GDB::server.reportMemRead(address, 4);
}
u32 data = m32x.readInternal(1, 1, address & ~3 | 0) << 16;
return data | m32x.readInternal(1, 1, address & ~3 | 2) << 0;
}

auto M32X::SH7604::busWriteByte(u32 address, u32 data) -> void {
if (GDB::server.hasActiveClient && m32x.shm.active()) {
GDB::server.reportMemWrite(address, 1);
}
debugger.tracer.instruction->invalidate(address & ~1);
if(address & 1) {
m32x.writeInternal(0, 1, address & ~1, data << 8 | (u8)data << 0);
Expand All @@ -160,11 +188,17 @@ auto M32X::SH7604::busWriteByte(u32 address, u32 data) -> void {
}

auto M32X::SH7604::busWriteWord(u32 address, u32 data) -> void {
if (GDB::server.hasActiveClient && m32x.shm.active()) {
GDB::server.reportMemWrite(address, 2);
}
debugger.tracer.instruction->invalidate(address & ~1);
m32x.writeInternal(1, 1, address & ~1, data);
}

auto M32X::SH7604::busWriteLong(u32 address, u32 data) -> void {
if (GDB::server.hasActiveClient && m32x.shm.active()) {
GDB::server.reportMemWrite(address, 4);
}
debugger.tracer.instruction->invalidate(address & ~3 | 0);
debugger.tracer.instruction->invalidate(address & ~3 | 2);
m32x.writeInternal(1, 1, address & ~3 | 0, data >> 16);
Expand Down
1 change: 1 addition & 0 deletions ares/md/md.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <component/audio/sn76489/sn76489.hpp>
#include <component/audio/ym2612/ym2612.hpp>
#include <component/eeprom/m24c/m24c.hpp>
#include <nall/gdb/server.hpp>

namespace ares::MegaDrive {
#include <ares/inline.hpp>
Expand Down
25 changes: 24 additions & 1 deletion nall/nall/gdb/server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,29 @@ namespace nall::GDB {
return !needHalts;
}

auto Server::reportDelayedPC(u64 pc) -> bool {
if(!hasActiveClient)return true;

currentPC = pc;
bool needHalts = forceHalt || breakpoints.contains(pc - 4);

if(needHalts) {
forceHalt = true; // breakpoints may get deleted after a signal, but we have to stay stopped

if(!haltSignalSent) {
haltSignalSent = true;
sendSignal(Signal::TRAP);
}
}

if(singleStepActive) {
singleStepActive = false;
forceHalt = true;
}

return !needHalts;
}

/**
* NOTE: please read the comment in the header server.hpp file before making any changes here!
*/
Expand All @@ -115,7 +138,7 @@ namespace nall::GDB {
char cmdPrefix = cmdName.size() > 0 ? cmdName(0) : ' ';

if constexpr(GDB_LOG_MESSAGES) {
print("GDB <: %s\n", cmdBuffer.data());
printf("GDB <: %s\n", cmdBuffer.data());
}

switch(cmdPrefix)
Expand Down
4 changes: 3 additions & 1 deletion nall/nall/gdb/server.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ class Server : public nall::TCPText::Server {

// PC / Memory State Updates
auto reportPC(u64 pc) -> bool;
auto reportDelayedPC(u64 pc) -> bool;
auto reportMemRead(u64 address, u32 size) -> void;
auto reportMemWrite(u64 address, u32 size) -> void;

Expand All @@ -101,6 +102,8 @@ class Server : public nall::TCPText::Server {

auto updateLoop() -> void;
auto getStatusText(u32 port, bool useIPv4) -> string;

bool hasActiveClient{false};

protected:
auto onText(string_view text) -> void override;
Expand All @@ -120,7 +123,6 @@ class Server : public nall::TCPText::Server {
bool handshakeDone{false}; // set to true after a few handshake commands, used to prevent exception-reporting until client is ready
bool requestDisconnect{false}; // set to true if the client decides it wants to disconnect

bool hasActiveClient{false};
u32 messageCount{0}; // message count per update loop
s32 currentThreadC{-1}; // selected thread for the next 'c' command

Expand Down