🧩 What is a Module in SystemVerilog?#
A module in SystemVerilog is the core building block of RTL design — just like in Verilog — but with more powerful, typed, and maintainable syntax.
Modules can define logic, encapsulate submodules, accept parameters, and support synthesizable hardware description.
📦 Module Structure#
Modules promote hierarchical design, reusability, and testability.
🧱 Example Module#
module and_gate (
input logic a,
input logic b,
output logic y
);
assign y = a & b;
endmodule
✅
logic
replaceswire
andreg
— clearer, unified, and safer.
🔌 Module Port Types#
Keyword | Direction | Description |
---|---|---|
input | Into module | Read-only inside |
output | Out of module | Assigned internally (logic ) |
inout | Bidirectional | Shared bus / tri-state support |
🧱 Module Instantiation#
To use one module inside another, instantiate it with either positional or named mapping.
🔹 Positional Mapping (⚠️ Not Recommended)#
and_gate u1 (a, b, y); // Position must match!
❗ Risky if ports change position in the module declaration.
🔹 Named Mapping ✅ (Preferred)#
and_gate u1 (
.a(in1),
.b(in2),
.y(out)
);
✅ Safer, self-documenting, and required in large modules.
or if signal and port name is same then use .*
to auto match them,
and_gate u1 (.*);
🔁 Multiple Instances#
You can instantiate the same module multiple times with different connections:
and_gate u1 (.a(a1), .b(b1), .y(y1));
and_gate u2 (.a(a2), .b(b2), .y(y2));
Useful in parallel bit-slices, bus structures, or multi-lane logic.
⚙️ Parameters & Customization#
SystemVerilog modules can be parameterized:
module mux #(parameter WIDTH = 8) (
input logic [WIDTH-1:0] in0, in1,
input logic sel,
output logic [WIDTH-1:0] out
);
assign out = sel ? in1 : in0;
endmodule
Instantiation:
mux #(16) u_mux (.in0(a), .in1(b), .sel(sel), .out(result));
🔁 Loop-Based Replication (Without generate
)#
In SystemVerilog, generate
blocks are optional. You can use for
loops directly with genvar
in the same scope:
module bitwise_and (
input logic [3:0] a, b,
output logic [3:0] y
);
for (genvar i = 0; i < 4; i++) begin
assign y[i] = a[i] & b[i];
end
endmodule
✅ No need for
generate...endgenerate
— cleaner and more concise.
🧪 Continuous Assignment with assign
#
assign y = a & b;
- Only used for combinational logic on
logic
orwire
- Updates automatically when inputs change
🧬 Procedural Blocks#
⏱️ Sequential Logic: always_ff
#
always_ff @(posedge clk or posedge rst) begin
if (rst)
q <= 0;
else
q <= d;
end
- Uses non-blocking assignment (
<=
) - Synthesizes to registers
⚙️ Combinational Logic: always_comb
#
always_comb begin
case (sel)
2'b00: y = a;
2'b01: y = b;
default: y = 0;
endcase
end
- Uses blocking assignment (
=
) - Ensures combinational logic with sensitivity list inferred
🧬 Operators & Syntax Enhancements#
Bitwise Operators#
Operator | Meaning | Example |
---|---|---|
& | AND | y = a & b; |
| | OR | y = a | b; |
^ | XOR | y = a ^ b; |
~ | NOT | y = ~a; |
inside | inside | if (val inside {[1:5], 8, 10}) |
Concatenation & Replication#
assign bus = {addr, data}; // Concatenate
assign all_ones = {8{1'b1}}; // Replicate
assign combo = {addr, 4{1'b1}, data}; // Both
📊 Summary Table#
Construct | Use Case | Type of Logic | Recommended Use |
---|---|---|---|
assign | Combinational logic | Continuous | For simple wiring |
always_comb | Combinational logic | Procedural (= ) | Safe and clean |
always_ff | Sequential logic | Procedural (<= ) | Flip-flops/registers |
for(genvar) | Logic replication | Structural | No generate needed |
✅ Best Practices#
- ✅ Prefer named port mapping (
.a(a)
) - ✅ Use
logic
for unified signal types - ✅ Use
always_comb
,always_ff
instead of plainalways
- 🚫 Avoid mixing
=
and<=
in the same block - 🚫 Do not use
initial
,$display
, etc. in synthesizable code
SystemVerilog modules form the foundation of scalable, synthesizable RTL design.
With enhanced typing (logic
), cleaner instantiation, and improved constructs (always_ff
, for(genvar)
), they bring clarity and structure to modern hardware projects.