backend: Add MX quant/dequant on-the-fly compute (size-changing datapath) - #167
Merged
Conversation
DanielKellerM
force-pushed
the
otf/size-changing-compute
branch
4 times, most recently
from
August 6, 2026 09:43
fca1db0 to
aa0bf44
Compare
…ath) Per-op source:dest byte ratios in idma_pkg program the legalizer write length; the compute seam presents per-lane pack occupancy with full strobes and retires lane-exactly against the byte lanes the write port accepted (buffer_out_ready), so partial tails stay sound and identical- config transfers pipeline back-to-back with zero inter-transfer bubbles. Transpose keeps the per-write-transaction retire and its single-beat burst contract (now asserted). Guard asserts fence every unsupported configuration; all of them are covered by firing negative tests.
Hoist the block-completion datapath out of the unrolled element loop (64x replicated at 1024b: 2048 quantizer sites -> 32), generate-gate the FP16 path above 512b, drop output registers that duplicated pack state, reduce the subnormal shifter to its 3 reachable amounts, and rebuild the dequant pack as a one-block-per-cycle expansion into a pow2 circular buffer (no byte shifting). Bit-exact vs the DPI golden and throughput-neutral; the naive engines did not finish synthesis in 14h, the restructured ones close 1 GHz timing in a 12 nm technology (quant 39.5k/71.5k cells at 512b/1024b, dequant 37.4k/52.8k).
DanielKellerM
force-pushed
the
otf/size-changing-compute
branch
from
August 10, 2026 13:46
0b0abd3 to
4b5b54b
Compare
DanielKellerM
changed the base branch from
backend/w-beat-done-retire
to
devel
August 10, 2026 13:47
Two deliberate corrections vs the viDMA ALCU reference, mirrored in the DPI golden: the E8M0 scale saturates at [-128,127] instead of wrapping (all-tiny blocks no longer flush), and Inf/NaN lanes no longer poison the shared scale of their block's finite lanes. Directed all-tiny and Inf/NaN-poisoned blocks added to the quant stimulus.
(length/33)*128 must fit tf_len_t; ComputeMxdequantLengthFits rejects the rest, negative case 11 proves it fires. The overlap negative case is retired: the request interlock (next commit) makes that stream legal.
A request whose compute config differs from the last accepted one is held at the legalizer input until the datapath drained, so its reads can never race a draining engine (gating at the write seam is provably too late: the next transfer's read data enters the shared buffer and the still- armed engine consumes it). Same-config streams pipeline unchanged at 100% utilization; the sub-unit asserts remain as backstops. The rand TB issues a different-config transfer pipelined behind the quant stream and checks it byte-exact.
Collaborator
Author
|
The merge was reverted off |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds size-changing on-the-fly compute (write byte count != read byte count) on top of the transpose/otf_compute framework, with MX (OCP microscaling) quantization and dequantization as the first ops. Based directly on
devel(an earlier revision stacked on #166; the per-beat retire signal turned out to be unnecessary — see the retire note below — so #166 was withdrawn).Mechanism. Per-op source:dest byte ratios in
idma_pkg(compute_in_bytes/compute_out_bytes) program the legalizer write length, so the write burst's beat count matches the beats the compute engine emits. The compute seam presents per-lane valid (pack-buffer occupancy) with full strobes; the write manager's own beat mask gates acceptance, and the engine retires lane-exactly against the byte lanes the write port actually consumed (buffer_out_ready), so a partial tail beat pops only its own bytes — no drain FSM, no transport-layer state machine, and back-to-back transfers with an identical compute config pipeline with zero inter-transfer bubbles. The legalizer asserts fence the contract: input-granule alignment, beat-aligned src/dst, per-beat-capable destination protocols (no TileLink), the FP16 width cap, and that the requested op is elaborated (EnableCompute/ComputeOps).Retire note (transpose unchanged). Transpose keeps devel's per-write-transaction retire (
w_dp_req_ready) and its existing contract that every transpose write burst is single-beat (guaranteed by the midend strip decomposition, now made explicit by theComputeTransposeSingleBeatassert — multi-beat transpose bursts mis-stream under any single-signal retire and were already unsupported on devel; a whole-tile "compact" transpose is future work). The MX ops do not use a scalar retire at all: they pop lane-exactly frombuffer_out_ready, which the write ports already produce per beat. An earlier revision (#166) re-exposed a per-beatw_beat_donepulse for this; it is not needed and was dropped.Ops (selected via
compute_cfg.compute_op, same programming model as transpose):COMPUTE_MXQUANTCOMPUTE_MXQUANT_FP16COMPUTE_MXDEQUANTMX block layout is inline
[1B E8M0 scale][32B E5M2]. The quantizer is RNE with full subnormal, saturation and Inf/NaN handling, bit-exact with the viDMA ALCU reference except two deliberate corrections (mirrored in the DPI golden): the E8M0 scale saturates instead of wrapping for all-tiny blocks, and Inf/NaN lanes are excluded from the shared-scale scan so a block's finite lanes survive. The split normal/subnormal rounding bands are load-bearing; do not merge them.Validation
Byte-exact against a DPI-C golden (
test/idma_mxquant_dpi.c, pure integer pipeline) on Questa 2026.1 at every legal StrbWidth (DataWidth 32/64/128/256/512/1024):tb_idma_mxquant: FP16 and FP32 sources, a genuine partial 33B tail beat, a 4K page-crossing write.tb_idma_mxroundtrip: quant -> dequant back-to-back through one backend, byte-exact at both stages (the exact E5M2 identity); FP16 leg at 512b, FP32 leg at 1024b (256 blocks, 32KB legs).tb_idma_mxrand: constrained-random campaign — 40 serialized transfers per run with a random op each (FP16/FP32 quant, dequant, plain unaligned copy), random block counts, writes biased across 4K boundaries, behind an AXI shim injecting 40% random per-channel stalls; canary bytes fence each destination.tb_idma_mxneg: every compute guard assert proven to fire (11 cases, incl. the transpose single-beat and dequant length-overflow fences). Note this PR also adds+define+INC_ASSERTto the sim flow — without itASSERT_NEVERcompiles to nothing, so the legalizer guard asserts (including pre-existing ones) were inert in simulation.tb_idma_transpose_b2b/tb_idma_transpose_ndunchanged and green (backward compatibility).tb_idma_mxperf: steady-state throughput vs a plain-copy baseline on ideal memory — the bottleneck channel (quant: R, dequant: W) sustains 100% bus utilization at every StrbWidth, both for single transfers and for pipelined back-to-back streams (aggregate window across 8 transfers including the boundaries); the other channel sits at the compression ratio (e.g. 33/128). Three microarchitectural points make this hold: pack-buffer space only gates block-completing input beats, the dequant pack buffer carries one expanded-block window of refill-during-drain headroom, and lane-exact retire keeps tails sound across transfer boundaries. The pipelined quant stream is also checked byte-exact under the random-stall shim intb_idma_mxrand.Known scope / disclosures
idma_backend_rw_axi. Size-changing compute on non-AXI src/dst is fenced withNOT IMPLEMENTEDasserts (ComputeMxSrcProtocol/ComputeMxDstProtocol) until validated; OBI is the natural first candidate (its write ready is already per-beat). Transpose keeps its pre-existing protocol scope.tb_idma_mxneg).ComputeOpsdefaults to'1: existingEnableComputedesigns gain the MX engines on regeneration (area); setComputeOpsexplicitly to opt out.BufferDepth=3,MemSysDepth=0, 1D transfers only.