Add Tercel PHY reset synchronization
[microwatt.git] / fpu.vhdl
index 023dbf270c946a9776482903e80490f74a8fae58..93fa9d68880c996be4aefcdb961bd9430284222f 100644 (file)
--- a/fpu.vhdl
+++ b/fpu.vhdl
@@ -73,8 +73,11 @@ architecture behaviour of fpu is
         busy         : std_ulogic;
         instr_done   : std_ulogic;
         do_intr      : std_ulogic;
+        illegal      : std_ulogic;
         op           : insn_type_t;
         insn         : std_ulogic_vector(31 downto 0);
+        nia          : std_ulogic_vector(63 downto 0);
+        instr_tag    : instr_tag_t;
         dest_fpr     : gspr_index_t;
         fe_mode      : std_ulogic;
         rc           : std_ulogic;
@@ -157,7 +160,7 @@ architecture behaviour of fpu is
 
     constant BIN_ZERO : std_ulogic_vector(1 downto 0) := "00";
     constant BIN_R    : std_ulogic_vector(1 downto 0) := "01";
-    constant BIN_MASK : std_ulogic_vector(1 downto 0) := "10";
+    constant BIN_RND  : std_ulogic_vector(1 downto 0) := "10";
     constant BIN_PS6  : std_ulogic_vector(1 downto 0) := "11";
 
     constant RES_SUM   : std_ulogic_vector(1 downto 0) := "00";
@@ -571,9 +574,9 @@ begin
 
     e_out.busy <= r.busy;
     e_out.exception <= r.fpscr(FPSCR_FEX);
-    e_out.interrupt <= r.do_intr;
 
     w_out.valid <= r.instr_done and not r.do_intr;
+    w_out.instr_tag <= r.instr_tag;
     w_out.write_enable <= r.writing_back;
     w_out.write_reg <= r.dest_fpr;
     w_out.write_data <= fp_result;
@@ -581,6 +584,10 @@ begin
     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;
+    w_out.interrupt <= r.do_intr;
+    w_out.intr_vec <= 16#700#;
+    w_out.srr0 <= r.nia;
+    w_out.srr1 <= (47-44 => r.illegal, 47-43 => not r.illegal, others => '0');
 
     fpu_1: process(all)
         variable v           : reg_type;
@@ -632,6 +639,7 @@ begin
         variable mulexp      : signed(EXP_BITS-1 downto 0);
         variable maddend     : std_ulogic_vector(127 downto 0);
         variable sum         : std_ulogic_vector(63 downto 0);
+        variable round_inc   : std_ulogic_vector(63 downto 0);
     begin
         v := r;
         illegal := '0';
@@ -641,7 +649,9 @@ begin
         -- capture incoming instruction
         if e_in.valid = '1' then
             v.insn := e_in.insn;
+            v.nia := e_in.nia;
             v.op := e_in.op;
+            v.instr_tag := e_in.itag;
             v.fe_mode := or (e_in.fe_mode);
             v.dest_fpr := e_in.frt;
             v.single_prec := e_in.single;
@@ -1117,7 +1127,6 @@ begin
                     elsif r.b.exponent > to_signed(127, EXP_BITS) then
                         v.state := ROUND_OFLOW;
                     else
-                        v.shift := to_signed(-2, EXP_BITS);
                         v.state := ROUNDING;
                     end if;
                 else
@@ -1619,7 +1628,6 @@ begin
                     -- sum overflowed, shift right
                     opsel_r <= RES_SHIFT;
                     set_x := '1';
-                    v.shift := to_signed(-2, EXP_BITS);
                     if exp_huge = '1' then
                         v.state := ROUND_OFLOW;
                     else
@@ -1627,7 +1635,6 @@ begin
                     end if;
                 elsif r.r(54) = '1' then
                     set_x := '1';
-                    v.shift := to_signed(-2, EXP_BITS);
                     v.state := ROUNDING;
                 elsif (r_hi_nz or r_lo_nz or r.r(1) or r.r(0)) = '0' then
                     -- r.x must be zero at this point
@@ -1704,22 +1711,19 @@ begin
                 opsel_r <= RES_MULT;
                 opsel_s <= S_MULT;
                 set_s := '1';
-                v.shift := to_signed(56, EXP_BITS);
                 if multiply_to_f.valid = '1' then
-                    if multiply_to_f.result(121) = '1' then
-                        v.state := FMADD_5;
-                    else
-                        v.state := FMADD_6;
-                    end if;
+                    v.state := FMADD_5;
                 end if;
 
             when FMADD_5 =>
