translate.c
来自「xen虚拟机源代码安装包」· C语言 代码 · 共 2,711 行 · 第 1/5 页
C
2,711 行
/* * CRIS emulation for qemu: main translation routines. * * Copyright (c) 2008 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 *//* * FIXME: * The condition code translation is in need of attention. */#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 "tcg-op.h"#include "helper.h"#include "crisv32-decode.h"#include "qemu-common.h"#define DISAS_CRIS 0#if DISAS_CRIS#define DIS(x) x#else#define DIS(x)#endif#define D(x)#define BUG() (gen_BUG(dc, __FILE__, __LINE__))#define BUG_ON(x) ({if (x) BUG();})#define DISAS_SWI 5/* 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 0x10eTCGv cpu_env;TCGv cpu_T[2];TCGv cpu_R[16];TCGv cpu_PR[16];TCGv cc_src;TCGv cc_dest;TCGv cc_result;TCGv cc_op;TCGv cc_size;TCGv cc_mask;TCGv env_btarget;TCGv env_pc;/* This is the state at translation time. */typedef struct DisasContext { CPUState *env; target_ulong pc, ppc; /* Decoder. */ uint32_t ir; uint32_t opcode; unsigned int op1; unsigned int op2; unsigned int zsize, zzsize; unsigned int mode; unsigned int postinc; int update_cc; int cc_op; int cc_size; uint32_t cc_mask; int flags_live; /* Wether or not $ccs is uptodate. */ int flagx_live; /* Wether or not flags_x has the x flag known at translation time. */ int flags_x; int clear_x; /* Clear x after this insn? */ int user; /* user or kernel mode. */ int is_jmp; int delayed_branch; struct TranslationBlock *tb; int singlestep_enabled;} DisasContext;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_abort(dc->env, "%s:%d\n", file, line);}const char *regnames[] ={ "$r0", "$r1", "$r2", "$r3", "$r4", "$r5", "$r6", "$r7", "$r8", "$r9", "$r10", "$r11", "$r12", "$r13", "$sp", "$acr",};const char *pregnames[] ={ "$bz", "$vr", "$pid", "$srs", "$wz", "$exs", "$eda", "$mof", "$dz", "$ebp", "$erp", "$srp", "$nrp", "$ccs", "$usp", "$spc",};/* We need this table to handle preg-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,};#define t_gen_mov_TN_env(tn, member) \ _t_gen_mov_TN_env((tn), offsetof(CPUState, member))#define t_gen_mov_env_TN(member, tn) \ _t_gen_mov_env_TN(offsetof(CPUState, member), (tn))static inline void t_gen_mov_TN_reg(TCGv tn, int r){ if (r < 0 || r > 15) fprintf(stderr, "wrong register read $r%d\n", r); tcg_gen_mov_tl(tn, cpu_R[r]);}static inline void t_gen_mov_reg_TN(int r, TCGv tn){ if (r < 0 || r > 15) fprintf(stderr, "wrong register write $r%d\n", r); tcg_gen_mov_tl(cpu_R[r], tn);}static inline void _t_gen_mov_TN_env(TCGv tn, int offset){ if (offset > sizeof (CPUState)) fprintf(stderr, "wrong load from env from off=%d\n", offset); tcg_gen_ld_tl(tn, cpu_env, offset);}static inline void _t_gen_mov_env_TN(int offset, TCGv tn){ if (offset > sizeof (CPUState)) fprintf(stderr, "wrong store to env at off=%d\n", offset); tcg_gen_st_tl(tn, cpu_env, offset);}static inline void t_gen_mov_TN_preg(TCGv tn, int r){ if (r < 0 || r > 15) fprintf(stderr, "wrong register read $p%d\n", r); if (r == PR_BZ || r == PR_WZ || r == PR_DZ) tcg_gen_mov_tl(tn, tcg_const_tl(0)); else if (r == PR_VR) tcg_gen_mov_tl(tn, tcg_const_tl(32)); else if (r == PR_EXS) { printf("read from EXS!\n"); tcg_gen_mov_tl(tn, cpu_PR[r]); } else if (r == PR_EDA) { printf("read from EDA!\n"); tcg_gen_mov_tl(tn, cpu_PR[r]); } else tcg_gen_mov_tl(tn, cpu_PR[r]);}static inline void t_gen_mov_preg_TN(DisasContext *dc, int r, TCGv tn){ if (r < 0 || r > 15) fprintf(stderr, "wrong register write $p%d\n", r); if (r == PR_BZ || r == PR_WZ || r == PR_DZ) return; else if (r == PR_SRS) tcg_gen_andi_tl(cpu_PR[r], tn, 3); else { tcg_gen_mov_tl(cpu_PR[r], tn); if (r == PR_PID) tcg_gen_helper_0_1(helper_tlb_flush_pid, tn); }}static inline void t_gen_raise_exception(uint32_t index){ tcg_gen_helper_0_1(helper_raise_exception, tcg_const_tl(index));}static void t_gen_lsl(TCGv d, TCGv a, TCGv b){ int l1; l1 = gen_new_label(); /* Speculative shift. */ tcg_gen_shl_tl(d, a, b); tcg_gen_brcond_tl(TCG_COND_LEU, b, tcg_const_tl(31), l1); /* Clear dst if shift operands were to large. */ tcg_gen_movi_tl(d, 0); gen_set_label(l1);}static void t_gen_lsr(TCGv d, TCGv a, TCGv b){ int l1; l1 = gen_new_label(); /* Speculative shift. */ tcg_gen_shr_tl(d, a, b); tcg_gen_brcond_tl(TCG_COND_LEU, b, tcg_const_tl(31), l1); /* Clear dst if shift operands were to large. */ tcg_gen_movi_tl(d, 0); gen_set_label(l1);}static void t_gen_asr(TCGv d, TCGv a, TCGv b){ int l1; l1 = gen_new_label(); /* Speculative shift. */ tcg_gen_sar_tl(d, a, b); tcg_gen_brcond_tl(TCG_COND_LEU, b, tcg_const_tl(31), l1); /* Clear dst if shift operands were to large. */ tcg_gen_sar_tl(d, a, tcg_const_tl(30)); gen_set_label(l1);}/* 64-bit signed mul, lower result in d and upper in d2. */static void t_gen_muls(TCGv d, TCGv d2, TCGv a, TCGv b){ TCGv t0, t1; t0 = tcg_temp_new(TCG_TYPE_I64); t1 = tcg_temp_new(TCG_TYPE_I64); tcg_gen_ext32s_i64(t0, a); tcg_gen_ext32s_i64(t1, b); tcg_gen_mul_i64(t0, t0, t1); tcg_gen_trunc_i64_i32(d, t0); tcg_gen_shri_i64(t0, t0, 32); tcg_gen_trunc_i64_i32(d2, t0); tcg_gen_discard_i64(t0); tcg_gen_discard_i64(t1);}/* 64-bit unsigned muls, lower result in d and upper in d2. */static void t_gen_mulu(TCGv d, TCGv d2, TCGv a, TCGv b){ TCGv t0, t1; t0 = tcg_temp_new(TCG_TYPE_I64); t1 = tcg_temp_new(TCG_TYPE_I64); tcg_gen_extu_i32_i64(t0, a); tcg_gen_extu_i32_i64(t1, b); tcg_gen_mul_i64(t0, t0, t1); tcg_gen_trunc_i64_i32(d, t0); tcg_gen_shri_i64(t0, t0, 32); tcg_gen_trunc_i64_i32(d2, t0); tcg_gen_discard_i64(t0); tcg_gen_discard_i64(t1);}/* 32bit branch-free binary search for counting leading zeros. */static void t_gen_lz_i32(TCGv d, TCGv x){ TCGv y, m, n; y = tcg_temp_new(TCG_TYPE_I32); m = tcg_temp_new(TCG_TYPE_I32); n = tcg_temp_new(TCG_TYPE_I32); /* y = -(x >> 16) */ tcg_gen_shri_i32(y, x, 16); tcg_gen_neg_i32(y, y); /* m = (y >> 16) & 16 */ tcg_gen_sari_i32(m, y, 16); tcg_gen_andi_i32(m, m, 16); /* n = 16 - m */ tcg_gen_sub_i32(n, tcg_const_i32(16), m); /* x = x >> m */ tcg_gen_shr_i32(x, x, m); /* y = x - 0x100 */ tcg_gen_subi_i32(y, x, 0x100); /* m = (y >> 16) & 8 */ tcg_gen_sari_i32(m, y, 16); tcg_gen_andi_i32(m, m, 8); /* n = n + m */ tcg_gen_add_i32(n, n, m); /* x = x << m */ tcg_gen_shl_i32(x, x, m); /* y = x - 0x1000 */ tcg_gen_subi_i32(y, x, 0x1000); /* m = (y >> 16) & 4 */ tcg_gen_sari_i32(m, y, 16); tcg_gen_andi_i32(m, m, 4); /* n = n + m */ tcg_gen_add_i32(n, n, m); /* x = x << m */ tcg_gen_shl_i32(x, x, m); /* y = x - 0x4000 */ tcg_gen_subi_i32(y, x, 0x4000); /* m = (y >> 16) & 2 */ tcg_gen_sari_i32(m, y, 16); tcg_gen_andi_i32(m, m, 2); /* n = n + m */ tcg_gen_add_i32(n, n, m); /* x = x << m */ tcg_gen_shl_i32(x, x, m); /* y = x >> 14 */ tcg_gen_shri_i32(y, x, 14); /* m = y & ~(y >> 1) */ tcg_gen_sari_i32(m, y, 1); tcg_gen_xori_i32(m, m, 0xffffffff); tcg_gen_and_i32(m, m, y); /* d = n + 2 - m */ tcg_gen_addi_i32(d, n, 2); tcg_gen_sub_i32(d, d, m); tcg_gen_discard_i32(y); tcg_gen_discard_i32(m); tcg_gen_discard_i32(n);}static void t_gen_btst(TCGv d, TCGv s){ TCGv sbit; TCGv bset; int l1; /* des ref: The N flag is set according to the selected bit in the dest reg. The Z flag is set if the selected bit and all bits to the right are zero. The X flag is cleared. Other flags are left untouched. The destination reg is not affected. unsigned int fz, sbit, bset, mask, masked_t0; sbit = T1 & 31; bset = !!(T0 & (1 << sbit)); mask = sbit == 31 ? -1 : (1 << (sbit + 1)) - 1; masked_t0 = T0 & mask; fz = !(masked_t0 | bset); // Clear the X, N and Z flags. T0 = env->pregs[PR_CCS] & ~(X_FLAG | N_FLAG | Z_FLAG); // Set the N and Z flags accordingly. T0 |= (bset << 3) | (fz << 2); */ l1 = gen_new_label(); sbit = tcg_temp_new(TCG_TYPE_TL); bset = tcg_temp_new(TCG_TYPE_TL); /* Compute bset and sbit. */ tcg_gen_andi_tl(sbit, s, 31); tcg_gen_shl_tl(s, tcg_const_tl(1), sbit); tcg_gen_and_tl(bset, d, s); tcg_gen_shr_tl(bset, bset, sbit); /* Displace to N_FLAG. */ tcg_gen_shli_tl(bset, bset, 3); tcg_gen_shl_tl(sbit, tcg_const_tl(2), sbit); tcg_gen_subi_tl(sbit, sbit, 1); tcg_gen_and_tl(sbit, d, sbit); tcg_gen_andi_tl(d, cpu_PR[PR_CCS], ~(X_FLAG | N_FLAG | Z_FLAG)); /* or in the N_FLAG. */ tcg_gen_or_tl(d, d, bset); tcg_gen_brcond_tl(TCG_COND_NE, sbit, tcg_const_tl(0), l1); /* or in the Z_FLAG. */ tcg_gen_ori_tl(d, d, Z_FLAG); gen_set_label(l1); tcg_gen_discard_tl(sbit); tcg_gen_discard_tl(bset);}static void t_gen_cris_dstep(TCGv d, TCGv s){ int l1; l1 = gen_new_label(); /* * d <<= 1 * if (d >= s) * d -= s; */ tcg_gen_shli_tl(d, d, 1); tcg_gen_brcond_tl(TCG_COND_LTU, d, s, l1); tcg_gen_sub_tl(d, d, s); gen_set_label(l1);}/* Extended arithmetics on CRIS. */static inline void t_gen_add_flag(TCGv d, int flag){ TCGv c; c = tcg_temp_new(TCG_TYPE_TL); t_gen_mov_TN_preg(c, PR_CCS); /* Propagate carry into d. */ tcg_gen_andi_tl(c, c, 1 << flag); if (flag) tcg_gen_shri_tl(c, c, flag); tcg_gen_add_tl(d, d, c); tcg_gen_discard_tl(c);}static inline void t_gen_addx_carry(TCGv d){ TCGv x, c; x = tcg_temp_new(TCG_TYPE_TL); c = tcg_temp_new(TCG_TYPE_TL); t_gen_mov_TN_preg(x, PR_CCS); tcg_gen_mov_tl(c, x); /* Propagate carry into d if X is set. Branch free. */ tcg_gen_andi_tl(c, c, C_FLAG); tcg_gen_andi_tl(x, x, X_FLAG); tcg_gen_shri_tl(x, x, 4); tcg_gen_and_tl(x, x, c); tcg_gen_add_tl(d, d, x); tcg_gen_discard_tl(x); tcg_gen_discard_tl(c);}static inline void t_gen_subx_carry(DisasContext *dc, TCGv d){ if (dc->flagx_live) { TCGv x, c; x = tcg_temp_new(TCG_TYPE_TL); c = tcg_temp_new(TCG_TYPE_TL); t_gen_mov_TN_preg(x, PR_CCS); tcg_gen_mov_tl(c, x); /* Propagate carry into d if X is set. Branch free. */ tcg_gen_andi_tl(c, c, C_FLAG); tcg_gen_andi_tl(x, x, X_FLAG); tcg_gen_shri_tl(x, x, 4); tcg_gen_and_tl(x, x, c); tcg_gen_sub_tl(d, d, x); tcg_gen_discard_tl(x); tcg_gen_discard_tl(c); } else { if (dc->flags_x) { TCGv c; c = tcg_temp_new(TCG_TYPE_TL); /* C flag is already at bit 0. */ tcg_gen_andi_tl(c, c, C_FLAG); tcg_gen_add_tl(d, d, c); tcg_gen_discard_tl(c); } }}/* Swap the two bytes within each half word of the s operand. T0 = ((T0 << 8) & 0xff00ff00) | ((T0 >> 8) & 0x00ff00ff) */static inline void t_gen_swapb(TCGv d, TCGv s){ TCGv t, org_s; t = tcg_temp_new(TCG_TYPE_TL); org_s = tcg_temp_new(TCG_TYPE_TL); /* d and s may refer to the same object. */ tcg_gen_mov_tl(org_s, s); tcg_gen_shli_tl(t, org_s, 8); tcg_gen_andi_tl(d, t, 0xff00ff00); tcg_gen_shri_tl(t, org_s, 8); tcg_gen_andi_tl(t, t, 0x00ff00ff); tcg_gen_or_tl(d, d, t); tcg_gen_discard_tl(t); tcg_gen_discard_tl(org_s);}/* Swap the halfwords of the s operand. */static inline void t_gen_swapw(TCGv d, TCGv s){ TCGv t; /* d and s refer the same object. */ t = tcg_temp_new(TCG_TYPE_TL); tcg_gen_mov_tl(t, s); tcg_gen_shli_tl(d, t, 16); tcg_gen_shri_tl(t, t, 16); tcg_gen_or_tl(d, d, t); tcg_gen_discard_tl(t);}/* Reverse the within each byte. T0 = (((T0 << 7) & 0x80808080) | ((T0 << 5) & 0x40404040) | ((T0 << 3) & 0x20202020) | ((T0 << 1) & 0x10101010) | ((T0 >> 1) & 0x08080808) | ((T0 >> 3) & 0x04040404) | ((T0 >> 5) & 0x02020202) | ((T0 >> 7) & 0x01010101));
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?