Utilization of parameters in Verilog - verilog

I have always used Verilog parameters in the traditional manner, i.e. passing them to a module instantiation to allow different specification to be used. In other words, used to replace text in the HDL code with the given parameter value.
Can I also use it to perform logical calculations?
If I declare the following parameter:
parameter CONST = 100;
As I understand it, the CONST will be of 32 bits (integer).
So can I for example perform bit-wise operations with it:
assign tmp = CONST^net; //net is a 32-bit long wire
Thanks!

You are correct. A value parameter declared without an explicit datatype is implicitly the datatype of the value being assigned to it. In your example the value 100 has implicitly a 32-bit signed datatype with a decimal radix.
However, if CONST is a module parameter that get overwritten, the datatype of the value overwriting the declared value also overrides the implicit data type.
module #(CONST= 100) mod();
endmodule
module top;
mod #(2'b10) m1(); // in this instance CONST is 2 bits(unsigned);
mod #(8'h0F) m2(); // in this instance CONST is 8 bits(unsigned);
However if you declared CONST with an explicit datatype, only the value gets overwritten, not the datatype. I strongly recommend this approach.
module #(int CONST= 100) mod();
endmodule
module top;
mod #(2'b10) m1(); // in this instance CONST is 32 bits(signed);
mod #(8'h0F) m2(); // in this instance CONST is 32 bits(signed);

Related

Initialize parameter from array

I have a parameterised module whose SEED value has to change depending on the WIDTH parameter, where the seed values have to be hard-coded.
module Module;
parameter WIDTH = 8;
integer seeds [31:0] = {'hC, 'h1E, 'h39, 'h7E, /* ... */};
localparam SEED = seeds[WIDTH];
endmodule
This doesn't work, It's clear I'm trying to use the unpacked array in the wrong context.
Unable to bind parameter seeds[WIDTH] in module Module
How else can I implement this?
After adjusting the post to compile with the truncated 4-element array, Questa shows:
** Error: testbench.sv(): Parameter value must be constant.
Parameters and localparams can't accept variable values.
Integer is a variable type, it can change at run time.
Parameters must be known an compile time.
This compiles without warnings:
module Module;
parameter WIDTH = 1;
parameter integer seeds[4] = {4'hC, 8'h1E, 8'h39, 8'h7E};
localparam SEED = seeds[WIDTH];
initial
$display("SEED = %0h",SEED);
endmodule
Questa Produces:
# vsim -voptargs=+acc=npr
# run -all
# SEED = 1e
This has an array of 4 hex values, and uses index 1 (WIDTH==1) as an argument to seeds.

Multiple assignments to function return value

In a SystemVerilog function, is it legal to do multiple assignments to the implicitly-declared return variable? See the following function for an example:
localparam int Q=1,I=0;
function logic [1:0][Q:I][15:0] Cast24to16(input logic [1:0][Q:I][23:0] din);
foreach (Cast24to16[n,iq])
Cast24to16[n][iq] = din[n][iq][23 -: 8];
endfunction
The language reference manual, IEEE Std 1800-2017, sec 13.4.1 states:
Function return values can be specified in two ways, either by using a return statement or by assigning a value to the internal variable with the same name as the function.
This seems a little unclear as to whether you can assign multiple times, like in my example. Furthermore, the example from the LRM directly after this statement and also all other examples I can find online all show the implicit return value only being assigned once. This makes me feel a bit unsettled.
The LRM also says just before the section you quoted
The function definition shall implicitly declare a variable, internal to the function, with the same name as the function.
I think you can safely assume that if there is no explicit return statement, it effectively inserts an implicit return (var_function_name);
Also, if you declare your function with a static lifetime (which is the implicit default lifetime in a module), that implicit return variable has a static lifetime as well. That means it retains its value from the last time you called the function regardless of whether you assign it or not.
module top;
function int countme;
countme++;
endfunction
initial repeat (10) $display(countme());
endmodule

Passing parameters to a Verilog function

