Conditional breakpoints
A PC breakpoint can carry a condition so it only fires when the machine is in a state you care about — far quicker than stepping by hand. Attach one with the ADP bp command:
bp add pc <addr> if <cond>The condition is evaluated only once the address has already matched, so the hot path stays a cheap compare — the expression cost is paid only at that PC.
Grammar
The condition parser (crates/debugger/src/condition.rs) accepts:
or := and ( "||" and )*
and := cmp ( "&&" cmp )*
cmp := unary ( ( "==" | "!=" | "<" | "<=" | ">" | ">=" ) unary )?
unary := "!" unary | "(" or ")" | operand
operand := value ( "&" number )? // optional bit-mask
value := register | flag | "(" expr ")" | "nr[" n "]" | "nrraw[" n "]" | numberA bare expression (no comparison) is truthy when non-zero, so a & 0x80 breaks whenever bit 7 of A is set.
Operands
Registers
a f b c d e h l (8-bit) and af bc de hl ix iy sp pc i r (16-bit), plus the shadow set af' bc' de' hl' (also spelled af2 bc2 de2 hl2).
Flags
fs (sign), fz (zero), fh (half-carry), fpv / fp (parity/overflow), fn (add/subtract), fc (carry). Each is 1 or 0.
Memory
(expr) is the byte in memory at the address expr — paging-resolved (what the CPU sees). The inner expression can itself use registers: (hl), (0x4000), (sp).
Next registers
Two forms, and the distinction matters:
nr[N]— the CPU read-back value (decoded/gated — what software sees viaIN $253B).nrraw[N]— the stored/written byte (what was last written to the register).
These can differ where the hardware composes the read (e.g. MMU slots: nr[0x56] reads back the live effective slot). When you suspect a paging/register bug, check both.
Numbers
Decimal, or hex with 0x / $ (0x8000, $C0, 192 are all valid).
Operators
| Kind | Operators |
|---|---|
| Comparison | == != < <= > >= |
| Logic | && || ! |
| Bit-mask | & (applied to an operand, e.g. nr[7] & 3) |
| Grouping | ( … ) around a sub-condition |
Examples
bp add pc 0000 if i == 0xbd # only the demo's IM2 crash, not a NextZXOS launch at $0000
bp add pc 8000 if a == 0x3b
bp add pc 9abc if (hl) > 0x4000 && b != 0 # memory deref + logic
bp add pc 6276 if fz && sp < 0xff00 # flag + register
bp add pc 7752 if nr[0x56] != nrraw[0x56] # catch a raw-vs-read-back paging divergence
bp add pc 4a00 if a & 0x80 # bit test — break when bit 7 of A is setWatchpoints
To break on memory access rather than a PC, add a watchpoint (no condition expression):
bp add mem <addr> [r|w|rw]It breaks when <addr> is read (r), written (w) or either (rw, the default; rw registers two breakpoints), reporting the hit exactly like a PC breakpoint — so you catch what touches a byte without knowing where in the code. For headless memory-write watching, the Rhai on_mem_write + watch_mem event is usually more convenient.
For anything beyond a single condition — reacting to events, accumulating state across hits — use Rhai scripting. (Note: script eval <expr> is the Rhai language, not this condition grammar — don’t confuse the two.)