Move target-* CPU file into a target/ folder

We've currently got 18 architectures in QEMU, and thus 18 target-xxx
folders in the root folder of the QEMU source tree. More architectures
(e.g. RISC-V, AVR) are likely to be included soon, too, so the main
folder of the QEMU sources slowly gets quite overcrowded with the
target-xxx folders.
To disburden the main folder a little bit, let's move the target-xxx
folders into a dedicated target/ folder, so that target-xxx/ simply
becomes target/xxx/ instead.

Acked-by: Laurent Vivier <laurent@vivier.eu> [m68k part]
Acked-by: Bastian Koppelmann <kbastian@mail.uni-paderborn.de> [tricore part]
Acked-by: Michael Walle <michael@walle.cc> [lm32 part]
Acked-by: Cornelia Huck <cornelia.huck@de.ibm.com> [s390x part]
Reviewed-by: Christian Borntraeger <borntraeger@de.ibm.com> [s390x part]
Acked-by: Eduardo Habkost <ehabkost@redhat.com> [i386 part]
Acked-by: Artyom Tarasenko <atar4qemu@gmail.com> [sparc part]
Acked-by: Richard Henderson <rth@twiddle.net> [alpha part]
Acked-by: Max Filippov <jcmvbkbc@gmail.com> [xtensa part]
Reviewed-by: David Gibson <david@gibson.dropbear.id.au> [ppc part]
Acked-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com> [cris&microblaze part]
Acked-by: Guan Xuetao <gxt@mprc.pku.edu.cn> [unicore32 part]
Signed-off-by: Thomas Huth <thuth@redhat.com>
This commit is contained in:
Thomas Huth 2016-10-11 08:56:52 +02:00
parent 82ecffa8c0
commit fcf5ef2ab5
369 changed files with 78 additions and 80 deletions

View file

@ -0,0 +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_KVM) += kvm.o

51
target/mips/TODO Normal file
View file

@ -0,0 +1,51 @@
Unsolved issues/bugs in the mips/mipsel backend
-----------------------------------------------
General
-------
- Unimplemented ASEs:
- MDMX
- SmartMIPS
- microMIPS DSP r1 & r2 encodings
- MT ASE only partially implemented and not functional
- Shadow register support only partially implemented,
lacks set switching on interrupt/exception.
- 34K ITC not implemented.
- A general lack of documentation, especially for technical internals.
Existing documentation is x86-centric.
- Reverse endianness bit not implemented
- The TLB emulation is very inefficient:
QEMU's softmmu implements a x86-style MMU, with separate entries
for read/write/execute, a TLB index which is just a modulo of the
virtual address, and a set of TLBs for each user/kernel/supervisor
MMU mode.
MIPS has a single entry for read/write/execute and only one MMU mode.
But it is fully associative with randomized entry indices, and uses
up to 256 ASID tags as additional matching criterion (which roughly
equates to 256 MMU modes). It also has a global flag which causes
entries to match regardless of ASID.
To cope with these differences, QEMU currently flushes the TLB at
each ASID change. Using the MMU modes to implement ASIDs hinges on
implementing the global bit efficiently.
- save/restore of the CPU state is not implemented (see machine.c).
MIPS64
------
- Userland emulation (both n32 and n64) not functional.
"Generic" 4Kc system emulation
------------------------------
- Doesn't correspond to any real hardware. Should be removed some day,
U-Boot is the last remaining user.
PICA 61 system emulation
------------------------
- No framebuffer support yet.
MALTA system emulation
----------------------
- We fake firmware support instead of doing the real thing
- Real firmware (YAMON) falls over when trying to init RAM, presumably
due to lacking system controller emulation.
- Bonito system controller not implemented
- MSC1 system controller not implemented

56
target/mips/cpu-qom.h Normal file
View file

@ -0,0 +1,56 @@
/*
* QEMU MIPS CPU
*
* Copyright (c) 2012 SUSE LINUX Products GmbH
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <http://www.gnu.org/licenses/lgpl-2.1.html>
*/
#ifndef QEMU_MIPS_CPU_QOM_H
#define QEMU_MIPS_CPU_QOM_H
#include "qom/cpu.h"
#ifdef TARGET_MIPS64
#define TYPE_MIPS_CPU "mips64-cpu"
#else
#define TYPE_MIPS_CPU "mips-cpu"
#endif
#define MIPS_CPU_CLASS(klass) \
OBJECT_CLASS_CHECK(MIPSCPUClass, (klass), TYPE_MIPS_CPU)
#define MIPS_CPU(obj) \
OBJECT_CHECK(MIPSCPU, (obj), TYPE_MIPS_CPU)
#define MIPS_CPU_GET_CLASS(obj) \
OBJECT_GET_CLASS(MIPSCPUClass, (obj), TYPE_MIPS_CPU)
/**
* MIPSCPUClass:
* @parent_realize: The parent class' realize handler.
* @parent_reset: The parent class' reset handler.
*
* A MIPS CPU model.
*/
typedef struct MIPSCPUClass {
/*< private >*/
CPUClass parent_class;
/*< public >*/
DeviceRealize parent_realize;
void (*parent_reset)(CPUState *cpu);
} MIPSCPUClass;
typedef struct MIPSCPU MIPSCPU;
#endif

203
target/mips/cpu.c Normal file
View file

@ -0,0 +1,203 @@
/*
* QEMU MIPS CPU
*
* Copyright (c) 2012 SUSE LINUX Products GmbH
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <http://www.gnu.org/licenses/lgpl-2.1.html>
*/
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "cpu.h"
#include "kvm_mips.h"
#include "qemu-common.h"
#include "sysemu/kvm.h"
#include "exec/exec-all.h"
static void mips_cpu_set_pc(CPUState *cs, vaddr value)
{
MIPSCPU *cpu = MIPS_CPU(cs);
CPUMIPSState *env = &cpu->env;
env->active_tc.PC = value & ~(target_ulong)1;
if (value & 1) {
env->hflags |= MIPS_HFLAG_M16;
} else {
env->hflags &= ~(MIPS_HFLAG_M16);
}
}
static void mips_cpu_synchronize_from_tb(CPUState *cs, TranslationBlock *tb)
{
MIPSCPU *cpu = MIPS_CPU(cs);
CPUMIPSState *env = &cpu->env;
env->active_tc.PC = tb->pc;
env->hflags &= ~MIPS_HFLAG_BMASK;
env->hflags |= tb->flags & MIPS_HFLAG_BMASK;
}
static bool mips_cpu_has_work(CPUState *cs)
{
MIPSCPU *cpu = MIPS_CPU(cs);
CPUMIPSState *env = &cpu->env;
bool has_work = false;
/* Prior to MIPS Release 6 it is implementation dependent if non-enabled
interrupts wake-up the CPU, however most of the implementations only
check for interrupts that can be taken. */
if ((cs->interrupt_request & CPU_INTERRUPT_HARD) &&
cpu_mips_hw_interrupts_pending(env)) {
if (cpu_mips_hw_interrupts_enabled(env) ||
(env->insn_flags & ISA_MIPS32R6)) {
has_work = true;
}
}
/* MIPS-MT has the ability to halt the CPU. */
if (env->CP0_Config3 & (1 << CP0C3_MT)) {
/* The QEMU model will issue an _WAKE request whenever the CPUs
should be woken up. */
if (cs->interrupt_request & CPU_INTERRUPT_WAKE) {
has_work = true;
}
if (!mips_vpe_active(env)) {
has_work = false;
}
}
/* MIPS Release 6 has the ability to halt the CPU. */
if (env->CP0_Config5 & (1 << CP0C5_VP)) {
if (cs->interrupt_request & CPU_INTERRUPT_WAKE) {
has_work = true;
}
if (!mips_vp_active(env)) {
has_work = false;
}
}
return has_work;
}
/* CPUClass::reset() */
static void mips_cpu_reset(CPUState *s)
{
MIPSCPU *cpu = MIPS_CPU(s);
MIPSCPUClass *mcc = MIPS_CPU_GET_CLASS(cpu);
CPUMIPSState *env = &cpu->env;
mcc->parent_reset(s);
memset(env, 0, offsetof(CPUMIPSState, mvp));
tlb_flush(s, 1);
cpu_state_reset(env);
#ifndef CONFIG_USER_ONLY
if (kvm_enabled()) {
kvm_mips_reset_vcpu(cpu);
}
#endif
}
static void mips_cpu_disas_set_info(CPUState *s, disassemble_info *info) {
#ifdef TARGET_WORDS_BIGENDIAN
info->print_insn = print_insn_big_mips;
#else
info->print_insn = print_insn_little_mips;
#endif
}
static void mips_cpu_realizefn(DeviceState *dev, Error **errp)
{
CPUState *cs = CPU(dev);
MIPSCPUClass *mcc = MIPS_CPU_GET_CLASS(dev);
Error *local_err = NULL;
cpu_exec_realizefn(cs, &local_err);
if (local_err != NULL) {
error_propagate(errp, local_err);
return;
}
cpu_reset(cs);
qemu_init_vcpu(cs);
mcc->parent_realize(dev, errp);
}
static void mips_cpu_initfn(Object *obj)
{
CPUState *cs = CPU(obj);
MIPSCPU *cpu = MIPS_CPU(obj);
CPUMIPSState *env = &cpu->env;
cs->env_ptr = env;
if (tcg_enabled()) {
mips_tcg_init();
}
}
static void mips_cpu_class_init(ObjectClass *c, void *data)
{
MIPSCPUClass *mcc = MIPS_CPU_CLASS(c);
CPUClass *cc = CPU_CLASS(c);
DeviceClass *dc = DEVICE_CLASS(c);
mcc->parent_realize = dc->realize;
dc->realize = mips_cpu_realizefn;
mcc->parent_reset = cc->reset;
cc->reset = mips_cpu_reset;
cc->has_work = mips_cpu_has_work;
cc->do_interrupt = mips_cpu_do_interrupt;
cc->cpu_exec_interrupt = mips_cpu_exec_interrupt;
cc->dump_state = mips_cpu_dump_state;
cc->set_pc = mips_cpu_set_pc;
cc->synchronize_from_tb = mips_cpu_synchronize_from_tb;
cc->gdb_read_register = mips_cpu_gdb_read_register;
cc->gdb_write_register = mips_cpu_gdb_write_register;
#ifdef CONFIG_USER_ONLY
cc->handle_mmu_fault = mips_cpu_handle_mmu_fault;
#else
cc->do_unassigned_access = mips_cpu_unassigned_access;
cc->do_unaligned_access = mips_cpu_do_unaligned_access;
cc->get_phys_page_debug = mips_cpu_get_phys_page_debug;
cc->vmsd = &vmstate_mips_cpu;
#endif
cc->disas_set_info = mips_cpu_disas_set_info;
cc->gdb_num_core_regs = 73;
cc->gdb_stop_before_watchpoint = true;
}
static const TypeInfo mips_cpu_type_info = {
.name = TYPE_MIPS_CPU,
.parent = TYPE_CPU,
.instance_size = sizeof(MIPSCPU),
.instance_init = mips_cpu_initfn,
.abstract = false,
.class_size = sizeof(MIPSCPUClass),
.class_init = mips_cpu_class_init,
};
static void mips_cpu_register_types(void)
{
type_register_static(&mips_cpu_type_info);
}
type_init(mips_cpu_register_types)

1069
target/mips/cpu.h Normal file

File diff suppressed because it is too large Load diff

3762
target/mips/dsp_helper.c Normal file

File diff suppressed because it is too large Load diff

149
target/mips/gdbstub.c Normal file
View file

@ -0,0 +1,149 @@
/*
* MIPS gdb server stub
*
* Copyright (c) 2003-2005 Fabrice Bellard
* Copyright (c) 2013 SUSE LINUX Products GmbH
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include "qemu/osdep.h"
#include "qemu-common.h"
#include "cpu.h"
#include "exec/gdbstub.h"
int mips_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
{
MIPSCPU *cpu = MIPS_CPU(cs);
CPUMIPSState *env = &cpu->env;
if (n < 32) {
return gdb_get_regl(mem_buf, env->active_tc.gpr[n]);
}
if (env->CP0_Config1 & (1 << CP0C1_FP) && n >= 38 && n < 72) {
switch (n) {
case 70:
return gdb_get_regl(mem_buf, (int32_t)env->active_fpu.fcr31);
case 71:
return gdb_get_regl(mem_buf, (int32_t)env->active_fpu.fcr0);
default:
if (env->CP0_Status & (1 << CP0St_FR)) {
return gdb_get_regl(mem_buf,
env->active_fpu.fpr[n - 38].d);
} else {
return gdb_get_regl(mem_buf,
env->active_fpu.fpr[n - 38].w[FP_ENDIAN_IDX]);
}
}
}
switch (n) {
case 32:
return gdb_get_regl(mem_buf, (int32_t)env->CP0_Status);
case 33:
return gdb_get_regl(mem_buf, env->active_tc.LO[0]);
case 34:
return gdb_get_regl(mem_buf, env->active_tc.HI[0]);
case 35:
return gdb_get_regl(mem_buf, env->CP0_BadVAddr);
case 36:
return gdb_get_regl(mem_buf, (int32_t)env->CP0_Cause);
case 37:
return gdb_get_regl(mem_buf, env->active_tc.PC |
!!(env->hflags & MIPS_HFLAG_M16));
case 72:
return gdb_get_regl(mem_buf, 0); /* fp */
case 89:
return gdb_get_regl(mem_buf, (int32_t)env->CP0_PRid);
default:
if (n > 89) {
return 0;
}
/* 16 embedded regs. */
return gdb_get_regl(mem_buf, 0);
}
return 0;
}
int mips_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
{
MIPSCPU *cpu = MIPS_CPU(cs);
CPUMIPSState *env = &cpu->env;
target_ulong tmp;
tmp = ldtul_p(mem_buf);
if (n < 32) {
env->active_tc.gpr[n] = tmp;
return sizeof(target_ulong);
}
if (env->CP0_Config1 & (1 << CP0C1_FP) && n >= 38 && n < 72) {
switch (n) {
case 70:
env->active_fpu.fcr31 = (tmp & env->active_fpu.fcr31_rw_bitmask) |
(env->active_fpu.fcr31 & ~(env->active_fpu.fcr31_rw_bitmask));
restore_fp_status(env);
break;
case 71:
/* FIR is read-only. Ignore writes. */
break;
default:
if (env->CP0_Status & (1 << CP0St_FR)) {
env->active_fpu.fpr[n - 38].d = tmp;
} else {
env->active_fpu.fpr[n - 38].w[FP_ENDIAN_IDX] = tmp;
}
break;
}
return sizeof(target_ulong);
}
switch (n) {
case 32:
#ifndef CONFIG_USER_ONLY
cpu_mips_store_status(env, tmp);
#endif
break;
case 33:
env->active_tc.LO[0] = tmp;
break;
case 34:
env->active_tc.HI[0] = tmp;
break;
case 35:
env->CP0_BadVAddr = tmp;
break;
case 36:
#ifndef CONFIG_USER_ONLY
cpu_mips_store_cause(env, tmp);
#endif
break;
case 37:
env->active_tc.PC = tmp & ~(target_ulong)1;
if (tmp & 1) {
env->hflags |= MIPS_HFLAG_M16;
} else {
env->hflags &= ~(MIPS_HFLAG_M16);
}
break;
case 72: /* fp, ignored */
break;
default:
if (n > 89) {
return 0;
}
/* Other registers are readonly. Ignore writes. */
break;
}
return sizeof(target_ulong);
}

969
target/mips/helper.c Normal file
View file

