Hard · Assertions · Interfaces & Handshakes
Write a protocol checker: a small piece of synthesizable RTL that watches a valid/ready stream and flags the first violation of the handshake rules. Verification engineers usually write these rules as SystemVerilog Assertions (SVA). Writing the monitor by hand shows you exactly what an assertion means cycle by cycle. The same monitor can also go into an FPGA to catch protocol bugs in hardware, where assertions are not available.
A sender drives valid and data, a receiver drives ready; a transfer happens at a rising edge where valid && ready. Your module only observes these signals (all are inputs).
The monitor samples rst, valid, ready and data at every rising edge of clk. Call the values sampled at edge n "sample n". A sample is monitored if rst = 0 in it. A sample is stalled if valid = 1 and ready = 0 in it (the sender offers a beat that is not taken).
At every monitored sample n, check:
| code | name | violation at sample n |
|---|---|---|
| 1 | VALID_DROPPED | sample n−1 was monitored and stalled, and valid = 0 in sample n (valid withdrawn before the transfer) |
| 2 | DATA_CHANGED | sample n−1 was monitored and stalled, valid = 1 in sample n, and data in sample n differs from sample n−1 |
| 3 | STALL_TIMEOUT | sample n is stalled and so are the MAX_STALL samples before it, all monitored (that is, MAX_STALL + 1 consecutive stalled samples) |
Notes:
MAX_STALL consecutive samples followed by a transfer is legal.valid && ready), the sender may drop valid or change data freely.data is not checked when valid = 0.rst = 1 are not monitored and break every history: the first sample afterreset has no "previous sample" for rules 1 and 2, and the stall count of rule 3 starts again from zero.
module handshake_checker #(
parameter int WIDTH = 8,
parameter int MAX_STALL = 8
) (
input logic clk,
input logic rst, // synchronous, active-high
input logic valid,
input logic ready,
input logic [WIDTH-1:0] data,
output logic error, // sticky
output logic [1:0] error_code // code of the FIRST violation, 0 if none
);
error and error_code are registered. If a rule is violated at sample n, then rightafter edge n (that is, in the following cycle) error = 1 and error_code is the rule's code.
error = 1, error and error_code keep their values until reset; laterviolations change nothing.
rst = 1: error = 0, error_code = 0, and all history iscleared.
error = 0 and error_code = 0.other values of WIDTH and MAX_STALL (MAX_STALL >= 1), so size every register from the parameters.
The judge's simulators cannot grade concurrent assertions, so you must build the RTL monitor. For comparison, a verification engineer would write roughly:
// rule 1: once valid is offered and not taken, it must stay high
assert property (@(posedge clk) disable iff (rst)
(valid && !ready) |=> valid);
// rule 2: ... and data must stay the same
assert property (@(posedge clk) disable iff (rst)
(valid && !ready) ##1 valid |-> $stable(data));
// rule 3: no more than MAX_STALL consecutive stalled cycles
assert property (@(posedge clk) disable iff (rst)
not ((valid && !ready) [*MAX_STALL+1]));
(disable iff is asynchronous and assertion failures are not sticky; the spec above is the exact behavior to implement.)
Beat A is stalled in cycle 1; in cycle 2 the sender changes data to B while still stalled. The violation is sampled at the edge ending cycle 2, so error rises in cycle 3 with code 2 and stays high even after the transfer.
Sign up free to solve Valid/Ready Protocol Checker in your browser.