Hi, I found a problem when multiplying 0x80000000 by 0x80000000. The result should be 0x4000000000000000, but it is 0xC000000000000000. I found it with the following test code: li $t2, 0x80000000 mult $t2, $t2 mflo $t0 bne $t0, 0, fail mfhi $t1 bne $t1, 0x40000000, fail See you
Multiplying 0x80000000 times a negative number causes the bug. This is because -0x80000000 = ~0x80000000+1 = 0x80000000.
Here is a possible fix to mult.vhd:
when MULT_SIGNED_MULT =>
mode_reg <= MODE_MULT;
if b(31) = '0' then
aa_reg <= a;
bb_reg <= b;
sign_reg <= a(31);
--Special case of 0x80000000 * negative number
elsif a(31) = '1' and (a(30 downto 0) = ZERO(30 downto 0) or
b(30 downto 0) = ZERO(30 downto 0)) then
aa_reg <= a; --convert to unsigned mult
bb_reg <= b;
sign_reg <= '0';
else
aa_reg <= a_neg;
bb_reg <= b_neg;
sign_reg <= a_neg(31);
end if;
What do you think about the following change? Maybe it requires less logic.
mode_reg <= MODE_MULT; if b(31) = '0' then aa_reg <= a; bb_reg <= b; -- sign_reg <= a(31); else aa_reg <= a_neg; bb_reg <= b_neg; -- sign_reg <= a_neg(31); end if; sign_reg <= a(31) xor b(31); -- added line sign2_reg <= '0'; ...
Your solution is much better. I checked it in.
Thanks, Steve