Illegal operand for constant expression - verilog

I'm trying to build a task, which must delve into some hierarchy, that can concisely compare different pins on a particular instance. In particular, I'd like to do something like the following:
task check_expected;
input integer pin;
input [9:0] expected;
integer i, j;
reg [9:0] check;
begin
j = 0;
for (i = 0; i < 20; i = i + 1) begin
case (pin)
0: begin
check[0] = test.inst[i].lane_0.PIN_FIRST;
check[1] = test.inst[i].lane_1.PIN_FIRST;
...
check[9] = test.inst[i].lane_9.PIN_FIRST;
end
1: begin
check[0] = test.inst[i].lane_0.PIN_SECOND;
check[1] = test.inst[i].lane_1.PIN_SECOND;
...
check[9] = test.inst[i].lane_9.PIN_SECOND;
end
...
9: begin
check[0] = test.inst[i].lane_0.PIN_TENTH;
check[1] = test.inst[i].lane_1.PIN_TENTH;
...
check[9] = test.inst[i].lane_9.PIN_TENTH;
end
endcase
if (check[0] !== expected[j*10 + 0]) begin
TEST_FAILED = TEST_FAILED + 1;
$display("ERROR Expected=%b, # %0t",expected[j*10 + 0],$time);
end
if (check[1] !== expected[j*10 + 1]) begin
TEST_FAILED = TEST_FAILED + 1;
$display("ERROR Expected=%b, # %0t",expected[j*10 + 1],$time);
end
...
if (check[9] !== expected[j*10 + 9]) begin
TEST_FAILED = TEST_FAILED + 1;
$display("ERROR Expected=%b, # %0t",expected[j*10 + 9],$time);
end
end
end
endtask
Unfortunately, attempting to do the above throws a NOTPAR error during elaboration, claiming that it is unacceptable to assign a register to a non-constant (it doesn't like any lines like check[0] = test.inst[i].lane_0.PIN_FIRST;). This is just for testing purposes, not anything synthesizeable, by the way.
Can someone explain why this is disallowed and suggest a different solution? It's looking like I'll need to write a task for each and every loop iteration, and that seems like it would be needlessly bloated and ugly.
Thanks

To answer my own question, the answer is that there is no way to do it with Verilog. Verilog is an incredibly dumb (in terms of capabilities) language, and, with a task, can only support constant indices for module instances. No looping is possible.

Related

System Verilog Loops

Im currently working on the Shift-Add Algorithm (32x32 bit Multiplication) in System Verilog. System Verilog cant find any error and my code is working correctly according to GTKwave. When I synthesize my circuit with yosys, Latches will be added. And that is the Problem. I dont want Latches in my Circuit. Heres my Code:
module multiplier(
input logic clk_i,
input logic rst_i,
input logic start_i,
input logic [31:0] a_i,
input logic [31:0] b_i,
output logic finished_o,
output logic [63:0] result_o
);
typedef enum logic [1:0] { STATE_A, STATE_B} state_t;
state_t state_p, state_n;
logic [63:0] fin_res;
logic [63:0] tmp;
logic rst_flag;
integer i;
always #(posedge clk_i or posedge rst_i) begin
if (rst_i == 1'b1) begin
state_p <= STATE_B;
end
else begin
state_p <= state_n;
end
end
always #(*)begin
state_n = state_p;
case (state_p)
STATE_A: if (start_i == 0) state_n = STATE_B;
STATE_B: if (start_i == 1) state_n = STATE_A;
default: state_n = state_p;
endcase
end
always #(*) begin
case (state_p)
STATE_A: begin
rst_flag = 1;
fin_res = 0;
finished_o = 0;
tmp = 0;
for (i = 0; i < 32; i = i + 1) begin
if (a_i[i] == 1'b1) begin
tmp = b_i;
tmp = tmp << i;
fin_res = fin_res + tmp;
end
end
end
STATE_B: begin
result_o = fin_res;
if (rst_flag == 1) finished_o = 1;
if (start_i == 1) finished_o = 0;
end
default: begin
finished_o = 0;
result_o = 0;
end
endcase
end
endmodule
After spending 2 days only with debugging and not finding any mistake I would like to ask if u could help me. I am assigning every output (at least I think so). So where is my mistake? Is it the for loop? But what would be wrong with it? Thanks in advance for your help :)
Some useful Information for the Code-Snippet: start_i is the starting signal. If this is set to 1 the multiplication should be started. finished_o is the finish flag. If this is set to 1 the CPU will know that the computation is completed. a_i and b_i are the inputs which should be multiplied. result_o is the result of the multiplication which can be read when finished_o is set to 1.
According to yosys i get the following latches:
64 DLATCH_N
64 DLATCH_P
I think something may be wrong with fin_res in the for loop cause that logic variable is exactly 64 bits long as are the Latches
From the comment you have a bunch of variables which are not assigned in the second case statement causing synthesis to generate latches. To avoid it you need to assign all the vars in all branches of the case statement and conditional statements recursively.
However, if there is a default value you can assign to all of them, you can use a pattern similar to the one from the second always block, just assigning default values before the 'case' statement. This way you do not even need the default clause and you can get rid of it in the second always block as well.
always #(*) begin
// set default values
rst_flag = 0;
fin_res = 0;
finished_o = 0;
tmp = 0;
result_o = 0;
case (state_p)
STATE_A: begin
rst_flag = 1;
for (i = 0; i < 32; i = i + 1) begin
if (a_i[i] == 1'b1) begin
tmp = b_i;
tmp = tmp << i;
fin_res = fin_res + tmp;
end
end
end
STATE_B: begin
result_o = fin_res;
// are you sure that you do not need a latch here?
if (rst_flag == 1) finished_o = 1;
if (start_i == 1) finished_o = 0;
end
// you do not need 'default' here.
endcase
end
My fixes will cause combinational behavior and should get rid of latches in synthesis, but it does not look like they will behave as you expected. It looks like you really need a latches here.
rst_flag must be a latch. You set it in STATE_A and use it in STATE_B. It has to keep the value between states. This is a latch behavior.
In STATE_B you change finished_o only if some of conditions met. What happens if the rst_flag and start_i are both 0. do you want finished_o to be 0 or the previous value? In the latter case you need a latch.
How about fin_res ? What do you want to do with it in other states? keep previous value (latch) or have a default value (no latch).
...

verilog output stuck on last if statement

Problem: I'm synthesizing my code, which reads 1200 16 bit binary vectors, analyzes them and sets a 2 bit register named classe depending on the behavior of 4 if statements. The problem seems to be that classe is stuck on the last if statement - where classe is set to bit 11, or 3.
My code worked fine in when I was using a testbench.
I'm thinking it is stuck because somehow the always block is reading all 1200 vectors at once, as seen in the simulation, instead of one every clock edge?
I've attached a simulation screenshot here: https://imgur.com/a/No2E9cq
module final_final_code
(
output reg [ 0:1] classe
);
reg [0:15] memory [0:1199];
reg[0:15] vect:
integer i;
//// Internal Oscillator
defparam OSCH_inst.NOM_FREQ = "2.08";
OSCH OSCH_inst
(
.STDBY(1'b0), // 0=Enabled, 1=Disabled also Disabled with Bandgap=OFF
.OSC(osc_clk),
.SEDSTDBY() // this signal is not required if not using SED
);
initial begin
$readmemb("C:/Users/KP/Desktop/data.txt", memory, 0, 1199);
i = 0;
end
always #(posedge osc_clk) begin
vect = memory[i];
if ((memory[i][3] == 1'b0)) begin
classe = 2'b10;
end
if ((memory[i][11] == 1'b0)) begin
classe = 2'b01;
end
if ((memory[i][8] == 1'b1 && memory[i][4] + memory[i][5] + memory[i][6] + memory[i][7] >= 4'b0100)) begin
classe = 2'b00;
end
if ((memory[i][0] + memory[i][1] + memory[i][2] + memory[i][3] + memory[i][4] + memory[i][5] + memory[i][6] + memory[i][7] + memory[i][8] + memory[i][9] + memory[i][10] + memory[i][11] + memory[i][12] + memory[i][13] + memory[i][14] + memory[i][15] <= 1'b1)) begin
classe = 2'b11;
end
i = i + 1'd1;
if (i == 4'd1199) begin
i = 0;
end
end
endmodule
Apart from what john_log says:
Your last if statement is always TRUE. You are adding 1-bit operands and comparing against a 1-bit result thus the results is 1'b1 or 1'b0 which is always <= 1'b1.
You should check if your FPGA tool supports this:
initial begin
$readmemb("C:/Users/KP/Desktop/data.txt", memory, 0, 1199);
i = 0;
end
Especially the loading of a memory from a file by the synthesis tool. It was not possible the last time I used an FPGA.

How to create bit ranges with terms defined as logic

I understand the following code will not compile, but is there something similar that compiles?
logic [7:0] complete_set, partial_set;
logic [2:0] msb_bit, lsb_bit;
always_comb complete_set = <driven by a logic equation>;
always_comb msb_bit = <driven by a logic equation>;
always_comb lsb_bit = <driven by a logic equation>;
always_comb partial_set[msb_bit:lsb_bit] = complete_set[msb_bit:lsb_bit];
You could do some bitwise decisions like this. I just assumed you would want to set the other bits to zero, but you could also set it to don't cares (1'bx).
for(i = 0; i < 8; i = i + 1) begin
partial_set[i] = (i < lsb_bit) || (i > msb_bit) ? 1'b0 : complete_set[i];
end
Assuming you want the unspecified bits to be 0, you can do this in one line:
always_comb partial_set = complete_set & (2**(msb_bit+1-lsb_bit)-1)<<lsb_bit;
But I think a for loop would be much easer for someone else to understand
always_comb begin
partial_set = '0; // or whatever the unspecified bits should be
for(int ii = lsb_bit; ii <= msb_bit; ii++)
partial_set[ii] = complete_set[ii]
end

Parameterizing a casex statement in verilog

Consider the following function which I would like to parameterize. I have created some parameters to set a width of the input and a corresponding width parameter for the output.
parameter SELECT_WIDTH = 6;
parameter PRIENC_WIDTH = $clog2(SELECT_WIDTH+1);
function [PRIENC_WIDTH-1:0] prienc6;
input [SELECT_WIDTH-1:0] select;
reg [PRIENC_WIDTH-1:0] out;
begin
casex(select)
6'b000001: out = 3'b101; // Is it possible to parameterize the case statement with generate
6'b00001x: out = 3'b100;
6'b0001xx: out = 3'b011;
6'b001xxx: out = 3'b010;
6'b01xxxx: out = 3'b001;
6'b1xxxxx: out = 3'b000;
endcase
prienc6 = out ;
end
end function
Obviously, the casex statement cases will not expand as written.
So I tried the following, which didn't compile correctly indicating unexpected generate found.
function [PRIENC_WIDTH-1:0] prienc_n;
input [SELECT_WIDTH-1:0] select;
reg [PRIENC_WIDTH-1:0] out;
begin
genvar gv_j;
casex(select)
for (gv_j = 0; gv_j < SELECT_WIDTH; gv_j = gv_j + 1)
begin
{{(SELECT_WIDTH-1)-gv_j{1'b0}},1'b1,{gv_j{1'bx}}} : out = (SELECT_WIDTH-1)-gv_j;
end
endcase
prienc_n = out ;
end
end function
I have been able to get the correct behavior using parameterized if's, but it seems like I should be able to parameterize that casex statement. Any thoughts on how to do this? I guess what I will try next is to wrap the casex in the generate loop and create 6 casex statements, each with only one state.
Since you tagged this question with SystemVerilog, I'll show you how to do this without a case statement or generate
function logic [PRIENC_WIDTH-1:0] prienc_n(
input [SELECT_WIDTH-1:0] select);
for (int j = 0; j < SELECT_WIDTH; j++) begin
if (select[SELECT_WIDTH-1]) return j;
select <<=1;
end
// if no 1 found
return ('x); // you did not specify this case
endfunction
If you need to stay in Verilog, it will need an intermediate variable
function reg [PRIENC_WIDTH-1:0] prienc_n(
input [SELECT_WIDTH-1:0] select);
reg [PRIENC_WIDTH-1:0] out;
integer j;
begin
out = {PRIENC_WIDTH{1'bx}}; // what should be returned if no 1 found
for (j = 0; j < SELECT_WIDTH; j = j + 1) begin
if (select[SELECT_WIDTH-1]) begin
out = j;
select = 0;
end
select = select << 1;
end
prienc_n = out;
end
endfunction

How do I simplify ugly nested if else statements?

I am new to programming in general and I find myself depending too much on conditional statements. I find them similar to my train of thought when coding which makes them easy to implement.
Below I have a small code snippet in Verilog which controls a digital clock display. The entire code is pretty much laid out in this way. The code works and is pretty readable. However, I find it to be inelegant. Is it possible to simplify the code while at the same time improving readability?
if (cnt >= clkspeed) begin
cnt = 0;
out0 <= out0 + 4'h1;
// LED0 > 9 -> LED1 += 1
if (out0 == 4'h9) begin
out0 <= 4'h0;
out1 <= out1 + 4'h1;
// LED1 > 5 -> LED2 += 1
if (out1 == 4'h5) begin
out1 <= 4'h0;
out2 <= out2 + 4'h1;
// LED2 > 9 -> LED3 += 1
if (out2 == 4'h9) begin
out2 <= 4'h0;
out3 <= out3 + 4'h1;
// LED3 > 5 -> LED3 = 0
if (out3 == 4'h5) begin
out3 <= 4'h0;
end
end
end
end
end
Your problem here is that you perform the same operation four times, as you store your data in scalar variables. The solution for this case would be to store the numbers in an array, and loop through them. The pseudocode of this is something like:
array<int> digits;
int position = digits.length();
while (position >= 0) {
digits[position] = (digits[position] + 1) % 10;
if (digits[position]>0) break; // if there is no carry, just break
position--;
}
This code assumes that every digit counts up to 9. So you still have to add the logic for handling LED1 and LED3... (Through using another array, or if you have OOP creating a LED object which can store the actual number and the limit for the led...)

Resources