mirror of https://github.com/stella-emu/stella.git
added user defined timers to debugger (TODO: screenshots)
This commit is contained in:
parent
d8ed1d1d13
commit
3de6002c46
|
@ -15,7 +15,8 @@
|
|||
6.7 to 7.0 (XXXXX XX, 202X)
|
||||
|
||||
* Enhanced ROM launcher to allow multiple images per ROM
|
||||
(TODO: controller support, doc)
|
||||
|
||||
* Made heaps of additional images available for the ROM launcher
|
||||
|
||||
* Added searching by filename for ROM launcher images
|
||||
|
||||
|
@ -31,6 +32,8 @@
|
|||
|
||||
* Fixed broken 7800 pause key support
|
||||
|
||||
* Added user defined CPU cycle timers to debugger (TODO: screenshots)
|
||||
|
||||
-Have fun!
|
||||
|
||||
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
<li><a href="#PseudoRegisters">Pseudo-Registers</a></li>
|
||||
<li><a href="#Watches">Watches</a></li>
|
||||
<li><a href="#Traps">Traps</a></li>
|
||||
<li><a href="#Timers">Timers</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#SaveWork">Save your work!</a></li>
|
||||
|
@ -858,6 +859,23 @@ can remove a trap with "delTrap number", where the number comes from
|
|||
"listTraps" or by entering the identical trap again. You can get rid of
|
||||
all traps at once with the "clearTraps" command.</p></p>
|
||||
|
||||
<h4><a name="Timers">Timers</a></h4>
|
||||
|
||||
<p>Timers are used to measure cycles used between two timer points. They
|
||||
measure the minimum, maximum and average cycles executed between their two
|
||||
timer points. Start and end points can be set via prompt command or ROM
|
||||
Disassembly settings dialog.</p>
|
||||
|
||||
<p>Timer points can be defined with or without a bank. With a bank, they
|
||||
are triggered in the given bank only, using all mirror addresses too. Without
|
||||
a bank, the timer points are triggered in all bank, using the given adress
|
||||
only.</p>
|
||||
|
||||
<p>All timers can be shown in detail with "listTimers", a single timer
|
||||
with "printTimer number". "resetTimers" allows resetting all timer statistics,
|
||||
"delTimer number" removes a single timer. All timers can be deleted with the
|
||||
"clearTimers" command.</p>
|
||||
|
||||
</br>
|
||||
<h3><a name="SaveWork">Save your work!</a></h3>
|
||||
<p>Stella offers several commands to save your work inside the debugger for
|
||||
|
@ -945,6 +963,7 @@ Type "help 'cmd'" to see extended information about the given command.</p>
|
|||
clearConfig - Clear DiStella config directives [bank xx]
|
||||
clearHistory - Clear the prompt history
|
||||
clearSaveStateIfs - Clear all saveState points
|
||||
clearTimers - Clear all timers
|
||||
clearTraps - Clear all traps
|
||||
clearWatches - Clear all watches
|
||||
cls - Clear prompt area of text
|
||||
|
@ -959,6 +978,7 @@ clearSaveStateIfs - Clear all saveState points
|
|||
delFunction - Delete function with label xx
|
||||
delSaveStateIf - Delete conditional saveState point <xx>
|
||||
delTrap - Delete trap <xx>
|
||||
delTimer - Delete timer <xx>
|
||||
delWatch - Delete watch <xx>
|
||||
disAsm - Disassemble address xx [yy lines] (default=PC)
|
||||
dump - Dump data at address <xx> [to yy] [1: memory; 2: CPU state; 4: input regs] [?]
|
||||
|
@ -994,8 +1014,10 @@ clearSaveStateIfs - Clear all saveState points
|
|||
pCol - Mark 'PCOL' range in disassembly
|
||||
pGfx - Mark 'PGFX' range in disassembly
|
||||
print - Evaluate/print expression xx in hex/dec/binary
|
||||
printTimer - Print details of timer xx
|
||||
ram - Show ZP RAM, or set address xx to yy1 [yy2 ...]
|
||||
reset - Reset system to power-on state
|
||||
resetTimers - Reset all timers' statistics
|
||||
rewind - Rewind state by one or [xx] steps/traces/scanlines/frames...
|
||||
riot - Show RIOT timer/input status
|
||||
rom - Set ROM address xx to yy1 [yy2 ...]
|
||||
|
@ -1017,8 +1039,9 @@ clearSaveStateIfs - Clear all saveState points
|
|||
scanLine - Advance emulation by <xx> scanlines (default=1)
|
||||
step - Single step CPU [with count xx]
|
||||
stepWhile - Single step CPU while <condition> is true
|
||||
swchb - Set SWCHB to value xx
|
||||
swchb - Set SWCHB to value xx
|
||||
tia - Show TIA state
|
||||
timer - Set a timer point
|
||||
trace - Single step CPU over subroutines [with count xx]
|
||||
trap - Trap read/write access to address(es) xx [yy]
|
||||
trapIf - On <condition> trap R/W access to address(es) xx [yy]
|
||||
|
@ -1563,6 +1586,9 @@ matches the address of the disassembly line where the mouse was clicked.</li>
|
|||
<li><b>Disassemble @ current line</b>: Disassemble from the disassembly line where the mouse was clicked.
|
||||
This allows to fill gaps in the disassembly and is most useful for bankswitched ROMs.</li>
|
||||
|
||||
<li><b>Set timer @ current line</b>: Set a timer point using the current
|
||||
disassembly line's address and bank</li>
|
||||
|
||||
<li><b>Show tentative code</b>: Allow DiStella to do a static analysis/disassembly.</li>
|
||||
|
||||
<li><b>Show PC addresses</b>: Show Program Counter addresses as labels (where there
|
||||
|
|
|
@ -577,6 +577,83 @@ const string& DebuggerParser::cartName() const
|
|||
return debugger.myOSystem.console().properties().get(PropType::Cart_Name);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void DebuggerParser::printTimer(uInt32 idx, bool showHeader)
|
||||
{
|
||||
if(idx >= debugger.m6502().numTimers())
|
||||
{
|
||||
commandResult << red("invalid timer");
|
||||
return;
|
||||
}
|
||||
|
||||
const TimerMap::Timer& timer = debugger.m6502().getTimer(idx);
|
||||
const bool banked = debugger.cartDebug().romBankCount() > 1;
|
||||
ostringstream buf;
|
||||
|
||||
if(!debugger.cartDebug().getLabel(buf, timer.from.addr, true))
|
||||
buf << " $" << setw(4) << Base::HEX4 << timer.from.addr;
|
||||
string labelFrom = buf.str();
|
||||
|
||||
buf.str("");
|
||||
if(!debugger.cartDebug().getLabel(buf, timer.to.addr, true))
|
||||
buf << " $" << setw(4) << Base::HEX4 << timer.to.addr;
|
||||
string labelTo = buf.str();
|
||||
|
||||
labelFrom = (labelFrom + " ").substr(0, banked ? 12 : 15);
|
||||
labelTo = (labelTo + " ").substr(0, banked ? 12 : 15);
|
||||
|
||||
if(showHeader)
|
||||
{
|
||||
if(banked)
|
||||
commandResult << " #| From /Bk| To /Bk| Execs| Avg. | Min. | Max. |";
|
||||
else
|
||||
commandResult << " #| From | To | Execs| Avg. | Min. | Max. |";
|
||||
}
|
||||
commandResult << endl << Base::toString(idx) << "|" << labelFrom;
|
||||
if(banked)
|
||||
{
|
||||
commandResult << "/" << setw(2) << setfill(' ');
|
||||
if(timer.from.bank == TimerMap::ANY_BANK)
|
||||
commandResult << "-";
|
||||
else
|
||||
commandResult << dec << static_cast<uInt16>(timer.from.bank);
|
||||
}
|
||||
commandResult << "|";
|
||||
if(timer.isPartial)
|
||||
commandResult << (banked ? " - " : " - ")
|
||||
<< "| -| -| -| -|";
|
||||
else
|
||||
{
|
||||
commandResult << labelTo;
|
||||
if(banked)
|
||||
{
|
||||
commandResult << "/" << setw(2) << setfill(' ');
|
||||
if(timer.to.bank == TimerMap::ANY_BANK)
|
||||
commandResult << "-";
|
||||
else
|
||||
commandResult << dec << static_cast<uInt16>(timer.to.bank);
|
||||
}
|
||||
commandResult << "|"
|
||||
<< setw(6) << setfill(' ') << dec << timer.execs << "|";
|
||||
if(!timer.execs)
|
||||
commandResult << " -| -| -|";
|
||||
else
|
||||
commandResult
|
||||
<< setw(6) << dec << timer.averageCycles() << "|"
|
||||
<< setw(6) << dec << timer.minCycles << "|"
|
||||
<< setw(6) << dec << timer.maxCycles << "|";
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void DebuggerParser::listTimers()
|
||||
{
|
||||
commandResult << "timers:" << endl;
|
||||
|
||||
for(uInt32 i = 0; i < debugger.m6502().numTimers(); ++i)
|
||||
printTimer(i, i == 0);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void DebuggerParser::listTraps(bool listCond)
|
||||
{
|
||||
|
@ -973,6 +1050,14 @@ void DebuggerParser::executeClearSaveStateIfs()
|
|||
commandResult << "all saveState points cleared";
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// "clearTimers"
|
||||
void DebuggerParser::executeClearTimers()
|
||||
{
|
||||
debugger.m6502().clearTimers();
|
||||
commandResult << "all timers cleared";
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// "clearTraps"
|
||||
void DebuggerParser::executeClearTraps()
|
||||
|
@ -1085,6 +1170,17 @@ void DebuggerParser::executeDelSaveStateIf()
|
|||
commandResult << red("no such saveStateIf");
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// "delTimer"
|
||||
void DebuggerParser::executeDelTimer()
|
||||
{
|
||||
const int index = args[0];
|
||||
if(debugger.m6502().delTimer(index))
|
||||
commandResult << "removed timer " << Base::toString(index);
|
||||
else
|
||||
commandResult << red("no such timer");
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// "delTrap"
|
||||
void DebuggerParser::executeDelTrap()
|
||||
|
@ -1623,6 +1719,16 @@ void DebuggerParser::executeListSaveStateIfs()
|
|||
commandResult << "no savestateifs defined";
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// "listTimers"
|
||||
void DebuggerParser::executeListTimers()
|
||||
{
|
||||
if(debugger.m6502().numTimers())
|
||||
listTimers();
|
||||
else
|
||||
commandResult << "no timers set";
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// "listTraps"
|
||||
void DebuggerParser::executeListTraps()
|
||||
|
@ -1732,6 +1838,13 @@ void DebuggerParser::executePrint()
|
|||
commandResult << eval();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// "printTimer"
|
||||
void DebuggerParser::executePrintTimer()
|
||||
{
|
||||
printTimer(args[0]);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// "ram"
|
||||
void DebuggerParser::executeRam()
|
||||
|
@ -1757,6 +1870,14 @@ void DebuggerParser::executeReset()
|
|||
commandResult << "reset system";
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// "resetTimers"
|
||||
void DebuggerParser::executeResetTimers()
|
||||
{
|
||||
debugger.m6502().resetTimers();
|
||||
commandResult << "all timers reset";
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// "rewind"
|
||||
void DebuggerParser::executeRewind()
|
||||
|
@ -2169,6 +2290,65 @@ void DebuggerParser::executeTia()
|
|||
commandResult << debugger.tiaDebug().toString();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// "timer"
|
||||
void DebuggerParser::executeTimer()
|
||||
{
|
||||
const uInt32 romBankCount = debugger.cartDebug().romBankCount();
|
||||
|
||||
if(argCount < 2)
|
||||
{
|
||||
const uInt16 addr = !argCount ? debugger.cpuDebug().pc() : args[0];
|
||||
const uInt8 bank = !argCount ? debugger.cartDebug().getBank(addr) : TimerMap::ANY_BANK;
|
||||
const uInt32 idx = debugger.m6502().addTimer(addr, bank);
|
||||
commandResult << "set timer " << dec << idx << " "
|
||||
<< (debugger.m6502().getTimer(idx).isPartial ? "start" : "end");
|
||||
if(!argCount)
|
||||
commandResult << " at $" << Base::HEX4 << (addr & TimerMap::ADDRESS_MASK);
|
||||
if(romBankCount > 1 && !argCount)
|
||||
commandResult << " + mirrors in bank #" << std::dec << static_cast<int>(bank);
|
||||
return;
|
||||
}
|
||||
else if(argCount > 4)
|
||||
{
|
||||
outputCommandError("too many arguments", myCommand);
|
||||
return;
|
||||
}
|
||||
|
||||
// Detect if 2nd parameter is bank
|
||||
if(argCount == 2 && args[0] >= 0x1000 && args[1] <= TimerMap::ANY_BANK)
|
||||
{
|
||||
const uInt16 addr = args[0];
|
||||
const uInt8 bank = args[1];
|
||||
if(bank >= romBankCount && bank != TimerMap::ANY_BANK)
|
||||
{
|
||||
commandResult << red("invalid bank");
|
||||
return;
|
||||
}
|
||||
const uInt32 idx = debugger.m6502().addTimer(addr, bank);
|
||||
commandResult << "set timer " << dec << idx << " "
|
||||
<< (debugger.m6502().getTimer(idx).isPartial ? "start" : "end");
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
const uInt8 bankFrom = argCount >= 3 ? args[2] : TimerMap::ANY_BANK;
|
||||
if(bankFrom >= romBankCount && bankFrom != TimerMap::ANY_BANK)
|
||||
{
|
||||
commandResult << red("invalid bank");
|
||||
return;
|
||||
}
|
||||
const uInt8 bankTo = argCount == 4 ? args[3] : bankFrom;
|
||||
if(bankTo >= romBankCount && bankTo != TimerMap::ANY_BANK)
|
||||
{
|
||||
commandResult << red("invalid bank");
|
||||
return;
|
||||
}
|
||||
const uInt32 idx = debugger.m6502().addTimer(args[0], args[1], bankFrom, bankTo);
|
||||
commandResult << "timer " << idx << " added";
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// "trace"
|
||||
void DebuggerParser::executeTrace()
|
||||
|
@ -2648,6 +2828,16 @@ DebuggerParser::CommandArray DebuggerParser::commands = { {
|
|||
std::mem_fn(&DebuggerParser::executeClearSaveStateIfs)
|
||||
},
|
||||
|
||||
{
|
||||
"clearTimers",
|
||||
"Clear all timers",
|
||||
"All timers cleared\nExample: clearTimers (no parameters)",
|
||||
false,
|
||||
false,
|
||||
{ Parameters::ARG_END_ARGS },
|
||||
std::mem_fn(&DebuggerParser::executeClearTimers)
|
||||
},
|
||||
|
||||
{
|
||||
"clearTraps",
|
||||
"Clear all traps",
|
||||
|
@ -2778,6 +2968,16 @@ DebuggerParser::CommandArray DebuggerParser::commands = { {
|
|||
std::mem_fn(&DebuggerParser::executeDelSaveStateIf)
|
||||
},
|
||||
|
||||
{
|
||||
"delTimer",
|
||||
"Delete timer <xx>",
|
||||
"Example: delTimer 0",
|
||||
true,
|
||||
false,
|
||||
{ Parameters::ARG_WORD, Parameters::ARG_END_ARGS },
|
||||
std::mem_fn(&DebuggerParser::executeDelTimer)
|
||||
},
|
||||
|
||||
{
|
||||
"delTrap",
|
||||
"Delete trap <xx>",
|
||||
|
@ -3035,6 +3235,16 @@ DebuggerParser::CommandArray DebuggerParser::commands = { {
|
|||
std::mem_fn(&DebuggerParser::executeListSaveStateIfs)
|
||||
},
|
||||
|
||||
{
|
||||
"listTimers",
|
||||
"List timers",
|
||||
"Lists all timers\nExample: listTimers (no parameters)",
|
||||
false,
|
||||
false,
|
||||
{ Parameters::ARG_END_ARGS },
|
||||
std::mem_fn(&DebuggerParser::executeListTimers)
|
||||
},
|
||||
|
||||
{
|
||||
"listTraps",
|
||||
"List traps",
|
||||
|
@ -3146,6 +3356,16 @@ DebuggerParser::CommandArray DebuggerParser::commands = { {
|
|||
std::mem_fn(&DebuggerParser::executePrint)
|
||||
},
|
||||
|
||||
{
|
||||
"printTimer",
|
||||
"Print statistics for timer <xx>",
|
||||
"Example: printTimer 0",
|
||||
true,
|
||||
false,
|
||||
{ Parameters::ARG_WORD, Parameters::ARG_END_ARGS },
|
||||
std::mem_fn(&DebuggerParser::executePrintTimer)
|
||||
},
|
||||
|
||||
{
|
||||
"ram",
|
||||
"Show ZP RAM, or set address xx to yy1 [yy2 ...]",
|
||||
|
@ -3166,6 +3386,16 @@ DebuggerParser::CommandArray DebuggerParser::commands = { {
|
|||
std::mem_fn(&DebuggerParser::executeReset)
|
||||
},
|
||||
|
||||
{
|
||||
"resetTimers",
|
||||
"Reset all timers' statistics" ,
|
||||
"All timers resetted\nExample: resetTimers (no parameters)",
|
||||
false,
|
||||
false,
|
||||
{ Parameters::ARG_END_ARGS },
|
||||
std::mem_fn(&DebuggerParser::executeResetTimers)
|
||||
},
|
||||
|
||||
{
|
||||
"rewind",
|
||||
"Rewind state by one or [xx] steps/traces/scanlines/frames...",
|
||||
|
@ -3404,6 +3634,16 @@ DebuggerParser::CommandArray DebuggerParser::commands = { {
|
|||
std::mem_fn(&DebuggerParser::executeTia)
|
||||
},
|
||||
|
||||
{
|
||||
"timer",
|
||||
"Set a cycle counting timer from addresses xx to yy [banks aa bb]",
|
||||
"Example: timer, timer 1000, timer 3000 3100, timer f000 f800 1",
|
||||
false,
|
||||
true,
|
||||
{ Parameters::ARG_WORD, Parameters::ARG_MULTI_BYTE },
|
||||
std::mem_fn(&DebuggerParser::executeTimer)
|
||||
},
|
||||
|
||||
{
|
||||
"trace",
|
||||
"Single step CPU over subroutines [with count xx]",
|
||||
|
|
|
@ -101,7 +101,7 @@ class DebuggerParser
|
|||
std::array<Parameters, 10> parms;
|
||||
std::function<void (DebuggerParser*)> executor;
|
||||
};
|
||||
using CommandArray = std::array<Command, 104>;
|
||||
using CommandArray = std::array<Command, 110>;
|
||||
static CommandArray commands;
|
||||
|
||||
struct Trap
|
||||
|
@ -142,6 +142,9 @@ class DebuggerParser
|
|||
void listTraps(bool listCond);
|
||||
string trapStatus(const Trap& trap);
|
||||
|
||||
void printTimer(uInt32 idx,bool showHeader = true);
|
||||
void listTimers();
|
||||
|
||||
// output the error with the example provided for the command
|
||||
void outputCommandError(const string& errorMsg, int command);
|
||||
|
||||
|
@ -162,6 +165,7 @@ class DebuggerParser
|
|||
void executeClearConfig();
|
||||
void executeClearHistory();
|
||||
void executeClearSaveStateIfs();
|
||||
void executeClearTimers();
|
||||
void executeClearTraps();
|
||||
void executeClearWatches();
|
||||
void executeCls();
|
||||
|
@ -175,6 +179,7 @@ class DebuggerParser
|
|||
void executeDelBreakIf();
|
||||
void executeDelFunction();
|
||||
void executeDelSaveStateIf();
|
||||
void executeDelTimer();
|
||||
void executeDelTrap();
|
||||
void executeDelWatch();
|
||||
void executeDisAsm();
|
||||
|
@ -200,6 +205,7 @@ class DebuggerParser
|
|||
void executeListConfig();
|
||||
void executeListFunctions();
|
||||
void executeListSaveStateIfs();
|
||||
void executeListTimers();
|
||||
void executeListTraps();
|
||||
void executeLoadAllStates();
|
||||
void executeLoadConfig();
|
||||
|
@ -211,8 +217,10 @@ class DebuggerParser
|
|||
void executePCol();
|
||||
void executePGfx();
|
||||
void executePrint();
|
||||
void executePrintTimer();
|
||||
void executeRam();
|
||||
void executeReset();
|
||||
void executeResetTimers();
|
||||
void executeRewind();
|
||||
void executeRiot();
|
||||
void executeRom();
|
||||
|
@ -236,6 +244,7 @@ class DebuggerParser
|
|||
void executeStepWhile();
|
||||
void executeSwchb();
|
||||
void executeTia();
|
||||
void executeTimer();
|
||||
void executeTrace();
|
||||
void executeTrap();
|
||||
void executeTrapIf();
|
||||
|
|
|
@ -48,6 +48,13 @@ RomListSettings::RomListSettings(GuiObject* boss, const GUI::Font& font)
|
|||
"RunTo PC @ current line", RomListWidget::kRuntoPCCmd);
|
||||
wid.push_back(runtoPC);
|
||||
|
||||
// Toggle timer
|
||||
ypos += buttonHeight + 4;
|
||||
auto* setTimer =
|
||||
new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight,
|
||||
"Set timer @ current line", RomListWidget::kSetTimerCmd);
|
||||
wid.push_back(setTimer);
|
||||
|
||||
// Re-disassemble
|
||||
ypos += buttonHeight + 4;
|
||||
auto* disasm =
|
||||
|
@ -154,6 +161,11 @@ void RomListSettings::handleCommand(CommandSender* sender, int cmd, int data, in
|
|||
sendCommand(cmd, _item, -1);
|
||||
break;
|
||||
}
|
||||
case RomListWidget::kSetTimerCmd:
|
||||
{
|
||||
sendCommand(cmd, _item, -1);
|
||||
break;
|
||||
}
|
||||
case RomListWidget::kDisassembleCmd:
|
||||
{
|
||||
sendCommand(cmd, _item, -1);
|
||||
|
|
|
@ -37,6 +37,7 @@ class RomListWidget : public EditableWidget
|
|||
// 'id' will be the Base::Format of the data
|
||||
kSetPCCmd = 'STpc', // 'data' will be disassembly line number
|
||||
kRuntoPCCmd = 'RTpc', // 'data' will be disassembly line number
|
||||
kSetTimerCmd = 'STtm',
|
||||
kDisassembleCmd = 'REds',
|
||||
kTentativeCodeCmd = 'TEcd', // 'data' will be boolean
|
||||
kPCAddressesCmd = 'PCad', // 'data' will be boolean
|
||||
|
|
|
@ -105,6 +105,11 @@ void RomWidget::handleCommand(CommandSender* sender, int cmd, int data, int id)
|
|||
runtoPC(data);
|
||||
break;
|
||||
|
||||
case RomListWidget::kSetTimerCmd:
|
||||
// 'data' is the line in the disassemblylist to be accessed
|
||||
setTimer(data);
|
||||
break;
|
||||
|
||||
case RomListWidget::kDisassembleCmd:
|
||||
// 'data' is the line in the disassemblylist to be accessed
|
||||
disassemble(data);
|
||||
|
@ -196,6 +201,20 @@ void RomWidget::runtoPC(int disasm_line)
|
|||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void RomWidget::setTimer(int disasm_line)
|
||||
{
|
||||
const uInt16 address = getAddress(disasm_line);
|
||||
|
||||
if(address != 0)
|
||||
{
|
||||
ostringstream command;
|
||||
command << "timer #" << address << " " << instance().debugger().cartDebug().getBank(address);
|
||||
const string& msg = instance().debugger().run(command.str());
|
||||
instance().frameBuffer().showTextMessage(msg);
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void RomWidget::disassemble(int disasm_line)
|
||||
{
|
||||
|
|
|
@ -51,6 +51,7 @@ class RomWidget : public Widget, public CommandSender
|
|||
void toggleBreak(int disasm_line);
|
||||
void setPC(int disasm_line);
|
||||
void runtoPC(int disasm_line);
|
||||
void setTimer(int disasm_line);
|
||||
void disassemble(int disasm_line);
|
||||
void patchROM(int disasm_line, const string& bytes,
|
||||
Common::Base::Fmt base);
|
||||
|
|
|
@ -9,6 +9,7 @@ MODULE_OBJS := \
|
|||
src/debugger/DiStella.o \
|
||||
src/debugger/RiotDebug.o \
|
||||
src/debugger/TIADebug.o
|
||||
src/debugger/TimerMap.o \
|
||||
|
||||
MODULE_DIRS += \
|
||||
src/debugger
|
||||
|
|
|
@ -264,8 +264,10 @@ inline void M6502::_execute(uInt64 cycles, DispatchResult& result)
|
|||
if(myBreakPoints.check(PC, bank))
|
||||
{
|
||||
myLastBreakCycle = mySystem->cycles();
|
||||
const uInt32 flags = myBreakPoints.get(PC, bank);
|
||||
|
||||
// disable a one-shot breakpoint
|
||||
if(myBreakPoints.get(PC, bank) & BreakpointMap::ONE_SHOT)
|
||||
if(flags & BreakpointMap::ONE_SHOT)
|
||||
{
|
||||
myBreakPoints.erase(PC, bank);
|
||||
return;
|
||||
|
@ -292,6 +294,9 @@ inline void M6502::_execute(uInt64 cycles, DispatchResult& result)
|
|||
}
|
||||
}
|
||||
|
||||
if(myTimer.isInitialized())
|
||||
myTimer.update(PC, mySystem->cart().getBank(PC), mySystem->cycles());
|
||||
|
||||
const int cond = evalCondBreaks();
|
||||
if(cond > -1)
|
||||
{
|
||||
|
@ -656,12 +661,12 @@ uInt32 M6502::addCondTrap(Expression* e, const string& name)
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool M6502::delCondTrap(uInt32 brk)
|
||||
bool M6502::delCondTrap(uInt32 idx)
|
||||
{
|
||||
if(brk < myTrapConds.size())
|
||||
if(idx < myTrapConds.size())
|
||||
{
|
||||
Vec::removeAt(myTrapConds, brk);
|
||||
Vec::removeAt(myTrapCondNames, brk);
|
||||
Vec::removeAt(myTrapConds, idx);
|
||||
Vec::removeAt(myTrapCondNames, idx);
|
||||
|
||||
updateStepStateByInstruction();
|
||||
|
||||
|
@ -691,4 +696,36 @@ void M6502::updateStepStateByInstruction()
|
|||
myStepStateByInstruction =
|
||||
!myCondBreaks.empty() || !myCondSaveStates.empty() || !myTrapConds.empty();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 M6502::addTimer(const uInt16 fromAddr, const uInt16 toAddr,
|
||||
const uInt8 fromBank, const uInt8 toBank)
|
||||
{
|
||||
return myTimer.add(fromAddr, toAddr, fromBank, toBank);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 M6502::addTimer(const uInt16 addr, const uInt8 bank)
|
||||
{
|
||||
return myTimer.add(addr, bank);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool M6502::delTimer(const uInt32 idx)
|
||||
{
|
||||
return myTimer.erase(idx);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void M6502::clearTimers()
|
||||
{
|
||||
myTimer.clear();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void M6502::resetTimers()
|
||||
{
|
||||
myTimer.reset();
|
||||
}
|
||||
|
||||
#endif // DEBUGGER_SUPPORT
|
||||
|
|
|
@ -31,6 +31,7 @@ class DispatchResult;
|
|||
#include "Expression.hxx"
|
||||
#include "TrapArray.hxx"
|
||||
#include "BreakpointMap.hxx"
|
||||
#include "TimerMap.hxx"
|
||||
#endif
|
||||
|
||||
#include "bspf.hxx"
|
||||
|
@ -248,15 +249,25 @@ class M6502 : public Serializable
|
|||
|
||||
// methods for 'trapif' handling
|
||||
uInt32 addCondTrap(Expression* e, const string& name);
|
||||
bool delCondTrap(uInt32 brk);
|
||||
bool delCondTrap(uInt32 idx);
|
||||
void clearCondTraps();
|
||||
const StringList& getCondTrapNames() const;
|
||||
|
||||
// methods for 'timer' handling:
|
||||
uInt32 addTimer(uInt16 fromAddr, uInt16 toAddr,
|
||||
uInt8 fromBank, uInt8 toBank);
|
||||
uInt32 addTimer(uInt16 addr, uInt8 bank);
|
||||
bool delTimer(uInt32 idx);
|
||||
void clearTimers();
|
||||
void resetTimers();
|
||||
uInt32 numTimers() const { return myTimer.size(); }
|
||||
const TimerMap::Timer& getTimer(uInt32 idx) const { return myTimer.get(idx); };
|
||||
|
||||
void setGhostReadsTrap(bool enable) { myGhostReadsTrap = enable; }
|
||||
void setReadFromWritePortBreak(bool enable) { myReadFromWritePortBreak = enable; }
|
||||
void setWriteToReadPortBreak(bool enable) { myWriteToReadPortBreak = enable; }
|
||||
void setLogBreaks(bool enable) { myLogBreaks = enable; }
|
||||
bool getLogBreaks() { return myLogBreaks; }
|
||||
bool getLogBreaks() const { return myLogBreaks; }
|
||||
#endif // DEBUGGER_SUPPORT
|
||||
|
||||
private:
|
||||
|
@ -465,6 +476,9 @@ class M6502 : public Serializable
|
|||
StringList myCondSaveStateNames;
|
||||
vector<unique_ptr<Expression>> myTrapConds;
|
||||
StringList myTrapCondNames;
|
||||
|
||||
TimerMap myTimer;
|
||||
|
||||
#endif // DEBUGGER_SUPPORT
|
||||
|
||||
bool myGhostReadsTrap{false}; // trap on ghost reads
|
||||
|
|
|
@ -856,6 +856,7 @@
|
|||
<ClCompile Include="..\..\debugger\gui\TrakBallWidget.cxx">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug-NoDebugger|x64'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\debugger\TimerMap.cxx" />
|
||||
<ClCompile Include="..\..\emucore\Bankswitch.cxx" />
|
||||
<ClCompile Include="..\..\emucore\Cart3EPlus.cxx" />
|
||||
<ClCompile Include="..\..\emucore\Cart3EX.cxx" />
|
||||
|
@ -2051,6 +2052,7 @@
|
|||
<ClInclude Include="..\..\debugger\gui\TrakBallWidget.hxx">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug-NoDebugger|x64'">true</ExcludedFromBuild>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\debugger\TimerMap.hxx" />
|
||||
<ClInclude Include="..\..\debugger\TrapArray.hxx">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug-NoDebugger|x64'">true</ExcludedFromBuild>
|
||||
</ClInclude>
|
||||
|
|
|
@ -1194,6 +1194,9 @@
|
|||
<ClCompile Include="..\..\common\sdl_blitter\QisBlitter.cxx">
|
||||
<Filter>Source Files\sdl_blitter</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\debugger\TimerMap.cxx">
|
||||
<Filter>Source Files\debugger</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\common\bspf.hxx">
|
||||
|
@ -2435,6 +2438,9 @@
|
|||
<ClInclude Include="..\..\common\smartmod.hxx">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\debugger\TimerMap.hxx">
|
||||
<Filter>Header Files\debugger</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="stella.ico">
|
||||
|
|
Loading…
Reference in New Issue