diff --git a/configs/devices/sw64-softmmu/default.mak b/configs/devices/sw64-softmmu/default.mak new file mode 100644 index 0000000000000000000000000000000000000000..171f5bf9b44dfa78f63d48047507201ce0520bb4 --- /dev/null +++ b/configs/devices/sw64-softmmu/default.mak @@ -0,0 +1,11 @@ +# 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 diff --git a/configs/targets/sw64-softmmu.mak b/configs/targets/sw64-softmmu.mak new file mode 100644 index 0000000000000000000000000000000000000000..37cc2e05a6873dedd225cb28be443c79e2d8e65f --- /dev/null +++ b/configs/targets/sw64-softmmu.mak @@ -0,0 +1,8 @@ +# Default configuration for sw64-softmmu + +# Boards: +# +TARGET_ARCH=sw64 +TARGET_BASE_ARCH=sw64 +TARGET_ABI_DIR=sw64 +TARGET_SUPPORTS_MTTCG=y diff --git a/configure b/configure index 48c21775f3a90c91631d90bd6e3ec6b060215465..172cee93f1f4ed701d7ca96a080bfd28baa04c83 100755 --- a/configure +++ b/configure @@ -612,6 +612,9 @@ case "$cpu" in sparc|sun4[cdmuv]) cpu="sparc" ;; + sw_64) + cpu="sw64" + ;; *) # This will result in either an error or falling back to TCI later ARCH=unknown @@ -3268,6 +3271,10 @@ alpha) # Ensure there's only a single GP QEMU_CFLAGS="-msmall-data $QEMU_CFLAGS" ;; +sw*) + # Ensure there's only a single GP + cflags="-msmall-data $cflags" +;; esac if test "$gprof" = "yes" ; then diff --git a/disas.c b/disas.c index 3dab4482d1a1eeef0393f3c3efb4b54637270136..897de1d9a98d251de466c388177c50c0b63c20f0 100644 --- a/disas.c +++ b/disas.c @@ -207,6 +207,8 @@ static void initialize_debug_host(CPUDebug *s) s->info.cap_insn_split = 6; #elif defined(__hppa__) s->info.print_insn = print_insn_hppa; +#elif defined(__sw_64__) + s->info.print_insn = print_insn_sw_64; #endif } diff --git a/disas/meson.build b/disas/meson.build index 449f99e1de63b3bab10da894b4d4e681226b6618..5c5daa69a724b69dd69eb12b9c4182d40629eb13 100644 --- a/disas/meson.build +++ b/disas/meson.build @@ -20,4 +20,5 @@ common_ss.add(when: 'CONFIG_S390_DIS', if_true: files('s390.c')) common_ss.add(when: 'CONFIG_SH4_DIS', if_true: files('sh4.c')) common_ss.add(when: 'CONFIG_SPARC_DIS', if_true: files('sparc.c')) common_ss.add(when: 'CONFIG_XTENSA_DIS', if_true: files('xtensa.c')) +common_ss.add(when: 'CONFIG_SW64_DIS', if_true: files('sw64.c')) common_ss.add(when: capstone, if_true: files('capstone.c')) diff --git a/disas/sw64.c b/disas/sw64.c new file mode 100755 index 0000000000000000000000000000000000000000..9824190c7ee908613c8aa339283e963db0e62671 --- /dev/null +++ b/disas/sw64.c @@ -0,0 +1,1412 @@ +/* + * sw_64-dis.c -- Disassemble Sw_64 AXP 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 sw_64_opcode { + /* The opcode name. */ + const char *name; + + /* The opcode itself. Those bits which will be filled in with + operands are zeroes. */ + unsigned opcode; + + /* The opcode mask. This is used by the disassembler. This is a + mask containing ones indicating those bits which must match the + opcode field, and zeroes indicating those bits which need not + match (and are presumably filled in by operands). */ + unsigned mask; + + /* One bit flags for the opcode. These are primarily used to + indicate specific processors and environments support the + instructions. The defined values are listed below. */ + unsigned flags; + + /* An array of operand codes. Each code is an index into the + operand table. They appear in the order which the operands must + appear in assembly code, and are terminated by a zero. */ + unsigned char operands[5]; +}; + +/* The table itself is sorted by major opcode number, and is otherwise + in the order in which the disassembler should consider + instructions. */ +extern const struct sw_64_opcode sw_64_opcodes[]; +extern const unsigned sw_64_num_opcodes; + +/* Values defined for the flags field of a struct sw_64_opcode. */ + +/* CPU Availability */ +#define AXP_OPCODE_BASE 0x0001 /* Base architecture insns. */ +#define AXP_OPCODE_CORE3 0x0002 /* Core3 private insns. */ +#define AXP_OPCODE_CORE4 0x0004 /* Core4 private insns. */ +#define AXP_LITOP(i) (((i) >> 26) & 0x3D) + +#define AXP_OPCODE_NOPAL (~(AXP_OPCODE_BASE|AXP_OPCODE_CORE3|AXP_OPCODE_CORE4)) + +/* A macro to extract the major opcode from an instruction. */ +#define AXP_OP(i) (((i) >> 26) & 0x3F) + +/* The total number of major opcodes. */ +#define AXP_NOPS 0x40 + +/* The operands table is an array of struct sw_64_operand. */ + +struct sw_64_operand { + /* The number of bits in the operand. */ + unsigned int bits : 5; + + /* How far the operand is left shifted in the instruction. */ + unsigned int shift : 5; + + /* The default relocation type for this operand. */ + signed int default_reloc : 16; + + /* One bit syntax flags. */ + unsigned int flags : 16; + + /* Insertion function. This is used by the assembler. To insert an + operand value into an instruction, check this field. + + If it is NULL, execute + i |= (op & ((1 << o->bits) - 1)) << o->shift; + (i is the instruction which we are filling in, o is a pointer to + this structure, and op is the opcode value; this assumes twos + complement arithmetic). + + If this field is not NULL, then simply call it with the + instruction and the operand value. It will return the new value + of the instruction. If the ERRMSG argument is not NULL, then if + the operand value is illegal, *ERRMSG will be set to a warning + string (the operand will be inserted in any case). If the + operand value is legal, *ERRMSG will be unchanged (most operands + can accept any value). */ + unsigned (*insert) (unsigned instruction, int op, const char **errmsg); + + /* Extraction function. This is used by the disassembler. To + extract this operand type from an instruction, check this field. + + If it is NULL, compute + op = ((i) >> o->shift) & ((1 << o->bits) - 1); + if ((o->flags & AXP_OPERAND_SIGNED) != 0 + && (op & (1 << (o->bits - 1))) != 0) + op -= 1 << o->bits; + (i is the instruction, o is a pointer to this structure, and op + is the result; this assumes twos complement arithmetic). + + If this field is not NULL, then simply call it with the + instruction value. It will return the value of the operand. If + the INVALID argument is not NULL, *INVALID will be set to + non-zero if this operand type can not actually be extracted from + this operand (i.e., the instruction does not match). If the + operand is valid, *INVALID will not be changed. */ + int (*extract) (unsigned instruction, int *invalid); +}; + +/* Elements in the table are retrieved by indexing with values from + the operands field of the sw_64_opcodes table. */ + +extern const struct sw_64_operand sw_64_operands[]; +extern const unsigned sw_64_num_operands; +/* Values defined for the flags field of a struct sw_64_operand. */ + +/* Mask for selecting the type for typecheck purposes */ +#define AXP_OPERAND_TYPECHECK_MASK \ + (AXP_OPERAND_PARENS | AXP_OPERAND_COMMA | AXP_OPERAND_IR | \ + AXP_OPERAND_FPR | AXP_OPERAND_RELATIVE | AXP_OPERAND_SIGNED | \ + AXP_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 AXP_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 AXP_OPERAND_PARENS 02 + +/* Used in combination with PARENS, this supresses the supression of + the comma. This is used for "jmp Ra,(Rb),hint". */ +#define AXP_OPERAND_COMMA 04 + +/* This operand names an integer register. */ +#define AXP_OPERAND_IR 010 + +/* This operand names a floating point register. */ +#define AXP_OPERAND_FPR 020 + +/* This operand is a relative branch displacement. The disassembler + prints these symbolically if possible. */ +#define AXP_OPERAND_RELATIVE 040 + +/* This operand takes signed values. */ +#define AXP_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 AXP_OPERAND_UNSIGNED 0200 + +/* Supress overflow detection on this field. This is used for hints. */ +#define AXP_OPERAND_NOOVERFLOW 0400 + +/* Mask for optional argument default value. */ +#define AXP_OPERAND_OPTIONAL_MASK 07000 + +/* This operand defaults to zero. This is used for jump hints. */ +#define AXP_OPERAND_DEFAULT_ZERO 01000 + +/* This operand should default to the first (real) operand and is used + in conjunction with AXP_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 AXP_OPERAND_DEFAULT_FIRST 02000 + +/* Similarly, this operand should default to the second (real) operand. + This allows "negl $0" instead of "negl $0,$0". */ +#define AXP_OPERAND_DEFAULT_SECOND 04000 + +/* Register common names */ + +#define AXP_REG_V0 0 +#define AXP_REG_T0 1 +#define AXP_REG_T1 2 +#define AXP_REG_T2 3 +#define AXP_REG_T3 4 +#define AXP_REG_T4 5 +#define AXP_REG_T5 6 +#define AXP_REG_T6 7 +#define AXP_REG_T7 8 +#define AXP_REG_S0 9 +#define AXP_REG_S1 10 +#define AXP_REG_S2 11 +#define AXP_REG_S3 12 +#define AXP_REG_S4 13 +#define AXP_REG_S5 14 +#define AXP_REG_FP 15 +#define AXP_REG_A0 16 +#define AXP_REG_A1 17 +#define AXP_REG_A2 18 +#define AXP_REG_A3 19 +#define AXP_REG_A4 20 +#define AXP_REG_A5 21 +#define AXP_REG_T8 22 +#define AXP_REG_T9 23 +#define AXP_REG_T10 24 +#define AXP_REG_T11 25 +#define AXP_REG_RA 26 +#define AXP_REG_PV 27 +#define AXP_REG_T12 27 +#define AXP_REG_AT 28 +#define AXP_REG_GP 29 +#define AXP_REG_SP 30 +#define AXP_REG_ZERO 31 + +enum bfd_reloc_code_real { + BFD_RELOC_23_PCREL_S2, + BFD_RELOC_SW_64_HINT +}; + +static unsigned insert_rba(unsigned insn, int value ATTRIBUTE_UNUSED, + const char **errmsg ATTRIBUTE_UNUSED) +{ + return insn | (((insn >> 21) & 0x1f) << 16); +} + +static int extract_rba(unsigned insn, int *invalid) +{ + if (invalid != (int *) NULL + && ((insn >> 21) & 0x1f) != ((insn >> 16) & 0x1f)) + *invalid = 1; + return 0; +} + +/* The same for the RC field. */ +static unsigned insert_rca(unsigned insn, int value ATTRIBUTE_UNUSED, + const char **errmsg ATTRIBUTE_UNUSED) +{ + return insn | ((insn >> 21) & 0x1f); +} + +static unsigned insert_rdc(unsigned insn, int value ATTRIBUTE_UNUSED, + const char **errmsg ATTRIBUTE_UNUSED) +{ + return insn | ((insn >> 5) & 0x1f); +} + +static int extract_rdc(unsigned insn, int *invalid) +{ + if (invalid != (int *) NULL + && ((insn >> 5) & 0x1f) != (insn & 0x1f)) + *invalid = 1; + return 0; +} + +static int extract_rca(unsigned insn, int *invalid) +{ + if (invalid != (int *) NULL + && ((insn >> 21) & 0x1f) != (insn & 0x1f)) + *invalid = 1; + return 0; +} + +/* Fake arguments in which the registers must be set to ZERO. */ +static unsigned insert_za(unsigned insn, int value ATTRIBUTE_UNUSED, + const char **errmsg ATTRIBUTE_UNUSED) +{ + return insn | (31 << 21); +} + +static int extract_za(unsigned insn, int *invalid) +{ + if (invalid != (int *) NULL && ((insn >> 21) & 0x1f) != 31) + *invalid = 1; + return 0; +} + +static unsigned insert_zb(unsigned insn, int value ATTRIBUTE_UNUSED, + const char **errmsg ATTRIBUTE_UNUSED) +{ + return insn | (31 << 16); +} + +static int extract_zb(unsigned insn, int *invalid) +{ + if (invalid != (int *) NULL && ((insn >> 16) & 0x1f) != 31) + *invalid = 1; + return 0; +} + +static unsigned insert_zc(unsigned insn, int value ATTRIBUTE_UNUSED, + const char **errmsg ATTRIBUTE_UNUSED) +{ + return insn | 31; +} + +static int extract_zc(unsigned insn, int *invalid) +{ + if (invalid != (int *) NULL && (insn & 0x1f) != 31) + *invalid = 1; + return 0; +} + + +/* The displacement field of a Branch format insn. */ + +static unsigned insert_bdisp(unsigned insn, int value, const char **errmsg) +{ + if (errmsg != (const char **)NULL && (value & 3)) + *errmsg = "branch operand unaligned"; + return insn | ((value / 4) & 0x1FFFFF); +} + +static int extract_bdisp(unsigned insn, int *invalid ATTRIBUTE_UNUSED) +{ + return 4 * (((insn & 0x1FFFFF) ^ 0x100000) - 0x100000); +} + +static unsigned insert_bdisp26(unsigned insn, int value, const char **errmsg) +{ + if (errmsg != (const char **)NULL && (value & 3)) + *errmsg = "branch operand unaligned"; + return insn | ((value / 4) & 0x3FFFFFF); +} + +static int extract_bdisp26(unsigned insn, int *invalid ATTRIBUTE_UNUSED) +{ + return 4 * (((insn & 0x3FFFFFF) ^ 0x2000000) - 0x2000000); +} + +/* The hint field of a JMP/JSR insn. */ +/* sw use 16 bits hint disp. */ +static unsigned insert_jhint(unsigned insn, int value, const char **errmsg) +{ + if (errmsg != (const char **)NULL && (value & 3)) + *errmsg = "jump hint unaligned"; + return insn | ((value / 4) & 0xFFFF); +} + +static int extract_jhint(unsigned insn, int *invalid ATTRIBUTE_UNUSED) +{ + return 4 * (((insn & 0xFFFF) ^ 0x8000) - 0x8000); +} + +/* The hint field of an EV6 HW_JMP/JSR insn. */ + +static unsigned insert_sw4hwjhint(unsigned insn, int value, const char **errmsg) +{ + if (errmsg != (const char **)NULL && (value & 3)) + *errmsg = "jump hint unaligned"; + return insn | ((value / 4) & 0x1FFF); +} + +static int extract_sw4hwjhint(unsigned insn, int *invalid ATTRIBUTE_UNUSED) +{ + return 4 * (((insn & 0x1FFF) ^ 0x1000) - 0x1000); +} + +/* The operands table. */ + +const struct sw_64_operand sw_64_operands[] = { + /* The fields are bits, shift, insert, extract, flags */ + /* The zero index is used to indicate end-of-list */ +#define UNUSED 0 + { 0, 0, 0, 0, 0, 0 }, + + /* The plain integer register fields. */ +#define RA (UNUSED + 1) + { 5, 21, 0, AXP_OPERAND_IR, 0, 0 }, +#define RB (RA + 1) + { 5, 16, 0, AXP_OPERAND_IR, 0, 0 }, +#define RC (RB + 1) + { 5, 0, 0, AXP_OPERAND_IR, 0, 0 }, + + /* The plain fp register fields. */ +#define FA (RC + 1) + { 5, 21, 0, AXP_OPERAND_FPR, 0, 0 }, +#define FB (FA + 1) + { 5, 16, 0, AXP_OPERAND_FPR, 0, 0 }, +#define FC (FB + 1) + { 5, 0, 0, AXP_OPERAND_FPR, 0, 0 }, + + /* The integer registers when they are ZERO. */ +#define ZA (FC + 1) + { 5, 21, 0, AXP_OPERAND_FAKE, insert_za, extract_za }, +#define ZB (ZA + 1) + { 5, 16, 0, AXP_OPERAND_FAKE, insert_zb, extract_zb }, +#define ZC (ZB + 1) + { 5, 0, 0, AXP_OPERAND_FAKE, insert_zc, extract_zc }, + + /* The RB field when it needs parentheses. */ +#define PRB (ZC + 1) + { 5, 16, 0, AXP_OPERAND_IR | AXP_OPERAND_PARENS, 0, 0 }, + + /* The RB field when it needs parentheses _and_ a preceding comma. */ +#define CPRB (PRB + 1) + { 5, 16, 0, + AXP_OPERAND_IR | AXP_OPERAND_PARENS | AXP_OPERAND_COMMA, 0, 0 }, + + /* The RB field when it must be the same as the RA field. */ +#define RBA (CPRB + 1) + { 5, 16, 0, AXP_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, AXP_OPERAND_FAKE, insert_rca, extract_rca }, + +#define RDC (RCA + 1) + { 5, 0, 0, AXP_OPERAND_FAKE, insert_rdc, extract_rdc }, + + /* The RC field when it can *default* to RA. */ +#define DRC1 (RDC + 1) + { 5, 0, 0, + AXP_OPERAND_IR | AXP_OPERAND_DEFAULT_FIRST, 0, 0 }, + + /* The RC field when it can *default* to RB. */ +#define DRC2 (DRC1 + 1) + { 5, 0, 0, + AXP_OPERAND_IR | AXP_OPERAND_DEFAULT_SECOND, 0, 0 }, + + /* The FC field when it can *default* to RA. */ +#define DFC1 (DRC2 + 1) + { 5, 0, 0, + AXP_OPERAND_FPR | AXP_OPERAND_DEFAULT_FIRST, 0, 0 }, + + /* The FC field when it can *default* to RB. */ +#define DFC2 (DFC1 + 1) + { 5, 0, 0, + AXP_OPERAND_FPR | AXP_OPERAND_DEFAULT_SECOND, 0, 0 }, + + /* The unsigned 8-bit literal of Operate format insns. */ +#define LIT (DFC2 + 1) + { 8, 13, -LIT, AXP_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, AXP_OPERAND_SIGNED, 0, 0 }, + + /* The signed "23-bit" aligned displacement of Branch format insns. */ +#define BDISP (MDISP + 1) + { 21, 0, BFD_RELOC_23_PCREL_S2, + AXP_OPERAND_RELATIVE, insert_bdisp, extract_bdisp }, + + /* The 26-bit PALcode function for sys_call and sys_call / b. */ +#define PALFN (BDISP + 1) + { 25, 0, -PALFN, AXP_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 (PALFN + 1) + { 16, 0, BFD_RELOC_SW_64_HINT, + AXP_OPERAND_RELATIVE | AXP_OPERAND_DEFAULT_ZERO | AXP_OPERAND_NOOVERFLOW, + insert_jhint, extract_jhint }, + + /* The optional hint to RET/JSR_COROUTINE. */ +#define RETHINT (JMPHINT + 1) + { 16, 0, -RETHINT, + AXP_OPERAND_UNSIGNED | AXP_OPERAND_DEFAULT_ZERO, 0, 0 }, + + /* The 12-bit displacement for the ev[46] hw_{ld,st} (pal1b/pal1f) insns. */ +#define HWDISP (RETHINT + 1) + { 12, 0, -HWDISP, AXP_OPERAND_SIGNED, 0, 0 }, + + /* The 16-bit combined index/scoreboard mask for the ev6 + hw_m[ft]pr (pal19/pal1d) insns. */ +#define HWINDEX (HWDISP + 1) + { 16, 0, -HWINDEX, AXP_OPERAND_UNSIGNED, 0, 0 }, + + /* The 13-bit branch hint for the ev6 hw_jmp/jsr (pal1e) insn. */ +#define HWJMPHINT (HWINDEX + 1) + { 8, 0, -HWJMPHINT, + AXP_OPERAND_RELATIVE | AXP_OPERAND_DEFAULT_ZERO | AXP_OPERAND_NOOVERFLOW, + insert_sw4hwjhint, extract_sw4hwjhint }, + + /* for the third operand of ternary operands integer insn. */ +#define R3 (HWJMPHINT + 1) + { 5, 5, 0, AXP_OPERAND_IR, 0, 0 }, + /* The plain fp register fields */ +#define F3 (R3 + 1) + { 5, 5, 0, AXP_OPERAND_FPR, 0, 0 }, + /* sw simd settle instruction lit */ +#define FMALIT (F3 + 1) + { 5, 5, -FMALIT, AXP_OPERAND_UNSIGNED, 0, 0 }, //V1.1 +#define LMDISP (FMALIT + 1) + { 15, 0, -LMDISP, AXP_OPERAND_UNSIGNED, 0, 0 }, +#define RPIINDEX (LMDISP + 1) + { 8, 0, -RPIINDEX, AXP_OPERAND_UNSIGNED, 0, 0 }, +#define ATMDISP (RPIINDEX + 1) + { 12, 0, -ATMDISP, AXP_OPERAND_SIGNED, 0, 0 }, +#define DISP13 (ATMDISP + 1) + { 13, 13, -DISP13, AXP_OPERAND_SIGNED, 0, 0}, +#define BDISP26 (DISP13 + 1) + { 26, 0, 222, + AXP_OPERAND_RELATIVE, insert_bdisp26, extract_bdisp26 }, +#define DPFTH (BDISP26 + 1) + { 5, 21, -DPFTH, AXP_OPERAND_UNSIGNED, 0, 0} +}; + +const unsigned sw_64_num_operands = sizeof(sw_64_operands) / sizeof(*sw_64_operands); + +/* Macros used to form opcodes. */ + +/* The main opcode. */ +#define OP(x) (((x) & 0x3F) << 26) +#define OP_MASK 0xFC000000 + +/* Branch format instructions. */ +#define BRA_(oo) OP(oo) +#define BRA_MASK OP_MASK +#define BRA(oo) BRA_(oo), BRA_MASK + +#ifdef HUANGLM20171113 +/* Floating point format instructions. */ +#define FP_(oo,fff) (OP(oo) | (((fff) & 0x7FF) << 5)) +#define FP_MASK (OP_MASK | 0xFFE0) +#define FP(oo,fff) FP_(oo,fff), FP_MASK + +#else +/* Floating point format instructions. */ +#define FP_(oo,fff) (OP(oo) | (((fff) & 0xFF) << 5)) +#define FP_MASK (OP_MASK | 0x1FE0) +#define FP(oo,fff) FP_(oo,fff), FP_MASK + +#define FMA_(oo,fff) (OP(oo) | (((fff) & 0x3F) << 10 )) +#define FMA_MASK (OP_MASK | 0xFC00) +#define FMA(oo,fff) FMA_(oo,fff), FMA_MASK +#endif + +/* Memory format instructions. */ +#define MEM_(oo) OP(oo) +#define MEM_MASK OP_MASK +#define MEM(oo) MEM_(oo), MEM_MASK + +/* Memory/Func Code format instructions. */ +#define MFC_(oo,ffff) (OP(oo) | ((ffff) & 0xFFFF)) +#define MFC_MASK (OP_MASK | 0xFFFF) +#define MFC(oo,ffff) MFC_(oo,ffff), MFC_MASK + +/* Memory/Branch format instructions. */ +#define MBR_(oo,h) (OP(oo) | (((h) & 3) << 14)) +#define MBR_MASK (OP_MASK | 0xC000) +#define MBR(oo,h) MBR_(oo,h), MBR_MASK + +/* Now sw Operate format instructions is different with SW1. */ +#define OPR_(oo,ff) (OP(oo) | (((ff) & 0xFF) << 5)) +#define OPRL_(oo,ff) (OPR_((oo), (ff)) ) +#define OPR_MASK (OP_MASK | 0x1FE0) +#define OPR(oo,ff) OPR_(oo,ff), OPR_MASK +#define OPRL(oo,ff) OPRL_(oo,ff), OPR_MASK + +/* sw ternary operands Operate format instructions. */ +#define TOPR_(oo,ff) (OP(oo) | (((ff) & 0x07) << 10)) +#define TOPRL_(oo,ff) (TOPR_((oo), (ff))) +#define TOPR_MASK (OP_MASK | 0x1C00) +#define TOPR(oo,ff) TOPR_(oo,ff), TOPR_MASK +#define TOPRL(oo,ff) TOPRL_(oo,ff), TOPR_MASK + +/* sw atom instructions. */ +#define ATMEM_(oo,h) (OP(oo) | (((h) & 0xF) << 12)) +#define ATMEM_MASK (OP_MASK | 0xF000) +#define ATMEM(oo,h) ATMEM_(oo,h), ATMEM_MASK + +/* sw privilege instructions. */ +#define PRIRET_(oo,h) (OP(oo) | (((h) & 0x1) << 20)) +#define PRIRET_MASK (OP_MASK | 0x100000) +#define PRIRET(oo,h) PRIRET_(oo,h), PRIRET_MASK + +/* sw rpi_rcsr,rpi_wcsr. */ +#define CSR_(oo,ff) (OP(oo) | (((ff) & 0xFF) << 8)) +#define CSR_MASK (OP_MASK | 0xFF00) +#define CSR(oo,ff) CSR_(oo,ff), CSR_MASK + +#define PCD_(oo,ff) (OP(oo) | (ff << 25)) +#define PCD_MASK OP_MASK +#define PCD(oo,ff) PCD_(oo,ff), PCD_MASK + +/* Hardware memory (hw_{ld,st}) instructions. */ +#define HWMEM_(oo,f) (OP(oo) | (((f) & 0xF) << 12)) +#define HWMEM_MASK (OP_MASK | 0xF000) +#define HWMEM(oo,f) HWMEM_(oo,f), HWMEM_MASK + +#define LOGX_(oo,ff) (OP(oo) | (((ff) & 0x3F) << 10)) +#define LOGX_MASK (0xF0000000) +#define LOGX(oo,ff) LOGX_(oo,ff), LOGX_MASK + +/* Abbreviations for instruction subsets. */ +#define BASE AXP_OPCODE_BASE +#define CORE3 AXP_OPCODE_CORE3 +#define CORE4 AXP_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 { PALFN } +#define ARG_HWMEM { RA, HWDISP, PRB } +#define ARG_FPL { FA,LIT, DFC1 } +#define ARG_FMA { FA,FB,F3, DFC1 } +#define ARG_PREFETCH { ZA, MDISP, PRB } +#define ARG_TOPR { RA, RB,R3, DRC1 } +#define ARG_TOPRL { RA, LIT, R3,DRC1 } +#define ARG_FMAL { FA,FB,FMALIT, DFC1 } +#define ARG_ATMEM { RA, ATMDISP, PRB } +#define ARG_VUAMEM { FA, ATMDISP, PRB } +#define ARG_OPRLZ3 { RA, LIT, ZC } + +#define ARG_DISP13 {DISP13, RC} + +/* The opcode table. + + The format of the opcode table is: + + NAME OPCODE MASK { OPERANDS } + + NAME is the name of the instruction. + + OPCODE is the instruction opcode. + + MASK is the opcode mask; this is used to tell the disassembler + which bits in the actual opcode must match OPCODE. + + OPERANDS is the list of operands. + + The preceding macros merge the text of the OPCODE and MASK fields. + + The disassembler reads the table in order and prints the first + instruction which matches, so this table is sorted to put more + specific instructions before more general instructions. + + Otherwise, it is sorted by major opcode and minor function code. + */ + +const struct sw_64_opcode sw_64_opcodes[] = { + { "sys_call/b", PCD(0x00,0x00), BASE, ARG_PCD }, + { "sys_call", PCD(0x00,0x01), BASE, ARG_PCD }, + + { "call", MEM(0x01), BASE, { RA, CPRB, JMPHINT } }, + { "ret", MEM(0x02), BASE, { RA, CPRB, RETHINT } }, + { "jmp", MEM(0x03), BASE, { RA, CPRB, JMPHINT } }, + { "br", BRA(0x04), BASE, { ZA, BDISP } }, + { "br", BRA(0x04), BASE, ARG_BRA }, + { "bsr", BRA(0x05), BASE, ARG_BRA }, + { "memb", MFC(0x06,0x0000), BASE, ARG_NONE }, + { "imemb", MFC(0x06,0x0001), BASE, ARG_NONE }, + { "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 }}, + { "ldbu_a", ATMEM(0x1E,0x0), CORE4, ARG_ATMEM }, + { "ldhu_a", ATMEM(0x1E,0x1), CORE4, ARG_ATMEM }, + { "ldw_a", ATMEM(0x1E,0x2), CORE4, ARG_ATMEM }, + { "ldl_a", ATMEM(0x1E,0x3), CORE4, ARG_ATMEM }, + { "flds_a", ATMEM(0x1E,0x4), CORE4, ARG_VUAMEM }, + { "fldd_a", ATMEM(0x1E,0x5), CORE4, ARG_VUAMEM }, + { "stb_a", ATMEM(0x1E,0x6), CORE4, ARG_ATMEM }, + { "sth_a", ATMEM(0x1E,0x7), CORE4, ARG_ATMEM }, + { "stw_a", ATMEM(0x1E,0x8), CORE4, ARG_ATMEM }, + { "stl_a", ATMEM(0x1E,0x9), CORE4, ARG_ATMEM }, + { "fsts_a", ATMEM(0x1E,0xA), CORE4, ARG_VUAMEM }, + { "fstd_a", ATMEM(0x1E,0xB), CORE4, ARG_VUAMEM }, + { "dpfhr", ATMEM(0x1E,0xE), CORE4, { DPFTH, ATMDISP, PRB }}, + { "dpfhw", ATMEM(0x1E,0xF), CORE4, { DPFTH, ATMDISP, PRB }}, + + { "flushd", MEM(0x20), BASE, ARG_PREFETCH }, + { "ldbu", MEM(0x20), BASE, ARG_MEM }, + { "evictdg", MEM(0x21), BASE, ARG_PREFETCH }, + { "ldhu", MEM(0x21), BASE, ARG_MEM }, + { "s_fillcs", MEM(0x22), BASE, ARG_PREFETCH }, + { "ldw", MEM(0x22), BASE, ARG_MEM }, + { "s_fillde", MEM(0x23), BASE, ARG_PREFETCH }, + { "ldl", MEM(0x23), BASE, ARG_MEM }, + { "evictdl", MEM(0x24), BASE, ARG_PREFETCH }, + { "ldl_u", MEM(0x24), BASE, ARG_MEM }, + { "pri_ldw/p", HWMEM(0x25,0x0), BASE, ARG_HWMEM }, + { "pri_ldw/v", HWMEM(0x25,0x8), BASE, ARG_HWMEM }, + { "pri_ldl/p", HWMEM(0x25,0x1), BASE, ARG_HWMEM }, + { "pri_ldl/v", HWMEM(0x25,0x9), BASE, ARG_HWMEM }, + { "fillde", MEM(0x26), BASE, ARG_PREFETCH }, + { "flds", MEM(0x26), BASE, ARG_FMEM }, + { "fillde_e", MEM(0x27), BASE, ARG_PREFETCH }, + { "fldd", MEM(0x27), BASE, ARG_FMEM }, + + { "stb", MEM(0x28), BASE, ARG_MEM }, + { "sth", MEM(0x29), BASE, ARG_MEM }, + { "stw", MEM(0x2A), BASE, ARG_MEM }, + { "stl", MEM(0x2B), BASE, ARG_MEM }, + { "stl_u", MEM(0x2C), BASE, ARG_MEM }, + { "pri_stw/p", HWMEM(0x2D,0x0), BASE, ARG_HWMEM }, + { "pri_stw/v", HWMEM(0x2D,0x8), BASE, ARG_HWMEM }, + { "pri_stl/p", HWMEM(0x2D,0x1), BASE, ARG_HWMEM }, + { "pri_stl/v", HWMEM(0x2D,0x9), BASE, ARG_HWMEM }, + { "fsts", MEM(0x2E), BASE, ARG_FMEM }, + { "fstd", MEM(0x2F), BASE, ARG_FMEM }, + { "beq", BRA(0x30), BASE, ARG_BRA }, + { "bne", BRA(0x31), BASE, ARG_BRA }, + { "blt", BRA(0x32), BASE, ARG_BRA }, + { "ble", BRA(0x33), BASE, ARG_BRA }, + { "bgt", BRA(0x34), BASE, ARG_BRA }, + { "bge", BRA(0x35), BASE, ARG_BRA }, + { "blbc", BRA(0x36), BASE, ARG_BRA }, + { "blbs", BRA(0x37), BASE, ARG_BRA }, + + { "fbeq", BRA(0x38), BASE, ARG_FBRA }, + { "fbne", BRA(0x39), BASE, ARG_FBRA }, + { "fblt", BRA(0x3A), BASE, ARG_FBRA }, + { "fble", BRA(0x3B), BASE, ARG_FBRA }, + { "fbgt", BRA(0x3C), BASE, ARG_FBRA }, + { "fbge", BRA(0x3D), BASE, ARG_FBRA }, + { "ldi", MEM(0x3E), BASE, ARG_MEM }, + { "ldih", MEM(0x3F), BASE, ARG_MEM }, +}; + +const unsigned sw_64_num_opcodes = sizeof(sw_64_opcodes) / sizeof(*sw_64_opcodes); + +/* OSF register names. */ + +static const char * const osf_regnames[64] = { + "v0", "t0", "t1", "t2", "t3", "t4", "t5", "t6", + "t7", "s0", "s1", "s2", "s3", "s4", "s5", "fp", + "a0", "a1", "a2", "a3", "a4", "a5", "t8", "t9", + "t10", "t11", "ra", "t12", "at", "gp", "sp", "zero", + "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7", + "$f8", "$f9", "$f10", "$f11", "$f12", "$f13", "$f14", "$f15", + "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23", + "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31" +}; + +/* VMS register names. */ + +static const char * const vms_regnames[64] = { + "R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7", + "R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15", + "R16", "R17", "R18", "R19", "R20", "R21", "R22", "R23", + "R24", "AI", "RA", "PV", "AT", "FP", "SP", "RZ", + "F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7", + "F8", "F9", "F10", "F11", "F12", "F13", "F14", "F15", + "F16", "F17", "F18", "F19", "F20", "F21", "F22", "F23", + "F24", "F25", "F26", "F27", "F28", "F29", "F30", "FZ" +}; + +int print_insn_sw_64(bfd_vma memaddr, struct disassemble_info *info) +{ + static const struct sw_64_opcode *opcode_index[AXP_NOPS + 1]; + const char * const * regnames; + const struct sw_64_opcode *opcode, *opcode_end; + const unsigned char *opindex; + unsigned insn, op, isa_mask; + int need_comma; + + /* Initialize the majorop table the first time through */ + if (!opcode_index[0]) { + opcode = sw_64_opcodes; + opcode_end = opcode + sw_64_num_opcodes; + + for (op = 0; op < AXP_NOPS; ++op) { + opcode_index[op] = opcode; + if ((AXP_LITOP (opcode->opcode) != 0x10) && (AXP_LITOP (opcode->opcode) != 0x11)) { + while (opcode < opcode_end && op == AXP_OP (opcode->opcode)) + ++opcode; + } else { + while (opcode < opcode_end && op == AXP_LITOP (opcode->opcode)) + ++opcode; + } + } + opcode_index[op] = opcode; + } + + if (info->flavour == bfd_target_evax_flavour) + regnames = vms_regnames; + else + regnames = osf_regnames; + isa_mask = AXP_OPCODE_NOPAL; + switch (info->mach) { + case bfd_mach_sw_64_core3: + isa_mask |= AXP_OPCODE_BASE | AXP_OPCODE_CORE3; + break; + case bfd_mach_sw_64_core4: + isa_mask |= AXP_OPCODE_BASE | AXP_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 ((AXP_LITOP (insn) == 0x10) || (AXP_LITOP (insn) == 0x11)) + op = AXP_LITOP (insn); + else if ((AXP_OP(insn) & 0x3C) == 0x14 ) + op = 0x14; + else + op = AXP_OP (insn); + + /* Find the first match in the opcode table. */ + opcode_end = opcode_index[op + 1]; + for (opcode = opcode_index[op]; opcode < opcode_end; ++opcode) { + if ((insn ^ opcode->opcode) & opcode->mask) + continue; + + if (!(opcode->flags & isa_mask)) + continue; + + /* Make two passes over the operands. First see if any of them + have extraction functions, and, if they do, make sure the + instruction is valid. */ + { + int invalid = 0; + for (opindex = opcode->operands; *opindex != 0; opindex++) { + const struct sw_64_operand *operand = sw_64_operands + *opindex; + if (operand->extract) + (*operand->extract) (insn, &invalid); + } + if (invalid) + continue; + } + + /* The instruction is valid. */ + goto found; + } + + /* No instruction found */ + (*info->fprintf_func) (info->stream, ".long %#08x", insn); + + return 4; + +found: + if (!strncmp("sys_call",opcode->name,8)) { + if (insn & (0x1 << 25)) + (*info->fprintf_func) (info->stream, "%s", "sys_call"); + else + (*info->fprintf_func) (info->stream, "%s", "sys_call/b"); + } else + (*info->fprintf_func) (info->stream, "%s", opcode->name); + + /* get zz[7:6] and zz[5:0] to form truth for vlog */ + if (!strcmp(opcode->name, "vlog")) + { + unsigned int truth; + char tr[4]; + truth=(AXP_OP(insn) & 3) << 6; + truth = truth | ((insn & 0xFC00) >> 10); + sprintf(tr,"%x",truth); + (*info->fprintf_func) (info->stream, "%s", tr); + } + if (opcode->operands[0] != 0) + (*info->fprintf_func) (info->stream, "\t"); + + /* Now extract and print the operands. */ + need_comma = 0; + for (opindex = opcode->operands; *opindex != 0; opindex++) { + const struct sw_64_operand *operand = sw_64_operands + *opindex; + int value; + + /* Operands that are marked FAKE are simply ignored. We + already made sure that the extract function considered + the instruction to be valid. */ + if ((operand->flags & AXP_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 & AXP_OPERAND_SIGNED) { + int signbit = 1 << (operand->bits - 1); + value = (value ^ signbit) - signbit; + } + } + + if (need_comma && + ((operand->flags & (AXP_OPERAND_PARENS | AXP_OPERAND_COMMA)) + != AXP_OPERAND_PARENS)) { + (*info->fprintf_func) (info->stream, ","); + } + if (operand->flags & AXP_OPERAND_PARENS) + (*info->fprintf_func) (info->stream, "("); + + /* Print the operand as directed by the flags. */ + if (operand->flags & AXP_OPERAND_IR) + (*info->fprintf_func) (info->stream, "%s", regnames[value]); + else if (operand->flags & AXP_OPERAND_FPR) + (*info->fprintf_func) (info->stream, "%s", regnames[value + 32]); + else if (operand->flags & AXP_OPERAND_RELATIVE) + (*info->print_address_func) (memaddr + 4 + value, info); + else if (operand->flags & AXP_OPERAND_SIGNED) + (*info->fprintf_func) (info->stream, "%d", value); + else + (*info->fprintf_func) (info->stream, "%#x", value); + + if (operand->flags & AXP_OPERAND_PARENS) + (*info->fprintf_func) (info->stream, ")"); + need_comma = 1; + } + + return 4; +} diff --git a/disas/sw64.h b/disas/sw64.h new file mode 100755 index 0000000000000000000000000000000000000000..b3f302d734ae3ded3fdcac924a178ba69101b643 --- /dev/null +++ b/disas/sw64.h @@ -0,0 +1,246 @@ +/* sw_64.h -- Header file for Sw_64 opcode table + Copyright (C) 1996-2015 Free Software Foundation, Inc. + Contributed by Richard Henderson , + patterned after the PPC opcode table written by Ian Lance Taylor. + + This file is part of GDB, GAS, and the GNU binutils. + + GDB, GAS, and the GNU binutils are free software; you can redistribute + them and/or modify them 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. + + GDB, GAS, and the GNU binutils are distributed in the hope that they + 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 COPYING3. If not, write to the Free + Software Foundation, 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ + +#ifndef OPCODE_SW_64_H +#define OPCODE_SW_64_H + +/* The opcode table is an array of struct sw_64_opcode. */ + +struct sw_64_opcode +{ + /* The opcode name. */ + const char *name; + + /* The opcode itself. Those bits which will be filled in with + operands are zeroes. */ + unsigned opcode; + + /* The opcode mask. This is used by the disassembler. This is a + mask containing ones indicating those bits which must match the + opcode field, and zeroes indicating those bits which need not + match (and are presumably filled in by operands). */ + unsigned mask; + + /* One bit flags for the opcode. These are primarily used to + indicate specific processors and environments support the + instructions. The defined values are listed below. */ + unsigned flags; + + /* An array of operand codes. Each code is an index into the + operand table. They appear in the order which the operands must + appear in assembly code, and are terminated by a zero. */ +#ifdef XWB20161025 + unsigned char operands[4]; +#else + unsigned char operands[5]; +#endif +}; + +/* The table itself is sorted by major opcode number, and is otherwise + in the order in which the disassembler should consider + instructions. */ +extern const struct sw_64_opcode sw_64_opcodes[]; +extern const unsigned sw_64_num_opcodes; + +/* Values defined for the flags field of a struct sw_64_opcode. */ + +/* CPU Availability */ +#define AXP_OPCODE_BASE 0x0001 /* Base architecture -- all cpus. */ +#define AXP_OPCODE_EV4 0x0002 /* EV4 specific PALcode insns. */ +#define AXP_OPCODE_EV5 0x0004 /* EV5 specific PALcode insns. */ +#define AXP_OPCODE_EV6 0x0008 /* EV6 specific PALcode insns. */ +#define AXP_OPCODE_BWX 0x0100 /* Byte/word extension (amask bit 0). */ +#define AXP_OPCODE_CIX 0x0200 /* "Count" extension (amask bit 1). */ +#define AXP_OPCODE_MAX 0x0400 /* Multimedia extension (amask bit 8). */ + +#ifndef XWB20161017 +#define AXP_OPCODE_SW4 0x0800 /* SW4 insns. */ +#define AXP_LITOP(i) (((i) >> 26) & 0x3D) +#endif + +#define AXP_OPCODE_NOPAL (~(AXP_OPCODE_EV4|AXP_OPCODE_EV5|AXP_OPCODE_EV6)) + +/* A macro to extract the major opcode from an instruction. */ +#define AXP_OP(i) (((i) >> 26) & 0x3F) + +/* The total number of major opcodes. */ +#define AXP_NOPS 0x40 + + +/* The operands table is an array of struct sw_64_operand. */ + +struct sw_64_operand +{ + /* The number of bits in the operand. */ + unsigned int bits : 5; + + /* How far the operand is left shifted in the instruction. */ + unsigned int shift : 5; + + /* The default relocation type for this operand. */ + signed int default_reloc : 16; + + /* One bit syntax flags. */ + unsigned int flags : 16; + + /* Insertion function. This is used by the assembler. To insert an + operand value into an instruction, check this field. + + If it is NULL, execute + i |= (op & ((1 << o->bits) - 1)) << o->shift; + (i is the instruction which we are filling in, o is a pointer to + this structure, and op is the opcode value; this assumes twos + complement arithmetic). + + If this field is not NULL, then simply call it with the + instruction and the operand value. It will return the new value + of the instruction. If the ERRMSG argument is not NULL, then if + the operand value is illegal, *ERRMSG will be set to a warning + string (the operand will be inserted in any case). If the + operand value is legal, *ERRMSG will be unchanged (most operands + can accept any value). */ + unsigned (*insert) (unsigned instruction, int op, const char **errmsg); + + /* Extraction function. This is used by the disassembler. To + extract this operand type from an instruction, check this field. + + If it is NULL, compute + op = ((i) >> o->shift) & ((1 << o->bits) - 1); + if ((o->flags & AXP_OPERAND_SIGNED) != 0 + && (op & (1 << (o->bits - 1))) != 0) + op -= 1 << o->bits; + (i is the instruction, o is a pointer to this structure, and op + is the result; this assumes twos complement arithmetic). + + If this field is not NULL, then simply call it with the + instruction value. It will return the value of the operand. If + the INVALID argument is not NULL, *INVALID will be set to + non-zero if this operand type can not actually be extracted from + this operand (i.e., the instruction does not match). If the + operand is valid, *INVALID will not be changed. */ + int (*extract) (unsigned instruction, int *invalid); +}; + +/* Elements in the table are retrieved by indexing with values from + the operands field of the sw_64_opcodes table. */ + +extern const struct sw_64_operand sw_64_operands[]; +extern const unsigned sw_64_num_operands; +/* Values defined for the flags field of a struct sw_64_operand. */ + +/* Mask for selecting the type for typecheck purposes */ +#define AXP_OPERAND_TYPECHECK_MASK \ + (AXP_OPERAND_PARENS | AXP_OPERAND_COMMA | AXP_OPERAND_IR | \ + AXP_OPERAND_FPR | AXP_OPERAND_RELATIVE | AXP_OPERAND_SIGNED | \ + AXP_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 AXP_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 AXP_OPERAND_PARENS 02 + +/* Used in combination with PARENS, this supresses the supression of + the comma. This is used for "jmp Ra,(Rb),hint". */ +#define AXP_OPERAND_COMMA 04 + +/* This operand names an integer register. */ +#define AXP_OPERAND_IR 010 + +/* This operand names a floating point register. */ +#define AXP_OPERAND_FPR 020 + +/* This operand is a relative branch displacement. The disassembler + prints these symbolically if possible. */ +#define AXP_OPERAND_RELATIVE 040 + +/* This operand takes signed values. */ +#define AXP_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 AXP_OPERAND_UNSIGNED 0200 + +/* Supress overflow detection on this field. This is used for hints. */ +#define AXP_OPERAND_NOOVERFLOW 0400 + +/* Mask for optional argument default value. */ +#define AXP_OPERAND_OPTIONAL_MASK 07000 + +/* This operand defaults to zero. This is used for jump hints. */ +#define AXP_OPERAND_DEFAULT_ZERO 01000 + +/* This operand should default to the first (real) operand and is used + in conjunction with AXP_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 AXP_OPERAND_DEFAULT_FIRST 02000 + +/* Similarly, this operand should default to the second (real) operand. + This allows "negl $0" instead of "negl $0,$0". */ +#define AXP_OPERAND_DEFAULT_SECOND 04000 + + +/* Register common names */ + +#define AXP_REG_V0 0 +#define AXP_REG_T0 1 +#define AXP_REG_T1 2 +#define AXP_REG_T2 3 +#define AXP_REG_T3 4 +#define AXP_REG_T4 5 +#define AXP_REG_T5 6 +#define AXP_REG_T6 7 +#define AXP_REG_T7 8 +#define AXP_REG_S0 9 +#define AXP_REG_S1 10 +#define AXP_REG_S2 11 +#define AXP_REG_S3 12 +#define AXP_REG_S4 13 +#define AXP_REG_S5 14 +#define AXP_REG_FP 15 +#define AXP_REG_A0 16 +#define AXP_REG_A1 17 +#define AXP_REG_A2 18 +#define AXP_REG_A3 19 +#define AXP_REG_A4 20 +#define AXP_REG_A5 21 +#define AXP_REG_T8 22 +#define AXP_REG_T9 23 +#define AXP_REG_T10 24 +#define AXP_REG_T11 25 +#define AXP_REG_RA 26 +#define AXP_REG_PV 27 +#define AXP_REG_T12 27 +#define AXP_REG_AT 28 +#define AXP_REG_GP 29 +#define AXP_REG_SP 30 +#define AXP_REG_ZERO 31 + +#endif /* OPCODE_SW_64_H */ 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/meson.build b/hw/meson.build index b3366c888ef61b3093091c260d23926c0524ca6e..f39c1f7e7013231d7287b075c69de58ba183b850 100644 --- a/hw/meson.build +++ b/hw/meson.build @@ -62,5 +62,6 @@ subdir('s390x') subdir('sh4') subdir('sparc') subdir('sparc64') +subdir('sw64') subdir('tricore') subdir('xtensa') diff --git a/hw/rtc/sun4v-rtc.c b/hw/rtc/sun4v-rtc.c index e037acd1b56d723f91fa8871f9fd491decd59c1d..58a0cff48321defa71f8577ca3604747da7fdede 100644 --- a/hw/rtc/sun4v-rtc.c +++ b/hw/rtc/sun4v-rtc.c @@ -32,10 +32,17 @@ static uint64_t sun4v_rtc_read(void *opaque, hwaddr addr, unsigned size) { uint64_t val = get_clock_realtime() / NANOSECONDS_PER_SECOND; +#if defined(__sw_64__) + if (addr & 4ULL) { + /* accessing the high 32 bits */ + val >>= 32; + } +#else if (!(addr & 4ULL)) { /* accessing the high 32 bits */ val >>= 32; } +#endif trace_sun4v_rtc_read(addr, val); return val; } @@ -49,7 +56,11 @@ static void sun4v_rtc_write(void *opaque, hwaddr addr, static const MemoryRegionOps sun4v_rtc_ops = { .read = sun4v_rtc_read, .write = sun4v_rtc_write, +#if defined(__sw_64__) + .endianness = DEVICE_LITTLE_ENDIAN, +#else .endianness = DEVICE_NATIVE_ENDIAN, +#endif }; void sun4v_rtc_init(hwaddr addr) diff --git a/hw/sw64/Kconfig b/hw/sw64/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..f3ce2018757084134a190dd6942e0b031318ade0 --- /dev/null +++ b/hw/sw64/Kconfig @@ -0,0 +1,23 @@ +config CORE3 + bool + imply PCI_DEVICES + imply TEST_DEVICES + imply E1000_PCI + select PCI_EXPRESS + select SUN4V_RTC + select VIRTIO_MMIO + select SERIAL + select IDE_CMD646 + select VIRTIO_VGA + +config CORE4 + bool + imply PCI_DEVICES + imply TEST_DEVICES + imply E1000_PCI + select PCI_EXPRESS + select SUN4V_RTC + select VIRTIO_MMIO + select SERIAL + select IDE_CMD646 + select VIRTIO_VGA diff --git a/hw/sw64/Makefile.objs b/hw/sw64/Makefile.objs new file mode 100644 index 0000000000000000000000000000000000000000..f096f4f2883330366be7655b841b6e09d8f63d47 --- /dev/null +++ b/hw/sw64/Makefile.objs @@ -0,0 +1,2 @@ +obj-y += core3.o core3_board.o +obj-y += core4.o core4_board.o diff --git a/hw/sw64/core.h b/hw/sw64/core.h new file mode 100644 index 0000000000000000000000000000000000000000..e92fc2b7cfeff870e354e90c09c78d8fa0dc337e --- /dev/null +++ b/hw/sw64/core.h @@ -0,0 +1,20 @@ +#ifndef HW_SW64_SYS_H +#define HW_SW64_SYS_H + +typedef struct boot_params { + unsigned long initrd_size; /* size of initrd */ + unsigned long initrd_start; /* logical address of initrd */ + unsigned long dtb_start; /* logical address of dtb */ + unsigned long efi_systab; /* logical address of EFI system table */ + unsigned long efi_memmap; /* logical address of EFI memory map */ + unsigned long efi_memmap_size; /* size of EFI memory map */ + unsigned long efi_memdesc_size; /* size of an EFI memory map descriptor */ + unsigned long efi_memdesc_version; /* memory descriptor version */ + unsigned long cmdline; /* logical address of cmdline */ +} BOOT_PARAMS; + +void core4_board_init(SW64CPU *cpus[4], MemoryRegion *ram); +void core3_board_init(SW64CPU *cpus[4], MemoryRegion *ram); +#endif + +#define MAX_CPUS 64 diff --git a/hw/sw64/core3.c b/hw/sw64/core3.c new file mode 100644 index 0000000000000000000000000000000000000000..3b2fb18b97037b0f6fa90ab6ef5cefbe59a94118 --- /dev/null +++ b/hw/sw64/core3.c @@ -0,0 +1,123 @@ +/* + * QEMU CORE3 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/ide.h" +#include "hw/char/serial.h" +#include "qemu/cutils.h" +#include "ui/console.h" +#include "core.h" + +static uint64_t cpu_sw64_virt_to_phys(void *opaque, uint64_t addr) +{ + return addr &= ~0xffffffff80000000 ; +} + +static void core3_cpu_reset(void *opaque) +{ + SW64CPU *cpu = opaque; + + cpu_reset(CPU(cpu)); +} + +static void core3_init(MachineState *machine) +{ + ram_addr_t ram_size = machine->ram_size; + SW64CPU *cpus[machine->smp.max_cpus]; + long i, size; + const char *kernel_filename = machine->kernel_filename; + const char *kernel_cmdline = machine->kernel_cmdline; + char *hmcode_filename; + char *uefi_filename; + uint64_t hmcode_entry, hmcode_low, hmcode_high; + uint64_t kernel_entry, kernel_low, kernel_high; + BOOT_PARAMS *core3_boot_params = g_new0(BOOT_PARAMS, 1); + uint64_t param_offset; + + memset(cpus, 0, sizeof(cpus)); + + for (i = 0; i < machine->smp.cpus; ++i) { + cpus[i] = SW64_CPU(cpu_create(machine->cpu_type)); + cpus[i]->env.csr[CID] = i; + qemu_register_reset(core3_cpu_reset, cpus[i]); + } + core3_board_init(cpus, machine->ram); + rom_add_blob_fixed("ram_size", (char *)&ram_size, 0x8, 0x2040); + + param_offset = 0x90B000UL; + core3_boot_params->cmdline = param_offset | 0xfff0000000000000UL; + rom_add_blob_fixed("core3_boot_params", (core3_boot_params), 0x48, 0x90A100); + + hmcode_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, kvm_enabled() ? "core3-reset":"core3-hmcode"); + if (hmcode_filename == NULL) { + if (kvm_enabled()) + error_report("no core3-reset provided"); + else + error_report("no core3-hmcode provided"); + exit(1); + } + size = load_elf(hmcode_filename, NULL, cpu_sw64_virt_to_phys, NULL, + &hmcode_entry, &hmcode_low, &hmcode_high, NULL, 0, EM_SW64, 0, 0); + if (size < 0) { + if (kvm_enabled()) + error_report("could not load core3-reset: '%s'", hmcode_filename); + else + error_report("could not load core3-hmcode: '%s'", hmcode_filename); + exit(1); + } + g_free(hmcode_filename); + + /* Start all cpus at the PALcode RESET entry point. */ + for (i = 0; i < machine->smp.cpus; ++i) { + cpus[i]->env.pc = hmcode_entry; + cpus[i]->env.hm_entry = hmcode_entry; + } + + if (!kernel_filename) { + uefi_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, "uefi-bios-sw"); + load_image_targphys(uefi_filename, 0x2f00000UL, -1); + g_free(uefi_filename); + } else { + /* Load a kernel. */ + size = load_elf(kernel_filename, NULL, cpu_sw64_virt_to_phys, NULL, + &kernel_entry, &kernel_low, &kernel_high, NULL, 0, EM_SW64, 0,0); + if (size < 0) { + error_report("could not load kernel '%s'", kernel_filename); + exit(1); + } + cpus[0]->env.trap_arg1 = kernel_entry; + if (kernel_cmdline) + pstrcpy_targphys("cmdline", param_offset, 0x400, kernel_cmdline); + } +} + +static void board_reset(MachineState *state) +{ + qemu_devices_reset(); +} + +static void core3_machine_init(MachineClass *mc) +{ + mc->desc = "core3 BOARD"; + mc->init = core3_init; + mc->block_default_type = IF_IDE; + mc->max_cpus = MAX_CPUS; + mc->is_default = 0; + mc->reset = board_reset; + mc->default_cpu_type = SW64_CPU_TYPE_NAME("core3"); + mc->default_ram_id = "ram"; +} + +DEFINE_MACHINE("core3", core3_machine_init) diff --git a/hw/sw64/core3_board.c b/hw/sw64/core3_board.c new file mode 100644 index 0000000000000000000000000000000000000000..ac459fe13cf0a390e63c26df1466bfb55aa5dbcd --- /dev/null +++ b/hw/sw64/core3_board.c @@ -0,0 +1,502 @@ +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "cpu.h" +#include "core.h" +#include "hw/hw.h" +#include "hw/boards.h" +#include "sysemu/sysemu.h" +#include "exec/address-spaces.h" +#include "hw/pci/pci_host.h" +#include "hw/pci/pci.h" +#include "hw/char/serial.h" +#include "hw/irq.h" +#include "net/net.h" +#include "hw/usb.h" +#include "hw/ide/pci.h" +#include "hw/ide/ahci.h" +#include "sysemu/numa.h" +#include "sysemu/kvm.h" +#include "hw/rtc/sun4v-rtc.h" +#include "hw/pci/msi.h" +#include "hw/sw64/sw64_iommu.h" + +#define MAX_CPUS 64 +#define TYPE_SWBOARD_PCI_HOST_BRIDGE "core_board-pcihost" +#define SWBOARD_PCI_HOST_BRIDGE(obj) \ + OBJECT_CHECK(BoardState, (obj), TYPE_SWBOARD_PCI_HOST_BRIDGE) + +#define MAX_IDE_BUS 2 + +typedef struct SWBoard { + SW64CPU *cpu[MAX_CPUS]; +} SWBoard; + +typedef struct BoardState { + PCIHostState parent_obj; + + SWBoard sboard; + uint64_t expire_time; +} BoardState; + +typedef struct TimerState { + void *opaque; + int order; +} TimerState; + +#ifndef CONFIG_KVM +static void swboard_alarm_timer(void *opaque) +{ + TimerState *ts = (TimerState *)((uintptr_t)opaque); + BoardState *bs = (BoardState *)((uintptr_t)ts->opaque); + int64_t current_time; + + int cpu = ts->order; + current_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + cpu_interrupt(CPU(bs->sboard.cpu[cpu]), CPU_INTERRUPT_TIMER); + timer_mod(bs->sboard.cpu[cpu]->alarm_timer, bs->expire_time + current_time); +} +#endif + +static uint64_t convert_bit(int n) +{ + uint64_t ret = (1UL << n) - 1; + + if (n == 64) + ret = 0xffffffffffffffffUL; + return ret; +} + +static uint64_t mcu_read(void *opaque, hwaddr addr, unsigned size) +{ + MachineState *ms = MACHINE(qdev_get_machine()); + unsigned int smp_cpus = ms->smp.cpus; + uint64_t ret = 0; + switch (addr) { + case 0x0000: + /* CG_ONLINE */ + { + int i; + for (i = 0; i < smp_cpus; i = i + 4) + ret |= (1UL << i); + } + break; + /*IO_START*/ + case 0x1300: + ret = 0x1; + break; + case 0x3780: + /* MC_ONLINE */ + ret = convert_bit(smp_cpus); + break; + case 0x0900: + /* CPUID */ + ret = 0; + break; + case 0x1180: + /* LONGTIME */ + ret = qemu_clock_get_ns(QEMU_CLOCK_HOST) / 80; + break; + case 0x4900: + /* MC_CONFIG */ + break; + case 0x0780: + /* CORE_ONLINE */ + ret = convert_bit(smp_cpus); + break; + case 0x0680: + /* INIT_CTL */ + ret = 0x000003AE00000D28; + break; + default: + fprintf(stderr, "Unsupported MCU addr: 0x%04lx\n", addr); + return -1; + } + return ret; +} + +static void mcu_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) +{ +#ifndef CONFIG_KVM +#ifdef CONFIG_DUMP_PRINTK + uint64_t print_addr; + uint32_t len; + int i; + if (addr == 0x40000) { + print_addr = val & 0x7fffffff; + len = (uint32_t)(val >> 32); + uint8_t *buf; + buf = malloc(len + 10); + memset(buf, 0, len + 10); + cpu_physical_memory_rw(print_addr, buf, len, 0); + for (i = 0; i < len; i++) + printf("%c", buf[i]); + + free(buf); + return; + } +#endif +#endif +} + +static const MemoryRegionOps mcu_ops = { + .read = mcu_read, + .write = mcu_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = + { + .min_access_size = 8, + .max_access_size = 8, + }, + .impl = + { + .min_access_size = 8, + .max_access_size = 8, + }, +}; + +static uint64_t intpu_read(void *opaque, hwaddr addr, unsigned size) +{ + uint64_t ret = 0; +#ifndef CONFIG_KVM + switch (addr) { + case 0x180: + /* LONGTIME */ + ret = qemu_clock_get_ns(QEMU_CLOCK_HOST) / 80; + break; + } +#endif + return ret; +} + +static void intpu_write(void *opaque, hwaddr addr, uint64_t val, + unsigned size) +{ +#ifndef CONFIG_KVM + MachineState *ms = MACHINE(qdev_get_machine()); + unsigned int smp_cpus = ms->smp.cpus; + int i; + BoardState *bs = (BoardState *)opaque; + SW64CPU *cpu; + switch (addr) { + case 0x00: + val &= 0x1f; + cpu = bs->sboard.cpu[val]; + cpu->env.csr[II_REQ] = 0x100000; + cpu_interrupt(CPU(cpu),CPU_INTERRUPT_IIMAIL); + break; + case (0x3 << 7): + bs->expire_time = (int64_t)(1000000000 / 250); + for (i = 0; i < smp_cpus; i++) { + cpu = bs->sboard.cpu[i]; + if (cpu) timer_mod(cpu->alarm_timer, bs->expire_time); + } + break; + default: + fprintf(stderr, "Unsupported IPU addr: 0x%04lx\n", addr); + break; + } +#endif +} + +static const MemoryRegionOps intpu_ops = { + .read = intpu_read, + .write = intpu_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = + { + .min_access_size = 8, + .max_access_size = 8, + }, + .impl = + { + .min_access_size = 8, + .max_access_size = 8, + }, +}; + +static MemTxResult msi_read(void *opaque, hwaddr addr, + uint64_t *data, unsigned size, + MemTxAttrs attrs) +{ + return MEMTX_OK; +} + +MemTxResult msi_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size, + MemTxAttrs attrs) +{ + int ret = 0; + MSIMessage msg = {}; + + msg.address = (uint64_t) addr + 0x8000fee00000; + msg.data = (uint32_t) value; + + ret = kvm_irqchip_send_msi(kvm_state, msg); + if (ret < 0) { + fprintf(stderr, "KVM: injection failed, MSI lost (%s)\n", + strerror(-ret)); + } + return MEMTX_OK; +} + +static const MemoryRegionOps msi_ops = { + .read_with_attrs = msi_read, + .write_with_attrs = msi_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = + { + .min_access_size = 1, + .max_access_size = 8, + }, + .impl = + { + .min_access_size = 1, + .max_access_size = 8, + }, +}; + +static uint64_t ignore_read(void *opaque, hwaddr addr, unsigned size) +{ + return 1; +} + +static void ignore_write(void *opaque, hwaddr addr, uint64_t v, unsigned size) +{ +} + +const MemoryRegionOps core3_pci_ignore_ops = { + .read = ignore_read, + .write = ignore_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = + { + .min_access_size = 1, + .max_access_size = 8, + }, + .impl = + { + .min_access_size = 1, + .max_access_size = 8, + }, +}; + +static uint64_t config_read(void *opaque, hwaddr addr, unsigned size) +{ + PCIBus *b = opaque; + uint32_t trans_addr = 0; + trans_addr |= ((addr >> 16) & 0xffff) << 8; + trans_addr |= (addr & 0xff); + return pci_data_read(b, trans_addr, size); +} + +static void config_write(void *opaque, hwaddr addr, uint64_t val, + unsigned size) +{ + PCIBus *b = opaque; + uint32_t trans_addr = 0; + trans_addr |= ((addr >> 16) & 0xffff) << 8; + trans_addr |= (addr & 0xff); + pci_data_write(b, trans_addr, val, size); +} + +const MemoryRegionOps core3_pci_config_ops = { + .read = config_read, + .write = config_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = + { + .min_access_size = 1, + .max_access_size = 8, + }, + .impl = + { + .min_access_size = 1, + .max_access_size = 8, + }, +}; + +static void cpu_irq_change(SW64CPU *cpu, uint64_t req) +{ + if (cpu != NULL) { + CPUState *cs = CPU(cpu); + if (req) + cpu_interrupt(cs, CPU_INTERRUPT_HARD); + else + cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); + } +} + +static void swboard_set_irq(void *opaque, int irq, int level) +{ + BoardState *bs = opaque; + SW64CPU *cpu; + int i; + if (kvm_enabled()) { + kvm_set_irq(kvm_state, irq, level); + return; + } + for (i = 0; i < 1; i++) { + cpu = bs->sboard.cpu[i]; + if (cpu != NULL) { + CPUState *cs = CPU(cpu); + if (level) { + cpu->env.csr[C3_INT_STAT] |= (1UL << irq); + cpu->irq = irq; + cpu_interrupt(cs, CPU_INTERRUPT_PCIE); + } else { + cpu_reset_interrupt(cs, CPU_INTERRUPT_PCIE); + } + } + } + +} + +static int swboard_map_irq(PCIDevice *d, int irq_num) +{ + /* In fact,the return value is the interrupt type passed to kernel, + * so it must keep same with the type in do_entInt in kernel. + */ + return 16; +} + +static void serial_set_irq(void *opaque, int irq, int level) +{ + BoardState *bs = (BoardState *)opaque; + MachineState *ms = MACHINE(qdev_get_machine()); + unsigned int smp_cpus = ms->smp.cpus; + int i; + if (kvm_enabled()) { + kvm_set_irq(kvm_state, irq, level); + return; + } + if (level == 0) + return; + + for (i = 0; i < smp_cpus; i++) { + if (bs->sboard.cpu[i]) + cpu_irq_change(bs->sboard.cpu[i], 1); + } +} + +void core3_board_init(SW64CPU *cpus[MAX_CPUS], MemoryRegion *ram) +{ + DeviceState *dev; + BoardState *bs; +#ifndef CONFIG_KVM + TimerState *ts; +#endif + MemoryRegion *io_mcu = g_new(MemoryRegion, 1); + MemoryRegion *io_intpu = g_new(MemoryRegion, 1); + MemoryRegion *msi_ep = g_new(MemoryRegion, 1); + qemu_irq serial_irq; + uint64_t MB = 1024 * 1024; + MemoryRegion *mem_ep = g_new(MemoryRegion, 1); + MemoryRegion *mem_ep64 = g_new(MemoryRegion, 1); + MemoryRegion *conf_piu0 = g_new(MemoryRegion, 1); + MemoryRegion *io_ep = g_new(MemoryRegion, 1); + + MachineState *ms = MACHINE(qdev_get_machine()); + unsigned int smp_cpus = ms->smp.cpus; + + PCIBus *b; + PCIHostState *phb; + uint64_t GB = 1024 * MB; + + int i; + dev = qdev_new(TYPE_SWBOARD_PCI_HOST_BRIDGE); + phb = PCI_HOST_BRIDGE(dev); + bs = SWBOARD_PCI_HOST_BRIDGE(dev); + +#ifdef CONFIG_KVM + if (kvm_has_gsi_routing()) + msi_nonbroken = true; +#endif + +#ifndef CONFIG_KVM + bs->expire_time = (int64_t) (1000000000 / 250); +#endif + for (i = 0; i < smp_cpus; ++i) { + if (cpus[i] == NULL) + continue; + bs->sboard.cpu[i] = cpus[i]; +#ifndef CONFIG_KVM + ts = g_new(TimerState, 1); + ts->opaque = (void *) ((uintptr_t)bs); + ts->order = i; + cpus[i]->alarm_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &swboard_alarm_timer, ts); + timer_mod(cpus[i]->alarm_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + bs->expire_time); +#endif + } + memory_region_add_subregion(get_system_memory(), 0, ram); + + memory_region_init_io(io_mcu, NULL, &mcu_ops, bs, "io_mcu", 16 * MB); + memory_region_add_subregion(get_system_memory(), 0x803000000000ULL, io_mcu); + + memory_region_init_io(io_intpu, NULL, &intpu_ops, bs, "io_intpu", 1 * MB); + memory_region_add_subregion(get_system_memory(), 0x802a00000000ULL, + io_intpu); + + memory_region_init_io(msi_ep, NULL, &msi_ops, bs, "msi_ep", 1 * MB); + memory_region_add_subregion(get_system_memory(), 0x8000fee00000ULL, msi_ep); + + memory_region_init(mem_ep, OBJECT(bs), "pci0-mem", 0x890000000000ULL); + memory_region_add_subregion(get_system_memory(), 0x880000000000ULL, mem_ep); + + memory_region_init_alias(mem_ep64, NULL, "mem_ep64", mem_ep, 0x888000000000ULL, 1ULL << 39); + memory_region_add_subregion(get_system_memory(), 0x888000000000ULL, mem_ep64); + + memory_region_init_io(io_ep, OBJECT(bs), &core3_pci_ignore_ops, NULL, + "pci0-io-ep", 4 * GB); + + memory_region_add_subregion(get_system_memory(), 0x880100000000ULL, io_ep); + b = pci_register_root_bus(dev, "pcie.0", swboard_set_irq, swboard_map_irq, bs, + mem_ep, io_ep, 0, 537, TYPE_PCIE_BUS); + phb->bus = b; +// qdev_init_nofail(dev); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); + + memory_region_init_io(conf_piu0, OBJECT(bs), &core3_pci_config_ops, b, + "pci0-ep-conf-io", 4 * GB); + memory_region_add_subregion(get_system_memory(), 0x880600000000ULL, + conf_piu0); +#ifdef SW64_VT_IOMMU + sw64_vt_iommu_init(b); +#endif + for (i = 0; i < nb_nics; i++) { + pci_nic_init_nofail(&nd_table[i], b, "e1000", NULL); + } + + pci_vga_init(b); +#define MAX_SATA_PORTS 6 + PCIDevice *ahci; + DriveInfo *hd[MAX_SATA_PORTS]; + ahci = pci_create_simple_multifunction(b, PCI_DEVFN(0x1f, 0), true, + TYPE_ICH9_AHCI); + g_assert(MAX_SATA_PORTS == ahci_get_num_ports(ahci)); + ide_drive_get(hd, ahci_get_num_ports(ahci)); + ahci_ide_create_devs(ahci, hd); + + serial_irq = qemu_allocate_irq(serial_set_irq, bs, 12); + if (serial_hd(0)) { + serial_mm_init(get_system_memory(), 0x3F8 + 0x880100000000ULL, 0, + serial_irq, (1843200 >> 4), serial_hd(0), + DEVICE_LITTLE_ENDIAN); + } + pci_create_simple(phb->bus, -1, "nec-usb-xhci"); + usb_create_simple(usb_bus_find(-1), "usb-kbd"); + usb_create_simple(usb_bus_find(-1), "usb-mouse"); + sun4v_rtc_init(0x804910000000ULL); +} + +static const TypeInfo swboard_pcihost_info = { + .name = TYPE_SWBOARD_PCI_HOST_BRIDGE, + .parent = TYPE_PCI_HOST_BRIDGE, + .instance_size = sizeof(BoardState), +}; + +static void swboard_register_types(void) +{ + type_register_static(&swboard_pcihost_info); +} + +type_init(swboard_register_types) diff --git a/hw/sw64/core4.c b/hw/sw64/core4.c new file mode 100644 index 0000000000000000000000000000000000000000..3f381577674b4a4c56a18f2589dc3444b9b610f8 --- /dev/null +++ b/hw/sw64/core4.c @@ -0,0 +1,130 @@ +/* + * 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/ide.h" +#include "hw/char/serial.h" +#include "qemu/cutils.h" +#include "ui/console.h" +#include "core.h" + +static uint64_t cpu_sw64_virt_to_phys(void *opaque, uint64_t addr) +{ + return addr &= ~0xffffffff80000000; +} + +static void core4_cpu_reset(void *opaque) +{ + SW64CPU *cpu = opaque; + + cpu_reset(CPU(cpu)); +} + +static void core4_init(MachineState *machine) +{ + ram_addr_t ram_size = machine->ram_size; + SW64CPU *cpus[MAX_CPUS]; + long i, size; + const char *kernel_filename = machine->kernel_filename; + const char *kernel_cmdline = machine->kernel_cmdline; + char *hmcode_filename; + char *uefi_filename; + uint64_t hmcode_entry, hmcode_low, hmcode_high; + uint64_t kernel_entry, kernel_low, kernel_high; + BOOT_PARAMS *core4_boot_params = g_new0(BOOT_PARAMS, 1); + uint64_t param_offset; + + MachineState *ms = MACHINE(qdev_get_machine()); + unsigned int smp_cpus = ms->smp.cpus; + + memset(cpus, 0, sizeof(cpus)); + + for (i = 0; i < machine->smp.cpus; ++i) { + cpus[i] = SW64_CPU(cpu_create(machine->cpu_type)); + cpus[i]->env.csr[CID] = i; + qemu_register_reset(core4_cpu_reset, cpus[i]); + } + + core4_board_init(cpus, machine->ram); + rom_add_blob_fixed("ram_size", (char *)&ram_size, 0x8, 0x2040); + + param_offset = 0x90B000UL; + core4_boot_params->cmdline = param_offset | 0xfff0000000000000UL; + rom_add_blob_fixed("core4_boot_params", (core4_boot_params), 0x48, 0x90A100); + + hmcode_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, kvm_enabled() ? "core4-reset":"core4-hmcode"); + if (hmcode_filename == NULL) { + if (kvm_enabled()) + error_report("no core4-reset provided"); + else + error_report("no core4-hmcode provided"); + exit(1); + } + size = load_elf(hmcode_filename, NULL, cpu_sw64_virt_to_phys, NULL, + &hmcode_entry, &hmcode_low, &hmcode_high, NULL, 0, EM_SW64, 0, 0); + if (size < 0) { + if (kvm_enabled()) + error_report("could not load core4-reset: '%s'", hmcode_filename); + else + error_report("could not load core4-hmcode: '%s'", hmcode_filename); + exit(1); + } + g_free(hmcode_filename); + + /* Start all cpus at the PALcode RESET entry point. */ + for (i = 0; i < smp_cpus; ++i) { + cpus[i]->env.pc = hmcode_entry; + cpus[i]->env.hm_entry = hmcode_entry; + } + + if (!kernel_filename) { + uefi_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, "core4-bios-virtio.bin"); + load_image_targphys(uefi_filename, 0x2f00000UL, -1); + g_free(uefi_filename); + } else { + /* Load a kernel. */ + size = load_elf(kernel_filename, NULL, cpu_sw64_virt_to_phys, NULL, + &kernel_entry, &kernel_low, &kernel_high, NULL, 0, EM_SW64, 0, + 0); + + if (size < 0) { + error_report("could not load kernel '%s'", kernel_filename); + exit(1); + } + cpus[0]->env.trap_arg1 = kernel_entry; + if (kernel_cmdline) { + pstrcpy_targphys("cmdline", param_offset, 0x400, kernel_cmdline); + } + } +} + +static void board_reset(MachineState *state) +{ + qemu_devices_reset(); +} + +static void core4_machine_init(MachineClass *mc) +{ + mc->desc = "CORE4 BOARD"; + mc->init = core4_init; + mc->block_default_type = IF_IDE; + mc->max_cpus = MAX_CPUS; + mc->is_default = 0; + mc->reset = board_reset; + mc->default_cpu_type = SW64_CPU_TYPE_NAME("core4"); + mc->default_ram_id = "ram"; +} + +DEFINE_MACHINE("core4", core4_machine_init) diff --git a/hw/sw64/core4_board.c b/hw/sw64/core4_board.c new file mode 100644 index 0000000000000000000000000000000000000000..20aad8bd3fd9a7842cb51e967bb106c0e69a575e --- /dev/null +++ b/hw/sw64/core4_board.c @@ -0,0 +1,444 @@ +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "cpu.h" +#include "core.h" +#include "hw/hw.h" +#include "hw/boards.h" +#include "sysemu/sysemu.h" +#include "exec/address-spaces.h" +#include "hw/pci/pci_host.h" +#include "hw/pci/pci.h" +#include "hw/char/serial.h" +#include "hw/irq.h" +#include "net/net.h" +#include "hw/usb.h" +#include "hw/ide/pci.h" +#include "hw/ide/ahci.h" +#include "sysemu/numa.h" +#include "sysemu/kvm.h" +#include "hw/rtc/sun4v-rtc.h" +#include "hw/pci/msi.h" +#define TYPE_SWBOARD_PCI_HOST_BRIDGE "core4_board-pcihost" +#define SWBOARD_PCI_HOST_BRIDGE(obj) \ + OBJECT_CHECK(BoardState, (obj), TYPE_SWBOARD_PCI_HOST_BRIDGE) + +#define MAX_IDE_BUS 2 +#define DEBUGWYH 0 + +typedef struct SWBoard { + SW64CPU *cpu[MAX_CPUS]; +} SWBoard; + +typedef struct BoardState { + PCIHostState parent_obj; + + SWBoard sboard; + uint64_t expire_time; +} BoardState; + +typedef struct TimerState { + void *opaque; + int order; +} TimerState; + +#ifndef CONFIG_KVM +static void swboard_alarm_timer(void *opaque) +{ + TimerState *ts = (TimerState *)((uintptr_t)opaque); + BoardState *bs = (BoardState *)((uintptr_t)ts->opaque); + int64_t current_time; + + int cpu = ts->order; + + current_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + cpu_interrupt(CPU(bs->sboard.cpu[cpu]), CPU_INTERRUPT_TIMER); + timer_mod(bs->sboard.cpu[cpu]->alarm_timer, bs->expire_time + current_time); +} +#endif + +static uint64_t convert_bit(int n) +{ + uint64_t ret = (1UL << n) - 1; + + if (n == 64) + ret = 0xffffffffffffffffUL; + return ret; +} + +static uint64_t mcu_read(void *opaque, hwaddr addr, unsigned size) +{ + uint64_t ret = 0; + MachineState *ms = MACHINE(qdev_get_machine()); + unsigned int smp_cpus = ms->smp.cpus; + + switch (addr) { + case 0x0000: + /* CG_ONLINE */ + { + int i; + for (i = 0; i < smp_cpus; i = i + 4) + ret |= (1UL << i); + } + break; + /*IO_START*/ + case 0x1300: + ret = 0x1; + break; + case 0x3780: + /* MC_ONLINE */ + ret = convert_bit(smp_cpus); + break; + case 0x0900: + /* CPUID */ + ret = 0; + break; + case 0x1180: + /* LONGTIME */ + ret = qemu_clock_get_ns(QEMU_CLOCK_HOST) / 80; + break; + case 0x4900: + /* MC_CONFIG */ + break; + case 0x0780: + /* CORE_ONLINE */ + ret = convert_bit(smp_cpus); + break; + case 0x0680: + /* INIT_CTL */ + ret = 0x000003AE00000D28; + break; + default: + fprintf(stderr, "Unsupported MCU addr: 0x%04lx\n", addr); + return -1; + } + return ret; +} + +static void mcu_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) +{ +#ifndef CONFIG_KVM +#ifdef CONFIG_DUMP_PRINTK + uint64_t print_addr; + uint32_t len; + int i; + if (addr == 0x40000) { + print_addr = val & 0x7fffffff; + len = (uint32_t)(val >> 32); + uint8_t *buf; + buf = malloc(len + 10); + memset(buf, 0, len + 10); + cpu_physical_memory_rw(print_addr, buf, len, 0); + for (i = 0; i < len; i++) + printf("%c", buf[i]); + + free(buf); + return; + } +#endif +#endif +} + +static const MemoryRegionOps mcu_ops = { + .read = mcu_read, + .write = mcu_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = + { + .min_access_size = 8, + .max_access_size = 8, + }, + .impl = + { + .min_access_size = 8, + .max_access_size = 8, + }, +}; + +static uint64_t intpu_read(void *opaque, hwaddr addr, unsigned size) +{ + uint64_t ret = 0; +#ifndef CONFIG_KVM + switch (addr) { + case 0x180: + /* LONGTIME */ + ret = qemu_clock_get_ns(QEMU_CLOCK_HOST) / 80; + break; + } +#endif + return ret; +} + +static void intpu_write(void *opaque, hwaddr addr, uint64_t val, + unsigned size) +{ +#ifndef CONFIG_KVM + BoardState *bs = (BoardState *)opaque; + SW64CPU *cpu; + switch (addr) { + case 0x00: + val &= 0x1f; + cpu = bs->sboard.cpu[val]; + cpu->env.csr[II_REQ] = 0x100000; + cpu_interrupt(CPU(cpu), CPU_INTERRUPT_IIMAIL); + break; + default: + fprintf(stderr, "Unsupported IPU addr: 0x%04lx\n", addr); + break; + } +#endif +} + +static const MemoryRegionOps intpu_ops = { + .read = intpu_read, + .write = intpu_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = + { + .min_access_size = 8, + .max_access_size = 8, + }, + .impl = + { + .min_access_size = 8, + .max_access_size = 8, + }, +}; + +static 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 core4_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 core4_pci_config_ops = { + .read = config_read, + .write = config_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = + { + .min_access_size = 1, + .max_access_size = 8, + }, + .impl = + { + .min_access_size = 1, + .max_access_size = 8, + }, +}; + +static void cpu_irq_change(SW64CPU *cpu, uint64_t req) +{ + if (cpu != NULL) { + CPUState *cs = CPU(cpu); + if (req) + cpu_interrupt(cs, CPU_INTERRUPT_HARD); + else + cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); + } +} + +static void swboard_set_irq(void *opaque, int irq, int level) +{ + BoardState *bs = opaque; + SW64CPU *cpu; + int i; + if (kvm_enabled()) { + kvm_set_irq(kvm_state, irq, level); + return; + } + for (i = 0; i < 1; i++) { + cpu = bs->sboard.cpu[i]; + if (cpu != NULL) { + CPUState *cs = CPU(cpu); + if (level) { + cpu->env.csr[C4_INT_STAT] |= (1UL << irq); + cpu->irq = irq; + cpu_interrupt(cs, CPU_INTERRUPT_PCIE); + } else + cpu_reset_interrupt(cs, CPU_INTERRUPT_PCIE); + } + } + +} + +static int swboard_map_irq(PCIDevice *d, int irq_num) +{ + return 16; +} + +static void serial_set_irq(void *opaque, int irq, int level) +{ + BoardState *bs = (BoardState *)opaque; + int i; + MachineState *ms = MACHINE(qdev_get_machine()); + unsigned int smp_cpus = ms->smp.cpus; + + if (kvm_enabled()) { + kvm_set_irq(kvm_state, irq, level); + return; + } + if (level == 0) + return; + + for (i = 0; i < smp_cpus; i++) { + if (bs->sboard.cpu[i]) + cpu_irq_change(bs->sboard.cpu[i], 1); + } +} + +void core4_board_init(SW64CPU *cpus[MAX_CPUS], MemoryRegion *ram) +{ + DeviceState *dev; + BoardState *bs; +#ifndef CONFIG_KVM + TimerState *ts; +#endif + MemoryRegion *io_mcu = g_new(MemoryRegion, 1); + MemoryRegion *io_intpu = g_new(MemoryRegion, 1); + qemu_irq serial_irq; + uint64_t MB = 1024 * 1024; + MemoryRegion *mem_ep = g_new(MemoryRegion, 1); + MemoryRegion *mem_ep64 = g_new(MemoryRegion, 1); + MemoryRegion *io_piu0 = g_new(MemoryRegion, 1); + MemoryRegion *conf_piu0 = g_new(MemoryRegion, 1); + MemoryRegion *io_ep = g_new(MemoryRegion, 1); + PCIBus *b; + PCIHostState *phb; + uint64_t GB = 1024 * MB; + + MachineState *ms = MACHINE(qdev_get_machine()); + unsigned int smp_cpus = ms->smp.cpus; + + int i; + + dev = qdev_new(TYPE_SWBOARD_PCI_HOST_BRIDGE); + phb = PCI_HOST_BRIDGE(dev); + bs = SWBOARD_PCI_HOST_BRIDGE(dev); + +#ifdef CONFIG_KVM + if (kvm_has_gsi_routing()) + msi_nonbroken = true; +#endif + +#ifndef CONFIG_KVM + bs->expire_time = (int64_t) (1000000000 / 250); +#endif + for (i = 0; i < smp_cpus; ++i) { + if (cpus[i] == NULL) + continue; + bs->sboard.cpu[i] = cpus[i]; +#ifndef CONFIG_KVM + ts = g_new(TimerState, 1); + ts->opaque = (void *) ((uintptr_t)bs); + ts->order = i; + cpus[i]->alarm_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &swboard_alarm_timer, ts); + timer_mod(cpus[i]->alarm_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + bs->expire_time); +#endif + } + memory_region_add_subregion(get_system_memory(), 0, ram); + + memory_region_init_io(io_mcu, NULL, &mcu_ops, bs, "io_mcu", 16 * MB); + memory_region_add_subregion(get_system_memory(), 0x803000000000ULL, io_mcu); + + memory_region_init_io(io_intpu, NULL, &intpu_ops, bs, "io_intpu", 1 * MB); + memory_region_add_subregion(get_system_memory(), 0x802a00000000ULL, + io_intpu); + memory_region_init(mem_ep, OBJECT(bs), "pci0-mem", 0x890000000000ULL); + memory_region_add_subregion(get_system_memory(), 0x880000000000ULL, mem_ep); + + memory_region_init_alias(mem_ep64, NULL, "mem_ep64", mem_ep, 0x888000000000ULL, 1ULL << 39); + memory_region_add_subregion(get_system_memory(), 0x888000000000ULL, mem_ep64); + + memory_region_init_io(io_ep, OBJECT(bs), &core4_pci_ignore_ops, NULL, + "pci0-io-ep", 4 * GB); + + memory_region_add_subregion(get_system_memory(), 0x880100000000ULL, io_ep); + b = pci_register_root_bus(dev, "pci.0", swboard_set_irq, swboard_map_irq, bs, + mem_ep, io_ep, 0, 537, TYPE_PCI_BUS); + phb->bus = b; + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); + memory_region_init_io(io_piu0, OBJECT(bs), &core4_pci_ignore_ops, NULL, + "pci0-piu1-io", 4 * GB); + memory_region_add_subregion(get_system_memory(), 0x880300000000ULL, + io_piu0); + memory_region_init_io(conf_piu0, OBJECT(bs), &core4_pci_config_ops, b, + "pci0-ep-conf-io", 4 * GB); + memory_region_add_subregion(get_system_memory(), 0x880600000000ULL, + conf_piu0); + + for (i = 0; i < nb_nics; i++) + pci_nic_init_nofail(&nd_table[i], b, "e1000", NULL); + + pci_vga_init(b); +#define MAX_SATA_PORTS 6 + PCIDevice *ahci; + DriveInfo *hd[MAX_SATA_PORTS]; + ahci = pci_create_simple_multifunction(b, PCI_DEVFN(0x1f, 0), true, + TYPE_ICH9_AHCI); + g_assert(MAX_SATA_PORTS == ahci_get_num_ports(ahci)); + ide_drive_get(hd, ahci_get_num_ports(ahci)); + ahci_ide_create_devs(ahci, hd); + + serial_irq = qemu_allocate_irq(serial_set_irq, bs, 12); + if (serial_hd(0)) { + serial_mm_init(get_system_memory(), 0x3F8 + 0x880100000000ULL, 0, + serial_irq, (1843200 >> 4), serial_hd(0), + DEVICE_LITTLE_ENDIAN); + } + + pci_create_simple(phb->bus, -1, "nec-usb-xhci"); + usb_create_simple(usb_bus_find(-1), "usb-kbd"); + usb_create_simple(usb_bus_find(-1), "usb-mouse"); + sun4v_rtc_init(0x804910000000ULL); +} + +static const TypeInfo swboard_pcihost_info = { + .name = TYPE_SWBOARD_PCI_HOST_BRIDGE, + .parent = TYPE_PCI_HOST_BRIDGE, + .instance_size = sizeof(BoardState), +}; + +static void swboard_register_types(void) +{ + type_register_static(&swboard_pcihost_info); +} + +type_init(swboard_register_types) diff --git a/hw/sw64/meson.build b/hw/sw64/meson.build new file mode 100644 index 0000000000000000000000000000000000000000..f376e46eeacc684ba57bda892f6b0fd801c466db --- /dev/null +++ b/hw/sw64/meson.build @@ -0,0 +1,15 @@ +sw64_ss = ss.source_set() + +sw64_ss.add(files('sw64_iommu.c')) + +sw64_ss.add(when: 'CONFIG_CORE3', if_true: files( + 'core3.c', + 'core3_board.c', +)) + +sw64_ss.add(when: 'CONFIG_CORE4', if_true: files( + 'core4.c', + 'core4_board.c', +)) + +hw_arch += {'sw64': sw64_ss} diff --git a/hw/sw64/sw64_iommu.c b/hw/sw64/sw64_iommu.c new file mode 100644 index 0000000000000000000000000000000000000000..49301982e0553ab082f41219d4a1a14887d922b5 --- /dev/null +++ b/hw/sw64/sw64_iommu.c @@ -0,0 +1,568 @@ +/* + * 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 "trace.h" +#include "hw/sw64/sw64_iommu.h" +#include "sysemu/kvm.h" + +#define IOMMU_PAGE_SHIFT 13 +#define IOMMU_PAGE_SIZE_8K (1ULL << IOMMU_PAGE_SHIFT) +#define IOMMU_PAGE_MASK_8K (~(IOMMU_PAGE_SIZE_8K - 1)) +#define IOMMU_IOVA_SHIFT 16 +#define SW64IOMMU_PTIOTLB_MAX_SIZE 256 + +static MemTxResult swvt_msi_read(void *opaque, hwaddr addr, + uint64_t *data, unsigned size, MemTxAttrs attrs) +{ + return MEMTX_OK; +} + +static MemTxResult swvt_msi_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size, + MemTxAttrs attrs) +{ + MemTxResult ret; + + ret = msi_write(opaque, addr, value, size, attrs); + + return ret; +} + +static const MemoryRegionOps swvt_msi_ops = { + .read_with_attrs = swvt_msi_read, + .write_with_attrs = swvt_msi_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 1, + .max_access_size = 8, + }, + .impl = { + .min_access_size = 1, + .max_access_size = 8, + }, +}; + +SWVTAddressSpace *iommu_find_add_as(SW64IOMMUState *s, PCIBus *bus, int devfn) +{ + uintptr_t key = (uintptr_t)bus; + SWVTBus *swvt_bus = g_hash_table_lookup(s->swvtbus_as_by_busptr, &key); + SWVTAddressSpace *swvt_dev_as; + char name[128]; + + if (!swvt_bus) { + uintptr_t *new_key = g_malloc(sizeof(*new_key)); + *new_key = (uintptr_t)bus; + /* No corresponding free() */ + swvt_bus = g_malloc0(sizeof(SWVTBus) + sizeof(SWVTAddressSpace *) * \ + PCI_DEVFN_MAX); + swvt_bus->bus = bus; + g_hash_table_insert(s->swvtbus_as_by_busptr, new_key, swvt_bus); + } + swvt_dev_as = swvt_bus->dev_as[devfn]; + if (!swvt_dev_as) { + snprintf(name, sizeof(name), "sw64_iommu_devfn_%d", devfn); + swvt_bus->dev_as[devfn] = swvt_dev_as = g_malloc0(sizeof(SWVTAddressSpace)); + + swvt_dev_as->bus = bus; + swvt_dev_as->devfn = (uint8_t)devfn; + swvt_dev_as->iommu_state = s; + + memory_region_init_iommu(&swvt_dev_as->iommu, sizeof(swvt_dev_as->iommu), + TYPE_SW64_IOMMU_MEMORY_REGION, OBJECT(s), + "sw64_iommu_dmar", + 1UL << 32); + memory_region_init_io(&swvt_dev_as->msi, OBJECT(s), + &swvt_msi_ops, s, "sw_msi", 1 * 1024 * 1024); + memory_region_init(&swvt_dev_as->root, OBJECT(s), + "swvt_root", UINT64_MAX); + memory_region_add_subregion_overlap(&swvt_dev_as->root, + 0x8000fee00000ULL, + &swvt_dev_as->msi, 64); + address_space_init(&swvt_dev_as->as, &swvt_dev_as->root, name); + memory_region_add_subregion_overlap(&swvt_dev_as->root, 0, + MEMORY_REGION(&swvt_dev_as->iommu), + 1); + } + + memory_region_set_enabled(MEMORY_REGION(&swvt_dev_as->iommu), true); + + return swvt_dev_as; +} + +/** + * get_pte - Get the content of a page table entry located at + * @base_addr[@index] + */ +static int get_pte(dma_addr_t baseaddr, uint64_t *pte) +{ + int ret; + + /* TODO: guarantee 64-bit single-copy atomicity */ + ret = dma_memory_read(&address_space_memory, baseaddr, + (uint8_t *)pte, sizeof(*pte)); + + if (ret != MEMTX_OK) + return -EINVAL; + + return 0; +} + +static bool swvt_do_iommu_translate(SWVTAddressSpace *swvt_as, PCIBus *bus, + uint8_t devfn, hwaddr addr, IOMMUTLBEntry *entry) +{ + SW64IOMMUState *s = swvt_as->iommu_state; + uint8_t bus_num = pci_bus_num(bus); + unsigned long dtbbaseaddr, dtbbasecond; + unsigned long pdebaseaddr, ptebaseaddr; + unsigned long pte; + uint16_t source_id; + SW64DTIOTLBEntry *dtcached_entry = NULL; + SW64DTIOTLBKey dtkey, *new_key; + + dtcached_entry = g_hash_table_lookup(s->dtiotlb, &dtkey); + + if (unlikely(!dtcached_entry)) { + dtbbaseaddr = s->dtbr + (bus_num << 3); + + if (get_pte(dtbbaseaddr, &pte)) + goto error; + + dtbbasecond = (pte & (~(SW_IOMMU_ENTRY_VALID))) + (devfn << 3); + if (get_pte(dtbbasecond, &pte)) + goto error; + + source_id = ((bus_num & 0xffUL) << 8) | (devfn & 0xffUL); + dtcached_entry = g_new0(SW64DTIOTLBEntry, 1); + dtcached_entry->ptbase_addr = pte & (~(SW_IOMMU_ENTRY_VALID)); + dtcached_entry->source_id = source_id; + + new_key = g_new0(SW64DTIOTLBKey, 1); + new_key->source_id = source_id; + + g_hash_table_insert(s->dtiotlb, new_key, dtcached_entry); + } + + pdebaseaddr = dtcached_entry->ptbase_addr; + pdebaseaddr += ((addr >> 23) & SW_IOMMU_LEVEL1_OFFSET) << 3; + + if (get_pte(pdebaseaddr, &pte)) + goto error; + + ptebaseaddr = pte & (~(SW_IOMMU_ENTRY_VALID)); + ptebaseaddr += ((addr >> IOMMU_PAGE_SHIFT) & SW_IOMMU_LEVEL2_OFFSET) << 3; + + if (get_pte(ptebaseaddr, &pte)) + goto error; + + pte &= ~(SW_IOMMU_ENTRY_VALID | SW_IOMMU_GRN | SW_IOMMU_ENABLE); + entry->translated_addr = pte; + entry->addr_mask = IOMMU_PAGE_SIZE_8K - 1; + + return 0; + +error: + entry->perm = IOMMU_NONE; + return -EINVAL; +} + +static void swvt_ptiotlb_inv_all(SW64IOMMUState *s) +{ + g_hash_table_remove_all(s->ptiotlb); +} + +static void swvt_lookup_ptiotlb(SW64IOMMUState *s, uint16_t source_id, + hwaddr addr, IOMMUTLBEntry *entry) +{ + SW64PTIOTLBKey ptkey; + + ptkey.source_id = source_id; + ptkey.iova = addr; + + entry = g_hash_table_lookup(s->ptiotlb, &ptkey); +} + +static IOMMUTLBEntry sw64_translate_iommu(IOMMUMemoryRegion *iommu, hwaddr addr, + IOMMUAccessFlags flag, int iommu_idx) +{ + SWVTAddressSpace *swvt_as = container_of(iommu, SWVTAddressSpace, iommu); + SW64IOMMUState *s = swvt_as->iommu_state; + IOMMUTLBEntry *cached_entry = NULL; + IOMMUTLBEntry entry = { + .target_as = &address_space_memory, + .iova = addr, + .translated_addr = addr, + .addr_mask = ~(hwaddr)0, + .perm = IOMMU_NONE, + }; + uint8_t bus_num = pci_bus_num(swvt_as->bus); + uint16_t source_id; + SW64PTIOTLBKey *new_ptkey; + hwaddr aligned_addr; + + source_id = ((bus_num & 0xffUL) << 8) | (swvt_as->devfn & 0xffUL); + + qemu_mutex_lock(&s->iommu_lock); + + aligned_addr = addr & IOMMU_PAGE_MASK_8K; + + swvt_lookup_ptiotlb(s, aligned_addr, source_id, cached_entry); + + if (cached_entry) + goto out; + + if (g_hash_table_size(s->ptiotlb) >= SW64IOMMU_PTIOTLB_MAX_SIZE) { + swvt_ptiotlb_inv_all(s); + } + + cached_entry = g_new0(IOMMUTLBEntry, 1); + + if (swvt_do_iommu_translate(swvt_as, swvt_as->bus, swvt_as->devfn, + addr, cached_entry)) { + g_free(cached_entry); + qemu_mutex_unlock(&s->iommu_lock); + printf("%s: detected translation failure " + "(busnum=%d, devfn=%#x, iova=%#lx.\n", + __func__, pci_bus_num(swvt_as->bus), swvt_as->devfn, + entry.iova); + entry.iova = 0; + entry.translated_addr = 0; + entry.addr_mask = 0; + entry.perm = IOMMU_NONE; + + return entry; + } else { + new_ptkey = g_new0(SW64PTIOTLBKey, 1); + new_ptkey->source_id = source_id; + new_ptkey->iova = aligned_addr; + g_hash_table_insert(s->ptiotlb, new_ptkey, cached_entry); + } + +out: + qemu_mutex_unlock(&s->iommu_lock); + entry.perm = flag; + entry.translated_addr = cached_entry->translated_addr + + (addr & (IOMMU_PAGE_SIZE_8K - 1)); + entry.addr_mask = cached_entry->addr_mask; + + return entry; +} + +static void swvt_ptiotlb_inv_iova(SW64IOMMUState *s, uint16_t source_id, dma_addr_t iova) +{ + SW64PTIOTLBKey key = {.source_id = source_id, .iova = iova}; + + qemu_mutex_lock(&s->iommu_lock); + g_hash_table_remove(s->ptiotlb, &key); + qemu_mutex_unlock(&s->iommu_lock); +} + +void swvt_address_space_unmap_iova(SW64IOMMUState *s, unsigned long val) +{ + SWVTAddressSpace *swvt_as; + IOMMUNotifier *n; + uint16_t source_id; + dma_addr_t iova; + IOMMUTLBEvent event; + + source_id = val & 0xffff; + iova = (val >> IOMMU_IOVA_SHIFT) << IOMMU_PAGE_SHIFT; + + swvt_ptiotlb_inv_iova(s, source_id, iova); + + QLIST_FOREACH(swvt_as, &s->swvt_as_with_notifiers, next) { + uint8_t bus_num = pci_bus_num(swvt_as->bus); + uint16_t as_sourceid = ((bus_num & 0xffUL) << 8) | (swvt_as->devfn & 0xffUL); + + if (as_sourceid == source_id) { + IOMMU_NOTIFIER_FOREACH(n, &swvt_as->iommu) { + event.type = IOMMU_NOTIFIER_UNMAP; + event.entry.target_as = &address_space_memory; + event.entry.iova = iova & IOMMU_PAGE_MASK_8K; + event.entry.translated_addr = 0; + event.entry.perm = IOMMU_NONE; + event.entry.addr_mask = IOMMU_PAGE_SIZE_8K - 1; + + memory_region_notify_iommu(&swvt_as->iommu, 0, event); + } + } + } +} + +/* Unmap the whole range in the notifier's scope. */ +static void swvt_address_space_unmap(SWVTAddressSpace *as, IOMMUNotifier *n) +{ + IOMMUTLBEvent event; + hwaddr size; + hwaddr start = n->start; + hwaddr end = n->end; + + assert(start <= end); + size = end - start; + + event.entry.target_as = &address_space_memory; + /* Adjust iova for the size */ + event.entry.iova = n->start & ~(size - 1); + /* This field is meaningless for unmap */ + event.entry.translated_addr = 0; + event.entry.perm = IOMMU_NONE; + event.entry.addr_mask = size - 1; + + memory_region_notify_iommu_one(n, &event); +} + +void swvt_address_space_map_iova(SW64IOMMUState *s, unsigned long val) +{ + SWVTAddressSpace *swvt_as; + IOMMUNotifier *n; + uint16_t source_id; + dma_addr_t iova; + IOMMUTLBEvent event; + int ret; + + source_id = val & 0xffff; + iova = (val >> IOMMU_IOVA_SHIFT) << IOMMU_PAGE_SHIFT; + + swvt_ptiotlb_inv_iova(s, source_id, iova); + + QLIST_FOREACH(swvt_as, &s->swvt_as_with_notifiers, next) { + uint8_t bus_num = pci_bus_num(swvt_as->bus); + uint16_t as_sourceid = ((bus_num & 0xffUL) << 8) | (swvt_as->devfn & 0xffUL); + + if (as_sourceid == source_id) { + IOMMU_NOTIFIER_FOREACH(n, &swvt_as->iommu) { + event.type = IOMMU_NOTIFIER_UNMAP; + event.entry.target_as = &address_space_memory; + event.entry.iova = iova & IOMMU_PAGE_MASK_8K; + event.entry.perm = IOMMU_RW; + + ret = swvt_do_iommu_translate(swvt_as, swvt_as->bus, + swvt_as->devfn, iova, &event.entry); + if (ret) + goto out; + + memory_region_notify_iommu(&swvt_as->iommu, 0, event); + } + } + } +out: + return; +} + +void swvt_address_space_invalidate_iova(SW64IOMMUState *s, unsigned long val) +{ + int map_flag; + + map_flag = val >> 36; + + if (map_flag) + swvt_address_space_map_iova(s, val & 0xfffffffff); + else + swvt_address_space_unmap_iova(s, val); + + return; +} + +static AddressSpace *sw64_dma_iommu(PCIBus *bus, void *opaque, int devfn) +{ + SW64IOMMUState *s = opaque; + SWVTAddressSpace *swvt_as; + + assert(0 <= devfn && devfn < PCI_DEVFN_MAX); + + swvt_as = iommu_find_add_as(s, bus, devfn); + return &swvt_as->as; +} + +static uint64_t piu0_read(void *opaque, hwaddr addr, unsigned size) +{ + uint64_t ret = 0; + switch (addr) { + default: + break; + } + return ret; +} + +static void piu0_write(void *opaque, hwaddr addr, uint64_t val, + unsigned size) +{ + SW64IOMMUState *s = (SW64IOMMUState *)opaque; + + switch (addr) { + case 0xb000: + /* DTBaseAddr */ + s->dtbr = val; + break; + case 0xb280: + /* PTLB_FlushVAddr */ + swvt_address_space_invalidate_iova(s, val); + break; + default: + break; + } +} + +const MemoryRegionOps core3_pci_piu0_ops = { + .read = piu0_read, + .write = piu0_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 1, + .max_access_size = 8, + }, + .impl = { + .min_access_size = 1, + .max_access_size = 8, + }, +}; + +void sw64_vt_iommu_init(PCIBus *b) +{ + DeviceState *dev_iommu; + SW64IOMMUState *s; + MemoryRegion *io_piu0 = g_new(MemoryRegion, 1); + + dev_iommu = qdev_new(TYPE_SW64_IOMMU); + s = SW64_IOMMU(dev_iommu); + + s->pci_bus = b; + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev_iommu), &error_fatal); + + pci_setup_iommu(b, sw64_dma_iommu, dev_iommu); + + memory_region_init_io(io_piu0, OBJECT(s), &core3_pci_piu0_ops, s, + "pci0-piu0-io", 4 * 1024 * 1024); + memory_region_add_subregion(get_system_memory(), 0x880200000000ULL, + io_piu0); +} + +static int swvt_iommu_notify_flag_changed(IOMMUMemoryRegion *iommu, + IOMMUNotifierFlag old, + IOMMUNotifierFlag new, + Error **errp) +{ + SWVTAddressSpace *swvt_as = container_of(iommu, SWVTAddressSpace, iommu); + SW64IOMMUState *s = swvt_as->iommu_state; + + /* Update per-address-space notifier flags */ + swvt_as->notifier_flags = new; + + if (new & IOMMU_NOTIFIER_DEVIOTLB_UNMAP) { + error_setg(errp, "swvt does not support dev-iotlb yet"); + return -EINVAL; + } + + if (old == IOMMU_NOTIFIER_NONE) { + QLIST_INSERT_HEAD(&s->swvt_as_with_notifiers, swvt_as, next); + } else if (new == IOMMU_NOTIFIER_NONE) { + QLIST_REMOVE(swvt_as, next); + } + return 0; +} + +static void swvt_iommu_replay(IOMMUMemoryRegion *iommu_mr, IOMMUNotifier *n) +{ + SWVTAddressSpace *swvt_as = container_of(iommu_mr, SWVTAddressSpace, iommu); + + /* + * The replay can be triggered by either a invalidation or a newly + * created entry. No matter what, we release existing mappings + * (it means flushing caches for UNMAP-only registers). + */ + swvt_address_space_unmap(swvt_as, n); +} + +/* GHashTable functions */ +static gboolean swvt_uint64_equal(gconstpointer v1, gconstpointer v2) +{ + return *((const uint64_t *)v1) == *((const uint64_t *)v2); +} + +static guint swvt_uint64_hash(gconstpointer v) +{ + return (guint)*(const uint64_t *)v; +} + +static void iommu_realize(DeviceState *d, Error **errp) +{ + SW64IOMMUState *s = SW64_IOMMU(d); + + QLIST_INIT(&s->swvt_as_with_notifiers); + qemu_mutex_init(&s->iommu_lock); + + s->dtiotlb = g_hash_table_new_full(swvt_uint64_hash, swvt_uint64_equal, + g_free, g_free); + s->ptiotlb = g_hash_table_new_full(swvt_uint64_hash, swvt_uint64_equal, + g_free, g_free); + + s->swvtbus_as_by_busptr = g_hash_table_new(NULL, NULL); +} + +static void iommu_reset(DeviceState *d) +{ +} + +static void sw64_iommu_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->reset = iommu_reset; + dc->realize = iommu_realize; +} + +static void sw64_iommu_memory_region_class_init(ObjectClass *klass, void *data) +{ + IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass); + + imrc->translate = sw64_translate_iommu; + imrc->notify_flag_changed = swvt_iommu_notify_flag_changed; + imrc->replay = swvt_iommu_replay; +} + +static const TypeInfo sw64_iommu_info = { + .name = TYPE_SW64_IOMMU, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(SW64IOMMUState), + .class_init = sw64_iommu_class_init, + .class_size = sizeof(SW64IOMMUClass), +}; + +static const TypeInfo sw64_iommu_memory_region_info = { + .parent = TYPE_IOMMU_MEMORY_REGION, + .name = TYPE_SW64_IOMMU_MEMORY_REGION, + .class_init = sw64_iommu_memory_region_class_init, +}; + +static void sw64_iommu_register_types(void) +{ + type_register_static(&sw64_iommu_info); + type_register_static(&sw64_iommu_memory_region_info); +} + +type_init(sw64_iommu_register_types) diff --git a/hw/sw64/trace-events b/hw/sw64/trace-events new file mode 100644 index 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 08e1beec854f1a7260f883d902dff379e8f1bbaa..92f9d84ad4bb6429aff8579f648cc327d9fc8f37 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_sw_64, /* Dec Sw_64 */ +#define bfd_mach_sw_64 1 +#define bfd_mach_sw_64_core3 1621 +#define bfd_mach_sw_64_core4 3231 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_sw_64 (bfd_vma, disassemble_info*); int print_insn_arm (bfd_vma, disassemble_info*); int print_insn_sparc (bfd_vma, disassemble_info*); int print_insn_big_a29k (bfd_vma, disassemble_info*); diff --git a/include/elf.h b/include/elf.h index 811bf4a1cb5cc9e271ac09c65b1554350a929c26..79c188b62fed66dd21a4dd03a68fd6ed534b3507 100644 --- a/include/elf.h +++ b/include/elf.h @@ -207,6 +207,8 @@ typedef struct mips_elf_abiflags_v0 { #define EF_AVR_MACH 0x7F /* Mask for AVR e_flags to get core type */ +#define EM_SW64 0x9916 /* SW64 */ + /* This is the info that is needed to parse the dynamic section of the file */ #define DT_NULL 0 #define DT_NEEDED 1 @@ -1417,6 +1419,48 @@ typedef struct { #define EF_RISCV_RVE 0x0008 #define EF_RISCV_TSO 0x0010 +/* + SW_64 ELF relocation types + */ +#define EM_SW_64 0x9916 +#define R_SW_64_NONE 0 /* No reloc */ +#define R_SW_64_REFLONG 1 /* Direct 32 bit */ +#define R_SW_64_REFQUAD 2 /* Direct 64 bit */ +#define R_SW_64_GPREL32 3 /* GP relative 32 bit */ +#define R_SW_64_LITERAL 4 /* GP relative 16 bit w/optimization */ +#define R_SW_64_LITUSE 5 /* Optimization hint for LITERAL */ +#define R_SW_64_GPDISP 6 /* Add displacement to GP */ +#define R_SW_64_BRADDR 7 /* PC+4 relative 23 bit shifted */ +#define R_SW_64_HINT 8 /* PC+4 relative 16 bit shifted */ +#define R_SW_64_SREL16 9 /* PC relative 16 bit */ +#define R_SW_64_SREL32 10 /* PC relative 32 bit */ +#define R_SW_64_SREL64 11 /* PC relative 64 bit */ +#define R_SW_64_GPRELHIGH 17 /* GP relative 32 bit, high 16 bits */ +#define R_SW_64_GPRELLOW 18 /* GP relative 32 bit, low 16 bits */ +#define R_SW_64_GPREL16 19 /* GP relative 16 bit */ +#define R_SW_64_COPY 24 /* Copy symbol at runtime */ +#define R_SW_64_GLOB_DAT 25 /* Create GOT entry */ +#define R_SW_64_JMP_SLOT 26 /* Create PLT entry */ +#define R_SW_64_RELATIVE 27 /* Adjust by program base */ +#define R_SW_64_TLS_GD_HI 28 +#define R_SW_64_TLSGD 29 +#define R_SW_64_TLS_LDM 30 +#define R_SW_64_DTPMOD64 31 +#define R_SW_64_GOTDTPREL 32 +#define R_SW_64_DTPREL64 33 +#define R_SW_64_DTPRELHI 34 +#define R_SW_64_DTPRELLO 35 +#define R_SW_64_DTPREL16 36 +#define R_SW_64_GOTTPREL 37 +#define R_SW_64_TPREL64 38 +#define R_SW_64_TPRELHI 39 +#define R_SW_64_TPRELLO 40 +#define R_SW_64_TPREL16 41 +/* Keep this the last entry. */ +#define R_SW_64_NUM 46 +/* Legal values for sh_flags field of Elf64_Shdr. */ +#define SHF_SW_64_GPREL 0x10000000 + typedef struct elf32_rel { Elf32_Addr r_offset; Elf32_Word r_info; diff --git a/include/hw/sw64/sw64_iommu.h b/include/hw/sw64/sw64_iommu.h new file mode 100644 index 0000000000000000000000000000000000000000..71918760836034dba09bba4505e832d5cf0eaece --- /dev/null +++ b/include/hw/sw64/sw64_iommu.h @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2021-2025 Wuxi Institute of Advanced Technology + * Written by Lu Feifei + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ + +#ifndef HW_SW64_IOMMU_H +#define HW_SW64_IOMMU_H + +#include "hw/sysbus.h" +#include "hw/pci/pci.h" + +#define TYPE_SW64_IOMMU_MEMORY_REGION "sw64-iommu-memory-region" +#define SW_IOMMU_ENTRY_VALID ((1UL) << 63) +#define SW_IOMMU_LEVEL1_OFFSET 0x1ff +#define SW_IOMMU_LEVEL2_OFFSET 0x3ff +#define SW_IOMMU_ENABLE 3 +#define SW_IOMMU_GRN ((0UL) << 4) +#define SWVT_PCI_BUS_MAX 256 + +typedef struct SW64IOMMUClass SW64IOMMUClass; +typedef struct SW64IOMMUState SW64IOMMUState; +typedef struct SWVTAddressSpace SWVTAddressSpace; +typedef struct SW64DTIOTLBKey SW64DTIOTLBKey; +typedef struct SW64PTIOTLBKey SW64PTIOTLBKey; +typedef struct SW64DTIOTLBEntry SW64DTIOTLBEntry; +typedef struct SWVTBus SWVTBus; + +struct SW64DTIOTLBEntry { + uint16_t source_id; + unsigned long ptbase_addr; +}; + +struct SW64DTIOTLBKey { + uint16_t source_id; +}; + +struct SW64PTIOTLBKey { + uint16_t source_id; + dma_addr_t iova; +}; + +struct SWVTAddressSpace { + PCIBus *bus; + uint8_t devfn; + AddressSpace as; + IOMMUMemoryRegion iommu; + MemoryRegion root; + MemoryRegion msi; /* Interrupt region: 0xfeeXXXXX */ + SW64IOMMUState *iommu_state; + QLIST_ENTRY(SWVTAddressSpace) next; + /* Superset of notifier flags that this address space has */ + IOMMUNotifierFlag notifier_flags; +}; + +struct SWVTBus { + PCIBus* bus; /* A reference to the bus to provide translation for */ + SWVTAddressSpace *dev_as[0]; /* A table of SWVTAddressSpace objects indexed by devfn */ +}; + +struct SW64IOMMUState { + SysBusDevice busdev; + dma_addr_t dtbr; /* Current root table pointer */ + GHashTable *dtiotlb; /* IOTLB for device table */ + GHashTable *ptiotlb; /* IOTLB for page table */ + + GHashTable *swvtbus_as_by_busptr; + /* list of registered notifiers */ + QLIST_HEAD(, SWVTAddressSpace) swvt_as_with_notifiers; + + PCIBus *pci_bus; + QemuMutex iommu_lock; +}; + +struct SW64IOMMUClass { + SysBusDeviceClass parent; + DeviceRealize realize; +}; + +#define TYPE_SW64_IOMMU "sw64-iommu" +#define SW64_IOMMU(obj) \ + OBJECT_CHECK(SW64IOMMUState, (obj), TYPE_SW64_IOMMU) +#define SW64_IOMMU_CLASS(klass) \ + OBJECT_CLASS_CHECK(SW64IOMMUClass, (klass), TYPE_SW64_IOMMU) +#define SW64_IOMMU_GET_CLASS(obj) \ + OBJECT_GET_CLASS(SW64IOMMUClass, (obj), TYPE_SW64_IOMMU) +extern void sw64_vt_iommu_init(PCIBus *b); +extern void swvt_address_space_invalidate_iova(SW64IOMMUState *s, unsigned long val); +extern void swvt_address_space_unmap_iova(SW64IOMMUState *s, unsigned long val); +extern void swvt_address_space_map_iova(SW64IOMMUState *s, unsigned long val); +extern SWVTAddressSpace *iommu_find_add_as(SW64IOMMUState *s, PCIBus *bus, int devfn); +extern MemTxResult msi_write(void *opaque, hwaddr addr, uint64_t value, unsigned size, + MemTxAttrs attrs); +#endif diff --git a/include/qemu/atomic.h b/include/qemu/atomic.h index 112a29910bea1d481ab8f23557141e0fa2406bfc..614112230880ad1f97b89aa8178c5ce30de198b0 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 d263fad9a471f477aad6d61ce83764c5cc0e15ea..e6d442abeedca8a17690d25287ae965a5a5119b6 100644 --- a/include/qemu/timer.h +++ b/include/qemu/timer.h @@ -1007,6 +1007,16 @@ static inline int64_t cpu_get_host_ticks(void) return cur - ofs; } +#elif defined(__sw_64__) + +static inline int64_t cpu_get_host_ticks(void) +{ + uint64_t cc; + + asm volatile("rtc %0" : "=r"(cc)); + return cc; +} + #else /* The host CPU doesn't have an easily accessible cycle counter. Just return a monotonically increasing value. This will be diff --git a/include/sysemu/arch_init.h b/include/sysemu/arch_init.h index 70c579560adfd4e2bea6efadf2ea7f7ebc15fa38..1cf27baa7c14636c32704ede31a43da1c327e7e0 100644 --- a/include/sysemu/arch_init.h +++ b/include/sysemu/arch_init.h @@ -24,6 +24,7 @@ enum { QEMU_ARCH_RX = (1 << 20), QEMU_ARCH_AVR = (1 << 21), QEMU_ARCH_HEXAGON = (1 << 22), + QEMU_ARCH_SW64 = (1 << 23), }; extern const uint32_t arch_type; diff --git a/linux-headers/asm-sw64/kvm.h b/linux-headers/asm-sw64/kvm.h new file mode 100644 index 0000000000000000000000000000000000000000..16c6aeabbb72961bbbc389cb252d89554b4008cd --- /dev/null +++ b/linux-headers/asm-sw64/kvm.h @@ -0,0 +1,129 @@ +#ifndef __LINUX_KVM_SW64_H +#define __LINUX_KVM_SW64_H + +#include +/* + * for KVM_GET_REGS and KVM_SET_REGS + */ +struct kvm_regs { + unsigned long r0; + unsigned long r1; + unsigned long r2; + unsigned long r3; + + unsigned long r4; + unsigned long r5; + unsigned long r6; + unsigned long r7; + + unsigned long r8; + unsigned long r9; + unsigned long r10; + unsigned long r11; + + unsigned long r12; + unsigned long r13; + unsigned long r14; + unsigned long r15; + + unsigned long r19; + unsigned long r20; + unsigned long r21; + unsigned long r22; + + unsigned long r23; + unsigned long r24; + unsigned long r25; + unsigned long r26; + + unsigned long r27; + unsigned long r28; + unsigned long __padding0; + unsigned long fpcr; + + unsigned long fp[124]; + /* These are saved by PAL-code: */ + unsigned long ps; + unsigned long pc; + unsigned long gp; + unsigned long r16; + unsigned long r17; + unsigned long r18; +}; + +struct vcpucb { + unsigned long go_flag; + unsigned long pcbb; + unsigned long ksp; + unsigned long usp; + unsigned long kgp; + unsigned long ent_arith; + unsigned long ent_if; + unsigned long ent_int; + unsigned long ent_mm; + unsigned long ent_sys; + unsigned long ent_una; + unsigned long stack_pc; + unsigned long new_a0; + unsigned long new_a1; + unsigned long new_a2; + unsigned long whami; + unsigned long csr_save; + unsigned long wakeup_magic; + unsigned long host_vcpucb; + unsigned long upcr; + unsigned long vpcr; + unsigned long dtb_pcr; + unsigned long guest_ksp; + unsigned long guest_usp; + unsigned long vcpu_irq_disabled; + unsigned long vcpu_irq; + unsigned long ptbr; + unsigned long int_stat0; + unsigned long int_stat1; + unsigned long int_stat2; + unsigned long int_stat3; + unsigned long reset_entry; + unsigned long pvcpu; + unsigned long exit_reason; + unsigned long ipaddr; + unsigned long vcpu_irq_vector; +}; + +/* + * for KVM_GET_FPU and KVM_SET_FPU + */ +struct kvm_fpu { +}; + +/* + * KVM MIPS specific structures and definitions + * + */ +struct kvm_debug_exit_arch { +}; + +/* for KVM_SET_GUEST_DEBUG */ +struct kvm_guest_debug_arch { +}; + +/* definition of registers in kvm_run */ +struct kvm_sync_regs { +}; + +/* dummy definition */ +struct kvm_sregs { +}; + +struct kvm_mips_interrupt { + /* in */ + __u32 cpu; + __u32 irq; +}; + +#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/kvm_para.h b/linux-headers/asm-sw64/kvm_para.h new file mode 100644 index 0000000000000000000000000000000000000000..dbb2464f3b895caa02cbb4cb21646c296391d1a1 --- /dev/null +++ b/linux-headers/asm-sw64/kvm_para.h @@ -0,0 +1,5 @@ +#ifndef _ASM_MIPS_KVM_PARA_H +#define _ASM_MIPS_KVM_PARA_H + + +#endif /* _ASM_MIPS_KVM_PARA_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/meson.build b/linux-user/meson.build index bf62c13e378957087adc1d44e585bb14e83dd369..4f4196ed13a57e2e38dece7d008495e9a46731d3 100644 --- a/linux-user/meson.build +++ b/linux-user/meson.build @@ -37,5 +37,6 @@ subdir('ppc') subdir('s390x') subdir('sh4') subdir('sparc') +subdir('sw64') subdir('x86_64') subdir('xtensa') diff --git a/linux-user/sw64/cpu_loop.c b/linux-user/sw64/cpu_loop.c new file mode 100644 index 0000000000000000000000000000000000000000..9fe8e7eeb6dd93b5f6580264f2f656c9febe8614 --- /dev/null +++ b/linux-user/sw64/cpu_loop.c @@ -0,0 +1,108 @@ +/* + * qemu user cpu loop + * + * Copyright (c) 2003-2008 Fabrice Bellard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include "qemu/osdep.h" +#include "qemu.h" +#include "cpu_loop-common.h" + +void cpu_loop(CPUSW64State *env) +{ + CPUState *cs = CPU(sw64_env_get_cpu(env)); + int trapnr; + target_siginfo_t info; + abi_long sysret; + + while (1) { + cpu_exec_start(cs); + trapnr = cpu_exec(cs); + cpu_exec_end(cs); + process_queued_cpu_work(cs); + + switch (trapnr) { + case EXCP_OPCDEC: + cpu_abort(cs, "ILLEGAL SW64 insn at line %d!", __LINE__); + case EXCP_CALL_SYS: + switch (env->error_code) { + case 0x83: + /* CALLSYS */ + trapnr = env->ir[IDX_V0]; + sysret = do_syscall(env, trapnr, + env->ir[IDX_A0], env->ir[IDX_A1], + env->ir[IDX_A2], env->ir[IDX_A3], + env->ir[IDX_A4], env->ir[IDX_A5], + 0, 0); + if (sysret == -TARGET_ERESTARTSYS) { + env->pc -= 4; + break; + } + if (sysret == -TARGET_QEMU_ESIGRETURN) { + break; + } + /* Syscall writes 0 to V0 to bypass error check, similar + to how this is handled internal to Linux kernel. + (Ab)use trapnr temporarily as boolean indicating error. */ + trapnr = (env->ir[IDX_V0] != 0 && sysret < 0); + env->ir[IDX_V0] = (trapnr ? -sysret : sysret); + env->ir[IDX_A3] = trapnr; + break; + default: + printf("UNDO sys_call %lx\n", env->error_code); + exit(-1); + } + break; + case EXCP_MMFAULT: + info.si_signo = TARGET_SIGSEGV; + info.si_errno = 0; + info.si_code = (page_get_flags(env->trap_arg0) & PAGE_VALID + ? TARGET_SEGV_ACCERR : TARGET_SEGV_MAPERR); + info._sifields._sigfault._addr = env->trap_arg0; + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); + break; + case EXCP_ARITH: + info.si_signo = TARGET_SIGFPE; + info.si_errno = 0; + info.si_code = TARGET_FPE_FLTINV; + info._sifields._sigfault._addr = env->pc; + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); + break; + case EXCP_INTERRUPT: + /* just indicate that signals should be handled asap */ + break; + default: + cpu_abort(cs, "UNDO"); + } + process_pending_signals (env); + + /* Most of the traps imply a transition through PALcode, which + implies an REI instruction has been executed. Which means + that RX and LOCK_ADDR should be cleared. But there are a + few exceptions for traps internal to QEMU. */ + } +} + +void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs) +{ + int i; + + for(i = 0; i < 28; i++) { + env->ir[i] = ((abi_ulong *)regs)[i]; + } + env->ir[IDX_SP] = regs->usp; + env->pc = regs->pc; +} diff --git a/linux-user/sw64/signal.c b/linux-user/sw64/signal.c new file mode 100644 index 0000000000000000000000000000000000000000..021f36be2556e4d2e00ac1672f05675a2895bbc7 --- /dev/null +++ b/linux-user/sw64/signal.c @@ -0,0 +1,274 @@ +/* + * Emulation of Linux signals + * + * Copyright (c) 2003 Fabrice Bellard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ +#include "qemu/osdep.h" +#include "qemu.h" +#include "signal-common.h" +#include "linux-user/trace.h" + +struct target_sigcontext { + abi_long sc_onstack; + abi_long sc_mask; + abi_long sc_pc; + abi_long sc_ps; + abi_long sc_regs[32]; + abi_long sc_ownedfp; + abi_long sc_fpregs[32]; + abi_ulong sc_fpcr; + abi_ulong sc_fp_control; + abi_ulong sc_reserved1; + abi_ulong sc_reserved2; + abi_ulong sc_ssize; + abi_ulong sc_sbase; + abi_ulong sc_traparg_a0; + abi_ulong sc_traparg_a1; + abi_ulong sc_traparg_a2; + abi_ulong sc_fp_trap_pc; + abi_ulong sc_fp_trigger_sum; + abi_ulong sc_fp_trigger_inst; +}; + +struct target_ucontext { + abi_ulong tuc_flags; + abi_ulong tuc_link; + abi_ulong tuc_osf_sigmask; + target_stack_t tuc_stack; + struct target_sigcontext tuc_mcontext; + target_sigset_t tuc_sigmask; +}; + +struct target_sigframe { + struct target_sigcontext sc; + unsigned int retcode[3]; +}; + +struct target_rt_sigframe { + target_siginfo_t info; + struct target_ucontext uc; + unsigned int retcode[3]; +}; + +#define INSN_MOV_R30_R16 0x47fe0410 +#define INSN_LDI_R0 0x201f0000 +#define INSN_CALLSYS 0x00000083 + +static void setup_sigcontext(struct target_sigcontext *sc, CPUSW64State *env, + abi_ulong frame_addr, target_sigset_t *set) +{ + int i; + + __put_user(on_sig_stack(frame_addr), &sc->sc_onstack); + __put_user(set->sig[0], &sc->sc_mask); + __put_user(env->pc, &sc->sc_pc); + __put_user(8, &sc->sc_ps); + + for (i = 0; i < 31; ++i) { + __put_user(env->ir[i], &sc->sc_regs[i]); + } + __put_user(0, &sc->sc_regs[31]); + + for (i = 0; i < 31; ++i) { + __put_user(env->fr[i], &sc->sc_fpregs[i]); + } + __put_user(0, &sc->sc_fpregs[31]); + __put_user(cpu_sw64_load_fpcr(env), &sc->sc_fpcr); + + __put_user(0, &sc->sc_traparg_a0); /* FIXME */ + __put_user(0, &sc->sc_traparg_a1); /* FIXME */ + __put_user(0, &sc->sc_traparg_a2); /* FIXME */ +} + +static void restore_sigcontext(CPUSW64State *env, + struct target_sigcontext *sc) +{ + uint64_t fpcr; + int i; + + __get_user(env->pc, &sc->sc_pc); + + for (i = 0; i < 31; ++i) { + __get_user(env->ir[i], &sc->sc_regs[i]); + } + for (i = 0; i < 31; ++i) { + __get_user(env->fr[i], &sc->sc_fpregs[i]); + } + + __get_user(fpcr, &sc->sc_fpcr); + cpu_sw64_store_fpcr(env, fpcr); +} + +static inline abi_ulong get_sigframe(struct target_sigaction *sa, + CPUSW64State *env, + unsigned long framesize) +{ + abi_ulong sp; + + sp = target_sigsp(get_sp_from_cpustate(env), sa); + + return (sp - framesize) & -32; +} + +void setup_frame(int sig, struct target_sigaction *ka, + target_sigset_t *set, CPUSW64State *env) +{ + abi_ulong frame_addr, r26; + struct target_sigframe *frame; + int err = 0; + + frame_addr = get_sigframe(ka, env, sizeof(*frame)); + trace_user_setup_frame(env, frame_addr); + if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) { + goto give_sigsegv; + } + + setup_sigcontext(&frame->sc, env, frame_addr, set); + + if (ka->sa_restorer) { + r26 = ka->sa_restorer; + } else { + __put_user(INSN_MOV_R30_R16, &frame->retcode[0]); + __put_user(INSN_LDI_R0 + TARGET_NR_sigreturn, + &frame->retcode[1]); + __put_user(INSN_CALLSYS, &frame->retcode[2]); + /* imb() */ + r26 = frame_addr + offsetof(struct target_sigframe, retcode); + } + + unlock_user_struct(frame, frame_addr, 1); + + if (err) { +give_sigsegv: + force_sigsegv(sig); + return; + } + + env->ir[IDX_RA] = r26; + env->ir[IDX_PV] = env->pc = ka->_sa_handler; + env->ir[IDX_A0] = sig; + env->ir[IDX_A1] = 0; + env->ir[IDX_A2] = frame_addr + offsetof(struct target_sigframe, sc); + env->ir[IDX_SP] = frame_addr; +} + +void setup_rt_frame(int sig, struct target_sigaction *ka, + target_siginfo_t *info, + target_sigset_t *set, CPUSW64State *env) +{ + abi_ulong frame_addr, r26; + struct target_rt_sigframe *frame; + int i, err = 0; + + frame_addr = get_sigframe(ka, env, sizeof(*frame)); + trace_user_setup_rt_frame(env, frame_addr); + if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) { + goto give_sigsegv; + } + + tswap_siginfo(&frame->info, info); + + __put_user(0, &frame->uc.tuc_flags); + __put_user(0, &frame->uc.tuc_link); + __put_user(set->sig[0], &frame->uc.tuc_osf_sigmask); + + target_save_altstack(&frame->uc.tuc_stack, env); + + setup_sigcontext(&frame->uc.tuc_mcontext, env, frame_addr, set); + for (i = 0; i < TARGET_NSIG_WORDS; ++i) { + __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]); + } + + if (ka->sa_restorer) { + r26 = ka->sa_restorer; + } else { + __put_user(INSN_MOV_R30_R16, &frame->retcode[0]); + __put_user(INSN_LDI_R0 + TARGET_NR_rt_sigreturn, + &frame->retcode[1]); + __put_user(INSN_CALLSYS, &frame->retcode[2]); + /* imb(); */ + r26 = frame_addr + offsetof(struct target_sigframe, retcode); + } + + if (err) { +give_sigsegv: + force_sigsegv(sig); + return; + } + + env->ir[IDX_RA] = r26; + env->ir[IDX_PV] = env->pc = ka->_sa_handler; + env->ir[IDX_A0] = sig; + env->ir[IDX_A1] = frame_addr + offsetof(struct target_rt_sigframe, info); + env->ir[IDX_A2] = frame_addr + offsetof(struct target_rt_sigframe, uc); + env->ir[IDX_SP] = frame_addr; +} + +long do_sigreturn(CPUSW64State *env) +{ + struct target_sigcontext *sc; + abi_ulong sc_addr = env->ir[IDX_A0]; + target_sigset_t target_set; + sigset_t set; + + if (!lock_user_struct(VERIFY_READ, sc, sc_addr, 1)) { + goto badframe; + } + + target_sigemptyset(&target_set); + __get_user(target_set.sig[0], &sc->sc_mask); + + target_to_host_sigset_internal(&set, &target_set); + set_sigmask(&set); + + restore_sigcontext(env, sc); + unlock_user_struct(sc, sc_addr, 0); + return -TARGET_QEMU_ESIGRETURN; + +badframe: + force_sig(TARGET_SIGSEGV); + return -TARGET_QEMU_ESIGRETURN; +} + +long do_rt_sigreturn(CPUSW64State *env) +{ + abi_ulong frame_addr = env->ir[IDX_A0]; + struct target_rt_sigframe *frame; + sigset_t set; + + trace_user_do_rt_sigreturn(env, frame_addr); + if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) { + goto badframe; + } + target_to_host_sigset(&set, &frame->uc.tuc_sigmask); + set_sigmask(&set); + + restore_sigcontext(env, &frame->uc.tuc_mcontext); + if (do_sigaltstack(frame_addr + offsetof(struct target_rt_sigframe, + uc.tuc_stack), + 0, env->ir[IDX_SP]) == -EFAULT) { + goto badframe; + } + + unlock_user_struct(frame, frame_addr, 0); + return -TARGET_QEMU_ESIGRETURN; + + +badframe: + unlock_user_struct(frame, frame_addr, 0); + force_sig(TARGET_SIGSEGV); + return -TARGET_QEMU_ESIGRETURN; +} diff --git a/linux-user/sw64/sockbits.h b/linux-user/sw64/sockbits.h new file mode 100644 index 0000000000000000000000000000000000000000..0e4c8f012d781261da71333ae360abe22ca8083b --- /dev/null +++ b/linux-user/sw64/sockbits.h @@ -0,0 +1 @@ +#include "../generic/sockbits.h" diff --git a/linux-user/sw64/syscall_nr.h b/linux-user/sw64/syscall_nr.h new file mode 100644 index 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/target_cpu.h b/linux-user/sw64/target_cpu.h new file mode 100644 index 0000000000000000000000000000000000000000..8764542ba9c5b0fae9d3361814dbc6c31b74cf00 --- /dev/null +++ b/linux-user/sw64/target_cpu.h @@ -0,0 +1,40 @@ +/* + * SW64 specific CPU ABI and functions for linux-user + * + * Copyright (c) 2007 Jocelyn Mayer + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ +#ifndef SW64_TARGET_CPU_H +#define SW64_TARGET_CPU_H + +static inline void cpu_clone_regs(CPUSW64State *env, target_ulong newsp) +{ + if (newsp) { + env->ir[IDX_SP] = newsp; + } + env->ir[IDX_V0] = 0; + env->ir[IDX_A3] = 0; +} + +static inline void cpu_set_tls(CPUSW64State *env, target_ulong newtls) +{ + env->unique = newtls; +} + +static inline abi_ulong get_sp_from_cpustate(CPUSW64State *state) +{ + return state->ir[IDX_SP]; +} +#endif diff --git a/linux-user/sw64/target_elf.h b/linux-user/sw64/target_elf.h new file mode 100644 index 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_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..6393a7542f954ef9b2dc1daad20ae1799eb5d4a5 --- /dev/null +++ b/linux-user/sw64/target_signal.h @@ -0,0 +1,98 @@ +#ifndef SW64_TARGET_SIGNAL_H +#define SW64_TARGET_SIGNAL_H + +#include "cpu.h" + +#define TARGET_SIGHUP 1 +#define TARGET_SIGINT 2 +#define TARGET_SIGQUIT 3 +#define TARGET_SIGILL 4 +#define TARGET_SIGTRAP 5 +#define TARGET_SIGABRT 6 +#define TARGET_SIGSTKFLT 7 /* actually SIGEMT */ +#define TARGET_SIGFPE 8 +#define TARGET_SIGKILL 9 +#define TARGET_SIGBUS 10 +#define TARGET_SIGSEGV 11 +#define TARGET_SIGSYS 12 +#define TARGET_SIGPIPE 13 +#define TARGET_SIGALRM 14 +#define TARGET_SIGTERM 15 +#define TARGET_SIGURG 16 +#define TARGET_SIGSTOP 17 +#define TARGET_SIGTSTP 18 +#define TARGET_SIGCONT 19 +#define TARGET_SIGCHLD 20 +#define TARGET_SIGTTIN 21 +#define TARGET_SIGTTOU 22 +#define TARGET_SIGIO 23 +#define TARGET_SIGXCPU 24 +#define TARGET_SIGXFSZ 25 +#define TARGET_SIGVTALRM 26 +#define TARGET_SIGPROF 27 +#define TARGET_SIGWINCH 28 +#define TARGET_SIGPWR 29 /* actually SIGINFO */ +#define TARGET_SIGUSR1 30 +#define TARGET_SIGUSR2 31 +#define TARGET_SIGRTMIN 32 + +#define TARGET_SIG_BLOCK 1 +#define TARGET_SIG_UNBLOCK 2 +#define TARGET_SIG_SETMASK 3 + +/* this struct defines a stack used during syscall handling */ + +typedef struct target_sigaltstack { + abi_ulong ss_sp; + int32_t ss_flags; + int32_t dummy; + abi_ulong ss_size; +} target_stack_t; + + +/* + * sigaltstack controls + */ +#define TARGET_SS_ONSTACK 1 +#define TARGET_SS_DISABLE 2 + +#define TARGET_SA_ONSTACK 0x00000001 +#define TARGET_SA_RESTART 0x00000002 +#define TARGET_SA_NOCLDSTOP 0x00000004 +#define TARGET_SA_NODEFER 0x00000008 +#define TARGET_SA_RESETHAND 0x00000010 +#define TARGET_SA_NOCLDWAIT 0x00000020 /* not supported yet */ +#define TARGET_SA_SIGINFO 0x00000040 + +#define TARGET_MINSIGSTKSZ 4096 +#define TARGET_SIGSTKSZ 16384 + +/* From . */ +#define TARGET_GEN_INTOVF -1 /* integer overflow */ +#define TARGET_GEN_INTDIV -2 /* integer division by zero */ +#define TARGET_GEN_FLTOVF -3 /* fp overflow */ +#define TARGET_GEN_FLTDIV -4 /* fp division by zero */ +#define TARGET_GEN_FLTUND -5 /* fp underflow */ +#define TARGET_GEN_FLTINV -6 /* invalid fp operand */ +#define TARGET_GEN_FLTINE -7 /* inexact fp operand */ +#define TARGET_GEN_DECOVF -8 /* decimal overflow (for COBOL??) */ +#define TARGET_GEN_DECDIV -9 /* decimal division by zero */ +#define TARGET_GEN_DECINV -10 /* invalid decimal operand */ +#define TARGET_GEN_ROPRAND -11 /* reserved operand */ +#define TARGET_GEN_ASSERTERR -12 /* assertion error */ +#define TARGET_GEN_NULPTRERR -13 /* null pointer error */ +#define TARGET_GEN_STKOVF -14 /* stack overflow */ +#define TARGET_GEN_STRLENERR -15 /* string length error */ +#define TARGET_GEN_SUBSTRERR -16 /* substring error */ +#define TARGET_GEN_RANGERR -17 /* range error */ +#define TARGET_GEN_SUBRNG -18 +#define TARGET_GEN_SUBRNG1 -19 +#define TARGET_GEN_SUBRNG2 -20 +#define TARGET_GEN_SUBRNG3 -21 +#define TARGET_GEN_SUBRNG4 -22 +#define TARGET_GEN_SUBRNG5 -23 +#define TARGET_GEN_SUBRNG6 -24 +#define TARGET_GEN_SUBRNG7 -25 + +#define TARGET_ARCH_HAS_SETUP_FRAME +#endif /* SW64_TARGET_SIGNAL_H */ diff --git a/linux-user/sw64/target_structs.h b/linux-user/sw64/target_structs.h new file mode 100644 index 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..f5383c6836d0f6c332a20a67e6e27cdda5747363 --- /dev/null +++ b/linux-user/sw64/target_syscall.h @@ -0,0 +1,124 @@ +#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 PALcode */ + abi_ulong trap_a0; + abi_ulong trap_a1; + abi_ulong trap_a2; +/* These are saved by PAL-code: */ + 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_MLOCKALL_MCL_CURRENT 0x2000 +#define TARGET_MLOCKALL_MCL_FUTURE 0x4000 + + +#define UNAME_MACHINE "sw64" +#define UNAME_MINIMUM_RELEASE "2.6.32" +#undef TARGET_EOPNOTSUPP +#define TARGET_EOPNOTSUPP 45 /* Operation not supported on transport endpoint */ +#define SWCR_STATUS_INV0 (1UL<<17) +#define SWCR_STATUS_DZE0 (1UL<<18) +#define SWCR_STATUS_OVF0 (1UL<<19) +#define SWCR_STATUS_UNF0 (1UL<<20) +#define SWCR_STATUS_INE0 (1UL<<21) +#define SWCR_STATUS_DNO0 (1UL<<22) + +#define SWCR_STATUS_MASK0 (SWCR_STATUS_INV0 | SWCR_STATUS_DZE0 | \ + SWCR_STATUS_OVF0 | SWCR_STATUS_UNF0 | \ + SWCR_STATUS_INE0 | SWCR_STATUS_DNO0) + +#define SWCR_STATUS0_TO_EXCSUM_SHIFT 16 + +#define SWCR_STATUS_INV1 (1UL<<23) +#define SWCR_STATUS_DZE1 (1UL<<24) +#define SWCR_STATUS_OVF1 (1UL<<25) +#define SWCR_STATUS_UNF1 (1UL<<26) +#define SWCR_STATUS_INE1 (1UL<<27) +#define SWCR_STATUS_DNO1 (1UL<<28) + +#define SWCR_STATUS_MASK1 (SWCR_STATUS_INV1 | SWCR_STATUS_DZE1 | \ + SWCR_STATUS_OVF1 | SWCR_STATUS_UNF1 | \ + SWCR_STATUS_INE1 | SWCR_STATUS_DNO1) + +#define SWCR_STATUS1_TO_EXCSUM_SHIFT 22 +#define SWCR_STATUS_INV2 (1UL<<34) +#define SWCR_STATUS_DZE2 (1UL<<35) +#define SWCR_STATUS_OVF2 (1UL<<36) +#define SWCR_STATUS_UNF2 (1UL<<37) +#define SWCR_STATUS_INE2 (1UL<<38) +#define SWCR_STATUS_DNO2 (1UL<<39) + +#define SWCR_STATUS_MASK2 (SWCR_STATUS_INV2 | SWCR_STATUS_DZE2 | \ + SWCR_STATUS_OVF2 | SWCR_STATUS_UNF2 | \ + SWCR_STATUS_INE2 | SWCR_STATUS_DNO2) +#define SWCR_STATUS_INV3 (1UL<<40) +#define SWCR_STATUS_DZE3 (1UL<<41) +#define SWCR_STATUS_OVF3 (1UL<<42) +#define SWCR_STATUS_UNF3 (1UL<<43) +#define SWCR_STATUS_INE3 (1UL<<44) +#define SWCR_STATUS_DNO3 (1UL<<45) + +#define SWCR_STATUS_MASK3 (SWCR_STATUS_INV3 | SWCR_STATUS_DZE3 | \ + SWCR_STATUS_OVF3 | SWCR_STATUS_UNF3 | \ + SWCR_STATUS_INE3 | SWCR_STATUS_DNO3) +#define SWCR_TRAP_ENABLE_INV (1UL<<1) /* invalid op */ +#define SWCR_TRAP_ENABLE_DZE (1UL<<2) /* division by zero */ +#define SWCR_TRAP_ENABLE_OVF (1UL<<3) /* overflow */ +#define SWCR_TRAP_ENABLE_UNF (1UL<<4) /* underflow */ +#define SWCR_TRAP_ENABLE_INE (1UL<<5) /* inexact */ +#define SWCR_TRAP_ENABLE_DNO (1UL<<6) /* denorm */ +#define SWCR_TRAP_ENABLE_MASK (SWCR_TRAP_ENABLE_INV | SWCR_TRAP_ENABLE_DZE |\ + SWCR_TRAP_ENABLE_OVF | SWCR_TRAP_ENABLE_UNF |\ + SWCR_TRAP_ENABLE_INE | SWCR_TRAP_ENABLE_DNO) + +/* Denorm and Underflow flushing */ +#define SWCR_MAP_DMZ (1UL<<12) /* Map denorm inputs to zero */ +#define SWCR_MAP_UMZ (1UL<<13) /* Map underflowed outputs to zero */ + +#define SWCR_MAP_MASK (SWCR_MAP_DMZ | SWCR_MAP_UMZ) + +/* status bits coming from fpcr: */ +#define SWCR_STATUS_INV (1UL<<17) +#define SWCR_STATUS_DZE (1UL<<18) +#define SWCR_STATUS_OVF (1UL<<19) +#define SWCR_STATUS_UNF (1UL<<20) +#define SWCR_STATUS_INE (1UL<<21) +#define SWCR_STATUS_DNO (1UL<<22) + +#define SWCR_STATUS_MASK (SWCR_STATUS_INV | SWCR_STATUS_DZE | \ + SWCR_STATUS_OVF | SWCR_STATUS_UNF | \ + SWCR_STATUS_INE | SWCR_STATUS_DNO) +#define TARGET_GSI_IEEE_FP_CONTROL 45 +#define TARGET_SSI_IEEE_FP_CONTROL 14 +#endif diff --git a/linux-user/sw64/termbits.h b/linux-user/sw64/termbits.h new file mode 100644 index 0000000000000000000000000000000000000000..b33c3eb49426e12372739e36442c51f88289f4fc --- /dev/null +++ b/linux-user/sw64/termbits.h @@ -0,0 +1,265 @@ +typedef unsigned char target_cc_t; +typedef unsigned int target_speed_t; +typedef unsigned int target_tcflag_t; + +#define TARGET_NCCS 19 +struct target_termios { + target_tcflag_t c_iflag; /* input mode flags */ + target_tcflag_t c_oflag; /* output mode flags */ + target_tcflag_t c_cflag; /* control mode flags */ + target_tcflag_t c_lflag; /* local mode flags */ + target_cc_t c_cc[TARGET_NCCS]; /* control characters */ + target_cc_t c_line; /* line discipline (== c_cc[19]) */ + target_speed_t c_ispeed; /* input speed */ + target_speed_t c_ospeed; /* output speed */ +}; + +/* c_cc characters */ +#define TARGET_VEOF 0 +#define TARGET_VEOL 1 +#define TARGET_VEOL2 2 +#define TARGET_VERASE 3 +#define TARGET_VWERASE 4 +#define TARGET_VKILL 5 +#define TARGET_VREPRINT 6 +#define TARGET_VSWTC 7 +#define TARGET_VINTR 8 +#define TARGET_VQUIT 9 +#define TARGET_VSUSP 10 +#define TARGET_VSTART 12 +#define TARGET_VSTOP 13 +#define TARGET_VLNEXT 14 +#define TARGET_VDISCARD 15 +#define TARGET_VMIN 16 +#define TARGET_VTIME 17 + +/* c_iflag bits */ +#define TARGET_IGNBRK 0000001 +#define TARGET_BRKINT 0000002 +#define TARGET_IGNPAR 0000004 +#define TARGET_PARMRK 0000010 +#define TARGET_INPCK 0000020 +#define TARGET_ISTRIP 0000040 +#define TARGET_INLCR 0000100 +#define TARGET_IGNCR 0000200 +#define TARGET_ICRNL 0000400 +#define TARGET_IXON 0001000 +#define TARGET_IXOFF 0002000 +#define TARGET_IXANY 0004000 +#define TARGET_IUCLC 0010000 +#define TARGET_IMAXBEL 0020000 +#define TARGET_IUTF8 0040000 + +/* c_oflag bits */ +#define TARGET_OPOST 0000001 +#define TARGET_ONLCR 0000002 +#define TARGET_OLCUC 0000004 + +#define TARGET_OCRNL 0000010 +#define TARGET_ONOCR 0000020 +#define TARGET_ONLRET 0000040 + +#define TARGET_OFILL 00000100 +#define TARGET_OFDEL 00000200 +#define TARGET_NLDLY 00001400 +#define TARGET_NL0 00000000 +#define TARGET_NL1 00000400 +#define TARGET_NL2 00001000 +#define TARGET_NL3 00001400 +#define TARGET_TABDLY 00006000 +#define TARGET_TAB0 00000000 +#define TARGET_TAB1 00002000 +#define TARGET_TAB2 00004000 +#define TARGET_TAB3 00006000 +#define TARGET_CRDLY 00030000 +#define TARGET_CR0 00000000 +#define TARGET_CR1 00010000 +#define TARGET_CR2 00020000 +#define TARGET_CR3 00030000 +#define TARGET_FFDLY 00040000 +#define TARGET_FF0 00000000 +#define TARGET_FF1 00040000 +#define TARGET_BSDLY 00100000 +#define TARGET_BS0 00000000 +#define TARGET_BS1 00100000 +#define TARGET_VTDLY 00200000 +#define TARGET_VT0 00000000 +#define TARGET_VT1 00200000 +#define TARGET_XTABS 01000000 /* Hmm.. Linux/i386 considers this part of TABDLY.. */ + +/* c_cflag bit meaning */ +#define TARGET_CBAUD 0000037 +#define TARGET_B0 0000000 /* hang up */ +#define TARGET_B50 0000001 +#define TARGET_B75 0000002 +#define TARGET_B110 0000003 +#define TARGET_B134 0000004 +#define TARGET_B150 0000005 +#define TARGET_B200 0000006 +#define TARGET_B300 0000007 +#define TARGET_B600 0000010 +#define TARGET_B1200 0000011 +#define TARGET_B1800 0000012 +#define TARGET_B2400 0000013 +#define TARGET_B4800 0000014 +#define TARGET_B9600 0000015 +#define TARGET_B19200 0000016 +#define TARGET_B38400 0000017 +#define TARGET_EXTA B19200 +#define TARGET_EXTB B38400 +#define TARGET_CBAUDEX 0000000 +#define TARGET_B57600 00020 +#define TARGET_B115200 00021 +#define TARGET_B230400 00022 +#define TARGET_B460800 00023 +#define TARGET_B500000 00024 +#define TARGET_B576000 00025 +#define TARGET_B921600 00026 +#define TARGET_B1000000 00027 +#define TARGET_B1152000 00030 +#define TARGET_B1500000 00031 +#define TARGET_B2000000 00032 +#define TARGET_B2500000 00033 +#define TARGET_B3000000 00034 +#define TARGET_B3500000 00035 +#define TARGET_B4000000 00036 + +#define TARGET_CSIZE 00001400 +#define TARGET_CS5 00000000 +#define TARGET_CS6 00000400 +#define TARGET_CS7 00001000 +#define TARGET_CS8 00001400 + +#define TARGET_CSTOPB 00002000 +#define TARGET_CREAD 00004000 +#define TARGET_PARENB 00010000 +#define TARGET_PARODD 00020000 +#define TARGET_HUPCL 00040000 + +#define TARGET_CLOCAL 00100000 +#define TARGET_CMSPAR 010000000000 /* mark or space (stick) parity */ +#define TARGET_CRTSCTS 020000000000 /* flow control */ + +/* c_lflag bits */ +#define TARGET_ISIG 0x00000080 +#define TARGET_ICANON 0x00000100 +#define TARGET_XCASE 0x00004000 +#define TARGET_ECHO 0x00000008 +#define TARGET_ECHOE 0x00000002 +#define TARGET_ECHOK 0x00000004 +#define TARGET_ECHONL 0x00000010 +#define TARGET_NOFLSH 0x80000000 +#define TARGET_TOSTOP 0x00400000 +#define TARGET_ECHOCTL 0x00000040 +#define TARGET_ECHOPRT 0x00000020 +#define TARGET_ECHOKE 0x00000001 +#define TARGET_FLUSHO 0x00800000 +#define TARGET_PENDIN 0x20000000 +#define TARGET_IEXTEN 0x00000400 + +#define TARGET_FIOCLEX TARGET_IO('f', 1) +#define TARGET_FIONCLEX TARGET_IO('f', 2) +#define TARGET_FIOASYNC TARGET_IOW('f', 125, int) +#define TARGET_FIONBIO TARGET_IOW('f', 126, int) +#define TARGET_FIONREAD TARGET_IOR('f', 127, int) +#define TARGET_TIOCINQ FIONREAD +#define TARGET_FIOQSIZE TARGET_IOR('f', 128, loff_t) + +#define TARGET_TIOCGETP TARGET_IOR('t', 8, struct target_sgttyb) +#define TARGET_TIOCSETP TARGET_IOW('t', 9, struct target_sgttyb) +#define TARGET_TIOCSETN TARGET_IOW('t', 10, struct target_sgttyb) /* TIOCSETP wo flush */ + +#define TARGET_TIOCSETC TARGET_IOW('t', 17, struct target_tchars) +#define TARGET_TIOCGETC TARGET_IOR('t', 18, struct target_tchars) +#define TARGET_TCGETS TARGET_IOR('t', 19, struct target_termios) +#define TARGET_TCSETS TARGET_IOW('t', 20, struct target_termios) +#define TARGET_TCSETSW TARGET_IOW('t', 21, struct target_termios) +#define TARGET_TCSETSF TARGET_IOW('t', 22, struct target_termios) + +#define TARGET_TCGETA TARGET_IOR('t', 23, struct target_termio) +#define TARGET_TCSETA TARGET_IOW('t', 24, struct target_termio) +#define TARGET_TCSETAW TARGET_IOW('t', 25, struct target_termio) +#define TARGET_TCSETAF TARGET_IOW('t', 28, struct target_termio) + +#define TARGET_TCSBRK TARGET_IO('t', 29) +#define TARGET_TCXONC TARGET_IO('t', 30) +#define TARGET_TCFLSH TARGET_IO('t', 31) + +#define TARGET_TIOCSWINSZ TARGET_IOW('t', 103, struct target_winsize) +#define TARGET_TIOCGWINSZ TARGET_IOR('t', 104, struct target_winsize) +#define TARGET_TIOCSTART TARGET_IO('t', 110) /* start output, like ^Q */ +#define TARGET_TIOCSTOP TARGET_IO('t', 111) /* stop output, like ^S */ +#define TARGET_TIOCOUTQ TARGET_IOR('t', 115, int) /* output queue size */ + +#define TARGET_TIOCGLTC TARGET_IOR('t', 116, struct target_ltchars) +#define TARGET_TIOCSLTC TARGET_IOW('t', 117, struct target_ltchars) +#define TARGET_TIOCSPGRP TARGET_IOW('t', 118, int) +#define TARGET_TIOCGPGRP TARGET_IOR('t', 119, int) + +#define TARGET_TIOCEXCL 0x540C +#define TARGET_TIOCNXCL 0x540D +#define TARGET_TIOCSCTTY 0x540E + +#define TARGET_TIOCSTI 0x5412 +#define TARGET_TIOCMGET 0x5415 +#define TARGET_TIOCMBIS 0x5416 +#define TARGET_TIOCMBIC 0x5417 +#define TARGET_TIOCMSET 0x5418 +# define TARGET_TIOCM_LE 0x001 +# define TARGET_TIOCM_DTR 0x002 +# define TARGET_TIOCM_RTS 0x004 +# define TARGET_TIOCM_ST 0x008 +# define TARGET_TIOCM_SR 0x010 +# define TARGET_TIOCM_CTS 0x020 +# define TARGET_TIOCM_CAR 0x040 +# define TARGET_TIOCM_RNG 0x080 +# define TARGET_TIOCM_DSR 0x100 +# define TARGET_TIOCM_CD TIOCM_CAR +# define TARGET_TIOCM_RI TIOCM_RNG +# define TARGET_TIOCM_OUT1 0x2000 +# define TARGET_TIOCM_OUT2 0x4000 +# define TARGET_TIOCM_LOOP 0x8000 + +#define TARGET_TIOCGSOFTCAR 0x5419 +#define TARGET_TIOCSSOFTCAR 0x541A +#define TARGET_TIOCLINUX 0x541C +#define TARGET_TIOCCONS 0x541D +#define TARGET_TIOCGSERIAL 0x541E +#define TARGET_TIOCSSERIAL 0x541F +#define TARGET_TIOCPKT 0x5420 +# define TARGET_TIOCPKT_DATA 0 +# define TARGET_TIOCPKT_FLUSHREAD 1 +# define TARGET_TIOCPKT_FLUSHWRITE 2 +# define TARGET_TIOCPKT_STOP 4 +# define TARGET_TIOCPKT_START 8 +# define TARGET_TIOCPKT_NOSTOP 16 +# define TARGET_TIOCPKT_DOSTOP 32 + + +#define TARGET_TIOCNOTTY 0x5422 +#define TARGET_TIOCSETD 0x5423 +#define TARGET_TIOCGETD 0x5424 +#define TARGET_TCSBRKP 0x5425 /* Needed for POSIX tcsendbreak() */ +#define TARGET_TIOCSBRK 0x5427 /* BSD compatibility */ +#define TARGET_TIOCCBRK 0x5428 /* BSD compatibility */ +#define TARGET_TIOCGSID 0x5429 /* Return the session ID of FD */ +#define TARGET_TIOCGPTN TARGET_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ +#define TARGET_TIOCSPTLCK TARGET_IOW('T',0x31, int) /* Lock/unlock Pty */ +#define TARGET_TIOCGPTPEER TARGET_IO('T', 0x41) /* Safely open the slave */ + +#define TARGET_TIOCSERCONFIG 0x5453 +#define TARGET_TIOCSERGWILD 0x5454 +#define TARGET_TIOCSERSWILD 0x5455 +#define TARGET_TIOCGLCKTRMIOS 0x5456 +#define TARGET_TIOCSLCKTRMIOS 0x5457 +#define TARGET_TIOCSERGSTRUCT 0x5458 /* For debugging only */ +#define TARGET_TIOCSERGETLSR 0x5459 /* Get line status register */ + /* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */ +# define TARGET_TIOCSER_TEMT 0x01 /* Transmitter physically empty */ +#define TARGET_TIOCSERGETMULTI 0x545A /* Get multiport config */ +#define TARGET_TIOCSERSETMULTI 0x545B /* Set multiport config */ + +#define TARGET_TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */ +#define TARGET_TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */ +#define TARGET_TIOCGHAYESESP 0x545E /* Get Hayes ESP configuration */ +#define TARGET_TIOCSHAYESESP 0x545F /* Set Hayes ESP configuration */ diff --git a/meson.build b/meson.build index 96de1a6ef948542aa93bd03242005907643e6c47..d0bbceffe1337d3f54def01649b7cff8f6270e16 100644 --- a/meson.build +++ b/meson.build @@ -56,7 +56,7 @@ python = import('python').find_installation() supported_oses = ['windows', 'freebsd', 'netbsd', 'openbsd', 'darwin', 'sunos', 'linux'] supported_cpus = ['ppc', 'ppc64', 's390x', 'riscv', 'x86', 'x86_64', - 'arm', 'aarch64', 'mips', 'mips64', 'sparc', 'sparc64'] + 'arm', 'aarch64', 'mips', 'mips64', 'sparc', 'sparc64', 'sw64'] cpu = host_machine.cpu_family() @@ -65,6 +65,10 @@ if cpu in ['riscv32', 'riscv64'] cpu = 'riscv' endif +if cpu == 'sw_64' + cpu = 'sw64' +endif + targetos = host_machine.system() if cpu in ['x86', 'x86_64'] @@ -77,6 +81,8 @@ elif cpu in ['ppc', 'ppc64'] kvm_targets = ['ppc-softmmu', 'ppc64-softmmu'] elif cpu in ['mips', 'mips64'] kvm_targets = ['mips-softmmu', 'mipsel-softmmu', 'mips64-softmmu', 'mips64el-softmmu'] +elif cpu == 'sw64' + kvm_targets = ['sw64-softmmu'] else kvm_targets = [] endif @@ -359,6 +365,8 @@ if not get_option('tcg').disabled() tcg_arch = 'i386' elif config_host['ARCH'] == 'ppc64' tcg_arch = 'ppc' + elif config_host['ARCH'] in ['sw64'] + tcg_arch = 'sw64' endif add_project_arguments('-iquote', meson.current_source_dir() / 'tcg' / tcg_arch, language: ['c', 'cpp', 'objc']) @@ -1814,6 +1822,7 @@ disassemblers = { 'sh4' : ['CONFIG_SH4_DIS'], 'sparc' : ['CONFIG_SPARC_DIS'], 'xtensa' : ['CONFIG_XTENSA_DIS'], + 'sw64' : ['CONFIG_SW64_DIS'], } if link_language == 'cpp' disassemblers += { @@ -2466,6 +2475,7 @@ if have_system 'hw/sparc', 'hw/sparc64', 'hw/ssi', + 'hw/sw64', 'hw/timer', 'hw/tpm', 'hw/usb', diff --git a/pc-bios/core3-hmcode b/pc-bios/core3-hmcode new file mode 100755 index 0000000000000000000000000000000000000000..6092ad0d880092b6be4603015911ca2b91596845 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..fb5daad336e9511424129da3c61cc2197c59e3d3 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..668a9e97b3a39e9bd44273860d1f35505025ec71 Binary files /dev/null and b/pc-bios/core4-hmcode differ diff --git a/pc-bios/meson.build b/pc-bios/meson.build index b40ff3f2bd395f6ef79f49ba4ac85a566ac7307d..05e9065ad6271dd2e1eeaeacca78d75267002cdd 100644 --- a/pc-bios/meson.build +++ b/pc-bios/meson.build @@ -38,6 +38,9 @@ blobs = files( 'vgabios-ramfb.bin', 'vgabios-bochs-display.bin', 'vgabios-ati.bin', + 'uefi-bios-sw', + 'core3-reset', + 'core3-hmcode', 'openbios-sparc32', 'openbios-sparc64', 'openbios-ppc', diff --git a/pc-bios/uefi-bios-sw b/pc-bios/uefi-bios-sw new file mode 100755 index 0000000000000000000000000000000000000000..d99d3ae58fa67db329d2d241b8eb94948d84a7e4 Binary files /dev/null and b/pc-bios/uefi-bios-sw differ diff --git a/qapi/machine.json b/qapi/machine.json index 6822cafe2e07ad7678451b6636d2694bba011e38..6ed84882551f041560b5541da21ba9f8fce28223 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/run_kvm_config.sh b/run_kvm_config.sh new file mode 100755 index 0000000000000000000000000000000000000000..69d82e4c54ab5554d00bbe35e884ae985b59a269 --- /dev/null +++ b/run_kvm_config.sh @@ -0,0 +1 @@ +./configure --target-list=sw64-softmmu --enable-spice --enable-kvm --extra-cflags="-fpic -fPIC" --extra-ldflags="-fpic -fPIC" --enable-debug --enable-seccomp --disable-werror diff --git a/softmmu/qdev-monitor.c b/softmmu/qdev-monitor.c index 05e1d88d99896e770d578751ebe3d9b9172aa553..142352b24ebd2c032b7d5d72b132612e91e310ff 100644 --- a/softmmu/qdev-monitor.c +++ b/softmmu/qdev-monitor.c @@ -61,7 +61,8 @@ typedef struct QDevAlias QEMU_ARCH_HPPA | QEMU_ARCH_I386 | \ QEMU_ARCH_MIPS | QEMU_ARCH_PPC | \ QEMU_ARCH_RISCV | QEMU_ARCH_SH4 | \ - QEMU_ARCH_SPARC | QEMU_ARCH_XTENSA) + QEMU_ARCH_SPARC | QEMU_ARCH_XTENSA | \ + QEMU_ARCH_SW64) #define QEMU_ARCH_VIRTIO_CCW (QEMU_ARCH_S390X) #define QEMU_ARCH_VIRTIO_MMIO (QEMU_ARCH_M68K) diff --git a/target/Kconfig b/target/Kconfig index ae7f24fc66b00dea4318be4793fbf315dde02b90..a8d6cb1e972356decfc8962fc7675cc97b5e530f 100644 --- a/target/Kconfig +++ b/target/Kconfig @@ -17,3 +17,4 @@ source sh4/Kconfig source sparc/Kconfig source tricore/Kconfig source xtensa/Kconfig +source sw64/Kconfig diff --git a/target/meson.build b/target/meson.build index 2f6940255e6583e344ec0892fd8c4b55ee75766d..ec6bc97331b4b936630632af0f0c52263aea7867 100644 --- a/target/meson.build +++ b/target/meson.build @@ -16,5 +16,6 @@ subdir('rx') subdir('s390x') subdir('sh4') subdir('sparc') +subdir('sw64') subdir('tricore') subdir('xtensa') diff --git a/target/sw64/Kconfig b/target/sw64/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..ad50b9677e553c84e275134f40383e375956b6f1 --- /dev/null +++ b/target/sw64/Kconfig @@ -0,0 +1,2 @@ +config SW64 + bool diff --git a/target/sw64/Makefile.objs b/target/sw64/Makefile.objs new file mode 100644 index 0000000000000000000000000000000000000000..1e549d141c167c037c17ce0d0232790971a2f639 --- /dev/null +++ b/target/sw64/Makefile.objs @@ -0,0 +1,4 @@ +obj-$(CONFIG_SOFTMMU) += machine.o +obj-y += cpu.o translate.o profile.o helper.o +obj-y += int_helper.o float_helper.o simd_helper.o helper.o exception.o +obj-$(CONFIG_KVM) += kvm.o diff --git a/target/sw64/cpu-param.h b/target/sw64/cpu-param.h new file mode 100644 index 0000000000000000000000000000000000000000..978a3cd572513aaa49f41d6e9fa02b9d449f4971 --- /dev/null +++ b/target/sw64/cpu-param.h @@ -0,0 +1,24 @@ +/* + * SW64 cpu parameters for qemu. + * + * Copyright (c) 2018 Lin Hainan + */ + +#ifndef SW64_CPU_PARAM_H +#define SW64_CPU_PARAM_H 1 + +#define TARGET_LONG_BITS 64 /* if use th-1 ,TARGET_PAGE_BITS is 12 */ +#define TARGET_PAGE_BITS 13 + +#ifdef CONFIG_USER_ONLY +#define TARGET_VIRT_ADDR_SPACE_BITS 64 +#else +#define TARGET_PHYS_ADDR_SPACE_BITS 48 +#define TARGET_VIRT_ADDR_SPACE_BITS 64 +#endif + +#ifndef CONFIG_USER_ONLY +#define NB_MMU_MODES 4 +#endif + +#endif diff --git a/target/sw64/cpu-qom.h b/target/sw64/cpu-qom.h new file mode 100644 index 0000000000000000000000000000000000000000..b093c2bec81d1a001228fb51d7ff4e625fa72e44 --- /dev/null +++ b/target/sw64/cpu-qom.h @@ -0,0 +1,47 @@ +/* + * QEMU SW64 CPU + * + * Copyright (c) 2018 Lin Hainan + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#ifndef QEMU_SW64_CPU_QOM +#define QEMU_SW64_CPU_QOM + +#include "hw/core/cpu.h" + +#define TYPE_SW64_CPU "sw64-cpu" + +#define SW64_CPU_CLASS(kclass) \ + OBJECT_CLASS_CHECK(SW64CPUClass, (kclass), TYPE_SW64_CPU) +#define SW64_CPU(obj) \ + OBJECT_CHECK(SW64CPU, (obj), TYPE_SW64_CPU) +#define SW64_CPU_GET_CLASS(obj) \ + OBJECT_GET_CLASS(SW64CPUClass, (obj), TYPE_SW64_CPU) + +/** + * SW64CPUClass: + * @parent_realize: The parent class' realize handler. + * @parent_reset: The parent class' reset handler. + * + * An SW64 CPU model. + */ +typedef struct SW64CPUClass { + /* private */ + CPUClass parent_class; + /* public */ + DeviceRealize parent_realize; + DeviceReset parent_reset; +} SW64CPUClass; + +typedef struct SW64CPU SW64CPU; +#endif diff --git a/target/sw64/cpu.c b/target/sw64/cpu.c new file mode 100644 index 0000000000000000000000000000000000000000..97d4fb7a060beb33a6a02737ebf95328ec5fbec4 --- /dev/null +++ b/target/sw64/cpu.c @@ -0,0 +1,490 @@ +/* + * QEMU SW64 CPU + * + * Copyright (c) 2018 Lin Hainan + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu/qemu-print.h" +#include "cpu.h" +#include "exec/exec-all.h" +#include "sysemu/kvm.h" +#include "disas/dis-asm.h" +#include "kvm_sw64.h" +#include "sysemu/reset.h" +#include "hw/qdev-properties.h" + + +static void sw64_cpu_set_pc(CPUState *cs, vaddr value) +{ + SW64CPU *cpu = SW64_CPU(cs); + + cpu->env.pc = value; +} + +static void sw64_cpu_dump_state(CPUState *cs, FILE *f, int flags) +{ +#ifndef CONFIG_KVM + SW64CPU *cpu = SW64_CPU(cs); + CPUSW64State *env = &cpu->env; + int i; + + static const char ireg_names[31][4] = { + "v0", "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "s0", "s1", + "s2", "s3", "s4", "s5", "fp", "a0", "a1", "a2", "a3", "a4", "a5", + "t8", "t9", "t10", "t11", "ra", "t12", "at", "gp", "sp"}; + static const char freg_names[128][4] = { + "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", + "f10", "f11", "f12", "f13", "f14", "f15", "f16", "f17", "f18", "f19", + "f20", "f21", "f22", "f23", "f24", "f25", "f26", "f27", "f28", "f29", + "f30", "f31", "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", + "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", "f16", "f17", + "f18", "f19", "f20", "f21", "f22", "f23", "f24", "f25", "f26", "f27", + "f28", "f29", "f30", "f31", "f0", "f1", "f2", "f3", "f4", "f5", + "f6", "f7", "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", + "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", "f24", "f25", + "f26", "f27", "f28", "f29", "f30", "f31", "f0", "f1", "f2", "f3", + "f4", "f5", "f6", "f7", "f8", "f9", "f10", "f11", "f12", "f13", + "f14", "f15", "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", + "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31"}; + qemu_fprintf(f, "PC=%016" PRIx64 " SP=%016" PRIx64 "\n", env->pc, + env->ir[IDX_SP]); + for (i = 0; i < 31; i++) { + qemu_fprintf(f, "%s=%016" PRIx64, ireg_names[i], env->ir[i]); + if ((i % 4) == 3) { + qemu_fprintf(f, "\n"); + } else { + qemu_fprintf(f, " "); + } + } + qemu_fprintf(f, "\n"); +#ifndef CONFIG_USER_ONLY + static const char sreg_names[10][4] = {"p1", "p2", "p4", "p5", "p6", + "p7", "p20", "p21", "p22", "p23"}; + for (i = 0; i < 10; i++) { + qemu_fprintf(f, "%s=%016" PRIx64, sreg_names[i], env->sr[i]); + if ((i % 4) == 3) { + qemu_fprintf(f, "\n"); + } else { + qemu_fprintf(f, " "); + } + } + qemu_fprintf(f, "\n"); +#endif + for (i = 0; i < 32; i++) { + qemu_fprintf(f, "%s=%016" PRIx64, freg_names[i + 96], env->fr[i + 96]); + qemu_fprintf(f, " %016" PRIx64, env->fr[i + 64]); + qemu_fprintf(f, " %016" PRIx64, env->fr[i + 32]); + qemu_fprintf(f, " %016" PRIx64, env->fr[i]); + qemu_fprintf(f, "\n"); + } + qemu_fprintf(f, "\n"); +#endif +} + +#ifndef CONFIG_USER_ONLY +static void sw64_machine_cpu_reset(void *opaque) +{ + SW64CPU *cpu = opaque; + + cpu_reset(CPU(cpu)); +} +#endif + +static void sw64_cpu_realizefn(DeviceState *dev, Error **errp) +{ + CPUState *cs = CPU(dev); + SW64CPUClass *scc = SW64_CPU_GET_CLASS(dev); + Error *local_err = NULL; + + cpu_exec_realizefn(cs, &local_err); + if (local_err != NULL) { + error_propagate(errp, local_err); + return; + } +#ifndef CONFIG_USER_ONLY + qemu_register_reset(sw64_machine_cpu_reset, cs); +#endif + + qemu_init_vcpu(cs); + + scc->parent_realize(dev, errp); +} + +static void sw64_cpu_disas_set_info(CPUState *cs, disassemble_info *info) +{ + CPUSW64State *env = cs->env_ptr; + if (test_feature(env, SW64_FEATURE_CORE3)) + info->mach = bfd_mach_sw_64_core3; + else if(test_feature(env, SW64_FEATURE_CORE4)) + info->mach = bfd_mach_sw_64_core4; + info->print_insn = print_insn_sw_64; +} + +#include "fpu/softfloat.h" + +static void core3_init(Object *obj) +{ + CPUState *cs = CPU(obj); + CPUSW64State *env = cs->env_ptr; +#ifdef CONFIG_USER_ONLY + env->fpcr = 0x680e800000000000; + parallel_cpus = true; +#endif + set_feature(env, SW64_FEATURE_CORE3); +} + +static void core4_init(Object *obj) +{ + CPUState *cs = CPU(obj); + CPUSW64State *env = cs->env_ptr; +#ifdef CONFIG_USER_ONLY + env->fpcr = 0x680e800000000000; + parallel_cpus = true; +#endif + set_feature(env, SW64_FEATURE_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_IIMAIL | CPU_INTERRUPT_MCHK); +} + +static void sw64_cpu_initfn(Object *obj) +{ + CPUState *cs = CPU(obj); + SW64CPU *cpu = SW64_CPU(obj); + CPUSW64State *env = &cpu->env; + + cpu_set_cpustate_pointers(cpu); + + cs->env_ptr = env; +#ifndef CONFIG_USER_ONLY + env->flags = ENV_FLAG_HM_MODE; +#else + env->flags = ENV_FLAG_PS_USER; + cpu->int_en = 0; +#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 DEBUGWYH + if (retaddr) { + cpu_restore_state(cs, retaddr,true); + } + fprintf(stderr, "PC = %lx, Wrong IO addr. Hwaddr = %lx, vaddr = %lx, access_type = %d\n", + env->pc, physaddr, addr, access_type); +#endif +} +#endif + +#define a0(func) (((func & 0xFF) >> 6) & 0x1) +#define a1(func) ((((func & 0xFF) >> 6) & 0x2) >> 1) + +#define t(func) ((a0(func) ^ a1(func)) & 0x1) +#define b0(func) (t(func) | a0(func)) +#define b1(func) ((~t(func) & 1) | a1(func)) + +#define START_SYS_CALL_ADDR(func) \ + (b1(func) << 14) | (b0(func) << 13) | ((func & 0x3F) << 7) + +static void sw64_cpu_do_interrupt(CPUState *cs) +{ + int i = cs->exception_index; + + cs->exception_index = -1; +#if !defined(CONFIG_USER_ONLY) + SW64CPU *cpu = SW64_CPU(cs); + CPUSW64State *env = &cpu->env; + switch (i) { + case EXCP_OPCDEC: + cpu_abort(cs, "ILLEGAL INSN"); + break; + case EXCP_CALL_SYS: + i = START_SYS_CALL_ADDR(env->error_code); + if (i <= 0x3F) { + i += 0x4000; + } else if (i >= 0x40 && i <= 0x7F) { + i += 0x2000; + } else if (i >= 0x80 && i <= 0x8F) { + i += 0x6000; + } + break; + case EXCP_ARITH: + env->error_code = -1; + env->csr[EXC_PC] = env->pc - 4; + env->csr[EXC_SUM] = 1; + i = 0xB80; + break; + case EXCP_UNALIGN: + i = 0xB00; + env->csr[EXC_PC] = env->pc - 4; + break; + case EXCP_CLK_INTERRUPT: + case EXCP_DEV_INTERRUPT: + 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_IIMAIL: + env->csr[EXC_PC] = env->pc; + i = 0xE00; + break; + default: + break; + } + env->pc = env->hm_entry + i; + env->flags = ENV_FLAG_HM_MODE; +#else + switch (i) { + case EXCP_OPCDEC: + cpu_abort(cs, "ILLEGAL INSN"); + break; + case EXCP_CALL_SYS: + default: + break; + } +#endif +} + +#ifndef CONFIG_USER_ONLY +static bool sw64_cpu_exec_interrupt(CPUState *cs, int interrupt_request) +{ + SW64CPU *cpu = SW64_CPU(cs); + CPUSW64State *env = &cpu->env; + int idx = -1, INT_STAT = 0, IER = 0; + /* We never take interrupts while in PALmode. */ + if (env->flags & ENV_FLAG_HM_MODE) + return false; + + cpu->int_en =1; + if (cpu->int_en == 0) + return false; + + if (test_feature(env, SW64_FEATURE_CORE3)) { + IER = C3_IER; + INT_STAT = C3_INT_STAT; + } else if (test_feature(env, SW64_FEATURE_CORE4)) { + IER = INT_EN; + INT_STAT = C4_INT_STAT; + } + + if (interrupt_request & CPU_INTERRUPT_IIMAIL) { + idx = EXCP_IIMAIL; + env->csr[INT_STAT] |= 1UL << 6; + if ((env->csr[IER] & env->csr[INT_STAT]) == 0) + return false; + cs->interrupt_request &= ~CPU_INTERRUPT_IIMAIL; + goto done; + } + + if (interrupt_request & CPU_INTERRUPT_TIMER) { + idx = EXCP_CLK_INTERRUPT; + env->csr[INT_STAT] |= 1UL << 4; + if ((env->csr[IER] & env->csr[INT_STAT]) == 0) return false; + cs->interrupt_request &= ~CPU_INTERRUPT_TIMER; + goto done; + } + + if (interrupt_request & CPU_INTERRUPT_HARD) { + idx = EXCP_DEV_INTERRUPT; + env->csr[INT_STAT] |= 1UL << 1; + 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; + if ((env->csr[IER] & env->csr[INT_STAT]) == 0) return false; + cs->interrupt_request &= ~CPU_INTERRUPT_PCIE; + goto done; + } + +done: + if (idx >= 0) { + cs->exception_index = idx; + env->error_code = 0; + env->csr[EXC_PC] = env->pc; + sw64_cpu_do_interrupt(cs); + return true; + } + return false; +} +#endif + +static void sw64_cpu_reset(DeviceState *dev) +{ + CPUState *s = CPU(dev); + SW64CPU *cpu = SW64_CPU(s); + SW64CPUClass *scc = SW64_CPU_GET_CLASS(cpu); + + scc->parent_reset(dev); + +#ifndef CONFIG_USER_ONLY + if (kvm_enabled()) { + kvm_sw64_reset_vcpu(cpu); + } +#endif +} + +static Property sw64_cpu_properties[] = { +#ifdef CONFIG_USER_ONLY + /* apic_id = 0 by default for *-user, see commit 9886e834 */ + DEFINE_PROP_UINT32("cid", SW64CPU, cid, 0), +#else + DEFINE_PROP_UINT32("cid", SW64CPU, cid, 0xFFFFFFFF), +#endif + DEFINE_PROP_END_OF_LIST() +}; + +#ifndef CONFIG_USER_ONLY +#include "hw/core/sysemu-cpu-ops.h" + +static const struct SysemuCPUOps sw64_sysemu_ops = { + .get_phys_page_debug = sw64_cpu_get_phys_page_debug, +}; +#endif + +#include "hw/core/tcg-cpu-ops.h" +/* + * NB: cannot be const, as some elements are changed for specific + * mips hardware (see hw/mips/jazz.c). + */ +static const struct TCGCPUOps sw64_tcg_ops = { +#ifdef CONFIG_TCG + .initialize = sw64_translate_init, + .tlb_fill = sw64_cpu_tlb_fill, +#endif /* CONFIG_TCG */ + +#if !defined(CONFIG_USER_ONLY) + .do_unaligned_access = sw64_cpu_do_unaligned_access, + .cpu_exec_interrupt = sw64_cpu_exec_interrupt, + .do_transaction_failed = sw64_cpu_do_transaction_failed, +#endif /* !CONFIG_USER_ONLY */ + .do_interrupt = sw64_cpu_do_interrupt, +}; + +static void sw64_cpu_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + CPUClass *cc = CPU_CLASS(oc); + SW64CPUClass *scc = SW64_CPU_CLASS(oc); + + device_class_set_parent_realize(dc, sw64_cpu_realizefn, + &scc->parent_realize); + device_class_set_parent_reset(dc, sw64_cpu_reset, &scc->parent_reset); + device_class_set_props(dc, sw64_cpu_properties); + + cc->class_by_name = sw64_cpu_class_by_name; + dc->vmsd = &vmstate_sw64_cpu; + cc->has_work = sw64_cpu_has_work; + cc->set_pc = sw64_cpu_set_pc; + cc->disas_set_info = sw64_cpu_disas_set_info; + cc->dump_state = sw64_cpu_dump_state; + cc->tcg_ops = &sw64_tcg_ops; +#ifndef CONFIG_USER_ONLY + cc->sysemu_ops = &sw64_sysemu_ops; +#endif +} + +static const SW64CPUInfo sw64_cpus[] = +{ + { + .name = "core3", + .initfn = core3_init, + }, + { + .name = "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..4a8629d1d1b5fde4cf76e0ca73be979375e43ab8 --- /dev/null +++ b/target/sw64/cpu.h @@ -0,0 +1,406 @@ +/* + * SW64 emulation cpu definitions for qemu. + * + * Copyright (c) 2018 Lin Hainan + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + */ +#ifndef SW64_CPU_H +#define SW64_CPU_H + +#include "cpu-qom.h" +#include "fpu/softfloat.h" +#include "profile.h" +#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 PALcode uses all 4 modes; + The Unix PALcode only uses bit 4. */ +#define PS_USER_MODE 8u + +#define ENV_FLAG_HM_SHIFT 0 +#define ENV_FLAG_PS_SHIFT 8 +#define ENV_FLAG_FEN_SHIFT 24 + +#define ENV_FLAG_HM_MODE (1u << ENV_FLAG_HM_SHIFT) +#define ENV_FLAG_PS_USER (PS_USER_MODE << ENV_FLAG_PS_SHIFT) +#define ENV_FLAG_FEN (1u << ENV_FLAG_FEN_SHIFT) + +#define MCU_CLOCK 25000000 + +typedef struct CPUSW64State CPUSW64State; +typedef CPUSW64State CPUArchState; +typedef SW64CPU ArchCPU; + +struct CPUSW64State { + uint64_t ir[32]; + uint64_t fr[128]; + uint64_t pc; + bool is_slave; + + uint64_t csr[0x100]; + uint64_t fpcr; + uint64_t fpcr_exc_enable; + uint8_t fpcr_round_mode; + uint8_t fpcr_flush_to_zero; + + float_status fp_status; + + uint64_t hm_entry; + +#if !defined(CONFIG_USER_ONLY) + uint64_t sr[10]; /* shadow regs 1,2,4-7,20-23 */ +#endif + + uint32_t flags; + uint64_t error_code; + uint64_t unique; + uint64_t lock_addr; + uint64_t lock_valid; + uint64_t lock_flag; + uint64_t lock_success; +#ifdef SW64_FIXLOCK + uint64_t lock_value; +#endif + + uint64_t trap_arg0; + uint64_t trap_arg1; + uint64_t trap_arg2; + + uint64_t features; + uint64_t insn_count[537]; + + /* reserve for slave */ + uint64_t ca[4]; + uint64_t scala_gpr[64]; + uint64_t vec_gpr[224]; + uint64_t fpcr_base; + uint64_t fpcr_ext; + uint64_t pendding_flag; + uint64_t pendding_status; + uint64_t synr_pendding_status; + uint64_t sync_pendding_status; + uint8_t vlenma_idxa; + uint8_t stable; +}; +#define SW64_FEATURE_TH1 0x1 +#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[158]; + uint64_t k_vcb[36]; + QEMUTimer *alarm_timer; + target_ulong int_en; + target_ulong irq; + uint32_t cid; +}; + +enum { + IDX_V0 = 0, + IDX_T0 = 1, + IDX_T1 = 2, + IDX_T2 = 3, + IDX_T3 = 4, + IDX_T4 = 5, + IDX_T5 = 6, + IDX_T6 = 7, + IDX_T7 = 8, + IDX_S0 = 9, + IDX_S1 = 10, + IDX_S2 = 11, + IDX_S3 = 12, + IDX_S4 = 13, + IDX_S5 = 14, + IDX_S6 = 15, + IDX_FP = IDX_S6, + IDX_A0 = 16, + IDX_A1 = 17, + IDX_A2 = 18, + IDX_A3 = 19, + IDX_A4 = 20, + IDX_A5 = 21, + IDX_T8 = 22, + IDX_T9 = 23, + IDX_T10 = 24, + IDX_T11 = 25, + IDX_RA = 26, + IDX_T12 = 27, + IDX_PV = IDX_T12, + IDX_AT = 28, + IDX_GP = 29, + IDX_SP = 30, + IDX_ZERO = 31, +}; + +enum { + MM_K_TNV = 0x0, + MM_K_ACV = 0x1, + MM_K_FOR = 0x2, + MM_K_FOE = 0x3, + MM_K_FOW = 0x4 +}; + +enum { + PTE_VALID = 0x0001, + PTE_FOR = 0x0002, /* used for page protection (fault on read) */ + PTE_FOW = 0x0004, /* used for page protection (fault on write) */ + PTE_FOE = 0x0008, + PTE_KS = 0x0010, + PTE_PSE = 0x0040, + PTE_GH = 0x0060, + PTE_HRE = 0x0100, + PTE_VRE = 0x0200, + PTE_KRE = 0x0400, + PTE_URE = 0x0800, + PTE_HWE = 0x1000, + PTE_VWE = 0x2000, + PTE_KWE = 0x4000, + PTE_UWE = 0x8000 +}; + +static inline int cpu_mmu_index(CPUSW64State *env, bool ifetch) +{ + int ret = env->flags & ENV_FLAG_PS_USER ? MMU_USER_IDX : MMU_KERNEL_IDX; + if (env->flags & ENV_FLAG_HM_MODE) { + ret = MMU_PHYS_IDX; + } + return ret; +} + +static inline SW64CPU *sw64_env_get_cpu(CPUSW64State *env) +{ + return container_of(env, SW64CPU, env); +} + +#define ENV_GET_CPU(e) CPU(sw64_env_get_cpu(e)) +#define ENV_OFFSET offsetof(SW64CPU, env) + +#define cpu_init(cpu_model) cpu_generic_init(TYPE_SW64_CPU, cpu_model) + +#define SW64_CPU_TYPE_SUFFIX "-" TYPE_SW64_CPU +#define SW64_CPU_TYPE_NAME(name) (name SW64_CPU_TYPE_SUFFIX) +int cpu_sw64_signal_handler(int host_signum, void *pinfo, void *puc); +bool sw64_cpu_tlb_fill(CPUState *cs, vaddr address, int size, + MMUAccessType access_type, int mmu_idx, + bool probe, uintptr_t retaddr); +uint64_t sw64_ldl_phys(CPUState *cs, hwaddr addr); +hwaddr sw64_cpu_get_phys_page_debug(CPUState *cs, vaddr addr); +void sw64_stl_phys(CPUState *cs, hwaddr addr, uint64_t val); +uint64_t sw64_ldw_phys(CPUState *cs, hwaddr addr); +void sw64_stw_phys(CPUState *cs, hwaddr addr, uint64_t val); +uint64_t cpu_sw64_load_fpcr(CPUSW64State *env); +void cpu_sw64_store_fpcr(CPUSW64State *env, uint64_t val); +void sw64_cpu_do_unaligned_access(CPUState *cs, vaddr addr, + MMUAccessType access_type, int mmu_idx, + uintptr_t retaddr); +bool sw64_cpu_has_work(CPUState *cs); +extern struct VMStateDescription vmstate_sw64_cpu; + +/* SW64-specific interrupt pending bits */ +#define CPU_INTERRUPT_TIMER CPU_INTERRUPT_TGT_EXT_0 +#define CPU_INTERRUPT_IIMAIL CPU_INTERRUPT_TGT_EXT_1 +#define CPU_INTERRUPT_MCHK CPU_INTERRUPT_TGT_EXT_2 +#define CPU_INTERRUPT_PCIE CPU_INTERRUPT_TGT_EXT_3 +#define CPU_INTERRUPT_WAKEUP CPU_INTERRUPT_TGT_EXT_3 +#define CPU_INTERRUPT_SLAVE CPU_INTERRUPT_TGT_EXT_4 + +#define cpu_signal_handler cpu_sw64_signal_handler +#define CPU_RESOLVING_TYPE TYPE_SW64_CPU + +#define SWCSR(x, y) x = y +enum { + SWCSR(ITB_TAG, 0x0), + SWCSR(ITB_PTE, 0x1), + SWCSR(ITB_IA, 0x2), + SWCSR(ITB_IV, 0x3), + SWCSR(ITB_IVP, 0x4), + SWCSR(ITB_IU, 0x5), + SWCSR(ITB_IS, 0x6), + SWCSR(EXC_SUM, 0xd), + SWCSR(EXC_PC, 0xe), + SWCSR(DS_STAT, 0x48), + SWCSR(CID, 0xc4), + SWCSR(TID, 0xc7), + + SWCSR(DTB_TAG, 0x40), + SWCSR(DTB_PTE, 0x41), + SWCSR(DTB_IA, 0x42), + SWCSR(DTB_IV, 0x43), + SWCSR(DTB_IVP, 0x44), + SWCSR(DTB_IU, 0x45), + SWCSR(DTB_IS, 0x46), + SWCSR(II_REQ, 0x82), +/* core3 csr */ + SWCSR(C3_PTBR, 0x8), + SWCSR(C3_DVA, 0x4e), + SWCSR(C3_INT_STAT, 0x30), + SWCSR(C3_INT_CLR, 0x31), + SWCSR(C3_IER, 0x32), +/* core4 csr */ + SWCSR(INT_EN, 0x1a), + SWCSR(C4_DVA, 0x54), + SWCSR(C4_PTBR0, 0x68), + SWCSR(C4_PTBR1, 0x69), + SWCSR(C4_INT_STAT, 0x1b), + SWCSR(C4_INT_CLR, 0x1c), +}; + +#include "exec/cpu-all.h" +static inline void cpu_get_tb_cpu_state(CPUSW64State *env, target_ulong *pc, + target_ulong *cs_base, uint32_t *pflags) +{ + *pc = env->pc; + *cs_base = 0; + *pflags = env->flags; +} + +void sw64_translate_init(void); + +enum { + EXCP_NONE, + EXCP_HALT, + EXCP_IIMAIL, + EXCP_OPCDEC, + EXCP_CALL_SYS, + EXCP_ARITH, + EXCP_UNALIGN, +#ifdef SOFTMMU + EXCP_MMFAULT, +#else + EXCP_DTBD, + EXCP_DTBS_U, + EXCP_DTBS_K, + EXCP_ITB_U, + EXCP_ITB_K, +#endif + EXCP_CLK_INTERRUPT, + EXCP_DEV_INTERRUPT, + EXCP_SLAVE, +}; + +#define CSR_SHIFT_AND_MASK(name, func, shift, bits) \ + name##_##func##_S = shift, \ + name##_##func##_V = bits, \ + name##_##func##_M = (1UL << bits) - 1 + +#define FPCR_MASK(name) ((uint64_t)FPCR_##name##_M << FPCR_##name##_S) +/* FPCR */ +enum { + CSR_SHIFT_AND_MASK(FPCR, EXC_CTL, 0, 2), + CSR_SHIFT_AND_MASK(FPCR, EXC_CTL_WEN, 2, 1), + CSR_SHIFT_AND_MASK(FPCR, RSV0, 3, 1), + CSR_SHIFT_AND_MASK(FPCR, INV3, 4, 1), + CSR_SHIFT_AND_MASK(FPCR, ZERO0, 5, 1), + CSR_SHIFT_AND_MASK(FPCR, OVF3, 6, 1), + CSR_SHIFT_AND_MASK(FPCR, UNF3, 7, 1), + CSR_SHIFT_AND_MASK(FPCR, INE3, 8, 1), + CSR_SHIFT_AND_MASK(FPCR, ZERO1, 9, 1), + CSR_SHIFT_AND_MASK(FPCR, RSV1, 10, 10), + CSR_SHIFT_AND_MASK(FPCR, INV2, 20, 1), + CSR_SHIFT_AND_MASK(FPCR, ZERO2, 21, 1), + CSR_SHIFT_AND_MASK(FPCR, OVF2, 22, 1), + CSR_SHIFT_AND_MASK(FPCR, UNF2, 23, 1), + CSR_SHIFT_AND_MASK(FPCR, INE2, 24, 1), + CSR_SHIFT_AND_MASK(FPCR, ZERO3, 25, 1), + CSR_SHIFT_AND_MASK(FPCR, RSV2, 26, 10), + CSR_SHIFT_AND_MASK(FPCR, INV1, 36, 1), + CSR_SHIFT_AND_MASK(FPCR, ZERO4, 37, 1), + CSR_SHIFT_AND_MASK(FPCR, OVF1, 38, 1), + CSR_SHIFT_AND_MASK(FPCR, UNF1, 39, 1), + CSR_SHIFT_AND_MASK(FPCR, INE1, 40, 1), + CSR_SHIFT_AND_MASK(FPCR, ZERO5, 41, 1), + CSR_SHIFT_AND_MASK(FPCR, RSV3, 42, 6), + CSR_SHIFT_AND_MASK(FPCR, DNZ, 48, 1), + CSR_SHIFT_AND_MASK(FPCR, INVD, 49, 1), + CSR_SHIFT_AND_MASK(FPCR, DZED, 50, 1), + CSR_SHIFT_AND_MASK(FPCR, OVFD, 51, 1), + CSR_SHIFT_AND_MASK(FPCR, INV0, 52, 1), + CSR_SHIFT_AND_MASK(FPCR, DZE0, 53, 1), + CSR_SHIFT_AND_MASK(FPCR, OVF0, 54, 1), + CSR_SHIFT_AND_MASK(FPCR, UNF0, 55, 1), + CSR_SHIFT_AND_MASK(FPCR, INE0, 56, 1), + CSR_SHIFT_AND_MASK(FPCR, OVI0, 57, 1), + CSR_SHIFT_AND_MASK(FPCR, DYN, 58, 2), + CSR_SHIFT_AND_MASK(FPCR, UNDZ, 60, 1), + CSR_SHIFT_AND_MASK(FPCR, UNFD, 61, 1), + CSR_SHIFT_AND_MASK(FPCR, INED, 62, 1), + CSR_SHIFT_AND_MASK(FPCR, SUM, 63, 1), +}; + +/* Arithmetic exception (entArith) constants. */ +#define EXC_M_SWC 1 /* Software completion */ +#define EXC_M_INV 2 /* Invalid operation */ +#define EXC_M_DZE 4 /* Division by zero */ +#define EXC_M_OVF 8 /* Overflow */ +#define EXC_M_UNF 16 /* Underflow */ +#define EXC_M_INE 32 /* Inexact result */ +#define EXC_M_IOV 64 /* Integer Overflow */ +#define EXC_M_DNO 128 /* Denomal operation */ + +void QEMU_NORETURN dynamic_excp(CPUSW64State *env, uintptr_t retaddr, int excp, + int error); +void QEMU_NORETURN arith_excp(CPUSW64State *env, uintptr_t retaddr, int exc, + uint64_t mask); + +#define DEBUG_ARCH +#ifdef DEBUG_ARCH +#define arch_assert(x) \ + do { \ + g_assert(x); /*fprintf(stderr, "+6b %d\n", __LINE__); */ \ + } while (0) +#else +#define arch_assert(x) +#endif + +typedef struct SW64CPUInfo { + const char *name; + void (*initfn)(Object *obj); + void (*class_init)(ObjectClass *oc, void *data); +} SW64CPUInfo; +#define test_feature(env, x) (env->features & (x)) + +/* Slave */ +#endif diff --git a/target/sw64/exception.c b/target/sw64/exception.c new file mode 100644 index 0000000000000000000000000000000000000000..664173a479b3063ccac68f36b0d4dbe9f245f46f --- /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..b93d08049e7ddef1c01cf1c49341934f7c691c16 --- /dev/null +++ b/target/sw64/float_helper.c @@ -0,0 +1,872 @@ +#include "qemu/osdep.h" +#include "cpu.h" +#include "exec/exec-all.h" +#include "exec/helper-proto.h" +#include "fpu/softfloat.h" + +static inline uint32_t extractFloat16Frac(float16 a) +{ + return float16_val(a) & 0x3ff; +} + +/*---------------------------------------------------------------------------- +| Returns the exponent bits of the half-precision floating-point value `a'. +*----------------------------------------------------------------------------*/ + +static inline int extractFloat16Exp(float16 a) +{ + return (float16_val(a) >> 10) & 0x1f; +} + +/*---------------------------------------------------------------------------- +| Returns the sign bit of the single-precision floating-point value `a'. +*----------------------------------------------------------------------------*/ + +static inline uint8_t extractFloat16Sign(float16 a) +{ + return float16_val(a) >> 15; +} + +#define FP_STATUS (env->fp_status) + +#define CONVERT_BIT(X, SRC, DST) \ + (SRC > DST ? (X) / (SRC / DST) & (DST) : ((X)&SRC) * (DST / SRC)) + +static uint64_t soft_to_errcode_exc(CPUSW64State *env) +{ + uint8_t exc = get_float_exception_flags(&FP_STATUS); + + if (unlikely(exc)) { + set_float_exception_flags(0, &FP_STATUS); + } + return exc; +} + +static inline uint64_t float32_to_s_int(uint32_t fi) +{ + uint32_t frac = fi & 0x7fffff; + uint32_t sign = (fi >> 31) & 1; + uint32_t exp_msb = (fi >> 30) & 1; + uint32_t exp_low = (fi >> 23) & 0x7f; + uint32_t exp; + + exp = (exp_msb << 10) | exp_low; + if (exp_msb) { + if (exp_low == 0x7f) { + exp = 0x7ff; + } + } else { + if (exp_low != 0x00) { + exp |= 0x380; + } + } + + return (((uint64_t)sign << 63) | ((uint64_t)exp << 52) | + ((uint64_t)frac << 29)); +} + +static inline uint64_t float32_to_s(float32 fa) +{ + CPU_FloatU a; + a.f = fa; + return float32_to_s_int(a.l); +} +static inline uint32_t s_to_float32_int(uint64_t a) +{ + return ((a >> 32) & 0xc0000000) | ((a >> 29) & 0x3fffffff); +} + +static inline float32 s_to_float32(uint64_t a) +{ + CPU_FloatU r; + r.l = s_to_float32_int(a); + return r.f; +} + +uint32_t helper_s_to_memory(uint64_t a) +{ + return s_to_float32(a); +} + +uint64_t helper_memory_to_s(uint32_t a) +{ + return float32_to_s(a); +} + +uint64_t helper_fcvtls(CPUSW64State *env, uint64_t a) +{ + float32 fr = int64_to_float32(a, &FP_STATUS); + env->error_code = soft_to_errcode_exc(env); + return float32_to_s(fr); +} + +uint64_t helper_fcvtld(CPUSW64State *env, uint64_t a) +{ + float64 fr = int64_to_float64(a, &FP_STATUS); + env->error_code = soft_to_errcode_exc(env); + return (uint64_t)fr; +} + +static uint64_t do_fcvtdl(CPUSW64State *env, uint64_t a, uint64_t roundmode) +{ + uint64_t frac, ret = 0; + uint32_t exp, sign, exc = 0; + int shift; + + sign = (a >> 63); + exp = (uint32_t)(a >> 52) & 0x7ff; + frac = a & 0xfffffffffffffull; + + if (exp == 0) { + if (unlikely(frac != 0) && !env->fp_status.flush_inputs_to_zero) { + goto do_underflow; + } + } else if (exp == 0x7ff) { + exc = float_flag_invalid; + } else { + /* Restore implicit bit. */ + frac |= 0x10000000000000ull; + + shift = exp - 1023 - 52; + if (shift >= 0) { + /* In this case the number is so large that we must shift + the fraction left. There is no rounding to do. */ + if (shift < 64) { + ret = frac << shift; + } + /* Check for overflow. Note the special case of -0x1p63. */ + if (shift >= 11 && a != 0xC3E0000000000000ull) { + exc = float_flag_inexact; + } + } else { + uint64_t round; + + /* In this case the number is smaller than the fraction as + represented by the 52 bit number. Here we must think + about rounding the result. Handle this by shifting the + fractional part of the number into the high bits of ROUND. + This will let us efficiently handle round-to-nearest. */ + shift = -shift; + if (shift < 63) { + ret = frac >> shift; + round = frac << (64 - shift); + } else { + /* The exponent is so small we shift out everything. + Leave a sticky bit for proper rounding below. */ + do_underflow: + round = 1; + } + + if (round) { + exc = float_flag_inexact; + switch (roundmode) { + case float_round_nearest_even: + if (round == (1ull << 63)) { + /* Fraction is exactly 0.5; round to even. */ + ret += (ret & 1); + } else if (round > (1ull << 63)) { + ret += 1; + } + break; + case float_round_to_zero: + break; + case float_round_up: + ret += 1 - sign; + break; + case float_round_down: + ret += sign; + break; + } + } + } + if (sign) { + ret = -ret; + } + } + env->error_code = exc; + + return ret; +} + +/* TODO: */ +uint64_t helper_fris(CPUSW64State *env, uint64_t a, uint64_t roundmode) +{ + uint64_t ir; + float32 fr; + + if (roundmode == 5) + roundmode = env->fpcr_round_mode; + ir = do_fcvtdl(env, a, roundmode); + fr = int64_to_float32(ir, &FP_STATUS); + return float32_to_s(fr); +} + +/* TODO: */ +uint64_t helper_frid(CPUSW64State *env, uint64_t a, uint64_t roundmode) +{ + if (roundmode == 5) + roundmode = env->fpcr_round_mode; + return int64_to_float64(do_fcvtdl(env, a, roundmode), &FP_STATUS); +} + +uint64_t helper_fcvtdl(CPUSW64State *env, uint64_t a, uint64_t roundmode) +{ + return do_fcvtdl(env, a, roundmode); +} + +uint64_t helper_fcvtdl_dyn(CPUSW64State *env, uint64_t a) +{ + uint64_t roundmode = (uint64_t)(env->fpcr_round_mode); + return do_fcvtdl(env, a, roundmode); +} + +uint64_t helper_fcvtsd(CPUSW64State *env, uint64_t a) +{ + float32 fa; + float64 fr; + + fa = s_to_float32(a); + fr = float32_to_float64(fa, &FP_STATUS); + /* env->error_code = soft_to_fpcr_exc(env); */ + + return fr; +} + +uint64_t helper_fcvtds(CPUSW64State *env, uint64_t a) +{ + float32 fa; + + fa = float64_to_float32((float64)a, &FP_STATUS); + /* env->error_code = soft_to_fpcr_exc(env); */ + + return float32_to_s(fa); +} + +uint64_t helper_fcvtwl(CPUSW64State *env, uint64_t a) +{ + int32_t ret; + ret = (a >> 29) & 0x3fffffff; + ret |= ((a >> 62) & 0x3) << 30; + return (uint64_t)(int64_t)ret; //int32_t to int64_t as Sign-Extend +} + +uint64_t helper_fcvtlw(CPUSW64State *env, uint64_t a) +{ + uint64_t ret; + ret = (a & 0x3fffffff) << 29; + ret |= ((a >> 30) & 0x3) << 62; + return ret; +} + +uint64_t helper_fadds(CPUSW64State *env, uint64_t a, uint64_t b) +{ + float32 fa, fb, fr; + + fa = s_to_float32(a); + fb = s_to_float32(b); +#if 1 + fr = float32_add(fa, fb, &FP_STATUS); + + env->error_code = soft_to_errcode_exc(env); +#else + *(float*)&fr = *(float*)&fb + *(float*)&fa; +#endif + return float32_to_s(fr); +} + +/* Input handing without software completion. Trap for all + non-finite numbers. */ +uint64_t helper_faddd(CPUSW64State *env, uint64_t a, uint64_t b) +{ + float64 fa, fb, fr; + + fa = (float64)a; + fb = (float64)b; +#if 1 + fr = float64_add(fa, fb, &FP_STATUS); + env->error_code = soft_to_errcode_exc(env); +#else + *(double*)&fr = *(double*)&fb + *(double*)&fa; +#endif + return (uint64_t)fr; +} + +uint64_t helper_fsubs(CPUSW64State *env, uint64_t a, uint64_t b) +{ + float32 fa, fb, fr; + + fa = s_to_float32(a); + fb = s_to_float32(b); +#if 1 + fr = float32_sub(fa, fb, &FP_STATUS); + env->error_code = soft_to_errcode_exc(env); +#else + *(float*)&fr = *(float*)&fa - *(float*)&fb; +#endif + return float32_to_s(fr); +} + +uint64_t helper_fsubd(CPUSW64State *env, uint64_t a, uint64_t b) +{ + float64 fa, fb, fr; + + fa = (float64)a; + fb = (float64)b; +#if 1 + fr = float64_sub(fa, fb, &FP_STATUS); + env->error_code = soft_to_errcode_exc(env); +#else + *(double*)&fr = *(double*)&fa - *(double*)&fb; +#endif + return (uint64_t)fr; +} + +uint64_t helper_fmuls(CPUSW64State *env, uint64_t a, uint64_t b) +{ + float32 fa, fb, fr; + + fa = s_to_float32(a); + fb = s_to_float32(b); +#if 1 + fr = float32_mul(fa, fb, &FP_STATUS); + env->error_code = soft_to_errcode_exc(env); +#else + *(float*)&fr = *(float*)&fa * *(float*)&fb; +#endif + return float32_to_s(fr); +} + +uint64_t helper_fmuld(CPUSW64State *env, uint64_t a, uint64_t b) +{ + float64 fa, fb, fr; + + fa = (float64)a; + fb = (float64)b; +#if 1 + fr = float64_mul(fa, fb, &FP_STATUS); + env->error_code = soft_to_errcode_exc(env); +#else + *(double*)&fr = *(double*)&fa * *(double*)&fb; +#endif + return (uint64_t)fr; +} + +uint64_t helper_fdivs(CPUSW64State *env, uint64_t a, uint64_t b) +{ + float32 fa, fb, fr; + + fa = s_to_float32(a); + fb = s_to_float32(b); +#if 1 + fr = float32_div(fa, fb, &FP_STATUS); + env->error_code = soft_to_errcode_exc(env); +#else + *(float*)&fr = *(float*)&fa / *(float*)&fb; +#endif + return float32_to_s(fr); +} + +uint64_t helper_fdivd(CPUSW64State *env, uint64_t a, uint64_t b) +{ + float64 fa, fb, fr; + + fa = (float64)a; + fb = (float64)b; +#if 1 + fr = float64_div(fa, fb, &FP_STATUS); + env->error_code = soft_to_errcode_exc(env); +#else + *(double*)&fr = *(double*)&fa / *(double*)&fb; +#endif + + return (uint64_t)fr; +} + +uint64_t helper_frecs(CPUSW64State *env, uint64_t a) +{ + float32 fa, fb, fr; + + fa = s_to_float32(a); + fb = int64_to_float32(1, &FP_STATUS); +#if 1 + fr = float32_div(fb, fa, &FP_STATUS); + env->error_code = soft_to_errcode_exc(env); +#else + *(float*)&fr = *(float*)&fb / *(float*)&fa; +#endif + return float32_to_s(fr); +} + +uint64_t helper_frecd(CPUSW64State *env, uint64_t a) +{ + float64 fa, fb, fr; + + fa = (float64)a; + fb = int64_to_float64(1, &FP_STATUS); +#if 1 + fr = float64_div(fb, fa, &FP_STATUS); + env->error_code = soft_to_errcode_exc(env); +#else + *(double*)&fr = *(double*)&fb / *(double*)&fa; +#endif + + return (uint64_t)fr; +} + +uint64_t helper_fsqrts(CPUSW64State *env, uint64_t b) +{ + float32 fb, fr; +#if 1 + fb = s_to_float32(b); + fr = float32_sqrt(fb, &FP_STATUS); + env->error_code = soft_to_errcode_exc(env); +#else +#include + *(double*)&fr = sqrt(*(double*)&b); +#endif + + return float32_to_s(fr); +} + +uint64_t helper_fsqrt(CPUSW64State *env, uint64_t b) +{ + float64 fr; + +#if 1 + fr = float64_sqrt(b, &FP_STATUS); + env->error_code = soft_to_errcode_exc(env); +#else +#include + *(double*)&fr = sqrt(*(double*)&b); +#endif + + return (uint64_t)fr; +} + + +uint64_t helper_fmas(CPUSW64State *env, uint64_t a, uint64_t b, uint64_t c) +{ + float32 fa, fb, fc, fr; + fa = s_to_float32(a); + fb = s_to_float32(b); + fc = s_to_float32(c); + + fr = float32_muladd(fa, fb, fc, 0, &FP_STATUS); + + return float32_to_s(fr); +} + +uint64_t helper_fmad(CPUSW64State *env, uint64_t a, uint64_t b, uint64_t c) +{ + float64 fr; + + fr = float64_muladd(a, b, c, 0, &FP_STATUS); + + return fr; +} + + +uint64_t helper_fmss(CPUSW64State *env, uint64_t a, uint64_t b, uint64_t c) +{ + float32 fa, fb, fc, fr; + fa = s_to_float32(a); + fb = s_to_float32(b); + fc = s_to_float32(c); + + fr = float32_muladd(fa, fb, fc, float_muladd_negate_c, &FP_STATUS); + + return float32_to_s(fr); +} + +uint64_t helper_fmsd(CPUSW64State *env, uint64_t a, uint64_t b, uint64_t c) +{ + float64 fr; + + fr = float64_muladd(a, b, c, float_muladd_negate_c, &FP_STATUS); + + return fr; +} + + +uint64_t helper_fnmas(CPUSW64State *env, uint64_t a, uint64_t b, uint64_t c) +{ + float32 fa, fb, fc, fr; + fa = s_to_float32(a); + fb = s_to_float32(b); + fc = s_to_float32(c); + int flag = float_muladd_negate_product; + + fr = float32_muladd(fa, fb, fc, flag, &FP_STATUS); + + return float32_to_s(fr); +} + +uint64_t helper_fnmad(CPUSW64State *env, uint64_t a, uint64_t b, uint64_t c) +{ + float64 fr; + int flag = float_muladd_negate_product; + + fr = float64_muladd(a, b, c, flag, &FP_STATUS); + + return fr; +} + +uint64_t helper_fnmss(CPUSW64State *env, uint64_t a, uint64_t b, uint64_t c) +{ + float32 fa, fb, fc, fr; + fa = s_to_float32(a); + fb = s_to_float32(b); + fc = s_to_float32(c); + int flag = float_muladd_negate_product | float_muladd_negate_c; + + fr = float32_muladd(fa, fb, fc, flag, &FP_STATUS); + + return float32_to_s(fr); +} + +uint64_t helper_fnmsd(CPUSW64State *env, uint64_t a, uint64_t b, uint64_t c) +{ + float64 fr; + int flag = float_muladd_negate_product | float_muladd_negate_c; + + fr = float64_muladd(a, b, c, flag, &FP_STATUS); + + return fr; +} +uint64_t helper_load_fpcr(CPUSW64State *env) +{ + return cpu_sw64_load_fpcr(env); +} + +static void update_fpcr_status_mask(CPUSW64State *env) +{ + uint64_t t = 0; + + /* Don't mask the inv excp: + * EXC_CTL1 = 1 + * EXC_CTL1 = 0, input denormal, DNZ=0 + * EXC_CTL1 = 0, no input denormal or DNZ=1, INVD = 0 + */ + if ((env->fpcr & FPCR_MASK(EXC_CTL) & 0x2)) { + if (env->fpcr & FPCR_MASK(EXC_CTL) & 0x1) { + t |= (EXC_M_INE | EXC_M_UNF | EXC_M_IOV); + } else { + t |= EXC_M_INE; + } + } else { + /* INV and DNO mask */ + if (env->fpcr & FPCR_MASK(DNZ)) t |= EXC_M_DNO; + if (env->fpcr & FPCR_MASK(INVD)) t |= EXC_M_INV; + if (env->fpcr & FPCR_MASK(OVFD)) t |= EXC_M_OVF; + if (env->fpcr & FPCR_MASK(UNFD)) { + t |= EXC_M_UNF; + } + if (env->fpcr & FPCR_MASK(DZED)) t |= EXC_M_DZE; + if (env->fpcr & FPCR_MASK(INED)) t |= EXC_M_INE; + } + + env->fpcr_exc_enable = t; +} + +void helper_store_fpcr(CPUSW64State *env, uint64_t val) +{ + uint64_t fpcr = val; + uint8_t ret; + + switch ((fpcr & FPCR_MASK(DYN)) >> FPCR_DYN_S) { + case 0x0: + ret = float_round_to_zero; + break; + case 0x1: + ret = float_round_down; + break; + case 0x2: + ret = float_round_nearest_even; + break; + case 0x3: + ret = float_round_up; + break; + default: + ret = float_round_nearest_even; + break; + } + + env->fpcr_round_mode = ret; + + env->fp_status.float_rounding_mode = ret; + + env->fpcr_flush_to_zero = + (fpcr & FPCR_MASK(UNFD)) && (fpcr & FPCR_MASK(UNDZ)); + env->fp_status.flush_to_zero = env->fpcr_flush_to_zero; + + /* FIXME: Now the DNZ flag does not work int C3A. */ + //set_flush_inputs_to_zero((val & FPCR_MASK(DNZ)) != 0? 1 : 0, &FP_STATUS); + + val &= ~0x3UL; + val |= env->fpcr & 0x3UL; + env->fpcr = val; + update_fpcr_status_mask(env); +} + +void helper_setfpcrx(CPUSW64State *env, uint64_t val) +{ + if (env->fpcr & FPCR_MASK(EXC_CTL_WEN)) { + env->fpcr &= ~3UL; + env->fpcr |= val & 0x3; + update_fpcr_status_mask(env); + } +} +#ifndef CONFIG_USER_ONLY +/* +static uint64_t soft_to_fpcr_exc(uint64_t exc) +{ + uint64_t ret = 0; + + if (unlikely(exc)) { + ret |= CONVERT_BIT(exc, float_flag_invalid, FPCR_GET(INV0)); + ret |= CONVERT_BIT(exc, float_flag_divbyzero, FPCR_GET(DZE0)); + ret |= CONVERT_BIT(exc, float_flag_overflow, FPCR_GET(OVF0)); + ret |= CONVERT_BIT(exc, float_flag_underflow, FPCR_GET(UNF0)); + ret |= CONVERT_BIT(exc, float_flag_inexact, FPCR_GET(INE0)); + } + + return ret; +} +*/ +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); + // ret |= CONVERT_BIT(exc, float_flag_input_denormal, EXC_M_DNO); + } + + 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) { + /* arith_excp(env, GETPC(), EXC_M_INV, 0); */ + } + } else if (exp == 0x7ff) { + /* Infinity or NaN. */ + /* arith_excp(env, GETPC(), EXC_M_INV, 0); */ + 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) { + /* arith_excp(env, GETPC(), EXC_M_INV | EXC_M_SWC, 0); */ + } +} + +static inline float64 t_to_float64(uint64_t a) +{ + /* Memory format is the same as float64 */ + CPU_DoubleU r; + r.ll = a; + return r.d; +} + +uint64_t helper_fcmpun(CPUSW64State *env, uint64_t a, uint64_t b) +{ + float64 fa, fb; + uint64_t ret = 0; + + fa = t_to_float64(a); + fb = t_to_float64(b); + + if (float64_unordered_quiet(fa, fb, &FP_STATUS)) { + ret = 0x4000000000000000ULL; + } + env->error_code = soft_to_errcode_exc(env); + + return ret; +} + +uint64_t helper_fcmpeq(CPUSW64State *env, uint64_t a, uint64_t b) +{ + float64 fa, fb; + uint64_t ret = 0; + + fa = t_to_float64(a); + fb = t_to_float64(b); + + if (float64_eq_quiet(fa, fb, &FP_STATUS)) { + ret = 0x4000000000000000ULL; + } + env->error_code = soft_to_errcode_exc(env); + + return ret; +} + +uint64_t helper_fcmple(CPUSW64State *env, uint64_t a, uint64_t b) +{ + float64 fa, fb; + uint64_t ret = 0; + + fa = t_to_float64(a); + fb = t_to_float64(b); + + if (float64_le_quiet(fa, fb, &FP_STATUS)) { + ret = 0x4000000000000000ULL; + } + env->error_code = soft_to_errcode_exc(env); + + return ret; +} + +uint64_t helper_fcmplt(CPUSW64State *env, uint64_t a, uint64_t b) +{ + float64 fa, fb; + uint64_t ret = 0; + + fa = t_to_float64(a); + fb = t_to_float64(b); + + if (float64_lt_quiet(fa, fb, &FP_STATUS)) { + ret = 0x4000000000000000ULL; + } + env->error_code = soft_to_errcode_exc(env); + + return ret; +} + +uint64_t helper_fcmpge(CPUSW64State *env, uint64_t a, uint64_t b) +{ + float64 fa, fb; + uint64_t ret = 0; + + fa = t_to_float64(a); + fb = t_to_float64(b); + + if (float64_le_quiet(fb, fa, &FP_STATUS)) { + ret = 0x4000000000000000ULL; + } + env->error_code = soft_to_errcode_exc(env); + + return ret; +} + +uint64_t helper_fcmpgt(CPUSW64State *env, uint64_t a, uint64_t b) +{ + float64 fa, fb; + uint64_t ret = 0; + + fa = t_to_float64(a); + fb = t_to_float64(b); + + if (float64_lt_quiet(fb, fa, &FP_STATUS)) { + ret = 0x4000000000000000ULL; + } + env->error_code = soft_to_errcode_exc(env); + + return ret; +} + +uint64_t helper_fcmpge_s(CPUSW64State *env, uint64_t a, uint64_t b) +{ + float64 fa, fb; + uint64_t ret = 0; + + /* Make sure va and vb is s float. */ + fa = float32_to_float64(s_to_float32(a), &FP_STATUS); + fb = float32_to_float64(s_to_float32(b), &FP_STATUS); + + if (float64_le_quiet(fb, fa, &FP_STATUS)) { + ret = 0x4000000000000000ULL; + } + env->error_code = soft_to_errcode_exc(env); + + return ret; +} + +uint64_t helper_fcmple_s(CPUSW64State *env, uint64_t a, uint64_t b) +{ + float64 fa, fb; + uint64_t ret = 0; + + /* Make sure va and vb is s float. */ + fa = float32_to_float64(s_to_float32(a), &FP_STATUS); + fb = float32_to_float64(s_to_float32(b), &FP_STATUS); + + if (float64_le_quiet(fa, fb, &FP_STATUS)) { + ret = 0x4000000000000000ULL; + } + env->error_code = soft_to_errcode_exc(env); + + return ret; +} + +void helper_vfcvtsh(CPUSW64State *env, uint64_t ra, uint64_t rb, uint64_t vc, + uint64_t rd) +{ + uint64_t temp = 0; + int i; + for (i = 0; i < 4; i++) { + temp |= (uint64_t)float32_to_float16(s_to_float32(env->fr[ra + i * 32]), + 1, &FP_STATUS) + << (i * 16); + } + for (i = 0; i < 4; i++) { + if (i == (vc & 0x3)) { + env->fr[rd + i * 32] = temp; + } else { + env->fr[rd + i * 32] = env->fr[rb + i * 32]; + } + } +} + +void helper_vfcvths(CPUSW64State *env, uint64_t ra, uint64_t rb, uint64_t vc, + uint64_t rd) +{ + uint64_t temp; + int i; + + temp = env->fr[ra + 32 * (vc & 0x3)]; + for (i = 0; i < 4; i++) { + env->fr[rd + i * 32] = float32_to_s( + float16_to_float32((temp >> (i * 16)) & 0xffffUL, 1, &FP_STATUS)); + } +} diff --git a/target/sw64/helper.c b/target/sw64/helper.c new file mode 100644 index 0000000000000000000000000000000000000000..be263542ec3bd60e73179224f3ed4350519cb8cb --- /dev/null +++ b/target/sw64/helper.c @@ -0,0 +1,365 @@ +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ + +#include "qemu/osdep.h" +#include "qemu/timer.h" + +#include "cpu.h" +#include "exec/exec-all.h" +#include "fpu/softfloat.h" +#include "exec/helper-proto.h" +#include "hw/core/cpu.h" +#include "exec/memattrs.h" + +#if defined(CONFIG_USER_ONLY) +bool sw64_cpu_tlb_fill(CPUState *cs, vaddr address, int size, + MMUAccessType access_type, int mmu_idx, + bool probe, uintptr_t retaddr) +{ + SW64CPU *cpu = SW64_CPU(cs); + + cs->exception_index = EXCP_MMFAULT; + cpu->env.trap_arg0 = address; + cpu_loop_exit_restore(cs, retaddr); +} +#else +static target_ulong ldq_phys_clear(CPUState *cs, target_ulong phys) +{ + return ldq_phys(cs->as, phys & ~(3UL)); +} + +static int get_sw64_physical_address(CPUSW64State *env, target_ulong addr, + int prot_need, int mmu_idx, target_ulong *pphys, + int *pprot) +{ + CPUState *cs = CPU(sw64_env_get_cpu(env)); + target_ulong phys = 0; + int prot = 0, level_bits = 0; + int ret = MM_K_ACV; + target_ulong L1pte, L2pte, L3pte, L4pte; + target_ulong pt, index, pte_pfn_s; + + if ((((addr >> 28) & 0xffffffff8) == 0xffffffff8) && test_feature(env, SW64_FEATURE_CORE3)) { + 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)) { + level_bits = 10; + pte_pfn_s = 28; + pt = env->csr[C3_PTBR]; + } else if (test_feature(env, SW64_FEATURE_CORE4)) { + level_bits = 10; + pte_pfn_s = 24; + pt = env->csr[C4_PTBR1]; + } + index = (addr >> (TARGET_PAGE_BITS + 3 * level_bits)) & ((1 << level_bits)-1); + L1pte = ldq_phys_clear(cs, pt + index * 8); + if ((L1pte & PTE_VALID) == 0) { + ret = MM_K_TNV; + goto exit; + } + if (((L1pte >> 1) & 1) && prot_need == 0) { + ret = MM_K_FOR; + goto exit; + } + if (((L1pte >> 2) & 1) && prot_need == 1) { + ret = MM_K_FOW; + goto exit; + } + pt = L1pte >> pte_pfn_s << TARGET_PAGE_BITS; + + index = (addr >> (TARGET_PAGE_BITS + 2 * level_bits)) & ((1 << level_bits)-1); + L2pte = ldq_phys_clear(cs, pt + index * 8); + + if ((L2pte & PTE_VALID) == 0) { + ret = MM_K_TNV; + goto exit; + } + if (((L2pte >> 1) & 1) && prot_need == 0) { + ret = MM_K_FOR; + goto exit; + } + if (((L2pte >> 2) & 1) && prot_need == 1) { + ret = MM_K_FOW; + goto exit; + } + + pt = L2pte >> pte_pfn_s << TARGET_PAGE_BITS; + + index = (addr >> (TARGET_PAGE_BITS + 1 * level_bits)) & ((1 << level_bits)-1); + L3pte = ldq_phys_clear(cs, pt + index * 8); + + if ((L3pte & PTE_VALID) == 0) { + ret = MM_K_TNV; + goto exit; + } + if (((L3pte >> 1) & 1) && prot_need == 0) { + ret = MM_K_FOR; + goto exit; + } + if (((L3pte >> 2) & 1) && prot_need == 1) { + ret = MM_K_FOW; + goto exit; + } + + pt = L3pte >> pte_pfn_s << TARGET_PAGE_BITS; + + index = (addr >> TARGET_PAGE_BITS) & ((1 << level_bits)-1); + L4pte = ldq_phys_clear(cs, pt + index * 8); + if ((L4pte & PTE_VALID) == 0) { + ret = MM_K_TNV; + goto exit; + } +#if PAGE_READ != 1 || PAGE_WRITE != 2 || PAGE_EXEC != 4 +#error page bits out of date +#endif + + /* Check access violations. */ + if ((L4pte & PTE_FOR) == 0) { + prot |= PAGE_READ | PAGE_EXEC; + } + if ((L4pte & PTE_FOW) == 0) { + prot |= PAGE_WRITE; + } + + /* Check fault-on-operation violations. */ + prot &= ~(L4pte >> 1); + + phys = (L4pte >> pte_pfn_s << TARGET_PAGE_BITS); + + if (unlikely((prot & prot_need) == 0)) { + ret = (prot_need & PAGE_EXEC + ? MM_K_FOE + : prot_need & PAGE_WRITE + ? MM_K_FOW + : prot_need & PAGE_READ ? MM_K_FOR : -1); + goto exit; + } + + ret = -1; +exit: + *pphys = phys; + *pprot = prot; + return ret; +} + +bool sw64_cpu_tlb_fill(CPUState *cs, vaddr address, int size, + MMUAccessType access_type, int mmu_idx, + bool probe, uintptr_t retaddr) +{ + SW64CPU *cpu = SW64_CPU(cs); + CPUSW64State *env = &cpu->env; + target_ulong phys; + int prot, fail, DVA; + + 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); + if (unlikely(fail >= 0)) { + if (probe) { + return false; + } + cs->exception_index = EXCP_MMFAULT; + if (access_type == 2) { + env->csr[DS_STAT] = fail; + env->csr[DVA] = address & ~(3UL); + } else { + env->csr[DS_STAT] = fail | (((unsigned long)access_type + 1) << 3); + env->csr[DVA] = address; + } + env->error_code = access_type; + cpu_loop_exit_restore(cs, retaddr); + } +done: + tlb_set_page(cs, address & TARGET_PAGE_MASK, phys & TARGET_PAGE_MASK, prot, + mmu_idx, TARGET_PAGE_SIZE); + return true; +} + +hwaddr sw64_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) +{ + SW64CPU *cpu = SW64_CPU(cs); + CPUSW64State *env = &cpu->env; + target_ulong phys; + int prot, fail; + int mmu_index = cpu_mmu_index(env, 0); + if (mmu_index == MMU_PHYS_IDX) { + phys = addr; + prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; + fail = -1; + if ((addr >> 52) & 1) goto do_pgmiss; + goto done; + } +do_pgmiss: + fail = get_sw64_physical_address(&cpu->env, addr, 1, mmu_index, &phys, &prot); +done: + return (fail >= 0 ? -1 : phys); +} +#endif + +static void update_fpcr_status_mask(CPUSW64State* env) { + uint64_t t = 0; + + /* Don't mask the inv excp: + * EXC_CTL1 = 1 + * EXC_CTL1 = 0, input denormal, DNZ=0 + * EXC_CTL1 = 0, no input denormal or DNZ=1, INVD = 0 + */ + if ((env->fpcr & FPCR_MASK(EXC_CTL) & 0x2)) { + if (env->fpcr & FPCR_MASK(EXC_CTL) & 0x1) { + t |= (EXC_M_INE | EXC_M_UNF | EXC_M_IOV); + } else { + t |= EXC_M_INE; + } + } else { + /* INV and DNO mask */ + if (env->fpcr & FPCR_MASK(DNZ)) t |= EXC_M_DNO; + if (env->fpcr & FPCR_MASK(INVD)) t |= EXC_M_INV; + if (env->fpcr & FPCR_MASK(OVFD)) t |= EXC_M_OVF; + if (env->fpcr & FPCR_MASK(UNFD)) { + t |= EXC_M_UNF; + } + if (env->fpcr & FPCR_MASK(DZED)) t |= EXC_M_DZE; + if (env->fpcr & FPCR_MASK(INED)) t |= EXC_M_INE; + } + + env->fpcr_exc_enable = t; +} + +void cpu_sw64_store_fpcr(CPUSW64State* env, uint64_t val) { + uint64_t fpcr = val; + uint8_t ret; + + switch ((fpcr & FPCR_MASK(DYN)) >> FPCR_DYN_S) { + case 0x0: + ret = float_round_to_zero; + break; + case 0x1: + ret = float_round_down; + break; + case 0x2: + ret = float_round_nearest_even; + break; + case 0x3: + ret = float_round_up; + break; + default: + ret = float_round_nearest_even; + break; + } + + env->fpcr_round_mode = ret; + env->fp_status.float_rounding_mode = ret; + + env->fpcr_flush_to_zero = + (fpcr & FPCR_MASK(UNFD)) && (fpcr & FPCR_MASK(UNDZ)); + env->fp_status.flush_to_zero = env->fpcr_flush_to_zero; + + /* FIXME: Now the DNZ flag does not work int C3A. */ + //set_flush_inputs_to_zero((val & FPCR_MASK(DNZ)) != 0? 1 : 0, &FP_STATUS); + + val &= ~0x3UL; + val |= env->fpcr & 0x3UL; + env->fpcr = val; + update_fpcr_status_mask(env); +} + +uint64_t helper_read_csr(CPUSW64State *env, uint64_t index) +{ + return env->csr[index]; +} + +uint64_t helper_rtc(void) +{ +#ifndef CONFIG_USER_ONLY + return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); +#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); + 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_PTBR0) + || (index == C4_PTBR1)) { + tlb_flush(cs); + } +//core3 + if (index == C3_INT_CLR ) { + env->csr[C3_INT_STAT] &= ~va; + } +//core4 + if (index == C4_INT_CLR ) { + env->csr[C4_INT_STAT] &= ~va; + } + +#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..20da7bcd477722518d37449a7588d579ca0c5531 --- /dev/null +++ b/target/sw64/helper.h @@ -0,0 +1,125 @@ + +DEF_HELPER_FLAGS_2(zap, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(zapnot, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(cmpgeb, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_1(s_to_memory, TCG_CALL_NO_RWG_SE, i32, i64) +DEF_HELPER_FLAGS_1(memory_to_s, TCG_CALL_NO_RWG_SE, i64, i32) +DEF_HELPER_FLAGS_2(fcvtls, TCG_CALL_NO_RWG, i64, env, i64) +DEF_HELPER_FLAGS_2(fcvtld, TCG_CALL_NO_RWG, i64, env, i64) +DEF_HELPER_FLAGS_3(fcvtdl, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_2(fcvtdl_dyn, TCG_CALL_NO_RWG, i64, env, i64) +DEF_HELPER_FLAGS_3(fris, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(frid, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_2(fcvtsd, TCG_CALL_NO_RWG, i64, env, i64) +DEF_HELPER_FLAGS_2(fcvtds, TCG_CALL_NO_RWG, i64, env, i64) +DEF_HELPER_FLAGS_2(fcvtwl, TCG_CALL_NO_RWG, i64, env, i64) +DEF_HELPER_FLAGS_2(fcvtlw, TCG_CALL_NO_RWG, i64, env, i64) +DEF_HELPER_FLAGS_5(vfcvtsh, 0, void, env, i64, i64, i64, i64) +DEF_HELPER_FLAGS_5(vfcvths, 0, void, env, i64, i64, i64, i64) +DEF_HELPER_FLAGS_3(fadds, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(faddd, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fsubs, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fsubd, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fmuls, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fmuld, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fdivs, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fdivd, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_2(frecs, TCG_CALL_NO_RWG, i64, env, i64) +DEF_HELPER_FLAGS_2(frecd, TCG_CALL_NO_RWG, i64, env, i64) +DEF_HELPER_FLAGS_2(fsqrts, TCG_CALL_NO_RWG, i64, env, i64) +DEF_HELPER_FLAGS_2(fsqrt, TCG_CALL_NO_RWG, i64, env, i64) +DEF_HELPER_FLAGS_4(fmas, TCG_CALL_NO_RWG, i64, env, i64, i64, i64) +DEF_HELPER_FLAGS_4(fmad, TCG_CALL_NO_RWG, i64, env, i64, i64, i64) +DEF_HELPER_FLAGS_4(fmss, TCG_CALL_NO_RWG, i64, env, i64, i64, i64) +DEF_HELPER_FLAGS_4(fmsd, TCG_CALL_NO_RWG, i64, env, i64, i64, i64) +DEF_HELPER_FLAGS_4(fnmas, TCG_CALL_NO_RWG, i64, env, i64, i64, i64) +DEF_HELPER_FLAGS_4(fnmad, TCG_CALL_NO_RWG, i64, env, i64, i64, i64) +DEF_HELPER_FLAGS_4(fnmss, TCG_CALL_NO_RWG, i64, env, i64, i64, i64) +DEF_HELPER_FLAGS_4(fnmsd, TCG_CALL_NO_RWG, i64, env, i64, i64, i64) +DEF_HELPER_FLAGS_0(rtc, TCG_CALL_NO_RWG, i64) +DEF_HELPER_FLAGS_1(load_fpcr, 0, i64, env) +DEF_HELPER_FLAGS_2(store_fpcr, 0, void, env, i64) +DEF_HELPER_FLAGS_2(setfpcrx, 0, void, env, i64) +DEF_HELPER_FLAGS_2(ieee_input, 0, void, env, i64) +DEF_HELPER_FLAGS_2(ieee_input_s, 0, void, env, i64) +DEF_HELPER_FLAGS_2(read_csr, TCG_CALL_NO_RWG, i64, env, i64) +DEF_HELPER_FLAGS_3(write_csr, 0, void, env, i64, i64) +DEF_HELPER_FLAGS_2(cpustate_update, 0, void, env, i64) +DEF_HELPER_FLAGS_3(trace_mem, 0, void, env, i64, i64) +DEF_HELPER_FLAGS_3(fcmpun, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fcmpeq, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fcmple, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fcmplt, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fcmpge, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fcmpgt, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fcmpge_s, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fcmple_s, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_4(srlow, 0, void, env, i64, i64, i64) +DEF_HELPER_FLAGS_4(sllow, 0, void, env, i64, i64, i64) +DEF_HELPER_FLAGS_4(vlogzz, 0, void, env, i64, i64, i64) +DEF_HELPER_FLAGS_4(vconw, 0, void, env, i64, i64, i64) +DEF_HELPER_FLAGS_4(vcond, 0, void, env, i64, i64, i64) +DEF_HELPER_FLAGS_4(vshfw, 0, void, env, i64, i64, i64) +DEF_HELPER_FLAGS_2(ctlzow, 0, i64, env, i64) +DEF_HELPER_FLAGS_4(vucaddw, 0, void, env, i64, i64, i64) +DEF_HELPER_FLAGS_4(vucaddwi, 0, void, env, i64, i64, i64) +DEF_HELPER_FLAGS_4(vucsubw, 0, void, env, i64, i64, i64) +DEF_HELPER_FLAGS_4(vucsubwi, 0, void, env, i64, i64, i64) +DEF_HELPER_FLAGS_4(vucaddh, 0, void, env, i64, i64, i64) +DEF_HELPER_FLAGS_4(vucaddhi, 0, void, env, i64, i64, i64) +DEF_HELPER_FLAGS_4(vucsubh, 0, void, env, i64, i64, i64) +DEF_HELPER_FLAGS_4(vucsubhi, 0, void, env, i64, i64, i64) +DEF_HELPER_FLAGS_4(vucaddb, 0, void, env, i64, i64, i64) +DEF_HELPER_FLAGS_4(vucaddbi, 0, void, env, i64, i64, i64) +DEF_HELPER_FLAGS_4(vucsubb, 0, void, env, i64, i64, i64) +DEF_HELPER_FLAGS_4(vucsubbi, 0, void, env, i64, i64, i64) +DEF_HELPER_FLAGS_3(vstw, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(vsts, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(vstd, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_2(v_print, 0, void, env, i64) +DEF_HELPER_FLAGS_1(tb_flush, 0, void, env) +DEF_HELPER_FLAGS_4(vmaxb, 0, void, env, i64, i64, i64) +DEF_HELPER_FLAGS_4(vminb, 0, void, env, i64, i64, i64) +DEF_HELPER_FLAGS_4(vmaxh, 0, void, env, i64, i64, i64) +DEF_HELPER_FLAGS_4(vminh, 0, void, env, i64, i64, i64) +DEF_HELPER_FLAGS_4(vmaxw, 0, void, env, i64, i64, i64) +DEF_HELPER_FLAGS_4(vminw, 0, void, env, i64, i64, i64) +DEF_HELPER_FLAGS_4(sraow, 0, void, env, i64, i64, i64) +DEF_HELPER_FLAGS_4(vsm4r, 0, void, env, i64, i64, i64) +DEF_HELPER_FLAGS_4(vsm4key, 0, void, env, i64, i64, i64) +DEF_HELPER_FLAGS_4(vsm3msw, 0, void, env, i64, i64, i64) +DEF_HELPER_FLAGS_4(vcmpueqb, 0, void, env, i64, i64, i64) +DEF_HELPER_FLAGS_4(vcmpugtb, 0, void, env, i64, i64, i64) +DEF_HELPER_FLAGS_4(vcmpueqbi, 0, void, env, i64, i64, i64) +DEF_HELPER_FLAGS_4(vcmpugtbi, 0, void, env, i64, i64, i64) +DEF_HELPER_FLAGS_4(vumaxb, 0, void, env, i64, i64, i64) +DEF_HELPER_FLAGS_4(vuminb, 0, void, env, i64, i64, i64) +DEF_HELPER_FLAGS_4(vumaxh, 0, void, env, i64, i64, i64) +DEF_HELPER_FLAGS_4(vuminh, 0, void, env, i64, i64, i64) +DEF_HELPER_FLAGS_4(vumaxw, 0, void, env, i64, i64, i64) +DEF_HELPER_FLAGS_4(vuminw, 0, void, env, i64, i64, i64) +DEF_HELPER_FLAGS_5(vinsb, 0, void, env, i64, i64, i64, i64) +DEF_HELPER_FLAGS_5(vinsh, 0, void, env, i64, i64, i64, i64) +DEF_HELPER_FLAGS_4(vinsectlh, 0, void, env, i64, i64, i64) +DEF_HELPER_FLAGS_4(vinsectlw, 0, void, env, i64, i64, i64) +DEF_HELPER_FLAGS_4(vinsectlb, 0, void, env, i64, i64, i64) +DEF_HELPER_FLAGS_5(vshfq, 0, void, env, i64, i64, i64, i64) +DEF_HELPER_FLAGS_4(vshfqb, 0, void, env, i64, i64, i64) +DEF_HELPER_FLAGS_5(vsm3r, 0, void, env, i64, i64, i64, i64) + +#ifndef CONFIG_USER_ONLY +DEF_HELPER_FLAGS_2(fp_exc_raise, 0, void, env, i32) +DEF_HELPER_FLAGS_2(pri_ldw, 0, i64, env, i64) +DEF_HELPER_FLAGS_3(pri_stw, 0, void, env, i64, i64) +DEF_HELPER_FLAGS_2(pri_ldl, 0, i64, env, i64) +DEF_HELPER_FLAGS_3(pri_stl, 0, void, env, i64, i64) +#endif + +DEF_HELPER_3(excp, noreturn, env, int, int) +//DEF_HELPER_FLAGS_3(faddh, TCG_CALL_NO_RWG, i64, env, i64, i64) +//DEF_HELPER_FLAGS_3(fsubh, TCG_CALL_NO_RWG, i64, env, i64, i64) +//DEF_HELPER_FLAGS_3(fmulh, TCG_CALL_NO_RWG, i64, env, i64, i64) +#ifndef CONFIG_USER_ONLY +#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..d85c64af507c8217b0fd11ca8d1036b886d1712c --- /dev/null +++ b/target/sw64/kvm.c @@ -0,0 +1,215 @@ +/* + * SW64 implementation of KVM hooks + * + * Copyright Christoffer Dall 2009-2010 + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#include "qemu/osdep.h" +#include + +#include + +#include "qemu-common.h" +#include "qemu/timer.h" +#include "qemu/error-report.h" +#include "sysemu/sysemu.h" +#include "sysemu/kvm.h" +#include "kvm_sw64.h" +#include "cpu.h" +#include "exec/memattrs.h" +#include "exec/address-spaces.h" +#include "hw/boards.h" +#include "qemu/log.h" + +#define init_pc 0xffffffff80011000 +const KVMCapabilityInfo kvm_arch_required_capabilities[] = { + KVM_CAP_LAST_INFO +}; +/* 50000 jump to bootlader while 2f00000 jump to bios*/ +int kvm_sw64_vcpu_init(CPUState *cs) +{ + struct kvm_regs *regs; + SW64CPU *cpu = SW64_CPU(cs); + regs = (struct kvm_regs *)cpu->k_regs; + regs->pc = init_pc; + return kvm_vcpu_ioctl(cs, KVM_SET_REGS, ®s); +} + +static void kvm_sw64_host_cpu_class_init(ObjectClass *oc, void *data) +{ +} + +static void kvm_sw64_host_cpu_initfn(Object *obj) +{ +} + + +static const TypeInfo host_sw64_cpu_type_info = { + .name = TYPE_SW64_HOST_CPU, + .parent = TYPE_SW64_CPU, + .instance_init = kvm_sw64_host_cpu_initfn, + .class_init = kvm_sw64_host_cpu_class_init, + .class_size = sizeof(SW64HostCPUClass), +}; + +int kvm_arch_init(MachineState *ms, KVMState *s) +{ + kvm_async_interrupts_allowed = true; + + type_register_static(&host_sw64_cpu_type_info); + + return 0; +} + +/* 50000 jump to bootlader while 2f00000 jump to bios*/ +void kvm_sw64_reset_vcpu(SW64CPU *cpu) +{ + CPUState *cs = CPU(cpu); + struct kvm_regs *regs; + int ret; + + regs = (struct kvm_regs *)cpu->k_regs; + regs->pc = init_pc; + + ret = kvm_vcpu_ioctl(cs, KVM_SET_REGS, ®s); + + if (ret < 0) { + fprintf(stderr, "kvm_sw64_vcpu_init failed: %s\n", strerror(-ret)); + abort(); + } + + ret = kvm_vcpu_ioctl(cs, KVM_SW64_VCPU_INIT, NULL); + + if (ret < 0) { + fprintf(stderr, "kvm_sw64_vcpu_init failed: %s\n", strerror(-ret)); + abort(); + } +} + +unsigned long kvm_arch_vcpu_id(CPUState *cpu) +{ + return cpu->cpu_index; +} + +#include +int kvm_arch_init_vcpu(CPUState *cs) +{ + int ret; + ret = kvm_sw64_vcpu_init(cs); + if (ret) { + return ret; + } + return 0; +} + +int kvm_arch_destroy_vcpu(CPUState *cs) +{ + return 0; +} + +int kvm_arch_get_registers(CPUState *cs) +{ + int ret; + SW64CPU *cpu = SW64_CPU(cs); + ret = kvm_vcpu_ioctl(cs, KVM_GET_REGS, &cpu->k_regs); + if (ret < 0) + return ret; + return kvm_vcpu_ioctl(cs, KVM_SW64_GET_VCB, &cpu->k_vcb); +} + +int kvm_arch_put_registers(CPUState *cs, int level) +{ + int ret; + SW64CPU *cpu = SW64_CPU(cs); + struct vcpucb *vcb; + ret = kvm_vcpu_ioctl(cs, KVM_SET_REGS, &cpu->k_regs); + if (ret < 0) + return ret; + vcb = (struct vcpucb *)cpu->k_vcb; + vcb->whami = kvm_arch_vcpu_id(cs); + fprintf(stderr,"vcpu %ld init.\n", vcb->whami); + return kvm_vcpu_ioctl(cs, KVM_SW64_SET_VCB, &cpu->k_vcb); +} + +int kvm_arch_add_msi_route_post(struct kvm_irq_routing_entry *route, + int vector, PCIDevice *dev) +{ + return -1; +} + +int kvm_arch_fixup_msi_route(struct kvm_irq_routing_entry *route, + uint64_t address, uint32_t data, PCIDevice *dev) +{ + return 0; +} + +void kvm_arch_pre_run(CPUState *cs, struct kvm_run *run) +{ +} + +MemTxAttrs kvm_arch_post_run(CPUState *cs, struct kvm_run *run) +{ + return MEMTXATTRS_UNSPECIFIED; +} + + +int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run) +{ + return -1; +} + +bool kvm_arch_stop_on_emulation_error(CPUState *cs) +{ + return true; +} + +int kvm_arch_process_async_events(CPUState *cs) +{ + return 0; +} + +void kvm_arch_update_guest_debug(CPUState *cs, struct kvm_guest_debug *dbg) +{ +} + +void kvm_arch_init_irq_routing(KVMState *s) +{ + /* We know at this point that we're using the in-kernel + * irqchip, so we can use irqfds, and on x86 we know + * we can use msi via irqfd and GSI routing. + */ + kvm_msi_via_irqfd_allowed = true; + kvm_gsi_routing_allowed = true; +} + +int kvm_arch_irqchip_create(KVMState *s) +{ + return 0; +} + +int kvm_arch_release_virq_post(int virq) +{ + return -1; +} + +int kvm_arch_msi_data_to_gsi(uint32_t data) +{ + return -1; +} + + +void kvm_sw64_register_slave(SW64CPU *cpu) +{ + CPUState *cs = CPU(cpu); + + kvm_vcpu_ioctl(cs, KVM_SW64_USE_SLAVE, NULL); +} + +bool kvm_arch_cpu_check_are_resettable(void) +{ + return true; +} diff --git a/target/sw64/kvm_sw64.h b/target/sw64/kvm_sw64.h new file mode 100644 index 0000000000000000000000000000000000000000..358a33c26318a901d711977b1a2fef4a16cb95f3 --- /dev/null +++ b/target/sw64/kvm_sw64.h @@ -0,0 +1,47 @@ +/* + * QEMU KVM support -- SW64 specific functions. + * + * Copyright (c) 2018 oskern + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#ifndef QEMU_KVM_SW64_H +#define QEMU_KVM_SW64_H + +#include "sysemu/kvm.h" +#include "exec/memory.h" +#include "qemu/error-report.h" + +/** + * kvm_sw64_vcpu_init: + * @cs: CPUState + * + * Initialize (or reinitialize) the VCPU by invoking the + * KVM_SW64_VCPU_INIT ioctl with the CPU type and feature + * bitmask specified in the CPUState. + * + * Returns: 0 if success else < 0 error code + */ +int kvm_sw64_vcpu_init(CPUState *cs); +void kvm_sw64_reset_vcpu(SW64CPU *cpu); +void kvm_sw64_register_slave(SW64CPU *cpu); + +#define TYPE_SW64_HOST_CPU "host-" TYPE_SW64_CPU +#define SW64_HOST_CPU_CLASS(klass) \ + OBJECT_CLASS_CHECK(SW64HostCPUClass, (klass), TYPE_SW64_HOST_CPU) +#define SW64_HOST_CPU_GET_CLASS(obj) \ + OBJECT_GET_CLASS(SW64HostCPUClass, (obj), TYPE_SW64_HOST_CPU) + +typedef struct SW64HostCPUClass { + /*< private >*/ + SW64CPUClass parent_class; + /*< public >*/ + + uint64_t features; + uint32_t target; + const char *dtb_compatible; +} SW64HostCPUClass; +#endif diff --git a/target/sw64/machine.c b/target/sw64/machine.c new file mode 100644 index 0000000000000000000000000000000000000000..df18d3faba0af834b5a62707c9f6158532444189 --- /dev/null +++ b/target/sw64/machine.c @@ -0,0 +1,18 @@ +#include "qemu/osdep.h" +#include "qemu-common.h" +#include "cpu.h" +#include "migration/vmstate.h" +#include "migration/cpu.h" + +VMStateDescription vmstate_sw64_cpu = { + .name = "cpu", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { +#ifdef CONFIG_KVM + VMSTATE_UINTTL_ARRAY(k_regs, SW64CPU, 158), + VMSTATE_UINTTL_ARRAY(k_vcb, SW64CPU, 36), +#endif + VMSTATE_END_OF_LIST() + } +}; diff --git a/target/sw64/meson.build b/target/sw64/meson.build new file mode 100644 index 0000000000000000000000000000000000000000..ee49e4592798f96a943f14c2a9ccb105f22d9ec7 --- /dev/null +++ b/target/sw64/meson.build @@ -0,0 +1,19 @@ +sw64_ss = ss.source_set() +sw64_ss.add(files( + 'cpu.c', + 'exception.c', + 'float_helper.c', + 'helper.c', + 'int_helper.c', + 'profile.c', + 'simd_helper.c', + 'translate.c', +)) + +sw64_ss.add(when: 'CONFIG_KVM', if_true: files('kvm.c')) + +sw64_softmmu_ss = ss.source_set() +sw64_softmmu_ss.add(files('machine.c')) + +target_arch += {'sw64': sw64_ss} +target_softmmu_arch += {'sw64': sw64_softmmu_ss} diff --git a/target/sw64/profile.c b/target/sw64/profile.c new file mode 100644 index 0000000000000000000000000000000000000000..73fe077234c89200cab8414b9ecde23f0457da13 --- /dev/null +++ b/target/sw64/profile.c @@ -0,0 +1,2342 @@ +#include "translate.h" + +const char *insn_opc[535] = { + "sys_call", "call", "ret", "jmp", "br", "bsr", "memb", "imemb", + "wmemb", "rtc", "rcid", "halt", "rd_f", "wr_f", "rtid", + "csrws", "csrwc", "pri_rcsr", "pri_wcsr", "pri_ret", "lldw", "lldl", + "ldw_inc", "ldl_inc", "ldw_dec", "ldl_dec", "ldw_set", "ldl_set", "lstw", + "lstl", "ldw_nc", "ldl_nc", "ldd_nc", "stw_nc", "stl_nc", "std_nc", + "ldwe", "ldse", "ldde", "vlds", "vldd", "vsts", "vstd", + "fimovs", "fimovd", "addw", "subw", "s4addw", "s4subw", "s8addw", + "s8subw", "addl", "subl", "s4addl", "s4subl", "s8addl", "s8subl", + "mulw", "divw", "udivw", "remw", "uremw", "mull", "mulh", + "divl", "udivl", "reml", "ureml", "addpi", "addpis", "cmpeq", + "cmplt", "cmple", "cmpult", "cmpule", "sbt", "cbt", "and", + "bic", "bis", "ornot", "xor", "eqv", "inslb", "inslh", + "inslw", "insll", "inshb", "inshh", "inshw", "inshl", "slll", + "srll", "sral", "roll", "sllw", "srlw", "sraw", "rolw", + "extlb", "extlh", "extlw", "extll", "exthb", "exthh", "exthw", + "exthl", "ctpop", "ctlz", "cttz", "revbh", "revbw", "revbl", + "casw", "casl", "masklb", "masklh", "masklw", "maskll", "maskhb", + "maskhh", "maskhw", "maskhl", "zap", "zapnot", "sextb", "sexth", + "seleq", "selge", "selgt", "selle", "sellt", "selne", "sellbc", + "sellbs", "addwi", "subwi", "s4addwi", "s4subwi", "s8addwi", "s8subwi", + "addli", "subli", "s4addli", "s4subli", "s8addli", "s8subli", "mulwi", + "divwi", "udivwi", "remwi", "uremwi", "mulli", "mulhi", "divli", + "udivli", "remli", "uremli", "addpii", "addpisi", "cmpeqi", "cmplti", + "cmplei", "cmpulti", "cmpulei", "sbti", "cbti", "andi", "bici", + "bisi", "ornoti", "xori", "eqvi", "inslbi", "inslhi", "inslwi", + "inslli", "inshbi", "inshhi", "inshwi", "inshli", "sllli", "srlli", + "srali", "rolli", "sllwi", "srlwi", "srawi", "rolwi", "extlbi", + "extlhi", "extlwi", "extlli", "exthbi", "exthhi", "exthwi", "exthli", + "ctpopi", "ctlzi", "cttzi", "revbhi", "revbwi", "revbli", "caswi", + "casli", "masklbi", "masklhi", "masklwi", "masklli", "maskhbi", "maskhhi", + "maskhwi", "maskhli", "zapi", "zapnoti", "sextbi", "sexthi", "cmpgebi", + "seleqi", "selgei", "selgti", "sellei", "sellti", "selnei", "sellbci", + "sellbsi", "vlogzz", "fadds", "faddd", "fsubs", "fsubd", "fmuls", + "fmuld", "fdivs", "fdivd", "fsqrts", "fsqrtd", "fcmpeq", "fcmple", + "fcmplt", "fcmpun", "fcvtsd", "fcvtds", "fcvtdl_g", "fcvtdl_p", "fcvtdl_z", + "fcvtdl_n", "fcvtdl", "fcvtwl", "fcvtlw", "fcvtls", "fcvtld", "fcpys", + "fcpyse", "fcpysn", "ifmovs", "ifmovd", "rfpcr", "wfpcr", "setfpec0", + "setfpec1", "setfpec2", "setfpec3", "frecs", "frecd", "fris", "fris_g", + "fris_p", "fris_z", "fris_n", "frid", "frid_g", "frid_p", "frid_z", + "frid_n", "fmas", "fmad", "fmss", "fmsd", "fnmas", "fnmad", + "fnmss", "fnmsd", "fseleq", "fselne", "fsellt", "fselle", "fselgt", + "fselge", "vaddw", "vaddwi", "vsubw", "vsubwi", "vcmpgew", "vcmpgewi", + "vcmpeqw", "vcmpeqwi", "vcmplew", "vcmplewi", "vcmpltw", "vcmpltwi", "vcmpulew", + "vcmpulewi", "vcmpultw", "vcmpultwi", "vsllw", "vsllwi", "vsrlw", "vsrlwi", + "vsraw", "vsrawi", "vrolw", "vrolwi", "sllow", "sllowi", "srlow", + "srlowi", "vaddl", "vaddli", "vsubl", "vsubli", "vsllb", "vsllbi", + "vsrlb", "vsrlbi", "vsrab", "vsrabi", "vrolb", "vrolbi", "vsllh", + "vsllhi", "vsrlh", "vsrlhi", "vsrah", "vsrahi", "vrolh", "vrolhi", + "ctpopow", "ctlzow", "vslll", "vsllli", "vsrll", "vsrlli", "vsral", + "vsrali", "vroll", "vrolli", "vmaxb", "vminb", "vucaddw", "vucaddwi", + "vucsubw", "vucsubwi", "vucaddh", "vucaddhi", "vucsubh", "vucsubhi", "vucaddb", + "vucaddbi", "vucsubb", "vucsubbi", "sraow", "sraowi", "vsumw", "vsuml", + "vsm4r", "vbinvw", "vcmpueqb", "vcmpugtb", "vcmpugtbi", "vsm3msw", "vmaxh", + "vminh", "vmaxw", "vminw", "vmaxl", "vminl", "vumaxb", "vuminb", + "vumaxh", "vuminh", "vumaxw", "vuminw", "vumaxl", "vuminl", "vsm4key", + "vadds", "vaddd", "vsubs", "vsubd", "vmuls", "vmuld", "vdivs", + "vdivd", "vsqrts", "vsqrtd", "vfcmpeq", "vfcmple", "vfcmplt", "vfcmpun", + "vcpys", "vcpyse", "vcpysn", "vsums", "vsumd", "vfcvtsd", "vfcvtds", + "vfcvtls", "vfcvtld", "vfcvtdl", "vfcvtdl_g", "vfcvtdl_p", "vfcvtdl_z", "vfcvtdl_n", + "vfris", "vfris_g", "vfris_p", "vfris_z", "vfris_n", "vfrid", "vfrid_g", + "vfrid_p", "vfrid_z", "vfrid_n", "vfrecs", "vfrecd", "vmaxs", "vmins", + "vmaxd", "vmind", "vmas", "vmad", "vmss", "vmsd", "vnmas", + "vnmad", "vnmss", "vnmsd", "vfseleq", "vfsellt", "vfselle", "vseleqw", + "vseleqwi", "vsellbcw", "vsellbcwi", "vselltw", "vselltwi", "vsellew", "vsellewi", + "vinsw", "vinsf", "vextw", "vextf", "vcpyw", "vcpyf", "vconw", + "vshfw", "vcons", "vcond", "vinsb", "vinsh", "vinsectlh", "vinsectlw", + "vinsectll", "vinsectlb", "vshfq", "vshfqb", "vcpyb", "vcpyh", "vsm3r", + "vfcvtsh", "vfcvths", "vldw_u", "vstw_u", "vlds_u", "vsts_u", "vldd_u", + "vstd_u", "vstw_ul", "vstw_uh", "vsts_ul", "vsts_uh", "vstd_ul", "vstd_uh", + "vldd_nc", "vstd_nc", "lbr", "ldbu_a", "ldhu_a", "ldw_a", "ldl_a", + "flds_a", "fldd_a", "stbu_a", "sthu_a", "stw_a", "stl_a", "fsts_a", + "fstd_a", "dpfhr", "dpfhw", "ldbu", "ldhu", "ldw", "ldl", + "ldl_u", "pri_ldl", "pri_ldw", "flds", "fldd", "stb", "sth", + "stw", "stl", "stl_u", "pri_stl", "pri_stw", "fsts", "fstd", + "beq", "bne", "blt", "ble", "bgt", "bge", "blbc", + "blbs", "fbeq", "fbne", "fblt", "fble", "fbgt", "fbge", + "ldih", "ldi", }; + +void insn_profile(DisasContext *ctx, uint32_t insn) +{ + int32_t disp16, disp26 __attribute__((unused)); + uint8_t opc; + uint16_t fn3, fn4, fn6, fn8, fn11; + TCGv count; + int index, offs; + + opc = extract32(insn, 26, 6); + + fn3 = extract32(insn, 10, 3); + fn6 = extract32(insn, 10, 6); + fn4 = extract32(insn, 12, 4); + fn8 = extract32(insn, 5, 8); + fn11 = extract32(insn, 5, 11); + + disp16 = sextract32(insn, 0, 16); + disp26 = sextract32(insn, 0, 26); + + index = 0; + switch (opc) { + case 0x00: + /* SYS_CALL */ + index = SYS_CALL; + break; + case 0x01: + /* CALL */ + index = CALL; + break; + case 0x02: + /* RET */ + index = RET; + break; + case 0x03: + /* JMP */ + index = JMP; + break; + case 0x04: + /* BR */ + index = BR; + break; + case 0x05: + /* BSR */ + index = BSR; + break; + case 0x06: + switch (disp16) { + case 0x0000: + /* MEMB */ + index = MEMB; + break; + case 0x0001: + /* IMEMB */ + index = IMEMB; + break; + case 0x0002: + /* WMEMB */ + index = WMEMB; + break; + case 0x0020: + /* RTC */ + index = RTC; + break; + case 0x0040: + /* RCID */ + index = RCID; + break; + case 0x0080: + /* HALT */ + index = HALT; + break; + case 0x1000: + /* RD_F */ + index = RD_F; + break; + case 0x1020: + /* WR_F */ + index = WR_F; + break; + case 0x1040: + /* RTID */ + index = RTID; + break; + default: + if ((disp16 & 0xFF00) == 0xFC00) { + /* CSRWS */ + index = CSRWS; + break; + } + if ((disp16 & 0xFF00) == 0xFD00) { + /* CSRWC */ + index = CSRWC; + break; + } + if ((disp16 & 0xFF00) == 0xFE00) { + /* PRI_RCSR */ + index = PRI_RCSR; + break; + } + if ((disp16 & 0xFF00) == 0xFF00) { + /* PRI_WCSR */ + index = PRI_WCSR; + break; + } + goto do_invalid; + } + break; + case 0x07: + /* PRI_RET */ + index = PRI_RET; + break; + case 0x08: + switch (fn4) { + case 0x0: + /* LLDW */ + index = LLDW; + break; + case 0x1: + /* LLDL */ + index = LLDL; + break; + case 0x2: + /* LDW_INC */ + index = LDW_INC; + break; + case 0x3: + /* LDL_INC */ + index = LDL_INC; + break; + case 0x4: + /* LDW_DEC */ + index = LDW_DEC; + break; + case 0x5: + /* LDL_DEC */ + index = LDL_DEC; + break; + case 0x6: + /* LDW_SET */ + index = LDW_SET; + break; + case 0x7: + /* LDL_SET */ + index = LDL_SET; + break; + case 0x8: + /* LSTW */ + index = LSTW; + break; + case 0x9: + /* LSTL */ + index = LSTL; + break; + case 0xa: + /* LDW_NC */ + index = LDW_NC; + break; + case 0xb: + /* LDL_NC */ + index = LDL_NC; + break; + case 0xc: + /* LDD_NC */ + index = LDD_NC; + break; + case 0xd: + /* STW_NC */ + index = STW_NC; + break; + case 0xe: + /* STL_NC */ + index = STL_NC; + break; + case 0xf: + /* STD_NC */ + index = STD_NC; + break; + default: + goto do_invalid; + } + break; + case 0x9: + /* LDWE */ + index = LDWE; + break; + case 0x0a: + /* LDSE */ + index = LDSE; + break; + case 0x0b: + /* LDDE */ + index = LDDE; + break; + case 0x0c: + /* VLDS */ + index = VLDS; + break; + case 0x0d: + /* VLDD */ + index = VLDD; + break; + case 0x0e: + /* VSTS */ + index = VSTS; + break; + case 0x0f: + /* VSTD */ + index = VSTD; + break; + case 0x10: + if (fn11 == 0x70) { + /* FIMOVS */ + index = FIMOVS; + } else if (fn11 == 0x78) { + /* FIMOVD */ + index = FIMOVD; + } else { + switch (fn11 & 0xff) { + case 0x00: + /* ADDW */ + index = ADDW; + break; + case 0x01: + /* SUBW */ + index = SUBW; + break; + case 0x02: + /* S4ADDW */ + index = S4ADDW; + break; + case 0x03: + /* S4SUBW */ + index = S4SUBW; + break; + case 0x04: + /* S8ADDW */ + index = S8ADDW; + break; + case 0x05: + /* S8SUBW */ + index = S8SUBW; + break; + + case 0x08: + /* ADDL */ + index = ADDL; + break; + case 0x09: + /* SUBL */ + index = SUBL; + break; + case 0x0a: + /* S4ADDL */ + index = S4ADDL; + break; + case 0x0b: + /* S4SUBL */ + index = S4SUBL; + break; + case 0x0c: + /* S8ADDL */ + index = S8ADDL; + break; + case 0x0d: + /* S8SUBL */ + index = S8SUBL; + break; + case 0x10: + /* MULW */ + index = MULW; + break; + case 0x11: + /* DIVW */ + index = DIVW; + break; + case 0x12: + /* UDIVW */ + index = UDIVW; + break; + case 0x13: + /* REMW */ + index = REMW; + break; + case 0x14: + /* UREMW */ + index = UREMW; + break; + case 0x18: + /* MULL */ + index = MULL; + break; + case 0x19: + /* MULH */ + index = MULH; + break; + case 0x1A: + /* DIVL */ + index = DIVL; + break; + case 0x1B: + /* UDIVL */ + index = UDIVL; + break; + case 0x1C: + /* REML */ + index = REML; + break; + case 0x1D: + /* UREML */ + index = UREML; + break; + case 0x1E: + /* ADDPI */ + index = ADDPI; + break; + case 0x1F: + /* ADDPIS */ + index = ADDPIS; + break; + case 0x28: + /* CMPEQ */ + index = CMPEQ; + break; + case 0x29: + /* CMPLT */ + index = CMPLT; + break; + case 0x2a: + /* CMPLE */ + index = CMPLE; + break; + case 0x2b: + /* CMPULT */ + index = CMPULT; + break; + case 0x2c: + /* CMPULE */ + index = CMPULE; + break; + case 0x2D: + /* SBT */ + index = SBT; + break; + case 0x2E: + /* CBT */ + index = CBT; + break; + case 0x38: + /* AND */ + index = AND; + break; + case 0x39: + /* BIC */ + index = BIC; + break; + case 0x3a: + /* BIS */ + index = BIS; + break; + case 0x3b: + /* ORNOT */ + index = ORNOT; + break; + case 0x3c: + /* XOR */ + index = XOR; + break; + case 0x3d: + /* EQV */ + index = EQV; + break; + case 0x40: + /* INSLB */ + index = INSLB; + break; + case 0x41: + /* INSLH */ + index = INSLH; + break; + case 0x42: + /* INSLW */ + index = INSLW; + break; + case 0x43: + /* INSLL */ + index = INSLL; + break; + case 0x44: + /* INSHB */ + index = INSHB; + break; + case 0x45: + /* INSHH */ + index = INSHH; + break; + case 0x46: + /* INSHW */ + index = INSHW; + break; + case 0x47: + /* INSHL */ + index = INSHL; + break; + case 0x48: + /* SLLL */ + index = SLLL; + break; + case 0x49: + /* SRLL */ + index = SRLL; + break; + case 0x4a: + /* SRAL */ + index = SRAL; + break; + case 0x4B: + /* ROLL */ + index = ROLL; + break; + case 0x4C: + /* SLLW */ + index = SLLW; + break; + case 0x4D: + /* SRLW */ + index = SRLW; + break; + case 0x4E: + /* SRAW */ + index = SRAW; + break; + case 0x4F: + /* ROLW */ + index = ROLW; + break; + case 0x50: + /* EXTLB */ + index = EXTLB; + break; + case 0x51: + /* EXTLH */ + index = EXTLH; + break; + case 0x52: + /* EXTLW */ + index = EXTLW; + break; + case 0x53: + /* EXTLL */ + index = EXTLL; + break; + case 0x54: + /* EXTHB */ + index = EXTHB; + break; + case 0x55: + /* EXTHH */ + index = EXTHH; + break; + case 0x56: + /* EXTHW */ + index = EXTHW; + break; + case 0x57: + /* EXTHL */ + index = EXTHL; + break; + case 0x58: + /* CTPOP */ + index = CTPOP; + break; + case 0x59: + /* CTLZ */ + index = CTLZ; + break; + case 0x5a: + /* CTTZ */ + index = CTTZ; + break; + case 0x5B: + /* REVBH */ + index = REVBH; + break; + case 0x5C: + /* REVBW */ + index = REVBW; + break; + case 0x5D: + /* REVBL */ + index = REVBL; + break; + case 0x5E: + /* CASW */ + index = CASW; + break; + case 0x5F: + /* CASL */ + index = CASL; + break; + case 0x60: + /* MASKLB */ + index = MASKLB; + break; + case 0x61: + /* MASKLH */ + index = MASKLH; + break; + case 0x62: + /* MASKLW */ + index = MASKLW; + break; + case 0x63: + /* MASKLL */ + index = MASKLL; + break; + case 0x64: + /* MASKHB */ + index = MASKHB; + break; + case 0x65: + /* MASKHH */ + index = MASKHH; + break; + case 0x66: + /* MASKHW */ + index = MASKHW; + break; + case 0x67: + /* MASKHL */ + index = MASKHL; + break; + case 0x68: + /* ZAP */ + index = ZAP; + break; + case 0x69: + /* ZAPNOT */ + index = ZAPNOT; + break; + case 0x6a: + /* SEXTB */ + index = SEXTB; + break; + case 0x6b: + /* SEXTH */ + index = SEXTH; + break; + case 0x6c: + /* CMPGEB*/ + break; + default: + break; + } + } + break; + case 0x11: + switch (fn3) { + case 0x0: + /* SELEQ */ + index = SELEQ; + break; + case 0x1: + /* SELGE */ + index = SELGE; + break; + case 0x2: + /* SELGT */ + index = SELGT; + break; + case 0x3: + /* SELLE */ + index = SELLE; + break; + case 0x4: + /* SELLT */ + index = SELLT; + break; + case 0x5: + /* SELNE */ + index = SELNE; + break; + case 0x6: + /* SELLBC */ + index = SELLBC; + break; + case 0x7: + /* SELLBS */ + index = SELLBS; + break; + default: + break; + } + break; + case 0x12: + switch (fn8 & 0xff) { + case 0x00: + /* ADDWI */ + index = ADDWI; + break; + case 0x01: + /* SUBWI */ + index = SUBWI; + break; + case 0x02: + /* S4ADDWI */ + index = S4ADDWI; + break; + case 0x03: + /* S4SUBWI */ + index = S4SUBWI; + break; + case 0x04: + /* S8ADDWI */ + index = S8ADDWI; + break; + case 0x05: + /* S8SUBWI */ + index = S8SUBWI; + break; + + case 0x08: + /* ADDLI */ + index = ADDLI; + break; + case 0x09: + /* SUBLI */ + index = SUBLI; + break; + case 0x0a: + /* S4ADDLI */ + index = S4ADDLI; + break; + case 0x0b: + /* S4SUBLI */ + index = S4SUBLI; + break; + case 0x0c: + /* S8ADDLI */ + index = S8ADDLI; + break; + case 0x0d: + /* S8SUBLI */ + index = S8SUBLI; + break; + case 0x10: + /* MULWI */ + index = MULWI; + break; + case 0x11: + /* DIVWI */ + index = DIVWI; + break; + case 0x12: + /* UDIVWI */ + index = UDIVWI; + break; + case 0x13: + /* REMWI */ + index = REMWI; + break; + case 0x14: + /* UREMWI */ + index = UREMWI; + break; + case 0x18: + /* MULLI */ + index = MULLI; + break; + case 0x19: + /* MULHI */ + index = MULHI; + break; + case 0x1A: + /* DIVLI */ + index = DIVLI; + break; + case 0x1B: + /* UDIVLI */ + index = UDIVLI; + break; + case 0x1C: + /* REMLI */ + index = REMLI; + break; + case 0x1D: + /* UREMLI */ + index = UREMLI; + break; + case 0x1E: + /* ADDPII */ + index = ADDPII; + break; + case 0x1F: + /* ADDPISI */ + index = ADDPISI; + break; + case 0x28: + /* CMPEQI */ + index = CMPEQI; + break; + case 0x29: + /* CMPLTI */ + index = CMPLTI; + break; + case 0x2a: + /* CMPLEI */ + index = CMPLEI; + break; + case 0x2b: + /* CMPULTI */ + index = CMPULTI; + break; + case 0x2c: + /* CMPULEI */ + index = CMPULEI; + break; + case 0x2D: + /* SBTI */ + index = SBTI; + break; + case 0x2E: + /* CBTI */ + index = CBTI; + break; + case 0x38: + /* ANDI */ + index = ANDI; + break; + case 0x39: + /* BICI */ + index = BICI; + break; + case 0x3a: + /* BISI */ + index = BISI; + break; + case 0x3b: + /* ORNOTI */ + index = ORNOTI; + break; + case 0x3c: + /* XORI */ + index = XORI; + break; + case 0x3d: + /* EQVI */ + index = EQVI; + break; + case 0x40: + /* INSLBI */ + index = INSLBI; + break; + case 0x41: + /* INSLHI */ + index = INSLHI; + break; + case 0x42: + /* INSLWI */ + index = INSLWI; + break; + case 0x43: + /* INSLLI */ + index = INSLLI; + break; + case 0x44: + /* INSHBI */ + index = INSHBI; + break; + case 0x45: + /* INSHHI */ + index = INSHHI; + break; + case 0x46: + /* INSHWI */ + index = INSHWI; + break; + case 0x47: + /* INSHLI */ + index = INSHLI; + break; + case 0x48: + /* SLLLI */ + index = SLLLI; + break; + case 0x49: + /* SRLLI */ + index = SRLLI; + break; + case 0x4a: + /* SRALI */ + index = SRALI; + break; + case 0x4B: + /* ROLLI */ + index = ROLLI; + break; + case 0x4C: + /* SLLWI */ + index = SLLWI; + break; + case 0x4D: + /* SRLWI */ + index = SRLWI; + break; + case 0x4E: + /* SRAWI */ + index = SRAWI; + break; + case 0x4F: + /* ROLWI */ + index = ROLWI; + break; + case 0x50: + /* EXTLBI */ + index = EXTLBI; + break; + case 0x51: + /* EXTLHI */ + index = EXTLHI; + break; + case 0x52: + /* EXTLWI */ + index = EXTLWI; + break; + case 0x53: + /* EXTLLI */ + index = EXTLLI; + break; + case 0x54: + /* EXTHBI */ + index = EXTHBI; + break; + case 0x55: + /* EXTHHI */ + index = EXTHHI; + break; + case 0x56: + /* EXTHWI */ + index = EXTHWI; + break; + case 0x57: + /* EXTHLI */ + index = EXTHLI; + break; + case 0x58: + /* CTPOPI */ + index = CTPOPI; + break; + case 0x59: + /* CTLZI */ + index = CTLZI; + break; + case 0x5a: + /* CTTZI */ + index = CTTZI; + break; + case 0x5B: + /* REVBHI */ + index = REVBHI; + break; + case 0x5C: + /* REVBWI */ + index = REVBWI; + break; + case 0x5D: + /* REVBLI */ + index = REVBLI; + break; + case 0x5E: + /* CASWI */ + index = CASWI; + break; + case 0x5F: + /* CASLI */ + index = CASLI; + break; + case 0x60: + /* MASKLBI */ + index = MASKLBI; + break; + case 0x61: + /* MASKLHI */ + index = MASKLHI; + break; + case 0x62: + /* MASKLWI */ + index = MASKLWI; + break; + case 0x63: + /* MASKLLI */ + index = MASKLLI; + break; + case 0x64: + /* MASKHBI */ + index = MASKHBI; + break; + case 0x65: + /* MASKHHI */ + index = MASKHHI; + break; + case 0x66: + /* MASKHWI */ + index = MASKHWI; + break; + case 0x67: + /* MASKHLI */ + index = MASKHLI; + break; + case 0x68: + /* ZAPI */ + index = ZAPI; + break; + case 0x69: + /* ZAPNOTI */ + index = ZAPNOTI; + break; + case 0x6a: + /* SEXTBI */ + index = SEXTBI; + break; + case 0x6b: + /* SEXTHI */ + index = SEXTHI; + break; + case 0x6c: + /* CMPGEBI */ + index = CMPGEBI; + break; + default: + break; + } + break; + case 0x13: + switch (fn3) { + case 0x0: + /* SELEQI */ + index = SELEQI; + break; + case 0x1: + /* SELGEI */ + index = SELGEI; + break; + case 0x2: + /* SELGTI */ + index = SELGTI; + break; + case 0x3: + /* SELLEI */ + index = SELLEI; + break; + case 0x4: + /* SELLTI */ + index = SELLTI; + break; + case 0x5: + /* SELNEI */ + index = SELNEI; + break; + case 0x6: + /* SELLBCI */ + index = SELLBCI; + break; + case 0x7: + /* SELLBSI */ + index = SELLBSI; + break; + default: + break; + } + break; + case 0x14: + case 0x15: + case 0x16: + case 0x17: + /* VLOGZZ */ + index = VLOGZZ; + break; + case 0x18: + switch (fn8) { + case 0x00: + /* FADDS */ + index = FADDS; + break; + case 0x01: + /* FADDD */ + index = FADDD; + break; + case 0x02: + /* FSUBS */ + index = FSUBS; + break; + case 0x03: + /* FSUBD */ + index = FSUBD; + break; + case 0x4: + /* FMULS */ + index = FMULS; + break; + case 0x05: + /* FMULD */ + index = FMULD; + break; + case 0x06: + /* FDIVS */ + index = FDIVS; + break; + case 0x07: + /* FDIVD */ + index = FDIVD; + break; + case 0x08: + /* FSQRTS */ + index = FSQRTS; + break; + case 0x09: + /* FSQRTD */ + index = FSQRTD; + break; + case 0x10: + /* FCMPEQ */ + index = FCMPEQ; + break; + case 0x11: + /* FCMPLE */ + index = FCMPLE; + break; + case 0x12: + /* FCMPLT */ + index = FCMPLT; + break; + case 0x13: + /* FCMPUN */ + index = FCMPUN; + break; + case 0x20: + /* FCVTSD */ + index = FCVTSD; + break; + case 0x21: + /* FCVTDS */ + index = FCVTDS; + break; + case 0x22: + /* FCVTDL_G */ + index = FCVTDL_G; + break; + case 0x23: + /* FCVTDL_P */ + index = FCVTDL_P; + break; + case 0x24: + /* FCVTDL_Z */ + index = FCVTDL_Z; + break; + case 0x25: + /* FCVTDL_N */ + index = FCVTDL_N; + break; + case 0x27: + /* FCVTDL */ + index = FCVTDL; + break; + case 0x28: + /* FCVTWL */ + index = FCVTWL; + break; + case 0x29: + /* FCVTLW */ + index = FCVTLW; + break; + case 0x2d: + /* FCVTLS */ + index = FCVTLS; + break; + case 0x2f: + /* FCVTLD */ + index = FCVTLD; + break; + case 0x30: + /* FCPYS */ + index = FCPYS; + break; + case 0x31: + /* FCPYSE */ + index = FCPYSE; + break; + case 0x32: + /* FCPYSN */ + index = FCPYSN; + break; + case 0x40: + /* IFMOVS */ + index = IFMOVS; + break; + case 0x41: + /* IFMOVD */ + index = IFMOVD; + break; + case 0x50: + /* RFPCR */ + index = RFPCR; + break; + case 0x51: + /* WFPCR */ + index = WFPCR; + break; + case 0x54: + /* SETFPEC0 */ + index = SETFPEC0; + break; + case 0x55: + /* SETFPEC1 */ + index = SETFPEC1; + break; + case 0x56: + /* SETFPEC2 */ + index = SETFPEC2; + break; + case 0x57: + /* SETFPEC3 */ + index = SETFPEC3; + break; + case 0x58: + /* FRECS */ + index = FRECS; + break; + case 0x59: + /* FRECD */ + index = FRECD; + break; + case 0x5A: + /* FRIS */ + index = FRIS; + break; + case 0x5B: + /* FRIS_G */ + index = FRIS_G; + break; + case 0x5C: + /* FRIS_P */ + index = FRIS_P; + break; + case 0x5D: + /* FRIS_Z */ + index = FRIS_Z; + break; + case 0x5F: + /* FRIS_N */ + index = FRIS_N; + break; + case 0x60: + /* FRID */ + index = FRID; + break; + case 0x61: + /* FRID_G */ + index = FRID_G; + break; + case 0x62: + /* FRID_P */ + index = FRID_P; + break; + case 0x63: + /* FRID_Z */ + index = FRID_Z; + break; + case 0x64: + /* FRID_N */ + index = FRID_N; + break; + default: + break; + } + break; + case 0x19: + switch (fn6) { + case 0x00: + /* FMAS */ + index = FMAS; + break; + case 0x01: + /* FMAD */ + index = FMAD; + break; + case 0x02: + /* FMSS */ + index = FMSS; + break; + case 0x03: + /* FMSD */ + index = FMSD; + break; + case 0x04: + /* FNMAS */ + index = FNMAS; + break; + case 0x05: + /* FNMAD */ + index = FNMAD; + break; + case 0x06: + /* FNMSS */ + index = FNMSS; + break; + case 0x07: + /* FNMSD */ + index = FNMSD; + break; + case 0x10: + /* FSELEQ */ + index = FSELEQ; + break; + case 0x11: + /* FSELNE */ + index = FSELNE; + break; + case 0x12: + /* FSELLT */ + index = FSELLT; + break; + case 0x13: + /* FSELLE */ + index = FSELLE; + break; + case 0x14: + /* FSELGT */ + index = FSELGT; + break; + case 0x15: + /* FSELGE */ + index = FSELGE; + break; + default: + break; + } + break; + case 0x1A: + switch (fn8) { + case 0x00: + /* VADDW */ + index = VADDW; + break; + case 0x20: + /* VADDWI */ + index = VADDWI; + break; + case 0x01: + /* VSUBW */ + index = VSUBW; + break; + case 0x21: + /* VSUBWI */ + index = VSUBWI; + break; + case 0x02: + /* VCMPGEW */ + index = VCMPGEW; + break; + case 0x22: + /* VCMPGEWI */ + index = VCMPGEWI; + break; + case 0x03: + /* VCMPEQW */ + index = VCMPEQW; + break; + case 0x23: + /* VCMPEQWI */ + index = VCMPEQWI; + break; + case 0x04: + /* VCMPLEW */ + index = VCMPLEW; + break; + case 0x24: + /* VCMPLEWI */ + index = VCMPLEWI; + break; + case 0x05: + /* VCMPLTW */ + index = VCMPLTW; + break; + case 0x25: + /* VCMPLTWI */ + index = VCMPLTWI; + break; + case 0x06: + /* VCMPULEW */ + index = VCMPULEW; + break; + case 0x26: + /* VCMPULEWI */ + index = VCMPULEWI; + break; + case 0x07: + /* VCMPULTW */ + index = VCMPULTW; + break; + case 0x27: + /* VCMPULTWI */ + index = VCMPULTWI; + break; + case 0x08: + /* VSLLW */ + index = VSLLW; + break; + case 0x28: + /* VSLLWI */ + index = VSLLWI; + break; + case 0x09: + /* VSRLW */ + index = VSRLW; + break; + case 0x29: + /* VSRLWI */ + index = VSRLWI; + break; + case 0x0A: + /* VSRAW */ + index = VSRAW; + break; + case 0x2A: + /* VSRAWI */ + index = VSRAWI; + break; + case 0x0B: + /* VROLW */ + index = VROLW; + break; + case 0x2B: + /* VROLWI */ + index = VROLWI; + break; + case 0x0C: + /* SLLOW */ + index = SLLOW; + break; + case 0x2C: + /* SLLOWI */ + index = SLLOWI; + break; + case 0x0D: + /* SRLOW */ + index = SRLOW; + break; + case 0x2D: + /* SRLOWI */ + index = SRLOWI; + break; + case 0x0E: + /* VADDL */ + index = VADDL; + break; + case 0x2E: + /* VADDLI */ + index = VADDLI; + break; + case 0x0F: + /* VSUBL */ + index = VSUBL; + break; + case 0x2F: + /* VSUBLI */ + index = VSUBLI; + break; + case 0x10: + /* VSLLB */ + index = VSLLB; + break; + case 0x30: + /* VSLLBI */ + index = VSLLBI; + break; + case 0x11: + /* VSRLB */ + index = VSRLB; + break; + case 0x31: + /* VSRLBI */ + index = VSRLBI; + break; + case 0x12: + /* VSRAB */ + index = VSRAB; + break; + case 0x32: + /* VSRABI */ + index = VSRABI; + break; + case 0x13: + /* VROLB */ + index = VROLB; + break; + case 0x33: + /* VROLBI */ + index = VROLBI; + break; + case 0x14: + /* VSLLH */ + index = VSLLH; + break; + case 0x34: + /* VSLLHI */ + index = VSLLHI; + break; + case 0x15: + /* VSRLH */ + index = VSRLH; + break; + case 0x35: + /* VSRLHI */ + index = VSRLHI; + break; + case 0x16: + /* VSRAH */ + index = VSRAH; + break; + case 0x36: + /* VSRAHI */ + index = VSRAHI; + break; + case 0x17: + /* VROLH */ + index = VROLH; + break; + case 0x37: + /* VROLHI */ + index = VROLHI; + break; + case 0x18: + /* CTPOPOW */ + index = CTPOPOW; + break; + case 0x19: + /* CTLZOW */ + index = CTLZOW; + break; + case 0x1A: + /* VSLLL */ + index = VSLLL; + break; + case 0x3A: + /* VSLLLI */ + index = VSLLLI; + break; + case 0x1B: + /* VSRLL */ + index = VSRLL; + break; + case 0x3B: + /* VSRLLI */ + index = VSRLLI; + break; + case 0x1C: + /* VSRAL */ + index = VSRAL; + break; + case 0x3C: + /* VSRALI */ + index = VSRALI; + break; + case 0x1D: + /* VROLL */ + index = VROLL; + break; + case 0x3D: + /* VROLLI */ + index = VROLLI; + break; + case 0x1E: + /* VMAXB */ + index = VMAXB; + break; + case 0x1F: + /* VMINB */ + index = VMINB; + break; + case 0x40: + /* VUCADDW */ + index = VUCADDW; + break; + case 0x60: + /* VUCADDWI */ + index = VUCADDWI; + break; + case 0x41: + /* VUCSUBW */ + index = VUCSUBW; + break; + case 0x61: + /* VUCSUBWI */ + index = VUCSUBWI; + break; + case 0x42: + /* VUCADDH */ + index = VUCADDH; + break; + case 0x62: + /* VUCADDHI */ + index = VUCADDHI; + break; + case 0x43: + /* VUCSUBH */ + index = VUCSUBH; + break; + case 0x63: + /* VUCSUBHI */ + index = VUCSUBHI; + break; + case 0x44: + /* VUCADDB */ + index = VUCADDB; + break; + case 0x64: + /* VUCADDBI */ + index = VUCADDBI; + break; + case 0x45: + /* VUCSUBB */ + index = VUCSUBB; + break; + case 0x65: + /* VUCSUBBI */ + index = VUCSUBBI; + break; + case 0x46: + /* SRAOW */ + index = SRAOW; + break; + case 0x66: + /* SRAOWI */ + index = SRAOWI; + break; + case 0x47: + /* VSUMW */ + index = VSUMW; + break; + case 0x48: + /* VSUML */ + index = VSUML; + break; + case 0x49: + /* VSM4R */ + index = VSM4R; + break; + case 0x4A: + /* VBINVW */ + index = VBINVW; + break; + case 0x4B: + /* VCMPUEQB */ + index = VCMPUEQB; + break; + case 0x6B: + /* VCMPUEQBI*/ + break; + case 0x4C: + /* VCMPUGTB */ + index = VCMPUGTB; + break; + case 0x6C: + /* VCMPUGTBI */ + index = VCMPUGTBI; + break; + case 0x4D: + /* VSM3MSW */ + index = VSM3MSW; + break; + case 0x50: + /* VMAXH */ + index = VMAXH; + break; + case 0x51: + /* VMINH */ + index = VMINH; + break; + case 0x52: + /* VMAXW */ + index = VMAXW; + break; + case 0x53: + /* VMINW */ + index = VMINW; + break; + case 0x54: + /* VMAXL */ + index = VMAXL; + break; + case 0x55: + /* VMINL */ + index = VMINL; + break; + case 0x56: + /* VUMAXB */ + index = VUMAXB; + break; + case 0x57: + /* VUMINB */ + index = VUMINB; + break; + case 0x58: + /* VUMAXH */ + index = VUMAXH; + break; + case 0x59: + /* VUMINH */ + index = VUMINH; + break; + case 0x5A: + /* VUMAXW */ + index = VUMAXW; + break; + case 0x5B: + /* VUMINW */ + index = VUMINW; + break; + case 0x5C: + /* VUMAXL */ + index = VUMAXL; + break; + case 0x5D: + /* VUMINL */ + index = VUMINL; + break; + case 0x68: + /* VSM4KEY */ + index = VSM4KEY; + break; + case 0x80: + /* VADDS */ + index = VADDS; + break; + case 0x81: + /* VADDD */ + index = VADDD; + break; + case 0x82: + /* VSUBS */ + index = VSUBS; + break; + case 0x83: + /* VSUBD */ + index = VSUBD; + break; + case 0x84: + /* VMULS */ + index = VMULS; + break; + case 0x85: + /* VMULD */ + index = VMULD; + break; + case 0x86: + /* VDIVS */ + index = VDIVS; + break; + case 0x87: + /* VDIVD */ + index = VDIVD; + break; + case 0x88: + /* VSQRTS */ + index = VSQRTS; + break; + case 0x89: + /* VSQRTD */ + index = VSQRTD; + break; + case 0x8C: + /* VFCMPEQ */ + index = VFCMPEQ; + break; + case 0x8D: + /* VFCMPLE */ + index = VFCMPLE; + break; + case 0x8E: + /* VFCMPLT */ + index = VFCMPLT; + break; + case 0x8F: + /* VFCMPUN */ + index = VFCMPUN; + break; + case 0x90: + /* VCPYS */ + index = VCPYS; + break; + case 0x91: + /* VCPYSE */ + index = VCPYSE; + break; + case 0x92: + /* VCPYSN */ + index = VCPYSN; + break; + case 0x93: + /* VSUMS */ + index = VSUMS; + break; + case 0x94: + /* VSUMD */ + index = VSUMD; + break; + case 0x95: + /* VFCVTSD */ + index = VFCVTSD; + break; + case 0x96: + /* VFCVTDS */ + index = VFCVTDS; + break; + case 0x99: + /* VFCVTLS */ + index = VFCVTLS; + break; + case 0x9A: + /* VFCVTLD */ + index = VFCVTLD; + break; + case 0x9B: + /* VFCVTDL */ + index = VFCVTDL; + break; + case 0x9C: + /* VFCVTDL_G */ + index = VFCVTDL_G; + break; + case 0x9D: + /* VFCVTDL_P */ + index = VFCVTDL_P; + break; + case 0x9E: + /* VFCVTDL_Z */ + index = VFCVTDL_Z; + break; + case 0x9F: + /* VFCVTDL_N */ + index = VFCVTDL_N; + break; + case 0xA0: + /* VFRIS */ + index = VFRIS; + break; + case 0xA1: + /* VFRIS_G */ + index = VFRIS_G; + break; + case 0xA2: + /* VFRIS_P */ + index = VFRIS_P; + break; + case 0xA3: + /* VFRIS_Z */ + index = VFRIS_Z; + break; + case 0xA4: + /* VFRIS_N */ + index = VFRIS_N; + break; + case 0xA5: + /* VFRID */ + index = VFRID; + break; + case 0xA6: + /* VFRID_G */ + index = VFRID_G; + break; + case 0xA7: + /* VFRID_P */ + index = VFRID_P; + break; + case 0xA8: + /* VFRID_Z */ + index = VFRID_Z; + break; + case 0xA9: + /* VFRID_N */ + index = VFRID_N; + break; + case 0xAA: + /* VFRECS */ + index = VFRECS; + break; + case 0xAB: + /* VFRECD */ + index = VFRECD; + break; + case 0xAC: + /* VMAXS */ + index = VMAXS; + break; + case 0xAD: + /* VMINS */ + index = VMINS; + break; + case 0xAE: + /* VMAXD */ + index = VMAXD; + break; + case 0xAF: + /* VMIND */ + index = VMIND; + break; + default: + break; + } + break; + case 0x1B: + switch (fn6) { + case 0x00: + /* VMAS */ + index = VMAS; + break; + case 0x01: + /* VMAD */ + index = VMAD; + break; + case 0x02: + /* VMSS */ + index = VMSS; + break; + case 0x03: + /* VMSD */ + index = VMSD; + break; + case 0x04: + /* VNMAS */ + index = VNMAS; + break; + case 0x05: + /* VNMAD */ + index = VNMAD; + break; + case 0x06: + /* VNMSS */ + index = VNMSS; + break; + case 0x07: + /* VNMSD */ + index = VNMSD; + break; + case 0x10: + /* VFSELEQ */ + index = VFSELEQ; + break; + case 0x12: + /* VFSELLT */ + index = VFSELLT; + break; + case 0x13: + /* VFSELLE */ + index = VFSELLE; + break; + case 0x18: + /* VSELEQW */ + index = VSELEQW; + break; + case 0x38: + /* VSELEQWI */ + index = VSELEQWI; + break; + case 0x19: + /* VSELLBCW */ + index = VSELLBCW; + break; + case 0x39: + /* VSELLBCWI */ + index = VSELLBCWI; + break; + case 0x1A: + /* VSELLTW */ + index = VSELLTW; + break; + case 0x3A: + /* VSELLTWI */ + index = VSELLTWI; + break; + case 0x1B: + /* VSELLEW */ + index = VSELLEW; + break; + case 0x3B: + /* VSELLEWI */ + index = VSELLEWI; + break; + case 0x20: + /* VINSW */ + index = VINSW; + break; + case 0x21: + /* VINSF */ + index = VINSF; + break; + case 0x22: + /* VEXTW */ + index = VEXTW; + break; + case 0x23: + /* VEXTF */ + index = VEXTF; + break; + case 0x24: + /* VCPYW */ + index = VCPYW; + break; + case 0x25: + /* VCPYF */ + index = VCPYF; + break; + case 0x26: + /* VCONW */ + index = VCONW; + break; + case 0x27: + /* VSHFW */ + index = VSHFW; + break; + case 0x28: + /* VCONS */ + index = VCONS; + break; + case 0x29: + /* VCOND */ + index = VCOND; + break; + case 0x2A: + /* VINSB */ + index = VINSB; + break; + case 0x2B: + /* VINSH */ + index = VINSH; + break; + case 0x2C: + /* VINSECTLH */ + index = VINSECTLH; + break; + case 0x2D: + /* VINSECTLW */ + index = VINSECTLW; + break; + case 0x2E: + /* VINSECTLL */ + index = VINSECTLL; + break; + case 0x2F: + /* VINSECTLB */ + index = VINSECTLB; + break; + case 0x30: + /* VSHFQ */ + index = VSHFQ; + break; + case 0x31: + /* VSHFQB */ + index = VSHFQB; + break; + case 0x32: + /* VCPYB */ + index = VCPYB; + break; + case 0x33: + /* VCPYH */ + index = VCPYH; + break; + case 0x34: + /* VSM3R */ + index = VSM3R; + break; + case 0x35: + /* VFCVTSH */ + index = VFCVTSH; + break; + case 0x36: + /* VFCVTHS */ + index = VFCVTHS; + break; + default: + break; + } + break; + case 0x1C: + switch (fn4) { + case 0x0: + /* VLDW_U */ + index = VLDW_U; + break; + case 0x1: + /* VSTW_U */ + index = VSTW_U; + break; + case 0x2: + /* VLDS_U */ + index = VLDS_U; + break; + case 0x3: + /* VSTS_U */ + index = VSTS_U; + break; + case 0x4: + /* VLDD_U */ + index = VLDD_U; + break; + case 0x5: + /* VSTD_U */ + index = VSTD_U; + break; + case 0x8: + /* VSTW_UL */ + index = VSTW_UL; + break; + case 0x9: + /* VSTW_UH */ + index = VSTW_UH; + break; + case 0xa: + /* VSTS_UL */ + index = VSTS_UL; + break; + case 0xb: + /* VSTS_UH */ + index = VSTS_UH; + break; + case 0xc: + /* VSTD_UL */ + index = VSTD_UL; + break; + case 0xd: + /* VSTD_UH */ + index = VSTD_UH; + break; + case 0xe: + /* VLDD_NC */ + index = VLDD_NC; + break; + case 0xf: + /* VSTD_NC */ + index = VSTD_NC; + break; + default: + break; + } + break; + case 0x1D: + /* LBR */ + index = LBR; + break; + case 0x1E: + switch (fn4) { + case 0x0: + /* LDBU_A */ + index = LDBU_A; + break; + case 0x1: + /* LDHU_A */ + index = LDHU_A; + break; + case 0x2: + /* LDW_A */ + index = LDW_A; + break; + case 0x3: + /* LDL_A */ + index = LDL_A; + break; + case 0x4: + /* FLDS_A */ + index = FLDS_A; + break; + case 0x5: + /* FLDD_A */ + index = FLDD_A; + break; + case 0x6: + /* STBU_A */ + index = STBU_A; + break; + case 0x7: + /* STHU_A */ + index = STHU_A; + break; + case 0x8: + /* STW_A */ + index = STW_A; + break; + case 0x9: + /* STL_A */ + index = STL_A; + break; + case 0xA: + /* FSTS_A */ + index = FSTS_A; + break; + case 0xB: + /* FSTD_A */ + index = FSTD_A; + break; + case 0xE: + /* DPFHR */ + index = DPFHR; + break; + case 0xF: + /* DPFHW */ + index = DPFHW; + break; + default: + break; + } + break; + case 0x20: + /* LDBU */ + index = LDBU; + break; + case 0x21: + /* LDHU */ + index = LDHU; + break; + case 0x22: + /* LDW */ + index = LDW; + break; + case 0x23: + /* LDL */ + index = LDL; + break; + case 0x24: + /* LDL_U */ + index = LDL_U; + break; + case 0x25: + if ((insn >> 12) & 1) { + /* PRI_LDL */ + index = PRI_LDL; + } else { + /* PRI_LDW */ + index = PRI_LDW; + } + break; + case 0x26: + /* FLDS */ + index = FLDS; + break; + case 0x27: + /* FLDD */ + index = FLDD; + break; + case 0x28: + /* STB */ + index = STB; + break; + case 0x29: + /* STH */ + index = STH; + break; + case 0x2a: + /* STW */ + index = STW; + break; + case 0x2b: + /* STL */ + index = STL; + break; + case 0x2c: + /* STL_U */ + index = STL_U; + break; + case 0x2d: + if ((insn >> 12) & 1) { + /* PRI_STL */ + index = PRI_STL; + } else { + /* PRI_STW */ + index = PRI_STW; + } + break; + case 0x2e: + /* FSTS */ + index = FSTS; + break; + case 0x2f: + /* FSTD */ + index = FSTD; + break; + case 0x30: + /* BEQ */ + index = BEQ; + break; + case 0x31: + /* BNE */ + index = BNE; + break; + case 0x32: + /* BLT */ + index = BLT; + break; + case 0x33: + /* BLE */ + index = BLE; + break; + case 0x34: + /* BGT */ + index = BGT; + break; + case 0x35: + /* BGE */ + index = BGE; + break; + case 0x36: + /* BLBC */ + index = BLBC; + break; + case 0x37: + /* BLBS */ + index = BLBS; + break; + case 0x38: + /* FBEQ */ + index = FBEQ; + break; + case 0x39: + /* FBNE */ + index = FBNE; + break; + case 0x3a: + /* FBLT */ + index = FBLT; + break; + case 0x3b: + /* FBLE */ + index = FBLE; + break; + case 0x3c: + /* FBGT */ + index = FBGT; + break; + case 0x3d: + /* FBGE */ + index = FBGE; + break; + case 0x3f: + /* LDIH */ + index = LDIH; + break; + case 0x3e: + /* LDI */ + index = LDI; + break; + default: +do_invalid: + break; + } + count = tcg_temp_new(); + offs = offsetof(CPUSW64State, insn_count[index]); + tcg_gen_ld_i64(count, cpu_env, offs); + tcg_gen_addi_i64(count, count, 1); + tcg_gen_st_i64(count, cpu_env, offs); + tcg_temp_free(count); +} diff --git a/target/sw64/profile.h b/target/sw64/profile.h new file mode 100644 index 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..13bd52de3dce3f89fa59eddf715d9d2689289493 --- /dev/null +++ b/target/sw64/simd_helper.c @@ -0,0 +1,1058 @@ +#include "qemu/osdep.h" +#include "cpu.h" +#include "exec/exec-all.h" +#include "exec/helper-proto.h" + +#undef DEBUG_SIMD + +static inline uint8_t *get_element_b(CPUSW64State *env, uint64_t ra, + int index) +{ + return (uint8_t*)&env->fr[ra + (index / 8) * 32] + (index % 8); +} + +static inline uint16_t *get_element_h(CPUSW64State *env, uint64_t ra, + int index) +{ + return (uint16_t*)&env->fr[ra + (index / 4) * 32] + (index % 4); +} + +static inline uint32_t *get_element_w(CPUSW64State *env, uint64_t ra, + int index) +{ + return (uint32_t*)&env->fr[ra + (index / 2) * 32] + (index % 2); +} + +static inline uint64_t *get_element_l(CPUSW64State *env, uint64_t ra, + int index) +{ + return &env->fr[ra + index * 32]; +} + +void helper_srlow(CPUSW64State *env, uint64_t ra, uint64_t rc, uint64_t shift) +{ + int i; + int adden; + int dest, src; + adden = shift >> 6; + shift &= 0x3f; +#ifdef DEBUG_SIMD + printf("right shift = %ld adden = %d\n", shift, adden); + printf("in_fr[%ld]:", ra); + for (i = 3 ; i >= 0; i--) { + printf("%016lx ", env->fr[ra + 32 * i]); + } + printf("\n"); +#endif + + for (i = 0; (i + adden) < 4; i++) { + dest = i * 32 + rc; + src = (i + adden) * 32 + ra; + env->fr[dest] = env->fr[src] >> shift; + if (((i + adden) < 3) && (shift != 0)) + env->fr[dest] |= (env->fr[src + 32] << (64 - shift)); + } + + for (; i < 4; i++) { + env->fr[rc + i * 32] = 0; + } +#ifdef DEBUG_SIMD + printf("out_fr[%ld]:", rc); + for (i = 3 ; i >= 0; i--) { + printf("%016lx ", env->fr[rc + 32 * i]); + } + printf("\n"); +#endif +} + +void helper_sllow(CPUSW64State *env, uint64_t ra, uint64_t rc, uint64_t shift) +{ + int i; + int adden; + int dest, src; + adden = shift >> 6; + shift &= 0x3f; +#ifdef DEBUG_SIMD + printf("left shift = %ld adden = %d\n", shift, adden); + printf("in_fr[%ld]:", ra); + for (i = 3 ; i >= 0; i--) { + printf("%016lx ", env->fr[ra + 32 * i]); + } + printf("\n"); +#endif + + for (i = 3; (i - adden) >= 0; i--) { + dest = i * 32 + rc; + src = (i - adden) * 32 + ra; + env->fr[dest] = env->fr[src] << shift; + if (((i - adden) > 0) && (shift != 0)) + env->fr[dest] |= (env->fr[src - 32] >> (64 - shift)); + } + for (; i >= 0; i--) { + env->fr[rc + i * 32] = 0; + } +#ifdef DEBUG_SIMD + printf("out_fr[%ld]:", rc); + for (i = 3 ; i >= 0; i--) { + printf("%016lx ", env->fr[rc + 32 * i]); + } + printf("\n"); +#endif +} + +static uint64_t do_logzz(uint64_t va, uint64_t vb, uint64_t vc, uint64_t zz) +{ + int i; + uint64_t ret = 0; + int index; + + for (i = 0; i < 64; i++) { + index = (((va >> i) & 1) << 2) | (((vb >> i) & 1) << 1) | ((vc >> i) & 1); + ret |= ((zz >> index) & 1) << i; + } + + return ret; +} + +void helper_vlogzz(CPUSW64State *env, uint64_t args, uint64_t rd, uint64_t zz) +{ + int i; + int ra, rb, rc; + ra = args >> 16; + rb = (args >> 8) & 0xff; + rc = args & 0xff; +#ifdef DEBUG_SIMD + printf("zz = %lx\n", zz); + printf("in_fr[%d]:", ra); + for (i = 3 ; i >= 0; i--) { + printf("%016lx ", env->fr[ra + 32 * i]); + } + printf("\n"); + printf("in_fr[%d]:", rb); + for (i = 3 ; i >= 0; i--) { + printf("%016lx ", env->fr[rb + 32 * i]); + } + printf("\n"); + printf("in_fr[%d]:", rc); + for (i = 3 ; i >= 0; i--) { + printf("%016lx ", env->fr[rc + 32 * i]); + } + printf("\n"); +#endif + for (i = 0; i < 4; i++) { + env->fr[rd + i * 32] = do_logzz(env->fr[ra + i * 32], env->fr[rb + i * 32], + env->fr[rc + i * 32], zz); + } +#ifdef DEBUG_SIMD + printf("out_fr[%ld]:", rd); + for (i = 3 ; i >= 0; i--) { + printf("%016lx ", env->fr[rd + 32 * i]); + } + printf("\n"); +#endif +} + +void helper_v_print(CPUSW64State *env, uint64_t v) +{ + printf("PC[%lx]: fr[%lx]:\n", GETPC(), v); +} + +void helper_vconw(CPUSW64State *env, uint64_t args, uint64_t rd, + uint64_t byte4_len) +{ + int ra, rb; + int count; + int i; + uint32_t *ptr_dst, *ptr_src; + uint32_t tmp[8]; + + ra = (args >> 8) & 0xff; + rb = args & 0xff; + count = 8 - byte4_len; + + for (i = 0; i < 8; i++) { + ptr_dst = get_element_w(env, rd, i); + if (i < count) { + ptr_src = get_element_w(env, ra, i + byte4_len); + } else { + ptr_src = get_element_w(env, rb, i - count); + } + tmp[i] = *ptr_src; + } + for (i = 0; i < 8; i++) { + ptr_dst = get_element_w(env, rd, i); + *ptr_dst = tmp[i]; + } +} + +void helper_vcond(CPUSW64State *env, uint64_t args, uint64_t rd, + uint64_t byte8_len) +{ + int ra, rb; + int count; + int i; + uint64_t *ptr_dst, *ptr_src; + uint64_t tmp[8]; + + ra = (args >> 8) & 0xff; + rb = args & 0xff; + count = 4 - byte8_len; + + for (i = 0; i < 4; i++) { + if (i < count) { + ptr_src = get_element_l(env, ra, i + byte8_len); + } else { + ptr_src = get_element_l(env, rb, i - count); + } + tmp[i] = *ptr_src; + } + for (i = 0; i < 4; i++) { + ptr_dst = get_element_l(env, rd, i + byte8_len); + *ptr_dst = tmp[i]; + } +} + +void helper_vshfw(CPUSW64State *env, uint64_t args, uint64_t rd, uint64_t vc) +{ + int ra, rb; + int i; + uint32_t *ptr_dst, *ptr_src; + uint32_t tmp[8]; + int flag, idx; + + ra = (args >> 8) & 0xff; + rb = args & 0xff; + + for (i = 0; i < 8; i++) { + flag = (vc >> (i * 4)) & 0x8; + idx = (vc >> (i * 4)) & 0x7; + if (flag == 0) { + ptr_src = get_element_w(env, ra, idx); + } else { + ptr_src = get_element_w(env, rb, idx); + } + tmp[i] = *ptr_src; + } + for (i = 0; i < 8; i++) { + ptr_dst = get_element_w(env, rd, i); + *ptr_dst = tmp[i]; + } +} + +uint64_t helper_ctlzow(CPUSW64State *env, uint64_t ra) +{ + int i, j; + uint64_t val; + uint64_t ctlz = 0; + + for (j = 3; j >= 0; j--) { + val = env->fr[ra + 32 * j]; + for (i = 63; i >= 0; i--) { + if ((val >> i) & 1) + return ctlz << 29; + else + ctlz++; + } + } + return ctlz << 29; +} + +void helper_vucaddw(CPUSW64State *env, uint64_t ra, uint64_t rb, uint64_t rc) +{ + int a, b, c; + int ret; + int i; + + for (i = 0; i < 4; i++) { + a = (int)(env->fr[ra + i * 32] & 0xffffffff); + b = (int)(env->fr[rb + i * 32] & 0xffffffff); + c = a + b; + if ((c ^ a) < 0 && (c ^ b) < 0) { + if (a < 0) + c = 0x80000000; + else + c = 0x7fffffff; + } + ret = c; + + a = (int)(env->fr[ra + i * 32] >> 32); + b = (int)(env->fr[rb + i * 32] >> 32); + c = a + b; + if ((c ^ a) < 0 && (c ^ b) < 0) { + if (a < 0) + c = 0x80000000; + else + c = 0x7fffffff; + } + env->fr[rc + i * 32] = ((uint64_t)(uint32_t)c << 32) | + (uint64_t)(uint32_t)ret; + } +} + +void helper_vucaddwi(CPUSW64State *env, uint64_t ra, uint64_t vb, uint64_t rc) +{ + int a, b, c; + int ret; + int i; + + b = (int)vb; + for (i = 0; i < 4; i++) { + a = (int)(env->fr[ra + i * 32] & 0xffffffff); + c = a + b; + if ((c ^ a) < 0 && (c ^ b) < 0) { + if (a < 0) + c = 0x80000000; + else + c = 0x7fffffff; + } + ret = c; + + a = (int)(env->fr[ra + i * 32] >> 32); + c = a + b; + if ((c ^ a) < 0 && (c ^ b) < 0) { + if (a < 0) + c = 0x80000000; + else + c = 0x7fffffff; + } + env->fr[rc + i * 32] = ((uint64_t)(uint32_t)c << 32) | + (uint64_t)(uint32_t)ret; + } +} + +void helper_vucsubw(CPUSW64State *env, uint64_t ra, uint64_t rb, uint64_t rc) +{ + int a, b, c; + int ret; + int i; + + for (i = 0; i < 4; i++) { + a = (int)(env->fr[ra + i * 32] & 0xffffffff); + b = (int)(env->fr[rb + i * 32] & 0xffffffff); + c = a - b; + if ((b ^ a) < 0 && (c ^ a) < 0) { + if (a < 0) + c = 0x80000000; + else + c = 0x7fffffff; + } + ret = c; + + a = (int)(env->fr[ra + i * 32] >> 32); + b = (int)(env->fr[rb + i * 32] >> 32); + c = a - b; + if ((b ^ a) < 0 && (c ^ a) < 0) { + if (a < 0) + c = 0x80000000; + else + c = 0x7fffffff; + } + env->fr[rc + i * 32] = ((uint64_t)(uint32_t)c << 32) | + (uint64_t)(uint32_t)ret; + } +} + +void helper_vucsubwi(CPUSW64State *env, uint64_t ra, uint64_t vb, uint64_t rc) +{ + int a, b, c; + int ret; + int i; + + b = (int)vb; + for (i = 0; i < 4; i++) { + a = (int)(env->fr[ra + i * 32] & 0xffffffff); + c = a - b; + if ((b ^ a) < 0 && (c ^ a) < 0) { + if (a < 0) + c = 0x80000000; + else + c = 0x7fffffff; + } + ret = c; + + a = (int)(env->fr[ra + i * 32] >> 32); + c = a - b; + if ((b ^ a) < 0 && (c ^ a) < 0) { + if (a < 0) + c = 0x80000000; + else + c = 0x7fffffff; + } + env->fr[rc + i * 32] = ((uint64_t)(uint32_t)c << 32) | + (uint64_t)(uint32_t)ret; + } +} + +void helper_vucaddh(CPUSW64State *env, uint64_t ra, uint64_t rb, uint64_t rc) +{ + short a, b, c; + uint64_t ret; + int i, j; + + for (i = 0; i < 4; i++) { + ret = 0; + for (j = 0; j < 4; j++) { + a = (short)((env->fr[ra + i * 32] >> (j * 16)) & 0xffff); + b = (short)((env->fr[rb + i * 32] >> (j * 16)) & 0xffff); + c = a + b; + if ((c ^ a) < 0 && (c ^ b) < 0) { + if (a < 0) + c = 0x8000; + else + c = 0x7fff; + } + ret |= ((uint64_t)(uint16_t)c) << (j * 16); + } + env->fr[rc + i * 32] = ret; + } +} + +void helper_vucaddhi(CPUSW64State *env, uint64_t ra, uint64_t vb, uint64_t rc) +{ + short a, b, c; + uint64_t ret; + int i, j; + + b = (short)vb; + for (i = 0; i < 4; i++) { + ret = 0; + for (j = 0; j < 4; j++) { + a = (short)((env->fr[ra + i * 32] >> (j * 16)) & 0xffff); + c = a + b; + if ((c ^ a) < 0 && (c ^ b) < 0) { + if (a < 0) + c = 0x8000; + else + c = 0x7fff; + } + ret |= ((uint64_t)(uint16_t)c) << (j * 16); + } + env->fr[rc + i * 32] = ret; + } +} + +void helper_vucsubh(CPUSW64State *env, uint64_t ra, uint64_t rb, uint64_t rc) +{ + short a, b, c; + uint64_t ret; + int i, j; + + for (i = 0; i < 4; i++) { + ret = 0; + for (j = 0; j < 4; j++) { + a = (short)((env->fr[ra + i * 32] >> (j * 16)) & 0xffff); + b = (short)((env->fr[rb + i * 32] >> (j * 16)) & 0xffff); + c = a - b; + if ((b ^ a) < 0 && (c ^ a) < 0) { + if (a < 0) + c = 0x8000; + else + c = 0x7fff; + } + ret |= ((uint64_t)(uint16_t)c) << (j * 16); + } + env->fr[rc + i * 32] = ret; + } +} + +void helper_vucsubhi(CPUSW64State *env, uint64_t ra, uint64_t vb, uint64_t rc) +{ + short a, b, c; + uint64_t ret; + int i, j; + + b = (short)vb; + for (i = 0; i < 4; i++) { + ret = 0; + for (j = 0; j < 4; j++) { + a = (short)((env->fr[ra + i * 32] >> (j * 16)) & 0xffff); + c = a - b; + if ((b ^ a) < 0 && (c ^ a) < 0) { + if (a < 0) + c = 0x8000; + else + c = 0x7fff; + } + ret |= ((uint64_t)(uint16_t)c) << (j * 16); + } + env->fr[rc + i * 32] = ret; + } +} + +void helper_vucaddb(CPUSW64State *env, uint64_t ra, uint64_t rb, uint64_t rc) +{ + int8_t a, b, c; + uint64_t ret; + int i, j; + + for (i = 0; i < 4; i++) { + ret = 0; + for (j = 0; j < 8; j++) { + a = (int8_t)((env->fr[ra + i * 32] >> (j * 8)) & 0xff); + b = (int8_t)((env->fr[rb + i * 32] >> (j * 8)) & 0xff); + c = a + b; + if ((c ^ a) < 0 && (c ^ b) < 0) { + if (a < 0) + c = 0x80; + else + c = 0x7f; + } + ret |= ((uint64_t)(uint8_t)c) << (j * 8); + } + env->fr[rc + i * 32] = ret; + } +} + +void helper_vucaddbi(CPUSW64State *env, uint64_t ra, uint64_t vb, uint64_t rc) +{ + int8_t a, b, c; + uint64_t ret; + int i, j; + + b = (int8_t)(vb & 0xff); + for (i = 0; i < 4; i++) { + ret = 0; + for (j = 0; j < 8; j++) { + a = (int8_t)((env->fr[ra + i * 32] >> (j * 8)) & 0xff); + c = a + b; + if ((c ^ a) < 0 && (c ^ b) < 0) { + if (a < 0) + c = 0x80; + else + c = 0x7f; + } + ret |= ((uint64_t)(uint8_t)c) << (j * 8); + } + env->fr[rc + i * 32] = ret; + } +} + +void helper_vucsubb(CPUSW64State *env, uint64_t ra, uint64_t rb, uint64_t rc) +{ + int8_t a, b, c; + uint64_t ret; + int i, j; + + for (i = 0; i < 4; i++) { + ret = 0; + for (j = 0; j < 8; j++) { + a = (int8_t)((env->fr[ra + i * 32] >> (j * 8)) & 0xff); + b = (int8_t)((env->fr[rb + i * 32] >> (j * 8)) & 0xff); + c = a - b; + if ((b ^ a) < 0 && (c ^ a) < 0) { + if (a < 0) + c = 0x80; + else + c = 0x7f; + } + ret |= ((uint64_t)(uint8_t)c) << (j * 8); + } + env->fr[rc + i * 32] = ret; + } +} + +void helper_vucsubbi(CPUSW64State *env, uint64_t ra, uint64_t vb, uint64_t rc) +{ + int8_t a, b, c; + uint64_t ret; + int i, j; + + b = (int8_t)(vb & 0xff); + for (i = 0; i < 4; i++) { + ret = 0; + for (j = 0; j < 8; j++) { + a = (int8_t)((env->fr[ra + i * 32] >> (j * 8)) & 0xffff); + c = a - b; + if ((b ^ a) < 0 && (c ^ a) < 0) { + if (a < 0) + c = 0x80; + else + c = 0x7f; + } + ret |= ((uint64_t)(uint8_t)c) << (j * 8); + } + env->fr[rc + i * 32] = ret; + } +} + +uint64_t helper_vstw(CPUSW64State *env, uint64_t t0, uint64_t t1) +{ + uint64_t idx, shift; + + idx = t0 + (t1 / 2) * 32; + shift = (t1 % 2) * 32; + + return (env->fr[idx] >> shift) & 0xffffffffUL; +} + +uint64_t helper_vsts(CPUSW64State *env, uint64_t t0, uint64_t t1) +{ + uint64_t idx, val; + + idx = t0 + t1 * 32; + val = env->fr[idx]; + + return ((val >> 32) & 0xc0000000) | ((val >> 29) & 0x3fffffff); +} + +uint64_t helper_vstd(CPUSW64State *env, uint64_t t0, uint64_t t1) +{ + uint64_t idx; + + idx = t0 + t1 * 32; + return env->fr[idx]; +} + +#define HELPER_VMAX(name, _suffix, type, loop) \ + void glue(glue(helper_, name), _suffix)(CPUSW64State *env, uint64_t ra, \ + uint64_t rb, uint64_t rc) \ + { \ + int i; \ + type *ptr_dst, *ptr_src_a, *ptr_src_b; \ + \ + for (i = 0; i < loop; i++) { \ + ptr_dst = (type*)glue(get_element_, _suffix)(env, rc, i); \ + ptr_src_a = (type*)glue(get_element_, _suffix)(env, ra, i); \ + ptr_src_b = (type*)glue(get_element_, _suffix)(env, rb, i); \ + \ + if (*ptr_src_a >= *ptr_src_b) { \ + *ptr_dst = *ptr_src_a; \ + } else { \ + *ptr_dst = *ptr_src_b; \ + } \ + } \ + } + +#define HELPER_VMIN(name, _suffix, type, loop) \ + void glue(glue(helper_, name), _suffix)(CPUSW64State *env, uint64_t ra, \ + uint64_t rb, uint64_t rc) \ + { \ + int i; \ + type *ptr_dst, *ptr_src_a, *ptr_src_b; \ + \ + for (i = 0; i < loop; i++) { \ + ptr_dst = (type*)glue(get_element_, _suffix)(env, rc, i); \ + ptr_src_a = (type*)glue(get_element_, _suffix)(env, ra, i); \ + ptr_src_b = (type*)glue(get_element_, _suffix)(env, rb, i); \ + \ + if (*ptr_src_a <= *ptr_src_b) { \ + *ptr_dst = *ptr_src_a; \ + } else { \ + *ptr_dst = *ptr_src_b; \ + } \ + } \ + } + +HELPER_VMAX(vmax, b, int8_t, 32) +HELPER_VMIN(vmin, b, int8_t, 32) +HELPER_VMAX(vmax, h, int16_t, 16) +HELPER_VMIN(vmin, h, int16_t, 16) +HELPER_VMAX(vmax, w, int32_t, 8) +HELPER_VMIN(vmin, w, int32_t, 8) +HELPER_VMAX(vumax, b, uint8_t, 32) +HELPER_VMIN(vumin, b, uint8_t, 32) +HELPER_VMAX(vumax, h, uint16_t, 16) +HELPER_VMIN(vumin, h, uint16_t, 16) +HELPER_VMAX(vumax, w, uint32_t, 8) +HELPER_VMIN(vumin, w, uint32_t, 8) + +void helper_sraow(CPUSW64State *env, uint64_t ra, uint64_t rc, uint64_t shift) +{ + int i; + int adden; + int dest, src; + uint64_t sign; + adden = shift >> 6; + shift &= 0x3f; + sign = (uint64_t)((int64_t)env->fr[ra + 96] >> 63); +#ifdef DEBUG_SIMD + printf("right shift = %ld adden = %d\n", shift, adden); + printf("in_fr[%ld]:", ra); + for (i = 3 ; i >= 0; i--) { + printf("%016lx ", env->fr[ra + 32 * i]); + } + printf("\n"); +#endif + + for (i = 0; (i + adden) < 4; i++) { + dest = i * 32 + rc; + src = (i + adden) * 32 + ra; + env->fr[dest] = env->fr[src] >> shift; + if (shift != 0) { + if (((i + adden) < 3)) + env->fr[dest] |= (env->fr[src + 32] << (64 - shift)); + else + env->fr[dest] |= (sign << (64 - shift)); + } + } + + for (; i < 4; i++) { + env->fr[rc + i * 32] = sign; + } +#ifdef DEBUG_SIMD + printf("out_fr[%ld]:", rc); + for (i = 3 ; i >= 0; i--) { + printf("%016lx ", env->fr[rc + 32 * i]); + } + printf("\n"); +#endif +} + +static uint16_t sm4_sbox[16][16] = { + { 0xd6, 0x90, 0xe9, 0xfe, 0xcc, 0xe1, 0x3d, 0xb7, 0x16, 0xb6, 0x14, 0xc2, 0x28, 0xfb, 0x2c, 0x05 }, + { 0x2b, 0x67, 0x9a, 0x76, 0x2a, 0xbe, 0x04, 0xc3, 0xaa, 0x44, 0x13, 0x26, 0x49, 0x86, 0x06, 0x99 }, + { 0x9c, 0x42, 0x50, 0xf4, 0x91, 0xef, 0x98, 0x7a, 0x33, 0x54, 0x0b, 0x43, 0xed, 0xcf, 0xac, 0x62 }, + { 0xe4, 0xb3, 0x1c, 0xa9, 0xc9, 0x08, 0xe8, 0x95, 0x80, 0xdf, 0x94, 0xfa, 0x75, 0x8f, 0x3f, 0xa6 }, + { 0x47, 0x07, 0xa7, 0xfc, 0xf3, 0x73, 0x17, 0xba, 0x83, 0x59, 0x3c, 0x19, 0xe6, 0x85, 0x4f, 0xa8 }, + { 0x68, 0x6b, 0x81, 0xb2, 0x71, 0x64, 0xda, 0x8b, 0xf8, 0xeb, 0x0f, 0x4b, 0x70, 0x56, 0x9d, 0x35 }, + { 0x1e, 0x24, 0x0e, 0x5e, 0x63, 0x58, 0xd1, 0xa2, 0x25, 0x22, 0x7c, 0x3b, 0x01, 0x21, 0x78, 0x87 }, + { 0xd4, 0x00, 0x46, 0x57, 0x9f, 0xd3, 0x27, 0x52, 0x4c, 0x36, 0x02, 0xe7, 0xa0, 0xc4, 0xc8, 0x9e }, + { 0xea, 0xbf, 0x8a, 0xd2, 0x40, 0xc7, 0x38, 0xb5, 0xa3, 0xf7, 0xf2, 0xce, 0xf9, 0x61, 0x15, 0xa1 }, + { 0xe0, 0xae, 0x5d, 0xa4, 0x9b, 0x34, 0x1a, 0x55, 0xad, 0x93, 0x32, 0x30, 0xf5, 0x8c, 0xb1, 0xe3 }, + { 0x1d, 0xf6, 0xe2, 0x2e, 0x82, 0x66, 0xca, 0x60, 0xc0, 0x29, 0x23, 0xab, 0x0d, 0x53, 0x4e, 0x6f }, + { 0xd5, 0xdb, 0x37, 0x45, 0xde, 0xfd, 0x8e, 0x2f, 0x03, 0xff, 0x6a, 0x72, 0x6d, 0x6c, 0x5b, 0x51 }, + { 0x8d, 0x1b, 0xaf, 0x92, 0xbb, 0xdd, 0xbc, 0x7f, 0x11, 0xd9, 0x5c, 0x41, 0x1f, 0x10, 0x5a, 0xd8 }, + { 0x0a, 0xc1, 0x31, 0x88, 0xa5, 0xcd, 0x7b, 0xbd, 0x2d, 0x74, 0xd0, 0x12, 0xb8, 0xe5, 0xb4, 0xb0 }, + { 0x89, 0x69, 0x97, 0x4a, 0x0c, 0x96, 0x77, 0x7e, 0x65, 0xb9, 0xf1, 0x09, 0xc5, 0x6e, 0xc6, 0x84 }, + { 0x18, 0xf0, 0x7d, 0xec, 0x3a, 0xdc, 0x4d, 0x20, 0x79, 0xee, 0x5f, 0x3e, 0xd7, 0xcb, 0x39, 0x48 } +}; + +static uint32_t SBOX(uint32_t val) +{ + int ret = 0; + int i; + int idx_x, idx_y; + for (i = 0; i < 4; i++) { + idx_x = (val >> (i * 8)) & 0xff; + idx_y = idx_x & 0xf; + idx_x = idx_x >> 4; + + ret |= (sm4_sbox[idx_x][idx_y] << (i * 8)); + } + return ret; +} + +static uint32_t rotl(uint32_t val, int shift) +{ + uint64_t ret = (uint64_t)val; + ret = (ret << (shift & 0x1f)); + return (uint32_t)((ret & 0xffffffff) | (ret >> 32)); +} + +void helper_vsm4r(CPUSW64State *env, uint64_t ra, uint64_t rb, uint64_t rc) +{ + uint32_t W[12], rk[8]; + uint32_t temp1, temp2; + int i, j; + + for (i = 0; i < 8; i++) { + rk[i] = *get_element_w(env, rb, i); + } + for (i = 0; i < 2; i++) { + for (j = 0; j < 4; j++) { + W[j] = *get_element_w(env, ra, i * 4 + j); + } + for (j = 0; j < 8; j++) { + temp1 = W[j + 1] ^ W[j + 2] ^ W[j + 3] ^ rk[j]; + temp2 = SBOX(temp1); + W[j + 4] = W[j] ^ temp2 ^ rotl(temp2, 2) ^ rotl(temp2, 10) ^ rotl(temp2, 18) ^ rotl(temp2, 24); + } + + for (j = 0; j < 4; j++) { + *get_element_w(env, rc, i * 4 + j) = W[8 + j]; + } + } +} + +void helper_vcmpueqb(CPUSW64State *env, uint64_t ra, uint64_t rb, uint64_t rc) +{ + uint8_t *ptr_a, *ptr_b, *ptr_c; + int i; + + for (i = 0; i < 32; i++) { + ptr_a = get_element_b(env, ra, i); + ptr_b = get_element_b(env, rb, i); + ptr_c = get_element_b(env, rc, i); + + *ptr_c = (*ptr_a == *ptr_b) ? 1 : 0; + ; + } +} + +void helper_vcmpugtb(CPUSW64State *env, uint64_t ra, uint64_t rb, uint64_t rc) +{ + uint8_t *ptr_a, *ptr_b, *ptr_c; + int i; + + for (i = 0; i < 32; i++) { + ptr_a = get_element_b(env, ra, i); + ptr_b = get_element_b(env, rb, i); + ptr_c = get_element_b(env, rc, i); + + *ptr_c = (*ptr_a > *ptr_b) ? 1 : 0; + ; + } +} + +void helper_vcmpueqbi(CPUSW64State *env, uint64_t ra, uint64_t vb, + uint64_t rc) +{ + uint8_t *ptr_a, *ptr_c; + int i; + + for (i = 0; i < 32; i++) { + ptr_a = get_element_b(env, ra, i); + ptr_c = get_element_b(env, rc, i); + + *ptr_c = (*ptr_a == vb) ? 1 : 0; + ; + } +} + +void helper_vcmpugtbi(CPUSW64State *env, uint64_t ra, uint64_t vb, + uint64_t rc) +{ + uint8_t *ptr_a, *ptr_c; + int i; + + for (i = 0; i < 32; i++) { + ptr_a = get_element_b(env, ra, i); + ptr_c = get_element_b(env, rc, i); + + *ptr_c = (*ptr_a > vb) ? 1 : 0; + ; + } +} + +void helper_vsm3msw(CPUSW64State *env, uint64_t ra, uint64_t rb, uint64_t rc) +{ + uint32_t W[24]; + uint32_t temp; + int i; + + for (i = 0; i < 8; i++) { + W[i + 0] = *get_element_w(env, ra, i); + W[i + 8] = *get_element_w(env, rb, i); + } + for (i = 16; i < 24; i++) { + temp = W[i - 16] ^ W[i - 9] ^ rotl(W[i - 3], 15); + temp = temp ^ rotl(temp, 15) ^ rotl(temp, 23) ^ rotl(W[i - 13], 7) ^ W[i - 6]; + W[i] = temp; + } + for (i = 0; i < 8; i++) { + *get_element_w(env, rc, i) = W[16 + i]; + } +} + +static uint32_t selck[4][8] = { + {0x00070e15, 0x1c232a31, 0x383f464d, 0x545b6269, 0x70777e85, 0x8c939aa1, 0xa8afb6bd, 0xc4cbd2d9}, + {0xe0e7eef5, 0xfc030a11, 0x181f262d, 0x343b4249, 0x50575e65, 0x6c737a81, 0x888f969d, 0xa4abb2b9}, + {0xc0c7ced5, 0xdce3eaf1, 0xf8ff060d, 0x141b2229, 0x30373e45, 0x4c535a61, 0x686f767d, 0x848b9299}, + {0xa0a7aeb5, 0xbcc3cad1, 0xd8dfe6ed, 0xf4fb0209, 0x10171e25, 0x2c333a41, 0x484f565d, 0x646b7279} +}; + +void helper_vsm4key(CPUSW64State *env, uint64_t ra, uint64_t vb, uint64_t rc) +{ + uint32_t K[12], *CK; + int i; + uint32_t temp1, temp2; + + for (i = 4; i < 8; i++) { + K[i - 4] = *get_element_w(env, ra, i); + } + CK = selck[vb]; + + for (i = 0; i < 8; i++) { + temp1 = K[i + 1] ^ K[i + 2] ^ K[i + 3] ^ CK[i]; + temp2 = SBOX(temp1); + K[i + 4] = K[i] ^ temp2 ^ rotl(temp2, 13) ^ rotl(temp2, 23); + } + for (i = 0; i < 8; i++) { + *get_element_w(env, rc, i) = K[i + 4]; + } +} + +void helper_vinsb(CPUSW64State *env, uint64_t va, uint64_t rb, uint64_t vc, + uint64_t rd) +{ + int i; + + for (i = 0; i < 128; i += 32) { + env->fr[rd + i] = env->fr[rb + i]; + } + + *get_element_b(env, rd, vc) = (uint8_t)(va & 0xff); +} + +void helper_vinsh(CPUSW64State *env, uint64_t va, uint64_t rb, uint64_t vc, + uint64_t rd) +{ + int i; + + if (vc >= 16) + return; + + for (i = 0; i < 128; i += 32) { + env->fr[rd + i] = env->fr[rb + i]; + } + + *get_element_h(env, rd, vc) = (uint16_t)(va & 0xffff); +} + +void helper_vinsectlh(CPUSW64State *env, uint64_t ra, uint64_t rb, + uint64_t rd) +{ + int i; + uint32_t temp[8]; + for (i = 0; i < 8; i++) { + temp[i] = *get_element_h(env, ra, i) | ((uint32_t)*get_element_h(env, rb, i) << 16); + } + for (i = 0; i < 8; i++) { + *get_element_w(env, rd, i) = temp[i]; + } +} +void helper_vinsectlw(CPUSW64State *env, uint64_t ra, uint64_t rb, + uint64_t rd) +{ + int i; + uint64_t temp[4]; + for (i = 0; i < 4; i++) { + temp[i] = *get_element_w(env, ra, i) | ((uint64_t)*get_element_w(env, rb, i) << 32); + } + for (i = 0; i < 4; i++) { + *get_element_l(env, rd, i) = temp[i]; + } +} + +void helper_vinsectlb(CPUSW64State *env, uint64_t ra, uint64_t rb, + uint64_t rd) +{ + int i; + uint16_t temp[16]; + for (i = 0; i < 16; i++) { + temp[i] = *get_element_b(env, ra, i) | ((uint16_t)*get_element_b(env, rb, i) << 8); + } + for (i = 0; i < 16; i++) { + *get_element_h(env, rd, i) = temp[i]; + } +} + +void helper_vshfq(CPUSW64State *env, uint64_t ra, uint64_t rb, uint64_t vc, + uint64_t rd) +{ + int i; + int idx; + uint64_t temp[4]; + for (i = 0; i < 2; i++) { + idx = ((vc >> (i * 2)) & 1) * 64; + if ((vc >> (i * 2 + 1)) & 1) { + temp[i * 2] = env->fr[rb + idx]; + temp[i * 2 + 1] = env->fr[rb + idx + 32]; + } else { + temp[i * 2] = env->fr[ra + idx]; + temp[i * 2 + 1] = env->fr[ra + idx + 32]; + } + } + for (i = 0; i < 4; i++) { + env->fr[rd + i * 32] = temp[i]; + } +} + +void helper_vshfqb(CPUSW64State *env, uint64_t ra, uint64_t rb, uint64_t rd) +{ + int i; + int idx; + int vb; + uint8_t temp[32]; + + for (i = 0; i < 16; i++) { + vb = *get_element_b(env, rb, i); + if (vb >> 7) { + temp[i] = 0; + } else { + idx = vb & 0xf; + temp[i] = *get_element_b(env, ra, idx); + } + vb = *get_element_b(env, rb, i + 16); + if (vb >> 7) { + temp[i + 16] = 0; + } else { + idx = vb & 0xf; + temp[i + 16] = *get_element_b(env, ra, idx + 16); + } + } + for (i = 0; i < 4; i++) { + env->fr[rd + i * 32] = *((uint64_t*)temp + i); + } +} + +void helper_vsm3r(CPUSW64State *env, uint64_t ra, uint64_t rb, uint64_t vc, + uint64_t rd) +{ + uint32_t W[8]; + uint32_t A, B, C, D, E, F, G, H, T; + int i; + uint32_t SS1, SS2, TT1, TT2, P0; + + if (vc >= 16) + return; + for (i = 0; i < 8; i++) { + W[i] = *get_element_w(env, ra, i); + } + A = *get_element_w(env, rb, 0); + B = *get_element_w(env, rb, 1); + C = *get_element_w(env, rb, 2); + D = *get_element_w(env, rb, 3); + E = *get_element_w(env, rb, 4); + F = *get_element_w(env, rb, 5); + G = *get_element_w(env, rb, 6); + H = *get_element_w(env, rb, 7); + + if (vc < 4) { + T = 0x79cc4519; + for (i = 0; i < 4; i++) { + SS1 = rotl(rotl(A, 12) + E + rotl(T, 4 * vc + i), 7); + SS2 = SS1 ^ rotl(A, 12); + TT1 = (A ^ B ^ C) + D + SS2 + (W[i] ^ W[i + 4]); + TT2 = (E ^ F ^ G) + H + SS1 + W[i]; + + P0 = TT2 ^ rotl(TT2, 9) ^ rotl(TT2, 17); + + H = G; + G = rotl(F, 19); + F = E; + E = P0; + D = C; + C = rotl(B, 9); + B = A; + A = TT1; + } + } else { + T = 0x7a879d8a; + for (i = 0; i < 4; i++) { + SS1 = rotl(rotl(A, 12) + E + rotl(T, 4 * vc + i), 7); + SS2 = SS1 ^ rotl(A, 12); + TT1 = ((A & B) | (A & C) | (B & C)) + D + SS2 + (W[i] ^ W[i + 4]); + TT2 = ((E & F) | ((~E) & G)) + H + SS1 + W[i]; + + P0 = TT2 ^ rotl(TT2, 9) ^ rotl(TT2, 17); + + H = G; + G = rotl(F, 19); + F = E; + E = P0; + D = C; + C = rotl(B, 9); + B = A; + A = TT1; + } + } + *get_element_w(env, rd, 0) = A; + *get_element_w(env, rd, 1) = B; + *get_element_w(env, rd, 2) = C; + *get_element_w(env, rd, 3) = D; + *get_element_w(env, rd, 4) = E; + *get_element_w(env, rd, 5) = F; + *get_element_w(env, rd, 6) = G; + *get_element_w(env, rd, 7) = H; +} diff --git a/target/sw64/translate.c b/target/sw64/translate.c new file mode 100644 index 0000000000000000000000000000000000000000..98dd6906c930ec93bfaab9462d1bffc0b3063abf --- /dev/null +++ b/target/sw64/translate.c @@ -0,0 +1,5381 @@ +#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, bool clear) +{ + TCGv tmp, addr, va; + + /* LDQ_U with ra $31 is UNOP. Other various loads are forms of + prefetches, which we can treat as nops. No worries about + missed exceptions here. */ + if (unlikely(ra == 31)) { + return; + } + + tmp = tcg_temp_new(); + addr = load_gir(ctx, rb); + + if (disp16) { + tcg_gen_addi_i64(tmp, addr, (int64_t)disp16); + addr = tmp; + } else { + tcg_gen_mov_i64(tmp, addr); + addr = tmp; + } + if (clear) { + tcg_gen_andi_i64(tmp, addr, ~0x7UL); + addr = tmp; + } + + va = (fp ? cpu_fr[ra] : load_gir(ctx, ra)); + tcg_gen_qemu_load(va, addr, ctx->mem_idx); + //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, bool clear) +{ + TCGv tmp, addr, va; + + tmp = tcg_temp_new(); + addr = load_gir(ctx, rb); + if (disp16) { + tcg_gen_addi_i64(tmp, addr, disp16); + addr = tmp; + } else { + tcg_gen_mov_i64(tmp, addr); + addr = tmp; + } + if (clear) { + tcg_gen_andi_i64(tmp, addr, ~0x7); + addr = tmp; + } + va = (fp ? cpu_fr[ra] : load_gir(ctx, ra)); + + tcg_gen_qemu_store(va, addr, ctx->mem_idx); + gen_helper_trace_mem(cpu_env, addr, va); + tcg_temp_free(tmp); +} + +static void cal_with_iregs_2(DisasContext *ctx, TCGv vc, TCGv va, TCGv vb, + int32_t disp13, uint16_t fn) +{ + TCGv tmp, t1; + 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(); + tcg_gen_andi_i64(tmp, vb, 0x1f); + tcg_gen_ext32u_i64(va, va); + tcg_gen_shl_i64(vc, va, tmp); + tcg_gen_ext32u_i64(vc, vc); + tcg_temp_free(tmp); + 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); + // FIXME: for debug + //gen_helper_trace_mem(cpu_env, addr, va); + + tcg_temp_free(tmp); +} + +static inline void gen_store_mem_simd( + DisasContext *ctx, void (*tcg_gen_qemu_store)(int t0, TCGv t1, int flags), + int ra, int rb, int32_t disp16, uint64_t mask) +{ + TCGv tmp, addr; + + tmp = tcg_temp_new(); + addr = load_gir(ctx, rb); + if (disp16) { + tcg_gen_addi_i64(tmp, addr, (int64_t)disp16); + addr = tmp; + } else { + tcg_gen_mov_i64(tmp, addr); + addr = tmp; + } + if (mask) { + tcg_gen_andi_i64(addr, addr, mask); + } + // FIXME: for debug + //gen_helper_trace_mem(cpu_env, addr, addr); + 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 */ + // Maybe wrong translation. + tmp64 = tcg_temp_new(); + gen_helper_fcmpeq(tmp64, cpu_env, va, zero); + tcg_gen_movcond_i64(TCG_COND_EQ, vd, tmp64, zero, vc, vb); + tcg_temp_free(tmp64); + break; + case 0x11: + /* FSELNE */ + tmp64 = tcg_temp_new(); + gen_helper_fcmpeq(tmp64, cpu_env, va, zero); + tcg_gen_movcond_i64(TCG_COND_EQ, vd, tmp64, zero, vb, vc); + tcg_temp_free(tmp64); + break; + case 0x12: + /* FSELLT */ + tmp64 = tcg_temp_new(); + gen_helper_fcmplt(tmp64, cpu_env, va, zero); + tcg_gen_movcond_i64(TCG_COND_EQ, vd, tmp64, zero, vc, vb); + tcg_temp_free(tmp64); + break; + case 0x13: + /* FSELLE */ + tmp64 = tcg_temp_new(); + gen_helper_fcmple(tmp64, cpu_env, va, zero); + tcg_gen_movcond_i64(TCG_COND_EQ, vd, tmp64, zero, vc, vb); + tcg_temp_free(tmp64); + break; + case 0x14: + /* FSELGT */ + tmp64 = tcg_temp_new(); + gen_helper_fcmpgt(tmp64, cpu_env, va, zero); + tcg_gen_movcond_i64(TCG_COND_NE, vd, tmp64, zero, vb, vc); + tcg_temp_free(tmp64); + break; + case 0x15: + /* FSELGE */ + tmp64 = tcg_temp_new(); + gen_helper_fcmpge(tmp64, cpu_env, va, zero); + tcg_gen_movcond_i64(TCG_COND_NE, vd, tmp64, zero, vb, vc); + tcg_temp_free(tmp64); + break; + default: + fprintf(stderr, "Illegal insn func[%x]\n", fn); + gen_invalid(ctx); + break; + } + tcg_temp_free(zero); +} +static inline void gen_qemu_lldw(TCGv t0, TCGv t1, int flags) +{ + tcg_gen_qemu_ld_i64(t0, t1, flags, MO_LESL); + tcg_gen_mov_i64(cpu_lock_addr, t1); +#ifdef SW64_FIXLOCK + tcg_gen_ext32u_i64(cpu_lock_value, t0); +#endif +} + +static inline void gen_qemu_lldl(TCGv t0, TCGv t1, int flags) +{ + tcg_gen_qemu_ld_i64(t0, t1, flags, MO_LEQ); + tcg_gen_mov_i64(cpu_lock_addr, t1); +#ifdef SW64_FIXLOCK + tcg_gen_mov_i64(cpu_lock_value, t0); +#endif +} + +static DisasJumpType gen_store_conditional(DisasContext *ctx, int ra, int rb, + int32_t disp16, int mem_idx, + MemOp op) +{ + TCGLabel *lab_fail, *lab_done; + TCGv addr; + + addr = tcg_temp_new_i64(); + tcg_gen_addi_i64(addr, load_gir(ctx, rb), disp16); + free_context_temps(ctx); + + lab_fail = gen_new_label(); + lab_done = gen_new_label(); + tcg_gen_brcond_i64(TCG_COND_NE, addr, cpu_lock_addr, lab_fail); + tcg_temp_free_i64(addr); + +#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(0xc4, va); + break; + case 0x0080: + /* HALT */ +#ifndef CONFIG_USER_ONLY + { + tmp32 = tcg_const_i32(1); + tcg_gen_st_i32( + tmp32, cpu_env, + -offsetof(SW64CPU, env) + offsetof(CPUState, halted)); + tcg_temp_free_i32(tmp32); + } + ret = gen_excp(ctx, EXCP_HALTED, 0); +#endif + break; + case 0x1000: + /* RD_F */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE3)); + if (disp16 && unlikely(ra == 31)) break; + va = load_gir(ctx, ra); + tcg_gen_mov_i64(va, cpu_lock_success); + break; + case 0x1020: + /* WR_F */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE3)); + 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; + 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(); + /* FIXME: for debug + tcg_gen_movi_i64(tmp64, ra); + gen_helper_v_print(cpu_env, tmp64); + */ + tcg_gen_shri_i64(tmp64, cpu_fr[ra], 29); + tcg_gen_andi_i64(tmp64_0, tmp64, 0x3fffffffUL); + tcg_gen_shri_i64(tmp64, cpu_fr[ra], 62); + tcg_gen_shli_i64(tmp64, tmp64, 30); + tcg_gen_or_i64(tmp64_0, tmp64, tmp64_0); + tcg_gen_mov_i64(tmp64, tmp64_0); + tcg_gen_shli_i64(tmp64, tmp64, 32); + tcg_gen_or_i64(tmp64_0, tmp64_0, tmp64); + tcg_gen_mov_i64(cpu_fr[rc], tmp64_0); + tcg_gen_mov_i64(cpu_fr[rc + 32], cpu_fr[rc]); + tcg_gen_mov_i64(cpu_fr[rc + 64], cpu_fr[rc]); + tcg_gen_mov_i64(cpu_fr[rc + 96], cpu_fr[rc]); + /* FIXME: for debug + tcg_gen_movi_i64(tmp64, rb); + gen_helper_v_print(cpu_env, tmp64); + tcg_gen_movi_i64(tmp64, rc); + gen_helper_v_print(cpu_env, tmp64); + */ + tcg_temp_free(tmp64); + tcg_temp_free(tmp64_0); + break; + case 0x25: + /* VCPYF */ + for (i = 0; i < 128; i += 32) { + tcg_gen_mov_i64(cpu_fr[rc + i], cpu_fr[ra]); + } + break; + case 0x26: + /* VCONW */ + tmp64 = tcg_const_i64(ra << 8 | rb); + tmp64_0 = tcg_temp_new(); + vd = tcg_const_i64(rc); + tcg_gen_shri_i64(tmp64_0, cpu_fr[rd], 2); + tcg_gen_andi_i64(tmp64_0, tmp64_0, 0x7ul); + gen_helper_vconw(cpu_env, tmp64, vd, tmp64_0); + tcg_temp_free(tmp64_0); + tcg_temp_free(tmp64); + tcg_temp_free(vd); + break; + case 0x27: + /* VSHFW */ + tmp64 = tcg_const_i64(ra << 8 | rb); + vd = tcg_const_i64(rc); + gen_helper_vshfw(cpu_env, tmp64, vd, cpu_fr[rd]); + tcg_temp_free(tmp64); + tcg_temp_free(vd); + break; + case 0x28: + /* VCONS */ + tmp64 = tcg_const_i64(ra << 8 | rb); + tmp64_0 = tcg_temp_new(); + vd = tcg_const_i64(rc); + tcg_gen_shri_i64(tmp64_0, cpu_fr[rd], 2); + tcg_gen_andi_i64(tmp64_0, tmp64_0, 0x3ul); + gen_helper_vcond(cpu_env, tmp64, vd, tmp64_0); + tcg_temp_free(tmp64_0); + tcg_temp_free(tmp64); + tcg_temp_free(vd); + break; + case 0x29: + /* FIXME: VCOND maybe it's wrong in the instruction book + * that there are no temp. */ + tmp64 = tcg_const_i64(ra << 8 | rb); + tmp64_0 = tcg_temp_new(); + vd = tcg_const_i64(rc); + tcg_gen_shri_i64(tmp64_0, cpu_fr[rd], 3); + tcg_gen_andi_i64(tmp64_0, tmp64_0, 0x3ul); + gen_helper_vcond(cpu_env, tmp64, vd, tmp64_0); + tcg_temp_free(tmp64_0); + tcg_temp_free(tmp64); + tcg_temp_free(vd); + break; + 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, 1); + break; + case 0x25: + /* PRI_LD */ +#ifndef CONFIG_USER_ONLY + if ((insn >> 12) & 1) { + gen_load_mem(ctx, &gen_qemu_pri_ldl, ra, rb, disp12, 0, 1); + } else { + gen_load_mem(ctx, &gen_qemu_pri_ldw, ra, rb, disp12, 0, 1); + } +#endif + break; + case 0x26: + /* FLDS */ + gen_load_mem(ctx, &gen_qemu_flds, ra, rb, disp16, 1, 0); + break; + case 0x27: + /* FLDD */ + gen_load_mem(ctx, &tcg_gen_qemu_ld64, ra, rb, disp16, 1, 0); + break; + case 0x28: + /* STB */ + gen_store_mem(ctx, &tcg_gen_qemu_st8, ra, rb, disp16, 0, 0); + break; + case 0x29: + /* STH */ + gen_store_mem(ctx, &tcg_gen_qemu_st16, ra, rb, disp16, 0, 0); + break; + case 0x2a: + /* STW */ + gen_store_mem(ctx, &tcg_gen_qemu_st32, ra, rb, disp16, 0, 0); + break; + case 0x2b: + /* STL */ + gen_store_mem(ctx, &tcg_gen_qemu_st64, ra, rb, disp16, 0, 0); + break; + case 0x2c: + /* STL_U */ + gen_store_mem(ctx, &tcg_gen_qemu_st64, ra, rb, disp16, 0, 1); + break; + case 0x2d: + /* PRI_ST */ +#ifndef CONFIG_USER_ONLY + if ((insn >> 12) & 1) { + gen_store_mem(ctx, &gen_qemu_pri_stl, ra, rb, disp12, 0, 1); + } else { + gen_store_mem(ctx, &gen_qemu_pri_stw, ra, rb, disp12, 0, 1); + } +#endif + break; + case 0x2e: + /* FSTS */ + gen_store_mem(ctx, &gen_qemu_fsts, ra, rb, disp16, 1, 0); + break; + case 0x2f: + /* FSTD */ + gen_store_mem(ctx, &tcg_gen_qemu_st64, ra, rb, disp16, 1, 0); + break; + case 0x30: + /* BEQ */ + ret = gen_bcond(ctx, TCG_COND_EQ, ra, disp21, (uint64_t)-1); + break; + case 0x31: + /* BNE */ + ret = gen_bcond(ctx, TCG_COND_NE, ra, disp21, (uint64_t)-1); + break; + case 0x32: + /* BLT */ + ret = gen_bcond(ctx, TCG_COND_LT, ra, disp21, (uint64_t)-1); + break; + case 0x33: + /* BLE */ + ret = gen_bcond(ctx, TCG_COND_LE, ra, disp21, (uint64_t)-1); + break; + case 0x34: + /* BGT */ + ret = gen_bcond(ctx, TCG_COND_GT, ra, disp21, (uint64_t)-1); + break; + case 0x35: + /* BGE */ + ret = gen_bcond(ctx, TCG_COND_GE, ra, disp21, (uint64_t)-1); + break; + case 0x36: + /* BLBC */ + ret = gen_bcond(ctx, TCG_COND_EQ, ra, disp21, 1); + break; + case 0x37: + /* BLBS */ + ret = gen_bcond(ctx, TCG_COND_NE, ra, disp21, 1); + break; + case 0x38: + /* FBEQ */ + ret = gen_fbcond(ctx, TCG_COND_EQ, ra, disp21); + break; + case 0x39: + /* FBNE */ + ret = gen_fbcond(ctx, TCG_COND_NE, ra, disp21); + break; + case 0x3a: + /* FBLT */ + ret = gen_fbcond(ctx, TCG_COND_LT, ra, disp21); + break; + case 0x3b: + /* FBLE */ + ret = gen_fbcond(ctx, TCG_COND_LE, ra, disp21); + break; + case 0x3c: + /* FBGT */ + ret = gen_fbcond(ctx, TCG_COND_GT, ra, disp21); + break; + case 0x3d: + /* FBGE */ + ret = gen_fbcond(ctx, TCG_COND_GE, ra, disp21); + break; + case 0x3f: + /* LDIH */ + disp16 = ((uint32_t)disp16) << 16; + if (ra == 31) break; + va = load_gir(ctx, ra); + if (rb == 31) { + tcg_gen_movi_i64(va, disp16); + } else { + tcg_gen_addi_i64(va, load_gir(ctx, rb), (int64_t)disp16); + } + break; + case 0x3e: + /* LDI */ + if (ra == 31) break; + va = load_gir(ctx, ra); + if (rb == 31) { + tcg_gen_movi_i64(va, disp16); + } else { + tcg_gen_addi_i64(va, load_gir(ctx, rb), (int64_t)disp16); + } + break; + do_invalid: + default: + printf("ILLEGAL BELOW OPC[%x] insn[%08x]\n", opc, insn); + ret = gen_invalid(ctx); + } + return ret; +} +static void sw64_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cpu) +{ + DisasContext* ctx = container_of(dcbase, DisasContext, base); + CPUSW64State* env = cpu->env_ptr; /*init by instance_initfn*/ + + ctx->tbflags = ctx->base.tb->flags; + ctx->mem_idx = cpu_mmu_index(env, false); +#ifdef CONFIG_USER_ONLY + ctx->ir = cpu_std_ir; +#else + ctx->ir = (ctx->tbflags & ENV_FLAG_HM_MODE ? cpu_hm_ir : cpu_std_ir); +#endif + ctx->zero = NULL; +} + +static void sw64_tr_tb_start(DisasContextBase *db, CPUState *cpu) +{ +} + +static void sw64_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu) +{ + tcg_gen_insn_start(dcbase->pc_next); +} + +static void sw64_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu) +{ + DisasContext *ctx = container_of(dcbase, DisasContext, base); + CPUSW64State *env = cpu->env_ptr; + uint32_t insn; + + insn = cpu_ldl_code(env, ctx->base.pc_next & (~3UL)); + ctx->env = env; + ctx->base.pc_next += 4; + ctx->base.is_jmp = ctx->translate_one(dcbase, insn, cpu); + + free_context_temps(ctx); + translator_loop_temp_check(&ctx->base); +} + +/* FIXME:Linhainan */ +static void sw64_tr_tb_stop(DisasContextBase* dcbase, CPUState* cpu) { + DisasContext* ctx = container_of(dcbase, DisasContext, base); + + switch (ctx->base.is_jmp) { + case DISAS_NORETURN: + break; + case DISAS_TOO_MANY: + if (use_goto_tb(ctx, ctx->base.pc_next)) { + tcg_gen_goto_tb(0); + tcg_gen_movi_i64(cpu_pc, ctx->base.pc_next); + tcg_gen_exit_tb(ctx->base.tb,0); + } + /* FALLTHRU */ + case DISAS_PC_STALE: + tcg_gen_movi_i64(cpu_pc, ctx->base.pc_next); + /* FALLTHRU */ + case DISAS_PC_UPDATED: + if (!use_exit_tb(ctx)) { + tcg_gen_lookup_and_goto_ptr(); + break; + } + /* FALLTHRU */ + case DISAS_PC_UPDATED_NOCHAIN: + if (ctx->base.singlestep_enabled) { + /* FIXME: for gdb*/ + //gen_excp_1(EXCP_DEBUG, 0); + cpu_loop_exit(cpu); + } else { + tcg_gen_exit_tb(NULL,0); + } + break; + default: + g_assert_not_reached(); + } +} + +static void sw64_tr_disas_log(const DisasContextBase* dcbase, CPUState* cpu) { + SW64CPU* sc = SW64_CPU(cpu); + qemu_log("IN(%d): %s\n", sc->cid, + lookup_symbol(dcbase->pc_first)); + log_target_disas(cpu, dcbase->pc_first & (~0x3UL), dcbase->tb->size); +} + +static void init_transops(CPUState *cpu, DisasContext *dc) +{ + dc->translate_one = translate_one; +} + +void restore_state_to_opc(CPUSW64State* env, TranslationBlock* tb, + target_ulong* data) { + env->pc = data[0]; +} + +static const TranslatorOps sw64_trans_ops = { + .init_disas_context = sw64_tr_init_disas_context, + .tb_start = sw64_tr_tb_start, + .insn_start = sw64_tr_insn_start, + .translate_insn = sw64_tr_translate_insn, + .tb_stop = sw64_tr_tb_stop, + .disas_log = sw64_tr_disas_log, +}; + +void gen_intermediate_code(CPUState* cpu, TranslationBlock* tb, int max_insns) +{ + DisasContext dc; + init_transops(cpu, &dc); + translator_loop(&sw64_trans_ops, &dc.base, cpu, tb, max_insns); +} diff --git a/target/sw64/translate.h b/target/sw64/translate.h new file mode 100644 index 0000000000000000000000000000000000000000..13b32cc9406109ae7d4c2e90f5d5822b6fb24bb1 --- /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..0c14167fbf2a84f47329cbecc89c2c4db1a8164b --- /dev/null +++ b/tcg/sw64/tcg-target-con-set.h @@ -0,0 +1,41 @@ +/* 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) + +//gaoqing +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..c96729bb65dec32006c63491bed8dc85944fd64f --- /dev/null +++ b/tcg/sw64/tcg-target.c.inc @@ -0,0 +1,2332 @@ +/* + * Initial TCG Implementation for sw_64 + * + */ + +#include "../tcg-pool.c.inc" +#include "qemu/bitops.h" + +/* We're going to re-use TCGType in setting of the SF bit, which controls + the size of the operation performed. If we know the values match, it + makes things much cleaner. */ +QEMU_BUILD_BUG_ON(TCG_TYPE_I32 != 0 || TCG_TYPE_I64 != 1); +static const tcg_insn_unit *tb_ret_addr; + +#ifdef CONFIG_DEBUG_TCG +static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = { + "X0", "X1", "X2", "X3", "X4", "X5", "X6", "X7", + "X8", "X9", "X10", "X11", "X12", "X13", "X14", "fp", + "X16", "X17", "X18", "X19", "X20", "X21", "X22", "X23", + "X24", "X25", "X26", "X27", "X28", "X29", "Xsp", "X31", + + "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", + "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", + "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", + "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", +}; +#endif /* CONFIG_DEBUG_TCG */ + +static const int tcg_target_reg_alloc_order[] = { + /* TCG_REG_X9 qemu saved for AREG0*/ + TCG_REG_X10, TCG_REG_X11, TCG_REG_X12, TCG_REG_X13, TCG_REG_X14, + + TCG_REG_X0, TCG_REG_X1, TCG_REG_X2, TCG_REG_X3, TCG_REG_X4, + TCG_REG_X5, TCG_REG_X6, TCG_REG_X7, TCG_REG_X8, + + TCG_REG_X22, TCG_REG_X23, TCG_REG_X24, /*TCG_REG_X25, TCG_REG_X26, TCG_REG_X27, */ + + /* TCG_REG_SP=TCG_REG_X15 saved for system*/ + TCG_REG_X16, TCG_REG_X17, TCG_REG_X18, TCG_REG_X19, TCG_REG_X20, TCG_REG_X21, TCG_REG_X28, /* TCG_REG_X29, TCG_REG_X30, TCG_REG_X31 */ + + /* TCG_REG_TMP=TCG_REG_X27 reserved as temporary register */ + /* TCG_REG_TMP2=TCG_REG_X25 reserved as temporary register */ + /* TCG_REG_RA=TCG_REG_X26 reserved as temporary */ + /* TCG_REG_GP=TCG_REG_X29 gp saved for system*/ + /* TCG_REG_SP=TCG_REG_X30 sp saved for system*/ + /* TCG_REG_ZERO=TCG_REG_X31 zero saved for system*/ + + TCG_REG_F2, TCG_REG_F3, TCG_REG_F4, TCG_REG_F5, TCG_REG_F6, TCG_REG_F7, TCG_REG_F8, TCG_REG_F9, /* f2-f9 saved registers */ + /* TCG_VEC_TMP=TCG_REG_F10, TCG_VEC_TMP2=TCG_REG_F11, are saved as temporary */ + TCG_REG_F12, TCG_REG_F13, TCG_REG_F14, TCG_REG_F15, /* f10-f15 temporary registers */ + + TCG_REG_F22, TCG_REG_F23, TCG_REG_F24, TCG_REG_F25, TCG_REG_F26, TCG_REG_F27, TCG_REG_F28, TCG_REG_F29, TCG_REG_F30, /* f22-f30 temporary registers */ + /* TCG_REG_F31, zero saved for system */ + + TCG_REG_F16, TCG_REG_F17, TCG_REG_F18, TCG_REG_F19, TCG_REG_F20, TCG_REG_F21, /* input args */ + + TCG_REG_F0, TCG_REG_F1, /*output args */ +}; + +static const int tcg_target_call_iarg_regs[6] = { + TCG_REG_X16, TCG_REG_X17, TCG_REG_X18, TCG_REG_X19, TCG_REG_X20, TCG_REG_X21, +}; +static const int tcg_target_call_oarg_regs[1] = { + TCG_REG_X0, +}; + +#define TCG_REG_TMP TCG_REG_X27 +#define TCG_REG_TMP2 TCG_REG_X25 +#define TCG_FLOAT_TMP TCG_REG_F10 +#define TCG_FLOAT_TMP2 TCG_REG_F11 + +#define ALL_GENERAL_REGS 0xffffffffu +#define ALL_QLDST_REGS ALL_GENERAL_REGS +#define PUSH_SIZE ((15-9+1+1) * 8) +#define FRAME_SIZE \ + ((PUSH_SIZE \ + + TCG_STATIC_CALL_ARGS_SIZE \ + + CPU_TEMP_BUF_NLONGS * sizeof(long) \ + + TCG_TARGET_STACK_ALIGN - 1) \ + & ~(TCG_TARGET_STACK_ALIGN - 1)) + +/* We encode the format of the insn into the beginning of the name, so that + we can have the preprocessor help "typecheck" the insn vs the output + function. Arm didn't provide us with nice names for the formats, so we + use the section number of the architecture reference manual in which the + instruction group is described. */ +#define OPC_OP(x) ((( x ) & 0x3f) << 26) +#define OPC_FUNC(x) ((( x ) & 0xff) << 5) +#define OPC_FUNC_COMPLEX(x) ((( x ) & 0xff) << 10) +typedef enum { + OPC_NOP =0X43ff075f, + OPC_SYS_CALL =OPC_OP(0x00), + OPC_CALL =OPC_OP(0x01), + OPC_RET =OPC_OP(0x02), + OPC_JMP =OPC_OP(0x03), + OPC_BR =OPC_OP(0x04), + OPC_BSR =OPC_OP(0x05), + OPC_PRI_RET =OPC_OP(0x07), + OPC_LDWE =OPC_OP(0x09), + OPC_LDSE =OPC_OP(0x0A), + OPC_LDDE =OPC_OP(0x0B), + OPC_VLDS =OPC_OP(0x0C), + OPC_VLDD =OPC_OP(0x0D), + OPC_VSTS =OPC_OP(0x0E), + OPC_VSTD =OPC_OP(0x0F), + + OPC_LDBU =OPC_OP(0x20), + OPC_LDHU =OPC_OP(0x21), + OPC_LDW =OPC_OP(0x22), + OPC_LDL =OPC_OP(0x23), + OPC_LDL_U =OPC_OP(0x24), + OPC_FLDS =OPC_OP(0X26), + OPC_PRI_LD =OPC_OP(0x25), + OPC_FLDD =OPC_OP(0X27), + OPC_STB =OPC_OP(0X28), + OPC_STH =OPC_OP(0x29), + OPC_STW =OPC_OP(0x2a), + OPC_STL =OPC_OP(0x2B), + OPC_STL_U =OPC_OP(0x2C), + OPC_PRI_ST =OPC_OP(0x2D), + OPC_FSTS =OPC_OP(0x2E), + OPC_FSTD =OPC_OP(0x2F), + + OPC_BEQ =OPC_OP(0x30), + OPC_BNE =OPC_OP(0x31), + OPC_BLT =OPC_OP(0x32), + OPC_BLE =OPC_OP(0x33), + OPC_BGT =OPC_OP(0x34), + OPC_BGE =OPC_OP(0x35), + OPC_BLBC =OPC_OP(0x36), + OPC_BLBS =OPC_OP(0x37), + + OPC_FBEQ =OPC_OP(0x38), + OPC_FBNE =OPC_OP(0x39), + OPC_FBLT =OPC_OP(0x3A), + OPC_FBLE =OPC_OP(0x3B), + OPC_FBGT =OPC_OP(0x3C), + OPC_FBGE =OPC_OP(0x3D), + OPC_LDI =OPC_OP(0x3E), + OPC_LDIH =OPC_OP(0x3F), + + OPC_ADDW =(OPC_OP(0x10) | OPC_FUNC(0x0)), + OPC_ADDW_I =(OPC_OP(0x12) | OPC_FUNC(0x0)), + OPC_SUBW =(OPC_OP(0x10) | OPC_FUNC(0x1)), + OPC_SUBW_I =(OPC_OP(0x12) | OPC_FUNC(0x1)), + OPC_S4ADDW =(OPC_OP(0x10) | OPC_FUNC(0x02)), + OPC_S4ADDW_I =(OPC_OP(0x12) | OPC_FUNC(0x02)), + OPC_S4SUBW =(OPC_OP(0x10) | OPC_FUNC(0x03)), + OPC_S4SUBW_I =(OPC_OP(0x12) | OPC_FUNC(0x03)), + + OPC_S8ADDW =(OPC_OP(0x10) | OPC_FUNC(0x04)), + OPC_S8ADDW_I =(OPC_OP(0x12) | OPC_FUNC(0x04)), + OPC_S8SUBW =(OPC_OP(0x10) | OPC_FUNC(0x05)), + OPC_S8SUBW_I =(OPC_OP(0x12) | OPC_FUNC(0x05)), + + OPC_ADDL =(OPC_OP(0x10) | OPC_FUNC(0x8)), + OPC_ADDL_I =(OPC_OP(0x12) | OPC_FUNC(0x8)), + OPC_SUBL =(OPC_OP(0x10) | OPC_FUNC(0x9)), + OPC_SUBL_I =(OPC_OP(0x12) | OPC_FUNC(0x9)), + + OPC_S4ADDL =(OPC_OP(0x10) | OPC_FUNC(0xA)), + OPC_S4ADDL_I =(OPC_OP(0x12) | OPC_FUNC(0xA)), + OPC_S4SUBL =(OPC_OP(0x10) | OPC_FUNC(0xB)), + OPC_S4SUBL_I =(OPC_OP(0x12) | OPC_FUNC(0xB)), + + OPC_S8ADDL =(OPC_OP(0x10) | OPC_FUNC(0xC)), + OPC_S8ADDL_I =(OPC_OP(0x12) | OPC_FUNC(0xC)), + OPC_S8SUBL =(OPC_OP(0x10) | OPC_FUNC(0xD)), + OPC_S8SUBL_I =(OPC_OP(0x12) | OPC_FUNC(0xD)), + + OPC_MULW =(OPC_OP(0x10) | OPC_FUNC(0x10)), + OPC_MULW_I =(OPC_OP(0x12) | OPC_FUNC(0x10)), + OPC_MULL =(OPC_OP(0x10) | OPC_FUNC(0x18)), + OPC_MULL_I =(OPC_OP(0x12) | OPC_FUNC(0x18)), + + OPC_UMULH =(OPC_OP(0x10) | OPC_FUNC(0x19)), + OPC_UMULH_I =(OPC_OP(0x12) | OPC_FUNC(0x19)), + + OPC_CTPOP =(OPC_OP(0x10) | OPC_FUNC(0x58)), + OPC_CTLZ =(OPC_OP(0x10) | OPC_FUNC(0x59)), + OPC_CTTZ =(OPC_OP(0x10) | OPC_FUNC(0x5A)), + + OPC_ZAP =(OPC_OP(0x10) | OPC_FUNC(0x68)), + OPC_ZAP_I =(OPC_OP(0x12) | OPC_FUNC(0x68)), + OPC_ZAPNOT =(OPC_OP(0x10) | OPC_FUNC(0x69)), + OPC_ZAPNOT_I =(OPC_OP(0x12) | OPC_FUNC(0x69)), + + OPC_SEXTB =(OPC_OP(0x10) | OPC_FUNC(0x6A)), + OPC_SEXTB_I =(OPC_OP(0x12) | OPC_FUNC(0x6A)), + OPC_SEXTH =(OPC_OP(0x10) | OPC_FUNC(0x6B)), + OPC_SEXTH_I =(OPC_OP(0x12) | OPC_FUNC(0x6B)), + + OPC_CMPEQ =(OPC_OP(0x10) | OPC_FUNC(0x28)), + OPC_CMPEQ_I =(OPC_OP(0x12) | OPC_FUNC(0x28)), + + OPC_CMPLT =(OPC_OP(0x10) | OPC_FUNC(0x29)), + OPC_CMPLT_I =(OPC_OP(0x12) | OPC_FUNC(0x29)), + OPC_CMPLE =(OPC_OP(0x10) | OPC_FUNC(0x2A)), + OPC_CMPLE_I =(OPC_OP(0x12) | OPC_FUNC(0x2A)), + + OPC_CMPULT =(OPC_OP(0x10) | OPC_FUNC(0x2B)), + OPC_CMPULT_I =(OPC_OP(0x12) | OPC_FUNC(0x2B)), + OPC_CMPULE =(OPC_OP(0x10) | OPC_FUNC(0x2C)), + OPC_CMPULE_I =(OPC_OP(0x12) | OPC_FUNC(0x2C)), + + OPC_AND =(OPC_OP(0x10) | OPC_FUNC(0x38)), + OPC_BIC =(OPC_OP(0x10) | OPC_FUNC(0x39)), + OPC_BIS =(OPC_OP(0x10) | OPC_FUNC(0x3A)), + OPC_ORNOT =(OPC_OP(0x10) | OPC_FUNC(0x3B)), + OPC_XOR =(OPC_OP(0x10) | OPC_FUNC(0x3C)), + OPC_EQV =(OPC_OP(0x10) | OPC_FUNC(0x3D)), + + OPC_AND_I =(OPC_OP(0x12) | OPC_FUNC(0x38)), + OPC_BIC_I =(OPC_OP(0x12) | OPC_FUNC(0x39)), + OPC_BIS_I =(OPC_OP(0x12) | OPC_FUNC(0x3A)), + OPC_ORNOT_I =(OPC_OP(0x12) | OPC_FUNC(0x3B)), + OPC_XOR_I =(OPC_OP(0x12) | OPC_FUNC(0x3C)), + OPC_EQV_I =(OPC_OP(0x12) | OPC_FUNC(0x3D)), + + OPC_SLL =(OPC_OP(0x10) | OPC_FUNC(0x48)), + OPC_SRL =(OPC_OP(0x10) | OPC_FUNC(0x49)), + OPC_SRA =(OPC_OP(0x10) | OPC_FUNC(0x4A)), + OPC_SLL_I =(OPC_OP(0x12) | OPC_FUNC(0x48)), + OPC_SRL_I =(OPC_OP(0x12) | OPC_FUNC(0x49)), + OPC_SRA_I =(OPC_OP(0x12) | OPC_FUNC(0x4A)), + + OPC_SELEQ =(OPC_OP(0x11) | OPC_FUNC_COMPLEX(0x00)), + OPC_SELGE =(OPC_OP(0x11) | OPC_FUNC_COMPLEX(0x01)), + OPC_SELGT =(OPC_OP(0x11) | OPC_FUNC_COMPLEX(0x02)), + OPC_SELLE =(OPC_OP(0x11) | OPC_FUNC_COMPLEX(0x03)), + OPC_SELLT =(OPC_OP(0x11) | OPC_FUNC_COMPLEX(0x04)), + OPC_SELNE =(OPC_OP(0x11) | OPC_FUNC_COMPLEX(0x05)), + OPC_SELLBC =(OPC_OP(0x11) | OPC_FUNC_COMPLEX(0x06)), + OPC_SELLBS =(OPC_OP(0x11) | OPC_FUNC_COMPLEX(0x07)), + OPC_SELEQ_I =(OPC_OP(0x13) | OPC_FUNC_COMPLEX(0x00)), + OPC_SELGE_I =(OPC_OP(0x13) | OPC_FUNC_COMPLEX(0x01)), + OPC_SELGT_I =(OPC_OP(0x13) | OPC_FUNC_COMPLEX(0x02)), + OPC_SELLE_I =(OPC_OP(0x13) | OPC_FUNC_COMPLEX(0x03)), + OPC_SELLT_I =(OPC_OP(0x13) | OPC_FUNC_COMPLEX(0x04)), + OPC_SELNE_I =(OPC_OP(0x13) | OPC_FUNC_COMPLEX(0x05)), + OPC_SELLBC_I =(OPC_OP(0x13) | OPC_FUNC_COMPLEX(0x06)), + OPC_SELLBS_I =(OPC_OP(0x13) | OPC_FUNC_COMPLEX(0x07)), + + OPC_INS0B =(OPC_OP(0x10) | OPC_FUNC(0x40)), + OPC_INS1B =(OPC_OP(0x10) | OPC_FUNC(0x41)), + OPC_INS2B =(OPC_OP(0x10) | OPC_FUNC(0x42)), + OPC_INS3B =(OPC_OP(0x10) | OPC_FUNC(0x43)), + OPC_INS4B =(OPC_OP(0x10) | OPC_FUNC(0x44)), + OPC_INS5B =(OPC_OP(0x10) | OPC_FUNC(0x45)), + OPC_INS6B =(OPC_OP(0x10) | OPC_FUNC(0x46)), + OPC_INS7B =(OPC_OP(0x10) | OPC_FUNC(0x47)), + OPC_INS0B_I =(OPC_OP(0x12) | OPC_FUNC(0x40)), + OPC_INS1B_I =(OPC_OP(0x12) | OPC_FUNC(0x41)), + OPC_INS2B_I =(OPC_OP(0x12) | OPC_FUNC(0x42)), + OPC_INS3B_I =(OPC_OP(0x12) | OPC_FUNC(0x43)), + OPC_INS4B_I =(OPC_OP(0x12) | OPC_FUNC(0x44)), + OPC_INS5B_I =(OPC_OP(0x12) | OPC_FUNC(0x45)), + OPC_INS6B_I =(OPC_OP(0x12) | OPC_FUNC(0x46)), + OPC_INS7B_I =(OPC_OP(0x12) | OPC_FUNC(0x47)), + + OPC_EXT0B =(OPC_OP(0x10) | OPC_FUNC(0x50)), + OPC_EXT1B =(OPC_OP(0x10) | OPC_FUNC(0x51)), + OPC_EXT2B =(OPC_OP(0x10) | OPC_FUNC(0x52)), + OPC_EXT3B =(OPC_OP(0x10) | OPC_FUNC(0x53)), + OPC_EXT4B =(OPC_OP(0x10) | OPC_FUNC(0x54)), + OPC_EXT5B =(OPC_OP(0x10) | OPC_FUNC(0x55)), + OPC_EXT6B =(OPC_OP(0x10) | OPC_FUNC(0x56)), + OPC_EXT7B =(OPC_OP(0x10) | OPC_FUNC(0x57)), + OPC_EXT0B_I =(OPC_OP(0x12) | OPC_FUNC(0x50)), + OPC_EXT1B_I =(OPC_OP(0x12) | OPC_FUNC(0x51)), + OPC_EXT2B_I =(OPC_OP(0x12) | OPC_FUNC(0x52)), + OPC_EXT3B_I =(OPC_OP(0x12) | OPC_FUNC(0x53)), + OPC_EXT4B_I =(OPC_OP(0x12) | OPC_FUNC(0x54)), + OPC_EXT5B_I =(OPC_OP(0x12) | OPC_FUNC(0x55)), + OPC_EXT6B_I =(OPC_OP(0x12) | OPC_FUNC(0x56)), + OPC_EXT7B_I =(OPC_OP(0x12) | OPC_FUNC(0x57)), + + OPC_MASK0B =(OPC_OP(0x10) | OPC_FUNC(0x60)), + OPC_MASK1B =(OPC_OP(0x10) | OPC_FUNC(0x61)), + OPC_MASK2B =(OPC_OP(0x10) | OPC_FUNC(0x62)), + OPC_MASK3B =(OPC_OP(0x10) | OPC_FUNC(0x63)), + OPC_MASK4B =(OPC_OP(0x10) | OPC_FUNC(0x64)), + OPC_MASK5B =(OPC_OP(0x10) | OPC_FUNC(0x65)), + OPC_MASK6B =(OPC_OP(0x10) | OPC_FUNC(0x66)), + OPC_MASK7B =(OPC_OP(0x10) | OPC_FUNC(0x67)), + OPC_MASK0B_I =(OPC_OP(0x12) | OPC_FUNC(0x60)), + OPC_MASK1B_I =(OPC_OP(0x12) | OPC_FUNC(0x61)), + OPC_MASK2B_I =(OPC_OP(0x12) | OPC_FUNC(0x62)), + OPC_MASK3B_I =(OPC_OP(0x12) | OPC_FUNC(0x63)), + OPC_MASK4B_I =(OPC_OP(0x12) | OPC_FUNC(0x64)), + OPC_MASK5B_I =(OPC_OP(0x12) | OPC_FUNC(0x65)), + OPC_MASK6B_I =(OPC_OP(0x12) | OPC_FUNC(0x66)), + OPC_MASK7B_I =(OPC_OP(0x12) | OPC_FUNC(0x67)), + + OPC_CNPGEB =(OPC_OP(0x10) | OPC_FUNC(0x6C)), + OPC_CNPGEB_I =(OPC_OP(0x12) | OPC_FUNC(0x6C)), + + OPC_MEMB =(OPC_OP(0x06) | OPC_FUNC(0x0)), + OPC_RTC =(OPC_OP(0x06) | OPC_FUNC(0x20)), + + /*float insn*/ + OPC_RFPCR = (OPC_OP(0x18) | OPC_FUNC(0x50)), + OPC_WFPCR = (OPC_OP(0x18) | OPC_FUNC(0x51)), + OPC_SETFPEC0 = (OPC_OP(0x18) | OPC_FUNC(0x54)), + OPC_SETFPEC1 = (OPC_OP(0x18) | OPC_FUNC(0x55)), + OPC_SETFPEC2 = (OPC_OP(0x18) | OPC_FUNC(0x56)), + OPC_SETFPEC3 = (OPC_OP(0x18) | OPC_FUNC(0x57)), + + + OPC_IFMOVS = (OPC_OP(0x18) | OPC_FUNC(0x40)), + OPC_IFMOVD = (OPC_OP(0x18) | OPC_FUNC(0x41)), + OPC_FIMOVS = (OPC_OP(0x10) | OPC_FUNC(0x70)), + OPC_FIMOVD = (OPC_OP(0x10) | OPC_FUNC(0x78)), + + /*translate S--D*/ + /*translate S/D--Long*/ + OPC_FCVTSD = (OPC_OP(0x18) | OPC_FUNC(0x20)), + OPC_FCVTDS = (OPC_OP(0x18) | OPC_FUNC(0x21)), + OPC_FCVTDL_G = (OPC_OP(0x18) | OPC_FUNC(0x22)), + OPC_FCVTDL_P = (OPC_OP(0x18) | OPC_FUNC(0x23)), + OPC_FCVTDL_Z = (OPC_OP(0x18) | OPC_FUNC(0x24)), + OPC_FCVTDL_N = (OPC_OP(0x18) | OPC_FUNC(0x25)), + OPC_FCVTDL = (OPC_OP(0x18) | OPC_FUNC(0x27)), + OPC_FCVTLS = (OPC_OP(0x18) | OPC_FUNC(0x2D)), + OPC_FCVTLD = (OPC_OP(0x18) | OPC_FUNC(0x2F)), + + + OPC_FADDS = (OPC_OP(0x18) | OPC_FUNC(0x00)), + OPC_FADDD = (OPC_OP(0x18) | OPC_FUNC(0x01)), + OPC_FSUBS = (OPC_OP(0x18) | OPC_FUNC(0x02)), + OPC_FSUBD = (OPC_OP(0x18) | OPC_FUNC(0x03)), + OPC_FMULS = (OPC_OP(0x18) | OPC_FUNC(0x04)), + OPC_FMULD = (OPC_OP(0x18) | OPC_FUNC(0x05)), + OPC_FDIVS = (OPC_OP(0x18) | OPC_FUNC(0x06)), + OPC_FDIVD = (OPC_OP(0x18) | OPC_FUNC(0x07)), + OPC_FSQRTS = (OPC_OP(0x18) | OPC_FUNC(0x08)), + OPC_FSQRTD = (OPC_OP(0x18) | OPC_FUNC(0x09)), +}SW_64Insn; + +//static void tcg_out_insn_syscall(TCGContext *s, SW_64Insn insn, intptr_t imm26); +static void tcg_out_insn_br(TCGContext *s, SW_64Insn insn, TCGReg rd, intptr_t imm64); +static void tcg_out_insn_ldst(TCGContext *s, SW_64Insn insn, TCGReg rd, TCGReg rn, intptr_t imm16); +static void tcg_out_insn_simpleReg(TCGContext *s, SW_64Insn insn,TCGReg rd, TCGReg rn, TCGReg rm); +static void tcg_out_insn_simple(TCGContext *s, SW_64Insn insn_Imm, SW_64Insn insn_Reg, TCGReg rd, TCGReg rn, intptr_t imm64); +static void tcg_out_insn_simpleImm(TCGContext *s, SW_64Insn insn_Imm, TCGReg rd, TCGReg rn, intptr_t imm64); +static void tcg_out_insn_bitImm(TCGContext *s, SW_64Insn insn_Imm, TCGReg rd, TCGReg rn, unsigned long imm64); +static void tcg_out_insn_bit(TCGContext *s, SW_64Insn insn_Imm, SW_64Insn insn_Reg, TCGReg rd, TCGReg rn, unsigned long imm64); +static void tcg_out_insn_complexReg(TCGContext *s, SW_64Insn insn,TCGReg cond, TCGReg rd, TCGReg rn, TCGReg rm); +//static void tcg_out_insn_complexImm(TCGContext *s, SW_64Insn insn, TCGReg cond, TCGReg rd, intptr_t imm8, TCGReg rm); +static void tcg_out_movcond(TCGContext *s, TCGCond cond, TCGReg ret,TCGReg a1,TCGReg a2, bool const_b, TCGReg v1, TCGReg v2); +static bool reloc_pc21(tcg_insn_unit *src_rw, const tcg_insn_unit *target); +static inline uint32_t tcg_in32(TCGContext *s); +static void tcg_out_movr(TCGContext *s, TCGType ext, TCGReg rd, TCGReg rn); +static void tcg_out_ldst(TCGContext *s, SW_64Insn insn, TCGReg rd, TCGReg rn, intptr_t offset, bool sign); +static void tcg_out_cond_cmp(TCGContext *s, TCGCond cond, TCGReg ret, TCGArg a, TCGArg b, bool const_b); +static void tcg_out_addsubi(TCGContext *s, int ext, TCGReg rd,TCGReg rn, int64_t aimm); +static inline void tcg_out_extr(TCGContext *s, TCGType ext, TCGReg rd, TCGReg rn, TCGReg rm, unsigned int m); +static inline void tcg_out_rotl_Reg(TCGContext *s, TCGType ext, TCGReg rd, TCGReg rn, TCGReg rm); +static inline void tcg_out_rotr_Reg(TCGContext *s, TCGType ext, TCGReg rd, TCGReg rn, TCGReg rm); +static inline void tcg_out_rotl_Imm(TCGContext *s, TCGType ext, TCGReg rd, TCGReg rn, unsigned int m); +static inline void tcg_out_rotr_Imm(TCGContext *s, TCGType ext, TCGReg rd, TCGReg rn, unsigned int m); +static void tcg_out_cltz(TCGContext *s, SW_64Insn opc_clz, TCGType ext, TCGReg rd, TCGReg rn, TCGArg b, bool const_b); +static inline void tcg_out_bswap16u(TCGContext *s, TCGReg rd, TCGReg rn); +static inline void tcg_out_bswap16s(TCGContext *s, TCGReg rd, TCGReg rn); +static inline void tcg_out_bswap32u(TCGContext *s, TCGReg rd, TCGReg rn); +static inline void tcg_out_bswap32s(TCGContext *s, TCGReg rd, TCGReg rn); +static inline void tcg_out_bswap64(TCGContext *s, TCGReg rd, TCGReg rn); +static void tcg_out_qemu_st(TCGContext *s, TCGReg data_reg, TCGReg addr_reg, MemOpIdx oi); +static void tcg_out_qemu_ld(TCGContext *s, TCGReg data_reg, TCGReg addr_reg, MemOpIdx oi, TCGType ext); +static void tcg_out_setcond(TCGContext *s, TCGCond cond, TCGReg ret,TCGReg arg1, TCGReg arg2); +static void tcg_out_extract(TCGContext *s, TCGReg rd, TCGReg rn, int pos, int len); +static void tcg_out_dep(TCGContext *s, TCGReg rd, TCGReg rn, int pos, int len); +static void tcg_out_mulsh64(TCGContext *s, TCGReg rd, TCGReg rn, TCGReg rm); +//static void tcg_out_div32(TCGContext *s, TCGReg rd, TCGReg rn, TCGReg rm); +//static void tcg_out_addsub2(TCGContext *s, TCGType ext, TCGReg rl, TCGReg rh, TCGReg al, TCGReg ah, tcg_target_long bl, tcg_target_long bh, bool const_bl, bool const_bh, bool sub); + +#define tcg_out_insn_jump tcg_out_insn_ldst +#define tcg_out_insn_bitReg tcg_out_insn_simpleReg + +/* SW */ +static void tcg_target_init(TCGContext *s) +{ + tcg_target_available_regs[TCG_TYPE_I32] = 0xffffffffu; + tcg_target_available_regs[TCG_TYPE_I64] = 0xffffffffu; + tcg_target_available_regs[TCG_TYPE_V64] = 0xffffffff00000000ull; + tcg_target_available_regs[TCG_TYPE_V128] = 0xffffffff00000000ull; + tcg_target_call_clobber_regs = -1ull; + + //sw_64 callee saved x9-x15 + tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_X9); + tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_X10); + tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_X11); + tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_X12); + tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_X13); + tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_X14); + tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_X15); + + //sw_64 callee saved f2~f9 + tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_F2); + tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_F3); + tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_F4); + tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_F5); + tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_F6); + tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_F7); + tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_F8); + tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_F9); + + s->reserved_regs = 0; + tcg_regset_set_reg(s->reserved_regs, TCG_REG_SP); + tcg_regset_set_reg(s->reserved_regs, TCG_REG_FP); + tcg_regset_set_reg(s->reserved_regs, TCG_REG_TMP); //TCG_REG_X27 + tcg_regset_set_reg(s->reserved_regs, TCG_REG_TMP2); //TCG_REG_X25 + tcg_regset_set_reg(s->reserved_regs, TCG_REG_RA); //TCG_REG_X26 + tcg_regset_set_reg(s->reserved_regs, TCG_REG_X29); /*sw_64 platform register */ + tcg_regset_set_reg(s->reserved_regs, TCG_FLOAT_TMP); /*sw_64 platform register */ + tcg_regset_set_reg(s->reserved_regs, TCG_FLOAT_TMP2); /*sw_64 platform register */ +} + + +#ifndef CONFIG_SOFTMMU + #define USE_GUEST_BASE guest_base != 0 + #define TCG_REG_GUEST_BASE TCG_REG_X14 +#endif + + +#define zeroExt 0 +#define sigExt 1 + + +/* SW */ +static void tcg_target_qemu_prologue(TCGContext *s) +{ + TCGReg r; + int ofs; + + /* allocate space for all saved registers */ + /* subl $sp,PUSH_SIZE,$sp */ + tcg_out_insn_simple(s, OPC_SUBL_I, OPC_SUBL, TCG_REG_SP, TCG_REG_SP, PUSH_SIZE); + + /* Push (FP, LR) */ + /* stl $fp,0($sp) */ + tcg_out_insn_ldst(s, OPC_STL, TCG_REG_FP, TCG_REG_SP, 0); + /* stl $26,8($sp) */ + tcg_out_insn_ldst(s, OPC_STL, TCG_REG_RA, TCG_REG_SP, 8); + + + /* Set up frame pointer for canonical unwinding. */ + /* TCG_REG_FP=TCG_REG_SP */ + tcg_out_movr(s, TCG_TYPE_I64, TCG_REG_FP, TCG_REG_SP); + + /* Store callee-preserved regs x9..x14. */ + for (r = TCG_REG_X9; r <= TCG_REG_X14; r += 1){ + ofs = (r - TCG_REG_X9 + 2) * 8; + tcg_out_insn_ldst(s, OPC_STL, r, TCG_REG_SP, ofs); + } + + /* Make stack space for TCG locals. */ + /* subl $sp,FRAME_SIZE-PUSH_SIZE,$sp */ + tcg_out_insn_simple(s, OPC_SUBL_I, OPC_SUBL, TCG_REG_SP, TCG_REG_SP, FRAME_SIZE - PUSH_SIZE); + + /* Inform TCG about how to find TCG locals with register, offset, size. */ + tcg_set_frame(s, TCG_REG_SP, TCG_STATIC_CALL_ARGS_SIZE, + CPU_TEMP_BUF_NLONGS * sizeof(long)); + +#if !defined(CONFIG_SOFTMMU) + if (USE_GUEST_BASE) { + tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_GUEST_BASE, guest_base); + tcg_regset_set_reg(s->reserved_regs, TCG_REG_GUEST_BASE); + } +#endif + + /* TCG_AREG0=tcg_target_call_iarg_regs[0], on sw, we mov $16 to $9 */ + tcg_out_mov(s, TCG_TYPE_I64, TCG_AREG0, tcg_target_call_iarg_regs[0]); + tcg_out_insn_jump(s, OPC_JMP, TCG_REG_ZERO, tcg_target_call_iarg_regs[1], 0); + + /* + * Return path for goto_ptr. Set return value to 0, a-la exit_tb, + * and fall through to the rest of the epilogue. + */ + tcg_code_gen_epilogue = tcg_splitwx_to_rx(s->code_ptr); + tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_X0, 0); + + /* TB epilogue */ + tb_ret_addr = tcg_splitwx_to_rx(s->code_ptr); + + /* Remove TCG locals stack space. */ + /* addl $sp,FRAME_SIZE-PUSH_SIZE,$sp */ + tcg_out_insn_simple(s, OPC_ADDL_I, OPC_ADDL, TCG_REG_SP, TCG_REG_SP, FRAME_SIZE - PUSH_SIZE); + + /* Restore registers x9..x14. */ + for (r = TCG_REG_X9; r <= TCG_REG_X14; r += 1) { + int ofs = (r - TCG_REG_X9 + 2) * 8; + tcg_out_insn_ldst(s, OPC_LDL, r, TCG_REG_SP, ofs); + } + + + /* Pop (FP, LR) */ + /* ldl $fp,0($sp) */ + tcg_out_insn_ldst(s, OPC_LDL, TCG_REG_FP, TCG_REG_SP, 0); + /* ldl $26,8($sp) */ + tcg_out_insn_ldst(s, OPC_LDL, TCG_REG_RA, TCG_REG_SP, 8); + + /* restore SP to previous frame. */ + /* addl $sp,PUSH_SIZE,$sp */ + tcg_out_insn_simple(s, OPC_ADDL_I, OPC_ADDL, TCG_REG_SP, TCG_REG_SP, PUSH_SIZE); + + tcg_out_insn_jump(s, OPC_RET, TCG_REG_ZERO, TCG_REG_RA, 0); +} + +static bool tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg) +{ + if (ret == arg) { + return true; + } + switch (type) { + case TCG_TYPE_I32: + case TCG_TYPE_I64: + if (ret < 32 && arg < 32) { + tcg_out_movr(s, type, ret, arg); + break; + } else if (ret < 32) { + // tcg_out_insn(s, 3605, UMOV, type, ret, arg, 0, 0); + break; + } else if (arg < 32) { +// tcg_out_insn(s, 3605, INS, 0, ret, arg, 4 << type, 0); + break; + } + /* FALLTHRU */ + +/* case TCG_TYPE_V64: + tcg_debug_assert(ret >= 32 && arg >= 32); + tcg_out_insn(s, 3616, ORR, 0, 0, ret, arg, arg); + break; + case TCG_TYPE_V128: + tcg_debug_assert(ret >= 32 && arg >= 32); + tcg_out_insn(s, 3616, ORR, 1, 0, ret, arg, arg); + break; +*/ + default: + g_assert_not_reached(); + } + return true; +} + + +static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op) +{ + switch (op) { + case INDEX_op_goto_ptr: + return C_O0_I1(r); + + case INDEX_op_ld8u_i32: + case INDEX_op_ld8s_i32: + case INDEX_op_ld16u_i32: + case INDEX_op_ld16s_i32: + case INDEX_op_ld_i32: + case INDEX_op_ld8u_i64: + case INDEX_op_ld8s_i64: + case INDEX_op_ld16u_i64: + case INDEX_op_ld16s_i64: + case INDEX_op_ld32u_i64: + case INDEX_op_ld32s_i64: + case INDEX_op_ld_i64: + case INDEX_op_neg_i32: + case INDEX_op_neg_i64: + case INDEX_op_not_i32: + case INDEX_op_not_i64: + case INDEX_op_bswap16_i32: + case INDEX_op_bswap32_i32: + case INDEX_op_bswap16_i64: + case INDEX_op_bswap32_i64: + case INDEX_op_bswap64_i64: + case INDEX_op_ext8s_i32: + case INDEX_op_ext16s_i32: + case INDEX_op_ext8u_i32: + case INDEX_op_ext16u_i32: + case INDEX_op_ext8s_i64: + case INDEX_op_ext16s_i64: + case INDEX_op_ext32s_i64: + case INDEX_op_ext8u_i64: + case INDEX_op_ext16u_i64: + case INDEX_op_ext32u_i64: + case INDEX_op_ext_i32_i64: + case INDEX_op_extu_i32_i64: + case INDEX_op_extract_i32: + case INDEX_op_extract_i64: + case INDEX_op_sextract_i32: + case INDEX_op_sextract_i64: + return C_O1_I1(r, r); + + case INDEX_op_st8_i32: + case INDEX_op_st16_i32: + case INDEX_op_st_i32: + case INDEX_op_st8_i64: + case INDEX_op_st16_i64: + case INDEX_op_st32_i64: + case INDEX_op_st_i64: + return C_O0_I2(rZ, r); + + case INDEX_op_add_i32: + case INDEX_op_add_i64: + case INDEX_op_sub_i32: + case INDEX_op_sub_i64: + return C_O1_I2(r, r, rU);//gaoqing,rA + + case INDEX_op_setcond_i32: + case INDEX_op_setcond_i64: + return C_O1_I2(r, r, rU);//compare,gaoqing,rA + + case INDEX_op_mul_i32: + case INDEX_op_mul_i64: + case INDEX_op_div_i32: + case INDEX_op_div_i64: + case INDEX_op_divu_i32: + case INDEX_op_divu_i64: + case INDEX_op_rem_i32: + case INDEX_op_rem_i64: + case INDEX_op_remu_i32: + case INDEX_op_remu_i64: + case INDEX_op_muluh_i64: + case INDEX_op_mulsh_i64: + return C_O1_I2(r, r, r); + + case INDEX_op_and_i32: + case INDEX_op_and_i64: + case INDEX_op_or_i32: + case INDEX_op_or_i64: + case INDEX_op_xor_i32: + case INDEX_op_xor_i64: + case INDEX_op_andc_i32: + case INDEX_op_andc_i64: + case INDEX_op_orc_i32: + case INDEX_op_orc_i64: + case INDEX_op_eqv_i32: + case INDEX_op_eqv_i64: + return C_O1_I2(r, r, rU);//gaoqing,rL + + case INDEX_op_shl_i32: + case INDEX_op_shr_i32: + case INDEX_op_sar_i32: + case INDEX_op_rotl_i32: + case INDEX_op_rotr_i32: + case INDEX_op_shl_i64: + case INDEX_op_shr_i64: + case INDEX_op_sar_i64: + case INDEX_op_rotl_i64: + case INDEX_op_rotr_i64: + return C_O1_I2(r, r, ri); + + case INDEX_op_clz_i32: + case INDEX_op_clz_i64: + return C_O1_I2(r, r, r);//gaoqing rAL + + case INDEX_op_ctz_i32: + case INDEX_op_ctz_i64: + return C_O1_I2(r, r, r);//gaoqing rAL + + case INDEX_op_brcond_i32: + case INDEX_op_brcond_i64: + return C_O0_I2(r, rU);//gaoqing rA + + case INDEX_op_movcond_i32: + case INDEX_op_movcond_i64: + return C_O1_I4(r, r, rU, rZ, rZ);//gaoqing rA->rU + + case INDEX_op_qemu_ld_i32: + case INDEX_op_qemu_ld_i64: + return C_O1_I1(r, l); + + case INDEX_op_qemu_st_i32: + case INDEX_op_qemu_st_i64: + return C_O0_I2(lZ, l); + + case INDEX_op_deposit_i32: + case INDEX_op_deposit_i64: + return C_O1_I2(r, 0, rZ); + + case INDEX_op_extract2_i32: + case INDEX_op_extract2_i64: + return C_O1_I2(r, rZ, rZ); + + case INDEX_op_add2_i32: + case INDEX_op_add2_i64: + case INDEX_op_sub2_i32: + case INDEX_op_sub2_i64: + return C_O2_I4(r, r, rZ, rZ, rA, rMZ); + + case INDEX_op_add_vec: + case INDEX_op_sub_vec: + case INDEX_op_mul_vec: + case INDEX_op_xor_vec: + case INDEX_op_ssadd_vec: + case INDEX_op_sssub_vec: + case INDEX_op_usadd_vec: + case INDEX_op_ussub_vec: + case INDEX_op_smax_vec: + case INDEX_op_smin_vec: + case INDEX_op_umax_vec: + case INDEX_op_umin_vec: + case INDEX_op_shlv_vec: + case INDEX_op_shrv_vec: + case INDEX_op_sarv_vec: + //case INDEX_op_aa64_sshl_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); + //case INDEX_op_aa64_sli_vec: + // return C_O1_I2(w, 0, w); + + default: + g_assert_not_reached(); + } +} + + +static void tcg_out_nop_fill(tcg_insn_unit *p, int count) +{ + int i; + for (i = 0; i < count; ++i) { + p[i] = OPC_NOP; + } +} + +/* SW instruction format of syscall + * insn = opcode[31,26]:Function[25,0], + */ +/* +static void tcg_out_insn_syscall(TCGContext *s, SW_64Insn insn, intptr_t imm26) +{ + tcg_debug_assert(imm26 == sextract64(imm26, 0 ,26)); + tcg_out32(s, insn | (imm26 & 0x3ffffff)); +} +*/ + +/* SW instruction format of br(alias jump) +* insn = opcode[31,26]:Rd[25,21]:disp[20,0], + */ +static void tcg_out_insn_br(TCGContext *s, SW_64Insn insn, TCGReg rd, intptr_t imm64) +{ + tcg_debug_assert( imm64 <= 0xfffff && imm64 >= -0x100000 ); + tcg_out32(s, insn | (rd & 0x1f) << 21 | (imm64 & 0x1fffff)); +} + + +/* SW instruction format of (load and store) + * insn = opcode[31,26]:rd[25,21]:rn[20,16]:disp[15,0] + */ +static void tcg_out_insn_ldst(TCGContext *s, SW_64Insn insn, TCGReg rd, TCGReg rn, intptr_t imm16) +{ + tcg_debug_assert( imm16 <= 0x7fff && imm16 >= -0x8000 ); + tcg_out32(s, insn | (rd & 0x1f) << 21 | (rn & 0x1f) << 16 | (imm16 & 0xffff) ); +} + + +/* SW instruction format of simple operator for Register + * insn = opcode[31,26]:rn(ra)[25,21]:rn(rb)[20,16]:Zeors[15,13]:function[12,5]:rd(rc)[4,0] + */ + +static void tcg_out_insn_simpleReg(TCGContext *s, SW_64Insn insn,TCGReg rd, TCGReg rn, TCGReg rm) +{ + tcg_out32(s, insn | (rn & 0x1f) << 21 | (rm & 0x1f) << 16 | (rd & 0x1f)); +} + +/* SW instruction format of simple operator for imm + * insn = opcode[31,26]:rn(ra)[25,21]:disp[20,13]:function[12,5]:rd(rc)[4,0] + */ +static void tcg_out_insn_simple(TCGContext *s, SW_64Insn insn_Imm, SW_64Insn insn_Reg, TCGReg rd, TCGReg rn, intptr_t imm64) +{ + if( imm64 <= 0x7f && imm64 >= -0x80 ){ + tcg_out32(s, insn_Imm | (rn & 0x1f) << 21 | (imm64 & 0xff) << 13 | (rd & 0x1f)); + }else{ + tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_TMP, imm64); + tcg_out_insn_simpleReg(s, insn_Reg, rd, rn, TCG_REG_TMP); + } +} + + +static void tcg_out_insn_simpleImm(TCGContext *s, SW_64Insn insn_Imm, TCGReg rd, TCGReg rn, intptr_t imm64) +{ + tcg_debug_assert( imm64 <= 0x7f && imm64 >= -0x80 ); + tcg_out32(s, insn_Imm | (rn & 0x1f) << 21 | (imm64 & 0xff)<< 13 | (rd & 0x1f) ); + +} + +static void tcg_out_insn_bitImm(TCGContext *s, SW_64Insn insn_Imm, TCGReg rd, TCGReg rn, unsigned long imm64) +{ + tcg_debug_assert( imm64 <= 255 ); + tcg_out32(s, insn_Imm | (rn & 0x1f) << 21 | (imm64 & 0xff) << 13 | (rd & 0x1f) ); +} +/*sw luo 20210531 +* sw bit operation: and bis etc +*/ +static void tcg_out_insn_bit(TCGContext *s, SW_64Insn insn_Imm, SW_64Insn insn_Reg, TCGReg rd, TCGReg rn, unsigned long imm64) +{ + if( imm64 <= 255 ){ + tcg_out32(s, insn_Imm | (rn & 0x1f) << 21 | (imm64 & 0xff) << 13 | (rd & 0x1f) ); + }else{ + tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_TMP, imm64); + tcg_out_insn_bitReg(s, insn_Reg, rd, rn, TCG_REG_TMP); + } +} +/* SW instruction format of complex operator + * insn = opcode[31,26]:rd[25,21]:rn[20,16],function[15,10]:rm[9,5]:rx[4,0] + */ +static void tcg_out_insn_complexReg(TCGContext *s, SW_64Insn insn, TCGReg cond, TCGReg rd, TCGReg rn, TCGReg rm) +{ + tcg_out32(s, insn | (cond & 0x1f) << 21 | (rn & 0x1f) << 16 | (rm & 0x1f) << 5 | (rd & 0x1f)); +} +/* +static 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)); +} +*/ +/*sw*/ +static bool reloc_pc21(tcg_insn_unit *src_rw, const tcg_insn_unit *target) +{ + const tcg_insn_unit *src_rx = tcg_splitwx_to_rx(src_rw); + ptrdiff_t offset = target - (src_rx + 1) ; + + if (offset == sextract64(offset, 0, 21)) { + /* read instruction, mask away previous PC_REL21 parameter contents, + set the proper offset, then write back the instruction. */ + *src_rw = deposit32(*src_rw, 0, 21, offset); + return true; + } + return false; +} + +/* sw*/ +static bool patch_reloc(tcg_insn_unit *code_ptr, int type, intptr_t value, intptr_t addend) +{ + tcg_debug_assert(addend == 0); + switch (type) { + case R_SW_64_BRADDR: + //value = value - 4 ; /* sinc sw update (pc+4) */ + return reloc_pc21(code_ptr, (const tcg_insn_unit *)value); + default: + g_assert_not_reached(); + } +} + +/* sw */ +static inline uint32_t tcg_in32(TCGContext *s) +{ + uint32_t v = *(uint32_t *)s->code_ptr; + return v; +} + +/*SW Register to register move using ADDL*/ +static void tcg_out_movr(TCGContext *s, TCGType ext, TCGReg rd, TCGReg rn) +{ + tcg_out_insn_simpleReg(s, OPC_BIS, rd, rn, TCG_REG_ZERO); + if (ext == TCG_TYPE_I32){ + tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, rd, rd, 0xf); + } +} + +/*sw + *put imm into rd + */ +static void tcg_out_movi( TCGContext *s, TCGType type, TCGReg rd, tcg_target_long orig) +{ + long l0, l1, l2=0, l3=0, extra=0; + tcg_target_long val = orig; + TCGReg rs = TCG_REG_ZERO; + + if ( type == TCG_TYPE_I32 ) + val = (int32_t)val; + + l0 = (int16_t)val; + val = (val - l0) >> 16; + l1 = (int16_t)val; + + if ( orig >> 31 == -1 || orig >> 31 == 0 ) { + if ( l1 < 0 && orig >= 0) { + extra = 0x4000; + l1 = (int16_t)(val - 0x4000); + } + } else { + val = (val - l1) >> 16; + l2 = (int16_t)val; + val = (val - l2) >> 16; + l3 = (int16_t)val; + + if (l3) { + tcg_out_insn_ldst(s, OPC_LDIH, rd, rs, l3); + rs = rd; + } + if (l2) { + tcg_out_insn_ldst(s, OPC_LDI, rd, rs, l2); + rs = rd; + } + if ( l3 || l2 ) + tcg_out_insn_simpleImm(s, OPC_SLL_I, rd, rd, 32); + } + + if (l1) { + tcg_out_insn_ldst(s, OPC_LDIH, rd, rs, l1); + rs = rd; + } + + if (extra) { + tcg_out_insn_ldst(s, OPC_LDIH, rd, rs, extra); + rs = rd; + } + + tcg_out_insn_ldst(s, OPC_LDI, rd, rs, l0); +} + + +/*sw +* memory <=> Reg in (B H W L) bytes +*/ +static void tcg_out_ldst(TCGContext *s, SW_64Insn insn, TCGReg rd, TCGReg rn, intptr_t offset, bool sign) +{ + int16_t lo = offset; + if (offset != lo) { + tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_TMP, offset - lo); + if (rn != TCG_REG_ZERO) { + tcg_out_insn_simpleReg(s, OPC_ADDL, TCG_REG_TMP, TCG_REG_TMP, rn); + } + // rn = TCG_REG_TMP; + tcg_out_insn_ldst(s, insn, rd, TCG_REG_TMP, lo); + }else{ + tcg_out_insn_ldst(s, insn, rd, rn, lo); + } + + switch (insn){ + case OPC_LDBU: + if(sign) + tcg_out_insn_simpleReg(s, OPC_SEXTB, rd, TCG_REG_ZERO, rd);//for micro-op:INDEX_op_ld8s_i32/64,set rd[63,8]=1 + break; + case OPC_LDHU: + if(sign) + tcg_out_insn_simpleReg(s, OPC_SEXTH, rd, TCG_REG_ZERO, rd);//for micro-op:INDEX_op_ld16s_i32/64,set rd[63,16]=1 + break; + case OPC_LDW: + if(!sign) + tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, rd, rd, 0xf);//for micro-op:INDEX_op_ld32u_i32/64,set rd[63,32]=0 + break; + default: + break; + } +} + +/* sw gaoqing +* refer to aarch64 +* TCG_REG_TMP stores resulf_of_condition_compare +*/ +static void tcg_out_cond_cmp(TCGContext *s, TCGCond cond, TCGReg ret, TCGArg a, TCGArg b, bool const_b) +{ + if (const_b) { + switch(cond){ + case TCG_COND_ALWAYS: + case TCG_COND_NEVER: + break; + case TCG_COND_EQ: + case TCG_COND_NE: + tcg_out_insn_simple(s, OPC_CMPEQ_I, OPC_CMPEQ, ret, a, b); + break; + case TCG_COND_LT: + case TCG_COND_GE: + tcg_out_insn_simple(s, OPC_CMPLT_I, OPC_CMPLT, ret, a, b); + break; + case TCG_COND_LE: + case TCG_COND_GT: + tcg_out_insn_simple(s, OPC_CMPLE_I, OPC_CMPLE, ret, a, b); + break; + case TCG_COND_LTU: + case TCG_COND_GEU: + tcg_out_insn_simple(s, OPC_CMPULT_I, OPC_CMPULT, ret, a, b); + break; + case TCG_COND_LEU: + case TCG_COND_GTU: + tcg_out_insn_simple(s, OPC_CMPULE_I, OPC_CMPULE, ret, a, b); + break; + }//cond + }//if (const_b) + else { + switch(cond){ + case TCG_COND_ALWAYS: + case TCG_COND_NEVER: + break; + case TCG_COND_EQ: + case TCG_COND_NE: + tcg_out_insn_simpleReg(s, OPC_CMPEQ, ret, a, b); + break; + case TCG_COND_LT: + case TCG_COND_GE: + tcg_out_insn_simpleReg(s, OPC_CMPLT, ret, a, b); + break; + case TCG_COND_LE: + case TCG_COND_GT: + tcg_out_insn_simpleReg(s, OPC_CMPLE, ret, a, b); + break; + case TCG_COND_LTU: + case TCG_COND_GEU: + tcg_out_insn_simpleReg(s, OPC_CMPULT, ret, a, b); + break; + case TCG_COND_LEU: + case TCG_COND_GTU: + tcg_out_insn_simpleReg(s, OPC_CMPULE, ret, a, b); + break; + }//cond + }//else + switch(cond){ + case TCG_COND_ALWAYS: + case TCG_COND_NEVER: + case TCG_COND_EQ: + case TCG_COND_LT: + case TCG_COND_LE: + case TCG_COND_LTU: + case TCG_COND_LEU: + break; + case TCG_COND_NE: + case TCG_COND_GE: + case TCG_COND_GT: + case TCG_COND_GEU: + case TCG_COND_GTU: + tcg_out_insn_bitImm(s, OPC_XOR_I, ret, ret, 0x1); + break; + } +} + +/*sw +*step1 tcg_out_cmp() ,"eq" and "ne" in the same case with the same insn; +store compare result by TCG_REG_TMP, for step2; +step2: jump address with compare result. in last "switch" section, we diff qe/ne by different case with different insn. +*/ +static void tcg_out_brcond(TCGContext *s, TCGType ext, TCGCond cond, TCGArg a, TCGArg b, bool b_const, TCGLabel *l) +{ + intptr_t offset; + bool need_cmp; + + if (b_const && b == 0 && (cond == TCG_COND_EQ || cond == TCG_COND_NE)) { + need_cmp = false; + } else { + need_cmp = true; + tcg_out_cond_cmp(s, cond, TCG_REG_TMP, a, b, b_const); + } + + if (!l->has_value) { + tcg_out_reloc(s, s->code_ptr, R_SW_64_BRADDR, l, 0); + offset=0; //offset = tcg_in32(s) >> 5;//luo br $31, 0, do not jump here! + } else { + offset = tcg_pcrel_diff(s, l->u.value_ptr) ; + //offset = offset -4; /* update pc = pc +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); //a cond b,jmp + } else if (cond == TCG_COND_EQ) { + tcg_out_insn_br(s, OPC_BEQ, a, offset); + } else { + tcg_out_insn_br(s, OPC_BNE, a, offset); + } +} + +/*sw +* refer to mips +* contact with "tcg-target-con-str.h" +*/ +#define TCG_CT_CONST_ZERO 0x100 +#define TCG_CT_CONST_LONG 0x200 +#define TCG_CT_CONST_MONE 0x400 +#define TCG_CT_CONST_ORRI 0x800 +#define TCG_CT_CONST_WORD 0X1000 +#define TCG_CT_CONST_U8 0x2000 +#define TCG_CT_CONST_S8 0X4000 + +#define ALL_GENERAL_REGS 0xffffffffu +#define ALL_VECTOR_REGS 0xffffffff00000000ull + + +#ifdef CONFIG_SOFTMMU +/*sw #define ALL_QLDST_REGS */ +#else + #define ALL_QLDST_REGS ALL_GENERAL_REGS +#endif + +/* sw test if a constant matches the constraint */ +static bool tcg_target_const_match(int64_t val, TCGType type, int ct) +{ + if (ct & TCG_CT_CONST) { + return 1; + } + if (type == TCG_TYPE_I32) { + val = (int32_t)val; + } + if ((ct & TCG_CT_CONST_U8) && 0 <= val && val <= 255 ) { + return 1; + } + if ((ct & TCG_CT_CONST_LONG) ) { + return 1; + } + if ((ct & TCG_CT_CONST_MONE) ) { + return 1; + } + if ((ct & TCG_CT_CONST_ORRI) ) { + return 1; + } + if ((ct & TCG_CT_CONST_WORD) ) { + return 1; + } + if ((ct & TCG_CT_CONST_ZERO) && val == 0) { + return 1; + } + return 0; +} + + +/*sw*/ +static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg rd, TCGReg rn, intptr_t ofs) +{ + switch (type) { + case TCG_TYPE_I32: + tcg_out_ldst(s, OPC_LDW, rd, rn, ofs, sigExt); + break; + case TCG_TYPE_I64: + tcg_out_ldst(s, OPC_LDL, rd, rn, ofs, sigExt); + break; + //case TCG_TYPE_V64: for vector + default: + g_assert_not_reached(); + } +} + +/*sw*/ +static void tcg_out_st(TCGContext *s, TCGType type, TCGReg rd,TCGReg rn, intptr_t ofs) +{ + switch (type) { + case TCG_TYPE_I32: + tcg_out_insn_ldst(s, OPC_STW, rd, rn, ofs); + break; + case TCG_TYPE_I64: + tcg_out_insn_ldst(s, OPC_STL, rd, rn, ofs); + break; + //case TCG_TYPE_V64: + default: + g_assert_not_reached(); + } +} + +/*sw*/ +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; +} + +/*sw*/ +static void tcg_out_addsubi(TCGContext *s, int ext, TCGReg rd,TCGReg rn, int64_t imm64) +{ + if (imm64 >= 0) { + if(0 <=imm64 && imm64 <= 255){ + /* we use tcg_out_insn_bitImm because imm64 is between 0~255 */ + tcg_out_insn_bitImm(s, OPC_ADDL_I, rd, rn, imm64); + }//aimm>0 && aimm == sextract64(aim, 0, 8) + else{ + tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_TMP, imm64); + tcg_out_insn_simpleReg(s, OPC_ADDL, rd, rn, TCG_REG_TMP); + }//aimm>0 && aimm != sextract64(aim, 0, 8) + } else { + if(0 < -imm64 && -imm64 <= 255){ + /* we use tcg_out_insn_bitImm because -imm64 is between 0~255 */ + tcg_out_insn_bitImm(s, OPC_SUBL_I, rd, rn, -imm64); + }//aimm<0 && aimm == sextract64(aim, 0, 8) + else{ + tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_TMP, -imm64); + tcg_out_insn_simpleReg(s, OPC_SUBL, rd, rn, TCG_REG_TMP); + }//aimm<0 && aimm != sextract64(aim, 0, 8) + } +} + +/*sw*/ +static void tcg_out_goto(TCGContext *s, const tcg_insn_unit *target) +{ + ptrdiff_t offset = tcg_pcrel_diff(s, target) >> 2; + tcg_debug_assert(offset == sextract64(offset, 0, 21)); + tcg_out_insn_br(s, OPC_BR, TCG_REG_ZERO, offset); +} + +/*sw*/ +static void tcg_out_goto_long(TCGContext *s, const tcg_insn_unit *target) +{ + ptrdiff_t offset = tcg_pcrel_diff(s, target) >> 2; + if ( 0 <= offset && offset <= 0x1fffff) { + tcg_out_insn_br(s, OPC_BR, TCG_REG_ZERO, offset); + } else { + tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_TMP, (intptr_t)target); + tcg_out_insn_jump(s, OPC_JMP, TCG_REG_ZERO, TCG_REG_TMP, 0); + } +} + + +/*sw +* call subroutine +*/ +static void tcg_out_call(TCGContext *s, const tcg_insn_unit *target) +{ + ptrdiff_t offset = tcg_pcrel_diff(s, target) >> 2; + if (offset == sextract64(offset, 0, 21)) { + tcg_out_insn_br(s, OPC_BSR, TCG_REG_RA, offset); + } else { + tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_TMP, (intptr_t)target); + tcg_out_insn_jump(s, OPC_CALL, TCG_REG_RA, TCG_REG_TMP, 0); + } +} + +void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_rx, uintptr_t jmp_rw, uintptr_t addr) +{ + tcg_debug_assert(0); + //sw not support +} + +/*sw*/ +static inline void tcg_out_goto_label(TCGContext *s, TCGLabel *l) +{ + if (!l->has_value) { + tcg_out_reloc(s, s->code_ptr, R_SW_64_BRADDR, l, 0); + tcg_out_insn_br(s, OPC_BR, TCG_REG_ZERO, 0); + } else { + tcg_out_goto(s, l->u.value_ptr); + } +} + +/* sw + * resut: rd=rn(64,64-m]:rm(64-m,0] + * 1: rn(m,0]--->TCG_REG_TMP(64,64-m] + * 2: rm(64,64-m]--->rm(64-m,0] + * 3: rd=TCG_REG_TMP(64,64-m]:rm(64-m,0] + */ +static inline void tcg_out_extr(TCGContext *s, TCGType ext, TCGReg rd, TCGReg rn, TCGReg rm, unsigned int m) +{ + int bits = ext ? 64 : 32; + int max = bits - 1; + tcg_out_insn_bitImm(s, OPC_SLL_I, TCG_REG_TMP, rn, bits - (m & max)); + tcg_out_insn_bitImm(s, OPC_SRL_I, TCG_REG_TMP2, rm, (m & max)); + tcg_out_insn_bitReg(s, OPC_BIS, rd, TCG_REG_TMP, TCG_REG_TMP2); +} + +/* sw + * loop right shift + */ +static inline void tcg_out_rotr_Imm(TCGContext *s, TCGType ext, TCGReg rd, TCGReg rn, unsigned int m) +{ + int bits = ext ? 64 : 32; + int max = bits - 1; + tcg_out_insn_bitImm(s, OPC_SLL_I, TCG_REG_TMP, rn, bits - (m & max)); + tcg_out_insn_bitImm(s, OPC_SRL_I, TCG_REG_TMP2, rn, (m & max)); + tcg_out_insn_bitReg(s, OPC_BIS, rd, TCG_REG_TMP, TCG_REG_TMP2); +} + +/* sw loop right shift + */ +static inline void tcg_out_rotr_Reg(TCGContext *s, TCGType ext, TCGReg rd, TCGReg rn, TCGReg rm) +{ + int bits = ext ? 64 : 32; + //get TCG_REG_TMP=64-[rm] + tcg_out_insn_simpleImm(s, OPC_SUBL_I, TCG_REG_TMP, rm, bits); + tcg_out_insn_bitReg(s, OPC_ORNOT, TCG_REG_TMP, TCG_REG_ZERO, TCG_REG_TMP); + + tcg_out_insn_bitReg(s, OPC_SLL, TCG_REG_TMP2, rn, TCG_REG_TMP); //get rn right part to TCG_REG_TMP + tcg_out_insn_bitReg(s, OPC_SRL, TCG_REG_TMP, rn, rm); //get rn left part to TCG_REG_TMP + tcg_out_insn_bitReg(s, OPC_BIS, rd, TCG_REG_TMP, TCG_REG_TMP2); +} + +/* sw + * loop left shift + */ +static inline void tcg_out_rotl_Imm(TCGContext *s, TCGType ext, TCGReg rd, TCGReg rn, unsigned int m) +{ + int bits = ext ? 64 : 32; + int max = bits - 1; + + tcg_out_insn_bitImm(s, OPC_SRL_I, TCG_REG_TMP, rn, bits -(m & max)); + tcg_out_insn_bitImm(s, OPC_SLL_I, TCG_REG_TMP2, rn, (m & max)); //get rn left part to TCG_REG_TMP + tcg_out_insn_bitReg(s, OPC_BIS, rd, TCG_REG_TMP, TCG_REG_TMP2); //get rn right part to left +} + + +/* sw loop left shift + */ +static inline void tcg_out_rotl_Reg(TCGContext *s, TCGType ext, TCGReg rd, TCGReg rn, TCGReg rm) +{ + int bits = ext ? 64 : 32; + tcg_out_insn_simpleImm(s, OPC_SUBL_I, TCG_REG_TMP, rm, bits); //rm = 64-rm + tcg_out_insn_bitReg(s, OPC_ORNOT, TCG_REG_TMP, TCG_REG_ZERO, TCG_REG_TMP); + + tcg_out_insn_bitReg(s, OPC_SRL, TCG_REG_TMP2, rn, TCG_REG_TMP); //get rn left part to TCG_REG_TMP + tcg_out_insn_bitReg(s, OPC_SLL, TCG_REG_TMP, rn, rm); //get rn right part to left + tcg_out_insn_bitReg(s, OPC_BIS, rd, TCG_REG_TMP, TCG_REG_TMP2); +} + + + +static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg args[TCG_MAX_OP_ARGS],const int const_args[TCG_MAX_OP_ARGS]) +{ + /* 99% of the time, we can signal the use of extension registers + by looking to see if the opcode handles 64-bit data. */ + TCGType ext = (tcg_op_defs[opc].flags & TCG_OPF_64BIT) != 0; + /* Hoist the loads of the most common arguments. */ + TCGArg a0 = args[0]; + TCGArg a1 = args[1]; + TCGArg a2 = args[2]; + int c2 = const_args[2]; + + /* Some operands are defined with "rZ" constraint, a register or + the zero register. These need not actually test args[I] == 0. */ + #define REG0(I) (const_args[I] ? TCG_REG_ZERO : (TCGReg)args[I]) + + switch (opc) { + case INDEX_op_exit_tb: /* sw */ + /* 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: /* sw */ + if (s->tb_jmp_insn_offset != NULL) { + /* TCG_TARGET_HAS_direct_jump */ + tcg_debug_assert(0); + /* not support here */ + } else { + /* !TCG_TARGET_HAS_direct_jump */ + tcg_debug_assert(s->tb_jmp_target_addr != NULL); + tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_TMP, TCG_REG_ZERO, (uintptr_t)(s->tb_jmp_target_addr + a0)); + } + tcg_out_insn_jump(s, OPC_JMP, TCG_REG_ZERO, TCG_REG_TMP, 0); + set_jmp_reset_offset(s, a0); + break; + + case INDEX_op_goto_ptr: /* sw */ + tcg_out_insn_jump(s, OPC_JMP, TCG_REG_ZERO, a0, 0); + break; + + case INDEX_op_br: /* sw */ + tcg_out_goto_label(s, arg_label(a0)); + break; + + case INDEX_op_ld8u_i32: /* sw */ + case INDEX_op_ld8u_i64:/* sw */ + tcg_out_ldst(s, OPC_LDBU, a0, a1, a2, 0); + break; + case INDEX_op_ld8s_i32: /* sw */ + case INDEX_op_ld8s_i64: /* sw */ + tcg_out_ldst(s, OPC_LDBU, a0, a1, a2, 1); + break; + case INDEX_op_ld16u_i32: /* sw */ + case INDEX_op_ld16u_i64: /* sw */ + tcg_out_ldst(s, OPC_LDHU, a0, a1, a2, 0); + break; + case INDEX_op_ld16s_i32: /* sw */ + case INDEX_op_ld16s_i64: /* sw */ + tcg_out_ldst(s, OPC_LDHU, a0, a1, a2, 1); + break; + case INDEX_op_ld_i32: /* sw */ + tcg_out_ldst(s, OPC_LDW, a0, a1, a2, 1); + break; + case INDEX_op_ld32u_i64: /* sw */ + tcg_out_ldst(s, OPC_LDW, a0, a1, a2, 0); + break; + case INDEX_op_ld32s_i64: /* sw */ + tcg_out_ldst(s, OPC_LDW, a0, a1, a2, 1); + break; + case INDEX_op_ld_i64: /* sw */ + tcg_out_ldst(s, OPC_LDL, a0, a1, a2, 1); + break; + case INDEX_op_st8_i32: /* sw */ + case INDEX_op_st8_i64: /* sw */ + tcg_out_ldst(s, OPC_STB, a0, a1, a2, 0); + break; + case INDEX_op_st16_i32: /* sw */ + case INDEX_op_st16_i64: /* sw */ + tcg_out_ldst(s, OPC_STH, a0, a1, a2, 0); + break; + case INDEX_op_st_i32: /* sw */ + case INDEX_op_st32_i64: /* sw */ + tcg_out_ldst(s, OPC_STW, a0, a1, a2, 0); + break; + case INDEX_op_st_i64: /* sw */ + tcg_out_ldst(s, OPC_STL, a0, a1, a2, 0); + break; + + case INDEX_op_add_i32: /* sw */ + a2 = (int32_t)a2; + if (c2) { + tcg_out_addsubi(s, ext, a0, a1, a2); + } else { + tcg_out_insn_simpleReg(s, OPC_ADDL, a0, a1, a2); + } + break; + case INDEX_op_add_i64: /* sw */ + 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: /* sw */ + a2 = (int32_t)a2; + if (c2) { + tcg_out_addsubi(s, ext, a0, a1, -a2); + } else { + tcg_out_insn_simpleReg(s, OPC_SUBL, a0, a1, a2); + } + break; + case INDEX_op_sub_i64: /* sw */ + if (c2) { + tcg_out_addsubi(s, ext, a0, a1, -a2); + } else { + tcg_out_insn_simpleReg(s, OPC_SUBL, a0, a1, a2); + } + break; + + case INDEX_op_neg_i64: /* sw */ + case INDEX_op_neg_i32: /* sw */ + tcg_out_insn_bitReg(s, OPC_SUBL, a0, TCG_REG_ZERO, a1); + break; + + case INDEX_op_and_i32: /* sw */ + a2 = (int32_t)a2; + if (c2) { + tcg_out_insn_bit(s, OPC_AND_I, OPC_AND, a0, a1, a2); + } else { + tcg_out_insn_bitReg(s, OPC_AND, a0, a1, a2); + } + break; + case INDEX_op_and_i64: /* sw */ + if (c2) { + tcg_out_insn_bit(s, OPC_AND_I, OPC_AND, a0, a1, a2); + } else { + tcg_out_insn_bitReg(s, OPC_AND, a0, a1, a2); + } + break; + case INDEX_op_andc_i32: /* sw */ + a2 = (int32_t)a2; + tcg_debug_assert(0); + if (c2) { + tcg_out_insn_bit(s, OPC_AND_I, OPC_AND, a0, a1, ~a2); + } else { + tcg_out_insn_bitReg(s, OPC_BIC, a0, a1, a2); + } + break; + case INDEX_op_andc_i64: /* sw */ + tcg_debug_assert(0); + if (c2) { + tcg_out_insn_bit(s, OPC_AND_I, OPC_AND, a0, a1, ~a2); + } else { + tcg_out_insn_bitReg(s, OPC_BIC, a0, a1, a2); + } + break; + + case INDEX_op_or_i32: /* sw */ + a2 = (int32_t)a2; + if (c2) { + tcg_out_insn_bit(s, OPC_BIS_I, OPC_BIS, a0, a1, a2); + } else { + tcg_out_insn_bitReg(s, OPC_BIS, a0, a1, a2); + } + break; + case INDEX_op_or_i64: /* sw */ + if (c2) { + tcg_out_insn_bit(s, OPC_BIS_I, OPC_BIS, a0, a1, a2); + } else { + tcg_out_insn_bitReg(s, OPC_BIS, a0, a1, a2); + } + break; + + case INDEX_op_orc_i32: /* sw */ + a2 = (int32_t)a2; + tcg_debug_assert(0); + if (c2) { + tcg_out_insn_bit(s, OPC_BIS_I, OPC_BIS, a0, a1, ~a2); + } else { + tcg_out_insn_bitReg(s, OPC_ORNOT, a0, a1, a2); + } + break; + case INDEX_op_orc_i64: /* sw */ + tcg_debug_assert(0); + if (c2) { + tcg_out_insn_bit(s, OPC_BIS_I, OPC_BIS, a0, a1, ~a2); + } else { + tcg_out_insn_bitReg(s, OPC_ORNOT, a0, a1, a2); + } + break; + + case INDEX_op_xor_i32: /* sw */ + a2 = (int32_t)a2; + if (c2) { + tcg_out_insn_bit(s, OPC_XOR_I, OPC_XOR, a0, a1, a2); + } else { + tcg_out_insn_bitReg(s, OPC_XOR, a0, a1, a2); + } + break; + case INDEX_op_xor_i64: /* sw */ + if (c2) { + tcg_out_insn_bit(s, OPC_XOR_I, OPC_XOR, a0, a1, a2); + } else { + tcg_out_insn_bitReg(s, OPC_XOR, a0, a1, a2); + } + break; + + case INDEX_op_eqv_i32: /* sw */ + a2 = (int32_t)a2; + tcg_debug_assert(0); + if (c2) { + tcg_out_insn_bit(s, OPC_XOR_I, OPC_XOR, a0, a1, ~a2); + } else { + tcg_out_insn_bitReg(s, OPC_EQV, a0, a1, a2); + } + break; + + case INDEX_op_eqv_i64: /* sw */ + tcg_debug_assert(0); + if (c2) { + tcg_out_insn_bit(s, OPC_XOR_I, OPC_XOR, a0, a1, ~a2); + } else { + tcg_out_insn_bitReg(s, OPC_EQV, a0, a1, a2); + } + break; + + case INDEX_op_not_i64: /* sw */ + case INDEX_op_not_i32: /* sw */ + tcg_out_insn_bitReg(s, OPC_ORNOT, a0, TCG_REG_ZERO, a1); + break; + + case INDEX_op_mul_i64: /* sw */ + case INDEX_op_mul_i32: /* sw */ + tcg_out_insn_simpleReg(s, OPC_MULL, a0, a1, a2); + break; + + case INDEX_op_div_i64: /* a0=a1/a2 singed divide*/ + case INDEX_op_div_i32: /* luo */ + tcg_debug_assert(0); + //tcg_out_insn(s, 3508, SDIV, ext, a0, a1, a2); + break; + case INDEX_op_divu_i64: /* a0=a1/a2 unsigned divide */ + case INDEX_op_divu_i32: /* luo */ + tcg_debug_assert(0); + //tcg_out_insn(s, 3508, UDIV, ext, a0, a1, a2); + break; + + case INDEX_op_rem_i64: /* if a1=17,a2=4, 17/4=4...1, a0=1 */ + case INDEX_op_rem_i32: /* luo */ + tcg_debug_assert(0); + //tcg_out_insn(s, 3508, SDIV, ext, TCG_REG_TMP, a1, a2); + //tcg_out_insn(s, 3509, MSUB, ext, a0, TCG_REG_TMP, a2, a1); + break; + case INDEX_op_remu_i64: /* luo */ + case INDEX_op_remu_i32: + tcg_debug_assert(0); + //tcg_out_insn(s, 3508, UDIV, ext, TCG_REG_TMP, a1, a2); + //tcg_out_insn(s, 3509, MSUB, ext, a0, TCG_REG_TMP, a2, a1); + break; + + case INDEX_op_shl_i64: /* sw */ + case INDEX_op_shl_i32: /* sw logical left*/ + if (c2) { + int bits = ext ? 64 : 32; + int max = bits - 1; + tcg_out_insn_bitImm(s, OPC_SLL_I, a0, a1, a2&max); + } else { + tcg_out_insn_bitReg(s, OPC_SLL, a0, a1, a2); + } + break; + + case INDEX_op_shr_i64: /* sw */ + case INDEX_op_shr_i32: /* sw logical right */ + if (c2) { + int bits = ext ? 64 : 32; + int max = bits - 1; + tcg_out_insn_bitImm(s, OPC_SRL_I, a0, a1, a2&max); + } else { + tcg_out_insn_bitReg(s, OPC_SRL, a0, a1, a2); + } + break; + + case INDEX_op_sar_i64: /* sw */ + case INDEX_op_sar_i32: /* sw arithmetic right*/ + if (c2) { + int bits = ext ? 64 : 32; + int max = bits - 1; + tcg_out_insn_bitImm(s, OPC_SRA_I, a0, a1, a2&max); + } else { + tcg_out_insn_bitReg(s, OPC_SRA, a0, a1, a2); + } + break; + + case INDEX_op_rotr_i64: /* sw */ + case INDEX_op_rotr_i32: /* loop shift */ + if (c2) {/* loop right shift a2*/ + tcg_out_rotr_Imm(s, ext, a0, a1, a2); + } else { + tcg_out_rotr_Reg(s, ext, a0, a1, a2); + } + break; + + case INDEX_op_rotl_i64: /* sw */ + case INDEX_op_rotl_i32: /* loop shift */ + if (c2) {/* loop left shift a2*/ + tcg_out_rotl_Imm(s, ext, a0, a1, a2); + } else { + tcg_out_rotl_Reg(s, ext, a0, a1, a2); + } + break; + + case INDEX_op_clz_i64: /* counting leading zero numbers */ + case INDEX_op_clz_i32: + tcg_out_cltz(s, OPC_CTLZ,ext, a0, a1, a2, c2); + break; + case INDEX_op_ctz_i64: /* counting tailing zero numbers */ + case INDEX_op_ctz_i32: + tcg_out_cltz(s, OPC_CTTZ,ext, a0, a1, a2, c2); + break; + + case INDEX_op_brcond_i32: /* sw */ + a1 = (int32_t)a1; + tcg_out_brcond(s, ext, a2, a0, a1, const_args[1], arg_label(args[3])); + break; + + case INDEX_op_brcond_i64: /* sw */ + tcg_out_brcond(s, ext, a2, a0, a1, const_args[1], arg_label(args[3])); + break; + + case INDEX_op_setcond_i32: + a2 = (int32_t)a2; + tcg_out_setcond(s, args[3], a0, a1, a2); + break; + + case INDEX_op_setcond_i64: + tcg_out_setcond(s, args[3], a0, a1, a2); + break; + + case INDEX_op_movcond_i32: + a2 = (int32_t)a2; + tcg_out_movcond(s, args[5], a0, a1, a2, c2, REG0(3), REG0(4)); + break; + + /* FALLTHRU */ + case INDEX_op_movcond_i64: /* luo */ + tcg_out_movcond(s, args[5], a0, a1, a2, c2, REG0(3), REG0(4)); + break; + + case INDEX_op_qemu_ld_i32: + case INDEX_op_qemu_ld_i64: + tcg_out_qemu_ld(s, a0, a1, a2, ext); + break; + case INDEX_op_qemu_st_i32: /* sw */ + case INDEX_op_qemu_st_i64: /* sw */ + tcg_out_qemu_st(s, REG0(0), a1, a2); + break; + + case INDEX_op_bswap64_i64: /* 0x123456789abcdef--->0xefcdab8967452301 */ + tcg_debug_assert(0); + tcg_out_bswap64(s, a0, a1); + break; + case INDEX_op_bswap32_i64: /* 0x123456789abcdef--->0x67452301efcdab89 */ + tcg_debug_assert(0); + tcg_out_bswap32u(s, a0, a1); + break; + case INDEX_op_bswap32_i32: + tcg_debug_assert(0); + //tcg_out_rev32(s, a0, a1); + break; + case INDEX_op_bswap16_i64: /* 0x123456789abcdef--->0x23016745ab89efcd */ + case INDEX_op_bswap16_i32: + tcg_debug_assert(0); + //tcg_out_rev16(s, a0, a1); + break; + + case INDEX_op_ext8s_i64: + case INDEX_op_ext8s_i32: + tcg_out_insn_simpleReg(s, OPC_SEXTB, a0, TCG_REG_ZERO, a1); + break; + case INDEX_op_ext16s_i64: + case INDEX_op_ext16s_i32: + tcg_out_insn_simpleReg(s, OPC_SEXTH, a0, TCG_REG_ZERO, a1); + break; + case INDEX_op_ext_i32_i64: + case INDEX_op_ext32s_i64: + tcg_out_insn_simpleReg(s, OPC_ADDW, a0, TCG_REG_ZERO, a1); + break; + case INDEX_op_ext8u_i64: + case INDEX_op_ext8u_i32: + tcg_out_insn_simpleImm(s, OPC_EXT0B_I, a0, a1, 0x0); + break; + case INDEX_op_ext16u_i64: + case INDEX_op_ext16u_i32: + tcg_out_insn_simpleImm(s, OPC_EXT1B_I, a0, a1, 0x0); + break; + case INDEX_op_extu_i32_i64: + case INDEX_op_ext32u_i64:/*sw*/ + tcg_out_movr(s, TCG_TYPE_I32, a0, a1); + break; + + case INDEX_op_deposit_i64: + case INDEX_op_deposit_i32://sw 20210616 + tcg_out_dep(s, a0, a2, args[3], args[4]); + break; + + case INDEX_op_extract_i64: + case INDEX_op_extract_i32:/*sw 20210616*/ + tcg_out_extract(s, a0, a1, a2, args[3]);//refer mips + break; + + case INDEX_op_sextract_i64: + case INDEX_op_sextract_i32: + tcg_debug_assert(0); + //tcg_out_sbfm(s, ext, a0, a1, a2, a2 + args[3] - 1); + break; + + case INDEX_op_extract2_i64: /* sw */ + case INDEX_op_extract2_i32: /* extract REG0(2) right args[3] bit to REG0(1) left ,save to a0*/ + tcg_debug_assert(0); + //tcg_out_extr(s, ext, a0, REG0(2), REG0(1), args[3]); + break; + + case INDEX_op_add2_i32: + tcg_debug_assert(0); + /* tcg_out_addsub2(s, TCG_TYPE_I32, a0, a1, REG0(2), REG0(3), + (int32_t)args[4], args[5], const_args[4], + const_args[5], false); */ + break; + case INDEX_op_add2_i64: + tcg_debug_assert(0); + /* tcg_out_addsub2(s, TCG_TYPE_I64, a0, a1, REG0(2), REG0(3), args[4], + args[5], const_args[4], const_args[5], false); */ + break; + case INDEX_op_sub2_i32: + tcg_debug_assert(0); + /* tcg_out_addsub2(s, TCG_TYPE_I32, a0, a1, REG0(2), REG0(3), + (int32_t)args[4], args[5], const_args[4], + const_args[5], true); */ + break; + case INDEX_op_sub2_i64: + tcg_debug_assert(0); + /* tcg_out_addsub2(s, TCG_TYPE_I64, a0, a1, REG0(2), REG0(3), args[4], + args[5], const_args[4], const_args[5], true);*/ + break; + + case INDEX_op_muluh_i64: /* sw */ + tcg_out_insn_simpleReg(s, OPC_UMULH, a0, a1, a2); + break; + case INDEX_op_mulsh_i64: /* luo: sw not support */ + tcg_out_mulsh64(s, a0, a1, a2); + break; + + case INDEX_op_mb: /* luo */ + //tcg_out_mb(s, a0); + break; + + case INDEX_op_mov_i32: /* Always emitted via tcg_out_mov. */ + case INDEX_op_mov_i64: + case INDEX_op_call: /* Always emitted via tcg_out_call. */ + default: + g_assert_not_reached(); + } + +#undef REG0 +} + + + +/*sw gaoqing 20210526 +* counting heading/tailing zero numbers +*/ +static void tcg_out_cltz(TCGContext *s, SW_64Insn opc_clz, TCGType ext, TCGReg rd, + TCGReg rn, TCGArg b, bool const_b) +{ + /* cond1. b is a const, and b=64 or b=32 */ + if (const_b && b == (ext ? 64 : 32)) { + /* count rn zero numbers, and writes to rd */ + tcg_out_insn_simpleReg(s, opc_clz, rd, TCG_REG_ZERO, rn); + }else { + /* TCG_REG_TMP= counting rn heading/tailing zero numbers */ + tcg_out_insn_simpleReg(s, opc_clz, TCG_REG_TMP, TCG_REG_ZERO, rn); + + if(const_b){ + if(b == -1){ + /* cond2. b is const and b=-1 */ + /* if rn != 0 , rd= counting rn heading/tailing zero numbers, else rd = 0xffffffffffffffff*/ + tcg_out_insn_bitReg(s, OPC_ORNOT, TCG_REG_TMP2, TCG_REG_ZERO, TCG_REG_ZERO); + tcg_out_insn_complexReg(s, OPC_SELNE, rn, rd, TCG_REG_TMP, TCG_REG_TMP2); + } + else if (b == 0){ + /* cond3. b is const and b=0 */ + /* if rn != 0 , rd=counting rn heading/tailing zero numbers , else rd = TCG_REG_ZERO */ + tcg_out_insn_complexReg(s, OPC_SELNE, rn, rd, TCG_REG_TMP, TCG_REG_ZERO); + } else { + /* cond4. b is const */ + tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_TMP2, b); + /* if rn != 0 , rd=counting rn heading/tailing zero numbers , else mov b to rd */ + tcg_out_insn_complexReg(s, OPC_SELNE, rn, rd, TCG_REG_TMP, TCG_REG_TMP2); + } + } + else{ + /* if b is register */ + tcg_out_insn_complexReg(s, OPC_SELNE, rn, rd, TCG_REG_TMP, b); + } + } +} + + +/*sw gaoqing 20210531 +* memory protect for order of (ld and st) +*/ +/* +static void tcg_out_mb(TCGContext *s, TCGArg a0) +{ + tcg_out32(s, OPC_MEMB); +} +*/ + +/*sw gaoqing 20210531 +* unsigned 16bit, ab->ba +*/ +static inline void tcg_out_bswap16u(TCGContext *s, TCGReg rd, TCGReg rn) +{ + TCGReg TCG_TMP0 = rn; + TCGReg TCG_TMP1 = rd; + /*t1=00b0*/ + tcg_out_insn_bitImm(s, OPC_SLL_I, TCG_TMP1, TCG_TMP0, 8); + /*t1=(0000)000a*/ + tcg_out_insn_bitImm(s, OPC_SRL_I, TCG_TMP0, TCG_TMP0, 8); + tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, TCG_TMP0, TCG_TMP0, 0x1); + /*t1=ooba*/ + tcg_out_insn_simpleReg(s, OPC_BIS, TCG_TMP1, TCG_TMP1, TCG_TMP0); +} + +/*sw gaoqing 20210531 +* signed 16bit, ab->ssba +*/ +static inline void tcg_out_bswap16s(TCGContext *s, TCGReg rd, TCGReg rn) +{ + TCGReg TCG_TMP0 = rn; + TCGReg TCG_TMP1 = TCG_REG_TMP; + TCGReg TCG_TMP2 = rn; + /*t1=(ssss)ssb0*/ + tcg_out_insn_bitImm(s, OPC_SLL_I, TCG_TMP1, TCG_TMP0, 8); + tcg_out_insn_simpleImm(s, OPC_ZAP_I, TCG_TMP1, TCG_TMP1, 0x2); + tcg_out_insn_simpleReg(s ,OPC_SEXTH, TCG_TMP1, TCG_REG_ZERO, TCG_TMP1); + /*t2=(0000)000a*/ + tcg_out_insn_bitImm(s, OPC_SRL_I, TCG_TMP2, TCG_TMP0, 8); + tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, TCG_TMP2, TCG_TMP2, 0x1); + /*t2=(ssss)ssba*/ + tcg_out_insn_simpleReg(s, OPC_BIS, TCG_TMP1, TCG_TMP1, TCG_TMP2); +} + + +/*sw gaoqing 20210601 +* signed 32bit, abcd ->ssdcba +*/ +static inline void tcg_out_bswap32s(TCGContext *s, TCGReg rd, TCGReg rn) +{ + TCGReg TCG_TMP0 = rn; + TCGReg TCG_TMP3 = rd; + TCGReg TCG_TMP1 = TCG_REG_TMP; + TCGReg TCG_TMP2 = TCG_REG_TMP2; + /*swap32 -- 32-bit swap (signed result for mips64). a0 = abcd.*/ + + /* t3 = (ssss)d000 */ + tcg_out_insn_bitImm(s, OPC_SLL_I, TCG_TMP3, TCG_TMP0, 24); + tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, TCG_TMP3, TCG_TMP3, 0x0f); + tcg_out_insn_simpleReg(s, OPC_SEXTB, TCG_TMP1, TCG_REG_ZERO, TCG_TMP0); + tcg_out_insn_simpleImm(s, OPC_ZAP_I, TCG_TMP1, TCG_TMP1, 0x0f); + tcg_out_insn_bitReg(s, OPC_BIS, TCG_TMP3, TCG_TMP3, TCG_TMP1); + + /* t1 = 000a */ + tcg_out_insn_bitImm(s, OPC_SRL_I, TCG_TMP1, TCG_TMP0, 24); + tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, TCG_TMP1, TCG_TMP1, 0x1); + + /* t2 = 00c0 */ + tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, TCG_TMP2, TCG_TMP0, 0x2); + + /* t3 = (ssss)d00a */ + tcg_out_insn_bitReg(s, OPC_BIS, TCG_TMP3, TCG_TMP3, TCG_TMP1); + + /* t1 = 0abc */ + tcg_out_insn_bitImm(s, OPC_SRL_I, TCG_TMP1, TCG_TMP0, 8); + tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, TCG_TMP1, TCG_TMP1, 0x7); + + /* t2 = 0c00 */ + tcg_out_insn_bitImm(s, OPC_SLL_I, TCG_TMP2, TCG_TMP2, 8); + /* t1 = 00b0 */ + tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, TCG_TMP1, TCG_TMP1, 0x2); + /* t3 = (ssss)dc0a */ + tcg_out_insn_bitReg(s, OPC_BIS, TCG_TMP3, TCG_TMP3, TCG_TMP2); + /* t3 = (ssss)dcba -- delay slot */ + tcg_out_insn_bitReg(s, OPC_BIS, TCG_TMP3, TCG_TMP3, TCG_TMP1); +} + +/*sw gaoqing 20210531 +* unsigned 32bit, abcd->dcba +*/ +static void tcg_out_bswap32u(TCGContext *s, TCGReg rd, TCGReg rn) +{ + + TCGReg TCG_TMP0 = rn; + TCGReg TCG_TMP3 = rd; + TCGReg TCG_TMP1 = TCG_REG_TMP; + TCGReg TCG_TMP2 = TCG_REG_TMP2; + + /*bswap32u -- unsigned 32-bit swap. a0 = ....abcd.*/ + /* t1 = (0000)000d */ + tcg_out_insn_bitImm(s, OPC_AND_I, TCG_TMP1, TCG_TMP0, 0xff); + /* t3 = 000a */ + tcg_out_insn_bitImm(s, OPC_SRL_I, TCG_TMP3, TCG_TMP0, 24); + tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, TCG_TMP3, TCG_TMP3, 0x1); + /* t1 = (0000)d000 */ + tcg_out_insn_bitImm(s, OPC_SLL_I, TCG_TMP1, TCG_TMP1, 24); + /* t2 = 00c0 */ + tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, TCG_TMP2, TCG_TMP0, 0x2); + /* t3 = d00a */ + tcg_out_insn_bitReg(s, OPC_BIS, TCG_TMP3, TCG_TMP3, TCG_TMP1); + /* t1 = 0abc */ + tcg_out_insn_bitImm(s, OPC_SRL_I, TCG_TMP1, TCG_TMP0, 8); + tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, TCG_TMP1, TCG_TMP1, 0x7); + /* t2 = 0c00 */ + tcg_out_insn_bitImm(s, OPC_SLL_I, TCG_TMP2, TCG_TMP2, 8); + /* t1 = 00b0 */ + tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, TCG_TMP1, TCG_TMP1, 0x2); + /* t3 = dc0a */ + tcg_out_insn_bitReg(s, OPC_BIS, TCG_TMP3, TCG_TMP3, TCG_TMP2); + /* t3 = dcba -- delay slot */ + tcg_out_insn_bitReg(s, OPC_BIS, TCG_TMP3, TCG_TMP3, TCG_TMP1); +} + + + +/*sw gaoqing 20210601 +*swap 64bit, abcdefgh->hgfedcba +*/ +static void tcg_out_bswap64(TCGContext *s, TCGReg rd, TCGReg rn) +{ + + TCGReg TCG_TMP0 = rn; + TCGReg TCG_TMP3 = rd; + TCGReg TCG_TMP1 = TCG_REG_TMP; + TCGReg TCG_TMP2 = TCG_REG_TMP2; + + /* bswap64 -- 64-bit swap. a0 = abcdefgh*/ + + /* t3 = h0000000 */ + tcg_out_insn_bitImm(s, OPC_SLL_I, TCG_TMP3, TCG_TMP0, 56); + /* t1 = 0000000a */ + tcg_out_insn_bitImm(s, OPC_SRL_I, TCG_TMP1, TCG_TMP0, 56); + /* t2 = 000000g0 */ + tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, TCG_TMP2, TCG_TMP0, 0x2); + /* t3 = h000000a */ + tcg_out_insn_bitReg(s, OPC_BIS, TCG_TMP3, TCG_TMP3, TCG_TMP1); + /* t1 = 00000abc */ + tcg_out_insn_bitImm(s, OPC_SRL_I, TCG_TMP1, TCG_TMP0, 40); + /* t2 = 0g000000 */ + tcg_out_insn_bitImm(s, OPC_SLL_I, TCG_TMP2, TCG_TMP2, 40); + /* t1 = 000000b0 */ + tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, TCG_TMP1, TCG_TMP1, 0x2); + /* t3 = hg00000a */ + tcg_out_insn_bitReg(s, OPC_BIS, TCG_TMP3, TCG_TMP3, TCG_TMP2); + /* t2 = 0000abcd */ + tcg_out_insn_bitImm(s, OPC_SRL_I, TCG_TMP2, TCG_TMP0, 32); + /* t3 = hg0000ba */ + tcg_out_insn_bitReg(s, OPC_BIS, TCG_TMP3, TCG_TMP3, TCG_TMP1); + /* t1 = 000000c0 */ + tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, TCG_TMP1, TCG_TMP2, 0x2); + /* t2 = 0000000d */ + tcg_out_insn_bitImm(s, OPC_AND_I, TCG_TMP2, TCG_TMP2, 0xff); + /* t1 = 00000c00 */ + tcg_out_insn_bitImm(s, OPC_SLL_I, TCG_TMP1, TCG_TMP1, 8); + /* t2 = 0000d000 */ + tcg_out_insn_bitImm(s, OPC_SLL_I, TCG_TMP2, TCG_TMP2, 24); + /* t3 = hg000cba */ + tcg_out_insn_bitReg(s, OPC_BIS, TCG_TMP3, TCG_TMP3, TCG_TMP1); + /* t1 = 00abcdef */ + tcg_out_insn_bitImm(s, OPC_SRL_I, TCG_TMP1, TCG_TMP0, 16); + /* t3 = hg00dcba */ + tcg_out_insn_bitReg(s, OPC_BIS, TCG_TMP3, TCG_TMP3, TCG_TMP2); + /* t2 = 0000000f */ + tcg_out_insn_bitImm(s, OPC_AND_I, TCG_TMP2, TCG_TMP1, 0xff); + /* t1 = 000000e0 */ + tcg_out_insn_simpleImm(s, OPC_ZAPNOT_I, TCG_TMP1, TCG_TMP1, 0x2); + /* t2 = 00f00000 */ + tcg_out_insn_bitImm(s, OPC_SLL_I, TCG_TMP2, TCG_TMP2, 40); + /* t1 = 000e0000 */ + tcg_out_insn_bitImm(s, OPC_SLL_I, TCG_TMP1, TCG_TMP1, 24); + /* t3 = hgf0dcba */ + tcg_out_insn_bitReg(s, OPC_BIS, TCG_TMP3, TCG_TMP3, TCG_TMP2); + /* t3 = hgfedcba -- delay slot */ + tcg_out_insn_bitReg(s, OPC_BIS, TCG_TMP3, TCG_TMP3, TCG_TMP1); + +} + +/* +static void tcg_out_qemu_ld_direct(TCGContext *s, MemOp memop, + TCGReg data_r, TCGReg addr_r, + TCGType otype, intptr_t off_r) +{ + const MemOp bswap = memop & MO_BSWAP; + + switch (memop & MO_SSIZE) { + case MO_UB: + tcg_out_ldst(s, OPC_LDBU, data_r, addr_r, off_r, 0); + break; + case MO_SB: + tcg_out_ldst(s, OPC_LDBU, data_r, addr_r, off_r, 1); + break; + case MO_UW: + tcg_out_ldst(s, OPC_LDHU, data_r, addr_r, off_r, 0); + if (bswap) { + tcg_out_bswap16u(s, data_r, data_r); + } + break; + case MO_SW: + tcg_out_ldst(s, OPC_LDHU, data_r, addr_r, off_r, 1); + if(bswap) { + tcg_out_bswap16s(s, data_r, data_r); + } + break; + case MO_UL: + tcg_out_ldst(s, OPC_LDW, data_r, addr_r, off_r, 0); + if (bswap) { + tcg_out_bswap32u(s, data_r, data_r); + } + break; + case MO_SL: + tcg_out_ldst(s, OPC_LDW, data_r, addr_r, off_r, 1); + if (bswap) { + tcg_out_bswap32s(s, data_r, data_r); + } + break; + case MO_Q: + tcg_out_ldst(s, OPC_LDL, data_r, addr_r, off_r, 0); + if (bswap) { + tcg_out_bswap64(s, 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) +{ +#ifndef CONFIG_SOFTMMU + MemOp memop = get_memop(oi); + const TCGType otype = TCG_TYPE_I64; + + if (USE_GUEST_BASE) { + tcg_out_insn_simpleReg(s, OPC_ADDL, TCG_REG_GUEST_BASE, TCG_REG_GUEST_BASE, addr_reg); + tcg_out_qemu_ld_direct(s, memop, data_reg, TCG_REG_GUEST_BASE, otype, 0); + } else { + tcg_out_qemu_ld_direct(s, memop, data_reg, addr_reg, TCG_TYPE_I64, 0); + } +#endif /* CONFIG_SOFTMMU */ + +} + +/*sw gaoqing 20210602 +*/ +/* +static void tcg_out_qemu_st_direct(TCGContext *s, MemOp memop, + TCGReg data_r, TCGReg addr_r, + TCGType otype, intptr_t off_r) +{ + const MemOp bswap = memop & MO_BSWAP; + + switch (memop & MO_SIZE) { + case MO_8: + tcg_out_ldst(s, OPC_STB, data_r, addr_r, off_r, 0); + break; + case MO_16: + if (bswap && data_r != TCG_REG_ZERO) { + tcg_out_bswap16u(s, TCG_REG_TMP, data_r); + data_r = TCG_REG_TMP; + } + tcg_out_ldst(s, OPC_STH, data_r, addr_r, off_r, 0); + break; + case MO_32: + if (bswap && data_r != TCG_REG_ZERO) { + tcg_out_bswap32u(s, TCG_REG_TMP, data_r); + data_r = TCG_REG_TMP; + } + tcg_out_ldst(s, OPC_STW, data_r, addr_r, off_r, 0); + break; + case MO_64: + if (bswap && data_r != TCG_REG_ZERO) { + tcg_out_bswap64(s, TCG_REG_TMP, data_r); + data_r = TCG_REG_TMP; + } + tcg_out_ldst(s, OPC_STL, data_r, addr_r, off_r, 0); + break; + default: + tcg_abort(); + } +} +*/ + +/*sw gaoqing 20210602 +*/ +static void tcg_out_qemu_st(TCGContext *s, TCGReg data_reg, TCGReg addr_reg, + MemOpIdx oi) +{ +#ifndef CONFIG_SOFTMMU + MemOp memop = get_memop(oi); + const TCGType otype = TCG_TYPE_I64; + + if (USE_GUEST_BASE) { + tcg_out_insn_simpleReg(s, OPC_ADDL, TCG_REG_GUEST_BASE, TCG_REG_GUEST_BASE, addr_reg); + tcg_out_qemu_st_direct(s, memop, data_reg, TCG_REG_GUEST_BASE, otype, 0); + } else { + tcg_out_qemu_st_direct(s, memop, data_reg, addr_reg, TCG_TYPE_I64, 0); + } +#endif /* CONFIG_SOFTMMU */ +} + + +/*sw gaoqing 20210611 +* if cond is successful, ret=1, otherwise ret = 0 +*/ +static void tcg_out_setcond(TCGContext *s, TCGCond cond, TCGReg ret, + TCGReg arg1, TCGReg arg2) +{ + switch(cond){ + case TCG_COND_EQ: + case TCG_COND_LT: + case TCG_COND_LE: + case TCG_COND_LTU: + case TCG_COND_LEU: + case TCG_COND_NE: + case TCG_COND_GE: + case TCG_COND_GT: + case TCG_COND_GEU: + case TCG_COND_GTU: + tcg_out_cond_cmp(s, cond, ret, arg1, arg2, 0); + break; + default: + tcg_abort(); + break; + } +} +/*sw gaoqing 20210611 +*cond(a1,a2), yes:v1->ret, no:v2->ret +*/ +static void tcg_out_movcond(TCGContext *s, TCGCond cond, TCGReg ret, + TCGReg a1, TCGReg a2, bool const_b, TCGReg v1, TCGReg v2) +{ + tcg_out_cond_cmp(s, cond, TCG_REG_TMP, a1, a2, const_b); + tcg_out_insn_complexReg(s, OPC_SELLBS, TCG_REG_TMP, ret, v1, v2); +} + + + +/*sw 20210616 +* extract rn[lsb, lsb+len-1] -> rd[0, len-1] +*/ +static void tcg_out_extract(TCGContext *s, TCGReg rd, TCGReg rn, int lsb, int len) +{ + //get 000..111..0000 + tcg_out_insn_bitReg(s, OPC_ORNOT, TCG_REG_TMP, TCG_REG_ZERO, TCG_REG_ZERO); + tcg_out_insn_bitImm(s, OPC_SRL_I, TCG_REG_TMP, TCG_REG_TMP, 64 - len); + tcg_out_insn_bitImm(s, OPC_SLL_I, TCG_REG_TMP, TCG_REG_TMP, lsb); + /* get rn[lsb, lsb+len-1]-->rd[lsb, lsb+len-1] */ + tcg_out_insn_bitReg(s, OPC_AND, rd, rn, TCG_REG_TMP); + + /* rd[lsb, lsb+len-1] --> rd[0, len-1] */ + tcg_out_insn_bitImm(s, OPC_SRL_I, rd ,rd, lsb); +} + + +/*sw 20210616 +* depos: rd = rd[63:msb+1]:rn[msb,lsb]:rd[lsb-1,0] +* len = msb -lsb + 1 +*/ +static void tcg_out_dep(TCGContext *s, TCGReg rd, TCGReg rn, int lsb, int len) +{ + + //get 000..111..0000 + tcg_out_insn_bitReg(s, OPC_ORNOT, TCG_REG_TMP, TCG_REG_ZERO, TCG_REG_ZERO); + tcg_out_insn_bitImm(s, OPC_SRL_I, TCG_REG_TMP, TCG_REG_TMP, 64 - len); + tcg_out_insn_bitImm(s, OPC_SLL_I, TCG_REG_TMP, TCG_REG_TMP, lsb); + + /* TCG_REG_TMP2 = rn[msb,lsb] */ + tcg_out_insn_bitImm(s, OPC_SLL_I, TCG_REG_TMP2, rn, 64-len); + tcg_out_insn_bitImm(s, OPC_SRL_I, TCG_REG_TMP2, TCG_REG_TMP2, 64-len-lsb); + + /* clear rd[msb,lsb] */ + tcg_out_insn_bitReg(s, OPC_BIC, rd, rd, TCG_REG_TMP); + /* rd = rd[63:msb+1]:rn[msb,lsb]:rd[lsb-1,0] */ + tcg_out_insn_bitReg(s, OPC_BIS, rd, rd, TCG_REG_TMP2); +} + +/*sw 20210617 +* get val_s64(rn) * val_s64(rm) -> res_128 +* res[127:64] -> rd +* warn:maybe rd=rn or rm +*/ +static void tcg_out_mulsh64(TCGContext *s, TCGReg rd, TCGReg rn, TCGReg rm) +{ + tcg_out_insn_simpleReg(s, OPC_UMULH, TCG_REG_TMP, rn, rm); + + tcg_out_insn_bitImm(s, OPC_SRL_I, TCG_REG_TMP2, rn, 63); + tcg_out_insn_complexReg(s, OPC_SELEQ, TCG_REG_TMP2, TCG_REG_TMP2, TCG_REG_ZERO, rm); + tcg_out_insn_simpleReg(s, OPC_SUBL, TCG_REG_TMP, TCG_REG_TMP, TCG_REG_TMP2); + + tcg_out_insn_bitImm(s, OPC_SRL_I, TCG_REG_TMP2, rm, 63); + tcg_out_insn_complexReg(s, OPC_SELEQ, TCG_REG_TMP2, TCG_REG_TMP2, TCG_REG_ZERO, rn); + tcg_out_insn_simpleReg(s, OPC_SUBL, rd, TCG_REG_TMP, TCG_REG_TMP2); +} + +/*sw 20210617 +* get val_u64(rn) * val_u64(rm) -> res_128 +* res[127:64] -> rd +*/ + +//static void tcg_out_div32(TCGContext *s, TCGReg rd, TCGReg rn, TCGReg rm) +//{ +// tcg_out_insn_simpleReg(s, OPC_ADDW, TCG_REG_TMP, rn, TCG_REG_ZERO); +// tcg_out_insn_simpleReg(s, OPC_ADDW, TCG_REG_TMP2, rm, TCG_REG_ZERO); +// +// /* read fpcr */ +// tcg_out_insn_simpleReg(s, OPC_RFPCR, TCG_REG_ZERO, TCG_FLOAT_TMP, TCG_REG_ZERO); +// +// /* push fpcr */ +// tcg_out_insn_ldst(s, OPC_LDI, TCG_REG_SP, TCG_REG_SP, -8); +// tcg_out_insn_ldst(s, OPC_FSTD, TCG_FLOAT_TMP, TCG_REG_SP, 0); +// +// /* set fpcr[1:0]=11 */ +// tcg_out_insn_simpleReg(s, OPC_SETFPEC3, TCG_REG_ZERO, TCG_REG_ZERO, TCG_REG_ZERO); +// +// /* GPR(integrate) to FReg(double) */ +// tcg_out_insn_simpleReg(s, OPC_IFMOVD, TCG_FLOAT_TMP, TCG_REG_TMP, TCG_REG_ZERO); +// tcg_out_insn_simpleReg(s, OPC_IFMOVD, TCG_FLOAT_TMP2, TCG_REG_TMP2, TCG_REG_ZERO); +// +// tcg_out_insn_simpleReg(s, OPC_FCVTLD, TCG_FLOAT_TMP, TCG_REG_ZERO, TCG_FLOAT_TMP); +// tcg_out_insn_simpleReg(s, OPC_FCVTLD, TCG_FLOAT_TMP2, TCG_REG_ZERO,TCG_FLOAT_TMP2); +// +// /* FReg(double) div */ +// tcg_out_insn_simpleReg(s, OPC_FDIVD, TCG_FLOAT_TMP, TCG_FLOAT_TMP, TCG_FLOAT_TMP2); +// +// tcg_out_insn_simpleReg(s, OPC_FCVTDL_Z, TCG_FLOAT_TMP, TCG_REG_ZERO, TCG_FLOAT_TMP); +// +// /* FReg(double) to GPR(integrate) */ +// tcg_out_insn_simpleReg(s, OPC_FIMOVD, rd, TCG_REG_ZERO, TCG_FLOAT_TMP); +// +// /* pop fpcr */ +// tcg_out_insn_simpleReg(s, OPC_FLDD, TCG_FLOAT_TMP, TCG_REG_SP, 0); +// tcg_out_insn_ldst(s, OPC_LDI, TCG_REG_SP, TCG_REG_SP, 8); +// +// /* restore fpcr */ +// tcg_out_insn_simpleReg(s, OPC_RFPCR, TCG_FLOAT_TMP, TCG_FLOAT_TMP, TCG_FLOAT_TMP); +// +// /* set fpcr[1:0]=00 */ +// tcg_out_insn_simpleReg(s, OPC_SETFPEC0, TCG_REG_ZERO, TCG_REG_ZERO, TCG_REG_ZERO); +//} + +typedef struct { + DebugFrameHeader h; + uint8_t fde_def_cfa[4]; + uint8_t fde_reg_ofs[8 * 2]; +} DebugFrame; + +#define ELF_HOST_MACHINE EM_SW_64 +/* GDB doesn't appear to require proper setting of ELF_HOST_FLAGS, + which is good because they're really quite complicated for MIPS. */ + +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..4bc1e4601d76783eb48923edeb1f6ab969fbfe87 --- /dev/null +++ b/tcg/sw64/tcg-target.h @@ -0,0 +1,123 @@ +/* + * Initial TCG Implementation for sw_64 + * + */ + +#ifndef SW_64_TCG_TARGET_H +#define SW_64_TCG_TARGET_H + +#define TCG_TARGET_INSN_UNIT_SIZE 4 + +typedef enum { + TCG_REG_X0, TCG_REG_X1, TCG_REG_X2, TCG_REG_X3, + TCG_REG_X4, TCG_REG_X5, TCG_REG_X6, TCG_REG_X7, + TCG_REG_X8, TCG_REG_X9, TCG_REG_X10, TCG_REG_X11, + TCG_REG_X12, TCG_REG_X13, TCG_REG_X14, TCG_REG_X15, + TCG_REG_X16, TCG_REG_X17, TCG_REG_X18, TCG_REG_X19, + TCG_REG_X20, TCG_REG_X21, TCG_REG_X22, TCG_REG_X23, + TCG_REG_X24, TCG_REG_X25, TCG_REG_X26, TCG_REG_X27, + TCG_REG_X28, TCG_REG_X29, TCG_REG_X30, TCG_REG_X31, + + TCG_REG_F0=32, TCG_REG_F1, TCG_REG_F2, TCG_REG_F3, + TCG_REG_F4, TCG_REG_F5, TCG_REG_F6, TCG_REG_F7, + TCG_REG_F8, TCG_REG_F9, TCG_REG_F10, TCG_REG_F11, + TCG_REG_F12, TCG_REG_F13, TCG_REG_F14, TCG_REG_F15, + TCG_REG_F16, TCG_REG_F17, TCG_REG_F18, TCG_REG_F19, + TCG_REG_F20, TCG_REG_F21, TCG_REG_F22, TCG_REG_F23, + TCG_REG_F24, TCG_REG_F25, TCG_REG_F26, TCG_REG_F27, + TCG_REG_F28, TCG_REG_F29, TCG_REG_F30, TCG_REG_F31, + + /* Aliases. */ + TCG_REG_FP = TCG_REG_X15, + TCG_REG_RA = TCG_REG_X26, + TCG_REG_GP = TCG_REG_X29, + TCG_REG_SP = TCG_REG_X30, + TCG_REG_ZERO = TCG_REG_X31, + TCG_AREG0 = TCG_REG_X9, +} TCGReg; + +#define TCG_TARGET_NB_REGS 64 +#define MAX_CODE_GEN_BUFFER_SIZE ((size_t)-1) + +/* used for function call generation */ +#define TCG_REG_CALL_STACK TCG_REG_SP +#define TCG_TARGET_STACK_ALIGN 16 +#define TCG_TARGET_CALL_ALIGN_ARGS 1 /*luo*/ +#define TCG_TARGET_CALL_STACK_OFFSET 0 /*luo*/ +#define TCG_TARGET_HAS_neg_i64 1 +#define TCG_TARGET_HAS_direct_jump 0 +#define TCG_TARGET_HAS_goto_ptr 1 +#define TCG_TARGET_HAS_qemu_st8_i32 0 +#define TCG_TARGET_HAS_not_i32 1 +#define TCG_TARGET_HAS_neg_i32 1 +#define TCG_TARGET_HAS_div_i32 1 +#define TCG_TARGET_HAS_movcond_i32 1 +#define TCG_TARGET_HAS_rem_i32 0 +#define TCG_TARGET_HAS_rot_i32 1 +#define TCG_TARGET_HAS_deposit_i32 1 +#define TCG_TARGET_HAS_extract_i32 1 +#define TCG_TARGET_HAS_sextract_i32 0 +#define TCG_TARGET_HAS_extract2_i32 0 +#define TCG_TARGET_HAS_add2_i32 0 +#define TCG_TARGET_HAS_sub2_i32 0 +#define TCG_TARGET_HAS_sub2_i32 0 +#define TCG_TARGET_HAS_mulu2_i32 0 +#define TCG_TARGET_HAS_muluh_i32 0 +#define TCG_TARGET_HAS_muls2_i32 0 +#define TCG_TARGET_HAS_not_i32 1 +#define TCG_TARGET_HAS_mulsh_i32 0 +#define TCG_TARGET_HAS_ext8s_i32 0 +#define TCG_TARGET_HAS_ext16s_i32 0 +#define TCG_TARGET_HAS_ext8u_i32 1 +#define TCG_TARGET_HAS_ext16u_i32 1 +#define TCG_TARGET_HAS_bswap16_i32 0 +#define TCG_TARGET_HAS_bswap32_i32 0 +#define TCG_TARGET_HAS_andc_i32 0 +#define TCG_TARGET_HAS_eqv_i32 0 +#define TCG_TARGET_HAS_nand_i32 0 +#define TCG_TARGET_HAS_nor_i32 0 +#define TCG_TARGET_HAS_clz_i32 0 +#define TCG_TARGET_HAS_ctz_i32 0 +#define TCG_TARGET_HAS_orc_i32 0 +#define TCG_TARGET_HAS_ctpop_i32 0 +#define TCG_TARGET_HAS_movcond_i64 1 +#define TCG_TARGET_HAS_div_i64 1 +#define TCG_TARGET_HAS_rem_i64 0 +#define TCG_TARGET_HAS_div2_i64 0 +#define TCG_TARGET_HAS_rot_i64 1 +#define TCG_TARGET_HAS_deposit_i64 1 +#define TCG_TARGET_HAS_extract_i64 1 +#define TCG_TARGET_HAS_sextract_i64 0 +#define TCG_TARGET_HAS_extract2_i64 0 +#define TCG_TARGET_HAS_extrl_i64_i32 0 +#define TCG_TARGET_HAS_extrh_i64_i32 0 +#define TCG_TARGET_HAS_ext8s_i64 0 +#define TCG_TARGET_HAS_ext16s_i64 0 +#define TCG_TARGET_HAS_ext32s_i64 1 +#define TCG_TARGET_HAS_ext8u_i64 1 +#define TCG_TARGET_HAS_ext16u_i64 1 +#define TCG_TARGET_HAS_ext32u_i64 1 +#define TCG_TARGET_HAS_bswap16_i64 0 +#define TCG_TARGET_HAS_bswap32_i64 0 +#define TCG_TARGET_HAS_bswap64_i64 0 +#define TCG_TARGET_HAS_not_i64 1 +#define TCG_TARGET_HAS_andc_i64 0 +#define TCG_TARGET_HAS_orc_i64 1 +#define TCG_TARGET_HAS_eqv_i64 0 +#define TCG_TARGET_HAS_nand_i64 0 +#define TCG_TARGET_HAS_nor_i64 0 +#define TCG_TARGET_HAS_clz_i64 1 +#define TCG_TARGET_HAS_ctz_i64 1 +#define TCG_TARGET_HAS_ctpop_i64 0 +#define TCG_TARGET_HAS_add2_i64 0 +#define TCG_TARGET_HAS_sub2_i64 0 +#define TCG_TARGET_HAS_mulu2_i64 0 +#define TCG_TARGET_HAS_muls2_i64 0 +#define TCG_TARGET_HAS_muluh_i64 1 +#define TCG_TARGET_HAS_mulsh_i64 1 +#define TCG_TARGET_DEFAULT_MO (0) +#define TCG_TARGET_HAS_MEMORY_BSWAP 0 +/* optional instructions */ +void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t); +#define TCG_TARGET_NEED_POOL_LABELS +#endif /* SW_64_TCG_TARGET_H */ diff --git a/tcg/sw64/tcg-target.opc.h b/tcg/sw64/tcg-target.opc.h new file mode 100755 index 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)