@@ -22,7 +22,12 @@ SETHI 00 rd:5 100 i:22
CALL 01 i:s30
-Tcc 10 0 cond:4 111010 rs1:5 imm:1 cc:1 00000 rs2_or_imm:7
+##
+## Major Opcode 10 -- integer, floating-point, vis, and system insns.
+##
+
+&r_r_ri rd rs1 rs2_or_imm imm:bool
+@n_r_ri .. ..... ...... rs1:5 imm:1 rs2_or_imm:s13 &r_r_ri rd=0
{
[
@@ -46,6 +51,30 @@ Tcc 10 0 cond:4 111010 rs1:5 imm:1 cc:1 00000 rs2_or_imm:7
RDY 10 rd:5 101000 rs1:5 0 0000000000000
}
+{
+ [
+ WRY 10 00000 110000 ..... . ............. @n_r_ri
+ WRCCR 10 00010 110000 ..... . ............. @n_r_ri
+ WRASI 10 00011 110000 ..... . ............. @n_r_ri
+ WRFPRS 10 00110 110000 ..... . ............. @n_r_ri
+ {
+ WRGSR 10 10011 110000 ..... . ............. @n_r_ri
+ WRPOWERDOWN 10 10011 110000 ..... . ............. @n_r_ri
+ }
+ WRSOFTINT_SET 10 10100 110000 ..... . ............. @n_r_ri
+ WRSOFTINT_CLR 10 10101 110000 ..... . ............. @n_r_ri
+ WRSOFTINT 10 10110 110000 ..... . ............. @n_r_ri
+ WRTICK_CMPR 10 10111 110000 ..... . ............. @n_r_ri
+ WRSTICK 10 11000 110000 ..... . ............. @n_r_ri
+ WRSTICK_CMPR 10 11001 110000 ..... . ............. @n_r_ri
+ ]
+ # Before v8, rs1==0 was WRY, and the rest executed as nop.
+ [
+ NOP_v7 10 ----- 110000 ----- 0 00000000 -----
+ NOP_v7 10 ----- 110000 ----- 1 -------- -----
+ ]
+}
+
{
RDPSR 10 rd:5 101001 00000 0 0000000000000
RDHPR_hpstate 10 rd:5 101001 00000 0 0000000000000
@@ -82,3 +111,5 @@ RDPR_ver 10 rd:5 101010 11111 0 0000000000000
FLUSHW 10 00000 101011 00000 0 0000000000000
RDTBR 10 rd:5 101011 00000 0 0000000000000
}
+
+Tcc 10 0 cond:4 111010 rs1:5 imm:1 cc:1 00000 rs2_or_imm:7
@@ -37,10 +37,15 @@
#undef HELPER_H
#ifdef TARGET_SPARC64
-#define gen_helper_rdpsr(D, E) qemu_build_not_reached()
+#define gen_helper_rdpsr(D, E) qemu_build_not_reached()
+#define gen_helper_power_down(E) g_assert_not_reached()
#else
-#define gen_helper_rdccr(D, E) qemu_build_not_reached()
-#define gen_helper_rdcwp(D, E) qemu_build_not_reached()
+#define gen_helper_rdccr(D, E) qemu_build_not_reached()
+#define gen_helper_rdcwp(D, E) qemu_build_not_reached()
+#define gen_helper_wrccr(E, S) qemu_build_not_reached()
+#define gen_helper_set_softint(E, S) qemu_build_not_reached()
+#define gen_helper_clear_softint(E, S) qemu_build_not_reached()
+#define gen_helper_write_softint(E, S) qemu_build_not_reached()
#endif
/* Dynamic PC, must exit to main loop. */
@@ -2847,6 +2852,7 @@ static void gen_faligndata(TCGv dst, TCGv gsr, TCGv s1, TCGv s2)
#define avail_ASR17(C) ((C)->def->features & CPU_FEATURE_ASR17)
#define avail_GL(C) ((C)->def->features & CPU_FEATURE_GL)
#define avail_HYPV(C) ((C)->def->features & CPU_FEATURE_HYPV)
+#define avail_POWERDOWN(C) ((C)->def->features & CPU_FEATURE_POWERDOWN)
/* Default case for non jump instructions. */
static bool advance_pc(DisasContext *dc)
@@ -3064,6 +3070,10 @@ static bool trans_SETHI(DisasContext *dc, arg_SETHI *a)
return advance_pc(dc);
}
+/*
+ * Major Opcode 10 -- integer, floating-point, vis, and system insns.
+ */
+
static bool trans_Tcc(DisasContext *dc, arg_Tcc *a)
{
DisasCompare cmp;
@@ -3628,6 +3638,186 @@ static bool trans_FLUSHW(DisasContext *dc, arg_FLUSHW *a)
#endif
}
+static bool do_wr_special(DisasContext *dc, arg_r_r_ri *a, bool priv,
+ void (*func)(DisasContext *, TCGv))
+{
+ TCGv src;
+
+ /* For simplicity, we under-decoded the rs2 form. */
+ if (!a->imm && (a->rs2_or_imm & ~0x1f)) {
+ return false;
+ }
+ if (!priv) {
+ return raise_priv(dc);
+ }
+
+ if (a->rs1 == 0 && (a->imm || a->rs2_or_imm == 0)) {
+ src = tcg_constant_tl(a->rs2_or_imm);
+ } else {
+ TCGv src1 = gen_load_gpr(dc, a->rs1);
+ if (a->rs2_or_imm == 0) {
+ src = src1;
+ } else {
+ src = tcg_temp_new();
+ if (a->imm) {
+ tcg_gen_xori_tl(src, src1, a->rs2_or_imm);
+ } else {
+ tcg_gen_xor_tl(src, src1, gen_load_gpr(dc, a->rs2_or_imm));
+ }
+ }
+ }
+ func(dc, src);
+ return advance_pc(dc);
+}
+
+static void do_wry(DisasContext *dc, TCGv src)
+{
+ tcg_gen_ext32u_tl(cpu_y, src);
+}
+
+TRANS(WRY, ALL, do_wr_special, a, true, do_wry)
+
+static void do_wrccr(DisasContext *dc, TCGv src)
+{
+ gen_helper_wrccr(tcg_env, src);
+}
+
+TRANS(WRCCR, 64, do_wr_special, a, true, do_wrccr)
+
+static void do_wrasi(DisasContext *dc, TCGv src)
+{
+#ifdef TARGET_SPARC64
+ TCGv tmp = tcg_temp_new();
+ tcg_gen_andi_tl(tmp, src, 0xff);
+ tcg_gen_st32_tl(tmp, tcg_env, offsetof(CPUSPARCState, asi));
+ /* End TB to notice changed ASI. */
+ dc->base.is_jmp = DISAS_EXIT;
+#else
+ qemu_build_not_reached();
+#endif
+}
+
+TRANS(WRASI, 64, do_wr_special, a, true, do_wrasi)
+
+static void do_wrfprs(DisasContext *dc, TCGv src)
+{
+#ifdef TARGET_SPARC64
+ tcg_gen_trunc_tl_i32(cpu_fprs, src);
+ dc->fprs_dirty = 0;
+ dc->base.is_jmp = DISAS_EXIT;
+#else
+ qemu_build_not_reached();
+#endif
+}
+
+TRANS(WRFPRS, 64, do_wr_special, a, true, do_wrfprs)
+
+static void do_wrgsr(DisasContext *dc, TCGv src)
+{
+#ifdef TARGET_SPARC64
+ gen_trap_ifnofpu(dc);
+ tcg_gen_mov_tl(cpu_gsr, src);
+#else
+ qemu_build_not_reached();
+#endif
+}
+
+TRANS(WRGSR, 64, do_wr_special, a, true, do_wrgsr)
+
+static void do_wrsoftint_set(DisasContext *dc, TCGv src)
+{
+ gen_helper_set_softint(tcg_env, src);
+}
+
+TRANS(WRSOFTINT_SET, 64, do_wr_special, a, supervisor(dc), do_wrsoftint_set)
+
+static void do_wrsoftint_clr(DisasContext *dc, TCGv src)
+{
+ gen_helper_clear_softint(tcg_env, src);
+}
+
+TRANS(WRSOFTINT_CLR, 64, do_wr_special, a, supervisor(dc), do_wrsoftint_clr)
+
+static void do_wrsoftint(DisasContext *dc, TCGv src)
+{
+ gen_helper_write_softint(tcg_env, src);
+}
+
+TRANS(WRSOFTINT, 64, do_wr_special, a, supervisor(dc), do_wrsoftint)
+
+static void do_wrtick_cmpr(DisasContext *dc, TCGv src)
+{
+#ifdef TARGET_SPARC64
+ TCGv_ptr r_tickptr = tcg_temp_new_ptr();
+
+ tcg_gen_mov_tl(cpu_tick_cmpr, src);
+ tcg_gen_ld_ptr(r_tickptr, tcg_env, offsetof(CPUSPARCState, tick));
+ translator_io_start(&dc->base);
+ gen_helper_tick_set_limit(r_tickptr, cpu_tick_cmpr);
+ /* End TB to handle timer interrupt */
+ dc->base.is_jmp = DISAS_EXIT;
+#else
+ qemu_build_not_reached();
+#endif
+}
+
+TRANS(WRTICK_CMPR, 64, do_wr_special, a, supervisor(dc), do_wrtick_cmpr)
+
+static void do_wrstick(DisasContext *dc, TCGv src)
+{
+#ifdef TARGET_SPARC64
+ TCGv_ptr r_tickptr = tcg_temp_new_ptr();
+
+ tcg_gen_ld_ptr(r_tickptr, tcg_env, offsetof(CPUSPARCState, stick));
+ translator_io_start(&dc->base);
+ gen_helper_tick_set_count(r_tickptr, src);
+ /* End TB to handle timer interrupt */
+ dc->base.is_jmp = DISAS_EXIT;
+#else
+ qemu_build_not_reached();
+#endif
+}
+
+TRANS(WRSTICK, 64, do_wr_special, a, supervisor(dc), do_wrstick)
+
+static void do_wrstick_cmpr(DisasContext *dc, TCGv src)
+{
+#ifdef TARGET_SPARC64
+ TCGv_ptr r_tickptr = tcg_temp_new_ptr();
+
+ tcg_gen_mov_tl(cpu_stick_cmpr, src);
+ tcg_gen_ld_ptr(r_tickptr, tcg_env, offsetof(CPUSPARCState, stick));
+ translator_io_start(&dc->base);
+ gen_helper_tick_set_limit(r_tickptr, cpu_stick_cmpr);
+ /* End TB to handle timer interrupt */
+ dc->base.is_jmp = DISAS_EXIT;
+#else
+ qemu_build_not_reached();
+#endif
+}
+
+TRANS(WRSTICK_CMPR, 64, do_wr_special, a, supervisor(dc), do_wrstick_cmpr)
+
+static void do_wrpowerdown(DisasContext *dc, TCGv src)
+{
+ save_state(dc);
+ gen_helper_power_down(tcg_env);
+}
+
+TRANS(WRPOWERDOWN, POWERDOWN, do_wr_special, a, supervisor(dc), do_wrpowerdown)
+
+static bool trans_NOP_v7(DisasContext *dc, arg_NOP_v7 *a)
+{
+ /*
+ * TODO: Need a feature bit for sparcv8.
+ * In the meantime, treat all 32-bit cpus like sparcv7.
+ */
+ if (avail_32(dc)) {
+ return advance_pc(dc);
+ }
+ return false;
+}
+
#define CHECK_IU_FEATURE(dc, FEATURE) \
if (!((dc)->def->features & CPU_FEATURE_ ## FEATURE)) \
goto illegal_insn;
@@ -4288,162 +4478,7 @@ static void disas_sparc_legacy(DisasContext *dc, unsigned int insn)
break;
#endif
case 0x30:
- {
- cpu_tmp0 = tcg_temp_new();
- switch(rd) {
- case 0: /* wry */
- tcg_gen_xor_tl(cpu_tmp0, cpu_src1, cpu_src2);
- tcg_gen_andi_tl(cpu_y, cpu_tmp0, 0xffffffff);
- break;
-#ifndef TARGET_SPARC64
- case 0x01 ... 0x0f: /* undefined in the
- SPARCv8 manual, nop
- on the microSPARC
- II */
- case 0x10 ... 0x1f: /* implementation-dependent
- in the SPARCv8
- manual, nop on the
- microSPARC II */
- if ((rd == 0x13) && (dc->def->features &
- CPU_FEATURE_POWERDOWN)) {
- /* LEON3 power-down */
- save_state(dc);
- gen_helper_power_down(tcg_env);
- }
- break;
-#else
- case 0x2: /* V9 wrccr */
- tcg_gen_xor_tl(cpu_tmp0, cpu_src1, cpu_src2);
- gen_helper_wrccr(tcg_env, cpu_tmp0);
- tcg_gen_movi_i32(cpu_cc_op, CC_OP_FLAGS);
- dc->cc_op = CC_OP_FLAGS;
- break;
- case 0x3: /* V9 wrasi */
- tcg_gen_xor_tl(cpu_tmp0, cpu_src1, cpu_src2);
- tcg_gen_andi_tl(cpu_tmp0, cpu_tmp0, 0xff);
- tcg_gen_st32_tl(cpu_tmp0, tcg_env,
- offsetof(CPUSPARCState, asi));
- /*
- * End TB to notice changed ASI.
- * TODO: Could notice src1 = %g0 and IS_IMM,
- * update DisasContext and not exit the TB.
- */
- save_state(dc);
- gen_op_next_insn();
- tcg_gen_lookup_and_goto_ptr();
- dc->base.is_jmp = DISAS_NORETURN;
- break;
- case 0x6: /* V9 wrfprs */
- tcg_gen_xor_tl(cpu_tmp0, cpu_src1, cpu_src2);
- tcg_gen_trunc_tl_i32(cpu_fprs, cpu_tmp0);
- dc->fprs_dirty = 0;
- save_state(dc);
- gen_op_next_insn();
- tcg_gen_exit_tb(NULL, 0);
- dc->base.is_jmp = DISAS_NORETURN;
- break;
- case 0xf: /* V9 sir, nop if user */
-#if !defined(CONFIG_USER_ONLY)
- if (supervisor(dc)) {
- ; // XXX
- }
-#endif
- break;
- case 0x13: /* Graphics Status */
- if (gen_trap_ifnofpu(dc)) {
- goto jmp_insn;
- }
- tcg_gen_xor_tl(cpu_gsr, cpu_src1, cpu_src2);
- break;
- case 0x14: /* Softint set */
- if (!supervisor(dc))
- goto illegal_insn;
- tcg_gen_xor_tl(cpu_tmp0, cpu_src1, cpu_src2);
- gen_helper_set_softint(tcg_env, cpu_tmp0);
- break;
- case 0x15: /* Softint clear */
- if (!supervisor(dc))
- goto illegal_insn;
- tcg_gen_xor_tl(cpu_tmp0, cpu_src1, cpu_src2);
- gen_helper_clear_softint(tcg_env, cpu_tmp0);
- break;
- case 0x16: /* Softint write */
- if (!supervisor(dc))
- goto illegal_insn;
- tcg_gen_xor_tl(cpu_tmp0, cpu_src1, cpu_src2);
- gen_helper_write_softint(tcg_env, cpu_tmp0);
- break;
- case 0x17: /* Tick compare */
-#if !defined(CONFIG_USER_ONLY)
- if (!supervisor(dc))
- goto illegal_insn;
-#endif
- {
- TCGv_ptr r_tickptr;
-
- tcg_gen_xor_tl(cpu_tick_cmpr, cpu_src1,
- cpu_src2);
- r_tickptr = tcg_temp_new_ptr();
- tcg_gen_ld_ptr(r_tickptr, tcg_env,
- offsetof(CPUSPARCState, tick));
- translator_io_start(&dc->base);
- gen_helper_tick_set_limit(r_tickptr,
- cpu_tick_cmpr);
- /* End TB to handle timer interrupt */
- dc->base.is_jmp = DISAS_EXIT;
- }
- break;
- case 0x18: /* System tick */
-#if !defined(CONFIG_USER_ONLY)
- if (!supervisor(dc))
- goto illegal_insn;
-#endif
- {
- TCGv_ptr r_tickptr;
-
- tcg_gen_xor_tl(cpu_tmp0, cpu_src1,
- cpu_src2);
- r_tickptr = tcg_temp_new_ptr();
- tcg_gen_ld_ptr(r_tickptr, tcg_env,
- offsetof(CPUSPARCState, stick));
- translator_io_start(&dc->base);
- gen_helper_tick_set_count(r_tickptr,
- cpu_tmp0);
- /* End TB to handle timer interrupt */
- dc->base.is_jmp = DISAS_EXIT;
- }
- break;
- case 0x19: /* System tick compare */
-#if !defined(CONFIG_USER_ONLY)
- if (!supervisor(dc))
- goto illegal_insn;
-#endif
- {
- TCGv_ptr r_tickptr;
-
- tcg_gen_xor_tl(cpu_stick_cmpr, cpu_src1,
- cpu_src2);
- r_tickptr = tcg_temp_new_ptr();
- tcg_gen_ld_ptr(r_tickptr, tcg_env,
- offsetof(CPUSPARCState, stick));
- translator_io_start(&dc->base);
- gen_helper_tick_set_limit(r_tickptr,
- cpu_stick_cmpr);
- /* End TB to handle timer interrupt */
- dc->base.is_jmp = DISAS_EXIT;
- }
- break;
-
- case 0x10: /* Performance Control */
- case 0x11: /* Performance Instrumentation
- Counter */
- case 0x12: /* Dispatch Control */
-#endif
- default:
- goto illegal_insn;
- }
- }
- break;
+ goto illegal_insn; /* WRASR in decodetree */
#if !defined(CONFIG_USER_ONLY)
case 0x31: /* wrpsr, V9 saved, restored */
{
Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- target/sparc/insns.decode | 33 +++- target/sparc/translate.c | 353 +++++++++++++++++++++----------------- 2 files changed, 226 insertions(+), 160 deletions(-)