📄 decoder.c
字号:
break; case mfc_op: case dmfc_op: /* Destination of mfc, dmtc is RT, not RD (kind of silly)*/ thisGrp->no_reg_allocate = 1; if( Delayed ) thisGrp->delay_slot_reg_conflict |= ((rt(code)==ctl_reg1) || (rt(code)==ctl_reg2) ); break; case cfc_op: break; case bc_op: thisGrp->delay_slot_reg_conflict = 1; ctl_inst = 1; /* Relies on no integer registers */ break; default: /*arithmetic instruction s*/ break; } break; case j_op: case jal_op: ctl_inst = 1; /* No registers */ break; case beq_op: case bne_op: case blez_op: case bgtz_op: case beql_op: case bnel_op: case blezl_op: case bgtzl_op: thisGrp->reg2alloc[rs(code)].num_src++; thisGrp->reg2alloc[rt(code)].num_src++; ctl_inst = 1; ctl_reg1 = rs(code)?rs(code):REG_NONE; ctl_reg2 = rt(code)?rt(code):REG_NONE; break; case addi_op: /* rs op imm -> rt */ case addiu_op: case andi_op: case ori_op: case slti_op: case sltiu_op: case xori_op: case daddi_op: case daddiu_op: thisGrp->reg2alloc[rs(code)].num_src++; if( Delayed ) thisGrp->delay_slot_reg_conflict |= ((rt(code)==ctl_reg1) || (rt(code)==ctl_reg2) ); break; case lui_op: /* immed<<16 -> rt */ if( Delayed ) thisGrp->delay_slot_reg_conflict |= ((rt(code)==ctl_reg1) || (rt(code)==ctl_reg2) ); break; case ld_op:#if defined(SIM_MIPS32) && defined(DO_WARNING) CPUWarning("Hacked LD inst found at 0x%x\n", thisGrp->virt_pc); #endif case lld_op: case ldc2_op: case ll_op: case lb_op: case lbu_op: case lw_op: case lh_op: case lhu_op: case lwl_op: case lwr_op: case lwu_op: case ldl_op: case ldr_op: thisGrp->reg2alloc[rs(code)].num_src++; thisGrp->numDMemoryAcesses++; if( Delayed ) thisGrp->delay_slot_reg_conflict |= ((rt(code)==ctl_reg1) || (rt(code)==ctl_reg2) ); break; case sc_op: case scd_op: /* In page mode, sc calls compare and swap which uses temp regs */ if( embra.emode == EMBRA_PAGE ) thisGrp->no_reg_allocate = 1; /*FALLTHROUGH */ case sd_op:#if defined(SIM_MIPS32) && defined(DO_WARNING) CPUWarning("Hacked SD inst found at 0x%x\n", thisGrp->virt_pc); #endif case sdc2_op: case sb_op: case sh_op: case sw_op: case swl_op: case swr_op: case sdl_op: case sdr_op: thisGrp->reg2alloc[rs(code)].num_src++; thisGrp->reg2alloc[rt(code)].num_src++; thisGrp->numDMemoryAcesses++; break; case lwc1_op: case ldc1_op: thisGrp->reg2alloc[rs(code)].num_src++; thisGrp->numDMemoryAcesses++; break; case swc1_op: case sdc1_op: thisGrp->reg2alloc[rs(code)].num_src++; thisGrp->reg2alloc[rt(code)].num_src++; thisGrp->numDMemoryAcesses++; break; case mendel_tns: thisGrp->no_reg_allocate = 1; /* This instruction is (and should be) never in the delay slot */ /* but to be safe.. */ /* Because these functions callout & write the register file */ /* we have to treat them as contenders for the ctl_instr registers */ if( Delayed ) thisGrp->delay_slot_reg_conflict= 1; break; case cache_op: thisGrp->numDMemoryAcesses++; break; default: ; /*nothing*/ } /* Finished if that was the instruction in the delay slot */ if (Delayed) break; /* Reached the end of group when hit the control flow, or a page boundary */ if( ctl_inst ) { Delayed = 1; if( thisGrp->GrpLen == maxInGroup ) { /* We have just deocoded an instruction whose delay slot */ /* will not fit in this instruction group. Therefore, */ /* erase the knowledge of this instruction in this */ /* instruction group, so the decoder sees this as a */ /* sequential flow */ thisGrp->GrpLen--; break; } } /* XXX - This is a VERY hairy corner case */ /* When we hit a physical page boundary, we need to see if our */ /* virtual pc is in KSEG0. If it is not, then we need to translate */ /* the next address because code contiguous in virtual address */ /* space, is not necessarily contiguous in physical address */ /* space (exactly at the page boundary). So we translate at the */ /* next PC which is calculated by "raising" the virtual PC to */ /* the first entry on the next (virtual) page. Note that this */ /* wouldn't work if our basic block were over a page, but */ /* maxInGroup insures us that that can't happen. */ /* Also note that we are telling TranslateVirtual that this */ /* request is coming from the virtual address at the start of */ /* the basic block. That way, we return to the block (which we */ /* want to do because we have not yet translated it). This */ /* means that exectuting one instruction can cause an exception */ /* fiarly far downstream, even though none of the intervening */ /* instructions have been executed.*/ /* * To make things even hairier, we now oly straddle pages if * the last instruction on the first page is a control flow instruction. * Otherwise, we split the BB at page boundaries. Raising exceptions * at translation must be avoided whenever possible. In the case where * this is not possible (branch at end of page and delay slot in next page) * we DO raise the exception at translation time, but emit the page * residency check at the same place during the execution of the translated * BB. * * This only applies to user code. Kernel BB may still straddle pages * as the kernel text is in kseg0. * (bugnion) */ if (PAGE_BOUNDARY((unsigned) code_ptr) && !IS_KSEG0(thisGrp->virt_pc)) { PA pAddr; VA next_page_pc; uint tvRes; if (!Delayed) break; next_page_pc = NEXT_PAGE(thisGrp->virt_pc); tvRes = Em_TranslateVirtual(cpuNum, next_page_pc, &pAddr, ACT_IREAD); if( tvRes == EXCEPTION_CODE ) {#if 0 CPUWarning("Embra: decoder exception: 0x%x at %10lld \n", thisGrp->virt_pc, (uint64)EmbraCpuCycleCount(0)); #endif ReenterTC(&EMP[cpuNum]); /* NOT REACHED */ } code_ptr = (unsigned*) PHYS_TO_MEMADDR(M_FROM_CPU(cpuNum), pAddr); ASSERT( EMBRA_IS_MEMADDR( M_FROM_CPU(cpuNum), code_ptr ) ); thisGrp->next_maPC = (MA)code_ptr; thisGrp->next_phys_pc = pAddr; } } /* * Test for the presence of an 'unusual' number * of NOPS in the translated BB. Usually a good sign * fo beign in hyperspace. */ for(i=0;i<thisGrp->GrpLen-MAX_NOPS;i++) { int j=0; while(j < MAX_NOPS && !thisGrp->instrs[j]) { j++; } if (j==MAX_NOPS) { CPUError("EMBRA translating %d NOPs at cpu=%d PC=%#x mAddr=%#x \n", MAX_NOPS,thisGrp->cpuNum,thisGrp->virt_pc,thisGrp->maPC); } } /* Add Icache references */ thisGrp->numIMemoryAcesses = thisGrp->GrpLen;#ifdef DEBUG_TRANSLATOR { extern unsigned trans_test_num_decoded; trans_test_num_decoded = thisGrp->GrpLen; }#endif}int IsCtlInstr(uint inst){ int ctl = 0; switch( MAJOR_OPCODE(inst)) { case bcond_op: case j_op: case jal_op: case beq_op: case bne_op: case blez_op: case bgtz_op: case beql_op: case bnel_op: case blezl_op: case bgtzl_op: ctl = 1; break; case spec_op: switch( FUNC(inst)) { case jr_op: case jalr_op: ctl = 1; break; } break; case cop1_op: switch (rs(inst)) { case bc_op: case eret_op: ctl = 1; } break; } return ctl;}/* **************************************************** * EndOfBB returns the last VA of the BB given by * (VA,PA), but does not straddle pages. If the BB * goes on to the next page, EndOfBB returns the first * word of the second page of the BB * This is only used for an optimization, therefore it's * still ok if we miss a few control instruction. If * EndOfBB cannot prove that the BB ends on the same * page, Chaining optimization will be disabled. * ***************************************************/ VA EndOfBB(VA vA , MA mA){ VA curVA = vA; MA curMA = mA; int ctl = 0; while( 1 ) { uint inst = *(uint*)curMA; switch( MAJOR_OPCODE(inst)) { case bcond_op: case j_op: case jal_op: case beq_op: case bne_op: case blez_op: case bgtz_op: case beql_op: case bnel_op: case blezl_op: case bgtzl_op: ctl = 1; break; case spec_op: switch( FUNC(inst)) { case jr_op: case jalr_op: ctl = 1; break; } break; case cop1_op: switch (rs(inst)) { case bc_op: ctl = 1; } break; } if (ctl) { return curVA + INST_SIZE; } curVA += INST_SIZE; curMA += INST_SIZE; if( PAGE_NUMBER(curVA) != PAGE_NUMBER(vA)) { if (!IS_KSEG0(curVA)) { /* * The bb was split at translation time not * to straddle pages. */ return curVA-INST_SIZE; } return curVA; } }#if !defined(_COMPILER_VERSION) return vA; /* Make old compiler happy */#endif}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -