mirror of
https://github.com/RetroDECK/Supermodel.git
synced 2025-02-16 17:35:39 +00:00
Changes to debugger classes:
- fixed step-out to work properly - added ability to enable/disable debugging of individual CPUs Changes to console-based debugger: - tidied up syntax and split some commands out to make easier to use - implemented missing commands (loademustate, saveemustate, resetemu, configinput, configallinputs, help) - added new commands (nextframe, enablecpu, disablecpu, removeallcomments) - added ability to redirect command output to a file
This commit is contained in:
parent
0153a02b19
commit
8e2e8adeb3
|
@ -12,11 +12,11 @@ namespace Debugger
|
||||||
CCPUDebug::CCPUDebug(const char *cpuName, UINT8 cpuMinInstrLen, UINT8 cpuMaxInstrLen, bool cpuBigEndian, UINT8 cpuMemBusWidth, UINT8 cpuMaxMnemLen) :
|
CCPUDebug::CCPUDebug(const char *cpuName, UINT8 cpuMinInstrLen, UINT8 cpuMaxInstrLen, bool cpuBigEndian, UINT8 cpuMemBusWidth, UINT8 cpuMaxMnemLen) :
|
||||||
name(cpuName), minInstrLen(cpuMinInstrLen), maxInstrLen(cpuMaxInstrLen),
|
name(cpuName), minInstrLen(cpuMinInstrLen), maxInstrLen(cpuMaxInstrLen),
|
||||||
bigEndian(cpuBigEndian), memBusWidth(cpuMemBusWidth), maxMnemLen(cpuMaxMnemLen),
|
bigEndian(cpuBigEndian), memBusWidth(cpuMemBusWidth), maxMnemLen(cpuMaxMnemLen),
|
||||||
addrFmt(HexDollar), portFmt(Decimal), dataFmt(HexDollar), debugger(NULL),
|
enabled(true), addrFmt(HexDollar), portFmt(Decimal), dataFmt(HexDollar), debugger(NULL),
|
||||||
numExCodes(0), numIntCodes(0), numPorts(0), memSize(0), instrCount(0), pc(0), opcode(0),
|
numExCodes(0), numIntCodes(0), numPorts(0), memSize(0), instrCount(0), pc(0), opcode(0),
|
||||||
m_break(false), m_userBreak(false), m_step(false), m_steppingOver(false), m_steppingOut(false), m_count(0), m_until(false), m_untilAddr(0),
|
m_break(false), m_userBreak(false), m_step(false), m_steppingOver(false), m_steppingOut(false), m_count(0), m_until(false), m_untilAddr(0),
|
||||||
m_mappedIOTable(NULL), m_memWatchTable(NULL), m_bpTable(NULL), m_numRegMons(0), m_regMonArray(NULL), m_analyser(NULL),
|
m_mappedIOTable(NULL), m_memWatchTable(NULL), m_bpTable(NULL), m_numRegMons(0), m_regMonArray(NULL),
|
||||||
m_stateUpdated(false), m_exTrapped(NULL), m_intTrapped(NULL), m_bpReached(NULL),
|
m_analyser(NULL), m_stateUpdated(false), m_exRaised(NULL), m_exTrapped(NULL), m_intRaised(NULL), m_intTrapped(NULL), m_bpReached(NULL),
|
||||||
m_memWatchTriggered(NULL), m_ioWatchTriggered(NULL), m_regMonTriggered(NULL)
|
m_memWatchTriggered(NULL), m_ioWatchTriggered(NULL), m_regMonTriggered(NULL)
|
||||||
{
|
{
|
||||||
memset(m_exArray, NULL, sizeof(m_exArray));
|
memset(m_exArray, NULL, sizeof(m_exArray));
|
||||||
|
@ -1171,6 +1171,7 @@ namespace Debugger
|
||||||
if (ex == NULL)
|
if (ex == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
m_exRaised = ex;
|
||||||
ex->count++;
|
ex->count++;
|
||||||
if (!ex->trap)
|
if (!ex->trap)
|
||||||
return;
|
return;
|
||||||
|
@ -1188,6 +1189,7 @@ namespace Debugger
|
||||||
if (in == NULL)
|
if (in == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
m_intRaised = in;
|
||||||
in->count++;
|
in->count++;
|
||||||
if (!in->trap)
|
if (!in->trap)
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -104,16 +104,18 @@ namespace Debugger
|
||||||
void DetachFromDebugger(CDebugger *theDebugger);
|
void DetachFromDebugger(CDebugger *theDebugger);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
CCodeAnalyser *m_analyser;
|
||||||
|
|
||||||
bool m_stateUpdated;
|
bool m_stateUpdated;
|
||||||
|
CException *m_exRaised;
|
||||||
CException *m_exTrapped;
|
CException *m_exTrapped;
|
||||||
|
CInterrupt *m_intRaised;
|
||||||
CInterrupt *m_intTrapped;
|
CInterrupt *m_intTrapped;
|
||||||
CBreakpoint *m_bpReached;
|
CBreakpoint *m_bpReached;
|
||||||
CWatch *m_memWatchTriggered;
|
CWatch *m_memWatchTriggered;
|
||||||
CWatch *m_ioWatchTriggered;
|
CWatch *m_ioWatchTriggered;
|
||||||
CRegMonitor *m_regMonTriggered;
|
CRegMonitor *m_regMonTriggered;
|
||||||
|
|
||||||
CCodeAnalyser *m_analyser;
|
|
||||||
|
|
||||||
CCPUDebug(const char *cpuName, UINT8 cpuMinInstrLen, UINT8 cpuMaxInstrLen, bool cpuBigEndian, UINT8 cpuMemBusWidth, UINT8 cpuMaxMnemLen);
|
CCPUDebug(const char *cpuName, UINT8 cpuMinInstrLen, UINT8 cpuMaxInstrLen, bool cpuBigEndian, UINT8 cpuMemBusWidth, UINT8 cpuMaxMnemLen);
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -163,6 +165,7 @@ namespace Debugger
|
||||||
const UINT8 memBusWidth;
|
const UINT8 memBusWidth;
|
||||||
const UINT8 maxMnemLen;
|
const UINT8 maxMnemLen;
|
||||||
|
|
||||||
|
bool enabled;
|
||||||
EFormat addrFmt;
|
EFormat addrFmt;
|
||||||
EFormat portFmt;
|
EFormat portFmt;
|
||||||
EFormat dataFmt;
|
EFormat dataFmt;
|
||||||
|
@ -173,6 +176,7 @@ namespace Debugger
|
||||||
UINT16 numIntCodes;
|
UINT16 numIntCodes;
|
||||||
UINT16 numPorts;
|
UINT16 numPorts;
|
||||||
UINT32 memSize;
|
UINT32 memSize;
|
||||||
|
|
||||||
UINT64 instrCount;
|
UINT64 instrCount;
|
||||||
UINT32 pc;
|
UINT32 pc;
|
||||||
UINT32 opcode;
|
UINT32 opcode;
|
||||||
|
@ -744,6 +748,16 @@ namespace Debugger
|
||||||
|
|
||||||
inline bool CCPUDebug::CheckExecution(UINT32 newPC, UINT32 newOpcode)
|
inline bool CCPUDebug::CheckExecution(UINT32 newPC, UINT32 newOpcode)
|
||||||
{
|
{
|
||||||
|
// Check if debugging is enabled for this CPU
|
||||||
|
if (!enabled)
|
||||||
|
{
|
||||||
|
// If not, update instruction count, pc and opcode but don't allow any execution control
|
||||||
|
instrCount++;
|
||||||
|
pc = newPC;
|
||||||
|
opcode = newOpcode;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Check not just updating state
|
// Check not just updating state
|
||||||
bool stepBreak, countBreak, untilBreak;
|
bool stepBreak, countBreak, untilBreak;
|
||||||
if (!m_stateUpdated)
|
if (!m_stateUpdated)
|
||||||
|
@ -764,7 +778,7 @@ namespace Debugger
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now increase instruction count and update pc and opcode
|
// Now update instruction count, pc and opcode
|
||||||
instrCount++;
|
instrCount++;
|
||||||
pc = newPC;
|
pc = newPC;
|
||||||
opcode = newOpcode;
|
opcode = newOpcode;
|
||||||
|
@ -799,16 +813,17 @@ namespace Debugger
|
||||||
stepBreak = !m_steppingOver || pc == m_stepOverAddr;
|
stepBreak = !m_steppingOver || pc == m_stepOverAddr;
|
||||||
break;
|
break;
|
||||||
case StepOut:
|
case StepOut:
|
||||||
// Step-out steps over any jumps and breaks when it reaches a return
|
// Step-out steps over any jumps and breaks when it reaches a return or an exception/interrupt is raised
|
||||||
// TODO - following doesn't work if an exception occurs before the return
|
if (m_exRaised != NULL || m_intRaised != NULL)
|
||||||
if (m_steppingOver)
|
stepBreak = true;
|
||||||
|
else if (m_steppingOver)
|
||||||
{
|
{
|
||||||
if (pc == m_stepOverAddr)
|
if (pc == m_stepOverAddr)
|
||||||
m_steppingOver = false;
|
m_steppingOver = false;
|
||||||
stepBreak = false;
|
stepBreak = false;
|
||||||
}
|
}
|
||||||
else if (m_steppingOut)
|
else
|
||||||
stepBreak = pc == m_stepOutAddr;
|
stepBreak = m_steppingOut && pc == m_stepOutAddr;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
stepBreak = false;
|
stepBreak = false;
|
||||||
|
@ -825,7 +840,7 @@ namespace Debugger
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Update pc and opcode
|
// Just updating state so update pc and opcode, but do not update instruction count
|
||||||
pc = newPC;
|
pc = newPC;
|
||||||
opcode = newOpcode;
|
opcode = newOpcode;
|
||||||
|
|
||||||
|
@ -867,7 +882,9 @@ namespace Debugger
|
||||||
m_steppingOut = false;
|
m_steppingOut = false;
|
||||||
m_count = 0;
|
m_count = 0;
|
||||||
m_until = false;
|
m_until = false;
|
||||||
|
m_exRaised = NULL;
|
||||||
m_exTrapped = NULL;
|
m_exTrapped = NULL;
|
||||||
|
m_intRaised = NULL;
|
||||||
m_intTrapped = NULL;
|
m_intTrapped = NULL;
|
||||||
m_bpReached = NULL;
|
m_bpReached = NULL;
|
||||||
m_memWatchTriggered = NULL;
|
m_memWatchTriggered = NULL;
|
||||||
|
@ -894,8 +911,6 @@ namespace Debugger
|
||||||
// If stepping out, then make sure step over any jumps and if encounter a return instruction then break at return address
|
// If stepping out, then make sure step over any jumps and if encounter a return instruction then break at return address
|
||||||
if (m_step && m_stepMode == StepOut)
|
if (m_step && m_stepMode == StepOut)
|
||||||
{
|
{
|
||||||
// TODO - following is flakey, for example if an exception occurs whilst stepping out, then it obviously doesn't work
|
|
||||||
// - really ought to keep proper call stack, but harder to implement and will slow down debugger even more
|
|
||||||
if (!m_steppingOver)
|
if (!m_steppingOver)
|
||||||
m_steppingOver = GetJumpRetAddr(pc, opcode, m_stepOverAddr);
|
m_steppingOver = GetJumpRetAddr(pc, opcode, m_stepOverAddr);
|
||||||
if (!m_steppingOver)
|
if (!m_steppingOver)
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -7,6 +7,7 @@
|
||||||
#include "Types.h"
|
#include "Types.h"
|
||||||
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
#define NUM_LISTAUTOLABELS (sizeof(s_listAutoLabels) / sizeof(ELabelFlags))
|
#define NUM_LISTAUTOLABELS (sizeof(s_listAutoLabels) / sizeof(ELabelFlags))
|
||||||
|
|
||||||
|
@ -16,6 +17,7 @@ namespace Debugger
|
||||||
class CException;
|
class CException;
|
||||||
class CWatch;
|
class CWatch;
|
||||||
class CBreakpoint;
|
class CBreakpoint;
|
||||||
|
class CRegister;
|
||||||
class CRegMonitor;
|
class CRegMonitor;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -29,6 +31,9 @@ namespace Debugger
|
||||||
|
|
||||||
CCPUDebug *m_cpu;
|
CCPUDebug *m_cpu;
|
||||||
|
|
||||||
|
bool m_nextFrame;
|
||||||
|
unsigned m_nextFrameCount;
|
||||||
|
|
||||||
UINT32 m_listDism;
|
UINT32 m_listDism;
|
||||||
UINT32 m_listMem;
|
UINT32 m_listMem;
|
||||||
|
|
||||||
|
@ -41,11 +46,27 @@ namespace Debugger
|
||||||
bool m_showOpCodes;
|
bool m_showOpCodes;
|
||||||
unsigned m_memBytesPerRow;
|
unsigned m_memBytesPerRow;
|
||||||
|
|
||||||
|
FILE *m_file;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
void Read(char *str, size_t maxLen);
|
||||||
|
|
||||||
|
void Print(const char *fmtStr, ...);
|
||||||
|
|
||||||
|
void Error(const char *fmtStr, ...);
|
||||||
|
|
||||||
|
void PrintVL(const char *fmtStr, va_list vl);
|
||||||
|
|
||||||
|
void Flush();
|
||||||
|
|
||||||
bool CheckToken(const char *token, const char *simple, const char *full);
|
bool CheckToken(const char *token, const char *simple, const char *full);
|
||||||
|
|
||||||
|
bool CheckToken(const char *token, const char *simple, const char *full, char *modifier, size_t modSize, const char *defaultMod);
|
||||||
|
|
||||||
void Truncate(char *dst, size_t maxLen, const char *src);
|
void Truncate(char *dst, size_t maxLen, const char *src);
|
||||||
|
|
||||||
|
void UpperFirst(char *dst, const char *src);
|
||||||
|
|
||||||
void FormatOpCodes(char *str, int addr, int codesLen);
|
void FormatOpCodes(char *str, int addr, int codesLen);
|
||||||
|
|
||||||
bool GetLabelText(char *str, int maxLen, UINT32 addr);
|
bool GetLabelText(char *str, int maxLen, UINT32 addr);
|
||||||
|
@ -62,6 +83,10 @@ namespace Debugger
|
||||||
|
|
||||||
bool ParseDataSize(const char *str, unsigned &dataSize);
|
bool ParseDataSize(const char *str, unsigned &dataSize);
|
||||||
|
|
||||||
|
bool ParseCPU(const char *str, CCPUDebug *&cpu);
|
||||||
|
|
||||||
|
bool ParseRegister(const char *str, CRegister *®);
|
||||||
|
|
||||||
void ListCPUs();
|
void ListCPUs();
|
||||||
|
|
||||||
void ListRegisters();
|
void ListRegisters();
|
||||||
|
@ -92,10 +117,6 @@ namespace Debugger
|
||||||
|
|
||||||
UINT32 ListMemory(UINT32 start, UINT32 end, unsigned bytesPerRow);
|
UINT32 ListMemory(UINT32 start, UINT32 end, unsigned bytesPerRow);
|
||||||
|
|
||||||
void Attach();
|
|
||||||
|
|
||||||
void Detach();
|
|
||||||
|
|
||||||
virtual void ApplyConfig();
|
virtual void ApplyConfig();
|
||||||
|
|
||||||
virtual void Attached();
|
virtual void Attached();
|
||||||
|
@ -122,12 +143,18 @@ namespace Debugger
|
||||||
|
|
||||||
virtual bool ProcessToken(const char *token, const char *cmd);
|
virtual bool ProcessToken(const char *token, const char *cmd);
|
||||||
|
|
||||||
|
virtual void WriteOut(CCPUDebug *cpu, const char *typeStr, const char *fmtStr, va_list vl);
|
||||||
|
|
||||||
|
virtual void FlushOut(CCPUDebug *cpu);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CConsoleDebugger();
|
CConsoleDebugger();
|
||||||
|
|
||||||
void WriteOut(CCPUDebug *cpu, const char *typeStr, const char *fmtStr, va_list vl);
|
void Attach();
|
||||||
|
|
||||||
void FlushOut(CCPUDebug *cpu);
|
void Detach();
|
||||||
|
|
||||||
|
virtual void Poll();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -198,7 +198,7 @@ namespace Debugger
|
||||||
frameCount++;
|
frameCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CDebugger::WriteOut(CCPUDebug *cpu, const char *typeStr, const char *fmtStr, ...)
|
void CDebugger::Log(CCPUDebug *cpu, const char *typeStr, const char *fmtStr, ...)
|
||||||
{
|
{
|
||||||
va_list vl;
|
va_list vl;
|
||||||
va_start(vl, fmtStr);
|
va_start(vl, fmtStr);
|
||||||
|
|
|
@ -77,6 +77,9 @@ namespace Debugger
|
||||||
class CDebugger
|
class CDebugger
|
||||||
#endif // DEBUGGER_HASLOGGER
|
#endif // DEBUGGER_HASLOGGER
|
||||||
{
|
{
|
||||||
|
friend class CCPUDebug;
|
||||||
|
friend class CCodeAnalyser;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool m_exit;
|
bool m_exit;
|
||||||
bool m_pause;
|
bool m_pause;
|
||||||
|
@ -88,6 +91,32 @@ namespace Debugger
|
||||||
virtual bool SaveState(CBlockFile *state);
|
virtual bool SaveState(CBlockFile *state);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
//
|
||||||
|
// Protected virtual methods for sub-classes to implement
|
||||||
|
//
|
||||||
|
|
||||||
|
virtual void AnalysisUpdated(CCodeAnalyser *analyser) = 0;
|
||||||
|
|
||||||
|
virtual void ExceptionTrapped(CException *ex) = 0;
|
||||||
|
|
||||||
|
virtual void InterruptTrapped(CInterrupt *in) = 0;
|
||||||
|
|
||||||
|
virtual void MemWatchTriggered(CWatch *watch, UINT32 addr, unsigned dataSize, UINT64 data, bool isRead) = 0;
|
||||||
|
|
||||||
|
virtual void IOWatchTriggered(CWatch *watch, CIO *io, UINT64 data, bool isInput) = 0;
|
||||||
|
|
||||||
|
virtual void BreakpointReached(CBreakpoint *bp) = 0;
|
||||||
|
|
||||||
|
virtual void MonitorTriggered(CRegMonitor *regMon) = 0;
|
||||||
|
|
||||||
|
virtual void ExecutionHalted(CCPUDebug *cpu, EHaltReason reason) = 0;
|
||||||
|
|
||||||
|
virtual void WaitCommand(CCPUDebug *cpu) = 0;
|
||||||
|
|
||||||
|
virtual void WriteOut(CCPUDebug *cpu, const char *typeStr, const char *fmtStr, va_list vl) = 0;
|
||||||
|
|
||||||
|
virtual void FlushOut(CCPUDebug *cpu) = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
vector<CCPUDebug*> cpus;
|
vector<CCPUDebug*> cpus;
|
||||||
|
|
||||||
|
@ -134,10 +163,10 @@ namespace Debugger
|
||||||
bool CheckPause();
|
bool CheckPause();
|
||||||
|
|
||||||
//
|
//
|
||||||
// Console output
|
// Log
|
||||||
//
|
//
|
||||||
|
|
||||||
void WriteOut(CCPUDebug *cpu, const char *typeStr, const char *fmtStr, ...);
|
void Log(CCPUDebug *cpu, const char *typeStr, const char *fmtStr, ...);
|
||||||
|
|
||||||
#ifdef DEBUGGER_HASLOGGER
|
#ifdef DEBUGGER_HASLOGGER
|
||||||
//
|
//
|
||||||
|
@ -182,28 +211,6 @@ namespace Debugger
|
||||||
virtual void Reset();
|
virtual void Reset();
|
||||||
|
|
||||||
virtual void Poll();
|
virtual void Poll();
|
||||||
|
|
||||||
virtual void AnalysisUpdated(CCodeAnalyser *analyser) = 0;
|
|
||||||
|
|
||||||
virtual void ExceptionTrapped(CException *ex) = 0;
|
|
||||||
|
|
||||||
virtual void InterruptTrapped(CInterrupt *in) = 0;
|
|
||||||
|
|
||||||
virtual void MemWatchTriggered(CWatch *watch, UINT32 addr, unsigned dataSize, UINT64 data, bool isRead) = 0;
|
|
||||||
|
|
||||||
virtual void IOWatchTriggered(CWatch *watch, CIO *io, UINT64 data, bool isInput) = 0;
|
|
||||||
|
|
||||||
virtual void BreakpointReached(CBreakpoint *bp) = 0;
|
|
||||||
|
|
||||||
virtual void MonitorTriggered(CRegMonitor *regMon) = 0;
|
|
||||||
|
|
||||||
virtual void ExecutionHalted(CCPUDebug *cpu, EHaltReason reason) = 0;
|
|
||||||
|
|
||||||
virtual void WaitCommand(CCPUDebug *cpu) = 0;
|
|
||||||
|
|
||||||
virtual void WriteOut(CCPUDebug *cpu, const char *typeStr, const char *fmtStr, va_list vl) = 0;
|
|
||||||
|
|
||||||
virtual void FlushOut(CCPUDebug *cpu) = 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
|
@ -12,7 +12,8 @@
|
||||||
namespace Debugger
|
namespace Debugger
|
||||||
{
|
{
|
||||||
CSupermodelDebugger::CSupermodelDebugger(::CModel3 *model3, ::CInputs *inputs, ::CLogger *logger) :
|
CSupermodelDebugger::CSupermodelDebugger(::CModel3 *model3, ::CInputs *inputs, ::CLogger *logger) :
|
||||||
CConsoleDebugger(), m_model3(model3), m_inputs(inputs), m_logger(logger)
|
CConsoleDebugger(), m_model3(model3), m_inputs(inputs), m_logger(logger),
|
||||||
|
m_loadEmuState(false), m_saveEmuState(false), m_resetEmu(false)
|
||||||
{
|
{
|
||||||
AddCPU(new CPPCDebug());
|
AddCPU(new CPPCDebug());
|
||||||
#ifdef SUPERMODEL_SOUND
|
#ifdef SUPERMODEL_SOUND
|
||||||
|
@ -31,62 +32,64 @@ namespace Debugger
|
||||||
|
|
||||||
bool CSupermodelDebugger::ProcessToken(const char *token, const char *cmd)
|
bool CSupermodelDebugger::ProcessToken(const char *token, const char *cmd)
|
||||||
{
|
{
|
||||||
// TODO - load/saving emu state not supported
|
if (CheckToken(token, "les", "loademustate")) // loademustate FILENAME
|
||||||
//if (CheckToken(token, "les", "loademustate")) // loademustate FILENAME
|
|
||||||
//{
|
|
||||||
// // Parse arguments
|
|
||||||
// token = strtok(NULL, " ");
|
|
||||||
// if (token == NULL)
|
|
||||||
// {
|
|
||||||
// puts("Missing filename.");
|
|
||||||
// return false;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if (LoadModel3State(token))
|
|
||||||
// printf("Emulator state successfully loaded from <%s>\n", token);
|
|
||||||
// else
|
|
||||||
// printf("Unable to load emulator state from <%s>\n", token);
|
|
||||||
// return false;
|
|
||||||
//}
|
|
||||||
//else if (CheckToken(token, "ses", "savestate")) // saveemustate FILENAME
|
|
||||||
//{
|
|
||||||
// // Parse arguments
|
|
||||||
// token = strtok(NULL, " ");
|
|
||||||
// if (token == NULL)
|
|
||||||
// {
|
|
||||||
// puts("Missing filename.");
|
|
||||||
// return false;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if (SaveModel3State(token))
|
|
||||||
// printf("Emulator state successfully saved to <%s>\n", token);
|
|
||||||
// else
|
|
||||||
// printf("Unable to save emulator state to <%s>\n", token);
|
|
||||||
// return false;
|
|
||||||
//}
|
|
||||||
if (CheckToken(token, "lip", "listinputs")) // listinputs
|
|
||||||
{
|
|
||||||
ListInputs();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else if (CheckToken(token, "pip", "printinput")) // printinput NAME
|
|
||||||
{
|
{
|
||||||
// Parse arguments
|
// Parse arguments
|
||||||
token = strtok(NULL, " ");
|
token = strtok(NULL, " ");
|
||||||
if (token == NULL)
|
if (token == NULL)
|
||||||
{
|
{
|
||||||
puts("Mising input name.");
|
Print("Missing filename.\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
strncpy(m_stateFile, token, 254);
|
||||||
|
m_stateFile[254] = '\0';
|
||||||
|
m_loadEmuState = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (CheckToken(token, "ses", "saveemustate")) // saveemustate FILENAME
|
||||||
|
{
|
||||||
|
// Parse arguments
|
||||||
|
token = strtok(NULL, " ");
|
||||||
|
if (token == NULL)
|
||||||
|
{
|
||||||
|
Print("Missing filename.\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
strncpy(m_stateFile, token, 254);
|
||||||
|
m_stateFile[254] = '\0';
|
||||||
|
m_saveEmuState = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (CheckToken(token, "res", "resetemu")) // resetemu
|
||||||
|
{
|
||||||
|
m_resetEmu = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (CheckToken(token, "lip", "listinputs")) // listinputs
|
||||||
|
{
|
||||||
|
ListInputs();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (CheckToken(token, "pip", "printinput")) // printinput (<id>|<label>)
|
||||||
|
{
|
||||||
|
// Parse arguments
|
||||||
|
token = strtok(NULL, " ");
|
||||||
|
if (token == NULL)
|
||||||
|
{
|
||||||
|
Print("Mising input name.\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
::CInput *input = (*m_inputs)[token];
|
::CInput *input = (*m_inputs)[token];
|
||||||
if (input == NULL)
|
if (input == NULL)
|
||||||
{
|
{
|
||||||
printf("No input with id or label '%s'.\n", token);
|
Print("No input with id or label '%s'.\n", token);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!InputIsValid(input))
|
if (!InputIsValid(input))
|
||||||
{
|
{
|
||||||
printf("Input '%s' is not valid for current game.\n", token);
|
Print("Input '%s' is not valid for current game.\n", token);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,58 +97,115 @@ namespace Debugger
|
||||||
{
|
{
|
||||||
char mapTrunc[41];
|
char mapTrunc[41];
|
||||||
Truncate(mapTrunc, 40, input->GetMapping());
|
Truncate(mapTrunc, 40, input->GetMapping());
|
||||||
printf("Input %s (%s) [%s] = %04X (%d)\n", input->id, input->label, mapTrunc, input->value, input->value);
|
Print("Input %s (%s) [%s] = %04X (%d)\n", input->id, input->label, mapTrunc, input->value, input->value);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
printf("Input %s (%s) = %04X (%d)\n", input->id, input->label, input->value, input->value);
|
Print("Input %s (%s) = %04X (%d)\n", input->id, input->label, input->value, input->value);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else if (CheckToken(token, "sip", "setinput")) // setinput NAME MAPPING
|
else if (CheckToken(token, "sip", "setinput")) // setinput (<id>|<label>) <mapping>
|
||||||
{
|
{
|
||||||
// Parse arguments
|
// Parse arguments
|
||||||
token = strtok(NULL, " ");
|
token = strtok(NULL, " ");
|
||||||
if (token == NULL)
|
if (token == NULL)
|
||||||
{
|
{
|
||||||
puts("Mising input name.");
|
Print("Mising input id or label.\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
::CInput *input = (*m_inputs)[token];
|
::CInput *input = (*m_inputs)[token];
|
||||||
if (input == NULL)
|
if (input == NULL)
|
||||||
{
|
{
|
||||||
printf("No input with id or label '%s'.\n", token);
|
Print("No input with id or label '%s'.\n", token);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!InputIsValid(input))
|
if (!InputIsValid(input))
|
||||||
{
|
{
|
||||||
printf("Input '%s' is not valid for current game.\n", token);
|
Print("Input '%s' is not valid for current game.\n", token);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
token = strtok(NULL, " ");
|
token = strtok(NULL, " ");
|
||||||
if (token == NULL)
|
if (token == NULL)
|
||||||
{
|
{
|
||||||
puts("Missing mapping to set.");
|
Print("Missing mapping to set.\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
input->SetMapping(token);
|
input->SetMapping(token);
|
||||||
|
|
||||||
printf("Set input %s (%s) to [%s]\n", input->id, input->label, input->GetMapping());
|
Print("Set input %s (%s) to [%s]\n", input->id, input->label, input->GetMapping());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else if (CheckToken(token, "cip", "configinput")) // configinput NAME
|
else if (CheckToken(token, "rip", "resetinput")) // resetinput (<id>|<label>)
|
||||||
{
|
{
|
||||||
//// Parse arguments
|
// Parse arguments
|
||||||
// TODO
|
token = strtok(NULL, " ");
|
||||||
//token = strtok(NULL, " ");
|
if (token == NULL)
|
||||||
//if (token == NULL)
|
{
|
||||||
//{
|
Print("Mising input id or label.\n");
|
||||||
// puts("Missing mode (a)ll, (s)et single, (a)ppend single or (r)eset single");
|
return false;
|
||||||
// return false;
|
}
|
||||||
//}
|
::CInput *input = (*m_inputs)[token];
|
||||||
//if (CheckToken("a", "all"))
|
if (input == NULL)
|
||||||
//{
|
{
|
||||||
// //m_inputs->ConfigureInputs();
|
Print("No input with id or label '%s'.\n", token);
|
||||||
//}
|
return false;
|
||||||
|
}
|
||||||
|
if (!InputIsValid(input))
|
||||||
|
{
|
||||||
|
Print("Input '%s' is not valid for current game.\n", token);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
input->ResetToDefaultMapping();
|
||||||
|
|
||||||
|
Print("Reset input %s (%s) to [%s]\n", input->id, input->label, input->GetMapping());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (CheckToken(token, "cip", "configinput")) // configinput (<id>|<label>) [(s)et|(a)ppend]
|
||||||
|
{
|
||||||
|
// Parse arguments
|
||||||
|
token = strtok(NULL, " ");
|
||||||
|
if (token == NULL)
|
||||||
|
{
|
||||||
|
Print("Mising input id or label.\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
CInput *input = (*m_inputs)[token];
|
||||||
|
if (input == NULL)
|
||||||
|
{
|
||||||
|
Print("No input with id or label '%s'.\n", token);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!InputIsValid(input))
|
||||||
|
{
|
||||||
|
Print("Input '%s' is not valid for current game.\n", token);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
token = strtok(NULL, " ");
|
||||||
|
bool append;
|
||||||
|
if (token == NULL || CheckToken(token, "s", "set"))
|
||||||
|
append = false;
|
||||||
|
else if (CheckToken(token, "a", "append"))
|
||||||
|
append = true;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Print("Enter a valid mode (s)et or (a)ppend.\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Print("Configure input %s [%s]: %s...", input->label, input->GetMapping(), (append ? "Appending" : "Setting"));
|
||||||
|
fflush(stdout); // required on terminals that use buffering
|
||||||
|
|
||||||
|
// Configure the input
|
||||||
|
if (input->Configure(append, "KEY_ESCAPE"))
|
||||||
|
Print(" %s\n", input->GetMapping());
|
||||||
|
else
|
||||||
|
Print(" [Cancelled]\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (CheckToken(token, "caip", "configallinputs")) // configallinputs
|
||||||
|
{
|
||||||
|
m_inputs->ConfigureInputs(m_model3->GetGameInfo());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -159,9 +219,9 @@ namespace Debugger
|
||||||
|
|
||||||
void CSupermodelDebugger::ListInputs()
|
void CSupermodelDebugger::ListInputs()
|
||||||
{
|
{
|
||||||
puts("Inputs:");
|
Print("Inputs:\n");
|
||||||
if (m_inputs->Count() == 0)
|
if (m_inputs->Count() == 0)
|
||||||
puts(" None");
|
Print(" None\n");
|
||||||
|
|
||||||
// Get maximum id, label and mapping widths
|
// Get maximum id, label and mapping widths
|
||||||
size_t idAndLabelWidth = 0;
|
size_t idAndLabelWidth = 0;
|
||||||
|
@ -191,16 +251,16 @@ namespace Debugger
|
||||||
if (groupLabel == NULL || stricmp(groupLabel, input->GetInputGroup()) != 0)
|
if (groupLabel == NULL || stricmp(groupLabel, input->GetInputGroup()) != 0)
|
||||||
{
|
{
|
||||||
groupLabel = input->GetInputGroup();
|
groupLabel = input->GetInputGroup();
|
||||||
printf(" %s:\n", groupLabel);
|
Print(" %s:\n", groupLabel);
|
||||||
}
|
}
|
||||||
|
|
||||||
sprintf(idAndLabel, "%s (%s)", input->id, input->label);
|
sprintf(idAndLabel, "%s (%s)", input->id, input->label);
|
||||||
printf(" %-*s", (int)idAndLabelWidth, idAndLabel);
|
Print(" %-*s", (int)idAndLabelWidth, idAndLabel);
|
||||||
if (!input->IsVirtual())
|
if (!input->IsVirtual())
|
||||||
Truncate(mapping, 20, input->GetMapping());
|
Truncate(mapping, 20, input->GetMapping());
|
||||||
else
|
else
|
||||||
mapping[0] = '\0';
|
mapping[0] = '\0';
|
||||||
printf(" %-*s %04X (%d)\n", (int)mappingWidth, mapping, input->value, input->value);
|
Print(" %-*s %04X (%d)\n", (int)mappingWidth, mapping, input->value, input->value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -269,6 +329,15 @@ namespace Debugger
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSupermodelDebugger::ResetModel3()
|
||||||
|
{
|
||||||
|
// Reset Model3
|
||||||
|
m_model3->Reset();
|
||||||
|
|
||||||
|
// Reset debugger
|
||||||
|
Reset();
|
||||||
|
}
|
||||||
|
|
||||||
void CSupermodelDebugger::DebugLog(const char *fmt, va_list vl)
|
void CSupermodelDebugger::DebugLog(const char *fmt, va_list vl)
|
||||||
{
|
{
|
||||||
// Use the supplied logger, if any
|
// Use the supplied logger, if any
|
||||||
|
@ -295,6 +364,31 @@ namespace Debugger
|
||||||
else
|
else
|
||||||
CConsoleDebugger::ErrorLog(fmt, vl);
|
CConsoleDebugger::ErrorLog(fmt, vl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSupermodelDebugger::Poll()
|
||||||
|
{
|
||||||
|
CConsoleDebugger::Poll();
|
||||||
|
|
||||||
|
// Load/saving of emulator state and resetting emulator must be done here
|
||||||
|
if (m_loadEmuState)
|
||||||
|
{
|
||||||
|
LoadModel3State(m_stateFile);
|
||||||
|
m_loadEmuState = false;
|
||||||
|
ForceBreak(false);
|
||||||
|
}
|
||||||
|
else if (m_saveEmuState)
|
||||||
|
{
|
||||||
|
SaveModel3State(m_stateFile);
|
||||||
|
m_saveEmuState = false;
|
||||||
|
ForceBreak(false);
|
||||||
|
}
|
||||||
|
else if (m_resetEmu)
|
||||||
|
{
|
||||||
|
ResetModel3();
|
||||||
|
m_resetEmu = false;
|
||||||
|
ForceBreak(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // SUPERMODEL_DEBUGGER
|
#endif // SUPERMODEL_DEBUGGER
|
|
@ -26,6 +26,11 @@ namespace Debugger
|
||||||
::CInputs *m_inputs;
|
::CInputs *m_inputs;
|
||||||
::CLogger *m_logger;
|
::CLogger *m_logger;
|
||||||
|
|
||||||
|
bool m_loadEmuState;
|
||||||
|
bool m_saveEmuState;
|
||||||
|
bool m_resetEmu;
|
||||||
|
char m_stateFile[255];
|
||||||
|
|
||||||
bool InputIsValid(CInput *input);
|
bool InputIsValid(CInput *input);
|
||||||
|
|
||||||
void ListInputs();
|
void ListInputs();
|
||||||
|
@ -35,17 +40,21 @@ namespace Debugger
|
||||||
|
|
||||||
bool ProcessToken(const char *token, const char *cmd);
|
bool ProcessToken(const char *token, const char *cmd);
|
||||||
|
|
||||||
public:
|
|
||||||
CSupermodelDebugger(::CModel3 *model3, ::CInputs *inputs, ::CLogger *logger);
|
|
||||||
|
|
||||||
void Attached();
|
void Attached();
|
||||||
|
|
||||||
void Detaching();
|
void Detaching();
|
||||||
|
|
||||||
|
public:
|
||||||
|
CSupermodelDebugger(::CModel3 *model3, ::CInputs *inputs, ::CLogger *logger);
|
||||||
|
|
||||||
|
void Poll();
|
||||||
|
|
||||||
bool LoadModel3State(const char *fileName);
|
bool LoadModel3State(const char *fileName);
|
||||||
|
|
||||||
bool SaveModel3State(const char *fileName);
|
bool SaveModel3State(const char *fileName);
|
||||||
|
|
||||||
|
void ResetModel3();
|
||||||
|
|
||||||
void DebugLog(const char *fmt, va_list vl);
|
void DebugLog(const char *fmt, va_list vl);
|
||||||
|
|
||||||
void InfoLog(const char *fmt, va_list vl);
|
void InfoLog(const char *fmt, va_list vl);
|
||||||
|
|
|
@ -270,10 +270,10 @@ namespace Debugger
|
||||||
if (io != NULL)
|
if (io != NULL)
|
||||||
{
|
{
|
||||||
io->GetLocation(locStr);
|
io->GetLocation(locStr);
|
||||||
cpu->debugger->WriteOut(cpu, NULL, "%s data [%s] %s I/O %s\n", rwStr, dataStr, tfStr, locStr);
|
cpu->debugger->Log(cpu, NULL, "%s data [%s] %s I/O %s\n", rwStr, dataStr, tfStr, locStr);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
cpu->debugger->WriteOut(cpu, NULL, "%s data [%s] %s memory address %s\n", rwStr, dataStr, tfStr, addrStr);
|
cpu->debugger->Log(cpu, NULL, "%s data [%s] %s memory address %s\n", rwStr, dataStr, tfStr, addrStr);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue