0% found this document useful (0 votes)
7 views32 pages

Verilog HDL: A Comprehensive Guide

The document provides a comprehensive overview of Verilog, a Hardware Description Language (HDL) used for modeling and designing digital electronic systems. It covers key concepts such as data types, operators, procedural blocks, combinational and sequential logic, and module instantiation. Additionally, it highlights differences between Verilog and VHDL, as well as various programming constructs and their applications in digital design.

Uploaded by

avnjp80
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
7 views32 pages

Verilog HDL: A Comprehensive Guide

The document provides a comprehensive overview of Verilog, a Hardware Description Language (HDL) used for modeling and designing digital electronic systems. It covers key concepts such as data types, operators, procedural blocks, combinational and sequential logic, and module instantiation. Additionally, it highlights differences between Verilog and VHDL, as well as various programming constructs and their applications in digital design.

Uploaded by

avnjp80
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

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

Common questions

Powered by AI

Verilog supports multiple number formats which impact digital design by allowing flexible representation of values: binary ('b or 'B), octal ('o or 'O), decimal ('d or 'D), and hexadecimal ('h or 'H). These representations can be specified with size and base, allowing designers to define exact bit-width requirements for variables, which is crucial in ensuring correct interpretation and processing in digital circuits. Special values like x (unknown) and z (high impedance) help in modeling indeterminate states and floating wires, essential for certain simulation scenarios and behavioral modeling . Understanding these representations aids in accurate and efficient design abstraction and conversion during synthesis.

Blocking assignments in Verilog (using =) are sequential; they execute one after another, meaning each statement blocks the execution of the following statements until it completes. This is typically used in combinational logic . Non-blocking assignments (using <=) are designed for use in sequential logic, where all right-hand side evaluations occur before assignments take place, thereby preventing the same race conditions that can occur with blocking assignments in sequential circuits . Non-blocking assignments help maintain expected behavior in clocked processes by ensuring that all sequential logic updates according to the global time step rather than the order of execution, thus avoiding race conditions.

Verilog and VHDL differ primarily in their syntax and typing systems, which affects their usability and popularity. Verilog uses C-like syntax that is easier to learn and is case-sensitive, making it more concise and popular in the US and Asia, particularly in commercial ASIC and FPGA design applications . VHDL uses Pascal/Ada-like syntax, is case-insensitive, and is strongly typed, making it more verbose but robust, often favored in Europe and for defense applications due to its extensive typing and reliability features . These differences affect their use by aligning each language with particular design philosophies and regional preferences, with Verilog being preferred for faster prototyping and VHDL for projects requiring high reliability and error checking.

Synthesis and optimization techniques in Verilog play a critical role in enhancing digital circuit efficiency by translating high-level behavioral and RTL code into gate-level representations that are area, power, and speed optimized for target hardware. These processes involve the removal of redundant logic, minimization of logic expressions, and selection of optimal data paths and components (e.g., adders, multipliers), aiming to meet spatial and temporal constraints . Efficient synthesis and optimization lead to significant improvements in the performance and resource utilization of the final design, making it adaptable to different application requirements and constraints.

A Mealy FSM outputs depend on both the current state and the input signals, which allows for more immediate and potentially complex output behavior based on the latest inputs. This can lead to quicker responses to input changes . In contrast, a Moore FSM outputs depend solely on the current state, ensuring that output changes occur only on state transitions, simplifying the design but potentially resulting in delayed outputs since changes are contingent on state transitions only . This fundamental difference affects the complexity and timing of outputs in FSM designs.

Synchronous resets require the reset condition to be evaluated at the clock edge, allowing better control over when the reset occurs within the clock cycle which is safer for timing closure in modern design practices . However, they might delay the reset action until a clock edge arrives. Asynchronous resets trigger immediately when the reset condition is true, regardless of the clock, allowing faster resetting which is crucial for certain safety-critical applications . The downside is they can introduce metastability if not properly handled across asynchronous boundaries or if the reset release is not synchronized with the clock. The choice between them impacts both design complexity and robustness.

The `timescale directive in Verilog defines the time unit and precision of simulation, crucial for ensuring that all time delays and time-related statements are correctly interpreted in terms of real-time simulation conditions . It affects how simulations process time-based functions and delays. A common pitfall is setting an inappropriate timescale that leads to mismatched timing during simulation and actual operation, potentially causing incorrect validation of design behavior . Correctly configuring timescale is essential to ensure that the design performs as expected in both simulation and real-world applications, avoiding these mismatches.

Parameterization in Verilog allows designers to create generic modules by defining parameters that can be customized at instantiation. This increases the design's scalability by allowing a single module definition to be reused across various configurations without modifying the code manually . Designers can specify different bit widths, component sizes, and functional variations by altering parameters, thereby enabling the creation of more adaptable and efficient digital systems crafted to specific application needs while reducing code redundancy and enhancing maintainability. It supports systematic design and testing across multiple design configurations, acting as a critical feature in modern digital design workflows.

Tasks and functions in Verilog provide a mechanism to improve code reusability and modularity by encapsulating common functionalities and operations that can be invoked throughout the design. Functions return a single value and are used for combinational operations, ideal for arithmetic and logic calculations. Tasks can perform more complex operations involving multiple outputs and can execute sequential statements including delays . By using tasks and functions, designers can write cleaner, more modular code that is easier to maintain and extend, enhancing the scalability and efficiency of digital design projects by reusing code across different modules and projects.

The three always block coding style is recommended for FSM design in Verilog because it separates the FSM into clear functional parts: the state register, next state logic, and output logic, improving readability and maintainability. The state register block handles state storage updates sequentially, the next state logic block deals with purely combinational logic for state transitions, and the output logic block deals with output based solely on the current state . This separation ensures a modular design that enhances both simulation accuracy and synthesis results, making it easier to understand and debug individual FSM components, ensuring fewer errors during simulation and execution.

You might also like