⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fpu.c

📁 一个用在mips体系结构中的操作系统
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Copyright (C) 1996-1998 by the Board of Trustees *    of Leland Stanford Junior University. *  * This file is part of the SimOS distribution.  * See LICENSE file for terms of the license.  * *//***************************************************************** * fpu.c *  * $Author: bosch $ * $Date: 1998/02/10 00:31:40 $ *****************************************************************/#include <math.h>#include <limits.h>#ifdef __alpha#include <float.h>#else# ifndef i386# include <ieeefp.h># endif#endif#include "mipsy.h"#include "cpu.h"#include "cpu_state.h"#include "sim_error.h"#include "machine_params.h"#include "cp0.h"#include "fpu.h"#include "cpu_stats.h"extern Result MipsyPrefetch(CPUState *P, VA vAddr, uint hint);/* * CHECK_64BIT_ALLOWED() - Check to see if 64bit instructions are permitted, *                         if not raise an exception.  */#if defined(SIM_MIPS64)#define CHECK_64BIT_ALLOWED(_p)  \      if ((_p)->is32bitMode && !IS_KERNEL_MODE((_p))) {  \         EXCEPTION((_p), EXC_II);                 \         return C1_CONTINUE;                             \      }#else#define CHECK_64BIT_ALLOWED(_p) \      if (1) {                                           \         EXCEPTION((_p), EXC_II);                 \         return C1_CONTINUE;                             \      }#endif/* Enumeration of floating point exception types */typedef enum { FPE_I = 0, FPE_U, FPE_O, FPE_Z, FPE_V, FPE_E, FPECount } FPUException;static int FPCSRFlag[FPECount] = {   0x00000004, 0x00000008, 0x00000010, 0x00000020, 0x00000040, 0x00000000};static int FPCSREnable[FPECount] = {   0x00000080, 0x00000100, 0x00000200, 0x00000400, 0x00000800, 0x00000000};static int FPCSRCause[FPECount] = {   0x00001000, 0x00002000, 0x00004000, 0x00008000, 0x00010000, 0x00020000};/***************************************************************** * WARNING: An ugly feature of the sgi IEEE fp implementation greatly * complicates this c-based fpu model. FP operations on doubles take * place in a reversed order in the registers than they would in * memory. As a result, operations on doubles in my memory-based fp * registers would all be word-swapped. As a result, I swap every * single float reference so that reg 1 is in reg 0's place in memory * and vice versa. It's a pain, but will speed up the double * operations.  *  * There are a few side effects of this change: * -> The "real" fpu state must be copied into mipsy's special *    structure and out of it on entry and exit. * -> Gdb get reg needs to be aware of the special state * -> People debugging the fpu should be aware that FPR doesn't *    have the most up-to-date copy!!! ****************************************************************/ voidMipsyInitFPU(void){   CPUState *P;   int i,j;      for (i=0; i < TOTAL_CPUS; i++) {      P = &PE[i];      for (j=0; j < NUM_FP_REGS; j++) {#ifdef NEW_FP_REGS         LongLongReg(j) = P->FPR[j];#else         IntReg(j) = P->FPR[j];#endif      }   }}void MipsyExitFPU(void){   CPUState *P;   int i,j;      for (i=0; i < TOTAL_CPUS; i++) {      P = &PE[i];      for (j=0; j < NUM_FP_REGS; j++) {#ifdef NEW_FP_REGS         P->FPR[j] = LongLongReg(j);#else         P->FPR[j] = IntReg(j);#endif      }   }}static ResultMipsyFPUException(CPUState *P, FPUException type){   P->FCR[31] |= FPCSRFlag[type];   P->FCR[31] |= FPCSRCause[type];   if (P->FCR[31] & FPCSREnable[type]) {      EXCEPTION(P, EXC_FPE);      return C1_CONTINUE;   } else {      return C1_SUCCESS;   }}/***************************************************************** * MipsyFPU *****************************************************************/static Result MipsyFPU(CPUState *P, Inst instr) {   uint fmt = FORMAT(instr);   uint ft  = FT(instr); /* 2nd source register */   uint fs  = FS(instr); /* 1st source reg */   uint fd  = FD(instr); /* Destination */   uint func = FUNC(instr);   StatusReg statusReg;   /* Clear the exception flags from the FCR */   P->FCR[31] &= ~FPCSR_EXCEPTIONS;      switch(func+(fmt<<8)) {         case fabs_op+F_SSINGLE:      FloatReg(fd) = (FloatReg(fs) >= 0.0 ? FloatReg(fs) : -FloatReg(fs));      SIM_DEBUG(('f', "C1:ABS.S: f%d %e becomes f%d %e\n", fs, FloatReg(fs), fd,                  FloatReg(fd)));      break;   case fabs_op+F_SDOUBLE:      DoubleReg(fd) = (DoubleReg(fs) >= 0.0 ? DoubleReg(fs) : -DoubleReg(fs));      SIM_DEBUG(('f', "C1:ABS.D: f%d %Le becomes f%d %Le\n", fs, DoubleReg(fs), fd,                  DoubleReg(fd)));      break;         case fadd_op+F_SSINGLE:      FloatReg(fd) = FloatReg(fs) + FloatReg(ft);      SIM_DEBUG(('f', "C1:ADD.S: f%d %e + f%d %e = f%d %e\n", fs, FloatReg(fs), ft,                  FloatReg(ft), fd, FloatReg(fd)));      break;   case fadd_op+F_SDOUBLE:      DoubleReg(fd) = DoubleReg(fs) + DoubleReg(ft);      SIM_DEBUG(('f', "C1:ADD.D: f%d %Le + f%d %Le = f%d %Le\n", fs, DoubleReg(fs), ft,                  DoubleReg(ft), fd, DoubleReg(fd)));      break;   case fcvtd_op+F_SSINGLE:      DoubleReg(fd) = FloatReg(fs);      SIM_DEBUG(('f', "C1:CVTD.S: f%d %e becomes f%d %Le\n", fs, FloatReg(fs), fd,                  DoubleReg(fd)));       break;   case fcvtd_op+F_W: {      int old = IntReg(fs);      DoubleReg(fd) = (double)old;      SIM_DEBUG(('f', "C1:CVTD.W: f%d %d becomes f%d %Le\n", fs, old, fd,                  DoubleReg(fd)));      }      break;   case fcvts_op+F_SDOUBLE:      FloatReg(fd) = DoubleReg(fs);      SIM_DEBUG(('f', "C1:CVTS.D: f%d %Le becomes f%d %e\n", fs, DoubleReg(fs), fd,             FloatReg(fd)));      break;        case fcvts_op+F_W:      FloatReg(fd) = IntReg(fs);      SIM_DEBUG(('f', "C1:CVTS.W: f%d %d becomes f%d %e\n", fs, IntReg(fs), fd,                 FloatReg(fd)));      break;   case fcvts_op+F_L:      FloatReg(fd) = LongLongReg(fs);      /*CPUWarning("MIPSY: cvt.s.l @%#llx (partial impl.)\n", P->PC);*/      SIM_DEBUG(('f', "C1:CVTS.L: f%d %lld becomes f%d %e\n", fs,		 LongLongReg(fs), fd, FloatReg(fd)));      break;   case fcvtd_op+F_L:      DoubleReg(fd) = LongLongReg(fs);      /*CPUWarning("MIPSY: cvt.d.l @%#llx (partial impl.)\n", P->PC);*/      SIM_DEBUG(('f', "C1:CVTD.L: f%d %lld becomes f%d %Le\n", fs,		 LongLongReg(fs), fd, DoubleReg(fd)));      break;   case fcvtl_op+F_SSINGLE: {      uint roundMode = P->FCR[31] & 0x03;      CHECK_64BIT_ALLOWED(P);      switch (roundMode) {      case 0:                 /* RN: Round to nearest         */         LongLongReg(fd) = (FloatReg(fs) > 0.0 ? FloatReg(fs) + 0.5 : FloatReg(fs) - 0.5 );         break;               case 1:                 /* RZ: Round toward 0           */         LongLongReg(fd) = FloatReg(fs);         break;               case 2:                 /* RP: Round to +infinity       */         LongLongReg(fd) = (FloatReg(fs) >= 0.0 ?                      FloatReg(fs) + SP_NEAR_ONE :                      FloatReg(fs));         break;               case 3:                 /* RM: Round to -infinity       */         LongLongReg(fd) = (FloatReg(fs) >= 0.0 ?                      FloatReg(fs) :                     FloatReg(fs) - SP_NEAR_ONE);         break;      }      SIM_DEBUG(('f', "C1:CVTW.S: f%d %e becomes f%d %d rm = %d\n",                  fs, FloatReg(fs), fd, IntReg(fd), roundMode));      break;   }         case fcvtl_op+F_SDOUBLE: {      uint roundMode = P->FCR[31] & 0x03;      CHECK_64BIT_ALLOWED(P);      switch (roundMode) {      case 0:                 /* RN: Round to nearest         */         LongLongReg(fd) = (DoubleReg(fs) > 0.0 ? DoubleReg(fs) + 0.5 : DoubleReg(fs) - 0.5 );         break;               case 1:                 /* RZ: Round toward 0           */         LongLongReg(fd) = DoubleReg(fs);         break;               case 2:                 /* RP: Round to +infinity       */         LongLongReg(fd) = (DoubleReg(fs) >= 0.0 ?                      DoubleReg(fs) + DP_NEAR_ONE :                      DoubleReg(fs));         break;               case 3:                 /* RM: Round to -infinity       */         LongLongReg(fd) = (DoubleReg(fs) >= 0.0 ?                      DoubleReg(fs) :                     DoubleReg(fs) - DP_NEAR_ONE);         break;      }      SIM_DEBUG(('f', "C1:CVTL.D: f%d %Le becomes f%d %d rm = %d\n",                  fs, DoubleReg(fs), fd, IntReg(fd), roundMode));      break;   }   case fcvtw_op+F_SSINGLE: {      uint roundMode = P->FCR[31] & 0x03;      float rounded;      switch (roundMode) {      case 0:                 /* RN: Round to nearest         */         rounded = (FloatReg(fs) > 0.0 ? FloatReg(fs) + 0.5 : FloatReg(fs) - 0.5 );         break;               case 1:                 /* RZ: Round toward 0           */         rounded = FloatReg(fs);         break;               case 2:                 /* RP: Round to +infinity       */         rounded = (FloatReg(fs) >= 0.0 ?                      FloatReg(fs) + SP_NEAR_ONE :                      FloatReg(fs));         break;               case 3:                 /* RM: Round to -infinity       */         rounded = (FloatReg(fs) >= 0.0 ?                      FloatReg(fs) :                     FloatReg(fs) - SP_NEAR_ONE);         break;      }      IntReg(fd) = rounded;      SIM_DEBUG(('f', "C1:CVTW.S: f%d %e becomes f%d %d rm = %d\n",                  fs, FloatReg(fs), fd, IntReg(fd), roundMode));      /* Check for valid operand */      if ((rounded > (float)INT_MAX) || (rounded < (float)INT_MIN)) {         int ret = MipsyFPUException(P, FPE_V);         return ret;      }      break;   }         case fcvtw_op+F_SDOUBLE: {      uint roundMode = P->FCR[31] & 0x03;      double rounded;      switch (roundMode) {      case 0:                 /* RN: Round to nearest         */         rounded = (DoubleReg(fs) > 0.0 ? DoubleReg(fs) + 0.5 : DoubleReg(fs) - 0.5 );         break;               case 1:                 /* RZ: Round toward 0           */         rounded = DoubleReg(fs);         break;               case 2:                 /* RP: Round to +infinity       */         rounded = (DoubleReg(fs) >= 0.0 ?                      DoubleReg(fs) + DP_NEAR_ONE :                      DoubleReg(fs));         break;               case 3:                 /* RM: Round to -infinity       */         rounded = (DoubleReg(fs) >= 0.0 ?                      DoubleReg(fs) :                     DoubleReg(fs) - DP_NEAR_ONE);         break;      }      IntReg(fd) = rounded;      SIM_DEBUG(('f', "C1:CVTW.D: f%d %Le becomes f%d %d rm = %d\n",                  fs, DoubleReg(fs), fd, IntReg(fd), roundMode));      /* Check for valid operand */      if ((rounded > (double)INT_MAX) || (rounded < (double)INT_MIN)) {         int ret = MipsyFPUException(P, FPE_V);         return ret;      }      break;   }   case fdiv_op+F_SSINGLE:      if (FloatReg(ft) == 0.0) {         CPUWarning("MIPSY: FDIV divide by zero @%#llx\n", P->PC);      }       FloatReg(fd) = FloatReg(fs) / FloatReg(ft);      SIM_DEBUG(('f', "C1:FDIV.S: f%d %e / f%d %e = f%d %e\n",                  fs, FloatReg(fs), ft, FloatReg(ft), fd, FloatReg(fd)));      break;   case fdiv_op+F_SDOUBLE:      if (DoubleReg(ft) == 0.0) {         CPUWarning("MIPSY: FDIV divide by zero\n");      }       DoubleReg(fd) = DoubleReg(fs) / DoubleReg(ft);      SIM_DEBUG(('f', "C1:FDIV.D f%d %Le / f%d %Le = f%d %Le\n", fs, DoubleReg(fs), ft,                  DoubleReg(ft), fd, DoubleReg(fd)));      break;   case fmov_op+F_SSINGLE:      FloatReg(fd) = FloatReg(fs);      SIM_DEBUG(('f', "C1:FMOV.S %e to %e\n", FloatReg(fs),                  FloatReg(fd)));      break;     case fmov_op+F_SDOUBLE:      DoubleReg(fd) = DoubleReg(fs);      SIM_DEBUG(('f', "C1:FMOV.D %Le to %Le\n", DoubleReg(fs),                  DoubleReg(fd)));      break;     case fmovc_op+F_SSINGLE:      /* Move conditional on FP condition */      if (TF(instr)) {          if (P->FCR[31] & M_csr_c) {            FloatReg(fd) = FloatReg(fs);         }      } else {         if (!(P->FCR[31] & M_csr_c)) {            FloatReg(fd) = FloatReg(fs);         }      }      break;   case fmovc_op+F_SDOUBLE:      /* Move conditional on FP condition */      if (TF(instr)) {          if (P->FCR[31] & M_csr_c) {            DoubleReg(fd) = DoubleReg(fs);         }      } else {         if (!(P->FCR[31] & M_csr_c)) {            DoubleReg(fd) = DoubleReg(fs);         }      }      break;   case fmovn_op+F_SSINGLE:      if (P->R[ft] != 0) {          FloatReg(fd) = FloatReg(fs);      }      SIM_DEBUG(('f', "C1:FMOVN.S %e to %e\n", FloatReg(fs), FloatReg(fd)));      break;     case fmovn_op+F_SDOUBLE:      if (P->R[ft] != 0) {          DoubleReg(fd) = DoubleReg(fs);      }      SIM_DEBUG(('f', "C1:FMOVN.D %Le to %Le\n", DoubleReg(fs), DoubleReg(fd)));      break;     case fmovz_op+F_SSINGLE:      if (P->R[ft] == 0) {          FloatReg(fd) = FloatReg(fs);      }      SIM_DEBUG(('f', "C1:FMOVZ.S %e to %e\n", FloatReg(fs), FloatReg(fd)));      break;     case fmovz_op+F_SDOUBLE:      if (P->R[ft] == 0) {          DoubleReg(fd) = DoubleReg(fs);      }      SIM_DEBUG(('f', "C1:FMOVZ.D %Le to %Le\n", DoubleReg(fs), DoubleReg(fd)));      break;     case fmul_op+F_SSINGLE:      FloatReg(fd) = FloatReg(fs) * FloatReg(ft);      SIM_DEBUG(('f', "C1:FMUL.S: f%d %e * f%d %e = f%d %e\n",                  fs, FloatReg(fs), ft, FloatReg(ft), fd, FloatReg(fd)));      break;   case fmul_op+F_SDOUBLE:      DoubleReg(fd) = DoubleReg(fs) * DoubleReg(ft);      SIM_DEBUG(('f', "C1:FMUL.D: f%d %Le * f%d %Le = f%d %Le\n", fs, DoubleReg(fs), ft,                  DoubleReg(ft), fd, DoubleReg(fd)));      break;   case fneg_op+F_SSINGLE:      FloatReg(fd) = -FloatReg(fs);      SIM_DEBUG(('f', "C1:NEG.S: f%d %e becomes f%d %e\n",                  fs, FloatReg(fs), fd, FloatReg(fd)));      break;   case fneg_op+F_SDOUBLE:      DoubleReg(fd) = -DoubleReg(fs);      SIM_DEBUG(('f', "C1:NEG.D: f%d %Le becomes f%d %Le\n",                  fs, FloatReg(fs), fd, FloatReg(fd)));      break;   case fsub_op+F_SSINGLE:      FloatReg(fd) = FloatReg(fs) - FloatReg(ft);      SIM_DEBUG(('f', "C1:SUB.S: f%d %e - f%d %e = f%d %e\n",                  fs, FloatReg(fs), ft, FloatReg(ft), fd, FloatReg(fd)));      break;   case fsub_op+F_SDOUBLE:      DoubleReg(fd) = DoubleReg(fs) - DoubleReg(ft);      SIM_DEBUG(('f', "C1:SUB.D: f%d %Le - f%d %Le = f%d %Le\n",                  fs, DoubleReg(fs), ft, DoubleReg(ft), fd, DoubleReg(fd)));      break;       case fsqrt_op+F_SSINGLE:	      FloatReg(fd) = (float)sqrt((double)FloatReg(fs));      break;   case fsqrt_op+F_SDOUBLE:      DoubleReg(fd) = sqrt (DoubleReg(fs));      break;   case ftrunc_op+F_SSINGLE:      IntReg(fd) = FloatReg(fs);      break;   case ftrunc_op+F_SDOUBLE:      IntReg(fd) = DoubleReg(fs);      break;   case ftruncl_op+F_SSINGLE:      CHECK_64BIT_ALLOWED(P);      LongLongReg(fd) = FloatReg(fs);      break;   case ftruncl_op+F_SDOUBLE:      CHECK_64BIT_ALLOWED(P);      LongLongReg(fd) = DoubleReg(fs);      break;   case ffloorl_op+F_SSINGLE:      IntReg(fd) = (FloatReg(fs) >= 0.0 ? FloatReg(fs) : FloatReg(fs) - SP_NEAR_ONE );      break;   case ffloorl_op+F_SDOUBLE:      IntReg(fd) = (DoubleReg(fs) >= 0.0 ? DoubleReg(fs) : DoubleReg(fs) - DP_NEAR_ONE );      break;   case frecip_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: FDIV divide by zero\n");      }       FloatReg(fd) = 1.0 / FloatReg(fs);      SIM_DEBUG(('f', "C1:FRECIP.S: f%d %e / f%d %e = f%d %e\n",                  fs, FloatReg(fs), ft, FloatReg(ft), fd, FloatReg(fd)));      break;   }   case frecip_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)) {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -