diff --git a/configs/devices/sw64-softmmu/default.mak b/configs/devices/sw64-softmmu/default.mak new file mode 100644 index 0000000000000000000000000000000000000000..f76bbf6fddce09645df888b60de9c379481dbd99 --- /dev/null +++ b/configs/devices/sw64-softmmu/default.mak @@ -0,0 +1,19 @@ +# 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 +CONFIG_CORE4=y +CONFIG_ACPI=y +CONFIG_ACPI_MEMORY_HOTPLUG=y +CONFIG_ACPI_CPU_HOTPLUG = y +CONFIG_ACPI_SW64_PM=y +CONFIG_ACPI_PCI=y +CONFIG_MEM_DEVICE=y +CONFIG_DIMM=y +CONFIG_PCI_EXPRESS_GENERIC_BRIDGE=y diff --git a/configs/targets/sw64-linux-user.mak b/configs/targets/sw64-linux-user.mak new file mode 100644 index 0000000000000000000000000000000000000000..ae00665692470c2cf4352ec92e66785fa4b2c324 --- /dev/null +++ b/configs/targets/sw64-linux-user.mak @@ -0,0 +1,5 @@ +TARGET_ARCH=sw64 +TARGET_SYSTBL_ABI=common +TARGET_SYSTBL=syscall.tbl +TARGET_ALIGNED_ONLY=y +TARGET_XML_FILES= gdb-xml/sw64-core.xml diff --git a/configs/targets/sw64-softmmu.mak b/configs/targets/sw64-softmmu.mak new file mode 100644 index 0000000000000000000000000000000000000000..67351502572ee2829076c7656964799639aa1530 --- /dev/null +++ b/configs/targets/sw64-softmmu.mak @@ -0,0 +1,10 @@ +# Default configuration for sw64-softmmu + +# Boards: +# +TARGET_ARCH=sw64 +TARGET_BASE_ARCH=sw64 +TARGET_ABI_DIR=sw64 +TARGET_SUPPORTS_MTTCG=y +TARGET_XML_FILES= gdb-xml/sw64-core.xml +TARGET_NEED_FDT=y diff --git a/configure b/configure index 1f932f7eeb8c59f7f635659b12801366d3fbeb6a..6f4057f888667c5efb0a527b0f0747fc8f194af6 100755 --- a/configure +++ b/configure @@ -617,6 +617,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 @@ -1002,10 +1005,18 @@ for opt do ;; --disable-crypto-afalg) crypto_afalg="no" ;; + --disable-vt-iommu) vt_iommu="no" + ;; + --enable-vt-iommu) vt_iommu="yes" + ;; --disable-vhost-net) vhost_net="no" ;; --enable-vhost-net) vhost_net="yes" ;; + --disable-vt-memhp) vt_memhp="no" + ;; + --enable-vt-memhp) vt_memhp="yes" + ;; --disable-vhost-crypto) vhost_crypto="no" ;; --enable-vhost-crypto) vhost_crypto="yes" @@ -1443,6 +1454,8 @@ cat << EOF membarrier membarrier system call (for Linux 4.14+ or Windows) rdma Enable RDMA-based migration pvrdma Enable PVRDMA support + vt-iommu vt-iommu device support + vt_memhp vt-memhp support vhost-net vhost-net kernel acceleration support vhost-vsock virtio sockets device support vhost-scsi vhost-scsi kernel target support @@ -3273,6 +3286,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 @@ -3426,7 +3443,7 @@ else cxx= fi -if !(GIT="$git" "$source_path/scripts/git-submodule.sh" "$git_submodules_action" "$git_submodules"); then +if ! (GIT="$git" "$source_path/scripts/git-submodule.sh" "$git_submodules_action" "$git_submodules"); then exit 1 fi @@ -3539,6 +3556,12 @@ if test "$xen" = "enabled" ; then echo "XEN_CFLAGS=$xen_cflags" >> $config_host_mak echo "XEN_LIBS=$xen_libs" >> $config_host_mak fi +if test "$vt_iommu" = "yes" ; then + echo "CONFIG_SW64_VT_IOMMU=y" >> $config_host_mak +fi +if test "$vt_memhp" = "yes" ; then + echo "CONFIG_VT_MEMHOTPLUG=y" >> $config_host_mak +fi if test "$vhost_scsi" = "yes" ; then echo "CONFIG_VHOST_SCSI=y" >> $config_host_mak fi @@ -3859,7 +3882,10 @@ for bios_file in \ $source_path/pc-bios/u-boot.* \ $source_path/pc-bios/edk2-*.fd.bz2 \ $source_path/pc-bios/palcode-* \ - $source_path/pc-bios/qemu_vga.ndrv + $source_path/pc-bios/qemu_vga.ndrv \ + $source_path/pc-bios/*-reset \ + $source_path/pc-bios/*-hmcode \ + $source_path/pc-bios/*-sw do LINKS="$LINKS pc-bios/$(basename $bios_file)" diff --git a/disas.c b/disas.c index 3dab4482d1a1eeef0393f3c3efb4b54637270136..adc76d72b48ed65d7f9b6f03869972f4c7595ad3 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_sw64; #endif } diff --git a/disas/meson.build b/disas/meson.build index 06a69d9d726699414b5ddae566c12e2a468ec547..c337369cb1e8fde40b9f9d62ec973d02ddb1c951 100644 --- a/disas/meson.build +++ b/disas/meson.build @@ -21,4 +21,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 0000000000000000000000000000000000000000..0453d47d39f8fe4fd3edc59813b258bab4e67414 --- /dev/null +++ b/disas/sw64.c @@ -0,0 +1,1364 @@ +/* + * sw64-dis.c -- Disassemble SW64 instructions + * Copyright (C) 1996-2015 Free Software Foundation, Inc. + * Contributed by Richard Henderson , + * patterned after the PPC opcode handling written by Ian Lance Taylor. + * + * 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 sw64_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 sw64_opcode sw64_opcodes[]; +extern const unsigned sw64_num_opcodes; + +/* Values defined for the flags field of a struct sw64_opcode. */ + +/* CPU Availability */ +#define SW_OPCODE_BASE 0x0001 /* Base architecture insns. */ +#define SW_OPCODE_CORE3 0x0002 /* Core3 private insns. */ +#define SW_OPCODE_CORE4 0x0004 /* Core4 private insns. */ +#define SW_LITOP(i) (((i) >> 26) & 0x3D) + +#define SW_OPCODE_NOHMCODE (~(SW_OPCODE_BASE|SW_OPCODE_CORE3|SW_OPCODE_CORE4)) + +/* 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 sw64_operand. */ + +struct sw64_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 sw64_opcodes table. */ + +extern const struct sw64_operand sw64_operands[]; +extern const unsigned sw64_num_operands; +/* Values defined for the flags field of a struct sw64_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 + +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 operands table. */ + +const struct sw64_operand sw64_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, -BDISP, + 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, -JMPHINT, + 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 }, + + /* for the third operand of ternary operands integer insn. */ +#define R3 (HWINDEX + 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 }, +#define RPIINDEX (FMALIT + 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 sw64_num_operands = sizeof(sw64_operands) / sizeof(*sw64_operands); + +/* Macros used to form opcodes. */ + +/* The main opcode. */ +#define OP(x) (((uint32_t)(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 pri_rcsr,pri_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 +#define CORE4 SW_OPCODE_CORE4 + +/* 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_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 sw64_opcode sw64_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, { ZA, BDISP } }, + { "bsr", BRA(0x05), BASE, ARG_BRA }, + { "memb", MFC(0x06,0x0000), BASE, ARG_NONE }, + { "imemb", MFC(0x06,0x0001), BASE, ARG_NONE }, + { "wmemb", MFC(0x06,0x0002), CORE4, 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 } }, + { "csrrs", CSR(0x06,0xFC), CORE4, { RA, RPIINDEX, RB } }, + { "csrrc", CSR(0x06,0xFD), CORE4, { RA, RPIINDEX, RB } }, + { "csrr", CSR(0x06,0xFE), CORE4, { RA, RPIINDEX, ZB } }, + { "csrw", CSR(0x06,0xFF), CORE4, { 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 }, + { "divw", OPR(0x10,0x11), CORE4, ARG_OPR }, + { "udivw", OPR(0x10,0x12), CORE4, ARG_OPR }, + { "remw", OPR(0x10,0x13), CORE4, ARG_OPR }, + { "uremw", OPR(0x10,0x14), CORE4, ARG_OPR }, + { "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 }, + { "divl", OPR(0x10,0x1A), CORE4, ARG_OPR }, + { "udivl", OPR(0x10,0x1B), CORE4, ARG_OPR }, + { "reml", OPR(0x10,0x1C), CORE4, ARG_OPR }, + { "ureml", OPR(0x10,0x1D), CORE4, ARG_OPR }, + { "addpi", OPR(0x10,0x1E), CORE4, ARG_DISP13 }, + { "addpis", OPR(0x10,0x1F), CORE4, ARG_DISP13 }, + { "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 }, + { "sbt", OPR(0x10,0x2D), CORE4, ARG_OPR }, + { "sbt", OPRL(0x12,0x2D), CORE4, ARG_OPRL }, + { "cbt", OPR(0x10,0x2E), CORE4, ARG_OPR }, + { "cbt", OPRL(0x12,0x2E), CORE4, 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 }, + { "slll", OPR(0x10,0x48), CORE4, ARG_OPR }, + { "slll", OPRL(0x12,0x48),CORE4, ARG_OPRL }, + { "srll", OPR(0x10,0x49), CORE4, ARG_OPR }, + { "srll", OPRL(0x12,0x49),CORE4, ARG_OPRL }, + { "sral", OPR(0x10,0x4A), CORE4, ARG_OPR }, + { "sral", OPRL(0x12,0x4A),CORE4, ARG_OPRL }, + { "roll", OPR(0x10,0x4B), CORE4, ARG_OPR }, + { "roll", OPRL(0x12,0x4B),CORE4, ARG_OPRL }, + { "sllw", OPR(0x10,0x4C), CORE4, ARG_OPR }, + { "sllw", OPRL(0x12,0x4C),CORE4, ARG_OPRL }, + { "srlw", OPR(0x10,0x4D), CORE4, ARG_OPR }, + { "srlw", OPRL(0x12,0x4D),CORE4, ARG_OPRL }, + { "sraw", OPR(0x10,0x4E), CORE4, ARG_OPR }, + { "sraw", OPRL(0x12,0x4E),CORE4, ARG_OPRL }, + { "rolw", OPR(0x10,0x4F), CORE4, ARG_OPR }, + { "rolw", OPRL(0x12,0x4F),CORE4, 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 }, + { "revbh", OPR(0x10,0x5B), CORE4, ARG_OPRZ1 }, + { "revbw", OPR(0x10,0x5C), CORE4, ARG_OPRZ1 }, + { "revbl", OPR(0x10,0x5D), CORE4, ARG_OPRZ1 }, + { "casw", OPR(0x10,0x5E), CORE4, ARG_OPRCAS }, + { "casl", OPR(0x10,0x5F), CORE4, ARG_OPRCAS }, + { "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 }, + { "frecs", FP(0x18,0x58), CORE4, ARG_FPZ1 }, + { "frecd", FP(0x18,0x59), CORE4, ARG_FPZ1 }, + { "fris", FP(0x18,0x5A), CORE4, ARG_FPZ1 }, + { "fris_g", FP(0x18,0x5B), CORE4, ARG_FPZ1 }, + { "fris_p", FP(0x18,0x5C), CORE4, ARG_FPZ1 }, + { "fris_z", FP(0x18,0x5D), CORE4, ARG_FPZ1 }, + { "fris_n", FP(0x18,0x5F), CORE4, ARG_FPZ1 }, + { "frid", FP(0x18,0x60), CORE4, ARG_FPZ1 }, + { "frid_g", FP(0x18,0x61), CORE4, ARG_FPZ1 }, + { "frid_p", FP(0x18,0x62), CORE4, ARG_FPZ1 }, + { "frid_z", FP(0x18,0x63), CORE4, ARG_FPZ1 }, + { "frid_n", FP(0x18,0x64), CORE4, ARG_FPZ1 }, + { "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 }, + { "vsllb", FP(0x1A,0x10), CORE4, ARG_FP }, + { "vsllb", FP(0x1A,0x30), CORE4, ARG_FPL }, + { "vsrlb", FP(0x1A,0x11), CORE4, ARG_FP }, + { "vsrlb", FP(0x1A,0x31), CORE4, ARG_FPL }, + { "vsrab", FP(0x1A,0x12), CORE4, ARG_FP }, + { "vsrab", FP(0x1A,0x32), CORE4, ARG_FPL }, + { "vrolb", FP(0x1A,0x13), CORE4, ARG_FP }, + { "vrolb", FP(0x1A,0x33), CORE4, ARG_FPL }, + { "vsllh", FP(0x1A,0x14), CORE4, ARG_FP }, + { "vsllh", FP(0x1A,0x34), CORE4, ARG_FPL }, + { "vsrlh", FP(0x1A,0x15), CORE4, ARG_FP }, + { "vsrlh", FP(0x1A,0x35), CORE4, ARG_FPL }, + { "vsrah", FP(0x1A,0x16), CORE4, ARG_FP }, + { "vsrah", FP(0x1A,0x36), CORE4, ARG_FPL }, + { "vrolh", FP(0x1A,0x17), CORE4, ARG_FP }, + { "vrolh", FP(0x1A,0x37), CORE4, ARG_FPL }, + { "ctpopow", FP(0x1A,0x18), BASE, { FA, ZB, DFC1 } }, + { "ctlzow", FP(0x1A,0x19), BASE, { FA, ZB, DFC1 } }, + { "vslll", FP(0x1A,0x1A), CORE4, ARG_FP }, + { "vslll", FP(0x1A,0x3A), CORE4, ARG_FPL }, + { "vsrll", FP(0x1A,0x1B), CORE4, ARG_FP }, + { "vsrll", FP(0x1A,0x3B), CORE4, ARG_FPL }, + { "vsral", FP(0x1A,0x1C), CORE4, ARG_FP }, + { "vsral", FP(0x1A,0x3C), CORE4, ARG_FPL }, + { "vroll", FP(0x1A,0x1D), CORE4, ARG_FP }, + { "vroll", FP(0x1A,0x3D), CORE4, ARG_FPL }, + { "vmaxb", FP(0x1A,0x1E), CORE4, ARG_FP }, + { "vminb", FP(0x1A,0x1F), CORE4, ARG_FP }, + { "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 }, + { "sraow", FP(0x1A,0x46), CORE4, ARG_FP }, + { "sraow", FP(0x1A,0x66), CORE4, ARG_FPL }, + { "vsumw", FP(0x1A,0x47), CORE4, ARG_FPZ1 }, + { "vsuml", FP(0x1A,0x48), CORE4, ARG_FPZ1 }, + { "vcmpueqb", FP(0x1A,0x4B), CORE4, ARG_FP }, + { "vcmpueqb", FP(0x1A,0x6B), CORE4, ARG_FPL }, + { "vcmpugtb", FP(0x1A,0x4C), CORE4, ARG_FP }, + { "vcmpugtb", FP(0x1A,0x6C), CORE4, ARG_FPL }, + { "vmaxh", FP(0x1A,0x50), CORE4, ARG_FP }, + { "vminh", FP(0x1A,0x51), CORE4, ARG_FP }, + { "vmaxw", FP(0x1A,0x52), CORE4, ARG_FP }, + { "vminw", FP(0x1A,0x53), CORE4, ARG_FP }, + { "vmaxl", FP(0x1A,0x54), CORE4, ARG_FP }, + { "vminl", FP(0x1A,0x55), CORE4, ARG_FP }, + { "vumaxb", FP(0x1A,0x56), CORE4, ARG_FP }, + { "vuminb", FP(0x1A,0x57), CORE4, ARG_FP }, + { "vumaxh", FP(0x1A,0x58), CORE4, ARG_FP }, + { "vuminh", FP(0x1A,0x59), CORE4, ARG_FP }, + { "vumaxw", FP(0x1A,0x5A), CORE4, ARG_FP }, + { "vuminw", FP(0x1A,0x5B), CORE4, ARG_FP }, + { "vumaxl", FP(0x1A,0x5C), CORE4, ARG_FP }, + { "vuminl", FP(0x1A,0x5D), CORE4, ARG_FP }, + { "vsm3msw", FP(0x1A,0x67), CORE4, ARG_FP }, + { "vsm4key", FP(0x1A,0x68), CORE4, ARG_FPL }, + { "vsm4r", FP(0x1A,0x69), CORE4, ARG_FP }, + { "vbinvw", FP(0x1A,0x6A), CORE4, ARG_FPZ1 }, + { "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 }, + { "vsums", FP(0x1A,0x93), CORE4, ARG_FPZ1 }, + { "vsumd", FP(0x1A,0x94), CORE4, ARG_FPZ1 }, + { "vfcvtsd", FP(0x1A,0x95), CORE4, ARG_FPZ1 }, + { "vfcvtds", FP(0x1A,0x96), CORE4, ARG_FPZ1 }, + { "vfcvtls", FP(0x1A,0x99), CORE4, ARG_FPZ1 }, + { "vfcvtld", FP(0x1A,0x9A), CORE4, ARG_FPZ1 }, + { "vfcvtdl", FP(0x1A,0x9B), CORE4, ARG_FPZ1 }, + { "vfcvtdl_g", FP(0x1A,0x9C), CORE4, ARG_FPZ1 }, + { "vfcvtdl_p", FP(0x1A,0x9D), CORE4, ARG_FPZ1 }, + { "vfcvtdl_z", FP(0x1A,0x9E), CORE4, ARG_FPZ1 }, + { "vfcvtdl_n", FP(0x1A,0x9F), CORE4, ARG_FPZ1 }, + { "vfris", FP(0x1A,0xA0), CORE4, ARG_FPZ1 }, + { "vfris_g", FP(0x1A,0xA1), CORE4, ARG_FPZ1 }, + { "vfris_p", FP(0x1A,0xA2), CORE4, ARG_FPZ1 }, + { "vfris_z", FP(0x1A,0xA3), CORE4, ARG_FPZ1 }, + { "vfris_n", FP(0x1A,0xA4), CORE4, ARG_FPZ1 }, + { "vfrid", FP(0x1A,0xA5), CORE4, ARG_FPZ1 }, + { "vfrid_g", FP(0x1A,0xA6), CORE4, ARG_FPZ1 }, + { "vfrid_p", FP(0x1A,0xA7), CORE4, ARG_FPZ1 }, + { "vfrid_z", FP(0x1A,0xA8), CORE4, ARG_FPZ1 }, + { "vfrid_n", FP(0x1A,0xA9), CORE4, ARG_FPZ1 }, + { "vfrecs", FP(0x1A,0xAA), CORE4, ARG_FPZ1 }, + { "vfrecd", FP(0x1A,0xAB), CORE4, ARG_FPZ1 }, + { "vmaxs", FP(0x1A,0xAC), CORE4, ARG_FP }, + { "vmins", FP(0x1A,0xAD), CORE4, ARG_FP }, + { "vmaxd", FP(0x1A,0xAE), CORE4, ARG_FP }, + { "vmind", FP(0x1A,0xAF), CORE4, 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 }, + { "vinsb", FMA(0x1B,0x2A), CORE4, ARG_FMAL }, + { "vinsh", FMA(0x1B,0x2B), CORE4, ARG_FMAL }, + { "vinsectlh", FMA(0x1B,0x2C), CORE4, ARG_FMA }, + { "vinsectlw", FMA(0x1B,0x2D), CORE4, ARG_FMA }, + { "vinsectll", FMA(0x1B,0x2E), CORE4, ARG_FMA }, + { "vinsectlb", FMA(0x1B,0x2F), CORE4, ARG_FMA }, + { "vshfq", FMA(0x1B,0x30), CORE4, ARG_FMAL }, + { "vshfqb", FMA(0x1B,0x31), CORE4, ARG_FMA }, + { "vcpyb", FMA(0x1B,0x32), CORE4, { FA, DFC1 }}, + { "vcpyh", FMA(0x1B,0x33), CORE4, { FA, DFC1 }}, + { "vsm3r", FMA(0x1B,0x34), CORE4, ARG_FMAL }, + { "vfcvtsh", FMA(0x1B,0x35), CORE4, ARG_FMAL }, + { "vfcvths", FMA(0x1B,0x36), CORE4, {FA, FMALIT, FC} }, + { "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 }, + { "lbr", BRA(0x1D), CORE4, { BDISP26 }}, + { "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 sw64_num_opcodes = sizeof(sw64_opcodes) / sizeof(*sw64_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_sw64(bfd_vma memaddr, struct disassemble_info *info) +{ + static const struct sw64_opcode *opcode_index[SW_NOPS + 1]; + const char * const * regnames; + const struct sw64_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 = sw64_opcodes; + opcode_end = opcode + sw64_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_NOHMCODE; + switch (info->mach) { + case bfd_mach_sw64_core3: + isa_mask |= SW_OPCODE_BASE | SW_OPCODE_CORE3; + break; + case bfd_mach_sw64_core4: + isa_mask |= SW_OPCODE_BASE | SW_OPCODE_CORE4; + 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 sw64_operand *operand = sw64_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 sw64_operand *operand = sw64_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/gdb-xml/sw64-core.xml b/gdb-xml/sw64-core.xml new file mode 100644 index 0000000000000000000000000000000000000000..9498715e374d1cce827870aab2686ff71a172b19 --- /dev/null +++ b/gdb-xml/sw64-core.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/hw/Kconfig b/hw/Kconfig index ad20cce0a953ebba3f2ed0579d1305c4614a8193..5f3957be0f1812de7b78066558bd52a4266a342d 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/acpi/Kconfig b/hw/acpi/Kconfig index 2f2fb33a7b36b365fadbeaa278faa143d05f667f..aefe31628b7b31c039aadc6b7540d4ca3c472bd2 100644 --- a/hw/acpi/Kconfig +++ b/hw/acpi/Kconfig @@ -68,3 +68,11 @@ config ACPI_HW_REDUCED select ACPI select ACPI_MEMORY_HOTPLUG select ACPI_NVDIMM + +config ACPI_SW64_PM + bool + depends on ACPI + +config GPIO_SUNWAY + bool + depends on ACPI diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c index 65148d5b9d0b29b8c5742413df3bd53d35a59482..71b50a114e169e3cca9c9d52d0c3fa3690d0e457 100644 --- a/hw/acpi/aml-build.c +++ b/hw/acpi/aml-build.c @@ -1490,6 +1490,18 @@ Aml *aml_dword_io(AmlMinFixed min_fixed, AmlMaxFixed max_fixed, isa_ranges); } +Aml *aml_qword_io(AmlMinFixed min_fixed, AmlMaxFixed max_fixed, + AmlDecode dec, AmlISARanges isa_ranges, + uint64_t addr_gran, uint64_t addr_min, + uint64_t addr_max, uint64_t addr_trans, + uint64_t len) + +{ + return aml_qword_as_desc(AML_IO_RANGE, min_fixed, max_fixed, dec, + addr_gran, addr_min, addr_max, addr_trans, len, + isa_ranges); +} + /* * ACPI 1.0b: 6.4.3.5.4 ASL Macros for DWORD Address Space Descriptor * @@ -1724,9 +1736,9 @@ void acpi_table_begin(AcpiTable *desc, GArray *array) build_append_int_noprefix(array, 0, 4); /* Length */ build_append_int_noprefix(array, desc->rev, 1); /* Revision */ build_append_int_noprefix(array, 0, 1); /* Checksum */ - build_append_padded_str(array, desc->oem_id, 6, '\0'); /* OEMID */ + build_append_padded_str(array, desc->oem_id, 6, ' '); /* OEMID */ /* OEM Table ID */ - build_append_padded_str(array, desc->oem_table_id, 8, '\0'); + build_append_padded_str(array, desc->oem_table_id, 8, ' '); build_append_int_noprefix(array, 1, 4); /* OEM Revision */ g_array_append_vals(array, ACPI_BUILD_APPNAME8, 4); /* Creator ID */ build_append_int_noprefix(array, 1, 4); /* Creator Revision */ diff --git a/hw/acpi/gpio_sunway.c b/hw/acpi/gpio_sunway.c new file mode 100644 index 0000000000000000000000000000000000000000..70654f9b5ec8d9fc3a9690848500f1112db8e55b --- /dev/null +++ b/hw/acpi/gpio_sunway.c @@ -0,0 +1,258 @@ +/* + * Copyright (c) 2024 Wxiat Corporation + * Written by Wuyacheng + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2 or later, as published by the Free Software Foundation. + */ + +// SPDX-License-Identifier: GPL-2.0+ + +#include "qemu/osdep.h" +#include "exec/address-spaces.h" +#include "migration/vmstate.h" +#include "hw/sw64/gpio.h" +#include "hw/irq.h" + +static void sw64_gpio_update_int(SW64GPIOState *s) +{ + qemu_set_irq(s->irq[0], 1); +} + +static void sw64_gpio_set(void *opaque, int line, int level) +{ + SW64GPIOState *s = SW64_GPIO(opaque); + + sw64_gpio_update_int(s); +} + +static void sw64_gpio_write(void *opaque, hwaddr offset, uint64_t reg_value, + unsigned size) +{ + SW64GPIOState *s = SW64_GPIO(opaque); + reg_value = (uint32_t)reg_value; + + switch (offset) { + case GPIO_SWPORTA_DR: + s->padr = reg_value; + break; + case GPIO_SWPORTA_DDR: + s->paddr = reg_value ; + break; + case GPIO_INTEN: + s->inter = reg_value; + break; + case GPIO_INTMASK: + s->intmr = reg_value; + break; + case GPIO_INTTYPE_LEVEL: + s->intlr = reg_value; + break; + case GPIO_INTTYPE_POLA: + s->intpr = reg_value; + break; + case GPIO_INTTYPE_STATUS: + s->intsr = reg_value; + break; + case GPIO_RAW_INTTYPE_STATUS: + s->rintsr = reg_value; + break; + case GPIO_DEB_ENABLE: + s->deber = reg_value; + break; + case GPIO_CLEAN_INT: + s->clintr = reg_value; + break; + case GPIO_EXT_PORTA: + s->expar = reg_value; + break; + case GPIO_SYNC_LEVEL: + s->synlr = reg_value; + break; + case GPIO_ID_CODE: + s->idcr = reg_value; + break; + case GPIO_VERSION: + s->versionr = reg_value; + break; + case GPIO_CONF_R1: + s->conf1r = reg_value; + break; + case GPIO_CONF_R2: + s->conf2r = reg_value; + break; + default: + printf("error: Bad register at offset 0x%lx\n", offset); + } + + return; +} + +static uint64_t sw64_gpio_read(void *opaque, hwaddr offset, unsigned size) +{ + SW64GPIOState *s = SW64_GPIO(opaque); + uint32_t reg_value = 0; + + switch (offset) { + case GPIO_SWPORTA_DR: + reg_value = s->padr; + break; + case GPIO_SWPORTA_DDR: + reg_value = s->paddr; + break; + case GPIO_INTEN: + reg_value = s->inter; + break; + case GPIO_INTMASK: + reg_value = s->intmr; + break; + case GPIO_INTTYPE_LEVEL: + reg_value = s->intlr; + break; + case GPIO_INTTYPE_POLA: + reg_value = s->intpr; + break; + case GPIO_INTTYPE_STATUS: + reg_value = s->intsr; + break; + case GPIO_RAW_INTTYPE_STATUS: + reg_value = s->rintsr; + break; + case GPIO_DEB_ENABLE: + reg_value = s->deber; + break; + case GPIO_CLEAN_INT: + reg_value = s->clintr; + break; + case GPIO_EXT_PORTA: + reg_value = s->expar; + break; + case GPIO_SYNC_LEVEL: + reg_value = s->synlr; + break; + case GPIO_ID_CODE: + reg_value = s->idcr; + break; + case GPIO_VERSION: + reg_value = s->versionr; + break; + case GPIO_CONF_R1: + reg_value = s->conf1r; + break; + case GPIO_CONF_R2: + reg_value = s->conf2r; + break; + default: + printf("error: Bad register at offset 0x%lx\n", offset); + return (uint64_t)0; + } + + return (uint64_t)reg_value; +} + +static const VMStateDescription vmstate_sw64_gpio = { + .name = TYPE_SW64_GPIO, + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(padr, SW64GPIOState), + VMSTATE_UINT32(paddr, SW64GPIOState), + VMSTATE_UINT32(inter, SW64GPIOState), + VMSTATE_UINT32(intmr, SW64GPIOState), + VMSTATE_UINT32(intlr, SW64GPIOState), + VMSTATE_UINT32(intpr, SW64GPIOState), + VMSTATE_UINT32(intsr, SW64GPIOState), + VMSTATE_UINT32(rintsr, SW64GPIOState), + VMSTATE_UINT32(deber, SW64GPIOState), + VMSTATE_UINT32(clintr, SW64GPIOState), + VMSTATE_UINT32(expar, SW64GPIOState), + VMSTATE_UINT32(synlr, SW64GPIOState), + VMSTATE_UINT32(idcr, SW64GPIOState), + VMSTATE_UINT32(versionr, SW64GPIOState), + VMSTATE_UINT32(conf1r, SW64GPIOState), + VMSTATE_UINT32(conf2r, SW64GPIOState), + VMSTATE_END_OF_LIST() + } +}; + +static void sw64_gpio_reset(DeviceState *dev) +{ + SW64GPIOState *s = SW64_GPIO(dev); + + s->padr = 0; + s->paddr = 0; + s->inter = 0; + s->intmr = 0; + s->intlr = 0; + s->intpr = 0; + s->intsr = 0; + s->rintsr = 0; + s->deber = 0; + s->clintr = 0; + s->expar = 0; + s->synlr = 0; + s->idcr = 0; + s->versionr = 0; + s->conf1r = 0; + s->conf2r = 0; + + sw64_gpio_update_int(s); +} + +static const MemoryRegionOps sw64_gpio_ops = { + .read = sw64_gpio_read, + .write = sw64_gpio_write, + .valid.min_access_size = 4, + .valid.max_access_size = 4, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + + +static void sw64_gpio_realize(DeviceState *dev, Error **errp) +{ + SW64GPIOState *s = SW64_GPIO(dev); + MemoryRegion *sw64_gpio = g_new(MemoryRegion, 1); + memory_region_init_io(sw64_gpio, OBJECT(s), &sw64_gpio_ops, s, + TYPE_SW64_GPIO, SW64_GPIO_MEM_SIZE); + + qdev_init_gpio_in(DEVICE(s), sw64_gpio_set, SW64_GPIO_PIN_COUNT); + qdev_init_gpio_out(DEVICE(s), s->output, SW64_GPIO_PIN_COUNT); + s->irq[0] = qemu_allocate_irq(sw64_gpio_set_irq, s, 15); + memory_region_add_subregion(get_system_memory(), 0x804930000000ULL, + sw64_gpio); +} + +static void sw64_gpio_initfn(Object *obj) +{ + DeviceState *dev = DEVICE(obj); + Error *errp; + sw64_gpio_realize(dev, &errp); +} + + +static void sw64_gpio_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = sw64_gpio_realize; + dc->reset = sw64_gpio_reset; + dc->vmsd = &vmstate_sw64_gpio; + dc->desc = "SW64 GPIO controller"; +} + +static const TypeInfo sw64_gpio_info = { + .name = TYPE_SW64_GPIO, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(SW64GPIOState), + .instance_init = sw64_gpio_initfn, + .class_init = sw64_gpio_class_init, +}; + +static void sw64_gpio_register_types(void) +{ + type_register_static(&sw64_gpio_info); +} + +type_init(sw64_gpio_register_types) diff --git a/hw/acpi/meson.build b/hw/acpi/meson.build index 5fe4cfa4f13ded963bdcd518bdbcb6e2d356d97d..8f6cf647d172096be0ed68686716ac3f77d34fc2 100644 --- a/hw/acpi/meson.build +++ b/hw/acpi/meson.build @@ -12,6 +12,8 @@ acpi_ss.add(when: 'CONFIG_ACPI_CPU_HOTPLUG', if_false: files('acpi-cpu-hotplug-s acpi_ss.add(when: 'CONFIG_ACPI_MEMORY_HOTPLUG', if_true: files('memory_hotplug.c')) acpi_ss.add(when: 'CONFIG_ACPI_MEMORY_HOTPLUG', if_false: files('acpi-mem-hotplug-stub.c')) acpi_ss.add(when: 'CONFIG_ACPI_NVDIMM', if_true: files('nvdimm.c')) +acpi_ss.add(when: 'CONFIG_ACPI_SW64_PM', if_true: files('sw64_pm_device.c')) +acpi_ss.add(when: 'CONFIG_GPIO_SUNWAY', if_true: files('gpio_sunway.c')) acpi_ss.add(when: 'CONFIG_ACPI_NVDIMM', if_false: files('acpi-nvdimm-stub.c')) acpi_ss.add(when: 'CONFIG_ACPI_PCI', if_true: files('pci.c')) acpi_ss.add(when: 'CONFIG_ACPI_VMGENID', if_true: files('vmgenid.c')) diff --git a/hw/acpi/sw64_pm_device.c b/hw/acpi/sw64_pm_device.c new file mode 100644 index 0000000000000000000000000000000000000000..6d7c01260d77ddde193406d09249e6071975adc0 --- /dev/null +++ b/hw/acpi/sw64_pm_device.c @@ -0,0 +1,284 @@ +/* + * Copyright (c) 2022 Wxiat Corporation + * Written by Lufeifei, Min fanlei + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2 or later, as published by the Free Software Foundation. + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "hw/acpi/acpi.h" +#include "hw/irq.h" +#include "hw/mem/pc-dimm.h" +#include "hw/qdev-properties.h" +#include "migration/vmstate.h" +#include "qemu/error-report.h" +#include "hw/sw64/pm.h" +#include "exec/address-spaces.h" +#include "hw/acpi/cpu.h" + +static void sw64_pm_device_plug_cb(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) +{ + SW64PMState *s = SW64_PM(hotplug_dev); + + if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { + PCDIMMDevice *dimm = PC_DIMM(dev); + s->addr = dimm->addr; + s->length = object_property_get_uint(OBJECT(dimm), PC_DIMM_SIZE_PROP, NULL); + s->status = SUNWAY_MEMHOTPLUG_ADD; + s->slot = dimm->slot; + s->node = dimm->node; + + acpi_memory_plug_cb(hotplug_dev, &s->acpi_memory_hotplug, dev, errp); + } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { + s->status = SUNWAY_CPUHOTPLUG_ADD; + s->cpuid = cpu_hot_id; + acpi_cpu_plug_cb(hotplug_dev, &s->cpuhp_state, dev, errp); + } else { + error_setg(errp, "virt: device plug request for unsupported device" + " type: %s", object_get_typename(OBJECT(dev))); + } +} + +static void sw64_pm_unplug_request_cb(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) +{ + SW64PMState *s = SW64_PM(hotplug_dev); + + if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { + PCDIMMDevice *dimm = PC_DIMM(dev); + s->addr = dimm->addr; + s->slot = dimm->slot; + s->node = dimm->node; + s->length = object_property_get_uint(OBJECT(dimm), PC_DIMM_SIZE_PROP, NULL); + s->status = SUNWAY_MEMHOTPLUG_REMOVE; + + acpi_memory_unplug_request_cb(hotplug_dev, &s->acpi_memory_hotplug, dev, errp); + } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { + s->status = SUNWAY_CPUHOTPLUG_REMOVE; + s->cpuid = cpu_hot_id; + acpi_cpu_unplug_request_cb(hotplug_dev, &s->cpuhp_state, dev, errp); + } else { + error_setg(errp, "acpi: device unplug for unsupported device" + " type: %s", object_get_typename(OBJECT(dev))); + } +} + +static void sw64_pm_unplug_cb(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) +{ + SW64PMState *s = SW64_PM(hotplug_dev); + + if ((object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM))) { + acpi_memory_unplug_cb(&s->acpi_memory_hotplug, dev, errp); + } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { + acpi_cpu_unplug_cb(&s->cpuhp_state, dev, errp); + } else { + error_setg(errp, "acpi: device unplug request for unsupported device" + " type: %s", object_get_typename(OBJECT(dev))); + } +} + +static void sw64_pm_send_event(AcpiDeviceIf *adev, AcpiEventStatusBits ev) +{ + SW64PMState *s = SW64_PM(adev); + + if (!(ev & ACPI_MEMORY_HOTPLUG_STATUS) && !(ev & ACPI_CPU_HOTPLUG_STATUS)) { + /* Unknown event. Return without generating interrupt. */ + warn_report("GED: Uns:upported event %d. No irq injected", ev); + return; + } + + /* Trigger the event by sending an interrupt to the guest. */ + qemu_irq_pulse(s->irq); +} + +static uint64_t pm_read(void *opaque, hwaddr addr, unsigned size) +{ + SW64PMState *s = (SW64PMState *)opaque; + uint64_t ret = 0; + + switch (addr) { + case OFFSET_START_ADDR: + ret = s->addr; + break; + case OFFSET_LENGTH: + ret = s->length; + break; + case OFFSET_STATUS: + ret = s->status; + break; + case OFFSET_SLOT: + ret = s->slot; + break; + case OFFSET_CPUID: + ret = s->cpuid; + break; + case OFFSET_NODE: + ret = s->node; + break; + default: + break; + } + + return ret; +} + +static void pm_write(void *opaque, hwaddr addr, uint64_t val, + unsigned size) +{ + SW64PMState *s = (SW64PMState *)opaque; + MemStatus *mdev; + AcpiCpuStatus *cdev = NULL; + DeviceState *dev = NULL; + HotplugHandler *hotplug_ctrl = NULL; + Error *local_err = NULL; + + switch (addr) { + case OFFSET_SLOT: + s->acpi_memory_hotplug.selector = val; + mdev = &s->acpi_memory_hotplug.devs[s->acpi_memory_hotplug.selector]; + dev = DEVICE(mdev->dimm); + hotplug_ctrl = qdev_get_hotplug_handler(dev); + /* call pc-dimm unplug cb */ + hotplug_handler_unplug(hotplug_ctrl, dev, &local_err); + object_unparent(OBJECT(dev)); + break; + case OFFSET_CPUID: + s->cpuhp_state.selector = val; + int i; + for (i = 0; i < s->cpuhp_state.dev_count; i++) { + if (s->cpuhp_state.selector == s->cpuhp_state.devs[i].arch_id) { + cdev = &s->cpuhp_state.devs[i]; + } + } + dev = DEVICE(cdev->cpu); + hotplug_ctrl = qdev_get_hotplug_handler(dev); + hotplug_handler_unplug(hotplug_ctrl, dev, &local_err); + object_unparent(OBJECT(dev)); + break; + default: + break; + } +} + +const MemoryRegionOps sw64_pm_hotplug_ops = { + .read = pm_read, + .write = pm_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_cpu_hotplug_hw_init(CPUHotplugState *state, hwaddr base_addr) +{ + MachineState *machine = MACHINE(qdev_get_machine()); + MachineClass *mc = MACHINE_GET_CLASS(machine); + const CPUArchIdList *id_list; + int i; + + assert(mc->possible_cpu_arch_ids); + id_list = mc->possible_cpu_arch_ids(machine); + state->dev_count = id_list->len; + state->devs = g_new0(typeof(*state->devs), state->dev_count); + for (i = 0; i < id_list->len; i++) { + state->devs[i].cpu = CPU(id_list->cpus[i].cpu); + state->devs[i].arch_id = id_list->cpus[i].arch_id; + } +} + +void sw64_acpi_switch_to_modern_cphp(CPUHotplugState *cpuhp_state, + uint16_t io_port) +{ + sw64_cpu_hotplug_hw_init(cpuhp_state, io_port); +} + +static void sw64_set_cpu_hotplug_legacy(Object *obj, bool value) +{ + DeviceState *dev = DEVICE(obj); + SW64PMState *s = SW64_PM(dev); + assert(!value); + if (s->cpu_hotplug_legacy && value == false) { + sw64_acpi_switch_to_modern_cphp(&s->cpuhp_state, 0); + } + s->cpu_hotplug_legacy = value; +} + +static void sw64_pm_initfn(Object *obj) +{ + DeviceState *dev = DEVICE(obj); + SW64PMState *s = SW64_PM(dev); + MemoryRegion *pm_hotplug = g_new(MemoryRegion, 1); + + s->irq = qemu_allocate_irq(sw64_pm_set_irq, s, 13); + + memory_region_init_io(pm_hotplug, OBJECT(s), &sw64_pm_hotplug_ops, s, + "sw64_pm_hotplug", 4 * 1024 * 1024); + memory_region_add_subregion(get_system_memory(), 0x803600000000ULL, + pm_hotplug); + + if (s->acpi_memory_hotplug.is_enabled) { + MachineState *machine = MACHINE(qdev_get_machine()); + MemHotplugState *state = &s->acpi_memory_hotplug; + + state->dev_count = machine->ram_slots; + if (state->dev_count) { + state->devs = g_malloc0(sizeof(*state->devs) * state->dev_count); + } + } + + s->cpu_hotplug_legacy = true; + sw64_set_cpu_hotplug_legacy(obj, false); +} + +static Property sw64_pm_properties[] = { + DEFINE_PROP_BOOL("memory-hotplug-support", SW64PMState, + acpi_memory_hotplug.is_enabled, true), + DEFINE_PROP_END_OF_LIST(), +}; + +static void sw64_pm_class_init(ObjectClass *class, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(class); + HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(class); + AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_CLASS(class); + + dc->desc = "SW64 PM"; + device_class_set_props(dc, sw64_pm_properties); + + hc->plug = sw64_pm_device_plug_cb; + hc->unplug_request = sw64_pm_unplug_request_cb; + hc->unplug = sw64_pm_unplug_cb; + + adevc->send_event = sw64_pm_send_event; +} + +static const TypeInfo sw64_pm_info = { + .name = TYPE_SW64_PM, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(SW64PMState), + .instance_init = sw64_pm_initfn, + .class_init = sw64_pm_class_init, + .interfaces = (InterfaceInfo[]) { + { TYPE_HOTPLUG_HANDLER }, + { TYPE_ACPI_DEVICE_IF }, + { } + } +}; + +static void sw64_pm_register_types(void) +{ + type_register_static(&sw64_pm_info); +} + +type_init(sw64_pm_register_types) diff --git a/hw/meson.build b/hw/meson.build index f224f8ad2878c12e17c3468fc8f58d7f0e633423..a9a078ec3392aed25eb253a6a1a67821eff4b0fc 100644 --- a/hw/meson.build +++ b/hw/meson.build @@ -63,5 +63,6 @@ subdir('s390x') subdir('sh4') subdir('sparc') subdir('sparc64') +subdir('sw64') subdir('tricore') subdir('xtensa') diff --git a/hw/sw64/Kconfig b/hw/sw64/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..9895723fae01df9061f4b7e07d63056fe43abb99 --- /dev/null +++ b/hw/sw64/Kconfig @@ -0,0 +1,30 @@ +config CORE3 + bool + imply PCI_DEVICES + imply TEST_DEVICES + imply E1000_PCI + select PCI_EXPRESS + select SUN4V_RTC + select SMBIOS + select VIRTIO_MMIO + select SERIAL + select ISA_BUS + select PCKBD + select MSI_NONBROKEN + +config CORE4 + bool + imply PCI_DEVICES + imply TEST_DEVICES + imply E1000_PCI + select PCI_EXPRESS + select SUN4V_RTC + select SMBIOS + select VIRTIO_MMIO + select SERIAL + select ISA_BUS + select PCKBD + select MSI_NONBROKEN + select ACPI_NVDIMM + select GPIO_SUNWAY + select ACPI_HW_REDUCED diff --git a/hw/sw64/core3.c b/hw/sw64/core3.c new file mode 100644 index 0000000000000000000000000000000000000000..42bdcd1bc7f00df06a005b7a18e1f478a2008bfc --- /dev/null +++ b/hw/sw64/core3.c @@ -0,0 +1,117 @@ +/* + * QEMU CORE3 hardware system emulator. + * + * Copyright (c) 2018 Li Hainan + * + * 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/char/serial.h" +#include "qemu/cutils.h" +#include "ui/console.h" +#include "hw/sw64/core.h" +#include "hw/sw64/sunway.h" +#include "sysemu/numa.h" + +#define MAX_CPUS_CORE3 64 +#define C3_UEFI_BIOS_NAME "c3-uefi-bios-sw" + +static void core3_init(MachineState *machine) +{ + ram_addr_t ram_size = machine->ram_size; + const char *kernel_filename = machine->kernel_filename; + const char *kernel_cmdline = machine->kernel_cmdline; + const char *initrd_filename = machine->initrd_filename; + const char *hmcode_name = kvm_enabled() ? "core3-reset":"core3-hmcode"; + const char *bios_name = C3_UEFI_BIOS_NAME; + BOOT_PARAMS *sunway_boot_params = g_new0(BOOT_PARAMS, 1); + char *hmcode_filename; + uint64_t hmcode_entry, kernel_entry; + + if (kvm_enabled()) + sw64_set_clocksource(); + + core3_board_init(machine); + + sw64_set_ram_size(ram_size); + sw64_clear_smp_rcb(); + + hmcode_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, hmcode_name); + if (hmcode_filename == NULL) { + error_report("no '%s' provided", hmcode_name); + exit(1); + } + sw64_load_hmcode(hmcode_filename, &hmcode_entry); + + if (!kvm_enabled()) { + CPUState *cpu; + SW64CPU *sw64_cpu; + CPU_FOREACH(cpu) { + sw64_cpu = SW64_CPU(cpu); + sw64_cpu->env.pc = hmcode_entry; + sw64_cpu->env.hm_entry = hmcode_entry; + sw64_cpu->env.csr[CID] = sw64_cpu->core_id; + qemu_register_reset(sw64_cpu_reset, sw64_cpu); + } + } + g_free(hmcode_filename); + + if (!kernel_filename) + sw64_find_and_load_bios(bios_name); + else { + sw64_clear_uefi_bios(); + sw64_load_kernel(kernel_filename, &kernel_entry, kernel_cmdline); + + if (initrd_filename) { + sw64_load_initrd(initrd_filename, sunway_boot_params); + } + } + + if (sw64_load_dtb(machine, sunway_boot_params) < 0) { + exit(1); + } + + rom_add_blob_fixed("sunway_boot_params", (sunway_boot_params), 0x48, 0x90A100); +} + +static void core3_machine_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + mc->desc = "CORE3 BOARD"; + mc->init = core3_init; + mc->block_default_type = IF_VIRTIO; + mc->max_cpus = MAX_CPUS_CORE3; + mc->no_cdrom = 1; + mc->pci_allow_0_address = true; + mc->reset = sw64_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; +} + +static const TypeInfo core3_machine_info = { + .name = TYPE_CORE3_MACHINE, + .parent = TYPE_MACHINE, + .class_init = core3_machine_class_init, + .instance_size = sizeof(CORE3MachineState), +}; + +static void core3_machine_init(void) +{ + type_register_static(&core3_machine_info); +} +type_init(core3_machine_init); diff --git a/hw/sw64/core3_board.c b/hw/sw64/core3_board.c new file mode 100644 index 0000000000000000000000000000000000000000..92cd5cf4ef9eb5c879911d0d506b029246821c12 --- /dev/null +++ b/hw/sw64/core3_board.c @@ -0,0 +1,419 @@ +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "cpu.h" +#include "hw/sw64/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 "sysemu/numa.h" +#include "sysemu/kvm.h" +#include "sysemu/cpus.h" +#include "hw/pci/msi.h" +#include "hw/sw64/sw64_iommu.h" +#include "hw/sw64/sunway.h" +#include "hw/loader.h" +#include "hw/nvram/fw_cfg.h" +#include "hw/firmware/smbios.h" +#include "sysemu/device_tree.h" +#include "qemu/datadir.h" + +#define CORE3_MAX_CPUS_MASK 0x3ff +#define CORE3_CORES_SHIFT 10 +#define CORE3_CORES_MASK 0x3ff +#define CORE3_THREADS_SHIFT 20 +#define CORE3_THREADS_MASK 0xfff + +static const MemMapEntry memmap[] = { + [VIRT_PCIE_MMIO] = { 0xe0000000, 0x20000000 }, + [VIRT_MSI] = { 0x8000fee00000, 0x100000 }, + [VIRT_INTPU] = { 0x802a00000000, 0x100000 }, + [VIRT_MCU] = { 0x803000000000, 0x1000000 }, + [VIRT_RTC] = { 0x804910000000, 0x8 }, + [VIRT_FW_CFG] = { 0x804920000000, 0x18 }, + [VIRT_PCIE_IO_BASE] = { 0x880000000000, 0x890000000000 }, + [VIRT_PCIE_PIO] = { 0x880100000000, 0x100000000 }, + [VIRT_UART] = { 0x8801000003f8, 0x10 }, + [VIRT_PCIE_CFG] = { 0x880600000000, 0x100000000 }, + [VIRT_HIGH_PCIE_MMIO] = { 0x888000000000, 0x8000000000 }, +}; + +static const int irqmap[] = { + [VIRT_UART] = 12, + [VIRT_SUNWAY_GED] = 13, +}; + +static void core3_virt_build_smbios(CORE3MachineState *core3ms) +{ + FWCfgState *fw_cfg = core3ms->fw_cfg; + + if (!fw_cfg) + return; + + sw64_virt_build_smbios(fw_cfg); +} + +static uint64_t mcu_read(void *opaque, hwaddr addr, unsigned size) +{ + MachineState *ms = MACHINE(qdev_get_machine()); + unsigned int smp_cpus = ms->smp.cpus; + unsigned int smp_threads = ms->smp.threads; + unsigned int smp_cores = ms->smp.cores; + unsigned int max_cpus = ms->smp.max_cpus; + uint64_t ret = 0; + switch (addr) { + case 0x0080: + /* SMP_INFO */ + { + ret = (smp_threads & CORE3_THREADS_MASK) << CORE3_THREADS_SHIFT; + ret += (smp_cores & CORE3_CORES_MASK) << CORE3_CORES_SHIFT; + ret += max_cpus & CORE3_MAX_CPUS_MASK; + } + break; + case 0x0680: + /* INIT_CTL */ + ret = 0x3ae0000ddd9; + break; + case 0x0780: + /* CORE_ONLINE */ + ret = convert_bit(smp_cpus); + break; + case 0x3780: + /* MC_ONLINE */ + ret = convert_bit(smp_cpus); + 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) +{ +#ifdef CONFIG_DUMP_PRINTK + uint64_t print_addr; + uint32_t len; + int i; + + if (kvm_enabled()) + return; + + 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 +} + +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; + + if (kvm_enabled()) + return ret; + + switch (addr) { + case 0x180: + /* LONGTIME */ + ret = qemu_clock_get_ns(QEMU_CLOCK_HOST) / 32; + break; + } + return ret; +} + +static void intpu_write(void *opaque, hwaddr addr, uint64_t val, + unsigned size) +{ + SW64CPU *cpu_current = SW64_CPU(current_cpu); + + if (kvm_enabled()) + return; + + switch (addr) { + case 0x00: + cpu_interrupt(qemu_get_cpu(val & 0x3f), CPU_INTERRUPT_II0); + cpu_current->env.csr[II_REQ] &= ~(1 << 20); + break; + default: + fprintf(stderr, "Unsupported IPU addr: 0x%04lx\n", addr); + break; + } +} + +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 void create_fdt_misc_platform(CORE3MachineState *c3ms) +{ + char *nodename; + MachineState *ms = MACHINE(c3ms); + + nodename = g_strdup_printf("/soc/misc_platform@0"); + qemu_fdt_add_subnode(ms->fdt, nodename); + qemu_fdt_setprop_string(ms->fdt, nodename, + "compatible", "sunway,misc-platform"); + qemu_fdt_setprop_cell(ms->fdt, nodename, "numa-node-id", 0); + qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "sunway,spbu_base", + 2, c3ms->memmap[VIRT_MCU].base); + qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "sunway,intpu_base", + 2, c3ms->memmap[VIRT_INTPU].base); + g_free(nodename); +} + +static void core3_create_fdt(CORE3MachineState *c3ms) +{ + uint32_t intc_phandle; + MachineState *ms = MACHINE(c3ms); + + if (ms->dtb) { + char *filename; + + filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, ms->dtb); + if (!filename) { + fprintf(stderr, "Couldn't open dtb file %s\n", ms->dtb); + exit(1); + } + + ms->fdt = load_device_tree(ms->dtb, &c3ms->fdt_size); + if (!ms->fdt) { + error_report("load_device_tree() failed"); + exit(1); + } + } else { + ms->fdt = create_device_tree(&c3ms->fdt_size); + if (!ms->fdt) { + error_report("create_device_tree() failed"); + exit(1); + } + + qemu_fdt_setprop_string(ms->fdt, "/", "compatible", "sunway,chip3"); + qemu_fdt_setprop_string(ms->fdt, "/", "model", "chip3"); + qemu_fdt_setprop_cell(ms->fdt, "/", "#address-cells", 0x2); + qemu_fdt_setprop_cell(ms->fdt, "/", "#size-cells", 0x2); + + qemu_fdt_add_subnode(ms->fdt, "/chosen"); + + qemu_fdt_add_subnode(ms->fdt, "/soc"); + qemu_fdt_setprop_string(ms->fdt, "/soc", "compatible", "simple-bus"); + qemu_fdt_setprop_cell(ms->fdt, "/soc", "#address-cells", 0x2); + qemu_fdt_setprop_cell(ms->fdt, "/soc", "#size-cells", 0x2); + qemu_fdt_setprop(ms->fdt, "/soc", "ranges", NULL, 0); + + intc_phandle = qemu_fdt_alloc_phandle(ms->fdt); + qemu_fdt_add_subnode(ms->fdt, "/soc/interrupt-controller"); + qemu_fdt_setprop_string(ms->fdt, "/soc/interrupt-controller", + "compatible", "sw64,pintc_vt"); + qemu_fdt_setprop(ms->fdt, "/soc/interrupt-controller", + "interrupt-controller", NULL, 0); + qemu_fdt_setprop_cell(ms->fdt, "/soc/interrupt-controller", + "sw64,node", 0); + qemu_fdt_setprop_cell(ms->fdt, "/soc/interrupt-controller", + "sw64,irq-num", 16); + qemu_fdt_setprop_cell(ms->fdt, "/soc/interrupt-controller", + "sw64,ver", 0x1); + qemu_fdt_setprop_cell(ms->fdt, "/soc/interrupt-controller", + "#interrupt-cells", 0x1); + qemu_fdt_setprop_cell(ms->fdt, "/soc/interrupt-controller", + "phandle", intc_phandle); + + qemu_fdt_add_subnode(ms->fdt, "/soc/serial0@8801"); + qemu_fdt_setprop_cell(ms->fdt, "/soc/serial0@8801", + "#address-cells", 0x2); + qemu_fdt_setprop_cell(ms->fdt, "/soc/serial0@8801", + "#size-cells", 0x2); + qemu_fdt_setprop_string(ms->fdt, "/soc/serial0@8801", + "compatible", "ns16550a"); + qemu_fdt_setprop_sized_cells(ms->fdt, "/soc/serial0@8801", "reg", + 2, c3ms->memmap[VIRT_UART].base, + 2, c3ms->memmap[VIRT_UART].size); + qemu_fdt_setprop_cell(ms->fdt, "/soc/serial0@8801", + "interrupt-parent", intc_phandle); + qemu_fdt_setprop_cell(ms->fdt, "/soc/serial0@8801", + "interrupts", c3ms->irqmap[VIRT_UART]); + qemu_fdt_setprop_cell(ms->fdt, "/soc/serial0@8801", "reg-shift", 0x0); + qemu_fdt_setprop_cell(ms->fdt, "/soc/serial0@8801", + "reg-io-width", 0x1); + qemu_fdt_setprop_cell(ms->fdt, "/soc/serial0@8801", + "clock-frequency", 24000000); + qemu_fdt_setprop_string(ms->fdt, "/soc/serial0@8801", + "status", "okay"); + } + create_fdt_misc_platform(c3ms); +} + +static void core3_cpus_init(MachineState *ms) +{ + int i; + const CPUArchIdList *possible_cpus; + MachineClass *mc = MACHINE_GET_CLASS(ms); + + possible_cpus = mc->possible_cpu_arch_ids(ms); + for (i = 0; i < ms->smp.cpus; i++) { + sw64_new_cpu("core3-sw64-cpu", possible_cpus->cpus[i].arch_id, &error_fatal); + } +} + +void core3_board_init(MachineState *ms) +{ + CORE3MachineState *core3ms = CORE3_MACHINE(ms); + DeviceState *dev = qdev_new(TYPE_CORE3_BOARD); + BoardState *bs = CORE3_BOARD(dev); + PCIHostState *phb = PCI_HOST_BRIDGE(dev); + PCIBus *b; + + core3ms->memmap = memmap; + core3ms->irqmap = irqmap; + + /* Create device tree */ + core3_create_fdt(core3ms); + + core3_cpus_init(ms); + + if (kvm_enabled()) { + if (kvm_has_gsi_routing()) + msi_nonbroken = true; + } + else + sw64_create_alarm_timer(ms, bs); + + memory_region_add_subregion(get_system_memory(), 0, ms->ram); + + memory_region_init_io(&bs->io_mcu, NULL, &mcu_ops, bs, "io_mcu", + memmap[VIRT_MCU].size); + memory_region_add_subregion(get_system_memory(), memmap[VIRT_MCU].base, + &bs->io_mcu); + + memory_region_init_io(&bs->io_intpu, NULL, &intpu_ops, bs, "io_intpu", + memmap[VIRT_INTPU].size); + memory_region_add_subregion(get_system_memory(), memmap[VIRT_INTPU].base, + &bs->io_intpu); + + memory_region_init_io(&bs->msi_ep, NULL, &msi_ops, bs, "msi_ep", + memmap[VIRT_MSI].size); + memory_region_add_subregion(get_system_memory(), memmap[VIRT_MSI].base, + &bs->msi_ep); + + memory_region_init(&bs->mem_ep, OBJECT(bs), "pci0-mem", + memmap[VIRT_PCIE_IO_BASE].size); + memory_region_add_subregion(get_system_memory(), + memmap[VIRT_PCIE_IO_BASE].base, &bs->mem_ep); + + memory_region_init_alias(&bs->mem_ep64, NULL, "mem_ep64", &bs->mem_ep, + memmap[VIRT_HIGH_PCIE_MMIO].base, + memmap[VIRT_HIGH_PCIE_MMIO].size); + memory_region_add_subregion(get_system_memory(), + memmap[VIRT_HIGH_PCIE_MMIO].base, &bs->mem_ep64); + + memory_region_init_io(&bs->io_ep, OBJECT(bs), &sw64_pci_ignore_ops, NULL, + "pci0-io-ep", memmap[VIRT_PCIE_PIO].size); + memory_region_add_subregion(get_system_memory(), memmap[VIRT_PCIE_PIO].base, + &bs->io_ep); + + b = pci_register_root_bus(dev, "pcie.0", sw64_board_set_irq, + sw64_board_map_irq, bs, + &bs->mem_ep, &bs->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, sw64_route_intx_pin_to_irq); + memory_region_init_io(&bs->conf_piu0, OBJECT(bs), &sw64_pci_config_ops, b, + "pci0-ep-conf-io", memmap[VIRT_PCIE_CFG].size); + memory_region_add_subregion(get_system_memory(), memmap[VIRT_PCIE_CFG].base, + &bs->conf_piu0); + sw64_init_rtc_base_info(); + memory_region_init_io(&bs->io_rtc, OBJECT(bs), &rtc_ops, b, + "sw64-rtc", memmap[VIRT_RTC].size); + memory_region_add_subregion(get_system_memory(), memmap[VIRT_RTC].base, + &bs->io_rtc); + object_property_add_tm(OBJECT(core3ms), "rtc-time", rtc_get_time); +#ifdef CONFIG_SW64_VT_IOMMU + sw64_vt_iommu_init(b); +#endif + + sw64_create_pcie(bs, b, phb); + + core3ms->fw_cfg = sw64_create_fw_cfg(memmap[VIRT_FW_CFG].base, + memmap[VIRT_FW_CFG].size); + rom_set_fw(core3ms->fw_cfg); + + core3_virt_build_smbios(core3ms); +} + +static Property core3_main_pci_host_props[] = { + DEFINE_PROP_UINT32("ofw-addr", BoardState, ofw_addr, 0), + DEFINE_PROP_END_OF_LIST() +}; + +static char *core3_main_ofw_unit_address(const SysBusDevice *dev) +{ + BoardState *s = CORE3_BOARD(dev); + return g_strdup_printf("%x", s->ofw_addr); +} + +static void core3_board_pcihost_class_init(ObjectClass *obj, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(obj); + SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(obj); + + dc->props_ = core3_main_pci_host_props; + dc->fw_name = "pci"; + sbc->explicit_ofw_unit_address = core3_main_ofw_unit_address; +} + +static const TypeInfo swboard_pcihost_info = { + .name = TYPE_CORE3_BOARD, + .parent = TYPE_PCI_HOST_BRIDGE, + .instance_size = sizeof(BoardState), + .class_init = core3_board_pcihost_class_init, +}; + +static void swboard_register_types(void) +{ + type_register_static(&swboard_pcihost_info); +} + +type_init(swboard_register_types) diff --git a/hw/sw64/core4.c b/hw/sw64/core4.c new file mode 100644 index 0000000000000000000000000000000000000000..2206edc581c2069cdac390bc30d56ee16f4cc44b --- /dev/null +++ b/hw/sw64/core4.c @@ -0,0 +1,371 @@ +/* + * QEMU CORE4 hardware system emulator. + */ + +#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/char/serial.h" +#include "qemu/cutils.h" +#include "ui/console.h" +#include "hw/sw64/core.h" +#include "hw/sw64/sunway.h" +#include "sysemu/numa.h" +#include "hw/mem/pc-dimm.h" +#include "qapi/error.h" +#include "sysemu/device_tree.h" +#include "hw/core/cpu.h" +#include "hw/qdev-core.h" + +#define C4_UEFI_BIOS_NAME "c4-uefi-bios-sw" + +static unsigned long cpu_masks[4]; +static int hot_cpu_num; +int cpu_hot_id; + +static void core4_init(MachineState *machine) +{ + MachineClass *mc = MACHINE_GET_CLASS(machine); + const CPUArchIdList *possible_cpus = mc->possible_cpu_arch_ids(machine); + assert(possible_cpus->len); + + ram_addr_t ram_size = machine->ram_size; + const char *kernel_filename = machine->kernel_filename; + const char *kernel_cmdline = machine->kernel_cmdline; + const char *initrd_filename = machine->initrd_filename; + const char *hmcode_name = kvm_enabled() ? "core4-reset":"core4-hmcode"; + const char *bios_name = C4_UEFI_BIOS_NAME; + BOOT_PARAMS *sunway_boot_params = g_new0(BOOT_PARAMS, 1); + char *hmcode_filename; + uint64_t hmcode_entry, kernel_entry; + + core4_board_init(machine); + + sw64_set_ram_size(ram_size); + sw64_clear_smp_rcb(); + sw64_clear_kernel_print(); + + hmcode_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, hmcode_name); + if (hmcode_filename == NULL) { + error_report("no '%s' provided", hmcode_name); + exit(1); + } + sw64_load_hmcode(hmcode_filename, &hmcode_entry); + + g_free(hmcode_filename); + + if (!kernel_filename) + sw64_find_and_load_bios(bios_name); + else { + sw64_clear_uefi_bios(); + sw64_load_kernel(kernel_filename, &kernel_entry, kernel_cmdline); + + if (initrd_filename) { + unsigned long initrd_end_va; + + sw64_load_initrd(initrd_filename, sunway_boot_params); + initrd_end_va = sunway_boot_params->initrd_start + + (sunway_boot_params->initrd_size & + (~0xfff0000000000000UL)); + qemu_fdt_setprop_cell(machine->fdt, "/chosen", "linux,initrd-start", + sunway_boot_params->initrd_start); + qemu_fdt_setprop_cell(machine->fdt, "/chosen", "linux,initrd-end", + initrd_end_va); + } + } + + if (sw64_load_dtb(machine, sunway_boot_params) < 0) { + exit(1); + } + + /* Retained for forward compatibility */ + rom_add_blob_fixed("sunway_boot_params", (sunway_boot_params), 0x48, 0x90A100); + + if (!kvm_enabled()) { + CPUState *cpu; + SW64CPU *sw64_cpu; + CPU_FOREACH(cpu) { + sw64_cpu = SW64_CPU(cpu); + sw64_cpu->env.pc = hmcode_entry; + sw64_cpu->env.hm_entry = hmcode_entry; + sw64_cpu->env.csr[CID] = sw64_cpu->core_id; + qemu_register_reset(sw64_cpu_reset, sw64_cpu); + if (sw64_cpu->core_id == 0) { + sw64_cpu->env.ir[16] = 0xA2024; + sw64_cpu->env.ir[17] = dtb_start_c4; + } + } + } +} + +static void set_on_cpumask(int cpu_num) +{ + set_bit(cpu_num, cpu_masks); +} + +static void set_off_cpumask(int cpu_num) +{ + clear_bit(cpu_num, cpu_masks); +} + +int get_state_cpumask(int cpu_num) +{ + return test_bit(cpu_num, cpu_masks); +} + +static HotplugHandler *sw64_get_hotplug_handler(MachineState *machine, + DeviceState *dev) +{ + if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) + return HOTPLUG_HANDLER(machine); + + if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { + return HOTPLUG_HANDLER(machine); + } + + return NULL; +} + +static void core4_machine_device_pre_plug_cb(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) +{ + MachineState *ms = MACHINE(hotplug_dev); + Error *local_err = NULL; + + if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) + pc_dimm_pre_plug(PC_DIMM(dev), ms, NULL, &local_err); + + return; +} + +static CPUArchId *sw64_find_cpu_slot(MachineState *ms, uint32_t id) +{ + if (id >= ms->possible_cpus->len) { + return NULL; + } + if (hot_cpu_num < ms->smp.cpus) { + ++hot_cpu_num; + } + set_on_cpumask(id); + return &ms->possible_cpus->cpus[id]; +} + +static void sw64_cpu_plug(HotplugHandler *hotplug_dev, DeviceState *dev, + Error **errp) +{ + MachineState *ms = MACHINE(qdev_get_machine()); + uint16_t smp_cpus = ms->smp.cpus; + CPUArchId *found_cpu; + HotplugHandlerClass *hhc; + Error *local_err = NULL; + CPUState *cs = NULL; + SW64CPU *cpu = NULL; + CORE4MachineState *pcms = CORE4_MACHINE(hotplug_dev); + + if (pcms->acpi_dev) { + if (get_state_cpumask(cpu_hot_id)) { + error_setg(&local_err, "error: Unable to add already online cpu!"); + return; + } + + hhc = HOTPLUG_HANDLER_GET_CLASS(pcms->acpi_dev); + hhc->plug(HOTPLUG_HANDLER(pcms->acpi_dev), dev, &local_err); + if (local_err) { + goto out; + } + } + + cs = CPU(dev); + cpu = SW64_CPU(dev); + if (hot_cpu_num < smp_cpus) { + cs->cpu_index = hot_cpu_num; + cpu->core_id = hot_cpu_num; + found_cpu = sw64_find_cpu_slot(MACHINE(pcms), hot_cpu_num); + } else { + hot_cpu_num = smp_cpus; + cs->cpu_index = cpu_hot_id; + cpu->core_id = cpu_hot_id; + found_cpu = sw64_find_cpu_slot(MACHINE(pcms), cpu_hot_id); + } + if (!found_cpu) { + error_setg(&local_err, "error: No slot found for new hot add cpu!"); + return; + } + found_cpu->cpu = OBJECT(dev); +out: + error_propagate(errp, local_err); +} + +static void sw64_qdev_unrealize(DeviceState *dev) +{ + Error *err = NULL; + object_property_set_bool(OBJECT(dev), "realized", false, &err); +} + + +static void sw64_cpu_unplug_request(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) +{ + Error *local_err = NULL; + SW64CPU *cpu = NULL; + CPUState *cs = NULL; + HotplugHandlerClass *hhc; + CORE4MachineState *pcms = CORE4_MACHINE(hotplug_dev); + + if (!pcms->acpi_dev) { + error_setg(&local_err, "CPU hot unplug not supported without ACPI"); + goto out; + } + + cpu = SW64_CPU(dev); + cpu_hot_id = cpu->core_id; + cs = CPU(dev); + cs->cpu_index = cpu_hot_id; + + if (!cpu_hot_id) { + error_setg(&local_err, "Boot CPU is unpluggable"); + goto out; + } + + if (!get_state_cpumask(cpu_hot_id) || !cpu_hot_id) { + error_setg(&local_err, "error:" + "Unable to delete already offline cpu and cpu 0 can not offline!"); + return; + } + + hhc = HOTPLUG_HANDLER_GET_CLASS(pcms->acpi_dev); + hhc->unplug_request(HOTPLUG_HANDLER(pcms->acpi_dev), dev, &local_err); + +out: + error_propagate(errp, local_err); +} + +static void core4_machine_device_plug_cb(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) +{ + MachineState *ms = MACHINE(hotplug_dev); + CORE4MachineState *core4ms = CORE4_MACHINE(hotplug_dev); + Error *local_err = NULL; + + if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { + pc_dimm_plug(PC_DIMM(dev), ms); + hotplug_handler_plug(HOTPLUG_HANDLER(core4ms->acpi_dev), + dev, &local_err); + } + if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) + sw64_cpu_plug(hotplug_dev, dev, &local_err); +} + +static void core4_machine_device_unplug_request_cb(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) +{ + CORE4MachineState *core4ms = CORE4_MACHINE(hotplug_dev); + Error *local_err = NULL; + + if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { + hotplug_handler_unplug_request(HOTPLUG_HANDLER(core4ms->acpi_dev), + dev, &local_err); + } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { + sw64_cpu_unplug_request(hotplug_dev, dev, &local_err); + } else { + error_setg(&local_err, "device unplug request for unsupported device" + " type: %s", object_get_typename(OBJECT(dev))); + } +} + +static void core4_machine_device_unplug_cb(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) +{ + MachineState *ms = MACHINE(hotplug_dev); + CORE4MachineState *core4ms = CORE4_MACHINE(hotplug_dev); + Error *local_err = NULL; + CPUArchId *found_cpu; + + if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { + hotplug_handler_unplug(HOTPLUG_HANDLER(core4ms->acpi_dev), + dev, &local_err); + if (local_err) { + goto out; + } + pc_dimm_unplug(PC_DIMM(dev), MACHINE(ms)); + } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { + hotplug_handler_unplug(HOTPLUG_HANDLER(core4ms->acpi_dev), + dev, &local_err); + if (local_err) { + goto out; + } + found_cpu = sw64_find_cpu_slot(MACHINE(core4ms), cpu_hot_id); + found_cpu->cpu = NULL; + sw64_qdev_unrealize(dev); + set_off_cpumask(cpu_hot_id); + } else { + error_setg(&local_err, "device unplug for unsupported device" + " type: %s", object_get_typename(OBJECT(dev))); + } + +out: + return; +} + +static void core4_machine_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc); + + mc->desc = "CORE4 BOARD"; + mc->init = core4_init; + mc->block_default_type = IF_VIRTIO; + mc->max_cpus = MAX_CPUS_CORE4; + mc->no_cdrom = 1; + mc->pci_allow_0_address = true; + mc->reset = sw64_board_reset; + mc->possible_cpu_arch_ids = sw64_possible_cpu_arch_ids; + mc->default_cpu_type = SW64_CPU_TYPE_NAME("core4"); + mc->default_ram_id = "ram"; + mc->cpu_index_to_instance_props = sw64_cpu_index_to_props; + mc->get_default_cpu_node_id = sw64_get_default_cpu_node_id; + mc->get_hotplug_handler = sw64_get_hotplug_handler; + mc->has_hotpluggable_cpus = true; + hc->pre_plug = core4_machine_device_pre_plug_cb; + hc->plug = core4_machine_device_plug_cb; + hc->unplug_request = core4_machine_device_unplug_request_cb; + hc->unplug = core4_machine_device_unplug_cb; + mc->auto_enable_numa = true; +} + +static void core4_machine_initfn(Object *obj) +{ + CORE4MachineState *c4ms = CORE4_MACHINE(obj); + + c4ms->oem_id = g_strndup(SW_ACPI_BUILD_APPNAME6, 6); + c4ms->oem_table_id = g_strndup(SW_ACPI_BUILD_APPNAME8, 8); +} + +static const TypeInfo core4_machine_info = { + .name = TYPE_CORE4_MACHINE, + .parent = TYPE_MACHINE, + .instance_size = sizeof(CORE4MachineState), + .class_size = sizeof(CORE4MachineClass), + .class_init = core4_machine_class_init, + .instance_init = core4_machine_initfn, + .interfaces = (InterfaceInfo[]) { + { TYPE_HOTPLUG_HANDLER }, + { } + }, +}; + +static void core4_machine_init(void) +{ + type_register_static(&core4_machine_info); +} + +type_init(core4_machine_init) diff --git a/hw/sw64/core4_board.c b/hw/sw64/core4_board.c new file mode 100644 index 0000000000000000000000000000000000000000..92b799d3e5097de2b366ef4300d3401fe58a7007 --- /dev/null +++ b/hw/sw64/core4_board.c @@ -0,0 +1,814 @@ +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "cpu.h" +#include "hw/sw64/core.h" +#include "hw/sw64/sunway.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 "sysemu/numa.h" +#include "sysemu/kvm.h" +#include "hw/pci/msi.h" +#include "sysemu/device_tree.h" +#include "qemu/datadir.h" +#include "hw/sw64/gpio.h" + +#define CORE4_MAX_CPUS_MASK 0x3ff +#define CORE4_CORES_SHIFT 10 +#define CORE4_CORES_MASK 0x3ff +#define CORE4_THREADS_SHIFT 20 +#define CORE4_THREADS_MASK 0xfff + +#define DOMAIN_ID_SHIFT 12 +#define CORE_ID_SHIFT 0 + +static unsigned long coreonlines[4]; + +static const MemMapEntry memmap[] = { + [VIRT_BOOT_FLAG] = { 0x820000, 0x20 }, + [VIRT_PCIE_MMIO] = { 0xe0000000, 0x20000000 }, + [VIRT_MSI] = { 0x8000fee00000, 0x100000 }, + [VIRT_SPBU] = { 0x803000000000, 0x1000000 }, + [VIRT_SUNWAY_GED] = { 0x803600000000, 0x20 }, + [VIRT_INTPU] = { 0x803a00000000, 0x100000 }, + [VIRT_RTC] = { 0x804910000000, 0x8 }, + [VIRT_FW_CFG] = { 0x804920000000, 0x18 }, + [VIRT_GPIO] = { 0x804930000000, 0x0000008000 }, + [VIRT_PCIE_IO_BASE] = { 0x880000000000, 0x890000000000 }, + [VIRT_PCIE_PIO] = { 0x880100000000, 0x100000000 }, + [VIRT_UART] = { 0x8801000003f8, 0x10 }, + [VIRT_PCIE_CFG] = { 0x880600000000, 0x100000000 }, + [VIRT_HIGH_PCIE_MMIO] = { 0x888000000000, 0x8000000000 }, +}; + +static const int irqmap[] = { + [VIRT_UART] = 12, + [VIRT_SUNWAY_GED] = 13, + [VIRT_GPIO] = 15, +}; + +static void core4_virt_build_smbios(CORE4MachineState *core4ms) +{ + FWCfgState *fw_cfg = core4ms->fw_cfg; + + if (!fw_cfg) + return; + + sw64_virt_build_smbios(fw_cfg); +} + +static uint64_t spbu_read(void *opaque, hwaddr addr, unsigned size) +{ + MachineState *ms = MACHINE(qdev_get_machine()); + unsigned int smp_cpus = ms->smp.cpus; + unsigned int smp_threads = ms->smp.threads; + unsigned int smp_cores = ms->smp.cores; + unsigned int max_cpus = ms->smp.max_cpus; + uint64_t ret = 0; + switch (addr) { + case 0x0080: + /* SMP_INFO */ + { + ret = (smp_threads & CORE4_THREADS_MASK) << CORE4_THREADS_SHIFT; + ret += (smp_cores & CORE4_CORES_MASK) << CORE4_CORES_SHIFT; + ret += max_cpus & CORE4_MAX_CPUS_MASK; + } + break; + case 0x0100: + /* VT_ONLINE_CPU */ + ret = smp_cpus; + break; + case 0x3a00: + /* CLU_LV2_SEL_H */ + ret = 1; + break; + case 0x0680: + /* INIT_CTL */ + ret = 0x3ae0007802c; + break; + case 0x0780: + /* CORE_ONLINE */ + ret = convert_bit(max_cpus); + break; + case 0x3780: + /* MC_ONLINE */ + ret = convert_bit(smp_cpus); + break; + default: + fprintf(stderr, "Unsupported MCU addr: 0x%04lx\n", addr); + return -1; + } + return ret; +} + +static void spbu_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) +{ +#ifdef CONFIG_DUMP_PRINTK + uint64_t print_addr; + uint32_t len; + int i; + + if (kvm_enabled()) + return; + + 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 +} + +static const MemoryRegionOps spbu_ops = { + .read = spbu_read, + .write = spbu_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; + return ret; +} + +static void intpu_write(void *opaque, hwaddr addr, uint64_t val, + unsigned size) +{ + SW64CPU *cpu_current = SW64_CPU(current_cpu); + + if (kvm_enabled()) + return; + + switch (addr) { + case 0x00: + if (((cpu_current->env.csr[II_REQ] >> 16) & 7) == 6) + cpu_interrupt(qemu_get_cpu(val & 0x3f), CPU_INTERRUPT_IINM); + else + cpu_interrupt(qemu_get_cpu(val & 0x3f), CPU_INTERRUPT_II0); + cpu_current->env.csr[II_REQ] &= ~(1 << 20); + break; + default: + fprintf(stderr, "Unsupported IPU addr: 0x%04lx\n", addr); + break; + } +} + +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 void create_fdt_clk(CORE4MachineState *c4ms) +{ + FILE *fp; + char buff[64]; + char *nodename; + unsigned long mclk_hz; + MachineState *ms = MACHINE(c4ms); + + fp = fopen("/sys/kernel/debug/sw64/mclk_hz", "rb"); + if (fp == NULL) { + fprintf(stderr, "%s: Failed to open file mclk_hz\n", __func__); + return; + } + + if (fgets(buff, 64, fp) == NULL) { + fprintf(stderr, "%s: Error in reading mclk_hz\n", __func__); + fclose(fp); + fp = NULL; + return; + } + + mclk_hz = atoi(buff); + fclose(fp); + + qemu_fdt_add_subnode(ms->fdt, "/soc/clocks"); + + nodename = g_strdup_printf("/soc/clocks/mclk"); + qemu_fdt_add_subnode(ms->fdt, nodename); + qemu_fdt_setprop_string(ms->fdt, nodename, "compatible", "sw64,mclk"); + qemu_fdt_setprop_cell(ms->fdt, nodename, "clock-frequency", mclk_hz); + qemu_fdt_setprop_cell(ms->fdt, nodename, "#clock-cells", 0x0); + qemu_fdt_setprop_string(ms->fdt, nodename, "clock-output-names", "mclk"); + g_free(nodename); + + nodename = g_strdup_printf("/soc/clocks/extclk"); + qemu_fdt_add_subnode(ms->fdt, nodename); + qemu_fdt_setprop_string(ms->fdt, nodename, "compatible", "sw64,extclk"); + qemu_fdt_setprop_cell(ms->fdt, nodename, "clock-frequency", 0x0); + qemu_fdt_setprop_cell(ms->fdt, nodename, "#clock-cells", 0x0); + qemu_fdt_setprop_string(ms->fdt, nodename, "clock-output-names", "extclk"); + g_free(nodename); +} + +static void core4_set_coreonline(int cpuid) +{ + set_bit(cpuid, coreonlines); +} + +static int core4_get_stat_coreonline(int cpuid) +{ + int ret = test_bit(cpuid, coreonlines); + + clear_bit(cpuid, coreonlines); + return ret; +} + +static void core4_numa_set_coreonlines(MachineState *ms, int node, + unsigned int *logical_core_id, int *coreid_idx) +{ + unsigned int max_cpus = ms->smp.max_cpus; + int i, cpu_node_id, shift = 0; + + for (i = 0; i < max_cpus; i++) { + cpu_node_id = ms->possible_cpus->cpus[i].props.node_id; + + if (cpu_node_id == node) { + core4_set_coreonline(shift); + logical_core_id[*coreid_idx] = i; + shift++; + (*coreid_idx)++; + } + } +} + +static void core4_get_cpu_to_rcid(MachineState *ms, + unsigned long *__cpu_to_rcid) +{ + int nb_numa_nodes = ms->numa_state->num_nodes; + unsigned long rcid[MAX_CPUS_CORE4]; + unsigned int logical_core_id[MAX_CPUS_CORE4]; + int i, j, coreid_idx = 0, cpuid = 0, idx = 0; + + for (i = 0; i < nb_numa_nodes; i++) { + core4_numa_set_coreonlines(ms, i, logical_core_id, &coreid_idx); + + for (j = 0; j < MAX_CPUS_CORE4; j++) { + if (core4_get_stat_coreonline(j)) { + rcid[idx] = (i << DOMAIN_ID_SHIFT) | (j << CORE_ID_SHIFT); + idx++; + } + } + } + + for (i = 0; i < ms->smp.max_cpus; i++) { + cpuid = logical_core_id[i]; + __cpu_to_rcid[cpuid] = rcid[i]; + } + + cpuid = ms->smp.max_cpus; + while (cpuid < MAX_CPUS_CORE4) { + __cpu_to_rcid[cpuid] = -1; + cpuid++; + } +} + +static int core4_fdt_add_memory_node(void *fdt, hwaddr mem_base, + hwaddr mem_len, int numa_node_id) +{ + char *nodename; + int ret; + + nodename = g_strdup_printf("/memory@%" PRIx64, mem_base); + qemu_fdt_add_subnode(fdt, nodename); + qemu_fdt_setprop_string(fdt, nodename, "device_type", "memory"); + ret = qemu_fdt_setprop_sized_cells(fdt, nodename, "reg", 2, mem_base, + 2, mem_len); + if (ret < 0) { + goto out; + } + + /* only set the NUMA ID if it is specified */ + if (numa_node_id >= 0) { + ret = qemu_fdt_setprop_cell(fdt, nodename, + "numa-node-id", numa_node_id); + } +out: + g_free(nodename); + return ret; +} + +static void core4_add_memory_node(MachineState *ms) +{ + hwaddr mem_len, mem_start; + int nb_numa_nodes = ms->numa_state->num_nodes; + int i, rc; + + if (ms->numa_state != NULL && nb_numa_nodes > 0) { + for (i = 0; i < nb_numa_nodes; i++) { + mem_len = ms->numa_state->nodes[i].node_mem; + if (!mem_len) { + continue; + } + + if (!i) { + mem_start = 0x910000; + mem_len -= mem_start; + } + + rc = core4_fdt_add_memory_node(ms->fdt, mem_start, mem_len, i); + if (rc < 0) { + fprintf(stderr, "couldn't add /memory@%"PRIx64" node\n", + mem_start); + } + mem_start += mem_len; + } + } +} + +static void core4_add_cpu_map(CORE4MachineState *c4ms) +{ + MachineState *ms = MACHINE(c4ms); + int cpu; + + qemu_fdt_add_subnode(ms->fdt, "/cpus/cpu-map"); + + for (cpu = ms->smp.max_cpus - 1; cpu >= 0; cpu--) { + char *cpu_path = g_strdup_printf("/cpus/cpu@%d", cpu); + char *map_path; + + if (ms->smp.threads > 1) { + map_path = g_strdup_printf( + "/cpus/cpu-map/cluster%d/core%d/thread%d", + cpu / (ms->smp.cores * ms->smp.threads), + (cpu / ms->smp.threads) % ms->smp.cores, + cpu % ms->smp.threads); + } else { + map_path = g_strdup_printf( + "/cpus/cpu-map/cluster%d/core%d", + cpu / ms->smp.cores, + cpu % ms->smp.cores); + } + + qemu_fdt_add_path(ms->fdt, map_path); + qemu_fdt_setprop_phandle(ms->fdt, map_path, "cpu", cpu_path); + + g_free(map_path); + g_free(cpu_path); + } +} + +static void core4_add_cpu_node(CORE4MachineState *c4ms) +{ + MachineState *ms = MACHINE(c4ms); + unsigned long __cpu_to_rcid[MAX_CPUS_CORE4]; + char *nodename; + int cpu; + + qemu_fdt_add_subnode(ms->fdt, "/cpus"); + qemu_fdt_setprop_cell(ms->fdt, "/cpus", "#address-cells", 1); + qemu_fdt_setprop_cell(ms->fdt, "/cpus", "#size-cells", 0x0); + + core4_get_cpu_to_rcid(ms, __cpu_to_rcid); + for (cpu = ms->smp.max_cpus - 1; cpu >= 0; cpu--) { + nodename = g_strdup_printf("/cpus/cpu@%d", cpu); + + qemu_fdt_add_subnode(ms->fdt, nodename); + if (ms->possible_cpus->cpus[cpu].props.has_node_id) { + qemu_fdt_setprop_cell(ms->fdt, nodename, "numa-node-id", + ms->possible_cpus->cpus[cpu].props.node_id); + } + qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "sw64,boot_flag_address", + 1, 0x0, 1, c4ms->memmap[VIRT_BOOT_FLAG].base); + qemu_fdt_setprop_cell(ms->fdt, nodename, "reg", __cpu_to_rcid[cpu]); + qemu_fdt_setprop_string(ms->fdt, nodename, "device_type", "cpu"); + qemu_fdt_setprop_string(ms->fdt, nodename, + "compatible", "sw64,junzhang"); + qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle", + qemu_fdt_alloc_phandle(ms->fdt)); + + if (cpu < ms->smp.cpus) { + qemu_fdt_setprop_cell(ms->fdt, nodename, "online-capable", 0); + qemu_fdt_setprop_string(ms->fdt, nodename, "status", "okay"); + } else { + qemu_fdt_setprop_cell(ms->fdt, nodename, "online-capable", 1); + qemu_fdt_setprop_string(ms->fdt, nodename, "status", "disable"); + } + + g_free(nodename); + } + + core4_add_cpu_map(c4ms); +} + +static void core4_add_distance_map_node(MachineState *ms) +{ + int size; + uint32_t *matrix; + int idx, i, j; + int nb_numa_nodes = ms->numa_state->num_nodes; + + if (nb_numa_nodes > 0 && ms->numa_state->have_numa_distance) { + size = nb_numa_nodes * nb_numa_nodes * 3 * sizeof(uint32_t); + matrix = g_malloc0(size); + + for (i = 0; i < nb_numa_nodes; i++) { + for (j = 0; j < nb_numa_nodes; j++) { + idx = (i * nb_numa_nodes + j) * 3; + matrix[idx + 0] = cpu_to_be32(i); + } + } + + qemu_fdt_add_subnode(ms->fdt, "/distance-map"); + qemu_fdt_setprop_string(ms->fdt, "/distance-map", "compatible", + "numa-distance-map-v1"); + qemu_fdt_setprop(ms->fdt, "/distance-map", "distance-matrix", + matrix, size); + g_free(matrix); + } +} + +static void core4_create_numa_fdt(CORE4MachineState *c4ms) +{ + MachineState *ms = MACHINE(c4ms); + + /* Add memory node information */ + core4_add_memory_node(ms); + /* Add cpus node information */ + core4_add_cpu_node(c4ms); + /* Add distance-map node information */ + core4_add_distance_map_node(ms); +} + +static void create_fdt_misc_platform(CORE4MachineState *c4ms) +{ + char *nodename; + MachineState *ms = MACHINE(c4ms); + + nodename = g_strdup_printf("/soc/misc_platform@0"); + qemu_fdt_add_subnode(ms->fdt, nodename); + qemu_fdt_setprop_string(ms->fdt, nodename, + "compatible", "sunway,misc-platform"); + qemu_fdt_setprop_cell(ms->fdt, nodename, "numa-node-id", 0); + qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "sunway,spbu_base", + 2, c4ms->memmap[VIRT_SPBU].base); + qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "sunway,intpu_base", + 2, c4ms->memmap[VIRT_INTPU].base); + g_free(nodename); +} + +static void core4_create_fdt(CORE4MachineState *c4ms) +{ + uint32_t intc_phandle; + MachineState *ms = MACHINE(c4ms); + + if (ms->dtb) { + char *filename; + + filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, ms->dtb); + if (!filename) { + fprintf(stderr, "Couldn't open dtb file %s\n", ms->dtb); + exit(1); + } + + ms->fdt = load_device_tree(ms->dtb, &c4ms->fdt_size); + if (!ms->fdt) { + error_report("load_device_tree() failed"); + exit(1); + } + goto update_bootargs; + } else { + ms->fdt = create_device_tree(&c4ms->fdt_size); + if (!ms->fdt) { + error_report("create_device_tree() failed"); + exit(1); + } + + qemu_fdt_setprop_string(ms->fdt, "/", "compatible", "sunway,chip4"); + qemu_fdt_setprop_string(ms->fdt, "/", "model", "chip4"); + qemu_fdt_setprop_cell(ms->fdt, "/", "#address-cells", 0x2); + qemu_fdt_setprop_cell(ms->fdt, "/", "#size-cells", 0x2); + + qemu_fdt_add_subnode(ms->fdt, "/chosen"); + + qemu_fdt_add_subnode(ms->fdt, "/soc"); + qemu_fdt_setprop_string(ms->fdt, "/soc", "compatible", "simple-bus"); + qemu_fdt_setprop_cell(ms->fdt, "/soc", "#address-cells", 0x2); + qemu_fdt_setprop_cell(ms->fdt, "/soc", "#size-cells", 0x2); + qemu_fdt_setprop(ms->fdt, "/soc", "ranges", NULL, 0); + + intc_phandle = qemu_fdt_alloc_phandle(ms->fdt); + qemu_fdt_add_subnode(ms->fdt, "/soc/interrupt-controller"); + qemu_fdt_setprop_string(ms->fdt, "/soc/interrupt-controller", + "compatible", "sw64,pintc_vt"); + qemu_fdt_setprop(ms->fdt, "/soc/interrupt-controller", + "interrupt-controller", NULL, 0); + qemu_fdt_setprop_cell(ms->fdt, "/soc/interrupt-controller", + "sw64,node", 0); + qemu_fdt_setprop_cell(ms->fdt, "/soc/interrupt-controller", + "sw64,irq-num", 16); + qemu_fdt_setprop_cell(ms->fdt, "/soc/interrupt-controller", + "sw64,ver", 0x1); + qemu_fdt_setprop_cell(ms->fdt, "/soc/interrupt-controller", + "#interrupt-cells", 0x1); + qemu_fdt_setprop_cell(ms->fdt, "/soc/interrupt-controller", + "phandle", intc_phandle); + + qemu_fdt_add_subnode(ms->fdt, "/soc/serial0@8801"); + qemu_fdt_setprop_cell(ms->fdt, "/soc/serial0@8801", + "#address-cells", 0x2); + qemu_fdt_setprop_cell(ms->fdt, "/soc/serial0@8801", + "#size-cells", 0x2); + qemu_fdt_setprop_string(ms->fdt, "/soc/serial0@8801", + "compatible", "ns16550a"); + qemu_fdt_setprop_sized_cells(ms->fdt, "/soc/serial0@8801", "reg", + 2, c4ms->memmap[VIRT_UART].base, + 2, c4ms->memmap[VIRT_UART].size); + qemu_fdt_setprop_cell(ms->fdt, "/soc/serial0@8801", + "interrupt-parent", intc_phandle); + qemu_fdt_setprop_cell(ms->fdt, "/soc/serial0@8801", + "interrupts", c4ms->irqmap[VIRT_UART]); + qemu_fdt_setprop_cell(ms->fdt, "/soc/serial0@8801", "reg-shift", 0x0); + qemu_fdt_setprop_cell(ms->fdt, "/soc/serial0@8801", + "reg-io-width", 0x1); + qemu_fdt_setprop_cell(ms->fdt, "/soc/serial0@8801", + "clock-frequency", 20000000); + qemu_fdt_setprop_string(ms->fdt, "/soc/serial0@8801", + "status", "okay"); + + qemu_fdt_add_subnode(ms->fdt, "/soc/misc0@8036"); + qemu_fdt_setprop_cell(ms->fdt, "/soc/misc0@8036", + "#address-cells", 0x2); + qemu_fdt_setprop_cell(ms->fdt, "/soc/misc0@8036", "#size-cells", 0x2); + qemu_fdt_setprop_string(ms->fdt, "/soc/misc0@8036", + "compatible", "sw6,sunway-ged"); + qemu_fdt_setprop_sized_cells(ms->fdt, "/soc/misc0@8036", "reg", + 2, c4ms->memmap[VIRT_SUNWAY_GED].base, + 2, c4ms->memmap[VIRT_SUNWAY_GED].size); + qemu_fdt_setprop_cell(ms->fdt, "/soc/misc0@8036", + "interrupt-parent", intc_phandle); + qemu_fdt_setprop_cell(ms->fdt, "/soc/misc0@8036", + "interrupts", c4ms->irqmap[VIRT_SUNWAY_GED]); + qemu_fdt_setprop_cell(ms->fdt, "/soc/misc0@8036", "reg-shift", 0x0); + qemu_fdt_setprop_cell(ms->fdt, "/soc/misc0@8036", "reg-io-width", 0x8); + qemu_fdt_setprop_cell(ms->fdt, "/soc/misc0@8036", + "clock-frequency", 20000000); + qemu_fdt_setprop_string(ms->fdt, "/soc/misc0@8036", "status", "okay"); + + create_fdt_clk(c4ms); + core4_create_numa_fdt(c4ms); + create_fdt_misc_platform(c4ms); + } + +update_bootargs: + if (ms->kernel_cmdline) { + qemu_fdt_setprop_string(ms->fdt, "/chosen", "bootargs", ms->kernel_cmdline); + } +} + +static void core4_cpus_init(MachineState *ms) +{ + int i; + const CPUArchIdList *possible_cpus; + + MachineClass *mc = MACHINE_GET_CLASS(ms); + possible_cpus = mc->possible_cpu_arch_ids(ms); + + for (i = 0; i < ms->smp.cpus; i++) { + sw64_new_cpu("core4-sw64-cpu", possible_cpus->cpus[i].arch_id, + &error_fatal); + } +} + +void sw64_pm_set_irq(void *opaque, int irq, int level) +{ + if (kvm_enabled()) { + if (level == 0) + return; + kvm_set_irq(kvm_state, irq, level); + return; + } +} + +void sw64_gpio_set_irq(void *opaque, int irq, int level) +{ + if (kvm_enabled()) { + if (level == 0) { + return; + } + kvm_set_irq(kvm_state, irq, level); + return; + } +} + +static inline DeviceState *create_sw64_pm(CORE4MachineState *c4ms) +{ + DeviceState *dev; + + dev = qdev_try_new(TYPE_SW64_PM); + + if (!dev) { + printf("failed to create sw64_pm,Unknown device TYPE_SW64_PM"); + } + return dev; +} + +static inline DeviceState *create_sw64_gpio(CORE4MachineState *c4ms) +{ + DeviceState *dev; + + dev = qdev_try_new(TYPE_SW64_GPIO); + + if (!dev) { + printf("failed to create sw64_gpio,Unknown device TYPE_SW64_GPIO\n"); + } + return dev; +} + +static void sw64_create_device_memory(MachineState *machine, BoardState *bs) +{ + ram_addr_t ram_size = machine->ram_size; + ram_addr_t device_mem_size; + + /* always allocate the device memory information */ + machine->device_memory = g_malloc0(sizeof(*machine->device_memory)); + + /* initialize device memory address space */ + if (machine->ram_size < machine->maxram_size) { + device_mem_size = machine->maxram_size - machine->ram_size; + + if (machine->ram_slots > ACPI_MAX_RAM_SLOTS) { + printf("unsupported amount of memory slots: %"PRIu64, + machine->ram_slots); + exit(EXIT_FAILURE); + } + + if (QEMU_ALIGN_UP(machine->maxram_size, + TARGET_PAGE_SIZE) != machine->maxram_size) { + printf("maximum memory size must by aligned to multiple of " + "%d bytes", TARGET_PAGE_SIZE); + exit(EXIT_FAILURE); + } + + machine->device_memory->base = ram_size; + + memory_region_init(&machine->device_memory->mr, OBJECT(bs), + "device-memory", device_mem_size); + memory_region_add_subregion(get_system_memory(), machine->device_memory->base, + &machine->device_memory->mr); + } +} + +void core4_board_init(MachineState *ms) +{ + CORE4MachineState *core4ms = CORE4_MACHINE(ms); + DeviceState *dev = qdev_new(TYPE_CORE4_BOARD); + BoardState *bs = CORE4_BOARD(dev); + PCIHostState *phb = PCI_HOST_BRIDGE(dev); + PCIBus *b; + + core4ms->memmap = memmap; + core4ms->irqmap = irqmap; + + /* Create device tree */ + core4_create_fdt(core4ms); + + core4ms->acpi_dev = create_sw64_pm(core4ms); + + core4_cpus_init(ms); + + if (kvm_enabled()) { + if (kvm_has_gsi_routing()) + msi_nonbroken = true; + } + else + sw64_create_alarm_timer(ms, bs); + + sw64_create_device_memory(ms, bs); + + memory_region_add_subregion(get_system_memory(), 0, ms->ram); + + memory_region_init_io(&bs->io_spbu, NULL, &spbu_ops, bs, "io_spbu", + memmap[VIRT_SPBU].size); + memory_region_add_subregion(get_system_memory(), memmap[VIRT_SPBU].base, + &bs->io_spbu); + + memory_region_init_io(&bs->io_intpu, NULL, &intpu_ops, bs, "io_intpu", + memmap[VIRT_INTPU].size); + memory_region_add_subregion(get_system_memory(), memmap[VIRT_INTPU].base, + &bs->io_intpu); + + memory_region_init_io(&bs->msi_ep, NULL, &msi_ops, bs, "msi_ep", + memmap[VIRT_MSI].size); + memory_region_add_subregion(get_system_memory(), memmap[VIRT_MSI].base, + &bs->msi_ep); + + memory_region_init(&bs->mem_ep, OBJECT(bs), "pci0-mem", + memmap[VIRT_PCIE_IO_BASE].size); + + memory_region_add_subregion(get_system_memory(), + memmap[VIRT_PCIE_IO_BASE].base, &bs->mem_ep); + + memory_region_init_alias(&bs->mem_ep64, NULL, "mem_ep64", &bs->mem_ep, + memmap[VIRT_PCIE_IO_BASE].base, + memmap[VIRT_PCIE_IO_BASE].size); + memory_region_add_subregion(get_system_memory(), + memmap[VIRT_PCIE_IO_BASE].base, &bs->mem_ep64); + + memory_region_init_io(&bs->io_ep, OBJECT(bs), &sw64_pci_ignore_ops, NULL, + "pci0-io-ep", memmap[VIRT_PCIE_PIO].size); + memory_region_add_subregion(get_system_memory(), memmap[VIRT_PCIE_PIO].base, + &bs->io_ep); + + b = pci_register_root_bus(dev, "pcie.0", sw64_board_set_irq, + sw64_board_map_irq, bs, + &bs->mem_ep, &bs->io_ep, 0, 537, TYPE_PCI_BUS); + phb->bus = b; + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); + pci_bus_set_route_irq_fn(b, sw64_route_intx_pin_to_irq); + memory_region_init_io(&bs->conf_piu0, OBJECT(bs), &sw64_pci_config_ops, b, + "pci0-ep-conf-io", memmap[VIRT_PCIE_CFG].size); + memory_region_add_subregion(get_system_memory(), + memmap[VIRT_PCIE_CFG].base, &bs->conf_piu0); + + sw64_init_rtc_base_info(); + memory_region_init_io(&bs->io_rtc, OBJECT(bs), &rtc_ops, b, + "sw64-rtc", memmap[VIRT_RTC].size); + memory_region_add_subregion(get_system_memory(), memmap[VIRT_RTC].base, + &bs->io_rtc); + object_property_add_tm(OBJECT(core4ms), "rtc-time", rtc_get_time); + + sw64_create_pcie(bs, b, phb); + + core4ms->fw_cfg = sw64_create_fw_cfg(memmap[VIRT_FW_CFG].base, + memmap[VIRT_FW_CFG].size); + rom_set_fw(core4ms->fw_cfg); + + core4ms->gpio_dev = create_sw64_gpio(core4ms); + + core4ms->bus = phb->bus; + sw64_acpi_setup((SW64MachineState *)core4ms); + + core4_virt_build_smbios(core4ms); +} + +static Property core4_main_pci_host_props[] = { + DEFINE_PROP_UINT32("ofw-addr", BoardState, ofw_addr, 0), + DEFINE_PROP_END_OF_LIST() +}; + +static char *core4_main_ofw_unit_address(const SysBusDevice *dev) +{ + BoardState *s = CORE4_BOARD(dev); + return g_strdup_printf("%x", s->ofw_addr); +} + +static void core4_board_pcihost_class_init(ObjectClass *obj, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(obj); + SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(obj); + + dc->props_ = core4_main_pci_host_props; + dc->fw_name = "pci"; + sbc->explicit_ofw_unit_address = core4_main_ofw_unit_address; +} + +static const TypeInfo swboard_pcihost_info = { + .name = TYPE_CORE4_BOARD, + .parent = TYPE_PCI_HOST_BRIDGE, + .instance_size = sizeof(BoardState), + .class_init = core4_board_pcihost_class_init, +}; + +static void swboard_register_types(void) +{ + type_register_static(&swboard_pcihost_info); +} + +type_init(swboard_register_types) diff --git a/hw/sw64/gpio.h b/hw/sw64/gpio.h new file mode 100644 index 0000000000000000000000000000000000000000..b523ab879edbe93f3286ea349184b7d67180ff15 --- /dev/null +++ b/hw/sw64/gpio.h @@ -0,0 +1,54 @@ +#ifndef HW_SW64_GPIO_H +#define HW_SW64_GPIO_H + +#include "hw/sysbus.h" + +#define TYPE_SW64_GPIO "SW64_GPIO" +#define SW64_GPIO(obj) OBJECT_CHECK(SW64GPIOState, (obj), TYPE_SW64_GPIO) + +#define GPIO_SWPORTA_DR (0x00UL) +#define GPIO_SWPORTA_DDR (0X200UL) +#define GPIO_INTEN (0X1800UL) +#define GPIO_INTMASK (0X1a00UL) +#define GPIO_INTTYPE_LEVEL (0x1c00UL) +#define GPIO_INTTYPE_POLA (0x1e00UL) +#define GPIO_INTTYPE_STATUS (0x2000UL) +#define GPIO_RAW_INTTYPE_STATUS (0x2200UL) +#define GPIO_DEB_ENABLE (0x2400UL) +#define GPIO_CLEAN_INT (0x2600UL) +#define GPIO_EXT_PORTA (0x2800UL) +#define GPIO_SYNC_LEVEL (0x3000UL) +#define GPIO_ID_CODE (0x3200UL) +#define GPIO_VERSION (0x3600UL) +#define GPIO_CONF_R1 (0x3a00UL) +#define GPIO_CONF_R2 (0x3800UL) + +#define SW64_GPIO_MEM_SIZE 0x8000 +#define SW64_GPIO_PIN_COUNT 1 + +typedef struct SW64GPIOState { + SysBusDevice parent_obj; + + uint32_t padr; + uint32_t paddr; + uint32_t inter; + uint32_t intmr; + uint32_t intlr; + uint32_t intpr; + uint32_t intsr; + uint32_t rintsr; + uint32_t deber; + uint32_t clintr; + uint32_t expar; + uint32_t synlr; + uint32_t idcr; + uint32_t versionr; + uint32_t conf1r; + uint32_t conf2r; + + qemu_irq irq[SW64_GPIO_PIN_COUNT]; + qemu_irq output[SW64_GPIO_PIN_COUNT]; +} SW64GPIOState; + +void sw64_gpio_set_irq(void *opaque, int irq, int level); +#endif diff --git a/hw/sw64/meson.build b/hw/sw64/meson.build new file mode 100644 index 0000000000000000000000000000000000000000..456eb0290be125eb49f39c58f9f3405bc67e646b --- /dev/null +++ b/hw/sw64/meson.build @@ -0,0 +1,17 @@ +sw64_ss = ss.source_set() + +sw64_ss.add(files('sunway.c'), fdt) +sw64_ss.add(when: 'CONFIG_SW64_VT_IOMMU', if_true: files('sw64_iommu.c')) +sw64_ss.add(when: 'CONFIG_ACPI', if_true: files('sw64-acpi-build.c')) + +sw64_ss.add(when: 'CONFIG_CORE3', if_true: files( + 'core3.c', + 'core3_board.c', +)) + +sw64_ss.add(when: 'CONFIG_CORE4', if_true: files( + 'core4.c', + 'core4_board.c', +)) + +hw_arch += {'sw64': sw64_ss} diff --git a/hw/sw64/pm.h b/hw/sw64/pm.h new file mode 100644 index 0000000000000000000000000000000000000000..242fef0946993be84f6f4c0d920b44f7af4c400e --- /dev/null +++ b/hw/sw64/pm.h @@ -0,0 +1,59 @@ +#ifndef HW_SW64_PM_H +#define HW_SW64_PM_H + +#include "hw/sysbus.h" +#include "hw/acpi/memory_hotplug.h" + +#include "hw/acpi/cpu_hotplug.h" +#include "hw/acpi/cpu.h" +#include "hw/irq.h" +#include "hw/acpi/acpi_dev_interface.h" +#include "hw/core/cpu.h" +#include "qemu/option.h" +#include "qemu/option_int.h" +#include "qemu/config-file.h" +#include "qapi/qmp/qdict.h" + +#define SUNWAY_CPUHOTPLUG_ADD 0x4 +#define SUNWAY_CPUHOTPLUG_REMOVE 0x8 +#define OFFSET_CPUID 0x20 + +extern int cpu_hot_id; +int get_state_cpumask(int cpu_num); +void sw64_cpu_hotplug_hw_init(CPUHotplugState *state, hwaddr base_addr); +void sw64_acpi_switch_to_modern_cphp(CPUHotplugState *cpuhp_state, uint16_t io_port); + +#define OFFSET_START_ADDR 0x0 +#define OFFSET_LENGTH 0x8 +#define OFFSET_STATUS 0x10 +#define OFFSET_SLOT 0x18 + +#define OFFSET_NODE 0x28 + +#define SUNWAY_MEMHOTPLUG_ADD 0x1 +#define SUNWAY_MEMHOTPLUG_REMOVE 0x2 + +typedef struct SW64PMState { + /*< private >*/ + SysBusDevice parent_obj; + /*< public >*/ + + qemu_irq irq; + MemHotplugState acpi_memory_hotplug; + unsigned long addr; + unsigned long length; + unsigned long status; + unsigned long slot; + unsigned long cpuid; + unsigned long node; + bool cpu_hotplug_legacy; + AcpiCpuHotplug gpe_cpu; + CPUHotplugState cpuhp_state; +} SW64PMState; + +#define TYPE_SW64_PM "SW64_PM" + +DECLARE_INSTANCE_CHECKER(SW64PMState, SW64_PM, TYPE_SW64_PM) + +void sw64_pm_set_irq(void *opaque, int irq, int level); +#endif diff --git a/hw/sw64/sunway.c b/hw/sw64/sunway.c new file mode 100644 index 0000000000000000000000000000000000000000..a0544cb2963ca37d8185ed3164f0774f2919840c --- /dev/null +++ b/hw/sw64/sunway.c @@ -0,0 +1,628 @@ +/* + * QEMU SUNWAY syetem helper. + * + * Copyright (c) 2023 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 "qapi/error.h" +#include "cpu.h" +#include "hw/hw.h" +#include "hw/irq.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/char/serial.h" +#include "hw/pci/msi.h" +#include "hw/firmware/smbios.h" +#include "hw/nvram/fw_cfg.h" +#include "qemu/cutils.h" +#include "ui/console.h" +#include "hw/sw64/core.h" +#include "hw/sw64/sunway.h" +#include "sysemu/numa.h" +#include "net/net.h" +#include "sysemu/device_tree.h" +#include + +#define SW_PIN_TO_IRQ 16 +#define SW_FDT_BASE 0x2d00000ULL +#define SW_BIOS_BASE 0x2f00000ULL +#define SW_INITRD_BASE 0x3000000UL + +static uint64_t base_rtc; +static uint64_t last_update; +unsigned long dtb_start_c4; + +void sw64_init_rtc_base_info(void) +{ + struct tm tm; + qemu_get_timedate(&tm, 0); + base_rtc = mktimegm(&tm); + last_update = get_clock_realtime() / NANOSECONDS_PER_SECOND; +} + +static uint64_t rtc_read(void *opaque, hwaddr addr, unsigned size) +{ + uint64_t val; + uint64_t guest_clock = get_clock_realtime() / NANOSECONDS_PER_SECOND; + + val = base_rtc + guest_clock - last_update; + + return val; +} + +static void rtc_write(void *opaque, hwaddr addr, uint64_t val, + unsigned size) +{ +} + +const MemoryRegionOps rtc_ops = { + .read = rtc_read, + .write = rtc_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 sw64_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 sw64_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 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) +{ + int ret = 0; + MSIMessage msg = {}; + + if (!kvm_enabled()) + return MEMTX_DECODE_ERROR; + + 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)); + } + + return MEMTX_OK; +} + +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, + }, +}; + +uint64_t cpu_sw64_virt_to_phys(void *opaque, uint64_t addr) +{ + return addr &= ~0xffffffff80000000 ; +} + +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; +} + +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; +} + +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.has_core_id = true; + ms->possible_cpus->cpus[i].props.has_socket_id = true; + ms->possible_cpus->cpus[i].props.core_id = i; + ms->possible_cpus->cpus[i].props.thread_id = 0; + ms->possible_cpus->cpus[i].props.socket_id = 0; + } + + return ms->possible_cpus; +} + +void sw64_cpu_reset(void *opaque) +{ + SW64CPU *cpu = opaque; + + if (!kvm_enabled()) + cpu_reset(CPU(cpu)); + + return; +} + +void sw64_set_clocksource(void) +{ + FILE *fp; + unsigned long mclk; + char buff[64]; + + fp = fopen("/sys/kernel/debug/sw64/mclk", "rb"); + if (fp == NULL) { + printf("Failed to open file mclk \n"); + return; + } + + if (fgets(buff, 64, fp) == NULL) { + printf("Error in reading mclk \n"); + fclose(fp); + fp = NULL; + return; + } + + mclk = atoi(buff); + fclose(fp); + rom_add_blob_fixed("mclk", (char *)&mclk, 0x8, 0x908001); +} + +void sw64_board_reset(MachineState *state) +{ + qemu_devices_reset(); +} + +void sw64_set_ram_size(ram_addr_t ram_size) +{ + ram_addr_t buf; + + if (kvm_enabled()) + buf = ram_size; + else + buf = ram_size | (1UL << 63); + + rom_add_blob_fixed("ram_size", (char *)&buf, 0x8, 0x2040); + + return; +} + +void sw64_clear_uefi_bios(void) +{ + unsigned long uefi_bios[1] = {0}; + + /* Clear the first 8 bytes of UEFI BIOS to ensure the correctness + * of reset process. + * */ + rom_add_blob_fixed("uefi_bios", uefi_bios, 0x8, SW_BIOS_BASE); + + return; +} + +void sw64_clear_smp_rcb(void) +{ + unsigned long smp_rcb[4] = {0}; + + /* Clear the smp_rcb fields to ensure the correctness of reset process. */ + rom_add_blob_fixed("smp_rcb", smp_rcb, 0x20, 0x820000); + + return; +} + +void sw64_clear_kernel_print(void) +{ + unsigned long kernel_print[2048] = {0}; + + /* + * Clear the memory where the kernel is printed when the vm reboots + * will make debugging easier. + */ + rom_add_blob_fixed("kernel_print", kernel_print, 0x4000, 0x700000); + + return; +} + +void sw64_load_hmcode(const char *hmcode_filename, uint64_t *hmcode_entry) +{ + long size; + + size = load_elf(hmcode_filename, NULL, cpu_sw64_virt_to_phys, NULL, + hmcode_entry, NULL, NULL, NULL, 0, EM_SW64, 0, 0); + if (size < 0) { + error_report("could not load hmcode: '%s'", hmcode_filename); + exit(1); + } + + return; +} + +void sw64_find_and_load_bios(const char *bios_name) +{ + char *uefi_filename; + long size; + + uefi_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); + if (uefi_filename == NULL) { + error_report("no virtual bios provided"); + exit(1); + } + + size = load_image_targphys(uefi_filename, SW_BIOS_BASE, -1); + if (size < 0) { + error_report("could not load virtual bios: '%s'", uefi_filename); + exit(1); + } + + g_free(uefi_filename); + return; +} + +void sw64_load_kernel(const char *kernel_filename, uint64_t *kernel_entry, + const char *kernel_cmdline) +{ + long size; + uint64_t param_offset; + + size = load_elf(kernel_filename, NULL, cpu_sw64_virt_to_phys, NULL, + kernel_entry, NULL, NULL, NULL, 0, EM_SW64, 0, 0); + if (size < 0) { + error_report("could not load kernel '%s'", kernel_filename); + exit(1); + } + + if (kernel_cmdline) { + param_offset = 0x90B000UL; + pstrcpy_targphys("cmdline", param_offset, 0x400, kernel_cmdline); + } + + return; +} + +void sw64_load_initrd(const char *initrd_filename, + BOOT_PARAMS *sunway_boot_params) +{ + long initrd_size; + + initrd_size = get_image_size(initrd_filename); + if (initrd_size < 0) { + error_report("could not load initial ram disk '%s'", + initrd_filename); + exit(1); + } + /* Put the initrd image as high in memory as possible. */ + load_image_targphys(initrd_filename, SW_INITRD_BASE, initrd_size); + sunway_boot_params->initrd_start = SW_INITRD_BASE | 0xfff0000000000000UL; + sunway_boot_params->initrd_size = initrd_size; + + return; +} + +int sw64_load_dtb(MachineState *ms, BOOT_PARAMS *sunway_boot_params) +{ + int ret, fdt_size; + hwaddr fdt_base; + + if (ms->kernel_filename) { + /* For direct kernel boot, place the DTB after the initrd to avoid + * overlaying the loaded kernel. + */ + sunway_boot_params->dtb_start = (SW_INITRD_BASE | 0xfff0000000000000UL) + + sunway_boot_params->initrd_size; + } else { + /* For BIOS boot, place the DTB at SW_FDT_BASE temporarily, the + * bootloader will move it to a more proper place later. + */ + sunway_boot_params->dtb_start = SW_FDT_BASE | 0xfff0000000000000UL; + } + + if (!ms->fdt) { + fprintf(stderr, "Board was unable to create a dtb blob\n"); + return -1; + } + + ret = fdt_pack(ms->fdt); + /* Should only fail if we've built a corrupted tree */ + g_assert(ret == 0); + fdt_size = fdt_totalsize(ms->fdt); + qemu_fdt_dumpdtb(ms->fdt, fdt_size); + + /* Put the DTB into the memory map as a ROM image: this will ensure + * the DTB is copied again upon reset, even if addr points into RAM. + */ + fdt_base = sunway_boot_params->dtb_start & (~0xfff0000000000000UL); + + dtb_start_c4 = sunway_boot_params->dtb_start; + + rom_add_blob_fixed("dtb", ms->fdt, fdt_size, fdt_base); + + return 0; +} + +void sw64_board_alarm_timer(void *opaque) +{ + TimerState *ts = (TimerState *)((uintptr_t)opaque); + + if (!kvm_enabled()) { + int cpu = ts->order; + cpu_interrupt(qemu_get_cpu(cpu), CPU_INTERRUPT_TIMER); + } + + return; +} + +void sw64_create_alarm_timer(MachineState *ms, BoardState *bs) +{ + TimerState *ts; + SW64CPU *cpu; + int i; + + for (i = 0; i < ms->smp.cpus; ++i) { + cpu = SW64_CPU(qemu_get_cpu(i)); + ts = g_new(TimerState, 1); + ts->opaque = (void *) ((uintptr_t)bs); + ts->order = i; + cpu->alarm_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, + &sw64_board_alarm_timer, ts); + } +} + +PCIINTxRoute sw64_route_intx_pin_to_irq(void *opaque, int pin) +{ + PCIINTxRoute route; + + route.mode = PCI_INTX_ENABLED; + route.irq = SW_PIN_TO_IRQ; + return route; +} + +uint64_t convert_bit(int n) +{ + uint64_t ret; + + if (n == 64) + ret = 0xffffffffffffffffUL; + else + ret = (1UL << n) - 1; + + return ret; +} + +FWCfgState *sw64_create_fw_cfg(hwaddr addr, hwaddr size) +{ + MachineState *ms = MACHINE(qdev_get_machine()); + uint16_t smp_cpus = ms->smp.cpus; + FWCfgState *fw_cfg; + + fw_cfg = fw_cfg_init_mem_wide(addr + 8, addr, 8, + addr + 16, &address_space_memory); + fw_cfg_add_i16(fw_cfg, FW_CFG_NB_CPUS, smp_cpus); + + if (!ms->dtb) { + char *nodename; + + nodename = g_strdup_printf("/soc/fw_cfg@8049"); + qemu_fdt_add_subnode(ms->fdt, nodename); + qemu_fdt_setprop_string(ms->fdt, nodename, + "compatible", "qemu,fw-cfg-mmio"); + qemu_fdt_setprop(ms->fdt, nodename, "dma-coherent", NULL, 0); + qemu_fdt_setprop_sized_cells(ms->fdt, nodename, + "reg", 2, addr, 2, size); + g_free(nodename); + } + + return fw_cfg; +} + +void sw64_virt_build_smbios(FWCfgState *fw_cfg) +{ + uint8_t *smbios_tables, *smbios_anchor; + size_t smbios_tables_len, smbios_anchor_len; + const char *product = "QEMU Virtual Machine"; + + if (kvm_enabled()) + product = "KVM Virtual Machine"; + + smbios_set_defaults("QEMU", product, + "sw64", false, + true, NULL, NULL, SMBIOS_ENTRY_POINT_30); + + smbios_get_tables(MACHINE(qdev_get_machine()), NULL, 0, + &smbios_tables, &smbios_tables_len, + &smbios_anchor, &smbios_anchor_len, + &error_fatal); + + if (smbios_anchor) { + fw_cfg_add_file(fw_cfg, "etc/smbios/smbios-tables", + smbios_tables, smbios_tables_len); + fw_cfg_add_file(fw_cfg, "etc/smbios/smbios-anchor", + smbios_anchor, smbios_anchor_len); + } + + return; +} + +void sw64_board_set_irq(void *opaque, int irq, int level) +{ + if (level == 0) + return; + + if (kvm_enabled()) { + kvm_set_irq(kvm_state, irq, level); + return; + } + + cpu_interrupt(qemu_get_cpu(0), CPU_INTERRUPT_PCIE); +} + +int sw64_board_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; +} + +void serial_set_irq(void *opaque, int irq, int level) +{ + if (level == 0) + return; + + if (kvm_enabled()) { + kvm_set_irq(kvm_state, irq, level); + return; + } + + cpu_interrupt(qemu_get_cpu(0), CPU_INTERRUPT_HARD); +} + +void sw64_new_cpu(const char *name, int64_t arch_id, Error **errp) +{ + Object *cpu = NULL; + Error *local_err = NULL; + + cpu = object_new(name); + object_property_set_uint(cpu, "core-id", arch_id, &local_err); + object_property_set_bool(cpu, "realized", true, &local_err); + + object_unref(cpu); + error_propagate(errp, local_err); +} + +void sw64_create_pcie(BoardState *bs, PCIBus *b, PCIHostState *phb) +{ + int i; + + for (i = 0; i < nb_nics; i++) { + pci_nic_init_nofail(&nd_table[i], b, "e1000", NULL); + } + + pci_vga_init(b); + + bs->serial_irq = qemu_allocate_irq(serial_set_irq, bs, 12); + if (serial_hd(0)) { + serial_mm_init(get_system_memory(), 0x3F8 + 0x880100000000ULL, 0, + bs->serial_irq, (1843200 >> 4), serial_hd(0), + DEVICE_LITTLE_ENDIAN); + } + + pci_create_simple(phb->bus, -1, "nec-usb-xhci"); +} + +void rtc_get_time(Object *obj, struct tm *current_tm, Error **errp) +{ + time_t guest_sec; + int64_t guest_nsec; + + guest_nsec = get_clock_realtime(); + guest_sec = guest_nsec / NANOSECONDS_PER_SECOND; + gmtime_r(&guest_sec, current_tm); +} diff --git a/hw/sw64/sw64-acpi-build.c b/hw/sw64/sw64-acpi-build.c new file mode 100644 index 0000000000000000000000000000000000000000..66f1fc746fc3cc4bf3829e07f26818bf0e687493 --- /dev/null +++ b/hw/sw64/sw64-acpi-build.c @@ -0,0 +1,876 @@ +/* Support for generating ACPI tables and passing them to Guests + * + * SW64 ACPI generation + * + * Copyright (C) 2023 Wang Yuanheng + * + * This work is licensed under the GNU GPL license version 2 or later. + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu/bitmap.h" +#include "hw/core/cpu.h" +#include "target/sw64/cpu.h" +#include "hw/acpi/acpi-defs.h" +#include "hw/acpi/acpi.h" +#include "hw/nvram/fw_cfg.h" +#include "hw/acpi/bios-linker-loader.h" +#include "hw/acpi/aml-build.h" +#include "hw/acpi/utils.h" +#include "hw/acpi/pci.h" +#include "hw/acpi/memory_hotplug.h" +#include "hw/acpi/generic_event_device.h" +#include "hw/acpi/tpm.h" +#include "hw/pci/pcie_host.h" +#include "hw/acpi/aml-build.h" +#include "hw/pci/pci.h" +#include "hw/pci/pci_bus.h" +#include "hw/pci-host/gpex.h" +#include "hw/sw64/core.h" +#include "hw/platform-bus.h" +#include "sysemu/numa.h" +#include "sysemu/reset.h" +#include "sysemu/tpm.h" +#include "kvm_sw64.h" +#include "migration/vmstate.h" +#include "hw/acpi/ghes.h" +#include "hw/sw64/gpio.h" +#include "hw/irq.h" +#include "sysemu/runstate.h" + +#define SW64_PCIE_IRQMAP 16 +#define SW64_MCU_GSI_BASE 64 +#define ACPI_BUILD_TABLE_SIZE 0x20000 + +static void acpi_dsdt_add_uart(Aml *scope, const MemMapEntry *uart_memmap, + uint32_t uart_irq) +{ + Aml *method, *dev, *crs; + Aml *pkg; + Aml *pkg0, *pkg1, *pkg2, *pkg3; + + dev = aml_device("COM0"); + aml_append(dev, aml_name_decl("_HID", aml_string("PNP0501"))); + aml_append(dev, aml_name_decl("_UID", aml_int(0))); + + crs = aml_resource_template(); + aml_append(crs, + aml_qword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED, + AML_NON_CACHEABLE, AML_READ_WRITE, + 0, uart_memmap->base, + uart_memmap->base + uart_memmap->size - 1, + 0, uart_memmap->size)); + aml_append(crs, aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH, + AML_SHARED, &uart_irq, 1)); + aml_append(dev, aml_name_decl("_CRS", crs)); + + pkg0 = aml_package(0x2); + aml_append(pkg0, aml_string("clock-frequency")); + aml_append(pkg0, aml_int(20000000)); + + pkg1 = aml_package(0x2); + aml_append(pkg1, aml_string("reg-io-width")); + aml_append(pkg1, aml_int(0x1)); + + pkg2 = aml_package(0x2); + aml_append(pkg2, aml_string("reg-shift")); + aml_append(pkg2, aml_int(0x0)); + + pkg3 = aml_package(0x3); + aml_append(pkg3, pkg0); + aml_append(pkg3, pkg1); + aml_append(pkg3, pkg2); + + pkg = aml_package(0x2); + aml_append(pkg, aml_touuid("DAFFD814-6EBA-4D8C-8A91-BC9BBF4AA301")); + aml_append(pkg, pkg3); + + aml_append(dev, aml_name_decl("_DSD", pkg)); /* Device-Specific Data */ + aml_append(scope, dev); + + method = aml_method("_STA", 0, AML_NOTSERIALIZED); + aml_append(method, aml_return(aml_int(0xF))); + aml_append(dev, method); +} + +static void acpi_dsdt_add_sunway_ged(Aml *scope, const MemMapEntry *ged_memmap, + uint32_t ged_irq) +{ + Aml *method, *dev, *crs; + Aml *pkg, *pkg0; + + dev = aml_device("SMHP"); + aml_append(dev, aml_name_decl("_HID", aml_string("SUNW1000"))); + aml_append(dev, aml_name_decl("_UID", aml_int(0))); + + crs = aml_resource_template(); + aml_append(crs, + aml_qword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED, + AML_NON_CACHEABLE, AML_READ_WRITE, + 0, ged_memmap->base, + ged_memmap->base + ged_memmap->size - 1, + 0, ged_memmap->size)); + aml_append(crs, aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH, + AML_SHARED, &ged_irq, 1)); + aml_append(dev, aml_name_decl("_CRS", crs)); + + pkg0 = aml_package(0x2); + aml_append(pkg0, aml_string("clock-frequency")); + aml_append(pkg0, aml_int(20000000)); + + pkg = aml_package(0x2); + aml_append(pkg, aml_touuid("DAFFD814-6EBA-4D8C-8A91-BC9BBF4AA301")); + aml_append(pkg, pkg0); + + aml_append(dev, aml_name_decl("_DSD", pkg)); + aml_append(scope, dev); + + method = aml_method("_STA", 0, AML_NOTSERIALIZED); + aml_append(method, aml_return(aml_int(0xF))); + aml_append(dev, method); +} + + +static void acpi_dsdt_add_fw_cfg(Aml *scope, const MemMapEntry *fw_cfg_memmap) +{ + Aml *dev = aml_device("FWCF"); + aml_append(dev, aml_name_decl("_HID", aml_string("QEMU0002"))); + /* device present, functioning, decoding, not shown in UI */ + aml_append(dev, aml_name_decl("_STA", aml_int(0xB))); + aml_append(dev, aml_name_decl("_CCA", aml_int(1))); + + Aml *crs = aml_resource_template(); + aml_append(crs, + aml_qword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED, + AML_NON_CACHEABLE, AML_READ_WRITE, + 0, fw_cfg_memmap->base, + fw_cfg_memmap->base + fw_cfg_memmap->size - 1, + 0, fw_cfg_memmap->size)); + aml_append(dev, aml_name_decl("_CRS", crs)); + aml_append(scope, dev); +} + +static void acpi_dsdt_add_pci_osc(Aml *dev) +{ + Aml *method, *UUID, *ifctx, *ifctx1, *elsectx; + + /* Declare an _OSC (OS Control Handoff) method */ + aml_append(dev, aml_name_decl("SUPP", aml_int(0))); + aml_append(dev, aml_name_decl("CTRL", aml_int(0))); + method = aml_method("_OSC", 4, AML_NOTSERIALIZED); + aml_append(method, + aml_create_dword_field(aml_arg(3), aml_int(0), "CDW1")); + + /* PCI Firmware Specification 3.0 + * 4.5.1. _OSC Interface for PCI Host Bridge Devices + * The _OSC interface for a PCI/PCI-X/PCI Express hierarchy is + * identified by the Universal Unique IDentifier (UUID) + * 33DB4D5B-1FF7-401C-9657-7441C03DD766 + */ + UUID = aml_touuid("33DB4D5B-1FF7-401C-9657-7441C03DD766"); + ifctx = aml_if(aml_equal(aml_arg(0), UUID)); + aml_append(ifctx, + aml_create_dword_field(aml_arg(3), aml_int(4), "CDW2")); + aml_append(ifctx, + aml_create_dword_field(aml_arg(3), aml_int(8), "CDW3")); + aml_append(ifctx, aml_store(aml_name("CDW2"), aml_name("SUPP"))); + aml_append(ifctx, aml_store(aml_name("CDW3"), aml_name("CTRL"))); + /* + * Allow OS control for all 5 features: + * PCIeHotplug SHPCHotplug PME AER PCIeCapability. + */ + aml_append(ifctx, aml_and(aml_name("CTRL"), aml_int(0x1F), + aml_name("CTRL"))); + + ifctx1 = aml_if(aml_lnot(aml_equal(aml_arg(1), aml_int(0x1)))); + aml_append(ifctx1, aml_or(aml_name("CDW1"), aml_int(0x08), + aml_name("CDW1"))); + aml_append(ifctx, ifctx1); + + ifctx1 = aml_if(aml_lnot(aml_equal(aml_name("CDW3"), aml_name("CTRL")))); + aml_append(ifctx1, aml_or(aml_name("CDW1"), aml_int(0x10), + aml_name("CDW1"))); + aml_append(ifctx, ifctx1); + + aml_append(ifctx, aml_store(aml_name("CTRL"), aml_name("CDW3"))); + aml_append(ifctx, aml_return(aml_arg(3))); + aml_append(method, ifctx); + + elsectx = aml_else(); + aml_append(elsectx, aml_or(aml_name("CDW1"), aml_int(4), + aml_name("CDW1"))); + aml_append(elsectx, aml_return(aml_arg(3))); + aml_append(method, elsectx); + aml_append(dev, method); +} + +static void acpi_dsdt_add_pci(Aml *scope, uint32_t irq, SW64MachineState *vms) +{ + CrsRangeEntry *entry; + Aml *dev, *rbuf, *method, *crs; + CrsRangeSet crs_range_set; + int i; + Aml *pkg0, *pkg1, *pkg; + + struct GPEXConfig cfg = { + .mmio32 = vms->memmap[VIRT_PCIE_MMIO], + .mmio64 = vms->memmap[VIRT_HIGH_PCIE_MMIO], + .pio = vms->memmap[VIRT_PCIE_PIO], + .ecam = vms->memmap[VIRT_PCIE_CFG], + .irq = irq, + .bus = vms->bus, + }; + + /* PCI0 */ + dev = aml_device("PCI0"); + aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0A08"))); + aml_append(dev, aml_name_decl("_CID", aml_eisaid("PNP0A03"))); + aml_append(dev, aml_name_decl("_SEG", aml_int(0))); + aml_append(dev, aml_name_decl("_BBN", aml_int(0))); + method = aml_method("_PXM", 0, AML_SERIALIZED); + aml_append(method, aml_return(aml_int(0x0))); + aml_append(dev, method); + + method = aml_method("_STA", 0, AML_NOTSERIALIZED); + aml_append(method, aml_return(aml_int(0xF))); + aml_append(dev, method); + + pkg1 = aml_package(0x9); + + pkg0 = aml_package(0x2); + aml_append(pkg0, aml_string("sw64,rc_config_base")); + aml_append(pkg0, aml_int(0x0)); + aml_append(pkg1, pkg0); + + pkg0 = aml_package(0x2); + aml_append(pkg0, aml_string("sw64,ep_config_base")); + aml_append(pkg0, aml_int(vms->memmap[VIRT_PCIE_CFG].base)); + aml_append(pkg1, pkg0); + + pkg0 = aml_package(0x2); + aml_append(pkg0, aml_string("sw64,ep_mem_32_base")); + aml_append(pkg0, aml_int(vms->memmap[VIRT_PCIE_IO_BASE].base + | vms->memmap[VIRT_PCIE_MMIO].base)); + aml_append(pkg1, pkg0); + + pkg0 = aml_package(0x2); + aml_append(pkg0, aml_string("sw64,ep_mem_64_base")); + aml_append(pkg0, aml_int(vms->memmap[VIRT_HIGH_PCIE_MMIO].base)); + aml_append(pkg1, pkg0); + + pkg0 = aml_package(0x2); + aml_append(pkg0, aml_string("sw64,ep_io_base")); + aml_append(pkg0, aml_int(vms->memmap[VIRT_PCIE_PIO].base)); + aml_append(pkg1, pkg0); + + pkg0 = aml_package(0x2); + aml_append(pkg0, aml_string("sw64,piu_ior0_base")); + aml_append(pkg0, aml_int(0x0)); + aml_append(pkg1, pkg0); + + pkg0 = aml_package(0x2); + aml_append(pkg0, aml_string("sw64,piu_ior1_base")); + aml_append(pkg0, aml_int(0x0)); + aml_append(pkg1, pkg0); + + pkg0 = aml_package(0x2); + aml_append(pkg0, aml_string("sw64,rc_index")); + aml_append(pkg0, aml_int(0)); + aml_append(pkg1, pkg0); + + pkg0 = aml_package(0x2); + aml_append(pkg0, aml_string("sw64,pcie_io_base")); + aml_append(pkg0, aml_int(vms->memmap[VIRT_PCIE_IO_BASE].base)); + aml_append(pkg1, pkg0); + + pkg = aml_package(0x2); + aml_append(pkg, aml_touuid("DAFFD814-6EBA-4D8C-8A91-BC9BBF4AA301")); + aml_append(pkg, pkg1); + aml_append(dev, aml_name_decl("_DSD", pkg)); + + rbuf = aml_resource_template(); + aml_append(dev, aml_name_decl("CRS0", rbuf)); + aml_append(rbuf, + aml_word_bus_number(AML_MIN_FIXED, AML_MAX_FIXED, AML_POS_DECODE, + 0x0000, 0x0000, 0xFF, 0x0000, 0x100)); + crs_range_set_init(&crs_range_set); + if (cfg.mmio32.size) { + crs_replace_with_free_ranges(crs_range_set.mem_ranges, + cfg.mmio32.base, + cfg.mmio32.base + cfg.mmio32.size - 1); + for (i = 0; i < crs_range_set.mem_ranges->len; i++) { + entry = g_ptr_array_index(crs_range_set.mem_ranges, i); + aml_append(rbuf, + aml_dword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED, + AML_NON_CACHEABLE, AML_READ_WRITE, 0x0000, + entry->base, entry->limit, + 0x0000, entry->limit - entry->base + 1)); + } + } + + if (cfg.pio.size) { + crs_replace_with_free_ranges(crs_range_set.io_ranges, + cfg.pio.base, + cfg.pio.base + cfg.pio.size - 1); + for (i = 0; i < crs_range_set.io_ranges->len; i++) { + entry = g_ptr_array_index(crs_range_set.io_ranges, i); + aml_append(rbuf, + aml_qword_io(AML_MIN_FIXED, AML_MAX_FIXED, AML_POS_DECODE, + AML_ENTIRE_RANGE, 0x0000, entry->base, + entry->limit, 0x0000, + entry->limit - entry->base + 1)); + } + } + if (cfg.mmio64.size) { + crs_replace_with_free_ranges(crs_range_set.mem_64bit_ranges, + cfg.mmio64.base, + cfg.mmio64.base + cfg.mmio64.size - 1); + for (i = 0; i < crs_range_set.mem_64bit_ranges->len; i++) { + entry = g_ptr_array_index(crs_range_set.mem_64bit_ranges, i); + aml_append(rbuf, + aml_qword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED, + AML_NON_CACHEABLE, AML_READ_WRITE, 0x0000, + entry->base, + entry->limit, 0x0000, + entry->limit - entry->base + 1)); + } + } + + method = aml_method("_CRS", 0, AML_SERIALIZED); + aml_append(method, aml_return(rbuf)); + aml_append(dev, method); + acpi_dsdt_add_pci_osc(dev); + + /* RES0 */ + Aml *dev_res0 = aml_device("%s", "RES0"); + aml_append(dev_res0, aml_name_decl("_HID", aml_string("PNP0C02"))); + crs = aml_resource_template(); + aml_append(crs, + aml_qword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED, + AML_NON_CACHEABLE, AML_READ_WRITE, 0x0000, + cfg.ecam.base, + cfg.ecam.base + cfg.ecam.size - 1, + 0x0000, + cfg.ecam.size)); + method = aml_method("_STA", 0, AML_NOTSERIALIZED); + aml_append(method, aml_return(aml_int(0xF))); + aml_append(dev, dev_res0); + aml_append(scope, dev); + crs_range_set_free(&crs_range_set); +} + +static void +build_srat(GArray *table_data, BIOSLinker *linker, SW64MachineState *vms) +{ + int i; + uint64_t mem_base; + MachineClass *mc = MACHINE_GET_CLASS(vms); + MachineState *ms = MACHINE(vms); + const CPUArchIdList *cpu_list = mc->possible_cpu_arch_ids(ms); + AcpiTable table = { .sig = "SRAT", .rev = 3, .oem_id = vms->oem_id, + .oem_table_id = vms->oem_table_id }; + + acpi_table_begin(&table, table_data); + build_append_int_noprefix(table_data, 1, 4); /* Reserved */ + build_append_int_noprefix(table_data, 0, 8); /* Reserved */ + + for (i = 0; i < cpu_list->len; ++i) { + uint32_t node_id = cpu_list->cpus[i].props.node_id; + + /* CPU Affinity Structure */ + build_append_int_noprefix(table_data, 2, 1); /* Type */ + build_append_int_noprefix(table_data, 24, 1); /* Length */ + build_append_int_noprefix(table_data, 0, 2); /* Reserved */ + /* Proximity Domain */ + build_append_int_noprefix(table_data, node_id, 4); + build_append_int_noprefix(table_data, i, 4); /* APIC ID */ + /* Flags */ + build_append_int_noprefix(table_data, 1 /* Enabled */, 4); + build_append_int_noprefix(table_data, 0, 4); /* Clock Domain */ + build_append_int_noprefix(table_data, 0, 4); /* Reserved */ + } + + /* Memory Affinity Structure */ + mem_base = 0; + for (i = 0; i < ms->numa_state->num_nodes; ++i) { + if (ms->numa_state->nodes[i].node_mem > 0) { + build_srat_memory(table_data, mem_base, + ms->numa_state->nodes[i].node_mem, i, + MEM_AFFINITY_ENABLED); + mem_base += ms->numa_state->nodes[i].node_mem; + } + } + + if (ms->device_memory) { + build_srat_memory(table_data, ms->device_memory->base, + memory_region_size(&ms->device_memory->mr), + ms->numa_state->num_nodes - 1, + MEM_AFFINITY_HOTPLUGGABLE | MEM_AFFINITY_ENABLED); + } + + acpi_table_end(linker, &table); +} + +static void build_append_mcu_intc(GArray *table_data) +{ + build_append_int_noprefix(table_data, 0x0, 1); /* Type: MCU INTC */ + build_append_int_noprefix(table_data, 1, 1); /* Status */ + build_append_int_noprefix(table_data, 0, 2); /* Reserved */ + build_append_int_noprefix(table_data, 0xf0000001, 4);/* Hardware ID */ + build_append_int_noprefix(table_data, 0, 8); /* Address Base */ + build_append_int_noprefix(table_data, 0, 4); /* Size */ + build_append_int_noprefix(table_data, SW64_MCU_GSI_BASE, 4); /* GSI Base */ + build_append_int_noprefix(table_data, 16, 4); /* GSI Count */ + build_append_int_noprefix(table_data, 0, 4); /* Cascade Vector */ +} + +static void +build_madt(GArray *table_data, BIOSLinker *linker, SW64MachineState *vms) +{ + int i; + const MemMapEntry *memmap = vms->memmap; + MachineState *ms = MACHINE(vms); + unsigned int num_cpus = ms->smp.max_cpus; + uint32_t flags, enabled, virt, online_capable; + AcpiTable table = { .sig = "APIC", .rev = 4, .oem_id = vms->oem_id, + .oem_table_id = vms->oem_table_id }; + + acpi_table_begin(&table, table_data); + + /* Local Interrupt Controller Address */ + build_append_int_noprefix(table_data, 0, 4); + /* Flags */ + build_append_int_noprefix(table_data, 0, 4); + + /* CINTC Structure */ + for (i = 0; i < num_cpus; i++) { + SW64CPU *sw64cpu = SW64_CPU(qemu_get_cpu(i)); + enabled = sw64cpu ? 1 : 0; + online_capable = !enabled << 1; + virt = 0x1 << 2; + flags = virt | online_capable | enabled; + + build_append_int_noprefix(table_data, 0x80, 1); /* Type */ + build_append_int_noprefix(table_data, 28, 1); /* Length */ + build_append_int_noprefix(table_data, 0x2, 1); /* Version */ + build_append_int_noprefix(table_data, 0, 1); /* Reserved */ + build_append_int_noprefix(table_data, flags, 4);/* Flags */ + build_append_int_noprefix(table_data, 0, 4); /* Reserved */ + build_append_int_noprefix(table_data, i, 4); /* Hardware ID */ + build_append_int_noprefix(table_data, 0, 4); /* ACPI Processor UID */ + + /* Boot Flag Address */ + if (i) { + build_append_int_noprefix(table_data, 0, 8); + } else { + build_append_int_noprefix(table_data, + memmap[VIRT_BOOT_FLAG].base, 8); + } + } + + /* PINTC Structure */ + build_append_int_noprefix(table_data, 0x81, 1); /* Type */ + build_append_int_noprefix(table_data, 60, 1); /* Length */ + build_append_int_noprefix(table_data, 0x2, 1); /* Version */ + build_append_int_noprefix(table_data, 0, 1); /* Reserved */ + /* Flags */ + build_append_int_noprefix(table_data, 0x3 /* Enabled && Virtual */, 4); + build_append_int_noprefix(table_data, 0, 4); /* Node */ + build_append_int_noprefix(table_data, 0, 8); /* Address Base */ + build_append_int_noprefix(table_data, 0, 4); /* Size*/ + /* Number of sub Interrupt Controller, only support MCU INTC now */ + build_append_int_noprefix(table_data, 1, 4); /* N */ + + /* Sub PINTC Structure[0]: MCU INTC */ + build_append_mcu_intc(table_data); + + /* MSIC Structure */ + build_append_int_noprefix(table_data, 0x82, 1); /* Type */ + build_append_int_noprefix(table_data, 56, 1); /* Length */ + build_append_int_noprefix(table_data, 0x2, 1); /* Version */ + build_append_int_noprefix(table_data, 0, 1); /* Reserved */ + build_append_int_noprefix(table_data, 0xf2000001, 4); /* Hardware ID */ + /* Flags */ + build_append_int_noprefix(table_data, 0x3 /* Enabled && Virtual */, 4); + build_append_int_noprefix(table_data, 0, 8); /* Address Base */ + build_append_int_noprefix(table_data, 0, 4); /* Size*/ + build_append_int_noprefix(table_data, 0, 4); /* Cascade Vector */ + build_append_int_noprefix(table_data, 0, 4); /* Node */ + build_append_int_noprefix(table_data, 0, 4); /* RC */ + build_append_int_noprefix(table_data, 256, 4); /* Number of Interrupt */ + build_append_int_noprefix(table_data, + memmap[VIRT_MSI].base, 8); /* Message Address */ + build_append_int_noprefix(table_data, 0, 8); /* Reserved[2] */ + + acpi_table_end(linker, &table); +} + +static void acpi_dsdt_add_gpio(Aml *scope, const MemMapEntry *gpio_memmap, + uint32_t gpio_irq) +{ + Aml *method, *dev, *crs, *dev1; + Aml *pkg, *pkg0, *pkg1, *pkg2, *pkg3; + + dev = aml_device("GPI0"); + aml_append(dev, aml_name_decl("_HID", aml_string("SUNW0002"))); + aml_append(dev, aml_name_decl("_UID", aml_int(0))); + + crs = aml_resource_template(); + aml_append(crs, + aml_qword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED, + AML_NON_CACHEABLE, AML_READ_WRITE, + 0, gpio_memmap->base, + gpio_memmap->base + gpio_memmap->size - 1, + 0, gpio_memmap->size)); + aml_append(crs, aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH, + AML_SHARED, &gpio_irq, 1)); + aml_append(dev, aml_name_decl("_CRS", crs)); + + method = aml_method("_STA", 0, AML_NOTSERIALIZED); + aml_append(method, aml_return(aml_int(0xF))); + aml_append(dev, method); + + + Aml *aei = aml_resource_template(); + const uint32_t pin_list[1] = {0}; + aml_append(aei, aml_gpio_int(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH, + AML_EXCLUSIVE, AML_PULL_DOWN, 0, pin_list, 1, + "GPI0", NULL, 0)); + aml_append(dev, aml_name_decl("_AEI", aei)); + + method = aml_method("_L00", 0, AML_NOTSERIALIZED); + aml_append(method, aml_notify(aml_name(ACPI_POWER_BUTTON_DEVICE), + aml_int(0x80))); + aml_append(dev, method); + + + dev1 = aml_device("GP00"); + aml_append(dev1, aml_name_decl("_UID", aml_int(0))); + + pkg0 = aml_package(0x2); + aml_append(pkg0, aml_string("compatible")); + aml_append(pkg0, aml_string("snps,dw-apb-gpio-port")); + + pkg1 = aml_package(0x2); + aml_append(pkg1, aml_string("reg")); + aml_append(pkg1, aml_int(0x0)); + + pkg2 = aml_package(0x2); + aml_append(pkg2, aml_string("snps,nr-gpios")); + aml_append(pkg2, aml_int(0x8)); + + pkg3 = aml_package(0x3); + aml_append(pkg3, pkg0); + aml_append(pkg3, pkg1); + aml_append(pkg3, pkg2); + + pkg = aml_package(0x2); + aml_append(pkg, aml_touuid("DAFFD814-6EBA-4D8C-8A91-BC9BBF4AA301")); + aml_append(pkg, pkg3); + + aml_append(dev1, aml_name_decl("_DSD", pkg)); + + aml_append(dev, dev1); + aml_append(scope, dev); + +} + +static void acpi_dsdt_add_misc_platform(Aml *scope, SW64MachineState *vms) +{ + Aml *method, *dev; + Aml *pkg, *pkg0, *pkg1; + + dev = aml_device("MIS0"); + aml_append(dev, aml_name_decl("_HID", aml_string("SUNW0200"))); + aml_append(dev, aml_name_decl("_UID", aml_int(0))); + + pkg1 = aml_package(0x2); + + pkg0 = aml_package(0x2); + aml_append(pkg0, aml_string("sunway,spbu_base")); + aml_append(pkg0, aml_int(vms->memmap[VIRT_SPBU].base)); + aml_append(pkg1, pkg0); + + pkg0 = aml_package(0x2); + aml_append(pkg0, aml_string("sunway,intpu_base")); + aml_append(pkg0, aml_int(vms->memmap[VIRT_INTPU].base)); + aml_append(pkg1, pkg0); + + pkg = aml_package(0x2); + aml_append(pkg, aml_touuid("DAFFD814-6EBA-4D8C-8A91-BC9BBF4AA301")); + aml_append(pkg, pkg1); + aml_append(dev, aml_name_decl("_DSD", pkg)); + + method = aml_method("_STA", 0, AML_NOTSERIALIZED); + aml_append(method, aml_return(aml_int(0xF))); + + method = aml_method("_PXM", 0, AML_SERIALIZED); + aml_append(method, aml_return(aml_int(0x0))); + aml_append(dev, method); + + aml_append(scope, dev); +} + +/* DSDT */ +static void +build_dsdt(GArray *table_data, BIOSLinker *linker, SW64MachineState *vms) +{ + Aml *scope, *dsdt; + const MemMapEntry *memmap = vms->memmap; + const int *irqmap = vms->irqmap; + AcpiTable table = { .sig = "DSDT", .rev = 2, .oem_id = vms->oem_id, + .oem_table_id = vms->oem_table_id }; + + acpi_table_begin(&table, table_data); + dsdt = init_aml_allocator(); + + /* When booting the VM with UEFI, UEFI takes ownership of the RTC hardware. + * While UEFI can use libfdt to disable the RTC device node in the DTB that + * it passes to the OS, it cannot modify AML. Therefore, we won't generate + * the RTC ACPI device at all when using UEFI. + */ + scope = aml_scope("\\_SB"); + + acpi_dsdt_add_uart(scope, &memmap[VIRT_UART], + (irqmap[VIRT_UART] + SW64_MCU_GSI_BASE)); + + acpi_dsdt_add_sunway_ged(scope, &memmap[VIRT_SUNWAY_GED], + (irqmap[VIRT_SUNWAY_GED] + SW64_MCU_GSI_BASE)); + + acpi_dsdt_add_fw_cfg(scope, &memmap[VIRT_FW_CFG]); + acpi_dsdt_add_pci(scope, SW64_PCIE_IRQMAP, vms); + + acpi_dsdt_add_gpio(scope, &memmap[VIRT_GPIO], + (irqmap[VIRT_GPIO] + SW64_MCU_GSI_BASE)); + + acpi_dsdt_add_power_button(scope); + + acpi_dsdt_add_misc_platform(scope, vms); + + aml_append(dsdt, scope); + + /* copy AML table into ACPI tables blob */ + g_array_append_vals(table_data, dsdt->buf->data, dsdt->buf->len); + + acpi_table_end(linker, &table); + free_aml_allocator(); +} + +typedef +struct AcpiBuildState { + /* Copy of table in RAM (for patching). */ + MemoryRegion *table_mr; + MemoryRegion *rsdp_mr; + MemoryRegion *linker_mr; + /* Is table patched? */ + bool patched; +} AcpiBuildState; + +static void acpi_align_size(GArray *blob, unsigned align) +{ + /* + * Align size to multiple of given size. This reduces the chance + * we need to change size in the future (breaking cross version migration). + */ + g_array_set_size(blob, ROUND_UP(acpi_data_len(blob), align)); +} + +static +void sw64_acpi_build(SW64MachineState *vms, AcpiBuildTables *tables) +{ + GArray *table_offsets; + unsigned dsdt, xsdt; + GArray *tables_blob = tables->table_data; + MachineState *ms = MACHINE(vms); + + table_offsets = g_array_new(false, true /* clear */, + sizeof(uint32_t)); + + bios_linker_loader_alloc(tables->linker, + ACPI_BUILD_TABLE_FILE, tables_blob, + 64, false /* high memory */); + + /* DSDT is pointed to by FADT */ + dsdt = tables_blob->len; + build_dsdt(tables_blob, tables->linker, vms); + + /* FADT MADT MCFG is pointed to by XSDT*/ + acpi_add_table(table_offsets, tables_blob); + { + AcpiFadtData fadt = { + .rev = 5, + .minor_ver = 1, + .flags = 1 << ACPI_FADT_F_HW_REDUCED_ACPI, + .xdsdt_tbl_offset = &dsdt, + }; + build_fadt(tables_blob, tables->linker, &fadt, vms->oem_id, + vms->oem_table_id); + } + + acpi_add_table(table_offsets, tables_blob); + build_madt(tables_blob, tables->linker, vms); + + acpi_add_table(table_offsets, tables_blob); + build_pptt(tables_blob, tables->linker, ms, + vms->oem_id, vms->oem_table_id); + + acpi_add_table(table_offsets, tables_blob); + { + AcpiMcfgInfo mcfg = { + .base = vms->memmap[VIRT_PCIE_CFG].base, + .size = vms->memmap[VIRT_PCIE_CFG].size, + }; + build_mcfg(tables_blob, tables->linker, &mcfg, vms->oem_id, + vms->oem_table_id); + } + + /* NUMA support */ + if (ms->numa_state->num_nodes > 0) { + acpi_add_table(table_offsets, tables_blob); + build_srat(tables_blob, tables->linker, vms); + + if (ms->numa_state->have_numa_distance) { + acpi_add_table(table_offsets, tables_blob); + build_slit(tables_blob, tables->linker, ms, vms->oem_id, + vms->oem_table_id); + } + } + + /* XSDT is pointed to by RSDP */ + xsdt = tables_blob->len; + build_xsdt(tables_blob, tables->linker, table_offsets, vms->oem_id, + vms->oem_table_id); + + /* RSDP is in FSEG memory, so allocate it separately */ + { + AcpiRsdpData rsdp_data = { + .revision = 2, + .oem_id = vms->oem_id, + .xsdt_tbl_offset = &xsdt, + .rsdt_tbl_offset = NULL, + }; + build_rsdp(tables->rsdp, tables->linker, &rsdp_data); + } + + /* + * The align size is 128, warn if 64k is not enough therefore + * the align size could be resized. + */ + if (tables_blob->len > ACPI_BUILD_TABLE_SIZE / 2) { + warn_report("ACPI table size %u exceeds %d bytes," + " migration may not work", + tables_blob->len, ACPI_BUILD_TABLE_SIZE / 2); + error_printf("Try removing CPUs, NUMA nodes, memory slots" + " or PCI bridges."); + } + acpi_align_size(tables_blob, ACPI_BUILD_TABLE_SIZE); + + + /* Cleanup memory that's no longer used. */ + g_array_free(table_offsets, true); +} + +static void acpi_ram_update(MemoryRegion *mr, GArray *data) +{ + uint32_t size = acpi_data_len(data); + + /* Make sure RAM size is correct - in case it got changed + * e.g. by migration */ + memory_region_ram_resize(mr, size, &error_abort); + + memcpy(memory_region_get_ram_ptr(mr), data->data, size); + memory_region_set_dirty(mr, 0, size); +} + +static void sw64_acpi_build_update(void *build_opaque) +{ + AcpiBuildState *build_state = build_opaque; + AcpiBuildTables tables; + + /* No state to update or already patched? Nothing to do. */ + if (!build_state || build_state->patched) { + return; + } + build_state->patched = true; + + acpi_build_tables_init(&tables); + + sw64_acpi_build((SW64MachineState *)MACHINE(qdev_get_machine()), &tables); + + acpi_ram_update(build_state->table_mr, tables.table_data); + acpi_ram_update(build_state->rsdp_mr, tables.rsdp); + acpi_ram_update(build_state->linker_mr, tables.linker->cmd_blob); + + acpi_build_tables_cleanup(&tables, true); +} + +static void sw64_acpi_build_reset(void *build_opaque) +{ + AcpiBuildState *build_state = build_opaque; + build_state->patched = false; +} + +static const VMStateDescription vmstate_sw64_acpi_build = { + .name = "sw64_acpi_build", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_BOOL(patched, AcpiBuildState), + VMSTATE_END_OF_LIST() + }, +}; + +static void sw64_powerdown_req(Notifier *n, void *opaque) +{ + SW64MachineState *s = container_of(n, SW64MachineState, powerdown_notifier); + + if (s->gpio_dev) { + SW64GPIOState *gpio = SW64_GPIO(s->gpio_dev); + gpio->intsr = 0x1; + qemu_irq_pulse(gpio->irq[0]); + } else { + printf("error: no gpio device found!\n"); + } + +} + +void sw64_acpi_setup(SW64MachineState *vms) +{ + AcpiBuildTables tables; + AcpiBuildState *build_state; + + if (!vms->fw_cfg) { + return; + } + + build_state = g_malloc0(sizeof *build_state); + + acpi_build_tables_init(&tables); + + sw64_acpi_build(vms, &tables); + /* Now expose it all to Guest */ + build_state->table_mr = acpi_add_rom_blob(sw64_acpi_build_update, + build_state, tables.table_data, + ACPI_BUILD_TABLE_FILE); + assert(build_state->table_mr != NULL); + + build_state->linker_mr = acpi_add_rom_blob(sw64_acpi_build_update, + build_state, + tables.linker->cmd_blob, + ACPI_BUILD_LOADER_FILE); + build_state->rsdp_mr = acpi_add_rom_blob(sw64_acpi_build_update, + build_state, tables.rsdp, + ACPI_BUILD_RSDP_FILE); + + qemu_register_reset(sw64_acpi_build_reset, build_state); + vms->powerdown_notifier.notify = sw64_powerdown_req; + qemu_register_powerdown_notifier(&vms->powerdown_notifier); + sw64_acpi_build_reset(build_state); + vmstate_register(NULL, 0, &vmstate_sw64_acpi_build, build_state); + + /* Cleanup tables but don't free the memory: we track it + * in build_state. + */ + acpi_build_tables_cleanup(&tables, false); +} diff --git a/hw/sw64/sw64_iommu.c b/hw/sw64/sw64_iommu.c new file mode 100644 index 0000000000000000000000000000000000000000..40f0ae1d304076a56b6337c5aa1a81d7e32c4436 --- /dev/null +++ b/hw/sw64/sw64_iommu.c @@ -0,0 +1,570 @@ +/* + * 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 "hw/sw64/sunway.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 IOMMUTLBEntry *swvt_lookup_ptiotlb(SW64IOMMUState *s, uint16_t source_id, + hwaddr addr) +{ + SW64PTIOTLBKey ptkey; + IOMMUTLBEntry *entry = NULL; + + ptkey.source_id = source_id; + ptkey.iova = addr; + entry = g_hash_table_lookup(s->ptiotlb, &ptkey); + + return entry; +} + +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; + + cached_entry = swvt_lookup_ptiotlb(s, source_id, aligned_addr); + + 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 0000000000000000000000000000000000000000..1aa744c984979af6d8231bcff799dc6309951030 --- /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 95b93f10027ab8e6e864585843d24be736e55e8f..e045ff2c886ac5540fc24ed0b910c9504c9aec95 100644 --- a/include/disas/dis-asm.h +++ b/include/disas/dis-asm.h @@ -191,6 +191,10 @@ enum bfd_architecture #define bfd_mach_alpha_ev4 0x10 #define bfd_mach_alpha_ev5 0x20 #define bfd_mach_alpha_ev6 0x30 + bfd_arch_sw64, /* Sw64 */ +#define bfd_mach_sw64 1 +#define bfd_mach_sw64_core3 0x10 +#define bfd_mach_sw64_core4 0x20 bfd_arch_arm, /* Advanced Risc Machines ARM */ #define bfd_mach_arm_unknown 0 #define bfd_mach_arm_2 1 @@ -429,6 +433,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_sw64 (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 c614bfb1248456e9297761d5320232eb3a52dfce..fa3e6f3d5c401ad29082e8009f21a6f6dd8c5d45 100644 --- a/include/elf.h +++ b/include/elf.h @@ -209,6 +209,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 @@ -1419,6 +1421,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/acpi/aml-build.h b/include/hw/acpi/aml-build.h index 8346003a224b027e01996024abaae0582f116ce9..2a08788a18b52be997f644e6f19ddd8b1a9abe96 100644 --- a/include/hw/acpi/aml-build.h +++ b/include/hw/acpi/aml-build.h @@ -366,6 +366,11 @@ Aml *aml_dword_io(AmlMinFixed min_fixed, AmlMaxFixed max_fixed, uint32_t addr_gran, uint32_t addr_min, uint32_t addr_max, uint32_t addr_trans, uint32_t len); +Aml *aml_qword_io(AmlMinFixed min_fixed, AmlMaxFixed max_fixed, + AmlDecode dec, AmlISARanges isa_ranges, + uint64_t addr_gran, uint64_t addr_min, + uint64_t addr_max, uint64_t addr_trans, + uint64_t len); Aml *aml_dword_memory(AmlDecode dec, AmlMinFixed min_fixed, AmlMaxFixed max_fixed, AmlCacheable cacheable, AmlReadAndWrite read_and_write, diff --git a/include/hw/sw64/core.h b/include/hw/sw64/core.h new file mode 100644 index 0000000000000000000000000000000000000000..0aa35ff8bb809306750223da0acb39458f55f97c --- /dev/null +++ b/include/hw/sw64/core.h @@ -0,0 +1,136 @@ +#ifndef HW_SW64_CORE_H +#define HW_SW64_CORE_H + +#include "hw/pci/pci_host.h" +#include "qom/object.h" +#include "hw/boards.h" +#include "hw/sw64/pm.h" +#define TYPE_CORE3_BOARD "core3-board" +#define CORE3_BOARD(obj) \ + OBJECT_CHECK(BoardState, (obj), TYPE_CORE3_BOARD) + +#define TYPE_CORE4_BOARD "core4-board" +#define CORE4_BOARD(obj) \ + OBJECT_CHECK(BoardState, (obj), TYPE_CORE4_BOARD) + +#define SW_ACPI_BUILD_APPNAME6 "SUNWAY" +#define SW_ACPI_BUILD_APPNAME8 "SUNWAY " + +#define MAX_CPUS_CORE4 256 + +extern unsigned long dtb_start_c4; + +struct SW64MachineClass { + MachineClass parent; +}; + +struct SW64MachineState { + MachineState parent; + FWCfgState *fw_cfg; + DeviceState *acpi_dev; + DeviceState *gpio_dev; + PCIBus *bus; + char *oem_id; + char *oem_table_id; + MemMapEntry *memmap; + const int *irqmap; + Notifier powerdown_notifier; +}; + +#define TYPE_SW64_MACHINE MACHINE_TYPE_NAME("sw64") +OBJECT_DECLARE_TYPE(SW64MachineState, SW64MachineClass, SW64_MACHINE) + +struct CORE3MachineClass { + MachineClass parent; +}; + +struct CORE3MachineState { + MachineState parent; + FWCfgState *fw_cfg; + DeviceState *acpi_dev; + PCIBus *bus; + char *oem_id; + char *oem_table_id; + const MemMapEntry *memmap; + const int *irqmap; + int fdt_size; +}; + +#define TYPE_CORE3_MACHINE MACHINE_TYPE_NAME("core3") +OBJECT_DECLARE_TYPE(CORE3MachineState, CORE3MachineClass, CORE3_MACHINE) + +struct CORE4MachineClass { + MachineClass parent; +}; + +struct CORE4MachineState { + MachineState parent; + FWCfgState *fw_cfg; + DeviceState *acpi_dev; + DeviceState *gpio_dev; + PCIBus *bus; + char *oem_id; + char *oem_table_id; + const MemMapEntry *memmap; + const int *irqmap; + int fdt_size; +}; + +#define TYPE_CORE4_MACHINE MACHINE_TYPE_NAME("core4") +OBJECT_DECLARE_TYPE(CORE4MachineState, CORE4MachineClass, CORE4_MACHINE); + +typedef struct BoardState { + PCIHostState parent_obj; + MemoryRegion io_mcu; + MemoryRegion io_spbu; + MemoryRegion io_intpu; + MemoryRegion msi_ep; + MemoryRegion mem_ep; + MemoryRegion mem_ep64; + MemoryRegion conf_piu0; + MemoryRegion io_piu0; + MemoryRegion io_ep; + MemoryRegion io_rtc; + qemu_irq serial_irq; + uint32_t ofw_addr; +} BoardState; + +typedef struct TimerState { + void *opaque; + int order; +} TimerState; + +enum { + VIRT_BOOT_FLAG, + VIRT_PCIE_MMIO, + VIRT_MSI, + VIRT_SPBU, + VIRT_SUNWAY_GED, + VIRT_INTPU, + VIRT_RTC, + VIRT_FW_CFG, + VIRT_PCIE_IO_BASE, + VIRT_PCIE_PIO, + VIRT_UART, + VIRT_PCIE_CFG, + VIRT_HIGH_PCIE_MMIO, + VIRT_MCU, + VIRT_GPIO, +}; + +typedef struct boot_params { + unsigned long initrd_start; /* logical address of initrd */ + unsigned long initrd_size; /* size 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(MachineState *machine); +void core4_board_init(MachineState *machine); +void sw64_acpi_setup(SW64MachineState *vms); +#endif diff --git a/include/hw/sw64/sunway.h b/include/hw/sw64/sunway.h new file mode 100644 index 0000000000000000000000000000000000000000..47e55dbb8edb6000b1b32937994418a44e2aca54 --- /dev/null +++ b/include/hw/sw64/sunway.h @@ -0,0 +1,50 @@ +#ifndef SW64_SUNWAY_H +#define SW64_SUNWAY_H + +#include "exec/cpu-defs.h" +#include "hw/pci/pci.h" +#include "hw/loader.h" +#include "hw/sw64/core.h" + +extern const MemoryRegionOps rtc_ops; +extern const MemoryRegionOps sw64_pci_ignore_ops; +extern const MemoryRegionOps sw64_pci_config_ops; +extern const MemoryRegionOps msi_ops; +void sw64_clear_kernel_print(void); +void sw64_init_rtc_base_info(void); + +uint64_t cpu_sw64_virt_to_phys(void *opaque, uint64_t addr); +CpuInstanceProperties sw64_cpu_index_to_props(MachineState *ms, + unsigned cpu_index); +int64_t sw64_get_default_cpu_node_id(const MachineState *ms, + int idx); +const CPUArchIdList *sw64_possible_cpu_arch_ids(MachineState *ms); +void sw64_cpu_reset(void *opaque); +void sw64_board_reset(MachineState *state); + +void sw64_set_clocksource(void); +void sw64_set_ram_size(ram_addr_t ram_size); +void sw64_clear_uefi_bios(void); +void sw64_clear_smp_rcb(void); +void sw64_load_hmcode(const char *hmcode_filename, uint64_t *hmcode_entry); +void sw64_find_and_load_bios(const char *bios_name); +void sw64_load_kernel(const char *kernel_filename, uint64_t *kernel_entry, + const char *kernel_cmdline); +void sw64_load_initrd(const char *initrd_filename, + BOOT_PARAMS *sunway_boot_params); +int sw64_load_dtb(MachineState *ms, BOOT_PARAMS *sunway_boot_params); +void sw64_board_alarm_timer(void *opaque); +void sw64_create_alarm_timer(MachineState *ms, BoardState *bs); +uint64_t convert_bit(int n); +FWCfgState *sw64_create_fw_cfg(hwaddr addr, hwaddr size); +void sw64_virt_build_smbios(FWCfgState *fw_cfg); +void sw64_board_set_irq(void *opaque, int irq, int level); +int sw64_board_map_irq(PCIDevice *d, int irq_num); +void serial_set_irq(void *opaque, int irq, int level); +void sw64_new_cpu(const char *name, int64_t arch_id, Error **errp); +void sw64_create_pcie(BoardState *bs, PCIBus *b, PCIHostState *phb); +PCIINTxRoute sw64_route_intx_pin_to_irq(void *opaque, int pin); +MemTxResult msi_write(void *opaque, hwaddr addr, uint64_t value, + unsigned size, MemTxAttrs attrs); +void rtc_get_time(Object *obj, struct tm *current_tm, Error **errp); +#endif /* SW64_SUNWAY_H */ diff --git a/include/hw/sw64/sw64_iommu.h b/include/hw/sw64/sw64_iommu.h new file mode 100644 index 0000000000000000000000000000000000000000..eb59ff107adf886ad7e04ba064840e99bc16941b --- /dev/null +++ b/include/hw/sw64/sw64_iommu.h @@ -0,0 +1,103 @@ +/* + * 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); +#endif diff --git a/include/qemu/atomic.h b/include/qemu/atomic.h index 7855443cab974a4dcc2bbfc9af25243ddab9fb39..f126e195b66c2cafd592bcbdaff4fbb8fcdaa055 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 88ef11468944bb4a6ee924f271c8b8f41363c402..18f939aa2b56ce65c7a6dcbf1063e0d8f91fe9aa 100644 --- a/include/qemu/timer.h +++ b/include/qemu/timer.h @@ -979,6 +979,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 62d1a4b92dccf59f592fd80076e310e4a7a03638..f648bc6188c4919e78332adf3d5a57a6885a33a2 100644 --- a/include/sysemu/arch_init.h +++ b/include/sysemu/arch_init.h @@ -25,6 +25,7 @@ enum { QEMU_ARCH_AVR = (1 << 21), QEMU_ARCH_HEXAGON = (1 << 22), QEMU_ARCH_LOONGARCH64 = (1 << 23), + QEMU_ARCH_SW64 = (1 << 24), }; 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 0000000000000000000000000000000000000000..9310ad49bbb730a4b9539817333b484fcabf41d5 --- /dev/null +++ b/linux-headers/asm-sw64/kvm.h @@ -0,0 +1,88 @@ +#ifndef __LINUX_KVM_SW64_H +#define __LINUX_KVM_SW64_H + +#include + +#define __KVM_HAVE_GUEST_DEBUG + +/* + * for KVM_GET_REGS and KVM_SET_REGS + */ +struct user_pt_regs { + unsigned long r[31]; + unsigned long pc; + unsigned long pstate; +}; + +/* 256 bits aligned for simd */ +struct fpreg { + unsigned long v[4] __attribute__((aligned(32))); +}; + +struct user_fpsimd_state { + struct fpreg fp[31]; + unsigned long fpcr; + unsigned long __reserved[3]; +}; + +struct kvm_regs { + union { + struct { + unsigned long r[27]; + 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; + unsigned long reserved[6]; + } c3_regs; + struct { + union { + struct user_pt_regs reg; + struct { + unsigned long r[31]; + unsigned long pc; + unsigned long ps; + } + }; + struct user_fpsimd_state fpstate; + } c4_regs; + }; +}; + +/* + * for KVM_GET_FPU and KVM_SET_FPU + */ +struct kvm_fpu { +}; + +/* + * KVM SW_64 specific structures and definitions + */ +struct kvm_debug_exit_arch { + unsigned long epc; +}; + +/* 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 0000000000000000000000000000000000000000..affe297e734c41df6d57eddc1539e104d9d7d73a --- /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/elfload.c b/linux-user/elfload.c index 9fb632780af2397c677342077c2f6adfe46d2289..5b190e56d236b4286f38eb5cf1e49b00e43ee0fe 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -1552,6 +1552,24 @@ static inline void init_thread(struct target_pt_regs *regs, #endif /* TARGET_HPPA */ +#ifdef TARGET_SW64 + +#define ELF_CLASS ELFCLASS64 +#define ELF_ARCH EM_SW64 + +#define ELF_START_MMAP (0x30000000000ULL) + +/* TODO: todo after */ +static inline void init_thread(struct target_pt_regs *regs, + struct image_info *infop) +{ + regs->pc = infop->entry; + /* regs->ps = 8; */ + regs->usp = infop->start_stack; +} + +#endif /* TARGET_SW64 */ + #ifdef TARGET_XTENSA #define ELF_START_MMAP 0x20000000 diff --git a/linux-user/host/sw64/host-signal.h b/linux-user/host/sw64/host-signal.h new file mode 100644 index 0000000000000000000000000000000000000000..6aa981df032cecdb41485c354a823bdd22fad7b4 --- /dev/null +++ b/linux-user/host/sw64/host-signal.h @@ -0,0 +1,46 @@ +/* + * host-signal.h: signal info dependent on the host architecture + * + * Copyright (c) 2022 wxiat + * + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. + * See the COPYING file in the top-level directory. + */ + +#ifndef SW64_HOST_SIGNAL_H +#define SW64_HOST_SIGNAL_H + +static inline uintptr_t host_signal_pc(ucontext_t *uc) +{ + return uc->uc_mcontext.sc_pc; +} + +static inline void host_signal_set_pc(ucontext_t *uc, uintptr_t pc) +{ + uc->uc_mcontext.sc_pc = pc; +} + +static inline bool host_signal_write(siginfo_t *info, ucontext_t *uc) +{ + uint32_t *pc = (uint32_t *)host_signal_pc(uc); + uint32_t insn = *pc; + + /* XXX: need kernel patch to get write flag faster */ + switch (insn >> 26) { + case 0x0d: /* stw */ + case 0x0e: /* stb */ + case 0x0f: /* stq_u */ + case 0x24: /* stf */ + case 0x25: /* stg */ + case 0x26: /* sts */ + case 0x27: /* stt */ + case 0x2c: /* stl */ + case 0x2d: /* stq */ + case 0x2e: /* stl_c */ + case 0x2f: /* stq_c */ + return true; + } + return false; +} + +#endif diff --git a/linux-user/host/sw64/hostdep.h b/linux-user/host/sw64/hostdep.h new file mode 100755 index 0000000000000000000000000000000000000000..6493919f2669078af5a1bc4508ff2e9c731e9a32 --- /dev/null +++ b/linux-user/host/sw64/hostdep.h @@ -0,0 +1,14 @@ +/* + * hostdep.h : things which are dependent on the host architecture + * + * * Written by Wang Yuanheng + * + * Copyright (C) 2022 wxiat + * + * 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 SW_64_HOSTDEP_H +#define SW_64_HOSTDEP_H +#endif diff --git a/linux-user/meson.build b/linux-user/meson.build index 195f9e83ac0d094a8eb2d57a74a1a36f34fcef62..8b8edefa6ea30cba64117713db682e70339c4e0f 100644 --- a/linux-user/meson.build +++ b/linux-user/meson.build @@ -37,6 +37,7 @@ subdir('ppc') subdir('s390x') subdir('sh4') subdir('sparc') +subdir('sw64') subdir('x86_64') subdir('xtensa') subdir('loongarch64') diff --git a/linux-user/sw64/cpu_loop.c b/linux-user/sw64/cpu_loop.c new file mode 100644 index 0000000000000000000000000000000000000000..389b753401ca1ccaaf53f8ba793095bb0e6b4bc0 --- /dev/null +++ b/linux-user/sw64/cpu_loop.c @@ -0,0 +1,111 @@ +/* + * 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-common.h" +#include "qemu.h" +#include "user-internals.h" +#include "cpu_loop-common.h" +#include "signal-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/meson.build b/linux-user/sw64/meson.build new file mode 100644 index 0000000000000000000000000000000000000000..181fe002f2cf9967c5798f21d0bc3aac303dd72a --- /dev/null +++ b/linux-user/sw64/meson.build @@ -0,0 +1,5 @@ +syscall_nr_generators += { + 'sw64': generator(sh, + arguments: [ meson.current_source_dir() / 'syscallhdr.sh', '@INPUT@', '@OUTPUT@', '@EXTRA_ARGS@' ], + output: '@BASENAME@_nr.h') +} diff --git a/linux-user/sw64/signal.c b/linux-user/sw64/signal.c new file mode 100644 index 0000000000000000000000000000000000000000..1fbaa3839d6289e2764b1596f584541188d41e77 --- /dev/null +++ b/linux-user/sw64/signal.c @@ -0,0 +1,288 @@ +/* + * 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 "user-internals.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->ka_restorer) { + r26 = ka->ka_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->ka_restorer) { + r26 = ka->ka_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); + target_restore_altstack(&frame->uc.tuc_stack, env); + + 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; +} + +void setup_sigtramp(abi_ulong sigtramp_page) +{ + uint32_t *tramp = lock_user(VERIFY_WRITE, sigtramp_page, 6 * 4, 0); + assert(tramp != NULL); + + default_sigreturn = sigtramp_page; + __put_user(INSN_MOV_R30_R16, &tramp[0]); + __put_user(INSN_LDI_R0 + TARGET_NR_sigreturn, &tramp[1]); + __put_user(INSN_CALLSYS, &tramp[2]); + + default_rt_sigreturn = sigtramp_page + 3 * 4; + __put_user(INSN_MOV_R30_R16, &tramp[3]); + __put_user(INSN_LDI_R0 + TARGET_NR_rt_sigreturn, &tramp[4]); + __put_user(INSN_CALLSYS, &tramp[5]); + + unlock_user(tramp, sigtramp_page, 6 * 4); +} diff --git a/linux-user/sw64/sockbits.h b/linux-user/sw64/sockbits.h new file mode 100644 index 0000000000000000000000000000000000000000..0e4c8f012d781261da71333ae360abe22ca8083b --- /dev/null +++ b/linux-user/sw64/sockbits.h @@ -0,0 +1 @@ +#include "../generic/sockbits.h" diff --git a/linux-user/sw64/syscall.tbl b/linux-user/sw64/syscall.tbl new file mode 100644 index 0000000000000000000000000000000000000000..d007c7bb0761fa471f17575d13eb48cfe53bcef8 --- /dev/null +++ b/linux-user/sw64/syscall.tbl @@ -0,0 +1,488 @@ +# SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note +# +# system call numbers and entry vectors for sw64 +# +# The format is: +# +# +# The is always "common" for this file +# +0 common osf_syscall sw64_syscall_zero +1 common exit sys_exit +2 common fork sw64_fork +3 common read sys_read +4 common write sys_write +5 common osf_old_open sys_ni_syscall +6 common close sys_close +7 common osf_wait4 sys_osf_wait4 +8 common osf_old_creat sys_ni_syscall +9 common link sys_link +10 common unlink sys_unlink +11 common osf_execve sys_ni_syscall +12 common chdir sys_chdir +13 common fchdir sys_fchdir +14 common mknod sys_mknod +15 common chmod sys_chmod +16 common chown sys_chown +17 common brk sys_osf_brk +18 common osf_getfsstat sys_ni_syscall +19 common lseek sys_lseek +20 common getxpid sys_getxpid +21 common osf_mount sys_osf_mount +22 common umount2 sys_umount +23 common setuid sys_setuid +24 common getxuid sys_getxuid +25 common exec_with_loader sys_ni_syscall +26 common ptrace sys_ptrace +27 common osf_nrecvmsg sys_ni_syscall +28 common osf_nsendmsg sys_ni_syscall +29 common osf_nrecvfrom sys_ni_syscall +30 common osf_naccept sys_ni_syscall +31 common osf_ngetpeername sys_ni_syscall +32 common osf_ngetsockname sys_ni_syscall +33 common access sys_access +34 common osf_chflags sys_ni_syscall +35 common osf_fchflags sys_ni_syscall +36 common sync sys_sync +37 common kill sys_kill +38 common osf_old_stat sys_ni_syscall +39 common setpgid sys_setpgid +40 common osf_old_lstat sys_ni_syscall +41 common dup sys_dup +42 common pipe sys_sw64_pipe +43 common osf_set_program_attributes sys_osf_set_program_attributes +44 common osf_profil sys_ni_syscall +45 common open sys_open +46 common osf_old_sigaction sys_ni_syscall +47 common getxgid sys_getxgid +48 common osf_sigprocmask sys_osf_sigprocmask +49 common osf_getlogin sys_ni_syscall +50 common osf_setlogin sys_ni_syscall +51 common acct sys_acct +52 common sigpending sys_sigpending +54 common ioctl sys_ioctl +55 common osf_reboot sys_ni_syscall +56 common osf_revoke sys_ni_syscall +57 common symlink sys_symlink +58 common readlink sys_readlink +59 common execve sys_execve +60 common umask sys_umask +61 common chroot sys_chroot +62 common osf_old_fstat sys_ni_syscall +63 common getpgrp sys_getpgrp +64 common getpagesize sys_getpagesize +65 common osf_mremap sys_ni_syscall +66 common vfork sw64_vfork +67 common stat sys_newstat +68 common lstat sys_newlstat +69 common osf_sbrk sys_ni_syscall +70 common osf_sstk sys_ni_syscall +71 common mmap sys_osf_mmap +72 common osf_old_vadvise sys_ni_syscall +73 common munmap sys_munmap +74 common mprotect sys_mprotect +75 common madvise sys_madvise +76 common vhangup sys_vhangup +77 common osf_kmodcall sys_ni_syscall +78 common osf_mincore sys_ni_syscall +79 common getgroups sys_getgroups +80 common setgroups sys_setgroups +81 common osf_old_getpgrp sys_ni_syscall +82 common setpgrp sys_setpgid +83 common osf_setitimer compat_sys_setitimer +84 common osf_old_wait sys_ni_syscall +85 common osf_table sys_ni_syscall +86 common osf_getitimer compat_sys_getitimer +87 common gethostname sys_gethostname +88 common sethostname sys_sethostname +89 common getdtablesize sys_getdtablesize +90 common dup2 sys_dup2 +91 common fstat sys_newfstat +92 common fcntl sys_fcntl +93 common osf_select sys_osf_select +94 common poll sys_poll +95 common fsync sys_fsync +96 common setpriority sys_setpriority +97 common socket sys_socket +98 common connect sys_connect +99 common accept sys_accept +100 common getpriority sys_osf_getpriority +101 common send sys_send +102 common recv sys_recv +103 common sigreturn sys_sigreturn +104 common bind sys_bind +105 common setsockopt sys_setsockopt +106 common listen sys_listen +107 common osf_plock sys_ni_syscall +108 common osf_old_sigvec sys_ni_syscall +109 common osf_old_sigblock sys_ni_syscall +110 common osf_old_sigsetmask sys_ni_syscall +111 common sigsuspend sys_sigsuspend +112 common osf_sigstack sys_osf_sigstack +113 common recvmsg sys_recvmsg +114 common sendmsg sys_sendmsg +115 common osf_old_vtrace sys_ni_syscall +116 common osf_gettimeofday sys_osf_gettimeofday +117 common osf_getrusage sys_osf_getrusage +118 common getsockopt sys_getsockopt +120 common readv sys_osf_readv +121 common writev sys_osf_writev +122 common osf_settimeofday sys_osf_settimeofday +123 common fchown sys_fchown +124 common fchmod sys_fchmod +125 common recvfrom sys_recvfrom +126 common setreuid sys_setreuid +127 common setregid sys_setregid +128 common rename sys_rename +129 common truncate sys_truncate +130 common ftruncate sys_ftruncate +131 common flock sys_flock +132 common setgid sys_setgid +133 common sendto sys_sendto +134 common shutdown sys_shutdown +135 common socketpair sys_socketpair +136 common mkdir sys_mkdir +137 common rmdir sys_rmdir +138 common osf_utimes sys_osf_utimes +139 common osf_old_sigreturn sys_ni_syscall +140 common osf_adjtime sys_ni_syscall +141 common getpeername sys_getpeername +142 common osf_gethostid sys_ni_syscall +143 common osf_sethostid sys_ni_syscall +144 common getrlimit sys_getrlimit +145 common setrlimit sys_setrlimit +146 common osf_old_killpg sys_ni_syscall +147 common setsid sys_setsid +148 common quotactl sys_quotactl +149 common osf_oldquota sys_ni_syscall +150 common getsockname sys_getsockname +153 common osf_pid_block sys_ni_syscall +154 common osf_pid_unblock sys_ni_syscall +156 common sigaction sys_osf_sigaction +157 common osf_sigwaitprim sys_ni_syscall +158 common osf_nfssvc sys_ni_syscall +159 common osf_getdirentries sys_osf_getdirentries +160 common osf_statfs sys_osf_statfs +161 common osf_fstatfs sys_osf_fstatfs +163 common osf_asynch_daemon sys_ni_syscall +164 common osf_getfh sys_ni_syscall +165 common osf_getdomainname sys_osf_getdomainname +166 common setdomainname sys_setdomainname +169 common osf_exportfs sys_ni_syscall +181 common osf_alt_plock sys_ni_syscall +184 common osf_getmnt sys_ni_syscall +187 common osf_alt_sigpending sys_ni_syscall +188 common osf_alt_setsid sys_ni_syscall +199 common osf_swapon sys_swapon +200 common msgctl sys_old_msgctl +201 common msgget sys_msgget +202 common msgrcv sys_msgrcv +203 common msgsnd sys_msgsnd +204 common semctl sys_old_semctl +205 common semget sys_semget +206 common semop sys_semop +207 common osf_utsname sys_osf_utsname +208 common lchown sys_lchown +209 common shmat sys_shmat +210 common shmctl sys_old_shmctl +211 common shmdt sys_shmdt +212 common shmget sys_shmget +213 common osf_mvalid sys_ni_syscall +214 common osf_getaddressconf sys_ni_syscall +215 common osf_msleep sys_ni_syscall +216 common osf_mwakeup sys_ni_syscall +217 common msync sys_msync +218 common osf_signal sys_ni_syscall +219 common osf_utc_gettime sys_ni_syscall +220 common osf_utc_adjtime sys_ni_syscall +222 common osf_security sys_ni_syscall +223 common osf_kloadcall sys_ni_syscall +224 common osf_stat sys_osf_stat +225 common osf_lstat sys_osf_lstat +226 common osf_fstat sys_osf_fstat +227 common osf_statfs64 sys_osf_statfs64 +228 common osf_fstatfs64 sys_osf_fstatfs64 +233 common getpgid sys_getpgid +234 common getsid sys_getsid +235 common sigaltstack sys_sigaltstack +236 common osf_waitid sys_ni_syscall +237 common osf_priocntlset sys_ni_syscall +238 common osf_sigsendset sys_ni_syscall +239 common osf_set_speculative sys_ni_syscall +240 common osf_msfs_syscall sys_ni_syscall +241 common osf_sysinfo sys_osf_sysinfo +242 common osf_uadmin sys_ni_syscall +243 common osf_fuser sys_ni_syscall +244 common osf_proplist_syscall sys_osf_proplist_syscall +245 common osf_ntp_adjtime sys_ni_syscall +246 common osf_ntp_gettime sys_ni_syscall +247 common osf_pathconf sys_ni_syscall +248 common osf_fpathconf sys_ni_syscall +250 common osf_uswitch sys_ni_syscall +251 common osf_usleep_thread sys_osf_usleep_thread +252 common osf_audcntl sys_ni_syscall +253 common osf_audgen sys_ni_syscall +254 common sysfs sys_sysfs +255 common osf_subsys_info sys_ni_syscall +256 common osf_getsysinfo sys_osf_getsysinfo +257 common osf_setsysinfo sys_osf_setsysinfo +258 common osf_afs_syscall sys_ni_syscall +259 common osf_swapctl sys_ni_syscall +260 common osf_memcntl sys_ni_syscall +261 common osf_fdatasync sys_ni_syscall +300 common bdflush sys_bdflush +301 common sethae sys_sethae +302 common mount sys_mount +303 common old_adjtimex sys_old_adjtimex +304 common swapoff sys_swapoff +305 common getdents sys_getdents +306 common create_module sys_ni_syscall +307 common init_module sys_init_module +308 common delete_module sys_delete_module +309 common get_kernel_syms sys_ni_syscall +310 common syslog sys_syslog +311 common reboot sys_reboot +312 common clone sw64_clone +313 common uselib sys_uselib +314 common mlock sys_mlock +315 common munlock sys_munlock +316 common mlockall sys_mlockall +317 common munlockall sys_munlockall +318 common sysinfo sys_sysinfo +319 common _sysctl sys_ni_syscall +# 320 was sys_idle +321 common oldumount sys_oldumount +322 common swapon sys_swapon +323 common times sys_times +324 common personality sys_personality +325 common setfsuid sys_setfsuid +326 common setfsgid sys_setfsgid +327 common ustat sys_ustat +328 common statfs sys_statfs +329 common fstatfs sys_fstatfs +330 common sched_setparam sys_sched_setparam +331 common sched_getparam sys_sched_getparam +332 common sched_setscheduler sys_sched_setscheduler +333 common sched_getscheduler sys_sched_getscheduler +334 common sched_yield sys_sched_yield +335 common sched_get_priority_max sys_sched_get_priority_max +336 common sched_get_priority_min sys_sched_get_priority_min +337 common sched_rr_get_interval sys_sched_rr_get_interval +338 common afs_syscall sys_ni_syscall +339 common uname sys_newuname +340 common nanosleep sys_nanosleep +341 common mremap sys_mremap +342 common nfsservctl sys_ni_syscall +343 common setresuid sys_setresuid +344 common getresuid sys_getresuid +345 common pciconfig_read sys_pciconfig_read +346 common pciconfig_write sys_pciconfig_write +347 common query_module sys_ni_syscall +348 common prctl sys_prctl +349 common pread64 sys_pread64 +350 common pwrite64 sys_pwrite64 +351 common rt_sigreturn sys_rt_sigreturn +352 common rt_sigaction sys_rt_sigaction +353 common rt_sigprocmask sys_rt_sigprocmask +354 common rt_sigpending sys_rt_sigpending +355 common rt_sigtimedwait sys_rt_sigtimedwait +356 common rt_sigqueueinfo sys_rt_sigqueueinfo +357 common rt_sigsuspend sys_rt_sigsuspend +358 common select sys_select +359 common gettimeofday sys_gettimeofday +360 common settimeofday sys_settimeofday +361 common getitimer sys_getitimer +362 common setitimer sys_setitimer +363 common utimes sys_utimes +364 common getrusage sys_getrusage +365 common wait4 sys_wait4 +366 common adjtimex sys_adjtimex +367 common getcwd sys_getcwd +368 common capget sys_capget +369 common capset sys_capset +370 common sendfile sys_sendfile64 +371 common setresgid sys_setresgid +372 common getresgid sys_getresgid +373 common dipc sys_ni_syscall +374 common pivot_root sys_pivot_root +375 common mincore sys_mincore +376 common pciconfig_iobase sys_pciconfig_iobase +377 common getdents64 sys_getdents64 +378 common gettid sys_gettid +379 common readahead sys_readahead +# 380 is unused +381 common tkill sys_tkill +382 common setxattr sys_setxattr +383 common lsetxattr sys_lsetxattr +384 common fsetxattr sys_fsetxattr +385 common getxattr sys_getxattr +386 common lgetxattr sys_lgetxattr +387 common fgetxattr sys_fgetxattr +388 common listxattr sys_listxattr +389 common llistxattr sys_llistxattr +390 common flistxattr sys_flistxattr +391 common removexattr sys_removexattr +392 common lremovexattr sys_lremovexattr +393 common fremovexattr sys_fremovexattr +394 common futex sys_futex +395 common sched_setaffinity sys_sched_setaffinity +396 common sched_getaffinity sys_sched_getaffinity +397 common tuxcall sys_ni_syscall +398 common io_setup sys_io_setup +399 common io_destroy sys_io_destroy +400 common io_getevents sys_io_getevents +401 common io_submit sys_io_submit +402 common io_cancel sys_io_cancel +405 common exit_group sys_exit_group +406 common lookup_dcookie sys_lookup_dcookie +407 common epoll_create sys_epoll_create +408 common epoll_ctl sys_epoll_ctl +409 common epoll_wait sys_epoll_wait +410 common remap_file_pages sys_remap_file_pages +411 common set_tid_address sys_set_tid_address +412 common restart_syscall sys_restart_syscall +413 common fadvise64 sys_fadvise64 +414 common timer_create sys_timer_create +415 common timer_settime sys_timer_settime +416 common timer_gettime sys_timer_gettime +417 common timer_getoverrun sys_timer_getoverrun +418 common timer_delete sys_timer_delete +419 common clock_settime sys_clock_settime +420 common clock_gettime sys_clock_gettime +421 common clock_getres sys_clock_getres +422 common clock_nanosleep sys_clock_nanosleep +423 common semtimedop sys_semtimedop +424 common tgkill sys_tgkill +425 common stat64 sys_stat64 +426 common lstat64 sys_lstat64 +427 common fstat64 sys_fstat64 +428 common vserver sys_ni_syscall +429 common mbind sys_ni_syscall +430 common get_mempolicy sys_ni_syscall +431 common set_mempolicy sys_ni_syscall +432 common mq_open sys_mq_open +433 common mq_unlink sys_mq_unlink +434 common mq_timedsend sys_mq_timedsend +435 common mq_timedreceive sys_mq_timedreceive +436 common mq_notify sys_mq_notify +437 common mq_getsetattr sys_mq_getsetattr +438 common waitid sys_waitid +439 common add_key sys_add_key +440 common request_key sys_request_key +441 common keyctl sys_keyctl +442 common ioprio_set sys_ioprio_set +443 common ioprio_get sys_ioprio_get +444 common inotify_init sys_inotify_init +445 common inotify_add_watch sys_inotify_add_watch +446 common inotify_rm_watch sys_inotify_rm_watch +447 common fdatasync sys_fdatasync +448 common kexec_load sys_kexec_load +449 common migrate_pages sys_migrate_pages +450 common openat sys_openat +451 common mkdirat sys_mkdirat +452 common mknodat sys_mknodat +453 common fchownat sys_fchownat +454 common futimesat sys_futimesat +455 common fstatat64 sys_fstatat64 +456 common unlinkat sys_unlinkat +457 common renameat sys_renameat +458 common linkat sys_linkat +459 common symlinkat sys_symlinkat +460 common readlinkat sys_readlinkat +461 common fchmodat sys_fchmodat +462 common faccessat sys_faccessat +463 common pselect6 sys_pselect6 +464 common ppoll sys_ppoll +465 common unshare sys_unshare +466 common set_robust_list sys_set_robust_list +467 common get_robust_list sys_get_robust_list +468 common splice sys_splice +469 common sync_file_range sys_sync_file_range +470 common tee sys_tee +471 common vmsplice sys_vmsplice +472 common move_pages sys_move_pages +473 common getcpu sys_getcpu +474 common epoll_pwait sys_epoll_pwait +475 common utimensat sys_utimensat +476 common signalfd sys_signalfd +477 common timerfd sys_ni_syscall +478 common eventfd sys_eventfd +479 common recvmmsg sys_recvmmsg +480 common fallocate sys_fallocate +481 common timerfd_create sys_timerfd_create +482 common timerfd_settime sys_timerfd_settime +483 common timerfd_gettime sys_timerfd_gettime +484 common signalfd4 sys_signalfd4 +485 common eventfd2 sys_eventfd2 +486 common epoll_create1 sys_epoll_create1 +487 common dup3 sys_dup3 +488 common pipe2 sys_pipe2 +489 common inotify_init1 sys_inotify_init1 +490 common preadv sys_preadv +491 common pwritev sys_pwritev +492 common rt_tgsigqueueinfo sys_rt_tgsigqueueinfo +493 common perf_event_open sys_perf_event_open +494 common fanotify_init sys_fanotify_init +495 common fanotify_mark sys_fanotify_mark +496 common prlimit64 sys_prlimit64 +497 common name_to_handle_at sys_name_to_handle_at +498 common open_by_handle_at sys_open_by_handle_at +499 common clock_adjtime sys_clock_adjtime +500 common syncfs sys_syncfs +501 common setns sys_setns +502 common accept4 sys_accept4 +503 common sendmmsg sys_sendmmsg +504 common process_vm_readv sys_process_vm_readv +505 common process_vm_writev sys_process_vm_writev +506 common kcmp sys_kcmp +507 common finit_module sys_finit_module +508 common sched_setattr sys_sched_setattr +509 common sched_getattr sys_sched_getattr +510 common renameat2 sys_renameat2 +511 common getrandom sys_getrandom +512 common memfd_create sys_memfd_create +513 common execveat sys_execveat +514 common seccomp sys_seccomp +515 common bpf sys_bpf +516 common userfaultfd sys_userfaultfd +517 common membarrier sys_membarrier +518 common mlock2 sys_mlock2 +519 common copy_file_range sys_copy_file_range +520 common preadv2 sys_preadv2 +521 common pwritev2 sys_pwritev2 +522 common statx sys_statx +523 common io_pgetevents sys_io_pgetevents +524 common pkey_mprotect sys_pkey_mprotect +525 common pkey_alloc sys_pkey_alloc +526 common pkey_free sys_pkey_free +527 common rseq sys_rseq +528 common statfs64 sys_statfs64 +529 common fstatfs64 sys_fstatfs64 +530 common getegid sys_getegid +531 common geteuid sys_geteuid +532 common getppid sys_getppid +# all other architectures have common numbers for new syscall, sw64 +# is the exception. +534 common pidfd_send_signal sys_pidfd_send_signal +535 common io_uring_setup sys_io_uring_setup +536 common io_uring_enter sys_io_uring_enter +537 common io_uring_register sys_io_uring_register +538 common open_tree sys_open_tree +539 common move_mount sys_move_mount +540 common fsopen sys_fsopen +541 common fsconfig sys_fsconfig +542 common fsmount sys_fsmount +543 common fspick sys_fspick +544 common pidfd_open sys_pidfd_open +# 545 reserved for clone3 +546 common close_range sys_close_range +547 common openat2 sys_openat2 +548 common pidfd_getfd sys_pidfd_getfd +549 common faccessat2 sys_faccessat2 +550 common process_madvise sys_process_madvise +551 common epoll_pwait2 sys_epoll_pwait2 +552 common mount_setattr sys_mount_setattr +# 553 reserved for quotactl_path +554 common landlock_create_ruleset sys_landlock_create_ruleset +555 common landlock_add_rule sys_landlock_add_rule +556 common landlock_restrict_self sys_landlock_restrict_self diff --git a/linux-user/sw64/syscall_nr.h b/linux-user/sw64/syscall_nr.h new file mode 100644 index 0000000000000000000000000000000000000000..91737af322e64376faaadd1c5ba9a5f0d9de2cfc --- /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/syscallhdr.sh b/linux-user/sw64/syscallhdr.sh new file mode 100644 index 0000000000000000000000000000000000000000..46c166d8ae096898b70371ed610599e80ee16af4 --- /dev/null +++ b/linux-user/sw64/syscallhdr.sh @@ -0,0 +1,32 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0 + +in="$1" +out="$2" +my_abis=`echo "($3)" | tr ',' '|'` +prefix="$4" +offset="$5" + +fileguard=LINUX_USER_SW64_`basename "$out" | sed \ + -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/' \ + -e 's/[^A-Z0-9_]/_/g' -e 's/__/_/g'` +grep -E "^[0-9A-Fa-fXx]+[[:space:]]+${my_abis}" "$in" | sort -n | ( + printf "#ifndef %s\n" "${fileguard}" + printf "#define %s\n" "${fileguard}" + printf "\n" + + nxt=0 + while read nr abi name entry ; do + if [ -z "$offset" ]; then + printf "#define TARGET_NR_%s%s\t%s\n" \ + "${prefix}" "${name}" "${nr}" + else + printf "#define TARGET_NR_%s%s\t(%s + %s)\n" \ + "${prefix}" "${name}" "${offset}" "${nr}" + fi + nxt=$((nr+1)) + done + + printf "\n" + printf "#endif /* %s */" "${fileguard}" +) > "$out" diff --git a/linux-user/sw64/target_cpu.h b/linux-user/sw64/target_cpu.h new file mode 100644 index 0000000000000000000000000000000000000000..4553ea337de54b5ec36b4e13aa76cd423b9eae59 --- /dev/null +++ b/linux-user/sw64/target_cpu.h @@ -0,0 +1,52 @@ +/* + * 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_child(CPUSW64State *env, target_ulong newsp, + unsigned flags) +{ + if (newsp) { + env->ir[IDX_SP] = newsp; + } + env->ir[IDX_V0] = 0; + env->ir[IDX_A3] = 0; + env->ir[IDX_A4] = 1; /* OSF/1 secondary return: child */ +} + +static inline void cpu_clone_regs_parent(CPUSW64State *env, unsigned flags) +{ + /* + * OSF/1 secondary return: parent + * Note that the kernel does not do this if SETTLS, because the + * settls argument register is still live after copy_thread. + */ + if (!(flags & CLONE_SETTLS)) { + env->ir[IDX_A4] = 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 0000000000000000000000000000000000000000..be48b6dee3e27d5f518263a0924ced93bd3b0115 --- /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_errno_defs.h b/linux-user/sw64/target_errno_defs.h new file mode 100644 index 0000000000000000000000000000000000000000..fd637f5bc965414b5153c2eb8bb5369a1b652f1a --- /dev/null +++ b/linux-user/sw64/target_errno_defs.h @@ -0,0 +1,204 @@ +#ifndef sw64_TARGET_ERRNO_DEFS_H +#define sw64_TARGET_ERRNO_DEFS_H + +#include "../generic/target_errno_defs.h" + +/* + * Generic target errno overridden with definitions taken + * from asm-sw64/errno.h + */ +#undef TARGET_EWOULDBLOCK +#define TARGET_EWOULDBLOCK TARGET_EAGAIN +#undef TARGET_EDEADLK +#define TARGET_EDEADLK 11 +#undef TARGET_EAGAIN +#define TARGET_EAGAIN 35 +#undef TARGET_EINPROGRESS +#define TARGET_EINPROGRESS 36 +#undef TARGET_EALREADY +#define TARGET_EALREADY 37 +#undef TARGET_ENOTSOCK +#define TARGET_ENOTSOCK 38 +#undef TARGET_EDESTADDRREQ +#define TARGET_EDESTADDRREQ 39 +#undef TARGET_EMSGSIZE +#define TARGET_EMSGSIZE 40 +#undef TARGET_EPROTOTYPE +#define TARGET_EPROTOTYPE 41 +#undef TARGET_ENOPROTOOPT +#define TARGET_ENOPROTOOPT 42 +#undef TARGET_EPROTONOSUPPORT +#define TARGET_EPROTONOSUPPORT 43 +#undef TARGET_ESOCKTNOSUPPORT +#define TARGET_ESOCKTNOSUPPORT 44 +#undef TARGET_EOPNOTSUPP +#define TARGET_EOPNOTSUPP 45 +#undef TARGET_EPFNOSUPPORT +#define TARGET_EPFNOSUPPORT 46 +#undef TARGET_EAFNOSUPPORT +#define TARGET_EAFNOSUPPORT 47 +#undef TARGET_EADDRINUSE +#define TARGET_EADDRINUSE 48 +#undef TARGET_EADDRNOTAVAIL +#define TARGET_EADDRNOTAVAIL 49 +#undef TARGET_ENETDOWN +#define TARGET_ENETDOWN 50 +#undef TARGET_ENETUNREACH +#define TARGET_ENETUNREACH 51 +#undef TARGET_ENETRESET +#define TARGET_ENETRESET 52 +#undef TARGET_ECONNABORTED +#define TARGET_ECONNABORTED 53 +#undef TARGET_ECONNRESET +#define TARGET_ECONNRESET 54 +#undef TARGET_ENOBUFS +#define TARGET_ENOBUFS 55 +#undef TARGET_EISCONN +#define TARGET_EISCONN 56 +#undef TARGET_ENOTCONN +#define TARGET_ENOTCONN 57 +#undef TARGET_ESHUTDOWN +#define TARGET_ESHUTDOWN 58 +#undef TARGET_ETOOMANYREFS +#define TARGET_ETOOMANYREFS 59 +#undef TARGET_ETIMEDOUT +#define TARGET_ETIMEDOUT 60 +#undef TARGET_ECONNREFUSED +#define TARGET_ECONNREFUSED 61 +#undef TARGET_ELOOP +#define TARGET_ELOOP 62 +#undef TARGET_ENAMETOOLONG +#define TARGET_ENAMETOOLONG 63 +#undef TARGET_EHOSTDOWN +#define TARGET_EHOSTDOWN 64 +#undef TARGET_EHOSTUNREACH +#define TARGET_EHOSTUNREACH 65 +#undef TARGET_ENOTEMPTY +#define TARGET_ENOTEMPTY 66 +/* Unused 67 */ +#undef TARGET_EUSERS +#define TARGET_EUSERS 68 +#undef TARGET_EDQUOT +#define TARGET_EDQUOT 69 +#undef TARGET_ESTALE +#define TARGET_ESTALE 70 +#undef TARGET_EREMOTE +#define TARGET_EREMOTE 71 +/* Unused 72-76 */ +#undef TARGET_ENOLCK +#define TARGET_ENOLCK 77 +#undef TARGET_ENOSYS +#define TARGET_ENOSYS 78 +/* Unused 79 */ +#undef TARGET_ENOMSG +#define TARGET_ENOMSG 80 +#undef TARGET_EIDRM +#define TARGET_EIDRM 81 +#undef TARGET_ENOSR +#define TARGET_ENOSR 82 +#undef TARGET_ETIME +#define TARGET_ETIME 83 +#undef TARGET_EBADMSG +#define TARGET_EBADMSG 84 +#undef TARGET_EPROTO +#define TARGET_EPROTO 85 +#undef TARGET_ENODATA +#define TARGET_ENODATA 86 +#undef TARGET_ENOSTR +#define TARGET_ENOSTR 87 +#undef TARGET_ECHRNG +#define TARGET_ECHRNG 88 +#undef TARGET_EL2NSYNC +#define TARGET_EL2NSYNC 89 +#undef TARGET_EL3HLT +#define TARGET_EL3HLT 90 +#undef TARGET_EL3RST +#define TARGET_EL3RST 91 +#undef TARGET_ENOPKG +#define TARGET_ENOPKG 92 +#undef TARGET_ELNRNG +#define TARGET_ELNRNG 93 +#undef TARGET_EUNATCH +#define TARGET_EUNATCH 94 +#undef TARGET_ENOCSI +#define TARGET_ENOCSI 95 +#undef TARGET_EL2HLT +#define TARGET_EL2HLT 96 +#undef TARGET_EBADE +#define TARGET_EBADE 97 +#undef TARGET_EBADR +#define TARGET_EBADR 98 +#undef TARGET_EXFULL +#define TARGET_EXFULL 99 +#undef TARGET_ENOANO +#define TARGET_ENOANO 100 +#undef TARGET_EBADRQC +#define TARGET_EBADRQC 101 +#undef TARGET_EBADSLT +#define TARGET_EBADSLT 102 +/* Unused 103 */ +#undef TARGET_EBFONT +#define TARGET_EBFONT 104 +#undef TARGET_ENONET +#define TARGET_ENONET 105 +#undef TARGET_ENOLINK +#define TARGET_ENOLINK 106 +#undef TARGET_EADV +#define TARGET_EADV 107 +#undef TARGET_ESRMNT +#define TARGET_ESRMNT 108 +#undef TARGET_ECOMM +#define TARGET_ECOMM 109 +#undef TARGET_EMULTIHOP +#define TARGET_EMULTIHOP 110 +#undef TARGET_EDOTDOT +#define TARGET_EDOTDOT 111 +#undef TARGET_EOVERFLOW +#define TARGET_EOVERFLOW 112 +#undef TARGET_ENOTUNIQ +#define TARGET_ENOTUNIQ 113 +#undef TARGET_EBADFD +#define TARGET_EBADFD 114 +#undef TARGET_EREMCHG +#define TARGET_EREMCHG 115 +#undef TARGET_EILSEQ +#define TARGET_EILSEQ 116 +/* Same as default 117-121 */ +#undef TARGET_ELIBACC +#define TARGET_ELIBACC 122 +#undef TARGET_ELIBBAD +#define TARGET_ELIBBAD 123 +#undef TARGET_ELIBSCN +#define TARGET_ELIBSCN 124 +#undef TARGET_ELIBMAX +#define TARGET_ELIBMAX 125 +#undef TARGET_ELIBEXEC +#define TARGET_ELIBEXEC 126 +#undef TARGET_ERESTART +#define TARGET_ERESTART 127 +#undef TARGET_ESTRPIPE +#define TARGET_ESTRPIPE 128 +#undef TARGET_ENOMEDIUM +#define TARGET_ENOMEDIUM 129 +#undef TARGET_EMEDIUMTYPE +#define TARGET_EMEDIUMTYPE 130 +#undef TARGET_ECANCELED +#define TARGET_ECANCELED 131 +#undef TARGET_ENOKEY +#define TARGET_ENOKEY 132 +#undef TARGET_EKEYEXPIRED +#define TARGET_EKEYEXPIRED 133 +#undef TARGET_EKEYREVOKED +#define TARGET_EKEYREVOKED 134 +#undef TARGET_EKEYREJECTED +#define TARGET_EKEYREJECTED 135 +#undef TARGET_EOWNERDEAD +#define TARGET_EOWNERDEAD 136 +#undef TARGET_ENOTRECOVERABLE +#define TARGET_ENOTRECOVERABLE 137 +#undef TARGET_ERFKILL +#define TARGET_ERFKILL 138 +#undef TARGET_EHWPOISON +#define TARGET_EHWPOISON 139 + +#endif diff --git a/linux-user/sw64/target_fcntl.h b/linux-user/sw64/target_fcntl.h new file mode 100644 index 0000000000000000000000000000000000000000..9721e3de39bf6570f809436aee1d09fd14fc9042 --- /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 0000000000000000000000000000000000000000..8cc1693b0582b9d16bebd7071e19e675e37a0d19 --- /dev/null +++ b/linux-user/sw64/target_signal.h @@ -0,0 +1,100 @@ +#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 +#define TARGET_ARCH_HAS_KA_RESTORER +#define TARGET_ARCH_HAS_SIGTRAMP_PAGE 1 +#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 0000000000000000000000000000000000000000..7c13dc4bac0841cb2e649f35e7ca8ecf0933836e --- /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 0000000000000000000000000000000000000000..418905110cbe6dc880f8b8f4e9d3836559768395 --- /dev/null +++ b/linux-user/sw64/target_syscall.h @@ -0,0 +1,125 @@ +#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; +/* Those is needed by qemu to temporary store the user stack pointer */ + abi_ulong usp; + abi_ulong unique; +}; + + +#define TARGET_MCL_CURRENT 0x2000 +#define TARGET_MCL_FUTURE 0x4000 +#define TARGET_MCL_ONFAULT 0x8000 + +#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 0000000000000000000000000000000000000000..5c40efcb2074787e34c8c296d4b46951a400550e --- /dev/null +++ b/linux-user/sw64/termbits.h @@ -0,0 +1,266 @@ +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_EXTPROC 0x10000000 + +#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/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index 7e2915d53e49bae5ca239a368badf40e054f015c..0c8009071817c7c1553710a3c87f4159a1571b4c 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -85,7 +85,7 @@ #elif defined(TARGET_PPC) || defined(TARGET_ALPHA) || \ defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE) || \ - defined(TARGET_MIPS) + defined(TARGET_MIPS) || defined(TARGET_SW64) #define TARGET_IOC_SIZEBITS 13 #define TARGET_IOC_DIRBITS 3 @@ -2269,6 +2269,50 @@ struct target_stat { int __unused[2]; }; +#elif defined(TARGET_SW64) + +struct target_stat { + unsigned int st_dev; + unsigned int st_ino; + unsigned int st_mode; + unsigned int st_nlink; + unsigned int st_uid; + unsigned int st_gid; + unsigned int st_rdev; + abi_long st_size; + abi_ulong target_st_atime; + abi_ulong target_st_mtime; + abi_ulong target_st_ctime; + unsigned int st_blksize; + unsigned int st_blocks; + unsigned int st_flags; + unsigned int st_gen; +}; + +#define TARGET_HAS_STRUCT_STAT64 +struct target_stat64 { + abi_ulong st_dev; + abi_ulong st_ino; + abi_ulong st_rdev; + abi_long st_size; + abi_ulong st_blocks; + + unsigned int st_mode; + unsigned int st_uid; + unsigned int st_gid; + unsigned int st_blksize; + unsigned int st_nlink; + unsigned int __pad0; + + abi_ulong target_st_atime; + abi_ulong target_st_atime_nsec; + abi_ulong target_st_mtime; + abi_ulong target_st_mtime_nsec; + abi_ulong target_st_ctime; + abi_ulong target_st_ctime_nsec; + abi_long __unused[3]; +}; + #else #error unsupported CPU #endif diff --git a/meson.build b/meson.build index c5fdb785696c4f961539605891fcf682d866ed62..4d4fe04bd05880e4a286f9e99109f8add1ccf82c 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', 'loongarch64'] + 'arm', 'aarch64', 'mips', 'mips64', 'sparc', 'sparc64', 'loongarch64', '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'] elif cpu == 'loongarch64' kvm_targets = ['loongarch64-softmmu'] else @@ -361,6 +367,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' elif config_host['ARCH'] == 'loongarch64' tcg_arch = 'loongarch64' endif @@ -1818,6 +1826,7 @@ disassemblers = { 'sh4' : ['CONFIG_SH4_DIS'], 'sparc' : ['CONFIG_SPARC_DIS'], 'xtensa' : ['CONFIG_XTENSA_DIS'], + 'sw64' : ['CONFIG_SW64_DIS'], 'loongarch64' : ['CONFIG_LOONGARCH_DIS'], } if link_language == 'cpp' @@ -2473,6 +2482,7 @@ if have_system 'hw/sparc', 'hw/sparc64', 'hw/ssi', + 'hw/sw64', 'hw/timer', 'hw/tpm', 'hw/usb', @@ -3208,6 +3218,7 @@ summary_info += {'Trace backends': ','.join(get_option('trace_backends'))} if 'simple' in get_option('trace_backends') summary_info += {'Trace output file': get_option('trace_file') + '-'} endif +summary_info += {'vt-iommu': config_host.has_key('CONFIG_SW64_VT_IOMMU')} summary_info += {'QOM debugging': config_host.has_key('CONFIG_QOM_CAST_DEBUG')} summary_info += {'vhost-kernel support': config_host.has_key('CONFIG_VHOST_KERNEL')} summary_info += {'vhost-net support': config_host.has_key('CONFIG_VHOST_NET')} diff --git a/pc-bios/c3-uefi-bios-sw b/pc-bios/c3-uefi-bios-sw new file mode 100755 index 0000000000000000000000000000000000000000..095cc83a26872af6ee0f0bfb60a5301f2cffd31a Binary files /dev/null and b/pc-bios/c3-uefi-bios-sw differ diff --git a/pc-bios/c4-uefi-bios-sw b/pc-bios/c4-uefi-bios-sw new file mode 100644 index 0000000000000000000000000000000000000000..3dd29837b7fb3d621800f6f28da55002a634c721 Binary files /dev/null and b/pc-bios/c4-uefi-bios-sw differ diff --git a/pc-bios/core3-hmcode b/pc-bios/core3-hmcode new file mode 100644 index 0000000000000000000000000000000000000000..94bb0c2214d61ed5015b02c7843c0d79afb26696 Binary files /dev/null and b/pc-bios/core3-hmcode differ diff --git a/pc-bios/core3-reset b/pc-bios/core3-reset new file mode 100755 index 0000000000000000000000000000000000000000..5880780b3663f402d99b6fab68ed461c32f58566 Binary files /dev/null and b/pc-bios/core3-reset differ diff --git a/pc-bios/core4-hmcode b/pc-bios/core4-hmcode new file mode 100755 index 0000000000000000000000000000000000000000..e2e47b9c170fbffaf19429294332bb788770cecc Binary files /dev/null and b/pc-bios/core4-hmcode differ diff --git a/pc-bios/core4-reset b/pc-bios/core4-reset new file mode 100755 index 0000000000000000000000000000000000000000..ab5220ef7ecba0b26d73f734c83e936e982171e0 Binary files /dev/null and b/pc-bios/core4-reset differ diff --git a/pc-bios/meson.build b/pc-bios/meson.build index 60009bd89e84ecb8c7d66d70fb7078bb2038f3c8..0383ac84b48eeb26144376b4c01f7202fa8415fd 100644 --- a/pc-bios/meson.build +++ b/pc-bios/meson.build @@ -38,6 +38,12 @@ blobs = files( 'vgabios-ramfb.bin', 'vgabios-bochs-display.bin', 'vgabios-ati.bin', + 'c3-uefi-bios-sw', + 'core3-reset', + 'core3-hmcode', + 'c4-uefi-bios-sw', + 'core4-reset', + 'core4-hmcode', 'openbios-sparc32', 'openbios-sparc64', 'openbios-ppc', diff --git a/pc-bios/uefi-bios-sw-old b/pc-bios/uefi-bios-sw-old new file mode 100644 index 0000000000000000000000000000000000000000..8be24e6d73dac711276eb8bcc66625d689ce1e3f Binary files /dev/null and b/pc-bios/uefi-bios-sw-old differ diff --git a/qapi/machine-target.json b/qapi/machine-target.json index 682dc86b427c02ddba0387cb84529d0ffc8a324d..48be23e7f8cea6828c396c5bbe495d4ba69a57e8 100644 --- a/qapi/machine-target.json +++ b/qapi/machine-target.json @@ -325,6 +325,7 @@ 'TARGET_I386', 'TARGET_S390X', 'TARGET_MIPS', + 'TARGET_SW64', 'TARGET_LOONGARCH64' ] } } ## @@ -342,4 +343,5 @@ 'TARGET_I386', 'TARGET_S390X', 'TARGET_MIPS', + 'TARGET_SW64', 'TARGET_LOONGARCH64' ] } } diff --git a/qapi/machine.json b/qapi/machine.json index cd47b8d6bcb923f92658102b52ef5bc71a202814..e76311ccaa269c515ca4be8ebc12d62debd6f0df 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/qemu-options.hx b/qemu-options.hx index eaf16a68e0c8b014b31d0025b2719c5fe6acb4cb..c3c070de6f031ccbc4f3f3fcea2325743260d2b2 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -2480,7 +2480,7 @@ DEF("smbios", HAS_ARG, QEMU_OPTION_smbios, " specify SMBIOS type 17 fields\n" "-smbios type=41[,designation=str][,kind=str][,instance=%d][,pcidev=str]\n" " specify SMBIOS type 41 fields\n", - QEMU_ARCH_I386 | QEMU_ARCH_ARM | QEMU_ARCH_LOONGARCH64) + QEMU_ARCH_I386 | QEMU_ARCH_ARM | QEMU_ARCH_LOONGARCH64 | QEMU_ARCH_SW64) SRST ``-smbios file=binary`` Load SMBIOS entry from binary file. diff --git a/scripts/qemu-version.sh b/scripts/qemu-version.sh index 3f6e7e6d41d87b026a7a40681e2530e7c04bfc8a..31642ff3ddf6e76c429c89b4d0a1c869c3fbf15e 100755 --- a/scripts/qemu-version.sh +++ b/scripts/qemu-version.sh @@ -9,7 +9,7 @@ version="$3" if [ -z "$pkgversion" ]; then cd "$dir" if [ -e .git ]; then - pkgversion=$(git describe --match 'v*' --dirty) || : + pkgversion=$(git describe --tag --match 'v*' --dirty) || : fi fi diff --git a/softmmu/qdev-monitor.c b/softmmu/qdev-monitor.c index ece96121d3e09554e443a17ebf9a245b34f157b6..1b2d30d07c0e4f7e71f6a591e637b3f42c68d4a1 100644 --- a/softmmu/qdev-monitor.c +++ b/softmmu/qdev-monitor.c @@ -61,7 +61,7 @@ typedef struct QDevAlias QEMU_ARCH_MIPS | QEMU_ARCH_PPC | \ QEMU_ARCH_RISCV | QEMU_ARCH_SH4 | \ QEMU_ARCH_SPARC | QEMU_ARCH_XTENSA | \ - QEMU_ARCH_LOONGARCH64) + QEMU_ARCH_SW64 | QEMU_ARCH_LOONGARCH64) #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 50b46d0487fa10d2f6d3d1f830e864a18994a1ec..b2abc7b60b14ac3bc8b261a991ff6fde3a7c8402 100644 --- a/target/Kconfig +++ b/target/Kconfig @@ -18,3 +18,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 ac0ce618b7d43e8837275b163c7819ddfd4d7850..a824a390f9cc37361290176cc9728f59b46a935d 100644 --- a/target/meson.build +++ b/target/meson.build @@ -17,5 +17,6 @@ subdir('rx') subdir('s390x') subdir('sh4') subdir('sparc') +subdir('sw64') subdir('tricore') subdir('xtensa') diff --git a/target/openrisc/cpu.h b/target/openrisc/cpu.h index ee069b080c99d8eeccdfa09bd5ffbf64b5e0578f..a7a13cbb695da469e87d2ea18cfdff65bda59a24 100644 --- a/target/openrisc/cpu.h +++ b/target/openrisc/cpu.h @@ -81,7 +81,7 @@ enum { UPR_PMP = (1 << 8), UPR_PICP = (1 << 9), UPR_TTP = (1 << 10), - UPR_CUP = (255 << 24), + UPR_CUP = ((uint32_t)255 << 24), }; /* CPU configure register */ @@ -193,15 +193,15 @@ enum { TTMR_TP = (0xfffffff), TTMR_IP = (1 << 28), TTMR_IE = (1 << 29), - TTMR_M = (3 << 30), + TTMR_M = ((uint32_t)3 << 30), }; /* Timer Mode */ enum { TIMER_NONE = (0 << 30), TIMER_INTR = (1 << 30), - TIMER_SHOT = (2 << 30), - TIMER_CONT = (3 << 30), + TIMER_SHOT = ((uint32_t)2 << 30), + TIMER_CONT = ((uint32_t)3 << 30), }; /* TLB size */ diff --git a/target/sw64/Kconfig b/target/sw64/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..ad50b9677e553c84e275134f40383e375956b6f1 --- /dev/null +++ b/target/sw64/Kconfig @@ -0,0 +1,2 @@ +config SW64 + bool diff --git a/target/sw64/cpu-param.h b/target/sw64/cpu-param.h new file mode 100644 index 0000000000000000000000000000000000000000..464cfb3dc1b707508ee521ae61bc03a172917026 --- /dev/null +++ b/target/sw64/cpu-param.h @@ -0,0 +1,18 @@ +/* + * 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 +#define TARGET_PAGE_BITS 13 + +#define TARGET_VIRT_ADDR_SPACE_BITS 64 +#define TARGET_PHYS_ADDR_SPACE_BITS 48 + +#define NB_MMU_MODES 4 + +#endif diff --git a/target/sw64/cpu-qom.h b/target/sw64/cpu-qom.h new file mode 100644 index 0000000000000000000000000000000000000000..ea808fa71f2dd2b209c0ef121ddeb2c4e6031b78 --- /dev/null +++ b/target/sw64/cpu-qom.h @@ -0,0 +1,40 @@ +/* + * 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" +#include "qom/object.h" + +#define TYPE_SW64_CPU "sw64-cpu" +OBJECT_DECLARE_TYPE(SW64CPU, SW64CPUClass, 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; + DeviceUnrealize parent_unrealize; + DeviceReset parent_reset; +} SW64CPUClass; +#endif diff --git a/target/sw64/cpu.c b/target/sw64/cpu.c new file mode 100644 index 0000000000000000000000000000000000000000..1354abb5680c467650bde41552b900f75966324f --- /dev/null +++ b/target/sw64/cpu.c @@ -0,0 +1,454 @@ +/* + * 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" +#include "sysemu/arch_init.h" +#include "qapi/qapi-commands-machine-target.h" +#if !defined(CONFIG_USER_ONLY) +#include "hw/sw64/pm.h" +#endif + +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) +{ + 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"); +} + +#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; +#ifndef CONFIG_USER_ONLY + SW64CPU *cpu = SW64_CPU(dev); + MachineState *ms = MACHINE(qdev_get_machine()); + unsigned int max_cpus = ms->smp.max_cpus; + + if (cpu->core_id > 0) { + cpu_hot_id = cpu->core_id; + if (!cpu_hot_id || cpu_hot_id > max_cpus - 1) { + error_setg(&local_err, "error:" + "Cpu num must be less than max cpus and can not be 0!"); + error_propagate(errp, local_err); + return ; + } + if (get_state_cpumask(cpu_hot_id)) { + error_setg(&local_err, "error: Unable to add already online cpu!"); + error_propagate(errp, local_err); + return ; + } + } +#endif + + 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_unrealizefn(DeviceState *dev) +{ + SW64CPUClass *scc = SW64_CPU_GET_CLASS(dev); +#ifndef CONFIG_USER_ONLY + CPUState *cs = CPU(dev); + cpu_remove_sync(CPU(dev)); + qemu_unregister_reset(sw64_machine_cpu_reset, cs); +#endif + scc->parent_unrealize(dev); +} + +static char *sw64_cpu_class_get_model_name(SW64CPUClass *cc) +{ + const char *class_name = object_class_get_name(OBJECT_CLASS(cc)); + assert(g_str_has_suffix(class_name, SW64_CPU_TYPE_SUFFIX)); + return g_strndup(class_name, + strlen(class_name) - strlen(SW64_CPU_TYPE_SUFFIX)); +} + +static void sw64_cpu_list_entry(gpointer data, gpointer user_data) +{ + ObjectClass *oc = data; + SW64CPUClass *cc = SW64_CPU_CLASS(oc); + + char *name = sw64_cpu_class_get_model_name(cc); + qemu_printf("sw64 %s\n", name); + g_free(name); +} + +void sw64_cpu_list(void) +{ + GSList *list; + + list = object_class_get_list_sorted(TYPE_SW64_CPU, false); + qemu_printf("Available CPUs:\n"); + g_slist_foreach(list, sw64_cpu_list_entry, NULL); + g_slist_free(list); +} + +static void sw64_cpu_add_definition(gpointer data, gpointer user_data) +{ + ObjectClass *oc = data; + CpuDefinitionInfoList **cpu_list = user_data; + CpuDefinitionInfoList *entry; + CpuDefinitionInfo *info; + const char *typename; + + typename = object_class_get_name(oc); + info = g_malloc0(sizeof(*info)); + info->name = g_strndup(typename, + strlen(typename) - strlen("-" TYPE_SW64_CPU)); + info->q_typename = g_strdup(typename); + + entry = g_malloc0(sizeof(*entry)); + entry->value = info; + entry->next = *cpu_list; + *cpu_list = entry; +} + +CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp) +{ + CpuDefinitionInfoList *cpu_list = NULL; + GSList *list; + + list = object_class_get_list(TYPE_SW64_CPU, false); + g_slist_foreach(list, sw64_cpu_add_definition, &cpu_list); + g_slist_free(list); + + return cpu_list; +} + +static void sw64_cpu_disas_set_info(CPUState *cs, disassemble_info *info) +{ + CPUSW64State *env = cs->env_ptr; + if (test_feature(env, SW64_FEATURE_CORE3)) + info->mach = bfd_mach_sw64_core3; + else if(test_feature(env, SW64_FEATURE_CORE4)) + info->mach = bfd_mach_sw64_core4; + info->print_insn = print_insn_sw64; +} + +#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; +#endif + set_feature(env, SW64_FEATURE_CORE3); +} + +static void core4_init(Object *obj) +{ + CPUState *cs = CPU(obj); + CPUSW64State *env = cs->env_ptr; +#ifdef CONFIG_USER_ONLY + env->fpcr = 0x680e800000000000; +#endif + set_feature(env, SW64_FEATURE_CORE4); +} + +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_II0 | CPU_INTERRUPT_MCHK | CPU_INTERRUPT_IINM); +} + +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 + SW64CPU *cpu = SW64_CPU(cs); + CPUSW64State *env = &cpu->env; + + 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 + +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("thread-id", SW64CPU, thread_id, 0), + DEFINE_PROP_UINT32("core-id", SW64CPU, core_id, 0), + DEFINE_PROP_UINT32("socket-id", SW64CPU, socket_id, 0), +#else + DEFINE_PROP_UINT32("thread-id", SW64CPU, thread_id, 0), + DEFINE_PROP_UINT32("core-id", SW64CPU, core_id, 0xFFFFFFFF), + DEFINE_PROP_UINT32("socket-id", SW64CPU, socket_id, 0), +#endif + DEFINE_PROP_UINT32("node-id", SW64CPU, node_id, -1), + 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 = { + .initialize = sw64_translate_init, + +#ifndef CONFIG_USER_ONLY + .tlb_fill = sw64_cpu_tlb_fill, + .do_unaligned_access = sw64_cpu_do_unaligned_access, + .cpu_exec_interrupt = sw64_cpu_exec_interrupt, + .do_transaction_failed = sw64_cpu_do_transaction_failed, + .do_interrupt = sw64_cpu_do_interrupt, +#endif /* !CONFIG_USER_ONLY */ +}; + +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); + + scc->parent_unrealize = dc->unrealize; + dc->unrealize = sw64_cpu_unrealizefn; + + dc->user_creatable = true; + + cc->class_by_name = sw64_cpu_class_by_name; +#ifndef CONFIG_USER_ONLY + dc->vmsd = &vmstate_sw64_cpu; + cc->sysemu_ops = &sw64_sysemu_ops; +#endif + 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->gdb_read_register = sw64_cpu_gdb_read_register; + cc->gdb_write_register = sw64_cpu_gdb_write_register; + cc->gdb_num_core_regs = 67; + cc->gdb_core_xml_file = "sw64-core.xml"; + + cc->tcg_ops = &sw64_tcg_ops; +} + +static const SW64CPUInfo sw64_cpus[] = +{ + { + .name = "core3", + .initfn = core3_init, + }, + { + .name = "core4", + .initfn = core4_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 0000000000000000000000000000000000000000..8704d59def9400c723653bb73161b13f9c8905ee --- /dev/null +++ b/target/sw64/cpu.h @@ -0,0 +1,440 @@ +/* + * 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 + +#define PTE_MASK 0xbfffffffffffffff + +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 +#define SW64_FEATURE_CORE4 0x4 + +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[164]; + uint64_t k_vcb[96]; + QEMUTimer *alarm_timer; + target_ulong irq; + uint32_t node_id; + uint32_t thread_id; + uint32_t core_id; + uint32_t socket_id; +}; + +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) +#define cpu_list sw64_cpu_list +int cpu_sw64_signal_handler(int host_signum, void *pinfo, void *puc); +int sw64_cpu_gdb_read_register(CPUState *cs, GByteArray *buf, int reg); +int sw64_cpu_gdb_write_register(CPUState *cs, uint8_t *buf, int reg); +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); +#ifndef CONFIG_USER_ONLY +void sw64_cpu_do_interrupt(CPUState *cs); +bool sw64_cpu_exec_interrupt(CPUState *cpu, int int_req); +#endif +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; +void sw64_cpu_list(void); + +/* SW64-specific interrupt pending bits */ +#define CPU_INTERRUPT_TIMER CPU_INTERRUPT_TGT_EXT_0 +#define CPU_INTERRUPT_II0 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_IINM 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), +/* core3 csr */ + SWCSR(C3_PTBR, 0x8), + SWCSR(C3_PRI_BASE, 0x10), + SWCSR(C3_UPCR, 0x22), + SWCSR(C3_TIMER_CTL, 0x2a), + SWCSR(C3_TIMER_TH, 0x2b), + SWCSR(C3_INT_STAT, 0x30), + SWCSR(C3_INT_CLR, 0x31), + SWCSR(C3_IER, 0x32), + SWCSR(INT_PCI_INT, 0x33), + SWCSR(C3_DVA, 0x4e), + SWCSR(C3_DTB_PCR, 0x47), +/* core4 csr */ + SWCSR(C4_PRI_BASE, 0xf), + SWCSR(C4_UPCR, 0x15), + SWCSR(INT_EN, 0x1a), + SWCSR(C4_INT_STAT, 0x1b), + SWCSR(C4_INT_CLR, 0x1c), + SWCSR(PCIE_INT, 0x21), + SWCSR(C4_TIMER_TH, 0x23), + SWCSR(C4_TIMER_CTL, 0x24), + SWCSR(IINM, 0x2f), + SWCSR(C4_DVA, 0x54), + SWCSR(C4_DTB_UPCR, 0x58), + SWCSR(C4_PTBR_SYS, 0x68), + SWCSR(C4_PTBR_USR, 0x69), + SWCSR(SOFT_CID, 0xc9), + SWCSR(SHTCLOCK, 0xca), +}; + +#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_II0, + EXCP_IINM, + 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 0000000000000000000000000000000000000000..9b316a56e37102c5e2f6916587650971fd2c0536 --- /dev/null +++ b/target/sw64/exception.c @@ -0,0 +1,79 @@ +#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); + if (test_feature(env, SW64_FEATURE_CORE3)) + env->csr[C3_DVA] = addr; + else if (test_feature(env, SW64_FEATURE_CORE4)) + env->csr[C4_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 0000000000000000000000000000000000000000..c82fd0ce544f2b67cd56512a7363183764705d14 --- /dev/null +++ b/target/sw64/float_helper.c @@ -0,0 +1,797 @@ +#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; +} + +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); +} + +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; +} + +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); + fr = float32_add(fa, fb, &FP_STATUS); + + env->error_code = soft_to_errcode_exc(env); + 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; + fr = float64_add(fa, fb, &FP_STATUS); + env->error_code = soft_to_errcode_exc(env); + 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); + fr = float32_sub(fa, fb, &FP_STATUS); + env->error_code = soft_to_errcode_exc(env); + 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; + fr = float64_sub(fa, fb, &FP_STATUS); + env->error_code = soft_to_errcode_exc(env); + 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); + fr = float32_mul(fa, fb, &FP_STATUS); + env->error_code = soft_to_errcode_exc(env); + 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; + fr = float64_mul(fa, fb, &FP_STATUS); + env->error_code = soft_to_errcode_exc(env); + 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); + fr = float32_div(fa, fb, &FP_STATUS); + env->error_code = soft_to_errcode_exc(env); + 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; + fr = float64_div(fa, fb, &FP_STATUS); + env->error_code = soft_to_errcode_exc(env); + + 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); + fr = float32_div(fb, fa, &FP_STATUS); + env->error_code = soft_to_errcode_exc(env); + 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); + fr = float64_div(fb, fa, &FP_STATUS); + env->error_code = soft_to_errcode_exc(env); + + return (uint64_t)fr; +} + +uint64_t helper_fsqrts(CPUSW64State *env, uint64_t b) +{ + float32 fb, fr; + fb = s_to_float32(b); + fr = float32_sqrt(fb, &FP_STATUS); + env->error_code = soft_to_errcode_exc(env); + + return float32_to_s(fr); +} + +uint64_t helper_fsqrt(CPUSW64State *env, uint64_t b) +{ + float64 fr; + + fr = float64_sqrt(b, &FP_STATUS); + env->error_code = soft_to_errcode_exc(env); + + 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 CORE3. */ + 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 == 0) { + /* Denormals without /S raise an exception. */ + if (frac != 0) { + } + } else 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/gdbstub.c b/target/sw64/gdbstub.c new file mode 100644 index 0000000000000000000000000000000000000000..4e8f8f4a129d2021a32964bdbf211a4f71f797c4 --- /dev/null +++ b/target/sw64/gdbstub.c @@ -0,0 +1,56 @@ +/* + * SW64 gdb server stub + * + * Copyright (c) 2022 Lu Feifei + * + * 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-common.h" +#include "cpu.h" +#include "exec/gdbstub.h" + +int sw64_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) +{ + SW64CPU *cpu = SW64_CPU(cs); + CPUSW64State *env = &cpu->env; + + if (n < 31) { + return gdb_get_regl(mem_buf, env->ir[n]); + } else if (n == 31) { + return gdb_get_regl(mem_buf, 0); + } else if (n == 64) { + return gdb_get_regl(mem_buf, env->pc); + } + return 0; +} + +int sw64_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) +{ + SW64CPU *cpu = SW64_CPU(cs); + CPUSW64State *env = &cpu->env; + + if (n == 31) { + /* discard writes to r31 */ + return sizeof(target_ulong); + } else if (n < 31) { + env->ir[n] = ldtul_p(mem_buf); + return sizeof(target_ulong); + } else if (n == 64) { + env->pc = ldtul_p(mem_buf); + return sizeof(target_ulong); + } + + return 0; +} diff --git a/target/sw64/helper.c b/target/sw64/helper.c new file mode 100644 index 0000000000000000000000000000000000000000..345c13a5a2798f91f15838ec5a3c2ac97c0b575a --- /dev/null +++ b/target/sw64/helper.c @@ -0,0 +1,519 @@ +/* + * 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" + +#ifndef CONFIG_USER_ONLY +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, target_ulong *page_size) +{ + CPUState *cs = CPU(sw64_env_get_cpu(env)); + target_ulong phys = 0; + int prot = 0; + int ret = MM_K_ACV; + target_ulong page_offset = 0; + target_ulong L1pte, L2pte, L3pte, pte; + target_ulong pt = 0, index = 0, pte_pfn_s = 0; + + 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: + if (test_feature(env, SW64_FEATURE_CORE3)) { + pte_pfn_s = 28; + pt = env->csr[C3_PTBR]; + } else if (test_feature(env, SW64_FEATURE_CORE4)) { + pte_pfn_s = 24; + pt = (((addr>>52)&0x1) == 1) ? env->csr[C4_PTBR_SYS] : env->csr[C4_PTBR_USR]; + } + index = (addr >> (TARGET_PAGE_BITS + 3 * TARGET_LEVEL_BITS)) & ((1 << TARGET_LEVEL_BITS)-1); + L1pte = ldq_phys_clear(cs, pt + index * 8) & PTE_MASK; + 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) & PTE_MASK; + + 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) & PTE_MASK; + + 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); + + target_ulong page_granularity = (L3pte >> 5) & 0x3; + if (page_granularity != 0) { + pte = L3pte; + *page_size = 1 << 23; + page_offset = addr & 0x7fe000; + } else { + *page_size = TARGET_PAGE_SIZE; + page_offset = 0; + pte = ldq_phys_clear(cs, pt + index * 8) & PTE_MASK; + if ((pte & 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 ((pte & PTE_FOR) == 0) { + prot |= PAGE_READ | PAGE_EXEC; + } + if ((pte & PTE_FOW) == 0) { + prot |= PAGE_WRITE; + } + + /* Check fault-on-operation violations. */ + prot &= ~(pte >> 1); + + phys = (pte >> pte_pfn_s << TARGET_PAGE_BITS) + page_offset; + + 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, DVA = 0; + target_ulong page_size = TARGET_PAGE_SIZE; + + if (test_feature(env, SW64_FEATURE_CORE3)) { + DVA = C3_DVA; + } else if (test_feature(env, SW64_FEATURE_CORE4)){ + DVA = C4_DVA; + } + 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, &page_size); + 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, 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; + target_ulong page_size = TARGET_PAGE_SIZE; + 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, &page_size); +done: + return (fail >= 0 ? -1 : phys); +} + +#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) + +void sw64_cpu_do_interrupt(CPUState *cs) +{ + int i = cs->exception_index; + + cs->exception_index = -1; + 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: + case EXCP_IINM: + if (test_feature(env, SW64_FEATURE_CORE3)) + i = 0xE80;/* core3 */ + else if (test_feature(env, SW64_FEATURE_CORE4)) + i = 0xE00;/* core4 */ + break; + case EXCP_MMFAULT: + i = 0x980; + env->csr[EXC_PC] = env->pc; + break; + case EXCP_II0: + env->csr[EXC_PC] = env->pc; + i = 0xE00; + break; + default: + break; + } + env->pc = env->hm_entry + i; + env->flags = ENV_FLAG_HM_MODE; +} + +bool sw64_cpu_exec_interrupt(CPUState *cs, int interrupt_request) +{ + SW64CPU *cpu = SW64_CPU(cs); + CPUSW64State *env = &cpu->env; + int idx = -1, INT_STAT = 0, IER = 0, PCI_INT = 0; + /* We never take interrupts while in PALmode. */ + if (env->flags & ENV_FLAG_HM_MODE) + return false; + + if (test_feature(env, SW64_FEATURE_CORE3)) { + IER = C3_IER; + INT_STAT = C3_INT_STAT; + PCI_INT = INT_PCI_INT; + } else if (test_feature(env, SW64_FEATURE_CORE4)) { + IER = INT_EN; + INT_STAT = C4_INT_STAT; + PCI_INT = PCIE_INT; + } + + if (interrupt_request & CPU_INTERRUPT_IINM) { + idx = EXCP_IINM; + env->csr[IINM] = 1UL << 1; + cs->interrupt_request &= ~CPU_INTERRUPT_IINM; + goto done; + } + + if (interrupt_request & CPU_INTERRUPT_II0) { + idx = EXCP_II0; + env->csr[INT_STAT] |= 1UL << 6; + if ((env->csr[IER] & env->csr[INT_STAT]) == 0) + return false; + cs->interrupt_request &= ~CPU_INTERRUPT_II0; + 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[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 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 == C3_PRI_BASE) || (index == C4_PRI_BASE)) + env->csr[index] = 0x10000; +#ifndef CONFIG_USER_ONLY + if (index == SHTCLOCK) + env->csr[index] = qemu_clock_get_ns(QEMU_CLOCK_HOST) / 40; +#endif + 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 == C3_PTBR) || (index == C4_PTBR_SYS) || + (index == C4_PTBR_USR) || (index == C3_UPCR) || (index == C3_DTB_PCR) || + (index == C4_UPCR) || (index == C4_DTB_UPCR)) { + tlb_flush(cs); + } +//core3 + if (index == C3_INT_CLR) { + env->csr[C3_INT_STAT] &= ~va; + } + if ((index == C3_TIMER_CTL) && (va == 1)) { + timer_mod(cpu->alarm_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + env->csr[C3_TIMER_TH]); + } + +//core4 + if (index == C4_INT_CLR) { + env->csr[C4_INT_STAT] &= ~va; + } + if (index == IINM) + env->csr[index] &= ~va; + if ((index == C4_TIMER_CTL) && (va == 1)) { + timer_mod(cpu->alarm_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + env->csr[C4_TIMER_TH]); + } + +#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 0000000000000000000000000000000000000000..a72f2ca79698b4a37c8f917cca8741a282599b17 --- /dev/null +++ b/target/sw64/helper.h @@ -0,0 +1,123 @@ +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) +#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 0000000000000000000000000000000000000000..131182585a4b13030dc0156aca32cb0d86c95215 --- /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 0000000000000000000000000000000000000000..ce87dee3a558368d63090625fa21d02d46dfc2c3 --- /dev/null +++ b/target/sw64/kvm.c @@ -0,0 +1,390 @@ +/* + * 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 "hw/sw64/core.h" +#include "qemu/log.h" + +unsigned long core3_init_pc = 0xfff0000000011100; +unsigned long core4_init_pc = 0xfff0000000011002; + +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); + CPUSW64State *env = cs->env_ptr; + regs = (struct kvm_regs *)cpu->k_regs; + if (test_feature(env, SW64_FEATURE_CORE3)) + regs->c3_regs.pc = core3_init_pc; + else if (test_feature(env, SW64_FEATURE_CORE4)) + regs->c4_regs.pc = core4_init_pc; + return kvm_vcpu_ioctl(cs, KVM_SET_REGS, regs); +} + +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) +{ + struct kvm_regs *regs; + CPUState *cs = CPU(cpu); + CPUSW64State *env = cs->env_ptr; + int ret; + regs = (struct kvm_regs *)cpu->k_regs; + if (test_feature(env, SW64_FEATURE_CORE3)) + regs->c3_regs.pc = core3_init_pc; + else if (test_feature(env, SW64_FEATURE_CORE4)) { + if (kvm_arch_vcpu_id(cs) == 0) { + regs->c4_regs.r[16] = 0xDEED2024; + regs->c4_regs.r[17] = dtb_start_c4; + } + regs->c4_regs.pc = core4_init_pc; + } + ret = kvm_vcpu_ioctl(cs, KVM_SET_REGS, regs); + 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, i; + SW64CPU *cpu = SW64_CPU(cs); + CPUSW64State *env = &cpu->env; + struct kvm_regs *regs; + regs = (struct kvm_regs *)cpu->k_regs; + ret = kvm_vcpu_ioctl(cs, KVM_GET_REGS, regs); + if (ret < 0) + return ret; + + ret = kvm_vcpu_ioctl(cs, KVM_SW64_GET_VCB, &cpu->k_vcb); + if (ret < 0) + return ret; + if (test_feature(env, SW64_FEATURE_CORE3)) { + for (i = 0; i < 16; i++) + env->ir[i] = regs->c3_regs.r[i]; + + for (i = 19; i < 29; i++) + env->ir[i] = regs->c3_regs.r[i-3]; + + env->ir[16] = regs->c3_regs.r16; + env->ir[17] = regs->c3_regs.r17; + env->ir[18] = regs->c3_regs.r18; + + env->ir[29] = regs->c3_regs.gp; + env->pc = regs->c3_regs.pc; + if (regs->c3_regs.ps >> 3) + env->ir[30] = cpu->k_vcb[3]; //usp + else + env->ir[30] = cpu->k_vcb[2]; //ksp + } else if (test_feature(env, SW64_FEATURE_CORE4)) { + for (i = 0; i < 30; i++) { + env->ir[i] = regs->c4_regs.r[i]; + } + env->ir[30] = cpu->k_vcb[44]; + env->pc = regs->c4_regs.pc; + } + return 0; +} + +int kvm_arch_put_registers(CPUState *cs, int level) +{ + int ret; + SW64CPU *cpu = SW64_CPU(cs); + struct kvm_regs *regs; + CPUSW64State *env = &cpu->env; + + regs = (struct kvm_regs *)cpu->k_regs; + if (level == KVM_PUT_RUNTIME_STATE) { + int i; + if (test_feature(env, SW64_FEATURE_CORE3)) { + for (i = 0; i < 16; i++) + regs->c3_regs.r[i] = env->ir[i]; + + for (i = 19; i < 29; i++) + regs->c3_regs.r[i-3] = env->ir[i]; + + regs->c3_regs.r16 = env->ir[16]; + regs->c3_regs.r17 = env->ir[17]; + regs->c3_regs.r18 = env->ir[18]; + + regs->c3_regs.gp = env->ir[29]; + + if (regs->c3_regs.ps >> 3) + cpu->k_vcb[3] = env->ir[30]; //usp + else + cpu->k_vcb[2] = env->ir[30]; //ksp + + regs->c3_regs.pc = env->pc; + } else if (test_feature(env, SW64_FEATURE_CORE4)) { + for (i = 0; i < 30; i++) { + regs->c4_regs.r[i] = env->ir[i]; + } + cpu->k_vcb[44] = env->ir[30]; + + /* Using for guest kernel debugging */ + if ((env->pc & 0x2) == 0) { + env->pc |= 0x2; + } + regs->c4_regs.pc = env->pc; + } + } + + ret = kvm_vcpu_ioctl(cs, KVM_SET_REGS, regs); + if (ret < 0) + return ret; + + cpu->k_vcb[15] = kvm_arch_vcpu_id(cs); + fprintf(stderr,"vcpu %ld init.\n", cpu->k_vcb[15]); + + if (test_feature(env, SW64_FEATURE_CORE4)) { + if (level == KVM_PUT_RESET_STATE) { + /* Set initial value of PTBR_USR */ + cpu->k_vcb[27] = 0x0; + } + /* Set initial value of CSR_ATC */ + cpu->k_vcb[50] = 0x3; + /* Set initial value of CSR_PRI_BASE */ + cpu->k_vcb[51] = 0x10000; + } + + return kvm_vcpu_ioctl(cs, KVM_SW64_SET_VCB, &cpu->k_vcb); +} + +static const uint32_t brk_insn = 0x00000080; + +int kvm_arch_insert_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp) +{ + if (cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&bp->saved_insn, 4, 0) || + cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&brk_insn, 4, 1)) { + return -EINVAL; + } + + return 0; +} + +int kvm_arch_remove_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp) +{ + static uint32_t brk; + + if (cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&brk, 4, 0) || + brk != brk_insn || + cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&bp->saved_insn, 4, 1)) { + return -EINVAL; + } + + return 0; +} + +int kvm_arch_insert_hw_breakpoint(target_ulong addr, + target_ulong len, int type) +{ + qemu_log_mask(LOG_UNIMP, "%s: not implemented\n", __func__); + return -EINVAL; +} + +int kvm_arch_remove_hw_breakpoint(target_ulong addr, + target_ulong len, int type) +{ + qemu_log_mask(LOG_UNIMP, "%s: not implemented\n", __func__); + return -EINVAL; +} + +void kvm_arch_remove_all_hw_breakpoints(void) +{ + qemu_log_mask(LOG_UNIMP, "%s: not implemented\n", __func__); +} + +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; +} + +bool kvm_sw64_handle_debug(CPUState *cs, struct kvm_debug_exit_arch *debug_exit) +{ + SW64CPU *cpu = SW64_CPU(cs); + CPUSW64State *env = &cpu->env; + + /* Ensure PC is synchronised */ + kvm_cpu_synchronize_state(cs); + + /* For gdb correctness, remove the mode bit if it exists */ + if (env->pc & 0x2) { + env->pc &= ~0x2; + debug_exit->epc &= ~0x2; + } + + if (cs->singlestep_enabled) { + return true; + } else if (kvm_find_sw_breakpoint(cs, debug_exit->epc)) { + return true; + } else { + error_report("%s: unhandled debug exit (%"PRIx64", %"PRIx64")", + __func__, env->pc, debug_exit->epc); + } + + return false; +} + +int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run) +{ + int ret = 0; + + switch (run->exit_reason) { + case KVM_EXIT_DEBUG: + if (kvm_sw64_handle_debug(cs, &run->debug.arch)) { + ret = EXCP_DEBUG; + } /* otherwise return to guest */ + break; + default: + qemu_log_mask(LOG_UNIMP, "%s: un-handled exit reason %d\n", + __func__, run->exit_reason); + break; + } + return ret; +} + +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 0000000000000000000000000000000000000000..81dd760008c73283dce68b2e4b9ea830c5169346 --- /dev/null +++ b/target/sw64/kvm_sw64.h @@ -0,0 +1,56 @@ +/* + * 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; + +/** + * kvm_sw64_handle_debug: + * @cs: CPUState + * @debug_exit: debug part of the KVM exit structure + * + * Returns: TRUE if the debug exception was handled. + */ +bool kvm_sw64_handle_debug(CPUState *cs, struct kvm_debug_exit_arch *debug_exit); +#endif diff --git a/target/sw64/machine.c b/target/sw64/machine.c new file mode 100644 index 0000000000000000000000000000000000000000..e117acf8821e8257c79c88eddd16e13c1bb92db5 --- /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, 164), + VMSTATE_UINTTL_ARRAY(k_vcb, SW64CPU, 96), +#endif + VMSTATE_END_OF_LIST() + } +}; diff --git a/target/sw64/meson.build b/target/sw64/meson.build new file mode 100644 index 0000000000000000000000000000000000000000..332f2c2ee65dbcfa992f916dd0aab83687383eb1 --- /dev/null +++ b/target/sw64/meson.build @@ -0,0 +1,20 @@ +sw64_ss = ss.source_set() +sw64_ss.add(files( + 'cpu.c', + 'exception.c', + 'float_helper.c', + 'helper.c', + 'gdbstub.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 0000000000000000000000000000000000000000..a4ad6fd56a743f2e6a38da989a5322f32fe76287 --- /dev/null +++ b/target/sw64/profile.c @@ -0,0 +1,2263 @@ +#include "translate.h" + +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 0000000000000000000000000000000000000000..5aca541ea736a856f60ad74c0007c48a61318217 --- /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 0000000000000000000000000000000000000000..40e80b6c55e7596b5fa65f3a60eb3df439b494ff --- /dev/null +++ b/target/sw64/simd_helper.c @@ -0,0 +1,986 @@ +#include "qemu/osdep.h" +#include "cpu.h" +#include "exec/exec-all.h" +#include "exec/helper-proto.h" + +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; + + 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; + } +} + +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; + + 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; + } +} + +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; + 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); + } +} + +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); + + 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; + } +} + +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 0000000000000000000000000000000000000000..43662eca21148f0a72191570a8295aa7607aa24c --- /dev/null +++ b/target/sw64/translate.c @@ -0,0 +1,5362 @@ +#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 void gen_lshift_mask(TCGv v0, TCGv v1, int size) +{ + TCGv mask = tcg_const_i64((1UL << size) - 1); + int i; + + tcg_gen_shl_i64(mask, mask, v1); + tcg_gen_andi_i64(mask, mask, (uint64_t)((1UL << size) - 1)); + tcg_gen_mov_i64(v0, mask); + + for (i = size; i < 64; i = i * 2) { + tcg_gen_shli_i64(mask, v0, i); + tcg_gen_or_i64(v0, mask, v0); + } + tcg_temp_free(mask); +} + +static void gen_lshifti_mask(TCGv v0, int v1, int size) +{ + int i; + uint64_t mask; + mask = (1UL << size) - 1; + mask = (mask << v1) & (uint64_t)((1UL << size) - 1); + for (i = size; i < 64; i = i * 2) { + mask |= (mask << i); + } + tcg_gen_movi_i64(v0, mask); +} + +static void gen_rshift_mask(TCGv v0, TCGv v1, int size) +{ + TCGv mask = tcg_const_i64((1UL << size) - 1); + int i; + + tcg_gen_shr_i64(mask, mask, v1); + tcg_gen_mov_i64(v0, mask); + + for (i = size; i < 64; i = i * 2) { + tcg_gen_shli_i64(mask, v0, i); + tcg_gen_or_i64(v0, mask, v0); + } + tcg_temp_free(mask); +} + +static void gen_rshifti_mask(TCGv v0, int v1, int size) +{ + int i; + uint64_t mask; + mask = (1UL << size) - 1; + mask = (mask >> v1) & (uint64_t)((1UL << size) - 1); + for (i = size; i < 64; i = i * 2) { + mask |= (mask << i); + } + tcg_gen_movi_i64(v0, mask); +} + +static void gen_rsign_mask(TCGv v0, TCGv v1,int size) +{ + TCGv mask, tmp; + uint64_t sign_mask = 0; + mask = tcg_temp_new(); + tmp = tcg_temp_new(); + int i; + + for (i = 0; i < 64 / size; i++) { + sign_mask |= (1UL << (size - 1)) << (i * size); + } + + tcg_gen_andi_i64(mask, v1, sign_mask); + tcg_gen_mov_i64(tmp, mask); + for (i = 1; i < size; i = i * 2) { + tcg_gen_shri_i64(mask, tmp, i); + tcg_gen_or_i64(tmp, mask, tmp); + } + tcg_gen_andc_i64(v0, tmp, v0); + tcg_temp_free(mask); + tcg_temp_free(tmp); +} + +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, uint64_t mask) +{ + 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 (mask) { + tcg_gen_andi_i64(addr, addr, mask); + } + + va = (fp ? cpu_fr[ra] : load_gir(ctx, ra)); + tcg_gen_qemu_load(va, addr, ctx->mem_idx); + //gen_helper_trace_mem(cpu_env, addr, va); + + 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, uint64_t mask) +{ + 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 (mask) { + tcg_gen_andi_i64(addr, addr, mask); + } + 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, t1, tmp1; + TCGv_i32 tmpa, tmpb, tmpc; + + 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 0x11: + /* TODO: DIVW */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmpa = tcg_temp_new_i32(); + tmpb = tcg_temp_new_i32(); + tmpc = tcg_temp_new_i32(); + tcg_gen_extrl_i64_i32(tmpa, va); + tcg_gen_extrl_i64_i32(tmpb, vb); + tcg_gen_div_i32(tmpc, tmpa, tmpb); + tcg_gen_ext_i32_i64(vc, tmpc); + tcg_temp_free_i32(tmpa); + tcg_temp_free_i32(tmpb); + tcg_temp_free_i32(tmpc); + break; + case 0x12: + /* UDIVW */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmpa = tcg_temp_new_i32(); + tmpb = tcg_temp_new_i32(); + tmpc = tcg_temp_new_i32(); + tcg_gen_extrl_i64_i32(tmpa, va); + tcg_gen_extrl_i64_i32(tmpb, vb); + tcg_gen_divu_i32(tmpc, tmpa, tmpb); + tcg_gen_extu_i32_i64(vc, tmpc); + tcg_temp_free_i32(tmpa); + tcg_temp_free_i32(tmpb); + tcg_temp_free_i32(tmpc); + break; + case 0x13: + /* REMW */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmpa = tcg_temp_new_i32(); + tmpb = tcg_temp_new_i32(); + tmpc = tcg_temp_new_i32(); + tcg_gen_extrl_i64_i32(tmpa, va); + tcg_gen_extrl_i64_i32(tmpb, vb); + tcg_gen_rem_i32(tmpc, tmpa, tmpb); + tcg_gen_ext_i32_i64(vc, tmpc); + tcg_temp_free_i32(tmpa); + tcg_temp_free_i32(tmpb); + tcg_temp_free_i32(tmpc); + break; + case 0x14: + /* UREMW */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmpa = tcg_temp_new_i32(); + tmpb = tcg_temp_new_i32(); + tmpc = tcg_temp_new_i32(); + tcg_gen_extrl_i64_i32(tmpa, va); + tcg_gen_extrl_i64_i32(tmpb, vb); + tcg_gen_remu_i32(tmpc, tmpa, tmpb); + tcg_gen_extu_i32_i64(vc, tmpc); + tcg_temp_free_i32(tmpa); + tcg_temp_free_i32(tmpb); + tcg_temp_free_i32(tmpc); + 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 0x1A: + /* DIVL */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tcg_gen_div_i64(vc, va, vb); + break; + case 0x1B: + /* UDIVL */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tcg_gen_divu_i64(vc, va, vb); + break; + case 0x1C: + /* REML */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tcg_gen_rem_i64(vc, va, vb); + break; + case 0x1D: + /* UREML */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tcg_gen_remu_i64(vc, va, vb); + break; + case 0x1E: + /* TODO:ADDPI */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmp = tcg_const_i64(disp13); + tcg_gen_shli_i64(tmp, tmp, 2); + tcg_gen_addi_i64(vc, tmp, ctx->base.pc_next & ~3UL); + tcg_temp_free_i64(tmp); + break; + case 0x1F: + /* ADDPIS */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmp = tcg_const_i64(disp13); + tcg_gen_shli_i64(tmp, tmp, 16); + tcg_gen_addi_i64(vc, tmp, ctx->base.pc_next & 0xffffffffffff0000); + tcg_temp_free_i64(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 0x2D: + /* SBT */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmp = tcg_temp_new_i64(); + t1 = tcg_const_i64(1); + tcg_gen_andi_i64(tmp, vb, 0x3f); + tcg_gen_shl_i64(tmp, t1, tmp); + tcg_gen_or_i64(vc, va, tmp); + tcg_temp_free_i64(tmp); + tcg_temp_free_i64(t1); + break; + case 0x2E: + /* CBT */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmp = tcg_temp_new_i64(); + t1 = tcg_const_i64(1); + tcg_gen_andi_i64(tmp, vb, 0x3f); + tcg_gen_shl_i64(tmp, t1, tmp); + tcg_gen_andc_i64(vc, va, tmp); + tcg_temp_free_i64(tmp); + tcg_temp_free_i64(t1); + 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 0x4B: + /* ROLL */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmp = tcg_temp_new_i64(); + tcg_gen_andi_i64(tmp, vb, 0x3f); + tcg_gen_rotl_i64(vc, va, tmp); + tcg_temp_free_i64(tmp); + break; + case 0x4C: + /* SLLW */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmp = tcg_temp_new(); + tmp1 = tcg_temp_new(); + tcg_gen_andi_i64(tmp, vb, 0x1f); + tcg_gen_ext32u_i64(tmp1, va); + tcg_gen_shl_i64(vc, tmp1, tmp); + tcg_gen_ext32u_i64(vc, vc); + tcg_temp_free(tmp); + tcg_temp_free(tmp1); + break; + case 0x4D: + /* SRLW */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmp = tcg_temp_new(); + tcg_gen_andi_i64(tmp, vb, 0x1f); + tcg_gen_ext32u_i64(va, va); + tcg_gen_shr_i64(vc, va, tmp); + tcg_gen_ext32u_i64(vc, vc); + tcg_temp_free(tmp); + break; + case 0x4E: + /* SRAW */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmp = tcg_temp_new(); + tcg_gen_andi_i64(tmp, vb, 0x1f); + tcg_gen_ext32s_i64(va, va); + tcg_gen_sar_i64(vc, va, tmp); + tcg_gen_ext32u_i64(vc, vc); + tcg_temp_free(tmp); + break; + case 0x4F: + /* ROLW */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmpa = tcg_temp_new_i32(); + tmpb = tcg_temp_new_i32(); + tmpc = tcg_temp_new_i32(); + tcg_gen_extrl_i64_i32(tmpa, va); + tcg_gen_extrl_i64_i32(tmpb, vb); + tcg_gen_rotl_i32(tmpc, tmpa, tmpb); + tcg_gen_extu_i32_i64(vc, tmpc); + tcg_temp_free_i32(tmpa); + tcg_temp_free_i32(tmpb); + tcg_temp_free_i32(tmpc); + 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 0x5B: + /* REVBH */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmp = tcg_temp_new_i64(); + tcg_gen_andi_i64(tmp, vb, 0xffffUL); + tcg_gen_bswap16_i64(vc, tmp, TCG_BSWAP_IZ); + tcg_temp_free_i64(tmp); + break; + case 0x5C: + /* REVBW */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmp = tcg_temp_new_i64(); + tcg_gen_andi_i64(tmp, vb, 0xffffffffUL); + tcg_gen_bswap32_i64(vc, tmp, TCG_BSWAP_IZ); + tcg_temp_free_i64(tmp); + break; + case 0x5D: + /* REVBL */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tcg_gen_bswap64_i64(vc, vb); + break; + case 0x5E: + /* CASW */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tcg_gen_atomic_cmpxchg_i64(vc, vb, va, vc, ctx->mem_idx, MO_TEUL); + break; + case 0x5F: + /* CASL */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tcg_gen_atomic_cmpxchg_i64(vc, vb, va, vc, ctx->mem_idx, MO_TEQ); + 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); + 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); + } + 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 gen_transformat(int rb, int rc, + void (*helper)(TCGv, TCGv_ptr, TCGv, TCGv), + uint64_t round_mode) +{ + TCGv tmp64; + tmp64 = tcg_temp_new_i64(); + tcg_gen_movi_i64(tmp64, round_mode); + helper(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; + case 0x58: + /* TODO:FRECS */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + gen_frecs(ctx, ra, rc); + break; + case 0x59: + /* TODO:FRECD */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + gen_frecd(ctx, ra, rc); + break; + case 0x5A: + /* TODO:FRIS */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + gen_transformat(rb, rc, gen_helper_fris, + 5); + break; + case 0x5B: + /* TODO:FRIS_G */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + gen_transformat(rb, rc, gen_helper_fris, 0); + break; + case 0x5C: + /* TODO:FRIS_P */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + gen_transformat(rb, rc, gen_helper_fris, 2); + break; + case 0x5D: + /* TODO:FRIS_Z */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + gen_transformat(rb, rc, gen_helper_fris, 3); + break; + case 0x5F: + /* TODO:FRIS_N */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + gen_transformat(rb, rc, gen_helper_fris, 1); + break; + case 0x60: + /* TODO:FRID */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + gen_transformat(rb, rc, gen_helper_frid, + 5); + break; + case 0x61: + /* TODO:FRID_G */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + gen_transformat(rb, rc, gen_helper_frid, 0); + break; + case 0x62: + /* TODO:FRID_P */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + gen_transformat(rb, rc, gen_helper_frid, 2); + break; + case 0x63: + /* TODO:FRID_Z */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + gen_transformat(rb, rc, gen_helper_frid, 3); + break; + case 0x64: + /* TODO:FRID_N */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + gen_transformat(rb, rc, gen_helper_frid, 1); + 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 */ + 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); + if (test_feature(ctx->env, SW64_FEATURE_CORE3)) + 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); + + if (test_feature(ctx->env, SW64_FEATURE_CORE4)) + { + tcg_gen_mov_i64(load_gir(ctx, ra), cpu_lock_success); + tcg_gen_movi_i64(cpu_lock_success, 0); + } + 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 tcg_gen_sraow_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_sraow(cpu_env, va, vc, shift); + + tcg_temp_free(vc); + tcg_temp_free(va); + tcg_temp_free(shift); +} + +static void tcg_gen_sraowi_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_sraow(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, tmp64_2, tmp64_3, 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 0x0002: + /* WMEMB */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tcg_gen_mb(TCG_MO_ST_ST | TCG_BAR_SC); + 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(0xc9, 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(test_feature(ctx->env, SW64_FEATURE_CORE4)) break; + 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(test_feature(ctx->env, SW64_FEATURE_CORE4)) break; + 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) == 0xFC00) { + /* CSRWS */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmp64 = tcg_temp_new_i64(); + read_csr(disp16 & 0xff, tmp64); + va = load_gir(ctx, ra); + tcg_gen_or_i64(tmp64, tmp64, va); + write_csr(disp16 & 0xff, tmp64, ctx->env); + tcg_temp_free_i64(tmp64); + break; + } + if ((disp16 & 0xFF00) == 0xFD00) { + /* CSRWC */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmp64 = tcg_temp_new_i64(); + read_csr(disp16 & 0xff, tmp64); + va = load_gir(ctx, ra); + tcg_gen_andc_i64(tmp64, tmp64, va); + write_csr(disp16 & 0xff, tmp64, ctx->env); + tcg_temp_free_i64(tmp64); + break; + } + 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 0x10: + /* VSLLB */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmp64 = tcg_temp_new(); + shift = tcg_temp_new(); + tcg_gen_shri_i64(shift, cpu_fr[rb], 29); + tcg_gen_andi_i64(shift, shift, 0x7UL); + gen_lshift_mask(tmp64, shift, 8); + for (i = 0; i < 128; i += 32) { + tcg_gen_shl_i64(cpu_fr[rc + i], cpu_fr[ra + i], shift); + tcg_gen_and_i64(cpu_fr[rc + i], tmp64, cpu_fr[rc + i]); + } + tcg_temp_free(tmp64); + tcg_temp_free(shift); + break; + case 0x30: + /* VSLLBI */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmp64 = tcg_temp_new(); + gen_lshifti_mask(tmp64, disp8 & 0x7UL, 8); + for (i = 0; i < 128; i += 32) { + tcg_gen_shli_i64(cpu_fr[rc + i], cpu_fr[ra + i], + disp8 & 0x7UL); + tcg_gen_and_i64(cpu_fr[rc + i], tmp64, cpu_fr[rc + i]); + } + tcg_temp_free(tmp64); + break; + case 0x11: + /* VSRLB */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmp64 = tcg_temp_new(); + shift = tcg_temp_new(); + tcg_gen_shri_i64(shift, cpu_fr[rb], 29); + tcg_gen_andi_i64(shift, shift, 0x7UL); + gen_rshift_mask(tmp64, shift, 8); + for (i = 0; i < 128; i += 32) { + tcg_gen_shr_i64(cpu_fr[rc + i], cpu_fr[ra + i], shift); + tcg_gen_and_i64(cpu_fr[rc + i], tmp64, cpu_fr[rc + i]); + } + tcg_temp_free(tmp64); + tcg_temp_free(shift); + break; + case 0x31: + /* VSRLBI */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmp64 = tcg_temp_new(); + gen_rshifti_mask(tmp64, disp8 & 0x7UL, 8); + for (i = 0; i < 128; i += 32) { + tcg_gen_shri_i64(cpu_fr[rc + i], cpu_fr[ra + i], + disp8 & 0x7UL); + tcg_gen_and_i64(cpu_fr[rc + i], tmp64, cpu_fr[rc + i]); + } + break; + case 0x12: + /* VSRAB */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmp64 = tcg_temp_new(); + tmp64_0 = tcg_temp_new(); + tmp64_1 = tcg_temp_new(); + shift = tcg_temp_new(); + tcg_gen_shri_i64(shift, cpu_fr[rb], 29); + tcg_gen_andi_i64(shift, shift, 0x7UL); + gen_rshift_mask(tmp64, shift, 8); + for (i = 0; i < 128; i += 32) { + tcg_gen_mov_i64(tmp64_0, tmp64); + gen_rsign_mask(tmp64_0, cpu_fr[ra + i], 8); + tcg_gen_sar_i64(cpu_fr[rc + i], cpu_fr[ra + i], shift); + tcg_gen_and_i64(cpu_fr[rc + i], tmp64, cpu_fr[rc + i]); + tcg_gen_or_i64(cpu_fr[rc + i], tmp64_0, cpu_fr[rc + i]); + } + tcg_temp_free(tmp64); + tcg_temp_free(tmp64_0); + tcg_temp_free(shift); + break; + case 0x32: + /* VSRABI */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmp64 = tcg_temp_new(); + tmp64_0 = tcg_temp_new(); + gen_rshifti_mask(tmp64, disp8 & 0x7UL, 8); + for (i = 0; i < 128; i += 32) { + tcg_gen_mov_i64(tmp64_0, tmp64); + gen_rsign_mask(tmp64_0, cpu_fr[ra + i], 8); + tcg_gen_sari_i64(cpu_fr[rc + i], cpu_fr[ra + i], disp8 & 0x7UL); + tcg_gen_and_i64(cpu_fr[rc + i], tmp64, cpu_fr[rc + i]); + tcg_gen_or_i64(cpu_fr[rc + i], tmp64_0, cpu_fr[rc + i]); + } + tcg_temp_free(tmp64); + tcg_temp_free(tmp64_0); + break; + case 0x13: + /* VROLB */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmp64 = tcg_temp_new(); + tmp64_0 = tcg_temp_new(); + tmp64_1 = tcg_temp_new(); + tmp64_2 = tcg_temp_new(); + tmp64_3 = tcg_temp_new(); + shift = tcg_temp_new(); + tcg_gen_shri_i64(shift, cpu_fr[rb], 29); + tcg_gen_andi_i64(shift, shift, 0x7UL); + tcg_gen_subfi_i64(tmp64_3, 8, shift); + gen_lshift_mask(tmp64, shift, 8); + tcg_gen_not_i64(tmp64_0, tmp64); + for (i = 0; i < 128; i += 32) { + tcg_gen_shl_i64(tmp64_1, cpu_fr[ra + i], shift); + tcg_gen_and_i64(tmp64_1, tmp64_1, tmp64); + tcg_gen_shr_i64(tmp64_2, cpu_fr[ra + i], tmp64_3); + tcg_gen_and_i64(tmp64_2, tmp64_2, tmp64_0); + tcg_gen_or_i64(cpu_fr[rc + i], tmp64_1, tmp64_2); + } + tcg_temp_free(tmp64); + tcg_temp_free(tmp64_0); + tcg_temp_free(tmp64_1); + tcg_temp_free(tmp64_2); + tcg_temp_free(tmp64_3); + tcg_temp_free(shift); + break; + case 0x33: + /* VROLBI */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmp64 = tcg_temp_new(); + tmp64_0 = tcg_temp_new(); + tmp64_1 = tcg_temp_new(); + tmp64_2 = tcg_temp_new(); + tmp64_3 = tcg_temp_new(); + shift = tcg_temp_new(); + gen_lshifti_mask(tmp64, disp8 & 0x7UL, 8); + tcg_gen_not_i64(tmp64_0, tmp64); + for (i = 0; i < 128; i += 32) { + tcg_gen_shli_i64(tmp64_1, cpu_fr[ra + i], disp8 & 0x7UL); + tcg_gen_and_i64(tmp64_1, tmp64_1, tmp64); + tcg_gen_shri_i64(tmp64_2, cpu_fr[ra + i], 8 - (disp8 & 0x7UL)); + tcg_gen_and_i64(tmp64_2, tmp64_2, tmp64_0); + tcg_gen_or_i64(cpu_fr[rc + i], tmp64_1, tmp64_2); + } + tcg_temp_free(tmp64); + tcg_temp_free(tmp64_0); + tcg_temp_free(tmp64_1); + tcg_temp_free(tmp64_2); + tcg_temp_free(tmp64_3); + tcg_temp_free(shift); + break; + case 0x14: + /* VSLLH */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmp64 = tcg_temp_new(); + shift = tcg_temp_new(); + tcg_gen_shri_i64(shift, cpu_fr[rb], 29); + tcg_gen_andi_i64(shift, shift, 0xfUL); + gen_lshift_mask(tmp64, shift, 16); + for (i = 0; i < 128; i += 32) { + tcg_gen_shl_i64(cpu_fr[rc + i], cpu_fr[ra + i], shift); + tcg_gen_and_i64(cpu_fr[rc + i], tmp64, cpu_fr[rc + i]); + } + tcg_temp_free(tmp64); + tcg_temp_free(shift); + break; + case 0x34: + /* VSLLHI */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmp64 = tcg_temp_new(); + gen_lshifti_mask(tmp64, disp8 & 0xfUL, 16); + for (i = 0; i < 128; i += 32) { + tcg_gen_shli_i64(cpu_fr[rc + i], cpu_fr[ra + i], + disp8 & 0xfUL); + tcg_gen_and_i64(cpu_fr[rc + i], tmp64, cpu_fr[rc + i]); + } + tcg_temp_free(tmp64); + break; + case 0x15: + /* VSRLH */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmp64 = tcg_temp_new(); + shift = tcg_temp_new(); + tcg_gen_shri_i64(shift, cpu_fr[rb], 29); + tcg_gen_andi_i64(shift, shift, 0xfUL); + gen_rshift_mask(tmp64, shift, 16); + for (i = 0; i < 128; i += 32) { + tcg_gen_shr_i64(cpu_fr[rc + i], cpu_fr[ra + i], shift); + tcg_gen_and_i64(cpu_fr[rc + i], tmp64, cpu_fr[rc + i]); + } + tcg_temp_free(tmp64); + tcg_temp_free(shift); + break; + case 0x35: + /* VSRLHI */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmp64 = tcg_temp_new(); + gen_rshifti_mask(tmp64, disp8 & 0xfUL, 16); + for (i = 0; i < 128; i += 32) { + tcg_gen_shri_i64(cpu_fr[rc + i], cpu_fr[ra + i], + disp8 & 0xfUL); + tcg_gen_and_i64(cpu_fr[rc + i], tmp64, cpu_fr[rc + i]); + } + tcg_temp_free(tmp64); + break; + case 0x16: + /* VSRAH */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmp64 = tcg_temp_new(); + tmp64_0 = tcg_temp_new(); + shift = tcg_temp_new(); + tcg_gen_shri_i64(shift, cpu_fr[rb], 29); + tcg_gen_andi_i64(shift, shift, 0xfUL); + gen_rshift_mask(tmp64, shift, 16); + for (i = 0; i < 128; i += 32) { + tcg_gen_mov_i64(tmp64_0, tmp64); + gen_rsign_mask(tmp64_0, cpu_fr[ra + i], 16); + tcg_gen_sar_i64(cpu_fr[rc + i], cpu_fr[ra + i], shift); + tcg_gen_and_i64(cpu_fr[rc + i], tmp64, cpu_fr[rc + i]); + tcg_gen_or_i64(cpu_fr[rc + i], tmp64_0, cpu_fr[rc + i]); + } + tcg_temp_free(tmp64); + tcg_temp_free(tmp64_0); + tcg_temp_free(shift); + break; + case 0x36: + /* VSRAHI */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmp64 = tcg_temp_new(); + tmp64_0 = tcg_temp_new(); + shift = tcg_temp_new(); + gen_rshifti_mask(tmp64, disp8 & 0xfUL, 16); + for (i = 0; i < 128; i += 32) { + tcg_gen_mov_i64(tmp64_0, tmp64); + gen_rsign_mask(tmp64_0, cpu_fr[ra + i], 16); + tcg_gen_sari_i64(cpu_fr[rc + i], cpu_fr[ra + i], disp8 & 0xfUL); + tcg_gen_and_i64(cpu_fr[rc + i], tmp64, cpu_fr[rc + i]); + tcg_gen_or_i64(cpu_fr[rc + i], tmp64_0, cpu_fr[rc + i]); + } + tcg_temp_free(tmp64); + tcg_temp_free(tmp64_0); + tcg_temp_free(shift); + break; + case 0x17: + /* VROLH */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmp64 = tcg_temp_new(); + tmp64_0 = tcg_temp_new(); + tmp64_1 = tcg_temp_new(); + tmp64_2 = tcg_temp_new(); + tmp64_3 = tcg_temp_new(); + shift = tcg_temp_new(); + tcg_gen_shri_i64(shift, cpu_fr[rb], 29); + tcg_gen_andi_i64(shift, shift, 0xfUL); + tcg_gen_subfi_i64(tmp64_3, 16, shift); + gen_lshift_mask(tmp64, shift, 16); + tcg_gen_not_i64(tmp64_0, tmp64); + for (i = 0; i < 128; i += 32) { + tcg_gen_shl_i64(tmp64_1, cpu_fr[ra + i], shift); + tcg_gen_and_i64(tmp64_1, tmp64_1, tmp64); + tcg_gen_shr_i64(tmp64_2, cpu_fr[ra + i], tmp64_3); + tcg_gen_and_i64(tmp64_2, tmp64_2, tmp64_0); + tcg_gen_or_i64(cpu_fr[rc + i], tmp64_1, tmp64_2); + } + tcg_temp_free(tmp64); + tcg_temp_free(tmp64_0); + tcg_temp_free(tmp64_1); + tcg_temp_free(tmp64_2); + tcg_temp_free(tmp64_3); + tcg_temp_free(shift); + break; + case 0x37: + /* VROLHI */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmp64 = tcg_temp_new(); + tmp64_0 = tcg_temp_new(); + tmp64_1 = tcg_temp_new(); + tmp64_2 = tcg_temp_new(); + tmp64_3 = tcg_temp_new(); + shift = tcg_temp_new(); + gen_lshifti_mask(tmp64, disp8 & 0xfUL, 16); + tcg_gen_not_i64(tmp64_0, tmp64); + for (i = 0; i < 128; i += 32) { + tcg_gen_shli_i64(tmp64_1, cpu_fr[ra + i], disp8 & 0xfUL); + tcg_gen_and_i64(tmp64_1, tmp64_1, tmp64); + tcg_gen_shri_i64(tmp64_2, cpu_fr[ra + i], 16 - (disp8 & 0xfUL)); + tcg_gen_and_i64(tmp64_2, tmp64_2, tmp64_0); + tcg_gen_or_i64(cpu_fr[rc + i], tmp64_1, tmp64_2); + } + tcg_temp_free(tmp64); + tcg_temp_free(tmp64_0); + tcg_temp_free(tmp64_1); + tcg_temp_free(tmp64_2); + tcg_temp_free(tmp64_3); + tcg_temp_free(shift); + 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 0x1A: + /* VSLLL */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmp64 = tcg_temp_new(); + for (i = 0; i < 128; i += 32) { + tcg_gen_shri_i64(tmp64, cpu_fr[rb], 29); + tcg_gen_andi_i64(tmp64, tmp64, 0x3f); + + tcg_gen_shl_i64(cpu_fr[rc + i], cpu_fr[ra + i], tmp64); + } + tcg_temp_free(tmp64); + break; + case 0x3A: + /* VSLLLI */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + for (i = 0; i < 128; i += 32) { + tcg_gen_shli_i64(cpu_fr[rc + i], cpu_fr[ra + i], + disp8 & 0x3f); + } + break; + case 0x1B: + /* VSRLL */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmp64 = tcg_temp_new(); + for (i = 0; i < 128; i += 32) { + tcg_gen_shri_i64(tmp64, cpu_fr[rb], 29); + tcg_gen_andi_i64(tmp64, tmp64, 0x3f); + + tcg_gen_shr_i64(cpu_fr[rc + i], cpu_fr[ra + i], tmp64); + } + tcg_temp_free(tmp64); + break; + case 0x3B: + /* VSRLLI */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + for (i = 0; i < 128; i += 32) { + tcg_gen_shri_i64(cpu_fr[rc + i], cpu_fr[ra + i], + disp8 & 0x3f); + } + break; + case 0x1C: + /* VSRAL */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmp64 = tcg_temp_new(); + for (i = 0; i < 128; i += 32) { + tcg_gen_shri_i64(tmp64, cpu_fr[rb], 29); + tcg_gen_andi_i64(tmp64, tmp64, 0x3f); + + tcg_gen_sar_i64(cpu_fr[rc + i], cpu_fr[ra + i], tmp64); + } + tcg_temp_free(tmp64); + break; + case 0x3C: + /* VSRALI */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + for (i = 0; i < 128; i += 32) { + tcg_gen_sari_i64(cpu_fr[rc + i], cpu_fr[ra + i], + disp8 & 0x3f); + } + break; + case 0x1D: + /* VROLL */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmp64 = tcg_temp_new(); + for (i = 0; i < 128; i += 32) { + tcg_gen_shri_i64(tmp64, cpu_fr[rb], 29); + tcg_gen_andi_i64(tmp64, tmp64, 0x3f); + + tcg_gen_rotl_i64(cpu_fr[rc + i], cpu_fr[ra + i], tmp64); + } + tcg_temp_free(tmp64); + break; + case 0x3D: + /* VROLL */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + for (i = 0; i < 128; i += 32) { + tcg_gen_rotli_i64(cpu_fr[rc + i], cpu_fr[ra + i], + disp8 & 0x3f); + } + break; + case 0x1E: + /* VMAXB */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + va = tcg_const_i64(ra); + vb = tcg_const_i64(rb); + vc = tcg_const_i64(rc); + + gen_helper_vmaxb(cpu_env, va, vb, vc); + + tcg_temp_free(va); + tcg_temp_free(vb); + tcg_temp_free(vc); + break; + case 0x1F: + /* VMINB */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + va = tcg_const_i64(ra); + vb = tcg_const_i64(rb); + vc = tcg_const_i64(rc); + + gen_helper_vminb(cpu_env, va, vb, vc); + + tcg_temp_free(va); + tcg_temp_free(vb); + tcg_temp_free(vc); + 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 0x46: + /* SRAOW */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tcg_gen_sraow_i64(ra, rc, rb); + break; + case 0x66: + /* SRAOWI */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tcg_gen_sraowi_i64(ra, rc, disp8); + break; + case 0x47: + /* TODO:VSUMW */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmp64 = tcg_temp_new(); + tcg_gen_ext32u_i64(tmp64, cpu_fr[ra]); + tcg_gen_shri_i64(cpu_fr[rc], cpu_fr[ra], 32); + tcg_gen_add_i64(cpu_fr[rc], tmp64, cpu_fr[rc]); + for (i = 32; i < 128; i += 32) { + tcg_gen_ext32u_i64(tmp64, cpu_fr[ra + i]); + tcg_gen_add_i64(cpu_fr[rc], tmp64, cpu_fr[rc]); + tcg_gen_shri_i64(tmp64, cpu_fr[ra + i], 32); + tcg_gen_add_i64(cpu_fr[rc], tmp64, cpu_fr[rc]); + } + tcg_temp_free(tmp64); + break; + case 0x48: + /* VSUML */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tcg_gen_mov_i64(cpu_fr[rc], cpu_fr[ra]); + for (i = 32; i < 128; i += 32) { + tcg_gen_add_i64(cpu_fr[rc], cpu_fr[ra + i], cpu_fr[rc]); + } + break; + case 0x49: + /* VSM4R */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + va = tcg_const_i64(ra); + vb = tcg_const_i64(rb); + vc = tcg_const_i64(rc); + gen_helper_vsm4r(cpu_env, va, vb, vc); + tcg_temp_free(va); + tcg_temp_free(vb); + tcg_temp_free(vc); + break; + case 0x4A: + /* VBINVW */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmp64 = tcg_temp_new(); + for (i = 0; i < 128; i += 32) { + tcg_gen_bswap64_i64(tmp64, cpu_fr[rb + i]); + tcg_gen_rotli_i64(tmp64, tmp64, 32); + tcg_gen_mov_i64(cpu_fr[rc + i], tmp64); + } + break; + case 0x4B: + /* VCMPUEQB */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + va = tcg_const_i64(ra); + vb = tcg_const_i64(rb); + vc = tcg_const_i64(rc); + gen_helper_vcmpueqb(cpu_env, va, vb, vc); + tcg_temp_free(va); + tcg_temp_free(vb); + tcg_temp_free(vc); + break; + case 0x6B: + /* VCMPUEQBI*/ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + va = tcg_const_i64(ra); + vb = tcg_const_i64(disp8); + vc = tcg_const_i64(rc); + gen_helper_vcmpueqbi(cpu_env, va, vb, vc); + tcg_temp_free(va); + tcg_temp_free(vb); + tcg_temp_free(vc); + break; + case 0x4C: + /* VCMPUGTB */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + va = tcg_const_i64(ra); + vb = tcg_const_i64(rb); + vc = tcg_const_i64(rc); + gen_helper_vcmpugtb(cpu_env, va, vb, vc); + tcg_temp_free(va); + tcg_temp_free(vb); + tcg_temp_free(vc); + break; + case 0x6C: + /* VCMPUGTBI */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + va = tcg_const_i64(ra); + vb = tcg_const_i64(disp8); + vc = tcg_const_i64(rc); + gen_helper_vcmpugtbi(cpu_env, va, vb, vc); + tcg_temp_free(va); + tcg_temp_free(vb); + tcg_temp_free(vc); + break; + case 0x4D: + /* VSM3MSW */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + va = tcg_const_i64(ra); + vb = tcg_const_i64(rb); + vc = tcg_const_i64(rc); + gen_helper_vsm3msw(cpu_env, va, vb, vc); + tcg_temp_free(va); + tcg_temp_free(vb); + tcg_temp_free(vc); + break; + case 0x50: + /* VMAXH */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + va = tcg_const_i64(ra); + vb = tcg_const_i64(rb); + vc = tcg_const_i64(rc); + + gen_helper_vmaxh(cpu_env, va, vb, vc); + + tcg_temp_free(va); + tcg_temp_free(vb); + tcg_temp_free(vc); + break; + case 0x51: + /* VMINH */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + va = tcg_const_i64(ra); + vb = tcg_const_i64(rb); + vc = tcg_const_i64(rc); + + gen_helper_vminh(cpu_env, va, vb, vc); + + tcg_temp_free(va); + tcg_temp_free(vb); + tcg_temp_free(vc); + break; + case 0x52: + /* VMAXW */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + va = tcg_const_i64(ra); + vb = tcg_const_i64(rb); + vc = tcg_const_i64(rc); + + gen_helper_vmaxw(cpu_env, va, vb, vc); + + tcg_temp_free(va); + tcg_temp_free(vb); + tcg_temp_free(vc); + break; + case 0x53: + /* VMINW */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + va = tcg_const_i64(ra); + vb = tcg_const_i64(rb); + vc = tcg_const_i64(rc); + + gen_helper_vminw(cpu_env, va, vb, vc); + + tcg_temp_free(va); + tcg_temp_free(vb); + tcg_temp_free(vc); + break; + case 0x54: + /* VMAXL */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + for (i = 0; i < 128; i += 32) { + va = cpu_fr[ra + i]; + vb = cpu_fr[rb + i]; + vc = cpu_fr[rc + i]; + tcg_gen_movcond_i64(TCG_COND_GE, vc, va, vb, va, vb); + } + break; + case 0x55: + /* VMINL */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + for (i = 0; i < 128; i += 32) { + va = cpu_fr[ra + i]; + vb = cpu_fr[rb + i]; + vc = cpu_fr[rc + i]; + tcg_gen_movcond_i64(TCG_COND_LE, vc, va, vb, va, vb); + } + break; + case 0x56: + /* VUMAXB */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + va = tcg_const_i64(ra); + vb = tcg_const_i64(rb); + vc = tcg_const_i64(rc); + + gen_helper_vumaxb(cpu_env, va, vb, vc); + + tcg_temp_free(va); + tcg_temp_free(vb); + tcg_temp_free(vc); + break; + case 0x57: + /* VUMINB */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + va = tcg_const_i64(ra); + vb = tcg_const_i64(rb); + vc = tcg_const_i64(rc); + + gen_helper_vuminb(cpu_env, va, vb, vc); + + tcg_temp_free(va); + tcg_temp_free(vb); + tcg_temp_free(vc); + break; + case 0x58: + /* VUMAXH */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + va = tcg_const_i64(ra); + vb = tcg_const_i64(rb); + vc = tcg_const_i64(rc); + + gen_helper_vumaxh(cpu_env, va, vb, vc); + + tcg_temp_free(va); + tcg_temp_free(vb); + tcg_temp_free(vc); + break; + case 0x59: + /* VUMINH */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + va = tcg_const_i64(ra); + vb = tcg_const_i64(rb); + vc = tcg_const_i64(rc); + + gen_helper_vuminh(cpu_env, va, vb, vc); + + tcg_temp_free(va); + tcg_temp_free(vb); + tcg_temp_free(vc); + break; + case 0x5A: + /* VUMAXW */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + va = tcg_const_i64(ra); + vb = tcg_const_i64(rb); + vc = tcg_const_i64(rc); + + gen_helper_vumaxw(cpu_env, va, vb, vc); + + tcg_temp_free(va); + tcg_temp_free(vb); + tcg_temp_free(vc); + break; + case 0x5B: + /* VUMINW */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + va = tcg_const_i64(ra); + vb = tcg_const_i64(rb); + vc = tcg_const_i64(rc); + + gen_helper_vuminw(cpu_env, va, vb, vc); + + tcg_temp_free(va); + tcg_temp_free(vb); + tcg_temp_free(vc); + break; + case 0x5C: + /* VUMAXL */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + for (i = 0; i < 128; i += 32) { + va = cpu_fr[ra + i]; + vb = cpu_fr[rb + i]; + vc = cpu_fr[rc + i]; + tcg_gen_movcond_i64(TCG_COND_GEU, vc, va, vb, va, vb); + } + break; + case 0x5D: + /* VUMINL */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + for (i = 0; i < 128; i += 32) { + va = cpu_fr[ra + i]; + vb = cpu_fr[rb + i]; + vc = cpu_fr[rc + i]; + tcg_gen_movcond_i64(TCG_COND_LEU, vc, va, vb, va, vb); + } + break; + case 0x68: + /* VSM4KEY */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + va = tcg_const_i64(ra); + vb = tcg_const_i64(disp8); + vc = tcg_const_i64(rc); + gen_helper_vsm4key(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; + case 0x95: + /* VFCVTSD */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + for (i = 0; i < 128; i += 32) { + gen_helper_fcvtsd(cpu_fr[rc + i], cpu_env, + cpu_fr[rb + i]); + } + break; + case 0x96: + /* VFCVTDS */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + for (i = 0; i < 128; i += 32) { + gen_helper_fcvtds(cpu_fr[rc + i], cpu_env, + cpu_fr[rb + i]); + } + break; + case 0x99: + /* VFCVTLS */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + for (i = 0; i < 128; i += 32) { + gen_helper_fcvtls(cpu_fr[rc + i], cpu_env, + cpu_fr[rb + i]); + } + break; + case 0x9A: + /* VFCVTLD */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + for (i = 0; i < 128; i += 32) { + gen_helper_fcvtld(cpu_fr[rc + i], cpu_env, + cpu_fr[rb + i]); + } + break; + case 0x9B: + /* VFCVTDL */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + for (i = 0; i < 128; i += 32) { + gen_helper_fcvtdl_dyn(cpu_fr[rc + i], cpu_env, + cpu_fr[rb + i]); + } + break; + case 0x9C: + /* VFCVTDL_G */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + for (i = 0; i < 128; i += 32) { + gen_fcvtdl(rb + i, rc + i, 0); + } + break; + case 0x9D: + /* VFCVTDL_P */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + for (i = 0; i < 128; i += 32) { + gen_fcvtdl(rb + i, rc + i, 2); + } + break; + case 0x9E: + /* VFCVTDL_Z */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + for (i = 0; i < 128; i += 32) { + gen_fcvtdl(rb + i, rc + i, 3); + } + break; + case 0x9F: + /* VFCVTDL_N */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + for (i = 0; i < 128; i += 32) { + gen_fcvtdl(rb + i, rc + i, 1); + } + break; + case 0xA0: + /* VFRIS */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + for (i = 0; i < 128; i += 32) { + gen_transformat( + rb + i, rc + i, gen_helper_fris, + 5); + } + break; + case 0xA1: + /* VFRIS_G */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + for (i = 0; i < 128; i += 32) { + gen_transformat(rb + i, rc + i, gen_helper_fris, 0); + } + break; + case 0xA2: + /* VFRIS_P */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + for (i = 0; i < 128; i += 32) { + gen_transformat(rb + i, rc + i, gen_helper_fris, 2); + } + break; + case 0xA3: + /* VFRIS_Z */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + for (i = 0; i < 128; i += 32) { + gen_transformat(rb + i, rc + i, gen_helper_fris, 3); + } + break; + case 0xA4: + /* VFRIS_N */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + for (i = 0; i < 128; i += 32) { + gen_transformat(rb + i, rc + i, gen_helper_fris, 1); + } + break; + case 0xA5: + /* VFRID */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + for (i = 0; i < 128; i += 32) { + gen_transformat(rb + i, rc + i, gen_helper_frid, 5); + } + break; + case 0xA6: + /* VFRID_G */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + for (i = 0; i < 128; i += 32) { + gen_transformat(rb + i, rc + i, gen_helper_frid, 0); + } + break; + case 0xA7: + /* VFRID_P */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + for (i = 0; i < 128; i += 32) { + gen_transformat(rb + i, rc + i, gen_helper_frid, 2); + } + break; + case 0xA8: + /* VFRID_Z */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + for (i = 0; i < 128; i += 32) { + gen_transformat(rb + i, rc + i, gen_helper_frid, 3); + } + break; + case 0xA9: + /* VFRID_N */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + for (i = 0; i < 128; i += 32) { + gen_transformat(rb + i, rc + i, gen_helper_frid, 1); + } + break; + case 0xAA: + /* VFRECS */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + for (i = 0; i < 128; i += 32) { + gen_frecs(ctx, ra + i, rc + i); + } + break; + case 0xAB: + /* VFRECD */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + for (i = 0; i < 128; i += 32) { + gen_frecd(ctx, ra + i, rc + i); + } + break; + case 0xAC: + /* VMAXS */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmp64 = tcg_temp_new(); + tmp64_0 = tcg_const_i64(0); + for (i = 0; i < 128; i += 32) { + va = cpu_fr[ra + i]; + vb = cpu_fr[rb + i]; + vc = cpu_fr[rc + i]; + gen_helper_fcmpge_s(tmp64, cpu_env, va, vb); + tcg_gen_movcond_i64(TCG_COND_NE, vc, tmp64, tmp64_0, + va, vb); + } + tcg_temp_free(tmp64); + tcg_temp_free(tmp64_0); + break; + case 0xAD: + /* VMINS */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmp64 = tcg_temp_new(); + tmp64_0 = tcg_const_i64(0); + for (i = 0; i < 128; i += 32) { + va = cpu_fr[ra + i]; + vb = cpu_fr[rb + i]; + vc = cpu_fr[rc + i]; + gen_helper_fcmple_s(tmp64, cpu_env, va, vb); + tcg_gen_movcond_i64(TCG_COND_NE, vc, tmp64, tmp64_0, + va, vb); + } + tcg_temp_free(tmp64); + tcg_temp_free(tmp64_0); + break; + case 0xAE: + /* VMAXD */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmp64 = tcg_temp_new(); + tmp64_0 = tcg_const_i64(0); + for (i = 0; i < 128; i += 32) { + va = cpu_fr[ra + i]; + vb = cpu_fr[rb + i]; + vc = cpu_fr[rc + i]; + gen_helper_fcmpge(tmp64, cpu_env, va, vb); + tcg_gen_movcond_i64(TCG_COND_NE, vc, tmp64, tmp64_0, + va, vb); + } + tcg_temp_free(tmp64); + tcg_temp_free(tmp64_0); + break; + case 0xAF: + /* VMIND */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmp64 = tcg_temp_new(); + tmp64_0 = tcg_const_i64(0); + for (i = 0; i < 128; i += 32) { + va = cpu_fr[ra + i]; + vb = cpu_fr[rb + i]; + vc = cpu_fr[rc + i]; + gen_helper_fcmple(tmp64, cpu_env, va, vb); + tcg_gen_movcond_i64(TCG_COND_NE, vc, tmp64, tmp64_0, + va, vb); + } + tcg_temp_free(tmp64); + tcg_temp_free(tmp64_0); + 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(); + 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]); + 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; + case 0x2A: + /* VINSB */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + va = cpu_fr[ra]; + vb = tcg_const_i64(rb); + vc = tcg_const_i64(rd); + vd = tcg_const_i64(rc); + gen_helper_vinsb(cpu_env, va, vb, vc, vd); + tcg_temp_free(vb); + tcg_temp_free(vc); + tcg_temp_free(vd); + break; + case 0x2B: + /* VINSH */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + va = cpu_fr[ra]; + vb = tcg_const_i64(rb); + vc = tcg_const_i64(rd); + vd = tcg_const_i64(rc); + gen_helper_vinsh(cpu_env, va, vb, vc, vd); + tcg_temp_free(vb); + tcg_temp_free(vc); + tcg_temp_free(vd); + break; + case 0x2C: + /* VINSECTLH */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + va = tcg_const_i64(ra); + vb = tcg_const_i64(rb); + vd = tcg_const_i64(rc); + gen_helper_vinsectlh(cpu_env, va, vb, vd); + tcg_temp_free(va); + tcg_temp_free(vb); + tcg_temp_free(vd); + break; + case 0x2D: + /* VINSECTLW */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + va = tcg_const_i64(ra); + vb = tcg_const_i64(rb); + vd = tcg_const_i64(rc); + gen_helper_vinsectlw(cpu_env, va, vb, vd); + tcg_temp_free(va); + tcg_temp_free(vb); + tcg_temp_free(vd); + break; + case 0x2E: + /* VINSECTLL */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmp64 = tcg_temp_new(); + tmp64_0 = tcg_temp_new(); + tcg_gen_mov_i64(cpu_fr[rc + 96], cpu_fr[rb + 32]); + tcg_gen_mov_i64(cpu_fr[rc + 64], cpu_fr[ra + 32]); + tcg_gen_mov_i64(cpu_fr[rc + 32], cpu_fr[rb]); + tcg_gen_mov_i64(cpu_fr[rc], cpu_fr[ra]); + break; + case 0x2F: + /* VINSECTLB */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + va = tcg_const_i64(ra); + vb = tcg_const_i64(rb); + vd = tcg_const_i64(rc); + gen_helper_vinsectlb(cpu_env, va, vb, vd); + tcg_temp_free(va); + tcg_temp_free(vb); + tcg_temp_free(vd); + break; + case 0x30: + /* VSHFQ */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + va = tcg_const_i64(ra); + vb = tcg_const_i64(rb); + vc = tcg_const_i64(rd); + vd = tcg_const_i64(rc); + gen_helper_vshfq(cpu_env, va, vb, vc, vd); + tcg_temp_free(va); + tcg_temp_free(vb); + tcg_temp_free(vc); + tcg_temp_free(vd); + break; + case 0x31: + /* VSHFQB */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + va = tcg_const_i64(ra); + vb = tcg_const_i64(rb); + vd = tcg_const_i64(rc); + gen_helper_vshfqb(cpu_env, va, vb, vd); + tcg_temp_free(va); + tcg_temp_free(vb); + tcg_temp_free(vd); + break; + case 0x32: + /* VCPYB */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmp64 = tcg_temp_new(); + tcg_gen_andi_i64(cpu_fr[rc], cpu_fr[ra], 0xffUL); + tcg_gen_shli_i64(tmp64, cpu_fr[rc], 8); + tcg_gen_or_i64(cpu_fr[rc], tmp64, cpu_fr[rc]); + tcg_gen_shli_i64(tmp64, cpu_fr[rc], 16); + tcg_gen_or_i64(cpu_fr[rc], tmp64, cpu_fr[rc]); + tcg_gen_shli_i64(tmp64, cpu_fr[rc], 32); + tcg_gen_or_i64(cpu_fr[rc], tmp64, cpu_fr[rc]); + 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]); + tcg_temp_free(tmp64); + break; + case 0x33: + /* VCPYH */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmp64 = tcg_temp_new(); + tcg_gen_andi_i64(cpu_fr[rc], cpu_fr[ra], 0xffffUL); + tcg_gen_shli_i64(tmp64, cpu_fr[rc], 16); + tcg_gen_or_i64(cpu_fr[rc], tmp64, cpu_fr[rc]); + tcg_gen_shli_i64(tmp64, cpu_fr[rc], 32); + tcg_gen_or_i64(cpu_fr[rc], tmp64, cpu_fr[rc]); + 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]); + tcg_temp_free(tmp64); + break; + case 0x34: + /* VSM3R */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + va = tcg_const_i64(ra); + vb = tcg_const_i64(rb); + vc = tcg_const_i64(rd); + vd = tcg_const_i64(rc); + gen_helper_vsm3r(cpu_env, va, vb, vc, vd); + tcg_temp_free(va); + tcg_temp_free(vb); + tcg_temp_free(vc); + tcg_temp_free(vd); + break; + case 0x35: + /* VFCVTSH */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + va = tcg_const_i64(ra); + vb = tcg_const_i64(rb); + vc = tcg_const_i64(rd); + vd = tcg_const_i64(rc); + gen_helper_vfcvtsh(cpu_env, va, vb, vc, vd); + tcg_temp_free(va); + tcg_temp_free(vb); + tcg_temp_free(vc); + tcg_temp_free(vd); + break; + case 0x36: + /* VFCVTHS */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + va = tcg_const_i64(ra); + vb = tcg_const_i64(rb); + vc = tcg_const_i64(rd); + vd = tcg_const_i64(rc); + gen_helper_vfcvths(cpu_env, va, vb, vc, vd); + tcg_temp_free(va); + tcg_temp_free(vb); + tcg_temp_free(vc); + 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 0x1D: + /* LBR */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + ret = gen_bdirect(ctx, 31, disp26); + break; + case 0x1E: + /* LD/ST CORE4 */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + switch (fn4) { + case 0x0: + /* LDBU_A */ + vb = load_gir(ctx, rb); + gen_load_mem(ctx, &tcg_gen_qemu_ld8u, ra, rb, 0, 0, 0); + tcg_gen_addi_i64(vb, vb, disp12); + break; + case 0x1: + /* LDHU_A */ + vb = load_gir(ctx, rb); + gen_load_mem(ctx, &tcg_gen_qemu_ld16u, ra, rb, 0, 0, 0); + tcg_gen_addi_i64(vb, vb, disp12); + break; + case 0x2: + /* LDW_A */ + vb = load_gir(ctx, rb); + /* SEXT to ra */ + gen_load_mem(ctx, &tcg_gen_qemu_ld32s, ra, rb, 0, 0, 0); + tcg_gen_addi_i64(vb, vb, disp12); + break; + case 0x3: + /* LDL_A */ + vb = load_gir(ctx, rb); + gen_load_mem(ctx, &tcg_gen_qemu_ld64, ra, rb, 0, 0, 0); + tcg_gen_addi_i64(vb, vb, disp12); + break; + case 0x4: + /* FLDS_A */ + vb = load_gir(ctx, rb); + gen_load_mem(ctx, &gen_qemu_flds, ra, rb, 0, 1, 0); + tcg_gen_addi_i64(vb, vb, disp12); + break; + case 0x5: + /* FLDD_A */ + vb = load_gir(ctx, rb); + gen_load_mem(ctx, &tcg_gen_qemu_ld64, ra, rb, 0, 1, 0); + tcg_gen_addi_i64(vb, vb, disp12); + break; + case 0x6: + /* STBU_A */ + vb = load_gir(ctx, rb); + gen_store_mem(ctx, &tcg_gen_qemu_st8, ra, rb, 0, 0, 0); + tcg_gen_addi_i64(vb, vb, disp12); + break; + case 0x7: + /* STHU_A */ + vb = load_gir(ctx, rb); + gen_store_mem(ctx, &tcg_gen_qemu_st16, ra, rb, 0, 0, 0); + tcg_gen_addi_i64(vb, vb, disp12); + break; + case 0x8: + /* STW_A */ + vb = load_gir(ctx, rb); + gen_store_mem(ctx, &tcg_gen_qemu_st32, ra, rb, 0, 0, 0); + tcg_gen_addi_i64(vb, vb, disp12); + break; + case 0x9: + /* STL_A */ + vb = load_gir(ctx, rb); + gen_store_mem(ctx, &tcg_gen_qemu_st64, ra, rb, 0, 0, 0); + tcg_gen_addi_i64(vb, vb, disp12); + break; + case 0xA: + /* FSTS_A */ + vb = load_gir(ctx, rb); + gen_store_mem(ctx, &gen_qemu_fsts, ra, rb, 0, 1, 0); + tcg_gen_addi_i64(vb, vb, disp12); + break; + case 0xB: + /* FSTD_A */ + vb = load_gir(ctx, rb); + gen_store_mem(ctx, &tcg_gen_qemu_st64, ra, rb, 0, 1, + 0); + tcg_gen_addi_i64(vb, vb, disp12); + break; + case 0xE: + /* TODO: DPFHR */ + break; + case 0xF: + /* TODO: DPFHW */ + break; + default: + printf("ILLEGAL BELOW OPC[%x] func[%08x]\n", opc, fn4); + ret = gen_invalid(ctx); + } + 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, ~0x7UL); + 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, ~0x7UL); + } else { + gen_load_mem(ctx, &gen_qemu_pri_ldw, ra, rb, disp12, 0, ~0x3UL); + } +#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, ~0x7UL); + 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, ~0x7UL); + } else { + gen_store_mem(ctx, &gen_qemu_pri_stw, ra, rb, disp12, 0, ~0x3UL); + } +#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); +} + +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) { + 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->core_id, + 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 0000000000000000000000000000000000000000..e93df0815eb6c746a6dd205c7313c5f62e849ead --- /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 0000000000000000000000000000000000000000..71fdfdcbef6b95e6f1f4abca4f2396a9c73d0692 --- /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 0000000000000000000000000000000000000000..47edb3837bc8df5bec6a8e98df1587eaedb1002d --- /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 0000000000000000000000000000000000000000..097a31329417b8f3c5d4f50af03cd01cb9000d1f --- /dev/null +++ b/tcg/sw64/tcg-target.c.inc @@ -0,0 +1,2463 @@ +/* + * 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); + +#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_TMP3=TCG_REG_X24 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_REG_TMP3 TCG_REG_X24 +#define TCG_FLOAT_TMP TCG_REG_F10 +#define TCG_FLOAT_TMP2 TCG_REG_F11 + +#define REG0(I) (const_args[I] ? TCG_REG_ZERO : (TCGReg)args[I]) +#define tcg_out_insn_jump tcg_out_insn_ldst +#define tcg_out_insn_bitReg tcg_out_insn_simpleReg +#define zeroExt 0 +#define sigExt 1 +#define noPara 0//represent this parament of function isnot needed. + +#ifndef CONFIG_SOFTMMU +#define USE_GUEST_BASE (guest_base != 0 || TARGET_LONG_BITS == 32) +#define TCG_REG_GUEST_BASE TCG_REG_X14 +#endif + +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; +} + +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(); + } +} + +/* +* 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 +#define ALL_QLDST_REGS \ + (ALL_GENERAL_REGS & ~((1 << TCG_REG_X0) | (1 << TCG_REG_X1) | \ + (1 << TCG_REG_X2) | (1 << TCG_REG_X3))) +#else +#define ALL_QLDST_REGS ALL_GENERAL_REGS +#endif + +/* sw test if a constant matches the constraint */ +static bool tcg_target_const_match(tcg_target_long 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; +} + +#define OPC_OP(x) (((uint32_t)(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_EXTLB =(OPC_OP(0x10) | OPC_FUNC(0x50)), + OPC_EXTLH =(OPC_OP(0x10) | OPC_FUNC(0x51)), + OPC_EXTLW =(OPC_OP(0x10) | OPC_FUNC(0x52)), + OPC_EXTLL =(OPC_OP(0x10) | OPC_FUNC(0x53)), + OPC_EXTHB =(OPC_OP(0x10) | OPC_FUNC(0x54)), + OPC_EXTHH =(OPC_OP(0x10) | OPC_FUNC(0x55)), + OPC_EXTHW =(OPC_OP(0x10) | OPC_FUNC(0x56)), + OPC_EXTHL =(OPC_OP(0x10) | OPC_FUNC(0x57)), + OPC_EXTLB_I =(OPC_OP(0x12) | OPC_FUNC(0x50)), + OPC_EXTLH_I =(OPC_OP(0x12) | OPC_FUNC(0x51)), + OPC_EXTLW_I =(OPC_OP(0x12) | OPC_FUNC(0x52)), + OPC_EXTLL_I =(OPC_OP(0x12) | OPC_FUNC(0x53)), + OPC_EXTHB_I =(OPC_OP(0x12) | OPC_FUNC(0x54)), + OPC_EXTHH_I =(OPC_OP(0x12) | OPC_FUNC(0x55)), + OPC_EXTHW_I =(OPC_OP(0x12) | OPC_FUNC(0x56)), + OPC_EXTHL_I =(OPC_OP(0x12) | OPC_FUNC(0x57)), + + OPC_MASKLB =(OPC_OP(0x10) | OPC_FUNC(0x60)), + OPC_MASKLH =(OPC_OP(0x10) | OPC_FUNC(0x61)), + OPC_MASKLW =(OPC_OP(0x10) | OPC_FUNC(0x62)), + OPC_MASKLL =(OPC_OP(0x10) | OPC_FUNC(0x63)), + OPC_MASKHB =(OPC_OP(0x10) | OPC_FUNC(0x64)), + OPC_MASKHH =(OPC_OP(0x10) | OPC_FUNC(0x65)), + OPC_MASKHW =(OPC_OP(0x10) | OPC_FUNC(0x66)), + OPC_MASKHL =(OPC_OP(0x10) | OPC_FUNC(0x67)), + OPC_MASKLB_I =(OPC_OP(0x12) | OPC_FUNC(0x60)), + OPC_MASKLH_I =(OPC_OP(0x12) | OPC_FUNC(0x61)), + OPC_MASKLW_I =(OPC_OP(0x12) | OPC_FUNC(0x62)), + OPC_MASKLL_I =(OPC_OP(0x12) | OPC_FUNC(0x63)), + OPC_MASKHB_I =(OPC_OP(0x12) | OPC_FUNC(0x64)), + OPC_MASKHH_I =(OPC_OP(0x12) | OPC_FUNC(0x65)), + OPC_MASKHW_I =(OPC_OP(0x12) | OPC_FUNC(0x66)), + OPC_MASKHL_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 inline uint32_t tcg_in32(TCGContext *s) +{ + uint32_t v = *(uint32_t *)s->code_ptr; + return v; +} + +/* + * 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_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_TMP3, imm64); + tcg_out_insn_simpleReg(s, insn_Reg, rd, rn, TCG_REG_TMP3); + } +} + +static void tcg_out_insn_simpleImm(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_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 void tcg_out_insn_complexImm(TCGContext *s, SW_64Insn insn, TCGReg cond, TCGReg rd, intptr_t imm8, TCGReg rm) +{ + tcg_out32(s, insn | (cond & 0x1f) << 21 | (imm8 & 0xff) << 13 | (rm & 0x1f) << 5 | (rd & 0x1f)); +} + +static void tcg_out_movr(TCGContext *s, TCGType ext, TCGReg rd, TCGReg rn) +{ + if (ext == TCG_TYPE_I64) { + tcg_out_insn_simpleReg(s, OPC_BIS, rd, rn, TCG_REG_ZERO); + } else { + tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, rd, rn, 0xf); + } +} + +static void tcg_out_movi(TCGContext *s, TCGType type, TCGReg rd, tcg_target_long orig) +{ + tcg_target_long l0=0, l1=0, l2=0, l3=0, extra=0; + tcg_target_long val = orig; + TCGReg rs = TCG_REG_ZERO; + + if (TCG_TARGET_REG_BITS == 64 && type == TCG_TYPE_I32) { + val = (int32_t)val;//val64bit + } + + if (orig == (int16_t)orig) { + tcg_out_insn_ldst(s, OPC_LDI, rd, TCG_REG_ZERO, (int16_t)orig); + return; + } + + if (orig == (uint8_t)orig) { + tcg_out_insn_simpleImm(s, OPC_BIS_I, rd, TCG_REG_ZERO, (uint8_t)orig); + return; + } + + 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); + if (type == TCG_TYPE_I32) { + tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, rd, rd, 0xf); + } +} + +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) { + tcg_debug_assert(0); + break; + } else if (arg < 32) { + tcg_debug_assert(0); + break; + } + /* FALLTHRU */ + case TCG_TYPE_V64: + case TCG_TYPE_V128: + tcg_debug_assert(0); + break; + default: + g_assert_not_reached(); + } + return true; +} + +static inline void tcg_out_sxt(TCGContext *s, TCGType ext, MemOp s_bits, + TCGReg rd, TCGReg rn) +{ + /* + * Using ALIASes SXTB, SXTH, SXTW, of SBFM Xd, Xn, #0, #7|15|31 + * int bits = (8 << s_bits) - 1; + * tcg_out_sbfm(s, ext, rd, rn, 0, bits); + */ + switch (s_bits) { + case MO_8: + tcg_out_insn_simpleReg(s, OPC_SEXTB, rd, TCG_REG_ZERO, rn); + break; + case MO_16: + tcg_out_insn_simpleReg(s, OPC_SEXTH, rd, TCG_REG_ZERO, rn); + break; + case MO_32: + tcg_out_insn_simpleReg(s, OPC_ADDW, rd, rn, TCG_REG_ZERO); + break; + default: + tcg_debug_assert(0); + break; + } + if (ext == TCG_TYPE_I32) { + tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, rd, rd, 0xf); + } +} + +/* + * counting heading/tailing zero numbers + */ +static void tcg_out_ctz64(TCGContext *s, SW_64Insn opc, TCGReg rd, TCGReg rn, TCGArg b, bool const_b) +{ + if (const_b && b == 64) { + if (opc == OPC_CTLZ) { + tcg_out_insn_simpleReg(s, OPC_CTLZ, rd, TCG_REG_ZERO, rn); + } else { + tcg_out_insn_simpleReg(s, OPC_CTTZ, rd, TCG_REG_ZERO, rn); + } + } else { + if (opc == OPC_CTLZ) { + tcg_out_insn_simpleReg(s, OPC_CTLZ, TCG_REG_TMP2, TCG_REG_ZERO, rn); + } else { + tcg_out_insn_simpleReg(s, OPC_CTTZ, TCG_REG_TMP2, TCG_REG_ZERO, rn); + } + if (const_b) { + if (b == -1) { + tcg_out_insn_bitReg(s, OPC_ORNOT, rd, TCG_REG_ZERO, TCG_REG_ZERO); + tcg_out_insn_complexReg(s, OPC_SELNE, rn, rd, TCG_REG_TMP2, rd); + } else if (b == 0) { + tcg_out_insn_complexReg(s, OPC_SELNE, rn, rd, TCG_REG_TMP2, TCG_REG_ZERO); + } else { + tcg_out_movi(s, TCG_TYPE_I64, rd, b); + tcg_out_insn_complexReg(s, OPC_SELNE, rn, rd, TCG_REG_TMP2, rd); + } + } else { + tcg_out_insn_complexReg(s, OPC_SELNE, rn, rd, TCG_REG_TMP2, b); + } + } +} + +/* + * counting heading/tailing zero numbers + */ +static void tcg_out_ctz32(TCGContext *s, SW_64Insn opc, TCGReg rd, TCGReg rn, TCGArg b, bool const_b) +{ + tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, TCG_REG_TMP, rn, 0xf); + + if (const_b && b == 32) { + if (opc == OPC_CTLZ) { + tcg_out_insn_simpleReg(s, OPC_CTLZ, rd, TCG_REG_ZERO, TCG_REG_TMP); + tcg_out_insn_simpleImm(s, OPC_SUBW_I, rd, rd, 32); + } else { + tcg_out_insn_simpleReg(s, OPC_CTTZ, rd, TCG_REG_ZERO, TCG_REG_TMP); + tcg_out_insn_complexImm(s, OPC_SELEQ_I, TCG_REG_TMP, rd, 32, rd); + } + } else { + if (opc == OPC_CTLZ) { + tcg_out_insn_simpleReg(s, OPC_CTLZ, TCG_REG_TMP2, TCG_REG_ZERO, TCG_REG_TMP); + tcg_out_insn_simpleImm(s, OPC_SUBW_I, TCG_REG_TMP2, TCG_REG_TMP2, 32); + } else { + tcg_out_insn_simpleReg(s, OPC_CTTZ, TCG_REG_TMP2, TCG_REG_ZERO, TCG_REG_TMP); + tcg_out_insn_complexImm(s, OPC_SELEQ_I, TCG_REG_TMP, TCG_REG_TMP2, 32, TCG_REG_TMP2); + } + if (const_b) { + if (b == -1) { + tcg_out_insn_bitReg(s, OPC_ORNOT, rd, TCG_REG_ZERO, TCG_REG_ZERO); + tcg_out_insn_complexReg(s, OPC_SELNE, TCG_REG_TMP, rd, TCG_REG_TMP2, rd); + } else if (b == 0) { + tcg_out_insn_complexReg(s, OPC_SELNE, TCG_REG_TMP, rd, TCG_REG_TMP2, TCG_REG_ZERO); + } else { + tcg_out_movi(s, TCG_TYPE_I32, rd, b); + tcg_out_insn_complexReg(s, OPC_SELNE, TCG_REG_TMP, rd, TCG_REG_TMP2, rd); + } + } else { + tcg_out_insn_complexReg(s, OPC_SELNE, TCG_REG_TMP, rd, TCG_REG_TMP2, b); + tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, rd, rd, 0xf); + } + } +} + +/* + * memory protect for order of (ld and st) + */ +static void tcg_out_mb(TCGContext *s) +{ + tcg_out32(s, OPC_MEMB); +} + +static inline void tcg_out_bswap16(TCGContext *s, TCGType ext, TCGReg rd, TCGReg rn) +{ + tcg_out_insn_simpleImm(s, OPC_EXTLB_I, TCG_REG_TMP2, rn, 1); + + tcg_out_insn_simpleImm(s, OPC_EXTLB_I, TCG_REG_TMP, rn, 0); + tcg_out_insn_simpleImm(s, OPC_SLL_I, TCG_REG_TMP, TCG_REG_TMP, 8); + tcg_out_insn_bitReg(s, OPC_BIS, TCG_REG_TMP2, TCG_REG_TMP2, TCG_REG_TMP); + + tcg_out_insn_simpleImm(s, OPC_EXTLB_I, TCG_REG_TMP, rn, 3); + tcg_out_insn_simpleImm(s, OPC_SLL_I, TCG_REG_TMP, TCG_REG_TMP, 16); + tcg_out_insn_bitReg(s, OPC_BIS, TCG_REG_TMP2, TCG_REG_TMP2, TCG_REG_TMP); + + tcg_out_insn_simpleImm(s, OPC_EXTLB_I, TCG_REG_TMP, rn, 2); + tcg_out_insn_simpleImm(s, OPC_SLL_I, TCG_REG_TMP, TCG_REG_TMP, 24); + + if (ext == TCG_TYPE_I32) { + tcg_out_insn_bitReg(s, OPC_BIS, rd, TCG_REG_TMP2, TCG_REG_TMP); + } else { + tcg_out_insn_bitReg(s, OPC_BIS, TCG_REG_TMP2, TCG_REG_TMP2, TCG_REG_TMP); + + tcg_out_insn_simpleImm(s, OPC_EXTLB_I, TCG_REG_TMP, rn, 5); + tcg_out_insn_simpleImm(s, OPC_SLL_I, TCG_REG_TMP, TCG_REG_TMP, 32); + tcg_out_insn_bitReg(s, OPC_BIS, TCG_REG_TMP2, TCG_REG_TMP2, TCG_REG_TMP); + + tcg_out_insn_simpleImm(s, OPC_EXTLB_I, TCG_REG_TMP, rn, 4); + tcg_out_insn_simpleImm(s, OPC_SLL_I, TCG_REG_TMP, TCG_REG_TMP, 40); + tcg_out_insn_bitReg(s, OPC_BIS, TCG_REG_TMP2, TCG_REG_TMP2, TCG_REG_TMP); + + tcg_out_insn_simpleImm(s, OPC_EXTLB_I, TCG_REG_TMP, rn, 7); + tcg_out_insn_simpleImm(s, OPC_SLL_I, TCG_REG_TMP, TCG_REG_TMP, 48); + tcg_out_insn_bitReg(s, OPC_BIS, TCG_REG_TMP2, TCG_REG_TMP2, TCG_REG_TMP); + + tcg_out_insn_simpleImm(s, OPC_EXTLB_I, TCG_REG_TMP, rn, 6); + tcg_out_insn_simpleImm(s, OPC_SLL_I, TCG_REG_TMP, TCG_REG_TMP, 56); + tcg_out_insn_bitReg(s, OPC_BIS, rd, TCG_REG_TMP2, TCG_REG_TMP); + } +} + +static void tcg_out_bswap32(TCGContext *s, TCGType ext, TCGReg rd, TCGReg rn) +{ + tcg_out_insn_simpleImm(s, OPC_EXTLB_I, TCG_REG_TMP2, rn, 3); + + tcg_out_insn_simpleImm(s, OPC_EXTLB_I, TCG_REG_TMP, rn, 2); + tcg_out_insn_simpleImm(s, OPC_SLL_I, TCG_REG_TMP, TCG_REG_TMP, 8); + tcg_out_insn_bitReg(s, OPC_BIS, TCG_REG_TMP2, TCG_REG_TMP2, TCG_REG_TMP); + + tcg_out_insn_simpleImm(s, OPC_EXTLB_I, TCG_REG_TMP, rn, 1); + tcg_out_insn_simpleImm(s, OPC_SLL_I, TCG_REG_TMP, TCG_REG_TMP, 16); + tcg_out_insn_bitReg(s, OPC_BIS, TCG_REG_TMP2, TCG_REG_TMP2, TCG_REG_TMP); + + tcg_out_insn_simpleImm(s, OPC_EXTLB_I, TCG_REG_TMP, rn, 0); + tcg_out_insn_simpleImm(s, OPC_SLL_I, TCG_REG_TMP, TCG_REG_TMP, 24); + + if (ext == TCG_TYPE_I32) { + tcg_out_insn_bitReg(s, OPC_BIS, rd, TCG_REG_TMP2, TCG_REG_TMP); + } else { + tcg_out_insn_bitReg(s, OPC_BIS, TCG_REG_TMP2, TCG_REG_TMP2, TCG_REG_TMP); + + tcg_out_insn_simpleImm(s, OPC_EXTLB_I, TCG_REG_TMP, rn, 7); + tcg_out_insn_simpleImm(s, OPC_SLL_I, TCG_REG_TMP, TCG_REG_TMP, 32); + tcg_out_insn_bitReg(s, OPC_BIS, TCG_REG_TMP2, TCG_REG_TMP2, TCG_REG_TMP); + + tcg_out_insn_simpleImm(s, OPC_EXTLB_I, TCG_REG_TMP, rn, 6); + tcg_out_insn_simpleImm(s, OPC_SLL_I, TCG_REG_TMP, TCG_REG_TMP, 40); + tcg_out_insn_bitReg(s, OPC_BIS, TCG_REG_TMP2, TCG_REG_TMP2, TCG_REG_TMP); + + tcg_out_insn_simpleImm(s, OPC_EXTLB_I, TCG_REG_TMP, rn, 5); + tcg_out_insn_simpleImm(s, OPC_SLL_I, TCG_REG_TMP, TCG_REG_TMP, 48); + tcg_out_insn_bitReg(s, OPC_BIS, TCG_REG_TMP2, TCG_REG_TMP2, TCG_REG_TMP); + + tcg_out_insn_simpleImm(s, OPC_EXTLB_I, TCG_REG_TMP, rn, 4); + tcg_out_insn_simpleImm(s, OPC_SLL_I, TCG_REG_TMP, TCG_REG_TMP, 56); + tcg_out_insn_bitReg(s, OPC_BIS, rd, TCG_REG_TMP2, TCG_REG_TMP); + } +} + +static void tcg_out_bswap64(TCGContext *s, TCGType ext, TCGReg rd, TCGReg rn) +{ + tcg_out_insn_simpleImm(s, OPC_EXTLB_I, TCG_REG_TMP2, rn, 7); + + tcg_out_insn_simpleImm(s, OPC_EXTLB_I, TCG_REG_TMP, rn, 6); + tcg_out_insn_simpleImm(s, OPC_SLL_I, TCG_REG_TMP, TCG_REG_TMP, 8); + tcg_out_insn_bitReg(s, OPC_BIS, TCG_REG_TMP2, TCG_REG_TMP2, TCG_REG_TMP); + + tcg_out_insn_simpleImm(s, OPC_EXTLB_I, TCG_REG_TMP, rn, 5); + tcg_out_insn_simpleImm(s, OPC_SLL_I, TCG_REG_TMP, TCG_REG_TMP, 16); + tcg_out_insn_bitReg(s, OPC_BIS, TCG_REG_TMP2, TCG_REG_TMP2, TCG_REG_TMP); + + tcg_out_insn_simpleImm(s, OPC_EXTLB_I, TCG_REG_TMP, rn, 4); + tcg_out_insn_simpleImm(s, OPC_SLL_I, TCG_REG_TMP, TCG_REG_TMP, 24); + tcg_out_insn_bitReg(s, OPC_BIS, TCG_REG_TMP2, TCG_REG_TMP2, TCG_REG_TMP); + + tcg_out_insn_simpleImm(s, OPC_EXTLB_I, TCG_REG_TMP, rn, 3); + tcg_out_insn_simpleImm(s, OPC_SLL_I, TCG_REG_TMP, TCG_REG_TMP, 32); + tcg_out_insn_bitReg(s, OPC_BIS, TCG_REG_TMP2, TCG_REG_TMP2, TCG_REG_TMP); + + tcg_out_insn_simpleImm(s, OPC_EXTLB_I, TCG_REG_TMP, rn, 2); + tcg_out_insn_simpleImm(s, OPC_SLL_I, TCG_REG_TMP, TCG_REG_TMP, 40); + tcg_out_insn_bitReg(s, OPC_BIS, TCG_REG_TMP2, TCG_REG_TMP2, TCG_REG_TMP); + + tcg_out_insn_simpleImm(s, OPC_EXTLB_I, TCG_REG_TMP, rn, 1); + tcg_out_insn_simpleImm(s, OPC_SLL_I, TCG_REG_TMP, TCG_REG_TMP, 48); + tcg_out_insn_bitReg(s, OPC_BIS, TCG_REG_TMP2, TCG_REG_TMP2, TCG_REG_TMP); + + tcg_out_insn_simpleImm(s, OPC_EXTLB_I, TCG_REG_TMP, rn, 0); + tcg_out_insn_simpleImm(s, OPC_SLL_I, TCG_REG_TMP, TCG_REG_TMP, 56); + tcg_out_insn_bitReg(s, OPC_BIS, rd, TCG_REG_TMP2, TCG_REG_TMP); +} + +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_simpleImm(s, OPC_SRL_I, TCG_REG_TMP, TCG_REG_TMP, 64 - len); + tcg_out_insn_simpleImm(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_simpleImm(s, OPC_SRL_I, rd, rd, lsb); +} + +static void tcg_out_dep(TCGContext *s, TCGType ext, TCGReg rd, TCGReg rn, int lsb, int len) +{ + tcg_out_insn_bitReg(s, OPC_ORNOT, TCG_REG_TMP, TCG_REG_ZERO, TCG_REG_ZERO); + tcg_out_insn_simpleImm(s, OPC_SRL_I, TCG_REG_TMP, TCG_REG_TMP, 64 - len); + tcg_out_insn_simpleImm(s, OPC_SLL_I, TCG_REG_TMP, TCG_REG_TMP, lsb); + + /* TCG_REG_TMP2 = rn[msb,lsb] */ + tcg_out_insn_simpleImm(s, OPC_SLL_I, TCG_REG_TMP2, rn, 64-len); + tcg_out_insn_simpleImm(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); + + if (ext == TCG_TYPE_I32) { + tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, rd, rd, 0xf); + } +} + +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_simpleImm(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_simpleImm(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); +} + +static void tcg_out_sar(TCGContext *s, TCGType ext, TCGReg rd, TCGReg rn, TCGArg a2, bool c2) +{ + unsigned int bits = ext ? 64 : 32; + unsigned int max = bits - 1; + if (ext == TCG_TYPE_I32) { + tcg_out_insn_simpleReg(s, OPC_ADDW, TCG_REG_TMP, rn, TCG_REG_ZERO); + + if (c2) { + tcg_out_insn_simpleImm(s, OPC_SRA_I, rd, TCG_REG_TMP, a2 & max); + } else { + tcg_out_insn_bitReg(s, OPC_SRA, rd, TCG_REG_TMP, a2); + } + tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, rd, rd, 0xf); + } else { + if (c2) { + tcg_out_insn_simpleImm(s, OPC_SRA_I, rd, rn, a2 & max); + } else { + tcg_out_insn_bitReg(s, OPC_SRA, rd, rn, a2); + } + } +} + +/* + * 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) +{ + if (offset != sextract64(offset, 0, 15)) { + tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_TMP2, offset); + tcg_out_insn_simpleReg(s, OPC_ADDL, TCG_REG_TMP2, TCG_REG_TMP2, rn); + tcg_out_insn_ldst(s, insn, rd, TCG_REG_TMP2, 0); + } else { + tcg_out_insn_ldst(s, insn, rd, rn, offset); + } + + switch (insn) { + case OPC_LDBU: + if (sign) + tcg_out_insn_simpleReg(s, OPC_SEXTB, rd, TCG_REG_ZERO, rd); + break; + case OPC_LDHU: + if (sign) + tcg_out_insn_simpleReg(s, OPC_SEXTH, rd, TCG_REG_ZERO, rd); + break; + case OPC_LDW: + if (!sign) + tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, rd, rd, 0xf); + break; + default: + break; + } +} + +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, zeroExt); + break; + case TCG_TYPE_I64: + tcg_out_ldst(s, OPC_LDL, rd, rn, ofs, sigExt); + break; + case TCG_TYPE_V64: + case TCG_TYPE_V128: + tcg_debug_assert(0); + 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_ldst(s, OPC_STW, rd, rn, ofs, noPara); + break; + case TCG_TYPE_I64: + tcg_out_ldst(s, OPC_STL, rd, rn, ofs, noPara); + break; + case TCG_TYPE_V64: + case TCG_TYPE_V128: + tcg_debug_assert(0); + break; + default: + g_assert_not_reached(); + } +} + +static void tcg_out_cond_cmp(TCGContext *s, TCGType ext, TCGCond cond, TCGReg ret, TCGArg a, tcg_target_long b, bool const_b) +{ + if (const_b && (b < 0 || b > 0xff)) { + tcg_out_movi(s, ext, TCG_REG_TMP2, b); + b = TCG_REG_TMP2; + const_b = 0; + } + + if (ext == TCG_TYPE_I32) { + tcg_out_insn_simpleReg(s, OPC_ADDW, a, a, TCG_REG_ZERO); + if (!const_b) { + tcg_out_insn_simpleReg(s, OPC_ADDW, b, b, TCG_REG_ZERO); + } else { + b = (int32_t)b; + } + } + + if (const_b) { + switch (cond) { + case TCG_COND_EQ: + case TCG_COND_NE: + tcg_out_insn_simpleImm(s, OPC_CMPEQ_I, ret, a, b); + break; + case TCG_COND_LT: + case TCG_COND_GE: + tcg_out_insn_simpleImm(s, OPC_CMPLT_I, ret, a, b); + break; + case TCG_COND_LE: + case TCG_COND_GT: + tcg_out_insn_simpleImm(s, OPC_CMPLE_I, ret, a, b); + break; + case TCG_COND_LTU: + case TCG_COND_GEU: + tcg_out_insn_simpleImm(s, OPC_CMPULT_I, ret, a, b); + break; + case TCG_COND_LEU: + case TCG_COND_GTU: + tcg_out_insn_simpleImm(s, OPC_CMPULE_I, ret, a, b); + break; + default: + tcg_debug_assert(0); + break; + } + } else { + switch (cond) { + 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; + default: + tcg_debug_assert(0); + break; + } + } + + if (ext == TCG_TYPE_I32) { + tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, a, a, 0xf); + if (!const_b) { + tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, b, b, 0xf); + } + } + + switch (cond) { + case TCG_COND_NE: + case TCG_COND_GE: + case TCG_COND_GT: + case TCG_COND_GEU: + case TCG_COND_GTU: + tcg_out_insn_simpleImm(s, OPC_XOR_I, ret, ret, 0x1); + break; + case TCG_COND_ALWAYS: + case TCG_COND_NEVER: + tcg_debug_assert(0); + break; + default: + break; + } +} + +/* + * 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, tcg_target_long 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; + if (ext == TCG_TYPE_I32) { + tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, TCG_REG_TMP, a, 0xf); + } else { + tcg_out_insn_bitReg(s, OPC_BIS, TCG_REG_TMP, a, TCG_REG_ZERO); + } + } else { + need_cmp = true; + tcg_out_cond_cmp(s, ext, 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;//luo br $31, 0, do not jump here! + } else { + offset = tcg_pcrel_diff(s, l->u.value_ptr); + offset = offset - 4; + 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); + } else if (cond == TCG_COND_EQ) { + tcg_out_insn_br(s, OPC_BEQ, TCG_REG_TMP, offset); + } else { + tcg_out_insn_br(s, OPC_BNE, TCG_REG_TMP, offset); + } +} + +static void tcg_out_setcond(TCGContext *s, TCGType ext, TCGCond cond, TCGReg ret, + TCGReg a, tcg_target_long b, bool const_b) +{ + 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, ext, cond, ret, a, b, const_b); + break; + default: + tcg_abort(); + break; + } +} + +static void tcg_out_movcond(TCGContext *s, TCGType ext, TCGCond cond, TCGReg ret, + TCGReg a1, tcg_target_long a2, bool const_b, TCGReg v1, TCGReg v2) +{ + tcg_out_cond_cmp(s, ext, cond, TCG_REG_TMP, a1, a2, const_b); + tcg_out_insn_complexReg(s, OPC_SELLBS, TCG_REG_TMP, ret, v1, v2); +} + +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 (ext == TCG_TYPE_I64) { + if (imm64 >= 0) { + if (0 <=imm64 && imm64 <= 255) { + /* we use tcg_out_insn_simpleImm because imm64 is between 0~255 */ + tcg_out_insn_simpleImm(s, OPC_ADDL_I, rd, rn, imm64); + } else { + tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_TMP, imm64); + tcg_out_insn_simpleReg(s, OPC_ADDL, rd, rn, TCG_REG_TMP); + } + } else { + if (0 < -imm64 && -imm64 <= 255) { + /* we use tcg_out_insn_simpleImm because -imm64 is between 0~255 */ + tcg_out_insn_simpleImm(s, OPC_SUBL_I, rd, rn, -imm64); + } else { + tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_TMP, -imm64); + tcg_out_insn_simpleReg(s, OPC_SUBL, rd, rn, TCG_REG_TMP); + } + } + } else { + if (imm64 >= 0) { + if (0 <=imm64 && imm64 <= 255) { + /* we use tcg_out_insn_simpleImm because imm64 is between 0~255 */ + tcg_out_insn_simpleImm(s, OPC_ADDW_I, rd, rn, imm64); + tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, rd, rd, 0xf); + } else { + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_TMP, imm64); + tcg_out_insn_simpleReg(s, OPC_ADDW, rd, rn, TCG_REG_TMP); + tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, rd, rd, 0xf); + } + } else { + if (0 < -imm64 && -imm64 <= 255) { + /* we use tcg_out_insn_simpleImm because -imm64 is between 0~255 */ + tcg_out_insn_simpleImm(s, OPC_SUBW_I, rd, rn, -imm64); + tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, rd, rd, 0xf); + } else { + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_TMP, -imm64); + tcg_out_insn_simpleReg(s, OPC_SUBW, rd, rn, TCG_REG_TMP); + tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, rd, rd, 0xf); + } + } + } +} + +static void tcg_out_goto(TCGContext *s, const tcg_insn_unit *target) +{ + ptrdiff_t offset = (tcg_pcrel_diff(s, target) - 4) >> 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) - 4) >> 2; + if (offset == sextract64(offset, 0 ,21)) { + 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, noPara); + } +} + +static void tcg_out_call(TCGContext *s, const tcg_insn_unit *target) +{ + ptrdiff_t offset = (tcg_pcrel_diff(s, target) - 4) >> 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, noPara); + } +} + +static void modify_direct_addr(uintptr_t addr, uintptr_t jmp_rw, uintptr_t jmp_rx) +{ + tcg_target_long l0=0, l1=0; + tcg_target_long val = addr; + TCGReg rs = TCG_REG_ZERO; + TCGReg rd = TCG_REG_TMP; + tcg_insn_unit i_nop=0, i1=0, i2=0; + uint64_t pair = 0; + i_nop = OPC_NOP; + uintptr_t jmp = jmp_rw; + + l0 = (int16_t)val; + val = (val - l0) >> 16; + l1 = (int16_t)val; + if (l1) { + i1 = OPC_LDIH | (rd & 0x1f) << 21 | (rs & 0x1f) << 16 | (l1 & 0xffff); + } else { + i1 = i_nop; + } + i2 = OPC_LDI | (rd & 0x1f) << 21 | (rs & 0x1f) << 16 | (l0 & 0xffff); + pair = (uint64_t)i1 << 32 | i2; + qatomic_set((uint64_t *)jmp, pair); + flush_idcache_range(jmp_rx, jmp_rw, 8); +} + +void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_rx, uintptr_t jmp_rw, uintptr_t addr) +{ + tcg_insn_unit i1, i2; + uint64_t pair; + + ptrdiff_t offset = addr - jmp_rx -4; + + if (offset == sextract64(offset, 0, 21)) { + i1 = OPC_BR | (TCG_REG_ZERO & 0x1f) << 21| ((offset >> 2) & 0x1fffff); + i2 = OPC_NOP; + pair = (uint64_t)i2 << 32 | i1; + qatomic_set((uint64_t *)jmp_rw, pair); + flush_idcache_range(jmp_rx, jmp_rw, 8); + } else if (offset == sextract64(offset, 0, 32)) { + modify_direct_addr(addr, jmp_rw, jmp_rx); + } else { + tcg_debug_assert("tb_target"); + } +} + +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); + } +} + +/* + * result: 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_simpleImm(s, OPC_SLL_I, TCG_REG_TMP, rn, bits - (m & max)); + tcg_out_insn_simpleImm(s, OPC_SRL_I, TCG_REG_TMP2, rm, (m & max)); + tcg_out_insn_bitReg(s, OPC_BIS, rd, TCG_REG_TMP, TCG_REG_TMP2); +} + +static inline void tcg_out_rotr_Imm(TCGContext *s, TCGType ext, TCGReg rd, TCGReg rn, unsigned int m) +{ + unsigned int bits = ext ? 64 : 32; + unsigned int max = bits - 1; + if (ext == TCG_TYPE_I64) { + tcg_out_insn_simpleImm(s, OPC_SLL_I, TCG_REG_TMP, rn, bits - (m & max)); + tcg_out_insn_simpleImm(s, OPC_SRL_I, TCG_REG_TMP2, rn, (m & max)); + tcg_out_insn_bitReg(s, OPC_BIS, rd, TCG_REG_TMP, TCG_REG_TMP2); + } else { + tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, rd, rn, 0xf); + tcg_out_insn_simpleImm(s, OPC_SLL_I, TCG_REG_TMP, rd, bits - (m & max)); + tcg_out_insn_simpleImm(s, OPC_SRL_I, TCG_REG_TMP2, rd, (m & max)); + tcg_out_insn_bitReg(s, OPC_BIS, rd, TCG_REG_TMP, TCG_REG_TMP2); + tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, rd, rd, 0xf); + } +} + +static inline void tcg_out_rotr_Reg(TCGContext *s, TCGType ext, TCGReg rd, TCGReg rn, TCGReg rm) +{ + unsigned int bits = ext ? 64 : 32; + tcg_out_insn_simpleImm(s, OPC_SUBL_I, TCG_REG_TMP, rm, bits); + tcg_out_insn_bitReg(s, OPC_SUBL, TCG_REG_TMP, TCG_REG_ZERO, TCG_REG_TMP); + + if (ext == TCG_TYPE_I64) { + tcg_out_insn_bitReg(s, OPC_SLL, TCG_REG_TMP2, rn, TCG_REG_TMP); + tcg_out_insn_bitReg(s, OPC_SRL, TCG_REG_TMP, rn, rm); + tcg_out_insn_bitReg(s, OPC_BIS, rd, TCG_REG_TMP, TCG_REG_TMP2); + } else { + tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, rd, rn, 0xf); + tcg_out_insn_bitReg(s, OPC_SLL, TCG_REG_TMP2, rd, TCG_REG_TMP); + tcg_out_insn_bitReg(s, OPC_SRL, TCG_REG_TMP, rd, rm); + tcg_out_insn_bitReg(s, OPC_BIS, rd, TCG_REG_TMP, TCG_REG_TMP2); + tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, rd, rd, 0xf); + } +} + +static inline void tcg_out_rotl_Imm(TCGContext *s, TCGType ext, TCGReg rd, TCGReg rn, unsigned int m) +{ + unsigned int bits = ext ? 64 : 32; + unsigned int max = bits - 1; + + if (ext == TCG_TYPE_I64) { + tcg_out_insn_simpleImm(s, OPC_SRL_I, TCG_REG_TMP, rn, bits -(m & max)); + tcg_out_insn_simpleImm(s, OPC_SLL_I, TCG_REG_TMP2, rn, (m & max)); + tcg_out_insn_bitReg(s, OPC_BIS, rd, TCG_REG_TMP, TCG_REG_TMP2); + } else { + tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, rd, rn, 0xf); + tcg_out_insn_simpleImm(s, OPC_SRL_I, TCG_REG_TMP, rd, bits -(m & max)); + tcg_out_insn_simpleImm(s, OPC_SLL_I, TCG_REG_TMP2, rd, (m & max)); + tcg_out_insn_bitReg(s, OPC_BIS, rd, TCG_REG_TMP, TCG_REG_TMP2); + tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, rd, rd, 0xf); + } +} + +static inline void tcg_out_rotl_Reg(TCGContext *s, TCGType ext, TCGReg rd, TCGReg rn, TCGReg rm) +{ + unsigned int bits = ext ? 64 : 32; + tcg_out_insn_simpleImm(s, OPC_SUBL_I, TCG_REG_TMP, rm, bits); + tcg_out_insn_bitReg(s, OPC_SUBL, TCG_REG_TMP, TCG_REG_ZERO, TCG_REG_TMP); + + if (ext == TCG_TYPE_I64) { + tcg_out_insn_bitReg(s, OPC_SRL, TCG_REG_TMP2, rn, TCG_REG_TMP); + tcg_out_insn_bitReg(s, OPC_SLL, TCG_REG_TMP, rn, rm); + tcg_out_insn_bitReg(s, OPC_BIS, rd, TCG_REG_TMP, TCG_REG_TMP2); + } else { + tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, rd, rn, 0xf); + tcg_out_insn_bitReg(s, OPC_SRL, TCG_REG_TMP2, rd, TCG_REG_TMP); + tcg_out_insn_bitReg(s, OPC_SLL, TCG_REG_TMP, rd, rm); + tcg_out_insn_bitReg(s, OPC_BIS, rd, TCG_REG_TMP, TCG_REG_TMP2); + tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, rd, rd, 0xf); + } +} + +#ifdef CONFIG_SOFTMMU +#include "../tcg-ldst.c.inc" + +static void * const qemu_ld_helpers[(MO_SIZE | MO_BSWAP) + 1] = { + [MO_UB] = helper_ret_ldub_mmu, + [MO_LEUW] = helper_le_lduw_mmu, + [MO_LEUL] = helper_le_ldul_mmu, + [MO_LEQ] = helper_le_ldq_mmu, + [MO_BEUW] = helper_be_lduw_mmu, + [MO_BEUL] = helper_be_ldul_mmu, + [MO_BEQ] = helper_be_ldq_mmu, +}; + +static void * const qemu_st_helpers[(MO_SIZE | MO_BSWAP) + 1] = { + [MO_UB] = helper_ret_stb_mmu, + [MO_LEUW] = helper_le_stw_mmu, + [MO_LEUL] = helper_le_stl_mmu, + [MO_LEQ] = helper_le_stq_mmu, + [MO_BEUW] = helper_be_stw_mmu, + [MO_BEUL] = helper_be_stl_mmu, + [MO_BEQ] = helper_be_stq_mmu, +}; + +static inline void tcg_out_adr(TCGContext *s, TCGReg rd, const void *target) +{ + ptrdiff_t offset = tcg_pcrel_diff(s, target); + tcg_debug_assert(offset == sextract64(offset, 0, 21)); + tcg_out_insn_br(s, OPC_BR, rd, 0); + tcg_out_insn_simpleImm(s, OPC_SUBL_I, rd, rd, 4); + if (offset >= 0) { + tcg_out_simple(s, OPC_ADDL_I, OPC_ADDL, rd, rd, offset); + } else { + tcg_out_simple(s, OPC_SUBL_I, OPC_SUBL, rd, rd, -offset); + } +} + +static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *lb) +{ + MemOpIdx oi = lb->oi; + MemOp opc = get_memop(oi); + MemOp size = opc & MO_SIZE; + + if (!reloc_pc21(lb->label_ptr[0], tcg_splitwx_to_rx(s->code_ptr))) { + return false; + } + + tcg_out_mov(s, TCG_TYPE_PTR, TCG_REG_X16, TCG_AREG0); + tcg_out_mov(s, TARGET_LONG_BITS == 64, TCG_REG_X17, lb->addrlo_reg); + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_X18, oi); + tcg_out_adr(s, TCG_REG_X19, lb->raddr); + tcg_out_call(s, qemu_ld_helpers[opc & (MO_BSWAP | MO_SIZE)]); + if (opc & MO_SIGN) { + tcg_out_sxt(s, lb->type, size, lb->datalo_reg, TCG_REG_X0); + } else { + tcg_out_mov(s, size == MO_64, lb->datalo_reg, TCG_REG_X0); + } + + tcg_out_goto(s, lb->raddr); + return true; +} + +static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *lb) +{ + MemOpIdx oi = lb->oi; + MemOp opc = get_memop(oi); + MemOp size = opc & MO_SIZE; + + if (!reloc_pc21(lb->label_ptr[0], tcg_splitwx_to_rx(s->code_ptr))) { + return false; + } + + tcg_out_mov(s, TCG_TYPE_PTR, TCG_REG_X16, TCG_AREG0); + tcg_out_mov(s, TARGET_LONG_BITS == 64, TCG_REG_X17, lb->addrlo_reg); + tcg_out_mov(s, size == MO_64, TCG_REG_X18, lb->datalo_reg); + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_X19, oi); + tcg_out_adr(s, TCG_REG_X20, lb->raddr); + tcg_out_call(s, qemu_st_helpers[opc & (MO_BSWAP | MO_SIZE)]); + tcg_out_goto(s, lb->raddr); + return true; +} + +static void add_qemu_ldst_label(TCGContext *s, bool is_ld, MemOpIdx oi, + TCGType ext, TCGReg data_reg, TCGReg addr_reg, + tcg_insn_unit *raddr, tcg_insn_unit *label_ptr) +{ + TCGLabelQemuLdst *label = new_ldst_label(s); + + label->is_ld = is_ld; + label->oi = oi; + label->type = ext; + label->datalo_reg = data_reg; + label->addrlo_reg = addr_reg; + label->raddr = tcg_splitwx_to_rx(raddr); + label->label_ptr[0] = label_ptr; +} + +/* We expect to use a 7-bit scaled negative offset from ENV. */ +QEMU_BUILD_BUG_ON(TLB_MASK_TABLE_OFS(0) > 0); +QEMU_BUILD_BUG_ON(TLB_MASK_TABLE_OFS(0) < -512); + +/* These offsets are built into the LDP below. */ +QEMU_BUILD_BUG_ON(offsetof(CPUTLBDescFast, mask) != 0); +QEMU_BUILD_BUG_ON(offsetof(CPUTLBDescFast, table) != 8); + +/* + * Load and compare a TLB entry, emitting the conditional jump to the + * slow path for the failure case, which will be patched later when finalizing + * the slow path. Generated code returns the host addend in X1, + * clobbers X0,X2,X3,TMP. + */ +static void tcg_out_tlb_read(TCGContext *s, TCGReg addr_reg, MemOp opc, + tcg_insn_unit **label_ptr, int mem_index, + bool is_read) +{ + unsigned a_bits = get_alignment_bits(opc); + unsigned s_bits = opc & MO_SIZE; + unsigned a_mask = (1u << a_bits) - 1; + unsigned s_mask = (1u << s_bits) - 1; + TCGReg x3; + TCGType mask_type; + uint64_t compare_mask; + + mask_type = (TARGET_PAGE_BITS + CPU_TLB_DYN_MAX_BITS > 32 + ? TCG_TYPE_I64 : TCG_TYPE_I32); + + /* Load env_tlb(env)->f[mmu_idx].{mask,table} into {x0,x1}. */ + tcg_out_insn_ldst(s, OPC_LDL, TCG_REG_X0, TCG_AREG0, TLB_MASK_TABLE_OFS(mem_index)); + tcg_out_insn_ldst(s, OPC_LDL, TCG_REG_X1, TCG_AREG0, TLB_MASK_TABLE_OFS(mem_index)+8); + + /* Extract the TLB index from the address into X0. */ + if (mask_type == TCG_TYPE_I64) { + tcg_out_insn_simpleImm(s, OPC_SRL_I, TCG_REG_TMP, addr_reg, TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS); + tcg_out_insn_bitReg(s, OPC_AND, TCG_REG_X0, TCG_REG_X0, TCG_REG_TMP); + } else { + tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, TCG_REG_TMP, addr_reg, 0xf); + tcg_out_insn_simpleImm(s, OPC_SRL_I, TCG_REG_TMP, TCG_REG_TMP, TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS); + tcg_out_insn_bitReg(s, OPC_AND, TCG_REG_X0, TCG_REG_X0, TCG_REG_TMP); + tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, TCG_REG_X0, TCG_REG_X0, 0xf); + } + /* Add the tlb_table pointer, creating the CPUTLBEntry address into X1. */ + tcg_out_insn_simpleReg(s, OPC_ADDL, TCG_REG_X1, TCG_REG_X1, TCG_REG_X0); + + /* Load the tlb comparator into X0, and the fast path addend into X1. */ + tcg_out_ld(s, TCG_TYPE_TL, TCG_REG_X0, TCG_REG_X1, is_read + ? offsetof(CPUTLBEntry, addr_read) + : offsetof(CPUTLBEntry, addr_write)); + tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_X1, TCG_REG_X1, + offsetof(CPUTLBEntry, addend)); + + /* For aligned accesses, we check the first byte and include the alignment + bits within the address. For unaligned access, we check that we don't + cross pages using the address of the last byte of the access. */ + if (a_bits >= s_bits) { + x3 = addr_reg; + } else { + if (s_mask >= a_mask) { + tcg_out_simple(s, OPC_ADDL_I, OPC_ADDL, TCG_REG_X3, addr_reg, s_mask - a_mask); + } else { + tcg_out_simple(s, OPC_SUBL_I, OPC_SUBL, TCG_REG_X3, addr_reg, a_mask - s_mask); + } + + if (TARGET_LONG_BITS != 64) { + tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, TCG_REG_X3, TCG_REG_X3, 0xf); + } + x3 = TCG_REG_X3; + } + compare_mask = (uint64_t)TARGET_PAGE_MASK | a_mask; + + /* Store the page mask part of the address into X3. */ + tcg_out_bit(s, OPC_AND_I, OPC_AND, TCG_REG_X3, x3, compare_mask); + if (TARGET_LONG_BITS != 64) { + tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, TCG_REG_X3, TCG_REG_X3, 0xf); + } + + /* Perform the address comparison. */ + tcg_out_cond_cmp(s, TARGET_LONG_BITS == 64, TCG_COND_NE, TCG_REG_TMP, TCG_REG_X0, TCG_REG_X3, 0); + + /* If not equal, we jump to the slow path. */ + *label_ptr = s->code_ptr; + tcg_out_insn_br(s, OPC_BGT, TCG_REG_TMP, 0); +} + +#endif /* CONFIG_SOFTMMU */ + +static void tcg_out_qemu_ld_direct(TCGContext *s, MemOp memop, TCGType ext, + TCGReg data_r, TCGReg addr_r, + TCGType otype, TCGReg off_r) +{ + if (otype == TCG_TYPE_I32) { + tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, TCG_REG_TMP, off_r, 0xf); + tcg_out_insn_simpleReg(s, OPC_ADDL, TCG_REG_TMP, addr_r, TCG_REG_TMP); + } else { + tcg_out_insn_simpleReg(s, OPC_ADDL, TCG_REG_TMP, addr_r, off_r); + } + + const MemOp bswap = memop & MO_BSWAP; + + switch (memop & MO_SSIZE) { + case MO_UB: + tcg_out_ldst(s, OPC_LDBU, data_r, TCG_REG_TMP, 0, zeroExt); + break; + case MO_SB: + tcg_out_ldst(s, OPC_LDBU, data_r, TCG_REG_TMP, 0, sigExt); + if (ext == TCG_TYPE_I32) { + tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, data_r, data_r, 0xf); + } + break; + case MO_UW: + tcg_out_ldst(s, OPC_LDHU, data_r, TCG_REG_TMP, 0, zeroExt); + if (bswap) { + tcg_out_bswap16(s, ext, data_r, data_r); + } + break; + case MO_SW: + if (bswap) { + tcg_out_ldst(s, OPC_LDHU, data_r, TCG_REG_TMP, 0, zeroExt); + tcg_out_bswap16(s, ext, data_r, data_r); + tcg_out_insn_simpleReg(s, OPC_SEXTH, data_r, TCG_REG_ZERO, data_r); + } else { + tcg_out_ldst(s, OPC_LDHU, data_r, TCG_REG_TMP, 0, sigExt); + } + + if (ext == TCG_TYPE_I32) { + tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, data_r, data_r, 0xf); + } + break; + case MO_UL: + tcg_out_ldst(s, OPC_LDW, data_r, TCG_REG_TMP, 0, zeroExt); + if (bswap) { + tcg_out_bswap32(s, ext, data_r, data_r); + } + break; + case MO_SL: + if (bswap) { + tcg_out_ldst(s, OPC_LDW, data_r, TCG_REG_TMP, 0, zeroExt); + tcg_out_bswap32(s, ext, data_r, data_r); + tcg_out_insn_simpleReg(s, OPC_ADDW, data_r, data_r, TCG_REG_ZERO); + } else { + tcg_out_ldst(s, OPC_LDW, data_r, TCG_REG_TMP, 0, sigExt); + } + break; + case MO_Q: + tcg_out_ldst(s, OPC_LDL, data_r, TCG_REG_TMP, 0, zeroExt); + if (bswap) { + tcg_out_bswap64(s, ext, data_r, data_r); + } + break; + default: + tcg_abort(); + } +} + +static void tcg_out_qemu_ld(TCGContext *s, TCGReg data_reg, TCGReg addr_reg, MemOpIdx oi, TCGType ext) +{ + MemOp memop = get_memop(oi); + const TCGType otype = TARGET_LONG_BITS == 64 ? TCG_TYPE_I64: TCG_TYPE_I32; +#ifdef CONFIG_SOFTMMU + unsigned mem_index = get_mmuidx(oi); + tcg_insn_unit *label_ptr; + + tcg_out_tlb_read(s, addr_reg, memop, &label_ptr, mem_index, 1); + tcg_out_qemu_ld_direct(s, memop, ext, data_reg, + TCG_REG_X1, otype, addr_reg); + add_qemu_ldst_label(s, true, oi, ext, data_reg, addr_reg, + s->code_ptr, label_ptr); +#else /* !CONFIG_SOFTMMU */ + if (USE_GUEST_BASE) { + tcg_out_qemu_ld_direct(s, memop, ext, data_reg, TCG_REG_GUEST_BASE, otype, addr_reg); + } else { + tcg_out_qemu_ld_direct(s, memop, ext, data_reg, addr_reg, TCG_TYPE_I64, TCG_REG_ZERO); + } +#endif /* CONFIG_SOFTMMU */ +} + +static void tcg_out_qemu_st_direct(TCGContext *s, MemOp memop, + TCGReg data_r, TCGReg addr_r, + TCGType otype, TCGReg off_r) +{ + if (otype == TCG_TYPE_I32) { + tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, TCG_REG_TMP, off_r, 0xf); + tcg_out_insn_simpleReg(s, OPC_ADDL, TCG_REG_TMP, addr_r, TCG_REG_TMP); + } else { + tcg_out_insn_simpleReg(s, OPC_ADDL, TCG_REG_TMP, addr_r, off_r); + } + + const MemOp bswap = memop & MO_BSWAP; + + switch (memop & MO_SIZE) { + case MO_8: + tcg_out_ldst(s, OPC_STB, data_r, TCG_REG_TMP, 0, 0); + break; + case MO_16: + if (bswap && data_r != TCG_REG_ZERO) { + tcg_out_bswap16(s, TCG_TYPE_I32, TCG_REG_TMP3, data_r); + data_r = TCG_REG_TMP3; + } + tcg_out_ldst(s, OPC_STH, data_r, TCG_REG_TMP, 0, 0); + break; + case MO_32: + if (bswap && data_r != TCG_REG_ZERO) { + tcg_out_bswap32(s, TCG_TYPE_I32, TCG_REG_TMP3, data_r); + data_r = TCG_REG_TMP3; + } + tcg_out_ldst(s, OPC_STW, data_r, TCG_REG_TMP, 0, 0); + break; + case MO_64: + if (bswap && data_r != TCG_REG_ZERO) { + tcg_out_bswap64(s, TCG_TYPE_I64, TCG_REG_TMP3, data_r); + data_r = TCG_REG_TMP3; + } + tcg_out_ldst(s, OPC_STL, data_r, TCG_REG_TMP, 0, 0); + break; + default: + tcg_abort(); + } +} + +static void tcg_out_qemu_st(TCGContext *s, TCGReg data_reg, TCGReg addr_reg, + MemOpIdx oi) +{ + MemOp memop = get_memop(oi); + const TCGType otype = TARGET_LONG_BITS == 64 ? TCG_TYPE_I64: TCG_TYPE_I32; +#ifdef CONFIG_SOFTMMU + unsigned mem_index = get_mmuidx(oi); + tcg_insn_unit *label_ptr; + + tcg_out_tlb_read(s, addr_reg, memop, &label_ptr, mem_index, 0); + tcg_out_qemu_st_direct(s, memop, data_reg, TCG_REG_X1, otype, addr_reg); + add_qemu_ldst_label(s, false, oi, (memop & MO_SIZE)== MO_64, data_reg, addr_reg, s->code_ptr, label_ptr); +#else /* !CONFIG_SOFTMMU */ + if (USE_GUEST_BASE) { + tcg_out_qemu_st_direct(s, memop, data_reg, TCG_REG_GUEST_BASE, otype, addr_reg); + } else { + tcg_out_qemu_st_direct(s, memop, data_reg, addr_reg, TCG_TYPE_I64, TCG_REG_ZERO); + } +#endif /* CONFIG_SOFTMMU */ +} + +static const tcg_insn_unit *tb_ret_addr; + +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. */ + + 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 */ + /* Ensure that ADRP+ADD are 8-byte aligned so that an atomic + write can be used to patch the target address. */ + if ((uintptr_t)s->code_ptr & 7) { + tcg_out32(s, OPC_NOP); + } + s->tb_jmp_insn_offset[a0] = tcg_current_code_size(s); + tcg_out32(s, OPC_NOP); + tcg_out32(s, OPC_NOP); + } 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, noPara); + set_jmp_reset_offset(s, a0); + break; + case INDEX_op_goto_ptr: + tcg_out_insn_jump(s, OPC_JMP, TCG_REG_ZERO, a0, noPara); + 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: + tcg_out_ldst(s, OPC_LDBU, a0, a1, a2, 1); + tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, a0, a0, 0xf); + break; + 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: + tcg_out_ldst(s, OPC_LDHU, a0, a1, a2, 1); + tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, a0, a0, 0xf); + break; + 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, 0); + 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, REG0(0), a1, a2, 0); + break; + case INDEX_op_st16_i32: + case INDEX_op_st16_i64: + tcg_out_ldst(s, OPC_STH, REG0(0), a1, a2, 0); + break; + case INDEX_op_st_i32: + case INDEX_op_st32_i64: + tcg_out_ldst(s, OPC_STW, REG0(0), a1, a2, 0); + break; + case INDEX_op_st_i64: + tcg_out_ldst(s, OPC_STL, REG0(0), 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_ADDW, a0, a1, a2); + tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, a0, a0, 0xf); + } + 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_SUBW, a0, a1, a2); + tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, a0, a0, 0xf); + } + 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_i32: + tcg_out_insn_bitReg(s, OPC_SUBW, a0, TCG_REG_ZERO, a1); + tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, a0, a0, 0xf); + break; + case INDEX_op_neg_i64: + tcg_out_insn_bitReg(s, OPC_SUBL, a0, TCG_REG_ZERO, a1); + break; + case INDEX_op_and_i32: + if (c2) { + a2 = (int32_t)a2; + tcg_out_bit(s, OPC_AND_I, OPC_AND, a0, a1, a2); + } else { + tcg_out_insn_bitReg(s, OPC_AND, a0, a1, a2); + } + tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, a0, a0, 0xf); + break; + case INDEX_op_and_i64: + if (c2) { + tcg_out_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: + case INDEX_op_andc_i64: + tcg_debug_assert(0); + break; + case INDEX_op_or_i32: + if (c2) { + a2 = (int32_t)a2; + tcg_out_bit(s, OPC_BIS_I, OPC_BIS, a0, a1, a2); + } else { + tcg_out_insn_bitReg(s, OPC_BIS, a0, a1, a2); + } + tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, a0, a0, 0xf); + break; + case INDEX_op_or_i64: + if (c2) { + tcg_out_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: + if (c2) { + a2 = (int32_t)a2; + tcg_out_bit(s, OPC_BIS_I, OPC_BIS, a0, a1, ~a2); + } else { + tcg_out_insn_bitReg(s, OPC_ORNOT, a0, a1, a2); + } + tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, a0, a0, 0xf); + break; + case INDEX_op_orc_i64: + if (c2) { + tcg_out_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: + if (c2) { + a2 = (int32_t)a2; + tcg_out_bit(s, OPC_XOR_I, OPC_XOR, a0, a1, a2); + } else { + tcg_out_insn_bitReg(s, OPC_XOR, a0, a1, a2); + } + tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, a0, a0, 0xf); + break; + case INDEX_op_xor_i64: + if (c2) { + tcg_out_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: + case INDEX_op_eqv_i64: + tcg_debug_assert(0); + break; + case INDEX_op_not_i32: + tcg_out_insn_bitReg(s, OPC_ORNOT, a0, TCG_REG_ZERO, a1); + tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, a0, a0, 0xf); + break; + case INDEX_op_not_i64: + tcg_out_insn_bitReg(s, OPC_ORNOT, a0, TCG_REG_ZERO, a1); + break; + case INDEX_op_mul_i32: + tcg_out_insn_simpleReg(s, OPC_MULL, a0, a1, a2); + tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, a0, a0, 0xf); + break; + case INDEX_op_mul_i64: + tcg_out_insn_simpleReg(s, OPC_MULL, a0, a1, a2); + break; + case INDEX_op_div_i32: + case INDEX_op_div_i64: + tcg_debug_assert(0); + break; + case INDEX_op_divu_i32: + case INDEX_op_divu_i64: + tcg_debug_assert(0); + break; + case INDEX_op_rem_i32: + case INDEX_op_rem_i64: + tcg_debug_assert(0); + break; + case INDEX_op_remu_i32: + case INDEX_op_remu_i64: + tcg_debug_assert(0); + break; + case INDEX_op_shl_i32: /* sw logical left*/ + if (c2) { + unsigned int bits = ext ? 64 : 32; + unsigned int max = bits - 1; + tcg_out_insn_simpleImm(s, OPC_SLL_I, a0, a1, a2&max); + tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, a0, a0, 0xf); + } else { + tcg_out_insn_bitReg(s, OPC_SLL, a0, a1, a2); + tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, a0, a0, 0xf); + } + break; + case INDEX_op_shl_i64: + if (c2) { + unsigned int bits = ext ? 64 : 32; + unsigned int max = bits - 1; + tcg_out_insn_simpleImm(s, OPC_SLL_I, a0, a1, a2&max); + } else { + tcg_out_insn_bitReg(s, OPC_SLL, a0, a1, a2); + } + break; + case INDEX_op_shr_i32: /* sw logical right */ + a2 = (int32_t)a2; + if (c2) { + int bits = ext ? 64 : 32; + int max = bits - 1; + tcg_out_insn_simpleImm(s, OPC_SRL_I, a0, a1, a2&max); + } else { + tcg_out_insn_bitReg(s, OPC_SRL, a0, a1, a2); + } + break; + case INDEX_op_shr_i64: + if (c2) { + int bits = ext ? 64 : 32; + int max = bits - 1; + tcg_out_insn_simpleImm(s, OPC_SRL_I, a0, a1, a2&max); + } else { + tcg_out_insn_bitReg(s, OPC_SRL, a0, a1, a2); + } + break; + case INDEX_op_sar_i32: + a2 = (int32_t)a2; + tcg_out_sar(s, ext, a0, a1, a2, c2); + break; + case INDEX_op_sar_i64: /* sw arithmetic right*/ + tcg_out_sar(s, ext, a0, a1, a2, c2); + break; + case INDEX_op_rotr_i32: /* loop shift */ + case INDEX_op_rotr_i64: + 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_i32: /* loop shift */ + case INDEX_op_rotl_i64: /* sw */ + 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_i32: + tcg_out_ctz32(s, OPC_CTLZ, a0, a1, a2, c2); + break; + case INDEX_op_clz_i64: /* counting leading zero numbers */ + tcg_out_ctz64(s, OPC_CTLZ, a0, a1, a2, c2); + break; + case INDEX_op_ctz_i32: + tcg_out_ctz32(s, OPC_CTTZ, a0, a1, a2, c2); + break; + case INDEX_op_ctz_i64: /* counting tailing zero numbers */ + tcg_out_ctz64(s, OPC_CTTZ, a0, a1, a2, c2); + break; + case INDEX_op_brcond_i32: + 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, ext, args[3], a0, a1, a2, c2); + break; + case INDEX_op_setcond_i64: + tcg_out_setcond(s, ext, args[3], a0, a1, a2, c2); + break; + case INDEX_op_movcond_i32: + a2 = (int32_t)a2; + tcg_out_movcond(s, ext, args[5], a0, a1, a2, c2, REG0(3), REG0(4)); + break; + case INDEX_op_movcond_i64: + tcg_out_movcond(s, ext, 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: + tcg_out_bswap64(s, ext, a0, a1); + break; + case INDEX_op_bswap32_i32: + case INDEX_op_bswap32_i64: + tcg_out_bswap32(s, ext, a0, a1); + break; + case INDEX_op_bswap16_i32: + case INDEX_op_bswap16_i64: + tcg_out_bswap16(s, ext, a0, a1); + break; + case INDEX_op_ext8s_i32: + tcg_out_insn_simpleReg(s, OPC_SEXTB, a0, TCG_REG_ZERO, a1); + tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, a0, a0, 0xf); + break; + case INDEX_op_ext8s_i64: + tcg_out_insn_simpleReg(s, OPC_SEXTB, a0, TCG_REG_ZERO, a1); + break; + case INDEX_op_ext16s_i32: + tcg_out_insn_simpleReg(s, OPC_SEXTH, a0, TCG_REG_ZERO, a1); + tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, a0, a0, 0xf); + break; + case INDEX_op_ext16s_i64: + 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_i32: + case INDEX_op_ext8u_i64: + tcg_out_insn_simpleImm(s, OPC_EXTLB_I, a0, a1, 0x0); + break; + case INDEX_op_ext16u_i32: + case INDEX_op_ext16u_i64: + tcg_out_insn_simpleImm(s, OPC_EXTLH_I, a0, a1, 0x0); + break; + case INDEX_op_extu_i32_i64: + case INDEX_op_ext32u_i64: + tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, a0, a1, 0xf); + break; + case INDEX_op_deposit_i32: + case INDEX_op_deposit_i64: + tcg_out_dep(s, ext, a0, REG0(2), args[3], args[4]); + break; + case INDEX_op_extract_i32: + case INDEX_op_extract_i64: + tcg_out_extract(s, a0, a1, a2, args[3]); + break; + case INDEX_op_sextract_i32: + case INDEX_op_sextract_i64: + tcg_debug_assert(0); + break; + case INDEX_op_extract2_i32: /* extract REG0(2) right args[3] bit to REG0(1) left ,save to a0*/ + case INDEX_op_extract2_i64: + tcg_debug_assert(0); + break; + case INDEX_op_add2_i32: + case INDEX_op_add2_i64: + tcg_debug_assert(0); + break; + case INDEX_op_sub2_i32: + 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: + tcg_out_mulsh64(s, a0, a1, a2); + break; + case INDEX_op_mb: + tcg_out_mb(s); + break; + case INDEX_op_mov_i32: /* Always emitted via tcg_out_mov. */ + break; + case INDEX_op_mov_i64: + break; + case INDEX_op_call: /* Always emitted via tcg_out_call. */ + default: + g_assert_not_reached(); + } +#undef REG0 +} + +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); + case INDEX_op_setcond_i32: + case INDEX_op_setcond_i64: + return C_O1_I2(r, r, rU); + 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); + 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); + case INDEX_op_ctz_i32: + case INDEX_op_ctz_i64: + return C_O1_I2(r, r, r); + case INDEX_op_brcond_i32: + case INDEX_op_brcond_i64: + return C_O0_I2(r, rU); + case INDEX_op_movcond_i32: + case INDEX_op_movcond_i64: + return C_O1_I4(r, r, rU, rZ, rZ); + 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_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; + + 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); + + 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_regset_set_reg(s->reserved_regs, TCG_REG_TMP2); + tcg_regset_set_reg(s->reserved_regs, TCG_REG_TMP3); + tcg_regset_set_reg(s->reserved_regs, TCG_REG_RA); + tcg_regset_set_reg(s->reserved_regs, TCG_REG_X29); + tcg_regset_set_reg(s->reserved_regs, TCG_FLOAT_TMP); + tcg_regset_set_reg(s->reserved_regs, TCG_FLOAT_TMP2); +} + + +#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're expecting a 2 byte uleb128 encoded value. */ +QEMU_BUILD_BUG_ON(FRAME_SIZE >= (1 << 14)); + +/* We're expecting to use a single ADDI insn. */ +QEMU_BUILD_BUG_ON(FRAME_SIZE - PUSH_SIZE > 0xfff); + +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_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_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)); + +#ifndef 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], noPara); + + /* + * 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_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_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, noPara); +} + +static void tcg_out_nop_fill(tcg_insn_unit *p, int count) +{ + int i; + for (i = 0; i < count; ++i) { + p[i] = OPC_NOP; + } +} + +typedef struct { + DebugFrameHeader h; + uint8_t fde_def_cfa[4]; + uint8_t fde_reg_ofs[8 * 2]; +} DebugFrame; + +/* + * GDB doesn't appear to require proper setting of ELF_HOST_FLAGS, + * which is good because they're really quite complicated for SW64. + */ +#define ELF_HOST_MACHINE EM_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 0000000000000000000000000000000000000000..91681a0c75594362d14a2e912891474fe1c7578e --- /dev/null +++ b/tcg/sw64/tcg-target.h @@ -0,0 +1,126 @@ +/* + * 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); +#ifdef CONFIG_SOFTMMU +#define TCG_TARGET_NEED_LDST_LABELS +#endif +#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 0000000000000000000000000000000000000000..bce30accd9366f1665c58141616ca5e4e56c9f35 --- /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)