mirror of
https://github.com/antonblanchard/microwatt.git
synced 2026-04-04 20:28:30 +00:00
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>
This commit is contained in:
239
fpu.vhdl
239
fpu.vhdl
@@ -185,6 +185,7 @@ architecture behaviour of fpu is
|
||||
signal r, rin : reg_type;
|
||||
|
||||
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_r : 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_c : std_ulogic;
|
||||
variable set_y : std_ulogic;
|
||||
variable set_r : std_ulogic;
|
||||
variable set_s : std_ulogic;
|
||||
variable qnan_result : std_ulogic;
|
||||
variable invalid_mul : std_ulogic;
|
||||
@@ -1143,6 +1145,7 @@ begin
|
||||
v.first := '0';
|
||||
v.doing_ftdiv := "00";
|
||||
v.opsel_a := AIN_R;
|
||||
opsel_a <= AIN_R;
|
||||
opsel_ainv <= '0';
|
||||
opsel_mask <= '0';
|
||||
opsel_b <= BIN_ZERO;
|
||||
@@ -1166,6 +1169,7 @@ begin
|
||||
set_b := '0';
|
||||
set_b_mant := '0';
|
||||
set_c := '0';
|
||||
set_r := '1';
|
||||
set_s := '0';
|
||||
f_to_multiply.is_signed <= '0';
|
||||
f_to_multiply.valid <= '0';
|
||||
@@ -1207,12 +1211,7 @@ begin
|
||||
when IDLE =>
|
||||
v.invalid := '0';
|
||||
if e_in.valid = '1' then
|
||||
v.opsel_a := AIN_B;
|
||||
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;
|
||||
if is_nan_inf = '1' then
|
||||
v.state := DO_NAN_INF;
|
||||
@@ -1293,6 +1292,11 @@ begin
|
||||
|
||||
when DO_ZERO_DEN =>
|
||||
-- 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
|
||||
(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
|
||||
@@ -1320,7 +1324,7 @@ begin
|
||||
else
|
||||
-- B is zero, other operands are finite
|
||||
if r.int_result = '1' then
|
||||
-- fcti*, r.opsel_a = AIN_B
|
||||
-- fcti*
|
||||
arith_done := '1';
|
||||
elsif r.is_inverse = '1' then
|
||||
-- fdiv, fre, frsqrte
|
||||
@@ -1328,7 +1332,7 @@ begin
|
||||
zero_divide := '1';
|
||||
arith_done := '1';
|
||||
elsif r.is_addition = '1' then
|
||||
-- fadd, r.opsel_a = AIN_A
|
||||
-- fadd, fsub
|
||||
v.result_class := FINITE;
|
||||
re_sel1 <= REXP1_A;
|
||||
re_set_result <= '1';
|
||||
@@ -1342,21 +1346,8 @@ begin
|
||||
|
||||
else
|
||||
-- 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,
|
||||
-- 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
|
||||
-- This will trigger for fmul as well as fmadd/sub, but
|
||||
-- it doesn't matter since r.is_subtract = 0 for fmul.
|
||||
@@ -1389,7 +1380,7 @@ begin
|
||||
re_sel2 <= REXP2_B;
|
||||
re_set_result <= '1';
|
||||
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';
|
||||
end if;
|
||||
if r.a.class = NAN or r.a.class = INFINITY or
|
||||
@@ -1408,7 +1399,7 @@ begin
|
||||
v.instr_done := '1';
|
||||
v.cr_result := "0000";
|
||||
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';
|
||||
end if;
|
||||
if r.b.class = NAN or r.b.class = INFINITY or r.b.class = ZERO
|
||||
@@ -1418,7 +1409,7 @@ begin
|
||||
|
||||
when DO_FCMP =>
|
||||
-- fcmp[uo]
|
||||
-- r.opsel_a = AIN_B
|
||||
opsel_a <= AIN_B;
|
||||
v.instr_done := '1';
|
||||
update_fx := '1';
|
||||
re_sel2 <= REXP2_B;
|
||||
@@ -1467,7 +1458,6 @@ begin
|
||||
-- Prepare to subtract mantissas, put B in R
|
||||
v.cr_result := "0000";
|
||||
v.instr_done := '0';
|
||||
v.opsel_a := AIN_A;
|
||||
v.state := CMP_1;
|
||||
end if;
|
||||
v.fpscr(FPSCR_FL downto FPSCR_FU) := v.cr_result;
|
||||
@@ -1550,7 +1540,7 @@ begin
|
||||
v.instr_done := '1';
|
||||
|
||||
when DO_FMR =>
|
||||
-- r.opsel_a = AIN_B
|
||||
opsel_a <= AIN_B;
|
||||
v.result_class := r.b.class;
|
||||
re_sel2 <= REXP2_B;
|
||||
re_set_result <= '1';
|
||||
@@ -1558,7 +1548,7 @@ begin
|
||||
v.instr_done := '1';
|
||||
|
||||
when DO_FRI => -- fri[nzpm]
|
||||
-- r.opsel_a = AIN_B
|
||||
opsel_a <= AIN_B;
|
||||
v.result_class := r.b.class;
|
||||
re_sel2 <= REXP2_B;
|
||||
re_set_result <= '1';
|
||||
@@ -1574,14 +1564,15 @@ begin
|
||||
end if;
|
||||
|
||||
when DO_FRSP =>
|
||||
-- r.opsel_a = AIN_B, r.shift = 0
|
||||
-- r.shift = 0
|
||||
opsel_a <= AIN_B;
|
||||
v.result_class := r.b.class;
|
||||
re_sel2 <= REXP2_B;
|
||||
re_set_result <= '1';
|
||||
v.state := DO_FRSP_2;
|
||||
|
||||
when DO_FRSP_2 =>
|
||||
-- r.opsel_a = AIN_R, r.shift = 0
|
||||
-- r.shift = 0
|
||||
-- set shift to exponent - -126
|
||||
rs_sel1 <= RSH1_B;
|
||||
rs_con2 <= RSCON2_MINEXP;
|
||||
@@ -1599,7 +1590,7 @@ begin
|
||||
-- instr bit 9: 1=dword 0=word
|
||||
-- instr bit 8: 1=unsigned 0=signed
|
||||
-- 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;
|
||||
re_sel2 <= REXP2_B;
|
||||
re_set_result <= '1';
|
||||
@@ -1626,7 +1617,7 @@ begin
|
||||
end if;
|
||||
|
||||
when DO_FCFID =>
|
||||
-- r.opsel_a = AIN_B
|
||||
opsel_a <= AIN_B;
|
||||
if r.insn(8) = '0' and r.b.negative = '1' then
|
||||
-- fcfid[s] with negative operand, set R = -B
|
||||
opsel_ainv <= '1';
|
||||
@@ -1643,7 +1634,7 @@ begin
|
||||
|
||||
when DO_FADD =>
|
||||
-- fadd[s] and fsub[s]
|
||||
-- r.opsel_a = AIN_A
|
||||
opsel_a <= AIN_A;
|
||||
v.result_class := r.a.class;
|
||||
re_sel1 <= REXP1_A;
|
||||
re_set_result <= '1';
|
||||
@@ -1652,7 +1643,6 @@ begin
|
||||
rs_neg1 <= '1';
|
||||
rs_sel2 <= RSH2_A;
|
||||
v.add_bsmall := r.exp_cmp;
|
||||
v.opsel_a := AIN_B;
|
||||
if r.exp_cmp = '0' then
|
||||
if r.a.exponent = r.b.exponent then
|
||||
v.state := ADD_2;
|
||||
@@ -1666,15 +1656,16 @@ begin
|
||||
|
||||
when DO_FMUL =>
|
||||
-- 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;
|
||||
re_sel1 <= REXP1_A;
|
||||
re_sel2 <= REXP2_C;
|
||||
re_set_result <= '1';
|
||||
-- Renormalize denorm operands
|
||||
if r.a.mantissa(UNIT_BIT) = '0' then
|
||||
if r.a.denorm = '1' then
|
||||
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;
|
||||
else
|
||||
f_to_multiply.valid <= '1';
|
||||
@@ -1682,7 +1673,7 @@ begin
|
||||
end if;
|
||||
|
||||
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;
|
||||
re_sel1 <= REXP1_A;
|
||||
re_sel2 <= REXP2_B;
|
||||
@@ -1690,9 +1681,10 @@ begin
|
||||
re_set_result <= '1';
|
||||
v.count := "00";
|
||||
-- Renormalize denorm operands
|
||||
if r.a.mantissa(UNIT_BIT) = '0' then
|
||||
if r.a.denorm = '1' then
|
||||
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;
|
||||
else
|
||||
v.first := '1';
|
||||
@@ -1700,23 +1692,23 @@ begin
|
||||
end if;
|
||||
|
||||
when DO_FSEL =>
|
||||
rsgn_op := RSGN_SEL;
|
||||
if r.a.class = ZERO or (r.a.negative = '0' and r.a.class /= NAN) then
|
||||
v.opsel_a := AIN_C;
|
||||
rsgn_op := RSGN_SEL;
|
||||
else
|
||||
v.opsel_a := AIN_B;
|
||||
end if;
|
||||
v.state := EXC_RESULT;
|
||||
|
||||
when DO_FSQRT =>
|
||||
-- r.opsel_a = AIN_B
|
||||
opsel_a <= AIN_B;
|
||||
v.result_class := r.b.class;
|
||||
re_sel2 <= REXP2_B;
|
||||
re_set_result <= '1';
|
||||
if r.b.negative = '1' then
|
||||
v.fpscr(FPSCR_VXSQRT) := '1';
|
||||
qnan_result := '1';
|
||||
elsif r.b.mantissa(UNIT_BIT) = '0' then
|
||||
elsif r.b.denorm = '1' then
|
||||
v.state := RENORM_B;
|
||||
elsif r.b.exponent(0) = '0' then
|
||||
v.state := SQRT_1;
|
||||
@@ -1727,18 +1719,18 @@ begin
|
||||
end if;
|
||||
|
||||
when DO_FRE =>
|
||||
-- r.opsel_a = AIN_B
|
||||
opsel_a <= AIN_B;
|
||||
v.result_class := r.b.class;
|
||||
re_sel2 <= REXP2_B;
|
||||
re_set_result <= '1';
|
||||
if r.b.mantissa(UNIT_BIT) = '0' then
|
||||
if r.b.denorm = '1' then
|
||||
v.state := RENORM_B;
|
||||
else
|
||||
v.state := FRE_1;
|
||||
end if;
|
||||
|
||||
when DO_FRSQRTE =>
|
||||
-- r.opsel_a = AIN_B
|
||||
opsel_a <= AIN_B;
|
||||
v.result_class := r.b.class;
|
||||
re_sel2 <= REXP2_B;
|
||||
re_set_result <= '1';
|
||||
@@ -1747,7 +1739,7 @@ begin
|
||||
if r.b.negative = '1' then
|
||||
v.fpscr(FPSCR_VXSQRT) := '1';
|
||||
qnan_result := '1';
|
||||
elsif r.b.mantissa(UNIT_BIT) = '0' then
|
||||
elsif r.b.denorm = '1' then
|
||||
v.state := RENORM_B;
|
||||
elsif r.b.exponent(0) = '0' then
|
||||
v.state := RSQRT_1;
|
||||
@@ -1757,8 +1749,7 @@ begin
|
||||
|
||||
when DO_FMADD =>
|
||||
-- fmadd, fmsub, fnmadd, fnmsub
|
||||
-- r.opsel_a = AIN_A if A is denorm, else AIN_C if C is denorm,
|
||||
-- else AIN_B
|
||||
opsel_a <= AIN_B;
|
||||
v.result_class := r.a.class;
|
||||
-- put a.exp + c.exp into result_exp
|
||||
re_sel1 <= REXP1_A;
|
||||
@@ -1767,9 +1758,11 @@ begin
|
||||
-- put b.exp into shift
|
||||
rs_sel1 <= RSH1_B;
|
||||
-- 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;
|
||||
elsif r.c.mantissa(UNIT_BIT) = '0' then
|
||||
elsif r.c.denorm = '1' then
|
||||
opsel_a <= AIN_C;
|
||||
v.state := RENORM_C;
|
||||
elsif r.madd_cmp = '0' then
|
||||
-- addend is bigger, do multiply first
|
||||
@@ -1785,18 +1778,13 @@ begin
|
||||
when RENORM_A =>
|
||||
rs_norm <= '1';
|
||||
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 =>
|
||||
-- r.opsel_a = AIN_C for fmul/fmadd, AIN_B for fdiv
|
||||
set_a := '1';
|
||||
re_sel2 <= REXP2_NE;
|
||||
re_set_result <= '1';
|
||||
if r.is_multiply = '1' then
|
||||
opsel_a <= AIN_C;
|
||||
if r.c.mantissa(UNIT_BIT) = '1' then
|
||||
if r.is_addition = '0' or r.b.class = ZERO then
|
||||
v.first := '1';
|
||||
@@ -1806,13 +1794,13 @@ begin
|
||||
if new_exp + 1 >= r.b.exponent then
|
||||
v.madd_cmp := '1';
|
||||
end if;
|
||||
v.opsel_a := AIN_B;
|
||||
v.state := DO_FMADD;
|
||||
end if;
|
||||
else
|
||||
v.state := RENORM_C;
|
||||
end if;
|
||||
else
|
||||
opsel_a <= AIN_B;
|
||||
if r.b.mantissa(UNIT_BIT) = '1' then
|
||||
v.first := '1';
|
||||
v.state := DIV_2;
|
||||
@@ -1839,7 +1827,6 @@ begin
|
||||
re_sel2 <= REXP2_NE;
|
||||
re_set_result <= '1';
|
||||
end if;
|
||||
v.opsel_a := AIN_B;
|
||||
v.state := LOOKUP;
|
||||
|
||||
when RENORM_C =>
|
||||
@@ -1858,12 +1845,12 @@ begin
|
||||
if new_exp + 1 >= r.b.exponent then
|
||||
v.madd_cmp := '1';
|
||||
end if;
|
||||
v.opsel_a := AIN_B;
|
||||
v.state := DO_FMADD;
|
||||
end if;
|
||||
|
||||
when ADD_1 =>
|
||||
-- transferring B to R
|
||||
opsel_a <= AIN_B;
|
||||
re_sel2 <= REXP2_B;
|
||||
re_set_result <= '1';
|
||||
-- set shift to b.exp - a.exp
|
||||
@@ -1881,15 +1868,14 @@ begin
|
||||
v.x := s_nz;
|
||||
set_x := '1';
|
||||
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;
|
||||
|
||||
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_binv <= r.is_subtract;
|
||||
carry_in <= r.is_subtract and not r.x;
|
||||
@@ -1931,7 +1917,7 @@ begin
|
||||
end if;
|
||||
|
||||
when CMP_1 =>
|
||||
-- r.opsel_a = AIN_A
|
||||
opsel_a <= AIN_A;
|
||||
opsel_b <= BIN_R;
|
||||
opsel_binv <= '1';
|
||||
carry_in <= '1';
|
||||
@@ -2033,6 +2019,8 @@ begin
|
||||
|
||||
when FMADD_6 =>
|
||||
-- r.shift = UNIT_BIT (or 0, but only if r is now nonzero)
|
||||
set_r := '0';
|
||||
opsel_r <= RES_SHIFT;
|
||||
re_sel2 <= REXP2_NE;
|
||||
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
|
||||
@@ -2043,7 +2031,7 @@ begin
|
||||
else
|
||||
-- R is all zeroes but there are non-zero bits in S
|
||||
-- so shift them into R and set S to 0
|
||||
opsel_r <= RES_SHIFT;
|
||||
set_r := '1';
|
||||
re_set_result <= '1';
|
||||
set_s := '1';
|
||||
v.state := FINISH;
|
||||
@@ -2055,10 +2043,10 @@ begin
|
||||
end if;
|
||||
|
||||
when LOOKUP =>
|
||||
-- r.opsel_a = AIN_B
|
||||
-- wait one cycle for inverse_table[B] lookup
|
||||
-- if this is a division, compute exponent
|
||||
-- (see comment on RENORM_B2 above)
|
||||
opsel_a <= AIN_B;
|
||||
if r.use_a = '1' then
|
||||
re_sel2 <= REXP2_NE;
|
||||
re_set_result <= '1';
|
||||
@@ -2136,15 +2124,15 @@ begin
|
||||
end if;
|
||||
|
||||
when DIV_6 =>
|
||||
-- r.opsel_a = AIN_R
|
||||
-- test if remainder is 0 or >= B
|
||||
opsel_b <= BIN_RND;
|
||||
rbit_inc := '1';
|
||||
if pcmpb_lt = '1' then
|
||||
-- quotient is correct, set X if remainder non-zero
|
||||
set_r := '0';
|
||||
v.x := r.p(UNIT_BIT + 2) or px_nz;
|
||||
else
|
||||
-- quotient needs to be incremented by 1 in R-bit position
|
||||
rbit_inc := '1';
|
||||
opsel_b <= BIN_RND;
|
||||
v.x := not pcmpb_eq;
|
||||
end if;
|
||||
v.state := FINISH;
|
||||
@@ -2575,6 +2563,7 @@ begin
|
||||
|
||||
when ROUNDING_3 =>
|
||||
-- r.shift = clz(r.r) - 9
|
||||
opsel_r <= RES_SHIFT;
|
||||
mant_nz := r_hi_nz or (r_lo_nz and not r.single_prec);
|
||||
re_sel2 <= REXP2_NE;
|
||||
-- set shift to new_exp - min_exp (== -1022)
|
||||
@@ -2582,11 +2571,11 @@ begin
|
||||
rs_con2 <= RSCON2_MINEXP;
|
||||
rs_neg2 <= '1';
|
||||
if mant_nz = '0' then
|
||||
set_r := '0';
|
||||
v.result_class := ZERO;
|
||||
arith_done := '1';
|
||||
else
|
||||
-- Renormalize result after rounding
|
||||
opsel_r <= RES_SHIFT;
|
||||
re_set_result <= '1';
|
||||
v.denorm := exp_tiny;
|
||||
if new_exp < to_signed(-1022, EXP_BITS) then
|
||||
@@ -2605,6 +2594,7 @@ begin
|
||||
|
||||
when EXC_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
|
||||
when AIN_B =>
|
||||
re_sel2 <= REXP2_B;
|
||||
@@ -2620,7 +2610,7 @@ begin
|
||||
arith_done := '1';
|
||||
|
||||
when DO_IDIVMOD =>
|
||||
-- r.opsel_a = AIN_B
|
||||
opsel_a <= AIN_B;
|
||||
if r.b.class = ZERO then
|
||||
-- B is zero, signal overflow
|
||||
v.int_ovf := '1';
|
||||
@@ -2657,21 +2647,19 @@ begin
|
||||
-- add the X bit onto R to round up B
|
||||
carry_in <= r.x;
|
||||
-- prepare to do count-leading-zeroes on A
|
||||
v.opsel_a := AIN_A;
|
||||
v.state := IDIV_CLZA;
|
||||
when IDIV_CLZA =>
|
||||
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
|
||||
opsel_ainv <= '1';
|
||||
carry_in <= '1';
|
||||
end if;
|
||||
re_con2 <= RECON2_UNIT;
|
||||
re_set_result <= '1';
|
||||
v.opsel_a := AIN_C;
|
||||
v.state := IDIV_CLZA2;
|
||||
when IDIV_CLZA2 =>
|
||||
-- r.opsel_a = AIN_C
|
||||
opsel_a <= AIN_C;
|
||||
rs_norm <= '1';
|
||||
-- write the dividend back into A in case we negated it
|
||||
set_a_mant := '1';
|
||||
@@ -2720,6 +2708,12 @@ begin
|
||||
msel_inv <= '1';
|
||||
msel_2 <= MUL2_LUT;
|
||||
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
|
||||
-- rounding up of the mantissa caused overflow, meaning the
|
||||
-- normalized B is 2.0. Since this is outside the range
|
||||
@@ -2740,10 +2734,22 @@ begin
|
||||
msel_2 <= MUL2_P;
|
||||
set_y := r.first;
|
||||
pshift := '1';
|
||||
f_to_multiply.valid <= r.first;
|
||||
-- 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;
|
||||
end if;
|
||||
end if;
|
||||
if multiply_to_f.valid = '1' then
|
||||
v.first := '1';
|
||||
v.count := r.count + 1;
|
||||
v.state := IDIV_NR2;
|
||||
end if;
|
||||
when IDIV_NR2 =>
|
||||
@@ -2752,42 +2758,25 @@ begin
|
||||
msel_2 <= MUL2_P;
|
||||
f_to_multiply.valid <= r.first;
|
||||
pshift := '1';
|
||||
v.opsel_a := AIN_A;
|
||||
-- set shift to 64
|
||||
rs_con2 <= RSCON2_64;
|
||||
-- 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 r.first = '1' then
|
||||
v.count := r.count + 1;
|
||||
end if;
|
||||
if multiply_to_f.valid = '1' then
|
||||
v.first := '1';
|
||||
if r.count = "11" then
|
||||
v.state := IDIV_DODIV;
|
||||
else
|
||||
v.state := IDIV_NR1;
|
||||
end if;
|
||||
v.state := IDIV_NR1;
|
||||
end if;
|
||||
when IDIV_USE0_5 =>
|
||||
-- Get 0.5 into R; it turns out the generated
|
||||
-- QNaN mantissa is actually what we want
|
||||
opsel_r <= RES_MISC;
|
||||
misc_sel <= "001";
|
||||
v.opsel_a := AIN_A;
|
||||
-- Put the 0.5 which is in R into Y as the inverse estimate
|
||||
set_y := '1';
|
||||
msel_2 <= MUL2_R;
|
||||
-- set shift to 64
|
||||
rs_con2 <= RSCON2_64;
|
||||
v.state := IDIV_DODIV;
|
||||
when IDIV_DODIV =>
|
||||
-- r.opsel_a = AIN_A
|
||||
-- r.shift = 64
|
||||
-- inverse estimate is in P or in R; copy it to Y
|
||||
if r.b.mantissa(UNIT_BIT + 1) = '1' or
|
||||
(r.p(UNIT_BIT) = '0' and r.p(UNIT_BIT - 1) = '0') then
|
||||
msel_2 <= MUL2_R;
|
||||
else
|
||||
msel_2 <= MUL2_P;
|
||||
end if;
|
||||
set_y := '1';
|
||||
-- inverse estimate is in Y
|
||||
-- put A (dividend) into R
|
||||
opsel_a <= AIN_A;
|
||||
-- shift_res is 0 because r.shift = 64;
|
||||
-- put that into B, which now holds the quotient
|
||||
set_b_mant := '1';
|
||||
@@ -2809,7 +2798,6 @@ begin
|
||||
else
|
||||
-- handle top bit of quotient specially
|
||||
-- for this we need the divisor left-justified in B
|
||||
v.opsel_a := AIN_C;
|
||||
v.state := IDIV_EXT_TBH;
|
||||
end if;
|
||||
when IDIV_SH32 =>
|
||||
@@ -2864,7 +2852,8 @@ begin
|
||||
msel_2 <= MUL2_P;
|
||||
v.inc_quot := not pcmpc_lt and not r.divmod;
|
||||
if r.divmod = '0' then
|
||||
v.opsel_a := AIN_B;
|
||||
-- get B into R for IDIV_DIVADJ state
|
||||
opsel_a <= AIN_B;
|
||||
end if;
|
||||
-- set shift to UNIT_BIT (== 56)
|
||||
rs_con2 <= RSCON2_UNIT;
|
||||
@@ -2894,12 +2883,11 @@ begin
|
||||
-- r.shift = - b.exponent
|
||||
-- shift the quotient estimate right by b.exponent bits
|
||||
opsel_r <= RES_SHIFT;
|
||||
v.opsel_a := AIN_B;
|
||||
v.first := '1';
|
||||
v.state := IDIV_DIV7;
|
||||
when IDIV_DIV7 =>
|
||||
-- r.opsel_a = AIN_B
|
||||
-- add shifted quotient delta onto the total quotient
|
||||
opsel_a <= AIN_B;
|
||||
opsel_b <= BIN_R;
|
||||
v.first := '1';
|
||||
v.state := IDIV_DIV8;
|
||||
@@ -2923,12 +2911,11 @@ begin
|
||||
msel_1 <= MUL1_Y;
|
||||
msel_2 <= MUL2_P;
|
||||
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)
|
||||
rs_con2 <= RSCON2_UNIT;
|
||||
if r.divmod = '0' then
|
||||
-- get B into R for IDIV_DIVADJ state
|
||||
opsel_a <= AIN_B;
|
||||
v.state := IDIV_DIVADJ;
|
||||
elsif pcmpc_eq = '1' then
|
||||
v.state := IDIV_ZERO;
|
||||
@@ -2936,16 +2923,17 @@ begin
|
||||
v.state := IDIV_MODADJ;
|
||||
end if;
|
||||
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
|
||||
opsel_a <= AIN_C;
|
||||
rs_sel1 <= RSH1_B;
|
||||
rs_neg1 <= '1';
|
||||
rs_con2 <= RSCON2_63;
|
||||
v.opsel_a := AIN_A;
|
||||
v.state := 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
|
||||
opsel_a <= AIN_A;
|
||||
set_b_mant := '1';
|
||||
-- set shift to 64 - UNIT_BIT (== 8)
|
||||
rs_con2 <= RSCON2_64_UNIT;
|
||||
@@ -2966,13 +2954,13 @@ begin
|
||||
-- r.shift = 64 - B.exponent, so is at least 1
|
||||
opsel_r <= RES_SHIFT;
|
||||
-- top bit of A gets lost in the shift, so handle it specially
|
||||
v.opsel_a := AIN_B;
|
||||
-- set shift to 63
|
||||
rs_con2 <= RSCON2_63;
|
||||
v.state := 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
|
||||
opsel_a <= AIN_B;
|
||||
opsel_b <= BIN_R;
|
||||
opsel_ainv <= '1';
|
||||
carry_in <= '1';
|
||||
@@ -3004,15 +2992,14 @@ begin
|
||||
msel_2 <= MUL2_R;
|
||||
f_to_multiply.valid <= r.first;
|
||||
pshift := '1';
|
||||
v.opsel_a := AIN_B;
|
||||
opsel_r <= RES_MULT;
|
||||
if multiply_to_f.valid = '1' then
|
||||
v.first := '1';
|
||||
v.state := IDIV_EXTDIV3;
|
||||
end if;
|
||||
when IDIV_EXTDIV3 =>
|
||||
-- r.opsel_a = AIN_B
|
||||
-- delta quotient is in R; add it to B
|
||||
opsel_a <= AIN_B;
|
||||
opsel_b <= BIN_R;
|
||||
v.first := '1';
|
||||
v.state := IDIV_EXTDIV4;
|
||||
@@ -3040,12 +3027,11 @@ begin
|
||||
opsel_r <= RES_SHIFT;
|
||||
-- test LS 64b of remainder in P against divisor in C
|
||||
v.inc_quot := not pcmpc_lt;
|
||||
v.opsel_a := AIN_B;
|
||||
v.state := IDIV_EXTDIV6;
|
||||
when IDIV_EXTDIV6 =>
|
||||
-- r.opsel_a = AIN_B
|
||||
-- shifted remainder is in R, see if it is > 1
|
||||
-- and compute R = R * Y if so
|
||||
opsel_a <= AIN_B;
|
||||
msel_1 <= MUL1_Y;
|
||||
msel_2 <= MUL2_R;
|
||||
pshift := '1';
|
||||
@@ -3060,7 +3046,6 @@ begin
|
||||
-- result is in R/S
|
||||
opsel_r <= RES_SHIFT;
|
||||
if pcmpc_lt = '0' then
|
||||
v.opsel_a := AIN_C;
|
||||
v.state := IDIV_MODSUB;
|
||||
elsif r.result_sign = '0' then
|
||||
v.state := IDIV_DONE;
|
||||
@@ -3068,8 +3053,8 @@ begin
|
||||
v.state := IDIV_DIVADJ;
|
||||
end if;
|
||||
when IDIV_MODSUB =>
|
||||
-- r.opsel_a = AIN_C
|
||||
-- Subtract divisor from remainder
|
||||
opsel_a <= AIN_C;
|
||||
opsel_ainv <= '1';
|
||||
carry_in <= '1';
|
||||
opsel_b <= BIN_R;
|
||||
@@ -3079,7 +3064,7 @@ begin
|
||||
v.state := IDIV_DIVADJ;
|
||||
end if;
|
||||
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
|
||||
-- and also negate R if the answer is negative
|
||||
opsel_ainv <= r.result_sign;
|
||||
@@ -3274,7 +3259,7 @@ begin
|
||||
if (or (mask and r.r)) = '1' and set_x = '1' then
|
||||
v.x := '1';
|
||||
end if;
|
||||
case r.opsel_a is
|
||||
case opsel_a is
|
||||
when AIN_R =>
|
||||
in_a0 := r.r;
|
||||
when AIN_A =>
|
||||
@@ -3379,7 +3364,9 @@ begin
|
||||
end case;
|
||||
result <= misc;
|
||||
end case;
|
||||
v.r := result;
|
||||
if set_r = '1' then
|
||||
v.r := result;
|
||||
end if;
|
||||
if set_s = '1' then
|
||||
case opsel_s is
|
||||
when S_NEG =>
|
||||
|
||||
Reference in New Issue
Block a user