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

📄 r4k_cp0.c

📁 一个用在mips体系结构中的操作系统
💻 C
📖 第 1 页 / 共 5 页
字号:
   P->CP0[C0_TLBHI] = P->exception[exnum].hireg;   if (P->exception[exnum].cause == EXC_CPU)  {      CauseReg  causeReg;      causeReg.tc_data = P->CP0[C0_CAUSE];      causeReg.s32.tc_ce = P->exception[exnum].badaddr;      P->CP0[C0_CAUSE] = causeReg.tc_data;   } else {            /*       * MIPS r4k manual is WRONG on this one.       * Always latch badvaddr       */      P->CP0[C0_BADVADDR] = P->exception[exnum].badaddr;   }   P->CP0[C0_CTXT] = P->exception[exnum].ctxtreg;   if (P->exception[exnum].vec == UT_VEC) {      UTLB_EXCEPTION(P, P->exception[exnum].cause);   } else {      EXCEPTION(P, P->exception[exnum].cause);   }   P->PC = P->exception[exnum].vec;   P->nPC = P->exception[exnum].vec+4;   if (P->exception[exnum].cause == EXC_SYSCALL) {#define SYSVoffset 1000      int syscallNum = P->R[REG_V0] - SYSVoffset;      ASSERT((syscallNum < MAX_SYSCALL) && (syscallNum >= 0));      STATS_INC(P->myNum, numSyscalls, 1);      STATS_INC(P->myNum, syscallCount[syscallNum], 1);   }   CopyToMXS (P);  /* Resets the MXS instruction window */   return;}intFPusable(struct s_cpu_state *st){   CPUState *P = (CPUState *) (st->mipsyPtr);   StatusReg statusReg;   statusReg.ts_data = P->CP0[C0_SR];   if (!(statusReg.s32.ts_cu1)) {      /* CE bits of the cause register are set in badvaddr */      RECORD_EXCEPTION(P, EXC_CPU, E_VEC, 1,                        P->CP0[C0_TLBHI], P->CP0[C0_CTXT],P->CP0[C0_XCTXT]);      return 0;   }   return 1;}#endif /* MIPSY_MXS *//* END UNTOUCHED MXS *//***************************************************************** * ExceptionReturn * instruction for returning from an interrupt, exception, or * error trap.  if error trap load pc from the ErrorEPC and clear * ERL bit of the status register. else load pc from EPC and clear * EXL bit of the status register. * PC gets set in R4, not in R3. * Handler must save pc, op mode, status or interrupts enable,  * and restore. *****************************************************************/void ExceptionReturn(CPUState *P){   StatusReg statusReg;   statusReg.ts_data = P->CP0[C0_SR];   RFE_EVENT();      if (statusReg.s32.ts_erl){     P->PC = P->CP0[C0_ERROR_EPC];     statusReg.s32.ts_erl = 0;   } else {     P->PC = P->CP0[C0_EPC];     statusReg.s32.ts_exl = 0;   }   P->nPC = P->PC + INST_SIZE;   P->CP0[C0_SR] = statusReg.ts_data;   UpdateCPUMode(P);   MipsyCheckForInterrupts(P);}/***************************************************************** * MipsyCheckForInterrupts * The cause register needs to have its interrupt pending (IP) bits * before we determine if we have to take an interrupts. * MipsyCheckForInterrupts is called every time the cpu simulator * sets an interrupt, on every mtc_op to CO_SR and periodically to  * catch TTY and net interrupts. * For an interrupt exception to take place, a few things have  to be true:  * (1) an interrupt bit has to be set in the cause register  * (2) that interrupt must be enabled in the SR's IM field  * (3) the SR must have the current interrupt enabled field set * (4) Can't be running at exception level. ****************************************************************/void MipsyCheckForInterrupts(CPUState *P){   P->CP0[C0_CAUSE] = (P->CP0[C0_CAUSE] & ~CAUSE_EXTINTBITS) |      ((P->intrBitsPtr[0] << CAUSE_IPSHIFT) & CAUSE_EXTINTBITS);      if (((P->CP0[C0_CAUSE] & P->CP0[C0_SR]) & SR_IMASK)       && (P->CP0[C0_SR] & SR_IEC) &&           !(P->CP0[C0_SR] & (SR_EXL|SR_ERL))) {      STATS_SET(P->myNum, syncStallStart, 0);      P->takeInterrupt = TRUE;   }}/***************************************************************** * MipsyCacheError *  * Flashlite calls this for Cache Errors *  * 1) Set ERL * 2) Save the current PC as ERROR_EPC * 3) Set the PC to CACHE_ERROR_VEC (addr_layout.h) * * CAVEAT user: *  This doesn't yet implement the full R10K functionality. In the *  R10K, a second cache error may be posted, but will not be taken *  while the ERL status bit is set. To be done. * *****************************************************************/voidMipsyCacheError(int cpuNum, bool isAsync){   StatusReg statusReg;   CPUState *P = &PE[cpuNum];   /*    * Shift current mode and interrupt status to previous,     * previous to old, and old can be discarded. This lets the CPU    * respond to three levels of exceptions before software must    * save the contents of the Status register.    */   statusReg.ts_data = P->CP0[C0_SR];      statusReg.s32.ts_erl = 1;   P->CP0[C0_SR] = statusReg.ts_data;   P->cpuMode = KERNEL_MODE;   /* This is kind of messy. The R100000 manual says one thing and the      R4000 manual (and sbd.h) says another, so using the R4000 settings      for now... */   if (isAsync) {      /* from sysAD:  setting ED and EE */      P->CP0[C0_CACHE_ERR] = 0x24000000;   } else {      /* a real cache error:  setting ED */      P->CP0[C0_CACHE_ERR] = 0x20000000;   }   /* for uncached stalled cpus, wait for the stalled instruction to complete first */   if (P->cpuStatus == cpu_stalled_uncached) {      P->CP0[C0_ERROR_EPC] = P->nPC;      if (statusReg.s32.ts_bev == 0) {         P->nPC = CACHE_ERR_VEC_BEV0;      } else {         P->nPC = CACHE_ERR_VEC_BEV1;      }   } else {      /* if cpu is running, take cache error right now */      /* Save the current pc as C0_ERROR_EPC, DONT set Branch delay bit */      if (P->nPC != (P->PC + INST_SIZE)) {          /* The inst that was preempted is in a BD slot */         P->CP0[C0_ERROR_EPC] = P->PC - INST_SIZE;      } else {         P->CP0[C0_ERROR_EPC] = P->PC;      }      if (statusReg.s32.ts_bev == 0) {         P->PC = CACHE_ERR_VEC_BEV0;         P->nPC = CACHE_ERR_VEC_BEV0 + 4;      } else {         P->PC = CACHE_ERR_VEC_BEV1;         P->nPC = CACHE_ERR_VEC_BEV1 + 4;      }   }   P->stalledInst = FALSE;    /* Force inst refetch from exc vect */}/***************************************************************** * UpdateCPUMode * * This function is shared between mipsy and embra * Update with care. Do not remove the embra specific * stuff. *****************************************************************/static void UpdateCPUMode(CPUState *P){   StatusReg  statusReg;    statusReg.ts_data = P->CP0[C0_SR];   P->cpuMode = KERNEL_MODE;   if (!statusReg.s32.ts_erl && !statusReg.s32.ts_exl) {       ASSERT(statusReg.s32.ts_ksu != 3);     if (statusReg.s32.ts_ksu == 2) {        P->cpuMode = USER_MODE;     } else if (statusReg.s32.ts_ksu == 1) {         P->cpuMode = SUPERVISOR_MODE;     }  }   P->notFRbit = (statusReg.s32.ts_fr == 0);   switch (P->cpuMode) {    case KERNEL_MODE:       P->is32bitMode = (statusReg.s32.ts_kx == 0);      break;   case SUPERVISOR_MODE:       P->is32bitMode = (statusReg.s32.ts_sx == 0);#if defined(SIM_MIPS32)      ASSERT(IS_SUPERV_SEG(P->PC));#endif      break;   case USER_MODE:      P->is32bitMode = (statusReg.s32.ts_ux == 0);#if defined(SIM_MIPS32)      ASSERT( IS_KUSEG(P->PC));#endif      break;   default:       ASSERT(0);   }   SIM_DEBUG_DETAIL(('i', "CPUMode" , P->myNum,                     " going to %d PC=0x%llx SR=%x erl=%d exl=%d ksu=%d 32bit=%d\n",                    P->cpuMode, (uint64)P->PC, P->CP0[C0_SR],                    statusReg.s32.ts_erl,statusReg.s32.ts_exl,                    statusReg.s32.ts_ksu,P->is32bitMode));}extern int numLLactive;extern PA  LLAddrs[MIPSY_MAX_CPUS];/***************************************************************** * All cop0 instructions are handled here.  *****************************************************************/intExecuteC0Instruction(CPUState *P, Inst instr){   uint rs = RS(instr);   uint rt = RT(instr);   uint rd = RD(instr);   /* Handle the rs instructions */   if (!IS_KERNEL_MODE(P)) {                       /* CP0 is unusable only in kernel and or when the cu0 bit is set. */      CauseReg  causeReg;      StatusReg statusReg;      statusReg.ts_data = P->CP0[C0_SR];      if (!statusReg.s32.ts_cu0) {         causeReg.tc_data = P->CP0[C0_CAUSE];         causeReg.s32.tc_ce = 0;         P->CP0[C0_CAUSE] = causeReg.tc_data;         EXCEPTION(P, EXC_CPU);         return C0_CONTINUE;      }   }   switch(rs) {   case bc_op:      CPUError("BCC0 is not valid\n");      return C0_ILLEGAL_INST;         case cfc_op:      CPUError("CFC0 is not valid\n");      return C0_ILLEGAL_INST;         case ctc_op:      CPUError("CTC0 is not valid\n");      return C0_ILLEGAL_INST;         case dmfc_op:      if (P->is32bitMode) {           return C0_ILLEGAL_INST;      }      /* Fall thru */    case mfc_op:      /* update the count on a read */      if (rd == C0_COUNT){         /* If someone writes to count we need to watch the timer. */         P->CP0[C0_COUNT] += (MipsyReadTime(P->myNum) - P->timerCycleCount)/               COUNTER_FREQUENCY_DIVIDER;         P->CP0[C0_COUNT] &= 0xffffffff;         P->timerCycleCount = MipsyReadTime(P->myNum);       } else if (rd == C0_RAND) {  unsigned numRandEntries = P->numTlbEntries - P->CP0[C0_TLBWIRED];  P->CP0[C0_RAND] = P->CP0[C0_TLBWIRED] +            ((uint32)MipsyReadTime(P->myNum)) % numRandEntries;       }            if (rs == mfc_op) { #if defined(SIM_MIPS64)         if (P->CP0[rd] == 0x0000000080000000LL) {            /* WARNING! This is a hack to fix a compiler bug in 7.2.                It assigns 0x0000000080000000 rather than                0xffffffff80000000 */            P->R[rt] = 0xffffffff80000000LL;         } else {            P->R[rt] = (Reg)(Reg32_s)P->CP0[rd];         }#else         P->R[rt] = (Reg)(Reg32_s)P->CP0[rd];#endif      } else {          P->R[rt] = P->CP0[rd];      }      break;         case dmtc_op:      if (P->is32bitMode) {           return C0_ILLEGAL_INST;      }      /* Fall thru */    case mtc_op:        if (rs == dmtc_op) {          WriteC0Register(P, rd, P->R[rt], 1);      } else {         WriteC0Register(P, rd, (Reg32_s)(P->R[rt]), 0);      }       break;         default:       /* It wasn't any of these, so it's a CO function */      switch(FUNC(instr)) {               case rfe_op:      /* Treat rfe as an eret for NachOS */      case eret_op:         if (UNCACHED_LL_SC) {            if (P->LLbit) {               numLLactive--;               LLAddrs[P->myNum] = (PA) -1;            }         }                   /* Note that this is now check for >= instead of            just >. This is so we can capture the            instruction that causes the transistion in the            sample */          if (STATS_VALUE(P->myNum, numInstructions)              >= STATS_VALUE(P->myNum, nextInstrSample)) {            INST_SAMPLE_EVENT(MipsyReadTime(P->myNum), P->myNum, P->PC);            STATS_INC(P->myNum, nextInstrSample, MS_SAMPLE_INSTR_INTERVAL);         }                  P->LLbit = 0;         /* This is bad... this is the one case where flow control         gets messed up. */         TraceInstruction(P, instr);         ExceptionReturn(P);         return C0_CONTINUE;               case tlbp_op:         ProbeTLB(P);         break;               case tlbr_op:         ReadTLBEntry(P);         break;               case tlbwi_op:         if (WriteTLBEntry(P) != SUCCESS) {            CPUWarning("WriteTLB failed at %#x on %d\n",                       P->PC, P->myNum);         } else             break;               case tlbwr_op:         if (WriteRandomTLBEntry(P) != SUCCESS) {            CPUWarning("WriteRandomTLB failed at %#x on %d\n",                       P->PC, P->myNum);         } else            break;               default:         ASSERT(0);         return C0_ILLEGAL_INST;      }   }   return C0_SUCCESS;}

⌨️ 快捷键说明

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