How the for loop works in this case? - verilog

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

Related

Initialize and increment a genvar variable inside nested for loop of system verilog

I'm trying to write a synthesizable code in .sv to meet my requirements, but got stuck at the very end without a solution;
I've an incoming wire which is 99 bit wide and 10 (MAX) deep
I need to feed this to a module and get its output which is 99 bit
the output needs to be assigned to an array (99 bit wide ) from 0 .. max
I can't paste the snippet, but this is what I've coded:
--
param MAX = 10;
param TOT_INST = 45 ;
wire [98:0] inwire [MAX-1:0] ;
wire [98:0] outwire [TOT_INST-1:0]
genvar x,y,z ;
generate
for (x = 0, z=0; x<=MAX-1; x=x+1, z=z+1 )
begin : gen1
for (y = x + 1; y<=MAX-1; y=y+1)
begin : gen2
some_module mod_inst ( .in1(inwire[x]), .in2(inwire[y]), .y(outwire[z]) );
end
end
endgenerate
--
The expectation is to get outwire[0] to be an output of inwire[0] and inwire[1], outwire[1] to be a function of inwire[0], inwire[1] etc. So, it becomes necessary to increment the index of outwire.
I used another genvar z for this purpose (to increment from 0 to 44). But, it looks like the SV doesn't support multiple genvar variables to be incremented? im getting compilation error at the for loop itself.
Is there any way to achieve what i need? I really appreciate you taking time to go through this question. Any insight would be really helpful.
Thanks
Jr.
I understand your intent. It seems you are trying to use comma expressions, but they wont work here.
Also, it seems that the genvar can only be assigned in the initialization and increment of the for loop, otherwise it would be easy to increment them on the innermost loop.
Since you must have unique drivers to the outwires, and the number of entries you declared (45) matches the number of instances you will create I assume you simply want them to be set incrementally.
What I would do is to calculate the number of iterations algebraically and create a local parameter. If you can't see how, review triangular numbers.
parameter MAX = 10;
// Generalizing your TOT_INST
parameter TOT_INST = MAX * (MAX - 1) / 2 ;
wire [98:0] inwire [MAX-1:0] ;
wire [98:0] outwire [TOT_INST-1:0];
genvar x,y;
generate
for (x = 0; x <= MAX-1; x = x + 1 )
begin : gen1
for (y = x + 1; y<=MAX-1; y=y+1)
begin : gen2
localparam z = TOT_INST - ((MAX - x - 2) * (MAX - x - 1)) / 2 + y - MAX;
initial begin
$display("%d %d %d", x, y, z);
end
end
end
endgenerate
The formula would be simpler if we used the x in the inner loop.

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.

How to have a binary number with constant lenght

I'm trying to write a test_bench for a dynamic size register.
I defined a parameter variable like this and instantiated a register module:
parameter integer regSize = 8;
register #(.size(regSize)) R1 (
.clock(clk),
.reset(rst),
.enable(enb),
.regIn(in),
.regOut(outp)
);
now forexample I want to define "in" variable ( the 4th input of module )
reg [regSize - 1: 0] in = (regSize)'b0;
I expect this works as : reg [regSize - 1: 0] in = 8'b0;
But it doesn't.
I get this error:
near "'b": syntax error, unexpected BASE, expecting ';' or ','
How should I write this?
Thanks for any help.
Use the concatenation repeat structure:
reg [regSize - 1: 0] in = {regSize{1'b0}};
Or in System Verilog you can do :
reg [regSize - 1: 0] in = '0;
You might also need something similar for adding e.g. 1 to a counter with variable length:
...
counter <= counter + {{(regSize-1){1'b0}},1'b1}; // regSize>1!
As that becomes difficult to read I prefer to use a localparam :
localparam [regSize-1:0] value_1 = {{(regSize-1){1'b0}},1'b1}; // regSize>1!
...
counter <= counter + value_1;
Note that it can get rather messy if you also want to have a width of 1 bit as but I assume adding 1 to a 1 bit counter is likely to be a design error.
There is no need to pad 0's to a number in Verilog, it does that automatically for you. You can just do
reg [regSize - 1: 0] in = 0;

Verilog/SV conditional variable definition

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

How do I add 1 to a 4 bit wire in Verilog

This seems like it would be simple, but I can't find out how to do this anywhere... All I want to do is add 1 to a 4 bit wire.
Overall, I want to count the number of 1's in a 8 bit variable. Let's call this input inA. The output will be outA. Both are defined as wires; inA is 8 bits where outA is 4 bits.
wire[0:7] inA;
wire[0:3] outA;
I can do a for loop to go through the array:
for (i = 0; i <= 7; i = i + 1) begin
if (inA[i] == 1) begin
outA <= outA + 1;
end
end
But this isn't working.
Can someone please help? I am extremely new to Verilog (and VHDL), so I really have no clue what I am doing wrong.
There are a few ways to do this, here is one option:
reg [0:3] ones;
integer i;
always # (inA) begin
ones = 0;
for (i = 0; i < 8; i = i + 1) begin
ones = ones + inA[i];
end
end
assign outA = ones;
Since you haven't provided your full source code (e.g. the context of the for loop), we can only guess what the problem with that is.
Remember though that non-blocking assignments like outA <= outA + 1 will be scheduled to be executed at the end of the always block, such that the last assignment will override all previous ones.
Since outA (which by the way will have to be a reg if your for loop is embedded in an always block), is only updated after the always block has finished "executing", only inA[7] can cause an increment to outA.
Have a look at my answer here for further information on how always blocks are executed.

Resources