Verilog HDL: Syntax and Modeling Styles Explained Clearly
Verilog is one of the most widely used Hardware Description Languages (HDLs) in digital design. It allows you to describe hardware behavior and structure at multiple abstraction levels, from simple logic gates to complete processors.
This post focuses on two things:
- Core Verilog syntax you must understand
- The three main modeling styles used in real designs
If you are coming from a software background, think of Verilog as a way to describe hardware behavior over time, not a program that runs line by line.
What is Verilog?
Verilog is used to model digital systems such as:
- Combinational logic
- Sequential logic
- Finite state machines
- Complete SoCs and ASIC designs
Verilog code can be:
- Simulated to verify functionality
- Synthesized to generate real hardware
Basic Verilog Program Structure
Every Verilog design is built using modules.
module example_module (
input wire a,
input wire b,
output wire y
);
assign y = a & b;
endmodule
Key points:
- module and endmodule define a hardware block
- Inputs and outputs describe the interface
- Internal logic describes how outputs depend on inputs
Common Data Types
- Wire
- Used for continuous connections.
wire sum;
assign sum = a ^ b;
- Reg
- Used to store values inside procedural blocks.
reg q;
Despite the name, reg does not always mean a flip-flop. It simply means the signal is assigned inside an always block.
Operators You’ll Use Often
- Arithmetic + - * /
- Logical &&
- Bitwise &
- Comparison == != < >
- Assignment = (blocking), <= (non-blocking)
Verilog Modeling Styles
Verilog supports three main modeling styles. Choosing the right one depends on what you are designing and how abstract you want the description to be.
1. Behavioral Modeling
- Behavioral modeling focuses on what the circuit does, not how it is built.
- Example: 2:1 multiplexer
module mux2_behavioral (
input wire a,
input wire b,
input wire sel,
output reg y
);
always @(*) begin
if (sel)
y = b;
else
y = a;
end
endmodule
Characteristics:
- Uses always blocks
- Easy to read and write
- Ideal for control logic and FSMs
- Synthesizable when written carefully
2. Dataflow Modeling
- Dataflow modeling describes logic using continuous assignments and expressions.
- Example: Full adder
module full_adder_dataflow (
input wire a,
input wire b,
input wire cin,
output wire sum,
output wire cout
);
assign sum = a ^ b ^ cin;
assign cout = (a & b) | (b & cin) | (a & cin);
endmodule
Characteristics:
- Uses assign statements
- Very close to Boolean equations
- Best for combinational logic
- Simple and concise
3. Structural Modeling
- Structural modeling connects lower-level modules together, similar to a schematic.
- Example: Full adder using two half adders
module half_adder (
input wire a,
input wire b,
output wire sum,
output wire carry
);
assign sum = a ^ b;
assign carry = a & b;
endmodule
module full_adder_structural (
input wire a,
input wire b,
input wire cin,
output wire sum,
output wire cout
);
wire s1, c1, c2;
half_adder ha1 (a, b, s1, c1);
half_adder ha2 (s1, cin, sum, c2);
assign cout = c1 | c2;
endmodule
Characteristics:
- Hierarchical design
- Mirrors real hardware connections
- Common in large designs
- Improves reusability and clarity
4. Gate-level Modeling
- Gate-leve modeling uses Verilog primitives as shown in the below example.
- Example: half adder
module half_adder (
input wire a,
input wire b,
output wire sum,
output wire carry
);
xor (sum, a, b);
and (carry, a, b);
endmodule
Characteristics:
- gate-level design
- very complex to code for big designs
Blocking vs Non-Blocking Assignments
This is critical in Verilog.
- Blocking (=)
- Used for combinational logic.
always @(*) begin
x = a & b;
y = x | c;
end
- Non-blocking (<=)
- Used for sequential logic.
always @(posedge clk) begin
q <= d;
end
- Rule of thumb:
- Use = in combinational logic
- Use <= in clocked logic
Modeling Sequential Logic
- Example: D flip-flop with active-low reset
module dff (
input wire clk,
input wire rst,
input wire d,
output reg q
);
always @(posedge clk or posedge rst) begin
if (!rst)
q <= 1'b0;
else
q <= d;
end
endmodule
This style is synthesizable and maps directly to hardware flip-flops.
When to Use Each Modeling Style
Behavioral modeling is best for control logic and finite state machines, where the focus is on describing how the circuit behaves rather than how it is physically built. It is easier to read and maintain, especially for complex decision-making logic.
Dataflow modeling is ideal for combinational logic. It closely matches Boolean equations and is commonly used for arithmetic circuits, multiplexers, and simple logic blocks where outputs are directly derived from inputs.
Structural modeling is used for large, hierarchical designs. It connects smaller modules together to form bigger systems and closely reflects actual hardware structure, making it suitable for reusable and scalable designs.
Gate-level modeling is mainly used for demonstration and learning purposes. It is not used in large or modern designs. This style is written using Verilog gate primitives, which makes the code verbose and difficult to manage. As a result, it is not suitable for building reusable or scalable designs.
In real projects, you will often mix of three styles(Behavioral, Dataflow, Structural) in the same design.
Final Thoughts
Verilog is powerful because it lets you model hardware at different abstraction levels. Understanding syntax is important, but mastering modeling styles is what makes your designs clean, scalable, and synthesizable.
Top comments (0)