Skip to content

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

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)

Programming Sequence

  1. Write transfer parameters: Set src_addr, dst_addr, num_bytes, 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. 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. The register port stalls (backpressures the bus) until the backend accepts the request
  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
num_bytesR/WTransfer length in bytes

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

RegisterAccessDescription
confR/WTransfer configuration (see below)

Control/Statusnext_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)

BitsFieldDescription
0decouple_awEnable R-AW coupling (hold write addresses until read data arrives)
1decouple_rwFully decouple read and write channels
2src_reduce_lenShorten source bursts beyond page-boundary splitting
3dst_reduce_lenShorten destination bursts
6:4src_max_llenMax source burst length as log2(beats)
9:7dst_max_llenMax destination burst length as log2(beats)
10enable_ndEnable ND mode (use previously set reps/src_stride/dst_stride)
13:11src_protocolSource protocol select (protocol_e enum)
16:14dst_protocolDestination 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 parameters
write(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 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(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_nd
tid = 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