Valid/Ready Protocol Checker

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.

The stream being checked

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).

Rules

At every monitored sample n, check:

codenameviolation at sample n
1VALID_DROPPEDsample n−1 was monitored and stalled, and valid = 0 in sample n (valid withdrawn before the transfer)
2DATA_CHANGEDsample n−1 was monitored and stalled, valid = 1 in sample n, and data in sample n differs from sample n−1
3STALL_TIMEOUTsample n is stalled and so are the MAX_STALL samples before it, all monitored (that is, MAX_STALL + 1 consecutive stalled samples)

Notes:

reset has no "previous sample" for rules 1 and 2, and the stall count of rule 3 starts again from zero.

Outputs

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
);

after edge n (that is, in the following cycle) error = 1 and error_code is the rule's code.

violations change nothing.

cleared.

other values of WIDTH and MAX_STALL (MAX_STALL >= 1), so size every register from the parameters.

The same rules in SVA (illustration only)

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.)

Example

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.