FCEUX debugger: Difference between revisions
Rainwarrior (talk | contribs) (→Reference: found a usage guide for debugger) |
Rainwarrior (talk | contribs) m (→Breakpoints: revise Forbid description) |
||
Line 44: | Line 44: | ||
Double click on a breakpoint in the BreakPoints frame to quickly disable or enable it. | Double click on a breakpoint in the BreakPoints frame to quickly disable or enable it. | ||
The Forbid option creates an anti-breakpoint that will prevent | The Forbid option creates an anti-breakpoint that will prevent the specified address from triggering any of the other breakpoints. These can also be enabled and disabled as needed. | ||
Breakpoints are listed in the following form: | Breakpoints are listed in the following form: |
Revision as of 21:23, 4 September 2012
Tips for using the FCEUX debugger.
Memory
The memory pane displays the current contents of the NES' RAM and ROM. The following memory ranges may display useful data for inspection:
0000-00FF - zero page 0100-01FF - stack 0200-07FF - ram 4018-FFFF - mapper controlled
Memory contents are displayed in this form:
0F:C0A8:24 1F BIT $001F = #$80 bb:mmmm:dd dd dd iiiiiiiiiiiiiiii
bb - 16k iNES bank, designates which 16k bank from the iNES file is mapped here mmmm - physical address on the NES CPU data bus dd - data bytes belonging to the instruction beginning at this address iiii - description of the instruction
An instruction description with "= #$xx" at the end indicates the value currently in memory at the address referenced by the instruction (before that instruction executes).
When debugging an NSF program, the bank designation will be a 4k NSF bank instead of the 16k iNES bank.
There is an empty column to the left of the memory view. Hovering the mouse here will display at the bottom of the window more detailed information about the location of this code in the iNES file. Left clicking on this column will open the inline assembler, which allows you to patch the ROM at runtime. Right clicking on this column will open the hex editor, which allows you to directly edit the ROM.
Inline Assembler
Open the inline assembler by clicking in the empty column to the left of the memory view.
The starting memory address is displayed in the PC field at the top of the inline assembler window. Type a line of assembly to add in the empty field just below this, and hit enter. The assembled code of your patch will appear line by line below.
Click apply to apply your patch to the ROM in memory. Click undo to remove the last assembled line. After applying a patch, clicking Save will allow you to save this patch directly to the ROM file.
Breakpoints
To create a breakpoint, click the Add button in the BreakPoints frame in the upper right corner of the debugger.
Each breakpoint has an address range to watch (use only the left address field if you wish to watch a single byte address). Check one or more of the options to watch for Read, Write, or Execute at an address. Note that fetching of code from an address will not break as a Read; use the Execute box for this.
Double click on a breakpoint in the BreakPoints frame to quickly disable or enable it.
The Forbid option creates an anti-breakpoint that will prevent the specified address from triggering any of the other breakpoints. These can also be enabled and disabled as needed.
Breakpoints are listed in the following form:
aaaa: EmRWXF : nnnn aaaa-aaaa: EmRWXF : nnnn
aaaa - address of breakpoint E - enabled m - memory area C = CPU, P = PPU, S = sprite R - read W - write X - execute F - forbid nnnn - name of breakpoint
When entering the address of a breakpoint, a small number of convenient strings may be used instead of the hexadecimal memory address:
NES special addresses:
- NMI/VBL - non-maskable interrupt vector at FFFA
- RST - reset vector at FFFC
- IRQ - interrupt vector at FFFE
FDS special addresses:
- NMI1 - non-maskable interrupt vector at DFF6
- NMI2 - non-maskable interrupt vector at DFF8
- NMI3 - non-maskable interrupt vector at DFFA
- RST - reset vector at DFFC
- IRQ - interrupt vector at DFFE
NSF special addresses:
- LOAD - NSF LOAD address
- INIT - NSF INIT address
- PLAY - NSF PLAY address
Conditional Breakpoints
Breakpoints may have a conditional statement that cause them to execute only if that statement evaluates to true. The conditional breakpoint grammar has this form:
* P -> Connect * Connect -> Compare {('||' | '&&') Compare} * Compare -> Sum {('==' | '!=' | '<=' | '>=' | '<' | '>') Sum} * Sum -> Product {('+' | '-') Product} * Product -> Primitive {('*' | '/') Primitive} * Primitive -> Number | Address | Register | Flag | PC Bank | '(' Connect ')' * Number -> '#' [1-9A-F]* * Address -> '$' [1-9A-F]* | '$' '[' Connect ']' * Register -> 'A' | 'X' | 'Y' | 'R' * Flag -> 'N' | 'C' | 'Z' | 'I' | 'B' | 'V' * PC Bank -> 'K'
The parser is very strict. All numbers are hexadecimal. Always prefix a number with # for an immediate value, or $ for a memory address. If a memory address needs to be calculated use $[] with the calculation inside the brackets. After entering a condition in the condition field, you should click Ok and then reopen the breakpoint with the Edit button. If there was a problem parsing your condition, it will have been erased.
Example Conditions
break if register A is less than value at memory address $0005:
A < $0005
break if the register used by the instruction contains 05:
R == #05
break if the value in memory at location (X * 256) + Y is not equal to FF:
#FF != $[(X*#100)+Y]
A Story
Once upon a time, an NES programmer was trying to determine where in the code a screwed up value was being written to a specific memory location. Specifically, when the value $EE was being written to location $0028. To figure out what can be put into the "condition" text input field in the breakpoint dialog box, he dug into the source code for FCEUX and found the parser, whose grammar is listed near the top of the source file.
After the programmer had been staring at the problem for too long, a fox came and helped him.
- Address:
28
- Click "Write"
- Memory:
CPU
(the default) - Condition:
R == #ee
if you don't know what CPU register is used for the write orX == #ee
if you know it's X. The # is important; leaving it out will screw it up.