Skip to content

test(fixtures): multi-bit Hack ALU fixtures (parametric + single-file) - #71

Merged
jeffersonmourak merged 2 commits into
mainfrom
parametric-alu-fixture
May 25, 2026
Merged

test(fixtures): multi-bit Hack ALU fixtures (parametric + single-file)#71
jeffersonmourak merged 2 commits into
mainfrom
parametric-alu-fixture

Conversation

@jeffersonmourak

@jeffersonmourak jeffersonmourak commented May 25, 2026

Copy link
Copy Markdown
Owner

Summary

Two multi-bit Hack ALU test fixtures, each demonstrating a different language usage pattern:

Parametric project (tests/fixtures/projects/alu_parametric/):

  • A parametric Hack-style ALU sub-circuit (alu.circ) generic over <W>, plus four per-width root files (alu_2bit.circ, alu_4bit.circ, alu_6bit.circ, alu_8bit.circ) that instantiate it.
  • Each wrapper imports the parametric core and supplies a width-specific ripple-carry adder — the language can't express the carry chain parametrically (no iteration over bit positions).
  • Truth-table goldens included for the 2-bit (1024 rows) and 4-bit (16384 rows) wrappers; 6-bit (262k rows) and 8-bit (4M rows) are over the default --truth-table cap and are exercised via the .wasm runtime instead.

Single-file 4-bit (tests/fixtures/circuits/alu_4bit_multibit.circ):

  • A flat single-file companion to the existing scalar alu_4bit.circ — same Hack ALU logic, width-4 buses, no imports.
  • Truth-table golden matches the parametric 4-bit golden bit-for-bit on all 16,384 rows.

Why this is useful even with the workarounds

Both fixtures exercise three multi-bit-language papercuts surfaced while building them; each is worked around inline and documented in the fixture comments:

  1. Scalar→width-W broadcast can't go through a {c,c,...} concat directly into a parametric sub-circuit instance port. The wrappers route every scalar control through a wire[W] first.
  2. Sliced macro outputs feed scalar macros only via intermediate scalar wires — slice-into-scalar-macro trips the topology builder otherwise.
  3. xor[W] macro produces incorrect simulation values (or breaks topology build entirely) when its output flows through a wire-buffered slice chain into per-bit scalar macros. Both fixtures hand-expand the bit-parallel XOR propagate from and/not primitives. The variant that trips InternalError rather than producing wrong values appears specifically in the feedback chain from a sub-circuit instance's output back into its own input.

When these are fixed in the validator / topology builder / simulation engine, the workarounds collapse to one-line xor[W] calls and the goldens stay bit-identical — a clean diff later.

Test plan

  • zig-out/bin/circ-compile tests/fixtures/projects/alu_parametric/alu_2bit.circ --truth-table produces a 1024-row table matching the 2-bit golden.
  • zig-out/bin/circ-compile tests/fixtures/projects/alu_parametric/alu_4bit.circ --truth-table produces a 16384-row table matching both the parametric 4-bit golden and the existing scalar alu_4bit.truth.golden on every canonical Hack ALU operation.
  • zig-out/bin/circ-compile tests/fixtures/circuits/alu_4bit_multibit.circ --truth-table produces a 16384-row table identical to the parametric 4-bit golden (`diff` exit 0).
  • zig-out/bin/circ-compile tests/fixtures/projects/alu_parametric/alu_6bit.circ --truth-table --truth-table-cap=18 produces a 262k-row table (no golden checked in at this size).
  • zig-out/bin/circ-compile tests/fixtures/projects/alu_parametric/alu_8bit.circ -o /tmp/alu_8bit.wasm builds a self-contained ~955 KB .wasm.
  • Fixture-only — no source-code changes.

Add tests/fixtures/projects/alu_parametric/: a parametric Hack-style
ALU sub-circuit generic over <W>, plus four per-width root files that
instantiate it at W in {2, 4, 6, 8}. Each wrapper imports the
parametric core and supplies a width-specific ripple-carry adder
(the language can't express that parametrically: no iteration over
bit positions).

The wrappers document three multi-bit-language papercuts surfaced
while building this:

  1. Scalar -> width-W broadcast can't pass a {c,c,...} concat
     directly into a parametric sub-circuit instance port. The
     wrappers route every scalar control through a wire[W] first.
  2. Sliced macro outputs feed scalar macros only via intermediate
     scalar wires; slice-into-scalar-macro trips the topology
     builder otherwise.
  3. xor[W] macros and sub-circuit instances in the feedback chain
     from an instance's output back to its own input also trip the
     topology builder, so the bit-parallel propagate in each
     wrapper's adder is hand-expanded from and/not primitives.

Goldens included for the 2-bit (1024 rows) and 4-bit (16384 rows)
wrappers. 6-bit (262k rows) and 8-bit (4M rows) are above the
default --truth-table cap and are exercised via the .wasm runtime.
The 4-bit golden agrees with the existing scalar alu_4bit.truth.
golden on all canonical Hack ALU operations spot-checked.
Add tests/fixtures/circuits/alu_4bit_multibit.circ: a single-file
multi-bit variant of the scalar alu_4bit.circ, demonstrating the
same Hack ALU logic with width-4 buses. Sibling truth-table golden
matches the alu_parametric/alu_4bit golden bit-for-bit on all
16,384 rows, and matches the scalar alu_4bit.truth.golden on every
canonical operation spot-checked.

The fixture exercises the three multi-bit-language papercuts the
parametric project also works around, in a flatter single-file
context (no imports, no sub-circuit instances):

  1. Scalar broadcast routes through wire[4] (concat-into-macro
     port confuses the validator's width inference).
  2. xor[W] macro is hand-expanded from and/not primitives for the
     bit-parallel propagate -- the macro produces wrong simulation
     values when its output flows through a wire-buffered slice
     chain into the per-bit scalar macros below, even though it's
     correct in isolation.
  3. Slice-into-scalar-macro trips InternalError; per-bit slices
     are routed through scalar wire buffers.
@jeffersonmourak jeffersonmourak changed the title test(fixtures): parametric Hack ALU project with 2/4/6/8-bit wrappers test(fixtures): multi-bit Hack ALU fixtures (parametric + single-file) May 25, 2026
@jeffersonmourak
jeffersonmourak merged commit a9e1bcf into main May 25, 2026
3 checks passed
@jeffersonmourak
jeffersonmourak deleted the parametric-alu-fixture branch May 25, 2026 22:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant