diff options
Diffstat (limited to 'target')
-rw-r--r-- | target/mips/addr.c | 51 | ||||
-rw-r--r-- | target/mips/cp0_helper.c | 15 | ||||
-rw-r--r-- | target/mips/cpu.c | 299 | ||||
-rw-r--r-- | target/mips/cpu.h | 20 | ||||
-rw-r--r-- | target/mips/fpu_helper.c | 6 | ||||
-rw-r--r-- | target/mips/helper.c | 64 | ||||
-rw-r--r-- | target/mips/internal.h | 17 | ||||
-rw-r--r-- | target/mips/kvm.c | 11 | ||||
-rw-r--r-- | target/mips/meson.build | 3 | ||||
-rw-r--r-- | target/mips/op_helper.c | 4 | ||||
-rw-r--r-- | target/mips/translate.c | 262 | ||||
-rw-r--r-- | target/mips/translate_init.c.inc | 10 | ||||
-rw-r--r-- | target/ppc/cpu-qom.h | 5 | ||||
-rw-r--r-- | target/ppc/excp_helper.c | 4 | ||||
-rw-r--r-- | target/ppc/fpu_helper.c | 220 | ||||
-rw-r--r-- | target/ppc/machine.c | 4 | ||||
-rw-r--r-- | target/ppc/mmu-hash64.c | 2 | ||||
-rw-r--r-- | target/ppc/mmu_helper.c | 15 | ||||
-rw-r--r-- | target/ppc/translate.c | 4 | ||||
-rw-r--r-- | target/ppc/translate/vsx-impl.c.inc | 46 | ||||
-rw-r--r-- | target/ppc/translate_init.c.inc | 61 |
21 files changed, 579 insertions, 544 deletions
diff --git a/target/mips/addr.c b/target/mips/addr.c new file mode 100644 index 0000000000..27a6036c45 --- /dev/null +++ b/target/mips/addr.c @@ -0,0 +1,51 @@ +/* + * QEMU MIPS address translation support + * + * 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" + +static int mips_um_ksegs; + +uint64_t cpu_mips_kseg0_to_phys(void *opaque, uint64_t addr) +{ + return addr & 0x1fffffffll; +} + +uint64_t cpu_mips_phys_to_kseg0(void *opaque, uint64_t addr) +{ + return addr | ~0x7fffffffll; +} + +uint64_t cpu_mips_kvm_um_phys_to_kseg0(void *opaque, uint64_t addr) +{ + return addr | 0x40000000ll; +} + +bool mips_um_ksegs_enabled(void) +{ + return mips_um_ksegs; +} + +void mips_um_ksegs_enable(void) +{ + mips_um_ksegs = 1; +} diff --git a/target/mips/cp0_helper.c b/target/mips/cp0_helper.c index a1b5140cca..36a92857bf 100644 --- a/target/mips/cp0_helper.c +++ b/target/mips/cp0_helper.c @@ -21,18 +21,15 @@ */ #include "qemu/osdep.h" +#include "qemu/log.h" #include "qemu/main-loop.h" #include "cpu.h" #include "internal.h" #include "qemu/host-utils.h" #include "exec/helper-proto.h" #include "exec/exec-all.h" -#include "exec/cpu_ldst.h" -#include "exec/memop.h" -#include "sysemu/kvm.h" -#ifndef CONFIG_USER_ONLY /* SMP helpers. */ static bool mips_vpe_is_wfi(MIPSCPU *c) { @@ -904,7 +901,7 @@ void update_pagemask(CPUMIPSState *env, target_ulong arg1, int32_t *pagemask) goto invalid; } /* We don't support VTLB entry smaller than target page */ - if ((maskbits + 12) < TARGET_PAGE_BITS) { + if ((maskbits + TARGET_PAGE_BITS_MIN) < TARGET_PAGE_BITS) { goto invalid; } env->CP0_PageMask = mask << CP0PM_MASK; @@ -913,7 +910,8 @@ void update_pagemask(CPUMIPSState *env, target_ulong arg1, int32_t *pagemask) invalid: /* When invalid, set to default target page size. */ - env->CP0_PageMask = (~TARGET_PAGE_MASK >> 12) << CP0PM_MASK; + mask = (~TARGET_PAGE_MASK >> TARGET_PAGE_BITS_MIN); + env->CP0_PageMask = mask << CP0PM_MASK; } void helper_mtc0_pagemask(CPUMIPSState *env, target_ulong arg1) @@ -1166,7 +1164,7 @@ void helper_mtc0_entryhi(CPUMIPSState *env, target_ulong arg1) old = env->CP0_EntryHi; val = (arg1 & mask) | (old & ~mask); env->CP0_EntryHi = val; - if (env->CP0_Config3 & (1 << CP0C3_MT)) { + if (ase_mt_available(env)) { sync_c0_entryhi(env, env->current_tc); } /* If the ASID changes, flush qemu's TLB. */ @@ -1666,10 +1664,8 @@ target_ulong helper_evpe(CPUMIPSState *env) } return prev; } -#endif /* !CONFIG_USER_ONLY */ /* R6 Multi-threading */ -#ifndef CONFIG_USER_ONLY target_ulong helper_dvp(CPUMIPSState *env) { CPUState *other_cs = first_cpu; @@ -1708,4 +1704,3 @@ target_ulong helper_evp(CPUMIPSState *env) } return prev; } -#endif /* !CONFIG_USER_ONLY */ diff --git a/target/mips/cpu.c b/target/mips/cpu.c index 76d50b00b4..aadc6f8e74 100644 --- a/target/mips/cpu.c +++ b/target/mips/cpu.c @@ -20,6 +20,7 @@ #include "qemu/osdep.h" #include "qemu/cutils.h" +#include "qemu/qemu-print.h" #include "qapi/error.h" #include "cpu.h" #include "internal.h" @@ -30,6 +31,8 @@ #include "exec/exec-all.h" #include "hw/qdev-properties.h" #include "hw/qdev-clock.h" +#include "hw/semihosting/semihost.h" +#include "qapi/qapi-commands-machine-target.h" static void mips_cpu_set_pc(CPUState *cs, vaddr value) { @@ -74,7 +77,7 @@ static bool mips_cpu_has_work(CPUState *cs) } /* MIPS-MT has the ability to halt the CPU. */ - if (env->CP0_Config3 & (1 << CP0C3_MT)) { + if (ase_mt_available(env)) { /* * The QEMU model will issue an _WAKE request whenever the CPUs * should be woken up. @@ -99,6 +102,236 @@ static bool mips_cpu_has_work(CPUState *cs) return has_work; } +#include "translate_init.c.inc" + +/* TODO QOM'ify CPU reset and remove */ +static void cpu_state_reset(CPUMIPSState *env) +{ + CPUState *cs = env_cpu(env); + + /* Reset registers to their default values */ + env->CP0_PRid = env->cpu_model->CP0_PRid; + env->CP0_Config0 = env->cpu_model->CP0_Config0; +#ifdef TARGET_WORDS_BIGENDIAN + env->CP0_Config0 |= (1 << CP0C0_BE); +#endif + env->CP0_Config1 = env->cpu_model->CP0_Config1; + env->CP0_Config2 = env->cpu_model->CP0_Config2; + env->CP0_Config3 = env->cpu_model->CP0_Config3; + env->CP0_Config4 = env->cpu_model->CP0_Config4; + env->CP0_Config4_rw_bitmask = env->cpu_model->CP0_Config4_rw_bitmask; + env->CP0_Config5 = env->cpu_model->CP0_Config5; + env->CP0_Config5_rw_bitmask = env->cpu_model->CP0_Config5_rw_bitmask; + env->CP0_Config6 = env->cpu_model->CP0_Config6; + env->CP0_Config6_rw_bitmask = env->cpu_model->CP0_Config6_rw_bitmask; + env->CP0_Config7 = env->cpu_model->CP0_Config7; + env->CP0_Config7_rw_bitmask = env->cpu_model->CP0_Config7_rw_bitmask; + env->CP0_LLAddr_rw_bitmask = env->cpu_model->CP0_LLAddr_rw_bitmask + << env->cpu_model->CP0_LLAddr_shift; + env->CP0_LLAddr_shift = env->cpu_model->CP0_LLAddr_shift; + env->SYNCI_Step = env->cpu_model->SYNCI_Step; + env->CCRes = env->cpu_model->CCRes; + env->CP0_Status_rw_bitmask = env->cpu_model->CP0_Status_rw_bitmask; + env->CP0_TCStatus_rw_bitmask = env->cpu_model->CP0_TCStatus_rw_bitmask; + env->CP0_SRSCtl = env->cpu_model->CP0_SRSCtl; + env->current_tc = 0; + env->SEGBITS = env->cpu_model->SEGBITS; + env->SEGMask = (target_ulong)((1ULL << env->cpu_model->SEGBITS) - 1); +#if defined(TARGET_MIPS64) + if (env->cpu_model->insn_flags & ISA_MIPS3) { + env->SEGMask |= 3ULL << 62; + } +#endif + env->PABITS = env->cpu_model->PABITS; + env->CP0_SRSConf0_rw_bitmask = env->cpu_model->CP0_SRSConf0_rw_bitmask; + env->CP0_SRSConf0 = env->cpu_model->CP0_SRSConf0; + env->CP0_SRSConf1_rw_bitmask = env->cpu_model->CP0_SRSConf1_rw_bitmask; + env->CP0_SRSConf1 = env->cpu_model->CP0_SRSConf1; + env->CP0_SRSConf2_rw_bitmask = env->cpu_model->CP0_SRSConf2_rw_bitmask; + env->CP0_SRSConf2 = env->cpu_model->CP0_SRSConf2; + env->CP0_SRSConf3_rw_bitmask = env->cpu_model->CP0_SRSConf3_rw_bitmask; + env->CP0_SRSConf3 = env->cpu_model->CP0_SRSConf3; + env->CP0_SRSConf4_rw_bitmask = env->cpu_model->CP0_SRSConf4_rw_bitmask; + env->CP0_SRSConf4 = env->cpu_model->CP0_SRSConf4; + env->CP0_PageGrain_rw_bitmask = env->cpu_model->CP0_PageGrain_rw_bitmask; + env->CP0_PageGrain = env->cpu_model->CP0_PageGrain; + env->CP0_EBaseWG_rw_bitmask = env->cpu_model->CP0_EBaseWG_rw_bitmask; + env->active_fpu.fcr0 = env->cpu_model->CP1_fcr0; + env->active_fpu.fcr31_rw_bitmask = env->cpu_model->CP1_fcr31_rw_bitmask; + env->active_fpu.fcr31 = env->cpu_model->CP1_fcr31; + env->msair = env->cpu_model->MSAIR; + env->insn_flags = env->cpu_model->insn_flags; + +#if defined(CONFIG_USER_ONLY) + env->CP0_Status = (MIPS_HFLAG_UM << CP0St_KSU); +# ifdef TARGET_MIPS64 + /* Enable 64-bit register mode. */ + env->CP0_Status |= (1 << CP0St_PX); +# endif +# ifdef TARGET_ABI_MIPSN64 + /* Enable 64-bit address mode. */ + env->CP0_Status |= (1 << CP0St_UX); +# endif + /* + * Enable access to the CPUNum, SYNCI_Step, CC, and CCRes RDHWR + * hardware registers. + */ + env->CP0_HWREna |= 0x0000000F; + if (env->CP0_Config1 & (1 << CP0C1_FP)) { + env->CP0_Status |= (1 << CP0St_CU1); + } + if (env->CP0_Config3 & (1 << CP0C3_DSPP)) { + env->CP0_Status |= (1 << CP0St_MX); + } +# if defined(TARGET_MIPS64) + /* For MIPS64, init FR bit to 1 if FPU unit is there and bit is writable. */ + if ((env->CP0_Config1 & (1 << CP0C1_FP)) && + (env->CP0_Status_rw_bitmask & (1 << CP0St_FR))) { + env->CP0_Status |= (1 << CP0St_FR); + } +# endif +#else /* !CONFIG_USER_ONLY */ + if (env->hflags & MIPS_HFLAG_BMASK) { + /* + * If the exception was raised from a delay slot, + * come back to the jump. + */ + env->CP0_ErrorEPC = (env->active_tc.PC + - (env->hflags & MIPS_HFLAG_B16 ? 2 : 4)); + } else { + env->CP0_ErrorEPC = env->active_tc.PC; + } + env->active_tc.PC = env->exception_base; + env->CP0_Random = env->tlb->nb_tlb - 1; + env->tlb->tlb_in_use = env->tlb->nb_tlb; + env->CP0_Wired = 0; + env->CP0_GlobalNumber = (cs->cpu_index & 0xFF) << CP0GN_VPId; + env->CP0_EBase = (cs->cpu_index & 0x3FF); + if (mips_um_ksegs_enabled()) { + env->CP0_EBase |= 0x40000000; + } else { + env->CP0_EBase |= (int32_t)0x80000000; + } + if (env->CP0_Config3 & (1 << CP0C3_CMGCR)) { + env->CP0_CMGCRBase = 0x1fbf8000 >> 4; + } + env->CP0_EntryHi_ASID_mask = (env->CP0_Config5 & (1 << CP0C5_MI)) ? + 0x0 : (env->CP0_Config4 & (1 << CP0C4_AE)) ? 0x3ff : 0xff; + env->CP0_Status = (1 << CP0St_BEV) | (1 << CP0St_ERL); + /* + * Vectored interrupts not implemented, timer on int 7, + * no performance counters. + */ + env->CP0_IntCtl = 0xe0000000; + { + int i; + + for (i = 0; i < 7; i++) { + env->CP0_WatchLo[i] = 0; + env->CP0_WatchHi[i] = 0x80000000; + } + env->CP0_WatchLo[7] = 0; + env->CP0_WatchHi[7] = 0; + } + /* Count register increments in debug mode, EJTAG version 1 */ + env->CP0_Debug = (1 << CP0DB_CNT) | (0x1 << CP0DB_VER); + + cpu_mips_store_count(env, 1); + + if (ase_mt_available(env)) { + int i; + + /* Only TC0 on VPE 0 starts as active. */ + for (i = 0; i < ARRAY_SIZE(env->tcs); i++) { + env->tcs[i].CP0_TCBind = cs->cpu_index << CP0TCBd_CurVPE; + env->tcs[i].CP0_TCHalt = 1; + } + env->active_tc.CP0_TCHalt = 1; + cs->halted = 1; + + if (cs->cpu_index == 0) { + /* VPE0 starts up enabled. */ + env->mvp->CP0_MVPControl |= (1 << CP0MVPCo_EVP); + env->CP0_VPEConf0 |= (1 << CP0VPEC0_MVP) | (1 << CP0VPEC0_VPA); + + /* TC0 starts up unhalted. */ + cs->halted = 0; + env->active_tc.CP0_TCHalt = 0; + env->tcs[0].CP0_TCHalt = 0; + /* With thread 0 active. */ + env->active_tc.CP0_TCStatus = (1 << CP0TCSt_A); + env->tcs[0].CP0_TCStatus = (1 << CP0TCSt_A); + } + } + + /* + * Configure default legacy segmentation control. We use this regardless of + * whether segmentation control is presented to the guest. + */ + /* KSeg3 (seg0 0xE0000000..0xFFFFFFFF) */ + env->CP0_SegCtl0 = (CP0SC_AM_MK << CP0SC_AM); + /* KSeg2 (seg1 0xC0000000..0xDFFFFFFF) */ + env->CP0_SegCtl0 |= ((CP0SC_AM_MSK << CP0SC_AM)) << 16; + /* KSeg1 (seg2 0xA0000000..0x9FFFFFFF) */ + env->CP0_SegCtl1 = (0 << CP0SC_PA) | (CP0SC_AM_UK << CP0SC_AM) | + (2 << CP0SC_C); + /* KSeg0 (seg3 0x80000000..0x9FFFFFFF) */ + env->CP0_SegCtl1 |= ((0 << CP0SC_PA) | (CP0SC_AM_UK << CP0SC_AM) | + (3 << CP0SC_C)) << 16; + /* USeg (seg4 0x40000000..0x7FFFFFFF) */ + env->CP0_SegCtl2 = (2 << CP0SC_PA) | (CP0SC_AM_MUSK << CP0SC_AM) | + (1 << CP0SC_EU) | (2 << CP0SC_C); + /* USeg (seg5 0x00000000..0x3FFFFFFF) */ + env->CP0_SegCtl2 |= ((0 << CP0SC_PA) | (CP0SC_AM_MUSK << CP0SC_AM) | + (1 << CP0SC_EU) | (2 << CP0SC_C)) << 16; + /* XKPhys (note, SegCtl2.XR = 0, so XAM won't be used) */ + env->CP0_SegCtl1 |= (CP0SC_AM_UK << CP0SC1_XAM); +#endif /* !CONFIG_USER_ONLY */ + if ((env->insn_flags & ISA_MIPS32R6) && + (env->active_fpu.fcr0 & (1 << FCR0_F64))) { + /* Status.FR = 0 mode in 64-bit FPU not allowed in R6 */ + env->CP0_Status |= (1 << CP0St_FR); + } + + if (env->insn_flags & ISA_MIPS32R6) { + /* PTW = 1 */ + env->CP0_PWSize = 0x40; + /* GDI = 12 */ + /* UDI = 12 */ + /* MDI = 12 */ + /* PRI = 12 */ + /* PTEI = 2 */ + env->CP0_PWField = 0x0C30C302; + } else { + /* GDI = 0 */ + /* UDI = 0 */ + /* MDI = 0 */ + /* PRI = 0 */ + /* PTEI = 2 */ + env->CP0_PWField = 0x02; + } + + if (env->CP0_Config3 & (1 << CP0C3_ISA) & (1 << (CP0C3_ISA + 1))) { + /* microMIPS on reset when Config3.ISA is 3 */ + env->hflags |= MIPS_HFLAG_M16; + } + + /* MSA */ + if (env->CP0_Config3 & (1 << CP0C3_MSAP)) { + msa_reset(env); + } + + compute_hflags(env); + restore_fp_status(env); + restore_pamask(env); + cs->exception_index = EXCP_NONE; + + if (semihosting_get_argc()) { + /* UHI interface can be used to obtain argc and argv */ + env->active_tc.gpr[4] = -1; + } +} + static void mips_cpu_reset(DeviceState *dev) { CPUState *s = CPU(dev); @@ -156,6 +389,7 @@ static void mips_cpu_realizefn(DeviceState *dev, Error **errp) { CPUState *cs = CPU(dev); MIPSCPU *cpu = MIPS_CPU(dev); + CPUMIPSState *env = &cpu->env; MIPSCPUClass *mcc = MIPS_CPU_GET_CLASS(dev); Error *local_err = NULL; @@ -179,7 +413,13 @@ static void mips_cpu_realizefn(DeviceState *dev, Error **errp) return; } - cpu_mips_realize_env(&cpu->env); + env->exception_base = (int32_t)0xBFC00000; + +#ifndef CONFIG_USER_ONLY + mmu_init(env, env->cpu_model); +#endif + fpu_init(env, env->cpu_model); + mvp_init(env); cpu_reset(cs); qemu_init_vcpu(cs); @@ -299,6 +539,38 @@ static void mips_cpu_register_types(void) type_init(mips_cpu_register_types) +static void mips_cpu_add_definition(gpointer data, gpointer user_data) +{ + ObjectClass *oc = data; + CpuDefinitionInfoList **cpu_list = user_data; + CpuDefinitionInfoList *entry; + CpuDefinitionInfo *info; + const char *typename; + + typename = object_class_get_name(oc); + info = g_malloc0(sizeof(*info)); + info->name = g_strndup(typename, + strlen(typename) - strlen("-" TYPE_MIPS_CPU)); + info->q_typename = g_strdup(typename); + + entry = g_malloc0(sizeof(*entry)); + entry->value = info; + entry->next = *cpu_list; + *cpu_list = entry; +} + +CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp) +{ + CpuDefinitionInfoList *cpu_list = NULL; + GSList *list; + + list = object_class_get_list(TYPE_MIPS_CPU, false); + g_slist_foreach(list, mips_cpu_add_definition, &cpu_list); + g_slist_free(list); + + return cpu_list; +} + /* Could be used by generic CPU object */ MIPSCPU *mips_cpu_create_with_clock(const char *cpu_type, Clock *cpu_refclk) { @@ -310,3 +582,26 @@ MIPSCPU *mips_cpu_create_with_clock(const char *cpu_type, Clock *cpu_refclk) return MIPS_CPU(cpu); } + +bool cpu_supports_isa(const CPUMIPSState *env, uint64_t isa_mask) +{ + return (env->cpu_model->insn_flags & isa_mask) != 0; +} + +bool cpu_type_supports_isa(const char *cpu_type, uint64_t isa) +{ + const MIPSCPUClass *mcc = MIPS_CPU_CLASS(object_class_by_name(cpu_type)); + return (mcc->cpu_def->insn_flags & isa) != 0; +} + +bool cpu_type_supports_cps_smp(const char *cpu_type) +{ + const MIPSCPUClass *mcc = MIPS_CPU_CLASS(object_class_by_name(cpu_type)); + return (mcc->cpu_def->CP0_Config3 & (1 << CP0C3_CMGCR)) != 0; +} + +void cpu_set_exception_base(int vp_index, target_ulong address) +{ + MIPSCPU *vp = MIPS_CPU(qemu_get_cpu(vp_index)); + vp->env.exception_base = address; +} diff --git a/target/mips/cpu.h b/target/mips/cpu.h index 23f8c6f96c..3ac21d0e9c 100644 --- a/target/mips/cpu.h +++ b/target/mips/cpu.h @@ -1286,10 +1286,26 @@ int cpu_mips_signal_handler(int host_signum, void *pinfo, void *puc); #define MIPS_CPU_TYPE_NAME(model) model MIPS_CPU_TYPE_SUFFIX #define CPU_RESOLVING_TYPE TYPE_MIPS_CPU -bool cpu_supports_cps_smp(const char *cpu_type); -bool cpu_supports_isa(const char *cpu_type, uint64_t isa); +bool cpu_type_supports_cps_smp(const char *cpu_type); +bool cpu_supports_isa(const CPUMIPSState *env, uint64_t isa_mask); +bool cpu_type_supports_isa(const char *cpu_type, uint64_t isa); + +/* Check presence of multi-threading ASE implementation */ +static inline bool ase_mt_available(CPUMIPSState *env) +{ + return env->CP0_Config3 & (1 << CP0C3_MT); +} + void cpu_set_exception_base(int vp_index, target_ulong address); +/* addr.c */ +uint64_t cpu_mips_kseg0_to_phys(void *opaque, uint64_t addr); +uint64_t cpu_mips_phys_to_kseg0(void *opaque, uint64_t addr); + +uint64_t cpu_mips_kvm_um_phys_to_kseg0(void *opaque, uint64_t addr); +bool mips_um_ksegs_enabled(void); +void mips_um_ksegs_enable(void); + /* mips_int.c */ void cpu_mips_soft_irq(CPUMIPSState *env, int irq, int level); diff --git a/target/mips/fpu_helper.c b/target/mips/fpu_helper.c index 020b768e87..bdb65065ee 100644 --- a/target/mips/fpu_helper.c +++ b/target/mips/fpu_helper.c @@ -21,15 +21,11 @@ */ #include "qemu/osdep.h" -#include "qemu/main-loop.h" #include "cpu.h" #include "internal.h" -#include "qemu/host-utils.h" #include "exec/helper-proto.h" #include "exec/exec-all.h" #include "exec/cpu_ldst.h" -#include "exec/memop.h" -#include "sysemu/kvm.h" #include "fpu/softfloat.h" @@ -42,7 +38,7 @@ #define FP_TO_INT64_OVERFLOW 0x7fffffffffffffffULL /* convert MIPS rounding mode in FCR31 to IEEE library */ -unsigned int ieee_rm[] = { +const FloatRoundMode ieee_rm[4] = { float_round_nearest_even, float_round_to_zero, float_round_up, diff --git a/target/mips/helper.c b/target/mips/helper.c index 063b65c052..87296fbad6 100644 --- a/target/mips/helper.c +++ b/target/mips/helper.c @@ -24,7 +24,6 @@ #include "exec/cpu_ldst.h" #include "exec/log.h" #include "hw/mips/cpudevs.h" -#include "qapi/qapi-commands-machine-target.h" enum { TLBRET_XI = -6, @@ -419,7 +418,7 @@ void cpu_mips_store_status(CPUMIPSState *env, target_ulong val) tlb_flush(env_cpu(env)); } #endif - if (env->CP0_Config3 & (1 << CP0C3_MT)) { + if (ase_mt_available(env)) { sync_c0_status(env, env, env->current_tc); } else { compute_hflags(env); @@ -858,8 +857,8 @@ refill: break; } } - pw_pagemask = m >> 12; - update_pagemask(env, pw_pagemask << 13, &pw_pagemask); + pw_pagemask = m >> TARGET_PAGE_BITS_MIN; + update_pagemask(env, pw_pagemask << CP0PM_MASK, &pw_pagemask); pw_entryhi = (address & ~0x1fff) | (env->CP0_EntryHi & 0xFF); { target_ulong tmp_entryhi = env->CP0_EntryHi; @@ -978,6 +977,7 @@ hwaddr cpu_mips_translate_address(CPUMIPSState *env, target_ulong address, return physical; } } +#endif /* !CONFIG_USER_ONLY */ static const char * const excp_names[EXCP_LAST + 1] = { [EXCP_RESET] = "reset", @@ -1018,7 +1018,14 @@ static const char * const excp_names[EXCP_LAST + 1] = { [EXCP_MSADIS] = "MSA disabled", [EXCP_MSAFPE] = "MSA floating point", }; -#endif + +static const char *mips_exception_name(int32_t exception) +{ + if (exception < 0 || exception > EXCP_LAST) { + return "unknown"; + } + return excp_names[exception]; +} target_ulong exception_resume_pc(CPUMIPSState *env) { @@ -1091,19 +1098,13 @@ void mips_cpu_do_interrupt(CPUState *cs) bool update_badinstr = 0; target_ulong offset; int cause = -1; - const char *name; if (qemu_loglevel_mask(CPU_LOG_INT) && cs->exception_index != EXCP_EXT_INTERRUPT) { - if (cs->exception_index < 0 || cs->exception_index > EXCP_LAST) { - name = "unknown"; - } else { - name = excp_names[cs->exception_index]; - } - qemu_log("%s enter: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx " %s exception\n", - __func__, env->active_tc.PC, env->CP0_EPC, name); + __func__, env->active_tc.PC, env->CP0_EPC, + mips_exception_name(cs->exception_index)); } if (cs->exception_index == EXCP_EXT_INTERRUPT && (env->hflags & MIPS_HFLAG_DM)) { @@ -1490,42 +1491,11 @@ void QEMU_NORETURN do_raise_exception_err(CPUMIPSState *env, { CPUState *cs = env_cpu(env); - qemu_log_mask(CPU_LOG_INT, "%s: %d %d\n", - __func__, exception, error_code); + qemu_log_mask(CPU_LOG_INT, "%s: %d (%s) %d\n", + __func__, exception, mips_exception_name(exception), + error_code); cs->exception_index = exception; env->error_code = error_code; cpu_loop_exit_restore(cs, pc); } - -static void mips_cpu_add_definition(gpointer data, gpointer user_data) -{ - ObjectClass *oc = data; - CpuDefinitionInfoList **cpu_list = user_data; - CpuDefinitionInfoList *entry; - CpuDefinitionInfo *info; - const char *typename; - - typename = object_class_get_name(oc); - info = g_malloc0(sizeof(*info)); - info->name = g_strndup(typename, - strlen(typename) - strlen("-" TYPE_MIPS_CPU)); - info->q_typename = g_strdup(typename); - - entry = g_malloc0(sizeof(*entry)); - entry->value = info; - entry->next = *cpu_list; - *cpu_list = entry; -} - -CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp) -{ - CpuDefinitionInfoList *cpu_list = NULL; - GSList *list; - - list = object_class_get_list(TYPE_MIPS_CPU, false); - g_slist_foreach(list, mips_cpu_add_definition, &cpu_list); - g_slist_free(list); - - return cpu_list; -} diff --git a/target/mips/internal.h b/target/mips/internal.h index dd8a7809b6..e4d2d9f44f 100644 --- a/target/mips/internal.h +++ b/target/mips/internal.h @@ -8,6 +8,7 @@ #ifndef MIPS_INTERNAL_H #define MIPS_INTERNAL_H +#include "exec/memattrs.h" #include "fpu/softfloat-helpers.h" /* @@ -15,10 +16,11 @@ * CP0C0_MT field. */ enum mips_mmu_types { - MMU_TYPE_NONE, - MMU_TYPE_R4000, - MMU_TYPE_RESERVED, - MMU_TYPE_FMT, + MMU_TYPE_NONE = 0, + MMU_TYPE_R4000 = 1, /* Standard TLB */ + MMU_TYPE_BAT = 2, /* Block Address Translation */ + MMU_TYPE_FMT = 3, /* Fixed Mapping */ + MMU_TYPE_DVF = 4, /* Dual VTLB and FTLB */ MMU_TYPE_R3000, MMU_TYPE_R6000, MMU_TYPE_R8000 @@ -205,10 +207,6 @@ static inline bool cpu_mips_hw_interrupts_pending(CPUMIPSState *env) void mips_tcg_init(void); -/* TODO QOM'ify CPU reset and remove */ -void cpu_state_reset(CPUMIPSState *s); -void cpu_mips_realize_env(CPUMIPSState *env); - /* cp0_timer.c */ uint32_t cpu_mips_get_count(CPUMIPSState *env); void cpu_mips_store_count(CPUMIPSState *env, uint32_t value); @@ -225,7 +223,8 @@ bool mips_cpu_tlb_fill(CPUState *cs, vaddr address, int size, uint32_t float_class_s(uint32_t arg, float_status *fst); uint64_t float_class_d(uint64_t arg, float_status *fst); -extern unsigned int ieee_rm[]; +extern const FloatRoundMode ieee_rm[4]; + void update_pagemask(CPUMIPSState *env, target_ulong arg1, int32_t *pagemask); static inline void restore_rounding_mode(CPUMIPSState *env) diff --git a/target/mips/kvm.c b/target/mips/kvm.c index 72637a1e02..477692566a 100644 --- a/target/mips/kvm.c +++ b/target/mips/kvm.c @@ -19,13 +19,10 @@ #include "internal.h" #include "qemu/error-report.h" #include "qemu/main-loop.h" -#include "qemu/timer.h" #include "sysemu/kvm.h" #include "sysemu/kvm_int.h" #include "sysemu/runstate.h" -#include "sysemu/cpus.h" #include "kvm_mips.h" -#include "exec/memattrs.h" #include "hw/boards.h" #define DEBUG_KVM 0 @@ -198,9 +195,7 @@ int kvm_mips_set_interrupt(MIPSCPU *cpu, int irq, int level) CPUState *cs = CPU(cpu); struct kvm_mips_interrupt intr; - if (!kvm_enabled()) { - return 0; - } + assert(kvm_enabled()); intr.cpu = -1; @@ -221,9 +216,7 @@ int kvm_mips_set_ipi_interrupt(MIPSCPU *cpu, int irq, int level) CPUState *dest_cs = CPU(cpu); struct kvm_mips_interrupt intr; - if (!kvm_enabled()) { - return 0; - } + assert(kvm_enabled()); intr.cpu = dest_cs->cpu_index; diff --git a/target/mips/meson.build b/target/mips/meson.build index fa1f024e78..4179395a8e 100644 --- a/target/mips/meson.build +++ b/target/mips/meson.build @@ -1,6 +1,5 @@ mips_ss = ss.source_set() mips_ss.add(files( - 'cp0_helper.c', 'cpu.c', 'dsp_helper.c', 'fpu_helper.c', @@ -15,6 +14,8 @@ mips_ss.add(when: 'CONFIG_KVM', if_true: files('kvm.c')) mips_softmmu_ss = ss.source_set() mips_softmmu_ss.add(files( + 'addr.c', + 'cp0_helper.c', 'cp0_timer.c', 'machine.c', 'mips-semi.c', diff --git a/target/mips/op_helper.c b/target/mips/op_helper.c index 5184a1838b..5aa97902e9 100644 --- a/target/mips/op_helper.c +++ b/target/mips/op_helper.c @@ -19,15 +19,11 @@ */ #include "qemu/osdep.h" -#include "qemu/main-loop.h" #include "cpu.h" #include "internal.h" -#include "qemu/host-utils.h" #include "exec/helper-proto.h" #include "exec/exec-all.h" -#include "exec/cpu_ldst.h" #include "exec/memop.h" -#include "sysemu/kvm.h" /*****************************************************************************/ diff --git a/target/mips/translate.c b/target/mips/translate.c index c64a1bc42e..19933b7868 100644 --- a/target/mips/translate.c +++ b/target/mips/translate.c @@ -24,12 +24,8 @@ #include "qemu/osdep.h" #include "cpu.h" #include "internal.h" -#include "disas/disas.h" -#include "exec/exec-all.h" #include "tcg/tcg-op.h" #include "exec/cpu_ldst.h" -#include "hw/mips/cpudevs.h" - #include "exec/helper-proto.h" #include "exec/helper-gen.h" #include "hw/semihosting/semihost.h" @@ -31757,264 +31753,6 @@ void mips_tcg_init(void) #endif } -#include "translate_init.c.inc" - -void cpu_mips_realize_env(CPUMIPSState *env) -{ - env->exception_base = (int32_t)0xBFC00000; - -#ifndef CONFIG_USER_ONLY - mmu_init(env, env->cpu_model); -#endif - fpu_init(env, env->cpu_model); - mvp_init(env, env->cpu_model); -} - -bool cpu_supports_cps_smp(const char *cpu_type) -{ - const MIPSCPUClass *mcc = MIPS_CPU_CLASS(object_class_by_name(cpu_type)); - return (mcc->cpu_def->CP0_Config3 & (1 << CP0C3_CMGCR)) != 0; -} - -bool cpu_supports_isa(const char *cpu_type, uint64_t isa) -{ - const MIPSCPUClass *mcc = MIPS_CPU_CLASS(object_class_by_name(cpu_type)); - return (mcc->cpu_def->insn_flags & isa) != 0; -} - -void cpu_set_exception_base(int vp_index, target_ulong address) -{ - MIPSCPU *vp = MIPS_CPU(qemu_get_cpu(vp_index)); - vp->env.exception_base = address; -} - -void cpu_state_reset(CPUMIPSState *env) -{ - CPUState *cs = env_cpu(env); - - /* Reset registers to their default values */ - env->CP0_PRid = env->cpu_model->CP0_PRid; - env->CP0_Config0 = env->cpu_model->CP0_Config0; -#ifdef TARGET_WORDS_BIGENDIAN - env->CP0_Config0 |= (1 << CP0C0_BE); -#endif - env->CP0_Config1 = env->cpu_model->CP0_Config1; - env->CP0_Config2 = env->cpu_model->CP0_Config2; - env->CP0_Config3 = env->cpu_model->CP0_Config3; - env->CP0_Config4 = env->cpu_model->CP0_Config4; - env->CP0_Config4_rw_bitmask = env->cpu_model->CP0_Config4_rw_bitmask; - env->CP0_Config5 = env->cpu_model->CP0_Config5; - env->CP0_Config5_rw_bitmask = env->cpu_model->CP0_Config5_rw_bitmask; - env->CP0_Config6 = env->cpu_model->CP0_Config6; - env->CP0_Config6_rw_bitmask = env->cpu_model->CP0_Config6_rw_bitmask; - env->CP0_Config7 = env->cpu_model->CP0_Config7; - env->CP0_Config7_rw_bitmask = env->cpu_model->CP0_Config7_rw_bitmask; - env->CP0_LLAddr_rw_bitmask = env->cpu_model->CP0_LLAddr_rw_bitmask - << env->cpu_model->CP0_LLAddr_shift; - env->CP0_LLAddr_shift = env->cpu_model->CP0_LLAddr_shift; - env->SYNCI_Step = env->cpu_model->SYNCI_Step; - env->CCRes = env->cpu_model->CCRes; - env->CP0_Status_rw_bitmask = env->cpu_model->CP0_Status_rw_bitmask; - env->CP0_TCStatus_rw_bitmask = env->cpu_model->CP0_TCStatus_rw_bitmask; - env->CP0_SRSCtl = env->cpu_model->CP0_SRSCtl; - env->current_tc = 0; - env->SEGBITS = env->cpu_model->SEGBITS; - env->SEGMask = (target_ulong)((1ULL << env->cpu_model->SEGBITS) - 1); -#if defined(TARGET_MIPS64) - if (env->cpu_model->insn_flags & ISA_MIPS3) { - env->SEGMask |= 3ULL << 62; - } -#endif - env->PABITS = env->cpu_model->PABITS; - env->CP0_SRSConf0_rw_bitmask = env->cpu_model->CP0_SRSConf0_rw_bitmask; - env->CP0_SRSConf0 = env->cpu_model->CP0_SRSConf0; - env->CP0_SRSConf1_rw_bitmask = env->cpu_model->CP0_SRSConf1_rw_bitmask; - env->CP0_SRSConf1 = env->cpu_model->CP0_SRSConf1; - env->CP0_SRSConf2_rw_bitmask = env->cpu_model->CP0_SRSConf2_rw_bitmask; - env->CP0_SRSConf2 = env->cpu_model->CP0_SRSConf2; - env->CP0_SRSConf3_rw_bitmask = env->cpu_model->CP0_SRSConf3_rw_bitmask; - env->CP0_SRSConf3 = env->cpu_model->CP0_SRSConf3; - env->CP0_SRSConf4_rw_bitmask = env->cpu_model->CP0_SRSConf4_rw_bitmask; - env->CP0_SRSConf4 = env->cpu_model->CP0_SRSConf4; - env->CP0_PageGrain_rw_bitmask = env->cpu_model->CP0_PageGrain_rw_bitmask; - env->CP0_PageGrain = env->cpu_model->CP0_PageGrain; - env->CP0_EBaseWG_rw_bitmask = env->cpu_model->CP0_EBaseWG_rw_bitmask; - env->active_fpu.fcr0 = env->cpu_model->CP1_fcr0; - env->active_fpu.fcr31_rw_bitmask = env->cpu_model->CP1_fcr31_rw_bitmask; - env->active_fpu.fcr31 = env->cpu_model->CP1_fcr31; - env->msair = env->cpu_model->MSAIR; - env->insn_flags = env->cpu_model->insn_flags; - -#if defined(CONFIG_USER_ONLY) - env->CP0_Status = (MIPS_HFLAG_UM << CP0St_KSU); -# ifdef TARGET_MIPS64 - /* Enable 64-bit register mode. */ - env->CP0_Status |= (1 << CP0St_PX); -# endif -# ifdef TARGET_ABI_MIPSN64 - /* Enable 64-bit address mode. */ - env->CP0_Status |= (1 << CP0St_UX); -# endif - /* - * Enable access to the CPUNum, SYNCI_Step, CC, and CCRes RDHWR - * hardware registers. - */ - env->CP0_HWREna |= 0x0000000F; - if (env->CP0_Config1 & (1 << CP0C1_FP)) { - env->CP0_Status |= (1 << CP0St_CU1); - } - if (env->CP0_Config3 & (1 << CP0C3_DSPP)) { - env->CP0_Status |= (1 << CP0St_MX); - } -# if defined(TARGET_MIPS64) - /* For MIPS64, init FR bit to 1 if FPU unit is there and bit is writable. */ - if ((env->CP0_Config1 & (1 << CP0C1_FP)) && - (env->CP0_Status_rw_bitmask & (1 << CP0St_FR))) { - env->CP0_Status |= (1 << CP0St_FR); - } -# endif -#else - if (env->hflags & MIPS_HFLAG_BMASK) { - /* - * If the exception was raised from a delay slot, - * come back to the jump. - */ - env->CP0_ErrorEPC = (env->active_tc.PC - - (env->hflags & MIPS_HFLAG_B16 ? 2 : 4)); - } else { - env->CP0_ErrorEPC = env->active_tc.PC; - } - env->active_tc.PC = env->exception_base; - env->CP0_Random = env->tlb->nb_tlb - 1; - env->tlb->tlb_in_use = env->tlb->nb_tlb; - env->CP0_Wired = 0; - env->CP0_GlobalNumber = (cs->cpu_index & 0xFF) << CP0GN_VPId; - env->CP0_EBase = (cs->cpu_index & 0x3FF); - if (mips_um_ksegs_enabled()) { - env->CP0_EBase |= 0x40000000; - } else { - env->CP0_EBase |= (int32_t)0x80000000; - } - if (env->CP0_Config3 & (1 << CP0C3_CMGCR)) { - env->CP0_CMGCRBase = 0x1fbf8000 >> 4; - } - env->CP0_EntryHi_ASID_mask = (env->CP0_Config5 & (1 << CP0C5_MI)) ? - 0x0 : (env->CP0_Config4 & (1 << CP0C4_AE)) ? 0x3ff : 0xff; - env->CP0_Status = (1 << CP0St_BEV) | (1 << CP0St_ERL); - /* - * Vectored interrupts not implemented, timer on int 7, - * no performance counters. - */ - env->CP0_IntCtl = 0xe0000000; - { - int i; - - for (i = 0; i < 7; i++) { - env->CP0_WatchLo[i] = 0; - env->CP0_WatchHi[i] = 0x80000000; - } - env->CP0_WatchLo[7] = 0; - env->CP0_WatchHi[7] = 0; - } - /* Count register increments in debug mode, EJTAG version 1 */ - env->CP0_Debug = (1 << CP0DB_CNT) | (0x1 << CP0DB_VER); - - cpu_mips_store_count(env, 1); - - if (env->CP0_Config3 & (1 << CP0C3_MT)) { - int i; - - /* Only TC0 on VPE 0 starts as active. */ - for (i = 0; i < ARRAY_SIZE(env->tcs); i++) { - env->tcs[i].CP0_TCBind = cs->cpu_index << CP0TCBd_CurVPE; - env->tcs[i].CP0_TCHalt = 1; - } - env->active_tc.CP0_TCHalt = 1; - cs->halted = 1; - - if (cs->cpu_index == 0) { - /* VPE0 starts up enabled. */ - env->mvp->CP0_MVPControl |= (1 << CP0MVPCo_EVP); - env->CP0_VPEConf0 |= (1 << CP0VPEC0_MVP) | (1 << CP0VPEC0_VPA); - - /* TC0 starts up unhalted. */ - cs->halted = 0; - env->active_tc.CP0_TCHalt = 0; - env->tcs[0].CP0_TCHalt = 0; - /* With thread 0 active. */ - env->active_tc.CP0_TCStatus = (1 << CP0TCSt_A); - env->tcs[0].CP0_TCStatus = (1 << CP0TCSt_A); - } - } - - /* - * Configure default legacy segmentation control. We use this regardless of - * whether segmentation control is presented to the guest. - */ - /* KSeg3 (seg0 0xE0000000..0xFFFFFFFF) */ - env->CP0_SegCtl0 = (CP0SC_AM_MK << CP0SC_AM); - /* KSeg2 (seg1 0xC0000000..0xDFFFFFFF) */ - env->CP0_SegCtl0 |= ((CP0SC_AM_MSK << CP0SC_AM)) << 16; - /* KSeg1 (seg2 0xA0000000..0x9FFFFFFF) */ - env->CP0_SegCtl1 = (0 << CP0SC_PA) | (CP0SC_AM_UK << CP0SC_AM) | - (2 << CP0SC_C); - /* KSeg0 (seg3 0x80000000..0x9FFFFFFF) */ - env->CP0_SegCtl1 |= ((0 << CP0SC_PA) | (CP0SC_AM_UK << CP0SC_AM) | - (3 << CP0SC_C)) << 16; - /* USeg (seg4 0x40000000..0x7FFFFFFF) */ - env->CP0_SegCtl2 = (2 << CP0SC_PA) | (CP0SC_AM_MUSK << CP0SC_AM) | - (1 << CP0SC_EU) | (2 << CP0SC_C); - /* USeg (seg5 0x00000000..0x3FFFFFFF) */ - env->CP0_SegCtl2 |= ((0 << CP0SC_PA) | (CP0SC_AM_MUSK << CP0SC_AM) | - (1 << CP0SC_EU) | (2 << CP0SC_C)) << 16; - /* XKPhys (note, SegCtl2.XR = 0, so XAM won't be used) */ - env->CP0_SegCtl1 |= (CP0SC_AM_UK << CP0SC1_XAM); -#endif - if ((env->insn_flags & ISA_MIPS32R6) && - (env->active_fpu.fcr0 & (1 << FCR0_F64))) { - /* Status.FR = 0 mode in 64-bit FPU not allowed in R6 */ - env->CP0_Status |= (1 << CP0St_FR); - } - - if (env->insn_flags & ISA_MIPS32R6) { - /* PTW = 1 */ - env->CP0_PWSize = 0x40; - /* GDI = 12 */ - /* UDI = 12 */ - /* MDI = 12 */ - /* PRI = 12 */ - /* PTEI = 2 */ - env->CP0_PWField = 0x0C30C302; - } else { - /* GDI = 0 */ - /* UDI = 0 */ - /* MDI = 0 */ - /* PRI = 0 */ - /* PTEI = 2 */ - env->CP0_PWField = 0x02; - } - - if (env->CP0_Config3 & (1 << CP0C3_ISA) & (1 << (CP0C3_ISA + 1))) { - /* microMIPS on reset when Config3.ISA is 3 */ - env->hflags |= MIPS_HFLAG_M16; - } - - /* MSA */ - if (env->CP0_Config3 & (1 << CP0C3_MSAP)) { - msa_reset(env); - } - - compute_hflags(env); - restore_fp_status(env); - restore_pamask(env); - cs->exception_index = EXCP_NONE; - - if (semihosting_get_argc()) { - /* UHI interface can be used to obtain argc and argv */ - env->active_tc.gpr[4] = -1; - } -} - void restore_state_to_opc(CPUMIPSState *env, TranslationBlock *tb, target_ulong *data) { diff --git a/target/mips/translate_init.c.inc b/target/mips/translate_init.c.inc index ea85d5c6a7..f72fee3b40 100644 --- a/target/mips/translate_init.c.inc +++ b/target/mips/translate_init.c.inc @@ -832,7 +832,7 @@ const mips_def_t mips_defs[] = .mmu_type = MMU_TYPE_R4000, }, { - .name = "Loongson-3A4000", + .name = "Loongson-3A4000", /* GS464V-based */ .CP0_PRid = 0x14C000, /* 64KB I-cache and d-cache. 4 way with 32 bit cache line size. */ .CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR) | (0x2 << CP0C0_AT) | @@ -885,7 +885,7 @@ const mips_def_t mips_defs[] = .CP1_fcr31_rw_bitmask = 0xFF83FFFF, .SEGBITS = 48, .PABITS = 48, - .insn_flags = CPU_LOONGSON3A, + .insn_flags = CPU_LOONGSON3A | ASE_MSA, .mmu_type = MMU_TYPE_R4000, }, { @@ -989,10 +989,14 @@ static void fpu_init (CPUMIPSState *env, const mips_def_t *def) memcpy(&env->active_fpu, &env->fpus[0], sizeof(env->active_fpu)); } -static void mvp_init (CPUMIPSState *env, const mips_def_t *def) +static void mvp_init(CPUMIPSState *env) { env->mvp = g_malloc0(sizeof(CPUMIPSMVPContext)); + if (!ase_mt_available(env)) { + return; + } + /* MVPConf1 implemented, TLB sharable, no gating storage support, programmable cache partitioning implemented, number of allocatable and shareable TLB entries, MVP has allocatable TCs, 2 VPEs diff --git a/target/ppc/cpu-qom.h b/target/ppc/cpu-qom.h index 5fdb96f04d..63b9e8632c 100644 --- a/target/ppc/cpu-qom.h +++ b/target/ppc/cpu-qom.h @@ -74,6 +74,11 @@ enum powerpc_mmu_t { POWERPC_MMU_3_00 = POWERPC_MMU_64 | 0x00000005, }; +static inline bool mmu_is_64bit(powerpc_mmu_t mmu_model) +{ + return mmu_model & POWERPC_MMU_64; +} + /*****************************************************************************/ /* Exception model */ typedef enum powerpc_excp_t powerpc_excp_t; diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c index 74f987080f..85de7e6c90 100644 --- a/target/ppc/excp_helper.c +++ b/target/ppc/excp_helper.c @@ -266,7 +266,7 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) */ if (excp == POWERPC_EXCP_HV_EMU #if defined(TARGET_PPC64) - && !((env->mmu_model & POWERPC_MMU_64) && (env->msr_mask & MSR_HVB)) + && !(mmu_is_64bit(env->mmu_model) && (env->msr_mask & MSR_HVB)) #endif /* defined(TARGET_PPC64) */ ) { @@ -824,7 +824,7 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) vector = (uint32_t)vector; } } else { - if (!msr_isf && !(env->mmu_model & POWERPC_MMU_64)) { + if (!msr_isf && !mmu_is_64bit(env->mmu_model)) { vector = (uint32_t)vector; } else { new_msr |= (target_ulong)1 << MSR_SF; diff --git a/target/ppc/fpu_helper.c b/target/ppc/fpu_helper.c index 32a9a8a0f8..44315fca0b 100644 --- a/target/ppc/fpu_helper.c +++ b/target/ppc/fpu_helper.c @@ -2467,101 +2467,135 @@ void helper_xscmpexpqp(CPUPPCState *env, uint32_t opcode, do_float_check_status(env, GETPC()); } -#define VSX_SCALAR_CMP(op, ordered) \ -void helper_##op(CPUPPCState *env, uint32_t opcode, \ - ppc_vsr_t *xa, ppc_vsr_t *xb) \ -{ \ - uint32_t cc = 0; \ - bool vxsnan_flag = false, vxvc_flag = false; \ - \ - helper_reset_fpstatus(env); \ - \ - if (float64_is_signaling_nan(xa->VsrD(0), &env->fp_status) || \ - float64_is_signaling_nan(xb->VsrD(0), &env->fp_status)) { \ - vxsnan_flag = true; \ - cc = CRF_SO; \ - if (fpscr_ve == 0 && ordered) { \ - vxvc_flag = true; \ - } \ - } else if (float64_is_quiet_nan(xa->VsrD(0), &env->fp_status) || \ - float64_is_quiet_nan(xb->VsrD(0), &env->fp_status)) { \ - cc = CRF_SO; \ - if (ordered) { \ - vxvc_flag = true; \ - } \ - } \ - if (vxsnan_flag) { \ - float_invalid_op_vxsnan(env, GETPC()); \ - } \ - if (vxvc_flag) { \ - float_invalid_op_vxvc(env, 0, GETPC()); \ - } \ - \ - if (float64_lt(xa->VsrD(0), xb->VsrD(0), &env->fp_status)) { \ - cc |= CRF_LT; \ - } else if (!float64_le(xa->VsrD(0), xb->VsrD(0), &env->fp_status)) { \ - cc |= CRF_GT; \ - } else { \ - cc |= CRF_EQ; \ - } \ - \ - env->fpscr &= ~FP_FPCC; \ - env->fpscr |= cc << FPSCR_FPCC; \ - env->crf[BF(opcode)] = cc; \ - \ - do_float_check_status(env, GETPC()); \ -} - -VSX_SCALAR_CMP(xscmpodp, 1) -VSX_SCALAR_CMP(xscmpudp, 0) - -#define VSX_SCALAR_CMPQ(op, ordered) \ -void helper_##op(CPUPPCState *env, uint32_t opcode, \ - ppc_vsr_t *xa, ppc_vsr_t *xb) \ -{ \ - uint32_t cc = 0; \ - bool vxsnan_flag = false, vxvc_flag = false; \ - \ - helper_reset_fpstatus(env); \ - \ - if (float128_is_signaling_nan(xa->f128, &env->fp_status) || \ - float128_is_signaling_nan(xb->f128, &env->fp_status)) { \ - vxsnan_flag = true; \ - cc = CRF_SO; \ - if (fpscr_ve == 0 && ordered) { \ - vxvc_flag = true; \ - } \ - } else if (float128_is_quiet_nan(xa->f128, &env->fp_status) || \ - float128_is_quiet_nan(xb->f128, &env->fp_status)) { \ - cc = CRF_SO; \ - if (ordered) { \ - vxvc_flag = true; \ - } \ - } \ - if (vxsnan_flag) { \ - float_invalid_op_vxsnan(env, GETPC()); \ - } \ - if (vxvc_flag) { \ - float_invalid_op_vxvc(env, 0, GETPC()); \ - } \ - \ - if (float128_lt(xa->f128, xb->f128, &env->fp_status)) { \ - cc |= CRF_LT; \ - } else if (!float128_le(xa->f128, xb->f128, &env->fp_status)) { \ - cc |= CRF_GT; \ - } else { \ - cc |= CRF_EQ; \ - } \ - \ - env->fpscr &= ~FP_FPCC; \ - env->fpscr |= cc << FPSCR_FPCC; \ - env->crf[BF(opcode)] = cc; \ - \ - do_float_check_status(env, GETPC()); \ +static inline void do_scalar_cmp(CPUPPCState *env, ppc_vsr_t *xa, ppc_vsr_t *xb, + int crf_idx, bool ordered) +{ + uint32_t cc; + bool vxsnan_flag = false, vxvc_flag = false; + + helper_reset_fpstatus(env); + + switch (float64_compare(xa->VsrD(0), xb->VsrD(0), &env->fp_status)) { + case float_relation_less: + cc = CRF_LT; + break; + case float_relation_equal: + cc = CRF_EQ; + break; + case float_relation_greater: + cc = CRF_GT; + break; + case float_relation_unordered: + cc = CRF_SO; + + if (float64_is_signaling_nan(xa->VsrD(0), &env->fp_status) || + float64_is_signaling_nan(xb->VsrD(0), &env->fp_status)) { + vxsnan_flag = true; + if (fpscr_ve == 0 && ordered) { + vxvc_flag = true; + } + } else if (float64_is_quiet_nan(xa->VsrD(0), &env->fp_status) || + float64_is_quiet_nan(xb->VsrD(0), &env->fp_status)) { + if (ordered) { + vxvc_flag = true; + } + } + + break; + default: + g_assert_not_reached(); + } + + env->fpscr &= ~FP_FPCC; + env->fpscr |= cc << FPSCR_FPCC; + env->crf[crf_idx] = cc; + + if (vxsnan_flag) { + float_invalid_op_vxsnan(env, GETPC()); + } + if (vxvc_flag) { + float_invalid_op_vxvc(env, 0, GETPC()); + } + + do_float_check_status(env, GETPC()); +} + +void helper_xscmpodp(CPUPPCState *env, uint32_t opcode, ppc_vsr_t *xa, + ppc_vsr_t *xb) +{ + do_scalar_cmp(env, xa, xb, BF(opcode), true); +} + +void helper_xscmpudp(CPUPPCState *env, uint32_t opcode, ppc_vsr_t *xa, + ppc_vsr_t *xb) +{ + do_scalar_cmp(env, xa, xb, BF(opcode), false); +} + +static inline void do_scalar_cmpq(CPUPPCState *env, ppc_vsr_t *xa, + ppc_vsr_t *xb, int crf_idx, bool ordered) +{ + uint32_t cc; + bool vxsnan_flag = false, vxvc_flag = false; + + helper_reset_fpstatus(env); + + switch (float128_compare(xa->f128, xb->f128, &env->fp_status)) { + case float_relation_less: + cc = CRF_LT; + break; + case float_relation_equal: + cc = CRF_EQ; + break; + case float_relation_greater: + cc = CRF_GT; + break; + case float_relation_unordered: + cc = CRF_SO; + + if (float128_is_signaling_nan(xa->f128, &env->fp_status) || + float128_is_signaling_nan(xb->f128, &env->fp_status)) { + vxsnan_flag = true; + if (fpscr_ve == 0 && ordered) { + vxvc_flag = true; + } + } else if (float128_is_quiet_nan(xa->f128, &env->fp_status) || + float128_is_quiet_nan(xb->f128, &env->fp_status)) { + if (ordered) { + vxvc_flag = true; + } + } + + break; + default: + g_assert_not_reached(); + } + + env->fpscr &= ~FP_FPCC; + env->fpscr |= cc << FPSCR_FPCC; + env->crf[crf_idx] = cc; + + if (vxsnan_flag) { + float_invalid_op_vxsnan(env, GETPC()); + } + if (vxvc_flag) { + float_invalid_op_vxvc(env, 0, GETPC()); + } + + do_float_check_status(env, GETPC()); } -VSX_SCALAR_CMPQ(xscmpoqp, 1) -VSX_SCALAR_CMPQ(xscmpuqp, 0) +void helper_xscmpoqp(CPUPPCState *env, uint32_t opcode, ppc_vsr_t *xa, + ppc_vsr_t *xb) +{ + do_scalar_cmpq(env, xa, xb, BF(opcode), true); +} + +void helper_xscmpuqp(CPUPPCState *env, uint32_t opcode, ppc_vsr_t *xa, + ppc_vsr_t *xb) +{ + do_scalar_cmpq(env, xa, xb, BF(opcode), false); +} /* * VSX_MAX_MIN - VSX floating point maximum/minimum diff --git a/target/ppc/machine.c b/target/ppc/machine.c index c38e7b1268..d9d911b9b1 100644 --- a/target/ppc/machine.c +++ b/target/ppc/machine.c @@ -550,7 +550,7 @@ static bool sr_needed(void *opaque) #ifdef TARGET_PPC64 PowerPCCPU *cpu = opaque; - return !(cpu->env.mmu_model & POWERPC_MMU_64); + return !mmu_is_64bit(cpu->env.mmu_model); #else return true; #endif @@ -606,7 +606,7 @@ static bool slb_needed(void *opaque) PowerPCCPU *cpu = opaque; /* We don't support any of the old segment table based 64-bit CPUs */ - return cpu->env.mmu_model & POWERPC_MMU_64; + return mmu_is_64bit(cpu->env.mmu_model); } static int slb_post_load(void *opaque, int version_id) diff --git a/target/ppc/mmu-hash64.c b/target/ppc/mmu-hash64.c index 1b1248fc90..0fabc10302 100644 --- a/target/ppc/mmu-hash64.c +++ b/target/ppc/mmu-hash64.c @@ -1140,7 +1140,7 @@ void ppc_hash64_init(PowerPCCPU *cpu) PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); if (!pcc->hash64_opts) { - assert(!(env->mmu_model & POWERPC_MMU_64)); + assert(!mmu_is_64bit(env->mmu_model)); return; } diff --git a/target/ppc/mmu_helper.c b/target/ppc/mmu_helper.c index 064d2e8d13..ca88658cba 100644 --- a/target/ppc/mmu_helper.c +++ b/target/ppc/mmu_helper.c @@ -1349,11 +1349,12 @@ void dump_mmu(CPUPPCState *env) break; case POWERPC_MMU_3_00: if (ppc64_v3_radix(env_archcpu(env))) { - /* TODO - Unsupported */ + qemu_log_mask(LOG_UNIMP, "%s: the PPC64 MMU is unsupported\n", + __func__); } else { dump_slb(env_archcpu(env)); - break; } + break; #endif default: qemu_log_mask(LOG_UNIMP, "%s: unimplemented\n", __func__); @@ -2001,7 +2002,7 @@ void helper_store_601_batl(CPUPPCState *env, uint32_t nr, target_ulong value) void ppc_tlb_invalidate_all(CPUPPCState *env) { #if defined(TARGET_PPC64) - if (env->mmu_model & POWERPC_MMU_64) { + if (mmu_is_64bit(env->mmu_model)) { env->tlb_need_flush = 0; tlb_flush(env_cpu(env)); } else @@ -2045,7 +2046,7 @@ void ppc_tlb_invalidate_one(CPUPPCState *env, target_ulong addr) #if !defined(FLUSH_ALL_TLBS) addr &= TARGET_PAGE_MASK; #if defined(TARGET_PPC64) - if (env->mmu_model & POWERPC_MMU_64) { + if (mmu_is_64bit(env->mmu_model)) { /* tlbie invalidate TLBs for all segments */ /* * XXX: given the fact that there are too many segments to invalidate, @@ -2090,7 +2091,7 @@ void ppc_store_sdr1(CPUPPCState *env, target_ulong value) qemu_log_mask(CPU_LOG_MMU, "%s: " TARGET_FMT_lx "\n", __func__, value); assert(!cpu->vhyp); #if defined(TARGET_PPC64) - if (env->mmu_model & POWERPC_MMU_64) { + if (mmu_is_64bit(env->mmu_model)) { target_ulong sdr_mask = SDR_64_HTABORG | SDR_64_HTABSIZE; target_ulong htabsize = value & SDR_64_HTABSIZE; @@ -2143,7 +2144,7 @@ void ppc_store_ptcr(CPUPPCState *env, target_ulong value) target_ulong helper_load_sr(CPUPPCState *env, target_ulong sr_num) { #if defined(TARGET_PPC64) - if (env->mmu_model & POWERPC_MMU_64) { + if (mmu_is_64bit(env->mmu_model)) { /* XXX */ return 0; } @@ -2157,7 +2158,7 @@ void helper_store_sr(CPUPPCState *env, target_ulong srnum, target_ulong value) "%s: reg=%d " TARGET_FMT_lx " " TARGET_FMT_lx "\n", __func__, (int)srnum, value, env->sr[srnum]); #if defined(TARGET_PPC64) - if (env->mmu_model & POWERPC_MMU_64) { + if (mmu_is_64bit(env->mmu_model)) { PowerPCCPU *cpu = env_archcpu(env); uint64_t esid, vsid; diff --git a/target/ppc/translate.c b/target/ppc/translate.c index 54cac0e6a7..0984ce637b 100644 --- a/target/ppc/translate.c +++ b/target/ppc/translate.c @@ -7892,7 +7892,7 @@ static void ppc_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) ctx->insns_flags = env->insns_flags; ctx->insns_flags2 = env->insns_flags2; ctx->access_type = -1; - ctx->need_access_type = !(env->mmu_model & POWERPC_MMU_64B); + ctx->need_access_type = !mmu_is_64bit(env->mmu_model); ctx->le_mode = !!(env->hflags & (1 << MSR_LE)); ctx->default_tcg_memop_mask = ctx->le_mode ? MO_LE : MO_BE; ctx->flags = env->flags; @@ -7902,7 +7902,7 @@ static void ppc_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) #endif ctx->lazy_tlb_flush = env->mmu_model == POWERPC_MMU_32B || env->mmu_model == POWERPC_MMU_601 - || (env->mmu_model & POWERPC_MMU_64B); + || env->mmu_model & POWERPC_MMU_64; ctx->fpu_enabled = !!msr_fp; if ((env->flags & POWERPC_FLAG_SPE) && msr_spe) { diff --git a/target/ppc/translate/vsx-impl.c.inc b/target/ppc/translate/vsx-impl.c.inc index 075f063e98..b817d31260 100644 --- a/target/ppc/translate/vsx-impl.c.inc +++ b/target/ppc/translate/vsx-impl.c.inc @@ -75,29 +75,6 @@ static void gen_lxvd2x(DisasContext *ctx) tcg_temp_free_i64(t0); } -static void gen_lxvdsx(DisasContext *ctx) -{ - TCGv EA; - TCGv_i64 t0; - TCGv_i64 t1; - if (unlikely(!ctx->vsx_enabled)) { - gen_exception(ctx, POWERPC_EXCP_VSXU); - return; - } - t0 = tcg_temp_new_i64(); - t1 = tcg_temp_new_i64(); - gen_set_access_type(ctx, ACCESS_INT); - EA = tcg_temp_new(); - gen_addr_reg_index(ctx, EA); - gen_qemu_ld64_i64(ctx, t0, EA); - set_cpu_vsrh(xT(ctx->opcode), t0); - tcg_gen_mov_i64(t1, t0); - set_cpu_vsrl(xT(ctx->opcode), t1); - tcg_temp_free(EA); - tcg_temp_free_i64(t0); - tcg_temp_free_i64(t1); -} - static void gen_lxvw4x(DisasContext *ctx) { TCGv EA; @@ -169,6 +146,29 @@ static void gen_lxvwsx(DisasContext *ctx) tcg_temp_free_i32(data); } +static void gen_lxvdsx(DisasContext *ctx) +{ + TCGv EA; + TCGv_i64 data; + + if (unlikely(!ctx->vsx_enabled)) { + gen_exception(ctx, POWERPC_EXCP_VSXU); + return; + } + + gen_set_access_type(ctx, ACCESS_INT); + EA = tcg_temp_new(); + + gen_addr_reg_index(ctx, EA); + + data = tcg_temp_new_i64(); + tcg_gen_qemu_ld_i64(data, EA, ctx->mem_idx, MO_TEQ); + tcg_gen_gvec_dup_i64(MO_Q, vsr_full_offset(xT(ctx->opcode)), 16, 16, data); + + tcg_temp_free(EA); + tcg_temp_free_i64(data); +} + static void gen_bswap16x8(TCGv_i64 outh, TCGv_i64 outl, TCGv_i64 inh, TCGv_i64 inl) { diff --git a/target/ppc/translate_init.c.inc b/target/ppc/translate_init.c.inc index 78cc8f043b..a4d0038828 100644 --- a/target/ppc/translate_init.c.inc +++ b/target/ppc/translate_init.c.inc @@ -10470,63 +10470,6 @@ static ObjectClass *ppc_cpu_class_by_name(const char *name) return oc; } -static void ppc_cpu_parse_featurestr(const char *type, char *features, - Error **errp) -{ - Object *machine = qdev_get_machine(); - const PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(object_class_by_name(type)); - - if (!features) { - return; - } - - if (object_property_find(machine, "max-cpu-compat")) { - int i; - char **inpieces; - char *s = features; - Error *local_err = NULL; - char *compat_str = NULL; - - /* - * Backwards compatibility hack: - * - * CPUs had a "compat=" property which didn't make sense for - * anything except pseries. It was replaced by "max-cpu-compat" - * machine option. This supports old command lines like - * -cpu POWER8,compat=power7 - * By stripping the compat option and applying it to the machine - * before passing it on to the cpu level parser. - */ - inpieces = g_strsplit(features, ",", 0); - *s = '\0'; - for (i = 0; inpieces[i]; i++) { - if (g_str_has_prefix(inpieces[i], "compat=")) { - warn_report_once("CPU 'compat' property is deprecated; " - "use max-cpu-compat machine property instead"); - compat_str = inpieces[i]; - continue; - } - if ((i != 0) && (s != features)) { - s = g_stpcpy(s, ","); - } - s = g_stpcpy(s, inpieces[i]); - } - - if (compat_str) { - char *v = compat_str + strlen("compat="); - object_property_set_str(machine, "max-cpu-compat", v, &local_err); - } - g_strfreev(inpieces); - if (local_err) { - error_propagate(errp, local_err); - return; - } - } - - /* do property processing with generic handler */ - pcc->parent_parse_features(type, features, errp); -} - PowerPCCPUClass *ppc_cpu_get_family_class(PowerPCCPUClass *pcc) { ObjectClass *oc = OBJECT_CLASS(pcc); @@ -10728,7 +10671,7 @@ static void ppc_cpu_reset(DeviceState *dev) #endif #if defined(TARGET_PPC64) - if (env->mmu_model & POWERPC_MMU_64) { + if (mmu_is_64bit(env->mmu_model)) { msr |= (1ULL << MSR_SF); } #endif @@ -10905,8 +10848,6 @@ static void ppc_cpu_class_init(ObjectClass *oc, void *data) device_class_set_parent_reset(dc, ppc_cpu_reset, &pcc->parent_reset); cc->class_by_name = ppc_cpu_class_by_name; - pcc->parent_parse_features = cc->parse_features; - cc->parse_features = ppc_cpu_parse_featurestr; cc->has_work = ppc_cpu_has_work; cc->do_interrupt = ppc_cpu_do_interrupt; cc->cpu_exec_interrupt = ppc_cpu_exec_interrupt; |