📄 cpu.c
字号:
* Called from the main execution loop each time an instruction * is needed. The first argument is the PC value to read from. * "backdoor" is a way of avoiding going through the cache * and memory system to directly access something in our real-life * address space (mipsy or simos). This procedure better be as fast as * possible!!! The Result returned is just a way of telling the * processor whether it has to stall or not (i.e. if there was an icache * miss. *****************************************************************/static ResultReadInstruction(VA vAddr, Inst *inst) { Result ret; PA pAddr; int64 bdoorRetval = 0; uint tlbFlavor = TLB_IFETCH|TLB_READING; void *bdoorAddr = 0; if (TranslateVirtual(P, vAddr, &pAddr, &tlbFlavor, &bdoorAddr) != SUCCESS) return FAILURE; if (!tlbFlavor) { P->pcVPNcache = PAGE_NUMBER(vAddr); P->pcPaddrcache = FORM_ADDR(PAGE_NUMBER(pAddr), 0); if (SKIP_CACHES(P)) { *inst =*(Inst *)HOST_DATA_ADDR(vAddr, pAddr, P->myNum); return SUCCESS; } ret = MemRefReadInst(P->myNum, vAddr, pAddr, inst); if (ret != SUCCESS) { if ((ret == STALL) || (ret == FAILURE)) { P->stalledInst = 0; P->cpuStatus = cpu_stalled; } else if (ret == BUSERROR) { RECORD_EXCEPTION(P, EXC_IBE, E_VEC, vAddr, P->CP0[C0_TLBHI], P->CP0[C0_CTXT], P->CP0[C0_XCTXT]); } else { CPUWarning("Unknown return value (%d) from ReadICache\n", ret); } } /* * The processor can have been idled as a consequence of an annotations * For now, we can implement this by checking for the cpuStatus */ if (P->cpuStatus == cpu_idle) { P->stalledInst = 0; ret = FAILURE; } return ret; } else {#ifndef SOLO /* this might be one of three things: * the boot prom (provided by flashlite) * the prom slave loop (SimOS magic) * a backdoor call */ if (tlbFlavor & TLB_UNCACHED) { /* executing instructions from the prom provided by flashlite * or simmagic */ return UncachedRead(vAddr, pAddr, inst, WORD_SZ); } /* A backdoor call. Execute it on the real CPU. This */ /* assumes that all backdoor calls take less than 4 */ /* arguments. */ ret = MemRefSync(P->myNum); if (ret != SUCCESS) { /* Make sure all cached and uncached writes are flushed * out of buffers before doing a backdoor call. This * is needed for calls that start I/O. */ return FAILURE; } SIM_DEBUG(('b', "MIPSY:CPU %d: Backdoor call at PC %#x PA %#x RA %#x\n", P->myNum, P->PC, pAddr, P->R[31])); if (tlbFlavor == TLB_BDOOR_DATA) { *inst = *(Inst *)bdoorAddr; } else if (tlbFlavor == TLB_BDOOR_FUNC) { Result returnFlag; returnFlag = ((Result (*)(int, uint, uint, unsigned char *))bdoorAddr) (P->myNum, vAddr, BDOOR_LOAD_WORD, (unsigned char *)inst); if (returnFlag == SUCCESS) { return SUCCESS; } else if (returnFlag == BUSERROR) { RECORD_EXCEPTION(P, EXC_IBE, E_VEC, vAddr, P->CP0[C0_TLBHI], P->CP0[C0_CTXT], P->CP0[C0_XCTXT]); return BUSERROR; } else { CPUError("Unknown result type: 0x%x\n", returnFlag); } } else { ASSERT(tlbFlavor == TLB_BDOOR_FUNC_COMPAT); bdoorRetval = ((int64 (*)(int,int,int,int)) (bdoorAddr))(P->R[4],P->R[5],P->R[6],P->R[7]); P->R[2] = bdoorRetval >> 32; P->R[3] = bdoorRetval & 0xffffffff; *inst = 0; /* NOP */ P->nPC = P->R[31]; } return SUCCESS;#endif#ifdef SOLO /* Solo Mipsy has back door calls that need to be handled */ /* We may need to know our cpu number at this time */ soloCPUNum = P->myNum; bdoorRetval = ((int64 (*)(int,int,int,int))P->PC) (P->R[4],P->R[5],P->R[6],P->R[7]); P->R[2] = bdoorRetval >> 32; P->R[3] = bdoorRetval & 0xffffffff; P->nPC = P->R[31]; *inst = 0; /* NOP */ STATS_INC(P->myNum, numBdoorInsts, 1); return SUCCESS;#endif }}/**************************************************************** * MipsyReadMem * * Common routine used by the CPU to read memory. *****************************************************************/ResultMipsyReadMem(VA vAddr, void *data, RefSize size, RefFlavor flavor){ Result ret; PA pAddr; uint tlbFlavor = TLB_READING; void *bdoorAddr = 0; ret = TranslateVirtual(P, vAddr, &pAddr, &tlbFlavor, &bdoorAddr); if (ret == SUCCESS) { if (!tlbFlavor) { if (flavor & LL_FLAVOR) { P->LLAddr = pAddr & ~(SCACHE_LINE_SIZE-1); if (UNCACHED_LL_SC) { LLAddrs[P->myNum] = pAddr & ~(SCACHE_LINE_SIZE-1); } } if (SKIP_CACHES(P)) { switch (size) { case BYTE_SZ: *(byte *)data = *(byte *)HOST_DATA_ADDR(vAddr, pAddr, P->myNum); break; case HALF_SZ: *(short *)data = BE2HO_2(*(short *)HOST_DATA_ADDR(vAddr, pAddr, P->myNum)); break; case WORD_SZ: *(uint *)data = BE2HO_4(*(uint *)HOST_DATA_ADDR(vAddr, pAddr, P->myNum)); break; case DOUBLE_SZ: *(int64 *)data =BE2HO_8(*(int64 *)HOST_DATA_ADDR(vAddr, pAddr, P->myNum)); break; default: CPUError("Bad size in MipsyReadMem\n"); ASSERT(0); } return SUCCESS; } /* Go through the cache interface */ switch (size) { case BYTE_SZ: ret = MemRefReadData(P->myNum, vAddr, pAddr, data, BYTE_SZ, NO_FLAVOR); break; case HALF_SZ: ret = MemRefReadData(P->myNum, vAddr, pAddr, data, HALF_SZ, NO_FLAVOR); *(short *)data = BE2HO_2(*(short *)data); break; case WORD_SZ: ret = MemRefReadData(P->myNum, vAddr, pAddr, data, WORD_SZ, flavor); *(uint *)data = BE2HO_4(*(uint *)data); break; case DOUBLE_SZ: ret = MemRefReadData(P->myNum, vAddr, pAddr, data, DOUBLE_SZ, flavor); *(int64 *)data = BE2HO_8(*(int64 *)data); break; default: CPUError("Bad size in MipsyReadMem\n"); ASSERT(0); } if (ret != SUCCESS) { if ((ret == STALL) || (ret == FAILURE)) { P->cpuStatus = cpu_stalled; } else if (ret == BUSERROR) { RECORD_EXCEPTION(P,EXC_DBE, E_VEC, vAddr, P->CP0[C0_TLBHI], P->CP0[C0_CTXT], P->CP0[C0_XCTXT]); return ret; } else { CPUWarning("Bad return value (%d) from MemRefReadData\n", ret); } } else { /* We hit in the DCACHE */ CHECK_LD_ANN(vAddr, pAddr); STATS_INC(P->myNum, dReads, 1); } } else { if (tlbFlavor & TLB_UNCACHED) { ret = UncachedRead(vAddr, pAddr, data, size);#ifdef HWBCOPY if ((size == DOUBLE_SZ) && (tlbFlavor == TLB_MSG_SPACE)) ret = SUCCESS;#endif } else if (tlbFlavor == TLB_BDOOR_DATA) { STATS_INC(P->myNum, numBdoorInsts, 1); switch (size) { case BYTE_SZ: *(byte *)data = *(byte *)bdoorAddr; break; case HALF_SZ: *(short *)data = *(short *)bdoorAddr; break; case WORD_SZ: *(uint *)data = *(uint *)pAddr; break; case DOUBLE_SZ: *(uint64 *)data = *(uint64 *)bdoorAddr; break; default: CPUError("Bad size in MipsyReadMem\n"); ASSERT(0); } return SUCCESS; } else { Result returnFlag; ASSERT(tlbFlavor == TLB_BDOOR_FUNC); switch (size) { case BYTE_SZ: returnFlag = ((Result (*)(int, uint, uint, unsigned char *))bdoorAddr) (P->myNum, vAddr, BDOOR_LOAD_BYTE, data); break; case HALF_SZ: returnFlag = ((Result (*)(int, uint, uint, short *))bdoorAddr) (P->myNum, vAddr, BDOOR_LOAD_HALF, data); break; case WORD_SZ: returnFlag = ((Result (*)(int, uint, uint, int*))bdoorAddr) (P->myNum, vAddr, BDOOR_LOAD_WORD, data); break; case DOUBLE_SZ: returnFlag = ((Result (*)(int, uint, uint, uint64 *))bdoorAddr) (P->myNum, vAddr, BDOOR_LOAD_DOUBLE, data); break; default: CPUError("Bad size in MipsyReadMem\n"); ASSERT(0); } if (returnFlag == SUCCESS) { return SUCCESS; } else if (returnFlag == BUSERROR) { RECORD_EXCEPTION(P, EXC_DBE, E_VEC, vAddr, P->CP0[C0_TLBHI], P->CP0[C0_CTXT], P->CP0[C0_XCTXT]); return BUSERROR; } else { CPUError("Unknown result type: 0x%x\n", returnFlag); } } } } return ret;}/* Used by solo */ResultSoloReadByte(int cpuNum, VA vAddr, char *data){ return MipsyReadMem(vAddr, (void *)data, BYTE_SZ, NO_FLAVOR);}/**************************************************************** * MipsyWriteMem * * Common routine used by the CPU to write memory. *****************************************************************/ResultMipsyWriteMem(VA vAddr, void *data, RefSize size, RefFlavor flavor){ Result ret; PA pAddr; uint tlbFlavor = TLB_WRITING; void *bdoorAddr = 0; if (TranslateVirtual(P, vAddr, &pAddr, &tlbFlavor, &bdoorAddr) != SUCCESS) { return FAILURE; } if (flavor == SC_FLAVOR) { if (!P->LLbit) return SCFAILURE; } if (!tlbFlavor) { /* Special code to handle LL/SC when caches are inactive */ if (UNCACHED_LL_SC) { if (numLLactive) { int cpu; PA matchAddr = pAddr & ~(SCACHE_LINE_SIZE-1); if (P->LLbit) { P->LLbit = 0; LLAddrs[P->myNum] = (PA) -1; numLLactive--; } for (cpu = 0; cpu < TOTAL_CPUS; cpu++) { if (LLAddrs[cpu] == matchAddr) { PE[cpu].LLbit = 0; LLAddrs[cpu] = (PA) -1; numLLactive--; } } } } if (SKIP_CACHES(P)) { switch (size) { case BYTE_SZ: *(byte *)HOST_DATA_ADDR(vAddr, pAddr, P->myNum) = *(byte *)data; break; case HALF_SZ: *(short *)HOST_DATA_ADDR(vAddr, pAddr, P->myNum) = HO2BE_2(*(short *)data); break; case WORD_SZ: *(uint *)HOST_DATA_ADDR(vAddr, pAddr, P->myNum) = HO2BE_4(*(uint *)data); break; case DOUBLE_SZ: *(uint64 *)HOST_DATA_ADDR(vAddr, pAddr, P->myNum) = HO2BE_8(*(uint64 *)data); break; default: ASSERT(0); } return SUCCESS; } /* Normal path through the cache interface. */ switch (size) { case BYTE_SZ: ret = MemRefWriteData(P->myNum, vAddr, pAddr, *(byte *)data, BYTE_SZ, NO_FLAVOR); break; case HALF_SZ: ret = MemRefWriteData(P->myNum, vAddr, pAddr, HO2BE_2(*(short *)data), HALF_SZ, NO_FLAVOR); break; case WORD_SZ: ret = MemRefWriteData(P->myNum, vAddr, pAddr, HO2BE_4(*(uint *)data), WORD_SZ, flavor); break; case DOUBLE_SZ: ret = MemRefWriteData(P->myNum, vAddr, pAddr, HO2BE_8(*(uint64 *)data), DOUBLE_SZ, flavor); break; default: ASSERT(0); } if (ret != SUCCESS) { if ((ret == STALL) || (ret == FAILURE)) { P->cpuStatus = cpu_stalled; } else if (ret == BUSERROR) { RECORD_EXCEPTION(P, EXC_DBE, E_VEC, vAddr, P->CP0[C0_TLBHI], P->CP0[C0_CTXT], P->CP0[C0_XCTXT]) ; return ret; } else if (ret == SCFAILURE) { /* This is OK, isn't it? */ } else { CPUWarning("Bad return value (%d) from MemRefWriteData\n", ret); } } else { CHECK_ST_ANN(vAddr, pAddr); STATS_INC(P->myNum, dWrites, 1); } return ret; } if (tlbFlavor & TLB_UNCACHED) { return UncachedWrite(vAddr, pAddr, data, size, (bool)tlbFlavor & TLB_ACCELERATED);#ifdef HWBCOPY } else if (tlbFlavor & TLB_MSG_SPACE) { return SUCCESS;#endif } else if (tlbFlavor == TLB_BDOOR_DATA) { #ifndef SOLO ASSERT(0);#endif switch (size) { case BYTE_SZ: *(byte *)bdoorAddr = *(byte *)data; break; case HALF_SZ: *(short *)bdoorAddr = *(short *)data; break; case WORD_SZ: *(uint *)pAddr = *(uint *)data; break; case DOUBLE_SZ:#ifdef SOLO *(uint64 *)pAddr = *(uint64 *)data;#else *(uint64 *)bdoorAddr = *(uint64 *)data;#endif break; default: ASSERT(0); } return SUCCESS; } else { Result returnFlag;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -