FPU: Remove need to set opsel_a one cycle ahead

Most states set opsel_a directly to select the operand for the A input
of the main adder.  The exception is the EXC_RESULT state, which uses
r.opsel_a set by the previous cycle to indicate which input operand to
use as the result.

In order to make timing, ensure that the controls that select the
inputs to the main adder (opsel_*, etc.) don't depend on any
complicated functions of the data (such as px_nz, pcmpb_eq, pcmpb_lt,
etc.), but are as far as possible constant for each state.  There is
now a control called set_r for whether the result is written to r.r,
which enables us to avoid setting opsel_b or opsel_r conditionally in
some cases.

Also, to avoid a data-dependent setting of msel_2 in IDIV_DODIV state,
the IDIV_NR1 and IDIV_NR2 states have been reworked so that completion
of the required number of iterations is checked in IDIV_NR1 state, and
at that point, if the inverse estimate is < 0.5, we go to IDIV_USE0_5
state in order to use 0.5 as the estimate.  This means that in the
normal case, the inverse estimate is already in Y when we get to
IDIV_DODIV state.  IDIV_USE0_5 has been reworked to put R (which will
contain 0.5) into Y as the inverse estimate.  That means that
IDIV_DODIV state doesn't have any data-dependent logic to put either P
or R into Y.

Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
pull/442/head
Paul Mackerras 1 year ago
parent 2731384a4b
commit ba2add029a

@ -185,6 +185,7 @@ 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_b : std_ulogic_vector(1 downto 0); signal opsel_b : std_ulogic_vector(1 downto 0);
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);
@ -838,6 +839,7 @@ begin
variable set_b_mant : std_ulogic; variable set_b_mant : std_ulogic;
variable set_c : std_ulogic; variable set_c : std_ulogic;
variable set_y : std_ulogic; variable set_y : std_ulogic;
variable set_r : std_ulogic;
variable set_s : std_ulogic; variable set_s : std_ulogic;
variable qnan_result : std_ulogic; variable qnan_result : std_ulogic;
variable invalid_mul : std_ulogic; variable invalid_mul : std_ulogic;
@ -1143,6 +1145,7 @@ begin
v.first := '0'; v.first := '0';
v.doing_ftdiv := "00"; v.doing_ftdiv := "00";
v.opsel_a := AIN_R; v.opsel_a := AIN_R;
opsel_a <= AIN_R;
opsel_ainv <= '0'; opsel_ainv <= '0';
opsel_mask <= '0'; opsel_mask <= '0';
opsel_b <= BIN_ZERO; opsel_b <= BIN_ZERO;
@ -1166,6 +1169,7 @@ begin
set_b := '0'; set_b := '0';
set_b_mant := '0'; set_b_mant := '0';
set_c := '0'; set_c := '0';
set_r := '1';
set_s := '0'; set_s := '0';
f_to_multiply.is_signed <= '0'; f_to_multiply.is_signed <= '0';
f_to_multiply.valid <= '0'; f_to_multiply.valid <= '0';
@ -1207,12 +1211,7 @@ begin
when IDLE => when IDLE =>
v.invalid := '0'; v.invalid := '0';
if e_in.valid = '1' then if e_in.valid = '1' then
v.opsel_a := AIN_B;
v.busy := '1'; v.busy := '1';
if e_in.op = OP_FP_ARITH and e_in.valid_a = '1' and
(e_in.valid_b = '0' or e_in.valid_c = '0') then
v.opsel_a := AIN_A;
end if;
v.exec_state := exec_state; v.exec_state := exec_state;
if is_nan_inf = '1' then if is_nan_inf = '1' then
v.state := DO_NAN_INF; v.state := DO_NAN_INF;
@ -1293,6 +1292,11 @@ 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
if r.is_addition = '1' then
opsel_a <= AIN_A;
else
opsel_a <= AIN_B;
end if;
if (r.use_a = '1' and r.a.class = ZERO) or if (r.use_a = '1' and r.a.class = ZERO) or
(r.use_b = '1' and r.b.class = ZERO and r.is_multiply = '0') or (r.use_b = '1' and r.b.class = ZERO and r.is_multiply = '0') or
(r.use_c = '1' and r.c.class = ZERO) then (r.use_c = '1' and r.c.class = ZERO) then
@ -1320,7 +1324,7 @@ begin
else else
-- B is zero, other operands are finite -- B is zero, other operands are finite
if r.int_result = '1' then if r.int_result = '1' then
-- fcti*, r.opsel_a = AIN_B -- fcti*
arith_done := '1'; arith_done := '1';
elsif r.is_inverse = '1' then elsif r.is_inverse = '1' then
-- fdiv, fre, frsqrte -- fdiv, fre, frsqrte
@ -1328,7 +1332,7 @@ begin
zero_divide := '1'; zero_divide := '1';
arith_done := '1'; arith_done := '1';
elsif r.is_addition = '1' then elsif r.is_addition = '1' then
-- fadd, r.opsel_a = AIN_A -- fadd, fsub
v.result_class := FINITE; v.result_class := FINITE;
re_sel1 <= REXP1_A; re_sel1 <= REXP1_A;
re_set_result <= '1'; re_set_result <= '1';
@ -1342,21 +1346,8 @@ begin


else else
-- some operand is denorm, and/or it's fmadd/fmsub with B=0 -- some operand is denorm, and/or it's fmadd/fmsub with B=0
-- input selection for denorm cases
-- A and C are non-zero if present, -- A and C are non-zero if present,
-- B is non-zero if present except for multiply-add -- B is non-zero if present except for multiply-add
if r.a.zeroexp = '1' and (r.is_multiply or r.is_inverse) = '1' then
v.opsel_a := AIN_A;
elsif r.b.zeroexp = '1' and (r.is_inverse or r.is_sqrt) = '1' then
v.opsel_a := AIN_B;
elsif r.c.zeroexp = '1' then
v.opsel_a := AIN_C;
else
v.opsel_a := AIN_B;
if r.use_a = '1' and (r.use_b = '0' or r.use_c = '0' or r.b.class = ZERO) then
v.opsel_a := AIN_A;
end if;
end if;
if r.is_multiply = '1' and r.b.class = ZERO then if r.is_multiply = '1' and r.b.class = ZERO then
-- This will trigger for fmul as well as fmadd/sub, but -- This will trigger for fmul as well as fmadd/sub, but
-- it doesn't matter since r.is_subtract = 0 for fmul. -- it doesn't matter since r.is_subtract = 0 for fmul.
@ -1389,7 +1380,7 @@ begin
re_sel2 <= REXP2_B; re_sel2 <= REXP2_B;
re_set_result <= '1'; re_set_result <= '1';
if r.a.class = INFINITY or r.b.class = ZERO or r.b.class = INFINITY or if r.a.class = INFINITY or r.b.class = ZERO or r.b.class = INFINITY or
(r.b.class = FINITE and r.b.mantissa(UNIT_BIT) = '0') then (r.b.class = FINITE and r.b.denorm = '1') then
v.cr_result(2) := '1'; v.cr_result(2) := '1';
end if; end if;
if r.a.class = NAN or r.a.class = INFINITY or if r.a.class = NAN or r.a.class = INFINITY or
@ -1408,7 +1399,7 @@ begin
v.instr_done := '1'; v.instr_done := '1';
v.cr_result := "0000"; v.cr_result := "0000";
if r.b.class = ZERO or r.b.class = INFINITY or if r.b.class = ZERO or r.b.class = INFINITY or
(r.b.class = FINITE and r.b.mantissa(UNIT_BIT) = '0') then (r.b.class = FINITE and r.b.denorm = '1') then
v.cr_result(2) := '1'; v.cr_result(2) := '1';
end if; end if;
if r.b.class = NAN or r.b.class = INFINITY or r.b.class = ZERO if r.b.class = NAN or r.b.class = INFINITY or r.b.class = ZERO
@ -1418,7 +1409,7 @@ begin


when DO_FCMP => when DO_FCMP =>
-- fcmp[uo] -- fcmp[uo]
-- r.opsel_a = AIN_B opsel_a <= AIN_B;
v.instr_done := '1'; v.instr_done := '1';
update_fx := '1'; update_fx := '1';
re_sel2 <= REXP2_B; re_sel2 <= REXP2_B;
@ -1467,7 +1458,6 @@ begin
-- Prepare to subtract mantissas, put B in R -- Prepare to subtract mantissas, put B in R
v.cr_result := "0000"; v.cr_result := "0000";
v.instr_done := '0'; v.instr_done := '0';
v.opsel_a := AIN_A;
v.state := CMP_1; v.state := CMP_1;
end if; end if;
v.fpscr(FPSCR_FL downto FPSCR_FU) := v.cr_result; v.fpscr(FPSCR_FL downto FPSCR_FU) := v.cr_result;
@ -1550,7 +1540,7 @@ begin
v.instr_done := '1'; v.instr_done := '1';


when DO_FMR => when DO_FMR =>
-- r.opsel_a = AIN_B opsel_a <= AIN_B;
v.result_class := r.b.class; v.result_class := r.b.class;
re_sel2 <= REXP2_B; re_sel2 <= REXP2_B;
re_set_result <= '1'; re_set_result <= '1';
@ -1558,7 +1548,7 @@ begin
v.instr_done := '1'; v.instr_done := '1';


when DO_FRI => -- fri[nzpm] when DO_FRI => -- fri[nzpm]
-- r.opsel_a = AIN_B opsel_a <= AIN_B;
v.result_class := r.b.class; v.result_class := r.b.class;
re_sel2 <= REXP2_B; re_sel2 <= REXP2_B;
re_set_result <= '1'; re_set_result <= '1';
@ -1574,14 +1564,15 @@ begin
end if; end if;


when DO_FRSP => when DO_FRSP =>
-- r.opsel_a = AIN_B, r.shift = 0 -- r.shift = 0
opsel_a <= AIN_B;
v.result_class := r.b.class; v.result_class := r.b.class;
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.opsel_a = AIN_R, r.shift = 0 -- r.shift = 0
-- set shift to exponent - -126 -- set shift to exponent - -126
rs_sel1 <= RSH1_B; rs_sel1 <= RSH1_B;
rs_con2 <= RSCON2_MINEXP; rs_con2 <= RSCON2_MINEXP;
@ -1599,7 +1590,7 @@ begin
-- instr bit 9: 1=dword 0=word -- instr bit 9: 1=dword 0=word
-- 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]
-- r.opsel_a = AIN_B opsel_a <= AIN_B;
v.result_class := r.b.class; v.result_class := r.b.class;
re_sel2 <= REXP2_B; re_sel2 <= REXP2_B;
re_set_result <= '1'; re_set_result <= '1';
@ -1626,7 +1617,7 @@ begin
end if; end if;


when DO_FCFID => when DO_FCFID =>
-- r.opsel_a = AIN_B opsel_a <= AIN_B;
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
opsel_ainv <= '1'; opsel_ainv <= '1';
@ -1643,7 +1634,7 @@ begin


when DO_FADD => when DO_FADD =>
-- fadd[s] and fsub[s] -- fadd[s] and fsub[s]
-- r.opsel_a = AIN_A opsel_a <= AIN_A;
v.result_class := r.a.class; v.result_class := r.a.class;
re_sel1 <= REXP1_A; re_sel1 <= REXP1_A;
re_set_result <= '1'; re_set_result <= '1';
@ -1652,7 +1643,6 @@ begin
rs_neg1 <= '1'; rs_neg1 <= '1';
rs_sel2 <= RSH2_A; rs_sel2 <= RSH2_A;
v.add_bsmall := r.exp_cmp; v.add_bsmall := r.exp_cmp;
v.opsel_a := AIN_B;
if r.exp_cmp = '0' then if r.exp_cmp = '0' then
if r.a.exponent = r.b.exponent then if r.a.exponent = r.b.exponent then
v.state := ADD_2; v.state := ADD_2;
@ -1666,15 +1656,16 @@ begin


when DO_FMUL => when DO_FMUL =>
-- fmul[s] -- fmul[s]
-- r.opsel_a = AIN_A unless C is denorm and A isn't opsel_a <= AIN_A;
v.result_class := r.a.class; v.result_class := r.a.class;
re_sel1 <= REXP1_A; re_sel1 <= REXP1_A;
re_sel2 <= REXP2_C; re_sel2 <= REXP2_C;
re_set_result <= '1'; re_set_result <= '1';
-- Renormalize denorm operands -- Renormalize denorm operands
if r.a.mantissa(UNIT_BIT) = '0' then if r.a.denorm = '1' then
v.state := RENORM_A; v.state := RENORM_A;
elsif r.c.mantissa(UNIT_BIT) = '0' then elsif r.c.denorm = '1' then
opsel_a <= AIN_C;
v.state := RENORM_C; v.state := RENORM_C;
else else
f_to_multiply.valid <= '1'; f_to_multiply.valid <= '1';
@ -1682,7 +1673,7 @@ begin
end if; end if;


when DO_FDIV => when DO_FDIV =>
-- r.opsel_a = AIN_A unless B is denorm and A isn't opsel_a <= AIN_A;
v.result_class := r.a.class; v.result_class := r.a.class;
re_sel1 <= REXP1_A; re_sel1 <= REXP1_A;
re_sel2 <= REXP2_B; re_sel2 <= REXP2_B;
@ -1690,9 +1681,10 @@ begin
re_set_result <= '1'; re_set_result <= '1';
v.count := "00"; v.count := "00";
-- Renormalize denorm operands -- Renormalize denorm operands
if r.a.mantissa(UNIT_BIT) = '0' then if r.a.denorm = '1' then
v.state := RENORM_A; v.state := RENORM_A;
elsif r.b.mantissa(UNIT_BIT) = '0' then elsif r.b.denorm = '1' then
opsel_a <= AIN_B;
v.state := RENORM_B; v.state := RENORM_B;
else else
v.first := '1'; v.first := '1';
@ -1700,23 +1692,23 @@ begin
end if; end if;


