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
      • Core AXI-Stream Signals
      • A Stream Pipeline Register
      • Packets, TLAST, TKEEP and Monitors
    • Bus Integration
    • Synchronous FIFO
    • Register-Map and CSR RTL
    • Memory Reliability
    • Peripheral RTL Integration
    • Full AXI4: RTL Roadmap
  • Advanced RTL28
  • Senior & Interview76
  • Glossary and Notation
Loading lesson

‹AXI-Stream
  1. Topics
  2. RTL Design
  3. Memory & Buses
  4. AXI-Stream
  5. A Stream Pipeline Register

Part 7 · Memory & Buses · Intermediate

A Stream Pipeline Register

A one-stage AXI-Stream register that holds order under backpressure, with a bounded random-stall scoreboard.

On this page

    Why this matters

    One register stage stores a whole beat, data, keep and last together, and never loses or reorders it under a stall. Its ready path is still combinational, so chaining stages chains the ready logic.

    After this lesson you can: build the one-beat stream register, and say what it guarantees and what it does not do to reverse timing.

    What one stage guarantees

    The stage stores one whole beat: data, keep and last together. It adds one cycle of latency and never reorders or drops.

    Throughput is one beat per cycle while the source offers and the sink accepts every cycle. Under a sink stall the stage holds its beat and deasserts ready.

    Situation

    Behavior

    Sink stalls while full

    The stage holds its beat and drives s_tready low. The source must hold its beat.

    Push and pop coincide

    The arriving beat replaces the departing beat in the same cycle. Nothing is lost.

    Continuous flow

    Each cycle moves one beat in and one beat out. The stage stays full.

    Latency

    An offered beat appears at the output no earlier than the next cycle.

    Each slot is one clock cycle. A beat accepted in one slot (s_tvalid and s_tready both high) appears on m_tdata in the next slot, and it leaves at the end of a slot where m_tvalid and m_tready are both high.

    • Slot 1 (fill): the stage is empty, so s_tready is high and A0 is accepted. It appears on the output in slot 2: one cycle of latency.

    • Slots 2 and 3 (stall): the stage is full and the sink is not ready, so s_tready is low and the source holds B0.

    • Slot 4 (replace): m_tready rises. A0 leaves and B0 enters at the same edge, so s_tready is high even though the stage is full.

    • Slots 5 to 7 (flow, then drain): C0 follows B0 one cycle behind; with no new offer the stage empties and m_tvalid falls in slot 7.

    The register

    A single full flag is the whole control. Ready is low only when the stage is full and nothing leaves.

    The forward payload is registered, but the reverse ready path is combinational: m_tready -> pop -> s_tready. Chaining these stages chains ready logic and routing delay across them. This stage therefore does not cut reverse timing. Use the Skid Buffer and Pipeline Stages design when registered backpressure is needed, with storage for the in-flight beat. Target timing reports are still required for physical signoff.

    The full listing sits with its testbench under Testbench below.

    The push branch runs first, so a coincident arrival replaces the departing beat. That ordering is what keeps the stage lossless.

    Common mistakes

    Common pitfall

    Reading m_tdata in the same cycle as the offer misses by one cycle. The stage is a register, so TLAST tracking and packet counters must allow for that cycle.

    Interview

    Likely question: “build a pipeline stage that never loses data under backpressure”. Answer with this register: one held beat plus s_tready = !full || pop, so a coincident arrival replaces the departing beat.

    Check yourself The stage is full, the sink accepts, and the source offers. What happens to each beat?

    Both move in one cycle: the held beat leaves and the new beat is stored. The stage stays full.

    Check yourself The stage is full and the sink stalls. What does the source see?

    s_tready is 0. The source must keep TVALID and the whole beat stable.

    Check yourself How soon after the offer can a beat first appear at the output?

    No earlier than the next cycle. The accepting edge samples it into the register first.

    Testbench

    The register plus directed partial-beat stall/replacement checks, then a finite scoreboard over 4000 beats with varying TKEEP, random stalls on both sides, and TLAST every ninth beat. Inputs change on falling edges; transfers are counted at rising edges before registered updates. After all offers are issued the sink stays ready for a bounded drain. A cycle watchdog reports accepted, delivered and pending beats.

    axis_pipe.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
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    module axis_pipe #(
      parameter int DW = 64,
      parameter int KW = DW/8
    ) (
      input  logic          clk,
      input  logic          rst_n,
      input  logic          s_tvalid,
      output logic          s_tready,
      input  logic [DW-1:0] s_tdata,
      input  logic [KW-1:0] s_tkeep,
      input  logic          s_tlast,
      output logic          m_tvalid,
      input  logic          m_tready,
      output logic [DW-1:0] m_tdata,
      output logic [KW-1:0] m_tkeep,
      output logic          m_tlast
    );
      logic full;
      logic [DW-1:0] data_q;
      logic [KW-1:0] keep_q;
      logic          last_q;
    
      wire push = s_tvalid && s_tready;
      wire pop  = m_tvalid && m_tready;
    
      assign s_tready = !full || pop;
      assign m_tvalid = full;
      assign m_tdata  = data_q;
      assign m_tkeep  = keep_q;
      assign m_tlast  = last_q;
    
      always_ff @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
          full   <= 1'b0;
          data_q <= '0;
          keep_q <= '0;
          last_q <= 1'b0;
        end else begin
          if (push) begin
            data_q <= s_tdata;
            keep_q <= s_tkeep;
            last_q <= s_tlast;
            full   <= 1'b1;
          end else if (pop) begin
            full <= 1'b0;
          end
        end
      end
    endmodule
    

    Remember

    • A single full flag is the whole control, and s_tready = !full || pop.

    • The push branch runs first, so a coincident arrival replaces the departing beat and the stage stays lossless.

    • The forward payload is registered, but ready is combinational. Use the skid buffer when backpressure must be registered.

    How this was checked

    Source checker, run with Icarus Verilog 13.0 (2026-10-16): prints PASS. Directed partial-beat stall and replacement checks, then a finite scoreboard over 4000 beats with varying TKEEP, random stalls on both sides and TLAST every ninth beat, with a bounded drain and a cycle watchdog. It is not a liveness proof under arbitrary permanent backpressure.

    Keep going

    • Code lab: Pipeline register stage

    • Interview: run a mock interview on this topic

    Related topics

    • Core AXI-Stream Signals

    • Packets, TLAST, TKEEP and Monitors

    Previous

    208 / 350

    Next: Packets, TLAST, TKEEP and Monitors

    Up next

    Up nextPackets, TLAST, TKEEP and Monitors

    Sign in to save progress

    Practice this lessonReport an error
    s_tvalids_tdata0a0b0c00s_treadym_tvalidm_tdata0a0b0c0m_tready
    The directed part of the testbench below: the stage fills with A0, stalls with B0 waiting, swaps A0 for B0 on one edge, passes C0, then drains