DMA and RMEM Transfer Interface – openenoc_dma_transfer_if
Defines commands, completions, and terminal status for bulk memory transfers and scalar remote accesses.
Source:
openenoc_dma_transfer_if.sv.
Parameters
Name |
Default value |
Allowed values |
Description |
|---|---|---|---|
|
|
Integer >= 1 |
Byte-address width in bits; connected interfaces must agree. |
|
|
Integer >= 1; endpoint protocol uses 32 |
Byte-count width for memory commands and terminal status. |
|
|
Integer >= 1; enough bits for the peer count |
Width of local peer indices; all connected interfaces must agree. |
|
|
Integer >= 1; endpoint transfer metadata uses 32 |
Width of local fragment sequence metadata; separate from wire Request ID. |
|
|
Integer >= 4 |
Width of completion/status error codes, including local and remote causes. |
Signals
Directions are relative to the requester and executor modports.
The mon modport observes all signals as inputs.
Name |
Type |
Direction / role |
Description |
|---|---|---|---|
|
|
requester: input; executor: output |
An armed, unclaimed raw-DMA receive descriptor is available. |
|
|
requester: output; executor: input |
Requests exclusive ownership of one armed raw receive descriptor. |
|
|
requester: input; executor: output |
Accepts and reserves the raw receive descriptor claim. |
|
|
requester: output; executor: input |
Request fields are valid and retained until accepted. |
|
|
requester: input; executor: output |
Accepts the request when req_valid is also asserted. |
|
|
requester: output; executor: input |
|
|
|
requester: output; executor: input |
|
|
|
requester: output; executor: input |
Final byte address in the executor target address space. |
|
|
requester: output; executor: input |
Requested memory bytes; scalar RMEM uses four. |
|
|
requester: output; executor: input |
Local peer entry associated with the transaction. |
|
|
requester: output; executor: input |
Local fragment sequence used to join payload and completion. |
|
|
requester: output; executor: input |
Marks the final fragment of a locally initiated block. |
|
|
requester: output; executor: input |
32-bit write mask for scalar RMEM; unused for bulk DMA. |
|
|
requester: output; executor: input |
Scalar RMEM write word; unused for bulk DMA. |
|
|
requester: output; executor: input |
Early protocol rejection without authorizing memory access. |
|
|
requester: output; executor: input |
Incoming write also requires final framing/EndOfData status. |
|
|
requester: output; executor: input |
Source-read terminal status is valid. |
|
|
requester: input; executor: output |
Source-read terminal status is accepted. |
|
|
requester: output; executor: input |
Source-read local peer entry. |
|
|
requester: output; executor: input |
Source-read local fragment sequence. |
|
|
requester: output; executor: input |
Source-read actual delivered memory byte count. |
|
|
requester: output; executor: input |
Source-read terminal cause; |
|
|
requester: output; executor: input |
Receive-framing terminal status is valid. |
|
|
requester: input; executor: output |
Receive-framing terminal status is accepted. |
|
|
requester: output; executor: input |
Receive-framing local peer entry. |
|
|
requester: output; executor: input |
Receive-framing local fragment sequence. |
|
|
requester: output; executor: input |
Receive-framing actual delivered memory byte count. |
|
|
requester: output; executor: input |
Receive-framing terminal cause; zero means success. |
|
|
requester: input; executor: output |
Completion fields are valid and retained until accepted. |
|
|
requester: output; executor: input |
Accepts the completion when cpl_valid is also asserted. |
|
|
requester: input; executor: output |
Transfer kind echoed from the request. |
|
|
requester: input; executor: output |
Operation echoed from the request. |
|
|
requester: input; executor: output |
Memory bytes actually transferred. |
|
|
requester: input; executor: output |
Matching local peer entry. |
|
|
requester: input; executor: output |
Matching local fragment sequence. |
|
|
requester: input; executor: output |
Final-block context echoed from the request. |
|
|
requester: input; executor: output |
Completion reports a failure. |
|
|
requester: input; executor: output |
Final CSR cause on the initiator path; wire cause on the responder path. |
|
|
requester: input; executor: output |
Scalar RMEM read result; unused for bulk DMA. |
Architecture and operation
This symmetric command/completion interface connects the memory owner, DMA Engine – openenoc_endpoint_dma_engine, to oETP Engine – openenoc_endpoint_oetp_engine. It is instantiated twice:
Initiator path: DMA is the requester; oETP is the executor.
Responder path: oETP is the requester; DMA is the executor.
Command and completion
req_valid/req_ready and cpl_valid/cpl_ready are independent handshakes.
Each transfer occurs on a rising edge with both VALID and READY high. Assert
VALID when a transfer is available, without waiting for READY, and retain
VALID and the channel’s fields until acceptance. The same rule applies to
descriptor claims and terminal status channels. Clock and reset belong to
the connected modules; the interface contains no clock/reset ports or storage.
The request carries kind, operation, final byte address, length, peer index,
fragment sequence, final-block flag, and the scalar RMEM fields. Completion
returns kind, operation, transferred length, matching peer/sequence/final-block
context, error flag/code, and scalar read data.
An initiating write’s tx_status_len reports bytes read from its local
source. Its cpl_transferred_len reports the transaction result; the
current oETP executor returns zero when a source error aborts that write.
The source-read count alone does not establish successful remote delivery.
DMA_OP_READ = 0 and DMA_OP_WRITE = 1 are defined from the executor’s
point of view. req_addr is already in the executor’s target address space.
The requester performs address translation once. The executor may validate
the permitted memory region but must not translate the address again.
req_kind distinguishes TRANSFER_KIND_DMA = 0 from
TRANSFER_KIND_RMEM = 1, including when a bulk fragment is four bytes long.
The interface defines RMEM_WORD_BYTES = 4. RMEM uses
req_len = RMEM_WORD_BYTES, req_biten and req_wdata for writes, and
cpl_rdata for reads. RMEM has no AXIS payload; the scalar fields are
unused for bulk DMA. RMEM reads do not transfer BitEnable.
Field |
Code |
Interface constant |
Meaning |
|---|---|---|---|
|
0 |
|
Bulk memory transfer. |
|
1 |
|
Scalar remote-memory access. |
|
0 |
|
Read the executor’s memory. |
|
1 |
|
Write the executor’s memory. |
Error reporting
The following encodings apply to req_error_code,
tx_status_error_code, rx_status_error_code, and cpl_error_code.
Interface constants have the ERROR_ prefix, omitted from the mnemonics
in diagrams and the table below. NONE is the successful status.
Code |
Mnemonic |
Meaning |
|---|---|---|
0 |
|
No error. |
1 |
|
Invalid local request, configuration, address, or parameters. |
2 |
|
Local stream length, KEEP, TLAST, or framing error. |
3 |
|
Local supported size or buffer capacity exceeded. |
4 |
|
Local AXI read SLVERR or local CPUIF read error. |
5 |
|
Local AXI read returned DECERR. |
6 |
|
Local AXI write SLVERR or local CPUIF write error. |
7 |
|
Local AXI write returned DECERR. |
8 |
|
Local response timeout. |
9 |
|
Remote request, configuration, address, or parameter rejection. |
10 |
|
Remote stream/framing error or incomplete received frame. |
11 |
|
Remote supported size or buffer capacity exceeded. |
12 |
|
Remote AXI read returned SLVERR. |
13 |
|
Remote AXI read returned DECERR. |
14 |
|
Remote AXI write returned SLVERR. |
15 |
|
Remote AXI write returned DECERR. |
Initiator completions carry final CSR error codes: local causes 1..7, local
TIMEOUT 8, and remote causes 9..15. The oETP engine validates the full 32-bit
ERROR_RSP cause with csr_error_from_wire: wire causes 1..7 map to CSR
codes 9..15; every other wire value maps to LOCAL_INVALID.
The DMA engine preserves the encoding rather than inferring error origin from
the completion channel.
An incomplete received DMA data frame, including missing or incorrect
EndOfData, directly records REMOTE_AXIS without requiring an
ERROR_RSP first. Responder completions instead supply wire causes 1..7. An
incomplete incoming write returns LOCAL_AXIS while its receiving peer CSR
records REMOTE_AXIS. Here LOCAL_AXIS names the responder’s wire cause;
it does not change the origin recorded in the receiving peer’s CSR.
The wire mapping is specified in oETP Engine – openenoc_endpoint_oetp_engine and the
RDL-derived HAL.
On the responder path, req_peer_idx identifies the receiving endpoint’s
peer entry resolved from the request’s source MAC. DMA records a servicing
failure there before exposing completion and retains an enabled local IRQ
independently of the reply. Success generates no responder IRQ. Diagnostics
do not change the idle/done state of a separately initiated transfer.
Companion AXIS contract
Each direction carries one shared stream. The route field in
TDEST = {route[1:0], peer_idx} selects:
Code |
Constant |
Payload |
|---|---|---|
0 |
|
Exactly |
1 |
|
Complete Ethernet frame, from Destination MAC through payload/padding. |
2 |
|
Ethernet frame from or to the direct CSR stream. |
3 |
|
Discard route. |
Peer payload contains no address/length fields, Ethernet/oETP headers, EndOfData, protocol word padding, Ethernet padding, or FCS. Address and length travel on the command channel. Raw frames retain their Ethernet headers and any existing Ethernet padding, but exclude preamble, SFD, and FCS.
TKEEP selects actual bytes and TLAST ends one memory fragment or raw
frame. TID carries the local fragment sequence. TUSER[0] marks the final
fragment of a block; TUSER[1] selects local role, initiator 0 or responder 1.
Keep metadata stable throughout a peer fragment, through accepted TLAST.
The role disambiguates equal peer/sequence values on independent command paths.
Raw/direct streams use role zero. These fields are internal metadata rather
than oETP wire parameters.
Every started stream frame or fragment ends with TLAST, even when it is shorter than the requested length because of an operation error. Missing TLAST is a transport-contract violation; no separate missing-TLAST watchdog is specified. Small pipeline buffers may synchronize data and control while retaining the streaming contract.
Raw receive descriptor claim
The responder path also exposes non_oetp_rx_available and
non_oetp_rx_claim_valid/ready. Claim one armed descriptor before submitting
its frame. The handshake reserves it once, independently of AXIS/FIFO readiness;
no further claim is accepted until software arms the next descriptor.
Hold claim valid until accepted, then supply exactly one
ROUTE_NON_OETP_DMA frame. available describes an unclaimed descriptor,
not available FIFO space. Filtered frames must not consume a descriptor.
Terminal status channels
req_error_code carries an early protocol rejection to the memory/status
owner without permitting a memory descriptor. req_rx_status marks an
incoming bulk write that also requires final RX framing/EndOfData validation.
A rejected write can still require that status while its wire frame is drained.
Operation |
Channel |
Producer and meaning |
|---|---|---|
Initiating DMA write |
|
DMA reports final source-read byte count and local error to oETP. |
Responding DMA read |
|
DMA reports final source-read completion to oETP. |
Incoming DMA write |
|
oETP reports final delivered byte count and framing outcome to DMA. |
Matched DMA read reply |
|
oETP reports final response validity and delivered byte count to DMA. |
The explicit status channels have valid/ready, peer index, local sequence,
length, and error code. TX status contains local CSR causes. Incoming RX
framing failure uses LOCAL_AXIS on this interface; DMA records
REMOTE_AXIS while returning wire cause LOCAL_AXIS in its completion.
An AXI source/target error keeps its original local cause over a derived stream
failure. The interface instance identifies the command path.
Status is independent of payload progress and remains stable until accepted.
Data TLAST does not authorize a successful wire trailer or completion: success
requires the associated final status. Zero delivered bytes with a receive error
permit cancellation of an unstarted memory descriptor. Partial data ends with
TLAST and is drained before the context is recycled. TUSER[0] remains a
final-block flag and TUSER[1] remains a role; neither conveys an error.
The detailed streaming and failure rules are specified in oETP Engine – openenoc_endpoint_oetp_engine.
Functional scenarios
The examples use ADDR_W = LEN_W = SEQUENCE_W = 32,
PEER_IDX_W = 2, and ERROR_W = 4. A0 and A1
denote final executor addresses; D0 and D1 denote scalar
data; M0 denotes a per-bit write mask; I0/I1 and
S0/S1 denote local peer indices and fragment sequences. Labels are
local to each diagram. All commands below have req_error_code = NONE
and req_last = 1; completions retain the command’s kind, operation,
peer, sequence, and final-block context.
clk is the common clock of the connected logic, shown as a sampling
reference. Numbered cycles label intervals between rising edges; transfers
occur at each interval’s ending rising edge when VALID and READY are both
high. Shaded x regions mark irrelevant values, not a requirement to
drive unknowns. The shown waiting times are illustrative.
Initiator and responder command/completion handshakes
On initiator_if, DMA requests a scalar RMEM write from oETP.
It asserts req_valid in cycle 1 with TRANSFER_KIND_RMEM,
DMA_OP_WRITE, address A0, length 4, mask M0, and write data D0.
The request remains stable until acceptance in cycle 3.
For example, M0 = 0x0000000F enables only bits 3:0 of the
32-bit word.
The completion becomes valid in cycle 7 and retains I0/S0,
a transferred length of 4, and zero error while cpl_ready = 0.
DMA accepts it in cycle 8. req_rx_status = 0; this scalar
operation completes through the request and completion channels.
Initiator RMEM write with request and completion backpressure
On responder_if, oETP requests a scalar RMEM read from DMA.
The request presents TRANSFER_KIND_RMEM, DMA_OP_READ, address A1, length 4,
and context I1/S1 in cycle 1; DMA accepts it in cycle 2.
DMA returns cpl_rdata = D1 with a transferred length of 4 and
zero error in cycle 5. The entire completion remains stable until oETP
accepts it in cycle 6. req_biten and req_wdata are unused
for this read, and req_rx_status = 0.
Responder RMEM read returning scalar data in the completion
Exclusive receive descriptor claims
An armed, unclaimed raw receive descriptor is available at the beginning
of the diagram. On responder_if, the requester asserts
non_oetp_rx_claim_valid in cycle 2. With claim READY also high,
that cycle’s ending rising edge transfers exclusive ownership.
Both non_oetp_rx_available and claim READY return low in cycle 3.
No new descriptor can be claimed while that ownership is outstanding.
After the first receive completes and software arms the next descriptor,
availability and claim READY rise in cycle 8. A second claim transfers in
cycle 9, and both controller outputs return low in cycle 10.
Availability reports one armed, unclaimed descriptor.
Exclusive ownership claimed once for each armed receive descriptor
Terminal status and failed completions
An initiating bulk write uses TRANSFER_KIND_DMA, DMA_OP_WRITE, a requested length
of 12, context I0/S0, and req_rx_status = 0.
The command is accepted in cycle 2.
A local source-read failure is reported with tx_status_len = 8
and tx_status_error_code = LOCAL_AXI_RD_SLVERR. DMA presents this status with
matching I0/S0 in cycle 6 and retains all fields until oETP
accepts it in cycle 7.
The subsequent initiator completion preserves LOCAL_AXI_RD_SLVERR, asserts
cpl_error, and reports cpl_transferred_len = 0 because the
write failed. Its local source-read count of 8 does not establish successful
remote delivery. The completion remains valid and stable from cycle 10
through acceptance in cycle 12.
Source-read terminal error followed by a failed initiator completion
For an incoming bulk write, responder_if instead carries
req_rx_status = 1, with TRANSFER_KIND_DMA, DMA_OP_WRITE, a requested length
of 12, and context I0/S0. The command is accepted in cycle 2.
The requester presents rx_status_len = 8 and LOCAL_AXIS for an
incomplete received transfer in cycle 6. The status retains matching peer
and sequence fields until acceptance in cycle 7. Assume memory servicing
has also finished and reports eight transferred bytes with no AXI error.
The executor waits for both the memory outcome and the required receive
status before completing the operation.
The completion becomes valid in cycle 10 with
cpl_transferred_len = 8, cpl_error = 1, and LOCAL_AXIS,
and is accepted in cycle 12. This responder-path code is the wire stream
cause; DMA records REMOTE_AXIS in the receiving peer’s CSR.
A local AXI error, if present, would take priority over the derived
framing error.
Receive terminal status joined with the failed responder completion