Table of Contents
1. Verilog Basics
2. Data Types and Operators
3. Procedural Blocks and Timing
4. Combinational Logic
5. Sequential Logic
6. FSM Design
7. Blocking vs Non-Blocking
8. Tasks and Functions
9. Generate Statements
10. Parameterization
11. Synthesis and Optimization
12. Timing and Constraints
13. Testbench and Verification
14. Advanced Concepts
15. Design Examples
1. Verilog Basics
Q1. What is Verilog and what is it used for?
Verilog is a Hardware Description Language (HDL) used to model, design, and verify digital
electronic systems at various levels of abstraction. It is primarily used for: • Design of digital circuits
(ASICs, FPGAs) • Behavioral and structural modeling • Simulation and verification of designs •
Synthesis of RTL code to gate-level netlists • Timing analysis and verification
Q2. What are the different levels of abstraction in Verilog?
Verilog supports multiple levels of abstraction:
1. Behavioral Level: Describes what the system does using high-level constructs
2. Register Transfer Level (RTL): Describes data flow between registers
3. Gate Level: Describes design using logic gates and their interconnections
4. Switch Level: Describes design using transistors and switches
Q3. What is the difference between Verilog and VHDL?
Key differences:
Verilog:
• C-like syntax, easier to learn
• Case-sensitive
• Weakly typed
• More concise code
• Popular in US and Asia
VHDL:
• Pascal/Ada-like syntax
• Case-insensitive
• Strongly typed
• More verbose
• Popular in Europe and defense applications
Q4. What are the basic building blocks of a Verilog module?
A Verilog module consists of:
1. Module declaration: module name and port list
2. Port declarations: input, output, inout
3. Internal signal declarations: wire, reg, integer, etc.
4. Functionality: assign statements, always blocks, initial blocks
5. Module instantiation: instances of other modules
6. Module end: endmodule keyword
module example(
input wire clk,
input wire reset,
output reg [7:0] data_out
);
// Internal signals
reg [7:0] counter;
// Functionality
always @(posedge clk or posedge reset) begin
if (reset)
counter <= 8'b0;
else
counter <= counter + 1;
end
assign data_out = counter;
endmodule
Q5. What is the difference between wire and reg?
wire:
• Represents physical connections/nets
• Cannot store values
• Driven by continuous assignments or module outputs
• Used for combinational logic
• Default value is 'z' (high impedance)
reg:
• Represents variables that can store values
• Used in procedural blocks (always, initial)
• Does not necessarily synthesize to a register
• Can represent combinational or sequential logic
• Default value is 'x' (unknown)
// wire examples
wire [7:0] bus;
assign bus = data_in & mask; // Continuous assignment
// reg examples
reg [7:0] counter;
always @(posedge clk) begin
counter <= counter + 1; // Sequential
end
reg [7:0] result;
always @(*) begin
result = a + b; // Combinational (still uses reg)
end
Q6. What are input, output, and inout ports?
input: Port that receives data into the module (read-only inside module)
output: Port that sends data out of the module (can be wire or reg)
inout: Bidirectional port (can be both input and output, must be wire type)
module port_example(
input wire clk, // Input
input wire [7:0] data_in, // 8-bit input
output reg [7:0] data_out, // 8-bit output (reg type)
output wire valid, // Output (wire type)
inout wire [7:0] bidir_bus // Bidirectional port
);
// Implementation
endmodule
Q7. What is a module in Verilog?
A module is the fundamental building block in Verilog that encapsulates functionality. It: • Defines a
hardware component with inputs and outputs • Can be instantiated multiple times • Supports
hierarchical design • Can contain other module instances • Provides abstraction and reusability
Q8. How do you instantiate a module?
Modules can be instantiated using two methods:
1. Positional Port Mapping: Port connections in the same order as module definition
2. Named Port Mapping: Explicit port connections using
.port_name(signal) syntax (recommended)
// Module definition
module adder(input a, input b, output sum);
assign sum = a + b;
endmodule
// Positional instantiation
adder u1(a_sig, b_sig, sum_sig);
// Named instantiation (preferred)
adder u2(
.a(a_sig),
.b(b_sig),
.sum(sum_sig)
);
Q9. What is the purpose of the timescale directive?
The `timescale directive defines:
1. Time unit: Base unit for delays
2. Time precision: Smallest time increment for simulation Syntax:
`timescale time_unit/time_precision
`timescale 1ns/1ps
// Time unit is 1 nanosecond
// Precision is 1 picosecond
module test;
reg clk;
initial begin
clk = 0;
#10 clk = 1; // 10 ns delay
#5.5 clk = 0; // 5.5 ns delay
end
endmodule
Q10. What are the different number representations in Verilog?
Verilog supports multiple number formats: Syntax: [size]'[base][value]
Bases:
• 'b or 'B – Binary
• 'o or 'O - Octal
• 'd or 'D - Decimal
• 'h or 'H - Hexadecimal
Special values:
• x or X – Unknown
• z or Z- High impedance
• _ - Underscore for readability (ignored)
// Different number representations
8'b1010_1010 // 8-bit binary: 170
8'd170 // 8-bit decimal: 170
8'hAA // 8-bit hex: 170
4'o12 // 4-bit octal: 10
// Without size (32-bit default)
'b1010 // 32-bit binary
'd100 // 32-bit decimal
// Special values
4'bxx10 // 4-bit with unknowns
8'hzz // 8-bit high-Z
Q11. What is the difference between = and <= operators?
= (Blocking Assignment):
• Used in combinational logic
• Executes sequentially
• Blocks execution until assignment completes
• Used in always @(*) or always @(combinational signals)
<= (Non-blocking Assignment):
• Used in sequential logic
• Executes concurrently
• Scheduled for end of time step
• Used in always @(posedge clk) blocks
// Blocking (=)
always @(*) begin
temp = a & b;
out = temp | c; // Uses updated temp value
end
// Non-blocking (<=)
always @(posedge clk) begin
q1 <= d;
q2 <= q1; // Uses old q1 value (shift register)
end
Q12. What are the different types of delays in Verilog?
1. Inertial Delay: Default delay model, filters glitches shorter than delay
2. Transport Delay: Propagates all transitions regardless of duration
3. Regular Delay (#): Delays assignment by specified time
4. Intra-assignment Delay: Evaluates RHS immediately, delays assignment
// Regular delay
#10 a = b; // Wait 10 time units, then assign
// Intra-assignment delay
a = #10 b; // Sample b now, assign to a after 10 units
// In continuous assignment
assign #5 out = in; // 5 time unit delay
Q13. What is the difference between $display and $monitor?
$display:
• Executes once when encountered
• Must be explicitly called each time
• Used for specific checkpoints
$monitor:
• Continuously monitors signals
• Automatically displays when any monitored signal changes
• Only one $monitor can be active at a time
• Can be turned on/off with
$monitoron/$monitoroff
initial begin
// $display - executes once
$display("Time=%0t: a=%b", $time, a);
// $monitor - executes on signal change
$monitor("Time=%0t: a=%b, b=%b", $time, a, b);
#10 a = 1; // $monitor will automatically display
#10 b = 1; // $monitor will automatically display
$monitoroff; // Stop monitoring
end
Q14. What are system tasks in Verilog?
System tasks are built-in functions starting with $ that provide various utilities:
Display Tasks: $display, $write, $monitor, $strobe
File I/O: $fopen, $fclose, $fwrite, $fread
Simulation Control:
$finish, $stop, $time
Value Change Dump: $dumpfile, $dumpvars
Random: $random, $urandom
Timing: $time, $realtime
Q15. What is the purpose of initial and always blocks?
initial block:
• Executes once at time 0
• Used for initialization and testbenches
• Not synthesizable (simulation only)
• Can have delays and loops
always block:
• Executes repeatedly based on sensitivity list
• Used for both synthesis and simulation
• Models combinational and sequential logic
• Continues throughout simulation
// initial block
initial begin
clk = 0;
reset = 1;
#100 reset = 0;
end
// always block - combinational
always @(*) begin
sum = a + b;
end
// always block - sequential
always @(posedge clk) begin
q <= d;
end
2. Data Types and Operators
Q16. What are the different data types in Verilog?
Net Types:
• wire (most common)
• tri, wand, wor, triand, trior
• supply0, supply1
• trireg
Variable Types:
• reg (most common)
• integer (32-bit signed)
• real (64-bit floating point)
• time (64-bit unsigned)
• realtime
Arrays and Vectors:
• Vectors: [MSB:LSB]
• Arrays: memory type
Q17. What is the difference between reg and integer?
reg:
• Can be any width (specified by user)
• Unsigned by default
• Can represent individual bits
• Used for both combinational and sequential logic
integer:
• Always 32-bit wide
• Signed by default
• Used for loop counters and arithmetic
• • Cannot access individual bits directly
reg [7:0] data; // 8-bit unsigned
reg [15:0] address; // 16-bit unsigned
integer i; // 32-bit signed
integer count; // Used for counting
// Usage
for (i = 0; i < 10; i = i + 1) begin
data[i] = 1'b0;
end
Q18. What are signed and unsigned numbers in Verilog?
By default, reg and wire are unsigned, integer is signed. Use 'signed' keyword for signed
arithmetic:
reg signed [7:0] signed_data; // Signed 8-bit
wire signed [15:0] signed_result; // Signed 16-bit
// Signed arithmetic
reg signed [7:0] a = -5;
reg signed [7:0] b = 3;
reg signed [7:0] result;
always @(*) begin
result = a + b; // Result = -2 (signed arithmetic)
end
// Unsigned arithmetic
reg [7:0] ua = 8'hFB; // 251 unsigned
reg [7:0] ub = 8'h03; // 3
// ua + ub = 254 (unsigned)
Q19. What are the different types of operators in Verilog?
Arithmetic: +, -, *, /, % (modulus)
Logical: && (AND), || (OR), ! (NOT)
Relational: <, <=, >, >=,
==, !=
Bitwise: & (AND), | (OR), ^ (XOR), ~(NOT), ~^ or ^~ (XNOR)
Reduction: &, |, ^, ~&, ~|, ~^
Shift: <<, >>, <<<, >>>
Concatenation: { }
Replication: {n{ }}
Conditional: ? :
// Bitwise
4'b1010 & 4'b1100 // = 4'b1000
// Reduction (operates on single operand)
&4'b1111 // = 1 (AND all bits)
|4'b0000 // = 0 (OR all bits)
// Shift
4'b0011 << 1 // = 4'b0110
4'b1100 >> 1 // = 4'b0110
// Concatenation
{4'b1010, 4'b0101} // = 8'b1010_0101
// Replication
{4{2'b10}} // = 8'b1010_1010
Q20. What is the difference between == and === operators?
== (Logical Equality): • Returns x if any operand has x or z • Used in synthesizable code • Cannot
distinguish x and z values
=== (Case Equality): • Compares including x and z values • Returns 0 or 1 only (never x) • Used
in testbenches (not synthesizable) • Also !== (case inequality)
reg [3:0] a = 4'b10x0;
reg [3:0] b = 4'b10x0;
reg [3:0] c = 4'b1000;
// Logical equality
a == b // Result: x (due to x in operands)
a == c // Result: x
// Case equality
a === b // Result: 1 (exact match including x)
a === c // Result: 0 (x doesn't match 0)
4'bz === 4'bz // Result: 1
Q21. Explain concatenation and replication operators.
Concatenation { }: Joins multiple signals/values into a single vector
Replication {n{ }}: Repeats a pattern n times
// Concatenation
wire [7:0] bus;
wire [3:0] upper = 4'b1010;
wire [3:0] lower = 4'b0101;
assign bus = {upper, lower}; // bus = 8'b1010_0101
// Multiple concatenation
wire [2:0] a = 3'b101;
wire [1:0] b = 2'b11;
wire c = 1'b0;
wire [5:0] result = {a, b, c}; // 6'b101110
// Replication
wire [7:0] pattern = {4{2'b10}}; // 8'b10101010
wire [15:0] zeros = {16{1'b0}}; // All zeros
// Sign extension
wire [7:0] data = 8'b1111_0000;
wire [15:0] extended = {{8{data[7]}}, data}; // Sign extend
Q22. What is the conditional operator and how is it used?
The conditional (ternary) operator ?: provides inline if-else functionality.
Syntax: condition ? true_value : false_value
// Basic usage
wire [7:0] result = (select) ? data_a : data_b;
// Multiple conditions (nested)
wire [1:0] sel;
wire [7:0] out = (sel == 2'b00) ? data0 :
(sel == 2'b01) ? data1 :
(sel == 2'b10) ? data2 : data3;
// In combinational logic
always @(*) begin
max = (a > b) ? a : b;
min = (a < b) ? a : b;
end
// MUX implementation
assign mux_out = sel ? in1 : in0;
Q23. What are shift operators? Difference between logical and arithmetic shift?
Logical Shift (<<, >>):
• Fills with zeros
• Used for unsigned numbers
• << : Left shift (multiply by 2^n)
• >> : Right shift (divide by 2^n)
Arithmetic Shift (<<<, >>>):
• <<< : Same as logical left shift
• >>> : Sign-extended right shift for signed numbers
• • Preserves sign bit
// Logical shift
reg [7:0] data = 8'b1100_0110;
data << 2 // = 8'b0001_1000 (zeros filled)
data >> 2 // = 8'b0011_0001 (zeros filled)
// Arithmetic shift
reg signed [7:0] neg = -4; // 8'b1111_1100
neg >>> 1 // = 8'b1111_1110 (sign extended, = -2)
neg >> 1 // = 8'b0111_1110 (logical, = 126)
// Practical use
wire [7:0] mult_by_4 = data << 2;
wire [7:0] div_by_2 = data >> 1;
Q24. What is operator precedence in Verilog?
Operator precedence (highest to lowest):
1. Unary: +, -, !, ~, &, |, ^
2. Multiply/Divide: *, /, %
3. Add/Subtract: +, -
4. Shift: <<, >>, <<<, >>>
5. Relational: <, <=, >, >=
6. Equality: ==, !=, ===, !==
7. Bitwise AND: &
8. Bitwise XOR: ^, ~^
9. Bitwise OR: |
10. Logical AND: &&
11. Logical OR: ||
12. Conditional: ? : Use parentheses for clarity!
// Without parentheses
result = a + b * c; // b*c evaluated first
// With parentheses (recommended)
result = (a + b) * c;
// Complex expression
out = (a & b) | (c ^ d); // Clear intent
Q25. What are reduction operators?
Reduction operators perform operations on all bits of a single operand, producing a single-bit
result.
Operators: & (AND), | (OR), ^ (XOR), ~& (NAND), ~| (NOR), ~^ or ^~ (XNOR)
reg [3:0] data = 4'b1010;
// Reduction operators
&data // = 1'b0 (AND all bits: 1&0&1&0 = 0)
|data // = 1'b1 (OR all bits: 1|0|1|0 = 1)
^data // = 1'b0 (XOR all bits: 1^0^1^0 = 0)
~&data // = 1'b1 (NAND all bits)
~|data // = 1'b0 (NOR all bits)
~^data // = 1'b1 (XNOR all bits, parity check)
// Practical use - Parity generation
wire [7:0] byte_data;
wire even_parity = ^byte_data; // Even parity
wire odd_parity = ~^byte_data; // Odd parity
// All ones check
wire all_ones = &bus; // True if all bits are 1
wire any_one = |bus; // True if any bit is 1
3. Procedural Blocks and Timing
Q26. What is a sensitivity list in an always block?
The sensitivity list specifies signals that trigger the always block execution.
Types:
• @(*) or @* - All signals on RHS (automatic)
• @(signal) - Specific signal
• @(posedge clk) - Clock edge
• @(posedge clk or negedge rst_n) - Multiple signals
// Combinational - all signals
always @(*) begin
result = a + b + c; // Triggers on a, b, or c change
end
// Sequential - clock edge
always @(posedge clk) begin
q <= d;
end
// With asynchronous reset
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
q <= 0;
else
q <= d;
end
Q27. What is the difference between @(posedge) and @(negedge)?
@(posedge signal): Triggers when signal transitions from 0 to 1
@(negedge signal): Triggers when signal transitions from 1 to 0
reg clk, data_pos, data_neg;
// Positive edge triggered
always @(posedge clk) begin
data_pos <= input_data; // Captures on rising edge
end
// Negative edge triggered
always @(negedge clk) begin
data_neg <= input_data; // Captures on falling edge
end
// Both edges
always @(posedge clk or negedge clk) begin
toggle <= ~toggle; // Toggles on both edges
end
Q28. What are delay controls in Verilog?
Types of delays:
1. Regular Delay (#): Delays execution
2. Intra-assignment Delay: Evaluates RHS first, then delays
3. Zero Delay (#0): Executes after current time events
// Regular delay
initial begin
a = 0;
#10 a = 1; // Wait 10 time units
#5 a = 0; // Wait 5 more units
end
// Intra-assignment delay
always @(trigger) begin
output_sig = #5 input_sig;
// Sample input_sig now, assign after 5 units
end
// Zero delay (delta delay)
initial begin
a = 1;
b = #0 a; // b gets value of a after delta delay
end
Q29. What is the difference between fork-join and begin-end blocks?
begin-end:
• Sequential execution
• Statements execute one after another
• Total time = sum of all delays
fork-join:
• Parallel execution
• All statements start simultaneously
• Total time = longest delay path
// Sequential (begin-end)
initial begin
#10 a = 1; // At time 10
#20 b = 1; // At time 30
#5 c = 1; // At time 35
end // Completes at time 35
// Parallel (fork-join)
initial fork
#10 a = 1; // At time 10
#20 b = 1; // At time 20
#5 c = 1; // At time 5
join // Completes at time 20 (longest delay)
Q30. What are event controls in Verilog?
Event controls pause execution until a specific event occurs. Types:
• @ - Edge sensitive
• @(*) - Level sensitive (all RHS signals)
• wait() - Level sensitive (specific condition)
• -> (event trigger)
// Edge event
always @(posedge clk) begin
// Execute on clock edge
end
// Named events
event data_ready;
initial begin
#100 -> data_ready; // Trigger event
end
always @(data_ready) begin
$display("Data is ready");
end
// wait statement
initial begin
wait(reset_done); // Wait until reset_done is true
start_test();
end
4. Combinational Logic Design
Q31. How do you design combinational logic in Verilog?
Combinational logic can be designed using:
1. Continuous assignment (assign)
2. always @(*) block with blocking assignments
3. Logic gates instantiation
Key rules:
• Output depends only on current inputs
• No clock or storage elements
• Use blocking assignments (=) in always blocks
• Include all inputs in sensitivity list
// Method 1: Continuous assignment
assign sum = a + b;
assign mux_out = sel ? in1 : in0;
// Method 2: always @(*) block
always @(*) begin
case(sel)
2'b00: out = in0;
2'b01: out = in1;
2'b10: out = in2;
2'b11: out = in3;
endcase
end
Q32. Design a 4:1 multiplexer in Verilog.
A multiplexer selects one input from multiple inputs based on select lines.
module mux_4to1 (
input [3:0] in,
input [1:0] sel,
output reg out
);
always @(*) begin
case(sel)
2'b00: out = in[0];
2'b01: out = in[1];
2'b10: out = in[2];
2'b11: out = in[3];
endcase
end
endmodule
// Alternative using conditional operator
module mux_4to1_alt (
input [3:0] in,
input [1:0] sel,
output out
);
assign out = (sel == 2'b00) ? in[0] :
(sel == 2'b01) ? in[1] :
(sel == 2'b10) ? in[2] : in[3];
endmodule
Q33. Design a priority encoder.
A priority encoder outputs the binary position of the highest priority active input.
module priority_encoder_8to3 (
input [7:0] in,
output reg [2:0] out,
output reg valid
);
always @(*) begin
valid = 1'b1;
casez (in)
8'b1???????: out = 3'd7;
8'b01??????: out = 3'd6;
8'b001?????: out = 3'd5;
8'b0001????: out = 3'd4;
8'b00001???: out = 3'd3;
8'b000001??: out = 3'd2;
8'b0000001?: out = 3'd1;
8'b00000001: out = 3'd0;
default: begin
out = 3'd0;
valid = 1'b0; // no input is high
end
endcase
end
endmodule
Q34. What is a decoder? Design a 3:8 decoder.
A decoder converts binary input to one-hot output.
module decoder_3to8 (
input [2:0] in,
input enable,
output reg [7:0] out
);
always @(*) begin
if (enable)
out = 1 << in; // One-hot encoding
else
out = 8'b0;
end
endmodule
// Alternative implementation
module decoder_3to8_alt (
input [2:0] in,
input enable,
output reg [7:0] out
);
always @(*) begin
out = 8'b0;
if (enable)
case(in)
3'd0: out = 8'b0000_0001;
3'd1: out = 8'b0000_0010;
3'd2: out = 8'b0000_0100;
3'd3: out = 8'b0000_1000;
3'd4: out = 8'b0001_0000;
3'd5: out = 8'b0010_0000;
3'd6: out = 8'b0100_0000;
3'd7: out = 8'b1000_0000;
endcase
end
endmodule
Q35. Design a full adder in Verilog.
A full adder adds three bits (A, B, Cin) and produces Sum and Cout.
module full_adder (
input a, b, cin,
output sum, cout
);
assign sum = a ^ b ^ cin;
assign cout = (a & b) | (b & cin) | (a & cin);
endmodule
// Using always block
module full_adder_behavioral (
input a, b, cin,
output reg sum, cout
);
always @(*) begin
{cout, sum} = a + b + cin;
end
endmodule
// 4-bit ripple carry adder
module ripple_carry_adder_4bit (
input [3:0] a, b,
input cin,
output [3:0] sum,
output cout
);
wire [3:1] carry;full_adder fa0(.a(a[0]), .b(b[0]), .cin(cin),
.sum(sum[0]), .cout(carry[1]));
full_adder fa1(.a(a[1]), .b(b[1]), .cin(carry[1]),
.sum(sum[1]), .cout(carry[2]));
full_adder fa2(.a(a[2]), .b(b[2]), .cin(carry[2]),
.sum(sum[2]), .cout(carry[3]));
full_adder fa3(.a(a[3]), .b(b[3]), .cin(carry[3]),
.sum(sum[3]), .cout(cout));
endmodule
Q36. What are the common pitfalls in combinational logic design?
Common mistakes:
1. Incomplete sensitivity list: Missing signals in always @()
2. Latches: Not assigning outputs in all paths
3. Combinational loops: Output feeding back to input
4. Using non-blocking assignments: Should use blocking (=)
5. Missing default case: In case statements
// WRONG: Incomplete sensitivity - missing 'b'
always @(a) begin
out = a & b; // 'b' missing from sensitivity
end
// CORRECT: Use @(*)
always @(*) begin
out = a & b;
end
// WRONG: Creates latch (out not assigned when enable=0)
always @(*) begin
if (enable)
out = data;
end
// CORRECT: Assign in all paths
always @(*) begin
if (enable)
out = data;
else
out = 1'b0; // or previous value if latch intended
end
// WRONG: Missing default creates latch
always @(*) begin
case(sel)
2'b00: out = a;
2'b01: out = b;
// Missing 2'b10 and 2'b11
endcase
end
// CORRECT: Include default
always @(*) begin
case(sel)
2'b00: out = a;
2'b01: out = b;
2'b10: out = c;
default: out = d;
endcase
end
5. Sequential Logic Design
Q37. How do you design sequential logic in Verilog?
Sequential logic requires storage elements (flip-flops) and uses:
1. always @(posedge clk) or @(negedge clk)
2. Non-blocking assignments (<=)
3. Clock and optional reset signals Key characteristics:
• Output depends on current inputs AND previous state
• Requires clock signal
• Uses flip-flops or latches for storage
// D Flip-Flop
always @(posedge clk) begin
q <= d;
end
// D Flip-Flop with asynchronous reset
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
q <= 1'b0;
else
q <= d;
end
// D Flip-Flop with synchronous reset
always @(posedge clk) begin
if (rst)
q <= 1'b0;
else
q <= d;
end
Q38. What is the difference between synchronous and asynchronous reset?
Asynchronous Reset:
• Resets immediately when reset signal is asserted • Independent of clock
• Reset in sensitivity list • Faster reset response • May cause metastability issues
Synchronous Reset:
• Resets only on clock edge • Reset checked inside always block • Not in sensitivity list • Safer for
timing closure • Recommended for modern designs
// Asynchronous reset (active low)
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
counter <= 8'b0; // Reset immediately
else
counter <= counter + 1;
end
// Synchronous reset (active high)
always @(posedge clk) begin
if (rst)
counter <= 8'b0; // Reset on clock edge
else
counter <= counter + 1;
end
// Asynchronous reset, synchronous release
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
q <= 1'b0;
else if (enable)
q <= d;
end
Q39. Design a 4-bit counter in Verilog.
Counters can be implemented with various features: up/down, enable, load, etc.
// Simple up counter
module counter_4bit (
input clk,
input rst_n,
output reg [3:0] count
);
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
count <= 4'b0;
else
count <= count + 1;
end
endmodule
// Up/Down counter with enable and load
module counter_4bit_advanced (
input clk,
input rst_n,
input enable,
input load,
input up_down, // 1=up, 0=down
input [3:0] data_in,
output reg [3:0] count
);
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
count <= 4'b0;
else if (load)
count <= data_in;
else if (enable) begin
if (up_down)
count <= count + 1;
else
count <= count - 1;
end
end
endmodule
Q40. Design a shift register (SISO, SIPO, PISO, PIPO).
Shift registers move data serially or in parallel.
// Serial In Serial Out (SISO)
module siso_shift_reg (
input clk, rst_n,
input serial_in,
output serial_out
);
reg [7:0] shift_reg;
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
shift_reg <= 8'b0;
else
shift_reg <= {shift_reg[6:0], serial_in};
end
assign serial_out = shift_reg[7];
endmodule
// Serial In Parallel Out (SIPO)
module sipo_shift_reg (
input clk, rst_n,
input serial_in,
output [7:0] parallel_out
);
reg [7:0] shift_reg;
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
shift_reg <= 8'b0;
else
shift_reg <= {shift_reg[6:0], serial_in};
end
assign parallel_out = shift_reg;
endmodule
// Parallel In Serial Out (PISO)
module piso_shift_reg (
input clk, rst_n,
input load,
input [7:0] parallel_in,
output serial_out
);
reg [7:0] shift_reg;
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
shift_reg <= 8'b0;
else if (load)
shift_reg <= parallel_in;
else
shift_reg <= {shift_reg[6:0], 1'b0};
end
assign serial_out = shift_reg[7];
endmodule
// Universal Shift Register (bi-directional)
module universal_shift_reg (
input clk, rst_n,
input [1:0] mode, // 00:hold, 01:right, 10:left, 11:load
input serial_in_left,
input serial_in_right,
input [7:0] parallel_in,
output reg [7:0] parallel_out
);
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
parallel_out <= 8'b0;
else
case(mode)
2'b00: parallel_out <= parallel_out; // Hold
2'b01: parallel_out <= {serial_in_right, parallel_out[7:1]}; // Right
2'b10: parallel_out <= {parallel_out[6:0], serial_in_left}; // Left
2'b11: parallel_out <= parallel_in; // Load
endcase
end
endmodule
Q41. Design a T flip-flop and JK flip-flop in Verilog.
T and JK flip-flops are variants of D flip-flops with specific behavior.
// T Flip-Flop (Toggle)
module t_flip_flop (
input clk, rst_n,
input t,
output reg q
);
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
q <= 1'b0;
else if (t)
q <= ~q; // Toggle when t=1
end
endmodule
// JK Flip-Flop
module jk_flip_flop (
input clk, rst_n,
input j, k,
output reg q
);
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
q <= 1'b0;
else
case({j,k})
2'b00: q <= q; // Hold
2'b01: q <= 1'b0; // Reset
2'b10: q <= 1'b1; // Set
2'b11: q <= ~q; // Toggle
endcase
end
endmodule
6. Finite State Machine Design
Q42. What is a Finite State Machine (FSM)?
An FSM is a sequential circuit that transitions between states based on inputs and current state.
Types:
1. Mealy Machine: Output depends on current state and inputs
2. Moore Machine: Output depends only on current state
Components: • State register (sequential logic) • Next state logic (combinational logic) •
Output logic (combinational logic)
// FSM States
typedef enum logic [1:0] {
IDLE = 2'b00,
START = 2'b01,
RUN = 2'b10,
DONE = 2'b11
} state_t;
Q43. Design a Mealy FSM for sequence detector (1011).
Mealy machine output depends on both state and input.
module mealy_sequence_detector (
input clk, rst_n,
input din,
output reg detected
);
typedef enum logic [2:0] {
S0, S1, S10, S101
} state_t;
state_t current_state, next_state;
// State register
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
current_state <= S0;
else
current_state <= next_state;
end
// Next state logic
always @(*) begin
next_state = current_state;
case(current_state)
S0: next_state = din ? S1 : S0;
S1: next_state = din ? S1 : S10;
S10: next_state = din ? S101 : S0;
S101: next_state = din ? S1 : S10;
endcase
end
// Output logic (Mealy - depends on state and input)
always @(*) begin
detected = (current_state == S101) && (din == 1);
end
endmodule
Q44. Design a Moore FSM for sequence detector (1011).
Moore machine output depends only on current state.
module moore_sequence_detector (
input clk, rst_n,
input din,
output reg detected
);
typedef enum logic [2:0] {
S0, S1, S10, S101, S1011
} state_t;
state_t current_state, next_state;
// State register
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
current_state <= S0;
else
current_state <= next_state;
end
// Next state logic
always @(*) begin
next_state = S0;
case(current_state)
S0: next_state = din ? S1 : S0;
S1: next_state = din ? S1 : S10;
S10: next_state = din ? S101 : S0;
S101: next_state = din ? S1011 : S10;
S1011: next_state = din ? S1 : S10;
endcase
end
// Output logic (Moore - depends only on state)
always @(*) begin
detected = (current_state == S1011);
end
endmodule
Q45. What are the FSM coding styles?
Three common FSM coding styles:
1. One Always Block: Everything in one block (not recommended)
2. Two Always Blocks: - One for state register - One combined for next state and output logic
[Link] Always Blocks (Recommended): - State register (sequential) - Next state logic
(combinational) - Output logic (combinational)
// Three always block style (RECOMMENDED)
module fsm_three_block (
input clk, rst_n, input_signal,
output reg output_signal
);
typedef enum {IDLE, ACTIVE, DONE} state_t;
state_t current_state, next_state;
// 1. State register (sequential)
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
current_state <= IDLE;
else
current_state <= next_state;
end
// 2. Next state logic (combinational)
always @(*) begin
next_state = current_state;
case(current_state)
IDLE: if (input_signal) next_state = ACTIVE;
ACTIVE: next_state = DONE;
DONE: next_state = IDLE;
endcase
end
// 3. Output logic (combinational)
always @(*) begin
output_signal = (current_state == DONE);
end
endmodule
7. Blocking vs Non-Blocking Assignments
Q46. What is the key difference between blocking and non-blocking assignments?
Blocking (=):
• Executes sequentially
• Blocks next statement until current completes
• Order matters
• Use for combinational logic
• Can create race conditions in sequential logic
Non-Blocking (<=):
• Executes concurrently
• All RHS evaluated first, then assigned
• Order doesn't matter for concurrent assignments
• Use for sequential logic
• Avoids race conditions
// Blocking - Sequential execution
always @(*) begin
temp = a & b; // Executes first
out = temp | c; // Uses updated temp
end
// Non-blocking - Concurrent execution
always @(posedge clk) begin
q1 <= d; // Both RHS evaluated
q2 <= q1; // simultaneously
end // Then both assigned (creates shift register)
Q47. What happens if you mix blocking and non-blocking?
Mixing can cause:
• Simulation/synthesis mismatch
• Race conditions
• Unpredictable behavior
Golden Rule:
• Use = (blocking) for combinational logic in always @(*)
• Use <= (non-blocking) for sequential logic in always @(posedge clk)
• Never mix in same always block
// BAD - Mixed assignments
always @(posedge clk) begin
temp = a & b; // Blocking
q <= temp | c; // Non-blocking
end // Can cause issues!
// GOOD - Consistent assignments
always @(posedge clk) begin
temp <= a & b;
q <= temp | c;
end
Q48. Explain with example: Why non-blocking for sequential logic?
Non-blocking assignments correctly model hardware registers updating simultaneously.
// Using blocking (WRONG for shift register)
always @(posedge clk) begin
q1 = d; // q1 gets d
q2 = q1; // q2 gets new q1 value (same as d!)
q3 = q2; // q3 gets same value as q2,q1,d
end
// Result: All registers get same value!
// Using non-blocking (CORRECT for shift register)
always @(posedge clk) begin
q1 <= d; // q1 will get d
q2 <= q1; // q2 will get old q1
q3 <= q2; // q3 will get old q2
end
// Result: Proper shift register operation
8. Tasks and Functions
Q49. What is the difference between task and function?
Task:
• Can have delays (#, @, wait)
• Can have zero or more outputs
• Can call other tasks and functions
• Can have input, output, inout arguments
• Not synthesizable if contains delays
Function:
• Cannot have delays
• Must have exactly one return value
• Can call other functions only
• Can have only input arguments
• Must execute in zero simulation time
• Always synthesizable
// Task example
task automatic byte_swap;
input [7:0] data_in;
output [7:0] data_out;
begin
#5 data_out = {data_in[3:0], data_in[7:4]};
end
endtask
// Function example
function [7:0] byte_swap_func;
input [7:0] data_in;
begin
byte_swap_func = {data_in[3:0], data_in[7:4]};
end
endfunction
// Usage
always @(posedge clk) begin
byte_swap(input_data, output_data); // Task call
result = byte_swap_func(input_data); // Function call
end
Q50. When to use automatic keyword with task/function?
static (default):
• Single copy of variables
• Shared across all calls
• Can cause issues with recursion and concurrent calls
automatic:
• New copy of variables for each call
• Supports recursion
• Safe for concurrent calls
• Uses stack memory
// Static function (default)
function [31:0] factorial;
input [31:0] n;
integer i;
begin
factorial = 1;
for (i = 2; i <= n; i = i + 1)
factorial = factorial * i;
end
endfunction
// Automatic function (supports recursion)
function automatic [31:0] factorial_recursive;
input [31:0] n;
begin
if (n <= 1)
factorial_recursive = 1;
else
factorial_recursive = n * factorial_recursive(n-1);
end
endfunction