mirror of
https://github.com/imjasonh/nescript
synced 2026-07-11 18:20:47 +00:00
debug: add debug.frame_overrun_count() and debug.frame_overran() builtins
The frame-overrun counter at $07FF was previously only readable via `peek(0x07FF)`, which forces every program that wants to guard against missed frames to know the magic address. This adds two named query expressions: - `debug.frame_overrun_count()` — cumulative miss count since reset - `debug.frame_overran()` — sticky bit cleared by the next wait_frame, so `debug.assert(not debug.frame_overran())` catches a miss in the previous window without waiting for the counter to roll over. The sticky bit lives at $07FE alongside the existing counter and is set inside the same NMI-time overrun branch. Release builds emit none of the runtime side: the NMI handler still skips both writes, the codegen `wait_frame` only clears $07FE in debug mode, and committed example ROMs stay byte-identical. The new expression form parses through `parse_primary`'s `KwDebug` arm, so the existing `debug.log(...)` / `debug.assert(...)` *statement* parser stays untouched. The analyzer rejects unknown methods with E0201 and stray arguments with E0203 so typos don't silently compile to a zero load. https://claude.ai/code/session_01KEczoNUX3WmcFLfq6iAQxB
This commit is contained in:
parent
bf7819ca0f
commit
d4e613fb7c
9 changed files with 401 additions and 7 deletions
|
|
@ -1090,6 +1090,29 @@ impl LoweringContext {
|
|||
// For now, just evaluate the inner expression (truncation/extension is a no-op on 8-bit)
|
||||
self.lower_expr(inner)
|
||||
}
|
||||
Expr::DebugCall(method, _args, _) => {
|
||||
// The analyzer already validated the method name and
|
||||
// argument count, so we can dispatch on the method
|
||||
// name directly. Both currently-supported methods
|
||||
// map to a Peek of a runtime address: the codegen
|
||||
// strips the read out and substitutes a constant
|
||||
// zero in release builds, so the builtin disappears
|
||||
// from non-debug ROMs.
|
||||
let t = self.fresh_temp();
|
||||
let addr: u16 = match method.as_str() {
|
||||
"frame_overrun_count" => 0x07FF,
|
||||
"frame_overran" => 0x07FE,
|
||||
// Should be unreachable post-analyzer, but emit
|
||||
// a zero rather than panicking so a parser test
|
||||
// that bypasses the analyzer still produces IR.
|
||||
_ => {
|
||||
self.emit(IrOp::LoadImm(t, 0));
|
||||
return t;
|
||||
}
|
||||
};
|
||||
self.emit(IrOp::Peek(t, addr));
|
||||
t
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue