Presentation is loading. Please wait.

Presentation is loading. Please wait.

ECE 551 Digital System Design & Synthesis Lecture 07 Parameters Code Generation Functions & Tasks.

Similar presentations


Presentation on theme: "ECE 551 Digital System Design & Synthesis Lecture 07 Parameters Code Generation Functions & Tasks."— Presentation transcript:

1 ECE 551 Digital System Design & Synthesis Lecture 07 Parameters Code Generation Functions & Tasks

2 Elaboration of Verilog Code 2

3  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  We’ve already examined one part of Elaboration  Unrolling of FOR Loops  Next we’ll look at other uses of Elaboration  Parameterization  Code Generation  Constant Functions  Macros 3

4 Overview  Parameters  Generated Instantiation  Functions and Tasks  “Compiler” Directives 4

5 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

6 More Readable, Less Error-Prone 6 always @(*) begin case (mode) 4’b0000: … 4’b0100: … 4’b0101: … 4’b1010: … 4’b1100: … default: … endcase end parameter ADD=4’b0000; parameter SUB=4’b0100; parameter XOR=4’b0101; parameter AND=4’b1010; parameter EQ=4’b1100; always @(*) begin case (mode) ADD: … SUB: … XOR: … AND: … EQ: … default: … endcase end VS

7 Reusability/Extensibility of Modules 7 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?

8 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

9 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) 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 very common use of parameters

10 Parameterized Ripple Carry Adder 10 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);

11 Parameterized Shift Register [1] 11 module shift(out, in, clk, rst); parameter BITS=8; input in; 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);

12 Parameterized Shift Register [2] 12 module shift_bhv (outbit, out, in, clk, rst); parameter WIDTH = 8; output [WIDTH-1:0] out; output outbit; input in; 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);

13 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 13

14 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 14

15 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 15

16 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; genvar i; generate for (i=0; i<SIZE; i=i+1) begin: bit assign bin[i] = ^gray[SIZE-1:i]; // reduction XOR end endgenerate endmodule 16 How does this differ from a standard for loop?

17 Generate Loops in LHC Firmware 17 input [CLUSTER_ET_SIZE-1:0] cluster_grid[GRID_X-1:0][GRID_Y-1:0]; wire eg_grid_mask[GRID_X-1:0][GRID_Y-1:0]; …… genvar i, j; generate begin : mask_gen for (i = 0; i < GRID_X; i=i+1) begin : xcoord for (j = 0; j < GRID_Y; j=j+1) begin : ycoord logic [CLUSTER_ET_SIZE-1:0] central_et = cluster_grid[i][j]; assign eg_grid_mask [i][j] = (central_et >= EG_THRESHOLD); assign tau_grid_mask[i][j] = (central_et >= TAU_THRESHOLD); end endgenerate//This must be SystemVerilog. Why?

18 Accessing Data from other Loops 18 generate for(i = 0; i < GRID_X; i = i + 1) begin : aliasing_x for(j = 0; j < GRID_Y; j = j + 1) begin : aliasing_y if((i >= ISO_X1) && (i <= ISO_X2) && (j >= ISO_Y1) && (j <= ISO_Y2)) begin assign et_array[i-ISO_X1][j-ISO_Y1] = mask_gen.xcoord[i].ycoord[j].central_et; assign eg_correction [i-ISO_X1][j-ISO_Y1] = eg_grid_mask[i][j]; assign tau_correction[i-ISO_X1][j-ISO_Y1] = tau_grid_mask[i][j]; end endgenerate

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; output [PRODUCT_WIDTH-1:0] product; generate 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 19 These are parameters, not variables!

20 Generate-Case  A generate-case allows conditional (pre-synthesis) instantiation using case constructs  See Standard 12.1.3 for more details 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 endgenerate endmodule 20 Can have a “default” in a generate-case

21 Generate a Pipeline [Part 1] 21 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

22 Generate a Pipeline [Part 2] 22 // 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 endgenerate endmodule What does this generate?

23 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! 23

24 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 24

25 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 25

26 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 26

27 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  Other restrictions apply – see 10.3.5  Constant functions are useful when one constant value is dependent on another. It can simplify the calculation of values in parameterized modules. 27

28 Function Example 28 module word_aligner (word_out, word_in); output[7: 0]word_out; 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) 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? size of return value input to function

29 Function Example 29 module arithmetic_unit (result_1, result_2, operand_1, operand_2,); output [4: 0] result_1; output[3: 0] result_2; 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 [3: 0] larger_operand(input [3: 0] operand_1, operand_2); larger_operand = (operand_1 >= operand_2) ? operand_1 : operand_2; endfunction endmodule function inputs function output function call

30 Constant Function Example 30 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

31 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 31

