How to invert a bit of a packed array - verilog

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.

Related

Bit slicing in verilog

How can I write wdata[((8*j)+7) : (8*i)] = $random; in verilog programming language? , where i and j are reg type variable. Modelsim gives error for constant range variable. How could I write it in proper manner.
You should think from Hardware prospective for the solution.
Here is one solution. Hope that it will help you.
module temp(clk);
input clk;
reg i, j;
reg [23:0] register, select;
wire [23:0] temp;
initial
begin
i = 'd1;
j = 'd1;
end
generate
for(genvar i = 0; i<24; i++)
begin
assign temp[i] = select[i] ? $random : register[i];
end
endgenerate
always # (posedge clk)
begin
register <= temp;
end
always # *
begin
select = (32'hffff_ffff << ((j<<3)+8)) ^ (32'hffff_ffff << (i<<3));
end
endmodule
Use the array slicing construction. You can find more detailed explanation at Array slicing Q&A
bit [7:0] PA, PB;
int loc;
initial begin
loc = 3;
PA = PB; // Read/Write
PA[7:4] = 'hA; // Read/Write of a slice
PA[loc -:4] = PA[loc+1 +:4]; // Read/Write of a variable slice equivalent to PA[3:0] = PA[7:4];
end
Verilog 2001 Syntax
[M -: N] // negative offset from bit index M, N bit result
[M +: N] // positive offset from bit index M, N bit result

Verilog : Variable index is not supported in signal

I get an error saying 'Index is not supported in signal'. From what I can see the error is on the left hand side of the non-blocking assignment. Why does the code below give an error and is there a way to work around it?
...
parameter width = 32;
parameter size = 3;
input clk, reset;
input [width*size-1:0] A;
input [width*size-1:0] B;
output [width*size-1:0] result;
reg signed [width*size-1:0] partials;
reg signed [width-1:0] temp;
reg signed [width-1:0] currenta;
reg signed [width-1:0] currentb;
wire signed [width-1:0] temp1wire;
...
integer k = 0;
always # (posedge clk)
begin
currenta[width-1:0] <= A[width*k +: width];
k = k+1
currentb[width-1:0] <= B[width*k +: width];
partials[width*k +: width] <= temp1wire;
end
Add Add1(clk, temp1wire, currenta, currentb);
...
This code is part of a sequential block that does vector addition and saves the result at partials[width*k +: width].
I found this on the Xilinx forum:
"XST works fine with the indexed part-select operator "+:" if it is on the right-hand side (RHS) of the assignment. It also works fine when it is on the left-hand side (LHS) AND the starting index is a constant. Your case uses a variable as the starting index on the LHS and that what XST doesn't like although it's legal."
k needs to be clamped or wrapped around after reaching size-1.
Wrapping around can be done with the mod operator (%); example:k = (k+1)%size. % may not synthesize optimally (check your synthesizer), so a if-statement is a functional alternative if(k==SIZE-1) k = 0; else k=k+1;
Suggestions:
It is generally recommenced to keep parameters as uppercase, this way you can easily identity parameters form signal names. Putting a blocking assignment inside a sequential block is legal, but most design rules recommend separating combinational logic from sequential assignments. I would prefer writing your code like the following:
// $clog is IEEE1364-2005 ยง 17.11, some synthesizers support it, others don't
reg [$clog2(SIZE):0] k=0, next_k;
always #* begin
if (k==SIZE-1) begin
next_k = 0; // wrap around
// next_k = k; // clamp
end
else begin
next_k = k+1;
end
end
always # (posedge clk)
begin
currenta[WIDTH-1:0] <= A[WIDTH*k +: WIDTH];
currentb[WIDTH-1:0] <= A[WIDTH*next_k +: WIDTH];
partials[WIDTH*next_k +: WIDTH] <= temp1wire;
k <= next_k;
end

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 HDL syntax error near text "for"; expecting "endmodule"

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

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