Verilog - Nested generate for loop with multiple genvars, not possible? - verilog

I'm trying to add a second level of nesting to my generate loop in the following code, but iverilog is throwing an error that the register j is unknown:
../crc.v:119: register ``j'' unknown in crc_tb.U_crc.loop[31].
So is it possible to use multiple genvars in verilog? It looks like j is being interpreted as a register.
Code snippet:
genvar i;
genvar j;
reg [DATA_WIDTH-1:0] temp;
generate
for(i = 0; i < CRC_WIDTH; i= i + 1)
begin : loop
always #(posedge clock or posedge reset)
begin
if (reset)
begin
crc_out[i+:1] = SEED[i+:1];
end
else if (init)
begin
crc_out[i+:1] = SEED[i+:1];
end
else if (data_enable)
begin
if (DEBUG)
$display("\n\nCRC OUT[%0d]\n***************************************************************************", i);
if (REVERSE)
begin
for (j = DATA_WIDTH-1; j >= 0; j = j - 1)
begin : reverse_loop
temp[DATA_WIDTH-1-j] = data[i][j];
end
crc_out[i+:1] <= prev(DATA_WIDTH-1,i,temp,crc_out);
end
else
begin
crc_out[i+:1] <= prev(DATA_WIDTH-1,i,data,crc_out);
end
end
end
end
endgenerate

You can nest multiple generate loops, but your inner generate loop is inside a procedural block of code - that is illegal. Perhapsj should just be a local variable instead of a genvar.

Related

Resolving a warning in verilog: read after blocking assignment in same process

