0% found this document useful (0 votes)
39 views

Chapter7 Parameters Functions Task (Edited)

Uploaded by

baxuanhanh113
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)
39 views

Chapter7 Parameters Functions Task (Edited)

Uploaded by

baxuanhanh113
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/ 38

Digital Design with the Verilog HDL

Chapter 7: Parameters, Task, and Function in


Verilog

Dr. Phạm Quốc Cường

Computer Engineering – CSE – HCMUT 1


Elaboration of Verilog Code

2
Elaboration of Verilog Code
• Elaboration is a pre-processing stage that takes place
before code is synthesized.
• It allows us to automatically alter our code before
Synthesis based on Compile-Time information
• Uses of Elaboration
– Unrolling of FOR Loops
– Parameterization
– Code Generation
– Constant Functions
– Macros

3
Overview
• Parameters
• Generated Instantiation
• Functions and Tasks

4
Parameters

• Compile-time constant parameters in Verilog


– In Verilog: parameter N=8’d100;
– Values are substituted during Elaboration; parameters
cannot change value after synthesis

• Can be used for three main reasons


– Make code more readable
– Make it easier to update code
– Improve (re)usability of modules

5
More Readable, Less Error-Prone
parameter ADD=4’b0000;
parameter SUB=4’b0100;
parameter XOR=4’b0101;
parameter AND=4’b1010;
parameter EQ=4’b1100;

always @(*) begin always @(*) begin


case (mode) case (mode)
4’b0000: … ADD: …
4’b0100: … SUB: …
4’b0101: … VS XOR: …
4’b1010: … AND: …
4’b1100: … EQ: …
default: … default: …
endcase endcase
end end
6
Reusability/Extensibility of Modules
module xor_array(y_out, a, b);
parameter SIZE = 8, DELAY = 15; // parameter defaults
output [SIZE-1:0] y_out;
input [SIZE-1:0] a,b;
wire #DELAY y_out = a ^ b;
endmodule

xor_array G1 (y1, a1, b1); // use defaults


xor_array #(4, 5) G2(y2, a2, b2); // override default parameters
// SIZE = 4, DELAY = 5

• Module instantiations cannot specify delays without parameters


– Where would delays go? What type would they be?

7
Overriding Parameters
• Parameters can be overridden
– Generally done to “resize” module or change its delay
• Implicitly: override in order of appearance
– xor_array #(4, 5) G2(y2, a2, b2);
• Explicitly: name association (preferred)
– xor_array #(.SIZE(4), .DELAY(5)) G3(y2, a2, b2);
• Explicitly: defparam
– defparam G4.SIZE = 4, G4.DELAY = 15;
– xor_array G4(y2, a2, b2);

• localparam parameters in a module can’t be overridden


– localparam SIZE = 8, DELAY = 15;

8
Parameters With Instance Arrays
module array_of_xor (y, a, b);
parameter SIZE=4;
input [SIZE-1:0] a,b;
output [SIZE-1:0] y;
xor G3[SIZE-1:0] (y, a, b); // instantiates 4 xor gates
endmodule // (unless size overridden)
very common use of
parameters
module variable_size_register (q, data_in, clk, set, rst);
parameter BITWIDTH=8;
input [BITWIDTH-1:0] data_in; // one per flip-flop
input clk, set, rst; // shared signals
output [BITWIDTH-1:0] q; // one per flip-flop
// instantiate flip-flops to form a BITWIDTH-bit register
flip_flop M [BITWIDTH-1:0] (q, data_in, clk, set, rst);
endmodule

9
Synthesized array_of_xor

10
Synthesized variable_size_register

11
Parameterized Ripple Carry Adder
module RCA(sum, c_out, a, b, c_in);
parameter BITS=8;
input [BITS-1:0] a, b;
input c_in;
output [BITS-1:0] sum;
output c_out;
wire [BITS-1:1] c;

Add_full M[BITS-1:0](sum, {c_out, c[BITS-1:1]},


a, b, {c[BITS-1:1], c_in});
endmodule

 Instantiate a 16-bit ripple-carry adder:


RCA #(.BITS(16)) add_16(sum, carryout, a, b,
carryin); 12
Parameterized Shift Left Register [1]
module shift(out, in, clk, rst);
parameter BITS=8;
input in, clk, rst;
output [BITS-1:0] out;

dff shiftreg[BITS-1:0](out, {out[BITS-2:0], in}, clk, rst);


endmodule

 Instantiate a 5-bit shift register:


shift #(.BITS(5)) shift_5(shiftval, shiftin, clk, rst);

13
Parameterized Shift Left Register [2]
module shift_bhv (outbit, out, in, clk, rst);
parameter WIDTH = 8;
output reg [WIDTH-1:0] out;
output reg outbit;
input in, clk, rst;
always @(posedge clk) begin
if (rst) {outbit,out} <= 0;
else {outbit,out} <= {out[WIDTH-1:0],in};
end
endmodule

 Instantiate a 16-bit shift register:


shift_bhv #(16) shift_16(shiftbit, shiftout, shiftin, clk, rst);
14
Synthesized Shift Left Register

15
Parameters + Generate Statements
• Problem: Certain types of logic structures are
efficient only in certain scenarios

• For example when designing an adder:


– Ripple-Carry Adders are better for small operands
– Carry Look-ahead Adders are better for large operands

• If we change a parameter to use a larger or smaller


adder size, we may also want to change the structure
of the logic

16
Generated Instantiation
• Generate statements: control over the
instantiation/creation of
– Modules, gate primitives, continuous assignments, initial
blocks, always blocks, nets and regs

• Generate instantiations are resolved during


Elaboration
– Can alter or replace a piece of code based on compile-time
information
– Before the design is simulated or synthesized
– Think of it as having the code help write itself

17
Special Generate Variables
• Index variables used in generate statements;
declared using genvar (e.g., genvar i )

• Useful when developing parameterized modules


• Can override the parameters to create different-sized
structures
• Easier than creating different structures for all
different possible bitwidths

18
Generate-Loop
• A generate-loop permits making one or more instantiations
(pre-synthesis) using a for-loop.

module gray2bin1 (bin, gray);


parameter SIZE = 8; // this module is parameterizable
output [SIZE-1:0] bin; input [SIZE-1:0] gray;
How does this differ
genvar i; from a standard for
generate loop?
for (i=0; i<SIZE; i=i+1) begin: bit
assign bin[i] = ^gray[SIZE-1:i]; // reduction XOR
end
endgenerate
endmodule
19
Generate-Conditional
• A generate-conditional allows conditional (pre-synthesis)
instantiation using if-else-if constructs

module multiplier(a ,b ,product);


parameter A_WIDTH = 8, B_WIDTH = 8;
localparam PRODUCT_WIDTH = A_WIDTH+B_WIDTH;
input [A_WIDTH-1:0] a; input [B_WIDTH-1:0] b; These are
output [PRODUCT_WIDTH-1:0] product; parameters,
generate
not variables!
if ((A_WIDTH < 8) || (B_WIDTH < 8))
CLA_multiplier #(A_WIDTH,B_WIDTH) u1(a, b, product);
else
WALLACE_multiplier #(A_WIDTH,B_WIDTH) u1(a, b, product);
endgenerate
endmodule

22
Generate-Case
• A generate-case allows conditional (pre-synthesis)
instantiation using case constructs

module adder (output co, sum, input a, b, ci);


parameter WIDTH = 8;
generate
case (WIDTH)
1: adder_1bit x1(co, sum, a, b, ci); // 1-bit adder implementation
2: adder_2bit x1(co, sum, a, b, ci); // 2-bit adder implementation
default: adder_cla #(WIDTH) x1(co, sum, a, b, ci);
endcase Can have a “default” in
endgenerate a generate-case
endmodule
23
Generate a Pipeline [Part 1]
module pipeline(out, in, clk, rst);
parameter BITS = 8;
parameter STAGES = 4;
input [BITS-1:0] in;
output [BITS-1:0] out;
wire [BITS-1:0] stagein [0:STAGES-1]; // value from previous stage
reg [BITS-1:0] stage [0:STAGES-1]; // pipeline registers

assign stagein[0] = in;


generate
genvar s;
for (s = 1; s < STAGES; s = s + 1) begin : stageinput
assign stagein[s] = stage[s-1];
end
endgenerate

// continued on next slide

24
Generate a Pipeline [Part 2]
// continued from previous slide
assign out = stage[STAGES-1];
generate
genvar j;
for (j = 0; j < STAGES; j = j + 1) begin : pipe
always @(posedge clk) begin
if (rst) stage[j] <= 0;
else stage[j] <= stagein[j];
end
end
endgenerate
endmodule

What does this generate?

25
Functions and Tasks
• HDL constructs that look similar to calling a function or
procedure in an HLL.
• Designed to allow for more code reuse

• There are 3 major uses for functions/tasks


– To describe logic hardware in synthesizable modules
– To describe functional behavior in testbenches
– To compute values for parameters and other constants for
synthesizable modules before they are synthesized

• When describing hardware, you must make sure the


function or task can be synthesized!

26
Functions and Tasks in Logic Design
• It is critical to be aware of whether something you
are designing is intended for a synthesized module
– Hardware doesn’t actually “call a function”
– No instruction pointer or program counter
– This is an abstraction for the designer

• In synthesized modules, they are used to describe


the behavior we want the hardware to have
– Help make HDL code shorter and easier to read
– The synthesis tool will try to create hardware to match that
description
27
Functions and Tasks in Testbenches
• Since testbenches do not need to synthesize, we do
not have to worry about what hardware would be
needed to implement a function

• Be careful: This doesn’t mean that we can treat such


functions & tasks as software

• Even testbench code must follow Verilog standards,


including the timing of the Stratified Event Queue

28
Functions
• Declared and called within a module
• Used to implement combinational behavior
– Contain no timing controls or tasks
– Can use behavioral constructs
• Inputs/outputs
– At least one input, exactly one output
– Return variable is the same as function name
• Can specify type/range (default: 1-bit wire)
• Usage rules:
– May be referenced in any expression (RHS)
– May call other functions
– Use automatic keyword to declare recursive functions

