Register Frontend
Register Frontend Role
The register frontend (idma_reg64_2d) exposes a standard memory-mapped register file through which software configures and launches DMA transfers. It connects via the PULP register interface and is the most common frontend for general-purpose SoCs. The module is generated from src/frontend/reg/tpl/idma_reg.sv.tpl.
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) |
Programming Sequence
- Write transfer parameters: Set
src_addr,dst_addr,num_bytes, and optionallyreps/src_stride/dst_stridefor 2D mode - Write configuration: Set
confwith the desired decouple flags, protocol selection, and ND mode enable. 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. The register port stalls (backpressures the bus) until the backend accepts the request - 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 |
num_bytes | 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)
| Bits | Field | Description |
|---|---|---|
| 0 | decouple_aw | Enable R-AW coupling (hold write addresses until read data arrives) |
| 1 | decouple_rw | Fully decouple read and write channels |
| 2 | src_reduce_len | Shorten source bursts beyond page-boundary splitting |
| 3 | dst_reduce_len | Shorten destination bursts |
| 6:4 | src_max_llen | Max source burst length as log2(beats) |
| 9:7 | dst_max_llen | Max destination burst length as log2(beats) |
| 10 | enable_nd | Enable ND mode (use previously set reps/src_stride/dst_stride) |
| 13:11 | src_protocol | Source protocol select (protocol_e enum) |
| 16:14 | dst_protocol | Destination protocol select (protocol_e enum) |
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(num_bytes_low, 1024);write(num_bytes_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(num_bytes_low, 64);write(num_bytes_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
- Template:
src/frontend/reg/tpl/idma_reg.sv.tpl - Generated output:
target/rtl/idma_reg64_2d.sv,target/rtl/idma_reg32_2d.sv