📄 simos_interface.c
字号:
break; } } SIM_DEBUG(('d', "\n"));}/***************************************************************** * remap region support * *****************************************************************/static voidEmbraRemapInit(void){ int i; if (!remapVec->NodeAddrInitialized) { for (i=0; i<TOTAL_CPUS; i++) { int m = M_FROM_CPU(i);#ifdef TORNADO remapVec->NodeAddr[i] = (i*NUM_MEMORIES(m)/NUM_CPUS(m)) * (MEM_SIZE(m) / NUM_CPUS(m)); CPUWarning("embra: nodeaddr for %d is %lx\n", i, (unsigned long)(remapVec->NodeAddr[i]));#elif defined(SIM_ORIGIN) remapVec->NodeAddr[i] = MEMADDR_TO_PHYS(m, SIM_MEM_ADDR(m) + (MCPU_FROM_CPU(i)/2) * 2 * (MEM_SIZE(m) / NUM_CPUS(m)));#else remapVec->NodeAddr[i] = MEMADDR_TO_PHYS(m, SIM_MEM_ADDR(m) + MCPU_FROM_CPU(i) * (MEM_SIZE(m) / NUM_CPUS(m)));#endif } remapVec->NodeAddrInitialized = 1; }}static voidem_setremap(int cpunum, PA mask){ unsigned int cnum = (unsigned int) cpunum; if (cnum < SIM_MAXCPUS) { remapVec->RemapMask[cnum] = mask; /* changing the mask might increase or decrease the remap zone. * The simplest way to reflect this change in the mmu is to * flush the mmu and renew it. */ qc_renew(cnum); } else { CPUWarning("cpunum out of range in em_setremap"); }}static voidem_controlremap(int cpunum, int isEnabled){ unsigned int cnum = (unsigned int) cpunum; if (cnum < SIM_MAXCPUS) { remapVec->RemapEnable[cnum] = isEnabled; /* the simplest way to update the mmu is to flush and renew it. */ qc_renew(cnum); } else { CPUWarning("cpunum out of range in em_controlremap"); }}static PAem_getnodeaddr(int cpunum){ return remapVec->NodeAddr[cpunum];}uint NearestLog2(int n){ uint pwr = 0x80000000; while( !(pwr & n) ) { pwr >>= 1; } return pwr;}/***************************************************************** * EmbraCPUVectorInit * * Assign the proper function pointers to the shared CPUVector *****************************************************************/void EmbraCPUVectorInit(void){ CPUVec.Handle_Debug_Signal = Embra_Handle_Debug_Signal; CPUVec.InstallMemAnnotation = EmbraInstallMemAnnotation; CPUVec.GetRegister = Embra_GetRegister; CPUVec.PutRegister = Embra_PutRegister; CPUVec.GetMemory = Embra_GetMemory; CPUVec.PutMemory = Embra_PutMemory; CPUVec.TranslateVirtualNoSE = Embra_TranslateVirtualNoSE; CPUVec.CycleCount = EmbraCpuCycleCount; CPUVec.InstrCount = EmbraCpuInstrCount; CPUVec.Send_Interrupt = Embra_Send_Interrupt; CPUVec.Deliver_SIPS = Embra_Deliver_SIPS; CPUVec.FaultInject = Embra_FaultInject; CPUVec.ResetCPU = Embra_ResetCPU; CPUVec.CurrentCpuNum = EmbraCurrentCpuNum; CPUVec.CurrentPC = EmbraCurrentPC; memsysVec.type = NO_MEMSYS; memsysVec.MemsysCmd = 0; memsysVec.MemsysSetRemap = em_setremap; memsysVec.MemsysGetNodeAddress = em_getnodeaddr; memsysVec.MemsysControlRemap = em_controlremap; CPUVec.DMAInval = EmbraDMAInval; if( embra.sequential ) { CPUVec.singleEventQueue = 1; } else { CPUVec.singleEventQueue = 0; } CPUVec.SelectorChange = Dump_QC_Counters; CPUVec.DoCheckpoint = EmbraCheckpoint; CPUVec.ProcMakeProcExit = EmbraMakeProcExit; CPUVec.ExitSimulator = EmbraExit; CPUVec.IntrBitsChanged = EmIntrBitsChanged; CPUVec.FirewallChange = EmFirewallChange; CPUVec.MigRepStart = MigRepStart; CPUVec.MigRepEnd = MigRepEnd; CPUVec.useMemRef = FALSE;}/***************************************************************** * Procexit Support *****************************************************************//****************************************************************** * Write a call to the system call exit on the user's stack. Then * jump to it *****************************************************************//* Macros to cons up instructions ( ConsInstruction<instruction_type>) */#define CIi(opCode, rt, rs, immed) ((int)\((opCode) << 26 | (rs) << 21 | (rt) << 16 | ((immed) & 0xffff ) ) )#define CIs(funct, rd, rs, rt) ((int)\(spec_op << 26 | (rs) << 21 | (rt) << 16 | (rd) << 11 | funct) )int EmbraMakeProcessExit(int cpuNum){ EmbraState *P = &EMP[cpuNum]; uint *pPtr; VA vSP; if (CURRENT_MODE(P) != USER_MODE ){ CPUWarning("%d %llu Tyring to make pid exit\n", cpuNum, EmbraCpuCycleCount(cpuNum)); return 0; } /* Insure that we are not writting over a page boundary by using */ /* the beginning of the page*/ vSP = FORM_ADDR( PAGE_NUMBER(P->R[REG_SP]), 0 ); pPtr = (uint*) non_excepting_tv( cpuNum, vSP ); if( !pPtr ) { CPUWarning("Failure to translate stack address in MakeProcExit\n"); return 0; } CPUWarning("PROCexit: CPU %d smashing address %#x\n", P->myNum, vSP); *pPtr++ = CIi( addiu_op, A0, G0, 0 ); /* li a0, 0 */ *pPtr++ = CIi( addiu_op, V0, G0, 1001 ); /* li v0, 1001 */ /* This trick won't work in base mode both because of this opcode */ /* because we are not flushing the data cache*/ *pPtr++ = CIs( syscall_op, 0, 0, 0); /* syscall */ P->PC = vSP; return 1;}/***************************************************************** * fault support * */static EventCallbackHdr DeadCpuCycleMaintenance[SIM_MAXCPUS];static int lowest_live_cpu = 0;static uint deadcpus = 0;#define DEADCPUCYCLEINTERVAL 10000intEmbraCurrentCpuNum(void) { int cpuNum = curEmp - &EMP[0]; ASSERT( cpuNum == curEmp->myNum); ASSERT( cpuNum >= 0 && cpuNum < TOTAL_CPUS); return cpuNum;}VAEmbraCurrentPC(int cpuNum) { return EMP[cpuNum].PC;}static voidEmbra_FaultInject(int cpuno, faultTypeEnum faultType){ switch (faultType) { case SIMFAULT_HALT: /* do something lower-level (not the right thing, eventually) */ ProcRemove( cpuno ); /* the problem with ProcRemove is that the cycle counter of * the failed cpu stops incrementing, so events driven off of * that (notably the timer interrupt) cause an infinite loop * when the time on that cpu gets sufficiently far behind the * time on the rest of the system. We need to set up a periodic * callback on some other cpu that increments the cycle count * on the failed cpu. * * We use the lowest_live_cpu to do this. If it is the lowest * live cpu itself that has failed, need to move any previous * cycle maintenance callbacks to the new lowest live cpu. */ if (cpuno == lowest_live_cpu) { int i; lowest_live_cpu = -1; for (i=0; i<TOTAL_CPUS; i++) { if (i == cpuno) continue; if (deadcpus & (1<<i)) continue; lowest_live_cpu = i; break; } ASSERT(lowest_live_cpu != -1); /* should be at least 1 live one*/ for (i=0; i<TOTAL_CPUS; i++) { if (deadcpus & (1<<i)) { SimTime delta = DeadCpuCycleMaintenance[i].when - EmbraCpuCycleCount(cpuno); EventCallbackRemove(&DeadCpuCycleMaintenance[i]); EventDoCallback(lowest_live_cpu, DeadCpuCycleInc, &DeadCpuCycleMaintenance[i], (void*) i, delta); } } } deadcpus |= (1 << cpuno); EventDoCallback(lowest_live_cpu, DeadCpuCycleInc, &DeadCpuCycleMaintenance[cpuno], (void*) cpuno, DEADCPUCYCLEINTERVAL); break; default: CPUWarning("Unknown fault (%d) ignored\n", faultType); break; }}static void DeadCpuCycleInc(int cpuNum, EventCallbackHdr *E, void* arg){ int deadcpu = (int) arg; EMP[deadcpu].cycleCount += DEADCPUCYCLEINTERVAL; EventDoCallback(lowest_live_cpu, DeadCpuCycleInc, &DeadCpuCycleMaintenance[deadcpu], (void*) deadcpu, DEADCPUCYCLEINTERVAL); }int Embra_ResetCPU(int cpuNum){ /* TBD: clear cached state about interrupts, etc */ /* by calling putregister for the pc and RA, we trigger normal side- * effect detection which prevents us from returning to bad code * in the TC */ Embra_PutRegister(cpuNum, PC_REGNUM, (uint)continue_run_without_chaining); Embra_PutRegister(cpuNum, 31, (uint)continue_run_without_chaining); EMP[cpuNum].jumpPC = (uint)continue_run_without_chaining; return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -