📄 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:31:59 $ *****************************************************************/ #include <stdio.h>#include <string.h>#include <stdlib.h>#include "mipsy.h"#include "cpu.h"#include "fpu.h"#include "machine_params.h"#include "simutil.h"#include "cpu_stats.h"#ifdef MIPSY_MXS# include "ms.h"#endif#include "cpu_state.h"#include "sim_error.h"#include "cp0.h"#include "eventcallback.h"#include "cpu_interface.h"#include "simmisc.h" #include "simmagic.h"#include "annotations.h"#include "hw_events.h"#include "registry.h"#include "memref.h"/* Global Functions */extern void HandleDebugSignal(int cpuid, int sigusr); /* Defined in debug.c */extern void CPUVectorInit(void);extern void MipsyDumpAllStats(void);extern CPUState *SBase;/* Local Functions */static void ReadConfiguration(void);static void SetupMipsy(int cpuNum);static void SendIntr(int cpunum, IEC, SimTime delay);static void IntrBitsChanged(int cpunum);static void DeliverSIPS(int r, int chan, SimTime delay);static void FaultInject(int cpuNum, faultTypeEnum);static void MakeProcExit(int cpuNum);static int MipsyResetCPU(int cpuNum);static CPUType mipsyExitTo = BASE;/***************************************************************** * MipsyEnter * * This is the main interface into setting up MIPSY 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. * If count is set to zero, MipsyRun will not be called, but the * final stats will be printed and we will return to base mode. *****************************************************************/voidMipsyEnter(int swtch){ int cpu; static int initialized = 0; PE = SBase; CPUVectorInit(); if (!initialized) { initialized = 1; MipsyInit(); HWEventsLateInit(); } ReadConfiguration(); for (cpu = 0; cpu < TOTAL_CPUS; cpu++) { SetupMipsy(cpu); ASSERT(PE[cpu].myNum == cpu); } InstallTimers(); /* tell simmagic to start timers */ InstallPoller(); /* add poll callback to eventqueue */ for (cpu = 0; cpu < TOTAL_CPUS; cpu++) { MipsyCheckForInterrupts(&PE[cpu]); } /* * Jump into Mipsy */ MipsyRun(swtch); /* Right now we dump everything when switching out of mipsy */ MipsyDumpAllStats(); CPUPrint("*************** %lld final annotations ****************\n", (uint64) MipsyReadTime(0)); AnnExec(AnnFind("simos","periodic")); if (mipsyExitTo == BASE) { AnnExec(AnnFind("simos","exit")); CPUWarning("User requested abort at cycle count %lld\n", (uint64)MipsyReadTime(0)); exit(0); }#ifdef MIPSY_MXS for (cpu = 0; cpu < TOTAL_CPUS; cpu++) { CopyFromMXS(&PE[cpu]); }#endif SimulatorSwitch(MIPSY,mipsyExitTo);}/***************************************************************** * SetupMipsy * * These are mipsy specific variables that need to be set whenever * switching to this Uber-simulator. *****************************************************************/static voidSetupMipsy(int cpuNum){ register CPUState *P = &PE[cpuNum]; MIPSY_SET_TIME(cpuNum, P->cycleCount); if (P->cpuStatus != cpu_running) { P->cpuStatus = cpu_stalled; CPUPrint("MIPSY: Processor %d is NOT RUNNING\n", P->myNum); } else { P->cpuStatus = cpu_running; CPUPrint("MIPSY: Processor %d is running\n", P->myNum); } P->myNum = cpuNum; P->takeInterrupt = FALSE; STATS_SET(cpuNum, numInstructions, 0); STATS_SET(cpuNum, nextInstrSample, MS_SAMPLE_INSTR_INTERVAL); STATS_SET(cpuNum, iReads, 0); STATS_SET(cpuNum, dReads, 0); STATS_SET(cpuNum, dWrites, 0); STATS_SET(cpuNum, stallTime, 0); /* Assuming you never enter mipsy in a delay slot */ P->nPC = P->PC + INST_SIZE; MipsyInitTLBHashTable(P); #ifdef MIPSY_MXS CopyToMXS(P);#endif}/***************************************************************** * SimosMipsySetExitSimulator * * This overrides the default exit simulator passed into * SimosCPUEnter *****************************************************************/voidMipsySetExitSimulator(CPUType newCpu){ mipsyExitTo = newCpu; simosCPUType = newCpu;}/***************************************************************** * ReadConfiguration * There are several mipsy variables set in the uid configuration * file interpreted by simos. Set these to mipsy variables. *****************************************************************/static voidReadConfiguration(void){ simosCPUType = MIPSY; CPUVec.Send_Interrupt = SendIntr; CPUVec.Deliver_SIPS = DeliverSIPS; CPUVec.IntrBitsChanged = IntrBitsChanged; /* Fault injection model. */ CPUVec.FaultInject = FaultInject; CPUVec.FirewallChange = 0; CPUVec.ResetCPU = MipsyResetCPU; CPUVec.MigRepStart = MigRepStart; CPUVec.MigRepEnd = MigRepEnd;; /* parallel event queues */ CPUVec.singleEventQueue = TRUE; CPUVec.ProcMakeProcExit = MakeProcExit; CPUVec.ExitSimulator = MipsyExit;} /***************************************************************** * CPU Fault handling *****************************************************************/static voidFaultInject(int cpuNum, faultTypeEnum faultType){ extern Result smashinst(int cpunum, VA addr, int rnd, char* errbuf); /* smashinst only here to avoid linking problems... actually called * directly from faults.c in common/tcl */ switch (faultType) { case SIMFAULT_HALT: /* We simulate a fault by halting the specified cpu */ PE[cpuNum].cpuStatus = cpu_halted; break; case SIMFAULT_DISABLECPU: ASSERT (cpuNum>=0 && cpuNum < SIM_MAXCPUS); PE[cpuNum].cpuStatus = cpu_idle; break; default: CPUWarning("Unknown fault (%d) ignored\n", faultType); smashinst(0, 0, 0, 0); break; }}/***************************************************************** * Interrupt posting code. *****************************************************************/#define MAXIBLOCKS 64static struct IntrBlock { EventCallbackHdr cbhdr; int cpunum; /* CPU to interrupt. */ IEC intrtoset;} iblocks[MAXIBLOCKS];static int irotor = 0;static voidSendIntrCallback(int cpuNum, EventCallbackHdr *E, void* arg){ struct IntrBlock *iblock = (struct IntrBlock *)arg; RaiseIBit(cpuNum, iblock->intrtoset); MipsyCheckForInterrupts(&PE[cpuNum]); return;}static voidSendIntr(int cpuNum, IEC intrtoset, SimTime delay){ int i; if (delay == 0) { RaiseIBit(cpuNum, intrtoset); MipsyCheckForInterrupts(&PE[cpuNum]); return; } i = irotor; do { if (iblocks[i].cbhdr.active == FALSE) { iblocks[i].cpunum = cpuNum; iblocks[i].intrtoset = intrtoset; EventDoCallback(cpuNum, SendIntrCallback, &iblocks[i].cbhdr, &iblocks[i], delay); if (i == MAXIBLOCKS-1) irotor = 0; else irotor = i+1; return; } if (i == MAXIBLOCKS-1) i = 0; else i += 1; } while (i != irotor); CPUError("Too many simultaneous interrupts");}static void IntrBitsChanged(int cpuNum){ MipsyCheckForInterrupts(&PE[cpuNum]);}/***************************************************************** * put a cpu back into the initial state where we watch * outOfSlaveLoop to indicate when to restart *****************************************************************/static int MipsyResetCPU(int cpuNum) /* what about flush the cache so loadimage won't lead to inconsistencies? */{ PE[cpuNum].stalledInst = FALSE; return 0; /* nothing more to do: simmisc.c:ResetCPUs changes cpuStatus to cpu_not_booted, * LaunchSlave changes it back to Running. */}/* GET THIS OUT OF HERE */#include "sips.h"/*****************************************************************//* SIPS delivery code (actually only calls back into simmagic.c). */#define MAXSBLOCKS 128static struct SIPSBlock { EventCallbackHdr cbhdr; int r; /* recipient CPU. */ int chan; /* recipient's channel. */} sblocks[MAXSBLOCKS];static int srotor = 0;static void DeliverSIPSCallback(int cpuNum, EventCallbackHdr *E, void* arg){ struct SIPSBlock *sipsBlock = (struct SIPSBlock *)arg; sim_sips_deliver(sipsBlock->r, sipsBlock->chan); MipsyCheckForInterrupts(&PE[cpuNum]); return;}static voidDeliverSIPS(int cpuNum, int chan, SimTime delay){ int i; if (delay == 0) { /* deliver NOW */ sim_sips_deliver(cpuNum, chan); MipsyCheckForInterrupts(&PE[cpuNum]); return; } i = srotor; do { if (sblocks[i].cbhdr.active == FALSE) { sblocks[i].r = cpuNum; sblocks[i].chan = chan; EventDoCallback(cpuNum, DeliverSIPSCallback, &sblocks[i].cbhdr, &sblocks[i], delay); if (i == MAXSBLOCKS-1) srotor = 0; else srotor = i+1; return; } if (i == MAXSBLOCKS-1) i = 0; else i += 1; } while (i != srotor); CPUError("Too many simultaneous SIPS");}/****************************************************************** * Write a call to the system call exit on the user's stack. Then * jump to it *****************************************************************/static void MakeProcExit(int cpuNum){ CPUState *P = &PE[cpuNum]; PA pAddr; VA vSP; uint smash[4]; /* Ensure 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); if (TranslateVirtualNoSideeffect(P, vSP, &pAddr) != SUCCESS) { CPUWarning("Can't translate address in MipsyMakeProcExit\n"); return; } CPUWarning("PROCexit: CPU %d smashing address %#x\n", P->myNum, vSP); smash[0] = CIi( addiu_op, A0, G0, 0 ); /* li a0, 0 */ smash[1] = CIi( addiu_op, V0, G0, 1001 ); /* li v0, 1001 */ smash[2] = CIs( syscall_op, 0, 0, 0); /* syscall */ MemRefDebugWriteData(cpuNum, vSP, pAddr, (char *)smash, 12); /* This trick won't work in base mode both because of this opcode */ /* because we are not flushing the data cache*/ P->nPC = vSP; P->branchTarget = vSP + INST_SIZE;} #ifdef MIPSY_MXS /* * Routines that copy state from Mipsy down to MXS, or from * MXS back up to Mipsy. * * These routines must only be called when MXS is in a * consistent state. The state of the processor is taken * from the thread that holds the status at the graduation * point. * * When initializing MXS, the graduation thread and the * thread belonging to branch node 0 start out in the * same state. */void CopyToMXS (CPUState *P) { struct s_cpu_state *st; int i; THREAD *th; st = P->st; th = &st->grad; if (P->PC+4 == P->nPC) { th->thread_st = TH_ACTIVE; th->pc = P->PC; } else { th->thread_st |= TH_BRANCH|TH_ACTIVE; th->pc = P->PC; th->branch_pc = P->nPC; }#ifdef BREAKPOINT th->debugpc = th->pc;#endif ms_iwin_init (st); for (i=0; i < NUM_GP_REGS; i++) st->regs[th->regnames[i]] = P->R[i]; for (i=0; i < NUM_FP_REGS; i++) st->regs[th->regnames[FPREG+i]] = IntReg(i^0x1); st->regs[th->regnames[HIREG]] = P->HI; st->regs[th->regnames[LOREG]] = P->LO; st->regs[th->regnames[FPCTL]] = P->FCR[0]; st->regs[th->regnames[FPCTL+1]] = P->FCR[31] & (~CONDBIT); st->regs[th->regnames[CNDREG]] = P->FCR[31] & CONDBIT; }void CopyFromMXS (CPUState *P) { struct s_cpu_state *st; int i; THREAD *th; st = P->st; th = &st->grad; if (th->thread_st & TH_BRANCH) { /* We are in delay slot */ P->PC = th->pc; P->nPC = th->branch_pc; } else { P->PC = th->pc; P->nPC = P->PC + 4; } for (i=0; i < NUM_GP_REGS; i++) P->R[i] = st->regs[th->regnames[i]]; for (i=0; i < NUM_FP_REGS; i++) IntReg(i^0x1) = st->regs[th->regnames[FPREG+i]]; P->HI = st->regs[th->regnames[HIREG]]; P->LO = st->regs[th->regnames[LOREG]]; P->FCR[0] = st->regs[th->regnames[FPCTL]]; P->FCR[31] = ((~CONDBIT) & st->regs[th->regnames[FPCTL+1]]) | (CONDBIT & st->regs[th->regnames[CNDREG]]); }#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -