You are on page 1of 92

Re Configurable Computing

CS G553

Introduction to Verilog
Hardware Description Languages (HDL)
The 'capture language'often beginning with a high-level algorithmic
description.
Resemble concurrent programming languages.
HDL design generally ends at the synthesis stage
HDLs, 'compiler' refers to synthesis, a process of transforming the HDL
code listing into a physically realizable gate netlist
Simulation by a test bench. Even driven.
Two widely used hardware description languages
VHDL
Verilog
HDL languages can describe circuits from two perspectives
function
structure
Verilog introduced by Gateway Design automation in 1985.

Levels of Abstraction
Switch Level: Module implemented with switches and
interconnects. Lowest level of Abstraction
Gate Level: Module implemented in terms of logic gates
and interconnection between gates
Dataflow Level: Module designed by specifying dataflow.
Designer is aware of how data flows between hardware
registers and how the data is processed in the design
Behavioral Level :Module can be implemented in terms of
the desired design algorithm without concern for the
hardware implementation details. Very similar to C
programming.
Module
Basic building block in
Verilog.
A module definition starts
with the keyword
module ends with the
keyword endmodule

module name (port_list)
port declarations
parameter declarations
include directives
variable declarations
assignments
low-level module instantiation
initial and always blocks
task and function
End module
Interface
Optional add-ons
Body
Ex: Module
module toggle(q, clk, reset);

<functionality of module>

endmodule
toggle
q
clk
reset
The internal of each module can be defined at four levels of
abstraction
o Behavioral or algorithmic level
o Dataflow level
o Gate level
o Switch level

Verilog allows different levels of abstraction to be mixed in the same
module.
Number specification
Comments are designated by // to the end of a line or by /* to */
across several lines.
<size><base format><number>
specifies the
number of bits
in the number
d or D for decimal
h or H for hexadecimal
b or B for binary
o or O for octal
Number
depends on
the base
Examples:
4b1111
12habc
16d235
12h13x
-6d3
12b1111_0000_1010
X or x: dont care
Z or z: high impedence
_ : used for readability
Net
Represents connections between
hardware elements.
Continuously driven by output of
connected devices.
Declared using the keyword
wire.
wire a;//Declare net a for above ckt
wire b, c;//Declare two wires b,c
wire d=1b0;
Ex: Net declaration
M
e
m
o
r
y

P
r
o
c
e
s
s
o
r

r_w
data
addr

wire r_w; // scalar signal
wire [7:0] data; // vector signal
wire [9:0] addr; // vector signal

Port
Provide interface by
which a module can
communicate with
its environment

module fulladd4(sum, c_out, a, b, c_in); //Module with a list of ports
module Top; // No list of ports, top-level module in simulation
Verilog
keyword
Type of
port
input Input port
output Output port
inout Bi-
directional
Ex: Port
module DFF(q, d, clk, reset);
output q;
reg q;
input d, clk, reset;
...
...
endmodule
Port connection rules
Internally, input ports must
always be of the type net.
Externally, the inputs can be
connected to a variable which is a
reg or a net.
Internally, outputs ports can be
of the type reg or net.
Externally, outputs must always
be connected to a net.
Internally, inout ports must
always be of the type net.
Externally, inout ports must
always be connected to a net.
Legal to connect internal and
external items of different sizes
when making intermodule port
connections.
Allows ports to remain
unconnected
Nets vs Ports
M
e
m
o
r
y

P
r
o
c
e
s
s
o
r

r_w
data[7:0]
addr[9:0]
clk
rst
status[3:0]
i_o[7:0]
pc
module pc (clk, rst, status, i_o);
input clk, rst;
output [3:0] status;
inout [7:0] i_o;
wire r_w;
wire [7:0] data;
wire [9:0] addr;

endmodule
Nets are internal signals that cannot be accessed by outside
environment
Ports are external signals to interface with outside environment
input ports can be read but cannot be written
output ports can be written but cannot be read
inout ports can be read and written

Register
Registers represent data storage elements.
They retain value until another value is placed
onto them.
In Verilog, a register is merely a variable that can
hold a value.
They do not need a clock as hardware registers
do.

reg reset;
initial
begin
reset = 1b1;
#100 reset=1b0;
end
Register declaration
module pc (clk, rst, status, i_o);
input clk, rst;
output [3:0] status;
reg [3:0] status;
inout [7:0] i_o;

A register declaration starts with keyword reg.
Registers can be used to describe the behaviour of
sequential circuits
Registers can also be used to implement registered
output ports
Vectors
A net or register can be declared as vectors.
wire a;
wire [7:0] bus;
wire [31:0] busA, busB, busC;
reg clock;
reg [0:40] virt_address;

Possible to address bits or parts of vectors
busA[7]
bus[2:0]
virt_addr[0:2]


Real
real delta;
initial
begin
delta = 4e10;
delta = 2.13;
end
integer i;
initial
i = delta;

declared with the keyword real
cannot have a range declaration
default value is 0
Arrays
Arrays are multiple elements that are 1-bit or n-bits wide.
Possible to have arrays of type reg, integer, real
Arrays of nets can also be used to connect ports of generated
instances
integer count[0:7];
reg [4:0] port_id[0:7]; // Array of 8 port_ids; each port_id is 5 bits wide
integer matrix[4:0][0:255]; // Two dimensional array of integers

Memory
Used to model register files, RAMs and ROMs.
A memory component can be defined using reg variables
Modeled in Verilog as a one-dimensional array of registers.


reg mem1bit[0:1023]; // Memory mem1bit with 1K 1-bit words
reg [7:0] membyte[0:1023]; // Memory membyte with 1K 8-bit words(bytes)
membyte[511] // Fetches 1 byte word whose address is 511.
myMem[0]
myMem[1]
myMem[2]
myMem[3]
reg [7:0] myMem [3:0];
Parameters
Define constants .
Makes code easy to read and modify
Cant be used as variables.

parameter port_id=5;
parameter bussize = 8;
reg [bussize-1 : 0] databus1;
reg [bussize-1 : 0] databus2;
Strings

Strings can be stored in reg.
The width of the register variables must be large enough to hold the
string.
reg [8*19:1] string_value;
initial
string_value = Hello Verilog World;
Modules and ports
module fulladd4(sum, c_out, a, b,
c_in);
output [3:0] sum;
output c_out;
input [3:0] a, b;
input c_in;


endmodule
If the output hold their value,
they must be declared as reg
module DFF(q, d, clk, reset);
output reg q;
input d, clk, reset;


endmodule
All port declarations (input,
output, inout) are implicitly
declared as wire
Module declaration (ANSI C style)
module fulladd4(output reg[3:0] sum,
output reg c_out,
input [3:0] a, b,
input c_in);


endmodule
Module instantiation
module Top;
reg [3:0] A, B;
reg C_IN;//externally, inputs can be a reg or a wire; internally must be wires
wire [3:0] SUM; //externally must be wires
wire C_OUT;
// one way
fulladd4 FA1(SUM, C_OUT, A, B, CIN);
// another possible way
fulladd4 FA2(.c_out(C_OUT), .sum(SUM), .b(B), .c_in(C_IN), .a(A));

endmodule
module fulladd4(sum, c_out, a, b, c_in);
output [3:0] sum;
output c_out;
input [3:0] a, b;
input c_in;


endmodule
Module instantiation..
Port connecting rules
input net or reg
inout net
output net
Module instantiation
Signal assignment follows port list order
Module instantiation..
Signal assignment by port names
The two methods cannot be mixed!
Module instantiation..
Unconnected ports
by port list order
by name
Gate level modeling (structural)
.
wire Z, Z1, OUT, OUT1, OUT2, IN1, IN2;
and a1(OUT1, IN1, IN2);
nand na1(OUT2, IN1, IN2);
xor x1(OUT, OUT1, OUT2);
not (Z, OUT);
buf final (Z1, Z);
.
The circuit is described in terms of gates.
Hardware design at this level is intuitive
All instances are executed concurrently just as in hardware
Instance name is not necessary
The first terminal in the list of terminals is an output and the other
terminals are inputs
Predefined gate primitives
a
b d
c
and (d, a, b, c)
not (a, b, c)
a
b
c
buf (a, b)
a
b
supports basic logic gates as predefined primitives.
instantiated like any other modules.
tri-state gates: bufif1, bufif0, notif1, notif0
notif0 (a, b, c)
e.g.
bufif1 (a, b, c)
e.g.
a
b
c
a
b
c
Predefined gate primitives
Example of structural Verilog code
Example of using predefined gate primitives
Array of gate instances
wire [7:0] OUT, IN1, IN2;

// array of gates instantiations
nand n_gate [7:0] (OUT, IN1, IN2);

// which is equivalent to the following
nand n_gate0 (OUT[0], IN1[0], IN2[0]);
nand n_gate1 (OUT[1], IN1[1], IN2[1]);
nand n_gate2 (OUT[2], IN1[2], IN2[2]);
nand n_gate3 (OUT[3], IN1[3], IN2[3]);
nand n_gate4 (OUT[4], IN1[4], IN2[4]);
nand n_gate5 (OUT[5], IN1[5], IN2[5]);
nand n_gate6 (OUT[6], IN1[6], IN2[6]);
nand n_gate7 (OUT[7], IN1[7], IN2[7]);

User Defined Primitives (UDPs)
custom-built primitives
do not instantiate other
modules or primitives
instantiated exactly like gate-
level primitives
//UDP name and terminal list
primitive <udp_name> (
<output_terminal_name>(only one allowed)
<input_terminal_names> );
//Terminal declarations
output <output_terminal_name>;
input <input_terminal_names>;
reg <output_terminal_name>;(optional; only for
sequential UDP)
// UDP initialization (optional; only for sequential UDP
initial <output_terminal_name> = <value>;
//UDP state table
table
<table entries>
endtable
//End of UDP definition
endprimitive
Combinational UDPs
Example: 2-to-1 multiplexer
Combinational UDPs dont need initialization
The first signal in the port list is always output. However, in the truth table
the output signal value is at the end (after a colon).
Input order in the truth table must follow the order given in the port list.
Output for unspecified combination is always X.
primitive <udp_name> (
<output_terminal_name>
<input_terminal_names> );
output <output_terminal_name>;
input <input_terminal_names>;
table
<table entries>
endtable
endprimitive
Sequential UDPs
Example: D-Latch
Output Q is initialized by initial block.
In the truth table Q is the current state, Q* is the next state.
Symbol indicates the next state is the same as the current state.
primitive <udp_name> (
<output_terminal_name> <input_terminal_names> );
output <output_terminal_name>;
input <input_terminal_names>;
reg <output_terminal_name>;
initial <output_terminal_name> = <value>;
table
<table entries>
endtable
endprimitive
Sequential UDPs
Example: D Flip-Flop
r for rising edge, same as (01)
f for falling edge, same as (10)
p for positive edge, same as (01), (0X), (X1)
n for negative edge, same as (10), (1X), (X0)
* for any change, same as (??)
Using UDPs
Example: 4-bit synchronous counter
Cannot be defined
within modules.
Can be defined after
or before the module in
the same file.
Can be defined
in a separate file
and use include
directive to include
to the code.
Defining UDPs
Dataflow modeling
Module is designed by specifying the data flow.
Designer is aware of how data flows between hardware registers
and how the data is processed in the design
Continuous assignment is one of the main constructs used in
dataflow modeling
assign out = i1 & i2;
assign addr[15:0] = addr1[15:0] ^ addr2[15:0];
assign {c_out, sum[3:0]}=a[3:0]+b[3:0]+c_in;

A continuous assignment is always active and the assignment
expression is evaluated as soon as one of the right-hand-side
variables changes
Left-hand side must be a scalar or vector net.
Right-hand side operands can be registers, nets, integers, real,
Operators in dataflow expressions
Similar to C except that there are no ++ or

Arithmetic: *, /, +, -, % and **
Logical: !, && and ||
Relational: >, <, >= and <=
Equality: ==, !=, === and !==
Bitwise: ~, &, |, ^ and ^~
Reduction: &, ~&, |, ~|, ^ and ^~
Shift: <<, >>, >>> and <<<
Concatenation: { }
Replication: {{}}
Conditional: ?:
Example
module mux4(out, i0, i1, i2, i3, s1, s0);
output out;
input i0, i1, i2, i3;
output s1, s0;

assign out = (~s1 & ~s0 & i0) |
(~s1 & s0 & i1) |
(s1 & ~s0 & i2) |
(s1 & s0 & i3);

// OR THIS WAY
assign out = s1 ? (s0 ? i3:i2) : (s0 ? i1:i0);

endmodule
Example: A 2-to-4 decoder
Circuit schematic
Structural code
Data flow code
Arithmetic operators
Available operators: +, -, *, /, % (modulo)
Arithmetic operators treat register operands as unsigned values
Example:

integer A;
A = -12;
A/4 -3
reg [7:0] A;
A = -12;
A/4 61
Shifter operators
<< : shift left
>> : shift right
reg [3:0] A;
1 1 0 1 A << 2 0 1 0 0
zeros are moved in from the right end
reg [3:0] A;
1 1 0 1 A >> 2 0 0 1 1
Concatenation operators
Example
reg [7:0] A, B, Data;
reg c;

A = 10101101; B= 00110011;
c = 0;
Data = {A[3:0], B[7:6], c, c}; // Data = 11010000
1 1 0 1 0 0 0 0 Data
A[3:0] B[7:6]
c c
Continuous assignment
Example
a
b
c
x
o
AND
OR
module cir1 (o, a, b, c);
output o;
input a, b, c;
wire x;
assign x = a & b;
assign o = x | c;
endmodule
module cir1 (o, a, b, c);
output o;
input a, b, c;
wire x = a & b;
assign o = x | c;
endmodule
OR
Continuous assignment starts with keyword
assign.
The left hand side of a continuous assignment
command must be a net-type signal

Rules:
The left hand side of an assignment must always be a scalar
or vector net
It cannot be a scalar or vector register.
Continuous assignments are always active.
The assignment expression is evaluated as soon as one of
the right-hand-side operands changes and the value is
assigned to the left-hand-side net.
The operands on the right-hand side can be registers or
nets.
Delay values can be specified for assignments in terms of
time units. Delay values are used to control the time when a
net is assigned the evaluated value.


Conditional assignment
A conditional assignment has three signals at the right hand side.
The first signal is the control signal
If the control signal is true, the second signal is assigned to
the left hand side (LHS) signal ; otherwise, the third signal
is assigned to LHS signal.

Adding delay to continuous assignment
`timescale 10ns/1ns // <ref_time_unit>/<time_precision>
module buf1 (o, i);
output o;
input i;
.
assign #3 o = 1; // delay for 3 time units
.
endmodule
Delay is added by # t after keyword assign, t is the number of
delayed time units.
Time unit is defined by `timescale

Example
Delay in procedural assignments
Delay specified in front of procedural assignment statements
(e.g. #3 a = b&c;) delay the execution of the entire statement.
Module delayTest;
integer a, b, c;

initial begin
a = 2; b = 3;
end

initial #3 a = 4;

initial #5 c = a+b;

endmodule
Execution order:
1. delay
2. evaluation
3. assignment
Result: c=7
Change a from 2 to 4
after 3 time unit
Delay in procedural assignments
Delay specified right after = in procedural assignment statements
(e.g. a = #3 b&c;) just delay the assignment operation. The evaluation
of the right hand side expression is executed without delay.
Module delayTest;
integer a, b, c;

initial begin
a = 2; b = 3;
end

initial #3 a = 4;

initial c = #5 a+b;

endmodule
Execution order:
1. evaluation
2. delay
3. assignment
Result: c=5
Change a from 2 to 4
after 3 time unit
Behavioral or algorithmic modeling
Design is expressed in algorithmic level,
which frees designers from thinking in
terms of logic gates or data flow.
Designing at this model is very similar to
programming in C.
All algorithmic statements in Verilog can
appear only inside two statements:
always and initial.
Each always and initial statement
represents a separate activity flow in
Verilog.
Activity flows in Verilog run in parallel.
You can have multiple initial and
always statements but you cant nest
them.
.
.
reg a, b, c;

initial a=1b0;
.
.
always
begin
b = a ^ 1b1;
c = a + b;
end
.
.
Behavioral blocks
In additional to assignment, other functional description
codes are included in two-type behavioural blocks:
initial blocks
always blocks
A module can have multiple blocks, but blocks cannot be
nested.
When a block has multiple statements, they must be
grouped using
begin and end (for sequential statements) or
fork and join (for concurrent statements).
An initial block is executed at the beginning of simulation. It
is executed only once.
Always blocks are repeatedly executed until simulation is
stopped.


Initial statement
An initial block start at time 0, executes exactly once
and then never again.
If there are multiple initial blocks, each block starts to
execute concurrently at time 0 and each block finishes
execution independently of the others.
Multiple behavioral statements must be grouped using
begin and end. If there is one statement then grouping is
not necessary.

reg x, y, m;
initial m=1b0;

initial
begin
x=1b0;
y=1b1;
end
Example
A 2-to-4 decoder behavioral Verilog code
always statement
The always statement starts at time 0 and executes the
statements in the always block continuously in a looping
fashion.
It models a block of activity that is repeated
continuously in a digital circuit.
Multiple behavioral statements must be grouped using
begin and end. If there is one statement then grouping is
not necessary.

integer count;
count=0;
always
begin
count=count+1;
end
Events-based timing control
An event is the change in the value on a register or a net.
Events can be utilized to trigger the execution of a statement of a
block of statements.
The @ symbol is used to specify an event control.
Statements can be executed on changes in signal value or at a
positive (posedge) or negative (negedge) transition of the signal.
input clock;
integer count;

count=0;

always @(clock)
begin
count=count+1;
end
input clock1, clock 2;
integer count;

count=0;

always @(clock1 or clock2)
begin
count=count+1;
end
Procedural assignments
Procedural assignments update values of reg, integer,
or real variables.
The value will remain unchanged until another
procedural assignment updates the variable with a
different value different from dataflow continuous
assignments.
Two types of procedural assignments: blocking and
nonblocking.



Blocking statements,
specified using the =
operator.
are executed in the
order they are specified
in a sequential block.
Nonblocking
statements
specified using the
<= operator
are executed without
blocking the
statements that flow
in a sequential
block.
reg x, y;

initial
begin
x=1b1;
y=1b0;
end
reg x, y;

initial
begin
x<=1b1;
y<=1b0;
end
Blocking assignments v.s. Non-blocking assignments
Blocking assignments are performed sequentially.
Non-blocking assignments are performed concurrently.
initial begin
a = #1 1; // assignment at time 1
b = #3 0; // assignment at time 4 (3+1)
c = #6 1; // assignment at time 10 (6+3+1)
end
initial begin
#1 a < = 1; // assignment at time 1
#3 b <= 0; // assignment at time 3
#6 c <= 1; // assignment at time 6
end
Parallel blocks
Parallel block is a more flexible method to write concurrent statements.
It uses fork and join, instead of begin and end, in block description.
Sequential block with
blocking assignments
Sequential block with
Non-blocking assignments
Parallel block
Event control statements
An event occurs when a net or register changes it value.
The event can be further specified as a rising edge (by posedge) or
falling edge (by negedge) of a signal.
An event control statement always starts with symbol @
@ (clk) Q = D; // assignment will be performed whenever
signal clk changes to its value
@ (posedge clk) Q = D; // assignment will be performed whenever
signal clk has a rising edge (01, 0X,
0Z, X1, Z1)
@ (negedge clk) Q = D; // assignment will be performed whenever
signal clk has a falling edge (10, 1X,
1Z, X0, Z0)
Uses of nonblocking assignments
always @(posedge clock)
begin
a = b;
b = a;
end
always @(posedge clock)
begin
a <= b;
b <= a;
end
If the intention is to swap the contents of a and b, which one of
these will work?
Nonblocking assignments eliminate the race conditions.
At the positive edge of clock, the values of all the RHS
variables are read, expressions evaluated and then
assigned to the LHS.
Conditional statements
Very similar to C
Can always appear inside
always and initial blocks
.
if(x)
begin
y= 1b1;
z= 1b0;
end
.
if (count < 10)
count = count+1;
else
count = 0;
.
expression
.
if(alu_control == 0)
y = x + z;
else if (alu_control == 1)
y = x z;
else if (alu_control == 2)
y = x * z;
else
y = x;
.
reg [1:0] alu_control;
..
case (alu_control)
2d0 : y = x + z;
2d1 : y = x z;
2d2 : y = x * z;
default: y=x;
endcase
Loops
integer count;
integer y=1;
integer x=2;

initial
for (count = 0; count < 128; count = count + 1)
begin
x <= x + y;
y <= x;
end
initial
count = 0;
while (count < 128)
begin
.
.
count = count +1;
end
initial
count = 0;
repeat(128)
begin
.
.
count = count +1;
end
Four types of loops
while, for, repeat, and forever
Can appear only inside an initial
or always block.
Can contain delay expressions.
Must contain a
number or a
signal value;
only evaluated
once at the
beginning
Loop Example..
Synthesizing registers
Wait statements
Allow designers to more specifically control when to execute statements.
Starts with keyword wait followed by a logic condition

module testWait;
integer a, b, c;
reg en;

initial a = 0;
initial #3 a = 3;
intial #6 a = 7;

wait (a==7) b = 1; // assign 1 to b when a=7

wait (en) c = 2; // assign 2 to c when en is true
endmodule
Case statement
Readable alternative to nested if-else statements.
Sensitivity list
Sensitivity list specifies events on which signals activate or block
//A level-sensitive latch with asynchronous reset
always @( reset or clock or d)
//Wait for reset or clock or d to change
begin
if (reset) //if reset signal is high, set q to 0.
q = 1'b0;
else if(clock) //if clock is high, latch input
q = d;
end
Hierarchical naming
As described, every module instance, signal, or variable is identified with
an identifier.
Each identifier has a unique place in the design hierarchy.
Hierarchical name referencing allows us to denote every identifier in the
design hierarchy with a unique name.
A hierarchical name is a list of identifiers separated by dots . for each
level of hierarchy
Examples: stimulus.q, stimulus.m1.Q, stimulus.m1.n2
Named blocks
Blocks can be given names
Local variables can be declared from the names block
Variables in a named block can be accessed by using
hierarchical name referencing
Named blocks can be disabled

always
begin : block1
integer i;
i=1;

end

always
begin : block2
integer j;
j = block1.i^1;
end
Disabling named blocks
The keyword disable provides a way to terminate the
execution of a named block.
Disable can be used to get out of loops, handle error
conditions, or control execution of pieces of code based on
control signal
Disabling a block causes the execution control to be passed
to the statement immediately succeeding the block
initial
begin
i=0;
flag=8b0010_0101;
begin: block1
while (i < 16)
begin
if (flag[i]) disable block1;
i = i+1;
end
end
Tasks and functions
Often it is required to implement the same functionality at
many times in a behavioral design.
Verilog provides tasks and functions to break up large
behavioral code into smaller pieces.
Tasks and functions are included in the design hierarchy.
Like named blocks, tasks and functions can be addressed
by means of hierarchical names.
Tasks have input, output and inout arguments
Functions have input arguments
Tasks and functions are included in the design hierarchy.
Like named blocks, tasks or functions can be addressed by
means of hierarchical names
Tasks
Tasks are declared with the
keywords task and endtask.
Tasks can have input, inout,
and output arguments to
pass values (different than
in modules).
Tasks or functions can have
local variables but cannot
have wires.
Tasks and functions can only
contain behavioral
statements.
Tasks and functions do not
contain always or initial
statements but are called
from always blocks, initial
blocks, or other tasks and
functions.
Can operate directly on reg
variables defined in the
module



module

always
begin
BOP (AB_AND, AB_OR, AB_XOR, A, B);
BOP (CD_AND, CD_OR, CD_XOR, C, D);
end


task BOP;
output [15:0] ab_and, ab_or, ab_xor;
input [15:0] a, b;
begin
ab_and = a & b;
ab_or = a | b;
ab_xor = a ^ b;
end
endtask

endmodule
Module vs task instantiation
Instantiated modules create
duplicate copies in hardware.
In contrast tasks are static in
nature. All declared items are
statically allocated and they are
shared across all uses of the
task.
If a task is called from within a
behavioral block, only one copy
is needed
However, a task/function might
be called concurrently form
different behavioral blocks,
which can lead to incorrect
operation avoid by using the
automatic keyword to make a
task re-entrant
module

always
BOP (AB_AND, AB_OR, AB_XOR, A, B);

always
BOP (CD_AND, CD_OR, CD_XOR, C, D);


task automatic BOP;
output [15:0] ab_and, ab_or, ab_xor;
input [15:0] a, b;
begin
ab_and = a & b;
ab_or = a | b;
ab_xor = a ^ b;
end
endtask

endmodule
Functions
Functions are typically used for
combinational modeling (use for
conversions and commonly used
calculations).
Need at least one input argument
but cannot have output or inout
arguments.
The function is invoked by
specifying function name and input
arguments, and at the end
execution, the return value is
placed where the function was
invoked
Functions cannot invoke other
tasks; they can only invoke other
functions. Recursive functions are
not synthesizable
module

reg [31:0] parity;

always @(addr)
begin
parity = calc_parity(addr);
end

function calc_parity;
input [31:0] address;
begin
calc_parity = ^address;
end
endfunction

endmodule
Functions vs Tasks
Functions Tasks

A function can enable another
function but not another task.
A task can enable other tasks
and functions.
Functions always execute in 0
simulation time.
Tasks may execute in non-zero
simulation time.
Functions must not contain any
delay, event, or timing control
statements.
Tasks may contain delay, event,
or timing control statements.
Functions must have at least
one input argument. They can
have more than one input.
Tasks may have zero or more
arguments of type input,
output, or inout.
Functions always return a
single value. They cannot have
output or inout arguments.
Tasks do not return with a
value, but can pass multiple
values through output and
inout arguments.

Avoiding unwanted latches
Incomplete system specifications (if-else, or case) lead to unwanted latches
Latch-prone code
Latch-free code
Creating testbench
Used to verify the designed circuit.
Testbench example
Testbench
Unit under test
Simulation result
Example: clock display
seconds
HEX1 HEX0
minutes
HEX3 HEX2
Task to display digits

task digit2sev(input integer digit, output [6:0] disp);
begin
if (digit == 0) disp = 7'b1000000;
else if (digit == 1) disp = 7'b1111001;
else if (digit == 2) disp = 7'b0100100;
else if (digit == 3) disp = 7'b0110000;
else if (digit == 4) disp = 7'b0011001;
else if (digit == 5) disp = 7'b0010010;
else if (digit == 6) disp = 7'b0000011;
else if (digit == 7) disp = 7'b1111000;
else if (digit == 8) disp = 7'b0000000;
else if (digit == 9) disp = 7'b0011000;
end
endtask
task display_time(input [5:0] s, input [5:0] m);
begin
digit2sev(s%10, HEX0);
digit2sev(s/10, HEX1);
digit2sev(m%10, HEX2);
digit2sev(m/10, HEX3);
end
endtask

task digit2sev(input integer digit, output [6:0] disp);
begin
if (digit == 0) disp = 7'b1000000;
else if (digit == 1) disp = 7'b1111001;
else if (digit == 2) disp = 7'b0100100;
else if(digit == 3) disp = 7'b0110000;
else if(digit == 4) disp = 7'b0011001;
else if(digit == 5) disp = 7'b0010010;
else if(digit == 6) disp = 7'b0000011;
else if(digit == 7) disp = 7'b1111000;
else if(digit == 8) disp = 7'b0000000;
else if(digit == 9) disp = 7'b0011000;
end
endtask
endmodule
HEX3 HEX2 HEX1 HEX0
Implementation
module clock(CLOCK_50, HEX0, HEX1, HEX2, HEX3);
output reg [6:0] HEX0, HEX1, HEX2, HEX3;
input CLOCK_50; integer count=0;
reg [3:0] d1=0, d2=0, d3=0, d4=0;

always @(posedge CLOCK_50)
begin
count=count+1;
if (count == 50_000_000)
begin
count=0; d1 = d1+1;
if(d1 == 10)
begin
d1 = 0; d2 = d2+1;
if(d2 == 6)
begin
d2 = 0; d3 = d3 + 1;
if(d3 == 10)
begin
d3 = 0; d4 = d4 + 1;
if(d4 == 6) d4 = 0;

end
end
end
digit2sev(d1, HEX0); digit2sev(d2, HEX1);
digit2sev(d3, HEX2); digit2sev(d4, HEX3);

end
end

task digit2sev;

endtask

endmodule
module clock(CLOCK_50, HEX0, HEX1, HEX2, HEX3);
input CLOCK_50;
output reg [6:0] HEX0, HEX1, HEX2, HEX3;
integer count=0;
reg [15:0] ticks=16'd0;
reg [5:0] seconds=6'd0, minutes=6'd0;

initial display_time(seconds, minutes);

always @(posedge CLOCK_50)
begin
count = count+1;
if (count == 50_000_000)
begin
count=0;
ticks = ticks + 1;
seconds = ticks % 60;
minutes = ticks / 60;
display_time (seconds, minutes);
end
end
Alt-2
Alt-1
Resource utilization is 152 LEs
Resource utilization=Alt 1
Resource utilization for Alt-2
Circuit consumes 611 LEs (2% of the chip logic resources).
You have to be careful! Changing ticks, seconds and
minutes to integer increases area to become 2500 LEs (8%
of the utilization)
Synthesis tips
Nested if-else leads to lengthy mux-chain, which is normally slow.
Using case instead.
However, case results in mux with multiple inputs, which makes
routing more difficult.
Using instantiated module to implement arithmetic operators,
instead of directly using arithmetic operators. Good partition
leads to better results.
Assign values to all outputs in all cases (to avoid unwanted
latches).

Register all the outputs of critical design blocks
Avoid path that traces through number of hierarchies
and then return back to same hierarchy
Partition the design based on functional goals and the
clock domains
Avoid instantiating technology specific modules
Use parameters and declare them at the top with
meaningful names
Avoid internally generated clocks and resets
Avoid glue logic at the top level
Synthesis for Reusability
References
Verilog HDL by Samir Palnitkar; Pearson
Verilog Interactive tutorial by Aldec
Design guidelines: http://www.inno-logic.com/resourcesTips.html

You might also like