FPU: Implement fcmpu and fcmpo
authorPaul Mackerras <paulus@ozlabs.org>
Thu, 30 Jul 2020 00:00:25 +0000 (10:00 +1000)
committerPaul Mackerras <paulus@ozlabs.org>
Thu, 3 Sep 2020 07:45:22 +0000 (17:45 +1000)
Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
decode1.vhdl
fpu.vhdl

index 09aaf9196a011edf2f6730369215408541f9f0b4..ba9964e0a34621c2efb05f3dee1301ad81281b0f 100644 (file)
@@ -436,6 +436,8 @@ architecture behaviour of decode1 is
     constant decode_op_63l_array : op_63_subop_array_0_t := (
         --                unit   internal       in1   in2   in3   out   CR   CR   inv  inv  cry   cry  ldst  BR   sgn  upd  rsrv 32b  sgn  rc    lk   sgl
         --                             op                               in   out   A   out  in    out  len        ext                                pipe
+        2#000000000#  => (FPU,   OP_FPOP,       FRA,  FRB,  NONE, NONE, '0', '1', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0'), --  0/0=fcmpu
+        2#000000001#  => (FPU,   OP_FPOP,       FRA,  FRB,  NONE, NONE, '0', '1', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0'), --  1/0=fcmpo
         2#000000010#  => (FPU,   OP_FPOP,       NONE, NONE, NONE, NONE, '0', '1', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0'), --  2/0=mcrfs
         2#011000001#  => (FPU,   OP_FPOP,       NONE, NONE, NONE, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', RC,   '0', '0'), --  1/6=mtfsb1
         2#011000010#  => (FPU,   OP_FPOP,       NONE, NONE, NONE, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', RC,   '0', '0'), --  2/6=mtfsb0
index 59e6f5d829782ec61f13977a36a18ff85b9cc691..c726be37d382ae436252fd34260142b6ed4186e1 100644 (file)
--- a/fpu.vhdl
+++ b/fpu.vhdl
@@ -37,7 +37,7 @@ architecture behaviour of fpu is
 
     type state_t is (IDLE,
                      DO_MCRFS, DO_MTFSB, DO_MTFSFI, DO_MFFS, DO_MTFSF,
-                     DO_FMR, DO_FMRG,
+                     DO_FMR, DO_FMRG, DO_FCMP,
                      DO_FCFID, DO_FCTI,
                      DO_FRSP, DO_FRI,
                      DO_FADD, DO_FMUL, DO_FDIV,
@@ -45,6 +45,7 @@ architecture behaviour of fpu is
                      DO_FSEL,
                      FRI_1,
                      ADD_SHIFT, ADD_2, ADD_3,
+                     CMP_1, CMP_2,
                      MULT_1,
                      LOOKUP,
                      DIV_2, DIV_3, DIV_4, DIV_5, DIV_6,
@@ -603,7 +604,11 @@ begin
                 if e_in.valid = '1' then
                     case e_in.insn(5 downto 1) is
                         when "00000" =>
-                            v.state := DO_MCRFS;
+                            if e_in.insn(7) = '1' then
+                                v.state := DO_MCRFS;
+                            else
+                                v.state := DO_FCMP;
+                            end if;
                         when "00110" =>
                             if e_in.insn(10) = '0' then
                                 if e_in.insn(8) = '0' then
@@ -669,6 +674,62 @@ begin
                 v.instr_done := '1';
                 v.state := IDLE;
 
+            when DO_FCMP =>
+                -- fcmp[uo]
+                v.instr_done := '1';
+                v.state := IDLE;
+                update_fx := '1';
+                opsel_a <= AIN_B;
+                opsel_r <= RES_SUM;
+                v.result_exp := r.b.exponent;
+                if (r.a.class = NAN and r.a.mantissa(53) = '0') or
+                    (r.b.class = NAN and r.b.mantissa(53) = '0') then
+                    -- Signalling NAN
+                    v.fpscr(FPSCR_VXSNAN) := '1';
+                    if r.insn(6) = '1' and r.fpscr(FPSCR_VE) = '0' then
+                        v.fpscr(FPSCR_VXVC) := '1';
+                    end if;
+                    invalid := '1';
+                    v.cr_result := "0001";          -- unordered
+                elsif r.a.class = NAN or r.b.class = NAN then
+                    if r.insn(6) = '1' then
+                        -- fcmpo
+                        v.fpscr(FPSCR_VXVC) := '1';
+                        invalid := '1';
+                    end if;
+                    v.cr_result := "0001";          -- unordered
+                elsif r.a.class = ZERO and r.b.class = ZERO then
+                    v.cr_result := "0010";          -- equal
+                elsif r.a.negative /= r.b.negative then
+                    v.cr_result := r.a.negative & r.b.negative & "00";
+                elsif r.a.class = ZERO then
+                    -- A and B are the same sign from here down
+                    v.cr_result := not r.b.negative & r.b.negative & "00";
+                elsif r.a.class = INFINITY then
+                    if r.b.class = INFINITY then
+                        v.cr_result := "0010";
+                    else
+                        v.cr_result := r.a.negative & not r.a.negative & "00";
+                    end if;
+                elsif r.b.class = ZERO then
+                    -- A is finite from here down
+                    v.cr_result := r.a.negative & not r.a.negative & "00";
+                elsif r.b.class = INFINITY then
+                    v.cr_result := not r.b.negative & r.b.negative & "00";
+                elsif r.exp_cmp = '1' then
+                    -- A and B are both finite from here down
+                    v.cr_result := r.a.negative & not r.a.negative & "00";
+                elsif r.a.exponent /= r.b.exponent then
+                    -- A exponent is smaller than B
+                    v.cr_result := not r.a.negative & r.a.negative & "00";
+                else
+                    -- Prepare to subtract mantissas, put B in R
+                    v.cr_result := "0000";
+                    v.instr_done := '0';
+                    v.state := CMP_1;
+                end if;
+                v.fpscr(FPSCR_FL downto FPSCR_FU) := v.cr_result;
+
             when DO_MTFSB =>
                 -- mtfsb{0,1}
                 j := to_integer(unsigned(insn_bt(r.insn)));
@@ -1193,6 +1254,26 @@ begin
                     v.state := NORMALIZE;
                 end if;
 
+            when CMP_1 =>
+                opsel_a <= AIN_A;
+                opsel_b <= BIN_R;
+                opsel_binv <= '1';
+                carry_in <= '1';
+                v.state := CMP_2;
+
+            when CMP_2 =>
+                if r.r(63) = '1' then
+                    -- A is smaller in magnitude
+                    v.cr_result := not r.a.negative & r.a.negative & "00";
+                elsif (r_hi_nz or r_lo_nz) = '0' then
+                    v.cr_result := "0010";
+                else
+                    v.cr_result := r.a.negative & not r.a.negative & "00";
+                end if;
+                v.fpscr(FPSCR_FL downto FPSCR_FU) := v.cr_result;
+                v.instr_done := '1';
+                v.state := IDLE;
+
             when MULT_1 =>
                 f_to_multiply.valid <= r.first;
                 opsel_r <= RES_MULT;