📄 translate.c.svn-base
字号:
/* * CRIS emulation for qemu: main translation routines. * * Copyright (c) 2007 AXIS Communications AB * Written by Edgar E. Iglesias. * * 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 *//* * This file implements a CRIS decoder-stage in SW. The decoder translates the * guest (CRIS) machine-code into host machine code via dyngen using the * micro-operations described in op.c * * The micro-operations for CRIS translation implement a RISC style ISA. * Note that the micro-operations typically order their operands * starting with the dst. CRIS asm, does the opposite. * * For example the following CRIS code: * add.d [$r0], $r1 * * translates into: * * gen_movl_T0_reg(0); // Fetch $r0 into T0 * gen_load_T0_T0(); // Load T0, @T0 * gen_movl_reg_T0(1); // Writeback T0 into $r1 * * The actual names for the micro-code generators vary but the example * illustrates the point. */#include <stdarg.h>#include <stdlib.h>#include <stdio.h>#include <string.h>#include <inttypes.h>#include <assert.h>#include "cpu.h"#include "exec-all.h"#include "disas.h"#include "crisv32-decode.h"#define CRIS_STATS 0#if CRIS_STATS#define STATS(x) x#else#define STATS(x)#endif#define DISAS_CRIS 0#if DISAS_CRIS#define DIS(x) x#else#define DIS(x)#endif#ifdef USE_DIRECT_JUMP#define TBPARAM(x)#else#define TBPARAM(x) (long)(x)#endif#define BUG() (gen_BUG(dc, __FILE__, __LINE__))#define BUG_ON(x) ({if (x) BUG();})/* Used by the decoder. */#define EXTRACT_FIELD(src, start, end) \ (((src) >> start) & ((1 << (end - start + 1)) - 1))#define CC_MASK_NZ 0xc#define CC_MASK_NZV 0xe#define CC_MASK_NZVC 0xf#define CC_MASK_RNZV 0x10estatic uint16_t *gen_opc_ptr;static uint32_t *gen_opparam_ptr;enum {#define DEF(s, n, copy_size) INDEX_op_ ## s,#include "opc.h"#undef DEF NB_OPS,};#include "gen-op.h"/* This is the state at translation time. */typedef struct DisasContext { CPUState *env; target_ulong pc, insn_pc; /* Decoder. */ uint32_t ir; uint32_t opcode; unsigned int op1; unsigned int op2; unsigned int zsize, zzsize; unsigned int mode; unsigned int postinc; struct { int op; int size; unsigned int mask; } cc_state[3]; int cc_i; int update_cc; int cc_op; int cc_size; uint32_t cc_mask; int flags_live; int flagx_live; int flags_x; uint32_t tb_entry_flags; int memidx; /* user or kernel mode. */ int is_jmp; int dyn_jmp; uint32_t delayed_pc; int delayed_branch; int bcc; uint32_t condlabel; struct TranslationBlock *tb; int singlestep_enabled;} DisasContext;void cris_prepare_jmp (DisasContext *dc, uint32_t dst);static void gen_BUG(DisasContext *dc, char *file, int line){ printf ("BUG: pc=%x %s %d\n", dc->pc, file, line); fprintf (logfile, "BUG: pc=%x %s %d\n", dc->pc, file, line); cpu_dump_state (dc->env, stdout, fprintf, 0); fflush(NULL); cris_prepare_jmp (dc, 0x70000000 + line);}/* Table to generate quick moves from T0 onto any register. */static GenOpFunc *gen_movl_reg_T0[16] ={ gen_op_movl_r0_T0, gen_op_movl_r1_T0, gen_op_movl_r2_T0, gen_op_movl_r3_T0, gen_op_movl_r4_T0, gen_op_movl_r5_T0, gen_op_movl_r6_T0, gen_op_movl_r7_T0, gen_op_movl_r8_T0, gen_op_movl_r9_T0, gen_op_movl_r10_T0, gen_op_movl_r11_T0, gen_op_movl_r12_T0, gen_op_movl_r13_T0, gen_op_movl_r14_T0, gen_op_movl_r15_T0,};static GenOpFunc *gen_movl_T0_reg[16] ={ gen_op_movl_T0_r0, gen_op_movl_T0_r1, gen_op_movl_T0_r2, gen_op_movl_T0_r3, gen_op_movl_T0_r4, gen_op_movl_T0_r5, gen_op_movl_T0_r6, gen_op_movl_T0_r7, gen_op_movl_T0_r8, gen_op_movl_T0_r9, gen_op_movl_T0_r10, gen_op_movl_T0_r11, gen_op_movl_T0_r12, gen_op_movl_T0_r13, gen_op_movl_T0_r14, gen_op_movl_T0_r15,};static void noop_write(void) { /* nop. */}static void gen_vr_read(void) { gen_op_movl_T0_im(32);}static void gen_ccs_read(void) { gen_op_movl_T0_p13();}static void gen_ccs_write(void) { gen_op_movl_p13_T0();}/* Table to generate quick moves from T0 onto any register. */static GenOpFunc *gen_movl_preg_T0[16] ={ noop_write, /* bz, not writeable. */ noop_write, /* vr, not writeable. */ gen_op_movl_p2_T0, gen_op_movl_p3_T0, noop_write, /* wz, not writeable. */ gen_op_movl_p5_T0, gen_op_movl_p6_T0, gen_op_movl_p7_T0, noop_write, /* dz, not writeable. */ gen_op_movl_p9_T0, gen_op_movl_p10_T0, gen_op_movl_p11_T0, gen_op_movl_p12_T0, gen_ccs_write, /* ccs needs special treatment. */ gen_op_movl_p14_T0, gen_op_movl_p15_T0,};static GenOpFunc *gen_movl_T0_preg[16] ={ gen_op_movl_T0_p0, gen_vr_read, gen_op_movl_T0_p2, gen_op_movl_T0_p3, gen_op_movl_T0_p4, gen_op_movl_T0_p5, gen_op_movl_T0_p6, gen_op_movl_T0_p7, gen_op_movl_T0_p8, gen_op_movl_T0_p9, gen_op_movl_T0_p10, gen_op_movl_T0_p11, gen_op_movl_T0_p12, gen_ccs_read, /* ccs needs special treatment. */ gen_op_movl_T0_p14, gen_op_movl_T0_p15,};/* We need this table to handle moves with implicit width. */int preg_sizes[] = { 1, /* bz. */ 1, /* vr. */ 4, /* pid. */ 1, /* srs. */ 2, /* wz. */ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,};#ifdef CONFIG_USER_ONLY#define GEN_OP_LD(width, reg) \ void gen_op_ld##width##_T0_##reg (DisasContext *dc) { \ gen_op_ld##width##_T0_##reg##_raw(); \ }#define GEN_OP_ST(width, reg) \ void gen_op_st##width##_##reg##_T1 (DisasContext *dc) { \ gen_op_st##width##_##reg##_T1_raw(); \ }#else#define GEN_OP_LD(width, reg) \ void gen_op_ld##width##_T0_##reg (DisasContext *dc) { \ if (dc->memidx) gen_op_ld##width##_T0_##reg##_kernel(); \ else gen_op_ld##width##_T0_##reg##_user();\ }#define GEN_OP_ST(width, reg) \ void gen_op_st##width##_##reg##_T1 (DisasContext *dc) { \ if (dc->memidx) gen_op_st##width##_##reg##_T1_kernel(); \ else gen_op_st##width##_##reg##_T1_user();\ }#endifGEN_OP_LD(ub, T0)GEN_OP_LD(b, T0)GEN_OP_ST(b, T0)GEN_OP_LD(uw, T0)GEN_OP_LD(w, T0)GEN_OP_ST(w, T0)GEN_OP_LD(l, T0)GEN_OP_ST(l, T0)static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest){ TranslationBlock *tb; tb = dc->tb; if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) { if (n == 0) gen_op_goto_tb0(TBPARAM(tb)); else gen_op_goto_tb1(TBPARAM(tb)); gen_op_movl_T0_0(); } else { gen_op_movl_T0_0(); } gen_op_exit_tb();}/* Sign extend at translation time. */static int sign_extend(unsigned int val, unsigned int width){ int sval; /* LSL. */ val <<= 31 - width; sval = val; /* ASR. */ sval >>= 31 - width; return sval;}static void cris_evaluate_flags(DisasContext *dc){ if (!dc->flags_live) { switch (dc->cc_op) { case CC_OP_MCP: gen_op_evaluate_flags_mcp (); break; case CC_OP_MULS: gen_op_evaluate_flags_muls (); break; case CC_OP_MULU: gen_op_evaluate_flags_mulu (); break; case CC_OP_MOVE: switch (dc->cc_size) { case 4: gen_op_evaluate_flags_move_4(); break; case 2: gen_op_evaluate_flags_move_2(); break; default: gen_op_evaluate_flags (); break; } break; default: { switch (dc->cc_size) { case 4: gen_op_evaluate_flags_alu_4 (); break; default: gen_op_evaluate_flags (); break; } } break; } dc->flags_live = 1; }}static void cris_cc_mask(DisasContext *dc, unsigned int mask){ uint32_t ovl; ovl = (dc->cc_mask ^ mask) & ~mask; if (ovl) { /* TODO: optimize this case. It trigs all the time. */ cris_evaluate_flags (dc); } dc->cc_mask = mask; dc->update_cc = 1; if (mask == 0) dc->update_cc = 0; else { gen_op_update_cc_mask(mask); dc->flags_live = 0; }}static void cris_update_cc_op(DisasContext *dc, int op){ dc->cc_op = op; gen_op_update_cc_op(op); dc->flags_live = 0;}static void cris_update_cc_size(DisasContext *dc, int size){ dc->cc_size = size; gen_op_update_cc_size_im(size);}/* op is the operation. T0, T1 are the operands. dst is the destination reg.*/static void crisv32_alu_op(DisasContext *dc, int op, int rd, int size){ int writeback = 1; if (dc->update_cc) { cris_update_cc_op(dc, op); cris_update_cc_size(dc, size); gen_op_update_cc_x(dc->flagx_live, dc->flags_x); gen_op_update_cc_dest_T0(); } /* Emit the ALU insns. */ switch (op) { case CC_OP_ADD: gen_op_addl_T0_T1(); /* Extended arithmetics. */ if (!dc->flagx_live) gen_op_addxl_T0_C(); else if (dc->flags_x) gen_op_addxl_T0_C(); break; case CC_OP_ADDC: gen_op_addl_T0_T1(); gen_op_addl_T0_C(); break; case CC_OP_MCP: gen_op_addl_T0_T1(); gen_op_addl_T0_R(); break; case CC_OP_SUB: gen_op_negl_T1_T1(); gen_op_addl_T0_T1(); /* CRIS flag evaluation needs ~src. */ gen_op_negl_T1_T1(); gen_op_not_T1_T1(); /* Extended arithmetics. */ if (!dc->flagx_live) gen_op_subxl_T0_C(); else if (dc->flags_x) gen_op_subxl_T0_C(); break; case CC_OP_MOVE: gen_op_movl_T0_T1(); break; case CC_OP_OR: gen_op_orl_T0_T1(); break; case CC_OP_AND: gen_op_andl_T0_T1(); break; case CC_OP_XOR: gen_op_xorl_T0_T1(); break; case CC_OP_LSL: gen_op_lsll_T0_T1(); break; case CC_OP_LSR: gen_op_lsrl_T0_T1(); break; case CC_OP_ASR: gen_op_asrl_T0_T1(); break; case CC_OP_NEG: gen_op_negl_T0_T1(); /* Extended arithmetics. */ gen_op_subxl_T0_C(); break; case CC_OP_LZ: gen_op_lz_T0_T1(); break; case CC_OP_BTST: gen_op_btst_T0_T1(); writeback = 0; break; case CC_OP_MULS: gen_op_muls_T0_T1(); break; case CC_OP_MULU: gen_op_mulu_T0_T1(); break; case CC_OP_DSTEP: gen_op_dstep_T0_T1(); break; case CC_OP_BOUND: gen_op_bound_T0_T1(); break; case CC_OP_CMP: gen_op_negl_T1_T1(); gen_op_addl_T0_T1(); /* CRIS flag evaluation needs ~src. */ gen_op_negl_T1_T1(); gen_op_not_T1_T1(); /* Extended arithmetics. */ gen_op_subxl_T0_C(); writeback = 0; break; default: fprintf (logfile, "illegal ALU op.\n"); BUG(); break; } if (dc->update_cc) gen_op_update_cc_src_T1(); if (size == 1) gen_op_andl_T0_im(0xff); else if (size == 2) gen_op_andl_T0_im(0xffff); /* Writeback. */ if (writeback) { if (size == 4) gen_movl_reg_T0[rd](); else { gen_op_movl_T1_T0(); gen_movl_T0_reg[rd](); if (size == 1) gen_op_andl_T0_im(~0xff); else gen_op_andl_T0_im(~0xffff); gen_op_orl_T0_T1(); gen_movl_reg_T0[rd](); gen_op_movl_T0_T1(); } } if (dc->update_cc) gen_op_update_cc_result_T0(); { /* TODO: Optimize this. */ if (!dc->flagx_live) cris_evaluate_flags(dc); }}static int arith_cc(DisasContext *dc){ if (dc->update_cc) { switch (dc->cc_op) { case CC_OP_ADD: return 1; case CC_OP_SUB: return 1; case CC_OP_LSL: return 1; case CC_OP_LSR: return 1; case CC_OP_ASR: return 1; case CC_OP_CMP: return 1; default: return 0; } } return 0;}static void gen_tst_cc (DisasContext *dc, int cond){ int arith_opt; /* TODO: optimize more condition codes. */ arith_opt = arith_cc(dc) && !dc->flags_live; switch (cond) { case CC_EQ: if (arith_opt) gen_op_tst_cc_eq_fast (); else { cris_evaluate_flags(dc); gen_op_tst_cc_eq (); } break; case CC_NE: if (arith_opt) gen_op_tst_cc_ne_fast (); else { cris_evaluate_flags(dc); gen_op_tst_cc_ne (); } break; case CC_CS: cris_evaluate_flags(dc); gen_op_tst_cc_cs (); break; case CC_CC: cris_evaluate_flags(dc); gen_op_tst_cc_cc (); break; case CC_VS: cris_evaluate_flags(dc); gen_op_tst_cc_vs (); break; case CC_VC: cris_evaluate_flags(dc); gen_op_tst_cc_vc (); break; case CC_PL: if (arith_opt) gen_op_tst_cc_pl_fast (); else { cris_evaluate_flags(dc); gen_op_tst_cc_pl (); } break; case CC_MI: if (arith_opt) gen_op_tst_cc_mi_fast (); else { cris_evaluate_flags(dc); gen_op_tst_cc_mi (); } break; case CC_LS: cris_evaluate_flags(dc); gen_op_tst_cc_ls (); break; case CC_HI: cris_evaluate_flags(dc); gen_op_tst_cc_hi (); break; case CC_GE: cris_evaluate_flags(dc); gen_op_tst_cc_ge (); break; case CC_LT: cris_evaluate_flags(dc); gen_op_tst_cc_lt (); break; case CC_GT: cris_evaluate_flags(dc); gen_op_tst_cc_gt (); break; case CC_LE: cris_evaluate_flags(dc); gen_op_tst_cc_le (); break; case CC_P: cris_evaluate_flags(dc); gen_op_tst_cc_p (); break; case CC_A: cris_evaluate_flags(dc); gen_op_movl_T0_im (1); break; default: BUG(); break; };}static void cris_prepare_cc_branch (DisasContext *dc, int offset, int cond)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -