aboutsummaryrefslogtreecommitdiff
path: root/target-sparc/translate.c
diff options
context:
space:
mode:
Diffstat (limited to 'target-sparc/translate.c')
-rw-r--r--target-sparc/translate.c249
1 files changed, 204 insertions, 45 deletions
diff --git a/target-sparc/translate.c b/target-sparc/translate.c
index e1c02725fe..c2ba2e35cd 100644
--- a/target-sparc/translate.c
+++ b/target-sparc/translate.c
@@ -86,6 +86,12 @@ enum {
#define DFPREG(r) (r)
#endif
+#ifdef USE_DIRECT_JUMP
+#define TBPARAM(x)
+#else
+#define TBPARAM(x) (long)(x)
+#endif
+
static int sign_extend(int x, int len)
{
len = 32 - len;
@@ -462,7 +468,7 @@ OP_LD_TABLE(casx);
static inline void gen_movl_imm_TN(int reg, uint32_t imm)
{
- gen_op_movl_TN_im[reg] (imm);
+ gen_op_movl_TN_im[reg](imm);
}
static inline void gen_movl_imm_T1(uint32_t val)
@@ -529,15 +535,6 @@ static inline void gen_movl_T1_reg(int reg)
gen_movl_TN_reg(reg, 1);
}
-/* call this function before using T2 as it may have been set for a jump */
-static inline void flush_T2(DisasContext * dc)
-{
- if (dc->npc == JUMP_PC) {
- gen_op_generic_branch(dc->jump_pc[0], dc->jump_pc[1]);
- dc->npc = DYNAMIC_PC;
- }
-}
-
static inline void gen_jmp_im(target_ulong pc)
{
#ifdef TARGET_SPARC64
@@ -564,10 +561,88 @@ static inline void gen_movl_npc_im(target_ulong npc)
#endif
}
+static inline void gen_branch2(DisasContext *dc, long tb, target_ulong pc1, target_ulong pc2)
+{
+ int l1;
+
+ l1 = gen_new_label();
+
+ gen_op_jz_T2_label(l1);
+
+ gen_op_goto_tb0(TBPARAM(tb));
+ gen_jmp_im(pc1);
+ gen_movl_npc_im(pc1 + 4);
+ gen_op_movl_T0_im((long)tb + 0);
+ gen_op_exit_tb();
+
+ gen_set_label(l1);
+ gen_op_goto_tb1(TBPARAM(tb));
+ gen_jmp_im(pc2);
+ gen_movl_npc_im(pc2 + 4);
+ gen_op_movl_T0_im((long)tb + 1);
+ gen_op_exit_tb();
+}
+
+static inline void gen_branch_a(DisasContext *dc, long tb, target_ulong pc1, target_ulong pc2)
+{
+ int l1;
+
+ l1 = gen_new_label();
+
+ gen_op_jz_T2_label(l1);
+
+ gen_op_goto_tb0(TBPARAM(tb));
+ gen_jmp_im(pc2);
+ gen_movl_npc_im(pc1);
+ gen_op_movl_T0_im((long)tb + 0);
+ gen_op_exit_tb();
+
+ gen_set_label(l1);
+ gen_op_goto_tb1(TBPARAM(tb));
+ gen_jmp_im(pc2 + 4);
+ gen_movl_npc_im(pc2 + 8);
+ gen_op_movl_T0_im((long)tb + 1);
+ gen_op_exit_tb();
+}
+
+static inline void gen_branch(DisasContext *dc, long tb, target_ulong pc, target_ulong npc)
+{
+ gen_op_goto_tb0(TBPARAM(tb));
+ gen_jmp_im(pc);
+ gen_movl_npc_im(npc);
+ gen_op_movl_T0_im((long)tb + 0);
+ gen_op_exit_tb();
+}
+
+static inline void gen_generic_branch(DisasContext *dc, target_ulong npc1, target_ulong npc2)
+{
+ int l1, l2;
+
+ l1 = gen_new_label();
+ l2 = gen_new_label();
+ gen_op_jz_T2_label(l1);
+
+ gen_movl_npc_im(npc1);
+ gen_op_jmp_label(l2);
+
+ gen_set_label(l1);
+ gen_movl_npc_im(npc2);
+ gen_set_label(l2);
+}
+
+/* call this function before using T2 as it may have been set for a jump */
+static inline void flush_T2(DisasContext * dc)
+{
+ if (dc->npc == JUMP_PC) {
+ gen_generic_branch(dc, dc->jump_pc[0], dc->jump_pc[1]);
+ dc->npc = DYNAMIC_PC;
+ }
+}
+
static inline void save_npc(DisasContext * dc)
{
if (dc->npc == JUMP_PC) {
- gen_op_generic_branch(dc->jump_pc[0], dc->jump_pc[1]);
+ gen_generic_branch(dc, dc->jump_pc[0], dc->jump_pc[1]);
dc->npc = DYNAMIC_PC;
} else if (dc->npc != DYNAMIC_PC) {
gen_movl_npc_im(dc->npc);
@@ -583,7 +658,7 @@ static inline void save_state(DisasContext * dc)
static inline void gen_mov_pc_npc(DisasContext * dc)
{
if (dc->npc == JUMP_PC) {
- gen_op_generic_branch(dc->jump_pc[0], dc->jump_pc[1]);
+ gen_generic_branch(dc, dc->jump_pc[0], dc->jump_pc[1]);
gen_op_mov_pc_npc();
dc->pc = DYNAMIC_PC;
} else if (dc->npc == DYNAMIC_PC) {
@@ -769,7 +844,7 @@ static void do_branch(DisasContext * dc, int32_t offset, uint32_t insn, int cc)
flush_T2(dc);
gen_cond[cc][cond]();
if (a) {
- gen_op_branch_a((long)dc->tb, target, dc->npc);
+ gen_branch_a(dc, (long)dc->tb, target, dc->npc);
dc->is_br = 1;
} else {
dc->pc = dc->npc;
@@ -808,7 +883,7 @@ static void do_fbranch(DisasContext * dc, int32_t offset, uint32_t insn, int cc)
flush_T2(dc);
gen_fcond[cc][cond]();
if (a) {
- gen_op_branch_a((long)dc->tb, target, dc->npc);
+ gen_branch_a(dc, (long)dc->tb, target, dc->npc);
dc->is_br = 1;
} else {
dc->pc = dc->npc;
@@ -829,7 +904,7 @@ static void do_branch_reg(DisasContext * dc, int32_t offset, uint32_t insn)
flush_T2(dc);
gen_cond_reg(cond);
if (a) {
- gen_op_branch_a((long)dc->tb, target, dc->npc);
+ gen_branch_a(dc, (long)dc->tb, target, dc->npc);
dc->is_br = 1;
} else {
dc->pc = dc->npc;
@@ -893,7 +968,7 @@ static void disas_sparc_insn(DisasContext * dc)
target <<= 2;
target = sign_extend(target, 16);
rs1 = GET_FIELD(insn, 13, 17);
- gen_movl_T0_reg(rs1);
+ gen_movl_reg_T0(rs1);
do_branch_reg(dc, target, insn);
goto jmp_insn;
}
@@ -952,7 +1027,15 @@ static void disas_sparc_insn(DisasContext * dc)
/*CALL*/ {
target_long target = GET_FIELDs(insn, 2, 31) << 2;
+#ifdef TARGET_SPARC64
+ if (dc->pc == (uint32_t)dc->pc) {
+ gen_op_movl_T0_im(dc->pc);
+ } else {
+ gen_op_movq_T0_im64(dc->pc >> 32, dc->pc);
+ }
+#else
gen_op_movl_T0_im(dc->pc);
+#endif
gen_movl_T0_reg(15);
target += dc->pc;
gen_mov_pc_npc(dc);
@@ -1039,6 +1122,25 @@ static void disas_sparc_insn(DisasContext * dc)
gen_op_movl_T0_env(offsetof(CPUSPARCState, fprs));
gen_movl_T0_reg(rd);
break;
+ case 0x17: /* Tick compare */
+ gen_op_movtl_T0_env(offsetof(CPUSPARCState, tick_cmpr));
+ gen_movl_T0_reg(rd);
+ break;
+ case 0x18: /* System tick */
+ gen_op_rdtick(); // XXX
+ gen_movl_T0_reg(rd);
+ break;
+ case 0x19: /* System tick compare */
+ gen_op_movtl_T0_env(offsetof(CPUSPARCState, stick_cmpr));
+ gen_movl_T0_reg(rd);
+ break;
+ case 0x10: /* Performance Control */
+ case 0x11: /* Performance Instrumentation Counter */
+ case 0x12: /* Dispatch Control */
+ case 0x13: /* Graphics Status */
+ case 0x14: /* Softint set, WO */
+ case 0x15: /* Softint clear, WO */
+ case 0x16: /* Softint write */
#endif
default:
goto illegal_insn;
@@ -1549,6 +1651,50 @@ static void disas_sparc_insn(DisasContext * dc)
gen_movl_T0_reg(rd);
}
#endif
+#ifdef TARGET_SPARC64
+ } else if (xop == 0x25) { /* sll, V9 sllx ( == sll) */
+ rs1 = GET_FIELD(insn, 13, 17);
+ gen_movl_reg_T0(rs1);
+ if (IS_IMM) { /* immediate */
+ rs2 = GET_FIELDs(insn, 20, 31);
+ gen_movl_simm_T1(rs2);
+ } else { /* register */
+ rs2 = GET_FIELD(insn, 27, 31);
+ gen_movl_reg_T1(rs2);
+ }
+ gen_op_sll();
+ gen_movl_T0_reg(rd);
+ } else if (xop == 0x26) { /* srl, V9 srlx */
+ rs1 = GET_FIELD(insn, 13, 17);
+ gen_movl_reg_T0(rs1);
+ if (IS_IMM) { /* immediate */
+ rs2 = GET_FIELDs(insn, 20, 31);
+ gen_movl_simm_T1(rs2);
+ } else { /* register */
+ rs2 = GET_FIELD(insn, 27, 31);
+ gen_movl_reg_T1(rs2);
+ }
+ if (insn & (1 << 12))
+ gen_op_srlx();
+ else
+ gen_op_srl();
+ gen_movl_T0_reg(rd);
+ } else if (xop == 0x27) { /* sra, V9 srax */
+ rs1 = GET_FIELD(insn, 13, 17);
+ gen_movl_reg_T0(rs1);
+ if (IS_IMM) { /* immediate */
+ rs2 = GET_FIELDs(insn, 20, 31);
+ gen_movl_simm_T1(rs2);
+ } else { /* register */
+ rs2 = GET_FIELD(insn, 27, 31);
+ gen_movl_reg_T1(rs2);
+ }
+ if (insn & (1 << 12))
+ gen_op_srax();
+ else
+ gen_op_sra();
+ gen_movl_T0_reg(rd);
+#endif
} else if (xop < 0x38) {
rs1 = GET_FIELD(insn, 13, 17);
gen_movl_reg_T0(rs1);
@@ -1660,32 +1806,20 @@ static void disas_sparc_insn(DisasContext * dc)
gen_op_mulscc_T1_T0();
gen_movl_T0_reg(rd);
break;
- case 0x25: /* sll, V9 sllx ( == sll) */
+#ifndef TARGET_SPARC64
+ case 0x25: /* sll */
gen_op_sll();
gen_movl_T0_reg(rd);
break;
- case 0x26: /* srl, V9 srlx */
-#ifdef TARGET_SPARC64
- if (insn & (1 << 12))
- gen_op_srlx();
- else
- gen_op_srl();
-#else
+ case 0x26: /* srl */
gen_op_srl();
-#endif
gen_movl_T0_reg(rd);
break;
- case 0x27: /* sra, V9 srax */
-#ifdef TARGET_SPARC64
- if (insn & (1 << 12))
- gen_op_srax();
- else
- gen_op_sra();
-#else
+ case 0x27: /* sra */
gen_op_sra();
-#endif
gen_movl_T0_reg(rd);
break;
+#endif
case 0x30:
{
switch(rd) {
@@ -1709,7 +1843,28 @@ static void disas_sparc_insn(DisasContext * dc)
gen_op_sir();
#endif
break;
+ case 0x17: /* Tick compare */
+#if !defined(CONFIG_USER_ONLY)
+ if (!supervisor(dc))
+ goto illegal_insn;
+#endif
+ gen_op_movtl_env_T0(offsetof(CPUSPARCState, tick_cmpr));
+ break;
+ case 0x18: /* System tick */
+#if !defined(CONFIG_USER_ONLY)
+ if (!supervisor(dc))
+ goto illegal_insn;
+#endif
+ gen_op_movtl_env_T0(offsetof(CPUSPARCState, stick_cmpr));
+ break;
+ case 0x19: /* System tick compare */
+#if !defined(CONFIG_USER_ONLY)
+ if (!supervisor(dc))
+ goto illegal_insn;
#endif
+ gen_op_movtl_env_T0(offsetof(CPUSPARCState, stick_cmpr));
+ break;
+
case 0x10: /* Performance Control */
case 0x11: /* Performance Instrumentation Counter */
case 0x12: /* Dispatch Control */
@@ -1717,9 +1872,7 @@ static void disas_sparc_insn(DisasContext * dc)
case 0x14: /* Softint set */
case 0x15: /* Softint clear */
case 0x16: /* Softint write */
- case 0x17: /* Tick compare */
- case 0x18: /* System tick */
- case 0x19: /* System tick compare */
+#endif
default:
goto illegal_insn;
}
@@ -1770,7 +1923,7 @@ static void disas_sparc_insn(DisasContext * dc)
gen_op_wrtick();
break;
case 5: // tba
- gen_op_movl_env_T0(offsetof(CPUSPARCState, tbr));
+ gen_op_movtl_env_T0(offsetof(CPUSPARCState, tbr));
break;
case 6: // pstate
gen_op_wrpstate();
@@ -1896,7 +2049,6 @@ static void disas_sparc_insn(DisasContext * dc)
}
#ifdef TARGET_SPARC64
} else if (xop == 0x39) { /* V9 return */
- gen_op_restore();
rs1 = GET_FIELD(insn, 13, 17);
gen_movl_reg_T0(rs1);
if (IS_IMM) { /* immediate */
@@ -1920,6 +2072,7 @@ static void disas_sparc_insn(DisasContext * dc)
}
#endif
}
+ gen_op_restore();
gen_mov_pc_npc(dc);
gen_op_movl_npc_T0();
dc->npc = DYNAMIC_PC;
@@ -1993,13 +2146,17 @@ static void disas_sparc_insn(DisasContext * dc)
case 0:
if (!supervisor(dc))
goto priv_insn;
+ dc->npc = DYNAMIC_PC;
+ dc->pc = DYNAMIC_PC;
gen_op_done();
- break;
+ goto jmp_insn;
case 1:
if (!supervisor(dc))
goto priv_insn;
+ dc->npc = DYNAMIC_PC;
+ dc->pc = DYNAMIC_PC;
gen_op_retry();
- break;
+ goto jmp_insn;
default:
goto illegal_insn;
}
@@ -2317,7 +2474,7 @@ static void disas_sparc_insn(DisasContext * dc)
gen_op_next_insn();
} else if (dc->npc == JUMP_PC) {
/* we can do a static jump */
- gen_op_branch2((long)dc->tb, dc->jump_pc[0], dc->jump_pc[1]);
+ gen_branch2(dc, (long)dc->tb, dc->jump_pc[0], dc->jump_pc[1]);
dc->is_br = 1;
} else {
dc->pc = dc->npc;
@@ -2365,6 +2522,7 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb,
gen_opc_ptr = gen_opc_buf;
gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
gen_opparam_ptr = gen_opparam_buf;
+ nb_gen_labels = 0;
do {
if (env->nb_breakpoints > 0) {
@@ -2421,7 +2579,7 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb,
if (dc->pc != DYNAMIC_PC &&
(dc->npc != DYNAMIC_PC && dc->npc != JUMP_PC)) {
/* static PC and NPC: we can use direct chaining */
- gen_op_branch((long)tb, dc->pc, dc->npc);
+ gen_branch(dc, (long)tb, dc->pc, dc->npc);
} else {
if (dc->pc != DYNAMIC_PC)
gen_jmp_im(dc->pc);
@@ -2487,15 +2645,16 @@ void cpu_reset(CPUSPARCState *env)
#else
env->psrs = 1;
env->psrps = 1;
- env->pc = 0xffd00000;
env->gregs[1] = ram_size;
- env->npc = env->pc + 4;
#ifdef TARGET_SPARC64
- env->pstate = PS_AM | PS_PRIV; // XXX: Force AM
+ env->pstate = PS_PRIV;
env->version = GET_VER(env);
+ env->pc = 0x1fff0000000ULL;
#else
env->mmuregs[0] = (0x04 << 24); /* Impl 0, ver 4, MMU disabled */
+ env->pc = 0xffd00000;
#endif
+ env->npc = env->pc + 4;
#endif
}