📄 simos_interface.c
字号:
/* * Copyright (C) 1996-1998 by the Board of Trustees * of Leland Stanford Junior University. * * This file is part of the SimOS distribution. * See LICENSE file for terms of the license. * *//***************************************************************** * simos_interface.c * * This is the interface from simos into the detailed cpu simulator. * Simos puts all of the state into a structure that can be directly * loaded into the cpus data structures. When this level of simulation * has completed, the new state will be restored and control will be * passed back to simos. Mipsy will run until it has executed the * number of instructions passed to MipsyEnter() or until MipsyExit() * is invoked. * * $Author: bosch $ * $Date: 1998/02/10 00:30:58 $ *****************************************************************/#include <stdio.h>#include <bstring.h>#include <string.h>#include <sys/types.h>#include <unistd.h>#include <sys/types.h>#include <sys/prctl.h>#include <sys/time.h>#include <limits.h>#include <sys/mman.h>#include "simtypes.h"#include "simutil.h"#include "simmisc.h"#include "firewall.h"#include "simmagic.h"#include "cpu_interface.h"#include "gdb_interface.h"#include "simstats.h"#include "embra.h"#include "driver.h"#include "cp0.h"#include "cache.h"#include "clock.h"#include "qc.h"#include "mem_control.h"#include "main_run.h"#include "stats.h"#include "debug.h"#include "directory.h"#include "translator.h"#include "registry.h"#include "embra_interface.h"#include "hw_events.h"#include "tc.h"#include "params.h"#include "embra.h"#include "../../memsystems/memsys.h"/* Local Functions */static void Embra_FaultInject(int cpuNum, faultTypeEnum faultType);static void DeadCpuCycleInc(int cpuNum, EventCallbackHdr *E, void* arg);static void EmbraRemapInit(void);int Embra_ResetCPU(int cpuNum);int EmbraCurrentCpuNum(void);VA EmbraCurrentPC(int cpuNum);extern CPUState *SBase;extern SimTime embraLastCount[SIM_MAXCPUS];void EmbraTclInit(Tcl_Interp *interp){ ParamRegister("PARAM(CPU.Embra.MPinUP)", (char *)&embra.MPinUP, PARAM_BOOLEAN); ParamRegister("PARAM(CPU.EmbraPage.UseETLB)", (char *)&embra.useETLB, PARAM_BOOLEAN); ParamRegister("PARAM(CPU.EmbraCache.UseVQC)", (char *)&embra.useVQC, PARAM_BOOLEAN); ParamRegister("PARAM(CPU.Embra.DisableStat)", (char *)&embra.stats, PARAM_BOOLEAN); ParamRegister("PARAM(CPU.Embra.InlineQC)", (char *) &embra.inlineQC, PARAM_BOOLEAN); ParamRegister("PARAM(CPU.Embra.TimeQuantum)", (char *)&embra.timeQuantum, PARAM_INT); ParamRegister("PARAM(CPU.Embra.PeriodAnnInterval)", (char *)&embra.periodicAnnInterval, PARAM_INT); ParamRegister("PARAM(CPU.Embra.StatInterval)", (char *)&embra.statInterval, PARAM_INT); ParamRegister("PARAM(CPU.Embra.MiscCheckInterval)", (char *)&embra.miscCheckInterval, PARAM_INT); ParamRegister("PARAM(CPU.Embra.SeparateMMUs)", (char *)&embra.separateMMUs,PARAM_BOOLEAN);}/***************************************************************** * EmbraEnter * * This is the main interface into setting up Embra to run. It * should be called from simos to set up registers, tlb, cache, * memory, etc. The second parameter is the number of instructions * to simulate. *****************************************************************/voidEmbraEnter(int swtch){ int i; EMP = SBase; /* If we are uniprocessor, don't do MPinUP */ if (TOTAL_CPUS == 1) { embra.MPinUP = 0; embra.sequential = 1; embra.parallel = 0; } else if (embra.MPinUP) { embra.sequential = 1; embra.parallel = 0; } else { ASSERT(0); embra.sequential = 0; embra.parallel = 1; } embra.emode = sim_misc.myCPUType; ASSERT( embra.emode ==EMBRA_PAGE || embra.emode==EMBRA_CACHE); if (embra.emode==EMBRA_CACHE) { if (SCACHE_ASSOC!=1) { CPUError("EMBRA_CACHE requires a direct-mapped cache. set PARAM(CACHE.2Level.L2Assoc) 1 \n"); } }#ifdef EMBRA_USE_QC64 embra.inlineQC = FALSE; /* Doesn't work with 64bit mode */#endif /* Load these on each entry */ EmbraCPUVectorInit(); EmbraDebugInit(); /* enable reinstating callbacks */ InstallTimers(); /* tell simmagic to start timers */ InstallPoller(); /* add poll callback to eventqueue */ EmbraRemapInit(); /* initialize remap array */ simosCPUType = embra.emode; Embra_Init(0, swtch); Clear_Translation_State( TCFLUSH_ALL); if (!swtch) { /* this is not a switch from another simulator */ for (i=0;i<TOTAL_CPUS;i++) { curEmp = &EMP[i]; embraLastCount[i] = 0ll; AnnExec(AnnFind("simos", "enter")); } } /* if switching from MIPSY, check for not_booted/faulted cpus */ if (swtch) { for (i = 0; i < TOTAL_CPUS; i++) { if (SBase[i].cpuStatus == cpu_not_booted) { Embra_ResetCPU(i); } } } EmbraTimeDiff(); HWEventsLateInit(); Embra_Run(0, 1); /* Will we return from here? */ ASSERT(0); }/***************************************************************** * EmbraExit * *****************************************************************/voidEmbraExit(CPUType new_cpu){ extern struct timeval run_start; /* driver.c */ extern struct timeval run_end; /* driver.c */ if (new_cpu != NO_CPU) { CPUWarning("Exit embra into %s\n", simName[new_cpu]); } sim_misc.enterThisCPU = new_cpu; if (embra.sequential) { int cpu; int annType = EmbraAnnType(); EmbraClosePeriodicCallbacks(); /* * XXX this is key. If we have a post-pc annotation, * XXX we better advance the pc. */ if (annType==ANNFM_PC_TYPE) { CPUWarning("Embra: switching on PC annotation. Advancing PC \n"); EMP[CPUVec.CurrentCpuNum()].PC += INST_SIZE; } /* Switching in delay slot doesn't work. */ ASSERT ((new_cpu == NO_CPU) || !IN_BD(EMP[CPUVec.CurrentCpuNum()].PC)); /* * sync the clocks or mipsy will get confused. */ EmbraFixCycleCounts(); EventProcess(-1,EMP[0].cycleCount); } else { ASSERT (0); } Em_Tlb_Clear(0); AnnExec(AnnFind("simos","periodic")); if ((new_cpu == NO_CPU) || (new_cpu == BASE)) { AnnExec(AnnFind("simos", "exit")); } Print_Recent_Stats(0); gettimeofday( &run_end ); CPUPrint("EmbraRunTime %u sec for %10lld cycles\n", run_end.tv_sec - run_start.tv_sec , (uint64)EmbraCpuCycleCount(0)); SimulatorSwitch(embra.emode, new_cpu);}/***************************************************************** * This is called from simhd DMA engine *****************************************************************/voidEmbraDMAInval(int machine, PA* k0list){ int cpu; SIM_DEBUG(('d', "DMA Clear ")); while( *k0list ) { switch( embra.emode ) { case EMBRA_CACHE: { /* Invalidate caches */ PA pa; for( pa = K0_TO_PHYS(*k0list); pa < K0_TO_PHYS(*k0list) + DEFAULT_PAGESZ; pa += SCACHE_LINE_SIZE ) { if( embra.sequential ) { /* Invalidate from everybodies cache */ unsigned dir_entry; if (NUM_CPUS(machine)>1) { dir_entry = directory[machine][ADDR2SLINE(pa)]; } else { dir_entry = 1<<FIRST_CPU(machine); } Cache_Clobber( machine, TOTAL_CPUS, pa, dir_entry, MEM_D_EXCLUSIVE ); } else { Dir_Entry new_dir_entry = Directory_Lock(CURR_CPU, pa, 0/*VA*/, MEM_D_EXCLUSIVE); /* Invalidate from everybodies cache */ Cache_Clobber( machine, TOTAL_CPUS, pa, (~((Dir_Entry)0)) >> (32 - TOTAL_CPUS), MEM_D_EXCLUSIVE ); Directory_Free(CURR_CPU, pa, new_dir_entry); } } /* Note that this is being called via the backdoor, so on the */ /* stack is mem_translate. Since that routine returns via */ /* ReenterTC..., it is acceptable to call icache_co... without */ /* checkint the return code and doing a ReenterTC... */ for (cpu = 0; cpu < TOTAL_CPUS; cpu++) EmbraTCCoherenceCheck(cpu, 0,(PA)*k0list, (PA)*k0list+DEFAULT_PAGESZ); k0list++; break; } case EMBRA_PAGE: SIM_DEBUG(('d', "0x%08x ", *k0list)); /* Note that this is being called via the backdoor, so on the */ /* stack is mem_translate. Since that routine returns via */ /* ReenterTC..., it is acceptable to call icache_co... without */ /* checkint the return code and doing a ReenterTC... */ /*xxx This MUST be called in embra page mode to invalidate any * stale translations which might still linger in the TC (the real * Icache will also be flushed). *xxx Also note that ALL CPU caches must be invalidated! */ for (cpu = 0; cpu < TOTAL_CPUS; cpu++) EmbraTCCoherenceCheck(cpu, 0,(PA)*k0list, (PA)*k0list+DEFAULT_PAGESZ); k0list++;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -