Cog/Frameworks/lazyusf2/lazyusf2/r4300/cp1.c

110 lines
4.6 KiB
C

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus - cp1.c *
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
* Copyright (C) 2002 Hacktarux *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "usf/usf.h"
#include "new_dynarec/new_dynarec.h"
#include "usf/usf_internal.h"
/* 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(usf_state_t * state, int oldStatus, int newStatus)
{
#if defined(M64P_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 *) &state->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 *) &state->reg_cop1_fgr_64[(i>>1)+16] + (i & 1));
*((int *) &state->reg_cop1_fgr_64[i] + isBigEndian) = temp_fgr_32[i];
*((int *) &state->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 *) &state->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++)
{
unsigned int least32 = *((unsigned int *) &state->reg_cop1_fgr_64[i*2] + isBigEndian);
unsigned int most32 = *((unsigned int *) &state->reg_cop1_fgr_64[i*2+1] + isBigEndian);
state->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 *) &state->reg_cop1_fgr_64[(i>>1)+16] + (i & 1)) = temp_fgr_32[i];
}
}
}
}
void set_fpr_pointers(usf_state_t * state, int newStatus)
{
int i;
#if defined(M64P_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++)
{
state->reg_cop1_double[i] = (double*) &state->reg_cop1_fgr_64[i];
state->reg_cop1_simple[i] = ((float*) &state->reg_cop1_fgr_64[i]) + isBigEndian;
}
}
else
{
for (i = 0; i < 32; i++)
{
state->reg_cop1_double[i] = (double*) &state->reg_cop1_fgr_64[i>>1];
state->reg_cop1_simple[i] = ((float*) &state->reg_cop1_fgr_64[i>>1]) + ((i & 1) ^ isBigEndian);
}
}
}