Initialize parameter from array - verilog

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.

Related

Utilization of parameters in 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);

Proper way to use a bus in a for loop in SystemVerilog?

I'm trying to make a module in SystemVerilog that can find the dot product between two vectors with up to 8 8-bit values. I'm trying to make it flexible for vectors of different length, so I have an input called EN that's 3 bits and determines the number of multiplications to perform.
So, if EN == 3'b101, the first five values of each vector will be multiplied and added together, then output as a 32-bit value. Right now, I'm trying to do that like:
int acc = 0;
always_comb
begin
for(int i = 0; i < EN; i++) begin
acc += A[i] * B[i];
end
end
assign OUT = acc;
Where A and B are the two input vectors. However, SystemVerilog is telling me there's an illegal comparison being performed between i and EN.
So my questions are:
1) Is this the proper way to have a variable vector "length" in SystemVerilog?
2) If so, what's the proper way to iterate n times where n is the value on a bus?
Thank you!
I have to guess here, but I'm assuming it's a synthesizer complaining about that code. The synthesizer I use accepts your code with minor modifications, but maybe not all do since the loop can't be unrolled statically (notice I have input logic [2:0] EN, maybe input int EN does not work due to having too big a max number of cycles). Your loop per se (question #2) is fine.
int acc;
always_comb
begin
// If acc is not reset always_comb tries to update on its old value and puts
// it in sensitivity list, halting simulation... also no initialization to variable
// used in always_comb is allowed.
acc = 0;
...
This is a somewhat decent reason to complain about your otherwise perfectly good code, and the tool does not make the assumption that it is "reasonable" to generate all possible loops in this specific case (if EN was an unsigned integer your chip would be stupidly huge after all): you can force the tool to infer all possibilities with something that looks like the following:
module test (
input int A[8],
input int B[8],
input logic [2:0] EN,
output int OUT
);
int acc[8]; // 8 accumulators
always_comb begin
acc[0] = A[0] * B[0]; // acc[-1] does not exist, different formula!
for (int i = 1; i < 8; i++) begin
// Each partial sum builds on previous one.
acc[i] = acc[i-1] + (A[i] * B[i]);
end
end
assign OUT = acc[EN]; // EN used as selector for a multiplexer on partial sums
endmodule: test
The above module is an explicit description of the "parallel loop" my synthesizer infers.
Regarding your question #1, the answer is "it depends". In hardware there is no variable length, so unless you fix the number of iterations as a parameter as opposed to an input you either have a maximum size and ignore some values or you iterate over multiple cycles using pointers to some memory. If you want to have a variable vector length in a test (not going to silicon) then you can declare a "dynamic array" that you can resize at will (IEEE 1800-2017, 7.5: Dynamic arrays):
int dyn_vec[];
As a final side note, int bad integer good for everything that is not testbench in order to catch X values and avoid RTL-synthesis mismatch.

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);

generating random the same numbers in verilog issue

I'm trying to generate the random numbers in verilog in verilog.
But the Problem is when I re-run the simulation, that random value is fixed.
so previous simulation value and current simulation random value are the same.
reg [20:0] temp;
integer seed;
reg [31:0] rand;
initial fork
seed = $random;
for (i=0; i<10; i=i+1)begin
temp = $random(seed) %10 ;
end
wait(verif_fcnt == 3) begin
temp = $random(seed) %10 ;
task1(temp[0],temp[7:0]);
end
wait(verif_fcnt == 3) begin
temp = $random(seed) %10;
task2(temp[0],temp[7:0]);
end
wait(verif_fcnt == 3) begin
temp = $random(seed) %10;
task3(temp[0],temp[7:0]);
end
join
In order to reproduce a bug, you want to 'control' the randomness. So that is something you want most of the time.
The $random system call is constrained by seed. When a seed is give the random calls will give the same sequence.
I would advise you to keep the seed parameter and generate it by a $random call (without seed). Just be sure to print the seed variable used in case you stumble upon a bug.
Instead of:
seed = 0;
Use:
seed = $random;
$display("Seed used: %d",seed);
EDIT
Seed value can also be set in the simulation command-line.
In NCsim for example, it is the -seed integer option that sets it.
In this case, you can add in your simulation script:
#!/bin/bash
export SEED=$RANDOM
echo "Seed used: $SEED"
ncsim ...various command line options... -seed $SEED
EDIT 2
Verilog actually behaves (by default) like constant a seed is given so you can reproduce bugs (see here).
To manually pass a seed in Verilog source, you will have to use $srandom(seed) to initialize the seed of the next random calls. Then you should use $urandom instead of $random (see here)
To generate the inital seed, I would try to use $urandom before setting the seed.
integer seed;
initial begin
seed = $urandom();
$srandom(seed);
end
//**
... tests with $urandom() calls
**//
IMHO, It will finally be simpler to use the command line option.

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