aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--target-sparc/cpu.h39
-rw-r--r--target-sparc/op.c5
-rw-r--r--target-sparc/op_helper.c98
-rw-r--r--target-sparc/translate.c27
4 files changed, 121 insertions, 48 deletions
diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h
index e9699cfdc4..51cbd4c328 100644
--- a/target-sparc/cpu.h
+++ b/target-sparc/cpu.h
@@ -98,6 +98,8 @@
#define PS_AG (1<<0)
#define FPRS_FEF (1<<2)
+
+#define HS_PRIV (1<<2)
#endif
/* Fcc */
@@ -166,7 +168,11 @@
typedef struct sparc_def_t sparc_def_t;
+#if !defined(TARGET_SPARC64)
#define NB_MMU_MODES 2
+#else
+#define NB_MMU_MODES 3
+#endif
typedef struct CPUSPARCState {
target_ulong gregs[8]; /* general registers */
@@ -323,12 +329,37 @@ void cpu_check_irqs(CPUSPARCState *env);
#define cpu_list sparc_cpu_list
/* MMU modes definitions */
-#define MMU_MODE0_SUFFIX _kernel
-#define MMU_MODE1_SUFFIX _user
-#define MMU_USER_IDX 1
+#define MMU_MODE0_SUFFIX _user
+#define MMU_MODE1_SUFFIX _kernel
+#ifdef TARGET_SPARC64
+#define MMU_MODE2_SUFFIX _hypv
+#endif
+#define MMU_USER_IDX 0
static inline int cpu_mmu_index (CPUState *env)
{
- return env->psrs == 0 ? 1 : 0;
+#if defined(CONFIG_USER_ONLY)
+ return 0;
+#elif !defined(TARGET_SPARC64)
+ return env->psrs;
+#else
+ if (!env->psrs)
+ return 0;
+ else if ((env->hpstate & HS_PRIV) == 0)
+ return 1;
+ else
+ return 2;
+#endif
+}
+
+static inline int cpu_fpu_enabled(CPUState *env)
+{
+#if defined(CONFIG_USER_ONLY)
+ return 1;
+#elif !defined(TARGET_SPARC64)
+ return env->psref;
+#else
+ return ((env->pstate & PS_PEF) != 0) && ((env->fprs & FPRS_FEF) != 0);
+#endif
}
#include "cpu-all.h"
diff --git a/target-sparc/op.c b/target-sparc/op.c
index e12347df1f..80864c3bb8 100644
--- a/target-sparc/op.c
+++ b/target-sparc/op.c
@@ -1023,6 +1023,11 @@ void OPPROTO op_sra(void)
#define MEMSUFFIX _kernel
#include "op_mem.h"
+
+#ifdef TARGET_SPARC64
+#define MEMSUFFIX _hypv
+#include "op_mem.h"
+#endif
#endif
void OPPROTO op_ldfsr(void)
diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c
index ac88b55d52..28c18b4036 100644
--- a/target-sparc/op_helper.c
+++ b/target-sparc/op_helper.c
@@ -789,7 +789,8 @@ void helper_ld_asi(int asi, int size, int sign)
{
uint64_t ret = 0;
- if (asi < 0x80 && (env->pstate & PS_PRIV) == 0)
+ if ((asi < 0x80 && (env->pstate & PS_PRIV) == 0)
+ || (asi >= 0x30 && asi < 0x80) && !(env->hpstate & HS_PRIV))
raise_exception(TT_PRIV_ACT);
switch (asi) {
@@ -800,20 +801,38 @@ void helper_ld_asi(int asi, int size, int sign)
case 0x88: // Primary LE
case 0x8a: // Primary no-fault LE
if ((asi & 0x80) && (env->pstate & PS_PRIV)) {
- switch(size) {
- case 1:
- ret = ldub_kernel(T0);
- break;
- case 2:
- ret = lduw_kernel(T0 & ~1);
- break;
- case 4:
- ret = ldl_kernel(T0 & ~3);
- break;
- default:
- case 8:
- ret = ldq_kernel(T0 & ~7);
- break;
+ if (env->hpstate & HS_PRIV) {
+ switch(size) {
+ case 1:
+ ret = ldub_hypv(T0);
+ break;
+ case 2:
+ ret = lduw_hypv(T0 & ~1);
+ break;
+ case 4:
+ ret = ldl_hypv(T0 & ~3);
+ break;
+ default:
+ case 8:
+ ret = ldq_hypv(T0 & ~7);
+ break;
+ }
+ } else {
+ switch(size) {
+ case 1:
+ ret = ldub_kernel(T0);
+ break;
+ case 2:
+ ret = lduw_kernel(T0 & ~1);
+ break;
+ case 4:
+ ret = ldl_kernel(T0 & ~3);
+ break;
+ default:
+ case 8:
+ ret = ldq_kernel(T0 & ~7);
+ break;
+ }
}
} else {
switch(size) {
@@ -987,7 +1006,8 @@ void helper_ld_asi(int asi, int size, int sign)
void helper_st_asi(int asi, int size)
{
- if (asi < 0x80 && (env->pstate & PS_PRIV) == 0)
+ if ((asi < 0x80 && (env->pstate & PS_PRIV) == 0)
+ || (asi >= 0x30 && asi < 0x80) && !(env->hpstate & HS_PRIV))
raise_exception(TT_PRIV_ACT);
/* Convert to little endian */
@@ -1022,20 +1042,38 @@ void helper_st_asi(int asi, int size)
case 0x80: // Primary
case 0x88: // Primary LE
if ((asi & 0x80) && (env->pstate & PS_PRIV)) {
- switch(size) {
- case 1:
- stb_kernel(T0, T1);
- break;
- case 2:
- stw_kernel(T0 & ~1, T1);
- break;
- case 4:
- stl_kernel(T0 & ~3, T1);
- break;
- case 8:
- default:
- stq_kernel(T0 & ~7, T1);
- break;
+ if (env->hpstate & HS_PRIV) {
+ switch(size) {
+ case 1:
+ stb_hypv(T0, T1);
+ break;
+ case 2:
+ stw_hypv(T0 & ~1, T1);
+ break;
+ case 4:
+ stl_hypv(T0 & ~3, T1);
+ break;
+ case 8:
+ default:
+ stq_hypv(T0 & ~7, T1);
+ break;
+ }
+ } else {
+ switch(size) {
+ case 1:
+ stb_kernel(T0, T1);
+ break;
+ case 2:
+ stw_kernel(T0 & ~1, T1);
+ break;
+ case 4:
+ stl_kernel(T0 & ~3, T1);
+ break;
+ case 8:
+ default:
+ stq_kernel(T0 & ~7, T1);
+ break;
+ }
}
} else {
switch(size) {
diff --git a/target-sparc/translate.c b/target-sparc/translate.c
index 046dc0b2e1..d0dc511073 100644
--- a/target-sparc/translate.c
+++ b/target-sparc/translate.c
@@ -361,17 +361,24 @@ GEN32(gen_op_store_DT1_fpr, gen_op_store_DT1_fpr_fprf);
#endif
#define gen_op_ldst(name) gen_op_##name##_raw()
#else
-#define supervisor(dc) (dc->mem_idx == 1)
+#define supervisor(dc) (dc->mem_idx >= 1)
#ifdef TARGET_SPARC64
#define hypervisor(dc) (dc->mem_idx == 2)
-#endif
-#define gen_op_ldst(name) (*gen_op_##name[dc->mem_idx])()
+#define OP_LD_TABLE(width) \
+ static GenOpFunc * const gen_op_##width[] = { \
+ &gen_op_##width##_user, \
+ &gen_op_##width##_kernel, \
+ &gen_op_##width##_hypv, \
+ };
+#else
#define OP_LD_TABLE(width) \
static GenOpFunc * const gen_op_##width[] = { \
&gen_op_##width##_user, \
&gen_op_##width##_kernel, \
};
#endif
+#define gen_op_ldst(name) (*gen_op_##name[dc->mem_idx])()
+#endif
#ifndef CONFIG_USER_ONLY
OP_LD_TABLE(ld);
@@ -3378,17 +3385,8 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb,
dc->pc = pc_start;
last_pc = dc->pc;
dc->npc = (target_ulong) tb->cs_base;
-#if defined(CONFIG_USER_ONLY)
- dc->mem_idx = 0;
- dc->fpu_enabled = 1;
-#else
- dc->mem_idx = ((env->psrs) != 0);
-#ifdef TARGET_SPARC64
- dc->fpu_enabled = (((env->pstate & PS_PEF) != 0) && ((env->fprs & FPRS_FEF) != 0));
-#else
- dc->fpu_enabled = ((env->psref) != 0);
-#endif
-#endif
+ dc->mem_idx = cpu_mmu_index(env);
+ dc->fpu_enabled = cpu_fpu_enabled(env);
gen_opc_ptr = gen_opc_buf;
gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
gen_opparam_ptr = gen_opparam_buf;
@@ -3522,6 +3520,7 @@ void cpu_reset(CPUSPARCState *env)
env->psrps = 1;
#ifdef TARGET_SPARC64
env->pstate = PS_PRIV;
+ env->hpstate = HS_PRIV;
env->pc = 0x1fff0000000ULL;
#else
env->pc = 0;