📄 translator.c
字号:
int i; int alloc = 0; for(i = 0; i < NUM_ALLOCATABLE_REGS ; i++) if( src2alloc[i]->alloc_reg ) { ECi( REG_LD_OP, src2alloc[i]->alloc_reg, VSS_BASE, REG_OFFSET(src2alloc[i]->reg_num) ); alloc++; } return alloc;}static void Store( int used, int real){ /* No need to store to register 0 */ if( !real ) return; ECi( REG_ST_OP, used, VSS_BASE, REG_OFFSET(real) ); /* Only use this trick with a non-allocated register */ /* XXX- Make this trick real (i.e. use register), or possibly discard */ if( used == SIM_T2 ) { prev_store.real = real; prev_store.used = used; } else { prev_store.real = 0; prev_store.used = 0; }}/* No matter what, store to simulated registers. If this is an allocated register *//* then move value into the allocated register also */static void Store_Move( int contents, int store_or_alloc ){ if( reg2alloc[store_or_alloc].alloc_reg ) ECs(or_op_, reg2alloc[store_or_alloc].alloc_reg, G0, contents); ECi( REG_ST_OP, contents, VSS_BASE, REG_OFFSET(store_or_alloc) );}static int Set_Destination( int suggestion, int reg ){ if( !reg ) return 0; if( reg2alloc[reg].alloc_reg ) return reg2alloc[reg].alloc_reg; return suggestion;}#if defined(SIM_MIPS64)static void Load_64_Bit_Immed( int reg, Reg64 immed ){ AddLongConst(immed, memptr, reg); /* ECi(cop0_op,0,mfc_op,0); In case we forget */ /* ECi(cop0_op,0,mfc_op,0); to fill this in */ memptr++; memptr++; ASSERT(LOAD_REG_SIZE == 2);}static void FillInLongConst(void){ int i; TCA current_memptr; current_memptr = memptr; /* We use the EcX() macros so we need to * reset memptr to point at the place to * insert. Save current_memptr before hand. */ for (i = 0; i < nextLongConstIndex; i++) { Reg64 val = longConstTable[i].value; memptr = longConstTable[i].memptr; if ((int64)val == (signed int)val) { /* Is really a 32bit bit consts */ Load_32_Bit_Immed(longConstTable[i].regno, val); } else { /* Is 64bits - Allocate space for const at end of translation */ if (((int)current_memptr) & 0x7) current_memptr++; (*(Reg64 *)current_memptr) = val; ASSERT((uint)current_memptr == (Reg64)current_memptr); Load_Op_Immed(ld_op, longConstTable[i].regno, (uint)current_memptr); current_memptr += 2; } } memptr = current_memptr;}#endif/* UGH! We will have to generate this on the fly... */extern void (*Em_dynPQCdsh)(void);extern void (*Em_dynPQCdex)(void);extern void (*Em_HackedIPageMMUQC)(VA *);#ifdef RECORD_TRANSLATIONSstatic int trans;#endifint fildes;void Translator_Init(void){ int i; char* chainModeStr; static int initialized; /* I hope this is OK!! moved from below -BL */ if( initialized ) return; initialized = 1; /* Generate interface code */ GenInterfaceCode(); if( embra.MPinUP ) { dispatchChain = (void *)continue_run; dispatchNoChain = (void *)continue_run_without_chaining; periodicCallout = (void *)Embra_CX; } else { dispatchChain = (void *)continue_run; dispatchNoChain = (void *)continue_run_without_chaining; if( TOTAL_CPUS == 1 ) { periodicCallout = (void *)UPperiodic_callout; } else { periodicCallout = 0;#ifdef obsolete periodicCallout = (void *)do_periodic_callout;#endif } }#if CHECKREGS if (check_regs) fildes = open("regs",O_RDONLY);#endif for (i = 0; i < TOTAL_CPUS; i++) { /* XXXX evil! more hacks; init fpcr -BL */ EMP[i].FCR[0] = 0x900; /* for R10000???? */ EMP[i].FCR[30] = 0x900; /* eir -> same as fcr0 on r10k */ } /* XXX Hard-wire register allocation - fix this??? */ for(i = 0; i < 32; i++ ) reg2alloc[i].reg_num = i;#ifdef RECORD_TRANSLATIONS trans = open("./trans", (O_CREAT|O_RDWR|O_TRUNC), 0); if( trans == -1 ) perror("open trans");#endif /* Make this a 1 to run without ll/sc */ chainMode = BB_C; /* BB_C or NO_C */}static void set_src2alloc( void ){ int i = 0; int j; /* Don't allocate register 0, and use it as a reference */ /* Registers have to be used at least once to get on the list */ reg2alloc[0].num_src = 1; for(i = 0; i < NUM_ALLOCATABLE_REGS; i++) src2alloc[i] = ®2alloc[0]; /* Exclude 0 from the running */ for(i = 1; i < 32; i++ ) { j = NUM_ALLOCATABLE_REGS-1; if( reg2alloc[i].num_src >= src2alloc[j]->num_src ) { src2alloc[j] = ®2alloc[i]; /* Bubble entry down to index 0 */ while( j && src2alloc[j]->num_src >= src2alloc[j-1]->num_src ) { register alloc_reg_t* tmp; tmp = src2alloc[j]; src2alloc[j] = src2alloc[j-1]; src2alloc[j-1] = tmp; j--; } } } /* Remember, don't allocate register zero, we can just use it directly */ reg2alloc[0].num_src = 0;}/* Provides a 2 instruction load from a 32 bit quantity */static void Load_Op_Immed( int loadOpCode, int reg, uint addr ){ uint low; uint *temp = memptr; /* Use lui and load offset to load from a 32 bit address. We have */ /* to play games because lw sign extends its offset. If the offset */ /* has its sign bit set, we take action to correct the value. */ ASSERT (addr >= 0x10000000); ASSERT (addr < 0x80000000); ASSERT ((addr < MA_TO_UINT(SIM_MEM_ADDR(0))) || (addr >= MA_TO_UINT(SIM_MEM_ADDR(NUM_MACHINES-1) + MEM_SIZE(NUM_MACHINES-1)))); if (addr & 0x8000) { /* Correct the value computed by lw */ ECi( lui_op_, reg, 0, (addr>>16)+1 ); low = (addr & 0xffff) - (1<<16); } else { ECi( lui_op_, reg, 0, (addr>>16)); low = (addr & 0xffff); } /* must be 16 bits for vcode !! */ ASSERT(is16bit(low)); switch (loadOpCode) { case lb_op: ECi( lb_op_, reg, reg, low ); break; case lw_op: ECi( lw_op_, reg, reg, low ); break; case ld_op: ECi( REG_LD_OP, reg, reg, low ); break; } /* we're dead if we use more than 2 instructions */ ASSERT( memptr - temp == 2);}/*----------------------------------------------------------------------------- * * This section provides support for chaining * *---------------------------------------------------------------------------*//* This is a deceptively simple function. It emits a prelude to *//* the basic block's translation. Only embra gods may modify it*//* XXX BL comment: Will this qualify me as an embra god?? soon!! ;-) */static void Page_Prelude_Chain_Check( InstrGrp *instrGrp, int cycles ){ TCA start = memptr; /* This is the bail out code, called if we should not have chained */ /* to here */ /* It can be chained, because the old ra is still in the register */ /* (and old & new pc are) correct -- except when we are coming from */ /* our exception return path, continue_run_without_chaining -- see */ /* main_run.s for details */ SET_LABEL(cont_run ); ECj(j_op_, dispatchChain); ECnop; /* do_periodic: we end up here when our clock goes to zero or below */ SET_LABEL(do_periodic ); ECi(addiu_op_, CLOCK_REG, CLOCK_REG, cycles); ECj( jal_op_, periodicCallout ); ECnop; ECi(ori_op_, RA, G0, 8); /* Smash RA from callout to prevent bogus chain ; * Note that chain will be to $ra-8 = 0, so no chain */ if (!SPECULATIVE_ENTRY) SPECULATIVE_ENTRY = memptr - start; ASSERT (start+SPECULATIVE_ENTRY == memptr); start = memptr; /* SPECULATIVE_ENTRY: */ /* Entry point number 1 is for jr (conditional chaining). It checks */ /* virtual address match */ Load_Reg_Immed( SIM_T1, instrGrp->virt_pc ); /* If the virtual address of the last BB's target is not our VA, */ /* bail out to j continue_run;nop */ ECilab( bne_op_, PC_REG, SIM_T1, USE_LABEL( cont_run ) ); ECnop; if (!CHECK_MAPPING_ENTRY) CHECK_MAPPING_ENTRY = memptr - start; ASSERT (start+CHECK_MAPPING_ENTRY == memptr); start = memptr; /* CHECK_MAPPING_ENTRY: */ /* Entry point number 2 is for regular chaining. It checks physical */ /* address match */ /* For kernel (unmapped) code, there is no mapping, so no check */ if( !IS_UNMAPPED_ADDR( instrGrp->virt_pc ) ) {#ifdef EMBRA_USE_QC64 ECi(ori_op_,SHADOW0,RA, 0); /* Save RA for chaining purpose */ ECi(ADDR_ADDI_OP, A0, PC_REG, 0); /* argument = PC */ ECj(jal_op_, Em_HackedIPageMMUQC); /* Returns in SIM_T2 */ ECi(ori_op_,RA, SHADOW0, 0); /* Restore RA for chaining purpose */#else if( embra.MPinUP ) { /* This code uses the actual virtual address of the current */ /* process because we can't do the faster version for MPinMP. */ /* There is such strong incentive for all dynamically linked */ /* libraries to be mapped at the same VA, that we can simply */ /* say that each VA, PA pair has its own translated block. This */ /* allows the faster check done below. */ ECsh( srl_op_, SIM_T2, PC_REG, NUM_OFFSET_BITS ); /* Word Align */ ECsh( sll_op_, SIM_T2, SIM_T2, 2 ); ECs(addu_op_, SIM_T2, SIM_T2, MMU_REG ); ECi(lw_op_, SIM_T2, SIM_T2, 0); } else { Load_Op_Immed( lw_op, SIM_T2, (uint)&EMP[instrGrp->cpuNum].mmu[PAGE_NUMBER(instrGrp->virt_pc)] ); }#endif Load_32_Bit_Immed( SIM_T1, MA_TO_UINT(instrGrp->maPC)&0x7FFFF000 ); /* If the physical page corresponding to the present virtual page is */ /* not what we think know ours to be, then bail out. */ /* Don't allow matches to pages which are set exclusive -- */ /* this implies we are executing of a page which was just */ /* written to */ ECilab( bne_op_, SIM_T1, SIM_T2, USE_LABEL( cont_run ) ); ECnop; if (!SAME_PAGE_ENTRY) SAME_PAGE_ENTRY = memptr - start; /* SAME_PAGE_ENTRY: no need to check anything */ ASSERT (start + SAME_PAGE_ENTRY ==memptr); } /* if !IS_UNMAPPED_ADDR */} /* Page_Prelude_Chain_Check *//* Comments are in Page_Prelude_Chain_Check */static void Cache_Prelude_Chain_Check( InstrGrp *instrGrp, int cycles){ uint laddr; TCA start =memptr; /* * Prelude to basic block */ SET_LABEL(cont_run ); ECj( j_op_, continue_run ); ECnop; /* do_periodic: we end up here when our clock goes to zero or below */ SET_LABEL(do_periodic ); ECi( addiu_op_, CLOCK_REG, CLOCK_REG, cycles ); ECj( jal_op_, periodicCallout ); ECnop; ECi(ori_op_, RA, G0, 8); /* Smash RA from callout to prevent bogus chain */ /*ECi( REG_ST_OP, PC_REG, VSS_BASE, PC_OFF );*/ /* * Main (first) entry point of translated BB */ if( instrGrp->is_delay_slot_instr ) { /* Align and adjust PC */#if defined(SIM_MIPS32) ECsh( srl_op_, PC_REG, PC_REG, 1 ); ECsh( sll_op_, PC_REG, PC_REG, 1 );#else ECsh( dsrl_op_, PC_REG, PC_REG, 1 ); ECsh( dsll_op_, PC_REG, PC_REG, 1 );#endif ECi(ADDR_ADDI_OP, PC_REG, PC_REG, -4); return; } if (!SPECULATIVE_ENTRY) SPECULATIVE_ENTRY = memptr - start; ASSERT (start+SPECULATIVE_ENTRY == memptr); start = memptr; /* Entry point number 1 is for jr (conditional chaining). It checks */ /* virtual address match */ Load_Reg_Immed( SIM_T1, instrGrp->virt_pc ); /* If the virtual address of the last BB's target is not our VA, */ /* bail out to j continue_run;nop */ ECilab( bne_op_, PC_REG, SIM_T1, USE_LABEL(cont_run) ); ECnop; if (!CHECK_MAPPING_ENTRY) CHECK_MAPPING_ENTRY = memptr - start; ASSERT (start+CHECK_MAPPING_ENTRY == memptr); start = memptr; /* For kernel code, virtual/physical mapping is the identity map */ if( !IS_UNMAPPED_ADDR( instrGrp->virt_pc ) ) { #ifdef EMBRA_USE_QC64 ECi(ori_op_,SHADOW0,RA, 0); /* Save RA for chaining purpose */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -