for all
20 Advanced Verilog HDL Projects with Easy Explanations
Here are easy explanations and annotated Verilog code snippets for all 20 advanced-level
Verilog problems mentioned earlier. Every explanation breaks down what each module does and
why it’s important for digital design learning.
1. Pipelined 8x8 Signed Multiplier
What it does: Multiplies two signed 8-bit numbers, outputting a 16-bit result. Pipelining
enables a result every clock cycle (once setup is complete), which is important for high-
speed designs.
module pipelined_multiplier(input clk, input signed [7:0] a, b, output reg signed [15:0]
reg signed [7:0] a_reg, b_reg;
reg signed [15:0] mult_reg;
always @(posedge clk) begin
a_reg <= a; // Store input a
b_reg <= b; // Store input b
mult_reg <= a_reg * b_reg; // Multiply previously stored values
result <= mult_reg; // Output the stored multiplication
end
endmodule
2. 16-to-4 Priority Encoder with Error
What it does: From 16 inputs, finds the highest '1' position, encodes it as output, and signals
error if more than one '1' is present.
module priority_encoder(input [15:0] in, output reg [3:0] code, output reg valid, error);
integer i, count;
always @(*) begin
code = 0; valid = 0; error = 0; count = 0;
for (i = 0; i < 16; i = i + 1) begin
if (in[i]) begin
code = i[3:0]; // Capture index of last '1'
valid = 1; // Indicate something was found
count = count + 1;
end
end
error = (count > 1); // Set error if more than one input is '1'
end
endmodule
3. Parametric Synchronous FIFO
What it does: A queue with customizable size and width. Tracks status (full/empty, error
flags) for safe operation.
module fifo #(parameter WIDTH=8, DEPTH=16)
(input clk, rst, wr, rd, input [WIDTH-1:0] din, output reg [WIDTH-1:0] dout,
output reg empty, full, overflow, underflow);
reg [WIDTH-1:0] mem [0:DEPTH-1];
reg [$clog2(DEPTH):0] wptr = 0, rptr = 0, count = 0;
always @(posedge clk, posedge rst) begin
if (rst) begin
wptr <= 0; rptr <= 0; count <= 0; empty <= 1; full <= 0; overflow <= 0; under
end else begin
overflow <= 0; underflow <= 0;
if (wr && !full) begin
mem[wptr] <= din; wptr <= wptr + 1; count <= count + 1;
end else if (wr && full) overflow <= 1;
if (rd && !empty) begin
dout <= mem[rptr]; rptr <= rptr + 1; count <= count - 1;
end else if (rd && empty) underflow <= 1;
empty <= (count == 0);
full <= (count == DEPTH);
end
end
endmodule
4. Configurable Universal Shift Register
What it does: Stores a value and can shift left/right, hold, or load data based on ‘mode’
input.
module universal_shift_reg #(parameter N=8)
(input clk, rst, input [1:0] mode, // 00: hold, 01: shift left, 10: shift right, 11: pa
input [N-1:0] din, output reg [N-1:0] dout);
always @(posedge clk or posedge rst) begin
if (rst) dout <= 0;
else case (mode)
2'b00: dout <= dout; // Hold value
2'b01: dout <= {dout[N-2:0], din[0]};// Shift left; insert din[0]
2'b10: dout <= {din[N-1], dout[N-1:1]}; // Shift right; insert din[N-1]
2'b11: dout <= din; // Load new data
endcase
end
endmodule
5. Parametric N-bit Gray Code Counter
What it does: Counts in Gray code, where only one bit changes per count, useful for
minimizing glitches.
module gray_counter #(parameter N=4)
(input clk, rst, output reg [N-1:0] gray);
reg [N-1:0] bin;
always @(posedge clk or posedge rst) begin
if (rst) bin <= 0;
else bin <= bin + 1;
gray <= bin ^ (bin >> 1); // Binary to Gray conversion
end
endmodule
6. PWM Generator with Configurable Duty Cycle
What it does: Produces a pulse-width modulated output—useful for motor speed/LED
dimming—where you can set the duty cycle.
module pwm #(parameter WIDTH=8)
(input clk, rst, input [WIDTH-1:0] duty, output reg pwm_out);
reg [WIDTH-1:0] cnt;
always @(posedge clk or posedge rst) begin
if (rst) cnt <= 0;
else cnt <= cnt + 1;
pwm_out <= (cnt < duty); // Output high if count below 'duty'
end
endmodule
7. AXI4-Lite Slave Memory Core (Outline)
What it does: The skeleton for a bus interface to memory, showing the main connections for
handshake signals.
module axi_lite_slave #(parameter ADDR_WIDTH=4, DATA_WIDTH=32)
(input clk, rst, input awvalid, input [ADDR_WIDTH-1:0] awaddr,
input wvalid, input [DATA_WIDTH-1:0] wdata,
input bready, output reg bvalid,
output reg [DATA_WIDTH-1:0] rdata, input arvalid, input [ADDR_WIDTH-1:0] araddr,
output reg rvalid);
// Students fill in the details for state machine, RAM, protocol, etc.
endmodule
8. Traffic Light FSM with Pedestrian Request
What it does: Manages four-way traffic lights; switches states for emergency or pedestrian
button.
module traffic_fsm(input clk, rst, ped, emerg,
output reg [1:0] ns_light, ew_light, ped_light);
typedef enum reg [2:0] {NS_GREEN, NS_YEL, EW_GREEN, EW_YEL, PED} state_t;
state_t state, next;
always @(posedge clk or posedge rst)
if (rst) state <= NS_GREEN;
else state <= next;
always @(*) begin
// Example transitions
if (emerg) next = PED; // Go to pedestrian state on emergency
else case (state)
NS_GREEN: next = ped ? PED : NS_YEL;
NS_YEL: next = EW_GREEN;
EW_GREEN: next = ped ? PED : EW_YEL;
EW_YEL: next = NS_GREEN;
PED: next = NS_GREEN;
endcase
// Students complete light assignments
end
endmodule
9. 32-bit Barrel Shifter
What it does: Shifts a 32-bit input left or right by a variable amount instantly, supporting
arithmetic/logical modes.
module barrel_shifter(input [31:0] data, input [4:0] shamt, input dir, // 0: left, 1: rig
input arith, output reg [31:0] out);
always @(*) begin
if (dir) out = arith ? $signed(data) >>> shamt : data >> shamt; // Right shift
else out = data << shamt; // Left shift
end
endmodule
10. Signed Divider (Restoring Algorithm, Outline)
What it does: Begins the structure for a sequential divider that handles signed numbers and
outputs quotient/remainder.
module signed_divider(input clk, rst, start, input signed [7:0] num, denom,
output reg signed [7:0] quotient, remainder, output reg done);
// Full multi-step state machine omitted for brevity—students fill FSM and datapath.
endmodule
11. Dual-Port RAM with Separate Clocks
What it does: Allows reading or writing two memory locations at once, each on separate
clocks—typical in FPGAs.
module dual_port_ram #(parameter WIDTH=8, DEPTH=16)
(input clk_a, clk_b, input [$clog2(DEPTH)-1:0] addr_a, addr_b,
input we_a, we_b, input [WIDTH-1:0] din_a, din_b,
output reg [WIDTH-1:0] dout_a, dout_b);
reg [WIDTH-1:0] mem [0:DEPTH-1];
always @(posedge clk_a) begin
if (we_a) mem[addr_a] <= din_a;
dout_a <= mem[addr_a];
end
always @(posedge clk_b) begin
if (we_b) mem[addr_b] <= din_b;
dout_b <= mem[addr_b];
end
endmodule
12. UART TX/RX Pair with Parity (Outline)
What it does: Core idea for transmit and receive of serial binary data with parity checks;
key for communication interfaces.
module uart_tx(input clk, input [7:0] data, input start, output reg tx, output reg busy);
// Implement state machine, add parity bits; sends bits one at a time.
endmodule
module uart_rx(input clk, input rx, output reg [7:0] data, output reg done, error);
// Implement sampler/state machine, check parity; sets done/error when byte received.
endmodule
13. Generic Clock Domain Crossing Synchronizer
What it does: Safely brings a signal from one clock domain into another, preventing glitches
(metastability).
module cdc_sync(input clk_dst, rst_dst, input async_sig, output reg sync_sig);
reg sync1;
always @(posedge clk_dst or posedge rst_dst) begin
if (rst_dst) {sync1, sync_sig} <= 0;
else begin
sync1 <= async_sig;
sync_sig <= sync1;
end
end
endmodule
14. SPI Master with All Modes (Outline)
What it does: Structure for an SPI master supporting all SPI modes using configurable clock
polarity and phase.
module spi_master(input clk, rst, start, input [7:0] mosi_data,
input cpol, cpha, output reg sclk, mosi, output reg done);
// Build FSM to shift out data and generate clk per cpol/cpha.
endmodule
15. FSM for Sequence Detection (e.g. '101101')
What it does: Recognizes a specific binary pattern on an input, outputs '1' when it is found.
module seq_detect(input clk, rst, in, output reg detected);
reg [2:0] state;
always @(posedge clk or posedge rst) begin
if (rst) {state, detected} <= 0;
else begin
// Update state according to pattern, set detected if matched.
end
end
endmodule
16. N-way Round Robin Arbiter
What it does: Grants access to one of several requestors in turn, distributing fair access.
module rr_arbiter #(parameter N=4)
(input clk, rst, input [N-1:0] req, output reg [N-1:0] grant);
reg [$clog2(N)-1:0] last;
always @(posedge clk or posedge rst) begin
if (rst) last <= 0;
else begin
// For each clock, grant to next requestor after 'last'
end
end
endmodule
17. Matrix Multiplication Engine (NxN, Outline)
What it does: Multiplies two N×N matrices in hardware; useful in DSP and AI accelerators.
module matmul #(parameter N=2, WIDTH=8)
(input clk, input [N*WIDTH-1:0] a, b, output reg [(2*WIDTH)-1:0] result [N-1:0]);
// Unpack a, b; compute result by summing products; assign to result matrix.
endmodule
18. CRC Generator (Parameterizable Poly)
What it does: Computes Cyclic Redundancy Check for error detection (choose poly for
CRC-8, CRC-16, etc.).
module crc #(parameter POLY=8'h07, WIDTH=8)
(input clk, rst, input [WIDTH-1:0] data, input valid, output reg [WIDTH-1:0] crc_out);
always @(posedge clk or posedge rst) begin
if (rst) crc_out <= 0;
else if (valid) crc_out <= (crc_out << 1) ^ (crc_out[WIDTH-1] ? POLY : 0) ^ data;
end
endmodule
19. FIR Digital Filter with Coefficient Loading (Outline)
What it does: Implements a digital filter where coefficients can be updated in real time,
used in signal processing.
module fir #(parameter N=4, WIDTH=8)
(input clk, rst, input [WIDTH-1:0] x, input load_coef, input [WIDTH-1:0] coef_in, input [
output reg [2*WIDTH-1:0] y);
reg [WIDTH-1:0] x_reg [0:N-1], coef [0:N-1];
integer i;
always @(posedge clk or posedge rst) begin
if (rst) begin
for (i=0;i<N;i=i+1) x_reg[i]<=0;
end else begin
// Shift previous samples, load x into x_reg[0];
end
if (load_coef) coef[coef_addr]<=coef_in; // Dynamic coefficient update
// Multiply x_reg by coef, sum into y
end
endmodule
20. Prioritized Maskable Interrupt Controller
What it does: Handles multiple interrupt sources, each with a mask and a priority. Finds and
signals the highest-priority unmasked interrupt.
module int_ctrl #(parameter N=8)
(input clk, rst, input [N-1:0] irq, input [N-1:0] mask, output reg irq_req, output reg [$
integer i;
always @(*) begin
irq_req = 0;
for (i = N-1; i >= 0; i = i - 1) begin
if (irq[i] && mask[i]) begin
irq_req = 1; irq_vec = i[$clog2(N)-1:0];
end
end
end
endmodule
Each module here has a clear real-world use, and every code block contains enough annotation
to help students follow along or expand into complete systems. If you’d like full implementations
for any specific problem (including all state machines, detailed handshaking, or testbenches), let
me know which ones!