From 0dba7af51bd1ea24738150bf02892ea3fb78fbdc Mon Sep 17 00:00:00 2001
From: Thomas Jentzsch
Using the ` key will always enter the debugger at the end of -the frame (for NTSC games usually scanline 262). This is because Stella only checks +the frame (for NTSC games usually scanLine 262). This is because Stella only checks for keystrokes once per frame. Once in the debugger, you can control -execution by stepping one instruction, scanline, or frame at a time +execution by stepping one instruction, scanLine, or frame at a time (or more than one at a time, using commands in the prompt). You can also set breakpoints or traps, which will cause the emulator to enter the debugger when they are triggered, even if it happens in mid-frame.
@@ -408,7 +408,7 @@ in detail in the User's Guide.The debugger tracks changes to the CPU, TIA and RIOT registers and RAM by displaying changed locations or registers with a red background after each step, -trace, scanline, or frame advance. This sounds simple, and it is, but +trace, scanLine, or frame advance. This sounds simple, and it is, but it's also amazingly useful.
One clarification about the change tracking: it only tracks when values @@ -476,7 +476,8 @@ completions (try with "tr" instead of "g"), you'll see a list of them, and your partial name will be completed as far as possible. After the first character, the autocompletion considers all characters in the right order as a match (e.g. "twf" will be completed to -"trapwriteif").
+"trapWriteIf"). Alternatively you can make use of the camel case names and type +e.g. "tWI" ("trapWriteIf") or "lAS" ("LoadAllStates").Tab completion works on all labels: built-in, loaded from a symbol file, or set during debugging with the "define" command. It also works with @@ -630,10 +631,10 @@ set it. In the example, "break kernel" will remove the breakpoint. The "break" command can be thought of as a *toggle*: it turns the breakpoint on & off, like a light switch.
-You could also use "clearbreaks" to remove all the breakpoints. Also, -there is a "listbreaks" command that will list them all.
+You could also use "clearBreaks" to remove all the breakpoints. Also, +there is a "listBreaks" command that will list them all.
-¹ By enabling "logbreaks" you can log the current state into +
¹ By enabling "logBreaks" you can log the current state into the System Log and continue emulation instead.
"breakif !(*SWCHB&1)" will do the job for us. However, it's an ugly mess +
"breakIf !(*SWCHB&1)" will do the job for us. However, it's an ugly mess of letters, numbers, and punctuation. We can do a little better:
-"breakif { !(*SWCHB & 1 ) }" is a lot more readable, isn't it? If +
"breakIf { !(*SWCHB & 1 ) }" is a lot more readable, isn't it? If you're going to use readable expressions with spaces in them, enclose the entire expression in curly braces.
@@ -676,9 +677,9 @@ condition that depends on input (like SWCHB) will always happen at the end of a frame. This is different from how a real 2600 works, but most ROMs only check for input once per frame anyway. -Conditional breaks appear in "listbreaks", numbered starting from -zero. You can remove a cond-break with "delbreakif number", where -the number comes from "listbreaks" or by entering the same conditional break again.
+Conditional breaks appear in "listBreaks", numbered starting from +zero. You can remove a cond-break with "delBreakIf number", where +the number comes from "listBreaks" or by entering the same conditional break again.
Any time the debugger is entered due to a trap, breakpoint, or conditional break, the reason will be displayed in the @@ -687,16 +688,16 @@ conditional break, the reason will be displayed in the
There is one annoyance about complex expressions: once we -remove the conditional break with "delbreakif" or "clearbreaks", +remove the conditional break with "delBreakIf" or "clearBreaks", we'd have to retype it (or search backwards with the up-arrow key) if we wanted to use it again.
We can avoid this by defining the expression as a function, then using -"breakif function_name":
+"breakIf function_name":function gameReset { !(*SWCHB & 1 ) } - breakif gameReset + breakIf gameReset
Now we have a meaningful name for the condition, so we can use it again. @@ -706,16 +707,16 @@ if the Game Select switch is pressed. We want to break when the user presses both Select and Reset:
- breakif { gameReset && gameSelect } + breakIf { gameReset && gameSelect }-
User-defined functions appear in "listfunctions", which shows the label +
User-defined functions appear in "listFunctions", which shows the label and expression for each function. Functions can be removed with -"delfunction label", where the labels come from "listfunctions".
+"delFunction label", where the labels come from "listFunctions".Stella has some pre-defined functions for use with the "breakif" +
Stella has some pre-defined functions for use with the "breakIf" command. These allow you to break and enter the debugger on various conditions without having to define the conditions yourself.
@@ -726,24 +727,24 @@ Stella debugger.Function | Definition | Description |
---|---|---|
_joy0left | !(*SWCHA & $40) | Left joystick moved left |
_joy0right | !(*SWCHA & $80) | Left joystick moved right |
_joy0up | !(*SWCHA & $10) | Left joystick moved up |
_joy0down | !(*SWCHA & $20) | Left joystick moved down |
_joy0button | !(*INPT4 & $80) | Left joystick button pressed |
_joy1left | !(*SWCHA & $04) | Right joystick moved left |
_joy1right | !(*SWCHA & $08) | Right joystick moved right |
_joy1up | !(*SWCHA & $01) | Right joystick moved up |
_joy1down | !(*SWCHA & $02) | Right joystick moved down |
_joy1button | !(*INPT5 & $80) | Right joystick button pressed |
_joy0Left | !(*SWCHA & $40) | Left joystick moved left |
_joy0Right | !(*SWCHA & $80) | Left joystick moved right |
_joy0Up | !(*SWCHA & $10) | Left joystick moved up |
_joy0Down | !(*SWCHA & $20) | Left joystick moved down |
_joy0Fire | !(*INPT4 & $80) | Left joystick fire button pressed |
_joy1Left | !(*SWCHA & $04) | Right joystick moved left |
_joy1Right | !(*SWCHA & $08) | Right joystick moved right |
_joy1Up | !(*SWCHA & $01) | Right joystick moved up |
_joy1Down | !(*SWCHA & $02) | Right joystick moved down |
_joy1Fire | !(*INPT5 & $80) | Right joystick fire button pressed |
_select | !(*SWCHB & $02) | Game Select pressed |
_reset | !(*SWCHB & $01) | Game Reset pressed |
_color | *SWCHB & $08 | Color/BW set to Color |
_bw | !(*SWCHB & $08) | Color/BW set to BW |
_diff0b | !(*SWCHB & $40) | Left difficulty set to B (easy) |
_diff0a | *SWCHB & $40 | Left difficulty set to A (hard) |
_diff1b | !(*SWCHB & $80) | Right difficulty set to B (easy) |
_diff1a | *SWCHB & $80 | Right difficulty set to A (hard) |
_diff0B | !(*SWCHB & $40) | Left difficulty set to B (easy) |
_diff0A | *SWCHB & $40 | Left difficulty set to A (hard) |
_diff1B | !(*SWCHB & $80) | Right difficulty set to B (easy) |
_diff1A | *SWCHB & $80 | Right difficulty set to A (hard) |
Don't worry about memorizing them all: the Prompt "help" command @@ -759,36 +760,36 @@ that holds 'number of scanlines' on an actual console).
Function | Description |
---|---|
_bank | Currently selected bank |
_cclocks | Color clocks on a scanline |
_cycleshi | Higher 32 bits of number of cycles since emulation started |
_cycleslo | Lower 32 bits of number of cycles since emulation started |
_fcount | Number of frames since emulation started |
_fcycles | Number of cycles since frame started |
_ftimreadcycles | Number of cycles used by timer reads since frame started |
_fwsynccycles | Number of cycles skipped by WSYNC since frame started |
_icycles | Number of cycles of last instruction |
_scan | Current scanline count |
_scanend | Scanline count at end of last frame |
_scycles | Number of cycles in current scanline |
_timwrapread | Timer read wrapped on this cycle |
_timwrapwrite | Timer write wrapped on this cycle |
_vblank | Whether vertical blank is enabled (1 or 0) |
_vsync | Whether vertical sync is enabled (1 or 0) |
_cClocks | Color clocks on a scanLine |
_cyclesHi | Higher 32 bits of number of cycles since emulation started |
_cyclesLo | Lower 32 bits of number of cycles since emulation started |
_fCount | Number of frames since emulation started |
_fCycles | Number of cycles since frame started |
_fTimReadCycles | Number of cycles used by timer reads since frame started |
_fWsyncCycles | Number of cycles skipped by WSYNC since frame started |
_iCycles | Number of cycles of last instruction |
_scan | Current scanLine count |
_scanEnd | Scanline count at end of last frame |
_sCycles | Number of cycles in current scanLine |
_timWrapRead | Timer read wrapped on this cycle |
_timWrapWrite | Timer write wrapped on this cycle |
_vBlank | Whether vertical blank is enabled (1 or 0) |
_vSync | Whether vertical sync is enabled (1 or 0) |
_scan always contains the current scanline count. You can use +
_scan always contains the current scanLine count. You can use this to break your program in the middle of your kernel. Example:
- breakif _scan==#64 + breakIf _scan==#64
This will cause Stella to enter the debugger when the TIA reaches the -beginning of the 64th scanline.
+beginning of the 64th scanLine._bank always contains the currently selected bank. For 2K or 4K (non-bankswitched) ROMs, it will always contain 0. One useful use is:
- breakif { pc==myLabel && _bank==1 } + breakIf { pc==myLabel && _bank==1 }
This is similar to setting a regular breakpoint, but it will only trigger @@ -807,8 +808,8 @@ pointed to by the Y register, even if the Y register changes.
The watches are numbered. The numbers are printed along with the watches, so you can tell which is which. To delete a watch use the -"delwatch" command with the watch number (1 to whatever). You can -also delete them all with the "clearwatches" command.
+"delWatch" command with the watch number (1 to whatever). You can +also delete them all with the "clearWatches" command.Note that there's no real point in watching a label or CPU register without dereferencing it: Labels are constants, and CPU registers @@ -821,7 +822,7 @@ accesses to a memory address, rather than specific location in the program. They're useful for finding code that modifies TIA registers or memory.
-Traps can also combined with a condition ("trapif"). If an access +
Traps can also combined with a condition ("trapIf"). If an access to a memory address is caught, the condition is evaluated additionally. Only if the condition is true too, the emulations stops. For details about conditions see Conditional Breaks described above.
@@ -845,12 +846,12 @@ so the best we can do is stop before the next instruction runs.Traps come in two varieties: read access traps and write access traps. It is possible to set both types of trap on the same address (that's what the plain "trap" command does). To set a read or write only trap, -use "trapread(if)" or "trapwrite(if)". +use "trapRead(if)" or "trapWrite(if)". -
All traps appear in "listtraps", numbered starting from zero. You -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.
+All traps appear in "listTraps", numbered starting from zero. You +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.
This will be automatically loaded the next time your start the debugger. - From there on, you can continue analyzing the ROM and then use "saveconfig" - again to update the configuration. You can also use "loadconfig" to load it + From there on, you can continue analyzing the ROM and then use "saveConfig" + again to update the configuration. You can also use "loadConfig" to load it manually.
Note that this is not tested for multi-banked ROMs.
Note that this currently only works for single banked ROMs. For larger ROMs, the created disassembly is incomplete.
saverom: - If you have manipulated a ROM, you can save it with "saverom". The file is +
saveRom: + If you have manipulated a ROM, you can save it with "saveRom". The file is named "<rom_filename>.a26".
saveses: - The "saveses" command dumps the whole prompt session into a file named +
saveSes: + The "saveSes" command dumps the whole prompt session into a file named "<YYYY-MM-DD_HH-mm-ss>.txt". So you can later lookup what you did exactly when you were debugging at that time.
saveallstates: +
saveAllStates: This command works identical to the save all states hotkey (Alt + F9) during emulation. - The saved states can be loaded with "loadallstates".
+ The saved states can be loaded with "loadAllStates".savestate: +
saveState: This command works identical to the save state hotkey (F9) during emulation. - Any previously saved state can be loaded with "loadstate" plus the slot + Any previously saved state can be loaded with "loadState" plus the slot number (0-9).
In the upper left of the debugger, you'll see the current frame of video as generated by the TIA. If a complete frame hasn't been drawn, the partial contents of the current frame will be displayed up to the -current scanline, with the contents of the old frame (in black & +current scanLine, with the contents of the old frame (in black & white) filling the rest of the display. Note that if 'phosphor mode' or TV effects are enabled, you won't see the effects here; this shows the raw TIA image only.
-To e.g. watch the TIA draw the frame one scanline at a time, you can +
To e.g. watch the TIA draw the frame one scanLine at a time, you can use the 'Scan+1' button, the prompt "scan" command or the Control-L key.
You can also right-click anywhere in this window to show a context menu, @@ -1128,10 +1129,10 @@ as illustrated:
The options are as follows:
The indicators are as follows (note that all these are read-only):
These options allow you to: