Verilog/SV conditional variable definition - verilog

Is there a way to manipulate variable instantiation depending on a parameter?
For example, here if I were to put just bit [WIDTH-1:0] a; and set DEPTH == 1, WIDTH would be 0 and bit [-1:0] a; would not make sense.
When I code it like in the example below I get an error on the second $display: "Undeclared identifier: a". Is there a way to achieve this in Verilog/SV or is there an error in my code?
module test #(
parameter DEPTH = 2,
parameter WIDTH = $clog2(DEPTH)
)();
generate
if (WIDTH == 0) begin
bit a;
end else begin
bit [WIDTH-1:0] a;
end
endgenerate
initial begin
$display("WIDTH: %d", WIDTH);
$display("Bit width of a: %d", $bits(a));
end
endmodule: test

All you need to do is
bit [(WIDTH>0 ? WIDTH-1 : 0):0] a;

Which version of Verilog are you using? $clog2 was introduced in Verilog-2005. Prior implementations, can give odd results.
See below, I did a loop to show incrementing depth versus result of clog2.
CLOG2(0) = 0
CLOG2(1) = 0
CLOG2(2) = 1
CLOG2(3) = 2
CLOG2(4) = 2
To represent the value of 1, for instance, you need 1 bit, not 0
To represent the value of 2, you need 2 bits...not 1.
To represent the value of 4, you need 3 bits. CLOG2 is always 1 short at the transition points. The prior solution will not account for that as you grow.
So if you say
WIDTH = $clog(DEPTH+1);
I think you will automatically get the results you want.

I made & use this on a regular basis. It determines the width in bits of an integer value. Special case of 0 will return a value of 1 (you still need 1 bit to hold the value). Let's say you need to define an index variable based on memory that has 256 addresses
parameter NUM_ADDR 256
localparam A_SZ = bit_size(NUM_ADDR-1); // example: 255 (highest address) should return 8
logic [A_SZ-1:0] index; // example: [7:0] index
Then All I ever need to change is NUM_ADDR
function integer bit_size;
input integer value;
reg [31:0] shifted;
integer res;
begin
if (value != 0)
begin
shifted = value;
for (res=0; (shifted != 0); res=res+1)
shifted = shifted >> 1;
bit_size = res;
end
else
bit_size = 1; // minimum size, even for a value of 0
end
endfunction

Related

How the for loop works in this case?

As title. I'm quite unsure how the for loop would help to count the number of 1's in the input.
always #(*)
begin
for ( int i= 0 ;i< 255 ;i++ )
out = out + in[i];
end
If my input is 1001, out = out + in[1001]. So how can it count the number of 1's in this case?
Thank you
Assuming your input in is defined something like input [254:0] in then you would never have in[1001] as in is indexed on i that goes from 0 to 254.
As long as out is at least 8 bits, this should calculate the number of 1s in the input though not very efficiently for hardware as it's describing a long chain of 1-bit adders starting from in[0] + out to in[254] + out where the output of the previous adder is fed into the next. There is also an error as you need to initialize out to 0 or your loop will run forever as the always block depends on both in and out in its current implementation.
The main problem with your code is it doesn't initialize out. Without resetting out to zero, any change to in will only increment out; potentially overflow and keep adding.
The question is tagged as Verilog, but it is using SystemVerilog syntax. There proper Verilog way of writing this code would be:
integer i; // 'int' is a SystemVerilog keyword
always #(*)
begin
out = 0; // <-- initialize to zero
for ( i = 0 ; i < 255 ; i=i+1 ) // Verilog doesn't allow decelerating 'i' here or '++'
out = out + in[i];
end
With SystemVerilog, it can be written as bellow. Modern Verilog simulations are SystemVerilog simulations. The preferred way to enable the feature is changing the file extension from .v to .sv
always_comb
begin
out = '0; // <-- fill with zeros
for ( int i = 0 ; i < 255 ; i++ ) // or: foreach(in[i])
out += in[i];
end

Verilog Minimum Bit Width

I'm looking for a clean way to declare Verilog/SystemVerilog types with a parameterised bit width. This is what I've got so far and was wondering if there is a better way to do it. I've looked through the system functions in the LRM 1800-2009 and -2017. The closest I could find is $bits, but I would like something like $minbits. Have I overlooked something?
In VHDL, it's done by simply specifying the range:
signal counter: integer range 0 to MAX_COUNT;
...and the compiler will calculate the minimum bit width to hold that range.
For the parameter values of 20 ns and 125 ms, the counter should be 23 bits with MAX_COUNT being 6,250,000.
module Debounce
#(
parameter CLOCK_PERIOD_ns = 20, // nanoseconds.
parameter DEBOUNCE_PERIOD_ms = 125 // milliseconds.
)
. . .
function int MinBitWidth([1023:0] value);
begin
for (MinBitWidth = 0; value > 0; MinBitWidth = MinBitWidth + 1)
begin
value = value >> 1;
end
end
endfunction
localparam MAX_COUNT_32BITS = DEBOUNCE_PERIOD_ms * 1_000_000 / CLOCK_PERIOD_ns; // Default type of 32-bits.
localparam COUNTER_BITS = MinBitWidth(MAX_COUNT_32BITS); // Calculate actual bit width needed.
typedef logic [COUNTER_BITS - 1 : 0] TCounter;
localparam TCounter MAX_COUNT = MAX_COUNT_32BITS; // Assign to a type of the actual bit width (truncation warning from Quartus).
localparam TCounter ONE = 1;
TCounter counter;
. . .
always #(posedge clock)
begin
. . .
if (counter == MAX_COUNT_32BITS - 1) // Synthesises a 32-bit comparer no matter how many bits are needed with unused bits tied to ground.
. . .
if (counter == MAX_COUNT - ONE) // Synthesises a 23-bit comparer as expected.
. . .
counter <= counter + 1; // Synthesises a 23-bit counter as expected.
. . .
counter <= counter + ONE; // Synthesises a 23-bit counter as expected.
Incorrect Algorithm
I considered $clog2 which is the correct way to obtain an address bus width from a RAM depth parameter. However, this is not the same as the minimum bit width of a value. Let me explain...
Consider a value of 4 which is 100 base-2 (3 bits wide).
The $clog2 algorithm calculates a value of 2, which is incorrect. It should be 3. The reason for this miscalculation is because $clog2 subtracts 1 from the value before it starts to compute the number of bits, i.e. 4 becomes 3, then it calculates the minimum bit width of the value 3, giving 2 bits. While this is mathematically correct for the ceiling of log base-2, it is not the bit width of the original value.
Here is the clogb2 algorithm from the LRM:
function integer clogb2;
input [31:0] value;
begin
value = value - 1; // GOTCHA!
for (clogb2 = 0; value > 0; clogb2 = clogb2 + 1) begin
value = value >> 1;
end
end
endfunction
Correct Algorithm
The correct algorithm is to calculate the minimum bit width of the original value, which is the algorithm given by #jonathan-mayer in his first answer before he edited it.
Here is the correct algorithm as a function:
function integer MinBitWidth;
input [1023:0] value;
begin
for (MinBitWidth = 0; value > 0; MinBitWidth = MinBitWidth + 1)
begin
value = value >> 1;
end
end
endfunction
Just do +1 to get correct values for powers of 2.
$clog2(MAX_COUNT_32BITS + 1);
$clog2 from IEEE Std 1800-2017, section 20.8.1 Integer math functions:
The system function $clog2 shall return the ceiling of the log base 2
of the argument (the log rounded up to an integer value).
module tb;
parameter CLOCK_PERIOD_ns = 20; // nanoseconds.
parameter DEBOUNCE_PERIOD_ms = 125; // milliseconds.
localparam MAX_COUNT_32BITS = DEBOUNCE_PERIOD_ms * 1_000_000 / CLOCK_PERIOD_ns; // Default type of 32-bits.
localparam COUNTER_BITS = $clog2(MAX_COUNT_32BITS); // Calculate actual bit width needed.
initial begin
$display("MAX_COUNT_32BITS = %0d, COUNTER_BITS = %0d", MAX_COUNT_32BITS, COUNTER_BITS);
end
endmodule
Outputs:
MAX_COUNT_32BITS = 6250000, COUNTER_BITS = 23

How to dynamically change value assigned to a vector register

I am a newbie to verilog coding. In my problem statement, I will get number of entries in a sorted table from another module and based on number of entries I need to decide where should I start my binary search
(e.g. Let num_entries be 15, then start index should be 8). Code snippet is given below:
srch_addr <= {{(TBL_AW-msb_loc(num_entries)-1){1'b0}},2'b10, {(msb_loc(num_entries)-1){1'b0}}};
//function to find out MSB 1
integer LOC;
function [3:0] msb_loc;
input [TBL_AW:0] num_entries;
reg found;
//input start;
begin
//if(start = 1)
//begin
found = 1'b0;
msb_loc = 3'b000;
for (LOC=TBL_AW; LOC> 0; LOC=LOC-1)
begin
if((num_entries[LOC] == 1) && !found)
begin
msb_loc = LOC;
found = 1'b1; //TO exit the loop
end
end
//end
end
endfunction
Compiler gives me this error "Illegal operand for constant expression". What can be done to resolve this error?
The replicator 'count' value must be a non-zero, non-X and non-Z constant expression.
{(TBL_AW-msb_loc(num_entries)-1){1'b0}}
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This is not a constant.
To get the 'halfway' address you can just the standard mathematical way: divided and round upwards. In this case add one and divide by two:
srch_addr <= (msb_loc(num_entries)+1)>>1;
Coming back to your formula. This part just makes zeros: {(TBL_AW-msb_loc(num_entries)-1){1'b0}} You don't need that.
This part 2'b10, {(msb_loc(num_entries)-1){1'b0}} actually shifts 2'b10 left by "(msb_loc(num_entries)-1)" positions.
This does the same but then without syntax errors:
srch_addr <= 1'b1 << msb_loc(num_entries);
What I can see it does NOT give you the half-way address.
Further:
Your integer LOC; should be inside your function as a local variable.

Calculating a parameter in a loop generate block

I have an array of parameters WIDTHS, and I need to calculate another parameter RIGHT based on some values in WIDTHS in a generate block. Is this possible? If not, is there an alternative way?
Here is an example of what I am trying to do. Suppose we have a predefined register module REG which has inputs d, q, we (write enable), CLK and _RESET. I would like to create a new module called GroupReg, which instantiates N instances of REG. Each instance has a different width (hence the WIDTH parameter array). The d, q, and we of each group are aggregated in arrays with the same name in GroupReg and need to be specified for each instance. Specifying we is easy (we[i]) since it is only one bit. However, specifying d and q with the correct LEFT and RIGHT values is where I have problem with since each group has a different width.
Looks like the only way to assign a value to a parameter is upon its definition, which prevents assigning a value to it in a generate loop.
module GroupReg(d, q, we, CLK, _RESET);
parameter N = 4; //Number of groups
//INDICES has to have N+1 members. Last member should be 0
parameter integer WIDTHS [N:0] = {40, 30, 20, 10, 0};
parameter integer DW_TOTAL = 128;
input logic [DW_TOTAL-1:0] d; // Data Input
input logic [N-1:0] we; // write enable
input logic CLK; // Clock Input
input logic _RESET; // Reset input (active low)
output logic [DW_TOTAL-1:0] q; // Q output
genvar i, j;
for (i=N-1 ; i>=0 ; i--) begin:REGISTERS
localparam WIDTH = WIDTHS[i];
localparam LEFT = RIGHT + WIDTHS[i];;
localparam RIGHT = 0;
for (j = 0 ; j<i ; j++) // <<----- Does not work
RIGHT = RIGHT + WIDTH[j];
REG #(
.DW (WIDTH),
)
reg_i
(
.d(d[LEFT:RIGHT]),
.q(q[LEFT:RIGHT]),
.we(we[i]),
.CLK(CLK),
._RESET(_RESET)
);
end : REGISTERS
endmodule
I tried using the sum() array reduction method on WIDTHS and it worked in Aldec Riviera PRO:
module some_module;
parameter N = 4; //Number of groups
parameter integer WIDTHS [N:0] = '{40, 30, 20, 10, 0};
parameter integer DW_TOTAL = WIDTHS.sum();
initial begin
$display("DW_TOTAL", DW_TOTAL);
end
endmodule
If you're lucky it's going to work in your simulator too.
I anyway don't really get what you're trying to do making N a parameter, seeing as how you're anyway hardcoding a fixed number of values for the widths.
This works in Modelsim:
module some_module;
parameter N = 4; //Number of groups
parameter integer WIDTHS [N:0] = '{40, 30, 20, 10, 0};
genvar i;
for (i=N-1 ; i>=0 ; i--) begin
localparam integer FOO[i:0] = WIDTHS[i:0];
//localparam RIGHT = FOO.sum();
initial begin
foreach (FOO[i])
$display("FOO[%0d] = %h", i, FOO[i]);
end
end
endmodule
The FOO parameter would only store the relevant entries from WIDTH for a specific loop iteration. If sum() would work, you'd be home free. The slicing syntax doesn't work in Riviera, however.
This is a typical example of vendors interpreting the standard differently, basically because it's not specific enough. Still, if you use a simulator from a different EDA company, try combining the two answers; maybe you're lucky and it works.

Verilog - generate weighted random numbers

I am trying to generate random single bits and this is simple as long as you want a normal randomization:
wire R;
assign R = $random % 2;
What I am looking for is a sort of weighted probability like:
wire R;
assign R = 60%(0) || 40%(1);
Forgive me if it is not conform to standard Verilog code, it is just to give an idea of what I want.
Can anyone help me out?
Thank you
The SystemVerilog solution has a distribution method within randomize called dist. Weights are assigned by value_or_range := weight or value_or_range :/ distributed_weight. This exert from the IEEE Std 1800-2012 § 18.5.4 page 476 gives a clear example:
When weights are applied to ranges, they can be applied to each value in the range, or they can be applied to the range as a whole. For example:
x dist { [100:102] := 1, 200 := 2, 300 := 5}
means x is equal to 100, 101, 102, 200, or 300 with a weighted ratio of 1-1-1-2-5, and
x dist { [100:102] :/ 1, 200 := 2, 300 := 5}
means x is equal to one of 100, 101, 102, 200, or 300 with a weighted ratio of
1/3-1/3-1/3-2-5.
dist is used in randomization so it needs to be mare of a randomize() with (or a class constraint). randomize returns a success bit, therefore it should be in called within an assert, void'(), or the RHS of an assignment.
In your we can set the weight of 0 to 6 and the weight of 1 to 4, creating a total weight of 10 with a 60/40 distribution. Example:
reg R;
initial begin
assert( randomize(R) with { R dist { 0 := 6, 1 := 4 }; } );
end
From more about dist see IEEE Std 1800-2012 § 18.5.4 "Distribution".
Create a random integer then based on Value return 1 or 0; NB you may want to seed your random number, for repeatability use the same seed. This way when a test fails it can be debugged.
$urandom works a little different to $random it doe not update the seed value so should only be seeded the first time it is called in a thread (always block). It is also thread safe, each always block works independently.
initial begin
$urandom(seed);
$urandom;
$urandom;
end
integer temp;
reg r ;
always # ... begin
temp = $urandom; //Range: +2_147_483_647 -2_147_483_648
// weighting; 0 would be 50:50
// real weighting is (0.1 + 0.5), 0.5 inherent from positive number.
r = (temp > (2_147_483_647*0.1);
end
NB: the random functions are not synthesizable and should only be used for testbenches. if you want a random number for synthesis check out this Question
For Verilog you can always so something like:
integer R;
R = ($dist_uniform(0,100) < 60) : $dist_uniform(0,5) : $dist_uniform(6,10)
and this in SystemVerilog would be the same as:
std::randomize(R) with {R dist {[0:5] :/60, [6:10] :/ 40} ;};
You could also do this procedural code:
randcase
60: R = 1;
40: R = 0;
endcase
Following Code Will Generate Random Variable as Per Your Requirement :
program top;
class Packet;
rand reg R;
constraint percentage {R dist {1:=60,0:=40};};
function void display;
$display("Random Reg : %0d",this.R);
endfunction
endclass
Packet P;
initial
begin
P = new;
repeat(10)
begin
P.randomize();
P.display;
end
end
endprogram
It seems not so hard at verilog.
reg [7:0] R;
reg rand_bit;
R = $random();
if (R < 76)
rand_bit = 1'b0;
else
rand_bit = 1'b1;
Here I assume that $random is pretty uniform. I think it should work :)
Something like:
wire R;
if ($random[7:0]>(40*255/100))
assign R = 1'b0;
else
assign R = 1'b1;
I'm assuming that the algorithm that $random uses produces numbers that are equally random whatever bits you take from it.

Resources