Implement the FPSCR register.

This commit is contained in:
Andrew Church 2015-01-19 03:17:51 +09:00
parent 6627cc9666
commit a87de1b565
2 changed files with 55 additions and 57 deletions

View file

@ -981,8 +981,10 @@ private:
void FSCRRD(u32 rt) void FSCRRD(u32 rt)
{ {
// TODO (rarely used) CPU.GPR[rt]._u32[3] = CPU.FPSCR._u32[3];
CPU.GPR[rt].clear(); CPU.GPR[rt]._u32[2] = CPU.FPSCR._u32[2];
CPU.GPR[rt]._u32[1] = CPU.FPSCR._u32[1];
CPU.GPR[rt]._u32[0] = CPU.FPSCR._u32[0];
} }
void FESD(u32 rt, u32 ra) void FESD(u32 rt, u32 ra)
{ {
@ -998,12 +1000,10 @@ private:
} }
void FSCRWR(u32 rt, u32 ra) void FSCRWR(u32 rt, u32 ra)
{ {
// TODO (rarely used) CPU.FPSCR._u32[3] = CPU.GPR[ra]._u32[3] & 0x00000F07;
if (CPU.GPR[ra]._u64[0] || CPU.GPR[ra]._u64[1]) CPU.FPSCR._u32[2] = CPU.GPR[ra]._u32[2] & 0x00003F07;
{ CPU.FPSCR._u32[1] = CPU.GPR[ra]._u32[1] & 0x00003F07;
LOG_ERROR(SPU, "FSCRWR(%d,%d): value = %s", rt, ra, CPU.GPR[ra].to_hex().c_str()); CPU.FPSCR._u32[0] = CPU.GPR[ra]._u32[0] & 0x00000F07;
UNIMPLEMENTED();
}
} }
void DFTSV(u32 rt, u32 ra, s32 i7) void DFTSV(u32 rt, u32 ra, s32 i7)
{ {

View file

@ -167,45 +167,49 @@ struct g_imm_table_struct
extern const g_imm_table_struct g_imm_table; extern const g_imm_table_struct g_imm_table;
//Floating point status and control register. Unsure if this is one of the GPRs or SPRs enum FPSCR_EX
{
//Single-precision exceptions
FPSCR_SOVF = 1 << 2, //Overflow
FPSCR_SUNF = 1 << 1, //Underflow
FPSCR_SDIFF = 1 << 0, //Different (could be IEEE non-compliant)
//Double-precision exceptions
FPSCR_DOVF = 1 << 13, //Overflow
FPSCR_DUNF = 1 << 12, //Underflow
FPSCR_DINX = 1 << 11, //Inexact
FPSCR_DINV = 1 << 10, //Invalid operation
FPSCR_DNAN = 1 << 9, //NaN
FPSCR_DDENORM = 1 << 8, //Denormal
};
//Is 128 bits, but bits 0-19, 24-28, 32-49, 56-60, 64-81, 88-92, 96-115, 120-124 are unused //Is 128 bits, but bits 0-19, 24-28, 32-49, 56-60, 64-81, 88-92, 96-115, 120-124 are unused
class FPSCR class SPU_FPSCR
{ {
public: public:
u64 low; u32 _u32[4];
u64 hi;
FPSCR() {} SPU_FPSCR() {}
std::string ToString() const std::string ToString() const
{ {
return "FPSCR writer not yet implemented"; //fmt::Format("%08x%08x%08x%08x", _u32[3], _u32[2], _u32[1], _u32[0]); return fmt::Format("%08x%08x%08x%08x", _u32[3], _u32[2], _u32[1], _u32[0]);
} }
void Reset() void Reset()
{ {
memset(this, 0, sizeof(*this)); memset(this, 0, sizeof(*this));
} }
//slice -> 0 - 1 (4 slices total, only two have rounding) //slice -> 0 - 1 (double-precision slice index)
//NOTE: slices follow u128 indexing, i.e. slice 0 is RIGHT end of register!
//0 -> round even //0 -> round even
//1 -> round towards zero (truncate) //1 -> round towards zero (truncate)
//2 -> round towards positive inf //2 -> round towards positive inf
//3 -> round towards neg inf //3 -> round towards neg inf
void setSliceRounding(u8 slice, u8 roundTo) void setSliceRounding(u8 slice, u8 roundTo)
{ {
u64 mask = roundTo; int shift = 8 + 2*slice;
switch(slice) //rounding is located in the left end of the FPSCR
{ this->_u32[3] = (this->_u32[3] & ~(3 << shift)) | (roundTo << shift);
case 0:
mask = mask << 20;
break;
case 1:
mask = mask << 22;
break;
}
//rounding is located in the low end of the FPSCR
this->low = this->low & mask;
} }
//Slice 0 or 1 //Slice 0 or 1
u8 checkSliceRounding(u8 slice) const u8 checkSliceRounding(u8 slice) const
@ -213,10 +217,10 @@ public:
switch(slice) switch(slice)
{ {
case 0: case 0:
return this->low >> 20 & 0x3; return this->_u32[3] >> 8 & 0x3;
case 1: case 1:
return this->low >> 22 & 0x3; return this->_u32[3] >> 10 & 0x3;
default: default:
throw fmt::Format("Unexpected slice value in FPSCR::checkSliceRounding(): %d", slice); throw fmt::Format("Unexpected slice value in FPSCR::checkSliceRounding(): %d", slice);
@ -224,34 +228,28 @@ public:
} }
} }
//Single Precision Exception Flags (all 3 slices) //Single-precision exception flags (all 4 slices)
//slice -> slice number (0-3) //slice -> slice number (0-3)
//exception: 1 -> Overflow 2 -> Underflow 4-> Diff (could be IE^3 non compliant) //exception: FPSCR_S* bitmask
void setSinglePrecisionExceptionFlags(u8 slice, u8 exception) void setSinglePrecisionExceptionFlags(u8 slice, u32 exceptions)
{ {
u64 mask = exception; _u32[slice] |= exceptions;
switch(slice) }
{
case 0: //Single-precision divide-by-zero flags (all 4 slices)
mask = mask << 29; //slice -> slice number (0-3)
this->low = this->low & mask; void setDivideByZeroFlag(u8 slice)
break; {
case 1: _u32[0] |= 1 << (8 + slice);
mask = mask << 61; }
this->low = this->low & mask;
break; //Double-precision exception flags
case 2: //slice -> slice number (0-1)
mask = mask << 29; //exception: FPSCR_D* bitmask
this->hi = this->hi & mask; void setDoublePrecisionExceptionFlags(u8 slice, u32 exceptions)
break; {
case 3: _u32[1+slice] |= exceptions;
mask = mask << 61;
this->hi = this->hi & mask;
break;
}
} }
}; };
union SPU_SNRConfig_hdr union SPU_SNRConfig_hdr
@ -277,7 +275,7 @@ class SPUThread : public PPCThread
{ {
public: public:
u128 GPR[128]; // General-Purpose Registers u128 GPR[128]; // General-Purpose Registers
//FPSCR FPSCR; SPU_FPSCR FPSCR;
SPU_SNRConfig_hdr cfg; // Signal Notification Registers Configuration (OR-mode enabled: 0x1 for SNR1, 0x2 for SNR2) SPU_SNRConfig_hdr cfg; // Signal Notification Registers Configuration (OR-mode enabled: 0x1 for SNR1, 0x2 for SNR2)
u64 R_ADDR; // reservation address u64 R_ADDR; // reservation address
@ -630,4 +628,4 @@ public:
return *this; return *this;
} }
}; };