Use FPU for division instructions if we have an FPU
authorPaul Mackerras <paulus@ozlabs.org>
Mon, 9 May 2022 09:18:42 +0000 (19:18 +1000)
committerPaul Mackerras <paulus@ozlabs.org>
Fri, 22 Jul 2022 12:20:28 +0000 (22:20 +1000)
- Arrange for XER to be written for OE=1 forms
- Arrange for condition codes to be set for RC=1 forms
  (including correct handling for 32-bit mode)
- Don't instantiate the divider if we have an FPU.

Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
common.vhdl
decode1.vhdl
execute1.vhdl
fpu.vhdl
tests/fpu/fpu.c
writeback.vhdl

index aa7b8308acc0ee51d36e1b8b277749801b40a299..f846fb420f865af2c712f31d943c20c78e553f24 100644 (file)
@@ -640,7 +640,10 @@ package common is
         frc       : std_ulogic_vector(63 downto 0);
         frt       : gspr_index_t;
         rc        : std_ulogic;
+        m32b      : std_ulogic;
         out_cr    : std_ulogic;
+        oe        : std_ulogic;
+        xerc      : xer_common_t;
         stall     : std_ulogic;
     end record;
     constant Execute1ToFPUInit : Execute1ToFPUType := (valid => '0', op => OP_ILLEGAL, nia => (others => '0'),
@@ -649,6 +652,7 @@ package common is
                                                        fra => (others => '0'), frb => (others => '0'),
                                                        frc => (others => '0'), frt => (others => '0'),
                                                        single => '0', is_signed => '0', out_cr => '0',
+                                                       m32b => '0', oe => '0', xerc => xerc_init,
                                                        stall => '0');
 
     type FPUToExecute1Type is record
@@ -668,6 +672,8 @@ package common is
         write_cr_enable : std_ulogic;
         write_cr_mask   : std_ulogic_vector(7 downto 0);
         write_cr_data   : std_ulogic_vector(31 downto 0);
+        write_xerc      : std_ulogic;
+        xerc            : xer_common_t;
         intr_vec        : intr_vector_t;
         srr0            : std_ulogic_vector(63 downto 0);
         srr1            : std_ulogic_vector(15 downto 0);
@@ -677,6 +683,7 @@ package common is
          write_enable => '0', write_reg => (others => '0'),
          write_cr_enable => '0', write_cr_mask => (others => '0'),
          write_cr_data => (others => '0'),
+         write_xerc => '0', xerc => xerc_init,
          intr_vec => 0, srr1 => (others => '0'),
          others => (others => '0'));
 
index 5bc023b14340b1d535aed2f2624fec0724025c7c..2e2a8e351fdb80a7eefdc95171561096760773ba 100644 (file)
@@ -35,6 +35,18 @@ architecture behaviour of decode1 is
     constant illegal_inst : decode_rom_t :=
         (NONE, NONE, OP_ILLEGAL,   NONE,       NONE,        NONE, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE);
 
+    -- If we have an FPU, then it is used for integer divisions,
+    -- otherwise a dedicated divider in the ALU is used.
+    function divider_unit(hf : boolean) return unit_t is
+    begin
+        if hf then
+            return FPU;
+        else
+            return ALU;
+        end if;
+    end;
+    constant DVU : unit_t := divider_unit(HAS_FPU);
+
     type reg_internal_t is record
         override : std_ulogic;
         override_decode: decode_rom_t;
@@ -225,22 +237,22 @@ architecture behaviour of decode1 is
         2#0100010110#  =>       (ALU,  NONE, OP_DCBT,      NONE,       NONE,        NONE, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE), -- dcbt
         2#0011110110#  =>       (ALU,  NONE, OP_DCBTST,    NONE,       NONE,        NONE, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE), -- dcbtst
         2#1111110110#  =>       (LDST, NONE, OP_DCBZ,      RA_OR_ZERO, RB,          NONE, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE), -- dcbz
-        2#0110001001#  =>       (ALU,  NONE, OP_DIVE,      RA,         RB,          NONE, RT,   '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', RC,   '0', '0', NONE), -- divdeu
-        2#1110001001#  =>       (ALU,  NONE, OP_DIVE,      RA,         RB,          NONE, RT,   '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', RC,   '0', '0', NONE), -- divdeuo
-        2#0110001011#  =>       (ALU,  NONE, OP_DIVE,      RA,         RB,          NONE, RT,   '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '1', '0', RC,   '0', '0', NONE), -- divweu
-        2#1110001011#  =>       (ALU,  NONE, OP_DIVE,      RA,         RB,          NONE, RT,   '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '1', '0', RC,   '0', '0', NONE), -- divweuo
-        2#0110101001#  =>       (ALU,  NONE, OP_DIVE,      RA,         RB,          NONE, RT,   '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '1', RC,   '0', '0', NONE), -- divde
-        2#1110101001#  =>       (ALU,  NONE, OP_DIVE,      RA,         RB,          NONE, RT,   '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '1', RC,   '0', '0', NONE), -- divdeo
-        2#0110101011#  =>       (ALU,  NONE, OP_DIVE,      RA,         RB,          NONE, RT,   '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '1', '1', RC,   '0', '0', NONE), -- divwe
-        2#1110101011#  =>       (ALU,  NONE, OP_DIVE,      RA,         RB,          NONE, RT,   '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '1', '1', RC,   '0', '0', NONE), -- divweo
-        2#0111001001#  =>       (ALU,  NONE, OP_DIV,       RA,         RB,          NONE, RT,   '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', RC,   '0', '0', NONE), -- divdu
-        2#1111001001#  =>       (ALU,  NONE, OP_DIV,       RA,         RB,          NONE, RT,   '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', RC,   '0', '0', NONE), -- divduo
-        2#0111001011#  =>       (ALU,  NONE, OP_DIV,       RA,         RB,          NONE, RT,   '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '1', '0', RC,   '0', '0', NONE), -- divwu
-        2#1111001011#  =>       (ALU,  NONE, OP_DIV,       RA,         RB,          NONE, RT,   '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '1', '0', RC,   '0', '0', NONE), -- divwuo
-        2#0111101001#  =>       (ALU,  NONE, OP_DIV,       RA,         RB,          NONE, RT,   '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '1', RC,   '0', '0', NONE), -- divd
-        2#1111101001#  =>       (ALU,  NONE, OP_DIV,       RA,         RB,          NONE, RT,   '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '1', RC,   '0', '0', NONE), -- divdo
-        2#0111101011#  =>       (ALU,  NONE, OP_DIV,       RA,         RB,          NONE, RT,   '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '1', '1', RC,   '0', '0', NONE), -- divw
-        2#1111101011#  =>       (ALU,  NONE, OP_DIV,       RA,         RB,          NONE, RT,   '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '1', '1', RC,   '0', '0', NONE), -- divwo
+        2#0110001001#  =>       (DVU,  NONE, OP_DIVE,      RA,         RB,          NONE, RT,   '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', RC,   '0', '0', NONE), -- divdeu
+        2#1110001001#  =>       (DVU,  NONE, OP_DIVE,      RA,         RB,          NONE, RT,   '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', RC,   '0', '0', NONE), -- divdeuo
+        2#0110001011#  =>       (DVU,  NONE, OP_DIVE,      RA,         RB,          NONE, RT,   '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '1', '0', RC,   '0', '0', NONE), -- divweu
+        2#1110001011#  =>       (DVU,  NONE, OP_DIVE,      RA,         RB,          NONE, RT,   '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '1', '0', RC,   '0', '0', NONE), -- divweuo
+        2#0110101001#  =>       (DVU,  NONE, OP_DIVE,      RA,         RB,          NONE, RT,   '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '1', RC,   '0', '0', NONE), -- divde
+        2#1110101001#  =>       (DVU,  NONE, OP_DIVE,      RA,         RB,          NONE, RT,   '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '1', RC,   '0', '0', NONE), -- divdeo
+        2#0110101011#  =>       (DVU,  NONE, OP_DIVE,      RA,         RB,          NONE, RT,   '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '1', '1', RC,   '0', '0', NONE), -- divwe
+        2#1110101011#  =>       (DVU,  NONE, OP_DIVE,      RA,         RB,          NONE, RT,   '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '1', '1', RC,   '0', '0', NONE), -- divweo
+        2#0111001001#  =>       (DVU,  NONE, OP_DIV,       RA,         RB,          NONE, RT,   '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', RC,   '0', '0', NONE), -- divdu
+        2#1111001001#  =>       (DVU,  NONE, OP_DIV,       RA,         RB,          NONE, RT,   '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', RC,   '0', '0', NONE), -- divduo
+        2#0111001011#  =>       (DVU,  NONE, OP_DIV,       RA,         RB,          NONE, RT,   '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '1', '0', RC,   '0', '0', NONE), -- divwu
+        2#1111001011#  =>       (DVU,  NONE, OP_DIV,       RA,         RB,          NONE, RT,   '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '1', '0', RC,   '0', '0', NONE), -- divwuo
+        2#0111101001#  =>       (DVU,  NONE, OP_DIV,       RA,         RB,          NONE, RT,   '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '1', RC,   '0', '0', NONE), -- divd
+        2#1111101001#  =>       (DVU,  NONE, OP_DIV,       RA,         RB,          NONE, RT,   '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '1', RC,   '0', '0', NONE), -- divdo
+        2#0111101011#  =>       (DVU,  NONE, OP_DIV,       RA,         RB,          NONE, RT,   '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '1', '1', RC,   '0', '0', NONE), -- divw
+        2#1111101011#  =>       (DVU,  NONE, OP_DIV,       RA,         RB,          NONE, RT,   '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '1', '1', RC,   '0', '0', NONE), -- divwo
         2#1100110110#  =>       (ALU,  NONE, OP_NOP,       NONE,       NONE,        NONE, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE), -- dss
         2#0101010110#  =>       (ALU,  NONE, OP_NOP,       NONE,       NONE,        NONE, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE), -- dst
         2#0101110110#  =>       (ALU,  NONE, OP_NOP,       NONE,       NONE,        NONE, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE), -- dstst
@@ -318,10 +330,10 @@ architecture behaviour of decode1 is
         2#0000010011#  =>       (ALU,  NONE, OP_MFCR,      NONE,       NONE,        NONE, RT,   '1', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE), -- mfcr/mfocrf
         2#0001010011#  =>       (ALU,  NONE, OP_MFMSR,     NONE,       NONE,        NONE, RT,   '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '1', NONE), -- mfmsr
         2#0101010011#  =>       (ALU,  NONE, OP_MFSPR,     SPR,        NONE,        RS,   RT,   '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE), -- mfspr
-        2#0100001001#  =>       (ALU,  NONE, OP_MOD,       RA,         RB,          NONE, RT,   '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE), -- modud
-        2#0100001011#  =>       (ALU,  NONE, OP_MOD,       RA,         RB,          NONE, RT,   '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '1', '0', NONE, '0', '0', NONE), -- moduw
-        2#1100001001#  =>       (ALU,  NONE, OP_MOD,       RA,         RB,          NONE, RT,   '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '1', NONE, '0', '0', NONE), -- modsd
-        2#1100001011#  =>       (ALU,  NONE, OP_MOD,       RA,         RB,          NONE, RT,   '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '1', '1', NONE, '0', '0', NONE), -- modsw
+        2#0100001001#  =>       (DVU,  NONE, OP_MOD,       RA,         RB,          NONE, RT,   '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE), -- modud
+        2#0100001011#  =>       (DVU,  NONE, OP_MOD,       RA,         RB,          NONE, RT,   '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '1', '0', NONE, '0', '0', NONE), -- moduw
+        2#1100001001#  =>       (DVU,  NONE, OP_MOD,       RA,         RB,          NONE, RT,   '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '1', NONE, '0', '0', NONE), -- modsd
+        2#1100001011#  =>       (DVU,  NONE, OP_MOD,       RA,         RB,          NONE, RT,   '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '1', '1', NONE, '0', '0', NONE), -- modsw
         2#0010010000#  =>       (ALU,  NONE, OP_MTCRF,     NONE,       NONE,        RS,   NONE, '0', '1', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE), -- mtcrf/mtocrf
         2#0010010010#  =>       (ALU,  NONE, OP_MTMSRD,    NONE,       NONE,        RS,   NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '1', '0', NONE, '0', '0', NONE), -- mtmsr
         2#0010110010#  =>       (ALU,  NONE, OP_MTMSRD,    NONE,       NONE,        RS,   NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE), -- mtmsrd # ignore top bits and d
