From 3eb5480adeec8896e57f938c8cd667eea65829a6 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Sun, 8 May 2016 13:32:22 +0200 Subject: [PATCH] Initial VFPU --- Core/MIPS/IR/IRCompVFPU.cpp | 66 +++++++++++++++++++++++++++++++++++-- Core/MIPS/IR/IRInst.cpp | 53 ++++++++++++++++++++++++++++- Core/MIPS/IR/IRInst.h | 7 +++- 3 files changed, 122 insertions(+), 4 deletions(-) diff --git a/Core/MIPS/IR/IRCompVFPU.cpp b/Core/MIPS/IR/IRCompVFPU.cpp index d7b807fe63..1f2623ac67 100644 --- a/Core/MIPS/IR/IRCompVFPU.cpp +++ b/Core/MIPS/IR/IRCompVFPU.cpp @@ -181,7 +181,38 @@ namespace MIPSComp { } void IRJit::Comp_SVQ(MIPSOpcode op) { - DISABLE; + int imm = (signed short)(op & 0xFFFC); + int vt = (((op >> 16) & 0x1f)) | ((op & 1) << 5); + MIPSGPReg rs = _RS; + + u8 vregs[4]; + GetVectorRegs(vregs, V_Quad, vt); + + switch (op >> 26) { + case 54: //lv.q + { + // TODO: Add vector load/store instruction to the IR + ir.Write(IROp::LoadFloatV, vregs[0], rs, ir.AddConstant(imm)); + ir.Write(IROp::LoadFloatV, vregs[1], rs, ir.AddConstant(imm + 4)); + ir.Write(IROp::LoadFloatV, vregs[2], rs, ir.AddConstant(imm + 8)); + ir.Write(IROp::LoadFloatV, vregs[3], rs, ir.AddConstant(imm + 12)); + } + break; + + case 62: //sv.q + { + // CC might be set by slow path below, so load regs first. + ir.Write(IROp::StoreFloatV, vregs[0], rs, ir.AddConstant(imm)); + ir.Write(IROp::StoreFloatV, vregs[1], rs, ir.AddConstant(imm + 4)); + ir.Write(IROp::StoreFloatV, vregs[2], rs, ir.AddConstant(imm + 8)); + ir.Write(IROp::StoreFloatV, vregs[3], rs, ir.AddConstant(imm + 12)); + } + break; + + default: + DISABLE; + break; + } } void IRJit::Comp_VVectorInit(MIPSOpcode op) { @@ -215,6 +246,11 @@ namespace MIPSComp { } void IRJit::Comp_VV2Op(MIPSOpcode op) { + CONDITIONAL_DISABLE; + // Pre-processing: Eliminate silly no-op VMOVs, common in Wipeout Pure + if (((op >> 16) & 0x1f) == 0 && _VS == _VD && js.HasNoPrefix()) { + return; + } DISABLE; } @@ -231,7 +267,33 @@ namespace MIPSComp { } void IRJit::Comp_Mftv(MIPSOpcode op) { - DISABLE; + int imm = op & 0xFF; + MIPSGPReg rt = _RT; + switch ((op >> 21) & 0x1f) { + case 3: //mfv / mfvc + // rt = 0, imm = 255 appears to be used as a CPU interlock by some games. + if (rt != 0) { + if (imm < 128) { //R(rt) = VI(imm); + ir.Write(IROp::VMovToGPR, rt, imm); + logBlocks = 1; + } else { + DISABLE; + } + } + break; + + case 7: // mtv + if (imm < 128) { + ir.Write(IROp::VMovFromGPR, imm, rt); + logBlocks = 1; + } else { + DISABLE; + } + break; + + default: + DISABLE; + } } void IRJit::Comp_Vmfvc(MIPSOpcode op) { diff --git a/Core/MIPS/IR/IRInst.cpp b/Core/MIPS/IR/IRInst.cpp index 1a184e00eb..45902a4485 100644 --- a/Core/MIPS/IR/IRInst.cpp +++ b/Core/MIPS/IR/IRInst.cpp @@ -10,6 +10,8 @@ static const IRMeta irMeta[] = { { IROp::SetConst, "SetConst", "GC" }, + { IROp::SetConstF, "SetConstF", "FC" }, + { IROp::SetConstV, "SetConstV", "VC" }, { IROp::Mov, "Mov", "GG" }, { IROp::Add, "Add", "GGG" }, { IROp::Sub, "Sub", "GGG" }, @@ -62,10 +64,12 @@ static const IRMeta irMeta[] = { { IROp::Load16Ext, "Load16Ext", "GGC" }, { IROp::Load32, "Load32", "GGC" }, { IROp::LoadFloat, "LoadFloat", "FGC" }, + { IROp::LoadFloatV, "LoadFloatV", "VGC" }, { IROp::Store8, "Store8", "GGC" }, { IROp::Store16, "Store16", "GGC" }, { IROp::Store32, "Store32", "GGC" }, { IROp::StoreFloat, "StoreFloat", "FGC" }, + { IROp::StoreFloatV, "StoreFloatV", "VGC" }, { IROp::FAdd, "FAdd", "FFF" }, { IROp::FSub, "FSub", "FFF" }, { IROp::FMul, "FMul", "FFF" }, @@ -82,6 +86,8 @@ static const IRMeta irMeta[] = { { IROp::FCvtSW, "FCvtSW", "FF" }, { IROp::FMovFromGPR, "FMovFromGPR", "FG" }, { IROp::FMovToGPR, "FMovToGPR", "GF" }, + { IROp::VMovFromGPR, "VMovFromGPR", "VG" }, + { IROp::VMovToGPR, "VMovToGPR", "GV" }, { IROp::FpCondToReg, "FpCondToReg", "G" }, { IROp::VfpuCtrlToReg, "VfpuCtrlToReg", "GI" }, { IROp::SetCtrlVFPU, "SetCtrlVFPU", "TC" }, @@ -117,6 +123,12 @@ u32 IRInterpret(MIPSState *mips, const IRInst *inst, const u32 *constPool, int c case IROp::SetConst: mips->r[inst->dest] = constPool[inst->src1]; break; + case IROp::SetConstF: + memcpy(&mips->f[inst->dest], &constPool[inst->src1], 4); + break; + case IROp::SetConstV: + memcpy(&mips->f[inst->dest], &constPool[inst->src1], 4); + break; case IROp::Add: mips->r[inst->dest] = mips->r[inst->src1] + mips->r[inst->src2]; break; @@ -181,6 +193,9 @@ u32 IRInterpret(MIPSState *mips, const IRInst *inst, const u32 *constPool, int c case IROp::LoadFloat: mips->f[inst->dest] = Memory::ReadUnchecked_Float(mips->r[inst->src1] + constPool[inst->src2]); break; + case IROp::LoadFloatV: + mips->v[voffset[inst->dest]] = Memory::ReadUnchecked_Float(mips->r[inst->src1] + constPool[inst->src2]); + break; case IROp::Store8: Memory::WriteUnchecked_U8(mips->r[inst->src3], mips->r[inst->src1] + constPool[inst->src2]); @@ -194,6 +209,9 @@ u32 IRInterpret(MIPSState *mips, const IRInst *inst, const u32 *constPool, int c case IROp::StoreFloat: Memory::WriteUnchecked_Float(mips->f[inst->src3], mips->r[inst->src1] + constPool[inst->src2]); break; + case IROp::StoreFloatV: + Memory::WriteUnchecked_Float(mips->v[voffset[inst->src3]], mips->r[inst->src1] + constPool[inst->src2]); + break; case IROp::ShlImm: mips->r[inst->dest] = mips->r[inst->src1] << (int)inst->src2; @@ -389,6 +407,7 @@ u32 IRInterpret(MIPSState *mips, const IRInst *inst, const u32 *constPool, int c } break; //cvt.w.s } + case IROp::ZeroFpCond: mips->fpcond = 0; break; @@ -400,6 +419,13 @@ u32 IRInterpret(MIPSState *mips, const IRInst *inst, const u32 *constPool, int c memcpy(&mips->r[inst->dest], &mips->f[inst->src1], 4); break; + case IROp::VMovFromGPR: + memcpy(&mips->v[voffset[inst->dest]], &mips->r[inst->src1], 4); + break; + case IROp::VMovToGPR: + memcpy(&mips->r[inst->dest], &mips->v[voffset[inst->src1]], 4); + break; + case IROp::ExitToConst: return constPool[inst->dest]; @@ -540,12 +566,31 @@ const char *GetGPRName(int r) { } void DisassembleParam(char *buf, int bufSize, u8 param, char type, const u32 *constPool) { + static const char *vfpuCtrlNames[VFPU_CTRL_MAX] = { + "SPFX", + "TPFX", + "DPFX", + "CC", + "INF4", + "RSV5", + "RSV6", + "REV", + "RCX0", + "RCX1", + "RCX2", + "RCX3", + "RCX4", + "RCX5", + "RCX6", + "RCX7", + }; + switch (type) { case 'G': snprintf(buf, bufSize, "%s", GetGPRName(param)); break; case 'F': - snprintf(buf, bufSize, "r%d", param); + snprintf(buf, bufSize, "f%d", param); break; case 'C': snprintf(buf, bufSize, "%08x", constPool[param]); @@ -553,6 +598,12 @@ void DisassembleParam(char *buf, int bufSize, u8 param, char type, const u32 *co case 'I': snprintf(buf, bufSize, "%02x", param); break; + case 'V': + snprintf(buf, bufSize, "v%d", param); + break; + case 'T': + snprintf(buf, bufSize, "%s", vfpuCtrlNames[param]); + break; case '_': case '\0': buf[0] = 0; diff --git a/Core/MIPS/IR/IRInst.h b/Core/MIPS/IR/IRInst.h index 062d5189ab..b19651e3d8 100644 --- a/Core/MIPS/IR/IRInst.h +++ b/Core/MIPS/IR/IRInst.h @@ -17,7 +17,8 @@ enum class IROp : u8 { SetConst, - FSetConst, + SetConstF, + SetConstV, Mov, @@ -88,11 +89,13 @@ enum class IROp : u8 { Load16Ext, Load32, LoadFloat, + LoadFloatV, Store8, Store16, Store32, StoreFloat, + StoreFloatV, Ext8to32, Ext16to32, @@ -136,6 +139,8 @@ enum class IROp : u8 { UpdateRoundingMode, SetCtrlVFPU, + VMovFromGPR, + VMovToGPR, // Fake/System instructions Interpret,