📄 cpu.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. * *//**************************************************************** * cpu.c * * Main fetch/decode/execute loop and supporting routines. * * $Author: bosch $ * $Date: 1998/02/10 00:31:26 $ *****************************************************************/#include <stdio.h>#include <limits.h>#include <string.h>#include <sys/types.h>#include <unistd.h>#include <setjmp.h>#include "mipsy_simos.h"#include "addr_layout.h"#include "simtypes.h"#include "cpu.h"#include "cpu_state.h"#include "sim_error.h"#include "cp0.h"#include "fpu.h"#include "eventcallback.h"#include "cpu_stats.h"#include "cpu_interface.h"#include "hw_events.h"#include "tcl_init.h"#include "params.h"#include "simutil.h"#include "registry.h"#include "print_insts.h"#include "trace.h"#include "memref.h"#include "machine_params.h"#include "opcodes.h"#ifdef USE_FLASHLITE#include "flash_interface.h"#endif#ifdef MIPSY_MXS# include <errno.h># include <stdlib.h># include "ms.h"# define IN_MXS(_P) ((_P)->inMXS)#else # define IN_MXS(_P) (0)#endif#ifdef SOLO# include "solo.h"extern int sys_place_range_StallCPUS;static int isSolo = 1;# ifdef FLASHPOINT# include "solo_page.h"# define BIG_ENDIAN 1# include "machine.h"# include "memspy_simulator.h"# include "mipsy_interface.h"# endif#elsevoid SoloTclInit(Tcl_Interp *interp) {}static int isSolo = 0;#endif#ifdef SOLO#define HOST_DATA_ADDR(vAddr, paddr, cpu) (char *)(vAddr)#else#define HOST_DATA_ADDR(vAddr, paddr, cpu) \ (PHYS_TO_MEMADDR(M_FROM_CPU(cpu),paddr)+(IS_REMAPPED_PADDR(paddr,cpu) ? remapVec->NodeAddr[cpu] : 0))#endif/***************************************************************** * Global CPU Variables *****************************************************************/CPUState *PE; /* The big daddy of them all */CPUState *pePtr[MIPSY_MAX_CPUS];jmp_buf jmpEnv; /* Used to exit the main loop */PA LLAddrs[MIPSY_MAX_CPUS]; /* LL/SC sans caches */int numLLactive = 0; /* LL/SC sans caches */bool mipsySyncWhenDone = FALSE;bool mipsySkipCaches = FALSE;bool exitMipsy = FALSE; /* Set this flag in the debugger to leave mipsy */static CPUState *P; /* P is always set to current cpu */SimTime mipsyCurrentTime = 0;extern int InterpretVerboseDebug(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[]);extern void MipsyInitStats(void);#ifdef DEBUG_DATA_VERBOSEunsigned long verboseDebugEnabled = 0;#endif/* Local CPU Functions */static Result ReadInstruction(VA, Inst *);static Result UncachedWrite(VA, PA, void *, RefSize, bool accelerated);static Result UncachedRead(VA, PA, void *, RefSize);static void CPURun(void *);static void DoneRunning(void);#ifdef USE_FLASHLITE# ifndef FLASHPOINTtypedef uint64 LL;# endifextern LL FlashAdvanceTime(LL newInstTime);/* Advance flashlite notion of time. */#endif#ifdef T5_MODELint enableVerilogNode;/* This may allow me to enable the verilog node after mipsy initializes itself */int T5NodeNum;/* Which node is the T5 acting like? */#endif#ifdef MIPSY_MXSstatic void SwitchSimulators(int cpuNum,EventCallbackHdr *hdr, void *arg);static EventCallbackHdr switchSimHdr;int mxs_annotation = 0;#endifstatic uint mxsRunInterval, mipsyRunInterval;/***************************************************************** * EVENT Support *****************************************************************/#define INSTRUCTION_DONE_EVENT() \ TraceInstruction(P, instr); \ PRINT_INSTRUCTION(instr); \ STATS_INC(cpuNum, numInstructions, 1); \ if (STATS_VALUE(cpuNum, numInstructions) > STATS_VALUE(cpuNum, nextInstrSample)) { \ INST_SAMPLE_EVENT(MipsyReadTime(cpuNum), cpuNum, P->PC); \ STATS_INC(cpuNum, nextInstrSample, MS_SAMPLE_INSTR_INTERVAL); \ }/***************************************************************** * MEMORY ANNOTATION SUPPORT! *****************************************************************/#define CHECK_LD_ANN(_vAddr, _pAddr) \{ if (annLoads) { \ AnnPtr ptr = AnnFMLookup(_vAddr, ANNFM_LD_TYPE);\ if (ptr) \ AnnExec(ptr); \ ptr = AnnFMLookup(_pAddr, ANNFM_LD_TYPE);\ if (ptr) \ AnnExec(ptr); \ } \}#define CHECK_ST_ANN(_vAddr,_pAddr) \{ if (annStores) { \ AnnPtr ptr = AnnFMLookup(_vAddr, ANNFM_ST_TYPE);\ if (ptr) \ AnnExec(ptr); \ ptr = AnnFMLookup(_pAddr, ANNFM_ST_TYPE);\ if (ptr) \ AnnExec(ptr); \ } \}/***************************************************************** * MipsyInit * *****************************************************************/voidMipsyInit(void) { int i; if (!strcmp(CACHE_MODEL, "None")) { MipsyTurnOffCaches(); } MipsyInitStats(); MipsyInitFPU(); PrintInstsInit(); for (i = 0; i < TOTAL_CPUS; i++) {#ifndef SOLO EnableInterruptCheck(&PE[i], CHECK_FOR_INTERRUPTS_INTERVAL);#endif LLAddrs[i] = (PA) -1; PE[i].timerCycleCount = 0; PE[i].inMXS = 0; }#ifdef MIPSY_MXS { int i; for (i=0; i < TOTAL_CPUS; i++) { PE[i].st = (struct s_cpu_state *) ZMALLOC(sizeof (struct s_cpu_state),"s_cpu_state"); if (PE[i].st == NULL) { perror ("Mipsy - malloc failed"); ASSERT (0); } ms_st_init (PE[i].st); PE[i].st->mipsyPtr = (void *) (PE + i); PE[i].switchToMXS = PE[i].switchToMIPSY = 0; } }#endif}/***************************************************************** * MipsyCycleCount * This is entered into the backdoor vector and is used by memstat * to get the time at each entry into the log. *****************************************************************/SimTimeMipsyCycleCount(int cpuNum) { return MipsyReadTime(cpuNum);}/***************************************************************** * MipsyCurrentCpuCycleCount * * This is entered into the detail vector and is used by the OS * as the on-chip cycle counter of the T5 COP0. * *****************************************************************/SimTimeMipsyCurrentCpuCycleCount(void){ return MipsyReadTime(P->myNum);}/***************************************************************** * MipsyInstructionCount * *****************************************************************/SimTimeMipsyInstructionCount(int cpuNum){ return STATS_VALUE(cpuNum, numInstructions);}/***************************************************************** * MipsyCurrentCpuNum * * Anyone can call this from the cpu vector to determine the current * cpu. *****************************************************************/intMipsyCurrentCpuNum(void){ return P->myNum;}/***************************************************************** * *****************************************************************/voidMipsyStall(int cpuNum){ PE[cpuNum].cpuStatus = cpu_stalled; STATS_SET(cpuNum, stallStart, MipsyReadTime(cpuNum));}/***************************************************************** * MipsyUnstall * * Call this from any memory simulators when a processor is no * longer stalled. * The initial if test ensures that the CPU can transition to the halted * state at any time without having to ensure that no memory * request is outstanding. *****************************************************************/voidMipsyUnstall(int cpuNum){ if (PE[cpuNum].cpuStatus == cpu_halted) { return; } if (PE[cpuNum].cpuStatus == cpu_stalled) { PE[cpuNum].cpuStatus = cpu_running; STATS_ADD_INTERVAL(cpuNum, stallTime, stallStart); } else if (PE[cpuNum].cpuStatus == cpu_libc_blocked) { return; } else if (PE[cpuNum].cpuStatus == cpu_bdoor_stalled) { return; } else { /* Was probably stalled on an uncached_op */ PE[cpuNum].cpuStatus = cpu_running; }}/* ***************************************************************** * Mipsy LL/SC support routines * *****************************************************************/void MipsyClearLockFlag(int cpuNum){ PE[cpuNum].LLbit = 0;}bool MipsyGetLockFlag(int cpuNum){ return PE[cpuNum].LLbit;}PA MipsyGetLockAddr(int cpuNum){ return PE[cpuNum].LLAddr;}CPUStatus MipsyCPUStatus(int cpuNum){ return PE[cpuNum].cpuStatus; }/***************************************************************** * MipsyFinishMemRequests * * Spin advancing time until all cpus are unstalled. *****************************************************************/void MipsyFinishMemRequests(void) { CPUState *lastP; CPUState *firstP; bool somebodyStalled = FALSE; int i; for (i = 0; i < TOTAL_CPUS; i++) { if (PE[i].cpuStatus != cpu_running) { somebodyStalled = TRUE; } } firstP = &PE[0]; lastP = &PE[TOTAL_CPUS-1]; P = lastP; while (somebodyStalled) { P++; if (P > lastP) { P = firstP; mipsyCurrentTime++; EventPollSingleQueue(MipsyReadTime(0)); } /* Things to do each wrap-around */ somebodyStalled = FALSE; for (i = 0; i < TOTAL_CPUS; i++) { if (PE[i].cpuStatus != cpu_running && PE[i].cpuStatus != cpu_idle && /* idle if it was taken out */ PE[i].cpuStatus != cpu_halted) { /* was halted after fault injection */ somebodyStalled = TRUE; } } }}/***************************************************************** * PrepareToSwitch * * This just checks if the current PC value has an annotation. * This is needed in the cpu switching code so that we get a chance * to advance the PC before moving to the next simulator. *****************************************************************/static voidPrepareToSwitch(void){ int cpu; for (cpu=0; cpu < TOTAL_CPUS; cpu++) { CPUState *P = &PE[cpu]; if (AnnFMLookup(P->PC, ANNFM_PC_TYPE)) { CPUWarning("MIPSY: Switching on PC annotation -> advancing PC\n"); /* advance PC only if current instruction is not a branch thats going to be taken */ if (P->branchStatus == BranchStatus_taken) { CPUWarning("CPU %d on branch 0x%x (postPC), keeping it there\n", cpu, P->PC); } else { P->PC = P->nPC; P->nPC += INST_SIZE; } } else if (AnnFMLookup(P->PC, ANNFM_PRE_PC_TYPE)) { if (P->nPC != (PE->PC + INST_SIZE)) { CPUWarning("CPU %d on delay slot 0x%x (prePC), backing up to 0x%x\n", cpu, P->PC, P->PC - INST_SIZE); P->PC -= INST_SIZE; } } }}/***************************************************************** * MipsyExit * *****************************************************************/void MipsyExit(CPUType exitTo){ PrepareToSwitch();#ifndef SOLO /* Before we exit mipsy, we need to make sure that all outstanding memory references have completed. This just advances time until all outstanding memory references are complete. This is determined to be done when all processors have moved */ MipsySetExitSimulator(exitTo); MipsyFinishMemRequests();#endif PrintRealTime("Simulation End"); /* This kicks us out of the main loop */ longjmp(jmpEnv, 1);}/***************************************************************** * ReadInstruction() *
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -