⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 translate.c

📁 qemu虚拟机代码
💻 C
📖 第 1 页 / 共 4 页
字号:
/* *  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 + -