#include "cpu.h"
#include "disas/disas.h"
-#include "helper.h"
+#include "exec/helper-proto.h"
#include "tcg-op.h"
+#include "exec/cpu_ldst.h"
+
+#include "exec/helper-gen.h"
+
+#include "trace-tcg.h"
-#define GEN_HELPER 1
-#include "helper.h"
#define DEBUG_DISAS
/* Floating point registers */
static TCGv_i64 cpu_fpr[TARGET_DPREGS];
-static target_ulong gen_opc_npc[OPC_BUF_SIZE];
-static target_ulong gen_opc_jump_pc[2];
-
#include "exec/gen-icount.h"
typedef struct DisasContext {
TCGv_i64 t = tcg_temp_new_i64();
tcg_gen_shri_i64(t, cpu_fpr[src / 2], 32);
- tcg_gen_trunc_i64_i32(ret, t);
+ tcg_gen_extrl_i64_i32(ret, t);
tcg_temp_free_i64(t);
return ret;
tcg_gen_andi_tl(reg, reg, 0x1);
}
-static inline void gen_op_addi_cc(TCGv dst, TCGv src1, target_long src2)
-{
- tcg_gen_mov_tl(cpu_cc_src, src1);
- tcg_gen_movi_tl(cpu_cc_src2, src2);
- tcg_gen_addi_tl(cpu_cc_dst, cpu_cc_src, src2);
- tcg_gen_mov_tl(dst, cpu_cc_dst);
-}
-
static inline void gen_op_add_cc(TCGv dst, TCGv src1, TCGv src2)
{
tcg_gen_mov_tl(cpu_cc_src, src1);
#if TARGET_LONG_BITS == 64
cc_src1_32 = tcg_temp_new_i32();
cc_src2_32 = tcg_temp_new_i32();
- tcg_gen_trunc_i64_i32(cc_src1_32, cpu_cc_dst);
- tcg_gen_trunc_i64_i32(cc_src2_32, cpu_cc_src);
+ tcg_gen_extrl_i64_i32(cc_src1_32, cpu_cc_dst);
+ tcg_gen_extrl_i64_i32(cc_src2_32, cpu_cc_src);
#else
cc_src1_32 = cpu_cc_dst;
cc_src2_32 = cpu_cc_src;
#if TARGET_LONG_BITS == 64
cc_src1_32 = tcg_temp_new_i32();
cc_src2_32 = tcg_temp_new_i32();
- tcg_gen_trunc_i64_i32(cc_src1_32, cpu_cc_src);
- tcg_gen_trunc_i64_i32(cc_src2_32, cpu_cc_src2);
+ tcg_gen_extrl_i64_i32(cc_src1_32, cpu_cc_src);
+ tcg_gen_extrl_i64_i32(cc_src2_32, cpu_cc_src2);
#else
cc_src1_32 = cpu_cc_src;
cc_src2_32 = cpu_cc_src2;
}
}
-static inline void gen_op_subi_cc(TCGv dst, TCGv src1, target_long src2, DisasContext *dc)
-{
- tcg_gen_mov_tl(cpu_cc_src, src1);
- tcg_gen_movi_tl(cpu_cc_src2, src2);
- if (src2 == 0) {
- tcg_gen_mov_tl(cpu_cc_dst, src1);
- tcg_gen_movi_i32(cpu_cc_op, CC_OP_LOGIC);
- dc->cc_op = CC_OP_LOGIC;
- } else {
- tcg_gen_subi_tl(cpu_cc_dst, cpu_cc_src, src2);
- tcg_gen_movi_i32(cpu_cc_op, CC_OP_SUB);
- dc->cc_op = CC_OP_SUB;
- }
- tcg_gen_mov_tl(dst, cpu_cc_dst);
-}
-
static inline void gen_op_sub_cc(TCGv dst, TCGv src1, TCGv src2)
{
tcg_gen_mov_tl(cpu_cc_src, src1);
static inline void gen_branch2(DisasContext *dc, target_ulong pc1,
target_ulong pc2, TCGv r_cond)
{
- int l1;
-
- l1 = gen_new_label();
+ TCGLabel *l1 = gen_new_label();
tcg_gen_brcondi_tl(TCG_COND_EQ, r_cond, 0, l1);
gen_goto_tb(dc, 1, pc2, pc2 + 4);
}
-static inline void gen_branch_a(DisasContext *dc, target_ulong pc1,
- target_ulong pc2, TCGv r_cond)
+static void gen_branch_a(DisasContext *dc, target_ulong pc1)
{
- int l1;
+ TCGLabel *l1 = gen_new_label();
+ target_ulong npc = dc->npc;
- l1 = gen_new_label();
+ tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_cond, 0, l1);
- tcg_gen_brcondi_tl(TCG_COND_EQ, r_cond, 0, l1);
-
- gen_goto_tb(dc, 0, pc2, pc1);
+ gen_goto_tb(dc, 0, npc, pc1);
gen_set_label(l1);
- gen_goto_tb(dc, 1, pc2 + 4, pc2 + 8);
+ gen_goto_tb(dc, 1, npc + 4, npc + 8);
+
+ dc->is_br = 1;
+}
+
+static void gen_branch_n(DisasContext *dc, target_ulong pc1)
+{
+ target_ulong npc = dc->npc;
+
+ if (likely(npc != DYNAMIC_PC)) {
+ dc->pc = npc;
+ dc->jump_pc[0] = pc1;
+ dc->jump_pc[1] = npc + 4;
+ dc->npc = JUMP_PC;
+ } else {
+ TCGv t, z;
+
+ tcg_gen_mov_tl(cpu_pc, cpu_npc);
+
+ tcg_gen_addi_tl(cpu_npc, cpu_npc, 4);
+ t = tcg_const_tl(pc1);
+ z = tcg_const_tl(0);
+ tcg_gen_movcond_tl(TCG_COND_NE, cpu_npc, cpu_cond, z, t, cpu_npc);
+ tcg_temp_free(t);
+ tcg_temp_free(z);
+
+ dc->pc = DYNAMIC_PC;
+ }
}
static inline void gen_generic_branch(DisasContext *dc)
flush_cond(dc);
gen_cond(cpu_cond, cc, cond, dc);
if (a) {
- gen_branch_a(dc, target, dc->npc, cpu_cond);
- dc->is_br = 1;
+ gen_branch_a(dc, target);
} else {
- dc->pc = dc->npc;
- dc->jump_pc[0] = target;
- if (unlikely(dc->npc == DYNAMIC_PC)) {
- dc->jump_pc[1] = DYNAMIC_PC;
- tcg_gen_addi_tl(cpu_pc, cpu_npc, 4);
- } else {
- dc->jump_pc[1] = dc->npc + 4;
- dc->npc = JUMP_PC;
- }
+ gen_branch_n(dc, target);
}
}
}
flush_cond(dc);
gen_fcond(cpu_cond, cc, cond);
if (a) {
- gen_branch_a(dc, target, dc->npc, cpu_cond);
- dc->is_br = 1;
+ gen_branch_a(dc, target);
} else {
- dc->pc = dc->npc;
- dc->jump_pc[0] = target;
- if (unlikely(dc->npc == DYNAMIC_PC)) {
- dc->jump_pc[1] = DYNAMIC_PC;
- tcg_gen_addi_tl(cpu_pc, cpu_npc, 4);
- } else {
- dc->jump_pc[1] = dc->npc + 4;
- dc->npc = JUMP_PC;
- }
+ gen_branch_n(dc, target);
}
}
}
flush_cond(dc);
gen_cond_reg(cpu_cond, cond, r_reg);
if (a) {
- gen_branch_a(dc, target, dc->npc, cpu_cond);
- dc->is_br = 1;
+ gen_branch_a(dc, target);
} else {
- dc->pc = dc->npc;
- dc->jump_pc[0] = target;
- if (unlikely(dc->npc == DYNAMIC_PC)) {
- dc->jump_pc[1] = DYNAMIC_PC;
- tcg_gen_addi_tl(cpu_pc, cpu_npc, 4);
- } else {
- dc->jump_pc[1] = dc->npc + 4;
- dc->npc = JUMP_PC;
- }
+ gen_branch_n(dc, target);
}
}
the later. */
c32 = tcg_temp_new_i32();
if (cmp->is_bool) {
- tcg_gen_trunc_i64_i32(c32, cmp->c1);
+ tcg_gen_extrl_i64_i32(c32, cmp->c1);
} else {
TCGv_i64 c64 = tcg_temp_new_i64();
tcg_gen_setcond_i64(cmp->cond, c64, cmp->c1, cmp->c2);
- tcg_gen_trunc_i64_i32(c32, c64);
+ tcg_gen_extrl_i64_i32(c32, c64);
tcg_temp_free_i64(c64);
}
gen_update_fprs_dirty(qd);
}
+#ifndef CONFIG_USER_ONLY
static inline void gen_load_trap_state_at_tl(TCGv_ptr r_tsptr, TCGv_ptr cpu_env)
{
TCGv_i32 r_tl = tcg_temp_new_i32();
tcg_temp_free_i32(r_tl);
}
+#endif
static void gen_edge(DisasContext *dc, TCGv dst, TCGv s1, TCGv s2,
int width, bool cc, bool left)
TCGv_i64 cpu_src1_64, cpu_src2_64, cpu_dst_64;
target_long simm;
- if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP | CPU_LOG_TB_OP_OPT))) {
- tcg_gen_debug_insn_start(dc->pc);
- }
-
opc = GET_FIELD(insn, 0, 1);
rd = GET_FIELD(insn, 2, 6);
if (xop == 0x3a) { /* generate trap */
int cond = GET_FIELD(insn, 3, 6);
TCGv_i32 trap;
- int l1 = -1, mask;
+ TCGLabel *l1 = NULL;
+ int mask;
if (cond == 0) {
/* Trap never. */
if (IS_IMM) {
goto illegal_insn;
}
- if (!supervisor(dc)) {
+ /* LEON3 allows CASA from user space with ASI 0xa */
+ if ((GET_FIELD(insn, 19, 26) != 0xa) && !supervisor(dc)) {
goto priv_insn;
}
#endif
}
}
-static inline void gen_intermediate_code_internal(SPARCCPU *cpu,
- TranslationBlock *tb,
- bool spc)
+void gen_intermediate_code(CPUSPARCState * env, TranslationBlock * tb)
{
+ SPARCCPU *cpu = sparc_env_get_cpu(env);
CPUState *cs = CPU(cpu);
- CPUSPARCState *env = &cpu->env;
target_ulong pc_start, last_pc;
- uint16_t *gen_opc_end;
DisasContext dc1, *dc = &dc1;
- CPUBreakpoint *bp;
- int j, lj = -1;
int num_insns;
int max_insns;
unsigned int insn;
last_pc = dc->pc;
dc->npc = (target_ulong) tb->cs_base;
dc->cc_op = CC_OP_DYNAMIC;
- dc->mem_idx = cpu_mmu_index(env);
+ dc->mem_idx = cpu_mmu_index(env, false);
dc->def = env->def;
dc->fpu_enabled = tb_fpu_enabled(tb->flags);
dc->address_mask_32bit = tb_am_enabled(tb->flags);
dc->singlestep = (cs->singlestep_enabled || singlestep);
- gen_opc_end = tcg_ctx.gen_opc_buf + OPC_MAX_SIZE;
num_insns = 0;
max_insns = tb->cflags & CF_COUNT_MASK;
- if (max_insns == 0)
+ if (max_insns == 0) {
max_insns = CF_COUNT_MASK;
- gen_tb_start();
+ }
+ if (max_insns > TCG_MAX_INSNS) {
+ max_insns = TCG_MAX_INSNS;
+ }
+
+ gen_tb_start(tb);
do {
- if (unlikely(!QTAILQ_EMPTY(&cs->breakpoints))) {
- QTAILQ_FOREACH(bp, &cs->breakpoints, entry) {
- if (bp->pc == dc->pc) {
- if (dc->pc != pc_start)
- save_state(dc);
- gen_helper_debug(cpu_env);
- tcg_gen_exit_tb(0);
- dc->is_br = 1;
- goto exit_gen_loop;
- }
- }
+ if (dc->npc & JUMP_PC) {
+ assert(dc->jump_pc[1] == dc->pc + 4);
+ tcg_gen_insn_start(dc->pc, dc->jump_pc[0] | JUMP_PC);
+ } else {
+ tcg_gen_insn_start(dc->pc, dc->npc);
}
- if (spc) {
- qemu_log("Search PC...\n");
- j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf;
- if (lj < j) {
- lj++;
- while (lj < j)
- tcg_ctx.gen_opc_instr_start[lj++] = 0;
- tcg_ctx.gen_opc_pc[lj] = dc->pc;
- gen_opc_npc[lj] = dc->npc;
- tcg_ctx.gen_opc_instr_start[lj] = 1;
- tcg_ctx.gen_opc_icount[lj] = num_insns;
+ num_insns++;
+ last_pc = dc->pc;
+
+ if (unlikely(cpu_breakpoint_test(cs, dc->pc, BP_ANY))) {
+ if (dc->pc != pc_start) {
+ save_state(dc);
}
+ gen_helper_debug(cpu_env);
+ tcg_gen_exit_tb(0);
+ dc->is_br = 1;
+ goto exit_gen_loop;
}
- if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO))
+
+ if (num_insns == max_insns && (tb->cflags & CF_LAST_IO)) {
gen_io_start();
- last_pc = dc->pc;
+ }
+
insn = cpu_ldl_code(env, dc->pc);
disas_sparc_insn(dc, insn);
- num_insns++;
if (dc->is_br)
break;
if (dc->singlestep) {
break;
}
- } while ((tcg_ctx.gen_opc_ptr < gen_opc_end) &&
+ } while (!tcg_op_buf_full() &&
(dc->pc - pc_start) < (TARGET_PAGE_SIZE - 32) &&
num_insns < max_insns);
}
}
gen_tb_end(tb, num_insns);
- *tcg_ctx.gen_opc_ptr = INDEX_op_end;
- if (spc) {
- j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf;
- lj++;
- while (lj <= j)
- tcg_ctx.gen_opc_instr_start[lj++] = 0;
-#if 0
- log_page_dump();
-#endif
- gen_opc_jump_pc[0] = dc->jump_pc[0];
- gen_opc_jump_pc[1] = dc->jump_pc[1];
- } else {
- tb->size = last_pc + 4 - pc_start;
- tb->icount = num_insns;
- }
+
+ tb->size = last_pc + 4 - pc_start;
+ tb->icount = num_insns;
+
#ifdef DEBUG_DISAS
if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) {
qemu_log("--------------\n");
qemu_log("IN: %s\n", lookup_symbol(pc_start));
- log_target_disas(env, pc_start, last_pc + 4 - pc_start, 0);
+ log_target_disas(cs, pc_start, last_pc + 4 - pc_start, 0);
qemu_log("\n");
}
#endif
}
-void gen_intermediate_code(CPUSPARCState * env, TranslationBlock * tb)
-{
- gen_intermediate_code_internal(sparc_env_get_cpu(env), tb, false);
-}
-
-void gen_intermediate_code_pc(CPUSPARCState * env, TranslationBlock * tb)
-{
- gen_intermediate_code_internal(sparc_env_get_cpu(env), tb, true);
-}
-
void gen_intermediate_code_init(CPUSPARCState *env)
{
unsigned int i;
}
}
-void restore_state_to_opc(CPUSPARCState *env, TranslationBlock *tb, int pc_pos)
+void restore_state_to_opc(CPUSPARCState *env, TranslationBlock *tb,
+ target_ulong *data)
{
- target_ulong npc;
- env->pc = tcg_ctx.gen_opc_pc[pc_pos];
- npc = gen_opc_npc[pc_pos];
- if (npc == 1) {
+ target_ulong pc = data[0];
+ target_ulong npc = data[1];
+
+ env->pc = pc;
+ if (npc == DYNAMIC_PC) {
/* dynamic NPC: already stored */
- } else if (npc == 2) {
+ } else if (npc & JUMP_PC) {
/* jump PC: use 'cond' and the jump targets of the translation */
if (env->cond) {
- env->npc = gen_opc_jump_pc[0];
+ env->npc = npc & ~3;
} else {
- env->npc = gen_opc_jump_pc[1];
+ env->npc = pc + 4;
}
} else {
env->npc = npc;