diff --git a/BinDir.tar.gz b/BinDir.tar.gz index 313f1fe4ec24d08eb57204d497834eb9262f9787..3642262e92563a532519a197d212fa3de78d3d6e 100644 Binary files a/BinDir.tar.gz and b/BinDir.tar.gz differ diff --git a/qemu.spec b/qemu.spec index 28fa8f3aa5259816875b0a7952eeffb56d53da54..9ae6a04eae498d6b4391d693629b5e400cf13072 100644 --- a/qemu.spec +++ b/qemu.spec @@ -1,6 +1,6 @@ Name: qemu Version: 6.2.0 -Release: 24 +Release: 25 Epoch: 2 Summary: QEMU is a generic and open source machine emulator and virtualizer License: GPLv2 and BSD and MIT and CC-BY-SA-4.0 @@ -682,6 +682,10 @@ getent passwd qemu >/dev/null || \ %endif %changelog +* Tue Mar 15 2022 yezengruan +- sw_64: Add sw64 architecture support +- update BinDir + * Mon Mar 14 2022 jiangdawei - qemu.spec: Add --enable-debug parameter to configure diff --git a/sw_64-Add-sw64-architecture-support.patch b/sw_64-Add-sw64-architecture-support.patch new file mode 100644 index 0000000000000000000000000000000000000000..4bffadfbd69453b5c58bc32e821ed88148d809e1 --- /dev/null +++ b/sw_64-Add-sw64-architecture-support.patch @@ -0,0 +1,18277 @@ +From d74713d8e656e8d0f7a5200122119802e639ff49 Mon Sep 17 00:00:00 2001 +From: Lu Feifei +Date: Mon, 14 Mar 2022 11:04:02 +0800 +Subject: [PATCH] sw_64: Add sw64 architecture support + +Signed-off-by: Lu Feifei +--- + configs/devices/sw64-softmmu/default.mak | 10 + + configs/targets/sw64-softmmu.mak | 8 + + configure | 7 + + disas.c | 2 + + disas/meson.build | 1 + + disas/sw64.c | 1242 +++++++ + hw/Kconfig | 1 + + hw/meson.build | 1 + + hw/rtc/sun4v-rtc.c | 11 + + hw/sw64/Kconfig | 11 + + hw/sw64/Makefile.objs | 1 + + hw/sw64/core.h | 25 + + hw/sw64/core3.c | 182 ++ + hw/sw64/core3_board.c | 493 +++ + hw/sw64/meson.build | 10 + + hw/sw64/sw64_iommu.c | 567 ++++ + hw/sw64/trace-events | 3 + + include/disas/dis-asm.h | 4 + + include/elf.h | 44 + + include/hw/sw64/sw64_iommu.h | 105 + + include/qemu/atomic.h | 2 + + include/qemu/timer.h | 10 + + include/sysemu/arch_init.h | 1 + + linux-headers/asm-sw64/kvm.h | 122 + + linux-headers/asm-sw64/unistd.h | 380 +++ + linux-user/meson.build | 1 + + linux-user/sw64/cpu_loop.c | 108 + + linux-user/sw64/signal.c | 273 ++ + linux-user/sw64/sockbits.h | 1 + + linux-user/sw64/syscall_nr.h | 471 +++ + linux-user/sw64/target_cpu.h | 38 + + linux-user/sw64/target_elf.h | 14 + + linux-user/sw64/target_fcntl.h | 11 + + linux-user/sw64/target_signal.h | 98 + + linux-user/sw64/target_structs.h | 47 + + linux-user/sw64/target_syscall.h | 121 + + linux-user/sw64/termbits.h | 265 ++ + meson.build | 12 +- + pc-bios/core3-hmcode | Bin 0 -> 225904 bytes + pc-bios/core3-reset | Bin 0 -> 5032 bytes + pc-bios/core4-hmcode | Bin 0 -> 243040 bytes + pc-bios/meson.build | 3 + + pc-bios/uefi-bios-sw | Bin 0 -> 3145728 bytes + qapi/machine.json | 2 +- + softmmu/qdev-monitor.c | 3 +- + target/Kconfig | 1 + + target/meson.build | 1 + + target/sw64/Kconfig | 2 + + target/sw64/Makefile.objs | 4 + + target/sw64/cpu-param.h | 24 + + target/sw64/cpu-qom.h | 47 + + target/sw64/cpu.c | 457 +++ + target/sw64/cpu.h | 406 +++ + target/sw64/exception.c | 76 + + target/sw64/float_helper.c | 846 +++++ + target/sw64/helper.c | 349 ++ + target/sw64/helper.h | 127 + + target/sw64/int_helper.c | 118 + + target/sw64/kvm.c | 215 ++ + target/sw64/kvm_sw64.h | 47 + + target/sw64/machine.c | 18 + + target/sw64/meson.build | 19 + + target/sw64/profile.c | 2342 +++++++++++++ + target/sw64/profile.h | 541 +++ + target/sw64/simd_helper.c | 1058 ++++++ + target/sw64/translate.c | 3798 ++++++++++++++++++++++ + target/sw64/translate.h | 60 + + tcg/sw64/tcg-target-con-set.h | 39 + + tcg/sw64/tcg-target-con-str.h | 28 + + tcg/sw64/tcg-target.c.inc | 2109 ++++++++++++ + tcg/sw64/tcg-target.h | 123 + + tcg/sw64/tcg-target.opc.h | 15 + + 72 files changed, 17578 insertions(+), 3 deletions(-) + create mode 100644 configs/devices/sw64-softmmu/default.mak + create mode 100644 configs/targets/sw64-softmmu.mak + create mode 100755 disas/sw64.c + create mode 100644 hw/sw64/Kconfig + create mode 100644 hw/sw64/Makefile.objs + create mode 100644 hw/sw64/core.h + create mode 100644 hw/sw64/core3.c + create mode 100644 hw/sw64/core3_board.c + create mode 100644 hw/sw64/meson.build + create mode 100644 hw/sw64/sw64_iommu.c + create mode 100644 hw/sw64/trace-events + create mode 100644 include/hw/sw64/sw64_iommu.h + create mode 100644 linux-headers/asm-sw64/kvm.h + create mode 100644 linux-headers/asm-sw64/unistd.h + create mode 100644 linux-user/sw64/cpu_loop.c + create mode 100644 linux-user/sw64/signal.c + create mode 100644 linux-user/sw64/sockbits.h + create mode 100644 linux-user/sw64/syscall_nr.h + create mode 100644 linux-user/sw64/target_cpu.h + create mode 100644 linux-user/sw64/target_elf.h + create mode 100644 linux-user/sw64/target_fcntl.h + create mode 100644 linux-user/sw64/target_signal.h + create mode 100644 linux-user/sw64/target_structs.h + create mode 100644 linux-user/sw64/target_syscall.h + create mode 100644 linux-user/sw64/termbits.h + create mode 100755 pc-bios/core3-hmcode + create mode 100755 pc-bios/core3-reset + create mode 100755 pc-bios/core4-hmcode + create mode 100755 pc-bios/uefi-bios-sw + create mode 100644 target/sw64/Kconfig + create mode 100644 target/sw64/Makefile.objs + create mode 100644 target/sw64/cpu-param.h + create mode 100644 target/sw64/cpu-qom.h + create mode 100644 target/sw64/cpu.c + create mode 100644 target/sw64/cpu.h + create mode 100644 target/sw64/exception.c + create mode 100644 target/sw64/float_helper.c + create mode 100644 target/sw64/helper.c + create mode 100644 target/sw64/helper.h + create mode 100644 target/sw64/int_helper.c + create mode 100644 target/sw64/kvm.c + create mode 100644 target/sw64/kvm_sw64.h + create mode 100644 target/sw64/machine.c + create mode 100644 target/sw64/meson.build + create mode 100644 target/sw64/profile.c + create mode 100644 target/sw64/profile.h + create mode 100644 target/sw64/simd_helper.c + create mode 100644 target/sw64/translate.c + create mode 100644 target/sw64/translate.h + create mode 100755 tcg/sw64/tcg-target-con-set.h + create mode 100755 tcg/sw64/tcg-target-con-str.h + create mode 100755 tcg/sw64/tcg-target.c.inc + create mode 100755 tcg/sw64/tcg-target.h + create mode 100755 tcg/sw64/tcg-target.opc.h + +diff --git a/configs/devices/sw64-softmmu/default.mak b/configs/devices/sw64-softmmu/default.mak +new file mode 100644 +index 0000000000..0b4d56b43e +--- /dev/null ++++ b/configs/devices/sw64-softmmu/default.mak +@@ -0,0 +1,10 @@ ++# Default configuration for sw64-softmmu ++ ++# Uncomment the following lines to disable these optional devices: ++# ++#CONFIG_PCI_DEVICES=n ++#CONFIG_TEST_DEVICES=n ++ ++# Boards: ++# ++CONFIG_CORE3=y +diff --git a/configs/targets/sw64-softmmu.mak b/configs/targets/sw64-softmmu.mak +new file mode 100644 +index 0000000000..37cc2e05a6 +--- /dev/null ++++ b/configs/targets/sw64-softmmu.mak +@@ -0,0 +1,8 @@ ++# Default configuration for sw64-softmmu ++ ++# Boards: ++# ++TARGET_ARCH=sw64 ++TARGET_BASE_ARCH=sw64 ++TARGET_ABI_DIR=sw64 ++TARGET_SUPPORTS_MTTCG=y +diff --git a/configure b/configure +index 48c21775f3..9569d7a3d0 100755 +--- a/configure ++++ b/configure +@@ -612,6 +612,9 @@ case "$cpu" in + sparc|sun4[cdmuv]) + cpu="sparc" + ;; ++ sw_64) ++ cpu="sw64" ++ ;; + *) + # This will result in either an error or falling back to TCI later + ARCH=unknown +@@ -3268,6 +3271,10 @@ alpha) + # Ensure there's only a single GP + QEMU_CFLAGS="-msmall-data $QEMU_CFLAGS" + ;; ++sw*) ++ # Ensure there's only a single GP ++ QEMU_CFLAGS="-msmall-data $QEMU_CFLAGS" ++;; + esac + + if test "$gprof" = "yes" ; then +diff --git a/disas.c b/disas.c +index 3dab4482d1..897de1d9a9 100644 +--- a/disas.c ++++ b/disas.c +@@ -207,6 +207,8 @@ static void initialize_debug_host(CPUDebug *s) + s->info.cap_insn_split = 6; + #elif defined(__hppa__) + s->info.print_insn = print_insn_hppa; ++#elif defined(__sw_64__) ++ s->info.print_insn = print_insn_sw_64; + #endif + } + +diff --git a/disas/meson.build b/disas/meson.build +index 449f99e1de..5c5daa69a7 100644 +--- a/disas/meson.build ++++ b/disas/meson.build +@@ -20,4 +20,5 @@ common_ss.add(when: 'CONFIG_S390_DIS', if_true: files('s390.c')) + common_ss.add(when: 'CONFIG_SH4_DIS', if_true: files('sh4.c')) + common_ss.add(when: 'CONFIG_SPARC_DIS', if_true: files('sparc.c')) + common_ss.add(when: 'CONFIG_XTENSA_DIS', if_true: files('xtensa.c')) ++common_ss.add(when: 'CONFIG_SW64_DIS', if_true: files('sw64.c')) + common_ss.add(when: capstone, if_true: files('capstone.c')) +diff --git a/disas/sw64.c b/disas/sw64.c +new file mode 100755 +index 0000000000..c5bd578e07 +--- /dev/null ++++ b/disas/sw64.c +@@ -0,0 +1,1242 @@ ++/* ++ * sw_64-dis.c -- Disassemble Sw_64 CORE3 instructions ++ * ++ * This file is part of libopcodes. ++ * ++ * This library is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 3, or (at your option) ++ * any later version. ++ * ++ * It 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 General Public ++ * License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this file; see the file COPYING. If not, write to the Free ++ * Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA ++ * 02110-1301, USA. ++ */ ++ ++#include "qemu/osdep.h" ++#include "disas/dis-asm.h" ++ ++#undef MAX ++ ++struct sw_64_opcode { ++ /* The opcode name. */ ++ const char *name; ++ ++ /* The opcode itself. Those bits which will be filled in with ++ operands are zeroes. */ ++ unsigned opcode; ++ ++ /* The opcode mask. This is used by the disassembler. This is a ++ mask containing ones indicating those bits which must match the ++ opcode field, and zeroes indicating those bits which need not ++ match (and are presumably filled in by operands). */ ++ unsigned mask; ++ ++ /* One bit flags for the opcode. These are primarily used to ++ indicate specific processors and environments support the ++ instructions. The defined values are listed below. */ ++ unsigned flags; ++ ++ /* An array of operand codes. Each code is an index into the ++ operand table. They appear in the order which the operands must ++ appear in assembly code, and are terminated by a zero. */ ++ unsigned char operands[5]; ++}; ++ ++/* The table itself is sorted by major opcode number, and is otherwise ++ in the order in which the disassembler should consider ++ instructions. */ ++extern const struct sw_64_opcode sw_64_opcodes[]; ++extern const unsigned sw_64_num_opcodes; ++ ++/* Values defined for the flags field of a struct sw_64_opcode. */ ++ ++/* CPU Availability */ ++#define SW_OPCODE_BASE 0x0001 /* Base architecture insns. */ ++#define SW_OPCODE_CORE3 0x0002 /* Core3 private insns. */ ++#define SW_LITOP(i) (((i) >> 26) & 0x3D) ++ ++#define SW_OPCODE_NOHM (~(SW_OPCODE_BASE|SW_OPCODE_CORE3)) ++ ++/* A macro to extract the major opcode from an instruction. */ ++#define SW_OP(i) (((i) >> 26) & 0x3F) ++ ++/* The total number of major opcodes. */ ++#define SW_NOPS 0x40 ++ ++/* The operands table is an array of struct sw_64_operand. */ ++ ++struct sw_64_operand { ++ /* The number of bits in the operand. */ ++ unsigned int bits : 5; ++ ++ /* How far the operand is left shifted in the instruction. */ ++ unsigned int shift : 5; ++ ++ /* The default relocation type for this operand. */ ++ signed int default_reloc : 16; ++ ++ /* One bit syntax flags. */ ++ unsigned int flags : 16; ++ ++ /* Insertion function. This is used by the assembler. To insert an ++ operand value into an instruction, check this field. ++ ++ If it is NULL, execute ++ i |= (op & ((1 << o->bits) - 1)) << o->shift; ++ (i is the instruction which we are filling in, o is a pointer to ++ this structure, and op is the opcode value; this assumes twos ++ complement arithmetic). ++ ++ If this field is not NULL, then simply call it with the ++ instruction and the operand value. It will return the new value ++ of the instruction. If the ERRMSG argument is not NULL, then if ++ the operand value is illegal, *ERRMSG will be set to a warning ++ string (the operand will be inserted in any case). If the ++ operand value is legal, *ERRMSG will be unchanged (most operands ++ can accept any value). */ ++ unsigned (*insert) (unsigned instruction, int op, const char **errmsg); ++ ++ /* Extraction function. This is used by the disassembler. To ++ extract this operand type from an instruction, check this field. ++ ++ If it is NULL, compute ++ op = ((i) >> o->shift) & ((1 << o->bits) - 1); ++ if ((o->flags & SW_OPERAND_SIGNED) != 0 ++ && (op & (1 << (o->bits - 1))) != 0) ++ op -= 1 << o->bits; ++ (i is the instruction, o is a pointer to this structure, and op ++ is the result; this assumes twos complement arithmetic). ++ ++ If this field is not NULL, then simply call it with the ++ instruction value. It will return the value of the operand. If ++ the INVALID argument is not NULL, *INVALID will be set to ++ non-zero if this operand type can not actually be extracted from ++ this operand (i.e., the instruction does not match). If the ++ operand is valid, *INVALID will not be changed. */ ++ int (*extract) (unsigned instruction, int *invalid); ++}; ++ ++/* Elements in the table are retrieved by indexing with values from ++ the operands field of the sw_64_opcodes table. */ ++ ++extern const struct sw_64_operand sw_64_operands[]; ++extern const unsigned sw_64_num_operands; ++/* Values defined for the flags field of a struct sw_64_operand. */ ++ ++/* Mask for selecting the type for typecheck purposes */ ++#define SW_OPERAND_TYPECHECK_MASK \ ++ (SW_OPERAND_PARENS | SW_OPERAND_COMMA | SW_OPERAND_IR | \ ++ SW_OPERAND_FPR | SW_OPERAND_RELATIVE | SW_OPERAND_SIGNED | \ ++ SW_OPERAND_UNSIGNED) ++ ++/* This operand does not actually exist in the assembler input. This ++ is used to support extended mnemonics, for which two operands fields ++ are identical. The assembler should call the insert function with ++ any op value. The disassembler should call the extract function, ++ ignore the return value, and check the value placed in the invalid ++ argument. */ ++#define SW_OPERAND_FAKE 01 ++ ++/* The operand should be wrapped in parentheses rather than separated ++ from the previous by a comma. This is used for the load and store ++ instructions which want their operands to look like "Ra,disp(Rb)". */ ++#define SW_OPERAND_PARENS 02 ++ ++/* Used in combination with PARENS, this supresses the supression of ++ the comma. This is used for "jmp Ra,(Rb),hint". */ ++#define SW_OPERAND_COMMA 04 ++ ++/* This operand names an integer register. */ ++#define SW_OPERAND_IR 010 ++ ++/* This operand names a floating point register. */ ++#define SW_OPERAND_FPR 020 ++ ++/* This operand is a relative branch displacement. The disassembler ++ prints these symbolically if possible. */ ++#define SW_OPERAND_RELATIVE 040 ++ ++/* This operand takes signed values. */ ++#define SW_OPERAND_SIGNED 0100 ++ ++/* This operand takes unsigned values. This exists primarily so that ++ a flags value of 0 can be treated as end-of-arguments. */ ++#define SW_OPERAND_UNSIGNED 0200 ++ ++/* Supress overflow detection on this field. This is used for hints. */ ++#define SW_OPERAND_NOOVERFLOW 0400 ++ ++/* Mask for optional argument default value. */ ++#define SW_OPERAND_OPTIONAL_MASK 07000 ++ ++/* This operand defaults to zero. This is used for jump hints. */ ++#define SW_OPERAND_DEFAULT_ZERO 01000 ++ ++/* This operand should default to the first (real) operand and is used ++ in conjunction with SW_OPERAND_OPTIONAL. This allows ++ "and $0,3,$0" to be written as "and $0,3", etc. I don't like ++ it, but it's what DEC does. */ ++#define SW_OPERAND_DEFAULT_FIRST 02000 ++ ++/* Similarly, this operand should default to the second (real) operand. ++ This allows "negl $0" instead of "negl $0,$0". */ ++#define SW_OPERAND_DEFAULT_SECOND 04000 ++ ++/* Register common names */ ++ ++#define SW_REG_V0 0 ++#define SW_REG_T0 1 ++#define SW_REG_T1 2 ++#define SW_REG_T2 3 ++#define SW_REG_T3 4 ++#define SW_REG_T4 5 ++#define SW_REG_T5 6 ++#define SW_REG_T6 7 ++#define SW_REG_T7 8 ++#define SW_REG_S0 9 ++#define SW_REG_S1 10 ++#define SW_REG_S2 11 ++#define SW_REG_S3 12 ++#define SW_REG_S4 13 ++#define SW_REG_S5 14 ++#define SW_REG_FP 15 ++#define SW_REG_A0 16 ++#define SW_REG_A1 17 ++#define SW_REG_A2 18 ++#define SW_REG_A3 19 ++#define SW_REG_A4 20 ++#define SW_REG_A5 21 ++#define SW_REG_T8 22 ++#define SW_REG_T9 23 ++#define SW_REG_T10 24 ++#define SW_REG_T11 25 ++#define SW_REG_RA 26 ++#define SW_REG_PV 27 ++#define SW_REG_T12 27 ++#define SW_REG_AT 28 ++#define SW_REG_GP 29 ++#define SW_REG_SP 30 ++#define SW_REG_ZERO 31 ++ ++enum bfd_reloc_code_real { ++ BFD_RELOC_23_PCREL_S2, ++ BFD_RELOC_SW_64_HINT ++}; ++ ++static unsigned insert_rba(unsigned insn, int value ATTRIBUTE_UNUSED, ++ const char **errmsg ATTRIBUTE_UNUSED) ++{ ++ return insn | (((insn >> 21) & 0x1f) << 16); ++} ++ ++static int extract_rba(unsigned insn, int *invalid) ++{ ++ if (invalid != (int *) NULL ++ && ((insn >> 21) & 0x1f) != ((insn >> 16) & 0x1f)) ++ *invalid = 1; ++ return 0; ++} ++ ++/* The same for the RC field. */ ++static unsigned insert_rca(unsigned insn, int value ATTRIBUTE_UNUSED, ++ const char **errmsg ATTRIBUTE_UNUSED) ++{ ++ return insn | ((insn >> 21) & 0x1f); ++} ++ ++static unsigned insert_rdc(unsigned insn, int value ATTRIBUTE_UNUSED, ++ const char **errmsg ATTRIBUTE_UNUSED) ++{ ++ return insn | ((insn >> 5) & 0x1f); ++} ++ ++static int extract_rdc(unsigned insn, int *invalid) ++{ ++ if (invalid != (int *) NULL ++ && ((insn >> 5) & 0x1f) != (insn & 0x1f)) ++ *invalid = 1; ++ return 0; ++} ++ ++static int extract_rca(unsigned insn, int *invalid) ++{ ++ if (invalid != (int *) NULL ++ && ((insn >> 21) & 0x1f) != (insn & 0x1f)) ++ *invalid = 1; ++ return 0; ++} ++ ++/* Fake arguments in which the registers must be set to ZERO. */ ++static unsigned insert_za(unsigned insn, int value ATTRIBUTE_UNUSED, ++ const char **errmsg ATTRIBUTE_UNUSED) ++{ ++ return insn | (31 << 21); ++} ++ ++static int extract_za(unsigned insn, int *invalid) ++{ ++ if (invalid != (int *) NULL && ((insn >> 21) & 0x1f) != 31) ++ *invalid = 1; ++ return 0; ++} ++ ++static unsigned insert_zb(unsigned insn, int value ATTRIBUTE_UNUSED, ++ const char **errmsg ATTRIBUTE_UNUSED) ++{ ++ return insn | (31 << 16); ++} ++ ++static int extract_zb(unsigned insn, int *invalid) ++{ ++ if (invalid != (int *) NULL && ((insn >> 16) & 0x1f) != 31) ++ *invalid = 1; ++ return 0; ++} ++ ++static unsigned insert_zc(unsigned insn, int value ATTRIBUTE_UNUSED, ++ const char **errmsg ATTRIBUTE_UNUSED) ++{ ++ return insn | 31; ++} ++ ++static int extract_zc(unsigned insn, int *invalid) ++{ ++ if (invalid != (int *) NULL && (insn & 0x1f) != 31) ++ *invalid = 1; ++ return 0; ++} ++ ++ ++/* The displacement field of a Branch format insn. */ ++ ++static unsigned insert_bdisp(unsigned insn, int value, const char **errmsg) ++{ ++ if (errmsg != (const char **)NULL && (value & 3)) ++ *errmsg = "branch operand unaligned"; ++ return insn | ((value / 4) & 0x1FFFFF); ++} ++ ++static int extract_bdisp(unsigned insn, int *invalid ATTRIBUTE_UNUSED) ++{ ++ return 4 * (((insn & 0x1FFFFF) ^ 0x100000) - 0x100000); ++} ++ ++static unsigned insert_bdisp26(unsigned insn, int value, const char **errmsg) ++{ ++ if (errmsg != (const char **)NULL && (value & 3)) ++ *errmsg = "branch operand unaligned"; ++ return insn | ((value / 4) & 0x3FFFFFF); ++} ++ ++static int extract_bdisp26(unsigned insn, int *invalid ATTRIBUTE_UNUSED) ++{ ++ return 4 * (((insn & 0x3FFFFFF) ^ 0x2000000) - 0x2000000); ++} ++ ++/* The hint field of a JMP/JSR insn. */ ++/* sw use 16 bits hint disp. */ ++static unsigned insert_jhint(unsigned insn, int value, const char **errmsg) ++{ ++ if (errmsg != (const char **)NULL && (value & 3)) ++ *errmsg = "jump hint unaligned"; ++ return insn | ((value / 4) & 0xFFFF); ++} ++ ++static int extract_jhint(unsigned insn, int *invalid ATTRIBUTE_UNUSED) ++{ ++ return 4 * (((insn & 0xFFFF) ^ 0x8000) - 0x8000); ++} ++ ++/* The hint field of an CORE3 HW_JMP/JSR insn. */ ++ ++static unsigned insert_sw4hwjhint(unsigned insn, int value, const char **errmsg) ++{ ++ if (errmsg != (const char **)NULL && (value & 3)) ++ *errmsg = "jump hint unaligned"; ++ return insn | ((value / 4) & 0x1FFF); ++} ++ ++static int extract_sw4hwjhint(unsigned insn, int *invalid ATTRIBUTE_UNUSED) ++{ ++ return 4 * (((insn & 0x1FFF) ^ 0x1000) - 0x1000); ++} ++ ++/* The operands table. */ ++ ++const struct sw_64_operand sw_64_operands[] = { ++ /* The fields are bits, shift, insert, extract, flags */ ++ /* The zero index is used to indicate end-of-list */ ++#define UNUSED 0 ++ { 0, 0, 0, 0, 0, 0 }, ++ ++ /* The plain integer register fields. */ ++#define RA (UNUSED + 1) ++ { 5, 21, 0, SW_OPERAND_IR, 0, 0 }, ++#define RB (RA + 1) ++ { 5, 16, 0, SW_OPERAND_IR, 0, 0 }, ++#define RC (RB + 1) ++ { 5, 0, 0, SW_OPERAND_IR, 0, 0 }, ++ ++ /* The plain fp register fields. */ ++#define FA (RC + 1) ++ { 5, 21, 0, SW_OPERAND_FPR, 0, 0 }, ++#define FB (FA + 1) ++ { 5, 16, 0, SW_OPERAND_FPR, 0, 0 }, ++#define FC (FB + 1) ++ { 5, 0, 0, SW_OPERAND_FPR, 0, 0 }, ++ ++ /* The integer registers when they are ZERO. */ ++#define ZA (FC + 1) ++ { 5, 21, 0, SW_OPERAND_FAKE, insert_za, extract_za }, ++#define ZB (ZA + 1) ++ { 5, 16, 0, SW_OPERAND_FAKE, insert_zb, extract_zb }, ++#define ZC (ZB + 1) ++ { 5, 0, 0, SW_OPERAND_FAKE, insert_zc, extract_zc }, ++ ++ /* The RB field when it needs parentheses. */ ++#define PRB (ZC + 1) ++ { 5, 16, 0, SW_OPERAND_IR | SW_OPERAND_PARENS, 0, 0 }, ++ ++ /* The RB field when it needs parentheses _and_ a preceding comma. */ ++#define CPRB (PRB + 1) ++ { 5, 16, 0, ++ SW_OPERAND_IR | SW_OPERAND_PARENS | SW_OPERAND_COMMA, 0, 0 }, ++ ++ /* The RB field when it must be the same as the RA field. */ ++#define RBA (CPRB + 1) ++ { 5, 16, 0, SW_OPERAND_FAKE, insert_rba, extract_rba }, ++ ++ /* The RC field when it must be the same as the RB field. */ ++#define RCA (RBA + 1) ++ { 5, 0, 0, SW_OPERAND_FAKE, insert_rca, extract_rca }, ++ ++#define RDC (RCA + 1) ++ { 5, 0, 0, SW_OPERAND_FAKE, insert_rdc, extract_rdc }, ++ ++ /* The RC field when it can *default* to RA. */ ++#define DRC1 (RDC + 1) ++ { 5, 0, 0, ++ SW_OPERAND_IR | SW_OPERAND_DEFAULT_FIRST, 0, 0 }, ++ ++ /* The RC field when it can *default* to RB. */ ++#define DRC2 (DRC1 + 1) ++ { 5, 0, 0, ++ SW_OPERAND_IR | SW_OPERAND_DEFAULT_SECOND, 0, 0 }, ++ ++ /* The FC field when it can *default* to RA. */ ++#define DFC1 (DRC2 + 1) ++ { 5, 0, 0, ++ SW_OPERAND_FPR | SW_OPERAND_DEFAULT_FIRST, 0, 0 }, ++ ++ /* The FC field when it can *default* to RB. */ ++#define DFC2 (DFC1 + 1) ++ { 5, 0, 0, ++ SW_OPERAND_FPR | SW_OPERAND_DEFAULT_SECOND, 0, 0 }, ++ ++ /* The unsigned 8-bit literal of Operate format insns. */ ++#define LIT (DFC2 + 1) ++ { 8, 13, -LIT, SW_OPERAND_UNSIGNED, 0, 0 }, ++ ++ /* The signed 16-bit displacement of Memory format insns. From here ++ we can't tell what relocation should be used, so don't use a default. */ ++#define MDISP (LIT + 1) ++ { 16, 0, -MDISP, SW_OPERAND_SIGNED, 0, 0 }, ++ ++ /* The signed "23-bit" aligned displacement of Branch format insns. */ ++#define BDISP (MDISP + 1) ++ { 21, 0, BFD_RELOC_23_PCREL_S2, ++ SW_OPERAND_RELATIVE, insert_bdisp, extract_bdisp }, ++ ++ /* The 26-bit hmcode function for sys_call and sys_call / b. */ ++#define HMFN (BDISP + 1) ++ { 25, 0, -HMFN, SW_OPERAND_UNSIGNED, 0, 0 }, ++ ++ /* sw jsr/ret insntructions has no function bits. */ ++ /* The optional signed "16-bit" aligned displacement of the JMP/JSR hint. */ ++#define JMPHINT (HMFN + 1) ++ { 16, 0, BFD_RELOC_SW_64_HINT, ++ SW_OPERAND_RELATIVE | SW_OPERAND_DEFAULT_ZERO | SW_OPERAND_NOOVERFLOW, ++ insert_jhint, extract_jhint }, ++ ++ /* The optional hint to RET/JSR_COROUTINE. */ ++#define RETHINT (JMPHINT + 1) ++ { 16, 0, -RETHINT, ++ SW_OPERAND_UNSIGNED | SW_OPERAND_DEFAULT_ZERO, 0, 0 }, ++ ++ /* The 12-bit displacement for the core3 hw_{ld,st} (pal1b/pal1f) insns. */ ++#define HWDISP (RETHINT + 1) ++ { 12, 0, -HWDISP, SW_OPERAND_SIGNED, 0, 0 }, ++ ++ /* The 16-bit combined index/scoreboard mask for the core3 ++ hw_m[ft]pr (pal19/pal1d) insns. */ ++#define HWINDEX (HWDISP + 1) ++ { 16, 0, -HWINDEX, SW_OPERAND_UNSIGNED, 0, 0 }, ++ ++ /* The 13-bit branch hint for the core3 hw_jmp/jsr (pal1e) insn. */ ++#define HWJMPHINT (HWINDEX + 1) ++ { 8, 0, -HWJMPHINT, ++ SW_OPERAND_RELATIVE | SW_OPERAND_DEFAULT_ZERO | SW_OPERAND_NOOVERFLOW, ++ insert_sw4hwjhint, extract_sw4hwjhint }, ++ ++ /* for the third operand of ternary operands integer insn. */ ++#define R3 (HWJMPHINT + 1) ++ { 5, 5, 0, SW_OPERAND_IR, 0, 0 }, ++ /* The plain fp register fields */ ++#define F3 (R3 + 1) ++ { 5, 5, 0, SW_OPERAND_FPR, 0, 0 }, ++ /* sw simd settle instruction lit */ ++#define FMALIT (F3 + 1) ++ { 5, 5, -FMALIT, SW_OPERAND_UNSIGNED, 0, 0 }, //V1.1 ++#define LMDISP (FMALIT + 1) ++ { 15, 0, -LMDISP, SW_OPERAND_UNSIGNED, 0, 0 }, ++#define RPIINDEX (LMDISP + 1) ++ { 8, 0, -RPIINDEX, SW_OPERAND_UNSIGNED, 0, 0 }, ++#define ATMDISP (RPIINDEX + 1) ++ { 12, 0, -ATMDISP, SW_OPERAND_SIGNED, 0, 0 }, ++#define DISP13 (ATMDISP + 1) ++ { 13, 13, -DISP13, SW_OPERAND_SIGNED, 0, 0}, ++#define BDISP26 (DISP13 + 1) ++ { 26, 0, 222, ++ SW_OPERAND_RELATIVE, insert_bdisp26, extract_bdisp26 }, ++#define DPFTH (BDISP26 + 1) ++ { 5, 21, -DPFTH, SW_OPERAND_UNSIGNED, 0, 0} ++}; ++ ++const unsigned sw_64_num_operands = sizeof(sw_64_operands) / sizeof(*sw_64_operands); ++ ++/* Macros used to form opcodes. */ ++ ++/* The main opcode. */ ++#define OP(x) (((x) & 0x3F) << 26) ++#define OP_MASK 0xFC000000 ++ ++/* Branch format instructions. */ ++#define BRA_(oo) OP(oo) ++#define BRA_MASK OP_MASK ++#define BRA(oo) BRA_(oo), BRA_MASK ++ ++#ifdef HUANGLM20171113 ++/* Floating point format instructions. */ ++#define FP_(oo,fff) (OP(oo) | (((fff) & 0x7FF) << 5)) ++#define FP_MASK (OP_MASK | 0xFFE0) ++#define FP(oo,fff) FP_(oo,fff), FP_MASK ++ ++#else ++/* Floating point format instructions. */ ++#define FP_(oo,fff) (OP(oo) | (((fff) & 0xFF) << 5)) ++#define FP_MASK (OP_MASK | 0x1FE0) ++#define FP(oo,fff) FP_(oo,fff), FP_MASK ++ ++#define FMA_(oo,fff) (OP(oo) | (((fff) & 0x3F) << 10 )) ++#define FMA_MASK (OP_MASK | 0xFC00) ++#define FMA(oo,fff) FMA_(oo,fff), FMA_MASK ++#endif ++ ++/* Memory format instructions. */ ++#define MEM_(oo) OP(oo) ++#define MEM_MASK OP_MASK ++#define MEM(oo) MEM_(oo), MEM_MASK ++ ++/* Memory/Func Code format instructions. */ ++#define MFC_(oo,ffff) (OP(oo) | ((ffff) & 0xFFFF)) ++#define MFC_MASK (OP_MASK | 0xFFFF) ++#define MFC(oo,ffff) MFC_(oo,ffff), MFC_MASK ++ ++/* Memory/Branch format instructions. */ ++#define MBR_(oo,h) (OP(oo) | (((h) & 3) << 14)) ++#define MBR_MASK (OP_MASK | 0xC000) ++#define MBR(oo,h) MBR_(oo,h), MBR_MASK ++ ++/* Now sw Operate format instructions is different with SW1. */ ++#define OPR_(oo,ff) (OP(oo) | (((ff) & 0xFF) << 5)) ++#define OPRL_(oo,ff) (OPR_((oo), (ff)) ) ++#define OPR_MASK (OP_MASK | 0x1FE0) ++#define OPR(oo,ff) OPR_(oo,ff), OPR_MASK ++#define OPRL(oo,ff) OPRL_(oo,ff), OPR_MASK ++ ++/* sw ternary operands Operate format instructions. */ ++#define TOPR_(oo,ff) (OP(oo) | (((ff) & 0x07) << 10)) ++#define TOPRL_(oo,ff) (TOPR_((oo), (ff))) ++#define TOPR_MASK (OP_MASK | 0x1C00) ++#define TOPR(oo,ff) TOPR_(oo,ff), TOPR_MASK ++#define TOPRL(oo,ff) TOPRL_(oo,ff), TOPR_MASK ++ ++/* sw atom instructions. */ ++#define ATMEM_(oo,h) (OP(oo) | (((h) & 0xF) << 12)) ++#define ATMEM_MASK (OP_MASK | 0xF000) ++#define ATMEM(oo,h) ATMEM_(oo,h), ATMEM_MASK ++ ++/* sw privilege instructions. */ ++#define PRIRET_(oo,h) (OP(oo) | (((h) & 0x1) << 20)) ++#define PRIRET_MASK (OP_MASK | 0x100000) ++#define PRIRET(oo,h) PRIRET_(oo,h), PRIRET_MASK ++ ++/* sw rpi_rcsr,rpi_wcsr. */ ++#define CSR_(oo,ff) (OP(oo) | (((ff) & 0xFF) << 8)) ++#define CSR_MASK (OP_MASK | 0xFF00) ++#define CSR(oo,ff) CSR_(oo,ff), CSR_MASK ++ ++#define PCD_(oo,ff) (OP(oo) | (ff << 25)) ++#define PCD_MASK OP_MASK ++#define PCD(oo,ff) PCD_(oo,ff), PCD_MASK ++ ++/* Hardware memory (hw_{ld,st}) instructions. */ ++#define HWMEM_(oo,f) (OP(oo) | (((f) & 0xF) << 12)) ++#define HWMEM_MASK (OP_MASK | 0xF000) ++#define HWMEM(oo,f) HWMEM_(oo,f), HWMEM_MASK ++ ++#define LOGX_(oo,ff) (OP(oo) | (((ff) & 0x3F) << 10)) ++#define LOGX_MASK (0xF0000000) ++#define LOGX(oo,ff) LOGX_(oo,ff), LOGX_MASK ++ ++/* Abbreviations for instruction subsets. */ ++#define BASE SW_OPCODE_BASE ++#define CORE3 SW_OPCODE_CORE3 ++ ++/* Common combinations of arguments. */ ++#define ARG_NONE { 0 } ++#define ARG_BRA { RA, BDISP } ++#define ARG_FBRA { FA, BDISP } ++#define ARG_FP { FA, FB, DFC1 } ++#define ARG_FPZ1 { ZA, FB, DFC1 } ++#define ARG_MEM { RA, MDISP, PRB } ++#define ARG_FMEM { FA, MDISP, PRB } ++#define ARG_OPR { RA, RB, DRC1 } ++ ++#define ARG_OPRCAS { RA, RB, RC } ++ ++#define ARG_OPRL { RA, LIT, DRC1 } ++#define ARG_OPRZ1 { ZA, RB, DRC1 } ++#define ARG_OPRLZ1 { ZA, LIT, RC } ++#define ARG_PCD { HMFN } ++#define ARG_HWMEM { RA, HWDISP, PRB } ++#define ARG_FPL { FA,LIT, DFC1 } ++#define ARG_FMA { FA,FB,F3, DFC1 } ++#define ARG_PREFETCH { ZA, MDISP, PRB } ++#define ARG_TOPR { RA, RB,R3, DRC1 } ++#define ARG_TOPRL { RA, LIT, R3,DRC1 } ++#define ARG_FMAL { FA,FB,FMALIT, DFC1 } ++#define ARG_ATMEM { RA, ATMDISP, PRB } ++#define ARG_VUAMEM { FA, ATMDISP, PRB } ++#define ARG_OPRLZ3 { RA, LIT, ZC } ++ ++#define ARG_DISP13 {DISP13, RC} ++ ++/* The opcode table. ++ ++ The format of the opcode table is: ++ ++ NAME OPCODE MASK { OPERANDS } ++ ++ NAME is the name of the instruction. ++ ++ OPCODE is the instruction opcode. ++ ++ MASK is the opcode mask; this is used to tell the disassembler ++ which bits in the actual opcode must match OPCODE. ++ ++ OPERANDS is the list of operands. ++ ++ The preceding macros merge the text of the OPCODE and MASK fields. ++ ++ The disassembler reads the table in order and prints the first ++ instruction which matches, so this table is sorted to put more ++ specific instructions before more general instructions. ++ ++ Otherwise, it is sorted by major opcode and minor function code. ++ */ ++ ++const struct sw_64_opcode sw_64_opcodes[] = { ++ { "sys_call/b", PCD(0x00,0x00), BASE, ARG_PCD }, ++ { "sys_call", PCD(0x00,0x01), BASE, ARG_PCD }, ++ ++ { "call", MEM(0x01), BASE, { RA, CPRB, JMPHINT } }, ++ { "ret", MEM(0x02), BASE, { RA, CPRB, RETHINT } }, ++ { "jmp", MEM(0x03), BASE, { RA, CPRB, JMPHINT } }, ++ { "br", BRA(0x04), BASE, { ZA, BDISP } }, ++ { "br", BRA(0x04), BASE, ARG_BRA }, ++ { "bsr", BRA(0x05), BASE, ARG_BRA }, ++ { "memb", MFC(0x06,0x0000), BASE, ARG_NONE }, ++ { "imemb", MFC(0x06,0x0001), BASE, ARG_NONE }, ++ { "rtc", MFC(0x06,0x0020), BASE, { RA, ZB } }, ++ { "rtc", MFC(0x06,0x0020), BASE, { RA, RB } }, ++ { "rcid", MFC(0x06,0x0040), BASE, { RA , ZB} }, ++ { "halt", MFC(0x06,0x0080), BASE, { ZA, ZB } }, ++ { "rd_f", MFC(0x06,0x1000), CORE3, { RA, ZB } }, ++ { "wr_f", MFC(0x06,0x1020), CORE3, { RA, ZB } }, ++ { "rtid", MFC(0x06,0x1040), BASE, { RA } }, ++ { "pri_rcsr", CSR(0x06,0xFE), CORE3, { RA, RPIINDEX ,ZB } }, ++ { "pri_wcsr", CSR(0x06,0xFF), CORE3, { RA, RPIINDEX ,ZB } }, ++ { "pri_ret", PRIRET(0x07,0x0), BASE, { RA } }, ++ { "pri_ret/b", PRIRET(0x07,0x1), BASE, { RA } }, ++ { "lldw", ATMEM(0x08,0x0), BASE, ARG_ATMEM }, ++ { "lldl", ATMEM(0x08,0x1), BASE, ARG_ATMEM }, ++ { "ldw_inc", ATMEM(0x08,0x2), CORE3, ARG_ATMEM }, ++ { "ldl_inc", ATMEM(0x08,0x3), CORE3, ARG_ATMEM }, ++ { "ldw_dec", ATMEM(0x08,0x4), CORE3, ARG_ATMEM }, ++ { "ldl_dec", ATMEM(0x08,0x5), CORE3, ARG_ATMEM }, ++ { "ldw_set", ATMEM(0x08,0x6), CORE3, ARG_ATMEM }, ++ { "ldl_set", ATMEM(0x08,0x7), CORE3, ARG_ATMEM }, ++ { "lstw", ATMEM(0x08,0x8), BASE, ARG_ATMEM }, ++ { "lstl", ATMEM(0x08,0x9), BASE, ARG_ATMEM }, ++ { "ldw_nc", ATMEM(0x08,0xA), BASE, ARG_ATMEM }, ++ { "ldl_nc", ATMEM(0x08,0xB), BASE, ARG_ATMEM }, ++ { "ldd_nc", ATMEM(0x08,0xC), BASE, ARG_VUAMEM }, ++ { "stw_nc", ATMEM(0x08,0xD), BASE, ARG_ATMEM }, ++ { "stl_nc", ATMEM(0x08,0xE), BASE, ARG_ATMEM }, ++ { "std_nc", ATMEM(0x08,0xF), BASE, ARG_VUAMEM }, ++ { "fillcs", MEM(0x09), BASE, ARG_PREFETCH }, ++ { "ldwe", MEM(0x09), BASE, ARG_FMEM }, ++ { "e_fillcs", MEM(0x0A), BASE, ARG_PREFETCH }, ++ { "ldse", MEM(0x0A), BASE, ARG_FMEM }, ++ { "fillcs_e", MEM(0x0B), BASE, ARG_PREFETCH }, ++ { "ldde", MEM(0x0B), BASE, ARG_FMEM }, ++ { "vlds", MEM(0x0C), BASE, ARG_FMEM }, ++ { "vldd", MEM(0x0D), BASE, ARG_FMEM }, ++ { "vsts", MEM(0x0E), BASE, ARG_FMEM }, ++ { "vstd", MEM(0x0F), BASE, ARG_FMEM }, ++ { "addw", OPR(0x10,0x00), BASE, ARG_OPR }, ++ { "addw", OPRL(0x12,0x00), BASE, ARG_OPRL }, ++ { "subw", OPR(0x10,0x01), BASE, ARG_OPR }, ++ { "subw", OPRL(0x12,0x01), BASE, ARG_OPRL }, ++ { "s4addw", OPR(0x10,0x02), BASE, ARG_OPR }, ++ { "s4addw", OPRL(0x12,0x02), BASE, ARG_OPRL }, ++ { "s4subw", OPR(0x10,0x03), BASE, ARG_OPR }, ++ { "s4subw", OPRL(0x12,0x03), BASE, ARG_OPRL }, ++ { "s8addw", OPR(0x10,0x04), BASE, ARG_OPR }, ++ { "s8addw", OPRL(0x12,0x04), BASE, ARG_OPRL }, ++ { "s8subw", OPR(0x10,0x05), BASE, ARG_OPR }, ++ { "s8subw", OPRL(0x12,0x05), BASE, ARG_OPRL }, ++ { "addl", OPR(0x10,0x08), BASE, ARG_OPR }, ++ { "addl", OPRL(0x12,0x08), BASE, ARG_OPRL }, ++ { "subl", OPR(0x10,0x09), BASE, ARG_OPR }, ++ { "subl", OPRL(0x12,0x09), BASE, ARG_OPRL }, ++ { "s4addl", OPR(0x10,0x0A), BASE, ARG_OPR }, ++ { "s4addl", OPRL(0x12,0x0A), BASE, ARG_OPRL }, ++ { "s4subl", OPR(0x10,0x0B), BASE, ARG_OPR }, ++ { "s4subl", OPRL(0x12,0x0B), BASE, ARG_OPRL }, ++ { "s8addl", OPR(0x10,0x0C), BASE, ARG_OPR }, ++ { "s8addl", OPRL(0x12,0x0C), BASE, ARG_OPRL }, ++ { "s8subl", OPR(0x10,0x0D), BASE, ARG_OPR }, ++ { "s8subl", OPRL(0x12,0x0D), BASE, ARG_OPRL }, ++ { "mulw", OPR(0x10,0x10), BASE, ARG_OPR }, ++ { "mulw", OPRL(0x12,0x10), BASE, ARG_OPRL }, ++ { "mull", OPR(0x10,0x18), BASE, ARG_OPR }, ++ { "mull", OPRL(0x12,0x18), BASE, ARG_OPRL }, ++ { "umulh", OPR(0x10,0x19), BASE, ARG_OPR }, ++ { "umulh", OPRL(0x12,0x19), BASE, ARG_OPRL }, ++ { "cmpeq", OPR(0x10,0x28), BASE, ARG_OPR }, ++ { "cmpeq", OPRL(0x12,0x28), BASE, ARG_OPRL }, ++ { "cmplt", OPR(0x10,0x29), BASE, ARG_OPR }, ++ { "cmplt", OPRL(0x12,0x29), BASE, ARG_OPRL }, ++ { "cmple", OPR(0x10,0x2A), BASE, ARG_OPR }, ++ { "cmple", OPRL(0x12,0x2A), BASE, ARG_OPRL }, ++ { "cmpult", OPR(0x10,0x2B), BASE, ARG_OPR }, ++ { "cmpult", OPRL(0x12,0x2B), BASE, ARG_OPRL }, ++ { "cmpule", OPR(0x10,0x2C), BASE, ARG_OPR }, ++ { "cmpule", OPRL(0x12,0x2C), BASE, ARG_OPRL }, ++ ++ { "and", OPR(0x10,0x38), BASE, ARG_OPR }, ++ { "and", OPRL(0x12,0x38),BASE, ARG_OPRL }, ++ { "bic", OPR(0x10,0x39), BASE, ARG_OPR }, ++ { "bic", OPRL(0x12,0x39),BASE, ARG_OPRL }, ++ { "bis", OPR(0x10,0x3A), BASE, ARG_OPR }, ++ { "bis", OPRL(0x12,0x3A),BASE, ARG_OPRL }, ++ { "ornot", OPR(0x10,0x3B), BASE, ARG_OPR }, ++ { "ornot", OPRL(0x12,0x3B),BASE, ARG_OPRL }, ++ { "xor", OPR(0x10,0x3C), BASE, ARG_OPR }, ++ { "xor", OPRL(0x12,0x3C),BASE, ARG_OPRL }, ++ { "eqv", OPR(0x10,0x3D), BASE, ARG_OPR }, ++ { "eqv", OPRL(0x12,0x3D),BASE, ARG_OPRL }, ++ { "inslb", OPR(0x10,0x40), BASE, ARG_OPR }, ++ { "inslb", OPRL(0x12,0x40),BASE, ARG_OPRL }, ++ { "inslh", OPR(0x10,0x41), BASE, ARG_OPR }, ++ { "inslh", OPRL(0x12,0x41),BASE, ARG_OPRL }, ++ { "inslw", OPR(0x10,0x42), BASE, ARG_OPR }, ++ { "inslw", OPRL(0x12,0x42),BASE, ARG_OPRL }, ++ { "insll", OPR(0x10,0x43), BASE, ARG_OPR }, ++ { "insll", OPRL(0x12,0x43),BASE, ARG_OPRL }, ++ { "inshb", OPR(0x10,0x44), BASE, ARG_OPR }, ++ { "inshb", OPRL(0x12,0x44),BASE, ARG_OPRL }, ++ { "inshh", OPR(0x10,0x45), BASE, ARG_OPR }, ++ { "inshh", OPRL(0x12,0x45),BASE, ARG_OPRL }, ++ { "inshw", OPR(0x10,0x46), BASE, ARG_OPR }, ++ { "inshw", OPRL(0x12,0x46),BASE, ARG_OPRL }, ++ { "inshl", OPR(0x10,0x47), BASE, ARG_OPR }, ++ { "inshl", OPRL(0x12,0x47),BASE, ARG_OPRL }, ++ ++ { "sll", OPR(0x10,0x48), BASE, ARG_OPR }, ++ { "sll", OPRL(0x12,0x48),BASE, ARG_OPRL }, ++ { "srl", OPR(0x10,0x49), BASE, ARG_OPR }, ++ { "srl", OPRL(0x12,0x49),BASE, ARG_OPRL }, ++ { "sra", OPR(0x10,0x4A), BASE, ARG_OPR }, ++ { "sra", OPRL(0x12,0x4A),BASE, ARG_OPRL }, ++ { "extlb", OPR(0x10,0x50), BASE, ARG_OPR }, ++ { "extlb", OPRL(0x12,0x50),BASE, ARG_OPRL }, ++ { "extlh", OPR(0x10,0x51), BASE, ARG_OPR }, ++ { "extlh", OPRL(0x12,0x51),BASE, ARG_OPRL }, ++ { "extlw", OPR(0x10,0x52), BASE, ARG_OPR }, ++ { "extlw", OPRL(0x12,0x52),BASE, ARG_OPRL }, ++ { "extll", OPR(0x10,0x53), BASE, ARG_OPR }, ++ { "extll", OPRL(0x12,0x53),BASE, ARG_OPRL }, ++ { "exthb", OPR(0x10,0x54), BASE, ARG_OPR }, ++ { "exthb", OPRL(0x12,0x54),BASE, ARG_OPRL }, ++ { "exthh", OPR(0x10,0x55), BASE, ARG_OPR }, ++ { "exthh", OPRL(0x12,0x55),BASE, ARG_OPRL }, ++ { "exthw", OPR(0x10,0x56), BASE, ARG_OPR }, ++ { "exthw", OPRL(0x12,0x56),BASE, ARG_OPRL }, ++ { "exthl", OPR(0x10,0x57), BASE, ARG_OPR }, ++ { "exthl", OPRL(0x12,0x57),BASE, ARG_OPRL }, ++ { "ctpop", OPR(0x10,0x58), BASE, ARG_OPRZ1 }, ++ { "ctlz", OPR(0x10,0x59), BASE, ARG_OPRZ1 }, ++ { "cttz", OPR(0x10,0x5A), BASE, ARG_OPRZ1 }, ++ { "masklb", OPR(0x10,0x60), BASE, ARG_OPR }, ++ { "masklb", OPRL(0x12,0x60),BASE, ARG_OPRL }, ++ { "masklh", OPR(0x10,0x61), BASE, ARG_OPR }, ++ { "masklh", OPRL(0x12,0x61),BASE, ARG_OPRL }, ++ { "masklw", OPR(0x10,0x62), BASE, ARG_OPR }, ++ { "masklw", OPRL(0x12,0x62),BASE, ARG_OPRL }, ++ { "maskll", OPR(0x10,0x63), BASE, ARG_OPR }, ++ { "maskll", OPRL(0x12,0x63),BASE, ARG_OPRL }, ++ { "maskhb", OPR(0x10,0x64), BASE, ARG_OPR }, ++ { "maskhb", OPRL(0x12,0x64),BASE, ARG_OPRL }, ++ { "maskhh", OPR(0x10,0x65), BASE, ARG_OPR }, ++ { "maskhh", OPRL(0x12,0x65),BASE, ARG_OPRL }, ++ { "maskhw", OPR(0x10,0x66), BASE, ARG_OPR }, ++ { "maskhw", OPRL(0x12,0x66),BASE, ARG_OPRL }, ++ { "maskhl", OPR(0x10,0x67), BASE, ARG_OPR }, ++ { "maskhl", OPRL(0x12,0x67),BASE, ARG_OPRL }, ++ { "zap", OPR(0x10,0x68), BASE, ARG_OPR }, ++ { "zap", OPRL(0x12,0x68),BASE, ARG_OPRL }, ++ { "zapnot", OPR(0x10,0x69), BASE, ARG_OPR }, ++ { "zapnot", OPRL(0x12,0x69),BASE, ARG_OPRL }, ++ { "sextb", OPR(0x10,0x6A), BASE, ARG_OPRZ1}, ++ { "sextb", OPRL(0x12,0x6A),BASE, ARG_OPRLZ1 }, ++ { "sexth", OPR(0x10,0x6B), BASE, ARG_OPRZ1 }, ++ { "sexth", OPRL(0x12,0x6B),BASE, ARG_OPRLZ1 }, ++ { "cmpgeb", OPR(0x10,0x6C), BASE, ARG_OPR }, ++ { "cmpgeb", OPRL(0x12,0x6C),BASE, ARG_OPRL }, ++ { "fimovs", OPR(0x10,0x70), BASE, { FA, ZB, RC } }, ++ { "fimovd", OPR(0x10,0x78), BASE, { FA, ZB, RC } }, ++ { "seleq", TOPR(0x11,0x0), BASE, ARG_TOPR }, ++ { "seleq", TOPRL(0x13,0x0),BASE, ARG_TOPRL }, ++ { "selge", TOPR(0x11,0x1), BASE, ARG_TOPR }, ++ { "selge", TOPRL(0x13,0x1),BASE, ARG_TOPRL }, ++ { "selgt", TOPR(0x11,0x2), BASE, ARG_TOPR }, ++ { "selgt", TOPRL(0x13,0x2),BASE, ARG_TOPRL }, ++ { "selle", TOPR(0x11,0x3), BASE, ARG_TOPR }, ++ { "selle", TOPRL(0x13,0x3),BASE, ARG_TOPRL }, ++ { "sellt", TOPR(0x11,0x4), BASE, ARG_TOPR }, ++ { "sellt", TOPRL(0x13,0x4),BASE, ARG_TOPRL }, ++ { "selne", TOPR(0x11,0x5), BASE, ARG_TOPR }, ++ { "selne", TOPRL(0x13,0x5),BASE, ARG_TOPRL }, ++ { "sellbc", TOPR(0x11,0x6), BASE, ARG_TOPR }, ++ { "sellbc", TOPRL(0x13,0x6),BASE, ARG_TOPRL }, ++ { "sellbs", TOPR(0x11,0x7), BASE, ARG_TOPR }, ++ { "sellbs", TOPRL(0x13,0x7),BASE, ARG_TOPRL }, ++ { "vlog", LOGX(0x14,0x00), BASE, ARG_FMA }, ++ ++ { "fadds", FP(0x18,0x00), BASE, ARG_FP }, ++ { "faddd", FP(0x18,0x01), BASE, ARG_FP }, ++ { "fsubs", FP(0x18,0x02), BASE, ARG_FP }, ++ { "fsubd", FP(0x18,0x03), BASE, ARG_FP }, ++ { "fmuls", FP(0x18,0x04), BASE, ARG_FP }, ++ { "fmuld", FP(0x18,0x05), BASE, ARG_FP }, ++ { "fdivs", FP(0x18,0x06), BASE, ARG_FP }, ++ { "fdivd", FP(0x18,0x07), BASE, ARG_FP }, ++ { "fsqrts", FP(0x18,0x08), BASE, ARG_FPZ1 }, ++ { "fsqrtd", FP(0x18,0x09), BASE, ARG_FPZ1 }, ++ { "fcmpeq", FP(0x18,0x10), BASE, ARG_FP }, ++ { "fcmple", FP(0x18,0x11), BASE, ARG_FP }, ++ { "fcmplt", FP(0x18,0x12), BASE, ARG_FP }, ++ { "fcmpun", FP(0x18,0x13), BASE, ARG_FP }, ++ ++ { "fcvtsd", FP(0x18,0x20), BASE, ARG_FPZ1 }, ++ { "fcvtds", FP(0x18,0x21), BASE, ARG_FPZ1 }, ++ { "fcvtdl_g", FP(0x18,0x22), BASE, ARG_FPZ1 }, ++ { "fcvtdl_p", FP(0x18,0x23), BASE, ARG_FPZ1 }, ++ { "fcvtdl_z", FP(0x18,0x24), BASE, ARG_FPZ1 }, ++ { "fcvtdl_n", FP(0x18,0x25), BASE, ARG_FPZ1 }, ++ { "fcvtdl", FP(0x18,0x27), BASE, ARG_FPZ1 }, ++ { "fcvtwl", FP(0x18,0x28), BASE, ARG_FPZ1 }, ++ { "fcvtlw", FP(0x18,0x29), BASE, ARG_FPZ1 }, ++ { "fcvtls", FP(0x18,0x2d), BASE, ARG_FPZ1 }, ++ { "fcvtld", FP(0x18,0x2f), BASE, ARG_FPZ1 }, ++ { "fcpys", FP(0x18,0x30), BASE, ARG_FP }, ++ { "fcpyse", FP(0x18,0x31), BASE, ARG_FP }, ++ { "fcpysn", FP(0x18,0x32), BASE, ARG_FP }, ++ { "ifmovs", FP(0x18,0x40), BASE, { RA, ZB, FC } }, ++ { "ifmovd", FP(0x18,0x41), BASE, { RA, ZB, FC } }, ++ { "rfpcr", FP(0x18,0x50), BASE, { FA, RBA, RCA } }, ++ { "wfpcr", FP(0x18,0x51), BASE, { FA, RBA, RCA } }, ++ { "setfpec0", FP(0x18,0x54), BASE, ARG_NONE }, ++ { "setfpec1", FP(0x18,0x55), BASE, ARG_NONE }, ++ { "setfpec2", FP(0x18,0x56), BASE, ARG_NONE }, ++ { "setfpec3", FP(0x18,0x57), BASE, ARG_NONE }, ++ { "fmas", FMA(0x19,0x00), BASE, ARG_FMA }, ++ { "fmad", FMA(0x19,0x01), BASE, ARG_FMA }, ++ { "fmss", FMA(0x19,0x02), BASE, ARG_FMA }, ++ { "fmsd", FMA(0x19,0x03), BASE, ARG_FMA }, ++ { "fnmas", FMA(0x19,0x04), BASE, ARG_FMA }, ++ { "fnmad", FMA(0x19,0x05), BASE, ARG_FMA }, ++ { "fnmss", FMA(0x19,0x06), BASE, ARG_FMA }, ++ { "fnmsd", FMA(0x19,0x07), BASE, ARG_FMA }, ++ { "fseleq", FMA(0x19,0x10), BASE, ARG_FMA }, ++ { "fselne", FMA(0x19,0x11), BASE, ARG_FMA }, ++ { "fsellt", FMA(0x19,0x12), BASE, ARG_FMA }, ++ { "fselle", FMA(0x19,0x13), BASE, ARG_FMA }, ++ { "fselgt", FMA(0x19,0x14), BASE, ARG_FMA }, ++ { "fselge", FMA(0x19,0x15), BASE, ARG_FMA }, ++ { "vaddw", FP(0x1A,0x00), BASE, ARG_FP }, ++ { "vaddw", FP(0x1A,0x20), BASE, ARG_FPL }, ++ { "vsubw", FP(0x1A,0x01), BASE, ARG_FP }, ++ { "vsubw", FP(0x1A,0x21), BASE, ARG_FPL }, ++ { "vcmpgew", FP(0x1A,0x02), BASE, ARG_FP }, ++ { "vcmpgew", FP(0x1A,0x22), BASE, ARG_FPL }, ++ { "vcmpeqw", FP(0x1A,0x03), BASE, ARG_FP }, ++ { "vcmpeqw", FP(0x1A,0x23), BASE, ARG_FPL }, ++ { "vcmplew", FP(0x1A,0x04), BASE, ARG_FP }, ++ { "vcmplew", FP(0x1A,0x24), BASE, ARG_FPL }, ++ { "vcmpltw", FP(0x1A,0x05), BASE, ARG_FP }, ++ { "vcmpltw", FP(0x1A,0x25), BASE, ARG_FPL }, ++ { "vcmpulew", FP(0x1A,0x06), BASE, ARG_FP }, ++ { "vcmpulew", FP(0x1A,0x26), BASE, ARG_FPL }, ++ { "vcmpultw", FP(0x1A,0x07), BASE, ARG_FP }, ++ { "vcmpultw", FP(0x1A,0x27), BASE, ARG_FPL }, ++ ++ { "vsllw", FP(0x1A,0x08), BASE, ARG_FP }, ++ { "vsllw", FP(0x1A,0x28), BASE, ARG_FPL }, ++ { "vsrlw", FP(0x1A,0x09), BASE, ARG_FP }, ++ { "vsrlw", FP(0x1A,0x29), BASE, ARG_FPL }, ++ { "vsraw", FP(0x1A,0x0A), BASE, ARG_FP }, ++ { "vsraw", FP(0x1A,0x2A), BASE, ARG_FPL }, ++ { "vrolw", FP(0x1A,0x0B), BASE, ARG_FP }, ++ { "vrolw", FP(0x1A,0x2B), BASE, ARG_FPL }, ++ { "sllow", FP(0x1A,0x0C), BASE, ARG_FP }, ++ { "sllow", FP(0x1A,0x2C), BASE, ARG_FPL }, ++ { "srlow", FP(0x1A,0x0D), BASE, ARG_FP }, ++ { "srlow", FP(0x1A,0x2D), BASE, ARG_FPL }, ++ { "vaddl", FP(0x1A,0x0E), BASE, ARG_FP }, ++ { "vaddl", FP(0x1A,0x2E), BASE, ARG_FPL }, ++ { "vsubl", FP(0x1A,0x0F), BASE, ARG_FP }, ++ { "vsubl", FP(0x1A,0x2F), BASE, ARG_FPL }, ++ { "ctpopow", FP(0x1A,0x18), BASE, { FA, ZB, DFC1 } }, ++ { "ctlzow", FP(0x1A,0x19), BASE, { FA, ZB, DFC1 } }, ++ { "vucaddw", FP(0x1A,0x40), BASE, ARG_FP }, ++ { "vucaddw", FP(0x1A,0x60), BASE, ARG_FPL }, ++ { "vucsubw", FP(0x1A,0x41), BASE, ARG_FP }, ++ { "vucsubw", FP(0x1A,0x61), BASE, ARG_FPL }, ++ { "vucaddh", FP(0x1A,0x42), BASE, ARG_FP }, ++ { "vucaddh", FP(0x1A,0x62), BASE, ARG_FPL }, ++ { "vucsubh", FP(0x1A,0x43), BASE, ARG_FP }, ++ { "vucsubh", FP(0x1A,0x63), BASE, ARG_FPL }, ++ { "vucaddb", FP(0x1A,0x44), BASE, ARG_FP }, ++ { "vucaddb", FP(0x1A,0x64), BASE, ARG_FPL }, ++ { "vucsubb", FP(0x1A,0x45), BASE, ARG_FP }, ++ { "vucsubb", FP(0x1A,0x65), BASE, ARG_FPL }, ++ { "vadds", FP(0x1A,0x80), BASE, ARG_FP }, ++ { "vaddd", FP(0x1A,0x81), BASE, ARG_FP }, ++ { "vsubs", FP(0x1A,0x82), BASE, ARG_FP }, ++ { "vsubd", FP(0x1A,0x83), BASE, ARG_FP }, ++ { "vmuls", FP(0x1A,0x84), BASE, ARG_FP }, ++ { "vmuld", FP(0x1A,0x85), BASE, ARG_FP }, ++ { "vdivs", FP(0x1A,0x86), BASE, ARG_FP }, ++ { "vdivd", FP(0x1A,0x87), BASE, ARG_FP }, ++ { "vsqrts", FP(0x1A,0x88), BASE, ARG_FPZ1 }, ++ { "vsqrtd", FP(0x1A,0x89), BASE, ARG_FPZ1 }, ++ { "vfcmpeq", FP(0x1A,0x8C), BASE, ARG_FP }, ++ { "vfcmple", FP(0x1A,0x8D), BASE, ARG_FP }, ++ { "vfcmplt", FP(0x1A,0x8E), BASE, ARG_FP }, ++ { "vfcmpun", FP(0x1A,0x8F), BASE, ARG_FP }, ++ { "vcpys", FP(0x1A,0x90), BASE, ARG_FP }, ++ { "vcpyse", FP(0x1A,0x91), BASE, ARG_FP }, ++ { "vcpysn", FP(0x1A,0x92), BASE, ARG_FP }, ++ { "vmas", FMA(0x1B,0x00), BASE, ARG_FMA }, ++ { "vmad", FMA(0x1B,0x01), BASE, ARG_FMA }, ++ { "vmss", FMA(0x1B,0x02), BASE, ARG_FMA }, ++ { "vmsd", FMA(0x1B,0x03), BASE, ARG_FMA }, ++ { "vnmas", FMA(0x1B,0x04), BASE, ARG_FMA }, ++ { "vnmad", FMA(0x1B,0x05), BASE, ARG_FMA }, ++ { "vnmss", FMA(0x1B,0x06), BASE, ARG_FMA }, ++ { "vnmsd", FMA(0x1B,0x07), BASE, ARG_FMA }, ++ { "vfseleq", FMA(0x1B,0x10), BASE, ARG_FMA }, ++ { "vfsellt", FMA(0x1B,0x12), BASE, ARG_FMA }, ++ { "vfselle", FMA(0x1B,0x13), BASE, ARG_FMA }, ++ { "vseleqw", FMA(0x1B,0x18), BASE, ARG_FMA }, ++ { "vseleqw", FMA(0x1B,0x38), BASE, ARG_FMAL }, ++ { "vsellbcw", FMA(0x1B,0x19), BASE, ARG_FMA }, ++ { "vsellbcw", FMA(0x1B,0x39), BASE, ARG_FMAL }, ++ { "vselltw", FMA(0x1B,0x1A), BASE, ARG_FMA }, ++ { "vselltw", FMA(0x1B,0x3A), BASE, ARG_FMAL }, ++ { "vsellew", FMA(0x1B,0x1B), BASE, ARG_FMA }, ++ { "vsellew", FMA(0x1B,0x3B), BASE, ARG_FMAL }, ++ { "vinsw", FMA(0x1B,0x20), BASE, ARG_FMAL }, ++ { "vinsf", FMA(0x1B,0x21), BASE, ARG_FMAL }, ++ { "vextw", FMA(0x1B,0x22), BASE, { FA, FMALIT, DFC1 }}, ++ { "vextf", FMA(0x1B,0x23), BASE, { FA, FMALIT, DFC1 }}, ++ { "vcpyw", FMA(0x1B,0x24), BASE, { FA, DFC1 }}, ++ { "vcpyf", FMA(0x1B,0x25), BASE, { FA, DFC1 }}, ++ { "vconw", FMA(0x1B,0x26), BASE, ARG_FMA }, ++ { "vshfw", FMA(0x1B,0x27), BASE, ARG_FMA }, ++ { "vcons", FMA(0x1B,0x28), BASE, ARG_FMA }, ++ { "vcond", FMA(0x1B,0x29), BASE, ARG_FMA }, ++ { "vldw_u", ATMEM(0x1C,0x0), BASE, ARG_VUAMEM }, ++ { "vstw_u", ATMEM(0x1C,0x1), BASE, ARG_VUAMEM }, ++ { "vlds_u", ATMEM(0x1C,0x2), BASE, ARG_VUAMEM }, ++ { "vsts_u", ATMEM(0x1C,0x3), BASE, ARG_VUAMEM }, ++ { "vldd_u", ATMEM(0x1C,0x4), BASE, ARG_VUAMEM }, ++ { "vstd_u", ATMEM(0x1C,0x5), BASE, ARG_VUAMEM }, ++ { "vstw_ul", ATMEM(0x1C,0x8), BASE, ARG_VUAMEM }, ++ { "vstw_uh", ATMEM(0x1C,0x9), BASE, ARG_VUAMEM }, ++ { "vsts_ul", ATMEM(0x1C,0xA), BASE, ARG_VUAMEM }, ++ { "vsts_uh", ATMEM(0x1C,0xB), BASE, ARG_VUAMEM }, ++ { "vstd_ul", ATMEM(0x1C,0xC), BASE, ARG_VUAMEM }, ++ { "vstd_uh", ATMEM(0x1C,0xD), BASE, ARG_VUAMEM }, ++ { "vldd_nc", ATMEM(0x1C,0xE), BASE, ARG_VUAMEM }, ++ { "vstd_nc", ATMEM(0x1C,0xF), BASE, ARG_VUAMEM }, ++ ++ { "flushd", MEM(0x20), BASE, ARG_PREFETCH }, ++ { "ldbu", MEM(0x20), BASE, ARG_MEM }, ++ { "evictdg", MEM(0x21), BASE, ARG_PREFETCH }, ++ { "ldhu", MEM(0x21), BASE, ARG_MEM }, ++ { "s_fillcs", MEM(0x22), BASE, ARG_PREFETCH }, ++ { "ldw", MEM(0x22), BASE, ARG_MEM }, ++ { "s_fillde", MEM(0x23), BASE, ARG_PREFETCH }, ++ { "ldl", MEM(0x23), BASE, ARG_MEM }, ++ { "evictdl", MEM(0x24), BASE, ARG_PREFETCH }, ++ { "ldl_u", MEM(0x24), BASE, ARG_MEM }, ++ { "pri_ldw/p", HWMEM(0x25,0x0), BASE, ARG_HWMEM }, ++ { "pri_ldw/v", HWMEM(0x25,0x8), BASE, ARG_HWMEM }, ++ { "pri_ldl/p", HWMEM(0x25,0x1), BASE, ARG_HWMEM }, ++ { "pri_ldl/v", HWMEM(0x25,0x9), BASE, ARG_HWMEM }, ++ { "fillde", MEM(0x26), BASE, ARG_PREFETCH }, ++ { "flds", MEM(0x26), BASE, ARG_FMEM }, ++ { "fillde_e", MEM(0x27), BASE, ARG_PREFETCH }, ++ { "fldd", MEM(0x27), BASE, ARG_FMEM }, ++ ++ { "stb", MEM(0x28), BASE, ARG_MEM }, ++ { "sth", MEM(0x29), BASE, ARG_MEM }, ++ { "stw", MEM(0x2A), BASE, ARG_MEM }, ++ { "stl", MEM(0x2B), BASE, ARG_MEM }, ++ { "stl_u", MEM(0x2C), BASE, ARG_MEM }, ++ { "pri_stw/p", HWMEM(0x2D,0x0), BASE, ARG_HWMEM }, ++ { "pri_stw/v", HWMEM(0x2D,0x8), BASE, ARG_HWMEM }, ++ { "pri_stl/p", HWMEM(0x2D,0x1), BASE, ARG_HWMEM }, ++ { "pri_stl/v", HWMEM(0x2D,0x9), BASE, ARG_HWMEM }, ++ { "fsts", MEM(0x2E), BASE, ARG_FMEM }, ++ { "fstd", MEM(0x2F), BASE, ARG_FMEM }, ++ { "beq", BRA(0x30), BASE, ARG_BRA }, ++ { "bne", BRA(0x31), BASE, ARG_BRA }, ++ { "blt", BRA(0x32), BASE, ARG_BRA }, ++ { "ble", BRA(0x33), BASE, ARG_BRA }, ++ { "bgt", BRA(0x34), BASE, ARG_BRA }, ++ { "bge", BRA(0x35), BASE, ARG_BRA }, ++ { "blbc", BRA(0x36), BASE, ARG_BRA }, ++ { "blbs", BRA(0x37), BASE, ARG_BRA }, ++ ++ { "fbeq", BRA(0x38), BASE, ARG_FBRA }, ++ { "fbne", BRA(0x39), BASE, ARG_FBRA }, ++ { "fblt", BRA(0x3A), BASE, ARG_FBRA }, ++ { "fble", BRA(0x3B), BASE, ARG_FBRA }, ++ { "fbgt", BRA(0x3C), BASE, ARG_FBRA }, ++ { "fbge", BRA(0x3D), BASE, ARG_FBRA }, ++ { "ldi", MEM(0x3E), BASE, ARG_MEM }, ++ { "ldih", MEM(0x3F), BASE, ARG_MEM }, ++}; ++ ++const unsigned sw_64_num_opcodes = sizeof(sw_64_opcodes) / sizeof(*sw_64_opcodes); ++ ++/* OSF register names. */ ++ ++static const char * const osf_regnames[64] = { ++ "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", ++ "$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", "$f31" ++}; ++ ++/* VMS register names. */ ++ ++static const char * const vms_regnames[64] = { ++ "R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7", ++ "R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15", ++ "R16", "R17", "R18", "R19", "R20", "R21", "R22", "R23", ++ "R24", "AI", "RA", "PV", "AT", "FP", "SP", "RZ", ++ "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", "FZ" ++}; ++ ++int print_insn_sw_64(bfd_vma memaddr, struct disassemble_info *info) ++{ ++ static const struct sw_64_opcode *opcode_index[SW_NOPS + 1]; ++ const char * const * regnames; ++ const struct sw_64_opcode *opcode, *opcode_end; ++ const unsigned char *opindex; ++ unsigned insn, op, isa_mask; ++ int need_comma; ++ ++ /* Initialize the majorop table the first time through */ ++ if (!opcode_index[0]) { ++ opcode = sw_64_opcodes; ++ opcode_end = opcode + sw_64_num_opcodes; ++ ++ for (op = 0; op < SW_NOPS; ++op) { ++ opcode_index[op] = opcode; ++ if ((SW_LITOP (opcode->opcode) != 0x10) && (SW_LITOP (opcode->opcode) != 0x11)) { ++ while (opcode < opcode_end && op == SW_OP (opcode->opcode)) ++ ++opcode; ++ } else { ++ while (opcode < opcode_end && op == SW_LITOP (opcode->opcode)) ++ ++opcode; ++ } ++ } ++ opcode_index[op] = opcode; ++ } ++ ++ if (info->flavour == bfd_target_evax_flavour) ++ regnames = vms_regnames; ++ else ++ regnames = osf_regnames; ++ isa_mask = SW_OPCODE_NOHM; ++ switch (info->mach) { ++ case bfd_mach_sw_64_core3: ++ isa_mask |= SW_OPCODE_BASE | SW_OPCODE_CORE3; ++ break; ++ } ++ ++ /* Read the insn into a host word */ ++ { ++ bfd_byte buffer[4]; ++ int status = (*info->read_memory_func) (memaddr, buffer, 4, info); ++ if (status != 0) { ++ (*info->memory_error_func) (status, memaddr, info); ++ return -1; ++ } ++ insn = bfd_getl32 (buffer); ++ } ++ ++ /* Get the major opcode of the instruction. */ ++ if ((SW_LITOP (insn) == 0x10) || (SW_LITOP (insn) == 0x11)) ++ op = SW_LITOP (insn); ++ else if ((SW_OP(insn) & 0x3C) == 0x14 ) ++ op = 0x14; ++ else ++ op = SW_OP (insn); ++ ++ /* Find the first match in the opcode table. */ ++ opcode_end = opcode_index[op + 1]; ++ for (opcode = opcode_index[op]; opcode < opcode_end; ++opcode) { ++ if ((insn ^ opcode->opcode) & opcode->mask) ++ continue; ++ ++ if (!(opcode->flags & isa_mask)) ++ continue; ++ ++ /* Make two passes over the operands. First see if any of them ++ have extraction functions, and, if they do, make sure the ++ instruction is valid. */ ++ { ++ int invalid = 0; ++ for (opindex = opcode->operands; *opindex != 0; opindex++) { ++ const struct sw_64_operand *operand = sw_64_operands + *opindex; ++ if (operand->extract) ++ (*operand->extract) (insn, &invalid); ++ } ++ if (invalid) ++ continue; ++ } ++ ++ /* The instruction is valid. */ ++ goto found; ++ } ++ ++ /* No instruction found */ ++ (*info->fprintf_func) (info->stream, ".long %#08x", insn); ++ ++ return 4; ++ ++found: ++ if (!strncmp("sys_call",opcode->name,8)) { ++ if (insn & (0x1 << 25)) ++ (*info->fprintf_func) (info->stream, "%s", "sys_call"); ++ else ++ (*info->fprintf_func) (info->stream, "%s", "sys_call/b"); ++ } else ++ (*info->fprintf_func) (info->stream, "%s", opcode->name); ++ ++ /* get zz[7:6] and zz[5:0] to form truth for vlog */ ++ if (!strcmp(opcode->name, "vlog")) ++ { ++ unsigned int truth; ++ char tr[4]; ++ truth=(SW_OP(insn) & 3) << 6; ++ truth = truth | ((insn & 0xFC00) >> 10); ++ sprintf(tr,"%x",truth); ++ (*info->fprintf_func) (info->stream, "%s", tr); ++ } ++ if (opcode->operands[0] != 0) ++ (*info->fprintf_func) (info->stream, "\t"); ++ ++ /* Now extract and print the operands. */ ++ need_comma = 0; ++ for (opindex = opcode->operands; *opindex != 0; opindex++) { ++ const struct sw_64_operand *operand = sw_64_operands + *opindex; ++ int value; ++ ++ /* Operands that are marked FAKE are simply ignored. We ++ already made sure that the extract function considered ++ the instruction to be valid. */ ++ if ((operand->flags & SW_OPERAND_FAKE) != 0) ++ continue; ++ ++ /* Extract the value from the instruction. */ ++ if (operand->extract) ++ value = (*operand->extract) (insn, (int *) NULL); ++ else { ++ value = (insn >> operand->shift) & ((1 << operand->bits) - 1); ++ if (operand->flags & SW_OPERAND_SIGNED) { ++ int signbit = 1 << (operand->bits - 1); ++ value = (value ^ signbit) - signbit; ++ } ++ } ++ ++ if (need_comma && ++ ((operand->flags & (SW_OPERAND_PARENS | SW_OPERAND_COMMA)) ++ != SW_OPERAND_PARENS)) { ++ (*info->fprintf_func) (info->stream, ","); ++ } ++ if (operand->flags & SW_OPERAND_PARENS) ++ (*info->fprintf_func) (info->stream, "("); ++ ++ /* Print the operand as directed by the flags. */ ++ if (operand->flags & SW_OPERAND_IR) ++ (*info->fprintf_func) (info->stream, "%s", regnames[value]); ++ else if (operand->flags & SW_OPERAND_FPR) ++ (*info->fprintf_func) (info->stream, "%s", regnames[value + 32]); ++ else if (operand->flags & SW_OPERAND_RELATIVE) ++ (*info->print_address_func) (memaddr + 4 + value, info); ++ else if (operand->flags & SW_OPERAND_SIGNED) ++ (*info->fprintf_func) (info->stream, "%d", value); ++ else ++ (*info->fprintf_func) (info->stream, "%#x", value); ++ ++ if (operand->flags & SW_OPERAND_PARENS) ++ (*info->fprintf_func) (info->stream, ")"); ++ need_comma = 1; ++ } ++ ++ return 4; ++} +diff --git a/hw/Kconfig b/hw/Kconfig +index ad20cce0a9..5f3957be0f 100644 +--- a/hw/Kconfig ++++ b/hw/Kconfig +@@ -63,6 +63,7 @@ source sparc/Kconfig + source sparc64/Kconfig + source tricore/Kconfig + source xtensa/Kconfig ++source sw64/Kconfig + + # Symbols used by multiple targets + config TEST_DEVICES +diff --git a/hw/meson.build b/hw/meson.build +index b3366c888e..f39c1f7e70 100644 +--- a/hw/meson.build ++++ b/hw/meson.build +@@ -62,5 +62,6 @@ subdir('s390x') + subdir('sh4') + subdir('sparc') + subdir('sparc64') ++subdir('sw64') + subdir('tricore') + subdir('xtensa') +diff --git a/hw/rtc/sun4v-rtc.c b/hw/rtc/sun4v-rtc.c +index e037acd1b5..58a0cff483 100644 +--- a/hw/rtc/sun4v-rtc.c ++++ b/hw/rtc/sun4v-rtc.c +@@ -32,10 +32,17 @@ static uint64_t sun4v_rtc_read(void *opaque, hwaddr addr, + unsigned size) + { + uint64_t val = get_clock_realtime() / NANOSECONDS_PER_SECOND; ++#if defined(__sw_64__) ++ if (addr & 4ULL) { ++ /* accessing the high 32 bits */ ++ val >>= 32; ++ } ++#else + if (!(addr & 4ULL)) { + /* accessing the high 32 bits */ + val >>= 32; + } ++#endif + trace_sun4v_rtc_read(addr, val); + return val; + } +@@ -49,7 +56,11 @@ static void sun4v_rtc_write(void *opaque, hwaddr addr, + static const MemoryRegionOps sun4v_rtc_ops = { + .read = sun4v_rtc_read, + .write = sun4v_rtc_write, ++#if defined(__sw_64__) ++ .endianness = DEVICE_LITTLE_ENDIAN, ++#else + .endianness = DEVICE_NATIVE_ENDIAN, ++#endif + }; + + void sun4v_rtc_init(hwaddr addr) +diff --git a/hw/sw64/Kconfig b/hw/sw64/Kconfig +new file mode 100644 +index 0000000000..2bf19e8234 +--- /dev/null ++++ b/hw/sw64/Kconfig +@@ -0,0 +1,11 @@ ++config CORE3 ++ bool ++ imply PCI_DEVICES ++ imply TEST_DEVICES ++ imply E1000_PCI ++ select PCI_EXPRESS ++ select SUN4V_RTC ++ select VIRTIO_MMIO ++ select SERIAL ++ select IDE_CMD646 ++ select VIRTIO_VGA +diff --git a/hw/sw64/Makefile.objs b/hw/sw64/Makefile.objs +new file mode 100644 +index 0000000000..73add9a91d +--- /dev/null ++++ b/hw/sw64/Makefile.objs +@@ -0,0 +1 @@ ++obj-y += core3.o core3_board.o +diff --git a/hw/sw64/core.h b/hw/sw64/core.h +new file mode 100644 +index 0000000000..4923382229 +--- /dev/null ++++ b/hw/sw64/core.h +@@ -0,0 +1,25 @@ ++#ifndef HW_SW64_SYS_H ++#define HW_SW64_SYS_H ++ ++typedef struct boot_params { ++ unsigned long initrd_size; /* size of initrd */ ++ unsigned long initrd_start; /* logical address of initrd */ ++ unsigned long dtb_start; /* logical address of dtb */ ++ unsigned long efi_systab; /* logical address of EFI system table */ ++ unsigned long efi_memmap; /* logical address of EFI memory map */ ++ unsigned long efi_memmap_size; /* size of EFI memory map */ ++ unsigned long efi_memdesc_size; /* size of an EFI memory map descriptor */ ++ unsigned long efi_memdesc_version; /* memory descriptor version */ ++ unsigned long cmdline; /* logical address of cmdline */ ++} BOOT_PARAMS; ++ ++void core3_board_init(SW64CPU *cpus[4], MemoryRegion *ram); ++#endif ++ ++#define MAX_CPUS 64 ++ ++#ifdef CONFIG_KVM ++#define MAX_CPUS_CORE3 64 ++#else ++#define MAX_CPUS_CORE3 32 ++#endif +diff --git a/hw/sw64/core3.c b/hw/sw64/core3.c +new file mode 100644 +index 0000000000..dbe4ed6fa1 +--- /dev/null ++++ b/hw/sw64/core3.c +@@ -0,0 +1,182 @@ ++/* ++ * QEMU CORE3 hardware system emulator. ++ * ++ * Copyright (c) 2021 Lu Feifei ++ * ++ * This work is licensed under the GNU GPL license version 2 or later. ++ */ ++ ++#include "qemu/osdep.h" ++#include "qemu-common.h" ++#include "qemu/datadir.h" ++#include "cpu.h" ++#include "hw/hw.h" ++#include "elf.h" ++#include "hw/loader.h" ++#include "hw/boards.h" ++#include "qemu/error-report.h" ++#include "sysemu/sysemu.h" ++#include "sysemu/kvm.h" ++#include "sysemu/reset.h" ++#include "hw/ide.h" ++#include "hw/char/serial.h" ++#include "qemu/cutils.h" ++#include "ui/console.h" ++#include "core.h" ++#include "hw/boards.h" ++#include "sysemu/numa.h" ++ ++static uint64_t cpu_sw64_virt_to_phys(void *opaque, uint64_t addr) ++{ ++ return addr &= ~0xffffffff80000000 ; ++} ++ ++static CpuInstanceProperties ++sw64_cpu_index_to_props(MachineState *ms, unsigned cpu_index) ++{ ++ MachineClass *mc = MACHINE_GET_CLASS(ms); ++ const CPUArchIdList *possible_cpus = mc->possible_cpu_arch_ids(ms); ++ ++ assert(cpu_index < possible_cpus->len); ++ return possible_cpus->cpus[cpu_index].props; ++} ++ ++static int64_t sw64_get_default_cpu_node_id(const MachineState *ms, int idx) ++{ ++ int nb_numa_nodes = ms->numa_state->num_nodes; ++ return idx % nb_numa_nodes; ++} ++ ++static const CPUArchIdList *sw64_possible_cpu_arch_ids(MachineState *ms) ++{ ++ int i; ++ unsigned int max_cpus = ms->smp.max_cpus; ++ ++ if (ms->possible_cpus) { ++ /* ++ * make sure that max_cpus hasn't changed since the first use, i.e. ++ * -smp hasn't been parsed after it ++ */ ++ assert(ms->possible_cpus->len == max_cpus); ++ return ms->possible_cpus; ++ } ++ ++ ms->possible_cpus = g_malloc0(sizeof(CPUArchIdList) + ++ sizeof(CPUArchId) * max_cpus); ++ ms->possible_cpus->len = max_cpus; ++ for (i = 0; i < ms->possible_cpus->len; i++) { ++ ms->possible_cpus->cpus[i].type = ms->cpu_type; ++ ms->possible_cpus->cpus[i].vcpus_count = 1; ++ ms->possible_cpus->cpus[i].arch_id = i; ++ ms->possible_cpus->cpus[i].props.has_thread_id = true; ++ ms->possible_cpus->cpus[i].props.core_id = i; ++ } ++ ++ return ms->possible_cpus; ++} ++ ++static void core3_cpu_reset(void *opaque) ++{ ++ SW64CPU *cpu = opaque; ++ ++ cpu_reset(CPU(cpu)); ++} ++ ++static void core3_init(MachineState *machine) ++{ ++ ram_addr_t ram_size = machine->ram_size; ++ ram_addr_t buf; ++ SW64CPU *cpus[machine->smp.max_cpus]; ++ long i, size; ++ const char *kernel_filename = machine->kernel_filename; ++ const char *kernel_cmdline = machine->kernel_cmdline; ++ char *hmcode_filename; ++ char *uefi_filename; ++ uint64_t hmcode_entry, hmcode_low, hmcode_high; ++ uint64_t kernel_entry, kernel_low, kernel_high; ++ BOOT_PARAMS *core3_boot_params = g_new0(BOOT_PARAMS, 1); ++ uint64_t param_offset; ++ ++ memset(cpus, 0, sizeof(cpus)); ++ ++ for (i = 0; i < machine->smp.cpus; ++i) { ++ cpus[i] = SW64_CPU(cpu_create(machine->cpu_type)); ++ cpus[i]->env.csr[CID] = i; ++ qemu_register_reset(core3_cpu_reset, cpus[i]); ++ } ++ core3_board_init(cpus, machine->ram); ++ if (kvm_enabled()) ++ buf = ram_size; ++ else ++ buf = ram_size | (1UL << 63); ++ ++ rom_add_blob_fixed("ram_size", (char *)&buf, 0x8, 0x2040); ++ ++ param_offset = 0x90B000UL; ++ core3_boot_params->cmdline = param_offset | 0xfff0000000000000UL; ++ rom_add_blob_fixed("core3_boot_params", (core3_boot_params), 0x48, 0x90A100); ++ ++ hmcode_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, kvm_enabled() ? "core3-reset":"core3-hmcode"); ++ if (hmcode_filename == NULL) { ++ if (kvm_enabled()) ++ error_report("no core3-reset provided"); ++ else ++ error_report("no core3-hmcode provided"); ++ exit(1); ++ } ++ size = load_elf(hmcode_filename, NULL, cpu_sw64_virt_to_phys, NULL, ++ &hmcode_entry, &hmcode_low, &hmcode_high, NULL, 0, EM_SW64, 0, 0); ++ if (size < 0) { ++ if (kvm_enabled()) ++ error_report("could not load core3-reset: '%s'", hmcode_filename); ++ else ++ error_report("could not load core3-hmcode: '%s'", hmcode_filename); ++ exit(1); ++ } ++ g_free(hmcode_filename); ++ ++ /* Start all cpus at the hmcode RESET entry point. */ ++ for (i = 0; i < machine->smp.cpus; ++i) { ++ cpus[i]->env.pc = hmcode_entry; ++ cpus[i]->env.hm_entry = hmcode_entry; ++ } ++ ++ if (!kernel_filename) { ++ uefi_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, "uefi-bios-sw"); ++ load_image_targphys(uefi_filename, 0x2f00000UL, -1); ++ g_free(uefi_filename); ++ } else { ++ /* Load a kernel. */ ++ size = load_elf(kernel_filename, NULL, cpu_sw64_virt_to_phys, NULL, ++ &kernel_entry, &kernel_low, &kernel_high, NULL, 0, EM_SW64, 0, 0); ++ if (size < 0) { ++ error_report("could not load kernel '%s'", kernel_filename); ++ exit(1); ++ } ++ cpus[0]->env.trap_arg1 = kernel_entry; ++ if (kernel_cmdline) ++ pstrcpy_targphys("cmdline", param_offset, 0x400, kernel_cmdline); ++ } ++} ++ ++static void board_reset(MachineState *state) ++{ ++ qemu_devices_reset(); ++} ++ ++static void core3_machine_init(MachineClass *mc) ++{ ++ mc->desc = "core3 BOARD"; ++ mc->init = core3_init; ++ mc->block_default_type = IF_IDE; ++ mc->max_cpus = MAX_CPUS_CORE3; ++ mc->is_default = 0; ++ mc->reset = board_reset; ++ mc->possible_cpu_arch_ids = sw64_possible_cpu_arch_ids; ++ mc->cpu_index_to_instance_props = sw64_cpu_index_to_props; ++ mc->default_cpu_type = SW64_CPU_TYPE_NAME("core3"); ++ mc->default_ram_id = "ram"; ++ mc->get_default_cpu_node_id = sw64_get_default_cpu_node_id; ++} ++ ++DEFINE_MACHINE("core3", core3_machine_init) +diff --git a/hw/sw64/core3_board.c b/hw/sw64/core3_board.c +new file mode 100644 +index 0000000000..7853e01edb +--- /dev/null ++++ b/hw/sw64/core3_board.c +@@ -0,0 +1,493 @@ ++#include "qemu/osdep.h" ++#include "qapi/error.h" ++#include "cpu.h" ++#include "core.h" ++#include "hw/hw.h" ++#include "hw/boards.h" ++#include "sysemu/sysemu.h" ++#include "exec/address-spaces.h" ++#include "hw/pci/pci_host.h" ++#include "hw/pci/pci.h" ++#include "hw/char/serial.h" ++#include "hw/irq.h" ++#include "net/net.h" ++#include "hw/usb.h" ++#include "hw/ide/pci.h" ++#include "hw/ide/ahci.h" ++#include "sysemu/numa.h" ++#include "sysemu/kvm.h" ++#include "hw/rtc/sun4v-rtc.h" ++#include "hw/pci/msi.h" ++#include "hw/sw64/sw64_iommu.h" ++ ++#define TYPE_SWBOARD_PCI_HOST_BRIDGE "core_board-pcihost" ++#define SWBOARD_PCI_HOST_BRIDGE(obj) \ ++ OBJECT_CHECK(BoardState, (obj), TYPE_SWBOARD_PCI_HOST_BRIDGE) ++ ++#define MAX_IDE_BUS 2 ++#define SW_PIN_TO_IRQ 16 ++ ++typedef struct SWBoard { ++ SW64CPU *cpu[MAX_CPUS_CORE3]; ++} SWBoard; ++ ++typedef struct BoardState { ++ PCIHostState parent_obj; ++ ++ SWBoard sboard; ++ uint64_t expire_time; ++} BoardState; ++ ++typedef struct TimerState { ++ void *opaque; ++ int order; ++} TimerState; ++ ++#ifndef CONFIG_KVM ++static void swboard_alarm_timer(void *opaque) ++{ ++ TimerState *ts = (TimerState *)((uintptr_t)opaque); ++ BoardState *bs = (BoardState *)((uintptr_t)ts->opaque); ++ ++ int cpu = ts->order; ++ cpu_interrupt(CPU(bs->sboard.cpu[cpu]), CPU_INTERRUPT_TIMER); ++} ++#endif ++ ++static PCIINTxRoute sw_route_intx_pin_to_irq(void *opaque, int pin) ++{ ++ PCIINTxRoute route; ++ ++ route.mode = PCI_INTX_ENABLED; ++ route.irq = SW_PIN_TO_IRQ; ++ return route; ++} ++ ++static uint64_t convert_bit(int n) ++{ ++ uint64_t ret = (1UL << n) - 1; ++ ++ if (n == 64) ++ ret = 0xffffffffffffffffUL; ++ return ret; ++} ++ ++static uint64_t mcu_read(void *opaque, hwaddr addr, unsigned size) ++{ ++ MachineState *ms = MACHINE(qdev_get_machine()); ++ unsigned int smp_cpus = ms->smp.cpus; ++ uint64_t ret = 0; ++ switch (addr) { ++ case 0x0000: ++ /* CG_ONLINE */ ++ { ++ int i; ++ for (i = 0; i < smp_cpus; i = i + 4) ++ ret |= (1UL << i); ++ } ++ break; ++ /*IO_START*/ ++ case 0x1300: ++ ret = 0x1; ++ break; ++ case 0x3780: ++ /* MC_ONLINE */ ++ ret = convert_bit(smp_cpus); ++ break; ++ case 0x0900: ++ /* CPUID */ ++ ret = 0; ++ break; ++ case 0x1180: ++ /* LONGTIME */ ++ ret = qemu_clock_get_ns(QEMU_CLOCK_HOST) / 80; ++ break; ++ case 0x4900: ++ /* MC_CONFIG */ ++ break; ++ case 0x0780: ++ /* CORE_ONLINE */ ++ ret = convert_bit(smp_cpus); ++ break; ++ case 0x0680: ++ /* INIT_CTL */ ++ ret = 0x000003AE00000D28; ++ break; ++ default: ++ fprintf(stderr, "Unsupported MCU addr: 0x%04lx\n", addr); ++ return -1; ++ } ++ return ret; ++} ++ ++static void mcu_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) ++{ ++#ifndef CONFIG_KVM ++#ifdef CONFIG_DUMP_PRINTK ++ uint64_t print_addr; ++ uint32_t len; ++ int i; ++ ++ if (addr == 0x40000) { ++ print_addr = val & 0x7fffffff; ++ len = (uint32_t)(val >> 32); ++ uint8_t *buf; ++ buf = malloc(len + 10); ++ memset(buf, 0, len + 10); ++ cpu_physical_memory_rw(print_addr, buf, len, 0); ++ for (i = 0; i < len; i++) ++ printf("%c", buf[i]); ++ ++ free(buf); ++ return; ++ } ++#endif ++#endif ++} ++ ++static const MemoryRegionOps mcu_ops = { ++ .read = mcu_read, ++ .write = mcu_write, ++ .endianness = DEVICE_LITTLE_ENDIAN, ++ .valid = ++ { ++ .min_access_size = 8, ++ .max_access_size = 8, ++ }, ++ .impl = ++ { ++ .min_access_size = 8, ++ .max_access_size = 8, ++ }, ++}; ++ ++static uint64_t intpu_read(void *opaque, hwaddr addr, unsigned size) ++{ ++ uint64_t ret = 0; ++#ifndef CONFIG_KVM ++ switch (addr) { ++ case 0x180: ++ /* LONGTIME */ ++ ret = qemu_clock_get_ns(QEMU_CLOCK_HOST) / 32; ++ break; ++ } ++#endif ++ return ret; ++} ++ ++static void intpu_write(void *opaque, hwaddr addr, uint64_t val, ++ unsigned size) ++{ ++#ifndef CONFIG_KVM ++ BoardState *bs = (BoardState *)opaque; ++ SW64CPU *cpu; ++ switch (addr) { ++ case 0x00: ++ val &= 0x1f; ++ cpu = bs->sboard.cpu[val]; ++ cpu->env.csr[II_REQ] = 0x100000; ++ cpu_interrupt(CPU(cpu),CPU_INTERRUPT_IIMAIL); ++ break; ++ default: ++ fprintf(stderr, "Unsupported IPU addr: 0x%04lx\n", addr); ++ break; ++ } ++#endif ++} ++ ++static const MemoryRegionOps intpu_ops = { ++ .read = intpu_read, ++ .write = intpu_write, ++ .endianness = DEVICE_LITTLE_ENDIAN, ++ .valid = ++ { ++ .min_access_size = 8, ++ .max_access_size = 8, ++ }, ++ .impl = ++ { ++ .min_access_size = 8, ++ .max_access_size = 8, ++ }, ++}; ++ ++static MemTxResult msi_read(void *opaque, hwaddr addr, ++ uint64_t *data, unsigned size, ++ MemTxAttrs attrs) ++{ ++ return MEMTX_OK; ++} ++ ++MemTxResult msi_write(void *opaque, hwaddr addr, ++ uint64_t value, unsigned size, ++ MemTxAttrs attrs) ++{ ++#ifdef CONFIG_KVM ++ int ret = 0; ++ MSIMessage msg = {}; ++ ++ msg.address = (uint64_t) addr + 0x8000fee00000; ++ msg.data = (uint32_t) value; ++ ++ ret = kvm_irqchip_send_msi(kvm_state, msg); ++ if (ret < 0) { ++ fprintf(stderr, "KVM: injection failed, MSI lost (%s)\n", ++ strerror(-ret)); ++ } ++#endif ++ return MEMTX_OK; ++} ++ ++static const MemoryRegionOps msi_ops = { ++ .read_with_attrs = msi_read, ++ .write_with_attrs = msi_write, ++ .endianness = DEVICE_LITTLE_ENDIAN, ++ .valid = ++ { ++ .min_access_size = 1, ++ .max_access_size = 8, ++ }, ++ .impl = ++ { ++ .min_access_size = 1, ++ .max_access_size = 8, ++ }, ++}; ++ ++static uint64_t ignore_read(void *opaque, hwaddr addr, unsigned size) ++{ ++ return 1; ++} ++ ++static void ignore_write(void *opaque, hwaddr addr, uint64_t v, unsigned size) ++{ ++} ++ ++const MemoryRegionOps core3_pci_ignore_ops = { ++ .read = ignore_read, ++ .write = ignore_write, ++ .endianness = DEVICE_LITTLE_ENDIAN, ++ .valid = ++ { ++ .min_access_size = 1, ++ .max_access_size = 8, ++ }, ++ .impl = ++ { ++ .min_access_size = 1, ++ .max_access_size = 8, ++ }, ++}; ++ ++static uint64_t config_read(void *opaque, hwaddr addr, unsigned size) ++{ ++ PCIBus *b = opaque; ++ uint32_t trans_addr = 0; ++ trans_addr |= ((addr >> 16) & 0xffff) << 8; ++ trans_addr |= (addr & 0xff); ++ return pci_data_read(b, trans_addr, size); ++} ++ ++static void config_write(void *opaque, hwaddr addr, uint64_t val, ++ unsigned size) ++{ ++ PCIBus *b = opaque; ++ uint32_t trans_addr = 0; ++ trans_addr |= ((addr >> 16) & 0xffff) << 8; ++ trans_addr |= (addr & 0xff); ++ pci_data_write(b, trans_addr, val, size); ++} ++ ++const MemoryRegionOps core3_pci_config_ops = { ++ .read = config_read, ++ .write = config_write, ++ .endianness = DEVICE_LITTLE_ENDIAN, ++ .valid = ++ { ++ .min_access_size = 1, ++ .max_access_size = 8, ++ }, ++ .impl = ++ { ++ .min_access_size = 1, ++ .max_access_size = 8, ++ }, ++}; ++ ++static void cpu_irq_change(SW64CPU *cpu, uint64_t req) ++{ ++ if (cpu != NULL) { ++ CPUState *cs = CPU(cpu); ++ if (req) ++ cpu_interrupt(cs, CPU_INTERRUPT_HARD); ++ else ++ cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); ++ } ++} ++ ++static void swboard_set_irq(void *opaque, int irq, int level) ++{ ++ BoardState *bs = opaque; ++ SW64CPU *cpu; ++ int i; ++ ++ if (kvm_enabled()) { ++ if (level == 0) ++ return; ++ kvm_set_irq(kvm_state, irq, level); ++ return; ++ } ++ ++ for (i = 0; i < 1; i++) { ++ cpu = bs->sboard.cpu[i]; ++ if (cpu != NULL) { ++ CPUState *cs = CPU(cpu); ++ if (level) ++ cpu_interrupt(cs, CPU_INTERRUPT_PCIE); ++ else ++ cpu_reset_interrupt(cs, CPU_INTERRUPT_PCIE); ++ } ++ } ++} ++ ++static int swboard_map_irq(PCIDevice *d, int irq_num) ++{ ++ /* In fact,the return value is the interrupt type passed to kernel, ++ * so it must keep same with the type in do_entInt in kernel. ++ */ ++ return 16; ++} ++ ++static void serial_set_irq(void *opaque, int irq, int level) ++{ ++ BoardState *bs = (BoardState *)opaque; ++ MachineState *ms = MACHINE(qdev_get_machine()); ++ unsigned int smp_cpus = ms->smp.cpus; ++ int i; ++ if (level == 0) ++ return; ++ if (kvm_enabled()) { ++ kvm_set_irq(kvm_state, irq, level); ++ return; ++ } ++ for (i = 0; i < smp_cpus; i++) { ++ if (bs->sboard.cpu[i]) ++ cpu_irq_change(bs->sboard.cpu[i], 1); ++ } ++} ++ ++void core3_board_init(SW64CPU *cpus[MAX_CPUS], MemoryRegion *ram) ++{ ++ DeviceState *dev; ++ BoardState *bs; ++#ifndef CONFIG_KVM ++ TimerState *ts; ++#endif ++ MemoryRegion *io_mcu = g_new(MemoryRegion, 1); ++ MemoryRegion *io_intpu = g_new(MemoryRegion, 1); ++ MemoryRegion *msi_ep = g_new(MemoryRegion, 1); ++ qemu_irq serial_irq; ++ uint64_t MB = 1024 * 1024; ++ MemoryRegion *mem_ep = g_new(MemoryRegion, 1); ++ MemoryRegion *mem_ep64 = g_new(MemoryRegion, 1); ++ MemoryRegion *conf_piu0 = g_new(MemoryRegion, 1); ++ MemoryRegion *io_ep = g_new(MemoryRegion, 1); ++ ++ MachineState *ms = MACHINE(qdev_get_machine()); ++ unsigned int smp_cpus = ms->smp.cpus; ++ ++ PCIBus *b; ++ PCIHostState *phb; ++ uint64_t GB = 1024 * MB; ++ ++ int i; ++ dev = qdev_new(TYPE_SWBOARD_PCI_HOST_BRIDGE); ++ phb = PCI_HOST_BRIDGE(dev); ++ bs = SWBOARD_PCI_HOST_BRIDGE(dev); ++ ++#ifdef CONFIG_KVM ++ if (kvm_has_gsi_routing()) ++ msi_nonbroken = true; ++#endif ++ ++ for (i = 0; i < smp_cpus; ++i) { ++ if (cpus[i] == NULL) ++ continue; ++ bs->sboard.cpu[i] = cpus[i]; ++#ifndef CONFIG_KVM ++ ts = g_new(TimerState, 1); ++ ts->opaque = (void *) ((uintptr_t)bs); ++ ts->order = i; ++ cpus[i]->alarm_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &swboard_alarm_timer, ts); ++#endif ++ } ++ memory_region_add_subregion(get_system_memory(), 0, ram); ++ ++ memory_region_init_io(io_mcu, NULL, &mcu_ops, bs, "io_mcu", 16 * MB); ++ memory_region_add_subregion(get_system_memory(), 0x803000000000ULL, io_mcu); ++ ++ memory_region_init_io(io_intpu, NULL, &intpu_ops, bs, "io_intpu", 1 * MB); ++ memory_region_add_subregion(get_system_memory(), 0x802a00000000ULL, ++ io_intpu); ++ ++ memory_region_init_io(msi_ep, NULL, &msi_ops, bs, "msi_ep", 1 * MB); ++ memory_region_add_subregion(get_system_memory(), 0x8000fee00000ULL, msi_ep); ++ ++ memory_region_init(mem_ep, OBJECT(bs), "pci0-mem", 0x890000000000ULL); ++ memory_region_add_subregion(get_system_memory(), 0x880000000000ULL, mem_ep); ++ ++ memory_region_init_alias(mem_ep64, NULL, "mem_ep64", mem_ep, 0x888000000000ULL, 1ULL << 39); ++ memory_region_add_subregion(get_system_memory(), 0x888000000000ULL, mem_ep64); ++ ++ memory_region_init_io(io_ep, OBJECT(bs), &core3_pci_ignore_ops, NULL, ++ "pci0-io-ep", 4 * GB); ++ ++ memory_region_add_subregion(get_system_memory(), 0x880100000000ULL, io_ep); ++ b = pci_register_root_bus(dev, "pcie.0", swboard_set_irq, swboard_map_irq, bs, ++ mem_ep, io_ep, 0, 537, TYPE_PCIE_BUS); ++ phb->bus = b; ++ sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); ++ pci_bus_set_route_irq_fn(b, sw_route_intx_pin_to_irq); ++ memory_region_init_io(conf_piu0, OBJECT(bs), &core3_pci_config_ops, b, ++ "pci0-ep-conf-io", 4 * GB); ++ memory_region_add_subregion(get_system_memory(), 0x880600000000ULL, ++ conf_piu0); ++#ifdef SW64_VT_IOMMU ++ sw64_vt_iommu_init(b); ++#endif ++ for (i = 0; i < nb_nics; i++) { ++ pci_nic_init_nofail(&nd_table[i], b, "e1000", NULL); ++ } ++ ++ pci_vga_init(b); ++#define MAX_SATA_PORTS 6 ++ PCIDevice *ahci; ++ DriveInfo *hd[MAX_SATA_PORTS]; ++ ahci = pci_create_simple_multifunction(b, PCI_DEVFN(0x1f, 0), true, ++ TYPE_ICH9_AHCI); ++ g_assert(MAX_SATA_PORTS == ahci_get_num_ports(ahci)); ++ ide_drive_get(hd, ahci_get_num_ports(ahci)); ++ ahci_ide_create_devs(ahci, hd); ++ ++ serial_irq = qemu_allocate_irq(serial_set_irq, bs, 12); ++ if (serial_hd(0)) { ++ serial_mm_init(get_system_memory(), 0x3F8 + 0x880100000000ULL, 0, ++ serial_irq, (1843200 >> 4), serial_hd(0), ++ DEVICE_LITTLE_ENDIAN); ++ } ++ pci_create_simple(phb->bus, -1, "nec-usb-xhci"); ++ sun4v_rtc_init(0x804910000000ULL); ++} ++ ++static const TypeInfo swboard_pcihost_info = { ++ .name = TYPE_SWBOARD_PCI_HOST_BRIDGE, ++ .parent = TYPE_PCI_HOST_BRIDGE, ++ .instance_size = sizeof(BoardState), ++}; ++ ++static void swboard_register_types(void) ++{ ++ type_register_static(&swboard_pcihost_info); ++} ++ ++type_init(swboard_register_types) +diff --git a/hw/sw64/meson.build b/hw/sw64/meson.build +new file mode 100644 +index 0000000000..8abb18222a +--- /dev/null ++++ b/hw/sw64/meson.build +@@ -0,0 +1,10 @@ ++sw64_ss = ss.source_set() ++ ++sw64_ss.add(files('sw64_iommu.c')) ++ ++sw64_ss.add(when: 'CONFIG_CORE3', if_true: files( ++ 'core3.c', ++ 'core3_board.c', ++)) ++ ++hw_arch += {'sw64': sw64_ss} +diff --git a/hw/sw64/sw64_iommu.c b/hw/sw64/sw64_iommu.c +new file mode 100644 +index 0000000000..8ded65f213 +--- /dev/null ++++ b/hw/sw64/sw64_iommu.c +@@ -0,0 +1,567 @@ ++/* ++ * QEMU sw64 IOMMU emulation ++ * ++ * Copyright (c) 2021 Lu Feifei ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to deal ++ * in the Software without restriction, including without limitation the rights ++ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++ * copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN ++ * THE SOFTWARE. ++ */ ++ ++#include "qemu/osdep.h" ++#include "hw/sysbus.h" ++#include "exec/address-spaces.h" ++#include "qemu/log.h" ++#include "qapi/error.h" ++#include "hw/sw64/sw64_iommu.h" ++#include "sysemu/kvm.h" ++ ++#define IOMMU_PAGE_SHIFT 13 ++#define IOMMU_PAGE_SIZE_8K (1ULL << IOMMU_PAGE_SHIFT) ++#define IOMMU_PAGE_MASK_8K (~(IOMMU_PAGE_SIZE_8K - 1)) ++#define IOMMU_IOVA_SHIFT 16 ++#define SW64IOMMU_PTIOTLB_MAX_SIZE 256 ++ ++static MemTxResult swvt_msi_read(void *opaque, hwaddr addr, ++ uint64_t *data, unsigned size, MemTxAttrs attrs) ++{ ++ return MEMTX_OK; ++} ++ ++static MemTxResult swvt_msi_write(void *opaque, hwaddr addr, ++ uint64_t value, unsigned size, ++ MemTxAttrs attrs) ++{ ++ MemTxResult ret; ++ ++ ret = msi_write(opaque, addr, value, size, attrs); ++ ++ return ret; ++} ++ ++static const MemoryRegionOps swvt_msi_ops = { ++ .read_with_attrs = swvt_msi_read, ++ .write_with_attrs = swvt_msi_write, ++ .endianness = DEVICE_LITTLE_ENDIAN, ++ .valid = { ++ .min_access_size = 1, ++ .max_access_size = 8, ++ }, ++ .impl = { ++ .min_access_size = 1, ++ .max_access_size = 8, ++ }, ++}; ++ ++SWVTAddressSpace *iommu_find_add_as(SW64IOMMUState *s, PCIBus *bus, int devfn) ++{ ++ uintptr_t key = (uintptr_t)bus; ++ SWVTBus *swvt_bus = g_hash_table_lookup(s->swvtbus_as_by_busptr, &key); ++ SWVTAddressSpace *swvt_dev_as; ++ char name[128]; ++ ++ if (!swvt_bus) { ++ uintptr_t *new_key = g_malloc(sizeof(*new_key)); ++ *new_key = (uintptr_t)bus; ++ /* No corresponding free() */ ++ swvt_bus = g_malloc0(sizeof(SWVTBus) + sizeof(SWVTAddressSpace *) * \ ++ PCI_DEVFN_MAX); ++ swvt_bus->bus = bus; ++ g_hash_table_insert(s->swvtbus_as_by_busptr, new_key, swvt_bus); ++ } ++ swvt_dev_as = swvt_bus->dev_as[devfn]; ++ if (!swvt_dev_as) { ++ snprintf(name, sizeof(name), "sw64_iommu_devfn_%d", devfn); ++ swvt_bus->dev_as[devfn] = swvt_dev_as = g_malloc0(sizeof(SWVTAddressSpace)); ++ ++ swvt_dev_as->bus = bus; ++ swvt_dev_as->devfn = (uint8_t)devfn; ++ swvt_dev_as->iommu_state = s; ++ ++ memory_region_init_iommu(&swvt_dev_as->iommu, sizeof(swvt_dev_as->iommu), ++ TYPE_SW64_IOMMU_MEMORY_REGION, OBJECT(s), ++ "sw64_iommu_dmar", ++ 1UL << 32); ++ memory_region_init_io(&swvt_dev_as->msi, OBJECT(s), ++ &swvt_msi_ops, s, "sw_msi", 1 * 1024 * 1024); ++ memory_region_init(&swvt_dev_as->root, OBJECT(s), ++ "swvt_root", UINT64_MAX); ++ memory_region_add_subregion_overlap(&swvt_dev_as->root, ++ 0x8000fee00000ULL, ++ &swvt_dev_as->msi, 64); ++ address_space_init(&swvt_dev_as->as, &swvt_dev_as->root, name); ++ memory_region_add_subregion_overlap(&swvt_dev_as->root, 0, ++ MEMORY_REGION(&swvt_dev_as->iommu), ++ 1); ++ } ++ ++ memory_region_set_enabled(MEMORY_REGION(&swvt_dev_as->iommu), true); ++ ++ return swvt_dev_as; ++} ++ ++/** ++ * get_pte - Get the content of a page table entry located at ++ * @base_addr[@index] ++ */ ++static int get_pte(dma_addr_t baseaddr, uint64_t *pte) ++{ ++ int ret; ++ ++ /* TODO: guarantee 64-bit single-copy atomicity */ ++ ret = dma_memory_read(&address_space_memory, baseaddr, ++ (uint8_t *)pte, sizeof(*pte)); ++ ++ if (ret != MEMTX_OK) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++static bool swvt_do_iommu_translate(SWVTAddressSpace *swvt_as, PCIBus *bus, ++ uint8_t devfn, hwaddr addr, IOMMUTLBEntry *entry) ++{ ++ SW64IOMMUState *s = swvt_as->iommu_state; ++ uint8_t bus_num = pci_bus_num(bus); ++ unsigned long dtbbaseaddr, dtbbasecond; ++ unsigned long pdebaseaddr, ptebaseaddr; ++ unsigned long pte; ++ uint16_t source_id; ++ SW64DTIOTLBEntry *dtcached_entry = NULL; ++ SW64DTIOTLBKey dtkey, *new_key; ++ ++ dtcached_entry = g_hash_table_lookup(s->dtiotlb, &dtkey); ++ ++ if (unlikely(!dtcached_entry)) { ++ dtbbaseaddr = s->dtbr + (bus_num << 3); ++ ++ if (get_pte(dtbbaseaddr, &pte)) ++ goto error; ++ ++ dtbbasecond = (pte & (~(SW_IOMMU_ENTRY_VALID))) + (devfn << 3); ++ if (get_pte(dtbbasecond, &pte)) ++ goto error; ++ ++ source_id = ((bus_num & 0xffUL) << 8) | (devfn & 0xffUL); ++ dtcached_entry = g_new0(SW64DTIOTLBEntry, 1); ++ dtcached_entry->ptbase_addr = pte & (~(SW_IOMMU_ENTRY_VALID)); ++ dtcached_entry->source_id = source_id; ++ ++ new_key = g_new0(SW64DTIOTLBKey, 1); ++ new_key->source_id = source_id; ++ ++ g_hash_table_insert(s->dtiotlb, new_key, dtcached_entry); ++ } ++ ++ pdebaseaddr = dtcached_entry->ptbase_addr; ++ pdebaseaddr += ((addr >> 23) & SW_IOMMU_LEVEL1_OFFSET) << 3; ++ ++ if (get_pte(pdebaseaddr, &pte)) ++ goto error; ++ ++ ptebaseaddr = pte & (~(SW_IOMMU_ENTRY_VALID)); ++ ptebaseaddr += ((addr >> IOMMU_PAGE_SHIFT) & SW_IOMMU_LEVEL2_OFFSET) << 3; ++ ++ if (get_pte(ptebaseaddr, &pte)) ++ goto error; ++ ++ pte &= ~(SW_IOMMU_ENTRY_VALID | SW_IOMMU_GRN | SW_IOMMU_ENABLE); ++ entry->translated_addr = pte; ++ entry->addr_mask = IOMMU_PAGE_SIZE_8K - 1; ++ ++ return 0; ++ ++error: ++ entry->perm = IOMMU_NONE; ++ return -EINVAL; ++} ++ ++static void swvt_ptiotlb_inv_all(SW64IOMMUState *s) ++{ ++ g_hash_table_remove_all(s->ptiotlb); ++} ++ ++static void swvt_lookup_ptiotlb(SW64IOMMUState *s, uint16_t source_id, ++ hwaddr addr, IOMMUTLBEntry *entry) ++{ ++ SW64PTIOTLBKey ptkey; ++ ++ ptkey.source_id = source_id; ++ ptkey.iova = addr; ++ ++ entry = g_hash_table_lookup(s->ptiotlb, &ptkey); ++} ++ ++static IOMMUTLBEntry sw64_translate_iommu(IOMMUMemoryRegion *iommu, hwaddr addr, ++ IOMMUAccessFlags flag, int iommu_idx) ++{ ++ SWVTAddressSpace *swvt_as = container_of(iommu, SWVTAddressSpace, iommu); ++ SW64IOMMUState *s = swvt_as->iommu_state; ++ IOMMUTLBEntry *cached_entry = NULL; ++ IOMMUTLBEntry entry = { ++ .target_as = &address_space_memory, ++ .iova = addr, ++ .translated_addr = addr, ++ .addr_mask = ~(hwaddr)0, ++ .perm = IOMMU_NONE, ++ }; ++ uint8_t bus_num = pci_bus_num(swvt_as->bus); ++ uint16_t source_id; ++ SW64PTIOTLBKey *new_ptkey; ++ hwaddr aligned_addr; ++ ++ source_id = ((bus_num & 0xffUL) << 8) | (swvt_as->devfn & 0xffUL); ++ ++ qemu_mutex_lock(&s->iommu_lock); ++ ++ aligned_addr = addr & IOMMU_PAGE_MASK_8K; ++ ++ swvt_lookup_ptiotlb(s, aligned_addr, source_id, cached_entry); ++ ++ if (cached_entry) ++ goto out; ++ ++ if (g_hash_table_size(s->ptiotlb) >= SW64IOMMU_PTIOTLB_MAX_SIZE) { ++ swvt_ptiotlb_inv_all(s); ++ } ++ ++ cached_entry = g_new0(IOMMUTLBEntry, 1); ++ ++ if (swvt_do_iommu_translate(swvt_as, swvt_as->bus, swvt_as->devfn, ++ addr, cached_entry)) { ++ g_free(cached_entry); ++ qemu_mutex_unlock(&s->iommu_lock); ++ printf("%s: detected translation failure " ++ "(busnum=%d, devfn=%#x, iova=%#lx.\n", ++ __func__, pci_bus_num(swvt_as->bus), swvt_as->devfn, ++ entry.iova); ++ entry.iova = 0; ++ entry.translated_addr = 0; ++ entry.addr_mask = 0; ++ entry.perm = IOMMU_NONE; ++ ++ return entry; ++ } else { ++ new_ptkey = g_new0(SW64PTIOTLBKey, 1); ++ new_ptkey->source_id = source_id; ++ new_ptkey->iova = aligned_addr; ++ g_hash_table_insert(s->ptiotlb, new_ptkey, cached_entry); ++ } ++ ++out: ++ qemu_mutex_unlock(&s->iommu_lock); ++ entry.perm = flag; ++ entry.translated_addr = cached_entry->translated_addr + ++ (addr & (IOMMU_PAGE_SIZE_8K - 1)); ++ entry.addr_mask = cached_entry->addr_mask; ++ ++ return entry; ++} ++ ++static void swvt_ptiotlb_inv_iova(SW64IOMMUState *s, uint16_t source_id, dma_addr_t iova) ++{ ++ SW64PTIOTLBKey key = {.source_id = source_id, .iova = iova}; ++ ++ qemu_mutex_lock(&s->iommu_lock); ++ g_hash_table_remove(s->ptiotlb, &key); ++ qemu_mutex_unlock(&s->iommu_lock); ++} ++ ++void swvt_address_space_unmap_iova(SW64IOMMUState *s, unsigned long val) ++{ ++ SWVTAddressSpace *swvt_as; ++ IOMMUNotifier *n; ++ uint16_t source_id; ++ dma_addr_t iova; ++ IOMMUTLBEvent event; ++ ++ source_id = val & 0xffff; ++ iova = (val >> IOMMU_IOVA_SHIFT) << IOMMU_PAGE_SHIFT; ++ ++ swvt_ptiotlb_inv_iova(s, source_id, iova); ++ ++ QLIST_FOREACH(swvt_as, &s->swvt_as_with_notifiers, next) { ++ uint8_t bus_num = pci_bus_num(swvt_as->bus); ++ uint16_t as_sourceid = ((bus_num & 0xffUL) << 8) | (swvt_as->devfn & 0xffUL); ++ ++ if (as_sourceid == source_id) { ++ IOMMU_NOTIFIER_FOREACH(n, &swvt_as->iommu) { ++ event.type = IOMMU_NOTIFIER_UNMAP; ++ event.entry.target_as = &address_space_memory; ++ event.entry.iova = iova & IOMMU_PAGE_MASK_8K; ++ event.entry.translated_addr = 0; ++ event.entry.perm = IOMMU_NONE; ++ event.entry.addr_mask = IOMMU_PAGE_SIZE_8K - 1; ++ ++ memory_region_notify_iommu(&swvt_as->iommu, 0, event); ++ } ++ } ++ } ++} ++ ++/* Unmap the whole range in the notifier's scope. */ ++static void swvt_address_space_unmap(SWVTAddressSpace *as, IOMMUNotifier *n) ++{ ++ IOMMUTLBEvent event; ++ hwaddr size; ++ hwaddr start = n->start; ++ hwaddr end = n->end; ++ ++ assert(start <= end); ++ size = end - start; ++ ++ event.entry.target_as = &address_space_memory; ++ /* Adjust iova for the size */ ++ event.entry.iova = n->start & ~(size - 1); ++ /* This field is meaningless for unmap */ ++ event.entry.translated_addr = 0; ++ event.entry.perm = IOMMU_NONE; ++ event.entry.addr_mask = size - 1; ++ ++ memory_region_notify_iommu_one(n, &event); ++} ++ ++void swvt_address_space_map_iova(SW64IOMMUState *s, unsigned long val) ++{ ++ SWVTAddressSpace *swvt_as; ++ IOMMUNotifier *n; ++ uint16_t source_id; ++ dma_addr_t iova; ++ IOMMUTLBEvent event; ++ int ret; ++ ++ source_id = val & 0xffff; ++ iova = (val >> IOMMU_IOVA_SHIFT) << IOMMU_PAGE_SHIFT; ++ ++ swvt_ptiotlb_inv_iova(s, source_id, iova); ++ ++ QLIST_FOREACH(swvt_as, &s->swvt_as_with_notifiers, next) { ++ uint8_t bus_num = pci_bus_num(swvt_as->bus); ++ uint16_t as_sourceid = ((bus_num & 0xffUL) << 8) | (swvt_as->devfn & 0xffUL); ++ ++ if (as_sourceid == source_id) { ++ IOMMU_NOTIFIER_FOREACH(n, &swvt_as->iommu) { ++ event.type = IOMMU_NOTIFIER_UNMAP; ++ event.entry.target_as = &address_space_memory; ++ event.entry.iova = iova & IOMMU_PAGE_MASK_8K; ++ event.entry.perm = IOMMU_RW; ++ ++ ret = swvt_do_iommu_translate(swvt_as, swvt_as->bus, ++ swvt_as->devfn, iova, &event.entry); ++ if (ret) ++ goto out; ++ ++ memory_region_notify_iommu(&swvt_as->iommu, 0, event); ++ } ++ } ++ } ++out: ++ return; ++} ++ ++void swvt_address_space_invalidate_iova(SW64IOMMUState *s, unsigned long val) ++{ ++ int map_flag; ++ ++ map_flag = val >> 36; ++ ++ if (map_flag) ++ swvt_address_space_map_iova(s, val & 0xfffffffff); ++ else ++ swvt_address_space_unmap_iova(s, val); ++ ++ return; ++} ++ ++static AddressSpace *sw64_dma_iommu(PCIBus *bus, void *opaque, int devfn) ++{ ++ SW64IOMMUState *s = opaque; ++ SWVTAddressSpace *swvt_as; ++ ++ assert(0 <= devfn && devfn < PCI_DEVFN_MAX); ++ ++ swvt_as = iommu_find_add_as(s, bus, devfn); ++ return &swvt_as->as; ++} ++ ++static uint64_t piu0_read(void *opaque, hwaddr addr, unsigned size) ++{ ++ uint64_t ret = 0; ++ switch (addr) { ++ default: ++ break; ++ } ++ return ret; ++} ++ ++static void piu0_write(void *opaque, hwaddr addr, uint64_t val, ++ unsigned size) ++{ ++ SW64IOMMUState *s = (SW64IOMMUState *)opaque; ++ ++ switch (addr) { ++ case 0xb000: ++ /* DTBaseAddr */ ++ s->dtbr = val; ++ break; ++ case 0xb280: ++ /* PTLB_FlushVAddr */ ++ swvt_address_space_invalidate_iova(s, val); ++ break; ++ default: ++ break; ++ } ++} ++ ++const MemoryRegionOps core3_pci_piu0_ops = { ++ .read = piu0_read, ++ .write = piu0_write, ++ .endianness = DEVICE_LITTLE_ENDIAN, ++ .valid = { ++ .min_access_size = 1, ++ .max_access_size = 8, ++ }, ++ .impl = { ++ .min_access_size = 1, ++ .max_access_size = 8, ++ }, ++}; ++ ++void sw64_vt_iommu_init(PCIBus *b) ++{ ++ DeviceState *dev_iommu; ++ SW64IOMMUState *s; ++ MemoryRegion *io_piu0 = g_new(MemoryRegion, 1); ++ ++ dev_iommu = qdev_new(TYPE_SW64_IOMMU); ++ s = SW64_IOMMU(dev_iommu); ++ ++ s->pci_bus = b; ++ sysbus_realize_and_unref(SYS_BUS_DEVICE(dev_iommu), &error_fatal); ++ ++ pci_setup_iommu(b, sw64_dma_iommu, dev_iommu); ++ ++ memory_region_init_io(io_piu0, OBJECT(s), &core3_pci_piu0_ops, s, ++ "pci0-piu0-io", 4 * 1024 * 1024); ++ memory_region_add_subregion(get_system_memory(), 0x880200000000ULL, ++ io_piu0); ++} ++ ++static int swvt_iommu_notify_flag_changed(IOMMUMemoryRegion *iommu, ++ IOMMUNotifierFlag old, ++ IOMMUNotifierFlag new, ++ Error **errp) ++{ ++ SWVTAddressSpace *swvt_as = container_of(iommu, SWVTAddressSpace, iommu); ++ SW64IOMMUState *s = swvt_as->iommu_state; ++ ++ /* Update per-address-space notifier flags */ ++ swvt_as->notifier_flags = new; ++ ++ if (new & IOMMU_NOTIFIER_DEVIOTLB_UNMAP) { ++ error_setg(errp, "swvt does not support dev-iotlb yet"); ++ return -EINVAL; ++ } ++ ++ if (old == IOMMU_NOTIFIER_NONE) { ++ QLIST_INSERT_HEAD(&s->swvt_as_with_notifiers, swvt_as, next); ++ } else if (new == IOMMU_NOTIFIER_NONE) { ++ QLIST_REMOVE(swvt_as, next); ++ } ++ return 0; ++} ++ ++static void swvt_iommu_replay(IOMMUMemoryRegion *iommu_mr, IOMMUNotifier *n) ++{ ++ SWVTAddressSpace *swvt_as = container_of(iommu_mr, SWVTAddressSpace, iommu); ++ ++ /* ++ * The replay can be triggered by either a invalidation or a newly ++ * created entry. No matter what, we release existing mappings ++ * (it means flushing caches for UNMAP-only registers). ++ */ ++ swvt_address_space_unmap(swvt_as, n); ++} ++ ++/* GHashTable functions */ ++static gboolean swvt_uint64_equal(gconstpointer v1, gconstpointer v2) ++{ ++ return *((const uint64_t *)v1) == *((const uint64_t *)v2); ++} ++ ++static guint swvt_uint64_hash(gconstpointer v) ++{ ++ return (guint)*(const uint64_t *)v; ++} ++ ++static void iommu_realize(DeviceState *d, Error **errp) ++{ ++ SW64IOMMUState *s = SW64_IOMMU(d); ++ ++ QLIST_INIT(&s->swvt_as_with_notifiers); ++ qemu_mutex_init(&s->iommu_lock); ++ ++ s->dtiotlb = g_hash_table_new_full(swvt_uint64_hash, swvt_uint64_equal, ++ g_free, g_free); ++ s->ptiotlb = g_hash_table_new_full(swvt_uint64_hash, swvt_uint64_equal, ++ g_free, g_free); ++ ++ s->swvtbus_as_by_busptr = g_hash_table_new(NULL, NULL); ++} ++ ++static void iommu_reset(DeviceState *d) ++{ ++} ++ ++static void sw64_iommu_class_init(ObjectClass *klass, void *data) ++{ ++ DeviceClass *dc = DEVICE_CLASS(klass); ++ ++ dc->reset = iommu_reset; ++ dc->realize = iommu_realize; ++} ++ ++static void sw64_iommu_memory_region_class_init(ObjectClass *klass, void *data) ++{ ++ IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass); ++ ++ imrc->translate = sw64_translate_iommu; ++ imrc->notify_flag_changed = swvt_iommu_notify_flag_changed; ++ imrc->replay = swvt_iommu_replay; ++} ++ ++static const TypeInfo sw64_iommu_info = { ++ .name = TYPE_SW64_IOMMU, ++ .parent = TYPE_SYS_BUS_DEVICE, ++ .instance_size = sizeof(SW64IOMMUState), ++ .class_init = sw64_iommu_class_init, ++ .class_size = sizeof(SW64IOMMUClass), ++}; ++ ++static const TypeInfo sw64_iommu_memory_region_info = { ++ .parent = TYPE_IOMMU_MEMORY_REGION, ++ .name = TYPE_SW64_IOMMU_MEMORY_REGION, ++ .class_init = sw64_iommu_memory_region_class_init, ++}; ++ ++static void sw64_iommu_register_types(void) ++{ ++ type_register_static(&sw64_iommu_info); ++ type_register_static(&sw64_iommu_memory_region_info); ++} ++ ++type_init(sw64_iommu_register_types) +diff --git a/hw/sw64/trace-events b/hw/sw64/trace-events +new file mode 100644 +index 0000000000..1aa744c984 +--- /dev/null ++++ b/hw/sw64/trace-events +@@ -0,0 +1,3 @@ ++# See docs/devel/tracing.rst for syntax documentation. ++ ++# pci.c +diff --git a/include/disas/dis-asm.h b/include/disas/dis-asm.h +index 08e1beec85..4590bcc968 100644 +--- a/include/disas/dis-asm.h ++++ b/include/disas/dis-asm.h +@@ -191,6 +191,9 @@ enum bfd_architecture + #define bfd_mach_alpha_ev4 0x10 + #define bfd_mach_alpha_ev5 0x20 + #define bfd_mach_alpha_ev6 0x30 ++ bfd_arch_sw_64, /* Dec Sw_64 */ ++#define bfd_mach_sw_64 1 ++#define bfd_mach_sw_64_core3 1621 + bfd_arch_arm, /* Advanced Risc Machines ARM */ + #define bfd_mach_arm_unknown 0 + #define bfd_mach_arm_2 1 +@@ -429,6 +432,7 @@ int print_insn_h8500 (bfd_vma, disassemble_info*); + int print_insn_arm_a64 (bfd_vma, disassemble_info*); + int print_insn_alpha (bfd_vma, disassemble_info*); + disassembler_ftype arc_get_disassembler (int, int); ++int print_insn_sw_64 (bfd_vma, disassemble_info*); + int print_insn_arm (bfd_vma, disassemble_info*); + int print_insn_sparc (bfd_vma, disassemble_info*); + int print_insn_big_a29k (bfd_vma, disassemble_info*); +diff --git a/include/elf.h b/include/elf.h +index 811bf4a1cb..79c188b62f 100644 +--- a/include/elf.h ++++ b/include/elf.h +@@ -207,6 +207,8 @@ typedef struct mips_elf_abiflags_v0 { + + #define EF_AVR_MACH 0x7F /* Mask for AVR e_flags to get core type */ + ++#define EM_SW64 0x9916 /* SW64 */ ++ + /* This is the info that is needed to parse the dynamic section of the file */ + #define DT_NULL 0 + #define DT_NEEDED 1 +@@ -1417,6 +1419,48 @@ typedef struct { + #define EF_RISCV_RVE 0x0008 + #define EF_RISCV_TSO 0x0010 + ++/* ++ SW_64 ELF relocation types ++ */ ++#define EM_SW_64 0x9916 ++#define R_SW_64_NONE 0 /* No reloc */ ++#define R_SW_64_REFLONG 1 /* Direct 32 bit */ ++#define R_SW_64_REFQUAD 2 /* Direct 64 bit */ ++#define R_SW_64_GPREL32 3 /* GP relative 32 bit */ ++#define R_SW_64_LITERAL 4 /* GP relative 16 bit w/optimization */ ++#define R_SW_64_LITUSE 5 /* Optimization hint for LITERAL */ ++#define R_SW_64_GPDISP 6 /* Add displacement to GP */ ++#define R_SW_64_BRADDR 7 /* PC+4 relative 23 bit shifted */ ++#define R_SW_64_HINT 8 /* PC+4 relative 16 bit shifted */ ++#define R_SW_64_SREL16 9 /* PC relative 16 bit */ ++#define R_SW_64_SREL32 10 /* PC relative 32 bit */ ++#define R_SW_64_SREL64 11 /* PC relative 64 bit */ ++#define R_SW_64_GPRELHIGH 17 /* GP relative 32 bit, high 16 bits */ ++#define R_SW_64_GPRELLOW 18 /* GP relative 32 bit, low 16 bits */ ++#define R_SW_64_GPREL16 19 /* GP relative 16 bit */ ++#define R_SW_64_COPY 24 /* Copy symbol at runtime */ ++#define R_SW_64_GLOB_DAT 25 /* Create GOT entry */ ++#define R_SW_64_JMP_SLOT 26 /* Create PLT entry */ ++#define R_SW_64_RELATIVE 27 /* Adjust by program base */ ++#define R_SW_64_TLS_GD_HI 28 ++#define R_SW_64_TLSGD 29 ++#define R_SW_64_TLS_LDM 30 ++#define R_SW_64_DTPMOD64 31 ++#define R_SW_64_GOTDTPREL 32 ++#define R_SW_64_DTPREL64 33 ++#define R_SW_64_DTPRELHI 34 ++#define R_SW_64_DTPRELLO 35 ++#define R_SW_64_DTPREL16 36 ++#define R_SW_64_GOTTPREL 37 ++#define R_SW_64_TPREL64 38 ++#define R_SW_64_TPRELHI 39 ++#define R_SW_64_TPRELLO 40 ++#define R_SW_64_TPREL16 41 ++/* Keep this the last entry. */ ++#define R_SW_64_NUM 46 ++/* Legal values for sh_flags field of Elf64_Shdr. */ ++#define SHF_SW_64_GPREL 0x10000000 ++ + typedef struct elf32_rel { + Elf32_Addr r_offset; + Elf32_Word r_info; +diff --git a/include/hw/sw64/sw64_iommu.h b/include/hw/sw64/sw64_iommu.h +new file mode 100644 +index 0000000000..7191876083 +--- /dev/null ++++ b/include/hw/sw64/sw64_iommu.h +@@ -0,0 +1,105 @@ ++/* ++ * Copyright (C) 2021-2025 Wuxi Institute of Advanced Technology ++ * Written by Lu Feifei ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * This program 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 General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, see . ++ */ ++ ++#ifndef HW_SW64_IOMMU_H ++#define HW_SW64_IOMMU_H ++ ++#include "hw/sysbus.h" ++#include "hw/pci/pci.h" ++ ++#define TYPE_SW64_IOMMU_MEMORY_REGION "sw64-iommu-memory-region" ++#define SW_IOMMU_ENTRY_VALID ((1UL) << 63) ++#define SW_IOMMU_LEVEL1_OFFSET 0x1ff ++#define SW_IOMMU_LEVEL2_OFFSET 0x3ff ++#define SW_IOMMU_ENABLE 3 ++#define SW_IOMMU_GRN ((0UL) << 4) ++#define SWVT_PCI_BUS_MAX 256 ++ ++typedef struct SW64IOMMUClass SW64IOMMUClass; ++typedef struct SW64IOMMUState SW64IOMMUState; ++typedef struct SWVTAddressSpace SWVTAddressSpace; ++typedef struct SW64DTIOTLBKey SW64DTIOTLBKey; ++typedef struct SW64PTIOTLBKey SW64PTIOTLBKey; ++typedef struct SW64DTIOTLBEntry SW64DTIOTLBEntry; ++typedef struct SWVTBus SWVTBus; ++ ++struct SW64DTIOTLBEntry { ++ uint16_t source_id; ++ unsigned long ptbase_addr; ++}; ++ ++struct SW64DTIOTLBKey { ++ uint16_t source_id; ++}; ++ ++struct SW64PTIOTLBKey { ++ uint16_t source_id; ++ dma_addr_t iova; ++}; ++ ++struct SWVTAddressSpace { ++ PCIBus *bus; ++ uint8_t devfn; ++ AddressSpace as; ++ IOMMUMemoryRegion iommu; ++ MemoryRegion root; ++ MemoryRegion msi; /* Interrupt region: 0xfeeXXXXX */ ++ SW64IOMMUState *iommu_state; ++ QLIST_ENTRY(SWVTAddressSpace) next; ++ /* Superset of notifier flags that this address space has */ ++ IOMMUNotifierFlag notifier_flags; ++}; ++ ++struct SWVTBus { ++ PCIBus* bus; /* A reference to the bus to provide translation for */ ++ SWVTAddressSpace *dev_as[0]; /* A table of SWVTAddressSpace objects indexed by devfn */ ++}; ++ ++struct SW64IOMMUState { ++ SysBusDevice busdev; ++ dma_addr_t dtbr; /* Current root table pointer */ ++ GHashTable *dtiotlb; /* IOTLB for device table */ ++ GHashTable *ptiotlb; /* IOTLB for page table */ ++ ++ GHashTable *swvtbus_as_by_busptr; ++ /* list of registered notifiers */ ++ QLIST_HEAD(, SWVTAddressSpace) swvt_as_with_notifiers; ++ ++ PCIBus *pci_bus; ++ QemuMutex iommu_lock; ++}; ++ ++struct SW64IOMMUClass { ++ SysBusDeviceClass parent; ++ DeviceRealize realize; ++}; ++ ++#define TYPE_SW64_IOMMU "sw64-iommu" ++#define SW64_IOMMU(obj) \ ++ OBJECT_CHECK(SW64IOMMUState, (obj), TYPE_SW64_IOMMU) ++#define SW64_IOMMU_CLASS(klass) \ ++ OBJECT_CLASS_CHECK(SW64IOMMUClass, (klass), TYPE_SW64_IOMMU) ++#define SW64_IOMMU_GET_CLASS(obj) \ ++ OBJECT_GET_CLASS(SW64IOMMUClass, (obj), TYPE_SW64_IOMMU) ++extern void sw64_vt_iommu_init(PCIBus *b); ++extern void swvt_address_space_invalidate_iova(SW64IOMMUState *s, unsigned long val); ++extern void swvt_address_space_unmap_iova(SW64IOMMUState *s, unsigned long val); ++extern void swvt_address_space_map_iova(SW64IOMMUState *s, unsigned long val); ++extern SWVTAddressSpace *iommu_find_add_as(SW64IOMMUState *s, PCIBus *bus, int devfn); ++extern MemTxResult msi_write(void *opaque, hwaddr addr, uint64_t value, unsigned size, ++ MemTxAttrs attrs); ++#endif +diff --git a/include/qemu/atomic.h b/include/qemu/atomic.h +index 112a29910b..6141122308 100644 +--- a/include/qemu/atomic.h ++++ b/include/qemu/atomic.h +@@ -85,6 +85,8 @@ + #define smp_read_barrier_depends() ({ barrier(); __atomic_thread_fence(__ATOMIC_CONSUME); }) + #elif defined(__alpha__) + #define smp_read_barrier_depends() asm volatile("mb":::"memory") ++#elif defined(__sw_64__) ++#define smp_read_barrier_depends() asm volatile("memb":::"memory") + #else + #define smp_read_barrier_depends() barrier() + #endif +diff --git a/include/qemu/timer.h b/include/qemu/timer.h +index d263fad9a4..e6d442abee 100644 +--- a/include/qemu/timer.h ++++ b/include/qemu/timer.h +@@ -1007,6 +1007,16 @@ static inline int64_t cpu_get_host_ticks(void) + return cur - ofs; + } + ++#elif defined(__sw_64__) ++ ++static inline int64_t cpu_get_host_ticks(void) ++{ ++ uint64_t cc; ++ ++ asm volatile("rtc %0" : "=r"(cc)); ++ return cc; ++} ++ + #else + /* The host CPU doesn't have an easily accessible cycle counter. + Just return a monotonically increasing value. This will be +diff --git a/include/sysemu/arch_init.h b/include/sysemu/arch_init.h +index 70c579560a..1cf27baa7c 100644 +--- a/include/sysemu/arch_init.h ++++ b/include/sysemu/arch_init.h +@@ -24,6 +24,7 @@ enum { + QEMU_ARCH_RX = (1 << 20), + QEMU_ARCH_AVR = (1 << 21), + QEMU_ARCH_HEXAGON = (1 << 22), ++ QEMU_ARCH_SW64 = (1 << 23), + }; + + extern const uint32_t arch_type; +diff --git a/linux-headers/asm-sw64/kvm.h b/linux-headers/asm-sw64/kvm.h +new file mode 100644 +index 0000000000..b0ce2ca346 +--- /dev/null ++++ b/linux-headers/asm-sw64/kvm.h +@@ -0,0 +1,122 @@ ++#ifndef __LINUX_KVM_SW64_H ++#define __LINUX_KVM_SW64_H ++ ++#include ++/* ++ * for KVM_GET_REGS and KVM_SET_REGS ++ */ ++struct kvm_regs { ++ unsigned long r0; ++ unsigned long r1; ++ unsigned long r2; ++ unsigned long r3; ++ ++ unsigned long r4; ++ unsigned long r5; ++ unsigned long r6; ++ unsigned long r7; ++ ++ unsigned long r8; ++ unsigned long r9; ++ unsigned long r10; ++ unsigned long r11; ++ ++ unsigned long r12; ++ unsigned long r13; ++ unsigned long r14; ++ unsigned long r15; ++ ++ unsigned long r19; ++ unsigned long r20; ++ unsigned long r21; ++ unsigned long r22; ++ ++ unsigned long r23; ++ unsigned long r24; ++ unsigned long r25; ++ unsigned long r26; ++ ++ unsigned long r27; ++ unsigned long r28; ++ unsigned long __padding0; ++ unsigned long fpcr; ++ ++ unsigned long fp[124]; ++ /* These are saved by hmcode: */ ++ unsigned long ps; ++ unsigned long pc; ++ unsigned long gp; ++ unsigned long r16; ++ unsigned long r17; ++ unsigned long r18; ++}; ++ ++struct vcpucb { ++ unsigned long go_flag; ++ unsigned long pcbb; ++ unsigned long ksp; ++ unsigned long usp; ++ unsigned long kgp; ++ unsigned long ent_arith; ++ unsigned long ent_if; ++ unsigned long ent_int; ++ unsigned long ent_mm; ++ unsigned long ent_sys; ++ unsigned long ent_una; ++ unsigned long stack_pc; ++ unsigned long new_a0; ++ unsigned long new_a1; ++ unsigned long new_a2; ++ unsigned long whami; ++ unsigned long csr_save; ++ unsigned long wakeup_magic; ++ unsigned long host_vcpucb; ++ unsigned long upcr; ++ unsigned long vpcr; ++ unsigned long dtb_pcr; ++ unsigned long guest_ksp; ++ unsigned long guest_usp; ++ unsigned long vcpu_irq_disabled; ++ unsigned long vcpu_irq; ++ unsigned long ptbr; ++ unsigned long int_stat0; ++ unsigned long int_stat1; ++ unsigned long int_stat2; ++ unsigned long int_stat3; ++ unsigned long reset_entry; ++ unsigned long pvcpu; ++ unsigned long exit_reason; ++ unsigned long ipaddr; ++ unsigned long vcpu_irq_vector; ++}; ++ ++/* ++ * for KVM_GET_FPU and KVM_SET_FPU ++ */ ++struct kvm_fpu { ++}; ++ ++/* ++ * KVM SW_64 specific structures and definitions ++ */ ++struct kvm_debug_exit_arch { ++}; ++ ++/* for KVM_SET_GUEST_DEBUG */ ++struct kvm_guest_debug_arch { ++}; ++ ++/* definition of registers in kvm_run */ ++struct kvm_sync_regs { ++}; ++ ++/* dummy definition */ ++struct kvm_sregs { ++}; ++ ++#define KVM_SW64_VCPU_INIT _IO(KVMIO, 0xba) ++#define KVM_SW64_USE_SLAVE _IO(KVMIO, 0xbb) ++#define KVM_SW64_GET_VCB _IO(KVMIO, 0xbc) ++#define KVM_SW64_SET_VCB _IO(KVMIO, 0xbd) ++ ++#endif /* __LINUX_KVM_SW64_H */ +diff --git a/linux-headers/asm-sw64/unistd.h b/linux-headers/asm-sw64/unistd.h +new file mode 100644 +index 0000000000..affe297e73 +--- /dev/null ++++ b/linux-headers/asm-sw64/unistd.h +@@ -0,0 +1,380 @@ ++#ifndef _UAPI_ASM_SW64_UNISTD_64_H ++#define _UAPI_ASM_SW64_UNISTD_64_H ++ ++#define __NR_exit 1 ++#define __NR_fork 2 ++#define __NR_read 3 ++#define __NR_write 4 ++#define __NR_close 6 ++#define __NR_osf_wait4 7 ++#define __NR_link 9 ++#define __NR_unlink 10 ++#define __NR_chdir 12 ++#define __NR_fchdir 13 ++#define __NR_mknod 14 ++#define __NR_chmod 15 ++#define __NR_chown 16 ++#define __NR_brk 17 ++#define __NR_lseek 19 ++#define __NR_getxpid 20 ++#define __NR_osf_mount 21 ++#define __NR_umount2 22 ++#define __NR_setuid 23 ++#define __NR_getxuid 24 ++#define __NR_ptrace 26 ++#define __NR_access 33 ++#define __NR_sync 36 ++#define __NR_kill 37 ++#define __NR_setpgid 39 ++#define __NR_dup 41 ++#define __NR_pipe 42 ++#define __NR_osf_set_program_attributes 43 ++#define __NR_open 45 ++#define __NR_getxgid 47 ++#define __NR_osf_sigprocmask 48 ++#define __NR_acct 51 ++#define __NR_sigpending 52 ++#define __NR_ioctl 54 ++#define __NR_symlink 57 ++#define __NR_readlink 58 ++#define __NR_execve 59 ++#define __NR_umask 60 ++#define __NR_chroot 61 ++#define __NR_getpgrp 63 ++#define __NR_getpagesize 64 ++#define __NR_vfork 66 ++#define __NR_stat 67 ++#define __NR_lstat 68 ++#define __NR_mmap 71 ++#define __NR_munmap 73 ++#define __NR_mprotect 74 ++#define __NR_madvise 75 ++#define __NR_vhangup 76 ++#define __NR_getgroups 79 ++#define __NR_setgroups 80 ++#define __NR_setpgrp 82 ++#define __NR_osf_setitimer 83 ++#define __NR_osf_getitimer 86 ++#define __NR_gethostname 87 ++#define __NR_sethostname 88 ++#define __NR_getdtablesize 89 ++#define __NR_dup2 90 ++#define __NR_fstat 91 ++#define __NR_fcntl 92 ++#define __NR_osf_select 93 ++#define __NR_poll 94 ++#define __NR_fsync 95 ++#define __NR_setpriority 96 ++#define __NR_socket 97 ++#define __NR_connect 98 ++#define __NR_accept 99 ++#define __NR_getpriority 100 ++#define __NR_send 101 ++#define __NR_recv 102 ++#define __NR_sigreturn 103 ++#define __NR_bind 104 ++#define __NR_setsockopt 105 ++#define __NR_listen 106 ++#define __NR_sigsuspend 111 ++#define __NR_osf_sigstack 112 ++#define __NR_recvmsg 113 ++#define __NR_sendmsg 114 ++#define __NR_osf_gettimeofday 116 ++#define __NR_osf_getrusage 117 ++#define __NR_getsockopt 118 ++#define __NR_socketcall 119 ++#define __NR_readv 120 ++#define __NR_writev 121 ++#define __NR_osf_settimeofday 122 ++#define __NR_fchown 123 ++#define __NR_fchmod 124 ++#define __NR_recvfrom 125 ++#define __NR_setreuid 126 ++#define __NR_setregid 127 ++#define __NR_rename 128 ++#define __NR_truncate 129 ++#define __NR_ftruncate 130 ++#define __NR_flock 131 ++#define __NR_setgid 132 ++#define __NR_sendto 133 ++#define __NR_shutdown 134 ++#define __NR_socketpair 135 ++#define __NR_mkdir 136 ++#define __NR_rmdir 137 ++#define __NR_osf_utimes 138 ++#define __NR_getpeername 141 ++#define __NR_getrlimit 144 ++#define __NR_setrlimit 145 ++#define __NR_setsid 147 ++#define __NR_quotactl 148 ++#define __NR_getsockname 150 ++#define __NR_sigaction 156 ++#define __NR_osf_getdirentries 159 ++#define __NR_osf_statfs 160 ++#define __NR_osf_fstatfs 161 ++#define __NR_osf_getdomainname 165 ++#define __NR_setdomainname 166 ++#define __NR_bpf 170 ++#define __NR_userfaultfd 171 ++#define __NR_membarrier 172 ++#define __NR_mlock2 173 ++#define __NR_getpid 174 ++#define __NR_getppid 175 ++#define __NR_getuid 176 ++#define __NR_geteuid 177 ++#define __NR_getgid 178 ++#define __NR_getegid 179 ++#define __NR_osf_swapon 199 ++#define __NR_msgctl 200 ++#define __NR_msgget 201 ++#define __NR_msgrcv 202 ++#define __NR_msgsnd 203 ++#define __NR_semctl 204 ++#define __NR_semget 205 ++#define __NR_semop 206 ++#define __NR_osf_utsname 207 ++#define __NR_lchown 208 ++#define __NR_shmat 209 ++#define __NR_shmctl 210 ++#define __NR_shmdt 211 ++#define __NR_shmget 212 ++#define __NR_msync 217 ++#define __NR_osf_stat 224 ++#define __NR_osf_lstat 225 ++#define __NR_osf_fstat 226 ++#define __NR_osf_statfs64 227 ++#define __NR_osf_fstatfs64 228 ++#define __NR_statfs64 229 ++#define __NR_fstatfs64 230 ++#define __NR_getpgid 233 ++#define __NR_getsid 234 ++#define __NR_sigaltstack 235 ++#define __NR_osf_sysinfo 241 ++#define __NR_osf_proplist_syscall 244 ++#define __NR_osf_usleep_thread 251 ++#define __NR_sysfs 254 ++#define __NR_osf_getsysinfo 256 ++#define __NR_osf_setsysinfo 257 ++#define __NR_bdflush 300 ++#define __NR_sethae 301 ++#define __NR_mount 302 ++#define __NR_old_adjtimex 303 ++#define __NR_swapoff 304 ++#define __NR_getdents 305 ++#define __NR_create_module 306 ++#define __NR_init_module 307 ++#define __NR_delete_module 308 ++#define __NR_get_kernel_syms 309 ++#define __NR_syslog 310 ++#define __NR_reboot 311 ++#define __NR_clone 312 ++#define __NR_uselib 313 ++#define __NR_mlock 314 ++#define __NR_munlock 315 ++#define __NR_mlockall 316 ++#define __NR_munlockall 317 ++#define __NR_sysinfo 318 ++#define __NR__sysctl 319 ++#define __NR_oldumount 321 ++#define __NR_swapon 322 ++#define __NR_times 323 ++#define __NR_personality 324 ++#define __NR_setfsuid 325 ++#define __NR_setfsgid 326 ++#define __NR_ustat 327 ++#define __NR_statfs 328 ++#define __NR_fstatfs 329 ++#define __NR_sched_setparam 330 ++#define __NR_sched_getparam 331 ++#define __NR_sched_setscheduler 332 ++#define __NR_sched_getscheduler 333 ++#define __NR_sched_yield 334 ++#define __NR_sched_get_priority_max 335 ++#define __NR_sched_get_priority_min 336 ++#define __NR_sched_rr_get_interval 337 ++#define __NR_afs_syscall 338 ++#define __NR_uname 339 ++#define __NR_nanosleep 340 ++#define __NR_mremap 341 ++#define __NR_nfsservctl 342 ++#define __NR_setresuid 343 ++#define __NR_getresuid 344 ++#define __NR_pciconfig_read 345 ++#define __NR_pciconfig_write 346 ++#define __NR_query_module 347 ++#define __NR_prctl 348 ++#define __NR_pread64 349 ++#define __NR_pwrite64 350 ++#define __NR_rt_sigreturn 351 ++#define __NR_rt_sigaction 352 ++#define __NR_rt_sigprocmask 353 ++#define __NR_rt_sigpending 354 ++#define __NR_rt_sigtimedwait 355 ++#define __NR_rt_sigqueueinfo 356 ++#define __NR_rt_sigsuspend 357 ++#define __NR_select 358 ++#define __NR_gettimeofday 359 ++#define __NR_settimeofday 360 ++#define __NR_getitimer 361 ++#define __NR_setitimer 362 ++#define __NR_utimes 363 ++#define __NR_getrusage 364 ++#define __NR_wait4 365 ++#define __NR_adjtimex 366 ++#define __NR_getcwd 367 ++#define __NR_capget 368 ++#define __NR_capset 369 ++#define __NR_sendfile 370 ++#define __NR_setresgid 371 ++#define __NR_getresgid 372 ++#define __NR_dipc 373 ++#define __NR_pivot_root 374 ++#define __NR_mincore 375 ++#define __NR_pciconfig_iobase 376 ++#define __NR_getdents64 377 ++#define __NR_gettid 378 ++#define __NR_readahead 379 ++#define __NR_tkill 381 ++#define __NR_setxattr 382 ++#define __NR_lsetxattr 383 ++#define __NR_fsetxattr 384 ++#define __NR_getxattr 385 ++#define __NR_lgetxattr 386 ++#define __NR_fgetxattr 387 ++#define __NR_listxattr 388 ++#define __NR_llistxattr 389 ++#define __NR_flistxattr 390 ++#define __NR_removexattr 391 ++#define __NR_lremovexattr 392 ++#define __NR_fremovexattr 393 ++#define __NR_futex 394 ++#define __NR_sched_setaffinity 395 ++#define __NR_sched_getaffinity 396 ++#define __NR_tuxcall 397 ++#define __NR_io_setup 398 ++#define __NR_io_destroy 399 ++#define __NR_io_getevents 400 ++#define __NR_io_submit 401 ++#define __NR_io_cancel 402 ++#define __NR_io_pgetevents 403 ++#define __NR_rseq 404 ++#define __NR_exit_group 405 ++#define __NR_lookup_dcookie 406 ++#define __NR_epoll_create 407 ++#define __NR_epoll_ctl 408 ++#define __NR_epoll_wait 409 ++#define __NR_remap_file_pages 410 ++#define __NR_set_tid_address 411 ++#define __NR_restart_syscall 412 ++#define __NR_fadvise64 413 ++#define __NR_timer_create 414 ++#define __NR_timer_settime 415 ++#define __NR_timer_gettime 416 ++#define __NR_timer_getoverrun 417 ++#define __NR_timer_delete 418 ++#define __NR_clock_settime 419 ++#define __NR_clock_gettime 420 ++#define __NR_clock_getres 421 ++#define __NR_clock_nanosleep 422 ++#define __NR_semtimedop 423 ++#define __NR_tgkill 424 ++#define __NR_stat64 425 ++#define __NR_lstat64 426 ++#define __NR_fstat64 427 ++#define __NR_vserver 428 ++#define __NR_mbind 429 ++#define __NR_get_mempolicy 430 ++#define __NR_set_mempolicy 431 ++#define __NR_mq_open 432 ++#define __NR_mq_unlink 433 ++#define __NR_mq_timedsend 434 ++#define __NR_mq_timedreceive 435 ++#define __NR_mq_notify 436 ++#define __NR_mq_getsetattr 437 ++#define __NR_waitid 438 ++#define __NR_add_key 439 ++#define __NR_request_key 440 ++#define __NR_keyctl 441 ++#define __NR_ioprio_set 442 ++#define __NR_ioprio_get 443 ++#define __NR_inotify_init 444 ++#define __NR_inotify_add_watch 445 ++#define __NR_inotify_rm_watch 446 ++#define __NR_fdatasync 447 ++#define __NR_kexec_load 448 ++#define __NR_migrate_pages 449 ++#define __NR_openat 450 ++#define __NR_mkdirat 451 ++#define __NR_mknodat 452 ++#define __NR_fchownat 453 ++#define __NR_futimesat 454 ++#define __NR_fstatat64 455 ++#define __NR_unlinkat 456 ++#define __NR_renameat 457 ++#define __NR_linkat 458 ++#define __NR_symlinkat 459 ++#define __NR_readlinkat 460 ++#define __NR_fchmodat 461 ++#define __NR_faccessat 462 ++#define __NR_pselect6 463 ++#define __NR_ppoll 464 ++#define __NR_unshare 465 ++#define __NR_set_robust_list 466 ++#define __NR_get_robust_list 467 ++#define __NR_splice 468 ++#define __NR_sync_file_range 469 ++#define __NR_tee 470 ++#define __NR_vmsplice 471 ++#define __NR_move_pages 472 ++#define __NR_getcpu 473 ++#define __NR_epoll_pwait 474 ++#define __NR_utimensat 475 ++#define __NR_signalfd 476 ++#define __NR_timerfd 477 ++#define __NR_eventfd 478 ++#define __NR_recvmmsg 479 ++#define __NR_fallocate 480 ++#define __NR_timerfd_create 481 ++#define __NR_timerfd_settime 482 ++#define __NR_timerfd_gettime 483 ++#define __NR_signalfd4 484 ++#define __NR_eventfd2 485 ++#define __NR_epoll_create1 486 ++#define __NR_dup3 487 ++#define __NR_pipe2 488 ++#define __NR_inotify_init1 489 ++#define __NR_preadv 490 ++#define __NR_pwritev 491 ++#define __NR_rt_tgsigqueueinfo 492 ++#define __NR_perf_event_open 493 ++#define __NR_fanotify_init 494 ++#define __NR_fanotify_mark 495 ++#define __NR_prlimit64 496 ++#define __NR_name_to_handle_at 497 ++#define __NR_open_by_handle_at 498 ++#define __NR_clock_adjtime 499 ++#define __NR_syncfs 500 ++#define __NR_setns 501 ++#define __NR_accept4 502 ++#define __NR_sendmmsg 503 ++#define __NR_process_vm_readv 504 ++#define __NR_process_vm_writev 505 ++#define __NR_kcmp 506 ++#define __NR_finit_module 507 ++#define __NR_sched_setattr 508 ++#define __NR_sched_getattr 509 ++#define __NR_renameat2 510 ++#define __NR_getrandom 511 ++#define __NR_memfd_create 512 ++#define __NR_execveat 513 ++#define __NR_seccomp 514 ++#define __NR_copy_file_range 515 ++#define __NR_preadv2 516 ++#define __NR_pwritev2 517 ++#define __NR_statx 518 ++ ++#ifdef __KERNEL__ ++#define __NR_syscalls 519 ++#endif ++ ++#endif /* _UAPI_ASM_SW64_UNISTD_64_H */ +diff --git a/linux-user/meson.build b/linux-user/meson.build +index bf62c13e37..4f4196ed13 100644 +--- a/linux-user/meson.build ++++ b/linux-user/meson.build +@@ -37,5 +37,6 @@ subdir('ppc') + subdir('s390x') + subdir('sh4') + subdir('sparc') ++subdir('sw64') + subdir('x86_64') + subdir('xtensa') +diff --git a/linux-user/sw64/cpu_loop.c b/linux-user/sw64/cpu_loop.c +new file mode 100644 +index 0000000000..3f2fde0fba +--- /dev/null ++++ b/linux-user/sw64/cpu_loop.c +@@ -0,0 +1,108 @@ ++/* ++ * qemu user cpu loop ++ * ++ * Copyright (c) 2003-2008 Fabrice Bellard ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program 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 General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, see . ++ */ ++ ++#include "qemu/osdep.h" ++#include "qemu.h" ++#include "cpu_loop-common.h" ++ ++void cpu_loop(CPUSW64State *env) ++{ ++ CPUState *cs = CPU(sw64_env_get_cpu(env)); ++ int trapnr; ++ target_siginfo_t info; ++ abi_long sysret; ++ ++ while (1) { ++ cpu_exec_start(cs); ++ trapnr = cpu_exec(cs); ++ cpu_exec_end(cs); ++ process_queued_cpu_work(cs); ++ ++ switch (trapnr) { ++ case EXCP_OPCDEC: ++ cpu_abort(cs, "ILLEGAL SW64 insn at line %d!", __LINE__); ++ case EXCP_CALL_SYS: ++ switch (env->error_code) { ++ case 0x83: ++ /* CALLSYS */ ++ trapnr = env->ir[IDX_V0]; ++ sysret = do_syscall(env, trapnr, ++ env->ir[IDX_A0], env->ir[IDX_A1], ++ env->ir[IDX_A2], env->ir[IDX_A3], ++ env->ir[IDX_A4], env->ir[IDX_A5], ++ 0, 0); ++ if (sysret == -TARGET_ERESTARTSYS) { ++ env->pc -= 4; ++ break; ++ } ++ if (sysret == -TARGET_QEMU_ESIGRETURN) { ++ break; ++ } ++ /* Syscall writes 0 to V0 to bypass error check, similar ++ to how this is handled internal to Linux kernel. ++ (Ab)use trapnr temporarily as boolean indicating error. */ ++ trapnr = (env->ir[IDX_V0] != 0 && sysret < 0); ++ env->ir[IDX_V0] = (trapnr ? -sysret : sysret); ++ env->ir[IDX_A3] = trapnr; ++ break; ++ default: ++ printf("UNDO sys_call %lx\n", env->error_code); ++ exit(-1); ++ } ++ break; ++ case EXCP_MMFAULT: ++ info.si_signo = TARGET_SIGSEGV; ++ info.si_errno = 0; ++ info.si_code = (page_get_flags(env->trap_arg0) & PAGE_VALID ++ ? TARGET_SEGV_ACCERR : TARGET_SEGV_MAPERR); ++ info._sifields._sigfault._addr = env->trap_arg0; ++ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); ++ break; ++ case EXCP_ARITH: ++ info.si_signo = TARGET_SIGFPE; ++ info.si_errno = 0; ++ info.si_code = TARGET_FPE_FLTINV; ++ info._sifields._sigfault._addr = env->pc; ++ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); ++ break; ++ case EXCP_INTERRUPT: ++ /* just indicate that signals should be handled asap */ ++ break; ++ default: ++ cpu_abort(cs, "UNDO"); ++ } ++ process_pending_signals (env); ++ ++ /* Most of the traps imply a transition through HMcode, which ++ implies an REI instruction has been executed. Which means ++ that RX and LOCK_ADDR should be cleared. But there are a ++ few exceptions for traps internal to QEMU. */ ++ } ++} ++ ++void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs) ++{ ++ int i; ++ ++ for(i = 0; i < 28; i++) { ++ env->ir[i] = ((abi_ulong *)regs)[i]; ++ } ++ env->ir[IDX_SP] = regs->usp; ++ env->pc = regs->pc; ++} +diff --git a/linux-user/sw64/signal.c b/linux-user/sw64/signal.c +new file mode 100644 +index 0000000000..5822e808d3 +--- /dev/null ++++ b/linux-user/sw64/signal.c +@@ -0,0 +1,273 @@ ++/* ++ * Emulation of Linux signals ++ * ++ * Copyright (c) 2003 Fabrice Bellard ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program 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 General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, see . ++ */ ++#include "qemu/osdep.h" ++#include "qemu.h" ++#include "signal-common.h" ++#include "linux-user/trace.h" ++ ++struct target_sigcontext { ++ abi_long sc_onstack; ++ abi_long sc_mask; ++ abi_long sc_pc; ++ abi_long sc_ps; ++ abi_long sc_regs[32]; ++ abi_long sc_ownedfp; ++ abi_long sc_fpregs[32]; ++ abi_ulong sc_fpcr; ++ abi_ulong sc_fp_control; ++ abi_ulong sc_reserved1; ++ abi_ulong sc_reserved2; ++ abi_ulong sc_ssize; ++ abi_ulong sc_sbase; ++ abi_ulong sc_traparg_a0; ++ abi_ulong sc_traparg_a1; ++ abi_ulong sc_traparg_a2; ++ abi_ulong sc_fp_trap_pc; ++ abi_ulong sc_fp_trigger_sum; ++ abi_ulong sc_fp_trigger_inst; ++}; ++ ++struct target_ucontext { ++ abi_ulong tuc_flags; ++ abi_ulong tuc_link; ++ abi_ulong tuc_osf_sigmask; ++ target_stack_t tuc_stack; ++ struct target_sigcontext tuc_mcontext; ++ target_sigset_t tuc_sigmask; ++}; ++ ++struct target_sigframe { ++ struct target_sigcontext sc; ++ unsigned int retcode[3]; ++}; ++ ++struct target_rt_sigframe { ++ target_siginfo_t info; ++ struct target_ucontext uc; ++ unsigned int retcode[3]; ++}; ++ ++#define INSN_MOV_R30_R16 0x47fe0410 ++#define INSN_LDI_R0 0x201f0000 ++#define INSN_CALLSYS 0x00000083 ++ ++static void setup_sigcontext(struct target_sigcontext *sc, CPUSW64State *env, ++ abi_ulong frame_addr, target_sigset_t *set) ++{ ++ int i; ++ ++ __put_user(on_sig_stack(frame_addr), &sc->sc_onstack); ++ __put_user(set->sig[0], &sc->sc_mask); ++ __put_user(env->pc, &sc->sc_pc); ++ __put_user(8, &sc->sc_ps); ++ ++ for (i = 0; i < 31; ++i) { ++ __put_user(env->ir[i], &sc->sc_regs[i]); ++ } ++ __put_user(0, &sc->sc_regs[31]); ++ ++ for (i = 0; i < 31; ++i) { ++ __put_user(env->fr[i], &sc->sc_fpregs[i]); ++ } ++ __put_user(0, &sc->sc_fpregs[31]); ++ __put_user(cpu_sw64_load_fpcr(env), &sc->sc_fpcr); ++ ++ __put_user(0, &sc->sc_traparg_a0); /* FIXME */ ++ __put_user(0, &sc->sc_traparg_a1); /* FIXME */ ++ __put_user(0, &sc->sc_traparg_a2); /* FIXME */ ++} ++ ++static void restore_sigcontext(CPUSW64State *env, ++ struct target_sigcontext *sc) ++{ ++ uint64_t fpcr; ++ int i; ++ ++ __get_user(env->pc, &sc->sc_pc); ++ ++ for (i = 0; i < 31; ++i) { ++ __get_user(env->ir[i], &sc->sc_regs[i]); ++ } ++ for (i = 0; i < 31; ++i) { ++ __get_user(env->fr[i], &sc->sc_fpregs[i]); ++ } ++ ++ __get_user(fpcr, &sc->sc_fpcr); ++ cpu_sw64_store_fpcr(env, fpcr); ++} ++ ++static inline abi_ulong get_sigframe(struct target_sigaction *sa, ++ CPUSW64State *env, ++ unsigned long framesize) ++{ ++ abi_ulong sp; ++ ++ sp = target_sigsp(get_sp_from_cpustate(env), sa); ++ ++ return (sp - framesize) & -32; ++} ++ ++void setup_frame(int sig, struct target_sigaction *ka, ++ target_sigset_t *set, CPUSW64State *env) ++{ ++ abi_ulong frame_addr, r26; ++ struct target_sigframe *frame; ++ int err = 0; ++ ++ frame_addr = get_sigframe(ka, env, sizeof(*frame)); ++ trace_user_setup_frame(env, frame_addr); ++ if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) { ++ goto give_sigsegv; ++ } ++ ++ setup_sigcontext(&frame->sc, env, frame_addr, set); ++ ++ if (ka->sa_restorer) { ++ r26 = ka->sa_restorer; ++ } else { ++ __put_user(INSN_MOV_R30_R16, &frame->retcode[0]); ++ __put_user(INSN_LDI_R0 + TARGET_NR_sigreturn, ++ &frame->retcode[1]); ++ __put_user(INSN_CALLSYS, &frame->retcode[2]); ++ /* imb() */ ++ r26 = frame_addr + offsetof(struct target_sigframe, retcode); ++ } ++ ++ unlock_user_struct(frame, frame_addr, 1); ++ ++ if (err) { ++give_sigsegv: ++ force_sigsegv(sig); ++ return; ++ } ++ ++ env->ir[IDX_RA] = r26; ++ env->ir[IDX_PV] = env->pc = ka->_sa_handler; ++ env->ir[IDX_A0] = sig; ++ env->ir[IDX_A1] = 0; ++ env->ir[IDX_A2] = frame_addr + offsetof(struct target_sigframe, sc); ++ env->ir[IDX_SP] = frame_addr; ++} ++ ++void setup_rt_frame(int sig, struct target_sigaction *ka, ++ target_siginfo_t *info, ++ target_sigset_t *set, CPUSW64State *env) ++{ ++ abi_ulong frame_addr, r26; ++ struct target_rt_sigframe *frame; ++ int i, err = 0; ++ ++ frame_addr = get_sigframe(ka, env, sizeof(*frame)); ++ trace_user_setup_rt_frame(env, frame_addr); ++ if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) { ++ goto give_sigsegv; ++ } ++ ++ tswap_siginfo(&frame->info, info); ++ ++ __put_user(0, &frame->uc.tuc_flags); ++ __put_user(0, &frame->uc.tuc_link); ++ __put_user(set->sig[0], &frame->uc.tuc_osf_sigmask); ++ ++ target_save_altstack(&frame->uc.tuc_stack, env); ++ ++ setup_sigcontext(&frame->uc.tuc_mcontext, env, frame_addr, set); ++ for (i = 0; i < TARGET_NSIG_WORDS; ++i) { ++ __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]); ++ } ++ ++ if (ka->sa_restorer) { ++ r26 = ka->sa_restorer; ++ } else { ++ __put_user(INSN_MOV_R30_R16, &frame->retcode[0]); ++ __put_user(INSN_LDI_R0 + TARGET_NR_rt_sigreturn, ++ &frame->retcode[1]); ++ __put_user(INSN_CALLSYS, &frame->retcode[2]); ++ r26 = frame_addr + offsetof(struct target_sigframe, retcode); ++ } ++ ++ if (err) { ++give_sigsegv: ++ force_sigsegv(sig); ++ return; ++ } ++ ++ env->ir[IDX_RA] = r26; ++ env->ir[IDX_PV] = env->pc = ka->_sa_handler; ++ env->ir[IDX_A0] = sig; ++ env->ir[IDX_A1] = frame_addr + offsetof(struct target_rt_sigframe, info); ++ env->ir[IDX_A2] = frame_addr + offsetof(struct target_rt_sigframe, uc); ++ env->ir[IDX_SP] = frame_addr; ++} ++ ++long do_sigreturn(CPUSW64State *env) ++{ ++ struct target_sigcontext *sc; ++ abi_ulong sc_addr = env->ir[IDX_A0]; ++ target_sigset_t target_set; ++ sigset_t set; ++ ++ if (!lock_user_struct(VERIFY_READ, sc, sc_addr, 1)) { ++ goto badframe; ++ } ++ ++ target_sigemptyset(&target_set); ++ __get_user(target_set.sig[0], &sc->sc_mask); ++ ++ target_to_host_sigset_internal(&set, &target_set); ++ set_sigmask(&set); ++ ++ restore_sigcontext(env, sc); ++ unlock_user_struct(sc, sc_addr, 0); ++ return -TARGET_QEMU_ESIGRETURN; ++ ++badframe: ++ force_sig(TARGET_SIGSEGV); ++ return -TARGET_QEMU_ESIGRETURN; ++} ++ ++long do_rt_sigreturn(CPUSW64State *env) ++{ ++ abi_ulong frame_addr = env->ir[IDX_A0]; ++ struct target_rt_sigframe *frame; ++ sigset_t set; ++ ++ trace_user_do_rt_sigreturn(env, frame_addr); ++ if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) { ++ goto badframe; ++ } ++ target_to_host_sigset(&set, &frame->uc.tuc_sigmask); ++ set_sigmask(&set); ++ ++ restore_sigcontext(env, &frame->uc.tuc_mcontext); ++ if (do_sigaltstack(frame_addr + offsetof(struct target_rt_sigframe, ++ uc.tuc_stack), ++ 0, env->ir[IDX_SP]) == -EFAULT) { ++ goto badframe; ++ } ++ ++ unlock_user_struct(frame, frame_addr, 0); ++ return -TARGET_QEMU_ESIGRETURN; ++ ++ ++badframe: ++ unlock_user_struct(frame, frame_addr, 0); ++ force_sig(TARGET_SIGSEGV); ++ return -TARGET_QEMU_ESIGRETURN; ++} +diff --git a/linux-user/sw64/sockbits.h b/linux-user/sw64/sockbits.h +new file mode 100644 +index 0000000000..0e4c8f012d +--- /dev/null ++++ b/linux-user/sw64/sockbits.h +@@ -0,0 +1 @@ ++#include "../generic/sockbits.h" +diff --git a/linux-user/sw64/syscall_nr.h b/linux-user/sw64/syscall_nr.h +new file mode 100644 +index 0000000000..91737af322 +--- /dev/null ++++ b/linux-user/sw64/syscall_nr.h +@@ -0,0 +1,471 @@ ++/* ++ * This file contains the system call numbers. ++ */ ++#define TARGET_NR_osf_syscall 0 /* not implemented */ ++#define TARGET_NR_exit 1 ++#define TARGET_NR_fork 2 ++#define TARGET_NR_read 3 ++#define TARGET_NR_write 4 ++#define TARGET_NR_osf_old_open 5 /* not implemented */ ++#define TARGET_NR_close 6 ++#define TARGET_NR_osf_wait4 7 ++#define TARGET_NR_osf_old_creat 8 /* not implemented */ ++#define TARGET_NR_link 9 ++#define TARGET_NR_unlink 10 ++#define TARGET_NR_osf_execve 11 /* not implemented */ ++#define TARGET_NR_chdir 12 ++#define TARGET_NR_fchdir 13 ++#define TARGET_NR_mknod 14 ++#define TARGET_NR_chmod 15 ++#define TARGET_NR_chown 16 ++#define TARGET_NR_brk 17 ++#define TARGET_NR_osf_getfsstat 18 /* not implemented */ ++#define TARGET_NR_lseek 19 ++#define TARGET_NR_getxpid 20 ++#define TARGET_NR_osf_mount 21 ++#define TARGET_NR_umount 22 ++#define TARGET_NR_setuid 23 ++#define TARGET_NR_getxuid 24 ++#define TARGET_NR_exec_with_loader 25 /* not implemented */ ++#define TARGET_NR_ptrace 26 ++#define TARGET_NR_osf_nrecvmsg 27 /* not implemented */ ++#define TARGET_NR_osf_nsendmsg 28 /* not implemented */ ++#define TARGET_NR_osf_nrecvfrom 29 /* not implemented */ ++#define TARGET_NR_osf_naccept 30 /* not implemented */ ++#define TARGET_NR_osf_ngetpeername 31 /* not implemented */ ++#define TARGET_NR_osf_ngetsockname 32 /* not implemented */ ++#define TARGET_NR_access 33 ++#define TARGET_NR_osf_chflags 34 /* not implemented */ ++#define TARGET_NR_osf_fchflags 35 /* not implemented */ ++#define TARGET_NR_sync 36 ++#define TARGET_NR_kill 37 ++#define TARGET_NR_osf_old_stat 38 /* not implemented */ ++#define TARGET_NR_setpgid 39 ++#define TARGET_NR_osf_old_lstat 40 /* not implemented */ ++#define TARGET_NR_dup 41 ++#define TARGET_NR_pipe 42 ++#define TARGET_NR_osf_set_program_attributes 43 ++#define TARGET_NR_osf_profil 44 /* not implemented */ ++#define TARGET_NR_open 45 ++#define TARGET_NR_osf_old_sigaction 46 /* not implemented */ ++#define TARGET_NR_getxgid 47 ++#define TARGET_NR_osf_sigprocmask 48 ++#define TARGET_NR_osf_getlogin 49 /* not implemented */ ++#define TARGET_NR_osf_setlogin 50 /* not implemented */ ++#define TARGET_NR_acct 51 ++#define TARGET_NR_sigpending 52 ++ ++#define TARGET_NR_ioctl 54 ++#define TARGET_NR_osf_reboot 55 /* not implemented */ ++#define TARGET_NR_osf_revoke 56 /* not implemented */ ++#define TARGET_NR_symlink 57 ++#define TARGET_NR_readlink 58 ++#define TARGET_NR_execve 59 ++#define TARGET_NR_umask 60 ++#define TARGET_NR_chroot 61 ++#define TARGET_NR_osf_old_fstat 62 /* not implemented */ ++#define TARGET_NR_getpgrp 63 ++#define TARGET_NR_getpagesize 64 ++#define TARGET_NR_osf_mremap 65 /* not implemented */ ++#define TARGET_NR_vfork 66 ++#define TARGET_NR_stat 67 ++#define TARGET_NR_lstat 68 ++#define TARGET_NR_osf_sbrk 69 /* not implemented */ ++#define TARGET_NR_osf_sstk 70 /* not implemented */ ++#define TARGET_NR_mmap 71 /* OSF/1 mmap is superset of Linux */ ++#define TARGET_NR_osf_old_vadvise 72 /* not implemented */ ++#define TARGET_NR_munmap 73 ++#define TARGET_NR_mprotect 74 ++#define TARGET_NR_madvise 75 ++#define TARGET_NR_vhangup 76 ++#define TARGET_NR_osf_kmodcall 77 /* not implemented */ ++#define TARGET_NR_osf_mincore 78 /* not implemented */ ++#define TARGET_NR_getgroups 79 ++#define TARGET_NR_setgroups 80 ++#define TARGET_NR_osf_old_getpgrp 81 /* not implemented */ ++#define TARGET_NR_setpgrp 82 /* BSD alias for setpgid */ ++#define TARGET_NR_osf_setitimer 83 ++#define TARGET_NR_osf_old_wait 84 /* not implemented */ ++#define TARGET_NR_osf_table 85 /* not implemented */ ++#define TARGET_NR_osf_getitimer 86 ++#define TARGET_NR_gethostname 87 ++#define TARGET_NR_sethostname 88 ++#define TARGET_NR_getdtablesize 89 ++#define TARGET_NR_dup2 90 ++#define TARGET_NR_fstat 91 ++#define TARGET_NR_fcntl 92 ++#define TARGET_NR_osf_select 93 ++#define TARGET_NR_poll 94 ++#define TARGET_NR_fsync 95 ++#define TARGET_NR_setpriority 96 ++#define TARGET_NR_socket 97 ++#define TARGET_NR_connect 98 ++#define TARGET_NR_accept 99 ++#define TARGET_NR_getpriority 100 ++#define TARGET_NR_send 101 ++#define TARGET_NR_recv 102 ++#define TARGET_NR_sigreturn 103 ++#define TARGET_NR_bind 104 ++#define TARGET_NR_setsockopt 105 ++#define TARGET_NR_listen 106 ++#define TARGET_NR_osf_plock 107 /* not implemented */ ++#define TARGET_NR_osf_old_sigvec 108 /* not implemented */ ++#define TARGET_NR_osf_old_sigblock 109 /* not implemented */ ++#define TARGET_NR_osf_old_sigsetmask 110 /* not implemented */ ++#define TARGET_NR_sigsuspend 111 ++#define TARGET_NR_osf_sigstack 112 ++#define TARGET_NR_recvmsg 113 ++#define TARGET_NR_sendmsg 114 ++#define TARGET_NR_osf_old_vtrace 115 /* not implemented */ ++#define TARGET_NR_osf_gettimeofday 116 ++#define TARGET_NR_osf_getrusage 117 ++#define TARGET_NR_getsockopt 118 ++ ++#define TARGET_NR_readv 120 ++#define TARGET_NR_writev 121 ++#define TARGET_NR_osf_settimeofday 122 ++#define TARGET_NR_fchown 123 ++#define TARGET_NR_fchmod 124 ++#define TARGET_NR_recvfrom 125 ++#define TARGET_NR_setreuid 126 ++#define TARGET_NR_setregid 127 ++#define TARGET_NR_rename 128 ++#define TARGET_NR_truncate 129 ++#define TARGET_NR_ftruncate 130 ++#define TARGET_NR_flock 131 ++#define TARGET_NR_setgid 132 ++#define TARGET_NR_sendto 133 ++#define TARGET_NR_shutdown 134 ++#define TARGET_NR_socketpair 135 ++#define TARGET_NR_mkdir 136 ++#define TARGET_NR_rmdir 137 ++#define TARGET_NR_osf_utimes 138 ++#define TARGET_NR_osf_old_sigreturn 139 /* not implemented */ ++#define TARGET_NR_osf_adjtime 140 /* not implemented */ ++#define TARGET_NR_getpeername 141 ++#define TARGET_NR_osf_gethostid 142 /* not implemented */ ++#define TARGET_NR_osf_sethostid 143 /* not implemented */ ++#define TARGET_NR_getrlimit 144 ++#define TARGET_NR_setrlimit 145 ++#define TARGET_NR_osf_old_killpg 146 /* not implemented */ ++#define TARGET_NR_setsid 147 ++#define TARGET_NR_quotactl 148 ++#define TARGET_NR_osf_oldquota 149 /* not implemented */ ++#define TARGET_NR_getsockname 150 ++ ++#define TARGET_NR_osf_pid_block 153 /* not implemented */ ++#define TARGET_NR_osf_pid_unblock 154 /* not implemented */ ++ ++#define TARGET_NR_sigaction 156 ++#define TARGET_NR_osf_sigwaitprim 157 /* not implemented */ ++#define TARGET_NR_osf_nfssvc 158 /* not implemented */ ++#define TARGET_NR_osf_getdirentries 159 ++#define TARGET_NR_osf_statfs 160 ++#define TARGET_NR_osf_fstatfs 161 ++ ++#define TARGET_NR_osf_asynch_daemon 163 /* not implemented */ ++#define TARGET_NR_osf_getfh 164 /* not implemented */ ++#define TARGET_NR_osf_getdomainname 165 ++#define TARGET_NR_setdomainname 166 ++ ++#define TARGET_NR_osf_exportfs 169 /* not implemented */ ++ ++#define TARGET_NR_osf_alt_plock 181 /* not implemented */ ++ ++#define TARGET_NR_osf_getmnt 184 /* not implemented */ ++ ++#define TARGET_NR_osf_alt_sigpending 187 /* not implemented */ ++#define TARGET_NR_osf_alt_setsid 188 /* not implemented */ ++ ++#define TARGET_NR_osf_swapon 199 ++#define TARGET_NR_msgctl 200 ++#define TARGET_NR_msgget 201 ++#define TARGET_NR_msgrcv 202 ++#define TARGET_NR_msgsnd 203 ++#define TARGET_NR_semctl 204 ++#define TARGET_NR_semget 205 ++#define TARGET_NR_semop 206 ++#define TARGET_NR_osf_utsname 207 ++#define TARGET_NR_lchown 208 ++#define TARGET_NR_osf_shmat 209 ++#define TARGET_NR_shmctl 210 ++#define TARGET_NR_shmdt 211 ++#define TARGET_NR_shmget 212 ++#define TARGET_NR_osf_mvalid 213 /* not implemented */ ++#define TARGET_NR_osf_getaddressconf 214 /* not implemented */ ++#define TARGET_NR_osf_msleep 215 /* not implemented */ ++#define TARGET_NR_osf_mwakeup 216 /* not implemented */ ++#define TARGET_NR_msync 217 ++#define TARGET_NR_osf_signal 218 /* not implemented */ ++#define TARGET_NR_osf_utc_gettime 219 /* not implemented */ ++#define TARGET_NR_osf_utc_adjtime 220 /* not implemented */ ++ ++#define TARGET_NR_osf_security 222 /* not implemented */ ++#define TARGET_NR_osf_kloadcall 223 /* not implemented */ ++ ++#define TARGET_NR_osf_stat 224 ++#define TARGET_NR_osf_lstat 225 ++#define TARGET_NR_osf_fstat 226 ++#define TARGET_NR_osf_statfs64 227 ++#define TARGET_NR_osf_fstatfs64 228 ++ ++#define TARGET_NR_getpgid 233 ++#define TARGET_NR_getsid 234 ++#define TARGET_NR_sigaltstack 235 ++#define TARGET_NR_osf_waitid 236 /* not implemented */ ++#define TARGET_NR_osf_priocntlset 237 /* not implemented */ ++#define TARGET_NR_osf_sigsendset 238 /* not implemented */ ++#define TARGET_NR_osf_set_speculative 239 /* not implemented */ ++#define TARGET_NR_osf_msfs_syscall 240 /* not implemented */ ++#define TARGET_NR_osf_sysinfo 241 ++#define TARGET_NR_osf_uadmin 242 /* not implemented */ ++#define TARGET_NR_osf_fuser 243 /* not implemented */ ++#define TARGET_NR_osf_proplist_syscall 244 ++#define TARGET_NR_osf_ntp_adjtime 245 /* not implemented */ ++#define TARGET_NR_osf_ntp_gettime 246 /* not implemented */ ++#define TARGET_NR_osf_pathconf 247 /* not implemented */ ++#define TARGET_NR_osf_fpathconf 248 /* not implemented */ ++ ++#define TARGET_NR_osf_uswitch 250 /* not implemented */ ++#define TARGET_NR_osf_usleep_thread 251 ++#define TARGET_NR_osf_audcntl 252 /* not implemented */ ++#define TARGET_NR_osf_audgen 253 /* not implemented */ ++#define TARGET_NR_sysfs 254 ++#define TARGET_NR_osf_subsys_info 255 /* not implemented */ ++#define TARGET_NR_osf_getsysinfo 256 ++#define TARGET_NR_osf_setsysinfo 257 ++#define TARGET_NR_osf_afs_syscall 258 /* not implemented */ ++#define TARGET_NR_osf_swapctl 259 /* not implemented */ ++#define TARGET_NR_osf_memcntl 260 /* not implemented */ ++#define TARGET_NR_osf_fdatasync 261 /* not implemented */ ++ ++/* ++ * Ignore legacy syscalls that we don't use. ++ */ ++#define TARGET_IGNORE_alarm ++#define TARGET_IGNORE_creat ++#define TARGET_IGNORE_getegid ++#define TARGET_IGNORE_geteuid ++#define TARGET_IGNORE_getgid ++#define TARGET_IGNORE_getpid ++#define TARGET_IGNORE_getppid ++#define TARGET_IGNORE_getuid ++#define TARGET_IGNORE_pause ++#define TARGET_IGNORE_time ++#define TARGET_IGNORE_utime ++#define TARGET_IGNORE_umount2 ++ ++/* ++ * Linux-specific system calls begin at 300 ++ */ ++#define TARGET_NR_bdflush 300 ++#define TARGET_NR_sethae 301 ++#define TARGET_NR_mount 302 ++#define TARGET_NR_old_adjtimex 303 ++#define TARGET_NR_swapoff 304 ++#define TARGET_NR_getdents 305 ++#define TARGET_NR_create_module 306 ++#define TARGET_NR_init_module 307 ++#define TARGET_NR_delete_module 308 ++#define TARGET_NR_get_kernel_syms 309 ++#define TARGET_NR_syslog 310 ++#define TARGET_NR_reboot 311 ++#define TARGET_NR_clone 312 ++#define TARGET_NR_uselib 313 ++#define TARGET_NR_mlock 314 ++#define TARGET_NR_munlock 315 ++#define TARGET_NR_mlockall 316 ++#define TARGET_NR_munlockall 317 ++#define TARGET_NR_sysinfo 318 ++#define TARGET_NR__sysctl 319 ++/* 320 was sysTARGETidle. */ ++#define TARGET_NR_oldumount 321 ++#define TARGET_NR_swapon 322 ++#define TARGET_NR_times 323 ++#define TARGET_NR_personality 324 ++#define TARGET_NR_setfsuid 325 ++#define TARGET_NR_setfsgid 326 ++#define TARGET_NR_ustat 327 ++#define TARGET_NR_statfs 328 ++#define TARGET_NR_fstatfs 329 ++#define TARGET_NR_sched_setparam 330 ++#define TARGET_NR_sched_getparam 331 ++#define TARGET_NR_sched_setscheduler 332 ++#define TARGET_NR_sched_getscheduler 333 ++#define TARGET_NR_sched_yield 334 ++#define TARGET_NR_sched_get_priority_max 335 ++#define TARGET_NR_sched_get_priority_min 336 ++#define TARGET_NR_sched_rr_get_interval 337 ++#define TARGET_NR_afs_syscall 338 ++#define TARGET_NR_uname 339 ++#define TARGET_NR_nanosleep 340 ++#define TARGET_NR_mremap 341 ++#define TARGET_NR_nfsservctl 342 ++#define TARGET_NR_setresuid 343 ++#define TARGET_NR_getresuid 344 ++#define TARGET_NR_pciconfig_read 345 ++#define TARGET_NR_pciconfig_write 346 ++#define TARGET_NR_query_module 347 ++#define TARGET_NR_prctl 348 ++#define TARGET_NR_pread64 349 ++#define TARGET_NR_pwrite64 350 ++#define TARGET_NR_rt_sigreturn 351 ++#define TARGET_NR_rt_sigaction 352 ++#define TARGET_NR_rt_sigprocmask 353 ++#define TARGET_NR_rt_sigpending 354 ++#define TARGET_NR_rt_sigtimedwait 355 ++#define TARGET_NR_rt_sigqueueinfo 356 ++#define TARGET_NR_rt_sigsuspend 357 ++#define TARGET_NR_select 358 ++#define TARGET_NR_gettimeofday 359 ++#define TARGET_NR_settimeofday 360 ++#define TARGET_NR_getitimer 361 ++#define TARGET_NR_setitimer 362 ++#define TARGET_NR_utimes 363 ++#define TARGET_NR_getrusage 364 ++#define TARGET_NR_wait4 365 ++#define TARGET_NR_adjtimex 366 ++#define TARGET_NR_getcwd 367 ++#define TARGET_NR_capget 368 ++#define TARGET_NR_capset 369 ++#define TARGET_NR_sendfile 370 ++#define TARGET_NR_setresgid 371 ++#define TARGET_NR_getresgid 372 ++#define TARGET_NR_dipc 373 ++#define TARGET_NR_pivot_root 374 ++#define TARGET_NR_mincore 375 ++#define TARGET_NR_pciconfig_iobase 376 ++#define TARGET_NR_getdents64 377 ++#define TARGET_NR_gettid 378 ++#define TARGET_NR_readahead 379 ++/* 380 is unused */ ++#define TARGET_NR_tkill 381 ++#define TARGET_NR_setxattr 382 ++#define TARGET_NR_lsetxattr 383 ++#define TARGET_NR_fsetxattr 384 ++#define TARGET_NR_getxattr 385 ++#define TARGET_NR_lgetxattr 386 ++#define TARGET_NR_fgetxattr 387 ++#define TARGET_NR_listxattr 388 ++#define TARGET_NR_llistxattr 389 ++#define TARGET_NR_flistxattr 390 ++#define TARGET_NR_removexattr 391 ++#define TARGET_NR_lremovexattr 392 ++#define TARGET_NR_fremovexattr 393 ++#define TARGET_NR_futex 394 ++#define TARGET_NR_sched_setaffinity 395 ++#define TARGET_NR_sched_getaffinity 396 ++#define TARGET_NR_tuxcall 397 ++#define TARGET_NR_io_setup 398 ++#define TARGET_NR_io_destroy 399 ++#define TARGET_NR_io_getevents 400 ++#define TARGET_NR_io_submit 401 ++#define TARGET_NR_io_cancel 402 ++#define TARGET_NR_exit_group 405 ++#define TARGET_NR_lookup_dcookie 406 ++#define TARGET_NR_epoll_create 407 ++#define TARGET_NR_epoll_ctl 408 ++#define TARGET_NR_epoll_wait 409 ++/* Feb 2007: These three sysTARGETepoll defines shouldn't be here but culling ++ * them would break userspace apps ... we'll kill them off in 2010 :) */ ++#define TARGET_NR_sys_epoll_create TARGET_NR_epoll_create ++#define TARGET_NR_sys_epoll_ctl TARGET_NR_epoll_ctl ++#define TARGET_NR_sys_epoll_wait TARGET_NR_epoll_wait ++#define TARGET_NR_remap_file_pages 410 ++#define TARGET_NR_set_tid_address 411 ++#define TARGET_NR_restart_syscall 412 ++#define TARGET_NR_fadvise64 413 ++#define TARGET_NR_timer_create 414 ++#define TARGET_NR_timer_settime 415 ++#define TARGET_NR_timer_gettime 416 ++#define TARGET_NR_timer_getoverrun 417 ++#define TARGET_NR_timer_delete 418 ++#define TARGET_NR_clock_settime 419 ++#define TARGET_NR_clock_gettime 420 ++#define TARGET_NR_clock_getres 421 ++#define TARGET_NR_clock_nanosleep 422 ++#define TARGET_NR_semtimedop 423 ++#define TARGET_NR_tgkill 424 ++#define TARGET_NR_stat64 425 ++#define TARGET_NR_lstat64 426 ++#define TARGET_NR_fstat64 427 ++#define TARGET_NR_vserver 428 ++#define TARGET_NR_mbind 429 ++#define TARGET_NR_get_mempolicy 430 ++#define TARGET_NR_set_mempolicy 431 ++#define TARGET_NR_mq_open 432 ++#define TARGET_NR_mq_unlink 433 ++#define TARGET_NR_mq_timedsend 434 ++#define TARGET_NR_mq_timedreceive 435 ++#define TARGET_NR_mq_notify 436 ++#define TARGET_NR_mq_getsetattr 437 ++#define TARGET_NR_waitid 438 ++#define TARGET_NR_add_key 439 ++#define TARGET_NR_request_key 440 ++#define TARGET_NR_keyctl 441 ++#define TARGET_NR_ioprio_set 442 ++#define TARGET_NR_ioprio_get 443 ++#define TARGET_NR_inotify_init 444 ++#define TARGET_NR_inotify_add_watch 445 ++#define TARGET_NR_inotify_rm_watch 446 ++#define TARGET_NR_fdatasync 447 ++#define TARGET_NR_kexec_load 448 ++#define TARGET_NR_migrate_pages 449 ++#define TARGET_NR_openat 450 ++#define TARGET_NR_mkdirat 451 ++#define TARGET_NR_mknodat 452 ++#define TARGET_NR_fchownat 453 ++#define TARGET_NR_futimesat 454 ++#define TARGET_NR_fstatat64 455 ++#define TARGET_NR_unlinkat 456 ++#define TARGET_NR_renameat 457 ++#define TARGET_NR_linkat 458 ++#define TARGET_NR_symlinkat 459 ++#define TARGET_NR_readlinkat 460 ++#define TARGET_NR_fchmodat 461 ++#define TARGET_NR_faccessat 462 ++#define TARGET_NR_pselect6 463 ++#define TARGET_NR_ppoll 464 ++#define TARGET_NR_unshare 465 ++#define TARGET_NR_set_robust_list 466 ++#define TARGET_NR_get_robust_list 467 ++#define TARGET_NR_splice 468 ++#define TARGET_NR_sync_file_range 469 ++#define TARGET_NR_tee 470 ++#define TARGET_NR_vmsplice 471 ++#define TARGET_NR_move_pages 472 ++#define TARGET_NR_getcpu 473 ++#define TARGET_NR_epoll_pwait 474 ++#define TARGET_NR_utimensat 475 ++#define TARGET_NR_signalfd 476 ++#define TARGET_NR_timerfd 477 ++#define TARGET_NR_eventfd 478 ++#define TARGET_NR_recvmmsg 479 ++#define TARGET_NR_fallocate 480 ++#define TARGET_NR_timerfd_create 481 ++#define TARGET_NR_timerfd_settime 482 ++#define TARGET_NR_timerfd_gettime 483 ++#define TARGET_NR_signalfd4 484 ++#define TARGET_NR_eventfd2 485 ++#define TARGET_NR_epoll_create1 486 ++#define TARGET_NR_dup3 487 ++#define TARGET_NR_pipe2 488 ++#define TARGET_NR_inotify_init1 489 ++#define TARGET_NR_preadv 490 ++#define TARGET_NR_pwritev 491 ++#define TARGET_NR_rt_tgsigqueueinfo 492 ++#define TARGET_NR_perf_event_open 493 ++#define TARGET_NR_fanotify_init 494 ++#define TARGET_NR_fanotify_mark 495 ++#define TARGET_NR_prlimit64 496 ++#define TARGET_NR_name_to_handle_at 497 ++#define TARGET_NR_open_by_handle_at 498 ++#define TARGET_NR_clock_adjtime 499 ++#define TARGET_NR_syncfs 500 ++#define TARGET_NR_setns 501 ++#define TARGET_NR_accept4 502 ++#define TARGET_NR_sendmmsg 503 ++#define TARGET_NR_process_vm_readv 504 ++#define TARGET_NR_process_vm_writev 505 ++#define TARGET_NR_sw_slave_rwperfmons 506 ++#define TARGET_NR_sys_get_vmflags 507 +diff --git a/linux-user/sw64/target_cpu.h b/linux-user/sw64/target_cpu.h +new file mode 100644 +index 0000000000..1b87c8ba6d +--- /dev/null ++++ b/linux-user/sw64/target_cpu.h +@@ -0,0 +1,38 @@ ++/* ++ * SW64 specific CPU ABI and functions for linux-user ++ * ++ * 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 . ++ */ ++#ifndef SW64_TARGET_CPU_H ++#define SW64_TARGET_CPU_H ++ ++static inline void cpu_clone_regs(CPUSW64State *env, target_ulong newsp) ++{ ++ if (newsp) { ++ env->ir[IDX_SP] = newsp; ++ } ++ env->ir[IDX_V0] = 0; ++ env->ir[IDX_A3] = 0; ++} ++ ++static inline void cpu_set_tls(CPUSW64State *env, target_ulong newtls) ++{ ++ env->unique = newtls; ++} ++ ++static inline abi_ulong get_sp_from_cpustate(CPUSW64State *state) ++{ ++ return state->ir[IDX_SP]; ++} ++#endif +diff --git a/linux-user/sw64/target_elf.h b/linux-user/sw64/target_elf.h +new file mode 100644 +index 0000000000..be48b6dee3 +--- /dev/null ++++ b/linux-user/sw64/target_elf.h +@@ -0,0 +1,14 @@ ++/* ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation, or (at your option) any ++ * later version. See the COPYING file in the top-level directory. ++ */ ++ ++#ifndef SW64_TARGET_ELF_H ++#define SW64_TARGET_ELF_H ++static inline const char *cpu_get_model(uint32_t eflags) ++{ ++ return "any"; ++} ++#endif +diff --git a/linux-user/sw64/target_fcntl.h b/linux-user/sw64/target_fcntl.h +new file mode 100644 +index 0000000000..9721e3de39 +--- /dev/null ++++ b/linux-user/sw64/target_fcntl.h +@@ -0,0 +1,11 @@ ++/* ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation, or (at your option) any ++ * later version. See the COPYING file in the top-level directory. ++ */ ++ ++#ifndef SW64_TARGET_FCNTL_H ++#define sw64_TARGET_FCNTL_H ++#include "../generic/fcntl.h" ++#endif +diff --git a/linux-user/sw64/target_signal.h b/linux-user/sw64/target_signal.h +new file mode 100644 +index 0000000000..6393a7542f +--- /dev/null ++++ b/linux-user/sw64/target_signal.h +@@ -0,0 +1,98 @@ ++#ifndef SW64_TARGET_SIGNAL_H ++#define SW64_TARGET_SIGNAL_H ++ ++#include "cpu.h" ++ ++#define TARGET_SIGHUP 1 ++#define TARGET_SIGINT 2 ++#define TARGET_SIGQUIT 3 ++#define TARGET_SIGILL 4 ++#define TARGET_SIGTRAP 5 ++#define TARGET_SIGABRT 6 ++#define TARGET_SIGSTKFLT 7 /* actually SIGEMT */ ++#define TARGET_SIGFPE 8 ++#define TARGET_SIGKILL 9 ++#define TARGET_SIGBUS 10 ++#define TARGET_SIGSEGV 11 ++#define TARGET_SIGSYS 12 ++#define TARGET_SIGPIPE 13 ++#define TARGET_SIGALRM 14 ++#define TARGET_SIGTERM 15 ++#define TARGET_SIGURG 16 ++#define TARGET_SIGSTOP 17 ++#define TARGET_SIGTSTP 18 ++#define TARGET_SIGCONT 19 ++#define TARGET_SIGCHLD 20 ++#define TARGET_SIGTTIN 21 ++#define TARGET_SIGTTOU 22 ++#define TARGET_SIGIO 23 ++#define TARGET_SIGXCPU 24 ++#define TARGET_SIGXFSZ 25 ++#define TARGET_SIGVTALRM 26 ++#define TARGET_SIGPROF 27 ++#define TARGET_SIGWINCH 28 ++#define TARGET_SIGPWR 29 /* actually SIGINFO */ ++#define TARGET_SIGUSR1 30 ++#define TARGET_SIGUSR2 31 ++#define TARGET_SIGRTMIN 32 ++ ++#define TARGET_SIG_BLOCK 1 ++#define TARGET_SIG_UNBLOCK 2 ++#define TARGET_SIG_SETMASK 3 ++ ++/* this struct defines a stack used during syscall handling */ ++ ++typedef struct target_sigaltstack { ++ abi_ulong ss_sp; ++ int32_t ss_flags; ++ int32_t dummy; ++ abi_ulong ss_size; ++} target_stack_t; ++ ++ ++/* ++ * sigaltstack controls ++ */ ++#define TARGET_SS_ONSTACK 1 ++#define TARGET_SS_DISABLE 2 ++ ++#define TARGET_SA_ONSTACK 0x00000001 ++#define TARGET_SA_RESTART 0x00000002 ++#define TARGET_SA_NOCLDSTOP 0x00000004 ++#define TARGET_SA_NODEFER 0x00000008 ++#define TARGET_SA_RESETHAND 0x00000010 ++#define TARGET_SA_NOCLDWAIT 0x00000020 /* not supported yet */ ++#define TARGET_SA_SIGINFO 0x00000040 ++ ++#define TARGET_MINSIGSTKSZ 4096 ++#define TARGET_SIGSTKSZ 16384 ++ ++/* From . */ ++#define TARGET_GEN_INTOVF -1 /* integer overflow */ ++#define TARGET_GEN_INTDIV -2 /* integer division by zero */ ++#define TARGET_GEN_FLTOVF -3 /* fp overflow */ ++#define TARGET_GEN_FLTDIV -4 /* fp division by zero */ ++#define TARGET_GEN_FLTUND -5 /* fp underflow */ ++#define TARGET_GEN_FLTINV -6 /* invalid fp operand */ ++#define TARGET_GEN_FLTINE -7 /* inexact fp operand */ ++#define TARGET_GEN_DECOVF -8 /* decimal overflow (for COBOL??) */ ++#define TARGET_GEN_DECDIV -9 /* decimal division by zero */ ++#define TARGET_GEN_DECINV -10 /* invalid decimal operand */ ++#define TARGET_GEN_ROPRAND -11 /* reserved operand */ ++#define TARGET_GEN_ASSERTERR -12 /* assertion error */ ++#define TARGET_GEN_NULPTRERR -13 /* null pointer error */ ++#define TARGET_GEN_STKOVF -14 /* stack overflow */ ++#define TARGET_GEN_STRLENERR -15 /* string length error */ ++#define TARGET_GEN_SUBSTRERR -16 /* substring error */ ++#define TARGET_GEN_RANGERR -17 /* range error */ ++#define TARGET_GEN_SUBRNG -18 ++#define TARGET_GEN_SUBRNG1 -19 ++#define TARGET_GEN_SUBRNG2 -20 ++#define TARGET_GEN_SUBRNG3 -21 ++#define TARGET_GEN_SUBRNG4 -22 ++#define TARGET_GEN_SUBRNG5 -23 ++#define TARGET_GEN_SUBRNG6 -24 ++#define TARGET_GEN_SUBRNG7 -25 ++ ++#define TARGET_ARCH_HAS_SETUP_FRAME ++#endif /* SW64_TARGET_SIGNAL_H */ +diff --git a/linux-user/sw64/target_structs.h b/linux-user/sw64/target_structs.h +new file mode 100644 +index 0000000000..7c13dc4bac +--- /dev/null ++++ b/linux-user/sw64/target_structs.h +@@ -0,0 +1,47 @@ ++/* ++ * SW64 specific structures for linux-user ++ * ++ * Copyright (c) 2018 Lin Hainan ++ * ++ * 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. ++ * ++ */ ++#ifndef SW64_TARGET_STRUCTS_H ++#define SW64_TARGET_STRUCTS_H ++ ++/* TODO: Maybe it should be update. now it's different from other arch */ ++struct target_ipc_perm { ++ abi_int __key; /* Key. */ ++ abi_uint uid; /* Owner's user ID. */ ++ abi_uint gid; /* Owner's group ID. */ ++ abi_uint cuid; /* Creator's user ID. */ ++ abi_uint cgid; /* Creator's group ID. */ ++ abi_uint mode; /* Read/write permission. */ ++ abi_ushort __seq; /* Sequence number. */ ++ abi_ushort __pad1; ++ abi_ulong __unused1; ++ abi_ulong __unused2; ++}; ++ ++struct target_shmid_ds { ++ struct target_ipc_perm shm_perm; /* operation permission struct */ ++ abi_long shm_segsz; /* size of segment in bytes */ ++ abi_ulong shm_atime; /* time of last shmat() */ ++ abi_ulong shm_dtime; /* time of last shmdt() */ ++ abi_ulong shm_ctime; /* time of last change by shmctl() */ ++ abi_int shm_cpid; /* pid of creator */ ++ abi_int shm_lpid; /* pid of last shmop */ ++ abi_ulong shm_nattch; /* number of current attaches */ ++ abi_ulong __unused1; ++ abi_ulong __unused2; ++}; ++ ++#endif +diff --git a/linux-user/sw64/target_syscall.h b/linux-user/sw64/target_syscall.h +new file mode 100644 +index 0000000000..c901ae95d8 +--- /dev/null ++++ b/linux-user/sw64/target_syscall.h +@@ -0,0 +1,121 @@ ++#ifndef SW64_TARGET_SYSCALL_H ++#define SW64_TARGET_SYSCALL_H ++ ++/* TODO */ ++struct target_pt_regs { ++ abi_ulong r0; ++ abi_ulong r1; ++ abi_ulong r2; ++ abi_ulong r3; ++ abi_ulong r4; ++ abi_ulong r5; ++ abi_ulong r6; ++ abi_ulong r7; ++ abi_ulong r8; ++ abi_ulong r19; ++ abi_ulong r20; ++ abi_ulong r21; ++ abi_ulong r22; ++ abi_ulong r23; ++ abi_ulong r24; ++ abi_ulong r25; ++ abi_ulong r26; ++ abi_ulong r27; ++ abi_ulong r28; ++ abi_ulong hae; ++/* JRP - These are the values provided to a0-a2 by HMcode */ ++ abi_ulong trap_a0; ++ abi_ulong trap_a1; ++ abi_ulong trap_a2; ++/* These are saved by HMcode: */ ++ abi_ulong ps; ++ abi_ulong pc; ++ abi_ulong gp; ++ abi_ulong r16; ++ abi_ulong r17; ++ abi_ulong r18; ++}; ++ ++#define TARGET_MLOCKALL_MCL_CURRENT 0x2000 ++#define TARGET_MLOCKALL_MCL_FUTURE 0x4000 ++ ++ ++#define UNAME_MACHINE "sw64" ++#define UNAME_MINIMUM_RELEASE "2.6.32" ++#undef TARGET_EOPNOTSUPP ++#define TARGET_EOPNOTSUPP 45 /* Operation not supported on transport endpoint */ ++#define SWCR_STATUS_INV0 (1UL<<17) ++#define SWCR_STATUS_DZE0 (1UL<<18) ++#define SWCR_STATUS_OVF0 (1UL<<19) ++#define SWCR_STATUS_UNF0 (1UL<<20) ++#define SWCR_STATUS_INE0 (1UL<<21) ++#define SWCR_STATUS_DNO0 (1UL<<22) ++ ++#define SWCR_STATUS_MASK0 (SWCR_STATUS_INV0 | SWCR_STATUS_DZE0 | \ ++ SWCR_STATUS_OVF0 | SWCR_STATUS_UNF0 | \ ++ SWCR_STATUS_INE0 | SWCR_STATUS_DNO0) ++ ++#define SWCR_STATUS0_TO_EXCSUM_SHIFT 16 ++ ++#define SWCR_STATUS_INV1 (1UL<<23) ++#define SWCR_STATUS_DZE1 (1UL<<24) ++#define SWCR_STATUS_OVF1 (1UL<<25) ++#define SWCR_STATUS_UNF1 (1UL<<26) ++#define SWCR_STATUS_INE1 (1UL<<27) ++#define SWCR_STATUS_DNO1 (1UL<<28) ++ ++#define SWCR_STATUS_MASK1 (SWCR_STATUS_INV1 | SWCR_STATUS_DZE1 | \ ++ SWCR_STATUS_OVF1 | SWCR_STATUS_UNF1 | \ ++ SWCR_STATUS_INE1 | SWCR_STATUS_DNO1) ++ ++#define SWCR_STATUS1_TO_EXCSUM_SHIFT 22 ++#define SWCR_STATUS_INV2 (1UL<<34) ++#define SWCR_STATUS_DZE2 (1UL<<35) ++#define SWCR_STATUS_OVF2 (1UL<<36) ++#define SWCR_STATUS_UNF2 (1UL<<37) ++#define SWCR_STATUS_INE2 (1UL<<38) ++#define SWCR_STATUS_DNO2 (1UL<<39) ++ ++#define SWCR_STATUS_MASK2 (SWCR_STATUS_INV2 | SWCR_STATUS_DZE2 | \ ++ SWCR_STATUS_OVF2 | SWCR_STATUS_UNF2 | \ ++ SWCR_STATUS_INE2 | SWCR_STATUS_DNO2) ++#define SWCR_STATUS_INV3 (1UL<<40) ++#define SWCR_STATUS_DZE3 (1UL<<41) ++#define SWCR_STATUS_OVF3 (1UL<<42) ++#define SWCR_STATUS_UNF3 (1UL<<43) ++#define SWCR_STATUS_INE3 (1UL<<44) ++#define SWCR_STATUS_DNO3 (1UL<<45) ++ ++#define SWCR_STATUS_MASK3 (SWCR_STATUS_INV3 | SWCR_STATUS_DZE3 | \ ++ SWCR_STATUS_OVF3 | SWCR_STATUS_UNF3 | \ ++ SWCR_STATUS_INE3 | SWCR_STATUS_DNO3) ++#define SWCR_TRAP_ENABLE_INV (1UL<<1) /* invalid op */ ++#define SWCR_TRAP_ENABLE_DZE (1UL<<2) /* division by zero */ ++#define SWCR_TRAP_ENABLE_OVF (1UL<<3) /* overflow */ ++#define SWCR_TRAP_ENABLE_UNF (1UL<<4) /* underflow */ ++#define SWCR_TRAP_ENABLE_INE (1UL<<5) /* inexact */ ++#define SWCR_TRAP_ENABLE_DNO (1UL<<6) /* denorm */ ++#define SWCR_TRAP_ENABLE_MASK (SWCR_TRAP_ENABLE_INV | SWCR_TRAP_ENABLE_DZE | \ ++ SWCR_TRAP_ENABLE_OVF | SWCR_TRAP_ENABLE_UNF | \ ++ SWCR_TRAP_ENABLE_INE | SWCR_TRAP_ENABLE_DNO) ++ ++/* Denorm and Underflow flushing */ ++#define SWCR_MAP_DMZ (1UL<<12) /* Map denorm inputs to zero */ ++#define SWCR_MAP_UMZ (1UL<<13) /* Map underflowed outputs to zero */ ++ ++#define SWCR_MAP_MASK (SWCR_MAP_DMZ | SWCR_MAP_UMZ) ++ ++/* status bits coming from fpcr: */ ++#define SWCR_STATUS_INV (1UL<<17) ++#define SWCR_STATUS_DZE (1UL<<18) ++#define SWCR_STATUS_OVF (1UL<<19) ++#define SWCR_STATUS_UNF (1UL<<20) ++#define SWCR_STATUS_INE (1UL<<21) ++#define SWCR_STATUS_DNO (1UL<<22) ++ ++#define SWCR_STATUS_MASK (SWCR_STATUS_INV | SWCR_STATUS_DZE | \ ++ SWCR_STATUS_OVF | SWCR_STATUS_UNF | \ ++ SWCR_STATUS_INE | SWCR_STATUS_DNO) ++#define TARGET_GSI_IEEE_FP_CONTROL 45 ++#define TARGET_SSI_IEEE_FP_CONTROL 14 ++#endif +diff --git a/linux-user/sw64/termbits.h b/linux-user/sw64/termbits.h +new file mode 100644 +index 0000000000..37dd77120c +--- /dev/null ++++ b/linux-user/sw64/termbits.h +@@ -0,0 +1,265 @@ ++typedef unsigned char target_cc_t; ++typedef unsigned int target_speed_t; ++typedef unsigned int target_tcflag_t; ++ ++#define TARGET_NCCS 19 ++struct target_termios { ++ target_tcflag_t c_iflag; /* input mode flags */ ++ target_tcflag_t c_oflag; /* output mode flags */ ++ target_tcflag_t c_cflag; /* control mode flags */ ++ target_tcflag_t c_lflag; /* local mode flags */ ++ target_cc_t c_cc[TARGET_NCCS]; /* control characters */ ++ target_cc_t c_line; /* line discipline (== c_cc[19]) */ ++ target_speed_t c_ispeed; /* input speed */ ++ target_speed_t c_ospeed; /* output speed */ ++}; ++ ++/* c_cc characters */ ++#define TARGET_VEOF 0 ++#define TARGET_VEOL 1 ++#define TARGET_VEOL2 2 ++#define TARGET_VERASE 3 ++#define TARGET_VWERASE 4 ++#define TARGET_VKILL 5 ++#define TARGET_VREPRINT 6 ++#define TARGET_VSWTC 7 ++#define TARGET_VINTR 8 ++#define TARGET_VQUIT 9 ++#define TARGET_VSUSP 10 ++#define TARGET_VSTART 12 ++#define TARGET_VSTOP 13 ++#define TARGET_VLNEXT 14 ++#define TARGET_VDISCARD 15 ++#define TARGET_VMIN 16 ++#define TARGET_VTIME 17 ++ ++/* c_iflag bits */ ++#define TARGET_IGNBRK 0000001 ++#define TARGET_BRKINT 0000002 ++#define TARGET_IGNPAR 0000004 ++#define TARGET_PARMRK 0000010 ++#define TARGET_INPCK 0000020 ++#define TARGET_ISTRIP 0000040 ++#define TARGET_INLCR 0000100 ++#define TARGET_IGNCR 0000200 ++#define TARGET_ICRNL 0000400 ++#define TARGET_IXON 0001000 ++#define TARGET_IXOFF 0002000 ++#define TARGET_IXANY 0004000 ++#define TARGET_IUCLC 0010000 ++#define TARGET_IMAXBEL 0020000 ++#define TARGET_IUTF8 0040000 ++ ++/* c_oflag bits */ ++#define TARGET_OPOST 0000001 ++#define TARGET_ONLCR 0000002 ++#define TARGET_OLCUC 0000004 ++ ++#define TARGET_OCRNL 0000010 ++#define TARGET_ONOCR 0000020 ++#define TARGET_ONLRET 0000040 ++ ++#define TARGET_OFILL 00000100 ++#define TARGET_OFDEL 00000200 ++#define TARGET_NLDLY 00001400 ++#define TARGET_NL0 00000000 ++#define TARGET_NL1 00000400 ++#define TARGET_NL2 00001000 ++#define TARGET_NL3 00001400 ++#define TARGET_TABDLY 00006000 ++#define TARGET_TAB0 00000000 ++#define TARGET_TAB1 00002000 ++#define TARGET_TAB2 00004000 ++#define TARGET_TAB3 00006000 ++#define TARGET_CRDLY 00030000 ++#define TARGET_CR0 00000000 ++#define TARGET_CR1 00010000 ++#define TARGET_CR2 00020000 ++#define TARGET_CR3 00030000 ++#define TARGET_FFDLY 00040000 ++#define TARGET_FF0 00000000 ++#define TARGET_FF1 00040000 ++#define TARGET_BSDLY 00100000 ++#define TARGET_BS0 00000000 ++#define TARGET_BS1 00100000 ++#define TARGET_VTDLY 00200000 ++#define TARGET_VT0 00000000 ++#define TARGET_VT1 00200000 ++#define TARGET_XTABS 01000000 /* Hmm.. Linux/i386 considers this part of TABDLY.. */ ++ ++/* c_cflag bit meaning */ ++#define TARGET_CBAUD 0000037 ++#define TARGET_B0 0000000 /* hang up */ ++#define TARGET_B50 0000001 ++#define TARGET_B75 0000002 ++#define TARGET_B110 0000003 ++#define TARGET_B134 0000004 ++#define TARGET_B150 0000005 ++#define TARGET_B200 0000006 ++#define TARGET_B300 0000007 ++#define TARGET_B600 0000010 ++#define TARGET_B1200 0000011 ++#define TARGET_B1800 0000012 ++#define TARGET_B2400 0000013 ++#define TARGET_B4800 0000014 ++#define TARGET_B9600 0000015 ++#define TARGET_B19200 0000016 ++#define TARGET_B38400 0000017 ++#define TARGET_EXTA B19200 ++#define TARGET_EXTB B38400 ++#define TARGET_CBAUDEX 0000000 ++#define TARGET_B57600 00020 ++#define TARGET_B115200 00021 ++#define TARGET_B230400 00022 ++#define TARGET_B460800 00023 ++#define TARGET_B500000 00024 ++#define TARGET_B576000 00025 ++#define TARGET_B921600 00026 ++#define TARGET_B1000000 00027 ++#define TARGET_B1152000 00030 ++#define TARGET_B1500000 00031 ++#define TARGET_B2000000 00032 ++#define TARGET_B2500000 00033 ++#define TARGET_B3000000 00034 ++#define TARGET_B3500000 00035 ++#define TARGET_B4000000 00036 ++ ++#define TARGET_CSIZE 00001400 ++#define TARGET_CS5 00000000 ++#define TARGET_CS6 00000400 ++#define TARGET_CS7 00001000 ++#define TARGET_CS8 00001400 ++ ++#define TARGET_CSTOPB 00002000 ++#define TARGET_CREAD 00004000 ++#define TARGET_PARENB 00010000 ++#define TARGET_PARODD 00020000 ++#define TARGET_HUPCL 00040000 ++ ++#define TARGET_CLOCAL 00100000 ++#define TARGET_CMSPAR 010000000000 /* mark or space (stick) parity */ ++#define TARGET_CRTSCTS 020000000000 /* flow control */ ++ ++/* c_lflag bits */ ++#define TARGET_ISIG 0x00000080 ++#define TARGET_ICANON 0x00000100 ++#define TARGET_XCASE 0x00004000 ++#define TARGET_ECHO 0x00000008 ++#define TARGET_ECHOE 0x00000002 ++#define TARGET_ECHOK 0x00000004 ++#define TARGET_ECHONL 0x00000010 ++#define TARGET_NOFLSH 0x80000000 ++#define TARGET_TOSTOP 0x00400000 ++#define TARGET_ECHOCTL 0x00000040 ++#define TARGET_ECHOPRT 0x00000020 ++#define TARGET_ECHOKE 0x00000001 ++#define TARGET_FLUSHO 0x00800000 ++#define TARGET_PENDIN 0x20000000 ++#define TARGET_IEXTEN 0x00000400 ++ ++#define TARGET_FIOCLEX TARGET_IO('f', 1) ++#define TARGET_FIONCLEX TARGET_IO('f', 2) ++#define TARGET_FIOASYNC TARGET_IOW('f', 125, int) ++#define TARGET_FIONBIO TARGET_IOW('f', 126, int) ++#define TARGET_FIONREAD TARGET_IOR('f', 127, int) ++#define TARGET_TIOCINQ FIONREAD ++#define TARGET_FIOQSIZE TARGET_IOR('f', 128, loff_t) ++ ++#define TARGET_TIOCGETP TARGET_IOR('t', 8, struct target_sgttyb) ++#define TARGET_TIOCSETP TARGET_IOW('t', 9, struct target_sgttyb) ++#define TARGET_TIOCSETN TARGET_IOW('t', 10, struct target_sgttyb) /* TIOCSETP wo flush */ ++ ++#define TARGET_TIOCSETC TARGET_IOW('t', 17, struct target_tchars) ++#define TARGET_TIOCGETC TARGET_IOR('t', 18, struct target_tchars) ++#define TARGET_TCGETS TARGET_IOR('t', 19, struct target_termios) ++#define TARGET_TCSETS TARGET_IOW('t', 20, struct target_termios) ++#define TARGET_TCSETSW TARGET_IOW('t', 21, struct target_termios) ++#define TARGET_TCSETSF TARGET_IOW('t', 22, struct target_termios) ++ ++#define TARGET_TCGETA TARGET_IOR('t', 23, struct target_termio) ++#define TARGET_TCSETA TARGET_IOW('t', 24, struct target_termio) ++#define TARGET_TCSETAW TARGET_IOW('t', 25, struct target_termio) ++#define TARGET_TCSETAF TARGET_IOW('t', 28, struct target_termio) ++ ++#define TARGET_TCSBRK TARGET_IO('t', 29) ++#define TARGET_TCXONC TARGET_IO('t', 30) ++#define TARGET_TCFLSH TARGET_IO('t', 31) ++ ++#define TARGET_TIOCSWINSZ TARGET_IOW('t', 103, struct target_winsize) ++#define TARGET_TIOCGWINSZ TARGET_IOR('t', 104, struct target_winsize) ++#define TARGET_TIOCSTART TARGET_IO('t', 110) /* start output, like ^Q */ ++#define TARGET_TIOCSTOP TARGET_IO('t', 111) /* stop output, like ^S */ ++#define TARGET_TIOCOUTQ TARGET_IOR('t', 115, int) /* output queue size */ ++ ++#define TARGET_TIOCGLTC TARGET_IOR('t', 116, struct target_ltchars) ++#define TARGET_TIOCSLTC TARGET_IOW('t', 117, struct target_ltchars) ++#define TARGET_TIOCSPGRP TARGET_IOW('t', 118, int) ++#define TARGET_TIOCGPGRP TARGET_IOR('t', 119, int) ++ ++#define TARGET_TIOCEXCL 0x540C ++#define TARGET_TIOCNXCL 0x540D ++#define TARGET_TIOCSCTTY 0x540E ++ ++#define TARGET_TIOCSTI 0x5412 ++#define TARGET_TIOCMGET 0x5415 ++#define TARGET_TIOCMBIS 0x5416 ++#define TARGET_TIOCMBIC 0x5417 ++#define TARGET_TIOCMSET 0x5418 ++# define TARGET_TIOCM_LE 0x001 ++# define TARGET_TIOCM_DTR 0x002 ++# define TARGET_TIOCM_RTS 0x004 ++# define TARGET_TIOCM_ST 0x008 ++# define TARGET_TIOCM_SR 0x010 ++# define TARGET_TIOCM_CTS 0x020 ++# define TARGET_TIOCM_CAR 0x040 ++# define TARGET_TIOCM_RNG 0x080 ++# define TARGET_TIOCM_DSR 0x100 ++# define TARGET_TIOCM_CD TIOCM_CAR ++# define TARGET_TIOCM_RI TIOCM_RNG ++# define TARGET_TIOCM_OUT1 0x2000 ++# define TARGET_TIOCM_OUT2 0x4000 ++# define TARGET_TIOCM_LOOP 0x8000 ++ ++#define TARGET_TIOCGSOFTCAR 0x5419 ++#define TARGET_TIOCSSOFTCAR 0x541A ++#define TARGET_TIOCLINUX 0x541C ++#define TARGET_TIOCCONS 0x541D ++#define TARGET_TIOCGSERIAL 0x541E ++#define TARGET_TIOCSSERIAL 0x541F ++#define TARGET_TIOCPKT 0x5420 ++# define TARGET_TIOCPKT_DATA 0 ++# define TARGET_TIOCPKT_FLUSHREAD 1 ++# define TARGET_TIOCPKT_FLUSHWRITE 2 ++# define TARGET_TIOCPKT_STOP 4 ++# define TARGET_TIOCPKT_START 8 ++# define TARGET_TIOCPKT_NOSTOP 16 ++# define TARGET_TIOCPKT_DOSTOP 32 ++ ++ ++#define TARGET_TIOCNOTTY 0x5422 ++#define TARGET_TIOCSETD 0x5423 ++#define TARGET_TIOCGETD 0x5424 ++#define TARGET_TCSBRKP 0x5425 /* Needed for POSIX tcsendbreak() */ ++#define TARGET_TIOCSBRK 0x5427 /* BSD compatibility */ ++#define TARGET_TIOCCBRK 0x5428 /* BSD compatibility */ ++#define TARGET_TIOCGSID 0x5429 /* Return the session ID of FD */ ++#define TARGET_TIOCGPTN TARGET_IOR('T', 0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ ++#define TARGET_TIOCSPTLCK TARGET_IOW('T', 0x31, int) /* Lock/unlock Pty */ ++#define TARGET_TIOCGPTPEER TARGET_IO('T', 0x41) /* Safely open the slave */ ++ ++#define TARGET_TIOCSERCONFIG 0x5453 ++#define TARGET_TIOCSERGWILD 0x5454 ++#define TARGET_TIOCSERSWILD 0x5455 ++#define TARGET_TIOCGLCKTRMIOS 0x5456 ++#define TARGET_TIOCSLCKTRMIOS 0x5457 ++#define TARGET_TIOCSERGSTRUCT 0x5458 /* For debugging only */ ++#define TARGET_TIOCSERGETLSR 0x5459 /* Get line status register */ ++ /* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */ ++# define TARGET_TIOCSER_TEMT 0x01 /* Transmitter physically empty */ ++#define TARGET_TIOCSERGETMULTI 0x545A /* Get multiport config */ ++#define TARGET_TIOCSERSETMULTI 0x545B /* Set multiport config */ ++ ++#define TARGET_TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */ ++#define TARGET_TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */ ++#define TARGET_TIOCGHAYESESP 0x545E /* Get Hayes ESP configuration */ ++#define TARGET_TIOCSHAYESESP 0x545F /* Set Hayes ESP configuration */ +diff --git a/meson.build b/meson.build +index 96de1a6ef9..d0bbceffe1 100644 +--- a/meson.build ++++ b/meson.build +@@ -56,7 +56,7 @@ python = import('python').find_installation() + + supported_oses = ['windows', 'freebsd', 'netbsd', 'openbsd', 'darwin', 'sunos', 'linux'] + supported_cpus = ['ppc', 'ppc64', 's390x', 'riscv', 'x86', 'x86_64', +- 'arm', 'aarch64', 'mips', 'mips64', 'sparc', 'sparc64'] ++ 'arm', 'aarch64', 'mips', 'mips64', 'sparc', 'sparc64', 'sw64'] + + cpu = host_machine.cpu_family() + +@@ -65,6 +65,10 @@ if cpu in ['riscv32', 'riscv64'] + cpu = 'riscv' + endif + ++if cpu == 'sw_64' ++ cpu = 'sw64' ++endif ++ + targetos = host_machine.system() + + if cpu in ['x86', 'x86_64'] +@@ -77,6 +81,8 @@ elif cpu in ['ppc', 'ppc64'] + kvm_targets = ['ppc-softmmu', 'ppc64-softmmu'] + elif cpu in ['mips', 'mips64'] + kvm_targets = ['mips-softmmu', 'mipsel-softmmu', 'mips64-softmmu', 'mips64el-softmmu'] ++elif cpu == 'sw64' ++ kvm_targets = ['sw64-softmmu'] + else + kvm_targets = [] + endif +@@ -359,6 +365,8 @@ if not get_option('tcg').disabled() + tcg_arch = 'i386' + elif config_host['ARCH'] == 'ppc64' + tcg_arch = 'ppc' ++ elif config_host['ARCH'] in ['sw64'] ++ tcg_arch = 'sw64' + endif + add_project_arguments('-iquote', meson.current_source_dir() / 'tcg' / tcg_arch, + language: ['c', 'cpp', 'objc']) +@@ -1814,6 +1822,7 @@ disassemblers = { + 'sh4' : ['CONFIG_SH4_DIS'], + 'sparc' : ['CONFIG_SPARC_DIS'], + 'xtensa' : ['CONFIG_XTENSA_DIS'], ++ 'sw64' : ['CONFIG_SW64_DIS'], + } + if link_language == 'cpp' + disassemblers += { +@@ -2466,6 +2475,7 @@ if have_system + 'hw/sparc', + 'hw/sparc64', + 'hw/ssi', ++ 'hw/sw64', + 'hw/timer', + 'hw/tpm', + 'hw/usb', +diff --git a/pc-bios/meson.build b/pc-bios/meson.build +index b40ff3f2bd..05e9065ad6 100644 +--- a/pc-bios/meson.build ++++ b/pc-bios/meson.build +@@ -38,6 +38,9 @@ blobs = files( + 'vgabios-ramfb.bin', + 'vgabios-bochs-display.bin', + 'vgabios-ati.bin', ++ 'uefi-bios-sw', ++ 'core3-reset', ++ 'core3-hmcode', + 'openbios-sparc32', + 'openbios-sparc64', + 'openbios-ppc', +diff --git a/qapi/machine.json b/qapi/machine.json +index 6822cafe2e..6ed8488255 100644 +--- a/qapi/machine.json ++++ b/qapi/machine.json +@@ -29,7 +29,7 @@ + # Since: 3.0 + ## + { 'enum' : 'SysEmuTarget', +- 'data' : [ 'aarch64', 'alpha', 'arm', 'avr', 'cris', 'hppa', 'i386', ++ 'data' : [ 'aarch64', 'alpha', 'sw64', 'arm', 'avr', 'cris', 'hppa', 'i386', + 'm68k', 'microblaze', 'microblazeel', 'mips', 'mips64', + 'mips64el', 'mipsel', 'nios2', 'or1k', 'ppc', + 'ppc64', 'riscv32', 'riscv64', 'rx', 's390x', 'sh4', +diff --git a/softmmu/qdev-monitor.c b/softmmu/qdev-monitor.c +index 05e1d88d99..142352b24e 100644 +--- a/softmmu/qdev-monitor.c ++++ b/softmmu/qdev-monitor.c +@@ -61,7 +61,8 @@ typedef struct QDevAlias + QEMU_ARCH_HPPA | QEMU_ARCH_I386 | \ + QEMU_ARCH_MIPS | QEMU_ARCH_PPC | \ + QEMU_ARCH_RISCV | QEMU_ARCH_SH4 | \ +- QEMU_ARCH_SPARC | QEMU_ARCH_XTENSA) ++ QEMU_ARCH_SPARC | QEMU_ARCH_XTENSA | \ ++ QEMU_ARCH_SW64) + #define QEMU_ARCH_VIRTIO_CCW (QEMU_ARCH_S390X) + #define QEMU_ARCH_VIRTIO_MMIO (QEMU_ARCH_M68K) + +diff --git a/target/Kconfig b/target/Kconfig +index ae7f24fc66..a8d6cb1e97 100644 +--- a/target/Kconfig ++++ b/target/Kconfig +@@ -17,3 +17,4 @@ source sh4/Kconfig + source sparc/Kconfig + source tricore/Kconfig + source xtensa/Kconfig ++source sw64/Kconfig +diff --git a/target/meson.build b/target/meson.build +index 2f6940255e..ec6bc97331 100644 +--- a/target/meson.build ++++ b/target/meson.build +@@ -16,5 +16,6 @@ subdir('rx') + subdir('s390x') + subdir('sh4') + subdir('sparc') ++subdir('sw64') + subdir('tricore') + subdir('xtensa') +diff --git a/target/sw64/Kconfig b/target/sw64/Kconfig +new file mode 100644 +index 0000000000..ad50b9677e +--- /dev/null ++++ b/target/sw64/Kconfig +@@ -0,0 +1,2 @@ ++config SW64 ++ bool +diff --git a/target/sw64/Makefile.objs b/target/sw64/Makefile.objs +new file mode 100644 +index 0000000000..1e549d141c +--- /dev/null ++++ b/target/sw64/Makefile.objs +@@ -0,0 +1,4 @@ ++obj-$(CONFIG_SOFTMMU) += machine.o ++obj-y += cpu.o translate.o profile.o helper.o ++obj-y += int_helper.o float_helper.o simd_helper.o helper.o exception.o ++obj-$(CONFIG_KVM) += kvm.o +diff --git a/target/sw64/cpu-param.h b/target/sw64/cpu-param.h +new file mode 100644 +index 0000000000..978a3cd572 +--- /dev/null ++++ b/target/sw64/cpu-param.h +@@ -0,0 +1,24 @@ ++/* ++ * SW64 cpu parameters for qemu. ++ * ++ * Copyright (c) 2018 Lin Hainan ++ */ ++ ++#ifndef SW64_CPU_PARAM_H ++#define SW64_CPU_PARAM_H 1 ++ ++#define TARGET_LONG_BITS 64 /* if use th-1 ,TARGET_PAGE_BITS is 12 */ ++#define TARGET_PAGE_BITS 13 ++ ++#ifdef CONFIG_USER_ONLY ++#define TARGET_VIRT_ADDR_SPACE_BITS 64 ++#else ++#define TARGET_PHYS_ADDR_SPACE_BITS 48 ++#define TARGET_VIRT_ADDR_SPACE_BITS 64 ++#endif ++ ++#ifndef CONFIG_USER_ONLY ++#define NB_MMU_MODES 4 ++#endif ++ ++#endif +diff --git a/target/sw64/cpu-qom.h b/target/sw64/cpu-qom.h +new file mode 100644 +index 0000000000..b093c2bec8 +--- /dev/null ++++ b/target/sw64/cpu-qom.h +@@ -0,0 +1,47 @@ ++/* ++ * QEMU SW64 CPU ++ * ++ * Copyright (c) 2018 Lin Hainan ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * as published by the Free Software Foundation; either version 2 ++ * of the License, or (at your option) any later version. ++ * ++ * This program 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 General Public License for more details. ++ * ++ */ ++#ifndef QEMU_SW64_CPU_QOM ++#define QEMU_SW64_CPU_QOM ++ ++#include "hw/core/cpu.h" ++ ++#define TYPE_SW64_CPU "sw64-cpu" ++ ++#define SW64_CPU_CLASS(kclass) \ ++ OBJECT_CLASS_CHECK(SW64CPUClass, (kclass), TYPE_SW64_CPU) ++#define SW64_CPU(obj) \ ++ OBJECT_CHECK(SW64CPU, (obj), TYPE_SW64_CPU) ++#define SW64_CPU_GET_CLASS(obj) \ ++ OBJECT_GET_CLASS(SW64CPUClass, (obj), TYPE_SW64_CPU) ++ ++/** ++ * SW64CPUClass: ++ * @parent_realize: The parent class' realize handler. ++ * @parent_reset: The parent class' reset handler. ++ * ++ * An SW64 CPU model. ++ */ ++typedef struct SW64CPUClass { ++ /* private */ ++ CPUClass parent_class; ++ /* public */ ++ DeviceRealize parent_realize; ++ DeviceReset parent_reset; ++} SW64CPUClass; ++ ++typedef struct SW64CPU SW64CPU; ++#endif +diff --git a/target/sw64/cpu.c b/target/sw64/cpu.c +new file mode 100644 +index 0000000000..89c21850e1 +--- /dev/null ++++ b/target/sw64/cpu.c +@@ -0,0 +1,457 @@ ++/* ++ * QEMU SW64 CPU ++ * ++ * Copyright (c) 2018 Lin Hainan ++ * ++ * 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. ++ * ++ */ ++ ++#include "qemu/osdep.h" ++#include "qapi/error.h" ++#include "qemu/qemu-print.h" ++#include "cpu.h" ++#include "exec/exec-all.h" ++#include "sysemu/kvm.h" ++#include "disas/dis-asm.h" ++#include "kvm_sw64.h" ++#include "sysemu/reset.h" ++#include "hw/qdev-properties.h" ++ ++ ++static void sw64_cpu_set_pc(CPUState *cs, vaddr value) ++{ ++ SW64CPU *cpu = SW64_CPU(cs); ++ ++ cpu->env.pc = value; ++} ++ ++static void sw64_cpu_dump_state(CPUState *cs, FILE *f, int flags) ++{ ++#ifndef CONFIG_KVM ++ SW64CPU *cpu = SW64_CPU(cs); ++ CPUSW64State *env = &cpu->env; ++ int i; ++ ++ static const char ireg_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[128][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", "f31", "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", "f31", "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", "f31", "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", "f31"}; ++ qemu_fprintf(f, "PC=%016" PRIx64 " SP=%016" PRIx64 "\n", env->pc, ++ env->ir[IDX_SP]); ++ for (i = 0; i < 31; i++) { ++ qemu_fprintf(f, "%s=%016" PRIx64, ireg_names[i], env->ir[i]); ++ if ((i % 4) == 3) { ++ qemu_fprintf(f, "\n"); ++ } else { ++ qemu_fprintf(f, " "); ++ } ++ } ++ qemu_fprintf(f, "\n"); ++#ifndef CONFIG_USER_ONLY ++ static const char sreg_names[10][4] = {"p1", "p2", "p4", "p5", "p6", ++ "p7", "p20", "p21", "p22", "p23"}; ++ for (i = 0; i < 10; i++) { ++ qemu_fprintf(f, "%s=%016" PRIx64, sreg_names[i], env->sr[i]); ++ if ((i % 4) == 3) { ++ qemu_fprintf(f, "\n"); ++ } else { ++ qemu_fprintf(f, " "); ++ } ++ } ++ qemu_fprintf(f, "\n"); ++#endif ++ for (i = 0; i < 32; i++) { ++ qemu_fprintf(f, "%s=%016" PRIx64, freg_names[i + 96], env->fr[i + 96]); ++ qemu_fprintf(f, " %016" PRIx64, env->fr[i + 64]); ++ qemu_fprintf(f, " %016" PRIx64, env->fr[i + 32]); ++ qemu_fprintf(f, " %016" PRIx64, env->fr[i]); ++ qemu_fprintf(f, "\n"); ++ } ++ qemu_fprintf(f, "\n"); ++#endif ++} ++ ++#ifndef CONFIG_USER_ONLY ++static void sw64_machine_cpu_reset(void *opaque) ++{ ++ SW64CPU *cpu = opaque; ++ ++ cpu_reset(CPU(cpu)); ++} ++#endif ++ ++static void sw64_cpu_realizefn(DeviceState *dev, Error **errp) ++{ ++ CPUState *cs = CPU(dev); ++ SW64CPUClass *scc = SW64_CPU_GET_CLASS(dev); ++ Error *local_err = NULL; ++ ++ cpu_exec_realizefn(cs, &local_err); ++ if (local_err != NULL) { ++ error_propagate(errp, local_err); ++ return; ++ } ++#ifndef CONFIG_USER_ONLY ++ qemu_register_reset(sw64_machine_cpu_reset, cs); ++#endif ++ ++ qemu_init_vcpu(cs); ++ ++ scc->parent_realize(dev, errp); ++} ++ ++static void sw64_cpu_disas_set_info(CPUState *cs, disassemble_info *info) ++{ ++ info->mach = bfd_mach_sw_64_core3; ++ info->print_insn = print_insn_sw_64; ++} ++ ++#include "fpu/softfloat.h" ++ ++static void core3_init(Object *obj) ++{ ++ CPUState *cs = CPU(obj); ++ CPUSW64State *env = cs->env_ptr; ++#ifdef CONFIG_USER_ONLY ++ env->fpcr = 0x680e800000000000; ++ parallel_cpus = true; ++#endif ++ set_feature(env, SW64_FEATURE_CORE3); ++} ++ ++static ObjectClass *sw64_cpu_class_by_name(const char *cpu_model) ++{ ++ ObjectClass *oc; ++ char *typename; ++ char **cpuname; ++ ++ cpuname = g_strsplit(cpu_model, ",", 1); ++ typename = g_strdup_printf(SW64_CPU_TYPE_NAME("%s"), cpu_model); ++ ++ oc = object_class_by_name(typename); ++ g_strfreev(cpuname); ++ g_free(typename); ++ ++ if (oc && object_class_dynamic_cast(oc, TYPE_SW64_CPU) && ++ !object_class_is_abstract(oc)) { ++ return oc; ++ } ++ return NULL; ++} ++ ++bool sw64_cpu_has_work(CPUState *cs) ++{ ++ /* If CPU has gotten into asleep(halt), then it may be ++ * wake up by hard interrupt, timer, ii, mail or mchk. ++ */ ++ return cs->interrupt_request & (CPU_INTERRUPT_HARD | CPU_INTERRUPT_TIMER | ++ CPU_INTERRUPT_IIMAIL | CPU_INTERRUPT_MCHK); ++} ++ ++static void sw64_cpu_initfn(Object *obj) ++{ ++ CPUState *cs = CPU(obj); ++ SW64CPU *cpu = SW64_CPU(obj); ++ CPUSW64State *env = &cpu->env; ++ ++ cpu_set_cpustate_pointers(cpu); ++ ++ cs->env_ptr = env; ++#ifndef CONFIG_USER_ONLY ++ env->flags = ENV_FLAG_HM_MODE; ++#else ++ env->flags = ENV_FLAG_PS_USER; ++#endif ++ tlb_flush(cs); ++} ++ ++#ifndef CONFIG_USER_ONLY ++static void sw64_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr, vaddr addr, ++ unsigned size, MMUAccessType access_type, ++ int mmu_idx, MemTxAttrs attrs, ++ MemTxResult response, uintptr_t retaddr) ++{ ++#ifdef DEBUG_TRANS ++ if (retaddr) { ++ cpu_restore_state(cs, retaddr, true); ++ } ++ fprintf(stderr, "PC = %lx, Wrong IO addr. Hwaddr = %lx, vaddr = %lx, access_type = %d\n", ++ env->pc, physaddr, addr, access_type); ++#endif ++} ++#endif ++ ++#define a0(func) (((func & 0xFF) >> 6) & 0x1) ++#define a1(func) ((((func & 0xFF) >> 6) & 0x2) >> 1) ++ ++#define t(func) ((a0(func) ^ a1(func)) & 0x1) ++#define b0(func) (t(func) | a0(func)) ++#define b1(func) ((~t(func) & 1) | a1(func)) ++ ++#define START_SYS_CALL_ADDR(func) \ ++ (b1(func) << 14) | (b0(func) << 13) | ((func & 0x3F) << 7) ++ ++static void sw64_cpu_do_interrupt(CPUState *cs) ++{ ++ int i = cs->exception_index; ++ ++ cs->exception_index = -1; ++#if !defined(CONFIG_USER_ONLY) ++ SW64CPU *cpu = SW64_CPU(cs); ++ CPUSW64State *env = &cpu->env; ++ switch (i) { ++ case EXCP_OPCDEC: ++ cpu_abort(cs, "ILLEGAL INSN"); ++ break; ++ case EXCP_CALL_SYS: ++ i = START_SYS_CALL_ADDR(env->error_code); ++ if (i <= 0x3F) { ++ i += 0x4000; ++ } else if (i >= 0x40 && i <= 0x7F) { ++ i += 0x2000; ++ } else if (i >= 0x80 && i <= 0x8F) { ++ i += 0x6000; ++ } ++ break; ++ case EXCP_ARITH: ++ env->error_code = -1; ++ env->csr[EXC_PC] = env->pc - 4; ++ env->csr[EXC_SUM] = 1; ++ i = 0xB80; ++ break; ++ case EXCP_UNALIGN: ++ i = 0xB00; ++ env->csr[EXC_PC] = env->pc - 4; ++ break; ++ case EXCP_CLK_INTERRUPT: ++ case EXCP_DEV_INTERRUPT: ++ i = 0xE80; ++ break; ++ case EXCP_MMFAULT: ++ i = 0x980; ++ env->csr[EXC_PC] = env->pc; ++ break; ++ case EXCP_IIMAIL: ++ env->csr[EXC_PC] = env->pc; ++ i = 0xE00; ++ break; ++ default: ++ break; ++ } ++ env->pc = env->hm_entry + i; ++ env->flags = ENV_FLAG_HM_MODE; ++#else ++ switch (i) { ++ case EXCP_OPCDEC: ++ cpu_abort(cs, "ILLEGAL INSN"); ++ break; ++ case EXCP_CALL_SYS: ++ default: ++ break; ++ } ++#endif ++} ++ ++#ifndef CONFIG_USER_ONLY ++static bool sw64_cpu_exec_interrupt(CPUState *cs, int interrupt_request) ++{ ++ SW64CPU *cpu = SW64_CPU(cs); ++ CPUSW64State *env = &cpu->env; ++ int idx = -1; ++ /* We never take interrupts while in Hardmode. */ ++ if (env->flags & ENV_FLAG_HM_MODE) ++ return false; ++ ++ if (interrupt_request & CPU_INTERRUPT_IIMAIL) { ++ idx = EXCP_IIMAIL; ++ env->csr[INT_STAT] |= 1UL << 6; ++ if ((env->csr[IER] & env->csr[INT_STAT]) == 0) ++ return false; ++ cs->interrupt_request &= ~CPU_INTERRUPT_IIMAIL; ++ goto done; ++ } ++ ++ if (interrupt_request & CPU_INTERRUPT_TIMER) { ++ idx = EXCP_CLK_INTERRUPT; ++ env->csr[INT_STAT] |= 1UL << 4; ++ if ((env->csr[IER] & env->csr[INT_STAT]) == 0) ++ return false; ++ cs->interrupt_request &= ~CPU_INTERRUPT_TIMER; ++ goto done; ++ } ++ ++ if (interrupt_request & CPU_INTERRUPT_HARD) { ++ idx = EXCP_DEV_INTERRUPT; ++ env->csr[INT_STAT] |= 1UL << 12; ++ if ((env->csr[IER] & env->csr[INT_STAT]) == 0) ++ return false; ++ cs->interrupt_request &= ~CPU_INTERRUPT_HARD; ++ goto done; ++ } ++ ++ if (interrupt_request & CPU_INTERRUPT_PCIE) { ++ idx = EXCP_DEV_INTERRUPT; ++ env->csr[INT_STAT] |= 1UL << 1; ++ env->csr[INT_PCI_INT] = 0x10; ++ if ((env->csr[IER] & env->csr[INT_STAT]) == 0) ++ return false; ++ cs->interrupt_request &= ~CPU_INTERRUPT_PCIE; ++ goto done; ++ } ++ ++done: ++ if (idx >= 0) { ++ cs->exception_index = idx; ++ env->error_code = 0; ++ env->csr[EXC_PC] = env->pc; ++ sw64_cpu_do_interrupt(cs); ++ return true; ++ } ++ return false; ++} ++#endif ++ ++static void sw64_cpu_reset(DeviceState *dev) ++{ ++ CPUState *s = CPU(dev); ++ SW64CPU *cpu = SW64_CPU(s); ++ SW64CPUClass *scc = SW64_CPU_GET_CLASS(cpu); ++ ++ scc->parent_reset(dev); ++ ++#ifndef CONFIG_USER_ONLY ++ if (kvm_enabled()) { ++ kvm_sw64_reset_vcpu(cpu); ++ } ++#endif ++} ++ ++static Property sw64_cpu_properties[] = { ++#ifdef CONFIG_USER_ONLY ++ /* apic_id = 0 by default for *-user, see commit 9886e834 */ ++ DEFINE_PROP_UINT32("cid", SW64CPU, cid, 0), ++#else ++ DEFINE_PROP_UINT32("cid", SW64CPU, cid, 0xFFFFFFFF), ++#endif ++ DEFINE_PROP_END_OF_LIST() ++}; ++ ++#ifndef CONFIG_USER_ONLY ++#include "hw/core/sysemu-cpu-ops.h" ++ ++static const struct SysemuCPUOps sw64_sysemu_ops = { ++ .get_phys_page_debug = sw64_cpu_get_phys_page_debug, ++}; ++#endif ++ ++#include "hw/core/tcg-cpu-ops.h" ++ ++static const struct TCGCPUOps sw64_tcg_ops = { ++#ifdef CONFIG_TCG ++ .initialize = sw64_translate_init, ++ .tlb_fill = sw64_cpu_tlb_fill, ++#endif /* CONFIG_TCG */ ++ ++#if !defined(CONFIG_USER_ONLY) ++ .do_unaligned_access = sw64_cpu_do_unaligned_access, ++ .cpu_exec_interrupt = sw64_cpu_exec_interrupt, ++ .do_transaction_failed = sw64_cpu_do_transaction_failed, ++#endif /* !CONFIG_USER_ONLY */ ++ .do_interrupt = sw64_cpu_do_interrupt, ++}; ++ ++static void sw64_cpu_class_init(ObjectClass *oc, void *data) ++{ ++ DeviceClass *dc = DEVICE_CLASS(oc); ++ CPUClass *cc = CPU_CLASS(oc); ++ SW64CPUClass *scc = SW64_CPU_CLASS(oc); ++ ++ device_class_set_parent_realize(dc, sw64_cpu_realizefn, ++ &scc->parent_realize); ++ device_class_set_parent_reset(dc, sw64_cpu_reset, &scc->parent_reset); ++ device_class_set_props(dc, sw64_cpu_properties); ++ ++ cc->class_by_name = sw64_cpu_class_by_name; ++ dc->vmsd = &vmstate_sw64_cpu; ++ cc->has_work = sw64_cpu_has_work; ++ cc->set_pc = sw64_cpu_set_pc; ++ cc->disas_set_info = sw64_cpu_disas_set_info; ++ cc->dump_state = sw64_cpu_dump_state; ++ cc->tcg_ops = &sw64_tcg_ops; ++#ifndef CONFIG_USER_ONLY ++ cc->sysemu_ops = &sw64_sysemu_ops; ++#endif ++} ++ ++static const SW64CPUInfo sw64_cpus[] = ++{ ++ { ++ .name = "core3", ++ .initfn = core3_init, ++ }, ++ { ++ .name = NULL ++ }, ++}; ++ ++static void cpu_register(const SW64CPUInfo *info) ++{ ++ TypeInfo type_info = { ++ .parent = TYPE_SW64_CPU, ++ .instance_size = sizeof(SW64CPU), ++ .instance_init = info->initfn, ++ .class_size = sizeof(SW64CPUClass), ++ .class_init = info->class_init, ++ }; ++ ++ type_info.name = g_strdup_printf("%s-" TYPE_SW64_CPU, info->name); ++ type_register(&type_info); ++ g_free((void*)type_info.name); ++} ++ ++static const TypeInfo sw64_cpu_type_info = { ++ .name = TYPE_SW64_CPU, ++ .parent = TYPE_CPU, ++ .instance_size = sizeof(SW64CPU), ++ .instance_init = sw64_cpu_initfn, ++ .abstract = true, ++ .class_size = sizeof(SW64CPUClass), ++ .class_init = sw64_cpu_class_init, ++}; ++ ++static void sw64_cpu_register_types(void) ++{ ++ const SW64CPUInfo *info = sw64_cpus; ++ ++ type_register_static(&sw64_cpu_type_info); ++ ++ while (info->name) { ++ cpu_register(info); ++ info++; ++ } ++} ++ ++type_init(sw64_cpu_register_types) +diff --git a/target/sw64/cpu.h b/target/sw64/cpu.h +new file mode 100644 +index 0000000000..5a490e2b4a +--- /dev/null ++++ b/target/sw64/cpu.h +@@ -0,0 +1,406 @@ ++/* ++ * SW64 emulation cpu definitions for qemu. ++ * ++ * Copyright (c) 2018 Lin Hainan ++ * ++ * 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. ++ * ++ */ ++#ifndef SW64_CPU_H ++#define SW64_CPU_H ++ ++#include "cpu-qom.h" ++#include "fpu/softfloat.h" ++#include "profile.h" ++ ++/* QEMU addressing/paging config */ ++#define TARGET_PAGE_BITS 13 ++#define TARGET_LONG_BITS 64 ++#define TARGET_LEVEL_BITS 10 ++//#define ALIGNED_ONLY ++ ++#include "exec/cpu-defs.h" ++ ++/* FIXME: LOCKFIX */ ++#define SW64_FIXLOCK 1 ++ ++/* swcore processors have a weak memory model */ ++#define TCG_GUEST_DEFAULT_MO (0) ++ ++#define SOFTMMU 1 ++ ++#ifndef CONFIG_USER_ONLY ++#define MMU_MODE0_SUFFIX _phys ++#define MMU_MODE3_SUFFIX _user ++#define MMU_MODE2_SUFFIX _kernel ++#endif ++#define MMU_PHYS_IDX 0 ++#define MMU_KERNEL_IDX 2 ++#define MMU_USER_IDX 3 ++ ++/* FIXME:Bits 4 and 5 are the mmu mode. The VMS hmcode uses all 4 modes; ++ The Unix hmcode only uses bit 4. */ ++#define PS_USER_MODE 8u ++ ++#define ENV_FLAG_HM_SHIFT 0 ++#define ENV_FLAG_PS_SHIFT 8 ++#define ENV_FLAG_FEN_SHIFT 24 ++ ++#define ENV_FLAG_HM_MODE (1u << ENV_FLAG_HM_SHIFT) ++#define ENV_FLAG_PS_USER (PS_USER_MODE << ENV_FLAG_PS_SHIFT) ++#define ENV_FLAG_FEN (1u << ENV_FLAG_FEN_SHIFT) ++ ++#define MCU_CLOCK 25000000 ++ ++typedef struct CPUSW64State CPUSW64State; ++typedef CPUSW64State CPUArchState; ++typedef SW64CPU ArchCPU; ++ ++struct CPUSW64State { ++ uint64_t ir[32]; ++ uint64_t fr[128]; ++ uint64_t pc; ++ bool is_slave; ++ ++ uint64_t csr[0x100]; ++ uint64_t fpcr; ++ uint64_t fpcr_exc_enable; ++ uint8_t fpcr_round_mode; ++ uint8_t fpcr_flush_to_zero; ++ ++ float_status fp_status; ++ ++ uint64_t hm_entry; ++ ++#if !defined(CONFIG_USER_ONLY) ++ uint64_t sr[10]; /* shadow regs 1,2,4-7,20-23 */ ++#endif ++ ++ uint32_t flags; ++ uint64_t error_code; ++ uint64_t unique; ++ uint64_t lock_addr; ++ uint64_t lock_valid; ++ uint64_t lock_flag; ++ uint64_t lock_success; ++#ifdef SW64_FIXLOCK ++ uint64_t lock_value; ++#endif ++ ++ uint64_t trap_arg0; ++ uint64_t trap_arg1; ++ uint64_t trap_arg2; ++ ++ uint64_t features; ++ uint64_t insn_count[537]; ++ ++ /* reserve for slave */ ++ uint64_t ca[4]; ++ uint64_t scala_gpr[64]; ++ uint64_t vec_gpr[224]; ++ uint64_t fpcr_base; ++ uint64_t fpcr_ext; ++ uint64_t pendding_flag; ++ uint64_t pendding_status; ++ uint64_t synr_pendding_status; ++ uint64_t sync_pendding_status; ++ uint8_t vlenma_idxa; ++ uint8_t stable; ++}; ++#define SW64_FEATURE_CORE3 0x2 ++ ++static inline void set_feature(CPUSW64State *env, int feature) ++{ ++ env->features |= feature; ++} ++ ++/** ++ * SW64CPU: ++ * @env: #CPUSW64State ++ * ++ * An SW64 CPU ++ */ ++struct SW64CPU { ++ /*< private >*/ ++ CPUState parent_obj; ++ /*< public >*/ ++ CPUNegativeOffsetState neg; ++ CPUSW64State env; ++ ++ uint64_t k_regs[158]; ++ uint64_t k_vcb[36]; ++ QEMUTimer *alarm_timer; ++ target_ulong irq; ++ uint32_t cid; ++}; ++ ++enum { ++ IDX_V0 = 0, ++ IDX_T0 = 1, ++ IDX_T1 = 2, ++ IDX_T2 = 3, ++ IDX_T3 = 4, ++ IDX_T4 = 5, ++ IDX_T5 = 6, ++ IDX_T6 = 7, ++ IDX_T7 = 8, ++ IDX_S0 = 9, ++ IDX_S1 = 10, ++ IDX_S2 = 11, ++ IDX_S3 = 12, ++ IDX_S4 = 13, ++ IDX_S5 = 14, ++ IDX_S6 = 15, ++ IDX_FP = IDX_S6, ++ IDX_A0 = 16, ++ IDX_A1 = 17, ++ IDX_A2 = 18, ++ IDX_A3 = 19, ++ IDX_A4 = 20, ++ IDX_A5 = 21, ++ IDX_T8 = 22, ++ IDX_T9 = 23, ++ IDX_T10 = 24, ++ IDX_T11 = 25, ++ IDX_RA = 26, ++ IDX_T12 = 27, ++ IDX_PV = IDX_T12, ++ IDX_AT = 28, ++ IDX_GP = 29, ++ IDX_SP = 30, ++ IDX_ZERO = 31, ++}; ++ ++enum { ++ MM_K_TNV = 0x0, ++ MM_K_ACV = 0x1, ++ MM_K_FOR = 0x2, ++ MM_K_FOE = 0x3, ++ MM_K_FOW = 0x4 ++}; ++ ++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, ++ PTE_KS = 0x0010, ++ PTE_PSE = 0x0040, ++ PTE_GH = 0x0060, ++ PTE_HRE = 0x0100, ++ PTE_VRE = 0x0200, ++ PTE_KRE = 0x0400, ++ PTE_URE = 0x0800, ++ PTE_HWE = 0x1000, ++ PTE_VWE = 0x2000, ++ PTE_KWE = 0x4000, ++ PTE_UWE = 0x8000 ++}; ++ ++static inline int cpu_mmu_index(CPUSW64State *env, bool ifetch) ++{ ++ int ret = env->flags & ENV_FLAG_PS_USER ? MMU_USER_IDX : MMU_KERNEL_IDX; ++ if (env->flags & ENV_FLAG_HM_MODE) { ++ ret = MMU_PHYS_IDX; ++ } ++ return ret; ++} ++ ++static inline SW64CPU *sw64_env_get_cpu(CPUSW64State *env) ++{ ++ return container_of(env, SW64CPU, env); ++} ++ ++#define ENV_GET_CPU(e) CPU(sw64_env_get_cpu(e)) ++#define ENV_OFFSET offsetof(SW64CPU, env) ++ ++#define cpu_init(cpu_model) cpu_generic_init(TYPE_SW64_CPU, cpu_model) ++ ++#define SW64_CPU_TYPE_SUFFIX "-" TYPE_SW64_CPU ++#define SW64_CPU_TYPE_NAME(name) (name SW64_CPU_TYPE_SUFFIX) ++int cpu_sw64_signal_handler(int host_signum, void *pinfo, void *puc); ++bool sw64_cpu_tlb_fill(CPUState *cs, vaddr address, int size, ++ MMUAccessType access_type, int mmu_idx, ++ bool probe, uintptr_t retaddr); ++uint64_t sw64_ldl_phys(CPUState *cs, hwaddr addr); ++hwaddr sw64_cpu_get_phys_page_debug(CPUState *cs, vaddr addr); ++void sw64_stl_phys(CPUState *cs, hwaddr addr, uint64_t val); ++uint64_t sw64_ldw_phys(CPUState *cs, hwaddr addr); ++void sw64_stw_phys(CPUState *cs, hwaddr addr, uint64_t val); ++uint64_t cpu_sw64_load_fpcr(CPUSW64State *env); ++void cpu_sw64_store_fpcr(CPUSW64State *env, uint64_t val); ++void sw64_cpu_do_unaligned_access(CPUState *cs, vaddr addr, ++ MMUAccessType access_type, int mmu_idx, ++ uintptr_t retaddr) QEMU_NORETURN; ++bool sw64_cpu_has_work(CPUState *cs); ++extern struct VMStateDescription vmstate_sw64_cpu; ++ ++/* SW64-specific interrupt pending bits */ ++#define CPU_INTERRUPT_TIMER CPU_INTERRUPT_TGT_EXT_0 ++#define CPU_INTERRUPT_IIMAIL CPU_INTERRUPT_TGT_EXT_1 ++#define CPU_INTERRUPT_MCHK CPU_INTERRUPT_TGT_EXT_2 ++#define CPU_INTERRUPT_PCIE CPU_INTERRUPT_TGT_EXT_3 ++#define CPU_INTERRUPT_WAKEUP CPU_INTERRUPT_TGT_EXT_3 ++#define CPU_INTERRUPT_SLAVE CPU_INTERRUPT_TGT_EXT_4 ++ ++#define cpu_signal_handler cpu_sw64_signal_handler ++#define CPU_RESOLVING_TYPE TYPE_SW64_CPU ++ ++#define SWCSR(x, y) x = y ++enum { ++ SWCSR(ITB_TAG, 0x0), ++ SWCSR(ITB_PTE, 0x1), ++ SWCSR(ITB_IA, 0x2), ++ SWCSR(ITB_IV, 0x3), ++ SWCSR(ITB_IVP, 0x4), ++ SWCSR(ITB_IU, 0x5), ++ SWCSR(ITB_IS, 0x6), ++ SWCSR(EXC_SUM, 0xd), ++ SWCSR(EXC_PC, 0xe), ++ SWCSR(DS_STAT, 0x48), ++ SWCSR(CID, 0xc4), ++ SWCSR(TID, 0xc7), ++ ++ SWCSR(DTB_TAG, 0x40), ++ SWCSR(DTB_PTE, 0x41), ++ SWCSR(DTB_IA, 0x42), ++ SWCSR(DTB_IV, 0x43), ++ SWCSR(DTB_IVP, 0x44), ++ SWCSR(DTB_IU, 0x45), ++ SWCSR(DTB_IS, 0x46), ++ SWCSR(II_REQ, 0x82), ++ ++ SWCSR(PTBR, 0x8), ++ SWCSR(PRI_BASE, 0x10), ++ SWCSR(TIMER_CTL, 0x2a), ++ SWCSR(INT_STAT, 0x30), ++ SWCSR(INT_CLR, 0x31), ++ SWCSR(IER, 0x32), ++ SWCSR(INT_PCI_INT, 0x33), ++ SWCSR(DVA, 0x4e), ++}; ++ ++#include "exec/cpu-all.h" ++static inline void cpu_get_tb_cpu_state(CPUSW64State *env, target_ulong *pc, ++ target_ulong *cs_base, uint32_t *pflags) ++{ ++ *pc = env->pc; ++ *cs_base = 0; ++ *pflags = env->flags; ++} ++ ++void sw64_translate_init(void); ++ ++enum { ++ EXCP_NONE, ++ EXCP_HALT, ++ EXCP_IIMAIL, ++ EXCP_OPCDEC, ++ EXCP_CALL_SYS, ++ EXCP_ARITH, ++ EXCP_UNALIGN, ++#ifdef SOFTMMU ++ EXCP_MMFAULT, ++#else ++ EXCP_DTBD, ++ EXCP_DTBS_U, ++ EXCP_DTBS_K, ++ EXCP_ITB_U, ++ EXCP_ITB_K, ++#endif ++ EXCP_CLK_INTERRUPT, ++ EXCP_DEV_INTERRUPT, ++ EXCP_SLAVE, ++}; ++ ++#define CSR_SHIFT_AND_MASK(name, func, shift, bits) \ ++ name##_##func##_S = shift, \ ++ name##_##func##_V = bits, \ ++ name##_##func##_M = (1UL << bits) - 1 ++ ++#define FPCR_MASK(name) ((uint64_t)FPCR_##name##_M << FPCR_##name##_S) ++/* FPCR */ ++enum { ++ CSR_SHIFT_AND_MASK(FPCR, EXC_CTL, 0, 2), ++ CSR_SHIFT_AND_MASK(FPCR, EXC_CTL_WEN, 2, 1), ++ CSR_SHIFT_AND_MASK(FPCR, RSV0, 3, 1), ++ CSR_SHIFT_AND_MASK(FPCR, INV3, 4, 1), ++ CSR_SHIFT_AND_MASK(FPCR, ZERO0, 5, 1), ++ CSR_SHIFT_AND_MASK(FPCR, OVF3, 6, 1), ++ CSR_SHIFT_AND_MASK(FPCR, UNF3, 7, 1), ++ CSR_SHIFT_AND_MASK(FPCR, INE3, 8, 1), ++ CSR_SHIFT_AND_MASK(FPCR, ZERO1, 9, 1), ++ CSR_SHIFT_AND_MASK(FPCR, RSV1, 10, 10), ++ CSR_SHIFT_AND_MASK(FPCR, INV2, 20, 1), ++ CSR_SHIFT_AND_MASK(FPCR, ZERO2, 21, 1), ++ CSR_SHIFT_AND_MASK(FPCR, OVF2, 22, 1), ++ CSR_SHIFT_AND_MASK(FPCR, UNF2, 23, 1), ++ CSR_SHIFT_AND_MASK(FPCR, INE2, 24, 1), ++ CSR_SHIFT_AND_MASK(FPCR, ZERO3, 25, 1), ++ CSR_SHIFT_AND_MASK(FPCR, RSV2, 26, 10), ++ CSR_SHIFT_AND_MASK(FPCR, INV1, 36, 1), ++ CSR_SHIFT_AND_MASK(FPCR, ZERO4, 37, 1), ++ CSR_SHIFT_AND_MASK(FPCR, OVF1, 38, 1), ++ CSR_SHIFT_AND_MASK(FPCR, UNF1, 39, 1), ++ CSR_SHIFT_AND_MASK(FPCR, INE1, 40, 1), ++ CSR_SHIFT_AND_MASK(FPCR, ZERO5, 41, 1), ++ CSR_SHIFT_AND_MASK(FPCR, RSV3, 42, 6), ++ CSR_SHIFT_AND_MASK(FPCR, DNZ, 48, 1), ++ CSR_SHIFT_AND_MASK(FPCR, INVD, 49, 1), ++ CSR_SHIFT_AND_MASK(FPCR, DZED, 50, 1), ++ CSR_SHIFT_AND_MASK(FPCR, OVFD, 51, 1), ++ CSR_SHIFT_AND_MASK(FPCR, INV0, 52, 1), ++ CSR_SHIFT_AND_MASK(FPCR, DZE0, 53, 1), ++ CSR_SHIFT_AND_MASK(FPCR, OVF0, 54, 1), ++ CSR_SHIFT_AND_MASK(FPCR, UNF0, 55, 1), ++ CSR_SHIFT_AND_MASK(FPCR, INE0, 56, 1), ++ CSR_SHIFT_AND_MASK(FPCR, OVI0, 57, 1), ++ CSR_SHIFT_AND_MASK(FPCR, DYN, 58, 2), ++ CSR_SHIFT_AND_MASK(FPCR, UNDZ, 60, 1), ++ CSR_SHIFT_AND_MASK(FPCR, UNFD, 61, 1), ++ CSR_SHIFT_AND_MASK(FPCR, INED, 62, 1), ++ CSR_SHIFT_AND_MASK(FPCR, SUM, 63, 1), ++}; ++ ++/* Arithmetic exception (entArith) constants. */ ++#define EXC_M_SWC 1 /* Software completion */ ++#define EXC_M_INV 2 /* Invalid operation */ ++#define EXC_M_DZE 4 /* Division by zero */ ++#define EXC_M_OVF 8 /* Overflow */ ++#define EXC_M_UNF 16 /* Underflow */ ++#define EXC_M_INE 32 /* Inexact result */ ++#define EXC_M_IOV 64 /* Integer Overflow */ ++#define EXC_M_DNO 128 /* Denomal operation */ ++ ++void QEMU_NORETURN dynamic_excp(CPUSW64State *env, uintptr_t retaddr, int excp, ++ int error); ++void QEMU_NORETURN arith_excp(CPUSW64State *env, uintptr_t retaddr, int exc, ++ uint64_t mask); ++ ++#define DEBUG_ARCH ++#ifdef DEBUG_ARCH ++#define arch_assert(x) \ ++ do { \ ++ g_assert(x); /*fprintf(stderr, "+6b %d\n", __LINE__); */ \ ++ } while (0) ++#else ++#define arch_assert(x) ++#endif ++ ++typedef struct SW64CPUInfo { ++ const char *name; ++ void (*initfn)(Object *obj); ++ void (*class_init)(ObjectClass *oc, void *data); ++} SW64CPUInfo; ++#define test_feature(env, x) (env->features & (x)) ++ ++/* Slave */ ++#endif +diff --git a/target/sw64/exception.c b/target/sw64/exception.c +new file mode 100644 +index 0000000000..a2df1cd329 +--- /dev/null ++++ b/target/sw64/exception.c +@@ -0,0 +1,76 @@ ++#include "qemu/osdep.h" ++#include "qemu/timer.h" ++ ++#include "cpu.h" ++#include "exec/exec-all.h" ++#include "fpu/softfloat.h" ++#include "exec/helper-proto.h" ++#include "hw/core/cpu.h" ++ ++#ifndef CONFIG_USER_ONLY ++void QEMU_NORETURN sw64_cpu_do_unaligned_access(CPUState *cs, vaddr addr, ++ MMUAccessType access_type, ++ int mmu_idx, uintptr_t retaddr) ++{ ++ SW64CPU *cpu = SW64_CPU(cs); ++ CPUSW64State *env = &cpu->env; ++ uint32_t insn = 0; ++ ++ if (retaddr) { ++ cpu_restore_state(cs, retaddr, true); ++ } ++ ++ fprintf(stderr, "Error %s addr = %lx\n", __func__, addr); ++ env->csr[DVA] = addr; ++ ++ env->csr[EXC_SUM] = ((insn >> 21) & 31) << 8; /* opcode */ ++ env->csr[DS_STAT] = (insn >> 26) << 4; /* dest regno */ ++ cs->exception_index = EXCP_UNALIGN; ++ env->error_code = 0; ++ cpu_loop_exit(cs); ++} ++ ++#endif ++ ++/* This should only be called from translate, via gen_excp. ++ We expect that ENV->PC has already been updated. */ ++void QEMU_NORETURN helper_excp(CPUSW64State *env, int excp, int error) ++{ ++ SW64CPU *cpu = sw64_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(CPUSW64State *env, uintptr_t retaddr, int excp, ++ int error) ++{ ++ SW64CPU *cpu = sw64_env_get_cpu(env); ++ CPUState *cs = CPU(cpu); ++ ++ cs->exception_index = excp; ++ env->error_code = error; ++ if (retaddr) { ++ /* FIXME: Not jump to another tb, but jump to next insn emu */ ++ cpu_restore_state(cs, retaddr, true); ++ /* Floating-point exceptions (our only users) point to the next PC. */ ++ env->pc += 4; ++ } ++ cpu_loop_exit(cs); ++} ++ ++void QEMU_NORETURN arith_excp(CPUSW64State *env, uintptr_t retaddr, int exc, ++ uint64_t mask) ++{ ++ env->csr[EXC_SUM] = exc; ++ dynamic_excp(env, retaddr, EXCP_ARITH, 0); ++} ++ ++ ++void helper_trace_mem(CPUSW64State *env, uint64_t addr, uint64_t val) ++{ ++ /* printf("pc = %lx: Access mem addr =%lx, val = %lx\n", env->pc, addr,val); */ ++} +diff --git a/target/sw64/float_helper.c b/target/sw64/float_helper.c +new file mode 100644 +index 0000000000..ad1c3cce48 +--- /dev/null ++++ b/target/sw64/float_helper.c +@@ -0,0 +1,846 @@ ++#include "qemu/osdep.h" ++#include "cpu.h" ++#include "exec/exec-all.h" ++#include "exec/helper-proto.h" ++#include "fpu/softfloat.h" ++ ++static inline uint32_t extractFloat16Frac(float16 a) ++{ ++ return float16_val(a) & 0x3ff; ++} ++ ++/*---------------------------------------------------------------------------- ++| Returns the exponent bits of the half-precision floating-point value `a'. ++*----------------------------------------------------------------------------*/ ++ ++static inline int extractFloat16Exp(float16 a) ++{ ++ return (float16_val(a) >> 10) & 0x1f; ++} ++ ++/*---------------------------------------------------------------------------- ++| Returns the sign bit of the single-precision floating-point value `a'. ++*----------------------------------------------------------------------------*/ ++ ++static inline uint8_t extractFloat16Sign(float16 a) ++{ ++ return float16_val(a) >> 15; ++} ++ ++#define FP_STATUS (env->fp_status) ++ ++#define CONVERT_BIT(X, SRC, DST) \ ++ (SRC > DST ? (X) / (SRC / DST) & (DST) : ((X)&SRC) * (DST / SRC)) ++ ++static uint64_t soft_to_errcode_exc(CPUSW64State *env) ++{ ++ uint8_t exc = get_float_exception_flags(&FP_STATUS); ++ ++ if (unlikely(exc)) { ++ set_float_exception_flags(0, &FP_STATUS); ++ } ++ return exc; ++} ++ ++static inline uint64_t float32_to_s_int(uint32_t fi) ++{ ++ uint32_t frac = fi & 0x7fffff; ++ uint32_t sign = (fi >> 31) & 1; ++ 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(a); ++} ++ ++uint64_t helper_memory_to_s(uint32_t a) ++{ ++ return float32_to_s(a); ++} ++ ++uint64_t helper_fcvtls(CPUSW64State *env, uint64_t a) ++{ ++ float32 fr = int64_to_float32(a, &FP_STATUS); ++ env->error_code = soft_to_errcode_exc(env); ++ return float32_to_s(fr); ++} ++ ++uint64_t helper_fcvtld(CPUSW64State *env, uint64_t a) ++{ ++ float64 fr = int64_to_float64(a, &FP_STATUS); ++ env->error_code = soft_to_errcode_exc(env); ++ return (uint64_t)fr; ++} ++ ++static uint64_t do_fcvtdl(CPUSW64State *env, uint64_t a, uint64_t 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 = float_flag_invalid; ++ } 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 = float_flag_inexact; ++ } ++ } 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 = float_flag_inexact; ++ 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; ++} ++ ++/* TODO: */ ++uint64_t helper_fris(CPUSW64State *env, uint64_t a, uint64_t roundmode) ++{ ++ uint64_t ir; ++ float32 fr; ++ ++ if (roundmode == 5) ++ roundmode = env->fpcr_round_mode; ++ ir = do_fcvtdl(env, a, roundmode); ++ fr = int64_to_float32(ir, &FP_STATUS); ++ return float32_to_s(fr); ++} ++ ++/* TODO: */ ++uint64_t helper_frid(CPUSW64State *env, uint64_t a, uint64_t roundmode) ++{ ++ if (roundmode == 5) ++ roundmode = env->fpcr_round_mode; ++ return int64_to_float64(do_fcvtdl(env, a, roundmode), &FP_STATUS); ++} ++ ++uint64_t helper_fcvtdl(CPUSW64State *env, uint64_t a, uint64_t roundmode) ++{ ++ return do_fcvtdl(env, a, roundmode); ++} ++ ++uint64_t helper_fcvtdl_dyn(CPUSW64State *env, uint64_t a) ++{ ++ uint64_t roundmode = (uint64_t)(env->fpcr_round_mode); ++ return do_fcvtdl(env, a, roundmode); ++} ++ ++uint64_t helper_fcvtsd(CPUSW64State *env, uint64_t a) ++{ ++ float32 fa; ++ float64 fr; ++ ++ fa = s_to_float32(a); ++ fr = float32_to_float64(fa, &FP_STATUS); ++ ++ return fr; ++} ++ ++uint64_t helper_fcvtds(CPUSW64State *env, uint64_t a) ++{ ++ float32 fa; ++ ++ fa = float64_to_float32((float64)a, &FP_STATUS); ++ ++ return float32_to_s(fa); ++} ++ ++uint64_t helper_fcvtwl(CPUSW64State *env, uint64_t a) ++{ ++ int32_t ret; ++ ret = (a >> 29) & 0x3fffffff; ++ ret |= ((a >> 62) & 0x3) << 30; ++ return (uint64_t)(int64_t)ret; //int32_t to int64_t as Sign-Extend ++} ++ ++uint64_t helper_fcvtlw(CPUSW64State *env, uint64_t a) ++{ ++ uint64_t ret; ++ ret = (a & 0x3fffffff) << 29; ++ ret |= ((a >> 30) & 0x3) << 62; ++ return ret; ++} ++ ++uint64_t helper_fadds(CPUSW64State *env, uint64_t a, uint64_t b) ++{ ++ float32 fa, fb, fr; ++ ++ fa = s_to_float32(a); ++ fb = s_to_float32(b); ++#if 1 ++ fr = float32_add(fa, fb, &FP_STATUS); ++ ++ env->error_code = soft_to_errcode_exc(env); ++#else ++ *(float*)&fr = *(float*)&fb + *(float*)&fa; ++#endif ++ return float32_to_s(fr); ++} ++ ++/* Input handing without software completion. Trap for all ++ non-finite numbers. */ ++uint64_t helper_faddd(CPUSW64State *env, uint64_t a, uint64_t b) ++{ ++ float64 fa, fb, fr; ++ ++ fa = (float64)a; ++ fb = (float64)b; ++#if 1 ++ fr = float64_add(fa, fb, &FP_STATUS); ++ env->error_code = soft_to_errcode_exc(env); ++#else ++ *(double*)&fr = *(double*)&fb + *(double*)&fa; ++#endif ++ return (uint64_t)fr; ++} ++ ++uint64_t helper_fsubs(CPUSW64State *env, uint64_t a, uint64_t b) ++{ ++ float32 fa, fb, fr; ++ ++ fa = s_to_float32(a); ++ fb = s_to_float32(b); ++#if 1 ++ fr = float32_sub(fa, fb, &FP_STATUS); ++ env->error_code = soft_to_errcode_exc(env); ++#else ++ *(float*)&fr = *(float*)&fa - *(float*)&fb; ++#endif ++ return float32_to_s(fr); ++} ++ ++uint64_t helper_fsubd(CPUSW64State *env, uint64_t a, uint64_t b) ++{ ++ float64 fa, fb, fr; ++ ++ fa = (float64)a; ++ fb = (float64)b; ++#if 1 ++ fr = float64_sub(fa, fb, &FP_STATUS); ++ env->error_code = soft_to_errcode_exc(env); ++#else ++ *(double*)&fr = *(double*)&fa - *(double*)&fb; ++#endif ++ return (uint64_t)fr; ++} ++ ++uint64_t helper_fmuls(CPUSW64State *env, uint64_t a, uint64_t b) ++{ ++ float32 fa, fb, fr; ++ ++ fa = s_to_float32(a); ++ fb = s_to_float32(b); ++#if 1 ++ fr = float32_mul(fa, fb, &FP_STATUS); ++ env->error_code = soft_to_errcode_exc(env); ++#else ++ *(float*)&fr = *(float*)&fa * *(float*)&fb; ++#endif ++ return float32_to_s(fr); ++} ++ ++uint64_t helper_fmuld(CPUSW64State *env, uint64_t a, uint64_t b) ++{ ++ float64 fa, fb, fr; ++ ++ fa = (float64)a; ++ fb = (float64)b; ++#if 1 ++ fr = float64_mul(fa, fb, &FP_STATUS); ++ env->error_code = soft_to_errcode_exc(env); ++#else ++ *(double*)&fr = *(double*)&fa * *(double*)&fb; ++#endif ++ return (uint64_t)fr; ++} ++ ++uint64_t helper_fdivs(CPUSW64State *env, uint64_t a, uint64_t b) ++{ ++ float32 fa, fb, fr; ++ ++ fa = s_to_float32(a); ++ fb = s_to_float32(b); ++#if 1 ++ fr = float32_div(fa, fb, &FP_STATUS); ++ env->error_code = soft_to_errcode_exc(env); ++#else ++ *(float*)&fr = *(float*)&fa / *(float*)&fb; ++#endif ++ return float32_to_s(fr); ++} ++ ++uint64_t helper_fdivd(CPUSW64State *env, uint64_t a, uint64_t b) ++{ ++ float64 fa, fb, fr; ++ ++ fa = (float64)a; ++ fb = (float64)b; ++#if 1 ++ fr = float64_div(fa, fb, &FP_STATUS); ++ env->error_code = soft_to_errcode_exc(env); ++#else ++ *(double*)&fr = *(double*)&fa / *(double*)&fb; ++#endif ++ ++ return (uint64_t)fr; ++} ++ ++uint64_t helper_frecs(CPUSW64State *env, uint64_t a) ++{ ++ float32 fa, fb, fr; ++ ++ fa = s_to_float32(a); ++ fb = int64_to_float32(1, &FP_STATUS); ++#if 1 ++ fr = float32_div(fb, fa, &FP_STATUS); ++ env->error_code = soft_to_errcode_exc(env); ++#else ++ *(float*)&fr = *(float*)&fb / *(float*)&fa; ++#endif ++ return float32_to_s(fr); ++} ++ ++uint64_t helper_frecd(CPUSW64State *env, uint64_t a) ++{ ++ float64 fa, fb, fr; ++ ++ fa = (float64)a; ++ fb = int64_to_float64(1, &FP_STATUS); ++#if 1 ++ fr = float64_div(fb, fa, &FP_STATUS); ++ env->error_code = soft_to_errcode_exc(env); ++#else ++ *(double*)&fr = *(double*)&fb / *(double*)&fa; ++#endif ++ ++ return (uint64_t)fr; ++} ++ ++uint64_t helper_fsqrts(CPUSW64State *env, uint64_t b) ++{ ++ float32 fb, fr; ++#if 1 ++ fb = s_to_float32(b); ++ fr = float32_sqrt(fb, &FP_STATUS); ++ env->error_code = soft_to_errcode_exc(env); ++#else ++#include ++ *(double*)&fr = sqrt(*(double*)&b); ++#endif ++ ++ return float32_to_s(fr); ++} ++ ++uint64_t helper_fsqrt(CPUSW64State *env, uint64_t b) ++{ ++ float64 fr; ++ ++#if 1 ++ fr = float64_sqrt(b, &FP_STATUS); ++ env->error_code = soft_to_errcode_exc(env); ++#else ++#include ++ *(double*)&fr = sqrt(*(double*)&b); ++#endif ++ ++ return (uint64_t)fr; ++} ++ ++ ++uint64_t helper_fmas(CPUSW64State *env, uint64_t a, uint64_t b, uint64_t c) ++{ ++ float32 fa, fb, fc, fr; ++ fa = s_to_float32(a); ++ fb = s_to_float32(b); ++ fc = s_to_float32(c); ++ ++ fr = float32_muladd(fa, fb, fc, 0, &FP_STATUS); ++ ++ return float32_to_s(fr); ++} ++ ++uint64_t helper_fmad(CPUSW64State *env, uint64_t a, uint64_t b, uint64_t c) ++{ ++ float64 fr; ++ ++ fr = float64_muladd(a, b, c, 0, &FP_STATUS); ++ ++ return fr; ++} ++ ++ ++uint64_t helper_fmss(CPUSW64State *env, uint64_t a, uint64_t b, uint64_t c) ++{ ++ float32 fa, fb, fc, fr; ++ fa = s_to_float32(a); ++ fb = s_to_float32(b); ++ fc = s_to_float32(c); ++ ++ fr = float32_muladd(fa, fb, fc, float_muladd_negate_c, &FP_STATUS); ++ ++ return float32_to_s(fr); ++} ++ ++uint64_t helper_fmsd(CPUSW64State *env, uint64_t a, uint64_t b, uint64_t c) ++{ ++ float64 fr; ++ ++ fr = float64_muladd(a, b, c, float_muladd_negate_c, &FP_STATUS); ++ ++ return fr; ++} ++ ++ ++uint64_t helper_fnmas(CPUSW64State *env, uint64_t a, uint64_t b, uint64_t c) ++{ ++ float32 fa, fb, fc, fr; ++ fa = s_to_float32(a); ++ fb = s_to_float32(b); ++ fc = s_to_float32(c); ++ int flag = float_muladd_negate_product; ++ ++ fr = float32_muladd(fa, fb, fc, flag, &FP_STATUS); ++ ++ return float32_to_s(fr); ++} ++ ++uint64_t helper_fnmad(CPUSW64State *env, uint64_t a, uint64_t b, uint64_t c) ++{ ++ float64 fr; ++ int flag = float_muladd_negate_product; ++ ++ fr = float64_muladd(a, b, c, flag, &FP_STATUS); ++ ++ return fr; ++} ++ ++uint64_t helper_fnmss(CPUSW64State *env, uint64_t a, uint64_t b, uint64_t c) ++{ ++ float32 fa, fb, fc, fr; ++ fa = s_to_float32(a); ++ fb = s_to_float32(b); ++ fc = s_to_float32(c); ++ int flag = float_muladd_negate_product | float_muladd_negate_c; ++ ++ fr = float32_muladd(fa, fb, fc, flag, &FP_STATUS); ++ ++ return float32_to_s(fr); ++} ++ ++uint64_t helper_fnmsd(CPUSW64State *env, uint64_t a, uint64_t b, uint64_t c) ++{ ++ float64 fr; ++ int flag = float_muladd_negate_product | float_muladd_negate_c; ++ ++ fr = float64_muladd(a, b, c, flag, &FP_STATUS); ++ ++ return fr; ++} ++uint64_t helper_load_fpcr(CPUSW64State *env) ++{ ++ return cpu_sw64_load_fpcr(env); ++} ++ ++static void update_fpcr_status_mask(CPUSW64State *env) ++{ ++ uint64_t t = 0; ++ ++ /* Don't mask the inv excp: ++ * EXC_CTL1 = 1 ++ * EXC_CTL1 = 0, input denormal, DNZ=0 ++ * EXC_CTL1 = 0, no input denormal or DNZ=1, INVD = 0 ++ */ ++ if ((env->fpcr & FPCR_MASK(EXC_CTL) & 0x2)) { ++ if (env->fpcr & FPCR_MASK(EXC_CTL) & 0x1) { ++ t |= (EXC_M_INE | EXC_M_UNF | EXC_M_IOV); ++ } else { ++ t |= EXC_M_INE; ++ } ++ } else { ++ /* INV and DNO mask */ ++ if (env->fpcr & FPCR_MASK(DNZ)) t |= EXC_M_DNO; ++ if (env->fpcr & FPCR_MASK(INVD)) t |= EXC_M_INV; ++ if (env->fpcr & FPCR_MASK(OVFD)) t |= EXC_M_OVF; ++ if (env->fpcr & FPCR_MASK(UNFD)) { ++ t |= EXC_M_UNF; ++ } ++ if (env->fpcr & FPCR_MASK(DZED)) t |= EXC_M_DZE; ++ if (env->fpcr & FPCR_MASK(INED)) t |= EXC_M_INE; ++ } ++ ++ env->fpcr_exc_enable = t; ++} ++ ++void helper_store_fpcr(CPUSW64State *env, uint64_t val) ++{ ++ uint64_t fpcr = val; ++ uint8_t ret; ++ ++ switch ((fpcr & FPCR_MASK(DYN)) >> FPCR_DYN_S) { ++ case 0x0: ++ ret = float_round_to_zero; ++ break; ++ case 0x1: ++ ret = float_round_down; ++ break; ++ case 0x2: ++ ret = float_round_nearest_even; ++ break; ++ case 0x3: ++ ret = float_round_up; ++ break; ++ default: ++ ret = float_round_nearest_even; ++ break; ++ } ++ ++ env->fpcr_round_mode = ret; ++ ++ env->fp_status.float_rounding_mode = ret; ++ ++ env->fpcr_flush_to_zero = ++ (fpcr & FPCR_MASK(UNFD)) && (fpcr & FPCR_MASK(UNDZ)); ++ env->fp_status.flush_to_zero = env->fpcr_flush_to_zero; ++ ++ /* FIXME: Now the DNZ flag does not work int C3A. */ ++ //set_flush_inputs_to_zero((val & FPCR_MASK(DNZ)) != 0? 1 : 0, &FP_STATUS); ++ ++ val &= ~0x3UL; ++ val |= env->fpcr & 0x3UL; ++ env->fpcr = val; ++ update_fpcr_status_mask(env); ++} ++ ++void helper_setfpcrx(CPUSW64State *env, uint64_t val) ++{ ++ if (env->fpcr & FPCR_MASK(EXC_CTL_WEN)) { ++ env->fpcr &= ~3UL; ++ env->fpcr |= val & 0x3; ++ update_fpcr_status_mask(env); ++ } ++} ++#ifndef CONFIG_USER_ONLY ++static uint32_t soft_to_exc_type(uint64_t exc) ++{ ++ uint32_t ret = 0; ++ ++ if (unlikely(exc)) { ++ ret |= CONVERT_BIT(exc, float_flag_invalid, EXC_M_INV); ++ ret |= CONVERT_BIT(exc, float_flag_divbyzero, EXC_M_DZE); ++ ret |= CONVERT_BIT(exc, float_flag_overflow, EXC_M_OVF); ++ ret |= CONVERT_BIT(exc, float_flag_underflow, EXC_M_UNF); ++ ret |= CONVERT_BIT(exc, float_flag_inexact, EXC_M_INE); ++ } ++ ++ return ret; ++} ++static void fp_exc_raise1(CPUSW64State *env, uintptr_t retaddr, uint64_t exc, ++ uint32_t regno) ++{ ++ if (!likely(exc)) ++ return; ++ arith_excp(env, retaddr, exc, 1ull << regno); ++} ++ ++void helper_fp_exc_raise(CPUSW64State *env, uint32_t regno) ++{ ++ uint64_t exc = env->error_code; ++ uint32_t exc_type = soft_to_exc_type(exc); ++ ++ if (exc_type) { ++ exc_type &= ~(env->fpcr_exc_enable); ++ if (exc_type) fp_exc_raise1(env, GETPC(), exc_type | EXC_M_SWC, regno); ++ } ++} ++#endif ++ ++void helper_ieee_input(CPUSW64State *env, uint64_t val) ++{ ++#ifndef CONFIG_USER_ONLY ++ uint32_t exp = (uint32_t)(val >> 52) & 0x7ff; ++ uint64_t frac = val & 0xfffffffffffffull; ++ ++ if (exp == 0x7ff) { ++ /* Infinity or NaN. */ ++ uint32_t exc_type = EXC_M_INV; ++ ++ if (exc_type) { ++ exc_type &= ~(env->fpcr_exc_enable); ++ if (exc_type) ++ fp_exc_raise1(env, GETPC(), exc_type | EXC_M_SWC, 32); ++ } ++ } ++#endif ++} ++ ++void helper_ieee_input_s(CPUSW64State *env, uint64_t val) ++{ ++ if (unlikely(2 * val - 1 < 0x1fffffffffffffull) && ++ !env->fp_status.flush_inputs_to_zero) { ++ } ++} ++ ++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; ++} ++ ++uint64_t helper_fcmpun(CPUSW64State *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_errcode_exc(env); ++ ++ return ret; ++} ++ ++uint64_t helper_fcmpeq(CPUSW64State *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_errcode_exc(env); ++ ++ return ret; ++} ++ ++uint64_t helper_fcmple(CPUSW64State *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_quiet(fa, fb, &FP_STATUS)) { ++ ret = 0x4000000000000000ULL; ++ } ++ env->error_code = soft_to_errcode_exc(env); ++ ++ return ret; ++} ++ ++uint64_t helper_fcmplt(CPUSW64State *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_quiet(fa, fb, &FP_STATUS)) { ++ ret = 0x4000000000000000ULL; ++ } ++ env->error_code = soft_to_errcode_exc(env); ++ ++ return ret; ++} ++ ++uint64_t helper_fcmpge(CPUSW64State *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_quiet(fb, fa, &FP_STATUS)) { ++ ret = 0x4000000000000000ULL; ++ } ++ env->error_code = soft_to_errcode_exc(env); ++ ++ return ret; ++} ++ ++uint64_t helper_fcmpgt(CPUSW64State *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_quiet(fb, fa, &FP_STATUS)) { ++ ret = 0x4000000000000000ULL; ++ } ++ env->error_code = soft_to_errcode_exc(env); ++ ++ return ret; ++} ++ ++uint64_t helper_fcmpge_s(CPUSW64State *env, uint64_t a, uint64_t b) ++{ ++ float64 fa, fb; ++ uint64_t ret = 0; ++ ++ /* Make sure va and vb is s float. */ ++ fa = float32_to_float64(s_to_float32(a), &FP_STATUS); ++ fb = float32_to_float64(s_to_float32(b), &FP_STATUS); ++ ++ if (float64_le_quiet(fb, fa, &FP_STATUS)) { ++ ret = 0x4000000000000000ULL; ++ } ++ env->error_code = soft_to_errcode_exc(env); ++ ++ return ret; ++} ++ ++uint64_t helper_fcmple_s(CPUSW64State *env, uint64_t a, uint64_t b) ++{ ++ float64 fa, fb; ++ uint64_t ret = 0; ++ ++ /* Make sure va and vb is s float. */ ++ fa = float32_to_float64(s_to_float32(a), &FP_STATUS); ++ fb = float32_to_float64(s_to_float32(b), &FP_STATUS); ++ ++ if (float64_le_quiet(fa, fb, &FP_STATUS)) { ++ ret = 0x4000000000000000ULL; ++ } ++ env->error_code = soft_to_errcode_exc(env); ++ ++ return ret; ++} ++ ++void helper_vfcvtsh(CPUSW64State *env, uint64_t ra, uint64_t rb, uint64_t vc, ++ uint64_t rd) ++{ ++ uint64_t temp = 0; ++ int i; ++ for (i = 0; i < 4; i++) { ++ temp |= (uint64_t)float32_to_float16(s_to_float32(env->fr[ra + i * 32]), ++ 1, &FP_STATUS) ++ << (i * 16); ++ } ++ for (i = 0; i < 4; i++) { ++ if (i == (vc & 0x3)) { ++ env->fr[rd + i * 32] = temp; ++ } else { ++ env->fr[rd + i * 32] = env->fr[rb + i * 32]; ++ } ++ } ++} ++ ++void helper_vfcvths(CPUSW64State *env, uint64_t ra, uint64_t rb, uint64_t vc, ++ uint64_t rd) ++{ ++ uint64_t temp; ++ int i; ++ ++ temp = env->fr[ra + 32 * (vc & 0x3)]; ++ for (i = 0; i < 4; i++) { ++ env->fr[rd + i * 32] = float32_to_s( ++ float16_to_float32((temp >> (i * 16)) & 0xffffUL, 1, &FP_STATUS)); ++ } ++} +diff --git a/target/sw64/helper.c b/target/sw64/helper.c +new file mode 100644 +index 0000000000..0cc0af7087 +--- /dev/null ++++ b/target/sw64/helper.c +@@ -0,0 +1,349 @@ ++/* ++ * 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 . ++ */ ++ ++#include "qemu/osdep.h" ++#include "qemu/timer.h" ++ ++#include "cpu.h" ++#include "exec/exec-all.h" ++#include "fpu/softfloat.h" ++#include "exec/helper-proto.h" ++#include "hw/core/cpu.h" ++#include "exec/memattrs.h" ++ ++#if defined(CONFIG_USER_ONLY) ++bool sw64_cpu_tlb_fill(CPUState *cs, vaddr address, int size, ++ MMUAccessType access_type, int mmu_idx, ++ bool probe, uintptr_t retaddr) ++{ ++ SW64CPU *cpu = SW64_CPU(cs); ++ ++ cs->exception_index = EXCP_MMFAULT; ++ cpu->env.trap_arg0 = address; ++ cpu_loop_exit_restore(cs, retaddr); ++} ++#else ++static target_ulong ldq_phys_clear(CPUState *cs, target_ulong phys) ++{ ++ return ldq_phys(cs->as, phys & ~(3UL)); ++} ++ ++static int get_sw64_physical_address(CPUSW64State *env, target_ulong addr, ++ int prot_need, int mmu_idx, target_ulong *pphys, ++ int *pprot) ++{ ++ CPUState *cs = CPU(sw64_env_get_cpu(env)); ++ target_ulong phys = 0; ++ int prot = 0; ++ int ret = MM_K_ACV; ++ target_ulong L1pte, L2pte, L3pte, L4pte; ++ target_ulong pt, index, pte_pfn_s; ++ ++ if (((addr >> 28) & 0xffffffff8) == 0xffffffff8) { ++ phys = (~(0xffffffff80000000)) & addr; ++ prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; ++ ret = -1; ++ goto exit; ++ } else if (((addr >> 32) & 0xfffff000) == 0xfffff000) { ++ goto do_pgmiss; ++ } else if (((addr >> 52) & 0xfff) == 0xfff) { ++ phys = (~(0xfff0000000000000)) & addr; ++ prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; ++ ret = -1; ++ goto exit; ++ } ++do_pgmiss: ++ pte_pfn_s = 28; ++ pt = env->csr[PTBR]; ++ index = (addr >> (TARGET_PAGE_BITS + 3 * TARGET_LEVEL_BITS)) & ((1 << TARGET_LEVEL_BITS)-1); ++ L1pte = ldq_phys_clear(cs, pt + index * 8); ++ if ((L1pte & PTE_VALID) == 0) { ++ ret = MM_K_TNV; ++ goto exit; ++ } ++ if (((L1pte >> 1) & 1) && prot_need == 0) { ++ ret = MM_K_FOR; ++ goto exit; ++ } ++ if (((L1pte >> 2) & 1) && prot_need == 1) { ++ ret = MM_K_FOW; ++ goto exit; ++ } ++ pt = L1pte >> pte_pfn_s << TARGET_PAGE_BITS; ++ ++ index = (addr >> (TARGET_PAGE_BITS + 2 * TARGET_LEVEL_BITS)) & ((1 << TARGET_LEVEL_BITS)-1); ++ L2pte = ldq_phys_clear(cs, pt + index * 8); ++ ++ if ((L2pte & PTE_VALID) == 0) { ++ ret = MM_K_TNV; ++ goto exit; ++ } ++ if (((L2pte >> 1) & 1) && prot_need == 0) { ++ ret = MM_K_FOR; ++ goto exit; ++ } ++ if (((L2pte >> 2) & 1) && prot_need == 1) { ++ ret = MM_K_FOW; ++ goto exit; ++ } ++ ++ pt = L2pte >> pte_pfn_s << TARGET_PAGE_BITS; ++ ++ index = (addr >> (TARGET_PAGE_BITS + 1 * TARGET_LEVEL_BITS)) & ((1 << TARGET_LEVEL_BITS)-1); ++ L3pte = ldq_phys_clear(cs, pt + index * 8); ++ ++ if ((L3pte & PTE_VALID) == 0) { ++ ret = MM_K_TNV; ++ goto exit; ++ } ++ if (((L3pte >> 1) & 1) && prot_need == 0) { ++ ret = MM_K_FOR; ++ goto exit; ++ } ++ if (((L3pte >> 2) & 1) && prot_need == 1) { ++ ret = MM_K_FOW; ++ goto exit; ++ } ++ ++ pt = L3pte >> pte_pfn_s << TARGET_PAGE_BITS; ++ ++ index = (addr >> TARGET_PAGE_BITS) & ((1 << TARGET_LEVEL_BITS)-1); ++ L4pte = ldq_phys_clear(cs, pt + index * 8); ++ if ((L4pte & 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 ((L4pte & PTE_FOR) == 0) { ++ prot |= PAGE_READ | PAGE_EXEC; ++ } ++ if ((L4pte & PTE_FOW) == 0) { ++ prot |= PAGE_WRITE; ++ } ++ ++ /* Check fault-on-operation violations. */ ++ prot &= ~(L4pte >> 1); ++ ++ phys = (L4pte >> pte_pfn_s << TARGET_PAGE_BITS); ++ ++ 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); ++ goto exit; ++ } ++ ++ ret = -1; ++exit: ++ *pphys = phys; ++ *pprot = prot; ++ return ret; ++} ++ ++bool sw64_cpu_tlb_fill(CPUState *cs, vaddr address, int size, ++ MMUAccessType access_type, int mmu_idx, ++ bool probe, uintptr_t retaddr) ++{ ++ SW64CPU *cpu = SW64_CPU(cs); ++ CPUSW64State *env = &cpu->env; ++ target_ulong phys; ++ int prot, fail; ++ ++ if (mmu_idx == MMU_PHYS_IDX) { ++ phys = address; ++ prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; ++ fail = 0; ++ if ((address >> 52) & 1) goto do_pgmiss; ++ goto done; ++ } ++ ++do_pgmiss: ++ fail = get_sw64_physical_address(env, address, 1 << access_type, mmu_idx, &phys, &prot); ++ if (unlikely(fail >= 0)) { ++ if (probe) { ++ return false; ++ } ++ cs->exception_index = EXCP_MMFAULT; ++ if (access_type == 2) { ++ env->csr[DS_STAT] = fail; ++ env->csr[DVA] = address & ~(3UL); ++ } else { ++ env->csr[DS_STAT] = fail | (((unsigned long)access_type + 1) << 3); ++ env->csr[DVA] = address; ++ } ++ env->error_code = access_type; ++ cpu_loop_exit_restore(cs, retaddr); ++ } ++done: ++ tlb_set_page(cs, address & TARGET_PAGE_MASK, phys & TARGET_PAGE_MASK, prot, ++ mmu_idx, TARGET_PAGE_SIZE); ++ return true; ++} ++ ++hwaddr sw64_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) ++{ ++ SW64CPU *cpu = SW64_CPU(cs); ++ CPUSW64State *env = &cpu->env; ++ target_ulong phys; ++ int prot, fail; ++ int mmu_index = cpu_mmu_index(env, 0); ++ if (mmu_index == MMU_PHYS_IDX) { ++ phys = addr; ++ prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; ++ fail = -1; ++ if ((addr >> 52) & 1) goto do_pgmiss; ++ goto done; ++ } ++do_pgmiss: ++ fail = get_sw64_physical_address(&cpu->env, addr, 1, mmu_index, &phys, &prot); ++done: ++ return (fail >= 0 ? -1 : phys); ++} ++#endif ++ ++static void update_fpcr_status_mask(CPUSW64State* env) { ++ uint64_t t = 0; ++ ++ /* Don't mask the inv excp: ++ * EXC_CTL1 = 1 ++ * EXC_CTL1 = 0, input denormal, DNZ=0 ++ * EXC_CTL1 = 0, no input denormal or DNZ=1, INVD = 0 ++ */ ++ if ((env->fpcr & FPCR_MASK(EXC_CTL) & 0x2)) { ++ if (env->fpcr & FPCR_MASK(EXC_CTL) & 0x1) { ++ t |= (EXC_M_INE | EXC_M_UNF | EXC_M_IOV); ++ } else { ++ t |= EXC_M_INE; ++ } ++ } else { ++ /* INV and DNO mask */ ++ if (env->fpcr & FPCR_MASK(DNZ)) t |= EXC_M_DNO; ++ if (env->fpcr & FPCR_MASK(INVD)) t |= EXC_M_INV; ++ if (env->fpcr & FPCR_MASK(OVFD)) t |= EXC_M_OVF; ++ if (env->fpcr & FPCR_MASK(UNFD)) { ++ t |= EXC_M_UNF; ++ } ++ if (env->fpcr & FPCR_MASK(DZED)) t |= EXC_M_DZE; ++ if (env->fpcr & FPCR_MASK(INED)) t |= EXC_M_INE; ++ } ++ ++ env->fpcr_exc_enable = t; ++} ++ ++void cpu_sw64_store_fpcr(CPUSW64State* env, uint64_t val) { ++ uint64_t fpcr = val; ++ uint8_t ret; ++ ++ switch ((fpcr & FPCR_MASK(DYN)) >> FPCR_DYN_S) { ++ case 0x0: ++ ret = float_round_to_zero; ++ break; ++ case 0x1: ++ ret = float_round_down; ++ break; ++ case 0x2: ++ ret = float_round_nearest_even; ++ break; ++ case 0x3: ++ ret = float_round_up; ++ break; ++ default: ++ ret = float_round_nearest_even; ++ break; ++ } ++ ++ env->fpcr_round_mode = ret; ++ env->fp_status.float_rounding_mode = ret; ++ ++ env->fpcr_flush_to_zero = ++ (fpcr & FPCR_MASK(UNFD)) && (fpcr & FPCR_MASK(UNDZ)); ++ env->fp_status.flush_to_zero = env->fpcr_flush_to_zero; ++ ++ val &= ~0x3UL; ++ val |= env->fpcr & 0x3UL; ++ env->fpcr = val; ++ update_fpcr_status_mask(env); ++} ++ ++uint64_t helper_read_csr(CPUSW64State *env, uint64_t index) ++{ ++ if (index == PRI_BASE) ++ return 0x10000; ++ return env->csr[index]; ++} ++ ++uint64_t helper_rtc(void) ++{ ++#ifndef CONFIG_USER_ONLY ++ return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) * CPUFREQ_SCALE; ++#else ++ return 0; ++#endif ++} ++ ++void helper_write_csr(CPUSW64State *env, uint64_t index, uint64_t va) ++{ ++ env->csr[index] = va; ++#ifndef CONFIG_USER_ONLY ++ CPUState *cs = &(sw64_env_get_cpu(env)->parent_obj); ++ SW64CPU *cpu = SW64_CPU(cs); ++ if ((index == DTB_IA) || (index == DTB_IV) || (index == DTB_IVP) || ++ (index == DTB_IU) || (index == DTB_IS) || (index == ITB_IA) || ++ (index == ITB_IV) || (index == ITB_IVP) || (index == ITB_IU) || ++ (index == ITB_IS) || (index == PTBR)) { ++ tlb_flush(cs); ++ } ++ if (index == INT_CLR || index == INT_PCI_INT) { ++ env->csr[INT_STAT] &= ~va; ++ } ++ ++ if (index == TIMER_CTL && env->csr[index] == 1) { ++ timer_mod(cpu->alarm_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 1000000000 / 250); ++ } ++#endif ++} ++ ++uint64_t cpu_sw64_load_fpcr(CPUSW64State *env) ++{ ++ return (uint64_t)env->fpcr; ++} ++ ++void helper_tb_flush(CPUSW64State *env) ++{ ++ tb_flush(CPU(sw64_env_get_cpu(env))); ++} ++ ++void helper_cpustate_update(CPUSW64State *env, uint64_t pc) ++{ ++ switch (pc & 0x3) { ++ case 0x00: ++ env->flags = ENV_FLAG_HM_MODE; ++ break; ++ case 0x01: ++ env->flags &= ~(ENV_FLAG_PS_USER | ENV_FLAG_HM_MODE); ++ break; ++ case 0x02: ++ env->flags &= ~(ENV_FLAG_PS_USER | ENV_FLAG_HM_MODE); ++ break; ++ case 0x03: ++ env->flags = ENV_FLAG_PS_USER; ++ } ++} +diff --git a/target/sw64/helper.h b/target/sw64/helper.h +new file mode 100644 +index 0000000000..7cafa563c2 +--- /dev/null ++++ b/target/sw64/helper.h +@@ -0,0 +1,127 @@ ++ ++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_2(cmpgeb, TCG_CALL_NO_RWG_SE, i64, i64, 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_2(fcvtls, TCG_CALL_NO_RWG, i64, env, i64) ++DEF_HELPER_FLAGS_2(fcvtld, TCG_CALL_NO_RWG, i64, env, i64) ++DEF_HELPER_FLAGS_3(fcvtdl, TCG_CALL_NO_RWG, i64, env, i64, i64) ++DEF_HELPER_FLAGS_2(fcvtdl_dyn, TCG_CALL_NO_RWG, i64, env, i64) ++DEF_HELPER_FLAGS_3(fris, TCG_CALL_NO_RWG, i64, env, i64, i64) ++DEF_HELPER_FLAGS_3(frid, TCG_CALL_NO_RWG, i64, env, i64, i64) ++DEF_HELPER_FLAGS_2(fcvtsd, TCG_CALL_NO_RWG, i64, env, i64) ++DEF_HELPER_FLAGS_2(fcvtds, TCG_CALL_NO_RWG, i64, env, i64) ++DEF_HELPER_FLAGS_2(fcvtwl, TCG_CALL_NO_RWG, i64, env, i64) ++DEF_HELPER_FLAGS_2(fcvtlw, TCG_CALL_NO_RWG, i64, env, i64) ++DEF_HELPER_FLAGS_5(vfcvtsh, 0, void, env, i64, i64, i64, i64) ++DEF_HELPER_FLAGS_5(vfcvths, 0, void, env, i64, i64, i64, i64) ++DEF_HELPER_FLAGS_3(fadds, TCG_CALL_NO_RWG, i64, env, i64, i64) ++DEF_HELPER_FLAGS_3(faddd, TCG_CALL_NO_RWG, i64, env, i64, i64) ++DEF_HELPER_FLAGS_3(fsubs, TCG_CALL_NO_RWG, i64, env, i64, i64) ++DEF_HELPER_FLAGS_3(fsubd, TCG_CALL_NO_RWG, i64, env, i64, i64) ++DEF_HELPER_FLAGS_3(fmuls, TCG_CALL_NO_RWG, i64, env, i64, i64) ++DEF_HELPER_FLAGS_3(fmuld, TCG_CALL_NO_RWG, i64, env, i64, i64) ++DEF_HELPER_FLAGS_3(fdivs, TCG_CALL_NO_RWG, i64, env, i64, i64) ++DEF_HELPER_FLAGS_3(fdivd, TCG_CALL_NO_RWG, i64, env, i64, i64) ++DEF_HELPER_FLAGS_2(frecs, TCG_CALL_NO_RWG, i64, env, i64) ++DEF_HELPER_FLAGS_2(frecd, TCG_CALL_NO_RWG, i64, env, i64) ++DEF_HELPER_FLAGS_2(fsqrts, TCG_CALL_NO_RWG, i64, env, i64) ++DEF_HELPER_FLAGS_2(fsqrt, TCG_CALL_NO_RWG, i64, env, i64) ++DEF_HELPER_FLAGS_4(fmas, TCG_CALL_NO_RWG, i64, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(fmad, TCG_CALL_NO_RWG, i64, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(fmss, TCG_CALL_NO_RWG, i64, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(fmsd, TCG_CALL_NO_RWG, i64, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(fnmas, TCG_CALL_NO_RWG, i64, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(fnmad, TCG_CALL_NO_RWG, i64, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(fnmss, TCG_CALL_NO_RWG, i64, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(fnmsd, TCG_CALL_NO_RWG, i64, env, i64, i64, i64) ++DEF_HELPER_FLAGS_0(rtc, TCG_CALL_NO_RWG, i64) ++DEF_HELPER_FLAGS_1(load_fpcr, 0, i64, env) ++DEF_HELPER_FLAGS_2(store_fpcr, 0, void, env, i64) ++DEF_HELPER_FLAGS_2(setfpcrx, 0, void, env, i64) ++DEF_HELPER_FLAGS_2(ieee_input, 0, void, env, i64) ++DEF_HELPER_FLAGS_2(ieee_input_s, 0, void, env, i64) ++DEF_HELPER_FLAGS_2(read_csr, TCG_CALL_NO_RWG, i64, env, i64) ++DEF_HELPER_FLAGS_3(write_csr, 0, void, env, i64, i64) ++DEF_HELPER_FLAGS_2(cpustate_update, 0, void, env, i64) ++DEF_HELPER_FLAGS_3(trace_mem, 0, void, env, i64, i64) ++DEF_HELPER_FLAGS_3(fcmpun, TCG_CALL_NO_RWG, i64, env, i64, i64) ++DEF_HELPER_FLAGS_3(fcmpeq, TCG_CALL_NO_RWG, i64, env, i64, i64) ++DEF_HELPER_FLAGS_3(fcmple, TCG_CALL_NO_RWG, i64, env, i64, i64) ++DEF_HELPER_FLAGS_3(fcmplt, TCG_CALL_NO_RWG, i64, env, i64, i64) ++DEF_HELPER_FLAGS_3(fcmpge, TCG_CALL_NO_RWG, i64, env, i64, i64) ++DEF_HELPER_FLAGS_3(fcmpgt, TCG_CALL_NO_RWG, i64, env, i64, i64) ++DEF_HELPER_FLAGS_3(fcmpge_s, TCG_CALL_NO_RWG, i64, env, i64, i64) ++DEF_HELPER_FLAGS_3(fcmple_s, TCG_CALL_NO_RWG, i64, env, i64, i64) ++DEF_HELPER_FLAGS_4(srlow, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(sllow, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(vlogzz, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(vconw, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(vcond, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(vshfw, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_2(ctlzow, 0, i64, env, i64) ++DEF_HELPER_FLAGS_4(vucaddw, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(vucaddwi, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(vucsubw, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(vucsubwi, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(vucaddh, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(vucaddhi, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(vucsubh, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(vucsubhi, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(vucaddb, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(vucaddbi, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(vucsubb, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(vucsubbi, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_3(vstw, TCG_CALL_NO_RWG, i64, env, i64, i64) ++DEF_HELPER_FLAGS_3(vsts, TCG_CALL_NO_RWG, i64, env, i64, i64) ++DEF_HELPER_FLAGS_3(vstd, TCG_CALL_NO_RWG, i64, env, i64, i64) ++DEF_HELPER_FLAGS_2(v_print, 0, void, env, i64) ++DEF_HELPER_FLAGS_1(tb_flush, 0, void, env) ++DEF_HELPER_FLAGS_4(vmaxb, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(vminb, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(vmaxh, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(vminh, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(vmaxw, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(vminw, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(sraow, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(vsm4r, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(vsm4key, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(vsm3msw, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(vcmpueqb, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(vcmpugtb, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(vcmpueqbi, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(vcmpugtbi, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(vumaxb, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(vuminb, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(vumaxh, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(vuminh, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(vumaxw, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(vuminw, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_5(vinsb, 0, void, env, i64, i64, i64, i64) ++DEF_HELPER_FLAGS_5(vinsh, 0, void, env, i64, i64, i64, i64) ++DEF_HELPER_FLAGS_4(vinsectlh, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(vinsectlw, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_4(vinsectlb, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_5(vshfq, 0, void, env, i64, i64, i64, i64) ++DEF_HELPER_FLAGS_4(vshfqb, 0, void, env, i64, i64, i64) ++DEF_HELPER_FLAGS_5(vsm3r, 0, void, env, i64, i64, i64, i64) ++ ++#ifndef CONFIG_USER_ONLY ++DEF_HELPER_FLAGS_2(fp_exc_raise, 0, void, env, i32) ++DEF_HELPER_FLAGS_2(pri_ldw, 0, i64, env, i64) ++DEF_HELPER_FLAGS_3(pri_stw, 0, void, env, i64, i64) ++DEF_HELPER_FLAGS_2(pri_ldl, 0, i64, env, i64) ++DEF_HELPER_FLAGS_3(pri_stl, 0, void, env, i64, i64) ++#endif ++ ++DEF_HELPER_3(excp, noreturn, env, int, int) ++//DEF_HELPER_FLAGS_3(faddh, TCG_CALL_NO_RWG, i64, env, i64, i64) ++//DEF_HELPER_FLAGS_3(fsubh, TCG_CALL_NO_RWG, i64, env, i64, i64) ++//DEF_HELPER_FLAGS_3(fmulh, TCG_CALL_NO_RWG, i64, env, i64, i64) ++#ifndef CONFIG_USER_ONLY ++/* Scale factor for core3 cpu freq, ie number of ns per tick. */ ++#define CPUFREQ_SCALE 3 ++#endif ++ ++/* SLAVE FLOAT HELPER. */ +diff --git a/target/sw64/int_helper.c b/target/sw64/int_helper.c +new file mode 100644 +index 0000000000..131182585a +--- /dev/null ++++ b/target/sw64/int_helper.c +@@ -0,0 +1,118 @@ ++#include "qemu/osdep.h" ++#include "cpu.h" ++#include "exec/exec-all.h" ++#include "exec/helper-proto.h" ++#include "qemu/host-utils.h" ++#include "exec/memattrs.h" ++ ++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_cmpgeb(uint64_t va, uint64_t vb) ++{ ++ int i; ++ uint64_t ret = 0; ++ uint64_t tmp; ++ for (i = 0; i < 64; i += 8) { ++ tmp = ((va >> i) & 0xff) + (~(vb >> i) & 0xff) + 1; ++ ret |= (tmp >> 8) << (i / 8); ++ } ++ return ret; ++} ++ ++#ifndef CONFIG_USER_ONLY ++static inline MemTxAttrs cpu_get_mem_attrs(CPUSW64State *env) ++{ ++ return ((MemTxAttrs) { .secure = 1 }); ++} ++ ++static inline AddressSpace *cpu_addressspace(CPUState *cs, MemTxAttrs attrs) ++{ ++ return cpu_get_address_space(cs, cpu_asidx_from_attrs(cs, attrs)); ++} ++ ++uint64_t sw64_ldw_phys(CPUState *cs, hwaddr addr) ++{ ++ SW64CPU *cpu = SW64_CPU(cs); ++ int32_t ret; ++ CPUSW64State *env = &cpu->env; ++ MemTxAttrs attrs = cpu_get_mem_attrs(env); ++ AddressSpace *as = cpu_addressspace(cs, attrs); ++ ++ ret = (int32_t)address_space_ldl(as, addr, attrs, NULL); ++ ++ return (uint64_t)(int64_t)ret; ++} ++ ++void sw64_stw_phys(CPUState *cs, hwaddr addr, uint64_t val) ++{ ++ SW64CPU *cpu = SW64_CPU(cs); ++ CPUSW64State *env = &cpu->env; ++ MemTxAttrs attrs = cpu_get_mem_attrs(env); ++ AddressSpace *as = cpu_addressspace(cs, attrs); ++ ++ address_space_stl(as, addr, (uint32_t)val, attrs, NULL); ++} ++ ++uint64_t sw64_ldl_phys(CPUState *cs, hwaddr addr) ++{ ++ SW64CPU *cpu = SW64_CPU(cs); ++ CPUSW64State *env = &cpu->env; ++ MemTxAttrs attrs = cpu_get_mem_attrs(env); ++ AddressSpace *as = cpu_addressspace(cs, attrs); ++ ++ return address_space_ldq(as, addr, attrs, NULL); ++} ++ ++void sw64_stl_phys(CPUState *cs, hwaddr addr, uint64_t val) ++{ ++ SW64CPU *cpu = SW64_CPU(cs); ++ CPUSW64State *env = &cpu->env; ++ MemTxAttrs attrs = cpu_get_mem_attrs(env); ++ AddressSpace *as = cpu_addressspace(cs, attrs); ++ ++ address_space_stq(as, addr, val, attrs, NULL); ++} ++ ++uint64_t helper_pri_ldw(CPUSW64State *env, uint64_t hwaddr) ++{ ++ CPUState *cs = CPU(sw64_env_get_cpu(env)); ++ return sw64_ldw_phys(cs, hwaddr); ++} ++ ++void helper_pri_stw(CPUSW64State *env, uint64_t val, uint64_t hwaddr) ++{ ++ CPUState *cs = CPU(sw64_env_get_cpu(env)); ++ sw64_stw_phys(cs, hwaddr, val); ++} ++ ++uint64_t helper_pri_ldl(CPUSW64State *env, uint64_t hwaddr) ++{ ++ CPUState *cs = CPU(sw64_env_get_cpu(env)); ++ return sw64_ldl_phys(cs, hwaddr); ++} ++ ++void helper_pri_stl(CPUSW64State *env, uint64_t val, uint64_t hwaddr) ++{ ++ CPUState *cs = CPU(sw64_env_get_cpu(env)); ++ sw64_stl_phys(cs, hwaddr, val); ++} ++#endif +diff --git a/target/sw64/kvm.c b/target/sw64/kvm.c +new file mode 100644 +index 0000000000..fc134c83fb +--- /dev/null ++++ b/target/sw64/kvm.c +@@ -0,0 +1,215 @@ ++/* ++ * SW64 implementation of KVM hooks ++ * ++ * Copyright (c) 2018 Lin Hainan ++ * ++ * This work is licensed under the terms of the GNU GPL, version 2 or later. ++ * See the COPYING file in the top-level directory. ++ * ++ */ ++ ++#include "qemu/osdep.h" ++#include ++ ++#include ++ ++#include "qemu-common.h" ++#include "qemu/timer.h" ++#include "qemu/error-report.h" ++#include "sysemu/sysemu.h" ++#include "sysemu/kvm.h" ++#include "kvm_sw64.h" ++#include "cpu.h" ++#include "exec/memattrs.h" ++#include "exec/address-spaces.h" ++#include "hw/boards.h" ++#include "qemu/log.h" ++ ++#define init_pc 0xffffffff80011000 ++const KVMCapabilityInfo kvm_arch_required_capabilities[] = { ++ KVM_CAP_LAST_INFO ++}; ++/* 50000 jump to bootlader while 2f00000 jump to bios*/ ++int kvm_sw64_vcpu_init(CPUState *cs) ++{ ++ struct kvm_regs *regs; ++ SW64CPU *cpu = SW64_CPU(cs); ++ regs = (struct kvm_regs *)cpu->k_regs; ++ regs->pc = init_pc; ++ return kvm_vcpu_ioctl(cs, KVM_SET_REGS, ®s); ++} ++ ++static void kvm_sw64_host_cpu_class_init(ObjectClass *oc, void *data) ++{ ++} ++ ++static void kvm_sw64_host_cpu_initfn(Object *obj) ++{ ++} ++ ++ ++static const TypeInfo host_sw64_cpu_type_info = { ++ .name = TYPE_SW64_HOST_CPU, ++ .parent = TYPE_SW64_CPU, ++ .instance_init = kvm_sw64_host_cpu_initfn, ++ .class_init = kvm_sw64_host_cpu_class_init, ++ .class_size = sizeof(SW64HostCPUClass), ++}; ++ ++int kvm_arch_init(MachineState *ms, KVMState *s) ++{ ++ kvm_async_interrupts_allowed = true; ++ ++ type_register_static(&host_sw64_cpu_type_info); ++ ++ return 0; ++} ++ ++/* 50000 jump to bootlader while 2f00000 jump to bios*/ ++void kvm_sw64_reset_vcpu(SW64CPU *cpu) ++{ ++ CPUState *cs = CPU(cpu); ++ struct kvm_regs *regs; ++ int ret; ++ ++ regs = (struct kvm_regs *)cpu->k_regs; ++ regs->pc = init_pc; ++ ++ ret = kvm_vcpu_ioctl(cs, KVM_SET_REGS, ®s); ++ ++ if (ret < 0) { ++ fprintf(stderr, "kvm_sw64_vcpu_init failed: %s\n", strerror(-ret)); ++ abort(); ++ } ++ ++ ret = kvm_vcpu_ioctl(cs, KVM_SW64_VCPU_INIT, NULL); ++ ++ if (ret < 0) { ++ fprintf(stderr, "kvm_sw64_vcpu_init failed: %s\n", strerror(-ret)); ++ abort(); ++ } ++} ++ ++unsigned long kvm_arch_vcpu_id(CPUState *cpu) ++{ ++ return cpu->cpu_index; ++} ++ ++#include ++int kvm_arch_init_vcpu(CPUState *cs) ++{ ++ int ret; ++ ret = kvm_sw64_vcpu_init(cs); ++ if (ret) { ++ return ret; ++ } ++ return 0; ++} ++ ++int kvm_arch_destroy_vcpu(CPUState *cs) ++{ ++ return 0; ++} ++ ++int kvm_arch_get_registers(CPUState *cs) ++{ ++ int ret; ++ SW64CPU *cpu = SW64_CPU(cs); ++ ret = kvm_vcpu_ioctl(cs, KVM_GET_REGS, &cpu->k_regs); ++ if (ret < 0) ++ return ret; ++ return kvm_vcpu_ioctl(cs, KVM_SW64_GET_VCB, &cpu->k_vcb); ++} ++ ++int kvm_arch_put_registers(CPUState *cs, int level) ++{ ++ int ret; ++ SW64CPU *cpu = SW64_CPU(cs); ++ struct vcpucb *vcb; ++ ret = kvm_vcpu_ioctl(cs, KVM_SET_REGS, &cpu->k_regs); ++ if (ret < 0) ++ return ret; ++ vcb = (struct vcpucb *)cpu->k_vcb; ++ vcb->whami = kvm_arch_vcpu_id(cs); ++ fprintf(stderr,"vcpu %ld init.\n", vcb->whami); ++ return kvm_vcpu_ioctl(cs, KVM_SW64_SET_VCB, &cpu->k_vcb); ++} ++ ++int kvm_arch_add_msi_route_post(struct kvm_irq_routing_entry *route, ++ int vector, PCIDevice *dev) ++{ ++ return -1; ++} ++ ++int kvm_arch_fixup_msi_route(struct kvm_irq_routing_entry *route, ++ uint64_t address, uint32_t data, PCIDevice *dev) ++{ ++ return 0; ++} ++ ++void kvm_arch_pre_run(CPUState *cs, struct kvm_run *run) ++{ ++} ++ ++MemTxAttrs kvm_arch_post_run(CPUState *cs, struct kvm_run *run) ++{ ++ return MEMTXATTRS_UNSPECIFIED; ++} ++ ++ ++int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run) ++{ ++ return -1; ++} ++ ++bool kvm_arch_stop_on_emulation_error(CPUState *cs) ++{ ++ return true; ++} ++ ++int kvm_arch_process_async_events(CPUState *cs) ++{ ++ return 0; ++} ++ ++void kvm_arch_update_guest_debug(CPUState *cs, struct kvm_guest_debug *dbg) ++{ ++} ++ ++void kvm_arch_init_irq_routing(KVMState *s) ++{ ++ /* We know at this point that we're using the in-kernel ++ * irqchip, so we can use irqfds, and on x86 we know ++ * we can use msi via irqfd and GSI routing. ++ */ ++ kvm_msi_via_irqfd_allowed = true; ++ kvm_gsi_routing_allowed = true; ++} ++ ++int kvm_arch_irqchip_create(KVMState *s) ++{ ++ return 0; ++} ++ ++int kvm_arch_release_virq_post(int virq) ++{ ++ return -1; ++} ++ ++int kvm_arch_msi_data_to_gsi(uint32_t data) ++{ ++ return -1; ++} ++ ++ ++void kvm_sw64_register_slave(SW64CPU *cpu) ++{ ++ CPUState *cs = CPU(cpu); ++ ++ kvm_vcpu_ioctl(cs, KVM_SW64_USE_SLAVE, NULL); ++} ++ ++bool kvm_arch_cpu_check_are_resettable(void) ++{ ++ return true; ++} +diff --git a/target/sw64/kvm_sw64.h b/target/sw64/kvm_sw64.h +new file mode 100644 +index 0000000000..5ebd4ec6fd +--- /dev/null ++++ b/target/sw64/kvm_sw64.h +@@ -0,0 +1,47 @@ ++/* ++ * QEMU KVM support -- SW64 specific functions. ++ * ++ * Copyright (c) 2018 Lin Hainan ++ * ++ * This work is licensed under the terms of the GNU GPL, version 2 or later. ++ * See the COPYING file in the top-level directory. ++ * ++ */ ++ ++#ifndef QEMU_KVM_SW64_H ++#define QEMU_KVM_SW64_H ++ ++#include "sysemu/kvm.h" ++#include "exec/memory.h" ++#include "qemu/error-report.h" ++ ++/** ++ * kvm_sw64_vcpu_init: ++ * @cs: CPUState ++ * ++ * Initialize (or reinitialize) the VCPU by invoking the ++ * KVM_SW64_VCPU_INIT ioctl with the CPU type and feature ++ * bitmask specified in the CPUState. ++ * ++ * Returns: 0 if success else < 0 error code ++ */ ++int kvm_sw64_vcpu_init(CPUState *cs); ++void kvm_sw64_reset_vcpu(SW64CPU *cpu); ++void kvm_sw64_register_slave(SW64CPU *cpu); ++ ++#define TYPE_SW64_HOST_CPU "host-" TYPE_SW64_CPU ++#define SW64_HOST_CPU_CLASS(klass) \ ++ OBJECT_CLASS_CHECK(SW64HostCPUClass, (klass), TYPE_SW64_HOST_CPU) ++#define SW64_HOST_CPU_GET_CLASS(obj) \ ++ OBJECT_GET_CLASS(SW64HostCPUClass, (obj), TYPE_SW64_HOST_CPU) ++ ++typedef struct SW64HostCPUClass { ++ /*< private >*/ ++ SW64CPUClass parent_class; ++ /*< public >*/ ++ ++ uint64_t features; ++ uint32_t target; ++ const char *dtb_compatible; ++} SW64HostCPUClass; ++#endif +diff --git a/target/sw64/machine.c b/target/sw64/machine.c +new file mode 100644 +index 0000000000..df18d3faba +--- /dev/null ++++ b/target/sw64/machine.c +@@ -0,0 +1,18 @@ ++#include "qemu/osdep.h" ++#include "qemu-common.h" ++#include "cpu.h" ++#include "migration/vmstate.h" ++#include "migration/cpu.h" ++ ++VMStateDescription vmstate_sw64_cpu = { ++ .name = "cpu", ++ .version_id = 1, ++ .minimum_version_id = 1, ++ .fields = (VMStateField[]) { ++#ifdef CONFIG_KVM ++ VMSTATE_UINTTL_ARRAY(k_regs, SW64CPU, 158), ++ VMSTATE_UINTTL_ARRAY(k_vcb, SW64CPU, 36), ++#endif ++ VMSTATE_END_OF_LIST() ++ } ++}; +diff --git a/target/sw64/meson.build b/target/sw64/meson.build +new file mode 100644 +index 0000000000..ee49e45927 +--- /dev/null ++++ b/target/sw64/meson.build +@@ -0,0 +1,19 @@ ++sw64_ss = ss.source_set() ++sw64_ss.add(files( ++ 'cpu.c', ++ 'exception.c', ++ 'float_helper.c', ++ 'helper.c', ++ 'int_helper.c', ++ 'profile.c', ++ 'simd_helper.c', ++ 'translate.c', ++)) ++ ++sw64_ss.add(when: 'CONFIG_KVM', if_true: files('kvm.c')) ++ ++sw64_softmmu_ss = ss.source_set() ++sw64_softmmu_ss.add(files('machine.c')) ++ ++target_arch += {'sw64': sw64_ss} ++target_softmmu_arch += {'sw64': sw64_softmmu_ss} +diff --git a/target/sw64/profile.c b/target/sw64/profile.c +new file mode 100644 +index 0000000000..73fe077234 +--- /dev/null ++++ b/target/sw64/profile.c +@@ -0,0 +1,2342 @@ ++#include "translate.h" ++ ++const char *insn_opc[535] = { ++ "sys_call", "call", "ret", "jmp", "br", "bsr", "memb", "imemb", ++ "wmemb", "rtc", "rcid", "halt", "rd_f", "wr_f", "rtid", ++ "csrws", "csrwc", "pri_rcsr", "pri_wcsr", "pri_ret", "lldw", "lldl", ++ "ldw_inc", "ldl_inc", "ldw_dec", "ldl_dec", "ldw_set", "ldl_set", "lstw", ++ "lstl", "ldw_nc", "ldl_nc", "ldd_nc", "stw_nc", "stl_nc", "std_nc", ++ "ldwe", "ldse", "ldde", "vlds", "vldd", "vsts", "vstd", ++ "fimovs", "fimovd", "addw", "subw", "s4addw", "s4subw", "s8addw", ++ "s8subw", "addl", "subl", "s4addl", "s4subl", "s8addl", "s8subl", ++ "mulw", "divw", "udivw", "remw", "uremw", "mull", "mulh", ++ "divl", "udivl", "reml", "ureml", "addpi", "addpis", "cmpeq", ++ "cmplt", "cmple", "cmpult", "cmpule", "sbt", "cbt", "and", ++ "bic", "bis", "ornot", "xor", "eqv", "inslb", "inslh", ++ "inslw", "insll", "inshb", "inshh", "inshw", "inshl", "slll", ++ "srll", "sral", "roll", "sllw", "srlw", "sraw", "rolw", ++ "extlb", "extlh", "extlw", "extll", "exthb", "exthh", "exthw", ++ "exthl", "ctpop", "ctlz", "cttz", "revbh", "revbw", "revbl", ++ "casw", "casl", "masklb", "masklh", "masklw", "maskll", "maskhb", ++ "maskhh", "maskhw", "maskhl", "zap", "zapnot", "sextb", "sexth", ++ "seleq", "selge", "selgt", "selle", "sellt", "selne", "sellbc", ++ "sellbs", "addwi", "subwi", "s4addwi", "s4subwi", "s8addwi", "s8subwi", ++ "addli", "subli", "s4addli", "s4subli", "s8addli", "s8subli", "mulwi", ++ "divwi", "udivwi", "remwi", "uremwi", "mulli", "mulhi", "divli", ++ "udivli", "remli", "uremli", "addpii", "addpisi", "cmpeqi", "cmplti", ++ "cmplei", "cmpulti", "cmpulei", "sbti", "cbti", "andi", "bici", ++ "bisi", "ornoti", "xori", "eqvi", "inslbi", "inslhi", "inslwi", ++ "inslli", "inshbi", "inshhi", "inshwi", "inshli", "sllli", "srlli", ++ "srali", "rolli", "sllwi", "srlwi", "srawi", "rolwi", "extlbi", ++ "extlhi", "extlwi", "extlli", "exthbi", "exthhi", "exthwi", "exthli", ++ "ctpopi", "ctlzi", "cttzi", "revbhi", "revbwi", "revbli", "caswi", ++ "casli", "masklbi", "masklhi", "masklwi", "masklli", "maskhbi", "maskhhi", ++ "maskhwi", "maskhli", "zapi", "zapnoti", "sextbi", "sexthi", "cmpgebi", ++ "seleqi", "selgei", "selgti", "sellei", "sellti", "selnei", "sellbci", ++ "sellbsi", "vlogzz", "fadds", "faddd", "fsubs", "fsubd", "fmuls", ++ "fmuld", "fdivs", "fdivd", "fsqrts", "fsqrtd", "fcmpeq", "fcmple", ++ "fcmplt", "fcmpun", "fcvtsd", "fcvtds", "fcvtdl_g", "fcvtdl_p", "fcvtdl_z", ++ "fcvtdl_n", "fcvtdl", "fcvtwl", "fcvtlw", "fcvtls", "fcvtld", "fcpys", ++ "fcpyse", "fcpysn", "ifmovs", "ifmovd", "rfpcr", "wfpcr", "setfpec0", ++ "setfpec1", "setfpec2", "setfpec3", "frecs", "frecd", "fris", "fris_g", ++ "fris_p", "fris_z", "fris_n", "frid", "frid_g", "frid_p", "frid_z", ++ "frid_n", "fmas", "fmad", "fmss", "fmsd", "fnmas", "fnmad", ++ "fnmss", "fnmsd", "fseleq", "fselne", "fsellt", "fselle", "fselgt", ++ "fselge", "vaddw", "vaddwi", "vsubw", "vsubwi", "vcmpgew", "vcmpgewi", ++ "vcmpeqw", "vcmpeqwi", "vcmplew", "vcmplewi", "vcmpltw", "vcmpltwi", "vcmpulew", ++ "vcmpulewi", "vcmpultw", "vcmpultwi", "vsllw", "vsllwi", "vsrlw", "vsrlwi", ++ "vsraw", "vsrawi", "vrolw", "vrolwi", "sllow", "sllowi", "srlow", ++ "srlowi", "vaddl", "vaddli", "vsubl", "vsubli", "vsllb", "vsllbi", ++ "vsrlb", "vsrlbi", "vsrab", "vsrabi", "vrolb", "vrolbi", "vsllh", ++ "vsllhi", "vsrlh", "vsrlhi", "vsrah", "vsrahi", "vrolh", "vrolhi", ++ "ctpopow", "ctlzow", "vslll", "vsllli", "vsrll", "vsrlli", "vsral", ++ "vsrali", "vroll", "vrolli", "vmaxb", "vminb", "vucaddw", "vucaddwi", ++ "vucsubw", "vucsubwi", "vucaddh", "vucaddhi", "vucsubh", "vucsubhi", "vucaddb", ++ "vucaddbi", "vucsubb", "vucsubbi", "sraow", "sraowi", "vsumw", "vsuml", ++ "vsm4r", "vbinvw", "vcmpueqb", "vcmpugtb", "vcmpugtbi", "vsm3msw", "vmaxh", ++ "vminh", "vmaxw", "vminw", "vmaxl", "vminl", "vumaxb", "vuminb", ++ "vumaxh", "vuminh", "vumaxw", "vuminw", "vumaxl", "vuminl", "vsm4key", ++ "vadds", "vaddd", "vsubs", "vsubd", "vmuls", "vmuld", "vdivs", ++ "vdivd", "vsqrts", "vsqrtd", "vfcmpeq", "vfcmple", "vfcmplt", "vfcmpun", ++ "vcpys", "vcpyse", "vcpysn", "vsums", "vsumd", "vfcvtsd", "vfcvtds", ++ "vfcvtls", "vfcvtld", "vfcvtdl", "vfcvtdl_g", "vfcvtdl_p", "vfcvtdl_z", "vfcvtdl_n", ++ "vfris", "vfris_g", "vfris_p", "vfris_z", "vfris_n", "vfrid", "vfrid_g", ++ "vfrid_p", "vfrid_z", "vfrid_n", "vfrecs", "vfrecd", "vmaxs", "vmins", ++ "vmaxd", "vmind", "vmas", "vmad", "vmss", "vmsd", "vnmas", ++ "vnmad", "vnmss", "vnmsd", "vfseleq", "vfsellt", "vfselle", "vseleqw", ++ "vseleqwi", "vsellbcw", "vsellbcwi", "vselltw", "vselltwi", "vsellew", "vsellewi", ++ "vinsw", "vinsf", "vextw", "vextf", "vcpyw", "vcpyf", "vconw", ++ "vshfw", "vcons", "vcond", "vinsb", "vinsh", "vinsectlh", "vinsectlw", ++ "vinsectll", "vinsectlb", "vshfq", "vshfqb", "vcpyb", "vcpyh", "vsm3r", ++ "vfcvtsh", "vfcvths", "vldw_u", "vstw_u", "vlds_u", "vsts_u", "vldd_u", ++ "vstd_u", "vstw_ul", "vstw_uh", "vsts_ul", "vsts_uh", "vstd_ul", "vstd_uh", ++ "vldd_nc", "vstd_nc", "lbr", "ldbu_a", "ldhu_a", "ldw_a", "ldl_a", ++ "flds_a", "fldd_a", "stbu_a", "sthu_a", "stw_a", "stl_a", "fsts_a", ++ "fstd_a", "dpfhr", "dpfhw", "ldbu", "ldhu", "ldw", "ldl", ++ "ldl_u", "pri_ldl", "pri_ldw", "flds", "fldd", "stb", "sth", ++ "stw", "stl", "stl_u", "pri_stl", "pri_stw", "fsts", "fstd", ++ "beq", "bne", "blt", "ble", "bgt", "bge", "blbc", ++ "blbs", "fbeq", "fbne", "fblt", "fble", "fbgt", "fbge", ++ "ldih", "ldi", }; ++ ++void insn_profile(DisasContext *ctx, uint32_t insn) ++{ ++ int32_t disp16, disp26 __attribute__((unused)); ++ uint8_t opc; ++ uint16_t fn3, fn4, fn6, fn8, fn11; ++ TCGv count; ++ int index, offs; ++ ++ opc = extract32(insn, 26, 6); ++ ++ fn3 = extract32(insn, 10, 3); ++ fn6 = extract32(insn, 10, 6); ++ fn4 = extract32(insn, 12, 4); ++ fn8 = extract32(insn, 5, 8); ++ fn11 = extract32(insn, 5, 11); ++ ++ disp16 = sextract32(insn, 0, 16); ++ disp26 = sextract32(insn, 0, 26); ++ ++ index = 0; ++ switch (opc) { ++ case 0x00: ++ /* SYS_CALL */ ++ index = SYS_CALL; ++ break; ++ case 0x01: ++ /* CALL */ ++ index = CALL; ++ break; ++ case 0x02: ++ /* RET */ ++ index = RET; ++ break; ++ case 0x03: ++ /* JMP */ ++ index = JMP; ++ break; ++ case 0x04: ++ /* BR */ ++ index = BR; ++ break; ++ case 0x05: ++ /* BSR */ ++ index = BSR; ++ break; ++ case 0x06: ++ switch (disp16) { ++ case 0x0000: ++ /* MEMB */ ++ index = MEMB; ++ break; ++ case 0x0001: ++ /* IMEMB */ ++ index = IMEMB; ++ break; ++ case 0x0002: ++ /* WMEMB */ ++ index = WMEMB; ++ break; ++ case 0x0020: ++ /* RTC */ ++ index = RTC; ++ break; ++ case 0x0040: ++ /* RCID */ ++ index = RCID; ++ break; ++ case 0x0080: ++ /* HALT */ ++ index = HALT; ++ break; ++ case 0x1000: ++ /* RD_F */ ++ index = RD_F; ++ break; ++ case 0x1020: ++ /* WR_F */ ++ index = WR_F; ++ break; ++ case 0x1040: ++ /* RTID */ ++ index = RTID; ++ break; ++ default: ++ if ((disp16 & 0xFF00) == 0xFC00) { ++ /* CSRWS */ ++ index = CSRWS; ++ break; ++ } ++ if ((disp16 & 0xFF00) == 0xFD00) { ++ /* CSRWC */ ++ index = CSRWC; ++ break; ++ } ++ if ((disp16 & 0xFF00) == 0xFE00) { ++ /* PRI_RCSR */ ++ index = PRI_RCSR; ++ break; ++ } ++ if ((disp16 & 0xFF00) == 0xFF00) { ++ /* PRI_WCSR */ ++ index = PRI_WCSR; ++ break; ++ } ++ goto do_invalid; ++ } ++ break; ++ case 0x07: ++ /* PRI_RET */ ++ index = PRI_RET; ++ break; ++ case 0x08: ++ switch (fn4) { ++ case 0x0: ++ /* LLDW */ ++ index = LLDW; ++ break; ++ case 0x1: ++ /* LLDL */ ++ index = LLDL; ++ break; ++ case 0x2: ++ /* LDW_INC */ ++ index = LDW_INC; ++ break; ++ case 0x3: ++ /* LDL_INC */ ++ index = LDL_INC; ++ break; ++ case 0x4: ++ /* LDW_DEC */ ++ index = LDW_DEC; ++ break; ++ case 0x5: ++ /* LDL_DEC */ ++ index = LDL_DEC; ++ break; ++ case 0x6: ++ /* LDW_SET */ ++ index = LDW_SET; ++ break; ++ case 0x7: ++ /* LDL_SET */ ++ index = LDL_SET; ++ break; ++ case 0x8: ++ /* LSTW */ ++ index = LSTW; ++ break; ++ case 0x9: ++ /* LSTL */ ++ index = LSTL; ++ break; ++ case 0xa: ++ /* LDW_NC */ ++ index = LDW_NC; ++ break; ++ case 0xb: ++ /* LDL_NC */ ++ index = LDL_NC; ++ break; ++ case 0xc: ++ /* LDD_NC */ ++ index = LDD_NC; ++ break; ++ case 0xd: ++ /* STW_NC */ ++ index = STW_NC; ++ break; ++ case 0xe: ++ /* STL_NC */ ++ index = STL_NC; ++ break; ++ case 0xf: ++ /* STD_NC */ ++ index = STD_NC; ++ break; ++ default: ++ goto do_invalid; ++ } ++ break; ++ case 0x9: ++ /* LDWE */ ++ index = LDWE; ++ break; ++ case 0x0a: ++ /* LDSE */ ++ index = LDSE; ++ break; ++ case 0x0b: ++ /* LDDE */ ++ index = LDDE; ++ break; ++ case 0x0c: ++ /* VLDS */ ++ index = VLDS; ++ break; ++ case 0x0d: ++ /* VLDD */ ++ index = VLDD; ++ break; ++ case 0x0e: ++ /* VSTS */ ++ index = VSTS; ++ break; ++ case 0x0f: ++ /* VSTD */ ++ index = VSTD; ++ break; ++ case 0x10: ++ if (fn11 == 0x70) { ++ /* FIMOVS */ ++ index = FIMOVS; ++ } else if (fn11 == 0x78) { ++ /* FIMOVD */ ++ index = FIMOVD; ++ } else { ++ switch (fn11 & 0xff) { ++ case 0x00: ++ /* ADDW */ ++ index = ADDW; ++ break; ++ case 0x01: ++ /* SUBW */ ++ index = SUBW; ++ break; ++ case 0x02: ++ /* S4ADDW */ ++ index = S4ADDW; ++ break; ++ case 0x03: ++ /* S4SUBW */ ++ index = S4SUBW; ++ break; ++ case 0x04: ++ /* S8ADDW */ ++ index = S8ADDW; ++ break; ++ case 0x05: ++ /* S8SUBW */ ++ index = S8SUBW; ++ break; ++ ++ case 0x08: ++ /* ADDL */ ++ index = ADDL; ++ break; ++ case 0x09: ++ /* SUBL */ ++ index = SUBL; ++ break; ++ case 0x0a: ++ /* S4ADDL */ ++ index = S4ADDL; ++ break; ++ case 0x0b: ++ /* S4SUBL */ ++ index = S4SUBL; ++ break; ++ case 0x0c: ++ /* S8ADDL */ ++ index = S8ADDL; ++ break; ++ case 0x0d: ++ /* S8SUBL */ ++ index = S8SUBL; ++ break; ++ case 0x10: ++ /* MULW */ ++ index = MULW; ++ break; ++ case 0x11: ++ /* DIVW */ ++ index = DIVW; ++ break; ++ case 0x12: ++ /* UDIVW */ ++ index = UDIVW; ++ break; ++ case 0x13: ++ /* REMW */ ++ index = REMW; ++ break; ++ case 0x14: ++ /* UREMW */ ++ index = UREMW; ++ break; ++ case 0x18: ++ /* MULL */ ++ index = MULL; ++ break; ++ case 0x19: ++ /* MULH */ ++ index = MULH; ++ break; ++ case 0x1A: ++ /* DIVL */ ++ index = DIVL; ++ break; ++ case 0x1B: ++ /* UDIVL */ ++ index = UDIVL; ++ break; ++ case 0x1C: ++ /* REML */ ++ index = REML; ++ break; ++ case 0x1D: ++ /* UREML */ ++ index = UREML; ++ break; ++ case 0x1E: ++ /* ADDPI */ ++ index = ADDPI; ++ break; ++ case 0x1F: ++ /* ADDPIS */ ++ index = ADDPIS; ++ break; ++ case 0x28: ++ /* CMPEQ */ ++ index = CMPEQ; ++ break; ++ case 0x29: ++ /* CMPLT */ ++ index = CMPLT; ++ break; ++ case 0x2a: ++ /* CMPLE */ ++ index = CMPLE; ++ break; ++ case 0x2b: ++ /* CMPULT */ ++ index = CMPULT; ++ break; ++ case 0x2c: ++ /* CMPULE */ ++ index = CMPULE; ++ break; ++ case 0x2D: ++ /* SBT */ ++ index = SBT; ++ break; ++ case 0x2E: ++ /* CBT */ ++ index = CBT; ++ break; ++ case 0x38: ++ /* AND */ ++ index = AND; ++ break; ++ case 0x39: ++ /* BIC */ ++ index = BIC; ++ break; ++ case 0x3a: ++ /* BIS */ ++ index = BIS; ++ break; ++ case 0x3b: ++ /* ORNOT */ ++ index = ORNOT; ++ break; ++ case 0x3c: ++ /* XOR */ ++ index = XOR; ++ break; ++ case 0x3d: ++ /* EQV */ ++ index = EQV; ++ break; ++ case 0x40: ++ /* INSLB */ ++ index = INSLB; ++ break; ++ case 0x41: ++ /* INSLH */ ++ index = INSLH; ++ break; ++ case 0x42: ++ /* INSLW */ ++ index = INSLW; ++ break; ++ case 0x43: ++ /* INSLL */ ++ index = INSLL; ++ break; ++ case 0x44: ++ /* INSHB */ ++ index = INSHB; ++ break; ++ case 0x45: ++ /* INSHH */ ++ index = INSHH; ++ break; ++ case 0x46: ++ /* INSHW */ ++ index = INSHW; ++ break; ++ case 0x47: ++ /* INSHL */ ++ index = INSHL; ++ break; ++ case 0x48: ++ /* SLLL */ ++ index = SLLL; ++ break; ++ case 0x49: ++ /* SRLL */ ++ index = SRLL; ++ break; ++ case 0x4a: ++ /* SRAL */ ++ index = SRAL; ++ break; ++ case 0x4B: ++ /* ROLL */ ++ index = ROLL; ++ break; ++ case 0x4C: ++ /* SLLW */ ++ index = SLLW; ++ break; ++ case 0x4D: ++ /* SRLW */ ++ index = SRLW; ++ break; ++ case 0x4E: ++ /* SRAW */ ++ index = SRAW; ++ break; ++ case 0x4F: ++ /* ROLW */ ++ index = ROLW; ++ break; ++ case 0x50: ++ /* EXTLB */ ++ index = EXTLB; ++ break; ++ case 0x51: ++ /* EXTLH */ ++ index = EXTLH; ++ break; ++ case 0x52: ++ /* EXTLW */ ++ index = EXTLW; ++ break; ++ case 0x53: ++ /* EXTLL */ ++ index = EXTLL; ++ break; ++ case 0x54: ++ /* EXTHB */ ++ index = EXTHB; ++ break; ++ case 0x55: ++ /* EXTHH */ ++ index = EXTHH; ++ break; ++ case 0x56: ++ /* EXTHW */ ++ index = EXTHW; ++ break; ++ case 0x57: ++ /* EXTHL */ ++ index = EXTHL; ++ break; ++ case 0x58: ++ /* CTPOP */ ++ index = CTPOP; ++ break; ++ case 0x59: ++ /* CTLZ */ ++ index = CTLZ; ++ break; ++ case 0x5a: ++ /* CTTZ */ ++ index = CTTZ; ++ break; ++ case 0x5B: ++ /* REVBH */ ++ index = REVBH; ++ break; ++ case 0x5C: ++ /* REVBW */ ++ index = REVBW; ++ break; ++ case 0x5D: ++ /* REVBL */ ++ index = REVBL; ++ break; ++ case 0x5E: ++ /* CASW */ ++ index = CASW; ++ break; ++ case 0x5F: ++ /* CASL */ ++ index = CASL; ++ break; ++ case 0x60: ++ /* MASKLB */ ++ index = MASKLB; ++ break; ++ case 0x61: ++ /* MASKLH */ ++ index = MASKLH; ++ break; ++ case 0x62: ++ /* MASKLW */ ++ index = MASKLW; ++ break; ++ case 0x63: ++ /* MASKLL */ ++ index = MASKLL; ++ break; ++ case 0x64: ++ /* MASKHB */ ++ index = MASKHB; ++ break; ++ case 0x65: ++ /* MASKHH */ ++ index = MASKHH; ++ break; ++ case 0x66: ++ /* MASKHW */ ++ index = MASKHW; ++ break; ++ case 0x67: ++ /* MASKHL */ ++ index = MASKHL; ++ break; ++ case 0x68: ++ /* ZAP */ ++ index = ZAP; ++ break; ++ case 0x69: ++ /* ZAPNOT */ ++ index = ZAPNOT; ++ break; ++ case 0x6a: ++ /* SEXTB */ ++ index = SEXTB; ++ break; ++ case 0x6b: ++ /* SEXTH */ ++ index = SEXTH; ++ break; ++ case 0x6c: ++ /* CMPGEB*/ ++ break; ++ default: ++ break; ++ } ++ } ++ break; ++ case 0x11: ++ switch (fn3) { ++ case 0x0: ++ /* SELEQ */ ++ index = SELEQ; ++ break; ++ case 0x1: ++ /* SELGE */ ++ index = SELGE; ++ break; ++ case 0x2: ++ /* SELGT */ ++ index = SELGT; ++ break; ++ case 0x3: ++ /* SELLE */ ++ index = SELLE; ++ break; ++ case 0x4: ++ /* SELLT */ ++ index = SELLT; ++ break; ++ case 0x5: ++ /* SELNE */ ++ index = SELNE; ++ break; ++ case 0x6: ++ /* SELLBC */ ++ index = SELLBC; ++ break; ++ case 0x7: ++ /* SELLBS */ ++ index = SELLBS; ++ break; ++ default: ++ break; ++ } ++ break; ++ case 0x12: ++ switch (fn8 & 0xff) { ++ case 0x00: ++ /* ADDWI */ ++ index = ADDWI; ++ break; ++ case 0x01: ++ /* SUBWI */ ++ index = SUBWI; ++ break; ++ case 0x02: ++ /* S4ADDWI */ ++ index = S4ADDWI; ++ break; ++ case 0x03: ++ /* S4SUBWI */ ++ index = S4SUBWI; ++ break; ++ case 0x04: ++ /* S8ADDWI */ ++ index = S8ADDWI; ++ break; ++ case 0x05: ++ /* S8SUBWI */ ++ index = S8SUBWI; ++ break; ++ ++ case 0x08: ++ /* ADDLI */ ++ index = ADDLI; ++ break; ++ case 0x09: ++ /* SUBLI */ ++ index = SUBLI; ++ break; ++ case 0x0a: ++ /* S4ADDLI */ ++ index = S4ADDLI; ++ break; ++ case 0x0b: ++ /* S4SUBLI */ ++ index = S4SUBLI; ++ break; ++ case 0x0c: ++ /* S8ADDLI */ ++ index = S8ADDLI; ++ break; ++ case 0x0d: ++ /* S8SUBLI */ ++ index = S8SUBLI; ++ break; ++ case 0x10: ++ /* MULWI */ ++ index = MULWI; ++ break; ++ case 0x11: ++ /* DIVWI */ ++ index = DIVWI; ++ break; ++ case 0x12: ++ /* UDIVWI */ ++ index = UDIVWI; ++ break; ++ case 0x13: ++ /* REMWI */ ++ index = REMWI; ++ break; ++ case 0x14: ++ /* UREMWI */ ++ index = UREMWI; ++ break; ++ case 0x18: ++ /* MULLI */ ++ index = MULLI; ++ break; ++ case 0x19: ++ /* MULHI */ ++ index = MULHI; ++ break; ++ case 0x1A: ++ /* DIVLI */ ++ index = DIVLI; ++ break; ++ case 0x1B: ++ /* UDIVLI */ ++ index = UDIVLI; ++ break; ++ case 0x1C: ++ /* REMLI */ ++ index = REMLI; ++ break; ++ case 0x1D: ++ /* UREMLI */ ++ index = UREMLI; ++ break; ++ case 0x1E: ++ /* ADDPII */ ++ index = ADDPII; ++ break; ++ case 0x1F: ++ /* ADDPISI */ ++ index = ADDPISI; ++ break; ++ case 0x28: ++ /* CMPEQI */ ++ index = CMPEQI; ++ break; ++ case 0x29: ++ /* CMPLTI */ ++ index = CMPLTI; ++ break; ++ case 0x2a: ++ /* CMPLEI */ ++ index = CMPLEI; ++ break; ++ case 0x2b: ++ /* CMPULTI */ ++ index = CMPULTI; ++ break; ++ case 0x2c: ++ /* CMPULEI */ ++ index = CMPULEI; ++ break; ++ case 0x2D: ++ /* SBTI */ ++ index = SBTI; ++ break; ++ case 0x2E: ++ /* CBTI */ ++ index = CBTI; ++ break; ++ case 0x38: ++ /* ANDI */ ++ index = ANDI; ++ break; ++ case 0x39: ++ /* BICI */ ++ index = BICI; ++ break; ++ case 0x3a: ++ /* BISI */ ++ index = BISI; ++ break; ++ case 0x3b: ++ /* ORNOTI */ ++ index = ORNOTI; ++ break; ++ case 0x3c: ++ /* XORI */ ++ index = XORI; ++ break; ++ case 0x3d: ++ /* EQVI */ ++ index = EQVI; ++ break; ++ case 0x40: ++ /* INSLBI */ ++ index = INSLBI; ++ break; ++ case 0x41: ++ /* INSLHI */ ++ index = INSLHI; ++ break; ++ case 0x42: ++ /* INSLWI */ ++ index = INSLWI; ++ break; ++ case 0x43: ++ /* INSLLI */ ++ index = INSLLI; ++ break; ++ case 0x44: ++ /* INSHBI */ ++ index = INSHBI; ++ break; ++ case 0x45: ++ /* INSHHI */ ++ index = INSHHI; ++ break; ++ case 0x46: ++ /* INSHWI */ ++ index = INSHWI; ++ break; ++ case 0x47: ++ /* INSHLI */ ++ index = INSHLI; ++ break; ++ case 0x48: ++ /* SLLLI */ ++ index = SLLLI; ++ break; ++ case 0x49: ++ /* SRLLI */ ++ index = SRLLI; ++ break; ++ case 0x4a: ++ /* SRALI */ ++ index = SRALI; ++ break; ++ case 0x4B: ++ /* ROLLI */ ++ index = ROLLI; ++ break; ++ case 0x4C: ++ /* SLLWI */ ++ index = SLLWI; ++ break; ++ case 0x4D: ++ /* SRLWI */ ++ index = SRLWI; ++ break; ++ case 0x4E: ++ /* SRAWI */ ++ index = SRAWI; ++ break; ++ case 0x4F: ++ /* ROLWI */ ++ index = ROLWI; ++ break; ++ case 0x50: ++ /* EXTLBI */ ++ index = EXTLBI; ++ break; ++ case 0x51: ++ /* EXTLHI */ ++ index = EXTLHI; ++ break; ++ case 0x52: ++ /* EXTLWI */ ++ index = EXTLWI; ++ break; ++ case 0x53: ++ /* EXTLLI */ ++ index = EXTLLI; ++ break; ++ case 0x54: ++ /* EXTHBI */ ++ index = EXTHBI; ++ break; ++ case 0x55: ++ /* EXTHHI */ ++ index = EXTHHI; ++ break; ++ case 0x56: ++ /* EXTHWI */ ++ index = EXTHWI; ++ break; ++ case 0x57: ++ /* EXTHLI */ ++ index = EXTHLI; ++ break; ++ case 0x58: ++ /* CTPOPI */ ++ index = CTPOPI; ++ break; ++ case 0x59: ++ /* CTLZI */ ++ index = CTLZI; ++ break; ++ case 0x5a: ++ /* CTTZI */ ++ index = CTTZI; ++ break; ++ case 0x5B: ++ /* REVBHI */ ++ index = REVBHI; ++ break; ++ case 0x5C: ++ /* REVBWI */ ++ index = REVBWI; ++ break; ++ case 0x5D: ++ /* REVBLI */ ++ index = REVBLI; ++ break; ++ case 0x5E: ++ /* CASWI */ ++ index = CASWI; ++ break; ++ case 0x5F: ++ /* CASLI */ ++ index = CASLI; ++ break; ++ case 0x60: ++ /* MASKLBI */ ++ index = MASKLBI; ++ break; ++ case 0x61: ++ /* MASKLHI */ ++ index = MASKLHI; ++ break; ++ case 0x62: ++ /* MASKLWI */ ++ index = MASKLWI; ++ break; ++ case 0x63: ++ /* MASKLLI */ ++ index = MASKLLI; ++ break; ++ case 0x64: ++ /* MASKHBI */ ++ index = MASKHBI; ++ break; ++ case 0x65: ++ /* MASKHHI */ ++ index = MASKHHI; ++ break; ++ case 0x66: ++ /* MASKHWI */ ++ index = MASKHWI; ++ break; ++ case 0x67: ++ /* MASKHLI */ ++ index = MASKHLI; ++ break; ++ case 0x68: ++ /* ZAPI */ ++ index = ZAPI; ++ break; ++ case 0x69: ++ /* ZAPNOTI */ ++ index = ZAPNOTI; ++ break; ++ case 0x6a: ++ /* SEXTBI */ ++ index = SEXTBI; ++ break; ++ case 0x6b: ++ /* SEXTHI */ ++ index = SEXTHI; ++ break; ++ case 0x6c: ++ /* CMPGEBI */ ++ index = CMPGEBI; ++ break; ++ default: ++ break; ++ } ++ break; ++ case 0x13: ++ switch (fn3) { ++ case 0x0: ++ /* SELEQI */ ++ index = SELEQI; ++ break; ++ case 0x1: ++ /* SELGEI */ ++ index = SELGEI; ++ break; ++ case 0x2: ++ /* SELGTI */ ++ index = SELGTI; ++ break; ++ case 0x3: ++ /* SELLEI */ ++ index = SELLEI; ++ break; ++ case 0x4: ++ /* SELLTI */ ++ index = SELLTI; ++ break; ++ case 0x5: ++ /* SELNEI */ ++ index = SELNEI; ++ break; ++ case 0x6: ++ /* SELLBCI */ ++ index = SELLBCI; ++ break; ++ case 0x7: ++ /* SELLBSI */ ++ index = SELLBSI; ++ break; ++ default: ++ break; ++ } ++ break; ++ case 0x14: ++ case 0x15: ++ case 0x16: ++ case 0x17: ++ /* VLOGZZ */ ++ index = VLOGZZ; ++ break; ++ case 0x18: ++ switch (fn8) { ++ case 0x00: ++ /* FADDS */ ++ index = FADDS; ++ break; ++ case 0x01: ++ /* FADDD */ ++ index = FADDD; ++ break; ++ case 0x02: ++ /* FSUBS */ ++ index = FSUBS; ++ break; ++ case 0x03: ++ /* FSUBD */ ++ index = FSUBD; ++ break; ++ case 0x4: ++ /* FMULS */ ++ index = FMULS; ++ break; ++ case 0x05: ++ /* FMULD */ ++ index = FMULD; ++ break; ++ case 0x06: ++ /* FDIVS */ ++ index = FDIVS; ++ break; ++ case 0x07: ++ /* FDIVD */ ++ index = FDIVD; ++ break; ++ case 0x08: ++ /* FSQRTS */ ++ index = FSQRTS; ++ break; ++ case 0x09: ++ /* FSQRTD */ ++ index = FSQRTD; ++ break; ++ case 0x10: ++ /* FCMPEQ */ ++ index = FCMPEQ; ++ break; ++ case 0x11: ++ /* FCMPLE */ ++ index = FCMPLE; ++ break; ++ case 0x12: ++ /* FCMPLT */ ++ index = FCMPLT; ++ break; ++ case 0x13: ++ /* FCMPUN */ ++ index = FCMPUN; ++ break; ++ case 0x20: ++ /* FCVTSD */ ++ index = FCVTSD; ++ break; ++ case 0x21: ++ /* FCVTDS */ ++ index = FCVTDS; ++ break; ++ case 0x22: ++ /* FCVTDL_G */ ++ index = FCVTDL_G; ++ break; ++ case 0x23: ++ /* FCVTDL_P */ ++ index = FCVTDL_P; ++ break; ++ case 0x24: ++ /* FCVTDL_Z */ ++ index = FCVTDL_Z; ++ break; ++ case 0x25: ++ /* FCVTDL_N */ ++ index = FCVTDL_N; ++ break; ++ case 0x27: ++ /* FCVTDL */ ++ index = FCVTDL; ++ break; ++ case 0x28: ++ /* FCVTWL */ ++ index = FCVTWL; ++ break; ++ case 0x29: ++ /* FCVTLW */ ++ index = FCVTLW; ++ break; ++ case 0x2d: ++ /* FCVTLS */ ++ index = FCVTLS; ++ break; ++ case 0x2f: ++ /* FCVTLD */ ++ index = FCVTLD; ++ break; ++ case 0x30: ++ /* FCPYS */ ++ index = FCPYS; ++ break; ++ case 0x31: ++ /* FCPYSE */ ++ index = FCPYSE; ++ break; ++ case 0x32: ++ /* FCPYSN */ ++ index = FCPYSN; ++ break; ++ case 0x40: ++ /* IFMOVS */ ++ index = IFMOVS; ++ break; ++ case 0x41: ++ /* IFMOVD */ ++ index = IFMOVD; ++ break; ++ case 0x50: ++ /* RFPCR */ ++ index = RFPCR; ++ break; ++ case 0x51: ++ /* WFPCR */ ++ index = WFPCR; ++ break; ++ case 0x54: ++ /* SETFPEC0 */ ++ index = SETFPEC0; ++ break; ++ case 0x55: ++ /* SETFPEC1 */ ++ index = SETFPEC1; ++ break; ++ case 0x56: ++ /* SETFPEC2 */ ++ index = SETFPEC2; ++ break; ++ case 0x57: ++ /* SETFPEC3 */ ++ index = SETFPEC3; ++ break; ++ case 0x58: ++ /* FRECS */ ++ index = FRECS; ++ break; ++ case 0x59: ++ /* FRECD */ ++ index = FRECD; ++ break; ++ case 0x5A: ++ /* FRIS */ ++ index = FRIS; ++ break; ++ case 0x5B: ++ /* FRIS_G */ ++ index = FRIS_G; ++ break; ++ case 0x5C: ++ /* FRIS_P */ ++ index = FRIS_P; ++ break; ++ case 0x5D: ++ /* FRIS_Z */ ++ index = FRIS_Z; ++ break; ++ case 0x5F: ++ /* FRIS_N */ ++ index = FRIS_N; ++ break; ++ case 0x60: ++ /* FRID */ ++ index = FRID; ++ break; ++ case 0x61: ++ /* FRID_G */ ++ index = FRID_G; ++ break; ++ case 0x62: ++ /* FRID_P */ ++ index = FRID_P; ++ break; ++ case 0x63: ++ /* FRID_Z */ ++ index = FRID_Z; ++ break; ++ case 0x64: ++ /* FRID_N */ ++ index = FRID_N; ++ break; ++ default: ++ break; ++ } ++ break; ++ case 0x19: ++ switch (fn6) { ++ case 0x00: ++ /* FMAS */ ++ index = FMAS; ++ break; ++ case 0x01: ++ /* FMAD */ ++ index = FMAD; ++ break; ++ case 0x02: ++ /* FMSS */ ++ index = FMSS; ++ break; ++ case 0x03: ++ /* FMSD */ ++ index = FMSD; ++ break; ++ case 0x04: ++ /* FNMAS */ ++ index = FNMAS; ++ break; ++ case 0x05: ++ /* FNMAD */ ++ index = FNMAD; ++ break; ++ case 0x06: ++ /* FNMSS */ ++ index = FNMSS; ++ break; ++ case 0x07: ++ /* FNMSD */ ++ index = FNMSD; ++ break; ++ case 0x10: ++ /* FSELEQ */ ++ index = FSELEQ; ++ break; ++ case 0x11: ++ /* FSELNE */ ++ index = FSELNE; ++ break; ++ case 0x12: ++ /* FSELLT */ ++ index = FSELLT; ++ break; ++ case 0x13: ++ /* FSELLE */ ++ index = FSELLE; ++ break; ++ case 0x14: ++ /* FSELGT */ ++ index = FSELGT; ++ break; ++ case 0x15: ++ /* FSELGE */ ++ index = FSELGE; ++ break; ++ default: ++ break; ++ } ++ break; ++ case 0x1A: ++ switch (fn8) { ++ case 0x00: ++ /* VADDW */ ++ index = VADDW; ++ break; ++ case 0x20: ++ /* VADDWI */ ++ index = VADDWI; ++ break; ++ case 0x01: ++ /* VSUBW */ ++ index = VSUBW; ++ break; ++ case 0x21: ++ /* VSUBWI */ ++ index = VSUBWI; ++ break; ++ case 0x02: ++ /* VCMPGEW */ ++ index = VCMPGEW; ++ break; ++ case 0x22: ++ /* VCMPGEWI */ ++ index = VCMPGEWI; ++ break; ++ case 0x03: ++ /* VCMPEQW */ ++ index = VCMPEQW; ++ break; ++ case 0x23: ++ /* VCMPEQWI */ ++ index = VCMPEQWI; ++ break; ++ case 0x04: ++ /* VCMPLEW */ ++ index = VCMPLEW; ++ break; ++ case 0x24: ++ /* VCMPLEWI */ ++ index = VCMPLEWI; ++ break; ++ case 0x05: ++ /* VCMPLTW */ ++ index = VCMPLTW; ++ break; ++ case 0x25: ++ /* VCMPLTWI */ ++ index = VCMPLTWI; ++ break; ++ case 0x06: ++ /* VCMPULEW */ ++ index = VCMPULEW; ++ break; ++ case 0x26: ++ /* VCMPULEWI */ ++ index = VCMPULEWI; ++ break; ++ case 0x07: ++ /* VCMPULTW */ ++ index = VCMPULTW; ++ break; ++ case 0x27: ++ /* VCMPULTWI */ ++ index = VCMPULTWI; ++ break; ++ case 0x08: ++ /* VSLLW */ ++ index = VSLLW; ++ break; ++ case 0x28: ++ /* VSLLWI */ ++ index = VSLLWI; ++ break; ++ case 0x09: ++ /* VSRLW */ ++ index = VSRLW; ++ break; ++ case 0x29: ++ /* VSRLWI */ ++ index = VSRLWI; ++ break; ++ case 0x0A: ++ /* VSRAW */ ++ index = VSRAW; ++ break; ++ case 0x2A: ++ /* VSRAWI */ ++ index = VSRAWI; ++ break; ++ case 0x0B: ++ /* VROLW */ ++ index = VROLW; ++ break; ++ case 0x2B: ++ /* VROLWI */ ++ index = VROLWI; ++ break; ++ case 0x0C: ++ /* SLLOW */ ++ index = SLLOW; ++ break; ++ case 0x2C: ++ /* SLLOWI */ ++ index = SLLOWI; ++ break; ++ case 0x0D: ++ /* SRLOW */ ++ index = SRLOW; ++ break; ++ case 0x2D: ++ /* SRLOWI */ ++ index = SRLOWI; ++ break; ++ case 0x0E: ++ /* VADDL */ ++ index = VADDL; ++ break; ++ case 0x2E: ++ /* VADDLI */ ++ index = VADDLI; ++ break; ++ case 0x0F: ++ /* VSUBL */ ++ index = VSUBL; ++ break; ++ case 0x2F: ++ /* VSUBLI */ ++ index = VSUBLI; ++ break; ++ case 0x10: ++ /* VSLLB */ ++ index = VSLLB; ++ break; ++ case 0x30: ++ /* VSLLBI */ ++ index = VSLLBI; ++ break; ++ case 0x11: ++ /* VSRLB */ ++ index = VSRLB; ++ break; ++ case 0x31: ++ /* VSRLBI */ ++ index = VSRLBI; ++ break; ++ case 0x12: ++ /* VSRAB */ ++ index = VSRAB; ++ break; ++ case 0x32: ++ /* VSRABI */ ++ index = VSRABI; ++ break; ++ case 0x13: ++ /* VROLB */ ++ index = VROLB; ++ break; ++ case 0x33: ++ /* VROLBI */ ++ index = VROLBI; ++ break; ++ case 0x14: ++ /* VSLLH */ ++ index = VSLLH; ++ break; ++ case 0x34: ++ /* VSLLHI */ ++ index = VSLLHI; ++ break; ++ case 0x15: ++ /* VSRLH */ ++ index = VSRLH; ++ break; ++ case 0x35: ++ /* VSRLHI */ ++ index = VSRLHI; ++ break; ++ case 0x16: ++ /* VSRAH */ ++ index = VSRAH; ++ break; ++ case 0x36: ++ /* VSRAHI */ ++ index = VSRAHI; ++ break; ++ case 0x17: ++ /* VROLH */ ++ index = VROLH; ++ break; ++ case 0x37: ++ /* VROLHI */ ++ index = VROLHI; ++ break; ++ case 0x18: ++ /* CTPOPOW */ ++ index = CTPOPOW; ++ break; ++ case 0x19: ++ /* CTLZOW */ ++ index = CTLZOW; ++ break; ++ case 0x1A: ++ /* VSLLL */ ++ index = VSLLL; ++ break; ++ case 0x3A: ++ /* VSLLLI */ ++ index = VSLLLI; ++ break; ++ case 0x1B: ++ /* VSRLL */ ++ index = VSRLL; ++ break; ++ case 0x3B: ++ /* VSRLLI */ ++ index = VSRLLI; ++ break; ++ case 0x1C: ++ /* VSRAL */ ++ index = VSRAL; ++ break; ++ case 0x3C: ++ /* VSRALI */ ++ index = VSRALI; ++ break; ++ case 0x1D: ++ /* VROLL */ ++ index = VROLL; ++ break; ++ case 0x3D: ++ /* VROLLI */ ++ index = VROLLI; ++ break; ++ case 0x1E: ++ /* VMAXB */ ++ index = VMAXB; ++ break; ++ case 0x1F: ++ /* VMINB */ ++ index = VMINB; ++ break; ++ case 0x40: ++ /* VUCADDW */ ++ index = VUCADDW; ++ break; ++ case 0x60: ++ /* VUCADDWI */ ++ index = VUCADDWI; ++ break; ++ case 0x41: ++ /* VUCSUBW */ ++ index = VUCSUBW; ++ break; ++ case 0x61: ++ /* VUCSUBWI */ ++ index = VUCSUBWI; ++ break; ++ case 0x42: ++ /* VUCADDH */ ++ index = VUCADDH; ++ break; ++ case 0x62: ++ /* VUCADDHI */ ++ index = VUCADDHI; ++ break; ++ case 0x43: ++ /* VUCSUBH */ ++ index = VUCSUBH; ++ break; ++ case 0x63: ++ /* VUCSUBHI */ ++ index = VUCSUBHI; ++ break; ++ case 0x44: ++ /* VUCADDB */ ++ index = VUCADDB; ++ break; ++ case 0x64: ++ /* VUCADDBI */ ++ index = VUCADDBI; ++ break; ++ case 0x45: ++ /* VUCSUBB */ ++ index = VUCSUBB; ++ break; ++ case 0x65: ++ /* VUCSUBBI */ ++ index = VUCSUBBI; ++ break; ++ case 0x46: ++ /* SRAOW */ ++ index = SRAOW; ++ break; ++ case 0x66: ++ /* SRAOWI */ ++ index = SRAOWI; ++ break; ++ case 0x47: ++ /* VSUMW */ ++ index = VSUMW; ++ break; ++ case 0x48: ++ /* VSUML */ ++ index = VSUML; ++ break; ++ case 0x49: ++ /* VSM4R */ ++ index = VSM4R; ++ break; ++ case 0x4A: ++ /* VBINVW */ ++ index = VBINVW; ++ break; ++ case 0x4B: ++ /* VCMPUEQB */ ++ index = VCMPUEQB; ++ break; ++ case 0x6B: ++ /* VCMPUEQBI*/ ++ break; ++ case 0x4C: ++ /* VCMPUGTB */ ++ index = VCMPUGTB; ++ break; ++ case 0x6C: ++ /* VCMPUGTBI */ ++ index = VCMPUGTBI; ++ break; ++ case 0x4D: ++ /* VSM3MSW */ ++ index = VSM3MSW; ++ break; ++ case 0x50: ++ /* VMAXH */ ++ index = VMAXH; ++ break; ++ case 0x51: ++ /* VMINH */ ++ index = VMINH; ++ break; ++ case 0x52: ++ /* VMAXW */ ++ index = VMAXW; ++ break; ++ case 0x53: ++ /* VMINW */ ++ index = VMINW; ++ break; ++ case 0x54: ++ /* VMAXL */ ++ index = VMAXL; ++ break; ++ case 0x55: ++ /* VMINL */ ++ index = VMINL; ++ break; ++ case 0x56: ++ /* VUMAXB */ ++ index = VUMAXB; ++ break; ++ case 0x57: ++ /* VUMINB */ ++ index = VUMINB; ++ break; ++ case 0x58: ++ /* VUMAXH */ ++ index = VUMAXH; ++ break; ++ case 0x59: ++ /* VUMINH */ ++ index = VUMINH; ++ break; ++ case 0x5A: ++ /* VUMAXW */ ++ index = VUMAXW; ++ break; ++ case 0x5B: ++ /* VUMINW */ ++ index = VUMINW; ++ break; ++ case 0x5C: ++ /* VUMAXL */ ++ index = VUMAXL; ++ break; ++ case 0x5D: ++ /* VUMINL */ ++ index = VUMINL; ++ break; ++ case 0x68: ++ /* VSM4KEY */ ++ index = VSM4KEY; ++ break; ++ case 0x80: ++ /* VADDS */ ++ index = VADDS; ++ break; ++ case 0x81: ++ /* VADDD */ ++ index = VADDD; ++ break; ++ case 0x82: ++ /* VSUBS */ ++ index = VSUBS; ++ break; ++ case 0x83: ++ /* VSUBD */ ++ index = VSUBD; ++ break; ++ case 0x84: ++ /* VMULS */ ++ index = VMULS; ++ break; ++ case 0x85: ++ /* VMULD */ ++ index = VMULD; ++ break; ++ case 0x86: ++ /* VDIVS */ ++ index = VDIVS; ++ break; ++ case 0x87: ++ /* VDIVD */ ++ index = VDIVD; ++ break; ++ case 0x88: ++ /* VSQRTS */ ++ index = VSQRTS; ++ break; ++ case 0x89: ++ /* VSQRTD */ ++ index = VSQRTD; ++ break; ++ case 0x8C: ++ /* VFCMPEQ */ ++ index = VFCMPEQ; ++ break; ++ case 0x8D: ++ /* VFCMPLE */ ++ index = VFCMPLE; ++ break; ++ case 0x8E: ++ /* VFCMPLT */ ++ index = VFCMPLT; ++ break; ++ case 0x8F: ++ /* VFCMPUN */ ++ index = VFCMPUN; ++ break; ++ case 0x90: ++ /* VCPYS */ ++ index = VCPYS; ++ break; ++ case 0x91: ++ /* VCPYSE */ ++ index = VCPYSE; ++ break; ++ case 0x92: ++ /* VCPYSN */ ++ index = VCPYSN; ++ break; ++ case 0x93: ++ /* VSUMS */ ++ index = VSUMS; ++ break; ++ case 0x94: ++ /* VSUMD */ ++ index = VSUMD; ++ break; ++ case 0x95: ++ /* VFCVTSD */ ++ index = VFCVTSD; ++ break; ++ case 0x96: ++ /* VFCVTDS */ ++ index = VFCVTDS; ++ break; ++ case 0x99: ++ /* VFCVTLS */ ++ index = VFCVTLS; ++ break; ++ case 0x9A: ++ /* VFCVTLD */ ++ index = VFCVTLD; ++ break; ++ case 0x9B: ++ /* VFCVTDL */ ++ index = VFCVTDL; ++ break; ++ case 0x9C: ++ /* VFCVTDL_G */ ++ index = VFCVTDL_G; ++ break; ++ case 0x9D: ++ /* VFCVTDL_P */ ++ index = VFCVTDL_P; ++ break; ++ case 0x9E: ++ /* VFCVTDL_Z */ ++ index = VFCVTDL_Z; ++ break; ++ case 0x9F: ++ /* VFCVTDL_N */ ++ index = VFCVTDL_N; ++ break; ++ case 0xA0: ++ /* VFRIS */ ++ index = VFRIS; ++ break; ++ case 0xA1: ++ /* VFRIS_G */ ++ index = VFRIS_G; ++ break; ++ case 0xA2: ++ /* VFRIS_P */ ++ index = VFRIS_P; ++ break; ++ case 0xA3: ++ /* VFRIS_Z */ ++ index = VFRIS_Z; ++ break; ++ case 0xA4: ++ /* VFRIS_N */ ++ index = VFRIS_N; ++ break; ++ case 0xA5: ++ /* VFRID */ ++ index = VFRID; ++ break; ++ case 0xA6: ++ /* VFRID_G */ ++ index = VFRID_G; ++ break; ++ case 0xA7: ++ /* VFRID_P */ ++ index = VFRID_P; ++ break; ++ case 0xA8: ++ /* VFRID_Z */ ++ index = VFRID_Z; ++ break; ++ case 0xA9: ++ /* VFRID_N */ ++ index = VFRID_N; ++ break; ++ case 0xAA: ++ /* VFRECS */ ++ index = VFRECS; ++ break; ++ case 0xAB: ++ /* VFRECD */ ++ index = VFRECD; ++ break; ++ case 0xAC: ++ /* VMAXS */ ++ index = VMAXS; ++ break; ++ case 0xAD: ++ /* VMINS */ ++ index = VMINS; ++ break; ++ case 0xAE: ++ /* VMAXD */ ++ index = VMAXD; ++ break; ++ case 0xAF: ++ /* VMIND */ ++ index = VMIND; ++ break; ++ default: ++ break; ++ } ++ break; ++ case 0x1B: ++ switch (fn6) { ++ case 0x00: ++ /* VMAS */ ++ index = VMAS; ++ break; ++ case 0x01: ++ /* VMAD */ ++ index = VMAD; ++ break; ++ case 0x02: ++ /* VMSS */ ++ index = VMSS; ++ break; ++ case 0x03: ++ /* VMSD */ ++ index = VMSD; ++ break; ++ case 0x04: ++ /* VNMAS */ ++ index = VNMAS; ++ break; ++ case 0x05: ++ /* VNMAD */ ++ index = VNMAD; ++ break; ++ case 0x06: ++ /* VNMSS */ ++ index = VNMSS; ++ break; ++ case 0x07: ++ /* VNMSD */ ++ index = VNMSD; ++ break; ++ case 0x10: ++ /* VFSELEQ */ ++ index = VFSELEQ; ++ break; ++ case 0x12: ++ /* VFSELLT */ ++ index = VFSELLT; ++ break; ++ case 0x13: ++ /* VFSELLE */ ++ index = VFSELLE; ++ break; ++ case 0x18: ++ /* VSELEQW */ ++ index = VSELEQW; ++ break; ++ case 0x38: ++ /* VSELEQWI */ ++ index = VSELEQWI; ++ break; ++ case 0x19: ++ /* VSELLBCW */ ++ index = VSELLBCW; ++ break; ++ case 0x39: ++ /* VSELLBCWI */ ++ index = VSELLBCWI; ++ break; ++ case 0x1A: ++ /* VSELLTW */ ++ index = VSELLTW; ++ break; ++ case 0x3A: ++ /* VSELLTWI */ ++ index = VSELLTWI; ++ break; ++ case 0x1B: ++ /* VSELLEW */ ++ index = VSELLEW; ++ break; ++ case 0x3B: ++ /* VSELLEWI */ ++ index = VSELLEWI; ++ break; ++ case 0x20: ++ /* VINSW */ ++ index = VINSW; ++ break; ++ case 0x21: ++ /* VINSF */ ++ index = VINSF; ++ break; ++ case 0x22: ++ /* VEXTW */ ++ index = VEXTW; ++ break; ++ case 0x23: ++ /* VEXTF */ ++ index = VEXTF; ++ break; ++ case 0x24: ++ /* VCPYW */ ++ index = VCPYW; ++ break; ++ case 0x25: ++ /* VCPYF */ ++ index = VCPYF; ++ break; ++ case 0x26: ++ /* VCONW */ ++ index = VCONW; ++ break; ++ case 0x27: ++ /* VSHFW */ ++ index = VSHFW; ++ break; ++ case 0x28: ++ /* VCONS */ ++ index = VCONS; ++ break; ++ case 0x29: ++ /* VCOND */ ++ index = VCOND; ++ break; ++ case 0x2A: ++ /* VINSB */ ++ index = VINSB; ++ break; ++ case 0x2B: ++ /* VINSH */ ++ index = VINSH; ++ break; ++ case 0x2C: ++ /* VINSECTLH */ ++ index = VINSECTLH; ++ break; ++ case 0x2D: ++ /* VINSECTLW */ ++ index = VINSECTLW; ++ break; ++ case 0x2E: ++ /* VINSECTLL */ ++ index = VINSECTLL; ++ break; ++ case 0x2F: ++ /* VINSECTLB */ ++ index = VINSECTLB; ++ break; ++ case 0x30: ++ /* VSHFQ */ ++ index = VSHFQ; ++ break; ++ case 0x31: ++ /* VSHFQB */ ++ index = VSHFQB; ++ break; ++ case 0x32: ++ /* VCPYB */ ++ index = VCPYB; ++ break; ++ case 0x33: ++ /* VCPYH */ ++ index = VCPYH; ++ break; ++ case 0x34: ++ /* VSM3R */ ++ index = VSM3R; ++ break; ++ case 0x35: ++ /* VFCVTSH */ ++ index = VFCVTSH; ++ break; ++ case 0x36: ++ /* VFCVTHS */ ++ index = VFCVTHS; ++ break; ++ default: ++ break; ++ } ++ break; ++ case 0x1C: ++ switch (fn4) { ++ case 0x0: ++ /* VLDW_U */ ++ index = VLDW_U; ++ break; ++ case 0x1: ++ /* VSTW_U */ ++ index = VSTW_U; ++ break; ++ case 0x2: ++ /* VLDS_U */ ++ index = VLDS_U; ++ break; ++ case 0x3: ++ /* VSTS_U */ ++ index = VSTS_U; ++ break; ++ case 0x4: ++ /* VLDD_U */ ++ index = VLDD_U; ++ break; ++ case 0x5: ++ /* VSTD_U */ ++ index = VSTD_U; ++ break; ++ case 0x8: ++ /* VSTW_UL */ ++ index = VSTW_UL; ++ break; ++ case 0x9: ++ /* VSTW_UH */ ++ index = VSTW_UH; ++ break; ++ case 0xa: ++ /* VSTS_UL */ ++ index = VSTS_UL; ++ break; ++ case 0xb: ++ /* VSTS_UH */ ++ index = VSTS_UH; ++ break; ++ case 0xc: ++ /* VSTD_UL */ ++ index = VSTD_UL; ++ break; ++ case 0xd: ++ /* VSTD_UH */ ++ index = VSTD_UH; ++ break; ++ case 0xe: ++ /* VLDD_NC */ ++ index = VLDD_NC; ++ break; ++ case 0xf: ++ /* VSTD_NC */ ++ index = VSTD_NC; ++ break; ++ default: ++ break; ++ } ++ break; ++ case 0x1D: ++ /* LBR */ ++ index = LBR; ++ break; ++ case 0x1E: ++ switch (fn4) { ++ case 0x0: ++ /* LDBU_A */ ++ index = LDBU_A; ++ break; ++ case 0x1: ++ /* LDHU_A */ ++ index = LDHU_A; ++ break; ++ case 0x2: ++ /* LDW_A */ ++ index = LDW_A; ++ break; ++ case 0x3: ++ /* LDL_A */ ++ index = LDL_A; ++ break; ++ case 0x4: ++ /* FLDS_A */ ++ index = FLDS_A; ++ break; ++ case 0x5: ++ /* FLDD_A */ ++ index = FLDD_A; ++ break; ++ case 0x6: ++ /* STBU_A */ ++ index = STBU_A; ++ break; ++ case 0x7: ++ /* STHU_A */ ++ index = STHU_A; ++ break; ++ case 0x8: ++ /* STW_A */ ++ index = STW_A; ++ break; ++ case 0x9: ++ /* STL_A */ ++ index = STL_A; ++ break; ++ case 0xA: ++ /* FSTS_A */ ++ index = FSTS_A; ++ break; ++ case 0xB: ++ /* FSTD_A */ ++ index = FSTD_A; ++ break; ++ case 0xE: ++ /* DPFHR */ ++ index = DPFHR; ++ break; ++ case 0xF: ++ /* DPFHW */ ++ index = DPFHW; ++ break; ++ default: ++ break; ++ } ++ break; ++ case 0x20: ++ /* LDBU */ ++ index = LDBU; ++ break; ++ case 0x21: ++ /* LDHU */ ++ index = LDHU; ++ break; ++ case 0x22: ++ /* LDW */ ++ index = LDW; ++ break; ++ case 0x23: ++ /* LDL */ ++ index = LDL; ++ break; ++ case 0x24: ++ /* LDL_U */ ++ index = LDL_U; ++ break; ++ case 0x25: ++ if ((insn >> 12) & 1) { ++ /* PRI_LDL */ ++ index = PRI_LDL; ++ } else { ++ /* PRI_LDW */ ++ index = PRI_LDW; ++ } ++ break; ++ case 0x26: ++ /* FLDS */ ++ index = FLDS; ++ break; ++ case 0x27: ++ /* FLDD */ ++ index = FLDD; ++ break; ++ case 0x28: ++ /* STB */ ++ index = STB; ++ break; ++ case 0x29: ++ /* STH */ ++ index = STH; ++ break; ++ case 0x2a: ++ /* STW */ ++ index = STW; ++ break; ++ case 0x2b: ++ /* STL */ ++ index = STL; ++ break; ++ case 0x2c: ++ /* STL_U */ ++ index = STL_U; ++ break; ++ case 0x2d: ++ if ((insn >> 12) & 1) { ++ /* PRI_STL */ ++ index = PRI_STL; ++ } else { ++ /* PRI_STW */ ++ index = PRI_STW; ++ } ++ break; ++ case 0x2e: ++ /* FSTS */ ++ index = FSTS; ++ break; ++ case 0x2f: ++ /* FSTD */ ++ index = FSTD; ++ break; ++ case 0x30: ++ /* BEQ */ ++ index = BEQ; ++ break; ++ case 0x31: ++ /* BNE */ ++ index = BNE; ++ break; ++ case 0x32: ++ /* BLT */ ++ index = BLT; ++ break; ++ case 0x33: ++ /* BLE */ ++ index = BLE; ++ break; ++ case 0x34: ++ /* BGT */ ++ index = BGT; ++ break; ++ case 0x35: ++ /* BGE */ ++ index = BGE; ++ break; ++ case 0x36: ++ /* BLBC */ ++ index = BLBC; ++ break; ++ case 0x37: ++ /* BLBS */ ++ index = BLBS; ++ break; ++ case 0x38: ++ /* FBEQ */ ++ index = FBEQ; ++ break; ++ case 0x39: ++ /* FBNE */ ++ index = FBNE; ++ break; ++ case 0x3a: ++ /* FBLT */ ++ index = FBLT; ++ break; ++ case 0x3b: ++ /* FBLE */ ++ index = FBLE; ++ break; ++ case 0x3c: ++ /* FBGT */ ++ index = FBGT; ++ break; ++ case 0x3d: ++ /* FBGE */ ++ index = FBGE; ++ break; ++ case 0x3f: ++ /* LDIH */ ++ index = LDIH; ++ break; ++ case 0x3e: ++ /* LDI */ ++ index = LDI; ++ break; ++ default: ++do_invalid: ++ break; ++ } ++ count = tcg_temp_new(); ++ offs = offsetof(CPUSW64State, insn_count[index]); ++ tcg_gen_ld_i64(count, cpu_env, offs); ++ tcg_gen_addi_i64(count, count, 1); ++ tcg_gen_st_i64(count, cpu_env, offs); ++ tcg_temp_free(count); ++} +diff --git a/target/sw64/profile.h b/target/sw64/profile.h +new file mode 100644 +index 0000000000..5aca541ea7 +--- /dev/null ++++ b/target/sw64/profile.h +@@ -0,0 +1,541 @@ ++#ifndef PROFILE_H ++#define PROFILE_H ++#define SYS_CALL 0 ++#define CALL 1 ++#define RET 2 ++#define JMP 3 ++#define BR 4 ++#define BSR 5 ++#define MEMB 6 ++#define IMEMB 7 ++#define WMEMB 8 ++#define RTC 9 ++#define RCID 10 ++#define HALT 11 ++#define RD_F 12 ++#define WR_F 13 ++#define RTID 14 ++#define CSRWS 15 ++#define CSRWC 16 ++#define PRI_RCSR 17 ++#define PRI_WCSR 18 ++#define PRI_RET 19 ++#define LLDW 20 ++#define LLDL 21 ++#define LDW_INC 22 ++#define LDL_INC 23 ++#define LDW_DEC 24 ++#define LDL_DEC 25 ++#define LDW_SET 26 ++#define LDL_SET 27 ++#define LSTW 28 ++#define LSTL 29 ++#define LDW_NC 30 ++#define LDL_NC 31 ++#define LDD_NC 32 ++#define STW_NC 33 ++#define STL_NC 34 ++#define STD_NC 35 ++#define LDWE 36 ++#define LDSE 37 ++#define LDDE 38 ++#define VLDS 39 ++#define VLDD 40 ++#define VSTS 41 ++#define VSTD 42 ++#define FIMOVS 43 ++#define FIMOVD 44 ++#define ADDW 45 ++#define SUBW 46 ++#define S4ADDW 47 ++#define S4SUBW 48 ++#define S8ADDW 49 ++#define S8SUBW 50 ++#define ADDL 51 ++#define SUBL 52 ++#define S4ADDL 53 ++#define S4SUBL 54 ++#define S8ADDL 55 ++#define S8SUBL 56 ++#define MULW 57 ++#define DIVW 58 ++#define UDIVW 59 ++#define REMW 60 ++#define UREMW 61 ++#define MULL 62 ++#define MULH 63 ++#define DIVL 64 ++#define UDIVL 65 ++#define REML 66 ++#define UREML 67 ++#define ADDPI 68 ++#define ADDPIS 69 ++#define CMPEQ 70 ++#define CMPLT 71 ++#define CMPLE 72 ++#define CMPULT 73 ++#define CMPULE 74 ++#define SBT 75 ++#define CBT 76 ++#define AND 77 ++#define BIC 78 ++#define BIS 79 ++#define ORNOT 80 ++#define XOR 81 ++#define EQV 82 ++#define INSLB 83 ++#define INSLH 84 ++#define INSLW 85 ++#define INSLL 86 ++#define INSHB 87 ++#define INSHH 88 ++#define INSHW 89 ++#define INSHL 90 ++#define SLLL 91 ++#define SRLL 92 ++#define SRAL 93 ++#define ROLL 94 ++#define SLLW 95 ++#define SRLW 96 ++#define SRAW 97 ++#define ROLW 98 ++#define EXTLB 99 ++#define EXTLH 100 ++#define EXTLW 101 ++#define EXTLL 102 ++#define EXTHB 103 ++#define EXTHH 104 ++#define EXTHW 105 ++#define EXTHL 106 ++#define CTPOP 107 ++#define CTLZ 108 ++#define CTTZ 109 ++#define REVBH 110 ++#define REVBW 111 ++#define REVBL 112 ++#define CASW 113 ++#define CASL 114 ++#define MASKLB 115 ++#define MASKLH 116 ++#define MASKLW 117 ++#define MASKLL 118 ++#define MASKHB 119 ++#define MASKHH 120 ++#define MASKHW 121 ++#define MASKHL 122 ++#define ZAP 123 ++#define ZAPNOT 124 ++#define SEXTB 125 ++#define SEXTH 126 ++#define SELEQ 127 ++#define SELGE 128 ++#define SELGT 129 ++#define SELLE 130 ++#define SELLT 131 ++#define SELNE 132 ++#define SELLBC 133 ++#define SELLBS 134 ++#define ADDWI 135 ++#define SUBWI 136 ++#define S4ADDWI 137 ++#define S4SUBWI 138 ++#define S8ADDWI 139 ++#define S8SUBWI 140 ++#define ADDLI 141 ++#define SUBLI 142 ++#define S4ADDLI 143 ++#define S4SUBLI 144 ++#define S8ADDLI 145 ++#define S8SUBLI 146 ++#define MULWI 147 ++#define DIVWI 148 ++#define UDIVWI 149 ++#define REMWI 150 ++#define UREMWI 151 ++#define MULLI 152 ++#define MULHI 153 ++#define DIVLI 154 ++#define UDIVLI 155 ++#define REMLI 156 ++#define UREMLI 157 ++#define ADDPII 158 ++#define ADDPISI 159 ++#define CMPEQI 160 ++#define CMPLTI 161 ++#define CMPLEI 162 ++#define CMPULTI 163 ++#define CMPULEI 164 ++#define SBTI 165 ++#define CBTI 166 ++#define ANDI 167 ++#define BICI 168 ++#define BISI 169 ++#define ORNOTI 170 ++#define XORI 171 ++#define EQVI 172 ++#define INSLBI 173 ++#define INSLHI 174 ++#define INSLWI 175 ++#define INSLLI 176 ++#define INSHBI 177 ++#define INSHHI 178 ++#define INSHWI 179 ++#define INSHLI 180 ++#define SLLLI 181 ++#define SRLLI 182 ++#define SRALI 183 ++#define ROLLI 184 ++#define SLLWI 185 ++#define SRLWI 186 ++#define SRAWI 187 ++#define ROLWI 188 ++#define EXTLBI 189 ++#define EXTLHI 190 ++#define EXTLWI 191 ++#define EXTLLI 192 ++#define EXTHBI 193 ++#define EXTHHI 194 ++#define EXTHWI 195 ++#define EXTHLI 196 ++#define CTPOPI 197 ++#define CTLZI 198 ++#define CTTZI 199 ++#define REVBHI 200 ++#define REVBWI 201 ++#define REVBLI 202 ++#define CASWI 203 ++#define CASLI 204 ++#define MASKLBI 205 ++#define MASKLHI 206 ++#define MASKLWI 207 ++#define MASKLLI 208 ++#define MASKHBI 209 ++#define MASKHHI 210 ++#define MASKHWI 211 ++#define MASKHLI 212 ++#define ZAPI 213 ++#define ZAPNOTI 214 ++#define SEXTBI 215 ++#define SEXTHI 216 ++#define CMPGEBI 217 ++#define SELEQI 218 ++#define SELGEI 219 ++#define SELGTI 220 ++#define SELLEI 221 ++#define SELLTI 222 ++#define SELNEI 223 ++#define SELLBCI 224 ++#define SELLBSI 225 ++#define VLOGZZ 226 ++#define FADDS 227 ++#define FADDD 228 ++#define FSUBS 229 ++#define FSUBD 230 ++#define FMULS 231 ++#define FMULD 232 ++#define FDIVS 233 ++#define FDIVD 234 ++#define FSQRTS 235 ++#define FSQRTD 236 ++#define FCMPEQ 237 ++#define FCMPLE 238 ++#define FCMPLT 239 ++#define FCMPUN 240 ++#define FCVTSD 241 ++#define FCVTDS 242 ++#define FCVTDL_G 243 ++#define FCVTDL_P 244 ++#define FCVTDL_Z 245 ++#define FCVTDL_N 246 ++#define FCVTDL 247 ++#define FCVTWL 248 ++#define FCVTLW 249 ++#define FCVTLS 250 ++#define FCVTLD 251 ++#define FCPYS 252 ++#define FCPYSE 253 ++#define FCPYSN 254 ++#define IFMOVS 255 ++#define IFMOVD 256 ++#define RFPCR 257 ++#define WFPCR 258 ++#define SETFPEC0 259 ++#define SETFPEC1 260 ++#define SETFPEC2 261 ++#define SETFPEC3 262 ++#define FRECS 263 ++#define FRECD 264 ++#define FRIS 265 ++#define FRIS_G 266 ++#define FRIS_P 267 ++#define FRIS_Z 268 ++#define FRIS_N 269 ++#define FRID 270 ++#define FRID_G 271 ++#define FRID_P 272 ++#define FRID_Z 273 ++#define FRID_N 274 ++#define FMAS 275 ++#define FMAD 276 ++#define FMSS 277 ++#define FMSD 278 ++#define FNMAS 279 ++#define FNMAD 280 ++#define FNMSS 281 ++#define FNMSD 282 ++#define FSELEQ 283 ++#define FSELNE 284 ++#define FSELLT 285 ++#define FSELLE 286 ++#define FSELGT 287 ++#define FSELGE 288 ++#define VADDW 289 ++#define VADDWI 290 ++#define VSUBW 291 ++#define VSUBWI 292 ++#define VCMPGEW 293 ++#define VCMPGEWI 294 ++#define VCMPEQW 295 ++#define VCMPEQWI 296 ++#define VCMPLEW 297 ++#define VCMPLEWI 298 ++#define VCMPLTW 299 ++#define VCMPLTWI 300 ++#define VCMPULEW 301 ++#define VCMPULEWI 302 ++#define VCMPULTW 303 ++#define VCMPULTWI 304 ++#define VSLLW 305 ++#define VSLLWI 306 ++#define VSRLW 307 ++#define VSRLWI 308 ++#define VSRAW 309 ++#define VSRAWI 310 ++#define VROLW 311 ++#define VROLWI 312 ++#define SLLOW 313 ++#define SLLOWI 314 ++#define SRLOW 315 ++#define SRLOWI 316 ++#define VADDL 317 ++#define VADDLI 318 ++#define VSUBL 319 ++#define VSUBLI 320 ++#define VSLLB 321 ++#define VSLLBI 322 ++#define VSRLB 323 ++#define VSRLBI 324 ++#define VSRAB 325 ++#define VSRABI 326 ++#define VROLB 327 ++#define VROLBI 328 ++#define VSLLH 329 ++#define VSLLHI 330 ++#define VSRLH 331 ++#define VSRLHI 332 ++#define VSRAH 333 ++#define VSRAHI 334 ++#define VROLH 335 ++#define VROLHI 336 ++#define CTPOPOW 337 ++#define CTLZOW 338 ++#define VSLLL 339 ++#define VSLLLI 340 ++#define VSRLL 341 ++#define VSRLLI 342 ++#define VSRAL 343 ++#define VSRALI 344 ++#define VROLL 345 ++#define VROLLI 346 ++#define VMAXB 347 ++#define VMINB 348 ++#define VUCADDW 349 ++#define VUCADDWI 350 ++#define VUCSUBW 351 ++#define VUCSUBWI 352 ++#define VUCADDH 353 ++#define VUCADDHI 354 ++#define VUCSUBH 355 ++#define VUCSUBHI 356 ++#define VUCADDB 357 ++#define VUCADDBI 358 ++#define VUCSUBB 359 ++#define VUCSUBBI 360 ++#define SRAOW 361 ++#define SRAOWI 362 ++#define VSUMW 363 ++#define VSUML 364 ++#define VSM4R 365 ++#define VBINVW 366 ++#define VCMPUEQB 367 ++#define VCMPUGTB 368 ++#define VCMPUGTBI 369 ++#define VSM3MSW 370 ++#define VMAXH 371 ++#define VMINH 372 ++#define VMAXW 373 ++#define VMINW 374 ++#define VMAXL 375 ++#define VMINL 376 ++#define VUMAXB 377 ++#define VUMINB 378 ++#define VUMAXH 379 ++#define VUMINH 380 ++#define VUMAXW 381 ++#define VUMINW 382 ++#define VUMAXL 383 ++#define VUMINL 384 ++#define VSM4KEY 385 ++#define VADDS 386 ++#define VADDD 387 ++#define VSUBS 388 ++#define VSUBD 389 ++#define VMULS 390 ++#define VMULD 391 ++#define VDIVS 392 ++#define VDIVD 393 ++#define VSQRTS 394 ++#define VSQRTD 395 ++#define VFCMPEQ 396 ++#define VFCMPLE 397 ++#define VFCMPLT 398 ++#define VFCMPUN 399 ++#define VCPYS 400 ++#define VCPYSE 401 ++#define VCPYSN 402 ++#define VSUMS 403 ++#define VSUMD 404 ++#define VFCVTSD 405 ++#define VFCVTDS 406 ++#define VFCVTLS 407 ++#define VFCVTLD 408 ++#define VFCVTDL 409 ++#define VFCVTDL_G 410 ++#define VFCVTDL_P 411 ++#define VFCVTDL_Z 412 ++#define VFCVTDL_N 413 ++#define VFRIS 414 ++#define VFRIS_G 415 ++#define VFRIS_P 416 ++#define VFRIS_Z 417 ++#define VFRIS_N 418 ++#define VFRID 419 ++#define VFRID_G 420 ++#define VFRID_P 421 ++#define VFRID_Z 422 ++#define VFRID_N 423 ++#define VFRECS 424 ++#define VFRECD 425 ++#define VMAXS 426 ++#define VMINS 427 ++#define VMAXD 428 ++#define VMIND 429 ++#define VMAS 430 ++#define VMAD 431 ++#define VMSS 432 ++#define VMSD 433 ++#define VNMAS 434 ++#define VNMAD 435 ++#define VNMSS 436 ++#define VNMSD 437 ++#define VFSELEQ 438 ++#define VFSELLT 439 ++#define VFSELLE 440 ++#define VSELEQW 441 ++#define VSELEQWI 442 ++#define VSELLBCW 443 ++#define VSELLBCWI 444 ++#define VSELLTW 445 ++#define VSELLTWI 446 ++#define VSELLEW 447 ++#define VSELLEWI 448 ++#define VINSW 449 ++#define VINSF 450 ++#define VEXTW 451 ++#define VEXTF 452 ++#define VCPYW 453 ++#define VCPYF 454 ++#define VCONW 455 ++#define VSHFW 456 ++#define VCONS 457 ++#define VCOND 458 ++#define VINSB 459 ++#define VINSH 460 ++#define VINSECTLH 461 ++#define VINSECTLW 462 ++#define VINSECTLL 463 ++#define VINSECTLB 464 ++#define VSHFQ 465 ++#define VSHFQB 466 ++#define VCPYB 467 ++#define VCPYH 468 ++#define VSM3R 469 ++#define VFCVTSH 470 ++#define VFCVTHS 471 ++#define VLDW_U 472 ++#define VSTW_U 473 ++#define VLDS_U 474 ++#define VSTS_U 475 ++#define VLDD_U 476 ++#define VSTD_U 477 ++#define VSTW_UL 478 ++#define VSTW_UH 479 ++#define VSTS_UL 480 ++#define VSTS_UH 481 ++#define VSTD_UL 482 ++#define VSTD_UH 483 ++#define VLDD_NC 484 ++#define VSTD_NC 485 ++#define LBR 486 ++#define LDBU_A 487 ++#define LDHU_A 488 ++#define LDW_A 489 ++#define LDL_A 490 ++#define FLDS_A 491 ++#define FLDD_A 492 ++#define STBU_A 493 ++#define STHU_A 494 ++#define STW_A 495 ++#define STL_A 496 ++#define FSTS_A 497 ++#define FSTD_A 498 ++#define DPFHR 499 ++#define DPFHW 500 ++#define LDBU 501 ++#define LDHU 502 ++#define LDW 503 ++#define LDL 504 ++#define LDL_U 505 ++#define PRI_LDL 506 ++#define PRI_LDW 507 ++#define FLDS 508 ++#define FLDD 509 ++#define STB 510 ++#define STH 511 ++#define STW 512 ++#define STL 513 ++#define STL_U 514 ++#define PRI_STL 515 ++#define PRI_STW 516 ++#define FSTS 517 ++#define FSTD 518 ++#define BEQ 519 ++#define BNE 520 ++#define BLT 521 ++#define BLE 522 ++#define BGT 523 ++#define BGE 524 ++#define BLBC 525 ++#define BLBS 526 ++#define FBEQ 527 ++#define FBNE 528 ++#define FBLT 529 ++#define FBLE 530 ++#define FBGT 531 ++#define FBGE 532 ++#define LDIH 533 ++#define LDI 534 ++ ++extern const char *insn_opc[535]; ++ ++#endif +diff --git a/target/sw64/simd_helper.c b/target/sw64/simd_helper.c +new file mode 100644 +index 0000000000..13bd52de3d +--- /dev/null ++++ b/target/sw64/simd_helper.c +@@ -0,0 +1,1058 @@ ++#include "qemu/osdep.h" ++#include "cpu.h" ++#include "exec/exec-all.h" ++#include "exec/helper-proto.h" ++ ++#undef DEBUG_SIMD ++ ++static inline uint8_t *get_element_b(CPUSW64State *env, uint64_t ra, ++ int index) ++{ ++ return (uint8_t*)&env->fr[ra + (index / 8) * 32] + (index % 8); ++} ++ ++static inline uint16_t *get_element_h(CPUSW64State *env, uint64_t ra, ++ int index) ++{ ++ return (uint16_t*)&env->fr[ra + (index / 4) * 32] + (index % 4); ++} ++ ++static inline uint32_t *get_element_w(CPUSW64State *env, uint64_t ra, ++ int index) ++{ ++ return (uint32_t*)&env->fr[ra + (index / 2) * 32] + (index % 2); ++} ++ ++static inline uint64_t *get_element_l(CPUSW64State *env, uint64_t ra, ++ int index) ++{ ++ return &env->fr[ra + index * 32]; ++} ++ ++void helper_srlow(CPUSW64State *env, uint64_t ra, uint64_t rc, uint64_t shift) ++{ ++ int i; ++ int adden; ++ int dest, src; ++ adden = shift >> 6; ++ shift &= 0x3f; ++#ifdef DEBUG_SIMD ++ printf("right shift = %ld adden = %d\n", shift, adden); ++ printf("in_fr[%ld]:", ra); ++ for (i = 3 ; i >= 0; i--) { ++ printf("%016lx ", env->fr[ra + 32 * i]); ++ } ++ printf("\n"); ++#endif ++ ++ for (i = 0; (i + adden) < 4; i++) { ++ dest = i * 32 + rc; ++ src = (i + adden) * 32 + ra; ++ env->fr[dest] = env->fr[src] >> shift; ++ if (((i + adden) < 3) && (shift != 0)) ++ env->fr[dest] |= (env->fr[src + 32] << (64 - shift)); ++ } ++ ++ for (; i < 4; i++) { ++ env->fr[rc + i * 32] = 0; ++ } ++#ifdef DEBUG_SIMD ++ printf("out_fr[%ld]:", rc); ++ for (i = 3 ; i >= 0; i--) { ++ printf("%016lx ", env->fr[rc + 32 * i]); ++ } ++ printf("\n"); ++#endif ++} ++ ++void helper_sllow(CPUSW64State *env, uint64_t ra, uint64_t rc, uint64_t shift) ++{ ++ int i; ++ int adden; ++ int dest, src; ++ adden = shift >> 6; ++ shift &= 0x3f; ++#ifdef DEBUG_SIMD ++ printf("left shift = %ld adden = %d\n", shift, adden); ++ printf("in_fr[%ld]:", ra); ++ for (i = 3 ; i >= 0; i--) { ++ printf("%016lx ", env->fr[ra + 32 * i]); ++ } ++ printf("\n"); ++#endif ++ ++ for (i = 3; (i - adden) >= 0; i--) { ++ dest = i * 32 + rc; ++ src = (i - adden) * 32 + ra; ++ env->fr[dest] = env->fr[src] << shift; ++ if (((i - adden) > 0) && (shift != 0)) ++ env->fr[dest] |= (env->fr[src - 32] >> (64 - shift)); ++ } ++ for (; i >= 0; i--) { ++ env->fr[rc + i * 32] = 0; ++ } ++#ifdef DEBUG_SIMD ++ printf("out_fr[%ld]:", rc); ++ for (i = 3 ; i >= 0; i--) { ++ printf("%016lx ", env->fr[rc + 32 * i]); ++ } ++ printf("\n"); ++#endif ++} ++ ++static uint64_t do_logzz(uint64_t va, uint64_t vb, uint64_t vc, uint64_t zz) ++{ ++ int i; ++ uint64_t ret = 0; ++ int index; ++ ++ for (i = 0; i < 64; i++) { ++ index = (((va >> i) & 1) << 2) | (((vb >> i) & 1) << 1) | ((vc >> i) & 1); ++ ret |= ((zz >> index) & 1) << i; ++ } ++ ++ return ret; ++} ++ ++void helper_vlogzz(CPUSW64State *env, uint64_t args, uint64_t rd, uint64_t zz) ++{ ++ int i; ++ int ra, rb, rc; ++ ra = args >> 16; ++ rb = (args >> 8) & 0xff; ++ rc = args & 0xff; ++#ifdef DEBUG_SIMD ++ printf("zz = %lx\n", zz); ++ printf("in_fr[%d]:", ra); ++ for (i = 3 ; i >= 0; i--) { ++ printf("%016lx ", env->fr[ra + 32 * i]); ++ } ++ printf("\n"); ++ printf("in_fr[%d]:", rb); ++ for (i = 3 ; i >= 0; i--) { ++ printf("%016lx ", env->fr[rb + 32 * i]); ++ } ++ printf("\n"); ++ printf("in_fr[%d]:", rc); ++ for (i = 3 ; i >= 0; i--) { ++ printf("%016lx ", env->fr[rc + 32 * i]); ++ } ++ printf("\n"); ++#endif ++ for (i = 0; i < 4; i++) { ++ env->fr[rd + i * 32] = do_logzz(env->fr[ra + i * 32], env->fr[rb + i * 32], ++ env->fr[rc + i * 32], zz); ++ } ++#ifdef DEBUG_SIMD ++ printf("out_fr[%ld]:", rd); ++ for (i = 3 ; i >= 0; i--) { ++ printf("%016lx ", env->fr[rd + 32 * i]); ++ } ++ printf("\n"); ++#endif ++} ++ ++void helper_v_print(CPUSW64State *env, uint64_t v) ++{ ++ printf("PC[%lx]: fr[%lx]:\n", GETPC(), v); ++} ++ ++void helper_vconw(CPUSW64State *env, uint64_t args, uint64_t rd, ++ uint64_t byte4_len) ++{ ++ int ra, rb; ++ int count; ++ int i; ++ uint32_t *ptr_dst, *ptr_src; ++ uint32_t tmp[8]; ++ ++ ra = (args >> 8) & 0xff; ++ rb = args & 0xff; ++ count = 8 - byte4_len; ++ ++ for (i = 0; i < 8; i++) { ++ ptr_dst = get_element_w(env, rd, i); ++ if (i < count) { ++ ptr_src = get_element_w(env, ra, i + byte4_len); ++ } else { ++ ptr_src = get_element_w(env, rb, i - count); ++ } ++ tmp[i] = *ptr_src; ++ } ++ for (i = 0; i < 8; i++) { ++ ptr_dst = get_element_w(env, rd, i); ++ *ptr_dst = tmp[i]; ++ } ++} ++ ++void helper_vcond(CPUSW64State *env, uint64_t args, uint64_t rd, ++ uint64_t byte8_len) ++{ ++ int ra, rb; ++ int count; ++ int i; ++ uint64_t *ptr_dst, *ptr_src; ++ uint64_t tmp[8]; ++ ++ ra = (args >> 8) & 0xff; ++ rb = args & 0xff; ++ count = 4 - byte8_len; ++ ++ for (i = 0; i < 4; i++) { ++ if (i < count) { ++ ptr_src = get_element_l(env, ra, i + byte8_len); ++ } else { ++ ptr_src = get_element_l(env, rb, i - count); ++ } ++ tmp[i] = *ptr_src; ++ } ++ for (i = 0; i < 4; i++) { ++ ptr_dst = get_element_l(env, rd, i + byte8_len); ++ *ptr_dst = tmp[i]; ++ } ++} ++ ++void helper_vshfw(CPUSW64State *env, uint64_t args, uint64_t rd, uint64_t vc) ++{ ++ int ra, rb; ++ int i; ++ uint32_t *ptr_dst, *ptr_src; ++ uint32_t tmp[8]; ++ int flag, idx; ++ ++ ra = (args >> 8) & 0xff; ++ rb = args & 0xff; ++ ++ for (i = 0; i < 8; i++) { ++ flag = (vc >> (i * 4)) & 0x8; ++ idx = (vc >> (i * 4)) & 0x7; ++ if (flag == 0) { ++ ptr_src = get_element_w(env, ra, idx); ++ } else { ++ ptr_src = get_element_w(env, rb, idx); ++ } ++ tmp[i] = *ptr_src; ++ } ++ for (i = 0; i < 8; i++) { ++ ptr_dst = get_element_w(env, rd, i); ++ *ptr_dst = tmp[i]; ++ } ++} ++ ++uint64_t helper_ctlzow(CPUSW64State *env, uint64_t ra) ++{ ++ int i, j; ++ uint64_t val; ++ uint64_t ctlz = 0; ++ ++ for (j = 3; j >= 0; j--) { ++ val = env->fr[ra + 32 * j]; ++ for (i = 63; i >= 0; i--) { ++ if ((val >> i) & 1) ++ return ctlz << 29; ++ else ++ ctlz++; ++ } ++ } ++ return ctlz << 29; ++} ++ ++void helper_vucaddw(CPUSW64State *env, uint64_t ra, uint64_t rb, uint64_t rc) ++{ ++ int a, b, c; ++ int ret; ++ int i; ++ ++ for (i = 0; i < 4; i++) { ++ a = (int)(env->fr[ra + i * 32] & 0xffffffff); ++ b = (int)(env->fr[rb + i * 32] & 0xffffffff); ++ c = a + b; ++ if ((c ^ a) < 0 && (c ^ b) < 0) { ++ if (a < 0) ++ c = 0x80000000; ++ else ++ c = 0x7fffffff; ++ } ++ ret = c; ++ ++ a = (int)(env->fr[ra + i * 32] >> 32); ++ b = (int)(env->fr[rb + i * 32] >> 32); ++ c = a + b; ++ if ((c ^ a) < 0 && (c ^ b) < 0) { ++ if (a < 0) ++ c = 0x80000000; ++ else ++ c = 0x7fffffff; ++ } ++ env->fr[rc + i * 32] = ((uint64_t)(uint32_t)c << 32) | ++ (uint64_t)(uint32_t)ret; ++ } ++} ++ ++void helper_vucaddwi(CPUSW64State *env, uint64_t ra, uint64_t vb, uint64_t rc) ++{ ++ int a, b, c; ++ int ret; ++ int i; ++ ++ b = (int)vb; ++ for (i = 0; i < 4; i++) { ++ a = (int)(env->fr[ra + i * 32] & 0xffffffff); ++ c = a + b; ++ if ((c ^ a) < 0 && (c ^ b) < 0) { ++ if (a < 0) ++ c = 0x80000000; ++ else ++ c = 0x7fffffff; ++ } ++ ret = c; ++ ++ a = (int)(env->fr[ra + i * 32] >> 32); ++ c = a + b; ++ if ((c ^ a) < 0 && (c ^ b) < 0) { ++ if (a < 0) ++ c = 0x80000000; ++ else ++ c = 0x7fffffff; ++ } ++ env->fr[rc + i * 32] = ((uint64_t)(uint32_t)c << 32) | ++ (uint64_t)(uint32_t)ret; ++ } ++} ++ ++void helper_vucsubw(CPUSW64State *env, uint64_t ra, uint64_t rb, uint64_t rc) ++{ ++ int a, b, c; ++ int ret; ++ int i; ++ ++ for (i = 0; i < 4; i++) { ++ a = (int)(env->fr[ra + i * 32] & 0xffffffff); ++ b = (int)(env->fr[rb + i * 32] & 0xffffffff); ++ c = a - b; ++ if ((b ^ a) < 0 && (c ^ a) < 0) { ++ if (a < 0) ++ c = 0x80000000; ++ else ++ c = 0x7fffffff; ++ } ++ ret = c; ++ ++ a = (int)(env->fr[ra + i * 32] >> 32); ++ b = (int)(env->fr[rb + i * 32] >> 32); ++ c = a - b; ++ if ((b ^ a) < 0 && (c ^ a) < 0) { ++ if (a < 0) ++ c = 0x80000000; ++ else ++ c = 0x7fffffff; ++ } ++ env->fr[rc + i * 32] = ((uint64_t)(uint32_t)c << 32) | ++ (uint64_t)(uint32_t)ret; ++ } ++} ++ ++void helper_vucsubwi(CPUSW64State *env, uint64_t ra, uint64_t vb, uint64_t rc) ++{ ++ int a, b, c; ++ int ret; ++ int i; ++ ++ b = (int)vb; ++ for (i = 0; i < 4; i++) { ++ a = (int)(env->fr[ra + i * 32] & 0xffffffff); ++ c = a - b; ++ if ((b ^ a) < 0 && (c ^ a) < 0) { ++ if (a < 0) ++ c = 0x80000000; ++ else ++ c = 0x7fffffff; ++ } ++ ret = c; ++ ++ a = (int)(env->fr[ra + i * 32] >> 32); ++ c = a - b; ++ if ((b ^ a) < 0 && (c ^ a) < 0) { ++ if (a < 0) ++ c = 0x80000000; ++ else ++ c = 0x7fffffff; ++ } ++ env->fr[rc + i * 32] = ((uint64_t)(uint32_t)c << 32) | ++ (uint64_t)(uint32_t)ret; ++ } ++} ++ ++void helper_vucaddh(CPUSW64State *env, uint64_t ra, uint64_t rb, uint64_t rc) ++{ ++ short a, b, c; ++ uint64_t ret; ++ int i, j; ++ ++ for (i = 0; i < 4; i++) { ++ ret = 0; ++ for (j = 0; j < 4; j++) { ++ a = (short)((env->fr[ra + i * 32] >> (j * 16)) & 0xffff); ++ b = (short)((env->fr[rb + i * 32] >> (j * 16)) & 0xffff); ++ c = a + b; ++ if ((c ^ a) < 0 && (c ^ b) < 0) { ++ if (a < 0) ++ c = 0x8000; ++ else ++ c = 0x7fff; ++ } ++ ret |= ((uint64_t)(uint16_t)c) << (j * 16); ++ } ++ env->fr[rc + i * 32] = ret; ++ } ++} ++ ++void helper_vucaddhi(CPUSW64State *env, uint64_t ra, uint64_t vb, uint64_t rc) ++{ ++ short a, b, c; ++ uint64_t ret; ++ int i, j; ++ ++ b = (short)vb; ++ for (i = 0; i < 4; i++) { ++ ret = 0; ++ for (j = 0; j < 4; j++) { ++ a = (short)((env->fr[ra + i * 32] >> (j * 16)) & 0xffff); ++ c = a + b; ++ if ((c ^ a) < 0 && (c ^ b) < 0) { ++ if (a < 0) ++ c = 0x8000; ++ else ++ c = 0x7fff; ++ } ++ ret |= ((uint64_t)(uint16_t)c) << (j * 16); ++ } ++ env->fr[rc + i * 32] = ret; ++ } ++} ++ ++void helper_vucsubh(CPUSW64State *env, uint64_t ra, uint64_t rb, uint64_t rc) ++{ ++ short a, b, c; ++ uint64_t ret; ++ int i, j; ++ ++ for (i = 0; i < 4; i++) { ++ ret = 0; ++ for (j = 0; j < 4; j++) { ++ a = (short)((env->fr[ra + i * 32] >> (j * 16)) & 0xffff); ++ b = (short)((env->fr[rb + i * 32] >> (j * 16)) & 0xffff); ++ c = a - b; ++ if ((b ^ a) < 0 && (c ^ a) < 0) { ++ if (a < 0) ++ c = 0x8000; ++ else ++ c = 0x7fff; ++ } ++ ret |= ((uint64_t)(uint16_t)c) << (j * 16); ++ } ++ env->fr[rc + i * 32] = ret; ++ } ++} ++ ++void helper_vucsubhi(CPUSW64State *env, uint64_t ra, uint64_t vb, uint64_t rc) ++{ ++ short a, b, c; ++ uint64_t ret; ++ int i, j; ++ ++ b = (short)vb; ++ for (i = 0; i < 4; i++) { ++ ret = 0; ++ for (j = 0; j < 4; j++) { ++ a = (short)((env->fr[ra + i * 32] >> (j * 16)) & 0xffff); ++ c = a - b; ++ if ((b ^ a) < 0 && (c ^ a) < 0) { ++ if (a < 0) ++ c = 0x8000; ++ else ++ c = 0x7fff; ++ } ++ ret |= ((uint64_t)(uint16_t)c) << (j * 16); ++ } ++ env->fr[rc + i * 32] = ret; ++ } ++} ++ ++void helper_vucaddb(CPUSW64State *env, uint64_t ra, uint64_t rb, uint64_t rc) ++{ ++ int8_t a, b, c; ++ uint64_t ret; ++ int i, j; ++ ++ for (i = 0; i < 4; i++) { ++ ret = 0; ++ for (j = 0; j < 8; j++) { ++ a = (int8_t)((env->fr[ra + i * 32] >> (j * 8)) & 0xff); ++ b = (int8_t)((env->fr[rb + i * 32] >> (j * 8)) & 0xff); ++ c = a + b; ++ if ((c ^ a) < 0 && (c ^ b) < 0) { ++ if (a < 0) ++ c = 0x80; ++ else ++ c = 0x7f; ++ } ++ ret |= ((uint64_t)(uint8_t)c) << (j * 8); ++ } ++ env->fr[rc + i * 32] = ret; ++ } ++} ++ ++void helper_vucaddbi(CPUSW64State *env, uint64_t ra, uint64_t vb, uint64_t rc) ++{ ++ int8_t a, b, c; ++ uint64_t ret; ++ int i, j; ++ ++ b = (int8_t)(vb & 0xff); ++ for (i = 0; i < 4; i++) { ++ ret = 0; ++ for (j = 0; j < 8; j++) { ++ a = (int8_t)((env->fr[ra + i * 32] >> (j * 8)) & 0xff); ++ c = a + b; ++ if ((c ^ a) < 0 && (c ^ b) < 0) { ++ if (a < 0) ++ c = 0x80; ++ else ++ c = 0x7f; ++ } ++ ret |= ((uint64_t)(uint8_t)c) << (j * 8); ++ } ++ env->fr[rc + i * 32] = ret; ++ } ++} ++ ++void helper_vucsubb(CPUSW64State *env, uint64_t ra, uint64_t rb, uint64_t rc) ++{ ++ int8_t a, b, c; ++ uint64_t ret; ++ int i, j; ++ ++ for (i = 0; i < 4; i++) { ++ ret = 0; ++ for (j = 0; j < 8; j++) { ++ a = (int8_t)((env->fr[ra + i * 32] >> (j * 8)) & 0xff); ++ b = (int8_t)((env->fr[rb + i * 32] >> (j * 8)) & 0xff); ++ c = a - b; ++ if ((b ^ a) < 0 && (c ^ a) < 0) { ++ if (a < 0) ++ c = 0x80; ++ else ++ c = 0x7f; ++ } ++ ret |= ((uint64_t)(uint8_t)c) << (j * 8); ++ } ++ env->fr[rc + i * 32] = ret; ++ } ++} ++ ++void helper_vucsubbi(CPUSW64State *env, uint64_t ra, uint64_t vb, uint64_t rc) ++{ ++ int8_t a, b, c; ++ uint64_t ret; ++ int i, j; ++ ++ b = (int8_t)(vb & 0xff); ++ for (i = 0; i < 4; i++) { ++ ret = 0; ++ for (j = 0; j < 8; j++) { ++ a = (int8_t)((env->fr[ra + i * 32] >> (j * 8)) & 0xffff); ++ c = a - b; ++ if ((b ^ a) < 0 && (c ^ a) < 0) { ++ if (a < 0) ++ c = 0x80; ++ else ++ c = 0x7f; ++ } ++ ret |= ((uint64_t)(uint8_t)c) << (j * 8); ++ } ++ env->fr[rc + i * 32] = ret; ++ } ++} ++ ++uint64_t helper_vstw(CPUSW64State *env, uint64_t t0, uint64_t t1) ++{ ++ uint64_t idx, shift; ++ ++ idx = t0 + (t1 / 2) * 32; ++ shift = (t1 % 2) * 32; ++ ++ return (env->fr[idx] >> shift) & 0xffffffffUL; ++} ++ ++uint64_t helper_vsts(CPUSW64State *env, uint64_t t0, uint64_t t1) ++{ ++ uint64_t idx, val; ++ ++ idx = t0 + t1 * 32; ++ val = env->fr[idx]; ++ ++ return ((val >> 32) & 0xc0000000) | ((val >> 29) & 0x3fffffff); ++} ++ ++uint64_t helper_vstd(CPUSW64State *env, uint64_t t0, uint64_t t1) ++{ ++ uint64_t idx; ++ ++ idx = t0 + t1 * 32; ++ return env->fr[idx]; ++} ++ ++#define HELPER_VMAX(name, _suffix, type, loop) \ ++ void glue(glue(helper_, name), _suffix)(CPUSW64State *env, uint64_t ra, \ ++ uint64_t rb, uint64_t rc) \ ++ { \ ++ int i; \ ++ type *ptr_dst, *ptr_src_a, *ptr_src_b; \ ++ \ ++ for (i = 0; i < loop; i++) { \ ++ ptr_dst = (type*)glue(get_element_, _suffix)(env, rc, i); \ ++ ptr_src_a = (type*)glue(get_element_, _suffix)(env, ra, i); \ ++ ptr_src_b = (type*)glue(get_element_, _suffix)(env, rb, i); \ ++ \ ++ if (*ptr_src_a >= *ptr_src_b) { \ ++ *ptr_dst = *ptr_src_a; \ ++ } else { \ ++ *ptr_dst = *ptr_src_b; \ ++ } \ ++ } \ ++ } ++ ++#define HELPER_VMIN(name, _suffix, type, loop) \ ++ void glue(glue(helper_, name), _suffix)(CPUSW64State *env, uint64_t ra, \ ++ uint64_t rb, uint64_t rc) \ ++ { \ ++ int i; \ ++ type *ptr_dst, *ptr_src_a, *ptr_src_b; \ ++ \ ++ for (i = 0; i < loop; i++) { \ ++ ptr_dst = (type*)glue(get_element_, _suffix)(env, rc, i); \ ++ ptr_src_a = (type*)glue(get_element_, _suffix)(env, ra, i); \ ++ ptr_src_b = (type*)glue(get_element_, _suffix)(env, rb, i); \ ++ \ ++ if (*ptr_src_a <= *ptr_src_b) { \ ++ *ptr_dst = *ptr_src_a; \ ++ } else { \ ++ *ptr_dst = *ptr_src_b; \ ++ } \ ++ } \ ++ } ++ ++HELPER_VMAX(vmax, b, int8_t, 32) ++HELPER_VMIN(vmin, b, int8_t, 32) ++HELPER_VMAX(vmax, h, int16_t, 16) ++HELPER_VMIN(vmin, h, int16_t, 16) ++HELPER_VMAX(vmax, w, int32_t, 8) ++HELPER_VMIN(vmin, w, int32_t, 8) ++HELPER_VMAX(vumax, b, uint8_t, 32) ++HELPER_VMIN(vumin, b, uint8_t, 32) ++HELPER_VMAX(vumax, h, uint16_t, 16) ++HELPER_VMIN(vumin, h, uint16_t, 16) ++HELPER_VMAX(vumax, w, uint32_t, 8) ++HELPER_VMIN(vumin, w, uint32_t, 8) ++ ++void helper_sraow(CPUSW64State *env, uint64_t ra, uint64_t rc, uint64_t shift) ++{ ++ int i; ++ int adden; ++ int dest, src; ++ uint64_t sign; ++ adden = shift >> 6; ++ shift &= 0x3f; ++ sign = (uint64_t)((int64_t)env->fr[ra + 96] >> 63); ++#ifdef DEBUG_SIMD ++ printf("right shift = %ld adden = %d\n", shift, adden); ++ printf("in_fr[%ld]:", ra); ++ for (i = 3 ; i >= 0; i--) { ++ printf("%016lx ", env->fr[ra + 32 * i]); ++ } ++ printf("\n"); ++#endif ++ ++ for (i = 0; (i + adden) < 4; i++) { ++ dest = i * 32 + rc; ++ src = (i + adden) * 32 + ra; ++ env->fr[dest] = env->fr[src] >> shift; ++ if (shift != 0) { ++ if (((i + adden) < 3)) ++ env->fr[dest] |= (env->fr[src + 32] << (64 - shift)); ++ else ++ env->fr[dest] |= (sign << (64 - shift)); ++ } ++ } ++ ++ for (; i < 4; i++) { ++ env->fr[rc + i * 32] = sign; ++ } ++#ifdef DEBUG_SIMD ++ printf("out_fr[%ld]:", rc); ++ for (i = 3 ; i >= 0; i--) { ++ printf("%016lx ", env->fr[rc + 32 * i]); ++ } ++ printf("\n"); ++#endif ++} ++ ++static uint16_t sm4_sbox[16][16] = { ++ { 0xd6, 0x90, 0xe9, 0xfe, 0xcc, 0xe1, 0x3d, 0xb7, 0x16, 0xb6, 0x14, 0xc2, 0x28, 0xfb, 0x2c, 0x05 }, ++ { 0x2b, 0x67, 0x9a, 0x76, 0x2a, 0xbe, 0x04, 0xc3, 0xaa, 0x44, 0x13, 0x26, 0x49, 0x86, 0x06, 0x99 }, ++ { 0x9c, 0x42, 0x50, 0xf4, 0x91, 0xef, 0x98, 0x7a, 0x33, 0x54, 0x0b, 0x43, 0xed, 0xcf, 0xac, 0x62 }, ++ { 0xe4, 0xb3, 0x1c, 0xa9, 0xc9, 0x08, 0xe8, 0x95, 0x80, 0xdf, 0x94, 0xfa, 0x75, 0x8f, 0x3f, 0xa6 }, ++ { 0x47, 0x07, 0xa7, 0xfc, 0xf3, 0x73, 0x17, 0xba, 0x83, 0x59, 0x3c, 0x19, 0xe6, 0x85, 0x4f, 0xa8 }, ++ { 0x68, 0x6b, 0x81, 0xb2, 0x71, 0x64, 0xda, 0x8b, 0xf8, 0xeb, 0x0f, 0x4b, 0x70, 0x56, 0x9d, 0x35 }, ++ { 0x1e, 0x24, 0x0e, 0x5e, 0x63, 0x58, 0xd1, 0xa2, 0x25, 0x22, 0x7c, 0x3b, 0x01, 0x21, 0x78, 0x87 }, ++ { 0xd4, 0x00, 0x46, 0x57, 0x9f, 0xd3, 0x27, 0x52, 0x4c, 0x36, 0x02, 0xe7, 0xa0, 0xc4, 0xc8, 0x9e }, ++ { 0xea, 0xbf, 0x8a, 0xd2, 0x40, 0xc7, 0x38, 0xb5, 0xa3, 0xf7, 0xf2, 0xce, 0xf9, 0x61, 0x15, 0xa1 }, ++ { 0xe0, 0xae, 0x5d, 0xa4, 0x9b, 0x34, 0x1a, 0x55, 0xad, 0x93, 0x32, 0x30, 0xf5, 0x8c, 0xb1, 0xe3 }, ++ { 0x1d, 0xf6, 0xe2, 0x2e, 0x82, 0x66, 0xca, 0x60, 0xc0, 0x29, 0x23, 0xab, 0x0d, 0x53, 0x4e, 0x6f }, ++ { 0xd5, 0xdb, 0x37, 0x45, 0xde, 0xfd, 0x8e, 0x2f, 0x03, 0xff, 0x6a, 0x72, 0x6d, 0x6c, 0x5b, 0x51 }, ++ { 0x8d, 0x1b, 0xaf, 0x92, 0xbb, 0xdd, 0xbc, 0x7f, 0x11, 0xd9, 0x5c, 0x41, 0x1f, 0x10, 0x5a, 0xd8 }, ++ { 0x0a, 0xc1, 0x31, 0x88, 0xa5, 0xcd, 0x7b, 0xbd, 0x2d, 0x74, 0xd0, 0x12, 0xb8, 0xe5, 0xb4, 0xb0 }, ++ { 0x89, 0x69, 0x97, 0x4a, 0x0c, 0x96, 0x77, 0x7e, 0x65, 0xb9, 0xf1, 0x09, 0xc5, 0x6e, 0xc6, 0x84 }, ++ { 0x18, 0xf0, 0x7d, 0xec, 0x3a, 0xdc, 0x4d, 0x20, 0x79, 0xee, 0x5f, 0x3e, 0xd7, 0xcb, 0x39, 0x48 } ++}; ++ ++static uint32_t SBOX(uint32_t val) ++{ ++ int ret = 0; ++ int i; ++ int idx_x, idx_y; ++ for (i = 0; i < 4; i++) { ++ idx_x = (val >> (i * 8)) & 0xff; ++ idx_y = idx_x & 0xf; ++ idx_x = idx_x >> 4; ++ ++ ret |= (sm4_sbox[idx_x][idx_y] << (i * 8)); ++ } ++ return ret; ++} ++ ++static uint32_t rotl(uint32_t val, int shift) ++{ ++ uint64_t ret = (uint64_t)val; ++ ret = (ret << (shift & 0x1f)); ++ return (uint32_t)((ret & 0xffffffff) | (ret >> 32)); ++} ++ ++void helper_vsm4r(CPUSW64State *env, uint64_t ra, uint64_t rb, uint64_t rc) ++{ ++ uint32_t W[12], rk[8]; ++ uint32_t temp1, temp2; ++ int i, j; ++ ++ for (i = 0; i < 8; i++) { ++ rk[i] = *get_element_w(env, rb, i); ++ } ++ for (i = 0; i < 2; i++) { ++ for (j = 0; j < 4; j++) { ++ W[j] = *get_element_w(env, ra, i * 4 + j); ++ } ++ for (j = 0; j < 8; j++) { ++ temp1 = W[j + 1] ^ W[j + 2] ^ W[j + 3] ^ rk[j]; ++ temp2 = SBOX(temp1); ++ W[j + 4] = W[j] ^ temp2 ^ rotl(temp2, 2) ^ rotl(temp2, 10) ^ rotl(temp2, 18) ^ rotl(temp2, 24); ++ } ++ ++ for (j = 0; j < 4; j++) { ++ *get_element_w(env, rc, i * 4 + j) = W[8 + j]; ++ } ++ } ++} ++ ++void helper_vcmpueqb(CPUSW64State *env, uint64_t ra, uint64_t rb, uint64_t rc) ++{ ++ uint8_t *ptr_a, *ptr_b, *ptr_c; ++ int i; ++ ++ for (i = 0; i < 32; i++) { ++ ptr_a = get_element_b(env, ra, i); ++ ptr_b = get_element_b(env, rb, i); ++ ptr_c = get_element_b(env, rc, i); ++ ++ *ptr_c = (*ptr_a == *ptr_b) ? 1 : 0; ++ ; ++ } ++} ++ ++void helper_vcmpugtb(CPUSW64State *env, uint64_t ra, uint64_t rb, uint64_t rc) ++{ ++ uint8_t *ptr_a, *ptr_b, *ptr_c; ++ int i; ++ ++ for (i = 0; i < 32; i++) { ++ ptr_a = get_element_b(env, ra, i); ++ ptr_b = get_element_b(env, rb, i); ++ ptr_c = get_element_b(env, rc, i); ++ ++ *ptr_c = (*ptr_a > *ptr_b) ? 1 : 0; ++ ; ++ } ++} ++ ++void helper_vcmpueqbi(CPUSW64State *env, uint64_t ra, uint64_t vb, ++ uint64_t rc) ++{ ++ uint8_t *ptr_a, *ptr_c; ++ int i; ++ ++ for (i = 0; i < 32; i++) { ++ ptr_a = get_element_b(env, ra, i); ++ ptr_c = get_element_b(env, rc, i); ++ ++ *ptr_c = (*ptr_a == vb) ? 1 : 0; ++ ; ++ } ++} ++ ++void helper_vcmpugtbi(CPUSW64State *env, uint64_t ra, uint64_t vb, ++ uint64_t rc) ++{ ++ uint8_t *ptr_a, *ptr_c; ++ int i; ++ ++ for (i = 0; i < 32; i++) { ++ ptr_a = get_element_b(env, ra, i); ++ ptr_c = get_element_b(env, rc, i); ++ ++ *ptr_c = (*ptr_a > vb) ? 1 : 0; ++ ; ++ } ++} ++ ++void helper_vsm3msw(CPUSW64State *env, uint64_t ra, uint64_t rb, uint64_t rc) ++{ ++ uint32_t W[24]; ++ uint32_t temp; ++ int i; ++ ++ for (i = 0; i < 8; i++) { ++ W[i + 0] = *get_element_w(env, ra, i); ++ W[i + 8] = *get_element_w(env, rb, i); ++ } ++ for (i = 16; i < 24; i++) { ++ temp = W[i - 16] ^ W[i - 9] ^ rotl(W[i - 3], 15); ++ temp = temp ^ rotl(temp, 15) ^ rotl(temp, 23) ^ rotl(W[i - 13], 7) ^ W[i - 6]; ++ W[i] = temp; ++ } ++ for (i = 0; i < 8; i++) { ++ *get_element_w(env, rc, i) = W[16 + i]; ++ } ++} ++ ++static uint32_t selck[4][8] = { ++ {0x00070e15, 0x1c232a31, 0x383f464d, 0x545b6269, 0x70777e85, 0x8c939aa1, 0xa8afb6bd, 0xc4cbd2d9}, ++ {0xe0e7eef5, 0xfc030a11, 0x181f262d, 0x343b4249, 0x50575e65, 0x6c737a81, 0x888f969d, 0xa4abb2b9}, ++ {0xc0c7ced5, 0xdce3eaf1, 0xf8ff060d, 0x141b2229, 0x30373e45, 0x4c535a61, 0x686f767d, 0x848b9299}, ++ {0xa0a7aeb5, 0xbcc3cad1, 0xd8dfe6ed, 0xf4fb0209, 0x10171e25, 0x2c333a41, 0x484f565d, 0x646b7279} ++}; ++ ++void helper_vsm4key(CPUSW64State *env, uint64_t ra, uint64_t vb, uint64_t rc) ++{ ++ uint32_t K[12], *CK; ++ int i; ++ uint32_t temp1, temp2; ++ ++ for (i = 4; i < 8; i++) { ++ K[i - 4] = *get_element_w(env, ra, i); ++ } ++ CK = selck[vb]; ++ ++ for (i = 0; i < 8; i++) { ++ temp1 = K[i + 1] ^ K[i + 2] ^ K[i + 3] ^ CK[i]; ++ temp2 = SBOX(temp1); ++ K[i + 4] = K[i] ^ temp2 ^ rotl(temp2, 13) ^ rotl(temp2, 23); ++ } ++ for (i = 0; i < 8; i++) { ++ *get_element_w(env, rc, i) = K[i + 4]; ++ } ++} ++ ++void helper_vinsb(CPUSW64State *env, uint64_t va, uint64_t rb, uint64_t vc, ++ uint64_t rd) ++{ ++ int i; ++ ++ for (i = 0; i < 128; i += 32) { ++ env->fr[rd + i] = env->fr[rb + i]; ++ } ++ ++ *get_element_b(env, rd, vc) = (uint8_t)(va & 0xff); ++} ++ ++void helper_vinsh(CPUSW64State *env, uint64_t va, uint64_t rb, uint64_t vc, ++ uint64_t rd) ++{ ++ int i; ++ ++ if (vc >= 16) ++ return; ++ ++ for (i = 0; i < 128; i += 32) { ++ env->fr[rd + i] = env->fr[rb + i]; ++ } ++ ++ *get_element_h(env, rd, vc) = (uint16_t)(va & 0xffff); ++} ++ ++void helper_vinsectlh(CPUSW64State *env, uint64_t ra, uint64_t rb, ++ uint64_t rd) ++{ ++ int i; ++ uint32_t temp[8]; ++ for (i = 0; i < 8; i++) { ++ temp[i] = *get_element_h(env, ra, i) | ((uint32_t)*get_element_h(env, rb, i) << 16); ++ } ++ for (i = 0; i < 8; i++) { ++ *get_element_w(env, rd, i) = temp[i]; ++ } ++} ++void helper_vinsectlw(CPUSW64State *env, uint64_t ra, uint64_t rb, ++ uint64_t rd) ++{ ++ int i; ++ uint64_t temp[4]; ++ for (i = 0; i < 4; i++) { ++ temp[i] = *get_element_w(env, ra, i) | ((uint64_t)*get_element_w(env, rb, i) << 32); ++ } ++ for (i = 0; i < 4; i++) { ++ *get_element_l(env, rd, i) = temp[i]; ++ } ++} ++ ++void helper_vinsectlb(CPUSW64State *env, uint64_t ra, uint64_t rb, ++ uint64_t rd) ++{ ++ int i; ++ uint16_t temp[16]; ++ for (i = 0; i < 16; i++) { ++ temp[i] = *get_element_b(env, ra, i) | ((uint16_t)*get_element_b(env, rb, i) << 8); ++ } ++ for (i = 0; i < 16; i++) { ++ *get_element_h(env, rd, i) = temp[i]; ++ } ++} ++ ++void helper_vshfq(CPUSW64State *env, uint64_t ra, uint64_t rb, uint64_t vc, ++ uint64_t rd) ++{ ++ int i; ++ int idx; ++ uint64_t temp[4]; ++ for (i = 0; i < 2; i++) { ++ idx = ((vc >> (i * 2)) & 1) * 64; ++ if ((vc >> (i * 2 + 1)) & 1) { ++ temp[i * 2] = env->fr[rb + idx]; ++ temp[i * 2 + 1] = env->fr[rb + idx + 32]; ++ } else { ++ temp[i * 2] = env->fr[ra + idx]; ++ temp[i * 2 + 1] = env->fr[ra + idx + 32]; ++ } ++ } ++ for (i = 0; i < 4; i++) { ++ env->fr[rd + i * 32] = temp[i]; ++ } ++} ++ ++void helper_vshfqb(CPUSW64State *env, uint64_t ra, uint64_t rb, uint64_t rd) ++{ ++ int i; ++ int idx; ++ int vb; ++ uint8_t temp[32]; ++ ++ for (i = 0; i < 16; i++) { ++ vb = *get_element_b(env, rb, i); ++ if (vb >> 7) { ++ temp[i] = 0; ++ } else { ++ idx = vb & 0xf; ++ temp[i] = *get_element_b(env, ra, idx); ++ } ++ vb = *get_element_b(env, rb, i + 16); ++ if (vb >> 7) { ++ temp[i + 16] = 0; ++ } else { ++ idx = vb & 0xf; ++ temp[i + 16] = *get_element_b(env, ra, idx + 16); ++ } ++ } ++ for (i = 0; i < 4; i++) { ++ env->fr[rd + i * 32] = *((uint64_t*)temp + i); ++ } ++} ++ ++void helper_vsm3r(CPUSW64State *env, uint64_t ra, uint64_t rb, uint64_t vc, ++ uint64_t rd) ++{ ++ uint32_t W[8]; ++ uint32_t A, B, C, D, E, F, G, H, T; ++ int i; ++ uint32_t SS1, SS2, TT1, TT2, P0; ++ ++ if (vc >= 16) ++ return; ++ for (i = 0; i < 8; i++) { ++ W[i] = *get_element_w(env, ra, i); ++ } ++ A = *get_element_w(env, rb, 0); ++ B = *get_element_w(env, rb, 1); ++ C = *get_element_w(env, rb, 2); ++ D = *get_element_w(env, rb, 3); ++ E = *get_element_w(env, rb, 4); ++ F = *get_element_w(env, rb, 5); ++ G = *get_element_w(env, rb, 6); ++ H = *get_element_w(env, rb, 7); ++ ++ if (vc < 4) { ++ T = 0x79cc4519; ++ for (i = 0; i < 4; i++) { ++ SS1 = rotl(rotl(A, 12) + E + rotl(T, 4 * vc + i), 7); ++ SS2 = SS1 ^ rotl(A, 12); ++ TT1 = (A ^ B ^ C) + D + SS2 + (W[i] ^ W[i + 4]); ++ TT2 = (E ^ F ^ G) + H + SS1 + W[i]; ++ ++ P0 = TT2 ^ rotl(TT2, 9) ^ rotl(TT2, 17); ++ ++ H = G; ++ G = rotl(F, 19); ++ F = E; ++ E = P0; ++ D = C; ++ C = rotl(B, 9); ++ B = A; ++ A = TT1; ++ } ++ } else { ++ T = 0x7a879d8a; ++ for (i = 0; i < 4; i++) { ++ SS1 = rotl(rotl(A, 12) + E + rotl(T, 4 * vc + i), 7); ++ SS2 = SS1 ^ rotl(A, 12); ++ TT1 = ((A & B) | (A & C) | (B & C)) + D + SS2 + (W[i] ^ W[i + 4]); ++ TT2 = ((E & F) | ((~E) & G)) + H + SS1 + W[i]; ++ ++ P0 = TT2 ^ rotl(TT2, 9) ^ rotl(TT2, 17); ++ ++ H = G; ++ G = rotl(F, 19); ++ F = E; ++ E = P0; ++ D = C; ++ C = rotl(B, 9); ++ B = A; ++ A = TT1; ++ } ++ } ++ *get_element_w(env, rd, 0) = A; ++ *get_element_w(env, rd, 1) = B; ++ *get_element_w(env, rd, 2) = C; ++ *get_element_w(env, rd, 3) = D; ++ *get_element_w(env, rd, 4) = E; ++ *get_element_w(env, rd, 5) = F; ++ *get_element_w(env, rd, 6) = G; ++ *get_element_w(env, rd, 7) = H; ++} +diff --git a/target/sw64/translate.c b/target/sw64/translate.c +new file mode 100644 +index 0000000000..37b7e89077 +--- /dev/null ++++ b/target/sw64/translate.c +@@ -0,0 +1,3798 @@ ++#include "translate.h" ++#include "tcg/tcg.h" ++#define DEVELOP_SW64 1 ++#ifdef DEVELOP_SW64 ++ ++#define ILLEGAL(x) \ ++ do { \ ++ printf("Illegal SW64 0x%x at line %d!\n", x, __LINE__); \ ++ exit(-1); \ ++ } while (0) ++#endif ++ ++TCGv cpu_pc; ++TCGv cpu_std_ir[31]; ++TCGv cpu_fr[128]; ++TCGv cpu_lock_addr; ++TCGv cpu_lock_flag; ++TCGv cpu_lock_success; ++#ifdef SW64_FIXLOCK ++TCGv cpu_lock_value; ++#endif ++ ++#ifndef CONFIG_USER_ONLY ++TCGv cpu_hm_ir[31]; ++#endif ++ ++#include "exec/gen-icount.h" ++ ++void sw64_translate_init(void) ++{ ++#define DEF_VAR(V) \ ++ { &cpu_##V, #V, offsetof(CPUSW64State, 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_flag), DEF_VAR(lock_success), ++#ifdef SW64_FIXLOCK ++ DEF_VAR(lock_value), ++#endif ++ }; ++ cpu_pc = tcg_global_mem_new_i64(cpu_env, ++ offsetof(CPUSW64State, pc), "PC"); ++ ++#undef DEF_VAR ++ ++ /* Use the symbolic register names that match the disassembler. */ ++ static const char ireg_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[128][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", "f31", "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", "f31", "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", "f31", "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", "f31"}; ++ ++#ifndef CONFIG_USER_ONLY ++ static const char shadow_names[10][8] = { ++ "hm_p1", "hm_p2", "hm_p4", "hm_p5", "hm_p6", ++ "hm_p7", "hm_p20", "hm_p21", "hm_p22", "hm_p23"}; ++ static const int shadow_index[10] = {1, 2, 4, 5, 6, 7, 20, 21, 22, 23}; ++#endif ++ ++ int i; ++ ++ for (i = 0; i < 31; i++) { ++ cpu_std_ir[i] = tcg_global_mem_new_i64( ++ cpu_env, offsetof(CPUSW64State, ir[i]), ireg_names[i]); ++ } ++ ++ for (i = 0; i < 128; i++) { ++ cpu_fr[i] = tcg_global_mem_new_i64( ++ cpu_env, offsetof(CPUSW64State, fr[i]), freg_names[i]); ++ } ++ 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); ++ } ++#ifndef CONFIG_USER_ONLY ++ memcpy(cpu_hm_ir, cpu_std_ir, sizeof(cpu_hm_ir)); ++ for (i = 0; i < 10; i++) { ++ int r = shadow_index[i]; ++ cpu_hm_ir[r] = tcg_global_mem_new_i64( ++ cpu_env, offsetof(CPUSW64State, sr[i]), shadow_names[i]); ++ } ++#endif ++} ++ ++static bool in_superpage(DisasContext* ctx, int64_t addr) ++{ ++ return false; ++} ++ ++bool use_exit_tb(DisasContext* ctx) ++{ ++ return ((tb_cflags(ctx->base.tb) & CF_LAST_IO) || ++ ctx->base.singlestep_enabled || singlestep); ++} ++ ++bool use_goto_tb(DisasContext* ctx, uint64_t dest) ++{ ++ /* Suppress goto_tb in the case of single-steping and IO. */ ++ if (unlikely(use_exit_tb(ctx))) { ++ return false; ++ } ++ /* 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. */ ++#ifndef CONFIG_USER_ONLY ++ return ((ctx->base.tb->pc ^ dest) & TARGET_PAGE_MASK) == 0; ++#else ++ return true; ++#endif ++} ++ ++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 TCGv load_zero(DisasContext *ctx) ++{ ++ if (!ctx->zero) { ++ ctx->zero = tcg_const_i64(0); ++ } ++ return ctx->zero; ++} ++ ++static void free_context_temps(DisasContext *ctx) ++{ ++ if (ctx->zero) { ++ tcg_temp_free(ctx->zero); ++ ctx->zero = NULL; ++ } ++} ++ ++static TCGv load_gir(DisasContext *ctx, unsigned reg) ++{ ++ if (likely(reg < 31)) { ++ return ctx->ir[reg]; ++ } else { ++ return load_zero(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 DisasJumpType gen_excp(DisasContext* ctx, int exception, ++ int error_code) ++{ ++ tcg_gen_movi_i64(cpu_pc, ctx->base.pc_next); ++ gen_excp_1(exception, error_code); ++ return DISAS_NORETURN; ++} ++ ++static int i_count = 1; ++ ++static inline DisasJumpType gen_invalid(DisasContext *ctx) ++{ ++ if (i_count == 0) { ++ i_count++; ++ return DISAS_NEXT; ++ } ++ fprintf(stderr, "here %lx\n", ctx->base.pc_next); ++ return gen_excp(ctx, EXCP_OPCDEC, 0); ++} ++ ++static uint64_t zapnot_mask(uint8_t byte_mask) ++{ ++ uint64_t mask = 0; ++ int i; ++ ++ for (i = 0; i < 8; ++i) { ++ if ((byte_mask >> i) & 1) { ++ mask |= 0xffull << (i * 8); ++ } ++ } ++ return mask; ++} ++ ++static void gen_ins_l(DisasContext* ctx, TCGv vc, TCGv va, TCGv vb, ++ uint8_t byte_mask) ++{ ++ TCGv tmp = tcg_temp_new(); ++ TCGv shift = tcg_temp_new(); ++ ++ tcg_gen_andi_i64(tmp, va, zapnot_mask(byte_mask)); ++ ++ tcg_gen_andi_i64(shift, vb, 7); ++ tcg_gen_shli_i64(shift, shift, 3); ++ tcg_gen_shl_i64(vc, tmp, shift); ++ ++ tcg_temp_free(shift); ++ tcg_temp_free(tmp); ++} ++ ++static void gen_ins_h(DisasContext* ctx, TCGv vc, TCGv va, TCGv vb, ++ uint8_t byte_mask) ++{ ++ TCGv tmp = tcg_temp_new(); ++ TCGv shift = tcg_temp_new(); ++ ++ tcg_gen_andi_i64(tmp, va, zapnot_mask(byte_mask)); ++ ++ tcg_gen_shli_i64(shift, vb, 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); ++} ++ ++static void gen_ext_l(DisasContext* ctx, TCGv vc, TCGv va, TCGv vb, ++ uint8_t byte_mask) ++{ ++ TCGv tmp = tcg_temp_new(); ++ TCGv shift = tcg_temp_new(); ++ ++ tcg_gen_andi_i64(shift, vb, 7); ++ tcg_gen_shli_i64(shift, shift, 3); ++ tcg_gen_shr_i64(tmp, va, shift); ++ ++ tcg_gen_andi_i64(vc, tmp, zapnot_mask(byte_mask)); ++ ++ tcg_temp_free(shift); ++ tcg_temp_free(tmp); ++} ++ ++static void gen_ext_h(DisasContext* ctx, TCGv vc, TCGv va, TCGv vb, ++ uint8_t byte_mask) ++{ ++ TCGv tmp = tcg_temp_new(); ++ TCGv shift = tcg_temp_new(); ++ ++ tcg_gen_andi_i64(shift, vb, 7); ++ tcg_gen_shli_i64(shift, shift, 3); ++ tcg_gen_movi_i64(tmp, 64); ++ tcg_gen_sub_i64(shift, tmp, shift); ++ tcg_gen_shl_i64(tmp, va, shift); ++ ++ tcg_gen_andi_i64(vc, tmp, zapnot_mask(byte_mask)); ++ ++ tcg_temp_free(shift); ++ tcg_temp_free(tmp); ++} ++ ++static void gen_mask_l(DisasContext* ctx, TCGv vc, TCGv va, TCGv vb, ++ uint8_t byte_mask) ++{ ++ TCGv shift = tcg_temp_new(); ++ TCGv mask = tcg_temp_new(); ++ ++ tcg_gen_andi_i64(shift, vb, 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_mask_h(DisasContext *ctx, TCGv vc, TCGv va, TCGv vb, ++ uint8_t byte_mask) ++{ ++ 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, vb, 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); ++} ++ ++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_gir(ctx, rb); ++ ++ if (disp16) { ++ tcg_gen_addi_i64(tmp, addr, (int64_t)disp16); ++ addr = tmp; ++ } else { ++ tcg_gen_mov_i64(tmp, addr); ++ addr = tmp; ++ } ++ if (clear) { ++ tcg_gen_andi_i64(tmp, addr, ~0x7UL); ++ addr = tmp; ++ } ++ ++ va = (fp ? cpu_fr[ra] : load_gir(ctx, ra)); ++ tcg_gen_qemu_load(va, addr, ctx->mem_idx); ++ ++ tcg_temp_free(tmp); ++} ++ ++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_gir(ctx, rb); ++ if (disp16) { ++ tcg_gen_addi_i64(tmp, addr, disp16); ++ addr = tmp; ++ } else { ++ tcg_gen_mov_i64(tmp, addr); ++ addr = tmp; ++ } ++ if (clear) { ++ tcg_gen_andi_i64(tmp, addr, ~0x7); ++ addr = tmp; ++ } ++ va = (fp ? cpu_fr[ra] : load_gir(ctx, ra)); ++ ++ tcg_gen_qemu_store(va, addr, ctx->mem_idx); ++ gen_helper_trace_mem(cpu_env, addr, va); ++ tcg_temp_free(tmp); ++} ++ ++static void cal_with_iregs_2(DisasContext *ctx, TCGv vc, TCGv va, TCGv vb, ++ int32_t disp13, uint16_t fn) ++{ ++ TCGv tmp; ++ ++ switch (fn & 0xff) { ++ case 0x00: ++ /* ADDW */ ++ tcg_gen_add_i64(vc, va, vb); ++ tcg_gen_ext32s_i64(vc, vc); ++ break; ++ case 0x01: ++ /* SUBW */ ++ tcg_gen_sub_i64(vc, va, vb); ++ tcg_gen_ext32s_i64(vc, vc); ++ break; ++ case 0x02: ++ /* S4ADDW */ ++ 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 0x03: ++ /* S4SUBW */ ++ 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 0x04: ++ /* S8ADDW */ ++ 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 0x05: ++ /* S8SUBW */ ++ 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 0x08: ++ /* ADDL */ ++ tcg_gen_add_i64(vc, va, vb); ++ break; ++ case 0x09: ++ /* SUBL */ ++ tcg_gen_sub_i64(vc, va, vb); ++ break; ++ case 0x0a: ++ /* S4ADDL */ ++ tmp = tcg_temp_new(); ++ tcg_gen_shli_i64(tmp, va, 2); ++ tcg_gen_add_i64(vc, tmp, vb); ++ tcg_temp_free(tmp); ++ break; ++ case 0x0b: ++ /* S4SUBL */ ++ tmp = tcg_temp_new(); ++ tcg_gen_shli_i64(tmp, va, 2); ++ tcg_gen_sub_i64(vc, tmp, vb); ++ tcg_temp_free(tmp); ++ break; ++ case 0x0c: ++ /* S8ADDL */ ++ tmp = tcg_temp_new(); ++ tcg_gen_shli_i64(tmp, va, 3); ++ tcg_gen_add_i64(vc, tmp, vb); ++ tcg_temp_free(tmp); ++ break; ++ case 0x0d: ++ /* S8SUBL */ ++ tmp = tcg_temp_new(); ++ tcg_gen_shli_i64(tmp, va, 3); ++ tcg_gen_sub_i64(vc, tmp, vb); ++ tcg_temp_free(tmp); ++ break; ++ case 0x10: ++ /* MULW */ ++ tcg_gen_mul_i64(vc, va, vb); ++ tcg_gen_ext32s_i64(vc, vc); ++ break; ++ case 0x18: ++ /* MULL */ ++ tcg_gen_mul_i64(vc, va, vb); ++ break; ++ case 0x19: ++ /* MULH */ ++ tmp = tcg_temp_new(); ++ tcg_gen_mulu2_i64(tmp, vc, va, vb); ++ tcg_temp_free(tmp); ++ break; ++ case 0x28: ++ /* CMPEQ */ ++ tcg_gen_setcond_i64(TCG_COND_EQ, vc, va, vb); ++ break; ++ case 0x29: ++ /* CMPLT */ ++ tcg_gen_setcond_i64(TCG_COND_LT, vc, va, vb); ++ break; ++ case 0x2a: ++ /* CMPLE */ ++ tcg_gen_setcond_i64(TCG_COND_LE, vc, va, vb); ++ break; ++ case 0x2b: ++ /* CMPULT */ ++ tcg_gen_setcond_i64(TCG_COND_LTU, vc, va, vb); ++ break; ++ case 0x2c: ++ /* CMPULE */ ++ tcg_gen_setcond_i64(TCG_COND_LEU, vc, va, vb); ++ break; ++ case 0x38: ++ /* AND */ ++ tcg_gen_and_i64(vc, va, vb); ++ break; ++ case 0x39: ++ /* BIC */ ++ tcg_gen_andc_i64(vc, va, vb); ++ break; ++ case 0x3a: ++ /* BIS */ ++ tcg_gen_or_i64(vc, va, vb); ++ break; ++ case 0x3b: ++ /* ORNOT */ ++ tcg_gen_orc_i64(vc, va, vb); ++ break; ++ case 0x3c: ++ /* XOR */ ++ tcg_gen_xor_i64(vc, va, vb); ++ break; ++ case 0x3d: ++ /* EQV */ ++ tcg_gen_eqv_i64(vc, va, vb); ++ break; ++ case 0x40: ++ /* INSLB */ ++ gen_ins_l(ctx, vc, va, vb, 0x1); ++ break; ++ case 0x41: ++ /* INSLH */ ++ gen_ins_l(ctx, vc, va, vb, 0x3); ++ break; ++ case 0x42: ++ /* INSLW */ ++ gen_ins_l(ctx, vc, va, vb, 0xf); ++ break; ++ case 0x43: ++ /* INSLL */ ++ gen_ins_l(ctx, vc, va, vb, 0xff); ++ break; ++ case 0x44: ++ /* INSHB */ ++ gen_ins_h(ctx, vc, va, vb, 0x1); ++ break; ++ case 0x45: ++ /* INSHH */ ++ gen_ins_h(ctx, vc, va, vb, 0x3); ++ break; ++ case 0x46: ++ /* INSHW */ ++ gen_ins_h(ctx, vc, va, vb, 0xf); ++ break; ++ case 0x47: ++ /* INSHL */ ++ gen_ins_h(ctx, vc, va, vb, 0xff); ++ break; ++ case 0x48: ++ /* SLL/SLLL */ ++ tmp = tcg_temp_new(); ++ tcg_gen_andi_i64(tmp, vb, 0x3f); ++ tcg_gen_shl_i64(vc, va, tmp); ++ tcg_temp_free(tmp); ++ break; ++ case 0x49: ++ /* SRL/SRLL */ ++ tmp = tcg_temp_new(); ++ tcg_gen_andi_i64(tmp, vb, 0x3f); ++ tcg_gen_shr_i64(vc, va, tmp); ++ tcg_temp_free(tmp); ++ break; ++ case 0x4a: ++ /* SRA/SRAL */ ++ tmp = tcg_temp_new(); ++ tcg_gen_andi_i64(tmp, vb, 0x3f); ++ tcg_gen_sar_i64(vc, va, tmp); ++ tcg_temp_free(tmp); ++ break; ++ case 0x50: ++ /* EXTLB */ ++ gen_ext_l(ctx, vc, va, vb, 0x1); ++ break; ++ case 0x51: ++ /* EXTLH */ ++ gen_ext_l(ctx, vc, va, vb, 0x3); ++ break; ++ case 0x52: ++ /* EXTLW */ ++ gen_ext_l(ctx, vc, va, vb, 0xf); ++ break; ++ case 0x53: ++ /* EXTLL */ ++ gen_ext_l(ctx, vc, va, vb, 0xff); ++ break; ++ case 0x54: ++ /* EXTHB */ ++ gen_ext_h(ctx, vc, va, vb, 0x1); ++ break; ++ case 0x55: ++ /* EXTHH */ ++ gen_ext_h(ctx, vc, va, vb, 0x3); ++ break; ++ case 0x56: ++ /* EXTHW */ ++ gen_ext_h(ctx, vc, va, vb, 0xf); ++ break; ++ case 0x57: ++ /* EXTHL */ ++ gen_ext_h(ctx, vc, va, vb, 0xff); ++ break; ++ case 0x58: ++ /* CTPOP */ ++ tcg_gen_ctpop_i64(vc, vb); ++ break; ++ case 0x59: ++ /* CTLZ */ ++ tcg_gen_clzi_i64(vc, vb, 64); ++ break; ++ case 0x5a: ++ /* CTTZ */ ++ tcg_gen_ctzi_i64(vc, vb, 64); ++ break; ++ case 0x60: ++ /* MASKLB */ ++ gen_mask_l(ctx, vc, va, vb, 0x1); ++ break; ++ case 0x61: ++ /* MASKLH */ ++ gen_mask_l(ctx, vc, va, vb, 0x3); ++ break; ++ case 0x62: ++ /* MASKLW */ ++ gen_mask_l(ctx, vc, va, vb, 0xf); ++ break; ++ case 0x63: ++ /* MASKLL */ ++ gen_mask_l(ctx, vc, va, vb, 0xff); ++ break; ++ case 0x64: ++ /* MASKHB */ ++ gen_mask_h(ctx, vc, va, vb, 0x1); ++ break; ++ case 0x65: ++ /* MASKHH */ ++ gen_mask_h(ctx, vc, va, vb, 0x3); ++ break; ++ case 0x66: ++ /* MASKHW */ ++ gen_mask_h(ctx, vc, va, vb, 0xf); ++ break; ++ case 0x67: ++ /* MASKHL */ ++ gen_mask_h(ctx, vc, va, vb, 0xff); ++ break; ++ case 0x68: ++ /* ZAP */ ++ gen_helper_zap(vc, va, vb); ++ break; ++ case 0x69: ++ /* ZAPNOT */ ++ gen_helper_zapnot(vc, va, vb); ++ break; ++ case 0x6a: ++ /* SEXTB */ ++ tcg_gen_ext8s_i64(vc, vb); ++ break; ++ case 0x6b: ++ /* SEXTH */ ++ tcg_gen_ext16s_i64(vc, vb); ++ break; ++ case 0x6c: ++ /* CMPGEB*/ ++ gen_helper_cmpgeb(vc, va, vb); ++ break; ++ default: ++ ILLEGAL(fn); ++ } ++} ++ ++static void cal_with_imm_2(DisasContext *ctx, TCGv vc, TCGv va, int64_t disp, ++ uint8_t fn) ++{ ++ TCGv_i64 t0 = tcg_const_i64(disp); ++ cal_with_iregs_2(ctx, vc, va, t0, 0, fn); ++ tcg_temp_free_i64(t0); ++} ++ ++static void cal_with_iregs_3(DisasContext *ctx, TCGv vd, TCGv va, TCGv vb, ++ TCGv vc, uint8_t fn) ++{ ++ TCGv_i64 t0 = tcg_const_i64(0); ++ TCGv_i64 tmp; ++ switch (fn) { ++ case 0x0: ++ /* SELEQ */ ++ tcg_gen_movcond_i64(TCG_COND_EQ, vd, va, t0, vb, vc); ++ break; ++ case 0x1: ++ /* SELGE */ ++ tcg_gen_movcond_i64(TCG_COND_GE, vd, va, t0, vb, vc); ++ break; ++ case 0x2: ++ /* SELGT */ ++ tcg_gen_movcond_i64(TCG_COND_GT, vd, va, t0, vb, vc); ++ break; ++ case 0x3: ++ /* SELLE */ ++ tcg_gen_movcond_i64(TCG_COND_LE, vd, va, t0, vb, vc); ++ break; ++ case 0x4: ++ /* SELLT */ ++ tcg_gen_movcond_i64(TCG_COND_LT, vd, va, t0, vb, vc); ++ break; ++ case 0x5: ++ /* SELNE */ ++ tcg_gen_movcond_i64(TCG_COND_NE, vd, va, t0, vb, vc); ++ break; ++ case 0x6: ++ /* SELLBC */ ++ tmp = tcg_temp_new_i64(); ++ tcg_gen_andi_i64(tmp, va, 1); ++ tcg_gen_movcond_i64(TCG_COND_EQ, vd, tmp, t0, vb, vc); ++ tcg_temp_free_i64(tmp); ++ break; ++ case 0x7: ++ /* SELLBS */ ++ tmp = tcg_temp_new_i64(); ++ tcg_gen_andi_i64(tmp, va, 1); ++ tcg_gen_movcond_i64(TCG_COND_NE, vd, tmp, t0, vb, vc); ++ tcg_temp_free_i64(tmp); ++ break; ++ default: ++ ILLEGAL(fn); ++ break; ++ } ++ tcg_temp_free_i64(t0); ++} ++ ++static void cal_with_imm_3(DisasContext *ctx, TCGv vd, TCGv va, int32_t disp, ++ TCGv vc, uint8_t fn) ++{ ++ TCGv_i64 vb = tcg_const_i64(disp); ++ cal_with_iregs_3(ctx, vd, va, vb, vc, fn); ++ tcg_temp_free_i64(vb); ++} ++ ++static DisasJumpType gen_bdirect(DisasContext *ctx, int ra, int32_t disp) ++{ ++ uint64_t dest = ctx->base.pc_next + ((int64_t)disp << 2); ++ if (ra != 31) { ++ tcg_gen_movi_i64(load_gir(ctx, ra), ctx->base.pc_next & (~0x3UL)); ++ } ++ 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(ctx->base.tb, 0); ++ return DISAS_NORETURN; ++ } else { ++ tcg_gen_movi_i64(cpu_pc, dest); ++ return DISAS_PC_UPDATED; ++ } ++} ++ ++static DisasJumpType gen_bcond_internal(DisasContext *ctx, TCGCond cond, ++ TCGv cmp, int disp) ++{ ++ uint64_t dest = ctx->base.pc_next + (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->base.pc_next); ++ tcg_gen_exit_tb(ctx->base.tb, 0); ++ ++ gen_set_label(lab_true); ++ tcg_gen_goto_tb(1); ++ tcg_gen_movi_i64(cpu_pc, dest); ++ tcg_gen_exit_tb(ctx->base.tb, 1); ++ ++ return DISAS_NORETURN; ++ } else { ++ TCGv_i64 t = tcg_const_i64(0); ++ TCGv_i64 d = tcg_const_i64(dest); ++ TCGv_i64 p = tcg_const_i64(ctx->base.pc_next); ++ ++ tcg_gen_movcond_i64(cond, cpu_pc, cmp, t, d, p); ++ ++ tcg_temp_free_i64(t); ++ tcg_temp_free_i64(d); ++ tcg_temp_free_i64(p); ++ return DISAS_PC_UPDATED; ++ } ++} ++ ++static DisasJumpType gen_bcond(DisasContext *ctx, TCGCond cond, uint32_t ra, ++ int32_t disp, uint64_t mask) ++{ ++ TCGv tmp = tcg_temp_new(); ++ DisasJumpType ret; ++ ++ tcg_gen_andi_i64(tmp, load_gir(ctx, ra), mask); ++ ret = gen_bcond_internal(ctx, cond, tmp, disp); ++ tcg_temp_free(tmp); ++ return ret; ++} ++ ++static DisasJumpType gen_fbcond(DisasContext *ctx, TCGCond cond, int ra, ++ int32_t disp) ++{ ++ TCGv cmp_tmp = tcg_temp_new(); ++ DisasJumpType ret; ++ ++ gen_fold_mzero(cond, cmp_tmp, cpu_fr[ra]); ++ ret = gen_bcond_internal(ctx, cond, cmp_tmp, disp); ++ tcg_temp_free(cmp_tmp); ++ return ret; ++} ++ ++#ifndef CONFIG_USER_ONLY ++static void gen_qemu_pri_ldw(TCGv t0, TCGv t1, int memidx) ++{ ++ gen_helper_pri_ldw(t0, cpu_env, t1); ++} ++ ++static void gen_qemu_pri_stw(TCGv t0, TCGv t1, int memidx) ++{ ++ gen_helper_pri_stw(cpu_env, t0, t1); ++} ++ ++static void gen_qemu_pri_ldl(TCGv t0, TCGv t1, int memidx) ++{ ++ gen_helper_pri_ldl(t0, cpu_env, t1); ++} ++ ++static void gen_qemu_pri_stl(TCGv t0, TCGv t1, int memidx) ++{ ++ gen_helper_pri_stl(cpu_env, t0, t1); ++} ++#endif ++ ++static inline void gen_load_mem_simd( ++ DisasContext *ctx, void (*tcg_gen_qemu_load)(int t0, TCGv t1, int flags), ++ int ra, int rb, int32_t disp16, uint64_t mask) ++{ ++ TCGv tmp, addr; ++ ++ /* 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_gir(ctx, rb); ++ ++ if (disp16) { ++ tcg_gen_addi_i64(tmp, addr, (int64_t)disp16); ++ addr = tmp; ++ } else { ++ tcg_gen_mov_i64(tmp, addr); ++ addr = tmp; ++ } ++ ++ if (mask) { ++ tcg_gen_andi_i64(addr, addr, mask); ++ } ++ ++ tcg_gen_qemu_load(ra, addr, ctx->mem_idx); ++ // FIXME: for debug ++ ++ tcg_temp_free(tmp); ++} ++ ++static inline void gen_store_mem_simd( ++ DisasContext *ctx, void (*tcg_gen_qemu_store)(int t0, TCGv t1, int flags), ++ int ra, int rb, int32_t disp16, uint64_t mask) ++{ ++ TCGv tmp, addr; ++ ++ tmp = tcg_temp_new(); ++ addr = load_gir(ctx, rb); ++ if (disp16) { ++ tcg_gen_addi_i64(tmp, addr, (int64_t)disp16); ++ addr = tmp; ++ } else { ++ tcg_gen_mov_i64(tmp, addr); ++ addr = tmp; ++ } ++ if (mask) { ++ tcg_gen_andi_i64(addr, addr, mask); ++ } ++ // FIXME: for debug ++ tcg_gen_qemu_store(ra, addr, ctx->mem_idx); ++ ++ tcg_temp_free(tmp); ++} ++ ++static void gen_qemu_ldwe(int t0, TCGv t1, int memidx) ++{ ++ TCGv tmp = tcg_temp_new(); ++ ++ tcg_gen_qemu_ld_i64(tmp, t1, memidx, MO_ALIGN_4 | MO_LEUL); ++ tcg_gen_shli_i64(cpu_fr[t0], tmp, 32); ++ tcg_gen_or_i64(cpu_fr[t0], cpu_fr[t0], tmp); ++ tcg_gen_mov_i64(cpu_fr[t0 + 32], cpu_fr[t0]); ++ tcg_gen_mov_i64(cpu_fr[t0 + 64], cpu_fr[t0]); ++ tcg_gen_mov_i64(cpu_fr[t0 + 96], cpu_fr[t0]); ++ ++ tcg_temp_free(tmp); ++} ++ ++static void gen_qemu_vlds(int t0, TCGv t1, int memidx) ++{ ++ int i; ++ TCGv_i32 tmp32 = tcg_temp_new_i32(); ++ ++ tcg_gen_qemu_ld_i32(tmp32, t1, memidx, MO_ALIGN_4 | MO_LEUL); ++ gen_helper_memory_to_s(cpu_fr[t0], tmp32); ++ tcg_gen_addi_i64(t1, t1, 4); ++ ++ for (i = 1; i < 4; i++) { ++ tcg_gen_qemu_ld_i32(tmp32, t1, memidx, MO_LEUL); ++ gen_helper_memory_to_s(cpu_fr[t0 + i * 32], tmp32); ++ tcg_gen_addi_i64(t1, t1, 4); ++ } ++ ++ tcg_temp_free_i32(tmp32); ++} ++ ++static void gen_qemu_ldse(int t0, TCGv t1, int memidx) ++{ ++ TCGv_i32 tmp32 = tcg_temp_new_i32(); ++ TCGv tmp64 = tcg_temp_new(); ++ ++ tcg_gen_qemu_ld_i32(tmp32, t1, memidx, MO_ALIGN_4 | MO_LEUL); ++ gen_helper_memory_to_s(cpu_fr[t0], tmp32); ++ tcg_gen_mov_i64(cpu_fr[t0 + 32], cpu_fr[t0]); ++ tcg_gen_mov_i64(cpu_fr[t0 + 64], cpu_fr[t0]); ++ tcg_gen_mov_i64(cpu_fr[t0 + 96], cpu_fr[t0]); ++ ++ tcg_temp_free(tmp64); ++ tcg_temp_free_i32(tmp32); ++} ++ ++static void gen_qemu_ldde(int t0, TCGv t1, int memidx) ++{ ++ tcg_gen_qemu_ld_i64(cpu_fr[t0], t1, memidx, MO_ALIGN_4 | MO_TEQ); ++ tcg_gen_mov_i64(cpu_fr[t0 + 32], cpu_fr[t0]); ++ tcg_gen_mov_i64(cpu_fr[t0 + 64], cpu_fr[t0]); ++ tcg_gen_mov_i64(cpu_fr[t0 + 96], cpu_fr[t0]); ++} ++ ++static void gen_qemu_vldd(int t0, TCGv t1, int memidx) ++{ ++ tcg_gen_qemu_ld_i64(cpu_fr[t0], t1, memidx, MO_ALIGN_4 | MO_TEQ); ++ tcg_gen_addi_i64(t1, t1, 8); ++ tcg_gen_qemu_ld_i64(cpu_fr[t0 + 32], t1, memidx, MO_TEQ); ++ tcg_gen_addi_i64(t1, t1, 8); ++ tcg_gen_qemu_ld_i64(cpu_fr[t0 + 64], t1, memidx, MO_TEQ); ++ tcg_gen_addi_i64(t1, t1, 8); ++ tcg_gen_qemu_ld_i64(cpu_fr[t0 + 96], t1, memidx, MO_TEQ); ++} ++ ++static void gen_qemu_vsts(int t0, TCGv t1, int memidx) ++{ ++ int i; ++ TCGv_i32 tmp = tcg_temp_new_i32(); ++ ++ gen_helper_s_to_memory(tmp, cpu_fr[t0]); ++ tcg_gen_qemu_st_i32(tmp, t1, memidx, MO_ALIGN_4 | MO_LEUL); ++ tcg_gen_addi_i64(t1, t1, 4); ++ for (i = 1; i < 4; i++) { ++ gen_helper_s_to_memory(tmp, cpu_fr[t0 + 32 * i]); ++ tcg_gen_qemu_st_i32(tmp, t1, memidx, MO_LEUL); ++ tcg_gen_addi_i64(t1, t1, 4); ++ } ++ tcg_temp_free_i32(tmp); ++} ++ ++static void gen_qemu_vstd(int t0, TCGv t1, int memidx) ++{ ++ tcg_gen_qemu_st_i64(cpu_fr[t0], t1, memidx, MO_ALIGN_4 | MO_TEQ); ++ tcg_gen_addi_i64(t1, t1, 8); ++ tcg_gen_qemu_st_i64(cpu_fr[t0 + 32], t1, memidx, MO_TEQ); ++ tcg_gen_addi_i64(t1, t1, 8); ++ tcg_gen_qemu_st_i64(cpu_fr[t0 + 64], t1, memidx, MO_TEQ); ++ tcg_gen_addi_i64(t1, t1, 8); ++ tcg_gen_qemu_st_i64(cpu_fr[t0 + 96], t1, memidx, MO_TEQ); ++} ++ ++static inline void gen_qemu_fsts(TCGv t0, TCGv t1, int flags) ++{ ++ TCGv_i32 tmp = tcg_temp_new_i32(); ++ gen_helper_s_to_memory(tmp, t0); ++ tcg_gen_qemu_st_i32(tmp, t1, flags, MO_LEUL); ++ tcg_temp_free_i32(tmp); ++} ++ ++static inline void gen_qemu_flds(TCGv t0, TCGv t1, int flags) ++{ ++ TCGv_i32 tmp = tcg_temp_new_i32(); ++ tcg_gen_qemu_ld_i32(tmp, t1, flags, MO_LEUL); ++ gen_helper_memory_to_s(t0, tmp); ++ tcg_temp_free_i32(tmp); ++} ++ ++static TCGv gen_ieee_input(DisasContext *ctx, int reg, int is_cmp) ++{ ++ TCGv val; ++ ++ if (unlikely(reg == 31)) { ++ val = load_zero(ctx); ++ } else { ++ val = cpu_fr[reg]; ++#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(cpu_env, val); ++#endif ++ } ++ return val; ++} ++ ++static void gen_fp_exc_raise(int rc) ++{ ++#ifndef CONFIG_USER_ONLY ++ TCGv_i32 reg = tcg_const_i32(rc + 32); ++ gen_helper_fp_exc_raise(cpu_env, reg); ++ tcg_temp_free_i32(reg); ++#endif ++} ++ ++static void gen_ieee_arith2(DisasContext *ctx, ++ void (*helper)(TCGv, TCGv_ptr, TCGv), int ra, ++ int rc) ++{ ++ TCGv va, vc; ++ ++ va = gen_ieee_input(ctx, ra, 0); ++ vc = cpu_fr[rc]; ++ helper(vc, cpu_env, va); ++ ++ gen_fp_exc_raise(rc); ++} ++ ++static void gen_ieee_arith3(DisasContext *ctx, ++ void (*helper)(TCGv, TCGv_ptr, TCGv, TCGv), int ra, ++ int rb, int rc) ++{ ++ TCGv va, vb, vc; ++ ++ va = gen_ieee_input(ctx, ra, 0); ++ vb = gen_ieee_input(ctx, rb, 0); ++ vc = cpu_fr[rc]; ++ helper(vc, cpu_env, va, vb); ++ ++ gen_fp_exc_raise(rc); ++} ++ ++#define IEEE_ARITH2(name) \ ++ static inline void glue(gen_, name)(DisasContext * ctx, int ra, int rc) { \ ++ gen_ieee_arith2(ctx, gen_helper_##name, ra, rc); \ ++ } ++ ++#define IEEE_ARITH3(name) \ ++ static inline void glue(gen_, name)(DisasContext * ctx, int ra, int rb, \ ++ int rc) { \ ++ gen_ieee_arith3(ctx, gen_helper_##name, ra, rb, rc); \ ++ } ++IEEE_ARITH3(fadds) ++IEEE_ARITH3(faddd) ++IEEE_ARITH3(fsubs) ++IEEE_ARITH3(fsubd) ++IEEE_ARITH3(fmuls) ++IEEE_ARITH3(fmuld) ++IEEE_ARITH3(fdivs) ++IEEE_ARITH3(fdivd) ++IEEE_ARITH2(frecs) ++IEEE_ARITH2(frecd) ++ ++static void gen_ieee_compare(DisasContext *ctx, ++ void (*helper)(TCGv, TCGv_ptr, TCGv, TCGv), int ra, ++ int rb, int rc) ++{ ++ TCGv va, vb, vc; ++ ++ va = gen_ieee_input(ctx, ra, 1); ++ vb = gen_ieee_input(ctx, rb, 1); ++ vc = cpu_fr[rc]; ++ helper(vc, cpu_env, va, vb); ++ ++ gen_fp_exc_raise(rc); ++} ++ ++#define IEEE_CMP2(name) \ ++ static inline void glue(gen_, name)(DisasContext *ctx, int ra, int rb, \ ++ int rc) { \ ++ gen_ieee_compare(ctx, gen_helper_##name, ra, rb, rc); \ ++ } ++ ++IEEE_CMP2(fcmpun) ++IEEE_CMP2(fcmpeq) ++IEEE_CMP2(fcmplt) ++IEEE_CMP2(fcmple) ++ ++static void gen_fcvtdl(int rb, int rc, uint64_t round_mode) ++{ ++ TCGv tmp64; ++ tmp64 = tcg_temp_new_i64(); ++ tcg_gen_movi_i64(tmp64, round_mode); ++ gen_helper_fcvtdl(cpu_fr[rc], cpu_env, cpu_fr[rb], tmp64); ++ tcg_temp_free(tmp64); ++ gen_fp_exc_raise(rc); ++} ++ ++static void cal_with_fregs_2(DisasContext *ctx, uint8_t rc, uint8_t ra, ++ uint8_t rb, uint8_t fn) ++{ ++ TCGv tmp64; ++ TCGv_i32 tmp32; ++ switch (fn) { ++ case 0x00: ++ /* FADDS */ ++ gen_fadds(ctx, ra, rb, rc); ++ break; ++ case 0x01: ++ /* FADDD */ ++ gen_faddd(ctx, ra, rb, rc); ++ break; ++ case 0x02: ++ /* FSUBS */ ++ gen_fsubs(ctx, ra, rb, rc); ++ break; ++ case 0x03: ++ /* FSUBD */ ++ gen_fsubd(ctx, ra, rb, rc); ++ break; ++ case 0x4: ++ /* FMULS */ ++ gen_fmuls(ctx, ra, rb, rc); ++ break; ++ case 0x05: ++ /* FMULD */ ++ gen_fmuld(ctx, ra, rb, rc); ++ break; ++ case 0x06: ++ /* FDIVS */ ++ gen_fdivs(ctx, ra, rb, rc); ++ break; ++ case 0x07: ++ /* FDIVD */ ++ gen_fdivd(ctx, ra, rb, rc); ++ break; ++ case 0x08: ++ /* FSQRTS */ ++ gen_helper_fsqrts(cpu_fr[rc], cpu_env, cpu_fr[rb]); ++ break; ++ case 0x09: ++ /* FSQRTD */ ++ gen_helper_fsqrt(cpu_fr[rc], cpu_env, cpu_fr[rb]); ++ break; ++ case 0x10: ++ /* FCMPEQ */ ++ gen_fcmpeq(ctx, ra, rb, rc); ++ break; ++ case 0x11: ++ /* FCMPLE */ ++ gen_fcmple(ctx, ra, rb, rc); ++ break; ++ case 0x12: ++ /* FCMPLT */ ++ gen_fcmplt(ctx, ra, rb, rc); ++ break; ++ case 0x13: ++ /* FCMPUN */ ++ gen_fcmpun(ctx, ra, rb, rc); ++ break; ++ case 0x20: ++ /* FCVTSD */ ++ gen_helper_fcvtsd(cpu_fr[rc], cpu_env, cpu_fr[rb]); ++ break; ++ case 0x21: ++ /* FCVTDS */ ++ gen_helper_fcvtds(cpu_fr[rc], cpu_env, cpu_fr[rb]); ++ break; ++ case 0x22: ++ /* FCVTDL_G */ ++ gen_fcvtdl(rb, rc, 0); ++ break; ++ case 0x23: ++ /* FCVTDL_P */ ++ gen_fcvtdl(rb, rc, 2); ++ break; ++ case 0x24: ++ /* FCVTDL_Z */ ++ gen_fcvtdl(rb, rc, 3); ++ break; ++ case 0x25: ++ /* FCVTDL_N */ ++ gen_fcvtdl(rb, rc, 1); ++ break; ++ case 0x27: ++ /* FCVTDL */ ++ gen_helper_fcvtdl_dyn(cpu_fr[rc], cpu_env, cpu_fr[rb]); ++ break; ++ case 0x28: ++ /* FCVTWL */ ++ gen_helper_fcvtwl(cpu_fr[rc], cpu_env, cpu_fr[rb]); ++ tcg_gen_ext32s_i64(cpu_fr[rc], cpu_fr[rc]); ++ break; ++ case 0x29: ++ /* FCVTLW */ ++ gen_helper_fcvtlw(cpu_fr[rc], cpu_env, cpu_fr[rb]); ++ break; ++ case 0x2d: ++ /* FCVTLS */ ++ gen_helper_fcvtls(cpu_fr[rc], cpu_env, cpu_fr[rb]); ++ break; ++ case 0x2f: ++ /* FCVTLD */ ++ gen_helper_fcvtld(cpu_fr[rc], cpu_env, cpu_fr[rb]); ++ break; ++ case 0x30: ++ /* FCPYS */ ++ tmp64 = tcg_temp_new(); ++ tcg_gen_shri_i64(tmp64, cpu_fr[ra], 63); ++ tcg_gen_shli_i64(tmp64, tmp64, 63); ++ tcg_gen_andi_i64(cpu_fr[rc], cpu_fr[rb], 0x7fffffffffffffffUL); ++ tcg_gen_or_i64(cpu_fr[rc], tmp64, cpu_fr[rc]); ++ tcg_temp_free(tmp64); ++ break; ++ case 0x31: ++ /* FCPYSE */ ++ tmp64 = tcg_temp_new(); ++ tcg_gen_shri_i64(tmp64, cpu_fr[ra], 52); ++ tcg_gen_shli_i64(tmp64, tmp64, 52); ++ tcg_gen_andi_i64(cpu_fr[rc], cpu_fr[rb], 0x000fffffffffffffUL); ++ tcg_gen_or_i64(cpu_fr[rc], tmp64, cpu_fr[rc]); ++ tcg_temp_free(tmp64); ++ break; ++ case 0x32: ++ /* FCPYSN */ ++ tmp64 = tcg_temp_new(); ++ tcg_gen_shri_i64(tmp64, cpu_fr[ra], 63); ++ tcg_gen_not_i64(tmp64, tmp64); ++ tcg_gen_shli_i64(tmp64, tmp64, 63); ++ tcg_gen_andi_i64(cpu_fr[rc], cpu_fr[rb], 0x7fffffffffffffffUL); ++ tcg_gen_or_i64(cpu_fr[rc], tmp64, cpu_fr[rc]); ++ tcg_temp_free(tmp64); ++ break; ++ case 0x40: ++ /* IFMOVS */ ++ tmp64 = tcg_temp_new(); ++ tmp32 = tcg_temp_new_i32(); ++ tcg_gen_movi_i64(tmp64, ra); ++ tcg_gen_extrl_i64_i32(tmp32, load_gir(ctx, ra)); ++ gen_helper_memory_to_s(tmp64, tmp32); ++ tcg_gen_mov_i64(cpu_fr[rc], tmp64); ++ tcg_gen_movi_i64(tmp64, rc); ++ tcg_temp_free(tmp64); ++ tcg_temp_free_i32(tmp32); ++ break; ++ case 0x41: ++ /* IFMOVD */ ++ tcg_gen_mov_i64(cpu_fr[rc], load_gir(ctx, ra)); ++ break; ++ case 0x50: ++ /* RFPCR */ ++ gen_helper_load_fpcr(cpu_fr[ra], cpu_env); ++ break; ++ case 0x51: ++ /* WFPCR */ ++ gen_helper_store_fpcr(cpu_env, cpu_fr[ra]); ++ break; ++ case 0x54: ++ /* SETFPEC0 */ ++ tmp64 = tcg_const_i64(0); ++ gen_helper_setfpcrx(cpu_env, tmp64); ++ tcg_temp_free(tmp64); ++ break; ++ case 0x55: ++ /* SETFPEC1 */ ++ tmp64 = tcg_const_i64(1); ++ gen_helper_setfpcrx(cpu_env, tmp64); ++ tcg_temp_free(tmp64); ++ break; ++ case 0x56: ++ /* SETFPEC2 */ ++ tmp64 = tcg_const_i64(2); ++ gen_helper_setfpcrx(cpu_env, tmp64); ++ tcg_temp_free(tmp64); ++ break; ++ case 0x57: ++ /* SETFPEC3 */ ++ tmp64 = tcg_const_i64(3); ++ gen_helper_setfpcrx(cpu_env, tmp64); ++ tcg_temp_free(tmp64); ++ break; ++ default: ++ fprintf(stderr, "Illegal insn func[%x]\n", fn); ++ gen_invalid(ctx); ++ break; ++ } ++} ++ ++static void cal_with_fregs_4(DisasContext *ctx, uint8_t rd, uint8_t ra, ++ uint8_t rb, uint8_t rc, uint8_t fn) ++{ ++ TCGv zero = tcg_const_i64(0); ++ TCGv va, vb, vc, vd, tmp64; ++ ++ va = cpu_fr[ra]; ++ vb = cpu_fr[rb]; ++ vc = cpu_fr[rc]; ++ vd = cpu_fr[rd]; ++ ++ switch (fn) { ++ case 0x00: ++ /* FMAS */ ++ gen_helper_fmas(vd, cpu_env, va, vb, vc); ++ break; ++ case 0x01: ++ /* FMAD */ ++ gen_helper_fmad(vd, cpu_env, va, vb, vc); ++ break; ++ case 0x02: ++ /* FMSS */ ++ gen_helper_fmss(vd, cpu_env, va, vb, vc); ++ break; ++ case 0x03: ++ /* FMSD */ ++ gen_helper_fmsd(vd, cpu_env, va, vb, vc); ++ break; ++ case 0x04: ++ /* FNMAS */ ++ gen_helper_fnmas(vd, cpu_env, va, vb, vc); ++ break; ++ case 0x05: ++ /* FNMAD */ ++ gen_helper_fnmad(vd, cpu_env, va, vb, vc); ++ break; ++ case 0x06: ++ /* FNMSS */ ++ gen_helper_fnmss(vd, cpu_env, va, vb, vc); ++ break; ++ case 0x07: ++ /* FNMSD */ ++ gen_helper_fnmsd(vd, cpu_env, va, vb, vc); ++ break; ++ case 0x10: ++ /* FSELEQ */ ++ // Maybe wrong translation. ++ tmp64 = tcg_temp_new(); ++ gen_helper_fcmpeq(tmp64, cpu_env, va, zero); ++ tcg_gen_movcond_i64(TCG_COND_EQ, vd, tmp64, zero, vc, vb); ++ tcg_temp_free(tmp64); ++ break; ++ case 0x11: ++ /* FSELNE */ ++ tmp64 = tcg_temp_new(); ++ gen_helper_fcmpeq(tmp64, cpu_env, va, zero); ++ tcg_gen_movcond_i64(TCG_COND_EQ, vd, tmp64, zero, vb, vc); ++ tcg_temp_free(tmp64); ++ break; ++ case 0x12: ++ /* FSELLT */ ++ tmp64 = tcg_temp_new(); ++ gen_helper_fcmplt(tmp64, cpu_env, va, zero); ++ tcg_gen_movcond_i64(TCG_COND_EQ, vd, tmp64, zero, vc, vb); ++ tcg_temp_free(tmp64); ++ break; ++ case 0x13: ++ /* FSELLE */ ++ tmp64 = tcg_temp_new(); ++ gen_helper_fcmple(tmp64, cpu_env, va, zero); ++ tcg_gen_movcond_i64(TCG_COND_EQ, vd, tmp64, zero, vc, vb); ++ tcg_temp_free(tmp64); ++ break; ++ case 0x14: ++ /* FSELGT */ ++ tmp64 = tcg_temp_new(); ++ gen_helper_fcmpgt(tmp64, cpu_env, va, zero); ++ tcg_gen_movcond_i64(TCG_COND_NE, vd, tmp64, zero, vb, vc); ++ tcg_temp_free(tmp64); ++ break; ++ case 0x15: ++ /* FSELGE */ ++ tmp64 = tcg_temp_new(); ++ gen_helper_fcmpge(tmp64, cpu_env, va, zero); ++ tcg_gen_movcond_i64(TCG_COND_NE, vd, tmp64, zero, vb, vc); ++ tcg_temp_free(tmp64); ++ break; ++ default: ++ fprintf(stderr, "Illegal insn func[%x]\n", fn); ++ gen_invalid(ctx); ++ break; ++ } ++ tcg_temp_free(zero); ++} ++static inline void gen_qemu_lldw(TCGv t0, TCGv t1, int flags) ++{ ++ tcg_gen_qemu_ld_i64(t0, t1, flags, MO_LESL); ++ tcg_gen_mov_i64(cpu_lock_addr, t1); ++#ifdef SW64_FIXLOCK ++ tcg_gen_ext32u_i64(cpu_lock_value, t0); ++#endif ++} ++ ++static inline void gen_qemu_lldl(TCGv t0, TCGv t1, int flags) ++{ ++ tcg_gen_qemu_ld_i64(t0, t1, flags, MO_LEQ); ++ tcg_gen_mov_i64(cpu_lock_addr, t1); ++#ifdef SW64_FIXLOCK ++ tcg_gen_mov_i64(cpu_lock_value, t0); ++#endif ++} ++ ++static DisasJumpType gen_store_conditional(DisasContext *ctx, int ra, int rb, ++ int32_t disp16, int mem_idx, ++ MemOp op) ++{ ++ TCGLabel *lab_fail, *lab_done; ++ TCGv addr; ++ ++ addr = tcg_temp_new_i64(); ++ tcg_gen_addi_i64(addr, load_gir(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); ++ tcg_gen_brcondi_i64(TCG_COND_NE, cpu_lock_flag, 0x1, lab_fail); ++#ifdef SW64_FIXLOCK ++ TCGv val = tcg_temp_new_i64(); ++ tcg_gen_atomic_cmpxchg_i64(val, cpu_lock_addr, cpu_lock_value, ++ load_gir(ctx, ra), mem_idx, op); ++ tcg_gen_setcond_i64(TCG_COND_EQ, cpu_lock_success, val, cpu_lock_value); ++ tcg_temp_free_i64(val); ++#else ++ tcg_gen_qemu_st_i64(load_gir(ctx, ra), addr, mem_idx, op); ++#endif ++ ++ tcg_gen_br(lab_done); ++ ++ gen_set_label(lab_fail); ++ tcg_gen_movi_i64(cpu_lock_success, 0); ++ gen_set_label(lab_done); ++ ++ tcg_gen_movi_i64(cpu_lock_flag, 0); ++ tcg_gen_movi_i64(cpu_lock_addr, -1); ++ return DISAS_NEXT; ++} ++ ++static DisasJumpType gen_sys_call(DisasContext *ctx, int syscode) ++{ ++ if (syscode >= 0x80 && syscode <= 0xbf) { ++ switch (syscode) { ++ case 0x86: ++ /* IMB */ ++ /* No-op inside QEMU */ ++ break; ++#ifdef CONFIG_USER_ONLY ++ case 0x9E: ++ /* RDUNIQUE */ ++ tcg_gen_ld_i64(ctx->ir[IDX_V0], cpu_env, ++ offsetof(CPUSW64State, unique)); ++ break; ++ case 0x9F: ++ /* WRUNIQUE */ ++ tcg_gen_st_i64(ctx->ir[IDX_A0], cpu_env, ++ offsetof(CPUSW64State, unique)); ++ break; ++#endif ++ default: ++ goto do_sys_call; ++ } ++ return DISAS_NEXT; ++ } ++do_sys_call: ++#ifdef CONFIG_USER_ONLY ++ return gen_excp(ctx, EXCP_CALL_SYS, syscode); ++#else ++ tcg_gen_movi_i64(cpu_hm_ir[23], ctx->base.pc_next); ++ return gen_excp(ctx, EXCP_CALL_SYS, syscode); ++#endif ++} ++ ++static void read_csr(int idx, TCGv va) ++{ ++ TCGv_i64 tmp = tcg_const_i64(idx); ++ gen_helper_read_csr(va, cpu_env, tmp); ++ tcg_temp_free_i64(tmp); ++} ++ ++static void write_csr(int idx, TCGv va, CPUSW64State *env) ++{ ++ TCGv_i64 tmp = tcg_const_i64(idx); ++ gen_helper_write_csr(cpu_env, tmp, va); ++ tcg_temp_free_i64(tmp); ++} ++ ++static inline void ldx_set(DisasContext *ctx, int ra, int rb, int32_t disp12, ++ bool bype) ++{ ++ TCGv tmp, addr, va, t1; ++ ++ /* 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(); ++ t1 = tcg_const_i64(1); ++ addr = load_gir(ctx, rb); ++ ++ tcg_gen_addi_i64(tmp, addr, disp12); ++ addr = tmp; ++ ++ va = load_gir(ctx, ra); ++ if (bype == 0) { ++ tcg_gen_atomic_xchg_i64(va, addr, t1, ctx->mem_idx, MO_TESL); ++ } else { ++ tcg_gen_atomic_xchg_i64(va, addr, t1, ctx->mem_idx, MO_TEQ); ++ } ++ ++ tcg_temp_free(tmp); ++ tcg_temp_free(t1); ++} ++ ++static inline void ldx_xxx(DisasContext *ctx, int ra, int rb, int32_t disp12, ++ bool bype, int64_t val) ++{ ++ TCGv tmp, addr, va, t; ++ ++ /* 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(); ++ t = tcg_const_i64(val); ++ addr = load_gir(ctx, rb); ++ ++ tcg_gen_addi_i64(tmp, addr, disp12); ++ addr = tmp; ++ ++ va = load_gir(ctx, ra); ++ if (bype == 0) { ++ tcg_gen_atomic_fetch_add_i64(va, addr, t, ctx->mem_idx, MO_TESL); ++ } else { ++ tcg_gen_atomic_fetch_add_i64(va, addr, t, ctx->mem_idx, MO_TEQ); ++ } ++ ++ tcg_temp_free(tmp); ++ tcg_temp_free(t); ++} ++ ++static void tcg_gen_srlow_i64(int ra, int rc, int rb) ++{ ++ TCGv va, vb, vc; ++ TCGv shift; ++ ++ va = tcg_const_i64(ra); ++ vc = tcg_const_i64(rc); ++ shift = tcg_temp_new(); ++ vb = cpu_fr[rb]; ++ tcg_gen_shri_i64(shift, vb, 29); ++ tcg_gen_andi_i64(shift, shift, 0xff); ++ ++ gen_helper_srlow(cpu_env, va, vc, shift); ++ ++ tcg_temp_free(vc); ++ tcg_temp_free(va); ++ tcg_temp_free(shift); ++} ++ ++static void tcg_gen_srlowi_i64(int ra, int rc, int disp8) ++{ ++ TCGv va, vc; ++ TCGv shift; ++ ++ va = tcg_const_i64(ra); ++ vc = tcg_const_i64(rc); ++ shift = tcg_temp_new(); ++ tcg_gen_movi_i64(shift, disp8); ++ tcg_gen_andi_i64(shift, shift, 0xff); ++ ++ gen_helper_srlow(cpu_env, va, vc, shift); ++ ++ tcg_temp_free(vc); ++ tcg_temp_free(va); ++ tcg_temp_free(shift); ++} ++ ++static void tcg_gen_sllow_i64(int ra, int rc, int rb) ++{ ++ TCGv va, vb, vc; ++ TCGv shift; ++ ++ va = tcg_const_i64(ra); ++ vc = tcg_const_i64(rc); ++ shift = tcg_temp_new(); ++ vb = cpu_fr[rb]; ++ tcg_gen_shri_i64(shift, vb, 29); ++ tcg_gen_andi_i64(shift, shift, 0xff); ++ ++ gen_helper_sllow(cpu_env, va, vc, shift); ++ ++ tcg_temp_free(vc); ++ tcg_temp_free(va); ++ tcg_temp_free(shift); ++} ++ ++static void tcg_gen_sllowi_i64(int ra, int rc, int disp8) ++{ ++ TCGv va, vc; ++ TCGv shift; ++ ++ va = tcg_const_i64(ra); ++ vc = tcg_const_i64(rc); ++ shift = tcg_temp_new(); ++ tcg_gen_movi_i64(shift, disp8); ++ tcg_gen_andi_i64(shift, shift, 0xff); ++ ++ gen_helper_sllow(cpu_env, va, vc, shift); ++ ++ tcg_temp_free(vc); ++ tcg_temp_free(va); ++ tcg_temp_free(shift); ++} ++ ++static void gen_qemu_vstw_uh(int t0, TCGv t1, int memidx) ++{ ++ TCGv byte4_len; ++ TCGv addr_start, addr_end; ++ TCGv tmp[8]; ++ TCGv ti; ++ int i; ++ ++ tmp[0] = tcg_temp_new(); ++ tmp[1] = tcg_temp_new(); ++ tmp[2] = tcg_temp_new(); ++ tmp[3] = tcg_temp_new(); ++ tmp[4] = tcg_temp_new(); ++ tmp[5] = tcg_temp_new(); ++ tmp[6] = tcg_temp_new(); ++ tmp[7] = tcg_temp_new(); ++ ti = tcg_temp_new(); ++ addr_start = tcg_temp_new(); ++ addr_end = tcg_temp_new(); ++ byte4_len = tcg_temp_new(); ++ ++ tcg_gen_shri_i64(byte4_len, t1, 2); ++ tcg_gen_andi_i64(byte4_len, byte4_len, 0x7UL); ++ tcg_gen_andi_i64(t1, t1, ~0x3UL); /* t1 = addr + byte4_len * 4 */ ++ tcg_gen_andi_i64(addr_start, t1, ~0x1fUL); ++ tcg_gen_mov_i64(addr_end, t1); ++ for (i = 7; i >= 0; i--) { ++ tcg_gen_movcond_i64(TCG_COND_GEU, t1, t1, addr_start, t1, addr_start); ++ tcg_gen_qemu_ld_i64(tmp[i], t1, memidx, MO_TEUL); ++ tcg_gen_subi_i64(t1, t1, 4); ++ tcg_gen_movi_i64(ti, i); ++ if (i % 2) ++ tcg_gen_shli_i64(tmp[i], tmp[i], 32); ++ } ++ tcg_gen_subfi_i64(byte4_len, 8, byte4_len); ++ ++ for (i = 0; i < 8; i++) { ++ tcg_gen_movi_i64(ti, i); ++ tcg_gen_movcond_i64(TCG_COND_GEU, tmp[i], ti, byte4_len, cpu_fr[t0 + (i / 2)*32], tmp[i]); ++ if (i % 2) ++ tcg_gen_shri_i64(tmp[i], tmp[i], 32); ++ else ++ tcg_gen_andi_i64(tmp[i], tmp[i], 0xffffffffUL); ++ } ++ ++ tcg_gen_subi_i64(addr_end, addr_end, 32); ++ for (i = 0; i < 8; i++) { ++ tcg_gen_movcond_i64(TCG_COND_GEU, t1, addr_end, addr_start, addr_end, addr_start); ++ tcg_gen_qemu_st_i64(tmp[i], t1, memidx, MO_TEUL); ++ tcg_gen_addi_i64(addr_end, addr_end, 4); ++ } ++ ++ tcg_temp_free(ti); ++ tcg_temp_free(addr_start); ++ tcg_temp_free(addr_end); ++ tcg_temp_free(byte4_len); ++ tcg_temp_free(tmp[0]); ++ tcg_temp_free(tmp[1]); ++ tcg_temp_free(tmp[2]); ++ tcg_temp_free(tmp[3]); ++ tcg_temp_free(tmp[4]); ++ tcg_temp_free(tmp[5]); ++ tcg_temp_free(tmp[6]); ++ tcg_temp_free(tmp[7]); ++} ++ ++static void gen_qemu_vstw_ul(int t0, TCGv t1, int memidx) ++{ ++ TCGv byte4_len; ++ TCGv addr_start, addr_end; ++ TCGv tmp[8]; ++ TCGv ti; ++ int i; ++ ++ tmp[0] = tcg_temp_new(); ++ tmp[1] = tcg_temp_new(); ++ tmp[2] = tcg_temp_new(); ++ tmp[3] = tcg_temp_new(); ++ tmp[4] = tcg_temp_new(); ++ tmp[5] = tcg_temp_new(); ++ tmp[6] = tcg_temp_new(); ++ tmp[7] = tcg_temp_new(); ++ ti = tcg_temp_new(); ++ addr_start = tcg_temp_new(); ++ addr_end = tcg_temp_new(); ++ byte4_len = tcg_temp_new(); ++ ++ tcg_gen_shri_i64(byte4_len, t1, 2); ++ tcg_gen_andi_i64(byte4_len, byte4_len, 0x7UL); ++ tcg_gen_andi_i64(t1, t1, ~0x3UL); /* t1 = addr + byte4_len * 4 */ ++ tcg_gen_mov_i64(addr_start, t1); /* t1 = addr + byte4_len * 4 */ ++ tcg_gen_addi_i64(addr_end, addr_start, 24); ++ for (i = 0; i < 8; i++) { ++ tcg_gen_movcond_i64(TCG_COND_LEU, t1, t1, addr_end, t1, addr_end); ++ tcg_gen_qemu_ld_i64(tmp[i], t1, memidx, MO_TEUL); ++ tcg_gen_addi_i64(t1, t1, 4); ++ if (i % 2) ++ tcg_gen_shli_i64(tmp[i], tmp[i], 32); ++ } ++ tcg_gen_subfi_i64(byte4_len, 8, byte4_len); ++ ++ for (i = 0; i < 8; i++) { ++ tcg_gen_movi_i64(ti, i); ++ tcg_gen_movcond_i64(TCG_COND_LTU, tmp[i], ti, byte4_len, cpu_fr[t0 + (i/2)*32], tmp[i]); ++ if (i % 2) ++ tcg_gen_shri_i64(tmp[i], tmp[i], 32); ++ else ++ tcg_gen_andi_i64(tmp[i], tmp[i], 0xffffffffUL); ++ } ++ ++ tcg_gen_addi_i64(addr_start, addr_start, 32); ++ for (i = 7; i >= 0; i--) { ++ tcg_gen_subi_i64(addr_start, addr_start, 4); ++ tcg_gen_movcond_i64(TCG_COND_LEU, t1, addr_start, addr_end, addr_start, addr_end); ++ tcg_gen_qemu_st_i64(tmp[i], t1, memidx, MO_TEUL); ++ } ++ ++ tcg_temp_free(ti); ++ tcg_temp_free(addr_start); ++ tcg_temp_free(addr_end); ++ tcg_temp_free(byte4_len); ++ tcg_temp_free(tmp[0]); ++ tcg_temp_free(tmp[1]); ++ tcg_temp_free(tmp[2]); ++ tcg_temp_free(tmp[3]); ++ tcg_temp_free(tmp[4]); ++ tcg_temp_free(tmp[5]); ++ tcg_temp_free(tmp[6]); ++ tcg_temp_free(tmp[7]); ++} ++ ++static void gen_qemu_vsts_uh(int t0, TCGv t1, int memidx) ++{ ++ TCGv byte4_len; ++ TCGv addr_start, addr_end; ++ TCGv tmp[4]; ++ TCGv ftmp; ++ TCGv ti; ++ int i; ++ ++ tmp[0] = tcg_temp_new(); ++ tmp[1] = tcg_temp_new(); ++ tmp[2] = tcg_temp_new(); ++ tmp[3] = tcg_temp_new(); ++ ti = tcg_temp_new(); ++ ftmp = tcg_temp_new(); ++ addr_start = tcg_temp_new(); ++ addr_end = tcg_temp_new(); ++ byte4_len = tcg_temp_new(); ++ ++ tcg_gen_shri_i64(byte4_len, t1, 2); ++ tcg_gen_andi_i64(byte4_len, byte4_len, 0x3UL); ++ tcg_gen_andi_i64(t1, t1, ~0x3UL); /* t1 = addr + byte4_len * 4 */ ++ tcg_gen_andi_i64(addr_start, t1, ~0xfUL); ++ tcg_gen_mov_i64(addr_end, t1); ++ for (i = 3; i >= 0; i--) { ++ tcg_gen_movcond_i64(TCG_COND_GEU, t1, t1, addr_start, t1, addr_start); ++ tcg_gen_qemu_ld_i64(tmp[i], t1, memidx, MO_TEUL); ++ tcg_gen_subi_i64(t1, t1, 4); ++ } ++ tcg_gen_subfi_i64(byte4_len, 4, byte4_len); ++ ++ for (i = 0; i < 4; i++) { ++ tcg_gen_shri_i64(ti, cpu_fr[t0 + i * 32], 62); ++ tcg_gen_shli_i64(ti, ti, 30); ++ tcg_gen_shri_i64(ftmp, cpu_fr[t0 + i * 32], 29); ++ tcg_gen_andi_i64(ftmp, ftmp, 0x3fffffffUL); ++ tcg_gen_or_i64(ftmp, ftmp, ti); ++ tcg_gen_movi_i64(ti, i); ++ tcg_gen_movcond_i64(TCG_COND_GEU, tmp[i], ti, byte4_len, ftmp, tmp[i]); ++ } ++ ++ tcg_gen_subi_i64(addr_end, addr_end, 16); ++ for (i = 0; i < 4; i++) { ++ tcg_gen_movcond_i64(TCG_COND_GEU, t1, addr_end, addr_start, addr_end, addr_start); ++ tcg_gen_qemu_st_i64(tmp[i], t1, memidx, MO_TEUL); ++ tcg_gen_addi_i64(addr_end, addr_end, 4); ++ } ++ ++ tcg_temp_free(ti); ++ tcg_temp_free(ftmp); ++ tcg_temp_free(addr_start); ++ tcg_temp_free(addr_end); ++ tcg_temp_free(byte4_len); ++ tcg_temp_free(tmp[0]); ++ tcg_temp_free(tmp[1]); ++ tcg_temp_free(tmp[2]); ++ tcg_temp_free(tmp[3]); ++} ++ ++static void gen_qemu_vsts_ul(int t0, TCGv t1, int memidx) ++{ ++ TCGv byte4_len; ++ TCGv addr_start, addr_end; ++ TCGv tmp[4]; ++ TCGv ftmp; ++ TCGv ti; ++ int i; ++ ++ tmp[0] = tcg_temp_new(); ++ tmp[1] = tcg_temp_new(); ++ tmp[2] = tcg_temp_new(); ++ tmp[3] = tcg_temp_new(); ++ ftmp = tcg_temp_new(); ++ ti = tcg_temp_new(); ++ addr_start = tcg_temp_new(); ++ addr_end = tcg_temp_new(); ++ byte4_len = tcg_temp_new(); ++ ++ tcg_gen_shri_i64(byte4_len, t1, 2); ++ tcg_gen_andi_i64(byte4_len, byte4_len, 0x3UL); ++ tcg_gen_andi_i64(t1, t1, ~0x3UL); /* t1 = addr + byte4_len * 4 */ ++ tcg_gen_mov_i64(addr_start, t1); /* t1 = addr + byte4_len * 4 */ ++ tcg_gen_addi_i64(addr_end, addr_start, 12); ++ for (i = 0; i < 4; i++) { ++ tcg_gen_movcond_i64(TCG_COND_LEU, t1, t1, addr_end, t1, addr_end); ++ tcg_gen_qemu_ld_i64(tmp[i], t1, memidx, MO_TEUL); ++ tcg_gen_addi_i64(t1, t1, 4); ++ } ++ tcg_gen_subfi_i64(byte4_len, 4, byte4_len); ++ ++ for (i = 0; i < 4; i++) { ++ tcg_gen_shri_i64(ti, cpu_fr[t0 + i * 32], 62); ++ tcg_gen_shli_i64(ti, ti, 30); ++ tcg_gen_shri_i64(ftmp, cpu_fr[t0 + i * 32], 29); ++ tcg_gen_andi_i64(ftmp, ftmp, 0x3fffffffUL); ++ tcg_gen_or_i64(ftmp, ftmp, ti); ++ tcg_gen_movi_i64(ti, i); ++ tcg_gen_movcond_i64(TCG_COND_LTU, tmp[i], ti, byte4_len, ftmp, tmp[i]); ++ } ++ ++ tcg_gen_addi_i64(addr_start, addr_start, 16); ++ for (i = 3; i >= 0; i--) { ++ tcg_gen_subi_i64(addr_start, addr_start, 4); ++ tcg_gen_movcond_i64(TCG_COND_LEU, t1, addr_start, addr_end, addr_start, addr_end); ++ tcg_gen_qemu_st_i64(tmp[i], t1, memidx, MO_TEUL); ++ } ++ ++ tcg_temp_free(ti); ++ tcg_temp_free(addr_start); ++ tcg_temp_free(addr_end); ++ tcg_temp_free(byte4_len); ++ tcg_temp_free(ftmp); ++ tcg_temp_free(tmp[0]); ++ tcg_temp_free(tmp[1]); ++ tcg_temp_free(tmp[2]); ++ tcg_temp_free(tmp[3]); ++} ++ ++static void gen_qemu_vstd_uh(int t0, TCGv t1, int memidx) ++{ ++ TCGv byte8_len; ++ TCGv addr_start, addr_end; ++ TCGv tmp[4]; ++ TCGv ti; ++ int i; ++ ++ tmp[0] = tcg_temp_new(); ++ tmp[1] = tcg_temp_new(); ++ tmp[2] = tcg_temp_new(); ++ tmp[3] = tcg_temp_new(); ++ ti = tcg_temp_new(); ++ addr_start = tcg_temp_new(); ++ addr_end = tcg_temp_new(); ++ byte8_len = tcg_temp_new(); ++ ++ tcg_gen_shri_i64(byte8_len, t1, 3); ++ tcg_gen_andi_i64(byte8_len, byte8_len, 0x3UL); ++ tcg_gen_andi_i64(t1, t1, ~0x7UL); /* t1 = addr + byte4_len * 4 */ ++ tcg_gen_andi_i64(addr_start, t1, ~0x1fUL); ++ tcg_gen_mov_i64(addr_end, t1); ++ for (i = 3; i >= 0; i--) { ++ tcg_gen_movcond_i64(TCG_COND_GEU, t1, t1, addr_start, t1, addr_start); ++ tcg_gen_qemu_ld_i64(tmp[i], t1, memidx, MO_TEQ); ++ tcg_gen_subi_i64(t1, t1, 8); ++ } ++ tcg_gen_subfi_i64(byte8_len, 4, byte8_len); ++ ++ for (i = 0; i < 4; i++) { ++ tcg_gen_movi_i64(ti, i); ++ tcg_gen_movcond_i64(TCG_COND_GEU, tmp[i], ti, byte8_len, cpu_fr[t0 + i*32], tmp[i]); ++ } ++ ++ tcg_gen_subi_i64(addr_end, addr_end, 32); ++ for (i = 0; i < 4; i++) { ++ tcg_gen_movcond_i64(TCG_COND_GEU, t1, addr_end, addr_start, addr_end, addr_start); ++ tcg_gen_qemu_st_i64(tmp[i], t1, memidx, MO_TEQ); ++ tcg_gen_addi_i64(addr_end, addr_end, 8); ++ } ++ ++ tcg_temp_free(ti); ++ tcg_temp_free(addr_start); ++ tcg_temp_free(addr_end); ++ tcg_temp_free(byte8_len); ++ tcg_temp_free(tmp[0]); ++ tcg_temp_free(tmp[1]); ++ tcg_temp_free(tmp[2]); ++ tcg_temp_free(tmp[3]); ++} ++ ++static void gen_qemu_vstd_ul(int t0, TCGv t1, int memidx) ++{ ++ TCGv byte8_len; ++ TCGv addr_start, addr_end; ++ TCGv tmp[4]; ++ TCGv ti; ++ int i; ++ ++ tmp[0] = tcg_temp_new(); ++ tmp[1] = tcg_temp_new(); ++ tmp[2] = tcg_temp_new(); ++ tmp[3] = tcg_temp_new(); ++ ti = tcg_temp_new(); ++ addr_start = tcg_temp_new(); ++ addr_end = tcg_temp_new(); ++ byte8_len = tcg_temp_new(); ++ ++ tcg_gen_shri_i64(byte8_len, t1, 3); ++ tcg_gen_andi_i64(byte8_len, byte8_len, 0x3UL); ++ tcg_gen_andi_i64(t1, t1, ~0x7UL); /* t1 = addr + byte4_len * 4 */ ++ tcg_gen_mov_i64(addr_start, t1); /* t1 = addr + byte4_len * 4 */ ++ tcg_gen_addi_i64(addr_end, addr_start, 24); ++ for (i = 0; i < 4; i++) { ++ tcg_gen_movcond_i64(TCG_COND_LEU, t1, t1, addr_end, t1, addr_end); ++ tcg_gen_qemu_ld_i64(tmp[i], t1, memidx, MO_TEQ); ++ tcg_gen_addi_i64(t1, t1, 8); ++ } ++ tcg_gen_subfi_i64(byte8_len, 4, byte8_len); ++ ++ for (i = 0; i < 4; i++) { ++ tcg_gen_movi_i64(ti, i); ++ tcg_gen_movcond_i64(TCG_COND_LTU, tmp[i], ti, byte8_len, cpu_fr[t0 + i*32], tmp[i]); ++ } ++ ++ tcg_gen_addi_i64(addr_start, addr_start, 32); ++ for (i = 3; i >= 0; i--) { ++ tcg_gen_subi_i64(addr_start, addr_start, 8); ++ tcg_gen_movcond_i64(TCG_COND_LEU, t1, addr_start, addr_end, addr_start, addr_end); ++ tcg_gen_qemu_st_i64(tmp[i], t1, memidx, MO_TEQ); ++ } ++ ++ tcg_temp_free(ti); ++ tcg_temp_free(addr_start); ++ tcg_temp_free(addr_end); ++ tcg_temp_free(byte8_len); ++ tcg_temp_free(tmp[0]); ++ tcg_temp_free(tmp[1]); ++ tcg_temp_free(tmp[2]); ++ tcg_temp_free(tmp[3]); ++} ++ ++static void tcg_gen_vcpys_i64(int ra, int rb, int rc) ++{ ++ int i; ++ TCGv tmp64 = tcg_temp_new(); ++ for (i = 0; i < 128; i += 32) { ++ tcg_gen_shri_i64(tmp64, cpu_fr[ra + i], 63); ++ tcg_gen_shli_i64(tmp64, tmp64, 63); ++ tcg_gen_andi_i64(cpu_fr[rc + i], cpu_fr[rb + i], 0x7fffffffffffffffUL); ++ tcg_gen_or_i64(cpu_fr[rc + i], tmp64, cpu_fr[rc + i]); ++ } ++ tcg_temp_free(tmp64); ++} ++ ++static void tcg_gen_vcpyse_i64(int ra, int rb, int rc) ++{ ++ int i; ++ ++ TCGv tmp64 = tcg_temp_new(); ++ ++ for (i = 0; i < 128; i += 32) { ++ tcg_gen_shri_i64(tmp64, cpu_fr[ra + i], 52); ++ tcg_gen_shli_i64(tmp64, tmp64, 52); ++ tcg_gen_andi_i64(cpu_fr[rc + i], cpu_fr[rb + i], 0x000fffffffffffffUL); ++ tcg_gen_or_i64(cpu_fr[rc + i], tmp64, cpu_fr[rc + i]); ++ } ++ tcg_temp_free(tmp64); ++} ++ ++static void tcg_gen_vcpysn_i64(int ra, int rb, int rc) ++{ ++ int i; ++ TCGv tmp64 = tcg_temp_new(); ++ for (i = 0; i < 128; i += 32) { ++ tcg_gen_shri_i64(tmp64, cpu_fr[ra + i], 63); ++ tcg_gen_not_i64(tmp64, tmp64); ++ tcg_gen_shli_i64(tmp64, tmp64, 63); ++ tcg_gen_andi_i64(cpu_fr[rc + i], cpu_fr[rb + i], 0x7fffffffffffffffUL); ++ tcg_gen_or_i64(cpu_fr[rc + i], tmp64, cpu_fr[rc + i]); ++ } ++ tcg_temp_free(tmp64); ++} ++ ++static void tcg_gen_vlogzz_i64(DisasContext *ctx, int opc, int ra, int rb, ++ int rc, int rd, int fn6) ++{ ++ TCGv zz; ++ TCGv args, vd; ++ zz = tcg_const_i64(((opc & 0x3) << 6) | fn6); ++ args = tcg_const_i64((ra << 16) | (rb << 8) | rc); ++ vd = tcg_const_i64(rd); ++ ++ gen_helper_vlogzz(cpu_env, args, vd, zz); ++ ++ tcg_temp_free(vd); ++ tcg_temp_free(args); ++ tcg_temp_free(zz); ++} ++ ++static void gen_qemu_vcmpxxw_i64(TCGCond cond, int ra, int rb, int rc) ++{ ++ TCGv va, vb, vc, tmp64; ++ int i; ++ ++ va = tcg_temp_new(); ++ vb = tcg_temp_new(); ++ vc = tcg_temp_new(); ++ tmp64 = tcg_temp_new(); ++ ++ for (i = 0; i < 128; i += 32) { ++ if ((cond >> 1) & 1) { ++ tcg_gen_ext32s_i64(va, cpu_fr[ra + i]); ++ tcg_gen_ext32s_i64(vb, cpu_fr[rb + i]); ++ } else { ++ tcg_gen_ext32u_i64(va, cpu_fr[ra + i]); ++ tcg_gen_ext32u_i64(vb, cpu_fr[rb + i]); ++ } ++ tcg_gen_setcond_i64(cond, vc, va, vb); ++ tcg_gen_mov_i64(tmp64, vc); ++ ++ tcg_gen_shri_i64(va, cpu_fr[ra + i], 32); ++ tcg_gen_shri_i64(vb, cpu_fr[rb + i], 32); ++ if ((cond >> 1) & 1) { ++ tcg_gen_ext32s_i64(va, va); ++ tcg_gen_ext32s_i64(vb, vb); ++ } else { ++ tcg_gen_ext32u_i64(va, va); ++ tcg_gen_ext32u_i64(vb, vb); ++ } ++ tcg_gen_setcond_i64(cond, vc, va, vb); ++ tcg_gen_shli_i64(vc, vc, 32); ++ tcg_gen_or_i64(cpu_fr[rc + i], tmp64, vc); ++ } ++ tcg_temp_free(va); ++ tcg_temp_free(vb); ++ tcg_temp_free(vc); ++ tcg_temp_free(tmp64); ++} ++ ++static void gen_qemu_vcmpxxwi_i64(TCGCond cond, int ra, int rb, int rc) ++{ ++ TCGv va, vb, vc, tmp64; ++ int i; ++ ++ va = tcg_temp_new(); ++ vb = tcg_const_i64(rb); ++ vc = tcg_temp_new(); ++ tmp64 = tcg_temp_new(); ++ ++ for (i = 0; i < 128; i += 32) { ++ if ((cond >> 1) & 1) { ++ tcg_gen_ext32s_i64(va, cpu_fr[ra + i]); ++ } else { ++ tcg_gen_ext32u_i64(va, cpu_fr[ra + i]); ++ } ++ tcg_gen_setcond_i64(cond, vc, va, vb); ++ tcg_gen_mov_i64(tmp64, vc); ++ ++ tcg_gen_shri_i64(va, cpu_fr[ra + i], 32); ++ if ((cond >> 1) & 1) { ++ tcg_gen_ext32s_i64(va, va); ++ } else { ++ tcg_gen_ext32u_i64(va, va); ++ } ++ tcg_gen_setcond_i64(cond, vc, va, vb); ++ tcg_gen_shli_i64(vc, vc, 32); ++ tcg_gen_or_i64(cpu_fr[rc + i], tmp64, vc); ++ } ++ tcg_temp_free(va); ++ tcg_temp_free(vb); ++ tcg_temp_free(vc); ++ tcg_temp_free(tmp64); ++} ++ ++static void gen_qemu_vselxxw(TCGCond cond, int ra, int rb, int rc, int rd, ++ int mask) ++{ ++ int i; ++ ++ TCGv t0 = tcg_const_i64(0); ++ TCGv tmpa = tcg_temp_new(); ++ TCGv tmpb = tcg_temp_new(); ++ TCGv tmpc = tcg_temp_new(); ++ TCGv tmpd = tcg_temp_new(); ++ ++ for (i = 0; i < 128; i += 32) { ++ tcg_gen_ext32s_i64(tmpa, cpu_fr[ra + i]); ++ tcg_gen_ext32u_i64(tmpb, cpu_fr[rb + i]); ++ tcg_gen_ext32u_i64(tmpc, cpu_fr[rc + i]); ++ if (mask) tcg_gen_andi_i64(tmpa, tmpa, mask); ++ tcg_gen_movcond_i64(cond, tmpd, tmpa, t0, tmpb, tmpc); ++ ++ tcg_gen_andi_i64(tmpa, cpu_fr[ra + i], 0xffffffff00000000UL); ++ tcg_gen_andi_i64(tmpb, cpu_fr[rb + i], 0xffffffff00000000UL); ++ tcg_gen_andi_i64(tmpc, cpu_fr[rc + i], 0xffffffff00000000UL); ++ if (mask) tcg_gen_andi_i64(tmpa, tmpa, (uint64_t)mask << 32); ++ tcg_gen_movcond_i64(cond, cpu_fr[rd + i], tmpa, t0, tmpb, tmpc); ++ ++ tcg_gen_or_i64(cpu_fr[rd + i], cpu_fr[rd + i], tmpd); ++ } ++ ++ tcg_temp_free(t0); ++ tcg_temp_free(tmpa); ++ tcg_temp_free(tmpb); ++ tcg_temp_free(tmpc); ++ tcg_temp_free(tmpd); ++} ++ ++static void gen_qemu_vselxxwi(TCGCond cond, int ra, int rb, int disp8, int rd, ++ int mask) ++{ ++ int i; ++ ++ TCGv t0 = tcg_const_i64(0); ++ TCGv tmpa = tcg_temp_new(); ++ TCGv tmpb = tcg_temp_new(); ++ TCGv tmpc_0 = tcg_temp_new(); ++ TCGv tmpc_1 = tcg_temp_new(); ++ TCGv tmpd = tcg_temp_new(); ++ ++ tcg_gen_movi_i64(tmpc_0, (uint64_t)(((uint64_t)disp8))); ++ tcg_gen_movi_i64(tmpc_1, (uint64_t)(((uint64_t)disp8 << 32))); ++ for (i = 0; i < 128; i += 32) { ++ tcg_gen_ext32s_i64(tmpa, cpu_fr[ra + i]); ++ tcg_gen_ext32u_i64(tmpb, cpu_fr[rb + i]); ++ if (mask) tcg_gen_andi_i64(tmpa, tmpa, mask); ++ tcg_gen_movcond_i64(cond, tmpd, tmpa, t0, tmpb, tmpc_0); ++ ++ tcg_gen_andi_i64(tmpa, cpu_fr[ra + i], 0xffffffff00000000UL); ++ tcg_gen_andi_i64(tmpb, cpu_fr[rb + i], 0xffffffff00000000UL); ++ if (mask) tcg_gen_andi_i64(tmpa, tmpa, (uint64_t)mask << 32); ++ tcg_gen_movcond_i64(cond, cpu_fr[rd + i], tmpa, t0, tmpb, tmpc_1); ++ ++ tcg_gen_or_i64(cpu_fr[rd + i], cpu_fr[rd + i], tmpd); ++ } ++ ++ tcg_temp_free(t0); ++ tcg_temp_free(tmpa); ++ tcg_temp_free(tmpb); ++ tcg_temp_free(tmpc_0); ++ tcg_temp_free(tmpc_1); ++ tcg_temp_free(tmpd); ++} ++ ++DisasJumpType translate_one(DisasContextBase *dcbase, uint32_t insn, ++ CPUState *cpu) ++{ ++ int32_t disp5, disp8, disp12, disp13, disp16, disp21, disp26 __attribute__((unused)); ++ uint8_t opc, ra, rb, rc, rd; ++ uint16_t fn3, fn4, fn6, fn8, fn11; ++ int32_t i; ++ TCGv va, vb, vc, vd; ++ TCGv_i32 tmp32; ++ TCGv_i64 tmp64, tmp64_0, tmp64_1, shift; ++ TCGv_i32 tmpa, tmpb, tmpc; ++ DisasJumpType ret; ++ DisasContext* ctx = container_of(dcbase, DisasContext, base); ++ ++ opc = extract32(insn, 26, 6); ++ ra = extract32(insn, 21, 5); ++ rb = extract32(insn, 16, 5); ++ rc = extract32(insn, 0, 5); ++ rd = extract32(insn, 5, 5); ++ ++ fn3 = extract32(insn, 10, 3); ++ fn6 = extract32(insn, 10, 6); ++ fn4 = extract32(insn, 12, 4); ++ fn8 = extract32(insn, 5, 8); ++ fn11 = extract32(insn, 5, 11); ++ ++ disp5 = extract32(insn, 5, 5); ++ disp8 = extract32(insn, 13, 8); ++ disp12 = sextract32(insn, 0, 12); ++ disp13 = sextract32(insn, 13, 13); ++ disp16 = sextract32(insn, 0, 16); ++ disp21 = sextract32(insn, 0, 21); ++ disp26 = sextract32(insn, 0, 26); ++ ++ ret = DISAS_NEXT; ++ insn_profile(ctx, insn); ++ ++ switch (opc) { ++ case 0x00: ++ /* SYS_CALL */ ++ ret = gen_sys_call(ctx, insn & 0x1ffffff); ++ break; ++ case 0x01: ++ /* CALL */ ++ case 0x02: ++ /* RET */ ++ case 0x03: ++ /* JMP */ ++ vb = load_gir(ctx, rb); ++ tcg_gen_addi_i64(cpu_pc, vb, ctx->base.pc_next & 0x3); ++ if (ra != 31) { ++ tcg_gen_movi_i64(load_gir(ctx, ra), ctx->base.pc_next & (~3UL)); ++ } ++ ret = DISAS_PC_UPDATED; ++ break; ++ case 0x04: ++ /* BR */ ++ case 0x05: ++ /* BSR */ ++ ret = gen_bdirect(ctx, ra, disp21); ++ break; ++ case 0x06: ++ switch (disp16) { ++ case 0x0000: ++ /* MEMB */ ++ tcg_gen_mb(TCG_MO_ALL | TCG_BAR_SC); ++ break; ++ case 0x0001: ++ /* IMEMB */ ++ /* No achievement in Qemu*/ ++ break; ++ case 0x0020: ++ /* RTC */ ++ if (disp16 && unlikely(ra == 31)) break; ++ va = load_gir(ctx, ra); ++ gen_helper_rtc(va); ++ break; ++ case 0x0040: ++ /* RCID */ ++ if (disp16 && unlikely(ra == 31)) break; ++ va = load_gir(ctx, ra); ++ read_csr(0xc4, va); ++ break; ++ case 0x0080: ++ /* HALT */ ++#ifndef CONFIG_USER_ONLY ++ { ++ tmp32 = tcg_const_i32(1); ++ tcg_gen_st_i32( ++ tmp32, cpu_env, ++ -offsetof(SW64CPU, env) + offsetof(CPUState, halted)); ++ tcg_temp_free_i32(tmp32); ++ } ++ ret = gen_excp(ctx, EXCP_HALTED, 0); ++#endif ++ break; ++ case 0x1000: ++ /* RD_F */ ++ if (disp16 && unlikely(ra == 31)) break; ++ va = load_gir(ctx, ra); ++ tcg_gen_mov_i64(va, cpu_lock_success); ++ break; ++ case 0x1020: ++ /* WR_F */ ++ if (disp16 && unlikely(ra == 31)) break; ++ va = load_gir(ctx, ra); ++ tcg_gen_andi_i64(cpu_lock_flag, va, 0x1); ++ break; ++ case 0x1040: ++ /* RTID */ ++ if (unlikely(ra == 31)) break; ++ va = load_gir(ctx, ra); ++ read_csr(0xc7, va); ++ break; ++ default: ++ if ((disp16 & 0xFF00) == 0xFE00) { ++ /* PRI_RCSR */ ++ if (disp16 && unlikely(ra == 31)) break; ++ va = load_gir(ctx, ra); ++ read_csr(disp16 & 0xff, va); ++ break; ++ } ++ if ((disp16 & 0xFF00) == 0xFF00) { ++ /* PRI_WCSR */ ++ va = load_gir(ctx, ra); ++ write_csr(disp16 & 0xff, va, ctx->env); ++ break; ++ } ++ goto do_invalid; ++ } ++ break; ++ case 0x07: ++ /* PRI_RET */ ++ va = load_gir(ctx, ra); ++ tcg_gen_mov_i64(cpu_pc, va); ++ gen_helper_cpustate_update(cpu_env, va); ++ ret = DISAS_PC_UPDATED_NOCHAIN; ++ break; ++ case 0x08: ++ switch (fn4) { ++ case 0x0: ++ /* LLDW */ ++ gen_load_mem(ctx, &gen_qemu_lldw, ra, rb, disp12, 0, 0); ++ break; ++ case 0x1: ++ /* LLDL */ ++ gen_load_mem(ctx, &gen_qemu_lldl, ra, rb, disp12, 0, 0); ++ break; ++ case 0x2: ++ /* LDW_INC */ ++ ldx_xxx(ctx, ra, rb, disp12, 0, 1); ++ break; ++ case 0x3: ++ /* LDL_INC */ ++ ldx_xxx(ctx, ra, rb, disp12, 1, 1); ++ break; ++ case 0x4: ++ /* LDW_DEC */ ++ ldx_xxx(ctx, ra, rb, disp12, 0, -1); ++ break; ++ case 0x5: ++ /* LDL_DEC */ ++ ldx_xxx(ctx, ra, rb, disp12, 1, -1); ++ break; ++ case 0x6: ++ /* LDW_SET */ ++ ldx_set(ctx, ra, rb, disp12, 0); ++ break; ++ case 0x7: ++ /* LDL_SET */ ++ ldx_set(ctx, ra, rb, disp12, 1); ++ break; ++ case 0x8: ++ /* LSTW */ ++ ret = gen_store_conditional(ctx, ra, rb, disp12, ++ ctx->mem_idx, MO_LEUL); ++ break; ++ case 0x9: ++ /* LSTL */ ++ ret = gen_store_conditional(ctx, ra, rb, disp12, ++ ctx->mem_idx, MO_LEQ); ++ break; ++ case 0xa: ++ /* LDW_NC */ ++ gen_load_mem(ctx, &tcg_gen_qemu_ld32s, ra, rb, disp12, 0, ++ 0); ++ break; ++ case 0xb: ++ /* LDL_NC */ ++ gen_load_mem(ctx, &tcg_gen_qemu_ld64, ra, rb, disp12, 0, 0); ++ break; ++ case 0xc: ++ /* LDD_NC */ ++ gen_load_mem(ctx, &tcg_gen_qemu_ld64, ra, rb, disp12, 1, 0); ++ break; ++ case 0xd: ++ /* STW_NC */ ++ gen_store_mem(ctx, &tcg_gen_qemu_st32, ra, rb, disp12, 0, ++ 0); ++ break; ++ case 0xe: ++ /* STL_NC */ ++ gen_store_mem(ctx, &tcg_gen_qemu_st64, ra, rb, disp12, 0, ++ 0); ++ break; ++ case 0xf: ++ /* STD_NC */ ++ gen_store_mem(ctx, &tcg_gen_qemu_st64, ra, rb, disp12, 1, ++ 0); ++ break; ++ default: ++ goto do_invalid; ++ } ++ break; ++ case 0x9: ++ /* LDWE */ ++ gen_load_mem_simd(ctx, &gen_qemu_ldwe, ra, rb, disp16, 0); ++ break; ++ case 0x0a: ++ /* LDSE */ ++ gen_load_mem_simd(ctx, &gen_qemu_ldse, ra, rb, disp16, 0); ++ break; ++ case 0x0b: ++ /* LDDE */ ++ gen_load_mem_simd(ctx, &gen_qemu_ldde, ra, rb, disp16, 0); ++ break; ++ case 0x0c: ++ /* VLDS */ ++ gen_load_mem_simd(ctx, &gen_qemu_vlds, ra, rb, disp16, 0); ++ break; ++ case 0x0d: ++ /* VLDD */ ++ if (unlikely(ra == 31)) break; ++ gen_load_mem_simd(ctx, &gen_qemu_vldd, ra, rb, disp16, 0); ++ break; ++ case 0x0e: ++ /* VSTS */ ++ gen_store_mem_simd(ctx, &gen_qemu_vsts, ra, rb, disp16, 0); ++ break; ++ case 0x0f: ++ /* VSTD */ ++ gen_store_mem_simd(ctx, &gen_qemu_vstd, ra, rb, disp16, 0); ++ break; ++ case 0x10: ++ if (unlikely(rc == 31)) break; ++ if (fn11 == 0x70) { ++ /* FIMOVS */ ++ va = cpu_fr[ra]; ++ vc = load_gir(ctx, rc); ++ tmp32 = tcg_temp_new_i32(); ++ gen_helper_s_to_memory(tmp32, va); ++ tcg_gen_ext_i32_i64(vc, tmp32); ++ tcg_temp_free_i32(tmp32); ++ } else if (fn11 == 0x78) { ++ /* FIMOVD */ ++ va = cpu_fr[ra]; ++ vc = load_gir(ctx, rc); ++ tcg_gen_mov_i64(vc, va); ++ } else { ++ va = load_gir(ctx, ra); ++ vb = load_gir(ctx, rb); ++ vc = load_gir(ctx, rc); ++ cal_with_iregs_2(ctx, vc, va, vb, disp13, fn11); ++ } ++ break; ++ case 0x11: ++ if (unlikely(rc == 31)) break; ++ va = load_gir(ctx, ra); ++ vb = load_gir(ctx, rb); ++ vc = load_gir(ctx, rc); ++ vd = load_gir(ctx, rd); ++ cal_with_iregs_3(ctx, vc, va, vb, vd, fn3); ++ break; ++ case 0x12: ++ if (unlikely(rc == 31)) break; ++ va = load_gir(ctx, ra); ++ vc = load_gir(ctx, rc); ++ cal_with_imm_2(ctx, vc, va, disp8, fn8); ++ break; ++ case 0x13: ++ if (rc == 31) /* Special deal */ ++ break; ++ va = load_gir(ctx, ra); ++ vc = load_gir(ctx, rc); ++ vd = load_gir(ctx, rd); ++ cal_with_imm_3(ctx, vc, va, disp8, vd, fn3); ++ break; ++ case 0x14: ++ case 0x15: ++ case 0x16: ++ case 0x17: ++ /* VLOGZZ */ ++ tcg_gen_vlogzz_i64(ctx, opc, ra, rb, rd, rc, fn6); ++ break; ++ case 0x18: ++ if (unlikely(rc == 31)) break; ++ cal_with_fregs_2(ctx, rc, ra, rb, fn8); ++ break; ++ case 0x19: ++ if (unlikely(rc == 31)) break; ++ cal_with_fregs_4(ctx, rc, ra, rb, rd, fn6); ++ break; ++ case 0x1A: ++ /* SIMD */ ++ if (unlikely(rc == 31)) break; ++ switch (fn8) { ++ case 0x00: ++ /* VADDW */ ++ tmp64 = tcg_temp_new(); ++ va = tcg_temp_new(); ++ vb = tcg_temp_new(); ++ vc = tcg_temp_new(); ++ ++ for (i = 0; i < 128; i += 32) { ++ tcg_gen_andi_i64(va, cpu_fr[ra + i], 0xffffffffUL); ++ tcg_gen_andi_i64(vb, cpu_fr[rb + i], 0xffffffffUL); ++ tcg_gen_add_i64(tmp64, va, vb); ++ tcg_gen_ext32u_i64(tmp64, tmp64); ++ tcg_gen_andi_i64(va, cpu_fr[ra + i], ++ 0xffffffff00000000UL); ++ tcg_gen_andi_i64(vb, cpu_fr[rb + i], ++ 0xffffffff00000000UL); ++ tcg_gen_add_i64(vc, va, vb); ++ tcg_gen_or_i64(tmp64, tmp64, vc); ++ tcg_gen_mov_i64(cpu_fr[rc + i], tmp64); ++ } ++ tcg_temp_free(va); ++ tcg_temp_free(vb); ++ tcg_temp_free(vc); ++ tcg_temp_free(tmp64); ++ break; ++ case 0x20: ++ /* VADDW */ ++ tmp64 = tcg_temp_new(); ++ va = tcg_temp_new(); ++ vc = tcg_temp_new(); ++ ++ for (i = 0; i < 128; i += 32) { ++ tcg_gen_andi_i64(va, cpu_fr[ra + i], 0xffffffffUL); ++ tcg_gen_addi_i64(tmp64, va, disp8); ++ tcg_gen_ext32u_i64(tmp64, tmp64); ++ tcg_gen_andi_i64(va, cpu_fr[ra + i], ++ 0xffffffff00000000UL); ++ tcg_gen_addi_i64(vc, va, ((uint64_t)disp8 << 32)); ++ tcg_gen_or_i64(tmp64, tmp64, vc); ++ tcg_gen_mov_i64(cpu_fr[rc + i], tmp64); ++ } ++ tcg_temp_free(va); ++ tcg_temp_free(vc); ++ tcg_temp_free(tmp64); ++ break; ++ case 0x01: ++ /* VSUBW */ ++ tmp64 = tcg_temp_new(); ++ va = tcg_temp_new(); ++ vb = tcg_temp_new(); ++ vc = tcg_temp_new(); ++ ++ for (i = 0; i < 128; i += 32) { ++ tcg_gen_andi_i64(va, cpu_fr[ra + i], 0xffffffffUL); ++ tcg_gen_andi_i64(vb, cpu_fr[rb + i], 0xffffffffUL); ++ tcg_gen_sub_i64(tmp64, va, vb); ++ tcg_gen_ext32u_i64(tmp64, tmp64); ++ tcg_gen_andi_i64(va, cpu_fr[ra + i], ++ 0xffffffff00000000UL); ++ tcg_gen_andi_i64(vb, cpu_fr[rb + i], ++ 0xffffffff00000000UL); ++ tcg_gen_sub_i64(vc, va, vb); ++ tcg_gen_or_i64(tmp64, tmp64, vc); ++ tcg_gen_mov_i64(cpu_fr[rc + i], tmp64); ++ } ++ tcg_temp_free(va); ++ tcg_temp_free(vb); ++ tcg_temp_free(vc); ++ tcg_temp_free(tmp64); ++ break; ++ case 0x21: ++ /* VSUBW */ ++ tmp64 = tcg_temp_new(); ++ va = tcg_temp_new(); ++ vc = tcg_temp_new(); ++ ++ for (i = 0; i < 128; i += 32) { ++ tcg_gen_andi_i64(va, cpu_fr[ra + i], 0xffffffffUL); ++ tcg_gen_subi_i64(tmp64, va, disp8); ++ tcg_gen_ext32u_i64(tmp64, tmp64); ++ tcg_gen_andi_i64(va, cpu_fr[ra + i], ++ 0xffffffff00000000UL); ++ tcg_gen_subi_i64(vc, va, ((uint64_t)disp8 << 32)); ++ tcg_gen_or_i64(tmp64, tmp64, vc); ++ tcg_gen_mov_i64(cpu_fr[rc + i], tmp64); ++ } ++ tcg_temp_free(va); ++ tcg_temp_free(vc); ++ tcg_temp_free(tmp64); ++ break; ++ case 0x02: ++ /* VCMPGEW */ ++ tmp64 = tcg_const_i64(0); ++ va = tcg_temp_new(); ++ vb = tcg_temp_new(); ++ vc = tcg_temp_new(); ++ ++ for (i = 0; i < 128; i += 32) { ++ tcg_gen_ext32s_i64(va, cpu_fr[ra + i]); ++ tcg_gen_ext32s_i64(vb, cpu_fr[rb + i]); ++ tcg_gen_setcond_i64(TCG_COND_GE, vc, va, vb); ++ tcg_gen_or_i64(tmp64, tmp64, vc); ++ tcg_gen_shri_i64(va, cpu_fr[ra + i], 32); ++ tcg_gen_shri_i64(vb, cpu_fr[rb + i], 32); ++ tcg_gen_ext32s_i64(va, va); ++ tcg_gen_ext32s_i64(vb, vb); ++ tcg_gen_setcond_i64(TCG_COND_GE, vc, va, vb); ++ tcg_gen_or_i64(tmp64, tmp64, vc); ++ } ++ tcg_gen_shli_i64(cpu_fr[rc], tmp64, 29); ++ tcg_temp_free(va); ++ tcg_temp_free(vb); ++ tcg_temp_free(vc); ++ tcg_temp_free(tmp64); ++ break; ++ case 0x22: ++ /* VCMPGEW */ ++ tmp64 = tcg_const_i64(0); ++ va = tcg_temp_new(); ++ vb = tcg_const_i64(disp8); ++ vc = tcg_temp_new(); ++ ++ for (i = 0; i < 128; i += 32) { ++ tcg_gen_ext32s_i64(va, cpu_fr[ra + i]); ++ tcg_gen_setcond_i64(TCG_COND_GE, vc, va, vb); ++ tcg_gen_or_i64(tmp64, tmp64, vc); ++ tcg_gen_shri_i64(va, cpu_fr[ra + i], 32); ++ tcg_gen_ext32s_i64(va, va); ++ tcg_gen_setcond_i64(TCG_COND_GE, vc, va, vb); ++ tcg_gen_or_i64(tmp64, tmp64, vc); ++ } ++ tcg_gen_shli_i64(cpu_fr[rc], tmp64, 29); ++ tcg_temp_free(va); ++ tcg_temp_free(vb); ++ tcg_temp_free(vc); ++ tcg_temp_free(tmp64); ++ break; ++ case 0x03: ++ /* VCMPEQW */ ++ gen_qemu_vcmpxxw_i64(TCG_COND_EQ, ra, rb, rc); ++ break; ++ case 0x23: ++ /* VCMPEQW */ ++ gen_qemu_vcmpxxwi_i64(TCG_COND_EQ, ra, disp8, rc); ++ break; ++ case 0x04: ++ /* VCMPLEW */ ++ gen_qemu_vcmpxxw_i64(TCG_COND_LE, ra, rb, rc); ++ break; ++ case 0x24: ++ /* VCMPLEW */ ++ gen_qemu_vcmpxxwi_i64(TCG_COND_LE, ra, disp8, rc); ++ break; ++ case 0x05: ++ /* VCMPLTW */ ++ gen_qemu_vcmpxxw_i64(TCG_COND_LT, ra, rb, rc); ++ break; ++ case 0x25: ++ /* VCMPLTW */ ++ gen_qemu_vcmpxxwi_i64(TCG_COND_LT, ra, disp8, rc); ++ break; ++ case 0x06: ++ /* VCMPULEW */ ++ gen_qemu_vcmpxxw_i64(TCG_COND_LEU, ra, rb, rc); ++ break; ++ case 0x26: ++ /* VCMPULEW */ ++ gen_qemu_vcmpxxwi_i64(TCG_COND_LEU, ra, disp8, rc); ++ break; ++ case 0x07: ++ /* VCMPULTW */ ++ gen_qemu_vcmpxxw_i64(TCG_COND_LTU, ra, rb, rc); ++ break; ++ case 0x27: ++ /* VCMPULTW */ ++ gen_qemu_vcmpxxwi_i64(TCG_COND_LTU, ra, disp8, rc); ++ break; ++ case 0x08: ++ /* VSLLW */ ++ tmp64 = tcg_temp_new(); ++ shift = tcg_temp_new(); ++ vc = tcg_temp_new(); ++ for (i = 0; i < 128; i += 32) { ++ tcg_gen_shri_i64(shift, cpu_fr[rb], 29); ++ tcg_gen_andi_i64(shift, shift, 0x1fUL); ++ ++ tcg_gen_shl_i64(vc, cpu_fr[ra + i], shift); ++ tcg_gen_ext32u_i64(tmp64, vc); ++ ++ tcg_gen_andi_i64(vc, cpu_fr[ra + i], ++ 0xffffffff00000000UL); ++ tcg_gen_shl_i64(vc, vc, shift); ++ tcg_gen_or_i64(cpu_fr[rc + i], tmp64, vc); ++ } ++ tcg_temp_free(tmp64); ++ tcg_temp_free(shift); ++ tcg_temp_free(vc); ++ break; ++ case 0x28: ++ /* VSLLW */ ++ tmp64 = tcg_temp_new(); ++ shift = tcg_temp_new(); ++ vc = tcg_temp_new(); ++ for (i = 0; i < 128; i += 32) { ++ tcg_gen_movi_i64(shift, disp8 & 0x1fUL); ++ ++ tcg_gen_shl_i64(vc, cpu_fr[ra + i], shift); ++ tcg_gen_ext32u_i64(tmp64, vc); ++ ++ tcg_gen_andi_i64(vc, cpu_fr[ra + i], ++ 0xffffffff00000000UL); ++ tcg_gen_shl_i64(vc, vc, shift); ++ tcg_gen_or_i64(cpu_fr[rc + i], tmp64, vc); ++ } ++ tcg_temp_free(tmp64); ++ tcg_temp_free(shift); ++ tcg_temp_free(vc); ++ break; ++ case 0x09: ++ /* VSRLW */ ++ tmp64 = tcg_temp_new(); ++ shift = tcg_temp_new(); ++ vc = tcg_temp_new(); ++ for (i = 0; i < 128; i += 32) { ++ tcg_gen_shri_i64(shift, cpu_fr[rb], 29); ++ tcg_gen_andi_i64(shift, shift, 0x1fUL); ++ ++ tcg_gen_ext32u_i64(vc, cpu_fr[ra + i]); ++ tcg_gen_shr_i64(tmp64, vc, shift); ++ ++ tcg_gen_shr_i64(vc, cpu_fr[ra + i], shift); ++ tcg_gen_andi_i64(vc, vc, 0xffffffff00000000UL); ++ tcg_gen_or_i64(cpu_fr[rc + i], tmp64, vc); ++ } ++ tcg_temp_free(tmp64); ++ tcg_temp_free(shift); ++ tcg_temp_free(vc); ++ break; ++ case 0x29: ++ /* VSRLW */ ++ tmp64 = tcg_temp_new(); ++ shift = tcg_temp_new(); ++ vc = tcg_temp_new(); ++ for (i = 0; i < 128; i += 32) { ++ tcg_gen_movi_i64(shift, disp8 & 0x1fUL); ++ ++ tcg_gen_ext32u_i64(vc, cpu_fr[ra + i]); ++ tcg_gen_shr_i64(tmp64, vc, shift); ++ ++ tcg_gen_shr_i64(vc, cpu_fr[ra + i], shift); ++ tcg_gen_andi_i64(vc, vc, 0xffffffff00000000UL); ++ tcg_gen_or_i64(cpu_fr[rc + i], tmp64, vc); ++ } ++ tcg_temp_free(tmp64); ++ tcg_temp_free(shift); ++ tcg_temp_free(vc); ++ break; ++ case 0x0A: ++ /* VSRAW */ ++ tmp64 = tcg_temp_new(); ++ shift = tcg_temp_new(); ++ vc = tcg_temp_new(); ++ for (i = 0; i < 128; i += 32) { ++ tcg_gen_shri_i64(shift, cpu_fr[rb], 29); ++ tcg_gen_andi_i64(shift, shift, 0x1fUL); ++ ++ tcg_gen_ext32s_i64(vc, cpu_fr[ra + i]); ++ tcg_gen_sar_i64(tmp64, vc, shift); ++ ++ tcg_gen_sar_i64(vc, cpu_fr[ra + i], shift); ++ tcg_gen_andi_i64(vc, vc, 0xffffffff00000000UL); ++ tcg_gen_or_i64(cpu_fr[rc + i], tmp64, vc); ++ } ++ tcg_temp_free(tmp64); ++ tcg_temp_free(shift); ++ tcg_temp_free(vc); ++ break; ++ case 0x2A: ++ /* VSRAWI */ ++ tmp64 = tcg_temp_new(); ++ shift = tcg_temp_new(); ++ vc = tcg_temp_new(); ++ for (i = 0; i < 128; i += 32) { ++ tcg_gen_movi_i64(shift, disp8 & 0x1fUL); ++ ++ tcg_gen_ext32s_i64(vc, cpu_fr[ra + i]); ++ tcg_gen_sar_i64(tmp64, vc, shift); ++ ++ tcg_gen_sar_i64(vc, cpu_fr[ra + i], shift); ++ tcg_gen_andi_i64(vc, vc, 0xffffffff00000000UL); ++ tcg_gen_or_i64(cpu_fr[rc + i], tmp64, vc); ++ } ++ tcg_temp_free(tmp64); ++ tcg_temp_free(shift); ++ tcg_temp_free(vc); ++ break; ++ case 0x0B: ++ /* VROLW */ ++ tmpa = tcg_temp_new_i32(); ++ tmpb = tcg_temp_new_i32(); ++ tmpc = tcg_temp_new_i32(); ++ tmp64 = tcg_temp_new(); ++ shift = tcg_temp_new(); ++ vc = tcg_temp_new(); ++ ++ for (i = 0; i < 128; i += 32) { ++ tcg_gen_shri_i64(shift, cpu_fr[rb], 29); ++ tcg_gen_andi_i64(shift, shift, 0x1fUL); ++ ++ tcg_gen_extrl_i64_i32(tmpa, cpu_fr[ra + i]); ++ tcg_gen_extrl_i64_i32(tmpb, shift); ++ ++ tcg_gen_rotl_i32(tmpc, tmpa, tmpb); ++ tcg_gen_extu_i32_i64(tmp64, tmpc); ++ ++ tcg_gen_extrh_i64_i32(tmpa, cpu_fr[ra + i]); ++ tcg_gen_rotl_i32(tmpc, tmpa, tmpb); ++ tcg_gen_extu_i32_i64(vc, tmpc); ++ tcg_gen_shli_i64(vc, vc, 32); ++ ++ tcg_gen_or_i64(cpu_fr[rc + i], vc, tmp64); ++ } ++ tcg_temp_free_i32(tmpa); ++ tcg_temp_free_i32(tmpb); ++ tcg_temp_free_i32(tmpc); ++ tcg_temp_free(tmp64); ++ tcg_temp_free(shift); ++ tcg_temp_free(vc); ++ break; ++ case 0x2B: ++ /* VROLW */ ++ tmpa = tcg_temp_new_i32(); ++ tmpb = tcg_temp_new_i32(); ++ tmpc = tcg_temp_new_i32(); ++ tmp64 = tcg_temp_new(); ++ shift = tcg_temp_new(); ++ vc = tcg_temp_new(); ++ ++ for (i = 0; i < 128; i += 32) { ++ tcg_gen_movi_i64(shift, disp8 & 0x1fUL); ++ ++ tcg_gen_extrl_i64_i32(tmpa, cpu_fr[ra + i]); ++ tcg_gen_extrl_i64_i32(tmpb, shift); ++ ++ tcg_gen_rotl_i32(tmpc, tmpa, tmpb); ++ tcg_gen_extu_i32_i64(tmp64, tmpc); ++ ++ tcg_gen_extrh_i64_i32(tmpa, cpu_fr[ra + i]); ++ tcg_gen_rotl_i32(tmpc, tmpa, tmpb); ++ tcg_gen_extu_i32_i64(vc, tmpc); ++ tcg_gen_shli_i64(vc, vc, 32); ++ ++ tcg_gen_or_i64(cpu_fr[rc + i], vc, tmp64); ++ } ++ tcg_temp_free_i32(tmpa); ++ tcg_temp_free_i32(tmpb); ++ tcg_temp_free_i32(tmpc); ++ tcg_temp_free(tmp64); ++ tcg_temp_free(shift); ++ tcg_temp_free(vc); ++ break; ++ case 0x0C: ++ /* SLLOW */ ++ tcg_gen_sllow_i64(ra, rc, rb); ++ break; ++ case 0x2C: ++ /* SLLOW */ ++ tcg_gen_sllowi_i64(ra, rc, disp8); ++ break; ++ case 0x0D: ++ /* SRLOW */ ++ tcg_gen_srlow_i64(ra, rc, rb); ++ break; ++ case 0x2D: ++ /* SRLOW */ ++ tcg_gen_srlowi_i64(ra, rc, disp8); ++ break; ++ case 0x0E: ++ /* VADDL */ ++ for (i = 0; i < 128; i += 32) { ++ tcg_gen_add_i64(cpu_fr[rc + i], cpu_fr[ra + i], ++ cpu_fr[rb + i]); ++ } ++ break; ++ case 0x2E: ++ /* VADDL */ ++ for (i = 0; i < 128; i += 32) { ++ tcg_gen_addi_i64(cpu_fr[rc + i], cpu_fr[ra + i], disp8); ++ } ++ break; ++ case 0x0F: ++ /* VSUBL */ ++ for (i = 0; i < 128; i += 32) { ++ tcg_gen_sub_i64(cpu_fr[rc + i], cpu_fr[ra + i], ++ cpu_fr[rb + i]); ++ } ++ break; ++ case 0x2F: ++ /* VSUBL */ ++ for (i = 0; i < 128; i += 32) { ++ tcg_gen_subi_i64(cpu_fr[rc + i], cpu_fr[ra + i], disp8); ++ } ++ break; ++ case 0x18: ++ /* CTPOPOW */ ++ tmp64 = tcg_const_i64(0); ++ tmp64_0 = tcg_temp_new(); ++ ++ for (i = 0; i < 128; i += 32) { ++ tcg_gen_ctpop_i64(tmp64_0, cpu_fr[ra + i]); ++ tcg_gen_add_i64(tmp64, tmp64, tmp64_0); ++ } ++ tcg_gen_shli_i64(cpu_fr[rc], tmp64, 29); ++ tcg_temp_free(tmp64); ++ tcg_temp_free(tmp64_0); ++ break; ++ case 0x19: ++ /* CTLZOW */ ++ va = tcg_const_i64(ra); ++ gen_helper_ctlzow(cpu_fr[rc], cpu_env, va); ++ tcg_temp_free(va); ++ break; ++ case 0x40: ++ /* VUCADDW */ ++ va = tcg_const_i64(ra); ++ vb = tcg_const_i64(rb); ++ vc = tcg_const_i64(rc); ++ gen_helper_vucaddw(cpu_env, va, vb, vc); ++ tcg_temp_free(va); ++ tcg_temp_free(vb); ++ tcg_temp_free(vc); ++ break; ++ case 0x60: ++ /* VUCADDW */ ++ va = tcg_const_i64(ra); ++ vb = tcg_const_i64(disp8); ++ vc = tcg_const_i64(rc); ++ gen_helper_vucaddwi(cpu_env, va, vb, vc); ++ tcg_temp_free(va); ++ tcg_temp_free(vb); ++ tcg_temp_free(vc); ++ break; ++ case 0x41: ++ /* VUCSUBW */ ++ va = tcg_const_i64(ra); ++ vb = tcg_const_i64(rb); ++ vc = tcg_const_i64(rc); ++ gen_helper_vucsubw(cpu_env, va, vb, vc); ++ tcg_temp_free(va); ++ tcg_temp_free(vb); ++ tcg_temp_free(vc); ++ break; ++ case 0x61: ++ /* VUCSUBW */ ++ va = tcg_const_i64(ra); ++ vb = tcg_const_i64(disp8); ++ vc = tcg_const_i64(rc); ++ gen_helper_vucsubwi(cpu_env, va, vb, vc); ++ tcg_temp_free(va); ++ tcg_temp_free(vb); ++ tcg_temp_free(vc); ++ break; ++ case 0x42: ++ /* VUCADDH */ ++ va = tcg_const_i64(ra); ++ vb = tcg_const_i64(rb); ++ vc = tcg_const_i64(rc); ++ gen_helper_vucaddh(cpu_env, va, vb, vc); ++ tcg_temp_free(va); ++ tcg_temp_free(vb); ++ tcg_temp_free(vc); ++ break; ++ case 0x62: ++ /* VUCADDH */ ++ va = tcg_const_i64(ra); ++ vb = tcg_const_i64(disp8); ++ vc = tcg_const_i64(rc); ++ gen_helper_vucaddhi(cpu_env, va, vb, vc); ++ tcg_temp_free(va); ++ tcg_temp_free(vb); ++ tcg_temp_free(vc); ++ break; ++ case 0x43: ++ /* VUCSUBH */ ++ va = tcg_const_i64(ra); ++ vb = tcg_const_i64(rb); ++ vc = tcg_const_i64(rc); ++ gen_helper_vucsubh(cpu_env, va, vb, vc); ++ tcg_temp_free(va); ++ tcg_temp_free(vb); ++ tcg_temp_free(vc); ++ break; ++ case 0x63: ++ /* VUCSUBH */ ++ va = tcg_const_i64(ra); ++ vb = tcg_const_i64(disp8); ++ vc = tcg_const_i64(rc); ++ gen_helper_vucsubhi(cpu_env, va, vb, vc); ++ tcg_temp_free(va); ++ tcg_temp_free(vb); ++ tcg_temp_free(vc); ++ break; ++ case 0x44: ++ /* VUCADDB */ ++ va = tcg_const_i64(ra); ++ vb = tcg_const_i64(rb); ++ vc = tcg_const_i64(rc); ++ gen_helper_vucaddb(cpu_env, va, vb, vc); ++ tcg_temp_free(va); ++ tcg_temp_free(vb); ++ tcg_temp_free(vc); ++ break; ++ case 0x64: ++ /* VUCADDB */ ++ va = tcg_const_i64(ra); ++ vb = tcg_const_i64(disp8); ++ vc = tcg_const_i64(rc); ++ gen_helper_vucaddbi(cpu_env, va, vb, vc); ++ tcg_temp_free(va); ++ tcg_temp_free(vb); ++ tcg_temp_free(vc); ++ break; ++ case 0x45: ++ /* VUCSUBB */ ++ va = tcg_const_i64(ra); ++ vb = tcg_const_i64(rb); ++ vc = tcg_const_i64(rc); ++ gen_helper_vucsubb(cpu_env, va, vb, vc); ++ tcg_temp_free(va); ++ tcg_temp_free(vb); ++ tcg_temp_free(vc); ++ break; ++ case 0x65: ++ /* VUCSUBB */ ++ va = tcg_const_i64(ra); ++ vb = tcg_const_i64(disp8); ++ vc = tcg_const_i64(rc); ++ gen_helper_vucsubbi(cpu_env, va, vb, vc); ++ tcg_temp_free(va); ++ tcg_temp_free(vb); ++ tcg_temp_free(vc); ++ break; ++ case 0x80: ++ /* VADDS */ ++ for (i = 0; i < 128; i += 32) ++ gen_fadds(ctx, ra + i, rb + i, rc + i); ++ break; ++ case 0x81: ++ /* VADDD */ ++ for (i = 0; i < 128; i += 32) ++ gen_faddd(ctx, ra + i, rb + i, rc + i); ++ break; ++ case 0x82: ++ /* VSUBS */ ++ for (i = 0; i < 128; i += 32) ++ gen_fsubs(ctx, ra + i, rb + i, rc + i); ++ break; ++ case 0x83: ++ /* VSUBD */ ++ for (i = 0; i < 128; i += 32) ++ gen_fsubd(ctx, ra + i, rb + i, rc + i); ++ break; ++ case 0x84: ++ /* VMULS */ ++ for (i = 0; i < 128; i += 32) ++ gen_fmuls(ctx, ra + i, rb + i, rc + i); ++ break; ++ case 0x85: ++ /* VMULD */ ++ for (i = 0; i < 128; i += 32) ++ gen_fmuld(ctx, ra + i, rb + i, rc + i); ++ break; ++ case 0x86: ++ /* VDIVS */ ++ for (i = 0; i < 128; i += 32) ++ gen_fdivs(ctx, ra + i, rb + i, rc + i); ++ break; ++ case 0x87: ++ /* VDIVD */ ++ for (i = 0; i < 128; i += 32) ++ gen_fdivd(ctx, ra + i, rb + i, rc + i); ++ break; ++ case 0x88: ++ /* VSQRTS */ ++ for (i = 0; i < 128; i += 32) ++ gen_helper_fsqrts(cpu_fr[rc + i], cpu_env, ++ cpu_fr[rb + i]); ++ break; ++ case 0x89: ++ /* VSQRTD */ ++ for (i = 0; i < 128; i += 32) ++ gen_helper_fsqrt(cpu_fr[rc + i], cpu_env, ++ cpu_fr[rb + i]); ++ break; ++ case 0x8C: ++ /* VFCMPEQ */ ++ for (i = 0; i < 128; i += 32) ++ gen_fcmpeq(ctx, ra + i, rb + i, rc + i); ++ break; ++ case 0x8D: ++ /* VFCMPLE */ ++ for (i = 0; i < 128; i += 32) ++ gen_fcmple(ctx, ra + i, rb + i, rc + i); ++ break; ++ case 0x8E: ++ /* VFCMPLT */ ++ for (i = 0; i < 128; i += 32) ++ gen_fcmplt(ctx, ra + i, rb + i, rc + i); ++ break; ++ case 0x8F: ++ /* VFCMPUN */ ++ for (i = 0; i < 128; i += 32) ++ gen_fcmpun(ctx, ra + i, rb + i, rc + i); ++ break; ++ case 0x90: ++ /* VCPYS */ ++ tcg_gen_vcpys_i64(ra, rb, rc); ++ break; ++ case 0x91: ++ /* VCPYSE */ ++ tcg_gen_vcpyse_i64(ra, rb, rc); ++ break; ++ case 0x92: ++ /* VCPYSN */ ++ tcg_gen_vcpysn_i64(ra, rb, rc); ++ break; ++ case 0x93: ++ /* VSUMS */ ++ gen_fadds(ctx, ra, ra + 32, rc); ++ gen_fadds(ctx, rc, ra + 64, rc); ++ gen_fadds(ctx, rc, ra + 96, rc); ++ break; ++ case 0x94: ++ /* VSUMD */ ++ gen_faddd(ctx, ra, ra + 32, rc); ++ gen_faddd(ctx, rc, ra + 64, rc); ++ gen_faddd(ctx, rc, ra + 96, rc); ++ break; ++ default: ++ printf("ILLEGAL BELOW OPC[%x] func[%08x]\n", opc, fn8); ++ ret = gen_invalid(ctx); ++ break; ++ } ++ break; ++ case 0x1B: ++ /* SIMD */ ++ if (unlikely(rc == 31)) break; ++ switch (fn6) { ++ case 0x00: ++ /* VMAS */ ++ for (i = 0; i < 128; i += 32) ++ gen_helper_fmas(cpu_fr[rc + i], cpu_env, cpu_fr[ra + i], ++ cpu_fr[rb + i], cpu_fr[rd + i]); ++ break; ++ case 0x01: ++ /* VMAD */ ++ for (i = 0; i < 128; i += 32) ++ gen_helper_fmad(cpu_fr[rc + i], cpu_env, cpu_fr[ra + i], ++ cpu_fr[rb + i], cpu_fr[rd + i]); ++ break; ++ case 0x02: ++ /* VMSS */ ++ for (i = 0; i < 128; i += 32) ++ gen_helper_fmss(cpu_fr[rc + i], cpu_env, cpu_fr[ra + i], ++ cpu_fr[rb + i], cpu_fr[rd + i]); ++ break; ++ case 0x03: ++ /* VMSD */ ++ for (i = 0; i < 128; i += 32) ++ gen_helper_fmsd(cpu_fr[rc + i], cpu_env, cpu_fr[ra + i], ++ cpu_fr[rb + i], cpu_fr[rd + i]); ++ break; ++ case 0x04: ++ /* VNMAS */ ++ for (i = 0; i < 128; i += 32) ++ gen_helper_fnmas(cpu_fr[rc + i], cpu_env, ++ cpu_fr[ra + i], cpu_fr[rb + i], ++ cpu_fr[rd + i]); ++ break; ++ case 0x05: ++ /* VNMAD */ ++ for (i = 0; i < 128; i += 32) ++ gen_helper_fnmad(cpu_fr[rc + i], cpu_env, ++ cpu_fr[ra + i], cpu_fr[rb + i], ++ cpu_fr[rd + i]); ++ break; ++ case 0x06: ++ /* VNMSS */ ++ for (i = 0; i < 128; i += 32) ++ gen_helper_fnmss(cpu_fr[rc + i], cpu_env, ++ cpu_fr[ra + i], cpu_fr[rb + i], ++ cpu_fr[rd + i]); ++ break; ++ case 0x07: ++ /* VNMSD */ ++ for (i = 0; i < 128; i += 32) ++ gen_helper_fnmsd(cpu_fr[rc + i], cpu_env, ++ cpu_fr[ra + i], cpu_fr[rb + i], ++ cpu_fr[rd + i]); ++ break; ++ case 0x10: ++ /* VFSELEQ */ ++ tmp64 = tcg_temp_new(); ++ tmp64_0 = tcg_const_i64(0); ++ for (i = 0; i < 128; i += 32) { ++ gen_helper_fcmpeq(tmp64, cpu_env, cpu_fr[ra + i], ++ tmp64_0); ++ tcg_gen_movcond_i64(TCG_COND_EQ, cpu_fr[rc + i], tmp64, ++ tmp64_0, cpu_fr[rd + i], ++ cpu_fr[rb + i]); ++ } ++ tcg_temp_free(tmp64); ++ tcg_temp_free(tmp64_0); ++ break; ++ case 0x12: ++ /* VFSELLT */ ++ tmp64 = tcg_temp_new(); ++ tmp64_0 = tcg_const_i64(0); ++ tmp64_1 = tcg_temp_new(); ++ for (i = 0; i < 128; i += 32) { ++ tcg_gen_andi_i64(tmp64, cpu_fr[ra + i], ++ 0x7fffffffffffffffUL); ++ tcg_gen_setcond_i64(TCG_COND_NE, tmp64, tmp64, ++ tmp64_0); ++ tcg_gen_shri_i64(tmp64_1, cpu_fr[ra +i], 63); ++ tcg_gen_and_i64(tmp64, tmp64_1, tmp64); ++ tcg_gen_movcond_i64(TCG_COND_EQ, cpu_fr[rc + i], tmp64, ++ tmp64_0, cpu_fr[rd + i], ++ cpu_fr[rb + i]); ++ } ++ tcg_temp_free(tmp64); ++ tcg_temp_free(tmp64_0); ++ tcg_temp_free(tmp64_1); ++ break; ++ case 0x13: ++ /* VFSELLE */ ++ tmp64 = tcg_temp_new(); ++ tmp64_0 = tcg_const_i64(0); ++ tmp64_1 = tcg_temp_new(); ++ for (i = 0; i < 128; i += 32) { ++ tcg_gen_andi_i64(tmp64, cpu_fr[ra + i], ++ 0x7fffffffffffffffUL); ++ tcg_gen_setcond_i64(TCG_COND_EQ, tmp64, tmp64, ++ tmp64_0); ++ tcg_gen_shri_i64(tmp64_1, cpu_fr[ra + i], 63); ++ tcg_gen_or_i64(tmp64, tmp64_1, tmp64); ++ tcg_gen_movcond_i64(TCG_COND_EQ, cpu_fr[rc + i], tmp64, ++ tmp64_0, cpu_fr[rd + i], ++ cpu_fr[rb + i]); ++ } ++ tcg_temp_free(tmp64); ++ tcg_temp_free(tmp64_0); ++ tcg_temp_free(tmp64_1); ++ break; ++ case 0x18: ++ /* VSELEQW */ ++ gen_qemu_vselxxw(TCG_COND_EQ, ra, rb, rd, rc, 0); ++ break; ++ case 0x38: ++ /* VSELEQW */ ++ gen_qemu_vselxxwi(TCG_COND_EQ, ra, rb, disp5, rc, 0); ++ break; ++ case 0x19: ++ /* VSELLBCW */ ++ gen_qemu_vselxxw(TCG_COND_EQ, ra, rb, rd, rc, 1); ++ break; ++ case 0x39: ++ /* VSELLBCW */ ++ gen_qemu_vselxxwi(TCG_COND_EQ, ra, rb, disp5, rc, 1); ++ break; ++ case 0x1A: ++ /* VSELLTW */ ++ gen_qemu_vselxxw(TCG_COND_LT, ra, rb, rd, rc, 0); ++ break; ++ case 0x3A: ++ /* VSELLTW */ ++ gen_qemu_vselxxwi(TCG_COND_LT, ra, rb, disp5, rc, 0); ++ break; ++ case 0x1B: ++ /* VSELLEW */ ++ gen_qemu_vselxxw(TCG_COND_LE, ra, rb, rd, rc, 0); ++ break; ++ case 0x3B: ++ /* VSELLEW */ ++ gen_qemu_vselxxwi(TCG_COND_LE, ra, rb, disp5, rc, 0); ++ break; ++ case 0x20: ++ /* VINSW */ ++ if (disp5 > 7) break; ++ tmp64 = tcg_temp_new(); ++ tmp32 = tcg_temp_new_i32(); ++ gen_helper_s_to_memory(tmp32, cpu_fr[ra]); ++ tcg_gen_extu_i32_i64(tmp64, tmp32); ++ tcg_gen_shli_i64(tmp64, tmp64, (disp5 % 2) * 32); ++ for (i = 0; i < 128; i += 32) { ++ tcg_gen_mov_i64(cpu_fr[rc + i], cpu_fr[rb + i]); ++ } ++ if (disp5 % 2) { ++ tcg_gen_andi_i64(cpu_fr[rc + (disp5 / 2) * 32], ++ cpu_fr[rc + (disp5 / 2) * 32], ++ 0xffffffffUL); ++ } else { ++ tcg_gen_andi_i64(cpu_fr[rc + (disp5 / 2) * 32], ++ cpu_fr[rc + (disp5 / 2) * 32], ++ 0xffffffff00000000UL); ++ } ++ tcg_gen_or_i64(cpu_fr[rc + (disp5 / 2) * 32], ++ cpu_fr[rc + (disp5 / 2) * 32], tmp64); ++ tcg_temp_free(tmp64); ++ tcg_temp_free_i32(tmp32); ++ break; ++ case 0x21: ++ /* VINSF */ ++ if (disp5 > 3) break; ++ tmp64 = tcg_temp_new(); ++ tcg_gen_mov_i64(tmp64, cpu_fr[ra]); ++ ++ for (i = 0; i < 128; i += 32) { ++ tcg_gen_mov_i64(cpu_fr[rc + i], cpu_fr[rb + i]); ++ } ++ tcg_gen_mov_i64(cpu_fr[rc + disp5 * 32], tmp64); ++ tcg_temp_free(tmp64); ++ break; ++ case 0x22: ++ /* VEXTW */ ++ if (disp5 > 7) break; ++ tmp64 = tcg_temp_new(); ++ tmp32 = tcg_temp_new_i32(); ++ tcg_gen_shri_i64(tmp64, cpu_fr[ra + (disp5 / 2) * 32], ++ (disp5 % 2) * 32); ++ tcg_gen_extrl_i64_i32(tmp32, tmp64); ++ gen_helper_memory_to_s(tmp64, tmp32); ++ tcg_gen_mov_i64(cpu_fr[rc], tmp64); ++ tcg_temp_free(tmp64); ++ tcg_temp_free_i32(tmp32); ++ break; ++ case 0x23: ++ /* VEXTF */ ++ if (disp5 > 3) break; ++ tcg_gen_mov_i64(cpu_fr[rc], cpu_fr[ra + disp5 * 32]); ++ break; ++ case 0x24: ++ /* VCPYW */ ++ tmp64 = tcg_temp_new(); ++ tmp64_0 = tcg_temp_new(); ++ /* FIXME: for debug ++ tcg_gen_movi_i64(tmp64, ra); ++ gen_helper_v_print(cpu_env, tmp64); ++ */ ++ tcg_gen_shri_i64(tmp64, cpu_fr[ra], 29); ++ tcg_gen_andi_i64(tmp64_0, tmp64, 0x3fffffffUL); ++ tcg_gen_shri_i64(tmp64, cpu_fr[ra], 62); ++ tcg_gen_shli_i64(tmp64, tmp64, 30); ++ tcg_gen_or_i64(tmp64_0, tmp64, tmp64_0); ++ tcg_gen_mov_i64(tmp64, tmp64_0); ++ tcg_gen_shli_i64(tmp64, tmp64, 32); ++ tcg_gen_or_i64(tmp64_0, tmp64_0, tmp64); ++ tcg_gen_mov_i64(cpu_fr[rc], tmp64_0); ++ tcg_gen_mov_i64(cpu_fr[rc + 32], cpu_fr[rc]); ++ tcg_gen_mov_i64(cpu_fr[rc + 64], cpu_fr[rc]); ++ tcg_gen_mov_i64(cpu_fr[rc + 96], cpu_fr[rc]); ++ /* FIXME: for debug ++ tcg_gen_movi_i64(tmp64, rb); ++ gen_helper_v_print(cpu_env, tmp64); ++ tcg_gen_movi_i64(tmp64, rc); ++ gen_helper_v_print(cpu_env, tmp64); ++ */ ++ tcg_temp_free(tmp64); ++ tcg_temp_free(tmp64_0); ++ break; ++ case 0x25: ++ /* VCPYF */ ++ for (i = 0; i < 128; i += 32) { ++ tcg_gen_mov_i64(cpu_fr[rc + i], cpu_fr[ra]); ++ } ++ break; ++ case 0x26: ++ /* VCONW */ ++ tmp64 = tcg_const_i64(ra << 8 | rb); ++ tmp64_0 = tcg_temp_new(); ++ vd = tcg_const_i64(rc); ++ tcg_gen_shri_i64(tmp64_0, cpu_fr[rd], 2); ++ tcg_gen_andi_i64(tmp64_0, tmp64_0, 0x7ul); ++ gen_helper_vconw(cpu_env, tmp64, vd, tmp64_0); ++ tcg_temp_free(tmp64_0); ++ tcg_temp_free(tmp64); ++ tcg_temp_free(vd); ++ break; ++ case 0x27: ++ /* VSHFW */ ++ tmp64 = tcg_const_i64(ra << 8 | rb); ++ vd = tcg_const_i64(rc); ++ gen_helper_vshfw(cpu_env, tmp64, vd, cpu_fr[rd]); ++ tcg_temp_free(tmp64); ++ tcg_temp_free(vd); ++ break; ++ case 0x28: ++ /* VCONS */ ++ tmp64 = tcg_const_i64(ra << 8 | rb); ++ tmp64_0 = tcg_temp_new(); ++ vd = tcg_const_i64(rc); ++ tcg_gen_shri_i64(tmp64_0, cpu_fr[rd], 2); ++ tcg_gen_andi_i64(tmp64_0, tmp64_0, 0x3ul); ++ gen_helper_vcond(cpu_env, tmp64, vd, tmp64_0); ++ tcg_temp_free(tmp64_0); ++ tcg_temp_free(tmp64); ++ tcg_temp_free(vd); ++ break; ++ case 0x29: ++ /* FIXME: VCOND maybe it's wrong in the instruction book ++ * that there are no temp. */ ++ tmp64 = tcg_const_i64(ra << 8 | rb); ++ tmp64_0 = tcg_temp_new(); ++ vd = tcg_const_i64(rc); ++ tcg_gen_shri_i64(tmp64_0, cpu_fr[rd], 3); ++ tcg_gen_andi_i64(tmp64_0, tmp64_0, 0x3ul); ++ gen_helper_vcond(cpu_env, tmp64, vd, tmp64_0); ++ tcg_temp_free(tmp64_0); ++ tcg_temp_free(tmp64); ++ tcg_temp_free(vd); ++ break; ++ default: ++ printf("ILLEGAL BELOW OPC[%x] func[%08x]\n", opc, fn6); ++ ret = gen_invalid(ctx); ++ break; ++ } ++ break; ++ case 0x1C: ++ switch (fn4) { ++ case 0x0: ++ /* VLDW_U */ ++ if (unlikely(ra == 31)) break; ++ gen_load_mem_simd(ctx, &gen_qemu_vldd, ra, rb, disp12, ++ ~0x1fUL); ++ break; ++ case 0x1: ++ /* VSTW_U */ ++ gen_store_mem_simd(ctx, &gen_qemu_vstd, ra, rb, disp12, ++ ~0x1fUL); ++ break; ++ case 0x2: ++ /* VLDS_U */ ++ if (unlikely(ra == 31)) break; ++ gen_load_mem_simd(ctx, &gen_qemu_vlds, ra, rb, disp12, ++ ~0xfUL); ++ break; ++ case 0x3: ++ /* VSTS_U */ ++ gen_store_mem_simd(ctx, &gen_qemu_vsts, ra, rb, disp12, ++ ~0xfUL); ++ break; ++ case 0x4: ++ /* VLDD_U */ ++ if (unlikely(ra == 31)) break; ++ gen_load_mem_simd(ctx, &gen_qemu_vldd, ra, rb, disp12, ++ ~0x1fUL); ++ break; ++ case 0x5: ++ /* VSTD_U */ ++ gen_store_mem_simd(ctx, &gen_qemu_vstd, ra, rb, disp12, ++ ~0x1fUL); ++ break; ++ case 0x8: ++ /* VSTW_UL */ ++ gen_store_mem_simd(ctx, &gen_qemu_vstw_ul, ra, rb, disp12, ++ 0); ++ break; ++ case 0x9: ++ /* VSTW_UH */ ++ gen_store_mem_simd(ctx, &gen_qemu_vstw_uh, ra, rb, disp12, ++ 0); ++ break; ++ case 0xa: ++ /* VSTS_UL */ ++ gen_store_mem_simd(ctx, &gen_qemu_vsts_ul, ra, rb, disp12, ++ 0); ++ break; ++ case 0xb: ++ /* VSTS_UH */ ++ gen_store_mem_simd(ctx, &gen_qemu_vsts_uh, ra, rb, disp12, ++ 0); ++ break; ++ case 0xc: ++ /* VSTD_UL */ ++ gen_store_mem_simd(ctx, &gen_qemu_vstd_ul, ra, rb, disp12, ++ 0); ++ break; ++ case 0xd: ++ /* VSTD_UH */ ++ gen_store_mem_simd(ctx, &gen_qemu_vstd_uh, ra, rb, disp12, ++ 0); ++ break; ++ case 0xe: ++ /* VLDD_NC */ ++ gen_load_mem_simd(ctx, &gen_qemu_vldd, ra, rb, disp12, 0); ++ break; ++ case 0xf: ++ /* VSTD_NC */ ++ gen_store_mem_simd(ctx, &gen_qemu_vstd, ra, rb, disp12, 0); ++ break; ++ default: ++ printf("ILLEGAL BELOW OPC[%x] func[%08x]\n", opc, fn4); ++ ret = gen_invalid(ctx); ++ break; ++ } ++ break; ++ case 0x20: ++ /* LDBU */ ++ gen_load_mem(ctx, &tcg_gen_qemu_ld8u, ra, rb, disp16, 0, 0); ++ break; ++ case 0x21: ++ /* LDHU */ ++ gen_load_mem(ctx, &tcg_gen_qemu_ld16u, ra, rb, disp16, 0, 0); ++ break; ++ case 0x22: ++ /* LDW */ ++ gen_load_mem(ctx, &tcg_gen_qemu_ld32s, ra, rb, disp16, 0, 0); ++ break; ++ case 0x23: ++ /* LDL */ ++ gen_load_mem(ctx, &tcg_gen_qemu_ld64, ra, rb, disp16, 0, 0); ++ break; ++ case 0x24: ++ /* LDL_U */ ++ gen_load_mem(ctx, &tcg_gen_qemu_ld64, ra, rb, disp16, 0, 1); ++ break; ++ case 0x25: ++ /* PRI_LD */ ++#ifndef CONFIG_USER_ONLY ++ if ((insn >> 12) & 1) { ++ gen_load_mem(ctx, &gen_qemu_pri_ldl, ra, rb, disp12, 0, 1); ++ } else { ++ gen_load_mem(ctx, &gen_qemu_pri_ldw, ra, rb, disp12, 0, 1); ++ } ++#endif ++ break; ++ case 0x26: ++ /* FLDS */ ++ gen_load_mem(ctx, &gen_qemu_flds, ra, rb, disp16, 1, 0); ++ break; ++ case 0x27: ++ /* FLDD */ ++ gen_load_mem(ctx, &tcg_gen_qemu_ld64, ra, rb, disp16, 1, 0); ++ break; ++ case 0x28: ++ /* STB */ ++ gen_store_mem(ctx, &tcg_gen_qemu_st8, ra, rb, disp16, 0, 0); ++ break; ++ case 0x29: ++ /* STH */ ++ gen_store_mem(ctx, &tcg_gen_qemu_st16, ra, rb, disp16, 0, 0); ++ break; ++ case 0x2a: ++ /* STW */ ++ gen_store_mem(ctx, &tcg_gen_qemu_st32, ra, rb, disp16, 0, 0); ++ break; ++ case 0x2b: ++ /* STL */ ++ gen_store_mem(ctx, &tcg_gen_qemu_st64, ra, rb, disp16, 0, 0); ++ break; ++ case 0x2c: ++ /* STL_U */ ++ gen_store_mem(ctx, &tcg_gen_qemu_st64, ra, rb, disp16, 0, 1); ++ break; ++ case 0x2d: ++ /* PRI_ST */ ++#ifndef CONFIG_USER_ONLY ++ if ((insn >> 12) & 1) { ++ gen_store_mem(ctx, &gen_qemu_pri_stl, ra, rb, disp12, 0, 1); ++ } else { ++ gen_store_mem(ctx, &gen_qemu_pri_stw, ra, rb, disp12, 0, 1); ++ } ++#endif ++ break; ++ case 0x2e: ++ /* FSTS */ ++ gen_store_mem(ctx, &gen_qemu_fsts, ra, rb, disp16, 1, 0); ++ break; ++ case 0x2f: ++ /* FSTD */ ++ gen_store_mem(ctx, &tcg_gen_qemu_st64, ra, rb, disp16, 1, 0); ++ break; ++ case 0x30: ++ /* BEQ */ ++ ret = gen_bcond(ctx, TCG_COND_EQ, ra, disp21, (uint64_t)-1); ++ break; ++ case 0x31: ++ /* BNE */ ++ ret = gen_bcond(ctx, TCG_COND_NE, ra, disp21, (uint64_t)-1); ++ break; ++ case 0x32: ++ /* BLT */ ++ ret = gen_bcond(ctx, TCG_COND_LT, ra, disp21, (uint64_t)-1); ++ break; ++ case 0x33: ++ /* BLE */ ++ ret = gen_bcond(ctx, TCG_COND_LE, ra, disp21, (uint64_t)-1); ++ break; ++ case 0x34: ++ /* BGT */ ++ ret = gen_bcond(ctx, TCG_COND_GT, ra, disp21, (uint64_t)-1); ++ break; ++ case 0x35: ++ /* BGE */ ++ ret = gen_bcond(ctx, TCG_COND_GE, ra, disp21, (uint64_t)-1); ++ break; ++ case 0x36: ++ /* BLBC */ ++ ret = gen_bcond(ctx, TCG_COND_EQ, ra, disp21, 1); ++ break; ++ case 0x37: ++ /* BLBS */ ++ ret = gen_bcond(ctx, TCG_COND_NE, ra, disp21, 1); ++ break; ++ case 0x38: ++ /* FBEQ */ ++ ret = gen_fbcond(ctx, TCG_COND_EQ, ra, disp21); ++ break; ++ case 0x39: ++ /* FBNE */ ++ ret = gen_fbcond(ctx, TCG_COND_NE, ra, disp21); ++ break; ++ case 0x3a: ++ /* FBLT */ ++ ret = gen_fbcond(ctx, TCG_COND_LT, ra, disp21); ++ break; ++ case 0x3b: ++ /* FBLE */ ++ ret = gen_fbcond(ctx, TCG_COND_LE, ra, disp21); ++ break; ++ case 0x3c: ++ /* FBGT */ ++ ret = gen_fbcond(ctx, TCG_COND_GT, ra, disp21); ++ break; ++ case 0x3d: ++ /* FBGE */ ++ ret = gen_fbcond(ctx, TCG_COND_GE, ra, disp21); ++ break; ++ case 0x3f: ++ /* LDIH */ ++ disp16 = ((uint32_t)disp16) << 16; ++ if (ra == 31) break; ++ va = load_gir(ctx, ra); ++ if (rb == 31) { ++ tcg_gen_movi_i64(va, disp16); ++ } else { ++ tcg_gen_addi_i64(va, load_gir(ctx, rb), (int64_t)disp16); ++ } ++ break; ++ case 0x3e: ++ /* LDI */ ++ if (ra == 31) break; ++ va = load_gir(ctx, ra); ++ if (rb == 31) { ++ tcg_gen_movi_i64(va, disp16); ++ } else { ++ tcg_gen_addi_i64(va, load_gir(ctx, rb), (int64_t)disp16); ++ } ++ break; ++ do_invalid: ++ default: ++ printf("ILLEGAL BELOW OPC[%x] insn[%08x]\n", opc, insn); ++ ret = gen_invalid(ctx); ++ } ++ return ret; ++} ++static void sw64_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cpu) ++{ ++ DisasContext* ctx = container_of(dcbase, DisasContext, base); ++ CPUSW64State* env = cpu->env_ptr; /*init by instance_initfn*/ ++ ++ ctx->tbflags = ctx->base.tb->flags; ++ ctx->mem_idx = cpu_mmu_index(env, false); ++#ifdef CONFIG_USER_ONLY ++ ctx->ir = cpu_std_ir; ++#else ++ ctx->ir = (ctx->tbflags & ENV_FLAG_HM_MODE ? cpu_hm_ir : cpu_std_ir); ++#endif ++ ctx->zero = NULL; ++} ++ ++static void sw64_tr_tb_start(DisasContextBase *db, CPUState *cpu) ++{ ++} ++ ++static void sw64_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu) ++{ ++ tcg_gen_insn_start(dcbase->pc_next); ++} ++ ++static void sw64_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu) ++{ ++ DisasContext *ctx = container_of(dcbase, DisasContext, base); ++ CPUSW64State *env = cpu->env_ptr; ++ uint32_t insn; ++ ++ insn = cpu_ldl_code(env, ctx->base.pc_next & (~3UL)); ++ ctx->env = env; ++ ctx->base.pc_next += 4; ++ ctx->base.is_jmp = ctx->translate_one(dcbase, insn, cpu); ++ ++ free_context_temps(ctx); ++ translator_loop_temp_check(&ctx->base); ++} ++ ++/* FIXME:Linhainan */ ++static void sw64_tr_tb_stop(DisasContextBase* dcbase, CPUState* cpu) { ++ DisasContext* ctx = container_of(dcbase, DisasContext, base); ++ ++ switch (ctx->base.is_jmp) { ++ case DISAS_NORETURN: ++ break; ++ case DISAS_TOO_MANY: ++ if (use_goto_tb(ctx, ctx->base.pc_next)) { ++ tcg_gen_goto_tb(0); ++ tcg_gen_movi_i64(cpu_pc, ctx->base.pc_next); ++ tcg_gen_exit_tb(ctx->base.tb, 0); ++ } ++ /* FALLTHRU */ ++ case DISAS_PC_STALE: ++ tcg_gen_movi_i64(cpu_pc, ctx->base.pc_next); ++ /* FALLTHRU */ ++ case DISAS_PC_UPDATED: ++ if (!use_exit_tb(ctx)) { ++ tcg_gen_lookup_and_goto_ptr(); ++ break; ++ } ++ /* FALLTHRU */ ++ case DISAS_PC_UPDATED_NOCHAIN: ++ if (ctx->base.singlestep_enabled) { ++ /* FIXME: for gdb*/ ++ cpu_loop_exit(cpu); ++ } else { ++ tcg_gen_exit_tb(NULL, 0); ++ } ++ break; ++ default: ++ g_assert_not_reached(); ++ } ++} ++ ++static void sw64_tr_disas_log(const DisasContextBase* dcbase, CPUState* cpu) { ++ SW64CPU* sc = SW64_CPU(cpu); ++ qemu_log("IN(%d): %s\n", sc->cid, ++ lookup_symbol(dcbase->pc_first)); ++ log_target_disas(cpu, dcbase->pc_first & (~0x3UL), dcbase->tb->size); ++} ++ ++static void init_transops(CPUState *cpu, DisasContext *dc) ++{ ++ dc->translate_one = translate_one; ++} ++ ++void restore_state_to_opc(CPUSW64State* env, TranslationBlock* tb, ++ target_ulong* data) { ++ env->pc = data[0]; ++} ++ ++static const TranslatorOps sw64_trans_ops = { ++ .init_disas_context = sw64_tr_init_disas_context, ++ .tb_start = sw64_tr_tb_start, ++ .insn_start = sw64_tr_insn_start, ++ .translate_insn = sw64_tr_translate_insn, ++ .tb_stop = sw64_tr_tb_stop, ++ .disas_log = sw64_tr_disas_log, ++}; ++ ++void gen_intermediate_code(CPUState* cpu, TranslationBlock* tb, int max_insns) ++{ ++ DisasContext dc; ++ init_transops(cpu, &dc); ++ translator_loop(&sw64_trans_ops, &dc.base, cpu, tb, max_insns); ++} +diff --git a/target/sw64/translate.h b/target/sw64/translate.h +new file mode 100644 +index 0000000000..e93df0815e +--- /dev/null ++++ b/target/sw64/translate.h +@@ -0,0 +1,60 @@ ++#ifndef SW64_TRANSLATE_H ++#define SW64_TRANSLATE_H ++#include "qemu/osdep.h" ++#include "cpu.h" ++#include "sysemu/cpus.h" ++#include "disas/disas.h" ++#include "qemu/host-utils.h" ++#include "exec/exec-all.h" ++#include "exec/cpu_ldst.h" ++#include "tcg/tcg-op.h" ++#include "exec/helper-proto.h" ++#include "exec/helper-gen.h" ++#include "trace-tcg.h" ++#include "exec/translator.h" ++#include "exec/log.h" ++ ++#define DISAS_PC_UPDATED_NOCHAIN DISAS_TARGET_0 ++#define DISAS_PC_UPDATED DISAS_TARGET_1 ++#define DISAS_PC_STALE DISAS_TARGET_2 ++#define DISAS_PC_UPDATED_T DISAS_TOO_MANY ++ ++typedef struct DisasContext DisasContext; ++struct DisasContext { ++ DisasContextBase base; ++ ++ uint32_t tbflags; ++ ++ /* The set of registers active in the current context. */ ++ TCGv *ir; ++ ++ /* Accel: Temporaries for $31 and $f31 as source and destination. */ ++ TCGv zero; ++ int mem_idx; ++ CPUSW64State *env; ++ DisasJumpType (*translate_one)(DisasContextBase *dcbase, uint32_t insn, ++ CPUState *cpu); ++}; ++ ++extern TCGv cpu_pc; ++extern TCGv cpu_std_ir[31]; ++extern TCGv cpu_fr[128]; ++extern TCGv cpu_lock_addr; ++extern TCGv cpu_lock_flag; ++extern TCGv cpu_lock_success; ++#ifdef SW64_FIXLOCK ++extern TCGv cpu_lock_value; ++#endif ++#ifndef CONFIG_USER_ONLY ++extern TCGv cpu_hm_ir[31]; ++#endif ++ ++DisasJumpType translate_one(DisasContextBase *dcbase, uint32_t insn, ++ CPUState *cpu); ++DisasJumpType th1_translate_one(DisasContextBase *dcbase, uint32_t insn, ++ CPUState *cpu); ++bool use_exit_tb(DisasContext *ctx); ++bool use_goto_tb(DisasContext *ctx, uint64_t dest); ++void insn_profile(DisasContext *ctx, uint32_t insn); ++extern void gen_fold_mzero(TCGCond cond, TCGv dest, TCGv src); ++#endif +diff --git a/tcg/sw64/tcg-target-con-set.h b/tcg/sw64/tcg-target-con-set.h +new file mode 100755 +index 0000000000..71fdfdcbef +--- /dev/null ++++ b/tcg/sw64/tcg-target-con-set.h +@@ -0,0 +1,39 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Define SW_64 target-specific constraint sets. ++ * Copyright (c) 2021 Linaro ++ */ ++ ++/* ++ * C_On_Im(...) defines a constraint set with outputs and inputs. ++ * Each operand should be a sequence of constraint letters as defined by ++ * tcg-target-con-str.h; the constraint combination is inclusive or. ++ */ ++C_O0_I1(r) ++C_O0_I2(lZ, l) ++C_O0_I2(r, rA) ++C_O0_I2(rZ, r) ++C_O0_I2(w, r) ++C_O1_I1(r, l) ++C_O1_I1(r, r) ++C_O1_I1(w, r) ++C_O1_I1(w, w) ++C_O1_I1(w, wr) ++C_O1_I2(r, 0, rZ) ++C_O1_I2(r, r, r) ++C_O1_I2(r, r, rA) ++C_O1_I2(r, r, rAL) ++C_O1_I2(r, r, ri) ++C_O1_I2(r, r, rL) ++C_O1_I2(r, rZ, rZ) ++C_O1_I2(w, 0, w) ++C_O1_I2(w, w, w) ++C_O1_I2(w, w, wN) ++C_O1_I2(w, w, wO) ++C_O1_I2(w, w, wZ) ++C_O1_I3(w, w, w, w) ++C_O1_I4(r, r, rA, rZ, rZ) ++C_O2_I4(r, r, rZ, rZ, rA, rMZ) ++C_O1_I4(r, r, rU, rZ, rZ) ++C_O0_I2(r, rU) ++C_O1_I2(r, r, rU) +diff --git a/tcg/sw64/tcg-target-con-str.h b/tcg/sw64/tcg-target-con-str.h +new file mode 100755 +index 0000000000..47edb3837b +--- /dev/null ++++ b/tcg/sw64/tcg-target-con-str.h +@@ -0,0 +1,28 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Define sw_64 target-specific operand constraints. ++ * Copyright (c) 2021 Linaro ++ */ ++ ++/* ++ * Define constraint letters for register sets: ++ * REGS(letter, register_mask) ++ */ ++REGS('r', ALL_GENERAL_REGS) ++REGS('l', ALL_QLDST_REGS) ++REGS('w', ALL_VECTOR_REGS) ++ ++/* ++ * Define constraint letters for constants: ++ * CONST(letter, TCG_CT_CONST_* bit set) ++ */ ++ ++CONST('Z', TCG_CT_CONST_ZERO) ++CONST('A', TCG_CT_CONST_LONG) ++CONST('M', TCG_CT_CONST_MONE) ++CONST('O', TCG_CT_CONST_ORRI) ++CONST('W', TCG_CT_CONST_WORD) ++CONST('L', TCG_CT_CONST_LONG) ++CONST('U', TCG_CT_CONST_U8) ++CONST('S', TCG_CT_CONST_S8) ++ +diff --git a/tcg/sw64/tcg-target.c.inc b/tcg/sw64/tcg-target.c.inc +new file mode 100755 +index 0000000000..982f159e23 +--- /dev/null ++++ b/tcg/sw64/tcg-target.c.inc +@@ -0,0 +1,2109 @@ ++/* ++ * Initial TCG Implementation for sw_64 ++ * ++ */ ++ ++#include "../tcg-pool.c.inc" ++#include "qemu/bitops.h" ++ ++/* We're going to re-use TCGType in setting of the SF bit, which controls ++ the size of the operation performed. If we know the values match, it ++ makes things much cleaner. */ ++QEMU_BUILD_BUG_ON(TCG_TYPE_I32 != 0 || TCG_TYPE_I64 != 1); ++static const tcg_insn_unit *tb_ret_addr; ++ ++#ifdef CONFIG_DEBUG_TCG ++static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = { ++ "X0", "X1", "X2", "X3", "X4", "X5", "X6", "X7", ++ "X8", "X9", "X10", "X11", "X12", "X13", "X14", "fp", ++ "X16", "X17", "X18", "X19", "X20", "X21", "X22", "X23", ++ "X24", "X25", "X26", "X27", "X28", "X29", "Xsp", "X31", ++ ++ "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", "f31", ++}; ++#endif /* CONFIG_DEBUG_TCG */ ++ ++static const int tcg_target_reg_alloc_order[] = { ++ /* TCG_REG_X9 qemu saved for AREG0*/ ++ TCG_REG_X10, TCG_REG_X11, TCG_REG_X12, TCG_REG_X13, TCG_REG_X14, ++ ++ TCG_REG_X0, TCG_REG_X1, TCG_REG_X2, TCG_REG_X3, TCG_REG_X4, ++ TCG_REG_X5, TCG_REG_X6, TCG_REG_X7, TCG_REG_X8, ++ ++ TCG_REG_X22, TCG_REG_X23, TCG_REG_X24, /*TCG_REG_X25, TCG_REG_X26, TCG_REG_X27, */ ++ ++ /* TCG_REG_SP=TCG_REG_X15 saved for system*/ ++ TCG_REG_X16, TCG_REG_X17, TCG_REG_X18, TCG_REG_X19, TCG_REG_X20, TCG_REG_X21, TCG_REG_X28, /* TCG_REG_X29, TCG_REG_X30, TCG_REG_X31 */ ++ ++ /* TCG_REG_TMP=TCG_REG_X27 reserved as temporary register */ ++ /* TCG_REG_TMP2=TCG_REG_X25 reserved as temporary register */ ++ /* TCG_REG_RA=TCG_REG_X26 reserved as temporary */ ++ /* TCG_REG_GP=TCG_REG_X29 gp saved for system*/ ++ /* TCG_REG_SP=TCG_REG_X30 sp saved for system*/ ++ /* TCG_REG_ZERO=TCG_REG_X31 zero saved for system*/ ++ ++ TCG_REG_F2, TCG_REG_F3, TCG_REG_F4, TCG_REG_F5, TCG_REG_F6, TCG_REG_F7, TCG_REG_F8, TCG_REG_F9, /* f2-f9 saved registers */ ++ /* TCG_VEC_TMP=TCG_REG_F10, TCG_VEC_TMP2=TCG_REG_F11, are saved as temporary */ ++ TCG_REG_F12, TCG_REG_F13, TCG_REG_F14, TCG_REG_F15, /* f10-f15 temporary registers */ ++ ++ TCG_REG_F22, TCG_REG_F23, TCG_REG_F24, TCG_REG_F25, TCG_REG_F26, TCG_REG_F27, TCG_REG_F28, TCG_REG_F29, TCG_REG_F30, /* f22-f30 temporary registers */ ++ /* TCG_REG_F31, zero saved for system */ ++ ++ TCG_REG_F16, TCG_REG_F17, TCG_REG_F18, TCG_REG_F19, TCG_REG_F20, TCG_REG_F21, /* input args */ ++ ++ TCG_REG_F0, TCG_REG_F1, /*output args */ ++}; ++ ++static const int tcg_target_call_iarg_regs[6] = { ++ TCG_REG_X16, TCG_REG_X17, TCG_REG_X18, TCG_REG_X19, TCG_REG_X20, TCG_REG_X21, ++}; ++static const int tcg_target_call_oarg_regs[1] = { ++ TCG_REG_X0, ++}; ++ ++#define TCG_REG_TMP TCG_REG_X27 ++#define TCG_REG_TMP2 TCG_REG_X25 ++#define TCG_FLOAT_TMP TCG_REG_F10 ++#define TCG_FLOAT_TMP2 TCG_REG_F11 ++ ++#define ALL_GENERAL_REGS 0xffffffffu ++#define ALL_QLDST_REGS ALL_GENERAL_REGS ++#define PUSH_SIZE ((15-9+1+1) * 8) ++#define FRAME_SIZE \ ++ ((PUSH_SIZE \ ++ + TCG_STATIC_CALL_ARGS_SIZE \ ++ + CPU_TEMP_BUF_NLONGS * sizeof(long) \ ++ + TCG_TARGET_STACK_ALIGN - 1) \ ++ & ~(TCG_TARGET_STACK_ALIGN - 1)) ++ ++/* We encode the format of the insn into the beginning of the name, so that ++ we can have the preprocessor help "typecheck" the insn vs the output ++ function. We don't have nice names for the formats, so we use the section ++ number of the architecture reference manual in which the instruction ++ group is described. */ ++#define OPC_OP(x) ((x & 0x3f) << 26) ++#define OPC_FUNC(x) ((x & 0xff) << 5) ++#define OPC_FUNC_COMPLEX(x) ((x & 0xff) << 10) ++typedef enum { ++ OPC_NOP =0X43ff075f, ++ OPC_SYS_CALL =OPC_OP(0x00), ++ OPC_CALL =OPC_OP(0x01), ++ OPC_RET =OPC_OP(0x02), ++ OPC_JMP =OPC_OP(0x03), ++ OPC_BR =OPC_OP(0x04), ++ OPC_BSR =OPC_OP(0x05), ++ OPC_PRI_RET =OPC_OP(0x07), ++ OPC_LDWE =OPC_OP(0x09), ++ OPC_LDSE =OPC_OP(0x0A), ++ OPC_LDDE =OPC_OP(0x0B), ++ OPC_VLDS =OPC_OP(0x0C), ++ OPC_VLDD =OPC_OP(0x0D), ++ OPC_VSTS =OPC_OP(0x0E), ++ OPC_VSTD =OPC_OP(0x0F), ++ ++ OPC_LDBU =OPC_OP(0x20), ++ OPC_LDHU =OPC_OP(0x21), ++ OPC_LDW =OPC_OP(0x22), ++ OPC_LDL =OPC_OP(0x23), ++ OPC_LDL_U =OPC_OP(0x24), ++ OPC_FLDS =OPC_OP(0X26), ++ OPC_PRI_LD =OPC_OP(0x25), ++ OPC_FLDD =OPC_OP(0X27), ++ OPC_STB =OPC_OP(0X28), ++ OPC_STH =OPC_OP(0x29), ++ OPC_STW =OPC_OP(0x2a), ++ OPC_STL =OPC_OP(0x2B), ++ OPC_STL_U =OPC_OP(0x2C), ++ OPC_PRI_ST =OPC_OP(0x2D), ++ OPC_FSTS =OPC_OP(0x2E), ++ OPC_FSTD =OPC_OP(0x2F), ++ ++ OPC_BEQ =OPC_OP(0x30), ++ OPC_BNE =OPC_OP(0x31), ++ OPC_BLT =OPC_OP(0x32), ++ OPC_BLE =OPC_OP(0x33), ++ OPC_BGT =OPC_OP(0x34), ++ OPC_BGE =OPC_OP(0x35), ++ OPC_BLBC =OPC_OP(0x36), ++ OPC_BLBS =OPC_OP(0x37), ++ ++ OPC_FBEQ =OPC_OP(0x38), ++ OPC_FBNE =OPC_OP(0x39), ++ OPC_FBLT =OPC_OP(0x3A), ++ OPC_FBLE =OPC_OP(0x3B), ++ OPC_FBGT =OPC_OP(0x3C), ++ OPC_FBGE =OPC_OP(0x3D), ++ OPC_LDI =OPC_OP(0x3E), ++ OPC_LDIH =OPC_OP(0x3F), ++ ++ OPC_ADDW =(OPC_OP(0x10) | OPC_FUNC(0x0)), ++ OPC_ADDW_I =(OPC_OP(0x12) | OPC_FUNC(0x0)), ++ OPC_SUBW =(OPC_OP(0x10) | OPC_FUNC(0x1)), ++ OPC_SUBW_I =(OPC_OP(0x12) | OPC_FUNC(0x1)), ++ OPC_S4ADDW =(OPC_OP(0x10) | OPC_FUNC(0x02)), ++ OPC_S4ADDW_I =(OPC_OP(0x12) | OPC_FUNC(0x02)), ++ OPC_S4SUBW =(OPC_OP(0x10) | OPC_FUNC(0x03)), ++ OPC_S4SUBW_I =(OPC_OP(0x12) | OPC_FUNC(0x03)), ++ ++ OPC_S8ADDW =(OPC_OP(0x10) | OPC_FUNC(0x04)), ++ OPC_S8ADDW_I =(OPC_OP(0x12) | OPC_FUNC(0x04)), ++ OPC_S8SUBW =(OPC_OP(0x10) | OPC_FUNC(0x05)), ++ OPC_S8SUBW_I =(OPC_OP(0x12) | OPC_FUNC(0x05)), ++ ++ OPC_ADDL =(OPC_OP(0x10) | OPC_FUNC(0x8)), ++ OPC_ADDL_I =(OPC_OP(0x12) | OPC_FUNC(0x8)), ++ OPC_SUBL =(OPC_OP(0x10) | OPC_FUNC(0x9)), ++ OPC_SUBL_I =(OPC_OP(0x12) | OPC_FUNC(0x9)), ++ ++ OPC_S4ADDL =(OPC_OP(0x10) | OPC_FUNC(0xA)), ++ OPC_S4ADDL_I =(OPC_OP(0x12) | OPC_FUNC(0xA)), ++ OPC_S4SUBL =(OPC_OP(0x10) | OPC_FUNC(0xB)), ++ OPC_S4SUBL_I =(OPC_OP(0x12) | OPC_FUNC(0xB)), ++ ++ OPC_S8ADDL =(OPC_OP(0x10) | OPC_FUNC(0xC)), ++ OPC_S8ADDL_I =(OPC_OP(0x12) | OPC_FUNC(0xC)), ++ OPC_S8SUBL =(OPC_OP(0x10) | OPC_FUNC(0xD)), ++ OPC_S8SUBL_I =(OPC_OP(0x12) | OPC_FUNC(0xD)), ++ ++ OPC_MULW =(OPC_OP(0x10) | OPC_FUNC(0x10)), ++ OPC_MULW_I =(OPC_OP(0x12) | OPC_FUNC(0x10)), ++ OPC_MULL =(OPC_OP(0x10) | OPC_FUNC(0x18)), ++ OPC_MULL_I =(OPC_OP(0x12) | OPC_FUNC(0x18)), ++ ++ OPC_UMULH =(OPC_OP(0x10) | OPC_FUNC(0x19)), ++ OPC_UMULH_I =(OPC_OP(0x12) | OPC_FUNC(0x19)), ++ ++ OPC_CTPOP =(OPC_OP(0x10) | OPC_FUNC(0x58)), ++ OPC_CTLZ =(OPC_OP(0x10) | OPC_FUNC(0x59)), ++ OPC_CTTZ =(OPC_OP(0x10) | OPC_FUNC(0x5A)), ++ ++ OPC_ZAP =(OPC_OP(0x10) | OPC_FUNC(0x68)), ++ OPC_ZAP_I =(OPC_OP(0x12) | OPC_FUNC(0x68)), ++ OPC_ZAPNOT =(OPC_OP(0x10) | OPC_FUNC(0x69)), ++ OPC_ZAPNOT_I =(OPC_OP(0x12) | OPC_FUNC(0x69)), ++ ++ OPC_SEXTB =(OPC_OP(0x10) | OPC_FUNC(0x6A)), ++ OPC_SEXTB_I =(OPC_OP(0x12) | OPC_FUNC(0x6A)), ++ OPC_SEXTH =(OPC_OP(0x10) | OPC_FUNC(0x6B)), ++ OPC_SEXTH_I =(OPC_OP(0x12) | OPC_FUNC(0x6B)), ++ ++ OPC_CMPEQ =(OPC_OP(0x10) | OPC_FUNC(0x28)), ++ OPC_CMPEQ_I =(OPC_OP(0x12) | OPC_FUNC(0x28)), ++ ++ OPC_CMPLT =(OPC_OP(0x10) | OPC_FUNC(0x29)), ++ OPC_CMPLT_I =(OPC_OP(0x12) | OPC_FUNC(0x29)), ++ OPC_CMPLE =(OPC_OP(0x10) | OPC_FUNC(0x2A)), ++ OPC_CMPLE_I =(OPC_OP(0x12) | OPC_FUNC(0x2A)), ++ ++ OPC_CMPULT =(OPC_OP(0x10) | OPC_FUNC(0x2B)), ++ OPC_CMPULT_I =(OPC_OP(0x12) | OPC_FUNC(0x2B)), ++ OPC_CMPULE =(OPC_OP(0x10) | OPC_FUNC(0x2C)), ++ OPC_CMPULE_I =(OPC_OP(0x12) | OPC_FUNC(0x2C)), ++ ++ OPC_AND =(OPC_OP(0x10) | OPC_FUNC(0x38)), ++ OPC_BIC =(OPC_OP(0x10) | OPC_FUNC(0x39)), ++ OPC_BIS =(OPC_OP(0x10) | OPC_FUNC(0x3A)), ++ OPC_ORNOT =(OPC_OP(0x10) | OPC_FUNC(0x3B)), ++ OPC_XOR =(OPC_OP(0x10) | OPC_FUNC(0x3C)), ++ OPC_EQV =(OPC_OP(0x10) | OPC_FUNC(0x3D)), ++ ++ OPC_AND_I =(OPC_OP(0x12) | OPC_FUNC(0x38)), ++ OPC_BIC_I =(OPC_OP(0x12) | OPC_FUNC(0x39)), ++ OPC_BIS_I =(OPC_OP(0x12) | OPC_FUNC(0x3A)), ++ OPC_ORNOT_I =(OPC_OP(0x12) | OPC_FUNC(0x3B)), ++ OPC_XOR_I =(OPC_OP(0x12) | OPC_FUNC(0x3C)), ++ OPC_EQV_I =(OPC_OP(0x12) | OPC_FUNC(0x3D)), ++ ++ OPC_SLL =(OPC_OP(0x10) | OPC_FUNC(0x48)), ++ OPC_SRL =(OPC_OP(0x10) | OPC_FUNC(0x49)), ++ OPC_SRA =(OPC_OP(0x10) | OPC_FUNC(0x4A)), ++ OPC_SLL_I =(OPC_OP(0x12) | OPC_FUNC(0x48)), ++ OPC_SRL_I =(OPC_OP(0x12) | OPC_FUNC(0x49)), ++ OPC_SRA_I =(OPC_OP(0x12) | OPC_FUNC(0x4A)), ++ ++ OPC_SELEQ =(OPC_OP(0x11) | OPC_FUNC_COMPLEX(0x00)), ++ OPC_SELGE =(OPC_OP(0x11) | OPC_FUNC_COMPLEX(0x01)), ++ OPC_SELGT =(OPC_OP(0x11) | OPC_FUNC_COMPLEX(0x02)), ++ OPC_SELLE =(OPC_OP(0x11) | OPC_FUNC_COMPLEX(0x03)), ++ OPC_SELLT =(OPC_OP(0x11) | OPC_FUNC_COMPLEX(0x04)), ++ OPC_SELNE =(OPC_OP(0x11) | OPC_FUNC_COMPLEX(0x05)), ++ OPC_SELLBC =(OPC_OP(0x11) | OPC_FUNC_COMPLEX(0x06)), ++ OPC_SELLBS =(OPC_OP(0x11) | OPC_FUNC_COMPLEX(0x07)), ++ OPC_SELEQ_I =(OPC_OP(0x13) | OPC_FUNC_COMPLEX(0x00)), ++ OPC_SELGE_I =(OPC_OP(0x13) | OPC_FUNC_COMPLEX(0x01)), ++ OPC_SELGT_I =(OPC_OP(0x13) | OPC_FUNC_COMPLEX(0x02)), ++ OPC_SELLE_I =(OPC_OP(0x13) | OPC_FUNC_COMPLEX(0x03)), ++ OPC_SELLT_I =(OPC_OP(0x13) | OPC_FUNC_COMPLEX(0x04)), ++ OPC_SELNE_I =(OPC_OP(0x13) | OPC_FUNC_COMPLEX(0x05)), ++ OPC_SELLBC_I =(OPC_OP(0x13) | OPC_FUNC_COMPLEX(0x06)), ++ OPC_SELLBS_I =(OPC_OP(0x13) | OPC_FUNC_COMPLEX(0x07)), ++ ++ OPC_INS0B =(OPC_OP(0x10) | OPC_FUNC(0x40)), ++ OPC_INS1B =(OPC_OP(0x10) | OPC_FUNC(0x41)), ++ OPC_INS2B =(OPC_OP(0x10) | OPC_FUNC(0x42)), ++ OPC_INS3B =(OPC_OP(0x10) | OPC_FUNC(0x43)), ++ OPC_INS4B =(OPC_OP(0x10) | OPC_FUNC(0x44)), ++ OPC_INS5B =(OPC_OP(0x10) | OPC_FUNC(0x45)), ++ OPC_INS6B =(OPC_OP(0x10) | OPC_FUNC(0x46)), ++ OPC_INS7B =(OPC_OP(0x10) | OPC_FUNC(0x47)), ++ OPC_INS0B_I =(OPC_OP(0x12) | OPC_FUNC(0x40)), ++ OPC_INS1B_I =(OPC_OP(0x12) | OPC_FUNC(0x41)), ++ OPC_INS2B_I =(OPC_OP(0x12) | OPC_FUNC(0x42)), ++ OPC_INS3B_I =(OPC_OP(0x12) | OPC_FUNC(0x43)), ++ OPC_INS4B_I =(OPC_OP(0x12) | OPC_FUNC(0x44)), ++ OPC_INS5B_I =(OPC_OP(0x12) | OPC_FUNC(0x45)), ++ OPC_INS6B_I =(OPC_OP(0x12) | OPC_FUNC(0x46)), ++ OPC_INS7B_I =(OPC_OP(0x12) | OPC_FUNC(0x47)), ++ ++ OPC_EXT0B =(OPC_OP(0x10) | OPC_FUNC(0x50)), ++ OPC_EXT1B =(OPC_OP(0x10) | OPC_FUNC(0x51)), ++ OPC_EXT2B =(OPC_OP(0x10) | OPC_FUNC(0x52)), ++ OPC_EXT3B =(OPC_OP(0x10) | OPC_FUNC(0x53)), ++ OPC_EXT4B =(OPC_OP(0x10) | OPC_FUNC(0x54)), ++ OPC_EXT5B =(OPC_OP(0x10) | OPC_FUNC(0x55)), ++ OPC_EXT6B =(OPC_OP(0x10) | OPC_FUNC(0x56)), ++ OPC_EXT7B =(OPC_OP(0x10) | OPC_FUNC(0x57)), ++ OPC_EXT0B_I =(OPC_OP(0x12) | OPC_FUNC(0x50)), ++ OPC_EXT1B_I =(OPC_OP(0x12) | OPC_FUNC(0x51)), ++ OPC_EXT2B_I =(OPC_OP(0x12) | OPC_FUNC(0x52)), ++ OPC_EXT3B_I =(OPC_OP(0x12) | OPC_FUNC(0x53)), ++ OPC_EXT4B_I =(OPC_OP(0x12) | OPC_FUNC(0x54)), ++ OPC_EXT5B_I =(OPC_OP(0x12) | OPC_FUNC(0x55)), ++ OPC_EXT6B_I =(OPC_OP(0x12) | OPC_FUNC(0x56)), ++ OPC_EXT7B_I =(OPC_OP(0x12) | OPC_FUNC(0x57)), ++ ++ OPC_MASK0B =(OPC_OP(0x10) | OPC_FUNC(0x60)), ++ OPC_MASK1B =(OPC_OP(0x10) | OPC_FUNC(0x61)), ++ OPC_MASK2B =(OPC_OP(0x10) | OPC_FUNC(0x62)), ++ OPC_MASK3B =(OPC_OP(0x10) | OPC_FUNC(0x63)), ++ OPC_MASK4B =(OPC_OP(0x10) | OPC_FUNC(0x64)), ++ OPC_MASK5B =(OPC_OP(0x10) | OPC_FUNC(0x65)), ++ OPC_MASK6B =(OPC_OP(0x10) | OPC_FUNC(0x66)), ++ OPC_MASK7B =(OPC_OP(0x10) | OPC_FUNC(0x67)), ++ OPC_MASK0B_I =(OPC_OP(0x12) | OPC_FUNC(0x60)), ++ OPC_MASK1B_I =(OPC_OP(0x12) | OPC_FUNC(0x61)), ++ OPC_MASK2B_I =(OPC_OP(0x12) | OPC_FUNC(0x62)), ++ OPC_MASK3B_I =(OPC_OP(0x12) | OPC_FUNC(0x63)), ++ OPC_MASK4B_I =(OPC_OP(0x12) | OPC_FUNC(0x64)), ++ OPC_MASK5B_I =(OPC_OP(0x12) | OPC_FUNC(0x65)), ++ OPC_MASK6B_I =(OPC_OP(0x12) | OPC_FUNC(0x66)), ++ OPC_MASK7B_I =(OPC_OP(0x12) | OPC_FUNC(0x67)), ++ ++ OPC_CNPGEB =(OPC_OP(0x10) | OPC_FUNC(0x6C)), ++ OPC_CNPGEB_I =(OPC_OP(0x12) | OPC_FUNC(0x6C)), ++ ++ OPC_MEMB =(OPC_OP(0x06) | OPC_FUNC(0x0)), ++ OPC_RTC =(OPC_OP(0x06) | OPC_FUNC(0x20)), ++ ++ /*float insn*/ ++ OPC_RFPCR = (OPC_OP(0x18) | OPC_FUNC(0x50)), ++ OPC_WFPCR = (OPC_OP(0x18) | OPC_FUNC(0x51)), ++ OPC_SETFPEC0 = (OPC_OP(0x18) | OPC_FUNC(0x54)), ++ OPC_SETFPEC1 = (OPC_OP(0x18) | OPC_FUNC(0x55)), ++ OPC_SETFPEC2 = (OPC_OP(0x18) | OPC_FUNC(0x56)), ++ OPC_SETFPEC3 = (OPC_OP(0x18) | OPC_FUNC(0x57)), ++ ++ ++ OPC_IFMOVS = (OPC_OP(0x18) | OPC_FUNC(0x40)), ++ OPC_IFMOVD = (OPC_OP(0x18) | OPC_FUNC(0x41)), ++ OPC_FIMOVS = (OPC_OP(0x10) | OPC_FUNC(0x70)), ++ OPC_FIMOVD = (OPC_OP(0x10) | OPC_FUNC(0x78)), ++ ++ /*translate S--D*/ ++ /*translate S/D--Long*/ ++ OPC_FCVTSD = (OPC_OP(0x18) | OPC_FUNC(0x20)), ++ OPC_FCVTDS = (OPC_OP(0x18) | OPC_FUNC(0x21)), ++ OPC_FCVTDL_G = (OPC_OP(0x18) | OPC_FUNC(0x22)), ++ OPC_FCVTDL_P = (OPC_OP(0x18) | OPC_FUNC(0x23)), ++ OPC_FCVTDL_Z = (OPC_OP(0x18) | OPC_FUNC(0x24)), ++ OPC_FCVTDL_N = (OPC_OP(0x18) | OPC_FUNC(0x25)), ++ OPC_FCVTDL = (OPC_OP(0x18) | OPC_FUNC(0x27)), ++ OPC_FCVTLS = (OPC_OP(0x18) | OPC_FUNC(0x2D)), ++ OPC_FCVTLD = (OPC_OP(0x18) | OPC_FUNC(0x2F)), ++ ++ ++ OPC_FADDS = (OPC_OP(0x18) | OPC_FUNC(0x00)), ++ OPC_FADDD = (OPC_OP(0x18) | OPC_FUNC(0x01)), ++ OPC_FSUBS = (OPC_OP(0x18) | OPC_FUNC(0x02)), ++ OPC_FSUBD = (OPC_OP(0x18) | OPC_FUNC(0x03)), ++ OPC_FMULS = (OPC_OP(0x18) | OPC_FUNC(0x04)), ++ OPC_FMULD = (OPC_OP(0x18) | OPC_FUNC(0x05)), ++ OPC_FDIVS = (OPC_OP(0x18) | OPC_FUNC(0x06)), ++ OPC_FDIVD = (OPC_OP(0x18) | OPC_FUNC(0x07)), ++ OPC_FSQRTS = (OPC_OP(0x18) | OPC_FUNC(0x08)), ++ OPC_FSQRTD = (OPC_OP(0x18) | OPC_FUNC(0x09)), ++}SW_64Insn; ++ ++static void tcg_out_insn_br(TCGContext *s, SW_64Insn insn, TCGReg rd, intptr_t imm64); ++static void tcg_out_insn_ldst(TCGContext *s, SW_64Insn insn, TCGReg rd, TCGReg rn, intptr_t imm16); ++static void tcg_out_insn_simpleReg(TCGContext *s, SW_64Insn insn, TCGReg rd, TCGReg rn, TCGReg rm); ++static void tcg_out_insn_simple(TCGContext *s, SW_64Insn insn_Imm, SW_64Insn insn_Reg, TCGReg rd, TCGReg rn, intptr_t imm64); ++static void tcg_out_insn_simpleImm(TCGContext *s, SW_64Insn insn_Imm, TCGReg rd, TCGReg rn, intptr_t imm64); ++static void tcg_out_insn_bitImm(TCGContext *s, SW_64Insn insn_Imm, TCGReg rd, TCGReg rn, unsigned long imm64); ++static void tcg_out_insn_bit(TCGContext *s, SW_64Insn insn_Imm, SW_64Insn insn_Reg, TCGReg rd, TCGReg rn, unsigned long imm64); ++static void tcg_out_insn_complexReg(TCGContext *s, SW_64Insn insn, TCGReg cond, TCGReg rd, TCGReg rn, TCGReg rm); ++static void tcg_out_movcond(TCGContext *s, TCGCond cond, TCGReg ret,TCGReg a1,TCGReg a2, bool const_b, TCGReg v1, TCGReg v2); ++static bool reloc_pc21(tcg_insn_unit *src_rw, const tcg_insn_unit *target); ++static inline uint32_t tcg_in32(TCGContext *s); ++static void tcg_out_movr(TCGContext *s, TCGType ext, TCGReg rd, TCGReg rn); ++static void tcg_out_ldst(TCGContext *s, SW_64Insn insn, TCGReg rd, TCGReg rn, intptr_t offset, bool sign); ++static void tcg_out_cond_cmp(TCGContext *s, TCGCond cond, TCGReg ret, TCGArg a, TCGArg b, bool const_b); ++static void tcg_out_addsubi(TCGContext *s, int ext, TCGReg rd, TCGReg rn, int64_t aimm); ++static inline void tcg_out_extr(TCGContext *s, TCGType ext, TCGReg rd, TCGReg rn, TCGReg rm, unsigned int m); ++static inline void tcg_out_rotl_Reg(TCGContext *s, TCGType ext, TCGReg rd, TCGReg rn, TCGReg rm); ++static inline void tcg_out_rotr_Reg(TCGContext *s, TCGType ext, TCGReg rd, TCGReg rn, TCGReg rm); ++static inline void tcg_out_rotl_Imm(TCGContext *s, TCGType ext, TCGReg rd, TCGReg rn, unsigned int m); ++static inline void tcg_out_rotr_Imm(TCGContext *s, TCGType ext, TCGReg rd, TCGReg rn, unsigned int m); ++static void tcg_out_cltz(TCGContext *s, SW_64Insn opc_clz, TCGType ext, TCGReg rd, TCGReg rn, TCGArg b, bool const_b); ++static inline void tcg_out_bswap16u(TCGContext *s, TCGReg rd, TCGReg rn); ++static inline void tcg_out_bswap16s(TCGContext *s, TCGReg rd, TCGReg rn); ++static inline void tcg_out_bswap32u(TCGContext *s, TCGReg rd, TCGReg rn); ++static inline void tcg_out_bswap32s(TCGContext *s, TCGReg rd, TCGReg rn); ++static inline void tcg_out_bswap64(TCGContext *s, TCGReg rd, TCGReg rn); ++static void tcg_out_qemu_st(TCGContext *s, TCGReg data_reg, TCGReg addr_reg, MemOpIdx oi); ++static void tcg_out_qemu_ld(TCGContext *s, TCGReg data_reg, TCGReg addr_reg, MemOpIdx oi, TCGType ext); ++static void tcg_out_setcond(TCGContext *s, TCGCond cond, TCGReg ret, TCGReg arg1, TCGReg arg2); ++static void tcg_out_extract(TCGContext *s, TCGReg rd, TCGReg rn, int pos, int len); ++static void tcg_out_dep(TCGContext *s, TCGReg rd, TCGReg rn, int pos, int len); ++static void tcg_out_mulsh64(TCGContext *s, TCGReg rd, TCGReg rn, TCGReg rm); ++ ++#define tcg_out_insn_jump tcg_out_insn_ldst ++#define tcg_out_insn_bitReg tcg_out_insn_simpleReg ++ ++static void tcg_target_init(TCGContext *s) ++{ ++ tcg_target_available_regs[TCG_TYPE_I32] = 0xffffffffu; ++ tcg_target_available_regs[TCG_TYPE_I64] = 0xffffffffu; ++ tcg_target_available_regs[TCG_TYPE_V64] = 0xffffffff00000000ull; ++ tcg_target_available_regs[TCG_TYPE_V128] = 0xffffffff00000000ull; ++ tcg_target_call_clobber_regs = -1ull; ++ ++ //sw_64 callee saved x9-x15 ++ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_X9); ++ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_X10); ++ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_X11); ++ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_X12); ++ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_X13); ++ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_X14); ++ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_X15); ++ ++ //sw_64 callee saved f2~f9 ++ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_F2); ++ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_F3); ++ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_F4); ++ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_F5); ++ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_F6); ++ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_F7); ++ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_F8); ++ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_F9); ++ ++ s->reserved_regs = 0; ++ tcg_regset_set_reg(s->reserved_regs, TCG_REG_SP); ++ tcg_regset_set_reg(s->reserved_regs, TCG_REG_FP); ++ tcg_regset_set_reg(s->reserved_regs, TCG_REG_TMP); //TCG_REG_X27 ++ tcg_regset_set_reg(s->reserved_regs, TCG_REG_TMP2); //TCG_REG_X25 ++ tcg_regset_set_reg(s->reserved_regs, TCG_REG_RA); //TCG_REG_X26 ++ tcg_regset_set_reg(s->reserved_regs, TCG_REG_X29); /*sw_64 platform register */ ++ tcg_regset_set_reg(s->reserved_regs, TCG_FLOAT_TMP); /*sw_64 platform register */ ++ tcg_regset_set_reg(s->reserved_regs, TCG_FLOAT_TMP2); /*sw_64 platform register */ ++} ++ ++ ++#ifndef CONFIG_SOFTMMU ++ #define USE_GUEST_BASE guest_base != 0 ++ #define TCG_REG_GUEST_BASE TCG_REG_X14 ++#endif ++ ++ ++#define zeroExt 0 ++#define sigExt 1 ++ ++ ++static void tcg_target_qemu_prologue(TCGContext *s) ++{ ++ TCGReg r; ++ int ofs; ++ ++ /* allocate space for all saved registers */ ++ /* subl $sp,PUSH_SIZE,$sp */ ++ tcg_out_insn_simple(s, OPC_SUBL_I, OPC_SUBL, TCG_REG_SP, TCG_REG_SP, PUSH_SIZE); ++ ++ /* Push (FP, LR) */ ++ /* stl $fp,0($sp) */ ++ tcg_out_insn_ldst(s, OPC_STL, TCG_REG_FP, TCG_REG_SP, 0); ++ /* stl $26,8($sp) */ ++ tcg_out_insn_ldst(s, OPC_STL, TCG_REG_RA, TCG_REG_SP, 8); ++ ++ ++ /* Set up frame pointer for canonical unwinding. */ ++ /* TCG_REG_FP=TCG_REG_SP */ ++ tcg_out_movr(s, TCG_TYPE_I64, TCG_REG_FP, TCG_REG_SP); ++ ++ /* Store callee-preserved regs x9..x14. */ ++ for (r = TCG_REG_X9; r <= TCG_REG_X14; r += 1){ ++ ofs = (r - TCG_REG_X9 + 2) * 8; ++ tcg_out_insn_ldst(s, OPC_STL, r, TCG_REG_SP, ofs); ++ } ++ ++ /* Make stack space for TCG locals. */ ++ /* subl $sp,FRAME_SIZE-PUSH_SIZE,$sp */ ++ tcg_out_insn_simple(s, OPC_SUBL_I, OPC_SUBL, TCG_REG_SP, TCG_REG_SP, FRAME_SIZE - PUSH_SIZE); ++ ++ /* Inform TCG about how to find TCG locals with register, offset, size. */ ++ tcg_set_frame(s, TCG_REG_SP, TCG_STATIC_CALL_ARGS_SIZE, ++ CPU_TEMP_BUF_NLONGS * sizeof(long)); ++ ++#if !defined(CONFIG_SOFTMMU) ++ if (USE_GUEST_BASE) { ++ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_GUEST_BASE, guest_base); ++ tcg_regset_set_reg(s->reserved_regs, TCG_REG_GUEST_BASE); ++ } ++#endif ++ ++ /* TCG_AREG0=tcg_target_call_iarg_regs[0], on sw, we mov $16 to $9 */ ++ tcg_out_mov(s, TCG_TYPE_I64, TCG_AREG0, tcg_target_call_iarg_regs[0]); ++ tcg_out_insn_jump(s, OPC_JMP, TCG_REG_ZERO, tcg_target_call_iarg_regs[1], 0); ++ ++ /* ++ * Return path for goto_ptr. Set return value to 0, a-la exit_tb, ++ * and fall through to the rest of the epilogue. ++ */ ++ tcg_code_gen_epilogue = tcg_splitwx_to_rx(s->code_ptr); ++ tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_X0, 0); ++ ++ /* TB epilogue */ ++ tb_ret_addr = tcg_splitwx_to_rx(s->code_ptr); ++ ++ /* Remove TCG locals stack space. */ ++ /* addl $sp,FRAME_SIZE-PUSH_SIZE,$sp */ ++ tcg_out_insn_simple(s, OPC_ADDL_I, OPC_ADDL, TCG_REG_SP, TCG_REG_SP, FRAME_SIZE - PUSH_SIZE); ++ ++ /* Restore registers x9..x14. */ ++ for (r = TCG_REG_X9; r <= TCG_REG_X14; r += 1) { ++ int ofs = (r - TCG_REG_X9 + 2) * 8; ++ tcg_out_insn_ldst(s, OPC_LDL, r, TCG_REG_SP, ofs); ++ } ++ ++ ++ /* Pop (FP, LR) */ ++ /* ldl $fp,0($sp) */ ++ tcg_out_insn_ldst(s, OPC_LDL, TCG_REG_FP, TCG_REG_SP, 0); ++ /* ldl $26,8($sp) */ ++ tcg_out_insn_ldst(s, OPC_LDL, TCG_REG_RA, TCG_REG_SP, 8); ++ ++ /* restore SP to previous frame. */ ++ /* addl $sp,PUSH_SIZE,$sp */ ++ tcg_out_insn_simple(s, OPC_ADDL_I, OPC_ADDL, TCG_REG_SP, TCG_REG_SP, PUSH_SIZE); ++ ++ tcg_out_insn_jump(s, OPC_RET, TCG_REG_ZERO, TCG_REG_RA, 0); ++} ++ ++static bool tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg) ++{ ++ if (ret == arg) { ++ return true; ++ } ++ switch (type) { ++ case TCG_TYPE_I32: ++ case TCG_TYPE_I64: ++ if (ret < 32 && arg < 32) { ++ tcg_out_movr(s, type, ret, arg); ++ break; ++ } else if (ret < 32) { ++ break; ++ } else if (arg < 32) { ++ break; ++ } ++ /* FALLTHRU */ ++ default: ++ g_assert_not_reached(); ++ } ++ return true; ++} ++ ++ ++static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op) ++{ ++ switch (op) { ++ case INDEX_op_goto_ptr: ++ return C_O0_I1(r); ++ ++ case INDEX_op_ld8u_i32: ++ case INDEX_op_ld8s_i32: ++ case INDEX_op_ld16u_i32: ++ case INDEX_op_ld16s_i32: ++ case INDEX_op_ld_i32: ++ case INDEX_op_ld8u_i64: ++ case INDEX_op_ld8s_i64: ++ case INDEX_op_ld16u_i64: ++ case INDEX_op_ld16s_i64: ++ case INDEX_op_ld32u_i64: ++ case INDEX_op_ld32s_i64: ++ case INDEX_op_ld_i64: ++ case INDEX_op_neg_i32: ++ case INDEX_op_neg_i64: ++ case INDEX_op_not_i32: ++ case INDEX_op_not_i64: ++ case INDEX_op_bswap16_i32: ++ case INDEX_op_bswap32_i32: ++ case INDEX_op_bswap16_i64: ++ case INDEX_op_bswap32_i64: ++ case INDEX_op_bswap64_i64: ++ case INDEX_op_ext8s_i32: ++ case INDEX_op_ext16s_i32: ++ case INDEX_op_ext8u_i32: ++ case INDEX_op_ext16u_i32: ++ case INDEX_op_ext8s_i64: ++ case INDEX_op_ext16s_i64: ++ case INDEX_op_ext32s_i64: ++ case INDEX_op_ext8u_i64: ++ case INDEX_op_ext16u_i64: ++ case INDEX_op_ext32u_i64: ++ case INDEX_op_ext_i32_i64: ++ case INDEX_op_extu_i32_i64: ++ case INDEX_op_extract_i32: ++ case INDEX_op_extract_i64: ++ case INDEX_op_sextract_i32: ++ case INDEX_op_sextract_i64: ++ return C_O1_I1(r, r); ++ ++ case INDEX_op_st8_i32: ++ case INDEX_op_st16_i32: ++ case INDEX_op_st_i32: ++ case INDEX_op_st8_i64: ++ case INDEX_op_st16_i64: ++ case INDEX_op_st32_i64: ++ case INDEX_op_st_i64: ++ return C_O0_I2(rZ, r); ++ ++ case INDEX_op_add_i32: ++ case INDEX_op_add_i64: ++ case INDEX_op_sub_i32: ++ case INDEX_op_sub_i64: ++ return C_O1_I2(r, r, rU);//rA ++ ++ case INDEX_op_setcond_i32: ++ case INDEX_op_setcond_i64: ++ return C_O1_I2(r, r, rU);//compare,rA ++ ++ case INDEX_op_mul_i32: ++ case INDEX_op_mul_i64: ++ case INDEX_op_div_i32: ++ case INDEX_op_div_i64: ++ case INDEX_op_divu_i32: ++ case INDEX_op_divu_i64: ++ case INDEX_op_rem_i32: ++ case INDEX_op_rem_i64: ++ case INDEX_op_remu_i32: ++ case INDEX_op_remu_i64: ++ case INDEX_op_muluh_i64: ++ case INDEX_op_mulsh_i64: ++ return C_O1_I2(r, r, r); ++ ++ case INDEX_op_and_i32: ++ case INDEX_op_and_i64: ++ case INDEX_op_or_i32: ++ case INDEX_op_or_i64: ++ case INDEX_op_xor_i32: ++ case INDEX_op_xor_i64: ++ case INDEX_op_andc_i32: ++ case INDEX_op_andc_i64: ++ case INDEX_op_orc_i32: ++ case INDEX_op_orc_i64: ++ case INDEX_op_eqv_i32: ++ case INDEX_op_eqv_i64: ++ return C_O1_I2(r, r, rU);//rL ++ ++ case INDEX_op_shl_i32: ++ case INDEX_op_shr_i32: ++ case INDEX_op_sar_i32: ++ case INDEX_op_rotl_i32: ++ case INDEX_op_rotr_i32: ++ case INDEX_op_shl_i64: ++ case INDEX_op_shr_i64: ++ case INDEX_op_sar_i64: ++ case INDEX_op_rotl_i64: ++ case INDEX_op_rotr_i64: ++ return C_O1_I2(r, r, ri); ++ ++ case INDEX_op_clz_i32: ++ case INDEX_op_clz_i64: ++ return C_O1_I2(r, r, r); //rAL ++ ++ case INDEX_op_ctz_i32: ++ case INDEX_op_ctz_i64: ++ return C_O1_I2(r, r, r);//rAL ++ ++ case INDEX_op_brcond_i32: ++ case INDEX_op_brcond_i64: ++ return C_O0_I2(r, rU);//rA ++ ++ case INDEX_op_movcond_i32: ++ case INDEX_op_movcond_i64: ++ return C_O1_I4(r, r, rU, rZ, rZ);//rA->rU ++ ++ case INDEX_op_qemu_ld_i32: ++ case INDEX_op_qemu_ld_i64: ++ return C_O1_I1(r, l); ++ ++ case INDEX_op_qemu_st_i32: ++ case INDEX_op_qemu_st_i64: ++ return C_O0_I2(lZ, l); ++ ++ case INDEX_op_deposit_i32: ++ case INDEX_op_deposit_i64: ++ return C_O1_I2(r, 0, rZ); ++ ++ case INDEX_op_extract2_i32: ++ case INDEX_op_extract2_i64: ++ return C_O1_I2(r, rZ, rZ); ++ ++ case INDEX_op_add2_i32: ++ case INDEX_op_add2_i64: ++ case INDEX_op_sub2_i32: ++ case INDEX_op_sub2_i64: ++ return C_O2_I4(r, r, rZ, rZ, rA, rMZ); ++ ++ case INDEX_op_add_vec: ++ case INDEX_op_sub_vec: ++ case INDEX_op_mul_vec: ++ case INDEX_op_xor_vec: ++ case INDEX_op_ssadd_vec: ++ case INDEX_op_sssub_vec: ++ case INDEX_op_usadd_vec: ++ case INDEX_op_ussub_vec: ++ case INDEX_op_smax_vec: ++ case INDEX_op_smin_vec: ++ case INDEX_op_umax_vec: ++ case INDEX_op_umin_vec: ++ case INDEX_op_shlv_vec: ++ case INDEX_op_shrv_vec: ++ case INDEX_op_sarv_vec: ++ return C_O1_I2(w, w, w); ++ case INDEX_op_not_vec: ++ case INDEX_op_neg_vec: ++ case INDEX_op_abs_vec: ++ case INDEX_op_shli_vec: ++ case INDEX_op_shri_vec: ++ case INDEX_op_sari_vec: ++ return C_O1_I1(w, w); ++ case INDEX_op_ld_vec: ++ case INDEX_op_dupm_vec: ++ return C_O1_I1(w, r); ++ case INDEX_op_st_vec: ++ return C_O0_I2(w, r); ++ case INDEX_op_dup_vec: ++ return C_O1_I1(w, wr); ++ case INDEX_op_or_vec: ++ case INDEX_op_andc_vec: ++ return C_O1_I2(w, w, wO); ++ case INDEX_op_and_vec: ++ case INDEX_op_orc_vec: ++ return C_O1_I2(w, w, wN); ++ case INDEX_op_cmp_vec: ++ return C_O1_I2(w, w, wZ); ++ case INDEX_op_bitsel_vec: ++ return C_O1_I3(w, w, w, w); ++ ++ default: ++ g_assert_not_reached(); ++ } ++} ++ ++ ++static void tcg_out_nop_fill(tcg_insn_unit *p, int count) ++{ ++ int i; ++ for (i = 0; i < count; ++i) { ++ p[i] = OPC_NOP; ++ } ++} ++ ++/* SW instruction format of syscall ++ * insn = opcode[31,26]:Function[25,0], ++ */ ++ ++/* SW instruction format of br(alias jump) ++ * insn = opcode[31,26]:Rd[25,21]:disp[20,0], ++ */ ++static void tcg_out_insn_br(TCGContext *s, SW_64Insn insn, TCGReg rd, intptr_t imm64) ++{ ++ tcg_debug_assert(imm64 <= 0xfffff && imm64 >= -0x100000); ++ tcg_out32(s, insn | (rd & 0x1f) << 21 | (imm64 & 0x1fffff)); ++} ++ ++ ++/* SW instruction format of (load and store) ++ * insn = opcode[31,26]:rd[25,21]:rn[20,16]:disp[15,0] ++ */ ++static void tcg_out_insn_ldst(TCGContext *s, SW_64Insn insn, TCGReg rd, TCGReg rn, intptr_t imm16) ++{ ++ tcg_debug_assert(imm16 <= 0x7fff && imm16 >= -0x8000); ++ tcg_out32(s, insn | (rd & 0x1f) << 21 | (rn & 0x1f) << 16 | (imm16 & 0xffff)); ++} ++ ++ ++/* SW instruction format of simple operator for Register ++ * insn = opcode[31,26]:rn(ra)[25,21]:rn(rb)[20,16]:Zeors[15,13]:function[12,5]:rd(rc)[4,0] ++ */ ++static void tcg_out_insn_simpleReg(TCGContext *s, SW_64Insn insn, TCGReg rd, TCGReg rn, TCGReg rm) ++{ ++ tcg_out32(s, insn | (rn & 0x1f) << 21 | (rm & 0x1f) << 16 | (rd & 0x1f)); ++} ++ ++/* SW instruction format of simple operator for imm ++ * insn = opcode[31,26]:rn(ra)[25,21]:disp[20,13]:function[12,5]:rd(rc)[4,0] ++ */ ++static void tcg_out_insn_simple(TCGContext *s, SW_64Insn insn_Imm, SW_64Insn insn_Reg, TCGReg rd, TCGReg rn, intptr_t imm64) ++{ ++ if(imm64 <= 0x7f && imm64 >= -0x80) { ++ tcg_out32(s, insn_Imm | (rn & 0x1f) << 21 | (imm64 & 0xff) << 13 | (rd & 0x1f)); ++ } ++ else { ++ tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_TMP, imm64); ++ tcg_out_insn_simpleReg(s, insn_Reg, rd, rn, TCG_REG_TMP); ++ } ++} ++ ++ ++static void tcg_out_insn_simpleImm(TCGContext *s, SW_64Insn insn_Imm, TCGReg rd, TCGReg rn, intptr_t imm64) ++{ ++ tcg_debug_assert(imm64 <= 0x7f && imm64 >= -0x80); ++ tcg_out32(s, insn_Imm | (rn & 0x1f) << 21 | (imm64 & 0xff) << 13 | (rd & 0x1f)); ++ ++} ++ ++static void tcg_out_insn_bitImm(TCGContext *s, SW_64Insn insn_Imm, TCGReg rd, TCGReg rn, unsigned long imm64) ++{ ++ tcg_debug_assert(imm64 <= 255); ++ tcg_out32(s, insn_Imm | (rn & 0x1f) << 21 | (imm64 & 0xff) << 13 | (rd & 0x1f)); ++} ++/* sw bit operation: and bis etc */ ++static void tcg_out_insn_bit(TCGContext *s, SW_64Insn insn_Imm, SW_64Insn insn_Reg, TCGReg rd, TCGReg rn, unsigned long imm64) ++{ ++ if (imm64 <= 255) { ++ tcg_out32(s, insn_Imm | (rn & 0x1f) << 21 | (imm64 & 0xff) << 13 | (rd & 0x1f)); ++ } ++ else { ++ tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_TMP, imm64); ++ tcg_out_insn_bitReg(s, insn_Reg, rd, rn, TCG_REG_TMP); ++ } ++} ++ ++/* SW instruction format of complex operator ++ * insn = opcode[31,26]:rd[25,21]:rn[20,16],function[15,10]:rm[9,5]:rx[4,0] ++ */ ++static void tcg_out_insn_complexReg(TCGContext *s, SW_64Insn insn, TCGReg cond, TCGReg rd, TCGReg rn, TCGReg rm) ++{ ++ tcg_out32(s, insn | (cond & 0x1f) << 21 | (rn & 0x1f) << 16 | (rm & 0x1f) << 5 | (rd & 0x1f)); ++} ++ ++static bool reloc_pc21(tcg_insn_unit *src_rw, const tcg_insn_unit *target) ++{ ++ const tcg_insn_unit *src_rx = tcg_splitwx_to_rx(src_rw); ++ ptrdiff_t offset = target - (src_rx + 1) ; ++ ++ if (offset == sextract64(offset, 0, 21)) { ++ /* read instruction, mask away previous PC_REL21 parameter contents, ++ set the proper offset, then write back the instruction. */ ++ *src_rw = deposit32(*src_rw, 0, 21, offset); ++ return true; ++ } ++ return false; ++} ++ ++/* sw*/ ++static bool patch_reloc(tcg_insn_unit *code_ptr, int type, intptr_t value, intptr_t addend) ++{ ++ tcg_debug_assert(addend == 0); ++ switch (type) { ++ case R_SW_64_BRADDR: ++ return reloc_pc21(code_ptr, (const tcg_insn_unit *)value); ++ default: ++ g_assert_not_reached(); ++ } ++} ++ ++static inline uint32_t tcg_in32(TCGContext *s) ++{ ++ uint32_t v = *(uint32_t *)s->code_ptr; ++ return v; ++} ++ ++/*SW Register to register move using ADDL*/ ++static void tcg_out_movr(TCGContext *s, TCGType ext, TCGReg rd, TCGReg rn) ++{ ++ tcg_out_insn_simpleReg(s, OPC_BIS, rd, rn, TCG_REG_ZERO); ++ if (ext == TCG_TYPE_I32){ ++ tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, rd, rd, 0xf); ++ } ++} ++ ++/*sw ++ *put imm into rd ++ */ ++static void tcg_out_movi(TCGContext *s, TCGType type, TCGReg rd, tcg_target_long orig) ++{ ++ long l0, l1, l2=0, l3=0, extra=0; ++ tcg_target_long val = orig; ++ TCGReg rs = TCG_REG_ZERO; ++ ++ if (type == TCG_TYPE_I32) ++ val = (int32_t)val; ++ ++ l0 = (int16_t)val; ++ val = (val - l0) >> 16; ++ l1 = (int16_t)val; ++ ++ if (orig >> 31 == -1 || orig >> 31 == 0) { ++ if (l1 < 0 && orig >= 0) { ++ extra = 0x4000; ++ l1 = (int16_t)(val - 0x4000); ++ } ++ } else { ++ val = (val - l1) >> 16; ++ l2 = (int16_t)val; ++ val = (val - l2) >> 16; ++ l3 = (int16_t)val; ++ ++ if (l3) { ++ tcg_out_insn_ldst(s, OPC_LDIH, rd, rs, l3); ++ rs = rd; ++ } ++ if (l2) { ++ tcg_out_insn_ldst(s, OPC_LDI, rd, rs, l2); ++ rs = rd; ++ } ++ if (l3 || l2) ++ tcg_out_insn_simpleImm(s, OPC_SLL_I, rd, rd, 32); ++ } ++ ++ if (l1) { ++ tcg_out_insn_ldst(s, OPC_LDIH, rd, rs, l1); ++ rs = rd; ++ } ++ ++ if (extra) { ++ tcg_out_insn_ldst(s, OPC_LDIH, rd, rs, extra); ++ rs = rd; ++ } ++ ++ tcg_out_insn_ldst(s, OPC_LDI, rd, rs, l0); ++} ++ ++ ++/*sw ++* memory <=> Reg in (B H W L) bytes ++*/ ++static void tcg_out_ldst(TCGContext *s, SW_64Insn insn, TCGReg rd, TCGReg rn, intptr_t offset, bool sign) ++{ ++ int16_t lo = offset; ++ if (offset != lo) { ++ tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_TMP, offset - lo); ++ if (rn != TCG_REG_ZERO) { ++ tcg_out_insn_simpleReg(s, OPC_ADDL, TCG_REG_TMP, TCG_REG_TMP, rn); ++ } ++ tcg_out_insn_ldst(s, insn, rd, TCG_REG_TMP, lo); ++ } ++ else { ++ tcg_out_insn_ldst(s, insn, rd, rn, lo); ++ } ++ ++ switch (insn) { ++ case OPC_LDBU: ++ if (sign) ++ tcg_out_insn_simpleReg(s, OPC_SEXTB, rd, TCG_REG_ZERO, rd); //for micro-op:INDEX_op_ld8s_i32/64,set rd[63,8]=1 ++ break; ++ case OPC_LDHU: ++ if (sign) ++ tcg_out_insn_simpleReg(s, OPC_SEXTH, rd, TCG_REG_ZERO, rd); //for micro-op:INDEX_op_ld16s_i32/64,set rd[63,16]=1 ++ break; ++ case OPC_LDW: ++ if (!sign) ++ tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, rd, rd, 0xf); //for micro-op:INDEX_op_ld32u_i32/64,set rd[63,32]=0 ++ break; ++ default: ++ break; ++ } ++} ++ ++/* TCG_REG_TMP stores result_of_condition_compare */ ++static void tcg_out_cond_cmp(TCGContext *s, TCGCond cond, TCGReg ret, TCGArg a, TCGArg b, bool const_b) ++{ ++ if (const_b) { ++ switch(cond) { ++ case TCG_COND_ALWAYS: ++ case TCG_COND_NEVER: ++ break; ++ case TCG_COND_EQ: ++ case TCG_COND_NE: ++ tcg_out_insn_simple(s, OPC_CMPEQ_I, OPC_CMPEQ, ret, a, b); ++ break; ++ case TCG_COND_LT: ++ case TCG_COND_GE: ++ tcg_out_insn_simple(s, OPC_CMPLT_I, OPC_CMPLT, ret, a, b); ++ break; ++ case TCG_COND_LE: ++ case TCG_COND_GT: ++ tcg_out_insn_simple(s, OPC_CMPLE_I, OPC_CMPLE, ret, a, b); ++ break; ++ case TCG_COND_LTU: ++ case TCG_COND_GEU: ++ tcg_out_insn_simple(s, OPC_CMPULT_I, OPC_CMPULT, ret, a, b); ++ break; ++ case TCG_COND_LEU: ++ case TCG_COND_GTU: ++ tcg_out_insn_simple(s, OPC_CMPULE_I, OPC_CMPULE, ret, a, b); ++ break; ++ }//cond ++ }//if (const_b) ++ else { ++ switch(cond) { ++ case TCG_COND_ALWAYS: ++ case TCG_COND_NEVER: ++ break; ++ case TCG_COND_EQ: ++ case TCG_COND_NE: ++ tcg_out_insn_simpleReg(s, OPC_CMPEQ, ret, a, b); ++ break; ++ case TCG_COND_LT: ++ case TCG_COND_GE: ++ tcg_out_insn_simpleReg(s, OPC_CMPLT, ret, a, b); ++ break; ++ case TCG_COND_LE: ++ case TCG_COND_GT: ++ tcg_out_insn_simpleReg(s, OPC_CMPLE, ret, a, b); ++ break; ++ case TCG_COND_LTU: ++ case TCG_COND_GEU: ++ tcg_out_insn_simpleReg(s, OPC_CMPULT, ret, a, b); ++ break; ++ case TCG_COND_LEU: ++ case TCG_COND_GTU: ++ tcg_out_insn_simpleReg(s, OPC_CMPULE, ret, a, b); ++ break; ++ }//cond ++ }//else ++ switch(cond) { ++ case TCG_COND_ALWAYS: ++ case TCG_COND_NEVER: ++ case TCG_COND_EQ: ++ case TCG_COND_LT: ++ case TCG_COND_LE: ++ case TCG_COND_LTU: ++ case TCG_COND_LEU: ++ break; ++ case TCG_COND_NE: ++ case TCG_COND_GE: ++ case TCG_COND_GT: ++ case TCG_COND_GEU: ++ case TCG_COND_GTU: ++ tcg_out_insn_bitImm(s, OPC_XOR_I, ret, ret, 0x1); ++ break; ++ } ++} ++ ++/* sw ++ * step1 tcg_out_cmp() ,"eq" and "ne" in the same case with the same insn; ++ * store compare result by TCG_REG_TMP, for step2; ++ * step2: jump address with compare result. in last "switch" section, we diff qe/ne by different case with different insn. ++ */ ++static void tcg_out_brcond(TCGContext *s, TCGType ext, TCGCond cond, TCGArg a, TCGArg b, bool b_const, TCGLabel *l) ++{ ++ intptr_t offset; ++ bool need_cmp; ++ ++ if (b_const && b == 0 && (cond == TCG_COND_EQ || cond == TCG_COND_NE)) { ++ need_cmp = false; ++ } else { ++ need_cmp = true; ++ tcg_out_cond_cmp(s, cond, TCG_REG_TMP, a, b, b_const); ++ } ++ ++ if (!l->has_value) { ++ tcg_out_reloc(s, s->code_ptr, R_SW_64_BRADDR, l, 0); ++ offset=0; //offset = tcg_in32(s) >> 5; br $31, 0, do not jump here! ++ } else { ++ offset = tcg_pcrel_diff(s, l->u.value_ptr) ; ++ offset = offset >> 2; ++ tcg_debug_assert(offset == sextract64(offset, 0, 21)); ++ } ++ ++ if (need_cmp) { ++ tcg_out_insn_br(s, OPC_BGT, TCG_REG_TMP, offset); //a cond b,jmp ++ } else if (cond == TCG_COND_EQ) { ++ tcg_out_insn_br(s, OPC_BEQ, a, offset); ++ } else { ++ tcg_out_insn_br(s, OPC_BNE, a, offset); ++ } ++} ++ ++/*sw ++ * contact with "tcg-target-con-str.h" ++ */ ++#define TCG_CT_CONST_ZERO 0x100 ++#define TCG_CT_CONST_LONG 0x200 ++#define TCG_CT_CONST_MONE 0x400 ++#define TCG_CT_CONST_ORRI 0x800 ++#define TCG_CT_CONST_WORD 0X1000 ++#define TCG_CT_CONST_U8 0x2000 ++#define TCG_CT_CONST_S8 0X4000 ++ ++#define ALL_GENERAL_REGS 0xffffffffu ++#define ALL_VECTOR_REGS 0xffffffff00000000ull ++ ++ ++#ifdef CONFIG_SOFTMMU ++/*sw #define ALL_QLDST_REGS */ ++#else ++ #define ALL_QLDST_REGS ALL_GENERAL_REGS ++#endif ++ ++/* sw test if a constant matches the constraint */ ++static bool tcg_target_const_match(int64_t val, TCGType type, int ct) ++{ ++ if (ct & TCG_CT_CONST) { ++ return 1; ++ } ++ if (type == TCG_TYPE_I32) { ++ val = (int32_t)val; ++ } ++ if ((ct & TCG_CT_CONST_U8) && 0 <= val && val <= 255) { ++ return 1; ++ } ++ if ((ct & TCG_CT_CONST_LONG)) { ++ return 1; ++ } ++ if ((ct & TCG_CT_CONST_MONE)) { ++ return 1; ++ } ++ if ((ct & TCG_CT_CONST_ORRI)) { ++ return 1; ++ } ++ if ((ct & TCG_CT_CONST_WORD)) { ++ return 1; ++ } ++ if ((ct & TCG_CT_CONST_ZERO) && val == 0) { ++ return 1; ++ } ++ return 0; ++} ++ ++static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg rd, TCGReg rn, intptr_t ofs) ++{ ++ switch (type) { ++ case TCG_TYPE_I32: ++ tcg_out_ldst(s, OPC_LDW, rd, rn, ofs, sigExt); ++ break; ++ case TCG_TYPE_I64: ++ tcg_out_ldst(s, OPC_LDL, rd, rn, ofs, sigExt); ++ break; ++ default: ++ g_assert_not_reached(); ++ } ++} ++ ++static void tcg_out_st(TCGContext *s, TCGType type, TCGReg rd, TCGReg rn, intptr_t ofs) ++{ ++ switch (type) { ++ case TCG_TYPE_I32: ++ tcg_out_insn_ldst(s, OPC_STW, rd, rn, ofs); ++ break; ++ case TCG_TYPE_I64: ++ tcg_out_insn_ldst(s, OPC_STL, rd, rn, ofs); ++ break; ++ default: ++ g_assert_not_reached(); ++ } ++} ++ ++static inline bool tcg_out_sti(TCGContext *s, TCGType type, TCGArg val, TCGReg base, intptr_t ofs) ++{ ++ if (type <= TCG_TYPE_I64 && val == 0) { ++ tcg_out_st(s, type, TCG_REG_ZERO, base, ofs); ++ return true; ++ } ++ return false; ++} ++ ++static void tcg_out_addsubi(TCGContext *s, int ext, TCGReg rd, TCGReg rn, int64_t imm64) ++{ ++ if (imm64 >= 0) { ++ if(0 <=imm64 && imm64 <= 255) { ++ /* we use tcg_out_insn_bitImm because imm64 is between 0~255 */ ++ tcg_out_insn_bitImm(s, OPC_ADDL_I, rd, rn, imm64); ++ }//aimm>0 && aimm == sextract64(aim, 0, 8) ++ else { ++ tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_TMP, imm64); ++ tcg_out_insn_simpleReg(s, OPC_ADDL, rd, rn, TCG_REG_TMP); ++ }//aimm>0 && aimm != sextract64(aim, 0, 8) ++ } else { ++ if(0 < -imm64 && -imm64 <= 255) { ++ /* we use tcg_out_insn_bitImm because -imm64 is between 0~255 */ ++ tcg_out_insn_bitImm(s, OPC_SUBL_I, rd, rn, -imm64); ++ }//aimm<0 && aimm == sextract64(aim, 0, 8) ++ else { ++ tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_TMP, -imm64); ++ tcg_out_insn_simpleReg(s, OPC_SUBL, rd, rn, TCG_REG_TMP); ++ }//aimm<0 && aimm != sextract64(aim, 0, 8) ++ } ++} ++ ++static void tcg_out_goto(TCGContext *s, const tcg_insn_unit *target) ++{ ++ ptrdiff_t offset = tcg_pcrel_diff(s, target) >> 2; ++ tcg_debug_assert(offset == sextract64(offset, 0, 21)); ++ tcg_out_insn_br(s, OPC_BR, TCG_REG_ZERO, offset); ++} ++ ++static void tcg_out_goto_long(TCGContext *s, const tcg_insn_unit *target) ++{ ++ ptrdiff_t offset = tcg_pcrel_diff(s, target) >> 2; ++ if (0 <= offset && offset <= 0x1fffff) { ++ tcg_out_insn_br(s, OPC_BR, TCG_REG_ZERO, offset); ++ } else { ++ tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_TMP, (intptr_t)target); ++ tcg_out_insn_jump(s, OPC_JMP, TCG_REG_ZERO, TCG_REG_TMP, 0); ++ } ++} ++ ++ ++/*sw ++* call subroutine ++*/ ++static void tcg_out_call(TCGContext *s, const tcg_insn_unit *target) ++{ ++ ptrdiff_t offset = tcg_pcrel_diff(s, target) >> 2; ++ if (offset == sextract64(offset, 0, 21)) { ++ tcg_out_insn_br(s, OPC_BSR, TCG_REG_RA, offset); ++ } else { ++ tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_TMP, (intptr_t)target); ++ tcg_out_insn_jump(s, OPC_CALL, TCG_REG_RA, TCG_REG_TMP, 0); ++ } ++} ++ ++void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_rx, uintptr_t jmp_rw, uintptr_t addr) ++{ ++ tcg_debug_assert(0); ++ //sw not support ++} ++ ++static inline void tcg_out_goto_label(TCGContext *s, TCGLabel *l) ++{ ++ if (!l->has_value) { ++ tcg_out_reloc(s, s->code_ptr, R_SW_64_BRADDR, l, 0); ++ tcg_out_insn_br(s, OPC_BR, TCG_REG_ZERO, 0); ++ } else { ++ tcg_out_goto(s, l->u.value_ptr); ++ } ++} ++ ++/* sw ++ * resut: rd=rn(64,64-m]:rm(64-m,0] ++ * 1: rn(m,0]--->TCG_REG_TMP(64,64-m] ++ * 2: rm(64,64-m]--->rm(64-m,0] ++ * 3: rd=TCG_REG_TMP(64,64-m]:rm(64-m,0] ++ */ ++static inline void tcg_out_extr(TCGContext *s, TCGType ext, TCGReg rd, TCGReg rn, TCGReg rm, unsigned int m) ++{ ++ int bits = ext ? 64 : 32; ++ int max = bits - 1; ++ tcg_out_insn_bitImm(s, OPC_SLL_I, TCG_REG_TMP, rn, bits - (m & max)); ++ tcg_out_insn_bitImm(s, OPC_SRL_I, TCG_REG_TMP2, rm, (m & max)); ++ tcg_out_insn_bitReg(s, OPC_BIS, rd, TCG_REG_TMP, TCG_REG_TMP2); ++} ++ ++/* sw ++ * loop right shift ++ */ ++static inline void tcg_out_rotr_Imm(TCGContext *s, TCGType ext, TCGReg rd, TCGReg rn, unsigned int m) ++{ ++ int bits = ext ? 64 : 32; ++ int max = bits - 1; ++ tcg_out_insn_bitImm(s, OPC_SLL_I, TCG_REG_TMP, rn, bits - (m & max)); ++ tcg_out_insn_bitImm(s, OPC_SRL_I, TCG_REG_TMP2, rn, (m & max)); ++ tcg_out_insn_bitReg(s, OPC_BIS, rd, TCG_REG_TMP, TCG_REG_TMP2); ++} ++ ++/* sw loop right shift ++ */ ++static inline void tcg_out_rotr_Reg(TCGContext *s, TCGType ext, TCGReg rd, TCGReg rn, TCGReg rm) ++{ ++ int bits = ext ? 64 : 32; ++ //get TCG_REG_TMP=64-[rm] ++ tcg_out_insn_simpleImm(s, OPC_SUBL_I, TCG_REG_TMP, rm, bits); ++ tcg_out_insn_bitReg(s, OPC_ORNOT, TCG_REG_TMP, TCG_REG_ZERO, TCG_REG_TMP); ++ ++ tcg_out_insn_bitReg(s, OPC_SLL, TCG_REG_TMP2, rn, TCG_REG_TMP); //get rn right part to TCG_REG_TMP ++ tcg_out_insn_bitReg(s, OPC_SRL, TCG_REG_TMP, rn, rm); //get rn left part to TCG_REG_TMP ++ tcg_out_insn_bitReg(s, OPC_BIS, rd, TCG_REG_TMP, TCG_REG_TMP2); ++} ++ ++/* sw ++ * loop left shift ++ */ ++static inline void tcg_out_rotl_Imm(TCGContext *s, TCGType ext, TCGReg rd, TCGReg rn, unsigned int m) ++{ ++ int bits = ext ? 64 : 32; ++ int max = bits - 1; ++ ++ tcg_out_insn_bitImm(s, OPC_SRL_I, TCG_REG_TMP, rn, bits -(m & max)); ++ tcg_out_insn_bitImm(s, OPC_SLL_I, TCG_REG_TMP2, rn, (m & max)); //get rn left part to TCG_REG_TMP ++ tcg_out_insn_bitReg(s, OPC_BIS, rd, TCG_REG_TMP, TCG_REG_TMP2); //get rn right part to left ++} ++ ++ ++/* sw loop left shift ++ */ ++static inline void tcg_out_rotl_Reg(TCGContext *s, TCGType ext, TCGReg rd, TCGReg rn, TCGReg rm) ++{ ++ int bits = ext ? 64 : 32; ++ tcg_out_insn_simpleImm(s, OPC_SUBL_I, TCG_REG_TMP, rm, bits); //rm = 64-rm ++ tcg_out_insn_bitReg(s, OPC_ORNOT, TCG_REG_TMP, TCG_REG_ZERO, TCG_REG_TMP); ++ ++ tcg_out_insn_bitReg(s, OPC_SRL, TCG_REG_TMP2, rn, TCG_REG_TMP); //get rn left part to TCG_REG_TMP ++ tcg_out_insn_bitReg(s, OPC_SLL, TCG_REG_TMP, rn, rm); //get rn right part to left ++ tcg_out_insn_bitReg(s, OPC_BIS, rd, TCG_REG_TMP, TCG_REG_TMP2); ++} ++ ++ ++ ++static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) ++{ ++ /* 99% of the time, we can signal the use of extension registers ++ by looking to see if the opcode handles 64-bit data. */ ++ TCGType ext = (tcg_op_defs[opc].flags & TCG_OPF_64BIT) != 0; ++ /* Hoist the loads of the most common arguments. */ ++ TCGArg a0 = args[0]; ++ TCGArg a1 = args[1]; ++ TCGArg a2 = args[2]; ++ int c2 = const_args[2]; ++ ++ /* Some operands are defined with "rZ" constraint, a register or ++ the zero register. These need not actually test args[I] == 0. */ ++ #define REG0(I) (const_args[I] ? TCG_REG_ZERO : (TCGReg)args[I]) ++ ++ switch (opc) { ++ case INDEX_op_exit_tb: ++ /* Reuse the zeroing that exists for goto_ptr. */ ++ if (a0 == 0) { ++ tcg_out_goto_long(s, tcg_code_gen_epilogue); ++ } else { ++ tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_X0, a0); ++ tcg_out_goto_long(s, tb_ret_addr); ++ } ++ break; ++ ++ case INDEX_op_goto_tb: ++ if (s->tb_jmp_insn_offset != NULL) { ++ /* TCG_TARGET_HAS_direct_jump */ ++ tcg_debug_assert(0); ++ /* not support here */ ++ } else { ++ /* !TCG_TARGET_HAS_direct_jump */ ++ tcg_debug_assert(s->tb_jmp_target_addr != NULL); ++ tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_TMP, TCG_REG_ZERO, (uintptr_t)(s->tb_jmp_target_addr + a0)); ++ } ++ tcg_out_insn_jump(s, OPC_JMP, TCG_REG_ZERO, TCG_REG_TMP, 0); ++ set_jmp_reset_offset(s, a0); ++ break; ++ ++ case INDEX_op_goto_ptr: ++ tcg_out_insn_jump(s, OPC_JMP, TCG_REG_ZERO, a0, 0); ++ break; ++ ++ case INDEX_op_br: ++ tcg_out_goto_label(s, arg_label(a0)); ++ break; ++ ++ case INDEX_op_ld8u_i32: ++ case INDEX_op_ld8u_i64: ++ tcg_out_ldst(s, OPC_LDBU, a0, a1, a2, 0); ++ break; ++ case INDEX_op_ld8s_i32: ++ case INDEX_op_ld8s_i64: ++ tcg_out_ldst(s, OPC_LDBU, a0, a1, a2, 1); ++ break; ++ case INDEX_op_ld16u_i32: ++ case INDEX_op_ld16u_i64: ++ tcg_out_ldst(s, OPC_LDHU, a0, a1, a2, 0); ++ break; ++ case INDEX_op_ld16s_i32: ++ case INDEX_op_ld16s_i64: ++ tcg_out_ldst(s, OPC_LDHU, a0, a1, a2, 1); ++ break; ++ case INDEX_op_ld_i32: ++ tcg_out_ldst(s, OPC_LDW, a0, a1, a2, 1); ++ break; ++ case INDEX_op_ld32u_i64: ++ tcg_out_ldst(s, OPC_LDW, a0, a1, a2, 0); ++ break; ++ case INDEX_op_ld32s_i64: ++ tcg_out_ldst(s, OPC_LDW, a0, a1, a2, 1); ++ break; ++ case INDEX_op_ld_i64: ++ tcg_out_ldst(s, OPC_LDL, a0, a1, a2, 1); ++ break; ++ case INDEX_op_st8_i32: ++ case INDEX_op_st8_i64: ++ tcg_out_ldst(s, OPC_STB, a0, a1, a2, 0); ++ break; ++ case INDEX_op_st16_i32: ++ case INDEX_op_st16_i64: ++ tcg_out_ldst(s, OPC_STH, a0, a1, a2, 0); ++ break; ++ case INDEX_op_st_i32: ++ case INDEX_op_st32_i64: ++ tcg_out_ldst(s, OPC_STW, a0, a1, a2, 0); ++ break; ++ case INDEX_op_st_i64: ++ tcg_out_ldst(s, OPC_STL, a0, a1, a2, 0); ++ break; ++ ++ case INDEX_op_add_i32: ++ a2 = (int32_t)a2; ++ if (c2) { ++ tcg_out_addsubi(s, ext, a0, a1, a2); ++ } else { ++ tcg_out_insn_simpleReg(s, OPC_ADDL, a0, a1, a2); ++ } ++ break; ++ case INDEX_op_add_i64: ++ if (c2) { ++ tcg_out_addsubi(s, ext, a0, a1, a2); ++ } else { ++ tcg_out_insn_simpleReg(s, OPC_ADDL, a0, a1, a2); ++ } ++ break; ++ ++ case INDEX_op_sub_i32: ++ a2 = (int32_t)a2; ++ if (c2) { ++ tcg_out_addsubi(s, ext, a0, a1, -a2); ++ } else { ++ tcg_out_insn_simpleReg(s, OPC_SUBL, a0, a1, a2); ++ } ++ break; ++ case INDEX_op_sub_i64: ++ if (c2) { ++ tcg_out_addsubi(s, ext, a0, a1, -a2); ++ } else { ++ tcg_out_insn_simpleReg(s, OPC_SUBL, a0, a1, a2); ++ } ++ break; ++ ++ case INDEX_op_neg_i64: ++ case INDEX_op_neg_i32: ++ tcg_out_insn_bitReg(s, OPC_SUBL, a0, TCG_REG_ZERO, a1); ++ break; ++ ++ case INDEX_op_and_i32: ++ a2 = (int32_t)a2; ++ if (c2) { ++ tcg_out_insn_bit(s, OPC_AND_I, OPC_AND, a0, a1, a2); ++ } else { ++ tcg_out_insn_bitReg(s, OPC_AND, a0, a1, a2); ++ } ++ break; ++ case INDEX_op_and_i64: ++ if (c2) { ++ tcg_out_insn_bit(s, OPC_AND_I, OPC_AND, a0, a1, a2); ++ } else { ++ tcg_out_insn_bitReg(s, OPC_AND, a0, a1, a2); ++ } ++ break; ++ case INDEX_op_andc_i32: ++ a2 = (int32_t)a2; ++ tcg_debug_assert(0); ++ if (c2) { ++ tcg_out_insn_bit(s, OPC_AND_I, OPC_AND, a0, a1, ~a2); ++ } else { ++ tcg_out_insn_bitReg(s, OPC_BIC, a0, a1, a2); ++ } ++ break; ++ case INDEX_op_andc_i64: ++ tcg_debug_assert(0); ++ if (c2) { ++ tcg_out_insn_bit(s, OPC_AND_I, OPC_AND, a0, a1, ~a2); ++ } else { ++ tcg_out_insn_bitReg(s, OPC_BIC, a0, a1, a2); ++ } ++ break; ++ ++ case INDEX_op_or_i32: ++ a2 = (int32_t)a2; ++ if (c2) { ++ tcg_out_insn_bit(s, OPC_BIS_I, OPC_BIS, a0, a1, a2); ++ } else { ++ tcg_out_insn_bitReg(s, OPC_BIS, a0, a1, a2); ++ } ++ break; ++ case INDEX_op_or_i64: ++ if (c2) { ++ tcg_out_insn_bit(s, OPC_BIS_I, OPC_BIS, a0, a1, a2); ++ } else { ++ tcg_out_insn_bitReg(s, OPC_BIS, a0, a1, a2); ++ } ++ break; ++ ++ case INDEX_op_orc_i32: ++ a2 = (int32_t)a2; ++ tcg_debug_assert(0); ++ if (c2) { ++ tcg_out_insn_bit(s, OPC_BIS_I, OPC_BIS, a0, a1, ~a2); ++ } else { ++ tcg_out_insn_bitReg(s, OPC_ORNOT, a0, a1, a2); ++ } ++ break; ++ case INDEX_op_orc_i64: ++ tcg_debug_assert(0); ++ if (c2) { ++ tcg_out_insn_bit(s, OPC_BIS_I, OPC_BIS, a0, a1, ~a2); ++ } else { ++ tcg_out_insn_bitReg(s, OPC_ORNOT, a0, a1, a2); ++ } ++ break; ++ ++ case INDEX_op_xor_i32: ++ a2 = (int32_t)a2; ++ if (c2) { ++ tcg_out_insn_bit(s, OPC_XOR_I, OPC_XOR, a0, a1, a2); ++ } else { ++ tcg_out_insn_bitReg(s, OPC_XOR, a0, a1, a2); ++ } ++ break; ++ case INDEX_op_xor_i64: ++ if (c2) { ++ tcg_out_insn_bit(s, OPC_XOR_I, OPC_XOR, a0, a1, a2); ++ } else { ++ tcg_out_insn_bitReg(s, OPC_XOR, a0, a1, a2); ++ } ++ break; ++ ++ case INDEX_op_eqv_i32: ++ a2 = (int32_t)a2; ++ tcg_debug_assert(0); ++ if (c2) { ++ tcg_out_insn_bit(s, OPC_XOR_I, OPC_XOR, a0, a1, ~a2); ++ } else { ++ tcg_out_insn_bitReg(s, OPC_EQV, a0, a1, a2); ++ } ++ break; ++ ++ case INDEX_op_eqv_i64: ++ tcg_debug_assert(0); ++ if (c2) { ++ tcg_out_insn_bit(s, OPC_XOR_I, OPC_XOR, a0, a1, ~a2); ++ } else { ++ tcg_out_insn_bitReg(s, OPC_EQV, a0, a1, a2); ++ } ++ break; ++ ++ case INDEX_op_not_i64: ++ case INDEX_op_not_i32: ++ tcg_out_insn_bitReg(s, OPC_ORNOT, a0, TCG_REG_ZERO, a1); ++ break; ++ ++ case INDEX_op_mul_i64: ++ case INDEX_op_mul_i32: ++ tcg_out_insn_simpleReg(s, OPC_MULL, a0, a1, a2); ++ break; ++ ++ case INDEX_op_div_i64: /* a0=a1/a2 singed divide*/ ++ case INDEX_op_div_i32: ++ tcg_debug_assert(0); ++ break; ++ case INDEX_op_divu_i64: /* a0=a1/a2 unsigned divide */ ++ case INDEX_op_divu_i32: ++ tcg_debug_assert(0); ++ break; ++ ++ case INDEX_op_rem_i64: /* if a1=17,a2=4, 17/4=4...1, a0=1 */ ++ case INDEX_op_rem_i32: ++ tcg_debug_assert(0); ++ break; ++ case INDEX_op_remu_i64: ++ case INDEX_op_remu_i32: ++ tcg_debug_assert(0); ++ break; ++ ++ case INDEX_op_shl_i64: ++ case INDEX_op_shl_i32: /* sw logical left*/ ++ if (c2) { ++ int bits = ext ? 64 : 32; ++ int max = bits - 1; ++ tcg_out_insn_bitImm(s, OPC_SLL_I, a0, a1, a2&max); ++ } else { ++ tcg_out_insn_bitReg(s, OPC_SLL, a0, a1, a2); ++ } ++ break; ++ ++ case INDEX_op_shr_i64: ++ case INDEX_op_shr_i32: /* sw logical right */ ++ if (c2) { ++ int bits = ext ? 64 : 32; ++ int max = bits - 1; ++ tcg_out_insn_bitImm(s, OPC_SRL_I, a0, a1, a2&max); ++ } else { ++ tcg_out_insn_bitReg(s, OPC_SRL, a0, a1, a2); ++ } ++ break; ++ ++ case INDEX_op_sar_i64: ++ case INDEX_op_sar_i32: /* sw arithmetic right*/ ++ if (c2) { ++ int bits = ext ? 64 : 32; ++ int max = bits - 1; ++ tcg_out_insn_bitImm(s, OPC_SRA_I, a0, a1, a2&max); ++ } else { ++ tcg_out_insn_bitReg(s, OPC_SRA, a0, a1, a2); ++ } ++ break; ++ ++ case INDEX_op_rotr_i64: ++ case INDEX_op_rotr_i32: /* loop shift */ ++ if (c2) {/* loop right shift a2*/ ++ tcg_out_rotr_Imm(s, ext, a0, a1, a2); ++ } else { ++ tcg_out_rotr_Reg(s, ext, a0, a1, a2); ++ } ++ break; ++ ++ case INDEX_op_rotl_i64: ++ case INDEX_op_rotl_i32: /* loop shift */ ++ if (c2) {/* loop left shift a2*/ ++ tcg_out_rotl_Imm(s, ext, a0, a1, a2); ++ } else { ++ tcg_out_rotl_Reg(s, ext, a0, a1, a2); ++ } ++ break; ++ ++ case INDEX_op_clz_i64: /* counting leading zero numbers */ ++ case INDEX_op_clz_i32: ++ tcg_out_cltz(s, OPC_CTLZ, ext, a0, a1, a2, c2); ++ break; ++ case INDEX_op_ctz_i64: /* counting tailing zero numbers */ ++ case INDEX_op_ctz_i32: ++ tcg_out_cltz(s, OPC_CTTZ, ext, a0, a1, a2, c2); ++ break; ++ ++ case INDEX_op_brcond_i32: ++ a1 = (int32_t)a1; ++ tcg_out_brcond(s, ext, a2, a0, a1, const_args[1], arg_label(args[3])); ++ break; ++ ++ case INDEX_op_brcond_i64: ++ tcg_out_brcond(s, ext, a2, a0, a1, const_args[1], arg_label(args[3])); ++ break; ++ ++ case INDEX_op_setcond_i32: ++ a2 = (int32_t)a2; ++ tcg_out_setcond(s, args[3], a0, a1, a2); ++ break; ++ ++ case INDEX_op_setcond_i64: ++ tcg_out_setcond(s, args[3], a0, a1, a2); ++ break; ++ ++ case INDEX_op_movcond_i32: ++ a2 = (int32_t)a2; ++ tcg_out_movcond(s, args[5], a0, a1, a2, c2, REG0(3), REG0(4)); ++ break; ++ ++ /* FALLTHRU */ ++ case INDEX_op_movcond_i64: ++ tcg_out_movcond(s, args[5], a0, a1, a2, c2, REG0(3), REG0(4)); ++ break; ++ ++ case INDEX_op_qemu_ld_i32: ++ case INDEX_op_qemu_ld_i64: ++ tcg_out_qemu_ld(s, a0, a1, a2, ext); ++ break; ++ case INDEX_op_qemu_st_i32: ++ case INDEX_op_qemu_st_i64: ++ tcg_out_qemu_st(s, REG0(0), a1, a2); ++ break; ++ ++ case INDEX_op_bswap64_i64: /* 0x123456789abcdef--->0xefcdab8967452301 */ ++ tcg_debug_assert(0); ++ tcg_out_bswap64(s, a0, a1); ++ break; ++ case INDEX_op_bswap32_i64: /* 0x123456789abcdef--->0x67452301efcdab89 */ ++ tcg_debug_assert(0); ++ tcg_out_bswap32u(s, a0, a1); ++ break; ++ case INDEX_op_bswap32_i32: ++ tcg_debug_assert(0); ++ break; ++ case INDEX_op_bswap16_i64: /* 0x123456789abcdef--->0x23016745ab89efcd */ ++ case INDEX_op_bswap16_i32: ++ tcg_debug_assert(0); ++ break; ++ ++ case INDEX_op_ext8s_i64: ++ case INDEX_op_ext8s_i32: ++ tcg_out_insn_simpleReg(s, OPC_SEXTB, a0, TCG_REG_ZERO, a1); ++ break; ++ case INDEX_op_ext16s_i64: ++ case INDEX_op_ext16s_i32: ++ tcg_out_insn_simpleReg(s, OPC_SEXTH, a0, TCG_REG_ZERO, a1); ++ break; ++ case INDEX_op_ext_i32_i64: ++ case INDEX_op_ext32s_i64: ++ tcg_out_insn_simpleReg(s, OPC_ADDW, a0, TCG_REG_ZERO, a1); ++ break; ++ case INDEX_op_ext8u_i64: ++ case INDEX_op_ext8u_i32: ++ tcg_out_insn_simpleImm(s, OPC_EXT0B_I, a0, a1, 0x0); ++ break; ++ case INDEX_op_ext16u_i64: ++ case INDEX_op_ext16u_i32: ++ tcg_out_insn_simpleImm(s, OPC_EXT1B_I, a0, a1, 0x0); ++ break; ++ case INDEX_op_extu_i32_i64: ++ case INDEX_op_ext32u_i64: ++ tcg_out_movr(s, TCG_TYPE_I32, a0, a1); ++ break; ++ ++ case INDEX_op_deposit_i64: ++ case INDEX_op_deposit_i32: ++ tcg_out_dep(s, a0, a2, args[3], args[4]); ++ break; ++ ++ case INDEX_op_extract_i64: ++ case INDEX_op_extract_i32: ++ tcg_out_extract(s, a0, a1, a2, args[3]); ++ break; ++ ++ case INDEX_op_sextract_i64: ++ case INDEX_op_sextract_i32: ++ tcg_debug_assert(0); ++ break; ++ ++ case INDEX_op_extract2_i64: ++ case INDEX_op_extract2_i32: /* extract REG0(2) right args[3] bit to REG0(1) left ,save to a0*/ ++ tcg_debug_assert(0); ++ break; ++ ++ case INDEX_op_add2_i32: ++ tcg_debug_assert(0); ++ break; ++ case INDEX_op_add2_i64: ++ tcg_debug_assert(0); ++ break; ++ case INDEX_op_sub2_i32: ++ tcg_debug_assert(0); ++ break; ++ case INDEX_op_sub2_i64: ++ tcg_debug_assert(0); ++ break; ++ ++ case INDEX_op_muluh_i64: ++ tcg_out_insn_simpleReg(s, OPC_UMULH, a0, a1, a2); ++ break; ++ case INDEX_op_mulsh_i64: /* sw not support */ ++ tcg_out_mulsh64(s, a0, a1, a2); ++ break; ++ ++ case INDEX_op_mb: ++ break; ++ ++ case INDEX_op_mov_i32: /* Always emitted via tcg_out_mov. */ ++ case INDEX_op_mov_i64: ++ case INDEX_op_call: /* Always emitted via tcg_out_call. */ ++ default: ++ g_assert_not_reached(); ++ } ++ ++#undef REG0 ++} ++ ++ ++ ++/*sw ++* counting heading/tailing zero numbers ++*/ ++static void tcg_out_cltz(TCGContext *s, SW_64Insn opc_clz, TCGType ext, TCGReg rd, ++ TCGReg rn, TCGArg b, bool const_b) ++{ ++ /* cond1. b is a const, and b=64 or b=32 */ ++ if (const_b && b == (ext ? 64 : 32)) { ++ /* count rn zero numbers, and writes to rd */ ++ tcg_out_insn_simpleReg(s, opc_clz, rd, TCG_REG_ZERO, rn); ++ }else { ++ /* TCG_REG_TMP= counting rn heading/tailing zero numbers */ ++ tcg_out_insn_simpleReg(s, opc_clz, TCG_REG_TMP, TCG_REG_ZERO, rn); ++ ++ if (const_b) { ++ if (b == -1) { ++ /* cond2. b is const and b=-1 */ ++ /* if rn != 0 , rd= counting rn heading/tailing zero numbers, else rd = 0xffffffffffffffff*/ ++ tcg_out_insn_bitReg(s, OPC_ORNOT, TCG_REG_TMP2, TCG_REG_ZERO, TCG_REG_ZERO); ++ tcg_out_insn_complexReg(s, OPC_SELNE, rn, rd, TCG_REG_TMP, TCG_REG_TMP2); ++ } ++ else if (b == 0) { ++ /* cond3. b is const and b=0 */ ++ /* if rn != 0 , rd=counting rn heading/tailing zero numbers , else rd = TCG_REG_ZERO */ ++ tcg_out_insn_complexReg(s, OPC_SELNE, rn, rd, TCG_REG_TMP, TCG_REG_ZERO); ++ } else { ++ /* cond4. b is const */ ++ tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_TMP2, b); ++ /* if rn != 0 , rd=counting rn heading/tailing zero numbers , else mov b to rd */ ++ tcg_out_insn_complexReg(s, OPC_SELNE, rn, rd, TCG_REG_TMP, TCG_REG_TMP2); ++ } ++ } ++ else { ++ /* if b is register */ ++ tcg_out_insn_complexReg(s, OPC_SELNE, rn, rd, TCG_REG_TMP, b); ++ } ++ } ++} ++ ++/*sw ++ * unsigned 16bit, ab->ba ++ */ ++static inline void tcg_out_bswap16u(TCGContext *s, TCGReg rd, TCGReg rn) ++{ ++ TCGReg TCG_TMP0 = rn; ++ TCGReg TCG_TMP1 = rd; ++ /*t1=00b0*/ ++ tcg_out_insn_bitImm(s, OPC_SLL_I, TCG_TMP1, TCG_TMP0, 8); ++ /*t1=(0000)000a*/ ++ tcg_out_insn_bitImm(s, OPC_SRL_I, TCG_TMP0, TCG_TMP0, 8); ++ tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, TCG_TMP0, TCG_TMP0, 0x1); ++ /*t1=ooba*/ ++ tcg_out_insn_simpleReg(s, OPC_BIS, TCG_TMP1, TCG_TMP1, TCG_TMP0); ++} ++ ++/*sw ++ * signed 16bit, ab->ssba ++ */ ++static inline void tcg_out_bswap16s(TCGContext *s, TCGReg rd, TCGReg rn) ++{ ++ TCGReg TCG_TMP0 = rn; ++ TCGReg TCG_TMP1 = TCG_REG_TMP; ++ TCGReg TCG_TMP2 = rn; ++ /*t1=(ssss)ssb0*/ ++ tcg_out_insn_bitImm(s, OPC_SLL_I, TCG_TMP1, TCG_TMP0, 8); ++ tcg_out_insn_simpleImm(s, OPC_ZAP_I, TCG_TMP1, TCG_TMP1, 0x2); ++ tcg_out_insn_simpleReg(s, OPC_SEXTH, TCG_TMP1, TCG_REG_ZERO, TCG_TMP1); ++ /*t2=(0000)000a*/ ++ tcg_out_insn_bitImm(s, OPC_SRL_I, TCG_TMP2, TCG_TMP0, 8); ++ tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, TCG_TMP2, TCG_TMP2, 0x1); ++ /*t2=(ssss)ssba*/ ++ tcg_out_insn_simpleReg(s, OPC_BIS, TCG_TMP1, TCG_TMP1, TCG_TMP2); ++} ++ ++ ++/*sw ++ * signed 32bit, abcd -> ssdcba ++ */ ++static inline void tcg_out_bswap32s(TCGContext *s, TCGReg rd, TCGReg rn) ++{ ++ TCGReg TCG_TMP0 = rn; ++ TCGReg TCG_TMP3 = rd; ++ TCGReg TCG_TMP1 = TCG_REG_TMP; ++ TCGReg TCG_TMP2 = TCG_REG_TMP2; ++ /*swap32 -- 32-bit swap. a0 = abcd.*/ ++ ++ /* t3 = (ssss)d000 */ ++ tcg_out_insn_bitImm(s, OPC_SLL_I, TCG_TMP3, TCG_TMP0, 24); ++ tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, TCG_TMP3, TCG_TMP3, 0x0f); ++ tcg_out_insn_simpleReg(s, OPC_SEXTB, TCG_TMP1, TCG_REG_ZERO, TCG_TMP0); ++ tcg_out_insn_simpleImm(s, OPC_ZAP_I, TCG_TMP1, TCG_TMP1, 0x0f); ++ tcg_out_insn_bitReg(s, OPC_BIS, TCG_TMP3, TCG_TMP3, TCG_TMP1); ++ ++ /* t1 = 000a */ ++ tcg_out_insn_bitImm(s, OPC_SRL_I, TCG_TMP1, TCG_TMP0, 24); ++ tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, TCG_TMP1, TCG_TMP1, 0x1); ++ ++ /* t2 = 00c0 */ ++ tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, TCG_TMP2, TCG_TMP0, 0x2); ++ ++ /* t3 = (ssss)d00a */ ++ tcg_out_insn_bitReg(s, OPC_BIS, TCG_TMP3, TCG_TMP3, TCG_TMP1); ++ ++ /* t1 = 0abc */ ++ tcg_out_insn_bitImm(s, OPC_SRL_I, TCG_TMP1, TCG_TMP0, 8); ++ tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, TCG_TMP1, TCG_TMP1, 0x7); ++ ++ /* t2 = 0c00 */ ++ tcg_out_insn_bitImm(s, OPC_SLL_I, TCG_TMP2, TCG_TMP2, 8); ++ /* t1 = 00b0 */ ++ tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, TCG_TMP1, TCG_TMP1, 0x2); ++ /* t3 = (ssss)dc0a */ ++ tcg_out_insn_bitReg(s, OPC_BIS, TCG_TMP3, TCG_TMP3, TCG_TMP2); ++ /* t3 = (ssss)dcba -- delay slot */ ++ tcg_out_insn_bitReg(s, OPC_BIS, TCG_TMP3, TCG_TMP3, TCG_TMP1); ++} ++ ++/*sw ++ * unsigned 32bit, abcd->dcba ++ */ ++static void tcg_out_bswap32u(TCGContext *s, TCGReg rd, TCGReg rn) ++{ ++ TCGReg TCG_TMP0 = rn; ++ TCGReg TCG_TMP3 = rd; ++ TCGReg TCG_TMP1 = TCG_REG_TMP; ++ TCGReg TCG_TMP2 = TCG_REG_TMP2; ++ ++ /*bswap32u -- unsigned 32-bit swap. a0 = ....abcd.*/ ++ /* t1 = (0000)000d */ ++ tcg_out_insn_bitImm(s, OPC_AND_I, TCG_TMP1, TCG_TMP0, 0xff); ++ /* t3 = 000a */ ++ tcg_out_insn_bitImm(s, OPC_SRL_I, TCG_TMP3, TCG_TMP0, 24); ++ tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, TCG_TMP3, TCG_TMP3, 0x1); ++ /* t1 = (0000)d000 */ ++ tcg_out_insn_bitImm(s, OPC_SLL_I, TCG_TMP1, TCG_TMP1, 24); ++ /* t2 = 00c0 */ ++ tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, TCG_TMP2, TCG_TMP0, 0x2); ++ /* t3 = d00a */ ++ tcg_out_insn_bitReg(s, OPC_BIS, TCG_TMP3, TCG_TMP3, TCG_TMP1); ++ /* t1 = 0abc */ ++ tcg_out_insn_bitImm(s, OPC_SRL_I, TCG_TMP1, TCG_TMP0, 8); ++ tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, TCG_TMP1, TCG_TMP1, 0x7); ++ /* t2 = 0c00 */ ++ tcg_out_insn_bitImm(s, OPC_SLL_I, TCG_TMP2, TCG_TMP2, 8); ++ /* t1 = 00b0 */ ++ tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, TCG_TMP1, TCG_TMP1, 0x2); ++ /* t3 = dc0a */ ++ tcg_out_insn_bitReg(s, OPC_BIS, TCG_TMP3, TCG_TMP3, TCG_TMP2); ++ /* t3 = dcba -- delay slot */ ++ tcg_out_insn_bitReg(s, OPC_BIS, TCG_TMP3, TCG_TMP3, TCG_TMP1); ++} ++ ++ ++ ++/*sw ++ * swap 64bit, abcdefgh->hgfedcba ++ */ ++static void tcg_out_bswap64(TCGContext *s, TCGReg rd, TCGReg rn) ++{ ++ ++ TCGReg TCG_TMP0 = rn; ++ TCGReg TCG_TMP3 = rd; ++ TCGReg TCG_TMP1 = TCG_REG_TMP; ++ TCGReg TCG_TMP2 = TCG_REG_TMP2; ++ ++ /* bswap64 -- 64-bit swap. a0 = abcdefgh*/ ++ ++ /* t3 = h0000000 */ ++ tcg_out_insn_bitImm(s, OPC_SLL_I, TCG_TMP3, TCG_TMP0, 56); ++ /* t1 = 0000000a */ ++ tcg_out_insn_bitImm(s, OPC_SRL_I, TCG_TMP1, TCG_TMP0, 56); ++ /* t2 = 000000g0 */ ++ tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, TCG_TMP2, TCG_TMP0, 0x2); ++ /* t3 = h000000a */ ++ tcg_out_insn_bitReg(s, OPC_BIS, TCG_TMP3, TCG_TMP3, TCG_TMP1); ++ /* t1 = 00000abc */ ++ tcg_out_insn_bitImm(s, OPC_SRL_I, TCG_TMP1, TCG_TMP0, 40); ++ /* t2 = 0g000000 */ ++ tcg_out_insn_bitImm(s, OPC_SLL_I, TCG_TMP2, TCG_TMP2, 40); ++ /* t1 = 000000b0 */ ++ tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, TCG_TMP1, TCG_TMP1, 0x2); ++ /* t3 = hg00000a */ ++ tcg_out_insn_bitReg(s, OPC_BIS, TCG_TMP3, TCG_TMP3, TCG_TMP2); ++ /* t2 = 0000abcd */ ++ tcg_out_insn_bitImm(s, OPC_SRL_I, TCG_TMP2, TCG_TMP0, 32); ++ /* t3 = hg0000ba */ ++ tcg_out_insn_bitReg(s, OPC_BIS, TCG_TMP3, TCG_TMP3, TCG_TMP1); ++ /* t1 = 000000c0 */ ++ tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, TCG_TMP1, TCG_TMP2, 0x2); ++ /* t2 = 0000000d */ ++ tcg_out_insn_bitImm(s, OPC_AND_I, TCG_TMP2, TCG_TMP2, 0xff); ++ /* t1 = 00000c00 */ ++ tcg_out_insn_bitImm(s, OPC_SLL_I, TCG_TMP1, TCG_TMP1, 8); ++ /* t2 = 0000d000 */ ++ tcg_out_insn_bitImm(s, OPC_SLL_I, TCG_TMP2, TCG_TMP2, 24); ++ /* t3 = hg000cba */ ++ tcg_out_insn_bitReg(s, OPC_BIS, TCG_TMP3, TCG_TMP3, TCG_TMP1); ++ /* t1 = 00abcdef */ ++ tcg_out_insn_bitImm(s, OPC_SRL_I, TCG_TMP1, TCG_TMP0, 16); ++ /* t3 = hg00dcba */ ++ tcg_out_insn_bitReg(s, OPC_BIS, TCG_TMP3, TCG_TMP3, TCG_TMP2); ++ /* t2 = 0000000f */ ++ tcg_out_insn_bitImm(s, OPC_AND_I, TCG_TMP2, TCG_TMP1, 0xff); ++ /* t1 = 000000e0 */ ++ tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, TCG_TMP1, TCG_TMP1, 0x2); ++ /* t2 = 00f00000 */ ++ tcg_out_insn_bitImm(s, OPC_SLL_I, TCG_TMP2, TCG_TMP2, 40); ++ /* t1 = 000e0000 */ ++ tcg_out_insn_bitImm(s, OPC_SLL_I, TCG_TMP1, TCG_TMP1, 24); ++ /* t3 = hgf0dcba */ ++ tcg_out_insn_bitReg(s, OPC_BIS, TCG_TMP3, TCG_TMP3, TCG_TMP2); ++ /* t3 = hgfedcba -- delay slot */ ++ tcg_out_insn_bitReg(s, OPC_BIS, TCG_TMP3, TCG_TMP3, TCG_TMP1); ++ ++} ++ ++static void tcg_out_qemu_ld(TCGContext *s, TCGReg data_reg, TCGReg addr_reg, MemOpIdx oi, TCGType ext) ++{ ++#ifndef CONFIG_SOFTMMU ++ MemOp memop = get_memop(oi); ++ const TCGType otype = TCG_TYPE_I64; ++ ++ if (USE_GUEST_BASE) { ++ tcg_out_insn_simpleReg(s, OPC_ADDL, TCG_REG_GUEST_BASE, TCG_REG_GUEST_BASE, addr_reg); ++ tcg_out_qemu_ld_direct(s, memop, data_reg, TCG_REG_GUEST_BASE, otype, 0); ++ } else { ++ tcg_out_qemu_ld_direct(s, memop, data_reg, addr_reg, TCG_TYPE_I64, 0); ++ } ++#endif /* CONFIG_SOFTMMU */ ++ ++} ++ ++static void tcg_out_qemu_st(TCGContext *s, TCGReg data_reg, TCGReg addr_reg, ++ MemOpIdx oi) ++{ ++#ifndef CONFIG_SOFTMMU ++ MemOp memop = get_memop(oi); ++ const TCGType otype = TCG_TYPE_I64; ++ ++ if (USE_GUEST_BASE) { ++ tcg_out_insn_simpleReg(s, OPC_ADDL, TCG_REG_GUEST_BASE, TCG_REG_GUEST_BASE, addr_reg); ++ tcg_out_qemu_st_direct(s, memop, data_reg, TCG_REG_GUEST_BASE, otype, 0); ++ } else { ++ tcg_out_qemu_st_direct(s, memop, data_reg, addr_reg, TCG_TYPE_I64, 0); ++ } ++#endif /* CONFIG_SOFTMMU */ ++} ++ ++ ++/*sw ++ * if cond is successful, ret=1, otherwise ret = 0 ++ */ ++static void tcg_out_setcond(TCGContext *s, TCGCond cond, TCGReg ret, ++ TCGReg arg1, TCGReg arg2) ++{ ++ switch(cond) { ++ case TCG_COND_EQ: ++ case TCG_COND_LT: ++ case TCG_COND_LE: ++ case TCG_COND_LTU: ++ case TCG_COND_LEU: ++ case TCG_COND_NE: ++ case TCG_COND_GE: ++ case TCG_COND_GT: ++ case TCG_COND_GEU: ++ case TCG_COND_GTU: ++ tcg_out_cond_cmp(s, cond, ret, arg1, arg2, 0); ++ break; ++ default: ++ tcg_abort(); ++ break; ++ } ++} ++/*sw ++ * cond(a1,a2), yes:v1->ret, no:v2->ret ++ */ ++static void tcg_out_movcond(TCGContext *s, TCGCond cond, TCGReg ret, ++ TCGReg a1, TCGReg a2, bool const_b, TCGReg v1, TCGReg v2) ++{ ++ tcg_out_cond_cmp(s, cond, TCG_REG_TMP, a1, a2, const_b); ++ tcg_out_insn_complexReg(s, OPC_SELLBS, TCG_REG_TMP, ret, v1, v2); ++} ++ ++ ++ ++/*sw ++ * extract rn[lsb, lsb+len-1] -> rd[0, len-1] ++ */ ++static void tcg_out_extract(TCGContext *s, TCGReg rd, TCGReg rn, int lsb, int len) ++{ ++ //get 000..111..0000 ++ tcg_out_insn_bitReg(s, OPC_ORNOT, TCG_REG_TMP, TCG_REG_ZERO, TCG_REG_ZERO); ++ tcg_out_insn_bitImm(s, OPC_SRL_I, TCG_REG_TMP, TCG_REG_TMP, 64 - len); ++ tcg_out_insn_bitImm(s, OPC_SLL_I, TCG_REG_TMP, TCG_REG_TMP, lsb); ++ /* get rn[lsb, lsb+len-1]-->rd[lsb, lsb+len-1] */ ++ tcg_out_insn_bitReg(s, OPC_AND, rd, rn, TCG_REG_TMP); ++ ++ /* rd[lsb, lsb+len-1] --> rd[0, len-1] */ ++ tcg_out_insn_bitImm(s, OPC_SRL_I, rd, rd, lsb); ++} ++ ++ ++/*sw ++ * depos: rd = rd[63:msb+1]:rn[msb,lsb]:rd[lsb-1,0] ++ * len = msb -lsb + 1 ++ */ ++static void tcg_out_dep(TCGContext *s, TCGReg rd, TCGReg rn, int lsb, int len) ++{ ++ ++ //get 000..111..0000 ++ tcg_out_insn_bitReg(s, OPC_ORNOT, TCG_REG_TMP, TCG_REG_ZERO, TCG_REG_ZERO); ++ tcg_out_insn_bitImm(s, OPC_SRL_I, TCG_REG_TMP, TCG_REG_TMP, 64 - len); ++ tcg_out_insn_bitImm(s, OPC_SLL_I, TCG_REG_TMP, TCG_REG_TMP, lsb); ++ ++ /* TCG_REG_TMP2 = rn[msb,lsb] */ ++ tcg_out_insn_bitImm(s, OPC_SLL_I, TCG_REG_TMP2, rn, 64-len); ++ tcg_out_insn_bitImm(s, OPC_SRL_I, TCG_REG_TMP2, TCG_REG_TMP2, 64-len-lsb); ++ ++ /* clear rd[msb,lsb] */ ++ tcg_out_insn_bitReg(s, OPC_BIC, rd, rd, TCG_REG_TMP); ++ /* rd = rd[63:msb+1]:rn[msb,lsb]:rd[lsb-1,0] */ ++ tcg_out_insn_bitReg(s, OPC_BIS, rd, rd, TCG_REG_TMP2); ++} ++ ++/*sw ++ * get val_s64(rn) * val_s64(rm) -> res_128 ++ * res[127:64] -> rd ++ * warn:maybe rd=rn or rm ++ */ ++static void tcg_out_mulsh64(TCGContext *s, TCGReg rd, TCGReg rn, TCGReg rm) ++{ ++ tcg_out_insn_simpleReg(s, OPC_UMULH, TCG_REG_TMP, rn, rm); ++ ++ tcg_out_insn_bitImm(s, OPC_SRL_I, TCG_REG_TMP2, rn, 63); ++ tcg_out_insn_complexReg(s, OPC_SELEQ, TCG_REG_TMP2, TCG_REG_TMP2, TCG_REG_ZERO, rm); ++ tcg_out_insn_simpleReg(s, OPC_SUBL, TCG_REG_TMP, TCG_REG_TMP, TCG_REG_TMP2); ++ ++ tcg_out_insn_bitImm(s, OPC_SRL_I, TCG_REG_TMP2, rm, 63); ++ tcg_out_insn_complexReg(s, OPC_SELEQ, TCG_REG_TMP2, TCG_REG_TMP2, TCG_REG_ZERO, rn); ++ tcg_out_insn_simpleReg(s, OPC_SUBL, rd, TCG_REG_TMP, TCG_REG_TMP2); ++} ++ ++typedef struct { ++ DebugFrameHeader h; ++ uint8_t fde_def_cfa[4]; ++ uint8_t fde_reg_ofs[8 * 2]; ++} DebugFrame; ++ ++#define ELF_HOST_MACHINE EM_SW_64 ++/* GDB doesn't appear to require proper setting of ELF_HOST_FLAGS, ++ which is good because they're really quite complicated for SW_64. */ ++ ++static const DebugFrame debug_frame = { ++ .h.cie.len = sizeof(DebugFrameCIE) - 4, /* length after .len member */ ++ .h.cie.id = -1, ++ .h.cie.version = 1, ++ .h.cie.code_align = 1, ++ .h.cie.data_align = -(TCG_TARGET_REG_BITS / 8) & 0x7f, /* sleb128 */ ++ .h.cie.return_column = TCG_REG_RA, ++ ++ /* Total FDE size does not include the "len" member. */ ++ .h.fde.len = sizeof(DebugFrame) - offsetof(DebugFrame, h.fde.cie_offset), ++ ++ .fde_def_cfa = { ++ 12, TCG_REG_SP, /* DW_CFA_def_cfa sp, ... */ ++ (FRAME_SIZE & 0x7f) | 0x80, /* ... uleb128 FRAME_SIZE */ ++ (FRAME_SIZE >> 7) ++ }, ++ .fde_reg_ofs = { ++ 0x80 + 14, 1, /* DW_CFA_offset, */ ++ 0x80 + 13, 2, /* DW_CFA_offset, */ ++ 0x80 + 12, 3, /* DW_CFA_offset, */ ++ 0x80 + 11, 4, /* DW_CFA_offset, */ ++ 0x80 + 10, 5, /* DW_CFA_offset, */ ++ 0x80 + 9, 6, /* DW_CFA_offset, */ ++ 0x80 + 26, 7, /* DW_CFA_offset, ra, -24 */ ++ 0x80 + 15, 8, /* DW_CFA_offset, fp, -8 */ ++ } ++}; ++ ++void tcg_register_jit(const void *buf, size_t buf_size) ++{ ++ tcg_register_jit_int(buf, buf_size, &debug_frame, sizeof(debug_frame)); ++} +diff --git a/tcg/sw64/tcg-target.h b/tcg/sw64/tcg-target.h +new file mode 100755 +index 0000000000..3093e4fece +--- /dev/null ++++ b/tcg/sw64/tcg-target.h +@@ -0,0 +1,123 @@ ++/* ++ * Initial TCG Implementation for sw_64 ++ * ++ */ ++ ++#ifndef SW_64_TCG_TARGET_H ++#define SW_64_TCG_TARGET_H ++ ++#define TCG_TARGET_INSN_UNIT_SIZE 4 ++ ++typedef enum { ++ TCG_REG_X0, TCG_REG_X1, TCG_REG_X2, TCG_REG_X3, ++ TCG_REG_X4, TCG_REG_X5, TCG_REG_X6, TCG_REG_X7, ++ TCG_REG_X8, TCG_REG_X9, TCG_REG_X10, TCG_REG_X11, ++ TCG_REG_X12, TCG_REG_X13, TCG_REG_X14, TCG_REG_X15, ++ TCG_REG_X16, TCG_REG_X17, TCG_REG_X18, TCG_REG_X19, ++ TCG_REG_X20, TCG_REG_X21, TCG_REG_X22, TCG_REG_X23, ++ TCG_REG_X24, TCG_REG_X25, TCG_REG_X26, TCG_REG_X27, ++ TCG_REG_X28, TCG_REG_X29, TCG_REG_X30, TCG_REG_X31, ++ ++ TCG_REG_F0=32, TCG_REG_F1, TCG_REG_F2, TCG_REG_F3, ++ TCG_REG_F4, TCG_REG_F5, TCG_REG_F6, TCG_REG_F7, ++ TCG_REG_F8, TCG_REG_F9, TCG_REG_F10, TCG_REG_F11, ++ TCG_REG_F12, TCG_REG_F13, TCG_REG_F14, TCG_REG_F15, ++ TCG_REG_F16, TCG_REG_F17, TCG_REG_F18, TCG_REG_F19, ++ TCG_REG_F20, TCG_REG_F21, TCG_REG_F22, TCG_REG_F23, ++ TCG_REG_F24, TCG_REG_F25, TCG_REG_F26, TCG_REG_F27, ++ TCG_REG_F28, TCG_REG_F29, TCG_REG_F30, TCG_REG_F31, ++ ++ /* Aliases. */ ++ TCG_REG_FP = TCG_REG_X15, ++ TCG_REG_RA = TCG_REG_X26, ++ TCG_REG_GP = TCG_REG_X29, ++ TCG_REG_SP = TCG_REG_X30, ++ TCG_REG_ZERO = TCG_REG_X31, ++ TCG_AREG0 = TCG_REG_X9, ++} TCGReg; ++ ++#define TCG_TARGET_NB_REGS 64 ++#define MAX_CODE_GEN_BUFFER_SIZE ((size_t)-1) ++ ++/* used for function call generation */ ++#define TCG_REG_CALL_STACK TCG_REG_SP ++#define TCG_TARGET_STACK_ALIGN 16 ++#define TCG_TARGET_CALL_ALIGN_ARGS 1 /*luo*/ ++#define TCG_TARGET_CALL_STACK_OFFSET 0 /*luo*/ ++#define TCG_TARGET_HAS_neg_i64 1 ++#define TCG_TARGET_HAS_direct_jump 0 ++#define TCG_TARGET_HAS_goto_ptr 1 ++#define TCG_TARGET_HAS_qemu_st8_i32 0 ++#define TCG_TARGET_HAS_not_i32 1 ++#define TCG_TARGET_HAS_neg_i32 1 ++#define TCG_TARGET_HAS_div_i32 1 ++#define TCG_TARGET_HAS_movcond_i32 1 ++#define TCG_TARGET_HAS_rem_i32 0 ++#define TCG_TARGET_HAS_rot_i32 1 ++#define TCG_TARGET_HAS_deposit_i32 1 ++#define TCG_TARGET_HAS_extract_i32 1 ++#define TCG_TARGET_HAS_sextract_i32 0 ++#define TCG_TARGET_HAS_extract2_i32 0 ++#define TCG_TARGET_HAS_add2_i32 0 ++#define TCG_TARGET_HAS_sub2_i32 0 ++#define TCG_TARGET_HAS_sub2_i32 0 ++#define TCG_TARGET_HAS_mulu2_i32 0 ++#define TCG_TARGET_HAS_muluh_i32 0 ++#define TCG_TARGET_HAS_muls2_i32 0 ++#define TCG_TARGET_HAS_not_i32 1 ++#define TCG_TARGET_HAS_mulsh_i32 0 ++#define TCG_TARGET_HAS_ext8s_i32 0 ++#define TCG_TARGET_HAS_ext16s_i32 0 ++#define TCG_TARGET_HAS_ext8u_i32 1 ++#define TCG_TARGET_HAS_ext16u_i32 1 ++#define TCG_TARGET_HAS_bswap16_i32 0 ++#define TCG_TARGET_HAS_bswap32_i32 0 ++#define TCG_TARGET_HAS_andc_i32 0 ++#define TCG_TARGET_HAS_eqv_i32 0 ++#define TCG_TARGET_HAS_nand_i32 0 ++#define TCG_TARGET_HAS_nor_i32 0 ++#define TCG_TARGET_HAS_clz_i32 0 ++#define TCG_TARGET_HAS_ctz_i32 0 ++#define TCG_TARGET_HAS_orc_i32 0 ++#define TCG_TARGET_HAS_ctpop_i32 0 ++#define TCG_TARGET_HAS_movcond_i64 1 ++#define TCG_TARGET_HAS_div_i64 1 ++#define TCG_TARGET_HAS_rem_i64 0 ++#define TCG_TARGET_HAS_div2_i64 0 ++#define TCG_TARGET_HAS_rot_i64 1 ++#define TCG_TARGET_HAS_deposit_i64 1 ++#define TCG_TARGET_HAS_extract_i64 1 ++#define TCG_TARGET_HAS_sextract_i64 0 ++#define TCG_TARGET_HAS_extract2_i64 0 ++#define TCG_TARGET_HAS_extrl_i64_i32 0 ++#define TCG_TARGET_HAS_extrh_i64_i32 0 ++#define TCG_TARGET_HAS_ext8s_i64 0 ++#define TCG_TARGET_HAS_ext16s_i64 0 ++#define TCG_TARGET_HAS_ext32s_i64 1 ++#define TCG_TARGET_HAS_ext8u_i64 1 ++#define TCG_TARGET_HAS_ext16u_i64 1 ++#define TCG_TARGET_HAS_ext32u_i64 1 ++#define TCG_TARGET_HAS_bswap16_i64 0 ++#define TCG_TARGET_HAS_bswap32_i64 0 ++#define TCG_TARGET_HAS_bswap64_i64 0 ++#define TCG_TARGET_HAS_not_i64 1 ++#define TCG_TARGET_HAS_andc_i64 0 ++#define TCG_TARGET_HAS_orc_i64 1 ++#define TCG_TARGET_HAS_eqv_i64 0 ++#define TCG_TARGET_HAS_nand_i64 0 ++#define TCG_TARGET_HAS_nor_i64 0 ++#define TCG_TARGET_HAS_clz_i64 1 ++#define TCG_TARGET_HAS_ctz_i64 1 ++#define TCG_TARGET_HAS_ctpop_i64 0 ++#define TCG_TARGET_HAS_add2_i64 0 ++#define TCG_TARGET_HAS_sub2_i64 0 ++#define TCG_TARGET_HAS_mulu2_i64 0 ++#define TCG_TARGET_HAS_muls2_i64 0 ++#define TCG_TARGET_HAS_muluh_i64 1 ++#define TCG_TARGET_HAS_mulsh_i64 1 ++#define TCG_TARGET_DEFAULT_MO (0) ++#define TCG_TARGET_HAS_MEMORY_BSWAP 0 ++/* optional instructions */ ++void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t); ++#define TCG_TARGET_NEED_POOL_LABELS ++#endif /* SW_64_TCG_TARGET_H */ +diff --git a/tcg/sw64/tcg-target.opc.h b/tcg/sw64/tcg-target.opc.h +new file mode 100755 +index 0000000000..bce30accd9 +--- /dev/null ++++ b/tcg/sw64/tcg-target.opc.h +@@ -0,0 +1,15 @@ ++/* ++ * Copyright (c) 2019 Linaro ++ * ++ * This work is licensed under the terms of the GNU GPL, version 2 or ++ * (at your option) any later version. ++ * ++ * See the COPYING file in the top-level directory for details. ++ * ++ * Target-specific opcodes for host vector expansion. These will be ++ * emitted by tcg_expand_vec_op. For those familiar with GCC internals, ++ * consider these to be UNSPEC with names. ++ */ ++ ++DEF(aa64_sshl_vec, 1, 2, 0, IMPLVEC) ++DEF(aa64_sli_vec, 1, 2, 1, IMPLVEC) +-- +2.27.0 +