@ -0,0 +1,969 @@
/*
* MIPS emulation helpers for qemu.
*
* Copyright (c) 2004-2005 Jocelyn Mayer
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include "qemu/osdep.h"
#include "cpu.h"
#include "sysemu/kvm.h"
#include "exec/exec-all.h"
#include "exec/cpu_ldst.h"
#include "exec/log.h"
enum {
TLBRET_XI = -6,
TLBRET_RI = -5,
TLBRET_DIRTY = -4,
TLBRET_INVALID = -3,
TLBRET_NOMATCH = -2,
TLBRET_BADADDR = -1,
TLBRET_MATCH = 0
};
#if !defined(CONFIG_USER_ONLY)
/* no MMU emulation */
int no_mmu_map_address (CPUMIPSState *env, hwaddr *physical, int *prot,
target_ulong address, int rw, int access_type)
{
*physical = address;
*prot = PAGE_READ | PAGE_WRITE;
return TLBRET_MATCH;
}
/* fixed mapping MMU emulation */
int fixed_mmu_map_address (CPUMIPSState *env, hwaddr *physical, int *prot,
target_ulong address, int rw, int access_type)
{
if (address <= (int32_t)0x7FFFFFFFUL) {
if (!(env->CP0_Status & (1 << CP0St_ERL)))
*physical = address + 0x40000000UL;
else
*physical = address;
} else if (address <= (int32_t)0xBFFFFFFFUL)
*physical = address & 0x1FFFFFFF;
else
*physical = address;
*prot = PAGE_READ | PAGE_WRITE;
return TLBRET_MATCH;
}
/* MIPS32/MIPS64 R4000-style MMU emulation */
int r4k_map_address (CPUMIPSState *env, hwaddr *physical, int *prot,
target_ulong address, int rw, int access_type)
{
uint16_t ASID = env->CP0_EntryHi & env->CP0_EntryHi_ASID_mask;
int i;
for (i = 0; i < env->tlb->tlb_in_use; i++) {
r4k_tlb_t *tlb = &env->tlb->mmu.r4k.tlb[i];
/* 1k pages are not supported. */
target_ulong mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
target_ulong tag = address & ~mask;
target_ulong VPN = tlb->VPN & ~mask;
#if defined(TARGET_MIPS64)
tag &= env->SEGMask;
#endif
/* Check ASID, virtual page number & size */
if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag && !tlb->EHINV) {
/* TLB match */
int n = !!(address & mask & ~(mask >> 1));
/* Check access rights */
if (!(n ? tlb->V1 : tlb->V0)) {
return TLBRET_INVALID;
}
if (rw == MMU_INST_FETCH && (n ? tlb->XI1 : tlb->XI0)) {
return TLBRET_XI;
}
if (rw == MMU_DATA_LOAD && (n ? tlb->RI1 : tlb->RI0)) {
return TLBRET_RI;
}
if (rw != MMU_DATA_STORE || (n ? tlb->D1 : tlb->D0)) {
*physical = tlb->PFN[n] | (address & (mask >> 1));
*prot = PAGE_READ;
if (n ? tlb->D1 : tlb->D0)
*prot |= PAGE_WRITE;
return TLBRET_MATCH;
}
return TLBRET_DIRTY;
}
}
return TLBRET_NOMATCH;
}
static int get_physical_address (CPUMIPSState *env, hwaddr *physical,
int *prot, target_ulong real_address,
int rw, int access_type)
{
/* User mode can only access useg/xuseg */
int user_mode = (env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM;
int supervisor_mode = (env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_SM;
int kernel_mode = !user_mode && !supervisor_mode;
#if defined(TARGET_MIPS64)
int UX = (env->CP0_Status & (1 << CP0St_UX)) != 0;
int SX = (env->CP0_Status & (1 << CP0St_SX)) != 0;
int KX = (env->CP0_Status & (1 << CP0St_KX)) != 0;
#endif
int ret = TLBRET_MATCH;
/* effective address (modified for KVM T&E kernel segments) */
target_ulong address = real_address;
#define USEG_LIMIT 0x7FFFFFFFUL
#define KSEG0_BASE 0x80000000UL
#define KSEG1_BASE 0xA0000000UL
#define KSEG2_BASE 0xC0000000UL
#define KSEG3_BASE 0xE0000000UL
#define KVM_KSEG0_BASE 0x40000000UL
#define KVM_KSEG2_BASE 0x60000000UL
if (kvm_enabled()) {
/* KVM T&E adds guest kernel segments in useg */
if (real_address >= KVM_KSEG0_BASE) {
if (real_address < KVM_KSEG2_BASE) {
/* kseg0 */
address += KSEG0_BASE - KVM_KSEG0_BASE;
} else if (real_address <= USEG_LIMIT) {
/* kseg2/3 */
address += KSEG2_BASE - KVM_KSEG2_BASE;
}
}
}
if (address <= USEG_LIMIT) {
/* useg */
if (env->CP0_Status & (1 << CP0St_ERL)) {
*physical = address & 0xFFFFFFFF;
*prot = PAGE_READ | PAGE_WRITE;
} else {
ret = env->tlb->map_address(env, physical, prot, real_address, rw, access_type);
}
#if defined(TARGET_MIPS64)
} else if (address < 0x4000000000000000ULL) {
/* xuseg */
if (UX && address <= (0x3FFFFFFFFFFFFFFFULL & env->SEGMask)) {
ret = env->tlb->map_address(env, physical, prot, real_address, rw, access_type);
} else {
ret = TLBRET_BADADDR;
}
} else if (address < 0x8000000000000000ULL) {
/* xsseg */
if ((supervisor_mode || kernel_mode) &&
SX && address <= (0x7FFFFFFFFFFFFFFFULL & env->SEGMask)) {
ret = env->tlb->map_address(env, physical, prot, real_address, rw, access_type);
} else {
ret = TLBRET_BADADDR;
}
} else if (address < 0xC000000000000000ULL) {
/* xkphys */
if (kernel_mode && KX &&
(address & 0x07FFFFFFFFFFFFFFULL) <= env->PAMask) {
*physical = address & env->PAMask;
*prot = PAGE_READ | PAGE_WRITE;
} else {
ret = TLBRET_BADADDR;
}
} else if (address < 0xFFFFFFFF80000000ULL) {
/* xkseg */
if (kernel_mode && KX &&
address <= (0xFFFFFFFF7FFFFFFFULL & env->SEGMask)) {
ret = env->tlb->map_address(env, physical, prot, real_address, rw, access_type);
} else {
ret = TLBRET_BADADDR;
}
#endif
} else if (address < (int32_t)KSEG1_BASE) {
/* kseg0 */
if (kernel_mode) {
*physical = address - (int32_t)KSEG0_BASE;
*prot = PAGE_READ | PAGE_WRITE;
} else {
ret = TLBRET_BADADDR;
}
} else if (address < (int32_t)KSEG2_BASE) {
/* kseg1 */
if (kernel_mode) {
*physical = address - (int32_t)KSEG1_BASE;
*prot = PAGE_READ | PAGE_WRITE;
} else {
ret = TLBRET_BADADDR;
}
} else if (address < (int32_t)KSEG3_BASE) {
/* sseg (kseg2) */
if (supervisor_mode || kernel_mode) {
ret = env->tlb->map_address(env, physical, prot, real_address, rw, access_type);
} else {
ret = TLBRET_BADADDR;
}
} else {
/* kseg3 */
/* XXX: debug segment is not emulated */
if (kernel_mode) {
ret = env->tlb->map_address(env, physical, prot, real_address, rw, access_type);
} else {
ret = TLBRET_BADADDR;
}
}
return ret;
}
void cpu_mips_tlb_flush(CPUMIPSState *env, int flush_global)
{
MIPSCPU *cpu = mips_env_get_cpu(env);
/* Flush qemu's TLB and discard all shadowed entries. */
tlb_flush(CPU(cpu), flush_global);
env->tlb->tlb_in_use = env->tlb->nb_tlb;
}
/* Called for updates to CP0_Status. */
void sync_c0_status(CPUMIPSState *env, CPUMIPSState *cpu, int tc)
{
int32_t tcstatus, *tcst;
uint32_t v = cpu->CP0_Status;
uint32_t cu, mx, asid, ksu;
uint32_t mask = ((1 << CP0TCSt_TCU3)
| (1 << CP0TCSt_TCU2)
| (1 << CP0TCSt_TCU1)
| (1 << CP0TCSt_TCU0)
| (1 << CP0TCSt_TMX)
| (3 << CP0TCSt_TKSU)
| (0xff << CP0TCSt_TASID));
cu = (v >> CP0St_CU0) & 0xf;
mx = (v >> CP0St_MX) & 0x1;
ksu = (v >> CP0St_KSU) & 0x3;
asid = env->CP0_EntryHi & env->CP0_EntryHi_ASID_mask;
tcstatus = cu << CP0TCSt_TCU0;
tcstatus |= mx << CP0TCSt_TMX;
tcstatus |= ksu << CP0TCSt_TKSU;
tcstatus |= asid;
if (tc == cpu->current_tc) {
tcst = &cpu->active_tc.CP0_TCStatus;
} else {
tcst = &cpu->tcs[tc].CP0_TCStatus;
}
*tcst &= ~mask;
*tcst |= tcstatus;
compute_hflags(cpu);
}
void cpu_mips_store_status(CPUMIPSState *env, target_ulong val)
{
uint32_t mask = env->CP0_Status_rw_bitmask;
target_ulong old = env->CP0_Status;
if (env->insn_flags & ISA_MIPS32R6) {
bool has_supervisor = extract32(mask, CP0St_KSU, 2) == 0x3;
#if defined(TARGET_MIPS64)
uint32_t ksux = (1 << CP0St_KX) & val;
ksux |= (ksux >> 1) & val; /* KX = 0 forces SX to be 0 */
ksux |= (ksux >> 1) & val; /* SX = 0 forces UX to be 0 */
val = (val & ~(7 << CP0St_UX)) | ksux;
#endif
if (has_supervisor && extract32(val, CP0St_KSU, 2) == 0x3) {
mask &= ~(3 << CP0St_KSU);
}
mask &= ~(((1 << CP0St_SR) | (1 << CP0St_NMI)) & val);
}
env->CP0_Status = (old & ~mask) | (val & mask);
#if defined(TARGET_MIPS64)
if ((env->CP0_Status ^ old) & (old & (7 << CP0St_UX))) {
/* Access to at least one of the 64-bit segments has been disabled */
cpu_mips_tlb_flush(env, 1);
}
#endif
if (env->CP0_Config3 & (1 << CP0C3_MT)) {
sync_c0_status(env, env, env->current_tc);
} else {
compute_hflags(env);
}
}
void cpu_mips_store_cause(CPUMIPSState *env, target_ulong val)
{
uint32_t mask = 0x00C00300;
uint32_t old = env->CP0_Cause;
int i;
if (env->insn_flags & ISA_MIPS32R2) {
mask |= 1 << CP0Ca_DC;
}
if (env->insn_flags & ISA_MIPS32R6) {
mask &= ~((1 << CP0Ca_WP) & val);
}
env->CP0_Cause = (env->CP0_Cause & ~mask) | (val & mask);
if ((old ^ env->CP0_Cause) & (1 << CP0Ca_DC)) {
if (env->CP0_Cause & (1 << CP0Ca_DC)) {
cpu_mips_stop_count(env);
} else {
cpu_mips_start_count(env);
}
}
/* Set/reset software interrupts */
for (i = 0 ; i < 2 ; i++) {
if ((old ^ env->CP0_Cause) & (1 << (CP0Ca_IP + i))) {
cpu_mips_soft_irq(env, i, env->CP0_Cause & (1 << (CP0Ca_IP + i)));
}
}
}
#endif
static void raise_mmu_exception(CPUMIPSState *env, target_ulong address,
int rw, int tlb_error)
{
CPUState *cs = CPU(mips_env_get_cpu(env));
int exception = 0, error_code = 0;
if (rw == MMU_INST_FETCH) {
error_code |= EXCP_INST_NOTAVAIL;
}
switch (tlb_error) {
default:
case TLBRET_BADADDR:
/* Reference to kernel address from user mode or supervisor mode */
/* Reference to supervisor address from user mode */
if (rw == MMU_DATA_STORE) {
exception = EXCP_AdES;
} else {
exception = EXCP_AdEL;
}
break;
case TLBRET_NOMATCH:
/* No TLB match for a mapped address */
if (rw == MMU_DATA_STORE) {
exception = EXCP_TLBS;
} else {
exception = EXCP_TLBL;
}
error_code |= EXCP_TLB_NOMATCH;
break;
case TLBRET_INVALID:
/* TLB match with no valid bit */
if (rw == MMU_DATA_STORE) {
exception = EXCP_TLBS;
} else {
exception = EXCP_TLBL;
}
break;
case TLBRET_DIRTY:
/* TLB match but 'D' bit is cleared */
exception = EXCP_LTLBL;
break;
case TLBRET_XI:
/* Execute-Inhibit Exception */
if (env->CP0_PageGrain & (1 << CP0PG_IEC)) {
exception = EXCP_TLBXI;
} else {
exception = EXCP_TLBL;
}
break;
case TLBRET_RI:
/* Read-Inhibit Exception */
if (env->CP0_PageGrain & (1 << CP0PG_IEC)) {
exception = EXCP_TLBRI;
} else {
exception = EXCP_TLBL;
}
break;
}
/* Raise exception */
env->CP0_BadVAddr = address;
env->CP0_Context = (env->CP0_Context & ~0x007fffff) |
((address >> 9) & 0x007ffff0);
env->CP0_EntryHi = (env->CP0_EntryHi & env->CP0_EntryHi_ASID_mask) |
(env->CP0_EntryHi & (1 << CP0EnHi_EHINV)) |
(address & (TARGET_PAGE_MASK << 1));
#if defined(TARGET_MIPS64)
env->CP0_EntryHi &= env->SEGMask;
env->CP0_XContext =
/* PTEBase */ (env->CP0_XContext & ((~0ULL) << (env->SEGBITS - 7))) |
/* R */ (extract64(address, 62, 2) << (env->SEGBITS - 9)) |
/* BadVPN2 */ (extract64(address, 13, env->SEGBITS - 13) << 4);
#endif
cs->exception_index = exception;
env->error_code = error_code;
}
#if !defined(CONFIG_USER_ONLY)
hwaddr mips_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
{
MIPSCPU *cpu = MIPS_CPU(cs);
hwaddr phys_addr;
int prot;
if (get_physical_address(&cpu->env, &phys_addr, &prot, addr, 0,
ACCESS_INT) != 0) {
return -1;
}
return phys_addr;
}
#endif
int mips_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int rw,
int mmu_idx)
{
MIPSCPU *cpu = MIPS_CPU(cs);
CPUMIPSState *env = &cpu->env;
#if !defined(CONFIG_USER_ONLY)
hwaddr physical;
int prot;
int access_type;
#endif
int ret = 0;
#if 0
log_cpu_state(cs, 0);
#endif
qemu_log_mask(CPU_LOG_MMU,
"%s pc " TARGET_FMT_lx " ad %" VADDR_PRIx " rw %d mmu_idx %d\n",
__func__, env->active_tc.PC, address, rw, mmu_idx);
/* data access */
#if !defined(CONFIG_USER_ONLY)
/* XXX: put correct access by using cpu_restore_state()
correctly */
access_type = ACCESS_INT;
ret = get_physical_address(env, &physical, &prot,
address, rw, access_type);
qemu_log_mask(CPU_LOG_MMU,
"%s address=%" VADDR_PRIx " ret %d physical " TARGET_FMT_plx
" prot %d\n",
__func__, address, ret, physical, prot);
if (ret == TLBRET_MATCH) {
tlb_set_page(cs, address & TARGET_PAGE_MASK,
physical & TARGET_PAGE_MASK, prot | PAGE_EXEC,
mmu_idx, TARGET_PAGE_SIZE);
ret = 0;
} else if (ret < 0)
#endif
{
raise_mmu_exception(env, address, rw, ret);
ret = 1;
}
return ret;
}
#if !defined(CONFIG_USER_ONLY)
hwaddr cpu_mips_translate_address(CPUMIPSState *env, target_ulong address, int rw)
{
hwaddr physical;
int prot;
int access_type;
int ret = 0;
/* data access */
access_type = ACCESS_INT;
ret = get_physical_address(env, &physical, &prot,
address, rw, access_type);
if (ret != TLBRET_MATCH) {
raise_mmu_exception(env, address, rw, ret);
return -1LL;
} else {
return physical;
}
}
static const char * const excp_names[EXCP_LAST + 1] = {
[EXCP_RESET] = "reset",
[EXCP_SRESET] = "soft reset",
[EXCP_DSS] = "debug single step",
[EXCP_DINT] = "debug interrupt",
[EXCP_NMI] = "non-maskable interrupt",
[EXCP_MCHECK] = "machine check",
[EXCP_EXT_INTERRUPT] = "interrupt",
[EXCP_DFWATCH] = "deferred watchpoint",
[EXCP_DIB] = "debug instruction breakpoint",
[EXCP_IWATCH] = "instruction fetch watchpoint",
[EXCP_AdEL] = "address error load",
[EXCP_AdES] = "address error store",
[EXCP_TLBF] = "TLB refill",
[EXCP_IBE] = "instruction bus error",
[EXCP_DBp] = "debug breakpoint",
[EXCP_SYSCALL] = "syscall",
[EXCP_BREAK] = "break",
[EXCP_CpU] = "coprocessor unusable",
[EXCP_RI] = "reserved instruction",
[EXCP_OVERFLOW] = "arithmetic overflow",
[EXCP_TRAP] = "trap",
[EXCP_FPE] = "floating point",
[EXCP_DDBS] = "debug data break store",
[EXCP_DWATCH] = "data watchpoint",
[EXCP_LTLBL] = "TLB modify",
[EXCP_TLBL] = "TLB load",
[EXCP_TLBS] = "TLB store",
[EXCP_DBE] = "data bus error",
[EXCP_DDBL] = "debug data break load",
[EXCP_THREAD] = "thread",
[EXCP_MDMX] = "MDMX",
[EXCP_C2E] = "precise coprocessor 2",
[EXCP_CACHE] = "cache error",
[EXCP_TLBXI] = "TLB execute-inhibit",
[EXCP_TLBRI] = "TLB read-inhibit",
[EXCP_MSADIS] = "MSA disabled",
[EXCP_MSAFPE] = "MSA floating point",
};
#endif
target_ulong exception_resume_pc (CPUMIPSState *env)
{
target_ulong bad_pc;
target_ulong isa_mode;
isa_mode = !!(env->hflags & MIPS_HFLAG_M16);
bad_pc = env->active_tc.PC | isa_mode;
if (env->hflags & MIPS_HFLAG_BMASK) {
/* If the exception was raised from a delay slot, come back to
the jump. */
bad_pc -= (env->hflags & MIPS_HFLAG_B16 ? 2 : 4);
}
return bad_pc;
}
#if !defined(CONFIG_USER_ONLY)
static void set_hflags_for_handler (CPUMIPSState *env)
{
/* Exception handlers are entered in 32-bit mode. */
env->hflags &= ~(MIPS_HFLAG_M16);
/* ...except that microMIPS lets you choose. */
if (env->insn_flags & ASE_MICROMIPS) {
env->hflags |= (!!(env->CP0_Config3
& (1 << CP0C3_ISA_ON_EXC))
<< MIPS_HFLAG_M16_SHIFT);
}
}
static inline void set_badinstr_registers(CPUMIPSState *env)
{
if (env->hflags & MIPS_HFLAG_M16) {
/* TODO: add BadInstr support for microMIPS */
return;
}
if (env->CP0_Config3 & (1 << CP0C3_BI)) {
env->CP0_BadInstr = cpu_ldl_code(env, env->active_tc.PC);
}
if ((env->CP0_Config3 & (1 << CP0C3_BP)) &&
(env->hflags & MIPS_HFLAG_BMASK)) {
env->CP0_BadInstrP = cpu_ldl_code(env, env->active_tc.PC - 4);
}
}
#endif
void mips_cpu_do_interrupt(CPUState *cs)
{
#if !defined(CONFIG_USER_ONLY)
MIPSCPU *cpu = MIPS_CPU(cs);
CPUMIPSState *env = &cpu->env;
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);
}
if (cs->exception_index == EXCP_EXT_INTERRUPT &&
(env->hflags & MIPS_HFLAG_DM)) {
cs->exception_index = EXCP_DINT;
}
offset = 0x180;
switch (cs->exception_index) {
case EXCP_DSS:
env->CP0_Debug |= 1 << CP0DB_DSS;
/* Debug single step cannot be raised inside a delay slot and
resume will always occur on the next instruction
(but we assume the pc has always been updated during
code translation). */
env->CP0_DEPC = env->active_tc.PC | !!(env->hflags & MIPS_HFLAG_M16);
goto enter_debug_mode;
case EXCP_DINT:
env->CP0_Debug |= 1 << CP0DB_DINT;
goto set_DEPC;
case EXCP_DIB:
env->CP0_Debug |= 1 << CP0DB_DIB;
goto set_DEPC;
case EXCP_DBp:
env->CP0_Debug |= 1 << CP0DB_DBp;
goto set_DEPC;
case EXCP_DDBS:
env->CP0_Debug |= 1 << CP0DB_DDBS;
goto set_DEPC;
case EXCP_DDBL:
env->CP0_Debug |= 1 << CP0DB_DDBL;
set_DEPC:
env->CP0_DEPC = exception_resume_pc(env);
env->hflags &= ~MIPS_HFLAG_BMASK;
enter_debug_mode:
if (env->insn_flags & ISA_MIPS3) {
env->hflags |= MIPS_HFLAG_64;
if (!(env->insn_flags & ISA_MIPS64R6) ||
env->CP0_Status & (1 << CP0St_KX)) {
env->hflags &= ~MIPS_HFLAG_AWRAP;
}
}
env->hflags |= MIPS_HFLAG_DM | MIPS_HFLAG_CP0;
env->hflags &= ~(MIPS_HFLAG_KSU);
/* EJTAG probe trap enable is not implemented... */
if (!(env->CP0_Status & (1 << CP0St_EXL)))
env->CP0_Cause &= ~(1U << CP0Ca_BD);
env->active_tc.PC = env->exception_base + 0x480;
set_hflags_for_handler(env);
break;
case EXCP_RESET:
cpu_reset(CPU(cpu));
break;
case EXCP_SRESET:
env->CP0_Status |= (1 << CP0St_SR);
memset(env->CP0_WatchLo, 0, sizeof(env->CP0_WatchLo));
goto set_error_EPC;
case EXCP_NMI:
env->CP0_Status |= (1 << CP0St_NMI);
set_error_EPC:
env->CP0_ErrorEPC = exception_resume_pc(env);
env->hflags &= ~MIPS_HFLAG_BMASK;
env->CP0_Status |= (1 << CP0St_ERL) | (1 << CP0St_BEV);
if (env->insn_flags & ISA_MIPS3) {
env->hflags |= MIPS_HFLAG_64;
if (!(env->insn_flags & ISA_MIPS64R6) ||
env->CP0_Status & (1 << CP0St_KX)) {
env->hflags &= ~MIPS_HFLAG_AWRAP;
}
}
env->hflags |= MIPS_HFLAG_CP0;
env->hflags &= ~(MIPS_HFLAG_KSU);
if (!(env->CP0_Status & (1 << CP0St_EXL)))
env->CP0_Cause &= ~(1U << CP0Ca_BD);
env->active_tc.PC = env->exception_base;
set_hflags_for_handler(env);
break;
case EXCP_EXT_INTERRUPT:
cause = 0;
if (env->CP0_Cause & (1 << CP0Ca_IV)) {
uint32_t spacing = (env->CP0_IntCtl >> CP0IntCtl_VS) & 0x1f;
if ((env->CP0_Status & (1 << CP0St_BEV)) || spacing == 0) {
offset = 0x200;
} else {
uint32_t vector = 0;
uint32_t pending = (env->CP0_Cause & CP0Ca_IP_mask) >> CP0Ca_IP;
if (env->CP0_Config3 & (1 << CP0C3_VEIC)) {
/* For VEIC mode, the external interrupt controller feeds
* the vector through the CP0Cause IP lines. */
vector = pending;
} else {
/* Vectored Interrupts
* Mask with Status.IM7-IM0 to get enabled interrupts. */
pending &= (env->CP0_Status >> CP0St_IM) & 0xff;
/* Find the highest-priority interrupt. */
while (pending >>= 1) {
vector++;
}
}
offset = 0x200 + (vector * (spacing << 5));
}
}
goto set_EPC;
case EXCP_LTLBL:
cause = 1;
update_badinstr = !(env->error_code & EXCP_INST_NOTAVAIL);
goto set_EPC;
case EXCP_TLBL:
cause = 2;
update_badinstr = !(env->error_code & EXCP_INST_NOTAVAIL);
if ((env->error_code & EXCP_TLB_NOMATCH) &&
!(env->CP0_Status & (1 << CP0St_EXL))) {
#if defined(TARGET_MIPS64)
int R = env->CP0_BadVAddr >> 62;
int UX = (env->CP0_Status & (1 << CP0St_UX)) != 0;
int SX = (env->CP0_Status & (1 << CP0St_SX)) != 0;
int KX = (env->CP0_Status & (1 << CP0St_KX)) != 0;
if (((R == 0 && UX) || (R == 1 && SX) || (R == 3 && KX)) &&
(!(env->insn_flags & (INSN_LOONGSON2E | INSN_LOONGSON2F))))
offset = 0x080;
else
#endif
offset = 0x000;
}
goto set_EPC;
case EXCP_TLBS:
cause = 3;
update_badinstr = 1;
if ((env->error_code & EXCP_TLB_NOMATCH) &&
!(env->CP0_Status & (1 << CP0St_EXL))) {
#if defined(TARGET_MIPS64)
int R = env->CP0_BadVAddr >> 62;
int UX = (env->CP0_Status & (1 << CP0St_UX)) != 0;
int SX = (env->CP0_Status & (1 << CP0St_SX)) != 0;
int KX = (env->CP0_Status & (1 << CP0St_KX)) != 0;
if (((R == 0 && UX) || (R == 1 && SX) || (R == 3 && KX)) &&
(!(env->insn_flags & (INSN_LOONGSON2E | INSN_LOONGSON2F))))
offset = 0x080;
else
#endif
offset = 0x000;
}
goto set_EPC;
case EXCP_AdEL:
cause = 4;
update_badinstr = !(env->error_code & EXCP_INST_NOTAVAIL);
goto set_EPC;
case EXCP_AdES:
cause = 5;
update_badinstr = 1;
goto set_EPC;
case EXCP_IBE:
cause = 6;
goto set_EPC;
case EXCP_DBE:
cause = 7;
goto set_EPC;
case EXCP_SYSCALL:
cause = 8;
update_badinstr = 1;
goto set_EPC;
case EXCP_BREAK:
cause = 9;
update_badinstr = 1;
goto set_EPC;
case EXCP_RI:
cause = 10;
update_badinstr = 1;
goto set_EPC;
case EXCP_CpU:
cause = 11;
update_badinstr = 1;
env->CP0_Cause = (env->CP0_Cause & ~(0x3 << CP0Ca_CE)) |
(env->error_code << CP0Ca_CE);
goto set_EPC;
case EXCP_OVERFLOW:
cause = 12;
update_badinstr = 1;
goto set_EPC;
case EXCP_TRAP:
cause = 13;
update_badinstr = 1;
goto set_EPC;
case EXCP_MSAFPE:
cause = 14;
update_badinstr = 1;
goto set_EPC;
case EXCP_FPE:
cause = 15;
update_badinstr = 1;
goto set_EPC;
case EXCP_C2E:
cause = 18;
goto set_EPC;
case EXCP_TLBRI:
cause = 19;
update_badinstr = 1;
goto set_EPC;
case EXCP_TLBXI:
cause = 20;
goto set_EPC;
case EXCP_MSADIS:
cause = 21;
update_badinstr = 1;
goto set_EPC;
case EXCP_MDMX:
cause = 22;
goto set_EPC;
case EXCP_DWATCH:
cause = 23;
/* XXX: TODO: manage deferred watch exceptions */
goto set_EPC;
case EXCP_MCHECK:
cause = 24;
goto set_EPC;
case EXCP_THREAD:
cause = 25;
goto set_EPC;
case EXCP_DSPDIS:
cause = 26;
goto set_EPC;
case EXCP_CACHE:
cause = 30;
if (env->CP0_Status & (1 << CP0St_BEV)) {
offset = 0x100;
} else {
offset = 0x20000100;
}
set_EPC:
if (!(env->CP0_Status & (1 << CP0St_EXL))) {
env->CP0_EPC = exception_resume_pc(env);
if (update_badinstr) {
set_badinstr_registers(env);
}
if (env->hflags & MIPS_HFLAG_BMASK) {
env->CP0_Cause |= (1U << CP0Ca_BD);
} else {
env->CP0_Cause &= ~(1U << CP0Ca_BD);
}
env->CP0_Status |= (1 << CP0St_EXL);
if (env->insn_flags & ISA_MIPS3) {
env->hflags |= MIPS_HFLAG_64;
if (!(env->insn_flags & ISA_MIPS64R6) ||
env->CP0_Status & (1 << CP0St_KX)) {
env->hflags &= ~MIPS_HFLAG_AWRAP;
}
}
env->hflags |= MIPS_HFLAG_CP0;
env->hflags &= ~(MIPS_HFLAG_KSU);
}
env->hflags &= ~MIPS_HFLAG_BMASK;
if (env->CP0_Status & (1 << CP0St_BEV)) {
env->active_tc.PC = env->exception_base + 0x200;
} else {
env->active_tc.PC = (int32_t)(env->CP0_EBase & ~0x3ff);
}
env->active_tc.PC += offset;
set_hflags_for_handler(env);
env->CP0_Cause = (env->CP0_Cause & ~(0x1f << CP0Ca_EC)) | (cause << CP0Ca_EC);
break;
default:
abort();
}
if (qemu_loglevel_mask(CPU_LOG_INT)
&& cs->exception_index != EXCP_EXT_INTERRUPT) {
qemu_log("%s: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx " cause %d\n"
" S %08x C %08x A " TARGET_FMT_lx " D " TARGET_FMT_lx "\n",
__func__, env->active_tc.PC, env->CP0_EPC, cause,
env->CP0_Status, env->CP0_Cause, env->CP0_BadVAddr,
env->CP0_DEPC);
}
#endif
cs->exception_index = EXCP_NONE;
}
bool mips_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
{
if (interrupt_request & CPU_INTERRUPT_HARD) {
MIPSCPU *cpu = MIPS_CPU(cs);
CPUMIPSState *env = &cpu->env;
if (cpu_mips_hw_interrupts_enabled(env) &&
cpu_mips_hw_interrupts_pending(env)) {
/* Raise it */
cs->exception_index = EXCP_EXT_INTERRUPT;
env->error_code = 0;
mips_cpu_do_interrupt(cs);
return true;
}
}
return false;
}
#if !defined(CONFIG_USER_ONLY)
void r4k_invalidate_tlb (CPUMIPSState *env, int idx, int use_extra)
{
MIPSCPU *cpu = mips_env_get_cpu(env);
CPUState *cs;
r4k_tlb_t *tlb;
target_ulong addr;
target_ulong end;
uint16_t ASID = env->CP0_EntryHi & env->CP0_EntryHi_ASID_mask;
target_ulong mask;
tlb = &env->tlb->mmu.r4k.tlb[idx];
/* The qemu TLB is flushed when the ASID changes, so no need to
flush these entries again. */
if (tlb->G == 0 && tlb->ASID != ASID) {
return;
}
if (use_extra && env->tlb->tlb_in_use < MIPS_TLB_MAX) {
/* For tlbwr, we can shadow the discarded entry into
a new (fake) TLB entry, as long as the guest can not
tell that it's there. */
env->tlb->mmu.r4k.tlb[env->tlb->tlb_in_use] = *tlb;
env->tlb->tlb_in_use++;
return;
}
/* 1k pages are not supported. */
mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
if (tlb->V0) {
cs = CPU(cpu);
addr = tlb->VPN & ~mask;
#if defined(TARGET_MIPS64)
if (addr >= (0xFFFFFFFF80000000ULL & env->SEGMask)) {
addr |= 0x3FFFFF0000000000ULL;
}
#endif
end = addr | (mask >> 1);
while (addr < end) {
tlb_flush_page(cs, addr);
addr += TARGET_PAGE_SIZE;
}
}
if (tlb->V1) {
cs = CPU(cpu);
addr = (tlb->VPN & ~mask) | ((mask >> 1) + 1);
#if defined(TARGET_MIPS64)
if (addr >= (0xFFFFFFFF80000000ULL & env->SEGMask)) {
addr |= 0x3FFFFF0000000000ULL;
}
#endif
end = addr | mask;
while (addr - 1 < end) {
tlb_flush_page(cs, addr);
addr += TARGET_PAGE_SIZE;
}
}
}
#endif
void QEMU_NORETURN do_raise_exception_err(CPUMIPSState *env,
uint32_t exception,
int error_code,
uintptr_t pc)
{
CPUState *cs = CPU(mips_env_get_cpu(env));
if (exception < EXCP_SC) {
qemu_log_mask(CPU_LOG_INT, "%s: %d %d\n",
__func__, exception, error_code);
}
cs->exception_index = exception;
env->error_code = error_code;
cpu_loop_exit_restore(cs, pc);
}

962
target/mips/helper.h Normal file
View file

@ -0,0 +1,962 @@
DEF_HELPER_3(raise_exception_err, noreturn, env, i32, int)
DEF_HELPER_2(raise_exception, noreturn, env, i32)
DEF_HELPER_1(raise_exception_debug, noreturn, env)
DEF_HELPER_1(do_semihosting, void, env)
#ifdef TARGET_MIPS64
DEF_HELPER_4(sdl, void, env, tl, tl, int)
DEF_HELPER_4(sdr, void, env, tl, tl, int)
#endif
DEF_HELPER_4(swl, void, env, tl, tl, int)
DEF_HELPER_4(swr, void, env, tl, tl, int)
#ifndef CONFIG_USER_ONLY
DEF_HELPER_3(ll, tl, env, tl, int)
DEF_HELPER_4(sc, tl, env, tl, tl, int)
#ifdef TARGET_MIPS64
DEF_HELPER_3(lld, tl, env, tl, int)
DEF_HELPER_4(scd, tl, env, tl, tl, int)
#endif
#endif
DEF_HELPER_FLAGS_1(clo, TCG_CALL_NO_RWG_SE, tl, tl)
DEF_HELPER_FLAGS_1(clz, TCG_CALL_NO_RWG_SE, tl, tl)
#ifdef TARGET_MIPS64
DEF_HELPER_FLAGS_1(dclo, TCG_CALL_NO_RWG_SE, tl, tl)
DEF_HELPER_FLAGS_1(dclz, TCG_CALL_NO_RWG_SE, tl, tl)
#endif
DEF_HELPER_3(muls, tl, env, tl, tl)
DEF_HELPER_3(mulsu, tl, env, tl, tl)
DEF_HELPER_3(macc, tl, env, tl, tl)
DEF_HELPER_3(maccu, tl, env, tl, tl)
DEF_HELPER_3(msac, tl, env, tl, tl)
DEF_HELPER_3(msacu, tl, env, tl, tl)
DEF_HELPER_3(mulhi, tl, env, tl, tl)
DEF_HELPER_3(mulhiu, tl, env, tl, tl)
DEF_HELPER_3(mulshi, tl, env, tl, tl)
DEF_HELPER_3(mulshiu, tl, env, tl, tl)
DEF_HELPER_3(macchi, tl, env, tl, tl)
DEF_HELPER_3(macchiu, tl, env, tl, tl)
DEF_HELPER_3(msachi, tl, env, tl, tl)
DEF_HELPER_3(msachiu, tl, env, tl, tl)
DEF_HELPER_FLAGS_1(bitswap, TCG_CALL_NO_RWG_SE, tl, tl)
#ifdef TARGET_MIPS64
DEF_HELPER_FLAGS_1(dbitswap, TCG_CALL_NO_RWG_SE, tl, tl)
#endif
#ifndef CONFIG_USER_ONLY
/* CP0 helpers */
DEF_HELPER_1(mfc0_mvpcontrol, tl, env)
DEF_HELPER_1(mfc0_mvpconf0, tl, env)
DEF_HELPER_1(mfc0_mvpconf1, tl, env)
DEF_HELPER_1(mftc0_vpecontrol, tl, env)
DEF_HELPER_1(mftc0_vpeconf0, tl, env)
DEF_HELPER_1(mfc0_random, tl, env)
DEF_HELPER_1(mfc0_tcstatus, tl, env)
DEF_HELPER_1(mftc0_tcstatus, tl, env)
DEF_HELPER_1(mfc0_tcbind, tl, env)
DEF_HELPER_1(mftc0_tcbind, tl, env)
DEF_HELPER_1(mfc0_tcrestart, tl, env)
DEF_HELPER_1(mftc0_tcrestart, tl, env)
DEF_HELPER_1(mfc0_tchalt, tl, env)
DEF_HELPER_1(mftc0_tchalt, tl, env)
DEF_HELPER_1(mfc0_tccontext, tl, env)
DEF_HELPER_1(mftc0_tccontext, tl, env)
DEF_HELPER_1(mfc0_tcschedule, tl, env)
DEF_HELPER_1(mftc0_tcschedule, tl, env)
DEF_HELPER_1(mfc0_tcschefback, tl, env)
DEF_HELPER_1(mftc0_tcschefback, tl, env)
DEF_HELPER_1(mfc0_count, tl, env)
DEF_HELPER_1(mftc0_entryhi, tl, env)
DEF_HELPER_1(mftc0_status, tl, env)
DEF_HELPER_1(mftc0_cause, tl, env)
DEF_HELPER_1(mftc0_epc, tl, env)
DEF_HELPER_1(mftc0_ebase, tl, env)
DEF_HELPER_2(mftc0_configx, tl, env, tl)
DEF_HELPER_1(mfc0_lladdr, tl, env)
DEF_HELPER_1(mfc0_maar, tl, env)
DEF_HELPER_1(mfhc0_maar, tl, env)
DEF_HELPER_2(mfc0_watchlo, tl, env, i32)
DEF_HELPER_2(mfc0_watchhi, tl, env, i32)
DEF_HELPER_1(mfc0_debug, tl, env)
DEF_HELPER_1(mftc0_debug, tl, env)
#ifdef TARGET_MIPS64
DEF_HELPER_1(dmfc0_tcrestart, tl, env)
DEF_HELPER_1(dmfc0_tchalt, tl, env)
DEF_HELPER_1(dmfc0_tccontext, tl, env)
DEF_HELPER_1(dmfc0_tcschedule, tl, env)
DEF_HELPER_1(dmfc0_tcschefback, tl, env)
DEF_HELPER_1(dmfc0_lladdr, tl, env)
DEF_HELPER_1(dmfc0_maar, tl, env)
DEF_HELPER_2(dmfc0_watchlo, tl, env, i32)
#endif /* TARGET_MIPS64 */
DEF_HELPER_2(mtc0_index, void, env, tl)
DEF_HELPER_2(mtc0_mvpcontrol, void, env, tl)
DEF_HELPER_2(mtc0_vpecontrol, void, env, tl)
DEF_HELPER_2(mttc0_vpecontrol, void, env, tl)
DEF_HELPER_2(mtc0_vpeconf0, void, env, tl)
DEF_HELPER_2(mttc0_vpeconf0, void, env, tl)
DEF_HELPER_2(mtc0_vpeconf1, void, env, tl)
DEF_HELPER_2(mtc0_yqmask, void, env, tl)
DEF_HELPER_2(mtc0_vpeopt, void, env, tl)
DEF_HELPER_2(mtc0_entrylo0, void, env, tl)
DEF_HELPER_2(mtc0_tcstatus, void, env, tl)
DEF_HELPER_2(mttc0_tcstatus, void, env, tl)
DEF_HELPER_2(mtc0_tcbind, void, env, tl)
DEF_HELPER_2(mttc0_tcbind, void, env, tl)
DEF_HELPER_2(mtc0_tcrestart, void, env, tl)
DEF_HELPER_2(mttc0_tcrestart, void, env, tl)
DEF_HELPER_2(mtc0_tchalt, void, env, tl)
DEF_HELPER_2(mttc0_tchalt, void, env, tl)
DEF_HELPER_2(mtc0_tccontext, void, env, tl)
DEF_HELPER_2(mttc0_tccontext, void, env, tl)
DEF_HELPER_2(mtc0_tcschedule, void, env, tl)
DEF_HELPER_2(mttc0_tcschedule, void, env, tl)
DEF_HELPER_2(mtc0_tcschefback, void, env, tl)
DEF_HELPER_2(mttc0_tcschefback, void, env, tl)
DEF_HELPER_2(mtc0_entrylo1, void, env, tl)
DEF_HELPER_2(mtc0_context, void, env, tl)
DEF_HELPER_2(mtc0_pagemask, void, env, tl)
DEF_HELPER_2(mtc0_pagegrain, void, env, tl)
DEF_HELPER_2(mtc0_wired, void, env, tl)
DEF_HELPER_2(mtc0_srsconf0, void, env, tl)
DEF_HELPER_2(mtc0_srsconf1, void, env, tl)
DEF_HELPER_2(mtc0_srsconf2, void, env, tl)
DEF_HELPER_2(mtc0_srsconf3, void, env, tl)
DEF_HELPER_2(mtc0_srsconf4, void, env, tl)
DEF_HELPER_2(mtc0_hwrena, void, env, tl)
DEF_HELPER_2(mtc0_count, void, env, tl)
DEF_HELPER_2(mtc0_entryhi, void, env, tl)
DEF_HELPER_2(mttc0_entryhi, void, env, tl)
DEF_HELPER_2(mtc0_compare, void, env, tl)
DEF_HELPER_2(mtc0_status, void, env, tl)
DEF_HELPER_2(mttc0_status, void, env, tl)
DEF_HELPER_2(mtc0_intctl, void, env, tl)
DEF_HELPER_2(mtc0_srsctl, void, env, tl)
DEF_HELPER_2(mtc0_cause, void, env, tl)
DEF_HELPER_2(mttc0_cause, void, env, tl)
DEF_HELPER_2(mtc0_ebase, void, env, tl)
DEF_HELPER_2(mttc0_ebase, void, env, tl)
DEF_HELPER_2(mtc0_config0, void, env, tl)
DEF_HELPER_2(mtc0_config2, void, env, tl)
DEF_HELPER_2(mtc0_config3, void, env, tl)
DEF_HELPER_2(mtc0_config4, void, env, tl)
DEF_HELPER_2(mtc0_config5, void, env, tl)
DEF_HELPER_2(mtc0_lladdr, void, env, tl)
DEF_HELPER_2(mtc0_maar, void, env, tl)
DEF_HELPER_2(mthc0_maar, void, env, tl)
DEF_HELPER_2(mtc0_maari, void, env, tl)
DEF_HELPER_3(mtc0_watchlo, void, env, tl, i32)
DEF_HELPER_3(mtc0_watchhi, void, env, tl, i32)
DEF_HELPER_2(mtc0_xcontext, void, env, tl)
DEF_HELPER_2(mtc0_framemask, void, env, tl)
DEF_HELPER_2(mtc0_debug, void, env, tl)
DEF_HELPER_2(mttc0_debug, void, env, tl)
DEF_HELPER_2(mtc0_performance0, void, env, tl)
DEF_HELPER_2(mtc0_errctl, void, env, tl)
DEF_HELPER_2(mtc0_taglo, void, env, tl)
DEF_HELPER_2(mtc0_datalo, void, env, tl)
DEF_HELPER_2(mtc0_taghi, void, env, tl)
DEF_HELPER_2(mtc0_datahi, void, env, tl)
#if defined(TARGET_MIPS64)
DEF_HELPER_2(dmtc0_entrylo0, void, env, i64)
DEF_HELPER_2(dmtc0_entrylo1, void, env, i64)
#endif
/* MIPS MT functions */
DEF_HELPER_2(mftgpr, tl, env, i32)
DEF_HELPER_2(mftlo, tl, env, i32)
DEF_HELPER_2(mfthi, tl, env, i32)
DEF_HELPER_2(mftacx, tl, env, i32)
DEF_HELPER_1(mftdsp, tl, env)
DEF_HELPER_3(mttgpr, void, env, tl, i32)
DEF_HELPER_3(mttlo, void, env, tl, i32)
DEF_HELPER_3(mtthi, void, env, tl, i32)
DEF_HELPER_3(mttacx, void, env, tl, i32)
DEF_HELPER_2(mttdsp, void, env, tl)
DEF_HELPER_0(dmt, tl)
DEF_HELPER_0(emt, tl)
DEF_HELPER_1(dvpe, tl, env)
DEF_HELPER_1(evpe, tl, env)
/* R6 Multi-threading */
DEF_HELPER_1(dvp, tl, env)
DEF_HELPER_1(evp, tl, env)
#endif /* !CONFIG_USER_ONLY */
/* microMIPS functions */
DEF_HELPER_4(lwm, void, env, tl, tl, i32)
DEF_HELPER_4(swm, void, env, tl, tl, i32)
#ifdef TARGET_MIPS64
DEF_HELPER_4(ldm, void, env, tl, tl, i32)
DEF_HELPER_4(sdm, void, env, tl, tl, i32)
#endif
DEF_HELPER_2(fork, void, tl, tl)
DEF_HELPER_2(yield, tl, env, tl)
/* CP1 functions */
DEF_HELPER_2(cfc1, tl, env, i32)
DEF_HELPER_4(ctc1, void, env, tl, i32, i32)
DEF_HELPER_2(float_cvtd_s, i64, env, i32)
DEF_HELPER_2(float_cvtd_w, i64, env, i32)
DEF_HELPER_2(float_cvtd_l, i64, env, i64)
DEF_HELPER_2(float_cvtps_pw, i64, env, i64)
DEF_HELPER_2(float_cvtpw_ps, i64, env, i64)
DEF_HELPER_2(float_cvts_d, i32, env, i64)
DEF_HELPER_2(float_cvts_w, i32, env, i32)
DEF_HELPER_2(float_cvts_l, i32, env, i64)
DEF_HELPER_2(float_cvts_pl, i32, env, i32)
DEF_HELPER_2(float_cvts_pu, i32, env, i32)
DEF_HELPER_3(float_addr_ps, i64, env, i64, i64)
DEF_HELPER_3(float_mulr_ps, i64, env, i64, i64)
DEF_HELPER_FLAGS_2(float_class_s, TCG_CALL_NO_RWG_SE, i32, env, i32)
DEF_HELPER_FLAGS_2(float_class_d, TCG_CALL_NO_RWG_SE, i64, env, i64)
#define FOP_PROTO(op) \
DEF_HELPER_4(float_ ## op ## _s, i32, env, i32, i32, i32) \
DEF_HELPER_4(float_ ## op ## _d, i64, env, i64, i64, i64)
FOP_PROTO(maddf)
FOP_PROTO(msubf)
#undef FOP_PROTO
#define FOP_PROTO(op) \
DEF_HELPER_3(float_ ## op ## _s, i32, env, i32, i32) \
DEF_HELPER_3(float_ ## op ## _d, i64, env, i64, i64)
FOP_PROTO(max)
FOP_PROTO(maxa)
FOP_PROTO(min)
FOP_PROTO(mina)
#undef FOP_PROTO
#define FOP_PROTO(op) \
DEF_HELPER_2(float_ ## op ## _l_s, i64, env, i32) \
DEF_HELPER_2(float_ ## op ## _l_d, i64, env, i64) \
DEF_HELPER_2(float_ ## op ## _w_s, i32, env, i32) \
DEF_HELPER_2(float_ ## op ## _w_d, i32, env, i64)
FOP_PROTO(cvt)
FOP_PROTO(round)
FOP_PROTO(trunc)
FOP_PROTO(ceil)
FOP_PROTO(floor)
FOP_PROTO(cvt_2008)
FOP_PROTO(round_2008)
FOP_PROTO(trunc_2008)
FOP_PROTO(ceil_2008)
FOP_PROTO(floor_2008)
#undef FOP_PROTO
#define FOP_PROTO(op) \
DEF_HELPER_2(float_ ## op ## _s, i32, env, i32) \
DEF_HELPER_2(float_ ## op ## _d, i64, env, i64)
FOP_PROTO(sqrt)
FOP_PROTO(rsqrt)
FOP_PROTO(recip)
FOP_PROTO(rint)
#undef FOP_PROTO
#define FOP_PROTO(op) \
DEF_HELPER_1(float_ ## op ## _s, i32, i32) \
DEF_HELPER_1(float_ ## op ## _d, i64, i64) \
DEF_HELPER_1(float_ ## op ## _ps, i64, i64)
FOP_PROTO(abs)
FOP_PROTO(chs)
#undef FOP_PROTO
#define FOP_PROTO(op) \
DEF_HELPER_2(float_ ## op ## _s, i32, env, i32) \
DEF_HELPER_2(float_ ## op ## _d, i64, env, i64) \
DEF_HELPER_2(float_ ## op ## _ps, i64, env, i64)
FOP_PROTO(recip1)
FOP_PROTO(rsqrt1)
#undef FOP_PROTO
#define FOP_PROTO(op) \
DEF_HELPER_3(float_ ## op ## _s, i32, env, i32, i32) \
DEF_HELPER_3(float_ ## op ## _d, i64, env, i64, i64) \
DEF_HELPER_3(float_ ## op ## _ps, i64, env, i64, i64)
FOP_PROTO(add)
FOP_PROTO(sub)
FOP_PROTO(mul)
FOP_PROTO(div)
FOP_PROTO(recip2)
FOP_PROTO(rsqrt2)
#undef FOP_PROTO
#define FOP_PROTO(op) \
DEF_HELPER_4(float_ ## op ## _s, i32, env, i32, i32, i32) \
DEF_HELPER_4(float_ ## op ## _d, i64, env, i64, i64, i64) \
DEF_HELPER_4(float_ ## op ## _ps, i64, env, i64, i64, i64)
FOP_PROTO(madd)
FOP_PROTO(msub)
FOP_PROTO(nmadd)
FOP_PROTO(nmsub)
#undef FOP_PROTO
#define FOP_PROTO(op) \
DEF_HELPER_4(cmp_d_ ## op, void, env, i64, i64, int) \
DEF_HELPER_4(cmpabs_d_ ## op, void, env, i64, i64, int) \
DEF_HELPER_4(cmp_s_ ## op, void, env, i32, i32, int) \
DEF_HELPER_4(cmpabs_s_ ## op, void, env, i32, i32, int) \
DEF_HELPER_4(cmp_ps_ ## op, void, env, i64, i64, int) \
DEF_HELPER_4(cmpabs_ps_ ## op, void, env, i64, i64, int)
FOP_PROTO(f)
FOP_PROTO(un)
FOP_PROTO(eq)
FOP_PROTO(ueq)
FOP_PROTO(olt)
FOP_PROTO(ult)
FOP_PROTO(ole)
FOP_PROTO(ule)
FOP_PROTO(sf)
FOP_PROTO(ngle)
FOP_PROTO(seq)
FOP_PROTO(ngl)
FOP_PROTO(lt)
FOP_PROTO(nge)
FOP_PROTO(le)
FOP_PROTO(ngt)
#undef FOP_PROTO
#define FOP_PROTO(op) \
DEF_HELPER_3(r6_cmp_d_ ## op, i64, env, i64, i64) \
DEF_HELPER_3(r6_cmp_s_ ## op, i32, env, i32, i32)
FOP_PROTO(af)
FOP_PROTO(un)
FOP_PROTO(eq)
FOP_PROTO(ueq)
FOP_PROTO(lt)
FOP_PROTO(ult)
FOP_PROTO(le)
FOP_PROTO(ule)
FOP_PROTO(saf)
FOP_PROTO(sun)
FOP_PROTO(seq)
FOP_PROTO(sueq)
FOP_PROTO(slt)
FOP_PROTO(sult)
FOP_PROTO(sle)
FOP_PROTO(sule)
FOP_PROTO(or)
FOP_PROTO(une)
FOP_PROTO(ne)
FOP_PROTO(sor)
FOP_PROTO(sune)
FOP_PROTO(sne)
#undef FOP_PROTO
/* Special functions */
#ifndef CONFIG_USER_ONLY
DEF_HELPER_1(tlbwi, void, env)
DEF_HELPER_1(tlbwr, void, env)
DEF_HELPER_1(tlbp, void, env)
DEF_HELPER_1(tlbr, void, env)
DEF_HELPER_1(tlbinv, void, env)
DEF_HELPER_1(tlbinvf, void, env)
DEF_HELPER_1(di, tl, env)
DEF_HELPER_1(ei, tl, env)
DEF_HELPER_1(eret, void, env)
DEF_HELPER_1(eretnc, void, env)
DEF_HELPER_1(deret, void, env)
#endif /* !CONFIG_USER_ONLY */
DEF_HELPER_1(rdhwr_cpunum, tl, env)
DEF_HELPER_1(rdhwr_synci_step, tl, env)
DEF_HELPER_1(rdhwr_cc, tl, env)
DEF_HELPER_1(rdhwr_ccres, tl, env)
DEF_HELPER_1(rdhwr_performance, tl, env)
DEF_HELPER_1(rdhwr_xnp, tl, env)
DEF_HELPER_2(pmon, void, env, int)
DEF_HELPER_1(wait, void, env)
/* Loongson multimedia functions. */
DEF_HELPER_FLAGS_2(paddsh, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(paddush, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(paddh, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(paddw, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(paddsb, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(paddusb, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(paddb, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(psubsh, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(psubush, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(psubh, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(psubw, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(psubsb, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(psubusb, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(psubb, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(pshufh, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(packsswh, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(packsshb, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(packushb, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(punpcklhw, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(punpckhhw, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(punpcklbh, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(punpckhbh, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(punpcklwd, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(punpckhwd, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(pavgh, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(pavgb, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(pmaxsh, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(pminsh, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(pmaxub, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(pminub, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(pcmpeqw, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(pcmpgtw, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(pcmpeqh, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(pcmpgth, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(pcmpeqb, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(pcmpgtb, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(psllw, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(psllh, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(psrlw, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(psrlh, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(psraw, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(psrah, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(pmullh, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(pmulhh, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(pmulhuh, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(pmaddhw, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(pasubub, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_1(biadd, TCG_CALL_NO_RWG_SE, i64, i64)
DEF_HELPER_FLAGS_1(pmovmskb, TCG_CALL_NO_RWG_SE, i64, i64)
/*** MIPS DSP ***/
/* DSP Arithmetic Sub-class insns */
DEF_HELPER_FLAGS_3(addq_ph, 0, tl, tl, tl, env)
DEF_HELPER_FLAGS_3(addq_s_ph, 0, tl, tl, tl, env)
#if defined(TARGET_MIPS64)
DEF_HELPER_FLAGS_3(addq_qh, 0, tl, tl, tl, env)
DEF_HELPER_FLAGS_3(addq_s_qh, 0, tl, tl, tl, env)
#endif
DEF_HELPER_FLAGS_3(addq_s_w, 0, tl, tl, tl, env)
#if defined(TARGET_MIPS64)
DEF_HELPER_FLAGS_3(addq_pw, 0, tl, tl, tl, env)
DEF_HELPER_FLAGS_3(addq_s_pw, 0, tl, tl, tl, env)
#endif
DEF_HELPER_FLAGS_3(addu_qb, 0, tl, tl, tl, env)
DEF_HELPER_FLAGS_3(addu_s_qb, 0, tl, tl, tl, env)
DEF_HELPER_FLAGS_2(adduh_qb, TCG_CALL_NO_RWG_SE, tl, tl, tl)
DEF_HELPER_FLAGS_2(adduh_r_qb, TCG_CALL_NO_RWG_SE, tl, tl, tl)
DEF_HELPER_FLAGS_3(addu_ph, 0, tl, tl, tl, env)
DEF_HELPER_FLAGS_3(addu_s_ph, 0, tl, tl, tl, env)
DEF_HELPER_FLAGS_2(addqh_ph, TCG_CALL_NO_RWG_SE, tl, tl, tl)
DEF_HELPER_FLAGS_2(addqh_r_ph, TCG_CALL_NO_RWG_SE, tl, tl, tl)
DEF_HELPER_FLAGS_2(addqh_w, TCG_CALL_NO_RWG_SE, tl, tl, tl)
DEF_HELPER_FLAGS_2(addqh_r_w, TCG_CALL_NO_RWG_SE, tl, tl, tl)
#if defined(TARGET_MIPS64)
DEF_HELPER_FLAGS_3(addu_ob, 0, tl, tl, tl, env)
DEF_HELPER_FLAGS_3(addu_s_ob, 0, tl, tl, tl, env)
DEF_HELPER_FLAGS_2(adduh_ob, TCG_CALL_NO_RWG_SE, tl, tl, tl)
DEF_HELPER_FLAGS_2(adduh_r_ob, TCG_CALL_NO_RWG_SE, tl, tl, tl)
DEF_HELPER_FLAGS_3(addu_qh, 0, tl, tl, tl, env)
DEF_HELPER_FLAGS_3(addu_s_qh, 0, tl, tl, tl, env)
#endif
DEF_HELPER_FLAGS_3(subq_ph, 0, tl, tl, tl, env)
DEF_HELPER_FLAGS_3(subq_s_ph, 0, tl, tl, tl, env)
#if defined(TARGET_MIPS64)
DEF_HELPER_FLAGS_3(subq_qh, 0, tl, tl, tl, env)
DEF_HELPER_FLAGS_3(subq_s_qh, 0, tl, tl, tl, env)
#endif
DEF_HELPER_FLAGS_3(subq_s_w, 0, tl, tl, tl, env)
#if defined(TARGET_MIPS64)
DEF_HELPER_FLAGS_3(subq_pw, 0, tl, tl, tl, env)
DEF_HELPER_FLAGS_3(subq_s_pw, 0, tl, tl, tl, env)
#endif
DEF_HELPER_FLAGS_3(subu_qb, 0, tl, tl, tl, env)
DEF_HELPER_FLAGS_3(subu_s_qb, 0, tl, tl, tl, env)
DEF_HELPER_FLAGS_2(subuh_qb, TCG_CALL_NO_RWG_SE, tl, tl, tl)
DEF_HELPER_FLAGS_2(subuh_r_qb, TCG_CALL_NO_RWG_SE, tl, tl, tl)
DEF_HELPER_FLAGS_3(subu_ph, 0, tl, tl, tl, env)
DEF_HELPER_FLAGS_3(subu_s_ph, 0, tl, tl, tl, env)
DEF_HELPER_FLAGS_2(subqh_ph, TCG_CALL_NO_RWG_SE, tl, tl, tl)
DEF_HELPER_FLAGS_2(subqh_r_ph, TCG_CALL_NO_RWG_SE, tl, tl, tl)
DEF_HELPER_FLAGS_2(subqh_w, TCG_CALL_NO_RWG_SE, tl, tl, tl)
DEF_HELPER_FLAGS_2(subqh_r_w, TCG_CALL_NO_RWG_SE, tl, tl, tl)
#if defined(TARGET_MIPS64)
DEF_HELPER_FLAGS_3(subu_ob, 0, tl, tl, tl, env)
DEF_HELPER_FLAGS_3(subu_s_ob, 0, tl, tl, tl, env)
DEF_HELPER_FLAGS_2(subuh_ob, TCG_CALL_NO_RWG_SE, tl, tl, tl)
DEF_HELPER_FLAGS_2(subuh_r_ob, TCG_CALL_NO_RWG_SE, tl, tl, tl)
DEF_HELPER_FLAGS_3(subu_qh, 0, tl, tl, tl, env)
DEF_HELPER_FLAGS_3(subu_s_qh, 0, tl, tl, tl, env)
#endif
DEF_HELPER_FLAGS_3(addsc, 0, tl, tl, tl, env)
DEF_HELPER_FLAGS_3(addwc, 0, tl, tl, tl, env)
DEF_HELPER_FLAGS_2(modsub, TCG_CALL_NO_RWG_SE, tl, tl, tl)
DEF_HELPER_FLAGS_1(raddu_w_qb, TCG_CALL_NO_RWG_SE, tl, tl)
#if defined(TARGET_MIPS64)
DEF_HELPER_FLAGS_1(raddu_l_ob, TCG_CALL_NO_RWG_SE, tl, tl)
#endif
DEF_HELPER_FLAGS_2(absq_s_qb, 0, tl, tl, env)
DEF_HELPER_FLAGS_2(absq_s_ph, 0, tl, tl, env)
DEF_HELPER_FLAGS_2(absq_s_w, 0, tl, tl, env)
#if defined(TARGET_MIPS64)
DEF_HELPER_FLAGS_2(absq_s_ob, 0, tl, tl, env)
DEF_HELPER_FLAGS_2(absq_s_qh, 0, tl, tl, env)
DEF_HELPER_FLAGS_2(absq_s_pw, 0, tl, tl, env)
#endif
DEF_HELPER_FLAGS_2(precr_qb_ph, TCG_CALL_NO_RWG_SE, tl, tl, tl)
DEF_HELPER_FLAGS_2(precrq_qb_ph, TCG_CALL_NO_RWG_SE, tl, tl, tl)
DEF_HELPER_FLAGS_3(precr_sra_ph_w, TCG_CALL_NO_RWG_SE,
tl, i32, tl, tl)
DEF_HELPER_FLAGS_3(precr_sra_r_ph_w, TCG_CALL_NO_RWG_SE,
tl, i32, tl, tl)
DEF_HELPER_FLAGS_2(precrq_ph_w, TCG_CALL_NO_RWG_SE, tl, tl, tl)
DEF_HELPER_FLAGS_3(precrq_rs_ph_w, 0, tl, tl, tl, env)
#if defined(TARGET_MIPS64)
DEF_HELPER_FLAGS_2(precr_ob_qh, TCG_CALL_NO_RWG_SE, tl, tl, tl)
DEF_HELPER_FLAGS_3(precr_sra_qh_pw,
TCG_CALL_NO_RWG_SE, tl, tl, tl, i32)
DEF_HELPER_FLAGS_3(precr_sra_r_qh_pw,
TCG_CALL_NO_RWG_SE, tl, tl, tl, i32)
DEF_HELPER_FLAGS_2(precrq_ob_qh, TCG_CALL_NO_RWG_SE, tl, tl, tl)
DEF_HELPER_FLAGS_2(precrq_qh_pw, TCG_CALL_NO_RWG_SE, tl, tl, tl)
DEF_HELPER_FLAGS_3(precrq_rs_qh_pw,
TCG_CALL_NO_RWG_SE, tl, tl, tl, env)
DEF_HELPER_FLAGS_2(precrq_pw_l, TCG_CALL_NO_RWG_SE, tl, tl, tl)
#endif
DEF_HELPER_FLAGS_3(precrqu_s_qb_ph, 0, tl, tl, tl, env)
#if defined(TARGET_MIPS64)
DEF_HELPER_FLAGS_3(precrqu_s_ob_qh,
TCG_CALL_NO_RWG_SE, tl, tl, tl, env)
DEF_HELPER_FLAGS_1(preceq_pw_qhl, TCG_CALL_NO_RWG_SE, tl, tl)
DEF_HELPER_FLAGS_1(preceq_pw_qhr, TCG_CALL_NO_RWG_SE, tl, tl)
DEF_HELPER_FLAGS_1(preceq_pw_qhla, TCG_CALL_NO_RWG_SE, tl, tl)
DEF_HELPER_FLAGS_1(preceq_pw_qhra, TCG_CALL_NO_RWG_SE, tl, tl)
#endif
DEF_HELPER_FLAGS_1(precequ_ph_qbl, TCG_CALL_NO_RWG_SE, tl, tl)
DEF_HELPER_FLAGS_1(precequ_ph_qbr, TCG_CALL_NO_RWG_SE, tl, tl)
DEF_HELPER_FLAGS_1(precequ_ph_qbla, TCG_CALL_NO_RWG_SE, tl, tl)
DEF_HELPER_FLAGS_1(precequ_ph_qbra, TCG_CALL_NO_RWG_SE, tl, tl)
#if defined(TARGET_MIPS64)
DEF_HELPER_FLAGS_1(precequ_qh_obl, TCG_CALL_NO_RWG_SE, tl, tl)
DEF_HELPER_FLAGS_1(precequ_qh_obr, TCG_CALL_NO_RWG_SE, tl, tl)
DEF_HELPER_FLAGS_1(precequ_qh_obla, TCG_CALL_NO_RWG_SE, tl, tl)
DEF_HELPER_FLAGS_1(precequ_qh_obra, TCG_CALL_NO_RWG_SE, tl, tl)
#endif
DEF_HELPER_FLAGS_1(preceu_ph_qbl, TCG_CALL_NO_RWG_SE, tl, tl)
DEF_HELPER_FLAGS_1(preceu_ph_qbr, TCG_CALL_NO_RWG_SE, tl, tl)
DEF_HELPER_FLAGS_1(preceu_ph_qbla, TCG_CALL_NO_RWG_SE, tl, tl)
DEF_HELPER_FLAGS_1(preceu_ph_qbra, TCG_CALL_NO_RWG_SE, tl, tl)
#if defined(TARGET_MIPS64)
DEF_HELPER_FLAGS_1(preceu_qh_obl, TCG_CALL_NO_RWG_SE, tl, tl)
DEF_HELPER_FLAGS_1(preceu_qh_obr, TCG_CALL_NO_RWG_SE, tl, tl)
DEF_HELPER_FLAGS_1(preceu_qh_obla, TCG_CALL_NO_RWG_SE, tl, tl)
DEF_HELPER_FLAGS_1(preceu_qh_obra, TCG_CALL_NO_RWG_SE, tl, tl)
#endif
/* DSP GPR-Based Shift Sub-class insns */
DEF_HELPER_FLAGS_3(shll_qb, 0, tl, tl, tl, env)
#if defined(TARGET_MIPS64)
DEF_HELPER_FLAGS_3(shll_ob, 0, tl, tl, tl, env)
#endif
DEF_HELPER_FLAGS_3(shll_ph, 0, tl, tl, tl, env)
DEF_HELPER_FLAGS_3(shll_s_ph, 0, tl, tl, tl, env)
#if defined(TARGET_MIPS64)
DEF_HELPER_FLAGS_3(shll_qh, 0, tl, tl, tl, env)
DEF_HELPER_FLAGS_3(shll_s_qh, 0, tl, tl, tl, env)
#endif
DEF_HELPER_FLAGS_3(shll_s_w, 0, tl, tl, tl, env)
#if defined(TARGET_MIPS64)
DEF_HELPER_FLAGS_3(shll_pw, 0, tl, tl, tl, env)
DEF_HELPER_FLAGS_3(shll_s_pw, 0, tl, tl, tl, env)
#endif
DEF_HELPER_FLAGS_2(shrl_qb, TCG_CALL_NO_RWG_SE, tl, tl, tl)
DEF_HELPER_FLAGS_2(shrl_ph, TCG_CALL_NO_RWG_SE, tl, tl, tl)
#if defined(TARGET_MIPS64)
DEF_HELPER_FLAGS_2(shrl_ob, TCG_CALL_NO_RWG_SE, tl, tl, tl)
DEF_HELPER_FLAGS_2(shrl_qh, TCG_CALL_NO_RWG_SE, tl, tl, tl)
#endif
DEF_HELPER_FLAGS_2(shra_qb, TCG_CALL_NO_RWG_SE, tl, tl, tl)
DEF_HELPER_FLAGS_2(shra_r_qb, TCG_CALL_NO_RWG_SE, tl, tl, tl)
#if defined(TARGET_MIPS64)
DEF_HELPER_FLAGS_2(shra_ob, TCG_CALL_NO_RWG_SE, tl, tl, tl)
DEF_HELPER_FLAGS_2(shra_r_ob, TCG_CALL_NO_RWG_SE, tl, tl, tl)
#endif
DEF_HELPER_FLAGS_2(shra_ph, TCG_CALL_NO_RWG_SE, tl, tl, tl)
DEF_HELPER_FLAGS_2(shra_r_ph, TCG_CALL_NO_RWG_SE, tl, tl, tl)
DEF_HELPER_FLAGS_2(shra_r_w, TCG_CALL_NO_RWG_SE, tl, tl, tl)
#if defined(TARGET_MIPS64)
DEF_HELPER_FLAGS_2(shra_qh, TCG_CALL_NO_RWG_SE, tl, tl, tl)
DEF_HELPER_FLAGS_2(shra_r_qh, TCG_CALL_NO_RWG_SE, tl, tl, tl)
DEF_HELPER_FLAGS_2(shra_pw, TCG_CALL_NO_RWG_SE, tl, tl, tl)
DEF_HELPER_FLAGS_2(shra_r_pw, TCG_CALL_NO_RWG_SE, tl, tl, tl)
#endif
/* DSP Multiply Sub-class insns */
DEF_HELPER_FLAGS_3(muleu_s_ph_qbl, 0, tl, tl, tl, env)
DEF_HELPER_FLAGS_3(muleu_s_ph_qbr, 0, tl, tl, tl, env)
#if defined(TARGET_MIPS64)
DEF_HELPER_FLAGS_3(muleu_s_qh_obl, 0, tl, tl, tl, env)
DEF_HELPER_FLAGS_3(muleu_s_qh_obr, 0, tl, tl, tl, env)
#endif
DEF_HELPER_FLAGS_3(mulq_rs_ph, 0, tl, tl, tl, env)
#if defined(TARGET_MIPS64)
DEF_HELPER_FLAGS_3(mulq_rs_qh, 0, tl, tl, tl, env)
#endif
DEF_HELPER_FLAGS_3(muleq_s_w_phl, 0, tl, tl, tl, env)
DEF_HELPER_FLAGS_3(muleq_s_w_phr, 0, tl, tl, tl, env)
#if defined(TARGET_MIPS64)
DEF_HELPER_FLAGS_3(muleq_s_pw_qhl, 0, tl, tl, tl, env)
DEF_HELPER_FLAGS_3(muleq_s_pw_qhr, 0, tl, tl, tl, env)
#endif
DEF_HELPER_FLAGS_4(dpau_h_qbl, 0, void, i32, tl, tl, env)
DEF_HELPER_FLAGS_4(dpau_h_qbr, 0, void, i32, tl, tl, env)
#if defined(TARGET_MIPS64)
DEF_HELPER_FLAGS_4(dpau_h_obl, 0, void, tl, tl, i32, env)
DEF_HELPER_FLAGS_4(dpau_h_obr, 0, void, tl, tl, i32, env)
#endif
DEF_HELPER_FLAGS_4(dpsu_h_qbl, 0, void, i32, tl, tl, env)
DEF_HELPER_FLAGS_4(dpsu_h_qbr, 0, void, i32, tl, tl, env)
#if defined(TARGET_MIPS64)
DEF_HELPER_FLAGS_4(dpsu_h_obl, 0, void, tl, tl, i32, env)
DEF_HELPER_FLAGS_4(dpsu_h_obr, 0, void, tl, tl, i32, env)
#endif
DEF_HELPER_FLAGS_4(dpa_w_ph, 0, void, i32, tl, tl, env)
#if defined(TARGET_MIPS64)
DEF_HELPER_FLAGS_4(dpa_w_qh, 0, void, tl, tl, i32, env)
#endif
DEF_HELPER_FLAGS_4(dpax_w_ph, 0, void, i32, tl, tl, env)
DEF_HELPER_FLAGS_4(dpaq_s_w_ph, 0, void, i32, tl, tl, env)
#if defined(TARGET_MIPS64)
DEF_HELPER_FLAGS_4(dpaq_s_w_qh, 0, void, tl, tl, i32, env)
#endif
DEF_HELPER_FLAGS_4(dpaqx_s_w_ph, 0, void, i32, tl, tl, env)
DEF_HELPER_FLAGS_4(dpaqx_sa_w_ph, 0, void, i32, tl, tl, env)
DEF_HELPER_FLAGS_4(dps_w_ph, 0, void, i32, tl, tl, env)
#if defined(TARGET_MIPS64)
DEF_HELPER_FLAGS_4(dps_w_qh, 0, void, tl, tl, i32, env)
#endif
DEF_HELPER_FLAGS_4(dpsx_w_ph, 0, void, i32, tl, tl, env)
DEF_HELPER_FLAGS_4(dpsq_s_w_ph, 0, void, i32, tl, tl, env)
#if defined(TARGET_MIPS64)
DEF_HELPER_FLAGS_4(dpsq_s_w_qh, 0, void, tl, tl, i32, env)
#endif
DEF_HELPER_FLAGS_4(dpsqx_s_w_ph, 0, void, i32, tl, tl, env)
DEF_HELPER_FLAGS_4(dpsqx_sa_w_ph, 0, void, i32, tl, tl, env)
DEF_HELPER_FLAGS_4(mulsaq_s_w_ph, 0, void, i32, tl, tl, env)
#if defined(TARGET_MIPS64)
DEF_HELPER_FLAGS_4(mulsaq_s_w_qh, 0, void, tl, tl, i32, env)
#endif
DEF_HELPER_FLAGS_4(dpaq_sa_l_w, 0, void, i32, tl, tl, env)
#if defined(TARGET_MIPS64)
DEF_HELPER_FLAGS_4(dpaq_sa_l_pw, 0, void, tl, tl, i32, env)
#endif
DEF_HELPER_FLAGS_4(dpsq_sa_l_w, 0, void, i32, tl, tl, env)
#if defined(TARGET_MIPS64)
DEF_HELPER_FLAGS_4(dpsq_sa_l_pw, 0, void, tl, tl, i32, env)
DEF_HELPER_FLAGS_4(mulsaq_s_l_pw, 0, void, tl, tl, i32, env)
#endif
DEF_HELPER_FLAGS_4(maq_s_w_phl, 0, void, i32, tl, tl, env)
DEF_HELPER_FLAGS_4(maq_s_w_phr, 0, void, i32, tl, tl, env)
DEF_HELPER_FLAGS_4(maq_sa_w_phl, 0, void, i32, tl, tl, env)
DEF_HELPER_FLAGS_4(maq_sa_w_phr, 0, void, i32, tl, tl, env)
DEF_HELPER_FLAGS_3(mul_ph, 0, tl, tl, tl, env)
DEF_HELPER_FLAGS_3(mul_s_ph, 0, tl, tl, tl, env)
DEF_HELPER_FLAGS_3(mulq_s_ph, 0, tl, tl, tl, env)
DEF_HELPER_FLAGS_3(mulq_s_w, 0, tl, tl, tl, env)
DEF_HELPER_FLAGS_3(mulq_rs_w, 0, tl, tl, tl, env)
DEF_HELPER_FLAGS_4(mulsa_w_ph, 0, void, i32, tl, tl, env)
#if defined(TARGET_MIPS64)
DEF_HELPER_FLAGS_4(maq_s_w_qhll, 0, void, tl, tl, i32, env)
DEF_HELPER_FLAGS_4(maq_s_w_qhlr, 0, void, tl, tl, i32, env)
DEF_HELPER_FLAGS_4(maq_s_w_qhrl, 0, void, tl, tl, i32, env)
DEF_HELPER_FLAGS_4(maq_s_w_qhrr, 0, void, tl, tl, i32, env)
DEF_HELPER_FLAGS_4(maq_sa_w_qhll, 0, void, tl, tl, i32, env)
DEF_HELPER_FLAGS_4(maq_sa_w_qhlr, 0, void, tl, tl, i32, env)
DEF_HELPER_FLAGS_4(maq_sa_w_qhrl, 0, void, tl, tl, i32, env)
DEF_HELPER_FLAGS_4(maq_sa_w_qhrr, 0, void, tl, tl, i32, env)
DEF_HELPER_FLAGS_4(maq_s_l_pwl, 0, void, tl, tl, i32, env)
DEF_HELPER_FLAGS_4(maq_s_l_pwr, 0, void, tl, tl, i32, env)
DEF_HELPER_FLAGS_4(dmadd, 0, void, tl, tl, i32, env)
DEF_HELPER_FLAGS_4(dmaddu, 0, void, tl, tl, i32, env)
DEF_HELPER_FLAGS_4(dmsub, 0, void, tl, tl, i32, env)
DEF_HELPER_FLAGS_4(dmsubu, 0, void, tl, tl, i32, env)
#endif
/* DSP Bit/Manipulation Sub-class insns */
DEF_HELPER_FLAGS_1(bitrev, TCG_CALL_NO_RWG_SE, tl, tl)
DEF_HELPER_FLAGS_3(insv, 0, tl, env, tl, tl)
#if defined(TARGET_MIPS64)
DEF_HELPER_FLAGS_3(dinsv, 0, tl, env, tl, tl)
#endif
/* DSP Compare-Pick Sub-class insns */
DEF_HELPER_FLAGS_3(cmpu_eq_qb, 0, void, tl, tl, env)
DEF_HELPER_FLAGS_3(cmpu_lt_qb, 0, void, tl, tl, env)
DEF_HELPER_FLAGS_3(cmpu_le_qb, 0, void, tl, tl, env)
DEF_HELPER_FLAGS_2(cmpgu_eq_qb, TCG_CALL_NO_RWG_SE, tl, tl, tl)
DEF_HELPER_FLAGS_2(cmpgu_lt_qb, TCG_CALL_NO_RWG_SE, tl, tl, tl)
DEF_HELPER_FLAGS_2(cmpgu_le_qb, TCG_CALL_NO_RWG_SE, tl, tl, tl)
DEF_HELPER_FLAGS_3(cmp_eq_ph, 0, void, tl, tl, env)
DEF_HELPER_FLAGS_3(cmp_lt_ph, 0, void, tl, tl, env)
DEF_HELPER_FLAGS_3(cmp_le_ph, 0, void, tl, tl, env)
#if defined(TARGET_MIPS64)
DEF_HELPER_FLAGS_3(cmpu_eq_ob, 0, void, tl, tl, env)
DEF_HELPER_FLAGS_3(cmpu_lt_ob, 0, void, tl, tl, env)
DEF_HELPER_FLAGS_3(cmpu_le_ob, 0, void, tl, tl, env)
DEF_HELPER_FLAGS_3(cmpgdu_eq_ob, 0, tl, tl, tl, env)
DEF_HELPER_FLAGS_3(cmpgdu_lt_ob, 0, tl, tl, tl, env)
DEF_HELPER_FLAGS_3(cmpgdu_le_ob, 0, tl, tl, tl, env)
DEF_HELPER_FLAGS_2(cmpgu_eq_ob, TCG_CALL_NO_RWG_SE, tl, tl, tl)
DEF_HELPER_FLAGS_2(cmpgu_lt_ob, TCG_CALL_NO_RWG_SE, tl, tl, tl)
DEF_HELPER_FLAGS_2(cmpgu_le_ob, TCG_CALL_NO_RWG_SE, tl, tl, tl)
DEF_HELPER_FLAGS_3(cmp_eq_qh, 0, void, tl, tl, env)
DEF_HELPER_FLAGS_3(cmp_lt_qh, 0, void, tl, tl, env)
DEF_HELPER_FLAGS_3(cmp_le_qh, 0, void, tl, tl, env)
DEF_HELPER_FLAGS_3(cmp_eq_pw, 0, void, tl, tl, env)
DEF_HELPER_FLAGS_3(cmp_lt_pw, 0, void, tl, tl, env)
DEF_HELPER_FLAGS_3(cmp_le_pw, 0, void, tl, tl, env)
#endif
DEF_HELPER_FLAGS_3(pick_qb, 0, tl, tl, tl, env)
DEF_HELPER_FLAGS_3(pick_ph, 0, tl, tl, tl, env)
#if defined(TARGET_MIPS64)
DEF_HELPER_FLAGS_3(pick_ob, 0, tl, tl, tl, env)
DEF_HELPER_FLAGS_3(pick_qh, 0, tl, tl, tl, env)
DEF_HELPER_FLAGS_3(pick_pw, 0, tl, tl, tl, env)
#endif
DEF_HELPER_FLAGS_2(packrl_ph, TCG_CALL_NO_RWG_SE, tl, tl, tl)
#if defined(TARGET_MIPS64)
DEF_HELPER_FLAGS_2(packrl_pw, TCG_CALL_NO_RWG_SE, tl, tl, tl)
#endif
/* DSP Accumulator and DSPControl Access Sub-class insns */
DEF_HELPER_FLAGS_3(extr_w, 0, tl, tl, tl, env)
DEF_HELPER_FLAGS_3(extr_r_w, 0, tl, tl, tl, env)
DEF_HELPER_FLAGS_3(extr_rs_w, 0, tl, tl, tl, env)
#if defined(TARGET_MIPS64)
DEF_HELPER_FLAGS_3(dextr_w, 0, tl, tl, tl, env)
DEF_HELPER_FLAGS_3(dextr_r_w, 0, tl, tl, tl, env)
DEF_HELPER_FLAGS_3(dextr_rs_w, 0, tl, tl, tl, env)
DEF_HELPER_FLAGS_3(dextr_l, 0, tl, tl, tl, env)
DEF_HELPER_FLAGS_3(dextr_r_l, 0, tl, tl, tl, env)
DEF_HELPER_FLAGS_3(dextr_rs_l, 0, tl, tl, tl, env)
#endif
DEF_HELPER_FLAGS_3(extr_s_h, 0, tl, tl, tl, env)
#if defined(TARGET_MIPS64)
DEF_HELPER_FLAGS_3(dextr_s_h, 0, tl, tl, tl, env)
#endif
DEF_HELPER_FLAGS_3(extp, 0, tl, tl, tl, env)
DEF_HELPER_FLAGS_3(extpdp, 0, tl, tl, tl, env)
#if defined(TARGET_MIPS64)
DEF_HELPER_FLAGS_3(dextp, 0, tl, tl, tl, env)
DEF_HELPER_FLAGS_3(dextpdp, 0, tl, tl, tl, env)
#endif
DEF_HELPER_FLAGS_3(shilo, 0, void, tl, tl, env)
#if defined(TARGET_MIPS64)
DEF_HELPER_FLAGS_3(dshilo, 0, void, tl, tl, env)
#endif
DEF_HELPER_FLAGS_3(mthlip, 0, void, tl, tl, env)
#if defined(TARGET_MIPS64)
DEF_HELPER_FLAGS_3(dmthlip, 0, void, tl, tl, env)
#endif
DEF_HELPER_FLAGS_3(wrdsp, 0, void, tl, tl, env)
DEF_HELPER_FLAGS_2(rddsp, 0, tl, tl, env)
/* MIPS SIMD Architecture */
DEF_HELPER_4(msa_andi_b, void, env, i32, i32, i32)
DEF_HELPER_4(msa_ori_b, void, env, i32, i32, i32)
DEF_HELPER_4(msa_nori_b, void, env, i32, i32, i32)
DEF_HELPER_4(msa_xori_b, void, env, i32, i32, i32)
DEF_HELPER_4(msa_bmnzi_b, void, env, i32, i32, i32)
DEF_HELPER_4(msa_bmzi_b, void, env, i32, i32, i32)
DEF_HELPER_4(msa_bseli_b, void, env, i32, i32, i32)
DEF_HELPER_5(msa_shf_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_addvi_df, void, env, i32, i32, i32, s32)
DEF_HELPER_5(msa_subvi_df, void, env, i32, i32, i32, s32)
DEF_HELPER_5(msa_maxi_s_df, void, env, i32, i32, i32, s32)
DEF_HELPER_5(msa_maxi_u_df, void, env, i32, i32, i32, s32)
DEF_HELPER_5(msa_mini_s_df, void, env, i32, i32, i32, s32)
DEF_HELPER_5(msa_mini_u_df, void, env, i32, i32, i32, s32)
DEF_HELPER_5(msa_ceqi_df, void, env, i32, i32, i32, s32)
DEF_HELPER_5(msa_clti_s_df, void, env, i32, i32, i32, s32)
DEF_HELPER_5(msa_clti_u_df, void, env, i32, i32, i32, s32)
DEF_HELPER_5(msa_clei_s_df, void, env, i32, i32, i32, s32)
DEF_HELPER_5(msa_clei_u_df, void, env, i32, i32, i32, s32)
DEF_HELPER_4(msa_ldi_df, void, env, i32, i32, s32)
DEF_HELPER_5(msa_slli_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_srai_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_srli_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_bclri_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_bseti_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_bnegi_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_binsli_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_binsri_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_sat_s_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_sat_u_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_srari_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_srlri_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_sll_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_sra_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_srl_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_bclr_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_bset_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_bneg_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_binsl_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_binsr_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_addv_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_subv_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_max_s_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_max_u_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_min_s_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_min_u_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_max_a_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_min_a_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_ceq_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_clt_s_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_clt_u_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_cle_s_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_cle_u_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_add_a_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_adds_a_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_adds_s_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_adds_u_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_ave_s_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_ave_u_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_aver_s_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_aver_u_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_subs_s_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_subs_u_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_subsus_u_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_subsuu_s_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_asub_s_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_asub_u_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_mulv_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_maddv_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_msubv_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_div_s_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_div_u_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_mod_s_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_mod_u_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_dotp_s_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_dotp_u_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_dpadd_s_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_dpadd_u_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_dpsub_s_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_dpsub_u_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_sld_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_splat_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_pckev_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_pckod_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_ilvl_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_ilvr_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_ilvev_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_ilvod_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_vshf_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_srar_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_srlr_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_hadd_s_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_hadd_u_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_hsub_s_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_hsub_u_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_sldi_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_splati_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_copy_s_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_copy_u_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_insert_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_insve_df, void, env, i32, i32, i32, i32)
DEF_HELPER_3(msa_ctcmsa, void, env, tl, i32)
DEF_HELPER_2(msa_cfcmsa, tl, env, i32)
DEF_HELPER_3(msa_move_v, void, env, i32, i32)
DEF_HELPER_5(msa_fcaf_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_fcun_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_fceq_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_fcueq_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_fclt_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_fcult_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_fcle_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_fcule_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_fsaf_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_fsun_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_fseq_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_fsueq_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_fslt_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_fsult_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_fsle_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_fsule_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_fadd_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_fsub_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_fmul_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_fdiv_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_fmadd_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_fmsub_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_fexp2_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_fexdo_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_ftq_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_fmin_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_fmin_a_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_fmax_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_fmax_a_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_fcor_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_fcune_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_fcne_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_mul_q_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_madd_q_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_msub_q_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_fsor_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_fsune_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_fsne_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_mulr_q_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_maddr_q_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_msubr_q_df, void, env, i32, i32, i32, i32)
DEF_HELPER_4(msa_and_v, void, env, i32, i32, i32)
DEF_HELPER_4(msa_or_v, void, env, i32, i32, i32)
DEF_HELPER_4(msa_nor_v, void, env, i32, i32, i32)
DEF_HELPER_4(msa_xor_v, void, env, i32, i32, i32)
DEF_HELPER_4(msa_bmnz_v, void, env, i32, i32, i32)
DEF_HELPER_4(msa_bmz_v, void, env, i32, i32, i32)
DEF_HELPER_4(msa_bsel_v, void, env, i32, i32, i32)
DEF_HELPER_4(msa_fill_df, void, env, i32, i32, i32)
DEF_HELPER_4(msa_pcnt_df, void, env, i32, i32, i32)
DEF_HELPER_4(msa_nloc_df, void, env, i32, i32, i32)
DEF_HELPER_4(msa_nlzc_df, void, env, i32, i32, i32)
DEF_HELPER_4(msa_fclass_df, void, env, i32, i32, i32)
DEF_HELPER_4(msa_ftrunc_s_df, void, env, i32, i32, i32)
DEF_HELPER_4(msa_ftrunc_u_df, void, env, i32, i32, i32)
DEF_HELPER_4(msa_fsqrt_df, void, env, i32, i32, i32)
DEF_HELPER_4(msa_frsqrt_df, void, env, i32, i32, i32)
DEF_HELPER_4(msa_frcp_df, void, env, i32, i32, i32)
DEF_HELPER_4(msa_frint_df, void, env, i32, i32, i32)
DEF_HELPER_4(msa_flog2_df, void, env, i32, i32, i32)
DEF_HELPER_4(msa_fexupl_df, void, env, i32, i32, i32)
DEF_HELPER_4(msa_fexupr_df, void, env, i32, i32, i32)
DEF_HELPER_4(msa_ffql_df, void, env, i32, i32, i32)
DEF_HELPER_4(msa_ffqr_df, void, env, i32, i32, i32)
DEF_HELPER_4(msa_ftint_s_df, void, env, i32, i32, i32)
DEF_HELPER_4(msa_ftint_u_df, void, env, i32, i32, i32)
DEF_HELPER_4(msa_ffint_s_df, void, env, i32, i32, i32)
DEF_HELPER_4(msa_ffint_u_df, void, env, i32, i32, i32)
#define MSALDST_PROTO(type) \
DEF_HELPER_3(msa_ld_ ## type, void, env, i32, tl) \
DEF_HELPER_3(msa_st_ ## type, void, env, i32, tl)
MSALDST_PROTO(b)
MSALDST_PROTO(h)
MSALDST_PROTO(w)
MSALDST_PROTO(d)
#undef MSALDST_PROTO
DEF_HELPER_3(cache, void, env, tl, i32)

1060
target/mips/kvm.c Normal file

File diff suppressed because it is too large Load diff

26
target/mips/kvm_mips.h Normal file
View file

@ -0,0 +1,26 @@
/*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* KVM/MIPS: MIPS specific KVM APIs
*
* Copyright (C) 2012-2014 Imagination Technologies Ltd.
* Authors: Sanjay Lal <sanjayl@kymasys.com>
*/
#ifndef KVM_MIPS_H
#define KVM_MIPS_H
/**
* kvm_mips_reset_vcpu:
* @cpu: MIPSCPU
*
* Called at reset time to set kernel registers to their initial values.
*/
void kvm_mips_reset_vcpu(MIPSCPU *cpu);
int kvm_mips_set_interrupt(MIPSCPU *cpu, int irq, int level);
int kvm_mips_set_ipi_interrupt(MIPSCPU *cpu, int irq, int level);
#endif /* KVM_MIPS_H */

745
target/mips/lmi_helper.c Normal file
View file

@ -0,0 +1,745 @@
/*
* Loongson Multimedia Instruction emulation helpers for QEMU.
*
* Copyright (c) 2011 Richard Henderson <rth@twiddle.net>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include "qemu/osdep.h"
#include "cpu.h"
#include "exec/helper-proto.h"
/* If the byte ordering doesn't matter, i.e. all columns are treated
identically, then this union can be used directly. If byte ordering
does matter, we generally ignore dumping to memory. */
typedef union {
uint8_t ub[8];
int8_t sb[8];
uint16_t uh[4];
int16_t sh[4];
uint32_t uw[2];
int32_t sw[2];
uint64_t d;
} LMIValue;
/* Some byte ordering issues can be mitigated by XORing in the following. */
#ifdef HOST_WORDS_BIGENDIAN
# define BYTE_ORDER_XOR(N) N
#else
# define BYTE_ORDER_XOR(N) 0
#endif
#define SATSB(x) (x < -0x80 ? -0x80 : x > 0x7f ? 0x7f : x)
#define SATUB(x) (x > 0xff ? 0xff : x)
#define SATSH(x) (x < -0x8000 ? -0x8000 : x > 0x7fff ? 0x7fff : x)
#define SATUH(x) (x > 0xffff ? 0xffff : x)
#define SATSW(x) \
(x < -0x80000000ll ? -0x80000000ll : x > 0x7fffffff ? 0x7fffffff : x)
#define SATUW(x) (x > 0xffffffffull ? 0xffffffffull : x)
uint64_t helper_paddsb(uint64_t fs, uint64_t ft)
{
LMIValue vs, vt;
unsigned int i;
vs.d = fs;
vt.d = ft;
for (i = 0; i < 8; ++i) {
int r = vs.sb[i] + vt.sb[i];
vs.sb[i] = SATSB(r);
}
return vs.d;
}
uint64_t helper_paddusb(uint64_t fs, uint64_t ft)
{
LMIValue vs, vt;
unsigned int i;
vs.d = fs;
vt.d = ft;
for (i = 0; i < 8; ++i) {
int r = vs.ub[i] + vt.ub[i];
vs.ub[i] = SATUB(r);
}
return vs.d;
}
uint64_t helper_paddsh(uint64_t fs, uint64_t ft)
{
LMIValue vs, vt;
unsigned int i;
vs.d = fs;
vt.d = ft;
for (i = 0; i < 4; ++i) {
int r = vs.sh[i] + vt.sh[i];
vs.sh[i] = SATSH(r);
}
return vs.d;
}
uint64_t helper_paddush(uint64_t fs, uint64_t ft)
{
LMIValue vs, vt;
unsigned int i;
vs.d = fs;
vt.d = ft;
for (i = 0; i < 4; ++i) {
int r = vs.uh[i] + vt.uh[i];
vs.uh[i] = SATUH(r);
}
return vs.d;
}
uint64_t helper_paddb(uint64_t fs, uint64_t ft)
{
LMIValue vs, vt;
unsigned int i;
vs.d = fs;
vt.d = ft;
for (i = 0; i < 8; ++i) {
vs.ub[i] += vt.ub[i];
}
return vs.d;
}
uint64_t helper_paddh(uint64_t fs, uint64_t ft)
{
LMIValue vs, vt;
unsigned int i;
vs.d = fs;
vt.d = ft;
for (i = 0; i < 4; ++i) {
vs.uh[i] += vt.uh[i];
}
return vs.d;
}
uint64_t helper_paddw(uint64_t fs, uint64_t ft)
{
LMIValue vs, vt;
unsigned int i;
vs.d = fs;
vt.d = ft;
for (i = 0; i < 2; ++i) {
vs.uw[i] += vt.uw[i];
}
return vs.d;
}
uint64_t helper_psubsb(uint64_t fs, uint64_t ft)
{
LMIValue vs, vt;
unsigned int i;
vs.d = fs;
vt.d = ft;
for (i = 0; i < 8; ++i) {
int r = vs.sb[i] - vt.sb[i];
vs.sb[i] = SATSB(r);
}
return vs.d;
}
uint64_t helper_psubusb(uint64_t fs, uint64_t ft)
{
LMIValue vs, vt;
unsigned int i;
vs.d = fs;
vt.d = ft;
for (i = 0; i < 8; ++i) {
int r = vs.ub[i] - vt.ub[i];
vs.ub[i] = SATUB(r);
}
return vs.d;
}
uint64_t helper_psubsh(uint64_t fs, uint64_t ft)
{
LMIValue vs, vt;
unsigned int i;
vs.d = fs;
vt.d = ft;
for (i = 0; i < 4; ++i) {
int r = vs.sh[i] - vt.sh[i];
vs.sh[i] = SATSH(r);
}
return vs.d;
}
uint64_t helper_psubush(uint64_t fs, uint64_t ft)
{
LMIValue vs, vt;
unsigned int i;
vs.d = fs;
vt.d = ft;
for (i = 0; i < 4; ++i) {
int r = vs.uh[i] - vt.uh[i];
vs.uh[i] = SATUH(r);
}
return vs.d;
}
uint64_t helper_psubb(uint64_t fs, uint64_t ft)
{
LMIValue vs, vt;
unsigned int i;
vs.d = fs;
vt.d = ft;
for (i = 0; i < 8; ++i) {
vs.ub[i] -= vt.ub[i];
}
return vs.d;
}
uint64_t helper_psubh(uint64_t fs, uint64_t ft)
{
LMIValue vs, vt;
unsigned int i;
vs.d = fs;
vt.d = ft;
for (i = 0; i < 4; ++i) {
vs.uh[i] -= vt.uh[i];
}
return vs.d;
}
uint64_t helper_psubw(uint64_t fs, uint64_t ft)
{
LMIValue vs, vt;
unsigned int i;
vs.d = fs;
vt.d = ft;
for (i = 0; i < 2; ++i) {
vs.uw[i] -= vt.uw[i];
}
return vs.d;
}
uint64_t helper_pshufh(uint64_t fs, uint64_t ft)
{
unsigned host = BYTE_ORDER_XOR(3);
LMIValue vd, vs;
unsigned i;
vs.d = fs;
vd.d = 0;
for (i = 0; i < 4; i++, ft >>= 2) {
vd.uh[i ^ host] = vs.uh[(ft & 3) ^ host];
}
return vd.d;
}
uint64_t helper_packsswh(uint64_t fs, uint64_t ft)
{
uint64_t fd = 0;
int64_t tmp;
tmp = (int32_t)(fs >> 0);
tmp = SATSH(tmp);
fd |= (tmp & 0xffff) << 0;
tmp = (int32_t)(fs >> 32);
tmp = SATSH(tmp);
fd |= (tmp & 0xffff) << 16;
tmp = (int32_t)(ft >> 0);
tmp = SATSH(tmp);
fd |= (tmp & 0xffff) << 32;
tmp = (int32_t)(ft >> 32);
tmp = SATSH(tmp);
fd |= (tmp & 0xffff) << 48;
return fd;
}
uint64_t helper_packsshb(uint64_t fs, uint64_t ft)
{
uint64_t fd = 0;
unsigned int i;
for (i = 0; i < 4; ++i) {
int16_t tmp = fs >> (i * 16);
tmp = SATSB(tmp);
fd |= (uint64_t)(tmp & 0xff) << (i * 8);
}
for (i = 0; i < 4; ++i) {
int16_t tmp = ft >> (i * 16);
tmp = SATSB(tmp);
fd |= (uint64_t)(tmp & 0xff) << (i * 8 + 32);
}
return fd;
}
uint64_t helper_packushb(uint64_t fs, uint64_t ft)
{
uint64_t fd = 0;
unsigned int i;
for (i = 0; i < 4; ++i) {
int16_t tmp = fs >> (i * 16);
tmp = SATUB(tmp);
fd |= (uint64_t)(tmp & 0xff) << (i * 8);
}
for (i = 0; i < 4; ++i) {
int16_t tmp = ft >> (i * 16);
tmp = SATUB(tmp);
fd |= (uint64_t)(tmp & 0xff) << (i * 8 + 32);
}
return fd;
}
uint64_t helper_punpcklwd(uint64_t fs, uint64_t ft)
{
return (fs & 0xffffffff) | (ft << 32);
}
uint64_t helper_punpckhwd(uint64_t fs, uint64_t ft)
{
return (fs >> 32) | (ft & ~0xffffffffull);
}
uint64_t helper_punpcklhw(uint64_t fs, uint64_t ft)
{
unsigned host = BYTE_ORDER_XOR(3);
LMIValue vd, vs, vt;
vs.d = fs;
vt.d = ft;
vd.uh[0 ^ host] = vs.uh[0 ^ host];
vd.uh[1 ^ host] = vt.uh[0 ^ host];
vd.uh[2 ^ host] = vs.uh[1 ^ host];
vd.uh[3 ^ host] = vt.uh[1 ^ host];
return vd.d;
}
uint64_t helper_punpckhhw(uint64_t fs, uint64_t ft)
{
unsigned host = BYTE_ORDER_XOR(3);
LMIValue vd, vs, vt;
vs.d = fs;
vt.d = ft;
vd.uh[0 ^ host] = vs.uh[2 ^ host];
vd.uh[1 ^ host] = vt.uh[2 ^ host];
vd.uh[2 ^ host] = vs.uh[3 ^ host];
vd.uh[3 ^ host] = vt.uh[3 ^ host];
return vd.d;
}
uint64_t helper_punpcklbh(uint64_t fs, uint64_t ft)
{
unsigned host = BYTE_ORDER_XOR(7);
LMIValue vd, vs, vt;
vs.d = fs;
vt.d = ft;
vd.ub[0 ^ host] = vs.ub[0 ^ host];
vd.ub[1 ^ host] = vt.ub[0 ^ host];
vd.ub[2 ^ host] = vs.ub[1 ^ host];
vd.ub[3 ^ host] = vt.ub[1 ^ host];
vd.ub[4 ^ host] = vs.ub[2 ^ host];
vd.ub[5 ^ host] = vt.ub[2 ^ host];
vd.ub[6 ^ host] = vs.ub[3 ^ host];
vd.ub[7 ^ host] = vt.ub[3 ^ host];
return vd.d;
}
uint64_t helper_punpckhbh(uint64_t fs, uint64_t ft)
{
unsigned host = BYTE_ORDER_XOR(7);
LMIValue vd, vs, vt;
vs.d = fs;
vt.d = ft;
vd.ub[0 ^ host] = vs.ub[4 ^ host];
vd.ub[1 ^ host] = vt.ub[4 ^ host];
vd.ub[2 ^ host] = vs.ub[5 ^ host];
vd.ub[3 ^ host] = vt.ub[5 ^ host];
vd.ub[4 ^ host] = vs.ub[6 ^ host];
vd.ub[5 ^ host] = vt.ub[6 ^ host];
vd.ub[6 ^ host] = vs.ub[7 ^ host];
vd.ub[7 ^ host] = vt.ub[7 ^ host];
return vd.d;
}
uint64_t helper_pavgh(uint64_t fs, uint64_t ft)
{
LMIValue vs, vt;
unsigned i;
vs.d = fs;
vt.d = ft;
for (i = 0; i < 4; i++) {
vs.uh[i] = (vs.uh[i] + vt.uh[i] + 1) >> 1;
}
return vs.d;
}
uint64_t helper_pavgb(uint64_t fs, uint64_t ft)
{
LMIValue vs, vt;
unsigned i;
vs.d = fs;
vt.d = ft;
for (i = 0; i < 8; i++) {
vs.ub[i] = (vs.ub[i] + vt.ub[i] + 1) >> 1;
}
return vs.d;
}
uint64_t helper_pmaxsh(uint64_t fs, uint64_t ft)
{
LMIValue vs, vt;
unsigned i;
vs.d = fs;
vt.d = ft;
for (i = 0; i < 4; i++) {
vs.sh[i] = (vs.sh[i] >= vt.sh[i] ? vs.sh[i] : vt.sh[i]);
}
return vs.d;
}
uint64_t helper_pminsh(uint64_t fs, uint64_t ft)
{
LMIValue vs, vt;
unsigned i;
vs.d = fs;
vt.d = ft;
for (i = 0; i < 4; i++) {
vs.sh[i] = (vs.sh[i] <= vt.sh[i] ? vs.sh[i] : vt.sh[i]);
}
return vs.d;
}
uint64_t helper_pmaxub(uint64_t fs, uint64_t ft)
{
LMIValue vs, vt;
unsigned i;
vs.d = fs;
vt.d = ft;
for (i = 0; i < 4; i++) {
vs.ub[i] = (vs.ub[i] >= vt.ub[i] ? vs.ub[i] : vt.ub[i]);
}
return vs.d;
}
uint64_t helper_pminub(uint64_t fs, uint64_t ft)
{
LMIValue vs, vt;
unsigned i;
vs.d = fs;
vt.d = ft;
for (i = 0; i < 4; i++) {
vs.ub[i] = (vs.ub[i] <= vt.ub[i] ? vs.ub[i] : vt.ub[i]);
}
return vs.d;
}
uint64_t helper_pcmpeqw(uint64_t fs, uint64_t ft)
{
LMIValue vs, vt;
unsigned i;
vs.d = fs;
vt.d = ft;
for (i = 0; i < 2; i++) {
vs.uw[i] = -(vs.uw[i] == vt.uw[i]);
}
return vs.d;
}
uint64_t helper_pcmpgtw(uint64_t fs, uint64_t ft)
{
LMIValue vs, vt;
unsigned i;
vs.d = fs;
vt.d = ft;
for (i = 0; i < 2; i++) {
vs.uw[i] = -(vs.uw[i] > vt.uw[i]);
}
return vs.d;
}
uint64_t helper_pcmpeqh(uint64_t fs, uint64_t ft)
{
LMIValue vs, vt;
unsigned i;
vs.d = fs;
vt.d = ft;
for (i = 0; i < 4; i++) {
vs.uh[i] = -(vs.uh[i] == vt.uh[i]);
}
return vs.d;
}
uint64_t helper_pcmpgth(uint64_t fs, uint64_t ft)
{
LMIValue vs, vt;
unsigned i;
vs.d = fs;
vt.d = ft;
for (i = 0; i < 4; i++) {
vs.uh[i] = -(vs.uh[i] > vt.uh[i]);
}
return vs.d;
}
uint64_t helper_pcmpeqb(uint64_t fs, uint64_t ft)
{
LMIValue vs, vt;
unsigned i;
vs.d = fs;
vt.d = ft;
for (i = 0; i < 8; i++) {
vs.ub[i] = -(vs.ub[i] == vt.ub[i]);
}
return vs.d;
}
uint64_t helper_pcmpgtb(uint64_t fs, uint64_t ft)
{
LMIValue vs, vt;
unsigned i;
vs.d = fs;
vt.d = ft;
for (i = 0; i < 8; i++) {
vs.ub[i] = -(vs.ub[i] > vt.ub[i]);
}
return vs.d;
}
uint64_t helper_psllw(uint64_t fs, uint64_t ft)
{
LMIValue vs;
unsigned i;
ft &= 0x7f;
if (ft > 31) {
return 0;
}
vs.d = fs;
for (i = 0; i < 2; ++i) {
vs.uw[i] <<= ft;
}
return vs.d;
}
uint64_t helper_psrlw(uint64_t fs, uint64_t ft)
{
LMIValue vs;
unsigned i;
ft &= 0x7f;
if (ft > 31) {
return 0;
}
vs.d = fs;
for (i = 0; i < 2; ++i) {
vs.uw[i] >>= ft;
}
return vs.d;
}
uint64_t helper_psraw(uint64_t fs, uint64_t ft)
{
LMIValue vs;
unsigned i;
ft &= 0x7f;
if (ft > 31) {
ft = 31;
}
vs.d = fs;
for (i = 0; i < 2; ++i) {
vs.sw[i] >>= ft;
}
return vs.d;
}
uint64_t helper_psllh(uint64_t fs, uint64_t ft)
{
LMIValue vs;
unsigned i;
ft &= 0x7f;
if (ft > 15) {
return 0;
}
vs.d = fs;
for (i = 0; i < 4; ++i) {
vs.uh[i] <<= ft;
}
return vs.d;
}
uint64_t helper_psrlh(uint64_t fs, uint64_t ft)
{
LMIValue vs;
unsigned i;
ft &= 0x7f;
if (ft > 15) {
return 0;
}
vs.d = fs;
for (i = 0; i < 4; ++i) {
vs.uh[i] >>= ft;
}
return vs.d;
}
uint64_t helper_psrah(uint64_t fs, uint64_t ft)
{
LMIValue vs;
unsigned i;
ft &= 0x7f;
if (ft > 15) {
ft = 15;
}
vs.d = fs;
for (i = 0; i < 4; ++i) {
vs.sh[i] >>= ft;
}
return vs.d;
}
uint64_t helper_pmullh(uint64_t fs, uint64_t ft)
{
LMIValue vs, vt;
unsigned i;
vs.d = fs;
vt.d = ft;
for (i = 0; i < 4; ++i) {
vs.sh[i] *= vt.sh[i];
}
return vs.d;
}
uint64_t helper_pmulhh(uint64_t fs, uint64_t ft)
{
LMIValue vs, vt;
unsigned i;
vs.d = fs;
vt.d = ft;
for (i = 0; i < 4; ++i) {
int32_t r = vs.sh[i] * vt.sh[i];
vs.sh[i] = r >> 16;
}
return vs.d;
}
uint64_t helper_pmulhuh(uint64_t fs, uint64_t ft)
{
LMIValue vs, vt;
unsigned i;
vs.d = fs;
vt.d = ft;
for (i = 0; i < 4; ++i) {
uint32_t r = vs.uh[i] * vt.uh[i];
vs.uh[i] = r >> 16;
}
return vs.d;
}
uint64_t helper_pmaddhw(uint64_t fs, uint64_t ft)
{
unsigned host = BYTE_ORDER_XOR(3);
LMIValue vs, vt;
uint32_t p0, p1;
vs.d = fs;
vt.d = ft;
p0 = vs.sh[0 ^ host] * vt.sh[0 ^ host];
p0 += vs.sh[1 ^ host] * vt.sh[1 ^ host];
p1 = vs.sh[2 ^ host] * vt.sh[2 ^ host];
p1 += vs.sh[3 ^ host] * vt.sh[3 ^ host];
return ((uint64_t)p1 << 32) | p0;
}
uint64_t helper_pasubub(uint64_t fs, uint64_t ft)
{
LMIValue vs, vt;
unsigned i;
vs.d = fs;
vt.d = ft;
for (i = 0; i < 8; ++i) {
int r = vs.ub[i] - vt.ub[i];
vs.ub[i] = (r < 0 ? -r : r);
}
return vs.d;
}
uint64_t helper_biadd(uint64_t fs)
{
unsigned i, fd;
for (i = fd = 0; i < 8; ++i) {
fd += (fs >> (i * 8)) & 0xff;
}
return fd & 0xffff;
}
uint64_t helper_pmovmskb(uint64_t fs)
{
unsigned fd = 0;
fd |= ((fs >> 7) & 1) << 0;
fd |= ((fs >> 15) & 1) << 1;
fd |= ((fs >> 23) & 1) << 2;
fd |= ((fs >> 31) & 1) << 3;
fd |= ((fs >> 39) & 1) << 4;
fd |= ((fs >> 47) & 1) << 5;
fd |= ((fs >> 55) & 1) << 6;
fd |= ((fs >> 63) & 1) << 7;
return fd & 0xff;
}

302
target/mips/machine.c Normal file
View file

@ -0,0 +1,302 @@
#include "qemu/osdep.h"
#include "qemu-common.h"
#include "cpu.h"
#include "hw/hw.h"
#include "migration/cpu.h"
static int cpu_post_load(void *opaque, int version_id)
{
MIPSCPU *cpu = opaque;
CPUMIPSState *env = &cpu->env;
restore_fp_status(env);
restore_msa_fp_status(env);
compute_hflags(env);
restore_pamask(env);
return 0;
}
/* FPU state */
static int get_fpr(QEMUFile *f, void *pv, size_t size)
{
int i;
fpr_t *v = pv;
/* Restore entire MSA vector register */
for (i = 0; i < MSA_WRLEN/64; i++) {
qemu_get_sbe64s(f, &v->wr.d[i]);
}
return 0;
}
static void put_fpr(QEMUFile *f, void *pv, size_t size)
{
int i;
fpr_t *v = pv;
/* Save entire MSA vector register */
for (i = 0; i < MSA_WRLEN/64; i++) {
qemu_put_sbe64s(f, &v->wr.d[i]);
}
}
const VMStateInfo vmstate_info_fpr = {
.name = "fpr",
.get = get_fpr,
.put = put_fpr,
};
#define VMSTATE_FPR_ARRAY_V(_f, _s, _n, _v) \
VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_fpr, fpr_t)
#define VMSTATE_FPR_ARRAY(_f, _s, _n) \
VMSTATE_FPR_ARRAY_V(_f, _s, _n, 0)
static VMStateField vmstate_fpu_fields[] = {
VMSTATE_FPR_ARRAY(fpr, CPUMIPSFPUContext, 32),
VMSTATE_UINT32(fcr0, CPUMIPSFPUContext),
VMSTATE_UINT32(fcr31, CPUMIPSFPUContext),
VMSTATE_END_OF_LIST()
};
const VMStateDescription vmstate_fpu = {
.name = "cpu/fpu",
.version_id = 1,
.minimum_version_id = 1,
.fields = vmstate_fpu_fields
};
const VMStateDescription vmstate_inactive_fpu = {
.name = "cpu/inactive_fpu",
.version_id = 1,
.minimum_version_id = 1,
.fields = vmstate_fpu_fields
};
/* TC state */
static VMStateField vmstate_tc_fields[] = {
VMSTATE_UINTTL_ARRAY(gpr, TCState, 32),
VMSTATE_UINTTL(PC, TCState),
VMSTATE_UINTTL_ARRAY(HI, TCState, MIPS_DSP_ACC),
VMSTATE_UINTTL_ARRAY(LO, TCState, MIPS_DSP_ACC),
VMSTATE_UINTTL_ARRAY(ACX, TCState, MIPS_DSP_ACC),
VMSTATE_UINTTL(DSPControl, TCState),
VMSTATE_INT32(CP0_TCStatus, TCState),
VMSTATE_INT32(CP0_TCBind, TCState),
VMSTATE_UINTTL(CP0_TCHalt, TCState),
VMSTATE_UINTTL(CP0_TCContext, TCState),
VMSTATE_UINTTL(CP0_TCSchedule, TCState),
VMSTATE_UINTTL(CP0_TCScheFBack, TCState),
VMSTATE_INT32(CP0_Debug_tcstatus, TCState),
VMSTATE_UINTTL(CP0_UserLocal, TCState),
VMSTATE_INT32(msacsr, TCState),
VMSTATE_END_OF_LIST()
};
const VMStateDescription vmstate_tc = {
.name = "cpu/tc",
.version_id = 1,
.minimum_version_id = 1,
.fields = vmstate_tc_fields
};
const VMStateDescription vmstate_inactive_tc = {
.name = "cpu/inactive_tc",
.version_id = 1,
.minimum_version_id = 1,
.fields = vmstate_tc_fields
};
/* MVP state */
const VMStateDescription vmstate_mvp = {
.name = "cpu/mvp",
.version_id = 1,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
VMSTATE_INT32(CP0_MVPControl, CPUMIPSMVPContext),
VMSTATE_INT32(CP0_MVPConf0, CPUMIPSMVPContext),
VMSTATE_INT32(CP0_MVPConf1, CPUMIPSMVPContext),
VMSTATE_END_OF_LIST()
}
};
/* TLB state */
static int get_tlb(QEMUFile *f, void *pv, size_t size)
{
r4k_tlb_t *v = pv;
uint16_t flags;
qemu_get_betls(f, &v->VPN);
qemu_get_be32s(f, &v->PageMask);
qemu_get_be16s(f, &v->ASID);
qemu_get_be16s(f, &flags);
v->G = (flags >> 10) & 1;
v->C0 = (flags >> 7) & 3;
v->C1 = (flags >> 4) & 3;
v->V0 = (flags >> 3) & 1;
v->V1 = (flags >> 2) & 1;
v->D0 = (flags >> 1) & 1;
v->D1 = (flags >> 0) & 1;
v->EHINV = (flags >> 15) & 1;
v->RI1 = (flags >> 14) & 1;
v->RI0 = (flags >> 13) & 1;
v->XI1 = (flags >> 12) & 1;
v->XI0 = (flags >> 11) & 1;
qemu_get_be64s(f, &v->PFN[0]);
qemu_get_be64s(f, &v->PFN[1]);
return 0;
}
static void put_tlb(QEMUFile *f, void *pv, size_t size)
{
r4k_tlb_t *v = pv;
uint16_t asid = v->ASID;
uint16_t flags = ((v->EHINV << 15) |
(v->RI1 << 14) |
(v->RI0 << 13) |
(v->XI1 << 12) |
(v->XI0 << 11) |
(v->G << 10) |
(v->C0 << 7) |
(v->C1 << 4) |
(v->V0 << 3) |
(v->V1 << 2) |
(v->D0 << 1) |
(v->D1 << 0));
qemu_put_betls(f, &v->VPN);
qemu_put_be32s(f, &v->PageMask);
qemu_put_be16s(f, &asid);
qemu_put_be16s(f, &flags);
qemu_put_be64s(f, &v->PFN[0]);
qemu_put_be64s(f, &v->PFN[1]);
}
const VMStateInfo vmstate_info_tlb = {
.name = "tlb_entry",
.get = get_tlb,
.put = put_tlb,
};
#define VMSTATE_TLB_ARRAY_V(_f, _s, _n, _v) \
VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_tlb, r4k_tlb_t)
#define VMSTATE_TLB_ARRAY(_f, _s, _n) \
VMSTATE_TLB_ARRAY_V(_f, _s, _n, 0)
const VMStateDescription vmstate_tlb = {
.name = "cpu/tlb",
.version_id = 2,
.minimum_version_id = 2,
.fields = (VMStateField[]) {
VMSTATE_UINT32(nb_tlb, CPUMIPSTLBContext),
VMSTATE_UINT32(tlb_in_use, CPUMIPSTLBContext),
VMSTATE_TLB_ARRAY(mmu.r4k.tlb, CPUMIPSTLBContext, MIPS_TLB_MAX),
VMSTATE_END_OF_LIST()
}
};
/* MIPS CPU state */
const VMStateDescription vmstate_mips_cpu = {
.name = "cpu",
.version_id = 8,
.minimum_version_id = 8,
.post_load = cpu_post_load,
.fields = (VMStateField[]) {
/* Active TC */
VMSTATE_STRUCT(env.active_tc, MIPSCPU, 1, vmstate_tc, TCState),
/* Active FPU */
VMSTATE_STRUCT(env.active_fpu, MIPSCPU, 1, vmstate_fpu,
CPUMIPSFPUContext),
/* MVP */
VMSTATE_STRUCT_POINTER(env.mvp, MIPSCPU, vmstate_mvp,
CPUMIPSMVPContext),
/* TLB */
VMSTATE_STRUCT_POINTER(env.tlb, MIPSCPU, vmstate_tlb,
CPUMIPSTLBContext),
/* CPU metastate */
VMSTATE_UINT32(env.current_tc, MIPSCPU),
VMSTATE_UINT32(env.current_fpu, MIPSCPU),
VMSTATE_INT32(env.error_code, MIPSCPU),
VMSTATE_UINTTL(env.btarget, MIPSCPU),
VMSTATE_UINTTL(env.bcond, MIPSCPU),
/* Remaining CP0 registers */
VMSTATE_INT32(env.CP0_Index, MIPSCPU),
VMSTATE_INT32(env.CP0_Random, MIPSCPU),
VMSTATE_INT32(env.CP0_VPEControl, MIPSCPU),
VMSTATE_INT32(env.CP0_VPEConf0, MIPSCPU),
VMSTATE_INT32(env.CP0_VPEConf1, MIPSCPU),
VMSTATE_UINTTL(env.CP0_YQMask, MIPSCPU),
VMSTATE_UINTTL(env.CP0_VPESchedule, MIPSCPU),
VMSTATE_UINTTL(env.CP0_VPEScheFBack, MIPSCPU),
VMSTATE_INT32(env.CP0_VPEOpt, MIPSCPU),
VMSTATE_UINT64(env.CP0_EntryLo0, MIPSCPU),
VMSTATE_UINT64(env.CP0_EntryLo1, MIPSCPU),
VMSTATE_UINTTL(env.CP0_Context, MIPSCPU),
VMSTATE_INT32(env.CP0_PageMask, MIPSCPU),
VMSTATE_INT32(env.CP0_PageGrain, MIPSCPU),
VMSTATE_INT32(env.CP0_Wired, MIPSCPU),
VMSTATE_INT32(env.CP0_SRSConf0, MIPSCPU),
VMSTATE_INT32(env.CP0_SRSConf1, MIPSCPU),
VMSTATE_INT32(env.CP0_SRSConf2, MIPSCPU),
VMSTATE_INT32(env.CP0_SRSConf3, MIPSCPU),
VMSTATE_INT32(env.CP0_SRSConf4, MIPSCPU),
VMSTATE_INT32(env.CP0_HWREna, MIPSCPU),
VMSTATE_UINTTL(env.CP0_BadVAddr, MIPSCPU),
VMSTATE_UINT32(env.CP0_BadInstr, MIPSCPU),
VMSTATE_UINT32(env.CP0_BadInstrP, MIPSCPU),
VMSTATE_INT32(env.CP0_Count, MIPSCPU),
VMSTATE_UINTTL(env.CP0_EntryHi, MIPSCPU),
VMSTATE_INT32(env.CP0_Compare, MIPSCPU),
VMSTATE_INT32(env.CP0_Status, MIPSCPU),
VMSTATE_INT32(env.CP0_IntCtl, MIPSCPU),
VMSTATE_INT32(env.CP0_SRSCtl, MIPSCPU),
VMSTATE_INT32(env.CP0_SRSMap, MIPSCPU),
VMSTATE_INT32(env.CP0_Cause, MIPSCPU),
VMSTATE_UINTTL(env.CP0_EPC, MIPSCPU),
VMSTATE_INT32(env.CP0_PRid, MIPSCPU),
VMSTATE_INT32(env.CP0_EBase, MIPSCPU),
VMSTATE_INT32(env.CP0_Config0, MIPSCPU),
VMSTATE_INT32(env.CP0_Config1, MIPSCPU),
VMSTATE_INT32(env.CP0_Config2, MIPSCPU),
VMSTATE_INT32(env.CP0_Config3, MIPSCPU),
VMSTATE_INT32(env.CP0_Config6, MIPSCPU),
VMSTATE_INT32(env.CP0_Config7, MIPSCPU),
VMSTATE_UINT64_ARRAY(env.CP0_MAAR, MIPSCPU, MIPS_MAAR_MAX),
VMSTATE_INT32(env.CP0_MAARI, MIPSCPU),
VMSTATE_UINT64(env.lladdr, MIPSCPU),
VMSTATE_UINTTL_ARRAY(env.CP0_WatchLo, MIPSCPU, 8),
VMSTATE_INT32_ARRAY(env.CP0_WatchHi, MIPSCPU, 8),
VMSTATE_UINTTL(env.CP0_XContext, MIPSCPU),
VMSTATE_INT32(env.CP0_Framemask, MIPSCPU),
VMSTATE_INT32(env.CP0_Debug, MIPSCPU),
VMSTATE_UINTTL(env.CP0_DEPC, MIPSCPU),
VMSTATE_INT32(env.CP0_Performance0, MIPSCPU),
VMSTATE_UINT64(env.CP0_TagLo, MIPSCPU),
VMSTATE_INT32(env.CP0_DataLo, MIPSCPU),
VMSTATE_INT32(env.CP0_TagHi, MIPSCPU),
VMSTATE_INT32(env.CP0_DataHi, MIPSCPU),
VMSTATE_UINTTL(env.CP0_ErrorEPC, MIPSCPU),
VMSTATE_INT32(env.CP0_DESAVE, MIPSCPU),
VMSTATE_UINTTL_ARRAY(env.CP0_KScratch, MIPSCPU, MIPS_KSCRATCH_NUM),
/* Inactive TC */
VMSTATE_STRUCT_ARRAY(env.tcs, MIPSCPU, MIPS_SHADOW_SET_MAX, 1,
vmstate_inactive_tc, TCState),
VMSTATE_STRUCT_ARRAY(env.fpus, MIPSCPU, MIPS_FPU_MAX, 1,
vmstate_inactive_fpu, CPUMIPSFPUContext),
VMSTATE_END_OF_LIST()
},
};

91
target/mips/mips-defs.h Normal file
View file

@ -0,0 +1,91 @@
#ifndef QEMU_MIPS_DEFS_H
#define QEMU_MIPS_DEFS_H
/* If we want to use host float regs... */
//#define USE_HOST_FLOAT_REGS
/* Real pages are variable size... */
#define TARGET_PAGE_BITS 12
#define MIPS_TLB_MAX 128
#if defined(TARGET_MIPS64)
#define TARGET_LONG_BITS 64
#define TARGET_PHYS_ADDR_SPACE_BITS 48
#define TARGET_VIRT_ADDR_SPACE_BITS 48
#else
#define TARGET_LONG_BITS 32
#define TARGET_PHYS_ADDR_SPACE_BITS 40
#define TARGET_VIRT_ADDR_SPACE_BITS 32
#endif
/* Masks used to mark instructions to indicate which ISA level they
were introduced in. */
#define ISA_MIPS1 0x00000001
#define ISA_MIPS2 0x00000002
#define ISA_MIPS3 0x00000004
#define ISA_MIPS4 0x00000008
#define ISA_MIPS5 0x00000010
#define ISA_MIPS32 0x00000020
#define ISA_MIPS32R2 0x00000040
#define ISA_MIPS64 0x00000080
#define ISA_MIPS64R2 0x00000100
#define ISA_MIPS32R3 0x00000200
#define ISA_MIPS64R3 0x00000400
#define ISA_MIPS32R5 0x00000800
#define ISA_MIPS64R5 0x00001000
#define ISA_MIPS32R6 0x00002000
#define ISA_MIPS64R6 0x00004000
/* MIPS ASEs. */
#define ASE_MIPS16 0x00010000
#define ASE_MIPS3D 0x00020000
#define ASE_MDMX 0x00040000
#define ASE_DSP 0x00080000
#define ASE_DSPR2 0x00100000
#define ASE_MT 0x00200000
#define ASE_SMARTMIPS 0x00400000
#define ASE_MICROMIPS 0x00800000
#define ASE_MSA 0x01000000
/* Chip specific instructions. */
#define INSN_LOONGSON2E 0x20000000
#define INSN_LOONGSON2F 0x40000000
#define INSN_VR54XX 0x80000000
/* MIPS CPU defines. */
#define CPU_MIPS1 (ISA_MIPS1)
#define CPU_MIPS2 (CPU_MIPS1 | ISA_MIPS2)
#define CPU_MIPS3 (CPU_MIPS2 | ISA_MIPS3)
#define CPU_MIPS4 (CPU_MIPS3 | ISA_MIPS4)
#define CPU_VR54XX (CPU_MIPS4 | INSN_VR54XX)
#define CPU_LOONGSON2E (CPU_MIPS3 | INSN_LOONGSON2E)
#define CPU_LOONGSON2F (CPU_MIPS3 | INSN_LOONGSON2F)
#define CPU_MIPS5 (CPU_MIPS4 | ISA_MIPS5)
/* MIPS Technologies "Release 1" */
#define CPU_MIPS32 (CPU_MIPS2 | ISA_MIPS32)
#define CPU_MIPS64 (CPU_MIPS5 | CPU_MIPS32 | ISA_MIPS64)
/* MIPS Technologies "Release 2" */
#define CPU_MIPS32R2 (CPU_MIPS32 | ISA_MIPS32R2)
#define CPU_MIPS64R2 (CPU_MIPS64 | CPU_MIPS32R2 | ISA_MIPS64R2)
/* MIPS Technologies "Release 3" */
#define CPU_MIPS32R3 (CPU_MIPS32R2 | ISA_MIPS32R3)
#define CPU_MIPS64R3 (CPU_MIPS64R2 | CPU_MIPS32R3 | ISA_MIPS64R3)
/* MIPS Technologies "Release 5" */
#define CPU_MIPS32R5 (CPU_MIPS32R3 | ISA_MIPS32R5)
#define CPU_MIPS64R5 (CPU_MIPS64R3 | CPU_MIPS32R5 | ISA_MIPS64R5)
/* MIPS Technologies "Release 6" */
#define CPU_MIPS32R6 (CPU_MIPS32R5 | ISA_MIPS32R6)
#define CPU_MIPS64R6 (CPU_MIPS64R5 | CPU_MIPS32R6 | ISA_MIPS64R6)
/* Strictly follow the architecture standard:
- Disallow "special" instruction handling for PMON/SPIM.
Note that we still maintain Count/Compare to match the host clock. */
//#define MIPS_STRICT_STANDARD 1
#endif /* QEMU_MIPS_DEFS_H */

374
target/mips/mips-semi.c Normal file
View file

@ -0,0 +1,374 @@
/*
* Unified Hosting Interface syscalls.
*
* Copyright (c) 2015 Imagination Technologies
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include "qemu/osdep.h"
#include "cpu.h"
#include "qemu/log.h"
#include "exec/helper-proto.h"
#include "exec/softmmu-semi.h"
#include "exec/semihost.h"
typedef enum UHIOp {
UHI_exit = 1,
UHI_open = 2,
UHI_close = 3,
UHI_read = 4,
UHI_write = 5,
UHI_lseek = 6,
UHI_unlink = 7,
UHI_fstat = 8,
UHI_argc = 9,
UHI_argnlen = 10,
UHI_argn = 11,
UHI_plog = 13,
UHI_assert = 14,
UHI_pread = 19,
UHI_pwrite = 20,
UHI_link = 22
} UHIOp;
typedef struct UHIStat {
int16_t uhi_st_dev;
uint16_t uhi_st_ino;
uint32_t uhi_st_mode;
uint16_t uhi_st_nlink;
uint16_t uhi_st_uid;
uint16_t uhi_st_gid;
int16_t uhi_st_rdev;
uint64_t uhi_st_size;
uint64_t uhi_st_atime;
uint64_t uhi_st_spare1;
uint64_t uhi_st_mtime;
uint64_t uhi_st_spare2;
uint64_t uhi_st_ctime;
uint64_t uhi_st_spare3;
uint64_t uhi_st_blksize;
uint64_t uhi_st_blocks;
uint64_t uhi_st_spare4[2];
} UHIStat;
enum UHIOpenFlags {
UHIOpen_RDONLY = 0x0,
UHIOpen_WRONLY = 0x1,
UHIOpen_RDWR = 0x2,
UHIOpen_APPEND = 0x8,
UHIOpen_CREAT = 0x200,
UHIOpen_TRUNC = 0x400,
UHIOpen_EXCL = 0x800
};
/* Errno values taken from asm-mips/errno.h */
static uint16_t host_to_mips_errno[] = {
[ENAMETOOLONG] = 78,
#ifdef EOVERFLOW
[EOVERFLOW] = 79,
#endif
#ifdef ELOOP
[ELOOP] = 90,
#endif
};
static int errno_mips(int err)
{
if (err < 0 || err >= ARRAY_SIZE(host_to_mips_errno)) {
return EINVAL;
} else if (host_to_mips_errno[err]) {
return host_to_mips_errno[err];
} else {
return err;
}
}
static int copy_stat_to_target(CPUMIPSState *env, const struct stat *src,
target_ulong vaddr)
{
hwaddr len = sizeof(struct UHIStat);
UHIStat *dst = lock_user(VERIFY_WRITE, vaddr, len, 0);
if (!dst) {
errno = EFAULT;
return -1;
}
dst->uhi_st_dev = tswap16(src->st_dev);
dst->uhi_st_ino = tswap16(src->st_ino);
dst->uhi_st_mode = tswap32(src->st_mode);
dst->uhi_st_nlink = tswap16(src->st_nlink);
dst->uhi_st_uid = tswap16(src->st_uid);
dst->uhi_st_gid = tswap16(src->st_gid);
dst->uhi_st_rdev = tswap16(src->st_rdev);
dst->uhi_st_size = tswap64(src->st_size);
dst->uhi_st_atime = tswap64(src->st_atime);
dst->uhi_st_mtime = tswap64(src->st_mtime);
dst->uhi_st_ctime = tswap64(src->st_ctime);
#ifdef _WIN32
dst->uhi_st_blksize = 0;
dst->uhi_st_blocks = 0;
#else
dst->uhi_st_blksize = tswap64(src->st_blksize);
dst->uhi_st_blocks = tswap64(src->st_blocks);
#endif
unlock_user(dst, vaddr, len);
return 0;
}
static int get_open_flags(target_ulong target_flags)
{
int open_flags = 0;
if (target_flags & UHIOpen_RDWR) {
open_flags |= O_RDWR;
} else if (target_flags & UHIOpen_WRONLY) {
open_flags |= O_WRONLY;
} else {
open_flags |= O_RDONLY;
}
open_flags |= (target_flags & UHIOpen_APPEND) ? O_APPEND : 0;
open_flags |= (target_flags & UHIOpen_CREAT) ? O_CREAT : 0;
open_flags |= (target_flags & UHIOpen_TRUNC) ? O_TRUNC : 0;
open_flags |= (target_flags & UHIOpen_EXCL) ? O_EXCL : 0;
return open_flags;
}
static int write_to_file(CPUMIPSState *env, target_ulong fd, target_ulong vaddr,
target_ulong len, target_ulong offset)
{
int num_of_bytes;
void *dst = lock_user(VERIFY_READ, vaddr, len, 1);
if (!dst) {
errno = EFAULT;
return -1;
}
if (offset) {
#ifdef _WIN32
num_of_bytes = 0;
#else
num_of_bytes = pwrite(fd, dst, len, offset);
#endif
} else {
num_of_bytes = write(fd, dst, len);
}
unlock_user(dst, vaddr, 0);
return num_of_bytes;
}
static int read_from_file(CPUMIPSState *env, target_ulong fd,
target_ulong vaddr, target_ulong len,
target_ulong offset)
{
int num_of_bytes;
void *dst = lock_user(VERIFY_WRITE, vaddr, len, 0);
if (!dst) {
errno = EFAULT;
return -1;
}
if (offset) {
#ifdef _WIN32
num_of_bytes = 0;
#else
num_of_bytes = pread(fd, dst, len, offset);
#endif
} else {
num_of_bytes = read(fd, dst, len);
}
unlock_user(dst, vaddr, len);
return num_of_bytes;
}
static int copy_argn_to_target(CPUMIPSState *env, int arg_num,
target_ulong vaddr)
{
int strsize = strlen(semihosting_get_arg(arg_num)) + 1;
char *dst = lock_user(VERIFY_WRITE, vaddr, strsize, 0);
if (!dst) {
return -1;
}
strcpy(dst, semihosting_get_arg(arg_num));
unlock_user(dst, vaddr, strsize);
return 0;
}
#define GET_TARGET_STRING(p, addr) \
do { \
p = lock_user_string(addr); \
if (!p) { \
gpr[2] = -1; \
gpr[3] = EFAULT; \
goto uhi_done; \
} \
} while (0)
#define GET_TARGET_STRINGS_2(p, addr, p2, addr2) \
do { \
p = lock_user_string(addr); \
if (!p) { \
gpr[2] = -1; \
gpr[3] = EFAULT; \
goto uhi_done; \
} \
p2 = lock_user_string(addr2); \
if (!p2) { \
unlock_user(p, addr, 0); \
gpr[2] = -1; \
gpr[3] = EFAULT; \
goto uhi_done; \
} \
} while (0)
#define FREE_TARGET_STRING(p, gpr) \
do { \
unlock_user(p, gpr, 0); \
} while (0)
void helper_do_semihosting(CPUMIPSState *env)
{
target_ulong *gpr = env->active_tc.gpr;
const UHIOp op = gpr[25];
char *p, *p2;
switch (op) {
case UHI_exit:
qemu_log("UHI(%d): exit(%d)\n", op, (int)gpr[4]);
exit(gpr[4]);
case UHI_open:
GET_TARGET_STRING(p, gpr[4]);
if (!strcmp("/dev/stdin", p)) {
gpr[2] = 0;
} else if (!strcmp("/dev/stdout", p)) {
gpr[2] = 1;
} else if (!strcmp("/dev/stderr", p)) {
gpr[2] = 2;
} else {
gpr[2] = open(p, get_open_flags(gpr[5]), gpr[6]);
gpr[3] = errno_mips(errno);
}
FREE_TARGET_STRING(p, gpr[4]);
break;
case UHI_close:
if (gpr[4] < 3) {
/* ignore closing stdin/stdout/stderr */
gpr[2] = 0;
goto uhi_done;
}
gpr[2] = close(gpr[4]);
gpr[3] = errno_mips(errno);
break;
case UHI_read:
gpr[2] = read_from_file(env, gpr[4], gpr[5], gpr[6], 0);
gpr[3] = errno_mips(errno);
break;
case UHI_write:
gpr[2] = write_to_file(env, gpr[4], gpr[5], gpr[6], 0);
gpr[3] = errno_mips(errno);
break;
case UHI_lseek:
gpr[2] = lseek(gpr[4], gpr[5], gpr[6]);
gpr[3] = errno_mips(errno);
break;
case UHI_unlink:
GET_TARGET_STRING(p, gpr[4]);
gpr[2] = remove(p);
gpr[3] = errno_mips(errno);
FREE_TARGET_STRING(p, gpr[4]);
break;
case UHI_fstat:
{
struct stat sbuf;
memset(&sbuf, 0, sizeof(sbuf));
gpr[2] = fstat(gpr[4], &sbuf);
gpr[3] = errno_mips(errno);
if (gpr[2]) {
goto uhi_done;
}
gpr[2] = copy_stat_to_target(env, &sbuf, gpr[5]);
gpr[3] = errno_mips(errno);
}
break;
case UHI_argc:
gpr[2] = semihosting_get_argc();
break;
case UHI_argnlen:
if (gpr[4] >= semihosting_get_argc()) {
gpr[2] = -1;
goto uhi_done;
}
gpr[2] = strlen(semihosting_get_arg(gpr[4]));
break;
case UHI_argn:
if (gpr[4] >= semihosting_get_argc()) {
gpr[2] = -1;
goto uhi_done;
}
gpr[2] = copy_argn_to_target(env, gpr[4], gpr[5]);
break;
case UHI_plog:
GET_TARGET_STRING(p, gpr[4]);
p2 = strstr(p, "%d");
if (p2) {
int char_num = p2 - p;
char *buf = g_malloc(char_num + 1);
strncpy(buf, p, char_num);
buf[char_num] = '\0';
gpr[2] = printf("%s%d%s", buf, (int)gpr[5], p2 + 2);
g_free(buf);
} else {
gpr[2] = printf("%s", p);
}
FREE_TARGET_STRING(p, gpr[4]);
break;
case UHI_assert:
GET_TARGET_STRINGS_2(p, gpr[4], p2, gpr[5]);
printf("assertion '");
printf("\"%s\"", p);
printf("': file \"%s\", line %d\n", p2, (int)gpr[6]);
FREE_TARGET_STRING(p2, gpr[5]);
FREE_TARGET_STRING(p, gpr[4]);
abort();
break;
case UHI_pread:
gpr[2] = read_from_file(env, gpr[4], gpr[5], gpr[6], gpr[7]);
gpr[3] = errno_mips(errno);
break;
case UHI_pwrite:
gpr[2] = write_to_file(env, gpr[4], gpr[5], gpr[6], gpr[7]);
gpr[3] = errno_mips(errno);
break;
#ifndef _WIN32
case UHI_link:
GET_TARGET_STRINGS_2(p, gpr[4], p2, gpr[5]);
gpr[2] = link(p, p2);
gpr[3] = errno_mips(errno);
FREE_TARGET_STRING(p2, gpr[5]);
FREE_TARGET_STRING(p, gpr[4]);
break;
#endif
default:
fprintf(stderr, "Unknown UHI operation %d\n", op);
abort();
}
uhi_done:
return;
}

3453
target/mips/msa_helper.c Normal file

File diff suppressed because it is too large Load diff

4196
target/mips/op_helper.c Normal file

File diff suppressed because it is too large Load diff

20423
target/mips/translate.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,944 @@
/*
* MIPS emulation for qemu: CPU initialisation routines.
*
* Copyright (c) 2004-2005 Jocelyn Mayer
* Copyright (c) 2007 Herve Poussineau
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
/* CPU / CPU family specific config register values. */
/* Have config1, uncached coherency */
#define MIPS_CONFIG0 \
((1U << CP0C0_M) | (0x2 << CP0C0_K0))
/* Have config2, no coprocessor2 attached, no MDMX support attached,
no performance counters, watch registers present,
no code compression, EJTAG present, no FPU */
#define MIPS_CONFIG1 \
((1U << CP0C1_M) | \
(0 << CP0C1_C2) | (0 << CP0C1_MD) | (0 << CP0C1_PC) | \
(1 << CP0C1_WR) | (0 << CP0C1_CA) | (1 << CP0C1_EP) | \
(0 << CP0C1_FP))
/* Have config3, no tertiary/secondary caches implemented */
#define MIPS_CONFIG2 \
((1U << CP0C2_M))
/* No config4, no DSP ASE, no large physaddr (PABITS),
no external interrupt controller, no vectored interrupts,
no 1kb pages, no SmartMIPS ASE, no trace logic */
#define MIPS_CONFIG3 \
((0 << CP0C3_M) | (0 << CP0C3_DSPP) | (0 << CP0C3_LPA) | \
(0 << CP0C3_VEIC) | (0 << CP0C3_VInt) | (0 << CP0C3_SP) | \
(0 << CP0C3_SM) | (0 << CP0C3_TL))
#define MIPS_CONFIG4 \
((0 << CP0C4_M))
#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;
int insn_flags;
enum mips_mmu_types mmu_type;
};
/*****************************************************************************/
/* MIPS CPU definitions */
static const mips_def_t mips_defs[] =
{
{
.name = "4Kc",
.CP0_PRid = 0x00018000,
.CP0_Config0 = MIPS_CONFIG0 | (MMU_TYPE_R4000 << CP0C0_MT),
.CP0_Config1 = MIPS_CONFIG1 | (15 << CP0C1_MMU) |
(0 << CP0C1_IS) | (3 << CP0C1_IL) | (1 << CP0C1_IA) |
(0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA) |
(0 << CP0C1_CA),
.CP0_Config2 = MIPS_CONFIG2,
.CP0_Config3 = MIPS_CONFIG3,
.CP0_LLAddr_rw_bitmask = 0,
.CP0_LLAddr_shift = 4,
.SYNCI_Step = 32,
.CCRes = 2,
.CP0_Status_rw_bitmask = 0x1278FF17,
.SEGBITS = 32,
.PABITS = 32,
.insn_flags = CPU_MIPS32,
.mmu_type = MMU_TYPE_R4000,
},
{
.name = "4Km",
.CP0_PRid = 0x00018300,
/* Config1 implemented, fixed mapping MMU,
no virtual icache, uncached coherency. */
.CP0_Config0 = MIPS_CONFIG0 | (MMU_TYPE_FMT << CP0C0_MT),
.CP0_Config1 = MIPS_CONFIG1 |
(0 << CP0C1_IS) | (3 << CP0C1_IL) | (1 << CP0C1_IA) |
(0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA) |
(1 << CP0C1_CA),
.CP0_Config2 = MIPS_CONFIG2,
.CP0_Config3 = MIPS_CONFIG3,
.CP0_LLAddr_rw_bitmask = 0,
.CP0_LLAddr_shift = 4,
.SYNCI_Step = 32,
.CCRes = 2,
.CP0_Status_rw_bitmask = 0x1258FF17,
.SEGBITS = 32,
.PABITS = 32,
.insn_flags = CPU_MIPS32 | ASE_MIPS16,
.mmu_type = MMU_TYPE_FMT,
},
{
.name = "4KEcR1",
.CP0_PRid = 0x00018400,
.CP0_Config0 = MIPS_CONFIG0 | (MMU_TYPE_R4000 << CP0C0_MT),
.CP0_Config1 = MIPS_CONFIG1 | (15 << CP0C1_MMU) |
(0 << CP0C1_IS) | (3 << CP0C1_IL) | (1 << CP0C1_IA) |
(0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA) |
(0 << CP0C1_CA),
.CP0_Config2 = MIPS_CONFIG2,
.CP0_Config3 = MIPS_CONFIG3,
.CP0_LLAddr_rw_bitmask = 0,
.CP0_LLAddr_shift = 4,
.SYNCI_Step = 32,
.CCRes = 2,
.CP0_Status_rw_bitmask = 0x1278FF17,
.SEGBITS = 32,
.PABITS = 32,
.insn_flags = CPU_MIPS32,
.mmu_type = MMU_TYPE_R4000,
},
{
.name = "4KEmR1",
.CP0_PRid = 0x00018500,
.CP0_Config0 = MIPS_CONFIG0 | (MMU_TYPE_FMT << CP0C0_MT),
.CP0_Config1 = MIPS_CONFIG1 |
(0 << CP0C1_IS) | (3 << CP0C1_IL) | (1 << CP0C1_IA) |
(0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA) |
(1 << CP0C1_CA),
.CP0_Config2 = MIPS_CONFIG2,
.CP0_Config3 = MIPS_CONFIG3,
.CP0_LLAddr_rw_bitmask = 0,
.CP0_LLAddr_shift = 4,
.SYNCI_Step = 32,
.CCRes = 2,
.CP0_Status_rw_bitmask = 0x1258FF17,
.SEGBITS = 32,
.PABITS = 32,
.insn_flags = CPU_MIPS32 | ASE_MIPS16,
.mmu_type = MMU_TYPE_FMT,
},
{
.name = "4KEc",
.CP0_PRid = 0x00019000,
.CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR) |
(MMU_TYPE_R4000 << CP0C0_MT),
.CP0_Config1 = MIPS_CONFIG1 | (15 << CP0C1_MMU) |
(0 << CP0C1_IS) | (3 << CP0C1_IL) | (1 << CP0C1_IA) |
(0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA) |
(0 << CP0C1_CA),
.CP0_Config2 = MIPS_CONFIG2,
.CP0_Config3 = MIPS_CONFIG3 | (0 << CP0C3_VInt),
.CP0_LLAddr_rw_bitmask = 0,
.CP0_LLAddr_shift = 4,
.SYNCI_Step = 32,
.CCRes = 2,
.CP0_Status_rw_bitmask = 0x1278FF17,
.SEGBITS = 32,
.PABITS = 32,
.insn_flags = CPU_MIPS32R2,
.mmu_type = MMU_TYPE_R4000,
},
{
.name = "4KEm",
.CP0_PRid = 0x00019100,
.CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR) |
(MMU_TYPE_FMT << CP0C0_MT),
.CP0_Config1 = MIPS_CONFIG1 |
(0 << CP0C1_IS) | (3 << CP0C1_IL) | (1 << CP0C1_IA) |
(0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA) |
(1 << CP0C1_CA),
.CP0_Config2 = MIPS_CONFIG2,
.CP0_Config3 = MIPS_CONFIG3,
.CP0_LLAddr_rw_bitmask = 0,
.CP0_LLAddr_shift = 4,
.SYNCI_Step = 32,
.CCRes = 2,
.CP0_Status_rw_bitmask = 0x1258FF17,
.SEGBITS = 32,
.PABITS = 32,
.insn_flags = CPU_MIPS32R2 | ASE_MIPS16,
.mmu_type = MMU_TYPE_FMT,
},
{
.name = "24Kc",
.CP0_PRid = 0x00019300,
.CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR) |
(MMU_TYPE_R4000 << CP0C0_MT),
.CP0_Config1 = MIPS_CONFIG1 | (15 << CP0C1_MMU) |
(0 << CP0C1_IS) | (3 << CP0C1_IL) | (1 << CP0C1_IA) |
(0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA) |
(1 << CP0C1_CA),
.CP0_Config2 = MIPS_CONFIG2,
.CP0_Config3 = MIPS_CONFIG3 | (0 << CP0C3_VInt),
.CP0_LLAddr_rw_bitmask = 0,
.CP0_LLAddr_shift = 4,
.SYNCI_Step = 32,
.CCRes = 2,
/* No DSP implemented. */
.CP0_Status_rw_bitmask = 0x1278FF1F,
.SEGBITS = 32,
.PABITS = 32,
.insn_flags = CPU_MIPS32R2 | ASE_MIPS16,
.mmu_type = MMU_TYPE_R4000,
},
{
.name = "24KEc",
.CP0_PRid = 0x00019600,
.CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR) |
(MMU_TYPE_R4000 << CP0C0_MT),
.CP0_Config1 = MIPS_CONFIG1 | (15 << CP0C1_MMU) |
(0 << CP0C1_IS) | (3 << CP0C1_IL) | (1 << CP0C1_IA) |
(0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA) |
(1 << CP0C1_CA),
.CP0_Config2 = MIPS_CONFIG2,
.CP0_Config3 = MIPS_CONFIG3 | (1 << CP0C3_DSPP) | (0 << CP0C3_VInt),
.CP0_LLAddr_rw_bitmask = 0,
.CP0_LLAddr_shift = 4,
.SYNCI_Step = 32,
.CCRes = 2,
/* we have a DSP, but no FPU */
.CP0_Status_rw_bitmask = 0x1378FF1F,
.SEGBITS = 32,
.PABITS = 32,
.insn_flags = CPU_MIPS32R2 | ASE_MIPS16 | ASE_DSP,
.mmu_type = MMU_TYPE_R4000,
},
{
.name = "24Kf",
.CP0_PRid = 0x00019300,
.CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR) |
(MMU_TYPE_R4000 << CP0C0_MT),
.CP0_Config1 = MIPS_CONFIG1 | (1 << CP0C1_FP) | (15 << CP0C1_MMU) |
(0 << CP0C1_IS) | (3 << CP0C1_IL) | (1 << CP0C1_IA) |
(0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA) |
(1 << CP0C1_CA),
.CP0_Config2 = MIPS_CONFIG2,
.CP0_Config3 = MIPS_CONFIG3 | (0 << CP0C3_VInt),
.CP0_LLAddr_rw_bitmask = 0,
.CP0_LLAddr_shift = 4,
.SYNCI_Step = 32,
.CCRes = 2,
/* No DSP implemented. */
.CP0_Status_rw_bitmask = 0x3678FF1F,
.CP1_fcr0 = (1 << FCR0_F64) | (1 << FCR0_L) | (1 << FCR0_W) |
(1 << FCR0_D) | (1 << FCR0_S) | (0x93 << FCR0_PRID),
.CP1_fcr31 = 0,
.CP1_fcr31_rw_bitmask = 0xFF83FFFF,
.SEGBITS = 32,
.PABITS = 32,
.insn_flags = CPU_MIPS32R2 | ASE_MIPS16,
.mmu_type = MMU_TYPE_R4000,
},
{
.name = "34Kf",
.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) |
(0 << CP0C1_IS) | (3 << CP0C1_IL) | (1 << CP0C1_IA) |
(0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA) |
(1 << CP0C1_CA),
.CP0_Config2 = MIPS_CONFIG2,
.CP0_Config3 = MIPS_CONFIG3 | (1 << CP0C3_VInt) | (1 << CP0C3_MT) |
(1 << CP0C3_DSPP),
.CP0_LLAddr_rw_bitmask = 0,
.CP0_LLAddr_shift = 0,
.SYNCI_Step = 32,
.CCRes = 2,
.CP0_Status_rw_bitmask = 0x3778FF1F,
.CP0_TCStatus_rw_bitmask = (0 << CP0TCSt_TCU3) | (0 << CP0TCSt_TCU2) |
(1 << CP0TCSt_TCU1) | (1 << CP0TCSt_TCU0) |
(0 << CP0TCSt_TMX) | (1 << CP0TCSt_DT) |
(1 << CP0TCSt_DA) | (1 << CP0TCSt_A) |
(0x3 << CP0TCSt_TKSU) | (1 << CP0TCSt_IXMT) |
(0xff << CP0TCSt_TASID),
.CP1_fcr0 = (1 << FCR0_F64) | (1 << FCR0_L) | (1 << FCR0_W) |
(1 << FCR0_D) | (1 << FCR0_S) | (0x95 << FCR0_PRID),
.CP1_fcr31 = 0,
.CP1_fcr31_rw_bitmask = 0xFF83FFFF,
.CP0_SRSCtl = (0xf << CP0SRSCtl_HSS),
.CP0_SRSConf0_rw_bitmask = 0x3fffffff,
.CP0_SRSConf0 = (1U << CP0SRSC0_M) | (0x3fe << CP0SRSC0_SRS3) |
(0x3fe << CP0SRSC0_SRS2) | (0x3fe << CP0SRSC0_SRS1),
.CP0_SRSConf1_rw_bitmask = 0x3fffffff,
.CP0_SRSConf1 = (1U << CP0SRSC1_M) | (0x3fe << CP0SRSC1_SRS6) |
(0x3fe << CP0SRSC1_SRS5) | (0x3fe << CP0SRSC1_SRS4),
.CP0_SRSConf2_rw_bitmask = 0x3fffffff,
.CP0_SRSConf2 = (1U << CP0SRSC2_M) | (0x3fe << CP0SRSC2_SRS9) |
(0x3fe << CP0SRSC2_SRS8) | (0x3fe << CP0SRSC2_SRS7),
.CP0_SRSConf3_rw_bitmask = 0x3fffffff,
.CP0_SRSConf3 = (1U << CP0SRSC3_M) | (0x3fe << CP0SRSC3_SRS12) |
(0x3fe << CP0SRSC3_SRS11) | (0x3fe << CP0SRSC3_SRS10),
.CP0_SRSConf4_rw_bitmask = 0x3fffffff,
.CP0_SRSConf4 = (0x3fe << CP0SRSC4_SRS15) |
(0x3fe << CP0SRSC4_SRS14) | (0x3fe << CP0SRSC4_SRS13),
.SEGBITS = 32,
.PABITS = 32,
.insn_flags = CPU_MIPS32R2 | ASE_MIPS16 | ASE_DSP | ASE_MT,
.mmu_type = MMU_TYPE_R4000,
},
{
.name = "74Kf",
.CP0_PRid = 0x00019700,
.CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR) |
(MMU_TYPE_R4000 << CP0C0_MT),
.CP0_Config1 = MIPS_CONFIG1 | (1 << CP0C1_FP) | (15 << CP0C1_MMU) |
(0 << CP0C1_IS) | (3 << CP0C1_IL) | (1 << CP0C1_IA) |
(0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA) |
(1 << CP0C1_CA),
.CP0_Config2 = MIPS_CONFIG2,
.CP0_Config3 = MIPS_CONFIG3 | (1 << CP0C3_DSP2P) | (1 << CP0C3_DSPP) |
(1 << CP0C3_VInt),
.CP0_LLAddr_rw_bitmask = 0,
.CP0_LLAddr_shift = 4,
.SYNCI_Step = 32,
.CCRes = 2,
.CP0_Status_rw_bitmask = 0x3778FF1F,
.CP1_fcr0 = (1 << FCR0_F64) | (1 << FCR0_L) | (1 << FCR0_W) |
(1 << FCR0_D) | (1 << FCR0_S) | (0x93 << FCR0_PRID),
.CP1_fcr31 = 0,
.CP1_fcr31_rw_bitmask = 0xFF83FFFF,
.SEGBITS = 32,
.PABITS = 32,
.insn_flags = CPU_MIPS32R2 | ASE_MIPS16 | ASE_DSP | ASE_DSPR2,
.mmu_type = MMU_TYPE_R4000,
},
{
.name = "M14K",
.CP0_PRid = 0x00019b00,
/* Config1 implemented, fixed mapping MMU,
no virtual icache, uncached coherency. */
.CP0_Config0 = MIPS_CONFIG0 | (0x2 << CP0C0_KU) | (0x2 << CP0C0_K23) |
(0x1 << CP0C0_AR) | (MMU_TYPE_FMT << CP0C0_MT),
.CP0_Config1 = MIPS_CONFIG1,
.CP0_Config2 = MIPS_CONFIG2,
.CP0_Config3 = MIPS_CONFIG3 | (0x2 << CP0C3_ISA) | (1 << CP0C3_VInt),
.CP0_LLAddr_rw_bitmask = 0,
.CP0_LLAddr_shift = 4,
.SYNCI_Step = 32,
.CCRes = 2,
.CP0_Status_rw_bitmask = 0x1258FF17,
.SEGBITS = 32,
.PABITS = 32,
.insn_flags = CPU_MIPS32R2 | ASE_MICROMIPS,
.mmu_type = MMU_TYPE_FMT,
},
{
.name = "M14Kc",
/* This is the TLB-based MMU core. */
.CP0_PRid = 0x00019c00,
.CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR) |
(MMU_TYPE_R4000 << CP0C0_MT),
.CP0_Config1 = MIPS_CONFIG1 | (15 << CP0C1_MMU) |
(0 << CP0C1_IS) | (3 << CP0C1_IL) | (1 << CP0C1_IA) |
(0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA),
.CP0_Config2 = MIPS_CONFIG2,
.CP0_Config3 = MIPS_CONFIG3 | (0x2 << CP0C3_ISA) | (0 << CP0C3_VInt),
.CP0_LLAddr_rw_bitmask = 0,
.CP0_LLAddr_shift = 4,
.SYNCI_Step = 32,
.CCRes = 2,
.CP0_Status_rw_bitmask = 0x1278FF17,
.SEGBITS = 32,
.PABITS = 32,
.insn_flags = CPU_MIPS32R2 | ASE_MICROMIPS,
.mmu_type = MMU_TYPE_R4000,
},
{
/* FIXME:
* Config3: CMGCR, SC, PW, VZ, CTXTC, CDMM, TL
* Config4: MMUExtDef
* Config5: EVA, MRP
* FIR(FCR0): Has2008
* */
.name = "P5600",
.CP0_PRid = 0x0001A800,
.CP0_Config0 = MIPS_CONFIG0 | (1 << CP0C0_MM) | (1 << CP0C0_AR) |
(MMU_TYPE_R4000 << CP0C0_MT),
.CP0_Config1 = MIPS_CONFIG1 | (0x3F << CP0C1_MMU) |
(2 << CP0C1_IS) | (4 << CP0C1_IL) | (3 << CP0C1_IA) |
(2 << CP0C1_DS) | (4 << CP0C1_DL) | (3 << CP0C1_DA) |
(1 << CP0C1_PC) | (1 << CP0C1_FP),
.CP0_Config2 = MIPS_CONFIG2,
.CP0_Config3 = MIPS_CONFIG3 | (1U << CP0C3_M) | (1 << CP0C3_MSAP) |
(1 << CP0C3_BP) | (1 << CP0C3_BI) | (1 << CP0C3_ULRI) |
(1 << CP0C3_RXI) | (1 << CP0C3_LPA) | (1 << CP0C3_VInt),
.CP0_Config4 = MIPS_CONFIG4 | (1U << CP0C4_M) | (2 << CP0C4_IE) |
(0x1c << CP0C4_KScrExist),
.CP0_Config4_rw_bitmask = 0,
.CP0_Config5 = MIPS_CONFIG5 | (1 << CP0C5_MVH) | (1 << CP0C5_LLB) |
(1 << CP0C5_MRP),
.CP0_Config5_rw_bitmask = (1 << CP0C5_K) | (1 << CP0C5_CV) |
(1 << CP0C5_MSAEn) | (1 << CP0C5_UFE) |
(1 << CP0C5_FRE) | (1 << CP0C5_UFR),
.CP0_LLAddr_rw_bitmask = 0,
.CP0_LLAddr_shift = 0,
.SYNCI_Step = 32,
.CCRes = 2,
.CP0_Status_rw_bitmask = 0x3C68FF1F,
.CP0_PageGrain_rw_bitmask = (1U << CP0PG_RIE) | (1 << CP0PG_XIE) |
(1 << CP0PG_ELPA) | (1 << CP0PG_IEC),
.CP1_fcr0 = (1 << FCR0_FREP) | (1 << FCR0_UFRP) | (1 << FCR0_HAS2008) |
(1 << FCR0_F64) | (1 << FCR0_L) | (1 << FCR0_W) |
(1 << FCR0_D) | (1 << FCR0_S) | (0x03 << FCR0_PRID),
.CP1_fcr31 = (1 << FCR31_ABS2008) | (1 << FCR31_NAN2008),
.CP1_fcr31_rw_bitmask = 0xFF83FFFF,
.SEGBITS = 32,
.PABITS = 40,
.insn_flags = CPU_MIPS32R5 | ASE_MSA,
.mmu_type = MMU_TYPE_R4000,
},
{
/* A generic CPU supporting MIPS32 Release 6 ISA.
FIXME: Support IEEE 754-2008 FP.
Eventually this should be replaced by a real CPU model. */
.name = "mips32r6-generic",
.CP0_PRid = 0x00010000,
.CP0_Config0 = MIPS_CONFIG0 | (0x2 << CP0C0_AR) |
(MMU_TYPE_R4000 << CP0C0_MT),
.CP0_Config1 = MIPS_CONFIG1 | (1 << CP0C1_FP) | (31 << CP0C1_MMU) |
(2 << CP0C1_IS) | (4 << CP0C1_IL) | (3 << CP0C1_IA) |
(2 << CP0C1_DS) | (4 << CP0C1_DL) | (3 << CP0C1_DA) |
(0 << CP0C1_PC) | (1 << CP0C1_WR) | (1 << CP0C1_EP),
.CP0_Config2 = MIPS_CONFIG2,
.CP0_Config3 = MIPS_CONFIG3 | (1 << CP0C3_BP) | (1 << CP0C3_BI) |
(2 << CP0C3_ISA) | (1 << CP0C3_ULRI) |
(1 << CP0C3_RXI) | (1U << CP0C3_M),
.CP0_Config4 = MIPS_CONFIG4 | (0xfc << CP0C4_KScrExist) |
(3 << CP0C4_IE) | (1U << CP0C4_M),
.CP0_Config5 = MIPS_CONFIG5 | (1 << CP0C5_XNP) | (1 << CP0C5_LLB),
.CP0_Config5_rw_bitmask = (1 << CP0C5_SBRI) | (1 << CP0C5_FRE) |
(1 << CP0C5_UFE),
.CP0_LLAddr_rw_bitmask = 0,
.CP0_LLAddr_shift = 0,
.SYNCI_Step = 32,
.CCRes = 2,
.CP0_Status_rw_bitmask = 0x3058FF1F,
.CP0_PageGrain = (1 << CP0PG_IEC) | (1 << CP0PG_XIE) |
(1U << CP0PG_RIE),
.CP0_PageGrain_rw_bitmask = 0,
.CP1_fcr0 = (1 << FCR0_FREP) | (1 << FCR0_HAS2008) | (1 << FCR0_F64) |
(1 << FCR0_L) | (1 << FCR0_W) | (1 << FCR0_D) |
(1 << FCR0_S) | (0x00 << FCR0_PRID) | (0x0 << FCR0_REV),
.CP1_fcr31 = (1 << FCR31_ABS2008) | (1 << FCR31_NAN2008),
.CP1_fcr31_rw_bitmask = 0x0103FFFF,
.SEGBITS = 32,
.PABITS = 32,
.insn_flags = CPU_MIPS32R6 | ASE_MICROMIPS,
.mmu_type = MMU_TYPE_R4000,
},
#if defined(TARGET_MIPS64)
{
.name = "R4000",
.CP0_PRid = 0x00000400,
/* No L2 cache, icache size 8k, dcache size 8k, uncached coherency. */
.CP0_Config0 = (1 << 17) | (0x1 << 9) | (0x1 << 6) | (0x2 << CP0C0_K0),
/* Note: Config1 is only used internally, the R4000 has only Config0. */
.CP0_Config1 = (1 << CP0C1_FP) | (47 << CP0C1_MMU),
.CP0_LLAddr_rw_bitmask = 0xFFFFFFFF,
.CP0_LLAddr_shift = 4,
.SYNCI_Step = 16,
.CCRes = 2,
.CP0_Status_rw_bitmask = 0x3678FFFF,
/* The R4000 has a full 64bit FPU but doesn't use the fcr0 bits. */
.CP1_fcr0 = (0x5 << FCR0_PRID) | (0x0 << FCR0_REV),
.CP1_fcr31 = 0,
.CP1_fcr31_rw_bitmask = 0x0183FFFF,
.SEGBITS = 40,
.PABITS = 36,
.insn_flags = CPU_MIPS3,
.mmu_type = MMU_TYPE_R4000,
},
{
.name = "VR5432",
.CP0_PRid = 0x00005400,
/* No L2 cache, icache size 8k, dcache size 8k, uncached coherency. */
.CP0_Config0 = (1 << 17) | (0x1 << 9) | (0x1 << 6) | (0x2 << CP0C0_K0),
.CP0_Config1 = (1 << CP0C1_FP) | (47 << CP0C1_MMU),
.CP0_LLAddr_rw_bitmask = 0xFFFFFFFFL,
.CP0_LLAddr_shift = 4,
.SYNCI_Step = 16,
.CCRes = 2,
.CP0_Status_rw_bitmask = 0x3678FFFF,
/* The VR5432 has a full 64bit FPU but doesn't use the fcr0 bits. */
.CP1_fcr0 = (0x54 << FCR0_PRID) | (0x0 << FCR0_REV),
.CP1_fcr31 = 0,
.CP1_fcr31_rw_bitmask = 0xFF83FFFF,
.SEGBITS = 40,
.PABITS = 32,
.insn_flags = CPU_VR54XX,
.mmu_type = MMU_TYPE_R4000,
},
{
.name = "5Kc",
.CP0_PRid = 0x00018100,
.CP0_Config0 = MIPS_CONFIG0 | (0x2 << CP0C0_AT) |
(MMU_TYPE_R4000 << CP0C0_MT),
.CP0_Config1 = MIPS_CONFIG1 | (31 << CP0C1_MMU) |
(1 << CP0C1_IS) | (4 << CP0C1_IL) | (1 << CP0C1_IA) |
(1 << CP0C1_DS) | (4 << CP0C1_DL) | (1 << CP0C1_DA) |
(1 << CP0C1_PC) | (1 << CP0C1_WR) | (1 << CP0C1_EP),
.CP0_Config2 = MIPS_CONFIG2,
.CP0_Config3 = MIPS_CONFIG3,
.CP0_LLAddr_rw_bitmask = 0,
.CP0_LLAddr_shift = 4,
.SYNCI_Step = 32,
.CCRes = 2,
.CP0_Status_rw_bitmask = 0x12F8FFFF,
.SEGBITS = 42,
.PABITS = 36,
.insn_flags = CPU_MIPS64,
.mmu_type = MMU_TYPE_R4000,
},
{
.name = "5Kf",
.CP0_PRid = 0x00018100,
.CP0_Config0 = MIPS_CONFIG0 | (0x2 << CP0C0_AT) |
(MMU_TYPE_R4000 << CP0C0_MT),
.CP0_Config1 = MIPS_CONFIG1 | (1 << CP0C1_FP) | (31 << CP0C1_MMU) |
(1 << CP0C1_IS) | (4 << CP0C1_IL) | (1 << CP0C1_IA) |
(1 << CP0C1_DS) | (4 << CP0C1_DL) | (1 << CP0C1_DA) |
(1 << CP0C1_PC) | (1 << CP0C1_WR) | (1 << CP0C1_EP),
.CP0_Config2 = MIPS_CONFIG2,
.CP0_Config3 = MIPS_CONFIG3,
.CP0_LLAddr_rw_bitmask = 0,
.CP0_LLAddr_shift = 4,
.SYNCI_Step = 32,
.CCRes = 2,
.CP0_Status_rw_bitmask = 0x36F8FFFF,
/* The 5Kf has F64 / L / W but doesn't use the fcr0 bits. */
.CP1_fcr0 = (1 << FCR0_D) | (1 << FCR0_S) |
(0x81 << FCR0_PRID) | (0x0 << FCR0_REV),
.CP1_fcr31 = 0,
.CP1_fcr31_rw_bitmask = 0xFF83FFFF,
.SEGBITS = 42,
.PABITS = 36,
.insn_flags = CPU_MIPS64,
.mmu_type = MMU_TYPE_R4000,
},
{
.name = "20Kc",
/* We emulate a later version of the 20Kc, earlier ones had a broken
WAIT instruction. */
.CP0_PRid = 0x000182a0,
.CP0_Config0 = MIPS_CONFIG0 | (0x2 << CP0C0_AT) |
(MMU_TYPE_R4000 << CP0C0_MT) | (1 << CP0C0_VI),
.CP0_Config1 = MIPS_CONFIG1 | (1 << CP0C1_FP) | (47 << CP0C1_MMU) |
(2 << CP0C1_IS) | (4 << CP0C1_IL) | (3 << CP0C1_IA) |
(2 << CP0C1_DS) | (4 << CP0C1_DL) | (3 << CP0C1_DA) |
(1 << CP0C1_PC) | (1 << CP0C1_WR) | (1 << CP0C1_EP),
.CP0_Config2 = MIPS_CONFIG2,
.CP0_Config3 = MIPS_CONFIG3,
.CP0_LLAddr_rw_bitmask = 0,
.CP0_LLAddr_shift = 0,
.SYNCI_Step = 32,
.CCRes = 1,
.CP0_Status_rw_bitmask = 0x36FBFFFF,
/* The 20Kc has F64 / L / W but doesn't use the fcr0 bits. */
.CP1_fcr0 = (1 << FCR0_3D) | (1 << FCR0_PS) |
(1 << FCR0_D) | (1 << FCR0_S) |
(0x82 << FCR0_PRID) | (0x0 << FCR0_REV),
.CP1_fcr31 = 0,
.CP1_fcr31_rw_bitmask = 0xFF83FFFF,
.SEGBITS = 40,
.PABITS = 36,
.insn_flags = CPU_MIPS64 | ASE_MIPS3D,
.mmu_type = MMU_TYPE_R4000,
},
{
/* A generic CPU providing MIPS64 Release 2 features.
FIXME: Eventually this should be replaced by a real CPU model. */
.name = "MIPS64R2-generic",
.CP0_PRid = 0x00010000,
.CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR) | (0x2 << CP0C0_AT) |
(MMU_TYPE_R4000 << CP0C0_MT),
.CP0_Config1 = MIPS_CONFIG1 | (1 << CP0C1_FP) | (63 << CP0C1_MMU) |
(2 << CP0C1_IS) | (4 << CP0C1_IL) | (3 << CP0C1_IA) |
(2 << CP0C1_DS) | (4 << CP0C1_DL) | (3 << CP0C1_DA) |
(1 << CP0C1_PC) | (1 << CP0C1_WR) | (1 << CP0C1_EP),
.CP0_Config2 = MIPS_CONFIG2,
.CP0_Config3 = MIPS_CONFIG3 | (1 << CP0C3_LPA),
.CP0_LLAddr_rw_bitmask = 0,
.CP0_LLAddr_shift = 0,
.SYNCI_Step = 32,
.CCRes = 2,
.CP0_Status_rw_bitmask = 0x36FBFFFF,
.CP1_fcr0 = (1 << FCR0_F64) | (1 << FCR0_3D) | (1 << FCR0_PS) |
(1 << FCR0_L) | (1 << FCR0_W) | (1 << FCR0_D) |
(1 << FCR0_S) | (0x00 << FCR0_PRID) | (0x0 << FCR0_REV),
.CP1_fcr31 = 0,
.CP1_fcr31_rw_bitmask = 0xFF83FFFF,
.SEGBITS = 42,
.PABITS = 36,
.insn_flags = CPU_MIPS64R2 | ASE_MIPS3D,
.mmu_type = MMU_TYPE_R4000,
},
{
.name = "5KEc",
.CP0_PRid = 0x00018900,
.CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR) | (0x2 << CP0C0_AT) |
(MMU_TYPE_R4000 << CP0C0_MT),
.CP0_Config1 = MIPS_CONFIG1 | (31 << CP0C1_MMU) |
(1 << CP0C1_IS) | (4 << CP0C1_IL) | (1 << CP0C1_IA) |
(1 << CP0C1_DS) | (4 << CP0C1_DL) | (1 << CP0C1_DA) |
(1 << CP0C1_PC) | (1 << CP0C1_WR) | (1 << CP0C1_EP),
.CP0_Config2 = MIPS_CONFIG2,
.CP0_Config3 = MIPS_CONFIG3,
.CP0_LLAddr_rw_bitmask = 0,
.CP0_LLAddr_shift = 4,
.SYNCI_Step = 32,
.CCRes = 2,
.CP0_Status_rw_bitmask = 0x12F8FFFF,
.SEGBITS = 42,
.PABITS = 36,
.insn_flags = CPU_MIPS64R2,
.mmu_type = MMU_TYPE_R4000,
},
{
.name = "5KEf",
.CP0_PRid = 0x00018900,
.CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR) | (0x2 << CP0C0_AT) |
(MMU_TYPE_R4000 << CP0C0_MT),
.CP0_Config1 = MIPS_CONFIG1 | (1 << CP0C1_FP) | (31 << CP0C1_MMU) |
(1 << CP0C1_IS) | (4 << CP0C1_IL) | (1 << CP0C1_IA) |
(1 << CP0C1_DS) | (4 << CP0C1_DL) | (1 << CP0C1_DA) |
(1 << CP0C1_PC) | (1 << CP0C1_WR) | (1 << CP0C1_EP),
.CP0_Config2 = MIPS_CONFIG2,
.CP0_Config3 = MIPS_CONFIG3,
.CP0_LLAddr_rw_bitmask = 0,
.CP0_LLAddr_shift = 4,
.SYNCI_Step = 32,
.CCRes = 2,
.CP0_Status_rw_bitmask = 0x36F8FFFF,
.CP1_fcr0 = (1 << FCR0_F64) | (1 << FCR0_L) | (1 << FCR0_W) |
(1 << FCR0_D) | (1 << FCR0_S) |
(0x89 << FCR0_PRID) | (0x0 << FCR0_REV),
.SEGBITS = 42,
.PABITS = 36,
.insn_flags = CPU_MIPS64R2,
.mmu_type = MMU_TYPE_R4000,
},
{
.name = "I6400",
.CP0_PRid = 0x1A900,
.CP0_Config0 = MIPS_CONFIG0 | (0x2 << CP0C0_AR) | (0x2 << CP0C0_AT) |
(MMU_TYPE_R4000 << CP0C0_MT),
.CP0_Config1 = MIPS_CONFIG1 | (1 << CP0C1_FP) | (15 << CP0C1_MMU) |
(2 << CP0C1_IS) | (5 << CP0C1_IL) | (3 << CP0C1_IA) |
(2 << CP0C1_DS) | (5 << CP0C1_DL) | (3 << CP0C1_DA) |
(0 << CP0C1_PC) | (1 << CP0C1_WR) | (1 << CP0C1_EP),
.CP0_Config2 = MIPS_CONFIG2,
.CP0_Config3 = MIPS_CONFIG3 | (1U << CP0C3_M) |
(1 << CP0C3_CMGCR) | (1 << CP0C3_MSAP) |
(1 << CP0C3_BP) | (1 << CP0C3_BI) | (1 << CP0C3_ULRI) |
(1 << CP0C3_RXI) | (1 << CP0C3_LPA) | (1 << CP0C3_VInt),
.CP0_Config4 = MIPS_CONFIG4 | (1U << CP0C4_M) | (3 << CP0C4_IE) |
(1 << CP0C4_AE) | (0xfc << CP0C4_KScrExist),
.CP0_Config5 = MIPS_CONFIG5 | (1 << CP0C5_XNP) | (1 << CP0C5_VP) |
(1 << CP0C5_LLB) | (1 << CP0C5_MRP),
.CP0_Config5_rw_bitmask = (1 << CP0C5_MSAEn) | (1 << CP0C5_SBRI) |
(1 << CP0C5_FRE) | (1 << CP0C5_UFE),
.CP0_LLAddr_rw_bitmask = 0,
.CP0_LLAddr_shift = 0,
.SYNCI_Step = 32,
.CCRes = 2,
.CP0_Status_rw_bitmask = 0x30D8FFFF,
.CP0_PageGrain = (1 << CP0PG_IEC) | (1 << CP0PG_XIE) |
(1U << CP0PG_RIE),
.CP0_PageGrain_rw_bitmask = (1 << CP0PG_ELPA),
.CP1_fcr0 = (1 << FCR0_FREP) | (1 << FCR0_HAS2008) | (1 << FCR0_F64) |
(1 << FCR0_L) | (1 << FCR0_W) | (1 << FCR0_D) |
(1 << FCR0_S) | (0x03 << FCR0_PRID) | (0x0 << FCR0_REV),
.CP1_fcr31 = (1 << FCR31_ABS2008) | (1 << FCR31_NAN2008),
.CP1_fcr31_rw_bitmask = 0x0103FFFF,
.MSAIR = 0x03 << MSAIR_ProcID,
.SEGBITS = 48,
.PABITS = 48,
.insn_flags = CPU_MIPS64R6 | ASE_MSA,
.mmu_type = MMU_TYPE_R4000,
},
{
.name = "Loongson-2E",
.CP0_PRid = 0x6302,
/* 64KB I-cache and d-cache. 4 way with 32 bit cache line size. */
.CP0_Config0 = (0x1<<17) | (0x1<<16) | (0x1<<11) | (0x1<<8) |
(0x1<<5) | (0x1<<4) | (0x1<<1),
/* Note: Config1 is only used internally,
Loongson-2E has only Config0. */
.CP0_Config1 = (1 << CP0C1_FP) | (47 << CP0C1_MMU),
.SYNCI_Step = 16,
.CCRes = 2,
.CP0_Status_rw_bitmask = 0x35D0FFFF,
.CP1_fcr0 = (0x5 << FCR0_PRID) | (0x1 << FCR0_REV),
.CP1_fcr31 = 0,
.CP1_fcr31_rw_bitmask = 0xFF83FFFF,
.SEGBITS = 40,
.PABITS = 40,
.insn_flags = CPU_LOONGSON2E,
.mmu_type = MMU_TYPE_R4000,
},
{
.name = "Loongson-2F",
.CP0_PRid = 0x6303,
/* 64KB I-cache and d-cache. 4 way with 32 bit cache line size. */
.CP0_Config0 = (0x1<<17) | (0x1<<16) | (0x1<<11) | (0x1<<8) |
(0x1<<5) | (0x1<<4) | (0x1<<1),
/* Note: Config1 is only used internally,
Loongson-2F has only Config0. */
.CP0_Config1 = (1 << CP0C1_FP) | (47 << CP0C1_MMU),
.SYNCI_Step = 16,
.CCRes = 2,
.CP0_Status_rw_bitmask = 0xF5D0FF1F, /* Bits 7:5 not writable. */
.CP1_fcr0 = (0x5 << FCR0_PRID) | (0x1 << FCR0_REV),
.CP1_fcr31 = 0,
.CP1_fcr31_rw_bitmask = 0xFF83FFFF,
.SEGBITS = 40,
.PABITS = 40,
.insn_flags = CPU_LOONGSON2F,
.mmu_type = MMU_TYPE_R4000,
},
{
/* A generic CPU providing MIPS64 ASE DSP 2 features.
FIXME: Eventually this should be replaced by a real CPU model. */
.name = "mips64dspr2",
.CP0_PRid = 0x00010000,
.CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR) | (0x2 << CP0C0_AT) |
(MMU_TYPE_R4000 << CP0C0_MT),
.CP0_Config1 = MIPS_CONFIG1 | (1 << CP0C1_FP) | (63 << CP0C1_MMU) |
(2 << CP0C1_IS) | (4 << CP0C1_IL) | (3 << CP0C1_IA) |
(2 << CP0C1_DS) | (4 << CP0C1_DL) | (3 << CP0C1_DA) |
(1 << CP0C1_PC) | (1 << CP0C1_WR) | (1 << CP0C1_EP),
.CP0_Config2 = MIPS_CONFIG2,
.CP0_Config3 = MIPS_CONFIG3 | (1U << CP0C3_M) | (1 << CP0C3_DSP2P) |
(1 << CP0C3_DSPP) | (1 << CP0C3_LPA),
.CP0_LLAddr_rw_bitmask = 0,
.CP0_LLAddr_shift = 0,
.SYNCI_Step = 32,
.CCRes = 2,
.CP0_Status_rw_bitmask = 0x37FBFFFF,
.CP1_fcr0 = (1 << FCR0_F64) | (1 << FCR0_3D) | (1 << FCR0_PS) |
(1 << FCR0_L) | (1 << FCR0_W) | (1 << FCR0_D) |
(1 << FCR0_S) | (0x00 << FCR0_PRID) | (0x0 << FCR0_REV),
.CP1_fcr31 = 0,
.CP1_fcr31_rw_bitmask = 0xFF83FFFF,
.SEGBITS = 42,
.PABITS = 36,
.insn_flags = CPU_MIPS64R2 | ASE_DSP | ASE_DSPR2,
.mmu_type = MMU_TYPE_R4000,
},
#endif
};
static const mips_def_t *cpu_mips_find_by_name (const char *name)
{
int i;
for (i = 0; i < ARRAY_SIZE(mips_defs); i++) {
if (strcasecmp(name, mips_defs[i].name) == 0) {
return &mips_defs[i];
}
}
return NULL;
}
void mips_cpu_list (FILE *f, fprintf_function cpu_fprintf)
{
int i;
for (i = 0; i < ARRAY_SIZE(mips_defs); i++) {
(*cpu_fprintf)(f, "MIPS '%s'\n",
mips_defs[i].name);
}
}
#ifndef CONFIG_USER_ONLY
static void no_mmu_init (CPUMIPSState *env, const mips_def_t *def)
{
env->tlb->nb_tlb = 1;
env->tlb->map_address = &no_mmu_map_address;
}
static void fixed_mmu_init (CPUMIPSState *env, const mips_def_t *def)
{
env->tlb->nb_tlb = 1;
env->tlb->map_address = &fixed_mmu_map_address;
}
static void r4k_mmu_init (CPUMIPSState *env, const mips_def_t *def)
{
env->tlb->nb_tlb = 1 + ((def->CP0_Config1 >> CP0C1_MMU) & 63);
env->tlb->map_address = &r4k_map_address;
env->tlb->helper_tlbwi = r4k_helper_tlbwi;
env->tlb->helper_tlbwr = r4k_helper_tlbwr;
env->tlb->helper_tlbp = r4k_helper_tlbp;
env->tlb->helper_tlbr = r4k_helper_tlbr;
env->tlb->helper_tlbinv = r4k_helper_tlbinv;
env->tlb->helper_tlbinvf = r4k_helper_tlbinvf;
}
static void mmu_init (CPUMIPSState *env, const mips_def_t *def)
{
MIPSCPU *cpu = mips_env_get_cpu(env);
env->tlb = g_malloc0(sizeof(CPUMIPSTLBContext));
switch (def->mmu_type) {
case MMU_TYPE_NONE:
no_mmu_init(env, def);
break;
case MMU_TYPE_R4000:
r4k_mmu_init(env, def);
break;
case MMU_TYPE_FMT:
fixed_mmu_init(env, def);
break;
case MMU_TYPE_R3000:
case MMU_TYPE_R6000:
case MMU_TYPE_R8000:
default:
cpu_abort(CPU(cpu), "MMU type not supported\n");
}
}
#endif /* CONFIG_USER_ONLY */
static void fpu_init (CPUMIPSState *env, const mips_def_t *def)
{
int i;
for (i = 0; i < MIPS_FPU_MAX; i++)
env->fpus[i].fcr0 = def->CP1_fcr0;
memcpy(&env->active_fpu, &env->fpus[0], sizeof(env->active_fpu));
}
static void mvp_init (CPUMIPSState *env, const mips_def_t *def)
{
env->mvp = g_malloc0(sizeof(CPUMIPSMVPContext));
/* 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
implemented, 5 TCs implemented. */
env->mvp->CP0_MVPConf0 = (1U << CP0MVPC0_M) | (1 << CP0MVPC0_TLBS) |
(0 << CP0MVPC0_GS) | (1 << CP0MVPC0_PCP) |
// TODO: actually do 2 VPEs.
// (1 << CP0MVPC0_TCA) | (0x1 << CP0MVPC0_PVPE) |
// (0x04 << CP0MVPC0_PTC);
(1 << CP0MVPC0_TCA) | (0x0 << CP0MVPC0_PVPE) |
(0x00 << CP0MVPC0_PTC);
#if !defined(CONFIG_USER_ONLY)
/* Usermode has no TLB support */
env->mvp->CP0_MVPConf0 |= (env->tlb->nb_tlb << CP0MVPC0_PTLBE);
#endif
/* Allocatable CP1 have media extensions, allocatable CP1 have FP support,
no UDI implemented, no CP2 implemented, 1 CP1 implemented. */
env->mvp->CP0_MVPConf1 = (1U << CP0MVPC1_CIM) | (1 << CP0MVPC1_CIF) |
(0x0 << CP0MVPC1_PCX) | (0x0 << CP0MVPC1_PCP2) |
(0x1 << CP0MVPC1_PCP1);
}
static void msa_reset(CPUMIPSState *env)
{
#ifdef CONFIG_USER_ONLY
/* MSA access enabled */
env->CP0_Config5 |= 1 << CP0C5_MSAEn;
env->CP0_Status |= (1 << CP0St_CU1) | (1 << CP0St_FR);
#endif
/* MSA CSR:
- non-signaling floating point exception mode off (NX bit is 0)
- Cause, Enables, and Flags are all 0
- round to nearest / ties to even (RM bits are 0) */
env->active_tc.msacsr = 0;
restore_msa_fp_status(env);
/* tininess detected after rounding.*/
set_float_detect_tininess(float_tininess_after_rounding,
&env->active_tc.msa_fp_status);
/* clear float_status exception flags */
set_float_exception_flags(0, &env->active_tc.msa_fp_status);
/* clear float_status nan mode */
set_default_nan_mode(0, &env->active_tc.msa_fp_status);
/* set proper signanling bit meaning ("1" means "quiet") */
set_snan_bit_is_one(0, &env->active_tc.msa_fp_status);
}