32 Task Example [Part 1] 32 module adder_task (c_out, sum, clk, reset, c_in, data_a, data_b, clk); output reg[3: 0] sum; output regc_out; input [3: 0] data_a, data_b; 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 this is NOT conditionally “creating” hardware!

33 Task Example [Part 2] 33 // Continued from previous slide task add_values;// task declaration output regc_out; output reg[3: 0] sum input [3: 0] data_a, data_b; 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? task inputs task outputs

34 Function Example [Part 1] 34 module adder_func (c_out, sum, clk, reset, c_in, data_a, data_b, clk); output reg[3: 0] sum; output regc_out; input [3: 0] data_a, data_b; 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 this is NOT conditionally “creating” hardware!

35 Function Example [Part 2] 35 // 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?

36 Task Example 36 task leading_1(output reg [2:0] position, input [7:0] data_word); reg [7:0] temp; begin temp = data_word; position = 7; while (!temp[7]) begin temp = temp << 1; position = position - 1; end endtask  What does this task assume for it to work correctly?  How do tasks differ from modules?  How do tasks differ from functions? internal task variable NOTE: “while” loops usually not synthesizable!

37 10.1 Distinctions between tasks and functions 37 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.

38 `define Compiler Directives  Macro for text substitutions - Used within and outside of module declarations `define text_macro_name[(arguments)] macro-text  Example 1: `define address_register_length 16 reg [`address_register_length :1] address;  Example 2: `define nord(dly) nor #dly `nord(4) g1 (N3, A, B); // becomes nor #4 g1(N3, A, B); `undef nord  Be careful of conflicting directives!  `define applies until you indicate otherwise!  Note use of ` when referencing the defined macro  Use `undef to undefine  Use parameters when appropriate to encapsulate 38

39 `define Compiler Directives 39 `define WIRES(SIZE) wire[SIZE-1:0] `WIRES(8)a, b; `WIRES(16)prod; `WIRES(32)psquared; assign prod = a * b; assign psquared = prod * prod; When used properly, macros can make code easier to read, write, and understand. Be careful: Because Macros are only substituted at Elaboration time, any syntax errors inside the Macro itself will not be found when doing compile in ModelSim!

40 Conditional Compilation Directives  Conditional compilation directives include:  `ifdef, `ifndef, `else, `elsif, `endif  Useful when  Selecting different stimulus  Choosing different timing or structural information  Selecting different representations of modules module and_op (output a, input b, c); `ifdef RTL assign a = b & c; // continuous assign `else and a1 (a, b, c); // primitive `endif endmodule 40

41 Macros vs Parameters  Scope  Parameters scope is limited to the module they are declared in.  Macros have global scope.  Redefinition  Parameters can only be redefined when instantiating a module or using defparam.  Macros can be redefined at any point in any file in your project – beware! 41

42 Macros vs Parameters  Flexibility  Parameters only represent numerical values  Macros represent strings of text (including numbers)  Macros can take arguments  Macros can have control statements (`ifdef)  Ease of Use  Syntax errors with parameters are caught during syntax check (compile in ModelSim)  Syntax errors inside macro strings are caught in elaboration  This makes macros harder to debug  Moral – macros more powerful, but error-prone  Some designers opt to only use parameters 42

43 ‘resetall  Resets all compiler directives to defaults  Often used to start each file to avoid conflicts  Important because, unlike parameters, macros have global scope 43

44 ‘include Compiler Directives  `include filename  Inserts entire contents of another file at compilation  Can be placed anywhere in Verilog source  Useful for shared tasks/functions!  Example 1: module use_adder8(…); `include “adder8.v”; // include the task for adder8  Example 2: module use_incrementer(…); `include “/home/components/incrementer.v”  Can provide either relative or absolute path names  Useful for including tasks and functions in multiple modules  Also good for parameters used in more than one module! 44

45 ‘timescale  `timescale  Saw this already in our testbenches  `timescale time_unit/time_precision  time_unit - specifies unit of measurement for times and delays  time_precision  time_unit  Specifies how delays are rounded before use in simulation  The time unit for simulation is the smallest time_precision value specified over all modules  Allowable values {1, 10, 100} {s, ms, us, ns, ps, fs}  Example: `timescale 1 ns / 100 ps 45

46 Review Questions  Write a module for an adder with the following interface module adder(a, b, sum); Allow the widths of a, b, and sum to be specified using the parameters in_width and out_width, where each has a default value of 8. Use a function to perform the addition.  Show how to instantiate an adder using the module above named ADD1 with in_width = 4 and out_width = 6. Use named association.  Use a generate-loop to re-implement the above adder using continuous assignment statements with bitwise operations. Don’t use a function. 46


Download ppt "ECE 551 Digital System Design & Synthesis Lecture 07 Parameters Code Generation Functions & Tasks."

Similar presentations


Ads by Google