summaryrefslogtreecommitdiffstats
path: root/target-sparc
diff options
context:
space:
mode:
Diffstat (limited to 'target-sparc')
-rw-r--r--target-sparc/cc_helper.c485
-rw-r--r--target-sparc/cpu.h36
-rw-r--r--target-sparc/cpu_init.c848
-rw-r--r--target-sparc/fop_helper.c394
-rw-r--r--target-sparc/helper.c1929
-rw-r--r--target-sparc/helper.h226
-rw-r--r--target-sparc/int32_helper.c163
-rw-r--r--target-sparc/int64_helper.c201
-rw-r--r--target-sparc/ldst_helper.c2434
-rw-r--r--target-sparc/mmu_helper.c853
-rw-r--r--target-sparc/op_helper.c4292
-rw-r--r--target-sparc/translate.c366
-rw-r--r--target-sparc/vis_helper.c406
-rw-r--r--target-sparc/win_helper.c393
14 files changed, 6575 insertions, 6451 deletions
diff --git a/target-sparc/cc_helper.c b/target-sparc/cc_helper.c
new file mode 100644
index 0000000000..04bd2cf9c7
--- /dev/null
+++ b/target-sparc/cc_helper.c
@@ -0,0 +1,485 @@
+/*
+ * Helpers for lazy condition code handling
+ *
+ * Copyright (c) 2003-2005 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cpu.h"
+#include "helper.h"
+
+static uint32_t compute_all_flags(CPUState *env)
+{
+ return env->psr & PSR_ICC;
+}
+
+static uint32_t compute_C_flags(CPUState *env)
+{
+ return env->psr & PSR_CARRY;
+}
+
+static inline uint32_t get_NZ_icc(int32_t dst)
+{
+ uint32_t ret = 0;
+
+ if (dst == 0) {
+ ret = PSR_ZERO;
+ } else if (dst < 0) {
+ ret = PSR_NEG;
+ }
+ return ret;
+}
+
+#ifdef TARGET_SPARC64
+static uint32_t compute_all_flags_xcc(CPUState *env)
+{
+ return env->xcc & PSR_ICC;
+}
+
+static uint32_t compute_C_flags_xcc(CPUState *env)
+{
+ return env->xcc & PSR_CARRY;
+}
+
+static inline uint32_t get_NZ_xcc(target_long dst)
+{
+ uint32_t ret = 0;
+
+ if (!dst) {
+ ret = PSR_ZERO;
+ } else if (dst < 0) {
+ ret = PSR_NEG;
+ }
+ return ret;
+}
+#endif
+
+static inline uint32_t get_V_div_icc(target_ulong src2)
+{
+ uint32_t ret = 0;
+
+ if (src2 != 0) {
+ ret = PSR_OVF;
+ }
+ return ret;
+}
+
+static uint32_t compute_all_div(CPUState *env)
+{
+ uint32_t ret;
+
+ ret = get_NZ_icc(CC_DST);
+ ret |= get_V_div_icc(CC_SRC2);
+ return ret;
+}
+
+static uint32_t compute_C_div(CPUState *env)
+{
+ return 0;
+}
+
+static inline uint32_t get_C_add_icc(uint32_t dst, uint32_t src1)
+{
+ uint32_t ret = 0;
+
+ if (dst < src1) {
+ ret = PSR_CARRY;
+ }
+ return ret;
+}
+
+static inline uint32_t get_C_addx_icc(uint32_t dst, uint32_t src1,
+ uint32_t src2)
+{
+ uint32_t ret = 0;
+
+ if (((src1 & src2) | (~dst & (src1 | src2))) & (1U << 31)) {
+ ret = PSR_CARRY;
+ }
+ return ret;
+}
+
+static inline uint32_t get_V_add_icc(uint32_t dst, uint32_t src1,
+ uint32_t src2)
+{
+ uint32_t ret = 0;
+
+ if (((src1 ^ src2 ^ -1) & (src1 ^ dst)) & (1U << 31)) {
+ ret = PSR_OVF;
+ }
+ return ret;
+}
+
+#ifdef TARGET_SPARC64
+static inline uint32_t get_C_add_xcc(target_ulong dst, target_ulong src1)
+{
+ uint32_t ret = 0;
+
+ if (dst < src1) {
+ ret = PSR_CARRY;
+ }
+ return ret;
+}
+
+static inline uint32_t get_C_addx_xcc(target_ulong dst, target_ulong src1,
+ target_ulong src2)
+{
+ uint32_t ret = 0;
+
+ if (((src1 & src2) | (~dst & (src1 | src2))) & (1ULL << 63)) {
+ ret = PSR_CARRY;
+ }
+ return ret;
+}
+
+static inline uint32_t get_V_add_xcc(target_ulong dst, target_ulong src1,
+ target_ulong src2)
+{
+ uint32_t ret = 0;
+
+ if (((src1 ^ src2 ^ -1) & (src1 ^ dst)) & (1ULL << 63)) {
+ ret = PSR_OVF;
+ }
+ return ret;
+}
+
+static uint32_t compute_all_add_xcc(CPUState *env)
+{
+ uint32_t ret;
+
+ ret = get_NZ_xcc(CC_DST);
+ ret |= get_C_add_xcc(CC_DST, CC_SRC);
+ ret |= get_V_add_xcc(CC_DST, CC_SRC, CC_SRC2);
+ return ret;
+}
+
+static uint32_t compute_C_add_xcc(CPUState *env)
+{
+ return get_C_add_xcc(CC_DST, CC_SRC);
+}
+#endif
+
+static uint32_t compute_all_add(CPUState *env)
+{
+ uint32_t ret;
+
+ ret = get_NZ_icc(CC_DST);
+ ret |= get_C_add_icc(CC_DST, CC_SRC);
+ ret |= get_V_add_icc(CC_DST, CC_SRC, CC_SRC2);
+ return ret;
+}
+
+static uint32_t compute_C_add(CPUState *env)
+{
+ return get_C_add_icc(CC_DST, CC_SRC);
+}
+
+#ifdef TARGET_SPARC64
+static uint32_t compute_all_addx_xcc(CPUState *env)
+{
+ uint32_t ret;
+
+ ret = get_NZ_xcc(CC_DST);
+ ret |= get_C_addx_xcc(CC_DST, CC_SRC, CC_SRC2);
+ ret |= get_V_add_xcc(CC_DST, CC_SRC, CC_SRC2);
+ return ret;
+}
+
+static uint32_t compute_C_addx_xcc(CPUState *env)
+{
+ uint32_t ret;
+
+ ret = get_C_addx_xcc(CC_DST, CC_SRC, CC_SRC2);
+ return ret;
+}
+#endif
+
+static uint32_t compute_all_addx(CPUState *env)
+{
+ uint32_t ret;
+
+ ret = get_NZ_icc(CC_DST);
+ ret |= get_C_addx_icc(CC_DST, CC_SRC, CC_SRC2);
+ ret |= get_V_add_icc(CC_DST, CC_SRC, CC_SRC2);
+ return ret;
+}
+
+static uint32_t compute_C_addx(CPUState *env)
+{
+ uint32_t ret;
+
+ ret = get_C_addx_icc(CC_DST, CC_SRC, CC_SRC2);
+ return ret;
+}
+
+static inline uint32_t get_V_tag_icc(target_ulong src1, target_ulong src2)
+{
+ uint32_t ret = 0;
+
+ if ((src1 | src2) & 0x3) {
+ ret = PSR_OVF;
+ }
+ return ret;
+}
+
+static uint32_t compute_all_tadd(CPUState *env)
+{
+ uint32_t ret;
+
+ ret = get_NZ_icc(CC_DST);
+ ret |= get_C_add_icc(CC_DST, CC_SRC);
+ ret |= get_V_add_icc(CC_DST, CC_SRC, CC_SRC2);
+ ret |= get_V_tag_icc(CC_SRC, CC_SRC2);
+ return ret;
+}
+
+static uint32_t compute_all_taddtv(CPUState *env)
+{
+ uint32_t ret;
+
+ ret = get_NZ_icc(CC_DST);
+ ret |= get_C_add_icc(CC_DST, CC_SRC);
+ return ret;
+}
+
+static inline uint32_t get_C_sub_icc(uint32_t src1, uint32_t src2)
+{
+ uint32_t ret = 0;
+
+ if (src1 < src2) {
+ ret = PSR_CARRY;
+ }
+ return ret;
+}
+
+static inline uint32_t get_C_subx_icc(uint32_t dst, uint32_t src1,
+ uint32_t src2)
+{
+ uint32_t ret = 0;
+
+ if (((~src1 & src2) | (dst & (~src1 | src2))) & (1U << 31)) {
+ ret = PSR_CARRY;
+ }
+ return ret;
+}
+
+static inline uint32_t get_V_sub_icc(uint32_t dst, uint32_t src1,
+ uint32_t src2)
+{
+ uint32_t ret = 0;
+
+ if (((src1 ^ src2) & (src1 ^ dst)) & (1U << 31)) {
+ ret = PSR_OVF;
+ }
+ return ret;
+}
+
+
+#ifdef TARGET_SPARC64
+static inline uint32_t get_C_sub_xcc(target_ulong src1, target_ulong src2)
+{
+ uint32_t ret = 0;
+
+ if (src1 < src2) {
+ ret = PSR_CARRY;
+ }
+ return ret;
+}
+
+static inline uint32_t get_C_subx_xcc(target_ulong dst, target_ulong src1,
+ target_ulong src2)
+{
+ uint32_t ret = 0;
+
+ if (((~src1 & src2) | (dst & (~src1 | src2))) & (1ULL << 63)) {
+ ret = PSR_CARRY;
+ }
+ return ret;
+}
+
+static inline uint32_t get_V_sub_xcc(target_ulong dst, target_ulong src1,
+ target_ulong src2)
+{
+ uint32_t ret = 0;
+
+ if (((src1 ^ src2) & (src1 ^ dst)) & (1ULL << 63)) {
+ ret = PSR_OVF;
+ }
+ return ret;
+}
+
+static uint32_t compute_all_sub_xcc(CPUState *env)
+{
+ uint32_t ret;
+
+ ret = get_NZ_xcc(CC_DST);
+ ret |= get_C_sub_xcc(CC_SRC, CC_SRC2);
+ ret |= get_V_sub_xcc(CC_DST, CC_SRC, CC_SRC2);
+ return ret;
+}
+
+static uint32_t compute_C_sub_xcc(CPUState *env)
+{
+ return get_C_sub_xcc(CC_SRC, CC_SRC2);
+}
+#endif
+
+static uint32_t compute_all_sub(CPUState *env)
+{
+ uint32_t ret;
+
+ ret = get_NZ_icc(CC_DST);
+ ret |= get_C_sub_icc(CC_SRC, CC_SRC2);
+ ret |= get_V_sub_icc(CC_DST, CC_SRC, CC_SRC2);
+ return ret;
+}
+
+static uint32_t compute_C_sub(CPUState *env)
+{
+ return get_C_sub_icc(CC_SRC, CC_SRC2);
+}
+
+#ifdef TARGET_SPARC64
+static uint32_t compute_all_subx_xcc(CPUState *env)
+{
+ uint32_t ret;
+
+ ret = get_NZ_xcc(CC_DST);
+ ret |= get_C_subx_xcc(CC_DST, CC_SRC, CC_SRC2);
+ ret |= get_V_sub_xcc(CC_DST, CC_SRC, CC_SRC2);
+ return ret;
+}
+
+static uint32_t compute_C_subx_xcc(CPUState *env)
+{
+ uint32_t ret;
+
+ ret = get_C_subx_xcc(CC_DST, CC_SRC, CC_SRC2);
+ return ret;
+}
+#endif
+
+static uint32_t compute_all_subx(CPUState *env)
+{
+ uint32_t ret;
+
+ ret = get_NZ_icc(CC_DST);
+ ret |= get_C_subx_icc(CC_DST, CC_SRC, CC_SRC2);
+ ret |= get_V_sub_icc(CC_DST, CC_SRC, CC_SRC2);
+ return ret;
+}
+
+static uint32_t compute_C_subx(CPUState *env)
+{
+ uint32_t ret;
+
+ ret = get_C_subx_icc(CC_DST, CC_SRC, CC_SRC2);
+ return ret;
+}
+
+static uint32_t compute_all_tsub(CPUState *env)
+{
+ uint32_t ret;
+
+ ret = get_NZ_icc(CC_DST);
+ ret |= get_C_sub_icc(CC_SRC, CC_SRC2);
+ ret |= get_V_sub_icc(CC_DST, CC_SRC, CC_SRC2);
+ ret |= get_V_tag_icc(CC_SRC, CC_SRC2);
+ return ret;
+}
+
+static uint32_t compute_all_tsubtv(CPUState *env)
+{
+ uint32_t ret;
+
+ ret = get_NZ_icc(CC_DST);
+ ret |= get_C_sub_icc(CC_SRC, CC_SRC2);
+ return ret;
+}
+
+static uint32_t compute_all_logic(CPUState *env)
+{
+ return get_NZ_icc(CC_DST);
+}
+
+static uint32_t compute_C_logic(CPUState *env)
+{
+ return 0;
+}
+
+#ifdef TARGET_SPARC64
+static uint32_t compute_all_logic_xcc(CPUState *env)
+{
+ return get_NZ_xcc(CC_DST);
+}
+#endif
+
+typedef struct CCTable {
+ uint32_t (*compute_all)(CPUState *env); /* return all the flags */
+ uint32_t (*compute_c)(CPUState *env); /* return the C flag */
+} CCTable;
+
+static const CCTable icc_table[CC_OP_NB] = {
+ /* CC_OP_DYNAMIC should never happen */
+ [CC_OP_FLAGS] = { compute_all_flags, compute_C_flags },
+ [CC_OP_DIV] = { compute_all_div, compute_C_div },
+ [CC_OP_ADD] = { compute_all_add, compute_C_add },
+ [CC_OP_ADDX] = { compute_all_addx, compute_C_addx },
+ [CC_OP_TADD] = { compute_all_tadd, compute_C_add },
+ [CC_OP_TADDTV] = { compute_all_taddtv, compute_C_add },
+ [CC_OP_SUB] = { compute_all_sub, compute_C_sub },
+ [CC_OP_SUBX] = { compute_all_subx, compute_C_subx },
+ [CC_OP_TSUB] = { compute_all_tsub, compute_C_sub },
+ [CC_OP_TSUBTV] = { compute_all_tsubtv, compute_C_sub },
+ [CC_OP_LOGIC] = { compute_all_logic, compute_C_logic },
+};
+
+#ifdef TARGET_SPARC64
+static const CCTable xcc_table[CC_OP_NB] = {
+ /* CC_OP_DYNAMIC should never happen */
+ [CC_OP_FLAGS] = { compute_all_flags_xcc, compute_C_flags_xcc },
+ [CC_OP_DIV] = { compute_all_logic_xcc, compute_C_logic },
+ [CC_OP_ADD] = { compute_all_add_xcc, compute_C_add_xcc },
+ [CC_OP_ADDX] = { compute_all_addx_xcc, compute_C_addx_xcc },
+ [CC_OP_TADD] = { compute_all_add_xcc, compute_C_add_xcc },
+ [CC_OP_TADDTV] = { compute_all_add_xcc, compute_C_add_xcc },
+ [CC_OP_SUB] = { compute_all_sub_xcc, compute_C_sub_xcc },
+ [CC_OP_SUBX] = { compute_all_subx_xcc, compute_C_subx_xcc },
+ [CC_OP_TSUB] = { compute_all_sub_xcc, compute_C_sub_xcc },
+ [CC_OP_TSUBTV] = { compute_all_sub_xcc, compute_C_sub_xcc },
+ [CC_OP_LOGIC] = { compute_all_logic_xcc, compute_C_logic },
+};
+#endif
+
+void helper_compute_psr(CPUState *env)
+{
+ uint32_t new_psr;
+
+ new_psr = icc_table[CC_OP].compute_all(env);
+ env->psr = new_psr;
+#ifdef TARGET_SPARC64
+ new_psr = xcc_table[CC_OP].compute_all(env);
+ env->xcc = new_psr;
+#endif
+ CC_OP = CC_OP_FLAGS;
+}
+
+uint32_t helper_compute_C_icc(CPUState *env)
+{
+ uint32_t ret;
+
+ ret = icc_table[CC_OP].compute_c(env) >> PSR_CARRY_SHIFT;
+ return ret;
+}
diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h
index 19de5ba334..25b4f1a1dc 100644
--- a/target-sparc/cpu.h
+++ b/target-sparc/cpu.h
@@ -335,6 +335,27 @@ enum {
#define SFSR_CT_NOTRANS (3ULL << 4)
#define SFSR_CT_MASK (3ULL << 4)
+/* Leon3 cache control */
+
+/* Cache control: emulate the behavior of cache control registers but without
+ any effect on the emulated */
+
+#define CACHE_STATE_MASK 0x3
+#define CACHE_DISABLED 0x0
+#define CACHE_FROZEN 0x1
+#define CACHE_ENABLED 0x3
+
+/* Cache Control register fields */
+
+#define CACHE_CTRL_IF (1 << 4) /* Instruction Cache Freeze on Interrupt */
+#define CACHE_CTRL_DF (1 << 5) /* Data Cache Freeze on Interrupt */
+#define CACHE_CTRL_DP (1 << 14) /* Data cache flush pending */
+#define CACHE_CTRL_IP (1 << 15) /* Instruction cache flush pending */
+#define CACHE_CTRL_IB (1 << 16) /* Instruction burst fetch */
+#define CACHE_CTRL_FI (1 << 21) /* Flush Instruction cache (Write only) */
+#define CACHE_CTRL_FD (1 << 22) /* Flush Data cache (Write only) */
+#define CACHE_CTRL_DS (1 << 23) /* Data cache snoop enable */
+
typedef struct SparcTLBEntry {
uint64_t tag;
uint64_t tte;
@@ -478,17 +499,18 @@ typedef struct CPUSPARCState {
sparc_def_t *def;
void *irq_manager;
- void (*qemu_irq_ack) (void *irq_manager, int intno);
+ void (*qemu_irq_ack)(CPUState *env, void *irq_manager, int intno);
/* Leon3 cache control */
uint32_t cache_control;
} CPUSPARCState;
#ifndef NO_CPU_IO_DEFS
-/* helper.c */
+/* cpu_init.c */
CPUSPARCState *cpu_sparc_init(const char *cpu_model);
void cpu_sparc_set_id(CPUSPARCState *env, unsigned int cpu);
void sparc_cpu_list(FILE *f, fprintf_function cpu_fprintf);
+/* mmu_helper.c */
int cpu_sparc_handle_mmu_fault(CPUSPARCState *env1, target_ulong address, int rw,
int mmu_idx);
#define cpu_handle_mmu_fault cpu_sparc_handle_mmu_fault
@@ -508,7 +530,7 @@ void gen_intermediate_code_init(CPUSPARCState *env);
/* cpu-exec.c */
int cpu_sparc_exec(CPUSPARCState *s);
-/* op_helper.c */
+/* win_helper.c */
target_ulong cpu_get_psr(CPUState *env1);
void cpu_put_psr(CPUState *env1, target_ulong val);
#ifdef TARGET_SPARC64
@@ -521,7 +543,10 @@ void cpu_change_pstate(CPUState *env1, uint32_t new_pstate);
int cpu_cwp_inc(CPUState *env1, int cwp);
int cpu_cwp_dec(CPUState *env1, int cwp);
void cpu_set_cwp(CPUState *env1, int new_cwp);
-void leon3_irq_manager(void *irq_manager, int intno);
+
+/* int_helper.c */
+void do_interrupt(CPUState *env);
+void leon3_irq_manager(CPUState *env, void *irq_manager, int intno);
/* sun4m.c, sun4u.c */
void cpu_check_irqs(CPUSPARCState *env);
@@ -718,9 +743,6 @@ static inline bool tb_am_enabled(int tb_flags)
#endif
}
-/* helper.c */
-void do_interrupt(CPUState *env);
-
static inline bool cpu_has_work(CPUState *env1)
{
return (env1->interrupt_request & CPU_INTERRUPT_HARD) &&
diff --git a/target-sparc/cpu_init.c b/target-sparc/cpu_init.c
new file mode 100644
index 0000000000..6954800af0
--- /dev/null
+++ b/target-sparc/cpu_init.c
@@ -0,0 +1,848 @@
+/*
+ * Sparc CPU init helpers
+ *
+ * Copyright (c) 2003-2005 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cpu.h"
+
+//#define DEBUG_FEATURES
+
+static int cpu_sparc_find_by_name(sparc_def_t *cpu_def, const char *cpu_model);
+
+void cpu_reset(CPUSPARCState *env)
+{
+ if (qemu_loglevel_mask(CPU_LOG_RESET)) {
+ qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
+ log_cpu_state(env, 0);
+ }
+
+ tlb_flush(env, 1);
+ env->cwp = 0;
+#ifndef TARGET_SPARC64
+ env->wim = 1;
+#endif
+ env->regwptr = env->regbase + (env->cwp * 16);
+ CC_OP = CC_OP_FLAGS;
+#if defined(CONFIG_USER_ONLY)
+#ifdef TARGET_SPARC64
+ env->cleanwin = env->nwindows - 2;
+ env->cansave = env->nwindows - 2;
+ env->pstate = PS_RMO | PS_PEF | PS_IE;
+ env->asi = 0x82; /* Primary no-fault */
+#endif
+#else
+#if !defined(TARGET_SPARC64)
+ env->psret = 0;
+ env->psrs = 1;
+ env->psrps = 1;
+#endif
+#ifdef TARGET_SPARC64
+ env->pstate = PS_PRIV|PS_RED|PS_PEF|PS_AG;
+ env->hpstate = cpu_has_hypervisor(env) ? HS_PRIV : 0;
+ env->tl = env->maxtl;
+ cpu_tsptr(env)->tt = TT_POWER_ON_RESET;
+ env->lsu = 0;
+#else
+ env->mmuregs[0] &= ~(MMU_E | MMU_NF);
+ env->mmuregs[0] |= env->def->mmu_bm;
+#endif
+ env->pc = 0;
+ env->npc = env->pc + 4;
+#endif
+ env->cache_control = 0;
+}
+
+static int cpu_sparc_register(CPUSPARCState *env, const char *cpu_model)
+{
+ sparc_def_t def1, *def = &def1;
+
+ if (cpu_sparc_find_by_name(def, cpu_model) < 0) {
+ return -1;
+ }
+
+ env->def = g_new0(sparc_def_t, 1);
+ memcpy(env->def, def, sizeof(*def));
+#if defined(CONFIG_USER_ONLY)
+ if ((env->def->features & CPU_FEATURE_FLOAT)) {
+ env->def->features |= CPU_FEATURE_FLOAT128;
+ }
+#endif
+ env->cpu_model_str = cpu_model;
+ env->version = def->iu_version;
+ env->fsr = def->fpu_version;
+ env->nwindows = def->nwindows;
+#if !defined(TARGET_SPARC64)
+ env->mmuregs[0] |= def->mmu_version;
+ cpu_sparc_set_id(env, 0);
+ env->mxccregs[7] |= def->mxcc_version;
+#else
+ env->mmu_version = def->mmu_version;
+ env->maxtl = def->maxtl;
+ env->version |= def->maxtl << 8;
+ env->version |= def->nwindows - 1;
+#endif
+ return 0;
+}
+
+static void cpu_sparc_close(CPUSPARCState *env)
+{
+ g_free(env->def);
+ g_free(env);
+}
+
+CPUSPARCState *cpu_sparc_init(const char *cpu_model)
+{
+ CPUSPARCState *env;
+
+ env = g_new0(CPUSPARCState, 1);
+ cpu_exec_init(env);
+
+ gen_intermediate_code_init(env);
+
+ if (cpu_sparc_register(env, cpu_model) < 0) {
+ cpu_sparc_close(env);
+ return NULL;
+ }
+ qemu_init_vcpu(env);
+
+ return env;
+}
+
+void cpu_sparc_set_id(CPUSPARCState *env, unsigned int cpu)
+{
+#if !defined(TARGET_SPARC64)
+ env->mxccregs[7] = ((cpu + 8) & 0xf) << 24;
+#endif
+}
+
+static const sparc_def_t sparc_defs[] = {
+#ifdef TARGET_SPARC64
+ {
+ .name = "Fujitsu Sparc64",
+ .iu_version = ((0x04ULL << 48) | (0x02ULL << 32) | (0ULL << 24)),
+ .fpu_version = 0x00000000,
+ .mmu_version = mmu_us_12,
+ .nwindows = 4,
+ .maxtl = 4,
+ .features = CPU_DEFAULT_FEATURES,
+ },
+ {
+ .name = "Fujitsu Sparc64 III",
+ .iu_version = ((0x04ULL << 48) | (0x03ULL << 32) | (0ULL << 24)),
+ .fpu_version = 0x00000000,
+ .mmu_version = mmu_us_12,
+ .nwindows = 5,
+ .maxtl = 4,
+ .features = CPU_DEFAULT_FEATURES,
+ },
+ {
+ .name = "Fujitsu Sparc64 IV",
+ .iu_version = ((0x04ULL << 48) | (0x04ULL << 32) | (0ULL << 24)),
+ .fpu_version = 0x00000000,
+ .mmu_version = mmu_us_12,
+ .nwindows = 8,
+ .maxtl = 5,
+ .features = CPU_DEFAULT_FEATURES,
+ },
+ {
+ .name = "Fujitsu Sparc64 V",
+ .iu_version = ((0x04ULL << 48) | (0x05ULL << 32) | (0x51ULL << 24)),
+ .fpu_version = 0x00000000,
+ .mmu_version = mmu_us_12,
+ .nwindows = 8,
+ .maxtl = 5,
+ .features = CPU_DEFAULT_FEATURES,
+ },
+ {
+ .name = "TI UltraSparc I",
+ .iu_version = ((0x17ULL << 48) | (0x10ULL << 32) | (0x40ULL << 24)),
+ .fpu_version = 0x00000000,
+ .mmu_version = mmu_us_12,
+ .nwindows = 8,
+ .maxtl = 5,
+ .features = CPU_DEFAULT_FEATURES,
+ },
+ {
+ .name = "TI UltraSparc II",
+ .iu_version = ((0x17ULL << 48) | (0x11ULL << 32) | (0x20ULL << 24)),
+ .fpu_version = 0x00000000,
+ .mmu_version = mmu_us_12,
+ .nwindows = 8,
+ .maxtl = 5,
+ .features = CPU_DEFAULT_FEATURES,
+ },
+ {
+ .name = "TI UltraSparc IIi",
+ .iu_version = ((0x17ULL << 48) | (0x12ULL << 32) | (0x91ULL << 24)),
+ .fpu_version = 0x00000000,
+ .mmu_version = mmu_us_12,
+ .nwindows = 8,
+ .maxtl = 5,
+ .features = CPU_DEFAULT_FEATURES,
+ },
+ {
+ .name = "TI UltraSparc IIe",
+ .iu_version = ((0x17ULL << 48) | (0x13ULL << 32) | (0x14ULL << 24)),
+ .fpu_version = 0x00000000,
+ .mmu_version = mmu_us_12,
+ .nwindows = 8,
+ .maxtl = 5,
+ .features = CPU_DEFAULT_FEATURES,
+ },
+ {
+ .name = "Sun UltraSparc III",
+ .iu_version = ((0x3eULL << 48) | (0x14ULL << 32) | (0x34ULL << 24)),
+ .fpu_version = 0x00000000,
+ .mmu_version = mmu_us_12,
+ .nwindows = 8,
+ .maxtl = 5,
+ .features = CPU_DEFAULT_FEATURES,
+ },
+ {
+ .name = "Sun UltraSparc III Cu",
+ .iu_version = ((0x3eULL << 48) | (0x15ULL << 32) | (0x41ULL << 24)),
+ .fpu_version = 0x00000000,
+ .mmu_version = mmu_us_3,
+ .nwindows = 8,
+ .maxtl = 5,
+ .features = CPU_DEFAULT_FEATURES,
+ },
+ {
+ .name = "Sun UltraSparc IIIi",
+ .iu_version = ((0x3eULL << 48) | (0x16ULL << 32) | (0x34ULL << 24)),
+ .fpu_version = 0x00000000,
+ .mmu_version = mmu_us_12,
+ .nwindows = 8,
+ .maxtl = 5,
+ .features = CPU_DEFAULT_FEATURES,
+ },
+ {
+ .name = "Sun UltraSparc IV",
+ .iu_version = ((0x3eULL << 48) | (0x18ULL << 32) | (0x31ULL << 24)),
+ .fpu_version = 0x00000000,
+ .mmu_version = mmu_us_4,
+ .nwindows = 8,
+ .maxtl = 5,
+ .features = CPU_DEFAULT_FEATURES,
+ },
+ {
+ .name = "Sun UltraSparc IV+",
+ .iu_version = ((0x3eULL << 48) | (0x19ULL << 32) | (0x22ULL << 24)),
+ .fpu_version = 0x00000000,
+ .mmu_version = mmu_us_12,
+ .nwindows = 8,
+ .maxtl = 5,
+ .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_CMT,
+ },
+ {
+ .name = "Sun UltraSparc IIIi+",
+ .iu_version = ((0x3eULL << 48) | (0x22ULL << 32) | (0ULL << 24)),
+ .fpu_version = 0x00000000,
+ .mmu_version = mmu_us_3,
+ .nwindows = 8,
+ .maxtl = 5,
+ .features = CPU_DEFAULT_FEATURES,
+ },
+ {
+ .name = "Sun UltraSparc T1",
+ /* defined in sparc_ifu_fdp.v and ctu.h */
+ .iu_version = ((0x3eULL << 48) | (0x23ULL << 32) | (0x02ULL << 24)),
+ .fpu_version = 0x00000000,
+ .mmu_version = mmu_sun4v,
+ .nwindows = 8,
+ .maxtl = 6,
+ .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_HYPV | CPU_FEATURE_CMT
+ | CPU_FEATURE_GL,
+ },
+ {
+ .name = "Sun UltraSparc T2",
+ /* defined in tlu_asi_ctl.v and n2_revid_cust.v */
+ .iu_version = ((0x3eULL << 48) | (0x24ULL << 32) | (0x02ULL << 24)),
+ .fpu_version = 0x00000000,
+ .mmu_version = mmu_sun4v,
+ .nwindows = 8,
+ .maxtl = 6,
+ .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_HYPV | CPU_FEATURE_CMT
+ | CPU_FEATURE_GL,
+ },
+ {
+ .name = "NEC UltraSparc I",
+ .iu_version = ((0x22ULL << 48) | (0x10ULL << 32) | (0x40ULL << 24)),
+ .fpu_version = 0x00000000,
+ .mmu_version = mmu_us_12,
+ .nwindows = 8,
+ .maxtl = 5,
+ .features = CPU_DEFAULT_FEATURES,
+ },
+#else
+ {
+ .name = "Fujitsu MB86900",
+ .iu_version = 0x00 << 24, /* Impl 0, ver 0 */
+ .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
+ .mmu_version = 0x00 << 24, /* Impl 0, ver 0 */
+ .mmu_bm = 0x00004000,
+ .mmu_ctpr_mask = 0x007ffff0,
+ .mmu_cxr_mask = 0x0000003f,
+ .mmu_sfsr_mask = 0xffffffff,
+ .mmu_trcr_mask = 0xffffffff,
+ .nwindows = 7,
+ .features = CPU_FEATURE_FLOAT | CPU_FEATURE_FSMULD,
+ },
+ {
+ .name = "Fujitsu MB86904",
+ .iu_version = 0x04 << 24, /* Impl 0, ver 4 */
+ .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
+ .mmu_version = 0x04 << 24, /* Impl 0, ver 4 */
+ .mmu_bm = 0x00004000,
+ .mmu_ctpr_mask = 0x00ffffc0,
+ .mmu_cxr_mask = 0x000000ff,
+ .mmu_sfsr_mask = 0x00016fff,
+ .mmu_trcr_mask = 0x00ffffff,
+ .nwindows = 8,
+ .features = CPU_DEFAULT_FEATURES,
+ },
+ {
+ .name = "Fujitsu MB86907",
+ .iu_version = 0x05 << 24, /* Impl 0, ver 5 */
+ .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
+ .mmu_version = 0x05 << 24, /* Impl 0, ver 5 */
+ .mmu_bm = 0x00004000,
+ .mmu_ctpr_mask = 0xffffffc0,
+ .mmu_cxr_mask = 0x000000ff,
+ .mmu_sfsr_mask = 0x00016fff,
+ .mmu_trcr_mask = 0xffffffff,
+ .nwindows = 8,
+ .features = CPU_DEFAULT_FEATURES,
+ },
+ {
+ .name = "LSI L64811",
+ .iu_version = 0x10 << 24, /* Impl 1, ver 0 */
+ .fpu_version = 1 << 17, /* FPU version 1 (LSI L64814) */
+ .mmu_version = 0x10 << 24,
+ .mmu_bm = 0x00004000,
+ .mmu_ctpr_mask = 0x007ffff0,
+ .mmu_cxr_mask = 0x0000003f,
+ .mmu_sfsr_mask = 0xffffffff,
+ .mmu_trcr_mask = 0xffffffff,
+ .nwindows = 8,
+ .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT |
+ CPU_FEATURE_FSMULD,
+ },
+ {
+ .name = "Cypress CY7C601",
+ .iu_version = 0x11 << 24, /* Impl 1, ver 1 */
+ .fpu_version = 3 << 17, /* FPU version 3 (Cypress CY7C602) */
+ .mmu_version = 0x10 << 24,
+ .mmu_bm = 0x00004000,
+ .mmu_ctpr_mask = 0x007ffff0,
+ .mmu_cxr_mask = 0x0000003f,
+ .mmu_sfsr_mask = 0xffffffff,
+ .mmu_trcr_mask = 0xffffffff,
+ .nwindows = 8,
+ .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT |
+ CPU_FEATURE_FSMULD,
+ },
+ {
+ .name = "Cypress CY7C611",
+ .iu_version = 0x13 << 24, /* Impl 1, ver 3 */
+ .fpu_version = 3 << 17, /* FPU version 3 (Cypress CY7C602) */
+ .mmu_version = 0x10 << 24,
+ .mmu_bm = 0x00004000,
+ .mmu_ctpr_mask = 0x007ffff0,
+ .mmu_cxr_mask = 0x0000003f,
+ .mmu_sfsr_mask = 0xffffffff,
+ .mmu_trcr_mask = 0xffffffff,
+ .nwindows = 8,
+ .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT |
+ CPU_FEATURE_FSMULD,
+ },
+ {
+ .name = "TI MicroSparc I",
+ .iu_version = 0x41000000,
+ .fpu_version = 4 << 17,
+ .mmu_version = 0x41000000,
+ .mmu_bm = 0x00004000,
+ .mmu_ctpr_mask = 0x007ffff0,
+ .mmu_cxr_mask = 0x0000003f,
+ .mmu_sfsr_mask = 0x00016fff,
+ .mmu_trcr_mask = 0x0000003f,
+ .nwindows = 7,
+ .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_MUL |
+ CPU_FEATURE_DIV | CPU_FEATURE_FLUSH | CPU_FEATURE_FSQRT |
+ CPU_FEATURE_FMUL,
+ },
+ {
+ .name = "TI MicroSparc II",
+ .iu_version = 0x42000000,
+ .fpu_version = 4 << 17,
+ .mmu_version = 0x02000000,
+ .mmu_bm = 0x00004000,
+ .mmu_ctpr_mask = 0x00ffffc0,
+ .mmu_cxr_mask = 0x000000ff,
+ .mmu_sfsr_mask = 0x00016fff,
+ .mmu_trcr_mask = 0x00ffffff,
+ .nwindows = 8,
+ .features = CPU_DEFAULT_FEATURES,
+ },
+ {
+ .name = "TI MicroSparc IIep",
+ .iu_version = 0x42000000,
+ .fpu_version = 4 << 17,
+ .mmu_version = 0x04000000,
+ .mmu_bm = 0x00004000,
+ .mmu_ctpr_mask = 0x00ffffc0,
+ .mmu_cxr_mask = 0x000000ff,
+ .mmu_sfsr_mask = 0x00016bff,
+ .mmu_trcr_mask = 0x00ffffff,
+ .nwindows = 8,
+ .features = CPU_DEFAULT_FEATURES,
+ },
+ {
+ .name = "TI SuperSparc 40", /* STP1020NPGA */
+ .iu_version = 0x41000000, /* SuperSPARC 2.x */
+ .fpu_version = 0 << 17,
+ .mmu_version = 0x00000800, /* SuperSPARC 2.x, no MXCC */
+ .mmu_bm = 0x00002000,
+ .mmu_ctpr_mask = 0xffffffc0,
+ .mmu_cxr_mask = 0x0000ffff,
+ .mmu_sfsr_mask = 0xffffffff,
+ .mmu_trcr_mask = 0xffffffff,
+ .nwindows = 8,
+ .features = CPU_DEFAULT_FEATURES,
+ },
+ {
+ .name = "TI SuperSparc 50", /* STP1020PGA */
+ .iu_version = 0x40000000, /* SuperSPARC 3.x */
+ .fpu_version = 0 << 17,
+ .mmu_version = 0x01000800, /* SuperSPARC 3.x, no MXCC */
+ .mmu_bm = 0x00002000,
+ .mmu_ctpr_mask = 0xffffffc0,
+ .mmu_cxr_mask = 0x0000ffff,
+ .mmu_sfsr_mask = 0xffffffff,
+ .mmu_trcr_mask = 0xffffffff,
+ .nwindows = 8,
+ .features = CPU_DEFAULT_FEATURES,
+ },
+ {
+ .name = "TI SuperSparc 51",
+ .iu_version = 0x40000000, /* SuperSPARC 3.x */
+ .fpu_version = 0 << 17,
+ .mmu_version = 0x01000000, /* SuperSPARC 3.x, MXCC */
+ .mmu_bm = 0x00002000,
+ .mmu_ctpr_mask = 0xffffffc0,
+ .mmu_cxr_mask = 0x0000ffff,
+ .mmu_sfsr_mask = 0xffffffff,
+ .mmu_trcr_mask = 0xffffffff,
+ .mxcc_version = 0x00000104,
+ .nwindows = 8,
+ .features = CPU_DEFAULT_FEATURES,
+ },
+ {
+ .name = "TI SuperSparc 60", /* STP1020APGA */
+ .iu_version = 0x40000000, /* SuperSPARC 3.x */
+ .fpu_version = 0 << 17,
+ .mmu_version = 0x01000800, /* SuperSPARC 3.x, no MXCC */
+ .mmu_bm = 0x00002000,
+ .mmu_ctpr_mask = 0xffffffc0,
+ .mmu_cxr_mask = 0x0000ffff,
+ .mmu_sfsr_mask = 0xffffffff,
+ .mmu_trcr_mask = 0xffffffff,
+ .nwindows = 8,
+ .features = CPU_DEFAULT_FEATURES,
+ },
+ {
+ .name = "TI SuperSparc 61",
+ .iu_version = 0x44000000, /* SuperSPARC 3.x */
+ .fpu_version = 0 << 17,
+ .mmu_version = 0x01000000, /* SuperSPARC 3.x, MXCC */
+ .mmu_bm = 0x00002000,
+ .mmu_ctpr_mask = 0xffffffc0,
+ .mmu_cxr_mask = 0x0000ffff,
+ .mmu_sfsr_mask = 0xffffffff,
+ .mmu_trcr_mask = 0xffffffff,
+ .mxcc_version = 0x00000104,
+ .nwindows = 8,
+ .features = CPU_DEFAULT_FEATURES,
+ },
+ {
+ .name = "TI SuperSparc II",
+ .iu_version = 0x40000000, /* SuperSPARC II 1.x */
+ .fpu_version = 0 << 17,
+ .mmu_version = 0x08000000, /* SuperSPARC II 1.x, MXCC */
+ .mmu_bm = 0x00002000,
+ .mmu_ctpr_mask = 0xffffffc0,
+ .mmu_cxr_mask = 0x0000ffff,
+ .mmu_sfsr_mask = 0xffffffff,
+ .mmu_trcr_mask = 0xffffffff,
+ .mxcc_version = 0x00000104,
+ .nwindows = 8,
+ .features = CPU_DEFAULT_FEATURES,
+ },
+ {
+ .name = "Ross RT625",
+ .iu_version = 0x1e000000,
+ .fpu_version = 1 << 17,
+ .mmu_version = 0x1e000000,
+ .mmu_bm = 0x00004000,
+ .mmu_ctpr_mask = 0x007ffff0,
+ .mmu_cxr_mask = 0x0000003f,
+ .mmu_sfsr_mask = 0xffffffff,
+ .mmu_trcr_mask = 0xffffffff,
+ .nwindows = 8,
+ .features = CPU_DEFAULT_FEATURES,
+ },
+ {
+ .name = "Ross RT620",
+ .iu_version = 0x1f000000,
+ .fpu_version = 1 << 17,
+ .mmu_version = 0x1f000000,
+ .mmu_bm = 0x00004000,
+ .mmu_ctpr_mask = 0x007ffff0,
+ .mmu_cxr_mask = 0x0000003f,
+ .mmu_sfsr_mask = 0xffffffff,
+ .mmu_trcr_mask = 0xffffffff,
+ .nwindows = 8,
+ .features = CPU_DEFAULT_FEATURES,
+ },
+ {
+ .name = "BIT B5010",
+ .iu_version = 0x20000000,
+ .fpu_version = 0 << 17, /* B5010/B5110/B5120/B5210 */
+ .mmu_version = 0x20000000,
+ .mmu_bm = 0x00004000,
+ .mmu_ctpr_mask = 0x007ffff0,
+ .mmu_cxr_mask = 0x0000003f,
+ .mmu_sfsr_mask = 0xffffffff,
+ .mmu_trcr_mask = 0xffffffff,
+ .nwindows = 8,
+ .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT |
+ CPU_FEATURE_FSMULD,
+ },
+ {
+ .name = "Matsushita MN10501",
+ .iu_version = 0x50000000,
+ .fpu_version = 0 << 17,
+ .mmu_version = 0x50000000,
+ .mmu_bm = 0x00004000,
+ .mmu_ctpr_mask = 0x007ffff0,
+ .mmu_cxr_mask = 0x0000003f,
+ .mmu_sfsr_mask = 0xffffffff,
+ .mmu_trcr_mask = 0xffffffff,
+ .nwindows = 8,
+ .features = CPU_FEATURE_FLOAT | CPU_FEATURE_MUL | CPU_FEATURE_FSQRT |
+ CPU_FEATURE_FSMULD,
+ },
+ {
+ .name = "Weitek W8601",
+ .iu_version = 0x90 << 24, /* Impl 9, ver 0 */
+ .fpu_version = 3 << 17, /* FPU version 3 (Weitek WTL3170/2) */
+ .mmu_version = 0x10 << 24,
+ .mmu_bm = 0x00004000,
+ .mmu_ctpr_mask = 0x007ffff0,
+ .mmu_cxr_mask = 0x0000003f,
+ .mmu_sfsr_mask = 0xffffffff,
+ .mmu_trcr_mask = 0xffffffff,
+ .nwindows = 8,
+ .features = CPU_DEFAULT_FEATURES,
+ },
+ {
+ .name = "LEON2",
+ .iu_version = 0xf2000000,
+ .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
+ .mmu_version = 0xf2000000,
+ .mmu_bm = 0x00004000,
+ .mmu_ctpr_mask = 0x007ffff0,
+ .mmu_cxr_mask = 0x0000003f,
+ .mmu_sfsr_mask = 0xffffffff,
+ .mmu_trcr_mask = 0xffffffff,
+ .nwindows = 8,
+ .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_TA0_SHUTDOWN,
+ },
+ {
+ .name = "LEON3",
+ .iu_version = 0xf3000000,
+ .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
+ .mmu_version = 0xf3000000,
+ .mmu_bm = 0x00000000,
+ .mmu_ctpr_mask = 0x007ffff0,
+ .mmu_cxr_mask = 0x0000003f,
+ .mmu_sfsr_mask = 0xffffffff,
+ .mmu_trcr_mask = 0xffffffff,
+ .nwindows = 8,
+ .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_TA0_SHUTDOWN |
+ CPU_FEATURE_ASR17 | CPU_FEATURE_CACHE_CTRL,
+ },
+#endif
+};
+
+static const char * const feature_name[] = {
+ "float",
+ "float128",
+ "swap",
+ "mul",
+ "div",
+ "flush",
+ "fsqrt",
+ "fmul",
+ "vis1",
+ "vis2",
+ "fsmuld",
+ "hypv",
+ "cmt",
+ "gl",
+};
+
+static void print_features(FILE *f, fprintf_function cpu_fprintf,
+ uint32_t features, const char *prefix)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(feature_name); i++) {
+ if (feature_name[i] && (features & (1 << i))) {
+ if (prefix) {
+ (*cpu_fprintf)(f, "%s", prefix);
+ }
+ (*cpu_fprintf)(f, "%s ", feature_name[i]);
+ }
+ }
+}
+
+static void add_flagname_to_bitmaps(const char *flagname, uint32_t *features)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(feature_name); i++) {
+ if (feature_name[i] && !strcmp(flagname, feature_name[i])) {
+ *features |= 1 << i;
+ return;
+ }
+ }
+ fprintf(stderr, "CPU feature %s not found\n", flagname);
+}
+
+static int cpu_sparc_find_by_name(sparc_def_t *cpu_def, const char *cpu_model)
+{
+ unsigned int i;
+ const sparc_def_t *def = NULL;
+ char *s = strdup(cpu_model);
+ char *featurestr, *name = strtok(s, ",");
+ uint32_t plus_features = 0;
+ uint32_t minus_features = 0;
+ uint64_t iu_version;
+ uint32_t fpu_version, mmu_version, nwindows;
+
+ for (i = 0; i < ARRAY_SIZE(sparc_defs); i++) {
+ if (strcasecmp(name, sparc_defs[i].name) == 0) {
+ def = &sparc_defs[i];
+ }
+ }
+ if (!def) {
+ goto error;
+ }
+ memcpy(cpu_def, def, sizeof(*def));
+
+ featurestr = strtok(NULL, ",");
+ while (featurestr) {
+ char *val;
+
+ if (featurestr[0] == '+') {
+ add_flagname_to_bitmaps(featurestr + 1, &plus_features);
+ } else if (featurestr[0] == '-') {
+ add_flagname_to_bitmaps(featurestr + 1, &minus_features);
+ } else if ((val = strchr(featurestr, '='))) {
+ *val = 0; val++;
+ if (!strcmp(featurestr, "iu_version")) {
+ char *err;
+
+ iu_version = strtoll(val, &err, 0);
+ if (!*val || *err) {
+ fprintf(stderr, "bad numerical value %s\n", val);
+ goto error;
+ }
+ cpu_def->iu_version = iu_version;
+#ifdef DEBUG_FEATURES
+ fprintf(stderr, "iu_version %" PRIx64 "\n", iu_version);
+#endif
+ } else if (!strcmp(featurestr, "fpu_version")) {
+ char *err;
+
+ fpu_version = strtol(val, &err, 0);
+ if (!*val || *err) {
+ fprintf(stderr, "bad numerical value %s\n", val);
+ goto error;
+ }
+ cpu_def->fpu_version = fpu_version;
+#ifdef DEBUG_FEATURES
+ fprintf(stderr, "fpu_version %x\n", fpu_version);
+#endif
+ } else if (!strcmp(featurestr, "mmu_version")) {
+ char *err;
+
+ mmu_version = strtol(val, &err, 0);
+ if (!*val || *err) {
+ fprintf(stderr, "bad numerical value %s\n", val);
+ goto error;
+ }
+ cpu_def->mmu_version = mmu_version;
+#ifdef DEBUG_FEATURES
+ fprintf(stderr, "mmu_version %x\n", mmu_version);
+#endif
+ } else if (!strcmp(featurestr, "nwindows")) {
+ char *err;
+
+ nwindows = strtol(val, &err, 0);
+ if (!*val || *err || nwindows > MAX_NWINDOWS ||
+ nwindows < MIN_NWINDOWS) {
+ fprintf(stderr, "bad numerical value %s\n", val);
+ goto error;
+ }
+ cpu_def->nwindows = nwindows;
+#ifdef DEBUG_FEATURES
+ fprintf(stderr, "nwindows %d\n", nwindows);
+#endif
+ } else {
+ fprintf(stderr, "unrecognized feature %s\n", featurestr);
+ goto error;
+ }
+ } else {
+ fprintf(stderr, "feature string `%s' not in format "
+ "(+feature|-feature|feature=xyz)\n", featurestr);
+ goto error;
+ }
+ featurestr = strtok(NULL, ",");
+ }
+ cpu_def->features |= plus_features;
+ cpu_def->features &= ~minus_features;
+#ifdef DEBUG_FEATURES
+ print_features(stderr, fprintf, cpu_def->features, NULL);
+#endif
+ free(s);
+ return 0;
+
+ error:
+ free(s);
+ return -1;
+}
+
+void sparc_cpu_list(FILE *f, fprintf_function cpu_fprintf)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(sparc_defs); i++) {
+ (*cpu_fprintf)(f, "Sparc %16s IU " TARGET_FMT_lx
+ " FPU %08x MMU %08x NWINS %d ",
+ sparc_defs[i].name,
+ sparc_defs[i].iu_version,
+ sparc_defs[i].fpu_version,
+ sparc_defs[i].mmu_version,
+ sparc_defs[i].nwindows);
+ print_features(f, cpu_fprintf, CPU_DEFAULT_FEATURES &
+ ~sparc_defs[i].features, "-");
+ print_features(f, cpu_fprintf, ~CPU_DEFAULT_FEATURES &
+ sparc_defs[i].features, "+");
+ (*cpu_fprintf)(f, "\n");
+ }
+ (*cpu_fprintf)(f, "Default CPU feature flags (use '-' to remove): ");
+ print_features(f, cpu_fprintf, CPU_DEFAULT_FEATURES, NULL);
+ (*cpu_fprintf)(f, "\n");
+ (*cpu_fprintf)(f, "Available CPU feature flags (use '+' to add): ");
+ print_features(f, cpu_fprintf, ~CPU_DEFAULT_FEATURES, NULL);
+ (*cpu_fprintf)(f, "\n");
+ (*cpu_fprintf)(f, "Numerical features (use '=' to set): iu_version "
+ "fpu_version mmu_version nwindows\n");
+}
+
+static void cpu_print_cc(FILE *f, fprintf_function cpu_fprintf,
+ uint32_t cc)
+{
+ cpu_fprintf(f, "%c%c%c%c", cc & PSR_NEG ? 'N' : '-',
+ cc & PSR_ZERO ? 'Z' : '-', cc & PSR_OVF ? 'V' : '-',
+ cc & PSR_CARRY ? 'C' : '-');
+}
+
+#ifdef TARGET_SPARC64
+#define REGS_PER_LINE 4
+#else
+#define REGS_PER_LINE 8
+#endif
+
+void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf,
+ int flags)
+{
+ int i, x;
+
+ cpu_fprintf(f, "pc: " TARGET_FMT_lx " npc: " TARGET_FMT_lx "\n", env->pc,
+ env->npc);
+ cpu_fprintf(f, "General Registers:\n");
+
+ for (i = 0; i < 8; i++) {
+ if (i % REGS_PER_LINE == 0) {
+ cpu_fprintf(f, "%%g%d-%d:", i, i + REGS_PER_LINE - 1);
+ }
+ cpu_fprintf(f, " " TARGET_FMT_lx, env->gregs[i]);
+ if (i % REGS_PER_LINE == REGS_PER_LINE - 1) {
+ cpu_fprintf(f, "\n");
+ }
+ }
+ cpu_fprintf(f, "\nCurrent Register Window:\n");
+ for (x = 0; x < 3; x++) {
+ for (i = 0; i < 8; i++) {
+ if (i % REGS_PER_LINE == 0) {
+ cpu_fprintf(f, "%%%c%d-%d: ",
+ x == 0 ? 'o' : (x == 1 ? 'l' : 'i'),
+ i, i + REGS_PER_LINE - 1);
+ }
+ cpu_fprintf(f, TARGET_FMT_lx " ", env->regwptr[i + x * 8]);
+ if (i % REGS_PER_LINE == REGS_PER_LINE - 1) {
+ cpu_fprintf(f, "\n");
+ }
+ }
+ }
+ cpu_fprintf(f, "\nFloating Point Registers:\n");
+ for (i = 0; i < TARGET_FPREGS; i++) {
+ if ((i & 3) == 0) {
+ cpu_fprintf(f, "%%f%02d:", i);
+ }
+ cpu_fprintf(f, " %016f", *(float *)&env->fpr[i]);
+ if ((i & 3) == 3) {
+ cpu_fprintf(f, "\n");
+ }
+ }
+#ifdef TARGET_SPARC64
+ cpu_fprintf(f, "pstate: %08x ccr: %02x (icc: ", env->pstate,
+ (unsigned)cpu_get_ccr(env));
+ cpu_print_cc(f, cpu_fprintf, cpu_get_ccr(env) << PSR_CARRY_SHIFT);
+ cpu_fprintf(f, " xcc: ");
+ cpu_print_cc(f, cpu_fprintf, cpu_get_ccr(env) << (PSR_CARRY_SHIFT - 4));
+ cpu_fprintf(f, ") asi: %02x tl: %d pil: %x\n", env->asi, env->tl,
+ env->psrpil);
+ cpu_fprintf(f, "cansave: %d canrestore: %d otherwin: %d wstate: %d "
+ "cleanwin: %d cwp: %d\n",
+ env->cansave, env->canrestore, env->otherwin, env->wstate,
+ env->cleanwin, env->nwindows - 1 - env->cwp);
+ cpu_fprintf(f, "fsr: " TARGET_FMT_lx " y: " TARGET_FMT_lx " fprs: "
+ TARGET_FMT_lx "\n", env->fsr, env->y, env->fprs);
+#else
+ cpu_fprintf(f, "psr: %08x (icc: ", cpu_get_psr(env));
+ cpu_print_cc(f, cpu_fprintf, cpu_get_psr(env));
+ cpu_fprintf(f, " SPE: %c%c%c) wim: %08x\n", env->psrs ? 'S' : '-',
+ env->psrps ? 'P' : '-', env->psret ? 'E' : '-',
+ env->wim);
+ cpu_fprintf(f, "fsr: " TARGET_FMT_lx " y: " TARGET_FMT_lx "\n",
+ env->fsr, env->y);
+#endif
+}
diff --git a/target-sparc/fop_helper.c b/target-sparc/fop_helper.c
new file mode 100644
index 0000000000..23502f3020
--- /dev/null
+++ b/target-sparc/fop_helper.c
@@ -0,0 +1,394 @@
+/*
+ * FPU op helpers
+ *
+ * Copyright (c) 2003-2005 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cpu.h"
+#include "helper.h"
+
+#define DT0 (env->dt0)
+#define DT1 (env->dt1)
+#define QT0 (env->qt0)
+#define QT1 (env->qt1)
+
+#define F_HELPER(name, p) void helper_f##name##p(CPUState *env)
+
+#define F_BINOP(name) \
+ float32 helper_f ## name ## s (CPUState * env, float32 src1,\
+ float32 src2) \
+ { \
+ return float32_ ## name (src1, src2, &env->fp_status); \
+ } \
+ F_HELPER(name, d) \
+ { \
+ DT0 = float64_ ## name (DT0, DT1, &env->fp_status); \
+ } \
+ F_HELPER(name, q) \
+ { \
+ QT0 = float128_ ## name (QT0, QT1, &env->fp_status); \
+ }
+
+F_BINOP(add);
+F_BINOP(sub);
+F_BINOP(mul);
+F_BINOP(div);
+#undef F_BINOP
+
+void helper_fsmuld(CPUState *env, float32 src1, float32 src2)
+{
+ DT0 = float64_mul(float32_to_float64(src1, &env->fp_status),
+ float32_to_float64(src2, &env->fp_status),
+ &env->fp_status);
+}
+
+void helper_fdmulq(CPUState *env)
+{
+ QT0 = float128_mul(float64_to_float128(DT0, &env->fp_status),
+ float64_to_float128(DT1, &env->fp_status),
+ &env->fp_status);
+}
+
+float32 helper_fnegs(float32 src)
+{
+ return float32_chs(src);
+}
+
+#ifdef TARGET_SPARC64
+F_HELPER(neg, d)
+{
+ DT0 = float64_chs(DT1);
+}
+
+F_HELPER(neg, q)
+{
+ QT0 = float128_chs(QT1);
+}
+#endif
+
+/* Integer to float conversion. */
+float32 helper_fitos(CPUState *env, int32_t src)
+{
+ return int32_to_float32(src, &env->fp_status);
+}
+
+void helper_fitod(CPUState *env, int32_t src)
+{
+ DT0 = int32_to_float64(src, &env->fp_status);
+}
+
+void helper_fitoq(CPUState *env, int32_t src)
+{
+ QT0 = int32_to_float128(src, &env->fp_status);
+}
+
+#ifdef TARGET_SPARC64
+float32 helper_fxtos(CPUState *env)
+{
+ return int64_to_float32(*((int64_t *)&DT1), &env->fp_status);
+}
+
+F_HELPER(xto, d)
+{
+ DT0 = int64_to_float64(*((int64_t *)&DT1), &env->fp_status);
+}
+
+F_HELPER(xto, q)
+{
+ QT0 = int64_to_float128(*((int64_t *)&DT1), &env->fp_status);
+}
+#endif
+#undef F_HELPER
+
+/* floating point conversion */
+float32 helper_fdtos(CPUState *env)
+{
+ return float64_to_float32(DT1, &env->fp_status);
+}
+
+void helper_fstod(CPUState *env, float32 src)
+{
+ DT0 = float32_to_float64(src, &env->fp_status);
+}
+
+float32 helper_fqtos(CPUState *env)
+{
+ return float128_to_float32(QT1, &env->fp_status);
+}
+
+void helper_fstoq(CPUState *env, float32 src)
+{
+ QT0 = float32_to_float128(src, &env->fp_status);
+}
+
+void helper_fqtod(CPUState *env)
+{
+ DT0 = float128_to_float64(QT1, &env->fp_status);
+}
+
+void helper_fdtoq(CPUState *env)
+{
+ QT0 = float64_to_float128(DT1, &env->fp_status);
+}
+
+/* Float to integer conversion. */
+int32_t helper_fstoi(CPUState *env, float32 src)
+{
+ return float32_to_int32_round_to_zero(src, &env->fp_status);
+}
+
+int32_t helper_fdtoi(CPUState *env)
+{
+ return float64_to_int32_round_to_zero(DT1, &env->fp_status);
+}
+
+int32_t helper_fqtoi(CPUState *env)
+{
+ return float128_to_int32_round_to_zero(QT1, &env->fp_status);
+}
+
+#ifdef TARGET_SPARC64
+void helper_fstox(CPUState *env, float32 src)
+{
+ *((int64_t *)&DT0) = float32_to_int64_round_to_zero(src, &env->fp_status);
+}
+
+void helper_fdtox(CPUState *env)
+{
+ *((int64_t *)&DT0) = float64_to_int64_round_to_zero(DT1, &env->fp_status);
+}
+
+void helper_fqtox(CPUState *env)
+{
+ *((int64_t *)&DT0) = float128_to_int64_round_to_zero(QT1, &env->fp_status);
+}
+#endif
+
+float32 helper_fabss(float32 src)
+{
+ return float32_abs(src);
+}
+
+#ifdef TARGET_SPARC64
+void helper_fabsd(CPUState *env)
+{
+ DT0 = float64_abs(DT1);
+}
+
+void helper_fabsq(CPUState *env)
+{
+ QT0 = float128_abs(QT1);
+}
+#endif
+
+float32 helper_fsqrts(CPUState *env, float32 src)
+{
+ return float32_sqrt(src, &env->fp_status);
+}
+
+void helper_fsqrtd(CPUState *env)
+{
+ DT0 = float64_sqrt(DT1, &env->fp_status);
+}
+
+void helper_fsqrtq(CPUState *env)
+{
+ QT0 = float128_sqrt(QT1, &env->fp_status);
+}
+
+#define GEN_FCMP(name, size, reg1, reg2, FS, E) \
+ void glue(helper_, name) (CPUState *env) \
+ { \
+ env->fsr &= FSR_FTT_NMASK; \
+ if (E && (glue(size, _is_any_nan)(reg1) || \
+ glue(size, _is_any_nan)(reg2)) && \
+ (env->fsr & FSR_NVM)) { \
+ env->fsr |= FSR_NVC; \
+ env->fsr |= FSR_FTT_IEEE_EXCP; \
+ helper_raise_exception(env, TT_FP_EXCP); \
+ } \
+ switch (glue(size, _compare) (reg1, reg2, &env->fp_status)) { \
+ case float_relation_unordered: \
+ if ((env->fsr & FSR_NVM)) { \
+ env->fsr |= FSR_NVC; \
+ env->fsr |= FSR_FTT_IEEE_EXCP; \
+ helper_raise_exception(env, TT_FP_EXCP); \
+ } else { \
+ env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \
+ env->fsr |= (FSR_FCC1 | FSR_FCC0) << FS; \
+ env->fsr |= FSR_NVA; \
+ } \
+ break; \
+ case float_relation_less: \
+ env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \
+ env->fsr |= FSR_FCC0 << FS; \
+ break; \
+ case float_relation_greater: \
+ env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \
+ env->fsr |= FSR_FCC1 << FS; \
+ break; \
+ default: \
+ env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \
+ break; \
+ } \
+ }
+#define GEN_FCMPS(name, size, FS, E) \
+ void glue(helper_, name)(CPUState *env, float32 src1, float32 src2) \
+ { \
+ env->fsr &= FSR_FTT_NMASK; \
+ if (E && (glue(size, _is_any_nan)(src1) || \
+ glue(size, _is_any_nan)(src2)) && \
+ (env->fsr & FSR_NVM)) { \
+ env->fsr |= FSR_NVC; \
+ env->fsr |= FSR_FTT_IEEE_EXCP; \
+ helper_raise_exception(env, TT_FP_EXCP); \
+ } \
+ switch (glue(size, _compare) (src1, src2, &env->fp_status)) { \
+ case float_relation_unordered: \
+ if ((env->fsr & FSR_NVM)) { \
+ env->fsr |= FSR_NVC; \
+ env->fsr |= FSR_FTT_IEEE_EXCP; \
+ helper_raise_exception(env, TT_FP_EXCP); \
+ } else { \
+ env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \
+ env->fsr |= (FSR_FCC1 | FSR_FCC0) << FS; \
+ env->fsr |= FSR_NVA; \
+ } \
+ break; \
+ case float_relation_less: \
+ env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \
+ env->fsr |= FSR_FCC0 << FS; \
+ break; \
+ case float_relation_greater: \
+ env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \
+ env->fsr |= FSR_FCC1 << FS; \
+ break; \
+ default: \
+ env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \
+ break; \
+ } \
+ }
+
+GEN_FCMPS(fcmps, float32, 0, 0);
+GEN_FCMP(fcmpd, float64, DT0, DT1, 0, 0);
+
+GEN_FCMPS(fcmpes, float32, 0, 1);
+GEN_FCMP(fcmped, float64, DT0, DT1, 0, 1);
+
+GEN_FCMP(fcmpq, float128, QT0, QT1, 0, 0);
+GEN_FCMP(fcmpeq, float128, QT0, QT1, 0, 1);
+
+#ifdef TARGET_SPARC64
+GEN_FCMPS(fcmps_fcc1, float32, 22, 0);
+GEN_FCMP(fcmpd_fcc1, float64, DT0, DT1, 22, 0);
+GEN_FCMP(fcmpq_fcc1, float128, QT0, QT1, 22, 0);
+
+GEN_FCMPS(fcmps_fcc2, float32, 24, 0);
+GEN_FCMP(fcmpd_fcc2, float64, DT0, DT1, 24, 0);
+GEN_FCMP(fcmpq_fcc2, float128, QT0, QT1, 24, 0);
+
+GEN_FCMPS(fcmps_fcc3, float32, 26, 0);
+GEN_FCMP(fcmpd_fcc3, float64, DT0, DT1, 26, 0);
+GEN_FCMP(fcmpq_fcc3, float128, QT0, QT1, 26, 0);
+
+GEN_FCMPS(fcmpes_fcc1, float32, 22, 1);
+GEN_FCMP(fcmped_fcc1, float64, DT0, DT1, 22, 1);
+GEN_FCMP(fcmpeq_fcc1, float128, QT0, QT1, 22, 1);
+
+GEN_FCMPS(fcmpes_fcc2, float32, 24, 1);
+GEN_FCMP(fcmped_fcc2, float64, DT0, DT1, 24, 1);
+GEN_FCMP(fcmpeq_fcc2, float128, QT0, QT1, 24, 1);
+
+GEN_FCMPS(fcmpes_fcc3, float32, 26, 1);
+GEN_FCMP(fcmped_fcc3, float64, DT0, DT1, 26, 1);
+GEN_FCMP(fcmpeq_fcc3, float128, QT0, QT1, 26, 1);
+#endif
+#undef GEN_FCMPS
+
+void helper_check_ieee_exceptions(CPUState *env)
+{
+ target_ulong status;
+
+ status = get_float_exception_flags(&env->fp_status);
+ if (status) {
+ /* Copy IEEE 754 flags into FSR */
+ if (status & float_flag_invalid) {
+ env->fsr |= FSR_NVC;
+ }
+ if (status & float_flag_overflow) {
+ env->fsr |= FSR_OFC;
+ }
+ if (status & float_flag_underflow) {
+ env->fsr |= FSR_UFC;
+ }
+ if (status & float_flag_divbyzero) {
+ env->fsr |= FSR_DZC;
+ }
+ if (status & float_flag_inexact) {
+ env->fsr |= FSR_NXC;
+ }
+
+ if ((env->fsr & FSR_CEXC_MASK) & ((env->fsr & FSR_TEM_MASK) >> 23)) {
+ /* Unmasked exception, generate a trap */
+ env->fsr |= FSR_FTT_IEEE_EXCP;
+ helper_raise_exception(env, TT_FP_EXCP);
+ } else {
+ /* Accumulate exceptions */
+ env->fsr |= (env->fsr & FSR_CEXC_MASK) << 5;
+ }
+ }
+}
+
+void helper_clear_float_exceptions(CPUState *env)
+{
+ set_float_exception_flags(0, &env->fp_status);
+}
+
+static inline void set_fsr(CPUState *env)
+{
+ int rnd_mode;
+
+ switch (env->fsr & FSR_RD_MASK) {
+ case FSR_RD_NEAREST:
+ rnd_mode = float_round_nearest_even;
+ break;
+ default:
+ case FSR_RD_ZERO:
+ rnd_mode = float_round_to_zero;
+ break;
+ case FSR_RD_POS:
+ rnd_mode = float_round_up;
+ break;
+ case FSR_RD_NEG:
+ rnd_mode = float_round_down;
+ break;
+ }
+ set_float_rounding_mode(rnd_mode, &env->fp_status);
+}
+
+void helper_ldfsr(CPUState *env, uint32_t new_fsr)
+{
+ env->fsr = (new_fsr & FSR_LDFSR_MASK) | (env->fsr & FSR_LDFSR_OLDMASK);
+ set_fsr(env);
+}
+
+#ifdef TARGET_SPARC64
+void helper_ldxfsr(CPUState *env, uint64_t new_fsr)
+{
+ env->fsr = (new_fsr & FSR_LDXFSR_MASK) | (env->fsr & FSR_LDXFSR_OLDMASK);
+ set_fsr(env);
+}
+#endif
diff --git a/target-sparc/helper.c b/target-sparc/helper.c
index c80531a16c..18609c449c 100644
--- a/target-sparc/helper.c
+++ b/target-sparc/helper.c
@@ -1,5 +1,5 @@
/*
- * sparc helpers
+ * Misc Sparc helpers
*
* Copyright (c) 2003-2005 Fabrice Bellard
*
@@ -16,1926 +16,133 @@
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
-#include <stdarg.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <inttypes.h>
#include "cpu.h"
-#include "qemu-common.h"
+#include "host-utils.h"
+#include "helper.h"
+#include "sysemu.h"
-//#define DEBUG_MMU
-//#define DEBUG_FEATURES
-
-#ifdef DEBUG_MMU
-#define DPRINTF_MMU(fmt, ...) \
- do { printf("MMU: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF_MMU(fmt, ...) do {} while (0)
-#endif
-
-static int cpu_sparc_find_by_name(sparc_def_t *cpu_def, const char *cpu_model);
-
-/* Sparc MMU emulation */
-
-#if defined(CONFIG_USER_ONLY)
-
-int cpu_sparc_handle_mmu_fault(CPUState *env1, target_ulong address, int rw,
- int mmu_idx)
+void helper_raise_exception(CPUState *env, int tt)
{
- if (rw & 2)
- env1->exception_index = TT_TFAULT;
- else
- env1->exception_index = TT_DFAULT;
- return 1;
+ env->exception_index = tt;
+ cpu_loop_exit(env);
}
-#else
-
-#ifndef TARGET_SPARC64
-/*
- * Sparc V8 Reference MMU (SRMMU)
- */
-static const int access_table[8][8] = {
- { 0, 0, 0, 0, 8, 0, 12, 12 },
- { 0, 0, 0, 0, 8, 0, 0, 0 },
- { 8, 8, 0, 0, 0, 8, 12, 12 },
- { 8, 8, 0, 0, 0, 8, 0, 0 },
- { 8, 0, 8, 0, 8, 8, 12, 12 },
- { 8, 0, 8, 0, 8, 0, 8, 0 },
- { 8, 8, 8, 0, 8, 8, 12, 12 },
- { 8, 8, 8, 0, 8, 8, 8, 0 }
-};
-
-static const int perm_table[2][8] = {
- {
- PAGE_READ,
- PAGE_READ | PAGE_WRITE,
- PAGE_READ | PAGE_EXEC,
- PAGE_READ | PAGE_WRITE | PAGE_EXEC,
- PAGE_EXEC,
- PAGE_READ | PAGE_WRITE,
- PAGE_READ | PAGE_EXEC,
- PAGE_READ | PAGE_WRITE | PAGE_EXEC
- },
- {
- PAGE_READ,
- PAGE_READ | PAGE_WRITE,
- PAGE_READ | PAGE_EXEC,
- PAGE_READ | PAGE_WRITE | PAGE_EXEC,
- PAGE_EXEC,
- PAGE_READ,
- 0,
- 0,
- }
-};
-
-static int get_physical_address(CPUState *env, target_phys_addr_t *physical,
- int *prot, int *access_index,
- target_ulong address, int rw, int mmu_idx,
- target_ulong *page_size)
+void helper_debug(CPUState *env)
{
- int access_perms = 0;
- target_phys_addr_t pde_ptr;
- uint32_t pde;
- int error_code = 0, is_dirty, is_user;
- unsigned long page_offset;
-
- is_user = mmu_idx == MMU_USER_IDX;
-
- if ((env->mmuregs[0] & MMU_E) == 0) { /* MMU disabled */
- *page_size = TARGET_PAGE_SIZE;
- // Boot mode: instruction fetches are taken from PROM
- if (rw == 2 && (env->mmuregs[0] & env->def->mmu_bm)) {
- *physical = env->prom_addr | (address & 0x7ffffULL);
- *prot = PAGE_READ | PAGE_EXEC;
- return 0;
- }
- *physical = address;
- *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
- return 0;
- }
-
- *access_index = ((rw & 1) << 2) | (rw & 2) | (is_user? 0 : 1);
- *physical = 0xffffffffffff0000ULL;
-
- /* SPARC reference MMU table walk: Context table->L1->L2->PTE */
- /* Context base + context number */
- pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2);
- pde = ldl_phys(pde_ptr);
-
- /* Ctx pde */
- switch (pde & PTE_ENTRYTYPE_MASK) {
- default:
- case 0: /* Invalid */
- return 1 << 2;
- case 2: /* L0 PTE, maybe should not happen? */
- case 3: /* Reserved */
- return 4 << 2;
- case 1: /* L0 PDE */
- pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4);
- pde = ldl_phys(pde_ptr);
-
- switch (pde & PTE_ENTRYTYPE_MASK) {
- default:
- case 0: /* Invalid */
- return (1 << 8) | (1 << 2);
- case 3: /* Reserved */
- return (1 << 8) | (4 << 2);
- case 1: /* L1 PDE */
- pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4);
- pde = ldl_phys(pde_ptr);
-
- switch (pde & PTE_ENTRYTYPE_MASK) {
- default:
- case 0: /* Invalid */
- return (2 << 8) | (1 << 2);
- case 3: /* Reserved */
- return (2 << 8) | (4 << 2);
- case 1: /* L2 PDE */
- pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4);
- pde = ldl_phys(pde_ptr);
-
- switch (pde & PTE_ENTRYTYPE_MASK) {
- default:
- case 0: /* Invalid */
- return (3 << 8) | (1 << 2);
- case 1: /* PDE, should not happen */
- case 3: /* Reserved */
- return (3 << 8) | (4 << 2);
- case 2: /* L3 PTE */
- page_offset = (address & TARGET_PAGE_MASK) &
- (TARGET_PAGE_SIZE - 1);
- }
- *page_size = TARGET_PAGE_SIZE;
- break;
- case 2: /* L2 PTE */
- page_offset = address & 0x3ffff;
- *page_size = 0x40000;
- }
- break;
- case 2: /* L1 PTE */
- page_offset = address & 0xffffff;
- *page_size = 0x1000000;
- }
- }
-
- /* check access */
- access_perms = (pde & PTE_ACCESS_MASK) >> PTE_ACCESS_SHIFT;
- error_code = access_table[*access_index][access_perms];
- if (error_code && !((env->mmuregs[0] & MMU_NF) && is_user))
- return error_code;
-
- /* update page modified and dirty bits */
- is_dirty = (rw & 1) && !(pde & PG_MODIFIED_MASK);
- if (!(pde & PG_ACCESSED_MASK) || is_dirty) {
- pde |= PG_ACCESSED_MASK;
- if (is_dirty)
- pde |= PG_MODIFIED_MASK;
- stl_phys_notdirty(pde_ptr, pde);
- }
-
- /* the page can be put in the TLB */
- *prot = perm_table[is_user][access_perms];
- if (!(pde & PG_MODIFIED_MASK)) {
- /* only set write access if already dirty... otherwise wait
- for dirty access */
- *prot &= ~PAGE_WRITE;
- }
-
- /* Even if large ptes, we map only one 4KB page in the cache to
- avoid filling it too fast */
- *physical = ((target_phys_addr_t)(pde & PTE_ADDR_MASK) << 4) + page_offset;
- return error_code;
+ env->exception_index = EXCP_DEBUG;
+ cpu_loop_exit(env);
}
-/* Perform address translation */
-int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
- int mmu_idx)
+void helper_shutdown(void)
{
- target_phys_addr_t paddr;
- target_ulong vaddr;
- target_ulong page_size;
- int error_code = 0, prot, access_index;
-
- error_code = get_physical_address(env, &paddr, &prot, &access_index,
- address, rw, mmu_idx, &page_size);
- if (error_code == 0) {
- vaddr = address & TARGET_PAGE_MASK;
- paddr &= TARGET_PAGE_MASK;
-#ifdef DEBUG_MMU
- printf("Translate at " TARGET_FMT_lx " -> " TARGET_FMT_plx ", vaddr "
- TARGET_FMT_lx "\n", address, paddr, vaddr);
+#if !defined(CONFIG_USER_ONLY)
+ qemu_system_shutdown_request();
#endif
- tlb_set_page(env, vaddr, paddr, prot, mmu_idx, page_size);
- return 0;
- }
-
- if (env->mmuregs[3]) /* Fault status register */
- env->mmuregs[3] = 1; /* overflow (not read before another fault) */
- env->mmuregs[3] |= (access_index << 5) | error_code | 2;
- env->mmuregs[4] = address; /* Fault address register */
-
- if ((env->mmuregs[0] & MMU_NF) || env->psret == 0) {
- // No fault mode: if a mapping is available, just override
- // permissions. If no mapping is available, redirect accesses to
- // neverland. Fake/overridden mappings will be flushed when
- // switching to normal mode.
- vaddr = address & TARGET_PAGE_MASK;
- prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
- tlb_set_page(env, vaddr, paddr, prot, mmu_idx, TARGET_PAGE_SIZE);
- return 0;
- } else {
- if (rw & 2)
- env->exception_index = TT_TFAULT;
- else
- env->exception_index = TT_DFAULT;
- return 1;
- }
}
-target_ulong mmu_probe(CPUState *env, target_ulong address, int mmulev)
+#ifdef TARGET_SPARC64
+target_ulong helper_popc(target_ulong val)
{
- target_phys_addr_t pde_ptr;
- uint32_t pde;
-
- /* Context base + context number */
- pde_ptr = (target_phys_addr_t)(env->mmuregs[1] << 4) +
- (env->mmuregs[2] << 2);
- pde = ldl_phys(pde_ptr);
-
- switch (pde & PTE_ENTRYTYPE_MASK) {
- default:
- case 0: /* Invalid */
- case 2: /* PTE, maybe should not happen? */
- case 3: /* Reserved */
- return 0;
- case 1: /* L1 PDE */
- if (mmulev == 3)
- return pde;
- pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4);
- pde = ldl_phys(pde_ptr);
-
- switch (pde & PTE_ENTRYTYPE_MASK) {
- default:
- case 0: /* Invalid */
- case 3: /* Reserved */
- return 0;
- case 2: /* L1 PTE */
- return pde;
- case 1: /* L2 PDE */
- if (mmulev == 2)
- return pde;
- pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4);
- pde = ldl_phys(pde_ptr);
-
- switch (pde & PTE_ENTRYTYPE_MASK) {
- default:
- case 0: /* Invalid */
- case 3: /* Reserved */
- return 0;
- case 2: /* L2 PTE */
- return pde;
- case 1: /* L3 PDE */
- if (mmulev == 1)
- return pde;
- pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4);
- pde = ldl_phys(pde_ptr);
-
- switch (pde & PTE_ENTRYTYPE_MASK) {
- default:
- case 0: /* Invalid */
- case 1: /* PDE, should not happen */
- case 3: /* Reserved */
- return 0;
- case 2: /* L3 PTE */
- return pde;
- }
- }
- }
- }
- return 0;
+ return ctpop64(val);
}
-void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env)
+void helper_tick_set_count(void *opaque, uint64_t count)
{
- target_ulong va, va1, va2;
- unsigned int n, m, o;
- target_phys_addr_t pde_ptr, pa;
- uint32_t pde;
-
- pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2);
- pde = ldl_phys(pde_ptr);
- (*cpu_fprintf)(f, "Root ptr: " TARGET_FMT_plx ", ctx: %d\n",
- (target_phys_addr_t)env->mmuregs[1] << 4, env->mmuregs[2]);
- for (n = 0, va = 0; n < 256; n++, va += 16 * 1024 * 1024) {
- pde = mmu_probe(env, va, 2);
- if (pde) {
- pa = cpu_get_phys_page_debug(env, va);
- (*cpu_fprintf)(f, "VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_plx
- " PDE: " TARGET_FMT_lx "\n", va, pa, pde);
- for (m = 0, va1 = va; m < 64; m++, va1 += 256 * 1024) {
- pde = mmu_probe(env, va1, 1);
- if (pde) {
- pa = cpu_get_phys_page_debug(env, va1);
- (*cpu_fprintf)(f, " VA: " TARGET_FMT_lx ", PA: "
- TARGET_FMT_plx " PDE: " TARGET_FMT_lx "\n",
- va1, pa, pde);
- for (o = 0, va2 = va1; o < 64; o++, va2 += 4 * 1024) {
- pde = mmu_probe(env, va2, 0);
- if (pde) {
- pa = cpu_get_phys_page_debug(env, va2);
- (*cpu_fprintf)(f, " VA: " TARGET_FMT_lx ", PA: "
- TARGET_FMT_plx " PTE: "
- TARGET_FMT_lx "\n",
- va2, pa, pde);
- }
- }
- }
- }
- }
- }
-}
-
#if !defined(CONFIG_USER_ONLY)
-
-/* Gdb expects all registers windows to be flushed in ram. This function handles
- * reads (and only reads) in stack frames as if windows were flushed. We assume
- * that the sparc ABI is followed.
- */
-int target_memory_rw_debug(CPUState *env, target_ulong addr,
- uint8_t *buf, int len, int is_write)
-{
- int i;
- int len1;
- int cwp = env->cwp;
-
- if (!is_write) {
- for (i = 0; i < env->nwindows; i++) {
- int off;
- target_ulong fp = env->regbase[cwp * 16 + 22];
-
- /* Assume fp == 0 means end of frame. */
- if (fp == 0) {
- break;
- }
-
- cwp = cpu_cwp_inc(env, cwp + 1);
-
- /* Invalid window ? */
- if (env->wim & (1 << cwp)) {
- break;
- }
-
- /* According to the ABI, the stack is growing downward. */
- if (addr + len < fp) {
- break;
- }
-
- /* Not in this frame. */
- if (addr > fp + 64) {
- continue;
- }
-
- /* Handle access before this window. */
- if (addr < fp) {
- len1 = fp - addr;
- if (cpu_memory_rw_debug(env, addr, buf, len1, is_write) != 0) {
- return -1;
- }
- addr += len1;
- len -= len1;
- buf += len1;
- }
-
- /* Access byte per byte to registers. Not very efficient but speed
- * is not critical.
- */
- off = addr - fp;
- len1 = 64 - off;
-
- if (len1 > len) {
- len1 = len;
- }
-
- for (; len1; len1--) {
- int reg = cwp * 16 + 8 + (off >> 2);
- union {
- uint32_t v;
- uint8_t c[4];
- } u;
- u.v = cpu_to_be32(env->regbase[reg]);
- *buf++ = u.c[off & 3];
- addr++;
- len--;
- off++;
- }
-
- if (len == 0) {
- return 0;
- }
- }
- }
- return cpu_memory_rw_debug(env, addr, buf, len, is_write);
-}
-
-#endif /* !defined(CONFIG_USER_ONLY) */
-
-#else /* !TARGET_SPARC64 */
-
-// 41 bit physical address space
-static inline target_phys_addr_t ultrasparc_truncate_physical(uint64_t x)
-{
- return x & 0x1ffffffffffULL;
-}
-
-/*
- * UltraSparc IIi I/DMMUs
- */
-
-// Returns true if TTE tag is valid and matches virtual address value in context
-// requires virtual address mask value calculated from TTE entry size
-static inline int ultrasparc_tag_match(SparcTLBEntry *tlb,
- uint64_t address, uint64_t context,
- target_phys_addr_t *physical)
-{
- uint64_t mask;
-
- switch (TTE_PGSIZE(tlb->tte)) {
- default:
- case 0x0: // 8k
- mask = 0xffffffffffffe000ULL;
- break;
- case 0x1: // 64k
- mask = 0xffffffffffff0000ULL;
- break;
- case 0x2: // 512k
- mask = 0xfffffffffff80000ULL;
- break;
- case 0x3: // 4M
- mask = 0xffffffffffc00000ULL;
- break;
- }
-
- // valid, context match, virtual address match?
- if (TTE_IS_VALID(tlb->tte) &&
- (TTE_IS_GLOBAL(tlb->tte) || tlb_compare_context(tlb, context))
- && compare_masked(address, tlb->tag, mask))
- {
- // decode physical address
- *physical = ((tlb->tte & mask) | (address & ~mask)) & 0x1ffffffe000ULL;
- return 1;
- }
-
- return 0;
-}
-
-static int get_physical_address_data(CPUState *env,
- target_phys_addr_t *physical, int *prot,
- target_ulong address, int rw, int mmu_idx)
-{
- unsigned int i;
- uint64_t context;
- uint64_t sfsr = 0;
-
- int is_user = (mmu_idx == MMU_USER_IDX ||
- mmu_idx == MMU_USER_SECONDARY_IDX);
-
- if ((env->lsu & DMMU_E) == 0) { /* DMMU disabled */
- *physical = ultrasparc_truncate_physical(address);
- *prot = PAGE_READ | PAGE_WRITE;
- return 0;
- }
-
- switch(mmu_idx) {
- case MMU_USER_IDX:
- case MMU_KERNEL_IDX:
- context = env->dmmu.mmu_primary_context & 0x1fff;
- sfsr |= SFSR_CT_PRIMARY;
- break;
- case MMU_USER_SECONDARY_IDX:
- case MMU_KERNEL_SECONDARY_IDX:
- context = env->dmmu.mmu_secondary_context & 0x1fff;
- sfsr |= SFSR_CT_SECONDARY;
- break;
- case MMU_NUCLEUS_IDX:
- sfsr |= SFSR_CT_NUCLEUS;
- /* FALLTHRU */
- default:
- context = 0;
- break;
- }
-
- if (rw == 1) {
- sfsr |= SFSR_WRITE_BIT;
- } else if (rw == 4) {
- sfsr |= SFSR_NF_BIT;
- }
-
- for (i = 0; i < 64; i++) {
- // ctx match, vaddr match, valid?
- if (ultrasparc_tag_match(&env->dtlb[i], address, context, physical)) {
- int do_fault = 0;
-
- // access ok?
- /* multiple bits in SFSR.FT may be set on TT_DFAULT */
- if (TTE_IS_PRIV(env->dtlb[i].tte) && is_user) {
- do_fault = 1;
- sfsr |= SFSR_FT_PRIV_BIT; /* privilege violation */
-
- DPRINTF_MMU("DFAULT at %" PRIx64 " context %" PRIx64
- " mmu_idx=%d tl=%d\n",
- address, context, mmu_idx, env->tl);
- }
- if (rw == 4) {
- if (TTE_IS_SIDEEFFECT(env->dtlb[i].tte)) {
- do_fault = 1;
- sfsr |= SFSR_FT_NF_E_BIT;
- }
- } else {
- if (TTE_IS_NFO(env->dtlb[i].tte)) {
- do_fault = 1;
- sfsr |= SFSR_FT_NFO_BIT;
- }
- }
-
- if (do_fault) {
- /* faults above are reported with TT_DFAULT. */
- env->exception_index = TT_DFAULT;
- } else if (!TTE_IS_W_OK(env->dtlb[i].tte) && (rw == 1)) {
- do_fault = 1;
- env->exception_index = TT_DPROT;
-
- DPRINTF_MMU("DPROT at %" PRIx64 " context %" PRIx64
- " mmu_idx=%d tl=%d\n",
- address, context, mmu_idx, env->tl);
- }
-
- if (!do_fault) {
- *prot = PAGE_READ;
- if (TTE_IS_W_OK(env->dtlb[i].tte)) {
- *prot |= PAGE_WRITE;
- }
-
- TTE_SET_USED(env->dtlb[i].tte);
-
- return 0;
- }
-
- if (env->dmmu.sfsr & SFSR_VALID_BIT) { /* Fault status register */
- sfsr |= SFSR_OW_BIT; /* overflow (not read before
- another fault) */
- }
-
- if (env->pstate & PS_PRIV) {
- sfsr |= SFSR_PR_BIT;
- }
-
- /* FIXME: ASI field in SFSR must be set */
- env->dmmu.sfsr = sfsr | SFSR_VALID_BIT;
-
- env->dmmu.sfar = address; /* Fault address register */
-
- env->dmmu.tag_access = (address & ~0x1fffULL) | context;
-
- return 1;
- }
- }
-
- DPRINTF_MMU("DMISS at %" PRIx64 " context %" PRIx64 "\n",
- address, context);
-
- /*
- * On MMU misses:
- * - UltraSPARC IIi: SFSR and SFAR unmodified
- * - JPS1: SFAR updated and some fields of SFSR updated
- */
- env->dmmu.tag_access = (address & ~0x1fffULL) | context;
- env->exception_index = TT_DMISS;
- return 1;
-}
-
-static int get_physical_address_code(CPUState *env,
- target_phys_addr_t *physical, int *prot,
- target_ulong address, int mmu_idx)
-{
- unsigned int i;
- uint64_t context;
-
- int is_user = (mmu_idx == MMU_USER_IDX ||
- mmu_idx == MMU_USER_SECONDARY_IDX);
-
- if ((env->lsu & IMMU_E) == 0 || (env->pstate & PS_RED) != 0) {
- /* IMMU disabled */
- *physical = ultrasparc_truncate_physical(address);
- *prot = PAGE_EXEC;
- return 0;
- }
-
- if (env->tl == 0) {
- /* PRIMARY context */
- context = env->dmmu.mmu_primary_context & 0x1fff;
- } else {
- /* NUCLEUS context */
- context = 0;
- }
-
- for (i = 0; i < 64; i++) {
- // ctx match, vaddr match, valid?
- if (ultrasparc_tag_match(&env->itlb[i],
- address, context, physical)) {
- // access ok?
- if (TTE_IS_PRIV(env->itlb[i].tte) && is_user) {
- /* Fault status register */
- if (env->immu.sfsr & SFSR_VALID_BIT) {
- env->immu.sfsr = SFSR_OW_BIT; /* overflow (not read before
- another fault) */
- } else {
- env->immu.sfsr = 0;
- }
- if (env->pstate & PS_PRIV) {
- env->immu.sfsr |= SFSR_PR_BIT;
- }
- if (env->tl > 0) {
- env->immu.sfsr |= SFSR_CT_NUCLEUS;
- }
-
- /* FIXME: ASI field in SFSR must be set */
- env->immu.sfsr |= SFSR_FT_PRIV_BIT | SFSR_VALID_BIT;
- env->exception_index = TT_TFAULT;
-
- env->immu.tag_access = (address & ~0x1fffULL) | context;
-
- DPRINTF_MMU("TFAULT at %" PRIx64 " context %" PRIx64 "\n",
- address, context);
-
- return 1;
- }
- *prot = PAGE_EXEC;
- TTE_SET_USED(env->itlb[i].tte);
- return 0;
- }
- }
-
- DPRINTF_MMU("TMISS at %" PRIx64 " context %" PRIx64 "\n",
- address, context);
-
- /* Context is stored in DMMU (dmmuregs[1]) also for IMMU */
- env->immu.tag_access = (address & ~0x1fffULL) | context;
- env->exception_index = TT_TMISS;
- return 1;
-}
-
-static int get_physical_address(CPUState *env, target_phys_addr_t *physical,
- int *prot, int *access_index,
- target_ulong address, int rw, int mmu_idx,
- target_ulong *page_size)
-{
- /* ??? We treat everything as a small page, then explicitly flush
- everything when an entry is evicted. */
- *page_size = TARGET_PAGE_SIZE;
-
-#if defined (DEBUG_MMU)
- /* safety net to catch wrong softmmu index use from dynamic code */
- if (env->tl > 0 && mmu_idx != MMU_NUCLEUS_IDX) {
- DPRINTF_MMU("get_physical_address %s tl=%d mmu_idx=%d"
- " primary context=%" PRIx64
- " secondary context=%" PRIx64
- " address=%" PRIx64
- "\n",
- (rw == 2 ? "CODE" : "DATA"),
- env->tl, mmu_idx,
- env->dmmu.mmu_primary_context,
- env->dmmu.mmu_secondary_context,
- address);
- }
+ cpu_tick_set_count(opaque, count);
#endif
-
- if (rw == 2)
- return get_physical_address_code(env, physical, prot, address,
- mmu_idx);
- else
- return get_physical_address_data(env, physical, prot, address, rw,
- mmu_idx);
-}
-
-/* Perform address translation */
-int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
- int mmu_idx)
-{
- target_ulong virt_addr, vaddr;
- target_phys_addr_t paddr;
- target_ulong page_size;
- int error_code = 0, prot, access_index;
-
- error_code = get_physical_address(env, &paddr, &prot, &access_index,
- address, rw, mmu_idx, &page_size);
- if (error_code == 0) {
- virt_addr = address & TARGET_PAGE_MASK;
- vaddr = virt_addr + ((address & TARGET_PAGE_MASK) &
- (TARGET_PAGE_SIZE - 1));
-
- DPRINTF_MMU("Translate at %" PRIx64 " -> %" PRIx64 ","
- " vaddr %" PRIx64
- " mmu_idx=%d"
- " tl=%d"
- " primary context=%" PRIx64
- " secondary context=%" PRIx64
- "\n",
- address, paddr, vaddr, mmu_idx, env->tl,
- env->dmmu.mmu_primary_context,
- env->dmmu.mmu_secondary_context);
-
- tlb_set_page(env, vaddr, paddr, prot, mmu_idx, page_size);
- return 0;
- }
- // XXX
- return 1;
}
-void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env)
+uint64_t helper_tick_get_count(void *opaque)
{
- unsigned int i;
- const char *mask;
-
- (*cpu_fprintf)(f, "MMU contexts: Primary: %" PRId64 ", Secondary: %"
- PRId64 "\n",
- env->dmmu.mmu_primary_context,
- env->dmmu.mmu_secondary_context);
- if ((env->lsu & DMMU_E) == 0) {
- (*cpu_fprintf)(f, "DMMU disabled\n");
- } else {
- (*cpu_fprintf)(f, "DMMU dump\n");
- for (i = 0; i < 64; i++) {
- switch (TTE_PGSIZE(env->dtlb[i].tte)) {
- default:
- case 0x0:
- mask = " 8k";
- break;
- case 0x1:
- mask = " 64k";
- break;
- case 0x2:
- mask = "512k";
- break;
- case 0x3:
- mask = " 4M";
- break;
- }
- if (TTE_IS_VALID(env->dtlb[i].tte)) {
- (*cpu_fprintf)(f, "[%02u] VA: %" PRIx64 ", PA: %llx"
- ", %s, %s, %s, %s, ctx %" PRId64 " %s\n",
- i,
- env->dtlb[i].tag & (uint64_t)~0x1fffULL,
- TTE_PA(env->dtlb[i].tte),
- mask,
- TTE_IS_PRIV(env->dtlb[i].tte) ? "priv" : "user",
- TTE_IS_W_OK(env->dtlb[i].tte) ? "RW" : "RO",
- TTE_IS_LOCKED(env->dtlb[i].tte) ?
- "locked" : "unlocked",
- env->dtlb[i].tag & (uint64_t)0x1fffULL,
- TTE_IS_GLOBAL(env->dtlb[i].tte)?
- "global" : "local");
- }
- }
- }
- if ((env->lsu & IMMU_E) == 0) {
- (*cpu_fprintf)(f, "IMMU disabled\n");
- } else {
- (*cpu_fprintf)(f, "IMMU dump\n");
- for (i = 0; i < 64; i++) {
- switch (TTE_PGSIZE(env->itlb[i].tte)) {
- default:
- case 0x0:
- mask = " 8k";
- break;
- case 0x1:
- mask = " 64k";
- break;
- case 0x2:
- mask = "512k";
- break;
- case 0x3:
- mask = " 4M";
- break;
- }
- if (TTE_IS_VALID(env->itlb[i].tte)) {
- (*cpu_fprintf)(f, "[%02u] VA: %" PRIx64 ", PA: %llx"
- ", %s, %s, %s, ctx %" PRId64 " %s\n",
- i,
- env->itlb[i].tag & (uint64_t)~0x1fffULL,
- TTE_PA(env->itlb[i].tte),
- mask,
- TTE_IS_PRIV(env->itlb[i].tte) ? "priv" : "user",
- TTE_IS_LOCKED(env->itlb[i].tte) ?
- "locked" : "unlocked",
- env->itlb[i].tag & (uint64_t)0x1fffULL,
- TTE_IS_GLOBAL(env->itlb[i].tte)?
- "global" : "local");
- }
- }
- }
-}
-
-#endif /* TARGET_SPARC64 */
-#endif /* !CONFIG_USER_ONLY */
-
-
#if !defined(CONFIG_USER_ONLY)
-static int cpu_sparc_get_phys_page(CPUState *env, target_phys_addr_t *phys,
- target_ulong addr, int rw, int mmu_idx)
-{
- target_ulong page_size;
- int prot, access_index;
-
- return get_physical_address(env, phys, &prot, &access_index, addr, rw,
- mmu_idx, &page_size);
-}
-
-#if defined(TARGET_SPARC64)
-target_phys_addr_t cpu_get_phys_page_nofault(CPUState *env, target_ulong addr,
- int mmu_idx)
-{
- target_phys_addr_t phys_addr;
-
- if (cpu_sparc_get_phys_page(env, &phys_addr, addr, 4, mmu_idx) != 0) {
- return -1;
- }
- return phys_addr;
-}
+ return cpu_tick_get_count(opaque);
+#else
+ return 0;
#endif
-
-target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
-{
- target_phys_addr_t phys_addr;
- int mmu_idx = cpu_mmu_index(env);
-
- if (cpu_sparc_get_phys_page(env, &phys_addr, addr, 2, mmu_idx) != 0) {
- if (cpu_sparc_get_phys_page(env, &phys_addr, addr, 0, mmu_idx) != 0) {
- return -1;
- }
- }
- if (cpu_get_physical_page_desc(phys_addr) == IO_MEM_UNASSIGNED) {
- return -1;
- }
- return phys_addr;
}
-#endif
-
-#ifdef TARGET_SPARC64
-#ifdef DEBUG_PCALL
-static const char * const excp_names[0x80] = {
- [TT_TFAULT] = "Instruction Access Fault",
- [TT_TMISS] = "Instruction Access MMU Miss",
- [TT_CODE_ACCESS] = "Instruction Access Error",
- [TT_ILL_INSN] = "Illegal Instruction",
- [TT_PRIV_INSN] = "Privileged Instruction",
- [TT_NFPU_INSN] = "FPU Disabled",
- [TT_FP_EXCP] = "FPU Exception",
- [TT_TOVF] = "Tag Overflow",
- [TT_CLRWIN] = "Clean Windows",
- [TT_DIV_ZERO] = "Division By Zero",
- [TT_DFAULT] = "Data Access Fault",
- [TT_DMISS] = "Data Access MMU Miss",
- [TT_DATA_ACCESS] = "Data Access Error",
- [TT_DPROT] = "Data Protection Error",
- [TT_UNALIGNED] = "Unaligned Memory Access",
- [TT_PRIV_ACT] = "Privileged Action",
- [TT_EXTINT | 0x1] = "External Interrupt 1",
- [TT_EXTINT | 0x2] = "External Interrupt 2",
- [TT_EXTINT | 0x3] = "External Interrupt 3",
- [TT_EXTINT | 0x4] = "External Interrupt 4",
- [TT_EXTINT | 0x5] = "External Interrupt 5",
- [TT_EXTINT | 0x6] = "External Interrupt 6",
- [TT_EXTINT | 0x7] = "External Interrupt 7",
- [TT_EXTINT | 0x8] = "External Interrupt 8",
- [TT_EXTINT | 0x9] = "External Interrupt 9",
- [TT_EXTINT | 0xa] = "External Interrupt 10",
- [TT_EXTINT | 0xb] = "External Interrupt 11",
- [TT_EXTINT | 0xc] = "External Interrupt 12",
- [TT_EXTINT | 0xd] = "External Interrupt 13",
- [TT_EXTINT | 0xe] = "External Interrupt 14",
- [TT_EXTINT | 0xf] = "External Interrupt 15",
-};
-#endif
-void do_interrupt(CPUState *env)
+void helper_tick_set_limit(void *opaque, uint64_t limit)
{
- int intno = env->exception_index;
- trap_state *tsptr;
-
-#ifdef DEBUG_PCALL
- if (qemu_loglevel_mask(CPU_LOG_INT)) {
- static int count;
- const char *name;
-
- if (intno < 0 || intno >= 0x180) {
- name = "Unknown";
- } else if (intno >= 0x100) {
- name = "Trap Instruction";
- } else if (intno >= 0xc0) {
- name = "Window Fill";
- } else if (intno >= 0x80) {
- name = "Window Spill";
- } else {
- name = excp_names[intno];
- if (!name) {
- name = "Unknown";
- }
- }
-
- qemu_log("%6d: %s (v=%04x) pc=%016" PRIx64 " npc=%016" PRIx64
- " SP=%016" PRIx64 "\n",
- count, name, intno,
- env->pc,
- env->npc, env->regwptr[6]);
- log_cpu_state(env, 0);
-#if 0
- {
- int i;
- uint8_t *ptr;
-
- qemu_log(" code=");
- ptr = (uint8_t *)env->pc;
- for (i = 0; i < 16; i++) {
- qemu_log(" %02x", ldub(ptr + i));
- }
- qemu_log("\n");
- }
-#endif
- count++;
- }
-#endif
#if !defined(CONFIG_USER_ONLY)
- if (env->tl >= env->maxtl) {
- cpu_abort(env, "Trap 0x%04x while trap level (%d) >= MAXTL (%d),"
- " Error state", env->exception_index, env->tl, env->maxtl);
- return;
- }
+ cpu_tick_set_limit(opaque, limit);
#endif
- if (env->tl < env->maxtl - 1) {
- env->tl++;
- } else {
- env->pstate |= PS_RED;
- if (env->tl < env->maxtl) {
- env->tl++;
- }
- }
- tsptr = cpu_tsptr(env);
-
- tsptr->tstate = (cpu_get_ccr(env) << 32) |
- ((env->asi & 0xff) << 24) | ((env->pstate & 0xf3f) << 8) |
- cpu_get_cwp64(env);
- tsptr->tpc = env->pc;
- tsptr->tnpc = env->npc;
- tsptr->tt = intno;
-
- switch (intno) {
- case TT_IVEC:
- cpu_change_pstate(env, PS_PEF | PS_PRIV | PS_IG);
- break;
- case TT_TFAULT:
- case TT_DFAULT:
- case TT_TMISS ... TT_TMISS + 3:
- case TT_DMISS ... TT_DMISS + 3:
- case TT_DPROT ... TT_DPROT + 3:
- cpu_change_pstate(env, PS_PEF | PS_PRIV | PS_MG);
- break;
- default:
- cpu_change_pstate(env, PS_PEF | PS_PRIV | PS_AG);
- break;
- }
-
- if (intno == TT_CLRWIN) {
- cpu_set_cwp(env, cpu_cwp_dec(env, env->cwp - 1));
- } else if ((intno & 0x1c0) == TT_SPILL) {
- cpu_set_cwp(env, cpu_cwp_dec(env, env->cwp - env->cansave - 2));
- } else if ((intno & 0x1c0) == TT_FILL) {
- cpu_set_cwp(env, cpu_cwp_inc(env, env->cwp + 1));
- }
- env->tbr &= ~0x7fffULL;
- env->tbr |= ((env->tl > 1) ? 1 << 14 : 0) | (intno << 5);
- env->pc = env->tbr;
- env->npc = env->pc + 4;
- env->exception_index = -1;
}
-#else
-#ifdef DEBUG_PCALL
-static const char * const excp_names[0x80] = {
- [TT_TFAULT] = "Instruction Access Fault",
- [TT_ILL_INSN] = "Illegal Instruction",
- [TT_PRIV_INSN] = "Privileged Instruction",
- [TT_NFPU_INSN] = "FPU Disabled",
- [TT_WIN_OVF] = "Window Overflow",
- [TT_WIN_UNF] = "Window Underflow",
- [TT_UNALIGNED] = "Unaligned Memory Access",
- [TT_FP_EXCP] = "FPU Exception",
- [TT_DFAULT] = "Data Access Fault",
- [TT_TOVF] = "Tag Overflow",
- [TT_EXTINT | 0x1] = "External Interrupt 1",
- [TT_EXTINT | 0x2] = "External Interrupt 2",
- [TT_EXTINT | 0x3] = "External Interrupt 3",
- [TT_EXTINT | 0x4] = "External Interrupt 4",
- [TT_EXTINT | 0x5] = "External Interrupt 5",
- [TT_EXTINT | 0x6] = "External Interrupt 6",
- [TT_EXTINT | 0x7] = "External Interrupt 7",
- [TT_EXTINT | 0x8] = "External Interrupt 8",
- [TT_EXTINT | 0x9] = "External Interrupt 9",
- [TT_EXTINT | 0xa] = "External Interrupt 10",
- [TT_EXTINT | 0xb] = "External Interrupt 11",
- [TT_EXTINT | 0xc] = "External Interrupt 12",
- [TT_EXTINT | 0xd] = "External Interrupt 13",
- [TT_EXTINT | 0xe] = "External Interrupt 14",
- [TT_EXTINT | 0xf] = "External Interrupt 15",
- [TT_TOVF] = "Tag Overflow",
- [TT_CODE_ACCESS] = "Instruction Access Error",
- [TT_DATA_ACCESS] = "Data Access Error",
- [TT_DIV_ZERO] = "Division By Zero",
- [TT_NCP_INSN] = "Coprocessor Disabled",
-};
#endif
-void do_interrupt(CPUState *env)
+static target_ulong helper_udiv_common(CPUState *env, target_ulong a,
+ target_ulong b, int cc)
{
- int cwp, intno = env->exception_index;
-
-#ifdef DEBUG_PCALL
- if (qemu_loglevel_mask(CPU_LOG_INT)) {
- static int count;
- const char *name;
-
- if (intno < 0 || intno >= 0x100) {
- name = "Unknown";
- } else if (intno >= 0x80) {
- name = "Trap Instruction";
- } else {
- name = excp_names[intno];
- if (!name) {
- name = "Unknown";
- }
- }
-
- qemu_log("%6d: %s (v=%02x) pc=%08x npc=%08x SP=%08x\n",
- count, name, intno,
- env->pc,
- env->npc, env->regwptr[6]);
- log_cpu_state(env, 0);
-#if 0
- {
- int i;
- uint8_t *ptr;
+ int overflow = 0;
+ uint64_t x0;
+ uint32_t x1;
- qemu_log(" code=");
- ptr = (uint8_t *)env->pc;
- for (i = 0; i < 16; i++) {
- qemu_log(" %02x", ldub(ptr + i));
- }
- qemu_log("\n");
- }
-#endif
- count++;
- }
-#endif
-#if !defined(CONFIG_USER_ONLY)
- if (env->psret == 0) {
- cpu_abort(env, "Trap 0x%02x while interrupts disabled, Error state",
- env->exception_index);
- return;
- }
-#endif
- env->psret = 0;
- cwp = cpu_cwp_dec(env, env->cwp - 1);
- cpu_set_cwp(env, cwp);
- env->regwptr[9] = env->pc;
- env->regwptr[10] = env->npc;
- env->psrps = env->psrs;
- env->psrs = 1;
- env->tbr = (env->tbr & TBR_BASE_MASK) | (intno << 4);
- env->pc = env->tbr;
- env->npc = env->pc + 4;
- env->exception_index = -1;
+ x0 = (a & 0xffffffff) | ((int64_t) (env->y) << 32);
+ x1 = (b & 0xffffffff);
-#if !defined(CONFIG_USER_ONLY)
- /* IRQ acknowledgment */
- if ((intno & ~15) == TT_EXTINT && env->qemu_irq_ack != NULL) {
- env->qemu_irq_ack(env->irq_manager, intno);
+ if (x1 == 0) {
+ helper_raise_exception(env, TT_DIV_ZERO);
}
-#endif
-}
-#endif
-void cpu_reset(CPUSPARCState *env)
-{
- if (qemu_loglevel_mask(CPU_LOG_RESET)) {
- qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
- log_cpu_state(env, 0);
+ x0 = x0 / x1;
+ if (x0 > 0xffffffff) {
+ x0 = 0xffffffff;
+ overflow = 1;
}
- tlb_flush(env, 1);
- env->cwp = 0;
-#ifndef TARGET_SPARC64
- env->wim = 1;
-#endif
- env->regwptr = env->regbase + (env->cwp * 16);
- CC_OP = CC_OP_FLAGS;
-#if defined(CONFIG_USER_ONLY)
-#ifdef TARGET_SPARC64
- env->cleanwin = env->nwindows - 2;
- env->cansave = env->nwindows - 2;
- env->pstate = PS_RMO | PS_PEF | PS_IE;
- env->asi = 0x82; // Primary no-fault
-#endif
-#else
-#if !defined(TARGET_SPARC64)
- env->psret = 0;
- env->psrs = 1;
- env->psrps = 1;
-#endif
-#ifdef TARGET_SPARC64
- env->pstate = PS_PRIV|PS_RED|PS_PEF|PS_AG;
- env->hpstate = cpu_has_hypervisor(env) ? HS_PRIV : 0;
- env->tl = env->maxtl;
- cpu_tsptr(env)->tt = TT_POWER_ON_RESET;
- env->lsu = 0;
-#else
- env->mmuregs[0] &= ~(MMU_E | MMU_NF);
- env->mmuregs[0] |= env->def->mmu_bm;
-#endif
- env->pc = 0;
- env->npc = env->pc + 4;
-#endif
- env->cache_control = 0;
-}
-
-static int cpu_sparc_register(CPUSPARCState *env, const char *cpu_model)
-{
- sparc_def_t def1, *def = &def1;
-
- if (cpu_sparc_find_by_name(def, cpu_model) < 0)
- return -1;
-
- env->def = g_malloc0(sizeof(*def));
- memcpy(env->def, def, sizeof(*def));
-#if defined(CONFIG_USER_ONLY)
- if ((env->def->features & CPU_FEATURE_FLOAT))
- env->def->features |= CPU_FEATURE_FLOAT128;
-#endif
- env->cpu_model_str = cpu_model;
- env->version = def->iu_version;
- env->fsr = def->fpu_version;
- env->nwindows = def->nwindows;
-#if !defined(TARGET_SPARC64)
- env->mmuregs[0] |= def->mmu_version;
- cpu_sparc_set_id(env, 0);
- env->mxccregs[7] |= def->mxcc_version;
-#else
- env->mmu_version = def->mmu_version;
- env->maxtl = def->maxtl;
- env->version |= def->maxtl << 8;
- env->version |= def->nwindows - 1;
-#endif
- return 0;
-}
-
-static void cpu_sparc_close(CPUSPARCState *env)
-{
- free(env->def);
- free(env);
-}
-
-CPUSPARCState *cpu_sparc_init(const char *cpu_model)
-{
- CPUSPARCState *env;
-
- env = g_malloc0(sizeof(CPUSPARCState));
- cpu_exec_init(env);
-
- gen_intermediate_code_init(env);
-
- if (cpu_sparc_register(env, cpu_model) < 0) {
- cpu_sparc_close(env);
- return NULL;
+ if (cc) {
+ env->cc_dst = x0;
+ env->cc_src2 = overflow;
+ env->cc_op = CC_OP_DIV;
}
- qemu_init_vcpu(env);
-
- return env;
+ return x0;
}
-void cpu_sparc_set_id(CPUSPARCState *env, unsigned int cpu)
+target_ulong helper_udiv(CPUState *env, target_ulong a, target_ulong b)
{
-#if !defined(TARGET_SPARC64)
- env->mxccregs[7] = ((cpu + 8) & 0xf) << 24;
-#endif
+ return helper_udiv_common(env, a, b, 0);
}
-static const sparc_def_t sparc_defs[] = {
-#ifdef TARGET_SPARC64
- {
- .name = "Fujitsu Sparc64",
- .iu_version = ((0x04ULL << 48) | (0x02ULL << 32) | (0ULL << 24)),
- .fpu_version = 0x00000000,
- .mmu_version = mmu_us_12,
- .nwindows = 4,
- .maxtl = 4,
- .features = CPU_DEFAULT_FEATURES,
- },
- {
- .name = "Fujitsu Sparc64 III",
- .iu_version = ((0x04ULL << 48) | (0x03ULL << 32) | (0ULL << 24)),
- .fpu_version = 0x00000000,
- .mmu_version = mmu_us_12,
- .nwindows = 5,
- .maxtl = 4,
- .features = CPU_DEFAULT_FEATURES,
- },
- {
- .name = "Fujitsu Sparc64 IV",
- .iu_version = ((0x04ULL << 48) | (0x04ULL << 32) | (0ULL << 24)),
- .fpu_version = 0x00000000,
- .mmu_version = mmu_us_12,
- .nwindows = 8,
- .maxtl = 5,
- .features = CPU_DEFAULT_FEATURES,
- },
- {
- .name = "Fujitsu Sparc64 V",
- .iu_version = ((0x04ULL << 48) | (0x05ULL << 32) | (0x51ULL << 24)),
- .fpu_version = 0x00000000,
- .mmu_version = mmu_us_12,
- .nwindows = 8,
- .maxtl = 5,
- .features = CPU_DEFAULT_FEATURES,
- },
- {
- .name = "TI UltraSparc I",
- .iu_version = ((0x17ULL << 48) | (0x10ULL << 32) | (0x40ULL << 24)),
- .fpu_version = 0x00000000,
- .mmu_version = mmu_us_12,
- .nwindows = 8,
- .maxtl = 5,
- .features = CPU_DEFAULT_FEATURES,
- },
- {
- .name = "TI UltraSparc II",
- .iu_version = ((0x17ULL << 48) | (0x11ULL << 32) | (0x20ULL << 24)),
- .fpu_version = 0x00000000,
- .mmu_version = mmu_us_12,
- .nwindows = 8,
- .maxtl = 5,
- .features = CPU_DEFAULT_FEATURES,
- },
- {
- .name = "TI UltraSparc IIi",
- .iu_version = ((0x17ULL << 48) | (0x12ULL << 32) | (0x91ULL << 24)),
- .fpu_version = 0x00000000,
- .mmu_version = mmu_us_12,
- .nwindows = 8,
- .maxtl = 5,
- .features = CPU_DEFAULT_FEATURES,
- },
- {
- .name = "TI UltraSparc IIe",
- .iu_version = ((0x17ULL << 48) | (0x13ULL << 32) | (0x14ULL << 24)),
- .fpu_version = 0x00000000,
- .mmu_version = mmu_us_12,
- .nwindows = 8,
- .maxtl = 5,
- .features = CPU_DEFAULT_FEATURES,
- },
- {
- .name = "Sun UltraSparc III",
- .iu_version = ((0x3eULL << 48) | (0x14ULL << 32) | (0x34ULL << 24)),
- .fpu_version = 0x00000000,
- .mmu_version = mmu_us_12,
- .nwindows = 8,
- .maxtl = 5,
- .features = CPU_DEFAULT_FEATURES,
- },
- {
- .name = "Sun UltraSparc III Cu",
- .iu_version = ((0x3eULL << 48) | (0x15ULL << 32) | (0x41ULL << 24)),
- .fpu_version = 0x00000000,
- .mmu_version = mmu_us_3,
- .nwindows = 8,
- .maxtl = 5,
- .features = CPU_DEFAULT_FEATURES,
- },
- {
- .name = "Sun UltraSparc IIIi",
- .iu_version = ((0x3eULL << 48) | (0x16ULL << 32) | (0x34ULL << 24)),
- .fpu_version = 0x00000000,
- .mmu_version = mmu_us_12,
- .nwindows = 8,
- .maxtl = 5,
- .features = CPU_DEFAULT_FEATURES,
- },
- {
- .name = "Sun UltraSparc IV",
- .iu_version = ((0x3eULL << 48) | (0x18ULL << 32) | (0x31ULL << 24)),
- .fpu_version = 0x00000000,
- .mmu_version = mmu_us_4,
- .nwindows = 8,
- .maxtl = 5,
- .features = CPU_DEFAULT_FEATURES,
- },
- {
- .name = "Sun UltraSparc IV+",
- .iu_version = ((0x3eULL << 48) | (0x19ULL << 32) | (0x22ULL << 24)),
- .fpu_version = 0x00000000,
- .mmu_version = mmu_us_12,
- .nwindows = 8,
- .maxtl = 5,
- .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_CMT,
- },
- {
- .name = "Sun UltraSparc IIIi+",
- .iu_version = ((0x3eULL << 48) | (0x22ULL << 32) | (0ULL << 24)),
- .fpu_version = 0x00000000,
- .mmu_version = mmu_us_3,
- .nwindows = 8,
- .maxtl = 5,
- .features = CPU_DEFAULT_FEATURES,
- },
- {
- .name = "Sun UltraSparc T1",
- // defined in sparc_ifu_fdp.v and ctu.h
- .iu_version = ((0x3eULL << 48) | (0x23ULL << 32) | (0x02ULL << 24)),
- .fpu_version = 0x00000000,
- .mmu_version = mmu_sun4v,
- .nwindows = 8,
- .maxtl = 6,
- .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_HYPV | CPU_FEATURE_CMT
- | CPU_FEATURE_GL,
- },
- {
- .name = "Sun UltraSparc T2",
- // defined in tlu_asi_ctl.v and n2_revid_cust.v
- .iu_version = ((0x3eULL << 48) | (0x24ULL << 32) | (0x02ULL << 24)),
- .fpu_version = 0x00000000,
- .mmu_version = mmu_sun4v,
- .nwindows = 8,
- .maxtl = 6,
- .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_HYPV | CPU_FEATURE_CMT
- | CPU_FEATURE_GL,
- },
- {
- .name = "NEC UltraSparc I",
- .iu_version = ((0x22ULL << 48) | (0x10ULL << 32) | (0x40ULL << 24)),
- .fpu_version = 0x00000000,
- .mmu_version = mmu_us_12,
- .nwindows = 8,
- .maxtl = 5,
- .features = CPU_DEFAULT_FEATURES,
- },
-#else
- {
- .name = "Fujitsu MB86900",
- .iu_version = 0x00 << 24, /* Impl 0, ver 0 */
- .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
- .mmu_version = 0x00 << 24, /* Impl 0, ver 0 */
- .mmu_bm = 0x00004000,
- .mmu_ctpr_mask = 0x007ffff0,
- .mmu_cxr_mask = 0x0000003f,
- .mmu_sfsr_mask = 0xffffffff,
- .mmu_trcr_mask = 0xffffffff,
- .nwindows = 7,
- .features = CPU_FEATURE_FLOAT | CPU_FEATURE_FSMULD,
- },
- {
- .name = "Fujitsu MB86904",
- .iu_version = 0x04 << 24, /* Impl 0, ver 4 */
- .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
- .mmu_version = 0x04 << 24, /* Impl 0, ver 4 */
- .mmu_bm = 0x00004000,
- .mmu_ctpr_mask = 0x00ffffc0,
- .mmu_cxr_mask = 0x000000ff,
- .mmu_sfsr_mask = 0x00016fff,
- .mmu_trcr_mask = 0x00ffffff,
- .nwindows = 8,
- .features = CPU_DEFAULT_FEATURES,
- },
- {
- .name = "Fujitsu MB86907",
- .iu_version = 0x05 << 24, /* Impl 0, ver 5 */
- .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
- .mmu_version = 0x05 << 24, /* Impl 0, ver 5 */
- .mmu_bm = 0x00004000,
- .mmu_ctpr_mask = 0xffffffc0,
- .mmu_cxr_mask = 0x000000ff,
- .mmu_sfsr_mask = 0x00016fff,
- .mmu_trcr_mask = 0xffffffff,
- .nwindows = 8,
- .features = CPU_DEFAULT_FEATURES,
- },
- {
- .name = "LSI L64811",
- .iu_version = 0x10 << 24, /* Impl 1, ver 0 */
- .fpu_version = 1 << 17, /* FPU version 1 (LSI L64814) */
- .mmu_version = 0x10 << 24,
- .mmu_bm = 0x00004000,
- .mmu_ctpr_mask = 0x007ffff0,
- .mmu_cxr_mask = 0x0000003f,
- .mmu_sfsr_mask = 0xffffffff,
- .mmu_trcr_mask = 0xffffffff,
- .nwindows = 8,
- .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT |
- CPU_FEATURE_FSMULD,
- },
- {
- .name = "Cypress CY7C601",
- .iu_version = 0x11 << 24, /* Impl 1, ver 1 */
- .fpu_version = 3 << 17, /* FPU version 3 (Cypress CY7C602) */
- .mmu_version = 0x10 << 24,
- .mmu_bm = 0x00004000,
- .mmu_ctpr_mask = 0x007ffff0,
- .mmu_cxr_mask = 0x0000003f,
- .mmu_sfsr_mask = 0xffffffff,
- .mmu_trcr_mask = 0xffffffff,
- .nwindows = 8,
- .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT |
- CPU_FEATURE_FSMULD,
- },
- {
- .name = "Cypress CY7C611",
- .iu_version = 0x13 << 24, /* Impl 1, ver 3 */
- .fpu_version = 3 << 17, /* FPU version 3 (Cypress CY7C602) */
- .mmu_version = 0x10 << 24,
- .mmu_bm = 0x00004000,
- .mmu_ctpr_mask = 0x007ffff0,
- .mmu_cxr_mask = 0x0000003f,
- .mmu_sfsr_mask = 0xffffffff,
- .mmu_trcr_mask = 0xffffffff,
- .nwindows = 8,
- .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT |
- CPU_FEATURE_FSMULD,
- },
- {
- .name = "TI MicroSparc I",
- .iu_version = 0x41000000,
- .fpu_version = 4 << 17,
- .mmu_version = 0x41000000,
- .mmu_bm = 0x00004000,
- .mmu_ctpr_mask = 0x007ffff0,
- .mmu_cxr_mask = 0x0000003f,
- .mmu_sfsr_mask = 0x00016fff,
- .mmu_trcr_mask = 0x0000003f,
- .nwindows = 7,
- .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_MUL |
- CPU_FEATURE_DIV | CPU_FEATURE_FLUSH | CPU_FEATURE_FSQRT |
- CPU_FEATURE_FMUL,
- },
- {
- .name = "TI MicroSparc II",
- .iu_version = 0x42000000,
- .fpu_version = 4 << 17,
- .mmu_version = 0x02000000,
- .mmu_bm = 0x00004000,
- .mmu_ctpr_mask = 0x00ffffc0,
- .mmu_cxr_mask = 0x000000ff,
- .mmu_sfsr_mask = 0x00016fff,
- .mmu_trcr_mask = 0x00ffffff,
- .nwindows = 8,
- .features = CPU_DEFAULT_FEATURES,
- },
- {
- .name = "TI MicroSparc IIep",
- .iu_version = 0x42000000,
- .fpu_version = 4 << 17,
- .mmu_version = 0x04000000,
- .mmu_bm = 0x00004000,
- .mmu_ctpr_mask = 0x00ffffc0,
- .mmu_cxr_mask = 0x000000ff,
- .mmu_sfsr_mask = 0x00016bff,
- .mmu_trcr_mask = 0x00ffffff,
- .nwindows = 8,
- .features = CPU_DEFAULT_FEATURES,
- },
- {
- .name = "TI SuperSparc 40", // STP1020NPGA
- .iu_version = 0x41000000, // SuperSPARC 2.x
- .fpu_version = 0 << 17,
- .mmu_version = 0x00000800, // SuperSPARC 2.x, no MXCC
- .mmu_bm = 0x00002000,
- .mmu_ctpr_mask = 0xffffffc0,
- .mmu_cxr_mask = 0x0000ffff,
- .mmu_sfsr_mask = 0xffffffff,
- .mmu_trcr_mask = 0xffffffff,
- .nwindows = 8,
- .features = CPU_DEFAULT_FEATURES,
- },
- {
- .name = "TI SuperSparc 50", // STP1020PGA
- .iu_version = 0x40000000, // SuperSPARC 3.x
- .fpu_version = 0 << 17,
- .mmu_version = 0x01000800, // SuperSPARC 3.x, no MXCC
- .mmu_bm = 0x00002000,
- .mmu_ctpr_mask = 0xffffffc0,
- .mmu_cxr_mask = 0x0000ffff,
- .mmu_sfsr_mask = 0xffffffff,
- .mmu_trcr_mask = 0xffffffff,
- .nwindows = 8,
- .features = CPU_DEFAULT_FEATURES,
- },
- {
- .name = "TI SuperSparc 51",
- .iu_version = 0x40000000, // SuperSPARC 3.x
- .fpu_version = 0 << 17,
- .mmu_version = 0x01000000, // SuperSPARC 3.x, MXCC
- .mmu_bm = 0x00002000,
- .mmu_ctpr_mask = 0xffffffc0,
- .mmu_cxr_mask = 0x0000ffff,
- .mmu_sfsr_mask = 0xffffffff,
- .mmu_trcr_mask = 0xffffffff,
- .mxcc_version = 0x00000104,
- .nwindows = 8,
- .features = CPU_DEFAULT_FEATURES,
- },
- {
- .name = "TI SuperSparc 60", // STP1020APGA
- .iu_version = 0x40000000, // SuperSPARC 3.x
- .fpu_version = 0 << 17,
- .mmu_version = 0x01000800, // SuperSPARC 3.x, no MXCC
- .mmu_bm = 0x00002000,
- .mmu_ctpr_mask = 0xffffffc0,
- .mmu_cxr_mask = 0x0000ffff,
- .mmu_sfsr_mask = 0xffffffff,
- .mmu_trcr_mask = 0xffffffff,
- .nwindows = 8,
- .features = CPU_DEFAULT_FEATURES,
- },
- {
- .name = "TI SuperSparc 61",
- .iu_version = 0x44000000, // SuperSPARC 3.x
- .fpu_version = 0 << 17,
- .mmu_version = 0x01000000, // SuperSPARC 3.x, MXCC
- .mmu_bm = 0x00002000,
- .mmu_ctpr_mask = 0xffffffc0,
- .mmu_cxr_mask = 0x0000ffff,
- .mmu_sfsr_mask = 0xffffffff,
- .mmu_trcr_mask = 0xffffffff,
- .mxcc_version = 0x00000104,
- .nwindows = 8,
- .features = CPU_DEFAULT_FEATURES,
- },
- {
- .name = "TI SuperSparc II",
- .iu_version = 0x40000000, // SuperSPARC II 1.x
- .fpu_version = 0 << 17,
- .mmu_version = 0x08000000, // SuperSPARC II 1.x, MXCC
- .mmu_bm = 0x00002000,
- .mmu_ctpr_mask = 0xffffffc0,
- .mmu_cxr_mask = 0x0000ffff,
- .mmu_sfsr_mask = 0xffffffff,
- .mmu_trcr_mask = 0xffffffff,
- .mxcc_version = 0x00000104,
- .nwindows = 8,
- .features = CPU_DEFAULT_FEATURES,
- },
- {
- .name = "Ross RT625",
- .iu_version = 0x1e000000,
- .fpu_version = 1 << 17,
- .mmu_version = 0x1e000000,
- .mmu_bm = 0x00004000,
- .mmu_ctpr_mask = 0x007ffff0,
- .mmu_cxr_mask = 0x0000003f,
- .mmu_sfsr_mask = 0xffffffff,
- .mmu_trcr_mask = 0xffffffff,
- .nwindows = 8,
- .features = CPU_DEFAULT_FEATURES,
- },
- {
- .name = "Ross RT620",
- .iu_version = 0x1f000000,
- .fpu_version = 1 << 17,
- .mmu_version = 0x1f000000,
- .mmu_bm = 0x00004000,
- .mmu_ctpr_mask = 0x007ffff0,
- .mmu_cxr_mask = 0x0000003f,
- .mmu_sfsr_mask = 0xffffffff,
- .mmu_trcr_mask = 0xffffffff,
- .nwindows = 8,
- .features = CPU_DEFAULT_FEATURES,
- },
- {
- .name = "BIT B5010",
- .iu_version = 0x20000000,
- .fpu_version = 0 << 17, /* B5010/B5110/B5120/B5210 */
- .mmu_version = 0x20000000,
- .mmu_bm = 0x00004000,
- .mmu_ctpr_mask = 0x007ffff0,
- .mmu_cxr_mask = 0x0000003f,
- .mmu_sfsr_mask = 0xffffffff,
- .mmu_trcr_mask = 0xffffffff,
- .nwindows = 8,
- .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT |
- CPU_FEATURE_FSMULD,
- },
- {
- .name = "Matsushita MN10501",
- .iu_version = 0x50000000,
- .fpu_version = 0 << 17,
- .mmu_version = 0x50000000,
- .mmu_bm = 0x00004000,
- .mmu_ctpr_mask = 0x007ffff0,
- .mmu_cxr_mask = 0x0000003f,
- .mmu_sfsr_mask = 0xffffffff,
- .mmu_trcr_mask = 0xffffffff,
- .nwindows = 8,
- .features = CPU_FEATURE_FLOAT | CPU_FEATURE_MUL | CPU_FEATURE_FSQRT |
- CPU_FEATURE_FSMULD,
- },
- {
- .name = "Weitek W8601",
- .iu_version = 0x90 << 24, /* Impl 9, ver 0 */
- .fpu_version = 3 << 17, /* FPU version 3 (Weitek WTL3170/2) */
- .mmu_version = 0x10 << 24,
- .mmu_bm = 0x00004000,
- .mmu_ctpr_mask = 0x007ffff0,
- .mmu_cxr_mask = 0x0000003f,
- .mmu_sfsr_mask = 0xffffffff,
- .mmu_trcr_mask = 0xffffffff,
- .nwindows = 8,
- .features = CPU_DEFAULT_FEATURES,
- },
- {
- .name = "LEON2",
- .iu_version = 0xf2000000,
- .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
- .mmu_version = 0xf2000000,
- .mmu_bm = 0x00004000,
- .mmu_ctpr_mask = 0x007ffff0,
- .mmu_cxr_mask = 0x0000003f,
- .mmu_sfsr_mask = 0xffffffff,
- .mmu_trcr_mask = 0xffffffff,
- .nwindows = 8,
- .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_TA0_SHUTDOWN,
- },
- {
- .name = "LEON3",
- .iu_version = 0xf3000000,
- .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
- .mmu_version = 0xf3000000,
- .mmu_bm = 0x00000000,
- .mmu_ctpr_mask = 0x007ffff0,
- .mmu_cxr_mask = 0x0000003f,
- .mmu_sfsr_mask = 0xffffffff,
- .mmu_trcr_mask = 0xffffffff,
- .nwindows = 8,
- .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_TA0_SHUTDOWN |
- CPU_FEATURE_ASR17 | CPU_FEATURE_CACHE_CTRL,
- },
-#endif
-};
-
-static const char * const feature_name[] = {
- "float",
- "float128",
- "swap",
- "mul",
- "div",
- "flush",
- "fsqrt",
- "fmul",
- "vis1",
- "vis2",
- "fsmuld",
- "hypv",
- "cmt",
- "gl",
-};
-
-static void print_features(FILE *f, fprintf_function cpu_fprintf,
- uint32_t features, const char *prefix)
+target_ulong helper_udiv_cc(CPUState *env, target_ulong a, target_ulong b)
{
- unsigned int i;
-
- for (i = 0; i < ARRAY_SIZE(feature_name); i++)
- if (feature_name[i] && (features & (1 << i))) {
- if (prefix)
- (*cpu_fprintf)(f, "%s", prefix);
- (*cpu_fprintf)(f, "%s ", feature_name[i]);
- }
+ return helper_udiv_common(env, a, b, 1);
}
-static void add_flagname_to_bitmaps(const char *flagname, uint32_t *features)
+static target_ulong helper_sdiv_common(CPUState *env, target_ulong a,
+ target_ulong b, int cc)
{
- unsigned int i;
-
- for (i = 0; i < ARRAY_SIZE(feature_name); i++)
- if (feature_name[i] && !strcmp(flagname, feature_name[i])) {
- *features |= 1 << i;
- return;
- }
- fprintf(stderr, "CPU feature %s not found\n", flagname);
-}
+ int overflow = 0;
+ int64_t x0;
+ int32_t x1;
-static int cpu_sparc_find_by_name(sparc_def_t *cpu_def, const char *cpu_model)
-{
- unsigned int i;
- const sparc_def_t *def = NULL;
- char *s = strdup(cpu_model);
- char *featurestr, *name = strtok(s, ",");
- uint32_t plus_features = 0;
- uint32_t minus_features = 0;
- uint64_t iu_version;
- uint32_t fpu_version, mmu_version, nwindows;
+ x0 = (a & 0xffffffff) | ((int64_t) (env->y) << 32);
+ x1 = (b & 0xffffffff);
- for (i = 0; i < ARRAY_SIZE(sparc_defs); i++) {
- if (strcasecmp(name, sparc_defs[i].name) == 0) {
- def = &sparc_defs[i];
- }
+ if (x1 == 0) {
+ helper_raise_exception(env, TT_DIV_ZERO);
}
- if (!def)
- goto error;
- memcpy(cpu_def, def, sizeof(*def));
-
- featurestr = strtok(NULL, ",");
- while (featurestr) {
- char *val;
-
- if (featurestr[0] == '+') {
- add_flagname_to_bitmaps(featurestr + 1, &plus_features);
- } else if (featurestr[0] == '-') {
- add_flagname_to_bitmaps(featurestr + 1, &minus_features);
- } else if ((val = strchr(featurestr, '='))) {
- *val = 0; val++;
- if (!strcmp(featurestr, "iu_version")) {
- char *err;
-
- iu_version = strtoll(val, &err, 0);
- if (!*val || *err) {
- fprintf(stderr, "bad numerical value %s\n", val);
- goto error;
- }
- cpu_def->iu_version = iu_version;
-#ifdef DEBUG_FEATURES
- fprintf(stderr, "iu_version %" PRIx64 "\n", iu_version);
-#endif
- } else if (!strcmp(featurestr, "fpu_version")) {
- char *err;
-
- fpu_version = strtol(val, &err, 0);
- if (!*val || *err) {
- fprintf(stderr, "bad numerical value %s\n", val);
- goto error;
- }
- cpu_def->fpu_version = fpu_version;
-#ifdef DEBUG_FEATURES
- fprintf(stderr, "fpu_version %x\n", fpu_version);
-#endif
- } else if (!strcmp(featurestr, "mmu_version")) {
- char *err;
-
- mmu_version = strtol(val, &err, 0);
- if (!*val || *err) {
- fprintf(stderr, "bad numerical value %s\n", val);
- goto error;
- }
- cpu_def->mmu_version = mmu_version;
-#ifdef DEBUG_FEATURES
- fprintf(stderr, "mmu_version %x\n", mmu_version);
-#endif
- } else if (!strcmp(featurestr, "nwindows")) {
- char *err;
- nwindows = strtol(val, &err, 0);
- if (!*val || *err || nwindows > MAX_NWINDOWS ||
- nwindows < MIN_NWINDOWS) {
- fprintf(stderr, "bad numerical value %s\n", val);
- goto error;
- }
- cpu_def->nwindows = nwindows;
-#ifdef DEBUG_FEATURES
- fprintf(stderr, "nwindows %d\n", nwindows);
-#endif
- } else {
- fprintf(stderr, "unrecognized feature %s\n", featurestr);
- goto error;
- }
- } else {
- fprintf(stderr, "feature string `%s' not in format "
- "(+feature|-feature|feature=xyz)\n", featurestr);
- goto error;
- }
- featurestr = strtok(NULL, ",");
+ x0 = x0 / x1;
+ if ((int32_t) x0 != x0) {
+ x0 = x0 < 0 ? 0x80000000 : 0x7fffffff;
+ overflow = 1;
}
- cpu_def->features |= plus_features;
- cpu_def->features &= ~minus_features;
-#ifdef DEBUG_FEATURES
- print_features(stderr, fprintf, cpu_def->features, NULL);
-#endif
- free(s);
- return 0;
- error:
- free(s);
- return -1;
-}
-
-void sparc_cpu_list(FILE *f, fprintf_function cpu_fprintf)
-{
- unsigned int i;
-
- for (i = 0; i < ARRAY_SIZE(sparc_defs); i++) {
- (*cpu_fprintf)(f, "Sparc %16s IU " TARGET_FMT_lx " FPU %08x MMU %08x NWINS %d ",
- sparc_defs[i].name,
- sparc_defs[i].iu_version,
- sparc_defs[i].fpu_version,
- sparc_defs[i].mmu_version,
- sparc_defs[i].nwindows);
- print_features(f, cpu_fprintf, CPU_DEFAULT_FEATURES &
- ~sparc_defs[i].features, "-");
- print_features(f, cpu_fprintf, ~CPU_DEFAULT_FEATURES &
- sparc_defs[i].features, "+");
- (*cpu_fprintf)(f, "\n");
+ if (cc) {
+ env->cc_dst = x0;
+ env->cc_src2 = overflow;
+ env->cc_op = CC_OP_DIV;
}
- (*cpu_fprintf)(f, "Default CPU feature flags (use '-' to remove): ");
- print_features(f, cpu_fprintf, CPU_DEFAULT_FEATURES, NULL);
- (*cpu_fprintf)(f, "\n");
- (*cpu_fprintf)(f, "Available CPU feature flags (use '+' to add): ");
- print_features(f, cpu_fprintf, ~CPU_DEFAULT_FEATURES, NULL);
- (*cpu_fprintf)(f, "\n");
- (*cpu_fprintf)(f, "Numerical features (use '=' to set): iu_version "
- "fpu_version mmu_version nwindows\n");
+ return x0;
}
-static void cpu_print_cc(FILE *f, fprintf_function cpu_fprintf,
- uint32_t cc)
+target_ulong helper_sdiv(CPUState *env, target_ulong a, target_ulong b)
{
- cpu_fprintf(f, "%c%c%c%c", cc & PSR_NEG? 'N' : '-',
- cc & PSR_ZERO? 'Z' : '-', cc & PSR_OVF? 'V' : '-',
- cc & PSR_CARRY? 'C' : '-');
+ return helper_sdiv_common(env, a, b, 0);
}
-#ifdef TARGET_SPARC64
-#define REGS_PER_LINE 4
-#else
-#define REGS_PER_LINE 8
-#endif
-
-void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf,
- int flags)
+target_ulong helper_sdiv_cc(CPUState *env, target_ulong a, target_ulong b)
{
- int i, x;
-
- cpu_fprintf(f, "pc: " TARGET_FMT_lx " npc: " TARGET_FMT_lx "\n", env->pc,
- env->npc);
- cpu_fprintf(f, "General Registers:\n");
-
- for (i = 0; i < 8; i++) {
- if (i % REGS_PER_LINE == 0) {
- cpu_fprintf(f, "%%g%d-%d:", i, i + REGS_PER_LINE - 1);
- }
- cpu_fprintf(f, " " TARGET_FMT_lx, env->gregs[i]);
- if (i % REGS_PER_LINE == REGS_PER_LINE - 1) {
- cpu_fprintf(f, "\n");
- }
- }
- cpu_fprintf(f, "\nCurrent Register Window:\n");
- for (x = 0; x < 3; x++) {
- for (i = 0; i < 8; i++) {
- if (i % REGS_PER_LINE == 0) {
- cpu_fprintf(f, "%%%c%d-%d: ",
- x == 0 ? 'o' : (x == 1 ? 'l' : 'i'),
- i, i + REGS_PER_LINE - 1);
- }
- cpu_fprintf(f, TARGET_FMT_lx " ", env->regwptr[i + x * 8]);
- if (i % REGS_PER_LINE == REGS_PER_LINE - 1) {
- cpu_fprintf(f, "\n");
- }
- }
- }
- cpu_fprintf(f, "\nFloating Point Registers:\n");
- for (i = 0; i < TARGET_FPREGS; i++) {
- if ((i & 3) == 0)
- cpu_fprintf(f, "%%f%02d:", i);
- cpu_fprintf(f, " %016f", *(float *)&env->fpr[i]);
- if ((i & 3) == 3)
- cpu_fprintf(f, "\n");
- }
-#ifdef TARGET_SPARC64
- cpu_fprintf(f, "pstate: %08x ccr: %02x (icc: ", env->pstate,
- (unsigned)cpu_get_ccr(env));
- cpu_print_cc(f, cpu_fprintf, cpu_get_ccr(env) << PSR_CARRY_SHIFT);
- cpu_fprintf(f, " xcc: ");
- cpu_print_cc(f, cpu_fprintf, cpu_get_ccr(env) << (PSR_CARRY_SHIFT - 4));
- cpu_fprintf(f, ") asi: %02x tl: %d pil: %x\n", env->asi, env->tl,
- env->psrpil);
- cpu_fprintf(f, "cansave: %d canrestore: %d otherwin: %d wstate: %d "
- "cleanwin: %d cwp: %d\n",
- env->cansave, env->canrestore, env->otherwin, env->wstate,
- env->cleanwin, env->nwindows - 1 - env->cwp);
- cpu_fprintf(f, "fsr: " TARGET_FMT_lx " y: " TARGET_FMT_lx " fprs: "
- TARGET_FMT_lx "\n", env->fsr, env->y, env->fprs);
-#else
- cpu_fprintf(f, "psr: %08x (icc: ", cpu_get_psr(env));
- cpu_print_cc(f, cpu_fprintf, cpu_get_psr(env));
- cpu_fprintf(f, " SPE: %c%c%c) wim: %08x\n", env->psrs? 'S' : '-',
- env->psrps? 'P' : '-', env->psret? 'E' : '-',
- env->wim);
- cpu_fprintf(f, "fsr: " TARGET_FMT_lx " y: " TARGET_FMT_lx "\n",
- env->fsr, env->y);
-#endif
+ return helper_sdiv_common(env, a, b, 1);
}
diff --git a/target-sparc/helper.h b/target-sparc/helper.h
index 2d36af3a31..615ddefa92 100644
--- a/target-sparc/helper.h
+++ b/target-sparc/helper.h
@@ -1,44 +1,44 @@
#include "def-helper.h"
#ifndef TARGET_SPARC64
-DEF_HELPER_0(rett, void)
-DEF_HELPER_1(wrpsr, void, tl)
-DEF_HELPER_0(rdpsr, tl)
+DEF_HELPER_1(rett, void, env)
+DEF_HELPER_2(wrpsr, void, env, tl)
+DEF_HELPER_1(rdpsr, tl, env)
#else
-DEF_HELPER_1(wrpil, void, tl)
-DEF_HELPER_1(wrpstate, void, tl)
-DEF_HELPER_0(done, void)
-DEF_HELPER_0(retry, void)
-DEF_HELPER_0(flushw, void)
-DEF_HELPER_0(saved, void)
-DEF_HELPER_0(restored, void)
-DEF_HELPER_0(rdccr, tl)
-DEF_HELPER_1(wrccr, void, tl)
-DEF_HELPER_0(rdcwp, tl)
-DEF_HELPER_1(wrcwp, void, tl)
-DEF_HELPER_2(array8, tl, tl, tl)
-DEF_HELPER_2(alignaddr, tl, tl, tl)
+DEF_HELPER_2(wrpil, void, env, tl)
+DEF_HELPER_2(wrpstate, void, env, tl)
+DEF_HELPER_1(done, void, env)
+DEF_HELPER_1(retry, void, env)
+DEF_HELPER_1(flushw, void, env)
+DEF_HELPER_1(saved, void, env)
+DEF_HELPER_1(restored, void, env)
+DEF_HELPER_1(rdccr, tl, env)
+DEF_HELPER_2(wrccr, void, env, tl)
+DEF_HELPER_1(rdcwp, tl, env)
+DEF_HELPER_2(wrcwp, void, env, tl)
+DEF_HELPER_3(array8, tl, env, tl, tl)
+DEF_HELPER_3(alignaddr, tl, env, tl, tl)
DEF_HELPER_1(popc, tl, tl)
DEF_HELPER_3(ldda_asi, void, tl, int, int)
DEF_HELPER_4(ldf_asi, void, tl, int, int, int)
DEF_HELPER_4(stf_asi, void, tl, int, int, int)
DEF_HELPER_4(cas_asi, tl, tl, tl, tl, i32)
DEF_HELPER_4(casx_asi, tl, tl, tl, tl, i32)
-DEF_HELPER_1(set_softint, void, i64)
-DEF_HELPER_1(clear_softint, void, i64)
-DEF_HELPER_1(write_softint, void, i64)
+DEF_HELPER_2(set_softint, void, env, i64)
+DEF_HELPER_2(clear_softint, void, env, i64)
+DEF_HELPER_2(write_softint, void, env, i64)
DEF_HELPER_2(tick_set_count, void, ptr, i64)
DEF_HELPER_1(tick_get_count, i64, ptr)
DEF_HELPER_2(tick_set_limit, void, ptr, i64)
#endif
DEF_HELPER_2(check_align, void, tl, i32)
-DEF_HELPER_0(debug, void)
-DEF_HELPER_0(save, void)
-DEF_HELPER_0(restore, void)
-DEF_HELPER_2(udiv, tl, tl, tl)
-DEF_HELPER_2(udiv_cc, tl, tl, tl)
-DEF_HELPER_2(sdiv, tl, tl, tl)
-DEF_HELPER_2(sdiv_cc, tl, tl, tl)
+DEF_HELPER_1(debug, void, env)
+DEF_HELPER_1(save, void, env)
+DEF_HELPER_1(restore, void, env)
+DEF_HELPER_3(udiv, tl, env, tl, tl)
+DEF_HELPER_3(udiv_cc, tl, env, tl, tl)
+DEF_HELPER_3(sdiv, tl, env, tl, tl)
+DEF_HELPER_3(sdiv_cc, tl, env, tl, tl)
DEF_HELPER_2(stdf, void, tl, int)
DEF_HELPER_2(lddf, void, tl, int)
DEF_HELPER_2(ldqf, void, tl, int)
@@ -47,119 +47,119 @@ DEF_HELPER_2(stqf, void, tl, int)
DEF_HELPER_4(ld_asi, i64, tl, int, int, int)
DEF_HELPER_4(st_asi, void, tl, i64, int, int)
#endif
-DEF_HELPER_1(ldfsr, void, i32)
-DEF_HELPER_0(check_ieee_exceptions, void)
-DEF_HELPER_0(clear_float_exceptions, void)
+DEF_HELPER_2(ldfsr, void, env, i32)
+DEF_HELPER_1(check_ieee_exceptions, void, env)
+DEF_HELPER_1(clear_float_exceptions, void, env)
DEF_HELPER_1(fabss, f32, f32)
-DEF_HELPER_1(fsqrts, f32, f32)
-DEF_HELPER_0(fsqrtd, void)
-DEF_HELPER_2(fcmps, void, f32, f32)
-DEF_HELPER_0(fcmpd, void)
-DEF_HELPER_2(fcmpes, void, f32, f32)
-DEF_HELPER_0(fcmped, void)
-DEF_HELPER_0(fsqrtq, void)
-DEF_HELPER_0(fcmpq, void)
-DEF_HELPER_0(fcmpeq, void)
+DEF_HELPER_2(fsqrts, f32, env, f32)
+DEF_HELPER_1(fsqrtd, void, env)
+DEF_HELPER_3(fcmps, void, env, f32, f32)
+DEF_HELPER_1(fcmpd, void, env)
+DEF_HELPER_3(fcmpes, void, env, f32, f32)
+DEF_HELPER_1(fcmped, void, env)
+DEF_HELPER_1(fsqrtq, void, env)
+DEF_HELPER_1(fcmpq, void, env)
+DEF_HELPER_1(fcmpeq, void, env)
#ifdef TARGET_SPARC64
-DEF_HELPER_1(ldxfsr, void, i64)
-DEF_HELPER_0(fabsd, void)
-DEF_HELPER_2(fcmps_fcc1, void, f32, f32)
-DEF_HELPER_2(fcmps_fcc2, void, f32, f32)
-DEF_HELPER_2(fcmps_fcc3, void, f32, f32)
-DEF_HELPER_0(fcmpd_fcc1, void)
-DEF_HELPER_0(fcmpd_fcc2, void)
-DEF_HELPER_0(fcmpd_fcc3, void)
-DEF_HELPER_2(fcmpes_fcc1, void, f32, f32)
-DEF_HELPER_2(fcmpes_fcc2, void, f32, f32)
-DEF_HELPER_2(fcmpes_fcc3, void, f32, f32)
-DEF_HELPER_0(fcmped_fcc1, void)
-DEF_HELPER_0(fcmped_fcc2, void)
-DEF_HELPER_0(fcmped_fcc3, void)
-DEF_HELPER_0(fabsq, void)
-DEF_HELPER_0(fcmpq_fcc1, void)
-DEF_HELPER_0(fcmpq_fcc2, void)
-DEF_HELPER_0(fcmpq_fcc3, void)
-DEF_HELPER_0(fcmpeq_fcc1, void)
-DEF_HELPER_0(fcmpeq_fcc2, void)
-DEF_HELPER_0(fcmpeq_fcc3, void)
+DEF_HELPER_2(ldxfsr, void, env, i64)
+DEF_HELPER_1(fabsd, void, env)
+DEF_HELPER_3(fcmps_fcc1, void, env, f32, f32)
+DEF_HELPER_3(fcmps_fcc2, void, env, f32, f32)
+DEF_HELPER_3(fcmps_fcc3, void, env, f32, f32)
+DEF_HELPER_1(fcmpd_fcc1, void, env)
+DEF_HELPER_1(fcmpd_fcc2, void, env)
+DEF_HELPER_1(fcmpd_fcc3, void, env)
+DEF_HELPER_3(fcmpes_fcc1, void, env, f32, f32)
+DEF_HELPER_3(fcmpes_fcc2, void, env, f32, f32)
+DEF_HELPER_3(fcmpes_fcc3, void, env, f32, f32)
+DEF_HELPER_1(fcmped_fcc1, void, env)
+DEF_HELPER_1(fcmped_fcc2, void, env)
+DEF_HELPER_1(fcmped_fcc3, void, env)
+DEF_HELPER_1(fabsq, void, env)
+DEF_HELPER_1(fcmpq_fcc1, void, env)
+DEF_HELPER_1(fcmpq_fcc2, void, env)
+DEF_HELPER_1(fcmpq_fcc3, void, env)
+DEF_HELPER_1(fcmpeq_fcc1, void, env)
+DEF_HELPER_1(fcmpeq_fcc2, void, env)
+DEF_HELPER_1(fcmpeq_fcc3, void, env)
#endif
-DEF_HELPER_1(raise_exception, void, int)
+DEF_HELPER_2(raise_exception, void, env, int)
DEF_HELPER_0(shutdown, void)
-#define F_HELPER_0_0(name) DEF_HELPER_0(f ## name, void)
-#define F_HELPER_DQ_0_0(name) \
- F_HELPER_0_0(name ## d); \
- F_HELPER_0_0(name ## q)
+#define F_HELPER_0_1(name) DEF_HELPER_1(f ## name, void, env)
+#define F_HELPER_DQ_0_1(name) \
+ F_HELPER_0_1(name ## d); \
+ F_HELPER_0_1(name ## q)
-F_HELPER_DQ_0_0(add);
-F_HELPER_DQ_0_0(sub);
-F_HELPER_DQ_0_0(mul);
-F_HELPER_DQ_0_0(div);
+F_HELPER_DQ_0_1(add);
+F_HELPER_DQ_0_1(sub);
+F_HELPER_DQ_0_1(mul);
+F_HELPER_DQ_0_1(div);
-DEF_HELPER_2(fadds, f32, f32, f32)
-DEF_HELPER_2(fsubs, f32, f32, f32)
-DEF_HELPER_2(fmuls, f32, f32, f32)
-DEF_HELPER_2(fdivs, f32, f32, f32)
+DEF_HELPER_3(fadds, f32, env, f32, f32)
+DEF_HELPER_3(fsubs, f32, env, f32, f32)
+DEF_HELPER_3(fmuls, f32, env, f32, f32)
+DEF_HELPER_3(fdivs, f32, env, f32, f32)
-DEF_HELPER_2(fsmuld, void, f32, f32)
-F_HELPER_0_0(dmulq);
+DEF_HELPER_3(fsmuld, void, env, f32, f32)
+F_HELPER_0_1(dmulq);
DEF_HELPER_1(fnegs, f32, f32)
-DEF_HELPER_1(fitod, void, s32)
-DEF_HELPER_1(fitoq, void, s32)
+DEF_HELPER_2(fitod, void, env, s32)
+DEF_HELPER_2(fitoq, void, env, s32)
-DEF_HELPER_1(fitos, f32, s32)
+DEF_HELPER_2(fitos, f32, env, s32)
#ifdef TARGET_SPARC64
-DEF_HELPER_0(fnegd, void)
-DEF_HELPER_0(fnegq, void)
-DEF_HELPER_0(fxtos, i32)
-F_HELPER_DQ_0_0(xto);
+DEF_HELPER_1(fnegd, void, env)
+DEF_HELPER_1(fnegq, void, env)
+DEF_HELPER_1(fxtos, i32, env)
+F_HELPER_DQ_0_1(xto);
#endif
-DEF_HELPER_0(fdtos, f32)
-DEF_HELPER_1(fstod, void, f32)
-DEF_HELPER_0(fqtos, f32)
-DEF_HELPER_1(fstoq, void, f32)
-F_HELPER_0_0(qtod);
-F_HELPER_0_0(dtoq);
-DEF_HELPER_1(fstoi, s32, f32)
-DEF_HELPER_0(fdtoi, s32)
-DEF_HELPER_0(fqtoi, s32)
+DEF_HELPER_1(fdtos, f32, env)
+DEF_HELPER_2(fstod, void, env, f32)
+DEF_HELPER_1(fqtos, f32, env)
+DEF_HELPER_2(fstoq, void, env, f32)
+F_HELPER_0_1(qtod);
+F_HELPER_0_1(dtoq);
+DEF_HELPER_2(fstoi, s32, env, f32)
+DEF_HELPER_1(fdtoi, s32, env)
+DEF_HELPER_1(fqtoi, s32, env)
#ifdef TARGET_SPARC64
-DEF_HELPER_1(fstox, void, i32)
-F_HELPER_0_0(dtox);
-F_HELPER_0_0(qtox);
-F_HELPER_0_0(aligndata);
+DEF_HELPER_2(fstox, void, env, i32)
+F_HELPER_0_1(dtox);
+F_HELPER_0_1(qtox);
+F_HELPER_0_1(aligndata);
-F_HELPER_0_0(pmerge);
-F_HELPER_0_0(mul8x16);
-F_HELPER_0_0(mul8x16al);
-F_HELPER_0_0(mul8x16au);
-F_HELPER_0_0(mul8sux16);
-F_HELPER_0_0(mul8ulx16);
-F_HELPER_0_0(muld8sux16);
-F_HELPER_0_0(muld8ulx16);
-F_HELPER_0_0(expand);
+F_HELPER_0_1(pmerge);
+F_HELPER_0_1(mul8x16);
+F_HELPER_0_1(mul8x16al);
+F_HELPER_0_1(mul8x16au);
+F_HELPER_0_1(mul8sux16);
+F_HELPER_0_1(mul8ulx16);
+F_HELPER_0_1(muld8sux16);
+F_HELPER_0_1(muld8ulx16);
+F_HELPER_0_1(expand);
#define VIS_HELPER(name) \
- F_HELPER_0_0(name##16); \
- DEF_HELPER_2(f ## name ## 16s, i32, i32, i32) \
- F_HELPER_0_0(name##32); \
- DEF_HELPER_2(f ## name ## 32s, i32, i32, i32)
+ F_HELPER_0_1(name##16); \
+ DEF_HELPER_3(f ## name ## 16s, i32, env, i32, i32) \
+ F_HELPER_0_1(name##32); \
+ DEF_HELPER_3(f ## name ## 32s, i32, env, i32, i32)
VIS_HELPER(padd);
VIS_HELPER(psub);
#define VIS_CMPHELPER(name) \
- DEF_HELPER_0(f##name##16, i64); \
- DEF_HELPER_0(f##name##32, i64)
+ DEF_HELPER_1(f##name##16, i64, env); \
+ DEF_HELPER_1(f##name##32, i64, env)
VIS_CMPHELPER(cmpgt);
VIS_CMPHELPER(cmpeq);
VIS_CMPHELPER(cmple);
VIS_CMPHELPER(cmpne);
#endif
-#undef F_HELPER_0_0
-#undef F_HELPER_DQ_0_0
+#undef F_HELPER_0_1
+#undef F_HELPER_DQ_0_1
#undef VIS_HELPER
#undef VIS_CMPHELPER
-DEF_HELPER_0(compute_psr, void);
-DEF_HELPER_0(compute_C_icc, i32);
+DEF_HELPER_1(compute_psr, void, env);
+DEF_HELPER_1(compute_C_icc, i32, env);
#include "def-helper.h"
diff --git a/target-sparc/int32_helper.c b/target-sparc/int32_helper.c
new file mode 100644
index 0000000000..3a749bf5df
--- /dev/null
+++ b/target-sparc/int32_helper.c
@@ -0,0 +1,163 @@
+/*
+ * Sparc32 interrupt helpers
+ *
+ * Copyright (c) 2003-2005 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cpu.h"
+#include "trace.h"
+
+//#define DEBUG_PCALL
+
+#ifdef DEBUG_PCALL
+static const char * const excp_names[0x80] = {
+ [TT_TFAULT] = "Instruction Access Fault",
+ [TT_ILL_INSN] = "Illegal Instruction",
+ [TT_PRIV_INSN] = "Privileged Instruction",
+ [TT_NFPU_INSN] = "FPU Disabled",
+ [TT_WIN_OVF] = "Window Overflow",
+ [TT_WIN_UNF] = "Window Underflow",
+ [TT_UNALIGNED] = "Unaligned Memory Access",
+ [TT_FP_EXCP] = "FPU Exception",
+ [TT_DFAULT] = "Data Access Fault",
+ [TT_TOVF] = "Tag Overflow",
+ [TT_EXTINT | 0x1] = "External Interrupt 1",
+ [TT_EXTINT | 0x2] = "External Interrupt 2",
+ [TT_EXTINT | 0x3] = "External Interrupt 3",
+ [TT_EXTINT | 0x4] = "External Interrupt 4",
+ [TT_EXTINT | 0x5] = "External Interrupt 5",
+ [TT_EXTINT | 0x6] = "External Interrupt 6",
+ [TT_EXTINT | 0x7] = "External Interrupt 7",
+ [TT_EXTINT | 0x8] = "External Interrupt 8",
+ [TT_EXTINT | 0x9] = "External Interrupt 9",
+ [TT_EXTINT | 0xa] = "External Interrupt 10",
+ [TT_EXTINT | 0xb] = "External Interrupt 11",
+ [TT_EXTINT | 0xc] = "External Interrupt 12",
+ [TT_EXTINT | 0xd] = "External Interrupt 13",
+ [TT_EXTINT | 0xe] = "External Interrupt 14",
+ [TT_EXTINT | 0xf] = "External Interrupt 15",
+ [TT_TOVF] = "Tag Overflow",
+ [TT_CODE_ACCESS] = "Instruction Access Error",
+ [TT_DATA_ACCESS] = "Data Access Error",
+ [TT_DIV_ZERO] = "Division By Zero",
+ [TT_NCP_INSN] = "Coprocessor Disabled",
+};
+#endif
+
+void do_interrupt(CPUState *env)
+{
+ int cwp, intno = env->exception_index;
+
+#ifdef DEBUG_PCALL
+ if (qemu_loglevel_mask(CPU_LOG_INT)) {
+ static int count;
+ const char *name;
+
+ if (intno < 0 || intno >= 0x100) {
+ name = "Unknown";
+ } else if (intno >= 0x80) {
+ name = "Trap Instruction";
+ } else {
+ name = excp_names[intno];
+ if (!name) {
+ name = "Unknown";
+ }
+ }
+
+ qemu_log("%6d: %s (v=%02x) pc=%08x npc=%08x SP=%08x\n",
+ count, name, intno,
+ env->pc,
+ env->npc, env->regwptr[6]);
+ log_cpu_state(env, 0);
+#if 0
+ {
+ int i;
+ uint8_t *ptr;
+
+ qemu_log(" code=");
+ ptr = (uint8_t *)env->pc;
+ for (i = 0; i < 16; i++) {
+ qemu_log(" %02x", ldub(ptr + i));
+ }
+ qemu_log("\n");
+ }
+#endif
+ count++;
+ }
+#endif
+#if !defined(CONFIG_USER_ONLY)
+ if (env->psret == 0) {
+ cpu_abort(env, "Trap 0x%02x while interrupts disabled, Error state",
+ env->exception_index);
+ return;
+ }
+#endif
+ env->psret = 0;
+ cwp = cpu_cwp_dec(env, env->cwp - 1);
+ cpu_set_cwp(env, cwp);
+ env->regwptr[9] = env->pc;
+ env->regwptr[10] = env->npc;
+ env->psrps = env->psrs;
+ env->psrs = 1;
+ env->tbr = (env->tbr & TBR_BASE_MASK) | (intno << 4);
+ env->pc = env->tbr;
+ env->npc = env->pc + 4;
+ env->exception_index = -1;
+
+#if !defined(CONFIG_USER_ONLY)
+ /* IRQ acknowledgment */
+ if ((intno & ~15) == TT_EXTINT && env->qemu_irq_ack != NULL) {
+ env->qemu_irq_ack(env, env->irq_manager, intno);
+ }
+#endif
+}
+
+#if !defined(CONFIG_USER_ONLY)
+static void leon3_cache_control_int(CPUState *env)
+{
+ uint32_t state = 0;
+
+ if (env->cache_control & CACHE_CTRL_IF) {
+ /* Instruction cache state */
+ state = env->cache_control & CACHE_STATE_MASK;
+ if (state == CACHE_ENABLED) {
+ state = CACHE_FROZEN;
+ trace_int_helper_icache_freeze();
+ }
+
+ env->cache_control &= ~CACHE_STATE_MASK;
+ env->cache_control |= state;
+ }
+
+ if (env->cache_control & CACHE_CTRL_DF) {
+ /* Data cache state */
+ state = (env->cache_control >> 2) & CACHE_STATE_MASK;
+ if (state == CACHE_ENABLED) {
+ state = CACHE_FROZEN;
+ trace_int_helper_dcache_freeze();
+ }
+
+ env->cache_control &= ~(CACHE_STATE_MASK << 2);
+ env->cache_control |= (state << 2);
+ }
+}
+
+void leon3_irq_manager(CPUState *env, void *irq_manager, int intno)
+{
+ leon3_irq_ack(irq_manager, intno);
+ leon3_cache_control_int(env);
+}
+#endif
diff --git a/target-sparc/int64_helper.c b/target-sparc/int64_helper.c
new file mode 100644
index 0000000000..1d471db999
--- /dev/null
+++ b/target-sparc/int64_helper.c
@@ -0,0 +1,201 @@
+/*
+ * Sparc64 interrupt helpers
+ *
+ * Copyright (c) 2003-2005 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cpu.h"
+#include "helper.h"
+#include "trace.h"
+
+//#define DEBUG_PCALL
+
+#ifdef DEBUG_PCALL
+static const char * const excp_names[0x80] = {
+ [TT_TFAULT] = "Instruction Access Fault",
+ [TT_TMISS] = "Instruction Access MMU Miss",
+ [TT_CODE_ACCESS] = "Instruction Access Error",
+ [TT_ILL_INSN] = "Illegal Instruction",
+ [TT_PRIV_INSN] = "Privileged Instruction",
+ [TT_NFPU_INSN] = "FPU Disabled",
+ [TT_FP_EXCP] = "FPU Exception",
+ [TT_TOVF] = "Tag Overflow",
+ [TT_CLRWIN] = "Clean Windows",
+ [TT_DIV_ZERO] = "Division By Zero",
+ [TT_DFAULT] = "Data Access Fault",
+ [TT_DMISS] = "Data Access MMU Miss",
+ [TT_DATA_ACCESS] = "Data Access Error",
+ [TT_DPROT] = "Data Protection Error",
+ [TT_UNALIGNED] = "Unaligned Memory Access",
+ [TT_PRIV_ACT] = "Privileged Action",
+ [TT_EXTINT | 0x1] = "External Interrupt 1",
+ [TT_EXTINT | 0x2] = "External Interrupt 2",
+ [TT_EXTINT | 0x3] = "External Interrupt 3",
+ [TT_EXTINT | 0x4] = "External Interrupt 4",
+ [TT_EXTINT | 0x5] = "External Interrupt 5",
+ [TT_EXTINT | 0x6] = "External Interrupt 6",
+ [TT_EXTINT | 0x7] = "External Interrupt 7",
+ [TT_EXTINT | 0x8] = "External Interrupt 8",
+ [TT_EXTINT | 0x9] = "External Interrupt 9",
+ [TT_EXTINT | 0xa] = "External Interrupt 10",
+ [TT_EXTINT | 0xb] = "External Interrupt 11",
+ [TT_EXTINT | 0xc] = "External Interrupt 12",
+ [TT_EXTINT | 0xd] = "External Interrupt 13",
+ [TT_EXTINT | 0xe] = "External Interrupt 14",
+ [TT_EXTINT | 0xf] = "External Interrupt 15",
+};
+#endif
+
+void do_interrupt(CPUState *env)
+{
+ int intno = env->exception_index;
+ trap_state *tsptr;
+
+#ifdef DEBUG_PCALL
+ if (qemu_loglevel_mask(CPU_LOG_INT)) {
+ static int count;
+ const char *name;
+
+ if (intno < 0 || intno >= 0x180) {
+ name = "Unknown";
+ } else if (intno >= 0x100) {
+ name = "Trap Instruction";
+ } else if (intno >= 0xc0) {
+ name = "Window Fill";
+ } else if (intno >= 0x80) {
+ name = "Window Spill";
+ } else {
+ name = excp_names[intno];
+ if (!name) {
+ name = "Unknown";
+ }
+ }
+
+ qemu_log("%6d: %s (v=%04x) pc=%016" PRIx64 " npc=%016" PRIx64
+ " SP=%016" PRIx64 "\n",
+ count, name, intno,
+ env->pc,
+ env->npc, env->regwptr[6]);
+ log_cpu_state(env, 0);
+#if 0
+ {
+ int i;
+ uint8_t *ptr;
+
+ qemu_log(" code=");
+ ptr = (uint8_t *)env->pc;
+ for (i = 0; i < 16; i++) {
+ qemu_log(" %02x", ldub(ptr + i));
+ }
+ qemu_log("\n");
+ }
+#endif
+ count++;
+ }
+#endif
+#if !defined(CONFIG_USER_ONLY)
+ if (env->tl >= env->maxtl) {
+ cpu_abort(env, "Trap 0x%04x while trap level (%d) >= MAXTL (%d),"
+ " Error state", env->exception_index, env->tl, env->maxtl);
+ return;
+ }
+#endif
+ if (env->tl < env->maxtl - 1) {
+ env->tl++;
+ } else {
+ env->pstate |= PS_RED;
+ if (env->tl < env->maxtl) {
+ env->tl++;
+ }
+ }
+ tsptr = cpu_tsptr(env);
+
+ tsptr->tstate = (cpu_get_ccr(env) << 32) |
+ ((env->asi & 0xff) << 24) | ((env->pstate & 0xf3f) << 8) |
+ cpu_get_cwp64(env);
+ tsptr->tpc = env->pc;
+ tsptr->tnpc = env->npc;
+ tsptr->tt = intno;
+
+ switch (intno) {
+ case TT_IVEC:
+ cpu_change_pstate(env, PS_PEF | PS_PRIV | PS_IG);
+ break;
+ case TT_TFAULT:
+ case TT_DFAULT:
+ case TT_TMISS ... TT_TMISS + 3:
+ case TT_DMISS ... TT_DMISS + 3:
+ case TT_DPROT ... TT_DPROT + 3:
+ cpu_change_pstate(env, PS_PEF | PS_PRIV | PS_MG);
+ break;
+ default:
+ cpu_change_pstate(env, PS_PEF | PS_PRIV | PS_AG);
+ break;
+ }
+
+ if (intno == TT_CLRWIN) {
+ cpu_set_cwp(env, cpu_cwp_dec(env, env->cwp - 1));
+ } else if ((intno & 0x1c0) == TT_SPILL) {
+ cpu_set_cwp(env, cpu_cwp_dec(env, env->cwp - env->cansave - 2));
+ } else if ((intno & 0x1c0) == TT_FILL) {
+ cpu_set_cwp(env, cpu_cwp_inc(env, env->cwp + 1));
+ }
+ env->tbr &= ~0x7fffULL;
+ env->tbr |= ((env->tl > 1) ? 1 << 14 : 0) | (intno << 5);
+ env->pc = env->tbr;
+ env->npc = env->pc + 4;
+ env->exception_index = -1;
+}
+
+trap_state *cpu_tsptr(CPUState* env)
+{
+ return &env->ts[env->tl & MAXTL_MASK];
+}
+
+static bool do_modify_softint(CPUState *env, uint32_t value)
+{
+ if (env->softint != value) {
+ env->softint = value;
+#if !defined(CONFIG_USER_ONLY)
+ if (cpu_interrupts_enabled(env)) {
+ cpu_check_irqs(env);
+ }
+#endif
+ return true;
+ }
+ return false;
+}
+
+void helper_set_softint(CPUState *env, uint64_t value)
+{
+ if (do_modify_softint(env, env->softint | (uint32_t)value)) {
+ trace_int_helper_set_softint(env->softint);
+ }
+}
+
+void helper_clear_softint(CPUState *env, uint64_t value)
+{
+ if (do_modify_softint(env, env->softint & (uint32_t)~value)) {
+ trace_int_helper_clear_softint(env->softint);
+ }
+}
+
+void helper_write_softint(CPUState *env, uint64_t value)
+{
+ if (do_modify_softint(env, (uint32_t)value)) {
+ trace_int_helper_write_softint(env->softint);
+ }
+}
diff --git a/target-sparc/ldst_helper.c b/target-sparc/ldst_helper.c
new file mode 100644
index 0000000000..1fb3996fdb
--- /dev/null
+++ b/target-sparc/ldst_helper.c
@@ -0,0 +1,2434 @@
+/*
+ * Helpers for loads and stores
+ *
+ * Copyright (c) 2003-2005 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cpu.h"
+#include "dyngen-exec.h"
+#include "helper.h"
+
+#if !defined(CONFIG_USER_ONLY)
+#include "softmmu_exec.h"
+#endif
+
+//#define DEBUG_MMU
+//#define DEBUG_MXCC
+//#define DEBUG_UNALIGNED
+//#define DEBUG_UNASSIGNED
+//#define DEBUG_ASI
+//#define DEBUG_CACHE_CONTROL
+
+#ifdef DEBUG_MMU
+#define DPRINTF_MMU(fmt, ...) \
+ do { printf("MMU: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF_MMU(fmt, ...) do {} while (0)
+#endif
+
+#ifdef DEBUG_MXCC
+#define DPRINTF_MXCC(fmt, ...) \
+ do { printf("MXCC: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF_MXCC(fmt, ...) do {} while (0)
+#endif
+
+#ifdef DEBUG_ASI
+#define DPRINTF_ASI(fmt, ...) \
+ do { printf("ASI: " fmt , ## __VA_ARGS__); } while (0)
+#endif
+
+#ifdef DEBUG_CACHE_CONTROL
+#define DPRINTF_CACHE_CONTROL(fmt, ...) \
+ do { printf("CACHE_CONTROL: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF_CACHE_CONTROL(fmt, ...) do {} while (0)
+#endif
+
+#ifdef TARGET_SPARC64
+#ifndef TARGET_ABI32
+#define AM_CHECK(env1) ((env1)->pstate & PS_AM)
+#else
+#define AM_CHECK(env1) (1)
+#endif
+#endif
+
+#define DT0 (env->dt0)
+#define DT1 (env->dt1)
+#define QT0 (env->qt0)
+#define QT1 (env->qt1)
+
+#if !defined(CONFIG_USER_ONLY)
+static void do_unassigned_access(target_phys_addr_t addr, int is_write,
+ int is_exec, int is_asi, int size);
+#else
+#ifdef TARGET_SPARC64
+static void do_unassigned_access(target_ulong addr, int is_write, int is_exec,
+ int is_asi, int size);
+#endif
+#endif
+
+#if defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY)
+/* Calculates TSB pointer value for fault page size 8k or 64k */
+static uint64_t ultrasparc_tsb_pointer(uint64_t tsb_register,
+ uint64_t tag_access_register,
+ int page_size)
+{
+ uint64_t tsb_base = tsb_register & ~0x1fffULL;
+ int tsb_split = (tsb_register & 0x1000ULL) ? 1 : 0;
+ int tsb_size = tsb_register & 0xf;
+
+ /* discard lower 13 bits which hold tag access context */
+ uint64_t tag_access_va = tag_access_register & ~0x1fffULL;
+
+ /* now reorder bits */
+ uint64_t tsb_base_mask = ~0x1fffULL;
+ uint64_t va = tag_access_va;
+
+ /* move va bits to correct position */
+ if (page_size == 8*1024) {
+ va >>= 9;
+ } else if (page_size == 64*1024) {
+ va >>= 12;
+ }
+
+ if (tsb_size) {
+ tsb_base_mask <<= tsb_size;
+ }
+
+ /* calculate tsb_base mask and adjust va if split is in use */
+ if (tsb_split) {
+ if (page_size == 8*1024) {
+ va &= ~(1ULL << (13 + tsb_size));
+ } else if (page_size == 64*1024) {
+ va |= (1ULL << (13 + tsb_size));
+ }
+ tsb_base_mask <<= 1;
+ }
+
+ return ((tsb_base & tsb_base_mask) | (va & ~tsb_base_mask)) & ~0xfULL;
+}
+
+/* Calculates tag target register value by reordering bits
+ in tag access register */
+static uint64_t ultrasparc_tag_target(uint64_t tag_access_register)
+{
+ return ((tag_access_register & 0x1fff) << 48) | (tag_access_register >> 22);
+}
+
+static void replace_tlb_entry(SparcTLBEntry *tlb,
+ uint64_t tlb_tag, uint64_t tlb_tte,
+ CPUState *env1)
+{
+ target_ulong mask, size, va, offset;
+
+ /* flush page range if translation is valid */
+ if (TTE_IS_VALID(tlb->tte)) {
+
+ mask = 0xffffffffffffe000ULL;
+ mask <<= 3 * ((tlb->tte >> 61) & 3);
+ size = ~mask + 1;
+
+ va = tlb->tag & mask;
+
+ for (offset = 0; offset < size; offset += TARGET_PAGE_SIZE) {
+ tlb_flush_page(env1, va + offset);
+ }
+ }
+
+ tlb->tag = tlb_tag;
+ tlb->tte = tlb_tte;
+}
+
+static void demap_tlb(SparcTLBEntry *tlb, target_ulong demap_addr,
+ const char *strmmu, CPUState *env1)
+{
+ unsigned int i;
+ target_ulong mask;
+ uint64_t context;
+
+ int is_demap_context = (demap_addr >> 6) & 1;
+
+ /* demap context */
+ switch ((demap_addr >> 4) & 3) {
+ case 0: /* primary */
+ context = env1->dmmu.mmu_primary_context;
+ break;
+ case 1: /* secondary */
+ context = env1->dmmu.mmu_secondary_context;
+ break;
+ case 2: /* nucleus */
+ context = 0;
+ break;
+ case 3: /* reserved */
+ default:
+ return;
+ }
+
+ for (i = 0; i < 64; i++) {
+ if (TTE_IS_VALID(tlb[i].tte)) {
+
+ if (is_demap_context) {
+ /* will remove non-global entries matching context value */
+ if (TTE_IS_GLOBAL(tlb[i].tte) ||
+ !tlb_compare_context(&tlb[i], context)) {
+ continue;
+ }
+ } else {
+ /* demap page
+ will remove any entry matching VA */
+ mask = 0xffffffffffffe000ULL;
+ mask <<= 3 * ((tlb[i].tte >> 61) & 3);
+
+ if (!compare_masked(demap_addr, tlb[i].tag, mask)) {
+ continue;
+ }
+
+ /* entry should be global or matching context value */
+ if (!TTE_IS_GLOBAL(tlb[i].tte) &&
+ !tlb_compare_context(&tlb[i], context)) {
+ continue;
+ }
+ }
+
+ replace_tlb_entry(&tlb[i], 0, 0, env1);
+#ifdef DEBUG_MMU
+ DPRINTF_MMU("%s demap invalidated entry [%02u]\n", strmmu, i);
+ dump_mmu(stdout, fprintf, env1);
+#endif
+ }
+ }
+}
+
+static void replace_tlb_1bit_lru(SparcTLBEntry *tlb,
+ uint64_t tlb_tag, uint64_t tlb_tte,
+ const char *strmmu, CPUState *env1)
+{
+ unsigned int i, replace_used;
+
+ /* Try replacing invalid entry */
+ for (i = 0; i < 64; i++) {
+ if (!TTE_IS_VALID(tlb[i].tte)) {
+ replace_tlb_entry(&tlb[i], tlb_tag, tlb_tte, env1);
+#ifdef DEBUG_MMU
+ DPRINTF_MMU("%s lru replaced invalid entry [%i]\n", strmmu, i);
+ dump_mmu(stdout, fprintf, env1);
+#endif
+ return;
+ }
+ }
+
+ /* All entries are valid, try replacing unlocked entry */
+
+ for (replace_used = 0; replace_used < 2; ++replace_used) {
+
+ /* Used entries are not replaced on first pass */
+
+ for (i = 0; i < 64; i++) {
+ if (!TTE_IS_LOCKED(tlb[i].tte) && !TTE_IS_USED(tlb[i].tte)) {
+
+ replace_tlb_entry(&tlb[i], tlb_tag, tlb_tte, env1);
+#ifdef DEBUG_MMU
+ DPRINTF_MMU("%s lru replaced unlocked %s entry [%i]\n",
+ strmmu, (replace_used ? "used" : "unused"), i);
+ dump_mmu(stdout, fprintf, env1);
+#endif
+ return;
+ }
+ }
+
+ /* Now reset used bit and search for unused entries again */
+
+ for (i = 0; i < 64; i++) {
+ TTE_SET_UNUSED(tlb[i].tte);
+ }
+ }
+
+#ifdef DEBUG_MMU
+ DPRINTF_MMU("%s lru replacement failed: no entries available\n", strmmu);
+#endif
+ /* error state? */
+}
+
+#endif
+
+static inline target_ulong address_mask(CPUState *env1, target_ulong addr)
+{
+#ifdef TARGET_SPARC64
+ if (AM_CHECK(env1)) {
+ addr &= 0xffffffffULL;
+ }
+#endif
+ return addr;
+}
+
+/* returns true if access using this ASI is to have address translated by MMU
+ otherwise access is to raw physical address */
+static inline int is_translating_asi(int asi)
+{
+#ifdef TARGET_SPARC64
+ /* Ultrasparc IIi translating asi
+ - note this list is defined by cpu implementation
+ */
+ switch (asi) {
+ case 0x04 ... 0x11:
+ case 0x16 ... 0x19:
+ case 0x1E ... 0x1F:
+ case 0x24 ... 0x2C:
+ case 0x70 ... 0x73:
+ case 0x78 ... 0x79:
+ case 0x80 ... 0xFF:
+ return 1;
+
+ default:
+ return 0;
+ }
+#else
+ /* TODO: check sparc32 bits */
+ return 0;
+#endif
+}
+
+static inline target_ulong asi_address_mask(CPUState *env1,
+ int asi, target_ulong addr)
+{
+ if (is_translating_asi(asi)) {
+ return address_mask(env, addr);
+ } else {
+ return addr;
+ }
+}
+
+void helper_check_align(target_ulong addr, uint32_t align)
+{
+ if (addr & align) {
+#ifdef DEBUG_UNALIGNED
+ printf("Unaligned access to 0x" TARGET_FMT_lx " from 0x" TARGET_FMT_lx
+ "\n", addr, env->pc);
+#endif
+ helper_raise_exception(env, TT_UNALIGNED);
+ }
+}
+
+#if !defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY) && \
+ defined(DEBUG_MXCC)
+static void dump_mxcc(CPUState *env)
+{
+ printf("mxccdata: %016" PRIx64 " %016" PRIx64 " %016" PRIx64 " %016" PRIx64
+ "\n",
+ env->mxccdata[0], env->mxccdata[1],
+ env->mxccdata[2], env->mxccdata[3]);
+ printf("mxccregs: %016" PRIx64 " %016" PRIx64 " %016" PRIx64 " %016" PRIx64
+ "\n"
+ " %016" PRIx64 " %016" PRIx64 " %016" PRIx64 " %016" PRIx64
+ "\n",
+ env->mxccregs[0], env->mxccregs[1],
+ env->mxccregs[2], env->mxccregs[3],
+ env->mxccregs[4], env->mxccregs[5],
+ env->mxccregs[6], env->mxccregs[7]);
+}
+#endif
+
+#if (defined(TARGET_SPARC64) || !defined(CONFIG_USER_ONLY)) \
+ && defined(DEBUG_ASI)
+static void dump_asi(const char *txt, target_ulong addr, int asi, int size,
+ uint64_t r1)
+{
+ switch (size) {
+ case 1:
+ DPRINTF_ASI("%s "TARGET_FMT_lx " asi 0x%02x = %02" PRIx64 "\n", txt,
+ addr, asi, r1 & 0xff);
+ break;
+ case 2:
+ DPRINTF_ASI("%s "TARGET_FMT_lx " asi 0x%02x = %04" PRIx64 "\n", txt,
+ addr, asi, r1 & 0xffff);
+ break;
+ case 4:
+ DPRINTF_ASI("%s "TARGET_FMT_lx " asi 0x%02x = %08" PRIx64 "\n", txt,
+ addr, asi, r1 & 0xffffffff);
+ break;
+ case 8:
+ DPRINTF_ASI("%s "TARGET_FMT_lx " asi 0x%02x = %016" PRIx64 "\n", txt,
+ addr, asi, r1);
+ break;
+ }
+}
+#endif
+
+#ifndef TARGET_SPARC64
+#ifndef CONFIG_USER_ONLY
+
+
+/* Leon3 cache control */
+
+static void leon3_cache_control_st(target_ulong addr, uint64_t val, int size)
+{
+ DPRINTF_CACHE_CONTROL("st addr:%08x, val:%" PRIx64 ", size:%d\n",
+ addr, val, size);
+
+ if (size != 4) {
+ DPRINTF_CACHE_CONTROL("32bits only\n");
+ return;
+ }
+
+ switch (addr) {
+ case 0x00: /* Cache control */
+
+ /* These values must always be read as zeros */
+ val &= ~CACHE_CTRL_FD;
+ val &= ~CACHE_CTRL_FI;
+ val &= ~CACHE_CTRL_IB;
+ val &= ~CACHE_CTRL_IP;
+ val &= ~CACHE_CTRL_DP;
+
+ env->cache_control = val;
+ break;
+ case 0x04: /* Instruction cache configuration */
+ case 0x08: /* Data cache configuration */
+ /* Read Only */
+ break;
+ default:
+ DPRINTF_CACHE_CONTROL("write unknown register %08x\n", addr);
+ break;
+ };
+}
+
+static uint64_t leon3_cache_control_ld(target_ulong addr, int size)
+{
+ uint64_t ret = 0;
+
+ if (size != 4) {
+ DPRINTF_CACHE_CONTROL("32bits only\n");
+ return 0;
+ }
+
+ switch (addr) {
+ case 0x00: /* Cache control */
+ ret = env->cache_control;
+ break;
+
+ /* Configuration registers are read and only always keep those
+ predefined values */
+
+ case 0x04: /* Instruction cache configuration */
+ ret = 0x10220000;
+ break;
+ case 0x08: /* Data cache configuration */
+ ret = 0x18220000;
+ break;
+ default:
+ DPRINTF_CACHE_CONTROL("read unknown register %08x\n", addr);
+ break;
+ };
+ DPRINTF_CACHE_CONTROL("ld addr:%08x, ret:0x%" PRIx64 ", size:%d\n",
+ addr, ret, size);
+ return ret;
+}
+
+uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
+{
+ uint64_t ret = 0;
+#if defined(DEBUG_MXCC) || defined(DEBUG_ASI)
+ uint32_t last_addr = addr;
+#endif
+
+ helper_check_align(addr, size - 1);
+ switch (asi) {
+ case 2: /* SuperSparc MXCC registers and Leon3 cache control */
+ switch (addr) {
+ case 0x00: /* Leon3 Cache Control */
+ case 0x08: /* Leon3 Instruction Cache config */
+ case 0x0C: /* Leon3 Date Cache config */
+ if (env->def->features & CPU_FEATURE_CACHE_CTRL) {
+ ret = leon3_cache_control_ld(addr, size);
+ }
+ break;
+ case 0x01c00a00: /* MXCC control register */
+ if (size == 8) {
+ ret = env->mxccregs[3];
+ } else {
+ DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
+ size);
+ }
+ break;
+ case 0x01c00a04: /* MXCC control register */
+ if (size == 4) {
+ ret = env->mxccregs[3];
+ } else {
+ DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
+ size);
+ }
+ break;
+ case 0x01c00c00: /* Module reset register */
+ if (size == 8) {
+ ret = env->mxccregs[5];
+ /* should we do something here? */
+ } else {
+ DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
+ size);
+ }
+ break;
+ case 0x01c00f00: /* MBus port address register */
+ if (size == 8) {
+ ret = env->mxccregs[7];
+ } else {
+ DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
+ size);
+ }
+ break;
+ default:
+ DPRINTF_MXCC("%08x: unimplemented address, size: %d\n", addr,
+ size);
+ break;
+ }
+ DPRINTF_MXCC("asi = %d, size = %d, sign = %d, "
+ "addr = %08x -> ret = %" PRIx64 ","
+ "addr = %08x\n", asi, size, sign, last_addr, ret, addr);
+#ifdef DEBUG_MXCC
+ dump_mxcc(env);
+#endif
+ break;
+ case 3: /* MMU probe */
+ {
+ int mmulev;
+
+ mmulev = (addr >> 8) & 15;
+ if (mmulev > 4) {
+ ret = 0;
+ } else {
+ ret = mmu_probe(env, addr, mmulev);
+ }
+ DPRINTF_MMU("mmu_probe: 0x%08x (lev %d) -> 0x%08" PRIx64 "\n",
+ addr, mmulev, ret);
+ }
+ break;
+ case 4: /* read MMU regs */
+ {
+ int reg = (addr >> 8) & 0x1f;
+
+ ret = env->mmuregs[reg];
+ if (reg == 3) { /* Fault status cleared on read */
+ env->mmuregs[3] = 0;
+ } else if (reg == 0x13) { /* Fault status read */
+ ret = env->mmuregs[3];
+ } else if (reg == 0x14) { /* Fault address read */
+ ret = env->mmuregs[4];
+ }
+ DPRINTF_MMU("mmu_read: reg[%d] = 0x%08" PRIx64 "\n", reg, ret);
+ }
+ break;
+ case 5: /* Turbosparc ITLB Diagnostic */
+ case 6: /* Turbosparc DTLB Diagnostic */
+ case 7: /* Turbosparc IOTLB Diagnostic */
+ break;
+ case 9: /* Supervisor code access */
+ switch (size) {
+ case 1:
+ ret = ldub_code(addr);
+ break;
+ case 2:
+ ret = lduw_code(addr);
+ break;
+ default:
+ case 4:
+ ret = ldl_code(addr);
+ break;
+ case 8:
+ ret = ldq_code(addr);
+ break;
+ }
+ break;
+ case 0xa: /* User data access */
+ switch (size) {
+ case 1:
+ ret = ldub_user(addr);
+ break;
+ case 2:
+ ret = lduw_user(addr);
+ break;
+ default:
+ case 4:
+ ret = ldl_user(addr);
+ break;
+ case 8:
+ ret = ldq_user(addr);
+ break;
+ }
+ break;
+ case 0xb: /* Supervisor data access */
+ switch (size) {
+ case 1:
+ ret = ldub_kernel(addr);
+ break;
+ case 2:
+ ret = lduw_kernel(addr);
+ break;
+ default:
+ case 4:
+ ret = ldl_kernel(addr);
+ break;
+ case 8:
+ ret = ldq_kernel(addr);
+ break;
+ }
+ break;
+ case 0xc: /* I-cache tag */
+ case 0xd: /* I-cache data */
+ case 0xe: /* D-cache tag */
+ case 0xf: /* D-cache data */
+ break;
+ case 0x20: /* MMU passthrough */
+ switch (size) {
+ case 1:
+ ret = ldub_phys(addr);
+ break;
+ case 2:
+ ret = lduw_phys(addr);
+ break;
+ default:
+ case 4:
+ ret = ldl_phys(addr);
+ break;
+ case 8:
+ ret = ldq_phys(addr);
+ break;
+ }
+ break;
+ case 0x21 ... 0x2f: /* MMU passthrough, 0x100000000 to 0xfffffffff */
+ switch (size) {
+ case 1:
+ ret = ldub_phys((target_phys_addr_t)addr
+ | ((target_phys_addr_t)(asi & 0xf) << 32));
+ break;
+ case 2:
+ ret = lduw_phys((target_phys_addr_t)addr
+ | ((target_phys_addr_t)(asi & 0xf) << 32));
+ break;
+ default:
+ case 4:
+ ret = ldl_phys((target_phys_addr_t)addr
+ | ((target_phys_addr_t)(asi & 0xf) << 32));
+ break;
+ case 8:
+ ret = ldq_phys((target_phys_addr_t)addr
+ | ((target_phys_addr_t)(asi & 0xf) << 32));
+ break;
+ }
+ break;
+ case 0x30: /* Turbosparc secondary cache diagnostic */
+ case 0x31: /* Turbosparc RAM snoop */
+ case 0x32: /* Turbosparc page table descriptor diagnostic */
+ case 0x39: /* data cache diagnostic register */
+ ret = 0;
+ break;
+ case 0x38: /* SuperSPARC MMU Breakpoint Control Registers */
+ {
+ int reg = (addr >> 8) & 3;
+
+ switch (reg) {
+ case 0: /* Breakpoint Value (Addr) */
+ ret = env->mmubpregs[reg];
+ break;
+ case 1: /* Breakpoint Mask */
+ ret = env->mmubpregs[reg];
+ break;
+ case 2: /* Breakpoint Control */
+ ret = env->mmubpregs[reg];
+ break;
+ case 3: /* Breakpoint Status */
+ ret = env->mmubpregs[reg];
+ env->mmubpregs[reg] = 0ULL;
+ break;
+ }
+ DPRINTF_MMU("read breakpoint reg[%d] 0x%016" PRIx64 "\n", reg,
+ ret);
+ }
+ break;
+ case 0x49: /* SuperSPARC MMU Counter Breakpoint Value */
+ ret = env->mmubpctrv;
+ break;
+ case 0x4a: /* SuperSPARC MMU Counter Breakpoint Control */
+ ret = env->mmubpctrc;
+ break;
+ case 0x4b: /* SuperSPARC MMU Counter Breakpoint Status */
+ ret = env->mmubpctrs;
+ break;
+ case 0x4c: /* SuperSPARC MMU Breakpoint Action */
+ ret = env->mmubpaction;
+ break;
+ case 8: /* User code access, XXX */
+ default:
+ do_unassigned_access(addr, 0, 0, asi, size);
+ ret = 0;
+ break;
+ }
+ if (sign) {
+ switch (size) {
+ case 1:
+ ret = (int8_t) ret;
+ break;
+ case 2:
+ ret = (int16_t) ret;
+ break;
+ case 4:
+ ret = (int32_t) ret;
+ break;
+ default:
+ break;
+ }
+ }
+#ifdef DEBUG_ASI
+ dump_asi("read ", last_addr, asi, size, ret);
+#endif
+ return ret;
+}
+
+void helper_st_asi(target_ulong addr, uint64_t val, int asi, int size)
+{
+ helper_check_align(addr, size - 1);
+ switch (asi) {
+ case 2: /* SuperSparc MXCC registers and Leon3 cache control */
+ switch (addr) {
+ case 0x00: /* Leon3 Cache Control */
+ case 0x08: /* Leon3 Instruction Cache config */
+ case 0x0C: /* Leon3 Date Cache config */
+ if (env->def->features & CPU_FEATURE_CACHE_CTRL) {
+ leon3_cache_control_st(addr, val, size);
+ }
+ break;
+
+ case 0x01c00000: /* MXCC stream data register 0 */
+ if (size == 8) {
+ env->mxccdata[0] = val;
+ } else {
+ DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
+ size);
+ }
+ break;
+ case 0x01c00008: /* MXCC stream data register 1 */
+ if (size == 8) {
+ env->mxccdata[1] = val;
+ } else {
+ DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
+ size);
+ }
+ break;
+ case 0x01c00010: /* MXCC stream data register 2 */
+ if (size == 8) {
+ env->mxccdata[2] = val;
+ } else {
+ DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
+ size);
+ }
+ break;
+ case 0x01c00018: /* MXCC stream data register 3 */
+ if (size == 8) {
+ env->mxccdata[3] = val;
+ } else {
+ DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
+ size);
+ }
+ break;
+ case 0x01c00100: /* MXCC stream source */
+ if (size == 8) {
+ env->mxccregs[0] = val;
+ } else {
+ DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
+ size);
+ }
+ env->mxccdata[0] = ldq_phys((env->mxccregs[0] & 0xffffffffULL) +
+ 0);
+ env->mxccdata[1] = ldq_phys((env->mxccregs[0] & 0xffffffffULL) +
+ 8);
+ env->mxccdata[2] = ldq_phys((env->mxccregs[0] & 0xffffffffULL) +
+ 16);
+ env->mxccdata[3] = ldq_phys((env->mxccregs[0] & 0xffffffffULL) +
+ 24);
+ break;
+ case 0x01c00200: /* MXCC stream destination */
+ if (size == 8) {
+ env->mxccregs[1] = val;
+ } else {
+ DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
+ size);
+ }
+ stq_phys((env->mxccregs[1] & 0xffffffffULL) + 0,
+ env->mxccdata[0]);
+ stq_phys((env->mxccregs[1] & 0xffffffffULL) + 8,
+ env->mxccdata[1]);
+ stq_phys((env->mxccregs[1] & 0xffffffffULL) + 16,
+ env->mxccdata[2]);
+ stq_phys((env->mxccregs[1] & 0xffffffffULL) + 24,
+ env->mxccdata[3]);
+ break;
+ case 0x01c00a00: /* MXCC control register */
+ if (size == 8) {
+ env->mxccregs[3] = val;
+ } else {
+ DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
+ size);
+ }
+ break;
+ case 0x01c00a04: /* MXCC control register */
+ if (size == 4) {
+ env->mxccregs[3] = (env->mxccregs[3] & 0xffffffff00000000ULL)
+ | val;
+ } else {
+ DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
+ size);
+ }
+ break;
+ case 0x01c00e00: /* MXCC error register */
+ /* writing a 1 bit clears the error */
+ if (size == 8) {
+ env->mxccregs[6] &= ~val;
+ } else {
+ DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
+ size);
+ }
+ break;
+ case 0x01c00f00: /* MBus port address register */
+ if (size == 8) {
+ env->mxccregs[7] = val;
+ } else {
+ DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
+ size);
+ }
+ break;
+ default:
+ DPRINTF_MXCC("%08x: unimplemented address, size: %d\n", addr,
+ size);
+ break;
+ }
+ DPRINTF_MXCC("asi = %d, size = %d, addr = %08x, val = %" PRIx64 "\n",
+ asi, size, addr, val);
+#ifdef DEBUG_MXCC
+ dump_mxcc(env);
+#endif
+ break;
+ case 3: /* MMU flush */
+ {
+ int mmulev;
+
+ mmulev = (addr >> 8) & 15;
+ DPRINTF_MMU("mmu flush level %d\n", mmulev);
+ switch (mmulev) {
+ case 0: /* flush page */
+ tlb_flush_page(env, addr & 0xfffff000);
+ break;
+ case 1: /* flush segment (256k) */
+ case 2: /* flush region (16M) */
+ case 3: /* flush context (4G) */
+ case 4: /* flush entire */
+ tlb_flush(env, 1);
+ break;
+ default:
+ break;
+ }
+#ifdef DEBUG_MMU
+ dump_mmu(stdout, fprintf, env);
+#endif
+ }
+ break;
+ case 4: /* write MMU regs */
+ {
+ int reg = (addr >> 8) & 0x1f;
+ uint32_t oldreg;
+
+ oldreg = env->mmuregs[reg];
+ switch (reg) {
+ case 0: /* Control Register */
+ env->mmuregs[reg] = (env->mmuregs[reg] & 0xff000000) |
+ (val & 0x00ffffff);
+ /* Mappings generated during no-fault mode or MMU
+ disabled mode are invalid in normal mode */
+ if ((oldreg & (MMU_E | MMU_NF | env->def->mmu_bm)) !=
+ (env->mmuregs[reg] & (MMU_E | MMU_NF | env->def->mmu_bm))) {
+ tlb_flush(env, 1);
+ }
+ break;
+ case 1: /* Context Table Pointer Register */
+ env->mmuregs[reg] = val & env->def->mmu_ctpr_mask;
+ break;
+ case 2: /* Context Register */
+ env->mmuregs[reg] = val & env->def->mmu_cxr_mask;
+ if (oldreg != env->mmuregs[reg]) {
+ /* we flush when the MMU context changes because
+ QEMU has no MMU context support */
+ tlb_flush(env, 1);
+ }
+ break;
+ case 3: /* Synchronous Fault Status Register with Clear */
+ case 4: /* Synchronous Fault Address Register */
+ break;
+ case 0x10: /* TLB Replacement Control Register */
+ env->mmuregs[reg] = val & env->def->mmu_trcr_mask;
+ break;
+ case 0x13: /* Synchronous Fault Status Register with Read
+ and Clear */
+ env->mmuregs[3] = val & env->def->mmu_sfsr_mask;
+ break;
+ case 0x14: /* Synchronous Fault Address Register */
+ env->mmuregs[4] = val;
+ break;
+ default:
+ env->mmuregs[reg] = val;
+ break;
+ }
+ if (oldreg != env->mmuregs[reg]) {
+ DPRINTF_MMU("mmu change reg[%d]: 0x%08x -> 0x%08x\n",
+ reg, oldreg, env->mmuregs[reg]);
+ }
+#ifdef DEBUG_MMU
+ dump_mmu(stdout, fprintf, env);
+#endif
+ }
+ break;
+ case 5: /* Turbosparc ITLB Diagnostic */
+ case 6: /* Turbosparc DTLB Diagnostic */
+ case 7: /* Turbosparc IOTLB Diagnostic */
+ break;
+ case 0xa: /* User data access */
+ switch (size) {
+ case 1:
+ stb_user(addr, val);
+ break;
+ case 2:
+ stw_user(addr, val);
+ break;
+ default:
+ case 4:
+ stl_user(addr, val);
+ break;
+ case 8:
+ stq_user(addr, val);
+ break;
+ }
+ break;
+ case 0xb: /* Supervisor data access */
+ switch (size) {
+ case 1:
+ stb_kernel(addr, val);
+ break;
+ case 2:
+ stw_kernel(addr, val);
+ break;
+ default:
+ case 4:
+ stl_kernel(addr, val);
+ break;
+ case 8:
+ stq_kernel(addr, val);
+ break;
+ }
+ break;
+ case 0xc: /* I-cache tag */
+ case 0xd: /* I-cache data */
+ case 0xe: /* D-cache tag */
+ case 0xf: /* D-cache data */
+ case 0x10: /* I/D-cache flush page */
+ case 0x11: /* I/D-cache flush segment */
+ case 0x12: /* I/D-cache flush region */
+ case 0x13: /* I/D-cache flush context */
+ case 0x14: /* I/D-cache flush user */
+ break;
+ case 0x17: /* Block copy, sta access */
+ {
+ /* val = src
+ addr = dst
+ copy 32 bytes */
+ unsigned int i;
+ uint32_t src = val & ~3, dst = addr & ~3, temp;
+
+ for (i = 0; i < 32; i += 4, src += 4, dst += 4) {
+ temp = ldl_kernel(src);
+ stl_kernel(dst, temp);
+ }
+ }
+ break;
+ case 0x1f: /* Block fill, stda access */
+ {
+ /* addr = dst
+ fill 32 bytes with val */
+ unsigned int i;
+ uint32_t dst = addr & 7;
+
+ for (i = 0; i < 32; i += 8, dst += 8) {
+ stq_kernel(dst, val);
+ }
+ }
+ break;
+ case 0x20: /* MMU passthrough */
+ {
+ switch (size) {
+ case 1:
+ stb_phys(addr, val);
+ break;
+ case 2:
+ stw_phys(addr, val);
+ break;
+ case 4:
+ default:
+ stl_phys(addr, val);
+ break;
+ case 8:
+ stq_phys(addr, val);
+ break;
+ }
+ }
+ break;
+ case 0x21 ... 0x2f: /* MMU passthrough, 0x100000000 to 0xfffffffff */
+ {
+ switch (size) {
+ case 1:
+ stb_phys((target_phys_addr_t)addr
+ | ((target_phys_addr_t)(asi & 0xf) << 32), val);
+ break;
+ case 2:
+ stw_phys((target_phys_addr_t)addr
+ | ((target_phys_addr_t)(asi & 0xf) << 32), val);
+ break;
+ case 4:
+ default:
+ stl_phys((target_phys_addr_t)addr
+ | ((target_phys_addr_t)(asi & 0xf) << 32), val);
+ break;
+ case 8:
+ stq_phys((target_phys_addr_t)addr
+ | ((target_phys_addr_t)(asi & 0xf) << 32), val);
+ break;
+ }
+ }
+ break;
+ case 0x30: /* store buffer tags or Turbosparc secondary cache diagnostic */
+ case 0x31: /* store buffer data, Ross RT620 I-cache flush or
+ Turbosparc snoop RAM */
+ case 0x32: /* store buffer control or Turbosparc page table
+ descriptor diagnostic */
+ case 0x36: /* I-cache flash clear */
+ case 0x37: /* D-cache flash clear */
+ break;
+ case 0x38: /* SuperSPARC MMU Breakpoint Control Registers*/
+ {
+ int reg = (addr >> 8) & 3;
+
+ switch (reg) {
+ case 0: /* Breakpoint Value (Addr) */
+ env->mmubpregs[reg] = (val & 0xfffffffffULL);
+ break;
+ case 1: /* Breakpoint Mask */
+ env->mmubpregs[reg] = (val & 0xfffffffffULL);
+ break;
+ case 2: /* Breakpoint Control */
+ env->mmubpregs[reg] = (val & 0x7fULL);
+ break;
+ case 3: /* Breakpoint Status */
+ env->mmubpregs[reg] = (val & 0xfULL);
+ break;
+ }
+ DPRINTF_MMU("write breakpoint reg[%d] 0x%016x\n", reg,
+ env->mmuregs[reg]);
+ }
+ break;
+ case 0x49: /* SuperSPARC MMU Counter Breakpoint Value */
+ env->mmubpctrv = val & 0xffffffff;
+ break;
+ case 0x4a: /* SuperSPARC MMU Counter Breakpoint Control */
+ env->mmubpctrc = val & 0x3;
+ break;
+ case 0x4b: /* SuperSPARC MMU Counter Breakpoint Status */
+ env->mmubpctrs = val & 0x3;
+ break;
+ case 0x4c: /* SuperSPARC MMU Breakpoint Action */
+ env->mmubpaction = val & 0x1fff;
+ break;
+ case 8: /* User code access, XXX */
+ case 9: /* Supervisor code access, XXX */
+ default:
+ do_unassigned_access(addr, 1, 0, asi, size);
+ break;
+ }
+#ifdef DEBUG_ASI
+ dump_asi("write", addr, asi, size, val);
+#endif
+}
+
+#endif /* CONFIG_USER_ONLY */
+#else /* TARGET_SPARC64 */
+
+#ifdef CONFIG_USER_ONLY
+uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
+{
+ uint64_t ret = 0;
+#if defined(DEBUG_ASI)
+ target_ulong last_addr = addr;
+#endif
+
+ if (asi < 0x80) {
+ helper_raise_exception(env, TT_PRIV_ACT);
+ }
+
+ helper_check_align(addr, size - 1);
+ addr = asi_address_mask(env, asi, addr);
+
+ switch (asi) {
+ case 0x82: /* Primary no-fault */
+ case 0x8a: /* Primary no-fault LE */
+ if (page_check_range(addr, size, PAGE_READ) == -1) {
+#ifdef DEBUG_ASI
+ dump_asi("read ", last_addr, asi, size, ret);
+#endif
+ return 0;
+ }
+ /* Fall through */
+ case 0x80: /* Primary */
+ case 0x88: /* Primary LE */
+ {
+ switch (size) {
+ case 1:
+ ret = ldub_raw(addr);
+ break;
+ case 2:
+ ret = lduw_raw(addr);
+ break;
+ case 4:
+ ret = ldl_raw(addr);
+ break;
+ default:
+ case 8:
+ ret = ldq_raw(addr);
+ break;
+ }
+ }
+ break;
+ case 0x83: /* Secondary no-fault */
+ case 0x8b: /* Secondary no-fault LE */
+ if (page_check_range(addr, size, PAGE_READ) == -1) {
+#ifdef DEBUG_ASI
+ dump_asi("read ", last_addr, asi, size, ret);
+#endif
+ return 0;
+ }
+ /* Fall through */
+ case 0x81: /* Secondary */
+ case 0x89: /* Secondary LE */
+ /* XXX */
+ break;
+ default:
+ break;
+ }
+
+ /* Convert from little endian */
+ switch (asi) {
+ case 0x88: /* Primary LE */
+ case 0x89: /* Secondary LE */
+ case 0x8a: /* Primary no-fault LE */
+ case 0x8b: /* Secondary no-fault LE */
+ switch (size) {
+ case 2:
+ ret = bswap16(ret);
+ break;
+ case 4:
+ ret = bswap32(ret);
+ break;
+ case 8:
+ ret = bswap64(ret);
+ break;
+ default:
+ break;
+ }
+ default:
+ break;
+ }
+
+ /* Convert to signed number */
+ if (sign) {
+ switch (size) {
+ case 1:
+ ret = (int8_t) ret;
+ break;
+ case 2:
+ ret = (int16_t) ret;
+ break;
+ case 4:
+ ret = (int32_t) ret;
+ break;
+ default:
+ break;
+ }
+ }
+#ifdef DEBUG_ASI
+ dump_asi("read ", last_addr, asi, size, ret);
+#endif
+ return ret;
+}
+
+void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
+{
+#ifdef DEBUG_ASI
+ dump_asi("write", addr, asi, size, val);
+#endif
+ if (asi < 0x80) {
+ helper_raise_exception(env, TT_PRIV_ACT);
+ }
+
+ helper_check_align(addr, size - 1);
+ addr = asi_address_mask(env, asi, addr);
+
+ /* Convert to little endian */
+ switch (asi) {
+ case 0x88: /* Primary LE */
+ case 0x89: /* Secondary LE */
+ switch (size) {
+ case 2:
+ val = bswap16(val);
+ break;
+ case 4:
+ val = bswap32(val);
+ break;
+ case 8:
+ val = bswap64(val);
+ break;
+ default:
+ break;
+ }
+ default:
+ break;
+ }
+
+ switch (asi) {
+ case 0x80: /* Primary */
+ case 0x88: /* Primary LE */
+ {
+ switch (size) {
+ case 1:
+ stb_raw(addr, val);
+ break;
+ case 2:
+ stw_raw(addr, val);
+ break;
+ case 4:
+ stl_raw(addr, val);
+ break;
+ case 8:
+ default:
+ stq_raw(addr, val);
+ break;
+ }
+ }
+ break;
+ case 0x81: /* Secondary */
+ case 0x89: /* Secondary LE */
+ /* XXX */
+ return;
+
+ case 0x82: /* Primary no-fault, RO */
+ case 0x83: /* Secondary no-fault, RO */
+ case 0x8a: /* Primary no-fault LE, RO */
+ case 0x8b: /* Secondary no-fault LE, RO */
+ default:
+ do_unassigned_access(addr, 1, 0, 1, size);
+ return;
+ }
+}
+
+#else /* CONFIG_USER_ONLY */
+
+uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
+{
+ uint64_t ret = 0;
+#if defined(DEBUG_ASI)
+ target_ulong last_addr = addr;
+#endif
+
+ asi &= 0xff;
+
+ if ((asi < 0x80 && (env->pstate & PS_PRIV) == 0)
+ || (cpu_has_hypervisor(env)
+ && asi >= 0x30 && asi < 0x80
+ && !(env->hpstate & HS_PRIV))) {
+ helper_raise_exception(env, TT_PRIV_ACT);
+ }
+
+ helper_check_align(addr, size - 1);
+ addr = asi_address_mask(env, asi, addr);
+
+ /* process nonfaulting loads first */
+ if ((asi & 0xf6) == 0x82) {
+ int mmu_idx;
+
+ /* secondary space access has lowest asi bit equal to 1 */
+ if (env->pstate & PS_PRIV) {
+ mmu_idx = (asi & 1) ? MMU_KERNEL_SECONDARY_IDX : MMU_KERNEL_IDX;
+ } else {
+ mmu_idx = (asi & 1) ? MMU_USER_SECONDARY_IDX : MMU_USER_IDX;
+ }
+
+ if (cpu_get_phys_page_nofault(env, addr, mmu_idx) == -1ULL) {
+#ifdef DEBUG_ASI
+ dump_asi("read ", last_addr, asi, size, ret);
+#endif
+ /* env->exception_index is set in get_physical_address_data(). */
+ helper_raise_exception(env, env->exception_index);
+ }
+
+ /* convert nonfaulting load ASIs to normal load ASIs */
+ asi &= ~0x02;
+ }
+
+ switch (asi) {
+ case 0x10: /* As if user primary */
+ case 0x11: /* As if user secondary */
+ case 0x18: /* As if user primary LE */
+ case 0x19: /* As if user secondary LE */
+ case 0x80: /* Primary */
+ case 0x81: /* Secondary */
+ case 0x88: /* Primary LE */
+ case 0x89: /* Secondary LE */
+ case 0xe2: /* UA2007 Primary block init */
+ case 0xe3: /* UA2007 Secondary block init */
+ if ((asi & 0x80) && (env->pstate & PS_PRIV)) {
+ if (cpu_hypervisor_mode(env)) {
+ switch (size) {
+ case 1:
+ ret = ldub_hypv(addr);
+ break;
+ case 2:
+ ret = lduw_hypv(addr);
+ break;
+ case 4:
+ ret = ldl_hypv(addr);
+ break;
+ default:
+ case 8:
+ ret = ldq_hypv(addr);
+ break;
+ }
+ } else {
+ /* secondary space access has lowest asi bit equal to 1 */
+ if (asi & 1) {
+ switch (size) {
+ case 1:
+ ret = ldub_kernel_secondary(addr);
+ break;
+ case 2:
+ ret = lduw_kernel_secondary(addr);
+ break;
+ case 4:
+ ret = ldl_kernel_secondary(addr);
+ break;
+ default:
+ case 8:
+ ret = ldq_kernel_secondary(addr);
+ break;
+ }
+ } else {
+ switch (size) {
+ case 1:
+ ret = ldub_kernel(addr);
+ break;
+ case 2:
+ ret = lduw_kernel(addr);
+ break;
+ case 4:
+ ret = ldl_kernel(addr);
+ break;
+ default:
+ case 8:
+ ret = ldq_kernel(addr);
+ break;
+ }
+ }
+ }
+ } else {
+ /* secondary space access has lowest asi bit equal to 1 */
+ if (asi & 1) {
+ switch (size) {
+ case 1:
+ ret = ldub_user_secondary(addr);
+ break;
+ case 2:
+ ret = lduw_user_secondary(addr);
+ break;
+ case 4:
+ ret = ldl_user_secondary(addr);
+ break;
+ default:
+ case 8:
+ ret = ldq_user_secondary(addr);
+ break;
+ }
+ } else {
+ switch (size) {
+ case 1:
+ ret = ldub_user(addr);
+ break;
+ case 2:
+ ret = lduw_user(addr);
+ break;
+ case 4:
+ ret = ldl_user(addr);
+ break;
+ default:
+ case 8:
+ ret = ldq_user(addr);
+ break;
+ }
+ }
+ }
+ break;
+ case 0x14: /* Bypass */
+ case 0x15: /* Bypass, non-cacheable */
+ case 0x1c: /* Bypass LE */
+ case 0x1d: /* Bypass, non-cacheable LE */
+ {
+ switch (size) {
+ case 1:
+ ret = ldub_phys(addr);
+ break;
+ case 2:
+ ret = lduw_phys(addr);
+ break;
+ case 4:
+ ret = ldl_phys(addr);
+ break;
+ default:
+ case 8:
+ ret = ldq_phys(addr);
+ break;
+ }
+ break;
+ }
+ case 0x24: /* Nucleus quad LDD 128 bit atomic */
+ case 0x2c: /* Nucleus quad LDD 128 bit atomic LE
+ Only ldda allowed */
+ helper_raise_exception(env, TT_ILL_INSN);
+ return 0;
+ case 0x04: /* Nucleus */
+ case 0x0c: /* Nucleus Little Endian (LE) */
+ {
+ switch (size) {
+ case 1:
+ ret = ldub_nucleus(addr);
+ break;
+ case 2:
+ ret = lduw_nucleus(addr);
+ break;
+ case 4:
+ ret = ldl_nucleus(addr);
+ break;
+ default:
+ case 8:
+ ret = ldq_nucleus(addr);
+ break;
+ }
+ break;
+ }
+ case 0x4a: /* UPA config */
+ /* XXX */
+ break;
+ case 0x45: /* LSU */
+ ret = env->lsu;
+ break;
+ case 0x50: /* I-MMU regs */
+ {
+ int reg = (addr >> 3) & 0xf;
+
+ if (reg == 0) {
+ /* I-TSB Tag Target register */
+ ret = ultrasparc_tag_target(env->immu.tag_access);
+ } else {
+ ret = env->immuregs[reg];
+ }
+
+ break;
+ }
+ case 0x51: /* I-MMU 8k TSB pointer */
+ {
+ /* env->immuregs[5] holds I-MMU TSB register value
+ env->immuregs[6] holds I-MMU Tag Access register value */
+ ret = ultrasparc_tsb_pointer(env->immu.tsb, env->immu.tag_access,
+ 8*1024);
+ break;
+ }
+ case 0x52: /* I-MMU 64k TSB pointer */
+ {
+ /* env->immuregs[5] holds I-MMU TSB register value
+ env->immuregs[6] holds I-MMU Tag Access register value */
+ ret = ultrasparc_tsb_pointer(env->immu.tsb, env->immu.tag_access,
+ 64*1024);
+ break;
+ }
+ case 0x55: /* I-MMU data access */
+ {
+ int reg = (addr >> 3) & 0x3f;
+
+ ret = env->itlb[reg].tte;
+ break;
+ }
+ case 0x56: /* I-MMU tag read */
+ {
+ int reg = (addr >> 3) & 0x3f;
+
+ ret = env->itlb[reg].tag;
+ break;
+ }
+ case 0x58: /* D-MMU regs */
+ {
+ int reg = (addr >> 3) & 0xf;
+
+ if (reg == 0) {
+ /* D-TSB Tag Target register */
+ ret = ultrasparc_tag_target(env->dmmu.tag_access);
+ } else {
+ ret = env->dmmuregs[reg];
+ }
+ break;
+ }
+ case 0x59: /* D-MMU 8k TSB pointer */
+ {
+ /* env->dmmuregs[5] holds D-MMU TSB register value
+ env->dmmuregs[6] holds D-MMU Tag Access register value */
+ ret = ultrasparc_tsb_pointer(env->dmmu.tsb, env->dmmu.tag_access,
+ 8*1024);
+ break;
+ }
+ case 0x5a: /* D-MMU 64k TSB pointer */
+ {
+ /* env->dmmuregs[5] holds D-MMU TSB register value
+ env->dmmuregs[6] holds D-MMU Tag Access register value */
+ ret = ultrasparc_tsb_pointer(env->dmmu.tsb, env->dmmu.tag_access,
+ 64*1024);
+ break;
+ }
+ case 0x5d: /* D-MMU data access */
+ {
+ int reg = (addr >> 3) & 0x3f;
+
+ ret = env->dtlb[reg].tte;
+ break;
+ }
+ case 0x5e: /* D-MMU tag read */
+ {
+ int reg = (addr >> 3) & 0x3f;
+
+ ret = env->dtlb[reg].tag;
+ break;
+ }
+ case 0x46: /* D-cache data */
+ case 0x47: /* D-cache tag access */
+ case 0x4b: /* E-cache error enable */
+ case 0x4c: /* E-cache asynchronous fault status */
+ case 0x4d: /* E-cache asynchronous fault address */
+ case 0x4e: /* E-cache tag data */
+ case 0x66: /* I-cache instruction access */
+ case 0x67: /* I-cache tag access */
+ case 0x6e: /* I-cache predecode */
+ case 0x6f: /* I-cache LRU etc. */
+ case 0x76: /* E-cache tag */
+ case 0x7e: /* E-cache tag */
+ break;
+ case 0x5b: /* D-MMU data pointer */
+ case 0x48: /* Interrupt dispatch, RO */
+ case 0x49: /* Interrupt data receive */
+ case 0x7f: /* Incoming interrupt vector, RO */
+ /* XXX */
+ break;
+ case 0x54: /* I-MMU data in, WO */
+ case 0x57: /* I-MMU demap, WO */
+ case 0x5c: /* D-MMU data in, WO */
+ case 0x5f: /* D-MMU demap, WO */
+ case 0x77: /* Interrupt vector, WO */
+ default:
+ do_unassigned_access(addr, 0, 0, 1, size);
+ ret = 0;
+ break;
+ }
+
+ /* Convert from little endian */
+ switch (asi) {
+ case 0x0c: /* Nucleus Little Endian (LE) */
+ case 0x18: /* As if user primary LE */
+ case 0x19: /* As if user secondary LE */
+ case 0x1c: /* Bypass LE */
+ case 0x1d: /* Bypass, non-cacheable LE */
+ case 0x88: /* Primary LE */
+ case 0x89: /* Secondary LE */
+ switch(size) {
+ case 2:
+ ret = bswap16(ret);
+ break;
+ case 4:
+ ret = bswap32(ret);
+ break;
+ case 8:
+ ret = bswap64(ret);
+ break;
+ default:
+ break;
+ }
+ default:
+ break;
+ }
+
+ /* Convert to signed number */
+ if (sign) {
+ switch (size) {
+ case 1:
+ ret = (int8_t) ret;
+ break;
+ case 2:
+ ret = (int16_t) ret;
+ break;
+ case 4:
+ ret = (int32_t) ret;
+ break;
+ default:
+ break;
+ }
+ }
+#ifdef DEBUG_ASI
+ dump_asi("read ", last_addr, asi, size, ret);
+#endif
+ return ret;
+}
+
+void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
+{
+#ifdef DEBUG_ASI
+ dump_asi("write", addr, asi, size, val);
+#endif
+
+ asi &= 0xff;
+
+ if ((asi < 0x80 && (env->pstate & PS_PRIV) == 0)
+ || (cpu_has_hypervisor(env)
+ && asi >= 0x30 && asi < 0x80
+ && !(env->hpstate & HS_PRIV))) {
+ helper_raise_exception(env, TT_PRIV_ACT);
+ }
+
+ helper_check_align(addr, size - 1);
+ addr = asi_address_mask(env, asi, addr);
+
+ /* Convert to little endian */
+ switch (asi) {
+ case 0x0c: /* Nucleus Little Endian (LE) */
+ case 0x18: /* As if user primary LE */
+ case 0x19: /* As if user secondary LE */
+ case 0x1c: /* Bypass LE */
+ case 0x1d: /* Bypass, non-cacheable LE */
+ case 0x88: /* Primary LE */
+ case 0x89: /* Secondary LE */
+ switch (size) {
+ case 2:
+ val = bswap16(val);
+ break;
+ case 4:
+ val = bswap32(val);
+ break;
+ case 8:
+ val = bswap64(val);
+ break;
+ default:
+ break;
+ }
+ default:
+ break;
+ }
+
+ switch (asi) {
+ case 0x10: /* As if user primary */
+ case 0x11: /* As if user secondary */
+ case 0x18: /* As if user primary LE */
+ case 0x19: /* As if user secondary LE */
+ case 0x80: /* Primary */
+ case 0x81: /* Secondary */
+ case 0x88: /* Primary LE */
+ case 0x89: /* Secondary LE */
+ case 0xe2: /* UA2007 Primary block init */
+ case 0xe3: /* UA2007 Secondary block init */
+ if ((asi & 0x80) && (env->pstate & PS_PRIV)) {
+ if (cpu_hypervisor_mode(env)) {
+ switch (size) {
+ case 1:
+ stb_hypv(addr, val);
+ break;
+ case 2:
+ stw_hypv(addr, val);
+ break;
+ case 4:
+ stl_hypv(addr, val);
+ break;
+ case 8:
+ default:
+ stq_hypv(addr, val);
+ break;
+ }
+ } else {
+ /* secondary space access has lowest asi bit equal to 1 */
+ if (asi & 1) {
+ switch (size) {
+ case 1:
+ stb_kernel_secondary(addr, val);
+ break;
+ case 2:
+ stw_kernel_secondary(addr, val);
+ break;
+ case 4:
+ stl_kernel_secondary(addr, val);
+ break;
+ case 8:
+ default:
+ stq_kernel_secondary(addr, val);
+ break;
+ }
+ } else {
+ switch (size) {
+ case 1:
+ stb_kernel(addr, val);
+ break;
+ case 2:
+ stw_kernel(addr, val);
+ break;
+ case 4:
+ stl_kernel(addr, val);
+ break;
+ case 8:
+ default:
+ stq_kernel(addr, val);
+ break;
+ }
+ }
+ }
+ } else {
+ /* secondary space access has lowest asi bit equal to 1 */
+ if (asi & 1) {
+ switch (size) {
+ case 1:
+ stb_user_secondary(addr, val);
+ break;
+ case 2:
+ stw_user_secondary(addr, val);
+ break;
+ case 4:
+ stl_user_secondary(addr, val);
+ break;
+ case 8:
+ default:
+ stq_user_secondary(addr, val);
+ break;
+ }
+ } else {
+ switch (size) {
+ case 1:
+ stb_user(addr, val);
+ break;
+ case 2:
+ stw_user(addr, val);
+ break;
+ case 4:
+ stl_user(addr, val);
+ break;
+ case 8:
+ default:
+ stq_user(addr, val);
+ break;
+ }
+ }
+ }
+ break;
+ case 0x14: /* Bypass */
+ case 0x15: /* Bypass, non-cacheable */
+ case 0x1c: /* Bypass LE */
+ case 0x1d: /* Bypass, non-cacheable LE */
+ {
+ switch (size) {
+ case 1:
+ stb_phys(addr, val);
+ break;
+ case 2:
+ stw_phys(addr, val);
+ break;
+ case 4:
+ stl_phys(addr, val);
+ break;
+ case 8:
+ default:
+ stq_phys(addr, val);
+ break;
+ }
+ }
+ return;
+ case 0x24: /* Nucleus quad LDD 128 bit atomic */
+ case 0x2c: /* Nucleus quad LDD 128 bit atomic LE
+ Only ldda allowed */
+ helper_raise_exception(env, TT_ILL_INSN);
+ return;
+ case 0x04: /* Nucleus */
+ case 0x0c: /* Nucleus Little Endian (LE) */
+ {
+ switch (size) {
+ case 1:
+ stb_nucleus(addr, val);
+ break;
+ case 2:
+ stw_nucleus(addr, val);
+ break;
+ case 4:
+ stl_nucleus(addr, val);
+ break;
+ default:
+ case 8:
+ stq_nucleus(addr, val);
+ break;
+ }
+ break;
+ }
+
+ case 0x4a: /* UPA config */
+ /* XXX */
+ return;
+ case 0x45: /* LSU */
+ {
+ uint64_t oldreg;
+
+ oldreg = env->lsu;
+ env->lsu = val & (DMMU_E | IMMU_E);
+ /* Mappings generated during D/I MMU disabled mode are
+ invalid in normal mode */
+ if (oldreg != env->lsu) {
+ DPRINTF_MMU("LSU change: 0x%" PRIx64 " -> 0x%" PRIx64 "\n",
+ oldreg, env->lsu);
+#ifdef DEBUG_MMU
+ dump_mmu(stdout, fprintf, env1);
+#endif
+ tlb_flush(env, 1);
+ }
+ return;
+ }
+ case 0x50: /* I-MMU regs */
+ {
+ int reg = (addr >> 3) & 0xf;
+ uint64_t oldreg;
+
+ oldreg = env->immuregs[reg];
+ switch (reg) {
+ case 0: /* RO */
+ return;
+ case 1: /* Not in I-MMU */
+ case 2:
+ return;
+ case 3: /* SFSR */
+ if ((val & 1) == 0) {
+ val = 0; /* Clear SFSR */
+ }
+ env->immu.sfsr = val;
+ break;
+ case 4: /* RO */
+ return;
+ case 5: /* TSB access */
+ DPRINTF_MMU("immu TSB write: 0x%016" PRIx64 " -> 0x%016"
+ PRIx64 "\n", env->immu.tsb, val);
+ env->immu.tsb = val;
+ break;
+ case 6: /* Tag access */
+ env->immu.tag_access = val;
+ break;
+ case 7:
+ case 8:
+ return;
+ default:
+ break;
+ }
+
+ if (oldreg != env->immuregs[reg]) {
+ DPRINTF_MMU("immu change reg[%d]: 0x%016" PRIx64 " -> 0x%016"
+ PRIx64 "\n", reg, oldreg, env->immuregs[reg]);
+ }
+#ifdef DEBUG_MMU
+ dump_mmu(stdout, fprintf, env);
+#endif
+ return;
+ }
+ case 0x54: /* I-MMU data in */
+ replace_tlb_1bit_lru(env->itlb, env->immu.tag_access, val, "immu", env);
+ return;
+ case 0x55: /* I-MMU data access */
+ {
+ /* TODO: auto demap */
+
+ unsigned int i = (addr >> 3) & 0x3f;
+
+ replace_tlb_entry(&env->itlb[i], env->immu.tag_access, val, env);
+
+#ifdef DEBUG_MMU
+ DPRINTF_MMU("immu data access replaced entry [%i]\n", i);
+ dump_mmu(stdout, fprintf, env);
+#endif
+ return;
+ }
+ case 0x57: /* I-MMU demap */
+ demap_tlb(env->itlb, addr, "immu", env);
+ return;
+ case 0x58: /* D-MMU regs */
+ {
+ int reg = (addr >> 3) & 0xf;
+ uint64_t oldreg;
+
+ oldreg = env->dmmuregs[reg];
+ switch (reg) {
+ case 0: /* RO */
+ case 4:
+ return;
+ case 3: /* SFSR */
+ if ((val & 1) == 0) {
+ val = 0; /* Clear SFSR, Fault address */
+ env->dmmu.sfar = 0;
+ }
+ env->dmmu.sfsr = val;
+ break;
+ case 1: /* Primary context */
+ env->dmmu.mmu_primary_context = val;
+ /* can be optimized to only flush MMU_USER_IDX
+ and MMU_KERNEL_IDX entries */
+ tlb_flush(env, 1);
+ break;
+ case 2: /* Secondary context */
+ env->dmmu.mmu_secondary_context = val;
+ /* can be optimized to only flush MMU_USER_SECONDARY_IDX
+ and MMU_KERNEL_SECONDARY_IDX entries */
+ tlb_flush(env, 1);
+ break;
+ case 5: /* TSB access */
+ DPRINTF_MMU("dmmu TSB write: 0x%016" PRIx64 " -> 0x%016"
+ PRIx64 "\n", env->dmmu.tsb, val);
+ env->dmmu.tsb = val;
+ break;
+ case 6: /* Tag access */
+ env->dmmu.tag_access = val;
+ break;
+ case 7: /* Virtual Watchpoint */
+ case 8: /* Physical Watchpoint */
+ default:
+ env->dmmuregs[reg] = val;
+ break;
+ }
+
+ if (oldreg != env->dmmuregs[reg]) {
+ DPRINTF_MMU("dmmu change reg[%d]: 0x%016" PRIx64 " -> 0x%016"
+ PRIx64 "\n", reg, oldreg, env->dmmuregs[reg]);
+ }
+#ifdef DEBUG_MMU
+ dump_mmu(stdout, fprintf, env);
+#endif
+ return;
+ }
+ case 0x5c: /* D-MMU data in */
+ replace_tlb_1bit_lru(env->dtlb, env->dmmu.tag_access, val, "dmmu", env);
+ return;
+ case 0x5d: /* D-MMU data access */
+ {
+ unsigned int i = (addr >> 3) & 0x3f;
+
+ replace_tlb_entry(&env->dtlb[i], env->dmmu.tag_access, val, env);
+
+#ifdef DEBUG_MMU
+ DPRINTF_MMU("dmmu data access replaced entry [%i]\n", i);
+ dump_mmu(stdout, fprintf, env);
+#endif
+ return;
+ }
+ case 0x5f: /* D-MMU demap */
+ demap_tlb(env->dtlb, addr, "dmmu", env);
+ return;
+ case 0x49: /* Interrupt data receive */
+ /* XXX */
+ return;
+ case 0x46: /* D-cache data */
+ case 0x47: /* D-cache tag access */
+ case 0x4b: /* E-cache error enable */
+ case 0x4c: /* E-cache asynchronous fault status */
+ case 0x4d: /* E-cache asynchronous fault address */
+ case 0x4e: /* E-cache tag data */
+ case 0x66: /* I-cache instruction access */
+ case 0x67: /* I-cache tag access */
+ case 0x6e: /* I-cache predecode */
+ case 0x6f: /* I-cache LRU etc. */
+ case 0x76: /* E-cache tag */
+ case 0x7e: /* E-cache tag */
+ return;
+ case 0x51: /* I-MMU 8k TSB pointer, RO */
+ case 0x52: /* I-MMU 64k TSB pointer, RO */
+ case 0x56: /* I-MMU tag read, RO */
+ case 0x59: /* D-MMU 8k TSB pointer, RO */
+ case 0x5a: /* D-MMU 64k TSB pointer, RO */
+ case 0x5b: /* D-MMU data pointer, RO */
+ case 0x5e: /* D-MMU tag read, RO */
+ case 0x48: /* Interrupt dispatch, RO */
+ case 0x7f: /* Incoming interrupt vector, RO */
+ case 0x82: /* Primary no-fault, RO */
+ case 0x83: /* Secondary no-fault, RO */
+ case 0x8a: /* Primary no-fault LE, RO */
+ case 0x8b: /* Secondary no-fault LE, RO */
+ default:
+ do_unassigned_access(addr, 1, 0, 1, size);
+ return;
+ }
+}
+#endif /* CONFIG_USER_ONLY */
+
+void helper_ldda_asi(target_ulong addr, int asi, int rd)
+{
+ if ((asi < 0x80 && (env->pstate & PS_PRIV) == 0)
+ || (cpu_has_hypervisor(env)
+ && asi >= 0x30 && asi < 0x80
+ && !(env->hpstate & HS_PRIV))) {
+ helper_raise_exception(env, TT_PRIV_ACT);
+ }
+
+ addr = asi_address_mask(env, asi, addr);
+
+ switch (asi) {
+#if !defined(CONFIG_USER_ONLY)
+ case 0x24: /* Nucleus quad LDD 128 bit atomic */
+ case 0x2c: /* Nucleus quad LDD 128 bit atomic LE */
+ helper_check_align(addr, 0xf);
+ if (rd == 0) {
+ env->gregs[1] = ldq_nucleus(addr + 8);
+ if (asi == 0x2c) {
+ bswap64s(&env->gregs[1]);
+ }
+ } else if (rd < 8) {
+ env->gregs[rd] = ldq_nucleus(addr);
+ env->gregs[rd + 1] = ldq_nucleus(addr + 8);
+ if (asi == 0x2c) {
+ bswap64s(&env->gregs[rd]);
+ bswap64s(&env->gregs[rd + 1]);
+ }
+ } else {
+ env->regwptr[rd] = ldq_nucleus(addr);
+ env->regwptr[rd + 1] = ldq_nucleus(addr + 8);
+ if (asi == 0x2c) {
+ bswap64s(&env->regwptr[rd]);
+ bswap64s(&env->regwptr[rd + 1]);
+ }
+ }
+ break;
+#endif
+ default:
+ helper_check_align(addr, 0x3);
+ if (rd == 0) {
+ env->gregs[1] = helper_ld_asi(addr + 4, asi, 4, 0);
+ } else if (rd < 8) {
+ env->gregs[rd] = helper_ld_asi(addr, asi, 4, 0);
+ env->gregs[rd + 1] = helper_ld_asi(addr + 4, asi, 4, 0);
+ } else {
+ env->regwptr[rd] = helper_ld_asi(addr, asi, 4, 0);
+ env->regwptr[rd + 1] = helper_ld_asi(addr + 4, asi, 4, 0);
+ }
+ break;
+ }
+}
+
+void helper_ldf_asi(target_ulong addr, int asi, int size, int rd)
+{
+ unsigned int i;
+ CPU_DoubleU u;
+
+ helper_check_align(addr, 3);
+ addr = asi_address_mask(env, asi, addr);
+
+ switch (asi) {
+ case 0xf0: /* UA2007/JPS1 Block load primary */
+ case 0xf1: /* UA2007/JPS1 Block load secondary */
+ case 0xf8: /* UA2007/JPS1 Block load primary LE */
+ case 0xf9: /* UA2007/JPS1 Block load secondary LE */
+ if (rd & 7) {
+ helper_raise_exception(env, TT_ILL_INSN);
+ return;
+ }
+ helper_check_align(addr, 0x3f);
+ for (i = 0; i < 16; i++) {
+ *(uint32_t *)&env->fpr[rd++] = helper_ld_asi(addr, asi & 0x8f, 4,
+ 0);
+ addr += 4;
+ }
+
+ return;
+ case 0x16: /* UA2007 Block load primary, user privilege */
+ case 0x17: /* UA2007 Block load secondary, user privilege */
+ case 0x1e: /* UA2007 Block load primary LE, user privilege */
+ case 0x1f: /* UA2007 Block load secondary LE, user privilege */
+ case 0x70: /* JPS1 Block load primary, user privilege */
+ case 0x71: /* JPS1 Block load secondary, user privilege */
+ case 0x78: /* JPS1 Block load primary LE, user privilege */
+ case 0x79: /* JPS1 Block load secondary LE, user privilege */
+ if (rd & 7) {
+ helper_raise_exception(env, TT_ILL_INSN);
+ return;
+ }
+ helper_check_align(addr, 0x3f);
+ for (i = 0; i < 16; i++) {
+ *(uint32_t *)&env->fpr[rd++] = helper_ld_asi(addr, asi & 0x19, 4,
+ 0);
+ addr += 4;
+ }
+
+ return;
+ default:
+ break;
+ }
+
+ switch (size) {
+ default:
+ case 4:
+ *((uint32_t *)&env->fpr[rd]) = helper_ld_asi(addr, asi, size, 0);
+ break;
+ case 8:
+ u.ll = helper_ld_asi(addr, asi, size, 0);
+ *((uint32_t *)&env->fpr[rd++]) = u.l.upper;
+ *((uint32_t *)&env->fpr[rd++]) = u.l.lower;
+ break;
+ case 16:
+ u.ll = helper_ld_asi(addr, asi, 8, 0);
+ *((uint32_t *)&env->fpr[rd++]) = u.l.upper;
+ *((uint32_t *)&env->fpr[rd++]) = u.l.lower;
+ u.ll = helper_ld_asi(addr + 8, asi, 8, 0);
+ *((uint32_t *)&env->fpr[rd++]) = u.l.upper;
+ *((uint32_t *)&env->fpr[rd++]) = u.l.lower;
+ break;
+ }
+}
+
+void helper_stf_asi(target_ulong addr, int asi, int size, int rd)
+{
+ unsigned int i;
+ target_ulong val = 0;
+ CPU_DoubleU u;
+
+ helper_check_align(addr, 3);
+ addr = asi_address_mask(env, asi, addr);
+
+ switch (asi) {
+ case 0xe0: /* UA2007/JPS1 Block commit store primary (cache flush) */
+ case 0xe1: /* UA2007/JPS1 Block commit store secondary (cache flush) */
+ case 0xf0: /* UA2007/JPS1 Block store primary */
+ case 0xf1: /* UA2007/JPS1 Block store secondary */
+ case 0xf8: /* UA2007/JPS1 Block store primary LE */
+ case 0xf9: /* UA2007/JPS1 Block store secondary LE */
+ if (rd & 7) {
+ helper_raise_exception(env, TT_ILL_INSN);
+ return;
+ }
+ helper_check_align(addr, 0x3f);
+ for (i = 0; i < 16; i++) {
+ val = *(uint32_t *)&env->fpr[rd++];
+ helper_st_asi(addr, val, asi & 0x8f, 4);
+ addr += 4;
+ }
+
+ return;
+ case 0x16: /* UA2007 Block load primary, user privilege */
+ case 0x17: /* UA2007 Block load secondary, user privilege */
+ case 0x1e: /* UA2007 Block load primary LE, user privilege */
+ case 0x1f: /* UA2007 Block load secondary LE, user privilege */
+ case 0x70: /* JPS1 Block store primary, user privilege */
+ case 0x71: /* JPS1 Block store secondary, user privilege */
+ case 0x78: /* JPS1 Block load primary LE, user privilege */
+ case 0x79: /* JPS1 Block load secondary LE, user privilege */
+ if (rd & 7) {
+ helper_raise_exception(env, TT_ILL_INSN);
+ return;
+ }
+ helper_check_align(addr, 0x3f);
+ for (i = 0; i < 16; i++) {
+ val = *(uint32_t *)&env->fpr[rd++];
+ helper_st_asi(addr, val, asi & 0x19, 4);
+ addr += 4;
+ }
+
+ return;
+ default:
+ break;
+ }
+
+ switch (size) {
+ default:
+ case 4:
+ helper_st_asi(addr, *(uint32_t *)&env->fpr[rd], asi, size);
+ break;
+ case 8:
+ u.l.upper = *(uint32_t *)&env->fpr[rd++];
+ u.l.lower = *(uint32_t *)&env->fpr[rd++];
+ helper_st_asi(addr, u.ll, asi, size);
+ break;
+ case 16:
+ u.l.upper = *(uint32_t *)&env->fpr[rd++];
+ u.l.lower = *(uint32_t *)&env->fpr[rd++];
+ helper_st_asi(addr, u.ll, asi, 8);
+ u.l.upper = *(uint32_t *)&env->fpr[rd++];
+ u.l.lower = *(uint32_t *)&env->fpr[rd++];
+ helper_st_asi(addr + 8, u.ll, asi, 8);
+ break;
+ }
+}
+
+target_ulong helper_cas_asi(target_ulong addr, target_ulong val1,
+ target_ulong val2, uint32_t asi)
+{
+ target_ulong ret;
+
+ val2 &= 0xffffffffUL;
+ ret = helper_ld_asi(addr, asi, 4, 0);
+ ret &= 0xffffffffUL;
+ if (val2 == ret) {
+ helper_st_asi(addr, val1 & 0xffffffffUL, asi, 4);
+ }
+ return ret;
+}
+
+target_ulong helper_casx_asi(target_ulong addr, target_ulong val1,
+ target_ulong val2, uint32_t asi)
+{
+ target_ulong ret;
+
+ ret = helper_ld_asi(addr, asi, 8, 0);
+ if (val2 == ret) {
+ helper_st_asi(addr, val1, asi, 8);
+ }
+ return ret;
+}
+#endif /* TARGET_SPARC64 */
+
+void helper_stdf(target_ulong addr, int mem_idx)
+{
+ helper_check_align(addr, 7);
+#if !defined(CONFIG_USER_ONLY)
+ switch (mem_idx) {
+ case MMU_USER_IDX:
+ stfq_user(addr, DT0);
+ break;
+ case MMU_KERNEL_IDX:
+ stfq_kernel(addr, DT0);
+ break;
+#ifdef TARGET_SPARC64
+ case MMU_HYPV_IDX:
+ stfq_hypv(addr, DT0);
+ break;
+#endif
+ default:
+ DPRINTF_MMU("helper_stdf: need to check MMU idx %d\n", mem_idx);
+ break;
+ }
+#else
+ stfq_raw(address_mask(env, addr), DT0);
+#endif
+}
+
+void helper_lddf(target_ulong addr, int mem_idx)
+{
+ helper_check_align(addr, 7);
+#if !defined(CONFIG_USER_ONLY)
+ switch (mem_idx) {
+ case MMU_USER_IDX:
+ DT0 = ldfq_user(addr);
+ break;
+ case MMU_KERNEL_IDX:
+ DT0 = ldfq_kernel(addr);
+ break;
+#ifdef TARGET_SPARC64
+ case MMU_HYPV_IDX:
+ DT0 = ldfq_hypv(addr);
+ break;
+#endif
+ default:
+ DPRINTF_MMU("helper_lddf: need to check MMU idx %d\n", mem_idx);
+ break;
+ }
+#else
+ DT0 = ldfq_raw(address_mask(env, addr));
+#endif
+}
+
+void helper_ldqf(target_ulong addr, int mem_idx)
+{
+ /* XXX add 128 bit load */
+ CPU_QuadU u;
+
+ helper_check_align(addr, 7);
+#if !defined(CONFIG_USER_ONLY)
+ switch (mem_idx) {
+ case MMU_USER_IDX:
+ u.ll.upper = ldq_user(addr);
+ u.ll.lower = ldq_user(addr + 8);
+ QT0 = u.q;
+ break;
+ case MMU_KERNEL_IDX:
+ u.ll.upper = ldq_kernel(addr);
+ u.ll.lower = ldq_kernel(addr + 8);
+ QT0 = u.q;
+ break;
+#ifdef TARGET_SPARC64
+ case MMU_HYPV_IDX:
+ u.ll.upper = ldq_hypv(addr);
+ u.ll.lower = ldq_hypv(addr + 8);
+ QT0 = u.q;
+ break;
+#endif
+ default:
+ DPRINTF_MMU("helper_ldqf: need to check MMU idx %d\n", mem_idx);
+ break;
+ }
+#else
+ u.ll.upper = ldq_raw(address_mask(env, addr));
+ u.ll.lower = ldq_raw(address_mask(env, addr + 8));
+ QT0 = u.q;
+#endif
+}
+
+void helper_stqf(target_ulong addr, int mem_idx)
+{
+ /* XXX add 128 bit store */
+ CPU_QuadU u;
+
+ helper_check_align(addr, 7);
+#if !defined(CONFIG_USER_ONLY)
+ switch (mem_idx) {
+ case MMU_USER_IDX:
+ u.q = QT0;
+ stq_user(addr, u.ll.upper);
+ stq_user(addr + 8, u.ll.lower);
+ break;
+ case MMU_KERNEL_IDX:
+ u.q = QT0;
+ stq_kernel(addr, u.ll.upper);
+ stq_kernel(addr + 8, u.ll.lower);
+ break;
+#ifdef TARGET_SPARC64
+ case MMU_HYPV_IDX:
+ u.q = QT0;
+ stq_hypv(addr, u.ll.upper);
+ stq_hypv(addr + 8, u.ll.lower);
+ break;
+#endif
+ default:
+ DPRINTF_MMU("helper_stqf: need to check MMU idx %d\n", mem_idx);
+ break;
+ }
+#else
+ u.q = QT0;
+ stq_raw(address_mask(env, addr), u.ll.upper);
+ stq_raw(address_mask(env, addr + 8), u.ll.lower);
+#endif
+}
+
+#ifndef TARGET_SPARC64
+#if !defined(CONFIG_USER_ONLY)
+static void do_unassigned_access(target_phys_addr_t addr, int is_write,
+ int is_exec, int is_asi, int size)
+{
+ int fault_type;
+
+#ifdef DEBUG_UNASSIGNED
+ if (is_asi) {
+ printf("Unassigned mem %s access of %d byte%s to " TARGET_FMT_plx
+ " asi 0x%02x from " TARGET_FMT_lx "\n",
+ is_exec ? "exec" : is_write ? "write" : "read", size,
+ size == 1 ? "" : "s", addr, is_asi, env->pc);
+ } else {
+ printf("Unassigned mem %s access of %d byte%s to " TARGET_FMT_plx
+ " from " TARGET_FMT_lx "\n",
+ is_exec ? "exec" : is_write ? "write" : "read", size,
+ size == 1 ? "" : "s", addr, env->pc);
+ }
+#endif
+ /* Don't overwrite translation and access faults */
+ fault_type = (env->mmuregs[3] & 0x1c) >> 2;
+ if ((fault_type > 4) || (fault_type == 0)) {
+ env->mmuregs[3] = 0; /* Fault status register */
+ if (is_asi) {
+ env->mmuregs[3] |= 1 << 16;
+ }
+ if (env->psrs) {
+ env->mmuregs[3] |= 1 << 5;
+ }
+ if (is_exec) {
+ env->mmuregs[3] |= 1 << 6;
+ }
+ if (is_write) {
+ env->mmuregs[3] |= 1 << 7;
+ }
+ env->mmuregs[3] |= (5 << 2) | 2;
+ /* SuperSPARC will never place instruction fault addresses in the FAR */
+ if (!is_exec) {
+ env->mmuregs[4] = addr; /* Fault address register */
+ }
+ }
+ /* overflow (same type fault was not read before another fault) */
+ if (fault_type == ((env->mmuregs[3] & 0x1c)) >> 2) {
+ env->mmuregs[3] |= 1;
+ }
+
+ if ((env->mmuregs[0] & MMU_E) && !(env->mmuregs[0] & MMU_NF)) {
+ if (is_exec) {
+ helper_raise_exception(env, TT_CODE_ACCESS);
+ } else {
+ helper_raise_exception(env, TT_DATA_ACCESS);
+ }
+ }
+
+ /* flush neverland mappings created during no-fault mode,
+ so the sequential MMU faults report proper fault types */
+ if (env->mmuregs[0] & MMU_NF) {
+ tlb_flush(env, 1);
+ }
+}
+#endif
+#else
+#if defined(CONFIG_USER_ONLY)
+static void do_unassigned_access(target_ulong addr, int is_write, int is_exec,
+ int is_asi, int size)
+#else
+static void do_unassigned_access(target_phys_addr_t addr, int is_write,
+ int is_exec, int is_asi, int size)
+#endif
+{
+#ifdef DEBUG_UNASSIGNED
+ printf("Unassigned mem access to " TARGET_FMT_plx " from " TARGET_FMT_lx
+ "\n", addr, env->pc);
+#endif
+
+ if (is_exec) {
+ helper_raise_exception(env, TT_CODE_ACCESS);
+ } else {
+ helper_raise_exception(env, TT_DATA_ACCESS);
+ }
+}
+#endif
+
+#if !defined(CONFIG_USER_ONLY)
+void cpu_unassigned_access(CPUState *env1, target_phys_addr_t addr,
+ int is_write, int is_exec, int is_asi, int size)
+{
+ CPUState *saved_env;
+
+ saved_env = env;
+ env = env1;
+ do_unassigned_access(addr, is_write, is_exec, is_asi, size);
+ env = saved_env;
+}
+#endif
diff --git a/target-sparc/mmu_helper.c b/target-sparc/mmu_helper.c
new file mode 100644
index 0000000000..8cdc224ae3
--- /dev/null
+++ b/target-sparc/mmu_helper.c
@@ -0,0 +1,853 @@
+/*
+ * Sparc MMU helpers
+ *
+ * Copyright (c) 2003-2005 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cpu.h"
+#include "trace.h"
+
+/* Sparc MMU emulation */
+
+#if defined(CONFIG_USER_ONLY)
+
+int cpu_sparc_handle_mmu_fault(CPUState *env1, target_ulong address, int rw,
+ int mmu_idx)
+{
+ if (rw & 2) {
+ env1->exception_index = TT_TFAULT;
+ } else {
+ env1->exception_index = TT_DFAULT;
+ }
+ return 1;
+}
+
+#else
+
+#ifndef TARGET_SPARC64
+/*
+ * Sparc V8 Reference MMU (SRMMU)
+ */
+static const int access_table[8][8] = {
+ { 0, 0, 0, 0, 8, 0, 12, 12 },
+ { 0, 0, 0, 0, 8, 0, 0, 0 },
+ { 8, 8, 0, 0, 0, 8, 12, 12 },
+ { 8, 8, 0, 0, 0, 8, 0, 0 },
+ { 8, 0, 8, 0, 8, 8, 12, 12 },
+ { 8, 0, 8, 0, 8, 0, 8, 0 },
+ { 8, 8, 8, 0, 8, 8, 12, 12 },
+ { 8, 8, 8, 0, 8, 8, 8, 0 }
+};
+
+static const int perm_table[2][8] = {
+ {
+ PAGE_READ,
+ PAGE_READ | PAGE_WRITE,
+ PAGE_READ | PAGE_EXEC,
+ PAGE_READ | PAGE_WRITE | PAGE_EXEC,
+ PAGE_EXEC,
+ PAGE_READ | PAGE_WRITE,
+ PAGE_READ | PAGE_EXEC,
+ PAGE_READ | PAGE_WRITE | PAGE_EXEC
+ },
+ {
+ PAGE_READ,
+ PAGE_READ | PAGE_WRITE,
+ PAGE_READ | PAGE_EXEC,
+ PAGE_READ | PAGE_WRITE | PAGE_EXEC,
+ PAGE_EXEC,
+ PAGE_READ,
+ 0,
+ 0,
+ }
+};
+
+static int get_physical_address(CPUState *env, target_phys_addr_t *physical,
+ int *prot, int *access_index,
+ target_ulong address, int rw, int mmu_idx,
+ target_ulong *page_size)
+{
+ int access_perms = 0;
+ target_phys_addr_t pde_ptr;
+ uint32_t pde;
+ int error_code = 0, is_dirty, is_user;
+ unsigned long page_offset;
+
+ is_user = mmu_idx == MMU_USER_IDX;
+
+ if ((env->mmuregs[0] & MMU_E) == 0) { /* MMU disabled */
+ *page_size = TARGET_PAGE_SIZE;
+ /* Boot mode: instruction fetches are taken from PROM */
+ if (rw == 2 && (env->mmuregs[0] & env->def->mmu_bm)) {
+ *physical = env->prom_addr | (address & 0x7ffffULL);
+ *prot = PAGE_READ | PAGE_EXEC;
+ return 0;
+ }
+ *physical = address;
+ *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+ return 0;
+ }
+
+ *access_index = ((rw & 1) << 2) | (rw & 2) | (is_user ? 0 : 1);
+ *physical = 0xffffffffffff0000ULL;
+
+ /* SPARC reference MMU table walk: Context table->L1->L2->PTE */
+ /* Context base + context number */
+ pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2);
+ pde = ldl_phys(pde_ptr);
+
+ /* Ctx pde */
+ switch (pde & PTE_ENTRYTYPE_MASK) {
+ default:
+ case 0: /* Invalid */
+ return 1 << 2;
+ case 2: /* L0 PTE, maybe should not happen? */
+ case 3: /* Reserved */
+ return 4 << 2;
+ case 1: /* L0 PDE */
+ pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4);
+ pde = ldl_phys(pde_ptr);
+
+ switch (pde & PTE_ENTRYTYPE_MASK) {
+ default:
+ case 0: /* Invalid */
+ return (1 << 8) | (1 << 2);
+ case 3: /* Reserved */
+ return (1 << 8) | (4 << 2);
+ case 1: /* L1 PDE */
+ pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4);
+ pde = ldl_phys(pde_ptr);
+
+ switch (pde & PTE_ENTRYTYPE_MASK) {
+ default:
+ case 0: /* Invalid */
+ return (2 << 8) | (1 << 2);
+ case 3: /* Reserved */
+ return (2 << 8) | (4 << 2);
+ case 1: /* L2 PDE */
+ pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4);
+ pde = ldl_phys(pde_ptr);
+
+ switch (pde & PTE_ENTRYTYPE_MASK) {
+ default:
+ case 0: /* Invalid */
+ return (3 << 8) | (1 << 2);
+ case 1: /* PDE, should not happen */
+ case 3: /* Reserved */
+ return (3 << 8) | (4 << 2);
+ case 2: /* L3 PTE */
+ page_offset = (address & TARGET_PAGE_MASK) &
+ (TARGET_PAGE_SIZE - 1);
+ }
+ *page_size = TARGET_PAGE_SIZE;
+ break;
+ case 2: /* L2 PTE */
+ page_offset = address & 0x3ffff;
+ *page_size = 0x40000;
+ }
+ break;
+ case 2: /* L1 PTE */
+ page_offset = address & 0xffffff;
+ *page_size = 0x1000000;
+ }
+ }
+
+ /* check access */
+ access_perms = (pde & PTE_ACCESS_MASK) >> PTE_ACCESS_SHIFT;
+ error_code = access_table[*access_index][access_perms];
+ if (error_code && !((env->mmuregs[0] & MMU_NF) && is_user)) {
+ return error_code;
+ }
+
+ /* update page modified and dirty bits */
+ is_dirty = (rw & 1) && !(pde & PG_MODIFIED_MASK);
+ if (!(pde & PG_ACCESSED_MASK) || is_dirty) {
+ pde |= PG_ACCESSED_MASK;
+ if (is_dirty) {
+ pde |= PG_MODIFIED_MASK;
+ }
+ stl_phys_notdirty(pde_ptr, pde);
+ }
+
+ /* the page can be put in the TLB */
+ *prot = perm_table[is_user][access_perms];
+ if (!(pde & PG_MODIFIED_MASK)) {
+ /* only set write access if already dirty... otherwise wait
+ for dirty access */
+ *prot &= ~PAGE_WRITE;
+ }
+
+ /* Even if large ptes, we map only one 4KB page in the cache to
+ avoid filling it too fast */
+ *physical = ((target_phys_addr_t)(pde & PTE_ADDR_MASK) << 4) + page_offset;
+ return error_code;
+}
+
+/* Perform address translation */
+int cpu_sparc_handle_mmu_fault(CPUState *env, target_ulong address, int rw,
+ int mmu_idx)
+{
+ target_phys_addr_t paddr;
+ target_ulong vaddr;
+ target_ulong page_size;
+ int error_code = 0, prot, access_index;
+
+ error_code = get_physical_address(env, &paddr, &prot, &access_index,
+ address, rw, mmu_idx, &page_size);
+ if (error_code == 0) {
+ vaddr = address & TARGET_PAGE_MASK;
+ paddr &= TARGET_PAGE_MASK;
+#ifdef DEBUG_MMU
+ printf("Translate at " TARGET_FMT_lx " -> " TARGET_FMT_plx ", vaddr "
+ TARGET_FMT_lx "\n", address, paddr, vaddr);
+#endif
+ tlb_set_page(env, vaddr, paddr, prot, mmu_idx, page_size);
+ return 0;
+ }
+
+ if (env->mmuregs[3]) { /* Fault status register */
+ env->mmuregs[3] = 1; /* overflow (not read before another fault) */
+ }
+ env->mmuregs[3] |= (access_index << 5) | error_code | 2;
+ env->mmuregs[4] = address; /* Fault address register */
+
+ if ((env->mmuregs[0] & MMU_NF) || env->psret == 0) {
+ /* No fault mode: if a mapping is available, just override
+ permissions. If no mapping is available, redirect accesses to
+ neverland. Fake/overridden mappings will be flushed when
+ switching to normal mode. */
+ vaddr = address & TARGET_PAGE_MASK;
+ prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+ tlb_set_page(env, vaddr, paddr, prot, mmu_idx, TARGET_PAGE_SIZE);
+ return 0;
+ } else {
+ if (rw & 2) {
+ env->exception_index = TT_TFAULT;
+ } else {
+ env->exception_index = TT_DFAULT;
+ }
+ return 1;
+ }
+}
+
+target_ulong mmu_probe(CPUState *env, target_ulong address, int mmulev)
+{
+ target_phys_addr_t pde_ptr;
+ uint32_t pde;
+
+ /* Context base + context number */
+ pde_ptr = (target_phys_addr_t)(env->mmuregs[1] << 4) +
+ (env->mmuregs[2] << 2);
+ pde = ldl_phys(pde_ptr);
+
+ switch (pde & PTE_ENTRYTYPE_MASK) {
+ default:
+ case 0: /* Invalid */
+ case 2: /* PTE, maybe should not happen? */
+ case 3: /* Reserved */
+ return 0;
+ case 1: /* L1 PDE */
+ if (mmulev == 3) {
+ return pde;
+ }
+ pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4);
+ pde = ldl_phys(pde_ptr);
+
+ switch (pde & PTE_ENTRYTYPE_MASK) {
+ default:
+ case 0: /* Invalid */
+ case 3: /* Reserved */
+ return 0;
+ case 2: /* L1 PTE */
+ return pde;
+ case 1: /* L2 PDE */
+ if (mmulev == 2) {
+ return pde;
+ }
+ pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4);
+ pde = ldl_phys(pde_ptr);
+
+ switch (pde & PTE_ENTRYTYPE_MASK) {
+ default:
+ case 0: /* Invalid */
+ case 3: /* Reserved */
+ return 0;
+ case 2: /* L2 PTE */
+ return pde;
+ case 1: /* L3 PDE */
+ if (mmulev == 1) {
+ return pde;
+ }
+ pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4);
+ pde = ldl_phys(pde_ptr);
+
+ switch (pde & PTE_ENTRYTYPE_MASK) {
+ default:
+ case 0: /* Invalid */
+ case 1: /* PDE, should not happen */
+ case 3: /* Reserved */
+ return 0;
+ case 2: /* L3 PTE */
+ return pde;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env)
+{
+ target_ulong va, va1, va2;
+ unsigned int n, m, o;
+ target_phys_addr_t pde_ptr, pa;
+ uint32_t pde;
+
+ pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2);
+ pde = ldl_phys(pde_ptr);
+ (*cpu_fprintf)(f, "Root ptr: " TARGET_FMT_plx ", ctx: %d\n",
+ (target_phys_addr_t)env->mmuregs[1] << 4, env->mmuregs[2]);
+ for (n = 0, va = 0; n < 256; n++, va += 16 * 1024 * 1024) {
+ pde = mmu_probe(env, va, 2);
+ if (pde) {
+ pa = cpu_get_phys_page_debug(env, va);
+ (*cpu_fprintf)(f, "VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_plx
+ " PDE: " TARGET_FMT_lx "\n", va, pa, pde);
+ for (m = 0, va1 = va; m < 64; m++, va1 += 256 * 1024) {
+ pde = mmu_probe(env, va1, 1);
+ if (pde) {
+ pa = cpu_get_phys_page_debug(env, va1);
+ (*cpu_fprintf)(f, " VA: " TARGET_FMT_lx ", PA: "
+ TARGET_FMT_plx " PDE: " TARGET_FMT_lx "\n",
+ va1, pa, pde);
+ for (o = 0, va2 = va1; o < 64; o++, va2 += 4 * 1024) {
+ pde = mmu_probe(env, va2, 0);
+ if (pde) {
+ pa = cpu_get_phys_page_debug(env, va2);
+ (*cpu_fprintf)(f, " VA: " TARGET_FMT_lx ", PA: "
+ TARGET_FMT_plx " PTE: "
+ TARGET_FMT_lx "\n",
+ va2, pa, pde);
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+/* Gdb expects all registers windows to be flushed in ram. This function handles
+ * reads (and only reads) in stack frames as if windows were flushed. We assume
+ * that the sparc ABI is followed.
+ */
+int target_memory_rw_debug(CPUState *env, target_ulong addr,
+ uint8_t *buf, int len, int is_write)
+{
+ int i;
+ int len1;
+ int cwp = env->cwp;
+
+ if (!is_write) {
+ for (i = 0; i < env->nwindows; i++) {
+ int off;
+ target_ulong fp = env->regbase[cwp * 16 + 22];
+
+ /* Assume fp == 0 means end of frame. */
+ if (fp == 0) {
+ break;
+ }
+
+ cwp = cpu_cwp_inc(env, cwp + 1);
+
+ /* Invalid window ? */
+ if (env->wim & (1 << cwp)) {
+ break;
+ }
+
+ /* According to the ABI, the stack is growing downward. */
+ if (addr + len < fp) {
+ break;
+ }
+
+ /* Not in this frame. */
+ if (addr > fp + 64) {
+ continue;
+ }
+
+ /* Handle access before this window. */
+ if (addr < fp) {
+ len1 = fp - addr;
+ if (cpu_memory_rw_debug(env, addr, buf, len1, is_write) != 0) {
+ return -1;
+ }
+ addr += len1;
+ len -= len1;
+ buf += len1;
+ }
+
+ /* Access byte per byte to registers. Not very efficient but speed
+ * is not critical.
+ */
+ off = addr - fp;
+ len1 = 64 - off;
+
+ if (len1 > len) {
+ len1 = len;
+ }
+
+ for (; len1; len1--) {
+ int reg = cwp * 16 + 8 + (off >> 2);
+ union {
+ uint32_t v;
+ uint8_t c[4];
+ } u;
+ u.v = cpu_to_be32(env->regbase[reg]);
+ *buf++ = u.c[off & 3];
+ addr++;
+ len--;
+ off++;
+ }
+
+ if (len == 0) {
+ return 0;
+ }
+ }
+ }
+ return cpu_memory_rw_debug(env, addr, buf, len, is_write);
+}
+
+#else /* !TARGET_SPARC64 */
+
+/* 41 bit physical address space */
+static inline target_phys_addr_t ultrasparc_truncate_physical(uint64_t x)
+{
+ return x & 0x1ffffffffffULL;
+}
+
+/*
+ * UltraSparc IIi I/DMMUs
+ */
+
+/* Returns true if TTE tag is valid and matches virtual address value
+ in context requires virtual address mask value calculated from TTE
+ entry size */
+static inline int ultrasparc_tag_match(SparcTLBEntry *tlb,
+ uint64_t address, uint64_t context,
+ target_phys_addr_t *physical)
+{
+ uint64_t mask;
+
+ switch (TTE_PGSIZE(tlb->tte)) {
+ default:
+ case 0x0: /* 8k */
+ mask = 0xffffffffffffe000ULL;
+ break;
+ case 0x1: /* 64k */
+ mask = 0xffffffffffff0000ULL;
+ break;
+ case 0x2: /* 512k */
+ mask = 0xfffffffffff80000ULL;
+ break;
+ case 0x3: /* 4M */
+ mask = 0xffffffffffc00000ULL;
+ break;
+ }
+
+ /* valid, context match, virtual address match? */
+ if (TTE_IS_VALID(tlb->tte) &&
+ (TTE_IS_GLOBAL(tlb->tte) || tlb_compare_context(tlb, context))
+ && compare_masked(address, tlb->tag, mask)) {
+ /* decode physical address */
+ *physical = ((tlb->tte & mask) | (address & ~mask)) & 0x1ffffffe000ULL;
+ return 1;
+ }
+
+ return 0;
+}
+
+static int get_physical_address_data(CPUState *env,
+ target_phys_addr_t *physical, int *prot,
+ target_ulong address, int rw, int mmu_idx)
+{
+ unsigned int i;
+ uint64_t context;
+ uint64_t sfsr = 0;
+
+ int is_user = (mmu_idx == MMU_USER_IDX ||
+ mmu_idx == MMU_USER_SECONDARY_IDX);
+
+ if ((env->lsu & DMMU_E) == 0) { /* DMMU disabled */
+ *physical = ultrasparc_truncate_physical(address);
+ *prot = PAGE_READ | PAGE_WRITE;
+ return 0;
+ }
+
+ switch (mmu_idx) {
+ case MMU_USER_IDX:
+ case MMU_KERNEL_IDX:
+ context = env->dmmu.mmu_primary_context & 0x1fff;
+ sfsr |= SFSR_CT_PRIMARY;
+ break;
+ case MMU_USER_SECONDARY_IDX:
+ case MMU_KERNEL_SECONDARY_IDX:
+ context = env->dmmu.mmu_secondary_context & 0x1fff;
+ sfsr |= SFSR_CT_SECONDARY;
+ break;
+ case MMU_NUCLEUS_IDX:
+ sfsr |= SFSR_CT_NUCLEUS;
+ /* FALLTHRU */
+ default:
+ context = 0;
+ break;
+ }
+
+ if (rw == 1) {
+ sfsr |= SFSR_WRITE_BIT;
+ } else if (rw == 4) {
+ sfsr |= SFSR_NF_BIT;
+ }
+
+ for (i = 0; i < 64; i++) {
+ /* ctx match, vaddr match, valid? */
+ if (ultrasparc_tag_match(&env->dtlb[i], address, context, physical)) {
+ int do_fault = 0;
+
+ /* access ok? */
+ /* multiple bits in SFSR.FT may be set on TT_DFAULT */
+ if (TTE_IS_PRIV(env->dtlb[i].tte) && is_user) {
+ do_fault = 1;
+ sfsr |= SFSR_FT_PRIV_BIT; /* privilege violation */
+ trace_mmu_helper_dfault(address, context, mmu_idx, env->tl);
+ }
+ if (rw == 4) {
+ if (TTE_IS_SIDEEFFECT(env->dtlb[i].tte)) {
+ do_fault = 1;
+ sfsr |= SFSR_FT_NF_E_BIT;
+ }
+ } else {
+ if (TTE_IS_NFO(env->dtlb[i].tte)) {
+ do_fault = 1;
+ sfsr |= SFSR_FT_NFO_BIT;
+ }
+ }
+
+ if (do_fault) {
+ /* faults above are reported with TT_DFAULT. */
+ env->exception_index = TT_DFAULT;
+ } else if (!TTE_IS_W_OK(env->dtlb[i].tte) && (rw == 1)) {
+ do_fault = 1;
+ env->exception_index = TT_DPROT;
+
+ trace_mmu_helper_dprot(address, context, mmu_idx, env->tl);
+ }
+
+ if (!do_fault) {
+ *prot = PAGE_READ;
+ if (TTE_IS_W_OK(env->dtlb[i].tte)) {
+ *prot |= PAGE_WRITE;
+ }
+
+ TTE_SET_USED(env->dtlb[i].tte);
+
+ return 0;
+ }
+
+ if (env->dmmu.sfsr & SFSR_VALID_BIT) { /* Fault status register */
+ sfsr |= SFSR_OW_BIT; /* overflow (not read before
+ another fault) */
+ }
+
+ if (env->pstate & PS_PRIV) {
+ sfsr |= SFSR_PR_BIT;
+ }
+
+ /* FIXME: ASI field in SFSR must be set */
+ env->dmmu.sfsr = sfsr | SFSR_VALID_BIT;
+
+ env->dmmu.sfar = address; /* Fault address register */
+
+ env->dmmu.tag_access = (address & ~0x1fffULL) | context;
+
+ return 1;
+ }
+ }
+
+ trace_mmu_helper_dmiss(address, context);
+
+ /*
+ * On MMU misses:
+ * - UltraSPARC IIi: SFSR and SFAR unmodified
+ * - JPS1: SFAR updated and some fields of SFSR updated
+ */
+ env->dmmu.tag_access = (address & ~0x1fffULL) | context;
+ env->exception_index = TT_DMISS;
+ return 1;
+}
+
+static int get_physical_address_code(CPUState *env,
+ target_phys_addr_t *physical, int *prot,
+ target_ulong address, int mmu_idx)
+{
+ unsigned int i;
+ uint64_t context;
+
+ int is_user = (mmu_idx == MMU_USER_IDX ||
+ mmu_idx == MMU_USER_SECONDARY_IDX);
+
+ if ((env->lsu & IMMU_E) == 0 || (env->pstate & PS_RED) != 0) {
+ /* IMMU disabled */
+ *physical = ultrasparc_truncate_physical(address);
+ *prot = PAGE_EXEC;
+ return 0;
+ }
+
+ if (env->tl == 0) {
+ /* PRIMARY context */
+ context = env->dmmu.mmu_primary_context & 0x1fff;
+ } else {
+ /* NUCLEUS context */
+ context = 0;
+ }
+
+ for (i = 0; i < 64; i++) {
+ /* ctx match, vaddr match, valid? */
+ if (ultrasparc_tag_match(&env->itlb[i],
+ address, context, physical)) {
+ /* access ok? */
+ if (TTE_IS_PRIV(env->itlb[i].tte) && is_user) {
+ /* Fault status register */
+ if (env->immu.sfsr & SFSR_VALID_BIT) {
+ env->immu.sfsr = SFSR_OW_BIT; /* overflow (not read before
+ another fault) */
+ } else {
+ env->immu.sfsr = 0;
+ }
+ if (env->pstate & PS_PRIV) {
+ env->immu.sfsr |= SFSR_PR_BIT;
+ }
+ if (env->tl > 0) {
+ env->immu.sfsr |= SFSR_CT_NUCLEUS;
+ }
+
+ /* FIXME: ASI field in SFSR must be set */
+ env->immu.sfsr |= SFSR_FT_PRIV_BIT | SFSR_VALID_BIT;
+ env->exception_index = TT_TFAULT;
+
+ env->immu.tag_access = (address & ~0x1fffULL) | context;
+
+ trace_mmu_helper_tfault(address, context);
+
+ return 1;
+ }
+ *prot = PAGE_EXEC;
+ TTE_SET_USED(env->itlb[i].tte);
+ return 0;
+ }
+ }
+
+ trace_mmu_helper_tmiss(address, context);
+
+ /* Context is stored in DMMU (dmmuregs[1]) also for IMMU */
+ env->immu.tag_access = (address & ~0x1fffULL) | context;
+ env->exception_index = TT_TMISS;
+ return 1;
+}
+
+static int get_physical_address(CPUState *env, target_phys_addr_t *physical,
+ int *prot, int *access_index,
+ target_ulong address, int rw, int mmu_idx,
+ target_ulong *page_size)
+{
+ /* ??? We treat everything as a small page, then explicitly flush
+ everything when an entry is evicted. */
+ *page_size = TARGET_PAGE_SIZE;
+
+ /* safety net to catch wrong softmmu index use from dynamic code */
+ if (env->tl > 0 && mmu_idx != MMU_NUCLEUS_IDX) {
+ if (rw == 2) {
+ trace_mmu_helper_get_phys_addr_code(env->tl, mmu_idx,
+ env->dmmu.mmu_primary_context,
+ env->dmmu.mmu_secondary_context,
+ address);
+ } else {
+ trace_mmu_helper_get_phys_addr_data(env->tl, mmu_idx,
+ env->dmmu.mmu_primary_context,
+ env->dmmu.mmu_secondary_context,
+ address);
+ }
+ }
+
+ if (rw == 2) {
+ return get_physical_address_code(env, physical, prot, address,
+ mmu_idx);
+ } else {
+ return get_physical_address_data(env, physical, prot, address, rw,
+ mmu_idx);
+ }
+}
+
+/* Perform address translation */
+int cpu_sparc_handle_mmu_fault(CPUState *env, target_ulong address, int rw,
+ int mmu_idx)
+{
+ target_ulong virt_addr, vaddr;
+ target_phys_addr_t paddr;
+ target_ulong page_size;
+ int error_code = 0, prot, access_index;
+
+ error_code = get_physical_address(env, &paddr, &prot, &access_index,
+ address, rw, mmu_idx, &page_size);
+ if (error_code == 0) {
+ virt_addr = address & TARGET_PAGE_MASK;
+ vaddr = virt_addr + ((address & TARGET_PAGE_MASK) &
+ (TARGET_PAGE_SIZE - 1));
+
+ trace_mmu_helper_mmu_fault(address, paddr, mmu_idx, env->tl,
+ env->dmmu.mmu_primary_context,
+ env->dmmu.mmu_secondary_context);
+
+ tlb_set_page(env, vaddr, paddr, prot, mmu_idx, page_size);
+ return 0;
+ }
+ /* XXX */
+ return 1;
+}
+
+void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env)
+{
+ unsigned int i;
+ const char *mask;
+
+ (*cpu_fprintf)(f, "MMU contexts: Primary: %" PRId64 ", Secondary: %"
+ PRId64 "\n",
+ env->dmmu.mmu_primary_context,
+ env->dmmu.mmu_secondary_context);
+ if ((env->lsu & DMMU_E) == 0) {
+ (*cpu_fprintf)(f, "DMMU disabled\n");
+ } else {
+ (*cpu_fprintf)(f, "DMMU dump\n");
+ for (i = 0; i < 64; i++) {
+ switch (TTE_PGSIZE(env->dtlb[i].tte)) {
+ default:
+ case 0x0:
+ mask = " 8k";
+ break;
+ case 0x1:
+ mask = " 64k";
+ break;
+ case 0x2:
+ mask = "512k";
+ break;
+ case 0x3:
+ mask = " 4M";
+ break;
+ }
+ if (TTE_IS_VALID(env->dtlb[i].tte)) {
+ (*cpu_fprintf)(f, "[%02u] VA: %" PRIx64 ", PA: %llx"
+ ", %s, %s, %s, %s, ctx %" PRId64 " %s\n",
+ i,
+ env->dtlb[i].tag & (uint64_t)~0x1fffULL,
+ TTE_PA(env->dtlb[i].tte),
+ mask,
+ TTE_IS_PRIV(env->dtlb[i].tte) ? "priv" : "user",
+ TTE_IS_W_OK(env->dtlb[i].tte) ? "RW" : "RO",
+ TTE_IS_LOCKED(env->dtlb[i].tte) ?
+ "locked" : "unlocked",
+ env->dtlb[i].tag & (uint64_t)0x1fffULL,
+ TTE_IS_GLOBAL(env->dtlb[i].tte) ?
+ "global" : "local");
+ }
+ }
+ }
+ if ((env->lsu & IMMU_E) == 0) {
+ (*cpu_fprintf)(f, "IMMU disabled\n");
+ } else {
+ (*cpu_fprintf)(f, "IMMU dump\n");
+ for (i = 0; i < 64; i++) {
+ switch (TTE_PGSIZE(env->itlb[i].tte)) {
+ default:
+ case 0x0:
+ mask = " 8k";
+ break;
+ case 0x1:
+ mask = " 64k";
+ break;
+ case 0x2:
+ mask = "512k";
+ break;
+ case 0x3:
+ mask = " 4M";
+ break;
+ }
+ if (TTE_IS_VALID(env->itlb[i].tte)) {
+ (*cpu_fprintf)(f, "[%02u] VA: %" PRIx64 ", PA: %llx"
+ ", %s, %s, %s, ctx %" PRId64 " %s\n",
+ i,
+ env->itlb[i].tag & (uint64_t)~0x1fffULL,
+ TTE_PA(env->itlb[i].tte),
+ mask,
+ TTE_IS_PRIV(env->itlb[i].tte) ? "priv" : "user",
+ TTE_IS_LOCKED(env->itlb[i].tte) ?
+ "locked" : "unlocked",
+ env->itlb[i].tag & (uint64_t)0x1fffULL,
+ TTE_IS_GLOBAL(env->itlb[i].tte) ?
+ "global" : "local");
+ }
+ }
+ }
+}
+
+#endif /* TARGET_SPARC64 */
+
+static int cpu_sparc_get_phys_page(CPUState *env, target_phys_addr_t *phys,
+ target_ulong addr, int rw, int mmu_idx)
+{
+ target_ulong page_size;
+ int prot, access_index;
+
+ return get_physical_address(env, phys, &prot, &access_index, addr, rw,
+ mmu_idx, &page_size);
+}
+
+#if defined(TARGET_SPARC64)
+target_phys_addr_t cpu_get_phys_page_nofault(CPUState *env, target_ulong addr,
+ int mmu_idx)
+{
+ target_phys_addr_t phys_addr;
+
+ if (cpu_sparc_get_phys_page(env, &phys_addr, addr, 4, mmu_idx) != 0) {
+ return -1;
+ }
+ return phys_addr;
+}
+#endif
+
+target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
+{
+ target_phys_addr_t phys_addr;
+ int mmu_idx = cpu_mmu_index(env);
+
+ if (cpu_sparc_get_phys_page(env, &phys_addr, addr, 2, mmu_idx) != 0) {
+ if (cpu_sparc_get_phys_page(env, &phys_addr, addr, 0, mmu_idx) != 0) {
+ return -1;
+ }
+ }
+ if (cpu_get_physical_page_desc(phys_addr) == IO_MEM_UNASSIGNED) {
+ return -1;
+ }
+ return phys_addr;
+}
+#endif
diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c
index 1cb0636c30..02b660ddf9 100644
--- a/target-sparc/op_helper.c
+++ b/target-sparc/op_helper.c
@@ -1,4179 +1,8 @@
#include "cpu.h"
#include "dyngen-exec.h"
-#include "host-utils.h"
#include "helper.h"
-#include "sysemu.h"
#if !defined(CONFIG_USER_ONLY)
-#include "softmmu_exec.h"
-#endif
-
-//#define DEBUG_MMU
-//#define DEBUG_MXCC
-//#define DEBUG_UNALIGNED
-//#define DEBUG_UNASSIGNED
-//#define DEBUG_ASI
-//#define DEBUG_PCALL
-//#define DEBUG_PSTATE
-//#define DEBUG_CACHE_CONTROL
-
-#ifdef DEBUG_MMU
-#define DPRINTF_MMU(fmt, ...) \
- do { printf("MMU: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF_MMU(fmt, ...) do {} while (0)
-#endif
-
-#ifdef DEBUG_MXCC
-#define DPRINTF_MXCC(fmt, ...) \
- do { printf("MXCC: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF_MXCC(fmt, ...) do {} while (0)
-#endif
-
-#ifdef DEBUG_ASI
-#define DPRINTF_ASI(fmt, ...) \
- do { printf("ASI: " fmt , ## __VA_ARGS__); } while (0)
-#endif
-
-#ifdef DEBUG_PSTATE
-#define DPRINTF_PSTATE(fmt, ...) \
- do { printf("PSTATE: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF_PSTATE(fmt, ...) do {} while (0)
-#endif
-
-#ifdef DEBUG_CACHE_CONTROL
-#define DPRINTF_CACHE_CONTROL(fmt, ...) \
- do { printf("CACHE_CONTROL: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF_CACHE_CONTROL(fmt, ...) do {} while (0)
-#endif
-
-#ifdef TARGET_SPARC64
-#ifndef TARGET_ABI32
-#define AM_CHECK(env1) ((env1)->pstate & PS_AM)
-#else
-#define AM_CHECK(env1) (1)
-#endif
-#endif
-
-#define DT0 (env->dt0)
-#define DT1 (env->dt1)
-#define QT0 (env->qt0)
-#define QT1 (env->qt1)
-
-/* Leon3 cache control */
-
-/* Cache control: emulate the behavior of cache control registers but without
- any effect on the emulated */
-
-#define CACHE_STATE_MASK 0x3
-#define CACHE_DISABLED 0x0
-#define CACHE_FROZEN 0x1
-#define CACHE_ENABLED 0x3
-
-/* Cache Control register fields */
-
-#define CACHE_CTRL_IF (1 << 4) /* Instruction Cache Freeze on Interrupt */
-#define CACHE_CTRL_DF (1 << 5) /* Data Cache Freeze on Interrupt */
-#define CACHE_CTRL_DP (1 << 14) /* Data cache flush pending */
-#define CACHE_CTRL_IP (1 << 15) /* Instruction cache flush pending */
-#define CACHE_CTRL_IB (1 << 16) /* Instruction burst fetch */
-#define CACHE_CTRL_FI (1 << 21) /* Flush Instruction cache (Write only) */
-#define CACHE_CTRL_FD (1 << 22) /* Flush Data cache (Write only) */
-#define CACHE_CTRL_DS (1 << 23) /* Data cache snoop enable */
-
-#if !defined(CONFIG_USER_ONLY)
-static void do_unassigned_access(target_phys_addr_t addr, int is_write,
- int is_exec, int is_asi, int size);
-#else
-#ifdef TARGET_SPARC64
-static void do_unassigned_access(target_ulong addr, int is_write, int is_exec,
- int is_asi, int size);
-#endif
-#endif
-
-#if defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY)
-// Calculates TSB pointer value for fault page size 8k or 64k
-static uint64_t ultrasparc_tsb_pointer(uint64_t tsb_register,
- uint64_t tag_access_register,
- int page_size)
-{
- uint64_t tsb_base = tsb_register & ~0x1fffULL;
- int tsb_split = (tsb_register & 0x1000ULL) ? 1 : 0;
- int tsb_size = tsb_register & 0xf;
-
- // discard lower 13 bits which hold tag access context
- uint64_t tag_access_va = tag_access_register & ~0x1fffULL;
-
- // now reorder bits
- uint64_t tsb_base_mask = ~0x1fffULL;
- uint64_t va = tag_access_va;
-
- // move va bits to correct position
- if (page_size == 8*1024) {
- va >>= 9;
- } else if (page_size == 64*1024) {
- va >>= 12;
- }
-
- if (tsb_size) {
- tsb_base_mask <<= tsb_size;
- }
-
- // calculate tsb_base mask and adjust va if split is in use
- if (tsb_split) {
- if (page_size == 8*1024) {
- va &= ~(1ULL << (13 + tsb_size));
- } else if (page_size == 64*1024) {
- va |= (1ULL << (13 + tsb_size));
- }
- tsb_base_mask <<= 1;
- }
-
- return ((tsb_base & tsb_base_mask) | (va & ~tsb_base_mask)) & ~0xfULL;
-}
-
-// Calculates tag target register value by reordering bits
-// in tag access register
-static uint64_t ultrasparc_tag_target(uint64_t tag_access_register)
-{
- return ((tag_access_register & 0x1fff) << 48) | (tag_access_register >> 22);
-}
-
-static void replace_tlb_entry(SparcTLBEntry *tlb,
- uint64_t tlb_tag, uint64_t tlb_tte,
- CPUState *env1)
-{
- target_ulong mask, size, va, offset;
-
- // flush page range if translation is valid
- if (TTE_IS_VALID(tlb->tte)) {
-
- mask = 0xffffffffffffe000ULL;
- mask <<= 3 * ((tlb->tte >> 61) & 3);
- size = ~mask + 1;
-
- va = tlb->tag & mask;
-
- for (offset = 0; offset < size; offset += TARGET_PAGE_SIZE) {
- tlb_flush_page(env1, va + offset);
- }
- }
-
- tlb->tag = tlb_tag;
- tlb->tte = tlb_tte;
-}
-
-static void demap_tlb(SparcTLBEntry *tlb, target_ulong demap_addr,
- const char* strmmu, CPUState *env1)
-{
- unsigned int i;
- target_ulong mask;
- uint64_t context;
-
- int is_demap_context = (demap_addr >> 6) & 1;
-
- // demap context
- switch ((demap_addr >> 4) & 3) {
- case 0: // primary
- context = env1->dmmu.mmu_primary_context;
- break;
- case 1: // secondary
- context = env1->dmmu.mmu_secondary_context;
- break;
- case 2: // nucleus
- context = 0;
- break;
- case 3: // reserved
- default:
- return;
- }
-
- for (i = 0; i < 64; i++) {
- if (TTE_IS_VALID(tlb[i].tte)) {
-
- if (is_demap_context) {
- // will remove non-global entries matching context value
- if (TTE_IS_GLOBAL(tlb[i].tte) ||
- !tlb_compare_context(&tlb[i], context)) {
- continue;
- }
- } else {
- // demap page
- // will remove any entry matching VA
- mask = 0xffffffffffffe000ULL;
- mask <<= 3 * ((tlb[i].tte >> 61) & 3);
-
- if (!compare_masked(demap_addr, tlb[i].tag, mask)) {
- continue;
- }
-
- // entry should be global or matching context value
- if (!TTE_IS_GLOBAL(tlb[i].tte) &&
- !tlb_compare_context(&tlb[i], context)) {
- continue;
- }
- }
-
- replace_tlb_entry(&tlb[i], 0, 0, env1);
-#ifdef DEBUG_MMU
- DPRINTF_MMU("%s demap invalidated entry [%02u]\n", strmmu, i);
- dump_mmu(stdout, fprintf, env1);
-#endif
- }
- }
-}
-
-static void replace_tlb_1bit_lru(SparcTLBEntry *tlb,
- uint64_t tlb_tag, uint64_t tlb_tte,
- const char* strmmu, CPUState *env1)
-{
- unsigned int i, replace_used;
-
- // Try replacing invalid entry
- for (i = 0; i < 64; i++) {
- if (!TTE_IS_VALID(tlb[i].tte)) {
- replace_tlb_entry(&tlb[i], tlb_tag, tlb_tte, env1);
-#ifdef DEBUG_MMU
- DPRINTF_MMU("%s lru replaced invalid entry [%i]\n", strmmu, i);
- dump_mmu(stdout, fprintf, env1);
-#endif
- return;
- }
- }
-
- // All entries are valid, try replacing unlocked entry
-
- for (replace_used = 0; replace_used < 2; ++replace_used) {
-
- // Used entries are not replaced on first pass
-
- for (i = 0; i < 64; i++) {
- if (!TTE_IS_LOCKED(tlb[i].tte) && !TTE_IS_USED(tlb[i].tte)) {
-
- replace_tlb_entry(&tlb[i], tlb_tag, tlb_tte, env1);
-#ifdef DEBUG_MMU
- DPRINTF_MMU("%s lru replaced unlocked %s entry [%i]\n",
- strmmu, (replace_used?"used":"unused"), i);
- dump_mmu(stdout, fprintf, env1);
-#endif
- return;
- }
- }
-
- // Now reset used bit and search for unused entries again
-
- for (i = 0; i < 64; i++) {
- TTE_SET_UNUSED(tlb[i].tte);
- }
- }
-
-#ifdef DEBUG_MMU
- DPRINTF_MMU("%s lru replacement failed: no entries available\n", strmmu);
-#endif
- // error state?
-}
-
-#endif
-
-static inline target_ulong address_mask(CPUState *env1, target_ulong addr)
-{
-#ifdef TARGET_SPARC64
- if (AM_CHECK(env1))
- addr &= 0xffffffffULL;
-#endif
- return addr;
-}
-
-/* returns true if access using this ASI is to have address translated by MMU
- otherwise access is to raw physical address */
-static inline int is_translating_asi(int asi)
-{
-#ifdef TARGET_SPARC64
- /* Ultrasparc IIi translating asi
- - note this list is defined by cpu implementation
- */
- switch (asi) {
- case 0x04 ... 0x11:
- case 0x16 ... 0x19:
- case 0x1E ... 0x1F:
- case 0x24 ... 0x2C:
- case 0x70 ... 0x73:
- case 0x78 ... 0x79:
- case 0x80 ... 0xFF:
- return 1;
-
- default:
- return 0;
- }
-#else
- /* TODO: check sparc32 bits */
- return 0;
-#endif
-}
-
-static inline target_ulong asi_address_mask(CPUState *env1,
- int asi, target_ulong addr)
-{
- if (is_translating_asi(asi)) {
- return address_mask(env, addr);
- } else {
- return addr;
- }
-}
-
-static void raise_exception(int tt)
-{
- env->exception_index = tt;
- cpu_loop_exit(env);
-}
-
-void HELPER(raise_exception)(int tt)
-{
- raise_exception(tt);
-}
-
-void helper_shutdown(void)
-{
-#if !defined(CONFIG_USER_ONLY)
- qemu_system_shutdown_request();
-#endif
-}
-
-void helper_check_align(target_ulong addr, uint32_t align)
-{
- if (addr & align) {
-#ifdef DEBUG_UNALIGNED
- printf("Unaligned access to 0x" TARGET_FMT_lx " from 0x" TARGET_FMT_lx
- "\n", addr, env->pc);
-#endif
- raise_exception(TT_UNALIGNED);
- }
-}
-
-#define F_HELPER(name, p) void helper_f##name##p(void)
-
-#define F_BINOP(name) \
- float32 helper_f ## name ## s (float32 src1, float32 src2) \
- { \
- return float32_ ## name (src1, src2, &env->fp_status); \
- } \
- F_HELPER(name, d) \
- { \
- DT0 = float64_ ## name (DT0, DT1, &env->fp_status); \
- } \
- F_HELPER(name, q) \
- { \
- QT0 = float128_ ## name (QT0, QT1, &env->fp_status); \
- }
-
-F_BINOP(add);
-F_BINOP(sub);
-F_BINOP(mul);
-F_BINOP(div);
-#undef F_BINOP
-
-void helper_fsmuld(float32 src1, float32 src2)
-{
- DT0 = float64_mul(float32_to_float64(src1, &env->fp_status),
- float32_to_float64(src2, &env->fp_status),
- &env->fp_status);
-}
-
-void helper_fdmulq(void)
-{
- QT0 = float128_mul(float64_to_float128(DT0, &env->fp_status),
- float64_to_float128(DT1, &env->fp_status),
- &env->fp_status);
-}
-
-float32 helper_fnegs(float32 src)
-{
- return float32_chs(src);
-}
-
-#ifdef TARGET_SPARC64
-F_HELPER(neg, d)
-{
- DT0 = float64_chs(DT1);
-}
-
-F_HELPER(neg, q)
-{
- QT0 = float128_chs(QT1);
-}
-#endif
-
-/* Integer to float conversion. */
-float32 helper_fitos(int32_t src)
-{
- return int32_to_float32(src, &env->fp_status);
-}
-
-void helper_fitod(int32_t src)
-{
- DT0 = int32_to_float64(src, &env->fp_status);
-}
-
-void helper_fitoq(int32_t src)
-{
- QT0 = int32_to_float128(src, &env->fp_status);
-}
-
-#ifdef TARGET_SPARC64
-float32 helper_fxtos(void)
-{
- return int64_to_float32(*((int64_t *)&DT1), &env->fp_status);
-}
-
-F_HELPER(xto, d)
-{
- DT0 = int64_to_float64(*((int64_t *)&DT1), &env->fp_status);
-}
-
-F_HELPER(xto, q)
-{
- QT0 = int64_to_float128(*((int64_t *)&DT1), &env->fp_status);
-}
-#endif
-#undef F_HELPER
-
-/* floating point conversion */
-float32 helper_fdtos(void)
-{
- return float64_to_float32(DT1, &env->fp_status);
-}
-
-void helper_fstod(float32 src)
-{
- DT0 = float32_to_float64(src, &env->fp_status);
-}
-
-float32 helper_fqtos(void)
-{
- return float128_to_float32(QT1, &env->fp_status);
-}
-
-void helper_fstoq(float32 src)
-{
- QT0 = float32_to_float128(src, &env->fp_status);
-}
-
-void helper_fqtod(void)
-{
- DT0 = float128_to_float64(QT1, &env->fp_status);
-}
-
-void helper_fdtoq(void)
-{
- QT0 = float64_to_float128(DT1, &env->fp_status);
-}
-
-/* Float to integer conversion. */
-int32_t helper_fstoi(float32 src)
-{
- return float32_to_int32_round_to_zero(src, &env->fp_status);
-}
-
-int32_t helper_fdtoi(void)
-{
- return float64_to_int32_round_to_zero(DT1, &env->fp_status);
-}
-
-int32_t helper_fqtoi(void)
-{
- return float128_to_int32_round_to_zero(QT1, &env->fp_status);
-}
-
-#ifdef TARGET_SPARC64
-void helper_fstox(float32 src)
-{
- *((int64_t *)&DT0) = float32_to_int64_round_to_zero(src, &env->fp_status);
-}
-
-void helper_fdtox(void)
-{
- *((int64_t *)&DT0) = float64_to_int64_round_to_zero(DT1, &env->fp_status);
-}
-
-void helper_fqtox(void)
-{
- *((int64_t *)&DT0) = float128_to_int64_round_to_zero(QT1, &env->fp_status);
-}
-
-void helper_faligndata(void)
-{
- uint64_t tmp;
-
- tmp = (*((uint64_t *)&DT0)) << ((env->gsr & 7) * 8);
- /* on many architectures a shift of 64 does nothing */
- if ((env->gsr & 7) != 0) {
- tmp |= (*((uint64_t *)&DT1)) >> (64 - (env->gsr & 7) * 8);
- }
- *((uint64_t *)&DT0) = tmp;
-}
-
-#ifdef HOST_WORDS_BIGENDIAN
-#define VIS_B64(n) b[7 - (n)]
-#define VIS_W64(n) w[3 - (n)]
-#define VIS_SW64(n) sw[3 - (n)]
-#define VIS_L64(n) l[1 - (n)]
-#define VIS_B32(n) b[3 - (n)]
-#define VIS_W32(n) w[1 - (n)]
-#else
-#define VIS_B64(n) b[n]
-#define VIS_W64(n) w[n]
-#define VIS_SW64(n) sw[n]
-#define VIS_L64(n) l[n]
-#define VIS_B32(n) b[n]
-#define VIS_W32(n) w[n]
-#endif
-
-typedef union {
- uint8_t b[8];
- uint16_t w[4];
- int16_t sw[4];
- uint32_t l[2];
- uint64_t ll;
- float64 d;
-} vis64;
-
-typedef union {
- uint8_t b[4];
- uint16_t w[2];
- uint32_t l;
- float32 f;
-} vis32;
-
-void helper_fpmerge(void)
-{
- vis64 s, d;
-
- s.d = DT0;
- d.d = DT1;
-
- // Reverse calculation order to handle overlap
- d.VIS_B64(7) = s.VIS_B64(3);
- d.VIS_B64(6) = d.VIS_B64(3);
- d.VIS_B64(5) = s.VIS_B64(2);
- d.VIS_B64(4) = d.VIS_B64(2);
- d.VIS_B64(3) = s.VIS_B64(1);
- d.VIS_B64(2) = d.VIS_B64(1);
- d.VIS_B64(1) = s.VIS_B64(0);
- //d.VIS_B64(0) = d.VIS_B64(0);
-
- DT0 = d.d;
-}
-
-void helper_fmul8x16(void)
-{
- vis64 s, d;
- uint32_t tmp;
-
- s.d = DT0;
- d.d = DT1;
-
-#define PMUL(r) \
- tmp = (int32_t)d.VIS_SW64(r) * (int32_t)s.VIS_B64(r); \
- if ((tmp & 0xff) > 0x7f) \
- tmp += 0x100; \
- d.VIS_W64(r) = tmp >> 8;
-
- PMUL(0);
- PMUL(1);
- PMUL(2);
- PMUL(3);
-#undef PMUL
-
- DT0 = d.d;
-}
-
-void helper_fmul8x16al(void)
-{
- vis64 s, d;
- uint32_t tmp;
-
- s.d = DT0;
- d.d = DT1;
-
-#define PMUL(r) \
- tmp = (int32_t)d.VIS_SW64(1) * (int32_t)s.VIS_B64(r); \
- if ((tmp & 0xff) > 0x7f) \
- tmp += 0x100; \
- d.VIS_W64(r) = tmp >> 8;
-
- PMUL(0);
- PMUL(1);
- PMUL(2);
- PMUL(3);
-#undef PMUL
-
- DT0 = d.d;
-}
-
-void helper_fmul8x16au(void)
-{
- vis64 s, d;
- uint32_t tmp;
-
- s.d = DT0;
- d.d = DT1;
-
-#define PMUL(r) \
- tmp = (int32_t)d.VIS_SW64(0) * (int32_t)s.VIS_B64(r); \
- if ((tmp & 0xff) > 0x7f) \
- tmp += 0x100; \
- d.VIS_W64(r) = tmp >> 8;
-
- PMUL(0);
- PMUL(1);
- PMUL(2);
- PMUL(3);
-#undef PMUL
-
- DT0 = d.d;
-}
-
-void helper_fmul8sux16(void)
-{
- vis64 s, d;
- uint32_t tmp;
-
- s.d = DT0;
- d.d = DT1;
-
-#define PMUL(r) \
- tmp = (int32_t)d.VIS_SW64(r) * ((int32_t)s.VIS_SW64(r) >> 8); \
- if ((tmp & 0xff) > 0x7f) \
- tmp += 0x100; \
- d.VIS_W64(r) = tmp >> 8;
-
- PMUL(0);
- PMUL(1);
- PMUL(2);
- PMUL(3);
-#undef PMUL
-
- DT0 = d.d;
-}
-
-void helper_fmul8ulx16(void)
-{
- vis64 s, d;
- uint32_t tmp;
-
- s.d = DT0;
- d.d = DT1;
-
-#define PMUL(r) \
- tmp = (int32_t)d.VIS_SW64(r) * ((uint32_t)s.VIS_B64(r * 2)); \
- if ((tmp & 0xff) > 0x7f) \
- tmp += 0x100; \
- d.VIS_W64(r) = tmp >> 8;
-
- PMUL(0);
- PMUL(1);
- PMUL(2);
- PMUL(3);
-#undef PMUL
-
- DT0 = d.d;
-}
-
-void helper_fmuld8sux16(void)
-{
- vis64 s, d;
- uint32_t tmp;
-
- s.d = DT0;
- d.d = DT1;
-
-#define PMUL(r) \
- tmp = (int32_t)d.VIS_SW64(r) * ((int32_t)s.VIS_SW64(r) >> 8); \
- if ((tmp & 0xff) > 0x7f) \
- tmp += 0x100; \
- d.VIS_L64(r) = tmp;
-
- // Reverse calculation order to handle overlap
- PMUL(1);
- PMUL(0);
-#undef PMUL
-
- DT0 = d.d;
-}
-
-void helper_fmuld8ulx16(void)
-{
- vis64 s, d;
- uint32_t tmp;
-
- s.d = DT0;
- d.d = DT1;
-
-#define PMUL(r) \
- tmp = (int32_t)d.VIS_SW64(r) * ((uint32_t)s.VIS_B64(r * 2)); \
- if ((tmp & 0xff) > 0x7f) \
- tmp += 0x100; \
- d.VIS_L64(r) = tmp;
-
- // Reverse calculation order to handle overlap
- PMUL(1);
- PMUL(0);
-#undef PMUL
-
- DT0 = d.d;
-}
-
-void helper_fexpand(void)
-{
- vis32 s;
- vis64 d;
-
- s.l = (uint32_t)(*(uint64_t *)&DT0 & 0xffffffff);
- d.d = DT1;
- d.VIS_W64(0) = s.VIS_B32(0) << 4;
- d.VIS_W64(1) = s.VIS_B32(1) << 4;
- d.VIS_W64(2) = s.VIS_B32(2) << 4;
- d.VIS_W64(3) = s.VIS_B32(3) << 4;
-
- DT0 = d.d;
-}
-
-#define VIS_HELPER(name, F) \
- void name##16(void) \
- { \
- vis64 s, d; \
- \
- s.d = DT0; \
- d.d = DT1; \
- \
- d.VIS_W64(0) = F(d.VIS_W64(0), s.VIS_W64(0)); \
- d.VIS_W64(1) = F(d.VIS_W64(1), s.VIS_W64(1)); \
- d.VIS_W64(2) = F(d.VIS_W64(2), s.VIS_W64(2)); \
- d.VIS_W64(3) = F(d.VIS_W64(3), s.VIS_W64(3)); \
- \
- DT0 = d.d; \
- } \
- \
- uint32_t name##16s(uint32_t src1, uint32_t src2) \
- { \
- vis32 s, d; \
- \
- s.l = src1; \
- d.l = src2; \
- \
- d.VIS_W32(0) = F(d.VIS_W32(0), s.VIS_W32(0)); \
- d.VIS_W32(1) = F(d.VIS_W32(1), s.VIS_W32(1)); \
- \
- return d.l; \
- } \
- \
- void name##32(void) \
- { \
- vis64 s, d; \
- \
- s.d = DT0; \
- d.d = DT1; \
- \
- d.VIS_L64(0) = F(d.VIS_L64(0), s.VIS_L64(0)); \
- d.VIS_L64(1) = F(d.VIS_L64(1), s.VIS_L64(1)); \
- \
- DT0 = d.d; \
- } \
- \
- uint32_t name##32s(uint32_t src1, uint32_t src2) \
- { \
- vis32 s, d; \
- \
- s.l = src1; \
- d.l = src2; \
- \
- d.l = F(d.l, s.l); \
- \
- return d.l; \
- }
-
-#define FADD(a, b) ((a) + (b))
-#define FSUB(a, b) ((a) - (b))
-VIS_HELPER(helper_fpadd, FADD)
-VIS_HELPER(helper_fpsub, FSUB)
-
-#define VIS_CMPHELPER(name, F) \
- uint64_t name##16(void) \
- { \
- vis64 s, d; \
- \
- s.d = DT0; \
- d.d = DT1; \
- \
- d.VIS_W64(0) = F(s.VIS_W64(0), d.VIS_W64(0)) ? 1 : 0; \
- d.VIS_W64(0) |= F(s.VIS_W64(1), d.VIS_W64(1)) ? 2 : 0; \
- d.VIS_W64(0) |= F(s.VIS_W64(2), d.VIS_W64(2)) ? 4 : 0; \
- d.VIS_W64(0) |= F(s.VIS_W64(3), d.VIS_W64(3)) ? 8 : 0; \
- d.VIS_W64(1) = d.VIS_W64(2) = d.VIS_W64(3) = 0; \
- \
- return d.ll; \
- } \
- \
- uint64_t name##32(void) \
- { \
- vis64 s, d; \
- \
- s.d = DT0; \
- d.d = DT1; \
- \
- d.VIS_L64(0) = F(s.VIS_L64(0), d.VIS_L64(0)) ? 1 : 0; \
- d.VIS_L64(0) |= F(s.VIS_L64(1), d.VIS_L64(1)) ? 2 : 0; \
- d.VIS_L64(1) = 0; \
- \
- return d.ll; \
- }
-
-#define FCMPGT(a, b) ((a) > (b))
-#define FCMPEQ(a, b) ((a) == (b))
-#define FCMPLE(a, b) ((a) <= (b))
-#define FCMPNE(a, b) ((a) != (b))
-
-VIS_CMPHELPER(helper_fcmpgt, FCMPGT)
-VIS_CMPHELPER(helper_fcmpeq, FCMPEQ)
-VIS_CMPHELPER(helper_fcmple, FCMPLE)
-VIS_CMPHELPER(helper_fcmpne, FCMPNE)
-#endif
-
-void helper_check_ieee_exceptions(void)
-{
- target_ulong status;
-
- status = get_float_exception_flags(&env->fp_status);
- if (status) {
- /* Copy IEEE 754 flags into FSR */
- if (status & float_flag_invalid)
- env->fsr |= FSR_NVC;
- if (status & float_flag_overflow)
- env->fsr |= FSR_OFC;
- if (status & float_flag_underflow)
- env->fsr |= FSR_UFC;
- if (status & float_flag_divbyzero)
- env->fsr |= FSR_DZC;
- if (status & float_flag_inexact)
- env->fsr |= FSR_NXC;
-
- if ((env->fsr & FSR_CEXC_MASK) & ((env->fsr & FSR_TEM_MASK) >> 23)) {
- /* Unmasked exception, generate a trap */
- env->fsr |= FSR_FTT_IEEE_EXCP;
- raise_exception(TT_FP_EXCP);
- } else {
- /* Accumulate exceptions */
- env->fsr |= (env->fsr & FSR_CEXC_MASK) << 5;
- }
- }
-}
-
-void helper_clear_float_exceptions(void)
-{
- set_float_exception_flags(0, &env->fp_status);
-}
-
-float32 helper_fabss(float32 src)
-{
- return float32_abs(src);
-}
-
-#ifdef TARGET_SPARC64
-void helper_fabsd(void)
-{
- DT0 = float64_abs(DT1);
-}
-
-void helper_fabsq(void)
-{
- QT0 = float128_abs(QT1);
-}
-#endif
-
-float32 helper_fsqrts(float32 src)
-{
- return float32_sqrt(src, &env->fp_status);
-}
-
-void helper_fsqrtd(void)
-{
- DT0 = float64_sqrt(DT1, &env->fp_status);
-}
-
-void helper_fsqrtq(void)
-{
- QT0 = float128_sqrt(QT1, &env->fp_status);
-}
-
-#define GEN_FCMP(name, size, reg1, reg2, FS, E) \
- void glue(helper_, name) (void) \
- { \
- env->fsr &= FSR_FTT_NMASK; \
- if (E && (glue(size, _is_any_nan)(reg1) || \
- glue(size, _is_any_nan)(reg2)) && \
- (env->fsr & FSR_NVM)) { \
- env->fsr |= FSR_NVC; \
- env->fsr |= FSR_FTT_IEEE_EXCP; \
- raise_exception(TT_FP_EXCP); \
- } \
- switch (glue(size, _compare) (reg1, reg2, &env->fp_status)) { \
- case float_relation_unordered: \
- if ((env->fsr & FSR_NVM)) { \
- env->fsr |= FSR_NVC; \
- env->fsr |= FSR_FTT_IEEE_EXCP; \
- raise_exception(TT_FP_EXCP); \
- } else { \
- env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \
- env->fsr |= (FSR_FCC1 | FSR_FCC0) << FS; \
- env->fsr |= FSR_NVA; \
- } \
- break; \
- case float_relation_less: \
- env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \
- env->fsr |= FSR_FCC0 << FS; \
- break; \
- case float_relation_greater: \
- env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \
- env->fsr |= FSR_FCC1 << FS; \
- break; \
- default: \
- env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \
- break; \
- } \
- }
-#define GEN_FCMPS(name, size, FS, E) \
- void glue(helper_, name)(float32 src1, float32 src2) \
- { \
- env->fsr &= FSR_FTT_NMASK; \
- if (E && (glue(size, _is_any_nan)(src1) || \
- glue(size, _is_any_nan)(src2)) && \
- (env->fsr & FSR_NVM)) { \
- env->fsr |= FSR_NVC; \
- env->fsr |= FSR_FTT_IEEE_EXCP; \
- raise_exception(TT_FP_EXCP); \
- } \
- switch (glue(size, _compare) (src1, src2, &env->fp_status)) { \
- case float_relation_unordered: \
- if ((env->fsr & FSR_NVM)) { \
- env->fsr |= FSR_NVC; \
- env->fsr |= FSR_FTT_IEEE_EXCP; \
- raise_exception(TT_FP_EXCP); \
- } else { \
- env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \
- env->fsr |= (FSR_FCC1 | FSR_FCC0) << FS; \
- env->fsr |= FSR_NVA; \
- } \
- break; \
- case float_relation_less: \
- env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \
- env->fsr |= FSR_FCC0 << FS; \
- break; \
- case float_relation_greater: \
- env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \
- env->fsr |= FSR_FCC1 << FS; \
- break; \
- default: \
- env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \
- break; \
- } \
- }
-
-GEN_FCMPS(fcmps, float32, 0, 0);
-GEN_FCMP(fcmpd, float64, DT0, DT1, 0, 0);
-
-GEN_FCMPS(fcmpes, float32, 0, 1);
-GEN_FCMP(fcmped, float64, DT0, DT1, 0, 1);
-
-GEN_FCMP(fcmpq, float128, QT0, QT1, 0, 0);
-GEN_FCMP(fcmpeq, float128, QT0, QT1, 0, 1);
-
-static uint32_t compute_all_flags(void)
-{
- return env->psr & PSR_ICC;
-}
-
-static uint32_t compute_C_flags(void)
-{
- return env->psr & PSR_CARRY;
-}
-
-static inline uint32_t get_NZ_icc(int32_t dst)
-{
- uint32_t ret = 0;
-
- if (dst == 0) {
- ret = PSR_ZERO;
- } else if (dst < 0) {
- ret = PSR_NEG;
- }
- return ret;
-}
-
-#ifdef TARGET_SPARC64
-static uint32_t compute_all_flags_xcc(void)
-{
- return env->xcc & PSR_ICC;
-}
-
-static uint32_t compute_C_flags_xcc(void)
-{
- return env->xcc & PSR_CARRY;
-}
-
-static inline uint32_t get_NZ_xcc(target_long dst)
-{
- uint32_t ret = 0;
-
- if (!dst) {
- ret = PSR_ZERO;
- } else if (dst < 0) {
- ret = PSR_NEG;
- }
- return ret;
-}
-#endif
-
-static inline uint32_t get_V_div_icc(target_ulong src2)
-{
- uint32_t ret = 0;
-
- if (src2 != 0) {
- ret = PSR_OVF;
- }
- return ret;
-}
-
-static uint32_t compute_all_div(void)
-{
- uint32_t ret;
-
- ret = get_NZ_icc(CC_DST);
- ret |= get_V_div_icc(CC_SRC2);
- return ret;
-}
-
-static uint32_t compute_C_div(void)
-{
- return 0;
-}
-
-static inline uint32_t get_C_add_icc(uint32_t dst, uint32_t src1)
-{
- uint32_t ret = 0;
-
- if (dst < src1) {
- ret = PSR_CARRY;
- }
- return ret;
-}
-
-static inline uint32_t get_C_addx_icc(uint32_t dst, uint32_t src1,
- uint32_t src2)
-{
- uint32_t ret = 0;
-
- if (((src1 & src2) | (~dst & (src1 | src2))) & (1U << 31)) {
- ret = PSR_CARRY;
- }
- return ret;
-}
-
-static inline uint32_t get_V_add_icc(uint32_t dst, uint32_t src1,
- uint32_t src2)
-{
- uint32_t ret = 0;
-
- if (((src1 ^ src2 ^ -1) & (src1 ^ dst)) & (1U << 31)) {
- ret = PSR_OVF;
- }
- return ret;
-}
-
-#ifdef TARGET_SPARC64
-static inline uint32_t get_C_add_xcc(target_ulong dst, target_ulong src1)
-{
- uint32_t ret = 0;
-
- if (dst < src1) {
- ret = PSR_CARRY;
- }
- return ret;
-}
-
-static inline uint32_t get_C_addx_xcc(target_ulong dst, target_ulong src1,
- target_ulong src2)
-{
- uint32_t ret = 0;
-
- if (((src1 & src2) | (~dst & (src1 | src2))) & (1ULL << 63)) {
- ret = PSR_CARRY;
- }
- return ret;
-}
-
-static inline uint32_t get_V_add_xcc(target_ulong dst, target_ulong src1,
- target_ulong src2)
-{
- uint32_t ret = 0;
-
- if (((src1 ^ src2 ^ -1) & (src1 ^ dst)) & (1ULL << 63)) {
- ret = PSR_OVF;
- }
- return ret;
-}
-
-static uint32_t compute_all_add_xcc(void)
-{
- uint32_t ret;
-
- ret = get_NZ_xcc(CC_DST);
- ret |= get_C_add_xcc(CC_DST, CC_SRC);
- ret |= get_V_add_xcc(CC_DST, CC_SRC, CC_SRC2);
- return ret;
-}
-
-static uint32_t compute_C_add_xcc(void)
-{
- return get_C_add_xcc(CC_DST, CC_SRC);
-}
-#endif
-
-static uint32_t compute_all_add(void)
-{
- uint32_t ret;
-
- ret = get_NZ_icc(CC_DST);
- ret |= get_C_add_icc(CC_DST, CC_SRC);
- ret |= get_V_add_icc(CC_DST, CC_SRC, CC_SRC2);
- return ret;
-}
-
-static uint32_t compute_C_add(void)
-{
- return get_C_add_icc(CC_DST, CC_SRC);
-}
-
-#ifdef TARGET_SPARC64
-static uint32_t compute_all_addx_xcc(void)
-{
- uint32_t ret;
-
- ret = get_NZ_xcc(CC_DST);
- ret |= get_C_addx_xcc(CC_DST, CC_SRC, CC_SRC2);
- ret |= get_V_add_xcc(CC_DST, CC_SRC, CC_SRC2);
- return ret;
-}
-
-static uint32_t compute_C_addx_xcc(void)
-{
- uint32_t ret;
-
- ret = get_C_addx_xcc(CC_DST, CC_SRC, CC_SRC2);
- return ret;
-}
-#endif
-
-static uint32_t compute_all_addx(void)
-{
- uint32_t ret;
-
- ret = get_NZ_icc(CC_DST);
- ret |= get_C_addx_icc(CC_DST, CC_SRC, CC_SRC2);
- ret |= get_V_add_icc(CC_DST, CC_SRC, CC_SRC2);
- return ret;
-}
-
-static uint32_t compute_C_addx(void)
-{
- uint32_t ret;
-
- ret = get_C_addx_icc(CC_DST, CC_SRC, CC_SRC2);
- return ret;
-}
-
-static inline uint32_t get_V_tag_icc(target_ulong src1, target_ulong src2)
-{
- uint32_t ret = 0;
-
- if ((src1 | src2) & 0x3) {
- ret = PSR_OVF;
- }
- return ret;
-}
-
-static uint32_t compute_all_tadd(void)
-{
- uint32_t ret;
-
- ret = get_NZ_icc(CC_DST);
- ret |= get_C_add_icc(CC_DST, CC_SRC);
- ret |= get_V_add_icc(CC_DST, CC_SRC, CC_SRC2);
- ret |= get_V_tag_icc(CC_SRC, CC_SRC2);
- return ret;
-}
-
-static uint32_t compute_all_taddtv(void)
-{
- uint32_t ret;
-
- ret = get_NZ_icc(CC_DST);
- ret |= get_C_add_icc(CC_DST, CC_SRC);
- return ret;
-}
-
-static inline uint32_t get_C_sub_icc(uint32_t src1, uint32_t src2)
-{
- uint32_t ret = 0;
-
- if (src1 < src2) {
- ret = PSR_CARRY;
- }
- return ret;
-}
-
-static inline uint32_t get_C_subx_icc(uint32_t dst, uint32_t src1,
- uint32_t src2)
-{
- uint32_t ret = 0;
-
- if (((~src1 & src2) | (dst & (~src1 | src2))) & (1U << 31)) {
- ret = PSR_CARRY;
- }
- return ret;
-}
-
-static inline uint32_t get_V_sub_icc(uint32_t dst, uint32_t src1,
- uint32_t src2)
-{
- uint32_t ret = 0;
-
- if (((src1 ^ src2) & (src1 ^ dst)) & (1U << 31)) {
- ret = PSR_OVF;
- }
- return ret;
-}
-
-
-#ifdef TARGET_SPARC64
-static inline uint32_t get_C_sub_xcc(target_ulong src1, target_ulong src2)
-{
- uint32_t ret = 0;
-
- if (src1 < src2) {
- ret = PSR_CARRY;
- }
- return ret;
-}
-
-static inline uint32_t get_C_subx_xcc(target_ulong dst, target_ulong src1,
- target_ulong src2)
-{
- uint32_t ret = 0;
-
- if (((~src1 & src2) | (dst & (~src1 | src2))) & (1ULL << 63)) {
- ret = PSR_CARRY;
- }
- return ret;
-}
-
-static inline uint32_t get_V_sub_xcc(target_ulong dst, target_ulong src1,
- target_ulong src2)
-{
- uint32_t ret = 0;
-
- if (((src1 ^ src2) & (src1 ^ dst)) & (1ULL << 63)) {
- ret = PSR_OVF;
- }
- return ret;
-}
-
-static uint32_t compute_all_sub_xcc(void)
-{
- uint32_t ret;
-
- ret = get_NZ_xcc(CC_DST);
- ret |= get_C_sub_xcc(CC_SRC, CC_SRC2);
- ret |= get_V_sub_xcc(CC_DST, CC_SRC, CC_SRC2);
- return ret;
-}
-
-static uint32_t compute_C_sub_xcc(void)
-{
- return get_C_sub_xcc(CC_SRC, CC_SRC2);
-}
-#endif
-
-static uint32_t compute_all_sub(void)
-{
- uint32_t ret;
-
- ret = get_NZ_icc(CC_DST);
- ret |= get_C_sub_icc(CC_SRC, CC_SRC2);
- ret |= get_V_sub_icc(CC_DST, CC_SRC, CC_SRC2);
- return ret;
-}
-
-static uint32_t compute_C_sub(void)
-{
- return get_C_sub_icc(CC_SRC, CC_SRC2);
-}
-
-#ifdef TARGET_SPARC64
-static uint32_t compute_all_subx_xcc(void)
-{
- uint32_t ret;
-
- ret = get_NZ_xcc(CC_DST);
- ret |= get_C_subx_xcc(CC_DST, CC_SRC, CC_SRC2);
- ret |= get_V_sub_xcc(CC_DST, CC_SRC, CC_SRC2);
- return ret;
-}
-
-static uint32_t compute_C_subx_xcc(void)
-{
- uint32_t ret;
-
- ret = get_C_subx_xcc(CC_DST, CC_SRC, CC_SRC2);
- return ret;
-}
-#endif
-
-static uint32_t compute_all_subx(void)
-{
- uint32_t ret;
-
- ret = get_NZ_icc(CC_DST);
- ret |= get_C_subx_icc(CC_DST, CC_SRC, CC_SRC2);
- ret |= get_V_sub_icc(CC_DST, CC_SRC, CC_SRC2);
- return ret;
-}
-
-static uint32_t compute_C_subx(void)
-{
- uint32_t ret;
-
- ret = get_C_subx_icc(CC_DST, CC_SRC, CC_SRC2);
- return ret;
-}
-
-static uint32_t compute_all_tsub(void)
-{
- uint32_t ret;
-
- ret = get_NZ_icc(CC_DST);
- ret |= get_C_sub_icc(CC_SRC, CC_SRC2);
- ret |= get_V_sub_icc(CC_DST, CC_SRC, CC_SRC2);
- ret |= get_V_tag_icc(CC_SRC, CC_SRC2);
- return ret;
-}
-
-static uint32_t compute_all_tsubtv(void)
-{
- uint32_t ret;
-
- ret = get_NZ_icc(CC_DST);
- ret |= get_C_sub_icc(CC_SRC, CC_SRC2);
- return ret;
-}
-
-static uint32_t compute_all_logic(void)
-{
- return get_NZ_icc(CC_DST);
-}
-
-static uint32_t compute_C_logic(void)
-{
- return 0;
-}
-
-#ifdef TARGET_SPARC64
-static uint32_t compute_all_logic_xcc(void)
-{
- return get_NZ_xcc(CC_DST);
-}
-#endif
-
-typedef struct CCTable {
- uint32_t (*compute_all)(void); /* return all the flags */
- uint32_t (*compute_c)(void); /* return the C flag */
-} CCTable;
-
-static const CCTable icc_table[CC_OP_NB] = {
- /* CC_OP_DYNAMIC should never happen */
- [CC_OP_FLAGS] = { compute_all_flags, compute_C_flags },
- [CC_OP_DIV] = { compute_all_div, compute_C_div },
- [CC_OP_ADD] = { compute_all_add, compute_C_add },
- [CC_OP_ADDX] = { compute_all_addx, compute_C_addx },
- [CC_OP_TADD] = { compute_all_tadd, compute_C_add },
- [CC_OP_TADDTV] = { compute_all_taddtv, compute_C_add },
- [CC_OP_SUB] = { compute_all_sub, compute_C_sub },
- [CC_OP_SUBX] = { compute_all_subx, compute_C_subx },
- [CC_OP_TSUB] = { compute_all_tsub, compute_C_sub },
- [CC_OP_TSUBTV] = { compute_all_tsubtv, compute_C_sub },
- [CC_OP_LOGIC] = { compute_all_logic, compute_C_logic },
-};
-
-#ifdef TARGET_SPARC64
-static const CCTable xcc_table[CC_OP_NB] = {
- /* CC_OP_DYNAMIC should never happen */
- [CC_OP_FLAGS] = { compute_all_flags_xcc, compute_C_flags_xcc },
- [CC_OP_DIV] = { compute_all_logic_xcc, compute_C_logic },
- [CC_OP_ADD] = { compute_all_add_xcc, compute_C_add_xcc },
- [CC_OP_ADDX] = { compute_all_addx_xcc, compute_C_addx_xcc },
- [CC_OP_TADD] = { compute_all_add_xcc, compute_C_add_xcc },
- [CC_OP_TADDTV] = { compute_all_add_xcc, compute_C_add_xcc },
- [CC_OP_SUB] = { compute_all_sub_xcc, compute_C_sub_xcc },
- [CC_OP_SUBX] = { compute_all_subx_xcc, compute_C_subx_xcc },
- [CC_OP_TSUB] = { compute_all_sub_xcc, compute_C_sub_xcc },
- [CC_OP_TSUBTV] = { compute_all_sub_xcc, compute_C_sub_xcc },
- [CC_OP_LOGIC] = { compute_all_logic_xcc, compute_C_logic },
-};
-#endif
-
-void helper_compute_psr(void)
-{
- uint32_t new_psr;
-
- new_psr = icc_table[CC_OP].compute_all();
- env->psr = new_psr;
-#ifdef TARGET_SPARC64
- new_psr = xcc_table[CC_OP].compute_all();
- env->xcc = new_psr;
-#endif
- CC_OP = CC_OP_FLAGS;
-}
-
-uint32_t helper_compute_C_icc(void)
-{
- uint32_t ret;
-
- ret = icc_table[CC_OP].compute_c() >> PSR_CARRY_SHIFT;
- return ret;
-}
-
-static inline void memcpy32(target_ulong *dst, const target_ulong *src)
-{
- dst[0] = src[0];
- dst[1] = src[1];
- dst[2] = src[2];
- dst[3] = src[3];
- dst[4] = src[4];
- dst[5] = src[5];
- dst[6] = src[6];
- dst[7] = src[7];
-}
-
-static void set_cwp(int new_cwp)
-{
- /* put the modified wrap registers at their proper location */
- if (env->cwp == env->nwindows - 1) {
- memcpy32(env->regbase, env->regbase + env->nwindows * 16);
- }
- env->cwp = new_cwp;
-
- /* put the wrap registers at their temporary location */
- if (new_cwp == env->nwindows - 1) {
- memcpy32(env->regbase + env->nwindows * 16, env->regbase);
- }
- env->regwptr = env->regbase + (new_cwp * 16);
-}
-
-void cpu_set_cwp(CPUState *env1, int new_cwp)
-{
- CPUState *saved_env;
-
- saved_env = env;
- env = env1;
- set_cwp(new_cwp);
- env = saved_env;
-}
-
-static target_ulong get_psr(void)
-{
- helper_compute_psr();
-
-#if !defined (TARGET_SPARC64)
- return env->version | (env->psr & PSR_ICC) |
- (env->psref? PSR_EF : 0) |
- (env->psrpil << 8) |
- (env->psrs? PSR_S : 0) |
- (env->psrps? PSR_PS : 0) |
- (env->psret? PSR_ET : 0) | env->cwp;
-#else
- return env->psr & PSR_ICC;
-#endif
-}
-
-target_ulong cpu_get_psr(CPUState *env1)
-{
- CPUState *saved_env;
- target_ulong ret;
-
- saved_env = env;
- env = env1;
- ret = get_psr();
- env = saved_env;
- return ret;
-}
-
-static void put_psr(target_ulong val)
-{
- env->psr = val & PSR_ICC;
-#if !defined (TARGET_SPARC64)
- env->psref = (val & PSR_EF)? 1 : 0;
- env->psrpil = (val & PSR_PIL) >> 8;
-#endif
-#if ((!defined (TARGET_SPARC64)) && !defined(CONFIG_USER_ONLY))
- cpu_check_irqs(env);
-#endif
-#if !defined (TARGET_SPARC64)
- env->psrs = (val & PSR_S)? 1 : 0;
- env->psrps = (val & PSR_PS)? 1 : 0;
- env->psret = (val & PSR_ET)? 1 : 0;
- set_cwp(val & PSR_CWP);
-#endif
- env->cc_op = CC_OP_FLAGS;
-}
-
-void cpu_put_psr(CPUState *env1, target_ulong val)
-{
- CPUState *saved_env;
-
- saved_env = env;
- env = env1;
- put_psr(val);
- env = saved_env;
-}
-
-static int cwp_inc(int cwp)
-{
- if (unlikely(cwp >= env->nwindows)) {
- cwp -= env->nwindows;
- }
- return cwp;
-}
-
-int cpu_cwp_inc(CPUState *env1, int cwp)
-{
- CPUState *saved_env;
- target_ulong ret;
-
- saved_env = env;
- env = env1;
- ret = cwp_inc(cwp);
- env = saved_env;
- return ret;
-}
-
-static int cwp_dec(int cwp)
-{
- if (unlikely(cwp < 0)) {
- cwp += env->nwindows;
- }
- return cwp;
-}
-
-int cpu_cwp_dec(CPUState *env1, int cwp)
-{
- CPUState *saved_env;
- target_ulong ret;
-
- saved_env = env;
- env = env1;
- ret = cwp_dec(cwp);
- env = saved_env;
- return ret;
-}
-
-#ifdef TARGET_SPARC64
-GEN_FCMPS(fcmps_fcc1, float32, 22, 0);
-GEN_FCMP(fcmpd_fcc1, float64, DT0, DT1, 22, 0);
-GEN_FCMP(fcmpq_fcc1, float128, QT0, QT1, 22, 0);
-
-GEN_FCMPS(fcmps_fcc2, float32, 24, 0);
-GEN_FCMP(fcmpd_fcc2, float64, DT0, DT1, 24, 0);
-GEN_FCMP(fcmpq_fcc2, float128, QT0, QT1, 24, 0);
-
-GEN_FCMPS(fcmps_fcc3, float32, 26, 0);
-GEN_FCMP(fcmpd_fcc3, float64, DT0, DT1, 26, 0);
-GEN_FCMP(fcmpq_fcc3, float128, QT0, QT1, 26, 0);
-
-GEN_FCMPS(fcmpes_fcc1, float32, 22, 1);
-GEN_FCMP(fcmped_fcc1, float64, DT0, DT1, 22, 1);
-GEN_FCMP(fcmpeq_fcc1, float128, QT0, QT1, 22, 1);
-
-GEN_FCMPS(fcmpes_fcc2, float32, 24, 1);
-GEN_FCMP(fcmped_fcc2, float64, DT0, DT1, 24, 1);
-GEN_FCMP(fcmpeq_fcc2, float128, QT0, QT1, 24, 1);
-
-GEN_FCMPS(fcmpes_fcc3, float32, 26, 1);
-GEN_FCMP(fcmped_fcc3, float64, DT0, DT1, 26, 1);
-GEN_FCMP(fcmpeq_fcc3, float128, QT0, QT1, 26, 1);
-#endif
-#undef GEN_FCMPS
-
-#if !defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY) && \
- defined(DEBUG_MXCC)
-static void dump_mxcc(CPUState *env)
-{
- printf("mxccdata: %016" PRIx64 " %016" PRIx64 " %016" PRIx64 " %016" PRIx64
- "\n",
- env->mxccdata[0], env->mxccdata[1],
- env->mxccdata[2], env->mxccdata[3]);
- printf("mxccregs: %016" PRIx64 " %016" PRIx64 " %016" PRIx64 " %016" PRIx64
- "\n"
- " %016" PRIx64 " %016" PRIx64 " %016" PRIx64 " %016" PRIx64
- "\n",
- env->mxccregs[0], env->mxccregs[1],
- env->mxccregs[2], env->mxccregs[3],
- env->mxccregs[4], env->mxccregs[5],
- env->mxccregs[6], env->mxccregs[7]);
-}
-#endif
-
-#if (defined(TARGET_SPARC64) || !defined(CONFIG_USER_ONLY)) \
- && defined(DEBUG_ASI)
-static void dump_asi(const char *txt, target_ulong addr, int asi, int size,
- uint64_t r1)
-{
- switch (size)
- {
- case 1:
- DPRINTF_ASI("%s "TARGET_FMT_lx " asi 0x%02x = %02" PRIx64 "\n", txt,
- addr, asi, r1 & 0xff);
- break;
- case 2:
- DPRINTF_ASI("%s "TARGET_FMT_lx " asi 0x%02x = %04" PRIx64 "\n", txt,
- addr, asi, r1 & 0xffff);
- break;
- case 4:
- DPRINTF_ASI("%s "TARGET_FMT_lx " asi 0x%02x = %08" PRIx64 "\n", txt,
- addr, asi, r1 & 0xffffffff);
- break;
- case 8:
- DPRINTF_ASI("%s "TARGET_FMT_lx " asi 0x%02x = %016" PRIx64 "\n", txt,
- addr, asi, r1);
- break;
- }
-}
-#endif
-
-#ifndef TARGET_SPARC64
-#ifndef CONFIG_USER_ONLY
-
-
-/* Leon3 cache control */
-
-static void leon3_cache_control_int(void)
-{
- uint32_t state = 0;
-
- if (env->cache_control & CACHE_CTRL_IF) {
- /* Instruction cache state */
- state = env->cache_control & CACHE_STATE_MASK;
- if (state == CACHE_ENABLED) {
- state = CACHE_FROZEN;
- DPRINTF_CACHE_CONTROL("Instruction cache: freeze\n");
- }
-
- env->cache_control &= ~CACHE_STATE_MASK;
- env->cache_control |= state;
- }
-
- if (env->cache_control & CACHE_CTRL_DF) {
- /* Data cache state */
- state = (env->cache_control >> 2) & CACHE_STATE_MASK;
- if (state == CACHE_ENABLED) {
- state = CACHE_FROZEN;
- DPRINTF_CACHE_CONTROL("Data cache: freeze\n");
- }
-
- env->cache_control &= ~(CACHE_STATE_MASK << 2);
- env->cache_control |= (state << 2);
- }
-}
-
-static void leon3_cache_control_st(target_ulong addr, uint64_t val, int size)
-{
- DPRINTF_CACHE_CONTROL("st addr:%08x, val:%" PRIx64 ", size:%d\n",
- addr, val, size);
-
- if (size != 4) {
- DPRINTF_CACHE_CONTROL("32bits only\n");
- return;
- }
-
- switch (addr) {
- case 0x00: /* Cache control */
-
- /* These values must always be read as zeros */
- val &= ~CACHE_CTRL_FD;
- val &= ~CACHE_CTRL_FI;
- val &= ~CACHE_CTRL_IB;
- val &= ~CACHE_CTRL_IP;
- val &= ~CACHE_CTRL_DP;
-
- env->cache_control = val;
- break;
- case 0x04: /* Instruction cache configuration */
- case 0x08: /* Data cache configuration */
- /* Read Only */
- break;
- default:
- DPRINTF_CACHE_CONTROL("write unknown register %08x\n", addr);
- break;
- };
-}
-
-static uint64_t leon3_cache_control_ld(target_ulong addr, int size)
-{
- uint64_t ret = 0;
-
- if (size != 4) {
- DPRINTF_CACHE_CONTROL("32bits only\n");
- return 0;
- }
-
- switch (addr) {
- case 0x00: /* Cache control */
- ret = env->cache_control;
- break;
-
- /* Configuration registers are read and only always keep those
- predefined values */
-
- case 0x04: /* Instruction cache configuration */
- ret = 0x10220000;
- break;
- case 0x08: /* Data cache configuration */
- ret = 0x18220000;
- break;
- default:
- DPRINTF_CACHE_CONTROL("read unknown register %08x\n", addr);
- break;
- };
- DPRINTF_CACHE_CONTROL("ld addr:%08x, ret:0x%" PRIx64 ", size:%d\n",
- addr, ret, size);
- return ret;
-}
-
-void leon3_irq_manager(void *irq_manager, int intno)
-{
- leon3_irq_ack(irq_manager, intno);
- leon3_cache_control_int();
-}
-
-uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
-{
- uint64_t ret = 0;
-#if defined(DEBUG_MXCC) || defined(DEBUG_ASI)
- uint32_t last_addr = addr;
-#endif
-
- helper_check_align(addr, size - 1);
- switch (asi) {
- case 2: /* SuperSparc MXCC registers and Leon3 cache control */
- switch (addr) {
- case 0x00: /* Leon3 Cache Control */
- case 0x08: /* Leon3 Instruction Cache config */
- case 0x0C: /* Leon3 Date Cache config */
- if (env->def->features & CPU_FEATURE_CACHE_CTRL) {
- ret = leon3_cache_control_ld(addr, size);
- }
- break;
- case 0x01c00a00: /* MXCC control register */
- if (size == 8)
- ret = env->mxccregs[3];
- else
- DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
- size);
- break;
- case 0x01c00a04: /* MXCC control register */
- if (size == 4)
- ret = env->mxccregs[3];
- else
- DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
- size);
- break;
- case 0x01c00c00: /* Module reset register */
- if (size == 8) {
- ret = env->mxccregs[5];
- // should we do something here?
- } else
- DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
- size);
- break;
- case 0x01c00f00: /* MBus port address register */
- if (size == 8)
- ret = env->mxccregs[7];
- else
- DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
- size);
- break;
- default:
- DPRINTF_MXCC("%08x: unimplemented address, size: %d\n", addr,
- size);
- break;
- }
- DPRINTF_MXCC("asi = %d, size = %d, sign = %d, "
- "addr = %08x -> ret = %" PRIx64 ","
- "addr = %08x\n", asi, size, sign, last_addr, ret, addr);
-#ifdef DEBUG_MXCC
- dump_mxcc(env);
-#endif
- break;
- case 3: /* MMU probe */
- {
- int mmulev;
-
- mmulev = (addr >> 8) & 15;
- if (mmulev > 4)
- ret = 0;
- else
- ret = mmu_probe(env, addr, mmulev);
- DPRINTF_MMU("mmu_probe: 0x%08x (lev %d) -> 0x%08" PRIx64 "\n",
- addr, mmulev, ret);
- }
- break;
- case 4: /* read MMU regs */
- {
- int reg = (addr >> 8) & 0x1f;
-
- ret = env->mmuregs[reg];
- if (reg == 3) /* Fault status cleared on read */
- env->mmuregs[3] = 0;
- else if (reg == 0x13) /* Fault status read */
- ret = env->mmuregs[3];
- else if (reg == 0x14) /* Fault address read */
- ret = env->mmuregs[4];
- DPRINTF_MMU("mmu_read: reg[%d] = 0x%08" PRIx64 "\n", reg, ret);
- }
- break;
- case 5: // Turbosparc ITLB Diagnostic
- case 6: // Turbosparc DTLB Diagnostic
- case 7: // Turbosparc IOTLB Diagnostic
- break;
- case 9: /* Supervisor code access */
- switch(size) {
- case 1:
- ret = ldub_code(addr);
- break;
- case 2:
- ret = lduw_code(addr);
- break;
- default:
- case 4:
- ret = ldl_code(addr);
- break;
- case 8:
- ret = ldq_code(addr);
- break;
- }
- break;
- case 0xa: /* User data access */
- switch(size) {
- case 1:
- ret = ldub_user(addr);
- break;
- case 2:
- ret = lduw_user(addr);
- break;
- default:
- case 4:
- ret = ldl_user(addr);
- break;
- case 8:
- ret = ldq_user(addr);
- break;
- }
- break;
- case 0xb: /* Supervisor data access */
- switch(size) {
- case 1:
- ret = ldub_kernel(addr);
- break;
- case 2:
- ret = lduw_kernel(addr);
- break;
- default:
- case 4:
- ret = ldl_kernel(addr);
- break;
- case 8:
- ret = ldq_kernel(addr);
- break;
- }
- break;
- case 0xc: /* I-cache tag */
- case 0xd: /* I-cache data */
- case 0xe: /* D-cache tag */
- case 0xf: /* D-cache data */
- break;
- case 0x20: /* MMU passthrough */
- switch(size) {
- case 1:
- ret = ldub_phys(addr);
- break;
- case 2:
- ret = lduw_phys(addr);
- break;
- default:
- case 4:
- ret = ldl_phys(addr);
- break;
- case 8:
- ret = ldq_phys(addr);
- break;
- }
- break;
- case 0x21 ... 0x2f: /* MMU passthrough, 0x100000000 to 0xfffffffff */
- switch(size) {
- case 1:
- ret = ldub_phys((target_phys_addr_t)addr
- | ((target_phys_addr_t)(asi & 0xf) << 32));
- break;
- case 2:
- ret = lduw_phys((target_phys_addr_t)addr
- | ((target_phys_addr_t)(asi & 0xf) << 32));
- break;
- default:
- case 4:
- ret = ldl_phys((target_phys_addr_t)addr
- | ((target_phys_addr_t)(asi & 0xf) << 32));
- break;
- case 8:
- ret = ldq_phys((target_phys_addr_t)addr
- | ((target_phys_addr_t)(asi & 0xf) << 32));
- break;
- }
- break;
- case 0x30: // Turbosparc secondary cache diagnostic
- case 0x31: // Turbosparc RAM snoop
- case 0x32: // Turbosparc page table descriptor diagnostic
- case 0x39: /* data cache diagnostic register */
- ret = 0;
- break;
- case 0x38: /* SuperSPARC MMU Breakpoint Control Registers */
- {
- int reg = (addr >> 8) & 3;
-
- switch(reg) {
- case 0: /* Breakpoint Value (Addr) */
- ret = env->mmubpregs[reg];
- break;
- case 1: /* Breakpoint Mask */
- ret = env->mmubpregs[reg];
- break;
- case 2: /* Breakpoint Control */
- ret = env->mmubpregs[reg];
- break;
- case 3: /* Breakpoint Status */
- ret = env->mmubpregs[reg];
- env->mmubpregs[reg] = 0ULL;
- break;
- }
- DPRINTF_MMU("read breakpoint reg[%d] 0x%016" PRIx64 "\n", reg,
- ret);
- }
- break;
- case 0x49: /* SuperSPARC MMU Counter Breakpoint Value */
- ret = env->mmubpctrv;
- break;
- case 0x4a: /* SuperSPARC MMU Counter Breakpoint Control */
- ret = env->mmubpctrc;
- break;
- case 0x4b: /* SuperSPARC MMU Counter Breakpoint Status */
- ret = env->mmubpctrs;
- break;
- case 0x4c: /* SuperSPARC MMU Breakpoint Action */
- ret = env->mmubpaction;
- break;
- case 8: /* User code access, XXX */
- default:
- do_unassigned_access(addr, 0, 0, asi, size);
- ret = 0;
- break;
- }
- if (sign) {
- switch(size) {
- case 1:
- ret = (int8_t) ret;
- break;
- case 2:
- ret = (int16_t) ret;
- break;
- case 4:
- ret = (int32_t) ret;
- break;
- default:
- break;
- }
- }
-#ifdef DEBUG_ASI
- dump_asi("read ", last_addr, asi, size, ret);
-#endif
- return ret;
-}
-
-void helper_st_asi(target_ulong addr, uint64_t val, int asi, int size)
-{
- helper_check_align(addr, size - 1);
- switch(asi) {
- case 2: /* SuperSparc MXCC registers and Leon3 cache control */
- switch (addr) {
- case 0x00: /* Leon3 Cache Control */
- case 0x08: /* Leon3 Instruction Cache config */
- case 0x0C: /* Leon3 Date Cache config */
- if (env->def->features & CPU_FEATURE_CACHE_CTRL) {
- leon3_cache_control_st(addr, val, size);
- }
- break;
-
- case 0x01c00000: /* MXCC stream data register 0 */
- if (size == 8)
- env->mxccdata[0] = val;
- else
- DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
- size);
- break;
- case 0x01c00008: /* MXCC stream data register 1 */
- if (size == 8)
- env->mxccdata[1] = val;
- else
- DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
- size);
- break;
- case 0x01c00010: /* MXCC stream data register 2 */
- if (size == 8)
- env->mxccdata[2] = val;
- else
- DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
- size);
- break;
- case 0x01c00018: /* MXCC stream data register 3 */
- if (size == 8)
- env->mxccdata[3] = val;
- else
- DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
- size);
- break;
- case 0x01c00100: /* MXCC stream source */
- if (size == 8)
- env->mxccregs[0] = val;
- else
- DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
- size);
- env->mxccdata[0] = ldq_phys((env->mxccregs[0] & 0xffffffffULL) +
- 0);
- env->mxccdata[1] = ldq_phys((env->mxccregs[0] & 0xffffffffULL) +
- 8);
- env->mxccdata[2] = ldq_phys((env->mxccregs[0] & 0xffffffffULL) +
- 16);
- env->mxccdata[3] = ldq_phys((env->mxccregs[0] & 0xffffffffULL) +
- 24);
- break;
- case 0x01c00200: /* MXCC stream destination */
- if (size == 8)
- env->mxccregs[1] = val;
- else
- DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
- size);
- stq_phys((env->mxccregs[1] & 0xffffffffULL) + 0,
- env->mxccdata[0]);
- stq_phys((env->mxccregs[1] & 0xffffffffULL) + 8,
- env->mxccdata[1]);
- stq_phys((env->mxccregs[1] & 0xffffffffULL) + 16,
- env->mxccdata[2]);
- stq_phys((env->mxccregs[1] & 0xffffffffULL) + 24,
- env->mxccdata[3]);
- break;
- case 0x01c00a00: /* MXCC control register */
- if (size == 8)
- env->mxccregs[3] = val;
- else
- DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
- size);
- break;
- case 0x01c00a04: /* MXCC control register */
- if (size == 4)
- env->mxccregs[3] = (env->mxccregs[3] & 0xffffffff00000000ULL)
- | val;
- else
- DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
- size);
- break;
- case 0x01c00e00: /* MXCC error register */
- // writing a 1 bit clears the error
- if (size == 8)
- env->mxccregs[6] &= ~val;
- else
- DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
- size);
- break;
- case 0x01c00f00: /* MBus port address register */
- if (size == 8)
- env->mxccregs[7] = val;
- else
- DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
- size);
- break;
- default:
- DPRINTF_MXCC("%08x: unimplemented address, size: %d\n", addr,
- size);
- break;
- }
- DPRINTF_MXCC("asi = %d, size = %d, addr = %08x, val = %" PRIx64 "\n",
- asi, size, addr, val);
-#ifdef DEBUG_MXCC
- dump_mxcc(env);
-#endif
- break;
- case 3: /* MMU flush */
- {
- int mmulev;
-
- mmulev = (addr >> 8) & 15;
- DPRINTF_MMU("mmu flush level %d\n", mmulev);
- switch (mmulev) {
- case 0: // flush page
- tlb_flush_page(env, addr & 0xfffff000);
- break;
- case 1: // flush segment (256k)
- case 2: // flush region (16M)
- case 3: // flush context (4G)
- case 4: // flush entire
- tlb_flush(env, 1);
- break;
- default:
- break;
- }
-#ifdef DEBUG_MMU
- dump_mmu(stdout, fprintf, env);
-#endif
- }
- break;
- case 4: /* write MMU regs */
- {
- int reg = (addr >> 8) & 0x1f;
- uint32_t oldreg;
-
- oldreg = env->mmuregs[reg];
- switch(reg) {
- case 0: // Control Register
- env->mmuregs[reg] = (env->mmuregs[reg] & 0xff000000) |
- (val & 0x00ffffff);
- // Mappings generated during no-fault mode or MMU
- // disabled mode are invalid in normal mode
- if ((oldreg & (MMU_E | MMU_NF | env->def->mmu_bm)) !=
- (env->mmuregs[reg] & (MMU_E | MMU_NF | env->def->mmu_bm)))
- tlb_flush(env, 1);
- break;
- case 1: // Context Table Pointer Register
- env->mmuregs[reg] = val & env->def->mmu_ctpr_mask;
- break;
- case 2: // Context Register
- env->mmuregs[reg] = val & env->def->mmu_cxr_mask;
- if (oldreg != env->mmuregs[reg]) {
- /* we flush when the MMU context changes because
- QEMU has no MMU context support */
- tlb_flush(env, 1);
- }
- break;
- case 3: // Synchronous Fault Status Register with Clear
- case 4: // Synchronous Fault Address Register
- break;
- case 0x10: // TLB Replacement Control Register
- env->mmuregs[reg] = val & env->def->mmu_trcr_mask;
- break;
- case 0x13: // Synchronous Fault Status Register with Read and Clear
- env->mmuregs[3] = val & env->def->mmu_sfsr_mask;
- break;
- case 0x14: // Synchronous Fault Address Register
- env->mmuregs[4] = val;
- break;
- default:
- env->mmuregs[reg] = val;
- break;
- }
- if (oldreg != env->mmuregs[reg]) {
- DPRINTF_MMU("mmu change reg[%d]: 0x%08x -> 0x%08x\n",
- reg, oldreg, env->mmuregs[reg]);
- }
-#ifdef DEBUG_MMU
- dump_mmu(stdout, fprintf, env);
-#endif
- }
- break;
- case 5: // Turbosparc ITLB Diagnostic
- case 6: // Turbosparc DTLB Diagnostic
- case 7: // Turbosparc IOTLB Diagnostic
- break;
- case 0xa: /* User data access */
- switch(size) {
- case 1:
- stb_user(addr, val);
- break;
- case 2:
- stw_user(addr, val);
- break;
- default:
- case 4:
- stl_user(addr, val);
- break;
- case 8:
- stq_user(addr, val);
- break;
- }
- break;
- case 0xb: /* Supervisor data access */
- switch(size) {
- case 1:
- stb_kernel(addr, val);
- break;
- case 2:
- stw_kernel(addr, val);
- break;
- default:
- case 4:
- stl_kernel(addr, val);
- break;
- case 8:
- stq_kernel(addr, val);
- break;
- }
- break;
- case 0xc: /* I-cache tag */
- case 0xd: /* I-cache data */
- case 0xe: /* D-cache tag */
- case 0xf: /* D-cache data */
- case 0x10: /* I/D-cache flush page */
- case 0x11: /* I/D-cache flush segment */
- case 0x12: /* I/D-cache flush region */
- case 0x13: /* I/D-cache flush context */
- case 0x14: /* I/D-cache flush user */
- break;
- case 0x17: /* Block copy, sta access */
- {
- // val = src
- // addr = dst
- // copy 32 bytes
- unsigned int i;
- uint32_t src = val & ~3, dst = addr & ~3, temp;
-
- for (i = 0; i < 32; i += 4, src += 4, dst += 4) {
- temp = ldl_kernel(src);
- stl_kernel(dst, temp);
- }
- }
- break;
- case 0x1f: /* Block fill, stda access */
- {
- // addr = dst
- // fill 32 bytes with val
- unsigned int i;
- uint32_t dst = addr & 7;
-
- for (i = 0; i < 32; i += 8, dst += 8)
- stq_kernel(dst, val);
- }
- break;
- case 0x20: /* MMU passthrough */
- {
- switch(size) {
- case 1:
- stb_phys(addr, val);
- break;
- case 2:
- stw_phys(addr, val);
- break;
- case 4:
- default:
- stl_phys(addr, val);
- break;
- case 8:
- stq_phys(addr, val);
- break;
- }
- }
- break;
- case 0x21 ... 0x2f: /* MMU passthrough, 0x100000000 to 0xfffffffff */
- {
- switch(size) {
- case 1:
- stb_phys((target_phys_addr_t)addr
- | ((target_phys_addr_t)(asi & 0xf) << 32), val);
- break;
- case 2:
- stw_phys((target_phys_addr_t)addr
- | ((target_phys_addr_t)(asi & 0xf) << 32), val);
- break;
- case 4:
- default:
- stl_phys((target_phys_addr_t)addr
- | ((target_phys_addr_t)(asi & 0xf) << 32), val);
- break;
- case 8:
- stq_phys((target_phys_addr_t)addr
- | ((target_phys_addr_t)(asi & 0xf) << 32), val);
- break;
- }
- }
- break;
- case 0x30: // store buffer tags or Turbosparc secondary cache diagnostic
- case 0x31: // store buffer data, Ross RT620 I-cache flush or
- // Turbosparc snoop RAM
- case 0x32: // store buffer control or Turbosparc page table
- // descriptor diagnostic
- case 0x36: /* I-cache flash clear */
- case 0x37: /* D-cache flash clear */
- break;
- case 0x38: /* SuperSPARC MMU Breakpoint Control Registers*/
- {
- int reg = (addr >> 8) & 3;
-
- switch(reg) {
- case 0: /* Breakpoint Value (Addr) */
- env->mmubpregs[reg] = (val & 0xfffffffffULL);
- break;
- case 1: /* Breakpoint Mask */
- env->mmubpregs[reg] = (val & 0xfffffffffULL);
- break;
- case 2: /* Breakpoint Control */
- env->mmubpregs[reg] = (val & 0x7fULL);
- break;
- case 3: /* Breakpoint Status */
- env->mmubpregs[reg] = (val & 0xfULL);
- break;
- }
- DPRINTF_MMU("write breakpoint reg[%d] 0x%016x\n", reg,
- env->mmuregs[reg]);
- }
- break;
- case 0x49: /* SuperSPARC MMU Counter Breakpoint Value */
- env->mmubpctrv = val & 0xffffffff;
- break;
- case 0x4a: /* SuperSPARC MMU Counter Breakpoint Control */
- env->mmubpctrc = val & 0x3;
- break;
- case 0x4b: /* SuperSPARC MMU Counter Breakpoint Status */
- env->mmubpctrs = val & 0x3;
- break;
- case 0x4c: /* SuperSPARC MMU Breakpoint Action */
- env->mmubpaction = val & 0x1fff;
- break;
- case 8: /* User code access, XXX */
- case 9: /* Supervisor code access, XXX */
- default:
- do_unassigned_access(addr, 1, 0, asi, size);
- break;
- }
-#ifdef DEBUG_ASI
- dump_asi("write", addr, asi, size, val);
-#endif
-}
-
-#endif /* CONFIG_USER_ONLY */
-#else /* TARGET_SPARC64 */
-
-#ifdef CONFIG_USER_ONLY
-uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
-{
- uint64_t ret = 0;
-#if defined(DEBUG_ASI)
- target_ulong last_addr = addr;
-#endif
-
- if (asi < 0x80)
- raise_exception(TT_PRIV_ACT);
-
- helper_check_align(addr, size - 1);
- addr = asi_address_mask(env, asi, addr);
-
- switch (asi) {
- case 0x82: // Primary no-fault
- case 0x8a: // Primary no-fault LE
- if (page_check_range(addr, size, PAGE_READ) == -1) {
-#ifdef DEBUG_ASI
- dump_asi("read ", last_addr, asi, size, ret);
-#endif
- return 0;
- }
- // Fall through
- case 0x80: // Primary
- case 0x88: // Primary LE
- {
- switch(size) {
- case 1:
- ret = ldub_raw(addr);
- break;
- case 2:
- ret = lduw_raw(addr);
- break;
- case 4:
- ret = ldl_raw(addr);
- break;
- default:
- case 8:
- ret = ldq_raw(addr);
- break;
- }
- }
- break;
- case 0x83: // Secondary no-fault
- case 0x8b: // Secondary no-fault LE
- if (page_check_range(addr, size, PAGE_READ) == -1) {
-#ifdef DEBUG_ASI
- dump_asi("read ", last_addr, asi, size, ret);
-#endif
- return 0;
- }
- // Fall through
- case 0x81: // Secondary
- case 0x89: // Secondary LE
- // XXX
- break;
- default:
- break;
- }
-
- /* Convert from little endian */
- switch (asi) {
- case 0x88: // Primary LE
- case 0x89: // Secondary LE
- case 0x8a: // Primary no-fault LE
- case 0x8b: // Secondary no-fault LE
- switch(size) {
- case 2:
- ret = bswap16(ret);
- break;
- case 4:
- ret = bswap32(ret);
- break;
- case 8:
- ret = bswap64(ret);
- break;
- default:
- break;
- }
- default:
- break;
- }
-
- /* Convert to signed number */
- if (sign) {
- switch(size) {
- case 1:
- ret = (int8_t) ret;
- break;
- case 2:
- ret = (int16_t) ret;
- break;
- case 4:
- ret = (int32_t) ret;
- break;
- default:
- break;
- }
- }
-#ifdef DEBUG_ASI
- dump_asi("read ", last_addr, asi, size, ret);
-#endif
- return ret;
-}
-
-void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
-{
-#ifdef DEBUG_ASI
- dump_asi("write", addr, asi, size, val);
-#endif
- if (asi < 0x80)
- raise_exception(TT_PRIV_ACT);
-
- helper_check_align(addr, size - 1);
- addr = asi_address_mask(env, asi, addr);
-
- /* Convert to little endian */
- switch (asi) {
- case 0x88: // Primary LE
- case 0x89: // Secondary LE
- switch(size) {
- case 2:
- val = bswap16(val);
- break;
- case 4:
- val = bswap32(val);
- break;
- case 8:
- val = bswap64(val);
- break;
- default:
- break;
- }
- default:
- break;
- }
-
- switch(asi) {
- case 0x80: // Primary
- case 0x88: // Primary LE
- {
- switch(size) {
- case 1:
- stb_raw(addr, val);
- break;
- case 2:
- stw_raw(addr, val);
- break;
- case 4:
- stl_raw(addr, val);
- break;
- case 8:
- default:
- stq_raw(addr, val);
- break;
- }
- }
- break;
- case 0x81: // Secondary
- case 0x89: // Secondary LE
- // XXX
- return;
-
- case 0x82: // Primary no-fault, RO
- case 0x83: // Secondary no-fault, RO
- case 0x8a: // Primary no-fault LE, RO
- case 0x8b: // Secondary no-fault LE, RO
- default:
- do_unassigned_access(addr, 1, 0, 1, size);
- return;
- }
-}
-
-#else /* CONFIG_USER_ONLY */
-
-uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
-{
- uint64_t ret = 0;
-#if defined(DEBUG_ASI)
- target_ulong last_addr = addr;
-#endif
-
- asi &= 0xff;
-
- if ((asi < 0x80 && (env->pstate & PS_PRIV) == 0)
- || (cpu_has_hypervisor(env)
- && asi >= 0x30 && asi < 0x80
- && !(env->hpstate & HS_PRIV)))
- raise_exception(TT_PRIV_ACT);
-
- helper_check_align(addr, size - 1);
- addr = asi_address_mask(env, asi, addr);
-
- /* process nonfaulting loads first */
- if ((asi & 0xf6) == 0x82) {
- int mmu_idx;
-
- /* secondary space access has lowest asi bit equal to 1 */
- if (env->pstate & PS_PRIV) {
- mmu_idx = (asi & 1) ? MMU_KERNEL_SECONDARY_IDX : MMU_KERNEL_IDX;
- } else {
- mmu_idx = (asi & 1) ? MMU_USER_SECONDARY_IDX : MMU_USER_IDX;
- }
-
- if (cpu_get_phys_page_nofault(env, addr, mmu_idx) == -1ULL) {
-#ifdef DEBUG_ASI
- dump_asi("read ", last_addr, asi, size, ret);
-#endif
- /* env->exception_index is set in get_physical_address_data(). */
- raise_exception(env->exception_index);
- }
-
- /* convert nonfaulting load ASIs to normal load ASIs */
- asi &= ~0x02;
- }
-
- switch (asi) {
- case 0x10: // As if user primary
- case 0x11: // As if user secondary
- case 0x18: // As if user primary LE
- case 0x19: // As if user secondary LE
- case 0x80: // Primary
- case 0x81: // Secondary
- case 0x88: // Primary LE
- case 0x89: // Secondary LE
- case 0xe2: // UA2007 Primary block init
- case 0xe3: // UA2007 Secondary block init
- if ((asi & 0x80) && (env->pstate & PS_PRIV)) {
- if (cpu_hypervisor_mode(env)) {
- switch(size) {
- case 1:
- ret = ldub_hypv(addr);
- break;
- case 2:
- ret = lduw_hypv(addr);
- break;
- case 4:
- ret = ldl_hypv(addr);
- break;
- default:
- case 8:
- ret = ldq_hypv(addr);
- break;
- }
- } else {
- /* secondary space access has lowest asi bit equal to 1 */
- if (asi & 1) {
- switch(size) {
- case 1:
- ret = ldub_kernel_secondary(addr);
- break;
- case 2:
- ret = lduw_kernel_secondary(addr);
- break;
- case 4:
- ret = ldl_kernel_secondary(addr);
- break;
- default:
- case 8:
- ret = ldq_kernel_secondary(addr);
- break;
- }
- } else {
- switch(size) {
- case 1:
- ret = ldub_kernel(addr);
- break;
- case 2:
- ret = lduw_kernel(addr);
- break;
- case 4:
- ret = ldl_kernel(addr);
- break;
- default:
- case 8:
- ret = ldq_kernel(addr);
- break;
- }
- }
- }
- } else {
- /* secondary space access has lowest asi bit equal to 1 */
- if (asi & 1) {
- switch(size) {
- case 1:
- ret = ldub_user_secondary(addr);
- break;
- case 2:
- ret = lduw_user_secondary(addr);
- break;
- case 4:
- ret = ldl_user_secondary(addr);
- break;
- default:
- case 8:
- ret = ldq_user_secondary(addr);
- break;
- }
- } else {
- switch(size) {
- case 1:
- ret = ldub_user(addr);
- break;
- case 2:
- ret = lduw_user(addr);
- break;
- case 4:
- ret = ldl_user(addr);
- break;
- default:
- case 8:
- ret = ldq_user(addr);
- break;
- }
- }
- }
- break;
- case 0x14: // Bypass
- case 0x15: // Bypass, non-cacheable
- case 0x1c: // Bypass LE
- case 0x1d: // Bypass, non-cacheable LE
- {
- switch(size) {
- case 1:
- ret = ldub_phys(addr);
- break;
- case 2:
- ret = lduw_phys(addr);
- break;
- case 4:
- ret = ldl_phys(addr);
- break;
- default:
- case 8:
- ret = ldq_phys(addr);
- break;
- }
- break;
- }
- case 0x24: // Nucleus quad LDD 128 bit atomic
- case 0x2c: // Nucleus quad LDD 128 bit atomic LE
- // Only ldda allowed
- raise_exception(TT_ILL_INSN);
- return 0;
- case 0x04: // Nucleus
- case 0x0c: // Nucleus Little Endian (LE)
- {
- switch(size) {
- case 1:
- ret = ldub_nucleus(addr);
- break;
- case 2:
- ret = lduw_nucleus(addr);
- break;
- case 4:
- ret = ldl_nucleus(addr);
- break;
- default:
- case 8:
- ret = ldq_nucleus(addr);
- break;
- }
- break;
- }
- case 0x4a: // UPA config
- // XXX
- break;
- case 0x45: // LSU
- ret = env->lsu;
- break;
- case 0x50: // I-MMU regs
- {
- int reg = (addr >> 3) & 0xf;
-
- if (reg == 0) {
- // I-TSB Tag Target register
- ret = ultrasparc_tag_target(env->immu.tag_access);
- } else {
- ret = env->immuregs[reg];
- }
-
- break;
- }
- case 0x51: // I-MMU 8k TSB pointer
- {
- // env->immuregs[5] holds I-MMU TSB register value
- // env->immuregs[6] holds I-MMU Tag Access register value
- ret = ultrasparc_tsb_pointer(env->immu.tsb, env->immu.tag_access,
- 8*1024);
- break;
- }
- case 0x52: // I-MMU 64k TSB pointer
- {
- // env->immuregs[5] holds I-MMU TSB register value
- // env->immuregs[6] holds I-MMU Tag Access register value
- ret = ultrasparc_tsb_pointer(env->immu.tsb, env->immu.tag_access,
- 64*1024);
- break;
- }
- case 0x55: // I-MMU data access
- {
- int reg = (addr >> 3) & 0x3f;
-
- ret = env->itlb[reg].tte;
- break;
- }
- case 0x56: // I-MMU tag read
- {
- int reg = (addr >> 3) & 0x3f;
-
- ret = env->itlb[reg].tag;
- break;
- }
- case 0x58: // D-MMU regs
- {
- int reg = (addr >> 3) & 0xf;
-
- if (reg == 0) {
- // D-TSB Tag Target register
- ret = ultrasparc_tag_target(env->dmmu.tag_access);
- } else {
- ret = env->dmmuregs[reg];
- }
- break;
- }
- case 0x59: // D-MMU 8k TSB pointer
- {
- // env->dmmuregs[5] holds D-MMU TSB register value
- // env->dmmuregs[6] holds D-MMU Tag Access register value
- ret = ultrasparc_tsb_pointer(env->dmmu.tsb, env->dmmu.tag_access,
- 8*1024);
- break;
- }
- case 0x5a: // D-MMU 64k TSB pointer
- {
- // env->dmmuregs[5] holds D-MMU TSB register value
- // env->dmmuregs[6] holds D-MMU Tag Access register value
- ret = ultrasparc_tsb_pointer(env->dmmu.tsb, env->dmmu.tag_access,
- 64*1024);
- break;
- }
- case 0x5d: // D-MMU data access
- {
- int reg = (addr >> 3) & 0x3f;
-
- ret = env->dtlb[reg].tte;
- break;
- }
- case 0x5e: // D-MMU tag read
- {
- int reg = (addr >> 3) & 0x3f;
-
- ret = env->dtlb[reg].tag;
- break;
- }
- case 0x46: // D-cache data
- case 0x47: // D-cache tag access
- case 0x4b: // E-cache error enable
- case 0x4c: // E-cache asynchronous fault status
- case 0x4d: // E-cache asynchronous fault address
- case 0x4e: // E-cache tag data
- case 0x66: // I-cache instruction access
- case 0x67: // I-cache tag access
- case 0x6e: // I-cache predecode
- case 0x6f: // I-cache LRU etc.
- case 0x76: // E-cache tag
- case 0x7e: // E-cache tag
- break;
- case 0x5b: // D-MMU data pointer
- case 0x48: // Interrupt dispatch, RO
- case 0x49: // Interrupt data receive
- case 0x7f: // Incoming interrupt vector, RO
- // XXX
- break;
- case 0x54: // I-MMU data in, WO
- case 0x57: // I-MMU demap, WO
- case 0x5c: // D-MMU data in, WO
- case 0x5f: // D-MMU demap, WO
- case 0x77: // Interrupt vector, WO
- default:
- do_unassigned_access(addr, 0, 0, 1, size);
- ret = 0;
- break;
- }
-
- /* Convert from little endian */
- switch (asi) {
- case 0x0c: // Nucleus Little Endian (LE)
- case 0x18: // As if user primary LE
- case 0x19: // As if user secondary LE
- case 0x1c: // Bypass LE
- case 0x1d: // Bypass, non-cacheable LE
- case 0x88: // Primary LE
- case 0x89: // Secondary LE
- switch(size) {
- case 2:
- ret = bswap16(ret);
- break;
- case 4:
- ret = bswap32(ret);
- break;
- case 8:
- ret = bswap64(ret);
- break;
- default:
- break;
- }
- default:
- break;
- }
-
- /* Convert to signed number */
- if (sign) {
- switch(size) {
- case 1:
- ret = (int8_t) ret;
- break;
- case 2:
- ret = (int16_t) ret;
- break;
- case 4:
- ret = (int32_t) ret;
- break;
- default:
- break;
- }
- }
-#ifdef DEBUG_ASI
- dump_asi("read ", last_addr, asi, size, ret);
-#endif
- return ret;
-}
-
-void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
-{
-#ifdef DEBUG_ASI
- dump_asi("write", addr, asi, size, val);
-#endif
-
- asi &= 0xff;
-
- if ((asi < 0x80 && (env->pstate & PS_PRIV) == 0)
- || (cpu_has_hypervisor(env)
- && asi >= 0x30 && asi < 0x80
- && !(env->hpstate & HS_PRIV)))
- raise_exception(TT_PRIV_ACT);
-
- helper_check_align(addr, size - 1);
- addr = asi_address_mask(env, asi, addr);
-
- /* Convert to little endian */
- switch (asi) {
- case 0x0c: // Nucleus Little Endian (LE)
- case 0x18: // As if user primary LE
- case 0x19: // As if user secondary LE
- case 0x1c: // Bypass LE
- case 0x1d: // Bypass, non-cacheable LE
- case 0x88: // Primary LE
- case 0x89: // Secondary LE
- switch(size) {
- case 2:
- val = bswap16(val);
- break;
- case 4:
- val = bswap32(val);
- break;
- case 8:
- val = bswap64(val);
- break;
- default:
- break;
- }
- default:
- break;
- }
-
- switch(asi) {
- case 0x10: // As if user primary
- case 0x11: // As if user secondary
- case 0x18: // As if user primary LE
- case 0x19: // As if user secondary LE
- case 0x80: // Primary
- case 0x81: // Secondary
- case 0x88: // Primary LE
- case 0x89: // Secondary LE
- case 0xe2: // UA2007 Primary block init
- case 0xe3: // UA2007 Secondary block init
- if ((asi & 0x80) && (env->pstate & PS_PRIV)) {
- if (cpu_hypervisor_mode(env)) {
- switch(size) {
- case 1:
- stb_hypv(addr, val);
- break;
- case 2:
- stw_hypv(addr, val);
- break;
- case 4:
- stl_hypv(addr, val);
- break;
- case 8:
- default:
- stq_hypv(addr, val);
- break;
- }
- } else {
- /* secondary space access has lowest asi bit equal to 1 */
- if (asi & 1) {
- switch(size) {
- case 1:
- stb_kernel_secondary(addr, val);
- break;
- case 2:
- stw_kernel_secondary(addr, val);
- break;
- case 4:
- stl_kernel_secondary(addr, val);
- break;
- case 8:
- default:
- stq_kernel_secondary(addr, val);
- break;
- }
- } else {
- switch(size) {
- case 1:
- stb_kernel(addr, val);
- break;
- case 2:
- stw_kernel(addr, val);
- break;
- case 4:
- stl_kernel(addr, val);
- break;
- case 8:
- default:
- stq_kernel(addr, val);
- break;
- }
- }
- }
- } else {
- /* secondary space access has lowest asi bit equal to 1 */
- if (asi & 1) {
- switch(size) {
- case 1:
- stb_user_secondary(addr, val);
- break;
- case 2:
- stw_user_secondary(addr, val);
- break;
- case 4:
- stl_user_secondary(addr, val);
- break;
- case 8:
- default:
- stq_user_secondary(addr, val);
- break;
- }
- } else {
- switch(size) {
- case 1:
- stb_user(addr, val);
- break;
- case 2:
- stw_user(addr, val);
- break;
- case 4:
- stl_user(addr, val);
- break;
- case 8:
- default:
- stq_user(addr, val);
- break;
- }
- }
- }
- break;
- case 0x14: // Bypass
- case 0x15: // Bypass, non-cacheable
- case 0x1c: // Bypass LE
- case 0x1d: // Bypass, non-cacheable LE
- {
- switch(size) {
- case 1:
- stb_phys(addr, val);
- break;
- case 2:
- stw_phys(addr, val);
- break;
- case 4:
- stl_phys(addr, val);
- break;
- case 8:
- default:
- stq_phys(addr, val);
- break;
- }
- }
- return;
- case 0x24: // Nucleus quad LDD 128 bit atomic
- case 0x2c: // Nucleus quad LDD 128 bit atomic LE
- // Only ldda allowed
- raise_exception(TT_ILL_INSN);
- return;
- case 0x04: // Nucleus
- case 0x0c: // Nucleus Little Endian (LE)
- {
- switch(size) {
- case 1:
- stb_nucleus(addr, val);
- break;
- case 2:
- stw_nucleus(addr, val);
- break;
- case 4:
- stl_nucleus(addr, val);
- break;
- default:
- case 8:
- stq_nucleus(addr, val);
- break;
- }
- break;
- }
-
- case 0x4a: // UPA config
- // XXX
- return;
- case 0x45: // LSU
- {
- uint64_t oldreg;
-
- oldreg = env->lsu;
- env->lsu = val & (DMMU_E | IMMU_E);
- // Mappings generated during D/I MMU disabled mode are
- // invalid in normal mode
- if (oldreg != env->lsu) {
- DPRINTF_MMU("LSU change: 0x%" PRIx64 " -> 0x%" PRIx64 "\n",
- oldreg, env->lsu);
-#ifdef DEBUG_MMU
- dump_mmu(stdout, fprintf, env1);
-#endif
- tlb_flush(env, 1);
- }
- return;
- }
- case 0x50: // I-MMU regs
- {
- int reg = (addr >> 3) & 0xf;
- uint64_t oldreg;
-
- oldreg = env->immuregs[reg];
- switch(reg) {
- case 0: // RO
- return;
- case 1: // Not in I-MMU
- case 2:
- return;
- case 3: // SFSR
- if ((val & 1) == 0)
- val = 0; // Clear SFSR
- env->immu.sfsr = val;
- break;
- case 4: // RO
- return;
- case 5: // TSB access
- DPRINTF_MMU("immu TSB write: 0x%016" PRIx64 " -> 0x%016"
- PRIx64 "\n", env->immu.tsb, val);
- env->immu.tsb = val;
- break;
- case 6: // Tag access
- env->immu.tag_access = val;
- break;
- case 7:
- case 8:
- return;
- default:
- break;
- }
-
- if (oldreg != env->immuregs[reg]) {
- DPRINTF_MMU("immu change reg[%d]: 0x%016" PRIx64 " -> 0x%016"
- PRIx64 "\n", reg, oldreg, env->immuregs[reg]);
- }
-#ifdef DEBUG_MMU
- dump_mmu(stdout, fprintf, env);
-#endif
- return;
- }
- case 0x54: // I-MMU data in
- replace_tlb_1bit_lru(env->itlb, env->immu.tag_access, val, "immu", env);
- return;
- case 0x55: // I-MMU data access
- {
- // TODO: auto demap
-
- unsigned int i = (addr >> 3) & 0x3f;
-
- replace_tlb_entry(&env->itlb[i], env->immu.tag_access, val, env);
-
-#ifdef DEBUG_MMU
- DPRINTF_MMU("immu data access replaced entry [%i]\n", i);
- dump_mmu(stdout, fprintf, env);
-#endif
- return;
- }
- case 0x57: // I-MMU demap
- demap_tlb(env->itlb, addr, "immu", env);
- return;
- case 0x58: // D-MMU regs
- {
- int reg = (addr >> 3) & 0xf;
- uint64_t oldreg;
-
- oldreg = env->dmmuregs[reg];
- switch(reg) {
- case 0: // RO
- case 4:
- return;
- case 3: // SFSR
- if ((val & 1) == 0) {
- val = 0; // Clear SFSR, Fault address
- env->dmmu.sfar = 0;
- }
- env->dmmu.sfsr = val;
- break;
- case 1: // Primary context
- env->dmmu.mmu_primary_context = val;
- /* can be optimized to only flush MMU_USER_IDX
- and MMU_KERNEL_IDX entries */
- tlb_flush(env, 1);
- break;
- case 2: // Secondary context
- env->dmmu.mmu_secondary_context = val;
- /* can be optimized to only flush MMU_USER_SECONDARY_IDX
- and MMU_KERNEL_SECONDARY_IDX entries */
- tlb_flush(env, 1);
- break;
- case 5: // TSB access
- DPRINTF_MMU("dmmu TSB write: 0x%016" PRIx64 " -> 0x%016"
- PRIx64 "\n", env->dmmu.tsb, val);
- env->dmmu.tsb = val;
- break;
- case 6: // Tag access
- env->dmmu.tag_access = val;
- break;
- case 7: // Virtual Watchpoint
- case 8: // Physical Watchpoint
- default:
- env->dmmuregs[reg] = val;
- break;
- }
-
- if (oldreg != env->dmmuregs[reg]) {
- DPRINTF_MMU("dmmu change reg[%d]: 0x%016" PRIx64 " -> 0x%016"
- PRIx64 "\n", reg, oldreg, env->dmmuregs[reg]);
- }
-#ifdef DEBUG_MMU
- dump_mmu(stdout, fprintf, env);
-#endif
- return;
- }
- case 0x5c: // D-MMU data in
- replace_tlb_1bit_lru(env->dtlb, env->dmmu.tag_access, val, "dmmu", env);
- return;
- case 0x5d: // D-MMU data access
- {
- unsigned int i = (addr >> 3) & 0x3f;
-
- replace_tlb_entry(&env->dtlb[i], env->dmmu.tag_access, val, env);
-
-#ifdef DEBUG_MMU
- DPRINTF_MMU("dmmu data access replaced entry [%i]\n", i);
- dump_mmu(stdout, fprintf, env);
-#endif
- return;
- }
- case 0x5f: // D-MMU demap
- demap_tlb(env->dtlb, addr, "dmmu", env);
- return;
- case 0x49: // Interrupt data receive
- // XXX
- return;
- case 0x46: // D-cache data
- case 0x47: // D-cache tag access
- case 0x4b: // E-cache error enable
- case 0x4c: // E-cache asynchronous fault status
- case 0x4d: // E-cache asynchronous fault address
- case 0x4e: // E-cache tag data
- case 0x66: // I-cache instruction access
- case 0x67: // I-cache tag access
- case 0x6e: // I-cache predecode
- case 0x6f: // I-cache LRU etc.
- case 0x76: // E-cache tag
- case 0x7e: // E-cache tag
- return;
- case 0x51: // I-MMU 8k TSB pointer, RO
- case 0x52: // I-MMU 64k TSB pointer, RO
- case 0x56: // I-MMU tag read, RO
- case 0x59: // D-MMU 8k TSB pointer, RO
- case 0x5a: // D-MMU 64k TSB pointer, RO
- case 0x5b: // D-MMU data pointer, RO
- case 0x5e: // D-MMU tag read, RO
- case 0x48: // Interrupt dispatch, RO
- case 0x7f: // Incoming interrupt vector, RO
- case 0x82: // Primary no-fault, RO
- case 0x83: // Secondary no-fault, RO
- case 0x8a: // Primary no-fault LE, RO
- case 0x8b: // Secondary no-fault LE, RO
- default:
- do_unassigned_access(addr, 1, 0, 1, size);
- return;
- }
-}
-#endif /* CONFIG_USER_ONLY */
-
-void helper_ldda_asi(target_ulong addr, int asi, int rd)
-{
- if ((asi < 0x80 && (env->pstate & PS_PRIV) == 0)
- || (cpu_has_hypervisor(env)
- && asi >= 0x30 && asi < 0x80
- && !(env->hpstate & HS_PRIV)))
- raise_exception(TT_PRIV_ACT);
-
- addr = asi_address_mask(env, asi, addr);
-
- switch (asi) {
-#if !defined(CONFIG_USER_ONLY)
- case 0x24: // Nucleus quad LDD 128 bit atomic
- case 0x2c: // Nucleus quad LDD 128 bit atomic LE
- helper_check_align(addr, 0xf);
- if (rd == 0) {
- env->gregs[1] = ldq_nucleus(addr + 8);
- if (asi == 0x2c)
- bswap64s(&env->gregs[1]);
- } else if (rd < 8) {
- env->gregs[rd] = ldq_nucleus(addr);
- env->gregs[rd + 1] = ldq_nucleus(addr + 8);
- if (asi == 0x2c) {
- bswap64s(&env->gregs[rd]);
- bswap64s(&env->gregs[rd + 1]);
- }
- } else {
- env->regwptr[rd] = ldq_nucleus(addr);
- env->regwptr[rd + 1] = ldq_nucleus(addr + 8);
- if (asi == 0x2c) {
- bswap64s(&env->regwptr[rd]);
- bswap64s(&env->regwptr[rd + 1]);
- }
- }
- break;
-#endif
- default:
- helper_check_align(addr, 0x3);
- if (rd == 0)
- env->gregs[1] = helper_ld_asi(addr + 4, asi, 4, 0);
- else if (rd < 8) {
- env->gregs[rd] = helper_ld_asi(addr, asi, 4, 0);
- env->gregs[rd + 1] = helper_ld_asi(addr + 4, asi, 4, 0);
- } else {
- env->regwptr[rd] = helper_ld_asi(addr, asi, 4, 0);
- env->regwptr[rd + 1] = helper_ld_asi(addr + 4, asi, 4, 0);
- }
- break;
- }
-}
-
-void helper_ldf_asi(target_ulong addr, int asi, int size, int rd)
-{
- unsigned int i;
- CPU_DoubleU u;
-
- helper_check_align(addr, 3);
- addr = asi_address_mask(env, asi, addr);
-
- switch (asi) {
- case 0xf0: /* UA2007/JPS1 Block load primary */
- case 0xf1: /* UA2007/JPS1 Block load secondary */
- case 0xf8: /* UA2007/JPS1 Block load primary LE */
- case 0xf9: /* UA2007/JPS1 Block load secondary LE */
- if (rd & 7) {
- raise_exception(TT_ILL_INSN);
- return;
- }
- helper_check_align(addr, 0x3f);
- for (i = 0; i < 16; i++) {
- *(uint32_t *)&env->fpr[rd++] = helper_ld_asi(addr, asi & 0x8f, 4,
- 0);
- addr += 4;
- }
-
- return;
- case 0x16: /* UA2007 Block load primary, user privilege */
- case 0x17: /* UA2007 Block load secondary, user privilege */
- case 0x1e: /* UA2007 Block load primary LE, user privilege */
- case 0x1f: /* UA2007 Block load secondary LE, user privilege */
- case 0x70: /* JPS1 Block load primary, user privilege */
- case 0x71: /* JPS1 Block load secondary, user privilege */
- case 0x78: /* JPS1 Block load primary LE, user privilege */
- case 0x79: /* JPS1 Block load secondary LE, user privilege */
- if (rd & 7) {
- raise_exception(TT_ILL_INSN);
- return;
- }
- helper_check_align(addr, 0x3f);
- for (i = 0; i < 16; i++) {
- *(uint32_t *)&env->fpr[rd++] = helper_ld_asi(addr, asi & 0x19, 4,
- 0);
- addr += 4;
- }
-
- return;
- default:
- break;
- }
-
- switch(size) {
- default:
- case 4:
- *((uint32_t *)&env->fpr[rd]) = helper_ld_asi(addr, asi, size, 0);
- break;
- case 8:
- u.ll = helper_ld_asi(addr, asi, size, 0);
- *((uint32_t *)&env->fpr[rd++]) = u.l.upper;
- *((uint32_t *)&env->fpr[rd++]) = u.l.lower;
- break;
- case 16:
- u.ll = helper_ld_asi(addr, asi, 8, 0);
- *((uint32_t *)&env->fpr[rd++]) = u.l.upper;
- *((uint32_t *)&env->fpr[rd++]) = u.l.lower;
- u.ll = helper_ld_asi(addr + 8, asi, 8, 0);
- *((uint32_t *)&env->fpr[rd++]) = u.l.upper;
- *((uint32_t *)&env->fpr[rd++]) = u.l.lower;
- break;
- }
-}
-
-void helper_stf_asi(target_ulong addr, int asi, int size, int rd)
-{
- unsigned int i;
- target_ulong val = 0;
- CPU_DoubleU u;
-
- helper_check_align(addr, 3);
- addr = asi_address_mask(env, asi, addr);
-
- switch (asi) {
- case 0xe0: /* UA2007/JPS1 Block commit store primary (cache flush) */
- case 0xe1: /* UA2007/JPS1 Block commit store secondary (cache flush) */
- case 0xf0: /* UA2007/JPS1 Block store primary */
- case 0xf1: /* UA2007/JPS1 Block store secondary */
- case 0xf8: /* UA2007/JPS1 Block store primary LE */
- case 0xf9: /* UA2007/JPS1 Block store secondary LE */
- if (rd & 7) {
- raise_exception(TT_ILL_INSN);
- return;
- }
- helper_check_align(addr, 0x3f);
- for (i = 0; i < 16; i++) {
- val = *(uint32_t *)&env->fpr[rd++];
- helper_st_asi(addr, val, asi & 0x8f, 4);
- addr += 4;
- }
-
- return;
- case 0x16: /* UA2007 Block load primary, user privilege */
- case 0x17: /* UA2007 Block load secondary, user privilege */
- case 0x1e: /* UA2007 Block load primary LE, user privilege */
- case 0x1f: /* UA2007 Block load secondary LE, user privilege */
- case 0x70: /* JPS1 Block store primary, user privilege */
- case 0x71: /* JPS1 Block store secondary, user privilege */
- case 0x78: /* JPS1 Block load primary LE, user privilege */
- case 0x79: /* JPS1 Block load secondary LE, user privilege */
- if (rd & 7) {
- raise_exception(TT_ILL_INSN);
- return;
- }
- helper_check_align(addr, 0x3f);
- for (i = 0; i < 16; i++) {
- val = *(uint32_t *)&env->fpr[rd++];
- helper_st_asi(addr, val, asi & 0x19, 4);
- addr += 4;
- }
-
- return;
- default:
- break;
- }
-
- switch(size) {
- default:
- case 4:
- helper_st_asi(addr, *(uint32_t *)&env->fpr[rd], asi, size);
- break;
- case 8:
- u.l.upper = *(uint32_t *)&env->fpr[rd++];
- u.l.lower = *(uint32_t *)&env->fpr[rd++];
- helper_st_asi(addr, u.ll, asi, size);
- break;
- case 16:
- u.l.upper = *(uint32_t *)&env->fpr[rd++];
- u.l.lower = *(uint32_t *)&env->fpr[rd++];
- helper_st_asi(addr, u.ll, asi, 8);
- u.l.upper = *(uint32_t *)&env->fpr[rd++];
- u.l.lower = *(uint32_t *)&env->fpr[rd++];
- helper_st_asi(addr + 8, u.ll, asi, 8);
- break;
- }
-}
-
-target_ulong helper_cas_asi(target_ulong addr, target_ulong val1,
- target_ulong val2, uint32_t asi)
-{
- target_ulong ret;
-
- val2 &= 0xffffffffUL;
- ret = helper_ld_asi(addr, asi, 4, 0);
- ret &= 0xffffffffUL;
- if (val2 == ret)
- helper_st_asi(addr, val1 & 0xffffffffUL, asi, 4);
- return ret;
-}
-
-target_ulong helper_casx_asi(target_ulong addr, target_ulong val1,
- target_ulong val2, uint32_t asi)
-{
- target_ulong ret;
-
- ret = helper_ld_asi(addr, asi, 8, 0);
- if (val2 == ret)
- helper_st_asi(addr, val1, asi, 8);
- return ret;
-}
-#endif /* TARGET_SPARC64 */
-
-#ifndef TARGET_SPARC64
-void helper_rett(void)
-{
- unsigned int cwp;
-
- if (env->psret == 1)
- raise_exception(TT_ILL_INSN);
-
- env->psret = 1;
- cwp = cwp_inc(env->cwp + 1) ;
- if (env->wim & (1 << cwp)) {
- raise_exception(TT_WIN_UNF);
- }
- set_cwp(cwp);
- env->psrs = env->psrps;
-}
-#endif
-
-static target_ulong helper_udiv_common(target_ulong a, target_ulong b, int cc)
-{
- int overflow = 0;
- uint64_t x0;
- uint32_t x1;
-
- x0 = (a & 0xffffffff) | ((int64_t) (env->y) << 32);
- x1 = (b & 0xffffffff);
-
- if (x1 == 0) {
- raise_exception(TT_DIV_ZERO);
- }
-
- x0 = x0 / x1;
- if (x0 > 0xffffffff) {
- x0 = 0xffffffff;
- overflow = 1;
- }
-
- if (cc) {
- env->cc_dst = x0;
- env->cc_src2 = overflow;
- env->cc_op = CC_OP_DIV;
- }
- return x0;
-}
-
-target_ulong helper_udiv(target_ulong a, target_ulong b)
-{
- return helper_udiv_common(a, b, 0);
-}
-
-target_ulong helper_udiv_cc(target_ulong a, target_ulong b)
-{
- return helper_udiv_common(a, b, 1);
-}
-
-static target_ulong helper_sdiv_common(target_ulong a, target_ulong b, int cc)
-{
- int overflow = 0;
- int64_t x0;
- int32_t x1;
-
- x0 = (a & 0xffffffff) | ((int64_t) (env->y) << 32);
- x1 = (b & 0xffffffff);
-
- if (x1 == 0) {
- raise_exception(TT_DIV_ZERO);
- }
-
- x0 = x0 / x1;
- if ((int32_t) x0 != x0) {
- x0 = x0 < 0 ? 0x80000000: 0x7fffffff;
- overflow = 1;
- }
-
- if (cc) {
- env->cc_dst = x0;
- env->cc_src2 = overflow;
- env->cc_op = CC_OP_DIV;
- }
- return x0;
-}
-
-target_ulong helper_sdiv(target_ulong a, target_ulong b)
-{
- return helper_sdiv_common(a, b, 0);
-}
-
-target_ulong helper_sdiv_cc(target_ulong a, target_ulong b)
-{
- return helper_sdiv_common(a, b, 1);
-}
-
-void helper_stdf(target_ulong addr, int mem_idx)
-{
- helper_check_align(addr, 7);
-#if !defined(CONFIG_USER_ONLY)
- switch (mem_idx) {
- case MMU_USER_IDX:
- stfq_user(addr, DT0);
- break;
- case MMU_KERNEL_IDX:
- stfq_kernel(addr, DT0);
- break;
-#ifdef TARGET_SPARC64
- case MMU_HYPV_IDX:
- stfq_hypv(addr, DT0);
- break;
-#endif
- default:
- DPRINTF_MMU("helper_stdf: need to check MMU idx %d\n", mem_idx);
- break;
- }
-#else
- stfq_raw(address_mask(env, addr), DT0);
-#endif
-}
-
-void helper_lddf(target_ulong addr, int mem_idx)
-{
- helper_check_align(addr, 7);
-#if !defined(CONFIG_USER_ONLY)
- switch (mem_idx) {
- case MMU_USER_IDX:
- DT0 = ldfq_user(addr);
- break;
- case MMU_KERNEL_IDX:
- DT0 = ldfq_kernel(addr);
- break;
-#ifdef TARGET_SPARC64
- case MMU_HYPV_IDX:
- DT0 = ldfq_hypv(addr);
- break;
-#endif
- default:
- DPRINTF_MMU("helper_lddf: need to check MMU idx %d\n", mem_idx);
- break;
- }
-#else
- DT0 = ldfq_raw(address_mask(env, addr));
-#endif
-}
-
-void helper_ldqf(target_ulong addr, int mem_idx)
-{
- // XXX add 128 bit load
- CPU_QuadU u;
-
- helper_check_align(addr, 7);
-#if !defined(CONFIG_USER_ONLY)
- switch (mem_idx) {
- case MMU_USER_IDX:
- u.ll.upper = ldq_user(addr);
- u.ll.lower = ldq_user(addr + 8);
- QT0 = u.q;
- break;
- case MMU_KERNEL_IDX:
- u.ll.upper = ldq_kernel(addr);
- u.ll.lower = ldq_kernel(addr + 8);
- QT0 = u.q;
- break;
-#ifdef TARGET_SPARC64
- case MMU_HYPV_IDX:
- u.ll.upper = ldq_hypv(addr);
- u.ll.lower = ldq_hypv(addr + 8);
- QT0 = u.q;
- break;
-#endif
- default:
- DPRINTF_MMU("helper_ldqf: need to check MMU idx %d\n", mem_idx);
- break;
- }
-#else
- u.ll.upper = ldq_raw(address_mask(env, addr));
- u.ll.lower = ldq_raw(address_mask(env, addr + 8));
- QT0 = u.q;
-#endif
-}
-
-void helper_stqf(target_ulong addr, int mem_idx)
-{
- // XXX add 128 bit store
- CPU_QuadU u;
-
- helper_check_align(addr, 7);
-#if !defined(CONFIG_USER_ONLY)
- switch (mem_idx) {
- case MMU_USER_IDX:
- u.q = QT0;
- stq_user(addr, u.ll.upper);
- stq_user(addr + 8, u.ll.lower);
- break;
- case MMU_KERNEL_IDX:
- u.q = QT0;
- stq_kernel(addr, u.ll.upper);
- stq_kernel(addr + 8, u.ll.lower);
- break;
-#ifdef TARGET_SPARC64
- case MMU_HYPV_IDX:
- u.q = QT0;
- stq_hypv(addr, u.ll.upper);
- stq_hypv(addr + 8, u.ll.lower);
- break;
-#endif
- default:
- DPRINTF_MMU("helper_stqf: need to check MMU idx %d\n", mem_idx);
- break;
- }
-#else
- u.q = QT0;
- stq_raw(address_mask(env, addr), u.ll.upper);
- stq_raw(address_mask(env, addr + 8), u.ll.lower);
-#endif
-}
-
-static inline void set_fsr(void)
-{
- int rnd_mode;
-
- switch (env->fsr & FSR_RD_MASK) {
- case FSR_RD_NEAREST:
- rnd_mode = float_round_nearest_even;
- break;
- default:
- case FSR_RD_ZERO:
- rnd_mode = float_round_to_zero;
- break;
- case FSR_RD_POS:
- rnd_mode = float_round_up;
- break;
- case FSR_RD_NEG:
- rnd_mode = float_round_down;
- break;
- }
- set_float_rounding_mode(rnd_mode, &env->fp_status);
-}
-
-void helper_ldfsr(uint32_t new_fsr)
-{
- env->fsr = (new_fsr & FSR_LDFSR_MASK) | (env->fsr & FSR_LDFSR_OLDMASK);
- set_fsr();
-}
-
-#ifdef TARGET_SPARC64
-void helper_ldxfsr(uint64_t new_fsr)
-{
- env->fsr = (new_fsr & FSR_LDXFSR_MASK) | (env->fsr & FSR_LDXFSR_OLDMASK);
- set_fsr();
-}
-#endif
-
-void helper_debug(void)
-{
- env->exception_index = EXCP_DEBUG;
- cpu_loop_exit(env);
-}
-
-#ifndef TARGET_SPARC64
-/* XXX: use another pointer for %iN registers to avoid slow wrapping
- handling ? */
-void helper_save(void)
-{
- uint32_t cwp;
-
- cwp = cwp_dec(env->cwp - 1);
- if (env->wim & (1 << cwp)) {
- raise_exception(TT_WIN_OVF);
- }
- set_cwp(cwp);
-}
-
-void helper_restore(void)
-{
- uint32_t cwp;
-
- cwp = cwp_inc(env->cwp + 1);
- if (env->wim & (1 << cwp)) {
- raise_exception(TT_WIN_UNF);
- }
- set_cwp(cwp);
-}
-
-void helper_wrpsr(target_ulong new_psr)
-{
- if ((new_psr & PSR_CWP) >= env->nwindows) {
- raise_exception(TT_ILL_INSN);
- } else {
- cpu_put_psr(env, new_psr);
- }
-}
-
-target_ulong helper_rdpsr(void)
-{
- return get_psr();
-}
-
-#else
-/* XXX: use another pointer for %iN registers to avoid slow wrapping
- handling ? */
-void helper_save(void)
-{
- uint32_t cwp;
-
- cwp = cwp_dec(env->cwp - 1);
- if (env->cansave == 0) {
- raise_exception(TT_SPILL | (env->otherwin != 0 ?
- (TT_WOTHER | ((env->wstate & 0x38) >> 1)):
- ((env->wstate & 0x7) << 2)));
- } else {
- if (env->cleanwin - env->canrestore == 0) {
- // XXX Clean windows without trap
- raise_exception(TT_CLRWIN);
- } else {
- env->cansave--;
- env->canrestore++;
- set_cwp(cwp);
- }
- }
-}
-
-void helper_restore(void)
-{
- uint32_t cwp;
-
- cwp = cwp_inc(env->cwp + 1);
- if (env->canrestore == 0) {
- raise_exception(TT_FILL | (env->otherwin != 0 ?
- (TT_WOTHER | ((env->wstate & 0x38) >> 1)):
- ((env->wstate & 0x7) << 2)));
- } else {
- env->cansave++;
- env->canrestore--;
- set_cwp(cwp);
- }
-}
-
-void helper_flushw(void)
-{
- if (env->cansave != env->nwindows - 2) {
- raise_exception(TT_SPILL | (env->otherwin != 0 ?
- (TT_WOTHER | ((env->wstate & 0x38) >> 1)):
- ((env->wstate & 0x7) << 2)));
- }
-}
-
-void helper_saved(void)
-{
- env->cansave++;
- if (env->otherwin == 0)
- env->canrestore--;
- else
- env->otherwin--;
-}
-
-void helper_restored(void)
-{
- env->canrestore++;
- if (env->cleanwin < env->nwindows - 1)
- env->cleanwin++;
- if (env->otherwin == 0)
- env->cansave--;
- else
- env->otherwin--;
-}
-
-static target_ulong get_ccr(void)
-{
- target_ulong psr;
-
- psr = get_psr();
-
- return ((env->xcc >> 20) << 4) | ((psr & PSR_ICC) >> 20);
-}
-
-target_ulong cpu_get_ccr(CPUState *env1)
-{
- CPUState *saved_env;
- target_ulong ret;
-
- saved_env = env;
- env = env1;
- ret = get_ccr();
- env = saved_env;
- return ret;
-}
-
-static void put_ccr(target_ulong val)
-{
- env->xcc = (val >> 4) << 20;
- env->psr = (val & 0xf) << 20;
- CC_OP = CC_OP_FLAGS;
-}
-
-void cpu_put_ccr(CPUState *env1, target_ulong val)
-{
- CPUState *saved_env;
-
- saved_env = env;
- env = env1;
- put_ccr(val);
- env = saved_env;
-}
-
-static target_ulong get_cwp64(void)
-{
- return env->nwindows - 1 - env->cwp;
-}
-
-target_ulong cpu_get_cwp64(CPUState *env1)
-{
- CPUState *saved_env;
- target_ulong ret;
-
- saved_env = env;
- env = env1;
- ret = get_cwp64();
- env = saved_env;
- return ret;
-}
-
-static void put_cwp64(int cwp)
-{
- if (unlikely(cwp >= env->nwindows || cwp < 0)) {
- cwp %= env->nwindows;
- }
- set_cwp(env->nwindows - 1 - cwp);
-}
-
-void cpu_put_cwp64(CPUState *env1, int cwp)
-{
- CPUState *saved_env;
-
- saved_env = env;
- env = env1;
- put_cwp64(cwp);
- env = saved_env;
-}
-
-target_ulong helper_rdccr(void)
-{
- return get_ccr();
-}
-
-void helper_wrccr(target_ulong new_ccr)
-{
- put_ccr(new_ccr);
-}
-
-// CWP handling is reversed in V9, but we still use the V8 register
-// order.
-target_ulong helper_rdcwp(void)
-{
- return get_cwp64();
-}
-
-void helper_wrcwp(target_ulong new_cwp)
-{
- put_cwp64(new_cwp);
-}
-
-// This function uses non-native bit order
-#define GET_FIELD(X, FROM, TO) \
- ((X) >> (63 - (TO)) & ((1ULL << ((TO) - (FROM) + 1)) - 1))
-
-// This function uses the order in the manuals, i.e. bit 0 is 2^0
-#define GET_FIELD_SP(X, FROM, TO) \
- GET_FIELD(X, 63 - (TO), 63 - (FROM))
-
-target_ulong helper_array8(target_ulong pixel_addr, target_ulong cubesize)
-{
- return (GET_FIELD_SP(pixel_addr, 60, 63) << (17 + 2 * cubesize)) |
- (GET_FIELD_SP(pixel_addr, 39, 39 + cubesize - 1) << (17 + cubesize)) |
- (GET_FIELD_SP(pixel_addr, 17 + cubesize - 1, 17) << 17) |
- (GET_FIELD_SP(pixel_addr, 56, 59) << 13) |
- (GET_FIELD_SP(pixel_addr, 35, 38) << 9) |
- (GET_FIELD_SP(pixel_addr, 13, 16) << 5) |
- (((pixel_addr >> 55) & 1) << 4) |
- (GET_FIELD_SP(pixel_addr, 33, 34) << 2) |
- GET_FIELD_SP(pixel_addr, 11, 12);
-}
-
-target_ulong helper_alignaddr(target_ulong addr, target_ulong offset)
-{
- uint64_t tmp;
-
- tmp = addr + offset;
- env->gsr &= ~7ULL;
- env->gsr |= tmp & 7ULL;
- return tmp & ~7ULL;
-}
-
-target_ulong helper_popc(target_ulong val)
-{
- return ctpop64(val);
-}
-
-static inline uint64_t *get_gregset(uint32_t pstate)
-{
- switch (pstate) {
- default:
- DPRINTF_PSTATE("ERROR in get_gregset: active pstate bits=%x%s%s%s\n",
- pstate,
- (pstate & PS_IG) ? " IG" : "",
- (pstate & PS_MG) ? " MG" : "",
- (pstate & PS_AG) ? " AG" : "");
- /* pass through to normal set of global registers */
- case 0:
- return env->bgregs;
- case PS_AG:
- return env->agregs;
- case PS_MG:
- return env->mgregs;
- case PS_IG:
- return env->igregs;
- }
-}
-
-static inline void change_pstate(uint32_t new_pstate)
-{
- uint32_t pstate_regs, new_pstate_regs;
- uint64_t *src, *dst;
-
- if (env->def->features & CPU_FEATURE_GL) {
- // PS_AG is not implemented in this case
- new_pstate &= ~PS_AG;
- }
-
- pstate_regs = env->pstate & 0xc01;
- new_pstate_regs = new_pstate & 0xc01;
-
- if (new_pstate_regs != pstate_regs) {
- DPRINTF_PSTATE("change_pstate: switching regs old=%x new=%x\n",
- pstate_regs, new_pstate_regs);
- // Switch global register bank
- src = get_gregset(new_pstate_regs);
- dst = get_gregset(pstate_regs);
- memcpy32(dst, env->gregs);
- memcpy32(env->gregs, src);
- }
- else {
- DPRINTF_PSTATE("change_pstate: regs new=%x (unchanged)\n",
- new_pstate_regs);
- }
- env->pstate = new_pstate;
-}
-
-void helper_wrpstate(target_ulong new_state)
-{
- change_pstate(new_state & 0xf3f);
-
-#if !defined(CONFIG_USER_ONLY)
- if (cpu_interrupts_enabled(env)) {
- cpu_check_irqs(env);
- }
-#endif
-}
-
-void cpu_change_pstate(CPUState *env1, uint32_t new_pstate)
-{
- CPUState *saved_env;
-
- saved_env = env;
- env = env1;
- change_pstate(new_pstate);
- env = saved_env;
-}
-
-void helper_wrpil(target_ulong new_pil)
-{
-#if !defined(CONFIG_USER_ONLY)
- DPRINTF_PSTATE("helper_wrpil old=%x new=%x\n",
- env->psrpil, (uint32_t)new_pil);
-
- env->psrpil = new_pil;
-
- if (cpu_interrupts_enabled(env)) {
- cpu_check_irqs(env);
- }
-#endif
-}
-
-void helper_done(void)
-{
- trap_state* tsptr = cpu_tsptr(env);
-
- env->pc = tsptr->tnpc;
- env->npc = tsptr->tnpc + 4;
- put_ccr(tsptr->tstate >> 32);
- env->asi = (tsptr->tstate >> 24) & 0xff;
- change_pstate((tsptr->tstate >> 8) & 0xf3f);
- put_cwp64(tsptr->tstate & 0xff);
- env->tl--;
-
- DPRINTF_PSTATE("... helper_done tl=%d\n", env->tl);
-
-#if !defined(CONFIG_USER_ONLY)
- if (cpu_interrupts_enabled(env)) {
- cpu_check_irqs(env);
- }
-#endif
-}
-
-void helper_retry(void)
-{
- trap_state* tsptr = cpu_tsptr(env);
-
- env->pc = tsptr->tpc;
- env->npc = tsptr->tnpc;
- put_ccr(tsptr->tstate >> 32);
- env->asi = (tsptr->tstate >> 24) & 0xff;
- change_pstate((tsptr->tstate >> 8) & 0xf3f);
- put_cwp64(tsptr->tstate & 0xff);
- env->tl--;
-
- DPRINTF_PSTATE("... helper_retry tl=%d\n", env->tl);
-
-#if !defined(CONFIG_USER_ONLY)
- if (cpu_interrupts_enabled(env)) {
- cpu_check_irqs(env);
- }
-#endif
-}
-
-static void do_modify_softint(const char* operation, uint32_t value)
-{
- if (env->softint != value) {
- env->softint = value;
- DPRINTF_PSTATE(": %s new %08x\n", operation, env->softint);
-#if !defined(CONFIG_USER_ONLY)
- if (cpu_interrupts_enabled(env)) {
- cpu_check_irqs(env);
- }
-#endif
- }
-}
-
-void helper_set_softint(uint64_t value)
-{
- do_modify_softint("helper_set_softint", env->softint | (uint32_t)value);
-}
-
-void helper_clear_softint(uint64_t value)
-{
- do_modify_softint("helper_clear_softint", env->softint & (uint32_t)~value);
-}
-
-void helper_write_softint(uint64_t value)
-{
- do_modify_softint("helper_write_softint", (uint32_t)value);
-}
-#endif
-
-#ifdef TARGET_SPARC64
-trap_state* cpu_tsptr(CPUState* env)
-{
- return &env->ts[env->tl & MAXTL_MASK];
-}
-#endif
-
-#if !defined(CONFIG_USER_ONLY)
-
static void do_unaligned_access(target_ulong addr, int is_write, int is_user,
void *retaddr);
@@ -4218,7 +47,7 @@ static void do_unaligned_access(target_ulong addr, int is_write, int is_user,
"\n", addr, env->pc);
#endif
cpu_restore_state2(retaddr);
- raise_exception(TT_UNALIGNED);
+ helper_raise_exception(env, TT_UNALIGNED);
}
/* try to fill the TLB and return an exception if error. If retaddr is
@@ -4243,122 +72,3 @@ void tlb_fill(CPUState *env1, target_ulong addr, int is_write, int mmu_idx,
}
#endif /* !CONFIG_USER_ONLY */
-
-#ifndef TARGET_SPARC64
-#if !defined(CONFIG_USER_ONLY)
-static void do_unassigned_access(target_phys_addr_t addr, int is_write,
- int is_exec, int is_asi, int size)
-{
- int fault_type;
-
-#ifdef DEBUG_UNASSIGNED
- if (is_asi)
- printf("Unassigned mem %s access of %d byte%s to " TARGET_FMT_plx
- " asi 0x%02x from " TARGET_FMT_lx "\n",
- is_exec ? "exec" : is_write ? "write" : "read", size,
- size == 1 ? "" : "s", addr, is_asi, env->pc);
- else
- printf("Unassigned mem %s access of %d byte%s to " TARGET_FMT_plx
- " from " TARGET_FMT_lx "\n",
- is_exec ? "exec" : is_write ? "write" : "read", size,
- size == 1 ? "" : "s", addr, env->pc);
-#endif
- /* Don't overwrite translation and access faults */
- fault_type = (env->mmuregs[3] & 0x1c) >> 2;
- if ((fault_type > 4) || (fault_type == 0)) {
- env->mmuregs[3] = 0; /* Fault status register */
- if (is_asi)
- env->mmuregs[3] |= 1 << 16;
- if (env->psrs)
- env->mmuregs[3] |= 1 << 5;
- if (is_exec)
- env->mmuregs[3] |= 1 << 6;
- if (is_write)
- env->mmuregs[3] |= 1 << 7;
- env->mmuregs[3] |= (5 << 2) | 2;
- /* SuperSPARC will never place instruction fault addresses in the FAR */
- if (!is_exec) {
- env->mmuregs[4] = addr; /* Fault address register */
- }
- }
- /* overflow (same type fault was not read before another fault) */
- if (fault_type == ((env->mmuregs[3] & 0x1c)) >> 2) {
- env->mmuregs[3] |= 1;
- }
-
- if ((env->mmuregs[0] & MMU_E) && !(env->mmuregs[0] & MMU_NF)) {
- if (is_exec)
- raise_exception(TT_CODE_ACCESS);
- else
- raise_exception(TT_DATA_ACCESS);
- }
-
- /* flush neverland mappings created during no-fault mode,
- so the sequential MMU faults report proper fault types */
- if (env->mmuregs[0] & MMU_NF) {
- tlb_flush(env, 1);
- }
-}
-#endif
-#else
-#if defined(CONFIG_USER_ONLY)
-static void do_unassigned_access(target_ulong addr, int is_write, int is_exec,
- int is_asi, int size)
-#else
-static void do_unassigned_access(target_phys_addr_t addr, int is_write,
- int is_exec, int is_asi, int size)
-#endif
-{
-#ifdef DEBUG_UNASSIGNED
- printf("Unassigned mem access to " TARGET_FMT_plx " from " TARGET_FMT_lx
- "\n", addr, env->pc);
-#endif
-
- if (is_exec)
- raise_exception(TT_CODE_ACCESS);
- else
- raise_exception(TT_DATA_ACCESS);
-}
-#endif
-
-
-#ifdef TARGET_SPARC64
-void helper_tick_set_count(void *opaque, uint64_t count)
-{
-#if !defined(CONFIG_USER_ONLY)
- cpu_tick_set_count(opaque, count);
-#endif
-}
-
-uint64_t helper_tick_get_count(void *opaque)
-{
-#if !defined(CONFIG_USER_ONLY)
- return cpu_tick_get_count(opaque);
-#else
- return 0;
-#endif
-}
-
-void helper_tick_set_limit(void *opaque, uint64_t limit)
-{
-#if !defined(CONFIG_USER_ONLY)
- cpu_tick_set_limit(opaque, limit);
-#endif
-}
-#endif
-
-#if !defined(CONFIG_USER_ONLY)
-void cpu_unassigned_access(CPUState *env1, target_phys_addr_t addr,
- int is_write, int is_exec, int is_asi, int size)
-{
- CPUState *saved_env;
-
- saved_env = env;
- env = env1;
- /* Ignore unassigned accesses outside of CPU context */
- if (env1) {
- do_unassigned_access(addr, is_write, is_exec, is_asi, size);
- }
- env = saved_env;
-}
-#endif
diff --git a/target-sparc/translate.c b/target-sparc/translate.c
index dee67b334f..383fd9ce26 100644
--- a/target-sparc/translate.c
+++ b/target-sparc/translate.c
@@ -294,7 +294,7 @@ static inline void gen_add_tv(TCGv dst, TCGv src1, TCGv src2)
tcg_gen_andi_tl(r_temp, r_temp, (1ULL << 31));
tcg_gen_brcondi_tl(TCG_COND_EQ, r_temp, 0, l1);
r_const = tcg_const_i32(TT_TOVF);
- gen_helper_raise_exception(r_const);
+ gen_helper_raise_exception(cpu_env, r_const);
tcg_temp_free_i32(r_const);
gen_set_label(l1);
tcg_temp_free(r_temp);
@@ -310,7 +310,7 @@ static inline void gen_tag_tv(TCGv src1, TCGv src2)
tcg_gen_andi_tl(cpu_tmp0, cpu_tmp0, 0x3);
tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_tmp0, 0, l1);
r_const = tcg_const_i32(TT_TOVF);
- gen_helper_raise_exception(r_const);
+ gen_helper_raise_exception(cpu_env, r_const);
tcg_temp_free_i32(r_const);
gen_set_label(l1);
}
@@ -428,7 +428,7 @@ static void gen_op_addx_int(DisasContext *dc, TCGv dst, TCGv src1,
default:
/* We need external help to produce the carry. */
carry_32 = tcg_temp_new_i32();
- gen_helper_compute_C_icc(carry_32);
+ gen_helper_compute_C_icc(carry_32, cpu_env);
break;
}
@@ -492,7 +492,7 @@ static inline void gen_sub_tv(TCGv dst, TCGv src1, TCGv src2)
tcg_gen_andi_tl(r_temp, r_temp, (1ULL << 31));
tcg_gen_brcondi_tl(TCG_COND_EQ, r_temp, 0, l1);
r_const = tcg_const_i32(TT_TOVF);
- gen_helper_raise_exception(r_const);
+ gen_helper_raise_exception(cpu_env, r_const);
tcg_temp_free_i32(r_const);
gen_set_label(l1);
tcg_temp_free(r_temp);
@@ -567,7 +567,7 @@ static void gen_op_subx_int(DisasContext *dc, TCGv dst, TCGv src1,
default:
/* We need external help to produce the carry. */
carry_32 = tcg_temp_new_i32();
- gen_helper_compute_C_icc(carry_32);
+ gen_helper_compute_C_icc(carry_32, cpu_env);
break;
}
@@ -719,7 +719,7 @@ static inline void gen_trap_ifdivzero_tl(TCGv divisor)
l1 = gen_new_label();
tcg_gen_brcondi_tl(TCG_COND_NE, divisor, 0, l1);
r_const = tcg_const_i32(TT_DIV_ZERO);
- gen_helper_raise_exception(r_const);
+ gen_helper_raise_exception(cpu_env, r_const);
tcg_temp_free_i32(r_const);
gen_set_label(l1);
}
@@ -1091,7 +1091,7 @@ static inline void save_state(DisasContext *dc, TCGv cond)
/* flush pending conditional evaluations before exposing cpu state */
if (dc->cc_op != CC_OP_FLAGS) {
dc->cc_op = CC_OP_FLAGS;
- gen_helper_compute_psr();
+ gen_helper_compute_psr(cpu_env);
}
save_npc(dc, cond);
}
@@ -1133,7 +1133,7 @@ static inline void gen_cond(TCGv r_dst, unsigned int cc, unsigned int cond,
case CC_OP_FLAGS:
break;
default:
- gen_helper_compute_psr();
+ gen_helper_compute_psr(cpu_env);
dc->cc_op = CC_OP_FLAGS;
break;
}
@@ -1405,16 +1405,16 @@ static inline void gen_op_fcmps(int fccno, TCGv_i32 r_rs1, TCGv_i32 r_rs2)
{
switch (fccno) {
case 0:
- gen_helper_fcmps(r_rs1, r_rs2);
+ gen_helper_fcmps(cpu_env, r_rs1, r_rs2);
break;
case 1:
- gen_helper_fcmps_fcc1(r_rs1, r_rs2);
+ gen_helper_fcmps_fcc1(cpu_env, r_rs1, r_rs2);
break;
case 2:
- gen_helper_fcmps_fcc2(r_rs1, r_rs2);
+ gen_helper_fcmps_fcc2(cpu_env, r_rs1, r_rs2);
break;
case 3:
- gen_helper_fcmps_fcc3(r_rs1, r_rs2);
+ gen_helper_fcmps_fcc3(cpu_env, r_rs1, r_rs2);
break;
}
}
@@ -1423,16 +1423,16 @@ static inline void gen_op_fcmpd(int fccno)
{
switch (fccno) {
case 0:
- gen_helper_fcmpd();
+ gen_helper_fcmpd(cpu_env);
break;
case 1:
- gen_helper_fcmpd_fcc1();
+ gen_helper_fcmpd_fcc1(cpu_env);
break;
case 2:
- gen_helper_fcmpd_fcc2();
+ gen_helper_fcmpd_fcc2(cpu_env);
break;
case 3:
- gen_helper_fcmpd_fcc3();
+ gen_helper_fcmpd_fcc3(cpu_env);
break;
}
}
@@ -1441,16 +1441,16 @@ static inline void gen_op_fcmpq(int fccno)
{
switch (fccno) {
case 0:
- gen_helper_fcmpq();
+ gen_helper_fcmpq(cpu_env);
break;
case 1:
- gen_helper_fcmpq_fcc1();
+ gen_helper_fcmpq_fcc1(cpu_env);
break;
case 2:
- gen_helper_fcmpq_fcc2();
+ gen_helper_fcmpq_fcc2(cpu_env);
break;
case 3:
- gen_helper_fcmpq_fcc3();
+ gen_helper_fcmpq_fcc3(cpu_env);
break;
}
}
@@ -1459,16 +1459,16 @@ static inline void gen_op_fcmpes(int fccno, TCGv_i32 r_rs1, TCGv_i32 r_rs2)
{
switch (fccno) {
case 0:
- gen_helper_fcmpes(r_rs1, r_rs2);
+ gen_helper_fcmpes(cpu_env, r_rs1, r_rs2);
break;
case 1:
- gen_helper_fcmpes_fcc1(r_rs1, r_rs2);
+ gen_helper_fcmpes_fcc1(cpu_env, r_rs1, r_rs2);
break;
case 2:
- gen_helper_fcmpes_fcc2(r_rs1, r_rs2);
+ gen_helper_fcmpes_fcc2(cpu_env, r_rs1, r_rs2);
break;
case 3:
- gen_helper_fcmpes_fcc3(r_rs1, r_rs2);
+ gen_helper_fcmpes_fcc3(cpu_env, r_rs1, r_rs2);
break;
}
}
@@ -1477,16 +1477,16 @@ static inline void gen_op_fcmped(int fccno)
{
switch (fccno) {
case 0:
- gen_helper_fcmped();
+ gen_helper_fcmped(cpu_env);
break;
case 1:
- gen_helper_fcmped_fcc1();
+ gen_helper_fcmped_fcc1(cpu_env);
break;
case 2:
- gen_helper_fcmped_fcc2();
+ gen_helper_fcmped_fcc2(cpu_env);
break;
case 3:
- gen_helper_fcmped_fcc3();
+ gen_helper_fcmped_fcc3(cpu_env);
break;
}
}
@@ -1495,16 +1495,16 @@ static inline void gen_op_fcmpeq(int fccno)
{
switch (fccno) {
case 0:
- gen_helper_fcmpeq();
+ gen_helper_fcmpeq(cpu_env);
break;
case 1:
- gen_helper_fcmpeq_fcc1();
+ gen_helper_fcmpeq_fcc1(cpu_env);
break;
case 2:
- gen_helper_fcmpeq_fcc2();
+ gen_helper_fcmpeq_fcc2(cpu_env);
break;
case 3:
- gen_helper_fcmpeq_fcc3();
+ gen_helper_fcmpeq_fcc3(cpu_env);
break;
}
}
@@ -1513,32 +1513,32 @@ static inline void gen_op_fcmpeq(int fccno)
static inline void gen_op_fcmps(int fccno, TCGv r_rs1, TCGv r_rs2)
{
- gen_helper_fcmps(r_rs1, r_rs2);
+ gen_helper_fcmps(cpu_env, r_rs1, r_rs2);
}
static inline void gen_op_fcmpd(int fccno)
{
- gen_helper_fcmpd();
+ gen_helper_fcmpd(cpu_env);
}
static inline void gen_op_fcmpq(int fccno)
{
- gen_helper_fcmpq();
+ gen_helper_fcmpq(cpu_env);
}
static inline void gen_op_fcmpes(int fccno, TCGv r_rs1, TCGv r_rs2)
{
- gen_helper_fcmpes(r_rs1, r_rs2);
+ gen_helper_fcmpes(cpu_env, r_rs1, r_rs2);
}
static inline void gen_op_fcmped(int fccno)
{
- gen_helper_fcmped();
+ gen_helper_fcmped(cpu_env);
}
static inline void gen_op_fcmpeq(int fccno)
{
- gen_helper_fcmpeq();
+ gen_helper_fcmpeq(cpu_env);
}
#endif
@@ -1549,7 +1549,7 @@ static inline void gen_op_fpexception_im(int fsr_flags)
tcg_gen_andi_tl(cpu_fsr, cpu_fsr, FSR_FTT_NMASK);
tcg_gen_ori_tl(cpu_fsr, cpu_fsr, fsr_flags);
r_const = tcg_const_i32(TT_FP_EXCP);
- gen_helper_raise_exception(r_const);
+ gen_helper_raise_exception(cpu_env, r_const);
tcg_temp_free_i32(r_const);
}
@@ -1561,7 +1561,7 @@ static int gen_trap_ifnofpu(DisasContext *dc, TCGv r_cond)
save_state(dc, r_cond);
r_const = tcg_const_i32(TT_NFPU_INSN);
- gen_helper_raise_exception(r_const);
+ gen_helper_raise_exception(cpu_env, r_const);
tcg_temp_free_i32(r_const);
dc->is_br = 1;
return 1;
@@ -1584,7 +1584,7 @@ static inline void gen_op_clear_ieee_excp_and_FTT(void)
static inline void gen_clear_float_exceptions(void)
{
- gen_helper_clear_float_exceptions();
+ gen_helper_clear_float_exceptions(cpu_env);
}
/* asi moves */
@@ -2038,7 +2038,7 @@ static void disas_sparc_insn(DisasContext * dc)
gen_helper_shutdown();
} else {
- gen_helper_raise_exception(cpu_tmp32);
+ gen_helper_raise_exception(cpu_env, cpu_tmp32);
}
} else if (cond != 0) {
TCGv r_cond = tcg_temp_new();
@@ -2068,7 +2068,7 @@ static void disas_sparc_insn(DisasContext * dc)
tcg_gen_andi_tl(cpu_dst, cpu_dst, V8_TRAP_MASK);
tcg_gen_addi_tl(cpu_dst, cpu_dst, TT_TRAP);
tcg_gen_trunc_tl_i32(cpu_tmp32, cpu_dst);
- gen_helper_raise_exception(cpu_tmp32);
+ gen_helper_raise_exception(cpu_env, cpu_tmp32);
gen_set_label(l1);
tcg_temp_free(r_cond);
@@ -2106,8 +2106,8 @@ static void disas_sparc_insn(DisasContext * dc)
break;
#ifdef TARGET_SPARC64
case 0x2: /* V9 rdccr */
- gen_helper_compute_psr();
- gen_helper_rdccr(cpu_dst);
+ gen_helper_compute_psr(cpu_env);
+ gen_helper_rdccr(cpu_dst, cpu_env);
gen_movl_TN_reg(rd, cpu_dst);
break;
case 0x3: /* V9 rdasi */
@@ -2182,9 +2182,9 @@ static void disas_sparc_insn(DisasContext * dc)
#ifndef TARGET_SPARC64
if (!supervisor(dc))
goto priv_insn;
- gen_helper_compute_psr();
+ gen_helper_compute_psr(cpu_env);
dc->cc_op = CC_OP_FLAGS;
- gen_helper_rdpsr(cpu_dst);
+ gen_helper_rdpsr(cpu_dst, cpu_env);
#else
CHECK_IU_FEATURE(dc, HYPV);
if (!hypervisor(dc))
@@ -2297,7 +2297,7 @@ static void disas_sparc_insn(DisasContext * dc)
tcg_gen_ext_i32_tl(cpu_tmp0, cpu_tmp32);
break;
case 9: // cwp
- gen_helper_rdcwp(cpu_tmp0);
+ gen_helper_rdcwp(cpu_tmp0, cpu_env);
break;
case 10: // cansave
tcg_gen_ld_i32(cpu_tmp32, cpu_env,
@@ -2351,7 +2351,7 @@ static void disas_sparc_insn(DisasContext * dc)
} else if (xop == 0x2b) { /* rdtbr / V9 flushw */
#ifdef TARGET_SPARC64
save_state(dc, cpu_cond);
- gen_helper_flushw();
+ gen_helper_flushw(cpu_env);
#else
if (!supervisor(dc))
goto priv_insn;
@@ -2383,8 +2383,8 @@ static void disas_sparc_insn(DisasContext * dc)
case 0x29: /* fsqrts */
CHECK_FPU_FEATURE(dc, FSQRT);
gen_clear_float_exceptions();
- gen_helper_fsqrts(cpu_tmp32, cpu_fpr[rs2]);
- gen_helper_check_ieee_exceptions();
+ gen_helper_fsqrts(cpu_tmp32, cpu_env, cpu_fpr[rs2]);
+ gen_helper_check_ieee_exceptions(cpu_env);
tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
gen_update_fprs_dirty(rd);
break;
@@ -2392,8 +2392,8 @@ static void disas_sparc_insn(DisasContext * dc)
CHECK_FPU_FEATURE(dc, FSQRT);
gen_op_load_fpr_DT1(DFPREG(rs2));
gen_clear_float_exceptions();
- gen_helper_fsqrtd();
- gen_helper_check_ieee_exceptions();
+ gen_helper_fsqrtd(cpu_env);
+ gen_helper_check_ieee_exceptions(cpu_env);
gen_op_store_DT0_fpr(DFPREG(rd));
gen_update_fprs_dirty(DFPREG(rd));
break;
@@ -2401,15 +2401,16 @@ static void disas_sparc_insn(DisasContext * dc)
CHECK_FPU_FEATURE(dc, FLOAT128);
gen_op_load_fpr_QT1(QFPREG(rs2));
gen_clear_float_exceptions();
- gen_helper_fsqrtq();
- gen_helper_check_ieee_exceptions();
+ gen_helper_fsqrtq(cpu_env);
+ gen_helper_check_ieee_exceptions(cpu_env);
gen_op_store_QT0_fpr(QFPREG(rd));
gen_update_fprs_dirty(QFPREG(rd));
break;
case 0x41: /* fadds */
gen_clear_float_exceptions();
- gen_helper_fadds(cpu_tmp32, cpu_fpr[rs1], cpu_fpr[rs2]);
- gen_helper_check_ieee_exceptions();
+ gen_helper_fadds(cpu_tmp32, cpu_env, cpu_fpr[rs1],
+ cpu_fpr[rs2]);
+ gen_helper_check_ieee_exceptions(cpu_env);
tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
gen_update_fprs_dirty(rd);
break;
@@ -2417,8 +2418,8 @@ static void disas_sparc_insn(DisasContext * dc)
gen_op_load_fpr_DT0(DFPREG(rs1));
gen_op_load_fpr_DT1(DFPREG(rs2));
gen_clear_float_exceptions();
- gen_helper_faddd();
- gen_helper_check_ieee_exceptions();
+ gen_helper_faddd(cpu_env);
+ gen_helper_check_ieee_exceptions(cpu_env);
gen_op_store_DT0_fpr(DFPREG(rd));
gen_update_fprs_dirty(DFPREG(rd));
break;
@@ -2427,15 +2428,16 @@ static void disas_sparc_insn(DisasContext * dc)
gen_op_load_fpr_QT0(QFPREG(rs1));
gen_op_load_fpr_QT1(QFPREG(rs2));
gen_clear_float_exceptions();
- gen_helper_faddq();
- gen_helper_check_ieee_exceptions();
+ gen_helper_faddq(cpu_env);
+ gen_helper_check_ieee_exceptions(cpu_env);
gen_op_store_QT0_fpr(QFPREG(rd));
gen_update_fprs_dirty(QFPREG(rd));
break;
case 0x45: /* fsubs */
gen_clear_float_exceptions();
- gen_helper_fsubs(cpu_tmp32, cpu_fpr[rs1], cpu_fpr[rs2]);
- gen_helper_check_ieee_exceptions();
+ gen_helper_fsubs(cpu_tmp32, cpu_env, cpu_fpr[rs1],
+ cpu_fpr[rs2]);
+ gen_helper_check_ieee_exceptions(cpu_env);
tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
gen_update_fprs_dirty(rd);
break;
@@ -2443,8 +2445,8 @@ static void disas_sparc_insn(DisasContext * dc)
gen_op_load_fpr_DT0(DFPREG(rs1));
gen_op_load_fpr_DT1(DFPREG(rs2));
gen_clear_float_exceptions();
- gen_helper_fsubd();
- gen_helper_check_ieee_exceptions();
+ gen_helper_fsubd(cpu_env);
+ gen_helper_check_ieee_exceptions(cpu_env);
gen_op_store_DT0_fpr(DFPREG(rd));
gen_update_fprs_dirty(DFPREG(rd));
break;
@@ -2453,16 +2455,17 @@ static void disas_sparc_insn(DisasContext * dc)
gen_op_load_fpr_QT0(QFPREG(rs1));
gen_op_load_fpr_QT1(QFPREG(rs2));
gen_clear_float_exceptions();
- gen_helper_fsubq();
- gen_helper_check_ieee_exceptions();
+ gen_helper_fsubq(cpu_env);
+ gen_helper_check_ieee_exceptions(cpu_env);
gen_op_store_QT0_fpr(QFPREG(rd));
gen_update_fprs_dirty(QFPREG(rd));
break;
case 0x49: /* fmuls */
CHECK_FPU_FEATURE(dc, FMUL);
gen_clear_float_exceptions();
- gen_helper_fmuls(cpu_tmp32, cpu_fpr[rs1], cpu_fpr[rs2]);
- gen_helper_check_ieee_exceptions();
+ gen_helper_fmuls(cpu_tmp32, cpu_env, cpu_fpr[rs1],
+ cpu_fpr[rs2]);
+ gen_helper_check_ieee_exceptions(cpu_env);
tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
gen_update_fprs_dirty(rd);
break;
@@ -2471,8 +2474,8 @@ static void disas_sparc_insn(DisasContext * dc)
gen_op_load_fpr_DT0(DFPREG(rs1));
gen_op_load_fpr_DT1(DFPREG(rs2));
gen_clear_float_exceptions();
- gen_helper_fmuld();
- gen_helper_check_ieee_exceptions();
+ gen_helper_fmuld(cpu_env);
+ gen_helper_check_ieee_exceptions(cpu_env);
gen_op_store_DT0_fpr(DFPREG(rd));
gen_update_fprs_dirty(DFPREG(rd));
break;
@@ -2482,15 +2485,16 @@ static void disas_sparc_insn(DisasContext * dc)
gen_op_load_fpr_QT0(QFPREG(rs1));
gen_op_load_fpr_QT1(QFPREG(rs2));
gen_clear_float_exceptions();
- gen_helper_fmulq();
- gen_helper_check_ieee_exceptions();
+ gen_helper_fmulq(cpu_env);
+ gen_helper_check_ieee_exceptions(cpu_env);
gen_op_store_QT0_fpr(QFPREG(rd));
gen_update_fprs_dirty(QFPREG(rd));
break;
case 0x4d: /* fdivs */
gen_clear_float_exceptions();
- gen_helper_fdivs(cpu_tmp32, cpu_fpr[rs1], cpu_fpr[rs2]);
- gen_helper_check_ieee_exceptions();
+ gen_helper_fdivs(cpu_tmp32, cpu_env, cpu_fpr[rs1],
+ cpu_fpr[rs2]);
+ gen_helper_check_ieee_exceptions(cpu_env);
tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
gen_update_fprs_dirty(rd);
break;
@@ -2498,8 +2502,8 @@ static void disas_sparc_insn(DisasContext * dc)
gen_op_load_fpr_DT0(DFPREG(rs1));
gen_op_load_fpr_DT1(DFPREG(rs2));
gen_clear_float_exceptions();
- gen_helper_fdivd();
- gen_helper_check_ieee_exceptions();
+ gen_helper_fdivd(cpu_env);
+ gen_helper_check_ieee_exceptions(cpu_env);
gen_op_store_DT0_fpr(DFPREG(rd));
gen_update_fprs_dirty(DFPREG(rd));
break;
@@ -2508,16 +2512,16 @@ static void disas_sparc_insn(DisasContext * dc)
gen_op_load_fpr_QT0(QFPREG(rs1));
gen_op_load_fpr_QT1(QFPREG(rs2));
gen_clear_float_exceptions();
- gen_helper_fdivq();
- gen_helper_check_ieee_exceptions();
+ gen_helper_fdivq(cpu_env);
+ gen_helper_check_ieee_exceptions(cpu_env);
gen_op_store_QT0_fpr(QFPREG(rd));
gen_update_fprs_dirty(QFPREG(rd));
break;
case 0x69: /* fsmuld */
CHECK_FPU_FEATURE(dc, FSMULD);
gen_clear_float_exceptions();
- gen_helper_fsmuld(cpu_fpr[rs1], cpu_fpr[rs2]);
- gen_helper_check_ieee_exceptions();
+ gen_helper_fsmuld(cpu_env, cpu_fpr[rs1], cpu_fpr[rs2]);
+ gen_helper_check_ieee_exceptions(cpu_env);
gen_op_store_DT0_fpr(DFPREG(rd));
gen_update_fprs_dirty(DFPREG(rd));
break;
@@ -2526,23 +2530,23 @@ static void disas_sparc_insn(DisasContext * dc)
gen_op_load_fpr_DT0(DFPREG(rs1));
gen_op_load_fpr_DT1(DFPREG(rs2));
gen_clear_float_exceptions();
- gen_helper_fdmulq();
- gen_helper_check_ieee_exceptions();
+ gen_helper_fdmulq(cpu_env);
+ gen_helper_check_ieee_exceptions(cpu_env);
gen_op_store_QT0_fpr(QFPREG(rd));
gen_update_fprs_dirty(QFPREG(rd));
break;
case 0xc4: /* fitos */
gen_clear_float_exceptions();
- gen_helper_fitos(cpu_tmp32, cpu_fpr[rs2]);
- gen_helper_check_ieee_exceptions();
+ gen_helper_fitos(cpu_tmp32, cpu_env, cpu_fpr[rs2]);
+ gen_helper_check_ieee_exceptions(cpu_env);
tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
gen_update_fprs_dirty(rd);
break;
case 0xc6: /* fdtos */
gen_op_load_fpr_DT1(DFPREG(rs2));
gen_clear_float_exceptions();
- gen_helper_fdtos(cpu_tmp32);
- gen_helper_check_ieee_exceptions();
+ gen_helper_fdtos(cpu_tmp32, cpu_env);
+ gen_helper_check_ieee_exceptions(cpu_env);
tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
gen_update_fprs_dirty(rd);
break;
@@ -2550,18 +2554,18 @@ static void disas_sparc_insn(DisasContext * dc)
CHECK_FPU_FEATURE(dc, FLOAT128);
gen_op_load_fpr_QT1(QFPREG(rs2));
gen_clear_float_exceptions();
- gen_helper_fqtos(cpu_tmp32);
- gen_helper_check_ieee_exceptions();
+ gen_helper_fqtos(cpu_tmp32, cpu_env);
+ gen_helper_check_ieee_exceptions(cpu_env);
tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
gen_update_fprs_dirty(rd);
break;
case 0xc8: /* fitod */
- gen_helper_fitod(cpu_fpr[rs2]);
+ gen_helper_fitod(cpu_env, cpu_fpr[rs2]);
gen_op_store_DT0_fpr(DFPREG(rd));
gen_update_fprs_dirty(DFPREG(rd));
break;
case 0xc9: /* fstod */
- gen_helper_fstod(cpu_fpr[rs2]);
+ gen_helper_fstod(cpu_env, cpu_fpr[rs2]);
gen_op_store_DT0_fpr(DFPREG(rd));
gen_update_fprs_dirty(DFPREG(rd));
break;
@@ -2569,42 +2573,42 @@ static void disas_sparc_insn(DisasContext * dc)
CHECK_FPU_FEATURE(dc, FLOAT128);
gen_op_load_fpr_QT1(QFPREG(rs2));
gen_clear_float_exceptions();
- gen_helper_fqtod();
- gen_helper_check_ieee_exceptions();
+ gen_helper_fqtod(cpu_env);
+ gen_helper_check_ieee_exceptions(cpu_env);
gen_op_store_DT0_fpr(DFPREG(rd));
gen_update_fprs_dirty(DFPREG(rd));
break;
case 0xcc: /* fitoq */
CHECK_FPU_FEATURE(dc, FLOAT128);
- gen_helper_fitoq(cpu_fpr[rs2]);
+ gen_helper_fitoq(cpu_env, cpu_fpr[rs2]);
gen_op_store_QT0_fpr(QFPREG(rd));
gen_update_fprs_dirty(QFPREG(rd));
break;
case 0xcd: /* fstoq */
CHECK_FPU_FEATURE(dc, FLOAT128);
- gen_helper_fstoq(cpu_fpr[rs2]);
+ gen_helper_fstoq(cpu_env, cpu_fpr[rs2]);
gen_op_store_QT0_fpr(QFPREG(rd));
gen_update_fprs_dirty(QFPREG(rd));
break;
case 0xce: /* fdtoq */
CHECK_FPU_FEATURE(dc, FLOAT128);
gen_op_load_fpr_DT1(DFPREG(rs2));
- gen_helper_fdtoq();
+ gen_helper_fdtoq(cpu_env);
gen_op_store_QT0_fpr(QFPREG(rd));
gen_update_fprs_dirty(QFPREG(rd));
break;
case 0xd1: /* fstoi */
gen_clear_float_exceptions();
- gen_helper_fstoi(cpu_tmp32, cpu_fpr[rs2]);
- gen_helper_check_ieee_exceptions();
+ gen_helper_fstoi(cpu_tmp32, cpu_env, cpu_fpr[rs2]);
+ gen_helper_check_ieee_exceptions(cpu_env);
tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
gen_update_fprs_dirty(rd);
break;
case 0xd2: /* fdtoi */
gen_op_load_fpr_DT1(DFPREG(rs2));
gen_clear_float_exceptions();
- gen_helper_fdtoi(cpu_tmp32);
- gen_helper_check_ieee_exceptions();
+ gen_helper_fdtoi(cpu_tmp32, cpu_env);
+ gen_helper_check_ieee_exceptions(cpu_env);
tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
gen_update_fprs_dirty(rd);
break;
@@ -2612,8 +2616,8 @@ static void disas_sparc_insn(DisasContext * dc)
CHECK_FPU_FEATURE(dc, FLOAT128);
gen_op_load_fpr_QT1(QFPREG(rs2));
gen_clear_float_exceptions();
- gen_helper_fqtoi(cpu_tmp32);
- gen_helper_check_ieee_exceptions();
+ gen_helper_fqtoi(cpu_tmp32, cpu_env);
+ gen_helper_check_ieee_exceptions(cpu_env);
tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
gen_update_fprs_dirty(rd);
break;
@@ -2637,42 +2641,42 @@ static void disas_sparc_insn(DisasContext * dc)
break;
case 0x6: /* V9 fnegd */
gen_op_load_fpr_DT1(DFPREG(rs2));
- gen_helper_fnegd();
+ gen_helper_fnegd(cpu_env);
gen_op_store_DT0_fpr(DFPREG(rd));
gen_update_fprs_dirty(DFPREG(rd));
break;
case 0x7: /* V9 fnegq */
CHECK_FPU_FEATURE(dc, FLOAT128);
gen_op_load_fpr_QT1(QFPREG(rs2));
- gen_helper_fnegq();
+ gen_helper_fnegq(cpu_env);
gen_op_store_QT0_fpr(QFPREG(rd));
gen_update_fprs_dirty(QFPREG(rd));
break;
case 0xa: /* V9 fabsd */
gen_op_load_fpr_DT1(DFPREG(rs2));
- gen_helper_fabsd();
+ gen_helper_fabsd(cpu_env);
gen_op_store_DT0_fpr(DFPREG(rd));
gen_update_fprs_dirty(DFPREG(rd));
break;
case 0xb: /* V9 fabsq */
CHECK_FPU_FEATURE(dc, FLOAT128);
gen_op_load_fpr_QT1(QFPREG(rs2));
- gen_helper_fabsq();
+ gen_helper_fabsq(cpu_env);
gen_op_store_QT0_fpr(QFPREG(rd));
gen_update_fprs_dirty(QFPREG(rd));
break;
case 0x81: /* V9 fstox */
gen_clear_float_exceptions();
- gen_helper_fstox(cpu_fpr[rs2]);
- gen_helper_check_ieee_exceptions();
+ gen_helper_fstox(cpu_env, cpu_fpr[rs2]);
+ gen_helper_check_ieee_exceptions(cpu_env);
gen_op_store_DT0_fpr(DFPREG(rd));
gen_update_fprs_dirty(DFPREG(rd));
break;
case 0x82: /* V9 fdtox */
gen_op_load_fpr_DT1(DFPREG(rs2));
gen_clear_float_exceptions();
- gen_helper_fdtox();
- gen_helper_check_ieee_exceptions();
+ gen_helper_fdtox(cpu_env);
+ gen_helper_check_ieee_exceptions(cpu_env);
gen_op_store_DT0_fpr(DFPREG(rd));
gen_update_fprs_dirty(DFPREG(rd));
break;
@@ -2680,24 +2684,24 @@ static void disas_sparc_insn(DisasContext * dc)
CHECK_FPU_FEATURE(dc, FLOAT128);
gen_op_load_fpr_QT1(QFPREG(rs2));
gen_clear_float_exceptions();
- gen_helper_fqtox();
- gen_helper_check_ieee_exceptions();
+ gen_helper_fqtox(cpu_env);
+ gen_helper_check_ieee_exceptions(cpu_env);
gen_op_store_DT0_fpr(DFPREG(rd));
gen_update_fprs_dirty(DFPREG(rd));
break;
case 0x84: /* V9 fxtos */
gen_op_load_fpr_DT1(DFPREG(rs2));
gen_clear_float_exceptions();
- gen_helper_fxtos(cpu_tmp32);
- gen_helper_check_ieee_exceptions();
+ gen_helper_fxtos(cpu_tmp32, cpu_env);
+ gen_helper_check_ieee_exceptions(cpu_env);
tcg_gen_mov_i32(cpu_fpr[rd], cpu_tmp32);
gen_update_fprs_dirty(rd);
break;
case 0x88: /* V9 fxtod */
gen_op_load_fpr_DT1(DFPREG(rs2));
gen_clear_float_exceptions();
- gen_helper_fxtod();
- gen_helper_check_ieee_exceptions();
+ gen_helper_fxtod(cpu_env);
+ gen_helper_check_ieee_exceptions(cpu_env);
gen_op_store_DT0_fpr(DFPREG(rd));
gen_update_fprs_dirty(DFPREG(rd));
break;
@@ -2705,8 +2709,8 @@ static void disas_sparc_insn(DisasContext * dc)
CHECK_FPU_FEATURE(dc, FLOAT128);
gen_op_load_fpr_DT1(DFPREG(rs2));
gen_clear_float_exceptions();
- gen_helper_fxtoq();
- gen_helper_check_ieee_exceptions();
+ gen_helper_fxtoq(cpu_env);
+ gen_helper_check_ieee_exceptions(cpu_env);
gen_op_store_QT0_fpr(QFPREG(rd));
gen_update_fprs_dirty(QFPREG(rd));
break;
@@ -3267,19 +3271,23 @@ static void disas_sparc_insn(DisasContext * dc)
case 0xe: /* udiv */
CHECK_IU_FEATURE(dc, DIV);
if (xop & 0x10) {
- gen_helper_udiv_cc(cpu_dst, cpu_src1, cpu_src2);
+ gen_helper_udiv_cc(cpu_dst, cpu_env, cpu_src1,
+ cpu_src2);
dc->cc_op = CC_OP_DIV;
} else {
- gen_helper_udiv(cpu_dst, cpu_src1, cpu_src2);
+ gen_helper_udiv(cpu_dst, cpu_env, cpu_src1,
+ cpu_src2);
}
break;
case 0xf: /* sdiv */
CHECK_IU_FEATURE(dc, DIV);
if (xop & 0x10) {
- gen_helper_sdiv_cc(cpu_dst, cpu_src1, cpu_src2);
+ gen_helper_sdiv_cc(cpu_dst, cpu_env, cpu_src1,
+ cpu_src2);
dc->cc_op = CC_OP_DIV;
} else {
- gen_helper_sdiv(cpu_dst, cpu_src1, cpu_src2);
+ gen_helper_sdiv(cpu_dst, cpu_env, cpu_src1,
+ cpu_src2);
}
break;
default:
@@ -3317,7 +3325,7 @@ static void disas_sparc_insn(DisasContext * dc)
dc->cc_op = CC_OP_TSUBTV;
break;
case 0x24: /* mulscc */
- gen_helper_compute_psr();
+ gen_helper_compute_psr(cpu_env);
gen_op_mulscc(cpu_dst, cpu_src1, cpu_src2);
gen_movl_TN_reg(rd, cpu_dst);
tcg_gen_movi_i32(cpu_cc_op, CC_OP_ADD);
@@ -3375,7 +3383,7 @@ static void disas_sparc_insn(DisasContext * dc)
#else
case 0x2: /* V9 wrccr */
tcg_gen_xor_tl(cpu_dst, cpu_src1, cpu_src2);
- gen_helper_wrccr(cpu_dst);
+ gen_helper_wrccr(cpu_env, cpu_dst);
tcg_gen_movi_i32(cpu_cc_op, CC_OP_FLAGS);
dc->cc_op = CC_OP_FLAGS;
break;
@@ -3408,19 +3416,19 @@ static void disas_sparc_insn(DisasContext * dc)
if (!supervisor(dc))
goto illegal_insn;
tcg_gen_xor_tl(cpu_tmp64, cpu_src1, cpu_src2);
- gen_helper_set_softint(cpu_tmp64);
+ gen_helper_set_softint(cpu_env, cpu_tmp64);
break;
case 0x15: /* Softint clear */
if (!supervisor(dc))
goto illegal_insn;
tcg_gen_xor_tl(cpu_tmp64, cpu_src1, cpu_src2);
- gen_helper_clear_softint(cpu_tmp64);
+ gen_helper_clear_softint(cpu_env, cpu_tmp64);
break;
case 0x16: /* Softint write */
if (!supervisor(dc))
goto illegal_insn;
tcg_gen_xor_tl(cpu_tmp64, cpu_src1, cpu_src2);
- gen_helper_write_softint(cpu_tmp64);
+ gen_helper_write_softint(cpu_env, cpu_tmp64);
break;
case 0x17: /* Tick compare */
#if !defined(CONFIG_USER_ONLY)
@@ -3495,10 +3503,10 @@ static void disas_sparc_insn(DisasContext * dc)
#ifdef TARGET_SPARC64
switch (rd) {
case 0:
- gen_helper_saved();
+ gen_helper_saved(cpu_env);
break;
case 1:
- gen_helper_restored();
+ gen_helper_restored(cpu_env);
break;
case 2: /* UA2005 allclean */
case 3: /* UA2005 otherw */
@@ -3510,7 +3518,7 @@ static void disas_sparc_insn(DisasContext * dc)
}
#else
tcg_gen_xor_tl(cpu_dst, cpu_src1, cpu_src2);
- gen_helper_wrpsr(cpu_dst);
+ gen_helper_wrpsr(cpu_env, cpu_dst);
tcg_gen_movi_i32(cpu_cc_op, CC_OP_FLAGS);
dc->cc_op = CC_OP_FLAGS;
save_state(dc, cpu_cond);
@@ -3594,7 +3602,7 @@ static void disas_sparc_insn(DisasContext * dc)
tcg_gen_mov_tl(r_tmp, cpu_tmp0);
save_state(dc, cpu_cond);
- gen_helper_wrpstate(r_tmp);
+ gen_helper_wrpstate(cpu_env, r_tmp);
tcg_temp_free(r_tmp);
dc->npc = DYNAMIC_PC;
}
@@ -3613,10 +3621,10 @@ static void disas_sparc_insn(DisasContext * dc)
}
break;
case 8: // pil
- gen_helper_wrpil(cpu_tmp0);
+ gen_helper_wrpil(cpu_env, cpu_tmp0);
break;
case 9: // cwp
- gen_helper_wrcwp(cpu_tmp0);
+ gen_helper_wrcwp(cpu_env, cpu_tmp0);
break;
case 10: // cansave
tcg_gen_trunc_tl_i32(cpu_tmp32, cpu_tmp0);
@@ -3828,14 +3836,14 @@ static void disas_sparc_insn(DisasContext * dc)
CHECK_FPU_FEATURE(dc, VIS1);
cpu_src1 = get_src1(insn, cpu_src1);
gen_movl_reg_TN(rs2, cpu_src2);
- gen_helper_array8(cpu_dst, cpu_src1, cpu_src2);
+ gen_helper_array8(cpu_dst, cpu_env, cpu_src1, cpu_src2);
gen_movl_TN_reg(rd, cpu_dst);
break;
case 0x012: /* VIS I array16 */
CHECK_FPU_FEATURE(dc, VIS1);
cpu_src1 = get_src1(insn, cpu_src1);
gen_movl_reg_TN(rs2, cpu_src2);
- gen_helper_array8(cpu_dst, cpu_src1, cpu_src2);
+ gen_helper_array8(cpu_dst, cpu_env, cpu_src1, cpu_src2);
tcg_gen_shli_i64(cpu_dst, cpu_dst, 1);
gen_movl_TN_reg(rd, cpu_dst);
break;
@@ -3843,7 +3851,7 @@ static void disas_sparc_insn(DisasContext * dc)
CHECK_FPU_FEATURE(dc, VIS1);
cpu_src1 = get_src1(insn, cpu_src1);
gen_movl_reg_TN(rs2, cpu_src2);
- gen_helper_array8(cpu_dst, cpu_src1, cpu_src2);
+ gen_helper_array8(cpu_dst, cpu_env, cpu_src1, cpu_src2);
tcg_gen_shli_i64(cpu_dst, cpu_dst, 2);
gen_movl_TN_reg(rd, cpu_dst);
break;
@@ -3851,7 +3859,7 @@ static void disas_sparc_insn(DisasContext * dc)
CHECK_FPU_FEATURE(dc, VIS1);
cpu_src1 = get_src1(insn, cpu_src1);
gen_movl_reg_TN(rs2, cpu_src2);
- gen_helper_alignaddr(cpu_dst, cpu_src1, cpu_src2);
+ gen_helper_alignaddr(cpu_dst, cpu_env, cpu_src1, cpu_src2);
gen_movl_TN_reg(rd, cpu_dst);
break;
case 0x019: /* VIS II bmask */
@@ -3862,63 +3870,63 @@ static void disas_sparc_insn(DisasContext * dc)
CHECK_FPU_FEATURE(dc, VIS1);
gen_op_load_fpr_DT0(DFPREG(rs1));
gen_op_load_fpr_DT1(DFPREG(rs2));
- gen_helper_fcmple16(cpu_dst);
+ gen_helper_fcmple16(cpu_dst, cpu_env);
gen_movl_TN_reg(rd, cpu_dst);
break;
case 0x022: /* VIS I fcmpne16 */
CHECK_FPU_FEATURE(dc, VIS1);
gen_op_load_fpr_DT0(DFPREG(rs1));
gen_op_load_fpr_DT1(DFPREG(rs2));
- gen_helper_fcmpne16(cpu_dst);
+ gen_helper_fcmpne16(cpu_dst, cpu_env);
gen_movl_TN_reg(rd, cpu_dst);
break;
case 0x024: /* VIS I fcmple32 */
CHECK_FPU_FEATURE(dc, VIS1);
gen_op_load_fpr_DT0(DFPREG(rs1));
gen_op_load_fpr_DT1(DFPREG(rs2));
- gen_helper_fcmple32(cpu_dst);
+ gen_helper_fcmple32(cpu_dst, cpu_env);
gen_movl_TN_reg(rd, cpu_dst);
break;
case 0x026: /* VIS I fcmpne32 */
CHECK_FPU_FEATURE(dc, VIS1);
gen_op_load_fpr_DT0(DFPREG(rs1));
gen_op_load_fpr_DT1(DFPREG(rs2));
- gen_helper_fcmpne32(cpu_dst);
+ gen_helper_fcmpne32(cpu_dst, cpu_env);
gen_movl_TN_reg(rd, cpu_dst);
break;
case 0x028: /* VIS I fcmpgt16 */
CHECK_FPU_FEATURE(dc, VIS1);
gen_op_load_fpr_DT0(DFPREG(rs1));
gen_op_load_fpr_DT1(DFPREG(rs2));
- gen_helper_fcmpgt16(cpu_dst);
+ gen_helper_fcmpgt16(cpu_dst, cpu_env);
gen_movl_TN_reg(rd, cpu_dst);
break;
case 0x02a: /* VIS I fcmpeq16 */
CHECK_FPU_FEATURE(dc, VIS1);
gen_op_load_fpr_DT0(DFPREG(rs1));
gen_op_load_fpr_DT1(DFPREG(rs2));
- gen_helper_fcmpeq16(cpu_dst);
+ gen_helper_fcmpeq16(cpu_dst, cpu_env);
gen_movl_TN_reg(rd, cpu_dst);
break;
case 0x02c: /* VIS I fcmpgt32 */
CHECK_FPU_FEATURE(dc, VIS1);
gen_op_load_fpr_DT0(DFPREG(rs1));
gen_op_load_fpr_DT1(DFPREG(rs2));
- gen_helper_fcmpgt32(cpu_dst);
+ gen_helper_fcmpgt32(cpu_dst, cpu_env);
gen_movl_TN_reg(rd, cpu_dst);
break;
case 0x02e: /* VIS I fcmpeq32 */
CHECK_FPU_FEATURE(dc, VIS1);
gen_op_load_fpr_DT0(DFPREG(rs1));
gen_op_load_fpr_DT1(DFPREG(rs2));
- gen_helper_fcmpeq32(cpu_dst);
+ gen_helper_fcmpeq32(cpu_dst, cpu_env);
gen_movl_TN_reg(rd, cpu_dst);
break;
case 0x031: /* VIS I fmul8x16 */
CHECK_FPU_FEATURE(dc, VIS1);
gen_op_load_fpr_DT0(DFPREG(rs1));
gen_op_load_fpr_DT1(DFPREG(rs2));
- gen_helper_fmul8x16();
+ gen_helper_fmul8x16(cpu_env);
gen_op_store_DT0_fpr(DFPREG(rd));
gen_update_fprs_dirty(DFPREG(rd));
break;
@@ -3926,7 +3934,7 @@ static void disas_sparc_insn(DisasContext * dc)
CHECK_FPU_FEATURE(dc, VIS1);
gen_op_load_fpr_DT0(DFPREG(rs1));
gen_op_load_fpr_DT1(DFPREG(rs2));
- gen_helper_fmul8x16au();
+ gen_helper_fmul8x16au(cpu_env);
gen_op_store_DT0_fpr(DFPREG(rd));
gen_update_fprs_dirty(DFPREG(rd));
break;
@@ -3934,7 +3942,7 @@ static void disas_sparc_insn(DisasContext * dc)
CHECK_FPU_FEATURE(dc, VIS1);
gen_op_load_fpr_DT0(DFPREG(rs1));
gen_op_load_fpr_DT1(DFPREG(rs2));
- gen_helper_fmul8x16al();
+ gen_helper_fmul8x16al(cpu_env);
gen_op_store_DT0_fpr(DFPREG(rd));
gen_update_fprs_dirty(DFPREG(rd));
break;
@@ -3942,7 +3950,7 @@ static void disas_sparc_insn(DisasContext * dc)
CHECK_FPU_FEATURE(dc, VIS1);
gen_op_load_fpr_DT0(DFPREG(rs1));
gen_op_load_fpr_DT1(DFPREG(rs2));
- gen_helper_fmul8sux16();
+ gen_helper_fmul8sux16(cpu_env);
gen_op_store_DT0_fpr(DFPREG(rd));
gen_update_fprs_dirty(DFPREG(rd));
break;
@@ -3950,7 +3958,7 @@ static void disas_sparc_insn(DisasContext * dc)
CHECK_FPU_FEATURE(dc, VIS1);
gen_op_load_fpr_DT0(DFPREG(rs1));
gen_op_load_fpr_DT1(DFPREG(rs2));
- gen_helper_fmul8ulx16();
+ gen_helper_fmul8ulx16(cpu_env);
gen_op_store_DT0_fpr(DFPREG(rd));
gen_update_fprs_dirty(DFPREG(rd));
break;
@@ -3958,7 +3966,7 @@ static void disas_sparc_insn(DisasContext * dc)
CHECK_FPU_FEATURE(dc, VIS1);
gen_op_load_fpr_DT0(DFPREG(rs1));
gen_op_load_fpr_DT1(DFPREG(rs2));
- gen_helper_fmuld8sux16();
+ gen_helper_fmuld8sux16(cpu_env);
gen_op_store_DT0_fpr(DFPREG(rd));
gen_update_fprs_dirty(DFPREG(rd));
break;
@@ -3966,7 +3974,7 @@ static void disas_sparc_insn(DisasContext * dc)
CHECK_FPU_FEATURE(dc, VIS1);
gen_op_load_fpr_DT0(DFPREG(rs1));
gen_op_load_fpr_DT1(DFPREG(rs2));
- gen_helper_fmuld8ulx16();
+ gen_helper_fmuld8ulx16(cpu_env);
gen_op_store_DT0_fpr(DFPREG(rd));
gen_update_fprs_dirty(DFPREG(rd));
break;
@@ -3980,7 +3988,7 @@ static void disas_sparc_insn(DisasContext * dc)
CHECK_FPU_FEATURE(dc, VIS1);
gen_op_load_fpr_DT0(DFPREG(rs1));
gen_op_load_fpr_DT1(DFPREG(rs2));
- gen_helper_faligndata();
+ gen_helper_faligndata(cpu_env);
gen_op_store_DT0_fpr(DFPREG(rd));
gen_update_fprs_dirty(DFPREG(rd));
break;
@@ -3988,7 +3996,7 @@ static void disas_sparc_insn(DisasContext * dc)
CHECK_FPU_FEATURE(dc, VIS1);
gen_op_load_fpr_DT0(DFPREG(rs1));
gen_op_load_fpr_DT1(DFPREG(rs2));
- gen_helper_fpmerge();
+ gen_helper_fpmerge(cpu_env);
gen_op_store_DT0_fpr(DFPREG(rd));
gen_update_fprs_dirty(DFPREG(rd));
break;
@@ -3999,7 +4007,7 @@ static void disas_sparc_insn(DisasContext * dc)
CHECK_FPU_FEATURE(dc, VIS1);
gen_op_load_fpr_DT0(DFPREG(rs1));
gen_op_load_fpr_DT1(DFPREG(rs2));
- gen_helper_fexpand();
+ gen_helper_fexpand(cpu_env);
gen_op_store_DT0_fpr(DFPREG(rd));
gen_update_fprs_dirty(DFPREG(rd));
break;
@@ -4007,13 +4015,13 @@ static void disas_sparc_insn(DisasContext * dc)
CHECK_FPU_FEATURE(dc, VIS1);
gen_op_load_fpr_DT0(DFPREG(rs1));
gen_op_load_fpr_DT1(DFPREG(rs2));
- gen_helper_fpadd16();
+ gen_helper_fpadd16(cpu_env);
gen_op_store_DT0_fpr(DFPREG(rd));
gen_update_fprs_dirty(DFPREG(rd));
break;
case 0x051: /* VIS I fpadd16s */
CHECK_FPU_FEATURE(dc, VIS1);
- gen_helper_fpadd16s(cpu_fpr[rd],
+ gen_helper_fpadd16s(cpu_fpr[rd], cpu_env,
cpu_fpr[rs1], cpu_fpr[rs2]);
gen_update_fprs_dirty(rd);
break;
@@ -4021,13 +4029,13 @@ static void disas_sparc_insn(DisasContext * dc)
CHECK_FPU_FEATURE(dc, VIS1);
gen_op_load_fpr_DT0(DFPREG(rs1));
gen_op_load_fpr_DT1(DFPREG(rs2));
- gen_helper_fpadd32();
+ gen_helper_fpadd32(cpu_env);
gen_op_store_DT0_fpr(DFPREG(rd));
gen_update_fprs_dirty(DFPREG(rd));
break;
case 0x053: /* VIS I fpadd32s */
CHECK_FPU_FEATURE(dc, VIS1);
- gen_helper_fpadd32s(cpu_fpr[rd],
+ gen_helper_fpadd32s(cpu_fpr[rd], cpu_env,
cpu_fpr[rs1], cpu_fpr[rs2]);
gen_update_fprs_dirty(rd);
break;
@@ -4035,13 +4043,13 @@ static void disas_sparc_insn(DisasContext * dc)
CHECK_FPU_FEATURE(dc, VIS1);
gen_op_load_fpr_DT0(DFPREG(rs1));
gen_op_load_fpr_DT1(DFPREG(rs2));
- gen_helper_fpsub16();
+ gen_helper_fpsub16(cpu_env);
gen_op_store_DT0_fpr(DFPREG(rd));
gen_update_fprs_dirty(DFPREG(rd));
break;
case 0x055: /* VIS I fpsub16s */
CHECK_FPU_FEATURE(dc, VIS1);
- gen_helper_fpsub16s(cpu_fpr[rd],
+ gen_helper_fpsub16s(cpu_fpr[rd], cpu_env,
cpu_fpr[rs1], cpu_fpr[rs2]);
gen_update_fprs_dirty(rd);
break;
@@ -4049,13 +4057,13 @@ static void disas_sparc_insn(DisasContext * dc)
CHECK_FPU_FEATURE(dc, VIS1);
gen_op_load_fpr_DT0(DFPREG(rs1));
gen_op_load_fpr_DT1(DFPREG(rs2));
- gen_helper_fpsub32();
+ gen_helper_fpsub32(cpu_env);
gen_op_store_DT0_fpr(DFPREG(rd));
gen_update_fprs_dirty(DFPREG(rd));
break;
case 0x057: /* VIS I fpsub32s */
CHECK_FPU_FEATURE(dc, VIS1);
- gen_helper_fpsub32s(cpu_fpr[rd],
+ gen_helper_fpsub32s(cpu_fpr[rd], cpu_env,
cpu_fpr[rs1], cpu_fpr[rs2]);
gen_update_fprs_dirty(rd);
break;
@@ -4303,7 +4311,7 @@ static void disas_sparc_insn(DisasContext * dc)
} else
tcg_gen_mov_tl(cpu_dst, cpu_src1);
}
- gen_helper_restore();
+ gen_helper_restore(cpu_env);
gen_mov_pc_npc(dc, cpu_cond);
r_const = tcg_const_i32(3);
gen_helper_check_align(cpu_dst, r_const);
@@ -4355,7 +4363,7 @@ static void disas_sparc_insn(DisasContext * dc)
tcg_temp_free_i32(r_const);
tcg_gen_mov_tl(cpu_npc, cpu_dst);
dc->npc = DYNAMIC_PC;
- gen_helper_rett();
+ gen_helper_rett(cpu_env);
}
goto jmp_insn;
#endif
@@ -4366,12 +4374,12 @@ static void disas_sparc_insn(DisasContext * dc)
break;
case 0x3c: /* save */
save_state(dc, cpu_cond);
- gen_helper_save();
+ gen_helper_save(cpu_env);
gen_movl_TN_reg(rd, cpu_dst);
break;
case 0x3d: /* restore */
save_state(dc, cpu_cond);
- gen_helper_restore();
+ gen_helper_restore(cpu_env);
gen_movl_TN_reg(rd, cpu_dst);
break;
#if !defined(CONFIG_USER_ONLY) && defined(TARGET_SPARC64)
@@ -4383,14 +4391,14 @@ static void disas_sparc_insn(DisasContext * dc)
goto priv_insn;
dc->npc = DYNAMIC_PC;
dc->pc = DYNAMIC_PC;
- gen_helper_done();
+ gen_helper_done(cpu_env);
goto jmp_insn;
case 1:
if (!supervisor(dc))
goto priv_insn;
dc->npc = DYNAMIC_PC;
dc->pc = DYNAMIC_PC;
- gen_helper_retry();
+ gen_helper_retry(cpu_env);
goto jmp_insn;
default:
goto illegal_insn;
@@ -4413,7 +4421,7 @@ static void disas_sparc_insn(DisasContext * dc)
cpu state */
if (dc->cc_op != CC_OP_FLAGS) {
dc->cc_op = CC_OP_FLAGS;
- gen_helper_compute_psr();
+ gen_helper_compute_psr(cpu_env);
}
cpu_src1 = get_src1(insn, cpu_src1);
if (xop == 0x3c || xop == 0x3e) { // V9 casa/casxa
@@ -4659,16 +4667,16 @@ static void disas_sparc_insn(DisasContext * dc)
gen_address_mask(dc, cpu_addr);
if (rd == 1) {
tcg_gen_qemu_ld64(cpu_tmp64, cpu_addr, dc->mem_idx);
- gen_helper_ldxfsr(cpu_tmp64);
+ gen_helper_ldxfsr(cpu_env, cpu_tmp64);
} else {
tcg_gen_qemu_ld32u(cpu_tmp0, cpu_addr, dc->mem_idx);
tcg_gen_trunc_tl_i32(cpu_tmp32, cpu_tmp0);
- gen_helper_ldfsr(cpu_tmp32);
+ gen_helper_ldfsr(cpu_env, cpu_tmp32);
}
#else
{
tcg_gen_qemu_ld32u(cpu_tmp32, cpu_addr, dc->mem_idx);
- gen_helper_ldfsr(cpu_tmp32);
+ gen_helper_ldfsr(cpu_env, cpu_tmp32);
}
#endif
break;
@@ -4931,7 +4939,7 @@ static void disas_sparc_insn(DisasContext * dc)
save_state(dc, cpu_cond);
r_const = tcg_const_i32(TT_ILL_INSN);
- gen_helper_raise_exception(r_const);
+ gen_helper_raise_exception(cpu_env, r_const);
tcg_temp_free_i32(r_const);
dc->is_br = 1;
}
@@ -4942,7 +4950,7 @@ static void disas_sparc_insn(DisasContext * dc)
save_state(dc, cpu_cond);
r_const = tcg_const_i32(TT_UNIMP_FLUSH);
- gen_helper_raise_exception(r_const);
+ gen_helper_raise_exception(cpu_env, r_const);
tcg_temp_free_i32(r_const);
dc->is_br = 1;
}
@@ -4954,7 +4962,7 @@ static void disas_sparc_insn(DisasContext * dc)
save_state(dc, cpu_cond);
r_const = tcg_const_i32(TT_PRIV_INSN);
- gen_helper_raise_exception(r_const);
+ gen_helper_raise_exception(cpu_env, r_const);
tcg_temp_free_i32(r_const);
dc->is_br = 1;
}
@@ -4979,7 +4987,7 @@ static void disas_sparc_insn(DisasContext * dc)
save_state(dc, cpu_cond);
r_const = tcg_const_i32(TT_NCP_INSN);
- gen_helper_raise_exception(r_const);
+ gen_helper_raise_exception(cpu_env, r_const);
tcg_temp_free(r_const);
dc->is_br = 1;
}
@@ -5036,7 +5044,7 @@ static inline void gen_intermediate_code_internal(TranslationBlock * tb,
if (bp->pc == dc->pc) {
if (dc->pc != pc_start)
save_state(dc, cpu_cond);
- gen_helper_debug();
+ gen_helper_debug(cpu_env);
tcg_gen_exit_tb(0);
dc->is_br = 1;
goto exit_gen_loop;
@@ -5265,6 +5273,6 @@ void restore_state_to_opc(CPUState *env, TranslationBlock *tb, int pc_pos)
/* flush pending conditional evaluations before exposing cpu state */
if (CC_OP != CC_OP_FLAGS) {
- helper_compute_psr();
+ helper_compute_psr(env);
}
}
diff --git a/target-sparc/vis_helper.c b/target-sparc/vis_helper.c
new file mode 100644
index 0000000000..a22c10bb43
--- /dev/null
+++ b/target-sparc/vis_helper.c
@@ -0,0 +1,406 @@
+/*
+ * VIS op helpers
+ *
+ * Copyright (c) 2003-2005 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cpu.h"
+#include "helper.h"
+
+#define DT0 (env->dt0)
+#define DT1 (env->dt1)
+#define QT0 (env->qt0)
+#define QT1 (env->qt1)
+
+/* This function uses non-native bit order */
+#define GET_FIELD(X, FROM, TO) \
+ ((X) >> (63 - (TO)) & ((1ULL << ((TO) - (FROM) + 1)) - 1))
+
+/* This function uses the order in the manuals, i.e. bit 0 is 2^0 */
+#define GET_FIELD_SP(X, FROM, TO) \
+ GET_FIELD(X, 63 - (TO), 63 - (FROM))
+
+target_ulong helper_array8(CPUState *env, target_ulong pixel_addr,
+ target_ulong cubesize)
+{
+ return (GET_FIELD_SP(pixel_addr, 60, 63) << (17 + 2 * cubesize)) |
+ (GET_FIELD_SP(pixel_addr, 39, 39 + cubesize - 1) << (17 + cubesize)) |
+ (GET_FIELD_SP(pixel_addr, 17 + cubesize - 1, 17) << 17) |
+ (GET_FIELD_SP(pixel_addr, 56, 59) << 13) |
+ (GET_FIELD_SP(pixel_addr, 35, 38) << 9) |
+ (GET_FIELD_SP(pixel_addr, 13, 16) << 5) |
+ (((pixel_addr >> 55) & 1) << 4) |
+ (GET_FIELD_SP(pixel_addr, 33, 34) << 2) |
+ GET_FIELD_SP(pixel_addr, 11, 12);
+}
+
+target_ulong helper_alignaddr(CPUState *env, target_ulong addr,
+ target_ulong offset)
+{
+ uint64_t tmp;
+
+ tmp = addr + offset;
+ env->gsr &= ~7ULL;
+ env->gsr |= tmp & 7ULL;
+ return tmp & ~7ULL;
+}
+
+void helper_faligndata(CPUState *env)
+{
+ uint64_t tmp;
+
+ tmp = (*((uint64_t *)&DT0)) << ((env->gsr & 7) * 8);
+ /* on many architectures a shift of 64 does nothing */
+ if ((env->gsr & 7) != 0) {
+ tmp |= (*((uint64_t *)&DT1)) >> (64 - (env->gsr & 7) * 8);
+ }
+ *((uint64_t *)&DT0) = tmp;
+}
+
+#ifdef HOST_WORDS_BIGENDIAN
+#define VIS_B64(n) b[7 - (n)]
+#define VIS_W64(n) w[3 - (n)]
+#define VIS_SW64(n) sw[3 - (n)]
+#define VIS_L64(n) l[1 - (n)]
+#define VIS_B32(n) b[3 - (n)]
+#define VIS_W32(n) w[1 - (n)]
+#else
+#define VIS_B64(n) b[n]
+#define VIS_W64(n) w[n]
+#define VIS_SW64(n) sw[n]
+#define VIS_L64(n) l[n]
+#define VIS_B32(n) b[n]
+#define VIS_W32(n) w[n]
+#endif
+
+typedef union {
+ uint8_t b[8];
+ uint16_t w[4];
+ int16_t sw[4];
+ uint32_t l[2];
+ uint64_t ll;
+ float64 d;
+} VIS64;
+
+typedef union {
+ uint8_t b[4];
+ uint16_t w[2];
+ uint32_t l;
+ float32 f;
+} VIS32;
+
+void helper_fpmerge(CPUState *env)
+{
+ VIS64 s, d;
+
+ s.d = DT0;
+ d.d = DT1;
+
+ /* Reverse calculation order to handle overlap */
+ d.VIS_B64(7) = s.VIS_B64(3);
+ d.VIS_B64(6) = d.VIS_B64(3);
+ d.VIS_B64(5) = s.VIS_B64(2);
+ d.VIS_B64(4) = d.VIS_B64(2);
+ d.VIS_B64(3) = s.VIS_B64(1);
+ d.VIS_B64(2) = d.VIS_B64(1);
+ d.VIS_B64(1) = s.VIS_B64(0);
+ /* d.VIS_B64(0) = d.VIS_B64(0); */
+
+ DT0 = d.d;
+}
+
+void helper_fmul8x16(CPUState *env)
+{
+ VIS64 s, d;
+ uint32_t tmp;
+
+ s.d = DT0;
+ d.d = DT1;
+
+#define PMUL(r) \
+ tmp = (int32_t)d.VIS_SW64(r) * (int32_t)s.VIS_B64(r); \
+ if ((tmp & 0xff) > 0x7f) { \
+ tmp += 0x100; \
+ } \
+ d.VIS_W64(r) = tmp >> 8;
+
+ PMUL(0);
+ PMUL(1);
+ PMUL(2);
+ PMUL(3);
+#undef PMUL
+
+ DT0 = d.d;
+}
+
+void helper_fmul8x16al(CPUState *env)
+{
+ VIS64 s, d;
+ uint32_t tmp;
+
+ s.d = DT0;
+ d.d = DT1;
+
+#define PMUL(r) \
+ tmp = (int32_t)d.VIS_SW64(1) * (int32_t)s.VIS_B64(r); \
+ if ((tmp & 0xff) > 0x7f) { \
+ tmp += 0x100; \
+ } \
+ d.VIS_W64(r) = tmp >> 8;
+
+ PMUL(0);
+ PMUL(1);
+ PMUL(2);
+ PMUL(3);
+#undef PMUL
+
+ DT0 = d.d;
+}
+
+void helper_fmul8x16au(CPUState *env)
+{
+ VIS64 s, d;
+ uint32_t tmp;
+
+ s.d = DT0;
+ d.d = DT1;
+
+#define PMUL(r) \
+ tmp = (int32_t)d.VIS_SW64(0) * (int32_t)s.VIS_B64(r); \
+ if ((tmp & 0xff) > 0x7f) { \
+ tmp += 0x100; \
+ } \
+ d.VIS_W64(r) = tmp >> 8;
+
+ PMUL(0);
+ PMUL(1);
+ PMUL(2);
+ PMUL(3);
+#undef PMUL
+
+ DT0 = d.d;
+}
+
+void helper_fmul8sux16(CPUState *env)
+{
+ VIS64 s, d;
+ uint32_t tmp;
+
+ s.d = DT0;
+ d.d = DT1;
+
+#define PMUL(r) \
+ tmp = (int32_t)d.VIS_SW64(r) * ((int32_t)s.VIS_SW64(r) >> 8); \
+ if ((tmp & 0xff) > 0x7f) { \
+ tmp += 0x100; \
+ } \
+ d.VIS_W64(r) = tmp >> 8;
+
+ PMUL(0);
+ PMUL(1);
+ PMUL(2);
+ PMUL(3);
+#undef PMUL
+
+ DT0 = d.d;
+}
+
+void helper_fmul8ulx16(CPUState *env)
+{
+ VIS64 s, d;
+ uint32_t tmp;
+
+ s.d = DT0;
+ d.d = DT1;
+
+#define PMUL(r) \
+ tmp = (int32_t)d.VIS_SW64(r) * ((uint32_t)s.VIS_B64(r * 2)); \
+ if ((tmp & 0xff) > 0x7f) { \
+ tmp += 0x100; \
+ } \
+ d.VIS_W64(r) = tmp >> 8;
+
+ PMUL(0);
+ PMUL(1);
+ PMUL(2);
+ PMUL(3);
+#undef PMUL
+
+ DT0 = d.d;
+}
+
+void helper_fmuld8sux16(CPUState *env)
+{
+ VIS64 s, d;
+ uint32_t tmp;
+
+ s.d = DT0;
+ d.d = DT1;
+
+#define PMUL(r) \
+ tmp = (int32_t)d.VIS_SW64(r) * ((int32_t)s.VIS_SW64(r) >> 8); \
+ if ((tmp & 0xff) > 0x7f) { \
+ tmp += 0x100; \
+ } \
+ d.VIS_L64(r) = tmp;
+
+ /* Reverse calculation order to handle overlap */
+ PMUL(1);
+ PMUL(0);
+#undef PMUL
+
+ DT0 = d.d;
+}
+
+void helper_fmuld8ulx16(CPUState *env)
+{
+ VIS64 s, d;
+ uint32_t tmp;
+
+ s.d = DT0;
+ d.d = DT1;
+
+#define PMUL(r) \
+ tmp = (int32_t)d.VIS_SW64(r) * ((uint32_t)s.VIS_B64(r * 2)); \
+ if ((tmp & 0xff) > 0x7f) { \
+ tmp += 0x100; \
+ } \
+ d.VIS_L64(r) = tmp;
+
+ /* Reverse calculation order to handle overlap */
+ PMUL(1);
+ PMUL(0);
+#undef PMUL
+
+ DT0 = d.d;
+}
+
+void helper_fexpand(CPUState *env)
+{
+ VIS32 s;
+ VIS64 d;
+
+ s.l = (uint32_t)(*(uint64_t *)&DT0 & 0xffffffff);
+ d.d = DT1;
+ d.VIS_W64(0) = s.VIS_B32(0) << 4;
+ d.VIS_W64(1) = s.VIS_B32(1) << 4;
+ d.VIS_W64(2) = s.VIS_B32(2) << 4;
+ d.VIS_W64(3) = s.VIS_B32(3) << 4;
+
+ DT0 = d.d;
+}
+
+#define VIS_HELPER(name, F) \
+ void name##16(CPUState *env) \
+ { \
+ VIS64 s, d; \
+ \
+ s.d = DT0; \
+ d.d = DT1; \
+ \
+ d.VIS_W64(0) = F(d.VIS_W64(0), s.VIS_W64(0)); \
+ d.VIS_W64(1) = F(d.VIS_W64(1), s.VIS_W64(1)); \
+ d.VIS_W64(2) = F(d.VIS_W64(2), s.VIS_W64(2)); \
+ d.VIS_W64(3) = F(d.VIS_W64(3), s.VIS_W64(3)); \
+ \
+ DT0 = d.d; \
+ } \
+ \
+ uint32_t name##16s(CPUState *env, uint32_t src1, \
+ uint32_t src2) \
+ { \
+ VIS32 s, d; \
+ \
+ s.l = src1; \
+ d.l = src2; \
+ \
+ d.VIS_W32(0) = F(d.VIS_W32(0), s.VIS_W32(0)); \
+ d.VIS_W32(1) = F(d.VIS_W32(1), s.VIS_W32(1)); \
+ \
+ return d.l; \
+ } \
+ \
+ void name##32(CPUState *env) \
+ { \
+ VIS64 s, d; \
+ \
+ s.d = DT0; \
+ d.d = DT1; \
+ \
+ d.VIS_L64(0) = F(d.VIS_L64(0), s.VIS_L64(0)); \
+ d.VIS_L64(1) = F(d.VIS_L64(1), s.VIS_L64(1)); \
+ \
+ DT0 = d.d; \
+ } \
+ \
+ uint32_t name##32s(CPUState *env, uint32_t src1, \
+ uint32_t src2) \
+ { \
+ VIS32 s, d; \
+ \
+ s.l = src1; \
+ d.l = src2; \
+ \
+ d.l = F(d.l, s.l); \
+ \
+ return d.l; \
+ }
+
+#define FADD(a, b) ((a) + (b))
+#define FSUB(a, b) ((a) - (b))
+VIS_HELPER(helper_fpadd, FADD)
+VIS_HELPER(helper_fpsub, FSUB)
+
+#define VIS_CMPHELPER(name, F) \
+ uint64_t name##16(CPUState *env) \
+ { \
+ VIS64 s, d; \
+ \
+ s.d = DT0; \
+ d.d = DT1; \
+ \
+ d.VIS_W64(0) = F(s.VIS_W64(0), d.VIS_W64(0)) ? 1 : 0; \
+ d.VIS_W64(0) |= F(s.VIS_W64(1), d.VIS_W64(1)) ? 2 : 0; \
+ d.VIS_W64(0) |= F(s.VIS_W64(2), d.VIS_W64(2)) ? 4 : 0; \
+ d.VIS_W64(0) |= F(s.VIS_W64(3), d.VIS_W64(3)) ? 8 : 0; \
+ d.VIS_W64(1) = d.VIS_W64(2) = d.VIS_W64(3) = 0; \
+ \
+ return d.ll; \
+ } \
+ \
+ uint64_t name##32(CPUState *env) \
+ { \
+ VIS64 s, d; \
+ \
+ s.d = DT0; \
+ d.d = DT1; \
+ \
+ d.VIS_L64(0) = F(s.VIS_L64(0), d.VIS_L64(0)) ? 1 : 0; \
+ d.VIS_L64(0) |= F(s.VIS_L64(1), d.VIS_L64(1)) ? 2 : 0; \
+ d.VIS_L64(1) = 0; \
+ \
+ return d.ll; \
+ }
+
+#define FCMPGT(a, b) ((a) > (b))
+#define FCMPEQ(a, b) ((a) == (b))
+#define FCMPLE(a, b) ((a) <= (b))
+#define FCMPNE(a, b) ((a) != (b))
+
+VIS_CMPHELPER(helper_fcmpgt, FCMPGT)
+VIS_CMPHELPER(helper_fcmpeq, FCMPEQ)
+VIS_CMPHELPER(helper_fcmple, FCMPLE)
+VIS_CMPHELPER(helper_fcmpne, FCMPNE)
diff --git a/target-sparc/win_helper.c b/target-sparc/win_helper.c
new file mode 100644
index 0000000000..a68c649e7e
--- /dev/null
+++ b/target-sparc/win_helper.c
@@ -0,0 +1,393 @@
+/*
+ * Helpers for CWP and PSTATE handling
+ *
+ * Copyright (c) 2003-2005 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cpu.h"
+#include "helper.h"
+#include "trace.h"
+
+static inline void memcpy32(target_ulong *dst, const target_ulong *src)
+{
+ dst[0] = src[0];
+ dst[1] = src[1];
+ dst[2] = src[2];
+ dst[3] = src[3];
+ dst[4] = src[4];
+ dst[5] = src[5];
+ dst[6] = src[6];
+ dst[7] = src[7];
+}
+
+void cpu_set_cwp(CPUState *env, int new_cwp)
+{
+ /* put the modified wrap registers at their proper location */
+ if (env->cwp == env->nwindows - 1) {
+ memcpy32(env->regbase, env->regbase + env->nwindows * 16);
+ }
+ env->cwp = new_cwp;
+
+ /* put the wrap registers at their temporary location */
+ if (new_cwp == env->nwindows - 1) {
+ memcpy32(env->regbase + env->nwindows * 16, env->regbase);
+ }
+ env->regwptr = env->regbase + (new_cwp * 16);
+}
+
+target_ulong cpu_get_psr(CPUState *env)
+{
+ helper_compute_psr(env);
+
+#if !defined(TARGET_SPARC64)
+ return env->version | (env->psr & PSR_ICC) |
+ (env->psref ? PSR_EF : 0) |
+ (env->psrpil << 8) |
+ (env->psrs ? PSR_S : 0) |
+ (env->psrps ? PSR_PS : 0) |
+ (env->psret ? PSR_ET : 0) | env->cwp;
+#else
+ return env->psr & PSR_ICC;
+#endif
+}
+
+void cpu_put_psr(CPUState *env, target_ulong val)
+{
+ env->psr = val & PSR_ICC;
+#if !defined(TARGET_SPARC64)
+ env->psref = (val & PSR_EF) ? 1 : 0;
+ env->psrpil = (val & PSR_PIL) >> 8;
+#endif
+#if ((!defined(TARGET_SPARC64)) && !defined(CONFIG_USER_ONLY))
+ cpu_check_irqs(env);
+#endif
+#if !defined(TARGET_SPARC64)
+ env->psrs = (val & PSR_S) ? 1 : 0;
+ env->psrps = (val & PSR_PS) ? 1 : 0;
+ env->psret = (val & PSR_ET) ? 1 : 0;
+ cpu_set_cwp(env, val & PSR_CWP);
+#endif
+ env->cc_op = CC_OP_FLAGS;
+}
+
+int cpu_cwp_inc(CPUState *env, int cwp)
+{
+ if (unlikely(cwp >= env->nwindows)) {
+ cwp -= env->nwindows;
+ }
+ return cwp;
+}
+
+int cpu_cwp_dec(CPUState *env, int cwp)
+{
+ if (unlikely(cwp < 0)) {
+ cwp += env->nwindows;
+ }
+ return cwp;
+}
+
+#ifndef TARGET_SPARC64
+void helper_rett(CPUState *env)
+{
+ unsigned int cwp;
+
+ if (env->psret == 1) {
+ helper_raise_exception(env, TT_ILL_INSN);
+ }
+
+ env->psret = 1;
+ cwp = cpu_cwp_inc(env, env->cwp + 1) ;
+ if (env->wim & (1 << cwp)) {
+ helper_raise_exception(env, TT_WIN_UNF);
+ }
+ cpu_set_cwp(env, cwp);
+ env->psrs = env->psrps;
+}
+
+/* XXX: use another pointer for %iN registers to avoid slow wrapping
+ handling ? */
+void helper_save(CPUState *env)
+{
+ uint32_t cwp;
+
+ cwp = cpu_cwp_dec(env, env->cwp - 1);
+ if (env->wim & (1 << cwp)) {
+ helper_raise_exception(env, TT_WIN_OVF);
+ }
+ cpu_set_cwp(env, cwp);
+}
+
+void helper_restore(CPUState *env)
+{
+ uint32_t cwp;
+
+ cwp = cpu_cwp_inc(env, env->cwp + 1);
+ if (env->wim & (1 << cwp)) {
+ helper_raise_exception(env, TT_WIN_UNF);
+ }
+ cpu_set_cwp(env, cwp);
+}
+
+void helper_wrpsr(CPUState *env, target_ulong new_psr)
+{
+ if ((new_psr & PSR_CWP) >= env->nwindows) {
+ helper_raise_exception(env, TT_ILL_INSN);
+ } else {
+ cpu_put_psr(env, new_psr);
+ }
+}
+
+target_ulong helper_rdpsr(CPUState *env)
+{
+ return cpu_get_psr(env);
+}
+
+#else
+/* XXX: use another pointer for %iN registers to avoid slow wrapping
+ handling ? */
+void helper_save(CPUState *env)
+{
+ uint32_t cwp;
+
+ cwp = cpu_cwp_dec(env, env->cwp - 1);
+ if (env->cansave == 0) {
+ helper_raise_exception(env, TT_SPILL | (env->otherwin != 0 ?
+ (TT_WOTHER |
+ ((env->wstate & 0x38) >> 1)) :
+ ((env->wstate & 0x7) << 2)));
+ } else {
+ if (env->cleanwin - env->canrestore == 0) {
+ /* XXX Clean windows without trap */
+ helper_raise_exception(env, TT_CLRWIN);
+ } else {
+ env->cansave--;
+ env->canrestore++;
+ cpu_set_cwp(env, cwp);
+ }
+ }
+}
+
+void helper_restore(CPUState *env)
+{
+ uint32_t cwp;
+
+ cwp = cpu_cwp_inc(env, env->cwp + 1);
+ if (env->canrestore == 0) {
+ helper_raise_exception(env, TT_FILL | (env->otherwin != 0 ?
+ (TT_WOTHER |
+ ((env->wstate & 0x38) >> 1)) :
+ ((env->wstate & 0x7) << 2)));
+ } else {
+ env->cansave++;
+ env->canrestore--;
+ cpu_set_cwp(env, cwp);
+ }
+}
+
+void helper_flushw(CPUState *env)
+{
+ if (env->cansave != env->nwindows - 2) {
+ helper_raise_exception(env, TT_SPILL | (env->otherwin != 0 ?
+ (TT_WOTHER |
+ ((env->wstate & 0x38) >> 1)) :
+ ((env->wstate & 0x7) << 2)));
+ }
+}
+
+void helper_saved(CPUState *env)
+{
+ env->cansave++;
+ if (env->otherwin == 0) {
+ env->canrestore--;
+ } else {
+ env->otherwin--;
+ }
+}
+
+void helper_restored(CPUState *env)
+{
+ env->canrestore++;
+ if (env->cleanwin < env->nwindows - 1) {
+ env->cleanwin++;
+ }
+ if (env->otherwin == 0) {
+ env->cansave--;
+ } else {
+ env->otherwin--;
+ }
+}
+
+target_ulong cpu_get_ccr(CPUState *env)
+{
+ target_ulong psr;
+
+ psr = cpu_get_psr(env);
+
+ return ((env->xcc >> 20) << 4) | ((psr & PSR_ICC) >> 20);
+}
+
+void cpu_put_ccr(CPUState *env, target_ulong val)
+{
+ env->xcc = (val >> 4) << 20;
+ env->psr = (val & 0xf) << 20;
+ CC_OP = CC_OP_FLAGS;
+}
+
+target_ulong cpu_get_cwp64(CPUState *env)
+{
+ return env->nwindows - 1 - env->cwp;
+}
+
+void cpu_put_cwp64(CPUState *env, int cwp)
+{
+ if (unlikely(cwp >= env->nwindows || cwp < 0)) {
+ cwp %= env->nwindows;
+ }
+ cpu_set_cwp(env, env->nwindows - 1 - cwp);
+}
+
+target_ulong helper_rdccr(CPUState *env)
+{
+ return cpu_get_ccr(env);
+}
+
+void helper_wrccr(CPUState *env, target_ulong new_ccr)
+{
+ cpu_put_ccr(env, new_ccr);
+}
+
+/* CWP handling is reversed in V9, but we still use the V8 register
+ order. */
+target_ulong helper_rdcwp(CPUState *env)
+{
+ return cpu_get_cwp64(env);
+}
+
+void helper_wrcwp(CPUState *env, target_ulong new_cwp)
+{
+ cpu_put_cwp64(env, new_cwp);
+}
+
+static inline uint64_t *get_gregset(CPUState *env, uint32_t pstate)
+{
+ switch (pstate) {
+ default:
+ trace_win_helper_gregset_error(pstate);
+ /* pass through to normal set of global registers */
+ case 0:
+ return env->bgregs;
+ case PS_AG:
+ return env->agregs;
+ case PS_MG:
+ return env->mgregs;
+ case PS_IG:
+ return env->igregs;
+ }
+}
+
+void cpu_change_pstate(CPUState *env, uint32_t new_pstate)
+{
+ uint32_t pstate_regs, new_pstate_regs;
+ uint64_t *src, *dst;
+
+ if (env->def->features & CPU_FEATURE_GL) {
+ /* PS_AG is not implemented in this case */
+ new_pstate &= ~PS_AG;
+ }
+
+ pstate_regs = env->pstate & 0xc01;
+ new_pstate_regs = new_pstate & 0xc01;
+
+ if (new_pstate_regs != pstate_regs) {
+ trace_win_helper_switch_pstate(pstate_regs, new_pstate_regs);
+
+ /* Switch global register bank */
+ src = get_gregset(env, new_pstate_regs);
+ dst = get_gregset(env, pstate_regs);
+ memcpy32(dst, env->gregs);
+ memcpy32(env->gregs, src);
+ } else {
+ trace_win_helper_no_switch_pstate(new_pstate_regs);
+ }
+ env->pstate = new_pstate;
+}
+
+void helper_wrpstate(CPUState *env, target_ulong new_state)
+{
+ cpu_change_pstate(env, new_state & 0xf3f);
+
+#if !defined(CONFIG_USER_ONLY)
+ if (cpu_interrupts_enabled(env)) {
+ cpu_check_irqs(env);
+ }
+#endif
+}
+
+void helper_wrpil(CPUState *env, target_ulong new_pil)
+{
+#if !defined(CONFIG_USER_ONLY)
+ trace_win_helper_wrpil(env->psrpil, (uint32_t)new_pil);
+
+ env->psrpil = new_pil;
+
+ if (cpu_interrupts_enabled(env)) {
+ cpu_check_irqs(env);
+ }
+#endif
+}
+
+void helper_done(CPUState *env)
+{
+ trap_state *tsptr = cpu_tsptr(env);
+
+ env->pc = tsptr->tnpc;
+ env->npc = tsptr->tnpc + 4;
+ cpu_put_ccr(env, tsptr->tstate >> 32);
+ env->asi = (tsptr->tstate >> 24) & 0xff;
+ cpu_change_pstate(env, (tsptr->tstate >> 8) & 0xf3f);
+ cpu_put_cwp64(env, tsptr->tstate & 0xff);
+ env->tl--;
+
+ trace_win_helper_done(env->tl);
+
+#if !defined(CONFIG_USER_ONLY)
+ if (cpu_interrupts_enabled(env)) {
+ cpu_check_irqs(env);
+ }
+#endif
+}
+
+void helper_retry(CPUState *env)
+{
+ trap_state *tsptr = cpu_tsptr(env);
+
+ env->pc = tsptr->tpc;
+ env->npc = tsptr->tnpc;
+ cpu_put_ccr(env, tsptr->tstate >> 32);
+ env->asi = (tsptr->tstate >> 24) & 0xff;
+ cpu_change_pstate(env, (tsptr->tstate >> 8) & 0xf3f);
+ cpu_put_cwp64(env, tsptr->tstate & 0xff);
+ env->tl--;
+
+ trace_win_helper_retry(env->tl);
+
+#if !defined(CONFIG_USER_ONLY)
+ if (cpu_interrupts_enabled(env)) {
+ cpu_check_irqs(env);
+ }
+#endif
+}
+#endif