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

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.

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

Multiplication of 2 matrix in verilog

I've written a code for matrx multiplication in Verilog.
module multiply3x3(i1,i2,i3,i4,i5,i6,i7,i8,i9,j1,j2,j3,j4,j5,j6,j7,j8,j9,prod);
output reg [31:0]prod;
wire [7:0]resultant[3:0][3:0];
wire [7:0]a[3:0][3:0];
wire [7:0]b[3:0][3:0];
genvar i,j,k;
generate
for (i = 0; i <= 2; i=i+1) begin:i_
for (j = 0; j <= 2; j=j+1) begin:j_
assign resultant[i][j] = 8'd0;
for (k = 0; k <= 2; k=k+1) begin:k_
assign resultant[i][j] = resultant[i][j] + a[i][k] * b[k][j];
end
end
end
endgenerate
endmodule
initial begin
#100 prod = {resultant[0][0],resultant[0][1],resultant[0][2],resultant[1][0],resultant[1][1],resultant[1][2],resultant[2][0],resultant[2][1],resultant[2][2]};
end
This is where the multiplication happens, but i cannot get the output for this.
What am I doing wrong?
consider a,b declared properly.
Accumulation (a = a + p) doesn't work with wires. The type wire is supposed to model a physical wire.
You'll have to declare the variable resultant as a reg. The reg type, in Verilog, can in some cases be treated like a variable in other programming languages.
Also, you can't use the assign statement on a wire or reg multiple times (like you've done in line 78 and 80 of https://pastebin.com/txrcwUBd). You should use always (and not generate) blocks to perform such things.
Corrected Verilog:
reg [7:0] resultant[3:0][3:0];
int i, j, k;
always #(*)
for(i=0; i<3; i=i+1)
for(j=0; j<3; j=j+1) begin
resultant[i][j] = 8'd0;
for(k=0; k<3; k=k+1)
resultant[i][j] = resultant[i][j] + (a[i][k]*b[k][j]);
end

Verilog expression evaluates to 'x'

I am writing matrix multiplication module in Verilog and I encountered an issue where expression evaluates to bunch of 'xxxx':
// multiplies 5x32 matrix by 32x5 matrix
module matmul(input [4959:0] A, input [4959:0] B, output reg [799:0] out);
integer i,j,k;
integer start = 0;
reg [31:0] placeholder_A [4:0][31:0];
reg [31:0] placeholder_B [31:0][4:0];
reg [31:0] placeholder_out [4:0][4:0];
always #(A or B) begin
// initialize output to zeros
for (i=0; i<800; i=i+1)
out[i] = 0;
// initialize placeholder output to zeros
for (i=0; i<5; i=i+1)
for(j=0; j<5; j=j+1)
placeholder_out[i][j] = 32'd0;
// turn flat vector A array into matrix
for (i=0; i<5; i=i+1)
for(j=0; j<32; j=j+1) begin
placeholder_A[i][j] = A[start +: 31];
start = start + 32;
end
start = 0;
// turn flat vector B array into matrix
for (i=0; i<32; i=i+1)
for(j=0; j<5; j=j+1) begin
placeholder_B[i][j] = B[start +: 31];
start = start + 32;
end
start = 0;
// do the matrix multiplication
for (i=0; i<5; i=i+1) // A.shape[0]
for(j=0; j<5; j=j+1) // B.shape[1]
for(k=0; k<32; k=k+1) // B.shape[0] or A.shape[1]
placeholder_out[i][j] = placeholder_out[i][j] + (placeholder_A[i][k]*placeholder_B[k][j]); // this is where I am having problems
start = 0;
// flatten the output
for (i=0; i<5; i=i+1)
for(j=0; j<5; j=j+1) begin
out[start] = placeholder_out[i][j];
start = start + 1;
end
end
endmodule
placeholder_out variable (and therefore out output) are evaluated as 'xx...xxx' and I cannot understand why. When checking the signals through testbench both placeholder_A and placeholder_B contain valid values. Any help would be appreciated.
You can run the testbench here: https://www.edaplayground.com/x/2P7m
A couple of things that I observed from the code snippet. First of all the input is not having sufficient width. The required width is 32*5*5=5120. So we need input vectors of 5120 bits ( input [5119:0] A, input [5119:0] B). A linting tool might have caught this issue.
Secondly, the start needs to be initialized to zero at the start of computation. This will avoid latches on start and will compute from zeroth index of A and avoid X's to propagate further.
always #(A or B) begin
//...
start=0;
I'd advise to use always_comb instead of manual sensitivity but that is an entirely different topic.
As a side note, the given code snippet will create large combinational hardware as per my understanding. You may want to check synthesis result for timing violations on different nets and apply some alternate logic.

Using assign inside a for loop

I'm trying to assign I/O vectors inside a for loop in order to save space. I am unsure if this is not possible or I am running into a syntax issue.
I have tried using generate and am still running into issues
My current code is as follows:
module Test_IO
(
output [7:0] led,
input [7:0] sw
);
genvar i;
generate
for(i = 0;i < 8; i = i + 1)
{
assign led<i> = sw<i>;
}
endgenerate
endmodule
I was hoping to save space instead of having to use 8 assign statements but I have been receiving the following error:
ERROR:HDLCompiler:806 -
"C:/Users/Danie/Desktop/Digilent/Projects/Test_IO/Test_IO.v" Line 31:
Syntax error near "{".
I am assuming you are using verilog. Try the below code. You really don't need a genvar for the assignment you are doing.
module Test_IO
(
output [7:0] led,
input [7:0] sw
);
genvar i;
generate
for(i = 0;i < 8; i = i + 1)
assign led[i] = sw[i];
endgenerate
endmodule
Alternatively you may try the below one too
module Test_IO
(
output reg [7:0] led,
input [7:0] sw
);
integer i;
always#(*)
begin
for(i=0;i<8;i=i+1)
led[i] = sw[i];
end
endmodule
Your problem is syntax. In verilog use begin and end, not { and }
genvar i;
generate
for(i = 0;i < 8; i = i + 1)
{
assign led<i> = sw<i>;
}
endgenerate
becomes
genvar i;
generate
for(i = 0;i < 8; i = i + 1) begin
assign led[i] = sw[i];
end
endgenerate
sometimes compilers requires the generate loop to be named using : NAME after begin
genvar i;
generate
for(i = 0;i < 8; i = i + 1) begin : ASSIGN_GEN
assign led[i] = sw[i];
end
endgenerate

verilog debugging

I don't know what is wrong with the code below. Can someone help me debug?
module iloop(z,a);
input [31:0] a;
output z;
reg [4:0] i;
reg s, z;
initial begin
s = 0;
for(i=0; i<32; i=i+1) s = s | a[i];
z = !s;
end
endmodule
Your code has an infinite loop. You have declared i as a 5-bit reg, which means its range of values is (decimal) 0 to 31. But, your for loop checks if i < 32, which is always true.
Once i=31, i is incremented and rolls over to 0.
$display is your friend. If you add it to your for loop, you will see the problem:
for(i=0; i<32; i=i+1) begin $display(i); s = s | a[i]; end
I think you want i<31.
Or, maybe you want to OR all the bits of a together, using the bit-wise OR operator:
s = |a;
You should explain in words what you are trying to achieve.

Resources