index 212196326faa02379e91884d5a96d23a6bb0a791..2efe4394625d033fdff16a6bb81ef8453b94f8d3 100644 (file)
@@ -188,7 +188,7 @@ architecture behaviour of execute1 is
 
     -- divider signals
     signal x_to_divider: Execute1ToDividerType;
-    signal divider_to_x: DividerToExecute1Type;
+    signal divider_to_x: DividerToExecute1Type := DividerToExecute1Init;
 
     -- random number generator signals
     signal random_raw  : std_ulogic_vector(63 downto 0);
@@ -367,13 +367,15 @@ begin
             m_out => multiply_to_x
             );
 
-    divider_0: entity work.divider
-        port map (
-            clk => clk,
-            rst => rst,
-            d_in => x_to_divider,
-            d_out => divider_to_x
-            );
+    divider_0: if not HAS_FPU generate
+        div_0: entity work.divider
+            port map (
+                clk => clk,
+                rst => rst,
+                d_in => x_to_divider,
+                d_out => divider_to_x
+                );
+    end generate;
 
     random_0: entity work.random
         port map (
@@ -1159,9 +1161,11 @@ begin
                 owait := '1';
 
            when OP_DIV | OP_DIVE | OP_MOD =>
-                v.start_div := '1';
-                slow_op := '1';
-                owait := '1';
+                if not HAS_FPU then
+                    v.start_div := '1';
+                    slow_op := '1';
+                    owait := '1';
+                end if;
 
             when OP_FETCH_FAILED =>
                 -- Handling an ITLB miss doesn't count as having executed an instruction
@@ -1457,6 +1461,9 @@ begin
         fv.frt := e_in.write_reg;
         fv.rc := e_in.rc;
         fv.out_cr := e_in.output_cr;
+        fv.m32b := not ex1.msr(MSR_SF);
+        fv.oe := e_in.oe;
+        fv.xerc := xerc_in;
         fv.stall := l_in.l2stall;
 
        -- Update registers
index b8cea397139d78807fd23ea4228eb53595cb7183..90e04b3e42c49ad563b4cf59524dc8695c689503 100644 (file)
--- a/fpu.vhdl
+++ b/fpu.vhdl
@@ -125,6 +125,7 @@ architecture behaviour of fpu is
         write_reg    : gspr_index_t;
         complete_tag : instr_tag_t;
         writing_cr   : std_ulogic;
+        writing_xer  : std_ulogic;
         int_result   : std_ulogic;
         cr_result    : std_ulogic_vector(3 downto 0);
         cr_mask      : std_ulogic_vector(7 downto 0);
@@ -151,6 +152,7 @@ architecture behaviour of fpu is
         invalid      : std_ulogic;
         negate       : std_ulogic;
         longmask     : std_ulogic;
+        integer_op   : std_ulogic;
         divext       : std_ulogic;
         divmod       : std_ulogic;
         is_signed    : std_ulogic;
@@ -159,6 +161,10 @@ architecture behaviour of fpu is
         inc_quot     : std_ulogic;
         a_hi         : std_ulogic_vector(7 downto 0);
         a_lo         : std_ulogic_vector(55 downto 0);
+        m32b         : std_ulogic;
+        oe           : std_ulogic;
+        xerc         : xer_common_t;
+        xerc_result  : xer_common_t;
     end record;
 
     type lookup_table is array(0 to 1023) of std_ulogic_vector(17 downto 0);
@@ -604,6 +610,7 @@ begin
                 r.do_intr <= '0';
                 r.writing_fpr <= '0';
                 r.writing_cr <= '0';
+                r.writing_xer <= '0';
                 r.fpscr <= (others => '0');
                 r.write_reg <= (others =>'0');
                 r.complete_tag.valid <= '0';
@@ -658,6 +665,8 @@ 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.write_xerc <= r.writing_xer and r.complete;
+    w_out.xerc <= r.xerc_result;
     w_out.interrupt <= r.do_intr;
     w_out.intr_vec <= 16#700#;
     w_out.srr0 <= r.nia;
@@ -739,6 +748,7 @@ begin
             v.instr_done := '0';
             v.writing_fpr := '0';
             v.writing_cr := '0';
+            v.writing_xer := '0';
             v.comm_fpscr := r.fpscr;
             v.illegal := '0';
         end if;
@@ -755,7 +765,11 @@ begin
             v.is_signed := e_in.is_signed;
             v.rc := e_in.rc;
             v.is_cmp := e_in.out_cr;
+            v.oe := e_in.oe;
+            v.m32b := e_in.m32b;
+            v.xerc := e_in.xerc;
             v.longmask := '0';
+            v.integer_op := '0';
             v.divext := '0';
             v.divmod := '0';
             if e_in.op = OP_FPOP or e_in.op = OP_FPOP_I then
@@ -764,6 +778,7 @@ begin
                     int_input := '1';
                 end if;
             else -- OP_DIV, OP_DIVE, OP_MOD
+                v.integer_op := '1';
                 int_input := '1';
                 is_32bint := e_in.single;
                 if e_in.op = OP_DIVE then
@@ -2865,12 +2880,44 @@ begin
                     v.state := IDIV_DONE;
                 end if;
             when IDIV_DONE =>
+                v.xerc_result := v.xerc;
+                if r.oe = '1' then
+                    v.xerc_result.ov := '0';
+                    v.xerc_result.ov32 := '0';
+                    v.writing_xer := '1';
+                end if;
+                if r.m32b = '0' then
+                    v.cr_result(3) := r.r(63);
+                    v.cr_result(2 downto 1) := "00";
+                    if r.r = 64x"0" then
+                        v.cr_result(1) := '1';
+                    else
+                        v.cr_result(2) := not r.r(63);
+                    end if;
+                else
+                    v.cr_result(3) := r.r(31);
+                    v.cr_result(2 downto 1) := "00";
+                    if r.r(31 downto 0) = 32x"0" then
+                        v.cr_result(1) := '1';
+                    else
+                        v.cr_result(2) := not r.r(31);
+                    end if;
+                end if;
+                v.cr_result(0) := v.xerc.so;
                 int_result := '1';
                 v.writing_fpr := '1';
                 v.instr_done := '1';
             when IDIV_ZERO =>
                 opsel_r <= RES_MISC;
                 misc_sel <= "0101";
+                v.xerc_result := v.xerc;
+                if r.oe = '1' then
+                    v.xerc_result.ov := r.int_ovf;
+                    v.xerc_result.ov32 := r.int_ovf;
+                    v.xerc_result.so := r.xerc.so or r.int_ovf;
+                    v.writing_xer := '1';
+                end if;
+                v.cr_result := "001" & v.xerc_result.so;
                 int_result := '1';
                 v.writing_fpr := '1';
                 v.instr_done := '1';
@@ -3169,14 +3216,16 @@ begin
                 v.state := IDLE;
                 v.busy := '0';
                 v.f2stall := '0';
-                if r.rc = '1' then
+                if r.rc = '1' and (r.op = OP_FPOP or r.op = OP_FPOP_I) then
                     v.cr_result := v.fpscr(FPSCR_FX downto FPSCR_OX);
                 end if;
                 v.sp_result := r.single_prec;
                 v.int_result := int_result;
                 v.illegal := illegal;
                 v.nsnan_result := v.quieten_nan;
-                if r.is_cmp = '0' then
+                if r.integer_op = '1' then
+                    v.cr_mask := num_to_fxm(0);
+                elsif r.is_cmp = '0' then
                     v.cr_mask := num_to_fxm(1);
                 else
                     v.cr_mask := num_to_fxm(to_integer(unsigned(insn_bf(r.insn))));
index 500e92df0ea6d4d4b8c196862a1e9733d4094dd4..773c05d596059d49db4cdc19d5cd1b6bda797269 100644 (file)
@@ -1410,6 +1410,110 @@ int fpu_test_23(void)
        return trapit(0, test23);
 }
 
