diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2020-10-19 10:52:56 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2020-10-19 10:52:57 +0100 |
commit | 22d30b340aa5d8a2b1fbc90d5263f801f1584d01 (patch) | |
tree | de271aafb22a72bd5ccecf151e463c29b4b00524 /target | |
parent | 782d7b30dd8e27ba24346e7c411b476db88b59e7 (diff) | |
parent | 68fa519a6cb455005317bd61f95214b58b2f1e69 (diff) |
Merge remote-tracking branch 'remotes/philmd-gitlab/tags/mips-next-20201017' into staging
MIPS patches queue
. Fix some comment spelling errors
. Demacro some TCG helpers
. Add loongson-ext lswc2/lsdc2 group of instructions
. Log unimplemented cache opcode
. Increase number of TLB entries on the 34Kf core
. Allow the CPU to use dynamic frequencies
. Calculate the CP0 timer period using the CPU frequency
. Set CPU frequency for each machine
. Fix Malta FPGA I/O region size
. Allow running qtests when ROM is missing
. Add record/replay acceptance tests
. Update MIPS CPU documentation
. MAINTAINERS updates
CI jobs results:
https://gitlab.com/philmd/qemu/-/pipelines/203931842
https://travis-ci.org/github/philmd/qemu/builds/736491461
https://cirrus-ci.com/build/6272264062631936
https://app.shippable.com/github/philmd/qemu/runs/886/summary/console
# gpg: Signature made Sat 17 Oct 2020 14:59:53 BST
# gpg: using RSA key FAABE75E12917221DCFD6BB2E3E32C2CDEADC0DE
# gpg: Good signature from "Philippe Mathieu-Daudé (F4BUG) <f4bug@amsat.org>" [full]
# Primary key fingerprint: FAAB E75E 1291 7221 DCFD 6BB2 E3E3 2C2C DEAD C0DE
* remotes/philmd-gitlab/tags/mips-next-20201017: (44 commits)
target/mips: Increase number of TLB entries on the 34Kf core (16 -> 64)
MAINTAINERS: Remove duplicated Malta test entries
MAINTAINERS: Downgrade MIPS Boston to 'Odd Fixes', fix Paul Burton mail
MAINTAINERS: Put myself forward for MIPS target
MAINTAINERS: Remove myself
docs/system: Update MIPS CPU documentation
tests/acceptance: Add MIPS record/replay tests
hw/mips: Remove exit(1) in case of missing ROM
hw/mips: Rename TYPE_MIPS_BOSTON to TYPE_BOSTON
hw/mips: Simplify code using ROUND_UP(INITRD_PAGE_SIZE)
hw/mips: Simplify loading 64-bit ELF kernels
hw/mips/malta: Use clearer qdev style
hw/mips/malta: Move gt64120 related code together
hw/mips/malta: Fix FPGA I/O region size
target/mips/cpu: Display warning when CPU is used without input clock
hw/mips/cps: Do not allow use without input clock
hw/mips/malta: Set CPU frequency to 320 MHz
hw/mips/boston: Set CPU frequency to 1 GHz
hw/mips/cps: Expose input clock and connect it to CPU cores
hw/mips/jazz: Correct CPU frequencies
...
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'target')
-rw-r--r-- | target/mips/cp0_helper.c | 25 | ||||
-rw-r--r-- | target/mips/cp0_timer.c | 51 | ||||
-rw-r--r-- | target/mips/cpu.c | 55 | ||||
-rw-r--r-- | target/mips/cpu.h | 26 | ||||
-rw-r--r-- | target/mips/fpu_helper.c | 220 | ||||
-rw-r--r-- | target/mips/internal.h | 4 | ||||
-rw-r--r-- | target/mips/op_helper.c | 27 | ||||
-rw-r--r-- | target/mips/translate.c | 453 | ||||
-rw-r--r-- | target/mips/translate_init.c.inc | 4 |
9 files changed, 756 insertions, 109 deletions
diff --git a/target/mips/cp0_helper.c b/target/mips/cp0_helper.c index de64add038..12143ac55b 100644 --- a/target/mips/cp0_helper.c +++ b/target/mips/cp0_helper.c @@ -203,6 +203,31 @@ static void sync_c0_entryhi(CPUMIPSState *cpu, int tc) *tcst |= asid; } +/* XXX: do not use a global */ +uint32_t cpu_mips_get_random(CPUMIPSState *env) +{ + static uint32_t seed = 1; + static uint32_t prev_idx; + 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; +} + /* CP0 helpers */ target_ulong helper_mfc0_mvpcontrol(CPUMIPSState *env) { diff --git a/target/mips/cp0_timer.c b/target/mips/cp0_timer.c index bd7efb152d..5ec0d6249e 100644 --- a/target/mips/cp0_timer.c +++ b/target/mips/cp0_timer.c @@ -27,43 +27,17 @@ #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; + uint64_t now_ns, next_ns; 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); + now_ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + wait = env->CP0_Compare - env->CP0_Count - + (uint32_t)(now_ns / env->cp0_count_ns); + next_ns = now_ns + (uint64_t)wait * env->cp0_count_ns; + timer_mod(env->timer, next_ns); } /* Expire the timer. */ @@ -81,16 +55,16 @@ uint32_t cpu_mips_get_count(CPUMIPSState *env) if (env->CP0_Cause & (1 << CP0Ca_DC)) { return env->CP0_Count; } else { - uint64_t now; + uint64_t now_ns; - now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + now_ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); if (timer_pending(env->timer) - && timer_expired(env->timer, now)) { + && timer_expired(env->timer, now_ns)) { /* The timer has already expired. */ cpu_mips_timer_expire(env); } - return env->CP0_Count + (uint32_t)(now / TIMER_PERIOD); + return env->CP0_Count + (uint32_t)(now_ns / env->cp0_count_ns); } } @@ -106,7 +80,8 @@ void cpu_mips_store_count(CPUMIPSState *env, uint32_t count) } else { /* Store new count register */ env->CP0_Count = count - - (uint32_t)(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / TIMER_PERIOD); + (uint32_t)(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / + env->cp0_count_ns); /* Update timer timer */ cpu_mips_timer_update(env); } @@ -133,7 +108,7 @@ 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); + env->cp0_count_ns); } static void mips_timer_cb(void *opaque) diff --git a/target/mips/cpu.c b/target/mips/cpu.c index e86cd06548..76d50b00b4 100644 --- a/target/mips/cpu.c +++ b/target/mips/cpu.c @@ -19,14 +19,17 @@ */ #include "qemu/osdep.h" +#include "qemu/cutils.h" #include "qapi/error.h" #include "cpu.h" #include "internal.h" #include "kvm_mips.h" #include "qemu/module.h" #include "sysemu/kvm.h" +#include "sysemu/qtest.h" #include "exec/exec-all.h" - +#include "hw/qdev-properties.h" +#include "hw/qdev-clock.h" static void mips_cpu_set_pc(CPUState *cs, vaddr value) { @@ -134,6 +137,21 @@ static void mips_cpu_disas_set_info(CPUState *s, disassemble_info *info) } } +/* + * Since commit 6af0bf9c7c3 this model assumes a CPU clocked at 200MHz. + */ +#define CPU_FREQ_HZ_DEFAULT 200000000 +#define CP0_COUNT_RATE_DEFAULT 2 + +static void mips_cp0_period_set(MIPSCPU *cpu) +{ + CPUMIPSState *env = &cpu->env; + + env->cp0_count_ns = cpu->cp0_count_rate + * clock_get_ns(MIPS_CPU(cpu)->clock); + assert(env->cp0_count_ns); +} + static void mips_cpu_realizefn(DeviceState *dev, Error **errp) { CPUState *cs = CPU(dev); @@ -141,6 +159,20 @@ static void mips_cpu_realizefn(DeviceState *dev, Error **errp) MIPSCPUClass *mcc = MIPS_CPU_GET_CLASS(dev); Error *local_err = NULL; + if (!clock_get(cpu->clock)) { +#ifndef CONFIG_USER_ONLY + if (!qtest_enabled()) { + g_autofree char *cpu_freq_str = freq_to_str(CPU_FREQ_HZ_DEFAULT); + + warn_report("CPU input clock is not connected to any output clock, " + "using default frequency of %s.", cpu_freq_str); + } +#endif + /* Initialize the frequency in case the clock remains unconnected. */ + clock_set_hz(cpu->clock, CPU_FREQ_HZ_DEFAULT); + } + mips_cp0_period_set(cpu); + cpu_exec_realizefn(cs, &local_err); if (local_err != NULL) { error_propagate(errp, local_err); @@ -162,6 +194,7 @@ static void mips_cpu_initfn(Object *obj) MIPSCPUClass *mcc = MIPS_CPU_GET_CLASS(obj); cpu_set_cpustate_pointers(cpu); + cpu->clock = qdev_init_clock_in(DEVICE(obj), "clk-in", NULL, cpu); env->cpu_model = mcc->cpu_def; } @@ -181,6 +214,13 @@ static ObjectClass *mips_cpu_class_by_name(const char *cpu_model) return oc; } +static Property mips_cpu_properties[] = { + /* CP0 timer running at half the clock of the CPU */ + DEFINE_PROP_UINT32("cp0-count-rate", MIPSCPU, cp0_count_rate, + CP0_COUNT_RATE_DEFAULT), + DEFINE_PROP_END_OF_LIST() +}; + static void mips_cpu_class_init(ObjectClass *c, void *data) { MIPSCPUClass *mcc = MIPS_CPU_CLASS(c); @@ -190,6 +230,7 @@ static void mips_cpu_class_init(ObjectClass *c, void *data) device_class_set_parent_realize(dc, mips_cpu_realizefn, &mcc->parent_realize); device_class_set_parent_reset(dc, mips_cpu_reset, &mcc->parent_reset); + device_class_set_props(dc, mips_cpu_properties); cc->class_by_name = mips_cpu_class_by_name; cc->has_work = mips_cpu_has_work; @@ -257,3 +298,15 @@ static void mips_cpu_register_types(void) } type_init(mips_cpu_register_types) + +/* Could be used by generic CPU object */ +MIPSCPU *mips_cpu_create_with_clock(const char *cpu_type, Clock *cpu_refclk) +{ + DeviceState *cpu; + + cpu = DEVICE(object_new(cpu_type)); + qdev_connect_clock_in(cpu, "clk-in", cpu_refclk); + qdev_realize(cpu, NULL, &error_abort); + + return MIPS_CPU(cpu); +} diff --git a/target/mips/cpu.h b/target/mips/cpu.h index 7cf7f5239f..d41579d44a 100644 --- a/target/mips/cpu.h +++ b/target/mips/cpu.h @@ -4,6 +4,7 @@ #include "cpu-qom.h" #include "exec/cpu-defs.h" #include "fpu/softfloat-types.h" +#include "hw/clock.h" #include "mips-defs.h" #define TCG_GUEST_DEFAULT_MO (0) @@ -1145,11 +1146,15 @@ struct CPUMIPSState { struct MIPSITUState *itu; MemoryRegion *itc_tag; /* ITC Configuration Tags */ target_ulong exception_base; /* ExceptionBase input to the core */ + uint64_t cp0_count_ns; /* CP0_Count clock period (in nanoseconds) */ }; /** * MIPSCPU: * @env: #CPUMIPSState + * @clock: this CPU input clock (may be connected + * to an output clock from another device). + * @cp0_count_rate: rate at which the coprocessor 0 counter increments * * A MIPS CPU. */ @@ -1158,8 +1163,17 @@ struct MIPSCPU { CPUState parent_obj; /*< public >*/ + Clock *clock; CPUNegativeOffsetState neg; CPUMIPSState env; + /* + * The Count register acts as a timer, incrementing at a constant rate, + * whether or not an instruction is executed, retired, or any forward + * progress is made through the pipeline. The rate at which the counter + * increments is implementation dependent, and is a function of the + * pipeline clock of the processor, not the issue width of the processor. + */ + unsigned cp0_count_rate; }; @@ -1293,4 +1307,16 @@ static inline void cpu_get_tb_cpu_state(CPUMIPSState *env, target_ulong *pc, MIPS_HFLAG_HWRENA_ULR); } +/** + * mips_cpu_create_with_clock: + * @typename: a MIPS CPU type. + * @cpu_refclk: this cpu input clock (an output clock of another device) + * + * Instantiates a MIPS CPU, set the input clock of the CPU to @cpu_refclk, + * then realizes the CPU. + * + * Returns: A #CPUState or %NULL if an error occurred. + */ +MIPSCPU *mips_cpu_create_with_clock(const char *cpu_type, Clock *cpu_refclk); + #endif /* MIPS_CPU_H */ diff --git a/target/mips/fpu_helper.c b/target/mips/fpu_helper.c index 56beda49d8..6cc956c023 100644 --- a/target/mips/fpu_helper.c +++ b/target/mips/fpu_helper.c @@ -983,27 +983,46 @@ uint32_t helper_float_floor_2008_w_s(CPUMIPSState *env, uint32_t fst0) } /* unary operations, not modifying fp status */ -#define FLOAT_UNOP(name) \ -uint64_t helper_float_ ## name ## _d(uint64_t fdt0) \ -{ \ - return float64_ ## name(fdt0); \ -} \ -uint32_t helper_float_ ## name ## _s(uint32_t fst0) \ -{ \ - return float32_ ## name(fst0); \ -} \ -uint64_t helper_float_ ## name ## _ps(uint64_t fdt0) \ -{ \ - uint32_t wt0; \ - uint32_t wth0; \ - \ - wt0 = float32_ ## name(fdt0 & 0XFFFFFFFF); \ - wth0 = float32_ ## name(fdt0 >> 32); \ - return ((uint64_t)wth0 << 32) | wt0; \ + +uint64_t helper_float_abs_d(uint64_t fdt0) +{ + return float64_abs(fdt0); +} + +uint32_t helper_float_abs_s(uint32_t fst0) +{ + return float32_abs(fst0); +} + +uint64_t helper_float_abs_ps(uint64_t fdt0) +{ + uint32_t wt0; + uint32_t wth0; + + wt0 = float32_abs(fdt0 & 0XFFFFFFFF); + wth0 = float32_abs(fdt0 >> 32); + return ((uint64_t)wth0 << 32) | wt0; +} + +uint64_t helper_float_chs_d(uint64_t fdt0) +{ + return float64_chs(fdt0); +} + +uint32_t helper_float_chs_s(uint32_t fst0) +{ + return float32_chs(fst0); +} + +uint64_t helper_float_chs_ps(uint64_t fdt0) +{ + uint32_t wt0; + uint32_t wth0; + + wt0 = float32_chs(fdt0 & 0XFFFFFFFF); + wth0 = float32_chs(fdt0 >> 32); + return ((uint64_t)wth0 << 32) | wt0; } -FLOAT_UNOP(abs) -FLOAT_UNOP(chs) -#undef FLOAT_UNOP /* MIPS specific unary operations */ uint64_t helper_float_recip_d(CPUMIPSState *env, uint64_t fdt0) @@ -1456,29 +1475,87 @@ uint64_t helper_float_mulr_ps(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt1) return ((uint64_t)fsth2 << 32) | fstl2; } -#define FLOAT_MINMAX(name, bits, minmaxfunc) \ -uint ## bits ## _t helper_float_ ## name(CPUMIPSState *env, \ - uint ## bits ## _t fs, \ - uint ## bits ## _t ft) \ -{ \ - uint ## bits ## _t fdret; \ - \ - fdret = float ## bits ## _ ## minmaxfunc(fs, ft, \ - &env->active_fpu.fp_status); \ - update_fcr31(env, GETPC()); \ - return fdret; \ + +uint32_t helper_float_max_s(CPUMIPSState *env, uint32_t fs, uint32_t ft) +{ + uint32_t fdret; + + fdret = float32_maxnum(fs, ft, &env->active_fpu.fp_status); + + update_fcr31(env, GETPC()); + return fdret; +} + +uint64_t helper_float_max_d(CPUMIPSState *env, uint64_t fs, uint64_t ft) +{ + uint64_t fdret; + + fdret = float64_maxnum(fs, ft, &env->active_fpu.fp_status); + + update_fcr31(env, GETPC()); + return fdret; +} + +uint32_t helper_float_maxa_s(CPUMIPSState *env, uint32_t fs, uint32_t ft) +{ + uint32_t fdret; + + fdret = float32_maxnummag(fs, ft, &env->active_fpu.fp_status); + + update_fcr31(env, GETPC()); + return fdret; +} + +uint64_t helper_float_maxa_d(CPUMIPSState *env, uint64_t fs, uint64_t ft) +{ + uint64_t fdret; + + fdret = float64_maxnummag(fs, ft, &env->active_fpu.fp_status); + + update_fcr31(env, GETPC()); + return fdret; +} + +uint32_t helper_float_min_s(CPUMIPSState *env, uint32_t fs, uint32_t ft) +{ + uint32_t fdret; + + fdret = float32_minnum(fs, ft, &env->active_fpu.fp_status); + + update_fcr31(env, GETPC()); + return fdret; +} + +uint64_t helper_float_min_d(CPUMIPSState *env, uint64_t fs, uint64_t ft) +{ + uint64_t fdret; + + fdret = float64_minnum(fs, ft, &env->active_fpu.fp_status); + + update_fcr31(env, GETPC()); + return fdret; } -FLOAT_MINMAX(max_s, 32, maxnum) -FLOAT_MINMAX(max_d, 64, maxnum) -FLOAT_MINMAX(maxa_s, 32, maxnummag) -FLOAT_MINMAX(maxa_d, 64, maxnummag) +uint32_t helper_float_mina_s(CPUMIPSState *env, uint32_t fs, uint32_t ft) +{ + uint32_t fdret; + + fdret = float32_minnummag(fs, ft, &env->active_fpu.fp_status); + + update_fcr31(env, GETPC()); + return fdret; +} + +uint64_t helper_float_mina_d(CPUMIPSState *env, uint64_t fs, uint64_t ft) +{ + uint64_t fdret; + + fdret = float64_minnummag(fs, ft, &env->active_fpu.fp_status); + + update_fcr31(env, GETPC()); + return fdret; +} -FLOAT_MINMAX(min_s, 32, minnum) -FLOAT_MINMAX(min_d, 64, minnum) -FLOAT_MINMAX(mina_s, 32, minnummag) -FLOAT_MINMAX(mina_d, 64, minnummag) -#undef FLOAT_MINMAX /* ternary operations */ @@ -1647,25 +1724,54 @@ uint64_t helper_float_nmsub_ps(CPUMIPSState *env, uint64_t fdt0, } -#define FLOAT_FMADDSUB(name, bits, muladd_arg) \ -uint ## bits ## _t helper_float_ ## name(CPUMIPSState *env, \ - uint ## bits ## _t fs, \ - uint ## bits ## _t ft, \ - uint ## bits ## _t fd) \ -{ \ - uint ## bits ## _t fdret; \ - \ - fdret = float ## bits ## _muladd(fs, ft, fd, muladd_arg, \ - &env->active_fpu.fp_status); \ - update_fcr31(env, GETPC()); \ - return fdret; \ +uint32_t helper_float_maddf_s(CPUMIPSState *env, uint32_t fs, + uint32_t ft, uint32_t fd) +{ + uint32_t fdret; + + fdret = float32_muladd(fs, ft, fd, 0, + &env->active_fpu.fp_status); + + update_fcr31(env, GETPC()); + return fdret; +} + +uint64_t helper_float_maddf_d(CPUMIPSState *env, uint64_t fs, + uint64_t ft, uint64_t fd) +{ + uint64_t fdret; + + fdret = float64_muladd(fs, ft, fd, 0, + &env->active_fpu.fp_status); + + update_fcr31(env, GETPC()); + return fdret; +} + +uint32_t helper_float_msubf_s(CPUMIPSState *env, uint32_t fs, + uint32_t ft, uint32_t fd) +{ + uint32_t fdret; + + fdret = float32_muladd(fs, ft, fd, float_muladd_negate_product, + &env->active_fpu.fp_status); + + update_fcr31(env, GETPC()); + return fdret; +} + +uint64_t helper_float_msubf_d(CPUMIPSState *env, uint64_t fs, + uint64_t ft, uint64_t fd) +{ + uint64_t fdret; + + fdret = float64_muladd(fs, ft, fd, float_muladd_negate_product, + &env->active_fpu.fp_status); + + update_fcr31(env, GETPC()); + return fdret; } -FLOAT_FMADDSUB(maddf_s, 32, 0) -FLOAT_FMADDSUB(maddf_d, 64, 0) -FLOAT_FMADDSUB(msubf_s, 32, float_muladd_negate_product) -FLOAT_FMADDSUB(msubf_d, 64, float_muladd_negate_product) -#undef FLOAT_FMADDSUB /* compare operations */ #define FOP_COND_D(op, cond) \ diff --git a/target/mips/internal.h b/target/mips/internal.h index 7f159a9230..dd8a7809b6 100644 --- a/target/mips/internal.h +++ b/target/mips/internal.h @@ -144,6 +144,7 @@ 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); +uint32_t cpu_mips_get_random(CPUMIPSState *env); void mips_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr, vaddr addr, unsigned size, @@ -188,7 +189,7 @@ static inline bool cpu_mips_hw_interrupts_pending(CPUMIPSState *env) /* * 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. + * the status lines as a vector level, not as individual masks. */ r = pending > status; } else { @@ -209,7 +210,6 @@ 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); diff --git a/target/mips/op_helper.c b/target/mips/op_helper.c index 9552b280e0..0050d0616b 100644 --- a/target/mips/op_helper.c +++ b/target/mips/op_helper.c @@ -1574,15 +1574,34 @@ void helper_msa_st_d(CPUMIPSState *env, uint32_t wd, void helper_cache(CPUMIPSState *env, target_ulong addr, uint32_t op) { #ifndef CONFIG_USER_ONLY + static const char *const type_name[] = { + "Primary Instruction", + "Primary Data or Unified Primary", + "Tertiary", + "Secondary" + }; + uint32_t cache_type = extract32(op, 0, 2); + uint32_t cache_operation = extract32(op, 2, 3); target_ulong index = addr & 0x1fffffff; - if (op == 9) { - /* Index Store Tag */ + + switch (cache_operation) { + case 0b010: /* Index Store Tag */ memory_region_dispatch_write(env->itc_tag, index, env->CP0_TagLo, MO_64, MEMTXATTRS_UNSPECIFIED); - } else if (op == 5) { - /* Index Load Tag */ + break; + case 0b001: /* Index Load Tag */ memory_region_dispatch_read(env->itc_tag, index, &env->CP0_TagLo, MO_64, MEMTXATTRS_UNSPECIFIED); + break; + case 0b000: /* Index Invalidate */ + case 0b100: /* Hit Invalidate */ + case 0b110: /* Hit Writeback */ + /* no-op */ + break; + default: + qemu_log_mask(LOG_UNIMP, "cache operation:%u (type: %s cache)\n", + cache_operation, type_name[cache_type]); + break; } #endif } diff --git a/target/mips/translate.c b/target/mips/translate.c index 398edf7289..f449758606 100644 --- a/target/mips/translate.c +++ b/target/mips/translate.c @@ -460,6 +460,48 @@ enum { R6_OPC_SCD = 0x27 | OPC_SPECIAL3, }; +/* Loongson EXT load/store quad word opcodes */ +#define MASK_LOONGSON_GSLSQ(op) (MASK_OP_MAJOR(op) | (op & 0x8020)) +enum { + OPC_GSLQ = 0x0020 | OPC_LWC2, + OPC_GSLQC1 = 0x8020 | OPC_LWC2, + OPC_GSSHFL = OPC_LWC2, + OPC_GSSQ = 0x0020 | OPC_SWC2, + OPC_GSSQC1 = 0x8020 | OPC_SWC2, + OPC_GSSHFS = OPC_SWC2, +}; + +/* Loongson EXT shifted load/store opcodes */ +#define MASK_LOONGSON_GSSHFLS(op) (MASK_OP_MAJOR(op) | (op & 0xc03f)) +enum { + OPC_GSLWLC1 = 0x4 | OPC_GSSHFL, + OPC_GSLWRC1 = 0x5 | OPC_GSSHFL, + OPC_GSLDLC1 = 0x6 | OPC_GSSHFL, + OPC_GSLDRC1 = 0x7 | OPC_GSSHFL, + OPC_GSSWLC1 = 0x4 | OPC_GSSHFS, + OPC_GSSWRC1 = 0x5 | OPC_GSSHFS, + OPC_GSSDLC1 = 0x6 | OPC_GSSHFS, + OPC_GSSDRC1 = 0x7 | OPC_GSSHFS, +}; + +/* Loongson EXT LDC2/SDC2 opcodes */ +#define MASK_LOONGSON_LSDC2(op) (MASK_OP_MAJOR(op) | (op & 0x7)) + +enum { + OPC_GSLBX = 0x0 | OPC_LDC2, + OPC_GSLHX = 0x1 | OPC_LDC2, + OPC_GSLWX = 0x2 | OPC_LDC2, + OPC_GSLDX = 0x3 | OPC_LDC2, + OPC_GSLWXC1 = 0x6 | OPC_LDC2, + OPC_GSLDXC1 = 0x7 | OPC_LDC2, + OPC_GSSBX = 0x0 | OPC_SDC2, + OPC_GSSHX = 0x1 | OPC_SDC2, + OPC_GSSWX = 0x2 | OPC_SDC2, + OPC_GSSDX = 0x3 | OPC_SDC2, + OPC_GSSWXC1 = 0x6 | OPC_SDC2, + OPC_GSSDXC1 = 0x7 | OPC_SDC2, +}; + /* BSHFL opcodes */ #define MASK_BSHFL(op) (MASK_SPECIAL3(op) | (op & (0x1F << 6))) @@ -3718,7 +3760,7 @@ static void gen_st_cond(DisasContext *ctx, int rt, int base, int offset, t0 = tcg_temp_new(); addr = tcg_temp_new(); - /* compare the address against that of the preceeding LL */ + /* compare the address against that of the preceding LL */ gen_base_offset_addr(ctx, addr, base, offset); tcg_gen_brcond_tl(TCG_COND_EQ, addr, cpu_lladdr, l1); tcg_temp_free(addr); @@ -5910,6 +5952,403 @@ no_rd: tcg_temp_free_i64(t1); } +static void gen_loongson_lswc2(DisasContext *ctx, int rt, + int rs, int rd) +{ + TCGv t0, t1, t2; + TCGv_i32 fp0; +#if defined(TARGET_MIPS64) + int lsq_rt1 = ctx->opcode & 0x1f; + int lsq_offset = sextract32(ctx->opcode, 6, 9) << 4; +#endif + int shf_offset = sextract32(ctx->opcode, 6, 8); + + t0 = tcg_temp_new(); + + switch (MASK_LOONGSON_GSLSQ(ctx->opcode)) { +#if defined(TARGET_MIPS64) + case OPC_GSLQ: + t1 = tcg_temp_new(); + gen_base_offset_addr(ctx, t0, rs, lsq_offset); + tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_TEQ | + ctx->default_tcg_memop_mask); + gen_base_offset_addr(ctx, t0, rs, lsq_offset + 8); + tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEQ | + ctx->default_tcg_memop_mask); + gen_store_gpr(t1, rt); + gen_store_gpr(t0, lsq_rt1); + tcg_temp_free(t1); + break; + case OPC_GSLQC1: + check_cp1_enabled(ctx); + t1 = tcg_temp_new(); + gen_base_offset_addr(ctx, t0, rs, lsq_offset); + tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_TEQ | + ctx->default_tcg_memop_mask); + gen_base_offset_addr(ctx, t0, rs, lsq_offset + 8); + tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEQ | + ctx->default_tcg_memop_mask); + gen_store_fpr64(ctx, t1, rt); + gen_store_fpr64(ctx, t0, lsq_rt1); + tcg_temp_free(t1); + break; + case OPC_GSSQ: + t1 = tcg_temp_new(); + gen_base_offset_addr(ctx, t0, rs, lsq_offset); + gen_load_gpr(t1, rt); + tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEQ | + ctx->default_tcg_memop_mask); + gen_base_offset_addr(ctx, t0, rs, lsq_offset + 8); + gen_load_gpr(t1, lsq_rt1); + tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEQ | + ctx->default_tcg_memop_mask); + tcg_temp_free(t1); + break; + case OPC_GSSQC1: + check_cp1_enabled(ctx); + t1 = tcg_temp_new(); + gen_base_offset_addr(ctx, t0, rs, lsq_offset); + gen_load_fpr64(ctx, t1, rt); + tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEQ | + ctx->default_tcg_memop_mask); + gen_base_offset_addr(ctx, t0, rs, lsq_offset + 8); + gen_load_fpr64(ctx, t1, lsq_rt1); + tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEQ | + ctx->default_tcg_memop_mask); + tcg_temp_free(t1); + break; +#endif + case OPC_GSSHFL: + switch (MASK_LOONGSON_GSSHFLS(ctx->opcode)) { + case OPC_GSLWLC1: + check_cp1_enabled(ctx); + gen_base_offset_addr(ctx, t0, rs, shf_offset); + t1 = tcg_temp_new(); + tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_UB); + tcg_gen_andi_tl(t1, t0, 3); +#ifndef TARGET_WORDS_BIGENDIAN + tcg_gen_xori_tl(t1, t1, 3); +#endif + tcg_gen_shli_tl(t1, t1, 3); + tcg_gen_andi_tl(t0, t0, ~3); + tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEUL); + tcg_gen_shl_tl(t0, t0, t1); + t2 = tcg_const_tl(-1); + tcg_gen_shl_tl(t2, t2, t1); + fp0 = tcg_temp_new_i32(); + gen_load_fpr32(ctx, fp0, rt); + tcg_gen_ext_i32_tl(t1, fp0); + tcg_gen_andc_tl(t1, t1, t2); + tcg_temp_free(t2); + tcg_gen_or_tl(t0, t0, t1); + tcg_temp_free(t1); +#if defined(TARGET_MIPS64) + tcg_gen_extrl_i64_i32(fp0, t0); +#else + tcg_gen_ext32s_tl(fp0, t0); +#endif + gen_store_fpr32(ctx, fp0, rt); + tcg_temp_free_i32(fp0); + break; + case OPC_GSLWRC1: + check_cp1_enabled(ctx); + gen_base_offset_addr(ctx, t0, rs, shf_offset); + t1 = tcg_temp_new(); + tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_UB); + tcg_gen_andi_tl(t1, t0, 3); +#ifdef TARGET_WORDS_BIGENDIAN + tcg_gen_xori_tl(t1, t1, 3); +#endif + tcg_gen_shli_tl(t1, t1, 3); + tcg_gen_andi_tl(t0, t0, ~3); + tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEUL); + tcg_gen_shr_tl(t0, t0, t1); + tcg_gen_xori_tl(t1, t1, 31); + t2 = tcg_const_tl(0xfffffffeull); + tcg_gen_shl_tl(t2, t2, t1); + fp0 = tcg_temp_new_i32(); + gen_load_fpr32(ctx, fp0, rt); + tcg_gen_ext_i32_tl(t1, fp0); + tcg_gen_and_tl(t1, t1, t2); + tcg_temp_free(t2); + tcg_gen_or_tl(t0, t0, t1); + tcg_temp_free(t1); +#if defined(TARGET_MIPS64) + tcg_gen_extrl_i64_i32(fp0, t0); +#else + tcg_gen_ext32s_tl(fp0, t0); +#endif + gen_store_fpr32(ctx, fp0, rt); + tcg_temp_free_i32(fp0); + break; +#if defined(TARGET_MIPS64) + case OPC_GSLDLC1: + check_cp1_enabled(ctx); + gen_base_offset_addr(ctx, t0, rs, shf_offset); + t1 = tcg_temp_new(); + tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_UB); + tcg_gen_andi_tl(t1, t0, 7); +#ifndef TARGET_WORDS_BIGENDIAN + tcg_gen_xori_tl(t1, t1, 7); +#endif + tcg_gen_shli_tl(t1, t1, 3); + tcg_gen_andi_tl(t0, t0, ~7); + tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEQ); + tcg_gen_shl_tl(t0, t0, t1); + t2 = tcg_const_tl(-1); + tcg_gen_shl_tl(t2, t2, t1); + gen_load_fpr64(ctx, t1, rt); + tcg_gen_andc_tl(t1, t1, t2); + tcg_temp_free(t2); + tcg_gen_or_tl(t0, t0, t1); + tcg_temp_free(t1); + gen_store_fpr64(ctx, t0, rt); + break; + case OPC_GSLDRC1: + check_cp1_enabled(ctx); + gen_base_offset_addr(ctx, t0, rs, shf_offset); + t1 = tcg_temp_new(); + tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_UB); + tcg_gen_andi_tl(t1, t0, 7); +#ifdef TARGET_WORDS_BIGENDIAN + tcg_gen_xori_tl(t1, t1, 7); +#endif + tcg_gen_shli_tl(t1, t1, 3); + tcg_gen_andi_tl(t0, t0, ~7); + tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEQ); + tcg_gen_shr_tl(t0, t0, t1); + tcg_gen_xori_tl(t1, t1, 63); + t2 = tcg_const_tl(0xfffffffffffffffeull); + tcg_gen_shl_tl(t2, t2, t1); + gen_load_fpr64(ctx, t1, rt); + tcg_gen_and_tl(t1, t1, t2); + tcg_temp_free(t2); + tcg_gen_or_tl(t0, t0, t1); + tcg_temp_free(t1); + gen_store_fpr64(ctx, t0, rt); + break; +#endif + default: + MIPS_INVAL("loongson_gsshfl"); + generate_exception_end(ctx, EXCP_RI); + break; + } + break; + case OPC_GSSHFS: + switch (MASK_LOONGSON_GSSHFLS(ctx->opcode)) { + case OPC_GSSWLC1: + check_cp1_enabled(ctx); + t1 = tcg_temp_new(); + gen_base_offset_addr(ctx, t0, rs, shf_offset); + fp0 = tcg_temp_new_i32(); + gen_load_fpr32(ctx, fp0, rt); + tcg_gen_ext_i32_tl(t1, fp0); + gen_helper_0e2i(swl, t1, t0, ctx->mem_idx); + tcg_temp_free_i32(fp0); + tcg_temp_free(t1); + break; + case OPC_GSSWRC1: + check_cp1_enabled(ctx); + t1 = tcg_temp_new(); + gen_base_offset_addr(ctx, t0, rs, shf_offset); + fp0 = tcg_temp_new_i32(); + gen_load_fpr32(ctx, fp0, rt); + tcg_gen_ext_i32_tl(t1, fp0); + gen_helper_0e2i(swr, t1, t0, ctx->mem_idx); + tcg_temp_free_i32(fp0); + tcg_temp_free(t1); + break; +#if defined(TARGET_MIPS64) + case OPC_GSSDLC1: + check_cp1_enabled(ctx); + t1 = tcg_temp_new(); + gen_base_offset_addr(ctx, t0, rs, shf_offset); + gen_load_fpr64(ctx, t1, rt); + gen_helper_0e2i(sdl, t1, t0, ctx->mem_idx); + tcg_temp_free(t1); + break; + case OPC_GSSDRC1: + check_cp1_enabled(ctx); + t1 = tcg_temp_new(); + gen_base_offset_addr(ctx, t0, rs, shf_offset); + gen_load_fpr64(ctx, t1, rt); + gen_helper_0e2i(sdr, t1, t0, ctx->mem_idx); + tcg_temp_free(t1); + break; +#endif + default: + MIPS_INVAL("loongson_gsshfs"); + generate_exception_end(ctx, EXCP_RI); + break; + } + break; + default: + MIPS_INVAL("loongson_gslsq"); + generate_exception_end(ctx, EXCP_RI); + break; + } + tcg_temp_free(t0); +} + +/* Loongson EXT LDC2/SDC2 */ +static void gen_loongson_lsdc2(DisasContext *ctx, int rt, + int rs, int rd) +{ + int offset = sextract32(ctx->opcode, 3, 8); + uint32_t opc = MASK_LOONGSON_LSDC2(ctx->opcode); + TCGv t0, t1; + TCGv_i32 fp0; + + /* Pre-conditions */ + switch (opc) { + case OPC_GSLBX: + case OPC_GSLHX: + case OPC_GSLWX: + case OPC_GSLDX: + /* prefetch, implement as NOP */ + if (rt == 0) { + return; + } + break; + case OPC_GSSBX: + case OPC_GSSHX: + case OPC_GSSWX: + case OPC_GSSDX: + break; + case OPC_GSLWXC1: +#if defined(TARGET_MIPS64) + case OPC_GSLDXC1: +#endif + check_cp1_enabled(ctx); + /* prefetch, implement as NOP */ + if (rt == 0) { + return; + } + break; + case OPC_GSSWXC1: +#if defined(TARGET_MIPS64) + case OPC_GSSDXC1: +#endif + check_cp1_enabled(ctx); + break; + default: + MIPS_INVAL("loongson_lsdc2"); + generate_exception_end(ctx, EXCP_RI); + return; + break; + } + + t0 = tcg_temp_new(); + + gen_base_offset_addr(ctx, t0, rs, offset); + gen_op_addr_add(ctx, t0, cpu_gpr[rd], t0); + + switch (opc) { + case OPC_GSLBX: + tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_SB); + gen_store_gpr(t0, rt); + break; + case OPC_GSLHX: + tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TESW | + ctx->default_tcg_memop_mask); + gen_store_gpr(t0, rt); + break; + case OPC_GSLWX: + gen_base_offset_addr(ctx, t0, rs, offset); + if (rd) { + gen_op_addr_add(ctx, t0, cpu_gpr[rd], t0); + } + tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TESL | + ctx->default_tcg_memop_mask); + gen_store_gpr(t0, rt); + break; +#if defined(TARGET_MIPS64) + case OPC_GSLDX: + gen_base_offset_addr(ctx, t0, rs, offset); + if (rd) { + gen_op_addr_add(ctx, t0, cpu_gpr[rd], t0); + } + tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEQ | + ctx->default_tcg_memop_mask); + gen_store_gpr(t0, rt); + break; +#endif + case OPC_GSLWXC1: + check_cp1_enabled(ctx); + gen_base_offset_addr(ctx, t0, rs, offset); + if (rd) { + gen_op_addr_add(ctx, t0, cpu_gpr[rd], t0); + } + fp0 = tcg_temp_new_i32(); + tcg_gen_qemu_ld_i32(fp0, t0, ctx->mem_idx, MO_TESL | + ctx->default_tcg_memop_mask); + gen_store_fpr32(ctx, fp0, rt); + tcg_temp_free_i32(fp0); + break; +#if defined(TARGET_MIPS64) + case OPC_GSLDXC1: + check_cp1_enabled(ctx); + gen_base_offset_addr(ctx, t0, rs, offset); + if (rd) { + gen_op_addr_add(ctx, t0, cpu_gpr[rd], t0); + } + tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEQ | + ctx->default_tcg_memop_mask); + gen_store_fpr64(ctx, t0, rt); + break; +#endif + case OPC_GSSBX: + t1 = tcg_temp_new(); + gen_load_gpr(t1, rt); + tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_SB); + tcg_temp_free(t1); + break; + case OPC_GSSHX: + t1 = tcg_temp_new(); + gen_load_gpr(t1, rt); + tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUW | + ctx->default_tcg_memop_mask); + tcg_temp_free(t1); + break; + case OPC_GSSWX: + t1 = tcg_temp_new(); + gen_load_gpr(t1, rt); + tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUL | + ctx->default_tcg_memop_mask); + tcg_temp_free(t1); + break; +#if defined(TARGET_MIPS64) + case OPC_GSSDX: + t1 = tcg_temp_new(); + gen_load_gpr(t1, rt); + tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEQ | + ctx->default_tcg_memop_mask); + tcg_temp_free(t1); + break; +#endif + case OPC_GSSWXC1: + fp0 = tcg_temp_new_i32(); + gen_load_fpr32(ctx, fp0, rt); + tcg_gen_qemu_st_i32(fp0, t0, ctx->mem_idx, MO_TEUL | + ctx->default_tcg_memop_mask); + tcg_temp_free_i32(fp0); + break; +#if defined(TARGET_MIPS64) + case OPC_GSSDXC1: + t1 = tcg_temp_new(); + gen_load_fpr64(ctx, t1, rt); + tcg_gen_qemu_st_i64(t1, t0, ctx->mem_idx, MO_TEQ | + ctx->default_tcg_memop_mask); + tcg_temp_free(t1); + break; +#endif + default: + break; + } + + tcg_temp_free(t0); +} + /* Traps */ static void gen_trap(DisasContext *ctx, uint32_t opc, int rs, int rt, int16_t imm) @@ -25597,7 +26036,7 @@ static void gen_mxu_D16MAX_D16MIN(DisasContext *ctx) } /* return resulting half-words to its original position */ tcg_gen_shri_i32(t0, t0, 16); - /* finaly update the destination */ + /* finally update the destination */ tcg_gen_or_i32(mxu_gpr[XRa - 1], mxu_gpr[XRa - 1], t0); tcg_temp_free(t1); @@ -25633,7 +26072,7 @@ static void gen_mxu_D16MAX_D16MIN(DisasContext *ctx) } /* return resulting half-words to its original position */ tcg_gen_shri_i32(t0, t0, 16); - /* finaly update the destination */ + /* finally update the destination */ tcg_gen_or_i32(mxu_gpr[XRa - 1], mxu_gpr[XRa - 1], t0); tcg_temp_free(t1); @@ -25702,7 +26141,7 @@ static void gen_mxu_Q8MAX_Q8MIN(DisasContext *ctx) } /* return resulting byte to its original position */ tcg_gen_shri_i32(t0, t0, 8 * (3 - i)); - /* finaly update the destination */ + /* finally update the destination */ tcg_gen_or_i32(mxu_gpr[XRa - 1], mxu_gpr[XRa - 1], t0); } @@ -25742,7 +26181,7 @@ static void gen_mxu_Q8MAX_Q8MIN(DisasContext *ctx) } /* return resulting byte to its original position */ tcg_gen_shri_i32(t0, t0, 8 * (3 - i)); - /* finaly update the destination */ + /* finally update the destination */ tcg_gen_or_i32(mxu_gpr[XRa - 1], mxu_gpr[XRa - 1], t0); } @@ -30774,6 +31213,8 @@ static void decode_opc(CPUMIPSState *env, DisasContext *ctx) /* OPC_BC, OPC_BALC */ gen_compute_compact_branch(ctx, op, 0, 0, sextract32(ctx->opcode << 2, 0, 28)); + } else if (ctx->insn_flags & ASE_LEXT) { + gen_loongson_lswc2(ctx, rt, rs, rd); } else { /* OPC_LWC2, OPC_SWC2 */ /* COP2: Not implemented. */ @@ -30791,6 +31232,8 @@ static void decode_opc(CPUMIPSState *env, DisasContext *ctx) /* OPC_JIC, OPC_JIALC */ gen_compute_compact_branch(ctx, op, 0, rt, imm); } + } else if (ctx->insn_flags & ASE_LEXT) { + gen_loongson_lsdc2(ctx, rt, rs, rd); } else { /* OPC_LWC2, OPC_SWC2 */ /* COP2: Not implemented. */ diff --git a/target/mips/translate_init.c.inc b/target/mips/translate_init.c.inc index 637caccd89..fb5a9b38e5 100644 --- a/target/mips/translate_init.c.inc +++ b/target/mips/translate_init.c.inc @@ -254,7 +254,7 @@ const mips_def_t mips_defs[] = .CP0_PRid = 0x00019500, .CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR) | (MMU_TYPE_R4000 << CP0C0_MT), - .CP0_Config1 = MIPS_CONFIG1 | (1 << CP0C1_FP) | (15 << CP0C1_MMU) | + .CP0_Config1 = MIPS_CONFIG1 | (1 << CP0C1_FP) | (63 << CP0C1_MMU) | (0 << CP0C1_IS) | (3 << CP0C1_IL) | (1 << CP0C1_IA) | (0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA) | (1 << CP0C1_CA), @@ -995,7 +995,7 @@ static void mvp_init (CPUMIPSState *env, const mips_def_t *def) /* MVPConf1 implemented, TLB sharable, no gating storage support, programmable cache partitioning implemented, number of allocatable - and sharable TLB entries, MVP has allocatable TCs, 2 VPEs + and shareable TLB entries, MVP has allocatable TCs, 2 VPEs implemented, 5 TCs implemented. */ env->mvp->CP0_MVPConf0 = (1U << CP0MVPC0_M) | (1 << CP0MVPC0_TLBS) | (0 << CP0MVPC0_GS) | (1 << CP0MVPC0_PCP) | |