2#10010# => (FPU, OP_FPOP, FRA, FRB, NONE, FRT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '1', '0', RC, '0', '0'), -- fdivs
2#10100# => (FPU, OP_FPOP, FRA, FRB, NONE, FRT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '1', '0', RC, '0', '0'), -- fsubs
2#10101# => (FPU, OP_FPOP, FRA, FRB, NONE, FRT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '1', '0', RC, '0', '0'), -- fadds
+ 2#11000# => (FPU, OP_FPOP, NONE, FRB, NONE, FRT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '1', '0', RC, '0', '0'), -- fres
2#11001# => (FPU, OP_FPOP, FRA, NONE, FRC, FRT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '1', '0', RC, '0', '0'), -- fmuls
others => illegal_inst
);
2#0010# => (FPU, OP_FPOP, FRA, FRB, NONE, FRT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', RC, '0', '0'), -- fdiv
2#0100# => (FPU, OP_FPOP, FRA, FRB, NONE, FRT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', RC, '0', '0'), -- fsub
2#0101# => (FPU, OP_FPOP, FRA, FRB, NONE, FRT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', RC, '0', '0'), -- fadd
+ 2#1000# => (FPU, OP_FPOP, NONE, FRB, NONE, FRT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', RC, '0', '0'), -- fre
2#1001# => (FPU, OP_FPOP, FRA, NONE, FRC, FRT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', RC, '0', '0'), -- fmul
others => illegal_inst
);
DO_FCFID, DO_FCTI,
DO_FRSP, DO_FRI,
DO_FADD, DO_FMUL, DO_FDIV,
+ DO_FRE,
FRI_1,
ADD_SHIFT, ADD_2, ADD_3,
MULT_1,
LOOKUP,
DIV_2, DIV_3, DIV_4, DIV_5, DIV_6,
+ FRE_1,
INT_SHIFT, INT_ROUND, INT_ISHIFT,
INT_FINAL, INT_CHECK, INT_OFLOW,
FINISH, NORMALIZE,
v.state := DO_FDIV;
when "10100" | "10101" =>
v.state := DO_FADD;
+ when "11000" =>
+ v.state := DO_FRE;
when "11001" =>
v.is_multiply := '1';
v.state := DO_FMUL;
arith_done := '1';
end if;
+ when DO_FRE =>
+ opsel_a <= AIN_B;
+ v.result_class := r.b.class;
+ v.result_sign := r.b.negative;
+ v.fpscr(FPSCR_FR) := '0';
+ v.fpscr(FPSCR_FI) := '0';
+ if r.b.class = NAN and r.b.mantissa(53) = '0' then
+ v.fpscr(FPSCR_VXSNAN) := '1';
+ invalid := '1';
+ end if;
+ case r.b.class is
+ when FINITE =>
+ v.result_exp := - r.b.exponent;
+ if r.b.mantissa(54) = '0' then
+ v.state := RENORM_B;
+ else
+ v.state := FRE_1;
+ end if;
+ when NAN =>
+ -- result is B
+ arith_done := '1';
+ when INFINITY =>
+ v.result_class := ZERO;
+ arith_done := '1';
+ when ZERO =>
+ v.result_class := INFINITY;
+ zero_divide := '1';
+ arith_done := '1';
+ end case;
+
when RENORM_A =>
renormalize := '1';
v.state := RENORM_A2;
opsel_a <= AIN_B;
-- wait one cycle for inverse_table[B] lookup
v.first := '1';
- v.state := DIV_2;
+ if r.insn(4) = '0' then
+ v.state := DIV_2;
+ else
+ v.state := FRE_1;
+ end if;
when DIV_2 =>
-- compute Y = inverse_table[B] (when count=0); P = 2 - B * Y
end if;
v.state := FINISH;
+ when FRE_1 =>
+ opsel_r <= RES_MISC;
+ misc_sel <= "0111";
+ v.shift := to_signed(1, EXP_BITS);
+ v.state := NORMALIZE;
+
when INT_SHIFT =>
opsel_r <= RES_SHIFT;
set_x := '1';
when "0110" =>
-- fmrgew result
misc := r.a.mantissa(63 downto 32) & r.b.mantissa(63 downto 32);
+ when "0111" =>
+ misc := 10x"000" & inverse_est & 35x"000000000";
when "1000" =>
-- max positive result for fctiw[z]
misc := x"000000007fffffff";
return trapit(0, test17);
}
+struct recipvals {
+ unsigned long val;
+ unsigned long inv;
+} recipvals[] = {
+ { 0x0000000000000000, 0x7ff0000000000000 },
+ { 0xfff0000000000000, 0x8000000000000000 },
+ { 0x3ff0000000000000, 0x3feff00400000000 },
+ { 0xbff0000000000000, 0xbfeff00400000000 },
+ { 0x4008000000000000, 0x3fd54e3800000000 },
+ { 0xc03ffffffdffffbf, 0xbfa0040000000000 },
+};
+
+int test18(long arg)
+{
+ long i;
+ unsigned long result;
+ struct recipvals *vp = recipvals;
+
+ set_fpscr(FPS_RN_NEAR);
+ for (i = 0; i < sizeof(recipvals) / sizeof(recipvals[0]); ++i, ++vp) {
+ asm("lfd 6,0(%0); fre 7,6; stfd 7,0(%1)"
+ : : "b" (&vp->val), "b" (&result) : "memory");
+ if (result != vp->inv) {
+ print_hex(i, 2, " ");
+ print_hex(result, 16, " ");
+ return i + 1;
+ }
+ }
+ return 0;
+}
+
+int fpu_test_18(void)
+{
+ enable_fp();
+ return trapit(0, test18);
+}
+
int fail = 0;
void do_test(int num, int (*test)(void))
do_test(15, fpu_test_15);
do_test(16, fpu_test_16);
do_test(17, fpu_test_17);
+ do_test(18, fpu_test_18);
return fail;
}