In Verilog, how do I use a variable in logic - verilog

Say I have the following code:
genvar i,j;
generate
for(i = 0; i < MAX; i = i + 1) begin: gen_blah
for(j = 0; j < MAX; j = j + 1) begin: gen_foo
assign match[i] = entry[j] = i;
end
end
endgenerate
Is this a synthesizable expression? It seems like it should be since this will just unroll out into a bunch of compare-to-constant assignments. If not, how would I write this to accomplish that?

No. Imagine unrolling this and typing it out by hand. The fist two lines would cause a multiply driven net:
assign match[0] = (entry[0] == 0);
assign match[0] = (entry[1] == 0);
However, if you get rid of the generates and do this with loops inside an always block then it will work:
always_comb begin
for(int i = 0; i < MAX; i = i + 1) begin: gen_blah
for(int j = 0; j < MAX; j = j + 1) begin: gen_foo
match[i] = (entry[j] == i);
end
end
end
Inside this block you get multiple assignments to the same value but the last one "wins". I'm not sure what you are trying to accomplish with your code, so this might not actually perform the function you are looking for. If you are trying to see if any of the entries equal i then you should change it to:
always_comb begin
for(int i = 0; i < MAX; i = i + 1) begin: gen_blah
match[i]=0;
for(int j = 0; j < MAX; j = j + 1) begin: gen_foo
match[i] = match[i] || (entry[j] == i);
end
end
end

Related

How to loop for a variable amount in verilog?

In any hardware definition language, I know we can't declare a loop to loop over some circuits for some variable n times, instead we need to loop for a fixed value.
So I wanted to ask, if I have the following snippets of code:
I'm writing some sort of pseudocode in verilog, and this is an unfinished code.
input [7-1:0] note_switch;
reg[7-1:0] varnum[7-1:0];
reg[7-1:0] limit;
wire[7-1:0] numofhigh_switch;
check_high test (numofhigh_switch, note_switch);
always#(posedge octave) begin
if(octave) begin
for(count = 0; count < numofhigh_switch; count = count + 1) begin
varnum[numofhigh_switch + count] <= varnum[count] << 7;
end
end else begin
for(count = 0; count < numofhigh_switch; count = count + 1) begin
varnum[numofhigh_switch + count] <= varnum[numofhigh_switch + count];
end
end
end
I wanted to make something resembling like this, but again I know this will not work in a hardware description language, so how should I write so I can get the effect of rolling the for loop?
Actually, synthesis tools need to statically determine the maximum possible number of loops, not just a fixed number. You can do this a number of ways
Put the maximum into the conditional expression
for(count = 0; count < numofhigh_switch && count < 8; count = count + 1) begin
varnum[numofhigh_switch + count] <= varnum[count] << 7;
end
Use a conditional branching statement inside the loop
for(count = 0; count < 8; count = count + 1)
if (count < numofhigh_switch) begin
varnum[numofhigh_switch + count] <= varnum[count] << 7;
end
In SystemVerilog you can use a break statement.
for(count = 0; count < 8; count = count + 1) begin
if (count >= numofhigh_switch) break;
varnum[numofhigh_switch + count] <= varnum[count] << 7;
end

How to get rid of the error <variableName> is not constant while trying to do simple number comparison?

I am new to SystemVerilog and Basys3. I am trying to learn seven segment display. To do that, I wrote a simple demo which will do:
1- Take input from switches
2- From that Input, decide which seven segment output will be used with comparing numbers
3- Display on the seven segment display.
You can see my code.
module SevenSegmentNumber(input logic[3:0] inputFile, output logic [6:0] outputFile);
if (inputFile == 3'b000) begin
assign outputFile[6] = 0;
assign outputFile[5] = 0;
assign outputFile[4] = 0;
assign outputFile[3] = 0;
assign outputFile[2] = 0;
assign outputFile[1] = 0;
assign outputFile[0] = 1;
end
else if (inputFile == 3'b001) begin
assign outputFile[6] = 1;
assign outputFile[5] = 0;
assign outputFile[4] = 0;
assign outputFile[3] = 1;
assign outputFile[2] = 1;
assign outputFile[1] = 1;
assign outputFile[0] = 1;
end
else if (inputFile == 3'b010) begin
assign outputFile[6] = 0;
assign outputFile[5] = 0;
assign outputFile[4] = 1;
assign outputFile[3] = 0;
assign outputFile[2] = 0;
assign outputFile[1] = 1;
assign outputFile[0] = 0;
end
endmodule
assign outputFile[n] is hardcoded according to how seven segment display is work which I found on the Internet.
My problem here is I cannot compare whether input file is equal 0 or 1 or 2
Error message is:
inputFile is not constant
I also tried to code with form
inputFile == 0
inputFile == 1
inputFile == 2
Which did not solve my problems. How can I solve this problem?
Your error message informs you that the inputFile input port can not be used in that way because it is a variable type. Your code looks like it is using an implicit generate construct, which requires inputFile to be a constant type, such as a parameter.
One way to fix your code is to place your if/else statement inside a procedural block. Since you are describing combinational logic, you can use always_comb. In this case, there is no need to use the assign keyword.
module SevenSegmentNumber(input logic[3:0] inputFile, output logic [6:0] outputFile);
always_comb begin
outputFile = '0;
if (inputFile == 3'b000) begin
outputFile[6] = 0;
outputFile[5] = 0;
outputFile[4] = 0;
outputFile[3] = 0;
outputFile[2] = 0;
outputFile[1] = 0;
outputFile[0] = 1;
end
else if (inputFile == 3'b001) begin
outputFile[6] = 1;
outputFile[5] = 0;
outputFile[4] = 0;
outputFile[3] = 1;
outputFile[2] = 1;
outputFile[1] = 1;
outputFile[0] = 1;
end
else if (inputFile == 3'b010) begin
outputFile[6] = 0;
outputFile[5] = 0;
outputFile[4] = 1;
outputFile[3] = 0;
outputFile[2] = 0;
outputFile[1] = 1;
outputFile[0] = 0;
end
end
endmodule
Note that I initialized outputFile to 0 at the top of the block. This avoids inferring latches when synthesized. You can change 0 to be something more meaningful to your design (whatever your logic should do when the input is not 0, 1 or 2).

Two genvar in single genarte for loop?

Is below sort of generate loop is valid in system verilog.
genvar i,j;
for (i=0,j=5; i<5 && j<10; i++,j++) begin:M1
integer t;
initial begin
t = i*j;
end
endgenerate
Nope. I'm not even sure what the behavior of this code should be, or in what order they execute.
genvar i,j;
for (i = 0; i <5; i++) begin
for (j = 5; j < 10; j++) begin
$display("%d", i*j);
end
end
you don't need 'endgenerate' in the end.
You cannot do much with genvars in your example.
The following code mimics what you asked for, but it might not work with all simulators. It works with synopsys vcs but does not work with icarus.
module g;
genvar i;
for (i=0; i<5; i++) begin:M
if (i == 0) begin:B
parameter j = 5;
end
else begin:B
parameter j = g.M[i-1].B.j + 1;
end
integer t;
initial begin
t = i*B.j;
$display(i, B.j, t);
end
end // block: M
endmodule // g
the idea is to declare the parameter j inside the generate loop so that its value is an increment of the value declared in the previous iteration. You need to add a named block 'B' to declare conditionally.

Conditional increment in generate block

I want to create 256 instances of foo. Therefore, I have two nested generate loops. However, I need a separate index variable l to for a proper selection of the signal.
genvar j, i, l;
generate
l = 0;
for(j = 0; j < 16; j++)
begin
for(i = 0; i < 16; i++) begin
foo bar
(
.a_i(a_i[(l+1)*8-1:l*8]),
.b_i(b_i[(j+1)*8-1:j*8]),
.c_o(c_i[i][j])
);
if(i < 15)
l = (l + 1) % 16;
end
end
endgenerate
Unfortunately, this construction does not work. How to add l to this generate to get the correct selection of the input signals?
A genvar can only be assigned as the index in a for-loop. So Leave it as an expression:
genvar j, i;
generate
for (j = 0; j < 16; j++) begin
for (i = 0; i < 16; i++) begin
foo bar (
// prefix 1'b0 for correct sign extinction, 4'() does casting
.a_i(a_i[{1'b0,4'(i-j)}*8 +: 8]),
.b_i(b_i[j*8 +: 8]),
.c_o(c_i[i][j])
);
end
end
endgenerate
+: is for array slicing, allowing variable index and constant offset. It is more concise and easier to maintain then specifying the msb:lsb, and it is synthesizable. Refer to 'Indexing vectors and arrays with +:' and 'What is `+:` and `-:`?
You can also combined the this method with dave_59's parameter approach:
genvar j, i;
generate
for (j = 0; j < 16; j++) begin
for (i = 0; i < 16; i++) begin
// defining the parameter with a data type to insure it is a unsigned 4 bit value
parameter bit [3:0] l = (i-j);
foo bar (
.a_i(a_i[l*8 +: 8]),
.b_i(b_i[j*8 +: 8]),
.c_o(c_i[i][j])
);
end
end
endgenerate
Use the conditional operator ?:, and make l a parameter
genvar j, i;
generate
l = 0;
for(j = 0; j < 16; j++)
begin
for(i = 0; i < 16; i++) begin
parameter l = (i < 15) ? ((l + 1) % 16) : 0;
foo bar
(
.a_i(a_i[(l+1)*8-1:l*8]),
.b_i(b_i[(j+1)*8-1:j*8]),
.c_o(c_i[i][j])
);
end
end
endgenerate

How to write a Verilog function that determines if all elements in an array are equal?

Let's say I have N registers and I want a function that checks if all register contents are equal. How do I write that without having to spell out every single element?
function equal (input [0:N-1][width-1:0] in);
equal = (???) ? 1'b1 : 1'b0;
endfunction
A simple for loop is one way:
module tb;
parameter N = 8;
parameter width = 4;
reg [0:N-1][width-1:0] arr;
initial begin
for (int i=0; i<N; i++) arr[i] = 5;
$display(equal(arr));
for (int i=0; i<N; i++) arr[i] = 2*i;
$display(equal(arr));
end
function equal (input [0:N-1][width-1:0] in);
for (int i=1; i<N; i++) begin
if (in[i] !== in[0]) return 0;
end
return 1;
endfunction
endmodule
Output:
1
0
module tb;
parameter W = 8;
parameter N= 4;
logic [N-1:0][W-1:0] in0, in1;
logic res;
initial begin
in0 = {8'd6,8'd6,8'd6,8'd6};
in1 = {8'd6,8'd6,8'd55,8'd6};
res = equal(in0);
$display(res);
res = equal(in1);
$display(res);
end
function logic equal(input logic [N-1:0][W-1:0] in);
equal = (in === {N{in[0]}}) ? 1 : 0;
endfunction
endmodule
Modelsim results:
# 1
# 0

Resources