FPU: Implement remaining FPSCR-related instructions
authorPaul Mackerras <paulus@ozlabs.org>
Sat, 29 Aug 2020 10:34:55 +0000 (20:34 +1000)
committerPaul Mackerras <paulus@ozlabs.org>
Thu, 3 Sep 2020 07:44:26 +0000 (17:44 +1000)
This implements mcrfs, mtfsfi, mtfsb0/1, mffscr, mffscrn, mffscrni and
mffsl.

Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
decode1.vhdl
fpu.vhdl
insn_helpers.vhdl

index afd37ef69e0a77cfdc492cb40e1380c1268f7104..343c0c32f7245c702b47604761c54f6682c130c8 100644 (file)
@@ -422,6 +422,10 @@ 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#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
+        2#011000100#  => (FPU,   OP_FPOP,       NONE, NONE, NONE, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', RC,   '0', '0'), --  4/6=mtfsfi
         2#011110010#  => (FPU,   OP_FPOP_I,     NONE, FRB,  NONE, FRT,  '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', RC,   '0', '0'), -- 18/7=mffs family
         2#011110110#  => (FPU,   OP_FPOP_I,     NONE, FRB,  NONE, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', RC,   '0', '0'), -- 22/7=mtfsf
         others => illegal_inst
index b05ec9d684b1e8a306de49a000b19ca055541572..047bf2d0cecac030dc199193509fba5dc27acb5c 100644 (file)
--- a/fpu.vhdl
+++ b/fpu.vhdl
@@ -26,7 +26,7 @@ end entity fpu;
 architecture behaviour of fpu is
 
     type state_t is (IDLE,
-                     DO_MFFS, DO_MTFSF);
+                     DO_MCRFS, DO_MTFSB, DO_MTFSFI, DO_MFFS, DO_MTFSF);
 
     type reg_type is record
         state        : state_t;
@@ -42,6 +42,7 @@ architecture behaviour of fpu is
         single_prec  : std_ulogic;
         fpscr        : std_ulogic_vector(31 downto 0);
         b            : std_ulogic_vector(63 downto 0);
+        r            : std_ulogic_vector(63 downto 0);
         writing_back : std_ulogic;
         cr_result    : std_ulogic_vector(3 downto 0);
         cr_mask      : std_ulogic_vector(7 downto 0);
@@ -77,13 +78,14 @@ begin
     w_out.write_enable <= r.writing_back;
     w_out.write_reg <= r.dest_fpr;
     w_out.write_data <= fp_result;
-    w_out.write_cr_enable <= r.instr_done and r.rc;
+    w_out.write_cr_enable <= r.instr_done and (r.rc or r.is_cmp);
     w_out.write_cr_mask <= r.cr_mask;
     w_out.write_cr_data <= r.cr_result & r.cr_result & r.cr_result & r.cr_result &
                            r.cr_result & r.cr_result & r.cr_result & r.cr_result;
 
     fpu_1: process(all)
         variable v           : reg_type;
+        variable fpscr_mask  : std_ulogic_vector(31 downto 0);
         variable illegal     : std_ulogic;
         variable j, k        : integer;
         variable flm         : std_ulogic_vector(7 downto 0);
@@ -101,17 +103,30 @@ begin
             v.single_prec := e_in.single;
             v.rc := e_in.rc;
             v.is_cmp := e_in.out_cr;
-            v.cr_mask := num_to_fxm(1);
+            if e_in.out_cr = '0' then
+                v.cr_mask := num_to_fxm(1);
+            else
+                v.cr_mask := num_to_fxm(to_integer(unsigned(insn_bf(e_in.insn))));
+            end if;
             v.b := e_in.frb;
         end if;
 
         v.writing_back := '0';
         v.instr_done := '0';
+        fpscr_mask := (others => '1');
 
         case r.state is
             when IDLE =>
                 if e_in.valid = '1' then
                     case e_in.insn(5 downto 1) is
+                        when "00000" =>
+                            v.state := DO_MCRFS;
+                        when "00110" =>
+                            if e_in.insn(8) = '0' then
+                                v.state := DO_MTFSB;
+                            else
+                                v.state := DO_MTFSFI;
+                            end if;
                         when "00111" =>
                             if e_in.insn(8) = '0' then
                                 v.state := DO_MFFS;
