Skip to content
DenseChip
Learn
PracticeCode labInterview

DenseChip

Navigate

Menu

LearnPracticeCode labInterview

Tools

All toolsSV editorCode repoResume
DenseChip

Practice, courses, and chip-design tools in one focused workspace.

LearnPracticeCode labInterviewToolsLearning paths

© 2026 DenseChip

AboutContactPrivacyTerms
Skip to lesson

Course contents

  • RTL Foundations36
  • Combinational Design25
  • Sequential Design27
  • FSM & Control27
  • Timing & Clocking39
  • Reset & CDC34
  • Memory & Buses57
    • SRAM and ROM
    • Register Files
    • Valid/Ready Handshake
    • AXI-Lite
    • AXI-Stream
    • Bus Integration
    • Synchronous FIFO
    • Register-Map and CSR RTL
    • Memory Reliability
    • Peripheral RTL Integration
      • Peripheral Shell
      • Clock, Reset, and Power Contract
      • Interrupts and Events
      • FIFO and DMA Boundary
      • Errors and Integration Signoff
    • Full AXI4: RTL Roadmap
  • Advanced RTL28
  • Senior & Interview76
  • Glossary and Notation
Loading lesson

‹Peripheral RTL Integration
  1. Topics
  2. RTL Design
  3. Memory & Buses
  4. Peripheral RTL Integration
  5. FIFO and DMA Boundary

Part 7 · Memory & Buses · Intermediate

FIFO and DMA Boundary

Use occupancy and watermarks to request DMA service without overruns, underruns, or combinational loops.

Why this matters

A DMA request driven from a single FIFO threshold chatters on one-word level changes, and wiring a registered-pop FIFO into fall-through logic repeats or drops words. A request is not a transfer either.

After this lesson you can: drive a DMA request with high and low watermarks, wire a fall-through FIFO to a valid/ready DMA port, and count only accepted beats.

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.

design.sv
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// 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.

RX and TX FIFO levels with two watermarks each: the request sets at one mark, clears at the other, and holds its value in the shaded band between them

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.

Warning

A DMA request is not a data transfer. Count only accepted valid/ready beats when updating FIFO state or transfer length.

Check yourself One RX word 0xA5 is queued and DMA stalls for three cycles before accepting it. What must this boundary show?

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.

Check yourself Why use two watermarks instead of one?

A high start threshold and lower stop threshold provide hysteresis, allowing efficient bursts and preventing request chatter around one occupancy value.

Remember

  • The request sets at one watermark and clears at the other. Keep the low mark below the high mark, or the hysteresis disappears.

  • A fall-through wiring needs the front word stable until an accepted pop. A registered-pop FIFO needs a prefetch adapter first.

  • Software and DMA need arbitration so they cannot pop the same word.

Rule of thumb: count only accepted valid/ready beats, never the request.

Keep going

  • Practice: Simple single-channel DMA controller

  • Code lab: DMA controller FSM

  • Interview: run a mock interview on this topic

Related topics

  • Synchronous FIFO

  • Errors and integration signoff

Previous

242 / 350

Next: Errors and Integration Signoff

Up next

Up nextErrors and Integration Signoff

Sign in to save progress

Practice this lessonReport an error

See also

  • Peripheral Shell
  • Clock, Reset, and Power Contract
clkrx_levelbcdcbca878rx_dma_reqge_high
The RX DMA request sets one cycle after the fill level first reaches the high mark 12, rides through dips back to 10, and clears only after the level reaches the low mark 8