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

📄 r4k_cp0.c

📁 一个用在mips体系结构中的操作系统
💻 C
📖 第 1 页 / 共 5 页
字号:
/***************************************************************** * WriteC0Register *  * All writes to coprocessor come here for handling. This allows  * us to do whatever we want with read-only bits, etc. *****************************************************************/static voidWriteC0Register(CPUState *P, int c0RegNum, Reg value, int is64bit){   if (cp0RegCtl[c0RegNum].read_only) {      return;   }   if (cp0RegCtl[c0RegNum].size == -1) {      CPUWarning("WriteC0Reg write to invalid reg %d\n",                 c0RegNum);   }   if ((cp0RegCtl[c0RegNum].zero_mask & value) != 0) {      /* Trying to write must be zero bits, force them to zero. */      value &= ~cp0RegCtl[c0RegNum].zero_mask;      /* Print a warning message for the programmer. Special       * case 32bit signed-extention bits that set high zero bits       * of 64 bit registers (IRIX 6.2 does this).        */      if (is64bit || (cp0RegCtl[c0RegNum].size != 1) ||            ((cp0RegCtl[c0RegNum].zero_mask & value & 0xffffffff) != 0)) { #if defined(TORNADO) || defined(IRIX6_4)         /* for now, tornado sometimes writes funny values for tlb stuff */         /* So does IRIX 6.4 that that matter */        int warning = (c0RegNum != C0_TLBLO_0) && (c0RegNum != C0_TLBLO_1);#else         int warning = 1;#endif         if (warning) {             CPUWarning("WriteC0Reg zero bits set during write to %d @%#lx RA %#lx, clearing\n",                       (int)c0RegNum, (long)P->PC, (long)P->R[31]);	    /* got rid of the evil %llx -- PZ */         }      }   }   if (is64bit && (cp0RegCtl[c0RegNum].size == 0)) {#ifdef IRIX6_4             if (c0RegNum != C0_SR) #endif      CPUWarning("WriteC0Reg 64bit write to 32bit reg %d\n",                 c0RegNum);   }   if (c0RegNum == C0_CAUSE){       P->CP0[C0_CAUSE] &= ~(CAUSE_SW2|CAUSE_SW1);      P->CP0[C0_CAUSE] |= (value & (CAUSE_SW2|CAUSE_SW1));   } else {       P->CP0[c0RegNum] = value;           }   if (c0RegNum == C0_COMPARE) {      CompareWritten(P);   }      if (c0RegNum == C0_COUNT) {      CountWritten(P);   }   if (c0RegNum == C0_TLBHI) {      /* Clear the fill bits */      P->CP0[c0RegNum] &= TLBHI_FILLMASK;      /* Might be changing the ASID */      P->pcVPNcache = 0;       TraceCheckASID(P);   }   if (c0RegNum == C0_SR){       StatusReg statusReg;      statusReg.ts_data = P->CP0[C0_SR];#if defined(SIM_MIPS32)      if ((statusReg.s32.ts_ux) || (statusReg.s32.ts_sx) ||          (statusReg.s32.ts_kx)) {         static int warned_64 = 0;         if (!warned_64) {            CPUWarning("MIPSY: 64-bit mode not implemented, ignoring SR write\n");            warned_64 = 1;         }                  statusReg.s32.ts_ux = 0;         statusReg.s32.ts_sx = 0;         statusReg.s32.ts_kx = 0;         P->CP0[C0_SR] = statusReg.ts_data;      }#endif      /* Don't allow reverse endian either. */      if (statusReg.s32.ts_re) {         static int warned_re = 0;         if (!warned_re) {            CPUWarning("MIPSY: reverse-endian mode not implemented, ignore SR write\n");            warned_re = 1;         }         statusReg.s32.ts_re = 0;      }      UpdateCPUMode(P);      MipsyCheckForInterrupts(P);   }   if (c0RegNum == C0_CAUSE){       MipsyCheckForInterrupts(P);   }} /***************************************************************** * R4000 Timer support *****************************************************************/ static EventCallbackHdr timerCallbackHdr[MIPSY_MAX_CPUS];static void MipsySetTimerCallback(int cpuNum);/***************************************************************** * Things that need doing when the compare register is written.  * Right now just timer related actions. *****************************************************************/static voidCompareWritten(CPUState *P){   int cpuNum = P->myNum;   /* make sure upper bits are zero */   P->CP0[C0_COMPARE] &= 0xffffffff;   PE[cpuNum].CP0[C0_CAUSE] &= ~CAUSE_IP8;   if (EventCallbackActive(&(timerCallbackHdr[cpuNum]))) {      EventCallbackRemove(&(timerCallbackHdr[cpuNum]));   }   MipsySetTimerCallback(cpuNum); }/***************************************************************** * Things that need doing when the count register is written.  * Right now just timer related actions. *****************************************************************/static voidCountWritten(CPUState *P) {   int cpuNum = P->myNum;   /* make sure upper bits are zero */   P->CP0[C0_COUNT] &= 0xffffffff;   P->timerCycleCount = MipsyReadTime(P->myNum);   if (EventCallbackActive(&(timerCallbackHdr[cpuNum]))) {      EventCallbackRemove(&(timerCallbackHdr[cpuNum]));   }   MipsySetTimerCallback(cpuNum);}/**************************************************************** * TMipsyimerCallback * * This is the routine called back on the event that * the C0_COMPARE == C0_COUNT, it is  set when the  * COMPARE register is written.  Raise IP(7) in the  * C0_CAUSE register to signal a timer interrupt is  * pending.  Note: IP(7) is cleared when when the  * C0_COMPARE register is written. use DEV_IEC_MAGICERR * as it corresponds to hw interrupt bit #5 which raises * ip7 in the cause register. ****************************************************************/static void MipsyTimerCallback(int cpuNum, EventCallbackHdr *ECBhdr, void *empty) {  if (simosCPUType != MIPSY) {     return;  }  PE[cpuNum].CP0[C0_CAUSE] |= CAUSE_IP8;  MipsyCheckForInterrupts(&PE[cpuNum]);}/***************************************************************** * MipsySetTimerCallback * * Each processor has its own r4kTimerInfo and r4k_timerHdr * associated with it.  When the Compare register is written to * we check current cycle count, and, projecting into the future the * diff btwn the new Compare reg value and the current cycle count, a * callback is set to fire in that calculate amt of time.  It is tricky * only when they decide to write to the count reg, which is permited on * system initialization or to synchronize processors.  Since we do not  * update the Count register continually, our cycle count and the Count * register value could then be out-of-synch.  The r4kTimerInfo variable * is used to track this discrepency. ****************************************************************/static void MipsySetTimerCallback(int cpuNum){   CPUState *P = &PE[cpuNum];    SimTime  timeInFuture;   P->CP0[C0_COUNT] += (MipsyReadTime(cpuNum) - P->timerCycleCount)/      COUNTER_FREQUENCY_DIVIDER;   P->timerCycleCount = MipsyReadTime(cpuNum);      P->CP0[C0_COUNT] &= 0xffffffff;   if (P->CP0[C0_COMPARE] >= P->CP0[C0_COUNT]) {       timeInFuture =  (P->CP0[C0_COMPARE] - P->CP0[C0_COUNT]);       timeInFuture *=  COUNTER_FREQUENCY_DIVIDER;   } else {       timeInFuture =  0x100000000LL - (P->CP0[C0_COUNT] - P->CP0[C0_COMPARE]);       timeInFuture *=  COUNTER_FREQUENCY_DIVIDER;   }   EventDoCallback(cpuNum, MipsyTimerCallback,                    &(timerCallbackHdr[cpuNum]), NULL, timeInFuture);}/***************************************************************** * CHECKING OF INTERRUPTS *****************************************************************//***************************************************************** * CheckForInterrupts callback * This callback is in charge of polling for interrupts and checking  * if mipsy should be exited. You can exit by running the set number * of cycles or by attaching with a debugger and setting "mipsyExit" * to true. *****************************************************************/static struct CheckForInterruptsCallbackHdr {    EventCallbackHdr hdr;   SimTime interval;} checkForInterruptsEvent[SIM_MAXCPUS];extern bool exitMipsy;static voidCheckForInterruptsCallback(int cpuNum, EventCallbackHdr *hdr, void *empty){   int cpu;   if (simosCPUType != MIPSY) {      return;   }   for (cpu = 0; cpu < TOTAL_CPUS; cpu++) {      MipsyCheckForInterrupts(&PE[cpu]);   }   EventDoCallback(cpuNum, CheckForInterruptsCallback, hdr, 0,                    checkForInterruptsEvent[cpuNum].interval);   /* Another way of leaving mipsy is to attach to it with the */   /* debugger and set the exitMipsy flag to TRUE */   if (exitMipsy) {      CPUPrint("exitMipsy set to true (by debugger)\n");      MipsyExit(BASE);   }}void EnableInterruptCheck(CPUState *P, int interval){   checkForInterruptsEvent[P->myNum].interval = interval;   EventDoCallback(P->myNum, CheckForInterruptsCallback,                    &checkForInterruptsEvent[P->myNum].hdr,                    0, interval);}#ifdef MIPSY_MXS/***************************************************************** * DoPrivInst - Perform a priviledged instruction for MXS.  *              MXS passes us the instr and any source register *              values that come from the GP register set. We return *              to MXS any destination registers. *****************************************************************/      boolDoPrivInst(struct s_cpu_state *st, uint instr, uint srcreg, uint *dstreg,            bool *hack){   CPUState *P = (CPUState *) (st->mipsyPtr);   uint rs = RS(instr);   uint rd = RD(instr);   uint op = MAJOR_OP(instr);   (*hack) = FALSE;      if (!IS_KERNEL_MODE(P)) {      /* CP0 is unusable */      CPUWarning("Using CP0 inst in user mode!\n");      RECORD_EXCEPTION(P, EXC_CPU, E_VEC, 0,  P->CP0[C0_TLBHI],                        P->CP0[C0_CTXT],P->CP0[C0_XCTXT]);      return TRUE;   }   if (op == cop0_op) {       /* First handle the rs instructions */      switch(rs) {      case bc_op:         CPUError("BCC0 is not valid\n");         break;      case mfc_op:         (*dstreg) = P->CP0[rd];         break;      case mtc_op:        /*BAN: BEGIN*/        if (rs == dmtc_op) {           WriteC0Register(P, rd, srcreg, 1);        } else {          WriteC0Register(P, rd, (Reg32_s)srcreg, 0);        }         /*BAN: END*/        break;            default:          /* It wasn't any of these, so it's a CO function */         CopyFromMXS(P);         switch(FUNC(instr)) {         case eret_op:            P->LLbit = 0;#ifdef BANREMOVE            if (P->numInstructions >= P->nextInstrSample) {               INST_SAMPLE_EVENT(MipsyReadTime(P->myNum), P->myNum, P->PC);               P->nextInstrSample += MS_SAMPLE_INSTR_INTERVAL;            }#endif            /*BAN: BEGIN*/            ExceptionReturn(P);            /*BAN: END*/            (*hack) = TRUE;            break;         case rfe_op:            CPUError("MIPSY: Hit an RFE on an R4000\n");            break;         case tlbp_op:            ProbeTLB(P);            break;         case tlbr_op:            ReadTLBEntry(P);            break;         case tlbwi_op:            WriteTLBEntry(P);            break;         case tlbwr_op:            WriteRandomTLBEntry(P);            break;         default:            CPUWarning("COP0 instruction not found at %#x\n", P->PC);            break;         } /* cp0 functions */      } /* rs values */   } else if (op == cache_op) {      /* Be careful with this one. Mipsy's caches are         physically indexed. */      uint targetCache;      targetCache = TARGET_CACHE(instr);      switch(targetCache) {      case CACH_PI:      case CACH_PD:      case CACH_SI:         CPUWarning("Bad op for cache instruction\n");         break;      case CACH_SD:         CPUWarning("Bad op for cache instruction\n");         break;      default:            CPUWarning("BAD TARGET CACHE at %#x\n", P->PC);            break;       }   } else {      CPUError("Unknown CP0 opcode in DoPrivInst\n");   }   return FALSE;}#endif

⌨️ 快捷键说明

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