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

📄 translate.c

📁 qemu性能直逼VMware的仿真器QEMU 的模擬速度約為實機的 25%;約為 Bochs 的 60 倍。Plex86、User-Mode-Linux、VMware 和 Virtual PC 則比
💻 C
📖 第 1 页 / 共 5 页
字号:
/* *  m68k translation *  *  Copyright (c) 2005-2006 CodeSourcery *  Written by Paul Brook * * 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 * 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 "config.h"#include "cpu.h"#include "exec-all.h"#include "disas.h"#include "m68k-qreg.h"static inline void qemu_assert(int cond, const char *msg){    if (!cond) {        fprintf (stderr, "badness: %s\n", msg);        abort();    }}/* internal defines */typedef struct DisasContext {    target_ulong pc;    int is_jmp;    int cc_op;    uint32_t fpcr;    struct TranslationBlock *tb;    int singlestep_enabled;} DisasContext;#define DISAS_JUMP_NEXT 4/* XXX: move that elsewhere *//* ??? Fix exceptions.  */static void *gen_throws_exception;#define gen_last_qop NULLstatic uint16_t *gen_opc_ptr;static uint32_t *gen_opparam_ptr;extern FILE *logfile;extern int loglevel;enum {#define DEF(s, n, copy_size) INDEX_op_ ## s,#include "opc.h"#undef DEF    NB_OPS,};#include "gen-op.h"#include "op-hacks.h"#define OS_BYTE 0#define OS_WORD 1#define OS_LONG 2#define OS_SINGLE 4#define OS_DOUBLE 5#define DREG(insn, pos) (((insn >> pos) & 7) + QREG_D0)#define AREG(insn, pos) (((insn >> pos) & 7) + QREG_A0)#define FREG(insn, pos) (((insn >> pos) & 7) + QREG_F0)#define M68K_INSN_CF_A    (1 << 0)#define M68K_INSN_CF_B    (1 << 1)#define M68K_INSN_CF_C    (1 << 2)#define M68K_INSN_CF_MAC  (1 << 3)#define M68K_INSN_CF_EMAC (1 << 4)#define M68K_INSN_CF_FPU  (1 << 5)struct m68k_def_t {    const char * name;    uint32_t insns;};static m68k_def_t m68k_cpu_defs[] = {    {"m5206", M68K_INSN_CF_A},    {"cfv4e", M68K_INSN_CF_A | M68K_INSN_CF_B | M68K_INSN_CF_C            | M68K_INSN_CF_MAC | M68K_INSN_CF_EMAC | M68K_INSN_CF_FPU},    {NULL, 0}, };typedef void (*disas_proc)(DisasContext *, uint16_t);#define DISAS_INSN(name) \  static void disas_##name (DisasContext *s, uint16_t insn)/* Generate a load from the specified address.  Narrow values are   sign extended to full register width.  */static inline int gen_load(int opsize, int addr, int sign){    int tmp;    switch(opsize) {    case OS_BYTE:        tmp = gen_new_qreg(QMODE_I32);        if (sign)            gen_op_ld8s32(tmp, addr);        else            gen_op_ld8u32(tmp, addr);        break;    case OS_WORD:        tmp = gen_new_qreg(QMODE_I32);        if (sign)            gen_op_ld16s32(tmp, addr);        else            gen_op_ld16u32(tmp, addr);        break;    case OS_LONG:        tmp = gen_new_qreg(QMODE_I32);        gen_op_ld32(tmp, addr);        break;    case OS_SINGLE:        tmp = gen_new_qreg(QMODE_F32);        gen_op_ldf32(tmp, addr);        break;    case OS_DOUBLE:        tmp  = gen_new_qreg(QMODE_F64);        gen_op_ldf64(tmp, addr);        break;    default:        qemu_assert(0, "bad load size");    }    gen_throws_exception = gen_last_qop;    return tmp;}/* Generate a store.  */static inline void gen_store(int opsize, int addr, int val){    switch(opsize) {    case OS_BYTE:        gen_op_st8(addr, val);        break;    case OS_WORD:        gen_op_st16(addr, val);        break;    case OS_LONG:        gen_op_st32(addr, val);        break;    case OS_SINGLE:        gen_op_stf32(addr, val);        break;    case OS_DOUBLE:        gen_op_stf64(addr, val);        break;    default:        qemu_assert(0, "bad store size");    }    gen_throws_exception = gen_last_qop;}/* Generate an unsigned load if VAL is 0 a signed load if val is -1,   otherwise generate a store.  */static int gen_ldst(int opsize, int addr, int val){    if (val > 0) {        gen_store(opsize, addr, val);        return 0;    } else {        return gen_load(opsize, addr, val != 0);    }}/* Handle a base + index + displacement effective addresss.  A base of   -1 means pc-relative.  */static int gen_lea_indexed(DisasContext *s, int opsize, int base){    int scale;    uint32_t offset;    uint16_t ext;    int add;    int tmp;    offset = s->pc;    ext = lduw(s->pc);    s->pc += 2;    tmp = ((ext >> 12) & 7) + ((ext & 0x8000) ? QREG_A0 : QREG_D0);    /* ??? Check W/L bit.  */    scale = (ext >> 9) & 3;    if (scale == 0) {        add = tmp;    } else {        add = gen_new_qreg(QMODE_I32);        gen_op_shl32(add, tmp, gen_im32(scale));    }    tmp = gen_new_qreg(QMODE_I32);    if (base != -1) {        gen_op_add32(tmp, base, gen_im32((int8_t)ext));        gen_op_add32(tmp, tmp, add);    } else {        gen_op_add32(tmp, add, gen_im32(offset + (int8_t)ext));    }    return tmp;}/* Read a 32-bit immediate constant.  */static inline uint32_t read_im32(DisasContext *s){    uint32_t im;    im = ((uint32_t)lduw(s->pc)) << 16;    s->pc += 2;    im |= lduw(s->pc);    s->pc += 2;    return im;}/* Update the CPU env CC_OP state.  */static inline void gen_flush_cc_op(DisasContext *s){    if (s->cc_op != CC_OP_DYNAMIC)        gen_op_mov32(QREG_CC_OP, gen_im32(s->cc_op));}/* Evaluate all the CC flags.  */static inline void gen_flush_flags(DisasContext *s){    if (s->cc_op == CC_OP_FLAGS)        return;    gen_op_flush_flags(s->cc_op);    s->cc_op = CC_OP_FLAGS;}static inline int opsize_bytes(int opsize){    switch (opsize) {    case OS_BYTE: return 1;    case OS_WORD: return 2;    case OS_LONG: return 4;    case OS_SINGLE: return 4;    case OS_DOUBLE: return 8;    default:        qemu_assert(0, "bad operand size");    }}/* Assign value to a register.  If the width is less than the register width   only the low part of the register is set.  */static void gen_partset_reg(int opsize, int reg, int val){    int tmp;    switch (opsize) {    case OS_BYTE:        gen_op_and32(reg, reg, gen_im32(0xffffff00));        tmp = gen_new_qreg(QMODE_I32);        gen_op_and32(tmp, val, gen_im32(0xff));        gen_op_or32(reg, reg, tmp);        break;    case OS_WORD:        gen_op_and32(reg, reg, gen_im32(0xffff0000));        tmp = gen_new_qreg(QMODE_I32);        gen_op_and32(tmp, val, gen_im32(0xffff));        gen_op_or32(reg, reg, tmp);        break;    case OS_LONG:        gen_op_mov32(reg, val);        break;    case OS_SINGLE:        gen_op_pack_32_f32(reg, val);        break;    default:        qemu_assert(0, "Bad operand size");        break;    }}/* Sign or zero extend a value.  */static inline int gen_extend(int val, int opsize, int sign){    int tmp;    switch (opsize) {    case OS_BYTE:        tmp = gen_new_qreg(QMODE_I32);        if (sign)            gen_op_ext8s32(tmp, val);        else            gen_op_ext8u32(tmp, val);        break;    case OS_WORD:        tmp = gen_new_qreg(QMODE_I32);        if (sign)            gen_op_ext16s32(tmp, val);        else            gen_op_ext16u32(tmp, val);        break;    case OS_LONG:        tmp = val;        break;    case OS_SINGLE:        tmp = gen_new_qreg(QMODE_F32);        gen_op_pack_f32_32(tmp, val);        break;    default:        qemu_assert(0, "Bad operand size");    }    return tmp;}/* Generate code for an "effective address".  Does not adjust the base   register for autoincrememnt addressing modes.  */static int gen_lea(DisasContext *s, uint16_t insn, int opsize){    int reg;    int tmp;    uint16_t ext;    uint32_t offset;    reg = insn & 7;    switch ((insn >> 3) & 7) {    case 0: /* Data register direct.  */    case 1: /* Address register direct.  */        /* ??? generate bad addressing mode fault.  */        qemu_assert(0, "invalid addressing mode");    case 2: /* Indirect register */    case 3: /* Indirect postincrement.  */        reg += QREG_A0;        return reg;    case 4: /* Indirect predecrememnt.  */        reg += QREG_A0;        tmp = gen_new_qreg(QMODE_I32);        gen_op_sub32(tmp, reg, gen_im32(opsize_bytes(opsize)));        return tmp;    case 5: /* Indirect displacement.  */        reg += QREG_A0;        tmp = gen_new_qreg(QMODE_I32);        ext = lduw(s->pc);        s->pc += 2;        gen_op_add32(tmp, reg, gen_im32((int16_t)ext));        return tmp;    case 6: /* Indirect index + displacement.  */        reg += QREG_A0;        return gen_lea_indexed(s, opsize, reg);    case 7: /* Other */        switch (reg) {        case 0: /* Absolute short.  */            offset = ldsw(s->pc);            s->pc += 2;            return gen_im32(offset);        case 1: /* Absolute long.  */            offset = read_im32(s);            return gen_im32(offset);        case 2: /* pc displacement  */            tmp = gen_new_qreg(QMODE_I32);            offset = s->pc;            offset += ldsw(s->pc);            s->pc += 2;            return gen_im32(offset);        case 3: /* pc index+displacement.  */            return gen_lea_indexed(s, opsize, -1);        case 4: /* Immediate.  */        default:            /* ??? generate bad addressing mode fault.  */            qemu_assert(0, "invalid addressing mode");        }    }    /* Should never happen.  */    return -1;}/* Helper function for gen_ea. Reuse the computed address between the   for read/write operands.  */static inline int gen_ea_once(DisasContext *s, uint16_t insn, int opsize,                              int val, int *addrp){    int tmp;    if (addrp && val > 0) {        tmp = *addrp;    } else {        tmp = gen_lea(s, insn, opsize);        if (addrp)            *addrp = tmp;    }    return gen_ldst(opsize, tmp, val);}/* Generate code to load/store a value ito/from an EA.  If VAL > 0 this is   a write otherwise it is a read (0 == sign extend, -1 == zero extend).   ADDRP is non-null for readwrite operands.  */static int gen_ea(DisasContext *s, uint16_t insn, int opsize, int val,                  int *addrp){    int reg;    int result;    uint32_t offset;    reg = insn & 7;    switch ((insn >> 3) & 7) {    case 0: /* Data register direct.  */        reg += QREG_D0;        if (val > 0) {            gen_partset_reg(opsize, reg, val);            return 0;        } else {            return gen_extend(reg, opsize, val);        }    case 1: /* Address register direct.  */        reg += QREG_A0;        if (val > 0) {            gen_op_mov32(reg, val);            return 0;        } else {            return gen_extend(reg, opsize, val);        }    case 2: /* Indirect register */        reg += QREG_A0;        return gen_ldst(opsize, reg, val);    case 3: /* Indirect postincrement.  */        reg += QREG_A0;        result = gen_ldst(opsize, reg, val);        /* ??? This is not exception safe.  The instruction may still           fault after this point.  */        if (val > 0 || !addrp)            gen_op_add32(reg, reg, gen_im32(opsize_bytes(opsize)));        return result;    case 4: /* Indirect predecrememnt.  */        {            int tmp;            if (addrp && val > 0) {                tmp = *addrp;            } else {                tmp = gen_lea(s, insn, opsize);                if (addrp)                    *addrp = tmp;            }            result = gen_ldst(opsize, tmp, val);            /* ??? This is not exception safe.  The instruction may still               fault after this point.  */            if (val > 0 || !addrp) {                reg += QREG_A0;                gen_op_mov32(reg, tmp);            }        }        return result;    case 5: /* Indirect displacement.  */    case 6: /* Indirect index + displacement.  */        return gen_ea_once(s, insn, opsize, val, addrp);    case 7: /* Other */        switch (reg) {        case 0: /* Absolute short.  */        case 1: /* Absolute long.  */        case 2: /* pc displacement  */        case 3: /* pc index+displacement.  */            return gen_ea_once(s, insn, opsize, val, addrp);        case 4: /* Immediate.  */            /* Sign extend values for consistency.  */            switch (opsize) {            case OS_BYTE:                if (val)                    offset = ldsb(s->pc + 1);                else                    offset = ldub(s->pc + 1);                s->pc += 2;                break;            case OS_WORD:                if (val)                    offset = ldsw(s->pc);                else                    offset = lduw(s->pc);                s->pc += 2;                break;            case OS_LONG:                offset = read_im32(s);                break;            default:                qemu_assert(0, "Bad immediate operand");            }            return gen_im32(offset);        default:            qemu_assert(0, "invalid addressing mode");        }    }    /* Should never happen.  */    return -1;}static void gen_logic_cc(DisasContext *s, int val){    gen_op_logic_cc(val);    s->cc_op = CC_OP_LOGIC;}static void gen_jmpcc(DisasContext *s, int cond, int l1){    int tmp;    gen_flush_flags(s);    switch (cond) {    case 0: /* T */        gen_op_jmp(l1);        break;    case 1: /* F */        break;    case 2: /* HI (!C && !Z) */        tmp = gen_new_qreg(QMODE_I32);        gen_op_and32(tmp, QREG_CC_DEST, gen_im32(CCF_C | CCF_Z));        gen_op_jmp_z32(tmp, l1);        break;    case 3: /* LS (C || Z) */        tmp = gen_new_qreg(QMODE_I32);        gen_op_and32(tmp, QREG_CC_DEST, gen_im32(CCF_C | CCF_Z));        gen_op_jmp_nz32(tmp, l1);        break;    case 4: /* CC (!C) */        tmp = gen_new_qreg(QMODE_I32);        gen_op_and32(tmp, QREG_CC_DEST, gen_im32(CCF_C));        gen_op_jmp_z32(tmp, l1);        break;    case 5: /* CS (C) */        tmp = gen_new_qreg(QMODE_I32);        gen_op_and32(tmp, QREG_CC_DEST, gen_im32(CCF_C));

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -