Skip to main content

SystemVerilog Modules – Structure, Instantiation, and RTL Best Practices

· loading · loading · ·
Hardware Design SystemVerilog Module RTL Design Always_ff Parameter Instantiation
Hardware Design
Axolot Logic
Author
Axolot Logic
Digital Design Engineer
Table of Contents
SystemVerilog Design Series - This article is part of a series.
Part 7: This Article

🧩 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 replaces wire and reg — clearer, unified, and safer.


🔌 Module Port Types
#

KeywordDirectionDescription
inputInto moduleRead-only inside
outputOut of moduleAssigned internally (logic)
inoutBidirectionalShared 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 or wire
  • 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
#

OperatorMeaningExample
&ANDy = a & b;
|ORy = a | b;
^XORy = a ^ b;
~NOTy = ~a;
insideinsideif (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
#

ConstructUse CaseType of LogicRecommended Use
assignCombinational logicContinuousFor simple wiring
always_combCombinational logicProcedural (=)Safe and clean
always_ffSequential logicProcedural (<=)Flip-flops/registers
for(genvar)Logic replicationStructuralNo generate needed

✅ Best Practices
#

  • ✅ Prefer named port mapping (.a(a))
  • ✅ Use logic for unified signal types
  • ✅ Use always_comb, always_ff instead of plain always
  • 🚫 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.


SystemVerilog Design Series - This article is part of a series.
Part 7: This Article

Related

SystemVerilog always_ff vs always_comb vs always_latch – Safe RTL Coding Explained
· loading · loading
Hardware Design SystemVerilog Always_ff Always_comb RTL Design Sequential Logic Latches
Hardware Design
SystemVerilog Interface – Modular Signal Grouping with modport and Clocking Blocks
· loading · loading
Hardware Design Verification SystemVerilog Interface Modport Testbench RTL Design Connectivity
Hardware Design Verification
SystemVerilog Loops and Control Flow – for, while, foreach, repeat, break
· loading · loading
Hardware Design Verification SystemVerilog Loops Control Flow Testbench RTL Design Break/Continue
Hardware Design Verification
SystemVerilog Structs, Unions, and Typedefs – User-Defined Data Types Explained
· loading · loading
Hardware Design Verification SystemVerilog Struct Union Typedef Data Modeling RTL Design
Hardware Design Verification
SystemVerilog Tasks and Functions
· loading · loading
Hardware Design Verification SystemVerilog Tasks Functions RTL Design Testbench Reusability
Hardware Design Verification
SystemVerilog Blocking vs Non-Blocking Assignments Explained
· loading · loading
Hardware Design SystemVerilog Blocking Non-Blocking RTL Design Simulation Always Block
Hardware Design