// AXI4-Stream protocol monitor (passive). Corvel / RISCON Labs integration testbench. // Checks the transmitter obligations of AMBA AXI4-Stream: once TVALID is asserted // it stays asserted, and the payload (TDATA/TUSER/TLAST/TDEST) stays stable, until // TREADY. Optionally checks that TVALID and the payload do not react to a TREADY // change in the middle of a clock cycle (TVALID not combinationally dependent on // TREADY). For that check the receiver changes TREADY 1 ns after the falling edge; // the monitor samples 1 ns after the rising edge and compares 2 ns after the falling edge. `timescale 1ns/1ps module axis_monitor #( parameter integer PW = 64, // packed payload width parameter integer CHECK_TREADY_INDEP = 0 ) ( input wire clk, input wire rst_n, input wire tvalid, input wire tready, input wire [PW-1:0] payload ); integer errors = 0; integer n_xfer = 0, n_stall = 0, n_back_to_back = 0, n_ready_toggle_checks = 0; reg p_valid, p_ready, p_hs; reg [PW-1:0] p_payload; reg s_valid, s_ready, s_ok; reg [PW-1:0] s_payload; task automatic fail(input string what); begin errors = errors + 1; if (errors <= 20) $display("[%0t] AXIS-MON(%m) ERROR: %0s", $time, what); end endtask always @(posedge clk) if (rst_n) begin if ((^{tvalid, payload}) === 1'bx) fail("X/Z on TVALID or payload"); end always @(posedge clk or negedge rst_n) begin if (!rst_n) begin p_valid <= 1'b0; p_ready <= 1'b0; p_payload <= {PW{1'b0}}; p_hs <= 1'b0; end else begin if (p_valid && !p_ready && !tvalid) fail("TVALID deasserted before TREADY"); if (p_valid && !p_ready && payload !== p_payload) fail("payload changed while TVALID && !TREADY"); if (tvalid && tready) begin n_xfer = n_xfer + 1; if (p_hs) n_back_to_back = n_back_to_back + 1; end if (tvalid && !tready) n_stall = n_stall + 1; p_valid <= tvalid; p_ready <= tready; p_payload <= payload; p_hs <= tvalid && tready; end end generate if (CHECK_TREADY_INDEP != 0) begin : g_indep // Sample just after the rising edge, compare after the mid-cycle TREADY change. always @(posedge clk) begin #1; s_valid = tvalid; s_ready = tready; s_payload = payload; s_ok = rst_n; end always @(negedge rst_n) s_ok = 1'b0; always @(negedge clk) begin #2; if (rst_n && s_ok) begin if (tready !== s_ready) n_ready_toggle_checks = n_ready_toggle_checks + 1; if (tvalid !== s_valid || payload !== s_payload) fail("TVALID/payload changed between clock edges (combinational dependence on TREADY)"); end end end endgenerate endmodule