diff --git a/rpcs3/Emu/Cell/SPUDisAsm.h b/rpcs3/Emu/Cell/SPUDisAsm.h index ac1008273f..c0eee0044a 100644 --- a/rpcs3/Emu/Cell/SPUDisAsm.h +++ b/rpcs3/Emu/Cell/SPUDisAsm.h @@ -94,7 +94,7 @@ private: } void MFSPR(u32 rt, u32 sa) { - DisAsm("mfspr", spu_reg_name[rt], spu_reg_name[sa]); // Are SPR mapped on the GPR or are there 128 additional registers ? + DisAsm("mfspr", spu_reg_name[rt], spu_reg_name[sa]); // Are SPR mapped on the GPR or are there 128 additional registers ? Yes, there are also 128 SPR making 256 registers total } void RDCH(u32 rt, u32 ra) { @@ -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 0926dae80d..69eb99009b 100644 --- a/rpcs3/Emu/Cell/SPUInterpreter.h +++ b/rpcs3/Emu/Cell/SPUInterpreter.h @@ -44,7 +44,17 @@ private: } void MFSPR(u32 rt, u32 sa) { - UNIMPLEMENTED(); + //If register is a dummy register (register labeled 0x0) + if(sa == 0x0) + { + CPU.GPR[rt]._u128.hi = 0x0; + CPU.GPR[rt]._u128.lo = 0x0; + } + else + { + CPU.GPR[rt]._u128.hi = CPU.SPR[sa]._u128.hi; + CPU.GPR[rt]._u128.lo = CPU.SPR[sa]._u128.lo; + } } void RDCH(u32 rt, u32 ra) { @@ -250,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) { @@ -297,7 +311,7 @@ private: void IRET(u32 ra) { UNIMPLEMENTED(); - // SetBranch(SRR0); + //SetBranch(SRR0); } void BISLED(u32 rt, u32 ra) { @@ -618,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) { @@ -747,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) { @@ -814,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) @@ -890,7 +916,7 @@ private: void MPYU(u32 rt, u32 ra, u32 rb) { for (int w = 0; w < 4; w++) - CPU.GPR[rt]._u32[w] = CPU.GPR[ra]._u16[w*2 + 1] * CPU.GPR[rb]._u16[w*2 + 1]; + CPU.GPR[rt]._u32[w] = CPU.GPR[ra]._u16[w*2] * CPU.GPR[rb]._u16[w*2]; } void CEQB(u32 rt, u32 ra, u32 rb) { 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 7f9d58c13c..2031805718 100644 --- a/rpcs3/Emu/Cell/SPUThread.h +++ b/rpcs3/Emu/Cell/SPUThread.h @@ -22,6 +22,25 @@ static const wxString spu_reg_name[128] = "$112", "$113", "$114", "$115", "$116", "$117", "$118", "$119", "$120", "$121", "$122", "$123", "$124", "$125", "$126", "$127", }; +//SPU reg $0 is a dummy reg, and is used for certain instructions. +static const wxString spu_specialreg_name[128] = { + "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7", + "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", + "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23", + "$24", "$25", "$26", "$27", "$28", "$29", "$30", "$31", + "$32", "$33", "$34", "$35", "$36", "$37", "$38", "$39", + "$40", "$41", "$42", "$43", "$44", "$45", "$46", "$47", + "$48", "$49", "$50", "$51", "$52", "$53", "$54", "$55", + "$56", "$57", "$58", "$59", "$60", "$61", "$62", "$63", + "$64", "$65", "$66", "$67", "$68", "$69", "$70", "$71", + "$72", "$73", "$74", "$75", "$76", "$77", "$78", "$79", + "$80", "$81", "$82", "$83", "$84", "$85", "$86", "$87", + "$88", "$89", "$90", "$91", "$92", "$93", "$94", "$95", + "$96", "$97", "$98", "$99", "$100", "$101", "$102", "$103", + "$104", "$105", "$106", "$107", "$108", "$109", "$110", "$111", + "$112", "$113", "$114", "$115", "$116", "$117", "$118", "$119", + "$120", "$121", "$122", "$123", "$124", "$125", "$126", "$127", +}; static const wxString spu_ch_name[128] = { @@ -98,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; @@ -126,10 +228,31 @@ union SPU_GPR_hdr } }; +union SPU_SPR_hdr +{ + u128 _u128; + s128 _i128; + + + SPU_SPR_hdr() {} + + wxString ToString() const + { + return wxString::Format("%16%16", _u128.hi, _u128.lo); + } + + void Reset() + { + memset(this, 0, sizeof(*this)); + } +}; + class SPUThread : public PPCThread { public: SPU_GPR_hdr GPR[128]; //General-Purpose Register + SPU_SPR_hdr SPR[128]; //Special-Purpose Registers + FPSCR FPSCR; template class Channel