I want to pass a parameter to a function and use it as a parameter (e.g. to select bits) but I don't know how to tell the function that this input is a constant.
For example, if I wanted to do this:
assign foo = bar[MY_PARAM:0];
I want to write my_function so that I could do this:
assign foo = my_function(bar, MY_PARAM);
In my case I need to do a little more that just select bits but not too much, and I'll want it to work for inputs of different bit widths.
If I just wanted to select a bit I could use the function below and I'd hope for a solution of similar form but I can't work out the syntax:
function my_function;
input [3:0] data, my_bit;
begin
my_function = data[my_bit];
end
endfunction
As per Silicon1602's answer, the code I'd need for this would be:
virtual class myClass#(parameter LOCAL_PARAM);
static function [LOCAL_PARAM:0] my_function;
input [LOCAL_PARAM:0] data;
begin
my_function = data[LOCAL_PARAM:0];
end
endfunction
endclass
assign foo = myClass#(MY_PARAM)::my_function(bar);
At first I forgot about the [LOCAL_PARAM] part and was just getting 1-bit back.
The SystemVerilog LRM has a section on your particular case: 13.8 Parameterized tasks and functions. It says:
SystemVerilog provides a way to create parameterized tasks and functions, also known as parameterized subroutines. [...] The way to implement parameterized subroutines is through the use of static methods in parameterized classes (see 8.10 and 8.25).
In your case, you should declare your function like this:
virtual class myClass#(parameter MY_PARAM);
static function my_function;
input [MY_PARAM-1:0] data, my_bit;
begin
my_function = data[my_bit];
end
endfunction
endclass
You could then call your function like this:
assign my_function_output = myClass#(MY_PARAM)::my_function(data, my_bit);
Please note that you may declare multiple functions in your abstract class. So, if you have a whole bunch of functions which all depend on a parameter in the same way, you could all declare them in the same class.
Some additional information on the virtual and static keyword in the aforementioned context:
Section 8.10 of the LRM talks about static methods.
A static method is subject to all the class scoping and access rules, but behaves like a regular subroutine that can be called outside the class, even with no class instantiation. A static method has no access to non-static members (class properties or methods), but it can directly access static class properties or call static methods of the same class.
By using the virtual keyword for the class declaration, you show the compiler that this is an abstract class (see Section 8.21 in the LRM). Creating an object of a virtual class causes a compilation error. This enforces strict static usage of the method.
Since the question was also tagged as 'verilog', a similar trick could be played in a simple verilog. You can use parameterized modules to achieve the same effect. For example:
module util#(
parameter int W = 10)();
function funct;
input [W-1:0] inp;
funct = inp;
endfunction
endmodule
module top(out, in);
parameter W = 8;
output wire [W-1:0] out;
input wire [W-1:0] in;
util#(W) u1(); // inst util module with a parameter
assign out = u1.funct(in); // call the function
initial #1 $finish;
endmodule
By default, all functions declared within a module are static.
You can use macro expansion to achieve this. I wanted a function that would check different test stimulus. The simulation arrays of 'bus' signals (or multi-bit values) and this was my 'parameter'.
`define MY_FUNCTION(LOCAL_PARAM) \
function my_function_``LOCAL_PARAM``; \
input [LOCAL_PARAM:0] data, my_bit; \
begin \
my_function_``LOCAL_PARAM`` = data[my_bit]; \
end \
endfunction \
Later...
`MY_FUNCTION(10)
my_function_10 (data_ten, my_bit); // Really my_bit is size $clog of LOCAL_PARAM.
Like Serge's answer, this works with Verilog (2001). Also, you can use tasks and then the entire module net is available. The macro call is equivalent the module instantiation with a parameter. It is basically like the elaboration phase.
Probably the module solution has more valid syntax and constructs. However, a macro of a function can achieve a similar result for simulation and could be suitable for some synthesis cases.

Multi-dimentional packed parameter declaration using function

Recently I am thinking pre-calculating all necessary parameters using simple mathematical equations before instantiating logic units in generate struct. In the case where I need to have a 2-D parameter, it's easy if the 2-D array is a set of fixed values, such as
parameter para_1[1:0][2:0] = '{2{3{0}}};.
But what I want is a function that dictates the values, such that complicated equations can be implemented inside the function before assigning the return values to the parameter.
Ideally I want something as follows:
function func01 [1:0][1:0] (input int test);
int index;
for (index=0; index<=2; index++) begin
func01[index] = index + $floor(index/2) + $mod(index, 2) + test;
end
endfunction
parameter test1 = 1;
parameter logic test2 [1:0][1:0] = func01(test1);
But ModelSim complains about the first line of code straightaway - ** Error: (vlog-13069) near "[": syntax error, unexpected '[', expecting ';' or '('.
Ultimately the idea is to have a block that calculates all parameters/constants at elaboration time, so that these can be used in generate block for instantiation, also at elaboration time.
Hope it makes sense, and thanks a lot in advance.
Best,
Taihai
First, if you want packed arrays, the dimension ranges goes to the left of the array name. And I suggest using an explicit data type.
parameter bit [1:0][2:0] para_1 = '{2{3{0}}};.
Then, the return type of function declaration comes before the function name.
function bit [1:0][1:0] func01 (input int test);
BTW if you want the return type of a function to have an unpacked dimension, you must use a typedef, which is a good practice in any case.
typedef bit [1:0] myParam_t [2:0];
parameter myParam_t para_1 = '{default:0};
function myParam_t func01 (input int test);

Computed verilog parameter in Yosys

I am learning Verilog at the moment by using Yosys to synthesize code to an iCE40 development board. I am stuck at using parameters in verilog. I have the following code:
module tst;
parameter clkspd=12000000;
parameter baudrate=115200;
localparam bitperiod=$floor(clkspd/baudrate-0.5);
localparam bittmrwidth=$clog2(bitperiod);
//localparam bittmrwidth=$clog2(103);
initial begin
$display("Hello World!");
$display("width=%d",bittmrwidth);
end
endmodule
When I compile the code with :
yosys -p 'synth_ice40 -top tst -blif tst.blif' tst.v
I get an error:
ERROR: Failed to evaluate system function `\$clog2' with non-constant value at tst.v:5.
However if I use the commented out line, everything work as expected.
How can I calculate "bittmrwidth" with the given parameters ?
I don't have yosys installed, but when I run your code on another simulator, I get this error:
System function call $clog2 must have an integral argument.
This is consistent with the IEEE Std 1800-2012, section 20.8.1 Integer math functions, which states for $clog2:
The argument can be an integer or an arbitrary sized vector value.
The $floor function returns a real result type, according to section 20.8.2 Real math functions. Simply cast the $floor output to an integer type with $rtoi. The following code runs without errors for me:
module tst;
parameter clkspd=12000000;
parameter baudrate=115200;
localparam bitperiod = $rtoi($floor(clkspd/baudrate-0.5));
localparam bittmrwidth=$clog2(bitperiod);
initial begin
$display("Hello World!");
$display("width=%d",bittmrwidth);
end
endmodule
/*
Output:
Hello World!
width= 7
*/
My original code used a cast operator, but apparently yosys does not yet support it, according to the Comment below. Here was my original line:
localparam bitperiod = int'($floor(clkspd/baudrate-0.5));

Resources