29
Constant Functions
• A special class of functions that can always be used
in a synthesizable module
• Constant functions take only constant values (such as
numbers or parameters) as their inputs.
– All inputs are constant, so the output is also constant
– The result can be computed at elaboration, so there is no
reason to build hardware to do it
• Constant functions are useful when one constant
value is dependent on another. It can simplify the
calculation of values in parameterized modules.
30
Function Example
module word_aligner (word_out, word_in);
output [7: 0] word_out; size of return value
input [7: 0] word_in;
assign word_out = aligned_word(word_in); // invoke function

function [7: 0] aligned_word; // function declaration


input [7: 0] word;
begin
aligned_word = word;
if (aligned_word != 0) input to function
while (aligned_word[7] == 0) aligned_word = aligned_word << 1;
end
endfunction
endmodule
What sort of hardware might this describe?
Do you think this will synthesize?

31
Function Example
module arithmetic_unit (result_1, result_2, operand_1, operand_2,);
output [4: 0] result_1;
output [3: 0] result_2; function call
input [3: 0] operand_1, operand_2;
assign result_1 = sum_of_operands (operand_1, operand_2);
assign result_2 = larger_operand (operand_1, operand_2);

function [4: 0] sum_of_operands(input [3: 0] operand_1, operand_2);


sum_of_operands = operand_1 + operand_2;
endfunction
function inputs
function output
function [3: 0] larger_operand(input [3: 0] operand_1, operand_2);
larger_operand = (operand_1 >= operand_2) ? operand_1 : operand_2;
endfunction
endmodule

32
Constant Function Example
module register_file (…);
parameter NUM_ENTRIES=64;
localparam NUM_ADDR_BITS=ceil_log2(NUM_ENTRIES);

function [31: 0] ceil_log2(input [31: 0] in_val);


reg sticky;
reg [31:0] temp;
begin
sticky = 1'b0;
for (temp=32'd0; value>32'd1; temp=temp+1) begin
if((value[0]) & (|value[31:1]))
sticky = 1'b1;
value = value>>1;
end
clogb2 = temp + sticky;
end
endfunction

33
Tasks
• Declared within a module
– Only used within a behavior
• Tasks provide the ability to
– Describe common behavior in multiple places
– Divide large procedures into smaller ones
• Tasks are not limited to combinational logic
– Can have time-controlling statements (@, #, wait)
• Some of this better for testbenches
– Use automatic keyword to declare “reentrant” tasks
• Can have multiple outputs, inout ports
• Local variables can be declared & used

34
Task Example [Part 1]
module adder_task (c_out, sum, clk, reset, c_in, data_a, data_b, clk);
output reg [3: 0] sum;
output reg c_out; this is NOT conditionally
input [3: 0] data_a, data_b; “creating” hardware!
input clk, reset, c_in;

always @(posedge clk or posedge reset) begin


if (reset) {c_out, sum} <= 0;
else add_values (c_out, sum, data_a, data_b, c_in); // invoke task
end
// Continued on next slide

35
Task Example [Part 2]
// Continued from previous slide
task add_values; // task declaration
task outputs
output reg c_out;
output reg [3: 0] sum
input [3: 0] data_a, data_b; task inputs
input c_in;
{c_out, sum} <= data_a + (data_b + c_in);
endtask
endmodule

• Could have instead specified inputs/outputs using a port list.


task add_values (output reg c_out, output reg [3: 0] sum,
input [3:0] data_a, data_b, input c_in);
• Could we have implemented this as a function?

36
Function Example [Part 1]
module adder_func (c_out, sum, clk, reset, c_in, data_a, data_b, clk);
output reg [3: 0] sum;
output reg c_out; this is NOT conditionally
input [3: 0] data_a, data_b; “creating” hardware!
input clk, reset, c_in;

always @(posedge clk or posedge reset) begin


if (reset) {c_out, sum} <= 0;
else {cout, sum} <= add_values (data_a, data_b, c_in); // invoke task
end
// Continued on next slide

37
Function Example [Part 2]
// Continued from previous slide
function [4:0] add_values; // function declaration
input [3: 0] data_a, data_b;
input c_in;
add_values = data_a + (data_b + c_in);
endfunction
endmodule

How does this differ from the task-based version?

38
Task Example
task leading_1(output reg [2:0] position, input [7:0] data_word);
reg [7:0] temp;
begin
internal task variable
temp = data_word;
position = 7;
while (!temp[7]) begin NOTE:
temp = temp << 1; “while” loops usually
position = position - 1; not synthesizable!
end
end
endtask

• What does this task assume for it to work correctly?


• How do tasks differ from modules?
• How do tasks differ from functions?

39
Distinctions between tasks and functions

The following rules distinguish tasks from functions:


• A function shall execute in one simulation time unit; a task
can contain time-controlling statements.
• A function cannot enable a task; a task can enable other tasks
and functions.
• A function shall have at least one input type argument and
shall not have an output or inout type argument; a task can
have zero or more arguments of any type.
• A function shall return a single value; a task shall not return a
value.
The purpose of a function is to respond to an input value by
returning a single value. A task can support multiple goals and
can calculate multiple result values.

40

You might also like