// SPDX-License-Identifier: MIT `timescale 1ns/1ps module tb; bit clk = 0; bit reset = 1; bit valid = 0; bit ready = 0; bit pending = 0; bit [1:0] sent_id = 0; bit [1:0] received_id = 0; bit [7:0] payload = 0; bit previous_stall = 0; bit [7:0] held_payload = 0; int mode = 0; int transfers = 0; int outstanding = 0; int wait_cycles = 0; int progress_alarms = 0; int id_errors = 0; int limit_errors = 0; localparam int WAIT_BUDGET = 4; localparam int ACCEPT_CAPACITY = 1; always #5 clk = ~clk; initial begin if (!$value$plusargs("MODE=%d", mode)) mode = 0; repeat (2) @(negedge clk); reset = 0; pending = 1; payload = 8'h5a; sent_id = mode == 2 ? 2'd2 : 2'd0; $display("MODE %0d budget=%0d capacity=%0d", mode, WAIT_BUDGET, ACCEPT_CAPACITY); for (int cycle = 0; cycle < 8; cycle++) begin @(negedge clk); if (mode == 1) begin // Deliberately illegal source waits for READY. valid = pending && ready; // Receiver is allowed to wait for VALID. ready = valid; end else begin valid = pending; ready = cycle >= 2; end received_id = mode == 2 ? {1'b0, sent_id[0]} : sent_id; @(posedge clk); $display("TRACE cycle=%0d pending=%0b valid=%0b ready=%0b id=%0d wire_id=%0d data=%02x", cycle, pending, valid, ready, sent_id, received_id, payload); if (previous_stall && (!valid || payload != held_payload)) $fatal(1, "Stalled payload or VALID changed"); previous_stall = valid && !ready; held_payload = payload; if (valid && ready) begin transfers++; outstanding++; wait_cycles = 0; if (received_id != sent_id) begin id_errors++; $display("ID_MISMATCH sent=%0d received=%0d", sent_id, received_id); end if (outstanding > ACCEPT_CAPACITY) begin limit_errors++; $display("OUTSTANDING_LIMIT count=%0d", outstanding); end if (mode == 3 && transfers == 1) begin // A second request arrives before any response. pending = 1; sent_id = 2'd1; end else pending = 0; end else if (pending) begin wait_cycles++; if (wait_cycles == WAIT_BUDGET) begin progress_alarms++; $display("BOUNDED_WAIT cycle=%0d waited=%0d", cycle, wait_cycles); end end if (cycle == 6) outstanding = 0; end $display("RESULT transfers=%0d bounded_wait=%0d id_errors=%0d limit_errors=%0d", transfers, progress_alarms, id_errors, limit_errors); if (mode == 0 && (transfers != 1 || progress_alarms != 0)) $fatal(1, "Legal backpressure result differs"); if (mode == 1 && (transfers != 0 || progress_alarms != 1)) $fatal(1, "Expected deadlock alarm"); if (mode == 2 && id_errors != 1) $fatal(1, "Expected ID mismatch"); if (mode == 3 && limit_errors != 1) $fatal(1, "Expected capacity mismatch"); $finish; end endmodule