⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 main_run.c

📁 一个用在mips体系结构中的操作系统
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * 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.  * *//***************************************************************************      File:           main_run.c** This code is called once to generate the main simulator loop and* assorted other routines. It is a semi-platform-independent rewrite* of the old MIPS main_run.s. Of course, we could also just make a* platform-independent MIPS assembler, or write it in some intermediate* representation.** I have also added in the callout code. It is easier to generate* everything in one place. Also we avoid name-space pollution with* the register variables a0, a1, etc..** In this implementation, assembly routines have become C routines which* generate the desired code at translator init time.*** To-do: there are a lot of repulsive mips-isms in this code, most*	 notably that unfortunate t9 convention. These need to be*	 eliminated and hidden in the vcode interface. Register*	 allocation needs to be re-thought. RA needs to be re-thought.*	 much to be done to make this truly portable. However, for now*	 we at least have a possibility of generating code for other*	 architectures.** $author$* $date$***************************************************************************/#include "c_port.h"#include "mips_arch.h"		/* MIPS architecture specification */#include "embra.h"#include "callout.h"		/* useful macros for common code sequences */#include "main_run.h"#include "mem_control.h"#include "cp0.h"#include "debug.h"#include "tc.h"#include "translator.h"#include "driver.h"#include "qc.h"#include "vcode.h"		/* vcode types aXSnd macros */v_code *Main_Run_Buf;		/* Pointer to space for our generated   *				 * code. Allocated in tc.c		*/int	Main_Run_Buf_Size;	/* Size of code buffer *//* Guard against calls to uninitialized functions */static void bad(void){  CPUError("Embra: Call to uninitialized dynamic routine\n");  ASSERT(0);}vfptr 	EnterTC=(vfptr) bad,		/* Pointers to generated routines */	EnterTC_CX=(vfptr) bad,	IncCCasm=(vfptr) bad,	GeneralEmEventPollasm= (vfptr) bad,	EmEventPoll=(vfptr)bad,	UPperiodic_callout=(vfptr)bad,	Embra_CX=(vfptr)bad,	Embra_CX_nochain=(vfptr)bad,	continue_run_without_chaining=(vfptr)bad,	continue_run=(vfptr)bad,	SpillFP=(vfptr)bad,	RestoreFP=(vfptr)bad,	callout=(vfptr)bad;/* Memory reference wrappers */mr_ptr mem_ref_wrapper=(mr_ptr)bad;mar_ptr	phys_mem_ref_wrapper=(mar_ptr)bad,	pa_mem_ref_wrapper=(mar_ptr)bad;mar_ptr QC64HashFunc=(mar_ptr)bad,    Em_dynPQCdsh=(mar_ptr)bad,    Em_dynPQCdex=(mar_ptr)bad,    Em_HackedIPageMMUQC=(mar_ptr)bad;/* simple static symbol table to preserve my sanity */typedef struct main_run_sym {  char *name;  void *addr;} main_run_sym;main_run_sym main_run_syms[] = {	"Bad", (void *) &bad, 	"EnterTC", (void *) &EnterTC,	"EnterTC_CX",(void *) &EnterTC_CX,	"IncCCasm",(void *) &IncCCasm,	"GeneralEmEventPollasm",(void *) &GeneralEmEventPollasm,	"EmEventPoll",(void *) &EmEventPoll,	"UPperiodic_callout",(void *) &UPperiodic_callout,	"Embra_CX",(void *) &Embra_CX,	"Embra_CX_nochain",(void *) &Embra_CX_nochain,	"continue_run_without_chaining",	(void *) &continue_run_without_chaining,	"continue_run",(void *) &continue_run,	"SpillFP",(void *) &SpillFP,	"RestoreFP",(void *) &RestoreFP,	"callout",(void *) &callout,	"mem_ref_wrapper",(void *) &mem_ref_wrapper,	"phys_mem_ref_wrapper",(void *) &phys_mem_ref_wrapper,	"pa_mem_ref_wrapper",(void *) &pa_mem_ref_wrapper,	"QC64HashFunc",(void *) &QC64HashFunc,	"Em_dynPQCdsh",(void *) &Em_dynPQCdsh,	"Em_dynPQCdex",(void *) &Em_dynPQCdex,	"Em_HackedIPageMMUQC",(void *) &Em_HackedIPageMMUQC};extern v_reg_t VREGS[];		/* Allocated registers from translator.c */extern v_reg_t FVREGS[];static v_reg_t zero, sp, ra, a0, a1, a2, a3, s2,					/* registers we use */  t0, t1, t2, t3, t4, t7, t8, t9,  v0,v1,  vss_base,			/* = curEmp = EMP[curcpu] */  clock_reg,			/* clock */  dhit_reg,			/* cache registers */  ihit_reg,  qc_reg,			/* registers for memory addr quick check */  mmumask_reg,  mmu_reg,  sim_t1, sim_t2, sim_t4,  branchreg,    pc_reg;			/* simulated PC *//* Interfaces to several routines we call or call out to * This should be cleaned up */extern void VC_Allocate_Regs(void);	/* Allocate registers in VREGS[] */extern void IncCC(int cpuNum, int inc); /* Increment cycle count...					 Hmm.... parameters??? */extern void GeneralEmEventPoll(int cpuNum);extern void NonReturningProcReturned(void);extern EmbraState* CEmEventPoll(void);extern int callout_interval;extern MA Em_QC64Reload(VA vAddr, int flags );  TCA ChainBasicBlock( TCA jump_addr, VA new_pc);static v_label_t spill_fp_label;	/* labels can't be automatic! ??? ;-( *//* InterfaceInitRegs(): initialize register variables, which * we will use in all of our vcode calls  *//* XXX This register thing needs to be looked at. We need to * boil things down to the smallest possible set of registers. * Moreover, we need to get rid of MIPS-isms (e.g. t9, calling * conventions, etc.) or hide them within the vcode implementation * wherever possible. */void InterfaceInitRegs(void){  VC_Allocate_Regs();  zero		= VREGS[0]; /* bad */  sp		= VREGS[REG_SP];  ra		= VREGS[REG_RA];  a0		= VREGS[REG_A0];  a1		= VREGS[REG_A1];  a2		= VREGS[REG_A2];  a3		= VREGS[REG_A3];  s2		= VREGS[REG_S2];  t0		= VREGS[REG_T0];  t1		= VREGS[REG_T1];  t2		= VREGS[REG_T2];  t3		= VREGS[REG_T3];  /*  t4		= VREGS[REG_T4];  *** not used (yet?) ***/  /* t7		= VREGS[REG_T7];	*** not used (yet?) ***/  t8		= VREGS[REG_T8];  t9		= VREGS[REG_T9];  v0		= VREGS[REG_V0];  v1		= VREGS[REG_V1];  vss_base	= VREGS[VSS_BASE];  clock_reg	= VREGS[CLOCK_REG];  dhit_reg	= VREGS[DHIT_REG];  ihit_reg	= VREGS[IHIT_REG];  qc_reg	= VREGS[QC_REG];  mmumask_reg	= VREGS[MMUMASK_REG];  mmu_reg	= VREGS[MMU_REG];  sim_t1	= VREGS[SIM_T1];  sim_t2	= VREGS[SIM_T2];  sim_t4	= VREGS[SIM_T4];  branchreg	= VREGS[BRANCHREG];  pc_reg	= VREGS[PC_REG];}/* VLOAD_COMMON_VARS(): load common registers, in this case * registers which are used for memory quick check */void VLOAD_COMMON_VARS(void){  v_ldui(qc_reg, vss_base, CACHE_AX_OFF);  v_ldui(mmumask_reg, vss_base, SSREG2_OFF);  v_ldui(mmu_reg, vss_base, MMU_OFF);}/* EnterTC: we load registers used by Embra, and jump to the * main run loop (without chaining, because we are entering from * C code rather than translated code) */vfptr GenEnterTC(char *buf, int size, int *used){  v_reg_type arg[1]; /* one argument */  v_lambda("EnterTC", "%u", arg, V_LEAF, (v_code *) buf, size);  /* leave some stack space - 256 bytes for now XXX -BL */  v_addii(sp, sp, -512);    v_movu(vss_base, arg[0]); /* initialize vss_base with curEmp */  VLOAD_COMMON_VARS();  v_ldui(clock_reg, vss_base, CCD_OFF);  v_ldui(dhit_reg, vss_base, SDHIT_OFF);  v_ldui(ihit_reg, vss_base, SIHIT_OFF);  REG_LD_OP(pc_reg, vss_base, PC_OFF);  ASSERT(continue_run_without_chaining != 0);  v_jpi(continue_run_without_chaining);  v_nop();  return v_end(used).v;}/* EnterTC_CX: similar to EnterTC, but do a context switch * at the end (for MPinUP) */   vfptr GenEnterTC_CX(char *buf, int size, int *used){  v_reg_type arg[1]; /* one argument */  v_lambda("EnterTC_CX", "%u", arg, V_LEAF, (v_code *) buf, size);  /* leave some stack space - 256 bytes for now XXX -BL */  v_addii(sp, sp, -512);  /* Original comments follow: */    /* XXX - This is just here to support the boot */    /* Now it actually supports the memory system also */    /* void ReenterTC_CX( EmbraState* ) */    /* The jumpPC better be a C function or a standard TC entry point. */	/* For it to be a (more) arbitrary entry point, we need the scheme*/    /* discussed in phys_mem_ref_wrapper in qc.c */  /* XXX This thing may have to be changed!! */  v_movu(	vss_base, arg[0]); /* initialize vss_base with curEmp */  /* Load current countdown b/c it was adjusted */  v_ldui(	clock_reg, vss_base, CCD_OFF);  v_ldui(	s2, vss_base, SSREG2_OFF);  REG_LD_OP(	pc_reg, vss_base, PC_OFF);  v_ldui(	dhit_reg, vss_base, SDHIT_OFF);  v_ldui(	ihit_reg, vss_base, SIHIT_OFF);  /* This is really only necessary for debugging */  /* it also probably hoses us somehow!! */  v_stui(	ra, sp, STOFF_RA);  /* This gets stored as the jumpPC for this CPU */  v_ldui(	ra, vss_base, JUMPPC_OFF);  ASSERT(Embra_CX != 0);  v_jpi(	Embra_CX);      v_nop();  return v_end(used).v;}vfptr GenIncCCasm(char *buf, int size, int *used){  /* ack! we wanted to save our calling conventions,   * but I think that might have been hosing us because   * the original code stores ra in STOFF_RA   */    v_lambda("GeneralEmEventPollasm", "", NULL, V_LEAF, (v_code *) buf,	   size);  v_stui(ra, sp, STOFF_RA);  /* call C routine to increment (long) cycle count */  v_ldui(a0, vss_base, MYNUM_OFF);  v_seti(t9, (unsigned) IncCC);  v_jalp(ra, t9);  /* was: v_scallv(IncCC, "%u", a0); */  /* get low word of cycle count */  v_ldui(v0, vss_base, LOCC_OFF);  v_ldui(ra, sp, STOFF_RA);    /* jr ra */  return v_end(used).v;}vfptr GenGeneralEmEventPollasm(char *buf, int size, int *used){  v_lambda("GeneralEmEventPollasm", "", NULL, V_NLEAF, (v_code *) buf, size);    /* This procedure DOES NOT return */  v_ldui(a0, vss_base, MYNUM_OFF);  v_scallv(GeneralEmEventPoll, "%u", a0);  /* This procedure raises an assert of the above procedure returns */  v_scallv(NonReturningProcReturned, "");  return v_end(used).v;}/* EmEventPoll: Check for pending events and service if necessary. */vfptr GenEmEventPoll(char *buf, int size, int *used){  static v_label_t GeneralEmEventPollasm_label; /* has to be static? */  static v_label_t restore_proc_label;  GeneralEmEventPollasm_label = v_genlabel();  restore_proc_label = v_genlabel();    /* I didn't think up this name */    v_lambda("EmEventPoll", "", NULL, V_LEAF, (v_code *) buf, size);    /* Load callback time ptr */  v_ldui(t0, vss_base, CALL_OFF);  /* VSS_BASE = EMP[numCPUs].next -- Don't need old VSS_BASE anymore */  v_ldui(vss_base, vss_base, NEXT_OFF);  /* Old 3 instruction sequence to keep track of current cpu...     la      t1,                   curr_cpu     lw              t2,           MYNUM_OFF(VSS_BASE)                     sw      t2,  0(t1)               */  /* New 2 insn sequence */  {      v_seti(t1, ((unsigned)&curEmp) & 0xffff0000); /* XXX this is dumb - fix?? */  }  v_orui(t1, t1, ((unsigned)&curEmp) & 0x0000ffff);  v_stui(vss_base, t1, 0);  /* Load hi end of callback time */  v_ldui(t1, t0, 0);  /* Load hi end of cycle count */  v_ldui(t2, vss_base, HICC_OFF);  /* If the most signifigant word of the two do not agree, bail */  /* GeneralEvEventPollasm does not return */  v_bnei(t1, t2, GeneralEmEventPollasm_label);  /* Load lo end of callback time */  v_ldui(t1, t0, 4);  /* Load lo end of cycle count */  v_ldui(t2, vss_base, LOCC_OFF);  /* t3 = cyclecount - callbacktime */  v_subu(t3, t2, t1);  /* Event is probably pending -- service it  */  /* if (t3 >=0) jp GeneralEventPollasm (does not return) */  v_bltii(t3, 0, restore_proc_label);      /* GeneralEmEventPollasm_label:    */  v_label(GeneralEmEventPollasm_label);  ASSERT(GeneralEmEventPollasm != 0);  v_jpi(GeneralEmEventPollasm);  v_label(restore_proc_label);  /* Load S registers */  LOAD_COMMON_VARS  v_ldui(clock_reg, vss_base, CCD_OFF);  v_ldui(dhit_reg, vss_base, SDHIT_OFF);  v_ldui(ihit_reg, vss_base, SIHIT_OFF);  REG_LD_OP(pc_reg, vss_base, PC_OFF);  v_ldui(t9, vss_base, JUMPPC_OFF);  ASSERT(Embra_CX_nochain != 0);  v_jpi(Embra_CX_nochain);  v_nop();  return v_end(used).v;} /* GenEmEventPoll */    vfptr GenUPperiodic_callout(char *buf, int size, int *used){  static v_label_t up_event;    v_lambda("UPperiodic)callout", "", NULL, V_LEAF, (v_code *) buf, size);  up_event = v_genlabel();    /* original comments follow: */  /* XXX - This is the WRONG solution.  The right way of doing things */  /* is to figure out why the number of interrupts with and without */  /* polling is different.  Because we check for interrupts when we */  /* deliver them and when the SR is changed, we shouldn't need to poll */  /* Someone needs to route around in clock.c */  /* This is a fast way of checking to see if any callbacks are pending.*/  /* The C routine is high on the profile */  REG_ST_OP(pc_reg, vss_base, PC_OFF);  v_stui(ra, vss_base, JUMPPC_OFF);  /* Increment cycle count (int64) */  v_seti(a0, ((unsigned)&callout_interval)); /* get callout interval */  v_ldui(a0, a0, 0);  v_ldui(sim_t1, vss_base, LOCC_OFF);  v_ldui(sim_t2, vss_base, HICC_OFF);  v_addu(sim_t4, sim_t1, a0);  v_ltu(sim_t1, sim_t4, sim_t1);  v_addu(sim_t2, sim_t2, sim_t1);  v_stui(sim_t4, vss_base, LOCC_OFF);  v_stui(sim_t2, vss_base, HICC_OFF);  /* increment CLOCK register */  v_addu(clock_reg, clock_reg, a0);  v_stui(clock_reg, vss_base, CCD_OFF);  /* load callback time ptr */  v_ldui(a0, vss_base, CALL_OFF);  /* compare hi */  v_ldui(a1, a0, 0);  v_bneu(a1, sim_t2, up_event);  v_ldui(a1, a0, 4);  v_bltu(a1, sim_t4, up_event);  /* return */  v_jp(ra);  v_label(up_event);  SPILL_FP_IF_ENABLED  CORRECT_OUTGOING_CC(zero);  v_setl(t9, ((unsigned) CEmEventPoll));  v_jalp(ra,t9);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -