📄 fpu.c
字号:
EXCEPTION(P, EXC_II); return C1_CONTINUE; } if (DoubleReg(fs) == 0.0) { CPUWarning("MIPSY: FDIV divide by zero\n"); } DoubleReg(fd) = 1.0 / DoubleReg(fs); SIM_DEBUG(('f', "C1:FRECIP.D f%d %Le / f%d %Le = f%d %Le\n", fs, DoubleReg(fs), ft, DoubleReg(ft), fd, DoubleReg(fd))); break; } case frsqrt_op+F_SSINGLE: statusReg.ts_data = P->CP0[C0_SR]; /* Make sure we can execute mips4 instructions */ if (IS_USER_MODE(P) && !(statusReg.s32.ts_xx)) { EXCEPTION(P, EXC_II); return C1_CONTINUE; } if (FloatReg(fs) == 0.0) { CPUWarning("MIPSY: FRSQRT divide by zero\n"); } FloatReg(fd) = 1.0 / (float)sqrt((double)FloatReg(fs)); break; case frsqrt_op+F_SDOUBLE: statusReg.ts_data = P->CP0[C0_SR]; /* Make sure we can execute mips4 instructions */ if (IS_USER_MODE(P) && !(statusReg.s32.ts_xx)) { EXCEPTION(P, EXC_II); return C1_CONTINUE; } if (DoubleReg(fs) == 0.0) { CPUWarning("MIPSY: FDIV divide by zero\n"); } DoubleReg(fd) = 1.0 / sqrt(DoubleReg(fs)); break; case fround_op+F_SSINGLE: IntReg(fd) = (FloatReg(fs) > 0.0 ? FloatReg(fs) + 0.5 : FloatReg(fs) - 0.5 ); break; case fround_op+F_SDOUBLE: IntReg(fd) = (DoubleReg(fs) > 0.0 ? DoubleReg(fs) + 0.5 : DoubleReg(fs) - 0.5 ); break; case froundl_op+F_SSINGLE: CHECK_64BIT_ALLOWED(P); LongLongReg(fd) = (FloatReg(fs) > 0.0 ? FloatReg(fs) + 0.5 : FloatReg(fs) - 0.5 ); break; case froundl_op+F_SDOUBLE: CHECK_64BIT_ALLOWED(P); LongLongReg(fd) = (DoubleReg(fs) > 0.0 ? DoubleReg(fs) + 0.5 : DoubleReg(fs) - 0.5 ); break; case fceil_op+F_SSINGLE: IntReg(fd) = (FloatReg(fs) >= 0.0 ? FloatReg(fs) + SP_NEAR_ONE : FloatReg(fs) ); break; case fceil_op+F_SDOUBLE: IntReg(fd) = (DoubleReg(fs) >= 0.0 ? DoubleReg(fs) + DP_NEAR_ONE : DoubleReg(fs) ); break; case fceill_op+F_SSINGLE: CHECK_64BIT_ALLOWED(P); LongLongReg(fd) = (FloatReg(fs) >= 0.0 ? FloatReg(fs) + SP_NEAR_ONE : FloatReg(fs) ); break; case fceill_op+F_SDOUBLE: CHECK_64BIT_ALLOWED(P); LongLongReg(fd) = (DoubleReg(fs) >= 0.0 ? DoubleReg(fs) + DP_NEAR_ONE : DoubleReg(fs) ); break; /* floating point comparison operations */ case F_C_EQ+F_SSINGLE: if (FloatReg(fs) == FloatReg(ft)) P->FCR[31] |= M_csr_c; else P->FCR[31] &= ~M_csr_c; break; case F_C_EQ+F_SDOUBLE: if (DoubleReg(fs) == DoubleReg(ft)) P->FCR[31] |= M_csr_c; else P->FCR[31] &= ~M_csr_c; break; case F_C_NGL+F_SSINGLE: if (FloatReg(fs) == FloatReg(ft)) IntReg(fd) |= CONDBIT; else P->FCR[31] &= ~M_csr_c; break; case F_C_NGL+F_SDOUBLE: if (DoubleReg(fs) == DoubleReg(ft)) P->FCR[31] |= M_csr_c; else P->FCR[31] &= ~M_csr_c; break; case F_C_LE+F_SSINGLE: if (FloatReg(fs) <= FloatReg(ft)) P->FCR[31] |= M_csr_c; else P->FCR[31] &= ~M_csr_c; break; case F_C_LE+F_SDOUBLE: if (DoubleReg(fs) <= DoubleReg(ft)) P->FCR[31] |= M_csr_c; else P->FCR[31] &= ~M_csr_c; break; case F_C_LT+F_SSINGLE: if (FloatReg(fs) < FloatReg(ft)) P->FCR[31] |= M_csr_c; else P->FCR[31] &= ~M_csr_c; break; case F_C_LT+F_SDOUBLE: if (DoubleReg(fs) < DoubleReg(ft)) P->FCR[31] |= M_csr_c; else P->FCR[31] &= ~M_csr_c; break; case F_C_NGE+F_SSINGLE: if (FloatReg(fs) < FloatReg(ft)) P->FCR[31] |= M_csr_c; else P->FCR[31] &= ~M_csr_c; break; case F_C_NGE+F_SDOUBLE: if (DoubleReg(fs) < DoubleReg(ft)) P->FCR[31] |= M_csr_c; else P->FCR[31] &= ~M_csr_c; break; case F_C_NGLE+F_SSINGLE: P->FCR[31] &= ~M_csr_c; break; case F_C_NGLE+F_SDOUBLE: P->FCR[31] &= ~M_csr_c; break; case F_C_NGT+F_SSINGLE: if (FloatReg(fs) <= FloatReg(ft)) P->FCR[31] |= M_csr_c; else P->FCR[31] &= ~M_csr_c; break; case F_C_NGT+F_SDOUBLE: if (DoubleReg(fs) <= DoubleReg(ft)) P->FCR[31] |= M_csr_c; else P->FCR[31] &= ~M_csr_c; break; case F_C_OLE+F_SSINGLE: if (FloatReg(fs) < FloatReg(ft)) P->FCR[31] |= M_csr_c; else P->FCR[31] &= ~M_csr_c; break; case F_C_OLE+F_SDOUBLE: if (DoubleReg(fs) < DoubleReg(ft)) P->FCR[31] |= M_csr_c; else P->FCR[31] &= ~M_csr_c; break; case F_C_OLT+F_SSINGLE: if (FloatReg(fs) < FloatReg(ft)) P->FCR[31] |= M_csr_c; else P->FCR[31] &= ~M_csr_c; break; case F_C_OLT+F_SDOUBLE: if (DoubleReg(fs) < DoubleReg(ft)) { P->FCR[31] |= M_csr_c; } else { P->FCR[31] &= ~M_csr_c; } break; case F_C_SEQ+F_SSINGLE: if (FloatReg(fs) == FloatReg(ft)) P->FCR[31] |= M_csr_c; else P->FCR[31] &= ~M_csr_c; break; case F_C_SEQ+F_SDOUBLE: if (DoubleReg(fs) == DoubleReg(ft)) P->FCR[31] |= M_csr_c; else P->FCR[31] &= ~M_csr_c; break; case F_C_SF+F_SSINGLE: P->FCR[31] &= ~M_csr_c; break; case F_C_SF+F_SDOUBLE: P->FCR[31] &= ~M_csr_c; break; case F_C_UEQ+F_SSINGLE: if (FloatReg(fs) == FloatReg(ft)) P->FCR[31] |= M_csr_c; else P->FCR[31] &= ~M_csr_c; break; case F_C_UEQ+F_SDOUBLE: if (DoubleReg(fs) == DoubleReg(ft)) P->FCR[31] |= M_csr_c; else P->FCR[31] &= ~M_csr_c; break; case F_C_ULE+F_SSINGLE: if (FloatReg(fs) <= FloatReg(ft)) P->FCR[31] |= M_csr_c; else P->FCR[31] &= ~M_csr_c; break; case F_C_ULE+F_SDOUBLE: if (DoubleReg(fs) <= DoubleReg(ft)) P->FCR[31] |= M_csr_c; else P->FCR[31] &= ~M_csr_c; break; case F_C_ULT+F_SSINGLE: if (FloatReg(fs) < FloatReg(ft)) P->FCR[31] |= M_csr_c; else P->FCR[31] &= ~M_csr_c; break; case F_C_ULT+F_SDOUBLE: if (DoubleReg(fs) < DoubleReg(ft)) P->FCR[31] |= M_csr_c; else P->FCR[31] &= ~M_csr_c; break; case F_C_UN+F_SSINGLE: P->FCR[31] &= ~M_csr_c; break; case F_C_UN+F_SDOUBLE: P->FCR[31] &= ~M_csr_c; break; default: CPUWarning("ERROR!!! FPU instruction 0x%x unimplemented at PC 0x%llx\n", instr, (Reg64)P->PC); ASSERT(0); } /* cp1_function */ return C1_SUCCESS;}/***************************************************************** * MipsyFPU *****************************************************************/static Result MipsyFPUx(CPUState *P, Inst instr) { uint ft = FT(instr); /* 2nd source register */ uint fs = FS(instr); /* 1st source reg */ uint fr = FORMAT(instr); /* 3rd source reg. */ uint fd = FD(instr); /* destionation */ uint func = FUNC(instr); switch(func) { case madd_s_op: FloatReg(fd) = (FloatReg(fs) * FloatReg(ft)) + FloatReg(fr); break; case madd_d_op: DoubleReg(fd) = (DoubleReg(fs) * DoubleReg(ft)) + DoubleReg(fr); break; case msub_s_op: FloatReg(fd) = (FloatReg(fs) * FloatReg(ft)) - FloatReg(fr); break; case msub_d_op: DoubleReg(fd) = (DoubleReg(fs) * DoubleReg(ft)) - DoubleReg(fr); break; case nmadd_s_op: FloatReg(fd) = -((FloatReg(fs) * FloatReg(ft)) + FloatReg(fr)); break; case nmadd_d_op: DoubleReg(fd) = -((DoubleReg(fs) * DoubleReg(ft)) + DoubleReg(fr)); break; case nmsub_s_op: FloatReg(fd) = -((FloatReg(fs) * FloatReg(ft)) - FloatReg(fr)); break; case nmsub_d_op: DoubleReg(fd) = -((DoubleReg(fs) * DoubleReg(ft)) - DoubleReg(fr)); break; default: EXCEPTION(P, EXC_II); return C1_CONTINUE; } return C1_SUCCESS;}/***************************************************************** * Set the rounding mode of the host processor to match that of the * simulated machine. This is needed since we're actually executing the * instructions on the host platform. *****************************************************************/static void SetRoundingMode(int modeNum){#if defined(sgi) || defined(sparc) fp_rnd newMode = FP_RN; switch (modeNum) { case 0: newMode = FP_RN; break; case 1: newMode = FP_RZ; break; case 2: newMode = FP_RP; break; case 3: newMode = FP_RM; break; default: CPUWarning("Bad rounding mode set in FCR31 (%d)\n", modeNum); break; } fpsetround(newMode);#endif#ifdef __alpha write_rnd(modeNum);#endif#ifdef linux { static int fpwarned = 0; if (!fpwarned) { CPUWarning("MIPSY: could not figure out how to fpsetround on x86 \n"); fpwarned = 1; } }#endif}/***************************************************************** * All fpu (COP1) insts come through here. *****************************************************************/int ExecuteC1Instruction(CPUState *P, Inst instr){ int immediate = IMMED(instr); uint fs = FS(instr); /* 1st source reg */ uint ft = FT(instr); /* 2nd source register */ uint sub_value = FORMAT(instr); uint br_value = ft; uint major_op; Result result = C1_SUCCESS; uint func = FUNC(instr); StatusReg statusReg; /* The kernel sets the cop1 usable flag to 0 when it */ /* first starts a new context to limit the saving of */ /* FPU registers to those procs who use them. The */ /* first time a process uses a FPU instruction it */ /* needs to trap into the kernel for it to set this */ /* bit. */ statusReg.ts_data = P->CP0[C0_SR]; if (!(statusReg.s32.ts_cu1)) { CauseReg causeReg; causeReg.tc_data = P->CP0[C0_CAUSE]; causeReg.s32.tc_ce = 1; P->CP0[C0_CAUSE] = causeReg.tc_data; EXCEPTION(P, EXC_CPU); return C1_CONTINUE; } SetRoundingMode(P->FCR[31] & 0x3); major_op = MAJOR_OP(instr); if (major_op == cop1_op) { switch(sub_value) { case bc_op: if (br_value & 0x1) { /* BC1T */ /* Check if the condition bit in the csr is set */ if (P->FCR[31] & M_csr_c) { P->branchTarget = P->nPC + SIGN_EXTEND(18, (immediate << 2)); P->branchStatus = BranchStatus_taken; } else { if( br_value & 0x2 ) { /* branch likely */ /* Skip instruction in delay slot */ P->nPC = P->nPC + 4; } else { P->branchStatus = BranchStatus_nottaken; } } } else { /* BC1F */ /* Check if condition bit not set */ if (!(P->FCR[31] & M_csr_c)) { P->branchTarget = P->nPC + SIGN_EXTEND(18, (immediate << 2)); P->branchStatus = BranchStatus_taken; } else { if( br_value & 0x2 ) { /* branch likely */ /* Skip instruction in delay slot */ P->nPC = P->nPC + 4; } else { P->branchStatus = BranchStatus_nottaken; } } } break; case cfc_op: if (fs == 31) { P->R[ft] = P->FCR[fs]; } else { P->R[ft] = (3 << 8); /* R3010 FPU */ } SIM_DEBUG(('f', "C1: CFC1 got %#x from fcr %d\n", P->R[ft], fs)); break; case ctc_op: P->FCR[fs] = P->R[ft]; SIM_DEBUG(('f', "C1: CTC1 put %#x into fcr %d\n", P->R[ft], fs)); break; case mfc_op: P->R[ft] = (Reg32_s)IntReg(fs); SIM_DEBUG(('f', "C1: mfc1 put f%d %d into r%d \n", fs, IntReg(fs), ft)); break; case mtc_op: IntReg(fs) = (Reg32)P->R[ft]; SIM_DEBUG(('f', "C1: mtc1 put f%d %d into f%d -> %d\n", ft, P->R[ft], fs, IntReg(fs))); break; case dmfc_op: CHECK_64BIT_ALLOWED(P) P->R[ft] = LongLongReg(fs); SIM_DEBUG(('f', "C1: dmfc1 put f%d %lld into r%d \n", fs, LongLongReg(fs), ft)); break; case dmtc_op: CHECK_64BIT_ALLOWED(P) LongLongReg(fs) = P->R[ft]; SIM_DEBUG(('f', "C1: dmtc1 put f%d %lldd into f%d -> %lld\n", ft, P->R[ft], fs, LongLongReg(fs))); break; default: /* S, D, W format instructions */ switch (func) { case fmovc_op: case fmovn_op: case fmovz_op: { /* Make sure we can execute mips4 instructions */ if (IS_USER_MODE(P) && !(statusReg.s32.ts_xx)) { EXCEPTION(P, EXC_II); return C1_CONTINUE; } break; } default: STATS_INC(P->myNum, numFPOps, 1); break; } result = MipsyFPU(P, instr); break; } /* switch subvalue */ } else if (major_op == cop1x_op) { if (IS_USER_MODE(P) && !(statusReg.s32.ts_xx)) { EXCEPTION(P, EXC_II); return C1_CONTINUE; } STATS_INC(P->myNum, numFPOps, 1); result = MipsyFPUx(P,instr); } else if (major_op == spec_op) { /* Must be on the MOVC instructions */ ASSERT(FUNC(instr) == movc_op); /* Move conditional on FP condition */ if (TF(instr)) { if (P->FCR[31] & M_csr_c) { P->R[RT(instr)] = P->R[RS(instr)]; } } else { if (!(P->FCR[31] & M_csr_c)) { P->R[RT(instr)] = P->R[RS(instr)]; } } } else { ASSERT(0); /* unknown C1 instruction */ } return result;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -