aboutsummaryrefslogtreecommitdiff
path: root/target-cris/translate.c
diff options
context:
space:
mode:
authoredgar_igl <edgar_igl@c046a42c-6fe2-441c-8c8c-71466251a162>2008-05-13 10:59:14 +0000
committeredgar_igl <edgar_igl@c046a42c-6fe2-441c-8c8c-71466251a162>2008-05-13 10:59:14 +0000
commitcf1d97f07480b6197aebc489938b4e1fed78d3e7 (patch)
treed4ae1d25078f714690f5b01761f2bffd5d57f115 /target-cris/translate.c
parent3bd8c5e4f1fdb61a3eb8a4a8b6e5b4cf1156ba76 (diff)
CRIS: Improve TLB management and handle delayslots at page boundaries.
* Dont flush the entire qemu tlb when the $pid changes. Instead we go through the guests TLB and choose entries that need to be flushed. * Add env->dslot and handle delayslots at pageboundaries. * Remove some unused code. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4450 c046a42c-6fe2-441c-8c8c-71466251a162
Diffstat (limited to 'target-cris/translate.c')
-rw-r--r--target-cris/translate.c215
1 files changed, 116 insertions, 99 deletions
diff --git a/target-cris/translate.c b/target-cris/translate.c
index f8440fd7ad..a71991a544 100644
--- a/target-cris/translate.c
+++ b/target-cris/translate.c
@@ -21,8 +21,7 @@
/*
* FIXME:
- * The condition code translation is in desperate need of attention. It's slow
- * and for system simulation it seems buggy. It sucks.
+ * The condition code translation is in need of attention.
*/
#include <stdarg.h>
@@ -40,13 +39,6 @@
#include "crisv32-decode.h"
#include "qemu-common.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
@@ -109,25 +101,18 @@ typedef struct DisasContext {
int user; /* 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);
+ cpu_abort(dc->env, "%s:%d\n", file, line);
}
const char *regnames[] =
@@ -207,7 +192,7 @@ static inline void t_gen_mov_TN_preg(TCGv tn, int r)
else
tcg_gen_mov_tl(tn, cpu_PR[r]);
}
-static inline void t_gen_mov_preg_TN(int r, TCGv tn)
+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);
@@ -216,10 +201,9 @@ static inline void t_gen_mov_preg_TN(int r, TCGv tn)
else if (r == PR_SRS)
tcg_gen_andi_tl(cpu_PR[r], tn, 3);
else {
- if (r == PR_PID) {
- tcg_gen_helper_0_0(helper_tlb_flush);
- }
tcg_gen_mov_tl(cpu_PR[r], tn);
+ if (r == PR_PID)
+ tcg_gen_helper_0_1(helper_tlb_flush_pid, tn);
}
}
@@ -596,7 +580,7 @@ static inline void t_gen_swapr(TCGv d, TCGv s)
tcg_gen_discard_tl(org_s);
}
-static void t_gen_cc_jmp(target_ulong pc_true, target_ulong pc_false)
+static void t_gen_cc_jmp(TCGv pc_true, TCGv pc_false)
{
TCGv btaken;
int l1;
@@ -606,9 +590,9 @@ static void t_gen_cc_jmp(target_ulong pc_true, target_ulong pc_false)
/* Conditional jmp. */
t_gen_mov_TN_env(btaken, btaken);
- tcg_gen_movi_tl(env_pc, pc_false);
+ tcg_gen_mov_tl(env_pc, pc_false);
tcg_gen_brcond_tl(TCG_COND_EQ, btaken, tcg_const_tl(0), l1);
- tcg_gen_movi_tl(env_pc, pc_true);
+ tcg_gen_mov_tl(env_pc, pc_true);
gen_set_label(l1);
tcg_gen_discard_tl(btaken);
@@ -740,10 +724,11 @@ 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, size);
- tcg_gen_mov_tl(cc_dest, cpu_T[0]);
+ if (op != CC_OP_MOVE)
+ tcg_gen_mov_tl(cc_dest, cpu_T[0]);
/* FIXME: This shouldn't be needed. But we don't pass the
- tests without it. Investigate. */
+ tests without it. Investigate. */
t_gen_mov_env_TN(cc_x_live, tcg_const_tl(dc->flagx_live));
t_gen_mov_env_TN(cc_x, tcg_const_tl(dc->flags_x));
}
@@ -812,7 +797,7 @@ static void crisv32_alu_op(DisasContext *dc, int op, int rd, int size)
TCGv mof;
mof = tcg_temp_new(TCG_TYPE_TL);
t_gen_muls(cpu_T[0], mof, cpu_T[0], cpu_T[1]);
- t_gen_mov_preg_TN(PR_MOF, mof);
+ t_gen_mov_preg_TN(dc, PR_MOF, mof);
tcg_gen_discard_tl(mof);
}
break;
@@ -821,7 +806,7 @@ static void crisv32_alu_op(DisasContext *dc, int op, int rd, int size)
TCGv mof;
mof = tcg_temp_new(TCG_TYPE_TL);
t_gen_mulu(cpu_T[0], mof, cpu_T[0], cpu_T[1]);
- t_gen_mov_preg_TN(PR_MOF, mof);
+ t_gen_mov_preg_TN(dc, PR_MOF, mof);
tcg_gen_discard_tl(mof);
}
break;
@@ -875,12 +860,6 @@ static void crisv32_alu_op(DisasContext *dc, int op, int rd, int size)
}
if (dc->update_cc)
tcg_gen_mov_tl(cc_result, cpu_T[0]);
-
- {
- /* TODO: Optimize this. */
- if (!dc->flagx_live)
- cris_evaluate_flags(dc);
- }
}
static int arith_cc(DisasContext *dc)
@@ -1073,7 +1052,6 @@ static void gen_tst_cc (DisasContext *dc, int cond)
tcg_gen_andi_tl(cpu_T[0], cpu_PR[PR_CCS], P_FLAG);
break;
case CC_A:
- cris_evaluate_flags(dc);
tcg_gen_movi_tl(cpu_T[0], 1);
break;
default:
@@ -1087,14 +1065,13 @@ static void cris_prepare_cc_branch (DisasContext *dc, int offset, int cond)
/* This helps us re-schedule the micro-code to insns in delay-slots
before the actual jump. */
dc->delayed_branch = 2;
- dc->delayed_pc = dc->pc + offset;
- dc->bcc = cond;
if (cond != CC_A)
{
gen_tst_cc (dc, cond);
t_gen_mov_env_TN(btaken, cpu_T[0]);
- }
- tcg_gen_movi_tl(env_btarget, dc->delayed_pc);
+ } else
+ t_gen_mov_env_TN(btaken, tcg_const_tl(1));
+ tcg_gen_movi_tl(env_btarget, dc->pc + offset);
}
@@ -1104,18 +1081,7 @@ void cris_prepare_dyn_jmp (DisasContext *dc)
/* This helps us re-schedule the micro-code to insns in delay-slots
before the actual jump. */
dc->delayed_branch = 2;
- dc->dyn_jmp = 1;
- dc->bcc = CC_A;
-}
-
-void cris_prepare_jmp (DisasContext *dc, uint32_t dst)
-{
- /* This helps us re-schedule the micro-code to insns in delay-slots
- before the actual jump. */
- dc->delayed_branch = 2;
- dc->delayed_pc = dst;
- dc->dyn_jmp = 0;
- dc->bcc = CC_A;
+ t_gen_mov_env_TN(btaken, tcg_const_tl(1));
}
void gen_load(DisasContext *dc, TCGv dst, TCGv addr,
@@ -1123,6 +1089,7 @@ void gen_load(DisasContext *dc, TCGv dst, TCGv addr,
{
int mem_index = cpu_mmu_index(dc->env);
+ cris_evaluate_flags(dc);
if (size == 1) {
if (sign)
tcg_gen_qemu_ld8s(dst, addr, mem_index);
@@ -1236,10 +1203,7 @@ static void dec_prep_alu_r(DisasContext *dc, int rs, int rd,
t_gen_zext(cpu_T[0], cpu_R[rd], size);
}
-/* Prepare T0 and T1 for a memory + alu operation.
- s_ext decides if the operand1 should be sign-extended or zero-extended when
- needed. */
-static int dec_prep_alu_m(DisasContext *dc, int s_ext, int memsize)
+static int dec_prep_move_m(DisasContext *dc, int s_ext, int memsize)
{
unsigned int rs, rd;
uint32_t imm;
@@ -1272,7 +1236,7 @@ static int dec_prep_alu_m(DisasContext *dc, int s_ext, int memsize)
imm = ldl_code(dc->pc + 2);
DIS(fprintf (logfile, "imm=%x rd=%d sext=%d ms=%d\n",
- imm, rd, s_ext, memsize));
+ imm, rd, s_ext, memsize));
tcg_gen_movi_tl(cpu_T[1], imm);
dc->postinc = 0;
} else {
@@ -1282,9 +1246,20 @@ static int dec_prep_alu_m(DisasContext *dc, int s_ext, int memsize)
else
t_gen_zext(cpu_T[1], cpu_T[1], memsize);
}
+ return insn_len;
+}
+
+/* Prepare T0 and T1 for a memory + alu operation.
+ s_ext decides if the operand1 should be sign-extended or zero-extended when
+ needed. */
+static int dec_prep_alu_m(DisasContext *dc, int s_ext, int memsize)
+{
+ int insn_len;
+
+ insn_len = dec_prep_move_m(dc, s_ext, memsize);
/* put dest in T0. */
- t_gen_mov_TN_reg(cpu_T[0], rd);
+ tcg_gen_mov_tl(cpu_T[0], cpu_R[dc->op2]);
return insn_len;
}
@@ -1421,7 +1396,7 @@ static unsigned int dec_btstq(DisasContext *dc)
crisv32_alu_op(dc, CC_OP_BTST, dc->op2, 4);
cris_update_cc_op(dc, CC_OP_FLAGS, 4);
- t_gen_mov_preg_TN(PR_CCS, cpu_T[0]);
+ t_gen_mov_preg_TN(dc, PR_CCS, cpu_T[0]);
dc->flags_live = 1;
return 2;
}
@@ -1702,7 +1677,9 @@ static char * swapmode_name(int mode, char *modename) {
static unsigned int dec_swap_r(DisasContext *dc)
{
- DIS(char modename[4]);
+#if DISAS_CRIS
+ char modename[4];
+#endif
DIS(fprintf (logfile, "swap%s $r%u\n",
swapmode_name(dc->op2, modename), dc->op1));
@@ -1777,7 +1754,7 @@ static unsigned int dec_btst_r(DisasContext *dc)
crisv32_alu_op(dc, CC_OP_BTST, dc->op2, 4);
cris_update_cc_op(dc, CC_OP_FLAGS, 4);
- t_gen_mov_preg_TN(PR_CCS, cpu_T[0]);
+ t_gen_mov_preg_TN(dc, PR_CCS, cpu_T[0]);
dc->flags_live = 1;
return 2;
}
@@ -1900,14 +1877,16 @@ static unsigned int dec_setclrf(DisasContext *dc)
flags = (EXTRACT_FIELD(dc->ir, 12, 15) << 4)
| EXTRACT_FIELD(dc->ir, 0, 3);
DIS(fprintf (logfile, "set=%d flags=%x\n", set, flags));
- if (set && flags == 0)
+ if (set && flags == 0) {
DIS(fprintf (logfile, "nop\n"));
- else if (!set && (flags & 0x20))
+ } else if (!set && (flags & 0x20)) {
DIS(fprintf (logfile, "di\n"));
- else
+ }
+ else {
DIS(fprintf (logfile, "%sf %x\n",
- set ? "set" : "clr",
+ set ? "set" : "clr",
flags));
+ }
if (set && (flags & X_FLAG)) {
dc->flagx_live = 1;
@@ -1924,7 +1903,7 @@ static unsigned int dec_setclrf(DisasContext *dc)
/* Enter user mode. */
t_gen_mov_env_TN(ksp, cpu_R[R_SP]);
tcg_gen_mov_tl(cpu_R[R_SP], cpu_PR[PR_USP]);
- dc->is_jmp = DISAS_UPDATE;
+ dc->is_jmp = DISAS_NEXT;
}
tcg_gen_ori_tl(cpu_PR[PR_CCS], cpu_PR[PR_CCS], flags);
}
@@ -1971,7 +1950,7 @@ static unsigned int dec_move_rp(DisasContext *dc)
else
t_gen_mov_TN_reg(cpu_T[0], dc->op1);
- t_gen_mov_preg_TN(dc->op2, cpu_T[0]);
+ t_gen_mov_preg_TN(dc, dc->op2, cpu_T[0]);
if (dc->op2 == PR_CCS) {
cris_update_cc_op(dc, CC_OP_FLAGS, 4);
dc->flags_live = 1;
@@ -2004,7 +1983,7 @@ static unsigned int dec_move_mr(DisasContext *dc)
dc->op1, dc->postinc ? "+]" : "]",
dc->op2));
- insn_len = dec_prep_alu_m(dc, 0, memsize);
+ insn_len = dec_prep_move_m(dc, 0, memsize);
cris_cc_mask(dc, CC_MASK_NZ);
crisv32_alu_op(dc, CC_OP_MOVE, dc->op2, memsize);
do_postinc(dc, memsize);
@@ -2317,7 +2296,7 @@ static unsigned int dec_move_mp(DisasContext *dc)
}
}
- t_gen_mov_preg_TN(dc->op2, cpu_T[1]);
+ t_gen_mov_preg_TN(dc, dc->op2, cpu_T[1]);
do_postinc(dc, memsize);
return insn_len;
@@ -2337,7 +2316,6 @@ static unsigned int dec_move_pm(DisasContext *dc)
if (dc->op2 == PR_CCS)
cris_evaluate_flags(dc);
t_gen_mov_TN_preg(cpu_T[1], dc->op2);
-
gen_store(dc, cpu_R[dc->op1], cpu_T[1], memsize);
cris_cc_mask(dc, 0);
@@ -2482,7 +2460,7 @@ static unsigned int dec_jas_im(DisasContext *dc)
cris_cc_mask(dc, 0);
/* Store the return address in Pd. */
tcg_gen_movi_tl(env_btarget, imm);
- t_gen_mov_preg_TN(dc->op2, tcg_const_tl(dc->pc + 8));
+ t_gen_mov_preg_TN(dc, dc->op2, tcg_const_tl(dc->pc + 8));
cris_prepare_dyn_jmp(dc);
return 6;
}
@@ -2499,7 +2477,7 @@ static unsigned int dec_jasc_im(DisasContext *dc)
tcg_gen_movi_tl(cpu_T[0], imm);
tcg_gen_mov_tl(env_btarget, cpu_T[0]);
tcg_gen_movi_tl(cpu_T[0], dc->pc + 8 + 4);
- t_gen_mov_preg_TN(dc->op2, cpu_T[0]);
+ t_gen_mov_preg_TN(dc, dc->op2, cpu_T[0]);
cris_prepare_dyn_jmp(dc);
return 6;
}
@@ -2512,7 +2490,7 @@ static unsigned int dec_jasc_r(DisasContext *dc)
t_gen_mov_TN_reg(cpu_T[0], dc->op1);
tcg_gen_mov_tl(env_btarget, cpu_T[0]);
tcg_gen_movi_tl(cpu_T[0], dc->pc + 4 + 4);
- t_gen_mov_preg_TN(dc->op2, cpu_T[0]);
+ t_gen_mov_preg_TN(dc, dc->op2, cpu_T[0]);
cris_prepare_dyn_jmp(dc);
return 2;
}
@@ -2547,7 +2525,7 @@ static unsigned int dec_bas_im(DisasContext *dc)
tcg_gen_movi_tl(cpu_T[0], dc->pc + simm);
tcg_gen_mov_tl(env_btarget, cpu_T[0]);
tcg_gen_movi_tl(cpu_T[0], dc->pc + 8);
- t_gen_mov_preg_TN(dc->op2, cpu_T[0]);
+ t_gen_mov_preg_TN(dc, dc->op2, cpu_T[0]);
cris_prepare_dyn_jmp(dc);
return 6;
}
@@ -2563,7 +2541,7 @@ static unsigned int dec_basc_im(DisasContext *dc)
tcg_gen_movi_tl(cpu_T[0], dc->pc + simm);
tcg_gen_mov_tl(env_btarget, cpu_T[0]);
tcg_gen_movi_tl(cpu_T[0], dc->pc + 12);
- t_gen_mov_preg_TN(dc->op2, cpu_T[0]);
+ t_gen_mov_preg_TN(dc, dc->op2, cpu_T[0]);
cris_prepare_dyn_jmp(dc);
return 6;
}
@@ -2785,8 +2763,42 @@ static void check_breakpoint(CPUState *env, DisasContext *dc)
}
}
+
+/*
+ * Delay slots on QEMU/CRIS.
+ *
+ * If an exception hits on a delayslot, the core will let ERP (the Exception
+ * Return Pointer) point to the branch (the previous) insn and set the lsb to
+ * to give SW a hint that the exception actually hit on the dslot.
+ *
+ * CRIS expects all PC addresses to be 16-bit aligned. The lsb is ignored by
+ * the core and any jmp to an odd addresses will mask off that lsb. It is
+ * simply there to let sw know there was an exception on a dslot.
+ *
+ * When the software returns from an exception, the branch will re-execute.
+ * On QEMU care needs to be taken when a branch+delayslot sequence is broken
+ * and the branch and delayslot dont share pages.
+ *
+ * The TB contaning the branch insn will set up env->btarget and evaluate
+ * env->btaken. When the translation loop exits we will note that the branch
+ * sequence is broken and let env->dslot be the size of the branch insn (those
+ * vary in length).
+ *
+ * The TB contaning the delayslot will have the PC of its real insn (i.e no lsb
+ * set). It will also expect to have env->dslot setup with the size of the
+ * delay slot so that env->pc - env->dslot point to the branch insn. This TB
+ * will execute the dslot and take the branch, either to btarget or just one
+ * insn ahead.
+ *
+ * When exceptions occur, we check for env->dslot in do_interrupt to detect
+ * broken branch sequences and setup $erp accordingly (i.e let it point to the
+ * branch and set lsb). Then env->dslot gets cleared so that the exception
+ * handler can enter. When returning from exceptions (jump $erp) the lsb gets
+ * masked off and we will reexecute the branch insn.
+ *
+ */
+
/* generate intermediate code for basic block 'tb'. */
-struct DisasContext ctx;
static int
gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
int search_pc)
@@ -2795,6 +2807,7 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
uint32_t pc_start;
unsigned int insn_len;
int j, lj;
+ struct DisasContext ctx;
struct DisasContext *dc = &ctx;
uint32_t next_page_start;
@@ -2803,8 +2816,6 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
/* Odd PC indicates that branch is rexecuting due to exception in the
* delayslot, like in real hw.
- * FIXME: we need to handle the case were the branch and the insn in
- * the delayslot do not share pages.
*/
pc_start = tb->pc & ~1;
dc->env = env;
@@ -2820,19 +2831,24 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
dc->flagx_live = 0;
dc->flags_x = 0;
dc->cc_mask = 0;
+ dc->update_cc = 0;
cris_update_cc_op(dc, CC_OP_FLAGS, 4);
- dc->user = env->pregs[PR_CCS] & U_FLAG;
- dc->delayed_branch = 0;
+ /* Decode TB flags. */
+ dc->user = tb->flags & U_FLAG;
+ dc->delayed_branch = !!(tb->flags & 7);
if (loglevel & CPU_LOG_TB_IN_ASM) {
fprintf(logfile,
- "search=%d pc=%x ccs=%x pid=%x usp=%x dbg=%x %x %x\n"
+ "srch=%d pc=%x %x bt=%x ds=%lld ccs=%x\n"
+ "pid=%x usp=%x dbg=%x %x %x\n"
"%x.%x.%x.%x\n"
"%x.%x.%x.%x\n"
"%x.%x.%x.%x\n"
"%x.%x.%x.%x\n",
- search_pc, env->pc, env->pregs[PR_CCS],
+ search_pc, dc->pc, dc->ppc,
+ env->btarget, tb->flags & 7,
+ env->pregs[PR_CCS],
env->pregs[PR_PID], env->pregs[PR_USP],
env->debug1, env->debug2, env->debug3,
env->regs[0], env->regs[1], env->regs[2], env->regs[3],
@@ -2860,14 +2876,17 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
while (lj < j)
gen_opc_instr_start[lj++] = 0;
}
- if (dc->delayed_branch == 1) {
+ if (dc->delayed_branch == 1)
gen_opc_pc[lj] = dc->ppc | 1;
- gen_opc_instr_start[lj] = 0;
- }
- else {
+ else
gen_opc_pc[lj] = dc->pc;
- gen_opc_instr_start[lj] = 1;
- }
+ gen_opc_instr_start[lj] = 1;
+ }
+
+ /* Pretty disas. */
+ DIS(fprintf(logfile, "%x ", dc->pc));
+ if (search_pc) {
+ DIS(fprintf(logfile, "%x ", dc->pc));
}
dc->clear_x = 1;
@@ -2881,17 +2900,13 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
actually genereating any host code, the simulator will just
loop doing nothing for on this program location. */
if (dc->delayed_branch) {
+ t_gen_mov_env_TN(dslot, tcg_const_tl(0));
dc->delayed_branch--;
if (dc->delayed_branch == 0)
{
- if (dc->bcc == CC_A) {
- tcg_gen_mov_tl(env_pc, env_btarget);
- dc->is_jmp = DISAS_JUMP;
- }
- else {
- t_gen_cc_jmp(dc->delayed_pc, dc->pc);
- dc->is_jmp = DISAS_JUMP;
- }
+ t_gen_cc_jmp(env_btarget,
+ tcg_const_tl(dc->pc));
+ dc->is_jmp = DISAS_JUMP;
}
}
@@ -2900,15 +2915,16 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
if (!(tb->pc & 1) && env->singlestep_enabled)
break;
} while (!dc->is_jmp && gen_opc_ptr < gen_opc_end
- && ((dc->pc < next_page_start) || dc->delayed_branch));
+ && (dc->pc < next_page_start));
+ /* Broken branch+delayslot sequence. */
if (dc->delayed_branch == 1) {
- /* Reexecute the last insn. */
- dc->pc = dc->ppc | 1;
+ /* Set env->dslot to the size of the branch insn. */
+ t_gen_mov_env_TN(dslot, tcg_const_tl(dc->pc - dc->ppc));
}
if (!dc->is_jmp) {
- D(printf("!jmp pc=%x jmp=%d db=%d\n", dc->pc,
+ D(fprintf(logfile, "!jmp pc=%x jmp=%d db=%d\n", dc->pc,
dc->is_jmp, dc->delayed_branch));
/* T0 and env_pc should hold the new pc. */
tcg_gen_movi_tl(cpu_T[0], dc->pc);
@@ -3079,6 +3095,7 @@ CPUCRISState *cpu_cris_init (const char *cpu_model)
TCG_HELPER(helper_dummy);
TCG_HELPER(helper_tlb_flush);
+ TCG_HELPER(helper_tlb_flush_pid);
TCG_HELPER(helper_movl_sreg_reg);
TCG_HELPER(helper_movl_reg_sreg);
TCG_HELPER(helper_rfe);