when DO_FSEL => when DO_FSEL =>
rsgn_op := RSGN_SEL;
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;
rsgn_op := RSGN_SEL;
else else
v.opsel_a := AIN_B; v.opsel_a := AIN_B;
end if; end if;
v.state := EXC_RESULT; v.state := EXC_RESULT;


when DO_FSQRT => when DO_FSQRT =>
-- r.opsel_a = AIN_B opsel_a <= AIN_B;
v.result_class := r.b.class; v.result_class := r.b.class;
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
v.fpscr(FPSCR_VXSQRT) := '1'; v.fpscr(FPSCR_VXSQRT) := '1';
qnan_result := '1'; qnan_result := '1';
elsif r.b.mantissa(UNIT_BIT) = '0' then elsif r.b.denorm = '1' then
v.state := RENORM_B; v.state := RENORM_B;
elsif r.b.exponent(0) = '0' then elsif r.b.exponent(0) = '0' then
v.state := SQRT_1; v.state := SQRT_1;
@ -1727,18 +1719,18 @@ begin
end if; end if;


when DO_FRE => when DO_FRE =>
-- r.opsel_a = AIN_B opsel_a <= AIN_B;
v.result_class := r.b.class; v.result_class := r.b.class;
re_sel2 <= REXP2_B; re_sel2 <= REXP2_B;
re_set_result <= '1'; re_set_result <= '1';
if r.b.mantissa(UNIT_BIT) = '0' then if r.b.denorm = '1' then
v.state := RENORM_B; v.state := RENORM_B;
else else
v.state := FRE_1; v.state := FRE_1;
end if; end if;


when DO_FRSQRTE => when DO_FRSQRTE =>
-- r.opsel_a = AIN_B opsel_a <= AIN_B;
v.result_class := r.b.class; v.result_class := r.b.class;
re_sel2 <= REXP2_B; re_sel2 <= REXP2_B;
re_set_result <= '1'; re_set_result <= '1';
@ -1747,7 +1739,7 @@ begin
if r.b.negative = '1' then if r.b.negative = '1' then
v.fpscr(FPSCR_VXSQRT) := '1'; v.fpscr(FPSCR_VXSQRT) := '1';
qnan_result := '1'; qnan_result := '1';
elsif r.b.mantissa(UNIT_BIT) = '0' then elsif r.b.denorm = '1' then
v.state := RENORM_B; v.state := RENORM_B;
elsif r.b.exponent(0) = '0' then elsif r.b.exponent(0) = '0' then
v.state := RSQRT_1; v.state := RSQRT_1;
@ -1757,8 +1749,7 @@ begin


when DO_FMADD => when DO_FMADD =>
-- fmadd, fmsub, fnmadd, fnmsub -- fmadd, fmsub, fnmadd, fnmsub
-- r.opsel_a = AIN_A if A is denorm, else AIN_C if C is denorm, opsel_a <= AIN_B;
-- else AIN_B
v.result_class := r.a.class; v.result_class := r.a.class;
-- put a.exp + c.exp into result_exp -- put a.exp + c.exp into result_exp
re_sel1 <= REXP1_A; re_sel1 <= REXP1_A;
@ -1767,9 +1758,11 @@ begin
-- put b.exp into shift -- put b.exp into shift
rs_sel1 <= RSH1_B; rs_sel1 <= RSH1_B;
-- 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.denorm = '1' then
opsel_a <= AIN_A;
v.state := RENORM_A; v.state := RENORM_A;
elsif r.c.mantissa(UNIT_BIT) = '0' then elsif r.c.denorm = '1' then
opsel_a <= AIN_C;
v.state := RENORM_C; v.state := RENORM_C;
elsif r.madd_cmp = '0' then elsif r.madd_cmp = '0' then
-- addend is bigger, do multiply first -- addend is bigger, do multiply first
@ -1785,18 +1778,13 @@ begin
when RENORM_A => when RENORM_A =>
rs_norm <= '1'; rs_norm <= '1';
v.state := RENORM_A2; v.state := RENORM_A2;
if r.use_c = '1' and r.c.denorm = '1' then
v.opsel_a := AIN_C;
else
v.opsel_a := AIN_B;
end if;


when RENORM_A2 => when RENORM_A2 =>
-- r.opsel_a = AIN_C for fmul/fmadd, AIN_B for fdiv
set_a := '1'; set_a := '1';
re_sel2 <= REXP2_NE; re_sel2 <= REXP2_NE;
re_set_result <= '1'; re_set_result <= '1';
if r.is_multiply = '1' then if r.is_multiply = '1' then
opsel_a <= AIN_C;
if r.c.mantissa(UNIT_BIT) = '1' then if r.c.mantissa(UNIT_BIT) = '1' then
if r.is_addition = '0' or r.b.class = ZERO then if r.is_addition = '0' or r.b.class = ZERO then
v.first := '1'; v.first := '1';
@ -1806,13 +1794,13 @@ begin
if new_exp + 1 >= r.b.exponent then if new_exp + 1 >= r.b.exponent then
v.madd_cmp := '1'; v.madd_cmp := '1';
end if; end if;
v.opsel_a := AIN_B;
v.state := DO_FMADD; v.state := DO_FMADD;
end if; end if;
else else
v.state := RENORM_C; v.state := RENORM_C;
end if; end if;
else else
opsel_a <= AIN_B;
if r.b.mantissa(UNIT_BIT) = '1' then if r.b.mantissa(UNIT_BIT) = '1' then
v.first := '1'; v.first := '1';
v.state := DIV_2; v.state := DIV_2;
@ -1839,7 +1827,6 @@ begin
re_sel2 <= REXP2_NE; re_sel2 <= REXP2_NE;
re_set_result <= '1'; re_set_result <= '1';
end if; end if;
v.opsel_a := AIN_B;
v.state := LOOKUP; v.state := LOOKUP;


when RENORM_C => when RENORM_C =>
@ -1858,12 +1845,12 @@ begin
if new_exp + 1 >= r.b.exponent then if new_exp + 1 >= r.b.exponent then
v.madd_cmp := '1'; v.madd_cmp := '1';
end if; end if;
v.opsel_a := AIN_B;
v.state := DO_FMADD; v.state := DO_FMADD;
end if; end if;


when ADD_1 => when ADD_1 =>
-- transferring B to R -- transferring B to R
opsel_a <= AIN_B;
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
@ -1881,15 +1868,14 @@ begin
v.x := s_nz; v.x := s_nz;
set_x := '1'; set_x := '1';
v.longmask := r.single_prec; v.longmask := r.single_prec;
if r.add_bsmall = '1' then
v.opsel_a := AIN_A;
else
v.opsel_a := AIN_B;
end if;
v.state := ADD_2; v.state := ADD_2;


when ADD_2 => when ADD_2 =>
-- r.opsel_a = AIN_A if r.add_bsmall = 1 else AIN_B if r.add_bsmall = '1' then
opsel_a <= AIN_A;
else
opsel_a <= AIN_B;
end if;
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;
@ -1931,7 +1917,7 @@ begin
end if; end if;


when CMP_1 => when CMP_1 =>
-- r.opsel_a = AIN_A opsel_a <= AIN_A;
opsel_b <= BIN_R; opsel_b <= BIN_R;
opsel_binv <= '1'; opsel_binv <= '1';
carry_in <= '1'; carry_in <= '1';
@ -2033,6 +2019,8 @@ begin


when FMADD_6 => when FMADD_6 =>
-- r.shift = UNIT_BIT (or 0, but only if r is now nonzero) -- r.shift = UNIT_BIT (or 0, but only if r is now nonzero)
set_r := '0';
opsel_r <= RES_SHIFT;
re_sel2 <= REXP2_NE; re_sel2 <= REXP2_NE;
rs_norm <= '1'; rs_norm <= '1';
if (r.r(UNIT_BIT + 2) or r_hi_nz or r_lo_nz or (or (r.r(DP_LSB - 1 downto 0)))) = '0' then if (r.r(UNIT_BIT + 2) or r_hi_nz or r_lo_nz or (or (r.r(DP_LSB - 1 downto 0)))) = '0' then
@ -2043,7 +2031,7 @@ begin
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
-- so shift them into R and set S to 0 -- so shift them into R and set S to 0
opsel_r <= RES_SHIFT; set_r := '1';
re_set_result <= '1'; re_set_result <= '1';
set_s := '1'; set_s := '1';
v.state := FINISH; v.state := FINISH;
@ -2055,10 +2043,10 @@ begin
end if; end if;


when LOOKUP => when LOOKUP =>
-- r.opsel_a = AIN_B
-- wait one cycle for inverse_table[B] lookup -- wait one cycle for inverse_table[B] lookup
-- if this is a division, compute exponent -- if this is a division, compute exponent
-- (see comment on RENORM_B2 above) -- (see comment on RENORM_B2 above)
opsel_a <= AIN_B;
if r.use_a = '1' then if r.use_a = '1' then
re_sel2 <= REXP2_NE; re_sel2 <= REXP2_NE;
re_set_result <= '1'; re_set_result <= '1';
@ -2136,15 +2124,15 @@ begin
end if; end if;


when DIV_6 => when DIV_6 =>
-- r.opsel_a = AIN_R
-- test if remainder is 0 or >= B -- test if remainder is 0 or >= B
opsel_b <= BIN_RND;
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';
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
rbit_inc := '1';
opsel_b <= BIN_RND;
v.x := not pcmpb_eq; v.x := not pcmpb_eq;
end if; end if;
v.state := FINISH; v.state := FINISH;
@ -2575,6 +2563,7 @@ begin


when ROUNDING_3 => when ROUNDING_3 =>
-- r.shift = clz(r.r) - 9 -- r.shift = clz(r.r) - 9
opsel_r <= RES_SHIFT;
mant_nz := r_hi_nz or (r_lo_nz and not r.single_prec); mant_nz := r_hi_nz or (r_lo_nz and not r.single_prec);
re_sel2 <= REXP2_NE; re_sel2 <= REXP2_NE;
-- set shift to new_exp - min_exp (== -1022) -- set shift to new_exp - min_exp (== -1022)
@ -2582,11 +2571,11 @@ begin
rs_con2 <= RSCON2_MINEXP; rs_con2 <= RSCON2_MINEXP;
rs_neg2 <= '1'; rs_neg2 <= '1';
if mant_nz = '0' then if mant_nz = '0' then
set_r := '0';
v.result_class := ZERO; v.result_class := ZERO;
arith_done := '1'; arith_done := '1';
else else
-- Renormalize result after rounding -- Renormalize result after rounding
opsel_r <= RES_SHIFT;
re_set_result <= '1'; re_set_result <= '1';
v.denorm := exp_tiny; v.denorm := exp_tiny;
if new_exp < to_signed(-1022, EXP_BITS) then if new_exp < to_signed(-1022, EXP_BITS) then
@ -2605,6 +2594,7 @@ begin


when EXC_RESULT => when EXC_RESULT =>
-- 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
opsel_a <= r.opsel_a;
case r.opsel_a is case r.opsel_a is
when AIN_B => when AIN_B =>
re_sel2 <= REXP2_B; re_sel2 <= REXP2_B;
@ -2620,7 +2610,7 @@ begin
arith_done := '1'; arith_done := '1';


when DO_IDIVMOD => when DO_IDIVMOD =>
-- r.opsel_a = AIN_B opsel_a <= AIN_B;
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';
@ -2657,21 +2647,19 @@ begin
-- 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;
-- prepare to do count-leading-zeroes on A -- prepare to do count-leading-zeroes on A
v.opsel_a := AIN_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
-- r.opsel_a = AIN_A opsel_a <= AIN_A;
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';
end if; end if;
re_con2 <= RECON2_UNIT; re_con2 <= RECON2_UNIT;
re_set_result <= '1'; re_set_result <= '1';
v.opsel_a := AIN_C;
v.state := IDIV_CLZA2; v.state := IDIV_CLZA2;
when IDIV_CLZA2 => when IDIV_CLZA2 =>
-- r.opsel_a = AIN_C 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';
@ -2720,6 +2708,12 @@ begin
msel_inv <= '1'; msel_inv <= '1';
msel_2 <= MUL2_LUT; msel_2 <= MUL2_LUT;
set_y := '1'; set_y := '1';
-- Get 0.5 into R in case the inverse estimate turns out to be
-- less than 0.5, in which case we want to use 0.5, to avoid
-- infinite loops in some cases.
-- It turns out the generated QNaN mantissa is actually what we want
opsel_r <= RES_MISC;
misc_sel <= "001";
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
@ -2740,10 +2734,22 @@ begin
msel_2 <= MUL2_P; msel_2 <= MUL2_P;
set_y := r.first; set_y := r.first;
pshift := '1'; pshift := '1';
-- set shift to 64
rs_con2 <= RSCON2_64;
if r.first = '1' then
if r.count = "11" then
if r.p(UNIT_BIT) = '0' and r.p(UNIT_BIT - 1) = '0' then
-- inverse estimate is < 0.5, so use 0.5
v.state := IDIV_USE0_5;
else
v.state := IDIV_DODIV;
end if;
else
f_to_multiply.valid <= r.first; f_to_multiply.valid <= r.first;
end if;
end if;
if multiply_to_f.valid = '1' then if multiply_to_f.valid = '1' then
v.first := '1'; v.first := '1';
v.count := r.count + 1;
v.state := IDIV_NR2; v.state := IDIV_NR2;
end if; end if;
when IDIV_NR2 => when IDIV_NR2 =>
@ -2752,42 +2758,25 @@ begin
msel_2 <= MUL2_P; msel_2 <= MUL2_P;
f_to_multiply.valid <= r.first; f_to_multiply.valid <= r.first;
pshift := '1'; pshift := '1';
v.opsel_a := AIN_A; if r.first = '1' then
-- set shift to 64 v.count := r.count + 1;
rs_con2 <= RSCON2_64; end if;
-- Get 0.5 into R in case the inverse estimate turns out to be
-- less than 0.5, in which case we want to use 0.5, to avoid
-- infinite loops in some cases.
opsel_r <= RES_MISC;
misc_sel <= "001";
if multiply_to_f.valid = '1' then if multiply_to_f.valid = '1' then
v.first := '1'; v.first := '1';
if r.count = "11" then
v.state := IDIV_DODIV;
else
v.state := IDIV_NR1; v.state := IDIV_NR1;
end if; end if;
end if;
when IDIV_USE0_5 => when IDIV_USE0_5 =>
-- Get 0.5 into R; it turns out the generated -- Put the 0.5 which is in R into Y as the inverse estimate
-- QNaN mantissa is actually what we want set_y := '1';
opsel_r <= RES_MISC; msel_2 <= MUL2_R;
misc_sel <= "001";
v.opsel_a := AIN_A;
-- set shift to 64 -- set shift to 64
rs_con2 <= RSCON2_64; rs_con2 <= RSCON2_64;
v.state := IDIV_DODIV; v.state := IDIV_DODIV;
when IDIV_DODIV => when IDIV_DODIV =>
-- r.opsel_a = AIN_A
-- r.shift = 64 -- r.shift = 64
-- inverse estimate is in P or in R; copy it to Y -- inverse estimate is in Y
if r.b.mantissa(UNIT_BIT + 1) = '1' or -- put A (dividend) into R
(r.p(UNIT_BIT) = '0' and r.p(UNIT_BIT - 1) = '0') then opsel_a <= AIN_A;
msel_2 <= MUL2_R;
else
msel_2 <= MUL2_P;
end if;
set_y := '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';
@ -2809,7 +2798,6 @@ begin
else else
-- handle top bit of quotient specially -- handle top bit of quotient specially
-- for this we need the divisor left-justified in B -- for this we need the divisor left-justified in B
v.opsel_a := AIN_C;
v.state := IDIV_EXT_TBH; v.state := IDIV_EXT_TBH;
end if; end if;
when IDIV_SH32 => when IDIV_SH32 =>
@ -2864,7 +2852,8 @@ begin
msel_2 <= MUL2_P; msel_2 <= MUL2_P;
v.inc_quot := not pcmpc_lt and not r.divmod; v.inc_quot := not pcmpc_lt and not r.divmod;
if r.divmod = '0' then if r.divmod = '0' then
v.opsel_a := AIN_B; -- get B into R for IDIV_DIVADJ state
opsel_a <= AIN_B;
end if; end if;
-- set shift to UNIT_BIT (== 56) -- set shift to UNIT_BIT (== 56)
rs_con2 <= RSCON2_UNIT; rs_con2 <= RSCON2_UNIT;
@ -2894,12 +2883,11 @@ begin
-- 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;
v.opsel_a := AIN_B;
v.first := '1'; v.first := '1';
v.state := IDIV_DIV7; v.state := IDIV_DIV7;
when IDIV_DIV7 => when IDIV_DIV7 =>
-- r.opsel_a = AIN_B
-- add shifted quotient delta onto the total quotient -- add shifted quotient delta onto the total quotient
opsel_a <= AIN_B;
opsel_b <= BIN_R; opsel_b <= BIN_R;
v.first := '1'; v.first := '1';
v.state := IDIV_DIV8; v.state := IDIV_DIV8;
@ -2923,12 +2911,11 @@ begin
msel_1 <= MUL1_Y; msel_1 <= MUL1_Y;
msel_2 <= MUL2_P; msel_2 <= MUL2_P;
v.inc_quot := not pcmpc_lt and not r.divmod; v.inc_quot := not pcmpc_lt and not r.divmod;
if r.divmod = '0' then
v.opsel_a := AIN_B;
end if;
-- set shift to UNIT_BIT (== 56) -- set shift to UNIT_BIT (== 56)
rs_con2 <= RSCON2_UNIT; rs_con2 <= RSCON2_UNIT;
if r.divmod = '0' then if r.divmod = '0' then
-- get B into R for IDIV_DIVADJ state
opsel_a <= AIN_B;
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;
@ -2936,16 +2923,17 @@ begin
v.state := IDIV_MODADJ; v.state := IDIV_MODADJ;
end if; end if;
when IDIV_EXT_TBH => when IDIV_EXT_TBH =>
-- r.opsel_a = AIN_C; 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;
rs_sel1 <= RSH1_B; rs_sel1 <= RSH1_B;
rs_neg1 <= '1'; rs_neg1 <= '1';
rs_con2 <= RSCON2_63; rs_con2 <= RSCON2_63;
v.opsel_a := AIN_A;
v.state := IDIV_EXT_TBH2; v.state := IDIV_EXT_TBH2;
when IDIV_EXT_TBH2 => when IDIV_EXT_TBH2 =>
-- r.opsel_a = AIN_A; 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;
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;
@ -2966,13 +2954,13 @@ begin
-- 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;
-- 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
v.opsel_a := AIN_B;
-- set shift to 63 -- set shift to 63
rs_con2 <= RSCON2_63; rs_con2 <= RSCON2_63;
v.state := IDIV_EXT_TBH5; v.state := IDIV_EXT_TBH5;
when IDIV_EXT_TBH5 => when IDIV_EXT_TBH5 =>
-- r.opsel_a = AIN_B, r.shift = 63 -- r.shift = 63
-- shifted dividend is in R, subtract left-justified divisor -- shifted dividend is in R, subtract left-justified divisor
opsel_a <= AIN_B;
opsel_b <= BIN_R; opsel_b <= BIN_R;
opsel_ainv <= '1'; opsel_ainv <= '1';
carry_in <= '1'; carry_in <= '1';
@ -3004,15 +2992,14 @@ begin
msel_2 <= MUL2_R; msel_2 <= MUL2_R;
f_to_multiply.valid <= r.first; f_to_multiply.valid <= r.first;
pshift := '1'; pshift := '1';
v.opsel_a := AIN_B;
opsel_r <= RES_MULT; opsel_r <= RES_MULT;
if multiply_to_f.valid = '1' then if multiply_to_f.valid = '1' then
v.first := '1'; v.first := '1';
v.state := IDIV_EXTDIV3; v.state := IDIV_EXTDIV3;
end if; end if;
when IDIV_EXTDIV3 => when IDIV_EXTDIV3 =>
-- r.opsel_a = AIN_B
-- delta quotient is in R; add it to B -- delta quotient is in R; add it to B
opsel_a <= AIN_B;
opsel_b <= BIN_R; opsel_b <= BIN_R;
v.first := '1'; v.first := '1';
v.state := IDIV_EXTDIV4; v.state := IDIV_EXTDIV4;
@ -3040,12 +3027,11 @@ begin
opsel_r <= RES_SHIFT; opsel_r <= RES_SHIFT;
-- 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.opsel_a := AIN_B;
v.state := IDIV_EXTDIV6; v.state := IDIV_EXTDIV6;
when IDIV_EXTDIV6 => when IDIV_EXTDIV6 =>
-- r.opsel_a = AIN_B
-- 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;
msel_1 <= MUL1_Y; msel_1 <= MUL1_Y;
msel_2 <= MUL2_R; msel_2 <= MUL2_R;
pshift := '1'; pshift := '1';
@ -3060,7 +3046,6 @@ begin
-- result is in R/S -- result is in R/S
opsel_r <= RES_SHIFT; opsel_r <= RES_SHIFT;
if pcmpc_lt = '0' then if pcmpc_lt = '0' then
v.opsel_a := AIN_C;
v.state := IDIV_MODSUB; v.state := IDIV_MODSUB;
elsif r.result_sign = '0' then elsif r.result_sign = '0' then
v.state := IDIV_DONE; v.state := IDIV_DONE;
@ -3068,8 +3053,8 @@ begin
v.state := IDIV_DIVADJ; v.state := IDIV_DIVADJ;
end if; end if;
when IDIV_MODSUB => when IDIV_MODSUB =>
-- r.opsel_a = AIN_C
-- Subtract divisor from remainder -- Subtract divisor from remainder
opsel_a <= AIN_C;
opsel_ainv <= '1'; opsel_ainv <= '1';
carry_in <= '1'; carry_in <= '1';
opsel_b <= BIN_R; opsel_b <= BIN_R;
@ -3079,7 +3064,7 @@ begin
v.state := IDIV_DIVADJ; v.state := IDIV_DIVADJ;
end if; end if;
when IDIV_DIVADJ => when IDIV_DIVADJ =>
-- result (so far) is on the A input of the adder -- 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_ainv <= r.result_sign;
@ -3274,7 +3259,7 @@ begin
if (or (mask and r.r)) = '1' and set_x = '1' then if (or (mask and r.r)) = '1' and set_x = '1' then
v.x := '1'; v.x := '1';
end if; end if;
case r.opsel_a is case opsel_a is
when AIN_R => when AIN_R =>
in_a0 := r.r; in_a0 := r.r;
when AIN_A => when AIN_A =>
@ -3379,7 +3364,9 @@ begin
end case; end case;
result <= misc; result <= misc;
end case; end case;
if set_r = '1' then
v.r := result; v.r := result;
end if;
if set_s = '1' then if set_s = '1' then
case opsel_s is case opsel_s is
when S_NEG => when S_NEG =>

Loading…
Cancel
Save