-                -- negate R:S:X
-                v.result_sign := not r.result_sign;
-                opsel_ainv <= '1';
-                carry_in <= not (s_nz or r.x);
-                opsel_s <= S_NEG;
-                set_s := '1';
+                -- negate R:S:X if negative
+                if r.r(63) = '1' then
+                    v.result_sign := not r.result_sign;
+                    opsel_ainv <= '1';
+                    carry_in <= not (s_nz or r.x);
+                    opsel_s <= S_NEG;
+                    set_s := '1';
+                end if;
                 v.shift := to_signed(56, EXP_BITS);
                 v.state := FMADD_6;
 
@@ -2088,7 +2092,6 @@ begin
                 -- r.shift = b.exponent - 52
                 opsel_r <= RES_SHIFT;
                 set_x := '1';
-                v.shift := to_signed(-2, EXP_BITS);
                 v.state := ROUNDING;
 
             when FINISH =>
@@ -2106,7 +2109,6 @@ begin
                     elsif exp_huge = '1' then
                         v.state := ROUND_OFLOW;
                     else
-                        v.shift := to_signed(-2, EXP_BITS);
                         v.state := ROUNDING;
                     end if;
                 end if;
@@ -2122,7 +2124,6 @@ begin
                 elsif exp_huge = '1' then
                     v.state := ROUND_OFLOW;
                 else
-                    v.shift := to_signed(-2, EXP_BITS);
                     v.state := ROUNDING;
                 end if;
 
@@ -2134,7 +2135,6 @@ begin
                     -- have to denormalize before rounding
                     opsel_r <= RES_SHIFT;
                     set_x := '1';
-                    v.shift := to_signed(-2, EXP_BITS);
                     v.state := ROUNDING;
                 else
                     -- enabled underflow exception case
@@ -2145,7 +2145,6 @@ begin
                         renormalize := '1';
                         v.state := NORMALIZE;
                     else
-                        v.shift := to_signed(-2, EXP_BITS);
                         v.state := ROUNDING;
                     end if;
                 end if;
@@ -2172,7 +2171,6 @@ begin
                 else
                     -- enabled overflow exception
                     v.result_exp := r.result_exp - bias_exp;
-                    v.shift := to_signed(-2, EXP_BITS);
                     v.state := ROUNDING;
                 end if;
 
@@ -2181,9 +2179,8 @@ begin
                 round := fp_rounding(r.r, r.x, r.single_prec, r.round_mode, r.result_sign);
                 v.fpscr(FPSCR_FR downto FPSCR_FI) := round;
                 if round(1) = '1' then
-                    -- set mask to increment the LSB for the precision
-                    opsel_b <= BIN_MASK;
-                    carry_in <= '1';
+                    -- increment the LSB for the precision
+                    opsel_b <= BIN_RND;
                     v.shift := to_signed(-1, EXP_BITS);
                     v.state := ROUNDING_2;
                 else
@@ -2405,8 +2402,9 @@ begin
                 in_b0 := (others => '0');
             when BIN_R =>
                 in_b0 := r.r;
-            when BIN_MASK =>
-                in_b0 := mask;
+            when BIN_RND =>
+                round_inc := (31 => r.single_prec, 2 => not r.single_prec, others => '0');
+                in_b0 := round_inc;
             when others =>
                 -- BIN_PS6, 6 LSBs of P/4 sign-extended to 64
                 in_b0 := std_ulogic_vector(resize(signed(r.p(7 downto 2)), 64));
@@ -2423,7 +2421,10 @@ begin
         end if;
         sum := std_ulogic_vector(unsigned(in_a) + unsigned(in_b) + carry_in);
         if opsel_mask = '1' then
-            sum := sum and not mask;
+            sum(1 downto 0) := "00";
+            if r.single_prec = '1' then
+                sum(30 downto 2) := (others => '0');
+            end if;
         end if;
         case opsel_r is
             when RES_SUM =>
@@ -2548,9 +2549,10 @@ begin
             v.cr_result := v.fpscr(FPSCR_FX downto FPSCR_OX);
         end if;
 
+        v.illegal := illegal;
         if illegal = '1' then
             v.instr_done := '0';
-            v.do_intr := '0';
+            v.do_intr := '1';
             v.writing_back := '0';
             v.busy := '0';
             v.state := IDLE;
@@ -2562,7 +2564,6 @@ begin
         end if;
 
         rin <= v;
-        e_out.illegal <= illegal;
     end process;
 
 end architecture behaviour;