Tested-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Acked-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
target/sparc/insns.decode | 22 +++
target/sparc/translate.c | 342 ++++++++++++++++++++++++--------------
2 files changed, 235 insertions(+), 129 deletions(-)
diff --git a/target/sparc/insns.decode b/target/sparc/insns.decode
index 0517f5591b..1b084c5b97 100644
--- a/target/sparc/insns.decode
+++ b/target/sparc/insns.decode
@@ -22,6 +22,28 @@ SETHI 00 rd:5 100 i:22
CALL 01 i:s30
+{
+ [
+ STBAR 10 00000 101000 01111 0 0000000000000
+ MEMBAR 10 00000 101000 01111 1 000000 cmask:3 mmask:4
+
+ RDCCR 10 rd:5 101000 00010 0 0000000000000
+ RDASI 10 rd:5 101000 00011 0 0000000000000
+ RDTICK 10 rd:5 101000 00100 0 0000000000000
+ RDPC 10 rd:5 101000 00101 0 0000000000000
+ RDFPRS 10 rd:5 101000 00110 0 0000000000000
+ RDASR17 10 rd:5 101000 10001 0 0000000000000
+ RDGSR 10 rd:5 101000 10011 0 0000000000000
+ RDSOFTINT 10 rd:5 101000 10110 0 0000000000000
+ RDTICK_CMPR 10 rd:5 101000 10111 0 0000000000000
+ RDSTICK 10 rd:5 101000 11000 0 0000000000000
+ RDSTICK_CMPR 10 rd:5 101000 11001 0 0000000000000
+ RDSTRAND_STATUS 10 rd:5 101000 11010 0 0000000000000
+ ]
+ # Before v8, all rs1 accepted; otherwise rs1==0.
+ RDY 10 rd:5 101000 rs1:5 0 0000000000000
+}
+
Tcc_r 10 0 cond:4 111010 rs1:5 0 cc:1 0000000 rs2:5
{
# For v7, the entire simm13 field is present, but masked to 7 bits.
diff --git a/target/sparc/translate.c b/target/sparc/translate.c
index b927b212ca..9af4578525 100644
--- a/target/sparc/translate.c
+++ b/target/sparc/translate.c
@@ -36,6 +36,11 @@
#include "exec/helper-info.c.inc"
#undef HELPER_H
+#ifndef TARGET_SPARC64
+# define gen_helper_rdccr(D, E) qemu_build_not_reached()
+# define gen_helper_tick_get_count(D, E, T, C) qemu_build_not_reached()
+#endif
+
/* Dynamic PC, must exit to main loop. */
#define DYNAMIC_PC 1
/* Dynamic PC, one of two values according to jump_pc[T2]. */
@@ -64,10 +69,21 @@ static TCGv cpu_tick_cmpr, cpu_stick_cmpr, cpu_hstick_cmpr;
static TCGv cpu_hintp, cpu_htba, cpu_hver, cpu_ssr, cpu_ver;
#else
static TCGv cpu_wim;
+# define cpu_fprs ({ qemu_build_not_reached(); (TCGv)NULL; })
+# define cpu_gsr ({ qemu_build_not_reached(); (TCGv)NULL; })
+# define cpu_tick_cmpr ({ qemu_build_not_reached(); (TCGv)NULL; })
+# define cpu_stick_cmpr ({ qemu_build_not_reached(); (TCGv)NULL; })
#endif
/* Floating point registers */
static TCGv_i64 cpu_fpr[TARGET_DPREGS];
+#define env_field_offsetof(X) offsetof(CPUSPARCState, X)
+#ifdef TARGET_SPARC64
+# define env64_field_offsetof(X) env_field_offsetof(X)
+#else
+# define env64_field_offsetof(X) ({ qemu_build_not_reached(); 0; })
+#endif
+
typedef struct DisasDelayException {
struct DisasDelayException *next;
TCGLabel *lab;
@@ -2842,10 +2858,14 @@ static void gen_faligndata(TCGv dst, TCGv gsr, TCGv s1, TCGv s2)
#define avail_ALL(C) true
#ifdef TARGET_SPARC64
# define avail_32(C) false
+# define avail_ASR17(C) false
# define avail_64(C) true
+# define avail_HYPV(C) ((C)->def->features & CPU_FEATURE_HYPV)
#else
# define avail_32(C) true
+# define avail_ASR17(C) ((C)->def->features & CPU_FEATURE_ASR17)
# define avail_64(C) false
+# define avail_HYPV(C) false
#endif
/* Default case for non jump instructions. */
@@ -2947,6 +2967,12 @@ static bool advance_jump_cond(DisasContext *dc, DisasCompare *cmp,
return true;
}
+static bool raise_priv(DisasContext *dc)
+{
+ gen_exception(dc, TT_PRIV_INSN);
+ return true;
+}
+
static bool do_bpcc(DisasContext *dc, arg_bcc *a)
{
target_long target = address_mask_i(dc, dc->pc + a->i * 4);
@@ -3117,6 +3143,183 @@ static bool trans_Tcc_i_v9(DisasContext *dc, arg_Tcc_i_v9 *a)
return do_tcc(dc, a->cond, a->cc, a->rs1, true, a->i);
}
+static bool trans_STBAR(DisasContext *dc, arg_STBAR *a)
+{
+ tcg_gen_mb(TCG_MO_ST_ST | TCG_BAR_SC);
+ return advance_pc(dc);
+}
+
+static bool trans_MEMBAR(DisasContext *dc, arg_MEMBAR *a)
+{
+ if (avail_32(dc)) {
+ return false;
+ }
+ if (a->mmask) {
+ /* Note TCG_MO_* was modeled on sparc64, so mmask matches. */
+ tcg_gen_mb(a->mmask | TCG_BAR_SC);
+ }
+ if (a->cmask) {
+ /* For #Sync, etc, end the TB to recognize interrupts. */
+ dc->base.is_jmp = DISAS_EXIT;
+ }
+ return advance_pc(dc);
+}
+
+static bool do_rd_special(DisasContext *dc, bool priv, int rd,
+ TCGv (*func)(DisasContext *, TCGv))
+{
+ if (!priv) {
+ return raise_priv(dc);
+ }
+ gen_store_gpr(dc, rd, func(dc, gen_dest_gpr(dc, rd)));
+ return advance_pc(dc);
+}
+
+static TCGv do_rdy(DisasContext *dc, TCGv dst)
+{
+ return cpu_y;
+}
+
+static bool trans_RDY(DisasContext *dc, arg_RDY *a)
+{
+ /*
+ * TODO: Need a feature bit for sparcv8. In the meantime, treat all
+ * 32-bit cpus like sparcv7, which ignores the rs1 field.
+ * This matches after all other ASR, so Leon3 Asr17 is handled first.
+ */
+ if (avail_64(dc) && a->rs1 != 0) {
+ return false;
+ }
+ return do_rd_special(dc, true, a->rd, do_rdy);
+}
+
+static TCGv do_rd_leon3_config(DisasContext *dc, TCGv dst)
+{
+ uint32_t val;
+
+ /*
+ * TODO: There are many more fields to be filled,
+ * some of which are writable.
+ */
+ val = dc->def->nwindows - 1; /* [4:0] NWIN */
+ val |= 1 << 8; /* [8] V8 */
+
+ return tcg_constant_tl(val);
+}
+
+TRANS(RDASR17, ASR17, do_rd_special, true, a->rd, do_rd_leon3_config)
+
+static TCGv do_rdccr(DisasContext *dc, TCGv dst)
+{
+ update_psr(dc);
+ gen_helper_rdccr(dst, tcg_env);
+ return dst;
+}
+
+TRANS(RDCCR, 64, do_rd_special, true, a->rd, do_rdccr)
+
+static TCGv do_rdasi(DisasContext *dc, TCGv dst)
+{
+#ifdef TARGET_SPARC64
+ return tcg_constant_tl(dc->asi);
+#else
+ qemu_build_not_reached();
+#endif
+}
+
+TRANS(RDASI, 64, do_rd_special, true, a->rd, do_rdasi)
+
+static TCGv do_rdtick(DisasContext *dc, TCGv dst)
+{
+ TCGv_ptr r_tickptr = tcg_temp_new_ptr();
+
+ tcg_gen_ld_ptr(r_tickptr, tcg_env, env64_field_offsetof(tick));
+ if (translator_io_start(&dc->base)) {
+ dc->base.is_jmp = DISAS_EXIT;
+ }
+ gen_helper_tick_get_count(dst, tcg_env, r_tickptr,
+ tcg_constant_i32(dc->mem_idx));
+ return dst;
+}
+
+/* TODO: non-priv access only allowed when enabled. */
+TRANS(RDTICK, 64, do_rd_special, true, a->rd, do_rdtick)
+
+static TCGv do_rdpc(DisasContext *dc, TCGv dst)
+{
+ return tcg_constant_tl(address_mask_i(dc, dc->pc));
+}
+
+TRANS(RDPC, 64, do_rd_special, true, a->rd, do_rdpc)
+
+static TCGv do_rdfprs(DisasContext *dc, TCGv dst)
+{
+ tcg_gen_ext_i32_tl(dst, cpu_fprs);
+ return dst;
+}
+
+TRANS(RDFPRS, 64, do_rd_special, true, a->rd, do_rdfprs)
+
+static TCGv do_rdgsr(DisasContext *dc, TCGv dst)
+{
+ gen_trap_ifnofpu(dc);
+ return cpu_gsr;
+}
+
+TRANS(RDGSR, 64, do_rd_special, true, a->rd, do_rdgsr)
+
+static TCGv do_rdsoftint(DisasContext *dc, TCGv dst)
+{
+ tcg_gen_ld32s_tl(dst, tcg_env, env64_field_offsetof(softint));
+ return dst;
+}
+
+TRANS(RDSOFTINT, 64, do_rd_special, supervisor(dc), a->rd, do_rdsoftint)
+
+static TCGv do_rdtick_cmpr(DisasContext *dc, TCGv dst)
+{
+ return cpu_tick_cmpr;
+}
+
+/* TODO: non-priv access only allowed when enabled. */
+TRANS(RDTICK_CMPR, 64, do_rd_special, true, a->rd, do_rdtick_cmpr)
+
+static TCGv do_rdstick(DisasContext *dc, TCGv dst)
+{
+ TCGv_ptr r_tickptr = tcg_temp_new_ptr();
+
+ tcg_gen_ld_ptr(r_tickptr, tcg_env, env64_field_offsetof(stick));
+ if (translator_io_start(&dc->base)) {
+ dc->base.is_jmp = DISAS_EXIT;
+ }
+ gen_helper_tick_get_count(dst, tcg_env, r_tickptr,
+ tcg_constant_i32(dc->mem_idx));
+ return dst;
+}
+
+/* TODO: non-priv access only allowed when enabled. */
+TRANS(RDSTICK, 64, do_rd_special, true, a->rd, do_rdstick)
+
+static TCGv do_rdstick_cmpr(DisasContext *dc, TCGv dst)
+{
+ return cpu_stick_cmpr;
+}
+
+/* TODO: supervisor access only allowed when enabled by hypervisor. */
+TRANS(RDSTICK_CMPR, 64, do_rd_special, supervisor(dc), a->rd, do_rdstick_cmpr)
+
+/*
+ * UltraSPARC-T1 Strand status.
+ * HYPV check maybe not enough, UA2005 & UA2007 describe
+ * this ASR as impl. dep
+ */
+static TCGv do_rdstrand_status(DisasContext *dc, TCGv dst)
+{
+ return tcg_constant_tl(1);
+}
+
+TRANS(RDSTRAND_STATUS, HYPV, do_rd_special, true, a->rd, do_rdstrand_status)
+
#define CHECK_IU_FEATURE(dc, FEATURE) \
if (!((dc)->def->features & CPU_FEATURE_ ## FEATURE)) \
goto illegal_insn;
@@ -3143,134 +3346,12 @@ static void disas_sparc_legacy(DisasContext *dc, unsigned int insn)
g_assert_not_reached(); /* in decodetree */
case 2: /* FPU & Logical Operations */
{
- unsigned int xop = GET_FIELD(insn, 7, 12);
- TCGv cpu_dst = tcg_temp_new();
- TCGv cpu_tmp0;
+ unsigned int xop __attribute__((unused)) = GET_FIELD(insn, 7, 12);
+ TCGv cpu_dst __attribute__((unused)) = tcg_temp_new();
+ TCGv cpu_tmp0 __attribute__((unused));
- if (xop == 0x28) {
- rs1 = GET_FIELD(insn, 13, 17);
- switch(rs1) {
- case 0: /* rdy */
-#ifndef TARGET_SPARC64
- case 0x01 ... 0x0e: /* undefined in the SPARCv8
- manual, rdy on the microSPARC
- II */
- case 0x0f: /* stbar in the SPARCv8 manual,
- rdy on the microSPARC II */
- case 0x10 ... 0x1f: /* implementation-dependent in the
- SPARCv8 manual, rdy on the
- microSPARC II */
- /* Read Asr17 */
- if (rs1 == 0x11 && dc->def->features & CPU_FEATURE_ASR17) {
- TCGv t = gen_dest_gpr(dc, rd);
- /* Read Asr17 for a Leon3 monoprocessor */
- tcg_gen_movi_tl(t, (1 << 8) | (dc->def->nwindows - 1));
- gen_store_gpr(dc, rd, t);
- break;
- }
-#endif
- gen_store_gpr(dc, rd, cpu_y);
- break;
-#ifdef TARGET_SPARC64
- case 0x2: /* V9 rdccr */
- update_psr(dc);
- gen_helper_rdccr(cpu_dst, tcg_env);
- gen_store_gpr(dc, rd, cpu_dst);
- break;
- case 0x3: /* V9 rdasi */
- tcg_gen_movi_tl(cpu_dst, dc->asi);
- gen_store_gpr(dc, rd, cpu_dst);
- break;
- case 0x4: /* V9 rdtick */
- {
- TCGv_ptr r_tickptr;
- TCGv_i32 r_const;
-
- r_tickptr = tcg_temp_new_ptr();
- r_const = tcg_constant_i32(dc->mem_idx);
- tcg_gen_ld_ptr(r_tickptr, tcg_env,
- offsetof(CPUSPARCState, tick));
- if (translator_io_start(&dc->base)) {
- dc->base.is_jmp = DISAS_EXIT;
- }
- gen_helper_tick_get_count(cpu_dst, tcg_env, r_tickptr,
- r_const);
- gen_store_gpr(dc, rd, cpu_dst);
- }
- break;
- case 0x5: /* V9 rdpc */
- {
- TCGv t = gen_dest_gpr(dc, rd);
- if (unlikely(AM_CHECK(dc))) {
- tcg_gen_movi_tl(t, dc->pc & 0xffffffffULL);
- } else {
- tcg_gen_movi_tl(t, dc->pc);
- }
- gen_store_gpr(dc, rd, t);
- }
- break;
- case 0x6: /* V9 rdfprs */
- tcg_gen_ext_i32_tl(cpu_dst, cpu_fprs);
- gen_store_gpr(dc, rd, cpu_dst);
- break;
- case 0xf: /* V9 membar */
- break; /* no effect */
- case 0x13: /* Graphics Status */
- if (gen_trap_ifnofpu(dc)) {
- goto jmp_insn;
- }
- gen_store_gpr(dc, rd, cpu_gsr);
- break;
- case 0x16: /* Softint */
- tcg_gen_ld32s_tl(cpu_dst, tcg_env,
- offsetof(CPUSPARCState, softint));
- gen_store_gpr(dc, rd, cpu_dst);
- break;
- case 0x17: /* Tick compare */
- gen_store_gpr(dc, rd, cpu_tick_cmpr);
- break;
- case 0x18: /* System tick */
- {
- TCGv_ptr r_tickptr;
- TCGv_i32 r_const;
-
- r_tickptr = tcg_temp_new_ptr();
- r_const = tcg_constant_i32(dc->mem_idx);
- tcg_gen_ld_ptr(r_tickptr, tcg_env,
- offsetof(CPUSPARCState, stick));
- if (translator_io_start(&dc->base)) {
- dc->base.is_jmp = DISAS_EXIT;
- }
- gen_helper_tick_get_count(cpu_dst, tcg_env, r_tickptr,
- r_const);
- gen_store_gpr(dc, rd, cpu_dst);
- }
- break;
- case 0x19: /* System tick compare */
- gen_store_gpr(dc, rd, cpu_stick_cmpr);
- break;
- case 0x1a: /* UltraSPARC-T1 Strand status */
- /* XXX HYPV check maybe not enough, UA2005 & UA2007 describe
- * this ASR as impl. dep
- */
- CHECK_IU_FEATURE(dc, HYPV);
- {
- TCGv t = gen_dest_gpr(dc, rd);
- tcg_gen_movi_tl(t, 1UL);
- gen_store_gpr(dc, rd, t);
- }
- break;
- case 0x10: /* Performance Control */
- case 0x11: /* Performance Instrumentation Counter */
- case 0x12: /* Dispatch Control */
- case 0x14: /* Softint set, WO */
- case 0x15: /* Softint clear, WO */
-#endif
- default:
- goto illegal_insn;
- }
#if !defined(CONFIG_USER_ONLY)
- } else if (xop == 0x29) { /* rdpsr / UA2005 rdhpr */
+ if (xop == 0x29) { /* rdpsr / UA2005 rdhpr */
#ifndef TARGET_SPARC64
if (!supervisor(dc)) {
goto priv_insn;
@@ -3308,7 +3389,8 @@ static void disas_sparc_legacy(DisasContext *dc, unsigned int insn)
#endif
gen_store_gpr(dc, rd, cpu_dst);
break;
- } else if (xop == 0x2a) { /* rdwim / V9 rdpr */
+ }
+ if (xop == 0x2a) { /* rdwim / V9 rdpr */
if (!supervisor(dc)) {
goto priv_insn;
}
@@ -3432,9 +3514,10 @@ static void disas_sparc_legacy(DisasContext *dc, unsigned int insn)
#endif
gen_store_gpr(dc, rd, cpu_tmp0);
break;
+ }
#endif
#if defined(TARGET_SPARC64) || !defined(CONFIG_USER_ONLY)
- } else if (xop == 0x2b) { /* rdtbr / V9 flushw */
+ if (xop == 0x2b) { /* rdtbr / V9 flushw */
#ifdef TARGET_SPARC64
gen_helper_flushw(tcg_env);
#else
@@ -3443,8 +3526,9 @@ static void disas_sparc_legacy(DisasContext *dc, unsigned int insn)
gen_store_gpr(dc, rd, cpu_tbr);
#endif
break;
+ }
#endif
- } else if (xop == 0x34) { /* FPU Operations */
+ if (xop == 0x34) { /* FPU Operations */
if (gen_trap_ifnofpu(dc)) {
goto jmp_insn;
}
--
2.34.1