+struct idiv_tests {
+       unsigned long denom;
+       unsigned long divisor;
+       unsigned long divd;
+       unsigned long divdu;
+       unsigned long divde;
+       unsigned long divdeu;
+       unsigned long modsd;
+       unsigned long modud;
+} idiv_tests[] = {
+       { 0, 0,                 0, 0, 0, 0, 0, 0 },
+       { 0x56789a, 0x1234,     0x4c0, 0x4c0, 0, 0, 0x19a, 0x19a },
+       { 2, 3,                 0, 0, 0, 0xaaaaaaaaaaaaaaaa, 2, 2 },
+       { 31, 157,              0, 0, 0x328c3ab35cf15328, 0x328c3ab35cf15328, 31, 31 },
+       { -4329874, 43879,      -98, 0x17e5a119b9170, 0, 0, -29732, 39518 },
+       { -4329874, -43879,     98, 0, 0, 0xffffffffffbe99d4, -29732, -4329874 },
+       { 0x8000000000000000ul, -1, 0, 0, 0, 0x8000000000000000ul, 0, 0x8000000000000000ul },
+};
+
+int fpu_test_24(void)
+{
+       long i;
+       unsigned long a, b, results[6];
+
+       for (i = 0; i < sizeof(idiv_tests) / sizeof(idiv_tests[0]); ++i) {
+               a = idiv_tests[i].denom;
+               b = idiv_tests[i].divisor;
+               asm("divd %0,%1,%2" : "=r" (results[0]) : "r" (a), "r" (b));
+               asm("divdu %0,%1,%2" : "=r" (results[1]) : "r" (a), "r" (b));
+               asm("divde %0,%1,%2" : "=r" (results[2]) : "r" (a), "r" (b));
+               asm("divdeu %0,%1,%2" : "=r" (results[3]) : "r" (a), "r" (b));
+               asm("modsd %0,%1,%2" : "=r" (results[4]) : "r" (a), "r" (b));
+               asm("modud %0,%1,%2" : "=r" (results[5]) : "r" (a), "r" (b));
+               if (results[0] != idiv_tests[i].divd ||
+                   results[1] != idiv_tests[i].divdu ||
+                   results[2] != idiv_tests[i].divde ||
+                   results[3] != idiv_tests[i].divdeu ||
+                   results[4] != idiv_tests[i].modsd ||
+                   results[5] != idiv_tests[i].modud) {
+                       print_hex(i, 2, " ");
+                       print_hex(results[0], 16, " ");
+                       print_hex(results[1], 16, " ");
+                       print_hex(results[2], 16, " ");
+                       print_hex(results[3], 16, " ");
+                       print_hex(results[4], 16, " ");
+                       print_hex(results[5], 16, "\r\n");
+                       return i + 1;
+               }
+       }
+       return 0;
+}
+
+struct wdiv_tests {
+       unsigned int denom;
+       unsigned int divisor;
+       unsigned int divw;
+       unsigned int divwu;
+       unsigned int divwe;
+       unsigned int divweu;
+       unsigned int modsw;
+       unsigned int moduw;
+} wdiv_tests[] = {
+       { 0, 0,                 0, 0, 0, 0, 0, 0 },
+       { 0x56789a, 0x1234,     0x4c0, 0x4c0, 0, 0, 0x19a, 0x19a },
+       { 2, 3,                 0, 0, 0, 0xaaaaaaaa, 2, 2 },
+       { 31, 157,              0, 0, 0x328c3ab3, 0x328c3ab3, 31, 31 },
+       { -4329874, 43879,      -98, 0x17df7, 0, 0, -29732, 17165 },
+       { -4329874, -43879,     98, 0, 0, 0xffbe99a9, -29732, -4329874 },
+       { 0x80000000u, -1,      0, 0, 0, 0x80000000u, 0, 0x80000000u },
+};
+
+int fpu_test_25(void)
+{
+       long i;
+       unsigned int a, b, results[6];
+
+       for (i = 0; i < sizeof(wdiv_tests) / sizeof(wdiv_tests[0]); ++i) {
+               a = wdiv_tests[i].denom;
+               b = wdiv_tests[i].divisor;
+               asm("divw %0,%1,%2" : "=r" (results[0]) : "r" (a), "r" (b));
+               asm("divwu %0,%1,%2" : "=r" (results[1]) : "r" (a), "r" (b));
+               asm("divwe %0,%1,%2" : "=r" (results[2]) : "r" (a), "r" (b));
+               asm("divweu %0,%1,%2" : "=r" (results[3]) : "r" (a), "r" (b));
+               asm("modsw %0,%1,%2" : "=r" (results[4]) : "r" (a), "r" (b));
+               asm("moduw %0,%1,%2" : "=r" (results[5]) : "r" (a), "r" (b));
+               if (results[0] != wdiv_tests[i].divw ||
+                   results[1] != wdiv_tests[i].divwu ||
+                   results[2] != wdiv_tests[i].divwe ||
+                   results[3] != wdiv_tests[i].divweu ||
+                   results[4] != wdiv_tests[i].modsw ||
+                   results[5] != wdiv_tests[i].moduw) {
+                       print_hex(i, 2, " ");
+                       print_hex(results[0], 8, " ");
+                       print_hex(results[1], 8, " ");
+                       print_hex(results[2], 8, " ");
+                       print_hex(results[3], 8, " ");
+                       print_hex(results[4], 8, " ");
+                       print_hex(results[5], 8, "\r\n");
+                       return i + 1;
+               }
+       }
+       return 0;
+}
+
 int fail = 0;
 
 void do_test(int num, int (*test)(void))
