1
0
Fork 0
mirror of https://github.com/imjasonh/nescript synced 2026-07-12 10:39:31 +00:00

Codegen: on_scanline per-state dispatch + NMI reload

Extends the \`on_scanline\` codegen to support multiple scanline
handlers across states:

- \`__irq_user\` now dispatches by \`current_state\`: each state with a
  scanline handler gets a CMP/BNE/JSR entry in the dispatch table.
  States without a handler fall through to just acknowledge the IRQ.
- New \`__ir_mmc3_reload\` helper that (re)loads the MMC3 counter
  latch based on \`current_state\`. States without a scanline handler
  fall through to disable the IRQ (\$E000 write).
- Linker detects the \`__ir_mmc3_reload\` label in user code and
  splices a JSR into it at the top of the NMI handler, so the
  counter is reloaded once per frame with the current state's
  target scanline.
- IRQ handler no longer re-enables IRQ on ACK (the NMI reload now
  handles that) so it won't fire multiple times per frame.
- Program init chooses the start state's scanline count (if any) or
  the first scanline handler found as a fallback.

Also fixes \`dump_asm\`: a \`NOP\` with a \`Label\` operand is a label
definition, but any other opcode with a \`Label\` operand is a real
instruction like \`JSR foo\`. The old dump was hiding JSR/JMP targets.

https://claude.ai/code/session_01W6eQFStA66EuMKHUFo2rx3
This commit is contained in:
Claude 2026-04-12 16:29:15 +00:00
parent 359241d906
commit 08322abda4
No known key found for this signature in database
4 changed files with 127 additions and 26 deletions

View file

@ -90,10 +90,18 @@ fn main() {
}
fn dump_asm(instructions: &[nescript::asm::Instruction]) {
use nescript::asm::{AddressingMode, Opcode};
for inst in instructions {
if let nescript::asm::AddressingMode::Label(name) = &inst.mode {
println!("{name}:");
continue;
// A bare `NOP` with a `Label` operand is a label *definition*
// (the pseudo-instruction the codegen emits when marking a
// position). Any other opcode with `Label` mode is an actual
// instruction like `JSR foo` or `JMP bar`, so we show the
// opcode + target.
if inst.opcode == Opcode::NOP {
if let AddressingMode::Label(name) = &inst.mode {
println!("{name}:");
continue;
}
}
println!(" {:?} {:?}", inst.opcode, inst.mode);
}