Verilog Signed Multiplication "loses" the Signed Bit - verilog

I am writing a code which uses a multiplier module which returns weird answers when one of the inputs is a negative number. I am guessing this has to do with how Verilog treats signed numbers and the module is not storing the result properly in the 'reg signed out' decleration. All my input/output/wire/reg declarations are signed, so I am not sure what I am missing and what else I need to do to tell Verilog to take care of this. Sorry for the beginner question!
For example,
When X[0] is 1610 and Theta1[1] is -123, the result I am getting from the multiplier module is:
6914897148530
Here are the relevant parts of my code:
module mult(in1, in2, out, mult_start); // multiplication module
input signed [32-1:0] in1, in2;
input mult_start;
output signed [64-1:0] out;
reg signed [64-1:0] out;
always #(in1 or in2 or mult_start)
begin
if (mult_start)
begin
out <= (in1 * in2) & {64{1'b1}};
end
else
out <= out;
end
endmodule
module child_one (clk, rst_b, sig_start, Input_X, Input_Theta1)
// Internal Variables Memory
reg signed [`REG_LENGTH-1:0] Theta1 [0:217-1];
reg signed [`REG_LENGTH-1:0] X [0:216-1];
wire signed [`OUT_LENGTH-1:0] prod_1 [0:217-1];
reg signed [`OUT_LENGTH-1:0] prod_sum;
wire signed [`OUT_LENGTH-1:0] sig_result;
mult mult_001 (X[0], Theta1[1], prod_1[1], mult_start);
mult mult_002 (X[1], Theta1[2], prod_1[2], mult_start);
mult mult_003 (X[2], Theta1[3], prod_1[3], mult_start);
mult mult_004 (X[3], Theta1[4], prod_1[4], mult_start);
always #(posedge clk or negedge rst_b)
begin
if (sig_start == 1)
begin
if (state == 4'b0000)
begin
state <= 4'b0001; // initialize state variable to zero
k <= 0;
result_done <= 0;
index <= 0;
end
else if (state == 4'b0001) // Start Multiplication Operation
begin
k <= result_done ? 0 : k + 1;
result_done <= result_done ? 1 : (k == 10);
state <= result_done ? 4'b0010 : 4'b0001;
mult_start <= result_done ? 1'b1 : 1'b0;
//mult_start <= 1'b1;
//state <= 4'b0010;
end
else if (state == 4'b0010) // Stop Multiplication Operation
begin
k <= 0;
result_done <= 0;
mult_start <= 0;
state <= 4'b0011;
end
end
end
endmodule
Thanks,
Faisal.

Thanks for all the help and suggestions. Writing a separate testbench for the mult module helped arrive at a solution.
My issue was in the mult module. Since my inputs are 32 bits long, the mult output would be 32*2+1 = 65 bits long. My output port 'out' was only assigned to be 64 bits long which resulted in a sign issue when the answer was a negative number. Assigning it to be 65 bits long took care of my problem.

The issue is the & {64{1'b1}} part in the mult module. {64{1'b1}} is an unsigned subexpression. This causes in1 and in2 and to be treated as unsigned regardless of their declaration, and causes unsigned multiplication to be performed. The resulting bits assigned to out are then interpreted as signed again because of its declaration, but by then it's too late.
As you alluded to, the general Verilog signedness rule is that if any operand in a simple expression is unsigned, all operands in the expression are interpreted as unsigned, and thus the operators perform unsigned math. (There are many other nuances to the rules (e.g. relational operators), but they aren't applicable here.)
Note that you can't make {64{1'b1}} signed by changing it to {64{1'sb1}} because the result of the replication operator is always unsigned regardless of its operand. But you could wrap it in the $signed() system function, making the rest of the expression (the * and & steps) fully signed. Thus this would work correctly:
out <= (in1 * in2) & $signed({64{1'b1}});
But you really don't need to mask the result with that &. Regardless of the width of the inputs and the result of the multiplication, Verilog rules state that the final value of the RHS of the assignment will simply be truncated (discarding some MSBs) to the width of the LHS, if the RHS were wider. Thus masking with 64 ones is completely redundant.
To address the currently-accepted answer... It is not true that 65 bits are needed for 32x32 signed->signed multiplication. Only 64 bits are needed to handle even the most-extreme cases:
minimum result: -(2^31) * ((2^31) - 1) = -4611686016279904256 > -(2^63)
maximum result: ((2^31) - 1) * ((2^31) - 1) = 4611686014132420609 < (2^63) - 1
In general, for fully-signed multiplication of N bits by M bits, you only need N+M bits for the product (and N+M-1 would suffice if not for the single most-negative times most-negative case). This is also true for fully-unsigned multiplication. But if you were mixing signed and unsigned multiplicands/product (and using $signed() as needed to get Verilog to behave as desired), you would need an extra result bit in some cases (e.g. unsigned*unsigned->signed).

Related

Instantiate a module based on a condition in Verilog

I have a 1023 bit vector in Verilog. All I want to do is check if the ith bit is 1 and if it is 1 , I have to add 'i' to another variable .
In C , it would be something like :
int sum=0;
int i=0;
for(i=0;i<1023;i++) {
if(a[i]==1) {
sum=sum+i;
}
Of course , the addition that I am doing is over a Galois Field . So, I have a module called Galois_Field_Adder to do the computation .
So, my question now is how do I conditionally check if a specific bit is 1 and if so call my module to do that specific addition .
NOTE: The 1023 bit vector is declared as an input .
It's hard to answer your question without seeing your module, as we can't gage where you are in your Verilog. You always have to think of how your code translates in gates. If we want to translate your C code into synthesizable logic, we can take the same algorithm, go through each bit one after the other, and add to the sum depending on each bit. You would use something like this:
module gallois (
input wire clk,
input wire rst,
input wire [1022:0] a,
input wire a_valid,
output reg [18:0] sum,
output reg sum_valid
);
reg [9:0] cnt;
reg [1021:0] shift_a;
always #(posedge clk)
if (rst)
begin
sum[18:0] <= {19{1'bx}};
sum_valid <= 1'b0;
cnt[9:0] <= 10'd0;
shift_a[1021:0] <= {1022{1'bx}};
end
else
if (a_valid)
begin
sum[18:0] <= 19'd0;
sum_valid <= 1'b0;
cnt[9:0] <= 10'd1;
shift_a[1021:0] <= a[1022:1];
end
else if (cnt[9:0])
begin
if (cnt[9:0] == 10'd1022)
begin
sum_valid <= 1'b1;
cnt[9:0] <= 10'd0;
end
else
cnt[9:0] <= cnt[9:0] + 10'd1;
if (shift_a[0])
sum[18:0] <= sum[18:0] + cnt[9:0];
shift_a[1021:0] <= {1'bx, shift_a[1021:1]};
end
endmodule
You will get your result after 1023 clock cycles. This code needs to be modified depending on what goes around it, what interface you want etc...
Of importance here is that we use a shift register to test each bit, so that the logic adding your sum only takes shift_a[0], sum and cnt as an input.
Code based on the following would also work in simulation:
if (a[cnt[9:0])
sum[18:0] <= sum[18:0] + cnt[9:0];
but the logic adding to sum would in effect take all 1023 bits of a[] as an input. This would be quite hard to turn into actual lookup tables.
In simulation, you can also implement something very crude such as this:
reg [1022:0]a;
reg [9:0] sum;
integer i;
always #(a)
begin
sum[9:0] = 10'd0;
for (i=0; i < 1023; i=i+1)
if (a[i])
sum[9:0] = sum[9:0] + i;
end
If you were to try to synthesize this, sum would actually turn into a chunk of combinatorial logic, as the 'always' block doesn't rely on a clock. This code is in fact equivalent to this:
always #(a)
case(a):
1023'd0: sum[18:0] = 19'd0;
1023'd1: sum[18:0] = 19'd1;
1023'd2: sum[18:0] = 19'd3;
etc...
Needless to say that a lookup table with 1023 input bits is a VERY big memory...
Then if you want to improve your code, and use your FPGA as an FPGA and not like a CPU, you need to start thinking about parallelism, for instance working in parallel on different ranges of your input a. But this is another thread...

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

systemverilog arithmetic operation returns negative value

I have a part of code of my design as follows.
parameter n=256;
input [n-1:0] x;
output y;
initial begin
x = 0;
if(0 >= unsigned'(x-9))
y = 1;
end
My expectation is, the unsigned subtraction operation should return decimal 247 but in actual it returns -9. Is anyone having better way of coding to achieve this?
My actual requirement is, even if I subtract a smaller value from larger, the value should rollover w.r.t. parameter width (As if 0-1 should yield 255). My question may be wrong but this requirement is necessary from my project.
247 and -9 are the same bit pattern so the arithmetic is correct. Signed vs unsigned is an interpretation of the bit pattern.
NB: 0-1 is only 255 with 8 bit numbers you have defined them as 256 bit numbers.
The following example should help clarify, We use $signed and $unsigned keywords which alters how the decimal representation is displayed but the underlying binary form does not change.
module tb;
parameter n=8;
logic [n-1:0] x;
logic y;
initial begin
x = 0;
$display("%1d", x-9);
$display("%1b", x-9);
$display("");
$display("%1d", $unsigned(x-9) );
$display("%1b", $unsigned(x-9) );
$display("");
$display("%1d", $signed(x-9) );
$display("%1b", $signed(x-9) );
$display("");
$finish;
end
endmodule
Which Outputs:
4294967287
11111111111111111111111111110111
4294967287
11111111111111111111111111110111
-9
11111111111111111111111111110111
For your example you just need to use $unsigned:
module tb;
parameter n=8;
logic [n-1:0] x;
logic y;
initial begin
x = 0;
if(0 >= $unsigned(x-9)) begin
y = 1;
end
else begin
y = 0;
end
$display("y: %b", y);
$finish;
end
endmodule

How to zero-extend a number if it is valid, or X-extend it otherwise?

I have a 16-bit number which might be x (i.e. unknown).
I would like to zero-extend the number to 32 bits, but if the MSB is x, then I would like it to be x-extended instead of zero-extended. (This helps with my simulation.)
How can I do this?
Unless you are working with signed values, I think you will need a custom function for this. If you are working with signed values, the MSB will be X-extended on an assignment from a 16-bit value to a 32-bit value if the sign bit is X. However if the MSB (the sign bit) is a 1 then it will be 1-extended, which is most likely not what you want if you are working with unsigned values.
Here's a simple function to do this.
function [31:0] extend(input[15:0] in);
begin
if (in[15] === 1'bX) begin
extend = {16'hXXXX, in};
end else begin
extend = {16'h0000, in};
end
end
endfunction
Example:
$display("%032b", extend(16'h0000));
$display("%032b", extend(16'hFFFF));
$display("%032b", extend(16'bX000_0000_0000_0000));
Output:
00000000000000000000000000000000
00000000000000001111111111111111
xxxxxxxxxxxxxxxxx000000000000000
If your simulator is modern enough to support SystemVerilog syntax:
module tb;
reg [15:0] a;
reg [31:0] b;
initial begin
$monitor("a='b%b b='b%b", a, b);
#5 a= '1; extendo();
#5 a= '0; extendo();
#5 a= 'z; extendo();
end
task extendo;
b[15:0] = a[15:0];
b[31:16] = (a[15] === 1'bx) ? 'x : '0;
endtask
endmodule
Output:
a='bxxxxxxxxxxxxxxxx b='bxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
a='b1111111111111111 b='b00000000000000001111111111111111
a='b0000000000000000 b='b00000000000000000000000000000000
a='bzzzzzzzzzzzzzzzz b='b0000000000000000zzzzzzzzzzzzzzzz

Timing issue in Verilog

I am new to verilog and I am working on verilg code that defines two modules.
The first module calculates the mod of 2 numbers and the second uses the result to do some operation on it.
The result was wrong and has alot of don't care values because the same clk was used in both modules. Any suggestion please for synchronisation.
The mod module
module mod(m,a,b);
input [15:0] a,b;
output [15:0] m;
reg [31:0] mod;
reg [31:0] mul;
integer i;
always #* begin
mul = a*b;
mod = 32'h80008000;
for(i=0;i<16;i=i+1) begin
if(mul > mod) begin
mul = mul - mod;
mod = mod >> 1;
end
else begin
mod = mod >> 1;
end
end
assign m=mul[15:0];
endmodule
Part of the top module:
initial begin
keyp <= 2'b10;
shift <= 1'b0;
end
always #(posedge clk) begin
if(load)
case (keyp)
2'b10: begin
key[127:64] <= {k1,k0};
keyp <= 2'b01;
end
2'b01: begin
key[63:0] <= {k1,k0};
keyp <= 2'b00;
shift <= 1'b1;
end
//default: keyp <=2'b00;
endcase
else if (shift) begin
//shift key for first round
temp[24:0] <= key[127:103];
key[127:25] <= key[102:0];
key [24:0] <= temp [24:0];
shift <= 1'b0;
end
end
assign w1[2*SIZE-1:SIZE] = d1+key[2*SIZE-1:SIZE];
assign w1[3*SIZE-1:2*SIZE] = d2+key[3*SIZE-1:2*SIZE];
mod mod1( w1[SIZE-1:0], d0, key[SIZE-1:0] );
mod mod2( w1[4*SIZE-1:3*SIZE], d3, key[4*SIZE-1:3*SIZE]);
Assigning to the same value multiple times with blocking assignments is perfectly valid Verilog. Even having the same term appear on both sides is fine, provided it's been assigned at least once prior to that.
The code here is incomplete but the problem appears to be that the code is assigning to 'key' in multiple places. Both as the output of the mod instances and inside the clocked block. Anytime these two 'disagree' about the value of key it's going to been seen as an X. X in addition to representing unknown also reflects contention where two different assignments conflict.
Since I'm not sure what this code is meant to do (seems to be some sort of encryption) I can't offer a fix but you need to separate the assignments to key.
x's are referred to as do not cares in casex statements or Karnaugh maps, here they represent unknown values. Unknown values can come from a value not being initialised (reset) or multiple (conflicting) drivers.
The mod module contains this section of code:
always #* begin
mul = a*b;
mod = 32'h80008000;
for(i=0;i<16;i=i+1) begin
if(mul > mod) begin
mul = mul - mod;
mod = mod >> 1;
end
else begin
mod = mod >> 1;
end
end
always #* is a combinatorial block, you assign mul multiple times only the last assignment will have any effect.
The use of a for loop here makes it look like you are trying to reuse variables, as you would in c. Remember that we are describing hardware and that the value is intended to exist somewhere as flip flops or wires between modules and can only hold a single value in any given clock cycle.
In the combinatorial block you have mul = mul - mod; that is mul defining itself this will not work, you need to add a flip flop to break the loop.

Resources