Expand description
fabric_grid — a TRUE reconfigurable CGRA: place a fabric’s dataflow onto a 2-D array of identical tiles and route it through a LOCAL switchbox interconnect. The same silicon runs any fabric by reconfiguration — not a bespoke circuit per program.
Interconnect: each tile drives two INDEPENDENT channels — a vertical vs (to its south
neighbor) and a horizontal he (to its east neighbor) — so a value flowing down and a value
routed across CROSS without conflict (the standard CGRA switchbox). Dataflow is feed-forward
(south/east only), so the array is a combinational DAG. A tile reads its north neighbor’s vs
and its west neighbor’s he; it may pass either through, TURN one into the other, source a
global input / constant, or COMPUTE (an Alu/Select tapping those inputs) and drive the
result onto a channel.
The point (proven in fabric_grid’s S3 tests): whatever the placer/router did, the placed +
routed array computes EXACTLY the abstract datapath — certified exhaustively by our own SAT.
That is the property a trustworthy CGRA compiler needs: place-and-route is semantics-preserving.
Structs§
- Bounded
Build - The
BoundedExprinstance ofDatapath— the tree form. - Gate
Build - The shared-gate-DAG instance of
Datapath— the form the certifier refutes, linear in the circuit instead of in its unfolding. - Grid
- A placed-and-routed CGRA: a
rows × colsarray of tiles plus the tile/channel that carries the result. Feed-forward (dataflow goes south/east), so it is a combinational DAG. - Tile
- One configured CGRA tile.
Enums§
- Cell
Kind - A tile’s optional compute: an arithmetic op or a predicated select over its visible sources.
- Chan
- Which output channel of a tile carries the fabric’s result.
- Drive
- What drives one of a tile’s output channels: a routed source, or the tile’s compute result.
- MemOp
- The three state-plane operations a
Memtile performs against the shared heap (seeCellKind::Mem). - Src2
- A value source visible to a tile: its north/west channel inputs, a global input, a constant, or zero (an unused channel).
Constants§
- TILE_
OPERAND_ CHANNELS - A mux tile’s operand channels: its north and its west. The interconnect gives each tile two.
Traits§
- Datapath
- The datapath vocabulary a placed grid — or a straight-line cell body — is lowered through.
Functions§
- cells_
datapath - Lower a straight-line
LoopCellbody through the datapath vocabularyb— the placer’s own lowering vocabulary, and the SPECIFICATION side of the placement obligation.Nonefor a cell with no propositional lowering (a functional unit, a memory tile, a packed-SIMD tile). - cells_
to_ gates - An ALU/select cell body lowered STRAIGHT INTO THE SHARED GATE DAG at
width. Linear in the CELLS: a cell read by three later cells is built once and shared by pointer, where the tree form copies it three times (and their readers copy those, and so on —fib.lg’s 75-cell body unfolds to 1 657 763 tree nodes from a few hundred). - certify_
reconfig - Certify the reconfigurable array END TO END (Phase 5): build one grid per source function (they must be
same-shape residuals so they place identically), then for EACH config value
kprove via our certified SAT thatconfig == kreconfigures the ONE array to be EXACTLY the bespoke islandgrids[k], for ALL inputs. Returns the per-config verdicts — alltrue⇒ the config word (streamed per block from the bytecode frame) losslessly selects any block’s datapath on one physical array: “the fabric IS the interpreter”. Each source is(program, fn_name)with a straight-line residual body. - emit_
config_ grid_ verilog - Emit the N-CONFIG reconfigurable array as combinational RTL — the synthesizable twin of
time_mux_n_bounded. ONErows×colstile grid runs ANY ofgridsselected by acfg-bit config word: every tile computes all N fabrics’ drives over the SHARED (config-muxed) neighbour channels and selects bycfg; the result muxes the N output taps.gridsmust share dimensions (pad withpad_gridfirst). This is what afabric_socflashes: sendcfg(the block index from the bytecode frame) + the inputs and the ONE array becomes that block’s datapath — proven semantics-preserving bycertify_config_table. - emit_
grid_ testbench - A self-checking testbench for the (combinational) tile array: drive each input vector, compare
resultto the VM oracle fromgrid_{name}_{in,out}.hex. - emit_
grid_ verilog - Emit the tile array as combinational RTL: two channel wires (
vs/he) per tile, each tile wired only to its north/west neighbours — a genuine nearest-neighbour spatial fabric. - emit_
time_ multiplexed - Emit the time-multiplexed array as combinational RTL: every tile computes BOTH fabrics’ drives
and muxes each channel on
ctx; the result muxes the two fabrics’ output taps. One silicon array, two programs — selected by a configuration bit. - eval_
grid - Simulate the grid (feed-forward, row-major) and return the PRIMARY output value.
- eval_
grid_ all - Simulate the grid and return ALL output values in
all_outsorder (for multi-output loop bodies). - eval_
grid_ all_ with_ heap - Like
eval_grid_allbut threads a SHARED heap (for a whole-program block walk with a state plane): everyMemtile touchesheap(persisting across blocks), and ALL outputs are returned inall_outs()order so the block-sequencing controller can commit the block’s register writes + read its terminator operand. For a heap-free grid this equalseval_grid_all(the heap stays empty). - eval_
grid_ with_ heap - Simulate a STATE-PLANE grid — one that carries
Mem(heap read/write/alloc) tiles — threading ONE shared heap through the tiles in row-major (= placement = program) order, exactly as the model’seval_cellsthreads its heap. Non-Memtiles evaluate combinationally (eval_cell); aMemtile touches the heap and drives its result onto its output channel. Returns the primary output. This is how Stage X2 proves collections/structs/text run on the grid:eval_grid_with_heap ≡ the whole-program model ≡ the VM. - grid_
area - The grid’s area footprint:
(rows, cols, used_tiles)— a tile is USED if it computes or drives a non-zero channel. Used to compare placements. - grid_
is_ combinational - True iff every placed tile is
Arith/Select(or pure routing) — i.e. the grid is fully COMBINATIONAL and SAT-lowerable. AFunc(division/float) tile has no bitblast lowering, so such a grid is proven by eval ≡ VM + iverilog, not bycertify_reconfig/certify_config_table; those refuse a non-combinational grid rather than panic opaquely inside the SAT lowering. - grid_
output_ datapath - Lower output
which(inall_outsorder) through the datapath vocabularyb, resolving the array row-major so every tile’s north/west inputs are already lowered (the feed-forward invariant).Nonewhen any live tile has no propositional lowering. - grid_
output_ to_ bounded - Lower output
which(inall_outsorder) to aBoundedExpratwidth, naming global inputs vianame_in— so the placed+routed array can be proven EQUAL to a reference expressed in the SAME variable namespace (e.g. a loop body’ss0/iv/inv0), exhaustively. - grid_
output_ to_ gates - Lower output
whichSTRAIGHT INTO THE SHARED GATE DAG atwidth— the certifier’s path. Same walk, same tiles, same circuit asgrid_output_to_bounded; it just never materialises the tree, which for a reconvergent datapath is exponentially larger than the array that computes it.Nonewhen a tile has no propositional lowering. - grid_
to_ bounded - The PRIMARY output’s
BoundedExpr(output 0) with the defaultin{k}input names. - pad_
grid - Pad a placed grid to a larger
target_rows × target_colsarray: copy its tiles into the TOP-LEFT corner and leave the rest IDLE. This RESOLVES the same-shape constraint the reconfigurable-array proof needs (time_mux_n_boundedrequires equal dimensions) — grids of DIFFERENT shapes co-reside on ONE array without touching any datapath. The output taps keep their positions (valid since the array only GREW), and the added IDLE tiles drive zero; because dataflow is feed-forward (south/east only), no downstream idle tile ever feeds an upstream one, so the padded grid computes EXACTLY the original (eval_grid(pad_grid(g, R, C)) == eval_grid(g)). Panics if asked to shrink. - route_
leveled - AREA-MINIMIZING placer (level scheduling). The naive
route_straight_linegives every cell two rows (a routing row + a compute row). But a cell whose operands are all global inputs or constants (topological LEVEL 0) needs NO routing row — its operands are tapped directly — so all level-0 cells share ONE compute row (row 0), packed across columns. Deeper cells still get their own routing+compute rows. For DAGs with input-parallelism this collapses the row count (a chain saves a little; a wide fan-in tree saves a lot). Correctness is unchanged — the S3 SAT proof validates the compact placement exactly as it did the naive one. - route_
loop_ body - Map a LOOP BODY onto the tile array. Same diagonal placement + Manhattan routing as the
straight-line case, but each
LoopCellmay be aSelect(a mux tile — the grid already models it), and the body produces MULTIPLE outputs (one per loop-carried next-state register, innextorder). Global-input / constant operands are tapped directly; cell-value operands route (each distinct producer takes one of the tile’s two channels — a computed PREDICATE routes exactly like a computed data arm, and two ports reading one producer share a channel). This grid is the combinational BODY datapath of a loop-on-a-grid — the controller (counter / fabric predicate) latches its outputs, exactly as with the hand-wired body. - route_
straight_ line - The placer + router. Map a straight-line fabric (
FabricOpSSA, from the real compiled residual) onto the tile array. Placement: cellicomputes on the diagonal at(2(i+1), i)— its own columnicarries its result downward. Routing: an operand that is a global input or constant is TAPPED directly (inputs fan out for free); an operand that is another cell’s value is routed via a Manhattan path — forked EAST off its column (he←N, which coexists with the column’s downwardvs←N, so fan-out costs nothing) and turned back into the consumer’s north (vs←W) or read from its west. Correct by construction; the S3 SAT proof catches any slip. - run_
program_ cfg_ on_ grid - Run a whole (acyclic-control-flow) function on the reconfigurable GRID (Stage X4 — the whole-program XPU).
Each basic block’s straight-line body is PLACED on a fresh tile array (
route_loop_body, the block’s live-in registers as inputs) with its downstreamSrcs as the grid’s outputs — every register write, then the terminator’s predicate/return operand;eval_grid_allreads them off the placed array, the register file is updated, and a block-sequencing controller walks the terminator graph (Jump/Branch/Return), reconfiguring the array to the next block. So a BRANCHY whole program runs as spatial dataflow on ONE array (each block a reconfiguration), proven ≡eval_program_cfg_fabric≡ the VM. A block may carryMem(heap read/write/alloc) tiles: ONE heap is threaded across every reconfiguration (eval_grid_all_with_heap), so collections/structs persist across blocks — the state plane. (Loops are the separate loop fabric.) - tile_
channel_ demand - How many operand channels the switchbox must route into ONE tile for
cell. - time_
mux_ bounded - The combined output of a TIME-MULTIPLEXED array: one physical grid whose every tile is muxed by
a
ctxselector between fabrica’s config (ctx=1) and fabricb’s config (ctx=0). Because the neighbour channels are themselves ctx-muxed, when ctx=1 the whole array carriesa’s dataflow and when ctx=0 it carriesb’s — proven in the P3 test.aandbmust share dims. - time_
mux_ n_ bounded - The RECONFIGURABLE array (Phase 5): ONE tile grid runs ANY of
gridsselected by a CONFIG WORD — the generalization oftime_mux_boundedfrom a 1-bitctx(2 fabrics) to acfg_width-bit word (N fabrics). Every tile computes all N fabrics’ drives over the SHARED muxed neighbour channels, then selects byconfig; the output tap muxes likewise. This is “the fabric IS the interpreter”: the config word (streamed per block from theLGB1frame) reconfigures the SAME silicon to be any block’s datapath.configis fixed to a concrete value here so the lock proves, per valuek, that the reconfigured array is EXACTLY the bespoke islandgrids[k](config == k ⇒ array ≡ grids[k]). All grids must share dimensions (same-shape fabrics place identically). - unroutable_
cell - The first cell of
cellsthe router cannot place, as(cell index, channels it demands).Nonewhen every cell fits the interconnect. The gate a certifier consults BEFORE callingroute_loop_body, so an unplaceable body is declined by name instead of panicking inside the placer.