1
0
Fork 0
mirror of https://github.com/imjasonh/nescript synced 2026-07-10 17:52:51 +00:00

compiler: PRNG / edge input / palette fade / AxROM / CNROM / FCEUX labels

Closes seven of the cc65/nesdoug parity gaps catalogued in
docs/future-work.md in a single pass. All of the new features are
gated on marker labels so programs that don't use them produce
byte-identical ROM output (every pre-existing committed .nes file
round-trips unchanged).

Language / runtime additions:
- `rand8()` / `rand16()` / `seed_rand(u16)` intrinsics backed by a
  16-bit Galois LFSR (~30 bytes of runtime, ~40 cycles per draw).
  Reset path seeds state to 0xACE1 so the first draw is useful even
  without explicit seeding.
- `p1.button.a.pressed` / `.released` edge-triggered input via a
  new ReadInputEdge IR op plus an NMI-side prev-frame snapshot into
  $07E6/$07E7, gated on the `__edge_input_used` marker.
- `set_palette_brightness(level)` builtin mapping levels 0..8 to
  PPU mask emphasis bytes (`$2001`) for neslib-style screen fades.
- `mapper: AxROM` (iNES 7) with automatic 32 KB PRG padding so
  emulators that enforce mapper-7's 32 KB page size boot cleanly.
- `mapper: CNROM` (iNES 3) with a reset-time CHR bank 0 select.
- `--fceux-labels <prefix>` CLI flag emitting per-bank `.nl` label
  files and a `.ram.nl` file for FCEUX's debugger.

Tests + examples:
- Five new example programs with committed .nes ROMs and
  pixel+audio goldens: prng_demo, edge_input_demo,
  palette_brightness_demo, axrom_simple, cnrom_simple.
- Seven integration tests covering JSR emission, the
  omitted-when-unused invariant, the NMI prev-input snapshot, the
  correct mapper numbers for AxROM/CNROM, and negative tests for
  unknown button names and bad rand8 arity.
- `is_intrinsic()` now runs in expression-position Call paths too,
  so `var x = rand8(1, 2)` errors at compile time instead of
  silently dropping the extra arguments.
This commit is contained in:
Claude 2026-04-18 18:13:18 +00:00
parent c96135fd86
commit 7507459787
No known key found for this signature in database
35 changed files with 1272 additions and 22 deletions

View file

@ -574,6 +574,7 @@ fn collect_source_temps(op: &IrOp, used: &mut HashSet<IrTemp>) {
}
IrOp::LoadVarHi(_, _)
| IrOp::ReadInput(_, _)
| IrOp::ReadInputEdge { .. }
| IrOp::WaitFrame
| IrOp::CycleSprites
| IrOp::Transition(_)
@ -582,9 +583,18 @@ fn collect_source_temps(op: &IrOp, used: &mut HashSet<IrTemp>) {
| IrOp::PlaySfx(_)
| IrOp::StartMusic(_)
| IrOp::StopMusic
| IrOp::Rand8(_)
| IrOp::Rand16(_, _)
| IrOp::SetPalette(_)
| IrOp::LoadBackground(_)
| IrOp::SourceLoc(_) => {}
IrOp::SeedRand(lo, hi) => {
used.insert(*lo);
used.insert(*hi);
}
IrOp::SetPaletteBrightness(level) => {
used.insert(*level);
}
}
}
@ -614,9 +624,12 @@ fn op_dest(op: &IrOp) -> Option<IrTemp> {
| IrOp::CmpLtEq(d, _, _)
| IrOp::CmpGtEq(d, _, _)
| IrOp::ArrayLoad(d, _, _) => Some(*d),
IrOp::Rand16(d, _) => Some(*d),
IrOp::Call(dest, _, _) => *dest,
IrOp::ReadInput(d, _) => Some(*d),
IrOp::ReadInputEdge { dest, .. } => Some(*dest),
IrOp::Peek(d, _) => Some(*d),
IrOp::Rand8(d) => Some(*d),
IrOp::StoreVar(_, _)
| IrOp::StoreVarHi(_, _)
| IrOp::ArrayStore(_, _, _)
@ -632,6 +645,8 @@ fn op_dest(op: &IrOp) -> Option<IrTemp> {
| IrOp::PlaySfx(_)
| IrOp::StartMusic(_)
| IrOp::StopMusic
| IrOp::SeedRand(_, _)
| IrOp::SetPaletteBrightness(_)
| IrOp::SetPalette(_)
| IrOp::LoadBackground(_)
| IrOp::SourceLoc(_) => None,