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

📄 r4k_cp0.c

📁 一个用在mips体系结构中的操作系统
💻 C
📖 第 1 页 / 共 5 页
字号:
   IndexReg index;   /* I'm going to assume that the index register is in the       correct range. */      index = P->CP0[C0_INX];   P->CP0[C0_PGMASK] = P->tlbEntry[GET_IDX(index)].PgMsk;   P->CP0[C0_TLBHI] = P->tlbEntry[GET_IDX(index)].Hi &                       ~P->tlbEntry[GET_IDX(index)].PgMsk & ~TLBHI_G;   P->CP0[C0_TLBLO_0] = P->tlbEntry[GET_IDX(index)].Lo0;   P->CP0[C0_TLBLO_1] = P->tlbEntry[GET_IDX(index)].Lo1;   if (IS_GLOBAL_HI(P->tlbEntry[GET_IDX(index)].Hi)){      P->CP0[C0_TLBLO_0] |= TLBLO_G;       P->CP0[C0_TLBLO_1] |= TLBLO_G;   } else {      P->CP0[C0_TLBLO_0] &= ~TLBLO_G;      P->CP0[C0_TLBLO_1] &= ~TLBLO_G;   }      /* Reading into TLBHI could change the ASID */   P->pcVPNcache = 0;    TraceCheckASID(P);   return;}/***************************************************************** * Do_TLB_Write * Write the indexed TLB entry. The TLB entry pointed at by the  * contents of the TLB index register is loaded with the contents * of the Hi, Lo0, Lo1, and PgMsk registers.  Since both Lo0 and Lo1 * are written, the C0_TLBLO_1 and _0 must be in a consistent  * state before this instruction is called. * * R4000 CHANGES >> G bit of tlbhi written as AND of G bits * in EntryLo0 and EntryLo1. *****************************************************************/static Result DoTLBWrite(CPUState *P, int idx){   int hashNum;   Reg frameMask;   /* remove old entry from hash table */   if( P->indexList[idx].onList ) {      List_Remove( &(P->indexList[idx].links));      P->indexList[idx].onList = 0;    }   /* if we are doing an indexed write into a segment which should not    * be using the TLB we do NOTHING, and issue a mipsyswarning    * that this has been called.     */   if (IS_R10000(P)) {       frameMask = (P->CP0[C0_FRAMEMASK] << TLBFRAMESHIFT);   } else {      frameMask = 0;   }   P->tlbEntry[idx].PgMsk = P->CP0[C0_PGMASK];   P->tlbEntry[idx].Hi = P->CP0[C0_TLBHI] & ~P->CP0[C0_PGMASK];   P->tlbEntry[idx].Lo0 = (P->CP0[C0_TLBLO_0] & ~TLBLO_G) & ~frameMask;   P->tlbEntry[idx].Lo1 = (P->CP0[C0_TLBLO_1] & ~TLBLO_G) & ~frameMask;   P->tlbEntrySize[idx] = ComputeTlbEntrySize(P->tlbEntry[idx].PgMsk);   if (IS_GLOBAL_LO(P->CP0[C0_TLBLO_0])  && IS_GLOBAL_LO(P->CP0[C0_TLBLO_1])) {         P->tlbEntry[idx].Hi |= TLBHI_G;     }      /* To check which segment it is, I retrieve the VPN2 and shift up     * by 1 to get the original vpn.  Since all VPN2's are floored, and     * segs are on even boundaries, this should work. Then this number up    * to account for the page offset so that the MIPSY_IS_KSEG0 test will    * work.  This will change when PageMask register is used.     */   if (!IS_UNMAPPED_TLBHI(P->tlbEntry[idx].Hi)) {       /* update hash table Insert all global entries under ASID 0 */      if (IS_GLOBAL_HI( P->tlbEntry[idx].Hi)) {         hashNum = TLBHash(GET_VPN2(P->tlbEntry[idx].Hi),                            GET_REGION(P->tlbEntry[idx].Hi), 0);      } else {         hashNum = TLBHash(GET_VPN2(P->tlbEntry[idx].Hi),                           GET_REGION(P->tlbEntry[idx].Hi),                           GET_ASID(P->tlbEntry[idx].Hi));         if(GET_ASID(P->tlbEntry[idx].Hi) == 0) {            if (!((P->tlbEntry[idx].Hi == 0) &&                  !(TLBLO_V & P->tlbEntry[idx].Lo0) &&                   !(TLBLO_V & P->tlbEntry[idx].Lo1))) {                /* IRIX 6.2 seems to like to slam all zeros into                * the TLB. Don't print a message if this happens.                */#ifndef TORNADO/* common operation in Tornado; should be nothing wrong with it */#if 0 /* just as common in Topsy -- PZ */  CPUWarning("Non-global ASID 0 entry written to TLB @%#lx RA %#lx\n",	     (long)P->PC, (long)P->R[31]);  /* got rid of the evil %llx -- PZ */#endif#else#endif /* TORNADO */            }         }      }            List_Insert(&(P->indexList[idx].links),                   LIST_ATFRONT(&(P->tlbIndexHeaders[hashNum])));      P->indexList[idx].onList = 1;            if (!IS_CACHEABLE(P->tlbEntry[idx].Lo0) ||          !IS_CACHEABLE(P->tlbEntry[idx].Lo1)) {         CPUWarning("Entering uncached TLB Entry at PC %#x\n", P->PC);      }                } /* END IF KSEG0 || KSEG1 */         P->pcVPNcache = 0;    TraceCheckASID(P);   return SUCCESS;}/***************************************************************** * WriteTLBEntry - * Write the indexed TLB entry. The TLB entry pointed at by the  * contents of the TLB index register is loaded with the contents * of the Hi and Lo registers. *****************************************************************/static ResultWriteTLBEntry(CPUState *P){   IndexReg index;      /* I'm going to assume that the index register is in the       correct range. */   index = P->CP0[C0_INX];   return DoTLBWrite(P, GET_IDX(index));}/***************************************************************** * WriteRandomTLBEntry - * Write random TLB entry. The TLB entry pointed at by the contents   * of the TLB Random register is loaded with the contents of Hi * and Lo. * * Technically, the value of the Random register is decremented on * each machine clock cycle and ranges between NWIREDENTRIES * and NTLBENTRIES. To save time, I'll just read the clock. * TO_DO NUMWIREDENTRIES should be based on the register. it  * is, I keep the randomReg unimplemented and hueristically done as before. *  * R4000 CHANGES >> No changes. *****************************************************************/#ifdef DETERMINISTIC_TLBint currentRandom = 0;#endifstatic ResultWriteRandomTLBEntry(CPUState *P){   unsigned randomReg;   unsigned numRandEntries = P->numTlbEntries - P->CP0[C0_TLBWIRED];#ifdef DETERMINISTIC_TLB   randomReg = (currentRandom++ % numRandEntries);#else   randomReg = (MipsyReadTime(P->myNum) % numRandEntries);#endif   return DoTLBWrite(P, randomReg + P->CP0[C0_TLBWIRED]);}/***************************************************************** * EXCEPTION -  * This is sort of a major routine. When an exception is raised,  * execution is suspended and the processor enters kernel mode.  * The CPU should abort the instruction that caused the exception * along with any others in the pipeline. *  * The CPU loads the Exception Program Counter (EPC) with a  * restart location - either the instruction, or it's predecessor * if it's in the branch delay slot. I check if it's in a branch * delay slot by seeing if the difference between PC and nPC is * greater than one instruction.  * * R4000 STATUS REGISTER UPDATE  * 1.)  The handler needs to know the mode(user or supervisor) * so only do not change mode. * 2.)  disable interrupts * 3.)  Are we inside another Exception, if EXL == 1 we are, * and do not set PC or nPC. * 4.)  on start cpu loads EPC with restart location... * 5.)  check BEV bit and goto vector. *   * The current kernel/user mode and interrupt enable status is NOT saved.  * Currently does not set ce bit in status register.   ****************************************************************/static bool isREFILLException = FALSE; void EXCEPTION(CPUState *P, int code){      StatusReg statusReg;   CauseReg causeReg;   uint prettyCode = code >> CAUSE_EXCSHIFT;   VA exceptionBase;   TraceException(P, code);   SIM_DEBUG_DETAIL(('i', "INTR", P->myNum,                     "EXC code: 0x%x)\tintrbits: 0x%x\tPC: 0x%llx, RA: 0x%llx bad=0x%llx\n",                    code, P->intrBitsPtr[0], (uint64)P->PC,                     (uint64) P->R[31],(uint64)P->CP0[C0_BADVADDR]));   statusReg.ts_data = P->CP0[C0_SR];   /* no exceptions when ERL is asserted */   if (statusReg.s32.ts_erl)      return;   /* Clear any cached instruction in case this exception is terminating    * a miss stall    */   P->stalledInst = 0;      /* Set the BD bit, CE, IP, and ExcCode fields of the Cause    * register. Along with the BD bit, set the Exception Program    * Counter (either to current PC or PC - 4 if BD slot).    */      causeReg.tc_data = P->CP0[C0_CAUSE];   causeReg.s32.tc_exccode = code >> CAUSE_EXCSHIFT;      /* The code comes in already shifted to the left 2 bits */   if ((code == EXC_RMISS) || (code == EXC_WMISS)) {      STATS_INC(P->myNum, numFaults, 1);   }      if (code == EXC_INT) {      STATS_INC(P->myNum, numInterrupts, 1);   }      STATS_INC(P->myNum, causeCount[prettyCode], 1);   /* EPC must point to the preceeding branch or delay instruction */    if (P->branchStatus == BranchStatus_bd)  {       /* The inst causing the exception is in a BD slot */      causeReg.s32.tc_bd = TRUE;      if (statusReg.s32.ts_exl == 0){ P->CP0[C0_EPC] = P->PC-INST_SIZE; statusReg.s32.ts_exl = 1;      }   } else {      causeReg.s32.tc_bd = FALSE;      if (statusReg.s32.ts_exl == 0){         P->CP0[C0_EPC] = P->PC;         statusReg.s32.ts_exl = 1;      }   }      P->CP0[C0_SR] = statusReg.ts_data;   P->CP0[C0_CAUSE] = causeReg.tc_data;   UpdateCPUMode(P);   EXC_STALL_EVENT(P->myNum, P->PC, 1);   exceptionBase = (statusReg.s32.ts_bev == 0) ? EXC_VEC_BASE_0 :                                               EXC_VEC_BASE_1;   if (isREFILLException){#if defined(SIM_MIPS64)      Reg32     sr_reg =  statusReg.ts_data;      int region;      XContextReg xctxt;      xctxt.tc_data =  P->CP0[C0_XCTXT];      region = xctxt.s64.tc_region;      if (((region == 0) && (sr_reg & SR_UX)) ||          ((region == 3) && (sr_reg & SR_KX)) ||          ((region == 1) && (sr_reg & SR_SX))) {         P->PC  = exceptionBase + XUT_VEC_OFFSET;         P->nPC = exceptionBase + XUT_VEC_OFFSET + 4;      } else { #else      {#endif         P->PC  = exceptionBase;         P->nPC = exceptionBase+4;      }   } else {      P->PC = exceptionBase + E_VEC_OFFSET;      P->nPC = exceptionBase + E_VEC_OFFSET + 4;   }   if (isREFILLException) {      UTLB_EVENT();   } else {      EXC_EVENT(prettyCode);   }}/***************************************************************** * UTLB_EXCEPTION  *  * R4000 MIPS uses 1 special vector for any * TLB refill exception. * note:: this used to be called utlb_exception.   ****************************************************************/static void UTLB_EXCEPTION(CPUState *P, int code){   /* This will be counted here and in the EXC_WMISS and */   /* EXC_RMISS. Subtract out if needed. */   STATS_INC(P->myNum, utlbCount[code >> CAUSE_EXCSHIFT], 1);   isREFILLException = TRUE;   EXCEPTION(P, code);    isREFILLException = FALSE;}/* UNTOUCHED MXS */#ifdef MIPSY_MXS/* * PrintException - Print the specified exception - used for debugging. */void PrintException(struct s_cpu_state *st, int exnum) {   CPUState *P = (CPUState *) (st->mipsyPtr);   if (exnum >= 0)       CPUPrint("MXS: CPU%d: EXC @ 0x%x cause 0x%x badvaddr 0x%x time %lld\n",                P->myNum,               P->CP0[C0_EPC],               P->exception[exnum].cause,                P->exception[exnum].badaddr, (uint64)MipsyReadTime(P->myNum));   }/* * HandleException - Modify the register state of the machine *                   to reflect an exception happening. */void HandleException(struct s_cpu_state *st, int exnum, int in_delay) {   CPUState *P = (CPUState *) (st->mipsyPtr);   StatusReg statusReg;   statusReg.ts_data = P->CP0[C0_SR];        CopyFromMXS (P);   if (in_delay) {      P->branchStatus = BranchStatus_bd;   } else {      P->branchStatus = BranchStatus_none;   }   if (exnum < 0) {       if (exnum == -1) {         /* Coherency exception - Restart from point of exception */         if (in_delay) {           P->PC -= 4;           P->nPC = P->PC+4;         }         CopyToMXS (P);  /* Resets the MXS instruction window */         CPUPrint("MXS: Coherency exception at 0x%x time %lld\n", P->PC,                  (uint64) MipsyReadTime(P->myNum));      } else if (exnum == -2) {         /* Switch back to mipsy */         P->inMXS = 0;         P->switchToMIPSY = 0;         CopyToMXS(P);  /* This will cause MXS to be reset */         CPUPrint("MXS: Switching to MIPSY on CPU%d at 0x%x time %lld\n",                  P->myNum, P->PC, (uint64)MipsyReadTime(P->myNum));      } else if (exnum == -3) {         CPUPrint("MXS: About to ProcEXIT cpu %d at 0x%x time %lld\n",                  P->myNum, P->PC, (uint64)MipsyReadTime(P->myNum));         /* MakeProcessExit(P->myNum); */          CPUError("MakeProcessExit doesn't work\n");         CopyToMXS(P);  /* This will cause MXS to be reset */      } else if (exnum == -4) {         CPUPrint("MXS: About to EXIT cpu %d at 0x%x time %lld\n",                  P->myNum, P->PC, (uint64)MipsyReadTime(P->myNum));         CopyToMXS(P);  /* This will cause MXS to be reset */         MipsyExit(BASE);      }      return;   }

⌨️ 快捷键说明

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