@@ -123,11 +138,67 @@ begin
                     end case;
                 end if;
 
+            when DO_MCRFS =>
+                j := to_integer(unsigned(insn_bfa(r.insn)));
+                for i in 0 to 7 loop
+                    if i = j then
+                        k := (7 - i) * 4;
+                        v.cr_result := r.fpscr(k + 3 downto k);
+                        fpscr_mask(k + 3 downto k) := "0000";
+                    end if;
+                end loop;
+                v.fpscr := r.fpscr and (fpscr_mask or x"6007F8FF");
+                v.instr_done := '1';
+                v.state := IDLE;
+
+            when DO_MTFSB =>
+                -- mtfsb{0,1}
+                j := to_integer(unsigned(insn_bt(r.insn)));
+                for i in 0 to 31 loop
+                    if i = j then
+                        v.fpscr(31 - i) := r.insn(6);
+                    end if;
+                end loop;
+                v.instr_done := '1';
+                v.state := IDLE;
+
+            when DO_MTFSFI =>
+                -- mtfsfi
+                j := to_integer(unsigned(insn_bf(r.insn)));
+                if r.insn(16) = '0' then
+                    for i in 0 to 7 loop
+                        if i = j then
+                            k := (7 - i) * 4;
+                            v.fpscr(k + 3 downto k) := insn_u(r.insn);
+                        end if;
+                    end loop;
+                end if;
+                v.instr_done := '1';
+                v.state := IDLE;
+
             when DO_MFFS =>
                 v.writing_back := '1';
                 case r.insn(20 downto 16) is
                     when "00000" =>
                         -- mffs
+                    when "00001" =>
+                        -- mffsce
+                        v.fpscr(FPSCR_VE downto FPSCR_XE) := "00000";
+                    when "10100" | "10101" =>
+                        -- mffscdrn[i] (but we don't implement DRN)
+                        fpscr_mask := x"000000FF";
+                    when "10110" =>
+                        -- mffscrn
+                        fpscr_mask := x"000000FF";
+                        v.fpscr(FPSCR_RN+1 downto FPSCR_RN) :=
+                            r.b(FPSCR_RN+1 downto FPSCR_RN);
+                    when "10111" =>
+                        -- mffscrni
+                        fpscr_mask := x"000000FF";
+                        v.fpscr(FPSCR_RN+1 downto FPSCR_RN) := r.insn(12 downto 11);
+                    when "11000" =>
+                        -- mffsl
+                        fpscr_mask := x"0007F0FF";
                     when others =>
                         illegal := '1';
                 end case;
@@ -155,7 +226,9 @@ begin
 
         -- Data path.
         -- Just enough to read FPSCR for now.
-        fp_result <= x"00000000" & r.fpscr;
+        v.r := x"00000000" & (r.fpscr and fpscr_mask);
+
+        fp_result <= r.r;
 
         v.fpscr(FPSCR_VX) := (or (v.fpscr(FPSCR_VXSNAN downto FPSCR_VXVC))) or
                              (or (v.fpscr(FPSCR_VXSOFT downto FPSCR_VXCVI)));
index be3892a2ce7a50d36f839939ff5e5b69d09a0f3a..519aa76179f17578daebde5cae5af123022d5189 100644 (file)
@@ -41,6 +41,7 @@ package insn_helpers is
     function insn_fra (insn_in : std_ulogic_vector) return std_ulogic_vector;
     function insn_frb (insn_in : std_ulogic_vector) return std_ulogic_vector;
     function insn_frc (insn_in : std_ulogic_vector) return std_ulogic_vector;
+    function insn_u (insn_in : std_ulogic_vector) return std_ulogic_vector;
 end package insn_helpers;
 
 package body insn_helpers is
@@ -238,4 +239,9 @@ package body insn_helpers is
     begin
         return insn_in(10 downto 6);
     end;
+
+    function insn_u(insn_in : std_ulogic_vector) return std_ulogic_vector is
+    begin
+        return insn_in(15 downto 12);
+    end;
 end package body insn_helpers;