1. SVA Guide - Immediate Assertions
Immediate assertions are non-temporal checks that evaluate an expression instantly, like a procedural if-statement with built-in reporting. They're essential for validating conditions in testbenches and RTL.
What are Immediate Assertions?
Immediate assertions:
- Execute immediately when encountered (like procedural statements)
- Evaluate expressions in the current time step
- Have no temporal/clock relationship
- Provide built-in pass/fail reporting
Key Difference: Immediate assertions check values right now. Concurrent assertions check sequences over time.
Syntax
// Basic syntax
assert (expression) [pass_statement] [else fail_statement];
// With label
label: assert (expression) pass_action; else fail_action;
// Simple form
assert (expression);
Types of Immediate Assertions
flowchart TD
A["Immediate Assertions"] --> B["Simple Immediate"]
A --> C["Deferred Immediate"]
B --> B1["assert(expr)"]
B --> B2["Executes instantly"]
B --> B3["Glitch-sensitive"]
C --> C1["assert #0 (expr)"]
C --> C2["Executes at end of time step"]
C --> C3["Avoids glitches"]
style A fill:#dbeafe,stroke:#3b82f6
style C fill:#d1fae5,stroke:#10b981
| Type | Syntax | When Evaluated | Use Case |
|---|---|---|---|
| Simple | assert (expr) | Immediately | Procedural checks |
| Deferred (observed) | assert #0 (expr) | Observed region | Avoid glitches |
| Deferred (final) | assert final (expr) | Final region | End-of-delta checks |
Action Blocks
// Full syntax with action blocks
assert (condition)
// Pass action - executed if assertion passes
$display("PASS: condition met");
else
// Fail action - executed if assertion fails
$error("FAIL: condition not met");
Severity System Tasks
| Task | Severity | Simulation | Use When |
|---|---|---|---|
$fatal | Fatal | Terminates | Unrecoverable error |
$error | Error | Continues | Test failure (default) |
$warning | Warning | Continues | Non-critical issue |
$info | Info | Continues | Debug information |
// Severity examples
assert (data != 0) else $fatal(1, "Data is zero - cannot continue");
assert (valid) else $error("Valid signal not asserted");
assert (ready) else $warning("Ready not yet asserted");
assert (cfg_done) else $info("Configuration pending");
Complete Examples
Example 1: Basic Immediate Assertion
module tb;
logic [7:0] data;
logic valid;
logic ready;
initial begin
// Test case 1: Valid data
data = 8'hAB;
valid = 1;
ready = 1;
check_data: assert (data != 0)
$display("[PASS] Data is non-zero: 0x%0h", data);
else
$error("[FAIL] Data is zero!");
check_handshake: assert (valid && ready)
$display("[PASS] Handshake complete");
else
$error("[FAIL] Handshake failed: valid=%b ready=%b", valid, ready);
// Test case 2: Invalid data
data = 0;
assert (data != 0)
$display("[PASS] Data is valid");
else
$warning("[WARN] Data is zero");
end
endmodule
Output
[PASS] Data is non-zero: 0xab [PASS] Handshake complete [WARN] Data is zero
Example 2: Assertions in Functions
function automatic logic [31:0] divide(input int a, input int b);
// Check for divide by zero
assert (b != 0) else begin
$error("Division by zero! a=%0d, b=%0d", a, b);
return 0;
end
return a / b;
endfunction
module tb;
initial begin
int result;
result = divide(100, 5); // OK: result = 20
$display("100/5 = %0d", result);
result = divide(50, 0); // Assertion fires
$display("50/0 = %0d", result);
end
endmodule
Example 3: Deferred Assertions (Avoid Glitches)
module tb;
logic a, b, c;
// Simple immediate - may see glitches
always @(a or b or c) begin
simple_check: assert (a && b && c)
else $warning("Simple: not all high");
end
// Deferred immediate - evaluates after all updates
always @(a or b or c) begin
deferred_check: assert #0 (a && b && c)
else $warning("Deferred: not all high");
end
initial begin
// All signals change, but at slightly different times
a = 0; b = 0; c = 0;
#1;
a = 1; // Simple assertion may fire here (glitch)
b = 1;
c = 1; // All high now
#1;
$finish;
end
endmodule
Immediate vs Concurrent Assertions
| Feature | Immediate | Concurrent |
|---|---|---|
| Timing | Instant evaluation | Clock-based sampling |
| Location | Procedural blocks | Module scope or procedural |
| Syntax | assert (expr) | assert property (@(clk) p) |
| Temporal | No sequences | Supports sequences, delays |
| Use case | Value checks | Protocol/timing checks |
// Immediate: Check value NOW
always @(posedge clk) begin
assert (count < MAX) else $error("Counter overflow");
end
// Concurrent: Check sequence over clock cycles
assert property (@(posedge clk) req |-> ##[1:3] ack);
Best Practices
1. Always Use Labels
// GOOD - labeled assertions
check_valid: assert (valid) else $error("Valid check failed");
check_range: assert (data < 256) else $error("Data out of range");
// BAD - anonymous assertions (hard to identify in logs)
assert (valid);
assert (data < 256);
2. Include Context in Messages
// GOOD - detailed message
assert (addr[1:0] == 2'b00) else
$error("Unaligned address: addr=0x%0h at time %0t", addr, $time);
// BAD - vague message
assert (addr[1:0] == 2'b00) else
$error("Error");
3. Use Appropriate Severity
// Fatal: Cannot continue
assert (clk !== 1'bx) else $fatal(1, "Clock is X");
// Error: Test failure but can continue
assert (data == expected) else $error("Data mismatch");
// Warning: Suspicious but not failure
assert (delay < 100) else $warning("Long delay: %0d cycles", delay);
Common Patterns
Range Check
check_range: assert (value inside {[0:MAX]})
else $error("Value %0d out of range [0:%0d]", value, MAX);
Enum Validity
typedef enum logic [1:0] {IDLE, RUN, DONE} state_e;
state_e state;
check_state: assert (state inside {IDLE, RUN, DONE})
else $error("Invalid state: %0d", state);
FIFO Checks
always @(posedge clk) begin
if (push && !pop) begin
no_overflow: assert (count < DEPTH)
else $error("FIFO overflow! count=%0d", count);
end
if (pop && !push) begin
no_underflow: assert (count > 0)
else $error("FIFO underflow!");
end
end
Mutual Exclusion
mutex_check: assert ($onehot0({read, write, idle}))
else $error("Multiple states active: rd=%b wr=%b idle=%b",
read, write, idle);
Common Mistakes
| Mistake | Problem | Fix |
|---|---|---|
| Missing else | No message on failure | Add else $error(...) |
| No label | Hard to identify in logs | Add descriptive labels |
| Using in synthesizable code | Synthesis errors | Wrap with `ifdef SIMULATION |
| Glitch sensitivity | False failures | Use deferred assert #0 |
Synthesis Considerations
module rtl_with_assertions (
input logic clk,
input logic [7:0] data,
output logic [7:0] result
);
always_ff @(posedge clk) begin
result <= data + 1;
// Wrap assertions for simulation only
`ifdef SIMULATION
assert (data < 255) else $warning("Data near overflow");
`endif
end
endmodule
Interview Questions
Q1: What is an immediate assertion?
Answer: An immediate assertion evaluates an expression at the instant it's executed, like a procedural if-statement. It checks the current value without any temporal/clock relationship.
Q2: What's the difference between simple and deferred immediate assertions?
Answer: Simple assertions (assert(expr)) execute immediately and may see glitches. Deferred assertions (assert #0) execute in the Observed region after all updates, avoiding glitches.
Q3: When would you use $fatal vs $error?
Answer: Use $fatal for unrecoverable errors where simulation cannot meaningfully continue (e.g., clock is X). Use $error for test failures that should be reported but allow simulation to continue checking other conditions.
Key Takeaways
- Immediate assertions check values instantly (no clock)
- Use
assert #0for deferred evaluation to avoid glitches - Always add labels and meaningful messages
- Choose appropriate severity: $fatal, $error, $warning, $info
- Wrap in
`ifdef SIMULATIONfor synthesizable code - Use for value checks; use concurrent assertions for temporal checks
Comments (0)
Leave a Comment