verilog: how do I add parameters - verilog

I want to have parameterized module. It has the following definition:
module example (...);
parameter A = 2;
parameter B = 2;
parameter C = A + B;
endmodule
However, when I print out the parameter values, I get A = 2, B = 2, and C = 1... Any ideas why?

Found a solution - use localparam.
module example (...);
parameter A = 2;
parameter B = 2;
localparam C = A + B;
endmodule

Related

Modifying variables inside generate statements

I am trying to write the Verilog code for a multiplexer module, that has a parametrized number of inputs. I am aware that you can pack the inputs together and use the select input to slice that packed variable but I want to use a binary tree structure for my multiplexer.
The problem lies in using auxiliary variables to properly index inner wires (interm_w), meaning I need to be able to modify certain integer variables after each iteration of my inner for loop, but I don't know how. These variables include P, M, and K.
module multiplexer_v2(input_data_array, select, output_data);
parameter WIDTH = 16;
parameter NUMBER_OF_INPUTS = 8;
parameter SELECT_WIDTH = $clog2(NUMBER_OF_INPUTS);
localparam INTERMEDIATE_WIRES_COUNT = interm_value(SELECT_WIDTH, NUMBER_OF_INPUTS); // this is a function, that works correctly.
input [SELECT_WIDTH-1:0] select;
input [WIDTH-1:0] input_data_array [0:NUMBER_OF_INPUTS-1];
output [WIDTH-1:0] output_data;
wire [WIDTH-1:0] interm_w [0:INTERMEDIATE_WIRES_COUNT-1];
genvar i;
genvar j;
int K = NUMBER_OF_INPUTS / 2;
int M = NUMBER_OF_INPUTS;
int P = 0;
generate
for(i = 0; i < SELECT_WIDTH; i=i+1) begin
for(j = 0; j < K; j=j+1) begin
multiplexer_2_input #(
.WIDTH(WIDTH)
) mux_i (
.input_0(interm_w[P + j * 2]),
.input_1(interm_w[P + j * 2 + 1]),
.select(select[SELECT_WIDTH - i - 1]),
.output_data(interm_w[M + j])
);
end
P = M; // line 51 is here
M = M + K;
K = K / 2;
end
endgenerate
endmodule
I have tried using datatypes such as localparam, int, integer, parameter, and genvar for these variables, and moving around their initialization, but I face the same errors each time:
** Error: (vlog-13069) .../multiplexer_v2.sv(51): near "=": syntax error, unexpected '='.
** Error: .../multiplexer_v2.sv(51): (vlog-13205) Syntax error found in the scope following 'P'. Is there a missing '::'?
I would greatly appreciate any help I can get.
The interm_value() function is as follows:
function int interm_value(input int select_width, input int number_of_inputs);
begin
int i;
int interm_value;
int K;
interm_value = 0;
K = number_of_inputs;
for(i = 0; i < select_width; i=i+1) begin
interm_value = interm_value + K;
K = K / 2;
end
return interm_value + 1;
end
endfunction
The reason for the syntax errors is that variables require procedural assignments (from within an always block, for example). But, you are not doing that.
One approach to debugging problems associated with generate for loops is to manually unroll the loop.
In your code, the outer loop iterates 3 times. Removing the loop code, you are left with these assignments for M and P:
int M = NUMBER_OF_INPUTS;
int P = 0;
P = M;
P = M;
P = M;
M = M + K;
M = M + K;
M = M + K;
Those assignments should be inside a procedural block. Also, as you can see, it doesn't make much sense to assign the same value to P multiple times.
With that explanation, I recommend trying to design something simpler without the loops at first.

how to get the size of a parameter/number in bits?

