[PATCH v2 3/6] Opcodes changes for nanoMIPS support.
"Tsing" <[email protected]> Fri, 24 Jul 2026 18:30:55 +0800
| Newsgroups | gmane.comp.gnu.binutils |
|---|---|
| Message-ID | <[email protected]> |
From: tsing <[email protected]> include/ * dis-asm.h: Add prototypes for print_insn_nanomips and print_nanomips_disassembler_options. * opcode/nanomips.h: New file. opcodes/ * Makefile.am: Add nanoMIPS target. * Makefile.in: Regenerate. * configure: Add entry for bfd_nanomips_arch. * configure.ac: Regenerate. * disassemble.c (disassembler): Add support for naonmips. (disassembler_usage): Likewise. * nanomips-dis.c: New file. * nanomips-formats.h: New file. * nanomips-opc.c: New file. --- include/dis-asm.h | 1 + include/opcode/nanomips.h | 1238 ++++++++++++++++++++++++++++++++ opcodes/Makefile.am | 2 + opcodes/Makefile.in | 4 + opcodes/configure | 1 + opcodes/configure.ac | 1 + opcodes/disassemble.c | 14 + opcodes/disassemble.h | 1 + opcodes/nanomips-dis.c | 1394 ++++++++++++++++++++++++++++++++++++ opcodes/nanomips-formats.h | 265 +++++++ opcodes/nanomips-opc.c | 807 +++++++++++++++++++++ 11 files changed, 3728 insertions(+) create mode 100644 include/opcode/nanomips.h create mode 100644 opcodes/nanomips-dis.c create mode 100644 opcodes/nanomips-formats.h create mode 100644 opcodes/nanomips-opc.c diff --git a/include/dis-asm.h b/include/dis-asm.h index c3d5d8c5438..4dcddefe420 100644 --- a/include/dis-asm.h +++ b/include/dis-asm.h @@ -386,6 +386,7 @@ extern disassembler_ftype cris_get_disassembler (bfd *); extern void print_aarch64_disassembler_options (FILE *); extern void print_i386_disassembler_options (FILE *); extern void print_mips_disassembler_options (FILE *); +extern void print_nanomips_disassembler_options (FILE *); extern void print_nfp_disassembler_options (FILE *); extern void print_ppc_disassembler_options (FILE *); extern void print_riscv_disassembler_options (FILE *); diff --git a/include/opcode/nanomips.h b/include/opcode/nanomips.h new file mode 100644 index 00000000000..fb9d7b0ee9b --- /dev/null +++ b/include/opcode/nanomips.h @@ -0,0 +1,1238 @@ +/* nanomips.h. nanoMIPS opcode list for GDB, the GNU debugger. + Copyright (C) 2017-2026 Free Software Foundation, CIP United Inc. + Contributed by MIPS Tech LLC. + Written by Faraz Shahbazker <[email protected]> + + 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 _NANOMIPS_H_ +#define _NANOMIPS_H_ + +#include "bfd.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Enumerates the various types of nanoMIPS operand. */ +enum nanomips_operand_type { + /* Described by nanomips_int_operand. */ + OP_INT, + + /* Described by nanomips_mapped_int_operand. */ + OP_MAPPED_INT, + + /* Described by nanomips_msb_operand. */ + OP_MSB, + + /* Described by nanomips_reg_operand. */ + OP_REG, + + /* Like OP_REG, but can be omitted if the register is the same as the + previous operand. */ + OP_OPTIONAL_REG, + + /* Described by nanomips_reg_pair_operand. */ + OP_REG_PAIR, + + /* Described by nanomips_pcrel_operand. */ + OP_PCREL, + + /* The register list and frame size for a MIPS16 SAVE or RESTORE + instruction. */ + OP_SAVE_RESTORE_LIST, + + /* A register operand that must match the destination register. */ + OP_REPEAT_DEST_REG, + + /* A register operand that must match the previous register. */ + OP_REPEAT_PREV_REG, + + /* Described by nanomips_prev_operand. */ + OP_CHECK_PREV, + + /* A register operand that must not be zero. */ + OP_NON_ZERO_REG, + + /* The floating-point register list for a nanoMIPS SAVE or RESTORE + instruction. */ + OP_SAVE_RESTORE_FP_LIST, + + /* Fractured upper immediate PC-offset for nanoMIPS */ + OP_HI20_PCREL, + + /* Fractured upper immediate 20-bit signed integer for nanoMIPS */ + OP_HI20_INT, + + /* Fractured upper immediate 20-bit scaled integer for nanoMIPS */ + OP_HI20_SCALE, + + /* A non-zero PC-relative offset. */ + OP_NON_ZERO_PCREL_S1, + + /* To check a mapped register against a previous operand. */ + OP_MAPPED_CHECK_PREV, + + /* Unsigned word operand. */ + OP_UINT_WORD, + + /* Signed word operand. */ + OP_INT_WORD, + + /* Immediate PC-relative word operand. */ + OP_PC_WORD, + + /* Immediate GP-relative word operand. */ + OP_GPREL_WORD, + + /* Don't care bits. */ + OP_DONT_CARE, + + /* Immediate unsigned word operand, to be negated. */ + OP_NEG_INT, + + /* Immediate (non-relocatable) integer operand. */ + OP_IMM_INT, + + /* Immediate (non-relocatable) word operand. */ + OP_IMM_WORD, + + /* Base register for limited types of offsets. */ + OP_BASE_CHECK_OFFSET, + + /* Copy over bits from another part of instruction. */ + OP_COPY_BITS, + + /* Select bits for a COP0 register. */ + OP_CP0SEL, +}; + +/* Enumerates the types of nanoMIPS register. */ +enum nanomips_reg_operand_type { + /* General registers $0-$31. Software names like $at can also be used. */ + OP_REG_GP, + + /* Floating-point registers $f0-$f31. */ + OP_REG_FP, + + /* DSP accumulator registers $ac0-$ac3. */ + OP_REG_ACC, + + /* Coprocessor registers in numeric format, $0-$31. */ + OP_REG_COPRO, + + /* Hardware registers $0-$31. Mnemonic names like hwr_cpunum can + also be used in some contexts. */ + OP_REG_HW, + + /* Co-processor 0 named registers. */ + OP_REG_CP0, + + /* Co-processor 0 named registers with select. */ + OP_REG_CP0SEL +}; + +/* Base class for all operands. */ +struct nanomips_operand +{ + /* The type of the operand. */ + enum nanomips_operand_type type; + + /* The operand occupies SIZE bits of the instruction, starting at LSB. */ + unsigned short size; + unsigned short lsb; + + /* These are used to split a value across two different + parts of the instruction encoding. */ + unsigned int size_top; + unsigned int lsb_top; +}; + +/* Describes an integer operand with a regular encoding pattern. */ +struct nanomips_int_operand +{ + struct nanomips_operand root; + + /* The low ROOT.SIZE bits of MAX_VAL encodes (MAX_VAL + BIAS) << SHIFT. + The cyclically previous field value encodes 1 << SHIFT less than that, + and so on. E.g. + + - for { { T, 4, L }, 14, 0, 0 }, field values 0...14 encode themselves, + but 15 encodes -1. + + - { { T, 8, L }, 127, 0, 2 } is a normal signed 8-bit operand that is + shifted left two places. + + - { { T, 3, L }, 8, 0, 0 } is a normal unsigned 3-bit operand except + that 0 encodes 8. + + - { { ... }, 0, 1, 3 } means that N encodes (N + 1) << 3. */ + unsigned int max_val; + int bias; + unsigned int shift; + + /* True if the operand should be printed as hex rather than decimal. */ + bool print_hex; +}; + +/* Uses a lookup table to describe a small integer operand. */ +struct nanomips_mapped_int_operand +{ + struct nanomips_operand root; + + /* Maps each encoding value to the integer that it represents. */ + const int *int_map; + + /* True if the operand should be printed as hex rather than decimal. */ + bool print_hex; +}; + +/* An operand that encodes the most significant bit position of a bitfield. + Given a bitfield that spans bits [MSB, LSB], some operands of this type + encode MSB directly while others encode MSB - LSB. Each operand of this + type is preceded by an integer operand that specifies LSB. + + The assembly form varies between instructions. For some instructions, + such as EXT, the operand is written as the bitfield size. For others, + such as EXTS, it is written in raw MSB - LSB form. */ +struct nanomips_msb_operand +{ + struct nanomips_operand root; + + /* The assembly-level operand encoded by a field value of 0. */ + int bias; + + /* True if the operand encodes MSB directly, false if it encodes + MSB - LSB. */ + bool add_lsb; + + /* The maximum value of MSB + 1. */ + unsigned int opsize; +}; + +/* Describes a single register operand. */ +struct nanomips_reg_operand +{ + struct nanomips_operand root; + + /* The type of register. */ + enum nanomips_reg_operand_type reg_type; + + /* If nonnull, REG_MAP[N] gives the register associated with encoding N, + otherwise the encoding is the same as the register number. */ + const unsigned char *reg_map; +}; + +/* Describes an operand that which must match a condition based on the + previous operand. */ +struct nanomips_check_prev_operand +{ + struct nanomips_operand root; + + bool greater_than_ok; + bool less_than_ok; + bool equal_ok; + bool zero_ok; +}; + +/* Describes an operand that encodes a pair of registers. */ +struct nanomips_reg_pair_operand +{ + struct nanomips_operand root; + + /* The type of register. */ + enum nanomips_reg_operand_type reg_type; + + /* Encoding N represents REG1_MAP[N], REG2_MAP[N]. */ + unsigned char *reg1_map; + unsigned char *reg2_map; +}; + +/* Describes an operand that is calculated relative to a base PC. + The base PC is usually the address of the following instruction, + but the rules for MIPS16 instructions like ADDIUPC are more complicated. */ +struct nanomips_pcrel_operand +{ + /* Encodes the offset. */ + struct nanomips_int_operand root; + + /* The low ALIGN_LOG2 bits of the base PC are cleared to give PC', + which is then added to the offset encoded by ROOT. */ + unsigned int align_log2 : 8; + + /* If INCLUDE_ISA_BIT, the ISA bit of the original base PC is then + reinstated. This is true for jumps and branches and false for + PC-relative data instructions. */ + unsigned int include_isa_bit : 1; + + /* If FLIP_ISA_BIT, the ISA bit of the result is inverted. + This is true for JALX and false otherwise. */ + unsigned int flip_isa_bit : 1; +}; + +/* This structure holds information for a particular instruction. */ + +struct nanomips_opcode +{ + /* The name of the instruction. */ + const char *name; + /* An optional suffix. */ + const char *suffix; + /* A string describing the arguments for this instruction. */ + const char *args; + /* The basic opcode for the instruction. When assembling, this + opcode is modified by the arguments to produce the actual opcode + that is used. If pinfo is INSN_MACRO, then this is 0. */ + unsigned long match; + /* If pinfo is not INSN_MACRO, then this is a bit mask for the + relevant portions of the opcode when disassembling. If the + actual opcode anded with the match field equals the opcode field, + then we have found the correct instruction. If pinfo is + INSN_MACRO, then this field is the macro identifier. */ + unsigned long mask; + /* For a macro, this is INSN_MACRO. Otherwise, it is a collection + of bits describing the instruction, notably any relevant hazard + information. */ + unsigned long pinfo; + /* A collection of additional bits describing the instruction. */ + unsigned long pinfo2; + /* A collection of bits describing the instruction sets of which this + instruction or macro is a member. */ + unsigned long membership; + /* A collection of bits describing the ASE of which this instruction + or macro is a member. */ + unsigned long ase; +}; + +/* Return true if the assembly syntax allows OPERAND to be omitted. */ + +static inline bool +nanomips_optional_operand_p (const struct nanomips_operand *operand) +{ + return (operand->type == OP_OPTIONAL_REG + || operand->type == OP_REPEAT_PREV_REG + || (operand->type != OP_INT + && operand->size == 0 + && operand->lsb == 0)); +} + +/* Return a version of INSN in which the field specified by OPERAND + has value UVAL. */ + +static inline unsigned int +nanomips_insert_operand (const struct nanomips_operand *operand, + unsigned int insn, unsigned int uval) +{ + unsigned int mask; + unsigned int size_bottom = operand->size - operand->size_top; + + mask = (1 << size_bottom) - 1; + insn &= ~(mask << operand->lsb); + insn |= (uval & mask) << operand->lsb; + + mask = (1 << operand->size_top) - 1; + insn &= ~(mask << operand->lsb_top); + insn |= ((uval & (mask << size_bottom)) >> size_bottom) << operand->lsb_top; + return insn; +} + +/* Extract OPERAND from instruction INSN. */ + +static inline unsigned int +nanomips_extract_operand (const struct nanomips_operand *operand, + unsigned int insn) +{ + unsigned int uval; + unsigned int size_bottom = operand->size - operand->size_top; + + uval = (insn >> operand->lsb_top) & ((1 << operand->size_top) - 1); + uval <<= size_bottom; + uval |= (insn >> operand->lsb) & ((1 << size_bottom) - 1); + return uval; +} + +/* UVAL is the value encoded by OPERAND. Return it in signed form. */ + +static inline int +nanomips_signed_operand (const struct nanomips_operand *operand, + unsigned int uval) +{ + unsigned int sign_bit, mask; + + mask = (1 << operand->size) - 1; + sign_bit = 1 << (operand->size - 1); + return ((uval + sign_bit) & mask) - sign_bit; +} + +/* Return the integer that OPERAND encodes as UVAL. */ + +static inline int +nanomips_decode_int_operand (const struct nanomips_int_operand *operand, + unsigned int uval) +{ + uval |= (operand->max_val - uval) & -(1 << operand->root.size); + uval += operand->bias; + uval <<= operand->shift; + return uval; +} + +/* Return the maximum value that can be encoded by OPERAND. */ + +static inline int +nanomips_int_operand_max (const struct nanomips_int_operand *operand) +{ + return (operand->max_val + operand->bias) << operand->shift; +} + +/* Return the minimum value that can be encoded by OPERAND. */ + +static inline int +nanomips_int_operand_min (const struct nanomips_int_operand *operand) +{ + unsigned int mask; + + mask = (1 << operand->root.size) - 1; + return nanomips_int_operand_max (operand) - (mask << operand->shift); +} + +/* Return the register that OPERAND encodes as UVAL. */ + +static inline int +nanomips_decode_reg_operand (const struct nanomips_reg_operand *operand, + unsigned int uval) +{ + if (operand->reg_map) + uval = operand->reg_map[uval]; + return uval; +} + +/* PC-relative operand OPERAND has value UVAL and is relative to BASE_PC. + Return the address that it encodes. */ + +static inline bfd_vma +nanomips_decode_pcrel_operand (const struct nanomips_pcrel_operand *operand, + bfd_vma base_pc, unsigned int uval) +{ + bfd_vma addr; + + addr = base_pc & -(1 << operand->align_log2); + addr += nanomips_decode_int_operand (&operand->root, uval); + if (operand->include_isa_bit) + addr |= base_pc & 1; + if (operand->flip_isa_bit) + addr ^= 1; + return addr; +} + +/* Describes an operand that encapsulates a mapped register with + a check against the previous operand. */ +struct nanomips_mapped_check_prev_operand +{ + struct nanomips_operand root; + + enum nanomips_reg_operand_type reg_type; + const unsigned char *reg_map; + + bool greater_than_ok; + bool less_than_ok; + bool equal_ok; + bool zero_ok; +}; + +/* Describes an operand that encapsulates a base register with + a check against the type of offset. */ +struct nanomips_base_check_offset_operand +{ + struct nanomips_operand root; + + enum nanomips_reg_operand_type reg_type; + + bool const_ok; + bool expr_ok; +}; + +/* Return true if MO is an instruction that requires 32-bit encoding. */ + +static inline bool +nanomips_opcode_32bit_p (const struct nanomips_opcode *mo) +{ + return mo->mask >> 16 != 0; +} + +static inline int +nanomips_operand_mask (const struct nanomips_operand *operand) +{ + unsigned int mask; + + mask = ((1 << operand->size_top) - 1) << operand->lsb_top; + mask |= ((1 << (operand->size - operand->size_top)) - 1) << operand->lsb; + return mask; +} + +/* Return the UVAL encoding of REGNO as OPERAND. */ + +static inline unsigned int +nanomips_encode_reg_operand (const struct nanomips_operand *operand, + int regno) +{ + unsigned int uval; + const unsigned int num_vals = 1 << operand->size; + const struct nanomips_reg_operand *reg_op + = (const struct nanomips_reg_operand *) operand; + + for (uval = 0; uval < num_vals; uval++) + if (reg_op->reg_map[uval] == regno) + break; + return uval; +} + +/* Re-organize HI20 bits of OPERAND encoded as UVAL. */ + +#define SIGNEX_VALUE(OP) {OP_INT, OP->size - 1, 0, 0, 0} + +static inline int +nanomips_decode_hi20_operand (const struct nanomips_operand *operand, + unsigned int uval) +{ + const struct nanomips_operand op_ext = SIGNEX_VALUE (operand); + const struct nanomips_operand op_shuffle = {OP_INT, 19, 10, 10, 0}; + unsigned int low19 = nanomips_extract_operand (&op_shuffle, uval); + return nanomips_insert_operand (&op_ext, uval, low19); +} + +/* Decode HI20 signed integer. */ + +#define SIGNED_VALUE(OP) {OP_INT, OP->size, 0, 0, 0} + +static inline int +nanomips_decode_hi20_int_operand (const struct nanomips_operand *operand, + unsigned int uval) +{ + const struct nanomips_operand op_enc = SIGNED_VALUE (operand); + uval = nanomips_decode_hi20_operand (operand, uval); + return (nanomips_signed_operand (&op_enc, uval)); +} + +/* Decode HI20 PCREL */ + +#define PCREL_VALUE(OP) { { { OP_PCREL, OP->size, 0, 0, 0}, \ + (1 << (OP->size - 1)) - 1, 0, 0, false}, 12, 0, 0} + +static inline bfd_vma +nanomips_decode_hi20_pcrel_operand (const struct nanomips_operand *operand, + bfd_vma base_pc, unsigned int uval) +{ + const struct nanomips_pcrel_operand pcrel_op = PCREL_VALUE (operand); + uval = nanomips_decode_hi20_operand (operand, uval); + return nanomips_decode_pcrel_operand (&pcrel_op, base_pc, uval << 12); +} + +/* Return true if MO is an instruction that requires 48-bit encoding. */ + +static inline bool +opcode_48bit_p (const struct nanomips_opcode *mo) +{ + return ((mo->mask >> 16 == 0) + && ((mo->match >> 10) == 0x18)); +} + +/* These are the bits which may be set in the pinfo field of an + instructions, if it is not equal to INSN_MACRO. */ + +/* Writes to operand number N. */ +#define INSN_WRITE_SHIFT 0 +#define INSN_WRITE_1 0x00000001 +#define INSN_WRITE_2 0x00000002 +#define INSN_WRITE_ALL 0x00000003 +/* Reads from operand number N. */ +#define INSN_READ_SHIFT 2 +#define INSN_READ_1 0x00000004 +#define INSN_READ_2 0x00000008 +#define INSN_READ_3 0x00000010 +#define INSN_READ_ALL 0x0000001c +/* Modifies general purpose register 31. */ +#define INSN_WRITE_GPR_31 0x00000020 +/* Reads coprocessor register other than floating point register. */ +#define INSN_COP 0x00000040 +/* Instruction loads value from memory. */ +#define INSN_LOAD_MEMORY 0x00000080 +/* Reads the accumulator register. */ +#define INSN_READ_ACC 0x00000100 +/* Modifies the HI register. */ +#define INSN_WRITE_ACC 0x00000200 +/* Instruction stores value into memory. */ +#define INSN_STORE_MEMORY 0x00000400 +/* Instruction uses single precision floating point. */ +#define INSN_FP_S 0x00000800 +/* Instruction uses double precision floating point. */ +#define INSN_FP_D 0x00001000 +/* A user-defined instruction. */ +#define INSN_UDI 0x00002000 +/* Instruction is actually a macro. It should be ignored by the + disassembler, and requires special treatment by the assembler. */ +#define INSN_MACRO 0xffffffff + +/* These are the bits which may be set in the pinfo2 field of an + instruction. */ + +/* Instruction is a simple alias (I.E. "move" for daddu/addu/or) */ +#define INSN2_ALIAS 0x00000001 +/* Macro uses single-precision floating-point instructions. This should + only be set for macros. For instructions, FP_S in pinfo carries the + same information. */ +#define INSN2_M_FP_S 0x00000002 +/* Macro uses double-precision floating-point instructions. This should + only be set for macros. For instructions, FP_D in pinfo carries the + same information. */ +#define INSN2_M_FP_D 0x00000004 +/* Is an unconditional branch insn. */ +#define INSN2_UNCOND_BRANCH 0x00000008 +/* Is a conditional branch insn. */ +#define INSN2_COND_BRANCH 0x00000010 +/* This indicates delayed branch converted to compact branch. */ +#define INSN2_CONVERTED_TO_COMPACT 0x00000020 +/* Marks the LI macro expansion as special, temporary. */ +#define INSN2_MACRO 0x00000040 + +/* Masks used to mark instructions to indicate which MIPS ISA level + they were introduced in. INSN_ISA_MASK masks an enumeration that + specifies the base ISA level(s). The remainder of a 32-bit + word constructed using these macros is a bitmask of the remaining + INSN_* values below. */ + +#define INSN_ISA_MASK 0x00000003ul + +/* We cannot start at zero due to ISA_UNKNOWN below. */ +#define INSN_ISAN32R6 1 +#define INSN_ISAN64R6 2 + +#define ISA_UNKNOWN 0 /* Gas internal use. */ + +#define ISA_NANOMIPS32R6 INSN_ISAN32R6 +#define ISA_NANOMIPS64R6 INSN_ISAN64R6 + +/* CPU defines, use instead of hardcoding processor number. Keep this + in sync with bfd/archures.c in order for machine selection to work. */ +#define CPU_UNKNOWN 0 /* Gas internal use. */ + +#define CPU_NANOMIPS32R6 32 +#define CPU_NANOMIPS64R6 64 + +#define ISAF(X) (1 << (INSN_ISA##X - 1)) + +/* The same information in table form: bit INSN_ISA<X> - 1 of index + INSN_UPTO<Y> - 1 is set if ISA Y includes ISA X. */ +static const unsigned int nanomips_isa_table[] = { + ISAF(N32R6), + ISAF(N32R6) | ISAF(N64R6) +}; +#undef ISAF + +/* MT ASE */ +#define ASE_MT 0x00000010 +/* Virtualization ASE */ +#define ASE_VIRT 0x00000020 +#define ASE_VIRT64 0x00000040 +/* Excluded for low power instruction subset for nanoMIPS. */ +#define ASE_xNMS 0x00002000 + +static inline bool +nanomips_cpu_is_member (int cpu, unsigned int mask) +{ + switch (cpu) + { + case CPU_NANOMIPS32R6: + return (mask & INSN_ISA_MASK) == INSN_ISAN32R6; + + case CPU_NANOMIPS64R6: + return ((mask & INSN_ISA_MASK) == INSN_ISAN32R6) + || ((mask & INSN_ISA_MASK) == INSN_ISAN64R6); + + default: + return false; + } +} + +/* Test for membership in an ISA including chip specific ISAs. INSN + is pointer to an element of the opcode table; ISA is the specified + ISA/ASE bitmask to test against; and CPU is the CPU specific ISA to + test, or zero if no CPU specific ISA test is desired. Return true + if instruction INSN is available to the given ISA and CPU. */ +static inline bool +nanomips_opcode_is_member (const struct nanomips_opcode *insn, + int isa, int ase, int cpu) +{ + /* Test for ISA level compatibility. */ + if ((isa & INSN_ISA_MASK) != 0 + && (insn->membership & INSN_ISA_MASK) != 0 + && ((nanomips_isa_table[(isa & INSN_ISA_MASK) - 1] + >> ((insn->membership & INSN_ISA_MASK) - 1)) & 1) != 0) + return true; + + /* Test for ASE compatibility. */ + if (insn->ase != 0 && (ase & insn->ase) == insn->ase) + return true; + + /* Test for processor-specific extensions. */ + if (nanomips_cpu_is_member (cpu, insn->membership)) + return true; + + return false; +} + +/* This is a list of macro expanded instructions. + + _I appended means immediate + _A appended means target address of a jump + _AB appended means address with (possibly zero) base register + _AC appended means either symbolic address with no base register + or constant offset with base register. + _D appended means 64 bit floating point constant + _S appended means 32 bit floating point constant. */ + +enum +{ + M_ABS, + M_ACLR_AC, + M_ADD_I, + M_ADDU_I, + M_AND_I, + M_ASET_AC, + M_BEQ, + M_BEQ_I, + M_BGE, + M_BGE_I, + M_BGEU, + M_BGEU_I, + M_BGEZ, + M_BGT, + M_BGT_I, + M_BGTU, + M_BGTU_I, + M_BGTZ, + M_BLE, + M_BLE_I, + M_BLEU, + M_BLEU_I, + M_BLEZ, + M_BLT, + M_BLT_I, + M_BLTU, + M_BLTU_I, + M_BLTZ, + M_BNE, + M_BNE_I, + M_CACHE_AC, + M_CACHEE_AC, + M_DABS, + M_DADD_I, + M_DADDU_I, + M_DLA_AB, + M_DLI, + M_DMUL, + M_DMUL_I, + M_DSUB_I, + M_DSUBU_I, + M_J_A, + M_JAL_A, + M_JRADDIUSP, + M_LA_AB, + M_LB_AC, + M_LBE_AC, + M_LBU_AC, + M_LBUE_AC, + M_LD_AC, + M_LDC1_AC, + M_LDC2_AC, + M_LDM_AC, + M_LH_AC, + M_LHE_AC, + M_LHU_AC, + M_LHUE_AC, + M_LI, + M_LI_D, + M_LI_DD, + M_LI_S, + M_LI_SS, + M_LL_AC, + M_LLD_AC, + M_LLE_AC, + M_LW_AC, + M_LWC1_AC, + M_LWC2_AC, + M_LWE_AC, + M_LWM_AC, + M_LWU_AC, + M_MUL, + M_MUL_I, + M_NOR_I, + M_OR_I, + M_PREF_AC, + M_PREFE_AC, + M_REM_3I, + M_DROL, + M_ROL, + M_DROL_I, + M_ROL_I, + M_ROR_I, + M_SC_AC, + M_SCD_AC, + M_SCE_AC, + M_SD_AC, + M_SDC1_AC, + M_SDC2_AC, + M_SDM_AC, + M_SEQ, + M_SEQ_I, + M_SGE, + M_SGE_I, + M_SGEU, + M_SGEU_I, + M_SGT, + M_SGT_I, + M_SGTU, + M_SGTU_I, + M_SLE, + M_SLE_I, + M_SLEU, + M_SLEU_I, + M_SLT_I, + M_SLTU_I, + M_SNE, + M_SNE_I, + M_SB_AC, + M_SBE_AC, + M_SH_AC, + M_SHE_AC, + M_SW_AC, + M_SWE_AC, + M_SWC1_AC, + M_SWC2_AC, + M_SWM_AC, + M_SUB_I, + M_SUBU_I, + M_TEQ_I, + M_TNE_I, + M_ULD_AC, + M_ULH_AC, + M_ULW_AC, + M_USH_AC, + M_USW_AC, + M_USD_AC, + M_XOR_I, + M_BGEZAL, + M_BLTZAL, + M_EXT, + M_INS, + M_MOD_I, + M_MODU_I, + M_DMOD_I, + M_DMODU_I, + M_DIV_I, + M_DIVU_I, + M_DDIV_I, + M_DDIVU_I, + M_NANOMIPS_NUM_MACROS +}; + +/* These are the bit masks and shift counts used for the different fields + in the nanoMIPS instruction formats. No masks are provided for the + fixed portions of an instruction, since they are not needed. */ + +#define NANOMIPSOP_MASK_RS 0x1f +#define NANOMIPSOP_SH_RS 16 +#define NANOMIPSOP_MASK_RT 0x1f +#define NANOMIPSOP_SH_RT 21 +#define NANOMIPSOP_SH_MC 4 +#define NANOMIPSOP_SH_MD 7 +#define NANOMIPSOP_SH_MP 5 +#define NANOMIPSOP_SH_MM 7 + +#define NANOMIPSOP_SH_CP0SEL 5 +#define NANOMIPSOP_MASK_CP0SEL 0x1f + +/* Describes a COP0 named register with a fixed select. */ +struct nanomips_cp0_name +{ + const char *name; + unsigned int num; + unsigned int sel; +}; + +/* The reference list of COP0 named register with fixed selects. */ +static const struct nanomips_cp0_name nanomips_cp0_3264r6[] = { + {"$index", 0, 0}, + {"$mvpcontrol", 0, 1}, + {"$mvpconf0", 0, 2}, + {"$mvpconf1", 0, 3}, + {"$vpcontrol", 0, 4}, + {"$random", 1, 0}, + {"$vpecontrol", 1, 1}, + {"$vpeconf0", 1, 2}, + {"$vpeconf1", 1, 3}, + {"$yqmask", 1, 4}, + {"$vpeschedule", 1, 5}, + {"$vpeschefback", 1, 6}, + {"$vpeopt", 1, 7}, + {"$entrylo0", 2, 0}, + {"$tcstatus", 2, 1}, + {"$tcbind", 2, 2}, + {"$tcrestart", 2, 3}, + {"$tchalt", 2, 4}, + {"$tccontext", 2, 5}, + {"$tcschedule", 2, 6}, + {"$tcschefback", 2, 7}, + {"$entrylo1", 3, 0}, + {"$tcopt", 3, 7}, + {"$context", 4, 0}, + {"$contextconfig", 4, 1}, + {"$userlocal", 4, 2}, + {"$xcontextconfig", 4, 3}, + {"$pagemask", 5, 0}, + {"$pagegrain", 5, 1}, + {"$segctl0", 5, 2}, + {"$segctl1", 5, 3}, + {"$segctl2", 5, 4}, + {"$pwbase", 5, 5}, + {"$pwfield", 5, 6}, + {"$pwsize", 5, 7}, + {"$wired", 6, 0}, + {"$srsconf0", 6, 1}, + {"$srsconf1", 6, 2}, + {"$srsconf2", 6, 3}, + {"$srsconf3", 6, 4}, + {"$srsconf4", 6, 5}, + {"$pwctl", 6, 6}, + {"$hwrena", 7, 0}, + {"$badvaddr", 8, 0}, + {"$badinst", 8, 1}, + {"$badinstrp", 8, 2}, + {"$count", 9, 0}, + {"$entryhi", 10, 0}, + {"$guestctl1", 10, 4}, + {"$guestctl2", 10, 5}, + {"$guestctl3", 10, 6}, + {"$compare", 11, 0}, + {"$guestctl0ext", 11, 4}, + {"$status", 12, 0}, + {"$intctl", 12, 1}, + {"$srsctl", 12, 2}, + {"$srsmap", 12, 3}, + {"$view_ipl", 12, 4}, + {"$srsmap2", 12, 5}, + {"$guestctl0", 12, 6}, + {"$gtoffset", 12, 7}, + {"$cause", 13, 0}, + {"$view_ripl", 13, 4}, + {"$nestedexc", 13, 5}, + {"$epc", 14, 0}, + {"$nestedepc", 14, 2}, + {"$prid", 15, 0}, + {"$ebase", 15, 1}, + {"$cdmmbase", 15, 2}, + {"$cmgcrbase", 15, 3}, + {"$config", 16, 0}, + {"$config1", 16, 1}, + {"$config2", 16, 2}, + {"$config3", 16, 3}, + {"$config4", 16, 4}, + {"$config5", 16, 5}, + {"$lladdr", 17, 0}, + {"$xcontext", 20, 0}, + {"$debug", 23, 0}, + {"$tracecontrol", 23, 1}, + {"$tracecontrol2", 23, 2}, + {"$usertracedata1", 23, 3}, + {"$traceibpc", 23, 4}, + {"$tracedbpc", 23, 5}, + {"$debug2", 23, 6}, + {"$depc", 24, 0}, + {"$tracecontrol3", 24, 2}, + {"$usertracedata2", 24, 3}, + {"$errctl", 26, 0}, + {"$cacheerr", 27, 0}, + {"$errorepc", 30, 0}, + {"$desave", 31, 0}, + {"$kscratch1", 31, 2}, + {"$kscratch2", 31, 3}, + {"$kscratch3", 31, 4}, + {"$kscratch4", 31, 5}, + {"$kscratch5", 31, 6}, + {"$kscratch6", 31, 7}, + {NULL, 0, 0} +}; + +/* Describes a CP0 named register which permits various select values. */ + struct nanomips_cp0_select +{ + const char *name; + unsigned int num; + unsigned int selmask; +}; + +/* Currently recognized CP0 select patterns. */ + +#define NANOMIPS_CP0SEL_MASK_EVEN 0x55555555 +#define NANOMIPS_CP0SEL_MASK_ODD 0xaaaaaaaa +#define NANOMIPS_CP0SEL_MASK_ANY 0xffffffff + +/* The reference list of CP0 named register with variable selects. */ +static const struct nanomips_cp0_select nanomips_cp0sel_3264r6[] = { + {"$watchlo", 18, NANOMIPS_CP0SEL_MASK_ANY}, + {"$watchhi", 19, NANOMIPS_CP0SEL_MASK_ANY}, + {"$perfctl", 25, NANOMIPS_CP0SEL_MASK_EVEN}, + {"$perfcnt", 25, NANOMIPS_CP0SEL_MASK_ANY}, + {"$taglo", 28, NANOMIPS_CP0SEL_MASK_EVEN}, + {"$datalo", 28, NANOMIPS_CP0SEL_MASK_ODD}, + {"$taghi", 29, NANOMIPS_CP0SEL_MASK_EVEN}, + {"$datahi", 29, NANOMIPS_CP0SEL_MASK_ODD}, + {NULL, 0, 0} +}; + +/* These are the characters which may appears in the args field of a nanoMIPS + instruction. They appear in the order in which the fields appear when the + instruction is used. Commas and parentheses in the args string are ignored + when assembling, and written into the output when disassembling. + + Operands for 16-bit nanoMIPS instructions. + + "ma" must be $28 + "mb" 5-bit non-zero GP register at bit 5 + "mc" 3-bit nanoMIPS registers 4-7, 16-19 bit 4 + The same register used as both source and target. + "md" 3-bit nanoMIPS registers 4-7, 16-19 at bit 7 + "me" 3-bit nanoMIPS registers 4-7, 16-19 at bit 1 + "mf" 3-bit nanoMIPS register 4-7, 16-19 at bit 7. + Must be larger than the last seen register. + "mg" 3-bit nanoMIPS register 4-7, 16-19 at bit 4. + Must be smaller than the last seen register. + "mh" 3-bit nanoMIPS register 4-7, 16-19 at bit 7. + Must be at least as large as the last seen register. + "mi" 3-bit nanoMIPS register 4-7, 16-19 at bit 4. + May be at most as large as the last seen register. + + "mj" 5-bit nanoMIPS registers at bit 0 + "mk" must be the same as the destination register + "ml" 3-bit nanoMIPS registers 4-7, 16-19 at bit 4 + "mm" 3-bit nanoMIPS registers 0, 4-7, 17-19 at bit 7 + "mn" 5-bit encoding of a save/restore register list + "mp" 5-bit nanoMIPS registers at bit 5 + "mq" 2-bit pair at bits [8,3] maps to ($a0,$a1), ($a1,$a2), ($a2,$a3) + or ($a3,$a4) + "mr" 2-bit pair at bits [8,3] maps to ($a1,$a0), ($a2,$a1), ($a3,$a2) + or ($a4,$a3) + "ms" must be $29 + "mt" must be the same as the previous register + "mu" 4-bit encoding of nanoMIPS destination register at bit 5 + "mv" 4-bit encoding of nanoMIPS destination register at bit 0 + "mw" 4-bit encoding of nanoMIPS source register at bit 5 + "mx" 4-bit encoding of nanoMIPS source register at bit 0 + "my" must be $31 + "mz" must be literal 0 + + "mA" 7-bit relocatable GP offset (0 .. 127) << 2 + "mB" 3-bit immediate at bit 0 (0, 4, 8, 12, 16, 20, 24, 28) + "mC" 4-bit immediate at bit 0 (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 65535, 14, 15) + "mD" 10-bit signed branch address, split & scaled at bit 0 [S9:1,S10] + "mE" 7-bit signed branch address, split & scaled at bit 0 [S6:1,S7] + "mF" 4-bit unsigned branch address, scaled at bit 0 [U4:U1] + "mG" 4-bit scaled immediate at bit 4, (0 .. 15) << 4 + "mH" 2-bit scaled immediate at bit 1, (0 .. 3) << 1 + "mI" 7-bit immediate at bit 0, (-1 .. 126) + "mJ" 4-bit scaled immediate at bit 0, (0 .. 15) << 2 + "mK" 3-bit BREAK/SDBBP code at bit 0 + "mL" 2-bit immediate at bit 0, (0 .. 3) + "mM" 3-bit immediate at bit 0, (1 .. 8) + "mN" 2-bit split scaled immediate at bits 8 & 3 (0 .. 3) << 2 + "mO" 7-bit immediate GP offset at bit 0, (0 .. 127) << 2 + "mP" 2-bit SYSCALL/HYPCALL code at bit 0 + "mQ" 4-bit immediate signed offset, (s3,s2:s0) + "mR" 5-bit immediate at bit 0, (0 .. 31) << 2 + "mS" 6-bit immediate at bit 0, (0 .. 63) << 2 + "mZ" must be zero + + Operands for 32-bit nanoMIPS instructions. + + "+1" 18-bit unsigned GP-relative offset, (u17:u0) + "+2" 18-bit scaled GP-relative offset, (u18:u2) << 2 + "+3" 21-bit scaled GP-relative offset, (u18:u1) << 1 + "+4" 18-bit GP-relative offset, (0 .. 2^18-1) << 3 + "+5" 4-bit encoding of nanoMIPS source register at bit 21 + "+6" 5-bit mask encoding, corresponding to (1 << X) - 1 + "+7" 1-bit register at bit 24, (0,1) => ($a0,$a1) + "+8" 23-bit un-spec'ed value at bit 3 for UDIs. + "+9" 7-bit immediate at bit 11, (0 .. 127) + + "+A" 5-bit INS/EXT/DINS/DEXT/DINSM/DEXTM position, which becomes + LSB. + "+B" 5-bit INS/DINS size, which becomes MSB + Requires that "+A" or "+E" occur first to set position. + Enforces: 0 < (pos+size) <= 32. + "+C" 5-bit EXT/DEXT size, which becomes MSBD. + Requires that "+A" or "+E" occur first to set position. + Enforces: 0 < (pos+size) <= 32. + "+D" 4-bit encoding of a floating point save/restore register list + "+E" 5-bit DINSU/DEXTU position, which becomes LSB-32. + "+F" 5-bit DINSM/DINSU size, which becomes MSB-32. + Requires that "+A" or "+E" occur first to set position. + Enforces: 32 < (pos+size) <= 64. + "+G" 5-bit DEXTM size, which becomes MSBD-32. + Requires that "+A" or "+E" occur first to set position. + Enforces: 32 < (pos+size) <= 64. + "+H" 5-bit DEXTU size, which becomes MSBD. + Requires that "+A" or "+E" occur first to set position. + Enforces: 32 < (pos+size) <= 64. + "+I" 5-bit EXTW/EXTD/PREPEND position, which becomes LSB. + "+J" 19-bit BREAK/SDBBP function code at bit 0 + "+K" Tri-part upper 20-bits of immediate value. + "+L" 10-bit WAIT code at bit 16 + "+M" 18-bit SYSCALL/HYPCALL code at bit 0 + "+N" 9-bit immediate at bit 3, (0 .. 511) << 3 + + "+i" 5-bit SYNC code type at bit 16, (0..31) + "+j" 9-bit signed offset (s7:s0,s8), (-256 .. 255) + "+k" 5-bit nanoMIPS registers at bit 3 + "+p" 9-bit scaled signed offset, (s7:s2) << 2 for LL/SC* + "+q" 9-bit scaled signed offset, (s7:s3) << 3 for LLD/SCD* + "+r" 21-bit PC-relative branch offset (s19:s1,s20) << 1 + "+s" 21-bit immediate offset for PC-relative operation ((s19:s1,s20) + 2) << 1 + "+t" 5-bit non-zero GP register at bit 21 + "+u" 25-bit PC-relative branch offset (s24:s1,s25) << 1 + "+v" 5-bit mapping of R6 ALIGN byte-wise shift to EXTW bit-wise shift. + "+w" 2-bit shift for scaled address calculation at bit 9, (0..3) + "+*" 4-bit ROTX shift at bit 7, (0 .. 15) << 1 + "+|" 1-bit ROTX stripe at bit 6, (0 .. 1) + + "." 21-bit scaled GP-relative offset, (u21:u2) << 2 + "<" 5-bit immediate shift value for bit operations, (0..31) + "|" 3-bit Element count for load/store multiple, (1..8) + "~" 11-bit branch offset, (s9:s1,s10) << 1 + "^" 5-bit trap code at bit 11, (0..31) + "b" 5-bit base register at bit 16 for label or symbolic offsets + "c" 5-bit base register at bit 16, either used with immediate offset + or skipped with symbolic offset. + "d" 5-bit destination register specifier at bit 11 + "g" 12-bit unsigned immediate at bit 0, (0..4095) + "h" 12-bit negative immediate at bit 0, (-4095..0) + "i" 12-bit unsigned immediate at bit 0, (0..4095) + "j" 16-bit unsigned immediate at bit 0, (0..65535) + "k" 5-bit cache operation code at bit 21, (0..31) + "n" 11-bit encoding of save/restore register list + "o" 12-bit offset at bit 0, (0..4095) + "p" 14-bit PC-relative branch offset (s13:s1,s14) << 1 + "r" 5-bit same register at bit 16, used as both source and target + "s" 5-bit source register specifier at bit 16 + "t" 5-bit target register specifier at bit 21 + "u" Tri-part upper 20 bits of address + "x" Tri-part upper 20 bits of address, scaled by 12 bits + "v" 5-bit same register used as both source and destination at bit 15 + "w" 5-bit same register used as both target and destination at bit 21 + "z" must be zero register + + Used in special matching contexts: + "-a" 5-bit don't care at bit 16 + "-b" 8-bit split don't care, 5@16 and 4@9 + "-i" Ignored register operand, internally used for macro expansions. + "-m" Place-holder to copy 5 bits from bit 11 to bit 21 + "-n" Place-holder to copy 5 bits from bit 11 to bit 16 + + Exclusively for 48-bit nanoMIPS instructions: + + "+O" Signed GP-relative 32-bit offset in instruction byte order + "+P" Immediate signed 32-bit value in instruction byte order + "+Q" Unsigned 32-bit value or address in instruction byte order + "+R" Signed 32-bit value in instruction byte order + "+S" Signed PC-relative 32-bit offset in instruction byte order + + Coprocessor instructions: + "E" 5-bit target register + "G" 5-bit source register + "H" 5-bit sel field for (D)MTC* and (D)MFC* + "J" 5-bit select code at bit 11 for named COP1 registers, (0..31) + "K" 10-bit register+select encoding at bit 11 for named h/w register + "O" 10-bit register+select encoding at bit 11 for named COP1 register + "P" 5-bit named COP1 register at bit 16 + "Q" 5-bit select code at bit 11 + "U" 5-bit named HW register at bit 16 + + MT instructions: + "!" 1-bit u-mode for move to/from thread registers at bit 10, (0,1) + "$" 1-bit high-mode for move to/from thread registers at bit 3, (0,1) + "*" 2-bit accumulator register at bit 18, (0..3) + + Floating point instructions: + "D" 5-bit destination register + "R" 5-bit fr destination register + "S" 5-bit fs source 1 register + "T" 5-bit ft source 2 register + "V" 5-bit same register used as floating source and destination or target + + Macro instructions: + "A" general 32 bit expression + "I" 32-bit immediate (value placed in imm_expr). + "F" 64-bit floating point constant in memory + "L" 64-bit floating point constant in memory + "f" 32-bit floating point constant in memory + "l" 32-bit floating point constant in memory + + CP2 instructions: + "C" 23-bit coprocessor function code at bit 3 + + Other: + "()" parens surrounding optional value + "," separates operands + "+" start of extension sequence + + Characters used so far, for quick reference when adding more: + "12345 78 0" + ".<\|~@^!$*" + "A CDEFGHIJKL OP RSTUV " + " bcde ghijk nop rstuvwx z" + + Extension character sequences used so far ("+" followed by the + following), for quick reference when adding more: + "123456789 + "*|;" + "ABCDEFGHIJKLMNOPQRS " + " ij pqrstuvw " + + Extension character sequences used so far ("m" followed by the + following), for quick reference when adding more: + "" + "" + "ABCDEFGHIJKLMNOPQRS Z" + "abcdefghijklmn pqrstuvwxyz" + + Extension character sequences used so far ("-" followed by the + following), for quick reference when adding more: + "" + "" + " " + "ab i mn " +*/ + +extern const struct nanomips_operand *decode_nanomips_operand (const char *); +extern const struct nanomips_opcode nanomips_opcodes[]; +extern const int bfd_nanomips_num_opcodes; + +#ifdef __cplusplus +} +#endif + +#endif /* _NANOMIPS_H_ */ diff --git a/opcodes/Makefile.am b/opcodes/Makefile.am index a0fcf4d5ec7..0aa9836ece0 100644 --- a/opcodes/Makefile.am +++ b/opcodes/Makefile.am @@ -212,6 +212,8 @@ TARGET32_LIBOPCODES_CFILES = \ mt-dis.c \ mt-ibld.c \ mt-opc.c \ + nanomips-dis.c \ + nanomips-opc.c \ nds32-asm.c \ nds32-dis.c \ ns32k-dis.c \ diff --git a/opcodes/Makefile.in b/opcodes/Makefile.in index c5449bebf54..1f81ba70efc 100644 --- a/opcodes/Makefile.in +++ b/opcodes/Makefile.in @@ -618,6 +618,8 @@ TARGET32_LIBOPCODES_CFILES = \ mt-dis.c \ mt-ibld.c \ mt-opc.c \ + nanomips-dis.c \ + nanomips-opc.c \ nds32-asm.c \ nds32-dis.c \ ns32k-dis.c \ @@ -998,6 +1000,8 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mt-dis.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mt-ibld.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mt-opc.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nanomips-dis.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nanomips-opc.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nds32-asm.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nds32-dis.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nfp-dis.Plo@am__quote@ diff --git a/opcodes/configure b/opcodes/configure index 3e0962b9408..c544b7a569d 100755 --- a/opcodes/configure +++ b/opcodes/configure @@ -14369,6 +14369,7 @@ if test x${all_targets} = xfalse ; then bfd_mn10300_arch) ta="$ta m10300-dis.lo m10300-opc.lo" ;; bfd_mt_arch) ta="$ta mt-asm.lo mt-desc.lo mt-dis.lo mt-ibld.lo mt-opc.lo" using_cgen=yes ;; bfd_msp430_arch) ta="$ta msp430-dis.lo msp430-decode.lo" ;; + bfd_nanomips_arch) ta="$ta nanomips-dis.lo nanomips-opc.lo" ;; bfd_nds32_arch) ta="$ta nds32-asm.lo nds32-dis.lo" ;; bfd_nfp_arch) ta="$ta nfp-dis.lo" ;; bfd_ns32k_arch) ta="$ta ns32k-dis.lo" ;; diff --git a/opcodes/configure.ac b/opcodes/configure.ac index 2c2556598c9..a54c26ee880 100644 --- a/opcodes/configure.ac +++ b/opcodes/configure.ac @@ -308,6 +308,7 @@ if test x${all_targets} = xfalse ; then bfd_mn10300_arch) ta="$ta m10300-dis.lo m10300-opc.lo" ;; bfd_mt_arch) ta="$ta mt-asm.lo mt-desc.lo mt-dis.lo mt-ibld.lo mt-opc.lo" using_cgen=yes ;; bfd_msp430_arch) ta="$ta msp430-dis.lo msp430-decode.lo" ;; + bfd_nanomips_arch) ta="$ta nanomips-dis.lo nanomips-opc.lo" ;; bfd_nds32_arch) ta="$ta nds32-asm.lo nds32-dis.lo" ;; bfd_nfp_arch) ta="$ta nfp-dis.lo" ;; bfd_ns32k_arch) ta="$ta ns32k-dis.lo" ;; diff --git a/opcodes/disassemble.c b/opcodes/disassemble.c index 77d44bb08db..8760b28d107 100644 --- a/opcodes/disassemble.c +++ b/opcodes/disassemble.c @@ -102,6 +102,7 @@ #define ARCH_xtensa #define ARCH_z80 #define ARCH_z8k +#define ARCH_nanomips #endif #ifdef ARCH_m32c @@ -294,6 +295,11 @@ disassembler (enum bfd_architecture a, disassemble = print_insn_msp430; break; #endif +#ifdef ARCH_nanomips + case bfd_arch_nanomips: + disassemble = print_insn_nanomips; + break; +#endif #ifdef ARCH_nds32 case bfd_arch_nds32: disassemble = print_insn_nds32; @@ -556,6 +562,9 @@ disassembler_usage (FILE *stream ATTRIBUTE_UNUSED) #ifdef ARCH_nfp print_nfp_disassembler_options (stream); #endif +#ifdef ARCH_nanomips + print_nanomips_disassembler_options (stream); +#endif #ifdef ARCH_powerpc print_ppc_disassembler_options (stream); #endif @@ -683,6 +692,11 @@ disassemble_init_for_target (struct disassemble_info * info) info->created_styled_output = true; break; #endif +#ifdef ARCH_nanomips + case bfd_arch_nanomips: + info->disassembler_needs_relocs = true; + break; +#endif #ifdef ARCH_pru case bfd_arch_pru: info->disassembler_needs_relocs = true; diff --git a/opcodes/disassemble.h b/opcodes/disassemble.h index 2157790c947..901df877a0b 100644 --- a/opcodes/disassemble.h +++ b/opcodes/disassemble.h @@ -73,6 +73,7 @@ extern int print_insn_mn10300 (bfd_vma, disassemble_info *); extern int print_insn_moxie (bfd_vma, disassemble_info *); extern int print_insn_msp430 (bfd_vma, disassemble_info *); extern int print_insn_mt (bfd_vma, disassemble_info *); +extern int print_insn_nanomips (bfd_vma, disassemble_info *); extern int print_insn_nds32 (bfd_vma, disassemble_info *); extern int print_insn_nfp (bfd_vma, disassemble_info *); extern int print_insn_ns32k (bfd_vma, disassemble_info *); diff --git a/opcodes/nanomips-dis.c b/opcodes/nanomips-dis.c new file mode 100644 index 00000000000..195d2408d94 --- /dev/null +++ b/opcodes/nanomips-dis.c @@ -0,0 +1,1394 @@ +/* Print nanoMIPS instructions for GDB, the GNU debugger, or for objdump. + Copyright (C) 2017-2026 Free Software Foundation, CIP United Inc. + Contributed by MIPS Tech LLC. + Written by Faraz Shahbazker <[email protected]> + + This file is part of the GNU opcodes library. + + 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 program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ + +#include "sysdep.h" +#include "dis-asm.h" +#include "libiberty.h" +#include "opcode/nanomips.h" +#include "opintl.h" +#include "disassemble.h" + +#if !defined(EMBEDDED_ENV) +#include "elf-bfd.h" +#include "elf/nanomips.h" +#include "elfxx-nanomips.h" +#endif + +/* FIXME: These should be shared with gdb somehow. */ + +static const char * const nanomips_gpr_names_numeric[32] = { + "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7", + "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", + "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23", + "$24", "$25", "$26", "$27", "$28", "$29", "$30", "$31" +}; + +static const char * const nanomips_gpr_names_symbolic[32] = { + "zero", "at", "t4", "t5", "a0", "a1", "a2", "a3", + "a4", "a5", "a6", "a7", "t0", "t1", "t2", "t3", + "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", + "t8", "t9", "k0", "k1", "gp", "sp", "fp", "ra" +}; + +static const char * const nanomips_fpr_names_numeric[32] = { + "$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" +}; + +static const char * const nanomips_fpr_names_64[32] = { + "fv0", "ft12", "fv1", "ft13", "ft0", "ft1", "ft2", "ft3", + "ft4", "ft5", "ft6", "ft7", "fa0", "fa1", "fa2", "fa3", + "fa4", "fa5", "fa6", "fa7", "ft8", "ft9", "ft10", "ft11", + "fs0", "fs1", "fs2", "fs3", "fs4", "fs5", "fs6", "fs7" +}; + +static const char * const nanomips_cp0_names_numeric[32] = +{ + "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7", + "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", + "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23", + "$24", "$25", "$26", "$27", "$28", "$29", "$30", "$31" +}; + +static const char * const nanomips_hwr_names_numeric[32] = { + "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7", + "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", + "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23", + "$24", "$25", "$26", "$27", "$28", "$29", "$30", "$31" +}; + +static const char * const nanomips_hwr_names_3264r6[32] = { + "hwr_cpunum", "hwr_synci_step", "hwr_cc", "hwr_ccres", + "hwr_perfcnt", "hwr_xnp", "$6", "$7", + "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", + "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23", + "$24", "$25", "$26", "$27", "$28", "hwr_userlocal", + "$30", "$31" +}; + +/* The empty-list of CP0 registers serves as an indicator to fall-back to + numeric register names. */ +static const struct nanomips_cp0_name nanomips_cp0_numeric[] = { + {NULL, 0, 0} +}; +static const struct nanomips_cp0_select nanomips_cp0sel_numeric[] = { + {NULL, 0, 0} +}; + +struct nanomips_abi_choice +{ + const char *name; + const char *const *gpr_names; + const char *const *fpr_names; +}; + +struct nanomips_abi_choice nanomips_abi_choices[] = { + {"numeric", nanomips_gpr_names_numeric, nanomips_fpr_names_numeric}, + {"p32", nanomips_gpr_names_symbolic, nanomips_fpr_names_64}, + {"p64", nanomips_gpr_names_symbolic, nanomips_fpr_names_64}, +}; + +struct nanomips_arch_choice +{ + const char *name; + int bfd_mach_valid; + unsigned long bfd_mach; + int processor; + int isa; + int ase; + const struct nanomips_cp0_name *cp0_names; + const struct nanomips_cp0_select *cp0sel_names; + const char *const *hwr_names; +}; + +const struct nanomips_arch_choice nanomips_arch_choices[] = { + {"numeric", 0, 0, 0, 0, 0, + nanomips_cp0_numeric, nanomips_cp0sel_numeric, nanomips_hwr_names_numeric}, + + {"32r6", 1, bfd_mach_nanomipsisa32r6, CPU_NANOMIPS32R6, ISA_NANOMIPS32R6, + (ASE_VIRT | ASE_MT | ASE_xNMS), + nanomips_cp0_3264r6, nanomips_cp0sel_3264r6, nanomips_hwr_names_3264r6}, + + {"32r6s", 1, bfd_mach_nanomipsisa32r6, CPU_NANOMIPS32R6, ISA_NANOMIPS32R6, + (ASE_VIRT | ASE_MT), + nanomips_cp0_3264r6, nanomips_cp0sel_3264r6, nanomips_hwr_names_3264r6}, + + {"64r6", 1, bfd_mach_nanomipsisa64r6, CPU_NANOMIPS64R6, ISA_NANOMIPS64R6, + (ASE_VIRT | ASE_MT | ASE_xNMS), + nanomips_cp0_3264r6, nanomips_cp0sel_3264r6, nanomips_hwr_names_3264r6}, +}; + +/* ISA and processor type to disassemble for, and register names to use. + set_default_nanomips_dis_options and parse_nanomips_dis_options fill in + these values. */ + +static int nanomips_processor; +static int nanomips_ase; +static int nanomips_isa; +static const char *const *nanomips_gpr_names; +static const char *const *nanomips_fpr_names; +static const struct nanomips_cp0_name *nanomips_cp0_names; +static const struct nanomips_cp0_select *nanomips_cp0sel_names; +static const char *const *nanomips_hwr_names; + +/* Other options */ +static int no_aliases; /* If set, disassemble as most general inst. */ +static bool show_arch_insn; /* Mnemonics with suffix. */ + +/* Map ABI name to nanomips_abi_choice descriptor. */ + +static const struct nanomips_abi_choice * +choose_abi_by_name (const char *name, unsigned int namelen) +{ + const struct nanomips_abi_choice *c; + unsigned int i; + + for (i = 0, c = NULL; i < ARRAY_SIZE (nanomips_abi_choices) && c == NULL; + i++) + if (strncmp (nanomips_abi_choices[i].name, name, namelen) == 0 + && strlen (nanomips_abi_choices[i].name) == namelen) + c = &nanomips_abi_choices[i]; + + return c; +} + +/* Map architecture name to nanomips_arch_choice descriptor. */ + +static const struct nanomips_arch_choice * +choose_arch_by_name (const char *name, unsigned int namelen) +{ + const struct nanomips_arch_choice *c = NULL; + unsigned int i; + + for (i = 0, c = NULL; i < ARRAY_SIZE (nanomips_arch_choices) && c == NULL; + i++) + if (strncmp (nanomips_arch_choices[i].name, name, namelen) == 0 + && strlen (nanomips_arch_choices[i].name) == namelen) + c = &nanomips_arch_choices[i]; + + return c; +} + +/* Map BFD architecture to nanomips_arch_choice descriptor. */ + +static const struct nanomips_arch_choice * +choose_arch_by_number (unsigned long mach) +{ + static unsigned long hint_bfd_mach; + static const struct nanomips_arch_choice *hint_arch_choice; + const struct nanomips_arch_choice *c; + unsigned int i; + + /* We optimize this because even if the user specifies no + flags, this will be done for every instruction! */ + if (hint_bfd_mach == mach + && hint_arch_choice != NULL + && hint_arch_choice->bfd_mach == hint_bfd_mach) + return hint_arch_choice; + + for (i = 0, c = NULL; i < ARRAY_SIZE (nanomips_arch_choices) && c == NULL; + i++) + { + if (nanomips_arch_choices[i].bfd_mach_valid + && nanomips_arch_choices[i].bfd_mach == mach) + { + c = &nanomips_arch_choices[i]; + hint_bfd_mach = mach; + hint_arch_choice = c; + } + } + return c; +} + +/* Select default descriptors and initial mode for the default + architecture. */ + +static void +set_default_nanomips_dis_options (struct disassemble_info *info) +{ + const struct nanomips_arch_choice *chosen_arch; + + nanomips_isa = ISA_NANOMIPS32R6; + nanomips_processor = CPU_NANOMIPS32R6; + nanomips_isa = true; + nanomips_ase = 0; + nanomips_fpr_names = nanomips_fpr_names_numeric; + nanomips_cp0_names = nanomips_cp0_numeric; + nanomips_cp0sel_names = nanomips_cp0sel_numeric; + nanomips_hwr_names = nanomips_hwr_names_numeric; + no_aliases = 0; + show_arch_insn = false; + + nanomips_gpr_names = nanomips_gpr_names_symbolic; + + /* Set ISA, architecture, and cp0 register names as best we can. */ + chosen_arch = choose_arch_by_number (info->mach); + if (chosen_arch != NULL) + { + nanomips_processor = chosen_arch->processor; + nanomips_isa = chosen_arch->isa; + nanomips_ase = chosen_arch->ase; + nanomips_cp0_names = chosen_arch->cp0_names; + nanomips_cp0sel_names = chosen_arch->cp0sel_names; + nanomips_hwr_names = chosen_arch->hwr_names; + } +} + +/* Parse and translate a command-line options to internal state. */ + +static void +parse_nanomips_dis_option (const char *option, unsigned int len) +{ + unsigned int i, optionlen, vallen; + const char *val; + const struct nanomips_abi_choice *chosen_abi; + const struct nanomips_arch_choice *chosen_arch; + + /* Try to match options that are simple flags */ + if (startswith (option, "show-arch-insn")) + { + show_arch_insn = true; + return; + } + + if (startswith (option, "no-aliases")) + { + no_aliases = 1; + return; + } + + if (startswith (option, "virt")) + { + nanomips_ase |= ASE_VIRT; + + if (nanomips_isa & ISA_NANOMIPS64R6) + nanomips_ase |= ASE_VIRT64; + } + + /* Look for the = that delimits the end of the option name. */ + for (i = 0; i < len; i++) + if (option[i] == '=') + break; + + if (i == 0) /* Invalid option: no name before '='. */ + return; + if (i == len) /* Invalid option: no '='. */ + return; + if (i == (len - 1)) /* Invalid option: no value after '='. */ + return; + + optionlen = i; + val = option + (optionlen + 1); + vallen = len - (optionlen + 1); + + if (strncmp ("gpr-names", option, optionlen) == 0 + && strlen ("gpr-names") == optionlen) + { + chosen_abi = choose_abi_by_name (val, vallen); + if (chosen_abi != NULL) + nanomips_gpr_names = chosen_abi->gpr_names; + return; + } + + if (strncmp ("fpr-names", option, optionlen) == 0 + && strlen ("fpr-names") == optionlen) + { + chosen_abi = choose_abi_by_name (val, vallen); + if (chosen_abi != NULL) + nanomips_fpr_names = chosen_abi->fpr_names; + return; + } + + if (strncmp ("cp0-names", option, optionlen) == 0 + && strlen ("cp0-names") == optionlen) + { + chosen_arch = choose_arch_by_name (val, vallen); + if (chosen_arch != NULL) + { + nanomips_cp0_names = chosen_arch->cp0_names; + nanomips_cp0sel_names = chosen_arch->cp0sel_names; + } + return; + } + + if (strncmp ("hwr-names", option, optionlen) == 0 + && strlen ("hwr-names") == optionlen) + { + chosen_arch = choose_arch_by_name (val, vallen); + if (chosen_arch != NULL) + nanomips_hwr_names = chosen_arch->hwr_names; + return; + } + + if (strncmp ("reg-names", option, optionlen) == 0 + && strlen ("reg-names") == optionlen) + { + /* We check both ABI and ARCH here unconditionally, so + that "numeric" will do the desirable thing: select + numeric register names for all registers. Other than + that, a given name probably won't match both. */ + chosen_abi = choose_abi_by_name (val, vallen); + if (chosen_abi != NULL) + { + nanomips_gpr_names = chosen_abi->gpr_names; + nanomips_fpr_names = chosen_abi->fpr_names; + } + chosen_arch = choose_arch_by_name (val, vallen); + if (chosen_arch != NULL) + { + nanomips_cp0_names = chosen_arch->cp0_names; + nanomips_cp0sel_names = chosen_arch->cp0sel_names; + nanomips_hwr_names = chosen_arch->hwr_names; + } + return; + } +} + +/* Loop to parse nanoMIPS-specific command-line options. */ + +static void +parse_nanomips_dis_options (const char *options) +{ + const char *option_end; + + if (options == NULL) + return; + + while (*options != '\0') + { + /* Skip empty options. */ + if (*options == ',') + { + options++; + continue; + } + /* We know that *options is neither NUL or a comma. */ + option_end = options + 1; + while (*option_end != ',' && *option_end != '\0') + option_end++; + + parse_nanomips_dis_option (options, option_end - options); + + /* Go on to the next one. If option_end points to a comma, it + will be skipped above. */ + options = option_end; + } +} + +/* Look-up and print the symbolic name of a named CP0 register with + a fixed select value. Fall-back to numeric format if no match is + found. */ + +static void +print_cp0_reg (struct disassemble_info *info, int regno) +{ + const fprintf_styled_ftype infprintf = info->fprintf_styled_func; + + int i; + unsigned int selnum = regno & NANOMIPSOP_MASK_CP0SEL; + unsigned int cp0_regno = regno >> NANOMIPSOP_SH_CP0SEL; + + if (nanomips_cp0_names != nanomips_cp0_numeric) + for (i = cp0_regno; nanomips_cp0_names[i].name; i++) + { + if (nanomips_cp0_names[i].num == cp0_regno + && nanomips_cp0_names[i].sel == selnum) + { + infprintf (info->stream, dis_style_register, "%s", + nanomips_cp0_names[i].name + 1); + return; + } + } + + /* A select value of 0 is deemed optional. */ + if (selnum == 0) + infprintf (info->stream, dis_style_register, "$%d", cp0_regno); + else + infprintf (info->stream, dis_style_register, "$%d,%d", cp0_regno, selnum); +} + +/* Look-up and print the symbolic name of a named CP0 register with + a variable select value. Fall-back to numeric format if no match is + found. */ + +static void +print_cp0sel_reg (struct disassemble_info *info, unsigned int regno, + unsigned int selnum) +{ + const fprintf_styled_ftype infprintf = info->fprintf_styled_func; + int i; + + for (i = 0; nanomips_cp0sel_names[i].name; i++) + { + if (nanomips_cp0sel_names[i].num == regno + && ((1 << selnum) & nanomips_cp0sel_names[i].selmask) != 0) + { + infprintf (info->stream, dis_style_register, "%s,%d", + nanomips_cp0sel_names[i].name + 1, selnum); + return; + } + } + + /* A select value of 0 is deemed optional. */ + if (selnum == 0) + infprintf (info->stream, dis_style_register, "$%d", regno); + else + infprintf (info->stream, dis_style_register, "$%d,%d", regno, selnum); +} + +/* Print register REGNO, of type TYPE, for instruction OPCODE. */ + +static void +print_reg (struct disassemble_info *info, + const struct nanomips_opcode *opcode, + enum nanomips_reg_operand_type type, int regno) +{ + const fprintf_styled_ftype infprintf = info->fprintf_styled_func; + + switch (type) + { + case OP_REG_GP: + infprintf (info->stream, dis_style_register, "%s", nanomips_gpr_names[regno]); + break; + + case OP_REG_FP: + infprintf (info->stream, dis_style_register, "%s", nanomips_fpr_names[regno]); + break; + + case OP_REG_ACC: + infprintf (info->stream, dis_style_register, "$ac%d", regno); + break; + + case OP_REG_COPRO: + if (opcode->name[strlen (opcode->name) - 1] == '1') + infprintf (info->stream, dis_style_register, "%s", nanomips_cp0_names[regno]); + else + infprintf (info->stream, dis_style_register, "$%d", regno); + break; + + case OP_REG_HW: + info->fprintf_func (info->stream, "%s", nanomips_hwr_names[regno]); + break; + + case OP_REG_CP0: + print_cp0_reg (info, regno); + break; + + case OP_REG_CP0SEL: + /* Need to check select bits againt mask, defer output to next operand. */ + break; + } +} + +/* Used to track the state carried over from previous operands in + an instruction. */ + +struct nanomips_print_arg_state +{ + /* The value of the last OP_INT seen. We only use this for OP_MSB, + where the value is known to be unsigned and small. */ + unsigned int last_int; + + /* The type and number of the last OP_REG seen. We only use this for + OP_REPEAT_DEST_REG and OP_REPEAT_PREV_REG. */ + enum nanomips_reg_operand_type last_reg_type; + unsigned int last_regno; + unsigned int dest_regno; + unsigned int seen_dest; +}; + +/* Initialize STATE for the start of an instruction. */ + +static inline void +init_print_arg_state (struct nanomips_print_arg_state *state) +{ + memset (state, 0, sizeof (*state)); +} + +/* Record information about a register operand. */ + +static void +nanomips_seen_register (struct nanomips_print_arg_state *state, + unsigned int regno, + enum nanomips_reg_operand_type reg_type) +{ + state->last_reg_type = reg_type; + state->last_regno = regno; + + if (!state->seen_dest) + { + state->seen_dest = 1; + state->dest_regno = regno; + } +} + +/* Pretty-print a save/restore register list. */ + +static void +nanomips_print_save_restore (struct disassemble_info *info, + unsigned int uval, bool mode16) +{ + const fprintf_styled_ftype infprintf = info->fprintf_styled_func; + void *is = info->stream; + char *comma = ","; + unsigned int pending = 0; + unsigned int freg, fp, count, gp, ra; + fp = gp = ra = 0; + + if (mode16) + { + freg = 30 | (uval >> 4); + count = uval & 0xf; + } + else + { + freg = (uval >> 6) & 0x1f; + count = (uval >> 1) & 0xf; + if (count > 0) + gp = uval & 1; + } + + if (freg == 30 && count > 0) + fp = 1; + if ((freg == 31 && count > 0) || (freg == 30 && count > 1)) + ra = 1; + + if (freg + count == 45) + gp = 1; + + count = count - gp; + if (fp && count > 0) + { + freg = (freg & 0x10) | ((freg + 1) % 32); + count--; + } + + if (ra && count > 0) + { + freg = (freg & 0x10) | ((freg + 1) % 32); + count--; + } + + if (fp) + { + infprintf (is, dis_style_register, "%s", nanomips_gpr_names[30]); + pending = 1; + } + + if (ra) + { + infprintf (is, dis_style_register, "%s%s", (pending ? comma : ""), nanomips_gpr_names[31]); + pending = 1; + } + + if (count > 0) + { + if (count > 1) + infprintf (is, dis_style_register, "%s%s-%s", (pending ? comma : ""), + nanomips_gpr_names[freg], + nanomips_gpr_names[freg + count - 1]); + else + infprintf (is, dis_style_register, "%s%s", (pending ? comma : ""), + nanomips_gpr_names[freg]); + pending = 1; + } + + if (gp) + infprintf (is, dis_style_register, "%s%s", (pending ? comma : ""), nanomips_gpr_names[28]); +} + +/* Pretty-print save/restore floating-point register list. */ + +static void +nanomips_print_save_restore_fp (struct disassemble_info *info, + unsigned int count) +{ + const fprintf_styled_ftype infprintf = info->fprintf_styled_func; + void *is = info->stream; + + if (count == 1) + infprintf (is, dis_style_register, "%s", nanomips_fpr_names[0]); + else + infprintf (is, dis_style_register, "%s-%s", nanomips_fpr_names[0], + nanomips_fpr_names[count - 1]); +} + +/* Print operand OPERAND of OPCODE, using STATE to track inter-operand state. + UVAL is the encoding of the operand (shifted into bit 0) and BASE_PC is + the base address for OP_PCREL operands. */ + +static void +print_insn_arg (struct disassemble_info *info, + struct nanomips_print_arg_state *state, + const struct nanomips_opcode *opcode, + const struct nanomips_operand *operand, + bfd_vma base_pc, unsigned int uval) +{ + const fprintf_styled_ftype infprintf = info->fprintf_styled_func; + void *is = info->stream; + + switch (operand->type) + { + case OP_INT: + case OP_IMM_INT: + { + const struct nanomips_int_operand *int_op; + + int_op = (const struct nanomips_int_operand *) operand; + uval = nanomips_decode_int_operand (int_op, uval); + state->last_int = uval; + if (int_op->print_hex) + infprintf (is, dis_style_immediate, "0x%x", uval); + else + infprintf (is, dis_style_immediate, "%d", uval); + } + break; + + case OP_MAPPED_INT: + { + const struct nanomips_mapped_int_operand *mint_op; + + mint_op = (const struct nanomips_mapped_int_operand *) operand; + uval = mint_op->int_map[uval]; + state->last_int = uval; + if (mint_op->print_hex) + infprintf (is, dis_style_immediate, "0x%x", uval); + else + infprintf (is, dis_style_immediate, "%d", uval); + } + break; + + case OP_MSB: + { + const struct nanomips_msb_operand *msb_op; + + msb_op = (const struct nanomips_msb_operand *) operand; + uval += msb_op->bias; + if (msb_op->add_lsb) + uval -= state->last_int; + infprintf (is, dis_style_immediate, "%d", uval); + } + break; + + case OP_REG: + case OP_OPTIONAL_REG: + case OP_MAPPED_CHECK_PREV: + case OP_BASE_CHECK_OFFSET: + { + const struct nanomips_reg_operand *reg_op; + + reg_op = (const struct nanomips_reg_operand *) operand; + uval = nanomips_decode_reg_operand (reg_op, uval); + print_reg (info, opcode, reg_op->reg_type, uval); + + nanomips_seen_register (state, uval, reg_op->reg_type); + } + break; + + case OP_REG_PAIR: + { + const struct nanomips_reg_pair_operand *pair_op; + + pair_op = (const struct nanomips_reg_pair_operand *) operand; + print_reg (info, opcode, pair_op->reg_type, pair_op->reg1_map[uval]); + infprintf (is, dis_style_text, ","); + print_reg (info, opcode, pair_op->reg_type, pair_op->reg2_map[uval]); + } + break; + + case OP_PCREL: + { + const struct nanomips_pcrel_operand *pcrel_op; + + pcrel_op = (const struct nanomips_pcrel_operand *) operand; + info->target = nanomips_decode_pcrel_operand (pcrel_op, base_pc, uval); + + /* Preserve the ISA bit for the GDB disassembler, + otherwise clear it. */ + if (info->flavour != bfd_target_unknown_flavour) + info->target &= -2; + + (*info->print_address_func) (info->target, info); + } + break; + + case OP_NON_ZERO_PCREL_S1: + { + const struct nanomips_pcrel_operand pcrel_op = { + {{OP_PCREL, operand->size, operand->lsb, 0, 0}, + (1 << operand->size) - 1, 0, 1, true}, 0, 0, 0 + }; + + if ((info->flags & INSN_HAS_RELOC) == 0) + info->target = nanomips_decode_pcrel_operand (&pcrel_op, base_pc, + uval); + else + info->target = 0; + (*info->print_address_func) (info->target, info); + } + break; + + case OP_CHECK_PREV: + case OP_NON_ZERO_REG: + { + print_reg (info, opcode, OP_REG_GP, uval & 31); + nanomips_seen_register (state, uval, OP_REG_GP); + } + break; + + case OP_SAVE_RESTORE_LIST: + nanomips_print_save_restore (info, uval, opcode->mask >> 16 == 0); + break; + + case OP_SAVE_RESTORE_FP_LIST: + nanomips_print_save_restore_fp (info, uval + 1); + break; + + case OP_REPEAT_PREV_REG: + print_reg (info, opcode, state->last_reg_type, state->last_regno); + break; + + case OP_REPEAT_DEST_REG: + print_reg (info, opcode, state->last_reg_type, state->dest_regno); + break; + + case OP_HI20_PCREL: + { + if ((info->flags & INSN_HAS_RELOC) == 0) + { + uval = nanomips_decode_hi20_int_operand (operand, uval); + infprintf (is, dis_style_immediate, "0x%x", uval & 0xfffff); + } + else + { + info->target = nanomips_decode_hi20_pcrel_operand (operand, base_pc, + uval); + infprintf (is, dis_style_text, "%%pcrel_hi("); + (*info->print_address_func) (info->target, info); + infprintf (is, dis_style_text, ")"); + } + } + break; + + case OP_HI20_SCALE: + { + uval = nanomips_decode_hi20_int_operand (operand, uval); + state->last_int = uval; + infprintf (is, dis_style_immediate, "0x%x", uval & 0xfffff); + } + break; + + case OP_HI20_INT: + { + uval = nanomips_decode_hi20_int_operand (operand, uval); + state->last_int = uval; + if ((info->flags & INSN_HAS_RELOC) != 0 || uval == 0) + infprintf (is, dis_style_immediate, "0x%x", uval & 0xfffff); + else + infprintf (is, dis_style_immediate, "%%hi(0x%x)", (uval & 0xfffff) << 12); + } + break; + + case OP_IMM_WORD: + { + const struct nanomips_int_operand *int_op; + int_op = (const struct nanomips_int_operand *) operand; + state->last_int = ((uval >> 16) & 0xffff) | (uval << 16); + state->last_int += int_op->bias; + infprintf (is, dis_style_immediate, "%d", state->last_int); + } + break; + + case OP_INT_WORD: + case OP_GPREL_WORD: + { + state->last_int = ((uval >> 16) & 0xffff) | (uval << 16); + infprintf (is, dis_style_immediate, "%d", state->last_int); + } + break; + + case OP_UINT_WORD: + { + state->last_int = ((uval >> 16) & 0xffff) | (uval << 16); + infprintf (is, dis_style_immediate, "0x%x", state->last_int); + } + break; + + case OP_PC_WORD: + { + info->target = base_pc + (((uval >> 16) & 0xffff) | (uval << 16)); + (*info->print_address_func) (info->target, info); + } + break; + + case OP_NEG_INT: + infprintf (is, dis_style_immediate, "-%d", uval); + break; + + case OP_CP0SEL: + print_cp0sel_reg (info, state->last_regno, uval); + break; + + case OP_DONT_CARE: + case OP_COPY_BITS: + default: + break; + } +} + +/* Check if register+select map to a valid CP0 select sequence. */ + +static bool +validate_cp0_reg_operand (unsigned int uval) +{ + int i; + unsigned int regno, selnum; + regno = uval >> NANOMIPSOP_SH_CP0SEL; + selnum = uval & NANOMIPSOP_MASK_CP0SEL; + + for (i = 0; nanomips_cp0_3264r6[i].name; i++) + if (regno == nanomips_cp0_3264r6[i].num + && selnum == nanomips_cp0_3264r6[i].sel) + break; + else if (regno < nanomips_cp0_3264r6[i].num) + return false; + + if (nanomips_cp0_3264r6[i].name == NULL) + return false; + + return true; +} + +/* Validate the arguments for INSN, which is described by OPCODE. + Use DECODE_OPERAND to get the encoding of each operand. */ + +static bool +validate_insn_args (const struct nanomips_opcode *opcode, + const struct nanomips_operand *(*decode_operand) (const char *), + unsigned int insn, struct disassemble_info *info) +{ + struct nanomips_print_arg_state state; + const struct nanomips_operand *operand; + const char *s; + unsigned int uval; + + init_print_arg_state (&state); + for (s = opcode->args; *s; ++s) + { + switch (*s) + { + case ',': + case '(': + case ')': + break; + + case '#': + ++s; + break; + + default: + operand = decode_operand (s); + + if (!operand) + continue; + + uval = nanomips_extract_operand (operand, insn); + switch (operand->type) + { + case OP_REG: + case OP_OPTIONAL_REG: + case OP_BASE_CHECK_OFFSET: + { + const struct nanomips_reg_operand *reg_op; + + reg_op = (const struct nanomips_reg_operand *) operand; + + if (operand->type == OP_REG + && reg_op->reg_type == OP_REG_CP0 + && !validate_cp0_reg_operand (uval)) + return false; + + uval = nanomips_decode_reg_operand (reg_op, uval); + nanomips_seen_register (&state, uval, reg_op->reg_type); + } + break; + + case OP_CHECK_PREV: + { + const struct nanomips_check_prev_operand *prev_op + = (const struct nanomips_check_prev_operand *) operand; + + if (!prev_op->zero_ok && uval == 0) + return false; + + if (((prev_op->less_than_ok && uval < state.last_regno) + || (prev_op->greater_than_ok && uval > state.last_regno) + || (prev_op->equal_ok && uval == state.last_regno))) + break; + + return false; + } + + case OP_MAPPED_CHECK_PREV: + { + const struct nanomips_mapped_check_prev_operand *prev_op = + (const struct nanomips_mapped_check_prev_operand *) operand; + unsigned int last_uval = + nanomips_encode_reg_operand (operand, state.last_regno); + + if (((prev_op->less_than_ok && uval < last_uval) + || (prev_op->greater_than_ok && uval > last_uval) + || (prev_op->equal_ok && uval == last_uval))) + break; + + return false; + } + + case OP_NON_ZERO_REG: + if (uval == 0) + return false; + break; + + case OP_NON_ZERO_PCREL_S1: + if (uval == 0 && (info->flags & INSN_HAS_RELOC) == 0) + return false; + break; + + case OP_SAVE_RESTORE_LIST: + { + /* The operand for SAVE/RESTORE is split into 3 pieces + rather than just 2 but we only support a 2-way split + decode the last bit of the instruction here. */ + if (opcode->mask >> 16 != 0 && ((insn >> 20) & 0x1) != 0) + return false; + } + break; + + case OP_IMM_INT: + case OP_IMM_WORD: + case OP_NEG_INT: + case OP_INT: + case OP_MAPPED_INT: + case OP_MSB: + case OP_REG_PAIR: + case OP_PCREL: + case OP_REPEAT_PREV_REG: + case OP_REPEAT_DEST_REG: + case OP_SAVE_RESTORE_FP_LIST: + case OP_HI20_INT: + case OP_HI20_PCREL: + case OP_INT_WORD: + case OP_UINT_WORD: + case OP_PC_WORD: + case OP_GPREL_WORD: + case OP_DONT_CARE: + case OP_HI20_SCALE: + case OP_COPY_BITS: + case OP_CP0SEL: + break; + } + + if (*s == 'm' || *s == '+' || *s == '-' || *s == '`') + ++s; + } + } + return true; +} + +/* Print the arguments for INSN, which is described by OPCODE. + Use DECODE_OPERAND to get the encoding of each operand. Use BASE_PC + as the base of OP_PCREL operands, adjusting by LENGTH if the OP_PCREL + operand is for a branch or jump. */ + +static void +print_insn_args (struct disassemble_info *info, + const struct nanomips_opcode *opcode, + const struct nanomips_operand *(*decode_operand) (const char *), + uint64_t insn, bfd_vma insn_pc, unsigned int length) +{ + const fprintf_styled_ftype infprintf = info->fprintf_styled_func; + void *is = info->stream; + struct nanomips_print_arg_state state; + const struct nanomips_operand *operand; + const char *s; + bool pending_sep = false; + bool pending_space = true; + + init_print_arg_state (&state); + for (s = opcode->args; *s; ++s) + { + switch (*s) + { + case ',': + pending_sep = true; + break; + case '(': + if (pending_sep) + { + infprintf (is, dis_style_text, ","); + pending_sep = false; + } + /* fall-through */ + case ')': + infprintf (is, dis_style_text, "%c", *s); + break; + + case '#': + ++s; + infprintf (is, dis_style_text, "%c%c", *s, *s); + break; + + default: + operand = decode_operand (s); + if (!operand) + { + /* xgettext:c-format */ + infprintf (is, dis_style_text, + _("# internal error, undefined operand in `%s %s'"), + opcode->name, opcode->args); + return; + } + + /* Defer printing the comma separator for CP0-select values since + the preceding register output is also defered. */ + if (operand->type != OP_DONT_CARE + && operand->type != OP_CP0SEL + && pending_sep) + { + infprintf (is, dis_style_text, ","); + pending_sep = false; + } + + if (operand->type != OP_DONT_CARE && pending_space) + infprintf (is, dis_style_text, "\t"); + pending_space = false; + + { + bfd_vma base_pc = 0; + bool have_reloc = ((info->flags & INSN_HAS_RELOC) != 0); + + if (!have_reloc) + base_pc = insn_pc; + + if ((operand->type == OP_PCREL + || operand->type == OP_HI20_PCREL + || operand->type == OP_NON_ZERO_PCREL_S1 + || operand->type == OP_PC_WORD) + && !have_reloc) + base_pc += length; + + if (operand->type == OP_INT_WORD + || operand->type == OP_UINT_WORD + || operand->type == OP_PC_WORD + || operand->type == OP_GPREL_WORD + || operand->type == OP_IMM_WORD) + print_insn_arg (info, &state, opcode, operand, base_pc, + insn >> 32); + else if (operand->type != OP_DONT_CARE) + print_insn_arg (info, &state, opcode, operand, base_pc, + nanomips_extract_operand (operand, insn)); + } + if (*s == 'm' || *s == '+' || *s == '-' || *s == '`') + ++s; + break; + } + } +} + +enum match_kind +{ + MATCH_NONE, + MATCH_FULL, + MATCH_SHORT +}; + +/* Disassemble nanoMIPS instructions. */ + +static int +_print_insn_nanomips (bfd_vma memaddr_base, struct disassemble_info *info) +{ + const fprintf_styled_ftype infprintf = info->fprintf_styled_func; + const struct nanomips_opcode *op, *opend; + void *is = info->stream; + bfd_byte buffer[2]; + uint64_t higher = 0; + unsigned int length; + int status; + uint64_t insn; + + bfd_vma memaddr = memaddr_base; + + info->bytes_per_chunk = 2; + info->display_endian = info->endian; + info->insn_info_valid = 1; + info->branch_delay_insns = 0; + info->data_size = 0; + info->insn_type = dis_nonbranch; + info->target = 0; + info->target2 = 0; + + status = (*info->read_memory_func) (memaddr, buffer, 2, info); + if (status != 0) + { + (*info->memory_error_func) (status, memaddr, info); + return -1; + } + + length = 2; + + if (info->endian == BFD_ENDIAN_BIG) + insn = bfd_getb16 (buffer); + else + insn = bfd_getl16 (buffer); + + if ((insn & 0xfc00) == 0x6000) + { + unsigned imm; + /* This is a 48-bit nanoMIPS instruction. */ + status = (*info->read_memory_func) (memaddr + 2, buffer, 4, info); + if (status != 0) + { + infprintf (is, dis_style_text, "0x%x (expected 48 bits): ", + (unsigned) insn); + (*info->memory_error_func) (status, memaddr + 2, info); + return -1; + } + if (info->endian == BFD_ENDIAN_BIG) + imm = bfd_getb16 (buffer); + else + imm = bfd_getl16 (buffer); + higher = (imm << 16); + + status = (*info->read_memory_func) (memaddr + 4, buffer, 2, info); + + if (info->endian == BFD_ENDIAN_BIG) + imm = bfd_getb16 (buffer); + else + imm = bfd_getl16 (buffer); + higher = higher | imm; + + length += 4; + } + else if ((insn & 0x1000) == 0x0) + { + /* This is a 32-bit nanoMIPS instruction. */ + higher = insn; + + status = (*info->read_memory_func) (memaddr + 2, buffer, 2, info); + if (status != 0) + { + infprintf (is, dis_style_text, "0x%x (expected 32 bits): ", + (unsigned) higher); + (*info->memory_error_func) (status, memaddr + 2, info); + return -1; + } + + if (info->endian == BFD_ENDIAN_BIG) + insn = bfd_getb16 (buffer); + else + insn = bfd_getl16 (buffer); + + insn = insn | (higher << 16); + + length += 2; + } + + /* FIXME: Should probably use a hash table on the major opcode here. */ + const struct nanomips_opcode *opcodes; + int num_opcodes; + struct nanomips_operand const *(*decode) (const char *); + + opcodes = nanomips_opcodes; + num_opcodes = bfd_nanomips_num_opcodes; + decode = decode_nanomips_operand; + + opend = opcodes + num_opcodes; + for (op = opcodes; op < opend; op++) + { + if (op->pinfo != INSN_MACRO + && !(no_aliases && (op->pinfo2 & INSN2_ALIAS)) + && (insn & op->mask) == op->match + && ((length == 2 && (op->mask & 0xffff0000) == 0) + || (length == 6 + && (op->mask & 0xffff0000) == 0) + || (length == 4 && (op->mask & 0xffff0000) != 0))) + { + if (!nanomips_opcode_is_member (op, nanomips_isa, nanomips_ase, + nanomips_processor) + || (op->pinfo2 & INSN2_CONVERTED_TO_COMPACT)) + continue; + + if (!validate_insn_args (op, decode, insn, info)) + continue; + + infprintf (is, dis_style_mnemonic, "%s%s", op->name, + (show_arch_insn ? op->suffix : "")); + + if (length == 6) + insn |= (higher << 32); + + if (op->args[0]) + print_insn_args (info, op, decode, insn, memaddr, length); + + /* Figure out instruction type and branch delay information. */ + if ((op->pinfo2 & INSN2_UNCOND_BRANCH) != 0) + { + if ((op->pinfo & (INSN_WRITE_GPR_31 | INSN_WRITE_1)) != 0) + info->insn_type = dis_jsr; + else + info->insn_type = dis_branch; + } + else if ((op->pinfo2 & INSN2_COND_BRANCH) != 0) + { + if ((op->pinfo & INSN_WRITE_GPR_31) != 0) + info->insn_type = dis_condjsr; + else + info->insn_type = dis_condbranch; + } + else if ((op->pinfo & (INSN_STORE_MEMORY | INSN_LOAD_MEMORY)) != 0) + info->insn_type = dis_dref; + + return length; + } + } + + infprintf (is, dis_style_immediate, "0x%x", (unsigned) insn); + info->insn_type = dis_noninsn; + + return length; +} + +/* Set up the options and disassemble. */ + +int +print_insn_nanomips (bfd_vma memaddr, struct disassemble_info *info) +{ + set_default_nanomips_dis_options (info); + parse_nanomips_dis_options (info->disassembler_options); + + return _print_insn_nanomips (memaddr, info); +} + +/* Print description of nanoMIPS-specific command-line options. */ + +void +print_nanomips_disassembler_options (FILE *stream) +{ + unsigned int i; + + fprintf (stream, _("\n\ +The following nanoMIPS specific disassembler options are supported for use\n\ +with the -M switch (multiple options should be separated by commas):\n")); + + fprintf (stream, _("\n\ + no-aliases Use canonical instruction forms.\n")); + + fprintf (stream, _("\n\ + show-arch-insn Print extended mnemonics in disassembly including\n\ + suffix as in the architecture reference manual.\n")); + + fprintf (stream, _("\n\ + virt Recognize the virtualization ASE instructions.\n")); + + fprintf (stream, _("\n\ + mxu Recognize the MXU ASE instructions.\n")); + + fprintf (stream, _("\n\ + gpr-names=ABI Print GPR names according to specified ABI.\n\ + Default: based on binary being disassembled.\n")); + + fprintf (stream, _("\n\ + fpr-names=ABI Print FPR names according to specified ABI.\n\ + Default: numeric.\n")); + + fprintf (stream, _("\n\ + cp0-names=ARCH Print CP0 register names according to\n\ + specified architecture.\n\ + Default: based on binary being disassembled.\n")); + + fprintf (stream, _("\n\ + hwr-names=ARCH Print HWR names according to specified \n\ + architecture.\n\ + Default: based on binary being disassembled.\n")); + + fprintf (stream, _("\n\ + reg-names=ABI Print GPR and FPR names according to\n\ + specified ABI.\n")); + + fprintf (stream, _("\n\ + reg-names=ARCH Print CP0 register and HWR names according to\n\ + specified architecture.\n")); + + fprintf (stream, _("\n\ + For the options above, the following values are supported for \"ABI\":\n\ + ")); + for (i = 0; i < ARRAY_SIZE (nanomips_abi_choices); i++) + fprintf (stream, " %s", nanomips_abi_choices[i].name); + fprintf (stream, _("\n")); + + fprintf (stream, _("\n\ + For the options above, The following values are supported for \"ARCH\":\n\ + ")); + for (i = 0; i < ARRAY_SIZE (nanomips_arch_choices); i++) + if (*nanomips_arch_choices[i].name != '\0') + fprintf (stream, " %s", nanomips_arch_choices[i].name); + fprintf (stream, _("\n")); + + fprintf (stream, _("\n")); +} + +/* nanoMIPS hook to predict instruction length from opcode bits. */ + +int +nanomips_predict_insn_length (bfd_vma memaddr_base, + int previous_octect ATTRIBUTE_UNUSED, + struct disassemble_info *info) +{ + bfd_byte buffer[2]; + unsigned int length; + uint64_t insn; + bfd_vma memaddr = memaddr_base; + int status; + + status = (*info->read_memory_func) (memaddr, buffer, 2, info); + if (status != 0) + { + (*info->memory_error_func) (status, memaddr, info); + return -1; + } + + length = 2; + + if (info->endian == BFD_ENDIAN_BIG) + insn = bfd_getb16 (buffer); + else + insn = bfd_getl16 (buffer); + + if ((insn & 0xfc00) == 0x6000) + length += 4; + else if ((insn & 0x1000) == 0x0) + length += 2; + + return length; +} diff --git a/opcodes/nanomips-formats.h b/opcodes/nanomips-formats.h new file mode 100644 index 00000000000..e477313886d --- /dev/null +++ b/opcodes/nanomips-formats.h @@ -0,0 +1,265 @@ +/* nanomips-formats.h + Copyright (C) 2017-2026 Free Software Foundation, CIP United Inc. + Contributed by MIPS Tech LLC. + Written by Faraz Shahbazker <[email protected]> + + 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 program; see the file COPYING3. If not, + see <http://www.gnu.org/licenses/>. */ + +#include "libiberty.h" + +#define INT_BIAS(SIZE, LSB, MAX_VAL, BIAS, SHIFT, PRINT_HEX) \ + { \ + static const struct nanomips_int_operand op = { \ + { OP_INT, SIZE, LSB, 0, 0 }, MAX_VAL, BIAS, SHIFT, PRINT_HEX \ + }; \ + return &op.root; \ + } + +#define INT_ADJ(SIZE, LSB, MAX_VAL, SHIFT, PRINT_HEX) \ + INT_BIAS(SIZE, LSB, MAX_VAL, 0, SHIFT, PRINT_HEX) + +#define UINT(SIZE, LSB) \ + INT_ADJ(SIZE, LSB, (1 << (SIZE)) - 1, 0, false) + +#define SINT(SIZE, LSB) \ + INT_ADJ(SIZE, LSB, (1 << ((SIZE) - 1)) - 1, 0, false) + +#define HINT(SIZE, LSB) \ + INT_ADJ(SIZE, LSB, (1 << (SIZE)) - 1, 0, true) + +#define BIT(SIZE, LSB, BIAS) \ + { \ + static const struct nanomips_int_operand op = { \ + { OP_INT, SIZE, LSB, 0, 0 }, (1 << (SIZE)) - 1, BIAS, 0, false \ + }; \ + return &op.root; \ + } + +#define MAPPED_INT(SIZE, LSB, MAP, PRINT_HEX) \ + { \ + typedef char ATTRIBUTE_UNUSED \ + static_assert[(1 << (SIZE)) == ARRAY_SIZE (MAP)]; \ + static const struct nanomips_mapped_int_operand op = { \ + { OP_MAPPED_INT, SIZE, LSB, 0, 0 }, MAP, PRINT_HEX \ + }; \ + return &op.root; \ + } + +#define MSB(SIZE, LSB, BIAS, ADD_LSB, OPSIZE) \ + { \ + static const struct nanomips_msb_operand op = { \ + { OP_MSB, SIZE, LSB, 0, 0 }, BIAS, ADD_LSB, OPSIZE \ + }; \ + return &op.root; \ + } + +#define REG(SIZE, LSB, BANK) \ + { \ + static const struct nanomips_reg_operand op = { \ + { OP_REG, SIZE, LSB, 0, 0 }, OP_REG_##BANK, 0 \ + }; \ + return &op.root; \ + } + +#define OPTIONAL_REG(SIZE, LSB, BANK) \ + { \ + static const struct nanomips_reg_operand op = { \ + { OP_OPTIONAL_REG, SIZE, LSB, 0, 0 }, OP_REG_##BANK, 0 \ + }; \ + return &op.root; \ + } + +#define MAPPED_REG(SIZE, LSB, BANK, MAP) \ + { \ + typedef char ATTRIBUTE_UNUSED \ + static_assert[(1 << (SIZE)) == ARRAY_SIZE (MAP)]; \ + static const struct nanomips_reg_operand op = { \ + { OP_REG, SIZE, LSB, 0, 0 }, OP_REG_##BANK, MAP \ + }; \ + return &op.root; \ + } + +#define SPLIT_MAPPED_REG(SIZE, LSB, SIZE_T, LSB_T, BANK, MAP) \ + { \ + typedef char ATTRIBUTE_UNUSED \ + static_assert[(1 << (SIZE)) == ARRAY_SIZE (MAP)]; \ + static const struct nanomips_reg_operand op = { \ + { OP_REG, SIZE, LSB, SIZE_T, LSB_T }, OP_REG_##BANK, MAP \ + }; \ + return &op.root; \ + } + +#define OPTIONAL_MAPPED_REG(SIZE, LSB, BANK, MAP) \ + { \ + typedef char ATTRIBUTE_UNUSED \ + static_assert[(1 << (SIZE)) == ARRAY_SIZE (MAP)]; \ + static const struct nanomips_reg_operand op = { \ + { OP_OPTIONAL_REG, SIZE, LSB, 0, 0 }, OP_REG_##BANK, MAP \ + }; \ + return &op.root; \ + } + +#define REG_PAIR(SIZE, LSB, BANK, MAP) \ + { \ + typedef char ATTRIBUTE_UNUSED \ + static_assert1[(1 << (SIZE)) == ARRAY_SIZE (MAP##1)]; \ + typedef char ATTRIBUTE_UNUSED \ + static_assert2[(1 << (SIZE)) == ARRAY_SIZE (MAP##2)]; \ + static const struct nanomips_reg_pair_operand op = { \ + { OP_REG_PAIR, SIZE, LSB, 0, 0 }, OP_REG_##BANK, MAP##1, MAP##2 \ + }; \ + return &op.root; \ + } + +#define PCREL(SIZE, LSB, IS_SIGNED, SHIFT, ALIGN_LOG2, INCLUDE_ISA_BIT, \ + FLIP_ISA_BIT) \ + { \ + static const struct nanomips_pcrel_operand op = { \ + { { OP_PCREL, SIZE, LSB, 0, 0 }, \ + (1 << ((SIZE) - (IS_SIGNED))) - 1, 0, SHIFT, true }, \ + ALIGN_LOG2, INCLUDE_ISA_BIT, FLIP_ISA_BIT \ + }; \ + return &op.root.root; \ + } + +#define JUMP(SIZE, LSB, SHIFT) \ + PCREL (SIZE, LSB, false, SHIFT, SIZE + SHIFT, true, false) + +#define JALX(SIZE, LSB, SHIFT) \ + PCREL (SIZE, LSB, false, SHIFT, SIZE + SHIFT, true, true) + +#define BRANCH(SIZE, LSB, SHIFT) \ + PCREL (SIZE, LSB, true, SHIFT, 0, true, false) + +#define SPECIAL(SIZE, LSB, TYPE) \ + { \ + static const struct nanomips_operand op = { OP_##TYPE, SIZE, LSB, 0, 0 }; \ + return &op; \ + } + +#define PREV_CHECK(SIZE, LSB, GT_OK, LT_OK, EQ_OK, ZERO_OK) \ + { \ + static const struct nanomips_check_prev_operand op = { \ + { OP_CHECK_PREV, SIZE, LSB, 0, 0 }, GT_OK, LT_OK, EQ_OK, ZERO_OK \ + }; \ + return &op.root; \ + } + +#define IMM_INT_BIAS(SIZE, LSB, MAX_VAL, BIAS, SHIFT, PRINT_HEX) \ + { \ + static const struct nanomips_int_operand op = { \ + { OP_IMM_INT, SIZE, LSB, 0, 0 }, MAX_VAL, BIAS, SHIFT, PRINT_HEX \ + }; \ + return &op.root; \ + } + +#define IMM_INT_ADJ(SIZE, LSB, MAX_VAL, SHIFT, PRINT_HEX) \ + IMM_INT_BIAS(SIZE, LSB, MAX_VAL, 0, SHIFT, PRINT_HEX) + +#define UINT_SPLIT(SIZE, LSB, SHIFT, SIZE_TOP, LSB_TOP) \ + { \ + static const struct nanomips_int_operand op = { \ + { OP_INT, SIZE, LSB, SIZE_TOP, LSB_TOP }, \ + (1 << (SIZE)) - 1, 0, SHIFT, 0 \ + }; \ + return &op.root; \ + } + +#define SINT_SPLIT(SIZE, LSB, SHIFT, SIZE_TOP, LSB_TOP, BIAS) \ + { \ + static const struct nanomips_int_operand op = { \ + { OP_INT, SIZE, LSB, SIZE_TOP, LSB_TOP }, \ + (1 << ((SIZE) -1)) - 1, BIAS, SHIFT, 0 \ + }; \ + return &op.root; \ + } + +#define IMM_SINT_SPLIT(SIZE, LSB, SHIFT, SIZE_TOP, LSB_TOP, BIAS) \ + { \ + static const struct nanomips_int_operand op = { \ + { OP_IMM_INT, SIZE, LSB, SIZE_TOP, LSB_TOP }, \ + (1 << ((SIZE) -1)) - 1, BIAS, SHIFT, false \ + }; \ + return &op.root; \ + } + +#define HINT_SPLIT(SIZE, LSB, SIZE_T, LSB_T) \ + SINT_SPLIT(SIZE, LSB, 0, SIZE_T, LSB_T) + +#define SPLIT_MAPPED_REG_PAIR(SIZE, LSB, SIZE_T, LSB_T, BANK, MAP1, MAP2) \ + { \ + typedef char ATTRIBUTE_UNUSED \ + static_assert1[(1 << (SIZE)) == ARRAY_SIZE (MAP1)]; \ + typedef char ATTRIBUTE_UNUSED \ + static_assert2[(1 << (SIZE)) == ARRAY_SIZE (MAP2)]; \ + static const struct nanomips_reg_pair_operand op = { \ + { OP_REG_PAIR, SIZE, LSB, SIZE_T, LSB_T }, OP_REG_##BANK, \ + MAP1, MAP2 \ + }; \ + return &op.root; \ + } + +#define BRANCH_UNORD_SPLIT(SIZE, SHIFT) \ + { \ + static const struct nanomips_pcrel_operand op = { \ + { { OP_PCREL, SIZE, 1, 1, 0 }, \ + (1 << ((SIZE) - 1)) - 1, 0, SHIFT, true }, \ + 0, false, false \ + }; \ + return &op.root.root; \ + } + +#define BRANCH_SPLIT(SIZE, LSB, SHIFT, SIZE_TOP, LSB_TOP) \ + { \ + static const struct nanomips_pcrel_operand op = { \ + { { OP_PCREL, SIZE, 1, SIZE_TOP, LSB_TOP }, \ + (1 << ((SIZE) - 1)) - 1, LSB, SHIFT, true }, \ + 0, false, false \ + }; \ + return &op.root.root; \ + } + +#define SPECIAL_SPLIT(SIZE, LSB, SIZE_T, LSB_T, TYPE) \ + { \ + static const struct nanomips_operand op = { OP_##TYPE, SIZE, LSB, SIZE_T, LSB_T }; \ + return &op; \ + } + +#define SPECIAL_WORD(BIAS, TYPE) \ + { \ + static const struct nanomips_int_operand op = { { OP_##TYPE, 0, 0, 0, 0 }, \ + 0x7fffffff, BIAS, 0, false }; \ + return &op.root; \ + } + +#define MAPPED_PREV_CHECK(SIZE, LSB, BANK, MAP, GT_OK, LT_OK, EQ_OK, ZERO_OK) \ + { \ + typedef char ATTRIBUTE_UNUSED \ + static_assert[(1 << (SIZE)) == ARRAY_SIZE (MAP)]; \ + static const struct nanomips_mapped_check_prev_operand op = { \ + { OP_MAPPED_CHECK_PREV, SIZE, LSB, 0, 0 }, OP_REG_##BANK, MAP, \ + GT_OK, LT_OK, EQ_OK, ZERO_OK \ + }; \ + return &op.root; \ + } + +#define BASE_OFFSET_CHECK(SIZE, LSB, CONST_OK, EXPR_OK) \ + { \ + static const struct nanomips_base_check_offset_operand op = { \ + { OP_BASE_CHECK_OFFSET, SIZE, LSB, 0, 0 }, OP_REG_GP, \ + CONST_OK, EXPR_OK \ + }; \ + return &op.root; \ + } diff --git a/opcodes/nanomips-opc.c b/opcodes/nanomips-opc.c new file mode 100644 index 00000000000..d6e5523fc56 --- /dev/null +++ b/opcodes/nanomips-opc.c @@ -0,0 +1,807 @@ +/* nanomips-opc.c. nanoMIPS opcode table. + Copyright (C) 2017-2026 Free Software Foundation, CIP United Inc. + Contributed by MIPS Tech LLC. + Written by Faraz Shahbazker <[email protected]> + + This file is part of the GNU opcodes library. + + 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 "sysdep.h" +#include "opcode/nanomips.h" +#include "nanomips-formats.h" + +static unsigned char reg_0_map[] = { 0 }; +static unsigned char reg_28_map[] = { 28 }; +static unsigned char reg_29_map[] = { 29 }; +static unsigned char reg_31_map[] = { 31 }; +static unsigned char reg_m16_map[] = { 16, 17, 18, 19, 4, 5, 6, 7 }; +static unsigned char reg_q_map[] = { 0, 17, 18, 19, 4, 5, 6, 7 }; + +static unsigned char reg_4to5_map[] = { + 8, 9, 10, 11, 4, 5, 6, 7, + 16, 17, 18, 19, 20, 21, 22, 23 +}; + +static unsigned char reg_4to5_srcmap[] = { + 8, 9, 10, 0, 4, 5, 6, 7, + 16, 17, 18, 19, 20, 21, 22, 23 +}; + +static unsigned char reg_4or5_map[] = { 4, 5 }; + +static unsigned char reg_gpr2d_map1[] = { 4, 5, 6, 7 }; +static unsigned char reg_gpr2d_map2[] = { 5, 6, 7, 8 }; + +static int int_b_map[] = { + 0, 4, 8, 12, 16, 20, 24, 28 +}; + +static int int_c_map[] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 255, 65535, 14, 15 +}; + +static int word_byte_map[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 3, 0, 0, 0, 0, 0, 0, 0, + 2, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0 +}; + +static int int_mask_map[] = { + 0x1, 0x3, 0x7, 0xf, + 0x1f, 0x3f, 0x7f, 0xff, + 0x1ff, 0x3ff, 0x7ff, 0xfff, + 0x1fff, 0x3fff, 0x7fff, 0xffff, + 0x1ffff, 0x3ffff, 0x7ffff, 0xfffff, + 0x1fffff, 0x3fffff, 0x7fffff, 0xffffff, + 0x1ffffff,0x3ffffff,0x7ffffff,0xfffffff, + 0x1fffffff, 0x3fffffff, 0x7fffffff, 0xffffffff +}; + +/* Return the nanomips_operand structure for the operand at the + beginning of P. */ + +/* FIXME: Unused cases left commented in-place for quick reminder + of which character strings are unused. */ +const struct nanomips_operand * +decode_nanomips_operand (const char *p) +{ + switch (p[0]) + { + case 'm': + switch (p[1]) + { + case 'a': MAPPED_REG (0, 0, GP, reg_28_map); + case 'b': SPECIAL (5, 5, NON_ZERO_REG); + case 'c': OPTIONAL_MAPPED_REG (3, 4, GP, reg_m16_map); + case 'd': MAPPED_REG (3, 7, GP, reg_m16_map); + case 'e': MAPPED_REG (3, 1, GP, reg_m16_map); + case 'f': MAPPED_PREV_CHECK (3, 7, GP, reg_m16_map, true, false, false, false); + case 'g': MAPPED_PREV_CHECK (3, 4, GP, reg_m16_map, false, true, false, false); + case 'h': MAPPED_PREV_CHECK (3, 7, GP, reg_m16_map, false, true, true, false); + case 'i': MAPPED_PREV_CHECK (3, 4, GP, reg_m16_map, true, false, true, false); + case 'j': REG (5, 0, GP); + case 'k': SPECIAL (0, 0, REPEAT_DEST_REG); + case 'l': MAPPED_REG (3, 4, GP, reg_m16_map); + case 'm': MAPPED_REG (3, 7, GP, reg_q_map); + case 'n': SPECIAL_SPLIT (5, 0, 1, 9, SAVE_RESTORE_LIST); + case 'p': REG (5, 5, GP); + case 'q': SPLIT_MAPPED_REG_PAIR (2, 8, 1, 3, GP, reg_gpr2d_map1, + reg_gpr2d_map2); + case 'r': SPLIT_MAPPED_REG_PAIR (2, 8, 1, 3, GP, reg_gpr2d_map2, + reg_gpr2d_map1); + case 's': MAPPED_REG (0, 0, GP, reg_29_map); + case 't': SPECIAL (0, 0, REPEAT_PREV_REG); + case 'u': SPLIT_MAPPED_REG (4, 5, 1, 9, GP, reg_4to5_map); + case 'v': SPLIT_MAPPED_REG (4, 0, 1, 4, GP, reg_4to5_map); + case 'w': SPLIT_MAPPED_REG (4, 5, 1, 9, GP, reg_4to5_srcmap); + case 'x': SPLIT_MAPPED_REG (4, 0, 1, 4, GP, reg_4to5_srcmap); + case 'y': MAPPED_REG (0, 0, GP, reg_31_map); + case 'z': UINT (0, 0); /* Literal 0 */ + case 'A': INT_ADJ (7, 0, 127, 2, false); /* (0 .. 127) << 2 */ + case 'B': MAPPED_INT (3, 0, int_b_map, false); + case 'C': MAPPED_INT (4, 0, int_c_map, true); + case 'D': BRANCH_UNORD_SPLIT (10, 1); + case 'E': BRANCH_UNORD_SPLIT (7, 1); + case 'F': SPECIAL (4, 0, NON_ZERO_PCREL_S1); + case 'G': INT_ADJ (4, 4, 15, 4, false); + case 'H': INT_ADJ (2, 1, 3, 1, false); /* (0 .. 3) << 1 */ + case 'I': INT_ADJ (7, 0, 126, 0, false); /* (-1 .. 126) */ + case 'J': INT_ADJ (4, 0, 15, 2, false); /* (0 .. 15) << 2 */ + case 'K': HINT (3, 0); + case 'L': UINT (2, 0); /* (0 .. 3) */ + case 'M': INT_ADJ (3, 0, 8, 0, false); /* (1 .. 8) */ + case 'N': UINT_SPLIT (2, 8, 2, 1, 3); /* split encoded 2-bit offset << 2 */ + case 'O': IMM_INT_ADJ (7, 0, 127, 2, false); /* (0 .. 127) << 2 */ + case 'P': HINT (2, 0); + case 'Q': SINT_SPLIT (4, 0, 0, 1, 4, 0); + case 'R': INT_ADJ (5, 0, 31, 2, false); /* (0 .. 31) << 2 */ + case 'S': INT_ADJ (6, 0, 63, 2, false); /* (0 .. 63) << 2 */ + case 'Z': UINT (0, 0); /* 0 only */ + } + break; + + case '-': + switch (p[1]) + { + case 'a': SPECIAL (5, 16, DONT_CARE); + case 'b': SPECIAL_SPLIT (8, 9, 5, 16, DONT_CARE); + case 'i': REG (0, 0, GP); /* Ignored register operand. */ + case 'm': SPECIAL_SPLIT (5, 11, 5, 21, COPY_BITS); + case 'n': SPECIAL_SPLIT (5, 11, 5, 16, COPY_BITS); + } + break; + + case '+': + switch (p[1]) + { + case 'A': BIT (5, 0, 0); /* (0 .. 31) */ + case 'B': MSB (5, 6, 1, true, 32); /* (1 .. 32), 32-bit op */ + case 'C': MSB (5, 6, 1, false, 32); /* (1 .. 32), 32-bit op */ + case 'D': SPECIAL (4, 16, SAVE_RESTORE_FP_LIST); + case 'E': BIT (5, 0, 32); /* (32 .. 63) */ + case 'F': MSB (5, 6, 33, true, 64); /* (33 .. 64), 64-bit op */ + case 'G': MSB (5, 6, 33, false, 64); /* (33 .. 64), 64-bit op */ + case 'H': MSB (5, 6, 1, false, 64); /* (1 .. 32), 64-bit op */ + case 'I': BIT (5, 6, 0); /* (0 .. 31) */ + case 'J': HINT (19, 0); + case 'K': SPECIAL_SPLIT (20, 2, 1, 0, HI20_PCREL); /* tri-part 20-bit */ + case 'L': HINT (10, 16); + case 'M': HINT (18, 0); + case 'N': INT_ADJ (9, 3, 511, 3, false); /* 9-bit << 3 */ + case 'O': SPECIAL_WORD (0, GPREL_WORD); + case 'P': SPECIAL_WORD (6, IMM_WORD); + case 'Q': SPECIAL_WORD (0, UINT_WORD); + case 'R': SPECIAL_WORD (0, INT_WORD); + case 'S': SPECIAL_WORD (0, PC_WORD); + + case 'i': HINT (5, 16); + case 'j': SINT_SPLIT (9, 0, 0, 1, 15, 0); + case 'p': SINT_SPLIT (7, 2, 2, 1, 15, 0); /* split 7-bit signed << 2 */ + case 'q': SINT_SPLIT (6, 3, 3, 1, 15, 0); /* split 6-bit signed << 3 */ + case 'r': BRANCH_UNORD_SPLIT (21, 1); /* split 21-bit signed << 1 */ + case 's': IMM_SINT_SPLIT (21, 1, 1, 1, 0, 2); /* split (21-bit signed + 2) << 1 */ + case 't': SPECIAL (5, 21, NON_ZERO_REG); + case 'u': BRANCH_UNORD_SPLIT (25, 1); + case 'v': MAPPED_INT (5, 6, word_byte_map, false); + case 'w': BIT (2, 9, 0); /* (0 .. 3) */ + + case '*': INT_ADJ (4, 7, 15, 1, false); /* (0 .. 15) << 1 */ + case '|': UINT (1, 6); /* 0/1 */ + case ';': UINT (2, 21); /* (0 .. 3) */ + case '1': UINT (18, 0); + case '2': INT_ADJ (16, 2, (1<<16) - 1, 2, false); + case '3': INT_ADJ (17, 1, (1<<17) - 1, 1, false); + case '4': INT_ADJ (18, 3, (1<<18)-1, 3, false); /* 18-bit << 3 */ + case '5': SPLIT_MAPPED_REG (4, 21, 1, 25, GP, reg_4to5_srcmap); + case '6': MAPPED_INT (5, 6, int_mask_map, true); + case '7': MAPPED_REG (1, 24, GP, reg_4or5_map); + case '8': HINT (23, 3); + case '9': UINT (7, 11); + } + break; + + case '.': INT_ADJ (19, 2, (1<<19) - 1, 2, false); + case '<': BIT (5, 0, 0); /* (0 .. 31) */ +/* case '>': BIT (5, 11, 32); /\* (32 .. 63) *\/ */ + case '\\': BIT (3, 21, 0); /* (0 .. 7) */ + case '|': INT_ADJ (3, 12, 8, 0, false); /* 1 .. 8 */ + case '~': BRANCH_UNORD_SPLIT (11, 1); /* split 11-bit signed << 1 */ + case '@': SINT (10, 11); + case '^': HINT (5, 11); + case '!': UINT (1, 10); + case '$': UINT (1, 3); + case '*': REG (2, 18, ACC); +/* case '&': REG (2, 23, ACC); */ + + case '0': SINT (6, 16); + case '1': BIT (5, 11, 0); /* (0 .. 31) */ + case '2': BIT (5, 16, 0); /* (0 .. 31) */ + case '3': BIT (3, 13, 0); + case '4': BIT (4, 12, 0); + case '5': HINT (8, 13); + case '7': REG (2, 14, ACC); + case '8': HINT (7, 14); + + case 'C': HINT (23, 3); + case 'D': REG (5, 11, FP); + case 'E': REG (5, 21, COPRO); + case 'G': REG (5, 16, COPRO); + case 'H': UINT (5, 11); + case 'J': SPECIAL (5, 11, CP0SEL); + case 'K': REG (5, 16, HW); +/* case 'M': REG (3, 13, CCC); */ +/* case 'N': REG (3, 18, CCC); */ + case 'O': REG (10, 11, CP0); + case 'P': REG (5, 16, CP0SEL); +/* case 'Q': UINT (5, 11); */ + case 'R': REG (5, 11, FP); + case 'S': REG (5, 16, FP); + case 'T': REG (5, 21, FP); + case 'V': OPTIONAL_REG (5, 16, FP); + +/* case 'a': JUMP (26, 0, 1); */ + case 'b': REG (5, 16, GP); + case 'c': BASE_OFFSET_CHECK (5, 16, true, false); + case 'd': REG (5, 11, GP); + case 'e': REG (5, 3, GP); + case 'g': HINT (12, 0); + case 'h': SPECIAL (12, 0, NEG_INT); + case 'i': UINT (12, 0); + case 'j': UINT (16, 0); + case 'k': HINT (5, 21); + case 'n': SPECIAL_SPLIT (11, 2, 10, 16, SAVE_RESTORE_LIST); + case 'o': UINT (12, 0); + case 'p': BRANCH_UNORD_SPLIT (14, 1); +/* case 'q': BRANCH_UNORD_SPLIT (20, 1); - unused */ + case 'r': OPTIONAL_REG (5, 16, GP); + case 's': REG (5, 16, GP); + case 't': REG (5, 21, GP); + case 'u': SPECIAL_SPLIT (20, 2, 1, 0, HI20_INT); /* tri-part 20-bit */ + case 'v': OPTIONAL_REG (5, 16, GP); + case 'w': OPTIONAL_REG (5, 21, GP); + case 'x': SPECIAL_SPLIT (20, 2, 1, 0, HI20_SCALE); /* tri-part 20-bit */ + case 'z': MAPPED_REG (0, 0, GP, reg_0_map); + } + return 0; +} + +#define LM INSN_LOAD_MEMORY +#define SM INSN_STORE_MEMORY + +#define WR_1 INSN_WRITE_1 +#define WR_2 INSN_WRITE_2 +#define RD_1 INSN_READ_1 +#define RD_2 INSN_READ_2 +#define RD_3 INSN_READ_3 +#define MOD_1 (WR_1|RD_1) +#define MOD_2 (WR_2|RD_2) +#define FP_S INSN_FP_S +#define FP_D INSN_FP_D + + /* Write dsp accumulators */ +#define WR_a INSN_WRITE_ACC + /* Read dsp accumulators */ +#define RD_a INSN_READ_ACC + +/* Flags used in pinfo2. */ +#define CTC INSN2_CONVERTED_TO_COMPACT +#define UBR INSN2_UNCOND_BRANCH +#define CBR INSN2_COND_BRANCH +#define ALIAS INSN2_ALIAS + +/* For 32-bit nanoMIPS instructions. */ +#define WR_31 INSN_WRITE_GPR_31 + +/* nanoMIPS MT ASE support. */ +#define MT32 ASE_MT + +/* nanoMIPS instruction subset. */ +#define xNMS ASE_xNMS + +/* Base ISA for nanoMIPS. */ +#define I38 INSN_ISAN32R6 +#define I70 INSN_ISAN64R6 + +const struct nanomips_opcode nanomips_opcodes[] = { +/* These instructions appear first so that the disassembler will find + them first. The assemblers uses a hash table based on the + instruction name anyhow. */ +/* name, suffix, args, match, mask, pinfo pinfo2, membership, ase */ +/* Pure macros */ +{"la", "", "t,A(b)", 0, (int) M_LA_AB, INSN_MACRO, 0, I38, 0}, +{"dla", "", "t,A(b)", 0, (int) M_DLA_AB, INSN_MACRO, 0, I38, 0}, +/* Precedence=1 */ +{"aluipc", "", "t,+K", 0xe0000002, 0xfc000002, WR_1, 0, I38, 0}, /* ALUIPC */ +{"break", "[16]", "", 0x1010, 0xffff, 0, INSN2_ALIAS, I38, 0}, +{"break", "[16]", "mK", 0x1010, 0xfff8, 0, 0, I38, 0}, +{"break", "[32]", "", 0x00100000, 0xffffffff, 0, INSN2_ALIAS, I38, 0}, +{"break", "[32]", "+J", 0x00100000, 0xfff80000, 0, 0, I38, 0}, +{"dvp", "", "-a", 0x20000390, 0xffe0ffff, 0, INSN2_ALIAS, I38, 0}, /* DVP */ +{"dvp", "", "t,-a", 0x20000390, 0xfc00ffff, WR_1, 0, I38, 0}, +{"nop", "[16]", "", 0x9008, 0xffff, 0, 0, I38, 0}, /* NOP[16] */ +{"nop", "[32]", "", 0x8000c000, 0xffffffff, 0, 0, I38, 0}, /* NOP */ +{"sdbbp", "[16]", "", 0x1018, 0xffff, 0, INSN2_ALIAS, I38, 0}, +{"sdbbp", "[16]", "mK", 0x1018, 0xfff8, 0, 0, I38, 0}, +{"sdbbp", "[32]", "", 0x00180000, 0xffffffff, 0, INSN2_ALIAS, I38, 0}, +{"sdbbp", "[32]", "+J", 0x00180000, 0xfff80000, 0, 0, I38, 0}, +{"move", "", "mb,mj", 0x1000, 0xfc00, WR_1|RD_2, 0, I38, 0}, /* preceded by BREAK, SDBBP */ +{"move", "", "d,s", 0x20000290, 0xffe007ff, WR_1|RD_2, INSN2_ALIAS, I38, 0}, /* OR */ +{"move", "", "d,s", 0x20000150, 0xffe007ff, WR_1|RD_2, INSN2_ALIAS, I38, 0}, /* ADDU */ +{"sigrie", "", "+J", 0x00000000, 0xfff80000, 0, 0, I38, 0}, +{"synci", "[u12]", "o(b)", 0x87e03000, 0xffe0f000, RD_2, 0, I38, 0}, /* SYNCI[U12] */ +{"synci", "[s9]", "+j(b)", 0xa7e01800, 0xffe07f00, RD_2, 0, I38, 0}, /* SYNCI[S9] */ +{"jrc", "[16]", "mp", 0xd800, 0xfc1f, RD_1, 0, I38, 0}, /* JRC[16] */ +{"jrc", "[32]", "s", 0x48000000, 0xffe0ffff, RD_1, INSN2_ALIAS, I38, 0}, /* JALRC */ +{"jalrc", "[16]", "mp", 0xd810, 0xfc1f, WR_31|RD_1, 0, I38, 0}, /* JALRC[16] */ +{"jalrc", "[16]", "my,mp", 0xd810, 0xfc1f, WR_31|RD_1, INSN2_ALIAS, I38, 0}, /* JALRC[16] */ +{"jalrc", "[32]", "s", 0x4be00000, 0xffe0ffff, RD_1, INSN2_ALIAS, I38, 0}, /* JALRC[32] */ +{"jalrc", "[32]", "t,s", 0x48000000, 0xfc00ffff, WR_1|RD_2, 0, I38, 0}, +{"jalrc", "", "mp,-i", 0xd810, 0xfc1f, WR_31|RD_1, INSN2_ALIAS, I38, 0}, /* JALRC[16] */ +{"jalrc", "", "s,-i", 0x4be00000, 0xffe0ffff, RD_1, INSN2_ALIAS, I38, 0}, /* JALRC[32] */ +{"jr", "", "mp", 0xd800, 0xfc1f, RD_1, INSN2_ALIAS|UBR|CTC, I38, 0}, /* JRC */ +{"jr", "", "s", 0x48000000, 0xffe0ffff, RD_1, INSN2_ALIAS|UBR|CTC, I38, 0}, /* JALRC */ +{"jalr", "", "my,mp", 0xd810, 0xfc1f, WR_31|RD_1, INSN2_ALIAS|UBR|CTC, I38, 0}, /* JALRC[16] */ +{"jalr", "", "mp", 0xd810, 0xfc1f, WR_31|RD_1, INSN2_ALIAS|UBR|CTC, I38, 0}, /* JALRC[16] */ +{"jalr", "", "s", 0x4be00000, 0xffe0ffff, RD_1, INSN2_ALIAS|UBR|CTC, I38, 0}, /* JALRC */ +{"jalr", "", "t,s", 0x48000000, 0xfc00ffff, WR_1|RD_2, INSN2_ALIAS|UBR|CTC, I38, 0}, /* JALRC */ +{"lui", "", "t,u", 0xe0000000, 0xfc000002, WR_1, 0, I38, 0}, +{"li", "[16]", "md,mI", 0xd000, 0xfc00, WR_1, 0, I38, 0}, /* LI[16] */ +{"li", "", "mb,mZ", 0x1000, 0xfc1f, WR_1, INSN2_ALIAS, I38, 0}, /* MOVE[16] */ +{"li", "[32]", "+t,j", 0x00000000, 0xfc1f0000, WR_1, INSN2_ALIAS, I38, 0}, /* ADDIU[32] */ +{"li", "[neg]", "t,h", 0x80008000, 0xfc1ff000, WR_1, INSN2_ALIAS, I38, 0}, /* ADDIU[NEG] */ +{"li", "", "t,x", 0xe0000000, 0xfc000002, WR_1, INSN2_ALIAS, I38, 0}, /* LUI */ +{"li", "[48]", "mp,+Q", 0x6000, 0xfc1f, WR_1, 0, 0, xNMS}, /* LI[48] */ +{"li", "", "+t,A", 0, (int) M_LI, INSN_MACRO, INSN2_MACRO, I38, 0}, +{"ext", "", "t,r,+A,+C", 0x8000f000, 0xfc00f820, WR_1|RD_2, 0, 0, xNMS}, +{"ext", "", "t,r,+A,+C", 0, (int) M_EXT, INSN_MACRO, 0, I38, 0}, + +/* Precedence=0 */ +{"abs", "", "d,v", 0, (int) M_ABS, INSN_MACRO, 0, I38, 0}, +{"add", "", "d,v,t", 0x20000110, 0xfc0007ff, WR_1|RD_2|RD_3, 0, 0, xNMS}, +{"add", "", "t,r,I", 0, (int) M_ADD_I, INSN_MACRO, 0, 0, xNMS}, +{"addi", "", "t,r,I", 0, (int) M_ADD_I, INSN_MACRO, 0, 0, xNMS}, +{"addiu", "[r1.sp]", "md,ms,mS", 0x7040, 0xfc40, WR_1|RD_2, 0, I38, 0}, /* ADDIU[R1.SP] */ +{"addiu", "[r2]", "md,mc,mB", 0x9000, 0xfc08, WR_1|RD_2, 0, I38, 0}, /* ADDIU[R2] */ +{"addiu", "[rs5]", "mp,mk,mQ", 0x9008, 0xfc08, MOD_1, INSN2_ALIAS, I38, 0}, /* ADDIU[RS5] */ +{"addiu", "[rs5]", "mp,mQ", 0x9008, 0xfc08, MOD_1, 0, I38, 0}, /* ADDIU[RS5], preceded by NOP[16] */ +{"addiu", "[gp.b]", "t,ma,+1", 0x440c0000, 0xfc1c0000, WR_1|RD_2, 0, I38, 0}, /* ADDIU[GP.B] */ +{"addiu", "[gp.w]", "t,ma,.", 0x40000000, 0xfc000003, WR_1|RD_2, 0, I38, 0}, /* ADDIU[GP.W] */ +{"addiu", "[32]", "+t,r,j", 0x00000000, 0xfc000000, WR_1|RD_2, 0, I38, 0}, /* preceded by SIGRIE */ +{"addiu", "[neg]", "t,r,h", 0x80008000, 0xfc00f000, WR_1|RD_2, 0, I38, 0}, /* ADDIU[NEG] */ +{"addiu", "[48]", "mp,mt,+R", 0x6001, 0xfc1f, MOD_1, 0, 0, xNMS}, /* ADDIU[48] */ +{"addiu", "[gp48]", "mp,ma,+O", 0x6002, 0xfc1f, WR_1|RD_2, 0, 0, xNMS}, /* ADDIU[GP48] */ +{"lapc", "[32]", "t,+r", 0x04000000, 0xfc000000, WR_1, INSN2_ALIAS, I38, 0}, /* ADDIUPC */ +{"lapc", "[48]", "mp,+S", 0x6003, 0xfc1f, WR_1, INSN2_ALIAS, 0, xNMS}, /* ADDIUPC[48] */ +{"addiupc", "[32]", "t,+s", 0x04000000, 0xfc000000, WR_1, 0, I38, 0}, +{"addiupc", "[48]", "mp,+P", 0x6003, 0xfc1f, WR_1, 0, 0, xNMS}, /* ADDIUPC[48] */ +{"addiu.b", "", "t,ma,+1", 0x440c0000, 0xfc1c0000, WR_1|RD_2, INSN2_ALIAS, I38, 0}, /* ADDIU[GP.B] */ +{"addiu.w", "", "t,ma,.", 0x40000000, 0xfc000003, WR_1|RD_2, INSN2_ALIAS, I38, 0}, /* ADDIU[GP.W] */ +{"addu", "[16]", "me,mc,md", 0xb000, 0xfc01, WR_1|RD_2|RD_3, 0, I38, 0}, /* ADDU[16] */ +{"addu", "[4x4]", "mu,mt,mv", 0x3c00, 0xfd08, MOD_1|RD_3, 0, 0, xNMS}, /* ADDU[4X4] */ +{"addu", "[4x4]", "mu,mv,mk", 0x3c00, 0xfd08, MOD_1|RD_2, INSN2_ALIAS, 0, xNMS}, /* ADDU[4X4] */ +{"addu", "[32]", "d,v,t", 0x20000150, 0xfc0007ff, WR_1|RD_2|RD_3, 0, I38, 0}, +{"addu", "", "t,r,I", 0, (int) M_ADDU_I, INSN_MACRO, 0, I38, 0}, +{"extw", "", "d,s,t,+I", 0x2000001f, 0xfc00003f, WR_1|RD_2|RD_3, 0, I38, 0}, +{"align", "", "mb,-i,mj,mz", 0x1000, 0xfc00, WR_1|RD_3, INSN2_ALIAS, I38, 0}, /* MOVE[16] */ +{"align", "", "d,-i,s,mz", 0x20000290, 0xffe007ff, WR_1|RD_3, INSN2_ALIAS, I38, 0}, /* MOVE[32] */ +{"align", "", "d,s,t,+v", 0x2000001f, 0xfc00003f, WR_1|RD_2|RD_3, INSN2_ALIAS, I38, 0}, /* EXTW */ +{"and", "[16]", "md,mk,ml", 0x5008, 0xfc0f, MOD_1|RD_3, INSN2_ALIAS, I38, 0}, /* AND[16] */ +{"and", "[16]", "md,ml,mk", 0x5008, 0xfc0f, MOD_1|RD_2, INSN2_ALIAS, I38, 0}, /* AND[16] */ +{"and", "[16]", "md,ml", 0x5008, 0xfc0f, MOD_1|RD_2, 0, I38, 0}, /* AND[16] */ +{"and", "[32]", "d,v,t", 0x20000250, 0xfc0007ff, WR_1|RD_2|RD_3, 0, I38, 0}, +{"and", "[32]", "t,r,I", 0, (int) M_AND_I, INSN_MACRO, 0, I38, 0}, +{"andi", "[16]", "md,mc,mC", 0xf000, 0xfc00, WR_1|RD_2, 0, I38, 0}, /* ANDI[16] */ +{"andi", "[32]", "t,r,g", 0x80002000, 0xfc00f000, WR_1|RD_2, 0, I38, 0}, +{"andi", "", "t,r,+6", 0x8000f000, 0xfc00f83f, WR_1|RD_2, INSN2_ALIAS, 0, xNMS}, /* EXT */ +{"balc", "[16]", "mD", 0x3800, 0xfc00, WR_31, 0, I38, 0}, /* BALC[16] */ +{"balc", "[32]", "+u", 0x2a000000, 0xfe000000, WR_31, 0, I38, 0}, +{"bal", "", "mD", 0x3800, 0xfc00, WR_31, INSN2_ALIAS|UBR|CTC, I38, 0}, /* BALC[16] */ +{"bal", "", "+u", 0x2a000000, 0xfe000000, WR_31, INSN2_ALIAS|UBR|CTC, I38, 0}, /* BALC */ +{"balrsc", "", "+t,s", 0x48008000, 0xfc00ffff, WR_1|RD_2, 0, I38, 0}, +{"balrsc", "", "s", 0x4be08000, 0xffe0ffff, RD_1|WR_31, INSN2_ALIAS, I38, 0}, /* BALRSC */ +{"bbeqzc", "", "t,1,~", 0xc8040000, 0xfc1f0000, RD_1, 0, 0, xNMS}, +{"bbnezc", "", "t,1,~", 0xc8140000, 0xfc1f0000, RD_1, 0, 0, xNMS}, +{"bc", "[16]", "mD", 0x1800, 0xfc00, 0, 0, I38, 0}, /* BC[16] */ +{"bc", "[32]", "+u", 0x28000000, 0xfe000000, 0, 0, I38, 0}, +{"b", "", "mD", 0x1800, 0xfc00, 0, INSN2_ALIAS|UBR|CTC, I38, 0}, /* BC[16] */ +{"b", "", "+u", 0x28000000, 0xfe000000, 0, INSN2_ALIAS|UBR|CTC, I38, 0}, /* BC */ +{"beqzc", "[16]", "md,mE", 0x9800, 0xfc00, RD_1, 0, I38, 0}, /* BEQZC[16] */ +{"beqzc", "[32]", "t,p", 0x88000000, 0xfc1fc000, RD_1, INSN2_ALIAS, I38, 0}, /* BEQC */ +{"beqzc", "[32]", "s,p", 0x88000000, 0xffe0c000, RD_1, INSN2_ALIAS, I38, 0}, /* BEQC */ +{"beqz", "", "md,mE", 0x9800, 0xfc00, RD_1, INSN2_ALIAS|CBR|CTC, I38, 0}, /* BEQZC[16] */ +{"beqz", "", "t,p", 0x88000000, 0xfc1fc000, RD_1, INSN2_ALIAS|CBR|CTC, I38, 0}, /* BEQC */ +{"beqz", "", "s,p", 0x88000000, 0xffe0c000, RD_1, INSN2_ALIAS|CBR|CTC, I38, 0}, /* BEQC */ +{"beqc", "[16]", "md,z,mE", 0x9800, 0xfc00, RD_1, INSN2_ALIAS, I38, 0}, /* BEQZC[16] */ +{"beqc", "[16]", "z,md,mE", 0x9800, 0xfc00, RD_1, INSN2_ALIAS, I38, 0}, /* BEQZC[16] */ +{"beqc", "[16]", "ml,mf,mF", 0xd800, 0xfc00, RD_1|RD_2, 0, 0, xNMS}, /* BEQC[16], with rs3<rt3 && u[4:1]!=0 */ +{"beqc", "[16]", "md,mg,mF", 0xd800, 0xfc00, RD_1|RD_2, INSN2_ALIAS, 0, xNMS}, /* BEQC[16], with operands commutated */ +{"beqc", "[32]", "s,t,p", 0x88000000, 0xfc00c000, RD_1|RD_2, 0, I38, 0}, +{"beq", "", "md,z,mE", 0x9800, 0xfc00, RD_1, INSN2_ALIAS|CBR|CTC, I38, 0}, /* BEQZC[16] */ +{"beq", "", "z,md,mE", 0x9800, 0xfc00, RD_1, INSN2_ALIAS|CBR|CTC, I38, 0}, /* BEQZC[16] */ +{"beq", "", "ml,mf,mF", 0xd800, 0xfc00, RD_1|RD_2, INSN2_ALIAS|CBR|CTC, 0, xNMS}, /* BEQC[16], with rs3<rt3 && u[4:1]!=0 */ +{"beq", "", "md,mg,mF", 0xd800, 0xfc00, RD_1|RD_2, INSN2_ALIAS|CBR|CTC, 0, xNMS}, /* BEQC[16], with operands commutated */ +{"beq", "", "s,t,p", 0x88000000, 0xfc00c000, RD_1|RD_2, INSN2_ALIAS|CBR|CTC, I38, 0}, /* BEQC */ +{"beq", "", "s,I,p", 0, (int) M_BEQ_I, INSN_MACRO, 0, I38, 0}, +{"beqic", "", "t,+9,~", 0xc8000000, 0xfc1c0000, RD_1, 0, I38, 0}, +{"blezc", "", "t,p", 0x88008000, 0xfc1fc000, RD_1, INSN2_ALIAS, I38, 0}, /* BGEC $0, t */ +{"blez", "", "t,p", 0x88008000, 0xfc1fc000, RD_1, INSN2_ALIAS|CBR|CTC, I38, 0}, /* BGEC $0, t */ +{"bgezc", "", "s,p", 0x88008000, 0xffe0c000, RD_1, INSN2_ALIAS, I38, 0}, /* BGEC s, $0 */ +{"bgez", "", "s,p", 0x88008000, 0xffe0c000, RD_1, INSN2_ALIAS|CBR|CTC, I38, 0}, /* BGEC s, $0 */ +{"bgec", "", "s,t,p", 0x88008000, 0xfc00c000, RD_1|RD_2, 0, I38, 0}, +{"bge", "", "s,t,p", 0x88008000, 0xfc00c000, RD_1|RD_2, INSN2_ALIAS|CBR|CTC, I38, 0}, /* BGEC */ +{"bge", "", "s,I,p", 0, (int) M_BGE_I, INSN_MACRO, 0, I38, 0}, +{"bgt", "", "s,t,p", 0, (int) M_BGT, INSN_MACRO, 0, I38, 0}, +{"bgt", "", "s,I,p", 0, (int) M_BGT_I, INSN_MACRO, 0, I38, 0}, +{"bgtu", "", "s,t,p", 0, (int) M_BGTU, INSN_MACRO, 0, I38, 0}, +{"bgtu", "", "s,I,p", 0, (int) M_BGTU_I, INSN_MACRO, 0, I38, 0}, +{"ble", "", "s,t,p", 0, (int) M_BLE, INSN_MACRO, 0, I38, 0}, +{"ble", "", "s,I,p", 0, (int) M_BLE_I, INSN_MACRO, 0, I38, 0}, +{"bleu", "", "s,t,p", 0, (int) M_BLEU, INSN_MACRO, 0, I38, 0}, +{"bleu", "", "s,I,p", 0, (int) M_BLEU_I, INSN_MACRO, 0, I38, 0}, +{"bgezal", "", "s,p", 0, (int) M_BGEZAL, INSN_MACRO, 0, I38, 0}, +{"bgeic", "", "t,+9,~", 0xc8080000, 0xfc1c0000, RD_1, 0, I38, 0}, +{"bgeuc", "", "s,t,p", 0x8800c000, 0xfc00c000, RD_1|RD_2, 0, I38, 0}, +{"bgeu", "", "s,t,p", 0x8800c000, 0xfc00c000, RD_1|RD_2, INSN2_ALIAS|CBR|CTC, I38, 0}, /* BGEUC */ +{"bgeu", "", "s,I,p", 0, (int) M_BGEU_I, INSN_MACRO, 0, I38, 0}, +{"bgeiuc", "", "t,+9,~", 0xc80c0000, 0xfc1c0000, RD_1, 0, I38, 0}, +{"bitrevb", "", "t,r", 0x8000d247, 0xfc00ffff, WR_1|RD_2, INSN2_ALIAS, 0, xNMS}, /* ROTX t,s,7,8,1 */ +{"bitrevh", "", "t,r", 0x8000d40f, 0xfc00ffff, WR_1|RD_2, INSN2_ALIAS, 0, xNMS}, /* ROTX t,s,15,16 */ +{"bitrevw", "", "t,r", 0x8000d01f, 0xfc00ffff, WR_1|RD_2, INSN2_ALIAS, 0, xNMS}, /* ROTX t,s,31,0*/ +{"bitswap", "", "t,r", 0x8000d247, 0xfc00ffff, WR_1|RD_2, INSN2_ALIAS, 0, xNMS}, /* ROTX t,s,7,8,1*/ +{"bgtzc", "", "t,p", 0xa8008000, 0xfc1fc000, RD_1, INSN2_ALIAS, I38, 0}, /* BLTC $0, t */ +{"bgtz", "", "t,p", 0xa8008000, 0xfc1fc000, RD_1, INSN2_ALIAS|CBR|CTC, I38, 0}, /* BLTC $0, t */ +{"bltzc", "", "s,p", 0xa8008000, 0xffe0c000, RD_1, INSN2_ALIAS, I38, 0}, /* BLTC s, $0 */ +{"bltz", "", "s,p", 0xa8008000, 0xffe0c000, RD_1, INSN2_ALIAS|CBR|CTC, I38, 0}, /* BLTC s, $0 */ +{"bltc", "", "s,t,p", 0xa8008000, 0xfc00c000, RD_1|RD_2, 0, I38, 0}, +{"blt", "", "s,t,p", 0xa8008000, 0xfc00c000, RD_1|RD_2, INSN2_ALIAS|CBR|CTC, I38, 0}, /* BLTC */ +{"blt", "", "s,I,p", 0, (int) M_BLT_I, INSN_MACRO, 0, I38, 0}, +{"bltzal", "", "s,p", 0, (int) M_BLTZAL, INSN_MACRO, 0, I38, 0}, +{"bltic", "", "t,+9,~", 0xc8180000, 0xfc1c0000, RD_1, 0, I38, 0}, +{"bltuc", "", "s,t,p", 0xa800c000, 0xfc00c000, RD_1|RD_2, 0, I38, 0}, +{"bltu", "", "s,t,p", 0xa800c000, 0xfc00c000, RD_1|RD_2, INSN2_ALIAS|CBR|CTC, I38, 0}, /* BLTUC */ +{"bltu", "", "s,I,p", 0, (int) M_BLTU_I, INSN_MACRO, 0, I38, 0}, +{"bltiuc", "", "t,+9,~", 0xc81c0000, 0xfc1c0000, RD_1, 0, I38, 0}, +{"bnezc", "[16]", "md,mE", 0xb800, 0xfc00, RD_1, 0, I38, 0}, /* BNEZC[16] */ +{"bnezc", "[32]", "t,p", 0xa8000000, 0xfc1fc000, RD_1, INSN2_ALIAS, I38, 0}, /* BNEC */ +{"bnezc", "[32]", "s,p", 0xa8000000, 0xffe0c000, RD_1, INSN2_ALIAS, I38, 0}, /* BNEC */ +{"bnez", "", "md,mE", 0xb800, 0xfc00, RD_1, INSN2_ALIAS|CBR|CTC, I38, 0}, /* BNEZC[16] */ +{"bnez", "", "t,p", 0xa8000000, 0xfc1fc000, RD_1, INSN2_ALIAS|CBR|CTC, I38, 0}, /* BNEC */ +{"bnez", "", "s,p", 0xa8000000, 0xffe0c000, RD_1, INSN2_ALIAS, I38, 0}, /* BNEC */ +{"bnec", "[16]", "md,z,mE", 0xb800, 0xfc00, RD_1, INSN2_ALIAS, I38, 0}, /* BNEZC[16] */ +{"bnec", "[16]", "z,md,mE", 0xb800, 0xfc00, RD_2, INSN2_ALIAS, I38, 0}, /* BNEZC[16] */ +{"bnec", "[16]", "ml,mh,mF", 0xd800, 0xfc00, RD_1|RD_2, 0, 0, xNMS}, /* BNEC[16], with rs3>=rt3 && u[4:1]!=0 */ +{"bnec", "[16]", "md,mi,mF", 0xd800, 0xfc00, RD_1|RD_2, INSN2_ALIAS, 0, xNMS}, /* BNEC[16], with operands commutated */ +{"bnec", "[32]", "s,t,p", 0xa8000000, 0xfc00c000, RD_1|RD_2, 0, I38, 0}, +{"bne", "", "md,z,mE", 0xb800, 0xfc00, RD_1, INSN2_ALIAS|CBR|CTC, I38, 0}, /* BNEZC[16] */ +{"bne", "", "z,md,mE", 0xb800, 0xfc00, RD_2, INSN2_ALIAS|CBR|CTC, I38, 0}, /* BNEZC[16] */ +{"bne", "", "ml,mh,mF", 0xd800, 0xfc00, RD_1|RD_2, INSN2_ALIAS|CBR|CTC, 0, xNMS}, /* BNEC[16], with rs3>=rt3 && u[4:1]!=0 */ +{"bne", "", "md,mi,mF", 0xd800, 0xfc00, RD_1|RD_2, INSN2_ALIAS|CBR|CTC, 0, xNMS}, /* BNEC[16], with operands commutated */ +{"bne", "", "s,t,p", 0xa8000000, 0xfc00c000, RD_1|RD_2, INSN2_ALIAS|CBR|CTC, I38, 0}, /* BNEC */ +{"bne", "", "s,I,p", 0, (int) M_BNE_I, INSN_MACRO, 0, I38, 0}, +{"bneic", "", "t,+9,~", 0xc8100000, 0xfc1c0000, RD_1, 0, I38, 0}, +{"brsc", "", "s", 0x48008000, 0xffe0ffff, RD_1, 0, I38, 0}, +{"byterevh", "", "t,r", 0x8000d608, 0xfc00ffff, WR_1|RD_2, INSN2_ALIAS, 0, xNMS}, /* ROTX t,s,8,24 */ +{"byterevw", "", "t,r", 0x8000d218, 0xfc00ffff, WR_1|RD_2, INSN2_ALIAS, 0, xNMS}, /* ROTX t,s,24,8 */ +{"cache", "", "k,+j(b)", 0xa4003900, 0xfc007f00, RD_3, 0, I38, 0}, +{"cache", "", "k,A(c)", 0, (int) M_CACHE_AC, INSN_MACRO, 0, I38, 0}, +{"cfc1", "", "t,G", 0xa000103b, 0xfc00ffff, WR_1|RD_2, INSN2_ALIAS, I38, 0}, +{"cfc1", "", "t,S", 0xa000103b, 0xfc00ffff, WR_1|RD_2, 0, I38, 0}, +{"cftc1", "", "t,G", 0x20001e30, 0xfc00ffff, WR_1|RD_2, INSN2_ALIAS, 0, MT32}, /* MFTR */ +{"cftc1", "", "t,S", 0x20001e30, 0xfc00ffff, WR_1|RD_2, INSN2_ALIAS, 0, MT32}, /* MFTR */ +{"cftc2", "", "t,G", 0x20002e30, 0xfc00ffff, WR_1|RD_2, INSN2_ALIAS, 0, MT32}, /* MFTR */ +{"clo", "", "t,s", 0x20004b3f, 0xfc00ffff, WR_1|RD_2, 0, 0, xNMS}, +{"clz", "", "t,s", 0x20005b3f, 0xfc00ffff, WR_1|RD_2, 0, 0, xNMS}, +{"cop2_1", "", "C", 0x20000002, 0xfc000007, 0, 0, I38, 0}, +{"ctc1", "", "t,G", 0xa000183b, 0xfc00ffff, RD_1|WR_2, INSN2_ALIAS, I38, 0}, +{"ctc1", "", "t,S", 0xa000183b, 0xfc00ffff, RD_1|WR_2, 0, I38, 0}, +{"cttc1", "", "t,G", 0x20001e70, 0xfc00ffff, RD_1|WR_2, INSN2_ALIAS, 0, MT32}, /* MTTR */ +{"cttc1", "", "t,S", 0x20001e70, 0xfc00ffff, RD_1|WR_2, INSN2_ALIAS, 0, MT32}, /* MTTR */ +{"cttc2", "", "t,G", 0x20002e70, 0xfc00ffff, RD_1|WR_2, INSN2_ALIAS, 0, MT32}, /* MTTR */ +{"dabs", "", "d,v", 0, (int) M_DABS, INSN_MACRO, 0, I38, 0}, +{"daddiu", "[neg]", "t,r,h", 0x80008000, 0xfc00f000, WR_1|RD_2, 0, I38, 0}, /* DADDIU[NEG] */ +{"deret", "", "", 0x2000e37f, 0xffffffff, 0, 0, I38, 0}, +{"di", "", "", 0x2000477f, 0xffffffff, 0, INSN2_ALIAS, I38, 0}, +{"di", "", "w", 0x2000477f, 0xfc1fffff, WR_1, 0, I38, 0}, +{"div", "", "d,v,t", 0x20000118, 0xfc0007ff, WR_1|RD_2|RD_3, 0, I38, 0}, +{"div", "", "d,v,I", 0, (int) M_DIV_I, INSN_MACRO, 0, I38, 0}, +{"divu", "", "d,v,t", 0x20000198, 0xfc0007ff, WR_1|RD_2|RD_3, 0, I38, 0}, +{"divu", "", "d,v,I", 0, (int) M_DIVU_I, INSN_MACRO, 0, I38, 0}, +{"dmt", "", "", 0x20010ab0, 0xffffffff, 0, INSN2_ALIAS, 0, MT32}, +{"dmt", "", "t", 0x20010ab0, 0xfc1fffff, WR_1, 0, 0, MT32}, +{"dvpe", "", "", 0x20000ab0, 0xffffffff, 0, INSN2_ALIAS, 0, MT32}, /* DVPE */ +{"dvpe", "", "t", 0x20000ab0, 0xfc1fffff, WR_1, 0, 0, MT32}, +{"ehb", "", "", 0x8000c003, 0xffffffff, 0, 0, I38, 0}, +{"ei", "", "", 0x2000577f, 0xffffffff, 0, INSN2_ALIAS, I38, 0}, +{"ei", "", "t", 0x2000577f, 0xfc1fffff, WR_1, 0, I38, 0}, +{"emt", "", "", 0x20010eb0, 0xffffffff, 0, INSN2_ALIAS, 0, MT32}, +{"emt", "", "t", 0x20010eb0, 0xfc1fffff, WR_1, 0, 0, MT32}, +{"eret", "", "", 0x2000f37f, 0xffffffff, 0, 0, I38, 0}, +{"eretnc", "", "", 0x2001f37f, 0xffffffff, 0, 0, I38, 0}, +{"evpe", "", "", 0x20000eb0, 0xffffffff, 0, INSN2_ALIAS, 0, MT32}, /* EVPE */ +{"evpe", "", "t", 0x20000eb0, 0xfc1fffff, WR_1, 0, 0, MT32}, +{"evp", "", "-a", 0x20000790, 0xffe0ffff, 0, INSN2_ALIAS, I38, 0}, /* EVP */ +{"evp", "", "t,-a", 0x20000790, 0xfc00ffff, WR_1, 0, I38, 0}, +{"fork", "", "d,s,t", 0x20000228, 0xfc0007ff, WR_1|RD_2|RD_3, 0, 0, MT32}, +{"ins", "", "t,r,+A,+B", 0x8000e000, 0xfc00f820, WR_1|RD_2, 0, 0, xNMS}, +{"ins", "", "t,r,+A,+B", 0, (int) M_INS, INSN_MACRO, 0, I38, 0}, +{"j", "", "mp", 0xd800, 0xfc1f, RD_1, INSN2_ALIAS|UBR|CTC, I38, 0}, +{"j", "", "+u", 0x28000000, 0xfe000000, 0, INSN2_ALIAS|UBR|CTC, I38, 0}, /* BC */ +{"j", "", "s", 0x48000000, 0xffe0ffff, RD_1, INSN2_ALIAS|UBR|CTC, I38, 0}, /* JALRC */ +{"jrc.hb", "", "s", 0x48001000, 0xffe0ffff, RD_1, INSN2_ALIAS, I38, 0}, /* JALRC.HB */ +{"jr.hb", "", "s", 0x48001000, 0xffe0ffff, RD_1, INSN2_ALIAS|UBR|CTC, I38, 0}, /* JALRC.HB */ +{"jalrc.hb", "", "s", 0x4be01000, 0xffe0ffff, RD_1, INSN2_ALIAS, I38, 0}, /* JALRC.HB */ +{"jalrc.hb", "", "t,s", 0x48001000, 0xfc00ffff, WR_1|RD_2, 0, I38, 0}, +{"jalr.hb", "", "s", 0x4be01000, 0xffe0ffff, RD_1, INSN2_ALIAS|UBR|CTC, I38, 0}, /* JALRC.HB */ +{"jalr.hb", "", "t,s", 0x48001000, 0xfc00ffff, WR_1|RD_2, INSN2_ALIAS|UBR|CTC, I38, 0}, /* JALRC.HB */ +/* SVR4 PIC code requires special handling for jal, so it must be a macro. */ +{"jal", "", "my,mp", 0xd810, 0xfc1f, WR_31|RD_1, INSN2_ALIAS|UBR|CTC, I38, 0}, /* JALRC[16] */ +{"jal", "", "mp", 0xd810, 0xfc1f, WR_31|RD_1, INSN2_ALIAS|UBR|CTC, I38, 0}, /* JALRC[16] */ +{"jal", "", "s", 0x4be00000, 0xffe0ffff, RD_1, INSN2_ALIAS|UBR|CTC, I38, 0}, /* JALRC */ +{"jal", "", "t,s", 0x48000000, 0xfc00ffff, WR_1|RD_2, INSN2_ALIAS|UBR|CTC, I38, 0}, /* JALRC */ +{"jal", "", "A", 0, (int) M_JAL_A, INSN_MACRO, 0, I38, 0}, +{"jal", "", "+u", 0x2a000000, 0xfe000000, WR_31, INSN2_ALIAS|UBR|CTC, I38, 0}, /* BALC */ +{"lb", "[16]", "md,mL(ml)", 0x5c00, 0xfc0c, WR_1|RD_3, 0, I38, 0}, /* LB[16] */ +{"lb", "[gp]", "t,+1(ma)", 0x44000000, 0xfc1c0000, WR_1|RD_3, 0, I38, 0}, /* LB[GP] */ +{"lb", "[u12]", "t,o(b)", 0x84000000, 0xfc00f000, WR_1|RD_3, 0, I38, 0}, /* LB[U12] */ +{"lb", "[s9]", "t,+j(b)", 0xa4000000, 0xfc007f00, WR_1|RD_3, 0, I38, 0}, /* LB[S9] */ +{"lb", "", "t,A(c)", 0, (int) M_LB_AC, INSN_MACRO, 0, I38, 0}, +{"lbu", "[16]", "md,mL(ml)", 0x5c08, 0xfc0c, WR_1|RD_3, 0, I38, 0}, /* LBU[16] */ +{"lbu", "[gp]", "t,+1(ma)", 0x44080000, 0xfc1c0000, WR_1|RD_3, 0, I38, 0}, /* LBU[GP] */ +{"lbu", "[u12]", "t,o(b)", 0x84002000, 0xfc00f000, WR_1|RD_3, 0, I38, 0}, /* LBU[U12] */ +{"lbu", "[s9]", "t,+j(b)", 0xa4001000, 0xfc007f00, WR_1|RD_3, 0, I38, 0}, /* LBU[S9] */ +{"lbu", "", "t,A(c)", 0, (int) M_LBU_AC, INSN_MACRO, 0, I38, 0}, +{"lbux", "", "d,s(t)", 0x20000107, 0xfc0007ff, WR_1|RD_2|RD_3, 0, I38, 0}, +{"lbx", "", "d,s(t)", 0x20000007, 0xfc0007ff, WR_1|RD_2|RD_3, 0, I38, 0}, +{"ld", "", "t,A(c)", 0, (int) M_LD_AC, INSN_MACRO, 0, I38, 0}, +{"lh", "[16]", "md,mH(ml)", 0x7c00, 0xfc09, WR_1|RD_3, 0, I38, 0}, /* LH[16] */ +{"lh", "[gp]", "t,+3(ma)", 0x44100000, 0xfc1c0001, WR_1|RD_3, 0, I38, 0}, /* LH[GP] */ +{"lh", "[u12]", "t,o(b)", 0x84004000, 0xfc00f000, WR_1|RD_3, 0, I38, 0}, /* LH[U12] */ +{"lh", "[s9]", "t,+j(b)", 0xa4002000, 0xfc007f00, WR_1|RD_3, 0, I38, 0}, /* LH[S9] */ +{"lh", "", "t,A(c)", 0, (int) M_LH_AC, INSN_MACRO, 0, I38, 0}, +{"lhu", "[16]", "md,mH(ml)", 0x7c08, 0xfc09, WR_1|RD_3, 0, I38, 0}, /* LHU[16] */ +{"lhu", "[gp]", "t,+3(ma)", 0x44100001, 0xfc1c0001, WR_1|RD_3, 0, I38, 0}, /* LHU[GP] */ +{"lhu", "[u12]", "t,o(b)", 0x84006000, 0xfc00f000, WR_1|RD_3, 0, I38, 0}, /* LHU[U12] */ +{"lhu", "[s9]", "t,+j(b)", 0xa4003000, 0xfc007f00, WR_1|RD_3, 0, I38, 0}, /* LHU[S9] */ +{"lhu", "", "t,A(c)", 0, (int) M_LHU_AC, INSN_MACRO, 0, I38, 0}, +{"lhux", "", "d,s(t)", 0x20000307, 0xfc0007ff, WR_1|RD_2|RD_3, 0, I38, 0}, +{"lhuxs", "", "d,s(t)", 0x20000347, 0xfc0007ff, WR_1|RD_2|RD_3, 0, I38, 0}, +{"lhx", "", "d,s(t)", 0x20000207, 0xfc0007ff, WR_1|RD_2|RD_3, 0, I38, 0}, +{"lhxs", "", "d,s(t)", 0x20000247, 0xfc0007ff, WR_1|RD_2|RD_3, 0, I38, 0}, +{"li.d", "", "t,F", 0, (int) M_LI_D, INSN_MACRO, 0, I38, 0}, +{"li.s", "", "t,f", 0, (int) M_LI_S, INSN_MACRO, 0, I38, 0}, +{"ll", "", "t,+p(b)", 0xa4005100, 0xfc007f03, WR_1|RD_3, 0, I38, 0}, +{"ll", "", "t,A(c)", 0, (int) M_LL_AC, INSN_MACRO, 0, I38, 0}, +{"llwp", "", "t,e,(b)", 0xa4005101, 0xfc00ff07, WR_1|WR_2|RD_3, 0, 0, xNMS}, +{"lsa", "", "d,v,t,+w", 0x2000000f, 0xfc0001ff, WR_1|RD_2|RD_3, 0, I38, 0}, +{"lw", "[16]", "md,mJ(ml)", 0x1400, 0xfc00, WR_1|RD_3, 0, I38, 0}, /* LW[16] */ +{"lw", "[4x4]", "mu,mN(mv)", 0x7400, 0xfc00, WR_1|RD_3, 0, 0, xNMS}, /* LW[4X4] */ +{"lw", "[sp]", "mp,mR(ms)", 0x3400, 0xfc00, WR_1|RD_3, 0, I38, 0}, /* LW[SP] */ +{"lw", "[gp16]", "md,mO(ma)", 0x5400, 0xfc00, WR_1|RD_3, 0, I38, 0}, /* LW[GP16] */ +{"lw", "[gp]", "t,.(ma)", 0x40000002, 0xfc000003, WR_1|RD_3, 0, I38, 0}, /* LW[GP] */ +{"lw", "[gp16]", "md,mA(ma)", 0x5400, 0xfc00, WR_1|RD_3, 0, I38, 0}, /* LW[GP16] */ +{"lw", "[u12]", "t,o(b)", 0x84008000, 0xfc00f000, WR_1|RD_3, 0, I38, 0}, /* LW[U12] */ +{"lw", "[s9]", "t,+j(b)", 0xa4004000, 0xfc007f00, WR_1|RD_3, 0, I38, 0}, /* LW[S9] */ +{"lw", "", "t,A(c)", 0, (int) M_LW_AC, INSN_MACRO, 0, I38, 0}, +{"lwm", "", "t,+j(b),|", 0xa4000400, 0xfc000f00, WR_1|RD_3, 0, 0, xNMS}, /* LWM */ +{"lwpc", "[48]", "mp,+S", 0x600b, 0xfc1f, WR_1, 0, 0, xNMS}, /* LWPC[48] */ +{"lwx", "", "d,s(t)", 0x20000407, 0xfc0007ff, WR_1|RD_2|RD_3, 0, I38, 0}, +{"lwxs", "[16]", "me,ml(md)", 0x5001, 0xfc01, WR_1|RD_2|RD_3, 0, I38, 0}, /* LWXS[16] */ +{"lwxs", "[32]", "d,s(t)", 0x20000447, 0xfc0007ff, WR_1|RD_2|RD_3, 0, I38, 0}, +{"mfc0", "", "t,O", 0x20000030, 0xfc0007ff, WR_1, INSN2_ALIAS, I38, 0}, /* MFC0 with named register */ +{"mfc0", "", "t,P,J", 0x20000030, 0xfc0007ff, WR_1, INSN2_ALIAS, I38, 0}, /* MFC0 with named register & select */ +{"mfc0", "", "t,G,J", 0x20000030, 0xfc0007ff, WR_1, 0, I38, 0}, +{"mfhc0", "", "t,O", 0x20000038, 0xfc0007ff, WR_1, INSN2_ALIAS, I38, 0}, /* MFHC0 with named register */ +{"mfhc0", "", "t,P,J", 0x20000038, 0xfc0007ff, WR_1, INSN2_ALIAS, I38, 0}, /* MFHC0 with named register & select*/ +{"mfhc0", "", "t,G,J", 0x20000038, 0xfc0007ff, WR_1, 0, I38, 0}, +{"mftc0", "", "t,O", 0x20000230, 0xfc0007ff, WR_1, INSN2_ALIAS, 0, MT32}, /* MFTR with named register */ +{"mftc0", "", "t,P,J", 0x20000230, 0xfc0007ff, WR_1, INSN2_ALIAS, 0, MT32}, /* MFTR with named register & select */ +{"mfthc0", "", "t,O", 0x20000238, 0xfc0007ff, WR_1, INSN2_ALIAS, 0, MT32}, /* MFTR with named register */ +{"mfthc0", "", "t,P,J", 0x20000238, 0xfc0007ff, WR_1, INSN2_ALIAS, 0, MT32}, /* MFTR with named register & select*/ +{"mftc1", "", "t,S", 0x20001630, 0xfc00ffff, WR_1|RD_2|FP_S, INSN2_ALIAS, 0, MT32}, /* MFTR */ +{"mftc1", "", "t,G", 0x20001630, 0xfc00ffff, WR_1|RD_2|FP_S, INSN2_ALIAS, 0, MT32}, /* MFTR */ +{"mftc2", "", "t,G", 0x20002630, 0xfc00ffff, WR_1, INSN2_ALIAS, 0, MT32}, /* MFTR */ +{"mftdsp", "", "t", 0x20100e30, 0xfc1fffff, WR_1, INSN2_ALIAS, 0, MT32}, /* MFTR */ +{"mftgpr", "", "t,s", 0x20000630, 0xfc00ffff, WR_1|RD_2, INSN2_ALIAS, 0, MT32}, /* MFTR */ +{"mfthc1", "", "t,S", 0x20001638, 0xfc00ffff, WR_1|RD_2|FP_D, INSN2_ALIAS, 0, MT32}, /* MFTR */ +{"mfthc1", "", "t,G", 0x20001638, 0xfc00ffff, WR_1|RD_2|FP_D, INSN2_ALIAS, 0, MT32}, /* MFTR */ +{"mfthc2", "", "t,G", 0x20002638, 0xfc00ffff, WR_1, INSN2_ALIAS, 0, MT32}, /* MFTR */ +{"mfthi", "", "t", 0x20010e30, 0xfc1fffff, WR_1|RD_a, INSN2_ALIAS, 0, MT32}, /* MFTR */ +{"mfthi", "", "t,*", 0x20010e30, 0xfc13ffff, WR_1|RD_a, INSN2_ALIAS, 0, MT32}, /* MFTR */ +{"mftlo", "", "t", 0x20000e30, 0xfc1fffff, WR_1|RD_a, INSN2_ALIAS, 0, MT32}, /* MFTR */ +{"mftlo", "", "t,*", 0x20000e30, 0xfc13ffff, WR_1|RD_a, INSN2_ALIAS, 0, MT32}, /* MFTR */ +{"mftr", "", "t,s,!,H,$", 0x20000230, 0xfc0003f7, WR_1, 0, 0, MT32}, +{"mod", "", "d,v,t", 0x20000158, 0xfc0007ff, WR_1|RD_2|RD_3, 0, I38, 0}, +{"mod", "", "d,v,I", 0, (int) M_MOD_I, INSN_MACRO, 0, I38, 0}, +{"modu", "", "d,v,t", 0x200001d8, 0xfc0007ff, WR_1|RD_2|RD_3, 0, I38, 0}, +{"modu", "", "d,v,I", 0, (int) M_MODU_I, INSN_MACRO, 0, I38, 0}, +{"move.balc", "", "+7,+5,+r", 0x08000000, 0xfc000000, WR_1|RD_2, 0, 0, xNMS}, +{"move.bal", "", "+7,+5,+r", 0x08000000, 0xfc000000, WR_1|RD_2, INSN2_ALIAS|UBR|CTC, 0, xNMS}, /* MOVE.BALC */ +{"movep", "", "mq,mx,mw", 0xbc00, 0xfc00, WR_1|RD_2|RD_3, 0, 0, xNMS}, /* MOVEP */ +{"movep", "", "mr,mw,mx", 0xbc00, 0xfc00, WR_1|RD_2|RD_3, INSN2_ALIAS, 0, xNMS}, /* MOVEP */ +{"movep", "[rev]", "mv,mu,mq", 0xfc00, 0xfc00, WR_1|WR_2|RD_3, 0, 0, xNMS}, /* MOVEP[REV] */ +{"movep", "[rev]", "mu,mv,mr", 0xfc00, 0xfc00, WR_1|WR_2|RD_3, INSN2_ALIAS, 0, xNMS}, /* MOVEP[REV] */ +{"movn", "", "d,v,t", 0x20000610, 0xfc0007ff, WR_1|RD_2|RD_3, 0, I38, 0}, +{"movz", "", "d,v,t", 0x20000210, 0xfc0007ff, WR_1|RD_2|RD_3, 0, I38, 0}, +{"mtc0", "", "t,O", 0x20000070, 0xfc0007ff, RD_1, INSN2_ALIAS, I38, 0}, /* MTC0 with named register */ +{"mtc0", "", "t,P,J", 0x20000070, 0xfc0007ff, RD_1, INSN2_ALIAS, I38, 0}, /* MTCO with named register & select */ +{"mtc0", "", "t,G,J", 0x20000070, 0xfc0007ff, RD_1, 0, I38, 0}, +{"mthc0", "", "t,O", 0x20000078, 0xfc0007ff, RD_1, INSN2_ALIAS, I38, 0}, /* MTHC0 with named register */ +{"mthc0", "", "t,P,J", 0x20000078, 0xfc0007ff, RD_1, INSN2_ALIAS, I38, 0}, /* MTHC0 with named register & select */ +{"mthc0", "", "t,G,J", 0x20000078, 0xfc0007ff, RD_1, 0, I38, 0}, +{"mttc0", "", "t,O", 0x20000270, 0xfc0007ff, RD_1, INSN2_ALIAS, 0, MT32}, /* MTTR with named register */ +{"mttc0", "", "t,P,J", 0x20000270, 0xfc0007ff, RD_1, INSN2_ALIAS, 0, MT32}, /* MTTR with named register & select */ +{"mtthc0", "", "t,O", 0x20000278, 0xfc0007ff, RD_1, INSN2_ALIAS, 0, MT32}, /* MTTR with named register*/ +{"mtthc0", "", "t,P,J", 0x20000278, 0xfc0007ff, RD_1, INSN2_ALIAS, 0, MT32}, /* MTTR with named register & select */ +{"mttc1", "", "t,S", 0x20001670, 0xfc00ffff, RD_1|WR_2|FP_S, INSN2_ALIAS, 0, MT32}, /* MTTR */ +{"mttc1", "", "t,G", 0x20001670, 0xfc00ffff, RD_1|WR_2|FP_S, INSN2_ALIAS, 0, MT32}, /* MTTR */ +{"mttc2", "", "t,G", 0x20002670, 0xfc00ffff, RD_1, INSN2_ALIAS, 0, MT32}, /* MTTR */ +{"mttgpr", "", "t,s", 0x20000670, 0xfc00ffff, RD_1|WR_2, INSN2_ALIAS, 0, MT32}, /* MTTR */ +{"mtthc1", "", "t,S", 0x20001678, 0xfc00ffff, RD_1|WR_2|FP_D, INSN2_ALIAS, 0, MT32}, /* MTTR */ +{"mtthc1", "", "t,G", 0x20001678, 0xfc00ffff, RD_1|WR_2|FP_D, INSN2_ALIAS, 0, MT32}, /* MTTR */ +{"mtthc2", "", "t,G", 0x20002678, 0xfc00ffff, RD_1, INSN2_ALIAS, 0, MT32}, /* MTTR */ +{"mtthi", "", "t", 0x20010e70, 0xfc1fffff, RD_1|WR_a, INSN2_ALIAS, 0, MT32}, /* MTTR */ +{"mtthi", "", "t,*", 0x20010e70, 0xfc13ffff, RD_1|WR_a, INSN2_ALIAS, 0, MT32}, /* MTTR */ +{"mttlo", "", "t", 0x20000e70, 0xfc1fffff, RD_1|WR_a, INSN2_ALIAS, 0, MT32}, /* MTTR */ +{"mttlo", "", "t,*", 0x20000e70, 0xfc13ffff, RD_1|WR_a, INSN2_ALIAS, 0, MT32}, /* MTTR */ +{"mttdsp", "", "t", 0x20100e70, 0xfc1fffff, RD_1, INSN2_ALIAS, 0, MT32}, /* MTTR */ +{"mttr", "", "t,s,!,H,$", 0x20000270, 0xfc0003f7, RD_1, 0, 0, MT32}, +{"muh", "", "d,v,t", 0x20000058, 0xfc0007ff, WR_1|RD_2|RD_3, 0, I38, 0}, +{"muhu", "", "d,v,t", 0x200000d8, 0xfc0007ff, WR_1|RD_2|RD_3, 0, I38, 0}, +{"mul", "[4x4]", "mu,mt,mv", 0x3c08, 0xfd08, MOD_1|RD_3, 0, 0, xNMS}, /* MUL[4X4] */ +{"mul", "[4x4]", "mu,mv,mk", 0x3c08, 0xfd08, MOD_1|RD_2, INSN2_ALIAS, 0, xNMS}, /* MUL[4X4] */ +{"mul", "[32]", "d,v,t", 0x20000018, 0xfc0007ff, WR_1|RD_2|RD_3, 0, I38, 0}, +{"mul", "", "d,v,I", 0, (int) M_MUL_I, INSN_MACRO, 0, I38, 0}, +{"mulu", "", "d,v,t", 0x20000098, 0xfc0007ff, WR_1|RD_2|RD_3, 0, I38, 0}, +{"neg", "", "d,w", 0x20000190, 0xfc1f07ff, WR_1|RD_2, INSN2_ALIAS, 0, xNMS}, /* SUB */ +{"negu", "", "d,w", 0x200001d0, 0xfc1f07ff, WR_1|RD_2, INSN2_ALIAS, I38, 0}, /* SUBU */ +{"not", "[16]", "md,ml", 0x5000, 0xfc0f, WR_1|RD_2, 0, I38, 0}, /* NOT[16] */ +{"not", "[32]", "d,v", 0x200002d0, 0xffe007ff, WR_1|RD_2, INSN2_ALIAS, I38, 0}, /* NOR */ +{"nor", "", "d,v,t", 0x200002d0, 0xfc0007ff, WR_1|RD_2|RD_3, 0, I38, 0}, +{"nor", "", "t,r,I", 0, (int) M_NOR_I, INSN_MACRO, 0, I38, 0}, +{"or", "[16]", "md,mk,ml", 0x500c, 0xfc0f, WR_1|RD_3, INSN2_ALIAS, I38, 0}, /* OR[16] */ +{"or", "[16]", "md,ml,mk", 0x500c, 0xfc0f, WR_1|RD_2, INSN2_ALIAS, I38, 0}, /* OR[16] */ +{"or", "[16]", "md,ml", 0x500c, 0xfc0f, WR_1|RD_2, 0, I38, 0}, /* OR[16] */ +{"or", "[32]", "d,v,t", 0x20000290, 0xfc0007ff, WR_1|RD_2|RD_3, 0, I38, 0}, +{"or", "", "t,r,I", 0, (int) M_OR_I, INSN_MACRO, 0, I38, 0}, +{"ori", "", "t,r,g", 0x80000000, 0xfc00f000, WR_1|RD_2, 0, I38, 0}, +{"pause", "", "", 0x8000c005, 0xffffffff, 0, 0, I38, 0}, +{"pref", "[u12]", "k,o(b)", 0x84003000, 0xfc00f000, RD_3, 0, I38, 0}, /* PREF[U12] */ +{"pref", "[s9]", "k,+j(b)", 0xa4001800, 0xfc007f00, RD_3, 0, I38, 0}, /* PREF[S9], preceded by SYNCI[S9] */ +{"pref", "", "k,A(c)", 0, (int) M_PREF_AC, INSN_MACRO, 0, I38, 0}, +{"rdhwr", "", "t,K", 0x200001c0, 0xfc00ffff, WR_1|RD_2, INSN2_ALIAS, 0, xNMS}, +{"rdpgpr", "", "t,s", 0x2000e17f, 0xfc00ffff, WR_1|RD_2, 0, I38, 0}, +{"rem", "", "d,v,t", 0x20000158, 0xfc0007ff, WR_1|RD_2|RD_3, INSN2_ALIAS, I38, 0}, /* MOD */ +{"rem", "", "d,v,I", 0, (int) M_REM_3I, INSN_MACRO, 0, I38, 0}, +{"remu", "", "d,v,t", 0x200001d8, 0xfc0007ff, WR_1|RD_2|RD_3, INSN2_ALIAS, I38, 0}, /* MODU */ +{"restore", "[32]", "+N,n", 0x80003002, 0xfc00f003, 0, 0, I38, 0}, +{"restore.jrc", "[16]", "mG", 0x1d00, 0xff0f, 0, 0, I38, 0}, /* RESTORE.JRC[16] */ +{"restore.jrc", "[16]", "mG,mn", 0x1d00, 0xfd00, 0, 0, I38, 0}, /* RESTORE.JRC[16], preceded by RESTORE[16] */ +{"restore.jrc", "[32]", "+N", 0x80003003, 0xfffff007, 0, 0, I38, 0}, /* RESTORE.JRC[32] */ +{"restore.jrc", "[32]", "+N,n", 0x80003003, 0xfc00f003, 0, 0, I38, 0}, +{"jraddiusp", "", "mG", 0x1d00, 0xff0f, 0, INSN2_ALIAS, I38, 0}, /* RESTORE.JRC[16] */ +{"jraddiusp", "", "+N", 0x80003003, 0xfffff007, 0, INSN2_ALIAS, I38, 0}, /* RESTORE.JRC[32] */ +{"jraddiusp", "", "I", 0, (int) M_JRADDIUSP, INSN_MACRO, 0, I38, 0}, +{"rol", "", "d,v,t", 0, (int) M_ROL, INSN_MACRO, 0, I38, 0}, +{"rol", "", "d,v,I", 0, (int) M_ROL_I, INSN_MACRO, 0, I38, 0}, +{"rotrv", "", "d,s,t", 0x200000d0, 0xfc0007ff, WR_1|RD_2|RD_3, 0, I38, 0}, +{"rotr", "", "t,r,<", 0x8000c0c0, 0xfc00ffe0, WR_1|RD_2, 0, I38, 0}, +{"rotr", "", "d,v,t", 0x200000d0, 0xfc0007ff, WR_1|RD_2|RD_3, INSN2_ALIAS, I38, 0}, /* ROTRV */ +{"ror", "", "t,r,<", 0x8000c0c0, 0xfc00ffe0, WR_1|RD_2, INSN2_ALIAS, I38, 0}, /* ROTR */ +{"ror", "", "d,v,t", 0x200000d0, 0xfc0007ff, WR_1|RD_2|RD_3, INSN2_ALIAS, I38, 0}, /* ROTRV */ +{"ror", "", "d,v,I", 0, (int) M_ROR_I, INSN_MACRO, 0, I38, 0}, +{"rorv", "", "t,r,<", 0x8000c0c0, 0xfc00ffe0, WR_1|RD_2, INSN2_ALIAS, I38, 0}, /* ROTR */ +{"rorv", "", "d,v,t", 0x200000d0, 0xfc0007ff, WR_1|RD_2|RD_3, INSN2_ALIAS, I38, 0}, /* ROTRV */ +{"rotl", "", "d,v,t", 0, (int) M_ROL, INSN_MACRO, 0, I38, 0}, +{"rotl", "", "d,v,I", 0, (int) M_ROL_I, INSN_MACRO, 0, I38, 0}, +{"wsbh", "", "t,r", 0x8000d608, 0xfc00ffff, WR_1|RD_2, INSN2_ALIAS, 0, xNMS}, /* ROTX t,s,8,24*/ +{"rotx", "", "t,r,<,+*", 0x8000d000, 0xfc00f860, WR_1|RD_2, INSN2_ALIAS, 0, xNMS}, +{"rotx", "", "t,r,<,+*,+|", 0x8000d000, 0xfc00f820, WR_1|RD_2, 0, 0, xNMS}, +{"save", "[16]", "mG", 0x1c00, 0xff0f, 0, 0, I38, 0}, /* SAVE[16] */ +{"save", "[16]", "mG,mn", 0x1c00, 0xfd00, 0, 0, I38, 0}, /* SAVE[16] */ +{"save", "[32]", "+N,n", 0x80003000, 0xfc00f003, 0, 0, I38, 0}, +{"sb", "[16]", "mm,mL(ml)", 0x5c04, 0xfc0c, RD_1|RD_3, 0, I38, 0}, /* SB[16] */ +{"sb", "[gp]", "t,+1(ma)", 0x44040000, 0xfc1c0000, RD_1|RD_3, 0, I38, 0}, /* SB[GP] */ +{"sb", "[u12]", "t,o(b)", 0x84001000, 0xfc00f000, RD_1|RD_3, 0, I38, 0}, /* SB[U12] */ +{"sb", "[s9]", "t,+j(b)", 0xa4000800, 0xfc007f00, RD_1|RD_3, 0, I38, 0}, /* SB[S9] */ +{"sb", "", "t,A(c)", 0, (int) M_SB_AC, INSN_MACRO, 0, I38, 0}, +{"sbx", "", "d,s(t)", 0x20000087, 0xfc0007ff, RD_1|RD_2|RD_3, 0, 0, xNMS}, +{"sc", "", "t,+p(b)", 0xa4005900, 0xfc007f03, MOD_1|RD_3, 0, I38, 0}, +{"sc", "", "t,A(c)", 0, (int) M_SC_AC, INSN_MACRO, 0, I38, 0}, +{"scwp", "", "t,e,(b)", 0xa4005901, 0xfc00ff07, MOD_1|WR_2|RD_3, 0, 0, xNMS}, +{"sd", "", "t,A(c)", 0, (int) M_SD_AC, INSN_MACRO, 0, I38, 0}, +{"seb", "", "t,r", 0x20000008, 0xfc00ffff, WR_1|RD_2, 0, 0, xNMS}, +{"seh", "", "t,r", 0x20000048, 0xfc00ffff, WR_1|RD_2, 0, I38, 0}, +{"seqi", "", "t,r,i", 0x80006000, 0xfc00f000, WR_1|RD_2, 0, I38, 0}, +{"seq", "", "d,v,t", 0, (int) M_SEQ, INSN_MACRO, 0, I38, 0}, +{"seq", "", "d,v,I", 0, (int) M_SEQ_I, INSN_MACRO, 0, I38, 0}, +{"sge", "", "d,v,t", 0, (int) M_SGE, INSN_MACRO, 0, I38, 0}, +{"sge", "", "d,v,I", 0, (int) M_SGE_I, INSN_MACRO, 0, I38, 0}, +{"sgeu", "", "d,v,t", 0, (int) M_SGEU, INSN_MACRO, 0, I38, 0}, +{"sgeu", "", "d,v,I", 0, (int) M_SGEU_I, INSN_MACRO, 0, I38, 0}, +{"sgt", "", "d,v,t", 0, (int) M_SGT, INSN_MACRO, 0, I38, 0}, +{"sgt", "", "d,v,I", 0, (int) M_SGT_I, INSN_MACRO, 0, I38, 0}, +{"sgtu", "", "d,v,t", 0, (int) M_SGTU, INSN_MACRO, 0, I38, 0}, +{"sgtu", "", "d,v,I", 0, (int) M_SGTU_I, INSN_MACRO, 0, I38, 0}, +{"sh", "[16]", "mm,mH(ml)", 0x7c01, 0xfc09, RD_1|RD_3, 0, I38, 0}, /* SH[16] */ +{"sh", "[gp]", "t,+3(ma)", 0x44140000, 0xfc1c0001, RD_1|RD_3, 0, I38, 0}, /* SH[GP] */ +{"sh", "[u12]", "t,o(b)", 0x84005000, 0xfc00f000, RD_1|RD_3, 0, I38, 0}, /* SH[U12] */ +{"sh", "[s9]", "t,+j(b)", 0xa4002800, 0xfc007f00, RD_1|RD_3, 0, I38, 0}, /* SH[S9] */ +{"sh", "", "t,A(c)", 0, (int) M_SH_AC, INSN_MACRO, 0, I38, 0}, +{"shx", "", "d,s(t)", 0x20000287, 0xfc0007ff, RD_1|RD_2|RD_3, 0, 0, xNMS}, +{"shxs", "", "d,s(t)", 0x200002c7, 0xfc0007ff, RD_1|RD_2|RD_3, 0, 0, xNMS}, +{"sync", "", "", 0x8000c006, 0xffffffff, 0, 0, I38, 0}, +{"sync", "", "+i", 0x8000c006, 0xffe0ffff, 0, 0, I38, 0}, +{"sle", "", "d,v,t", 0, (int) M_SLE, INSN_MACRO, 0, I38, 0}, +{"sle", "", "d,v,I", 0, (int) M_SLE_I, INSN_MACRO, 0, I38, 0}, +{"sleu", "", "d,v,t", 0, (int) M_SLEU, INSN_MACRO, 0, I38, 0}, +{"sleu", "", "d,v,I", 0, (int) M_SLEU_I, INSN_MACRO, 0, I38, 0}, +{"sllv", "", "d,s,t", 0x20000010, 0xfc0007ff, WR_1|RD_2|RD_3, 0, I38, 0}, +{"sll", "[16]", "md,mc,mM", 0x3000, 0xfc08, WR_1|RD_2, 0, I38, 0}, /* SLL[16] */ +{"sll", "[32]", "t,r,<", 0x8000c000, 0xfc00ffe0, WR_1|RD_2, 0, I38, 0}, /* preceded by EHB, PAUSE, SYNC */ +{"sll", "[32]", "d,v,t", 0x20000010, 0xfc0007ff, WR_1|RD_2|RD_3, INSN2_ALIAS, I38, 0}, /* SLLV */ +{"slt", "", "d,v,t", 0x20000350, 0xfc0007ff, WR_1|RD_2|RD_3, 0, I38, 0}, +{"slt", "", "d,v,I", 0, (int) M_SLT_I, INSN_MACRO, 0, I38, 0}, +{"slti", "", "t,r,i", 0x80004000, 0xfc00f000, WR_1|RD_2, 0, I38, 0}, +{"sltiu", "", "t,r,i", 0x80005000, 0xfc00f000, WR_1|RD_2, 0, I38, 0}, +{"sltu", "", "d,v,t", 0x20000390, 0xfc0007ff, WR_1|RD_2|RD_3, 0, I38, 0}, /* preceded by DVP */ +{"sltu", "", "d,v,I", 0, (int) M_SLTU_I, INSN_MACRO, 0, I38, 0}, +{"sne", "", "d,v,t", 0, (int) M_SNE, INSN_MACRO, 0, I38, 0}, +{"sne", "", "d,v,I", 0, (int) M_SNE_I, INSN_MACRO, 0, I38, 0}, +{"sov", "", "d,v,t", 0x200003d0, 0xfc0007ff, WR_1|RD_2|RD_3, 0, I38, 0}, +{"srav", "", "d,s,t", 0x20000090, 0xfc0007ff, WR_1|RD_2|RD_3, 0, I38, 0}, +{"sra", "", "t,r,<", 0x8000c080, 0xfc00ffe0, WR_1|RD_2, 0, I38, 0}, +{"sra", "", "d,v,t", 0x20000090, 0xfc0007ff, WR_1|RD_2|RD_3, INSN2_ALIAS, I38, 0}, /* SRAV */ +{"srlv", "", "d,s,t", 0x20000050, 0xfc0007ff, WR_1|RD_2|RD_3, 0, I38, 0}, +{"srl", "[16]", "md,mc,mM", 0x3008, 0xfc08, WR_1|RD_2, 0, I38, 0}, /* SRL[16] */ +{"srl", "[32]", "t,r,<", 0x8000c040, 0xfc00ffe0, WR_1|RD_2, 0, I38, 0}, +{"srl", "[32]", "d,v,t", 0x20000050, 0xfc0007ff, WR_1|RD_2|RD_3, INSN2_ALIAS, I38, 0}, /* SRLV */ +{"sub", "", "d,v,t", 0x20000190, 0xfc0007ff, WR_1|RD_2|RD_3, 0, 0, xNMS}, +{"sub", "", "t,r,I", 0, (int) M_SUB_I, INSN_MACRO, 0, 0, xNMS}, +{"subu", "[16]", "me,mc,md", 0xb001, 0xfc01, WR_1|RD_2|RD_3, 0, I38, 0}, /* SUBU[16] */ +{"subu", "[32]", "d,v,t", 0x200001d0, 0xfc0007ff, WR_1|RD_2|RD_3, 0, I38, 0}, +{"subu", "", "d,v,I", 0, (int) M_SUBU_I, INSN_MACRO, 0, I38, 0}, +{"sw", "[16]", "mm,mJ(ml)", 0x9400, 0xfc00, RD_1|RD_3, 0, I38, 0}, /* SW[16] */ +{"sw", "[sp]", "mp,mR(ms)", 0xb400, 0xfc00, RD_1|RD_3, 0, I38, 0}, /* SW[SP] */ +{"sw", "[4x4]", "mw,mN(mv)", 0xf400, 0xfc00, RD_1|RD_3, 0, 0, xNMS}, /* SW[4X4] */ +{"sw", "[gp16]", "mm,mO(ma)", 0xd400, 0xfc00, RD_1|RD_3, 0, I38, 0}, /* SW[GP16] */ +{"sw", "[gp]", "t,.(ma)", 0x40000003, 0xfc000003, RD_1|RD_3, 0, I38, 0}, /* SW[GP] */ +{"sw", "[gp16]", "mm,mA(ma)", 0xd400, 0xfc00, RD_1|RD_3, 0, I38, 0}, /* SW[GP16] */ +{"sw", "[u12]", "t,o(b)", 0x84009000, 0xfc00f000, RD_1|RD_3, 0, I38, 0}, /* SW[U12] */ +{"sw", "[s9]", "t,+j(b)", 0xa4004800, 0xfc007f00, RD_1|RD_3, 0, I38, 0}, /* SW[S9] */ +{"sw", "", "t,A(c)", 0, (int) M_SW_AC, INSN_MACRO, 0, I38, 0}, +{"swm", "", "t,+j(b),|", 0xa4000c00, 0xfc000f00, RD_1|RD_3, 0, 0, xNMS}, /* SWM */ +{"swpc", "[48]", "mp,+S", 0x600f, 0xfc1f, WR_1, 0, 0, xNMS}, /* SWPC[48] */ +{"swx", "", "d,s(t)", 0x20000487, 0xfc0007ff, RD_1|RD_2|RD_3, 0, 0, xNMS}, +{"swxs", "", "d,s(t)", 0x200004c7, 0xfc0007ff, RD_1|RD_2|RD_3, 0, 0, xNMS}, +{"syscall", "[16]", "", 0x1008, 0xffff, 0, INSN2_ALIAS, I38, 0}, /* SYSCALL[16] */ +{"syscall", "[16]", "mP", 0x1008, 0xfffc, 0, 0, I38, 0}, /* SYSCALL[16] */ +{"syscall", "[32]", "", 0x00080000, 0xffffffff, 0, INSN2_ALIAS, I38, 0}, +{"syscall", "[32]", "+M", 0x00080000, 0xfffc0000, 0, 0, I38, 0}, +{"teq", "", "s,t", 0x20000000, 0xfc00ffff, RD_1|RD_2, INSN2_ALIAS, 0, xNMS}, /* TEQ */ +{"teq", "", "s,t,^", 0x20000000, 0xfc0007ff, RD_1|RD_2, 0, 0, xNMS}, /* TEQ */ +{"teq", "", "s,I", 0, (int) M_TEQ_I, INSN_MACRO, 0, 0, xNMS}, +{"tne", "", "s,t", 0x20000400, 0xfc00ffff, RD_1|RD_2, INSN2_ALIAS, 0, xNMS}, /* TNE */ +{"tne", "", "s,t,^", 0x20000400, 0xfc0007ff, RD_1|RD_2, 0, 0, xNMS}, /* TNE */ +{"tne", "", "s,I", 0, (int) M_TNE_I, INSN_MACRO, 0, 0, xNMS}, +{"ualh", "", "t,+j(b)", 0xa4002100, 0xfc007f00, WR_1|RD_3, 0, 0, xNMS}, +{"ualw", "", "t,+j(b)", 0xa4001500, 0xfc007f00, WR_1|RD_3, INSN2_ALIAS, 0, xNMS}, /* UALWM */ +{"ualwm", "", "t,+j(b),|", 0xa4000500, 0xfc000f00, WR_1|RD_3, 0, 0, xNMS}, /* UALWM */ +{"uash", "", "t,+j(b)", 0xa4002900, 0xfc007f00, RD_1|RD_3, 0, 0, xNMS}, +{"uasw", "", "t,+j(b)", 0xa4001d00, 0xfc007f00, RD_1|RD_3, INSN2_ALIAS, 0, xNMS}, /* UASWM */ +{"uaswm", "", "t,+j(b),|", 0xa4000d00, 0xfc000f00, RD_1|RD_3, 0, 0, xNMS}, /* UASWM */ +{"uld", "", "t,A(c)", 0, (int) M_ULD_AC, INSN_MACRO, 0, 0, xNMS}, +{"ulh", "", "t,A(c)", 0, (int) M_ULH_AC, INSN_MACRO, 0, 0, xNMS}, +{"ulw", "", "t,A(c)", 0, (int) M_ULW_AC, INSN_MACRO, 0, 0, xNMS}, +{"usd", "", "t,A(c)", 0, (int) M_USD_AC, INSN_MACRO, 0, 0, xNMS}, +{"ush", "", "t,A(c)", 0, (int) M_USH_AC, INSN_MACRO, 0, 0, xNMS}, +{"usw", "", "t,A(c)", 0, (int) M_USW_AC, INSN_MACRO, 0, 0, xNMS}, +{"wait", "", "", 0x2000c37f, 0xffffffff, 0, INSN2_ALIAS, I38, 0}, +{"wait", "", "+L", 0x2000c37f, 0xfc00ffff, 0, 0, I38, 0}, +{"wrpgpr", "", "t,r", 0x2000f17f, 0xfc00ffff, WR_1|RD_2, 0, I38, 0}, +{"xor", "[16]", "md,mk,ml", 0x5004, 0xfc0f, WR_1|RD_3, INSN2_ALIAS, I38, 0}, /* XOR[16] */ +{"xor", "[16]", "md,ml,mk", 0x5004, 0xfc0f, WR_1|RD_2, INSN2_ALIAS, I38, 0}, /* XOR[16] */ +{"xor", "[16]", "md,ml", 0x5004, 0xfc0f, WR_1|RD_2, 0, I38, 0}, /* XOR[16] */ +{"xor", "[32]", "d,v,t", 0x20000310, 0xfc0007ff, WR_1|RD_2|RD_3, 0, I38, 0}, +{"xor", "", "t,r,I", 0, (int) M_XOR_I, INSN_MACRO, 0, I38, 0}, +{"xori", "", "t,r,g", 0x80001000, 0xfc00f000, WR_1|RD_2, 0, I38, 0}, +{"yield", "", "s", 0x20000268, 0xffe0ffff, RD_1, INSN2_ALIAS, 0, MT32}, +{"yield", "", "t,s", 0x20000268, 0xfc00ffff, WR_1|RD_2, 0, 0, MT32}, +}; + +const int bfd_nanomips_num_opcodes = + ((sizeof nanomips_opcodes) / (sizeof (nanomips_opcodes[0]))); -- 2.39.5