📄 decoder.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. * *//*************************************************************************** * * File: decoder.c * * This decodes a basic block worth of instructions. * Its main complexity comes in the fact that it * is given a physical PC which, if it runs off the end of a page, it * must find the page on which the block continues by converting the * virtual PC. Thus we need to know the virtual and physical PC * * $Author: bosch $ * $Date: 1998/02/10 00:30:24 $ * ***************************************************************************/#include <stdio.h>#include "embra.h"#include "decoder.h"#include "main_run.h"#include "annotations.h"#include "mem_control.h"#include "cp0.h"#include "clock.h"#include "driver.h"/* We are at a page boundary if the lower 12 bits are 0 */#define PAGE_BOUNDARY( val ) (!((val) & (DEFAULT_PAGESZ-1)))#define NOP 0#define MAX_NOPS 12int maxInGroup;voidDecoderInit(void){/* maximum number of instructions in one group *//* It should be relatively large so 1 basic block doesn't have to get *//* artificially chopped up in the TC, but it must be smaller than *//* TQUANT so that you can guarantee interleaving every TQUANT *//* instructions, but you can still execute blocks larger than TQUANT *//* instructions */ maxInGroup = embra.timeQuantum - 1; if( maxInGroup > INST_GRP_LIMIT ) maxInGroup = INST_GRP_LIMIT;}/*----------------------------------------------------------------------------- * * Routine: DecodeInstrs * * Parameters: * * instrGrp - a group of instructions, to fill stuff in. * *----------------------------------------------------------------------------*/void DecodeInstrs( InstrGrp* thisGrp, int cpuNum, VA pc, int is_delay_slot_instr ){ unsigned int code; /* value of binary code read in. */ unsigned int *code_ptr; int ctl_inst = 0; int ctl_reg1 = REG_NONE; int ctl_reg2 = REG_NONE; int Delayed=0; /* used as a flag for the delayed slot. */ int i; /* Translate VA PC into a physical address PC */ /* Note, if the VA PC is a backdoor address, mem_translate jumps to */ /* it directly, and then executes goto_continue_run with the present */ /* return address. Simulating backdoor code is a bad idea */ /* If we take an exception, we don't return */ thisGrp->phys_pc = mem_translate(cpuNum,pc); thisGrp->maPC = PHYS_TO_MEMADDR(M_FROM_CPU(cpuNum),thisGrp->phys_pc ); thisGrp->cpuNum = cpuNum; thisGrp->virt_pc = pc; thisGrp->is_delay_slot_instr = is_delay_slot_instr; thisGrp->next_maPC = 0; thisGrp->GrpLen = 0; thisGrp->numDMemoryAcesses = 0; thisGrp->numIMemoryAcesses = 0; thisGrp->delay_slot_reg_conflict = 0; thisGrp->no_reg_allocate = 0; thisGrp->is_rfe_block = 0; thisGrp->delay_slot_reg_conflict = 0;#if defined(SIM_MIPS32) thisGrp->isKseg0 = IS_KSEG0(thisGrp->virt_pc);#else thisGrp->isKseg0 = IS_UNMAPPED_ADDR(thisGrp->virt_pc);#endif code_ptr = (uint*)thisGrp->maPC; /* Get a group of instructions, not exceeding maxInGroup number. */ while (thisGrp->GrpLen < maxInGroup) {#ifndef DEBUG_TRANSLATOR VASSERT( EMBRA_IS_MEMADDR( M_FROM_CPU(cpuNum), code_ptr ), ("\nDecoder code_ptr 0x%x thiGrp 0x%x\n", code_ptr, thisGrp) );#endif code = *code_ptr++; /* XXX Syscall instructions don't generate signals. To enable */ /* simos fast mode */ /* to catch syscalls, they are statically translated to the */ /* unaligned load */ if( code == SIMOS_HACKED_SYSCALL ) code = (spec_op<<26) | syscall_op; if( code == SIMOS_HACKED_TNS ) { code = (mendel_tns<<26); thisGrp->no_reg_allocate = 1; } thisGrp->instrs[thisGrp->GrpLen] = code; thisGrp->pcAnn[thisGrp->GrpLen] = 0; if (AnnFMLookup(thisGrp->virt_pc+INST_SIZE*thisGrp->GrpLen,ANNFM_PC_TYPE)) { thisGrp->pcAnn[thisGrp->GrpLen] =ANNFM_PC_TYPE ; thisGrp->no_reg_allocate = 1; thisGrp->delay_slot_reg_conflict = 1; } if (AnnFMLookup(thisGrp->virt_pc+INST_SIZE*thisGrp->GrpLen,ANNFM_PRE_PC_TYPE)) { thisGrp->pcAnn[thisGrp->GrpLen] |=ANNFM_PRE_PC_TYPE ; thisGrp->no_reg_allocate = 1; thisGrp->delay_slot_reg_conflict = 1; } thisGrp->GrpLen++; /* * Corner case: the NEXT instruction will be on the next page, * If this instruction is a control instruction, two things can * happen: either this is the first instruction of the BB, in * which case the (branch,DB) straddling pages case ocurs. * if this is not the case, ie a branch at the end of a * page that is not the first instruction of the BB, then * we shorten the BB to exclude the branch. the branch and branch * delay will be translated separately. */ if (PAGE_BOUNDARY((unsigned) code_ptr) && !IS_KSEG0(thisGrp->virt_pc) && IsCtlInstr(code) && thisGrp->GrpLen > 1) { thisGrp->GrpLen--; break; } /* Gather information about the instruction group */ switch( MAJOR_OPCODE( code ) ) { case spec_op: switch( FUNC( code ) ) { /*************************************/ /* Shifts -- */ /*************************************/ case sll_op: /* [rt] shift by shamt -> [rd] */ case sra_op: case srl_op: thisGrp->reg2alloc[rt(code)].num_src++; if( Delayed ) thisGrp->delay_slot_reg_conflict |= ((rd(code)==ctl_reg1) || (rd(code)==ctl_reg2) ); break; case syscall_op: case break_op: Delayed = 1; break; case div_op: /* [rs] op [rt] -> HI & LO */ case divu_op: case mult_op: case multu_op: case ddiv_op: case ddivu_op: case dmult_op: case dmultu_op: thisGrp->reg2alloc[rs(code)].num_src++; thisGrp->reg2alloc[rt(code)].num_src++; break; case mfhi_op: /* move HI to rd */ case mflo_op: /* move LO to rd */ /* Is this even allowed? */ if( Delayed ) thisGrp->delay_slot_reg_conflict |= ((rd(code)==ctl_reg1) || (rd(code)==ctl_reg2) ); break; case mthi_op: /* move rs to HI */ case mtlo_op: /* move rs to LO */ thisGrp->reg2alloc[rs(code)].num_src++; break; /*************************************/ /* Arithmetic specials */ /* rs == SIM_T1, rt == SIM_T2, rd == SIM_T2 */ /*************************************/ /* [rs] op [rt] -> [rd] */ case add_op: case addu_op: case and_op: case nor_op: case or_op: case sllv_op: case slt_op: case srav_op: case sltu_op: case srlv_op: case sub_op: case subu_op: case xor_op: case dadd_op: case daddu_op: case dsll_op: case dsll32_op: case dsllv_op: case dsrl_op: case dsrl32_op: case dsrlv_op: case dsra_op: case dsra32_op: case dsrav_op: case dsub_op: case dsubu_op: thisGrp->reg2alloc[rs(code)].num_src++; thisGrp->reg2alloc[rt(code)].num_src++; if( Delayed ) thisGrp->delay_slot_reg_conflict |= ((rd(code)==ctl_reg1) || (rd(code)==ctl_reg2) ); break; case movc_op: case movz_op: case movn_op: thisGrp->reg2alloc[rs(code)].num_src++; thisGrp->reg2alloc[rt(code)].num_src++; if( Delayed ) thisGrp->delay_slot_reg_conflict |= ((rd(code)==ctl_reg1) || (rd(code)==ctl_reg2) ); break; case tge_op: case tgeu_op: case tlt_op: case tltu_op: case teq_op: case tne_op: thisGrp->reg2alloc[rs(code)].num_src++; thisGrp->reg2alloc[rt(code)].num_src++; break; case jr_op: case jalr_op: ctl_inst = 1; ctl_reg1 = rs(code)?rs(code):REG_NONE; thisGrp->reg2alloc[rs(code)].num_src++; break; } break; case bcond_op: switch( rt(code) ) { case bgezal_op: case bgezall_op: case bgez_op: case bgezl_op: case bltzal_op: case bltzall_op: case bltz_op: case bltzl_op: thisGrp->reg2alloc[rs(code)].num_src++; ctl_inst = 1; ctl_reg1 = rs(code)?rs(code):REG_NONE; break; case tgei_op: case tgeiu_op: case tlti_op: case tltiu_op: case teqi_op: case tnei_op: thisGrp->reg2alloc[rs(code)].num_src++; break; default: CPUWarning("Unknown REGIMM opcode\n"); ASSERT(0); } break; /* NOTE: move to c0 are handled by callout */ case cop0_op: /* Because these functions callout & write the register file */ /* we have to treat them as contenders for the ctl_instr registers */ /* This is slightly conservative because one of these functions */ if( Delayed ) thisGrp->delay_slot_reg_conflict = 1; if( IS_CP0_FUNC( code ) ) { switch( FUNC( code ) ) { case tlbr_op: case tlbwi_op: case tlbwr_op: case tlbp_op: break; case eret_op: case rfe_op: /* * Remember that rfe and eret have the same * semantic in SimOS (we don't support the r3k, * and highjack the opcode */ Delayed = 1; /* ERET is non-delayed branch */ thisGrp->is_rfe_block = 1; break; default: break; } } else { /* Operation contained in rs */ switch( rs( code ) ) { case dmfc_op: case mfc_op: thisGrp->no_reg_allocate = 1; /* Destination of mfc, dmtc is RT, not RD (kind of silly)*/ if( Delayed ) thisGrp->delay_slot_reg_conflict |= ((rt(code)==ctl_reg1) || (rt(code)==ctl_reg2) ); break; case dmtc_op: case mtc_op: thisGrp->no_reg_allocate = 1; thisGrp->delay_slot_reg_conflict = 1; break; default: break; } } break; case cop1_op: switch( rs(code) ) { case mtc_op: case dmtc_op: case ctc_op:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -