🧠 What is let
in SystemVerilog?#
The let
construct in SystemVerilog allows you to define named expressions, similar to an inline macro or a parameterized function, but for expression reuse. It’s useful in both RTL and testbenches where a condition or formula is repeated multiple times.
🔧 Syntax#
let <name> = <expression>;
Or with arguments:
let <name>(arg1, arg2, ...) = <expression using args>;
✅ Basic Example#
let is_even(x) = (x % 2 == 0);
always_comb begin
if (is_even(count)) begin
// Do something when count is even
end
end
🎯 Instead of repeating
(x % 2 == 0)
everywhere, you can reuseis_even()
.
🧪 Use Case in Assertions#
let
is very useful in assert
or cover
statements:
let valid_condition(a, b) = (a > 0) && (b < 100);
assert property (@(posedge clk) valid_condition(a, b) |-> ready);
📌
let
improves readability and prevents duplication of complex expressions in assertions.
📦 let
in Packages#
You can define let
expressions inside packages to reuse them across modules and testbenches:
package math_expr_pkg;
let abs_diff(x, y) = (x > y) ? (x - y) : (y - x);
endpackage
And use it like this:
import math_expr_pkg::*;
logic [7:0] d = abs_diff(a, b);
🧬 Comparison: let
vs function
#
Feature | let | function |
---|---|---|
Syntax | Expression only | Procedural logic allowed |
Use in asserts | ✅ Yes | ❌ Not allowed in assert property |
Return type | Inferred from expression | Must be declared |
Usage | Inline, concise conditions | Complex operations, multi-line logic |
🔥 Real-World Examples#
1. Simplify Repeated Conditions#
let handshake = (valid && ready);
always_comb begin
if (handshake)
do_transfer();
end
2. Parametric Formulas#
let overflow_check(a, b, sum) = (sum < a) || (sum < b);
⚠️ Notes & Limitations#
let
is not synthesizable by all tools — check your synthesis tool’s support.- Use only for pure expressions — no side effects or procedural constructs.
- Cannot contain
begin-end
, loops, orif
statements — it’s not a function.
✅ Summary#
Benefit | Explanation |
---|---|
Improves readability | Gives names to complex expressions |
Reusable expressions | Use across modules, assertions, testbenches |
Assertion-friendly | Usable inside assert property , unlike function |
Lightweight | No overhead compared to function calls |
The let
construct brings elegance and reuse to your SystemVerilog code.
Use it to define meaningful, compact, and reusable logic conditions — especially in assertions and testbenches where clarity matters most.
// === File: math_pkg.sv ===
package math_pkg;
let abs_diff(x, y) = (x > y) ? (x - y) : (y - x);
let is_even(n) = (n % 2 == 0);
endpackage
// === File: dut.sv ===
import math_pkg::*;
module dut(input logic [3:0] a, b,
output logic [3:0] diff,
output logic even);
assign diff = abs_diff(a, b);
assign even = is_even(a);
endmodule
// === File: tb_let_demo.sv ===
import math_pkg::*;
module tb_let_demo;
logic [3:0] a = 4'd9, b = 4'd3;
logic [3:0] diff;
logic even;
dut u_dut (.a(a), .b(b), .diff(diff), .even(even));
initial begin
#1;
$display("abs_diff(%0d, %0d) = %0d", a, b, diff);
$display("is_even(%0d) = %b", a, even);
#5 $finish;
end
endmodule