Monitor/Debugger

Fuse features a moderately powerful, completely transparent monitor/debugger, which can be activated via the Machine, Debugger... menu option. A debugger window will appear, showing the current state of the emulated machine: the top-left `pane' shows the current state of the Z80 and the last bytes written to any emulated peripherals. The bottom-left pane lists any active breakpoints. Moving right, the next pane shows a disassembly, which by default starts at the current program counter, although this can be modified either by the `disassemble' command (see below) or by dragging the scrollbar next to it. The next pane shows the current stack, and the next pane has any `events' which are due to occur and could affect emulation. Below the events pane is the Spectrum's 64K memory map (the W? and C? indicate whether each 8K chunk is writeable or contended respectively). Below the displays are an entry box for debugger commands, and five buttons for controlling the debugger:

Evaluate Evaluate the command currently in the entry box.

Single Step Run precisely one Z80 opcode and then stop emulation again.

Continue Restart emulation, but leave the debugger window open. Note that the debugger window will not be updated while emulation is running.

Break Stop emulation and return to the debugger.

Close Close the debugger window and restart emulation.

Double-clicking on an entry in the stack pane will cause emulation to run until the program counter reaches the value stored at that address, while double-clicking on an entry in the `events' pane will cause emulation to run until that time is reached.

The main power of the debugger is via the commands entered into the entry box, which are similar in nature (but definitely not identical to or as powerful as) to those in the gdb debugger. In general, the debugger is case-insensitive, and numbers will be interpreted as decimal, unless prefixed by either `0x' or `$' when they will be interpreted as hex. Each command can be abbreviated to the portion not in curly braces.

ba{se} number Change the debugger window to displaying output in base number. Available values are 10 (decimal) or 16 (hex).

br{eakpoint} [address] [condition] Set a breakpoint to stop emulation and return to the debugger whenever an opcode is executed at address and condition evaluates true. If address is omitted, it defaults to the current value of PC.

br{eakpoint} p{ort} (r{ead}|w{rite}) port [condition] Set a breakpoint to trigger whenever IO port port is read from or written to and condition evaluates true.

br{eakpoint} (r{ead}|w{rite}) [address] [condition] Set a breakpoint to trigger whenever memory location address is read from (other than via an opcode fetch) or written to and condition evaluates true. Address again defaults to the current value of PC if omitted.

br{eakpoint} ti{me} time [condition] Set a breakpoint to occur time tstates after the start of every frame, assuming condition evaluates true (if one is given).

br{eakpoint} ev{ent} area:detail [condition] Set a breakpoint to occur when the event specified by area detail occurs and condition evaluates to true. The events which can be caught are:

divide:page
divide:unpage

The DivIDE interface is paged into or out of memory respectively

if1:page
if1:unpage

The Interface 1 shadow ROM is paged into or out of memory

rzx:end

An RZX recording finishes playing

tape:play
tape:stop

The emulated tape starts or stops playing

zxcf:page
zxcf:unpage

The ZXCF interface is paged into or out of memory

zxatasp:page
zxatasp:unpage

The ZXATASP interface is paged into or out of memory

In all cases, the event can be specified as area:* to catch all events from that area.

cl{ear} [address] Remove all breakpoints at address or the current value of PC if address is omitted. Port read/write breakpoints are unaffected.

cond{ition} id [condition] Set breakpoint id to trigger only when condition is true, or unconditionally if condition is omitted.

co{ntinue} Equivalent to the Continue button.

del{ete} [id] Remove breakpoint id, or all breakpoints if id is omitted.

di{sassemble} address Set the centre panel disassembly to begin at address.

fi{nish} Exit from the current CALL or equivalent. This isn't infallible: it works by setting a temporary breakpoint at the current contents of the stack pointer, so will not function correctly if the code returns to some other point or plays with its stack in other ways. Also, setting this breakpoint doesn't disable other breakpoints, which may trigger before this one. In that case, the temporary breakpoint remains, and the `continue' command can be used to return to it.

i{gnore} id count Do not trigger the next count times that breakpoint id would have triggered.

n{ext} Step to the opcode following the current one. As with the `finish' command, this works by setting a temporary breakpoint at the next opcode, so is not infalliable.

o{ut} port value Write value to IO port port.

se{t} address value Poke value into memory at address.

se{t} register value Set the value of the Z80 register register to value.

se{t} $variable value Set the value of the debugger variable variable to value.

s{tep} Equivalent to the Single Step button.

t{breakpoint} [options] This is the same as the `breakpoint' command in its various forms, except that that breakpoint is temporary: it will trigger once and once only, and then be removed.

Addresses can be specified in one of two forms: either an absolute addresses, specifed by an integer in the range 0x0000 to 0xFFFF or as a `page: offset ' combination, which refers to a location offset bytes into into memory bank page, independent of where that bank is currently paged into memory. RAM pages are indicated simply by an integer, while ROMs are prefixed by `R' (eg offset 0x1234 in ROM 1 is specified as `R1:0x1234'). Pages selected via the /ROMCS line are prefixed with `C', while the Timex Dock and Exrom use prefixes `D' and `X' respectively. The 48K machines are treated as having a permanent mapping of page 5 at 0x4000, page 2 at 0x8000 and page 0 at 0xC000; the 16K Spectrum is treated as having page 5 at 0x4000 and no page at 0x8000 and 0xC000.

Anywhere the debugger is expecting a numeric value, except where it expects a breakpoint id, you can instead use a numeric expression, which uses a restricted version of C's syntax; exactly the same syntax is used for conditional breakpoints, with `0' being false and any other value being true. In numeric expressions, you can use integer constants (all calculations are done in integers), register names (which simply evaluate to the value of the register), debugger variables, parentheses, the standard four numeric operations (`+', `-', `*' and `/'), the (non-)equality operators `==' and `!=', the comparision operators `>', `<', `>=' and `<=', bitwise and (`&'), or (`|') and exclusive or (`^') and logical and (`&&') and or (`||').