[mupen64plus] 145/262: Correct mapping of floating point registers in MIPS I mode

Sven Eckelmann ecsv-guest at moszumanska.debian.org
Thu Nov 26 05:59:28 UTC 2015


This is an automated email from the git hooks/post-receive script.

ecsv-guest pushed a commit to branch master
in repository mupen64plus.

commit 709eb7f482c8d6dc40a90a3791eb81b978079627
Author: Sven Eckelmann <sven.eckelmann at gmx.de>
Date:   Sat Oct 3 01:49:30 2009 +0200

    Correct mapping of floating point registers in MIPS I mode
    
    MIPS r4300i supports different floating point register sets. As the
    instruction set reference state that these are separated but not
    distinct and a program maybe switch between both with 'mtc0 $x, status'
    we must be sure that they don't override each other on write access in
    a non-compliant way.
    This is implemented by doing operations in separate floating point
    register banks for 32 bit and 64 bit wide FGRs. After a switch both gets
    synced to match the behavior specified in the documentation. Inside the
    savestate only the 64 bit wide FGRs gets saved and before a save and
    after a load of a savestate a sync of both is forced.
    More informations about these registers can be found in
     * Charles Brice, "MIPS IV Instruction Set" Rev. 3.2, September 1995 in
       "B.3 Floating-Point Registers".
     * Joe Heinrich, "MIPS R4000 Microprocessor User’s Manual",
       Second Edition in "6.3 FPU Programming Model" and
       "B.4 Computational Instructions"
---
 debian/changelog                           |   4 +
 debian/patches/correct_fpr32_mapping.patch | 294 +++++++++++++++++++++++++++++
 debian/patches/load-fpr-location.patch     |  55 ------
 debian/patches/series                      |   2 +-
 4 files changed, 299 insertions(+), 56 deletions(-)

diff --git a/debian/changelog b/debian/changelog
index ba209e9..95e3ffb 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -6,6 +6,10 @@ mupen64plus (1.5+dfsg1-6) UNRELEASED; urgency=low
     - Update ftbfs-glibc210.patch, Backport actual commit from upstream
     - Update noexecstack.patch, Backport actual commit from upstream
     - Update jttl_fix_romclosed.patch, Backport actual commit from upstream
+    - Add correct_fpr32_mapping.patch, Correct emulation of shared 32 bit wide
+      and 64 bit wide FPR in MIPS I and MIPS III mode
+    - Remove load-fpr-location.patch which is replaced by
+      correct_fpr32_mapping.patch
 
  -- Sven Eckelmann <sven.eckelmann at gmx.de>  Sat, 03 Oct 2009 00:36:41 +0200
 
diff --git a/debian/patches/correct_fpr32_mapping.patch b/debian/patches/correct_fpr32_mapping.patch
new file mode 100644
index 0000000..64c8003
--- /dev/null
+++ b/debian/patches/correct_fpr32_mapping.patch
@@ -0,0 +1,294 @@
+Description: Correct mapping of floating point registers in MIPS I mode
+ MIPS r4300i supports different floating point register sets. As the instruction
+ set reference state that these are separated but not distinct and a program
+ maybe switch between both with 'mtc0 $x, status' we must be sure that they
+ don't override each other on write access in a non-compliant way.
+ This is implemented by doing operations in separate floating point register
+ banks for 32 bit and 64 bit wide FGRs. After a switch both gets synced to
+ match the behavior specified in the documentation. Inside the savestate only
+ the 64 bit wide FGRs gets saved and before a save and after a load of a
+ savestate a sync of both is forced.
+ More informations about these registers can be found in
+ * Charles Brice, "MIPS IV Instruction Set" Rev. 3.2, September 1995 in
+   "B.3 Floating-Point Registers".
+ * Joe Heinrich, "MIPS R4000 Microprocessor User’s Manual", Second Edition in
+   "6.3 FPU Programming Model" and "B.4 Computational Instructions"
+Origin: backported, commit:1413
+Bug: http://code.google.com/p/mupen64plus/issues/detail?id=51
+Author: Sven Eckelmann <sven.eckelmann at gmx.de>
+Author: Richard Goedeken <Richard at fascinationsoftware.com>
+
+---
+diff --git a/main/savestates.c b/main/savestates.c
+index 940b4c409ae9cd66eb804b29e83d3be0df3fb69a..b6264ece050fd964c83b245b562dfc42c7aa0e8d 100644
+--- a/main/savestates.c
++++ b/main/savestates.c
+@@ -32,6 +32,7 @@
+ 
+ #include "../memory/memory.h"
+ #include "../memory/flashram.h"
++#include "../r4300/macros.h"
+ #include "../r4300/r4300.h"
+ #include "../r4300/interupt.h"
+ #include "../opengl/osd.h"
+@@ -173,7 +174,18 @@ void savestates_save()
+     gzwrite(f, reg_cop0, 32*4);
+     gzwrite(f, &lo, 8);
+     gzwrite(f, &hi, 8);
+-    gzwrite(f, reg_cop1_fgr_64, 32*8);
++
++    if ((Status & 0x04000000) == 0)
++    {   // FR bit == 0 means 32-bit (MIPS I) FGR mode
++        shuffle_fpr_data(0, 0x04000000);  // shuffle data into 64-bit register format for storage
++        gzwrite(f, reg_cop1_fgr_64, 32*8);
++        shuffle_fpr_data(0x04000000, 0);  // put it back in 32-bit mode
++    }
++    else
++    {
++        gzwrite(f, reg_cop1_fgr_64, 32*8);
++    }
++
+     gzwrite(f, &FCR0, 4);
+     gzwrite(f, &FCR31, 4);
+     gzwrite(f, tlb_e, 32*sizeof(tlb));
+@@ -286,9 +298,12 @@ void savestates_load()
+     gzread(f, &llbit, 4);
+     gzread(f, reg, 32*8);
+     gzread(f, reg_cop0, 32*4);
++    set_fpr_pointers(Status);  // Status is reg_cop0[12]
+     gzread(f, &lo, 8);
+     gzread(f, &hi, 8);
+     gzread(f, reg_cop1_fgr_64, 32*8);
++    if ((Status & 0x04000000) == 0)  // 32-bit FPR mode requires data shuffling because 64-bit layout is always stored in savestate file
++        shuffle_fpr_data(0x04000000, 0);
+     gzread(f, &FCR0, 4);
+     gzread(f, &FCR31, 4);
+     gzread(f, tlb_e, 32*sizeof(tlb));
+diff --git a/r4300/cop0.c b/r4300/cop0.c
+index 1ee72aa2c8e9805aeb1699cc1d4ca7f6e3126829..17c523f7e2712e31cafc1ffdf4b6ab281b41933a 100644
+--- a/r4300/cop0.c
++++ b/r4300/cop0.c
+@@ -91,29 +91,8 @@ void MTC0(void)
+       case 12:   // Status
+     if((rrt & 0x04000000) != (Status & 0x04000000))
+       {
+-         if (rrt & 0x04000000)
+-           {
+-          int i;
+-          for (i=0; i<32; i++)
+-            {
+-               reg_cop1_double[i]=(double*)&reg_cop1_fgr_64[i];
+-               reg_cop1_simple[i]=(float*)&reg_cop1_fgr_64[i];
+-            }
+-           }
+-         else
+-           {
+-          int i;
+-          for (i=0; i<32; i++)
+-            {
+-               if(!(i&1))
+-             reg_cop1_double[i]=(double*)&reg_cop1_fgr_64[i>>1];
+-#ifndef _BIG_ENDIAN
+-               reg_cop1_simple[i]=(float*)&reg_cop1_fgr_64[i>>1]+(i&1);
+-#else
+-               reg_cop1_simple[i]=(float*)&reg_cop1_fgr_64[i>>1]+(1-(i&1));
+-#endif
+-            }
+-           }
++         shuffle_fpr_data(Status, rrt);
++         set_fpr_pointers(rrt);
+       }
+     Status = rrt;
+     PC++;
+diff --git a/r4300/pure_interp.c b/r4300/pure_interp.c
+index 734e244c95b34a4e167b7975f3e7aaf3765dabda..d38cb9e2d00b0ade17fba2334246b20732a7a924 100644
+--- a/r4300/pure_interp.c
++++ b/r4300/pure_interp.c
+@@ -1040,38 +1040,10 @@ static void MTC0()
+     break;
+       case 12:   // Status
+     if((rrt & 0x04000000) != (Status & 0x04000000))
+-      {
+-         if (rrt & 0x04000000)
+-           {
+-          int i;
+-          for (i=0; i<32; i++)
+-            {
+-               //reg_cop1_fgr_64[i]=reg_cop1_fgr_32[i];
+-               reg_cop1_double[i]=(double*)&reg_cop1_fgr_64[i];
+-               reg_cop1_simple[i]=(float*)&reg_cop1_fgr_64[i];
+-            }
+-           }
+-         else
+-           {
+-          int i;
+-          for (i=0; i<32; i++)
+-            {
+-               //reg_cop1_fgr_32[i]=reg_cop1_fgr_64[i]&0xFFFFFFFF;
+-               //if (i<16) reg_cop1_double[i*2]=(double*)&reg_cop1_fgr_32[i*2];
+-               //reg_cop1_double[i]=(double*)&reg_cop1_fgr_64[i & 0xFFFE];
+-               if(!(i&1))
+-             reg_cop1_double[i]=(double*)&reg_cop1_fgr_64[i>>1];
+-               //reg_cop1_double[i]=(double*)&reg_cop1_fgr_64[i];
+-               //reg_cop1_simple[i]=(float*)&reg_cop1_fgr_32[i];
+-               //reg_cop1_simple[i]=(float*)&reg_cop1_fgr_64[i & 0xFFFE]+(i&1);
+-#ifndef _BIG_ENDIAN
+-               reg_cop1_simple[i]=(float*)&reg_cop1_fgr_64[i>>1]+(i&1);
+-#else
+-               reg_cop1_simple[i]=(float*)&reg_cop1_fgr_64[i>>1]+(1-(i&1));
+-#endif
+-            }
+-           }
+-      }
++    {
++      shuffle_fpr_data(Status, rrt);
++      set_fpr_pointers(rrt);
++    }
+     Status = rrt;
+     interp_addr+=4;
+     check_interupt();
+diff --git a/r4300/r4300.c b/r4300/r4300.c
+index f3203c3da1f34ab3d4d127252c4c39abdeebad6e..4584f34d6a0e0519dfec4015108b088a6cad05cb 100644
+--- a/r4300/r4300.c
++++ b/r4300/r4300.c
+@@ -45,7 +45,6 @@ int local_rs32, local_rt32;
+ unsigned int jump_target;
+ float *reg_cop1_simple[32];
+ double *reg_cop1_double[32];
+-int reg_cop1_fgr_32[32];
+ long long int reg_cop1_fgr_64[32];
+ int FCR0, FCR31;
+ tlb tlb_e[32];
+@@ -1496,6 +1495,90 @@ void jump_to_func()
+ }
+ #undef addr
+ 
++/* Refer to Figure 6-2 on page 155 and explanation on page B-11
++   of MIPS R4000 Microprocessor User's Manual (Second Edition)
++   by Joe Heinrich.
++*/
++void shuffle_fpr_data(int oldStatus, int newStatus)
++{
++#if defined(_BIG_ENDIAN)
++    const int isBigEndian = 1;
++#else
++    const int isBigEndian = 0;
++#endif
++
++    if ((newStatus & 0x04000000) != (oldStatus & 0x04000000))
++    {
++        int i;
++        int temp_fgr_32[32];
++
++        // pack or unpack the FGR register data
++        if (newStatus & 0x04000000)
++        {   // switching into 64-bit mode
++            // retrieve 32 FPR values from packed 32-bit FGR registers
++            for (i = 0; i < 32; i++)
++            {
++                temp_fgr_32[i] = *((int *) &reg_cop1_fgr_64[i>>1] + ((i & 1) ^ isBigEndian));
++            }
++            // unpack them into 32 64-bit registers, taking the high 32-bits from their temporary place in the upper 16 FGRs
++            for (i = 0; i < 32; i++)
++            {
++                int high32 = *((int *) &reg_cop1_fgr_64[(i>>1)+16] + (i & 1));
++                *((int *) &reg_cop1_fgr_64[i] + isBigEndian)     = temp_fgr_32[i];
++                *((int *) &reg_cop1_fgr_64[i] + (isBigEndian^1)) = high32;
++            }
++        }
++        else
++        {   // switching into 32-bit mode
++            // retrieve the high 32 bits from each 64-bit FGR register and store in temp array
++            for (i = 0; i < 32; i++)
++            {
++                temp_fgr_32[i] = *((int *) &reg_cop1_fgr_64[i] + (isBigEndian^1));
++            }
++            // take the low 32 bits from each register and pack them together into 64-bit pairs
++            for (i = 0; i < 16; i++)
++            {
++                int least32 = *((int *) &reg_cop1_fgr_64[i*2] + isBigEndian);
++                int most32 = *((int *) &reg_cop1_fgr_64[i*2+1] + isBigEndian);
++                reg_cop1_fgr_64[i] = ((unsigned long long) most32 << 32) | (unsigned long long) least32;
++            }
++            // store the high bits in the upper 16 FGRs, which wont be accessible in 32-bit mode
++            for (i = 0; i < 32; i++)
++            {
++                *((int *) &reg_cop1_fgr_64[(i>>1)+16] + (i & 1)) = temp_fgr_32[i];
++            }
++        }
++    }
++}
++
++void set_fpr_pointers(int newStatus)
++{
++    int i;
++#if defined(_BIG_ENDIAN)
++    const int isBigEndian = 1;
++#else
++    const int isBigEndian = 0;
++#endif
++
++    // update the FPR register pointers
++    if (newStatus & 0x04000000)
++    {
++        for (i = 0; i < 32; i++)
++        {
++            reg_cop1_double[i] = (double*) &reg_cop1_fgr_64[i];
++            reg_cop1_simple[i] = ((float*) &reg_cop1_fgr_64[i]) + isBigEndian;
++        }
++    }
++    else
++    {
++        for (i = 0; i < 32; i++)
++        {
++            reg_cop1_double[i] = (double*) &reg_cop1_fgr_64[i>>1];
++            reg_cop1_simple[i] = ((float*) &reg_cop1_fgr_64[i>>1]) + ((i & 1) ^ isBigEndian);
++        }
++    }
++}
++
+ int check_cop1_unusable()
+ {
+    if (!(Status & 0x20000000))
+@@ -1568,12 +1651,8 @@ void r4300_reset_hard()
+     {
+         reg[i]=0;
+         reg_cop0[i]=0;
+-        reg_cop1_fgr_32[i]=0;
+         reg_cop1_fgr_64[i]=0;
+ 
+-        reg_cop1_double[i]=(double *)&reg_cop1_fgr_64[i];
+-        reg_cop1_simple[i]=(float *)&reg_cop1_fgr_64[i];
+-
+         // --------------tlb------------------------
+         tlb_e[i].mask=0;
+         tlb_e[i].vpn2=0;
+@@ -1611,6 +1690,7 @@ void r4300_reset_hard()
+     // set COP0 registers
+     Random = 31;
+     Status= 0x34000000;
++    set_fpr_pointers(Status);
+     Config= 0x6e463;
+     PRevID = 0xb00;
+     Count = 0x5000;
+diff --git a/r4300/r4300.h b/r4300/r4300.h
+index 4759efd40f55039ee14f6fcbe69db44850e2e72c..3430bd92c9653ed88a3d7ef9c8a7663c4a8130cb 100644
+--- a/r4300/r4300.h
++++ b/r4300/r4300.h
+@@ -42,7 +42,6 @@ extern int local_rs32, local_rt32;
+ extern unsigned int jump_target;
+ extern double *reg_cop1_double[32];
+ extern float *reg_cop1_simple[32];
+-extern int reg_cop1_fgr_32[32];
+ extern long long int reg_cop1_fgr_64[32];
+ extern int FCR0, FCR31;
+ extern tlb tlb_e[32];
+@@ -66,6 +65,8 @@ void compare_core();
+ void jump_to_func();
+ void update_count();
+ int check_cop1_unusable();
++void shuffle_fpr_data(int oldStatus, int newStatus);
++void set_fpr_pointers(int newStatus);
+ 
+ #define jump_to(a) { jump_to_address = a; jump_to_func(); }
+ 
diff --git a/debian/patches/load-fpr-location.patch b/debian/patches/load-fpr-location.patch
deleted file mode 100644
index 105a61b..0000000
--- a/debian/patches/load-fpr-location.patch
+++ /dev/null
@@ -1,55 +0,0 @@
-Description: Set register bank location when loading savestate
- The program can change the register banks for floating point registers from
- MIPS I to MIPS III and back again using mtr0. We must set the register sets
- again after a savestate was loaded or invalid values could be loaded when
- accessing the wrong floating point registers.
-Bug: http://code.google.com/p/mupen64plus/issues/detail?id=51
-Author: Sven Eckelmann <sven.eckelmann at gmx.de>
-
----
-diff --git a/main/savestates.c b/main/savestates.c
-index 940b4c409ae9cd66eb804b29e83d3be0df3fb69a..f2df55824d0696d04472a268b6f9aae1aec731c4 100644
---- a/main/savestates.c
-+++ b/main/savestates.c
-@@ -194,6 +194,33 @@ void savestates_save()
-     free(filename);
- }
- 
-+static void set_cop1_register(void)
-+{
-+    if (reg_cop0[12] & 0x04000000)
-+    {
-+        int i;
-+        for (i=0; i<32; i++)
-+        {
-+            reg_cop1_double[i]=(double*)&reg_cop1_fgr_64[i];
-+            reg_cop1_simple[i]=(float*)&reg_cop1_fgr_64[i];
-+        }
-+    }
-+    else
-+    {
-+        int i;
-+        for (i=0; i<32; i++)
-+        {
-+               if(!(i&1))
-+             reg_cop1_double[i]=(double*)&reg_cop1_fgr_64[i>>1];
-+#ifndef _BIG_ENDIAN
-+               reg_cop1_simple[i]=(float*)&reg_cop1_fgr_64[i>>1]+(i&1);
-+#else
-+               reg_cop1_simple[i]=(float*)&reg_cop1_fgr_64[i>>1]+(1-(i&1));
-+#endif
-+        }
-+    }
-+}
-+
- void savestates_load()
- {
-     char *filename, *file, buffer[1024];
-@@ -286,6 +313,7 @@ void savestates_load()
-     gzread(f, &llbit, 4);
-     gzread(f, reg, 32*8);
-     gzread(f, reg_cop0, 32*4);
-+    set_cop1_register();
-     gzread(f, &lo, 8);
-     gzread(f, &hi, 8);
-     gzread(f, reg_cop1_fgr_64, 32*8);
diff --git a/debian/patches/series b/debian/patches/series
index 0b89d07..e7484be 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -27,4 +27,4 @@ fix_readpng.patch
 jttl_fix_romclosed.patch
 rice_nodebug.patch
 interpreter_x86_fldcw.patch
-load-fpr-location.patch
+correct_fpr32_mapping.patch

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-games/mupen64plus.git



More information about the Pkg-games-commits mailing list