📄 translator.c
字号:
#ifndef EMBRA_USE_QC64 ASSERT( !IS_MMU_PROT_WRITE(QC_MMU_LOOKUP(curEmp,curEmp->PC)));#endif } #if defined(SIM_MIPS64) ASSERT( IS_KSEG0(curEmp->PC) || IS_KUSEG(curEmp->PC) || IS_KSEG2(curEmp->PC));#endif #if CHECKREGS if (check_regs) { CheckRegs((unsigned) targetTCA, (unsigned) new_pc, 0); /* don't chain */ return targetTCA; }#endif /* no chaining for now!! */ if (!jump_addr) { /* * no chaining. simply return the targetTCA */ return targetTCA; } if( ((uint)jump_addr ) == (uint)Embra_CX_nochain ) { STAT_INC(chain_bounced); return targetTCA; } if (!TC_InTC(TC_USER,jump_addr) && !TC_InTC(TC_KERN,jump_addr)) { CPUWarning("EmbraChaining: %10lld cpu=%d PC=0x%llx chaining from 0x%x\n", (uint64)EmbraCpuCycleCount(curEmp->myNum), curEmp->myNum,(Reg64)curEmp->PC, jump_addr); return targetTCA; }#if CHECK_INTER_TC_CHAIN if ((TC_InTC(TC_USER,jump_addr) && TC_InTC(TC_KERN,targetTCA)) || (TC_InTC(TC_KERN,jump_addr) && TC_InTC(TC_USER,targetTCA))) { CPUError("EmbraChaining: inter-TC chain at %10lld cpu=%d PC=0x%llx chaining from 0x%x to 0x%x\n", (uint64)EmbraCpuCycleCount(curEmp->myNum), curEmp->myNum,(Reg64)curEmp->PC, jump_addr, targetTCA); return targetTCA; }#endif /* For regind we need to chain to speculative entry point; otherwise, * we can do better */ if( MIPS_ISNT_REGIND(jump_addr) ) { /* * get the translation for the page of the previous pc. * we need to decode it once more */#ifdef EMBRA_USE_QC64 MA memAddr = (MA) ((uint)Em_QC64Reload(curEmp->oldPC,QC64_READ) & ~(DEFAULT_PAGESZ-1));#else MA memAddr = MMU2ADDR(QC_MMU_LOOKUP(curEmp,curEmp->oldPC));#endif VA endOldBB = (memAddr?EndOfBB(curEmp->oldPC,memAddr+(curEmp->oldPC & (DEFAULT_PAGESZ-1))):0); chainTCA = FindEntryPoint(curEmp->oldPC,endOldBB,new_pc,targetTCA); } else { /* chain to speculative entry point */ chainTCA = targetTCA; } /* Actually overwrite old jump instr */ ASSERT( MIPS_IS_JUMP(jump_addr) ); /* ASSERT(!TC_In_TC( (void*)(((*(unsigned*)jump_addr) & 0x3ffffff) << 2) )); */ MIPS_CHANGE_JUMP_TARGET(jump_addr, chainTCA); FlushOneLine(jump_addr);#if 0 CPUWarning("Chain: (0x%x,0x%08x) -> (0x%x,0x%08x) : +%d val=0x%08x\n", old_pc, jump_addr, curEmp->PC,chainTCA, (uint)chainTCA-(uint)targetTCA, *(unsigned*)jump_addr);#endif return chainTCA;/* }*/}void Transfer_To(TransState *trans, VA vPC ){ TCA trans_PC; ASSERT( !IN_BD(vPC)); switch(chainMode) { case NO_C: /* This jumps directly to dispatch. Since NO_C is set, chaining */ /* is not in effect */ ECj(jal_op_, dispatchNoChain); return; case BB_C: trans_PC = FindTCA_NoSE(trans->instrGrp->cpuNum, vPC );#if CHECKREGS if (trans_PC && !check_regs) {#else if (trans_PC) {#endif VA oldPCstart = trans->instrGrp->virt_pc; VA oldPCend = trans->instrGrp->virt_pc + mem_size(trans->instrGrp->GrpLen); trans_PC = FindEntryPoint(oldPCstart,oldPCend,vPC,trans_PC); ECj(jal_op_, trans_PC); } else { ECj(jal_op_, dispatchChain); } }}/* ******************************************************** * EmitBranch * * Code immediately following the branch should * be for the branch NOT taken case, while * code for the branch taken case should * start after num_instr_to_skip * ********************************************************/static void Emit_Branch( TransState *trans, int num_instr_to_skip ){ int tmp1, tmp2; /* If we can load, registers and use the branch we are translating */ if( trans->instrGrp->delay_slot_reg_conflict ) { ECi(bgtz_op_, G0, BRANCHREG, num_instr_to_skip); }else{ switch( MAJOR_OPCODE(trans->branch_instr ) ) { case beq_op: case bne_op: if( prev_store.real == rt(trans->branch_instr) ) { tmp2 = Load( SIM_T2, rt(trans->branch_instr) ); tmp1 = Load( SIM_T1, rs(trans->branch_instr) ); } else { tmp1 = Load( SIM_T1, rs(trans->branch_instr) ); tmp2 = Load( SIM_T2, rt(trans->branch_instr) ); } switch( MAJOR_OPCODE(trans->branch_instr ) ) { case beq_op: ECi(beq_op_, tmp2, tmp1, num_instr_to_skip); break; case bne_op: ECi(bne_op_, tmp2, tmp1, num_instr_to_skip); break; } break; case cop1_op: /* Kinda hacky way of changing the offset of an fp branch */ /*** XXX THIS WILL HAVE TO BE FIXED -BL ******/ *memptr++ = (trans->branch_instr & 0xffff0000) | num_instr_to_skip; break; default: tmp1 = Load(SIM_T1, rs(trans->branch_instr)); if (MAJOR_OPCODE(trans->branch_instr) == bcond_op) { switch(rt(trans->branch_instr)) { case bltz_op: case bltzl_op: ECb(bltz_op_, tmp1, num_instr_to_skip); break; case bgez_op: case bgezl_op: ECb(bgez_op_, tmp1, num_instr_to_skip); break; default: fprintf(stderr, "Emit_Branch- unimplemented branch code = %x\n", rt(trans->branch_instr)); ASSERT(0); break; } } else { switch (MAJOR_OPCODE(trans->branch_instr)) { case blez_op: case blezl_op: ECi(blez_op_, G0, tmp1, num_instr_to_skip); break; case bgtz_op: case bgtzl_op: ECi(bgtz_op_, G0, tmp1, num_instr_to_skip); break; default: fprintf(stderr, "Emit_Branch - unimplemented branch opcode = %x\n", MAJOR_OPCODE(trans->branch_instr)); ASSERT(0); break; } } } }}/* *********************************************************************** * Update_PC * ***********************************************************************/static void Update_PC( TransState *trans, flow_t flow,VA next_PC ) /*flow_t flow, VA current_pc, int grp_len, VA next_PC,unsigned branch_instr,,int no_chain, int delay_slot_reg_conflict )*/{ int no_chain = trans->instrGrp->is_rfe_block; /* || is_delay_slot_instr */ VA current_pc = trans->instrGrp->virt_pc; switch( flow ){ case REGINDIRECT_FLOW: /* This is a register indirect jump, so we have to return to the */ /* main simulator loop */ ASSERT( trans->branch_instr ); /* Put previous PC in OLD_PC */ /*ECs(or_op, OLD_PC, G0, PC_REG);*/ ECi(REG_ST_OP, PC_REG, VSS_BASE, OLDPC_OFF); /* this seems to be needed.... ??? */ ECs( or_op_, PC_REG, G0, BRANCHREG); /* If we are returning from an exception, don't chain. Can't */ /* chain from kernel to user space */ if( no_chain ) { ECj(jal_op_, dispatchNoChain); } else { ECj(jal_op_, dispatchChain); } ECnop; break; case SEQ_FLOW: /* Put previous PC in OLD_PC */ /*ECs(or_op_, OLD_PC, G0, PC_REG);*/ ECi(REG_ST_OP, PC_REG, VSS_BASE, OLDPC_OFF); ECi(ADDR_ADDI_OP, PC_REG, PC_REG, mem_size(trans->instrGrp->GrpLen) ); Transfer_To( trans, current_pc + mem_size(trans->instrGrp->GrpLen) ); ECnop; break; case JMP_FLOW: /* Put previous PC in OLD_PC */ /*ECs(or_op_, OLD_PC, G0, PC_REG);*/ ECi(REG_ST_OP, PC_REG, VSS_BASE, OLDPC_OFF);#if defined(SIM_MIPS32) ECi( lui_op_, PC_REG, G0, next_PC>>16 ); ECi( ori_op_, PC_REG, PC_REG, next_PC ); Transfer_To( trans, next_PC ); ECnop;#else { int64 dist = next_PC - trans->instrGrp->virt_pc; ASSERT(dist == (int)dist); if ((((int)dist & 0xffff8000) == 0) || (((int)dist & 0xffff8000) == 0xffff8000)) { /* Fits in immediate field */ ECi( ADDR_ADDI_OP, PC_REG, PC_REG, (int)dist); Transfer_To( trans, next_PC ); } else { Load_32_Bit_Immed(SIM_T1, dist); ECs( ADDR_ADD_OP, PC_REG, PC_REG, SIM_T1); Transfer_To( trans, next_PC ); } }#endif break; case BRANCH_FLOW: /* Unconditional branches are implemented as beq $0 $0 */ if( MAJOR_OPCODE( trans->branch_instr == beq_op ) && rs( trans->branch_instr ) == G0 && rt( trans->branch_instr ) == G0 ) { /* Put previous PC in OLD_PC */ /*ECs(or_op_, OLD_PC, G0, PC_REG);*/ ECi(REG_ST_OP, PC_REG, VSS_BASE, OLDPC_OFF); if( ((int)(next_PC - current_pc) < (1<<15)) && ((int)(next_PC - current_pc) > (-(1<<15))) ) { ECi(ADDR_ADDI_OP, PC_REG, PC_REG, next_PC - current_pc); Transfer_To( trans, next_PC); ECnop; }else{ Load_32_Bit_Immed(SIM_T1, next_PC - current_pc); ECs(ADDR_ADD_OP, PC_REG, PC_REG, SIM_T1); Transfer_To( trans, next_PC); ECnop; } break; } ASSERT( trans->branch_instr ); /* Both branches need the pc moved to the old PC */ /*ECs(or_op_, OLD_PC, G0, PC_REG);*/ ECi(REG_ST_OP, PC_REG, VSS_BASE, OLDPC_OFF); Emit_Branch(trans, 3); ECnop; /* Fall Through Case */ ECi(ADDR_ADDI_OP, PC_REG, PC_REG, mem_size(trans->instrGrp->GrpLen) ); Transfer_To( trans, current_pc + mem_size(trans->instrGrp->GrpLen)); ECnop; VCTARGET; /* branch target for vcode */ /* Branch Taken */ if( ((int)(next_PC - current_pc) < (1<<15)) && ((int)(next_PC - current_pc) > (-(1<<15))) ) { ECi(ADDR_ADDI_OP, PC_REG, PC_REG, next_PC - current_pc); Transfer_To( trans, next_PC); ECnop; }else{ Load_32_Bit_Immed(SIM_T1, next_PC - current_pc); ECs(ADDR_ADD_OP, PC_REG, PC_REG, SIM_T1); Transfer_To( trans, next_PC ); ECnop; } break; case BRANCH_UNTAKEN: ASSERT( trans->branch_instr ); /* Skip the chain if condition says, "Taken"*/ /* Put previous PC in OLD_PC */ /*ECs(or_op_, OLD_PC, G0, PC_REG);*/ ECi(REG_ST_OP, PC_REG, VSS_BASE, OLDPC_OFF); Emit_Branch(trans, 4); /* was 3 -BL */ /* Fall Through (annulling) Case */ ECi(ADDR_ADDI_OP, PC_REG, PC_REG, mem_size(trans->instrGrp->GrpLen)); Transfer_To( trans, current_pc + mem_size(trans->instrGrp->GrpLen) ); ECnop; VCTARGET; /* branch target for vcode */ break; case BRANCH_TAKEN: /* Previous PC in OLD_PC in the BRANCH_UNTAKEN case */ /* Branch Taken */ if( ((int)(next_PC - current_pc) < (1<<15)) && ((int)(next_PC - current_pc) > -(1<<15)) ) { ECi(ADDR_ADDI_OP, PC_REG, PC_REG, next_PC - current_pc); Transfer_To( trans, next_PC ); ECnop; }else{ Load_32_Bit_Immed( SIM_T1, next_PC - current_pc ); ECs(ADDR_ADD_OP, PC_REG, PC_REG, SIM_T1); Transfer_To( trans, next_PC ); ECnop; } break; }}/*----------------------------------------------------------------------------- * * This section provides support for callout facilities * *---------------------------------------------------------------------------*//* XXX THIS IS WRONG!!! beware, was 7 */#define DO_EXCEPTION_CALLOUT_LEN (bogus)static void Do_Exception_Callout( TransState *trans, int exception_code){ TCA start = memptr; PC_BD pc = COMPOSE_PC(trans); /* Put exception code into A1 */ Load_32_Bit_Immed( A1, exception_code ); /* Put current pc into S */ ECi(ADDR_ADDI_OP, SIM_T4, PC_REG, COMPOSE_PC(trans) - trans->instrGrp->virt_pc); ECi(REG_ST_OP, SIM_T4, VSS_BASE, PC_OFF); ECi(addiu_op_, A3, G0, trans->cycle_correction); /* Put procedure number in SIM_T2 */ ECi( addiu_op_, SIM_T2, G0, CALLOUT_EXCEPTION ); /* XXX - Note we do not set A2 because it is only checked on an */ /* EXC_CPU, coprocessor unusable exception, and we do not raise */ /* those from emitted code */ /* Do the Callout */ ECj( jal_op_, callout ); ECnop;}void Do_Callout( TransState *trans, int callout_code ){ PC_BD pc = COMPOSE_PC(trans); TCA start = memptr; /* Put State pointer into A0 */ /* Put current pc into A1 */ ECi(ADDR_ADDI_OP, SIM_T4, PC_REG, COMPOSE_PC(trans) - trans->instrGrp->virt_pc); ECi(REG_ST_OP, SIM_T4, VSS_BASE, PC_OFF); ECi(addiu_op_, A3, G0, trans->cycle_correction); /* Put procedure number in SIM_T2 */ ECi(addiu_op_, SIM_T2, G0, callout_code ); /* Do the Callout */ ECj( jal_op_, callout ); ECnop;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -