diff options
author | Thomas Huth <thuth@redhat.com> | 2016-10-11 08:56:52 +0200 |
---|---|---|
committer | Thomas Huth <thuth@redhat.com> | 2016-12-20 21:52:12 +0100 |
commit | fcf5ef2ab52c621a4617ebbef36bf43b4003f4c0 (patch) | |
tree | 2b450d96b01455df8ed908bf8f26ddc388a03380 /target-alpha | |
parent | 82ecffa8c050bf5bbc13329e9b65eac1caa5b55c (diff) | |
download | qemu-fcf5ef2ab52c621a4617ebbef36bf43b4003f4c0.zip qemu-fcf5ef2ab52c621a4617ebbef36bf43b4003f4c0.tar.gz qemu-fcf5ef2ab52c621a4617ebbef36bf43b4003f4c0.tar.bz2 |
Move target-* CPU file into a target/ folder
We've currently got 18 architectures in QEMU, and thus 18 target-xxx
folders in the root folder of the QEMU source tree. More architectures
(e.g. RISC-V, AVR) are likely to be included soon, too, so the main
folder of the QEMU sources slowly gets quite overcrowded with the
target-xxx folders.
To disburden the main folder a little bit, let's move the target-xxx
folders into a dedicated target/ folder, so that target-xxx/ simply
becomes target/xxx/ instead.
Acked-by: Laurent Vivier <laurent@vivier.eu> [m68k part]
Acked-by: Bastian Koppelmann <kbastian@mail.uni-paderborn.de> [tricore part]
Acked-by: Michael Walle <michael@walle.cc> [lm32 part]
Acked-by: Cornelia Huck <cornelia.huck@de.ibm.com> [s390x part]
Reviewed-by: Christian Borntraeger <borntraeger@de.ibm.com> [s390x part]
Acked-by: Eduardo Habkost <ehabkost@redhat.com> [i386 part]
Acked-by: Artyom Tarasenko <atar4qemu@gmail.com> [sparc part]
Acked-by: Richard Henderson <rth@twiddle.net> [alpha part]
Acked-by: Max Filippov <jcmvbkbc@gmail.com> [xtensa part]
Reviewed-by: David Gibson <david@gibson.dropbear.id.au> [ppc part]
Acked-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com> [crisµblaze part]
Acked-by: Guan Xuetao <gxt@mprc.pku.edu.cn> [unicore32 part]
Signed-off-by: Thomas Huth <thuth@redhat.com>
Diffstat (limited to 'target-alpha')
-rw-r--r-- | target-alpha/Makefile.objs | 4 | ||||
-rw-r--r-- | target-alpha/STATUS | 28 | ||||
-rw-r--r-- | target-alpha/cpu-qom.h | 52 | ||||
-rw-r--r-- | target-alpha/cpu.c | 342 | ||||
-rw-r--r-- | target-alpha/cpu.h | 518 | ||||
-rw-r--r-- | target-alpha/fpu_helper.c | 553 | ||||
-rw-r--r-- | target-alpha/gdbstub.c | 94 | ||||
-rw-r--r-- | target-alpha/helper.c | 490 | ||||
-rw-r--r-- | target-alpha/helper.h | 104 | ||||
-rw-r--r-- | target-alpha/int_helper.c | 280 | ||||
-rw-r--r-- | target-alpha/machine.c | 91 | ||||
-rw-r--r-- | target-alpha/mem_helper.c | 89 | ||||
-rw-r--r-- | target-alpha/sys_helper.c | 91 | ||||
-rw-r--r-- | target-alpha/translate.c | 3010 | ||||
-rw-r--r-- | target-alpha/vax_helper.c | 355 |
15 files changed, 0 insertions, 6101 deletions
diff --git a/target-alpha/Makefile.objs b/target-alpha/Makefile.objs deleted file mode 100644 index 6366462..0000000 --- a/target-alpha/Makefile.objs +++ /dev/null @@ -1,4 +0,0 @@ -obj-$(CONFIG_SOFTMMU) += machine.o -obj-y += translate.o helper.o cpu.o -obj-y += int_helper.o fpu_helper.o vax_helper.o sys_helper.o mem_helper.o -obj-y += gdbstub.o diff --git a/target-alpha/STATUS b/target-alpha/STATUS deleted file mode 100644 index 6c97445..0000000 --- a/target-alpha/STATUS +++ /dev/null @@ -1,28 +0,0 @@ -(to be completed) - -Alpha emulation structure: -cpu.h : CPU definitions globally exported -exec.h : CPU definitions used only for translated code execution -helper.c : helpers that can be called either by the translated code - or the QEMU core, including the exception handler. -op_helper.c : helpers that can be called only from TCG -helper.h : TCG helpers prototypes -translate.c : Alpha instructions to micro-operations translator - -Code translator status: -The Alpha CPU instruction emulation should be quite complete with the -limitation that the VAX floating-point load and stores are not tested. -The 4 MMU modes are implemented. - -Linux user mode emulation status: -a few programs start to run. Most crash at a certain point, dereferencing a -NULL pointer. It seems that the UNIQUE register is not initialized properly. -It may appear that old executables, not relying on TLS support, run but -this is to be proved... - -Full system emulation status: -* Alpha PALCode emulation is in a very early stage and is not sufficient - to run any real OS. The alpha-softmmu target is not enabled for now. -* no hardware platform description is implemented -* there might be problems in the Alpha PALCode dedicated instructions - that would prevent to use a native PALCode image. diff --git a/target-alpha/cpu-qom.h b/target-alpha/cpu-qom.h deleted file mode 100644 index bae4945..0000000 --- a/target-alpha/cpu-qom.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * QEMU Alpha 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_ALPHA_CPU_QOM_H -#define QEMU_ALPHA_CPU_QOM_H - -#include "qom/cpu.h" - -#define TYPE_ALPHA_CPU "alpha-cpu" - -#define ALPHA_CPU_CLASS(klass) \ - OBJECT_CLASS_CHECK(AlphaCPUClass, (klass), TYPE_ALPHA_CPU) -#define ALPHA_CPU(obj) \ - OBJECT_CHECK(AlphaCPU, (obj), TYPE_ALPHA_CPU) -#define ALPHA_CPU_GET_CLASS(obj) \ - OBJECT_GET_CLASS(AlphaCPUClass, (obj), TYPE_ALPHA_CPU) - -/** - * AlphaCPUClass: - * @parent_realize: The parent class' realize handler. - * @parent_reset: The parent class' reset handler. - * - * An Alpha CPU model. - */ -typedef struct AlphaCPUClass { - /*< private >*/ - CPUClass parent_class; - /*< public >*/ - - DeviceRealize parent_realize; - void (*parent_reset)(CPUState *cpu); -} AlphaCPUClass; - -typedef struct AlphaCPU AlphaCPU; - -#endif diff --git a/target-alpha/cpu.c b/target-alpha/cpu.c deleted file mode 100644 index 30d77ce..0000000 --- a/target-alpha/cpu.c +++ /dev/null @@ -1,342 +0,0 @@ -/* - * QEMU Alpha CPU - * - * Copyright (c) 2007 Jocelyn Mayer - * Copyright (c) 2012 SUSE LINUX Products GmbH - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * <http://www.gnu.org/licenses/lgpl-2.1.html> - */ - -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "cpu.h" -#include "qemu-common.h" -#include "migration/vmstate.h" -#include "exec/exec-all.h" - - -static void alpha_cpu_set_pc(CPUState *cs, vaddr value) -{ - AlphaCPU *cpu = ALPHA_CPU(cs); - - cpu->env.pc = value; -} - -static bool alpha_cpu_has_work(CPUState *cs) -{ - /* Here we are checking to see if the CPU should wake up from HALT. - We will have gotten into this state only for WTINT from PALmode. */ - /* ??? I'm not sure how the IPL state works with WTINT to keep a CPU - asleep even if (some) interrupts have been asserted. For now, - assume that if a CPU really wants to stay asleep, it will mask - interrupts at the chipset level, which will prevent these bits - from being set in the first place. */ - return cs->interrupt_request & (CPU_INTERRUPT_HARD - | CPU_INTERRUPT_TIMER - | CPU_INTERRUPT_SMP - | CPU_INTERRUPT_MCHK); -} - -static void alpha_cpu_disas_set_info(CPUState *cpu, disassemble_info *info) -{ - info->mach = bfd_mach_alpha_ev6; - info->print_insn = print_insn_alpha; -} - -static void alpha_cpu_realizefn(DeviceState *dev, Error **errp) -{ - CPUState *cs = CPU(dev); - AlphaCPUClass *acc = ALPHA_CPU_GET_CLASS(dev); - Error *local_err = NULL; - - cpu_exec_realizefn(cs, &local_err); - if (local_err != NULL) { - error_propagate(errp, local_err); - return; - } - - qemu_init_vcpu(cs); - - acc->parent_realize(dev, errp); -} - -/* Sort alphabetically by type name. */ -static gint alpha_cpu_list_compare(gconstpointer a, gconstpointer b) -{ - ObjectClass *class_a = (ObjectClass *)a; - ObjectClass *class_b = (ObjectClass *)b; - const char *name_a, *name_b; - - name_a = object_class_get_name(class_a); - name_b = object_class_get_name(class_b); - return strcmp(name_a, name_b); -} - -static void alpha_cpu_list_entry(gpointer data, gpointer user_data) -{ - ObjectClass *oc = data; - CPUListState *s = user_data; - - (*s->cpu_fprintf)(s->file, " %s\n", - object_class_get_name(oc)); -} - -void alpha_cpu_list(FILE *f, fprintf_function cpu_fprintf) -{ - CPUListState s = { - .file = f, - .cpu_fprintf = cpu_fprintf, - }; - GSList *list; - - list = object_class_get_list(TYPE_ALPHA_CPU, false); - list = g_slist_sort(list, alpha_cpu_list_compare); - (*cpu_fprintf)(f, "Available CPUs:\n"); - g_slist_foreach(list, alpha_cpu_list_entry, &s); - g_slist_free(list); -} - -/* Models */ - -#define TYPE(model) model "-" TYPE_ALPHA_CPU - -typedef struct AlphaCPUAlias { - const char *alias; - const char *typename; -} AlphaCPUAlias; - -static const AlphaCPUAlias alpha_cpu_aliases[] = { - { "21064", TYPE("ev4") }, - { "21164", TYPE("ev5") }, - { "21164a", TYPE("ev56") }, - { "21164pc", TYPE("pca56") }, - { "21264", TYPE("ev6") }, - { "21264a", TYPE("ev67") }, -}; - -static ObjectClass *alpha_cpu_class_by_name(const char *cpu_model) -{ - ObjectClass *oc = NULL; - char *typename; - int i; - - if (cpu_model == NULL) { - return NULL; - } - - oc = object_class_by_name(cpu_model); - if (oc != NULL && object_class_dynamic_cast(oc, TYPE_ALPHA_CPU) != NULL && - !object_class_is_abstract(oc)) { - return oc; - } - - for (i = 0; i < ARRAY_SIZE(alpha_cpu_aliases); i++) { - if (strcmp(cpu_model, alpha_cpu_aliases[i].alias) == 0) { - oc = object_class_by_name(alpha_cpu_aliases[i].typename); - assert(oc != NULL && !object_class_is_abstract(oc)); - return oc; - } - } - - typename = g_strdup_printf("%s-" TYPE_ALPHA_CPU, cpu_model); - oc = object_class_by_name(typename); - g_free(typename); - if (oc != NULL && object_class_is_abstract(oc)) { - oc = NULL; - } - return oc; -} - -AlphaCPU *cpu_alpha_init(const char *cpu_model) -{ - AlphaCPU *cpu; - ObjectClass *cpu_class; - - cpu_class = alpha_cpu_class_by_name(cpu_model); - if (cpu_class == NULL) { - /* Default to ev67; no reason not to emulate insns by default. */ - cpu_class = object_class_by_name(TYPE("ev67")); - } - cpu = ALPHA_CPU(object_new(object_class_get_name(cpu_class))); - - object_property_set_bool(OBJECT(cpu), true, "realized", NULL); - - return cpu; -} - -static void ev4_cpu_initfn(Object *obj) -{ - AlphaCPU *cpu = ALPHA_CPU(obj); - CPUAlphaState *env = &cpu->env; - - env->implver = IMPLVER_2106x; -} - -static const TypeInfo ev4_cpu_type_info = { - .name = TYPE("ev4"), - .parent = TYPE_ALPHA_CPU, - .instance_init = ev4_cpu_initfn, -}; - -static void ev5_cpu_initfn(Object *obj) -{ - AlphaCPU *cpu = ALPHA_CPU(obj); - CPUAlphaState *env = &cpu->env; - - env->implver = IMPLVER_21164; -} - -static const TypeInfo ev5_cpu_type_info = { - .name = TYPE("ev5"), - .parent = TYPE_ALPHA_CPU, - .instance_init = ev5_cpu_initfn, -}; - -static void ev56_cpu_initfn(Object *obj) -{ - AlphaCPU *cpu = ALPHA_CPU(obj); - CPUAlphaState *env = &cpu->env; - - env->amask |= AMASK_BWX; -} - -static const TypeInfo ev56_cpu_type_info = { - .name = TYPE("ev56"), - .parent = TYPE("ev5"), - .instance_init = ev56_cpu_initfn, -}; - -static void pca56_cpu_initfn(Object *obj) -{ - AlphaCPU *cpu = ALPHA_CPU(obj); - CPUAlphaState *env = &cpu->env; - - env->amask |= AMASK_MVI; -} - -static const TypeInfo pca56_cpu_type_info = { - .name = TYPE("pca56"), - .parent = TYPE("ev56"), - .instance_init = pca56_cpu_initfn, -}; - -static void ev6_cpu_initfn(Object *obj) -{ - AlphaCPU *cpu = ALPHA_CPU(obj); - CPUAlphaState *env = &cpu->env; - - env->implver = IMPLVER_21264; - env->amask = AMASK_BWX | AMASK_FIX | AMASK_MVI | AMASK_TRAP; -} - -static const TypeInfo ev6_cpu_type_info = { - .name = TYPE("ev6"), - .parent = TYPE_ALPHA_CPU, - .instance_init = ev6_cpu_initfn, -}; - -static void ev67_cpu_initfn(Object *obj) -{ - AlphaCPU *cpu = ALPHA_CPU(obj); - CPUAlphaState *env = &cpu->env; - - env->amask |= AMASK_CIX | AMASK_PREFETCH; -} - -static const TypeInfo ev67_cpu_type_info = { - .name = TYPE("ev67"), - .parent = TYPE("ev6"), - .instance_init = ev67_cpu_initfn, -}; - -static const TypeInfo ev68_cpu_type_info = { - .name = TYPE("ev68"), - .parent = TYPE("ev67"), -}; - -static void alpha_cpu_initfn(Object *obj) -{ - CPUState *cs = CPU(obj); - AlphaCPU *cpu = ALPHA_CPU(obj); - CPUAlphaState *env = &cpu->env; - - cs->env_ptr = env; - tlb_flush(cs, 1); - - alpha_translate_init(); - -#if defined(CONFIG_USER_ONLY) - env->ps = PS_USER_MODE; - cpu_alpha_store_fpcr(env, (FPCR_INVD | FPCR_DZED | FPCR_OVFD - | FPCR_UNFD | FPCR_INED | FPCR_DNOD - | FPCR_DYN_NORMAL)); -#endif - env->lock_addr = -1; - env->fen = 1; -} - -static void alpha_cpu_class_init(ObjectClass *oc, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(oc); - CPUClass *cc = CPU_CLASS(oc); - AlphaCPUClass *acc = ALPHA_CPU_CLASS(oc); - - acc->parent_realize = dc->realize; - dc->realize = alpha_cpu_realizefn; - - cc->class_by_name = alpha_cpu_class_by_name; - cc->has_work = alpha_cpu_has_work; - cc->do_interrupt = alpha_cpu_do_interrupt; - cc->cpu_exec_interrupt = alpha_cpu_exec_interrupt; - cc->dump_state = alpha_cpu_dump_state; - cc->set_pc = alpha_cpu_set_pc; - cc->gdb_read_register = alpha_cpu_gdb_read_register; - cc->gdb_write_register = alpha_cpu_gdb_write_register; -#ifdef CONFIG_USER_ONLY - cc->handle_mmu_fault = alpha_cpu_handle_mmu_fault; -#else - cc->do_unassigned_access = alpha_cpu_unassigned_access; - cc->do_unaligned_access = alpha_cpu_do_unaligned_access; - cc->get_phys_page_debug = alpha_cpu_get_phys_page_debug; - dc->vmsd = &vmstate_alpha_cpu; -#endif - cc->disas_set_info = alpha_cpu_disas_set_info; - - cc->gdb_num_core_regs = 67; -} - -static const TypeInfo alpha_cpu_type_info = { - .name = TYPE_ALPHA_CPU, - .parent = TYPE_CPU, - .instance_size = sizeof(AlphaCPU), - .instance_init = alpha_cpu_initfn, - .abstract = true, - .class_size = sizeof(AlphaCPUClass), - .class_init = alpha_cpu_class_init, -}; - -static void alpha_cpu_register_types(void) -{ - type_register_static(&alpha_cpu_type_info); - type_register_static(&ev4_cpu_type_info); - type_register_static(&ev5_cpu_type_info); - type_register_static(&ev56_cpu_type_info); - type_register_static(&pca56_cpu_type_info); - type_register_static(&ev6_cpu_type_info); - type_register_static(&ev67_cpu_type_info); - type_register_static(&ev68_cpu_type_info); -} - -type_init(alpha_cpu_register_types) diff --git a/target-alpha/cpu.h b/target-alpha/cpu.h deleted file mode 100644 index b08d160..0000000 --- a/target-alpha/cpu.h +++ /dev/null @@ -1,518 +0,0 @@ -/* - * Alpha emulation cpu definitions for qemu. - * - * Copyright (c) 2007 Jocelyn Mayer - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef ALPHA_CPU_H -#define ALPHA_CPU_H - -#include "qemu-common.h" -#include "cpu-qom.h" - -#define TARGET_LONG_BITS 64 -#define ALIGNED_ONLY - -#define CPUArchState struct CPUAlphaState - -#include "exec/cpu-defs.h" - -#include "fpu/softfloat.h" - -#define ICACHE_LINE_SIZE 32 -#define DCACHE_LINE_SIZE 32 - -#define TARGET_PAGE_BITS 13 - -#ifdef CONFIG_USER_ONLY -/* ??? The kernel likes to give addresses in high memory. If the host has - more virtual address space than the guest, this can lead to impossible - allocations. Honor the long-standing assumption that only kernel addrs - are negative, but otherwise allow allocations anywhere. This could lead - to tricky emulation problems for programs doing tagged addressing, but - that's far fewer than encounter the impossible allocation problem. */ -#define TARGET_PHYS_ADDR_SPACE_BITS 63 -#define TARGET_VIRT_ADDR_SPACE_BITS 63 -#else -/* ??? EV4 has 34 phys addr bits, EV5 has 40, EV6 has 44. */ -#define TARGET_PHYS_ADDR_SPACE_BITS 44 -#define TARGET_VIRT_ADDR_SPACE_BITS (30 + TARGET_PAGE_BITS) -#endif - -/* Alpha major type */ -enum { - ALPHA_EV3 = 1, - ALPHA_EV4 = 2, - ALPHA_SIM = 3, - ALPHA_LCA = 4, - ALPHA_EV5 = 5, /* 21164 */ - ALPHA_EV45 = 6, /* 21064A */ - ALPHA_EV56 = 7, /* 21164A */ -}; - -/* EV4 minor type */ -enum { - ALPHA_EV4_2 = 0, - ALPHA_EV4_3 = 1, -}; - -/* LCA minor type */ -enum { - ALPHA_LCA_1 = 1, /* 21066 */ - ALPHA_LCA_2 = 2, /* 20166 */ - ALPHA_LCA_3 = 3, /* 21068 */ - ALPHA_LCA_4 = 4, /* 21068 */ - ALPHA_LCA_5 = 5, /* 21066A */ - ALPHA_LCA_6 = 6, /* 21068A */ -}; - -/* EV5 minor type */ -enum { - ALPHA_EV5_1 = 1, /* Rev BA, CA */ - ALPHA_EV5_2 = 2, /* Rev DA, EA */ - ALPHA_EV5_3 = 3, /* Pass 3 */ - ALPHA_EV5_4 = 4, /* Pass 3.2 */ - ALPHA_EV5_5 = 5, /* Pass 4 */ -}; - -/* EV45 minor type */ -enum { - ALPHA_EV45_1 = 1, /* Pass 1 */ - ALPHA_EV45_2 = 2, /* Pass 1.1 */ - ALPHA_EV45_3 = 3, /* Pass 2 */ -}; - -/* EV56 minor type */ -enum { - ALPHA_EV56_1 = 1, /* Pass 1 */ - ALPHA_EV56_2 = 2, /* Pass 2 */ -}; - -enum { - IMPLVER_2106x = 0, /* EV4, EV45 & LCA45 */ - IMPLVER_21164 = 1, /* EV5, EV56 & PCA45 */ - IMPLVER_21264 = 2, /* EV6, EV67 & EV68x */ - IMPLVER_21364 = 3, /* EV7 & EV79 */ -}; - -enum { - AMASK_BWX = 0x00000001, - AMASK_FIX = 0x00000002, - AMASK_CIX = 0x00000004, - AMASK_MVI = 0x00000100, - AMASK_TRAP = 0x00000200, - AMASK_PREFETCH = 0x00001000, -}; - -enum { - VAX_ROUND_NORMAL = 0, - VAX_ROUND_CHOPPED, -}; - -enum { - IEEE_ROUND_NORMAL = 0, - IEEE_ROUND_DYNAMIC, - IEEE_ROUND_PLUS, - IEEE_ROUND_MINUS, - IEEE_ROUND_CHOPPED, -}; - -/* IEEE floating-point operations encoding */ -/* Trap mode */ -enum { - FP_TRAP_I = 0x0, - FP_TRAP_U = 0x1, - FP_TRAP_S = 0x4, - FP_TRAP_SU = 0x5, - FP_TRAP_SUI = 0x7, -}; - -/* Rounding mode */ -enum { - FP_ROUND_CHOPPED = 0x0, - FP_ROUND_MINUS = 0x1, - FP_ROUND_NORMAL = 0x2, - FP_ROUND_DYNAMIC = 0x3, -}; - -/* FPCR bits -- right-shifted 32 so we can use a uint32_t. */ -#define FPCR_SUM (1U << (63 - 32)) -#define FPCR_INED (1U << (62 - 32)) -#define FPCR_UNFD (1U << (61 - 32)) -#define FPCR_UNDZ (1U << (60 - 32)) -#define FPCR_DYN_SHIFT (58 - 32) -#define FPCR_DYN_CHOPPED (0U << FPCR_DYN_SHIFT) -#define FPCR_DYN_MINUS (1U << FPCR_DYN_SHIFT) -#define FPCR_DYN_NORMAL (2U << FPCR_DYN_SHIFT) -#define FPCR_DYN_PLUS (3U << FPCR_DYN_SHIFT) -#define FPCR_DYN_MASK (3U << FPCR_DYN_SHIFT) -#define FPCR_IOV (1U << (57 - 32)) -#define FPCR_INE (1U << (56 - 32)) -#define FPCR_UNF (1U << (55 - 32)) -#define FPCR_OVF (1U << (54 - 32)) -#define FPCR_DZE (1U << (53 - 32)) -#define FPCR_INV (1U << (52 - 32)) -#define FPCR_OVFD (1U << (51 - 32)) -#define FPCR_DZED (1U << (50 - 32)) -#define FPCR_INVD (1U << (49 - 32)) -#define FPCR_DNZ (1U << (48 - 32)) -#define FPCR_DNOD (1U << (47 - 32)) -#define FPCR_STATUS_MASK (FPCR_IOV | FPCR_INE | FPCR_UNF \ - | FPCR_OVF | FPCR_DZE | FPCR_INV) - -/* The silly software trap enables implemented by the kernel emulation. - These are more or less architecturally required, since the real hardware - has read-as-zero bits in the FPCR when the features aren't implemented. - For the purposes of QEMU, we pretend the FPCR can hold everything. */ -#define SWCR_TRAP_ENABLE_INV (1U << 1) -#define SWCR_TRAP_ENABLE_DZE (1U << 2) -#define SWCR_TRAP_ENABLE_OVF (1U << 3) -#define SWCR_TRAP_ENABLE_UNF (1U << 4) -#define SWCR_TRAP_ENABLE_INE (1U << 5) -#define SWCR_TRAP_ENABLE_DNO (1U << 6) -#define SWCR_TRAP_ENABLE_MASK ((1U << 7) - (1U << 1)) - -#define SWCR_MAP_DMZ (1U << 12) -#define SWCR_MAP_UMZ (1U << 13) -#define SWCR_MAP_MASK (SWCR_MAP_DMZ | SWCR_MAP_UMZ) - -#define SWCR_STATUS_INV (1U << 17) -#define SWCR_STATUS_DZE (1U << 18) -#define SWCR_STATUS_OVF (1U << 19) -#define SWCR_STATUS_UNF (1U << 20) -#define SWCR_STATUS_INE (1U << 21) -#define SWCR_STATUS_DNO (1U << 22) -#define SWCR_STATUS_MASK ((1U << 23) - (1U << 17)) - -#define SWCR_MASK (SWCR_TRAP_ENABLE_MASK | SWCR_MAP_MASK | SWCR_STATUS_MASK) - -/* MMU modes definitions */ - -/* Alpha has 5 MMU modes: PALcode, Kernel, Executive, Supervisor, and User. - The Unix PALcode only exposes the kernel and user modes; presumably - executive and supervisor are used by VMS. - - PALcode itself uses physical mode for code and kernel mode for data; - there are PALmode instructions that can access data via physical mode - or via an os-installed "alternate mode", which is one of the 4 above. - - That said, we're only emulating Unix PALcode, and not attempting VMS, - so we don't need to implement Executive and Supervisor. QEMU's own - PALcode cheats and usees the KSEG mapping for its code+data rather than - physical addresses. */ - -#define NB_MMU_MODES 3 - -#define MMU_MODE0_SUFFIX _kernel -#define MMU_MODE1_SUFFIX _user -#define MMU_KERNEL_IDX 0 -#define MMU_USER_IDX 1 -#define MMU_PHYS_IDX 2 - -typedef struct CPUAlphaState CPUAlphaState; - -struct CPUAlphaState { - uint64_t ir[31]; - float64 fir[31]; - uint64_t pc; - uint64_t unique; - uint64_t lock_addr; - uint64_t lock_value; - - /* The FPCR, and disassembled portions thereof. */ - uint32_t fpcr; - uint32_t fpcr_exc_enable; - float_status fp_status; - uint8_t fpcr_dyn_round; - uint8_t fpcr_flush_to_zero; - - /* The Internal Processor Registers. Some of these we assume always - exist for use in user-mode. */ - uint8_t ps; - uint8_t intr_flag; - uint8_t pal_mode; - uint8_t fen; - - uint32_t pcc_ofs; - - /* These pass data from the exception logic in the translator and - helpers to the OS entry point. This is used for both system - emulation and user-mode. */ - uint64_t trap_arg0; - uint64_t trap_arg1; - uint64_t trap_arg2; - -#if !defined(CONFIG_USER_ONLY) - /* The internal data required by our emulation of the Unix PALcode. */ - uint64_t exc_addr; - uint64_t palbr; - uint64_t ptbr; - uint64_t vptptr; - uint64_t sysval; - uint64_t usp; - uint64_t shadow[8]; - uint64_t scratch[24]; -#endif - - /* This alarm doesn't exist in real hardware; we wish it did. */ - uint64_t alarm_expire; - - /* Those resources are used only in QEMU core */ - CPU_COMMON - - int error_code; - - uint32_t features; - uint32_t amask; - int implver; -}; - -/** - * AlphaCPU: - * @env: #CPUAlphaState - * - * An Alpha CPU. - */ -struct AlphaCPU { - /*< private >*/ - CPUState parent_obj; - /*< public >*/ - - CPUAlphaState env; - - /* This alarm doesn't exist in real hardware; we wish it did. */ - QEMUTimer *alarm_timer; -}; - -static inline AlphaCPU *alpha_env_get_cpu(CPUAlphaState *env) -{ - return container_of(env, AlphaCPU, env); -} - -#define ENV_GET_CPU(e) CPU(alpha_env_get_cpu(e)) - -#define ENV_OFFSET offsetof(AlphaCPU, env) - -#ifndef CONFIG_USER_ONLY -extern const struct VMStateDescription vmstate_alpha_cpu; -#endif - -void alpha_cpu_do_interrupt(CPUState *cpu); -bool alpha_cpu_exec_interrupt(CPUState *cpu, int int_req); -void alpha_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf, - int flags); -hwaddr alpha_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); -int alpha_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg); -int alpha_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); -void alpha_cpu_do_unaligned_access(CPUState *cpu, vaddr addr, - MMUAccessType access_type, - int mmu_idx, uintptr_t retaddr); - -#define cpu_list alpha_cpu_list -#define cpu_signal_handler cpu_alpha_signal_handler - -#include "exec/cpu-all.h" - -enum { - FEATURE_ASN = 0x00000001, - FEATURE_SPS = 0x00000002, - FEATURE_VIRBND = 0x00000004, - FEATURE_TBCHK = 0x00000008, -}; - -enum { - EXCP_RESET, - EXCP_MCHK, - EXCP_SMP_INTERRUPT, - EXCP_CLK_INTERRUPT, - EXCP_DEV_INTERRUPT, - EXCP_MMFAULT, - EXCP_UNALIGN, - EXCP_OPCDEC, - EXCP_ARITH, - EXCP_FEN, - EXCP_CALL_PAL, -}; - -/* Alpha-specific interrupt pending bits. */ -#define CPU_INTERRUPT_TIMER CPU_INTERRUPT_TGT_EXT_0 -#define CPU_INTERRUPT_SMP CPU_INTERRUPT_TGT_EXT_1 -#define CPU_INTERRUPT_MCHK CPU_INTERRUPT_TGT_EXT_2 - -/* OSF/1 Page table bits. */ -enum { - PTE_VALID = 0x0001, - PTE_FOR = 0x0002, /* used for page protection (fault on read) */ - PTE_FOW = 0x0004, /* used for page protection (fault on write) */ - PTE_FOE = 0x0008, /* used for page protection (fault on exec) */ - PTE_ASM = 0x0010, - PTE_KRE = 0x0100, - PTE_URE = 0x0200, - PTE_KWE = 0x1000, - PTE_UWE = 0x2000 -}; - -/* Hardware interrupt (entInt) constants. */ -enum { - INT_K_IP, - INT_K_CLK, - INT_K_MCHK, - INT_K_DEV, - INT_K_PERF, -}; - -/* Memory management (entMM) constants. */ -enum { - MM_K_TNV, - MM_K_ACV, - MM_K_FOR, - MM_K_FOE, - MM_K_FOW -}; - -/* Arithmetic exception (entArith) constants. */ -enum { - EXC_M_SWC = 1, /* Software completion */ - EXC_M_INV = 2, /* Invalid operation */ - EXC_M_DZE = 4, /* Division by zero */ - EXC_M_FOV = 8, /* Overflow */ - EXC_M_UNF = 16, /* Underflow */ - EXC_M_INE = 32, /* Inexact result */ - EXC_M_IOV = 64 /* Integer Overflow */ -}; - -/* Processor status constants. */ -enum { - /* Low 3 bits are interrupt mask level. */ - PS_INT_MASK = 7, - - /* Bits 4 and 5 are the mmu mode. The VMS PALcode uses all 4 modes; - The Unix PALcode only uses bit 4. */ - PS_USER_MODE = 8 -}; - -static inline int cpu_mmu_index(CPUAlphaState *env, bool ifetch) -{ - if (env->pal_mode) { - return MMU_KERNEL_IDX; - } else if (env->ps & PS_USER_MODE) { - return MMU_USER_IDX; - } else { - return MMU_KERNEL_IDX; - } -} - -enum { - IR_V0 = 0, - IR_T0 = 1, - IR_T1 = 2, - IR_T2 = 3, - IR_T3 = 4, - IR_T4 = 5, - IR_T5 = 6, - IR_T6 = 7, - IR_T7 = 8, - IR_S0 = 9, - IR_S1 = 10, - IR_S2 = 11, - IR_S3 = 12, - IR_S4 = 13, - IR_S5 = 14, - IR_S6 = 15, - IR_FP = IR_S6, - IR_A0 = 16, - IR_A1 = 17, - IR_A2 = 18, - IR_A3 = 19, - IR_A4 = 20, - IR_A5 = 21, - IR_T8 = 22, - IR_T9 = 23, - IR_T10 = 24, - IR_T11 = 25, - IR_RA = 26, - IR_T12 = 27, - IR_PV = IR_T12, - IR_AT = 28, - IR_GP = 29, - IR_SP = 30, - IR_ZERO = 31, -}; - -void alpha_translate_init(void); - -AlphaCPU *cpu_alpha_init(const char *cpu_model); - -#define cpu_init(cpu_model) CPU(cpu_alpha_init(cpu_model)) - -void alpha_cpu_list(FILE *f, fprintf_function cpu_fprintf); -/* you can call this signal handler from your SIGBUS and SIGSEGV - signal handlers to inform the virtual CPU of exceptions. non zero - is returned if the signal was handled by the virtual CPU. */ -int cpu_alpha_signal_handler(int host_signum, void *pinfo, - void *puc); -int alpha_cpu_handle_mmu_fault(CPUState *cpu, vaddr address, int rw, - int mmu_idx); -void QEMU_NORETURN dynamic_excp(CPUAlphaState *, uintptr_t, int, int); -void QEMU_NORETURN arith_excp(CPUAlphaState *, uintptr_t, int, uint64_t); - -uint64_t cpu_alpha_load_fpcr (CPUAlphaState *env); -void cpu_alpha_store_fpcr (CPUAlphaState *env, uint64_t val); -uint64_t cpu_alpha_load_gr(CPUAlphaState *env, unsigned reg); -void cpu_alpha_store_gr(CPUAlphaState *env, unsigned reg, uint64_t val); -#ifndef CONFIG_USER_ONLY -QEMU_NORETURN void alpha_cpu_unassigned_access(CPUState *cpu, hwaddr addr, - bool is_write, bool is_exec, - int unused, unsigned size); -#endif - -/* Bits in TB->FLAGS that control how translation is processed. */ -enum { - TB_FLAGS_PAL_MODE = 1, - TB_FLAGS_FEN = 2, - TB_FLAGS_USER_MODE = 8, - - TB_FLAGS_AMASK_SHIFT = 4, - TB_FLAGS_AMASK_BWX = AMASK_BWX << TB_FLAGS_AMASK_SHIFT, - TB_FLAGS_AMASK_FIX = AMASK_FIX << TB_FLAGS_AMASK_SHIFT, - TB_FLAGS_AMASK_CIX = AMASK_CIX << TB_FLAGS_AMASK_SHIFT, - TB_FLAGS_AMASK_MVI = AMASK_MVI << TB_FLAGS_AMASK_SHIFT, - TB_FLAGS_AMASK_TRAP = AMASK_TRAP << TB_FLAGS_AMASK_SHIFT, - TB_FLAGS_AMASK_PREFETCH = AMASK_PREFETCH << TB_FLAGS_AMASK_SHIFT, -}; - -static inline void cpu_get_tb_cpu_state(CPUAlphaState *env, target_ulong *pc, - target_ulong *cs_base, uint32_t *pflags) -{ - int flags = 0; - - *pc = env->pc; - *cs_base = 0; - - if (env->pal_mode) { - flags = TB_FLAGS_PAL_MODE; - } else { - flags = env->ps & PS_USER_MODE; - } - if (env->fen) { - flags |= TB_FLAGS_FEN; - } - flags |= env->amask << TB_FLAGS_AMASK_SHIFT; - - *pflags = flags; -} - -#endif /* ALPHA_CPU_H */ diff --git a/target-alpha/fpu_helper.c b/target-alpha/fpu_helper.c deleted file mode 100644 index 9645978..0000000 --- a/target-alpha/fpu_helper.c +++ /dev/null @@ -1,553 +0,0 @@ -/* - * Helpers for floating point instructions. - * - * Copyright (c) 2007 Jocelyn Mayer - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/>. - */ - -#include "qemu/osdep.h" -#include "cpu.h" -#include "exec/exec-all.h" -#include "exec/helper-proto.h" -#include "fpu/softfloat.h" - -#define FP_STATUS (env->fp_status) - - -void helper_setroundmode(CPUAlphaState *env, uint32_t val) -{ - set_float_rounding_mode(val, &FP_STATUS); -} - -void helper_setflushzero(CPUAlphaState *env, uint32_t val) -{ - set_flush_to_zero(val, &FP_STATUS); -} - -#define CONVERT_BIT(X, SRC, DST) \ - (SRC > DST ? (X) / (SRC / DST) & (DST) : ((X) & SRC) * (DST / SRC)) - -static uint32_t soft_to_fpcr_exc(CPUAlphaState *env) -{ - uint8_t exc = get_float_exception_flags(&FP_STATUS); - uint32_t ret = 0; - - if (unlikely(exc)) { - set_float_exception_flags(0, &FP_STATUS); - ret |= CONVERT_BIT(exc, float_flag_invalid, FPCR_INV); - ret |= CONVERT_BIT(exc, float_flag_divbyzero, FPCR_DZE); - ret |= CONVERT_BIT(exc, float_flag_overflow, FPCR_OVF); - ret |= CONVERT_BIT(exc, float_flag_underflow, FPCR_UNF); - ret |= CONVERT_BIT(exc, float_flag_inexact, FPCR_INE); - } - - return ret; -} - -static void fp_exc_raise1(CPUAlphaState *env, uintptr_t retaddr, - uint32_t exc, uint32_t regno, uint32_t hw_exc) -{ - hw_exc |= CONVERT_BIT(exc, FPCR_INV, EXC_M_INV); - hw_exc |= CONVERT_BIT(exc, FPCR_DZE, EXC_M_DZE); - hw_exc |= CONVERT_BIT(exc, FPCR_OVF, EXC_M_FOV); - hw_exc |= CONVERT_BIT(exc, FPCR_UNF, EXC_M_UNF); - hw_exc |= CONVERT_BIT(exc, FPCR_INE, EXC_M_INE); - hw_exc |= CONVERT_BIT(exc, FPCR_IOV, EXC_M_IOV); - - arith_excp(env, retaddr, hw_exc, 1ull << regno); -} - -/* Raise exceptions for ieee fp insns without software completion. - In that case there are no exceptions that don't trap; the mask - doesn't apply. */ -void helper_fp_exc_raise(CPUAlphaState *env, uint32_t ignore, uint32_t regno) -{ - uint32_t exc = env->error_code; - if (exc) { - env->fpcr |= exc; - exc &= ~ignore; - if (exc) { - fp_exc_raise1(env, GETPC(), exc, regno, 0); - } - } -} - -/* Raise exceptions for ieee fp insns with software completion. */ -void helper_fp_exc_raise_s(CPUAlphaState *env, uint32_t ignore, uint32_t regno) -{ - uint32_t exc = env->error_code & ~ignore; - if (exc) { - env->fpcr |= exc; - exc &= ~ignore; - if (exc) { - exc &= env->fpcr_exc_enable; - fp_exc_raise1(env, GETPC(), exc, regno, EXC_M_SWC); - } - } -} - -/* Input handing without software completion. Trap for all - non-finite numbers. */ -void helper_ieee_input(CPUAlphaState *env, uint64_t val) -{ - uint32_t exp = (uint32_t)(val >> 52) & 0x7ff; - uint64_t frac = val & 0xfffffffffffffull; - - if (exp == 0) { - /* Denormals without /S raise an exception. */ - if (frac != 0) { - arith_excp(env, GETPC(), EXC_M_INV, 0); - } - } else if (exp == 0x7ff) { - /* Infinity or NaN. */ - env->fpcr |= FPCR_INV; - arith_excp(env, GETPC(), EXC_M_INV, 0); - } -} - -/* Similar, but does not trap for infinities. Used for comparisons. */ -void helper_ieee_input_cmp(CPUAlphaState *env, uint64_t val) -{ - uint32_t exp = (uint32_t)(val >> 52) & 0x7ff; - uint64_t frac = val & 0xfffffffffffffull; - - if (exp == 0) { - /* Denormals without /S raise an exception. */ - if (frac != 0) { - arith_excp(env, GETPC(), EXC_M_INV, 0); - } - } else if (exp == 0x7ff && frac) { - /* NaN. */ - env->fpcr |= FPCR_INV; - arith_excp(env, GETPC(), EXC_M_INV, 0); - } -} - -/* Input handing with software completion. Trap for denorms, unless DNZ - is set. If we try to support DNOD (which none of the produced hardware - did, AFAICS), we'll need to suppress the trap when FPCR.DNOD is set; - then the code downstream of that will need to cope with denorms sans - flush_input_to_zero. Most of it should work sanely, but there's - nothing to compare with. */ -void helper_ieee_input_s(CPUAlphaState *env, uint64_t val) -{ - if (unlikely(2 * val - 1 < 0x1fffffffffffffull) - && !env->fp_status.flush_inputs_to_zero) { - arith_excp(env, GETPC(), EXC_M_INV | EXC_M_SWC, 0); - } -} - -/* S floating (single) */ - -/* Taken from linux/arch/alpha/kernel/traps.c, s_mem_to_reg. */ -static inline uint64_t float32_to_s_int(uint32_t fi) -{ - uint32_t frac = fi & 0x7fffff; - uint32_t sign = fi >> 31; - uint32_t exp_msb = (fi >> 30) & 1; - uint32_t exp_low = (fi >> 23) & 0x7f; - uint32_t exp; - - exp = (exp_msb << 10) | exp_low; - if (exp_msb) { - if (exp_low == 0x7f) { - exp = 0x7ff; - } - } else { - if (exp_low != 0x00) { - exp |= 0x380; - } - } - - return (((uint64_t)sign << 63) - | ((uint64_t)exp << 52) - | ((uint64_t)frac << 29)); -} - -static inline uint64_t float32_to_s(float32 fa) -{ - CPU_FloatU a; - a.f = fa; - return float32_to_s_int(a.l); -} - -static inline uint32_t s_to_float32_int(uint64_t a) -{ - return ((a >> 32) & 0xc0000000) | ((a >> 29) & 0x3fffffff); -} - -static inline float32 s_to_float32(uint64_t a) -{ - CPU_FloatU r; - r.l = s_to_float32_int(a); - return r.f; -} - -uint32_t helper_s_to_memory(uint64_t a) -{ - return s_to_float32_int(a); -} - -uint64_t helper_memory_to_s(uint32_t a) -{ - return float32_to_s_int(a); -} - -uint64_t helper_adds(CPUAlphaState *env, uint64_t a, uint64_t b) -{ - float32 fa, fb, fr; - - fa = s_to_float32(a); - fb = s_to_float32(b); - fr = float32_add(fa, fb, &FP_STATUS); - env->error_code = soft_to_fpcr_exc(env); - - return float32_to_s(fr); -} - -uint64_t helper_subs(CPUAlphaState *env, uint64_t a, uint64_t b) -{ - float32 fa, fb, fr; - - fa = s_to_float32(a); - fb = s_to_float32(b); - fr = float32_sub(fa, fb, &FP_STATUS); - env->error_code = soft_to_fpcr_exc(env); - - return float32_to_s(fr); -} - -uint64_t helper_muls(CPUAlphaState *env, uint64_t a, uint64_t b) -{ - float32 fa, fb, fr; - - fa = s_to_float32(a); - fb = s_to_float32(b); - fr = float32_mul(fa, fb, &FP_STATUS); - env->error_code = soft_to_fpcr_exc(env); - - return float32_to_s(fr); -} - -uint64_t helper_divs(CPUAlphaState *env, uint64_t a, uint64_t b) -{ - float32 fa, fb, fr; - - fa = s_to_float32(a); - fb = s_to_float32(b); - fr = float32_div(fa, fb, &FP_STATUS); - env->error_code = soft_to_fpcr_exc(env); - - return float32_to_s(fr); -} - -uint64_t helper_sqrts(CPUAlphaState *env, uint64_t a) -{ - float32 fa, fr; - - fa = s_to_float32(a); - fr = float32_sqrt(fa, &FP_STATUS); - env->error_code = soft_to_fpcr_exc(env); - - return float32_to_s(fr); -} - - -/* T floating (double) */ -static inline float64 t_to_float64(uint64_t a) -{ - /* Memory format is the same as float64 */ - CPU_DoubleU r; - r.ll = a; - return r.d; -} - -static inline uint64_t float64_to_t(float64 fa) -{ - /* Memory format is the same as float64 */ - CPU_DoubleU r; - r.d = fa; - return r.ll; -} - -uint64_t helper_addt(CPUAlphaState *env, uint64_t a, uint64_t b) -{ - float64 fa, fb, fr; - - fa = t_to_float64(a); - fb = t_to_float64(b); - fr = float64_add(fa, fb, &FP_STATUS); - env->error_code = soft_to_fpcr_exc(env); - - return float64_to_t(fr); -} - -uint64_t helper_subt(CPUAlphaState *env, uint64_t a, uint64_t b) -{ - float64 fa, fb, fr; - - fa = t_to_float64(a); - fb = t_to_float64(b); - fr = float64_sub(fa, fb, &FP_STATUS); - env->error_code = soft_to_fpcr_exc(env); - - return float64_to_t(fr); -} - -uint64_t helper_mult(CPUAlphaState *env, uint64_t a, uint64_t b) -{ - float64 fa, fb, fr; - - fa = t_to_float64(a); - fb = t_to_float64(b); - fr = float64_mul(fa, fb, &FP_STATUS); - env->error_code = soft_to_fpcr_exc(env); - - return float64_to_t(fr); -} - -uint64_t helper_divt(CPUAlphaState *env, uint64_t a, uint64_t b) -{ - float64 fa, fb, fr; - - fa = t_to_float64(a); - fb = t_to_float64(b); - fr = float64_div(fa, fb, &FP_STATUS); - env->error_code = soft_to_fpcr_exc(env); - - return float64_to_t(fr); -} - -uint64_t helper_sqrtt(CPUAlphaState *env, uint64_t a) -{ - float64 fa, fr; - - fa = t_to_float64(a); - fr = float64_sqrt(fa, &FP_STATUS); - env->error_code = soft_to_fpcr_exc(env); - - return float64_to_t(fr); -} - -/* Comparisons */ -uint64_t helper_cmptun(CPUAlphaState *env, uint64_t a, uint64_t b) -{ - float64 fa, fb; - uint64_t ret = 0; - - fa = t_to_float64(a); - fb = t_to_float64(b); - - if (float64_unordered_quiet(fa, fb, &FP_STATUS)) { - ret = 0x4000000000000000ULL; - } - env->error_code = soft_to_fpcr_exc(env); - - return ret; -} - -uint64_t helper_cmpteq(CPUAlphaState *env, uint64_t a, uint64_t b) -{ - float64 fa, fb; - uint64_t ret = 0; - - fa = t_to_float64(a); - fb = t_to_float64(b); - - if (float64_eq_quiet(fa, fb, &FP_STATUS)) { - ret = 0x4000000000000000ULL; - } - env->error_code = soft_to_fpcr_exc(env); - - return ret; -} - -uint64_t helper_cmptle(CPUAlphaState *env, uint64_t a, uint64_t b) -{ - float64 fa, fb; - uint64_t ret = 0; - - fa = t_to_float64(a); - fb = t_to_float64(b); - - if (float64_le(fa, fb, &FP_STATUS)) { - ret = 0x4000000000000000ULL; - } - env->error_code = soft_to_fpcr_exc(env); - - return ret; -} - -uint64_t helper_cmptlt(CPUAlphaState *env, uint64_t a, uint64_t b) -{ - float64 fa, fb; - uint64_t ret = 0; - - fa = t_to_float64(a); - fb = t_to_float64(b); - - if (float64_lt(fa, fb, &FP_STATUS)) { - ret = 0x4000000000000000ULL; - } - env->error_code = soft_to_fpcr_exc(env); - - return ret; -} - -/* Floating point format conversion */ -uint64_t helper_cvtts(CPUAlphaState *env, uint64_t a) -{ - float64 fa; - float32 fr; - - fa = t_to_float64(a); - fr = float64_to_float32(fa, &FP_STATUS); - env->error_code = soft_to_fpcr_exc(env); - - return float32_to_s(fr); -} - -uint64_t helper_cvtst(CPUAlphaState *env, uint64_t a) -{ - float32 fa; - float64 fr; - - fa = s_to_float32(a); - fr = float32_to_float64(fa, &FP_STATUS); - env->error_code = soft_to_fpcr_exc(env); - - return float64_to_t(fr); -} - -uint64_t helper_cvtqs(CPUAlphaState *env, uint64_t a) -{ - float32 fr = int64_to_float32(a, &FP_STATUS); - env->error_code = soft_to_fpcr_exc(env); - - return float32_to_s(fr); -} - -/* Implement float64 to uint64_t conversion without saturation -- we must - supply the truncated result. This behaviour is used by the compiler - to get unsigned conversion for free with the same instruction. */ - -static uint64_t do_cvttq(CPUAlphaState *env, uint64_t a, int roundmode) -{ - uint64_t frac, ret = 0; - uint32_t exp, sign, exc = 0; - int shift; - - sign = (a >> 63); - exp = (uint32_t)(a >> 52) & 0x7ff; - frac = a & 0xfffffffffffffull; - - if (exp == 0) { - if (unlikely(frac != 0) && !env->fp_status.flush_inputs_to_zero) { - goto do_underflow; - } - } else if (exp == 0x7ff) { - exc = FPCR_INV; - } else { - /* Restore implicit bit. */ - frac |= 0x10000000000000ull; - - shift = exp - 1023 - 52; - if (shift >= 0) { - /* In this case the number is so large that we must shift - the fraction left. There is no rounding to do. */ - if (shift < 64) { - ret = frac << shift; - } - /* Check for overflow. Note the special case of -0x1p63. */ - if (shift >= 11 && a != 0xC3E0000000000000ull) { - exc = FPCR_IOV | FPCR_INE; - } - } else { - uint64_t round; - - /* In this case the number is smaller than the fraction as - represented by the 52 bit number. Here we must think - about rounding the result. Handle this by shifting the - fractional part of the number into the high bits of ROUND. - This will let us efficiently handle round-to-nearest. */ - shift = -shift; - if (shift < 63) { - ret = frac >> shift; - round = frac << (64 - shift); - } else { - /* The exponent is so small we shift out everything. - Leave a sticky bit for proper rounding below. */ - do_underflow: - round = 1; - } - - if (round) { - exc = FPCR_INE; - switch (roundmode) { - case float_round_nearest_even: - if (round == (1ull << 63)) { - /* Fraction is exactly 0.5; round to even. */ - ret += (ret & 1); - } else if (round > (1ull << 63)) { - ret += 1; - } - break; - case float_round_to_zero: - break; - case float_round_up: - ret += 1 - sign; - break; - case float_round_down: - ret += sign; - break; - } - } - } - if (sign) { - ret = -ret; - } - } - env->error_code = exc; - - return ret; -} - -uint64_t helper_cvttq(CPUAlphaState *env, uint64_t a) -{ - return do_cvttq(env, a, FP_STATUS.float_rounding_mode); -} - -uint64_t helper_cvttq_c(CPUAlphaState *env, uint64_t a) -{ - return do_cvttq(env, a, float_round_to_zero); -} - -uint64_t helper_cvtqt(CPUAlphaState *env, uint64_t a) -{ - float64 fr = int64_to_float64(a, &FP_STATUS); - env->error_code = soft_to_fpcr_exc(env); - return float64_to_t(fr); -} - -uint64_t helper_cvtql(CPUAlphaState *env, uint64_t val) -{ - uint32_t exc = 0; - if (val != (int32_t)val) { - exc = FPCR_IOV | FPCR_INE; - } - env->error_code = exc; - - return ((val & 0xc0000000) << 32) | ((val & 0x3fffffff) << 29); -} diff --git a/target-alpha/gdbstub.c b/target-alpha/gdbstub.c deleted file mode 100644 index d64bccc..0000000 --- a/target-alpha/gdbstub.c +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Alpha gdb server stub - * - * Copyright (c) 2003-2005 Fabrice Bellard - * Copyright (c) 2013 SUSE LINUX Products GmbH - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/>. - */ -#include "qemu/osdep.h" -#include "qemu-common.h" -#include "cpu.h" -#include "exec/gdbstub.h" - -int alpha_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n) -{ - AlphaCPU *cpu = ALPHA_CPU(cs); - CPUAlphaState *env = &cpu->env; - uint64_t val; - CPU_DoubleU d; - - switch (n) { - case 0 ... 30: - val = cpu_alpha_load_gr(env, n); - break; - case 32 ... 62: - d.d = env->fir[n - 32]; - val = d.ll; - break; - case 63: - val = cpu_alpha_load_fpcr(env); - break; - case 64: - val = env->pc; - break; - case 66: - val = env->unique; - break; - case 31: - case 65: - /* 31 really is the zero register; 65 is unassigned in the - gdb protocol, but is still required to occupy 8 bytes. */ - val = 0; - break; - default: - return 0; - } - return gdb_get_regl(mem_buf, val); -} - -int alpha_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) -{ - AlphaCPU *cpu = ALPHA_CPU(cs); - CPUAlphaState *env = &cpu->env; - target_ulong tmp = ldtul_p(mem_buf); - CPU_DoubleU d; - - switch (n) { - case 0 ... 30: - cpu_alpha_store_gr(env, n, tmp); - break; - case 32 ... 62: - d.ll = tmp; - env->fir[n - 32] = d.d; - break; - case 63: - cpu_alpha_store_fpcr(env, tmp); - break; - case 64: - env->pc = tmp; - break; - case 66: - env->unique = tmp; - break; - case 31: - case 65: - /* 31 really is the zero register; 65 is unassigned in the - gdb protocol, but is still required to occupy 8 bytes. */ - break; - default: - return 0; - } - return 8; -} diff --git a/target-alpha/helper.c b/target-alpha/helper.c deleted file mode 100644 index a5c3088..0000000 --- a/target-alpha/helper.c +++ /dev/null @@ -1,490 +0,0 @@ -/* - * Alpha emulation cpu helpers for qemu. - * - * Copyright (c) 2007 Jocelyn Mayer - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/>. - */ - -#include "qemu/osdep.h" - -#include "cpu.h" -#include "exec/exec-all.h" -#include "fpu/softfloat.h" -#include "exec/helper-proto.h" - - -#define CONVERT_BIT(X, SRC, DST) \ - (SRC > DST ? (X) / (SRC / DST) & (DST) : ((X) & SRC) * (DST / SRC)) - -uint64_t cpu_alpha_load_fpcr (CPUAlphaState *env) -{ - return (uint64_t)env->fpcr << 32; -} - -void cpu_alpha_store_fpcr (CPUAlphaState *env, uint64_t val) -{ - uint32_t fpcr = val >> 32; - uint32_t t = 0; - - t |= CONVERT_BIT(fpcr, FPCR_INED, FPCR_INE); - t |= CONVERT_BIT(fpcr, FPCR_UNFD, FPCR_UNF); - t |= CONVERT_BIT(fpcr, FPCR_OVFD, FPCR_OVF); - t |= CONVERT_BIT(fpcr, FPCR_DZED, FPCR_DZE); - t |= CONVERT_BIT(fpcr, FPCR_INVD, FPCR_INV); - - env->fpcr = fpcr; - env->fpcr_exc_enable = ~t & FPCR_STATUS_MASK; - - switch (fpcr & FPCR_DYN_MASK) { - case FPCR_DYN_NORMAL: - default: - t = float_round_nearest_even; - break; - case FPCR_DYN_CHOPPED: - t = float_round_to_zero; - break; - case FPCR_DYN_MINUS: - t = float_round_down; - break; - case FPCR_DYN_PLUS: - t = float_round_up; - break; - } - env->fpcr_dyn_round = t; - - env->fpcr_flush_to_zero = (fpcr & FPCR_UNFD) && (fpcr & FPCR_UNDZ); - env->fp_status.flush_inputs_to_zero = (fpcr & FPCR_DNZ) != 0; -} - -uint64_t helper_load_fpcr(CPUAlphaState *env) -{ - return cpu_alpha_load_fpcr(env); -} - -void helper_store_fpcr(CPUAlphaState *env, uint64_t val) -{ - cpu_alpha_store_fpcr(env, val); -} - -static uint64_t *cpu_alpha_addr_gr(CPUAlphaState *env, unsigned reg) -{ -#ifndef CONFIG_USER_ONLY - if (env->pal_mode) { - if (reg >= 8 && reg <= 14) { - return &env->shadow[reg - 8]; - } else if (reg == 25) { - return &env->shadow[7]; - } - } -#endif - return &env->ir[reg]; -} - -uint64_t cpu_alpha_load_gr(CPUAlphaState *env, unsigned reg) -{ - return *cpu_alpha_addr_gr(env, reg); -} - -void cpu_alpha_store_gr(CPUAlphaState *env, unsigned reg, uint64_t val) -{ - *cpu_alpha_addr_gr(env, reg) = val; -} - -#if defined(CONFIG_USER_ONLY) -int alpha_cpu_handle_mmu_fault(CPUState *cs, vaddr address, - int rw, int mmu_idx) -{ - AlphaCPU *cpu = ALPHA_CPU(cs); - - cs->exception_index = EXCP_MMFAULT; - cpu->env.trap_arg0 = address; - return 1; -} -#else -/* Returns the OSF/1 entMM failure indication, or -1 on success. */ -static int get_physical_address(CPUAlphaState *env, target_ulong addr, - int prot_need, int mmu_idx, - target_ulong *pphys, int *pprot) -{ - CPUState *cs = CPU(alpha_env_get_cpu(env)); - target_long saddr = addr; - target_ulong phys = 0; - target_ulong L1pte, L2pte, L3pte; - target_ulong pt, index; - int prot = 0; - int ret = MM_K_ACV; - - /* Handle physical accesses. */ - if (mmu_idx == MMU_PHYS_IDX) { - phys = addr; - prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; - ret = -1; - goto exit; - } - - /* Ensure that the virtual address is properly sign-extended from - the last implemented virtual address bit. */ - if (saddr >> TARGET_VIRT_ADDR_SPACE_BITS != saddr >> 63) { - goto exit; - } - - /* Translate the superpage. */ - /* ??? When we do more than emulate Unix PALcode, we'll need to - determine which KSEG is actually active. */ - if (saddr < 0 && ((saddr >> 41) & 3) == 2) { - /* User-space cannot access KSEG addresses. */ - if (mmu_idx != MMU_KERNEL_IDX) { - goto exit; - } - - /* For the benefit of the Typhoon chipset, move bit 40 to bit 43. - We would not do this if the 48-bit KSEG is enabled. */ - phys = saddr & ((1ull << 40) - 1); - phys |= (saddr & (1ull << 40)) << 3; - - prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; - ret = -1; - goto exit; - } - - /* Interpret the page table exactly like PALcode does. */ - - pt = env->ptbr; - - /* L1 page table read. */ - index = (addr >> (TARGET_PAGE_BITS + 20)) & 0x3ff; - L1pte = ldq_phys(cs->as, pt + index*8); - - if (unlikely((L1pte & PTE_VALID) == 0)) { - ret = MM_K_TNV; - goto exit; - } - if (unlikely((L1pte & PTE_KRE) == 0)) { - goto exit; - } - pt = L1pte >> 32 << TARGET_PAGE_BITS; - - /* L2 page table read. */ - index = (addr >> (TARGET_PAGE_BITS + 10)) & 0x3ff; - L2pte = ldq_phys(cs->as, pt + index*8); - - if (unlikely((L2pte & PTE_VALID) == 0)) { - ret = MM_K_TNV; - goto exit; - } - if (unlikely((L2pte & PTE_KRE) == 0)) { - goto exit; - } - pt = L2pte >> 32 << TARGET_PAGE_BITS; - - /* L3 page table read. */ - index = (addr >> TARGET_PAGE_BITS) & 0x3ff; - L3pte = ldq_phys(cs->as, pt + index*8); - - phys = L3pte >> 32 << TARGET_PAGE_BITS; - if (unlikely((L3pte & PTE_VALID) == 0)) { - ret = MM_K_TNV; - goto exit; - } - -#if PAGE_READ != 1 || PAGE_WRITE != 2 || PAGE_EXEC != 4 -# error page bits out of date -#endif - - /* Check access violations. */ - if (L3pte & (PTE_KRE << mmu_idx)) { - prot |= PAGE_READ | PAGE_EXEC; - } - if (L3pte & (PTE_KWE << mmu_idx)) { - prot |= PAGE_WRITE; - } - if (unlikely((prot & prot_need) == 0 && prot_need)) { - goto exit; - } - - /* Check fault-on-operation violations. */ - prot &= ~(L3pte >> 1); - ret = -1; - if (unlikely((prot & prot_need) == 0)) { - ret = (prot_need & PAGE_EXEC ? MM_K_FOE : - prot_need & PAGE_WRITE ? MM_K_FOW : - prot_need & PAGE_READ ? MM_K_FOR : -1); - } - - exit: - *pphys = phys; - *pprot = prot; - return ret; -} - -hwaddr alpha_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) -{ - AlphaCPU *cpu = ALPHA_CPU(cs); - target_ulong phys; - int prot, fail; - - fail = get_physical_address(&cpu->env, addr, 0, 0, &phys, &prot); - return (fail >= 0 ? -1 : phys); -} - -int alpha_cpu_handle_mmu_fault(CPUState *cs, vaddr addr, int rw, - int mmu_idx) -{ - AlphaCPU *cpu = ALPHA_CPU(cs); - CPUAlphaState *env = &cpu->env; - target_ulong phys; - int prot, fail; - - fail = get_physical_address(env, addr, 1 << rw, mmu_idx, &phys, &prot); - if (unlikely(fail >= 0)) { - cs->exception_index = EXCP_MMFAULT; - env->trap_arg0 = addr; - env->trap_arg1 = fail; - env->trap_arg2 = (rw == 2 ? -1 : rw); - return 1; - } - - tlb_set_page(cs, addr & TARGET_PAGE_MASK, phys & TARGET_PAGE_MASK, - prot, mmu_idx, TARGET_PAGE_SIZE); - return 0; -} -#endif /* USER_ONLY */ - -void alpha_cpu_do_interrupt(CPUState *cs) -{ - AlphaCPU *cpu = ALPHA_CPU(cs); - CPUAlphaState *env = &cpu->env; - int i = cs->exception_index; - - if (qemu_loglevel_mask(CPU_LOG_INT)) { - static int count; - const char *name = "<unknown>"; - - switch (i) { - case EXCP_RESET: - name = "reset"; - break; - case EXCP_MCHK: - name = "mchk"; - break; - case EXCP_SMP_INTERRUPT: - name = "smp_interrupt"; - break; - case EXCP_CLK_INTERRUPT: - name = "clk_interrupt"; - break; - case EXCP_DEV_INTERRUPT: - name = "dev_interrupt"; - break; - case EXCP_MMFAULT: - name = "mmfault"; - break; - case EXCP_UNALIGN: - name = "unalign"; - break; - case EXCP_OPCDEC: - name = "opcdec"; - break; - case EXCP_ARITH: - name = "arith"; - break; - case EXCP_FEN: - name = "fen"; - break; - case EXCP_CALL_PAL: - name = "call_pal"; - break; - } - qemu_log("INT %6d: %s(%#x) cpu=%d pc=%016" - PRIx64 " sp=%016" PRIx64 "\n", - ++count, name, env->error_code, cs->cpu_index, - env->pc, env->ir[IR_SP]); - } - - cs->exception_index = -1; - -#if !defined(CONFIG_USER_ONLY) - switch (i) { - case EXCP_RESET: - i = 0x0000; - break; - case EXCP_MCHK: - i = 0x0080; - break; - case EXCP_SMP_INTERRUPT: - i = 0x0100; - break; - case EXCP_CLK_INTERRUPT: - i = 0x0180; - break; - case EXCP_DEV_INTERRUPT: - i = 0x0200; - break; - case EXCP_MMFAULT: - i = 0x0280; - break; - case EXCP_UNALIGN: - i = 0x0300; - break; - case EXCP_OPCDEC: - i = 0x0380; - break; - case EXCP_ARITH: - i = 0x0400; - break; - case EXCP_FEN: - i = 0x0480; - break; - case EXCP_CALL_PAL: - i = env->error_code; - /* There are 64 entry points for both privileged and unprivileged, - with bit 0x80 indicating unprivileged. Each entry point gets - 64 bytes to do its job. */ - if (i & 0x80) { - i = 0x2000 + (i - 0x80) * 64; - } else { - i = 0x1000 + i * 64; - } - break; - default: - cpu_abort(cs, "Unhandled CPU exception"); - } - - /* Remember where the exception happened. Emulate real hardware in - that the low bit of the PC indicates PALmode. */ - env->exc_addr = env->pc | env->pal_mode; - - /* Continue execution at the PALcode entry point. */ - env->pc = env->palbr + i; - - /* Switch to PALmode. */ - env->pal_mode = 1; -#endif /* !USER_ONLY */ -} - -bool alpha_cpu_exec_interrupt(CPUState *cs, int interrupt_request) -{ - AlphaCPU *cpu = ALPHA_CPU(cs); - CPUAlphaState *env = &cpu->env; - int idx = -1; - - /* We never take interrupts while in PALmode. */ - if (env->pal_mode) { - return false; - } - - /* Fall through the switch, collecting the highest priority - interrupt that isn't masked by the processor status IPL. */ - /* ??? This hard-codes the OSF/1 interrupt levels. */ - switch (env->ps & PS_INT_MASK) { - case 0 ... 3: - if (interrupt_request & CPU_INTERRUPT_HARD) { - idx = EXCP_DEV_INTERRUPT; - } - /* FALLTHRU */ - case 4: - if (interrupt_request & CPU_INTERRUPT_TIMER) { - idx = EXCP_CLK_INTERRUPT; - } - /* FALLTHRU */ - case 5: - if (interrupt_request & CPU_INTERRUPT_SMP) { - idx = EXCP_SMP_INTERRUPT; - } - /* FALLTHRU */ - case 6: - if (interrupt_request & CPU_INTERRUPT_MCHK) { - idx = EXCP_MCHK; - } - } - if (idx >= 0) { - cs->exception_index = idx; - env->error_code = 0; - alpha_cpu_do_interrupt(cs); - return true; - } - return false; -} - -void alpha_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf, - int flags) -{ - static const char *linux_reg_names[] = { - "v0 ", "t0 ", "t1 ", "t2 ", "t3 ", "t4 ", "t5 ", "t6 ", - "t7 ", "s0 ", "s1 ", "s2 ", "s3 ", "s4 ", "s5 ", "fp ", - "a0 ", "a1 ", "a2 ", "a3 ", "a4 ", "a5 ", "t8 ", "t9 ", - "t10", "t11", "ra ", "t12", "at ", "gp ", "sp ", "zero", - }; - AlphaCPU *cpu = ALPHA_CPU(cs); - CPUAlphaState *env = &cpu->env; - int i; - - cpu_fprintf(f, " PC " TARGET_FMT_lx " PS %02x\n", - env->pc, env->ps); - for (i = 0; i < 31; i++) { - cpu_fprintf(f, "IR%02d %s " TARGET_FMT_lx " ", i, - linux_reg_names[i], cpu_alpha_load_gr(env, i)); - if ((i % 3) == 2) - cpu_fprintf(f, "\n"); - } - - cpu_fprintf(f, "lock_a " TARGET_FMT_lx " lock_v " TARGET_FMT_lx "\n", - env->lock_addr, env->lock_value); - - for (i = 0; i < 31; i++) { - cpu_fprintf(f, "FIR%02d " TARGET_FMT_lx " ", i, - *((uint64_t *)(&env->fir[i]))); - if ((i % 3) == 2) - cpu_fprintf(f, "\n"); - } - cpu_fprintf(f, "\n"); -} - -/* This should only be called from translate, via gen_excp. - We expect that ENV->PC has already been updated. */ -void QEMU_NORETURN helper_excp(CPUAlphaState *env, int excp, int error) -{ - AlphaCPU *cpu = alpha_env_get_cpu(env); - CPUState *cs = CPU(cpu); - - cs->exception_index = excp; - env->error_code = error; - cpu_loop_exit(cs); -} - -/* This may be called from any of the helpers to set up EXCEPTION_INDEX. */ -void QEMU_NORETURN dynamic_excp(CPUAlphaState *env, uintptr_t retaddr, - int excp, int error) -{ - AlphaCPU *cpu = alpha_env_get_cpu(env); - CPUState *cs = CPU(cpu); - - cs->exception_index = excp; - env->error_code = error; - if (retaddr) { - cpu_restore_state(cs, retaddr); - /* Floating-point exceptions (our only users) point to the next PC. */ - env->pc += 4; - } - cpu_loop_exit(cs); -} - -void QEMU_NORETURN arith_excp(CPUAlphaState *env, uintptr_t retaddr, - int exc, uint64_t mask) -{ - env->trap_arg0 = exc; - env->trap_arg1 = mask; - dynamic_excp(env, retaddr, EXCP_ARITH, 0); -} diff --git a/target-alpha/helper.h b/target-alpha/helper.h deleted file mode 100644 index 004221d..0000000 --- a/target-alpha/helper.h +++ /dev/null @@ -1,104 +0,0 @@ -DEF_HELPER_3(excp, noreturn, env, int, int) -DEF_HELPER_FLAGS_1(load_pcc, TCG_CALL_NO_RWG_SE, i64, env) - -DEF_HELPER_FLAGS_3(check_overflow, TCG_CALL_NO_WG, void, env, i64, i64) - -DEF_HELPER_FLAGS_1(ctpop, TCG_CALL_NO_RWG_SE, i64, i64) -DEF_HELPER_FLAGS_1(ctlz, TCG_CALL_NO_RWG_SE, i64, i64) -DEF_HELPER_FLAGS_1(cttz, TCG_CALL_NO_RWG_SE, i64, i64) - -DEF_HELPER_FLAGS_2(zap, TCG_CALL_NO_RWG_SE, i64, i64, i64) -DEF_HELPER_FLAGS_2(zapnot, TCG_CALL_NO_RWG_SE, i64, i64, i64) - -DEF_HELPER_FLAGS_1(cmpbe0, TCG_CALL_NO_RWG_SE, i64, i64) -DEF_HELPER_FLAGS_2(cmpbge, TCG_CALL_NO_RWG_SE, i64, i64, i64) - -DEF_HELPER_FLAGS_2(minub8, TCG_CALL_NO_RWG_SE, i64, i64, i64) -DEF_HELPER_FLAGS_2(minsb8, TCG_CALL_NO_RWG_SE, i64, i64, i64) -DEF_HELPER_FLAGS_2(minuw4, TCG_CALL_NO_RWG_SE, i64, i64, i64) -DEF_HELPER_FLAGS_2(minsw4, TCG_CALL_NO_RWG_SE, i64, i64, i64) -DEF_HELPER_FLAGS_2(maxub8, TCG_CALL_NO_RWG_SE, i64, i64, i64) -DEF_HELPER_FLAGS_2(maxsb8, TCG_CALL_NO_RWG_SE, i64, i64, i64) -DEF_HELPER_FLAGS_2(maxuw4, TCG_CALL_NO_RWG_SE, i64, i64, i64) -DEF_HELPER_FLAGS_2(maxsw4, TCG_CALL_NO_RWG_SE, i64, i64, i64) -DEF_HELPER_FLAGS_2(perr, TCG_CALL_NO_RWG_SE, i64, i64, i64) -DEF_HELPER_FLAGS_1(pklb, TCG_CALL_NO_RWG_SE, i64, i64) -DEF_HELPER_FLAGS_1(pkwb, TCG_CALL_NO_RWG_SE, i64, i64) -DEF_HELPER_FLAGS_1(unpkbl, TCG_CALL_NO_RWG_SE, i64, i64) -DEF_HELPER_FLAGS_1(unpkbw, TCG_CALL_NO_RWG_SE, i64, i64) - -DEF_HELPER_FLAGS_1(load_fpcr, TCG_CALL_NO_RWG_SE, i64, env) -DEF_HELPER_FLAGS_2(store_fpcr, TCG_CALL_NO_RWG, void, env, i64) - -DEF_HELPER_FLAGS_1(f_to_memory, TCG_CALL_NO_RWG_SE, i32, i64) -DEF_HELPER_FLAGS_1(memory_to_f, TCG_CALL_NO_RWG_SE, i64, i32) -DEF_HELPER_FLAGS_3(addf, TCG_CALL_NO_RWG, i64, env, i64, i64) -DEF_HELPER_FLAGS_3(subf, TCG_CALL_NO_RWG, i64, env, i64, i64) -DEF_HELPER_FLAGS_3(mulf, TCG_CALL_NO_RWG, i64, env, i64, i64) -DEF_HELPER_FLAGS_3(divf, TCG_CALL_NO_RWG, i64, env, i64, i64) -DEF_HELPER_FLAGS_2(sqrtf, TCG_CALL_NO_RWG, i64, env, i64) - -DEF_HELPER_FLAGS_1(g_to_memory, TCG_CALL_NO_RWG_SE, i64, i64) -DEF_HELPER_FLAGS_1(memory_to_g, TCG_CALL_NO_RWG_SE, i64, i64) -DEF_HELPER_FLAGS_3(addg, TCG_CALL_NO_RWG, i64, env, i64, i64) -DEF_HELPER_FLAGS_3(subg, TCG_CALL_NO_RWG, i64, env, i64, i64) -DEF_HELPER_FLAGS_3(mulg, TCG_CALL_NO_RWG, i64, env, i64, i64) -DEF_HELPER_FLAGS_3(divg, TCG_CALL_NO_RWG, i64, env, i64, i64) -DEF_HELPER_FLAGS_2(sqrtg, TCG_CALL_NO_RWG, i64, env, i64) - -DEF_HELPER_FLAGS_1(s_to_memory, TCG_CALL_NO_RWG_SE, i32, i64) -DEF_HELPER_FLAGS_1(memory_to_s, TCG_CALL_NO_RWG_SE, i64, i32) -DEF_HELPER_FLAGS_3(adds, TCG_CALL_NO_RWG, i64, env, i64, i64) -DEF_HELPER_FLAGS_3(subs, TCG_CALL_NO_RWG, i64, env, i64, i64) -DEF_HELPER_FLAGS_3(muls, TCG_CALL_NO_RWG, i64, env, i64, i64) -DEF_HELPER_FLAGS_3(divs, TCG_CALL_NO_RWG, i64, env, i64, i64) -DEF_HELPER_FLAGS_2(sqrts, TCG_CALL_NO_RWG, i64, env, i64) - -DEF_HELPER_FLAGS_3(addt, TCG_CALL_NO_RWG, i64, env, i64, i64) -DEF_HELPER_FLAGS_3(subt, TCG_CALL_NO_RWG, i64, env, i64, i64) -DEF_HELPER_FLAGS_3(mult, TCG_CALL_NO_RWG, i64, env, i64, i64) -DEF_HELPER_FLAGS_3(divt, TCG_CALL_NO_RWG, i64, env, i64, i64) -DEF_HELPER_FLAGS_2(sqrtt, TCG_CALL_NO_RWG, i64, env, i64) - -DEF_HELPER_FLAGS_3(cmptun, TCG_CALL_NO_RWG, i64, env, i64, i64) -DEF_HELPER_FLAGS_3(cmpteq, TCG_CALL_NO_RWG, i64, env, i64, i64) -DEF_HELPER_FLAGS_3(cmptle, TCG_CALL_NO_RWG, i64, env, i64, i64) -DEF_HELPER_FLAGS_3(cmptlt, TCG_CALL_NO_RWG, i64, env, i64, i64) -DEF_HELPER_FLAGS_3(cmpgeq, TCG_CALL_NO_RWG, i64, env, i64, i64) -DEF_HELPER_FLAGS_3(cmpgle, TCG_CALL_NO_RWG, i64, env, i64, i64) -DEF_HELPER_FLAGS_3(cmpglt, TCG_CALL_NO_RWG, i64, env, i64, i64) - -DEF_HELPER_FLAGS_2(cvtts, TCG_CALL_NO_RWG, i64, env, i64) -DEF_HELPER_FLAGS_2(cvtst, TCG_CALL_NO_RWG, i64, env, i64) -DEF_HELPER_FLAGS_2(cvtqs, TCG_CALL_NO_RWG, i64, env, i64) -DEF_HELPER_FLAGS_2(cvtqt, TCG_CALL_NO_RWG, i64, env, i64) -DEF_HELPER_FLAGS_2(cvtqf, TCG_CALL_NO_RWG, i64, env, i64) -DEF_HELPER_FLAGS_2(cvtgf, TCG_CALL_NO_RWG, i64, env, i64) -DEF_HELPER_FLAGS_2(cvtgq, TCG_CALL_NO_RWG, i64, env, i64) -DEF_HELPER_FLAGS_2(cvtqg, TCG_CALL_NO_RWG, i64, env, i64) - -DEF_HELPER_FLAGS_2(cvttq, TCG_CALL_NO_RWG, i64, env, i64) -DEF_HELPER_FLAGS_2(cvttq_c, TCG_CALL_NO_RWG, i64, env, i64) - -DEF_HELPER_FLAGS_2(cvtql, TCG_CALL_NO_RWG, i64, env, i64) - -DEF_HELPER_FLAGS_2(setroundmode, TCG_CALL_NO_RWG, void, env, i32) -DEF_HELPER_FLAGS_2(setflushzero, TCG_CALL_NO_RWG, void, env, i32) -DEF_HELPER_FLAGS_3(fp_exc_raise, TCG_CALL_NO_WG, void, env, i32, i32) -DEF_HELPER_FLAGS_3(fp_exc_raise_s, TCG_CALL_NO_WG, void, env, i32, i32) - -DEF_HELPER_FLAGS_2(ieee_input, TCG_CALL_NO_WG, void, env, i64) -DEF_HELPER_FLAGS_2(ieee_input_cmp, TCG_CALL_NO_WG, void, env, i64) -DEF_HELPER_FLAGS_2(ieee_input_s, TCG_CALL_NO_WG, void, env, i64) - -#if !defined (CONFIG_USER_ONLY) -DEF_HELPER_FLAGS_1(tbia, TCG_CALL_NO_RWG, void, env) -DEF_HELPER_FLAGS_2(tbis, TCG_CALL_NO_RWG, void, env, i64) -DEF_HELPER_FLAGS_1(tb_flush, TCG_CALL_NO_RWG, void, env) - -DEF_HELPER_1(halt, void, i64) - -DEF_HELPER_FLAGS_0(get_vmtime, TCG_CALL_NO_RWG, i64) -DEF_HELPER_FLAGS_0(get_walltime, TCG_CALL_NO_RWG, i64) -DEF_HELPER_FLAGS_2(set_alarm, TCG_CALL_NO_RWG, void, env, i64) -#endif diff --git a/target-alpha/int_helper.c b/target-alpha/int_helper.c deleted file mode 100644 index 19bebfe..0000000 --- a/target-alpha/int_helper.c +++ /dev/null @@ -1,280 +0,0 @@ -/* - * Helpers for integer and multimedia instructions. - * - * Copyright (c) 2007 Jocelyn Mayer - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/>. - */ - -#include "qemu/osdep.h" -#include "cpu.h" -#include "exec/exec-all.h" -#include "exec/helper-proto.h" -#include "qemu/host-utils.h" - - -uint64_t helper_ctpop(uint64_t arg) -{ - return ctpop64(arg); -} - -uint64_t helper_ctlz(uint64_t arg) -{ - return clz64(arg); -} - -uint64_t helper_cttz(uint64_t arg) -{ - return ctz64(arg); -} - -uint64_t helper_zapnot(uint64_t val, uint64_t mskb) -{ - uint64_t mask; - - mask = -(mskb & 0x01) & 0x00000000000000ffull; - mask |= -(mskb & 0x02) & 0x000000000000ff00ull; - mask |= -(mskb & 0x04) & 0x0000000000ff0000ull; - mask |= -(mskb & 0x08) & 0x00000000ff000000ull; - mask |= -(mskb & 0x10) & 0x000000ff00000000ull; - mask |= -(mskb & 0x20) & 0x0000ff0000000000ull; - mask |= -(mskb & 0x40) & 0x00ff000000000000ull; - mask |= -(mskb & 0x80) & 0xff00000000000000ull; - - return val & mask; -} - -uint64_t helper_zap(uint64_t val, uint64_t mask) -{ - return helper_zapnot(val, ~mask); -} - -uint64_t helper_cmpbe0(uint64_t a) -{ - uint64_t m = 0x7f7f7f7f7f7f7f7fULL; - uint64_t c = ~(((a & m) + m) | a | m); - /* a.......b.......c.......d.......e.......f.......g.......h....... */ - c |= c << 7; - /* ab......bc......cd......de......ef......fg......gh......h....... */ - c |= c << 14; - /* abcd....bcde....cdef....defg....efgh....fgh.....gh......h....... */ - c |= c << 28; - /* abcdefghbcdefgh.cdefgh..defgh...efgh....fgh.....gh......h....... */ - return c >> 56; -} - -uint64_t helper_cmpbge(uint64_t a, uint64_t b) -{ - uint64_t mask = 0x00ff00ff00ff00ffULL; - uint64_t test = 0x0100010001000100ULL; - uint64_t al, ah, bl, bh, cl, ch; - - /* Separate the bytes to avoid false positives. */ - al = a & mask; - bl = b & mask; - ah = (a >> 8) & mask; - bh = (b >> 8) & mask; - - /* "Compare". If a byte in B is greater than a byte in A, - it will clear the test bit. */ - cl = ((al | test) - bl) & test; - ch = ((ah | test) - bh) & test; - - /* Fold all of the test bits into a contiguous set. */ - /* ch=.......a...............c...............e...............g........ */ - /* cl=.......b...............d...............f...............h........ */ - cl += ch << 1; - /* cl=......ab..............cd..............ef..............gh........ */ - cl |= cl << 14; - /* cl=......abcd............cdef............efgh............gh........ */ - cl |= cl << 28; - /* cl=......abcdefgh........cdefgh..........efgh............gh........ */ - return cl >> 50; -} - -uint64_t helper_minub8(uint64_t op1, uint64_t op2) -{ - uint64_t res = 0; - uint8_t opa, opb, opr; - int i; - - for (i = 0; i < 8; ++i) { - opa = op1 >> (i * 8); - opb = op2 >> (i * 8); - opr = opa < opb ? opa : opb; - res |= (uint64_t)opr << (i * 8); - } - return res; -} - -uint64_t helper_minsb8(uint64_t op1, uint64_t op2) -{ - uint64_t res = 0; - int8_t opa, opb; - uint8_t opr; - int i; - - for (i = 0; i < 8; ++i) { - opa = op1 >> (i * 8); - opb = op2 >> (i * 8); - opr = opa < opb ? opa : opb; - res |= (uint64_t)opr << (i * 8); - } - return res; -} - -uint64_t helper_minuw4(uint64_t op1, uint64_t op2) -{ - uint64_t res = 0; - uint16_t opa, opb, opr; - int i; - - for (i = 0; i < 4; ++i) { - opa = op1 >> (i * 16); - opb = op2 >> (i * 16); - opr = opa < opb ? opa : opb; - res |= (uint64_t)opr << (i * 16); - } - return res; -} - -uint64_t helper_minsw4(uint64_t op1, uint64_t op2) -{ - uint64_t res = 0; - int16_t opa, opb; - uint16_t opr; - int i; - - for (i = 0; i < 4; ++i) { - opa = op1 >> (i * 16); - opb = op2 >> (i * 16); - opr = opa < opb ? opa : opb; - res |= (uint64_t)opr << (i * 16); - } - return res; -} - -uint64_t helper_maxub8(uint64_t op1, uint64_t op2) -{ - uint64_t res = 0; - uint8_t opa, opb, opr; - int i; - - for (i = 0; i < 8; ++i) { - opa = op1 >> (i * 8); - opb = op2 >> (i * 8); - opr = opa > opb ? opa : opb; - res |= (uint64_t)opr << (i * 8); - } - return res; -} - -uint64_t helper_maxsb8(uint64_t op1, uint64_t op2) -{ - uint64_t res = 0; - int8_t opa, opb; - uint8_t opr; - int i; - - for (i = 0; i < 8; ++i) { - opa = op1 >> (i * 8); - opb = op2 >> (i * 8); - opr = opa > opb ? opa : opb; - res |= (uint64_t)opr << (i * 8); - } - return res; -} - -uint64_t helper_maxuw4(uint64_t op1, uint64_t op2) -{ - uint64_t res = 0; - uint16_t opa, opb, opr; - int i; - - for (i = 0; i < 4; ++i) { - opa = op1 >> (i * 16); - opb = op2 >> (i * 16); - opr = opa > opb ? opa : opb; - res |= (uint64_t)opr << (i * 16); - } - return res; -} - -uint64_t helper_maxsw4(uint64_t op1, uint64_t op2) -{ - uint64_t res = 0; - int16_t opa, opb; - uint16_t opr; - int i; - - for (i = 0; i < 4; ++i) { - opa = op1 >> (i * 16); - opb = op2 >> (i * 16); - opr = opa > opb ? opa : opb; - res |= (uint64_t)opr << (i * 16); - } - return res; -} - -uint64_t helper_perr(uint64_t op1, uint64_t op2) -{ - uint64_t res = 0; - uint8_t opa, opb, opr; - int i; - - for (i = 0; i < 8; ++i) { - opa = op1 >> (i * 8); - opb = op2 >> (i * 8); - if (opa >= opb) { - opr = opa - opb; - } else { - opr = opb - opa; - } - res += opr; - } - return res; -} - -uint64_t helper_pklb(uint64_t op1) -{ - return (op1 & 0xff) | ((op1 >> 24) & 0xff00); -} - -uint64_t helper_pkwb(uint64_t op1) -{ - return ((op1 & 0xff) - | ((op1 >> 8) & 0xff00) - | ((op1 >> 16) & 0xff0000) - | ((op1 >> 24) & 0xff000000)); -} - -uint64_t helper_unpkbl(uint64_t op1) -{ - return (op1 & 0xff) | ((op1 & 0xff00) << 24); -} - -uint64_t helper_unpkbw(uint64_t op1) -{ - return ((op1 & 0xff) - | ((op1 & 0xff00) << 8) - | ((op1 & 0xff0000) << 16) - | ((op1 & 0xff000000) << 24)); -} - -void helper_check_overflow(CPUAlphaState *env, uint64_t op1, uint64_t op2) -{ - if (unlikely(op1 != op2)) { - arith_excp(env, GETPC(), EXC_M_IOV, 0); - } -} diff --git a/target-alpha/machine.c b/target-alpha/machine.c deleted file mode 100644 index b99a123..0000000 --- a/target-alpha/machine.c +++ /dev/null @@ -1,91 +0,0 @@ -#include "qemu/osdep.h" -#include "qemu-common.h" -#include "cpu.h" -#include "hw/hw.h" -#include "hw/boards.h" -#include "migration/cpu.h" - -static int get_fpcr(QEMUFile *f, void *opaque, size_t size) -{ - CPUAlphaState *env = opaque; - cpu_alpha_store_fpcr(env, qemu_get_be64(f)); - return 0; -} - -static void put_fpcr(QEMUFile *f, void *opaque, size_t size) -{ - CPUAlphaState *env = opaque; - qemu_put_be64(f, cpu_alpha_load_fpcr(env)); -} - -static const VMStateInfo vmstate_fpcr = { - .name = "fpcr", - .get = get_fpcr, - .put = put_fpcr, -}; - -static VMStateField vmstate_env_fields[] = { - VMSTATE_UINTTL_ARRAY(ir, CPUAlphaState, 31), - VMSTATE_UINTTL_ARRAY(fir, CPUAlphaState, 31), - /* Save the architecture value of the fpcr, not the internally - expanded version. Since this architecture value does not - exist in memory to be stored, this requires a but of hoop - jumping. We want OFFSET=0 so that we effectively pass ENV - to the helper functions, and we need to fill in the name by - hand since there's no field of that name. */ - { - .name = "fpcr", - .version_id = 0, - .size = sizeof(uint64_t), - .info = &vmstate_fpcr, - .flags = VMS_SINGLE, - .offset = 0 - }, - VMSTATE_UINTTL(pc, CPUAlphaState), - VMSTATE_UINTTL(unique, CPUAlphaState), - VMSTATE_UINTTL(lock_addr, CPUAlphaState), - VMSTATE_UINTTL(lock_value, CPUAlphaState), - - VMSTATE_UINT8(ps, CPUAlphaState), - VMSTATE_UINT8(intr_flag, CPUAlphaState), - VMSTATE_UINT8(pal_mode, CPUAlphaState), - VMSTATE_UINT8(fen, CPUAlphaState), - - VMSTATE_UINT32(pcc_ofs, CPUAlphaState), - - VMSTATE_UINTTL(trap_arg0, CPUAlphaState), - VMSTATE_UINTTL(trap_arg1, CPUAlphaState), - VMSTATE_UINTTL(trap_arg2, CPUAlphaState), - - VMSTATE_UINTTL(exc_addr, CPUAlphaState), - VMSTATE_UINTTL(palbr, CPUAlphaState), - VMSTATE_UINTTL(ptbr, CPUAlphaState), - VMSTATE_UINTTL(vptptr, CPUAlphaState), - VMSTATE_UINTTL(sysval, CPUAlphaState), - VMSTATE_UINTTL(usp, CPUAlphaState), - - VMSTATE_UINTTL_ARRAY(shadow, CPUAlphaState, 8), - VMSTATE_UINTTL_ARRAY(scratch, CPUAlphaState, 24), - - VMSTATE_END_OF_LIST() -}; - -static const VMStateDescription vmstate_env = { - .name = "env", - .version_id = 2, - .minimum_version_id = 2, - .fields = vmstate_env_fields, -}; - -static VMStateField vmstate_cpu_fields[] = { - VMSTATE_CPU(), - VMSTATE_STRUCT(env, AlphaCPU, 1, vmstate_env, CPUAlphaState), - VMSTATE_END_OF_LIST() -}; - -const VMStateDescription vmstate_alpha_cpu = { - .name = "cpu", - .version_id = 1, - .minimum_version_id = 1, - .fields = vmstate_cpu_fields, -}; diff --git a/target-alpha/mem_helper.c b/target-alpha/mem_helper.c deleted file mode 100644 index 78a7d45..0000000 --- a/target-alpha/mem_helper.c +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Helpers for loads and stores - * - * Copyright (c) 2007 Jocelyn Mayer - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/>. - */ - -#include "qemu/osdep.h" -#include "cpu.h" -#include "exec/helper-proto.h" -#include "exec/exec-all.h" -#include "exec/cpu_ldst.h" - -/* Softmmu support */ -#ifndef CONFIG_USER_ONLY -void alpha_cpu_do_unaligned_access(CPUState *cs, vaddr addr, - MMUAccessType access_type, - int mmu_idx, uintptr_t retaddr) -{ - AlphaCPU *cpu = ALPHA_CPU(cs); - CPUAlphaState *env = &cpu->env; - uint64_t pc; - uint32_t insn; - - if (retaddr) { - cpu_restore_state(cs, retaddr); - } - - pc = env->pc; - insn = cpu_ldl_code(env, pc); - - env->trap_arg0 = addr; - env->trap_arg1 = insn >> 26; /* opcode */ - env->trap_arg2 = (insn >> 21) & 31; /* dest regno */ - cs->exception_index = EXCP_UNALIGN; - env->error_code = 0; - cpu_loop_exit(cs); -} - -void alpha_cpu_unassigned_access(CPUState *cs, hwaddr addr, - bool is_write, bool is_exec, int unused, - unsigned size) -{ - AlphaCPU *cpu = ALPHA_CPU(cs); - CPUAlphaState *env = &cpu->env; - - env->trap_arg0 = addr; - env->trap_arg1 = is_write ? 1 : 0; - cs->exception_index = EXCP_MCHK; - env->error_code = 0; - - /* ??? We should cpu_restore_state to the faulting insn, but this hook - does not have access to the retaddr value from the original helper. - It's all moot until the QEMU PALcode grows an MCHK handler. */ - - cpu_loop_exit(cs); -} - -/* try to fill the TLB and return an exception if error. If retaddr is - NULL, it means that the function was called in C code (i.e. not - from generated code or from helper.c) */ -/* XXX: fix it to restore all registers */ -void tlb_fill(CPUState *cs, target_ulong addr, MMUAccessType access_type, - int mmu_idx, uintptr_t retaddr) -{ - int ret; - - ret = alpha_cpu_handle_mmu_fault(cs, addr, access_type, mmu_idx); - if (unlikely(ret != 0)) { - if (retaddr) { - cpu_restore_state(cs, retaddr); - } - /* Exception index and error code are already set */ - cpu_loop_exit(cs); - } -} -#endif /* CONFIG_USER_ONLY */ diff --git a/target-alpha/sys_helper.c b/target-alpha/sys_helper.c deleted file mode 100644 index bec1e17..0000000 --- a/target-alpha/sys_helper.c +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Helpers for system instructions. - * - * Copyright (c) 2007 Jocelyn Mayer - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/>. - */ - -#include "qemu/osdep.h" -#include "cpu.h" -#include "exec/exec-all.h" -#include "exec/helper-proto.h" -#include "sysemu/sysemu.h" -#include "qemu/timer.h" - - -uint64_t helper_load_pcc(CPUAlphaState *env) -{ -#ifndef CONFIG_USER_ONLY - /* In system mode we have access to a decent high-resolution clock. - In order to make OS-level time accounting work with the RPCC, - present it with a well-timed clock fixed at 250MHz. */ - return (((uint64_t)env->pcc_ofs << 32) - | (uint32_t)(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) >> 2)); -#else - /* In user-mode, QEMU_CLOCK_VIRTUAL doesn't exist. Just pass through the host cpu - clock ticks. Also, don't bother taking PCC_OFS into account. */ - return (uint32_t)cpu_get_host_ticks(); -#endif -} - -/* PALcode support special instructions */ -#ifndef CONFIG_USER_ONLY -void helper_tbia(CPUAlphaState *env) -{ - tlb_flush(CPU(alpha_env_get_cpu(env)), 1); -} - -void helper_tbis(CPUAlphaState *env, uint64_t p) -{ - tlb_flush_page(CPU(alpha_env_get_cpu(env)), p); -} - -void helper_tb_flush(CPUAlphaState *env) -{ - tb_flush(CPU(alpha_env_get_cpu(env))); -} - -void helper_halt(uint64_t restart) -{ - if (restart) { - qemu_system_reset_request(); - } else { - qemu_system_shutdown_request(); - } -} - -uint64_t helper_get_vmtime(void) -{ - return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); -} - -uint64_t helper_get_walltime(void) -{ - return qemu_clock_get_ns(rtc_clock); -} - -void helper_set_alarm(CPUAlphaState *env, uint64_t expire) -{ - AlphaCPU *cpu = alpha_env_get_cpu(env); - - if (expire) { - env->alarm_expire = expire; - timer_mod(cpu->alarm_timer, expire); - } else { - timer_del(cpu->alarm_timer); - } -} - -#endif /* CONFIG_USER_ONLY */ diff --git a/target-alpha/translate.c b/target-alpha/translate.c deleted file mode 100644 index 114927b..0000000 --- a/target-alpha/translate.c +++ /dev/null @@ -1,3010 +0,0 @@ -/* - * Alpha emulation cpu translation for qemu. - * - * Copyright (c) 2007 Jocelyn Mayer - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/>. - */ - -#include "qemu/osdep.h" -#include "cpu.h" -#include "disas/disas.h" -#include "qemu/host-utils.h" -#include "exec/exec-all.h" -#include "tcg-op.h" -#include "exec/cpu_ldst.h" - -#include "exec/helper-proto.h" -#include "exec/helper-gen.h" - -#include "trace-tcg.h" -#include "exec/log.h" - - -#undef ALPHA_DEBUG_DISAS -#define CONFIG_SOFTFLOAT_INLINE - -#ifdef ALPHA_DEBUG_DISAS -# define LOG_DISAS(...) qemu_log_mask(CPU_LOG_TB_IN_ASM, ## __VA_ARGS__) -#else -# define LOG_DISAS(...) do { } while (0) -#endif - -typedef struct DisasContext DisasContext; -struct DisasContext { - struct TranslationBlock *tb; - uint64_t pc; -#ifndef CONFIG_USER_ONLY - uint64_t palbr; -#endif - int mem_idx; - - /* Current rounding mode for this TB. */ - int tb_rm; - /* Current flush-to-zero setting for this TB. */ - int tb_ftz; - - /* implver value for this CPU. */ - int implver; - - /* The set of registers active in the current context. */ - TCGv *ir; - - /* Temporaries for $31 and $f31 as source and destination. */ - TCGv zero; - TCGv sink; - /* Temporary for immediate constants. */ - TCGv lit; - - bool singlestep_enabled; -}; - -/* Return values from translate_one, indicating the state of the TB. - Note that zero indicates that we are not exiting the TB. */ - -typedef enum { - NO_EXIT, - - /* We have emitted one or more goto_tb. No fixup required. */ - EXIT_GOTO_TB, - - /* We are not using a goto_tb (for whatever reason), but have updated - the PC (for whatever reason), so there's no need to do it again on - exiting the TB. */ - EXIT_PC_UPDATED, - - /* We are exiting the TB, but have neither emitted a goto_tb, nor - updated the PC for the next instruction to be executed. */ - EXIT_PC_STALE, - - /* We are ending the TB with a noreturn function call, e.g. longjmp. - No following code will be executed. */ - EXIT_NORETURN, -} ExitStatus; - -/* global register indexes */ -static TCGv_env cpu_env; -static TCGv cpu_std_ir[31]; -static TCGv cpu_fir[31]; -static TCGv cpu_pc; -static TCGv cpu_lock_addr; -static TCGv cpu_lock_value; - -#ifndef CONFIG_USER_ONLY -static TCGv cpu_pal_ir[31]; -#endif - -#include "exec/gen-icount.h" - -void alpha_translate_init(void) -{ -#define DEF_VAR(V) { &cpu_##V, #V, offsetof(CPUAlphaState, V) } - - typedef struct { TCGv *var; const char *name; int ofs; } GlobalVar; - static const GlobalVar vars[] = { - DEF_VAR(pc), - DEF_VAR(lock_addr), - DEF_VAR(lock_value), - }; - -#undef DEF_VAR - - /* Use the symbolic register names that match the disassembler. */ - static const char greg_names[31][4] = { - "v0", "t0", "t1", "t2", "t3", "t4", "t5", "t6", - "t7", "s0", "s1", "s2", "s3", "s4", "s5", "fp", - "a0", "a1", "a2", "a3", "a4", "a5", "t8", "t9", - "t10", "t11", "ra", "t12", "at", "gp", "sp" - }; - static const char freg_names[31][4] = { - "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", - "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", - "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", - "f24", "f25", "f26", "f27", "f28", "f29", "f30" - }; -#ifndef CONFIG_USER_ONLY - static const char shadow_names[8][8] = { - "pal_t7", "pal_s0", "pal_s1", "pal_s2", - "pal_s3", "pal_s4", "pal_s5", "pal_t11" - }; -#endif - - static bool done_init = 0; - int i; - - if (done_init) { - return; - } - done_init = 1; - - cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env"); - tcg_ctx.tcg_env = cpu_env; - - for (i = 0; i < 31; i++) { - cpu_std_ir[i] = tcg_global_mem_new_i64(cpu_env, - offsetof(CPUAlphaState, ir[i]), - greg_names[i]); - } - - for (i = 0; i < 31; i++) { - cpu_fir[i] = tcg_global_mem_new_i64(cpu_env, - offsetof(CPUAlphaState, fir[i]), - freg_names[i]); - } - -#ifndef CONFIG_USER_ONLY - memcpy(cpu_pal_ir, cpu_std_ir, sizeof(cpu_pal_ir)); - for (i = 0; i < 8; i++) { - int r = (i == 7 ? 25 : i + 8); - cpu_pal_ir[r] = tcg_global_mem_new_i64(cpu_env, - offsetof(CPUAlphaState, - shadow[i]), - shadow_names[i]); - } -#endif - - for (i = 0; i < ARRAY_SIZE(vars); ++i) { - const GlobalVar *v = &vars[i]; - *v->var = tcg_global_mem_new_i64(cpu_env, v->ofs, v->name); - } -} - -static TCGv load_zero(DisasContext *ctx) -{ - if (TCGV_IS_UNUSED_I64(ctx->zero)) { - ctx->zero = tcg_const_i64(0); - } - return ctx->zero; -} - -static TCGv dest_sink(DisasContext *ctx) -{ - if (TCGV_IS_UNUSED_I64(ctx->sink)) { - ctx->sink = tcg_temp_new(); - } - return ctx->sink; -} - -static void free_context_temps(DisasContext *ctx) -{ - if (!TCGV_IS_UNUSED_I64(ctx->sink)) { - tcg_gen_discard_i64(ctx->sink); - tcg_temp_free(ctx->sink); - TCGV_UNUSED_I64(ctx->sink); - } - if (!TCGV_IS_UNUSED_I64(ctx->zero)) { - tcg_temp_free(ctx->zero); - TCGV_UNUSED_I64(ctx->zero); - } - if (!TCGV_IS_UNUSED_I64(ctx->lit)) { - tcg_temp_free(ctx->lit); - TCGV_UNUSED_I64(ctx->lit); - } -} - -static TCGv load_gpr(DisasContext *ctx, unsigned reg) -{ - if (likely(reg < 31)) { - return ctx->ir[reg]; - } else { - return load_zero(ctx); - } -} - -static TCGv load_gpr_lit(DisasContext *ctx, unsigned reg, - uint8_t lit, bool islit) -{ - if (islit) { - ctx->lit = tcg_const_i64(lit); - return ctx->lit; - } else if (likely(reg < 31)) { - return ctx->ir[reg]; - } else { - return load_zero(ctx); - } -} - -static TCGv dest_gpr(DisasContext *ctx, unsigned reg) -{ - if (likely(reg < 31)) { - return ctx->ir[reg]; - } else { - return dest_sink(ctx); - } -} - -static TCGv load_fpr(DisasContext *ctx, unsigned reg) -{ - if (likely(reg < 31)) { - return cpu_fir[reg]; - } else { - return load_zero(ctx); - } -} - -static TCGv dest_fpr(DisasContext *ctx, unsigned reg) -{ - if (likely(reg < 31)) { - return cpu_fir[reg]; - } else { - return dest_sink(ctx); - } -} - -static void gen_excp_1(int exception, int error_code) -{ - TCGv_i32 tmp1, tmp2; - - tmp1 = tcg_const_i32(exception); - tmp2 = tcg_const_i32(error_code); - gen_helper_excp(cpu_env, tmp1, tmp2); - tcg_temp_free_i32(tmp2); - tcg_temp_free_i32(tmp1); -} - -static ExitStatus gen_excp(DisasContext *ctx, int exception, int error_code) -{ - tcg_gen_movi_i64(cpu_pc, ctx->pc); - gen_excp_1(exception, error_code); - return EXIT_NORETURN; -} - -static inline ExitStatus gen_invalid(DisasContext *ctx) -{ - return gen_excp(ctx, EXCP_OPCDEC, 0); -} - -static inline void gen_qemu_ldf(TCGv t0, TCGv t1, int flags) -{ - TCGv_i32 tmp32 = tcg_temp_new_i32(); - tcg_gen_qemu_ld_i32(tmp32, t1, flags, MO_LEUL); - gen_helper_memory_to_f(t0, tmp32); - tcg_temp_free_i32(tmp32); -} - -static inline void gen_qemu_ldg(TCGv t0, TCGv t1, int flags) -{ - TCGv tmp = tcg_temp_new(); - tcg_gen_qemu_ld_i64(tmp, t1, flags, MO_LEQ); - gen_helper_memory_to_g(t0, tmp); - tcg_temp_free(tmp); -} - -static inline void gen_qemu_lds(TCGv t0, TCGv t1, int flags) -{ - TCGv_i32 tmp32 = tcg_temp_new_i32(); - tcg_gen_qemu_ld_i32(tmp32, t1, flags, MO_LEUL); - gen_helper_memory_to_s(t0, tmp32); - tcg_temp_free_i32(tmp32); -} - -static inline void gen_qemu_ldl_l(TCGv t0, TCGv t1, int flags) -{ - tcg_gen_qemu_ld_i64(t0, t1, flags, MO_LESL); - tcg_gen_mov_i64(cpu_lock_addr, t1); - tcg_gen_mov_i64(cpu_lock_value, t0); -} - -static inline void gen_qemu_ldq_l(TCGv t0, TCGv t1, int flags) -{ - tcg_gen_qemu_ld_i64(t0, t1, flags, MO_LEQ); - tcg_gen_mov_i64(cpu_lock_addr, t1); - tcg_gen_mov_i64(cpu_lock_value, t0); -} - -static inline void gen_load_mem(DisasContext *ctx, - void (*tcg_gen_qemu_load)(TCGv t0, TCGv t1, - int flags), - int ra, int rb, int32_t disp16, bool fp, - bool clear) -{ - TCGv tmp, addr, va; - - /* LDQ_U with ra $31 is UNOP. Other various loads are forms of - prefetches, which we can treat as nops. No worries about - missed exceptions here. */ - if (unlikely(ra == 31)) { - return; - } - - tmp = tcg_temp_new(); - addr = load_gpr(ctx, rb); - - if (disp16) { - tcg_gen_addi_i64(tmp, addr, disp16); - addr = tmp; - } - if (clear) { - tcg_gen_andi_i64(tmp, addr, ~0x7); - addr = tmp; - } - - va = (fp ? cpu_fir[ra] : ctx->ir[ra]); - tcg_gen_qemu_load(va, addr, ctx->mem_idx); - - tcg_temp_free(tmp); -} - -static inline void gen_qemu_stf(TCGv t0, TCGv t1, int flags) -{ - TCGv_i32 tmp32 = tcg_temp_new_i32(); - gen_helper_f_to_memory(tmp32, t0); - tcg_gen_qemu_st_i32(tmp32, t1, flags, MO_LEUL); - tcg_temp_free_i32(tmp32); -} - -static inline void gen_qemu_stg(TCGv t0, TCGv t1, int flags) -{ - TCGv tmp = tcg_temp_new(); - gen_helper_g_to_memory(tmp, t0); - tcg_gen_qemu_st_i64(tmp, t1, flags, MO_LEQ); - tcg_temp_free(tmp); -} - -static inline void gen_qemu_sts(TCGv t0, TCGv t1, int flags) -{ - TCGv_i32 tmp32 = tcg_temp_new_i32(); - gen_helper_s_to_memory(tmp32, t0); - tcg_gen_qemu_st_i32(tmp32, t1, flags, MO_LEUL); - tcg_temp_free_i32(tmp32); -} - -static inline void gen_store_mem(DisasContext *ctx, - void (*tcg_gen_qemu_store)(TCGv t0, TCGv t1, - int flags), - int ra, int rb, int32_t disp16, bool fp, - bool clear) -{ - TCGv tmp, addr, va; - - tmp = tcg_temp_new(); - addr = load_gpr(ctx, rb); - - if (disp16) { - tcg_gen_addi_i64(tmp, addr, disp16); - addr = tmp; - } - if (clear) { - tcg_gen_andi_i64(tmp, addr, ~0x7); - addr = tmp; - } - - va = (fp ? load_fpr(ctx, ra) : load_gpr(ctx, ra)); - tcg_gen_qemu_store(va, addr, ctx->mem_idx); - - tcg_temp_free(tmp); -} - -static ExitStatus gen_store_conditional(DisasContext *ctx, int ra, int rb, - int32_t disp16, int mem_idx, - TCGMemOp op) -{ - TCGLabel *lab_fail, *lab_done; - TCGv addr, val; - - addr = tcg_temp_new_i64(); - tcg_gen_addi_i64(addr, load_gpr(ctx, rb), disp16); - free_context_temps(ctx); - - lab_fail = gen_new_label(); - lab_done = gen_new_label(); - tcg_gen_brcond_i64(TCG_COND_NE, addr, cpu_lock_addr, lab_fail); - tcg_temp_free_i64(addr); - - val = tcg_temp_new_i64(); - tcg_gen_atomic_cmpxchg_i64(val, cpu_lock_addr, cpu_lock_value, - load_gpr(ctx, ra), mem_idx, op); - free_context_temps(ctx); - - if (ra != 31) { - tcg_gen_setcond_i64(TCG_COND_EQ, ctx->ir[ra], val, cpu_lock_value); - } - tcg_temp_free_i64(val); - tcg_gen_br(lab_done); - - gen_set_label(lab_fail); - if (ra != 31) { - tcg_gen_movi_i64(ctx->ir[ra], 0); - } - - gen_set_label(lab_done); - tcg_gen_movi_i64(cpu_lock_addr, -1); - return NO_EXIT; -} - -static bool in_superpage(DisasContext *ctx, int64_t addr) -{ -#ifndef CONFIG_USER_ONLY - return ((ctx->tb->flags & TB_FLAGS_USER_MODE) == 0 - && addr >> TARGET_VIRT_ADDR_SPACE_BITS == -1 - && ((addr >> 41) & 3) == 2); -#else - return false; -#endif -} - -static bool use_goto_tb(DisasContext *ctx, uint64_t dest) -{ - /* Suppress goto_tb in the case of single-steping and IO. */ - if ((ctx->tb->cflags & CF_LAST_IO) - || ctx->singlestep_enabled || singlestep) { - return false; - } -#ifndef CONFIG_USER_ONLY - /* If the destination is in the superpage, the page perms can't change. */ - if (in_superpage(ctx, dest)) { - return true; - } - /* Check for the dest on the same page as the start of the TB. */ - return ((ctx->tb->pc ^ dest) & TARGET_PAGE_MASK) == 0; -#else - return true; -#endif -} - -static ExitStatus gen_bdirect(DisasContext *ctx, int ra, int32_t disp) -{ - uint64_t dest = ctx->pc + (disp << 2); - - if (ra != 31) { - tcg_gen_movi_i64(ctx->ir[ra], ctx->pc); - } - - /* Notice branch-to-next; used to initialize RA with the PC. */ - if (disp == 0) { - return 0; - } else if (use_goto_tb(ctx, dest)) { - tcg_gen_goto_tb(0); - tcg_gen_movi_i64(cpu_pc, dest); - tcg_gen_exit_tb((uintptr_t)ctx->tb); - return EXIT_GOTO_TB; - } else { - tcg_gen_movi_i64(cpu_pc, dest); - return EXIT_PC_UPDATED; - } -} - -static ExitStatus gen_bcond_internal(DisasContext *ctx, TCGCond cond, - TCGv cmp, int32_t disp) -{ - uint64_t dest = ctx->pc + (disp << 2); - TCGLabel *lab_true = gen_new_label(); - - if (use_goto_tb(ctx, dest)) { - tcg_gen_brcondi_i64(cond, cmp, 0, lab_true); - - tcg_gen_goto_tb(0); - tcg_gen_movi_i64(cpu_pc, ctx->pc); - tcg_gen_exit_tb((uintptr_t)ctx->tb); - - gen_set_label(lab_true); - tcg_gen_goto_tb(1); - tcg_gen_movi_i64(cpu_pc, dest); - tcg_gen_exit_tb((uintptr_t)ctx->tb + 1); - - return EXIT_GOTO_TB; - } else { - TCGv_i64 z = tcg_const_i64(0); - TCGv_i64 d = tcg_const_i64(dest); - TCGv_i64 p = tcg_const_i64(ctx->pc); - - tcg_gen_movcond_i64(cond, cpu_pc, cmp, z, d, p); - - tcg_temp_free_i64(z); - tcg_temp_free_i64(d); - tcg_temp_free_i64(p); - return EXIT_PC_UPDATED; - } -} - -static ExitStatus gen_bcond(DisasContext *ctx, TCGCond cond, int ra, - int32_t disp, int mask) -{ - TCGv cmp_tmp; - - if (mask) { - cmp_tmp = tcg_temp_new(); - tcg_gen_andi_i64(cmp_tmp, load_gpr(ctx, ra), 1); - } else { - cmp_tmp = load_gpr(ctx, ra); - } - - return gen_bcond_internal(ctx, cond, cmp_tmp, disp); -} - -/* Fold -0.0 for comparison with COND. */ - -static void gen_fold_mzero(TCGCond cond, TCGv dest, TCGv src) -{ - uint64_t mzero = 1ull << 63; - - switch (cond) { - case TCG_COND_LE: - case TCG_COND_GT: - /* For <= or >, the -0.0 value directly compares the way we want. */ - tcg_gen_mov_i64(dest, src); - break; - - case TCG_COND_EQ: - case TCG_COND_NE: - /* For == or !=, we can simply mask off the sign bit and compare. */ - tcg_gen_andi_i64(dest, src, mzero - 1); - break; - - case TCG_COND_GE: - case TCG_COND_LT: - /* For >= or <, map -0.0 to +0.0 via comparison and mask. */ - tcg_gen_setcondi_i64(TCG_COND_NE, dest, src, mzero); - tcg_gen_neg_i64(dest, dest); - tcg_gen_and_i64(dest, dest, src); - break; - - default: - abort(); - } -} - -static ExitStatus gen_fbcond(DisasContext *ctx, TCGCond cond, int ra, - int32_t disp) -{ - TCGv cmp_tmp = tcg_temp_new(); - gen_fold_mzero(cond, cmp_tmp, load_fpr(ctx, ra)); - return gen_bcond_internal(ctx, cond, cmp_tmp, disp); -} - -static void gen_fcmov(DisasContext *ctx, TCGCond cond, int ra, int rb, int rc) -{ - TCGv_i64 va, vb, z; - - z = load_zero(ctx); - vb = load_fpr(ctx, rb); - va = tcg_temp_new(); - gen_fold_mzero(cond, va, load_fpr(ctx, ra)); - - tcg_gen_movcond_i64(cond, dest_fpr(ctx, rc), va, z, vb, load_fpr(ctx, rc)); - - tcg_temp_free(va); -} - -#define QUAL_RM_N 0x080 /* Round mode nearest even */ -#define QUAL_RM_C 0x000 /* Round mode chopped */ -#define QUAL_RM_M 0x040 /* Round mode minus infinity */ -#define QUAL_RM_D 0x0c0 /* Round mode dynamic */ -#define QUAL_RM_MASK 0x0c0 - -#define QUAL_U 0x100 /* Underflow enable (fp output) */ -#define QUAL_V 0x100 /* Overflow enable (int output) */ -#define QUAL_S 0x400 /* Software completion enable */ -#define QUAL_I 0x200 /* Inexact detection enable */ - -static void gen_qual_roundmode(DisasContext *ctx, int fn11) -{ - TCGv_i32 tmp; - - fn11 &= QUAL_RM_MASK; - if (fn11 == ctx->tb_rm) { - return; - } - ctx->tb_rm = fn11; - - tmp = tcg_temp_new_i32(); - switch (fn11) { - case QUAL_RM_N: - tcg_gen_movi_i32(tmp, float_round_nearest_even); - break; - case QUAL_RM_C: - tcg_gen_movi_i32(tmp, float_round_to_zero); - break; - case QUAL_RM_M: - tcg_gen_movi_i32(tmp, float_round_down); - break; - case QUAL_RM_D: - tcg_gen_ld8u_i32(tmp, cpu_env, - offsetof(CPUAlphaState, fpcr_dyn_round)); - break; - } - -#if defined(CONFIG_SOFTFLOAT_INLINE) - /* ??? The "fpu/softfloat.h" interface is to call set_float_rounding_mode. - With CONFIG_SOFTFLOAT that expands to an out-of-line call that just - sets the one field. */ - tcg_gen_st8_i32(tmp, cpu_env, - offsetof(CPUAlphaState, fp_status.float_rounding_mode)); -#else - gen_helper_setroundmode(tmp); -#endif - - tcg_temp_free_i32(tmp); -} - -static void gen_qual_flushzero(DisasContext *ctx, int fn11) -{ - TCGv_i32 tmp; - - fn11 &= QUAL_U; - if (fn11 == ctx->tb_ftz) { - return; - } - ctx->tb_ftz = fn11; - - tmp = tcg_temp_new_i32(); - if (fn11) { - /* Underflow is enabled, use the FPCR setting. */ - tcg_gen_ld8u_i32(tmp, cpu_env, - offsetof(CPUAlphaState, fpcr_flush_to_zero)); - } else { - /* Underflow is disabled, force flush-to-zero. */ - tcg_gen_movi_i32(tmp, 1); - } - -#if defined(CONFIG_SOFTFLOAT_INLINE) - tcg_gen_st8_i32(tmp, cpu_env, - offsetof(CPUAlphaState, fp_status.flush_to_zero)); -#else - gen_helper_setflushzero(tmp); -#endif - - tcg_temp_free_i32(tmp); -} - -static TCGv gen_ieee_input(DisasContext *ctx, int reg, int fn11, int is_cmp) -{ - TCGv val; - - if (unlikely(reg == 31)) { - val = load_zero(ctx); - } else { - val = cpu_fir[reg]; - if ((fn11 & QUAL_S) == 0) { - if (is_cmp) { - gen_helper_ieee_input_cmp(cpu_env, val); - } else { - gen_helper_ieee_input(cpu_env, val); - } - } else { -#ifndef CONFIG_USER_ONLY - /* In system mode, raise exceptions for denormals like real - hardware. In user mode, proceed as if the OS completion - handler is handling the denormal as per spec. */ - gen_helper_ieee_input_s(cpu_env, val); -#endif - } - } - return val; -} - -static void gen_fp_exc_raise(int rc, int fn11) -{ - /* ??? We ought to be able to do something with imprecise exceptions. - E.g. notice we're still in the trap shadow of something within the - TB and do not generate the code to signal the exception; end the TB - when an exception is forced to arrive, either by consumption of a - register value or TRAPB or EXCB. */ - TCGv_i32 reg, ign; - uint32_t ignore = 0; - - if (!(fn11 & QUAL_U)) { - /* Note that QUAL_U == QUAL_V, so ignore either. */ - ignore |= FPCR_UNF | FPCR_IOV; - } - if (!(fn11 & QUAL_I)) { - ignore |= FPCR_INE; - } - ign = tcg_const_i32(ignore); - - /* ??? Pass in the regno of the destination so that the helper can - set EXC_MASK, which contains a bitmask of destination registers - that have caused arithmetic traps. A simple userspace emulation - does not require this. We do need it for a guest kernel's entArith, - or if we were to do something clever with imprecise exceptions. */ - reg = tcg_const_i32(rc + 32); - if (fn11 & QUAL_S) { - gen_helper_fp_exc_raise_s(cpu_env, ign, reg); - } else { - gen_helper_fp_exc_raise(cpu_env, ign, reg); - } - - tcg_temp_free_i32(reg); - tcg_temp_free_i32(ign); -} - -static void gen_cvtlq(TCGv vc, TCGv vb) -{ - TCGv tmp = tcg_temp_new(); - - /* The arithmetic right shift here, plus the sign-extended mask below - yields a sign-extended result without an explicit ext32s_i64. */ - tcg_gen_sari_i64(tmp, vb, 32); - tcg_gen_shri_i64(vc, vb, 29); - tcg_gen_andi_i64(tmp, tmp, (int32_t)0xc0000000); - tcg_gen_andi_i64(vc, vc, 0x3fffffff); - tcg_gen_or_i64(vc, vc, tmp); - - tcg_temp_free(tmp); -} - -static void gen_ieee_arith2(DisasContext *ctx, - void (*helper)(TCGv, TCGv_ptr, TCGv), - int rb, int rc, int fn11) -{ - TCGv vb; - - gen_qual_roundmode(ctx, fn11); - gen_qual_flushzero(ctx, fn11); - - vb = gen_ieee_input(ctx, rb, fn11, 0); - helper(dest_fpr(ctx, rc), cpu_env, vb); - - gen_fp_exc_raise(rc, fn11); -} - -#define IEEE_ARITH2(name) \ -static inline void glue(gen_, name)(DisasContext *ctx, \ - int rb, int rc, int fn11) \ -{ \ - gen_ieee_arith2(ctx, gen_helper_##name, rb, rc, fn11); \ -} -IEEE_ARITH2(sqrts) -IEEE_ARITH2(sqrtt) -IEEE_ARITH2(cvtst) -IEEE_ARITH2(cvtts) - -static void gen_cvttq(DisasContext *ctx, int rb, int rc, int fn11) -{ - TCGv vb, vc; - - /* No need to set flushzero, since we have an integer output. */ - vb = gen_ieee_input(ctx, rb, fn11, 0); - vc = dest_fpr(ctx, rc); - - /* Almost all integer conversions use cropped rounding; - special case that. */ - if ((fn11 & QUAL_RM_MASK) == QUAL_RM_C) { - gen_helper_cvttq_c(vc, cpu_env, vb); - } else { - gen_qual_roundmode(ctx, fn11); - gen_helper_cvttq(vc, cpu_env, vb); - } - gen_fp_exc_raise(rc, fn11); -} - -static void gen_ieee_intcvt(DisasContext *ctx, - void (*helper)(TCGv, TCGv_ptr, TCGv), - int rb, int rc, int fn11) -{ - TCGv vb, vc; - - gen_qual_roundmode(ctx, fn11); - vb = load_fpr(ctx, rb); - vc = dest_fpr(ctx, rc); - - /* The only exception that can be raised by integer conversion - is inexact. Thus we only need to worry about exceptions when - inexact handling is requested. */ - if (fn11 & QUAL_I) { - helper(vc, cpu_env, vb); - gen_fp_exc_raise(rc, fn11); - } else { - helper(vc, cpu_env, vb); - } -} - -#define IEEE_INTCVT(name) \ -static inline void glue(gen_, name)(DisasContext *ctx, \ - int rb, int rc, int fn11) \ -{ \ - gen_ieee_intcvt(ctx, gen_helper_##name, rb, rc, fn11); \ -} -IEEE_INTCVT(cvtqs) -IEEE_INTCVT(cvtqt) - -static void gen_cpy_mask(TCGv vc, TCGv va, TCGv vb, bool inv_a, uint64_t mask) -{ - TCGv vmask = tcg_const_i64(mask); - TCGv tmp = tcg_temp_new_i64(); - - if (inv_a) { - tcg_gen_andc_i64(tmp, vmask, va); - } else { - tcg_gen_and_i64(tmp, va, vmask); - } - - tcg_gen_andc_i64(vc, vb, vmask); - tcg_gen_or_i64(vc, vc, tmp); - - tcg_temp_free(vmask); - tcg_temp_free(tmp); -} - -static void gen_ieee_arith3(DisasContext *ctx, - void (*helper)(TCGv, TCGv_ptr, TCGv, TCGv), - int ra, int rb, int rc, int fn11) -{ - TCGv va, vb, vc; - - gen_qual_roundmode(ctx, fn11); - gen_qual_flushzero(ctx, fn11); - - va = gen_ieee_input(ctx, ra, fn11, 0); - vb = gen_ieee_input(ctx, rb, fn11, 0); - vc = dest_fpr(ctx, rc); - helper(vc, cpu_env, va, vb); - - gen_fp_exc_raise(rc, fn11); -} - -#define IEEE_ARITH3(name) \ -static inline void glue(gen_, name)(DisasContext *ctx, \ - int ra, int rb, int rc, int fn11) \ -{ \ - gen_ieee_arith3(ctx, gen_helper_##name, ra, rb, rc, fn11); \ -} -IEEE_ARITH3(adds) -IEEE_ARITH3(subs) -IEEE_ARITH3(muls) -IEEE_ARITH3(divs) -IEEE_ARITH3(addt) -IEEE_ARITH3(subt) -IEEE_ARITH3(mult) -IEEE_ARITH3(divt) - -static void gen_ieee_compare(DisasContext *ctx, - void (*helper)(TCGv, TCGv_ptr, TCGv, TCGv), - int ra, int rb, int rc, int fn11) -{ - TCGv va, vb, vc; - - va = gen_ieee_input(ctx, ra, fn11, 1); - vb = gen_ieee_input(ctx, rb, fn11, 1); - vc = dest_fpr(ctx, rc); - helper(vc, cpu_env, va, vb); - - gen_fp_exc_raise(rc, fn11); -} - -#define IEEE_CMP3(name) \ -static inline void glue(gen_, name)(DisasContext *ctx, \ - int ra, int rb, int rc, int fn11) \ -{ \ - gen_ieee_compare(ctx, gen_helper_##name, ra, rb, rc, fn11); \ -} -IEEE_CMP3(cmptun) -IEEE_CMP3(cmpteq) -IEEE_CMP3(cmptlt) -IEEE_CMP3(cmptle) - -static inline uint64_t zapnot_mask(uint8_t lit) -{ - uint64_t mask = 0; - int i; - - for (i = 0; i < 8; ++i) { - if ((lit >> i) & 1) { - mask |= 0xffull << (i * 8); - } - } - return mask; -} - -/* Implement zapnot with an immediate operand, which expands to some - form of immediate AND. This is a basic building block in the - definition of many of the other byte manipulation instructions. */ -static void gen_zapnoti(TCGv dest, TCGv src, uint8_t lit) -{ - switch (lit) { - case 0x00: - tcg_gen_movi_i64(dest, 0); - break; - case 0x01: - tcg_gen_ext8u_i64(dest, src); - break; - case 0x03: - tcg_gen_ext16u_i64(dest, src); - break; - case 0x0f: - tcg_gen_ext32u_i64(dest, src); - break; - case 0xff: - tcg_gen_mov_i64(dest, src); - break; - default: - tcg_gen_andi_i64(dest, src, zapnot_mask(lit)); - break; - } -} - -/* EXTWH, EXTLH, EXTQH */ -static void gen_ext_h(DisasContext *ctx, TCGv vc, TCGv va, int rb, bool islit, - uint8_t lit, uint8_t byte_mask) -{ - if (islit) { - tcg_gen_shli_i64(vc, va, (64 - lit * 8) & 0x3f); - } else { - TCGv tmp = tcg_temp_new(); - tcg_gen_shli_i64(tmp, load_gpr(ctx, rb), 3); - tcg_gen_neg_i64(tmp, tmp); - tcg_gen_andi_i64(tmp, tmp, 0x3f); - tcg_gen_shl_i64(vc, va, tmp); - tcg_temp_free(tmp); - } - gen_zapnoti(vc, vc, byte_mask); -} - -/* EXTBL, EXTWL, EXTLL, EXTQL */ -static void gen_ext_l(DisasContext *ctx, TCGv vc, TCGv va, int rb, bool islit, - uint8_t lit, uint8_t byte_mask) -{ - if (islit) { - tcg_gen_shri_i64(vc, va, (lit & 7) * 8); - } else { - TCGv tmp = tcg_temp_new(); - tcg_gen_andi_i64(tmp, load_gpr(ctx, rb), 7); - tcg_gen_shli_i64(tmp, tmp, 3); - tcg_gen_shr_i64(vc, va, tmp); - tcg_temp_free(tmp); - } - gen_zapnoti(vc, vc, byte_mask); -} - -/* INSWH, INSLH, INSQH */ -static void gen_ins_h(DisasContext *ctx, TCGv vc, TCGv va, int rb, bool islit, - uint8_t lit, uint8_t byte_mask) -{ - TCGv tmp = tcg_temp_new(); - - /* The instruction description has us left-shift the byte mask and extract - bits <15:8> and apply that zap at the end. This is equivalent to simply - performing the zap first and shifting afterward. */ - gen_zapnoti(tmp, va, byte_mask); - - if (islit) { - lit &= 7; - if (unlikely(lit == 0)) { - tcg_gen_movi_i64(vc, 0); - } else { - tcg_gen_shri_i64(vc, tmp, 64 - lit * 8); - } - } else { - TCGv shift = tcg_temp_new(); - - /* If (B & 7) == 0, we need to shift by 64 and leave a zero. Do this - portably by splitting the shift into two parts: shift_count-1 and 1. - Arrange for the -1 by using ones-complement instead of - twos-complement in the negation: ~(B * 8) & 63. */ - - tcg_gen_shli_i64(shift, load_gpr(ctx, rb), 3); - tcg_gen_not_i64(shift, shift); - tcg_gen_andi_i64(shift, shift, 0x3f); - - tcg_gen_shr_i64(vc, tmp, shift); - tcg_gen_shri_i64(vc, vc, 1); - tcg_temp_free(shift); - } - tcg_temp_free(tmp); -} - -/* INSBL, INSWL, INSLL, INSQL */ -static void gen_ins_l(DisasContext *ctx, TCGv vc, TCGv va, int rb, bool islit, - uint8_t lit, uint8_t byte_mask) -{ - TCGv tmp = tcg_temp_new(); - - /* The instruction description has us left-shift the byte mask - the same number of byte slots as the data and apply the zap - at the end. This is equivalent to simply performing the zap - first and shifting afterward. */ - gen_zapnoti(tmp, va, byte_mask); - - if (islit) { - tcg_gen_shli_i64(vc, tmp, (lit & 7) * 8); - } else { - TCGv shift = tcg_temp_new(); - tcg_gen_andi_i64(shift, load_gpr(ctx, rb), 7); - tcg_gen_shli_i64(shift, shift, 3); - tcg_gen_shl_i64(vc, tmp, shift); - tcg_temp_free(shift); - } - tcg_temp_free(tmp); -} - -/* MSKWH, MSKLH, MSKQH */ -static void gen_msk_h(DisasContext *ctx, TCGv vc, TCGv va, int rb, bool islit, - uint8_t lit, uint8_t byte_mask) -{ - if (islit) { - gen_zapnoti(vc, va, ~((byte_mask << (lit & 7)) >> 8)); - } else { - TCGv shift = tcg_temp_new(); - TCGv mask = tcg_temp_new(); - - /* The instruction description is as above, where the byte_mask - is shifted left, and then we extract bits <15:8>. This can be - emulated with a right-shift on the expanded byte mask. This - requires extra care because for an input <2:0> == 0 we need a - shift of 64 bits in order to generate a zero. This is done by - splitting the shift into two parts, the variable shift - 1 - followed by a constant 1 shift. The code we expand below is - equivalent to ~(B * 8) & 63. */ - - tcg_gen_shli_i64(shift, load_gpr(ctx, rb), 3); - tcg_gen_not_i64(shift, shift); - tcg_gen_andi_i64(shift, shift, 0x3f); - tcg_gen_movi_i64(mask, zapnot_mask (byte_mask)); - tcg_gen_shr_i64(mask, mask, shift); - tcg_gen_shri_i64(mask, mask, 1); - - tcg_gen_andc_i64(vc, va, mask); - - tcg_temp_free(mask); - tcg_temp_free(shift); - } -} - -/* MSKBL, MSKWL, MSKLL, MSKQL */ -static void gen_msk_l(DisasContext *ctx, TCGv vc, TCGv va, int rb, bool islit, - uint8_t lit, uint8_t byte_mask) -{ - if (islit) { - gen_zapnoti(vc, va, ~(byte_mask << (lit & 7))); - } else { - TCGv shift = tcg_temp_new(); - TCGv mask = tcg_temp_new(); - - tcg_gen_andi_i64(shift, load_gpr(ctx, rb), 7); - tcg_gen_shli_i64(shift, shift, 3); - tcg_gen_movi_i64(mask, zapnot_mask(byte_mask)); - tcg_gen_shl_i64(mask, mask, shift); - - tcg_gen_andc_i64(vc, va, mask); - - tcg_temp_free(mask); - tcg_temp_free(shift); - } -} - -static void gen_rx(DisasContext *ctx, int ra, int set) -{ - TCGv_i32 tmp; - - if (ra != 31) { - tcg_gen_ld8u_i64(ctx->ir[ra], cpu_env, - offsetof(CPUAlphaState, intr_flag)); - } - - tmp = tcg_const_i32(set); - tcg_gen_st8_i32(tmp, cpu_env, offsetof(CPUAlphaState, intr_flag)); - tcg_temp_free_i32(tmp); -} - -static ExitStatus gen_call_pal(DisasContext *ctx, int palcode) -{ - /* We're emulating OSF/1 PALcode. Many of these are trivial access - to internal cpu registers. */ - - /* Unprivileged PAL call */ - if (palcode >= 0x80 && palcode < 0xC0) { - switch (palcode) { - case 0x86: - /* IMB */ - /* No-op inside QEMU. */ - break; - case 0x9E: - /* RDUNIQUE */ - tcg_gen_ld_i64(ctx->ir[IR_V0], cpu_env, - offsetof(CPUAlphaState, unique)); - break; - case 0x9F: - /* WRUNIQUE */ - tcg_gen_st_i64(ctx->ir[IR_A0], cpu_env, - offsetof(CPUAlphaState, unique)); - break; - default: - palcode &= 0xbf; - goto do_call_pal; - } - return NO_EXIT; - } - -#ifndef CONFIG_USER_ONLY - /* Privileged PAL code */ - if (palcode < 0x40 && (ctx->tb->flags & TB_FLAGS_USER_MODE) == 0) { - switch (palcode) { - case 0x01: - /* CFLUSH */ - /* No-op inside QEMU. */ - break; - case 0x02: - /* DRAINA */ - /* No-op inside QEMU. */ - break; - case 0x2D: - /* WRVPTPTR */ - tcg_gen_st_i64(ctx->ir[IR_A0], cpu_env, - offsetof(CPUAlphaState, vptptr)); - break; - case 0x31: - /* WRVAL */ - tcg_gen_st_i64(ctx->ir[IR_A0], cpu_env, - offsetof(CPUAlphaState, sysval)); - break; - case 0x32: - /* RDVAL */ - tcg_gen_ld_i64(ctx->ir[IR_V0], cpu_env, - offsetof(CPUAlphaState, sysval)); - break; - - case 0x35: { - /* SWPIPL */ - TCGv tmp; - - /* Note that we already know we're in kernel mode, so we know - that PS only contains the 3 IPL bits. */ - tcg_gen_ld8u_i64(ctx->ir[IR_V0], cpu_env, - offsetof(CPUAlphaState, ps)); - - /* But make sure and store only the 3 IPL bits from the user. */ - tmp = tcg_temp_new(); - tcg_gen_andi_i64(tmp, ctx->ir[IR_A0], PS_INT_MASK); - tcg_gen_st8_i64(tmp, cpu_env, offsetof(CPUAlphaState, ps)); - tcg_temp_free(tmp); - break; - } - - case 0x36: - /* RDPS */ - tcg_gen_ld8u_i64(ctx->ir[IR_V0], cpu_env, - offsetof(CPUAlphaState, ps)); - break; - case 0x38: - /* WRUSP */ - tcg_gen_st_i64(ctx->ir[IR_A0], cpu_env, - offsetof(CPUAlphaState, usp)); - break; - case 0x3A: - /* RDUSP */ - tcg_gen_ld_i64(ctx->ir[IR_V0], cpu_env, - offsetof(CPUAlphaState, usp)); - break; - case 0x3C: - /* WHAMI */ - tcg_gen_ld32s_i64(ctx->ir[IR_V0], cpu_env, - -offsetof(AlphaCPU, env) + offsetof(CPUState, cpu_index)); - break; - - default: - palcode &= 0x3f; - goto do_call_pal; - } - return NO_EXIT; - } -#endif - return gen_invalid(ctx); - - do_call_pal: -#ifdef CONFIG_USER_ONLY - return gen_excp(ctx, EXCP_CALL_PAL, palcode); -#else - { - TCGv tmp = tcg_temp_new(); - uint64_t exc_addr = ctx->pc; - uint64_t entry = ctx->palbr; - - if (ctx->tb->flags & TB_FLAGS_PAL_MODE) { - exc_addr |= 1; - } else { - tcg_gen_movi_i64(tmp, 1); - tcg_gen_st8_i64(tmp, cpu_env, offsetof(CPUAlphaState, pal_mode)); - } - - tcg_gen_movi_i64(tmp, exc_addr); - tcg_gen_st_i64(tmp, cpu_env, offsetof(CPUAlphaState, exc_addr)); - tcg_temp_free(tmp); - - entry += (palcode & 0x80 - ? 0x2000 + (palcode - 0x80) * 64 - : 0x1000 + palcode * 64); - - /* Since the destination is running in PALmode, we don't really - need the page permissions check. We'll see the existence of - the page when we create the TB, and we'll flush all TBs if - we change the PAL base register. */ - if (!ctx->singlestep_enabled && !(ctx->tb->cflags & CF_LAST_IO)) { - tcg_gen_goto_tb(0); - tcg_gen_movi_i64(cpu_pc, entry); - tcg_gen_exit_tb((uintptr_t)ctx->tb); - return EXIT_GOTO_TB; - } else { - tcg_gen_movi_i64(cpu_pc, entry); - return EXIT_PC_UPDATED; - } - } -#endif -} - -#ifndef CONFIG_USER_ONLY - -#define PR_BYTE 0x100000 -#define PR_LONG 0x200000 - -static int cpu_pr_data(int pr) -{ - switch (pr) { - case 0: return offsetof(CPUAlphaState, ps) | PR_BYTE; - case 1: return offsetof(CPUAlphaState, fen) | PR_BYTE; - case 2: return offsetof(CPUAlphaState, pcc_ofs) | PR_LONG; - case 3: return offsetof(CPUAlphaState, trap_arg0); - case 4: return offsetof(CPUAlphaState, trap_arg1); - case 5: return offsetof(CPUAlphaState, trap_arg2); - case 6: return offsetof(CPUAlphaState, exc_addr); - case 7: return offsetof(CPUAlphaState, palbr); - case 8: return offsetof(CPUAlphaState, ptbr); - case 9: return offsetof(CPUAlphaState, vptptr); - case 10: return offsetof(CPUAlphaState, unique); - case 11: return offsetof(CPUAlphaState, sysval); - case 12: return offsetof(CPUAlphaState, usp); - - case 40 ... 63: - return offsetof(CPUAlphaState, scratch[pr - 40]); - - case 251: - return offsetof(CPUAlphaState, alarm_expire); - } - return 0; -} - -static ExitStatus gen_mfpr(DisasContext *ctx, TCGv va, int regno) -{ - void (*helper)(TCGv); - int data; - - switch (regno) { - case 32 ... 39: - /* Accessing the "non-shadow" general registers. */ - regno = regno == 39 ? 25 : regno - 32 + 8; - tcg_gen_mov_i64(va, cpu_std_ir[regno]); - break; - - case 250: /* WALLTIME */ - helper = gen_helper_get_walltime; - goto do_helper; - case 249: /* VMTIME */ - helper = gen_helper_get_vmtime; - do_helper: - if (use_icount) { - gen_io_start(); - helper(va); - gen_io_end(); - return EXIT_PC_STALE; - } else { - helper(va); - } - break; - - default: - /* The basic registers are data only, and unknown registers - are read-zero, write-ignore. */ - data = cpu_pr_data(regno); - if (data == 0) { - tcg_gen_movi_i64(va, 0); - } else if (data & PR_BYTE) { - tcg_gen_ld8u_i64(va, cpu_env, data & ~PR_BYTE); - } else if (data & PR_LONG) { - tcg_gen_ld32s_i64(va, cpu_env, data & ~PR_LONG); - } else { - tcg_gen_ld_i64(va, cpu_env, data); - } - break; - } - - return NO_EXIT; -} - -static ExitStatus gen_mtpr(DisasContext *ctx, TCGv vb, int regno) -{ - TCGv tmp; - int data; - - switch (regno) { - case 255: - /* TBIA */ - gen_helper_tbia(cpu_env); - break; - - case 254: - /* TBIS */ - gen_helper_tbis(cpu_env, vb); - break; - - case 253: - /* WAIT */ - tmp = tcg_const_i64(1); - tcg_gen_st32_i64(tmp, cpu_env, -offsetof(AlphaCPU, env) + - offsetof(CPUState, halted)); - return gen_excp(ctx, EXCP_HLT, 0); - - case 252: - /* HALT */ - gen_helper_halt(vb); - return EXIT_PC_STALE; - - case 251: - /* ALARM */ - gen_helper_set_alarm(cpu_env, vb); - break; - - case 7: - /* PALBR */ - tcg_gen_st_i64(vb, cpu_env, offsetof(CPUAlphaState, palbr)); - /* Changing the PAL base register implies un-chaining all of the TBs - that ended with a CALL_PAL. Since the base register usually only - changes during boot, flushing everything works well. */ - gen_helper_tb_flush(cpu_env); - return EXIT_PC_STALE; - - case 32 ... 39: - /* Accessing the "non-shadow" general registers. */ - regno = regno == 39 ? 25 : regno - 32 + 8; - tcg_gen_mov_i64(cpu_std_ir[regno], vb); - break; - - default: - /* The basic registers are data only, and unknown registers - are read-zero, write-ignore. */ - data = cpu_pr_data(regno); - if (data != 0) { - if (data & PR_BYTE) { - tcg_gen_st8_i64(vb, cpu_env, data & ~PR_BYTE); - } else if (data & PR_LONG) { - tcg_gen_st32_i64(vb, cpu_env, data & ~PR_LONG); - } else { - tcg_gen_st_i64(vb, cpu_env, data); - } - } - break; - } - - return NO_EXIT; -} -#endif /* !USER_ONLY*/ - -#define REQUIRE_NO_LIT \ - do { \ - if (real_islit) { \ - goto invalid_opc; \ - } \ - } while (0) - -#define REQUIRE_TB_FLAG(FLAG) \ - do { \ - if ((ctx->tb->flags & (FLAG)) == 0) { \ - goto invalid_opc; \ - } \ - } while (0) - -#define REQUIRE_REG_31(WHICH) \ - do { \ - if (WHICH != 31) { \ - goto invalid_opc; \ - } \ - } while (0) - -static ExitStatus translate_one(DisasContext *ctx, uint32_t insn) -{ - int32_t disp21, disp16, disp12 __attribute__((unused)); - uint16_t fn11; - uint8_t opc, ra, rb, rc, fpfn, fn7, lit; - bool islit, real_islit; - TCGv va, vb, vc, tmp, tmp2; - TCGv_i32 t32; - ExitStatus ret; - - /* Decode all instruction fields */ - opc = extract32(insn, 26, 6); - ra = extract32(insn, 21, 5); - rb = extract32(insn, 16, 5); - rc = extract32(insn, 0, 5); - real_islit = islit = extract32(insn, 12, 1); - lit = extract32(insn, 13, 8); - - disp21 = sextract32(insn, 0, 21); - disp16 = sextract32(insn, 0, 16); - disp12 = sextract32(insn, 0, 12); - - fn11 = extract32(insn, 5, 11); - fpfn = extract32(insn, 5, 6); - fn7 = extract32(insn, 5, 7); - - if (rb == 31 && !islit) { - islit = true; - lit = 0; - } - - ret = NO_EXIT; - switch (opc) { - case 0x00: - /* CALL_PAL */ - ret = gen_call_pal(ctx, insn & 0x03ffffff); - break; - case 0x01: - /* OPC01 */ - goto invalid_opc; - case 0x02: - /* OPC02 */ - goto invalid_opc; - case 0x03: - /* OPC03 */ - goto invalid_opc; - case 0x04: - /* OPC04 */ - goto invalid_opc; - case 0x05: - /* OPC05 */ - goto invalid_opc; - case 0x06: - /* OPC06 */ - goto invalid_opc; - case 0x07: - /* OPC07 */ - goto invalid_opc; - - case 0x09: - /* LDAH */ - disp16 = (uint32_t)disp16 << 16; - /* fall through */ - case 0x08: - /* LDA */ - va = dest_gpr(ctx, ra); - /* It's worth special-casing immediate loads. */ - if (rb == 31) { - tcg_gen_movi_i64(va, disp16); - } else { - tcg_gen_addi_i64(va, load_gpr(ctx, rb), disp16); - } - break; - - case 0x0A: - /* LDBU */ - REQUIRE_TB_FLAG(TB_FLAGS_AMASK_BWX); - gen_load_mem(ctx, &tcg_gen_qemu_ld8u, ra, rb, disp16, 0, 0); - break; - case 0x0B: - /* LDQ_U */ - gen_load_mem(ctx, &tcg_gen_qemu_ld64, ra, rb, disp16, 0, 1); - break; - case 0x0C: - /* LDWU */ - REQUIRE_TB_FLAG(TB_FLAGS_AMASK_BWX); - gen_load_mem(ctx, &tcg_gen_qemu_ld16u, ra, rb, disp16, 0, 0); - break; - case 0x0D: - /* STW */ - REQUIRE_TB_FLAG(TB_FLAGS_AMASK_BWX); - gen_store_mem(ctx, &tcg_gen_qemu_st16, ra, rb, disp16, 0, 0); - break; - case 0x0E: - /* STB */ - REQUIRE_TB_FLAG(TB_FLAGS_AMASK_BWX); - gen_store_mem(ctx, &tcg_gen_qemu_st8, ra, rb, disp16, 0, 0); - break; - case 0x0F: - /* STQ_U */ - gen_store_mem(ctx, &tcg_gen_qemu_st64, ra, rb, disp16, 0, 1); - break; - - case 0x10: - vc = dest_gpr(ctx, rc); - vb = load_gpr_lit(ctx, rb, lit, islit); - - if (ra == 31) { - if (fn7 == 0x00) { - /* Special case ADDL as SEXTL. */ - tcg_gen_ext32s_i64(vc, vb); - break; - } - if (fn7 == 0x29) { - /* Special case SUBQ as NEGQ. */ - tcg_gen_neg_i64(vc, vb); - break; - } - } - - va = load_gpr(ctx, ra); - switch (fn7) { - case 0x00: - /* ADDL */ - tcg_gen_add_i64(vc, va, vb); - tcg_gen_ext32s_i64(vc, vc); - break; - case 0x02: - /* S4ADDL */ - tmp = tcg_temp_new(); - tcg_gen_shli_i64(tmp, va, 2); - tcg_gen_add_i64(tmp, tmp, vb); - tcg_gen_ext32s_i64(vc, tmp); - tcg_temp_free(tmp); - break; - case 0x09: - /* SUBL */ - tcg_gen_sub_i64(vc, va, vb); - tcg_gen_ext32s_i64(vc, vc); - break; - case 0x0B: - /* S4SUBL */ - tmp = tcg_temp_new(); - tcg_gen_shli_i64(tmp, va, 2); - tcg_gen_sub_i64(tmp, tmp, vb); - tcg_gen_ext32s_i64(vc, tmp); - tcg_temp_free(tmp); - break; - case 0x0F: - /* CMPBGE */ - if (ra == 31) { - /* Special case 0 >= X as X == 0. */ - gen_helper_cmpbe0(vc, vb); - } else { - gen_helper_cmpbge(vc, va, vb); - } - break; - case 0x12: - /* S8ADDL */ - tmp = tcg_temp_new(); - tcg_gen_shli_i64(tmp, va, 3); - tcg_gen_add_i64(tmp, tmp, vb); - tcg_gen_ext32s_i64(vc, tmp); - tcg_temp_free(tmp); - break; - case 0x1B: - /* S8SUBL */ - tmp = tcg_temp_new(); - tcg_gen_shli_i64(tmp, va, 3); - tcg_gen_sub_i64(tmp, tmp, vb); - tcg_gen_ext32s_i64(vc, tmp); - tcg_temp_free(tmp); - break; - case 0x1D: - /* CMPULT */ - tcg_gen_setcond_i64(TCG_COND_LTU, vc, va, vb); - break; - case 0x20: - /* ADDQ */ - tcg_gen_add_i64(vc, va, vb); - break; - case 0x22: - /* S4ADDQ */ - tmp = tcg_temp_new(); - tcg_gen_shli_i64(tmp, va, 2); - tcg_gen_add_i64(vc, tmp, vb); - tcg_temp_free(tmp); - break; - case 0x29: - /* SUBQ */ - tcg_gen_sub_i64(vc, va, vb); - break; - case 0x2B: - /* S4SUBQ */ - tmp = tcg_temp_new(); - tcg_gen_shli_i64(tmp, va, 2); - tcg_gen_sub_i64(vc, tmp, vb); - tcg_temp_free(tmp); - break; - case 0x2D: - /* CMPEQ */ - tcg_gen_setcond_i64(TCG_COND_EQ, vc, va, vb); - break; - case 0x32: - /* S8ADDQ */ - tmp = tcg_temp_new(); - tcg_gen_shli_i64(tmp, va, 3); - tcg_gen_add_i64(vc, tmp, vb); - tcg_temp_free(tmp); - break; - case 0x3B: - /* S8SUBQ */ - tmp = tcg_temp_new(); - tcg_gen_shli_i64(tmp, va, 3); - tcg_gen_sub_i64(vc, tmp, vb); - tcg_temp_free(tmp); - break; - case 0x3D: - /* CMPULE */ - tcg_gen_setcond_i64(TCG_COND_LEU, vc, va, vb); - break; - case 0x40: - /* ADDL/V */ - tmp = tcg_temp_new(); - tcg_gen_ext32s_i64(tmp, va); - tcg_gen_ext32s_i64(vc, vb); - tcg_gen_add_i64(tmp, tmp, vc); - tcg_gen_ext32s_i64(vc, tmp); - gen_helper_check_overflow(cpu_env, vc, tmp); - tcg_temp_free(tmp); - break; - case 0x49: - /* SUBL/V */ - tmp = tcg_temp_new(); - tcg_gen_ext32s_i64(tmp, va); - tcg_gen_ext32s_i64(vc, vb); - tcg_gen_sub_i64(tmp, tmp, vc); - tcg_gen_ext32s_i64(vc, tmp); - gen_helper_check_overflow(cpu_env, vc, tmp); - tcg_temp_free(tmp); - break; - case 0x4D: - /* CMPLT */ - tcg_gen_setcond_i64(TCG_COND_LT, vc, va, vb); - break; - case 0x60: - /* ADDQ/V */ - tmp = tcg_temp_new(); - tmp2 = tcg_temp_new(); - tcg_gen_eqv_i64(tmp, va, vb); - tcg_gen_mov_i64(tmp2, va); - tcg_gen_add_i64(vc, va, vb); - tcg_gen_xor_i64(tmp2, tmp2, vc); - tcg_gen_and_i64(tmp, tmp, tmp2); - tcg_gen_shri_i64(tmp, tmp, 63); - tcg_gen_movi_i64(tmp2, 0); - gen_helper_check_overflow(cpu_env, tmp, tmp2); - tcg_temp_free(tmp); - tcg_temp_free(tmp2); - break; - case 0x69: - /* SUBQ/V */ - tmp = tcg_temp_new(); - tmp2 = tcg_temp_new(); - tcg_gen_xor_i64(tmp, va, vb); - tcg_gen_mov_i64(tmp2, va); - tcg_gen_sub_i64(vc, va, vb); - tcg_gen_xor_i64(tmp2, tmp2, vc); - tcg_gen_and_i64(tmp, tmp, tmp2); - tcg_gen_shri_i64(tmp, tmp, 63); - tcg_gen_movi_i64(tmp2, 0); - gen_helper_check_overflow(cpu_env, tmp, tmp2); - tcg_temp_free(tmp); - tcg_temp_free(tmp2); - break; - case 0x6D: - /* CMPLE */ - tcg_gen_setcond_i64(TCG_COND_LE, vc, va, vb); - break; - default: - goto invalid_opc; - } - break; - - case 0x11: - if (fn7 == 0x20) { - if (rc == 31) { - /* Special case BIS as NOP. */ - break; - } - if (ra == 31) { - /* Special case BIS as MOV. */ - vc = dest_gpr(ctx, rc); - if (islit) { - tcg_gen_movi_i64(vc, lit); - } else { - tcg_gen_mov_i64(vc, load_gpr(ctx, rb)); - } - break; - } - } - - vc = dest_gpr(ctx, rc); - vb = load_gpr_lit(ctx, rb, lit, islit); - - if (fn7 == 0x28 && ra == 31) { - /* Special case ORNOT as NOT. */ - tcg_gen_not_i64(vc, vb); - break; - } - - va = load_gpr(ctx, ra); - switch (fn7) { - case 0x00: - /* AND */ - tcg_gen_and_i64(vc, va, vb); - break; - case 0x08: - /* BIC */ - tcg_gen_andc_i64(vc, va, vb); - break; - case 0x14: - /* CMOVLBS */ - tmp = tcg_temp_new(); - tcg_gen_andi_i64(tmp, va, 1); - tcg_gen_movcond_i64(TCG_COND_NE, vc, tmp, load_zero(ctx), - vb, load_gpr(ctx, rc)); - tcg_temp_free(tmp); - break; - case 0x16: - /* CMOVLBC */ - tmp = tcg_temp_new(); - tcg_gen_andi_i64(tmp, va, 1); - tcg_gen_movcond_i64(TCG_COND_EQ, vc, tmp, load_zero(ctx), - vb, load_gpr(ctx, rc)); - tcg_temp_free(tmp); - break; - case 0x20: - /* BIS */ - tcg_gen_or_i64(vc, va, vb); - break; - case 0x24: - /* CMOVEQ */ - tcg_gen_movcond_i64(TCG_COND_EQ, vc, va, load_zero(ctx), - vb, load_gpr(ctx, rc)); - break; - case 0x26: - /* CMOVNE */ - tcg_gen_movcond_i64(TCG_COND_NE, vc, va, load_zero(ctx), - vb, load_gpr(ctx, rc)); - break; - case 0x28: - /* ORNOT */ - tcg_gen_orc_i64(vc, va, vb); - break; - case 0x40: - /* XOR */ - tcg_gen_xor_i64(vc, va, vb); - break; - case 0x44: - /* CMOVLT */ - tcg_gen_movcond_i64(TCG_COND_LT, vc, va, load_zero(ctx), - vb, load_gpr(ctx, rc)); - break; - case 0x46: - /* CMOVGE */ - tcg_gen_movcond_i64(TCG_COND_GE, vc, va, load_zero(ctx), - vb, load_gpr(ctx, rc)); - break; - case 0x48: - /* EQV */ - tcg_gen_eqv_i64(vc, va, vb); - break; - case 0x61: - /* AMASK */ - REQUIRE_REG_31(ra); - { - uint64_t amask = ctx->tb->flags >> TB_FLAGS_AMASK_SHIFT; - tcg_gen_andi_i64(vc, vb, ~amask); - } - break; - case 0x64: - /* CMOVLE */ - tcg_gen_movcond_i64(TCG_COND_LE, vc, va, load_zero(ctx), - vb, load_gpr(ctx, rc)); - break; - case 0x66: - /* CMOVGT */ - tcg_gen_movcond_i64(TCG_COND_GT, vc, va, load_zero(ctx), - vb, load_gpr(ctx, rc)); - break; - case 0x6C: - /* IMPLVER */ - REQUIRE_REG_31(ra); - tcg_gen_movi_i64(vc, ctx->implver); - break; - default: - goto invalid_opc; - } - break; - - case 0x12: - vc = dest_gpr(ctx, rc); - va = load_gpr(ctx, ra); - switch (fn7) { - case 0x02: - /* MSKBL */ - gen_msk_l(ctx, vc, va, rb, islit, lit, 0x01); - break; - case 0x06: - /* EXTBL */ - gen_ext_l(ctx, vc, va, rb, islit, lit, 0x01); - break; - case 0x0B: - /* INSBL */ - gen_ins_l(ctx, vc, va, rb, islit, lit, 0x01); - break; - case 0x12: - /* MSKWL */ - gen_msk_l(ctx, vc, va, rb, islit, lit, 0x03); - break; - case 0x16: - /* EXTWL */ - gen_ext_l(ctx, vc, va, rb, islit, lit, 0x03); - break; - case 0x1B: - /* INSWL */ - gen_ins_l(ctx, vc, va, rb, islit, lit, 0x03); - break; - case 0x22: - /* MSKLL */ - gen_msk_l(ctx, vc, va, rb, islit, lit, 0x0f); - break; - case 0x26: - /* EXTLL */ - gen_ext_l(ctx, vc, va, rb, islit, lit, 0x0f); - break; - case 0x2B: - /* INSLL */ - gen_ins_l(ctx, vc, va, rb, islit, lit, 0x0f); - break; - case 0x30: - /* ZAP */ - if (islit) { - gen_zapnoti(vc, va, ~lit); - } else { - gen_helper_zap(vc, va, load_gpr(ctx, rb)); - } - break; - case 0x31: - /* ZAPNOT */ - if (islit) { - gen_zapnoti(vc, va, lit); - } else { - gen_helper_zapnot(vc, va, load_gpr(ctx, rb)); - } - break; - case 0x32: - /* MSKQL */ - gen_msk_l(ctx, vc, va, rb, islit, lit, 0xff); - break; - case 0x34: - /* SRL */ - if (islit) { - tcg_gen_shri_i64(vc, va, lit & 0x3f); - } else { - tmp = tcg_temp_new(); - vb = load_gpr(ctx, rb); - tcg_gen_andi_i64(tmp, vb, 0x3f); - tcg_gen_shr_i64(vc, va, tmp); - tcg_temp_free(tmp); - } - break; - case 0x36: - /* EXTQL */ - gen_ext_l(ctx, vc, va, rb, islit, lit, 0xff); - break; - case 0x39: - /* SLL */ - if (islit) { - tcg_gen_shli_i64(vc, va, lit & 0x3f); - } else { - tmp = tcg_temp_new(); - vb = load_gpr(ctx, rb); - tcg_gen_andi_i64(tmp, vb, 0x3f); - tcg_gen_shl_i64(vc, va, tmp); - tcg_temp_free(tmp); - } - break; - case 0x3B: - /* INSQL */ - gen_ins_l(ctx, vc, va, rb, islit, lit, 0xff); - break; - case 0x3C: - /* SRA */ - if (islit) { - tcg_gen_sari_i64(vc, va, lit & 0x3f); - } else { - tmp = tcg_temp_new(); - vb = load_gpr(ctx, rb); - tcg_gen_andi_i64(tmp, vb, 0x3f); - tcg_gen_sar_i64(vc, va, tmp); - tcg_temp_free(tmp); - } - break; - case 0x52: - /* MSKWH */ - gen_msk_h(ctx, vc, va, rb, islit, lit, 0x03); - break; - case 0x57: - /* INSWH */ - gen_ins_h(ctx, vc, va, rb, islit, lit, 0x03); - break; - case 0x5A: - /* EXTWH */ - gen_ext_h(ctx, vc, va, rb, islit, lit, 0x03); - break; - case 0x62: - /* MSKLH */ - gen_msk_h(ctx, vc, va, rb, islit, lit, 0x0f); - break; - case 0x67: - /* INSLH */ - gen_ins_h(ctx, vc, va, rb, islit, lit, 0x0f); - break; - case 0x6A: - /* EXTLH */ - gen_ext_h(ctx, vc, va, rb, islit, lit, 0x0f); - break; - case 0x72: - /* MSKQH */ - gen_msk_h(ctx, vc, va, rb, islit, lit, 0xff); - break; - case 0x77: - /* INSQH */ - gen_ins_h(ctx, vc, va, rb, islit, lit, 0xff); - break; - case 0x7A: - /* EXTQH */ - gen_ext_h(ctx, vc, va, rb, islit, lit, 0xff); - break; - default: - goto invalid_opc; - } - break; - - case 0x13: - vc = dest_gpr(ctx, rc); - vb = load_gpr_lit(ctx, rb, lit, islit); - va = load_gpr(ctx, ra); - switch (fn7) { - case 0x00: - /* MULL */ - tcg_gen_mul_i64(vc, va, vb); - tcg_gen_ext32s_i64(vc, vc); - break; - case 0x20: - /* MULQ */ - tcg_gen_mul_i64(vc, va, vb); - break; - case 0x30: - /* UMULH */ - tmp = tcg_temp_new(); - tcg_gen_mulu2_i64(tmp, vc, va, vb); - tcg_temp_free(tmp); - break; - case 0x40: - /* MULL/V */ - tmp = tcg_temp_new(); - tcg_gen_ext32s_i64(tmp, va); - tcg_gen_ext32s_i64(vc, vb); - tcg_gen_mul_i64(tmp, tmp, vc); - tcg_gen_ext32s_i64(vc, tmp); - gen_helper_check_overflow(cpu_env, vc, tmp); - tcg_temp_free(tmp); - break; - case 0x60: - /* MULQ/V */ - tmp = tcg_temp_new(); - tmp2 = tcg_temp_new(); - tcg_gen_muls2_i64(vc, tmp, va, vb); - tcg_gen_sari_i64(tmp2, vc, 63); - gen_helper_check_overflow(cpu_env, tmp, tmp2); - tcg_temp_free(tmp); - tcg_temp_free(tmp2); - break; - default: - goto invalid_opc; - } - break; - - case 0x14: - REQUIRE_TB_FLAG(TB_FLAGS_AMASK_FIX); - vc = dest_fpr(ctx, rc); - switch (fpfn) { /* fn11 & 0x3F */ - case 0x04: - /* ITOFS */ - REQUIRE_REG_31(rb); - t32 = tcg_temp_new_i32(); - va = load_gpr(ctx, ra); - tcg_gen_extrl_i64_i32(t32, va); - gen_helper_memory_to_s(vc, t32); - tcg_temp_free_i32(t32); - break; - case 0x0A: - /* SQRTF */ - REQUIRE_REG_31(ra); - vb = load_fpr(ctx, rb); - gen_helper_sqrtf(vc, cpu_env, vb); - break; - case 0x0B: - /* SQRTS */ - REQUIRE_REG_31(ra); - gen_sqrts(ctx, rb, rc, fn11); - break; - case 0x14: - /* ITOFF */ - REQUIRE_REG_31(rb); - t32 = tcg_temp_new_i32(); - va = load_gpr(ctx, ra); - tcg_gen_extrl_i64_i32(t32, va); - gen_helper_memory_to_f(vc, t32); - tcg_temp_free_i32(t32); - break; - case 0x24: - /* ITOFT */ - REQUIRE_REG_31(rb); - va = load_gpr(ctx, ra); - tcg_gen_mov_i64(vc, va); - break; - case 0x2A: - /* SQRTG */ - REQUIRE_REG_31(ra); - vb = load_fpr(ctx, rb); - gen_helper_sqrtg(vc, cpu_env, vb); - break; - case 0x02B: - /* SQRTT */ - REQUIRE_REG_31(ra); - gen_sqrtt(ctx, rb, rc, fn11); - break; - default: - goto invalid_opc; - } - break; - - case 0x15: - /* VAX floating point */ - /* XXX: rounding mode and trap are ignored (!) */ - vc = dest_fpr(ctx, rc); - vb = load_fpr(ctx, rb); - va = load_fpr(ctx, ra); - switch (fpfn) { /* fn11 & 0x3F */ - case 0x00: - /* ADDF */ - gen_helper_addf(vc, cpu_env, va, vb); - break; - case 0x01: - /* SUBF */ - gen_helper_subf(vc, cpu_env, va, vb); - break; - case 0x02: - /* MULF */ - gen_helper_mulf(vc, cpu_env, va, vb); - break; - case 0x03: - /* DIVF */ - gen_helper_divf(vc, cpu_env, va, vb); - break; - case 0x1E: - /* CVTDG -- TODO */ - REQUIRE_REG_31(ra); - goto invalid_opc; - case 0x20: - /* ADDG */ - gen_helper_addg(vc, cpu_env, va, vb); - break; - case 0x21: - /* SUBG */ - gen_helper_subg(vc, cpu_env, va, vb); - break; - case 0x22: - /* MULG */ - gen_helper_mulg(vc, cpu_env, va, vb); - break; - case 0x23: - /* DIVG */ - gen_helper_divg(vc, cpu_env, va, vb); - break; - case 0x25: - /* CMPGEQ */ - gen_helper_cmpgeq(vc, cpu_env, va, vb); - break; - case 0x26: - /* CMPGLT */ - gen_helper_cmpglt(vc, cpu_env, va, vb); - break; - case 0x27: - /* CMPGLE */ - gen_helper_cmpgle(vc, cpu_env, va, vb); - break; - case 0x2C: - /* CVTGF */ - REQUIRE_REG_31(ra); - gen_helper_cvtgf(vc, cpu_env, vb); - break; - case 0x2D: - /* CVTGD -- TODO */ - REQUIRE_REG_31(ra); - goto invalid_opc; - case 0x2F: - /* CVTGQ */ - REQUIRE_REG_31(ra); - gen_helper_cvtgq(vc, cpu_env, vb); - break; - case 0x3C: - /* CVTQF */ - REQUIRE_REG_31(ra); - gen_helper_cvtqf(vc, cpu_env, vb); - break; - case 0x3E: - /* CVTQG */ - REQUIRE_REG_31(ra); - gen_helper_cvtqg(vc, cpu_env, vb); - break; - default: - goto invalid_opc; - } - break; - - case 0x16: - /* IEEE floating-point */ - switch (fpfn) { /* fn11 & 0x3F */ - case 0x00: - /* ADDS */ - gen_adds(ctx, ra, rb, rc, fn11); - break; - case 0x01: - /* SUBS */ - gen_subs(ctx, ra, rb, rc, fn11); - break; - case 0x02: - /* MULS */ - gen_muls(ctx, ra, rb, rc, fn11); - break; - case 0x03: - /* DIVS */ - gen_divs(ctx, ra, rb, rc, fn11); - break; - case 0x20: - /* ADDT */ - gen_addt(ctx, ra, rb, rc, fn11); - break; - case 0x21: - /* SUBT */ - gen_subt(ctx, ra, rb, rc, fn11); - break; - case 0x22: - /* MULT */ - gen_mult(ctx, ra, rb, rc, fn11); - break; - case 0x23: - /* DIVT */ - gen_divt(ctx, ra, rb, rc, fn11); - break; - case 0x24: - /* CMPTUN */ - gen_cmptun(ctx, ra, rb, rc, fn11); - break; - case 0x25: - /* CMPTEQ */ - gen_cmpteq(ctx, ra, rb, rc, fn11); - break; - case 0x26: - /* CMPTLT */ - gen_cmptlt(ctx, ra, rb, rc, fn11); - break; - case 0x27: - /* CMPTLE */ - gen_cmptle(ctx, ra, rb, rc, fn11); - break; - case 0x2C: - REQUIRE_REG_31(ra); - if (fn11 == 0x2AC || fn11 == 0x6AC) { - /* CVTST */ - gen_cvtst(ctx, rb, rc, fn11); - } else { - /* CVTTS */ - gen_cvtts(ctx, rb, rc, fn11); - } - break; - case 0x2F: - /* CVTTQ */ - REQUIRE_REG_31(ra); - gen_cvttq(ctx, rb, rc, fn11); - break; - case 0x3C: - /* CVTQS */ - REQUIRE_REG_31(ra); - gen_cvtqs(ctx, rb, rc, fn11); - break; - case 0x3E: - /* CVTQT */ - REQUIRE_REG_31(ra); - gen_cvtqt(ctx, rb, rc, fn11); - break; - default: - goto invalid_opc; - } - break; - - case 0x17: - switch (fn11) { - case 0x010: - /* CVTLQ */ - REQUIRE_REG_31(ra); - vc = dest_fpr(ctx, rc); - vb = load_fpr(ctx, rb); - gen_cvtlq(vc, vb); - break; - case 0x020: - /* CPYS */ - if (rc == 31) { - /* Special case CPYS as FNOP. */ - } else { - vc = dest_fpr(ctx, rc); - va = load_fpr(ctx, ra); - if (ra == rb) { - /* Special case CPYS as FMOV. */ - tcg_gen_mov_i64(vc, va); - } else { - vb = load_fpr(ctx, rb); - gen_cpy_mask(vc, va, vb, 0, 0x8000000000000000ULL); - } - } - break; - case 0x021: - /* CPYSN */ - vc = dest_fpr(ctx, rc); - vb = load_fpr(ctx, rb); - va = load_fpr(ctx, ra); - gen_cpy_mask(vc, va, vb, 1, 0x8000000000000000ULL); - break; - case 0x022: - /* CPYSE */ - vc = dest_fpr(ctx, rc); - vb = load_fpr(ctx, rb); - va = load_fpr(ctx, ra); - gen_cpy_mask(vc, va, vb, 0, 0xFFF0000000000000ULL); - break; - case 0x024: - /* MT_FPCR */ - va = load_fpr(ctx, ra); - gen_helper_store_fpcr(cpu_env, va); - if (ctx->tb_rm == QUAL_RM_D) { - /* Re-do the copy of the rounding mode to fp_status - the next time we use dynamic rounding. */ - ctx->tb_rm = -1; - } - break; - case 0x025: - /* MF_FPCR */ - va = dest_fpr(ctx, ra); - gen_helper_load_fpcr(va, cpu_env); - break; - case 0x02A: - /* FCMOVEQ */ - gen_fcmov(ctx, TCG_COND_EQ, ra, rb, rc); - break; - case 0x02B: - /* FCMOVNE */ - gen_fcmov(ctx, TCG_COND_NE, ra, rb, rc); - break; - case 0x02C: - /* FCMOVLT */ - gen_fcmov(ctx, TCG_COND_LT, ra, rb, rc); - break; - case 0x02D: - /* FCMOVGE */ - gen_fcmov(ctx, TCG_COND_GE, ra, rb, rc); - break; - case 0x02E: - /* FCMOVLE */ - gen_fcmov(ctx, TCG_COND_LE, ra, rb, rc); - break; - case 0x02F: - /* FCMOVGT */ - gen_fcmov(ctx, TCG_COND_GT, ra, rb, rc); - break; - case 0x030: /* CVTQL */ - case 0x130: /* CVTQL/V */ - case 0x530: /* CVTQL/SV */ - REQUIRE_REG_31(ra); - vc = dest_fpr(ctx, rc); - vb = load_fpr(ctx, rb); - gen_helper_cvtql(vc, cpu_env, vb); - gen_fp_exc_raise(rc, fn11); - break; - default: - goto invalid_opc; - } - break; - - case 0x18: - switch ((uint16_t)disp16) { - case 0x0000: - /* TRAPB */ - /* No-op. */ - break; - case 0x0400: - /* EXCB */ - /* No-op. */ - break; - case 0x4000: - /* MB */ - tcg_gen_mb(TCG_MO_ALL | TCG_BAR_SC); - break; - case 0x4400: - /* WMB */ - tcg_gen_mb(TCG_MO_ST_ST | TCG_BAR_SC); - break; - case 0x8000: - /* FETCH */ - /* No-op */ - break; - case 0xA000: - /* FETCH_M */ - /* No-op */ - break; - case 0xC000: - /* RPCC */ - va = dest_gpr(ctx, ra); - if (ctx->tb->cflags & CF_USE_ICOUNT) { - gen_io_start(); - gen_helper_load_pcc(va, cpu_env); - gen_io_end(); - ret = EXIT_PC_STALE; - } else { - gen_helper_load_pcc(va, cpu_env); - } - break; - case 0xE000: - /* RC */ - gen_rx(ctx, ra, 0); - break; - case 0xE800: - /* ECB */ - break; - case 0xF000: - /* RS */ - gen_rx(ctx, ra, 1); - break; - case 0xF800: - /* WH64 */ - /* No-op */ - break; - case 0xFC00: - /* WH64EN */ - /* No-op */ - break; - default: - goto invalid_opc; - } - break; - - case 0x19: - /* HW_MFPR (PALcode) */ -#ifndef CONFIG_USER_ONLY - REQUIRE_TB_FLAG(TB_FLAGS_PAL_MODE); - va = dest_gpr(ctx, ra); - ret = gen_mfpr(ctx, va, insn & 0xffff); - break; -#else - goto invalid_opc; -#endif - - case 0x1A: - /* JMP, JSR, RET, JSR_COROUTINE. These only differ by the branch - prediction stack action, which of course we don't implement. */ - vb = load_gpr(ctx, rb); - tcg_gen_andi_i64(cpu_pc, vb, ~3); - if (ra != 31) { - tcg_gen_movi_i64(ctx->ir[ra], ctx->pc); - } - ret = EXIT_PC_UPDATED; - break; - - case 0x1B: - /* HW_LD (PALcode) */ -#ifndef CONFIG_USER_ONLY - REQUIRE_TB_FLAG(TB_FLAGS_PAL_MODE); - { - TCGv addr = tcg_temp_new(); - vb = load_gpr(ctx, rb); - va = dest_gpr(ctx, ra); - - tcg_gen_addi_i64(addr, vb, disp12); - switch ((insn >> 12) & 0xF) { - case 0x0: - /* Longword physical access (hw_ldl/p) */ - tcg_gen_qemu_ld_i64(va, addr, MMU_PHYS_IDX, MO_LESL); - break; - case 0x1: - /* Quadword physical access (hw_ldq/p) */ - tcg_gen_qemu_ld_i64(va, addr, MMU_PHYS_IDX, MO_LEQ); - break; - case 0x2: - /* Longword physical access with lock (hw_ldl_l/p) */ - gen_qemu_ldl_l(va, addr, MMU_PHYS_IDX); - break; - case 0x3: - /* Quadword physical access with lock (hw_ldq_l/p) */ - gen_qemu_ldq_l(va, addr, MMU_PHYS_IDX); - break; - case 0x4: - /* Longword virtual PTE fetch (hw_ldl/v) */ - goto invalid_opc; - case 0x5: - /* Quadword virtual PTE fetch (hw_ldq/v) */ - goto invalid_opc; - break; - case 0x6: - /* Invalid */ - goto invalid_opc; - case 0x7: - /* Invaliid */ - goto invalid_opc; - case 0x8: - /* Longword virtual access (hw_ldl) */ - goto invalid_opc; - case 0x9: - /* Quadword virtual access (hw_ldq) */ - goto invalid_opc; - case 0xA: - /* Longword virtual access with protection check (hw_ldl/w) */ - tcg_gen_qemu_ld_i64(va, addr, MMU_KERNEL_IDX, MO_LESL); - break; - case 0xB: - /* Quadword virtual access with protection check (hw_ldq/w) */ - tcg_gen_qemu_ld_i64(va, addr, MMU_KERNEL_IDX, MO_LEQ); - break; - case 0xC: - /* Longword virtual access with alt access mode (hw_ldl/a)*/ - goto invalid_opc; - case 0xD: - /* Quadword virtual access with alt access mode (hw_ldq/a) */ - goto invalid_opc; - case 0xE: - /* Longword virtual access with alternate access mode and - protection checks (hw_ldl/wa) */ - tcg_gen_qemu_ld_i64(va, addr, MMU_USER_IDX, MO_LESL); - break; - case 0xF: - /* Quadword virtual access with alternate access mode and - protection checks (hw_ldq/wa) */ - tcg_gen_qemu_ld_i64(va, addr, MMU_USER_IDX, MO_LEQ); - break; - } - tcg_temp_free(addr); - break; - } -#else - goto invalid_opc; -#endif - - case 0x1C: - vc = dest_gpr(ctx, rc); - if (fn7 == 0x70) { - /* FTOIT */ - REQUIRE_TB_FLAG(TB_FLAGS_AMASK_FIX); - REQUIRE_REG_31(rb); - va = load_fpr(ctx, ra); - tcg_gen_mov_i64(vc, va); - break; - } else if (fn7 == 0x78) { - /* FTOIS */ - REQUIRE_TB_FLAG(TB_FLAGS_AMASK_FIX); - REQUIRE_REG_31(rb); - t32 = tcg_temp_new_i32(); - va = load_fpr(ctx, ra); - gen_helper_s_to_memory(t32, va); - tcg_gen_ext_i32_i64(vc, t32); - tcg_temp_free_i32(t32); - break; - } - - vb = load_gpr_lit(ctx, rb, lit, islit); - switch (fn7) { - case 0x00: - /* SEXTB */ - REQUIRE_TB_FLAG(TB_FLAGS_AMASK_BWX); - REQUIRE_REG_31(ra); - tcg_gen_ext8s_i64(vc, vb); - break; - case 0x01: - /* SEXTW */ - REQUIRE_TB_FLAG(TB_FLAGS_AMASK_BWX); - REQUIRE_REG_31(ra); - tcg_gen_ext16s_i64(vc, vb); - break; - case 0x30: - /* CTPOP */ - REQUIRE_TB_FLAG(TB_FLAGS_AMASK_CIX); - REQUIRE_REG_31(ra); - REQUIRE_NO_LIT; - gen_helper_ctpop(vc, vb); - break; - case 0x31: - /* PERR */ - REQUIRE_TB_FLAG(TB_FLAGS_AMASK_MVI); - REQUIRE_NO_LIT; - va = load_gpr(ctx, ra); - gen_helper_perr(vc, va, vb); - break; - case 0x32: - /* CTLZ */ - REQUIRE_TB_FLAG(TB_FLAGS_AMASK_CIX); - REQUIRE_REG_31(ra); - REQUIRE_NO_LIT; - gen_helper_ctlz(vc, vb); - break; - case 0x33: - /* CTTZ */ - REQUIRE_TB_FLAG(TB_FLAGS_AMASK_CIX); - REQUIRE_REG_31(ra); - REQUIRE_NO_LIT; - gen_helper_cttz(vc, vb); - break; - case 0x34: - /* UNPKBW */ - REQUIRE_TB_FLAG(TB_FLAGS_AMASK_MVI); - REQUIRE_REG_31(ra); - REQUIRE_NO_LIT; - gen_helper_unpkbw(vc, vb); - break; - case 0x35: - /* UNPKBL */ - REQUIRE_TB_FLAG(TB_FLAGS_AMASK_MVI); - REQUIRE_REG_31(ra); - REQUIRE_NO_LIT; - gen_helper_unpkbl(vc, vb); - break; - case 0x36: - /* PKWB */ - REQUIRE_TB_FLAG(TB_FLAGS_AMASK_MVI); - REQUIRE_REG_31(ra); - REQUIRE_NO_LIT; - gen_helper_pkwb(vc, vb); - break; - case 0x37: - /* PKLB */ - REQUIRE_TB_FLAG(TB_FLAGS_AMASK_MVI); - REQUIRE_REG_31(ra); - REQUIRE_NO_LIT; - gen_helper_pklb(vc, vb); - break; - case 0x38: - /* MINSB8 */ - REQUIRE_TB_FLAG(TB_FLAGS_AMASK_MVI); - va = load_gpr(ctx, ra); - gen_helper_minsb8(vc, va, vb); - break; - case 0x39: - /* MINSW4 */ - REQUIRE_TB_FLAG(TB_FLAGS_AMASK_MVI); - va = load_gpr(ctx, ra); - gen_helper_minsw4(vc, va, vb); - break; - case 0x3A: - /* MINUB8 */ - REQUIRE_TB_FLAG(TB_FLAGS_AMASK_MVI); - va = load_gpr(ctx, ra); - gen_helper_minub8(vc, va, vb); - break; - case 0x3B: - /* MINUW4 */ - REQUIRE_TB_FLAG(TB_FLAGS_AMASK_MVI); - va = load_gpr(ctx, ra); - gen_helper_minuw4(vc, va, vb); - break; - case 0x3C: - /* MAXUB8 */ - REQUIRE_TB_FLAG(TB_FLAGS_AMASK_MVI); - va = load_gpr(ctx, ra); - gen_helper_maxub8(vc, va, vb); - break; - case 0x3D: - /* MAXUW4 */ - REQUIRE_TB_FLAG(TB_FLAGS_AMASK_MVI); - va = load_gpr(ctx, ra); - gen_helper_maxuw4(vc, va, vb); - break; - case 0x3E: - /* MAXSB8 */ - REQUIRE_TB_FLAG(TB_FLAGS_AMASK_MVI); - va = load_gpr(ctx, ra); - gen_helper_maxsb8(vc, va, vb); - break; - case 0x3F: - /* MAXSW4 */ - REQUIRE_TB_FLAG(TB_FLAGS_AMASK_MVI); - va = load_gpr(ctx, ra); - gen_helper_maxsw4(vc, va, vb); - break; - default: - goto invalid_opc; - } - break; - - case 0x1D: - /* HW_MTPR (PALcode) */ -#ifndef CONFIG_USER_ONLY - REQUIRE_TB_FLAG(TB_FLAGS_PAL_MODE); - vb = load_gpr(ctx, rb); - ret = gen_mtpr(ctx, vb, insn & 0xffff); - break; -#else - goto invalid_opc; -#endif - - case 0x1E: - /* HW_RET (PALcode) */ -#ifndef CONFIG_USER_ONLY - REQUIRE_TB_FLAG(TB_FLAGS_PAL_MODE); - if (rb == 31) { - /* Pre-EV6 CPUs interpreted this as HW_REI, loading the return - address from EXC_ADDR. This turns out to be useful for our - emulation PALcode, so continue to accept it. */ - ctx->lit = vb = tcg_temp_new(); - tcg_gen_ld_i64(vb, cpu_env, offsetof(CPUAlphaState, exc_addr)); - } else { - vb = load_gpr(ctx, rb); - } - tmp = tcg_temp_new(); - tcg_gen_movi_i64(tmp, 0); - tcg_gen_st8_i64(tmp, cpu_env, offsetof(CPUAlphaState, intr_flag)); - tcg_gen_movi_i64(cpu_lock_addr, -1); - tcg_gen_andi_i64(tmp, vb, 1); - tcg_gen_st8_i64(tmp, cpu_env, offsetof(CPUAlphaState, pal_mode)); - tcg_gen_andi_i64(cpu_pc, vb, ~3); - ret = EXIT_PC_UPDATED; - break; -#else - goto invalid_opc; -#endif - - case 0x1F: - /* HW_ST (PALcode) */ -#ifndef CONFIG_USER_ONLY - REQUIRE_TB_FLAG(TB_FLAGS_PAL_MODE); - { - switch ((insn >> 12) & 0xF) { - case 0x0: - /* Longword physical access */ - va = load_gpr(ctx, ra); - vb = load_gpr(ctx, rb); - tmp = tcg_temp_new(); - tcg_gen_addi_i64(tmp, vb, disp12); - tcg_gen_qemu_st_i64(va, tmp, MMU_PHYS_IDX, MO_LESL); - tcg_temp_free(tmp); - break; - case 0x1: - /* Quadword physical access */ - va = load_gpr(ctx, ra); - vb = load_gpr(ctx, rb); - tmp = tcg_temp_new(); - tcg_gen_addi_i64(tmp, vb, disp12); - tcg_gen_qemu_st_i64(va, tmp, MMU_PHYS_IDX, MO_LEQ); - tcg_temp_free(tmp); - break; - case 0x2: - /* Longword physical access with lock */ - ret = gen_store_conditional(ctx, ra, rb, disp12, - MMU_PHYS_IDX, MO_LESL); - break; - case 0x3: - /* Quadword physical access with lock */ - ret = gen_store_conditional(ctx, ra, rb, disp12, - MMU_PHYS_IDX, MO_LEQ); - break; - case 0x4: - /* Longword virtual access */ - goto invalid_opc; - case 0x5: - /* Quadword virtual access */ - goto invalid_opc; - case 0x6: - /* Invalid */ - goto invalid_opc; - case 0x7: - /* Invalid */ - goto invalid_opc; - case 0x8: - /* Invalid */ - goto invalid_opc; - case 0x9: - /* Invalid */ - goto invalid_opc; - case 0xA: - /* Invalid */ - goto invalid_opc; - case 0xB: - /* Invalid */ - goto invalid_opc; - case 0xC: - /* Longword virtual access with alternate access mode */ - goto invalid_opc; - case 0xD: - /* Quadword virtual access with alternate access mode */ - goto invalid_opc; - case 0xE: - /* Invalid */ - goto invalid_opc; - case 0xF: - /* Invalid */ - goto invalid_opc; - } - break; - } -#else - goto invalid_opc; -#endif - case 0x20: - /* LDF */ - gen_load_mem(ctx, &gen_qemu_ldf, ra, rb, disp16, 1, 0); - break; - case 0x21: - /* LDG */ - gen_load_mem(ctx, &gen_qemu_ldg, ra, rb, disp16, 1, 0); - break; - case 0x22: - /* LDS */ - gen_load_mem(ctx, &gen_qemu_lds, ra, rb, disp16, 1, 0); - break; - case 0x23: - /* LDT */ - gen_load_mem(ctx, &tcg_gen_qemu_ld64, ra, rb, disp16, 1, 0); - break; - case 0x24: - /* STF */ - gen_store_mem(ctx, &gen_qemu_stf, ra, rb, disp16, 1, 0); - break; - case 0x25: - /* STG */ - gen_store_mem(ctx, &gen_qemu_stg, ra, rb, disp16, 1, 0); - break; - case 0x26: - /* STS */ - gen_store_mem(ctx, &gen_qemu_sts, ra, rb, disp16, 1, 0); - break; - case 0x27: - /* STT */ - gen_store_mem(ctx, &tcg_gen_qemu_st64, ra, rb, disp16, 1, 0); - break; - case 0x28: - /* LDL */ - gen_load_mem(ctx, &tcg_gen_qemu_ld32s, ra, rb, disp16, 0, 0); - break; - case 0x29: - /* LDQ */ - gen_load_mem(ctx, &tcg_gen_qemu_ld64, ra, rb, disp16, 0, 0); - break; - case 0x2A: - /* LDL_L */ - gen_load_mem(ctx, &gen_qemu_ldl_l, ra, rb, disp16, 0, 0); - break; - case 0x2B: - /* LDQ_L */ - gen_load_mem(ctx, &gen_qemu_ldq_l, ra, rb, disp16, 0, 0); - break; - case 0x2C: - /* STL */ - gen_store_mem(ctx, &tcg_gen_qemu_st32, ra, rb, disp16, 0, 0); - break; - case 0x2D: - /* STQ */ - gen_store_mem(ctx, &tcg_gen_qemu_st64, ra, rb, disp16, 0, 0); - break; - case 0x2E: - /* STL_C */ - ret = gen_store_conditional(ctx, ra, rb, disp16, - ctx->mem_idx, MO_LESL); - break; - case 0x2F: - /* STQ_C */ - ret = gen_store_conditional(ctx, ra, rb, disp16, - ctx->mem_idx, MO_LEQ); - break; - case 0x30: - /* BR */ - ret = gen_bdirect(ctx, ra, disp21); - break; - case 0x31: /* FBEQ */ - ret = gen_fbcond(ctx, TCG_COND_EQ, ra, disp21); - break; - case 0x32: /* FBLT */ - ret = gen_fbcond(ctx, TCG_COND_LT, ra, disp21); - break; - case 0x33: /* FBLE */ - ret = gen_fbcond(ctx, TCG_COND_LE, ra, disp21); - break; - case 0x34: - /* BSR */ - ret = gen_bdirect(ctx, ra, disp21); - break; - case 0x35: /* FBNE */ - ret = gen_fbcond(ctx, TCG_COND_NE, ra, disp21); - break; - case 0x36: /* FBGE */ - ret = gen_fbcond(ctx, TCG_COND_GE, ra, disp21); - break; - case 0x37: /* FBGT */ - ret = gen_fbcond(ctx, TCG_COND_GT, ra, disp21); - break; - case 0x38: - /* BLBC */ - ret = gen_bcond(ctx, TCG_COND_EQ, ra, disp21, 1); - break; - case 0x39: - /* BEQ */ - ret = gen_bcond(ctx, TCG_COND_EQ, ra, disp21, 0); - break; - case 0x3A: - /* BLT */ - ret = gen_bcond(ctx, TCG_COND_LT, ra, disp21, 0); - break; - case 0x3B: - /* BLE */ - ret = gen_bcond(ctx, TCG_COND_LE, ra, disp21, 0); - break; - case 0x3C: - /* BLBS */ - ret = gen_bcond(ctx, TCG_COND_NE, ra, disp21, 1); - break; - case 0x3D: - /* BNE */ - ret = gen_bcond(ctx, TCG_COND_NE, ra, disp21, 0); - break; - case 0x3E: - /* BGE */ - ret = gen_bcond(ctx, TCG_COND_GE, ra, disp21, 0); - break; - case 0x3F: - /* BGT */ - ret = gen_bcond(ctx, TCG_COND_GT, ra, disp21, 0); - break; - invalid_opc: - ret = gen_invalid(ctx); - break; - } - - return ret; -} - -void gen_intermediate_code(CPUAlphaState *env, struct TranslationBlock *tb) -{ - AlphaCPU *cpu = alpha_env_get_cpu(env); - CPUState *cs = CPU(cpu); - DisasContext ctx, *ctxp = &ctx; - target_ulong pc_start; - target_ulong pc_mask; - uint32_t insn; - ExitStatus ret; - int num_insns; - int max_insns; - - pc_start = tb->pc; - - ctx.tb = tb; - ctx.pc = pc_start; - ctx.mem_idx = cpu_mmu_index(env, false); - ctx.implver = env->implver; - ctx.singlestep_enabled = cs->singlestep_enabled; - -#ifdef CONFIG_USER_ONLY - ctx.ir = cpu_std_ir; -#else - ctx.palbr = env->palbr; - ctx.ir = (tb->flags & TB_FLAGS_PAL_MODE ? cpu_pal_ir : cpu_std_ir); -#endif - - /* ??? Every TB begins with unset rounding mode, to be initialized on - the first fp insn of the TB. Alternately we could define a proper - default for every TB (e.g. QUAL_RM_N or QUAL_RM_D) and make sure - to reset the FP_STATUS to that default at the end of any TB that - changes the default. We could even (gasp) dynamiclly figure out - what default would be most efficient given the running program. */ - ctx.tb_rm = -1; - /* Similarly for flush-to-zero. */ - ctx.tb_ftz = -1; - - TCGV_UNUSED_I64(ctx.zero); - TCGV_UNUSED_I64(ctx.sink); - TCGV_UNUSED_I64(ctx.lit); - - num_insns = 0; - max_insns = tb->cflags & CF_COUNT_MASK; - if (max_insns == 0) { - max_insns = CF_COUNT_MASK; - } - if (max_insns > TCG_MAX_INSNS) { - max_insns = TCG_MAX_INSNS; - } - - if (in_superpage(&ctx, pc_start)) { - pc_mask = (1ULL << 41) - 1; - } else { - pc_mask = ~TARGET_PAGE_MASK; - } - - gen_tb_start(tb); - do { - tcg_gen_insn_start(ctx.pc); - num_insns++; - - if (unlikely(cpu_breakpoint_test(cs, ctx.pc, BP_ANY))) { - ret = gen_excp(&ctx, EXCP_DEBUG, 0); - /* The address covered by the breakpoint must be included in - [tb->pc, tb->pc + tb->size) in order to for it to be - properly cleared -- thus we increment the PC here so that - the logic setting tb->size below does the right thing. */ - ctx.pc += 4; - break; - } - if (num_insns == max_insns && (tb->cflags & CF_LAST_IO)) { - gen_io_start(); - } - insn = cpu_ldl_code(env, ctx.pc); - - ctx.pc += 4; - ret = translate_one(ctxp, insn); - free_context_temps(ctxp); - - /* If we reach a page boundary, are single stepping, - or exhaust instruction count, stop generation. */ - if (ret == NO_EXIT - && ((ctx.pc & pc_mask) == 0 - || tcg_op_buf_full() - || num_insns >= max_insns - || singlestep - || ctx.singlestep_enabled)) { - ret = EXIT_PC_STALE; - } - } while (ret == NO_EXIT); - - if (tb->cflags & CF_LAST_IO) { - gen_io_end(); - } - - switch (ret) { - case EXIT_GOTO_TB: - case EXIT_NORETURN: - break; - case EXIT_PC_STALE: - tcg_gen_movi_i64(cpu_pc, ctx.pc); - /* FALLTHRU */ - case EXIT_PC_UPDATED: - if (ctx.singlestep_enabled) { - gen_excp_1(EXCP_DEBUG, 0); - } else { - tcg_gen_exit_tb(0); - } - break; - default: - abort(); - } - - gen_tb_end(tb, num_insns); - - tb->size = ctx.pc - pc_start; - tb->icount = num_insns; - -#ifdef DEBUG_DISAS - if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM) - && qemu_log_in_addr_range(pc_start)) { - qemu_log_lock(); - qemu_log("IN: %s\n", lookup_symbol(pc_start)); - log_target_disas(cs, pc_start, ctx.pc - pc_start, 1); - qemu_log("\n"); - qemu_log_unlock(); - } -#endif -} - -void restore_state_to_opc(CPUAlphaState *env, TranslationBlock *tb, - target_ulong *data) -{ - env->pc = data[0]; -} diff --git a/target-alpha/vax_helper.c b/target-alpha/vax_helper.c deleted file mode 100644 index 2b0c178..0000000 --- a/target-alpha/vax_helper.c +++ /dev/null @@ -1,355 +0,0 @@ -/* - * Helpers for vax floating point instructions. - * - * Copyright (c) 2007 Jocelyn Mayer - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/>. - */ - -#include "qemu/osdep.h" -#include "cpu.h" -#include "exec/exec-all.h" -#include "exec/helper-proto.h" -#include "fpu/softfloat.h" - -#define FP_STATUS (env->fp_status) - - -/* F floating (VAX) */ -static uint64_t float32_to_f(float32 fa) -{ - uint64_t r, exp, mant, sig; - CPU_FloatU a; - - a.f = fa; - sig = ((uint64_t)a.l & 0x80000000) << 32; - exp = (a.l >> 23) & 0xff; - mant = ((uint64_t)a.l & 0x007fffff) << 29; - - if (exp == 255) { - /* NaN or infinity */ - r = 1; /* VAX dirty zero */ - } else if (exp == 0) { - if (mant == 0) { - /* Zero */ - r = 0; - } else { - /* Denormalized */ - r = sig | ((exp + 1) << 52) | mant; - } - } else { - if (exp >= 253) { - /* Overflow */ - r = 1; /* VAX dirty zero */ - } else { - r = sig | ((exp + 2) << 52); - } - } - - return r; -} - -static float32 f_to_float32(CPUAlphaState *env, uintptr_t retaddr, uint64_t a) -{ - uint32_t exp, mant_sig; - CPU_FloatU r; - - exp = ((a >> 55) & 0x80) | ((a >> 52) & 0x7f); - mant_sig = ((a >> 32) & 0x80000000) | ((a >> 29) & 0x007fffff); - - if (unlikely(!exp && mant_sig)) { - /* Reserved operands / Dirty zero */ - dynamic_excp(env, retaddr, EXCP_OPCDEC, 0); - } - - if (exp < 3) { - /* Underflow */ - r.l = 0; - } else { - r.l = ((exp - 2) << 23) | mant_sig; - } - - return r.f; -} - -uint32_t helper_f_to_memory(uint64_t a) -{ - uint32_t r; - r = (a & 0x00001fffe0000000ull) >> 13; - r |= (a & 0x07ffe00000000000ull) >> 45; - r |= (a & 0xc000000000000000ull) >> 48; - return r; -} - -uint64_t helper_memory_to_f(uint32_t a) -{ - uint64_t r; - r = ((uint64_t)(a & 0x0000c000)) << 48; - r |= ((uint64_t)(a & 0x003fffff)) << 45; - r |= ((uint64_t)(a & 0xffff0000)) << 13; - if (!(a & 0x00004000)) { - r |= 0x7ll << 59; - } - return r; -} - -/* ??? Emulating VAX arithmetic with IEEE arithmetic is wrong. We should - either implement VAX arithmetic properly or just signal invalid opcode. */ - -uint64_t helper_addf(CPUAlphaState *env, uint64_t a, uint64_t b) -{ - float32 fa, fb, fr; - - fa = f_to_float32(env, GETPC(), a); - fb = f_to_float32(env, GETPC(), b); - fr = float32_add(fa, fb, &FP_STATUS); - return float32_to_f(fr); -} - -uint64_t helper_subf(CPUAlphaState *env, uint64_t a, uint64_t b) -{ - float32 fa, fb, fr; - - fa = f_to_float32(env, GETPC(), a); - fb = f_to_float32(env, GETPC(), b); - fr = float32_sub(fa, fb, &FP_STATUS); - return float32_to_f(fr); -} - -uint64_t helper_mulf(CPUAlphaState *env, uint64_t a, uint64_t b) -{ - float32 fa, fb, fr; - - fa = f_to_float32(env, GETPC(), a); - fb = f_to_float32(env, GETPC(), b); - fr = float32_mul(fa, fb, &FP_STATUS); - return float32_to_f(fr); -} - -uint64_t helper_divf(CPUAlphaState *env, uint64_t a, uint64_t b) -{ - float32 fa, fb, fr; - - fa = f_to_float32(env, GETPC(), a); - fb = f_to_float32(env, GETPC(), b); - fr = float32_div(fa, fb, &FP_STATUS); - return float32_to_f(fr); -} - -uint64_t helper_sqrtf(CPUAlphaState *env, uint64_t t) -{ - float32 ft, fr; - - ft = f_to_float32(env, GETPC(), t); - fr = float32_sqrt(ft, &FP_STATUS); - return float32_to_f(fr); -} - - -/* G floating (VAX) */ -static uint64_t float64_to_g(float64 fa) -{ - uint64_t r, exp, mant, sig; - CPU_DoubleU a; - - a.d = fa; - sig = a.ll & 0x8000000000000000ull; - exp = (a.ll >> 52) & 0x7ff; - mant = a.ll & 0x000fffffffffffffull; - - if (exp == 2047) { - /* NaN or infinity */ - r = 1; /* VAX dirty zero */ - } else if (exp == 0) { - if (mant == 0) { - /* Zero */ - r = 0; - } else { - /* Denormalized */ - r = sig | ((exp + 1) << 52) | mant; - } - } else { - if (exp >= 2045) { - /* Overflow */ - r = 1; /* VAX dirty zero */ - } else { - r = sig | ((exp + 2) << 52); - } - } - - return r; -} - -static float64 g_to_float64(CPUAlphaState *env, uintptr_t retaddr, uint64_t a) -{ - uint64_t exp, mant_sig; - CPU_DoubleU r; - - exp = (a >> 52) & 0x7ff; - mant_sig = a & 0x800fffffffffffffull; - - if (!exp && mant_sig) { - /* Reserved operands / Dirty zero */ - dynamic_excp(env, retaddr, EXCP_OPCDEC, 0); - } - - if (exp < 3) { - /* Underflow */ - r.ll = 0; - } else { - r.ll = ((exp - 2) << 52) | mant_sig; - } - - return r.d; -} - -uint64_t helper_g_to_memory(uint64_t a) -{ - uint64_t r; - r = (a & 0x000000000000ffffull) << 48; - r |= (a & 0x00000000ffff0000ull) << 16; - r |= (a & 0x0000ffff00000000ull) >> 16; - r |= (a & 0xffff000000000000ull) >> 48; - return r; -} - -uint64_t helper_memory_to_g(uint64_t a) -{ - uint64_t r; - r = (a & 0x000000000000ffffull) << 48; - r |= (a & 0x00000000ffff0000ull) << 16; - r |= (a & 0x0000ffff00000000ull) >> 16; - r |= (a & 0xffff000000000000ull) >> 48; - return r; -} - -uint64_t helper_addg(CPUAlphaState *env, uint64_t a, uint64_t b) -{ - float64 fa, fb, fr; - - fa = g_to_float64(env, GETPC(), a); - fb = g_to_float64(env, GETPC(), b); - fr = float64_add(fa, fb, &FP_STATUS); - return float64_to_g(fr); -} - -uint64_t helper_subg(CPUAlphaState *env, uint64_t a, uint64_t b) -{ - float64 fa, fb, fr; - - fa = g_to_float64(env, GETPC(), a); - fb = g_to_float64(env, GETPC(), b); - fr = float64_sub(fa, fb, &FP_STATUS); - return float64_to_g(fr); -} - -uint64_t helper_mulg(CPUAlphaState *env, uint64_t a, uint64_t b) -{ - float64 fa, fb, fr; - - fa = g_to_float64(env, GETPC(), a); - fb = g_to_float64(env, GETPC(), b); - fr = float64_mul(fa, fb, &FP_STATUS); - return float64_to_g(fr); -} - -uint64_t helper_divg(CPUAlphaState *env, uint64_t a, uint64_t b) -{ - float64 fa, fb, fr; - - fa = g_to_float64(env, GETPC(), a); - fb = g_to_float64(env, GETPC(), b); - fr = float64_div(fa, fb, &FP_STATUS); - return float64_to_g(fr); -} - -uint64_t helper_sqrtg(CPUAlphaState *env, uint64_t a) -{ - float64 fa, fr; - - fa = g_to_float64(env, GETPC(), a); - fr = float64_sqrt(fa, &FP_STATUS); - return float64_to_g(fr); -} - -uint64_t helper_cmpgeq(CPUAlphaState *env, uint64_t a, uint64_t b) -{ - float64 fa, fb; - - fa = g_to_float64(env, GETPC(), a); - fb = g_to_float64(env, GETPC(), b); - - if (float64_eq_quiet(fa, fb, &FP_STATUS)) { - return 0x4000000000000000ULL; - } else { - return 0; - } -} - -uint64_t helper_cmpgle(CPUAlphaState *env, uint64_t a, uint64_t b) -{ - float64 fa, fb; - - fa = g_to_float64(env, GETPC(), a); - fb = g_to_float64(env, GETPC(), b); - - if (float64_le(fa, fb, &FP_STATUS)) { - return 0x4000000000000000ULL; - } else { - return 0; - } -} - -uint64_t helper_cmpglt(CPUAlphaState *env, uint64_t a, uint64_t b) -{ - float64 fa, fb; - - fa = g_to_float64(env, GETPC(), a); - fb = g_to_float64(env, GETPC(), b); - - if (float64_lt(fa, fb, &FP_STATUS)) { - return 0x4000000000000000ULL; - } else { - return 0; - } -} - -uint64_t helper_cvtqf(CPUAlphaState *env, uint64_t a) -{ - float32 fr = int64_to_float32(a, &FP_STATUS); - return float32_to_f(fr); -} - -uint64_t helper_cvtgf(CPUAlphaState *env, uint64_t a) -{ - float64 fa; - float32 fr; - - fa = g_to_float64(env, GETPC(), a); - fr = float64_to_float32(fa, &FP_STATUS); - return float32_to_f(fr); -} - -uint64_t helper_cvtgq(CPUAlphaState *env, uint64_t a) -{ - float64 fa = g_to_float64(env, GETPC(), a); - return float64_to_int64_round_to_zero(fa, &FP_STATUS); -} - -uint64_t helper_cvtqg(CPUAlphaState *env, uint64_t a) -{ - float64 fr; - fr = int64_to_float64(a, &FP_STATUS); - return float64_to_g(fr); -} |