From 38bb891dd6bd0074894cbfedbf9185e303cc549e Mon Sep 17 00:00:00 2001 From: Gabriel Schneider Date: Wed, 26 Aug 2026 12:40:24 -0300 Subject: Offer the editor the board's pads, and check one flips on the die ## The board half of Gpio `pardes_p4_init` gained a `GpioFn` and the ABI version went to 2, which is what turns a mixed pair of builds into a refusal to boot rather than five arguments read as six. `gpioToggle` is four lines over `hal.gpio`: configure the pad as a readable output, read the level it is driving, drive the other one, read it again. It is deliberately here and not in the editor. A toggle is not a write to GPIO_OUT - `configureOutput` sets the IO MUX function, the GPIO matrix route, the drive strength, the input buffer and the pulls, then the output enable, indexed by a per-pin table - and that code is already in this repo, already the call `src/main.zig` blinks with, and already checked against ESP-IDF's headers by `zig build diff`. The editor object gets a function pointer instead of a second copy nobody tests. `getDrivenLevel`, not `getLevel`: the answer is the level the board is driving, which is defined for every pin. The pad's own level is what the outside world says, and on an unconnected header pin that is noise. The input buffer is enabled anyway so `Peek` of GPIO_IN_REG can be compared to it. ## A fifth hardware check `p4-bench --check` runs `Gpio 33` three times and requires 0->1, 1->0, 0->1. The alternation is the oracle, not either answer. `0->1` alone is what a firmware printing a hardcoded string would also say; two runs that disagree can only come from a level that was stored and read again. Three, so the third rules out an ordering coincidence. GPIO33 because `src/oracle/ledc_cases.zig` already documents it as a free pin on this board's JP1 header - pin 21 on the diagram the editor now draws. GPIO20 is the blink demo's pin and may have a wire on it. This is the only check here that crosses the whole seam: editor word, C ABI, HAL, pad, and the level back out through the message row. Nothing smaller exercises the ABI at all. ## -Dtheme-animation forwarded Same path as the geometry, for the same reason: baked into the object, wanted from here. All five checks pass on the die; host tests green; the board is flashed with md5 932898f34ca1dc31. --- tools/bench_main.zig | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'tools') diff --git a/tools/bench_main.zig b/tools/bench_main.zig index 18b204e..973c004 100644 --- a/tools/bench_main.zig +++ b/tools/bench_main.zig @@ -961,6 +961,34 @@ fn check(port: *serial.Port, o: Options, r: *Report) !void { r.print(" and a later Peek still finds it {s}\n", .{if (still) "ok" else "FAILED"}); if (!still) failures += 1; + // 4. A PAD ACTUALLY FLIPS, AND THE FIRMWARE READS IT BACK RATHER THAN ASSUMING IT. + // + // `Gpio ` crosses the whole seam this check exists for: the editor's word, the C ABI + // (`GpioFn`, which is why the ABI version is 2), the firmware's `hal.gpio` configure-and-drive, + // the pad, and the level read back out of the output register onto the message row. Nothing + // smaller exercises the ABI at all. + // + // The ORACLE IS THE ALTERNATION, not either answer alone. `0->1` on its own is what a firmware + // that printed a hardcoded string would also say; two runs reporting `0->1` then `1->0` can only + // come from a level that was stored somewhere and read again. Three runs, so the third confirms + // the second was not a coincidence of ordering. + // + // GPIO33 because `src/oracle/ledc_cases.zig` already documents it as a free pin on this board's + // JP1 header - pin 21. GPIO20 is the blink demo's pin and may have a wire on it. + var flips: [3][]const u8 = undefined; + var flip_text: [3][4096]u8 = undefined; + for (&flips, &flip_text) |*f, *dst| { + const raw = try runWord(port, &buf, "Gpio 33"); + f.* = stripAnsi(dst, raw); + } + const first_low = std.mem.indexOf(u8, flips[0], "33: 0->1") != null; + const alternates = for (flips, 0..) |f, i| { + const want = if ((i % 2 == 0) == first_low) "33: 0->1" else "33: 1->0"; + if (std.mem.indexOf(u8, f, want) == null) break false; + } else true; + r.print(" a pad flips and reads back {s}\n", .{if (alternates) "ok" else "FAILED"}); + if (!alternates) failures += 1; + // A BURST IS NOT CHECKED HERE, deliberately. The bug it would cover - input lost while the // transmitter was full - has a deterministic host test in `src/pardes/input_rescue.zig` that // loses 67 bytes with the rescue removed and needs no board at all. Every hardware oracle for it -- cgit v1.3