From 1192d20295aa3171252bc99a0516bde90c4b5b1a Mon Sep 17 00:00:00 2001
From: Magn3s1um <sodroski@bu.edu>
Date: Sat, 9 Nov 2013 07:41:56 -0800
Subject: [PATCH] -Partial Implementation of Floating-Point Status and Control
 Register (FPSCR)

---
 rpcs3/Emu/Cell/SPUDisAsm.h      |  2 +-
 rpcs3/Emu/Cell/SPUInterpreter.h | 28 ++++++++---
 rpcs3/Emu/Cell/SPUOpcodes.h     |  2 +-
 rpcs3/Emu/Cell/SPUThread.h      | 84 +++++++++++++++++++++++++++++++++
 4 files changed, 108 insertions(+), 8 deletions(-)

diff --git a/rpcs3/Emu/Cell/SPUDisAsm.h b/rpcs3/Emu/Cell/SPUDisAsm.h
index 6c4dc82cd9..c0eee0044a 100644
--- a/rpcs3/Emu/Cell/SPUDisAsm.h
+++ b/rpcs3/Emu/Cell/SPUDisAsm.h
@@ -428,7 +428,7 @@ private:
 	{
 		DisAsm("sumb", spu_reg_name[rt], spu_reg_name[ra], spu_reg_name[rb]);
 	}
-	void HGT(u32 rt, u32 ra, u32 rb)
+	void HGT(u32 rt, s32 ra, s32 rb)
 	{
 		DisAsm("hgt", spu_reg_name[rt], spu_reg_name[ra], spu_reg_name[rb]);
 	}
diff --git a/rpcs3/Emu/Cell/SPUInterpreter.h b/rpcs3/Emu/Cell/SPUInterpreter.h
index 88e73ade2d..e123dfe48c 100644
--- a/rpcs3/Emu/Cell/SPUInterpreter.h
+++ b/rpcs3/Emu/Cell/SPUInterpreter.h
@@ -45,7 +45,7 @@ private:
 	void MFSPR(u32 rt, u32 sa)
 	{
 		//If register is a dummy register (register labeled 0x0)
-		if(sa == 0)
+		if(sa == 0x0)
 		{
 			CPU.GPR[rt]._u128.hi = 0x0;
 			CPU.GPR[rt]._u128.lo = 0x0;
@@ -260,7 +260,11 @@ private:
 	}
 	void MTSPR(u32 rt, u32 sa)
 	{
-		UNIMPLEMENTED();
+		if(sa != 0)
+		{
+			CPU.SPR[sa]._u128.hi = CPU.GPR[rt]._u128.hi;
+			CPU.SPR[sa]._u128.lo = CPU.GPR[rt]._u128.lo;
+		}
 	}
 	void WRCH(u32 ra, u32 rt)
 	{
@@ -307,7 +311,7 @@ private:
 	void IRET(u32 ra)
 	{
 		UNIMPLEMENTED();
-		// SetBranch(SRR0);
+		//SetBranch(SRR0);
 	}
 	void BISLED(u32 rt, u32 ra)
 	{
@@ -628,9 +632,13 @@ private:
 			CPU.GPR[rt]._u16[w*2 + 1] = CPU.GPR[rb]._u8[w*4] + CPU.GPR[rb]._u8[w*4 + 1] + CPU.GPR[rb]._u8[w*4 + 2] + CPU.GPR[rb]._u8[w*4 + 3];
 		}
 	}
-	void HGT(u32 rt, u32 ra, u32 rb)
+	//HGT uses signed values.  HLGT uses unsigned values
+	void HGT(u32 rt, s32 ra, s32 rb)
 	{
-		UNIMPLEMENTED();
+		if(CPU.GPR[ra]._i32[0] > CPU.GPR[rb]._i32[0])
+		{
+			CPU.Stop();
+		}
 	}
 	void CLZ(u32 rt, u32 ra)
 	{
@@ -757,7 +765,10 @@ private:
 	}
 	void HLGT(u32 rt, u32 ra, u32 rb)
 	{
-		UNIMPLEMENTED();
+		if(CPU.GPR[ra]._u32[0] > CPU.GPR[rb]._u32[0])
+		{
+			CPU.Stop();
+		}
 	}
 	void DFMA(u32 rt, u32 ra, u32 rb)
 	{
@@ -824,8 +835,13 @@ private:
 		for (int w = 0; w < 4; w++)
 			CPU.GPR[rt]._u32[w] += CPU.GPR[ra]._u16[w*2] * CPU.GPR[rb]._u16[w*2];
 	}
+	//Forced bits to 0, hence the shift:
+	
 	void FSCRRD(u32 rt)
 	{
+		/*CPU.GPR[rt]._u128.lo = 
+			CPU.FPSCR.Exception0 << 20 &
+			CPU.FPSCR.*/
 		UNIMPLEMENTED();
 	}
 	void FESD(u32 rt, u32 ra)
diff --git a/rpcs3/Emu/Cell/SPUOpcodes.h b/rpcs3/Emu/Cell/SPUOpcodes.h
index 8356f962a5..2b0a48744c 100644
--- a/rpcs3/Emu/Cell/SPUOpcodes.h
+++ b/rpcs3/Emu/Cell/SPUOpcodes.h
@@ -323,7 +323,7 @@ public:
 	virtual void EQV(u32  rt, u32  ra, u32  rb) = 0;
 	virtual void CGTB(u32  rt, u32  ra, u32  rb) = 0;
 	virtual void SUMB(u32  rt, u32  ra, u32  rb) = 0;
-	virtual void HGT(u32  rt, u32  ra, u32  rb) = 0;
+	virtual void HGT(u32  rt, s32  ra, s32  rb) = 0;
 	virtual void CLZ(u32  rt, u32  ra) = 0;
 	virtual void XSWD(u32  rt, u32  ra) = 0;
 	virtual void XSHW(u32  rt, u32  ra) = 0;
diff --git a/rpcs3/Emu/Cell/SPUThread.h b/rpcs3/Emu/Cell/SPUThread.h
index 40c14a09f1..89d1d45c45 100644
--- a/rpcs3/Emu/Cell/SPUThread.h
+++ b/rpcs3/Emu/Cell/SPUThread.h
@@ -117,6 +117,89 @@ enum
 	SPU_STATUS_SINGLE_STEP			= 0x10,
 };
 