I want to create an array in Verilog with a size based on a number of parameters.
I tried this code in ModelSim, but I got the following error:
Parameter value must be constant.
localparam a = 250;
localparam b = 480;
localparam m = a * 100 / (b * 2);
localparam s = $bits(2 * m);
To calculate the number of bits needed to hold the value in verilog you can use the $clog2 function. something like the following will provide the number of bits for 2 * m. The only caveat is when m == 0. You need at least one bit to hold 0.
localparam s = m == 0 ? 1 : $clog2(2 * m);
It help when you give complete runnable examples with the command used to run the example.
module top;
localparam a = 250;
localparam b = 480;
localparam m = a * 100 / (b * 2);
localparam s = $bits(2 * m);
endmodule
vlog file.v
$bits is not defined in Verilog, so the compiler thinks this is a user defined run-time function. You won't get that error if you change the file extension to .sv.

Selecting a set of parameters based on input value in Verilog

I am working on a Module which changes it's constant values based on the input to calculate it's output.
Let me illustrate what I am looking for,
Let x be the input, y the output and a,b,c,d,e the set of constants.
Module performs something like the following operation:
y=(a*x)+(b*x)+(c*x)+(d*x)+(e*x); //separate adder and multiplier modules are used and this code itself is huge so just providing the idea.
Now I have used following method to choose the right value for the constants depending on the input: (Pseudo code)
module top (x,clk,y);
input clk;
input [31:0] x;
output [31:0] y;
if (x>=32'h08000000 && x<32'h0A000000) begin
localparam a = 32'h058B90C0;
localparam b = 32'h193C9F60;
localparam c = 32'h29AC1740;
localparam d = 32'hA48B9440;
localparam e = 32'h0B6392E0;
end else if (x>=32'h0A000000 && x<32'h0C000000) begin
localparam a = 32'h028A50C1;
localparam b = 32'hE98B489C;
localparam c = 32'h17402948;
localparam d = 32'h9440E45B;
localparam e = 32'h392E00AF;
end
y=(a*x)+(b*x)+(c*x)+(d*x)+(e*x); // Module that computes using any of the above mentioned constant sets
endmodule
I get the following errors:
(1) "Unable to bind parameter".
(2) "Cannot evaluate genvar conditional expression: ((x)G(32'000010000....00))&& so on......"
My question is:
My user will give the input through x, right constants will be chosen, my module will calculate and provide the output. Just providing the right constants to the module is enough. How shall I do it? Ideas through pseudo code will be helpful for me.
I had to look up where localparam is allowed. You can define a localparam after a begin : < label >.
I tried it and found that (at least in Vivado) it passed and worked.
always #( a )
if (a>=1)
begin : a_be_1
localparam P1 = 3;
c = P1;
end
else
begin : a_sm_1
localparam P1 = 5;
c = P1;
end

Verilog assigning multiple reg's or wire's to the same value

How can I assign multiple reg's to the same value with more condensed code? This is the code that I want to improve:
a = 0;
b = 0;
c = 0;
d = 0;
e = 0;
you can use left-hand concats
The following example shows how to do it.
reg a,b,c,d,e;
initial begin
{a,b,c,d,e} = 5'b0;
end
there is no other more 'condenced' way, unless you use an array.
reg [4:0] var;
...
var = 5'b0;
or for multi-dimensional unpacked arrays you can use loops
reg [1:0] var [4:0];
...
for (i = 0; i < 5; i++) var[i] = 0;
If all the variables have the same bit-width, and therefore the values you want assigned to those variables have the same bit-width, you can do a replication concatenation:
{a,b,c,d,e} = {5{value}};

Generate block is not assigning any values to wire

