Compute
On-the-Fly Compute Role
iDMA can transform data while it is in flight instead of moving it verbatim. The compute engine sits in the transport layer on the write side, between the read dataflow buffer and the write barrel shifter, so the transform runs on the beats streaming from source to destination with no round trip to memory. It is optional and elaborated only when EnableCompute is set; otherwise the write path is a plain pass-through.
Two op families are provided:
- Transpose (
idma_otf_transpose) - tiled matrix transpose, element size 1/2/4/8 B. - MX quant / dequant (
idma_otf_mxquant,idma_otf_mxdequant) - OCP microscaling conversion between FP32/FP16 and MXFP8, with the FP cast math insrc/idma_float_pkg.sv.
A single dispatcher, idma_otf_compute, routes one op per transfer to the selected sub-unit. Changing the compute config drains the engine before the next transfer starts.
Elaboration and Selection
Compute is configured at two levels:
Compile time (backend/transport-layer parameters):
| Parameter | Type | Description |
|---|---|---|
EnableCompute | bit | Elaborate the compute engine at all |
ComputeOps | idma_pkg::compute_enable_t | Per-op enable mask: transpose, mxquant, mxdequant, mxfp16 |
ComputeTuning | idma_pkg::compute_tuning_t | Implementation knobs (transpose_full_duplex) |
mxfp16 gates the FP16 source/destination paths of the MX ops; leaving it off drops that area. An op requested at run time but not elaborated is caught by the legalizer (ComputeOpUnsupported) and a simulation assertion in the dispatcher.
Per transfer (idma_req_t.opt.compute, type idma_pkg::compute_options_t):
| Field | Description |
|---|---|
enable | Arm compute for this transfer |
op | idma_pkg::compute_op_e selector |
params.transpose | mode (element size), tensor_m, tensor_n (elements) |
The register frontend exposes these through its compute_cfg register. The op encoding is single-homed in src/frontend/reg/idma_reg.rdl and re-exported as idma_pkg::compute_op_e:
compute_op_e | Meaning | Input granule | Output granule |
|---|---|---|---|
COMPUTE_NONE | Plain copy | - | - |
COMPUTE_TRANSPOSE | Tiled transpose | = output | = input |
COMPUTE_MXQUANT | Quantize, FP32 source | 128 B / block | 33 B / block |
COMPUTE_MXQUANT_FP16 | Quantize, FP16 source | 64 B / block | 33 B / block |
COMPUTE_MXDEQUANT | Dequantize, FP32 destination | 33 B / block | 128 B / block |
COMPUTE_MXDEQUANT_FP16 | Dequantize, FP16 destination | 33 B / block | 64 B / block |
Transpose
idma_otf_transpose transposes a row-major M x N tensor using flip-flop tile banks. The element size is E = 1 << mode bytes (8/16/32/64 bit); tiles are NE x NE elements where NE = StrbWidth / E. Input is fed padded to full tiles in (col-tile, row-tile, row) order and the output realizes out[n][m] = in[m][n]; partial edge tiles are masked with the per-byte output strobe. Dimensions are TransposeDimWidth = 12 bits (elements).
Tuning: with transpose_full_duplex = 1 two tile banks let the engine fill one bank while draining the other (full rate, ~1 + 1/NE cycles per NE-beat tile); 0 uses a single bank at half area and half rate.
Transpose does not change transfer size (input bytes == output bytes). The write side is currently single-beat: the legalizer rejects transpose transfers with length > StrbWidth (ComputeTransposeSingleBeat); tiling across a larger tensor is driven by the midend issuing single-beat strips.
MX Quant / Dequant
The MX ops implement OCP microscaling (MX) format conversion in blocks of MxBlockElems = 32 elements. A compressed MX block is MxBlockBytes = 33 B: one E8M0-style block scale byte followed by 32 MXFP8 (E5M2) element bytes. The uncompressed forms are FP32 (4 * 32 = 128 B) or FP16 (2 * 32 = 64 B) per block.
- Quantize (
idma_otf_mxquant): gathers a 32-element block from the input beats (FP32 4 B/elem, or FP16 2 B/elem widened to FP32), computes the block scale from the maximum element exponent (Inf/NaN lanes excluded; the scale saturates rather than wrapping), casts each element to E5M2 with round-to-nearest-even and full subnormal support, and emits the packed 33 B block. - Dequantize (
idma_otf_mxdequant): expands each 33 B MX block back to FP32 (128 B) or FP16 (64 B), applying the decoded block scale per element.
The FP cast primitives (FP32 <-> MXFP8 E5M2, FP16 <-> FP32 widen/narrow, block-scale computation) live in the idma_float_pkg package.
Size-Changing Transfers
MX ops change the byte count between read and write. The legalizer computes the write length from the per-op ratio:
write_length = (req.length / compute_in_bytes(op)) * compute_out_bytes(op)and forces decouple_rw / decouple_aw on for any compute transfer. Constraints enforced by legalizer assertions:
| Assertion | Requirement |
|---|---|
ComputeSizeAligned | length is a whole multiple of the op’s input granule |
ComputeSrcAligned / ComputeDstAligned | src/dst addresses are beat-aligned for size-changing ops |
ComputeMxdequantBeatAligned | dequant input length is a multiple of MxBlockBytes * StrbWidth |
ComputeMxFp16Width | FP16 element formats require StrbWidth <= 64 (at most one block per beat) |
ComputeMxSrcProtocol / ComputeMxDstProtocol | size-changing ops are AXI-only on src and dst (OBI is a TODO) |
ComputeDstTilelink | compute retires per beat, so a TileLink destination is not supported |
ComputeMxdequantLengthFits | dequant output length must fit the length field width |
Source Files
src/backend/idma_otf_compute.sv- per-transfer op dispatchersrc/backend/idma_otf_transpose.sv- tiled transpose enginesrc/backend/idma_otf_mxquant.sv,src/backend/idma_otf_mxdequant.sv- MX pack/expandsrc/idma_float_pkg.sv- FP32/FP16 <-> MXFP8 cast math and block scalesrc/idma_pkg.sv-compute_options_t,compute_op_e,compute_enable_t, MX block geometrysrc/backend/tpl/idma_legalizer.sv.tpl- size-changing length calc and compute constraintssrc/backend/tpl/idma_transport_layer.sv.tpl- engine instantiation (gen_compute)