+//Floating point status and control register.  Unsure if this is one of the GPRs or SPRs
+//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
+{
+public:
+	u64 low;
+	u64 hi;
+
+	FPSCR() {}
+
+	wxString ToString() const
+	{
+		return "FPSCR writer not yet implemented"; //wxString::Format("%08x%08x%08x%08x", _u32[3], _u32[2], _u32[1], _u32[0]);
+	}
+
+	void Reset()
+	{
+		memset(this, 0, sizeof(*this));
+	}
+	//slice -> 0 - 1 (4 slices total, only two have rounding)
+	//0 -> round even
+	//1 -> round towards zero (truncate)
+	//2 -> round towards positive inf
+	//3 -> round towards neg inf
+	void setSliceRounding(u8 slice, u8 roundTo)
+	{
+		u64 mask = roundTo;
+		switch(slice)
+		{
+		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
+	u8 checkSliceRounding(u8 slice)
+	{
+		switch(slice)
+		{
+		case 0:
+			return this->low >> 20 & 0x3;
+		
+		case 1:
+			return this->low >> 22 & 0x3;
+		}
+	}
+
+	//Single Precision Exception Flags (all 3 slices)
+	//slice -> slice number (0-3)
+	//exception: 1 -> Overflow 2 -> Underflow 4-> Diff (could be IE^3 non compliant)
+	void setSinglePrecisionExceptionFlags(u8 slice, u8 exception)
+	{
+		u64 mask = exception;
+		switch(slice)
+		{
+		case 0:
+			mask = mask << 29;
+			this->low = this->low & mask;
+			break;
+		case 1: 
+			mask = mask << 61;
+			this->low = this->low & mask;
+			break;
+		case 2:
+			mask = mask << 29;
+			this->hi = this->hi & mask;
+			break;
+		case 3:
+			mask = mask << 61;
+			this->hi = this->hi & mask;
+			break;
+		}
+		
+	}
+	
+};
+
 union SPU_GPR_hdr
 {
 	u128 _u128;
@@ -169,6 +252,7 @@ class SPUThread : public PPCThread
 public:
 	SPU_GPR_hdr GPR[128]; //General-Purpose Register
 	SPU_SPR_hdr SPR[128]; //Special-Purpose Registers
+	FPSCR FPSCR;
 
 	template<size_t _max_count>
 	class Channel