Skip to content
WIP: parts of this documentation are AI-generated and may contain factual errors.

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 in src/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):

ParameterTypeDescription
EnableComputebitElaborate the compute engine at all
ComputeOpsidma_pkg::compute_enable_tPer-op enable mask: transpose, mxquant, mxdequant, mxfp16
ComputeTuningidma_pkg::compute_tuning_tImplementation 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):

FieldDescription
enableArm compute for this transfer
opidma_pkg::compute_op_e selector
params.transposemode (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_eMeaningInput granuleOutput granule
COMPUTE_NONEPlain copy--
COMPUTE_TRANSPOSETiled transpose= output= input
COMPUTE_MXQUANTQuantize, FP32 source128 B / block33 B / block
COMPUTE_MXQUANT_FP16Quantize, FP16 source64 B / block33 B / block
COMPUTE_MXDEQUANTDequantize, FP32 destination33 B / block128 B / block
COMPUTE_MXDEQUANT_FP16Dequantize, FP16 destination33 B / block64 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:

AssertionRequirement
ComputeSizeAlignedlength is a whole multiple of the op’s input granule
ComputeSrcAligned / ComputeDstAlignedsrc/dst addresses are beat-aligned for size-changing ops
ComputeMxdequantBeatAligneddequant input length is a multiple of MxBlockBytes * StrbWidth
ComputeMxFp16WidthFP16 element formats require StrbWidth <= 64 (at most one block per beat)
ComputeMxSrcProtocol / ComputeMxDstProtocolsize-changing ops are AXI-only on src and dst (OBI is a TODO)
ComputeDstTilelinkcompute retires per beat, so a TileLink destination is not supported
ComputeMxdequantLengthFitsdequant output length must fit the length field width

Source Files

  • src/backend/idma_otf_compute.sv - per-transfer op dispatcher
  • src/backend/idma_otf_transpose.sv - tiled transpose engine
  • src/backend/idma_otf_mxquant.sv, src/backend/idma_otf_mxdequant.sv - MX pack/expand
  • src/idma_float_pkg.sv - FP32/FP16 <-> MXFP8 cast math and block scale
  • src/idma_pkg.sv - compute_options_t, compute_op_e, compute_enable_t, MX block geometry
  • src/backend/tpl/idma_legalizer.sv.tpl - size-changing length calc and compute constraints
  • src/backend/tpl/idma_transport_layer.sv.tpl - engine instantiation (gen_compute)