@@ -1458,6 +1562,8 @@ int main(void)
        do_test(21, fpu_test_21);
        do_test(22, fpu_test_22);
        do_test(23, fpu_test_23);
+       do_test(24, fpu_test_24);
+       do_test(25, fpu_test_25);
 
        return fail;
 }
index 0d6f41d7ec38f93f64b2d95c03df4bf6a4e9571a..5b384c61ee5573cbe3e9f9326da5d59e711951d9 100644 (file)
@@ -73,6 +73,8 @@ begin
             assert (to_integer(unsigned(w)) + to_integer(unsigned(x)) +
                     to_integer(unsigned(y))) <= 1 severity failure;
 
+            assert (e_in.write_xerc_enable and fp_in.write_xerc) /= '1' severity failure;
+
             assert not (e_in.valid = '1' and e_in.instr_tag.valid = '0') severity failure;
             assert not (l_in.valid = '1' and l_in.instr_tag.valid = '0') severity failure;
             assert not (fp_in.valid = '1' and fp_in.instr_tag.valid = '0') severity failure;
@@ -168,6 +170,11 @@ begin
                 c_out.write_cr_data <= fp_in.write_cr_data;
             end if;
 
+            if fp_in.write_xerc = '1' then
+                c_out.write_xerc_enable <= '1';
+                c_out.write_xerc_data <= fp_in.xerc;
+            end if;
+
             if l_in.write_enable = '1' then
                 w_out.write_reg <= l_in.write_reg;
                 w_out.write_data <= l_in.write_data;