FPU: Rework inputs to the main adder

With this, the A input no longer has R as an option but now takes the
rounding constants and the low-order bits of P (used as an adjustment
in the square root algorithm).  The B input has either R or zero.
Both inputs can be optionally inverted for subtraction.  The select
inputs to the multiplexers now have 3 bits in opsel_a and 1 bit in
opsel_b.

The states which need R to be set now explicitly have set_r := 1 even
though that is the default, essentially for documentation reasons.
Similarly some states set opsel_b <= BIN_R even though that is the
default.

Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
pull/442/head
Paul Mackerras 1 year ago
parent 0e7c11a0e4
commit bbc485f336

@ -172,7 +172,7 @@ architecture behaviour of fpu is
res_int : std_ulogic; res_int : std_ulogic;
exec_state : state_t; exec_state : state_t;
cycle_1 : std_ulogic; cycle_1 : std_ulogic;
regsel : std_ulogic_vector(1 downto 0); regsel : 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);
@ -180,8 +180,8 @@ architecture behaviour of fpu is
signal r, rin : reg_type; signal r, rin : reg_type;


signal fp_result : std_ulogic_vector(63 downto 0); signal fp_result : std_ulogic_vector(63 downto 0);
signal opsel_a : std_ulogic_vector(1 downto 0); signal opsel_a : std_ulogic_vector(2 downto 0);
signal opsel_b : std_ulogic_vector(1 downto 0); signal opsel_b : std_ulogic;
signal opsel_r : std_ulogic_vector(1 downto 0); signal opsel_r : std_ulogic_vector(1 downto 0);
signal opsel_s : std_ulogic_vector(1 downto 0); signal opsel_s : std_ulogic_vector(1 downto 0);
signal opsel_ainv : std_ulogic; signal opsel_ainv : std_ulogic;
@ -206,15 +206,17 @@ architecture behaviour of fpu is
signal inverse_est : std_ulogic_vector(18 downto 0); signal inverse_est : std_ulogic_vector(18 downto 0);


-- opsel values -- opsel values
constant AIN_R : std_ulogic_vector(1 downto 0) := "00"; constant AIN_ZERO : std_ulogic_vector(2 downto 0) := "000";
constant AIN_A : std_ulogic_vector(1 downto 0) := "01"; constant AIN_A : std_ulogic_vector(2 downto 0) := "001";
constant AIN_B : std_ulogic_vector(1 downto 0) := "10"; constant AIN_B : std_ulogic_vector(2 downto 0) := "010";
constant AIN_C : std_ulogic_vector(1 downto 0) := "11"; constant AIN_C : std_ulogic_vector(2 downto 0) := "011";

constant AIN_PS8 : std_ulogic_vector(2 downto 0) := "100";
constant BIN_ZERO : std_ulogic_vector(1 downto 0) := "00"; constant AIN_RND_B32 : std_ulogic_vector(2 downto 0) := "101";
constant BIN_R : std_ulogic_vector(1 downto 0) := "01"; constant AIN_RND_RBIT : std_ulogic_vector(2 downto 0) := "110";
constant BIN_RND : std_ulogic_vector(1 downto 0) := "10"; constant AIN_RND : std_ulogic_vector(2 downto 0) := "111";
constant BIN_PS8 : std_ulogic_vector(1 downto 0) := "11";
constant BIN_ZERO : std_ulogic := '0';
constant BIN_R : std_ulogic := '1';


constant RES_SUM : std_ulogic_vector(1 downto 0) := "00"; constant RES_SUM : std_ulogic_vector(1 downto 0) := "00";
constant RES_SHIFT : std_ulogic_vector(1 downto 0) := "01"; constant RES_SHIFT : std_ulogic_vector(1 downto 0) := "01";
@ -857,10 +859,8 @@ begin
variable maddend : std_ulogic_vector(127 downto 0); variable maddend : std_ulogic_vector(127 downto 0);
variable sum : std_ulogic_vector(63 downto 0); variable sum : std_ulogic_vector(63 downto 0);
variable round_inc : std_ulogic_vector(63 downto 0); variable round_inc : std_ulogic_vector(63 downto 0);
variable rbit_inc : std_ulogic;
variable mult_mask : std_ulogic; variable mult_mask : std_ulogic;
variable sign_bit : std_ulogic; variable sign_bit : std_ulogic;
variable rnd_b32 : std_ulogic;
variable rexp_in1 : signed(EXP_BITS-1 downto 0); variable rexp_in1 : signed(EXP_BITS-1 downto 0);
variable rexp_in2 : signed(EXP_BITS-1 downto 0); variable rexp_in2 : signed(EXP_BITS-1 downto 0);
variable rexp_cin : std_ulogic; variable rexp_cin : std_ulogic;
@ -1134,10 +1134,10 @@ begin
v.update_fprf := '0'; v.update_fprf := '0';
v.first := '0'; v.first := '0';
v.doing_ftdiv := "00"; v.doing_ftdiv := "00";
opsel_a <= AIN_R; opsel_a <= AIN_ZERO;
opsel_ainv <= '0'; opsel_ainv <= '0';
opsel_mask <= '0'; opsel_mask <= '0';
opsel_b <= BIN_ZERO; opsel_b <= BIN_R;
opsel_binv <= '0'; opsel_binv <= '0';
opsel_r <= RES_SUM; opsel_r <= RES_SUM;
opsel_s <= S_ZERO; opsel_s <= S_ZERO;
@ -1171,9 +1171,7 @@ begin
renorm_sqrt := '0'; renorm_sqrt := '0';
shiftin := '0'; shiftin := '0';
shiftin0 := '0'; shiftin0 := '0';
rbit_inc := '0';
mult_mask := '0'; mult_mask := '0';
rnd_b32 := '0';
illegal := '0'; illegal := '0';
set_reg_ind := '0'; set_reg_ind := '0';


@ -1216,7 +1214,7 @@ begin
v.x := '0'; v.x := '0';
v.old_exc := r.fpscr(FPSCR_VX downto FPSCR_XX); v.old_exc := r.fpscr(FPSCR_VX downto FPSCR_XX);
set_s := '1'; set_s := '1';
v.regsel := AIN_R; v.regsel := AIN_ZERO;


when DO_NAN_INF => when DO_NAN_INF =>
-- At least one floating-point operand is infinity or NaN -- At least one floating-point operand is infinity or NaN
@ -1227,6 +1225,8 @@ begin
else else
opsel_a <= AIN_C; opsel_a <= AIN_C;
end if; end if;
opsel_b <= BIN_ZERO;
set_r := '1';


if (r.a.class = NAN and r.a.mantissa(QNAN_BIT) = '0') or if (r.a.class = NAN and r.a.mantissa(QNAN_BIT) = '0') or
(r.b.class = NAN and r.b.mantissa(QNAN_BIT) = '0') or (r.b.class = NAN and r.b.mantissa(QNAN_BIT) = '0') or
@ -1287,6 +1287,8 @@ begin


when DO_ZERO_DEN => when DO_ZERO_DEN =>
-- At least one floating point operand is zero or denormalized -- At least one floating point operand is zero or denormalized
opsel_b <= BIN_ZERO;
set_r := '1';
if r.use_a = '1' and r.a.class = ZERO then if r.use_a = '1' and r.a.class = ZERO then
opsel_a <= AIN_B; opsel_a <= AIN_B;
re_sel2 <= REXP2_B; re_sel2 <= REXP2_B;
@ -1406,6 +1408,8 @@ begin
when DO_FCMP => when DO_FCMP =>
-- fcmp[uo] -- fcmp[uo]
opsel_a <= AIN_B; opsel_a <= AIN_B;
opsel_b <= BIN_ZERO;
set_r := '1';
v.instr_done := '1'; v.instr_done := '1';
update_fx := '1'; update_fx := '1';
re_sel2 <= REXP2_B; re_sel2 <= REXP2_B;
@ -1483,6 +1487,7 @@ begin


when DO_FMRG => when DO_FMRG =>
-- fmrgew, fmrgow -- fmrgew, fmrgow
set_r := '1';
opsel_r <= RES_MISC; opsel_r <= RES_MISC;
misc_sel <= "100"; misc_sel <= "100";
v.writing_fpr := '1'; v.writing_fpr := '1';
@ -1490,6 +1495,7 @@ begin


when DO_MFFS => when DO_MFFS =>
v.writing_fpr := '1'; v.writing_fpr := '1';
set_r := '1';
opsel_r <= RES_MISC; opsel_r <= RES_MISC;
misc_sel <= "011"; misc_sel <= "011";
case r.insn(20 downto 16) is case r.insn(20 downto 16) is
@ -1537,6 +1543,8 @@ begin


when DO_FMR => when DO_FMR =>
opsel_a <= AIN_B; opsel_a <= AIN_B;
opsel_b <= BIN_ZERO;
set_r := '1';
rcls_op <= RCLS_SEL; rcls_op <= RCLS_SEL;
re_sel2 <= REXP2_B; re_sel2 <= REXP2_B;
re_set_result <= '1'; re_set_result <= '1';
@ -1545,6 +1553,8 @@ begin


when DO_FRI => -- fri[nzpm] when DO_FRI => -- fri[nzpm]
opsel_a <= AIN_B; opsel_a <= AIN_B;
opsel_b <= BIN_ZERO;
set_r := '1';
re_sel2 <= REXP2_B; re_sel2 <= REXP2_B;
re_set_result <= '1'; re_set_result <= '1';
-- set shift to exponent - 52 -- set shift to exponent - 52
@ -1561,17 +1571,19 @@ begin
when DO_FRSP => when DO_FRSP =>
-- r.shift = 0 -- r.shift = 0
opsel_a <= AIN_B; opsel_a <= AIN_B;
opsel_b <= BIN_ZERO;
set_r := '1';
re_sel2 <= REXP2_B; re_sel2 <= REXP2_B;
re_set_result <= '1'; re_set_result <= '1';
v.state := DO_FRSP_2; v.state := DO_FRSP_2;


when DO_FRSP_2 => when DO_FRSP_2 =>
-- r.shift = 0 -- r.shift = 0
-- set shift to exponent - -126 -- set shift to exponent - -126 (for ROUND_UFLOW state)
rs_sel1 <= RSH1_B; rs_sel1 <= RSH1_B;
rs_con2 <= RSCON2_MINEXP; rs_con2 <= RSCON2_MINEXP;
rs_neg2 <= '1'; rs_neg2 <= '1';
set_x := '1'; set_x := '1'; -- uses r.r and r.shift
if r.b.exponent < to_signed(-126, EXP_BITS) then if r.b.exponent < to_signed(-126, EXP_BITS) then
v.state := ROUND_UFLOW; v.state := ROUND_UFLOW;
elsif r.b.exponent > to_signed(127, EXP_BITS) then elsif r.b.exponent > to_signed(127, EXP_BITS) then
@ -1585,6 +1597,8 @@ begin
-- instr bit 8: 1=unsigned 0=signed -- instr bit 8: 1=unsigned 0=signed
-- instr bit 1: 1=round to zero 0=use fpscr[RN] -- instr bit 1: 1=round to zero 0=use fpscr[RN]
opsel_a <= AIN_B; opsel_a <= AIN_B;
opsel_b <= BIN_ZERO;
set_r := '1';
re_sel2 <= REXP2_B; re_sel2 <= REXP2_B;
re_set_result <= '1'; re_set_result <= '1';
rs_sel1 <= RSH1_B; rs_sel1 <= RSH1_B;
@ -1611,6 +1625,8 @@ begin


when DO_FCFID => when DO_FCFID =>
opsel_a <= AIN_B; opsel_a <= AIN_B;
opsel_b <= BIN_ZERO;
set_r := '1';
rcls_op <= RCLS_SEL; rcls_op <= RCLS_SEL;
if r.insn(8) = '0' and r.b.negative = '1' then if r.insn(8) = '0' and r.b.negative = '1' then
-- fcfid[s] with negative operand, set R = -B -- fcfid[s] with negative operand, set R = -B
@ -1628,6 +1644,8 @@ begin
when DO_FADD => when DO_FADD =>
-- fadd[s] and fsub[s] -- fadd[s] and fsub[s]
opsel_a <= AIN_A; opsel_a <= AIN_A;
opsel_b <= BIN_ZERO;
set_r := '1';
re_sel1 <= REXP1_A; re_sel1 <= REXP1_A;
re_set_result <= '1'; re_set_result <= '1';
-- set shift to a.exp - b.exp -- set shift to a.exp - b.exp
@ -1648,6 +1666,8 @@ begin
when DO_FMUL => when DO_FMUL =>
-- fmul[s] -- fmul[s]
opsel_a <= AIN_A; opsel_a <= AIN_A;
opsel_b <= BIN_ZERO;
set_r := '1';
re_sel1 <= REXP1_A; re_sel1 <= REXP1_A;
re_sel2 <= REXP2_C; re_sel2 <= REXP2_C;
re_set_result <= '1'; re_set_result <= '1';
@ -1656,6 +1676,8 @@ begin


when DO_FDIV => when DO_FDIV =>
opsel_a <= AIN_A; opsel_a <= AIN_A;
opsel_b <= BIN_ZERO;
set_r := '1';
re_sel1 <= REXP1_A; re_sel1 <= REXP1_A;
re_sel2 <= REXP2_B; re_sel2 <= REXP2_B;
re_neg2 <= '1'; re_neg2 <= '1';
@ -1674,11 +1696,15 @@ begin
opsel_a <= AIN_B; opsel_a <= AIN_B;
re_sel2 <= REXP2_B; re_sel2 <= REXP2_B;
end if; end if;
opsel_b <= BIN_ZERO;
set_r := '1';
re_set_result <= '1'; re_set_result <= '1';
arith_done := '1'; arith_done := '1';


