i'm trying to multiply two 32 bit signed fractional number (1 sign bit, 8 integer bit, 23 fraction bit)
the first one is
32'b0_00000001_00000000000000000000000 // 1.00
the 2nd one is
32'b0_00000100_00000000000000000000000 // 4.00
when i do like this for example
output signed[31:0] a;
assign a = 32'b0_00000001_00000000000000000000000 * 32'b0_00000100_00000000000000000000000;
the results is zero? why it isn't 4?
kindly please help me in which part i am mistaken and what should i do. thank you very much
regards
Isaac
Because you are trying to assign a 64 bit value to a 32 bit wire, and Verilog will truncate the value, keeping only the lower 32 bits of the result, which is zero.
To have a proper result, you can do as this:
module mult;
reg [31:0] a = 32'b0_00000001_00000000000000000000000; // 1.0
reg [31:0] b = 32'b0_00000100_00000000000000000000000; // 4.0
reg [63:0] t;
reg [31:0] c;
initial begin
t = a * b;
c = t[54:23];
$display ("%b",c);
$finish;
end
endmodule
Related
Tried implementing Karatsuba multiplier for multiplying two binary numbers, the logic below works well for unsigned numbers, but getting incorrect answer when I change one of the inputs to a negative. In the example below a=1010011111000000(equals -88.25) and b= 0001010001000000(equals 20.25). The answer should be 11111001000001001111000000000000(equals:-1787.0625)but I end up getting the incorect answer. Have used fixed point logic, with inputs 16 bits and fraction point 8 bits, output being 32 bits with fraction bits 16.
module karatsuba( input signed [15:0] a,
input signed [15:0] b,
output signed [31:0] out
);
reg [15:0] ac,bd;
reg [31:0] t1;
reg [31:0]t2;
reg [24:0] psum;
initial begin
assign ac = a[15:8]*b[15:8];
assign bd = a[7:0]*b[7:0];
assign t2= bd;
assign t1={ac,16'b0000000000000000};
assign psum = {(a[15:8]+a[7:0])*(b[15:8]+b[7:0])-ac-bd,8'b00000000};
end
assign out= t1+psum+t2;
endmodule
module karatsuba_tb();
reg signed [15:0]a,b;
wire signed [31:0]out;
karatsuba uut(.a(a),.b(b),.out(out));
initial begin
a=16'b0101100001000000;
b=16'b0001010001000000;
end
endmodule
enter image description here
enter image description here
There are two issues pertaining to the signed multiply in the post:
Slices of vector variables (even slices of signed vectors) are treated as unsigned in Verilog. This is because when a slice is taken there is no way to identify the original sign bit, therefore it must be treated as unsigned
The solution is to cast the slices to signed so that Verilog treats them as signed. Like this:
assign ac = signed'(a[3:2]) * signed'(b[3:2]);
Make the line that defines the variable ac,bd to be treated as signed using the signed keyword (default is unsigned).
You will need to propagate these changes to other places in the posted code which have the same issues.
Here is a simplified version of the post using small numbers to illustrate the cast and keyword use:
module karatsuba(
input signed [3:0] a,
input signed [3:0] b
);
reg signed [3:0] ac;
assign ac = signed'(a[3:2]) * signed'(b[3:2]);
endmodule
module karatsuba_tb();
reg signed [3:0]a,b;
karatsuba uut(.a(a),.b(b));
initial begin
a = 4'b1110;
b = 4'b1111;
#1;
//
$display("---------------");
$display("uut.a[3:2] = %b",uut.a[3:2]);
$display("uut.b[3:2] = %b",uut.b[3:2]);
$display("uut.ac = %b",uut.ac);
$display("---------------");
//
$display("uut.a[3:2] = %d",signed'(uut.a[3:2]));
$display("uut.b[3:2] = %d",signed'(uut.b[3:2]));
$display("uut.ac = %d",uut.ac);
$display("---------------");
end
endmodule
The example displays this message at runtime:
---------------
uut.a[3:2] = 11
uut.b[3:2] = 11
uut.ac = 0001
---------------
uut.a[3:2] = -1
uut.b[3:2] = -1
uut.ac = 1
---------------
I am designing a signed verilog multiplier which I intend to use multiple times in another module.
My two inputs will be always s4.27 format. 1 bit signed, 4 bits of integer and 27 bits of fraction. My output has to be also in s4.27 format and I have to get the most accurate result out of it.
In C, the following not so perfect code snippet did the job.
int32_t mul(int32_t x, int32_t y)
{
int64_t mul = x;
mul *= y;
mul >>= 27;
return (int32_t) mul;
}
In verilog my simple version of code is given below,
`timescale 1ns/1ps
module fixed_multiplier (
i_a,
i_b,
o_p,
clk
);
input clk;
input signed [31:0] i_a;
input signed [31:0] i_b;
output signed [31:0] o_p;
wire signed [63:0] out;
assign out = i_a*i_b;
assign o_p = out;
endmodule
The above mentioned code has bugs that I know because I am not getting the desired results at all.
So my questions are,
(1) As this line "assign o_result = out;" seems crucial to me, how shall I do my assignments to my final output so that I get the correct and most accurate s4.27 format output? Please note, this output will be fed to an adder and the adder output will be again an input for the multiplier.
Above question being asked, I also tried with xor-ing of sign bits of both inputs and assigning [57:27] bits to final output. Did not suit me and resulted in overflow, while in C same inputs did not give any overflow error.
(2) With C I did not have any problem with fixed-point multiplication while in verilog I guess I am struggling as I am quite a newbie. Any suggestions what things to keep in mind while dealing with signed multiplication/addition?
Below is the testbench code,
`timescale 1ns / 1ps
module tb_mul;
// Inputs
reg clk;
reg [31:0] a;
reg [31:0] b;
// Outputs
wire [31:0] c;
fixed_multiplier mul_i (
.clk(clk),
.i_a(a),
.i_b(b),
.o_p(c)
);
initial begin
$dumpfile("test_mul.vcd");
$dumpvars(1);
$monitor ("a=%h,\tb=%h,\tc=%h",a,b,c);
a = 32'h10000000;
b = 32'h10000000;
$finish();
end
endmodule
Thank you in advance.
Your multiplier does not work like you think it does. Verilog will assume your multiplication will be unsigned, and will compute it as such. You might want to do something like the following:
wire [61:0] temp_out;
assign temp_out = i_multiplicand[30:0] * i_multiplier[30:0];
assign sign = i_multiplicand[31] ^ i_multiplier[31];
assign out = {sign, temp_out[57:37]};
I have this verilog code from my university course which implements a basic multiplier.
//this is a portion of the code.
reg [16:0] multiplicand_copy;
input [7:0] multiplicand;
multiplicand_copy = {9'd0, multiplicand}; // this line is my question
somewhere in the code there is this assignment using brackets that i can't understand.What kind of assignment is this and what's happening in this line ?I appreciate any help.
reg [16:0] multiplicand_copy;
input [7:0] multiplicand;
multiplicand_copy = {9'd0, multiplicand};
In this code snippet, multiplicand is 8 bits variable and multiplicand_copy is 17 bits variable.
multiplicand_copy = {9'd0, multiplicand}; will do concatenation of 9 zeros and 8 bits of multiplicand and make assignment of 17 bits of multiplicand_copy.
Can you help me guys do a 32-bit ALU and explain me some things?
Wanna do:
0 bitwise AND: out = inA & inB.
1 bitwise OR: out = inA | inB.
2 addition: out = inA + inB.
6 subtraction: out = inA – inB //2's complement
7 Set On Less Than: out = ((inA < inB)?1:0)
12 NOR: out = ~( inA | inB)
Done this so far:
module ALU #(parameter N=32)(ALUOut, Zero, ALUinA, ALUinB, ALUop);
output [N-1:0] ALUOut;
reg [N-1:0] ALUOut;
output Zero;
reg Zero;
input [3:0] ALUop;
input [N-1:0] ALUinA, ALUinB;
always #(ALUinA or ALUinB or ALUop)
begin
case (ALUop)
4'b0000: ALUOut = ALUinA & ALUinB ; // 0:AND
Your code is good. Just some modifications required. ALUOut must be [N:0], since you'll require a carry bit in case of addition. Also, borrow bit must be required in case of subtraction.
Referring to SystemVerilog LRM 1800-2012 Section 11.6 Expression bit lengths,
SystemVerilog uses the bit length of the operands to determine how many bits to use while evaluating an
expression.
So, ALUOut[N-1:0] = ALUinA[N-1:0] + ALUinB[N-1:0]; will strictly evaluate an expression of N, while ALUOut = ALUinA + ALUinB; will
evaluate depending on size of ALUOut. Here, you can not see the difference, since all youe operands are N bits wide, but when ALUOut is increased to N+1 bits(including carry), then it can create a difference.
For example,
module top();
bit [3:0] a,b;
logic [3:0] sum;
bit carry;
assign sum[3:0] = a[3:0] + b[3:0];
// assign {carry,sum}= a + b;
initial
$monitor("a = %0d b = %0d carry = %0d sum = %0d",a,b,carry,sum);
initial
begin
a = 5; b = 1;
#5 ; a = 15; b = 1;
end
endmodule
shall execute to a = 15 b = 1 carry = 0 sum = 0 while, using the commented assign statement executes to a = 15 b = 1 carry = 1 sum = 0
Refer to LRM 1800-2012, Section 11.6 for further information.
Also, this and this links regarding ALU design can be useful.
In 2's complement -B is ~B+1 (~ is bit invert). Therefor A - B == A + (-B) == A + ~B + 1. But your doing RTL, so you don't need to write the 2's complement for subtraction as it is default. A - B and A + ~B + 1 will synthesize the same.
A[N-1:0] + B[N-1:0] is always an unsigned operation. A + B can be a signed operation if A and B are declared as input signed [N-1:0] A, B, otherwise it is an unsigned operation.
Other notes:
There is an issue with your header. Many simulators, synthesizers, and other Verilog tools will accept what you have, but it is not complaint with the IEEE standard. There are two header styles, ANSI and non-ANSI. I recommend ANSI unless required to follow the IEEE1364-1995 version of the standard.
ANSI style (IEEE Std 1364-2001 and above):
module ALU #(parameter N=32)(
output reg [N-1:0] ALUOut,
output reg Zero,
input [N-1:0] ALUinA, ALUinB,
input [3:0] ALUop );
Non-ANSI style (IEEE Std 1364-1995 and above):
module ALU (ALUOut, Zero, ALUinA, ALUinB, ALUop);
parameter N=32;
output [N-1:0] ALUOut;
output Zero;
input [3:0] ALUop;
input [N-1:0] ALUinA, ALUinB;
reg [N-1:0] ALUOut;
reg Zero;
always #(ALUinA or ALUinB or ALUop) is syntax legal. However since IEEE1364-2001 combinational logic is recommenced to be written as always #* or always #(*) (#* and #(*) are synonymous, user preference). With SystemVerilog (IEEE1800), the successor of Verilog (IEEE1364), always_comb is recommend over always #* for combinational logic, and always_latch for level-sensitive latching logic.
I'm trying to implement as follows to multiplying by 15.
module mul15(
output [10:0] result,
input [3:0] a
);
assign result = a*15;
endmodule
But is there any improve way to multiplying to a by 15?
I think there are 2 ways like this
1.result = a<<4 -1;
2.result = {a,3'b1111_1111};
Ans I think the best way is 2.
but I'm not sure also with aspect to synthesis.
update:
What if I am multiplying 0 at {a,3'b1111_1111}? This is 255 not 0.
Does anyone know the best way?
Update
How about this way?
Case1
result = {a,8'b0}+ {a,7'b0}+ {a,6'b0}+ {a,5'b0}+ {a,4'b0}+ {a,7'b0}+ {a,3'b0}+ {a,2'b0}+ {a,1'b0}+ a;
But it looks 8 adder used.
Case2
result = a<<8 -1
I'm not sure what is the best way else.
There is always a*16 - a. Static multiplications of power of 2 are basically free in hardware; it is just hard-coded 0s to the LSB. So you just need one 11-bit full-subtracter, which is a full adder and some inverters.
other forms:
result = a<<4 - a;
result = {a,4'b0} - a; // unsigned full-subtractor
result = {a,4'b0} + ~a + 1'b1; // unsigned full-adder w/ carry in, 2's complement
result = {{3{a[3]}},a,4'b0} + ~{ {7{a[3]}}, a} + 1'b1; // signed full-adder w/ carry in, 2's complement
The cleanest RTL version is as you have stated in the question:
module mul15(
input [3:0] a
output reg [7:0] result,
);
always #* begin
result = a * 4'd15;
end
endmodule
The Multiplicand 15 in binary is 4'b1111; That is 8 + 4 + 2 + 1.
Instead of a multiplier it could be broken down into the sum of these powers of 2. Powers of 2 are just barrel shifts. This is how a shift and add multiplier would work.
module mul15(
input [3:0] a
output reg [7:0] result,
);
always #* begin
// 8 4 2 1 =>15
result = (a<<3) + (a<<2) + (a<<1) + a;
end
endmodule
To minimise the number of adders required a CSD could be used. making 15 out of 16-1:
module mul15(
input [3:0] a
output reg [7:0] result,
);
always #* begin
// 16 - 1 =>15
result = (a<<4) - a;
end
endmodule
With a modern synthesis tool these should all result in same the thing. Therefore having more readable code which gives a clear instruction to the tool as to what you intended gives it the free rein to optimise as required.