import Unicorn2
This commit is contained in:
51
qemu/target/mips/TODO
Normal file
51
qemu/target/mips/TODO
Normal 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
|
||||
1692
qemu/target/mips/cp0_helper.c
Normal file
1692
qemu/target/mips/cp0_helper.c
Normal file
File diff suppressed because it is too large
Load Diff
172
qemu/target/mips/cp0_timer.c
Normal file
172
qemu/target/mips/cp0_timer.c
Normal file
@@ -0,0 +1,172 @@
|
||||
/*
|
||||
* QEMU MIPS timer support
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
//#include "hw/irq.h"
|
||||
//#include "hw/mips/cpudevs.h"
|
||||
#include "qemu/timer.h"
|
||||
//#include "sysemu/kvm.h"
|
||||
#include "internal.h"
|
||||
|
||||
#define TIMER_PERIOD 10 /* 10 ns period for 100 Mhz frequency */
|
||||
|
||||
/* XXX: do not use a global */
|
||||
uint32_t cpu_mips_get_random(CPUMIPSState *env)
|
||||
{
|
||||
static uint32_t seed = 1;
|
||||
static uint32_t prev_idx = 0;
|
||||
uint32_t idx;
|
||||
uint32_t nb_rand_tlb = env->tlb->nb_tlb - env->CP0_Wired;
|
||||
|
||||
if (nb_rand_tlb == 1) {
|
||||
return env->tlb->nb_tlb - 1;
|
||||
}
|
||||
|
||||
/* Don't return same value twice, so get another value */
|
||||
do {
|
||||
/*
|
||||
* Use a simple algorithm of Linear Congruential Generator
|
||||
* from ISO/IEC 9899 standard.
|
||||
*/
|
||||
seed = 1103515245 * seed + 12345;
|
||||
idx = (seed >> 16) % nb_rand_tlb + env->CP0_Wired;
|
||||
} while (idx == prev_idx);
|
||||
prev_idx = idx;
|
||||
return idx;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* MIPS R4K timer */
|
||||
static void cpu_mips_timer_update(CPUMIPSState *env)
|
||||
{
|
||||
uint64_t now, next;
|
||||
uint32_t wait;
|
||||
|
||||
now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
||||
wait = env->CP0_Compare - env->CP0_Count - (uint32_t)(now / TIMER_PERIOD);
|
||||
next = now + (uint64_t)wait * TIMER_PERIOD;
|
||||
timer_mod(env->timer, next);
|
||||
}
|
||||
|
||||
/* Expire the timer. */
|
||||
static void cpu_mips_timer_expire(CPUMIPSState *env)
|
||||
{
|
||||
cpu_mips_timer_update(env);
|
||||
if (env->insn_flags & ISA_MIPS32R2) {
|
||||
env->CP0_Cause |= 1 << CP0Ca_TI;
|
||||
}
|
||||
qemu_irq_raise(env->irq[(env->CP0_IntCtl >> CP0IntCtl_IPTI) & 0x7]);
|
||||
}
|
||||
|
||||
uint32_t cpu_mips_get_count(CPUMIPSState *env)
|
||||
{
|
||||
if (env->CP0_Cause & (1 << CP0Ca_DC)) {
|
||||
return env->CP0_Count;
|
||||
} else {
|
||||
uint64_t now;
|
||||
|
||||
now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
||||
if (timer_pending(env->timer)
|
||||
&& timer_expired(env->timer, now)) {
|
||||
/* The timer has already expired. */
|
||||
cpu_mips_timer_expire(env);
|
||||
}
|
||||
|
||||
return env->CP0_Count + (uint32_t)(now / TIMER_PERIOD);
|
||||
}
|
||||
}
|
||||
|
||||
void cpu_mips_store_count(CPUMIPSState *env, uint32_t count)
|
||||
{
|
||||
/*
|
||||
* This gets called from cpu_state_reset(), potentially before timer init.
|
||||
* So env->timer may be NULL, which is also the case with KVM enabled so
|
||||
* treat timer as disabled in that case.
|
||||
*/
|
||||
if (env->CP0_Cause & (1 << CP0Ca_DC) || !env->timer) {
|
||||
env->CP0_Count = count;
|
||||
} else {
|
||||
/* Store new count register */
|
||||
env->CP0_Count = count -
|
||||
(uint32_t)(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / TIMER_PERIOD);
|
||||
/* Update timer timer */
|
||||
cpu_mips_timer_update(env);
|
||||
}
|
||||
}
|
||||
|
||||
void cpu_mips_store_compare(CPUMIPSState *env, uint32_t value)
|
||||
{
|
||||
env->CP0_Compare = value;
|
||||
if (!(env->CP0_Cause & (1 << CP0Ca_DC))) {
|
||||
cpu_mips_timer_update(env);
|
||||
}
|
||||
if (env->insn_flags & ISA_MIPS32R2) {
|
||||
env->CP0_Cause &= ~(1 << CP0Ca_TI);
|
||||
}
|
||||
qemu_irq_lower(env->irq[(env->CP0_IntCtl >> CP0IntCtl_IPTI) & 0x7]);
|
||||
}
|
||||
|
||||
void cpu_mips_start_count(CPUMIPSState *env)
|
||||
{
|
||||
cpu_mips_store_count(env, env->CP0_Count);
|
||||
}
|
||||
|
||||
void cpu_mips_stop_count(CPUMIPSState *env)
|
||||
{
|
||||
/* Store the current value */
|
||||
env->CP0_Count += (uint32_t)(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) /
|
||||
TIMER_PERIOD);
|
||||
}
|
||||
|
||||
static void mips_timer_cb(void *opaque)
|
||||
{
|
||||
CPUMIPSState *env;
|
||||
|
||||
env = opaque;
|
||||
|
||||
if (env->CP0_Cause & (1 << CP0Ca_DC)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* ??? This callback should occur when the counter is exactly equal to
|
||||
* the comparator value. Offset the count by one to avoid immediately
|
||||
* retriggering the callback before any virtual time has passed.
|
||||
*/
|
||||
env->CP0_Count++;
|
||||
cpu_mips_timer_expire(env);
|
||||
env->CP0_Count--;
|
||||
}
|
||||
|
||||
void cpu_mips_clock_init(MIPSCPU *cpu)
|
||||
{
|
||||
CPUMIPSState *env = &cpu->env;
|
||||
|
||||
/*
|
||||
* If we're in KVM mode, don't create the periodic timer, that is handled in
|
||||
* kernel.
|
||||
*/
|
||||
if (!kvm_enabled()) {
|
||||
env->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &mips_timer_cb, env);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
25
qemu/target/mips/cpu-param.h
Normal file
25
qemu/target/mips/cpu-param.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* MIPS cpu parameters for qemu.
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.0+
|
||||
*/
|
||||
|
||||
#ifndef MIPS_CPU_PARAM_H
|
||||
#define MIPS_CPU_PARAM_H 1
|
||||
|
||||
#ifdef TARGET_MIPS64
|
||||
# define TARGET_LONG_BITS 64
|
||||
#else
|
||||
# define TARGET_LONG_BITS 32
|
||||
#endif
|
||||
#ifdef TARGET_MIPS64
|
||||
#define TARGET_PHYS_ADDR_SPACE_BITS 48
|
||||
#define TARGET_VIRT_ADDR_SPACE_BITS 48
|
||||
#else
|
||||
#define TARGET_PHYS_ADDR_SPACE_BITS 40
|
||||
#define TARGET_VIRT_ADDR_SPACE_BITS 32
|
||||
#endif
|
||||
#define TARGET_PAGE_BITS 12
|
||||
#define NB_MMU_MODES 4
|
||||
|
||||
#endif
|
||||
52
qemu/target/mips/cpu-qom.h
Normal file
52
qemu/target/mips/cpu-qom.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* 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 "hw/core/cpu.h"
|
||||
|
||||
#ifdef TARGET_MIPS64
|
||||
#define TYPE_MIPS_CPU "mips64-cpu"
|
||||
#else
|
||||
#define TYPE_MIPS_CPU "mips-cpu"
|
||||
#endif
|
||||
|
||||
#define MIPS_CPU(obj) ((MIPSCPU *)obj)
|
||||
#define MIPS_CPU_CLASS(klass) ((MIPSCPUClass *)klass)
|
||||
#define MIPS_CPU_GET_CLASS(obj) (&((MIPSCPU *)obj)->cc)
|
||||
|
||||
/**
|
||||
* 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 >*/
|
||||
|
||||
void (*parent_reset)(CPUState *cpu);
|
||||
} MIPSCPUClass;
|
||||
|
||||
typedef struct MIPSCPU MIPSCPU;
|
||||
|
||||
#endif
|
||||
208
qemu/target/mips/cpu.c
Normal file
208
qemu/target/mips/cpu.c
Normal file
@@ -0,0 +1,208 @@
|
||||
/*
|
||||
* 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 "cpu.h"
|
||||
#include "internal.h"
|
||||
#include "exec/exec-all.h"
|
||||
|
||||
#include <uc_priv.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, cs)) {
|
||||
has_work = false;
|
||||
}
|
||||
}
|
||||
|
||||
return has_work;
|
||||
}
|
||||
|
||||
static void mips_cpu_reset(CPUState *dev)
|
||||
{
|
||||
CPUState *s = CPU(dev);
|
||||
MIPSCPU *cpu = MIPS_CPU(s);
|
||||
MIPSCPUClass *mcc = MIPS_CPU_GET_CLASS(cpu);
|
||||
CPUMIPSState *env = &cpu->env;
|
||||
|
||||
mcc->parent_reset(dev);
|
||||
|
||||
memset(env, 0, offsetof(CPUMIPSState, end_reset_fields));
|
||||
|
||||
cpu_state_reset(env);
|
||||
}
|
||||
|
||||
static void mips_cpu_realizefn(CPUState *dev)
|
||||
{
|
||||
CPUState *cs = CPU(dev);
|
||||
MIPSCPU *cpu = MIPS_CPU(dev);
|
||||
|
||||
cpu_exec_realizefn(cs);
|
||||
|
||||
cpu_mips_realize_env(&cpu->env);
|
||||
|
||||
cpu_reset(cs);
|
||||
}
|
||||
|
||||
static void mips_cpu_initfn(struct uc_struct *uc, CPUState *obj)
|
||||
{
|
||||
MIPSCPU *cpu = MIPS_CPU(obj);
|
||||
CPUMIPSState *env = &cpu->env;
|
||||
|
||||
env->uc = uc;
|
||||
cpu_set_cpustate_pointers(cpu);
|
||||
}
|
||||
|
||||
static void mips_cpu_class_init(CPUClass *c)
|
||||
{
|
||||
MIPSCPUClass *mcc = MIPS_CPU_CLASS(c);
|
||||
CPUClass *cc = CPU_CLASS(c);
|
||||
|
||||
/* parent class is CPUClass, parent_reset() is cpu_common_reset(). */
|
||||
mcc->parent_reset = cc->reset;
|
||||
/* overwrite the CPUClass->reset to arch reset: x86_cpu_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->set_pc = mips_cpu_set_pc;
|
||||
cc->synchronize_from_tb = mips_cpu_synchronize_from_tb;
|
||||
cc->do_unaligned_access = mips_cpu_do_unaligned_access;
|
||||
cc->get_phys_page_debug = mips_cpu_get_phys_page_debug;
|
||||
cc->tcg_initialize = mips_tcg_init;
|
||||
cc->tlb_fill = mips_cpu_tlb_fill;
|
||||
}
|
||||
|
||||
MIPSCPU *cpu_mips_init(struct uc_struct *uc, const char *cpu_model)
|
||||
{
|
||||
MIPSCPU *cpu;
|
||||
CPUState *cs;
|
||||
CPUClass *cc;
|
||||
CPUMIPSState *env;
|
||||
int i;
|
||||
|
||||
if (cpu_model == NULL) {
|
||||
#ifdef TARGET_MIPS64
|
||||
cpu_model = "R4000";
|
||||
#else
|
||||
cpu_model = "24Kf";
|
||||
#endif
|
||||
}
|
||||
|
||||
cpu = calloc(1, sizeof(*cpu));
|
||||
if (cpu == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cs = (CPUState *)cpu;
|
||||
cc = (CPUClass *)&cpu->cc;
|
||||
cs->cc = cc;
|
||||
cs->uc = uc;
|
||||
uc->cpu = cs;
|
||||
|
||||
cpu_class_init(uc, cc);
|
||||
|
||||
mips_cpu_class_init(cc);
|
||||
|
||||
cpu_common_initfn(uc, cs);
|
||||
|
||||
mips_cpu_initfn(uc, cs);
|
||||
|
||||
env = &cpu->env;
|
||||
for (i = 0; i < mips_defs_number; i++) {
|
||||
if (strcasecmp(cpu_model, mips_defs[i].name) == 0) {
|
||||
env->cpu_model = &(mips_defs[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (env->cpu_model == NULL) {
|
||||
free(cpu);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mips_cpu_realizefn(cs);
|
||||
|
||||
// init address space
|
||||
cpu_address_space_init(cs, 0, cs->memory);
|
||||
|
||||
qemu_init_vcpu(cs);
|
||||
|
||||
return cpu;
|
||||
}
|
||||
1272
qemu/target/mips/cpu.h
Normal file
1272
qemu/target/mips/cpu.h
Normal file
File diff suppressed because it is too large
Load Diff
3771
qemu/target/mips/dsp_helper.c
Normal file
3771
qemu/target/mips/dsp_helper.c
Normal file
File diff suppressed because it is too large
Load Diff
1910
qemu/target/mips/fpu_helper.c
Normal file
1910
qemu/target/mips/fpu_helper.c
Normal file
File diff suppressed because it is too large
Load Diff
1498
qemu/target/mips/helper.c
Normal file
1498
qemu/target/mips/helper.c
Normal file
File diff suppressed because it is too large
Load Diff
1167
qemu/target/mips/helper.h
Normal file
1167
qemu/target/mips/helper.h
Normal file
File diff suppressed because it is too large
Load Diff
451
qemu/target/mips/internal.h
Normal file
451
qemu/target/mips/internal.h
Normal file
@@ -0,0 +1,451 @@
|
||||
/*
|
||||
* MIPS internal definitions and helpers
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#ifndef MIPS_INTERNAL_H
|
||||
#define MIPS_INTERNAL_H
|
||||
|
||||
#include "fpu/softfloat-helpers.h"
|
||||
#include "cpu.h"
|
||||
|
||||
struct uc_struct;
|
||||
|
||||
/*
|
||||
* MMU types, the first four entries have the same layout as the
|
||||
* CP0C0_MT field.
|
||||
*/
|
||||
enum mips_mmu_types {
|
||||
MMU_TYPE_NONE,
|
||||
MMU_TYPE_R4000,
|
||||
MMU_TYPE_RESERVED,
|
||||
MMU_TYPE_FMT,
|
||||
MMU_TYPE_R3000,
|
||||
MMU_TYPE_R6000,
|
||||
MMU_TYPE_R8000
|
||||
};
|
||||
|
||||
struct mips_def_t {
|
||||
const char *name;
|
||||
int32_t CP0_PRid;
|
||||
int32_t CP0_Config0;
|
||||
int32_t CP0_Config1;
|
||||
int32_t CP0_Config2;
|
||||
int32_t CP0_Config3;
|
||||
int32_t CP0_Config4;
|
||||
int32_t CP0_Config4_rw_bitmask;
|
||||
int32_t CP0_Config5;
|
||||
int32_t CP0_Config5_rw_bitmask;
|
||||
int32_t CP0_Config6;
|
||||
int32_t CP0_Config7;
|
||||
target_ulong CP0_LLAddr_rw_bitmask;
|
||||
int CP0_LLAddr_shift;
|
||||
int32_t SYNCI_Step;
|
||||
int32_t CCRes;
|
||||
int32_t CP0_Status_rw_bitmask;
|
||||
int32_t CP0_TCStatus_rw_bitmask;
|
||||
int32_t CP0_SRSCtl;
|
||||
int32_t CP1_fcr0;
|
||||
int32_t CP1_fcr31_rw_bitmask;
|
||||
int32_t CP1_fcr31;
|
||||
int32_t MSAIR;
|
||||
int32_t SEGBITS;
|
||||
int32_t PABITS;
|
||||
int32_t CP0_SRSConf0_rw_bitmask;
|
||||
int32_t CP0_SRSConf0;
|
||||
int32_t CP0_SRSConf1_rw_bitmask;
|
||||
int32_t CP0_SRSConf1;
|
||||
int32_t CP0_SRSConf2_rw_bitmask;
|
||||
int32_t CP0_SRSConf2;
|
||||
int32_t CP0_SRSConf3_rw_bitmask;
|
||||
int32_t CP0_SRSConf3;
|
||||
int32_t CP0_SRSConf4_rw_bitmask;
|
||||
int32_t CP0_SRSConf4;
|
||||
int32_t CP0_PageGrain_rw_bitmask;
|
||||
int32_t CP0_PageGrain;
|
||||
target_ulong CP0_EBaseWG_rw_bitmask;
|
||||
uint64_t insn_flags;
|
||||
enum mips_mmu_types mmu_type;
|
||||
int32_t SAARP;
|
||||
};
|
||||
|
||||
extern const struct mips_def_t mips_defs[];
|
||||
extern const int mips_defs_number;
|
||||
|
||||
enum CPUMIPSMSADataFormat {
|
||||
DF_BYTE = 0,
|
||||
DF_HALF,
|
||||
DF_WORD,
|
||||
DF_DOUBLE
|
||||
};
|
||||
|
||||
void mips_cpu_do_interrupt(CPUState *cpu);
|
||||
bool mips_cpu_exec_interrupt(CPUState *cpu, int int_req);
|
||||
hwaddr mips_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
|
||||
void mips_cpu_do_unaligned_access(CPUState *cpu, vaddr addr,
|
||||
MMUAccessType access_type,
|
||||
int mmu_idx, uintptr_t retaddr);
|
||||
|
||||
typedef struct r4k_tlb_t r4k_tlb_t;
|
||||
struct r4k_tlb_t {
|
||||
target_ulong VPN;
|
||||
uint32_t PageMask;
|
||||
uint16_t ASID;
|
||||
uint32_t MMID;
|
||||
unsigned int G:1;
|
||||
unsigned int C0:3;
|
||||
unsigned int C1:3;
|
||||
unsigned int V0:1;
|
||||
unsigned int V1:1;
|
||||
unsigned int D0:1;
|
||||
unsigned int D1:1;
|
||||
unsigned int XI0:1;
|
||||
unsigned int XI1:1;
|
||||
unsigned int RI0:1;
|
||||
unsigned int RI1:1;
|
||||
unsigned int EHINV:1;
|
||||
uint64_t PFN[2];
|
||||
};
|
||||
|
||||
struct CPUMIPSTLBContext {
|
||||
uint32_t nb_tlb;
|
||||
uint32_t tlb_in_use;
|
||||
int (*map_address)(struct CPUMIPSState *env, hwaddr *physical, int *prot,
|
||||
target_ulong address, int rw, int access_type);
|
||||
void (*helper_tlbwi)(struct CPUMIPSState *env);
|
||||
void (*helper_tlbwr)(struct CPUMIPSState *env);
|
||||
void (*helper_tlbp)(struct CPUMIPSState *env);
|
||||
void (*helper_tlbr)(struct CPUMIPSState *env);
|
||||
void (*helper_tlbinv)(struct CPUMIPSState *env);
|
||||
void (*helper_tlbinvf)(struct CPUMIPSState *env);
|
||||
union {
|
||||
struct {
|
||||
r4k_tlb_t tlb[MIPS_TLB_MAX];
|
||||
} r4k;
|
||||
} mmu;
|
||||
};
|
||||
|
||||
int no_mmu_map_address(CPUMIPSState *env, hwaddr *physical, int *prot,
|
||||
target_ulong address, int rw, int access_type);
|
||||
int fixed_mmu_map_address(CPUMIPSState *env, hwaddr *physical, int *prot,
|
||||
target_ulong address, int rw, int access_type);
|
||||
int r4k_map_address(CPUMIPSState *env, hwaddr *physical, int *prot,
|
||||
target_ulong address, int rw, int access_type);
|
||||
void r4k_helper_tlbwi(CPUMIPSState *env);
|
||||
void r4k_helper_tlbwr(CPUMIPSState *env);
|
||||
void r4k_helper_tlbp(CPUMIPSState *env);
|
||||
void r4k_helper_tlbr(CPUMIPSState *env);
|
||||
void r4k_helper_tlbinv(CPUMIPSState *env);
|
||||
void r4k_helper_tlbinvf(CPUMIPSState *env);
|
||||
void r4k_invalidate_tlb(CPUMIPSState *env, int idx, int use_extra);
|
||||
|
||||
void mips_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr,
|
||||
vaddr addr, unsigned size,
|
||||
MMUAccessType access_type,
|
||||
int mmu_idx, MemTxAttrs attrs,
|
||||
MemTxResult response, uintptr_t retaddr);
|
||||
hwaddr cpu_mips_translate_address(CPUMIPSState *env, target_ulong address,
|
||||
int rw);
|
||||
|
||||
#define cpu_signal_handler cpu_mips_signal_handler
|
||||
|
||||
static inline bool cpu_mips_hw_interrupts_enabled(CPUMIPSState *env)
|
||||
{
|
||||
return (env->CP0_Status & (1 << CP0St_IE)) &&
|
||||
!(env->CP0_Status & (1 << CP0St_EXL)) &&
|
||||
!(env->CP0_Status & (1 << CP0St_ERL)) &&
|
||||
!(env->hflags & MIPS_HFLAG_DM) &&
|
||||
/*
|
||||
* Note that the TCStatus IXMT field is initialized to zero,
|
||||
* and only MT capable cores can set it to one. So we don't
|
||||
* need to check for MT capabilities here.
|
||||
*/
|
||||
!(env->active_tc.CP0_TCStatus & (1 << CP0TCSt_IXMT));
|
||||
}
|
||||
|
||||
/* Check if there is pending and not masked out interrupt */
|
||||
static inline bool cpu_mips_hw_interrupts_pending(CPUMIPSState *env)
|
||||
{
|
||||
int32_t pending;
|
||||
int32_t status;
|
||||
bool r;
|
||||
|
||||
pending = env->CP0_Cause & CP0Ca_IP_mask;
|
||||
status = env->CP0_Status & CP0Ca_IP_mask;
|
||||
|
||||
if (env->CP0_Config3 & (1 << CP0C3_VEIC)) {
|
||||
/*
|
||||
* A MIPS configured with a vectorizing external interrupt controller
|
||||
* will feed a vector into the Cause pending lines. The core treats
|
||||
* the status lines as a vector level, not as indiviual masks.
|
||||
*/
|
||||
r = pending > status;
|
||||
} else {
|
||||
/*
|
||||
* A MIPS configured with compatibility or VInt (Vectored Interrupts)
|
||||
* treats the pending lines as individual interrupt lines, the status
|
||||
* lines are individual masks.
|
||||
*/
|
||||
r = (pending & status) != 0;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
void mips_tcg_init(struct uc_struct *uc);
|
||||
|
||||
/* TODO QOM'ify CPU reset and remove */
|
||||
void cpu_state_reset(CPUMIPSState *s);
|
||||
void cpu_mips_realize_env(CPUMIPSState *env);
|
||||
|
||||
/* cp0_timer.c */
|
||||
uint32_t cpu_mips_get_random(CPUMIPSState *env);
|
||||
uint32_t cpu_mips_get_count(CPUMIPSState *env);
|
||||
void cpu_mips_store_count(CPUMIPSState *env, uint32_t value);
|
||||
void cpu_mips_store_compare(CPUMIPSState *env, uint32_t value);
|
||||
void cpu_mips_start_count(CPUMIPSState *env);
|
||||
void cpu_mips_stop_count(CPUMIPSState *env);
|
||||
|
||||
/* helper.c */
|
||||
bool mips_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
||||
MMUAccessType access_type, int mmu_idx,
|
||||
bool probe, uintptr_t retaddr);
|
||||
|
||||
/* op_helper.c */
|
||||
uint32_t float_class_s(uint32_t arg, float_status *fst);
|
||||
uint64_t float_class_d(uint64_t arg, float_status *fst);
|
||||
|
||||
extern unsigned int ieee_rm[];
|
||||
int ieee_ex_to_mips(int xcpt);
|
||||
void update_pagemask(CPUMIPSState *env, target_ulong arg1, int32_t *pagemask);
|
||||
|
||||
static inline void restore_rounding_mode(CPUMIPSState *env)
|
||||
{
|
||||
set_float_rounding_mode(ieee_rm[env->active_fpu.fcr31 & 3],
|
||||
&env->active_fpu.fp_status);
|
||||
}
|
||||
|
||||
static inline void restore_flush_mode(CPUMIPSState *env)
|
||||
{
|
||||
set_flush_to_zero((env->active_fpu.fcr31 & (1 << FCR31_FS)) != 0,
|
||||
&env->active_fpu.fp_status);
|
||||
}
|
||||
|
||||
static inline void restore_snan_bit_mode(CPUMIPSState *env)
|
||||
{
|
||||
set_snan_bit_is_one((env->active_fpu.fcr31 & (1 << FCR31_NAN2008)) == 0,
|
||||
&env->active_fpu.fp_status);
|
||||
}
|
||||
|
||||
static inline void restore_fp_status(CPUMIPSState *env)
|
||||
{
|
||||
restore_rounding_mode(env);
|
||||
restore_flush_mode(env);
|
||||
restore_snan_bit_mode(env);
|
||||
}
|
||||
|
||||
static inline void restore_msa_fp_status(CPUMIPSState *env)
|
||||
{
|
||||
float_status *status = &env->active_tc.msa_fp_status;
|
||||
int rounding_mode = (env->active_tc.msacsr & MSACSR_RM_MASK) >> MSACSR_RM;
|
||||
bool flush_to_zero = (env->active_tc.msacsr & MSACSR_FS_MASK) != 0;
|
||||
|
||||
set_float_rounding_mode(ieee_rm[rounding_mode], status);
|
||||
set_flush_to_zero(flush_to_zero, status);
|
||||
set_flush_inputs_to_zero(flush_to_zero, status);
|
||||
}
|
||||
|
||||
static inline void restore_pamask(CPUMIPSState *env)
|
||||
{
|
||||
if (env->hflags & MIPS_HFLAG_ELPA) {
|
||||
env->PAMask = (1ULL << env->PABITS) - 1;
|
||||
} else {
|
||||
env->PAMask = PAMASK_BASE;
|
||||
}
|
||||
}
|
||||
|
||||
static inline int mips_vpe_active(CPUMIPSState *env)
|
||||
{
|
||||
int active = 1;
|
||||
|
||||
/* Check that the VPE is enabled. */
|
||||
if (!(env->mvp->CP0_MVPControl & (1 << CP0MVPCo_EVP))) {
|
||||
active = 0;
|
||||
}
|
||||
/* Check that the VPE is activated. */
|
||||
if (!(env->CP0_VPEConf0 & (1 << CP0VPEC0_VPA))) {
|
||||
active = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now verify that there are active thread contexts in the VPE.
|
||||
*
|
||||
* This assumes the CPU model will internally reschedule threads
|
||||
* if the active one goes to sleep. If there are no threads available
|
||||
* the active one will be in a sleeping state, and we can turn off
|
||||
* the entire VPE.
|
||||
*/
|
||||
if (!(env->active_tc.CP0_TCStatus & (1 << CP0TCSt_A))) {
|
||||
/* TC is not activated. */
|
||||
active = 0;
|
||||
}
|
||||
if (env->active_tc.CP0_TCHalt & 1) {
|
||||
/* TC is in halt state. */
|
||||
active = 0;
|
||||
}
|
||||
|
||||
return active;
|
||||
}
|
||||
|
||||
static inline int mips_vp_active(CPUMIPSState *env, CPUState *cpu)
|
||||
{
|
||||
/* Check if the VP disabled other VPs (which means the VP is enabled) */
|
||||
if ((env->CP0_VPControl >> CP0VPCtl_DIS) & 1) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Check if the virtual processor is disabled due to a DVP */
|
||||
MIPSCPU *cs = MIPS_CPU(cpu);
|
||||
if ((&cs->env != env) &&
|
||||
((cs->env.CP0_VPControl >> CP0VPCtl_DIS) & 1)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline void compute_hflags(CPUMIPSState *env)
|
||||
{
|
||||
env->hflags &= ~(MIPS_HFLAG_COP1X | MIPS_HFLAG_64 | MIPS_HFLAG_CP0 |
|
||||
MIPS_HFLAG_F64 | MIPS_HFLAG_FPU | MIPS_HFLAG_KSU |
|
||||
MIPS_HFLAG_AWRAP | MIPS_HFLAG_DSP | MIPS_HFLAG_DSP_R2 |
|
||||
MIPS_HFLAG_DSP_R3 | MIPS_HFLAG_SBRI | MIPS_HFLAG_MSA |
|
||||
MIPS_HFLAG_FRE | MIPS_HFLAG_ELPA | MIPS_HFLAG_ERL);
|
||||
if (env->CP0_Status & (1 << CP0St_ERL)) {
|
||||
env->hflags |= MIPS_HFLAG_ERL;
|
||||
}
|
||||
if (!(env->CP0_Status & (1 << CP0St_EXL)) &&
|
||||
!(env->CP0_Status & (1 << CP0St_ERL)) &&
|
||||
!(env->hflags & MIPS_HFLAG_DM)) {
|
||||
env->hflags |= (env->CP0_Status >> CP0St_KSU) &
|
||||
MIPS_HFLAG_KSU;
|
||||
}
|
||||
#if defined(TARGET_MIPS64)
|
||||
if ((env->insn_flags & ISA_MIPS3) &&
|
||||
(((env->hflags & MIPS_HFLAG_KSU) != MIPS_HFLAG_UM) ||
|
||||
(env->CP0_Status & (1 << CP0St_PX)) ||
|
||||
(env->CP0_Status & (1 << CP0St_UX)))) {
|
||||
env->hflags |= MIPS_HFLAG_64;
|
||||
}
|
||||
|
||||
if (!(env->insn_flags & ISA_MIPS3)) {
|
||||
env->hflags |= MIPS_HFLAG_AWRAP;
|
||||
} else if (((env->hflags & MIPS_HFLAG_KSU) == MIPS_HFLAG_UM) &&
|
||||
!(env->CP0_Status & (1 << CP0St_UX))) {
|
||||
env->hflags |= MIPS_HFLAG_AWRAP;
|
||||
} else if (env->insn_flags & ISA_MIPS64R6) {
|
||||
/* Address wrapping for Supervisor and Kernel is specified in R6 */
|
||||
if ((((env->hflags & MIPS_HFLAG_KSU) == MIPS_HFLAG_SM) &&
|
||||
!(env->CP0_Status & (1 << CP0St_SX))) ||
|
||||
(((env->hflags & MIPS_HFLAG_KSU) == MIPS_HFLAG_KM) &&
|
||||
!(env->CP0_Status & (1 << CP0St_KX)))) {
|
||||
env->hflags |= MIPS_HFLAG_AWRAP;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (((env->CP0_Status & (1 << CP0St_CU0)) &&
|
||||
!(env->insn_flags & ISA_MIPS32R6)) ||
|
||||
!(env->hflags & MIPS_HFLAG_KSU)) {
|
||||
env->hflags |= MIPS_HFLAG_CP0;
|
||||
}
|
||||
if (env->CP0_Status & (1 << CP0St_CU1)) {
|
||||
env->hflags |= MIPS_HFLAG_FPU;
|
||||
}
|
||||
if (env->CP0_Status & (1 << CP0St_FR)) {
|
||||
env->hflags |= MIPS_HFLAG_F64;
|
||||
}
|
||||
if (((env->hflags & MIPS_HFLAG_KSU) != MIPS_HFLAG_KM) &&
|
||||
(env->CP0_Config5 & (1 << CP0C5_SBRI))) {
|
||||
env->hflags |= MIPS_HFLAG_SBRI;
|
||||
}
|
||||
if (env->insn_flags & ASE_DSP_R3) {
|
||||
/*
|
||||
* Our cpu supports DSP R3 ASE, so enable
|
||||
* access to DSP R3 resources.
|
||||
*/
|
||||
if (env->CP0_Status & (1 << CP0St_MX)) {
|
||||
env->hflags |= MIPS_HFLAG_DSP | MIPS_HFLAG_DSP_R2 |
|
||||
MIPS_HFLAG_DSP_R3;
|
||||
}
|
||||
} else if (env->insn_flags & ASE_DSP_R2) {
|
||||
/*
|
||||
* Our cpu supports DSP R2 ASE, so enable
|
||||
* access to DSP R2 resources.
|
||||
*/
|
||||
if (env->CP0_Status & (1 << CP0St_MX)) {
|
||||
env->hflags |= MIPS_HFLAG_DSP | MIPS_HFLAG_DSP_R2;
|
||||
}
|
||||
|
||||
} else if (env->insn_flags & ASE_DSP) {
|
||||
/*
|
||||
* Our cpu supports DSP ASE, so enable
|
||||
* access to DSP resources.
|
||||
*/
|
||||
if (env->CP0_Status & (1 << CP0St_MX)) {
|
||||
env->hflags |= MIPS_HFLAG_DSP;
|
||||
}
|
||||
|
||||
}
|
||||
if (env->insn_flags & ISA_MIPS32R2) {
|
||||
if (env->active_fpu.fcr0 & (1 << FCR0_F64)) {
|
||||
env->hflags |= MIPS_HFLAG_COP1X;
|
||||
}
|
||||
} else if (env->insn_flags & ISA_MIPS32) {
|
||||
if (env->hflags & MIPS_HFLAG_64) {
|
||||
env->hflags |= MIPS_HFLAG_COP1X;
|
||||
}
|
||||
} else if (env->insn_flags & ISA_MIPS4) {
|
||||
/*
|
||||
* All supported MIPS IV CPUs use the XX (CU3) to enable
|
||||
* and disable the MIPS IV extensions to the MIPS III ISA.
|
||||
* Some other MIPS IV CPUs ignore the bit, so the check here
|
||||
* would be too restrictive for them.
|
||||
*/
|
||||
if (env->CP0_Status & (1U << CP0St_CU3)) {
|
||||
env->hflags |= MIPS_HFLAG_COP1X;
|
||||
}
|
||||
}
|
||||
if (env->insn_flags & ASE_MSA) {
|
||||
if (env->CP0_Config5 & (1 << CP0C5_MSAEn)) {
|
||||
env->hflags |= MIPS_HFLAG_MSA;
|
||||
}
|
||||
}
|
||||
if (env->active_fpu.fcr0 & (1 << FCR0_FREP)) {
|
||||
if (env->CP0_Config5 & (1 << CP0C5_FRE)) {
|
||||
env->hflags |= MIPS_HFLAG_FRE;
|
||||
}
|
||||
}
|
||||
if (env->CP0_Config3 & (1 << CP0C3_LPA)) {
|
||||
if (env->CP0_PageGrain & (1 << CP0PG_ELPA)) {
|
||||
env->hflags |= MIPS_HFLAG_ELPA;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cpu_mips_tlb_flush(CPUMIPSState *env);
|
||||
void sync_c0_status(CPUMIPSState *env, CPUMIPSState *cpu, int tc);
|
||||
void cpu_mips_store_status(CPUMIPSState *env, target_ulong val);
|
||||
void cpu_mips_store_cause(CPUMIPSState *env, target_ulong val);
|
||||
|
||||
void QEMU_NORETURN do_raise_exception_err(CPUMIPSState *env, uint32_t exception,
|
||||
int error_code, uintptr_t pc);
|
||||
|
||||
static inline void QEMU_NORETURN do_raise_exception(CPUMIPSState *env,
|
||||
uint32_t exception,
|
||||
uintptr_t pc)
|
||||
{
|
||||
do_raise_exception_err(env, exception, 0, pc);
|
||||
}
|
||||
|
||||
#endif
|
||||
747
qemu/target/mips/lmi_helper.c
Normal file
747
qemu/target/mips/lmi_helper.c
Normal file
@@ -0,0 +1,747 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
105
qemu/target/mips/mips-defs.h
Normal file
105
qemu/target/mips/mips-defs.h
Normal file
@@ -0,0 +1,105 @@
|
||||
#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 MIPS_TLB_MAX 128
|
||||
|
||||
/*
|
||||
* bit definitions for insn_flags (ISAs/ASEs flags)
|
||||
* ------------------------------------------------
|
||||
*/
|
||||
/*
|
||||
* bits 0-31: MIPS base instruction sets
|
||||
*/
|
||||
#define ISA_MIPS1 0x0000000000000001ULL
|
||||
#define ISA_MIPS2 0x0000000000000002ULL
|
||||
#define ISA_MIPS3 0x0000000000000004ULL
|
||||
#define ISA_MIPS4 0x0000000000000008ULL
|
||||
#define ISA_MIPS5 0x0000000000000010ULL
|
||||
#define ISA_MIPS32 0x0000000000000020ULL
|
||||
#define ISA_MIPS32R2 0x0000000000000040ULL
|
||||
#define ISA_MIPS64 0x0000000000000080ULL
|
||||
#define ISA_MIPS64R2 0x0000000000000100ULL
|
||||
#define ISA_MIPS32R3 0x0000000000000200ULL
|
||||
#define ISA_MIPS64R3 0x0000000000000400ULL
|
||||
#define ISA_MIPS32R5 0x0000000000000800ULL
|
||||
#define ISA_MIPS64R5 0x0000000000001000ULL
|
||||
#define ISA_MIPS32R6 0x0000000000002000ULL
|
||||
#define ISA_MIPS64R6 0x0000000000004000ULL
|
||||
#define ISA_NANOMIPS32 0x0000000000008000ULL
|
||||
/*
|
||||
* bits 32-47: MIPS ASEs
|
||||
*/
|
||||
#define ASE_MIPS16 0x0000000100000000ULL
|
||||
#define ASE_MIPS3D 0x0000000200000000ULL
|
||||
#define ASE_MDMX 0x0000000400000000ULL
|
||||
#define ASE_DSP 0x0000000800000000ULL
|
||||
#define ASE_DSP_R2 0x0000001000000000ULL
|
||||
#define ASE_DSP_R3 0x0000002000000000ULL
|
||||
#define ASE_MT 0x0000004000000000ULL
|
||||
#define ASE_SMARTMIPS 0x0000008000000000ULL
|
||||
#define ASE_MICROMIPS 0x0000010000000000ULL
|
||||
#define ASE_MSA 0x0000020000000000ULL
|
||||
/*
|
||||
* bits 48-55: vendor-specific base instruction sets
|
||||
*/
|
||||
#define INSN_LOONGSON2E 0x0001000000000000ULL
|
||||
#define INSN_LOONGSON2F 0x0002000000000000ULL
|
||||
#define INSN_VR54XX 0x0004000000000000ULL
|
||||
#define INSN_R5900 0x0008000000000000ULL
|
||||
/*
|
||||
* bits 56-63: vendor-specific ASEs
|
||||
*/
|
||||
#define ASE_MMI 0x0100000000000000ULL
|
||||
#define ASE_MXU 0x0200000000000000ULL
|
||||
|
||||
/* 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_R5900 (CPU_MIPS3 | INSN_R5900)
|
||||
#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)
|
||||
|
||||
/* Wave Computing: "nanoMIPS" */
|
||||
#define CPU_NANOMIPS32 (CPU_MIPS32R6 | ISA_NANOMIPS32)
|
||||
|
||||
/*
|
||||
* 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 */
|
||||
7419
qemu/target/mips/msa_helper.c
Normal file
7419
qemu/target/mips/msa_helper.c
Normal file
File diff suppressed because it is too large
Load Diff
1364
qemu/target/mips/op_helper.c
Normal file
1364
qemu/target/mips/op_helper.c
Normal file
File diff suppressed because it is too large
Load Diff
31409
qemu/target/mips/translate.c
Normal file
31409
qemu/target/mips/translate.c
Normal file
File diff suppressed because it is too large
Load Diff
941
qemu/target/mips/translate_init.inc.c
Normal file
941
qemu/target/mips/translate_init.inc.c
Normal file
@@ -0,0 +1,941 @@
|
||||
/*
|
||||
* 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))
|
||||
|
||||
/*****************************************************************************/
|
||||
/* MIPS CPU definitions */
|
||||
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_DSP_R2,
|
||||
.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, PW, VZ, CTXTC, CDMM, TL
|
||||
* Config4: MMUExtDef
|
||||
* Config5: 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_SC) |
|
||||
(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_EVA) | (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),
|
||||
.CP0_EBaseWG_rw_bitmask = (1 << CP0EBase_WG),
|
||||
.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,
|
||||
},
|
||||
{
|
||||
.name = "I7200",
|
||||
.CP0_PRid = 0x00010000,
|
||||
.CP0_Config0 = MIPS_CONFIG0 | (1 << CP0C0_MM) | (0x2 << CP0C0_AR) |
|
||||
(MMU_TYPE_R4000 << CP0C0_MT),
|
||||
.CP0_Config1 = (1U << CP0C1_M) | (15 << 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_EP),
|
||||
.CP0_Config2 = MIPS_CONFIG2,
|
||||
.CP0_Config3 = MIPS_CONFIG3 | (1U << CP0C3_M) | (1 << CP0C3_CMGCR) |
|
||||
(1 << CP0C3_BI) | (1 << CP0C3_SC) | (3 << CP0C3_MMAR) |
|
||||
(1 << CP0C3_ISA_ON_EXC) | (1 << CP0C3_ISA) |
|
||||
(1 << CP0C3_ULRI) | (1 << CP0C3_RXI) |
|
||||
(1 << CP0C3_DSP2P) | (1 << CP0C3_DSPP) |
|
||||
(1 << CP0C3_CTXTC) | (1 << CP0C3_VInt) |
|
||||
(1 << CP0C3_CDMM) | (1 << CP0C3_MT) | (1 << CP0C3_TL),
|
||||
.CP0_Config4 = MIPS_CONFIG4 | (0xfc << CP0C4_KScrExist) |
|
||||
(2 << CP0C4_IE) | (1U << CP0C4_M),
|
||||
.CP0_Config5 = MIPS_CONFIG5 | (1 << CP0C5_MVH) | (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 = 0x3158FF1F,
|
||||
.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) | (0x02 << FCR0_PRID) | (0x0 << FCR0_REV),
|
||||
.CP1_fcr31 = (1 << FCR31_ABS2008) | (1 << FCR31_NAN2008),
|
||||
.SEGBITS = 32,
|
||||
.PABITS = 32,
|
||||
.insn_flags = CPU_NANOMIPS32 | ASE_DSP | ASE_DSP_R2 | ASE_DSP_R3 |
|
||||
ASE_MT,
|
||||
.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,
|
||||
.CP0_EBaseWG_rw_bitmask = (1 << CP0EBase_WG),
|
||||
.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),
|
||||
.CP0_EBaseWG_rw_bitmask = (1 << CP0EBase_WG),
|
||||
.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 = "I6500",
|
||||
.CP0_PRid = 0x1B000,
|
||||
.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 = 64,
|
||||
.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),
|
||||
.CP0_EBaseWG_rw_bitmask = (1 << CP0EBase_WG),
|
||||
.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 DSP R2 ASE 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_DSP_R2,
|
||||
.mmu_type = MMU_TYPE_R4000,
|
||||
},
|
||||
|
||||
#endif
|
||||
};
|
||||
const int mips_defs_number = ARRAY_SIZE(mips_defs);
|
||||
|
||||
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)
|
||||
{
|
||||
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(env_cpu(env), "MMU type not supported\n");
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
/* Usermode has no TLB support */
|
||||
env->mvp->CP0_MVPConf0 |= (env->tlb->nb_tlb << CP0MVPC0_PTLBE);
|
||||
|
||||
/* 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)
|
||||
{
|
||||
/* 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);
|
||||
}
|
||||
239
qemu/target/mips/unicorn.c
Normal file
239
qemu/target/mips/unicorn.c
Normal file
@@ -0,0 +1,239 @@
|
||||
/* Unicorn Emulator Engine */
|
||||
/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2015 */
|
||||
/* Modified for Unicorn Engine by Chen Huitao<chenhuitao@hfmrit.com>, 2020 */
|
||||
|
||||
#include "sysemu/cpus.h"
|
||||
#include "cpu.h"
|
||||
#include "unicorn_common.h"
|
||||
#include "uc_priv.h"
|
||||
#include "unicorn.h"
|
||||
|
||||
#ifdef TARGET_MIPS64
|
||||
typedef uint64_t mipsreg_t;
|
||||
#else
|
||||
typedef uint32_t mipsreg_t;
|
||||
#endif
|
||||
|
||||
MIPSCPU *cpu_mips_init(struct uc_struct *uc, const char *cpu_model);
|
||||
|
||||
static uint64_t mips_mem_redirect(uint64_t address)
|
||||
{
|
||||
// kseg0 range masks off high address bit
|
||||
if (address >= 0x80000000 && address <= 0x9fffffff)
|
||||
return address & 0x7fffffff;
|
||||
|
||||
// kseg1 range masks off top 3 address bits
|
||||
if (address >= 0xa0000000 && address <= 0xbfffffff) {
|
||||
return address & 0x1fffffff;
|
||||
}
|
||||
|
||||
// no redirect
|
||||
return address;
|
||||
}
|
||||
|
||||
static void mips_set_pc(struct uc_struct *uc, uint64_t address)
|
||||
{
|
||||
((CPUMIPSState *)uc->cpu->env_ptr)->active_tc.PC = address;
|
||||
}
|
||||
|
||||
|
||||
static void mips_release(void *ctx)
|
||||
{
|
||||
int i;
|
||||
TCGContext *tcg_ctx = (TCGContext *)ctx;
|
||||
MIPSCPU *cpu = (MIPSCPU *)tcg_ctx->uc->cpu;
|
||||
CPUTLBDesc *d = cpu->neg.tlb.d;
|
||||
CPUTLBDescFast *f = cpu->neg.tlb.f;
|
||||
CPUTLBDesc *desc;
|
||||
CPUTLBDescFast *fast;
|
||||
|
||||
release_common(ctx);
|
||||
for (i = 0; i < NB_MMU_MODES; i++) {
|
||||
desc = &(d[i]);
|
||||
fast = &(f[i]);
|
||||
g_free(desc->iotlb);
|
||||
g_free(fast->table);
|
||||
}
|
||||
|
||||
g_free(cpu->env.mvp);
|
||||
g_free(cpu->env.tlb);
|
||||
}
|
||||
|
||||
void mips_reg_reset(struct uc_struct *uc)
|
||||
{
|
||||
CPUArchState *env;
|
||||
(void)uc;
|
||||
env = uc->cpu->env_ptr;
|
||||
memset(env->active_tc.gpr, 0, sizeof(env->active_tc.gpr));
|
||||
|
||||
env->active_tc.PC = 0;
|
||||
}
|
||||
|
||||
static void reg_read(CPUMIPSState *env, unsigned int regid, void *value)
|
||||
{
|
||||
if (regid >= UC_MIPS_REG_0 && regid <= UC_MIPS_REG_31)
|
||||
*(mipsreg_t *)value = env->active_tc.gpr[regid - UC_MIPS_REG_0];
|
||||
else {
|
||||
switch(regid) {
|
||||
default: break;
|
||||
case UC_MIPS_REG_PC:
|
||||
*(mipsreg_t *)value = env->active_tc.PC;
|
||||
break;
|
||||
case UC_MIPS_REG_CP0_CONFIG3:
|
||||
*(mipsreg_t *)value = env->CP0_Config3;
|
||||
break;
|
||||
case UC_MIPS_REG_CP0_USERLOCAL:
|
||||
*(mipsreg_t *)value = env->active_tc.CP0_UserLocal;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void reg_write(CPUMIPSState *env, unsigned int regid, const void *value)
|
||||
{
|
||||
if (regid >= UC_MIPS_REG_0 && regid <= UC_MIPS_REG_31)
|
||||
env->active_tc.gpr[regid - UC_MIPS_REG_0] = *(mipsreg_t *)value;
|
||||
else {
|
||||
switch(regid) {
|
||||
default: break;
|
||||
case UC_MIPS_REG_PC:
|
||||
env->active_tc.PC = *(mipsreg_t *)value;
|
||||
break;
|
||||
case UC_MIPS_REG_CP0_CONFIG3:
|
||||
env->CP0_Config3 = *(mipsreg_t *)value;
|
||||
break;
|
||||
case UC_MIPS_REG_CP0_USERLOCAL:
|
||||
env->active_tc.CP0_UserLocal = *(mipsreg_t *)value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int mips_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count)
|
||||
{
|
||||
CPUMIPSState *env = &(MIPS_CPU(uc->cpu)->env);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
unsigned int regid = regs[i];
|
||||
void *value = vals[i];
|
||||
reg_read(env, regid, value);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mips_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, int count)
|
||||
{
|
||||
CPUMIPSState *env = &(MIPS_CPU(uc->cpu)->env);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
unsigned int regid = regs[i];
|
||||
const void *value = vals[i];
|
||||
reg_write(env, regid, value);
|
||||
if(regid == UC_MIPS_REG_PC){
|
||||
// force to quit execution and flush TB
|
||||
uc->quit_request = true;
|
||||
uc_emu_stop(uc);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFAULT_VISIBILITY
|
||||
#ifdef TARGET_MIPS64
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
int mips64_context_reg_read(struct uc_context *ctx, unsigned int *regs, void **vals, int count)
|
||||
#else
|
||||
int mips64el_context_reg_read(struct uc_context *ctx, unsigned int *regs, void **vals, int count)
|
||||
#endif
|
||||
#else // if TARGET_MIPS
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
int mips_context_reg_read(struct uc_context *ctx, unsigned int *regs, void **vals, int count)
|
||||
#else
|
||||
int mipsel_context_reg_read(struct uc_context *ctx, unsigned int *regs, void **vals, int count)
|
||||
#endif
|
||||
#endif
|
||||
{
|
||||
CPUMIPSState *env = (CPUMIPSState *)ctx->data;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
unsigned int regid = regs[i];
|
||||
void *value = vals[i];
|
||||
reg_read(env, regid, value);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFAULT_VISIBILITY
|
||||
#ifdef TARGET_MIPS64
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
int mips64_context_reg_write(struct uc_context *ctx, unsigned int *regs, void *const *vals, int count)
|
||||
#else
|
||||
int mips64el_context_reg_write(struct uc_context *ctx, unsigned int *regs, void *const *vals, int count)
|
||||
#endif
|
||||
#else // if TARGET_MIPS
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
int mips_context_reg_write(struct uc_context *ctx, unsigned int *regs, void *const *vals, int count)
|
||||
#else
|
||||
int mipsel_context_reg_write(struct uc_context *ctx, unsigned int *regs, void *const *vals, int count)
|
||||
#endif
|
||||
#endif
|
||||
{
|
||||
CPUMIPSState *env = (CPUMIPSState *)ctx->data;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
unsigned int regid = regs[i];
|
||||
const void *value = vals[i];
|
||||
reg_write(env, regid, value);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mips_cpus_init(struct uc_struct *uc, const char *cpu_model)
|
||||
{
|
||||
MIPSCPU *cpu;
|
||||
|
||||
cpu = cpu_mips_init(uc, NULL);
|
||||
if (cpu == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFAULT_VISIBILITY
|
||||
#ifdef TARGET_MIPS64
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
void mips64_uc_init(struct uc_struct* uc)
|
||||
#else
|
||||
void mips64el_uc_init(struct uc_struct* uc)
|
||||
#endif
|
||||
#else // if TARGET_MIPS
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
void mips_uc_init(struct uc_struct* uc)
|
||||
#else
|
||||
void mipsel_uc_init(struct uc_struct* uc)
|
||||
#endif
|
||||
#endif
|
||||
{
|
||||
uc->reg_read = mips_reg_read;
|
||||
uc->reg_write = mips_reg_write;
|
||||
uc->reg_reset = mips_reg_reset;
|
||||
uc->release = mips_release;
|
||||
uc->set_pc = mips_set_pc;
|
||||
uc->mem_redirect = mips_mem_redirect;
|
||||
uc->cpus_init = mips_cpus_init;
|
||||
uc->cpu_context_size = offsetof(CPUMIPSState, end_reset_fields);
|
||||
uc_common_init(uc);
|
||||
}
|
||||
26
qemu/target/mips/unicorn.h
Normal file
26
qemu/target/mips/unicorn.h
Normal file
@@ -0,0 +1,26 @@
|
||||
/* Unicorn Emulator Engine */
|
||||
/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2015 */
|
||||
|
||||
#ifndef UC_QEMU_TARGET_MIPS_H
|
||||
#define UC_QEMU_TARGET_MIPS_H
|
||||
|
||||
// functions to read & write registers
|
||||
int mips_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count);
|
||||
int mips_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, int count);
|
||||
|
||||
int mips_context_reg_read(struct uc_context *ctx, unsigned int *regs, void **vals, int count);
|
||||
int mips_context_reg_write(struct uc_context *ctx, unsigned int *regs, void *const *vals, int count);
|
||||
int mipsel_context_reg_read(struct uc_context *ctx, unsigned int *regs, void **vals, int count);
|
||||
int mipsel_context_reg_write(struct uc_context *ctx, unsigned int *regs, void *const *vals, int count);
|
||||
int mips64_context_reg_read(struct uc_context *ctx, unsigned int *regs, void **vals, int count);
|
||||
int mips64_context_reg_write(struct uc_context *ctx, unsigned int *regs, void *const *vals, int count);
|
||||
int mips64el_context_reg_read(struct uc_context *ctx, unsigned int *regs, void **vals, int count);
|
||||
int mips64el_context_reg_write(struct uc_context *ctx, unsigned int *regs, void *const *vals, int count);
|
||||
|
||||
void mips_reg_reset(struct uc_struct *uc);
|
||||
|
||||
void mips_uc_init(struct uc_struct* uc);
|
||||
void mipsel_uc_init(struct uc_struct* uc);
|
||||
void mips64_uc_init(struct uc_struct* uc);
|
||||
void mips64el_uc_init(struct uc_struct* uc);
|
||||
#endif
|
||||
Reference in New Issue
Block a user