Verilog HDL syntax error near text "for"; expecting "endmodule" - verilog

So I just got around to learning verilog and I was implementing a basic binary adder in it.
From my limited understanding of verilog, the following should add two 16-bit values.
module ADD(X, Y, Z);
input[15:0] X;
input[15:0] Y;
output Z[15:0];
wire C[15:0];
assign C[0] = 0;
integer i;
for(i=1; i<16; i=i+1) begin
assign C[i]=(X[i-1]&Y[i-1])|(X[i-1]&C[i-1])|(Y[i-1]&C[i-1]);
end
for(i=0; i<16; i=i+1) begin
assign Z[i]=X[i]^Y[i]^C[i];
end
endmodule
However, I get an error when I try to synthesize the above.
Error (10170): Verilog HDL syntax error at add.v(10) near text "for"; expecting "endmodule"
I'm not sure what is wrong with the code. Any help is appreciated!

The for-loop is used outside of an always block, so i needs to be a genvar instead of an integer. Also, you probably want Z and C to declared an packed arrays instead of unpacked, mo the [15:0] to the other side.
output [15:0] Z; // make as packed bits
wire [15:0] C;
assign C[0] = 0;
genvar i; // not integer
generate // Required for IEEE 1364-2001, optional for *-2005 and SystemVerilog
for(i=1; i<16; i=i+1) begin
assign C[i]=(X[i-1]&Y[i-1])|(X[i-1]&C[i-1])|(Y[i-1]&C[i-1]);
end
for(i=0; i<16; i=i+1) begin
assign Z[i]=X[i]^Y[i]^C[i];
end
endgenerate // must be matched with a generate
Alternative solution 1: use an always block
output reg[15:0] Z; // make as reg
reg [15:0] C;
integer i; // integer OK
always #* begin
for(i=1; i<16; i=i+1) begin
if (i==0) C[i] = 1'b0;
else C[i]=(X[i-1]&Y[i-1])|(X[i-1]&C[i-1])|(Y[i-1]&C[i-1]);
Z[i]=X[i]^Y[i]^C[i];
end
end
Alternative solution 2: bit-wise assignment
output [15:0] Z;
wire [15:0] C = { (X&Y)|(X&C)|(Y&C) , 1'b0 };
assign Z = X^Y^C;
Alternative solution 3: behavioral assignment
output [15:0] Z;
assign Z = X+Y;
Working examples here

Change the definition of i from integer to genvar.
Notice that for loops can be used either in an always block or in a generate block. The latter is implicitly the context that you are using it in your code. In generate blocks, the loop variable should be of type genvar.
More info in IEEE Std 1800-2012

Related

How to invert a bit of a packed array

logic [4:0] count_zeros;
logic [2:0] id;
integer i;
logic [7:0] [15:0] vld;
always#*
begin
count_zeros = 5'b0;
for (i=0; i<2; i=i+1)
count_zeros = count_zeros + ~vld[id][i];
end
For an input as d8, I get count_zeros as 1e. My expected output is 2. What is wrong in the above snippet?
~ is a bitwise negation and ! is logical negation. Where am I going wrong?
Verilog expands the single bit value (vld[id][i]) to match the width of the expression it is in, which is 5 bits because of the count_zeros signal. This is done before the bitwise invert operator is applied. Since vld[0][0] is 1'b0, 1'b0 is expanded to 5'b00000. Then~(5'b00000) results in 5'b11111.
Create a 1-bit signal, such as temp, and directly set it to the inverted bit value. Then use it in the addition expression.
logic temp;
always #* begin
count_zeros = 5'b0;
for (i=0; i<2; i=i+1) begin
temp = ~vld[id][i];
count_zeros = count_zeros + temp;
end
end
Refer to IEEE Std 1800-2017, section 11.6 Expression bit lengths.

How can I use genvar variable to access input signals?

I have a module with 30-vector inputs.. I need help in the for loop assignment.
module test (
input [3:0] i0,
input [3:0] i1,
input [3:0] i2,
...
input [3:0] i29
);
wire [3:0] int_i [0:29];
genvar j;
generate
for (j=0; j<30; j=j+1) begin
assign int_i[j] = i(j) //need help here
end
endgenerate
endmodule
Is there a easy way to do this in Verilog. I know I can do this in System verilog by creating a 2-d vector of inputs. But is there a way to do this in Verilog?
The only way to do this in Verilog is to flatten out the 2-D array into a single vector.
module test (
input [30*4-1:0] i;
);
wire [3:0] int_i [0:29];
genvar j;
for (j=0; j<30; j=j+1) begin
assign int_i[j] = i[4*j+:4];
end
This is a systemverilog feature, in verilog, this should be packing the input array into a vector (I included a parameter in order to automatize things):
module test
# (
parameter WIDTH = 4,
parameter DEPTH = 30
) (input [(WIDTH*DEPTH)-1:0] i);
wire [WIDTH-1:0] int_i [DEPTH-1:0];
genvar j;
generate
for(j=0; j<DEPTH; j=j+1) begin: assign_i_gen //..(don't forget to name the for loop)
assign int_i[j] = i[(WIDTH*j)+:WIDTH];
end
endgenerate

