mirror of
https://github.com/imjasonh/nescript
synced 2026-07-08 08:55:38 +00:00
69 lines
2.5 KiB
Text
69 lines
2.5 KiB
Text
|
|
// UxROM User-Banked — first NEScript example to put real user code
|
||
|
|
// inside a switchable bank. The `bank Extras { fun ... }` block tells
|
||
|
|
// the linker that `step_animation` lives in the named PRG bank
|
||
|
|
// instead of the fixed bank; the IR codegen emits a
|
||
|
|
// `__tramp_step_animation` stub in the fixed bank, and every call
|
||
|
|
// from a state handler now goes through the trampoline (which
|
||
|
|
// selects bank 0 at $8000-$BFFF, JSRs the function, then restores
|
||
|
|
// the fixed bank before returning).
|
||
|
|
//
|
||
|
|
// UxROM is the friendliest mapper for this work because its
|
||
|
|
// `__bank_select` routine is a single bus-conflict-safe write to
|
||
|
|
// $FFF0; MMC1's serial shift register and MMC3's two-register dance
|
||
|
|
// would both work but add more moving parts to an already-large
|
||
|
|
// pipeline change.
|
||
|
|
//
|
||
|
|
// The example sweeps a smiley left-and-right entirely from inside
|
||
|
|
// the banked helper. The helper reads two globals (`px`, `dir`) and
|
||
|
|
// updates them in place — no parameters, no return value, so the
|
||
|
|
// fixed-bank call site is a single `JSR __tramp_step_animation`.
|
||
|
|
// The harness captures frame 180 somewhere along the sweep, so any
|
||
|
|
// regression in bank-switching, trampoline emission, or banked-stream
|
||
|
|
// assembly will flip the golden.
|
||
|
|
//
|
||
|
|
// Build: cargo run -- build examples/uxrom_user_banked.ne
|
||
|
|
|
||
|
|
game "UxROM User Banked" {
|
||
|
|
mapper: UxROM
|
||
|
|
mirroring: horizontal
|
||
|
|
}
|
||
|
|
|
||
|
|
// The banked helper drives `px` directly so the fixed-bank state
|
||
|
|
// handler is just `JSR __tramp_step_animation; draw Smiley`. `dir`
|
||
|
|
// is 0 while sweeping right and 1 while sweeping left.
|
||
|
|
var px: u8 = 110
|
||
|
|
var dir: u8 = 0
|
||
|
|
|
||
|
|
bank Extras {
|
||
|
|
// Step the smiley one pixel each frame, bouncing off x = 110
|
||
|
|
// and x = 150. The whole computation lives in the switchable
|
||
|
|
// bank: nothing here references any fixed-bank function, so the
|
||
|
|
// bank's instruction stream resolves cleanly during the linker's
|
||
|
|
// two-pass assembly without needing a second trampoline.
|
||
|
|
fun step_animation() {
|
||
|
|
if dir == 0 {
|
||
|
|
px = px + 1
|
||
|
|
if px == 150 {
|
||
|
|
dir = 1
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
px = px - 1
|
||
|
|
if px == 110 {
|
||
|
|
dir = 0
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
on frame {
|
||
|
|
// Trampoline call: the codegen emits `JSR __tramp_step_animation`
|
||
|
|
// because the function is tagged `bank: Some("Extras")`. The
|
||
|
|
// trampoline lives in the fixed bank, switches to bank 0, JSRs
|
||
|
|
// `__ir_fn_step_animation` at its $8000-window address, then
|
||
|
|
// switches back before returning.
|
||
|
|
step_animation()
|
||
|
|
draw Smiley at: (px, 120)
|
||
|
|
}
|
||
|
|
|
||
|
|
start Main
|