[go: up one dir, main page]

0% found this document useful (0 votes)
10 views61 pages

Verilog Intro

The document outlines the top-down design approach in Verilog, detailing the structure of modules, including their interfaces and bodies. It covers various techniques for implementing combinational circuits like NAND gates and multiplexers using both continuous and procedural assignments, as well as the use of bitwise and relational operators. Additionally, it discusses sequential circuits, specifically D flip-flops, with examples demonstrating their behavior under different conditions such as asynchronous resets and presets.

Uploaded by

Lokesh Sanepalli
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)
10 views61 pages

Verilog Intro

The document outlines the top-down design approach in Verilog, detailing the structure of modules, including their interfaces and bodies. It covers various techniques for implementing combinational circuits like NAND gates and multiplexers using both continuous and procedural assignments, as well as the use of bitwise and relational operators. Additionally, it discusses sequential circuits, specifically D flip-flops, with examples demonstrating their behavior under different conditions such as asynchronous resets and presets.

Uploaded by

Lokesh Sanepalli
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
You are on page 1/ 61

Top-Down Design Approach

Definition of Module

◼ Interface: port and


parameter declaration
◼ Body: Internal part of
module
◼ Add-ons (optional)
Representing signed numbers in 2’s complement format
Representing fixed point fractional numbers
Some points to remember

◼ The name of Module

◼ Comments in Verilog
❑ One line comment (// ………….)
❑ Block Comment (/*…………….*/)

◼ Description of Module (optional but


suggested)
The Module Interface

◼ Port List

◼ Port Declaration
Two-input NAND gate based on assign keyword

module example1(c,a,b);
input a, b;
output c;

// Functionality a
c
assign c = ~(a & b); b

endmodule

The “assign” technique is called a “continuous assignment.”

If there are several continuous assignments, the order does not matter, they are executed
concurrently.
Example: assign c=~(a&b);
assign d=a^b;
The code has to be modified accordingly adding the signal “d” as an output.
Signals a, b, c are wires by default, but we do not have to declare them in this example.

Note: The code must be written to a file, typically with a “.v” extension. Use the same name for the
file and the module to avoid confusion.
Two-Input NAND gate based on the always keyword

module example2 (a,b,c);


// Port modes
input a,b;
output c;
// Registered identifiers a
reg c; c
Sensitivity list b
// Functionality
always @ (a or b)
c = ~(a & b);
endmodule

• All inputs used in the procedure must appear in the sensitivity list (event/trigger list).
• The “always” keyword means that the circuit always (continuously) watches the signals in the
input list ( the @ (a or b) part) and responds to changes in those signals by immediately
updating the output. This is procedural assignment.
• Combinational circuit outputs must also be declared as registered identifiers when the “always”
method (“procedural assignment”) is used. In Verilog code reg variables can be used to model
either combinational or sequential parts of the circuit.
• The ‘=‘ blocking assignment was used in this example (inside the always block).
• Verilog compiler evaluates the statements in an always block in the order in which they are
written i.e. in sequential order. If a variable is given a value by a blocking assignment, then this
new value is used in evaluating all subsequent statements in the block .
Two-input NAND gate based on assign keyword

module example1(c,a,b);

input a, b;
output c;

// Functionality a
c
assign c = ~(a & b); b

endmodule

The “assign” technique is called a “continuous assignment.”

If there are several continuous assignments, the order does not matter, they are executed
concurrently.
Example: assign c=~(a&b);
assign d=a^b;
The code has to be modified accordingly adding the signal “d” as an output.
Signals a, b, c are wires by default, but we do not have to declare them in this example.

Note: The code must be written to a file, typically with a “.v” extension. Use the same name for the
file and the module to avoid confusion.
Two-Input NAND gate based on the always keyword

module example2 (a,b,c);


// Port modes
input a,b;
output c;
// Registered identifiers a
reg c; c
Sensitivity list b
// Functionality
always @ (a or b)
c = ~(a & b);
endmodule

• All inputs used in the procedure must appear in the sensitivity list (event/trigger list).
• The “always” keyword means that the circuit always (continuously) watches the signals in the
input list ( the @ (a or b) part) and responds to changes in those signals by immediately
updating the output. This is procedural assignment.
• Combinational circuit outputs must also be declared as registered identifiers when the “always”
method (“procedural assignment”) is used. In Verilog code reg variables can be used to model
either combinational or sequential parts of the circuit.
• The ‘=‘ blocking assignment was used in this example (inside the always block).
• Verilog compiler evaluates the statements in an always block in the order in which they are
written i.e. in sequential order. If a variable is given a value by a blocking assignment, then this
new value is used in evaluating all subsequent statements in the block .
Two-input NAND and Exclusive OR using non-blocking assignments

module example3(a,b,c,d);
// Port modes
input a, b;
output c; a
c
output d;
b
// Registered identifiers
reg c,d;
d
// Functionality
always @ (a or b)
begin
c <= ~(a & b);
d <= a ^ b;
end
endmodule

• Enclose multiple output signal assignments inside a “begin” - “end” block;


• The “<= “ non-blocking assignment was used in this example.
• Inside an always block, non-blocking and blocking assignments cannot be mixed.
• All non-blocking assignments are evaluated using the values that the variables have when the always
block is entered. Thus a given variable has the same value for all the statements in the block. The
meaning of non-blocking is that the result of each assignment is not seen until the end of an always
block. All non-blocking assignments are evaluated in parallel.
Example :
always @(a or b or c)
b<= a
if (b) // “b” will be the old “b”
• When there are multiple assignments to the same variable inside an always block, the result of the last
assignment is maintained.
• Blocking assignments are recommended for combinational circuits.
Two-input MUX
module Mux2 (A, B, Sel, Y);
input A, B, Sel; B
output Y;
reg Y; SEL
Y

// Functionality
always @ (A or B or Sel) A
if (Sel==0)
Y = A;
else
Y = B;
endmodule

• Use “if-else” to connect output “Y” to one of the two data inputs based on the value of the data
selector “Sel”.
• The expression inside the parentheses after “if” must evaluate to either “1” (true) or “0” (false).
Conditional Operator
◼ Verilog supports the ?: conditional operator
❑ Just like in C
❑ But much more common in Verilog

◼ Examples:
assign out = S ? B : A;

assign out = sel == 2'b00 ? a :


sel == 2'b01 ? b :
sel == 2'b10 ? c :
sel == 2'b11 ? d : 1'b0;

❑ What do these do?

17
2-to-1 MUX: an alternate method

module Mux2(A, B, Sel,Y);


// Port modes
input A, B, Sel;
output Y;
// Registered identifiers
reg Y;
//Functionality
always @ (A or B or Sel)
Y = (Sel) ? B : A;

endmodule

Here the conditional (ternary) operator is used. Read the statement like this: “Is
the control signal ‘Sel’ equal to 1? If yes, Y is assigned the value B else A.”
4-to-1 Multiplexor
module Mux4 (Data, Sel, Y);

//Port modes
input [3:0] Data;
input [1:0] Sel;
output Y; EN
reg Y;
S[1:0] S1
S0
always @ (Data or Sel)
if (Sel ==2’b00) D3
Y
Y = Data[0]; D2
Data[3:0] Q
else if (Sel ==2’b01) D1
Y = Data[1]; D0
else if (Sel == 2’b10)
Y = Data[2];
else if (Sel == 2’b11)
Y = Data[3];

endmodule

• “if-else-if” is used.
• A four-bit bus (vector). The square brackets define the bus width. The left-side number is the
MSB. A two-bit bus is used for the data selector.
• 2’b1 => implies a 2-bit value specified in binary form. Here, it is the binary value 01. The value
is zero-extended.
Four-Input MUX: an alternate method
module Mux4 (Data, Sel, Y);
//Port modes
input [3:0] Data;
input [1:0] Sel;
output Y;
reg Y;

always @ (Data or Sel)


case (Sel)
0: Y = Data[0];
1: Y = Data[1];
2: Y = Data[2];
2’b11: Y = Data[3];
default: Y =1’bx;
endcase
endmodule

• “case” is used. The controlling expression (Sel) and each alternative (0,1,2,3) are compared
bit by bit. The first successful match causes the associated statements to be evaluated.
• When the specified alternatives do not cover all possible valuations of the controlling
expression (Sel), the default clause (optional) is used.
• “default” keyword is a catch-all – if a match is not found, the default assignment is made.
• If possible, use don’t-care as the default output to reduce hardware.
4-to1 MUX
module Mux16 (Data, Sel, Y);
parameter DataWidth = 16;

input [DataWidth-1:0] Data;


input [3:0] Sel;
output Y;
reg Y;
// Functionality
always @ (Data or Sel)
case (Sel)
4’b0000: Y = Data[0];
4’b0001: Y = Data[1];
4’b01??: Y = Data[2];
default: Y = Data[3];
endcase
endmodule
• The question mark is a “don’t care” when it appears inside a numerical constant. In this example,
the case selection ignores the two lowest bits and looks for a match on the two highest bits. You
need to use the ‘casez’ version of the ‘case’ statement when using “don’t cares”. All other values
of the “Sel” control signal cause the fourth data bit to be selected. Data bits 15 through 4 are
effectively not used in this example.
• “parameter” can be used to define any constants.
Hierarchical Verilog Example
◼ Build up more complex modules using simpler
modules
◼ Example: 4-bit wide mux from four 1-bit muxes
❑ Again, just “drawing” boxes and wires
module mux2to1_4(
input [3:0] A,
input [3:0] B,
input Sel,
output [3:0] O );

mux2to1 mux0 (Sel, A[0], B[0], O[0]);


mux2to1 mux1 (Sel, A[1], B[1], O[1]);
mux2to1 mux2 (Sel, A[2], B[2], O[2]);
mux2to1 mux3 (Sel, A[3], B[3], O[3]);
endmodule
Bitwise operators Relational Operators:
== Equal to
~ NOT != Not equal
& AND < Less than
| OR > Greater than
^ EXOR <= Less than or equal
>= Greater than or equal
More Operators: && AND
>> Shift right || OR
<< Shift left
+ Add
- Subtract
* Multiply
/ Divide
% Modulus
Sequential circuits
D flip-flop, positive-edge triggered

module D_FF (D, Clock, Q);


input D, Clock;
output Q;
// Registered identifiers 1 D
reg Q; 0
Q
// Functionality D Q
20,20
always @ (posedge Clock) CLK
Q <= D; C

endmodule

▪ The sensitivity list contains only the signal that is responsible for triggering the flip flop, i.e., the
‘Clock’ signal; It is possible to specify that the response should take place only at a particular edge
of the signal, using the keywords “posedge” and “negedge”.
▪ The keyword “….edge” specifies that a change may occur only on the edge of the Clock. At this time
the output Q is set to the value of input D. Since Q is reg type it will maintain the value between the
edges of the clock.
▪ Other inputs such as ‘D’ may be used inside the ‘always’ block, but they must not appear in the
sensitivity list.
▪ Use non-blocking assignments to describe sequential circuits.
D flip-flop, positive-edge triggered, with Q_bar

module D_FF (D, Clock, Q);


input D, Clock;
output Q;
// Registered identifiers
reg Q;
wire Q_bar;

assign Q_bar = ~Q;


always @ (posedge Clock)
Q <= D;
endmodule
• In this example the ‘assign’ statement is used.
• The ‘always’ block implements most of the desired behavior, namely, a single-bit storage device with
appropriate behavior and clocking.
• The ‘assign’ statement simply copies the Q signal to an additional output while performing the
necessary inversion along the way.
• A variable on the left side of the equal sign must not be in the trigger list or the machine may go into
an infinite loop.
always@(state or A or B or C….)
begin
A<=B+C; //A will immediately retrigger the always procedure
D flip-flop, positive-edge triggered, with inverted and non-inverted outputs,
and asynchronous reset (active high)

module D_FF (D,Clock,Q,Q_bar,Reset);


input D,Clock,Reset;
output Q, Q_bar;
reg Q;
always @ (posedge Clock or posedge Reset)
if (Reset == 1)
Q <= 0;
else
Q <= D;
assign Q_bar = ~Q;
endmodule
• “Asynchronous Reset” means that asserting the reset will instantly set the Q output to zero,
regardless of the activity of D or Clock. Q will remain zero as long as Reset is asserted.
• The ‘always’ block needs to be “triggered” either by the Clock or the Reset, so the Reset signal is
added to the sensitivity list. Note that the sensitivity list specifies the posedge or negedge of reset as
an event trigger along with the positive edge of the clock.
• We cannot omit the keyword “....edge” because the sensitivity list cannot have both edge triggered
and level sensitivity signals
D flip-flop, positive-edge triggered, and asynchronous preset,
active low
module D_FF (D,Clock,Q,_Preset);
// Port modes
input D, Clock, _Preset;
output Q;
// Registered identifiers
reg Q;
// Functionality
always @ (posedge Clock or negedge _Preset)
if (_Preset == 0)
Q <= 1;
else
Q <= D;
endmodule

“Asynchronous preset” behaves similar to “reset”, except that the Q output is set to 1 instead of 0.

Avoid the temptation to design arbitrary flip-flop behavior, e.g., ability to trigger on both edges of the
same clock, ability to trigger on multiple clock signals, etc. The hardware synthesis tool does not
“magically” create new hardware from thin air! You have to write circuit descriptions that are physically
possible, that is, can be mapped onto existing (known) hardware elements such as standard D flip-
flops.
D flip-flop, positive-edge triggered, with synchronous reset (active low)

module D_FF (D,Clock,Q,Reset);


/* Port modes */
input D,Clock,Reset;
output Q;
// Registered identifiers
reg Q;

// Functionality
always @ (posedge Clock)
if (Reset==1)
Q <=0;
else
Q<= D;
endmodule

“Synchronous reset” means that the reset action does not occur until the next clock edge. Reset’
does not appear in the input list now, but it appears inside the ‘always’ block.

Another way to write the code:


Q <= (!Reset)? 0 : D;
Finite State Machine

A Finite State Machine is described by:


⚫ Its states and a description of their physical meaning.
⚫ The way the machine makes the transitions to the next state.
These must be based on the present state and/or the present
inputs only. The state is the collective contents of all Flip-flops; The
state memory is a set of n flip-flops that store the current state of
the machine, and it has 2n distinct states.
⚫ The outputs from each state.

Mealy versus Moore FSM


Moore outputs depend only on the state of the machine. Moore
machines are easier to design.
Mealy outputs depend on the present state and the inputs. Mealy
machines usually have fewer states and thus are often smaller.
Standard form for FSM in VERILOG

Break FSMs into four blocks:


State definitions-Next state calculations (decoder)-Registers or flip-flops calculation-Output
calculations (logic)

//state flip-flops
reg [2:0] state, next_state;

//state definitions
parameter S0=2’b00 S1=2’b 01, S2=2’b 10, S3=2’b11,…
// State machine descriptions
//Next state calculations
always @(state or….)
begin
case (state)
…..
end
//register or flip-flop calculation
always@(posedge clk)
state<=next_state
//Output calculations
Output=f(state, inputs)
FSM of a Mealy machine
Module FSM (clk, x, z);
input clk, x;
output z;
//state flip-flops
reg[2:0] state, next_state;
// State definition
parameter S0=0, S1=1, S2=2, S3=3, S4=4;
//State machine description using case
always@ (state or x)
begin
case(state)
S0: if (x) next_state=S1;
else next_state=S0; Present Next state Output
S1: if (x) next_state=S3; state X=0 X=1 z
else next_state=S2;
S2: if (x) next_state=S0; S0=000 S0=0 S1=1 0
else next_state=S4;
S3: if (x) next_state=S2; S1=001 S2=2 S3=3 0
else next_state=S4;
S4: next_state=S0;
default: next_state=S0; S2=010 S4=4 S2=2 0
endcase
end S3=011 S4=4 S0=0 0
//flip-flops calculations
always @ (posedge clk) S4=100 S0=0 S0=0 1
begin
state<=next_state;
end Default S0=0 S0=0 0
//output calculations
assign z=(state==S4);
endmodule
One language, Many Coding Style
One language, Many Coding Style (contd.)
One language, Many Coding Style (contd.)
Structural vs Behavioral HDL Constructs

◼ Structural constructs specify actual hardware structures


❑ Low-level, direct correspondence to hardware
◼ Primitive gates (e.g., and, or, not)
◼ Hierarchical structures via modules
❑ Analogous to programming software in assembly
◼ Behavioral constructs specify an operation on bits
❑ High-level, more abstract
◼ Specified via equations, e.g., out = (a & b) | c
◼ Not all behavioral constructs are synthesizable
❑ We’ve already talked about the pitfalls of trying to “program”

39
Why an HDL is not a Programming Language

◼ In a program, we start at the beginning (e.g.


“main”), and we proceed sequentially through
the code as directed
◼ The program represents an algorithm, a step-by-
step sequence of actions to solve some problem
for (i = 0; i<10; i=i+1) {
if (newPattern == oldPattern[i]) match = i;
}
◼ Hardware is all active at once; there is no
starting point
Structural style: Verilog Code
Dataflow style: Verilog Code
Behavioral style: Verilog Code
Data Values and Representation

◼ Four Data value

◼ Data representation
Type
❑ Binary 6’b100101
❑ Hex 6’h25
Class of Signals

◼ Nets: physical
connection
between hardware
elements

◼ Registers: Store
value even if
disconnected
Nets

◼ wire/tri
◼ wand/triand
◼ wor/trior
◼ Supply0,supply1,
tri0,tri1,trireg
Specifications of Ports
Registered Output
Delay Statement
Parameter
Test Bench
module main;
reg a, b, c;
wire sum, carry;

fulladder add(a,b,c,sum,carry);
initial
begin
a = 0; b = 0; c = 0;
#5
a = 0; b = 1; c = 0;
#5
a = 1; b = 0; c = 1;
#5
a = 1; b = 1; c = 1;
#5
end
endmodule
Auxiliary Variables

◼ C style variables that are used procedurally


❑ Understood to be “program helpers”, not pieces of hardware
integer i; // signed 32-bit (not int)
time t; // unsigned 64-bit
real r; // double precision FP
❑ memory (i.e., C) like array syntax
integer iarray[63:0]; // array of 64 integers
❑ E.g.,
integer i;
for (i = 0; i < N; i = i + 1)
memory[i] <= 0;
❑ E.g.,
time sim_num_insn; // retired instructions
Memory Operation

reg [31:0] register_file [0:7];


wire [31:0] rf_bus;
wire r2b4;
assign rf_bus = register_file [2];
assign r2b4 = rf_bus[4];
Can’t use register_file[2][4] for assigning value to
variable r2b4
Behavior Modules: Tasks

module memory ();


reg [7:0] memory [1023:0];
integer i;
task clear;
begin
for (i = 0; i < 1024; i = i + 1)
memory[i] <= 8’b0;
end
endtask
endmodule

memory mem();
initial mem.clear;

◼ Tasks: module “methods”


❑ Can be invoked from always and initial blocks
An Example Test Module
`include “mux.v”
module main;
reg [3:0] A, B;
wire [3:0] O;
reg S;

mux2to1_4 mux (S, A, B, O);

initial
begin
$monitor ($time,,“S=%b,A=%d,B=%d,O=%d”, S, A, B,
O);
$dumpvars(1, S, A, B, O);

#5 A=4’b1010; B=4’b0010; S=1’b0;


#5 S=1’b1;
#5 $finish;
end
endmodule

59
A Test Module With Clock
`include “fsm.v”
module main;
reg clk, in;
wire out;

fsm fsm1 (clk, in, out);

always #5 clk <= ~clk;

initial
begin
clk = 0;
$monitor ($time,,“CLK=%b”, clk, fsm1.state);
$dumpvars(1, clk, fsm1.state);
#100 $finish;
end
endmodule

60

You might also like