📄 translate.c
字号:
/* * MIPS32 emulation for qemu: main translation routines. * * Copyright (c) 2004-2005 Jocelyn Mayer * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */#include <stdarg.h>#include <stdlib.h>#include <stdio.h>#include <string.h>#include <inttypes.h>#include "cpu.h"#include "exec-all.h"#include "disas.h"//#define MIPS_DEBUG_DISAS//#define MIPS_SINGLE_STEP#ifdef USE_DIRECT_JUMP#define TBPARAM(x)#else#define TBPARAM(x) (long)(x)#endifenum {#define DEF(s, n, copy_size) INDEX_op_ ## s,#include "opc.h"#undef DEF NB_OPS,};static uint16_t *gen_opc_ptr;static uint32_t *gen_opparam_ptr;#include "gen-op.h"/* MIPS opcodes */#define EXT_SPECIAL 0x100#define EXT_SPECIAL2 0x200#define EXT_REGIMM 0x300#define EXT_CP0 0x400#define EXT_CP1 0x500#define EXT_CP2 0x600#define EXT_CP3 0x700enum { /* indirect opcode tables */ OPC_SPECIAL = 0x00, OPC_BREGIMM = 0x01, OPC_CP0 = 0x10, OPC_CP1 = 0x11, OPC_CP2 = 0x12, OPC_CP3 = 0x13, OPC_SPECIAL2 = 0x1C, /* arithmetic with immediate */ OPC_ADDI = 0x08, OPC_ADDIU = 0x09, OPC_SLTI = 0x0A, OPC_SLTIU = 0x0B, OPC_ANDI = 0x0C, OPC_ORI = 0x0D, OPC_XORI = 0x0E, OPC_LUI = 0x0F, /* Jump and branches */ OPC_J = 0x02, OPC_JAL = 0x03, OPC_BEQ = 0x04, /* Unconditional if rs = rt = 0 (B) */ OPC_BEQL = 0x14, OPC_BNE = 0x05, OPC_BNEL = 0x15, OPC_BLEZ = 0x06, OPC_BLEZL = 0x16, OPC_BGTZ = 0x07, OPC_BGTZL = 0x17, OPC_JALX = 0x1D, /* MIPS 16 only */ /* Load and stores */ OPC_LB = 0x20, OPC_LH = 0x21, OPC_LWL = 0x22, OPC_LW = 0x23, OPC_LBU = 0x24, OPC_LHU = 0x25, OPC_LWR = 0x26, OPC_SB = 0x28, OPC_SH = 0x29, OPC_SWL = 0x2A, OPC_SW = 0x2B, OPC_SWR = 0x2E, OPC_LL = 0x30, OPC_SC = 0x38, /* Floating point load/store */ OPC_LWC1 = 0x31, OPC_LWC2 = 0x32, OPC_LDC1 = 0x35, OPC_LDC2 = 0x36, OPC_SWC1 = 0x39, OPC_SWC2 = 0x3A, OPC_SDC1 = 0x3D, OPC_SDC2 = 0x3E, /* Cache and prefetch */ OPC_CACHE = 0x2F, OPC_PREF = 0x33,};/* MIPS special opcodes */enum { /* Shifts */ OPC_SLL = 0x00 | EXT_SPECIAL, /* NOP is SLL r0, r0, 0 */ /* SSNOP is SLL r0, r0, 1 */ OPC_SRL = 0x02 | EXT_SPECIAL, OPC_SRA = 0x03 | EXT_SPECIAL, OPC_SLLV = 0x04 | EXT_SPECIAL, OPC_SRLV = 0x06 | EXT_SPECIAL, OPC_SRAV = 0x07 | EXT_SPECIAL, /* Multiplication / division */ OPC_MULT = 0x18 | EXT_SPECIAL, OPC_MULTU = 0x19 | EXT_SPECIAL, OPC_DIV = 0x1A | EXT_SPECIAL, OPC_DIVU = 0x1B | EXT_SPECIAL, /* 2 registers arithmetic / logic */ OPC_ADD = 0x20 | EXT_SPECIAL, OPC_ADDU = 0x21 | EXT_SPECIAL, OPC_SUB = 0x22 | EXT_SPECIAL, OPC_SUBU = 0x23 | EXT_SPECIAL, OPC_AND = 0x24 | EXT_SPECIAL, OPC_OR = 0x25 | EXT_SPECIAL, OPC_XOR = 0x26 | EXT_SPECIAL, OPC_NOR = 0x27 | EXT_SPECIAL, OPC_SLT = 0x2A | EXT_SPECIAL, OPC_SLTU = 0x2B | EXT_SPECIAL, /* Jumps */ OPC_JR = 0x08 | EXT_SPECIAL, OPC_JALR = 0x09 | EXT_SPECIAL, /* Traps */ OPC_TGE = 0x30 | EXT_SPECIAL, OPC_TGEU = 0x31 | EXT_SPECIAL, OPC_TLT = 0x32 | EXT_SPECIAL, OPC_TLTU = 0x33 | EXT_SPECIAL, OPC_TEQ = 0x34 | EXT_SPECIAL, OPC_TNE = 0x36 | EXT_SPECIAL, /* HI / LO registers load & stores */ OPC_MFHI = 0x10 | EXT_SPECIAL, OPC_MTHI = 0x11 | EXT_SPECIAL, OPC_MFLO = 0x12 | EXT_SPECIAL, OPC_MTLO = 0x13 | EXT_SPECIAL, /* Conditional moves */ OPC_MOVZ = 0x0A | EXT_SPECIAL, OPC_MOVN = 0x0B | EXT_SPECIAL, OPC_MOVCI = 0x01 | EXT_SPECIAL, /* Special */ OPC_PMON = 0x05 | EXT_SPECIAL, OPC_SYSCALL = 0x0C | EXT_SPECIAL, OPC_BREAK = 0x0D | EXT_SPECIAL, OPC_SYNC = 0x0F | EXT_SPECIAL,};enum { /* Mutiply & xxx operations */ OPC_MADD = 0x00 | EXT_SPECIAL2, OPC_MADDU = 0x01 | EXT_SPECIAL2, OPC_MUL = 0x02 | EXT_SPECIAL2, OPC_MSUB = 0x04 | EXT_SPECIAL2, OPC_MSUBU = 0x05 | EXT_SPECIAL2, /* Misc */ OPC_CLZ = 0x20 | EXT_SPECIAL2, OPC_CLO = 0x21 | EXT_SPECIAL2, /* Special */ OPC_SDBBP = 0x3F | EXT_SPECIAL2,};/* Branch REGIMM */enum { OPC_BLTZ = 0x00 | EXT_REGIMM, OPC_BLTZL = 0x02 | EXT_REGIMM, OPC_BGEZ = 0x01 | EXT_REGIMM, OPC_BGEZL = 0x03 | EXT_REGIMM, OPC_BLTZAL = 0x10 | EXT_REGIMM, OPC_BLTZALL = 0x12 | EXT_REGIMM, OPC_BGEZAL = 0x11 | EXT_REGIMM, OPC_BGEZALL = 0x13 | EXT_REGIMM, OPC_TGEI = 0x08 | EXT_REGIMM, OPC_TGEIU = 0x09 | EXT_REGIMM, OPC_TLTI = 0x0A | EXT_REGIMM, OPC_TLTIU = 0x0B | EXT_REGIMM, OPC_TEQI = 0x0C | EXT_REGIMM, OPC_TNEI = 0x0E | EXT_REGIMM,};enum { /* Coprocessor 0 (MMU) */ OPC_MFC0 = 0x00 | EXT_CP0, OPC_MTC0 = 0x04 | EXT_CP0, OPC_TLBR = 0x01 | EXT_CP0, OPC_TLBWI = 0x02 | EXT_CP0, OPC_TLBWR = 0x06 | EXT_CP0, OPC_TLBP = 0x08 | EXT_CP0, OPC_ERET = 0x18 | EXT_CP0, OPC_DERET = 0x1F | EXT_CP0, OPC_WAIT = 0x20 | EXT_CP0,};const unsigned char *regnames[] = { "r0", "at", "v0", "v1", "a0", "a1", "a2", "a3", "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra", };/* Warning: no function for r0 register (hard wired to zero) */#define GEN32(func, NAME) \static GenOpFunc *NAME ## _table [32] = { \NULL, NAME ## 1, NAME ## 2, NAME ## 3, \NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7, \NAME ## 8, NAME ## 9, NAME ## 10, NAME ## 11, \NAME ## 12, NAME ## 13, NAME ## 14, NAME ## 15, \NAME ## 16, NAME ## 17, NAME ## 18, NAME ## 19, \NAME ## 20, NAME ## 21, NAME ## 22, NAME ## 23, \NAME ## 24, NAME ## 25, NAME ## 26, NAME ## 27, \NAME ## 28, NAME ## 29, NAME ## 30, NAME ## 31, \}; \static inline void func(int n) \{ \ NAME ## _table[n](); \}/* General purpose registers moves */GEN32(gen_op_load_gpr_T0, gen_op_load_gpr_T0_gpr);GEN32(gen_op_load_gpr_T1, gen_op_load_gpr_T1_gpr);GEN32(gen_op_load_gpr_T2, gen_op_load_gpr_T2_gpr);GEN32(gen_op_store_T0_gpr, gen_op_store_T0_gpr_gpr);GEN32(gen_op_store_T1_gpr, gen_op_store_T1_gpr_gpr);typedef struct DisasContext { struct TranslationBlock *tb; target_ulong pc, saved_pc; uint32_t opcode; /* Routine used to access memory */ int mem_idx; uint32_t hflags, saved_hflags; uint32_t CP0_Status; int bstate; target_ulong btarget;} DisasContext;enum { BS_NONE = 0, /* We go out of the TB without reaching a branch or an * exception condition */ BS_STOP = 1, /* We want to stop translation for any reason */ BS_BRANCH = 2, /* We reached a branch condition */ BS_EXCP = 3, /* We reached an exception condition */};#if defined MIPS_DEBUG_DISAS#define MIPS_DEBUG(fmt, args...) \do { \ if (loglevel & CPU_LOG_TB_IN_ASM) { \ fprintf(logfile, "%08x: %08x " fmt "\n", \ ctx->pc, ctx->opcode , ##args); \ } \} while (0)#else#define MIPS_DEBUG(fmt, args...) do { } while(0)#endif#define MIPS_INVAL(op) \do { \ MIPS_DEBUG("Invalid %s %03x %03x %03x", op, ctx->opcode >> 26, \ ctx->opcode & 0x3F, ((ctx->opcode >> 16) & 0x1F)); \} while (0)#define GEN_LOAD_REG_TN(Tn, Rn) \do { \ if (Rn == 0) { \ glue(gen_op_reset_, Tn)(); \ } else { \ glue(gen_op_load_gpr_, Tn)(Rn); \ } \} while (0)#define GEN_LOAD_IMM_TN(Tn, Imm) \do { \ if (Imm == 0) { \ glue(gen_op_reset_, Tn)(); \ } else { \ glue(gen_op_set_, Tn)(Imm); \ } \} while (0)#define GEN_STORE_TN_REG(Rn, Tn) \do { \ if (Rn != 0) { \ glue(glue(gen_op_store_, Tn),_gpr)(Rn); \ } \} while (0)static inline void save_cpu_state (DisasContext *ctx, int do_save_pc){#if defined MIPS_DEBUG_DISAS if (loglevel & CPU_LOG_TB_IN_ASM) { fprintf(logfile, "hflags %08x saved %08x\n", ctx->hflags, ctx->saved_hflags); }#endif if (do_save_pc && ctx->pc != ctx->saved_pc) { gen_op_save_pc(ctx->pc); ctx->saved_pc = ctx->pc; } if (ctx->hflags != ctx->saved_hflags) { gen_op_save_state(ctx->hflags); ctx->saved_hflags = ctx->hflags; if (ctx->hflags & MIPS_HFLAG_BR) { gen_op_save_breg_target(); } else if (ctx->hflags & MIPS_HFLAG_B) { gen_op_save_btarget(ctx->btarget); } else if (ctx->hflags & MIPS_HFLAG_BMASK) { gen_op_save_bcond(); gen_op_save_btarget(ctx->btarget); } }}static inline void generate_exception_err (DisasContext *ctx, int excp, int err){#if defined MIPS_DEBUG_DISAS if (loglevel & CPU_LOG_TB_IN_ASM) fprintf(logfile, "%s: raise exception %d\n", __func__, excp);#endif save_cpu_state(ctx, 1); if (err == 0) gen_op_raise_exception(excp); else gen_op_raise_exception_err(excp, err); ctx->bstate = BS_EXCP;}static inline void generate_exception (DisasContext *ctx, int excp){ generate_exception_err (ctx, excp, 0);}#if defined(CONFIG_USER_ONLY)#define op_ldst(name) gen_op_##name##_raw()#define OP_LD_TABLE(width)#define OP_ST_TABLE(width)#else#define op_ldst(name) (*gen_op_##name[ctx->mem_idx])()#define OP_LD_TABLE(width) \static GenOpFunc *gen_op_l##width[] = { \ &gen_op_l##width##_user, \ &gen_op_l##width##_kernel, \}#define OP_ST_TABLE(width) \static GenOpFunc *gen_op_s##width[] = { \ &gen_op_s##width##_user, \ &gen_op_s##width##_kernel, \}#endif#ifdef TARGET_MIPS64OP_LD_TABLE(d);OP_LD_TABLE(dl);OP_LD_TABLE(dr);OP_ST_TABLE(d);OP_ST_TABLE(dl);OP_ST_TABLE(dr);#endifOP_LD_TABLE(w);OP_LD_TABLE(wl);OP_LD_TABLE(wr);OP_ST_TABLE(w);OP_ST_TABLE(wl);OP_ST_TABLE(wr);OP_LD_TABLE(h);OP_LD_TABLE(hu);OP_ST_TABLE(h);OP_LD_TABLE(b);OP_LD_TABLE(bu);OP_ST_TABLE(b);OP_LD_TABLE(l);OP_ST_TABLE(c);/* Load and store */static void gen_ldst (DisasContext *ctx, uint16_t opc, int rt, int base, int16_t offset){ const unsigned char *opn = "unk"; if (base == 0) { GEN_LOAD_IMM_TN(T0, offset); } else if (offset == 0) { gen_op_load_gpr_T0(base); } else { gen_op_load_gpr_T0(base); gen_op_set_T1(offset); gen_op_add(); } /* Don't do NOP if destination is zero: we must perform the actual * memory access */ switch (opc) {#if defined(TARGET_MIPS64) case OPC_LD:#if defined (MIPS_HAS_UNALIGNED_LS) case OPC_ULD:#endif op_ldst(ld); GEN_STORE_TN_REG(rt, T0); opn = "ld"; break; case OPC_SD:#if defined (MIPS_HAS_UNALIGNED_LS) case OPC_USD:#endif GEN_LOAD_REG_TN(T1, rt); op_ldst(sd); opn = "sd"; break; case OPC_LDL: op_ldst(ldl); GEN_STORE_TN_REG(rt, T0); opn = "ldl"; break; case OPC_SDL: GEN_LOAD_REG_TN(T1, rt); op_ldst(sdl); opn = "sdl"; break; case OPC_LDR: op_ldst(ldr); GEN_STORE_TN_REG(rt, T0);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -