Changes to debugger classes:

- Added CPrintBreakpoint
Changes to console-based debugger:
 - Added new scp command and tidied up some other commands
 - Tidied up event logging
 - Sorted commands into common groups
 - Added ReadMe.txt help file
This commit is contained in:
Nik Henson 2011-06-29 23:21:50 +00:00
parent 8e2e8adeb3
commit 97ac46c82a
12 changed files with 1422 additions and 749 deletions

View file

@ -1,5 +1,6 @@
#ifdef SUPERMODEL_DEBUGGER
#include "CPUDebug.h"
#include "Breakpoint.h"
#include <stdio.h>
@ -58,6 +59,29 @@ namespace Debugger
sprintf(str, "%d / %d", m_counter, m_count);
return true;
}
CPrintBreakpoint::CPrintBreakpoint(CCPUDebug *bpCPU, int bpAddr) : CBreakpoint(bpCPU, bpAddr, 'P', "print")
{
//
}
bool CPrintBreakpoint::CheckBreak(UINT32 pc, UINT32 opcode)
{
char addrStr[50];
cpu->FormatAddress(addrStr, addr, true);
cpu->debugger->PrintEvent(cpu, "Breakpoint #%u hit at %s.\n", num, addrStr);
return false;
}
void CPrintBreakpoint::Reset()
{
//
}
bool CPrintBreakpoint::GetInfo(char *str)
{
return false;
}
}
#endif // SUPERMODEL_DEBUGGER

View file

@ -21,6 +21,8 @@ namespace Debugger
const char symbol;
const char *type;
unsigned num;
bool active;
bool Check(UINT32 pc, UINT32 opcode);
@ -64,6 +66,18 @@ namespace Debugger
bool GetInfo(char *str);
};
class CPrintBreakpoint : public CBreakpoint
{
public:
CPrintBreakpoint(CCPUDebug *bpCPU, int bpAddr);
bool CheckBreak(UINT32 pc, UINT32 opcode);
void Reset();
bool GetInfo(char *str);
};
//class CConditionBreakpoint : public CBrekapoint
//{
// // TODO

View file

@ -777,12 +777,14 @@ namespace Debugger
if (io->watch != NULL)
RemoveWatch(io->watch);
ioWatches.push_back(watch);
UpdateIOWatchNums();
io->watch = watch;
}
else
{
RemoveMemWatch(watch->addr, watch->size);
memWatches.push_back(watch);
UpdateMemWatchNums();
if (m_memWatchTable == NULL)
m_memWatchTable = new CAddressTable();
m_memWatchTable->Add(watch);
@ -799,6 +801,7 @@ namespace Debugger
if (it == ioWatches.end())
return false;
ioWatches.erase(it);
UpdateIOWatchNums();
}
else
{
@ -806,6 +809,7 @@ namespace Debugger
if (it == memWatches.end())
return false;
memWatches.erase(it);
UpdateMemWatchNums();
m_memWatchTable->Remove(watch);
if (m_memWatchTable->IsEmpty())
{
@ -817,6 +821,20 @@ namespace Debugger
return true;
}
void CCPUDebug::UpdateIOWatchNums()
{
unsigned num = 0;
for (vector<CWatch*>::iterator it = ioWatches.begin(); it != ioWatches.end(); it++)
(*it)->num = num++;
}
void CCPUDebug::UpdateMemWatchNums()
{
unsigned num = 0;
for (vector<CWatch*>::iterator it = memWatches.begin(); it != memWatches.end(); it++)
(*it)->num = num++;
}
CSimpleBreakpoint *CCPUDebug::AddSimpleBreakpoint(UINT32 addr)
{
CSimpleBreakpoint *bp = new CSimpleBreakpoint(this, addr);
@ -829,7 +847,14 @@ namespace Debugger
CCountBreakpoint *bp = new CCountBreakpoint(this, addr, count);
AddBreakpoint(bp);
return bp;
}
}
CPrintBreakpoint *CCPUDebug::AddPrintBreakpoint(UINT32 addr)
{
CPrintBreakpoint *bp = new CPrintBreakpoint(this, addr);
AddBreakpoint(bp);
return bp;
}
CBreakpoint *CCPUDebug::GetBreakpoint(UINT32 addr)
{
@ -842,6 +867,7 @@ namespace Debugger
{
RemoveBreakpoint(bp->addr);
bps.push_back(bp);
UpdateBreakpointNums();
if (m_bpTable == NULL)
m_bpTable = new CAddressTable();
m_bpTable->Add(bp);
@ -861,6 +887,7 @@ namespace Debugger
if (it == bps.end())
return false;
bps.erase(it);
UpdateBreakpointNums();
m_bpTable->Remove(bp);
if (m_bpTable->IsEmpty())
{
@ -883,6 +910,13 @@ namespace Debugger
return true;
}
void CCPUDebug::UpdateBreakpointNums()
{
unsigned num = 0;
for (vector<CBreakpoint*>::iterator it = bps.begin(); it != bps.end(); it++)
(*it)->num = num++;
}
CRegMonitor *CCPUDebug::AddRegMonitor(const char *regName)
{
RemoveRegMonitor(regName);

View file

@ -411,6 +411,10 @@ namespace Debugger
bool RemoveWatch(CWatch *watch);
void UpdateIOWatchNums();
void UpdateMemWatchNums();
//
// Breakpoint handling
//
@ -419,6 +423,8 @@ namespace Debugger
CCountBreakpoint *AddCountBreakpoint(UINT32 addr, unsigned count);
CPrintBreakpoint *AddPrintBreakpoint(UINT32 addr);
void AddBreakpoint(CBreakpoint *bp);
CBreakpoint *GetBreakpoint(UINT32 addr);
@ -429,6 +435,8 @@ namespace Debugger
bool RemoveAllBreakpoints();
void UpdateBreakpointNums();
//
// Register monitor handling
//

File diff suppressed because it is too large Load diff

View file

@ -79,10 +79,14 @@ namespace Debugger
bool SetFmtConfig(const char *str, EFormat &cfg);
bool ParseAddress(CCPUDebug *cpu, const char *str, UINT32 *addr);
bool ParseAddress(const char *str, UINT32 *addr);
const char *GetDataSizeStr(unsigned dataSize, bool shortName);
bool ParseDataSize(const char *str, unsigned &dataSize);
bool ParseFormat(const char *str, EFormat &fmt);
bool ParseCPU(const char *str, CCPUDebug *&cpu);
bool ParseRegister(const char *str, CRegister *&reg);
@ -103,10 +107,14 @@ namespace Debugger
void GetAllMemWatches(vector<CWatch*> &watches);
int GetIndexOfMemWatch(CWatch *watch);
void ListMemWatches();
void GetAllPortWatches(vector<CWatch*> &watches);
int GetIndexOfPortWatch(CWatch *watch);
void ListPortWatches();
void ListBreakpoints();
@ -143,9 +151,7 @@ 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);
virtual void Log(CCPUDebug *cpu, const char *typeStr, const char *fmtStr, va_list vl);
public:
CConsoleDebugger();

View file

@ -198,11 +198,11 @@ namespace Debugger
frameCount++;
}
void CDebugger::Log(CCPUDebug *cpu, const char *typeStr, const char *fmtStr, ...)
void CDebugger::PrintEvent(CCPUDebug *cpu, const char *fmt, ...)
{
va_list vl;
va_start(vl, fmtStr);
WriteOut(cpu, typeStr, fmtStr, vl);
va_start(vl, fmt);
Log(cpu, NULL, fmt, vl);
va_end(vl);
}
@ -210,19 +210,19 @@ namespace Debugger
void CDebugger::DebugLog(const char *fmt, va_list vl)
{
if (logDebug)
WriteOut(NULL, "Debug", fmt, vl);
Log(NULL, "Debug", fmt, vl);
}
void CDebugger::InfoLog(const char *fmt, va_list vl)
{
if (logInfo)
WriteOut(NULL, "Info", fmt, vl);
Log(NULL, "Info", fmt, vl);
}
void CDebugger::ErrorLog(const char *fmt, va_list vl)
{
if (logError)
WriteOut(NULL, "Error", fmt, vl);
Log(NULL, "Error", fmt, vl);
}
#endif // DEBUGGER_HASLOGGER

View file

@ -89,7 +89,7 @@ namespace Debugger
virtual bool LoadState(CBlockFile *state);
virtual bool SaveState(CBlockFile *state);
#endif
#endif // DEBUGGER_HASBLOCKFILE
//
// Protected virtual methods for sub-classes to implement
@ -113,9 +113,7 @@ namespace Debugger
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;
virtual void Log(CCPUDebug *cpu, const char *typeStr, const char *fmtStr, va_list vl) = 0;
public:
vector<CCPUDebug*> cpus;
@ -161,17 +159,15 @@ namespace Debugger
bool CheckExit();
bool CheckPause();
//
// Log
// Printing/logging
//
void Log(CCPUDebug *cpu, const char *typeStr, const char *fmtStr, ...);
void PrintEvent(CCPUDebug *cpu, const char *fmt, ...);
#ifdef DEBUGGER_HASLOGGER
//
// CLogger logging methods
//
virtual void DebugLog(const char *fmt, va_list vl);
virtual void InfoLog(const char *fmt, va_list vl);

396
Src/Debugger/ReadMe.txt Executable file
View file

@ -0,0 +1,396 @@
Help for Supermodel Console-based Debugger
==========================================
Relevant Supermodel Command Line Options
----------------------------------------
-enter-debugger Enters the debugger at the start of emulation,
-disable-debugger Completely disables the debugger in emulator.
At any point whilst running the emulator, execution can be halted and the debugger entered by pressing Alt+B.
Code Analysis
-------------
At startup, and whenever new code is encountered, the debugger analyses the program's code in order to work out all
reachable code locations from a given set of entry points (reset address, exception handlers etc). During the analysis,
it keeps track of all valid code locations and this is used to align instructions for CPUs with variable length instruction
sets. It also generates a set of auto-labels that identify places of interest such as sub-routines, jump destinations and
exception handlers etc. Code analysis can be switched off via the 'configure' command if required.
Debugger Commands
=================
Execution
---------
n next [<count>=1]
Runs the next single instruction or the next <count> instructions.
nf nextframe [<count>=1]
Runs until the next frame or for the next <count> frames.
s stepover
Runs the next instruction. If it is a call to a sub-routine then the sub-routine is 'stepped over' (ie control
breaks at the return address of the sub-routine).
si stepinto
Runs the next single instruction, entering any sub-routines (ie same as 'next' above).
so stepout
Runs until control returns from the current sub-routine or exception/interrupt handler. Note that if an
exception/interrupt occurs whilst stepping out then this will break execution too as control will have left
the sub-routine or handler.
c continue [<addr>]
Continues running until a break is forced or if <addr> specified, until the given address is reached.
spc setpc <addr>
Sets the PC of the current CPU to the given address.
CPUs
----
lc listcpus
Lists all the available CPUs with details about them.
sc switchcpu (<name>|<num>)
Switches to another CPU with the given name or number.
dc disablecpu (<name>|<num>)
Disables debugging for the CPU with the given name or number. Once disabled, it is no longer
possible to switch to or halt execution for that CPU, ie all breakpoints, watches, monitors and traps
are ignored. The current CPU cannot be disabled.
ec enablecpu (<name>|<num>)
Enables debugging for the CPU with the given name or number.
Registers
---------
lr listregisters
Lists all registers for the current CPU and their current values.
pr printregister <reg>
Prints the current value of the given register for the current CPU.
sr setregister <reg> <value>
Sets the value of the given register for the current CPU.
lm listmonitors
Lists all register monitors for the current CPU with details about them.
m monitor <reg>
am addmonitor <reg>
Adds a register monitor for the register with the given name, causing execution to break whenever the register's value
changes.
rm removemonitor <reg>
Removes the register monitor with the given name.
ram removeallmonitors
Removes all register monitors for the current CPU.
Exceptions & Interrupts
-----------------------
le listexceptions
Lists all known exceptions for the current CPU and details about them.
li listinterrupts
Lists all known interrupts for the current CPU and details about them.
t trap ((e)xception|(i)nterrupt) <id>
at addtrap ((e)xception|(i)nterrupt) <id>
Adds an exception or interrupt trap for the exception/interrupt with the given identifier.
rt removetrap ((e)xception|(i)nterrupt) <id>
Removes an exception or interrupt trap for the exception/interrupt with the given identifier.
rat removealltraps [(a)ll|(e)xceptions|(i)nterrupts]
Removes all exception and/or all interrupt traps for the current CPU. If no arguments are supplied, all exception and all
interrupt traps are removed.
Disassembly, Labels & Comments
------------------------------
l list [<start>=last [#<instrs>=20|<end>]]
ld listdisassembly [<start>=last [#<instrs>=20|<end>]]
Lists the disassembled code of the current CPU for the given address range and/or number of instructions.
If the start address is not supplied, the listing continues on from the last call, or from just before the current PC
address if this is the first call.
If the end address or instruction count is not supplied, then the default of 20 instructions are listed.
If code analysis is enabled, then this will be used to align the instructions in the disassembly. If code analysis is
off and the current PC address falls within the disassembly address range, then the instructions will line up with this.
Otherwise, instruction alignment will simply begin at the start address.
ll listlabels [(d)efault|(c)ustom|(a)utos|(e)ntrypoints|e(x)cephandlers|(i)interhandlers|(j)umptargets|(l)ooppoints]
Lists all labels for the current CPU. The default option is to list all custom labels (user-added) and any auto-labels
(labels generated by code analysis) of interest. The other options allow the display of particular types of auto-labels.
al addlabel <addr> <name>
Adds a custom label at the given address and with the given name.
rl removelabel [<name>|<addr>]
Removes a custom label with the given name or at the given address. If no argument is supplied, then it removes the
custom label at the current PC address.
ral removealllabels
Removes all custom labels for the current CPU.
ac addcomment <addr> <text...>
Adds a code comment at the given address and with the given text.
rc removecomment [<addr>]
Removes the code comment at the given address. If no argument is supplied, then it removes the code comment at the
current PC address.
rac removeallcomments
Removes all code comments for the current CPU.
Breakpoints
-----------
lb listbreakpoints
Lists all breakpoints for the current CPU with details about them.
b breakpoint [<addr> [[s)imple|(c)ount <count>|(p)rint)]]
ab addbreakpoint [<addr> [[s)imple|(c)ount <count>|(p)rint)]]
Adds a breakpoint at the given address. If no arguments are supplied, then it adds a simple breakpoint at the current PC
address.
Types of breakpoint (default is simple):
(s)imple - if the location is hit, execution always breaks,
(c)ount - if the location is hit the number of times specified by count, execution breaks.
(p)rint - if the location is hit, a message is printed to the console, but control does not break.
rb removebreakpoint [#<num>|<addr>]
Removes the breakpoint with the given number of at the given address. If no arguments is supplied, then it removes
the breakpoint at the current PC address.
Memory, I/O & Watches
---------------------
ln listregions
Lists all known memory regions in the current CPU's address space.
ly listmemory [<start>=last [#<rows>=8|<end>]]
Lists the memory contents of the current CPU for the given address range and/or number of rows.
If the start address is not supplied, the listing continues on from the last call, or from address 0 if this is the
first call.
If the end address or row count is not supplied, then the default of 8 rows are listed.
py printmemory[.<size>=b] <addr> [(h)ex|hexdo(l)lar|hex(p)osth|(d)ecimal|(b)inary]
Prints the current memory value at the given address for the current CPU. If no format is supplied, the default data
format is used.
The size specifier may be a number or (b)yte, (w)ord, (l)ong or (v)erylong. The default if omitted is byte.
sy setmemory[.<size>=b] <addr> <value>
Sets the memory value at the given address for the current CPU.
The size specifier may be a number or (b)yte, (w)ord, (l)ong or (v)erylong. The default if omitted is byte.
lo listios
Lists all known I/Os (both mapped I/O addresses and I/O ports) for the current CPU and details about them.
lw listmemwatches
Lists all memory watches for the current CPU with details about them.
w memwatch[.<size>=b] <addr> [((n)one|(r)ead|(w)rite|(rw)eadwrite) [((s)imple|(c)ount <count>|(m)atch <sequence>|captu(r)e <maxlen>|(p)rint)]]
aw addmemwatch[.<size>=b] <addr> [((n)one|(r)ead|(w)rite|(rw)eadwrite) [((s)imple|(c)ount <count>|(m)atch <sequence>|captu(r)e <maxlen>|(p)rint)]]
Adds a read/write memory watch at the given address.
If (r)ead, (w)rite or (rw)eadwrite are specified then the watch also triggers an event (see below) when the
address is read, written or either read or written, respectively.
If (n)one is specified (the default), the watch does not trigger and simply remembers the last read/write at the
given address (details about which are visible when listing memory watches).
The size specifier may be a number or (b)yte, (w)ord, (l)ong or (v)erylong. The default if omitted is byte. If the
address is mapped I/O address, then the size is ignored.
Types of watch (default is simple):
(s)imple - if the watch is triggered, execution always breaks,
(c)ount - if the watch is triggered, execution breaks after the number of times specified by count,
(m)atch - if the watch is triggered, execution breaks if the series of values read/written matches the given
sequence of data (comma separated),
captu(r)e - if the watch is triggered, the value read/written is recorded in a history whose maximum length
is as specified,
(p)rint - if the watch is triggered, a message with the value read/written is printed to the console.
rw removememwatch (#<num>|<addr>)
Removes the memory watch with the given number or at the given address.
raw removeallmemwatches
Removes all memory watches for the current CPU.
lpw listportwatches
Lists all I/O port watches for the current CPU with details about them.
pw portwatch <port> [((n)one|(i)nput|(o)utput|(io)nputoutput) [(s)imple|(c)ount <count>|(m)atch <sequence>|captu(r)e <maxlen>|(p)rint]]
apw addportwatch <port> [((n)one|(i)nput|(o)utput|(io)nputoutput) [(s)imple|(c)ount <count>|(m)atch <sequence>|captu(r)e <maxlen>|(p)rint]]
Adds an input/output watch for the given I/O port.
If (i)nput, (o)utput or (io)nputoutput are specified then the watch also triggers an event (see below) when the
port is read (input), written (output) or either read or written, respectively.
If (n)one is specified (the default), the watch does not trigger and simply remembers the last read/write for the
given port (details about which are visible when listing port watches).
Types of watch (default is simple):
(s)imple - if the watch is triggered, execution always breaks,
(c)ount - if the watch is triggered the number of times specified by count, execution breaks,
(m)atch - if the watch is triggered, execution breaks if the series of values input/output matches the given
sequence of data (comma separated),
captu(r)e - if the watch is triggered, the value inputted/outputted is recorded in a history whose maximum length
is as specified,
(p)rint - if the watch is triggered, a message with the value inputted/outputted is printed to the console.
rpw removeportwatch (#<num>|<port>)
Removes the port watch with the given number or for the given port.
rapw removeallportwatches
Removes all port watches for the current CPU.
General
--------
p print[.<size>=v] <expr> [(h)ex|hex(z)ero|hexdo(l)lar|hex(p)osth|(d)ecimal|(b)inary]
Prints the given expression as a number in the given format. If no format is supplied, the default data format is used.
Currently the "expression" can just be a number, label or register name.
The size specifier may be a number or (b)yte, (w)ord, (l)ong or (v)erylong. The default if omitted depends on the
type of expression.
cfg configure analysis [(o)n|of(f)]
addrfmt [(h)ex|hex(z)ero|hexdo(l)lar|hex(p)osth|(d)ecimal|(b)inary]
portfmt [(h)ex|hex(z)ero|hexdo(l)lar|hex(p)osth|(d)ecimal|(b)inary]
datafmt [(h)ex|hex(z)ero|hexdo(l)lar|hex(p)osth|(d)ecimal|(b)inary]
showlabels [(o)n|of(f)]
showopcodes [(o)n|of(f)]
membytesrow [<num>]
Configures the debugger.
If no arguments are passed, it outputs all the current settings.
If a setting is supplied, it outputs the current value for the given setting.
If both a setting and a value are supplied, it sets the current value for the given setting.
ls loadstate <file>
Loads the debugger state (custom labels and code comments) from the given file.
ss savestate <file>
Save the debugger state (custom labels and code comments) to the given file.
h help
Prints the available commands.
x exit
Exits the debugger and emulator.
Emulator
--------
les loademustate <file>
Loads the emulator state from the given file.
ses saveemustate <file>
Saves the emulator state to the given file.
res resetemu
Resets the emulator.
Inputs
------
lip listinputs
Lists all available inputs for the current game.
pip printinput (<id>|<label>)
Prints details about the input with the given id or label.
sip setinput (<id>|<label>) <mapping>
Sets the current mapping for the input with the given id or label.
rip resetinput (<id>|<label>)
Resets the mapping to its default for the input with the given id or label.
cip configinput (<id>|<label>) [(s)et|(a)ppend]
Configures the input with the given id or label, in a similar fashion to -config-inputs. The default is to
set the mapping but if append is specified the mapping is appended to.
caip configallinputs
Configures all the inputs for the current game, in a similar fashion to -config-inputs.
Notes
-----
The output of any command can be redirected to a file by adding the > or >> redirection symbols after the command together
with the filename to write or append to, eg:
listdisassembly MainEntry #50 > c:\disassembly.txt
or listmemory $0000 $1000 >> ramdump.txt

View file

@ -32,7 +32,10 @@ namespace Debugger
bool CSupermodelDebugger::ProcessToken(const char *token, const char *cmd)
{
if (CheckToken(token, "les", "loademustate")) // loademustate FILENAME
//
// Emulator
//
if (CheckToken(token, "les", "loademustate")) // loademustate <filename>
{
// Parse arguments
token = strtok(NULL, " ");
@ -47,7 +50,7 @@ namespace Debugger
m_loadEmuState = true;
return true;
}
else if (CheckToken(token, "ses", "saveemustate")) // saveemustate FILENAME
else if (CheckToken(token, "ses", "saveemustate")) // saveemustate <filename>
{
// Parse arguments
token = strtok(NULL, " ");
@ -67,6 +70,9 @@ namespace Debugger
m_resetEmu = true;
return true;
}
//
// Inputs
//
else if (CheckToken(token, "lip", "listinputs")) // listinputs
{
ListInputs();
@ -208,6 +214,27 @@ namespace Debugger
m_inputs->ConfigureInputs(m_model3->GetGameInfo());
return false;
}
//
// Help
//
else if (CheckToken(token, "h", "help"))
{
CConsoleDebugger::ProcessToken(token, cmd);
const char *fmt = " %-6s %-25s %s\n";
Print(" Emulator:\n");
Print(fmt, "les", "loademustate", "<filename>");
Print(fmt, "ses", "saveemustate", "<filename>");
Print(fmt, "res", "resetemu", "");
Print(" Inputs:\n");
Print(fmt, "lip", "listinputs", "");
Print(fmt, "pip", "printinput", "(<id>|<label>)");
Print(fmt, "sip", "setinput", "(<id>|<label>) <mapping>");
Print(fmt, "rip", "resetinput", "(<id>|<label>)");
Print(fmt, "cip", "configinput", "(<id>|<label>) [(s)et|(a)ppend]");
Print(fmt, "caip", "configallinputs", "");
return false;
}
else
return CConsoleDebugger::ProcessToken(token, cmd);
}

View file

@ -260,20 +260,20 @@ namespace Debugger
bool CPrintWatch::CheckBreak(bool isRead, UINT64 data)
{
const char *sizeStr = CDebugger::GetSizeString(size);
const char *rwStr = (isRead ? "Read" : "Wrote");
const char *tfStr = (isRead ? "from" : "to");
char dataStr[50];
char addrStr[50];
char locStr[50];
cpu->FormatData(dataStr, size, data);
cpu->FormatAddress(addrStr, addr, true);
const char *rwStr = (isRead ? "Read" : "Wrote");
const char *tfStr = (isRead ? "from" : "to");
if (io != NULL)
{
io->GetLocation(locStr);
cpu->debugger->Log(cpu, NULL, "%s data [%s] %s I/O %s\n", rwStr, dataStr, tfStr, locStr);
cpu->debugger->PrintEvent(cpu, "%s %s data (%s) %s I/O %s.\n", rwStr, sizeStr, dataStr, tfStr, locStr);
}
else
cpu->debugger->Log(cpu, NULL, "%s data [%s] %s memory address %s\n", rwStr, dataStr, tfStr, addrStr);
cpu->debugger->PrintEvent(cpu, "%s %s data (%s) %s memory %s.\n", rwStr, sizeStr, dataStr, tfStr, addrStr);
return false;
}
}

View file

@ -33,6 +33,7 @@ namespace Debugger
bool trigRead;
bool trigWrite;
unsigned num;
bool active;
unsigned readCount;