diff options
Diffstat (limited to 'qemu/target-sparc')
-rw-r--r-- | qemu/target-sparc/Makefile.objs | 2 | ||||
-rw-r--r-- | qemu/target-sparc/cc_helper.c | 1 | ||||
-rw-r--r-- | qemu/target-sparc/cpu-qom.h | 4 | ||||
-rw-r--r-- | qemu/target-sparc/cpu.c | 19 | ||||
-rw-r--r-- | qemu/target-sparc/cpu.h | 20 | ||||
-rw-r--r-- | qemu/target-sparc/fop_helper.c | 1 | ||||
-rw-r--r-- | qemu/target-sparc/gdbstub.c | 2 | ||||
-rw-r--r-- | qemu/target-sparc/helper.c | 11 | ||||
-rw-r--r-- | qemu/target-sparc/helper.h | 2 | ||||
-rw-r--r-- | qemu/target-sparc/int32_helper.c | 2 | ||||
-rw-r--r-- | qemu/target-sparc/int64_helper.c | 7 | ||||
-rw-r--r-- | qemu/target-sparc/ldst_helper.c | 13 | ||||
-rw-r--r-- | qemu/target-sparc/machine.c | 371 | ||||
-rw-r--r-- | qemu/target-sparc/mmu_helper.c | 3 | ||||
-rw-r--r-- | qemu/target-sparc/monitor.c | 159 | ||||
-rw-r--r-- | qemu/target-sparc/translate.c | 438 | ||||
-rw-r--r-- | qemu/target-sparc/vis_helper.c | 3 | ||||
-rw-r--r-- | qemu/target-sparc/win_helper.c | 20 |
18 files changed, 610 insertions, 468 deletions
diff --git a/qemu/target-sparc/Makefile.objs b/qemu/target-sparc/Makefile.objs index 1cd81cccc..ec905698c 100644 --- a/qemu/target-sparc/Makefile.objs +++ b/qemu/target-sparc/Makefile.objs @@ -1,4 +1,4 @@ -obj-$(CONFIG_SOFTMMU) += machine.o +obj-$(CONFIG_SOFTMMU) += machine.o monitor.o obj-y += translate.o helper.o cpu.o obj-y += fop_helper.o cc_helper.o win_helper.o mmu_helper.o ldst_helper.o obj-$(TARGET_SPARC) += int32_helper.o diff --git a/qemu/target-sparc/cc_helper.c b/qemu/target-sparc/cc_helper.c index 35dab7321..44c440934 100644 --- a/qemu/target-sparc/cc_helper.c +++ b/qemu/target-sparc/cc_helper.c @@ -17,6 +17,7 @@ * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ +#include "qemu/osdep.h" #include "cpu.h" #include "exec/helper-proto.h" diff --git a/qemu/target-sparc/cpu-qom.h b/qemu/target-sparc/cpu-qom.h index 477c4d513..5096b1047 100644 --- a/qemu/target-sparc/cpu-qom.h +++ b/qemu/target-sparc/cpu-qom.h @@ -75,6 +75,10 @@ static inline SPARCCPU *sparc_env_get_cpu(CPUSPARCState *env) #define ENV_OFFSET offsetof(SPARCCPU, env) +#ifndef CONFIG_USER_ONLY +extern const struct VMStateDescription vmstate_sparc_cpu; +#endif + void sparc_cpu_do_interrupt(CPUState *cpu); void sparc_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf, int flags); diff --git a/qemu/target-sparc/cpu.c b/qemu/target-sparc/cpu.c index 9528e3afb..fe4119e2b 100644 --- a/qemu/target-sparc/cpu.c +++ b/qemu/target-sparc/cpu.c @@ -17,6 +17,8 @@ * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ +#include "qemu/osdep.h" +#include "qapi/error.h" #include "cpu.h" #include "qemu/error-report.h" @@ -90,6 +92,14 @@ static bool sparc_cpu_exec_interrupt(CPUState *cs, int interrupt_request) return false; } +static void cpu_sparc_disas_set_info(CPUState *cpu, disassemble_info *info) +{ + info->print_insn = print_insn_sparc; +#ifdef TARGET_SPARC64 + info->mach = bfd_mach_sparc_v9b; +#endif +} + static int cpu_sparc_register(SPARCCPU *cpu, const char *cpu_model) { CPUClass *cc = CPU_GET_CLASS(cpu); @@ -847,13 +857,22 @@ static void sparc_cpu_class_init(ObjectClass *oc, void *data) cc->do_unassigned_access = sparc_cpu_unassigned_access; cc->do_unaligned_access = sparc_cpu_do_unaligned_access; cc->get_phys_page_debug = sparc_cpu_get_phys_page_debug; + cc->vmsd = &vmstate_sparc_cpu; #endif + cc->disas_set_info = cpu_sparc_disas_set_info; #if defined(TARGET_SPARC64) && !defined(TARGET_ABI32) cc->gdb_num_core_regs = 86; #else cc->gdb_num_core_regs = 72; #endif + + /* + * Reason: sparc_cpu_initfn() calls cpu_exec_init(), which saves + * the object in cpus -> dangling pointer after final + * object_unref(). + */ + dc->cannot_destroy_with_object_finalize_yet = true; } static const TypeInfo sparc_cpu_type_info = { diff --git a/qemu/target-sparc/cpu.h b/qemu/target-sparc/cpu.h index 0522b65f1..dc4612275 100644 --- a/qemu/target-sparc/cpu.h +++ b/qemu/target-sparc/cpu.h @@ -1,7 +1,6 @@ #ifndef CPU_SPARC_H #define CPU_SPARC_H -#include "config.h" #include "qemu-common.h" #include "qemu/bswap.h" @@ -31,12 +30,6 @@ #include "fpu/softfloat.h" -#if !defined(TARGET_SPARC64) -#define ELF_MACHINE EM_SPARC -#else -#define ELF_MACHINE EM_SPARCV9 -#endif - /*#define EXCP_INTERRUPT 0x100*/ /* trap definitions */ @@ -236,6 +229,7 @@ typedef struct trap_state { uint32_t tt; } trap_state; #endif +#define TARGET_INSN_START_EXTRA_WORDS 1 typedef struct sparc_def_t { const char *name; @@ -371,16 +365,14 @@ struct CPUTimer uint32_t frequency; uint32_t disabled; uint64_t disabled_mask; + uint32_t npt; + uint64_t npt_mask; int64_t clock_offset; QEMUTimer *qtimer; }; typedef struct CPUTimer CPUTimer; -struct QEMUFile; -void cpu_put_timer(struct QEMUFile *f, CPUTimer *s); -void cpu_get_timer(struct QEMUFile *f, CPUTimer *s); - typedef struct CPUSPARCState CPUSPARCState; struct CPUSPARCState { @@ -542,6 +534,7 @@ int cpu_sparc_exec(CPUState *cpu); /* win_helper.c */ target_ulong cpu_get_psr(CPUSPARCState *env1); void cpu_put_psr(CPUSPARCState *env1, target_ulong val); +void cpu_put_psr_raw(CPUSPARCState *env1, target_ulong val); #ifdef TARGET_SPARC64 target_ulong cpu_get_ccr(CPUSPARCState *env1); void cpu_put_ccr(CPUSPARCState *env1, target_ulong val); @@ -598,12 +591,9 @@ int cpu_sparc_signal_handler(int host_signum, void *pinfo, void *puc); #endif #define cpu_exec cpu_sparc_exec -#define cpu_gen_code cpu_sparc_gen_code #define cpu_signal_handler cpu_sparc_signal_handler #define cpu_list sparc_cpu_list -#define CPU_SAVE_VERSION 7 - /* MMU modes definitions */ #if defined (TARGET_SPARC64) #define MMU_USER_IDX 0 @@ -642,7 +632,7 @@ static inline int cpu_supervisor_mode(CPUSPARCState *env1) } #endif -static inline int cpu_mmu_index(CPUSPARCState *env1) +static inline int cpu_mmu_index(CPUSPARCState *env1, bool ifetch) { #if defined(CONFIG_USER_ONLY) return MMU_USER_IDX; diff --git a/qemu/target-sparc/fop_helper.c b/qemu/target-sparc/fop_helper.c index ee4592ef2..08306436a 100644 --- a/qemu/target-sparc/fop_helper.c +++ b/qemu/target-sparc/fop_helper.c @@ -17,6 +17,7 @@ * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ +#include "qemu/osdep.h" #include "cpu.h" #include "exec/helper-proto.h" diff --git a/qemu/target-sparc/gdbstub.c b/qemu/target-sparc/gdbstub.c index 3de3242b2..e530dc52f 100644 --- a/qemu/target-sparc/gdbstub.c +++ b/qemu/target-sparc/gdbstub.c @@ -17,7 +17,7 @@ * 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 "config.h" +#include "qemu/osdep.h" #include "qemu-common.h" #include "exec/gdbstub.h" diff --git a/qemu/target-sparc/helper.c b/qemu/target-sparc/helper.c index 4850c7cec..8349cbe2c 100644 --- a/qemu/target-sparc/helper.c +++ b/qemu/target-sparc/helper.c @@ -17,6 +17,7 @@ * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ +#include "qemu/osdep.h" #include "cpu.h" #include "qemu/host-utils.h" #include "exec/helper-proto.h" @@ -51,10 +52,16 @@ void helper_tick_set_count(void *opaque, uint64_t count) #endif } -uint64_t helper_tick_get_count(void *opaque) +uint64_t helper_tick_get_count(CPUSPARCState *env, void *opaque, int mem_idx) { #if !defined(CONFIG_USER_ONLY) - return cpu_tick_get_count(opaque); + CPUTimer *timer = opaque; + + if (timer->npt && mem_idx < MMU_KERNEL_IDX) { + helper_raise_exception(env, TT_PRIV_INSN); + } + + return cpu_tick_get_count(timer); #else return 0; #endif diff --git a/qemu/target-sparc/helper.h b/qemu/target-sparc/helper.h index 1ad23e8db..4374f0dd2 100644 --- a/qemu/target-sparc/helper.h +++ b/qemu/target-sparc/helper.h @@ -25,7 +25,7 @@ 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_3(tick_get_count, i64, env, ptr, int) DEF_HELPER_2(tick_set_limit, void, ptr, i64) #endif #if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64) diff --git a/qemu/target-sparc/int32_helper.c b/qemu/target-sparc/int32_helper.c index 7c380ba2a..09afe136e 100644 --- a/qemu/target-sparc/int32_helper.c +++ b/qemu/target-sparc/int32_helper.c @@ -17,9 +17,11 @@ * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ +#include "qemu/osdep.h" #include "cpu.h" #include "trace.h" #include "sysemu/sysemu.h" +#include "exec/log.h" #define DEBUG_PCALL diff --git a/qemu/target-sparc/int64_helper.c b/qemu/target-sparc/int64_helper.c index b02d22b19..29360fa5f 100644 --- a/qemu/target-sparc/int64_helper.c +++ b/qemu/target-sparc/int64_helper.c @@ -17,8 +17,10 @@ * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ +#include "qemu/osdep.h" #include "cpu.h" #include "exec/helper-proto.h" +#include "exec/log.h" #include "trace.h" #define DEBUG_PCALL @@ -156,9 +158,8 @@ void sparc_cpu_do_interrupt(CPUState *cs) } 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->pc = env->tbr & ~0x7fffULL; + env->pc |= ((env->tl > 1) ? 1 << 14 : 0) | (intno << 5); env->npc = env->pc + 4; cs->exception_index = -1; } diff --git a/qemu/target-sparc/ldst_helper.c b/qemu/target-sparc/ldst_helper.c index c7ad47d35..658e7d858 100644 --- a/qemu/target-sparc/ldst_helper.c +++ b/qemu/target-sparc/ldst_helper.c @@ -17,6 +17,7 @@ * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ +#include "qemu/osdep.h" #include "cpu.h" #include "exec/helper-proto.h" #include "exec/cpu_ldst.h" @@ -2058,11 +2059,11 @@ void helper_ldda_asi(CPUSPARCState *env, target_ulong addr, int asi, int rd) bswap64s(&env->gregs[rd + 1]); } } else { - env->regwptr[rd] = cpu_ldq_nucleus(env, addr); - env->regwptr[rd + 1] = cpu_ldq_nucleus(env, addr + 8); + env->regwptr[rd - 8] = cpu_ldq_nucleus(env, addr); + env->regwptr[rd + 1 - 8] = cpu_ldq_nucleus(env, addr + 8); if (asi == 0x2c) { - bswap64s(&env->regwptr[rd]); - bswap64s(&env->regwptr[rd + 1]); + bswap64s(&env->regwptr[rd - 8]); + bswap64s(&env->regwptr[rd + 1 - 8]); } } break; @@ -2075,8 +2076,8 @@ void helper_ldda_asi(CPUSPARCState *env, target_ulong addr, int asi, int rd) env->gregs[rd] = helper_ld_asi(env, addr, asi, 4, 0); env->gregs[rd + 1] = helper_ld_asi(env, addr + 4, asi, 4, 0); } else { - env->regwptr[rd] = helper_ld_asi(env, addr, asi, 4, 0); - env->regwptr[rd + 1] = helper_ld_asi(env, addr + 4, asi, 4, 0); + env->regwptr[rd - 8] = helper_ld_asi(env, addr, asi, 4, 0); + env->regwptr[rd + 1 - 8] = helper_ld_asi(env, addr + 4, asi, 4, 0); } break; } diff --git a/qemu/target-sparc/machine.c b/qemu/target-sparc/machine.c index 3f3de4c65..1046016f3 100644 --- a/qemu/target-sparc/machine.c +++ b/qemu/target-sparc/machine.c @@ -1,218 +1,191 @@ +#include "qemu/osdep.h" #include "hw/hw.h" #include "hw/boards.h" #include "qemu/timer.h" #include "cpu.h" -void cpu_save(QEMUFile *f, void *opaque) -{ - CPUSPARCState *env = opaque; - int i; - uint32_t tmp; - - // if env->cwp == env->nwindows - 1, this will set the ins of the last - // window as the outs of the first window - cpu_set_cwp(env, env->cwp); +#ifdef TARGET_SPARC64 +static const VMStateDescription vmstate_cpu_timer = { + .name = "cpu_timer", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(frequency, CPUTimer), + VMSTATE_UINT32(disabled, CPUTimer), + VMSTATE_UINT64(disabled_mask, CPUTimer), + VMSTATE_UINT32(npt, CPUTimer), + VMSTATE_UINT64(npt_mask, CPUTimer), + VMSTATE_INT64(clock_offset, CPUTimer), + VMSTATE_TIMER_PTR(qtimer, CPUTimer), + VMSTATE_END_OF_LIST() + } +}; - for(i = 0; i < 8; i++) - qemu_put_betls(f, &env->gregs[i]); - qemu_put_be32s(f, &env->nwindows); - for(i = 0; i < env->nwindows * 16; i++) - qemu_put_betls(f, &env->regbase[i]); +#define VMSTATE_CPU_TIMER(_f, _s) \ + VMSTATE_STRUCT_POINTER(_f, _s, vmstate_cpu_timer, CPUTimer) - /* FPU */ - for (i = 0; i < TARGET_DPREGS; i++) { - qemu_put_be32(f, env->fpr[i].l.upper); - qemu_put_be32(f, env->fpr[i].l.lower); +static const VMStateDescription vmstate_trap_state = { + .name = "trap_state", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT64(tpc, trap_state), + VMSTATE_UINT64(tnpc, trap_state), + VMSTATE_UINT64(tstate, trap_state), + VMSTATE_UINT32(tt, trap_state), + VMSTATE_END_OF_LIST() } +}; - qemu_put_betls(f, &env->pc); - qemu_put_betls(f, &env->npc); - qemu_put_betls(f, &env->y); - tmp = cpu_get_psr(env); - qemu_put_be32(f, tmp); - qemu_put_betls(f, &env->fsr); - qemu_put_betls(f, &env->tbr); - tmp = env->interrupt_index; - qemu_put_be32(f, tmp); - qemu_put_be32s(f, &env->pil_in); -#ifndef TARGET_SPARC64 - qemu_put_be32s(f, &env->wim); - /* MMU */ - for (i = 0; i < 32; i++) - qemu_put_be32s(f, &env->mmuregs[i]); - for (i = 0; i < 4; i++) { - qemu_put_be64s(f, &env->mxccdata[i]); - } - for (i = 0; i < 8; i++) { - qemu_put_be64s(f, &env->mxccregs[i]); - } - qemu_put_be32s(f, &env->mmubpctrv); - qemu_put_be32s(f, &env->mmubpctrc); - qemu_put_be32s(f, &env->mmubpctrs); - qemu_put_be64s(f, &env->mmubpaction); - for (i = 0; i < 4; i++) { - qemu_put_be64s(f, &env->mmubpregs[i]); - } -#else - qemu_put_be64s(f, &env->lsu); - for (i = 0; i < 16; i++) { - qemu_put_be64s(f, &env->immuregs[i]); - qemu_put_be64s(f, &env->dmmuregs[i]); - } - for (i = 0; i < 64; i++) { - qemu_put_be64s(f, &env->itlb[i].tag); - qemu_put_be64s(f, &env->itlb[i].tte); - qemu_put_be64s(f, &env->dtlb[i].tag); - qemu_put_be64s(f, &env->dtlb[i].tte); +static const VMStateDescription vmstate_tlb_entry = { + .name = "tlb_entry", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT64(tag, SparcTLBEntry), + VMSTATE_UINT64(tte, SparcTLBEntry), + VMSTATE_END_OF_LIST() } - qemu_put_be32s(f, &env->mmu_version); - for (i = 0; i < MAXTL_MAX; i++) { - qemu_put_be64s(f, &env->ts[i].tpc); - qemu_put_be64s(f, &env->ts[i].tnpc); - qemu_put_be64s(f, &env->ts[i].tstate); - qemu_put_be32s(f, &env->ts[i].tt); - } - qemu_put_be32s(f, &env->xcc); - qemu_put_be32s(f, &env->asi); - qemu_put_be32s(f, &env->pstate); - qemu_put_be32s(f, &env->tl); - qemu_put_be32s(f, &env->cansave); - qemu_put_be32s(f, &env->canrestore); - qemu_put_be32s(f, &env->otherwin); - qemu_put_be32s(f, &env->wstate); - qemu_put_be32s(f, &env->cleanwin); - for (i = 0; i < 8; i++) - qemu_put_be64s(f, &env->agregs[i]); - for (i = 0; i < 8; i++) - qemu_put_be64s(f, &env->bgregs[i]); - for (i = 0; i < 8; i++) - qemu_put_be64s(f, &env->igregs[i]); - for (i = 0; i < 8; i++) - qemu_put_be64s(f, &env->mgregs[i]); - qemu_put_be64s(f, &env->fprs); - qemu_put_be64s(f, &env->tick_cmpr); - qemu_put_be64s(f, &env->stick_cmpr); - cpu_put_timer(f, env->tick); - cpu_put_timer(f, env->stick); - qemu_put_be64s(f, &env->gsr); - qemu_put_be32s(f, &env->gl); - qemu_put_be64s(f, &env->hpstate); - for (i = 0; i < MAXTL_MAX; i++) - qemu_put_be64s(f, &env->htstate[i]); - qemu_put_be64s(f, &env->hintp); - qemu_put_be64s(f, &env->htba); - qemu_put_be64s(f, &env->hver); - qemu_put_be64s(f, &env->hstick_cmpr); - qemu_put_be64s(f, &env->ssr); - cpu_put_timer(f, env->hstick); +}; #endif + +static int get_psr(QEMUFile *f, void *opaque, size_t size) +{ + SPARCCPU *cpu = opaque; + CPUSPARCState *env = &cpu->env; + uint32_t val = qemu_get_be32(f); + + /* needed to ensure that the wrapping registers are correctly updated */ + env->cwp = 0; + cpu_put_psr_raw(env, val); + + return 0; } -int cpu_load(QEMUFile *f, void *opaque, int version_id) +static void put_psr(QEMUFile *f, void *opaque, size_t size) { - CPUSPARCState *env = opaque; - SPARCCPU *cpu = sparc_env_get_cpu(env); - int i; - uint32_t tmp; - - if (version_id < 6) - return -EINVAL; - for(i = 0; i < 8; i++) - qemu_get_betls(f, &env->gregs[i]); - qemu_get_be32s(f, &env->nwindows); - for(i = 0; i < env->nwindows * 16; i++) - qemu_get_betls(f, &env->regbase[i]); - - /* FPU */ - for (i = 0; i < TARGET_DPREGS; i++) { - env->fpr[i].l.upper = qemu_get_be32(f); - env->fpr[i].l.lower = qemu_get_be32(f); - } + SPARCCPU *cpu = opaque; + CPUSPARCState *env = &cpu->env; + uint32_t val; + + val = cpu_get_psr(env); + + qemu_put_be32(f, val); +} - qemu_get_betls(f, &env->pc); - qemu_get_betls(f, &env->npc); - qemu_get_betls(f, &env->y); - tmp = qemu_get_be32(f); - env->cwp = 0; /* needed to ensure that the wrapping registers are - correctly updated */ - cpu_put_psr(env, tmp); - qemu_get_betls(f, &env->fsr); - qemu_get_betls(f, &env->tbr); - tmp = qemu_get_be32(f); - env->interrupt_index = tmp; - qemu_get_be32s(f, &env->pil_in); +static const VMStateInfo vmstate_psr = { + .name = "psr", + .get = get_psr, + .put = put_psr, +}; + +static void cpu_pre_save(void *opaque) +{ + SPARCCPU *cpu = opaque; + CPUSPARCState *env = &cpu->env; + + /* if env->cwp == env->nwindows - 1, this will set the ins of the last + * window as the outs of the first window + */ + cpu_set_cwp(env, env->cwp); +} + +/* 32-bit SPARC retains migration compatibility with older versions + * of QEMU; 64-bit SPARC has had a migration break since then, so the + * versions are different. + */ #ifndef TARGET_SPARC64 - qemu_get_be32s(f, &env->wim); - /* MMU */ - for (i = 0; i < 32; i++) - qemu_get_be32s(f, &env->mmuregs[i]); - for (i = 0; i < 4; i++) { - qemu_get_be64s(f, &env->mxccdata[i]); - } - for (i = 0; i < 8; i++) { - qemu_get_be64s(f, &env->mxccregs[i]); - } - qemu_get_be32s(f, &env->mmubpctrv); - qemu_get_be32s(f, &env->mmubpctrc); - qemu_get_be32s(f, &env->mmubpctrs); - qemu_get_be64s(f, &env->mmubpaction); - for (i = 0; i < 4; i++) { - qemu_get_be64s(f, &env->mmubpregs[i]); - } +#define SPARC_VMSTATE_VER 7 #else - qemu_get_be64s(f, &env->lsu); - for (i = 0; i < 16; i++) { - qemu_get_be64s(f, &env->immuregs[i]); - qemu_get_be64s(f, &env->dmmuregs[i]); - } - for (i = 0; i < 64; i++) { - qemu_get_be64s(f, &env->itlb[i].tag); - qemu_get_be64s(f, &env->itlb[i].tte); - qemu_get_be64s(f, &env->dtlb[i].tag); - qemu_get_be64s(f, &env->dtlb[i].tte); - } - qemu_get_be32s(f, &env->mmu_version); - for (i = 0; i < MAXTL_MAX; i++) { - qemu_get_be64s(f, &env->ts[i].tpc); - qemu_get_be64s(f, &env->ts[i].tnpc); - qemu_get_be64s(f, &env->ts[i].tstate); - qemu_get_be32s(f, &env->ts[i].tt); - } - qemu_get_be32s(f, &env->xcc); - qemu_get_be32s(f, &env->asi); - qemu_get_be32s(f, &env->pstate); - qemu_get_be32s(f, &env->tl); - qemu_get_be32s(f, &env->cansave); - qemu_get_be32s(f, &env->canrestore); - qemu_get_be32s(f, &env->otherwin); - qemu_get_be32s(f, &env->wstate); - qemu_get_be32s(f, &env->cleanwin); - for (i = 0; i < 8; i++) - qemu_get_be64s(f, &env->agregs[i]); - for (i = 0; i < 8; i++) - qemu_get_be64s(f, &env->bgregs[i]); - for (i = 0; i < 8; i++) - qemu_get_be64s(f, &env->igregs[i]); - for (i = 0; i < 8; i++) - qemu_get_be64s(f, &env->mgregs[i]); - qemu_get_be64s(f, &env->fprs); - qemu_get_be64s(f, &env->tick_cmpr); - qemu_get_be64s(f, &env->stick_cmpr); - cpu_get_timer(f, env->tick); - cpu_get_timer(f, env->stick); - qemu_get_be64s(f, &env->gsr); - qemu_get_be32s(f, &env->gl); - qemu_get_be64s(f, &env->hpstate); - for (i = 0; i < MAXTL_MAX; i++) - qemu_get_be64s(f, &env->htstate[i]); - qemu_get_be64s(f, &env->hintp); - qemu_get_be64s(f, &env->htba); - qemu_get_be64s(f, &env->hver); - qemu_get_be64s(f, &env->hstick_cmpr); - qemu_get_be64s(f, &env->ssr); - cpu_get_timer(f, env->hstick); +#define SPARC_VMSTATE_VER 9 #endif - tlb_flush(CPU(cpu), 1); - return 0; -} + +const VMStateDescription vmstate_sparc_cpu = { + .name = "cpu", + .version_id = SPARC_VMSTATE_VER, + .minimum_version_id = SPARC_VMSTATE_VER, + .minimum_version_id_old = SPARC_VMSTATE_VER, + .pre_save = cpu_pre_save, + .fields = (VMStateField[]) { + VMSTATE_UINTTL_ARRAY(env.gregs, SPARCCPU, 8), + VMSTATE_UINT32(env.nwindows, SPARCCPU), + VMSTATE_VARRAY_MULTIPLY(env.regbase, SPARCCPU, env.nwindows, 16, + vmstate_info_uinttl, target_ulong), + VMSTATE_CPUDOUBLE_ARRAY(env.fpr, SPARCCPU, TARGET_DPREGS), + VMSTATE_UINTTL(env.pc, SPARCCPU), + VMSTATE_UINTTL(env.npc, SPARCCPU), + VMSTATE_UINTTL(env.y, SPARCCPU), + { + + .name = "psr", + .version_id = 0, + .size = sizeof(uint32_t), + .info = &vmstate_psr, + .flags = VMS_SINGLE, + .offset = 0, + }, + VMSTATE_UINTTL(env.fsr, SPARCCPU), + VMSTATE_UINTTL(env.tbr, SPARCCPU), + VMSTATE_INT32(env.interrupt_index, SPARCCPU), + VMSTATE_UINT32(env.pil_in, SPARCCPU), +#ifndef TARGET_SPARC64 + /* MMU */ + VMSTATE_UINT32(env.wim, SPARCCPU), + VMSTATE_UINT32_ARRAY(env.mmuregs, SPARCCPU, 32), + VMSTATE_UINT64_ARRAY(env.mxccdata, SPARCCPU, 4), + VMSTATE_UINT64_ARRAY(env.mxccregs, SPARCCPU, 8), + VMSTATE_UINT32(env.mmubpctrv, SPARCCPU), + VMSTATE_UINT32(env.mmubpctrc, SPARCCPU), + VMSTATE_UINT32(env.mmubpctrs, SPARCCPU), + VMSTATE_UINT64(env.mmubpaction, SPARCCPU), + VMSTATE_UINT64_ARRAY(env.mmubpregs, SPARCCPU, 4), +#else + VMSTATE_UINT64(env.lsu, SPARCCPU), + VMSTATE_UINT64_ARRAY(env.immuregs, SPARCCPU, 16), + VMSTATE_UINT64_ARRAY(env.dmmuregs, SPARCCPU, 16), + VMSTATE_STRUCT_ARRAY(env.itlb, SPARCCPU, 64, 0, + vmstate_tlb_entry, SparcTLBEntry), + VMSTATE_STRUCT_ARRAY(env.dtlb, SPARCCPU, 64, 0, + vmstate_tlb_entry, SparcTLBEntry), + VMSTATE_UINT32(env.mmu_version, SPARCCPU), + VMSTATE_STRUCT_ARRAY(env.ts, SPARCCPU, MAXTL_MAX, 0, + vmstate_trap_state, trap_state), + VMSTATE_UINT32(env.xcc, SPARCCPU), + VMSTATE_UINT32(env.asi, SPARCCPU), + VMSTATE_UINT32(env.pstate, SPARCCPU), + VMSTATE_UINT32(env.tl, SPARCCPU), + VMSTATE_UINT32(env.cansave, SPARCCPU), + VMSTATE_UINT32(env.canrestore, SPARCCPU), + VMSTATE_UINT32(env.otherwin, SPARCCPU), + VMSTATE_UINT32(env.wstate, SPARCCPU), + VMSTATE_UINT32(env.cleanwin, SPARCCPU), + VMSTATE_UINT64_ARRAY(env.agregs, SPARCCPU, 8), + VMSTATE_UINT64_ARRAY(env.bgregs, SPARCCPU, 8), + VMSTATE_UINT64_ARRAY(env.igregs, SPARCCPU, 8), + VMSTATE_UINT64_ARRAY(env.mgregs, SPARCCPU, 8), + VMSTATE_UINT64(env.fprs, SPARCCPU), + VMSTATE_UINT64(env.tick_cmpr, SPARCCPU), + VMSTATE_UINT64(env.stick_cmpr, SPARCCPU), + VMSTATE_CPU_TIMER(env.tick, SPARCCPU), + VMSTATE_CPU_TIMER(env.stick, SPARCCPU), + VMSTATE_UINT64(env.gsr, SPARCCPU), + VMSTATE_UINT32(env.gl, SPARCCPU), + VMSTATE_UINT64(env.hpstate, SPARCCPU), + VMSTATE_UINT64_ARRAY(env.htstate, SPARCCPU, MAXTL_MAX), + VMSTATE_UINT64(env.hintp, SPARCCPU), + VMSTATE_UINT64(env.htba, SPARCCPU), + VMSTATE_UINT64(env.hver, SPARCCPU), + VMSTATE_UINT64(env.hstick_cmpr, SPARCCPU), + VMSTATE_UINT64(env.ssr, SPARCCPU), + VMSTATE_CPU_TIMER(env.hstick, SPARCCPU), + /* On SPARC32 env.psrpil and env.cwp are migrated as part of the PSR */ + VMSTATE_UINT32(env.psrpil, SPARCCPU), + VMSTATE_UINT32(env.cwp, SPARCCPU), +#endif + VMSTATE_END_OF_LIST() + }, +}; diff --git a/qemu/target-sparc/mmu_helper.c b/qemu/target-sparc/mmu_helper.c index 2a0c6f0d3..aa80c4829 100644 --- a/qemu/target-sparc/mmu_helper.c +++ b/qemu/target-sparc/mmu_helper.c @@ -17,6 +17,7 @@ * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ +#include "qemu/osdep.h" #include "cpu.h" #include "trace.h" #include "exec/address-spaces.h" @@ -849,7 +850,7 @@ hwaddr sparc_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) SPARCCPU *cpu = SPARC_CPU(cs); CPUSPARCState *env = &cpu->env; hwaddr phys_addr; - int mmu_idx = cpu_mmu_index(env); + int mmu_idx = cpu_mmu_index(env, false); MemoryRegionSection section; if (cpu_sparc_get_phys_page(env, &phys_addr, addr, 2, mmu_idx) != 0) { diff --git a/qemu/target-sparc/monitor.c b/qemu/target-sparc/monitor.c new file mode 100644 index 000000000..7cc1b0f87 --- /dev/null +++ b/qemu/target-sparc/monitor.c @@ -0,0 +1,159 @@ +/* + * QEMU monitor + * + * Copyright (c) 2003-2004 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "qemu/osdep.h" +#include "cpu.h" +#include "monitor/monitor.h" +#include "monitor/hmp-target.h" +#include "hmp.h" + + +void hmp_info_tlb(Monitor *mon, const QDict *qdict) +{ + CPUArchState *env1 = mon_get_cpu_env(); + + dump_mmu((FILE*)mon, (fprintf_function)monitor_printf, env1); +} + +#ifndef TARGET_SPARC64 +static target_long monitor_get_psr (const struct MonitorDef *md, int val) +{ + CPUArchState *env = mon_get_cpu_env(); + + return cpu_get_psr(env); +} +#endif + +static target_long monitor_get_reg(const struct MonitorDef *md, int val) +{ + CPUArchState *env = mon_get_cpu_env(); + return env->regwptr[val]; +} + +const MonitorDef monitor_defs[] = { + { "g0", offsetof(CPUSPARCState, gregs[0]) }, + { "g1", offsetof(CPUSPARCState, gregs[1]) }, + { "g2", offsetof(CPUSPARCState, gregs[2]) }, + { "g3", offsetof(CPUSPARCState, gregs[3]) }, + { "g4", offsetof(CPUSPARCState, gregs[4]) }, + { "g5", offsetof(CPUSPARCState, gregs[5]) }, + { "g6", offsetof(CPUSPARCState, gregs[6]) }, + { "g7", offsetof(CPUSPARCState, gregs[7]) }, + { "o0", 0, monitor_get_reg }, + { "o1", 1, monitor_get_reg }, + { "o2", 2, monitor_get_reg }, + { "o3", 3, monitor_get_reg }, + { "o4", 4, monitor_get_reg }, + { "o5", 5, monitor_get_reg }, + { "o6", 6, monitor_get_reg }, + { "o7", 7, monitor_get_reg }, + { "l0", 8, monitor_get_reg }, + { "l1", 9, monitor_get_reg }, + { "l2", 10, monitor_get_reg }, + { "l3", 11, monitor_get_reg }, + { "l4", 12, monitor_get_reg }, + { "l5", 13, monitor_get_reg }, + { "l6", 14, monitor_get_reg }, + { "l7", 15, monitor_get_reg }, + { "i0", 16, monitor_get_reg }, + { "i1", 17, monitor_get_reg }, + { "i2", 18, monitor_get_reg }, + { "i3", 19, monitor_get_reg }, + { "i4", 20, monitor_get_reg }, + { "i5", 21, monitor_get_reg }, + { "i6", 22, monitor_get_reg }, + { "i7", 23, monitor_get_reg }, + { "pc", offsetof(CPUSPARCState, pc) }, + { "npc", offsetof(CPUSPARCState, npc) }, + { "y", offsetof(CPUSPARCState, y) }, +#ifndef TARGET_SPARC64 + { "psr", 0, &monitor_get_psr, }, + { "wim", offsetof(CPUSPARCState, wim) }, +#endif + { "tbr", offsetof(CPUSPARCState, tbr) }, + { "fsr", offsetof(CPUSPARCState, fsr) }, + { "f0", offsetof(CPUSPARCState, fpr[0].l.upper) }, + { "f1", offsetof(CPUSPARCState, fpr[0].l.lower) }, + { "f2", offsetof(CPUSPARCState, fpr[1].l.upper) }, + { "f3", offsetof(CPUSPARCState, fpr[1].l.lower) }, + { "f4", offsetof(CPUSPARCState, fpr[2].l.upper) }, + { "f5", offsetof(CPUSPARCState, fpr[2].l.lower) }, + { "f6", offsetof(CPUSPARCState, fpr[3].l.upper) }, + { "f7", offsetof(CPUSPARCState, fpr[3].l.lower) }, + { "f8", offsetof(CPUSPARCState, fpr[4].l.upper) }, + { "f9", offsetof(CPUSPARCState, fpr[4].l.lower) }, + { "f10", offsetof(CPUSPARCState, fpr[5].l.upper) }, + { "f11", offsetof(CPUSPARCState, fpr[5].l.lower) }, + { "f12", offsetof(CPUSPARCState, fpr[6].l.upper) }, + { "f13", offsetof(CPUSPARCState, fpr[6].l.lower) }, + { "f14", offsetof(CPUSPARCState, fpr[7].l.upper) }, + { "f15", offsetof(CPUSPARCState, fpr[7].l.lower) }, + { "f16", offsetof(CPUSPARCState, fpr[8].l.upper) }, + { "f17", offsetof(CPUSPARCState, fpr[8].l.lower) }, + { "f18", offsetof(CPUSPARCState, fpr[9].l.upper) }, + { "f19", offsetof(CPUSPARCState, fpr[9].l.lower) }, + { "f20", offsetof(CPUSPARCState, fpr[10].l.upper) }, + { "f21", offsetof(CPUSPARCState, fpr[10].l.lower) }, + { "f22", offsetof(CPUSPARCState, fpr[11].l.upper) }, + { "f23", offsetof(CPUSPARCState, fpr[11].l.lower) }, + { "f24", offsetof(CPUSPARCState, fpr[12].l.upper) }, + { "f25", offsetof(CPUSPARCState, fpr[12].l.lower) }, + { "f26", offsetof(CPUSPARCState, fpr[13].l.upper) }, + { "f27", offsetof(CPUSPARCState, fpr[13].l.lower) }, + { "f28", offsetof(CPUSPARCState, fpr[14].l.upper) }, + { "f29", offsetof(CPUSPARCState, fpr[14].l.lower) }, + { "f30", offsetof(CPUSPARCState, fpr[15].l.upper) }, + { "f31", offsetof(CPUSPARCState, fpr[15].l.lower) }, +#ifdef TARGET_SPARC64 + { "f32", offsetof(CPUSPARCState, fpr[16]) }, + { "f34", offsetof(CPUSPARCState, fpr[17]) }, + { "f36", offsetof(CPUSPARCState, fpr[18]) }, + { "f38", offsetof(CPUSPARCState, fpr[19]) }, + { "f40", offsetof(CPUSPARCState, fpr[20]) }, + { "f42", offsetof(CPUSPARCState, fpr[21]) }, + { "f44", offsetof(CPUSPARCState, fpr[22]) }, + { "f46", offsetof(CPUSPARCState, fpr[23]) }, + { "f48", offsetof(CPUSPARCState, fpr[24]) }, + { "f50", offsetof(CPUSPARCState, fpr[25]) }, + { "f52", offsetof(CPUSPARCState, fpr[26]) }, + { "f54", offsetof(CPUSPARCState, fpr[27]) }, + { "f56", offsetof(CPUSPARCState, fpr[28]) }, + { "f58", offsetof(CPUSPARCState, fpr[29]) }, + { "f60", offsetof(CPUSPARCState, fpr[30]) }, + { "f62", offsetof(CPUSPARCState, fpr[31]) }, + { "asi", offsetof(CPUSPARCState, asi) }, + { "pstate", offsetof(CPUSPARCState, pstate) }, + { "cansave", offsetof(CPUSPARCState, cansave) }, + { "canrestore", offsetof(CPUSPARCState, canrestore) }, + { "otherwin", offsetof(CPUSPARCState, otherwin) }, + { "wstate", offsetof(CPUSPARCState, wstate) }, + { "cleanwin", offsetof(CPUSPARCState, cleanwin) }, + { "fprs", offsetof(CPUSPARCState, fprs) }, +#endif + { NULL }, +}; + +const MonitorDef *target_monitor_defs(void) +{ + return monitor_defs; +} diff --git a/qemu/target-sparc/translate.c b/qemu/target-sparc/translate.c index c58dd4e95..7998ff57b 100644 --- a/qemu/target-sparc/translate.c +++ b/qemu/target-sparc/translate.c @@ -18,11 +18,7 @@ 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 "qemu/osdep.h" #include "cpu.h" #include "disas/disas.h" @@ -33,6 +29,7 @@ #include "exec/helper-gen.h" #include "trace-tcg.h" +#include "exec/log.h" #define DEBUG_DISAS @@ -42,11 +39,13 @@ according to jump_pc[T2] */ /* global register indexes */ -static TCGv_ptr cpu_env, cpu_regwptr; +static TCGv_env cpu_env; +static TCGv_ptr cpu_regwptr; static TCGv cpu_cc_src, cpu_cc_src2, cpu_cc_dst; static TCGv_i32 cpu_cc_op; static TCGv_i32 cpu_psr; -static TCGv cpu_fsr, cpu_pc, cpu_npc, cpu_gregs[8]; +static TCGv cpu_fsr, cpu_pc, cpu_npc; +static TCGv cpu_regs[32]; static TCGv cpu_y; #ifndef CONFIG_USER_ONLY static TCGv cpu_tbr; @@ -64,9 +63,6 @@ static TCGv cpu_wim; /* Floating point registers */ static TCGv_i64 cpu_fpr[TARGET_DPREGS]; -static target_ulong gen_opc_npc[OPC_BUF_SIZE]; -static target_ulong gen_opc_jump_pc[2]; - #include "exec/gen-icount.h" typedef struct DisasContext { @@ -164,7 +160,7 @@ static TCGv_i32 gen_load_fpr_F(DisasContext *dc, unsigned int src) TCGv_i64 t = tcg_temp_new_i64(); tcg_gen_shri_i64(t, cpu_fpr[src / 2], 32); - tcg_gen_trunc_i64_i32(ret, t); + tcg_gen_extrl_i64_i32(ret, t); tcg_temp_free_i64(t); return ret; @@ -279,36 +275,31 @@ static inline void gen_address_mask(DisasContext *dc, TCGv addr) static inline TCGv gen_load_gpr(DisasContext *dc, int reg) { - if (reg == 0 || reg >= 8) { + if (reg > 0) { + assert(reg < 32); + return cpu_regs[reg]; + } else { TCGv t = get_temp_tl(dc); - if (reg == 0) { - tcg_gen_movi_tl(t, 0); - } else { - tcg_gen_ld_tl(t, cpu_regwptr, (reg - 8) * sizeof(target_ulong)); - } + tcg_gen_movi_tl(t, 0); return t; - } else { - return cpu_gregs[reg]; } } static inline void gen_store_gpr(DisasContext *dc, int reg, TCGv v) { if (reg > 0) { - if (reg < 8) { - tcg_gen_mov_tl(cpu_gregs[reg], v); - } else { - tcg_gen_st_tl(v, cpu_regwptr, (reg - 8) * sizeof(target_ulong)); - } + assert(reg < 32); + tcg_gen_mov_tl(cpu_regs[reg], v); } } static inline TCGv gen_dest_gpr(DisasContext *dc, int reg) { - if (reg == 0 || reg >= 8) { - return get_temp_tl(dc); + if (reg > 0) { + assert(reg < 32); + return cpu_regs[reg]; } else { - return cpu_gregs[reg]; + return get_temp_tl(dc); } } @@ -379,8 +370,8 @@ static TCGv_i32 gen_add32_carry32(void) #if TARGET_LONG_BITS == 64 cc_src1_32 = tcg_temp_new_i32(); cc_src2_32 = tcg_temp_new_i32(); - tcg_gen_trunc_i64_i32(cc_src1_32, cpu_cc_dst); - tcg_gen_trunc_i64_i32(cc_src2_32, cpu_cc_src); + tcg_gen_extrl_i64_i32(cc_src1_32, cpu_cc_dst); + tcg_gen_extrl_i64_i32(cc_src2_32, cpu_cc_src); #else cc_src1_32 = cpu_cc_dst; cc_src2_32 = cpu_cc_src; @@ -405,8 +396,8 @@ static TCGv_i32 gen_sub32_carry32(void) #if TARGET_LONG_BITS == 64 cc_src1_32 = tcg_temp_new_i32(); cc_src2_32 = tcg_temp_new_i32(); - tcg_gen_trunc_i64_i32(cc_src1_32, cpu_cc_src); - tcg_gen_trunc_i64_i32(cc_src2_32, cpu_cc_src2); + tcg_gen_extrl_i64_i32(cc_src1_32, cpu_cc_src); + tcg_gen_extrl_i64_i32(cc_src2_32, cpu_cc_src2); #else cc_src1_32 = cpu_cc_src; cc_src2_32 = cpu_cc_src2; @@ -955,17 +946,44 @@ static inline void gen_branch2(DisasContext *dc, target_ulong pc1, gen_goto_tb(dc, 1, pc2, pc2 + 4); } -static inline void gen_branch_a(DisasContext *dc, target_ulong pc1, - target_ulong pc2, TCGv r_cond) +static void gen_branch_a(DisasContext *dc, target_ulong pc1) { TCGLabel *l1 = gen_new_label(); + target_ulong npc = dc->npc; - tcg_gen_brcondi_tl(TCG_COND_EQ, r_cond, 0, l1); + tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_cond, 0, l1); - gen_goto_tb(dc, 0, pc2, pc1); + gen_goto_tb(dc, 0, npc, pc1); gen_set_label(l1); - gen_goto_tb(dc, 1, pc2 + 4, pc2 + 8); + gen_goto_tb(dc, 1, npc + 4, npc + 8); + + dc->is_br = 1; +} + +static void gen_branch_n(DisasContext *dc, target_ulong pc1) +{ + target_ulong npc = dc->npc; + + if (likely(npc != DYNAMIC_PC)) { + dc->pc = npc; + dc->jump_pc[0] = pc1; + dc->jump_pc[1] = npc + 4; + dc->npc = JUMP_PC; + } else { + TCGv t, z; + + tcg_gen_mov_tl(cpu_pc, cpu_npc); + + tcg_gen_addi_tl(cpu_npc, cpu_npc, 4); + t = tcg_const_tl(pc1); + z = tcg_const_tl(0); + tcg_gen_movcond_tl(TCG_COND_NE, cpu_npc, cpu_cond, z, t, cpu_npc); + tcg_temp_free(t); + tcg_temp_free(z); + + dc->pc = DYNAMIC_PC; + } } static inline void gen_generic_branch(DisasContext *dc) @@ -1398,18 +1416,9 @@ static void do_branch(DisasContext *dc, int32_t offset, uint32_t insn, int cc) flush_cond(dc); gen_cond(cpu_cond, cc, cond, dc); if (a) { - gen_branch_a(dc, target, dc->npc, cpu_cond); - dc->is_br = 1; + gen_branch_a(dc, target); } else { - dc->pc = dc->npc; - dc->jump_pc[0] = target; - if (unlikely(dc->npc == DYNAMIC_PC)) { - dc->jump_pc[1] = DYNAMIC_PC; - tcg_gen_addi_tl(cpu_pc, cpu_npc, 4); - } else { - dc->jump_pc[1] = dc->npc + 4; - dc->npc = JUMP_PC; - } + gen_branch_n(dc, target); } } } @@ -1447,18 +1456,9 @@ static void do_fbranch(DisasContext *dc, int32_t offset, uint32_t insn, int cc) flush_cond(dc); gen_fcond(cpu_cond, cc, cond); if (a) { - gen_branch_a(dc, target, dc->npc, cpu_cond); - dc->is_br = 1; + gen_branch_a(dc, target); } else { - dc->pc = dc->npc; - dc->jump_pc[0] = target; - if (unlikely(dc->npc == DYNAMIC_PC)) { - dc->jump_pc[1] = DYNAMIC_PC; - tcg_gen_addi_tl(cpu_pc, cpu_npc, 4); - } else { - dc->jump_pc[1] = dc->npc + 4; - dc->npc = JUMP_PC; - } + gen_branch_n(dc, target); } } } @@ -1476,18 +1476,9 @@ static void do_branch_reg(DisasContext *dc, int32_t offset, uint32_t insn, flush_cond(dc); gen_cond_reg(cpu_cond, cond, r_reg); if (a) { - gen_branch_a(dc, target, dc->npc, cpu_cond); - dc->is_br = 1; + gen_branch_a(dc, target); } else { - dc->pc = dc->npc; - dc->jump_pc[0] = target; - if (unlikely(dc->npc == DYNAMIC_PC)) { - dc->jump_pc[1] = DYNAMIC_PC; - tcg_gen_addi_tl(cpu_pc, cpu_npc, 4); - } else { - dc->jump_pc[1] = dc->npc + 4; - dc->npc = JUMP_PC; - } + gen_branch_n(dc, target); } } @@ -2164,9 +2155,13 @@ static inline void gen_ldda_asi(DisasContext *dc, TCGv hi, TCGv addr, tcg_temp_free_i32(r_size); tcg_temp_free_i32(r_asi); - t = gen_dest_gpr(dc, rd + 1); + /* ??? Work around an apparent bug in Ubuntu gcc 4.8.2-10ubuntu2+12, + whereby "rd + 1" elicits "error: array subscript is above array". + Since we have already asserted that rd is even, the semantics + are unchanged. */ + t = gen_dest_gpr(dc, rd | 1); tcg_gen_trunc_i64_tl(t, t64); - gen_store_gpr(dc, rd + 1, t); + gen_store_gpr(dc, rd | 1, t); tcg_gen_shri_i64(t64, t64, 32); tcg_gen_trunc_i64_tl(hi, t64); @@ -2254,11 +2249,11 @@ static void gen_fmovs(DisasContext *dc, DisasCompare *cmp, int rd, int rs) the later. */ c32 = tcg_temp_new_i32(); if (cmp->is_bool) { - tcg_gen_trunc_i64_i32(c32, cmp->c1); + tcg_gen_extrl_i64_i32(c32, cmp->c1); } else { TCGv_i64 c64 = tcg_temp_new_i64(); tcg_gen_setcond_i64(cmp->cond, c64, cmp->c1, cmp->c2); - tcg_gen_trunc_i64_i32(c32, c64); + tcg_gen_extrl_i64_i32(c32, c64); tcg_temp_free_i64(c64); } @@ -2297,7 +2292,7 @@ static void gen_fmovq(DisasContext *dc, DisasCompare *cmp, int rd, int rs) } #ifndef CONFIG_USER_ONLY -static inline void gen_load_trap_state_at_tl(TCGv_ptr r_tsptr, TCGv_ptr cpu_env) +static inline void gen_load_trap_state_at_tl(TCGv_ptr r_tsptr, TCGv_env cpu_env) { TCGv_i32 r_tl = tcg_temp_new_i32(); @@ -2482,10 +2477,6 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) TCGv_i64 cpu_src1_64, cpu_src2_64, cpu_dst_64; target_long simm; - if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP | CPU_LOG_TB_OP_OPT))) { - tcg_gen_debug_insn_start(dc->pc); - } - opc = GET_FIELD(insn, 0, 1); rd = GET_FIELD(insn, 2, 6); @@ -2715,12 +2706,16 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) case 0x4: /* V9 rdtick */ { TCGv_ptr r_tickptr; + TCGv_i32 r_const; r_tickptr = tcg_temp_new_ptr(); + r_const = tcg_const_i32(dc->mem_idx); tcg_gen_ld_ptr(r_tickptr, cpu_env, offsetof(CPUSPARCState, tick)); - gen_helper_tick_get_count(cpu_dst, r_tickptr); + gen_helper_tick_get_count(cpu_dst, cpu_env, r_tickptr, + r_const); tcg_temp_free_ptr(r_tickptr); + tcg_temp_free_i32(r_const); gen_store_gpr(dc, rd, cpu_dst); } break; @@ -2757,12 +2752,16 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) case 0x18: /* System tick */ { TCGv_ptr r_tickptr; + TCGv_i32 r_const; r_tickptr = tcg_temp_new_ptr(); + r_const = tcg_const_i32(dc->mem_idx); tcg_gen_ld_ptr(r_tickptr, cpu_env, offsetof(CPUSPARCState, stick)); - gen_helper_tick_get_count(cpu_dst, r_tickptr); + gen_helper_tick_get_count(cpu_dst, cpu_env, r_tickptr, + r_const); tcg_temp_free_ptr(r_tickptr); + tcg_temp_free_i32(r_const); gen_store_gpr(dc, rd, cpu_dst); } break; @@ -2870,12 +2869,16 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) case 4: // tick { TCGv_ptr r_tickptr; + TCGv_i32 r_const; r_tickptr = tcg_temp_new_ptr(); + r_const = tcg_const_i32(dc->mem_idx); tcg_gen_ld_ptr(r_tickptr, cpu_env, offsetof(CPUSPARCState, tick)); - gen_helper_tick_get_count(cpu_tmp0, r_tickptr); + gen_helper_tick_get_count(cpu_tmp0, cpu_env, + r_tickptr, r_const); tcg_temp_free_ptr(r_tickptr); + tcg_temp_free_i32(r_const); } break; case 5: // tba @@ -4667,7 +4670,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) TCGv r_const; gen_address_mask(dc, cpu_addr); - tcg_gen_qemu_ld8s(cpu_val, cpu_addr, dc->mem_idx); + tcg_gen_qemu_ld8u(cpu_val, cpu_addr, dc->mem_idx); r_const = tcg_const_tl(0xff); tcg_gen_qemu_st8(r_const, cpu_addr, dc->mem_idx); tcg_temp_free(r_const); @@ -5104,7 +5107,8 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) if (IS_IMM) { goto illegal_insn; } - if (!supervisor(dc)) { + /* LEON3 allows CASA from user space with ASI 0xa */ + if ((GET_FIELD(insn, 19, 26) != 0xa) && !supervisor(dc)) { goto priv_insn; } #endif @@ -5213,16 +5217,12 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) } } -static inline void gen_intermediate_code_internal(SPARCCPU *cpu, - TranslationBlock *tb, - bool spc) +void gen_intermediate_code(CPUSPARCState * env, TranslationBlock * tb) { + SPARCCPU *cpu = sparc_env_get_cpu(env); CPUState *cs = CPU(cpu); - CPUSPARCState *env = &cpu->env; target_ulong pc_start, last_pc; DisasContext dc1, *dc = &dc1; - CPUBreakpoint *bp; - int j, lj = -1; int num_insns; int max_insns; unsigned int insn; @@ -5234,7 +5234,7 @@ static inline void gen_intermediate_code_internal(SPARCCPU *cpu, last_pc = dc->pc; dc->npc = (target_ulong) tb->cs_base; dc->cc_op = CC_OP_DYNAMIC; - dc->mem_idx = cpu_mmu_index(env); + dc->mem_idx = cpu_mmu_index(env, false); dc->def = env->def; dc->fpu_enabled = tb_fpu_enabled(tb->flags); dc->address_mask_32bit = tb_am_enabled(tb->flags); @@ -5242,42 +5242,41 @@ static inline void gen_intermediate_code_internal(SPARCCPU *cpu, num_insns = 0; max_insns = tb->cflags & CF_COUNT_MASK; - if (max_insns == 0) + if (max_insns == 0) { max_insns = CF_COUNT_MASK; + } + if (max_insns > TCG_MAX_INSNS) { + max_insns = TCG_MAX_INSNS; + } + gen_tb_start(tb); do { - if (unlikely(!QTAILQ_EMPTY(&cs->breakpoints))) { - QTAILQ_FOREACH(bp, &cs->breakpoints, entry) { - if (bp->pc == dc->pc) { - if (dc->pc != pc_start) - save_state(dc); - gen_helper_debug(cpu_env); - tcg_gen_exit_tb(0); - dc->is_br = 1; - goto exit_gen_loop; - } - } + if (dc->npc & JUMP_PC) { + assert(dc->jump_pc[1] == dc->pc + 4); + tcg_gen_insn_start(dc->pc, dc->jump_pc[0] | JUMP_PC); + } else { + tcg_gen_insn_start(dc->pc, dc->npc); } - if (spc) { - qemu_log("Search PC...\n"); - j = tcg_op_buf_count(); - if (lj < j) { - lj++; - while (lj < j) - tcg_ctx.gen_opc_instr_start[lj++] = 0; - tcg_ctx.gen_opc_pc[lj] = dc->pc; - gen_opc_npc[lj] = dc->npc; - tcg_ctx.gen_opc_instr_start[lj] = 1; - tcg_ctx.gen_opc_icount[lj] = num_insns; + num_insns++; + last_pc = dc->pc; + + if (unlikely(cpu_breakpoint_test(cs, dc->pc, BP_ANY))) { + if (dc->pc != pc_start) { + save_state(dc); } + gen_helper_debug(cpu_env); + tcg_gen_exit_tb(0); + dc->is_br = 1; + goto exit_gen_loop; } - if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO)) + + if (num_insns == max_insns && (tb->cflags & CF_LAST_IO)) { gen_io_start(); - last_pc = dc->pc; + } + insn = cpu_ldl_code(env, dc->pc); disas_sparc_insn(dc, insn); - num_insns++; if (dc->is_br) break; @@ -5316,20 +5315,9 @@ static inline void gen_intermediate_code_internal(SPARCCPU *cpu, } gen_tb_end(tb, num_insns); - if (spc) { - j = tcg_op_buf_count(); - lj++; - while (lj <= j) - tcg_ctx.gen_opc_instr_start[lj++] = 0; -#if 0 - log_page_dump(); -#endif - gen_opc_jump_pc[0] = dc->jump_pc[0]; - gen_opc_jump_pc[1] = dc->jump_pc[1]; - } else { - tb->size = last_pc + 4 - pc_start; - tb->icount = num_insns; - } + tb->size = last_pc + 4 - pc_start; + tb->icount = num_insns; + #ifdef DEBUG_DISAS if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) { qemu_log("--------------\n"); @@ -5340,130 +5328,118 @@ static inline void gen_intermediate_code_internal(SPARCCPU *cpu, #endif } -void gen_intermediate_code(CPUSPARCState * env, TranslationBlock * tb) -{ - gen_intermediate_code_internal(sparc_env_get_cpu(env), tb, false); -} - -void gen_intermediate_code_pc(CPUSPARCState * env, TranslationBlock * tb) -{ - gen_intermediate_code_internal(sparc_env_get_cpu(env), tb, true); -} - void gen_intermediate_code_init(CPUSPARCState *env) { - unsigned int i; static int inited; - static const char * const gregnames[8] = { - NULL, // g0 not used - "g1", - "g2", - "g3", - "g4", - "g5", - "g6", - "g7", + static const char gregnames[32][4] = { + "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7", + "o0", "o1", "o2", "o3", "o4", "o5", "o6", "o7", + "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7", + "i0", "i1", "i2", "i3", "i4", "i5", "i6", "i7", }; - static const char * const fregnames[32] = { + static const char fregnames[32][4] = { "f0", "f2", "f4", "f6", "f8", "f10", "f12", "f14", "f16", "f18", "f20", "f22", "f24", "f26", "f28", "f30", "f32", "f34", "f36", "f38", "f40", "f42", "f44", "f46", "f48", "f50", "f52", "f54", "f56", "f58", "f60", "f62", }; - /* init various static tables */ - if (!inited) { - inited = 1; - - cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env"); - cpu_regwptr = tcg_global_mem_new_ptr(TCG_AREG0, - offsetof(CPUSPARCState, regwptr), - "regwptr"); + static const struct { TCGv_i32 *ptr; int off; const char *name; } r32[] = { #ifdef TARGET_SPARC64 - cpu_xcc = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUSPARCState, xcc), - "xcc"); - cpu_asi = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUSPARCState, asi), - "asi"); - cpu_fprs = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUSPARCState, fprs), - "fprs"); - cpu_gsr = tcg_global_mem_new(TCG_AREG0, offsetof(CPUSPARCState, gsr), - "gsr"); - cpu_tick_cmpr = tcg_global_mem_new(TCG_AREG0, - offsetof(CPUSPARCState, tick_cmpr), - "tick_cmpr"); - cpu_stick_cmpr = tcg_global_mem_new(TCG_AREG0, - offsetof(CPUSPARCState, stick_cmpr), - "stick_cmpr"); - cpu_hstick_cmpr = tcg_global_mem_new(TCG_AREG0, - offsetof(CPUSPARCState, hstick_cmpr), - "hstick_cmpr"); - cpu_hintp = tcg_global_mem_new(TCG_AREG0, offsetof(CPUSPARCState, hintp), - "hintp"); - cpu_htba = tcg_global_mem_new(TCG_AREG0, offsetof(CPUSPARCState, htba), - "htba"); - cpu_hver = tcg_global_mem_new(TCG_AREG0, offsetof(CPUSPARCState, hver), - "hver"); - cpu_ssr = tcg_global_mem_new(TCG_AREG0, - offsetof(CPUSPARCState, ssr), "ssr"); - cpu_ver = tcg_global_mem_new(TCG_AREG0, - offsetof(CPUSPARCState, version), "ver"); - cpu_softint = tcg_global_mem_new_i32(TCG_AREG0, - offsetof(CPUSPARCState, softint), - "softint"); + { &cpu_xcc, offsetof(CPUSPARCState, xcc), "xcc" }, + { &cpu_asi, offsetof(CPUSPARCState, asi), "asi" }, + { &cpu_fprs, offsetof(CPUSPARCState, fprs), "fprs" }, + { &cpu_softint, offsetof(CPUSPARCState, softint), "softint" }, #else - cpu_wim = tcg_global_mem_new(TCG_AREG0, offsetof(CPUSPARCState, wim), - "wim"); + { &cpu_wim, offsetof(CPUSPARCState, wim), "wim" }, #endif - cpu_cond = tcg_global_mem_new(TCG_AREG0, offsetof(CPUSPARCState, cond), - "cond"); - cpu_cc_src = tcg_global_mem_new(TCG_AREG0, offsetof(CPUSPARCState, cc_src), - "cc_src"); - cpu_cc_src2 = tcg_global_mem_new(TCG_AREG0, - offsetof(CPUSPARCState, cc_src2), - "cc_src2"); - cpu_cc_dst = tcg_global_mem_new(TCG_AREG0, offsetof(CPUSPARCState, cc_dst), - "cc_dst"); - cpu_cc_op = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUSPARCState, cc_op), - "cc_op"); - cpu_psr = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUSPARCState, psr), - "psr"); - cpu_fsr = tcg_global_mem_new(TCG_AREG0, offsetof(CPUSPARCState, fsr), - "fsr"); - cpu_pc = tcg_global_mem_new(TCG_AREG0, offsetof(CPUSPARCState, pc), - "pc"); - cpu_npc = tcg_global_mem_new(TCG_AREG0, offsetof(CPUSPARCState, npc), - "npc"); - cpu_y = tcg_global_mem_new(TCG_AREG0, offsetof(CPUSPARCState, y), "y"); + { &cpu_cc_op, offsetof(CPUSPARCState, cc_op), "cc_op" }, + { &cpu_psr, offsetof(CPUSPARCState, psr), "psr" }, + }; + + static const struct { TCGv *ptr; int off; const char *name; } rtl[] = { +#ifdef TARGET_SPARC64 + { &cpu_gsr, offsetof(CPUSPARCState, gsr), "gsr" }, + { &cpu_tick_cmpr, offsetof(CPUSPARCState, tick_cmpr), "tick_cmpr" }, + { &cpu_stick_cmpr, offsetof(CPUSPARCState, stick_cmpr), "stick_cmpr" }, + { &cpu_hstick_cmpr, offsetof(CPUSPARCState, hstick_cmpr), + "hstick_cmpr" }, + { &cpu_hintp, offsetof(CPUSPARCState, hintp), "hintp" }, + { &cpu_htba, offsetof(CPUSPARCState, htba), "htba" }, + { &cpu_hver, offsetof(CPUSPARCState, hver), "hver" }, + { &cpu_ssr, offsetof(CPUSPARCState, ssr), "ssr" }, + { &cpu_ver, offsetof(CPUSPARCState, version), "ver" }, +#endif + { &cpu_cond, offsetof(CPUSPARCState, cond), "cond" }, + { &cpu_cc_src, offsetof(CPUSPARCState, cc_src), "cc_src" }, + { &cpu_cc_src2, offsetof(CPUSPARCState, cc_src2), "cc_src2" }, + { &cpu_cc_dst, offsetof(CPUSPARCState, cc_dst), "cc_dst" }, + { &cpu_fsr, offsetof(CPUSPARCState, fsr), "fsr" }, + { &cpu_pc, offsetof(CPUSPARCState, pc), "pc" }, + { &cpu_npc, offsetof(CPUSPARCState, npc), "npc" }, + { &cpu_y, offsetof(CPUSPARCState, y), "y" }, #ifndef CONFIG_USER_ONLY - cpu_tbr = tcg_global_mem_new(TCG_AREG0, offsetof(CPUSPARCState, tbr), - "tbr"); + { &cpu_tbr, offsetof(CPUSPARCState, tbr), "tbr" }, #endif - for (i = 1; i < 8; i++) { - cpu_gregs[i] = tcg_global_mem_new(TCG_AREG0, - offsetof(CPUSPARCState, gregs[i]), - gregnames[i]); - } - for (i = 0; i < TARGET_DPREGS; i++) { - cpu_fpr[i] = tcg_global_mem_new_i64(TCG_AREG0, - offsetof(CPUSPARCState, fpr[i]), - fregnames[i]); - } + }; + + unsigned int i; + + /* init various static tables */ + if (inited) { + return; + } + inited = 1; + + cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env"); + + cpu_regwptr = tcg_global_mem_new_ptr(cpu_env, + offsetof(CPUSPARCState, regwptr), + "regwptr"); + + for (i = 0; i < ARRAY_SIZE(r32); ++i) { + *r32[i].ptr = tcg_global_mem_new_i32(cpu_env, r32[i].off, r32[i].name); + } + + for (i = 0; i < ARRAY_SIZE(rtl); ++i) { + *rtl[i].ptr = tcg_global_mem_new(cpu_env, rtl[i].off, rtl[i].name); + } + + TCGV_UNUSED(cpu_regs[0]); + for (i = 1; i < 8; ++i) { + cpu_regs[i] = tcg_global_mem_new(cpu_env, + offsetof(CPUSPARCState, gregs[i]), + gregnames[i]); + } + + for (i = 8; i < 32; ++i) { + cpu_regs[i] = tcg_global_mem_new(cpu_regwptr, + (i - 8) * sizeof(target_ulong), + gregnames[i]); + } + + for (i = 0; i < TARGET_DPREGS; i++) { + cpu_fpr[i] = tcg_global_mem_new_i64(cpu_env, + offsetof(CPUSPARCState, fpr[i]), + fregnames[i]); } } -void restore_state_to_opc(CPUSPARCState *env, TranslationBlock *tb, int pc_pos) +void restore_state_to_opc(CPUSPARCState *env, TranslationBlock *tb, + target_ulong *data) { - target_ulong npc; - env->pc = tcg_ctx.gen_opc_pc[pc_pos]; - npc = gen_opc_npc[pc_pos]; - if (npc == 1) { + target_ulong pc = data[0]; + target_ulong npc = data[1]; + + env->pc = pc; + if (npc == DYNAMIC_PC) { /* dynamic NPC: already stored */ - } else if (npc == 2) { + } else if (npc & JUMP_PC) { /* jump PC: use 'cond' and the jump targets of the translation */ if (env->cond) { - env->npc = gen_opc_jump_pc[0]; + env->npc = npc & ~3; } else { - env->npc = gen_opc_jump_pc[1]; + env->npc = pc + 4; } } else { env->npc = npc; diff --git a/qemu/target-sparc/vis_helper.c b/qemu/target-sparc/vis_helper.c index 383cc8bdf..8a9b763d0 100644 --- a/qemu/target-sparc/vis_helper.c +++ b/qemu/target-sparc/vis_helper.c @@ -17,6 +17,7 @@ * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ +#include "qemu/osdep.h" #include "cpu.h" #include "exec/helper-proto.h" @@ -447,7 +448,7 @@ uint32_t helper_fpackfix(uint64_t gsr, uint64_t rs2) for (word = 0; word < 2; word++) { uint32_t val; int32_t src = rs2 >> (word * 32); - int64_t scaled = src << scale; + int64_t scaled = (int64_t)src << scale; int64_t from_fixed = scaled >> 16; val = (from_fixed < -32768 ? -32768 : diff --git a/qemu/target-sparc/win_helper.c b/qemu/target-sparc/win_helper.c index f01ae08f6..a8a6c0cfc 100644 --- a/qemu/target-sparc/win_helper.c +++ b/qemu/target-sparc/win_helper.c @@ -17,6 +17,7 @@ * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ +#include "qemu/osdep.h" #include "cpu.h" #include "exec/helper-proto.h" #include "trace.h" @@ -64,23 +65,28 @@ target_ulong cpu_get_psr(CPUSPARCState *env) #endif } -void cpu_put_psr(CPUSPARCState *env, target_ulong val) +void cpu_put_psr_raw(CPUSPARCState *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; +#if !defined(TARGET_SPARC64) + cpu_set_cwp(env, val & PSR_CWP); +#endif +} + +void cpu_put_psr(CPUSPARCState *env, target_ulong val) +{ + cpu_put_psr_raw(env, val); +#if ((!defined(TARGET_SPARC64)) && !defined(CONFIG_USER_ONLY)) + cpu_check_irqs(env); +#endif } int cpu_cwp_inc(CPUSPARCState *env, int cwp) |