Direction | DMA request | Completion effect |
|---|---|---|
Peripheral RX to memory | Assert when RX level reaches high watermark | DMA pops words until low watermark or programmed length |
Memory to peripheral TX | Assert when TX level falls below low watermark | DMA pushes words until high watermark or length ends |
The peripheral is a source on its RX DMA channel and a sink on its TX DMA channel. Directional suffixes below make valid and ready ownership explicit and prevent the two interfaces from being wired as if they had the same orientation.
The RX wiring below requires a first-word fall-through (FWFT/show-ahead) FIFO: whenever rx_fifo_empty is low, rx_fifo_data already contains the front word and remains stable until an accepted pop. Empty must describe front-word availability, not merely nonzero backing-memory occupancy. The linked synchronous FIFO's running implementation instead returns registered data after a pop, qualified by dout_valid_o; do not connect that interface directly to this wiring. It needs a prefetch adapter that captures pop results, holds output valid/data through DMA stalls, and accounts for in-flight reads and buffered words in its occupancy/watermark policy.
// snippet: level-based DMA requests and accepted transfers
// Hysteresis: set at the start threshold, clear only at the stop threshold,
// so a level stepping 12, 11, 12 around the high watermark does not chatter the request.
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
rx_dma_req_q <= 1'b0;
tx_dma_req_q <= 1'b0;
end else begin
if (!dma_rx_enable_q) rx_dma_req_q <= 1'b0;
else if (rx_level >= rx_high_wm_q) rx_dma_req_q <= 1'b1; // start: FIFO has filled to the high watermark
else if (rx_level <= rx_low_wm_q) rx_dma_req_q <= 1'b0; // stop: DMA has drained to the low watermark
if (!dma_tx_enable_q) tx_dma_req_q <= 1'b0;
else if (tx_level <= tx_low_wm_q) tx_dma_req_q <= 1'b1; // start: FIFO has drained to the low watermark
else if (tx_level >= tx_high_wm_q) tx_dma_req_q <= 1'b0; // stop: DMA has refilled to the high watermark
end
end
assign rx_dma_req_o = rx_dma_req_q;
assign tx_dma_req_o = tx_dma_req_q;
// RX requires FWFT: !empty means front data is already valid and held until pop.
// Not a direct connection to the linked registered-pop-result FIFO.
assign rx_dma_valid_o = !rx_fifo_empty;
assign rx_dma_data_o = rx_fifo_data;
assign rx_fifo_pop = rx_dma_valid_o && rx_dma_ready_i;
// TX: DMA produces data, peripheral accepts it
assign tx_dma_ready_o = !tx_fifo_full;
assign tx_fifo_push = tx_dma_valid_i && tx_dma_ready_o;
assign tx_fifo_data = tx_dma_data_i;The request is a register that sets at one watermark and clears at the other, with the enable forcing it low. It is not a comparison of the level against a single threshold, so one-word level changes near the watermark cannot chatter it. Keep rx_low_wm_q below rx_high_wm_q (and tx_low_wm_q below tx_high_wm_q); if they are equal the set condition wins and the hysteresis disappears. DMA and software accesses need explicit arbitration so two consumers cannot pop the same RX word.
Read each bar from empty on the left to full on the right. The shaded band is where the request keeps whatever value it had.
RX: the engine fills the FIFO, so the request sets at the high mark 12 and DMA drains it until the low mark 8.
TX: the engine drains the FIFO, so the marks swap roles: the request sets at the low mark and DMA refills it to the high mark.
The band is the hysteresis. A level stepping 12, 11, 12 stays inside it and cannot make the request chatter.
Each slot is one clock cycle. The request is a register, so it changes one slot after the level that caused the change. The low compare lane shows what a single-threshold compare against 12 alone would do.
Slot 1 first shows level 12 and the request rises in slot 2. The single-threshold compare is high there too.
Slots 3 to 6 step through 13, 12, 11 and 12 while the compare falls twice and the request holds 1 without chatter.
Slot 7 reaches the low mark 8 and the request still holds. It clears in slot 8 and stays clear through slots 9 and 10.
Valid stays high with data 0xA5 throughout the stall, pop stays low until valid and ready are both high, and exactly one 0xA5 transfer occurs. A registered-pop-result FIFO cannot satisfy this wiring directly: it exposes 0xA5 only after the pop, too late for that handshake.
A high start threshold and lower stop threshold provide hysteresis, allowing efficient bursts and preventing request chatter around one occupancy value.