when DO_FSQRT => when DO_FSQRT =>
opsel_a <= AIN_B; opsel_a <= AIN_B;
opsel_b <= BIN_ZERO;
set_r := '1';
re_sel2 <= REXP2_B; re_sel2 <= REXP2_B;
re_set_result <= '1'; re_set_result <= '1';
if r.b.negative = '1' then if r.b.negative = '1' then
@ -1694,7 +1720,6 @@ begin
end if; end if;


when DO_FRE => when DO_FRE =>
opsel_a <= AIN_B;
re_sel2 <= REXP2_B; re_sel2 <= REXP2_B;
re_set_result <= '1'; re_set_result <= '1';
v.state := FRE_1; v.state := FRE_1;
@ -1702,6 +1727,8 @@ begin
when DO_FMADD => when DO_FMADD =>
-- fmadd, fmsub, fnmadd, fnmsub -- fmadd, fmsub, fnmadd, fnmsub
opsel_a <= AIN_B; opsel_a <= AIN_B;
opsel_b <= BIN_ZERO;
set_r := '1';
-- put a.exp + c.exp into result_exp -- put a.exp + c.exp into result_exp
re_sel1 <= REXP1_A; re_sel1 <= REXP1_A;
re_sel2 <= REXP2_C; re_sel2 <= REXP2_C;
@ -1722,6 +1749,8 @@ begin
when RENORM_A => when RENORM_A =>
-- Get A into R -- Get A into R
opsel_a <= AIN_A; opsel_a <= AIN_A;
opsel_b <= BIN_ZERO;
set_r := '1';
v.regsel := AIN_A; v.regsel := AIN_A;
re_sel1 <= REXP1_A; re_sel1 <= REXP1_A;
re_set_result <= '1'; re_set_result <= '1';
@ -1731,6 +1760,8 @@ begin
when RENORM_B => when RENORM_B =>
-- Get B into R -- Get B into R
opsel_a <= AIN_B; opsel_a <= AIN_B;
opsel_b <= BIN_ZERO;
set_r := '1';
v.regsel := AIN_B; v.regsel := AIN_B;
re_sel2 <= REXP2_B; re_sel2 <= REXP2_B;
re_set_result <= '1'; re_set_result <= '1';
@ -1740,6 +1771,8 @@ begin
when RENORM_C => when RENORM_C =>
-- Get C into R -- Get C into R
opsel_a <= AIN_C; opsel_a <= AIN_C;
opsel_b <= BIN_ZERO;
set_r := '1';
v.regsel := AIN_C; v.regsel := AIN_C;
re_sel2 <= REXP2_C; re_sel2 <= REXP2_C;
re_set_result <= '1'; re_set_result <= '1';
@ -1767,6 +1800,8 @@ begin
when ADD_1 => when ADD_1 =>
-- transferring B to R -- transferring B to R
opsel_a <= AIN_B; opsel_a <= AIN_B;
opsel_b <= BIN_ZERO;
set_r := '1';
re_sel2 <= REXP2_B; re_sel2 <= REXP2_B;
re_set_result <= '1'; re_set_result <= '1';
-- set shift to b.exp - a.exp -- set shift to b.exp - a.exp
@ -1779,6 +1814,7 @@ begin
when ADD_SHIFT => when ADD_SHIFT =>
-- r.shift = - exponent difference, r.longmask = 0 -- r.shift = - exponent difference, r.longmask = 0
opsel_r <= RES_SHIFT; opsel_r <= RES_SHIFT;
set_r := '1';
re_sel2 <= REXP2_NE; re_sel2 <= REXP2_NE;
re_set_result <= '1'; re_set_result <= '1';
v.x := s_nz; v.x := s_nz;
@ -1795,6 +1831,7 @@ begin
opsel_b <= BIN_R; opsel_b <= BIN_R;
opsel_binv <= r.is_subtract; opsel_binv <= r.is_subtract;
carry_in <= r.is_subtract and not r.x; carry_in <= r.is_subtract and not r.x;
set_r := '1';
-- set shift to -1 -- set shift to -1
rs_con2 <= RSCON2_1; rs_con2 <= RSCON2_1;
rs_neg2 <= '1'; rs_neg2 <= '1';
@ -1808,12 +1845,15 @@ begin
if r.r(63) = '1' then if r.r(63) = '1' then
-- result is opposite sign to expected -- result is opposite sign to expected
rsgn_op := RSGN_INV; rsgn_op := RSGN_INV;
opsel_ainv <= '1'; opsel_a <= AIN_ZERO;
set_r := '1';
opsel_binv <= '1';
carry_in <= '1'; carry_in <= '1';
v.state := FINISH; v.state := FINISH;
elsif r.r(UNIT_BIT + 1) = '1' then elsif r.r(UNIT_BIT + 1) = '1' then
-- sum overflowed, shift right -- sum overflowed, shift right
opsel_r <= RES_SHIFT; opsel_r <= RES_SHIFT;
set_r := '1';
re_set_result <= '1'; re_set_result <= '1';
set_x := '1'; set_x := '1';
if exp_huge = '1' then if exp_huge = '1' then
@ -1834,6 +1874,7 @@ begin
opsel_b <= BIN_R; opsel_b <= BIN_R;
opsel_binv <= '1'; opsel_binv <= '1';
carry_in <= '1'; carry_in <= '1';
set_r := '1';
v.state := CMP_2; v.state := CMP_2;


when CMP_2 => when CMP_2 =>
@ -1851,6 +1892,7 @@ begin
when MULT_1 => when MULT_1 =>
f_to_multiply.valid <= r.first; f_to_multiply.valid <= r.first;
opsel_r <= RES_MULT; opsel_r <= RES_MULT;
set_r := '1';
if multiply_to_f.valid = '1' then if multiply_to_f.valid = '1' then
v.state := FINISH; v.state := FINISH;
end if; end if;
@ -1867,6 +1909,7 @@ begin
rs_sel1 <= RSH1_S; rs_sel1 <= RSH1_S;
end if; end if;
opsel_r <= RES_MULT; opsel_r <= RES_MULT;
set_r := '1';
opsel_s <= S_MULT; opsel_s <= S_MULT;
set_s := '1'; set_s := '1';
if multiply_to_f.valid = '1' then if multiply_to_f.valid = '1' then
@ -1901,6 +1944,7 @@ begin
when FMADD_3 => when FMADD_3 =>
-- r.shift = addend exp - product exp -- r.shift = addend exp - product exp
opsel_r <= RES_SHIFT; opsel_r <= RES_SHIFT;
set_r := '1';
re_sel2 <= REXP2_NE; re_sel2 <= REXP2_NE;
re_set_result <= '1'; re_set_result <= '1';
v.first := '1'; v.first := '1';
@ -1914,6 +1958,7 @@ begin
opsel_s <= S_MULT; opsel_s <= S_MULT;
set_s := '1'; set_s := '1';
if multiply_to_f.valid = '1' then if multiply_to_f.valid = '1' then
set_r := '1';
v.state := FMADD_5; v.state := FMADD_5;
end if; end if;


@ -1921,8 +1966,9 @@ begin
-- negate R:S:X if negative -- negate R:S:X if negative
if r.r(63) = '1' then if r.r(63) = '1' then
rsgn_op := RSGN_INV; rsgn_op := RSGN_INV;
opsel_ainv <= '1'; opsel_binv <= '1';
carry_in <= not (s_nz or r.x); carry_in <= not (s_nz or r.x);
set_r := '1';
opsel_s <= S_NEG; opsel_s <= S_NEG;
set_s := '1'; set_s := '1';
end if; end if;
@ -1993,8 +2039,9 @@ begin
f_to_multiply.valid <= r.first; f_to_multiply.valid <= r.first;
pshift := '1'; pshift := '1';
mult_mask := '1'; mult_mask := '1';
opsel_r <= RES_MULT;
if multiply_to_f.valid = '1' then if multiply_to_f.valid = '1' then
opsel_r <= RES_MULT; set_r := '1';
v.first := '1'; v.first := '1';
v.state := DIV_5; v.state := DIV_5;
end if; end if;
@ -2012,14 +2059,14 @@ begin


when DIV_6 => when DIV_6 =>
-- test if remainder is 0 or >= B -- test if remainder is 0 or >= B
opsel_b <= BIN_RND; opsel_a <= AIN_RND_RBIT;
rbit_inc := '1';
if pcmpb_lt = '1' then if pcmpb_lt = '1' then
-- quotient is correct, set X if remainder non-zero -- quotient is correct, set X if remainder non-zero
set_r := '0'; set_r := '0';
v.x := r.p(UNIT_BIT + 2) or px_nz; v.x := r.p(UNIT_BIT + 2) or px_nz;
else else
-- quotient needs to be incremented by 1 in R-bit position -- quotient needs to be incremented by 1 in R-bit position
set_r := '1';
v.x := not pcmpb_eq; v.x := not pcmpb_eq;
end if; end if;
v.state := FINISH; v.state := FINISH;
@ -2029,6 +2076,7 @@ begin
re_neg1 <= '1'; re_neg1 <= '1';
re_set_result <= '1'; re_set_result <= '1';
opsel_r <= RES_MISC; opsel_r <= RES_MISC;
set_r := '1';
misc_sel <= "101"; misc_sel <= "101";
-- set shift to 1 -- set shift to 1
rs_con2 <= RSCON2_1; rs_con2 <= RSCON2_1;
@ -2056,6 +2104,7 @@ begin
when RSQRT_1 => when RSQRT_1 =>
opsel_r <= RES_MISC; opsel_r <= RES_MISC;
misc_sel <= "101"; misc_sel <= "101";
set_r := '1';
re_sel1 <= REXP1_BHALF; re_sel1 <= REXP1_BHALF;
re_neg1 <= '1'; re_neg1 <= '1';
re_set_result <= '1'; re_set_result <= '1';
@ -2069,6 +2118,7 @@ begin
set_a := '1'; set_a := '1';
opsel_r <= RES_MISC; opsel_r <= RES_MISC;
misc_sel <= "101"; misc_sel <= "101";
set_r := '1';
msel_1 <= MUL1_B; msel_1 <= MUL1_B;
msel_2 <= MUL2_LUT; msel_2 <= MUL2_LUT;
f_to_multiply.valid <= '1'; f_to_multiply.valid <= '1';
@ -2083,6 +2133,7 @@ begin
-- not expecting multiplier result yet -- not expecting multiplier result yet
-- r.shift = -1 -- r.shift = -1
opsel_r <= RES_SHIFT; opsel_r <= RES_SHIFT;
set_r := '1';
re_sel2 <= REXP2_NE; re_sel2 <= REXP2_NE;
re_set_result <= '1'; re_set_result <= '1';
v.first := '1'; v.first := '1';
@ -2094,9 +2145,10 @@ begin
set_y := r.first; set_y := r.first;
pshift := '1'; pshift := '1';
mult_mask := '1'; mult_mask := '1';
opsel_r <= RES_MULT;
if multiply_to_f.valid = '1' then if multiply_to_f.valid = '1' then
-- put result into R -- put result into R
opsel_r <= RES_MULT; set_r := '1';
v.first := '1'; v.first := '1';
v.state := SQRT_4; v.state := SQRT_4;
end if; end if;
@ -2139,9 +2191,11 @@ begin
-- wait for second multiply (should be here already) -- wait for second multiply (should be here already)
pshift := '1'; pshift := '1';
mult_mask := '1'; mult_mask := '1';
opsel_r <= RES_MULT;
set_r := '1';
if multiply_to_f.valid = '1' then if multiply_to_f.valid = '1' then
-- put result into R -- put result into R
opsel_r <= RES_MULT; set_r := '1';
v.first := '1'; v.first := '1';
v.count := r.count + 1; v.count := r.count + 1;
if r.count < 2 then if r.count < 2 then
@ -2184,7 +2238,8 @@ begin


when SQRT_10 => when SQRT_10 =>
-- Add the bottom 8 bits of P, sign-extended, onto R. -- Add the bottom 8 bits of P, sign-extended, onto R.
opsel_b <= BIN_PS8; opsel_a <= AIN_PS8;
set_r := '1';
re_sel1 <= REXP1_BHALF; re_sel1 <= REXP1_BHALF;
re_set_result <= '1'; re_set_result <= '1';
-- set shift to 1 -- set shift to 1
@ -2208,12 +2263,14 @@ begin


when SQRT_12 => when SQRT_12 =>
-- test if remainder is 0 or >= B = 2*R + 1 -- test if remainder is 0 or >= B = 2*R + 1
set_r := '0';
carry_in <= '1';
if pcmpb_lt = '1' then if pcmpb_lt = '1' then
-- square root is correct, set X if remainder non-zero -- square root is correct, set X if remainder non-zero
v.x := r.p(UNIT_BIT + 2) or px_nz; v.x := r.p(UNIT_BIT + 2) or px_nz;
else else
-- square root needs to be incremented by 1 -- square root needs to be incremented by 1
carry_in <= '1'; set_r := '1';
v.x := not pcmpb_eq; v.x := not pcmpb_eq;
end if; end if;
v.state := FINISH; v.state := FINISH;
@ -2221,6 +2278,7 @@ begin
when INT_SHIFT => when INT_SHIFT =>
-- r.shift = b.exponent - 52 -- r.shift = b.exponent - 52
opsel_r <= RES_SHIFT; opsel_r <= RES_SHIFT;
set_r := '1';
re_sel2 <= REXP2_NE; re_sel2 <= REXP2_NE;
re_set_result <= '1'; re_set_result <= '1';
set_x := '1'; set_x := '1';
@ -2232,6 +2290,7 @@ begin
when INT_ROUND => when INT_ROUND =>
-- r.shift = -4 (== 52 - UNIT_BIT) -- r.shift = -4 (== 52 - UNIT_BIT)
opsel_r <= RES_SHIFT; opsel_r <= RES_SHIFT;
set_r := '1';
re_sel2 <= REXP2_NE; re_sel2 <= REXP2_NE;
re_set_result <= '1'; re_set_result <= '1';
round := fp_rounding(r.r, r.x, '0', r.round_mode, r.result_sign); round := fp_rounding(r.r, r.x, '0', r.round_mode, r.result_sign);
@ -2247,14 +2306,16 @@ begin
when INT_ISHIFT => when INT_ISHIFT =>
-- r.shift = b.exponent - UNIT_BIT; -- r.shift = b.exponent - UNIT_BIT;
opsel_r <= RES_SHIFT; opsel_r <= RES_SHIFT;
set_r := '1';
re_sel2 <= REXP2_NE; re_sel2 <= REXP2_NE;
re_set_result <= '1'; re_set_result <= '1';
v.state := INT_FINAL; v.state := INT_FINAL;


when INT_FINAL => when INT_FINAL =>
-- Negate if necessary, and increment for rounding if needed -- Negate if necessary, and increment for rounding if needed
opsel_ainv <= r.result_sign; opsel_binv <= r.result_sign;
carry_in <= r.fpscr(FPSCR_FR) xor r.result_sign; carry_in <= r.fpscr(FPSCR_FR) xor r.result_sign;
set_r := '1';
-- Check for possible overflows -- Check for possible overflows
case r.insn(9 downto 8) is case r.insn(9 downto 8) is
when "00" => -- fctiw[z] when "00" => -- fctiw[z]
@ -2281,13 +2342,15 @@ begin
else else
msb := r.r(63); msb := r.r(63);
end if; end if;
opsel_r <= RES_MISC;
misc_sel <= "110"; misc_sel <= "110";
if (r.insn(8) = '0' and msb /= r.result_sign) or if (r.insn(8) = '0' and msb /= r.result_sign) or
(r.insn(8) = '1' and msb /= '1') then (r.insn(8) = '1' and msb /= '1') then
opsel_r <= RES_MISC; set_r := '1';
v.fpscr(FPSCR_VXCVI) := '1'; v.fpscr(FPSCR_VXCVI) := '1';
invalid := '1'; invalid := '1';
else else
set_r := '0';
if r.fpscr(FPSCR_FI) = '1' then if r.fpscr(FPSCR_FI) = '1' then
v.fpscr(FPSCR_XX) := '1'; v.fpscr(FPSCR_XX) := '1';
end if; end if;
@ -2297,6 +2360,7 @@ begin
when INT_OFLOW => when INT_OFLOW =>
opsel_r <= RES_MISC; opsel_r <= RES_MISC;
misc_sel <= "110"; misc_sel <= "110";
set_r := '1';
v.fpscr(FPSCR_VXCVI) := '1'; v.fpscr(FPSCR_VXCVI) := '1';
invalid := '1'; invalid := '1';
arith_done := '1'; arith_done := '1';
@ -2304,6 +2368,7 @@ begin
when FRI_1 => when FRI_1 =>
-- r.shift = b.exponent - 52 -- r.shift = b.exponent - 52
opsel_r <= RES_SHIFT; opsel_r <= RES_SHIFT;
set_r := '1';
re_sel2 <= REXP2_NE; re_sel2 <= REXP2_NE;
re_set_result <= '1'; re_set_result <= '1';
set_x := '1'; set_x := '1';
@ -2335,6 +2400,7 @@ begin
-- Shift so we have 9 leading zeroes (we know R is non-zero) -- Shift so we have 9 leading zeroes (we know R is non-zero)
-- r.shift = clz(r.r) - 7 -- r.shift = clz(r.r) - 7
opsel_r <= RES_SHIFT; opsel_r <= RES_SHIFT;
set_r := '1';
re_sel2 <= REXP2_NE; re_sel2 <= REXP2_NE;
re_set_result <= '1'; re_set_result <= '1';
-- set shift to new_exp - min_exp -- set shift to new_exp - min_exp
@ -2353,10 +2419,12 @@ begin
when ROUND_UFLOW => when ROUND_UFLOW =>
-- r.shift = - amount by which exponent underflows -- r.shift = - amount by which exponent underflows
v.tiny := '1'; v.tiny := '1';
opsel_r <= RES_SHIFT;
set_r := '0';
if r.fpscr(FPSCR_UE) = '0' then if r.fpscr(FPSCR_UE) = '0' then
-- disabled underflow exception case -- disabled underflow exception case
-- have to denormalize before rounding -- have to denormalize before rounding
opsel_r <= RES_SHIFT; set_r := '1';
re_sel2 <= REXP2_NE; re_sel2 <= REXP2_NE;
re_set_result <= '1'; re_set_result <= '1';
set_x := '1'; set_x := '1';
@ -2379,16 +2447,18 @@ begin
when ROUND_OFLOW => when ROUND_OFLOW =>
rcls_op <= RCLS_TINF; rcls_op <= RCLS_TINF;
v.fpscr(FPSCR_OX) := '1'; v.fpscr(FPSCR_OX) := '1';
opsel_r <= RES_MISC;
misc_sel <= "010";
set_r := '0';
if r.fpscr(FPSCR_OE) = '0' then if r.fpscr(FPSCR_OE) = '0' then
-- disabled overflow exception -- disabled overflow exception
-- result depends on rounding mode -- result depends on rounding mode
set_r := '1';
v.fpscr(FPSCR_XX) := '1'; v.fpscr(FPSCR_XX) := '1';
v.fpscr(FPSCR_FI) := '1'; v.fpscr(FPSCR_FI) := '1';
-- construct largest representable number -- construct largest representable number
re_con2 <= RECON2_MAX; re_con2 <= RECON2_MAX;
re_set_result <= '1'; re_set_result <= '1';
opsel_r <= RES_MISC;
misc_sel <= "010";
arith_done := '1'; arith_done := '1';
else else
-- enabled overflow exception -- enabled overflow exception
@ -2401,11 +2471,12 @@ begin


when ROUNDING => when ROUNDING =>
opsel_mask <= '1'; opsel_mask <= '1';
set_r := '1';
round := fp_rounding(r.r, r.x, r.single_prec, r.round_mode, r.result_sign); round := fp_rounding(r.r, r.x, r.single_prec, r.round_mode, r.result_sign);
v.fpscr(FPSCR_FR downto FPSCR_FI) := round; v.fpscr(FPSCR_FR downto FPSCR_FI) := round;
if round(1) = '1' then if round(1) = '1' then
-- increment the LSB for the precision -- increment the LSB for the precision
opsel_b <= BIN_RND; opsel_a <= AIN_RND;
-- set shift to -1 -- set shift to -1
rs_con2 <= RSCON2_1; rs_con2 <= RSCON2_1;
rs_neg2 <= '1'; rs_neg2 <= '1';
@ -2432,8 +2503,10 @@ begin
-- r.shift = -1 -- r.shift = -1
v.x := '0'; v.x := '0';
re_sel2 <= REXP2_NE; re_sel2 <= REXP2_NE;
opsel_r <= RES_SHIFT;
set_r := '0';
if r.r(UNIT_BIT + 1) = '1' then if r.r(UNIT_BIT + 1) = '1' then
opsel_r <= RES_SHIFT; set_r := '1';
re_set_result <= '1'; re_set_result <= '1';
if exp_huge = '1' then if exp_huge = '1' then
v.state := ROUND_OFLOW; v.state := ROUND_OFLOW;
@ -2451,6 +2524,7 @@ begin
when ROUNDING_3 => when ROUNDING_3 =>
-- r.shift = clz(r.r) - 9 -- r.shift = clz(r.r) - 9
opsel_r <= RES_SHIFT; opsel_r <= RES_SHIFT;
set_r := '1';
re_sel2 <= REXP2_NE; re_sel2 <= REXP2_NE;
-- set shift to new_exp - min_exp (== -1022) -- set shift to new_exp - min_exp (== -1022)
rs_sel1 <= RSH1_NE; rs_sel1 <= RSH1_NE;
@ -2470,12 +2544,23 @@ begin
when DENORM => when DENORM =>
-- r.shift = result_exp - -1022 -- r.shift = result_exp - -1022
opsel_r <= RES_SHIFT; opsel_r <= RES_SHIFT;
set_r := '1';
re_sel2 <= REXP2_NE; re_sel2 <= REXP2_NE;
re_set_result <= '1'; re_set_result <= '1';
arith_done := '1'; arith_done := '1';