Im new to verilog, and Im trying to write certain multiplier, but when I run my testbench it doesn't show much. It looks like generate block does not assign any values to partial. Here is a screen:
And code:
Changed names in code, so it is more familiar for english users.
`timescale 1ns/1ps
`ifndef N_WIDTH
`define N_WIDTH 8
`endif
module mult(datX, datY, result);
parameter n = 8;
input [n-1:0] datX, datY;
output [2*n-1:0] result;
//assign datX = 8'b0;
//assign datY = 8'b0;
wire [n-1:0] partial;
genvar i;
generate
for(i=0; i<n; i=i+1) begin: IloczynyCzesciowe
if(i<7) assign partial[7:i] = datY[n-1-i:0];
if(i==1) assign partial[0] = datY[7];
if(i==7) assign partial[7] = datY[0];
if(i>1) assign partial[i-1:0] = datY[n-1:n-i];
assign partial = datX[i] * partial;
assign result = result + (partial % (2^n-1));
end
endgenerate
endmodule
module testbench_mul;
parameter n = 8;//`N_WIDTH;
parameter clk_period = 2;
reg clk, clk_ena;
reg [n-1:0] a,b;
wire [2*n-1:0] res;
reg [2*n-1:0] res_expected;
initial begin
a = 8'b00000001;
b = 8'b00001111;
#clk_period;
clk = 0;
clk_ena = 1;
$display("actual_s = %d", a );
res_expected = a + b;
end
always begin
#clk_period;
if (clk_ena)
clk = ~clk;
end
mult #(.n(n)) UUT (.datX(a), .datY(b), .result(res));
always #(posedge clk) begin
a = a + 1;
res_expected = a+b;
#1;
if (res != res_expected) begin
$display("ERROR: a: %b, b: %b, sum:%b, expected:%b partial:%d", a,b,res, res_expected, UUT.partial);
end
end
initial
#200 $finish;
endmodule
Please tell me what I'm doing wrong.
The generate block is assigning to partial and result, however there are multiple drivers to the same wire. Generate block expands the code at compile time. When Executed it will be the equivalent to the following:
// loop n=0
assign partial[7:0] = datY[n-1-0:0];
assign partial = datX[0] * partial;
assign result = result + (partial % (2^n-1));
// loop n=1
assign partial[7:1] = datY[n-1-1:0];
assign partial[0] = datY[7];
assign partial = datX[1] * partial;
assign result = result + (partial % (2^n-1));
// loop n=2
assign partial[7:2] = datY[n-1-2:0];
assign partial[2-1:0] = datY[n-1:n-2];
assign partial = datX[2] * partial;
assign result = result + (partial % (2^n-1));
// loop n=3
assign partial[7:3] = datY[n-1-3:0];
assign partial[3-1:0] = datY[n-1:n-3];
assign partial = datX[3] * partial;
assign result = result + (partial % (2^n-1));
// loop n=4
assign partial[7:4] = datY[n-1-4:0];
assign partial[4-1:0] = datY[n-1:n-4];
assign partial = datX[4] * partial;
assign result = result + (partial % (2^n-1));
// loop n=5
assign partial[7:5] = datY[n-1-5:0];
assign partial[5-1:0] = datY[n-1:n-5];
assign partial = datX[5] * partial;
assign result = result + (partial % (2^n-1));
// loop n=6
assign partial[7:6] = datY[n-1-6:0];
assign partial[6-1:0] = datY[n-1:n-6];
assign partial = datX[6] * partial;
assign result = result + (partial % (2^n-1));
// loop n=7
assign partial[7] = datY[0];
assign partial[7-1:0] = datY[n-1:n-7];
assign partial = datX[7] * partial;
assign result = result + (partial % (2^n-1));
Conflicting assignment values will cause the output to be X and having an assignment that feedback on self without a way to break the loop will also always be X.
An always block can be used instead. Part select cannot have variables (e.g. [7:i]), so you need to assign all of the bits at once or assign each bit. This is equivalent to generate code:
reg [2*n-1:0] result;
reg [n-1:0] partial;
integer i;
always #* begin
result = 0;
for(i=0; i<n; i=i+1) begin: IloczynyCzesciowe
// partial[7:0] = {datY,datY} >> (8-i); // this functional also works
for(j=0; j<n; j++) begin : assign_bits
partial[j] = datY[(8+j-i)%8];
end
partial = datX[i] * partial;
result = result + (partial % (2^n-1));
end
end
Note: The multiplier function does work as expected. It is outside the scope of the question to solve it.

Resources