mirror of
https://github.com/imjasonh/nescript
synced 2026-07-08 08:55:38 +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:
parent
359241d906
commit
08322abda4
4 changed files with 127 additions and 26 deletions
|
|
@ -22,6 +22,15 @@ pub struct SpriteData {
|
|||
pub chr_bytes: Vec<u8>,
|
||||
}
|
||||
|
||||
/// True if `instructions` contains a label definition with the given
|
||||
/// name. Labels are emitted as `NOP` pseudo-instructions whose mode
|
||||
/// is `AddressingMode::Label(name)`.
|
||||
fn has_label(instructions: &[Instruction], name: &str) -> bool {
|
||||
instructions
|
||||
.iter()
|
||||
.any(|i| matches!(&i.mode, AM::Label(n) if n == name))
|
||||
}
|
||||
|
||||
/// A smiley face CHR tile for the default sprite (M1).
|
||||
const DEFAULT_SPRITE_CHR: [u8; 16] = [
|
||||
// Plane 0 (low bits)
|
||||
|
|
@ -109,6 +118,17 @@ impl Linker {
|
|||
|
||||
// NMI handler
|
||||
all_instructions.push(Instruction::new(NOP, AM::Label("__nmi".into())));
|
||||
// If user code emits an MMC3 reload hook, splice in a JSR
|
||||
// before the regular NMI runs. This reloads the scanline IRQ
|
||||
// counter each frame so the handler fires at the right line.
|
||||
// The presence of the `__ir_mmc3_reload` label is detected
|
||||
// during assembly via the labels map; we unconditionally
|
||||
// emit a conditional JSR whose target is resolved at link
|
||||
// time. The helper emits an RTS so it's safe to call even
|
||||
// when there's no work to do.
|
||||
if has_label(user_code, "__ir_mmc3_reload") {
|
||||
all_instructions.push(Instruction::new(JSR, AM::Label("__ir_mmc3_reload".into())));
|
||||
}
|
||||
all_instructions.extend(runtime::gen_nmi());
|
||||
|
||||
// IRQ handler
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue