inspect_handshake
Classifies clocked valid/ready handshake cycles and reports stalls, backpressure imbalance, payload-hold violations, and premature deassertion to pinpoint protocol failures in simulation waveforms.
Instructions
Classify a clocked valid/ready handshake cycle-by-cycle and report protocol facts that leave no value pattern in scoreboard logs: stalls (valid high, ready low), the longest/over-threshold stall windows, backpressure imbalance (ready high, valid low), and — when payload signals are given — payload-hold violations (a payload that changes while the transfer is still stalled), and premature valid deassertion (a stalled beat whose valid/htrans drops before ready/HREADY arrives — the AHB master-not-waiting-for-HREADY bug, which needs no payload to detect). For AHB (valid_htrans) it ALSO runs x_while_valid (a control field is x/z while valid is asserted) and, when hwrite+write_data are given, a write data-phase HWDATA-hold check (HWDATA must stay stable through a write data-phase wait state). Protocol-agnostic: AXI *valid/*ready, an AHB pair (ready=hready, valid=a 1-bit 'htrans!=IDLE' signal, payload=[haddr,hwrite,hsize] address-phase control which must hold while hready is low; HWDATA goes in write_data, not payload), a generic valid-ready stream, or a credit interface. Returns coverage facts for the checks it actually ran (stall, backpressure, payload-hold, valid-hold, x-while-valid, write-data-hold) without assigning protocol side. Auto-registers a cursor at the first problem (x-while-valid > payload-hold > write-data hold > premature deassertion > long stall > longest stall). On AHB it also returns a protocol_semantics receipt naming which metrics are faithful vs suppressed. For the one-sided violations (x-while-valid, payload-hold, write-data hold, premature deassertion) it also returns a structured attribution block (violating_side=valid_driver, exonerated_side=ready_driver) so the caller does NOT start in the slave driver/monitor — the responder cannot cause either; a plain two-sided stall leaves attribution empty. Reads existing waveforms only — does NOT rerun simulation.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| edge | No | Clock edge to sample on. Default posedge. | posedge |
| clock | Yes | 1-bit clock signal full path. | |
| ready | Yes | Receiver ready/grant signal (1-bit). For AHB, hready. | |
| valid | No | Initiator valid/request signal (1-bit). Provide this OR valid_htrans. | |
| hwrite | No | AHB only: path to HWRITE. With write_data, enables the write data-phase HWDATA-hold check. | |
| payload | No | Optional signals that MUST stay stable while stalled (e.g. AHB htrans/haddr/hwrite/hsize, AXI awaddr/awlen). A mid-stall change is a payload_hold_violation. For AHB do NOT include hwdata here — pass it as write_data (it is a data-phase signal, a different window). | |
| wave_path | Yes | Waveform (FSDB or VCD). | |
| write_data | No | AHB only: path to HWDATA. With hwrite, checks that write data is held stable through a data-phase wait state (HREADY low) — a write_data_hold_violation otherwise. This is the data-phase window, distinct from the address-phase payload-hold. Pass it ONLY for the producer (initiator/master) interface: on a responder/slave interface HWDATA is an interconnect-mux output that glitches at the clock edge and would false-positive. | |
| active_high | No | valid/ready are active-high. Set false for active-low handshakes. Default true. | |
| cursor_name | No | Optional explicit cursor name. Defaults to hs_<sha8>. | |
| cursor_note | No | Optional note attached to the registered cursor. | |
| end_time_ps | No | Window end. -1 means end of simulation. Accepts an integer (ps), a cursor reference like '@div_3a7c', or a unit literal like '12.34ns'. | |
| htrans_rule | No | How valid_htrans derives valid. 'active' (default) = NONSEQ/SEQ (htrans[1]==1); 'non_idle' = htrans != IDLE (counts BUSY too). | active |
| valid_htrans | No | AHB only: path to the htrans signal. A derived valid is computed from it (AHB has no literal valid). Provide this OR valid, not both. | |
| start_time_ps | No | Window start. Default 0. Accepts an integer (ps), a cursor reference like '@div_3a7c', or a unit literal like '12.34ns'. | |
| max_wait_cycles | No | A stall longer than this many cycles becomes a long_stall finding. Default 16. | |
| check_valid_hold | No | Flag premature valid/transfer deassertion: a stalled beat (valid high, ready low) whose valid goes low the next edge before ready arrives = the master dropped the transfer instead of waiting (e.g. AHB htrans->IDLE without waiting for HREADY). Needs no payload. Default true. | |
| check_payload_hold | No | Flag payload changes during a stall. Default true (only meaningful when payload is given). |