[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*)®_cop1_fgr_64[i];
+- reg_cop1_simple[i]=(float*)®_cop1_fgr_64[i];
+- }
+- }
+- else
+- {
+- int i;
+- for (i=0; i<32; i++)
+- {
+- if(!(i&1))
+- reg_cop1_double[i]=(double*)®_cop1_fgr_64[i>>1];
+-#ifndef _BIG_ENDIAN
+- reg_cop1_simple[i]=(float*)®_cop1_fgr_64[i>>1]+(i&1);
+-#else
+- reg_cop1_simple[i]=(float*)®_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*)®_cop1_fgr_64[i];
+- reg_cop1_simple[i]=(float*)®_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*)®_cop1_fgr_32[i*2];
+- //reg_cop1_double[i]=(double*)®_cop1_fgr_64[i & 0xFFFE];
+- if(!(i&1))
+- reg_cop1_double[i]=(double*)®_cop1_fgr_64[i>>1];
+- //reg_cop1_double[i]=(double*)®_cop1_fgr_64[i];
+- //reg_cop1_simple[i]=(float*)®_cop1_fgr_32[i];
+- //reg_cop1_simple[i]=(float*)®_cop1_fgr_64[i & 0xFFFE]+(i&1);
+-#ifndef _BIG_ENDIAN
+- reg_cop1_simple[i]=(float*)®_cop1_fgr_64[i>>1]+(i&1);
+-#else
+- reg_cop1_simple[i]=(float*)®_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 *) ®_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 *) ®_cop1_fgr_64[(i>>1)+16] + (i & 1));
++ *((int *) ®_cop1_fgr_64[i] + isBigEndian) = temp_fgr_32[i];
++ *((int *) ®_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 *) ®_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 *) ®_cop1_fgr_64[i*2] + isBigEndian);
++ int most32 = *((int *) ®_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 *) ®_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*) ®_cop1_fgr_64[i];
++ reg_cop1_simple[i] = ((float*) ®_cop1_fgr_64[i]) + isBigEndian;
++ }
++ }
++ else
++ {
++ for (i = 0; i < 32; i++)
++ {
++ reg_cop1_double[i] = (double*) ®_cop1_fgr_64[i>>1];
++ reg_cop1_simple[i] = ((float*) ®_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 *)®_cop1_fgr_64[i];
+- reg_cop1_simple[i]=(float *)®_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*)®_cop1_fgr_64[i];
-+ reg_cop1_simple[i]=(float*)®_cop1_fgr_64[i];
-+ }
-+ }
-+ else
-+ {
-+ int i;
-+ for (i=0; i<32; i++)
-+ {
-+ if(!(i&1))
-+ reg_cop1_double[i]=(double*)®_cop1_fgr_64[i>>1];
-+#ifndef _BIG_ENDIAN
-+ reg_cop1_simple[i]=(float*)®_cop1_fgr_64[i>>1]+(i&1);
-+#else
-+ reg_cop1_simple[i]=(float*)®_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