Common Verilog Design Examples
This section presents common Verilog building blocks that appear frequently in RTL design. These examples demonstrate both combinational and sequential logic patterns, as well as parameterized modules for reuse.
Combinational Logic
Combinational logic produces outputs that depend only on the current inputs —
there is no state or memory. In Verilog, combinational logic is modeled with
assign statements or always @(*) blocks.
AND Gate
module and_gate (
input wire a,
input wire b,
output wire y
);
assign y = a & b;
endmodule
2-to-1 Multiplexer
A multiplexer selects between two inputs based on a select signal.
module mux2 (
input wire a,
input wire b,
input wire sel,
output wire y
);
assign y = sel ? b : a;
endmodule
4-to-1 Multiplexer
module mux4 (
input wire [3:0] d,
input wire [1:0] sel,
output reg y
);
always @(*) begin
case (sel)
2'b00: y = d[0];
2'b01: y = d[1];
2'b10: y = d[2];
2'b11: y = d[3];
default: y = 1'bx;
endcase
end
endmodule
Half Adder
module half_adder (
input wire a,
input wire b,
output wire sum,
output wire carry
);
assign sum = a ^ b;
assign carry = a & b;
endmodule
Full Adder
module full_adder (
input wire a,
input wire b,
input wire cin,
output wire sum,
output wire cout
);
assign {cout, sum} = a + b + cin;
endmodule
Sequential Logic
Sequential logic produces outputs that depend on current inputs and past
state. Sequential elements are clocked; use non-blocking assignments (<=)
inside clocked always blocks.
D Flip-Flop
module d_ff (
input wire clk,
input wire reset,
input wire d,
output reg q
);
always @(posedge clk or posedge reset) begin
if (reset)
q <= 1'b0;
else
q <= d;
end
endmodule
4-bit Counter
module counter (
input wire clk,
input wire reset,
output reg [3:0] count
);
always @(posedge clk or posedge reset) begin
if (reset)
count <= 4'd0;
else
count <= count + 1'b1;
end
endmodule
4-bit Shift Register
module shift_register (
input wire clk,
input wire reset,
input wire d,
output reg [3:0] q
);
always @(posedge clk or posedge reset) begin
if (reset)
q <= 4'b0000;
else
q <= {q[2:0], d}; // Shift left, insert d at LSB
end
endmodule
Parameterized Modules
Parameterized modules can be customized at instantiation time, avoiding code duplication.
N-bit Counter
module counter_n #(
parameter N = 8
) (
input wire clk,
input wire reset,
output reg [N-1:0] count
);
always @(posedge clk or posedge reset) begin
if (reset)
count <= {N{1'b0}};
else
count <= count + 1'b1;
end
endmodule
// Instantiate as 16-bit counter
counter_n #(.N(16)) u_cnt (.clk(clk), .reset(rst), .count(cnt));
N-bit Adder
module adder_n #(
parameter N = 8
) (
input wire [N-1:0] a,
input wire [N-1:0] b,
input wire cin,
output wire [N-1:0] sum,
output wire cout
);
assign {cout, sum} = a + b + cin;
endmodule
Synthesis-Friendly Style
Follow these coding guidelines for reliable synthesis results:
Use non-blocking
<=in clockedalwaysblocks (sequential).Use blocking
=in combinationalalways @(*)blocks.Always include a
defaultcase incasestatements.Do not use
#delayin synthesizable code — delays are simulation-only.Declare all outputs of combinational blocks in the sensitivity list (use
@(*)).
// BAD: incomplete sensitivity list (may not synthesize correctly)
always @(a) begin
y = a & b; // b is missing from sensitivity list
end
// GOOD: use @(*) for combinational logic
always @(*) begin
y = a & b;
end
See Also
Verilog Data Types — Data types used in these examples.
Procedural Blocks in Verilog — How
initialandalwaysblocks work.Finite State Machines in Verilog — State machine design as an advanced sequential pattern.