Part 4 · Assertions (SVA) · Intermediate

|-> vs |=>

Antecedent/consequent model, same-cycle vs next-cycle consequent start on identical waveforms, and the |=> ≡ |-> ##1 equivalence.

The antecedent/consequent model

An implication property has two halves: the antecedent (left), a sequence acting as the trigger, and the consequent (right), a sequence or property stating the obligation. The evaluation contract: at every clock tick an attempt starts; if the antecedent does not match from that tick, the attempt passes vacuously (next lesson). If the antecedent matches — possibly on several threads — the consequent must hold from EACH match's endpoint. The two implication operators differ only in where the consequent clock starts relative to that endpoint.

systemverilog
// Overlapped: consequent starts ON the antecedent end cycle
property p_ovl;
  @(posedge clk) req |-> gnt;        // gnt same cycle as req
endproperty

// Non-overlapped: consequent starts the NEXT cycle
property p_novl;
  @(posedge clk) req |=> gnt;        // gnt one cycle after req
endproperty

a_ovl:  assert property (p_ovl);
a_novl: assert property (p_novl);

Identical waveforms, different verdicts

The classic interview discriminator: one stimulus, both operators. |-> fuses the consequent onto the antecedent endpoint (it is ##0 at the property boundary); |=> inserts one tick (##1).

diagram
STIMULUS A — gnt in the SAME cycle as req

clk :  1    2    3    4
req :  0    1    0    0
gnt :  0    1    0    0
            A
req |-> gnt : consequent checked at tick 2  gnt=1  PASS
            P
req |=> gnt : consequent checked at tick 3  gnt=0  FAIL
                 F

STIMULUS B — gnt one cycle AFTER req

clk :  1    2    3    4
req :  0    1    0    0
gnt :  0    0    1    0
            A
req |-> gnt : checked at tick 2  gnt=0  FAIL at tick 2
            F
req |=> gnt : checked at tick 3  gnt=1  PASS
                 P

Same RTL, opposite verdicts — the operator IS the spec.

With a multi-cycle antecedent the rule reads from the antecedent's end tick: in (req ##1 ack) |-> done, done is checked on the ack cycle; with |=> it is checked one tick after ack.


The equivalence: |=> is |-> ##1

The two operators are not independent primitives: a |=> b is exactly a |-> ##1 b. This matters practically — any non-overlapped check can be rewritten overlapped with an explicit delay, which is the form you need when the consequent delay is data-dependent or ranged. The reverse direction also works: a |-> b equals a ##1 1 |=> b only with contortions — so |-> is the more primitive operator; treat |=> as convenient sugar for the common one-cycle case.

systemverilog
// These two are IDENTICAL in meaning:
property p_sugar;    @(posedge clk) req |=> gnt;       endproperty
property p_desugar;  @(posedge clk) req |-> ##1 gnt;   endproperty

// The desugared form generalizes; the sugar does not:
property p_window;   @(posedge clk) req |-> ##[1:3] gnt; endproperty
// There is no "|=> [0:2]" — ranged consequents use |-> ##[M:N].
diagram
WAVEFORM — req |=> gnt  ≡  req |-> ##1 gnt

clk :  1    2    3    4    5
req :  0    1    0    0    0
gnt :  0    0    1    0    0
            A    M
Both forms: antecedent ends @2, one tick inserted, gnt
required @3  identical attempt, identical match tick,
identical failure reporting. Tools display both the same way.

Choosing between them in protocols

Decision guide

  • Spec says "in the same cycle" (combinational guarantee, e.g. valid && ready handshake rules): |->.

  • Spec says "on the next cycle" (registered response, pipelined grant): |=>.

  • Spec gives a window ("within 1 to 3 cycles"): |-> ##[1:3] — overlapped plus explicit range.

  • Consequent must observe the same data the antecedent saw: |-> with $past, or sample into local variables (later topic); |=> shifts the observation point and often forces $past arithmetic.

  • Chained phase checks where the next phase begins on the end cycle of the previous: |-> mirrors the ##0 fusion of sequence land.

Interview angle

  • "Difference between |-> and |=>?" — same-cycle vs next-cycle consequent start, measured from the antecedent END tick. Then draw stimulus A/B above; the waveform is the expected proof.

  • "Rewrite a |=> b without |=>." — a |-> ##1 b. Instant follow-up: "and a window of 2 to 4?" — a |-> ##[2:4] b.

  • "Multi-cycle antecedent — where does the consequent start?" — from the antecedent endpoint, not its first cycle; many candidates miss this.

  • "Which is 'overlapped' and why the name?" — |->: the consequent's first observation overlaps the antecedent's last cycle.

Key takeaways

  • |-> checks the consequent starting ON the antecedent's end tick; |=> starts one tick later.

  • a |=> b is precisely a |-> ##1 b — |-> plus explicit delays is the general form.

  • Consequent timing is measured from the antecedent ENDPOINT, not from its first cycle.

  • Pick the operator from the spec's wording: same-cycle wording → |->, next-cycle wording → |=>.

Common pitfalls

  • Writing |=> for a same-cycle ready/valid rule — the check lands one cycle late and passes broken RTL.

  • Writing |-> gnt for a registered grant — guaranteed false failures on correct hardware.

  • Measuring consequent delay from the antecedent's START with multi-cycle antecedents — off-by-N checks.

  • Trying to range |=> directly — there is no ranged form; desugar to |-> ##[M:N].

  • Forgetting each antecedent match thread obliges its own consequent — a ranged antecedent fans out obligations.