Forum Discussion
Altera_Forum
Honored Contributor
17 years agosigned/unsigned multipliers
I can't seem to find a way to instantiate a multiplier that will dynamically select between signed and unsigned multiplication. This is on a Cyclone II, but applies to other parts as well.
Reading the Cyclone II documentation it is clear that signa, signb inputs does what I want, but none of the multipliers created with the Wizzard exports that as an input signal. Trying to infer it with the code below doesn't work (bug in Quartus II?); it complains that no logic depends on input_sign. However looking at the RTL with Tools/Netlist Viewers/RTL Viewer clearly shows it being used, however the technology map viewer shows input_sign as disconnected and signa and signb hardwired to ground. This looks like a bug to me, but I could be doing something wrong.
module mult(input clock,
input input_sign,
input input_a,
input input_b,
output reg output_c);
reg a, b;
reg sign;
always @(posedge clock) begin
sign <= input_sign;
a <= input_a;
b <= input_b;
if (sign)
output_c <= $signed(a) * $signed(b);
else
output_c <= $unsigned(a) * $unsigned(b);
end
endmodule
42 Replies
- Altera_Forum
Honored Contributor
--- Quote Start --- It is always true if we allow for correct width. The issue of 8 bit width representing numbers from 0~127 and -1 to -128 is separate. The puzzle still stands: - => + should reverse + => - naturally hence for - => + subtract 1 then invert (by definition) but how come the same rule apply to both conversions as well. i.e. [invert add 1] in either case. --- Quote End --- If you search Wikipedia for "two's complement" there is an explanation, but rather complex. For me, when you start with a positive number and complement the objective is to find the distance from zero in the negative direction so when you complement 0 "adding 1" has the effect of reducing the magnitude so that 0 is still zero, but the magnitude of all negative numbers appears to be offset toward 0. When you complement the negative number you have to add 1 to adjust the magnitude to get the correct distance from 0 in the positive direction. Therefore the maximum negative number 1.000 ... 0 is farther away from 0 than the maximum positive number and cannot be converted. - Altera_Forum
Honored Contributor
It makes sense. The way I make sense is this:
[invert => +1] naturally reverses by [-1 => invert] but if we also reverse the order of operations then : [-1 => invert] becomes equivalent to [invert => +1] - Altera_Forum
Honored Contributor
Consider the case for 8 bit values
Bitwise inversion of x is equivalent to 255-x Negation of x is equivalent to 0-x Ignoring any carry/borrow, 0-x is equivalent 256-x = (255-x)+1 = 255-(x-1) i.e Negation (2's complement) can be done as "invert then increment" or "decrement then invert" - Altera_Forum
Honored Contributor
It is always true if we allow for correct width. The issue of 8 bit width representing numbers from 0~127 and -1 to -128 is separate.
The puzzle still stands: - => + should reverse + => - naturally hence for - => + subtract 1 then invert (by definition) but how come the same rule apply to both conversions as well. i.e. [invert add 1] in either case. - Altera_Forum
Honored Contributor
--- Quote Start --- I - => + invert bits then add 1 ?? how come this correct --- Quote End --- Still true. The only problem may be in the most negative number, which does not have the equivalent positive number in two's complement. That is, for 8-bits we can represent from -128 to +127. So, -128 does not have its positive equivalent. - Altera_Forum
Honored Contributor
--- Quote Start --- the operand is signed the operands need to be converted to positive format, multiplied then converted to negative at the end if the signs are different. --- Quote End --- I agree and the math proof is very straightforward: n * -m = - (n * m) -n *m =-(n*m) so just convert -m to +m, multiply as unsigned, convert result back to negative. The overheads include two setd of inverter + two adders but: -m * -n = +(n*m) convert sign inputs but not output. I wonder if Trick have a math proof for his trick By the way here is a 2's complement puzzle: + => - invert bits then add 1 - => + invert bits then add 1 ?? how come this correct (or take 1 then invert bits, makes more sense) --- Quote Start --- Not commenting at all on the logistics of signed/unsigned multiplications, but more on synthesizable code, if you write: signal sum : signed(3 downto 0); IF(inc = '1') THEN sum <= sum + 1; ELSIF(dec = '1') THEN sum <= sum - 1; ELSE sum <= sum; END IF; It will usually generate two adders and then mux the output together. However, if you were to write: signal inc : integer range -1 to 1; signal sum : signed(3 downto 0); inc <= -1 when dec = '1' else 1 when inc = '1' else 0; sum <= sum + inc; Then it will usually generate a single adder with a mux at one of the input ports. Obviously the summation should be in a clocked process, but i am being lazy. Just a thought. Kevin --- Quote End --- True, compiler instantiates one operation unit per operand occurence. It doesn't want to know your intentions. I refrred to this ages ago regarding multipliers, to avoid this use one (*) assignment only then switch your inputs/outputs as you wish. - Altera_Forum
Honored Contributor
Not commenting at all on the logistics of signed/unsigned multiplications, but more on synthesizable code, if you write:
signal sum : signed(3 downto 0); IF(inc = '1') THEN sum <= sum + 1; ELSIF(dec = '1') THEN sum <= sum - 1; ELSE sum <= sum; END IF; It will usually generate two adders and then mux the output together. However, if you were to write: signal inc : integer range -1 to 1; signal sum : signed(3 downto 0); inc <= -1 when dec = '1' else 1 when inc = '1' else 0; sum <= sum + inc; Then it will usually generate a single adder with a mux at one of the input ports. Obviously the summation should be in a clocked process, but i am being lazy. Just a thought. Kevin - Altera_Forum
Honored Contributor
--- Quote Start --- I'm still trying to get the synthesis bug fixed --- Quote End --- I don't understand exactly, what's the synthesis bug in your opinion. Hardware multipliers can be used with variable number representation, but not through lpm_mult. Cause HDL inference uses apparently lpm_mult, it doesn't provide a variable representation. - Altera_Forum
Honored Contributor
There is no way to represent a negative number in an unsigned integer. Therefore an unsigned multiplier will generate a product as if all 1 bits represent positive 2 to the nth.
Whether the multiplier does it or not based on the most significant bit and an indicator of whether the operand is signed the operands need to be converted to positive format, multiplied then converted to negative at the end if the signs are different. let's multiply 2 times -7. (0007 -> fff8 + 1 = fff9) ... 0002 * fff9 = 0001fff2 unsigned. but 2 * 7 = e ... * -1 = 0000fff2 signed. So if you only look at the low 16 bits, they match. If you extend the sign to 32 bits, then you are multiplying 32 bit integers, which by the way produce 64 bit products. If your computer is to be a general purpose I think you have the choice to implement the traditional algorithm ... make both operands positive, multiply, and if signs were different, then complement the product, otherwise invent new multipliers which handle both ops negative or either op negative, then select one of the four based upon the sign bits. I have uploaded a zipped C# project file that has a simple loop to sequence through operand values which may be of interest. (if you have a C# IDE to run it on. - Altera_Forum
Honored Contributor
--- Quote Start --- Just to clarify, have you tried FvM's solution using altmult_add? It's certainly there in Quartus 6.1 and although the symbol in the MegaWizard looks a bit mad at first, if you do as FvM says and set the number of multipliers to 1 it simplifies up a treat. As a matter of interest, what was the workaround you chose in the end? --- Quote End --- Yes, the workaround looks great in Q II 8.1 (I failed to notice the "variable" option for input signedness when I first looked at it). I'm still trying to get the synthesis bug fixed, but that might take a while. I'll follow up if there's news. Thanks all, Tommy