4.8 KiB
PR-02 — PBS Prelude: Add SAFE builtins for Color / ButtonState / Pad / Touch (bounded)
Goal
Expose hardware types to PBS scripts as value structs using bounded (no u16).
Required PBS definitions (in prelude / hardware module)
Put these in the standard library surface that PBS sees without user creating them.
pub declare struct Color(value: bounded)
[
(r: int, g: int, b: int): (0b) as rgb
{
...
}
]
[[
BLACK: (...) {}
WHITE: (...) {}
RED: (...) {}
GREEN: (...) {}
BLUE: (...) {}
MAGENTA: (...) {}
TRANSPARENT: (...) {}
COLOR_KEY: (...) {}
]]
{
pub fn raw(self: Color): bounded;
}
pub declare struct ButtonState(
pressed: bool,
released: bool,
down: bool,
hold_frames: bounded
)
pub declare struct Pad(
up: ButtonState,
down: ButtonState,
left: ButtonState,
right: ButtonState,
a: ButtonState,
b: ButtonState,
x: ButtonState,
y: ButtonState,
l: ButtonState,
r: ButtonState,
start: ButtonState,
select: ButtonState
)
{
pub fn any(self: Pad): bool;
}
pub declare struct Touch(
f: ButtonState,
x: int,
y: int
)
Semantics / constraints
Color.valuestores the hardware RGB565 raw asbounded.hold_framesisbounded.x/yremainint.
Implementation notes (binding)
Color.rgb(r,g,b)must clamp inputs to 0..255 and then pack to RGB565.Color.raw()returns the internal bounded.Pad.any()must be a pure SAFE function compiled normally (no hostcall).
Tests (mandatory)
- FE/typecheck:
Color.WHITEis aColor. - FE/typecheck:
Gfx.clear(Color.WHITE)typechecks. - FE/typecheck:
let p: Pad = Input.pad(); if p.any() { }typechecks.
Non-goals
- No heap types
- No gates
PR-03 — Lowering: Host Contracts for Gfx/Input using deterministic syscalls
Goal
Map PBS host contracts to stable syscalls with a deterministic ABI.
Required host contracts in PBS surface
pub declare contract Gfx host
{
fn clear(color: Color): void;
}
pub declare contract Input host
{
fn pad(): Pad;
fn touch(): Touch;
}
Required lowering rules
Gfx.clear(color)
- Emit
SYSCALL_GFX_CLEAR - ABI: args = [Color.raw] as
bounded - returns: void
Input.pad()
- Emit
SYSCALL_INPUT_PAD - args: none
- returns: flattened
Padin field order as declared
Input.touch()
- Emit
SYSCALL_INPUT_TOUCH - args: none
- returns: flattened
Touchin field order as declared
Flattening order (binding)
ButtonState returns 4 slots in order:
- pressed (bool)
- released (bool)
- down (bool)
- hold_frames (bounded)
Pad returns 12 ButtonState blocks in this exact order:
up, down, left, right, a, b, x, y, l, r, start, select
Touch returns:
- f (ButtonState block)
- x (int)
- y (int)
Tests (mandatory)
- Lowering golden test:
Gfx.clear(Color.WHITE)emitsSYSCALL_GFX_CLEARwith 1 arg. - Lowering golden test:
Input.pad()emitsSYSCALL_INPUT_PADand assigns to local. - Lowering golden test:
Input.touch()emitsSYSCALL_INPUT_TOUCH.
Non-goals
- No runtime changes
- No VM heap
PR-04 — Runtime: Implement syscalls for Color/Gfx and Input pad/touch + integration cartridge
Goal
Make the new syscalls actually work and prove them with an integration test cartridge.
Required syscall implementations
1) SYSCALL_GFX_CLEAR
-
Read 1 arg:
boundedraw color -
Convert to
u16internally (runtime-only)- If raw > 0xFFFF, trap
TRAP_OOBorTRAP_TYPE(choose one and document)
- If raw > 0xFFFF, trap
-
Fill framebuffer with that RGB565 value
2) SYSCALL_INPUT_PAD
-
No args
-
Snapshot the current runtime
Padand push a flattenedPadreturn:- For each button: pressed, released, down, hold_frames
- hold_frames pushed as
bounded
3) SYSCALL_INPUT_TOUCH
-
No args
-
Snapshot
Touchand push flattenedTouchreturn:- f ButtonState
- x int
- y int
Integration cartridge (mandatory)
Add test-cartridges/hw_hello (or similar) with:
fn frame(): void
{
// 1) clear screen white
Gfx.clear(Color.WHITE);
// 2) read pad and branch
let p: Pad = Input.pad();
if p.any() {
Gfx.clear(Color.MAGENTA);
}
// 3) read touch and branch on f.down
let t: Touch = Input.touch();
if t.f.down {
// choose a third color to prove the struct returned correctly
Gfx.clear(Color.BLUE);
}
}
Acceptance criteria
- Cartridge runs without VM faults.
- With no input: screen is WHITE.
- With any pad button held: screen becomes MAGENTA.
- With touch f.down: screen becomes BLUE.
Tests (mandatory)
- Runtime unit test:
SYSCALL_GFX_CLEARrejects raw > 0xFFFF deterministically. - Runtime unit test:
SYSCALL_INPUT_PADreturns correct number of stack slots (48). - Runtime unit test:
SYSCALL_INPUT_TOUCHreturns correct number of stack slots (4 + 2 = 6).