1
0
Fork 0
mirror of https://github.com/imjasonh/nescript synced 2026-07-08 08:55:38 +00:00

Language: poke() and peek() hardware intrinsics

Common PPU/APU/mapper access previously required either variable
aliases or inline asm. Now two built-in intrinsics handle the
single-register case directly:

    poke(0x2006, 0x3F)     // STA \$3F, \$2006
    poke(0x2006, 0x00)
    poke(0x2007, 0x0F)
    var status: u8 = peek(0x2002)

- Analyzer: \`poke\` / \`peek\` are recognized as built-in intrinsics
  so they don't require a function declaration. Arity is still
  checked (E0203 on mismatch).
- IR: new \`IrOp::Poke(u16, IrTemp)\` and \`IrOp::Peek(IrTemp, u16)\`
  variants carrying the compile-time constant address.
- IR lowering: recognizes the \`poke\`/\`peek\` call names, evaluates
  the address as a const expression, and emits the intrinsic op.
  Falls back to a regular call if the address isn't a constant.
- IR codegen: emits a single LDA/STA in ZP or absolute mode based
  on whether the address fits in a byte.
- Optimizer: Poke has a source temp (liveness), Peek has a dest
  (new value); both pass through the existing passes.

https://claude.ai/code/session_01W6eQFStA66EuMKHUFo2rx3
This commit is contained in:
Claude 2026-04-12 17:40:34 +00:00
parent a45944e0f9
commit 496925344d
No known key found for this signature in database
7 changed files with 142 additions and 55 deletions

View file

@ -322,6 +322,26 @@ fn program_with_enums() {
rom::validate_ines(&rom_data).expect("should be valid iNES");
}
#[test]
fn program_with_poke_peek_intrinsics() {
let source = r#"
game "Hardware" { mapper: NROM }
var status: u8 = 0
on frame {
// Write to PPU address / data registers directly.
poke(0x2006, 0x3F)
poke(0x2006, 0x00)
poke(0x2007, 0x0F)
// Read PPU status.
status = peek(0x2002)
wait_frame
}
start Main
"#;
let rom_data = compile(source);
rom::validate_ines(&rom_data).expect("should be valid iNES");
}
#[test]
fn program_with_raw_asm_block() {
// `raw asm` bypasses `{var}` substitution so the body is passed