From ba2add029af5aea4bc5d0240a7fcb17351db74a7 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Tue, 5 Mar 2024 16:46:08 +1100 Subject: [PATCH] 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 --- fpu.vhdl | 239 ++++++++++++++++++++++++++----------------------------- 1 file changed, 113 insertions(+), 126 deletions(-) diff --git a/fpu.vhdl b/fpu.vhdl index a309705..3914a97 100644 --- a/fpu.vhdl +++ b/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 =>