📄 cpu.c
字号:
EXCEPTION(P, EXC_INT); } } }#ifdef MIPSY_MXS if (P->inMXS) { mxs: ms_cycle_once (P->st); continue; } else { if (P->switchToMXS && (P->PC == P->nPC-4) && (P->stalledInst == 0)) { P->inMXS = 1; P->switchToMXS = 0; CopyToMXS(P); CPUWarning("MXS: Switching to MXS on CPU%d at 0x%x time %lld\n", cpuNum, P->PC, (uint64)MipsyReadTime(cpuNum)); goto mxs; } }#endif /* * Shortcut to keep from going through ReadInstruction again * after an instruction caused a dcache miss and stalled. When * the processor's data cache miss completes, we'll still have * the instruction ready and waiting. */ if (P->stalledInst) { instr = P->stalledInst; P->stalledInst = FALSE; } else { Result ret; VA vAddr = P->PC; /* * Anything we can do to avoid translating the virtual * address is a good thing. This is a quick check to see if * the current instruction is on the same page as the last * one. If so, we don't have to translate it again. This * cache entry is of course cleared whenever there is a * chance that this translation is no longer correct. */ if (PAGE_NUMBER(vAddr) == P->pcVPNcache) { PA p = P->pcPaddrcache + PAGE_OFFSET(vAddr); if (SKIP_CACHES(P)) { instr = *(Inst *)HOST_DATA_ADDR(vAddr, p, cpuNum); } else { /* * Do a quick check if this was in the last line * checked. This cached address is set on a icache hit and * is invalidated whenever a line is flushed from the * icache. This could be changed to selectively delete the * line, but these are infrequent actions. */ if (QUICK_ICACHE_CHECK(p, P)) { int lineIndex; /* * Quick cache hit! Be careful here - it won't work * with bypassing l1 caches right now. Don't need to * touch the lru bit since it will be set to this line. */ MS_INSTRUCTION_SET(P->myNum, P->cachedSetIndex); MS_INSTRUCTION(cpuNum, p); lineIndex = p & (ICACHE_LINE_SIZE-1); instr = *(Inst *) (P->cachedILineData + lineIndex); } else { /* * 2nd quickest route to the icache, no translation * needed, but we must check the cache. */ ret = MemRefReadInst(cpuNum, vAddr, p, &instr); if (ret != SUCCESS) { if ((ret == STALL) || (ret == FAILURE)) { P->stalledInst = 0; STATS_SET(cpuNum, stallStart, MipsyReadTime(cpuNum)); P->cpuStatus = cpu_stalled; continue; } 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 { CPUError("Bad return(%d) from ReadICache\n", ret); } } } } } else { /* * This is the slow path to get an instruction. Full address * translation and checking of the Icache is required. */ ret = ReadInstruction(vAddr, &instr); if (ret != SUCCESS) { if (P->cpuStatus != cpu_running) { STATS_SET(cpuNum, stallStart, MipsyReadTime(cpuNum)); } continue; } else { STATS_ADD_INTERVAL(cpuNum, stallTime, stallStart); } } /* * The stalledInstr is stored in HO. In all other cases, we * instruction is fetched in BE and must be converted to HO. */ instr = BE2HO_4(instr); STATS_INC(cpuNum, iReads, 1); }; if (mipsy_debug_mode) { if ((cpuNum == mipsy_break_nexti) || (mipsy_break_nexti == MIPSY_BREAKANYCPU)) { /* * MipsyDebug returns nonzero if the PC has changed * or the contents of it have been overwritten, so it * needs to be reloaded. */ if (MipsyDebug(cpuNum, 1)) { continue; } } else if (mipsy_sigusr) { mipsy_debug_mode = 0; mipsy_sigusr = 0; AnnExec(AnnFind("simos", "sigusr")); } } op = MAJOR_OP(instr); if (mipsOpcodes[op].func(instr, P) == SUCCESS) { /* CPUPrint("PC %llx - %s\n", P->PC, mipsOpcodes[op].opname); */ /* Things to do after every successful instruction */ FIX_REG_ZERO; INSTRUCTION_DONE_EVENT(); if (RunPCAnnotations(P->PC, P->nPC)) continue; P->PC = P->nPC; if (P->branchStatus == BranchStatus_taken) { P->nPC = P->branchTarget; } else { P->nPC += INST_SIZE; } if (P->branchStatus == BranchStatus_taken || P->branchStatus == BranchStatus_nottaken ) { P->branchStatus = BranchStatus_bd; } else { P->branchStatus = BranchStatus_none; } } }}/***************************************************************** * DoneRunning *****************************************************************/static voidDoneRunning(void) { PrintRealTime("Simulation End"); MipsyExitFPU(); /* * Mark as much true sharing as possible */ FalseSharingCleanup(); if (SKIP_CACHES(P)) { CPUWarning("DoneRunning and no caches being used\n"); } else { if (mipsySyncWhenDone) { Result allret, ret; int timeout, i; CPUPrint("Syncing all processors at time %lld\n", (uint64) MipsyReadTime(0)); for (timeout = 0; timeout < 1000*1000; timeout++) { allret = SUCCESS; for (i = 0; i < TOTAL_CPUS; i++) { if (PE[i].cpuStatus == cpu_running) { ret = MemRefSync(i); if (ret == STALL) { allret = ret; } } else { if (PE[i].cpuStatus != cpu_halted && PE[i].cpuStatus != cpu_idle) { allret = STALL; } } } if (allret == SUCCESS) break; MIPSY_ADD_TIME(0, 1); EventPollSingleQueue(MipsyReadTime(0)); } if (allret != SUCCESS) CPUWarning("Sync failed!\n"); } }}/***************************************************************** * Mipsy-specific annotation code *****************************************************************/voidMipsyInstallMemAnnotation(VA vAddr){ /* Think of a clever way to optimize this! */}/***************************************************************** * MipsyTclInit - mipsy-specific tcl/memstat initialization*****************************************************************/extern int memstatOption;#define MemStatNone 0#define MemStatGlobal 1void MipsyTclInit(Tcl_Interp *interp){ Tcl_CreateCommand(interp, "instDump", PrintInstTclCmd, (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL); Tcl_CreateCommand(interp, "printInsts", PrintInstTclCmd, (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);#ifdef DASH_PREFETCH Tcl_CreateCommand(interp, "dashPrefetch", DashTclCmd, (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);#endif Tcl_CreateCommand(interp, "verboseDebug", InterpretVerboseDebug, (char *)NULL, (Tcl_CmdDeleteProc*)NULL);#ifdef TRACING Tcl_CreateCommand(interp, "traceDump", TraceDumpTclCmd, (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);#endif Tcl_LinkVar(interp, SaveString("SIMOS(SOLO)"), (char*)&isSolo, TCL_LINK_READ_ONLY | TCL_LINK_BOOLEAN); ParamRegister("PARAM(CPU.Mipsy.MipsySampleCycles)", (char *)&mipsyRunInterval, PARAM_INT); ParamRegister("PARAM(CPU.Mipsy.MXSSampleCycles)", (char *)&mxsRunInterval, PARAM_INT);#ifdef SOLO memstatOption = MemStatNone;#else memstatOption = MemStatGlobal;#endif#ifdef MIPSY_MXS ms_events_init();#endif}/***************************************************************** * Tcl interface for controlling mipsy's vebose debugging *****************************************************************/int InterpretVerboseDebug(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[]){#ifndef DEBUG_DATA_VERBOSE Tcl_AppendResult(interp, "verboseDebug not supported unless mipsy compiled -DDEBUG_DATA_VERBOSE", NULL); return TCL_ERROR;#else #ifndef SOLO if (simosCPUType != MIPSY) { Tcl_AppendResult(interp, "verboseDebug not supported unless running in mipsy", NULL); return TCL_ERROR; }#endif if (argc < 2) { Tcl_AppendResult(interp, "Bad: should be: verboseDebug <on|off>", NULL); return TCL_ERROR; } if (!strcmp(argv[1], "off")) { CPUWarning("verboseDebug: Turning verbose cache debugging OFF\n"); verboseDebugEnabled = 0; } else if (!strcmp(argv[1], "on")) { CPUWarning("verboseDebug: Turning verbose cache debugging ON\n"); verboseDebugEnabled = 1; } else { Tcl_AppendResult(interp, "bad: should be: verboseDebug <on|off>", NULL); return TCL_ERROR; } return TCL_OK;#endif}void MXSSwitch(int cpu, int enterMXS){#ifdef MIPSY_MXS if ((PE[cpu].inMXS && enterMXS) || (!PE[cpu].inMXS && !enterMXS)) return; if (enterMXS) PE[cpu].switchToMXS = 1; else PE[cpu].switchToMIPSY = 1; return;#else CPUWarning("Trying to switch between mipsy and MXS, " "but this simos was built without MXS\n");#endif}#ifdef MIPSY_MXS/* * DoUncachedRead - perform an uncached/bdoor read for MXS. */int DoUncachedRead(struct s_cpu_state *st, uint vAddr, uint pAddr, int size, void *data){ RefSize refsize; switch (size) { case 1: refsize = BYTE_SZ; break; case 2: refsize = HALF_SZ; break; case 4: refsize = WORD_SZ; break; case 8: refsize = DOUBLE_SZ; break; default: ASSERT(0); } return MipsyReadMem(vAddr, data, refsize, NO_FLAVOR);}/* * DoUncachedWrite - perform an uncached/bdoor write for MXS */int DoUncachedWrite(struct s_cpu_state *st, uint vAddr, uint pAddr, int size, int accel, void *data){ RefSize refsize; switch (size) { case 1: refsize = BYTE_SZ; break; case 2: refsize = HALF_SZ; break; case 4: refsize = WORD_SZ; break; case 8: refsize = DOUBLE_SZ; break; default: ASSERT(0); } return MipsyWriteMem(vAddr, data, refsize, NO_FLAVOR);}/* * GetLastException - Return the exception number of the last * execption RECORDed by the RECORD_EXCEPTION macro. */intGetLastException(struct s_cpu_state *st){ CPUState *P = (CPUState *) (st->mipsyPtr); return P->lastException;}voidRecordMxsMemsysStall(struct s_cpu_state *st, SimTime stallTime){ CPUState *P = (CPUState *) (st->mipsyPtr); int cpuNum = P->myNum; STATS_INC(cpuNum, stallTime, stallTime);}static void SwitchSimulators(int cpuNum,EventCallbackHdr *hdr, void *arg){ int i; SimTime interval; ASSERT( cpuNum == 0 ); if (PE[0].inMXS) { for (i = 0; i < TOTAL_CPUS; i++) { MXSSwitch(i,FALSE); /* WARNING - need switch simulators annotation */ } interval = mipsyRunInterval; } else { for (i = 0; i < TOTAL_CPUS; i++) { MXSSwitch(i,TRUE); /* WARNING - need switch simulators annotation */ } interval = mxsRunInterval; } EventDoCallback(cpuNum, SwitchSimulators, &switchSimHdr, 0, interval);}#endif /* MIPSY_MXS */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -