🧩 What is a Module in Verilog?#
A module is the fundamental building block in Verilog. It represents a self-contained hardware block — such as a gate, a flip-flop, a counter, or even an entire processor.
📦 Module Structure#
Modules promote hierarchical design, reuse, and testability.
🧱 Example Module#
module and_gate (
input wire a,
input wire b,
output wire y
);
assign y = a & b;
endmodule
🔌 Module Port Types#
Ports define how a module communicates with the outside world.
Keyword | Direction | Description |
---|---|---|
input | Into module | Read-only inside |
output | Out of module | Can be wire or reg |
inout | Bidirectional | Used for shared buses |
🧱 Module Instantiation Styles#
In Verilog, using a module inside another requires instantiating it. Below are the two main styles for module instantiation and how to create multiple instances.
module_name instance_name (a, b, y);
🔹 Positional Mapping#
Connections are made in order. This method is concise but error-prone.
and_gate u1 (a, b, y);
⚠️ Risky! The port order must match the module definition exactly. If the order changes, it may connect incorrectly without any syntax error.
⛔ Problem Example:#
// Definition: module and_gate (input a, input b, output y);
and_gate u1 (b, a, y); // WRONG order — 'a' and 'b' are swapped!
🔹 Named Mapping ✅ (Recommended)#
Each port is connected using its name. This is safer and more readable.
and_gate u1 (
.a(in1),
.b(in2),
.y(out)
);
✅ Preferred for most cases. The port order in the module doesn’t matter — names ensure correctness.
💡 Advantages:#
- More readable
- Safer with long port lists
- Standard practice in auto-generated or IP-based code
🔁 Multiple Instances#
You can instantiate the same module multiple times with different signals:
and_gate u1 (.a(a1), .b(b1), .y(y1));
and_gate u2 (.a(a2), .b(b2), .y(y2));
This is common for bit-parallel logic, bus slicing, or module arrays.
🧪 Continuous Assignment: assign
#
The assign
keyword is used for combinational logic on wire
-type signals.
assign y = a & b;
- Continuous: updates automatically when inputs change
- Can only be used with
wire
🔁 Procedural Logic: always
Block#
Used for logic that reacts to events (like clocks or conditions).
✅ Syntax#
always @(sensitivity_list) begin
// statements
end
⚙️ always @(*)
→ Combinational Logic#
always @(*) begin
case (sel)
2'b00: y = a;
2'b01: y = b;
default: y = 0;
endcase
end
- Use blocking assignment (
=
)
⏱️ always @(posedge clk)
→ Sequential Logic#
always @(posedge clk or posedge rst) begin
if (rst)
q <= 0;
else
q <= d;
end
- Use non-blocking assignment (
<=
) - Models flip-flops and registers
🧬 Bitwise Operators#
Operate on each bit individually:
Operator | Meaning | Example |
---|---|---|
& | AND | y = a & b; |
| | OR | y = a | b; |
^ | XOR | y = a ^ b; |
~ | NOT (bitwise) | y = ~a; |
~& | NAND | y = ~(a & b); |
~| | NOR | y = ~(a | b);\ |
Don’t confuse with logical operators (
&&
,||
) which are single-bit.
🔗 Concatenation & Replication#
🔹 Concatenation#
assign bus = {addr, data}; // Combines two 8-bit signals into one 16-bit bus
🔹 Replication#
assign all_ones = {8{1'b1}}; // 8-bit vector of all 1s
🔹 Both#
assign all_in_one = {addr, data, 8{1'b1}};
📊 Summary Table#
Construct | Use Case | Assignment Type | Typical Signal |
---|---|---|---|
assign | Continuous logic | = | wire |
always @(*) | Combinational logic | = (blocking) | reg |
always @(posedge clk) | Sequential logic | <= (non-blocking) | reg |
🧠 Best Practices#
- ✅ Always use named port mapping
- 🧾 Use meaningful instance names:
AND1
,stage0
, etc. - 🎯 Follow consistent port direction and grouping
- ⚠️ Avoid mixing
=
and<=
inside the samealways
block