I've this code which is throwing some warning messages which I'm trying to resolve.
module someModuleName(...)
...
...
reg [3:0] i;
wire [3:0] onstate_count;
wire [3:0] ack_count;
reg [3:0] j;
bit switchState;
always #(*) begin :EVAL_ACK
switchState = 1'b0;
for (i = 0; i < onstate_count; i = i+1) begin
if (onStateControls[i] == 1'b1) begin
switchState = 1'b1;
end
end
for (j = 0; j < ack_count; j = j+1) begin
if (ack_expression_type[j] == 1'b0) begin
if (switchState) begin
ack[j] = ack_logic_value[j];
end else begin
ack[j] = !ack_logic_value[j];
end
end else begin
ack[j] = ack_logic_value[j];
end
end
end
endmodule
The warning mesage I'm getting is:
Warning-[SM_TPL] Transaction path loss after synthesis
In module 'someModuleName', transaction path through signal 'i' will be
lost after synthesis due to read after blocking assignment in same process.
-
Warning-[SM_TPL] Transaction path loss after synthesis
In module 'someModuleName', transaction path through signal 'switchState' will be
lost after synthesis due to read after blocking assignment in same process.
-
Warning-[SM_TPL] Transaction path loss after synthesis
In module 'someModuleName', transaction path through signal 'j' will be
lost after synthesis due to read after blocking assignment in same process.
I tried making i, j as integer and genvar but no effect, I'm new to verilog and don't know how to resolve this warning.
Any help would be highly appreciated.
Thanks.
Synthesizers require loops to static unroll.
A loop must be able to static unroll to be synthesizable.
Using a snip it from your original code:
switchState = 1'b0;
for (i = 0; i < onstate_count; i = i+1) begin // <-- onstate_count is not a compile time constant, therefore cannot static unroll
if (onStateControls[i] == 1'b1) begin
switchState = 1'b1;
end
end
The equivalent synthesizer friendly version would be:
switchState = 1'b0;
for (i = 0; i < 16; i = i+1) begin // <-- loop is static
if (i < onstate_count) begin // <-- condition check
if (onStateControls[i] == 1'b1) begin
switchState = 1'b1;
end
end
end
A similar change needs to be made to for (j = 0; j < ack_count; j = j+1). The ack also needs to be assigned a value for indexes greater than ack_count or it will infer a latches; and most FPGA synthesizers do not support latches.
Try this code. Also are onstate_count and ack_count variables constants?
module someModuleName(...)
...
...
genvar i,j;
wire [3:0] onstate_count;
wire [3:0] ack_count;
bit switchState;
generate
for (i = 0; i < onstate_count; i = i+1) begin
always #(*) begin :EVAL_ACK
switchState = 1'b0;
if (onStateControls[i] == 1'b1) begin
switchState = 1'b1;
end
end
end
endgenerate
generate
for (j = 0; j < ack_count; j = j+1) begin
always #(*) begin
if (ack_expression_type[j] == 1'b0) begin
if (switchState) begin
ack[j] = ack_logic_value[j];
end else begin
ack[j] = !ack_logic_value[j];
end
end else begin
ack[j] = ack_logic_value[j];
end
end
end
endgenerate
endmodule

Multiple always block using for loop

Is it posible to generate multiple always statements using a for loop in Verilog
By example. Let's say we want to create a 4bit Ripple/Asynchronous Counter.
We can do this like this
always #(posedge MainClock)
begin
Q[0] = ~Q[0];
end
always #(posedge Q[0])
begin
Q[1] = ~Q[1];
end
always #(posedge Q[1])
begin
Q[2] = ~Q[2];
end
always #(posedge Q[2])
begin
Q[3] = ~Q[3];
end
Is it posible to do something like this instead:
always #(posedge MainClock)
begin
Q[0] = ~Q[0];
end
for (i = 1; i <= 3; i = i+1)
begin
always #(posedge Q[i-1])
begin
Q[i] = ~Q[i];
end
end
I know for a fact that the first methods works, because I tested it. The second method doesn't work, I did test it. Is there a different way to do that?
You can use generate to do that:
genvar i;
generate
for (i = 1; i <= 3; i = i+1) begin : ripple
always #(posedge Q[i-1])
Q[i] = ~Q[i];
end
endgenerate

How to access Verilog genvar generated instances and their signals

I need to initialize arrays in generated instances via generate block in Verilog. I'm trying to use the syntax below, however, I get an error as
External reference foo[0].bar.array[0] remains unresolved.
in Xilinx ISE.
integer i, j;
initial begin
// initialization of arrays
for(i=0; i<(2**7); i=i+1) begin
valid_array[i] = 0;
for(j=0; j<N; j=j+1) begin
foo[j].bar.array[i] = 0;
end
end
end
This is my generate block:
genvar jj;
generate
for(jj = 0; jj < N; jj = jj + 1) begin : foo
Memory_v3
#(
.ADDRESS_WIDTH(INDEX),
.DATA_WIDTH(TAG)
) bar
(
.clock(clock),
.we(we),
.addr_a(addra),
.addr_b(addrb),
.din(din),
.dout(dout)
);
end
endgenerate
What is the correct way to do this?
the problem is that foo block gets resolved at compile time. So, the names like foo[0], foo[1] are pre-generated and are compile-time names, they not work with dynamic index resolution at run-time. Therefore foo[j] will not work.
the solution in this case is to use another generate block to initialize them. Something like the following.
generate
for(jj = 0; jj < N; jj = jj + 1) begin : foo_init
initial begin
// initialization of arrays
for(i=0; i<(2**7); i=i+1) begin
foo[jj].bar.array[i] = 0;
end
end
end
endgenerate
Same story is with array of instances.
FOO bar[3:0](); // array of instances
int i,j;
generate
for(jj = 0; jj < 4; jj = jj + 1) begin : foo_init
initial begin
for(i=0; i<(2**7); i=i+1) begin
bar[jj].array[i] = 0;
end
end
end
endgenerate
BTW, in system verilog you can avoid using generate/endgenerate pairs:

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

Using a for loop inside a clocked process: "Cannot generate logic"

I would like to generate a number of statements inside a clocked process, seen below:
parameter C_INPUT_LENGTH = 32;
parameter C_OUTPUT_NUM_BITS = 5;
reg [C_OUTPUT_NUM_BITS-1:0] address;
reg [C_INPUT_LENGTH-1:0] vector_i;
always#(posedge clk) begin
if(rst) begin
address <= 0;
end
else begin
if (vector_i[0] == 1) begin
address <= 0;
end
if (vector_i[1] == 1) begin
address <= 1;
end
...
if (vector_i[C_INPUT_LENGTH-1] == 1) begin
address <= C_INPUT_LENGTH-1;
end
end
end // always# (posedge clk)
I did so like this:
integer forcount;
always#(posedge clk) begin
if(rst) begin
address <= 0;
end
else begin
for (forcount = 0;forcount <= C_INPUT_LENGTH-1 ;forcount = forcount + 1) begin
if (vector_i[forcount] == 1) begin <--
address <= forcount;
end
end
end
end // always# (posedge clk)
Xilinx vivado (2014.1) gives the following error, referring to the line indicated above:
[Synth 8-903] failed to generate logic
I've done this before using a similar method in the past and it has worked, what am I doing wrong? How do I generate these if statements?
According to Xilinx, this is a known bug documented under CR 801365. The use of an integer as a loop counter causes this issue in some cases. It's due to be fixed in vivado 2014.3.
The solution is to replace the integer with a signal type reg of appropriate size.
Is your input vector_i one-hot? The code you wrote doesn't guarantee that address will only be written to one value. Try this:
for (forcount = 0;forcount <= C_INPUT_LENGTH-1 ;forcount = forcount + 1) begin
if (vector_i[forcount] == 1) begin
address <= forcount;
break;
end
end
Adding the break statement will break out of the for loop the first time the condition is true. Note that this will generate some carry-chain logic and you might get better results with a case statement.
As a temporary work-around, you could consider using a generate statement.
For example:
genvar i;
always #(posedge clk) begin
if (rst) begin
address <= 0;
end else begin
generate
for (i = 0; i < C_INPUT_LENGTH; i = i + 1) begin: foreach_input
if (vector_i[i]) address <= i;
end
endgenerate
end // if (rst)
end // always #(posedge clk)
edit: oh, never mind -- I missed the bit above where Xilinx's recommended workaround is to simply use a dimensioned variable rather than "integer" for the iterator. That would be easier!

Resources