aboutsummaryrefslogtreecommitdiff
path: root/target
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2017-09-21 14:40:30 +0100
committerPeter Maydell <peter.maydell@linaro.org>2017-09-21 14:40:32 +0100
commit9ee660e7c138595224b65ddc1c5712549f0a278c (patch)
treefc91b907a3befd431541637c407b77142a829354 /target
parentff5667ed53c544c4dc88dcd7cb23cc509c9a55e0 (diff)
parent2a2be359c4335607c7f746cf27c412c08ab89aff (diff)
Merge remote-tracking branch 'remotes/yongbok/tags/mips-20170921' into staging
MIPS patches 2017-09-21 Changes: QOMify MIPS cpu Improve macro parenthesization # gpg: Signature made Thu 21 Sep 2017 13:50:37 BST # gpg: using RSA key 0x2238EB86D5F797C2 # gpg: Good signature from "Yongbok Kim <yongbok.kim@imgtec.com>" # gpg: WARNING: This key is not certified with sufficiently trusted signatures! # gpg: It is not certain that the signature belongs to the owner. # Primary key fingerprint: 8600 4CF5 3415 A5D9 4CFA 2B5C 2238 EB86 D5F7 97C2 * remotes/yongbok/tags/mips-20170921: mips: Improve macro parenthesization mips: replace cpu_mips_init() with cpu_generic_init() mips: MIPSCPU model subclasses mips: call cpu_mips_realize_env() from mips_cpu_realizefn() mips: split cpu_mips_realize_env() out of cpu_mips_init() mips: introduce internal.h and cleanup cpu.h mips: move hw/mips/cputimer.c to target/mips/ Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'target')
-rw-r--r--target/mips/Makefile.objs2
-rw-r--r--target/mips/cp0_timer.c165
-rw-r--r--target/mips/cpu-qom.h1
-rw-r--r--target/mips/cpu.c54
-rw-r--r--target/mips/cpu.h357
-rw-r--r--target/mips/dsp_helper.c56
-rw-r--r--target/mips/gdbstub.c1
-rw-r--r--target/mips/helper.c1
-rw-r--r--target/mips/internal.h422
-rw-r--r--target/mips/kvm.c1
-rw-r--r--target/mips/machine.c1
-rw-r--r--target/mips/msa_helper.c1
-rw-r--r--target/mips/op_helper.c1
-rw-r--r--target/mips/translate.c23
-rw-r--r--target/mips/translate_init.c58
15 files changed, 685 insertions, 459 deletions
diff --git a/target/mips/Makefile.objs b/target/mips/Makefile.objs
index bc5ed8511f..651f36f517 100644
--- a/target/mips/Makefile.objs
+++ b/target/mips/Makefile.objs
@@ -1,4 +1,4 @@
obj-y += translate.o dsp_helper.o op_helper.o lmi_helper.o helper.o cpu.o
obj-y += gdbstub.o msa_helper.o mips-semi.o
-obj-$(CONFIG_SOFTMMU) += machine.o
+obj-$(CONFIG_SOFTMMU) += machine.o cp0_timer.o
obj-$(CONFIG_KVM) += kvm.o
diff --git a/target/mips/cp0_timer.c b/target/mips/cp0_timer.c
new file mode 100644
index 0000000000..f4716395df
--- /dev/null
+++ b/target/mips/cp0_timer.c
@@ -0,0 +1,165 @@
+/*
+ * QEMU MIPS timer 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 "hw/mips/cpudevs.h"
+#include "qemu/timer.h"
+#include "sysemu/kvm.h"
+#include "internal.h"
+
+#define TIMER_PERIOD 10 /* 10 ns period for 100 Mhz frequency */
+
+/* XXX: do not use a global */
+uint32_t cpu_mips_get_random (CPUMIPSState *env)
+{
+ static uint32_t seed = 1;
+ static uint32_t prev_idx = 0;
+ uint32_t idx;
+ uint32_t nb_rand_tlb = env->tlb->nb_tlb - env->CP0_Wired;
+
+ if (nb_rand_tlb == 1) {
+ return env->tlb->nb_tlb - 1;
+ }
+
+ /* Don't return same value twice, so get another value */
+ do {
+ /* Use a simple algorithm of Linear Congruential Generator
+ * from ISO/IEC 9899 standard. */
+ seed = 1103515245 * seed + 12345;
+ idx = (seed >> 16) % nb_rand_tlb + env->CP0_Wired;
+ } while (idx == prev_idx);
+ prev_idx = idx;
+ return idx;
+}
+
+/* MIPS R4K timer */
+static void cpu_mips_timer_update(CPUMIPSState *env)
+{
+ uint64_t now, next;
+ uint32_t wait;
+
+ now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+ wait = env->CP0_Compare - env->CP0_Count - (uint32_t)(now / TIMER_PERIOD);
+ next = now + (uint64_t)wait * TIMER_PERIOD;
+ timer_mod(env->timer, next);
+}
+
+/* Expire the timer. */
+static void cpu_mips_timer_expire(CPUMIPSState *env)
+{
+ cpu_mips_timer_update(env);
+ if (env->insn_flags & ISA_MIPS32R2) {
+ env->CP0_Cause |= 1 << CP0Ca_TI;
+ }
+ qemu_irq_raise(env->irq[(env->CP0_IntCtl >> CP0IntCtl_IPTI) & 0x7]);
+}
+
+uint32_t cpu_mips_get_count (CPUMIPSState *env)
+{
+ if (env->CP0_Cause & (1 << CP0Ca_DC)) {
+ return env->CP0_Count;
+ } else {
+ uint64_t now;
+
+ now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+ if (timer_pending(env->timer)
+ && timer_expired(env->timer, now)) {
+ /* The timer has already expired. */
+ cpu_mips_timer_expire(env);
+ }
+
+ return env->CP0_Count + (uint32_t)(now / TIMER_PERIOD);
+ }
+}
+
+void cpu_mips_store_count (CPUMIPSState *env, uint32_t count)
+{
+ /*
+ * This gets called from cpu_state_reset(), potentially before timer init.
+ * So env->timer may be NULL, which is also the case with KVM enabled so
+ * treat timer as disabled in that case.
+ */
+ if (env->CP0_Cause & (1 << CP0Ca_DC) || !env->timer)
+ env->CP0_Count = count;
+ else {
+ /* Store new count register */
+ env->CP0_Count = count -
+ (uint32_t)(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / TIMER_PERIOD);
+ /* Update timer timer */
+ cpu_mips_timer_update(env);
+ }
+}
+
+void cpu_mips_store_compare (CPUMIPSState *env, uint32_t value)
+{
+ env->CP0_Compare = value;
+ if (!(env->CP0_Cause & (1 << CP0Ca_DC)))
+ cpu_mips_timer_update(env);
+ if (env->insn_flags & ISA_MIPS32R2)
+ env->CP0_Cause &= ~(1 << CP0Ca_TI);
+ qemu_irq_lower(env->irq[(env->CP0_IntCtl >> CP0IntCtl_IPTI) & 0x7]);
+}
+
+void cpu_mips_start_count(CPUMIPSState *env)
+{
+ cpu_mips_store_count(env, env->CP0_Count);
+}
+
+void cpu_mips_stop_count(CPUMIPSState *env)
+{
+ /* Store the current value */
+ env->CP0_Count += (uint32_t)(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) /
+ TIMER_PERIOD);
+}
+
+static void mips_timer_cb (void *opaque)
+{
+ CPUMIPSState *env;
+
+ env = opaque;
+#if 0
+ qemu_log("%s\n", __func__);
+#endif
+
+ if (env->CP0_Cause & (1 << CP0Ca_DC))
+ return;
+
+ /* ??? This callback should occur when the counter is exactly equal to
+ the comparator value. Offset the count by one to avoid immediately
+ retriggering the callback before any virtual time has passed. */
+ env->CP0_Count++;
+ cpu_mips_timer_expire(env);
+ env->CP0_Count--;
+}
+
+void cpu_mips_clock_init (MIPSCPU *cpu)
+{
+ CPUMIPSState *env = &cpu->env;
+
+ /*
+ * If we're in KVM mode, don't create the periodic timer, that is handled in
+ * kernel.
+ */
+ if (!kvm_enabled()) {
+ env->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &mips_timer_cb, env);
+ }
+}
diff --git a/target/mips/cpu-qom.h b/target/mips/cpu-qom.h
index 3f5bf23823..ee58606afe 100644
--- a/target/mips/cpu-qom.h
+++ b/target/mips/cpu-qom.h
@@ -49,6 +49,7 @@ typedef struct MIPSCPUClass {
DeviceRealize parent_realize;
void (*parent_reset)(CPUState *cpu);
+ const struct mips_def_t *cpu_def;
} MIPSCPUClass;
typedef struct MIPSCPU MIPSCPU;
diff --git a/target/mips/cpu.c b/target/mips/cpu.c
index 1bb66b7a5a..1a9a3ed94d 100644
--- a/target/mips/cpu.c
+++ b/target/mips/cpu.c
@@ -21,6 +21,7 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "cpu.h"
+#include "internal.h"
#include "kvm_mips.h"
#include "qemu-common.h"
#include "sysemu/kvm.h"
@@ -122,6 +123,7 @@ static void mips_cpu_disas_set_info(CPUState *s, disassemble_info *info) {
static void mips_cpu_realizefn(DeviceState *dev, Error **errp)
{
CPUState *cs = CPU(dev);
+ MIPSCPU *cpu = MIPS_CPU(dev);
MIPSCPUClass *mcc = MIPS_CPU_GET_CLASS(dev);
Error *local_err = NULL;
@@ -131,6 +133,8 @@ static void mips_cpu_realizefn(DeviceState *dev, Error **errp)
return;
}
+ cpu_mips_realize_env(&cpu->env);
+
cpu_reset(cs);
qemu_init_vcpu(cs);
@@ -142,14 +146,36 @@ static void mips_cpu_initfn(Object *obj)
CPUState *cs = CPU(obj);
MIPSCPU *cpu = MIPS_CPU(obj);
CPUMIPSState *env = &cpu->env;
+ MIPSCPUClass *mcc = MIPS_CPU_GET_CLASS(obj);
cs->env_ptr = env;
+ env->cpu_model = mcc->cpu_def;
if (tcg_enabled()) {
mips_tcg_init();
}
}
+static char *mips_cpu_type_name(const char *cpu_model)
+{
+ return g_strdup_printf("%s-" TYPE_MIPS_CPU, cpu_model);
+}
+
+static ObjectClass *mips_cpu_class_by_name(const char *cpu_model)
+{
+ ObjectClass *oc;
+ char *typename;
+
+ if (cpu_model == NULL) {
+ return NULL;
+ }
+
+ typename = mips_cpu_type_name(cpu_model);
+ oc = object_class_by_name(typename);
+ g_free(typename);
+ return oc;
+}
+
static void mips_cpu_class_init(ObjectClass *c, void *data)
{
MIPSCPUClass *mcc = MIPS_CPU_CLASS(c);
@@ -162,6 +188,7 @@ static void mips_cpu_class_init(ObjectClass *c, void *data)
mcc->parent_reset = cc->reset;
cc->reset = mips_cpu_reset;
+ cc->class_by_name = mips_cpu_class_by_name;
cc->has_work = mips_cpu_has_work;
cc->do_interrupt = mips_cpu_do_interrupt;
cc->cpu_exec_interrupt = mips_cpu_exec_interrupt;
@@ -189,14 +216,39 @@ static const TypeInfo mips_cpu_type_info = {
.parent = TYPE_CPU,
.instance_size = sizeof(MIPSCPU),
.instance_init = mips_cpu_initfn,
- .abstract = false,
+ .abstract = true,
.class_size = sizeof(MIPSCPUClass),
.class_init = mips_cpu_class_init,
};
+static void mips_cpu_cpudef_class_init(ObjectClass *oc, void *data)
+{
+ MIPSCPUClass *mcc = MIPS_CPU_CLASS(oc);
+ mcc->cpu_def = data;
+}
+
+static void mips_register_cpudef_type(const struct mips_def_t *def)
+{
+ char *typename = mips_cpu_type_name(def->name);
+ TypeInfo ti = {
+ .name = typename,
+ .parent = TYPE_MIPS_CPU,
+ .class_init = mips_cpu_cpudef_class_init,
+ .class_data = (void *)def,
+ };
+
+ type_register(&ti);
+ g_free(typename);
+}
+
static void mips_cpu_register_types(void)
{
+ int i;
+
type_register_static(&mips_cpu_type_info);
+ for (i = 0; i < mips_defs_number; i++) {
+ mips_register_cpudef_type(&mips_defs[i]);
+ }
}
type_init(mips_cpu_register_types)
diff --git a/target/mips/cpu.h b/target/mips/cpu.h
index 74f6a5b098..66265e4eb6 100644
--- a/target/mips/cpu.h
+++ b/target/mips/cpu.h
@@ -1,8 +1,6 @@
#ifndef MIPS_CPU_H
#define MIPS_CPU_H
-//#define DEBUG_OP
-
#define ALIGNED_ONLY
#define CPUArchState struct CPUMIPSState
@@ -15,56 +13,11 @@
struct CPUMIPSState;
-typedef struct r4k_tlb_t r4k_tlb_t;
-struct r4k_tlb_t {
- target_ulong VPN;
- uint32_t PageMask;
- uint16_t ASID;
- unsigned int G:1;
- unsigned int C0:3;
- unsigned int C1:3;
- unsigned int V0:1;
- unsigned int V1:1;
- unsigned int D0:1;
- unsigned int D1:1;
- unsigned int XI0:1;
- unsigned int XI1:1;
- unsigned int RI0:1;
- unsigned int RI1:1;
- unsigned int EHINV:1;
- uint64_t PFN[2];
-};
-
-#if !defined(CONFIG_USER_ONLY)
typedef struct CPUMIPSTLBContext CPUMIPSTLBContext;
-struct CPUMIPSTLBContext {
- uint32_t nb_tlb;
- uint32_t tlb_in_use;
- int (*map_address) (struct CPUMIPSState *env, hwaddr *physical, int *prot, target_ulong address, int rw, int access_type);
- void (*helper_tlbwi)(struct CPUMIPSState *env);
- void (*helper_tlbwr)(struct CPUMIPSState *env);
- void (*helper_tlbp)(struct CPUMIPSState *env);
- void (*helper_tlbr)(struct CPUMIPSState *env);
- void (*helper_tlbinv)(struct CPUMIPSState *env);
- void (*helper_tlbinvf)(struct CPUMIPSState *env);
- union {
- struct {
- r4k_tlb_t tlb[MIPS_TLB_MAX];
- } r4k;
- } mmu;
-};
-#endif
/* MSA Context */
#define MSA_WRLEN (128)
-enum CPUMIPSMSADataFormat {
- DF_BYTE = 0,
- DF_HALF,
- DF_WORD,
- DF_DOUBLE
-};
-
typedef union wr_t wr_t;
union wr_t {
int8_t b[MSA_WRLEN/8];
@@ -682,40 +635,6 @@ static inline MIPSCPU *mips_env_get_cpu(CPUMIPSState *env)
#define ENV_OFFSET offsetof(MIPSCPU, env)
-#ifndef CONFIG_USER_ONLY
-extern const struct VMStateDescription vmstate_mips_cpu;
-#endif
-
-void mips_cpu_do_interrupt(CPUState *cpu);
-bool mips_cpu_exec_interrupt(CPUState *cpu, int int_req);
-void mips_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf,
- int flags);
-hwaddr mips_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
-int mips_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
-int mips_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
-void mips_cpu_do_unaligned_access(CPUState *cpu, vaddr addr,
- MMUAccessType access_type,
- int mmu_idx, uintptr_t retaddr);
-
-#if !defined(CONFIG_USER_ONLY)
-int no_mmu_map_address (CPUMIPSState *env, hwaddr *physical, int *prot,
- target_ulong address, int rw, int access_type);
-int fixed_mmu_map_address (CPUMIPSState *env, hwaddr *physical, int *prot,
- target_ulong address, int rw, int access_type);
-int r4k_map_address (CPUMIPSState *env, hwaddr *physical, int *prot,
- target_ulong address, int rw, int access_type);
-void r4k_helper_tlbwi(CPUMIPSState *env);
-void r4k_helper_tlbwr(CPUMIPSState *env);
-void r4k_helper_tlbp(CPUMIPSState *env);
-void r4k_helper_tlbr(CPUMIPSState *env);
-void r4k_helper_tlbinv(CPUMIPSState *env);
-void r4k_helper_tlbinvf(CPUMIPSState *env);
-
-void mips_cpu_unassigned_access(CPUState *cpu, hwaddr addr,
- bool is_write, bool is_exec, int unused,
- unsigned size);
-#endif
-
void mips_cpu_list (FILE *f, fprintf_function cpu_fprintf);
#define cpu_signal_handler cpu_mips_signal_handler
@@ -746,42 +665,6 @@ static inline int cpu_mmu_index (CPUMIPSState *env, bool ifetch)
return hflags_mmu_index(env->hflags);
}
-static inline bool cpu_mips_hw_interrupts_enabled(CPUMIPSState *env)
-{
- return (env->CP0_Status & (1 << CP0St_IE)) &&
- !(env->CP0_Status & (1 << CP0St_EXL)) &&
- !(env->CP0_Status & (1 << CP0St_ERL)) &&
- !(env->hflags & MIPS_HFLAG_DM) &&
- /* Note that the TCStatus IXMT field is initialized to zero,
- and only MT capable cores can set it to one. So we don't
- need to check for MT capabilities here. */
- !(env->active_tc.CP0_TCStatus & (1 << CP0TCSt_IXMT));
-}
-
-/* Check if there is pending and not masked out interrupt */
-static inline bool cpu_mips_hw_interrupts_pending(CPUMIPSState *env)
-{
- int32_t pending;
- int32_t status;
- bool r;
-
- pending = env->CP0_Cause & CP0Ca_IP_mask;
- status = env->CP0_Status & CP0Ca_IP_mask;
-
- if (env->CP0_Config3 & (1 << CP0C3_VEIC)) {
- /* A MIPS configured with a vectorizing external interrupt controller
- will feed a vector into the Cause pending lines. The core treats
- the status lines as a vector level, not as indiviual masks. */
- r = pending > status;
- } else {
- /* A MIPS configured with compatibility or VInt (Vectored Interrupts)
- treats the pending lines as individual interrupt lines, the status
- lines are individual masks. */
- r = (pending & status) != 0;
- }
- return r;
-}
-
#include "exec/cpu-all.h"
/* Memory access type :
@@ -847,100 +730,32 @@ enum {
#define EXCP_SC 0x100
/*
- * This is an interrnally generated WAKE request line.
+ * This is an internally generated WAKE request line.
* It is driven by the CPU itself. Raised when the MT
* block wants to wake a VPE from an inactive state and
* cleared when VPE goes from active to inactive.
*/
#define CPU_INTERRUPT_WAKE CPU_INTERRUPT_TGT_INT_0
-void mips_tcg_init(void);
-MIPSCPU *cpu_mips_init(const char *cpu_model);
int cpu_mips_signal_handler(int host_signum, void *pinfo, void *puc);
-#define cpu_init(cpu_model) CPU(cpu_mips_init(cpu_model))
+#define cpu_init(cpu_model) cpu_generic_init(TYPE_MIPS_CPU, cpu_model)
bool cpu_supports_cps_smp(const char *cpu_model);
bool cpu_supports_isa(const char *cpu_model, unsigned int isa);
void cpu_set_exception_base(int vp_index, target_ulong address);
-/* TODO QOM'ify CPU reset and remove */
-void cpu_state_reset(CPUMIPSState *s);
-
-/* mips_timer.c */
-uint32_t cpu_mips_get_random (CPUMIPSState *env);
-uint32_t cpu_mips_get_count (CPUMIPSState *env);
-void cpu_mips_store_count (CPUMIPSState *env, uint32_t value);
-void cpu_mips_store_compare (CPUMIPSState *env, uint32_t value);
-void cpu_mips_start_count(CPUMIPSState *env);
-void cpu_mips_stop_count(CPUMIPSState *env);
-
/* mips_int.c */
void cpu_mips_soft_irq(CPUMIPSState *env, int irq, int level);
/* helper.c */
-int mips_cpu_handle_mmu_fault(CPUState *cpu, vaddr address, int rw,
- int mmu_idx);
-
-/* op_helper.c */
-uint32_t float_class_s(uint32_t arg, float_status *fst);
-uint64_t float_class_d(uint64_t arg, float_status *fst);
-
-#if !defined(CONFIG_USER_ONLY)
-void r4k_invalidate_tlb (CPUMIPSState *env, int idx, int use_extra);
-hwaddr cpu_mips_translate_address (CPUMIPSState *env, target_ulong address,
- int rw);
-#endif
target_ulong exception_resume_pc (CPUMIPSState *env);
-/* op_helper.c */
-extern unsigned int ieee_rm[];
-int ieee_ex_to_mips(int xcpt);
-
-static inline void restore_rounding_mode(CPUMIPSState *env)
-{
- set_float_rounding_mode(ieee_rm[env->active_fpu.fcr31 & 3],
- &env->active_fpu.fp_status);
-}
-
-static inline void restore_flush_mode(CPUMIPSState *env)
-{
- set_flush_to_zero((env->active_fpu.fcr31 & (1 << FCR31_FS)) != 0,
- &env->active_fpu.fp_status);
-}
-
static inline void restore_snan_bit_mode(CPUMIPSState *env)
{
set_snan_bit_is_one((env->active_fpu.fcr31 & (1 << FCR31_NAN2008)) == 0,
&env->active_fpu.fp_status);
}
-static inline void restore_fp_status(CPUMIPSState *env)
-{
- restore_rounding_mode(env);
- restore_flush_mode(env);
- restore_snan_bit_mode(env);
-}
-
-static inline void restore_msa_fp_status(CPUMIPSState *env)
-{
- float_status *status = &env->active_tc.msa_fp_status;
- int rounding_mode = (env->active_tc.msacsr & MSACSR_RM_MASK) >> MSACSR_RM;
- bool flush_to_zero = (env->active_tc.msacsr & MSACSR_FS_MASK) != 0;
-
- set_float_rounding_mode(ieee_rm[rounding_mode], status);
- set_flush_to_zero(flush_to_zero, status);
- set_flush_inputs_to_zero(flush_to_zero, status);
-}
-
-static inline void restore_pamask(CPUMIPSState *env)
-{
- if (env->hflags & MIPS_HFLAG_ELPA) {
- env->PAMask = (1ULL << env->PABITS) - 1;
- } else {
- env->PAMask = PAMASK_BASE;
- }
-}
-
static inline void cpu_get_tb_cpu_state(CPUMIPSState *env, target_ulong *pc,
target_ulong *cs_base, uint32_t *flags)
{
@@ -950,172 +765,4 @@ static inline void cpu_get_tb_cpu_state(CPUMIPSState *env, target_ulong *pc,
MIPS_HFLAG_HWRENA_ULR);
}
-static inline int mips_vpe_active(CPUMIPSState *env)
-{
- int active = 1;
-
- /* Check that the VPE is enabled. */
- if (!(env->mvp->CP0_MVPControl & (1 << CP0MVPCo_EVP))) {
- active = 0;
- }
- /* Check that the VPE is activated. */
- if (!(env->CP0_VPEConf0 & (1 << CP0VPEC0_VPA))) {
- active = 0;
- }
-
- /* Now verify that there are active thread contexts in the VPE.
-
- This assumes the CPU model will internally reschedule threads
- if the active one goes to sleep. If there are no threads available
- the active one will be in a sleeping state, and we can turn off
- the entire VPE. */
- if (!(env->active_tc.CP0_TCStatus & (1 << CP0TCSt_A))) {
- /* TC is not activated. */
- active = 0;
- }
- if (env->active_tc.CP0_TCHalt & 1) {
- /* TC is in halt state. */
- active = 0;
- }
-
- return active;
-}
-
-static inline int mips_vp_active(CPUMIPSState *env)
-{
- CPUState *other_cs = first_cpu;
-
- /* Check if the VP disabled other VPs (which means the VP is enabled) */
- if ((env->CP0_VPControl >> CP0VPCtl_DIS) & 1) {
- return 1;
- }
-
- /* Check if the virtual processor is disabled due to a DVP */
- CPU_FOREACH(other_cs) {
- MIPSCPU *other_cpu = MIPS_CPU(other_cs);
- if ((&other_cpu->env != env) &&
- ((other_cpu->env.CP0_VPControl >> CP0VPCtl_DIS) & 1)) {
- return 0;
- }
- }
- return 1;
-}
-
-static inline void compute_hflags(CPUMIPSState *env)
-{
- env->hflags &= ~(MIPS_HFLAG_COP1X | MIPS_HFLAG_64 | MIPS_HFLAG_CP0 |
- MIPS_HFLAG_F64 | MIPS_HFLAG_FPU | MIPS_HFLAG_KSU |
- MIPS_HFLAG_AWRAP | MIPS_HFLAG_DSP | MIPS_HFLAG_DSPR2 |
- MIPS_HFLAG_SBRI | MIPS_HFLAG_MSA | MIPS_HFLAG_FRE |
- MIPS_HFLAG_ELPA | MIPS_HFLAG_ERL);
- if (env->CP0_Status & (1 << CP0St_ERL)) {
- env->hflags |= MIPS_HFLAG_ERL;
- }
- if (!(env->CP0_Status & (1 << CP0St_EXL)) &&
- !(env->CP0_Status & (1 << CP0St_ERL)) &&
- !(env->hflags & MIPS_HFLAG_DM)) {
- env->hflags |= (env->CP0_Status >> CP0St_KSU) & MIPS_HFLAG_KSU;
- }
-#if defined(TARGET_MIPS64)
- if ((env->insn_flags & ISA_MIPS3) &&
- (((env->hflags & MIPS_HFLAG_KSU) != MIPS_HFLAG_UM) ||
- (env->CP0_Status & (1 << CP0St_PX)) ||
- (env->CP0_Status & (1 << CP0St_UX)))) {
- env->hflags |= MIPS_HFLAG_64;
- }
-
- if (!(env->insn_flags & ISA_MIPS3)) {
- env->hflags |= MIPS_HFLAG_AWRAP;
- } else if (((env->hflags & MIPS_HFLAG_KSU) == MIPS_HFLAG_UM) &&
- !(env->CP0_Status & (1 << CP0St_UX))) {
- env->hflags |= MIPS_HFLAG_AWRAP;
- } else if (env->insn_flags & ISA_MIPS64R6) {
- /* Address wrapping for Supervisor and Kernel is specified in R6 */
- if ((((env->hflags & MIPS_HFLAG_KSU) == MIPS_HFLAG_SM) &&
- !(env->CP0_Status & (1 << CP0St_SX))) ||
- (((env->hflags & MIPS_HFLAG_KSU) == MIPS_HFLAG_KM) &&
- !(env->CP0_Status & (1 << CP0St_KX)))) {
- env->hflags |= MIPS_HFLAG_AWRAP;
- }
- }
-#endif
- if (((env->CP0_Status & (1 << CP0St_CU0)) &&
- !(env->insn_flags & ISA_MIPS32R6)) ||
- !(env->hflags & MIPS_HFLAG_KSU)) {
- env->hflags |= MIPS_HFLAG_CP0;
- }
- if (env->CP0_Status & (1 << CP0St_CU1)) {
- env->hflags |= MIPS_HFLAG_FPU;
- }
- if (env->CP0_Status & (1 << CP0St_FR)) {
- env->hflags |= MIPS_HFLAG_F64;
- }
- if (((env->hflags & MIPS_HFLAG_KSU) != MIPS_HFLAG_KM) &&
- (env->CP0_Config5 & (1 << CP0C5_SBRI))) {
- env->hflags |= MIPS_HFLAG_SBRI;
- }
- if (env->insn_flags & ASE_DSPR2) {
- /* Enables access MIPS DSP resources, now our cpu is DSP ASER2,
- so enable to access DSPR2 resources. */
- if (env->CP0_Status & (1 << CP0St_MX)) {
- env->hflags |= MIPS_HFLAG_DSP | MIPS_HFLAG_DSPR2;
- }
-
- } else if (env->insn_flags & ASE_DSP) {
- /* Enables access MIPS DSP resources, now our cpu is DSP ASE,
- so enable to access DSP resources. */
- if (env->CP0_Status & (1 << CP0St_MX)) {
- env->hflags |= MIPS_HFLAG_DSP;
- }
-
- }
- if (env->insn_flags & ISA_MIPS32R2) {
- if (env->active_fpu.fcr0 & (1 << FCR0_F64)) {
- env->hflags |= MIPS_HFLAG_COP1X;
- }
- } else if (env->insn_flags & ISA_MIPS32) {
- if (env->hflags & MIPS_HFLAG_64) {
- env->hflags |= MIPS_HFLAG_COP1X;
- }
- } else if (env->insn_flags & ISA_MIPS4) {
- /* All supported MIPS IV CPUs use the XX (CU3) to enable
- and disable the MIPS IV extensions to the MIPS III ISA.
- Some other MIPS IV CPUs ignore the bit, so the check here
- would be too restrictive for them. */
- if (env->CP0_Status & (1U << CP0St_CU3)) {
- env->hflags |= MIPS_HFLAG_COP1X;
- }
- }
- if (env->insn_flags & ASE_MSA) {
- if (env->CP0_Config5 & (1 << CP0C5_MSAEn)) {
- env->hflags |= MIPS_HFLAG_MSA;
- }
- }
- if (env->active_fpu.fcr0 & (1 << FCR0_FREP)) {
- if (env->CP0_Config5 & (1 << CP0C5_FRE)) {
- env->hflags |= MIPS_HFLAG_FRE;
- }
- }
- if (env->CP0_Config3 & (1 << CP0C3_LPA)) {
- if (env->CP0_PageGrain & (1 << CP0PG_ELPA)) {
- env->hflags |= MIPS_HFLAG_ELPA;
- }
- }
-}
-
-void cpu_mips_tlb_flush(CPUMIPSState *env);
-void sync_c0_status(CPUMIPSState *env, CPUMIPSState *cpu, int tc);
-void cpu_mips_store_status(CPUMIPSState *env, target_ulong val);
-void cpu_mips_store_cause(CPUMIPSState *env, target_ulong val);
-
-void QEMU_NORETURN do_raise_exception_err(CPUMIPSState *env, uint32_t exception,
- int error_code, uintptr_t pc);
-
-static inline void QEMU_NORETURN do_raise_exception(CPUMIPSState *env,
- uint32_t exception,
- uintptr_t pc)
-{
- do_raise_exception_err(env, exception, 0, pc);
-}
-
#endif /* MIPS_CPU_H */
diff --git a/target/mips/dsp_helper.c b/target/mips/dsp_helper.c
index dc707934ea..f152fea34a 100644
--- a/target/mips/dsp_helper.c
+++ b/target/mips/dsp_helper.c
@@ -45,9 +45,9 @@ typedef union {
} DSP64Value;
/*** MIPS DSP internal functions begin ***/
-#define MIPSDSP_ABS(x) (((x) >= 0) ? x : -x)
-#define MIPSDSP_OVERFLOW_ADD(a, b, c, d) (~(a ^ b) & (a ^ c) & d)
-#define MIPSDSP_OVERFLOW_SUB(a, b, c, d) ((a ^ b) & (a ^ c) & d)
+#define MIPSDSP_ABS(x) (((x) >= 0) ? (x) : -(x))
+#define MIPSDSP_OVERFLOW_ADD(a, b, c, d) (~((a) ^ (b)) & ((a) ^ (c)) & (d))
+#define MIPSDSP_OVERFLOW_SUB(a, b, c, d) (((a) ^ (b)) & ((a) ^ (c)) & (d))
static inline void set_DSPControl_overflow_flag(uint32_t flag, int position,
CPUMIPSState *env)
@@ -1047,47 +1047,47 @@ static inline int32_t mipsdsp_cmpu_lt(uint32_t a, uint32_t b)
#define MIPSDSP_SPLIT32_8(num, a, b, c, d) \
do { \
- a = (num >> 24) & MIPSDSP_Q0; \
- b = (num >> 16) & MIPSDSP_Q0; \
- c = (num >> 8) & MIPSDSP_Q0; \
- d = num & MIPSDSP_Q0; \
+ a = ((num) >> 24) & MIPSDSP_Q0; \
+ b = ((num) >> 16) & MIPSDSP_Q0; \
+ c = ((num) >> 8) & MIPSDSP_Q0; \
+ d = (num) & MIPSDSP_Q0; \
} while (0)
#define MIPSDSP_SPLIT32_16(num, a, b) \
do { \
- a = (num >> 16) & MIPSDSP_LO; \
- b = num & MIPSDSP_LO; \
+ a = ((num) >> 16) & MIPSDSP_LO; \
+ b = (num) & MIPSDSP_LO; \
} while (0)
-#define MIPSDSP_RETURN32_8(a, b, c, d) ((target_long)(int32_t) \
- (((uint32_t)a << 24) | \
- (((uint32_t)b << 16) | \
- (((uint32_t)c << 8) | \
- ((uint32_t)d & 0xFF)))))
-#define MIPSDSP_RETURN32_16(a, b) ((target_long)(int32_t) \
- (((uint32_t)a << 16) | \
- ((uint32_t)b & 0xFFFF)))
+#define MIPSDSP_RETURN32_8(a, b, c, d) ((target_long)(int32_t) \
+ (((uint32_t)(a) << 24) | \
+ ((uint32_t)(b) << 16) | \
+ ((uint32_t)(c) << 8) | \
+ ((uint32_t)(d) & 0xFF)))
+#define MIPSDSP_RETURN32_16(a, b) ((target_long)(int32_t) \
+ (((uint32_t)(a) << 16) | \
+ ((uint32_t)(b) & 0xFFFF)))
#ifdef TARGET_MIPS64
#define MIPSDSP_SPLIT64_16(num, a, b, c, d) \
do { \
- a = (num >> 48) & MIPSDSP_LO; \
- b = (num >> 32) & MIPSDSP_LO; \
- c = (num >> 16) & MIPSDSP_LO; \
- d = num & MIPSDSP_LO; \
+ a = ((num) >> 48) & MIPSDSP_LO; \
+ b = ((num) >> 32) & MIPSDSP_LO; \
+ c = ((num) >> 16) & MIPSDSP_LO; \
+ d = (num) & MIPSDSP_LO; \
} while (0)
#define MIPSDSP_SPLIT64_32(num, a, b) \
do { \
- a = (num >> 32) & MIPSDSP_LLO; \
- b = num & MIPSDSP_LLO; \
+ a = ((num) >> 32) & MIPSDSP_LLO; \
+ b = (num) & MIPSDSP_LLO; \
} while (0)
-#define MIPSDSP_RETURN64_16(a, b, c, d) (((uint64_t)a << 48) | \
- ((uint64_t)b << 32) | \
- ((uint64_t)c << 16) | \
- (uint64_t)d)
-#define MIPSDSP_RETURN64_32(a, b) (((uint64_t)a << 32) | (uint64_t)b)
+#define MIPSDSP_RETURN64_16(a, b, c, d) (((uint64_t)(a) << 48) | \
+ ((uint64_t)(b) << 32) | \
+ ((uint64_t)(c) << 16) | \
+ (uint64_t)(d))
+#define MIPSDSP_RETURN64_32(a, b) (((uint64_t)(a) << 32) | (uint64_t)(b))
#endif
/** DSP Arithmetic Sub-class insns **/
diff --git a/target/mips/gdbstub.c b/target/mips/gdbstub.c
index 7c682289c2..6d1fb70f2c 100644
--- a/target/mips/gdbstub.c
+++ b/target/mips/gdbstub.c
@@ -20,6 +20,7 @@
#include "qemu/osdep.h"
#include "qemu-common.h"
#include "cpu.h"
+#include "internal.h"
#include "exec/gdbstub.h"
int mips_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
diff --git a/target/mips/helper.c b/target/mips/helper.c
index ca39aca08a..ea076261af 100644
--- a/target/mips/helper.c
+++ b/target/mips/helper.c
@@ -19,6 +19,7 @@
#include "qemu/osdep.h"
#include "cpu.h"
+#include "internal.h"
#include "exec/exec-all.h"
#include "exec/cpu_ldst.h"
#include "exec/log.h"
diff --git a/target/mips/internal.h b/target/mips/internal.h
new file mode 100644
index 0000000000..45ded3484c
--- /dev/null
+++ b/target/mips/internal.h
@@ -0,0 +1,422 @@
+/* mips internal definitions and helpers
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef MIPS_INTERNAL_H
+#define MIPS_INTERNAL_H
+
+
+/* MMU types, the first four entries have the same layout as the
+ CP0C0_MT field. */
+enum mips_mmu_types {
+ MMU_TYPE_NONE,
+ MMU_TYPE_R4000,
+ MMU_TYPE_RESERVED,
+ MMU_TYPE_FMT,
+ MMU_TYPE_R3000,
+ MMU_TYPE_R6000,
+ MMU_TYPE_R8000
+};
+
+struct mips_def_t {
+ const char *name;
+ int32_t CP0_PRid;
+ int32_t CP0_Config0;
+ int32_t CP0_Config1;
+ int32_t CP0_Config2;
+ int32_t CP0_Config3;
+ int32_t CP0_Config4;
+ int32_t CP0_Config4_rw_bitmask;
+ int32_t CP0_Config5;
+ int32_t CP0_Config5_rw_bitmask;
+ int32_t CP0_Config6;
+ int32_t CP0_Config7;
+ target_ulong CP0_LLAddr_rw_bitmask;
+ int CP0_LLAddr_shift;
+ int32_t SYNCI_Step;
+ int32_t CCRes;
+ int32_t CP0_Status_rw_bitmask;
+ int32_t CP0_TCStatus_rw_bitmask;
+ int32_t CP0_SRSCtl;
+ int32_t CP1_fcr0;
+ int32_t CP1_fcr31_rw_bitmask;
+ int32_t CP1_fcr31;
+ int32_t MSAIR;
+ int32_t SEGBITS;
+ int32_t PABITS;
+ int32_t CP0_SRSConf0_rw_bitmask;
+ int32_t CP0_SRSConf0;
+ int32_t CP0_SRSConf1_rw_bitmask;
+ int32_t CP0_SRSConf1;
+ int32_t CP0_SRSConf2_rw_bitmask;
+ int32_t CP0_SRSConf2;
+ int32_t CP0_SRSConf3_rw_bitmask;
+ int32_t CP0_SRSConf3;
+ int32_t CP0_SRSConf4_rw_bitmask;
+ int32_t CP0_SRSConf4;
+ int32_t CP0_PageGrain_rw_bitmask;
+ int32_t CP0_PageGrain;
+ target_ulong CP0_EBaseWG_rw_bitmask;
+ int insn_flags;
+ enum mips_mmu_types mmu_type;
+};
+
+extern const struct mips_def_t mips_defs[];
+extern const int mips_defs_number;
+
+enum CPUMIPSMSADataFormat {
+ DF_BYTE = 0,
+ DF_HALF,
+ DF_WORD,
+ DF_DOUBLE
+};
+
+void mips_cpu_do_interrupt(CPUState *cpu);
+bool mips_cpu_exec_interrupt(CPUState *cpu, int int_req);
+void mips_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf,
+ int flags);
+hwaddr mips_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
+int mips_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int mips_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
+void mips_cpu_do_unaligned_access(CPUState *cpu, vaddr addr,
+ MMUAccessType access_type,
+ int mmu_idx, uintptr_t retaddr);
+
+#if !defined(CONFIG_USER_ONLY)
+
+typedef struct r4k_tlb_t r4k_tlb_t;
+struct r4k_tlb_t {
+ target_ulong VPN;
+ uint32_t PageMask;
+ uint16_t ASID;
+ unsigned int G:1;
+ unsigned int C0:3;
+ unsigned int C1:3;
+ unsigned int V0:1;
+ unsigned int V1:1;
+ unsigned int D0:1;
+ unsigned int D1:1;
+ unsigned int XI0:1;
+ unsigned int XI1:1;
+ unsigned int RI0:1;
+ unsigned int RI1:1;
+ unsigned int EHINV:1;
+ uint64_t PFN[2];
+};
+
+struct CPUMIPSTLBContext {
+ uint32_t nb_tlb;
+ uint32_t tlb_in_use;
+ int (*map_address)(struct CPUMIPSState *env, hwaddr *physical, int *prot,
+ target_ulong address, int rw, int access_type);
+ void (*helper_tlbwi)(struct CPUMIPSState *env);
+ void (*helper_tlbwr)(struct CPUMIPSState *env);
+ void (*helper_tlbp)(struct CPUMIPSState *env);
+ void (*helper_tlbr)(struct CPUMIPSState *env);
+ void (*helper_tlbinv)(struct CPUMIPSState *env);
+ void (*helper_tlbinvf)(struct CPUMIPSState *env);
+ union {
+ struct {
+ r4k_tlb_t tlb[MIPS_TLB_MAX];
+ } r4k;
+ } mmu;
+};
+
+int no_mmu_map_address(CPUMIPSState *env, hwaddr *physical, int *prot,
+ target_ulong address, int rw, int access_type);
+int fixed_mmu_map_address(CPUMIPSState *env, hwaddr *physical, int *prot,
+ target_ulong address, int rw, int access_type);
+int r4k_map_address(CPUMIPSState *env, hwaddr *physical, int *prot,
+ target_ulong address, int rw, int access_type);
+void r4k_helper_tlbwi(CPUMIPSState *env);
+void r4k_helper_tlbwr(CPUMIPSState *env);
+void r4k_helper_tlbp(CPUMIPSState *env);
+void r4k_helper_tlbr(CPUMIPSState *env);
+void r4k_helper_tlbinv(CPUMIPSState *env);
+void r4k_helper_tlbinvf(CPUMIPSState *env);
+void r4k_invalidate_tlb(CPUMIPSState *env, int idx, int use_extra);
+
+void mips_cpu_unassigned_access(CPUState *cpu, hwaddr addr,
+ bool is_write, bool is_exec, int unused,
+ unsigned size);
+hwaddr cpu_mips_translate_address(CPUMIPSState *env, target_ulong address,
+ int rw);
+#endif
+
+#define cpu_signal_handler cpu_mips_signal_handler
+
+#ifndef CONFIG_USER_ONLY
+extern const struct VMStateDescription vmstate_mips_cpu;
+#endif
+
+static inline bool cpu_mips_hw_interrupts_enabled(CPUMIPSState *env)
+{
+ return (env->CP0_Status & (1 << CP0St_IE)) &&
+ !(env->CP0_Status & (1 << CP0St_EXL)) &&
+ !(env->CP0_Status & (1 << CP0St_ERL)) &&
+ !(env->hflags & MIPS_HFLAG_DM) &&
+ /* Note that the TCStatus IXMT field is initialized to zero,
+ and only MT capable cores can set it to one. So we don't
+ need to check for MT capabilities here. */
+ !(env->active_tc.CP0_TCStatus & (1 << CP0TCSt_IXMT));
+}
+
+/* Check if there is pending and not masked out interrupt */
+static inline bool cpu_mips_hw_interrupts_pending(CPUMIPSState *env)
+{
+ int32_t pending;
+ int32_t status;
+ bool r;
+
+ pending = env->CP0_Cause & CP0Ca_IP_mask;
+ status = env->CP0_Status & CP0Ca_IP_mask;
+
+ if (env->CP0_Config3 & (1 << CP0C3_VEIC)) {
+ /* A MIPS configured with a vectorizing external interrupt controller
+ will feed a vector into the Cause pending lines. The core treats
+ the status lines as a vector level, not as indiviual masks. */
+ r = pending > status;
+ } else {
+ /* A MIPS configured with compatibility or VInt (Vectored Interrupts)
+ treats the pending lines as individual interrupt lines, the status
+ lines are individual masks. */
+ r = (pending & status) != 0;
+ }
+ return r;
+}
+
+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_random(CPUMIPSState *env);
+uint32_t cpu_mips_get_count(CPUMIPSState *env);
+void cpu_mips_store_count(CPUMIPSState *env, uint32_t value);
+void cpu_mips_store_compare(CPUMIPSState *env, uint32_t value);
+void cpu_mips_start_count(CPUMIPSState *env);
+void cpu_mips_stop_count(CPUMIPSState *env);
+
+/* helper.c */
+int mips_cpu_handle_mmu_fault(CPUState *cpu, vaddr address, int rw,
+ int mmu_idx);
+
+/* op_helper.c */
+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[];
+int ieee_ex_to_mips(int xcpt);
+
+static inline void restore_rounding_mode(CPUMIPSState *env)
+{
+ set_float_rounding_mode(ieee_rm[env->active_fpu.fcr31 & 3],
+ &env->active_fpu.fp_status);
+}
+
+static inline void restore_flush_mode(CPUMIPSState *env)
+{
+ set_flush_to_zero((env->active_fpu.fcr31 & (1 << FCR31_FS)) != 0,
+ &env->active_fpu.fp_status);
+}
+
+static inline void restore_fp_status(CPUMIPSState *env)
+{
+ restore_rounding_mode(env);
+ restore_flush_mode(env);
+ restore_snan_bit_mode(env);
+}
+
+static inline void restore_msa_fp_status(CPUMIPSState *env)
+{
+ float_status *status = &env->active_tc.msa_fp_status;
+ int rounding_mode = (env->active_tc.msacsr & MSACSR_RM_MASK) >> MSACSR_RM;
+ bool flush_to_zero = (env->active_tc.msacsr & MSACSR_FS_MASK) != 0;
+
+ set_float_rounding_mode(ieee_rm[rounding_mode], status);
+ set_flush_to_zero(flush_to_zero, status);
+ set_flush_inputs_to_zero(flush_to_zero, status);
+}
+
+static inline void restore_pamask(CPUMIPSState *env)
+{
+ if (env->hflags & MIPS_HFLAG_ELPA) {
+ env->PAMask = (1ULL << env->PABITS) - 1;
+ } else {
+ env->PAMask = PAMASK_BASE;
+ }
+}
+
+static inline int mips_vpe_active(CPUMIPSState *env)
+{
+ int active = 1;
+
+ /* Check that the VPE is enabled. */
+ if (!(env->mvp->CP0_MVPControl & (1 << CP0MVPCo_EVP))) {
+ active = 0;
+ }
+ /* Check that the VPE is activated. */
+ if (!(env->CP0_VPEConf0 & (1 << CP0VPEC0_VPA))) {
+ active = 0;
+ }
+
+ /* Now verify that there are active thread contexts in the VPE.
+
+ This assumes the CPU model will internally reschedule threads
+ if the active one goes to sleep. If there are no threads available
+ the active one will be in a sleeping state, and we can turn off
+ the entire VPE. */
+ if (!(env->active_tc.CP0_TCStatus & (1 << CP0TCSt_A))) {
+ /* TC is not activated. */
+ active = 0;
+ }
+ if (env->active_tc.CP0_TCHalt & 1) {
+ /* TC is in halt state. */
+ active = 0;
+ }
+
+ return active;
+}
+
+static inline int mips_vp_active(CPUMIPSState *env)
+{
+ CPUState *other_cs = first_cpu;
+
+ /* Check if the VP disabled other VPs (which means the VP is enabled) */
+ if ((env->CP0_VPControl >> CP0VPCtl_DIS) & 1) {
+ return 1;
+ }
+
+ /* Check if the virtual processor is disabled due to a DVP */
+ CPU_FOREACH(other_cs) {
+ MIPSCPU *other_cpu = MIPS_CPU(other_cs);
+ if ((&other_cpu->env != env) &&
+ ((other_cpu->env.CP0_VPControl >> CP0VPCtl_DIS) & 1)) {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static inline void compute_hflags(CPUMIPSState *env)
+{
+ env->hflags &= ~(MIPS_HFLAG_COP1X | MIPS_HFLAG_64 | MIPS_HFLAG_CP0 |
+ MIPS_HFLAG_F64 | MIPS_HFLAG_FPU | MIPS_HFLAG_KSU |
+ MIPS_HFLAG_AWRAP | MIPS_HFLAG_DSP | MIPS_HFLAG_DSPR2 |
+ MIPS_HFLAG_SBRI | MIPS_HFLAG_MSA | MIPS_HFLAG_FRE |
+ MIPS_HFLAG_ELPA | MIPS_HFLAG_ERL);
+ if (env->CP0_Status & (1 << CP0St_ERL)) {
+ env->hflags |= MIPS_HFLAG_ERL;
+ }
+ if (!(env->CP0_Status & (1 << CP0St_EXL)) &&
+ !(env->CP0_Status & (1 << CP0St_ERL)) &&
+ !(env->hflags & MIPS_HFLAG_DM)) {
+ env->hflags |= (env->CP0_Status >> CP0St_KSU) & MIPS_HFLAG_KSU;
+ }
+#if defined(TARGET_MIPS64)
+ if ((env->insn_flags & ISA_MIPS3) &&
+ (((env->hflags & MIPS_HFLAG_KSU) != MIPS_HFLAG_UM) ||
+ (env->CP0_Status & (1 << CP0St_PX)) ||
+ (env->CP0_Status & (1 << CP0St_UX)))) {
+ env->hflags |= MIPS_HFLAG_64;
+ }
+
+ if (!(env->insn_flags & ISA_MIPS3)) {
+ env->hflags |= MIPS_HFLAG_AWRAP;
+ } else if (((env->hflags & MIPS_HFLAG_KSU) == MIPS_HFLAG_UM) &&
+ !(env->CP0_Status & (1 << CP0St_UX))) {
+ env->hflags |= MIPS_HFLAG_AWRAP;
+ } else if (env->insn_flags & ISA_MIPS64R6) {
+ /* Address wrapping for Supervisor and Kernel is specified in R6 */
+ if ((((env->hflags & MIPS_HFLAG_KSU) == MIPS_HFLAG_SM) &&
+ !(env->CP0_Status & (1 << CP0St_SX))) ||
+ (((env->hflags & MIPS_HFLAG_KSU) == MIPS_HFLAG_KM) &&
+ !(env->CP0_Status & (1 << CP0St_KX)))) {
+ env->hflags |= MIPS_HFLAG_AWRAP;
+ }
+ }
+#endif
+ if (((env->CP0_Status & (1 << CP0St_CU0)) &&
+ !(env->insn_flags & ISA_MIPS32R6)) ||
+ !(env->hflags & MIPS_HFLAG_KSU)) {
+ env->hflags |= MIPS_HFLAG_CP0;
+ }
+ if (env->CP0_Status & (1 << CP0St_CU1)) {
+ env->hflags |= MIPS_HFLAG_FPU;
+ }
+ if (env->CP0_Status & (1 << CP0St_FR)) {
+ env->hflags |= MIPS_HFLAG_F64;
+ }
+ if (((env->hflags & MIPS_HFLAG_KSU) != MIPS_HFLAG_KM) &&
+ (env->CP0_Config5 & (1 << CP0C5_SBRI))) {
+ env->hflags |= MIPS_HFLAG_SBRI;
+ }
+ if (env->insn_flags & ASE_DSPR2) {
+ /* Enables access MIPS DSP resources, now our cpu is DSP ASER2,
+ so enable to access DSPR2 resources. */
+ if (env->CP0_Status & (1 << CP0St_MX)) {
+ env->hflags |= MIPS_HFLAG_DSP | MIPS_HFLAG_DSPR2;
+ }
+
+ } else if (env->insn_flags & ASE_DSP) {
+ /* Enables access MIPS DSP resources, now our cpu is DSP ASE,
+ so enable to access DSP resources. */
+ if (env->CP0_Status & (1 << CP0St_MX)) {
+ env->hflags |= MIPS_HFLAG_DSP;
+ }
+
+ }
+ if (env->insn_flags & ISA_MIPS32R2) {
+ if (env->active_fpu.fcr0 & (1 << FCR0_F64)) {
+ env->hflags |= MIPS_HFLAG_COP1X;
+ }
+ } else if (env->insn_flags & ISA_MIPS32) {
+ if (env->hflags & MIPS_HFLAG_64) {
+ env->hflags |= MIPS_HFLAG_COP1X;
+ }
+ } else if (env->insn_flags & ISA_MIPS4) {
+ /* All supported MIPS IV CPUs use the XX (CU3) to enable
+ and disable the MIPS IV extensions to the MIPS III ISA.
+ Some other MIPS IV CPUs ignore the bit, so the check here
+ would be too restrictive for them. */
+ if (env->CP0_Status & (1U << CP0St_CU3)) {
+ env->hflags |= MIPS_HFLAG_COP1X;
+ }
+ }
+ if (env->insn_flags & ASE_MSA) {
+ if (env->CP0_Config5 & (1 << CP0C5_MSAEn)) {
+ env->hflags |= MIPS_HFLAG_MSA;
+ }
+ }
+ if (env->active_fpu.fcr0 & (1 << FCR0_FREP)) {
+ if (env->CP0_Config5 & (1 << CP0C5_FRE)) {
+ env->hflags |= MIPS_HFLAG_FRE;
+ }
+ }
+ if (env->CP0_Config3 & (1 << CP0C3_LPA)) {
+ if (env->CP0_PageGrain & (1 << CP0PG_ELPA)) {
+ env->hflags |= MIPS_HFLAG_ELPA;
+ }
+ }
+}
+
+void cpu_mips_tlb_flush(CPUMIPSState *env);
+void sync_c0_status(CPUMIPSState *env, CPUMIPSState *cpu, int tc);
+void cpu_mips_store_status(CPUMIPSState *env, target_ulong val);
+void cpu_mips_store_cause(CPUMIPSState *env, target_ulong val);
+
+void QEMU_NORETURN do_raise_exception_err(CPUMIPSState *env, uint32_t exception,
+ int error_code, uintptr_t pc);
+
+static inline void QEMU_NORETURN do_raise_exception(CPUMIPSState *env,
+ uint32_t exception,
+ uintptr_t pc)
+{
+ do_raise_exception_err(env, exception, 0, pc);
+}
+
+#endif
diff --git a/target/mips/kvm.c b/target/mips/kvm.c
index 3b7b1d962a..8e72850962 100644
--- a/target/mips/kvm.c
+++ b/target/mips/kvm.c
@@ -16,6 +16,7 @@
#include "qemu-common.h"
#include "cpu.h"
+#include "internal.h"
#include "qemu/error-report.h"
#include "qemu/timer.h"
#include "sysemu/sysemu.h"
diff --git a/target/mips/machine.c b/target/mips/machine.c
index 898825de3b..20100d5adb 100644
--- a/target/mips/machine.c
+++ b/target/mips/machine.c
@@ -1,6 +1,7 @@
#include "qemu/osdep.h"
#include "qemu-common.h"
#include "cpu.h"
+#include "internal.h"
#include "hw/hw.h"
#include "migration/cpu.h"
diff --git a/target/mips/msa_helper.c b/target/mips/msa_helper.c
index 1fdb0d9792..f167a42655 100644
--- a/target/mips/msa_helper.c
+++ b/target/mips/msa_helper.c
@@ -19,6 +19,7 @@
#include "qemu/osdep.h"
#include "cpu.h"
+#include "internal.h"
#include "exec/exec-all.h"
#include "exec/helper-proto.h"
diff --git a/target/mips/op_helper.c b/target/mips/op_helper.c
index 320f2b0dc4..e537a8bfd8 100644
--- a/target/mips/op_helper.c
+++ b/target/mips/op_helper.c
@@ -19,6 +19,7 @@
#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"
diff --git a/target/mips/translate.c b/target/mips/translate.c
index c78d27294c..d16d879df7 100644
--- a/target/mips/translate.c
+++ b/target/mips/translate.c
@@ -23,6 +23,7 @@
#include "qemu/osdep.h"
#include "cpu.h"
+#include "internal.h"
#include "disas/disas.h"
#include "exec/exec-all.h"
#include "tcg-op.h"
@@ -20511,29 +20512,15 @@ void mips_tcg_init(void)
#include "translate_init.c"
-MIPSCPU *cpu_mips_init(const char *cpu_model)
+void cpu_mips_realize_env(CPUMIPSState *env)
{
- MIPSCPU *cpu;
- CPUMIPSState *env;
- const mips_def_t *def;
-
- def = cpu_mips_find_by_name(cpu_model);
- if (!def)
- return NULL;
- cpu = MIPS_CPU(object_new(TYPE_MIPS_CPU));
- env = &cpu->env;
- env->cpu_model = def;
env->exception_base = (int32_t)0xBFC00000;
#ifndef CONFIG_USER_ONLY
- mmu_init(env, def);
+ mmu_init(env, env->cpu_model);
#endif
- fpu_init(env, def);
- mvp_init(env, def);
-
- object_property_set_bool(OBJECT(cpu), true, "realized", NULL);
-
- return cpu;
+ fpu_init(env, env->cpu_model);
+ mvp_init(env, env->cpu_model);
}
bool cpu_supports_cps_smp(const char *cpu_model)
diff --git a/target/mips/translate_init.c b/target/mips/translate_init.c
index 255d25bacd..8bbded46c4 100644
--- a/target/mips/translate_init.c
+++ b/target/mips/translate_init.c
@@ -51,64 +51,9 @@
#define MIPS_CONFIG5 \
((0 << CP0C5_M))
-/* MMU types, the first four entries have the same layout as the
- CP0C0_MT field. */
-enum mips_mmu_types {
- MMU_TYPE_NONE,
- MMU_TYPE_R4000,
- MMU_TYPE_RESERVED,
- MMU_TYPE_FMT,
- MMU_TYPE_R3000,
- MMU_TYPE_R6000,
- MMU_TYPE_R8000
-};
-
-struct mips_def_t {
- const char *name;
- int32_t CP0_PRid;
- int32_t CP0_Config0;
- int32_t CP0_Config1;
- int32_t CP0_Config2;
- int32_t CP0_Config3;
- int32_t CP0_Config4;
- int32_t CP0_Config4_rw_bitmask;
- int32_t CP0_Config5;
- int32_t CP0_Config5_rw_bitmask;
- int32_t CP0_Config6;
- int32_t CP0_Config7;
- target_ulong CP0_LLAddr_rw_bitmask;
- int CP0_LLAddr_shift;
- int32_t SYNCI_Step;
- int32_t CCRes;
- int32_t CP0_Status_rw_bitmask;
- int32_t CP0_TCStatus_rw_bitmask;
- int32_t CP0_SRSCtl;
- int32_t CP1_fcr0;
- int32_t CP1_fcr31_rw_bitmask;
- int32_t CP1_fcr31;
- int32_t MSAIR;
- int32_t SEGBITS;
- int32_t PABITS;
- int32_t CP0_SRSConf0_rw_bitmask;
- int32_t CP0_SRSConf0;
- int32_t CP0_SRSConf1_rw_bitmask;
- int32_t CP0_SRSConf1;
- int32_t CP0_SRSConf2_rw_bitmask;
- int32_t CP0_SRSConf2;
- int32_t CP0_SRSConf3_rw_bitmask;
- int32_t CP0_SRSConf3;
- int32_t CP0_SRSConf4_rw_bitmask;
- int32_t CP0_SRSConf4;
- int32_t CP0_PageGrain_rw_bitmask;
- int32_t CP0_PageGrain;
- target_ulong CP0_EBaseWG_rw_bitmask;
- int insn_flags;
- enum mips_mmu_types mmu_type;
-};
-
/*****************************************************************************/
/* MIPS CPU definitions */
-static const mips_def_t mips_defs[] =
+const mips_def_t mips_defs[] =
{
{
.name = "4Kc",
@@ -808,6 +753,7 @@ static const mips_def_t mips_defs[] =
#endif
};
+const int mips_defs_number = ARRAY_SIZE(mips_defs);
static const mips_def_t *cpu_mips_find_by_name (const char *name)
{