@ -169,6 +169,9 @@ architecture behaviour of fpu is
oe : std_ulogic;
oe : std_ulogic;
xerc : xer_common_t;
xerc : xer_common_t;
xerc_result : xer_common_t;
xerc_result : xer_common_t;
res_negate : std_ulogic;
res_subtract : std_ulogic;
res_rmode : std_ulogic_vector(2 downto 0);
end record;
end record;
type lookup_table is array(0 to 1023) of std_ulogic_vector(17 downto 0);
type lookup_table is array(0 to 1023) of std_ulogic_vector(17 downto 0);
@ -605,15 +608,21 @@ architecture behaviour of fpu is
end;
end;
-- Construct a DP floating-point result from components
-- Construct a DP floating-point result from components
function pack_dp(sign: std_ulogic; class: fp_number_class; exp: signed(EXP_BITS-1 downto 0);
function pack_dp(negative: std_ulogic; class: fp_number_class; exp: signed(EXP_BITS-1 downto 0);
mantissa: std_ulogic_vector; single_prec: std_ulogic; quieten_nan: std_ulogic)
mantissa: std_ulogic_vector; single_prec: std_ulogic; quieten_nan: std_ulogic;
negate: std_ulogic; is_subtract: std_ulogic; round_mode: std_ulogic_vector)
return std_ulogic_vector is
return std_ulogic_vector is
variable dp_result : std_ulogic_vector(63 downto 0);
variable dp_result : std_ulogic_vector(63 downto 0);
variable sign : std_ulogic;
begin
begin
dp_result := (others => '0');
dp_result := (others => '0');
dp_result(63) := sign;
sign := negative;
case class is
case class is
when ZERO =>
when ZERO =>
if is_subtract = '1' then
-- set result sign depending on rounding mode
sign := round_mode(0) and round_mode(1);
end if;
when FINITE =>
when FINITE =>
if mantissa(UNIT_BIT) = '1' then
if mantissa(UNIT_BIT) = '1' then
-- normalized number
-- normalized number
@ -633,6 +642,7 @@ architecture behaviour of fpu is
dp_result(28 downto 0) := mantissa(SP_LSB - 1 downto DP_LSB);
dp_result(28 downto 0) := mantissa(SP_LSB - 1 downto DP_LSB);
end if;
end if;
end case;
end case;
dp_result(63) := sign xor negate;
return dp_result;
return dp_result;
end;
end;
@ -1468,8 +1478,8 @@ begin
v.fpscr(FPSCR_FR) := '0';
v.fpscr(FPSCR_FR) := '0';
v.fpscr(FPSCR_FI) := '0';
v.fpscr(FPSCR_FI) := '0';
is_add := r.a.negative xor r.b.negative xor r.insn(1);
is_add := r.a.negative xor r.b.negative xor r.insn(1);
v.is_subtract := not is_add;
if r.a.class = FINITE and r.b.class = FINITE then
if r.a.class = FINITE and r.b.class = FINITE then
v.is_subtract := not is_add;
v.add_bsmall := r.exp_cmp;
v.add_bsmall := r.exp_cmp;
v.opsel_a := AIN_B;
v.opsel_a := AIN_B;
if r.exp_cmp = '0' then
if r.exp_cmp = '0' then
@ -1491,18 +1501,13 @@ begin
v.fpscr(FPSCR_VXISI) := '1';
v.fpscr(FPSCR_VXISI) := '1';
qnan_result := '1';
qnan_result := '1';
arith_done := '1';
arith_done := '1';
elsif r.a.class = ZERO and r.b.class = ZERO and is_add = '0' then
-- return -0 for rounding to -infinity
v.result_sign := r.round_mode(1) and r.round_mode(0);
arith_done := '1';
elsif r.a.class = INFINITY or r.b.class = ZERO then
elsif r.a.class = INFINITY or r.b.class = ZERO then
-- result is A
-- result is A; we're already set up to put A into R
v.opsel_a := AIN_A;
arith_done := '1';
v.state := EXC_RESULT;
else
else
-- result is +/- B
-- result is +/- B
v.opsel_a := AIN_B;
v.opsel_a := AIN_B;
v.negate := not r.insn(1);
v.result_sign := r.b.negative xnor r.insn(1);
v.state := EXC_RESULT;
v.state := EXC_RESULT;
end if;
end if;
end if;
end if;
@ -1541,7 +1546,6 @@ begin
else
else
-- r.c.class is ZERO or INFINITY
-- r.c.class is ZERO or INFINITY
v.opsel_a := AIN_C;
v.opsel_a := AIN_C;
v.negate := r.a.negative;
v.state := EXC_RESULT;
v.state := EXC_RESULT;
end if;
end if;
end if;
end if;
@ -1599,8 +1603,10 @@ begin
v.fpscr(FPSCR_FI) := '0';
v.fpscr(FPSCR_FI) := '0';
if r.a.class = ZERO or (r.a.negative = '0' and r.a.class /= NAN) then
if r.a.class = ZERO or (r.a.negative = '0' and r.a.class /= NAN) then
v.opsel_a := AIN_C;
v.opsel_a := AIN_C;
v.result_sign := r.c.negative;
else
else
v.opsel_a := AIN_B;
v.opsel_a := AIN_B;
v.result_sign := r.b.negative;
end if;
end if;
v.quieten_nan := '0';
v.quieten_nan := '0';
v.state := EXC_RESULT;
v.state := EXC_RESULT;
@ -1720,9 +1726,10 @@ begin
v.fpscr(FPSCR_FR) := '0';
v.fpscr(FPSCR_FR) := '0';
v.fpscr(FPSCR_FI) := '0';
v.fpscr(FPSCR_FI) := '0';
is_add := r.a.negative xor r.c.negative xor r.b.negative xor r.insn(1);
is_add := r.a.negative xor r.c.negative xor r.b.negative xor r.insn(1);
v.negate := r.insn(2);
v.is_subtract := not is_add;
if r.a.class = FINITE and r.c.class = FINITE and
if r.a.class = FINITE and r.c.class = FINITE and
(r.b.class = FINITE or r.b.class = ZERO) then
(r.b.class = FINITE or r.b.class = ZERO) then
v.is_subtract := not is_add;
-- Make sure A and C are normalized
-- Make sure A and C are normalized
if r.a.mantissa(UNIT_BIT) = '0' then
if r.a.mantissa(UNIT_BIT) = '0' then
v.state := RENORM_A;
v.state := RENORM_A;
@ -1730,13 +1737,13 @@ begin
v.state := RENORM_C;
v.state := RENORM_C;
elsif r.b.class = ZERO then
elsif r.b.class = ZERO then
-- no addend, degenerates to multiply
-- no addend, degenerates to multiply
v.result_sign := r.a.negative xor r.c.negative xor r.insn(2);
v.result_sign := r.a.negative xor r.c.negative;
f_to_multiply.valid <= '1';
f_to_multiply.valid <= '1';
v.is_multiply := '1';
v.is_multiply := '1';
v.state := MULT_1;
v.state := MULT_1;
elsif r.madd_cmp = '0' then
elsif r.madd_cmp = '0' then
-- addend is bigger, do multiply first
-- addend is bigger, do multiply first
v.result_sign := not (r.b.negative xor r.insn(1) xor r.insn(2));
v.result_sign := r.b.negative xnor r.insn(1);
f_to_multiply.valid <= '1';
f_to_multiply.valid <= '1';
v.first := '1';
v.first := '1';
v.state := FMADD_0;
v.state := FMADD_0;
@ -1760,19 +1767,14 @@ begin
else
else
-- result is infinity
-- result is infinity
v.result_class := INFINITY;
v.result_class := INFINITY;
v.result_sign := r.a.negative xor r.c.negative xor r.insn(2);
v.result_sign := r.a.negative xor r.c.negative;
arith_done := '1';
arith_done := '1';
end if;
end if;
else
else
-- Here A is zero, C is zero, or B is infinity
-- Here A is zero, C is zero, or B is infinity
-- Result is +/-B in all of those cases
-- Result is +/-B in all of those cases
v.opsel_a := AIN_B;
v.opsel_a := AIN_B;
if r.b.class /= ZERO or is_add = '1' then
v.result_sign := r.b.negative xnor r.insn(1);
v.negate := not (r.insn(1) xor r.insn(2));
else
-- have to be careful about rule for 0 - 0 result sign
v.negate := r.b.negative xor (r.round_mode(1) and r.round_mode(0)) xor r.insn(2);
end if;
v.state := EXC_RESULT;
v.state := EXC_RESULT;
end if;
end if;
end if;
end if;
@ -1910,10 +1912,6 @@ begin
elsif (r_hi_nz or r_lo_nz or (or (r.r(DP_LSB - 1 downto 0)))) = '0' then
elsif (r_hi_nz or r_lo_nz or (or (r.r(DP_LSB - 1 downto 0)))) = '0' then
-- r.x must be zero at this point
-- r.x must be zero at this point
v.result_class := ZERO;
v.result_class := ZERO;
if r.is_subtract = '1' then
-- set result sign depending on rounding mode
v.result_sign := r.round_mode(1) and r.round_mode(0);
end if;
arith_done := '1';
arith_done := '1';
else
else
rs_norm <= '1';
rs_norm <= '1';
@ -1970,7 +1968,7 @@ begin
-- product is bigger here
-- product is bigger here
-- shift B right and use it as the addend to the multiplier
-- shift B right and use it as the addend to the multiplier
-- for subtract, multiplier does B - A * C
-- for subtract, multiplier does B - A * C
v.result_sign := r.a.negative xor r.c.negative xor r.insn(2) xor r.is_subtract;
v.result_sign := r.a.negative xor r.c.negative xor r.is_subtract;
re_sel2 <= REXP2_B;
re_sel2 <= REXP2_B;
re_set_result <= '1';
re_set_result <= '1';
-- set shift to b.exp - result_exp + 64
-- set shift to b.exp - result_exp + 64
@ -2030,7 +2028,6 @@ begin
if s_nz = '0' then
if s_nz = '0' then
-- must be a subtraction, and r.x must be zero
-- must be a subtraction, and r.x must be zero
v.result_class := ZERO;
v.result_class := ZERO;
v.result_sign := r.round_mode(1) and r.round_mode(0);
arith_done := '1';
arith_done := '1';
else
else
-- R is all zeroes but there are non-zero bits in S
-- R is all zeroes but there are non-zero bits in S
@ -2572,10 +2569,6 @@ begin
rs_neg2 <= '1';
rs_neg2 <= '1';
if mant_nz = '0' then
if mant_nz = '0' then
v.result_class := ZERO;
v.result_class := ZERO;
if r.is_subtract = '1' then
-- set result sign depending on rounding mode
v.result_sign := r.round_mode(1) and r.round_mode(0);
end if;
arith_done := '1';
arith_done := '1';
else
else
-- Renormalize result after rounding
-- Renormalize result after rounding
@ -2597,6 +2590,7 @@ begin
arith_done := '1';
arith_done := '1';
when NAN_RESULT =>
when NAN_RESULT =>
v.negate := '0';
if (r.use_a = '1' and r.a.class = NAN and r.a.mantissa(QNAN_BIT) = '0') or
if (r.use_a = '1' and r.a.class = NAN and r.a.mantissa(QNAN_BIT) = '0') or
(r.use_b = '1' and r.b.class = NAN and r.b.mantissa(QNAN_BIT) = '0') or
(r.use_b = '1' and r.b.class = NAN and r.b.mantissa(QNAN_BIT) = '0') or
(r.use_c = '1' and r.c.class = NAN and r.c.mantissa(QNAN_BIT) = '0') then
(r.use_c = '1' and r.c.class = NAN and r.c.mantissa(QNAN_BIT) = '0') then
@ -2606,10 +2600,13 @@ begin
end if;
end if;
if r.use_a = '1' and r.a.class = NAN then
if r.use_a = '1' and r.a.class = NAN then
v.opsel_a := AIN_A;
v.opsel_a := AIN_A;
v.result_sign := r.a.negative;
elsif r.use_b = '1' and r.b.class = NAN then
elsif r.use_b = '1' and r.b.class = NAN then
v.opsel_a := AIN_B;
v.opsel_a := AIN_B;
v.result_sign := r.b.negative;
elsif r.use_c = '1' and r.c.class = NAN then
elsif r.use_c = '1' and r.c.class = NAN then
v.opsel_a := AIN_C;
v.opsel_a := AIN_C;
v.result_sign := r.c.negative;
end if;
end if;
v.state := EXC_RESULT;
v.state := EXC_RESULT;
@ -2617,15 +2614,12 @@ begin
-- r.opsel_a = AIN_A, AIN_B or AIN_C according to which input is the result
-- r.opsel_a = AIN_A, AIN_B or AIN_C according to which input is the result
case r.opsel_a is
case r.opsel_a is
when AIN_B =>
when AIN_B =>
v.result_sign := r.b.negative xor r.negate;
re_sel2 <= REXP2_B;
re_sel2 <= REXP2_B;
v.result_class := r.b.class;
v.result_class := r.b.class;
when AIN_C =>
when AIN_C =>
v.result_sign := r.c.negative xor r.negate;
re_sel2 <= REXP2_C;
re_sel2 <= REXP2_C;
v.result_class := r.c.class;
v.result_class := r.c.class;
when others =>
when others =>
v.result_sign := r.a.negative xor r.negate;
re_sel1 <= REXP1_A;
re_sel1 <= REXP1_A;
v.result_class := r.a.class;
v.result_class := r.a.class;
end case;
end case;
@ -3171,6 +3165,7 @@ begin
invalid := '1';
invalid := '1';
v.result_class := NAN;
v.result_class := NAN;
v.result_sign := '0';
v.result_sign := '0';
v.negate := '0';
misc_sel <= "0001";
misc_sel <= "0001";
opsel_r <= RES_MISC;
opsel_r <= RES_MISC;
arith_done := '1';
arith_done := '1';
@ -3550,6 +3545,9 @@ begin
v.int_result := int_result;
v.int_result := int_result;
v.illegal := illegal;
v.illegal := illegal;
v.nsnan_result := v.quieten_nan;
v.nsnan_result := v.quieten_nan;
v.res_negate := v.negate;
v.res_subtract := v.is_subtract;
v.res_rmode := r.round_mode;
if r.integer_op = '1' then
if r.integer_op = '1' then
v.cr_mask := num_to_fxm(0);
v.cr_mask := num_to_fxm(0);
elsif r.is_cmp = '0' then
elsif r.is_cmp = '0' then
@ -3581,7 +3579,8 @@ begin
fp_result <= r.r;
fp_result <= r.r;
else
else
fp_result <= pack_dp(r.result_sign, r.result_class, r.result_exp, r.r,
fp_result <= pack_dp(r.result_sign, r.result_class, r.result_exp, r.r,
r.sp_result, r.nsnan_result);
r.sp_result, r.nsnan_result,
r.res_negate, r.res_subtract, r.res_rmode);
end if;
end if;
rin <= v;
rin <= v;