How to represent assign logic array in Verilog generate block? - verilog

I have difficulties in representing a simple assignment with generate block.
My intention is
assign bus = disp[0] | disp[1] | disp[2] ...;
The following code does not work. How can I fix it? Such accumulation related assignments does not appear in the Verilog mannual. Thanks in advance for any advice.
genvar varx;
for (varx = 0; varx < `N; varx = varx + 1) begin
if (varx == 0) assign bus = disp[0];
else assign bus = bus | disp[varx];
end

That is an incorrect usage of generate and assign.
generates should not be used that liberally in Verilog and their use should be something special like extending a module for parametrization etc.
If it can be statically unrolled (as per your usage here) then a plain for loop could have been used. Generates would typically be used for parametrizing module instantiations;
assign should be once per wire and constantly drives the right hand side expression on to that wire.
Your code looks like you are simply trying to OR the disp bus, this can be achieved with an OR reduction operator:
wire bus;
assign bus = |disp ;
Update1
disp is actually defined as a memory and we are not trying to calculate a single bit or reduction. Here a for loop can be used to calculate the OR.
logic [3:0] data [5:0];
logic [3:0] or_data;
integer i;
always #* begin
or_data = 4'b0;
for(i=0; i<6; i=i+1) begin
or_data = or_data | data[i] ;
end
end
Simple Simulation:
logic [3:0] data [5:0];
logic [3:0] or_data;
integer i;
initial begin
for(i=0; i<6; i=i+1) begin
data[i] = i*2;
end
#1ns;
for(i=0; i<6; i=i+1) begin
$displayb(data[i]);
end
or_data = 4'b0;
for(i=0; i<6; i=i+1) begin
or_data = or_data | data[i] ;
end
#1ns;
$displayb(or_data);
end

Related

Does SystemVerilog Generate support delays?

I thought of generating clock using genvar like below:
reg [7:0]clk;
genvar i;
generate
for (i=0; i < 7; i++) begin
#1 clk[i]=~clk[i];
end
endgenerate
I am getting an error:
error: near "#": syntax error, unexpected '#'
How can we resolve it? Can I use delays inside generate block?
I feel it isn't necessary to have a generate, you can use the for loop directly in an always block:
reg [7:0] clk;
integer i;
always begin
#1;
for(i = 0; i < 7; i = i + 1)
clk[i] = ~clk[i];
end
Nevertheless, if all the bits are toggled at the same time, you can simplify it with:
always
#1 clk = ~clk; //..bitwise invert the array
Yes, generate blocks support delays. To fix your problem, use a procedural always block:
reg [7:0] clk;
genvar i;
generate
for (i=0; i < 7; i++) begin
always #1 clk[i]=~clk[i];
end
endgenerate
It looks like OP wanted to have a sequential delay model. In this case the code should look like this:
always begin
for(i = 0; i < 7; i = i + 1)
#1 clk[i] = ~clk[i];
end

Will temp variable in always_comb create latch

I have following code snippet where a temp variable is used to count number of 1s in an array:
// count the number 1s in array
logic [5:0] count_v; //temp
always_comb begin
count_v = arr[0];
if (valid) begin
for (int i=1; i<=31; i++) begin
count_v = arr[i] + count_v;
end
end
final_count = count_v;
end
Will this logic create a latch for count_v ? Is synthesis tool smart enough to properly synthesize this logic? I am struggling to find any coding recommendation for these kind of scenarios.
Another example:
logic temp; // temp variable
always_comb begin
temp = 0;
for (int i=0; i<32; i++) begin
if (i>=start) begin
out_data[temp*8 +: 8] = in_data[i*8 +: 8];
temp = temp + 1'b1;
end
end
end
For any always block with deterministic initial assignment, it will not generate latch except logic loop.
Sorry Eddy Yau, we seem to have some discussions going on regarding your post.
Here is some example code:
module latch_or_not (
input cond,
input [3:0] v_in,
output reg latch,
output reg [2:0] comb1,
output reg [2:0] comb2
);
reg [2:0] temp;
reg [2:0] comb_loop;
// Make a latch
always #( * )
if (cond)
latch = v_in[0];
always #( * )
begin : aw1
integer i;
for (i=0; i<4; i=i+1)
comb_loop = comb_loop + v_in[i];
comb2 = comb_loop;
end
always #( * )
begin : aw2
integer i;
temp = 7;
for (i=0; i<4; i=i+1)
temp = temp - v_in[i];
comb1 = temp;
end
endmodule
This is what came out if it according to the Xilinx Vivado tool after elaboration:
The 'latch' output is obvious. You will also notice that temp is not present in the end result.
The 'comb_loop' is not a latch but even worse: it is a combinatorial loop. The output of the logic goes back to the input. A definitely NO-NO!
General rule: if you read a variable before writing to it, then your code implies memory of some sort. In this case, both the simulator and synthesiser have to implement storage of a previous value, so a synthesiser will give you a register or latch. Both your examples write to the temporary before reading it, so no storage is implied.
Does it synthesisie? Try it and see. I've seen lots of this sort of thing in production code, and it works (with the synths I've used), but I don't do it myself. I would try it, see what logic is created, and use that to decide whether you need to think more about it. Counting set bits is easy without a loop, but the count loop will almost certainly work with your synth. The second example may be more problematical.

In synthesizable verilog, can we use assign statement in generate block?

For example, I have the below piece of code. Can we assign wire inside the generate block in synthesizable verilog? Can we use assign statement inside the generate block in synthesizable verilog?
genvar i;
generate
for (i = 0; i < W; i=i+1) begin:m
wire [2:0] L;
assign L[1:0] = { a[i], b[i] };
end
endgenerate
Yes. It is possible. A generate statement is just a code generator directive to the synthesizer. Basically, it is just loop unrolling. This is if the loop can be statically elaborated. That is, the number of times the loop is to executed should be determinable at compile time.
genvar i;
generate
for (i = 0; i < 2 ; i++) {
assign x[i] = i;}
endgenerate
unrolls into
assign x[0] = 0;
assign x[1] = 1;
In synthesizeable Verilog, it is possible to use an assign statement inside of a generate block. All a generate block does is mimic multiple instants. Be careful though, because just like a for loop, it could be very big space-wise.
You can use assign in generate statment, it is quite common to help parameterise the hook up modules
The original code has some issues: L is defined multiple times and it is only assigned 2 out of 3 bits
genvar i;
generate
for (i = 0; i < W; i=i+1) begin:m
wire [2:0] L;
assign L[1:0] = { a[i], b[i] };
end
endgenerate
Could be changed to:
localparam W = 4;
reg [W-1:0] a;
reg [W-1:0] b;
wire [1:0] L [0:W-1];
genvar i;
generate
for (i = 0; i < W; i=i+1) begin:m
assign L[i] = { a[i], b[i] };
end
endgenerate
Here L[i] selects the i'th wire [1:0] part of L. While a[i] and b[i] are bit selects.

Generate If Statements in Verilog

I'm trying to create a synthesizable, parametrized priority encoder in Verilog. Specifically, I want to find the least significant 1 in a vector and return a vector containing just that 1. For example:
IN[3:0] | OUT[4:0]
--------+---------
1010 | 00010
1111 | 00001
0100 | 00100
0000 | 10000 (special case)
So if the vectors are four bits wide, the code is:
if (in[0]==1'b1) least_one = 1;
else if (in[1]==1'b1) least_one = 2;
else if (in[2]==1'b1) least_one = 4;
else if (in[3]==1'b1) least_one = 8;
else out = 16; // special case in==0, set carry bit
I need a general, scalable way to do this because the input/output vector length is parametrized. My current code is:
module least_one_onehot
#(parameter ADDR_WIDTH=4)
(output reg [ADDR_WIDTH:0] least_one,
input [ADDR_WIDTH-1:0] in);
genvar i;
always #(in) begin
if (in[0]==1'b1) least_one = 1;
generate for (i=1; i<ADDR_WIDTH; i=i+1) begin : U
else if (in[i]==1'b1) least_one = 2**i;
end
endgenerate
else least_one = 2**ADDR_WIDTH;
end
endmodule
When I try to compile this, I receive the following errors:
file: least_one_onehot.v
generate for (i=1; i<ADDR_WIDTH; i=i+1) begin : U
|
ncvlog: *E,GIWSCP (least_one_onehot.v,10|8): Generated instantiation can only be valid within a module scope [12.1.3(IEEE 2001)].
else if (in[i]==1'b1) least_one = 2**i;
|
ncvlog: *E,NOTSTT (least_one_onehot.v,11|6): expecting a statement [9(IEEE)].
endgenerate
|
ncvlog: *E,GIWSCP (least_one_onehot.v,13|12): Generated instantiation can only be valid within a module scope [12.1.3(IEEE 2001)].
else least_one = 2**ADDR_WIDTH;
|
ncvlog: *E,NOTSTT (least_one_onehot.v,14|5): expecting a statement [9(IEEE)]
I've tried various arrangements of the generate, if, and always statements, all without success. Anyone know the proper syntax for this? Case-statement implementation or other alternatives would also be fine. Thanks.
I think you misunderstand how generate works. It isn't a text pre-processor that emits the code in between the generate/endgenerate pair with appropriate substitutions. You have to have complete syntactic entities withing the pair. I don't have access to a simulator right this minute but this might do the trick for you (totally untested)
genvar i;
generate
for (i = 1; i < ADDR_WIDTH; i = i + 1) begin : U
least_one[i] = in[i] & ~|in[i - 1:0];
end
endgenerate
least_one[0] = in[0];
least_one[ADDR_WIDTH] = ~|in;
Ordinarily Verilog would complain about the non-constant bit slice width but since it's within a generate loop it might work.
Failing something like the above you just test for the first set bit in a for-loop and then decode that result.
You do not need a generate block. You could use:
integer i;
reg found;
always #(in) begin
least_one = {(ADDR_WIDTH+1){1'b0}};
found = 1'b0;
for (i=0; i<ADDR_WIDTH; i=i+1) begin
if (in[i]==1'b1 && found==1'b0) begin
least_one[i] = 1'b1;
found = 1'b1;
end
end
least_one[ADDR_WIDTH] = (found==1'b0);
end
If you really want to use a generate block, then you need to assign each bit.
assign least_one[0] = in[0];
assign least_one[ADDR_WIDTH] = (in == {ADDR_WIDTH{1'b0}});
genvar i;
generate
for (i=1; i<ADDR_WIDTH; i=i+1) begin : U
assign least_one[i] = in[i] && (in[i - 1:0] == {i{1'b0}});
end
endgenerate
This simulates the way you want it to, but it is not synthesizable (you didn't specify if that was a requirement):
module least_one_onehot #(parameter ADDR_WIDTH=4) (
output reg [ADDR_WIDTH-1:0] least_one,
input [ADDR_WIDTH-1:0] in
);
always #* begin
least_one = '0;
for (int i=ADDR_WIDTH-1; i>=0; i--) begin
if (in[i]) least_one = 2**i;
end
end
endmodule
Note that it uses SystemVerilog constructs.
Personally, I like the following block of code for what you need:
assign out = {1'b1,in} & ((~{1'b1,in})+1);
You could try this (dropping the extra high bit for legibility), but I like to explicitly do the twos compliment to avoid any potential compatibility problems.
assign out = in & (-1*in);

Is there a more concise way to write the assign for this wire in Verilog?

Just trying to create a wire finished that is true iff data == dataNew for all registers and indexes. The only way I can come up with is using a bunch of finishedAgg wires as intermediate values; I'd love to get rid of them but I can't figure out how to. Seems like there has to be an easier way than this!
reg[24:0] data[0:24];
reg[24:0] dataNew[0:24];
wire finished;
genvar i;
generate
wire finishedAgg[-1:24];
assign finishedAgg[-1] = 1;
for (i=0; i<25; i=i+1) begin :b1
assign finishedAgg[i] = finishedAgg[i-1] & (data[i]==dataNew[i]);
end
assign finished = finishedAgg[24];
endgenerate
Here's my cut at it:
reg [24:0] finishAgg;
wire finished;
always #(*)
for (int i=0; i<25; i=i+1) begin :b1
finishedAgg[i] = (data[i]==dataNew[i]);
end : b1
assign finished = &finishedAgg;
It's not too much shorter than your version, but it doesn't need a generate block. I've declared i in-loop Systemverilog-style, and I'm using a reduction-AND to make the finished signal.

Resources