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

Register Frontend

Register Frontend Role

The register frontend (idma_reg64_2d and siblings) exposes a standard memory-mapped register file through which software configures and launches DMA transfers. It is the most common frontend for general-purpose SoCs.

The register file is described once in SystemRDL (src/frontend/reg/idma_reg.rdl) and generated by PeakRDL regblock. The config-bus attached to the register block is selectable via IDMA_REG_CPUIF (idma.mk):

IDMA_REG_CPUIFConfig busWrapper struct
apb4-flat (default)APB4apb_req_t / apb_rsp_t
obi-flatOBIobi_req_t / obi_rsp_t
axi4-lite-flatAXI4-Liteaxi_lite_req_t / axi_lite_rsp_t

A thin wrapper (src/frontend/reg/tpl/idma_reg.sv.tpl, rendered by MARIO for the selected CPUIF) packs the PeakRDL block’s flat config-bus signals into the matching request/response struct and drives the transfer-ID and launch logic. The register_interface dependency is no longer used.

Parameters

ParameterDefaultDescription
NumRegs1Number of configuration register ports (parallel access points)
NumStreams1Number of independent DMA streams (max 16). Each stream has its own transfer ID counter
IdCounterWidth32Width of the transfer ID counter (max 32-bit)
DataWidth512Backend data width; MX data planes, strides and lengths are checked against its beats
ComputeOpsallCompute ops of the backend (idma_pkg::compute_enable_t); a launch of any other op is refused

Programming Sequence

  1. Write transfer parameters: Set src_addr, length, dst_addr, and optionally reps/src_stride/dst_stride for 2D mode
  2. Write configuration: Set conf with the desired decouple flags, protocol selection, and ND mode enable. For an on-the-fly compute transfer also set compute_cfg (see below). Stream selection is implicit in which next_id[stream] register you read in the next step
  3. Read next_id[stream]: This read atomically launches the transfer on the selected stream and returns the assigned transfer ID. It returns 0 and launches nothing if the transfer is not set up correctly: a compute op that ComputeOps does not name (reserved op codes included), or an MX launch that breaks a rule of MX Scale Plane Registers
  4. Poll done_id[stream]: Wait until done_id >= next_id to confirm completion

Register Map

The register file provides direct access to all fields of the idma_req_t / idma_nd_req_t structs. Software writes the transfer parameters, then reads next_id to atomically submit the request:

Transfer Parameters - set these before launching a transfer:

RegisterAccessDescription
src_addrR/WSource address for the next transfer
dst_addrR/WDestination address for the next transfer
lengthR/WTransfer length in bytes

Configuration - controls decoupling, burst limits, protocol selection, and ND mode:

RegisterAccessDescription
confR/WTransfer configuration (see below)

Control/Status - next_id launches the transfer; done_id signals completion:

RegisterAccessDescription
statusROPer-stream busy flags
next_idROPer-stream next transfer ID. Reading launches the transfer
done_idROPer-stream last completed transfer ID

ND Mode - only used when enable_nd is set in conf:

RegisterAccessDescription
repsR/WNumber of 2D repetitions (ND mode)
src_strideR/WSource stride between rows (ND mode)
dst_strideR/WDestination stride between rows (ND mode)

Configuration Register (conf)

The bit positions of enable_nd and the protocol fields depend on the number of dimensions.

Bits reg32_3dBits reg64_1dBits reg64_2dFieldDescription
000decouple_awR-AW coupling: hold write addresses until the read data arrives
111decouple_rwFully decouple the read and write channels
222src_reduce_lenShorten source bursts to src_max_llen
333dst_reduce_lenShorten destination bursts to dst_max_llen
6:46:46:4src_max_llenMaximal source burst length as log2(beats)
9:79:79:7dst_max_llenMaximal destination burst length as log2(beats)
12:101011:10enable_ndDimensions in use beyond the first (0: 1D)
15:1313:1114:12src_protocolSource protocol (idma_pkg::protocol_e)
18:1616:1417:15dst_protocolDestination protocol (idma_pkg::protocol_e)

Compute Configuration Register (compute_cfg)

Present when on-the-fly compute is elaborated (EnableCompute). The fields are sampled together with the transfer parameters when next_id is read. Leave compute_enable at 0 for a plain copy.

BitsFieldDescription
0compute_enableEnable on-the-fly compute for the launched transfer.
4:1compute_opCompute operation selector (idma_pkg::compute_op_e).
6:5transpose_modeTranspose element-size mode. The element size is 1 << transpose_mode bytes, encoding 8b, 16b, 32b, and 64b elements.
18:7transpose_tensor_mTranspose tensor M dimension in elements. Must be non-zero when transpose is enabled.
30:19transpose_tensor_nTranspose tensor N dimension in elements. Must be non-zero when transpose is enabled.
31transpose_compactUse compact row-major output storage. When clear, transpose uses the legacy tile-padded layout.

MX Configuration Register (mx_cfg)

Follows compute_cfg and is sampled with it; used when compute_op is an MX op.

BitsFieldDescription
0mx_poison_disKeep Inf/NaN blocks finite instead of poisoning them (0xFF scale, NaN lanes)
1mx_rceilRound the block scale up (RCEIL) instead of down (FLOOR).
3:2mx_elem_fmtMX element format (0: E5M2, 1: E4M3; 2 E2M1 and 3 reserved).
4mx_groupBlocks per scale group; a group’s scale bytes move as one chunk.
31:5-Reserved

See MX planes for the data and scale plane layout.

MX Scale Plane Registers

RegisterAccessDescription
scale_addrR/WScale plane address of the next MX transfer, 64 B aligned; sampled with compute_cfg
mx_dim[d].scale_strideR/WND only: scale plane stride of dimension d, a multiple of 64 B, applied as dim[d] applies its strides

An MX launch is refused (next_id reads 0 and no transfer starts) when it carries a reserved element format, its scale plane or a used dimension’s scale stride is off a 64 B line, its data planes or a used dimension’s source or destination stride are off a beat of the frontend’s DataWidth parameter (default 512 bit), its length is not a whole number of blocks, or its written length (a dequant writes 4x or 2x its length) does not fit the length field.

Offsets

Byte offsets in the three frontend variants; a 64-bit value is a [0]/[1] word pair.

Registerreg32_3dreg64_1dreg64_2d
conf0x0000x0000x000
status[0..15]0x0040x0040x004
next_id[0..15]0x0440x0440x044
done_id[0..15]0x0840x0840x084
dst_addr[0]0x0D00x0D00x0D0
dst_addr[1]-0x0D40x0D4
src_addr[0]0x0D40x0D80x0D8
src_addr[1]-0x0DC0x0DC
length[0]0x0D80x0E00x0E0
length[1]-0x0E40x0E4
dim[0].dst_stride[0]0x0E0-0x100
dim[0].dst_stride[1]--0x104
dim[0].src_stride[0]0x0E4-0x108
dim[0].src_stride[1]--0x10C
dim[0].reps[0]0x0E8-0x110
dim[0].reps[1]--0x114
compute_cfg0x0F80x1180x118
mx_cfg0x0FC0x11C0x11C
scale_addr[0]0x1000x1200x120
scale_addr[1]-0x1240x124
mx_dim[0].scale_stride[0]0x104-0x128
mx_dim[0].scale_stride[1]--0x12C
dim[1].dst_stride[0]0x0EC--
dim[1].src_stride[0]0x0F0--
dim[1].reps[0]0x0F4--
mx_dim[1].scale_stride[0]0x108--

Multi-Port Arbitration

When NumRegs > 1, multiple register ports can submit transfers concurrently. An internal round-robin arbiter serializes requests to the single backend interface. Each port stalls independently on its next_id read until its request is accepted. This allows multiple cores to share a single DMA without software-level locking.

Worked Example: 1 KiB Transfer

The following register writes launch a 1 KiB AXI-to-AXI transfer from 0x8000_0000 to 0xC000_0000 with R-AW coupling enabled, on stream 0:

// 1. Write transfer parameters
write(src_addr_low, 0x80000000);
write(src_addr_high, 0x00000000);
write(dst_addr_low, 0xC0000000);
write(dst_addr_high, 0x00000000);
write(length_low, 1024);
write(length_high, 0);
// 2. Write configuration: decouple_aw=1, everything else default (AXI=0)
write(conf, 0x1); // bit 0 = decouple_aw
// 3. Read next_id[0] - launches the transfer, returns transfer ID
tid = read(next_id_0);
// 4. Poll for completion
while (read(done_id_0) < tid);

Worked Example: 2D Transfer

The following register writes launch a 2D transfer copying 4 rows of 64 bytes with different source and destination strides:

// 2D example: copy 4 rows of 64 bytes, src stride 256, dst stride 64
write(length_low, 64);
write(length_high, 0);
write(src_addr_low, 0x80000000);
write(src_addr_high, 0x00000000);
write(dst_addr_low, 0xC0000000);
write(dst_addr_high, 0x00000000);
write(reps, 4);
write(src_stride_low, 256);
write(src_stride_high, 0);
write(dst_stride_low, 64);
write(dst_stride_high, 0);
write(conf, 0x401); // bit 0 = decouple_aw, bit 10 = enable_nd
tid = read(next_id_0);
while (read(done_id_0) < tid);

Source Files

  • Register description: src/frontend/reg/idma_reg.rdl (SystemRDL, generated by PeakRDL regblock)
  • Config-bus wrapper template: src/frontend/reg/tpl/idma_reg.sv.tpl
  • CPUIF selection: IDMA_REG_CPUIF in idma.mk
  • Generated output: target/rtl/idma_reg64_2d.sv, target/rtl/idma_reg32_3d.sv, target/rtl/idma_reg64_1d.sv (plus the PeakRDL *_reg_top.sv, *_reg_pkg.sv, *_addrmap_pkg.sv)