summaryrefslogtreecommitdiff
path: root/src/runtime_config.zig
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-08-25 13:01:13 -0300
committerGabriel Schneider <[email protected]>2026-08-25 17:13:54 -0300
commit939e3a7288d6782139cac36f091ccd1d41cdfc0a (patch)
tree6b7b86c2ba4ade9f34c8f174354425a5d31a150a /src/runtime_config.zig
parente5f9e172330bc4500995ddd5954ed94f94e07af6 (diff)
downloadpardes-939e3a7288d6782139cac36f091ccd1d41cdfc0a.tar.gz
pardes-939e3a7288d6782139cac36f091ccd1d41cdfc0a.zip
A fourth platform: pardes as ESP32-P4 firmware, bytes in and bytes out
`-Dplatform=p4 -Dtarget=riscv32-freestanding` emits a single freestanding OBJECT exporting a seven-function C ABI, not an executable. The board's toolchain (../05-zig-p4) owns `_start`, the linker script and the UART driver and links this in. The seam is bytes rather than types, so neither side can accidentally depend on the other's internals, and a signature that drifts fails at link time. The serial line is the whole of the I/O. `src/p4.zig` drives vaxis unchanged over it: the renderer is a byte writer and `queryTerminalSend` is a byte writer, so the terminal emulator on the host answers the capability handshake and the firmware sees a real terminal. Measured going out over the wire on attach: alt screen, in-band resize, cursor report, kitty keyboard, kitty graphics, DA1. THREE WORDS EXIST ONLY HERE. `src/board_memory.zig` implements `Peek`, `Poke` and `Hexdump`, gated on `builtin.os.tag == .freestanding and !isWasm()` - derived from the TARGET, because they are a property of running with no OS under you rather than a product option, and because wasm is freestanding too and is exactly what must be excluded: in a browser an address is an offset into the linear memory this editor's own heap lives in. Every access goes through `*allowzero volatile`: a peripheral register is not memory, and address 0 is an ordinary unmapped address on this bus. One 4 KiB cap per command, set by the console rather than the memory - an unbounded dump would wedge the only console the board has for eleven hours. Measured on ESP32-P4 rev v1.3 silicon, driven from a host terminal: Peek 0x501101a4 0x0e63ce71, then 0xaeaa6919 on a second read - the RNG register, so the volatile loads are not folded Poke 0x5011002c 0xdeadbeef LP_STORE0; a later Peek returned 0xdeadbeef Hexdump 0x5011002c 32 16 bytes a row, hex columns and an ASCII gutter Peek 0x50110001 `peek: MisalignedAddress` on the message row That last line is the one that matters. A misaligned 32-bit access traps, and a trap in firmware is a watchdog reset that takes the session with it, so the check that turns it into a message is the reason the file is hand-written rather than a generic reader. BARE METAL BOOTS AN EMPTY OUTPUT BUFFER. Every other boot layout in `init` makes a shell, and on this platform that is not a preference but an impossibility: nothing to fork, no pty to give a terminal pane. Booting one anyway produced precisely what that describes - a pane whose tag ends in `Filter`, no gutter, no buffer, and every keystroke vanishing into the Fallback's silent pty. An output buffer is also what the platform's own words want, since Peek, Poke and Hexdump each fill one. Sized for the board rather than for a desktop: * `allocators.zig` gains a p4 tier that is ALL fallback - every capacity is zero, so each arena spills immediately to the 384 KiB heap the firmware hands over, and no megabyte-shaped static reservation lands in `.bss`. * `source_manifest.zig`'s allowlist is EMPTY on p4. The table is ~0.95 MiB of rodata against a 1.5 MiB flash partition; the firmware's filesystem is the serial host's, through the Host vtable. * The grid is clamped and the clamp is measured, not guessed: every cell is paid for four times (vaxis Screen + InternalScreen, pardes Surface + previous_cells), so 40x12 fits and 80x24 exhausts the heap during `Pardes.init`. * `Vaxis.resize` deinits both screens before allocating replacements, so a failed resize leaves vaxis rendering nothing. The p4 shell keeps the previous geometry on failure instead of leaving a half-applied one. Also here: `output_pane_integration_test.zig` had an exhaustive switch over `Platform` that adding `.p4` left unhandled, which broke `zig build unit-test` outright - the native test binary is the one consumer no platform build compiles. 346 tests pass again.
Diffstat (limited to 'src/runtime_config.zig')
-rw-r--r--src/runtime_config.zig26
1 files changed, 20 insertions, 6 deletions
diff --git a/src/runtime_config.zig b/src/runtime_config.zig
index 19964a48..bd1ba00b 100644
--- a/src/runtime_config.zig
+++ b/src/runtime_config.zig
@@ -5,6 +5,22 @@
const std = @import("std");
const panel_animation = @import("panel_animation.zig");
+/// HOW LONG A HOST-SUPPLIED ABSOLUTE PATH MAY BE, and the only reason this
+/// record was ever kilobytes: the shell a native host resolved, the font file
+/// a native picker returned, and (in pardes.zig) the one watched theme file.
+/// All three name something on a FILESYSTEM, and all three are retained
+/// inline because the core has no allocator at the point they arrive.
+///
+/// Fixed at 4095 wherever a filesystem exists — deliberately NOT derived from
+/// std.fs PATH_MAX, which web has no answer for, and 4095 rather than 4096 so
+/// the macOS C bridge's NUL fits without a second, subtly different limit at
+/// that boundary. Zero on the P4 firmware, which has no filesystem, no
+/// processes to spawn a shell for and no font picker: `Text(0)` is a
+/// zero-sized field whose `set` refuses every non-empty path, so the three
+/// producers report failure instead of storing 12 KiB nothing can fill.
+pub const host_path_cap: usize =
+ if (@import("pardes_config").platform == .p4) 0 else 4095;
+
/// Tagline glyphs retain body-cell geometry, so allowing a face larger than
/// the body would clip into neighbouring cells. Zero would make the role
/// invisible. Keep the runtime command on the same 1...100 contract as the
@@ -47,18 +63,16 @@ pub const State = struct {
/// pending until the next terminal spawn acknowledges it.
shell: struct {
requested: Text(255) = .{},
- // Fixed across native and freestanding builds: runtime State is one
- // data schema, and web has no std.fs PATH_MAX to derive this from.
- effective: Text(4095) = .{},
+ // One data schema across native, browser and freestanding builds; only
+ // its one absolute-path field follows `host_path_cap`.
+ effective: Text(host_path_cap) = .{},
pending: bool = true,
} = .{},
/// The shell acknowledges a font before `effective` changes. A rejected
/// request therefore remains queryable without claiming it is on screen.
font: struct {
- // 4095 leaves room for the NUL in the macOS C bridge without a
- // second, subtly different limit at that boundary.
- requested_path: Text(4095) = .{},
+ requested_path: Text(host_path_cap) = .{},
requested_name: Text(255) = .{},
effective_name: Text(255) = .{},
pending: bool = false,