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_CPUIF | Config bus | Wrapper struct |
|---|---|---|
apb4-flat (default) | APB4 | apb_req_t / apb_rsp_t |
obi-flat | OBI | obi_req_t / obi_rsp_t |
axi4-lite-flat | AXI4-Lite | axi_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
| Parameter | Default | Description |
|---|---|---|
NumRegs | 1 | Number of configuration register ports (parallel access points) |
NumStreams | 1 | Number of independent DMA streams (max 16). Each stream has its own transfer ID counter |
IdCounterWidth | 32 | Width of the transfer ID counter (max 32-bit) |
DataWidth | 512 | Backend data width; MX data planes, strides and lengths are checked against its beats |
ComputeOps | all | Compute ops of the backend (idma_pkg::compute_enable_t); a launch of any other op is refused |
Programming Sequence
- Write transfer parameters: Set
src_addr,length,dst_addr, and optionallyreps/src_stride/dst_stridefor 2D mode - Write configuration: Set
confwith the desired decouple flags, protocol selection, and ND mode enable. For an on-the-fly compute transfer also setcompute_cfg(see below). Stream selection is implicit in whichnext_id[stream]register you read in the next step - 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 thatComputeOpsdoes not name (reserved op codes included), or an MX launch that breaks a rule of MX Scale Plane Registers - Poll
done_id[stream]: Wait untildone_id >= next_idto 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:
| Register | Access | Description |
|---|---|---|
src_addr | R/W | Source address for the next transfer |
dst_addr | R/W | Destination address for the next transfer |
length | R/W | Transfer length in bytes |
Configuration - controls decoupling, burst limits, protocol selection, and ND mode:
| Register | Access | Description |
|---|---|---|
conf | R/W | Transfer configuration (see below) |
Control/Status - next_id launches the transfer; done_id signals completion:
| Register | Access | Description |
|---|---|---|
status | RO | Per-stream busy flags |
next_id | RO | Per-stream next transfer ID. Reading launches the transfer |
done_id | RO | Per-stream last completed transfer ID |
ND Mode - only used when enable_nd is set in conf:
| Register | Access | Description |
|---|---|---|
reps | R/W | Number of 2D repetitions (ND mode) |
src_stride | R/W | Source stride between rows (ND mode) |
dst_stride | R/W | Destination 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_3d | Bits reg64_1d | Bits reg64_2d | Field | Description |
|---|---|---|---|---|
| 0 | 0 | 0 | decouple_aw | R-AW coupling: hold write addresses until the read data arrives |
| 1 | 1 | 1 | decouple_rw | Fully decouple the read and write channels |
| 2 | 2 | 2 | src_reduce_len | Shorten source bursts to src_max_llen |
| 3 | 3 | 3 | dst_reduce_len | Shorten destination bursts to dst_max_llen |
| 6:4 | 6:4 | 6:4 | src_max_llen | Maximal source burst length as log2(beats) |
| 9:7 | 9:7 | 9:7 | dst_max_llen | Maximal destination burst length as log2(beats) |
| 12:10 | 10 | 11:10 | enable_nd | Dimensions in use beyond the first (0: 1D) |
| 15:13 | 13:11 | 14:12 | src_protocol | Source protocol (idma_pkg::protocol_e) |
| 18:16 | 16:14 | 17:15 | dst_protocol | Destination 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.
| Bits | Field | Description |
|---|---|---|
| 0 | compute_enable | Enable on-the-fly compute for the launched transfer. |
| 4:1 | compute_op | Compute operation selector (idma_pkg::compute_op_e). |
| 6:5 | transpose_mode | Transpose element-size mode. The element size is 1 << transpose_mode bytes, encoding 8b, 16b, 32b, and 64b elements. |
| 18:7 | transpose_tensor_m | Transpose tensor M dimension in elements. Must be non-zero when transpose is enabled. |
| 30:19 | transpose_tensor_n | Transpose tensor N dimension in elements. Must be non-zero when transpose is enabled. |
| 31 | transpose_compact | Use 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.
| Bits | Field | Description |
|---|---|---|
| 0 | mx_poison_dis | Keep Inf/NaN blocks finite instead of poisoning them (0xFF scale, NaN lanes) |
| 1 | mx_rceil | Round the block scale up (RCEIL) instead of down (FLOOR). |
| 3:2 | mx_elem_fmt | MX element format (0: E5M2, 1: E4M3; 2 E2M1 and 3 reserved). |
| 4 | mx_group | Blocks 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
| Register | Access | Description |
|---|---|---|
scale_addr | R/W | Scale plane address of the next MX transfer, 64 B aligned; sampled with compute_cfg |
mx_dim[d].scale_stride | R/W | ND 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.
| Register | reg32_3d | reg64_1d | reg64_2d |
|---|---|---|---|
conf | 0x000 | 0x000 | 0x000 |
status[0..15] | 0x004 | 0x004 | 0x004 |
next_id[0..15] | 0x044 | 0x044 | 0x044 |
done_id[0..15] | 0x084 | 0x084 | 0x084 |
dst_addr[0] | 0x0D0 | 0x0D0 | 0x0D0 |
dst_addr[1] | - | 0x0D4 | 0x0D4 |
src_addr[0] | 0x0D4 | 0x0D8 | 0x0D8 |
src_addr[1] | - | 0x0DC | 0x0DC |
length[0] | 0x0D8 | 0x0E0 | 0x0E0 |
length[1] | - | 0x0E4 | 0x0E4 |
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_cfg | 0x0F8 | 0x118 | 0x118 |
mx_cfg | 0x0FC | 0x11C | 0x11C |
scale_addr[0] | 0x100 | 0x120 | 0x120 |
scale_addr[1] | - | 0x124 | 0x124 |
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 parameterswrite(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 IDtid = read(next_id_0);
// 4. Poll for completionwhile (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 64write(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_ndtid = read(next_id_0);while (read(done_id_0) < tid);Source Files
- Register description:
src/frontend/reg/idma_reg.rdl(SystemRDL, generated by PeakRDLregblock) - Config-bus wrapper template:
src/frontend/reg/tpl/idma_reg.sv.tpl - CPUIF selection:
IDMA_REG_CPUIFinidma.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)