mirror of
https://github.com/imjasonh/nescript
synced 2026-07-11 02:02:58 +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:
parent
a45944e0f9
commit
496925344d
7 changed files with 142 additions and 55 deletions
|
|
@ -411,8 +411,20 @@ impl LoweringContext {
|
|||
self.emit(IrOp::WaitFrame);
|
||||
}
|
||||
Statement::Call(name, args, _) => {
|
||||
let arg_temps: Vec<_> = args.iter().map(|a| self.lower_expr(a)).collect();
|
||||
self.emit(IrOp::Call(None, name.clone(), arg_temps));
|
||||
match name.as_str() {
|
||||
// Built-in `poke(addr, value)` — write a byte to
|
||||
// a compile-time-constant address.
|
||||
"poke" if args.len() == 2 => {
|
||||
if let Some(addr) = self.eval_const(&args[0]) {
|
||||
let val = self.lower_expr(&args[1]);
|
||||
self.emit(IrOp::Poke(addr, val));
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
let arg_temps: Vec<_> = args.iter().map(|a| self.lower_expr(a)).collect();
|
||||
self.emit(IrOp::Call(None, name.clone(), arg_temps));
|
||||
}
|
||||
}
|
||||
}
|
||||
Statement::Scroll(x_expr, y_expr, _) => {
|
||||
let x = self.lower_expr(x_expr);
|
||||
|
|
@ -768,6 +780,15 @@ impl LoweringContext {
|
|||
t
|
||||
}
|
||||
Expr::Call(name, args, _) => {
|
||||
// Built-in `peek(addr)` reads a byte from a fixed
|
||||
// absolute address at compile time.
|
||||
if name == "peek" && args.len() == 1 {
|
||||
if let Some(addr) = self.eval_const(&args[0]) {
|
||||
let t = self.fresh_temp();
|
||||
self.emit(IrOp::Peek(t, addr));
|
||||
return t;
|
||||
}
|
||||
}
|
||||
let arg_temps: Vec<_> = args.iter().map(|a| self.lower_expr(a)).collect();
|
||||
let t = self.fresh_temp();
|
||||
self.emit(IrOp::Call(Some(t), name.clone(), arg_temps));
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue