void Jit::Comp_mxc1(u32 op) { CONDITIONAL_DISABLE; int fs = _FS; int rt = _RT; switch ((op >> 21) & 0x1f) { case 0: // R(rt) = FI(fs); break; //mfc1 // Let's just go through RAM for now. fpr.FlushR(fs); gpr.MapReg(rt, MAP_DIRTY | MAP_NOINIT); LDR(gpr.R(rt), CTXREG, fpr.GetMipsRegOffset(fs)); return; case 2: //cfc1 if (fs == 31) { gpr.MapReg(rt, MAP_DIRTY | MAP_NOINIT); LDR(R0, CTXREG, offsetof(MIPSState, fpcond)); AND(R0, R0, Operand2(1)); // Just in case LDR(gpr.R(rt), CTXREG, offsetof(MIPSState, fcr31)); BIC(gpr.R(rt), gpr.R(rt), Operand2(0x1 << 23)); ORR(gpr.R(rt), gpr.R(rt), Operand2(R0, ST_LSL, 23)); } else if (fs == 0) { gpr.MapReg(rt, MAP_DIRTY | MAP_NOINIT); LDR(gpr.R(rt), CTXREG, offsetof(MIPSState, fcr0)); } return; case 4: //FI(fs) = R(rt); break; //mtc1 // Let's just go through RAM for now. gpr.FlushR(rt); fpr.MapReg(fs, MAP_DIRTY | MAP_NOINIT); VLDR(fpr.R(fs), CTXREG, gpr.GetMipsRegOffset(rt)); return; case 6: //ctc1 if (fs == 31) { gpr.MapReg(rt, 0); // Hardware rounding method. // Left here in case it is faster than conditional method. /* AND(R0, gpr.R(rt), Operand2(3)); // MIPS Rounding Mode <-> ARM Rounding Mode // 0, 1, 2, 3 <-> 0, 3, 1, 2 CMP(R0, Operand2(1)); SetCC(CC_EQ); ADD(R0, R0, Operand2(2)); SetCC(CC_GT); SUB(R0, R0, Operand2(1)); SetCC(CC_AL); // Load and Store RM to FPSCR VMRS(R1); BIC(R1, R1, Operand2(0x3 << 22)); ORR(R1, R1, Operand2(R0, ST_LSL, 22)); VMSR(R1); */ // Update MIPS state STR(gpr.R(rt), CTXREG, offsetof(MIPSState, fcr31)); MOV(R0, Operand2(gpr.R(rt), ST_LSR, 23)); AND(R0, R0, Operand2(1)); STR(R0, CTXREG, offsetof(MIPSState, fpcond)); } return; } }
void Jit::Comp_FPU2op(u32 op) { CONDITIONAL_DISABLE; int fs = _FS; int fd = _FD; switch (op & 0x3f) { case 4: //F(fd) = sqrtf(F(fs)); break; //sqrt fpr.MapDirtyIn(fd, fs); VSQRT(fpr.R(fd), fpr.R(fs)); break; case 5: //F(fd) = fabsf(F(fs)); break; //abs fpr.MapDirtyIn(fd, fs); VABS(fpr.R(fd), fpr.R(fs)); break; case 6: //F(fd) = F(fs); break; //mov fpr.MapDirtyIn(fd, fs); VMOV(fpr.R(fd), fpr.R(fs)); break; case 7: //F(fd) = -F(fs); break; //neg fpr.MapDirtyIn(fd, fs); VNEG(fpr.R(fd), fpr.R(fs)); break; case 12: //FsI(fd) = (int)floorf(F(fs)+0.5f); break; //round.w.s fpr.MapDirtyIn(fd, fs); VCVT(fpr.R(fd), fpr.R(fs), TO_INT | IS_SIGNED); break; case 13: //FsI(fd) = Rto0(F(fs))); break; //trunc.w.s fpr.MapDirtyIn(fd, fs); VCVT(fpr.R(fd), fpr.R(fs), TO_INT | IS_SIGNED | ROUND_TO_ZERO); break; case 14: //FsI(fd) = (int)ceilf (F(fs)); break; //ceil.w.s fpr.MapDirtyIn(fd, fs); MOVI2F(S0, 0.5f, R0); VADD(S0,fpr.R(fs),S0); VCVT(fpr.R(fd), S0, TO_INT | IS_SIGNED); break; case 15: //FsI(fd) = (int)floorf(F(fs)); break; //floor.w.s fpr.MapDirtyIn(fd, fs); MOVI2F(S0, 0.5f, R0); VSUB(S0,fpr.R(fs),S0); VCVT(fpr.R(fd), S0, TO_INT | IS_SIGNED); break; case 32: //F(fd) = (float)FsI(fs); break; //cvt.s.w fpr.MapDirtyIn(fd, fs); VCVT(fpr.R(fd), fpr.R(fs), TO_FLOAT | IS_SIGNED); break; case 36: //FsI(fd) = (int) F(fs); break; //cvt.w.s fpr.MapDirtyIn(fd, fs); LDR(R0, CTXREG, offsetof(MIPSState, fcr31)); AND(R0, R0, Operand2(3)); // MIPS Rounding Mode: // 0: Round nearest // 1: Round to zero // 2: Round up (ceil) // 3: Round down (floor) CMP(R0, Operand2(2)); SetCC(CC_GE); MOVI2F(S0, 0.5f, R1); SetCC(CC_GT); VSUB(S0,fpr.R(fs),S0); SetCC(CC_EQ); VADD(S0,fpr.R(fs),S0); SetCC(CC_GE); VCVT(fpr.R(fd), S0, TO_INT | IS_SIGNED); /* 2,3 */ SetCC(CC_AL); CMP(R0, Operand2(1)); SetCC(CC_EQ); VCVT(fpr.R(fd), fpr.R(fs), TO_INT | IS_SIGNED | ROUND_TO_ZERO); /* 1 */ SetCC(CC_LT); VCVT(fpr.R(fd), fpr.R(fs), TO_INT | IS_SIGNED); /* 0 */ SetCC(CC_AL); break; default: DISABLE; } }
void JitArm::ps_cmpo1(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(bJITFloatingPointOff); u32 a = inst.FA, b = inst.FB; int cr = inst.CRFD; ARMReg vA = fpr.R1(a); ARMReg vB = fpr.R1(b); ARMReg fpscrReg = gpr.GetReg(); ARMReg crReg = gpr.GetReg(); Operand2 FPRFMask(0x1F, 0xA); // 0x1F000 Operand2 LessThan(0x8, 0xA); // 0x8000 Operand2 GreaterThan(0x4, 0xA); // 0x4000 Operand2 EqualTo(0x2, 0xA); // 0x2000 Operand2 NANRes(0x1, 0xA); // 0x1000 FixupBranch Done1, Done2, Done3; LDR(fpscrReg, R9, PPCSTATE_OFF(fpscr)); BIC(fpscrReg, fpscrReg, FPRFMask); VCMPE(vA, vB); VMRS(_PC); SetCC(CC_LT); ORR(fpscrReg, fpscrReg, LessThan); MOV(crReg, 8); Done1 = B(); SetCC(CC_GT); ORR(fpscrReg, fpscrReg, GreaterThan); MOV(crReg, 4); Done2 = B(); SetCC(CC_EQ); ORR(fpscrReg, fpscrReg, EqualTo); MOV(crReg, 2); Done3 = B(); SetCC(); ORR(fpscrReg, fpscrReg, NANRes); MOV(crReg, 1); VCMPE(vA, vA); VMRS(_PC); FixupBranch NanA = B_CC(CC_NEQ); VCMPE(vB, vB); VMRS(_PC); FixupBranch NanB = B_CC(CC_NEQ); SetFPException(fpscrReg, FPSCR_VXVC); FixupBranch Done4 = B(); SetJumpTarget(NanA); SetJumpTarget(NanB); SetFPException(fpscrReg, FPSCR_VXSNAN); TST(fpscrReg, VEMask); FixupBranch noVXVC = B_CC(CC_NEQ); SetFPException(fpscrReg, FPSCR_VXVC); SetJumpTarget(noVXVC); SetJumpTarget(Done1); SetJumpTarget(Done2); SetJumpTarget(Done3); SetJumpTarget(Done4); STRB(crReg, R9, PPCSTATE_OFF(cr_fast) + cr); STR(fpscrReg, R9, PPCSTATE_OFF(fpscr)); gpr.Unlock(fpscrReg, crReg); }
int assignExprCodegen(c_tree tree, int *registerNo, int topLevel, int getAddress, const char *breakLabel, const char *continueLabel) { c_tree rhs = TREE_EXPR_OPERAND(tree,1); c_tree lhs = TREE_EXPR_OPERAND(tree,0); if (TREE_CODE(lhs) == TREE_DECL && (strcmp(DECL_NAME_STRING(lhs), COUT) == 0)) { int rhsValue = c_codegen_recurse(rhs, registerNo, FALSE, FALSE, breakLabel, continueLabel); ADDi(R0, rhsValue, 0, "copying into R0", NULL); COUTASM("Displaying to COUT", ""); return R0; } else { c_tree type = get_type_for_uid(TYPE(TREE_TYPE(lhs))->uid); int typeSize = getSize(TREE_TYPE(lhs)); if(TYPE(type)->code!=STRUCT_TYPE || typeSize==1 ) { int rhsValue = c_codegen_recurse(rhs, registerNo, FALSE, FALSE, breakLabel, continueLabel); int lhsAddress = c_codegen_recurse(lhs, registerNo, FALSE, TRUE, breakLabel, continueLabel); STRi(rhsValue, lhsAddress, 0, "assignment", NULL); } else { int rhsAddress = c_codegen_recurse(rhs, registerNo, FALSE, TRUE, breakLabel, continueLabel); int lhsAddress = c_codegen_recurse(lhs, registerNo, FALSE, TRUE, breakLabel, continueLabel); static int copyCondLabelNo = 0; static char copyCondLabelPrefix[] = "SCC"; char copyCondLabelArray[LABEL_ARRAY_LENGTH]; static int copyEndLabelNo = 0; static char copyEndLabelPrefix[] = "SCE"; char copyEndLabelArray[LABEL_ARRAY_LENGTH]; sprintf(copyCondLabelArray, "%s%d", copyCondLabelPrefix, copyCondLabelNo++); sprintf(copyEndLabelArray, "%s%d", copyEndLabelPrefix, copyEndLabelNo++); int counterRegister = (*registerNo)++; int subResultRegister = (*registerNo)++; int tempCopyRegister = (*registerNo)++; // loop for copying SET(counterRegister, 0, "struct copy counter initial value", NULL); SUBi(subResultRegister, counterRegister, typeSize, "struct copy condition to end copying", copyCondLabelArray); BRnzp(subResultRegister, copyEndLabelArray, "struct copy branch to end", NULL, "z"); LDR(tempCopyRegister, rhsAddress, counterRegister, "struct assignment", NULL); STR(tempCopyRegister, lhsAddress, counterRegister, "struct assignment", NULL); ADDi(counterRegister, counterRegister, 1, "struct copy increment counter", NULL); BRA(copyCondLabelArray, "struct copy branch to condition", NULL); NOP("end of struct copying", copyEndLabelArray); } return c_codegen_recurse(lhs, registerNo, topLevel, getAddress, breakLabel, continueLabel); } }
void JitArm::lXX(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(bJITLoadStoreOff) u32 a = inst.RA, b = inst.RB, d = inst.RD; s32 offset = inst.SIMM_16; u32 accessSize = 0; s32 offsetReg = -1; bool zeroA = true; bool update = false; bool signExtend = false; bool reverse = false; bool fastmem = false; switch(inst.OPCD) { case 31: switch(inst.SUBOP10) { case 55: // lwzux zeroA = false; update = true; case 23: // lwzx accessSize = 32; offsetReg = b; break; case 119: //lbzux zeroA = false; update = true; case 87: // lbzx accessSize = 8; offsetReg = b; break; case 311: // lhzux zeroA = false; update = true; case 279: // lhzx accessSize = 16; offsetReg = b; break; case 375: // lhaux zeroA = false; update = true; case 343: // lhax accessSize = 16; signExtend = true; offsetReg = b; break; case 534: // lwbrx accessSize = 32; reverse = true; break; case 790: // lhbrx accessSize = 16; reverse = true; break; } break; case 33: // lwzu zeroA = false; update = true; case 32: // lwz fastmem = true; accessSize = 32; break; case 35: // lbzu zeroA = false; update = true; case 34: // lbz fastmem = true; accessSize = 8; break; case 41: // lhzu zeroA = false; update = true; case 40: // lhz fastmem = true; accessSize = 16; break; case 43: // lhau zeroA = false; update = true; case 42: // lha signExtend = true; accessSize = 16; break; } // Check for exception before loading ARMReg rA = gpr.GetReg(false); LDR(rA, R9, PPCSTATE_OFF(Exceptions)); CMP(rA, EXCEPTION_DSI); FixupBranch DoNotLoad = B_CC(CC_EQ); SafeLoadToReg(fastmem, d, zeroA ? a ? a : -1 : a, offsetReg, accessSize, offset, signExtend, reverse); if (update) { rA = gpr.GetReg(false); ARMReg RA = gpr.R(a); if (offsetReg == -1) MOVI2R(rA, offset); else MOV(RA, gpr.R(offsetReg)); ADD(RA, RA, rA); } SetJumpTarget(DoNotLoad); // LWZ idle skipping if (SConfig::GetInstance().m_LocalCoreStartupParameter.bSkipIdle && inst.OPCD == 32 && (inst.hex & 0xFFFF0000) == 0x800D0000 && (Memory::ReadUnchecked_U32(js.compilerPC + 4) == 0x28000000 || (SConfig::GetInstance().m_LocalCoreStartupParameter.bWii && Memory::ReadUnchecked_U32(js.compilerPC + 4) == 0x2C000000)) && Memory::ReadUnchecked_U32(js.compilerPC + 8) == 0x4182fff8) { ARMReg RD = gpr.R(d); gpr.Flush(); fpr.Flush(); // if it's still 0, we can wait until the next event TST(RD, RD); FixupBranch noIdle = B_CC(CC_NEQ); rA = gpr.GetReg(); MOVI2R(rA, (u32)&PowerPC::OnIdle); MOVI2R(R0, PowerPC::ppcState.gpr[a] + (s32)(s16)inst.SIMM_16); BL(rA); gpr.Unlock(rA); WriteExceptionExit(); SetJumpTarget(noIdle); //js.compilerPC += 8; return; } }
void JitArm::stX(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(bJITLoadStoreOff) u32 a = inst.RA, b = inst.RB, s = inst.RS; s32 offset = inst.SIMM_16; u32 accessSize = 0; s32 regOffset = -1; bool zeroA = true; bool update = false; bool fastmem = false; switch(inst.OPCD) { case 45: // sthu update = true; case 44: // sth accessSize = 16; break; case 31: switch (inst.SUBOP10) { case 183: // stwux zeroA = false; update = true; case 151: // stwx fastmem = true; accessSize = 32; regOffset = b; break; case 247: // stbux zeroA = false; update = true; case 215: // stbx accessSize = 8; regOffset = b; break; case 439: // sthux zeroA = false; update = true; case 407: // sthx accessSize = 16; regOffset = b; break; } break; case 37: // stwu update = true; case 36: // stw fastmem = true; accessSize = 32; break; case 39: // stbu update = true; case 38: // stb accessSize = 8; break; } SafeStoreFromReg(fastmem, zeroA ? a ? a : -1 : a, s, regOffset, accessSize, offset); if (update) { ARMReg rA = gpr.GetReg(); ARMReg RB; ARMReg RA = gpr.R(a); if (regOffset != -1) RB = gpr.R(regOffset); // Check for DSI exception prior to writing back address LDR(rA, R9, PPCSTATE_OFF(Exceptions)); CMP(rA, EXCEPTION_DSI); FixupBranch DoNotWrite = B_CC(CC_EQ); if (a) { if (regOffset == -1) MOVI2R(rA, offset); else MOV(rA, RB); ADD(RA, RA, rA); } else if (regOffset == -1) MOVI2R(RA, (u32)offset); else MOV(RA, RB); SetJumpTarget(DoNotWrite); gpr.Unlock(rA); } }