Forum Discussion
Altera_Forum
Honored Contributor
8 years agoI finally realized the reason the tools balk at using "*" for an unsigned times a signed is that numeric_std does not have function "*" defined for that case. My first inclination was to emulate numeric_std for that case. Works great in simulation, but for synthesis it gives incorrect answers if the upper bit of the unsigned is set. For example, for two 8 bit numbers, 160 * 2 gave -192 in SignalTap because 160 is "10100000" which is -96.
So synthesis is creating a signed * signed and really can't infer a mixed type multiplier. I had resisted your idea in the past since I'm pretty sure I lose a bit in my DSP block. But in practice very few of my multipliers are on the "edge" of the 18x18 or 18x19 boundary and I could handle them specially. It's worth the convenience. I just defined a function:
/*
Multiply an unsigned and signed.
*/
function "*" (L : unsigned; R : signed) return signed is
constant PROD_BITS : integer := L'length + R'length;
variable XL : signed(L'left + 1 downto 0); -- 1 bit longer than L
variable RESULT : signed(PROD_BITS downto 0) := (others => '0'); -- Extra bit
begin
-- Turn unsigned into a positive signed.
XL := signed('0' & L);
-- Infer a "signed" * signed mult
RESULT := XL * R;
-- Only need PROD_BITS of result
return RESULT(PROD_BITS - 1 downto 0);
end function "*";
and can now do things such as your example:
ip1 : unsigned(7 downto 0);
ip2 : signed(8 downto 0);
op : signed(16 downto 0); -- Extra bit not needed
...
op <= ip1 * ip2;
Really simplifies code and fitter report confirms it infers a hard multiplier. I used the "technique" of redefining component types in quite a few places in both Xilinx and Altera tools of last 20 years (eg address inputs to RAM as unsigned), but the multipliers were the main issue. Type conversions on inputs are pretty simple.