oe : std_ulogic;
xerc : 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;
type lookup_table is array(0 to 1023) of std_ulogic_vector(17 downto 0);
end;
-- 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);
- mantissa: std_ulogic_vector; single_prec: std_ulogic; quieten_nan: std_ulogic)
+ 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;
+ negate: std_ulogic; is_subtract: std_ulogic; round_mode: std_ulogic_vector)
return std_ulogic_vector is
variable dp_result : std_ulogic_vector(63 downto 0);
+ variable sign : std_ulogic;
begin
dp_result := (others => '0');
- dp_result(63) := sign;
+ sign := negative;
case class is
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 =>
if mantissa(UNIT_BIT) = '1' then
-- normalized number
dp_result(28 downto 0) := mantissa(SP_LSB - 1 downto DP_LSB);
end if;
end case;
+ dp_result(63) := sign xor negate;
return dp_result;
end;
v.fpscr(FPSCR_FR) := '0';
v.fpscr(FPSCR_FI) := '0';
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
- v.is_subtract := not is_add;
v.add_bsmall := r.exp_cmp;
v.opsel_a := AIN_B;
if r.exp_cmp = '0' then
v.fpscr(FPSCR_VXISI) := '1';
qnan_result := '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
- -- result is A
- v.opsel_a := AIN_A;
- v.state := EXC_RESULT;
+ -- result is A; we're already set up to put A into R
+ arith_done := '1';
else
-- result is +/- 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;
end if;
end if;
else
-- r.c.class is ZERO or INFINITY
v.opsel_a := AIN_C;
- v.negate := r.a.negative;
v.state := EXC_RESULT;
end if;
end if;
v.fpscr(FPSCR_FI) := '0';
if r.a.class = ZERO or (r.a.negative = '0' and r.a.class /= NAN) then
v.opsel_a := AIN_C;
+ v.result_sign := r.c.negative;
else
v.opsel_a := AIN_B;
+ v.result_sign := r.b.negative;
end if;
v.quieten_nan := '0';
v.state := EXC_RESULT;
v.fpscr(FPSCR_FR) := '0';
v.fpscr(FPSCR_FI) := '0';
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
(r.b.class = FINITE or r.b.class = ZERO) then
- v.is_subtract := not is_add;
-- Make sure A and C are normalized
if r.a.mantissa(UNIT_BIT) = '0' then
v.state := RENORM_A;
v.state := RENORM_C;
elsif r.b.class = ZERO then
-- 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';
v.is_multiply := '1';
v.state := MULT_1;
elsif r.madd_cmp = '0' then
-- 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';
v.first := '1';
v.state := FMADD_0;
else
-- result is 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';
end if;
else
-- Here A is zero, C is zero, or B is infinity
-- Result is +/-B in all of those cases
v.opsel_a := AIN_B;
- if r.b.class /= ZERO or is_add = '1' then
- 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.result_sign := r.b.negative xnor r.insn(1);
v.state := EXC_RESULT;
end if;
end if;
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
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';
else
rs_norm <= '1';
-- product is bigger here
-- shift B right and use it as the addend to the multiplier
-- 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_set_result <= '1';
-- set shift to b.exp - result_exp + 64
if s_nz = '0' then
-- must be a subtraction, and r.x must be zero
v.result_class := ZERO;
- v.result_sign := r.round_mode(1) and r.round_mode(0);
arith_done := '1';
else
-- R is all zeroes but there are non-zero bits in S
rs_neg2 <= '1';
if mant_nz = '0' then
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';
else
-- Renormalize result after rounding
arith_done := '1';
when NAN_RESULT =>
+ v.negate := '0';
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_c = '1' and r.c.class = NAN and r.c.mantissa(QNAN_BIT) = '0') then
end if;
if r.use_a = '1' and r.a.class = NAN then
v.opsel_a := AIN_A;
+ v.result_sign := r.a.negative;
elsif r.use_b = '1' and r.b.class = NAN then
v.opsel_a := AIN_B;
+ v.result_sign := r.b.negative;
elsif r.use_c = '1' and r.c.class = NAN then
v.opsel_a := AIN_C;
+ v.result_sign := r.c.negative;
end if;
v.state := EXC_RESULT;
-- r.opsel_a = AIN_A, AIN_B or AIN_C according to which input is the result
case r.opsel_a is
when AIN_B =>
- v.result_sign := r.b.negative xor r.negate;
re_sel2 <= REXP2_B;
v.result_class := r.b.class;
when AIN_C =>
- v.result_sign := r.c.negative xor r.negate;
re_sel2 <= REXP2_C;
v.result_class := r.c.class;
when others =>
- v.result_sign := r.a.negative xor r.negate;
re_sel1 <= REXP1_A;
v.result_class := r.a.class;
end case;
invalid := '1';
v.result_class := NAN;
v.result_sign := '0';
+ v.negate := '0';
misc_sel <= "0001";
opsel_r <= RES_MISC;
arith_done := '1';
v.int_result := int_result;
v.illegal := illegal;
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
v.cr_mask := num_to_fxm(0);
elsif r.is_cmp = '0' then
fp_result <= r.r;
else
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;
rin <= v;