Skip to content

Commit

Permalink
Merge pull request #9 from autc04/m68k-debugging
Browse files Browse the repository at this point in the history
M68K debugging and other improvements to the built-in debugger
  • Loading branch information
autc04 committed Feb 17, 2019
2 parents 90fe360 + b83f206 commit 3171cb4
Show file tree
Hide file tree
Showing 17 changed files with 832 additions and 207 deletions.
6 changes: 5 additions & 1 deletion src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,9 @@ set(base_sources

base/builtinlibs.h
base/builtinlibs.cpp

base/debugger.h
base/debugger.cpp
)
source_group(Base FILES ${base_sources})

Expand Down Expand Up @@ -397,7 +400,7 @@ set(prefs_sources
)

set(misc_sources
debugger.cpp
mon_debugger.cpp
desk.cpp device.cpp disk.cpp diskinit.cpp dump.cpp
gestalt.cpp iu.cpp launch.cpp notify.cpp
osutil.cpp pack.cpp scrap.cpp script.cpp segment.cpp serial.cpp
Expand Down Expand Up @@ -479,6 +482,7 @@ set(include_sources
include/rsys/macros.h
include/rsys/macstrings.h
include/rsys/mixed_mode.h
include/rsys/mon_debugger.h
include/rsys/noreturn.h
include/rsys/os.h
include/rsys/osutil.h
Expand Down
159 changes: 159 additions & 0 deletions src/base/debugger.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
#include "debugger.h"
#include <base/cpu.h>
#include <base/mactype.h>
#include <PowerCore.h>
#include <cassert>

using namespace Executor;
using namespace Executor::base;

Debugger *Debugger::instance = nullptr;

Debugger::Debugger()
{
PowerCore& cpu = getPowerCore();
cpu.debugger = [](PowerCore& cpu) {
cpu.CIA = instance->interact1({ Reason::breakpoint, nullptr, CPUMode::ppc, cpu.CIA });
};
cpu.getNextBreakpoint = [](uint32_t addr) -> uint32_t {
return instance->getNextBreakpoint(addr, 4);
};

syn68k_debugger_callbacks.debugger = [](uint32_t addr) -> uint32_t {
return instance->interact1({ Reason::breakpoint, nullptr, CPUMode::m68k, addr });
};
syn68k_debugger_callbacks.getNextBreakpoint = [](uint32_t addr) -> uint32_t {
return instance->getNextBreakpoint(addr, 1);
};

traps::entrypoints["Debugger"]->breakpoint = true;
}

Debugger::~Debugger()
{
PowerCore& cpu = getPowerCore();
cpu.debugger = nullptr;
cpu.getNextBreakpoint = nullptr;
syn68k_debugger_callbacks.debugger = nullptr;
syn68k_debugger_callbacks.getNextBreakpoint = nullptr;
}

uint32_t Debugger::interact1(DebuggerEntry entry)
{
DebuggerExit exit = interact(entry);
singlestep = exit.singlestep;
singlestepFrom = exit.addr;
getPowerCore().flushCache();
ROMlib_destroy_blocks(0, ~0, false);
return exit.addr;
}

uint32_t Debugger::nmi68K(uint32_t /*interruptCallbackAddr*/)
{
uint16_t frameType = (*ptr_from_longint<GUEST<uint16_t>*>(EM_A7 + 6)) >> 12;
assert(frameType == 0);

uint16_t sr = *ptr_from_longint<GUEST<uint16_t>*>(EM_A7);
uint32_t addr = *ptr_from_longint<GUEST<uint32_t>*>(EM_A7 + 2);
EM_A7 += 8;

assert((cpu_state.sr & 0x3000) == (sr & 0x3000)); // we should not need to switch stacks
cpu_state.sr = sr & ~31;
cpu_state.ccc = sr & 1;
cpu_state.ccv = sr & 2;
cpu_state.ccnz = ~sr & 4;
cpu_state.ccn = sr & 8;
cpu_state.ccx = sr & 16;
interrupt_note_if_present();

return interact1({ Reason::nmi, nullptr, CPUMode::m68k, addr });
}

void Debugger::nmiPPC()
{
PowerCore& cpu = getPowerCore();
cpu.CIA = interact1({ Reason::nmi, nullptr, CPUMode::ppc, cpu.CIA });
}

uint32_t Debugger::trapBreak68K(uint32_t addr, const char *name)
{
if(continuingFromEntrypoint)
{
continuingFromEntrypoint = false;
return ~0;
}

// figure out whether this was invoked via a trap
// (as opposed to function pointer)
uint32_t retaddr = *ptr_from_longint<GUEST<uint32_t>*>(EM_A7);

uint16_t potentialTrap = *ptr_from_longint<GUEST<uint16_t>*>(retaddr-2);
uint32_t trapaddr = 0;
if((potentialTrap & 0xF000) == 0xA000)
{
if(potentialTrap & TOOLBIT)
trapaddr = tooltraptable[potentialTrap & 0x3FF];
else
trapaddr = ostraptable[potentialTrap & 0xFF];
}

// if it's a trap call, pop stuff from the stack
if(trapaddr == addr)
{
addr = retaddr - 2;
EM_A7 += 4;
}

uint32_t newAddr = interact1({ Reason::entrypoint, name, CPUMode::m68k, addr });

if(addr == newAddr)
continuingFromEntrypoint = true;

return newAddr;
}

uint32_t Debugger::trapBreakPPC(PowerCore& cpu, const char *name)
{
if(continuingFromEntrypoint)
{
continuingFromEntrypoint = false;
return ~0;
}

// pop one stack frame so we are not in the emulator callback stub
cpu.CIA = cpu.lr -4;
cpu.r[2] = *ptr_from_longint<GUEST<uint32>*>(cpu.r[1]+0x14);
cpu.lr = *ptr_from_longint<GUEST<uint32>*>(cpu.r[1]+0x8);

uint32_t addr = cpu.CIA;
uint32_t newAddr = interact1({ Reason::entrypoint, name, CPUMode::ppc, addr });

if(addr == newAddr)
continuingFromEntrypoint = true;

return newAddr;
}

uint32_t Debugger::getNextBreakpoint(uint32_t addr, uint32_t nextOffset)
{
if(singlestep)
{
if(addr == singlestepFrom)
return addr + nextOffset;
else
return addr;
}

auto breakpoint_it = breakpoints.lower_bound(addr);
if(breakpoint_it == breakpoints.end())
return 0xFFFFFFFF;
else
return *breakpoint_it;
}

void Debugger::initProcess(uint32_t entrypoint)
{
breakpoints.clear();
if(breakOnProcessEntry)
breakpoints.insert(entrypoint);
}
68 changes: 68 additions & 0 deletions src/base/debugger.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
#pragma once

#include <base/cpu.h>

#include <stdint.h>
#include <set>

namespace Executor
{
namespace base
{
class Debugger
{
public:
Debugger();
~Debugger();

uint32_t nmi68K(uint32_t addr);
void nmiPPC();
uint32_t trapBreak68K(uint32_t addr, const char *name);
uint32_t trapBreakPPC(PowerCore& cpu, const char *name);

static Debugger *instance;

virtual bool interruptRequested() { return false; }

void initProcess(uint32_t entrypoint);

void setBreakOnProcessEntry(bool dobreak) { breakOnProcessEntry = dobreak; }
protected:
enum class Reason
{
nmi,
breakpoint,
singlestep,
entrypoint,
debugger_call,
debugstr_call
};

struct DebuggerEntry
{
Reason reason;
const char* str;
CPUMode mode;
uint32_t addr;
};

struct DebuggerExit
{
uint32_t addr;
bool singlestep = false;
};

virtual DebuggerExit interact(DebuggerEntry e) = 0;

std::set<uint32_t> breakpoints;
private:
uint32_t getNextBreakpoint(uint32_t addr, uint32_t nextOffset);
uint32_t interact1(DebuggerEntry e);

bool singlestep = false;
bool continuingFromEntrypoint = false;
uint32_t singlestepFrom;
bool breakOnProcessEntry = false;
};
}
}
35 changes: 30 additions & 5 deletions src/base/traps.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,26 @@
#include <base/functions.impl.h>
#include <base/logging.h>
#include <base/dispatcher.h>
#include <base/debugger.h>

#include <assert.h>

using namespace Executor;

syn68k_addr_t Executor::tooltraptable[NTOOLENTRIES]; /* Gets filled in at run time */
syn68k_addr_t Executor::ostraptable[NOSENTRIES]; /* Gets filled in at run time */

namespace Executor
{
RAW_68K_TRAP(Unimplemented, 0xA89F);
void ReferenceAllTraps();
}

Executor::traps::internal::DeferredInit *Executor::traps::internal::DeferredInit::first = nullptr;
Executor::traps::internal::DeferredInit *Executor::traps::internal::DeferredInit::last = nullptr;

std::unordered_map<std::string, traps::Entrypoint*> Executor::traps::entrypoints;

traps::internal::DeferredInit::DeferredInit()
: next(nullptr)
{
Expand All @@ -33,15 +45,28 @@ void traps::internal::DeferredInit::initAll()
p->init();
}

syn68k_addr_t Executor::tooltraptable[NTOOLENTRIES]; /* Gets filled in at run time */
syn68k_addr_t Executor::ostraptable[NOSENTRIES]; /* Gets filled in at run time */
void traps::Entrypoint::init()
{
entrypoints[name] = this;
}

namespace Executor
uint32_t traps::Entrypoint::break68K(uint32_t addr)
{
RAW_68K_TRAP(Unimplemented, 0xA89F);
void ReferenceAllTraps();
if(base::Debugger::instance)
return base::Debugger::instance->trapBreak68K(addr, name);
else
return (uint32_t)~0;
}

uint32_t traps::Entrypoint::breakPPC(PowerCore& cpu)
{
if(base::Debugger::instance)
return base::Debugger::instance->trapBreakPPC(cpu, name);
else
return (uint32_t)~0;
}


void traps::init(bool log)
{
logging::setEnabled(log);
Expand Down
Loading

0 comments on commit 3171cb4

Please sign in to comment.