when DO_IDIVMOD => when DO_IDIVMOD =>
opsel_a <= AIN_B; opsel_a <= AIN_B;
opsel_b <= BIN_ZERO;
set_r := '1';
-- take absolute value for signed division
if r.is_signed = '1' and r.b.negative = '1' then
opsel_ainv <= '1';
carry_in <= '1';
end if;
-- normalize and round up B to 8.56 format, like fcfid[u]
re_con2 <= RECON2_UNIT;
re_set_result <= '1';
if r.b.class = ZERO then if r.b.class = ZERO then
-- B is zero, signal overflow -- B is zero, signal overflow
v.int_ovf := '1'; v.int_ovf := '1';
@ -2484,14 +2569,6 @@ begin
-- A is zero, result is zero (both for div and for mod) -- A is zero, result is zero (both for div and for mod)
v.state := IDIV_ZERO; v.state := IDIV_ZERO;
else else
-- take absolute value for signed division, and
-- normalize and round up B to 8.56 format, like fcfid[u]
if r.is_signed = '1' and r.b.negative = '1' then
opsel_ainv <= '1';
carry_in <= '1';
end if;
re_con2 <= RECON2_UNIT;
re_set_result <= '1';
v.state := IDIV_NORMB; v.state := IDIV_NORMB;
end if; end if;
when IDIV_NORMB => when IDIV_NORMB =>
@ -2504,17 +2581,21 @@ begin
-- get B into the range [1, 2) in 8.56 format -- get B into the range [1, 2) in 8.56 format
set_x := '1'; -- record if any 1 bits shifted out set_x := '1'; -- record if any 1 bits shifted out
opsel_r <= RES_SHIFT; opsel_r <= RES_SHIFT;
set_r := '1';
re_sel2 <= REXP2_NE; re_sel2 <= REXP2_NE;
re_set_result <= '1'; re_set_result <= '1';
v.state := IDIV_NORMB3; v.state := IDIV_NORMB3;
when IDIV_NORMB3 => when IDIV_NORMB3 =>
-- add the X bit onto R to round up B -- add the X bit onto R to round up B
carry_in <= r.x; carry_in <= r.x;
set_r := '1';
-- prepare to do count-leading-zeroes on A -- prepare to do count-leading-zeroes on A
v.state := IDIV_CLZA; v.state := IDIV_CLZA;
when IDIV_CLZA => when IDIV_CLZA =>
set_b := '1'; -- put R back into B set_b := '1'; -- put R back into B
opsel_a <= AIN_A; opsel_a <= AIN_A;
opsel_b <= BIN_ZERO;
set_r := '1';
if r.is_signed = '1' and r.a.negative = '1' then if r.is_signed = '1' and r.a.negative = '1' then
opsel_ainv <= '1'; opsel_ainv <= '1';
carry_in <= '1'; carry_in <= '1';
@ -2523,16 +2604,17 @@ begin
re_set_result <= '1'; re_set_result <= '1';
v.state := IDIV_CLZA2; v.state := IDIV_CLZA2;
when IDIV_CLZA2 => when IDIV_CLZA2 =>
opsel_a <= AIN_C;
rs_norm <= '1'; rs_norm <= '1';
-- write the dividend back into A in case we negated it -- write the dividend back into A in case we negated it
set_a_mant := '1'; set_a_mant := '1';
-- while doing the count-leading-zeroes on A, -- while doing the count-leading-zeroes on A,
-- also compute A - B to tell us whether A >= B -- also compute A - B to tell us whether A >= B
-- (using the original value of B, which is now in C) -- (using the original value of B, which is now in C)
opsel_a <= AIN_C;
opsel_b <= BIN_R; opsel_b <= BIN_R;
opsel_ainv <= '1'; opsel_ainv <= '1';
carry_in <= '1'; carry_in <= '1';
set_r := '1';
v.state := IDIV_CLZA3; v.state := IDIV_CLZA3;
when IDIV_CLZA3 => when IDIV_CLZA3 =>
-- save the exponent of A (but don't overwrite the mantissa) -- save the exponent of A (but don't overwrite the mantissa)
@ -2578,6 +2660,7 @@ begin
-- It turns out the generated QNaN mantissa is actually what we want -- It turns out the generated QNaN mantissa is actually what we want
opsel_r <= RES_MISC; opsel_r <= RES_MISC;
misc_sel <= "001"; misc_sel <= "001";
set_r := '1';
if r.b.mantissa(UNIT_BIT + 1) = '1' then if r.b.mantissa(UNIT_BIT + 1) = '1' then
-- rounding up of the mantissa caused overflow, meaning the -- rounding up of the mantissa caused overflow, meaning the
-- normalized B is 2.0. Since this is outside the range -- normalized B is 2.0. Since this is outside the range
@ -2641,6 +2724,8 @@ begin
-- inverse estimate is in Y -- inverse estimate is in Y
-- put A (dividend) into R -- put A (dividend) into R
opsel_a <= AIN_A; opsel_a <= AIN_A;
opsel_b <= BIN_ZERO;
set_r := '1';
-- shift_res is 0 because r.shift = 64; -- shift_res is 0 because r.shift = 64;
-- put that into B, which now holds the quotient -- put that into B, which now holds the quotient
set_b_mant := '1'; set_b_mant := '1';
@ -2667,6 +2752,7 @@ begin
when IDIV_SH32 => when IDIV_SH32 =>
-- r.shift = 32, R contains the dividend -- r.shift = 32, R contains the dividend
opsel_r <= RES_SHIFT; opsel_r <= RES_SHIFT;
set_r := '1';
-- set shift to -UNIT_BIT (== -56) -- set shift to -UNIT_BIT (== -56)
rs_con2 <= RSCON2_UNIT; rs_con2 <= RSCON2_UNIT;
rs_neg2 <= '1'; rs_neg2 <= '1';
@ -2687,12 +2773,14 @@ begin
rs_sel1 <= RSH1_B; rs_sel1 <= RSH1_B;
rs_neg1 <= '1'; rs_neg1 <= '1';
if multiply_to_f.valid = '1' then if multiply_to_f.valid = '1' then
set_r := '1';
v.state := IDIV_DIV2; v.state := IDIV_DIV2;
end if; end if;
when IDIV_DIV2 => when IDIV_DIV2 =>
-- r.shift = - b.exponent -- r.shift = - b.exponent
-- shift the quotient estimate right by b.exponent bits -- shift the quotient estimate right by b.exponent bits
opsel_r <= RES_SHIFT; opsel_r <= RES_SHIFT;
set_r := '1';
v.first := '1'; v.first := '1';
v.state := IDIV_DIV3; v.state := IDIV_DIV3;
when IDIV_DIV3 => when IDIV_DIV3 =>
@ -2708,6 +2796,7 @@ begin
opsel_s <= S_MULT; opsel_s <= S_MULT;
set_s := '1'; set_s := '1';
if multiply_to_f.valid = '1' then if multiply_to_f.valid = '1' then
set_r := '1';
v.state := IDIV_DIV4; v.state := IDIV_DIV4;
end if; end if;
when IDIV_DIV4 => when IDIV_DIV4 =>
@ -2718,6 +2807,8 @@ begin
if r.divmod = '0' then if r.divmod = '0' then
-- get B into R for IDIV_DIVADJ state -- get B into R for IDIV_DIVADJ state
opsel_a <= AIN_B; opsel_a <= AIN_B;
opsel_b <= BIN_ZERO;
set_r := '1';
end if; end if;
-- set shift to UNIT_BIT (== 56) -- set shift to UNIT_BIT (== 56)
rs_con2 <= RSCON2_UNIT; rs_con2 <= RSCON2_UNIT;
@ -2741,18 +2832,21 @@ begin
rs_sel1 <= RSH1_B; rs_sel1 <= RSH1_B;
rs_neg1 <= '1'; rs_neg1 <= '1';
if multiply_to_f.valid = '1' then if multiply_to_f.valid = '1' then
set_r := '1';
v.state := IDIV_DIV6; v.state := IDIV_DIV6;
end if; end if;
when IDIV_DIV6 => when IDIV_DIV6 =>
-- r.shift = - b.exponent -- r.shift = - b.exponent
-- shift the quotient estimate right by b.exponent bits -- shift the quotient estimate right by b.exponent bits
opsel_r <= RES_SHIFT; opsel_r <= RES_SHIFT;
set_r := '1';
v.first := '1'; v.first := '1';
v.state := IDIV_DIV7; v.state := IDIV_DIV7;
when IDIV_DIV7 => when IDIV_DIV7 =>
-- add shifted quotient delta onto the total quotient -- add shifted quotient delta onto the total quotient
opsel_a <= AIN_B; opsel_a <= AIN_B;
opsel_b <= BIN_R; opsel_b <= BIN_R;
set_r := '1';
v.first := '1'; v.first := '1';
v.state := IDIV_DIV8; v.state := IDIV_DIV8;
when IDIV_DIV8 => when IDIV_DIV8 =>
@ -2768,6 +2862,7 @@ begin
opsel_s <= S_MULT; opsel_s <= S_MULT;
set_s := '1'; set_s := '1';
if multiply_to_f.valid = '1' then if multiply_to_f.valid = '1' then
set_r := '1';
v.state := IDIV_DIV9; v.state := IDIV_DIV9;
end if; end if;
when IDIV_DIV9 => when IDIV_DIV9 =>
@ -2780,6 +2875,8 @@ begin
if r.divmod = '0' then if r.divmod = '0' then
-- get B into R for IDIV_DIVADJ state -- get B into R for IDIV_DIVADJ state
opsel_a <= AIN_B; opsel_a <= AIN_B;
opsel_b <= BIN_ZERO;
set_r := '1';
v.state := IDIV_DIVADJ; v.state := IDIV_DIVADJ;
elsif pcmpc_eq = '1' then elsif pcmpc_eq = '1' then
v.state := IDIV_ZERO; v.state := IDIV_ZERO;
@ -2790,6 +2887,8 @@ begin
-- get divisor into R and prepare to shift left -- get divisor into R and prepare to shift left
-- set shift to 63 - b.exp -- set shift to 63 - b.exp
opsel_a <= AIN_C; opsel_a <= AIN_C;
opsel_b <= BIN_ZERO;
set_r := '1';
rs_sel1 <= RSH1_B; rs_sel1 <= RSH1_B;
rs_neg1 <= '1'; rs_neg1 <= '1';
rs_con2 <= RSCON2_63; rs_con2 <= RSCON2_63;
@ -2798,6 +2897,8 @@ begin
-- divisor is in R -- divisor is in R
-- r.shift = 63 - b.exponent; shift and put into B -- r.shift = 63 - b.exponent; shift and put into B
opsel_a <= AIN_A; opsel_a <= AIN_A;
opsel_b <= BIN_ZERO;
set_r := '1';
set_b_mant := '1'; set_b_mant := '1';
-- set shift to 64 - UNIT_BIT (== 8) -- set shift to 64 - UNIT_BIT (== 8)
rs_con2 <= RSCON2_64_UNIT; rs_con2 <= RSCON2_64_UNIT;
@ -2817,6 +2918,7 @@ begin
-- dividend (A) is in R -- dividend (A) is in R
-- r.shift = 64 - B.exponent, so is at least 1 -- r.shift = 64 - B.exponent, so is at least 1
opsel_r <= RES_SHIFT; opsel_r <= RES_SHIFT;
set_r := '1';
-- top bit of A gets lost in the shift, so handle it specially -- top bit of A gets lost in the shift, so handle it specially
-- set shift to 63 -- set shift to 63
rs_con2 <= RSCON2_63; rs_con2 <= RSCON2_63;
@ -2828,6 +2930,7 @@ begin
opsel_b <= BIN_R; opsel_b <= BIN_R;
opsel_ainv <= '1'; opsel_ainv <= '1';
carry_in <= '1'; carry_in <= '1';
set_r := '1';
-- and put 1<<63 into B as the divisor (S is still 0) -- and put 1<<63 into B as the divisor (S is still 0)
shiftin0 := '1'; shiftin0 := '1';
set_b_mant := '1'; set_b_mant := '1';
@ -2848,6 +2951,7 @@ begin
-- dividend is in R -- dividend is in R
-- r.shift = 64 - B.exponent -- r.shift = 64 - B.exponent
opsel_r <= RES_SHIFT; opsel_r <= RES_SHIFT;
set_r := '1';
v.first := '1'; v.first := '1';
v.state := IDIV_EXTDIV2; v.state := IDIV_EXTDIV2;
when IDIV_EXTDIV2 => when IDIV_EXTDIV2 =>
@ -2858,6 +2962,7 @@ begin
pshift := '1'; pshift := '1';
opsel_r <= RES_MULT; opsel_r <= RES_MULT;
if multiply_to_f.valid = '1' then if multiply_to_f.valid = '1' then
set_r := '1';
v.first := '1'; v.first := '1';
v.state := IDIV_EXTDIV3; v.state := IDIV_EXTDIV3;
end if; end if;
@ -2865,6 +2970,7 @@ begin
-- delta quotient is in R; add it to B -- delta quotient is in R; add it to B
opsel_a <= AIN_B; opsel_a <= AIN_B;
opsel_b <= BIN_R; opsel_b <= BIN_R;
set_r := '1';
v.first := '1'; v.first := '1';
v.state := IDIV_EXTDIV4; v.state := IDIV_EXTDIV4;
when IDIV_EXTDIV4 => when IDIV_EXTDIV4 =>
@ -2883,12 +2989,14 @@ begin
rs_neg1 <= '1'; rs_neg1 <= '1';
rs_con2 <= RSCON2_UNIT; rs_con2 <= RSCON2_UNIT;
if multiply_to_f.valid = '1' then if multiply_to_f.valid = '1' then
set_r := '1';
v.state := IDIV_EXTDIV5; v.state := IDIV_EXTDIV5;
end if; end if;
when IDIV_EXTDIV5 => when IDIV_EXTDIV5 =>
-- r.shift = r.b.exponent - 56 -- r.shift = r.b.exponent - 56
-- remainder is in R/S; shift it right r.b.exponent bits -- remainder is in R/S; shift it right r.b.exponent bits
opsel_r <= RES_SHIFT; opsel_r <= RES_SHIFT;
set_r := '1';
-- test LS 64b of remainder in P against divisor in C -- test LS 64b of remainder in P against divisor in C
v.inc_quot := not pcmpc_lt; v.inc_quot := not pcmpc_lt;
v.state := IDIV_EXTDIV6; v.state := IDIV_EXTDIV6;
@ -2896,6 +3004,8 @@ begin
-- shifted remainder is in R, see if it is > 1 -- shifted remainder is in R, see if it is > 1
-- and compute R = R * Y if so -- and compute R = R * Y if so
opsel_a <= AIN_B; opsel_a <= AIN_B;
opsel_b <= BIN_ZERO;
set_r := '0';
msel_1 <= MUL1_Y; msel_1 <= MUL1_Y;
msel_2 <= MUL2_R; msel_2 <= MUL2_R;
pshift := '1'; pshift := '1';
@ -2903,12 +3013,15 @@ begin
f_to_multiply.valid <= '1'; f_to_multiply.valid <= '1';
v.state := IDIV_EXTDIV2; v.state := IDIV_EXTDIV2;
else else
-- Put B (quotient) into R for IDIV_DIVADJ state
set_r := '1';
v.state := IDIV_DIVADJ; v.state := IDIV_DIVADJ;
end if; end if;
when IDIV_MODADJ => when IDIV_MODADJ =>
-- r.shift = 56 -- r.shift = 56
-- result is in R/S -- result is in R/S
opsel_r <= RES_SHIFT; opsel_r <= RES_SHIFT;
set_r := '1';
if pcmpc_lt = '0' then if pcmpc_lt = '0' then
v.state := IDIV_MODSUB; v.state := IDIV_MODSUB;
elsif r.result_sign = '0' then elsif r.result_sign = '0' then
@ -2922,6 +3035,7 @@ begin
opsel_ainv <= '1'; opsel_ainv <= '1';
carry_in <= '1'; carry_in <= '1';
opsel_b <= BIN_R; opsel_b <= BIN_R;
set_r := '1';
if r.result_sign = '0' then if r.result_sign = '0' then
v.state := IDIV_DONE; v.state := IDIV_DONE;
else else
@ -2931,11 +3045,11 @@ begin
-- result (so far) is in R -- result (so far) is in R
-- set carry to increment quotient if needed -- set carry to increment quotient if needed
-- and also negate R if the answer is negative -- and also negate R if the answer is negative
opsel_ainv <= r.result_sign; opsel_binv <= r.result_sign;
carry_in <= r.inc_quot xor r.result_sign; carry_in <= r.inc_quot xor r.result_sign;
rnd_b32 := '1'; set_r := '1';
if r.divmod = '0' then if r.divmod = '0' then
opsel_b <= BIN_RND; opsel_a <= AIN_RND_B32;
end if; end if;
if r.is_signed = '0' then if r.is_signed = '0' then
v.state := IDIV_DONE; v.state := IDIV_DONE;
@ -2984,6 +3098,7 @@ begin
when IDIV_ZERO => when IDIV_ZERO =>
opsel_r <= RES_MISC; opsel_r <= RES_MISC;
misc_sel <= "000"; misc_sel <= "000";
set_r := '1';
v.xerc_result := v.xerc; v.xerc_result := v.xerc;
if r.oe = '1' then if r.oe = '1' then
v.xerc_result.ov := r.int_ovf; v.xerc_result.ov := r.int_ovf;
@ -3156,36 +3271,32 @@ begin
v.x := '1'; v.x := '1';
end if; end if;
case opsel_a is case opsel_a is
when AIN_R =>
in_a0 := r.r;
when AIN_A => when AIN_A =>
in_a0 := r.a.mantissa; in_a0 := r.a.mantissa;
when AIN_B => when AIN_B =>
in_a0 := r.b.mantissa; in_a0 := r.b.mantissa;
when others => when AIN_C =>
in_a0 := r.c.mantissa; in_a0 := r.c.mantissa;
when AIN_PS8 => -- 8 LSBs of P sign-extended to 64
in_a0 := std_ulogic_vector(resize(signed(r.p(7 downto 0)), 64));
when AIN_RND_B32 =>
in_a0 := (32 => r.result_sign and r.single_prec, others => '0');
when AIN_RND_RBIT =>
in_a0 := (DP_RBIT => '1', others => '0');
when AIN_RND =>
in_a0 := (SP_LSB => r.single_prec, DP_LSB => not r.single_prec, others => '0');
when others =>
in_a0 := (others => '0');
end case; end case;
if opsel_ainv = '1' then if opsel_ainv = '1' then
in_a0 := not in_a0; in_a0 := not in_a0;
end if; end if;
in_a <= in_a0; in_a <= in_a0;
case opsel_b is case opsel_b is
when BIN_ZERO =>
in_b0 := (others => '0');
when BIN_R => when BIN_R =>
in_b0 := r.r; in_b0 := r.r;
when BIN_RND =>
if rnd_b32 = '1' then
round_inc := (32 => r.result_sign and r.single_prec, others => '0');
elsif rbit_inc = '0' then
round_inc := (SP_LSB => r.single_prec, DP_LSB => not r.single_prec, others => '0');
else
round_inc := (DP_RBIT => '1', others => '0');
end if;
in_b0 := round_inc;
when others => when others =>
-- BIN_PS8, 8 LSBs of P sign-extended to 64 in_b0 := (others => '0');
in_b0 := std_ulogic_vector(resize(signed(r.p(7 downto 0)), 64));
end case; end case;
if opsel_binv = '1' then if opsel_binv = '1' then
in_b0 := not in_b0; in_b0 := not in_b0;

Loading…
Cancel
Save