A PRACTICAL GUIDE FOR RTL DESIGNERS, VLSI
ENTHUSIASTS & INTERVIEW PREPARATION
25 ADVANCED
VERILOG
PROJECTS
COMPLETE CODE | REAL WORLD PROBLEMS | REUSABLE
SNIPPETS | OPTIMIZED FOR FPGA & ASIC
Prasanthi Chanda
Q1. 5-Stage Pipeline Instruction Fetch Stage (IF Stage)
module IF_stage (
input clk,
input reset,
input [31:0] pc_in,
output reg [31:0] pc_out,
output reg [31:0] instruction
);
// Simple Instruction Memory (ROM) - 16 instructions
for demo
reg [31:0] instr_mem [0:15];
initial begin
instr_mem[0] = 32'h00000013; // NOP (addi
x0,x0,0)
instr_mem[1] = 32'h00100093; // addi x1,x0,1
instr_mem[2] = 32'h00200113; // addi x2,x0,2
instr_mem[3] = 32'h00308193; // addi x3,x1,3
instr_mem[4] = 32'h00410213; // addi x4,x2,4
// ... fill rest with NOP
instr_mem[5] = 32'h00000013;
instr_mem[6] = 32'h00000013;
instr_mem[7] = 32'h00000013;
instr_mem[8] = 32'h00000013;
instr_mem[9] = 32'h00000013;
instr_mem[10] = 32'h00000013;
instr_mem[11] = 32'h00000013;
instr_mem[12] = 32'h00000013;
instr_mem[13] = 32'h00000013;
instr_mem[14] = 32'h00000013;
instr_mem[15] = 32'h00000013;
end
always @(posedge clk or posedge reset) begin
if(reset) begin
pc_out <= 32'd0;
instruction <= 32'd0;
end else begin
pc_out <= pc_in + 4;
instruction <= instr_mem[pc_in[5:2]]; // word-
aligned address indexing
end
end
endmodule
Q2. AXI4-Lite Slave Write Channel Basic Implementation
module axi4lite_slave #(
parameter ADDR_WIDTH = 4,
parameter DATA_WIDTH = 32
)(
input wire clk,
input wire resetn,
// Write address channel
input wire [ADDR_WIDTH-1:0] awaddr,
input wire awvalid,
output reg awready,
// Write data channel
input wire [DATA_WIDTH-1:0] wdata,
input wire [(DATA_WIDTH/8)-1:0] wstrb,
input wire wvalid,
output reg wready,
// Write response channel
output reg [1:0] bresp,
output reg bvalid,
input wire bready
);
// 4 registers
reg [DATA_WIDTH-1:0] regs [0:3];
reg aw_handshake;
reg w_handshake;
always @(posedge clk or negedge resetn) begin
if(!resetn) begin
awready <= 0;
wready <= 0;
bvalid <= 0;
bresp <= 2'b00;
aw_handshake <= 0;
w_handshake <= 0;
end else begin
// Address handshake
if(!awready && awvalid)
awready <= 1;
else
awready <= 0;
// Write data handshake
if(!wready && wvalid)
wready <= 1;
else
wready <= 0;
// When both handshake done, write register
aw_handshake <= awready & awvalid;
w_handshake <= wready & wvalid;
if(aw_handshake && w_handshake) begin
if(awaddr[3:2] < 4) begin
// write bytes with strobe
integer i;
for(i=0; i<DATA_WIDTH/8; i=i+1) begin
if(wstrb[i]) begin
regs[awaddr[3:2]][8*i +: 8] <= wdata[8*i +:
8];
end
end
bresp <= 2'b00; // OKAY
end else
bresp <= 2'b10; // SLVERR
bvalid <= 1;
end else if(bvalid && bready) begin
bvalid <= 0;
end
end
end
endmodule
Q3. Triple Modular Redundancy (TMR) Majority Voter
Module
module tmr_majority_voter #(parameter WIDTH = 8)(
input wire [WIDTH-1:0] in1,
input wire [WIDTH-1:0] in2,
input wire [WIDTH-1:0] in3,
output wire [WIDTH-1:0] out
);
assign out = (in1 & in2) | (in2 & in3) | (in1 & in3);
endmodule
Q4. UART Transmitter with Baud Rate Generator (Basic)
module uart_tx #(
parameter CLK_FREQ = 50_000_000,
parameter BAUD_RATE = 115200
)(
input wire clk,
input wire reset,
input wire tx_start,
input wire [7:0] tx_data,
output reg tx,
output reg tx_busy
);
localparam integer BAUD_DIV = CLK_FREQ /
BAUD_RATE;
reg [15:0] baud_cnt = 0;
reg baud_tick = 0;
// Baud rate generator
always @(posedge clk) begin
if(reset) begin
baud_cnt <= 0;
baud_tick <= 0;
end else if(baud_cnt == BAUD_DIV-1) begin
baud_cnt <= 0;
baud_tick <= 1;
end else begin
baud_cnt <= baud_cnt + 1;
baud_tick <= 0;
end
end
// UART TX FSM
reg [3:0] bit_idx = 0;
reg [9:0] shift_reg = 10'b1111111111; // start(0),
data(8), stop(1)
always @(posedge clk) begin
if(reset) begin
tx <= 1;
tx_busy <= 0;
bit_idx <= 0;
shift_reg <= 10'b1111111111;
end else if(baud_tick) begin
if(tx_busy) begin
tx <= shift_reg[0];
shift_reg <= {1'b1, shift_reg[9:1]};
if(bit_idx == 9) begin
tx_busy <= 0;
bit_idx <= 0;
end else
bit_idx <= bit_idx + 1;
end else if(tx_start) begin
shift_reg <= {1'b1, tx_data, 1'b0}; // stop bit =1,
data bits, start bit=0
tx_busy <= 1;
end else
tx <= 1; // idle high
end
end
endmodule
Q5. Power-Efficient Clock Gating Module (Simple
Enable-Based)
module clock_gating (
input clk,
input enable,
output gated_clk
);
reg gated_clk_reg;
always @(posedge clk) begin
gated_clk_reg <= enable;
end
assign gated_clk = clk & gated_clk_reg;
endmodule
Q6. Problem Statement: Synchronous FIFO (First-In-
First-Out) Buffer
module sync_fifo #(
parameter DATA_WIDTH = 8,
parameter DEPTH = 16,
parameter ADDR_WIDTH = 4
)(
input clk,
input reset,
input wr_en,
input rd_en,
input [DATA_WIDTH-1:0] data_in,
output reg [DATA_WIDTH-1:0] data_out,
output reg full,
output reg empty
);
reg [DATA_WIDTH-1:0] mem [0:DEPTH-1];
reg [ADDR_WIDTH-1:0] wr_ptr = 0, rd_ptr = 0;
reg [ADDR_WIDTH:0] count = 0;
always @(posedge clk) begin
if(reset) begin
wr_ptr <= 0; rd_ptr <= 0; count <= 0;
full <= 0; empty <= 1;
end else begin
// Write operation
if(wr_en && !full) begin
mem[wr_ptr] <= data_in;
wr_ptr <= wr_ptr + 1;
count <= count + 1;
end
// Read operation
if(rd_en && !empty) begin
data_out <= mem[rd_ptr];
rd_ptr <= rd_ptr + 1;
count <= count - 1;
end
// Update status flags
full <= (count == DEPTH);
empty <= (count == 0);
end
end
endmodule
Q7. Problem Statement: Parameterized N-bit
Comparator
module comparator #(
parameter WIDTH = 8
)(
input [WIDTH-1:0] a,
input [WIDTH-1:0] b,
output gt,
output eq,
output lt
);
assign gt = (a > b);
assign gt = (a > b);
assign eq = (a == b);
assign lt = (a < b);
endmodule
Q8. Problem Statement: Priority Encoder (4-to-2 bits)
module priority_encoder_4to2 (
input [3:0] in,
output reg [1:0] pos,
output reg valid
);
always @(*) begin
casex(in)
4'b0000: begin pos = 2'b00; valid = 0; end
4'b0001: begin pos = 2'b00; valid = 1; end
4'b001x: begin pos = 2'b01; valid = 1; end
4'b01xx: begin pos = 2'b10; valid = 1; end
4'b1xxx: begin pos = 2'b11; valid = 1; end
default: begin pos = 2'b00; valid = 0; end
endcase
end
endmodule
Q9. Problem Statement: Gray Code Counter (N-bit)
module gray_counter #(
parameter WIDTH = 4
)(
input clk,
input reset,
output reg [WIDTH-1:0] gray
);
reg [WIDTH-1:0] binary;
always @(posedge clk or posedge reset) begin
if(reset) begin
binary <= 0;
gray <= 0;
end else begin
binary <= binary + 1;
gray <= (binary >> 1) ^ binary;
end
end
endmodule
Q10. Problem Statement: Configurable Pulse Width
Modulator (PWM)
module pwm_generator #(
parameter COUNTER_WIDTH = 8
)(
input clk,
input reset,
input [COUNTER_WIDTH-1:0] duty_cycle, // 0 to max
count
input [COUNTER_WIDTH-1:0] period,
output reg pwm_out
);
reg [COUNTER_WIDTH-1:0] counter;
always @(posedge clk or posedge reset) begin
if(reset) begin
counter <= 0;
pwm_out <= 0;
end else begin
if(counter < period)
counter <= counter + 1;
else
counter <= 0;
pwm_out <= (counter < duty_cycle) ? 1'b1 : 1'b0;
end
end
endmodule
Q11. Problem Statement: N-bit Linear Feedback Shift
Register (LFSR)
module lfsr #(
parameter N = 8,
parameter TAP = 8'b10000011
)(
input clk,
input reset,
output reg [N-1:0] out
);
wire feedback = ^(out & TAP);
always @(posedge clk or posedge reset) begin
if (reset)
out <= 8'b1;
else
out <= {out[N-2:0], feedback};
end
endmodule
Q12. Problem Statement: Universal Shift Register (4-
bit)
module universal_shift_reg (
input clk,
input reset,
input [1:0] mode, // 00: hold, 01: right shift, 10: left
shift, 11: parallel load
input [3:0] d,
output reg [3:0] q
);
always @(posedge clk or posedge reset) begin
if(reset)
q <= 4'b0000;
else begin
case(mode)
2'b00: q <= q;
2'b01: q <= {1'b0, q[3:1]};
2'b10: q <= {q[2:0], 1'b0};
2'b11: q <= d;
endcase
end
end
endmodule
Q13. Problem Statement: Clock Divider by N
(parameterizable)
module clock_divider #(
parameter N = 10
)(
input clk,
input reset,
output reg clk_out
);
reg [$clog2(N)-1:0] count;
always @(posedge clk or posedge reset) begin
if(reset) begin
count <= 0;
clk_out <= 0;
end else begin
if(count == (N-1)) begin
count <= 0;
clk_out <= ~clk_out;
end else
count <= count + 1;
end
end
endmodule
Q14. Problem Statement: Sequence Detector (Detects
“1011”)
module seq_detector (
input clk,
input reset,
input in,
output reg detected
);
typedef enum reg [2:0] {S0, S1, S2, S3, S4} state_t;
state_t state;
always @(posedge clk or posedge reset) begin
if (reset) begin
state <= S0;
detected <= 0;
end else begin
case(state)
S0: state <= in ? S1 : S0;
S1: state <= in ? S1 : S2;
S2: state <= in ? S3 : S0;
S3: begin
state <= in ? S4 : S2;
detected <= in;
end
S4: begin
state <= in ? S1 : S2;
detected <= 0;
end
endcase
end
end
endmodule
Q15. Problem Statement: 8-bit Arithmetic Logic Unit
(ALU)
module alu (
input [7:0] a, b,
input [2:0] sel,
output reg [7:0] y
);
always @(*) begin
case(sel)
3'b000: y = a + b;
3'b001: y = a - b;
3'b010: y = a & b;
3'b011: y = a | b;
3'b100: y = a ^ b;
3'b101: y = ~a;
3'b110: y = a << 1;
3'b111: y = a >> 1;
endcase
end
endmodule
Q16. Problem Statement: N-bit Barrel Shifter
module barrel_shifter #(
parameter N = 8
)(
input [N-1:0] data_in,
input [$clog2(N)-1:0] shift_amt,
input dir, // 0 = left, 1 = right
output reg [N-1:0] data_out
);
always @(*) begin
if (dir == 0)
data_out = data_in << shift_amt;
else
data_out = data_in >> shift_amt;
end
endmodule
Q17. Problem Statement: Parity Generator and Checker
module parity_gen_check (
input [7:0] data_in,
input parity_bit, // received parity
output reg parity_gen,
output reg error
);
always @(*) begin
parity_gen = ^data_in; // Even parity
error = (parity_gen != parity_bit);
end
endmodule
Q18. Problem Statement: N-bit Up/Down Counter with
Load and Reset
module up_down_counter #(
parameter N = 8
)(
input clk,
input reset,
input load,
input up_down, // 1 = up, 0 = down
input [N-1:0] load_data,
output reg [N-1:0] count
);
always @(posedge clk or posedge reset) begin
if (reset)
count <= 0;
else if (load)
count <= load_data;
else if (up_down)
count <= count + 1;
else
count <= count - 1;
end
endmodule
Q19. Problem Statement: Pulse Synchronizer Between
Clock Domains
module pulse_synchronizer (
input clk_src,
input pulse_src,
input clk_dst,
output reg pulse_dst
);
reg pulse_meta, pulse_sync1, pulse_sync2;
// Sync to destination clock
always @(posedge clk_dst) begin
pulse_sync1 <= pulse_meta;
pulse_sync2 <= pulse_sync1;
pulse_dst <= pulse_sync1 & ~pulse_sync2;
end
// Meta-stability capture
always @(posedge clk_src)
pulse_meta <= pulse_src;
endmodule
Q20. Problem Statement: 8-bit BCD (Binary-Coded
Decimal) Counter
module bcd_counter (
input clk,
input reset,
output reg [3:0] units,
output reg [3:0] tens
);
always @(posedge clk or posedge reset) begin
if (reset) begin
units <= 0;
tens <= 0;
end else begin
if (units == 9) begin
units <= 0;
if (tens == 9)
tens <= 0;
else
tens <= tens + 1;
end else
units <= units + 1;
end
end
endmodule
Q21. Problem Statement: Priority Encoder (8-to-3)
module priority_encoder (
input [7:0] in,
output reg [2:0] out,
output reg valid
);
always @(*) begin
valid = 1;
casex(in)
8'b1xxxxxxx: out = 3'b111;
8'b01xxxxxx: out = 3'b110;
8'b001xxxxx: out = 3'b101;
8'b0001xxxx: out = 3'b100;
8'b00001xxx: out = 3'b011;
8'b000001xx: out = 3'b010;
8'b0000001x: out = 3'b001;
8'b00000001: out = 3'b000;
default: begin out = 3'b000; valid = 0; end
endcase
end
endmodule
Q22. Problem Statement: Gray Code Counter (4-bit)
module gray_counter (
input clk,
input reset,
output reg [3:0] gray
);
reg [3:0] binary;
always @(posedge clk or posedge reset) begin
if (reset) begin
binary <= 0;
gray <= 0;
end else begin
binary <= binary + 1;
gray <= binary ^ (binary >> 1);
end
end
endmodule
Q23. Problem Statement: Dual-Port RAM (Asynchronous
Write, Synchronous Read)
module dual_port_ram (
input clk,
input [2:0] rd_addr,
input [2:0] wr_addr,
input [7:0] wr_data,
input wr_en,
output reg [7:0] rd_data
);
reg [7:0] mem [7:0];
always @(posedge clk)
rd_data <= mem[rd_addr];
always @(*)
if (wr_en)
mem[wr_addr] = wr_data;
endmodule
Q24. Problem Statement: N-bit Carry-Save Adder (CSA)
module carry_save_adder #(
parameter N = 8
)(
input [N-1:0] a, b, c,
output [N-1:0] sum,
output [N-1:0] carry
);
assign sum = a ^ b ^ c;
assign carry = (a & b) | (b & c) | (c & a);
endmodule
Q25. Problem Statement: Signed Multiplier (4-bit
Booth’s Algorithm)
module booth_multiplier (
input clk,
input start,
input signed [3:0] multiplicand,
input signed [3:0] multiplier,
output reg signed [7:0] product,
output reg done
);
reg signed [7:0] A, S, P;
reg [2:0] count;
always @(posedge clk) begin
if (start) begin
A = {multiplicand, 4'b0000};
S = {-multiplicand, 4'b0000};
P = {4'b0000, multiplier, 1'b0};
count = 4;
done = 0;
end else if (count > 0) begin
case (P[1:0])
2'b01: P = P + A;
2'b10: P = P + S;
endcase
P = P >>> 1;
count = count - 1;
end else begin
product = P[7:0];
done = 1;
end
end
endmodule
Excellence in World class
VLSI Training & Placements
Do follow for updates & enquires
+91- 9182280927