How to fix X in the nonrestoring divider output?

I made a design for a divider, but the result is wrong.
module div(x,y,quotient,remainder);
parameter M=4;
parameter N=4;
input [M-1:0] x;
input [N-1:0] y;
output [N-1:0] quotient;
output [M-1:0] remainder;
wire [M-1:0] rem_carry;
wire sum[M-1:0][N-1:0];
wire carry[M-1:0][N-1:0];
genvar i, j;
generate for(i=N-1; i>=0; i=i-1) begin:
unsigned_divider
if(i==N-1)
for(j=0; j<M; j=j+1) begin: first_row
if(j==0)
assign {carry[j][i],sum[j][i]}=y[i]+!x[j]+1;
assign {carry[j][i],sum[j][i]}=!x[j]+carry[j-1][i];
end
else
for(j=0; j<M;j=j+1) begin:rest_rows
if(j==0)
assign{carry[j][i],sum[j][i]}=y[i]+(x[j]^carry[M-1][i+1])+carry[M-1][i+1];
else
assign {carry[j][i],sum[j][i]}=sum[j-1][i+1]+(x[j]^carry[M-1][i+1])+carry[j-1][i];
end
end endgenerate
generate for(i=0; i<N; i=i+1)
begin:product_quotient
assign quotient[i]=carry[M-1][i];
end endgenerate
generate for(j=0;j<M;j=j+1)
begin:remainder_adjust
if(j==0)
assign{rem_carry[j],remainder[j]} = sum[j][0]+(sum[M-1][0]&x[j]);
else
assign{rem_carry[j],remainder[j]} =sum[j][0]+(sum[M-1][0]&x[j])+rem_carry[j-1];
end endgenerate
endmodule
and testbench simulation code
module tb_div();
parameter M = 4; // default divisor width
parameter N = 4; // default dividend width
reg [M-1:0] x;
reg [N-1:0] y;
wire[N-1:0] quotient;
wire[M-1:0] remainder;
wire[M-1:0] rem_carry;
div U0(.x(x), .y(y), .quotient(quotient), .remainder(remainder));
initial begin
x = 0; y = 0;
// Wait 100 ns for global reset to finish
#100;
// Add stimulus here
x=4'b0001;y=4'b0000;
#300 x=4'b0100;y=4'b0011;
#300 x=4'b1101;y=4'b1010;
#300 x=4'b1110;y=4'b1001;
#300 x=4'b1111;y=4'b1010;
end
endmodule
But, quotient, remainder, rem_carry is not value.
How to change the code? I think testbench is the problem.
The X values on quotient and remainder are due to contention on carry and sum in the design. Change:
assign {carry[j][i],sum[j][i]}=!x[j]+carry[j-1][i];
to:
else assign {carry[j][i],sum[j][i]}=!x[j]+carry[j-1][i];
The missing else caused carry to be simultaneously driven by 2 assign statements. The same goes for sum. My simulators gave me a "part-select index out of declared bounds" compile warning on that line. Proper indentation would have made it easier to catch this bug.
You get Z on the rem_carry signal in the testbench because the signal is undriven. You need to add an output port to the div module and make the proper connection in the testbench.

verilog compile error - "variable not constant"

Why am I getting error "q is not constant"?
module prv(
input [7:0]x,
input [7:0]y,
output [49:0]z
);
wire [24:0]q;
assign z=1;
genvar k;
for (k=50; k<0; k=k-1)
begin
wire [25:0]a;
assign a=0;
assign q= x;
genvar i;
for(i=0; i<8; i=i+1)
begin
if(q[0]==1)
begin
assign a=a+z;
end
assign {a,q}={a,q}>>1;
end
assign z={a[24:0],q};
end
endmodule
I'm afraid that you are trying to use Verilog the wrong way. q is a wire, not a variable (a reg) so it cannot be assigned with a value that includes itself, because that would cause a combinational loop. You are using the assign statement as if it were a regular variable assignment statement and it's not.
Declare a and q as reg, not wire. i and k don't need to be genvars variables, unless you are trying to generate logic by replicating multiple times a piece of code (description). For for loops that need to behave as regular loops (simulation only) use integer variables.
Besides, behavioral code must be enclosed in a block, let it be combinational, sequential, or initial.
A revised (but I cannot make guarantees about its workings) version of your module would be something like this:
module prv(
input wire [7:0] x,
input wire [7:0] y,
output reg [49:0] z
);
reg [24:0] q;
reg [25:0] a;
integer i,k;
initial begin
z = 1;
for (k=50; k<0; k=k-1) begin
a = 0;
q = x;
for (i=0; i<8; i=i+1) begin
if (q[0] == 1) begin
a = a + z;
end
{a,q} = {a,q}>>1;
end
z = {a[24:0],q};
end
endmodule

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