aboutsummaryrefslogtreecommitdiff
path: root/target/sparc
diff options
context:
space:
mode:
Diffstat (limited to 'target/sparc')
-rw-r--r--target/sparc/cpu.c16
-rw-r--r--target/sparc/cpu.h1
-rw-r--r--target/sparc/fop_helper.c1
-rw-r--r--target/sparc/helper.c1
-rw-r--r--target/sparc/insns.decode83
-rw-r--r--target/sparc/int32_helper.c2
-rw-r--r--target/sparc/int64_helper.c7
-rw-r--r--target/sparc/translate.c83
8 files changed, 123 insertions, 71 deletions
diff --git a/target/sparc/cpu.c b/target/sparc/cpu.c
index 2a3e408..c9773f1 100644
--- a/target/sparc/cpu.c
+++ b/target/sparc/cpu.c
@@ -783,7 +783,7 @@ static void sparc_restore_state_to_opc(CPUState *cs,
#ifndef CONFIG_USER_ONLY
static bool sparc_cpu_has_work(CPUState *cs)
{
- return (cs->interrupt_request & CPU_INTERRUPT_HARD) &&
+ return cpu_test_interrupt(cs, CPU_INTERRUPT_HARD) &&
cpu_interrupts_enabled(cpu_env(cs));
}
#endif /* !CONFIG_USER_ONLY */
@@ -1002,6 +1002,18 @@ static const struct SysemuCPUOps sparc_sysemu_ops = {
#ifdef CONFIG_TCG
#include "accel/tcg/cpu-ops.h"
+#ifndef CONFIG_USER_ONLY
+static vaddr sparc_pointer_wrap(CPUState *cs, int mmu_idx,
+ vaddr result, vaddr base)
+{
+#ifdef TARGET_SPARC64
+ return cpu_env(cs)->pstate & PS_AM ? (uint32_t)result : result;
+#else
+ return (uint32_t)result;
+#endif
+}
+#endif
+
static const TCGCPUOps sparc_tcg_ops = {
/*
* From Oracle SPARC Architecture 2015:
@@ -1036,6 +1048,7 @@ static const TCGCPUOps sparc_tcg_ops = {
#ifndef CONFIG_USER_ONLY
.tlb_fill = sparc_cpu_tlb_fill,
+ .pointer_wrap = sparc_pointer_wrap,
.cpu_exec_interrupt = sparc_cpu_exec_interrupt,
.cpu_exec_halt = sparc_cpu_has_work,
.cpu_exec_reset = cpu_reset,
@@ -1077,6 +1090,7 @@ static void sparc_cpu_class_init(ObjectClass *oc, const void *data)
cc->disas_set_info = cpu_sparc_disas_set_info;
#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
+ cc->gdb_core_xml_file = "sparc64-core.xml";
cc->gdb_num_core_regs = 86;
#else
cc->gdb_num_core_regs = 72;
diff --git a/target/sparc/cpu.h b/target/sparc/cpu.h
index 31cb3d9..7169a50 100644
--- a/target/sparc/cpu.h
+++ b/target/sparc/cpu.h
@@ -3,7 +3,6 @@
#include "qemu/bswap.h"
#include "cpu-qom.h"
-#include "exec/cpu-common.h"
#include "exec/cpu-defs.h"
#include "exec/cpu-interrupt.h"
#include "qemu/cpu-float.h"
diff --git a/target/sparc/fop_helper.c b/target/sparc/fop_helper.c
index a493341..29fd166 100644
--- a/target/sparc/fop_helper.c
+++ b/target/sparc/fop_helper.c
@@ -445,7 +445,6 @@ static uint32_t finish_fcmp(CPUSPARCState *env, FloatRelation r, uintptr_t ra)
case float_relation_greater:
return 2;
case float_relation_unordered:
- env->fsr |= FSR_NVA;
return 3;
}
g_assert_not_reached();
diff --git a/target/sparc/helper.c b/target/sparc/helper.c
index 9163b9d..c5d88de 100644
--- a/target/sparc/helper.c
+++ b/target/sparc/helper.c
@@ -21,6 +21,7 @@
#include "cpu.h"
#include "qemu/timer.h"
#include "qemu/host-utils.h"
+#include "exec/cpu-common.h"
#include "exec/helper-proto.h"
void cpu_raise_exception_ra(CPUSPARCState *env, int tt, uintptr_t ra)
diff --git a/target/sparc/insns.decode b/target/sparc/insns.decode
index 9e39d23..242ec42 100644
--- a/target/sparc/insns.decode
+++ b/target/sparc/insns.decode
@@ -88,9 +88,10 @@ CALL 01 i:s30
{
[
- STBAR 10 00000 101000 01111 0 0000000000000
+ STBAR_v9 10 00000 101000 01111 0 0000000000000
MEMBAR 10 00000 101000 01111 1 000000 cmask:3 mmask:4
+ RDY_v9 10 rd:5 101000 00000 0 0000000000000
RDCCR 10 rd:5 101000 00010 0 0000000000000
RDASI 10 rd:5 101000 00011 0 0000000000000
RDTICK 10 rd:5 101000 00100 0 0000000000000
@@ -107,8 +108,26 @@ CALL 01 i:s30
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
+
+ # The v8 manual, section B.30 STBAR instruction, says
+ # bits [12:0] are ignored, but bit 13 must be 0.
+ # However, section B.28 Read State Register Instruction has a
+ # comment that RDASR with rs1 = 15, rd = 0 is STBAR. Here,
+ # bit 13 is also ignored and rd != 0 is merely reserved.
+ #
+ # Solaris 8 executes v9 MEMBAR instruction 0x8143e008 during boot.
+ # This confirms that bit 13 is ignored, as 0x8143c000 is STBAR.
+ STBAR_v8 10 ----- 101000 01111 - -------------
+
+ # For v7, bits [18:0] are ignored.
+ # For v8, bits [18:14], aka rs1, are repurposed and rs1 = 0 is RDY,
+ # and other values are RDASR. However, the v8 manual explicitly
+ # says that rs1 in 1..14 yield undefined results and do not cause
+ # an illegal instruction trap, and rs1 in 16..31 are available for
+ # implementation specific usage.
+ # Implement not causing an illegal instruction trap for v8 by
+ # continuing to interpret unused values per v7, i.e. as RDY.
+ RDY_v7 10 rd:5 101000 ----- - -------------
}
{
@@ -139,14 +158,16 @@ CALL 01 i:s30
}
{
- RDPSR 10 rd:5 101001 00000 0 0000000000000
- RDHPR_hpstate 10 rd:5 101001 00000 0 0000000000000
+ [
+ RDHPR_hpstate 10 rd:5 101001 00000 0 0000000000000
+ RDHPR_htstate 10 rd:5 101001 00001 0 0000000000000
+ RDHPR_hintp 10 rd:5 101001 00011 0 0000000000000
+ RDHPR_htba 10 rd:5 101001 00101 0 0000000000000
+ RDHPR_hver 10 rd:5 101001 00110 0 0000000000000
+ RDHPR_hstick_cmpr 10 rd:5 101001 11111 0 0000000000000
+ ]
+ RDPSR 10 rd:5 101001 ----- - -------------
}
-RDHPR_htstate 10 rd:5 101001 00001 0 0000000000000
-RDHPR_hintp 10 rd:5 101001 00011 0 0000000000000
-RDHPR_htba 10 rd:5 101001 00101 0 0000000000000
-RDHPR_hver 10 rd:5 101001 00110 0 0000000000000
-RDHPR_hstick_cmpr 10 rd:5 101001 11111 0 0000000000000
{
WRPSR 10 00000 110001 ..... . ............. @n_r_ri
@@ -159,26 +180,28 @@ RESTORED 10 00001 110001 00000 0 0000000000000
# UA2005 INVALW
{
- RDWIM 10 rd:5 101010 00000 0 0000000000000
- RDPR_tpc 10 rd:5 101010 00000 0 0000000000000
+ [
+ RDPR_tpc 10 rd:5 101010 00000 0 0000000000000
+ RDPR_tnpc 10 rd:5 101010 00001 0 0000000000000
+ RDPR_tstate 10 rd:5 101010 00010 0 0000000000000
+ RDPR_tt 10 rd:5 101010 00011 0 0000000000000
+ RDPR_tick 10 rd:5 101010 00100 0 0000000000000
+ RDPR_tba 10 rd:5 101010 00101 0 0000000000000
+ RDPR_pstate 10 rd:5 101010 00110 0 0000000000000
+ RDPR_tl 10 rd:5 101010 00111 0 0000000000000
+ RDPR_pil 10 rd:5 101010 01000 0 0000000000000
+ RDPR_cwp 10 rd:5 101010 01001 0 0000000000000
+ RDPR_cansave 10 rd:5 101010 01010 0 0000000000000
+ RDPR_canrestore 10 rd:5 101010 01011 0 0000000000000
+ RDPR_cleanwin 10 rd:5 101010 01100 0 0000000000000
+ RDPR_otherwin 10 rd:5 101010 01101 0 0000000000000
+ RDPR_wstate 10 rd:5 101010 01110 0 0000000000000
+ RDPR_gl 10 rd:5 101010 10000 0 0000000000000
+ RDPR_strand_status 10 rd:5 101010 11010 0 0000000000000
+ RDPR_ver 10 rd:5 101010 11111 0 0000000000000
+ ]
+ RDWIM 10 rd:5 101010 ----- - -------------
}
-RDPR_tnpc 10 rd:5 101010 00001 0 0000000000000
-RDPR_tstate 10 rd:5 101010 00010 0 0000000000000
-RDPR_tt 10 rd:5 101010 00011 0 0000000000000
-RDPR_tick 10 rd:5 101010 00100 0 0000000000000
-RDPR_tba 10 rd:5 101010 00101 0 0000000000000
-RDPR_pstate 10 rd:5 101010 00110 0 0000000000000
-RDPR_tl 10 rd:5 101010 00111 0 0000000000000
-RDPR_pil 10 rd:5 101010 01000 0 0000000000000
-RDPR_cwp 10 rd:5 101010 01001 0 0000000000000
-RDPR_cansave 10 rd:5 101010 01010 0 0000000000000
-RDPR_canrestore 10 rd:5 101010 01011 0 0000000000000
-RDPR_cleanwin 10 rd:5 101010 01100 0 0000000000000
-RDPR_otherwin 10 rd:5 101010 01101 0 0000000000000
-RDPR_wstate 10 rd:5 101010 01110 0 0000000000000
-RDPR_gl 10 rd:5 101010 10000 0 0000000000000
-RDPR_strand_status 10 rd:5 101010 11010 0 0000000000000
-RDPR_ver 10 rd:5 101010 11111 0 0000000000000
{
WRWIM 10 00000 110010 ..... . ............. @n_r_ri
@@ -203,7 +226,7 @@ WRPR_strand_status 10 11010 110010 ..... . ............. @n_r_ri
{
FLUSHW 10 00000 101011 00000 0 0000000000000
- RDTBR 10 rd:5 101011 00000 0 0000000000000
+ RDTBR 10 rd:5 101011 ----- - -------------
}
{
diff --git a/target/sparc/int32_helper.c b/target/sparc/int32_helper.c
index 39db4ff..fdcaa0a 100644
--- a/target/sparc/int32_helper.c
+++ b/target/sparc/int32_helper.c
@@ -65,6 +65,7 @@ static const char *excp_name_str(int32_t exception_index)
return excp_names[exception_index];
}
+#if !defined(CONFIG_USER_ONLY)
void cpu_check_irqs(CPUSPARCState *env)
{
CPUState *cs;
@@ -96,6 +97,7 @@ void cpu_check_irqs(CPUSPARCState *env)
cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
}
}
+#endif
void sparc_cpu_do_interrupt(CPUState *cs)
{
diff --git a/target/sparc/int64_helper.c b/target/sparc/int64_helper.c
index bd14c7a..96ef81c 100644
--- a/target/sparc/int64_helper.c
+++ b/target/sparc/int64_helper.c
@@ -20,6 +20,7 @@
#include "qemu/osdep.h"
#include "qemu/main-loop.h"
#include "cpu.h"
+#include "exec/cpu-common.h"
#include "exec/helper-proto.h"
#include "exec/log.h"
#include "trace.h"
@@ -62,6 +63,7 @@ static const char * const excp_names[0x80] = {
};
#endif
+#if !defined(CONFIG_USER_ONLY)
void cpu_check_irqs(CPUSPARCState *env)
{
CPUState *cs;
@@ -89,7 +91,7 @@ void cpu_check_irqs(CPUSPARCState *env)
* the next bit is (2 << psrpil).
*/
if (pil < (2 << env->psrpil)) {
- if (cs->interrupt_request & CPU_INTERRUPT_HARD) {
+ if (cpu_test_interrupt(cs, CPU_INTERRUPT_HARD)) {
trace_sparc64_cpu_check_irqs_reset_irq(env->interrupt_index);
env->interrupt_index = 0;
cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
@@ -120,13 +122,14 @@ void cpu_check_irqs(CPUSPARCState *env)
break;
}
}
- } else if (cs->interrupt_request & CPU_INTERRUPT_HARD) {
+ } else if (cpu_test_interrupt(cs, CPU_INTERRUPT_HARD)) {
trace_sparc64_cpu_check_irqs_disabled(pil, env->pil_in, env->softint,
env->interrupt_index);
env->interrupt_index = 0;
cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
}
}
+#endif
void sparc_cpu_do_interrupt(CPUState *cs)
{
diff --git a/target/sparc/translate.c b/target/sparc/translate.c
index b922e53..d6b599b 100644
--- a/target/sparc/translate.c
+++ b/target/sparc/translate.c
@@ -363,15 +363,15 @@ static bool use_goto_tb(DisasContext *s, target_ulong pc, target_ulong npc)
translator_use_goto_tb(&s->base, npc);
}
-static void gen_goto_tb(DisasContext *s, int tb_num,
+static void gen_goto_tb(DisasContext *s, unsigned tb_slot_idx,
target_ulong pc, target_ulong npc)
{
if (use_goto_tb(s, pc, npc)) {
/* jump to same page: we can use a direct jump */
- tcg_gen_goto_tb(tb_num);
+ tcg_gen_goto_tb(tb_slot_idx);
tcg_gen_movi_tl(cpu_pc, pc);
tcg_gen_movi_tl(cpu_npc, npc);
- tcg_gen_exit_tb(s->base.tb, tb_num);
+ tcg_gen_exit_tb(s->base.tb, tb_slot_idx);
} else {
/* jump to another page: we can use an indirect jump */
tcg_gen_movi_tl(cpu_pc, pc);
@@ -2487,7 +2487,7 @@ static int extract_qfpreg(DisasContext *dc, int x)
#define TRANS(NAME, AVAIL, FUNC, ...) \
static bool trans_##NAME(DisasContext *dc, arg_##NAME *a) \
- { return avail_##AVAIL(dc) && FUNC(dc, __VA_ARGS__); }
+ { return avail_##AVAIL(dc) && FUNC(dc, ## __VA_ARGS__); }
#define avail_ALL(C) true
#ifdef TARGET_SPARC64
@@ -2526,6 +2526,32 @@ static int extract_qfpreg(DisasContext *dc, int x)
# define avail_VIS4(C) false
#endif
+/*
+ * We decoded bit 13 as imm, and bits [12:0] as rs2_or_imm.
+ * For v9, if !imm, then the unused bits [12:5] must be zero.
+ * For v7 and v8, the unused bits are ignored; clear them here.
+ */
+static bool check_rs2(DisasContext *dc, int *rs2)
+{
+ if (unlikely(*rs2 & ~0x1f)) {
+ if (avail_64(dc)) {
+ return false;
+ }
+ *rs2 &= 0x1f;
+ }
+ return true;
+}
+
+static bool check_r_r_ri(DisasContext *dc, arg_r_r_ri *a)
+{
+ return a->imm || check_rs2(dc, &a->rs2_or_imm);
+}
+
+static bool check_r_r_ri_cc(DisasContext *dc, arg_r_r_ri_cc *a)
+{
+ return a->imm || check_rs2(dc, &a->rs2_or_imm);
+}
+
/* Default case for non jump instructions. */
static bool advance_pc(DisasContext *dc)
{
@@ -2823,12 +2849,15 @@ 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)
+static bool do_stbar(DisasContext *dc)
{
tcg_gen_mb(TCG_MO_ST_ST | TCG_BAR_SC);
return advance_pc(dc);
}
+TRANS(STBAR_v8, 32, do_stbar)
+TRANS(STBAR_v9, 64, do_stbar)
+
static bool trans_MEMBAR(DisasContext *dc, arg_MEMBAR *a)
{
if (avail_32(dc)) {
@@ -2860,18 +2889,8 @@ 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);
-}
+TRANS(RDY_v7, 32, do_rd_special, true, a->rd, do_rdy)
+TRANS(RDY_v9, 64, do_rd_special, true, a->rd, do_rdy)
static TCGv do_rd_leon3_config(DisasContext *dc, TCGv dst)
{
@@ -3256,8 +3275,7 @@ static bool do_wr_special(DisasContext *dc, arg_r_r_ri *a, bool priv,
{
TCGv src;
- /* For simplicity, we under-decoded the rs2 form. */
- if (!a->imm && (a->rs2_or_imm & ~0x1f)) {
+ if (!check_r_r_ri(dc, a)) {
return false;
}
if (!priv) {
@@ -3700,8 +3718,7 @@ static bool do_arith_int(DisasContext *dc, arg_r_r_ri_cc *a,
{
TCGv dst, src1;
- /* For simplicity, we under-decoded the rs2 form. */
- if (!a->imm && a->rs2_or_imm & ~0x1f) {
+ if (!check_r_r_ri_cc(dc, a)) {
return false;
}
@@ -3785,11 +3802,11 @@ static bool trans_OR(DisasContext *dc, arg_r_r_ri_cc *a)
{
/* OR with %g0 is the canonical alias for MOV. */
if (!a->cc && a->rs1 == 0) {
+ if (!check_r_r_ri_cc(dc, a)) {
+ return false;
+ }
if (a->imm || a->rs2_or_imm == 0) {
gen_store_gpr(dc, a->rd, tcg_constant_tl(a->rs2_or_imm));
- } else if (a->rs2_or_imm & ~0x1f) {
- /* For simplicity, we under-decoded the rs2 form. */
- return false;
} else {
gen_store_gpr(dc, a->rd, cpu_regs[a->rs2_or_imm]);
}
@@ -3806,8 +3823,7 @@ static bool trans_UDIV(DisasContext *dc, arg_r_r_ri *a)
if (!avail_DIV(dc)) {
return false;
}
- /* For simplicity, we under-decoded the rs2 form. */
- if (!a->imm && a->rs2_or_imm & ~0x1f) {
+ if (!check_r_r_ri(dc, a)) {
return false;
}
@@ -3858,8 +3874,7 @@ static bool trans_UDIVX(DisasContext *dc, arg_r_r_ri *a)
if (!avail_64(dc)) {
return false;
}
- /* For simplicity, we under-decoded the rs2 form. */
- if (!a->imm && a->rs2_or_imm & ~0x1f) {
+ if (!check_r_r_ri(dc, a)) {
return false;
}
@@ -3896,8 +3911,7 @@ static bool trans_SDIVX(DisasContext *dc, arg_r_r_ri *a)
if (!avail_64(dc)) {
return false;
}
- /* For simplicity, we under-decoded the rs2 form. */
- if (!a->imm && a->rs2_or_imm & ~0x1f) {
+ if (!check_r_r_ri(dc, a)) {
return false;
}
@@ -4193,8 +4207,7 @@ TRANS(SRA_i, ALL, do_shift_i, a, false, false)
static TCGv gen_rs2_or_imm(DisasContext *dc, bool imm, int rs2_or_imm)
{
- /* For simplicity, we under-decoded the rs2 form. */
- if (!imm && rs2_or_imm & ~0x1f) {
+ if (!imm && !check_rs2(dc, &rs2_or_imm)) {
return NULL;
}
if (imm || rs2_or_imm == 0) {
@@ -4257,8 +4270,7 @@ static bool do_add_special(DisasContext *dc, arg_r_r_ri *a,
{
TCGv src1, sum;
- /* For simplicity, we under-decoded the rs2 form. */
- if (!a->imm && a->rs2_or_imm & ~0x1f) {
+ if (!check_r_r_ri(dc, a)) {
return false;
}
@@ -4376,8 +4388,7 @@ static TCGv gen_ldst_addr(DisasContext *dc, int rs1, bool imm, int rs2_or_imm)
{
TCGv addr, tmp = NULL;
- /* For simplicity, we under-decoded the rs2 form. */
- if (!imm && rs2_or_imm & ~0x1f) {
+ if (!imm && !check_rs2(dc, &rs2_or_imm)) {
return NULL;
}