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

📄 r4k_cp0.c

📁 一个用在mips体系结构中的操作系统
💻 C
📖 第 1 页 / 共 5 页
字号:
  if( GET_ASID( EMP[cpuNum].tlbEntry[idx].Hi ) == CURRENT_ASID(cpuNum)  ||      IS_GLOBAL_HI( EMP[cpuNum].tlbEntry[idx].Hi))     {        qc_map_page( cpuNum, idx);     }#ifndef EMBRA_USE_QC64  qc_CheckForDuplicate(curEmp, idx);#endif  return NORMAL_CODE;}/***************************************************************** * 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 EntryHi and EntryLo registers. *****************************************************************/uint Em_WriteTLBEntry(int cpuNum){  IndexReg index;  uint res;  ASSERT (curEmp->myNum == cpuNum);  if (!IS_KERNEL_MODE(curEmp)) {     Em_EXCEPTION(cpuNum,EXC_CPU,0);     ReenterTC(curEmp);  }  /* I'm going to assume that the index register is in the 	 correct range. */     index = EMP[cpuNum].CP0[C0_INX];  res = Do_TLB_Write( cpuNum, GET_IDX(index) );  if( res != NORMAL_CODE ) {     ReenterTC(&EMP[cpuNum]);     /* NOT REACHED */  }  return res;}/***************************************************************** * WriteRandomTLBEntry - * Write random TLB entry. The TLB entry pointed at by the contents   * of the TLB Random register is loaded with the contents of EntryHi * and EntryLo. * * Technically, the value of the Random register is decremented on * each machine clock cycle and ranges between NWIREDENTRIES * and NTLBENTRIES.  *  *****************************************************************/uint Em_WriteRandomTLBEntry(int cpuNum){   uint res;   unsigned numRandEntries = EMP[cpuNum].numTlbEntries - EMP[cpuNum].CP0[C0_TLBWIRED];   ASSERT (curEmp == &EMP[cpuNum]);   if (!IS_KERNEL_MODE(curEmp)) {      Em_EXCEPTION(cpuNum,EXC_CPU,0);      ReenterTC(curEmp);   }      res =  Do_TLB_Write( cpuNum,                         (EmbraCpuCycleCount(cpuNum) % numRandEntries) +                        EMP[cpuNum].CP0[C0_TLBWIRED] );   if( res != NORMAL_CODE ) {      ReenterTC(&EMP[cpuNum]);      /* NOT REACHED */   }   return res;}/***************************************************************** * REFILL_EXCEPTION  *  ****************************************************************/static void REFILL_EXCEPTION(int cpuNum, int code, int isInstr, VA pc, VA addr, int isXRefill){   if (isInstr) {       ITLB_MISS_EVENT(EmbraCpuCycleCount(cpuNum),cpuNum,addr);   } else {       DTLB_MISS_EVENT(EmbraCpuCycleCount(cpuNum),cpuNum,pc,addr);   }   Em_EXCEPTION(cpuNum, (isXRefill? XREFILL_FLAG : 0)|REFILL_FLAG|code,0); }/***************************************************************** * EXCEPTION -  * This is sort of a major routine.  * 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.)  don't put in kernel mode is in kernel mode when KSU = 0 or EXL = 1 * or ERL = 1, strictly speaking this is saved/restored by the software b/c  * it could either by user or supervisor modes. * 2.)  disable interrupts * 3.)  goto vector. * 4.)  on start cpu loads EPC with restart location... *   *  * checks BEV in sr. * but need new vector for bootstrap this is currently unused. * * This currently is set as the General Exception Handler(hardware) * Also Watch and FP Control Status Registers not set (would be set  * only when their exc occurs) ****************************************************************/void Em_EXCEPTION(int cpuNum, int code, int ce){   StatusReg statusReg;   Reg causeReg;   VA exceptionBase;   uint prettyCode;   int refill_flag = code & REFILL_FLAG;   int xrefill_flag = code & XREFILL_FLAG;   if (!EMP[cpuNum].outOfSlaveLoop)      return;   /*    * To make sure that we never return to the TC from here,    * we increment the tcGenCounter.     */   if (cpuNum == curEmp->myNum) {       tcGenNumber++;      exceptionDuringBackdoor = TRUE;   }  code &= ~(REFILL_FLAG);  code &= ~(XREFILL_FLAG);  prettyCode = code >> CAUSE_EXCSHIFT;  if (DEBUG_INTR()) {    LogEntry("EXCEPTION", cpuNum, "code: 0x%x\tintrbits: 0x%x\n",	     code, EMP[cpuNum].intrBitsPtr[0]);  }  STAT_TIMER_STOP( trans_timer );/* One more spot where we must set current cpu, because   the timers (and perhaps other things) will cause exceptions   on processors other than the "current" one. */  /* Get rid of curr_cpu soon.. *//*  curr_cpu = cpuNum; *//*  curEmp = &EMP[cpuNum];*/#ifdef DEBUG_CP0  {     /* Yes more than one bit can be set at once */     char* typeOfInt = "";     int hwIntrBits =(EMP[cpuNum].CP0[C0_CAUSE] & CAUSE_IPMASK)>>CAUSE_IPSHIFT;     /* XXX - Hand Copied from kern/ml/SIMMP.c */     if( hwIntrBits & 0x10 ) {        typeOfInt = "CLOCK";     }     if( hwIntrBits & 0x04 ) {        typeOfInt = "DISK or ETHER";     }     if( hwIntrBits & 0x20 ) {        typeOfInt = "IPI";     }     if( code == EXC_CPU ) {        CPUPrint("HW_EX %lld %d EXC %d %s CE %d PC 0x%x\n",                  EmbraCpuCycleCount(cpuNum),                 cpuNum,                 code>>2,                  typeOfInt,                 ce,                 EMP[cpuNum].PC);     } else {        /* Exclude UTLB misses */        if( code == EXC_RMISS || code == EXC_WMISS ) {} else            CPUPrint("HW_EX %lld %d EXC %d HWBits 0x%x %-5s %-5s PC 0x%x\n",                     EmbraCpuCycleCount(cpuNum),                    cpuNum,                     code>>2,                     hwIntrBits,                    (refill_flag?"U":" "),                    typeOfInt,                    EMP[cpuNum].PC);     }  }#endif  STAT_INC( exceptions );  STAT_EXC( exception_type, code>>2, refill_flag?1:0 );   statusReg.ts_data = EMP[cpuNum].CP0[C0_SR];      /*    * 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 = EMP[cpuNum].CP0[C0_CAUSE];  causeReg = CAUSE_SET_EXC_NOSHIFT( causeReg, code );  /* Read the branch delay indicator bit from the PC, */  causeReg = CAUSE_SET_BD( causeReg, IN_BD(EMP[cpuNum].PC) );  EMP[cpuNum].CP0[C0_CAUSE] = causeReg;   /*Is this exception the first? (we're not in another exception) */  if (statusReg.s32.ts_exl == 0){    if( IN_BD( EMP[cpuNum].PC ) ) {      /* Clear the indicator bit to make the PC usable */      EMP[cpuNum].CP0[C0_EPC] = CLEAR_BD(EMP[cpuNum].PC) - INST_SIZE;    } else {      EMP[cpuNum].CP0[C0_EPC] = EMP[cpuNum].PC;    }    statusReg.s32.ts_exl = 1;  }  EMP[cpuNum].CP0[C0_SR] = statusReg.ts_data;     /*The cause register is read-only.  The hardware is responsible for */   /*clearing it */  if( code == EXC_CPU ) {     EMP[cpuNum].CP0[C0_CAUSE] = CAUSE_SET_CE( EMP[cpuNum].CP0[C0_CAUSE], ce );  } else {     EMP[cpuNum].CP0[C0_CAUSE] = CAUSE_SET_CE( EMP[cpuNum].CP0[C0_CAUSE], 0 );  }  VASSERT( *(unsigned*)K0_TO_MEMADDR(M_FROM_CPU(cpuNum), E_VEC),           ("\n%d Took exception before system exception vector written\n"	    "PC = 0x%08x\n",             cpuNum, EMP[cpuNum].PC) );    ASSERT( statusReg.s32.ts_bev == 0);   /* are we bootstrapping? */  if (statusReg.s32.ts_bev == 0) {      exceptionBase = EXC_VEC_BASE_0;   } else {       CPUError("Hello Beth and Scott. Is Emmett insane ? \n");     exceptionBase = EXC_VEC_BASE_1;   }  /* I'm not even checking if it was a RESET EXCEPTION */  /* Exception can be called from places where fp regs are saved (cp0 */  /* and clock callouts) and from places they are not saved (cache */  /* callouts) */  if( refill_flag ) {     ASSERT( embra.emode == EMBRA_PAGE || embra.sequential|| EMP[cpuNum].outTC );     EMP[cpuNum].PC = exceptionBase;     if (xrefill_flag) {        EMP[cpuNum].PC = exceptionBase + XUT_VEC_OFFSET;     }  } else {     ASSERT( embra.emode == EMBRA_PAGE || embra.sequential || EMP[cpuNum].outTC );     EMP[cpuNum].PC = exceptionBase + E_VEC_OFFSET;  }  UpdateCPUMode(&EMP[cpuNum]);  ASSERT (EMP[cpuNum].cpuMode == KERNEL_MODE);  {     /*      *  really important:      *  In the case of an interrupt, ipi, ... an exception      *  can be raised on cpuNum while it is not curEmp!!!      */     EmbraState *backup = curEmp;     curEmp = &EMP[cpuNum];     if (refill_flag) {        UTLB_EVENT();     } else {        EXC_EVENT(prettyCode);     }     curEmp = backup;  }  /*   * Bill 1 cycle for the exception itself. This is really   * important as it matches MIPSY's handling of exceptions   */  EMP[cpuNum].cycleCountdown--;  }/* Called from emitted code to raise breakpoint and syscall (others?) *//* exceptions */void Em_RaiseEXCEPTION(int cpuNum, int code, int ce){   Em_EXCEPTION(cpuNum, code, ce);   ReenterTC(&EMP[cpuNum]);   /* NOT REACHED */}/*R4000*********************************************************** * 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 Em_ExceptionReturn(int cpuNum){   StatusReg statusReg;   VA restoreAddr;   ASSERT( curEmp == &EMP[cpuNum]);   if (!IS_KERNEL_MODE(curEmp)) {      Em_EXCEPTION(cpuNum,EXC_CPU,0);      ReenterTC(curEmp);   }   if (DEBUG_INTR()) {     LogEntry("CPUMode", cpuNum, " ERET at %x \n",curEmp->PC);   }/* Annotations:*/   ASSERT (curEmp->myNum == cpuNum);   RFE_EVENT();   statusReg.ts_data = EMP[cpuNum].CP0[C0_SR];   if (statusReg.s32.ts_erl){     restoreAddr = EMP[cpuNum].CP0[C0_ERROR_EPC];     EMP[cpuNum].PC = restoreAddr;     statusReg.s32.ts_erl = 0;   } else {     restoreAddr = EMP[cpuNum].CP0[C0_EPC];     EMP[cpuNum].PC = restoreAddr;     statusReg.s32.ts_exl = 0;   }      EMP[cpuNum].CP0[C0_SR] = statusReg.ts_data;   UpdateCPUMode(&EMP[cpuNum]);   EMP[cpuNum].LLAddr = 0;   EMP[cpuNum].LLBit = 0;   /*    * Increment the cycle count, since the ERET     * instruction actually takes one cycle    */   EMP[cpuNum].cycleCountdown--;/* check for interrupts before we leave...*/   if (Update_And_Check_Interrupts(cpuNum,0)){   }      ReenterTC(&EMP[cpuNum]);}/***************************************************************** * RestoreFromException * Restore contol to a process that an exception preempted. This * restores the previous interrumpt mask and kernel/user mode bits * in the status register, moves the old to the previous, and keeps * the old unchanged.  ****************************************************************/void Em_RestoreFromException( int cpuNum , VA restoreAddr ){ CPUError("Embra:cp0 rfe on cpu %i, curEmp->myNum=%i, ~ERT on R4000!\n",                   cpuNum,curEmp->myNum);    }/***************************************************************** * Em_MoveFromC0 ****************************************************************/uintEm_MoveFromC0(int cpuNum, Inst instr){   unsigned gp_reg =  rt(instr);  /* dest   */   unsigned co_reg =  rd(instr);  /* source */   /* ASSERT( gp_reg < 32 && co_reg < 32 );*/

⌨️ 快捷键说明

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