mirror of
https://github.com/RetroDECK/Supermodel.git
synced 2024-11-22 13:55:38 +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) :
|
||||
name(cpuName), minInstrLen(cpuMinInstrLen), maxInstrLen(cpuMaxInstrLen),
|
||||
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),
|
||||
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_stateUpdated(false), m_exTrapped(NULL), m_intTrapped(NULL), m_bpReached(NULL),
|
||||
m_mappedIOTable(NULL), m_memWatchTable(NULL), m_bpTable(NULL), m_numRegMons(0), m_regMonArray(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)
|
||||
{
|
||||
memset(m_exArray, NULL, sizeof(m_exArray));
|
||||
|
@ -1171,6 +1171,7 @@ namespace Debugger
|
|||
if (ex == NULL)
|
||||
return;
|
||||
|
||||
m_exRaised = ex;
|
||||
ex->count++;
|
||||
if (!ex->trap)
|
||||
return;
|
||||
|
@ -1188,6 +1189,7 @@ namespace Debugger
|
|||
if (in == NULL)
|
||||
return;
|
||||
|
||||
m_intRaised = in;
|
||||
in->count++;
|
||||
if (!in->trap)
|
||||
return;
|
||||
|
|
|
@ -104,16 +104,18 @@ namespace Debugger
|
|||
void DetachFromDebugger(CDebugger *theDebugger);
|
||||
|
||||
protected:
|
||||
CCodeAnalyser *m_analyser;
|
||||
|
||||
bool m_stateUpdated;
|
||||
CException *m_exRaised;
|
||||
CException *m_exTrapped;
|
||||
CInterrupt *m_intRaised;
|
||||
CInterrupt *m_intTrapped;
|
||||
CBreakpoint *m_bpReached;
|
||||
CWatch *m_memWatchTriggered;
|
||||
CWatch *m_ioWatchTriggered;
|
||||
CRegMonitor *m_regMonTriggered;
|
||||
|
||||
CCodeAnalyser *m_analyser;
|
||||
|
||||
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 maxMnemLen;
|
||||
|
||||
bool enabled;
|
||||
EFormat addrFmt;
|
||||
EFormat portFmt;
|
||||
EFormat dataFmt;
|
||||
|
@ -173,6 +176,7 @@ namespace Debugger
|
|||
UINT16 numIntCodes;
|
||||
UINT16 numPorts;
|
||||
UINT32 memSize;
|
||||
|
||||
UINT64 instrCount;
|
||||
UINT32 pc;
|
||||
UINT32 opcode;
|
||||
|
@ -744,6 +748,16 @@ namespace Debugger
|
|||
|
||||
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
|
||||
bool stepBreak, countBreak, untilBreak;
|
||||
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++;
|
||||
pc = newPC;
|
||||
opcode = newOpcode;
|
||||
|
@ -799,16 +813,17 @@ namespace Debugger
|
|||
stepBreak = !m_steppingOver || pc == m_stepOverAddr;
|
||||
break;
|
||||
case StepOut:
|
||||
// Step-out steps over any jumps and breaks when it reaches a return
|
||||
// TODO - following doesn't work if an exception occurs before the return
|
||||
if (m_steppingOver)
|
||||
// Step-out steps over any jumps and breaks when it reaches a return or an exception/interrupt is raised
|
||||
if (m_exRaised != NULL || m_intRaised != NULL)
|
||||
stepBreak = true;
|
||||
else if (m_steppingOver)
|
||||
{
|
||||
if (pc == m_stepOverAddr)
|
||||
m_steppingOver = false;
|
||||
stepBreak = false;
|
||||
}
|
||||
else if (m_steppingOut)
|
||||
stepBreak = pc == m_stepOutAddr;
|
||||
else
|
||||
stepBreak = m_steppingOut && pc == m_stepOutAddr;
|
||||
break;
|
||||
default:
|
||||
stepBreak = false;
|
||||
|
@ -825,7 +840,7 @@ namespace Debugger
|
|||
}
|
||||
else
|
||||
{
|
||||
// Update pc and opcode
|
||||
// Just updating state so update pc and opcode, but do not update instruction count
|
||||
pc = newPC;
|
||||
opcode = newOpcode;
|
||||
|
||||
|
@ -867,7 +882,9 @@ namespace Debugger
|
|||
m_steppingOut = false;
|
||||
m_count = 0;
|
||||
m_until = false;
|
||||
m_exRaised = NULL;
|
||||
m_exTrapped = NULL;
|
||||
m_intRaised = NULL;
|
||||
m_intTrapped = NULL;
|
||||
m_bpReached = 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 (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)
|
||||
m_steppingOver = GetJumpRetAddr(pc, opcode, m_stepOverAddr);
|
||||
if (!m_steppingOver)
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -7,6 +7,7 @@
|
|||
#include "Types.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define NUM_LISTAUTOLABELS (sizeof(s_listAutoLabels) / sizeof(ELabelFlags))
|
||||
|
||||
|
@ -16,6 +17,7 @@ namespace Debugger
|
|||
class CException;
|
||||
class CWatch;
|
||||
class CBreakpoint;
|
||||
class CRegister;
|
||||
class CRegMonitor;
|
||||
|
||||
/*
|
||||
|
@ -29,6 +31,9 @@ namespace Debugger
|
|||
|
||||
CCPUDebug *m_cpu;
|
||||
|
||||
bool m_nextFrame;
|
||||
unsigned m_nextFrameCount;
|
||||
|
||||
UINT32 m_listDism;
|
||||
UINT32 m_listMem;
|
||||
|
||||
|
@ -41,11 +46,27 @@ namespace Debugger
|
|||
bool m_showOpCodes;
|
||||
unsigned m_memBytesPerRow;
|
||||
|
||||
FILE *m_file;
|
||||
|
||||
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, char *modifier, size_t modSize, const char *defaultMod);
|
||||
|
||||
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);
|
||||
|
||||
bool GetLabelText(char *str, int maxLen, UINT32 addr);
|
||||
|
@ -62,6 +83,10 @@ namespace Debugger
|
|||
|
||||
bool ParseDataSize(const char *str, unsigned &dataSize);
|
||||
|
||||
bool ParseCPU(const char *str, CCPUDebug *&cpu);
|
||||
|
||||
bool ParseRegister(const char *str, CRegister *®);
|
||||
|
||||
void ListCPUs();
|
||||
|
||||
void ListRegisters();
|
||||
|
@ -92,10 +117,6 @@ namespace Debugger
|
|||
|
||||
UINT32 ListMemory(UINT32 start, UINT32 end, unsigned bytesPerRow);
|
||||
|
||||
void Attach();
|
||||
|
||||
void Detach();
|
||||
|
||||
virtual void ApplyConfig();
|
||||
|
||||
virtual void Attached();
|
||||
|
@ -122,12 +143,18 @@ namespace Debugger
|
|||
|
||||
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:
|
||||
CConsoleDebugger();
|
||||
|
||||
void WriteOut(CCPUDebug *cpu, const char *typeStr, const char *fmtStr, va_list vl);
|
||||
|
||||
void FlushOut(CCPUDebug *cpu);
|
||||
void Attach();
|
||||
|
||||
void Detach();
|
||||
|
||||
virtual void Poll();
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -198,7 +198,7 @@ namespace Debugger
|
|||
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_start(vl, fmtStr);
|
||||
|
|
|
@ -77,6 +77,9 @@ namespace Debugger
|
|||
class CDebugger
|
||||
#endif // DEBUGGER_HASLOGGER
|
||||
{
|
||||
friend class CCPUDebug;
|
||||
friend class CCodeAnalyser;
|
||||
|
||||
private:
|
||||
bool m_exit;
|
||||
bool m_pause;
|
||||
|
@ -88,6 +91,32 @@ namespace Debugger
|
|||
virtual bool SaveState(CBlockFile *state);
|
||||
#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:
|
||||
vector<CCPUDebug*> cpus;
|
||||
|
||||
|
@ -134,10 +163,10 @@ namespace Debugger
|
|||
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
|
||||
//
|
||||
|
@ -182,28 +211,6 @@ namespace Debugger
|
|||
virtual void Reset();
|
||||
|
||||
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
|
||||
{
|
||||
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());
|
||||
#ifdef SUPERMODEL_SOUND
|
||||
|
@ -31,62 +32,64 @@ namespace Debugger
|
|||
|
||||
bool CSupermodelDebugger::ProcessToken(const char *token, const char *cmd)
|
||||
{
|
||||
// TODO - load/saving emu state not supported
|
||||
//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
|
||||
if (CheckToken(token, "les", "loademustate")) // loademustate FILENAME
|
||||
{
|
||||
// Parse arguments
|
||||
token = strtok(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;
|
||||
}
|
||||
::CInput *input = (*m_inputs)[token];
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -94,58 +97,115 @@ namespace Debugger
|
|||
{
|
||||
char mapTrunc[41];
|
||||
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
|
||||
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;
|
||||
}
|
||||
else if (CheckToken(token, "sip", "setinput")) // setinput NAME MAPPING
|
||||
else if (CheckToken(token, "sip", "setinput")) // setinput (<id>|<label>) <mapping>
|
||||
{
|
||||
// Parse arguments
|
||||
token = strtok(NULL, " ");
|
||||
if (token == NULL)
|
||||
{
|
||||
puts("Mising input name.");
|
||||
Print("Mising input id or label.\n");
|
||||
return false;
|
||||
}
|
||||
::CInput *input = (*m_inputs)[token];
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
token = strtok(NULL, " ");
|
||||
if (token == NULL)
|
||||
{
|
||||
puts("Missing mapping to set.");
|
||||
Print("Missing mapping to set.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
else if (CheckToken(token, "cip", "configinput")) // configinput NAME
|
||||
else if (CheckToken(token, "rip", "resetinput")) // resetinput (<id>|<label>)
|
||||
{
|
||||
//// Parse arguments
|
||||
// TODO
|
||||
//token = strtok(NULL, " ");
|
||||
//if (token == NULL)
|
||||
//{
|
||||
// puts("Missing mode (a)ll, (s)et single, (a)ppend single or (r)eset single");
|
||||
// return false;
|
||||
//}
|
||||
//if (CheckToken("a", "all"))
|
||||
//{
|
||||
// //m_inputs->ConfigureInputs();
|
||||
//}
|
||||
// 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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
else
|
||||
|
@ -159,9 +219,9 @@ namespace Debugger
|
|||
|
||||
void CSupermodelDebugger::ListInputs()
|
||||
{
|
||||
puts("Inputs:");
|
||||
Print("Inputs:\n");
|
||||
if (m_inputs->Count() == 0)
|
||||
puts(" None");
|
||||
Print(" None\n");
|
||||
|
||||
// Get maximum id, label and mapping widths
|
||||
size_t idAndLabelWidth = 0;
|
||||
|
@ -191,16 +251,16 @@ namespace Debugger
|
|||
if (groupLabel == NULL || stricmp(groupLabel, input->GetInputGroup()) != 0)
|
||||
{
|
||||
groupLabel = input->GetInputGroup();
|
||||
printf(" %s:\n", groupLabel);
|
||||
Print(" %s:\n", groupLabel);
|
||||
}
|
||||
|
||||
sprintf(idAndLabel, "%s (%s)", input->id, input->label);
|
||||
printf(" %-*s", (int)idAndLabelWidth, idAndLabel);
|
||||
Print(" %-*s", (int)idAndLabelWidth, idAndLabel);
|
||||
if (!input->IsVirtual())
|
||||
Truncate(mapping, 20, input->GetMapping());
|
||||
else
|
||||
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;
|
||||
}
|
||||
|
||||
void CSupermodelDebugger::ResetModel3()
|
||||
{
|
||||
// Reset Model3
|
||||
m_model3->Reset();
|
||||
|
||||
// Reset debugger
|
||||
Reset();
|
||||
}
|
||||
|
||||
void CSupermodelDebugger::DebugLog(const char *fmt, va_list vl)
|
||||
{
|
||||
// Use the supplied logger, if any
|
||||
|
@ -295,6 +364,31 @@ namespace Debugger
|
|||
else
|
||||
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
|
|
@ -26,6 +26,11 @@ namespace Debugger
|
|||
::CInputs *m_inputs;
|
||||
::CLogger *m_logger;
|
||||
|
||||
bool m_loadEmuState;
|
||||
bool m_saveEmuState;
|
||||
bool m_resetEmu;
|
||||
char m_stateFile[255];
|
||||
|
||||
bool InputIsValid(CInput *input);
|
||||
|
||||
void ListInputs();
|
||||
|
@ -35,17 +40,21 @@ namespace Debugger
|
|||
|
||||
bool ProcessToken(const char *token, const char *cmd);
|
||||
|
||||
public:
|
||||
CSupermodelDebugger(::CModel3 *model3, ::CInputs *inputs, ::CLogger *logger);
|
||||
|
||||
void Attached();
|
||||
|
||||
void Detaching();
|
||||
|
||||
public:
|
||||
CSupermodelDebugger(::CModel3 *model3, ::CInputs *inputs, ::CLogger *logger);
|
||||
|
||||
void Poll();
|
||||
|
||||
bool LoadModel3State(const char *fileName);
|
||||
|
||||
bool SaveModel3State(const char *fileName);
|
||||
|
||||
void ResetModel3();
|
||||
|
||||
void DebugLog(const char *fmt, va_list vl);
|
||||
|
||||
void InfoLog(const char *fmt, va_list vl);
|
||||
|
|
|
@ -270,10 +270,10 @@ namespace Debugger
|
|||
if (io != NULL)
|
||||
{
|
||||
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
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue