verilog lecture notes
-
Upload
ravi-kishore -
Category
Documents
-
view
138 -
download
0
description
Transcript of verilog lecture notes
-
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); 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.
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
Me
mo
ry
Pro
ce
sso
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
Me
mo
ry
Pro
ce
sso
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 (
(only one allowed)
);
//Terminal declarations
output ;
input ;
reg ;(optional; only for
sequential UDP)
// UDP initialization (optional; only for sequential UDP
initial = ;
//UDP state table
table
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 (
);
output ;
input ;
table
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 (
);
output ;
input ;
reg ;
initial = ;
table
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 >> and
-
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 right
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 // /
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
-
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
-
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
-
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
-
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