This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
[committed] Add structures to describe MIPS operands
- From: Richard Sandiford <rdsandiford at googlemail dot com>
- To: binutils at sourceware dot org
- Date: Sun, 14 Jul 2013 14:29:01 +0100
- Subject: [committed] Add structures to describe MIPS operands
This patch adds some enums and structures to classify MIPS operands.
It also adds functions for decoding the text operands used in mips-opc.c
and micromips-opc.c into structure form. (The next patch will handle
MIPS16.)
As a first step, the patch uses the structures when disassembling
(mips-dis.c) and when checking the integrity of the opcode table
(tc-mips.c). Later patches use them for other things too.
Tested on various targets and applied.
Richard
include/opcode/
* mips.h (mips_operand_type, mips_reg_operand_type): New enums.
(mips_operand, mips_int_operand, mips_mapped_int_operand)
(mips_msb_operand, mips_reg_operand, mips_reg_pair_operand)
(mips_pcrel_operand): New structures.
(mips_insert_operand, mips_extract_operand, mips_signed_operand)
(mips_decode_int_operand, mips_decode_pcrel_operand): New functions.
(decode_mips_operand, decode_micromips_operand): Declare.
opcodes/
* mips-formats.h: New file.
* mips-opc.c: Include mips-formats.h.
(reg_0_map): New static array.
(decode_mips_operand): New function.
* micromips-opc.c: Remove <stdio.h> include. Include mips-formats.h.
(reg_0_map, reg_28_map, reg_29_map, reg_31_map, reg_m16_map)
(reg_mn_map, reg_q_map, reg_h_map1, reg_h_map2, int_b_map)
(int_c_map): New static arrays.
(decode_micromips_operand): New function.
* mips-dis.c (micromips_to_32_reg_b_map, micromips_to_32_reg_c_map)
(micromips_to_32_reg_d_map, micromips_to_32_reg_e_map)
(micromips_to_32_reg_f_map, micromips_to_32_reg_g_map)
(micromips_to_32_reg_h_map1, micromips_to_32_reg_h_map2)
(micromips_to_32_reg_l_map, micromips_to_32_reg_m_map)
(micromips_to_32_reg_n_map, micromips_to_32_reg_q_map)
(micromips_imm_b_map, micromips_imm_c_map): Delete.
(print_reg): New function.
(mips_print_arg_state): New structure.
(init_print_arg_state, print_insn_arg): New functions.
(print_insn_args): Change interface and use mips_operand structures.
Delete GET_OP_S. Move GET_OP definition to...
(print_insn_mips): ...here. Update the call to print_insn_args.
(print_insn_micromips): Use print_insn_args.
gas/
* config/tc-mips.c (validate_mips_insn): Move further up file.
Add insn_bits and decode_operand arguments. Use the mips_operand
fields to work out which bits an operand occupies. Detect double
definitions.
(validate_micromips_insn): Move further up file. Call into
validate_mips_insn.
Index: include/opcode/mips.h
===================================================================
*** include/opcode/mips.h 2013-07-14 10:33:21.087809400 +0100
--- include/opcode/mips.h 2013-07-14 10:43:31.113619048 +0100
*************** #define OP_SH_IMMY 0
*** 332,337 ****
--- 332,623 ----
#define OP_SH_EVAOFFSET 7
#define OP_MASK_EVAOFFSET 0x1ff
+ /* Enumerates the various types of MIPS operand. */
+ enum mips_operand_type {
+ /* Described by mips_int_operand. */
+ OP_INT,
+
+ /* Described by mips_mapped_int_operand. */
+ OP_MAPPED_INT,
+
+ /* Described by mips_msb_operand. */
+ OP_MSB,
+
+ /* Described by mips_reg_operand. */
+ OP_REG,
+
+ /* Described by mips_reg_pair_operand. */
+ OP_REG_PAIR,
+
+ /* Described by mips_pcrel_operand. */
+ OP_PCREL,
+
+ /* A performance register. The field is 5 bits in size, but the supported
+ values are much more restricted. */
+ OP_PERF_REG,
+
+ /* The final operand in a microMIPS ADDIUSP instruction. It mostly acts
+ as a normal 9-bit signed offset that is multiplied by four, but there
+ are four special cases:
+
+ -2 * 4 => -258 * 4
+ -1 * 4 => -257 * 4
+ 0 * 4 => 256 * 4
+ 1 * 4 => 257 * 4. */
+ OP_ADDIUSP_INT,
+
+ /* The target of a (D)CLO or (D)CLZ instruction. The operand spans two
+ 5-bit register fields, both of which must be set to the destination
+ register. */
+ OP_CLO_CLZ_DEST,
+
+ /* A register list for a microMIPS LWM or SWM instruction. The operand
+ size determines whether the 16-bit or 32-bit encoding is required. */
+ OP_LWM_SWM_LIST,
+
+ /* A 10-bit field VVVVVNNNNN used for octobyte and quadhalf instructions:
+
+ V Meaning
+ ----- -------
+ 0EEE0 8 copies of $vN[E], OB format
+ 0EE01 4 copies of $vN[E], QH format
+ 10110 all 8 elements of $vN, OB format
+ 10101 all 4 elements of $vN, QH format
+ 11110 8 copies of immediate N, OB format
+ 11101 4 copies of immediate N, QH format. */
+ OP_MDMX_IMM_REG,
+
+ /* 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,
+
+ /* $pc, which has no encoding in the architectural instruction. */
+ OP_PC
+ };
+
+ /* Enumerates the types of MIPS register. */
+ enum mips_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,
+
+ /* Coprocessor condition code registers $cc0-$cc7. FPU condition codes
+ can also be written $fcc0-$fcc7. */
+ OP_REG_CCC,
+
+ /* FPRs used in a vector capacity. They can be written $f0-$f31
+ or $v0-$v31, although the latter form is not used for the VR5400
+ vector instructions. */
+ OP_REG_VEC,
+
+ /* DSP accumulator registers $ac0-$ac3. */
+ OP_REG_ACC,
+
+ /* Coprocessor registers $0-$31. Mnemonic names like c0_cause can
+ also be used in some contexts. */
+ OP_REG_COPRO,
+
+ /* Hardware registers $0-$31. Mnemonic names like hwr_cpunum can
+ also be used in some contexts. */
+ OP_REG_HW
+ };
+
+ /* Base class for all operands. */
+ struct mips_operand
+ {
+ /* The type of the operand. */
+ enum mips_operand_type type;
+
+ /* The operand occupies SIZE bits of the instruction, starting at LSB. */
+ unsigned short size;
+ unsigned short lsb;
+ };
+
+ /* Describes an integer operand with a regular encoding pattern. */
+ struct mips_int_operand
+ {
+ struct mips_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. */
+ bfd_boolean print_hex;
+ };
+
+ /* Uses a lookup table to describe a small integer operand. */
+ struct mips_mapped_int_operand
+ {
+ struct mips_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. */
+ bfd_boolean 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 mips_msb_operand
+ {
+ struct mips_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. */
+ bfd_boolean add_lsb;
+
+ /* The maximum value of MSB + 1. */
+ unsigned int opsize;
+ };
+
+ /* Describes a single register operand. */
+ struct mips_reg_operand
+ {
+ struct mips_operand root;
+
+ /* The type of register. */
+ enum mips_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 encodes a pair of registers. */
+ struct mips_reg_pair_operand
+ {
+ struct mips_operand root;
+
+ /* The type of register. */
+ enum mips_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 mips_pcrel_operand
+ {
+ struct mips_operand root;
+
+ /* The low ALIGN_LOG2 bits of the base PC are cleared to give PC'. */
+ unsigned int align_log2 : 8;
+
+ /* The operand is shifted left SHIFT places and added to PC'.
+ The operand is signed if IS_SIGNED. */
+ unsigned int shift : 8;
+ unsigned int is_signed : 1;
+
+ /* 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;
+ };
+
+ /* Return a version of INSN in which the field specified by OPERAND
+ has value UVAL. */
+
+ static inline unsigned int
+ mips_insert_operand (const struct mips_operand *operand, unsigned int insn,
+ unsigned int uval)
+ {
+ unsigned int mask;
+
+ mask = (1 << operand->size) - 1;
+ insn &= ~(mask << operand->lsb);
+ insn |= (uval & mask) << operand->lsb;
+ return insn;
+ }
+
+ /* Extract OPERAND from instruction INSN. */
+
+ static inline unsigned int
+ mips_extract_operand (const struct mips_operand *operand, unsigned int insn)
+ {
+ return (insn >> operand->lsb) & ((1 << operand->size) - 1);
+ }
+
+ /* UVAL is the value encoded by OPERAND. Return it in signed form. */
+
+ static inline int
+ mips_signed_operand (const struct mips_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
+ mips_decode_int_operand (const struct mips_int_operand *operand,
+ unsigned int uval)
+ {
+ uval |= (operand->max_val - uval) & -(1 << operand->root.size);
+ uval += operand->bias;
+ uval <<= operand->shift;
+ 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
+ mips_decode_pcrel_operand (const struct mips_pcrel_operand *operand,
+ bfd_vma base_pc, unsigned int uval)
+ {
+ bfd_vma addr;
+
+ addr = base_pc & -(1 << operand->align_log2);
+ if (operand->is_signed)
+ addr += mips_signed_operand (&operand->root, uval) * (1 << operand->shift);
+ else
+ addr += uval << operand->shift;
+ if (operand->include_isa_bit)
+ addr |= base_pc & 1;
+ if (operand->flip_isa_bit)
+ addr ^= 1;
+ return addr;
+ }
+
/* This structure holds information for a particular instruction. */
struct mips_opcode
*************** enum
*** 1215,1220 ****
--- 1501,1507 ----
Many instructions are short hand for other instructions (i.e., The
jal <register> instruction is short for jalr <register>). */
+ extern const struct mips_operand *decode_mips_operand (const char *);
extern const struct mips_opcode mips_builtin_opcodes[];
extern const int bfd_mips_num_builtin_opcodes;
extern struct mips_opcode *mips_opcodes;
*************** #define MICROMIPSOP_MASK_EVAOFFSET 0x1ff
*** 1780,1785 ****
--- 2067,2073 ----
" bcdefghij lmn pq st xyz"
*/
+ extern const struct mips_operand *decode_micromips_operand (const char *);
extern const struct mips_opcode micromips_opcodes[];
extern const int bfd_micromips_num_opcodes;
Index: opcodes/mips-formats.h
===================================================================
*** /dev/null 2013-07-07 08:24:27.294569946 +0100
--- opcodes/mips-formats.h 2013-07-14 10:35:55.849156274 +0100
***************
*** 0 ****
--- 1,113 ----
+ /* mips-formats.h
+ Copyright 2013 Free Software Foundation, Inc.
+
+ 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/>. */
+
+ /* For ARRAY_SIZE. */
+ #include "libiberty.h"
+
+ #define INT_ADJ(SIZE, LSB, MAX_VAL, SHIFT, PRINT_HEX) \
+ { \
+ static const struct mips_int_operand op = { \
+ { OP_INT, SIZE, LSB }, MAX_VAL, 0, SHIFT, PRINT_HEX \
+ }; \
+ return &op.root; \
+ }
+
+ #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 mips_int_operand op = { \
+ { OP_INT, SIZE, LSB }, (1 << (SIZE)) - 1, BIAS, 0, TRUE \
+ }; \
+ return &op.root; \
+ }
+
+ #define MAPPED_INT(SIZE, LSB, MAP, PRINT_HEX) \
+ { \
+ typedef char static_assert[(1 << (SIZE)) == ARRAY_SIZE (MAP)]; \
+ static const struct mips_mapped_int_operand op = { \
+ { OP_MAPPED_INT, SIZE, LSB }, MAP, PRINT_HEX \
+ }; \
+ return &op.root; \
+ }
+
+ #define MSB(SIZE, LSB, BIAS, ADD_LSB, OPSIZE) \
+ { \
+ static const struct mips_msb_operand op = { \
+ { OP_MSB, SIZE, LSB }, BIAS, ADD_LSB, OPSIZE \
+ }; \
+ return &op.root; \
+ }
+
+ #define REG(SIZE, LSB, BANK) \
+ { \
+ static const struct mips_reg_operand op = { \
+ { OP_REG, SIZE, LSB }, OP_REG_##BANK, 0 \
+ }; \
+ return &op.root; \
+ }
+
+ #define MAPPED_REG(SIZE, LSB, BANK, MAP) \
+ { \
+ typedef char static_assert[(1 << (SIZE)) == ARRAY_SIZE (MAP)]; \
+ static const struct mips_reg_operand op = { \
+ { OP_REG, SIZE, LSB }, OP_REG_##BANK, MAP \
+ }; \
+ return &op.root; \
+ }
+
+ #define REG_PAIR(SIZE, LSB, BANK, MAP) \
+ { \
+ typedef char static_assert1[(1 << (SIZE)) == ARRAY_SIZE (MAP##1)]; \
+ typedef char static_assert2[(1 << (SIZE)) == ARRAY_SIZE (MAP##2)]; \
+ static const struct mips_reg_pair_operand op = { \
+ { OP_REG_PAIR, SIZE, LSB }, OP_REG_##BANK, MAP##1, MAP##2 \
+ }; \
+ return &op.root; \
+ }
+
+ #define PCREL(SIZE, LSB, ALIGN_LOG2, SHIFT, IS_SIGNED, INCLUDE_ISA_BIT, \
+ FLIP_ISA_BIT) \
+ { \
+ static const struct mips_pcrel_operand op = { \
+ { OP_PCREL, SIZE, LSB }, ALIGN_LOG2, SHIFT, IS_SIGNED, \
+ INCLUDE_ISA_BIT, FLIP_ISA_BIT \
+ }; \
+ return &op.root; \
+ }
+
+ #define JUMP(SIZE, LSB, SHIFT) \
+ PCREL (SIZE, LSB, SIZE + SHIFT, SHIFT, FALSE, TRUE, FALSE)
+
+ #define JALX(SIZE, LSB, SHIFT) \
+ PCREL (SIZE, LSB, SIZE + SHIFT, SHIFT, FALSE, TRUE, TRUE)
+
+ #define BRANCH(SIZE, LSB, SHIFT) \
+ PCREL (SIZE, LSB, 0, SHIFT, TRUE, TRUE, FALSE)
+
+ #define SPECIAL(SIZE, LSB, TYPE) \
+ { \
+ static const struct mips_operand op = { OP_##TYPE, SIZE, LSB }; \
+ return &op; \
+ }
Index: opcodes/mips-opc.c
===================================================================
*** opcodes/mips-opc.c 2013-07-14 10:33:21.087809400 +0100
--- opcodes/mips-opc.c 2013-07-14 10:35:55.851156293 +0100
***************
*** 28,33 ****
--- 28,150 ----
#include "sysdep.h"
#include <stdio.h>
#include "opcode/mips.h"
+ #include "mips-formats.h"
+
+ static unsigned char reg_0_map[] = { 0 };
+
+ /* Return the mips_operand structure for the operand at the beginning of P. */
+
+ const struct mips_operand *
+ decode_mips_operand (const char *p)
+ {
+ switch (p[0])
+ {
+ case '+':
+ switch (p[1])
+ {
+ case '1': HINT (5, 6);
+ case '2': HINT (10, 6);
+ case '3': HINT (15, 6);
+ case '4': HINT (20, 6);
+
+ case 'A': BIT (5, 6, 0); /* (0 .. 31) */
+ case 'B': MSB (5, 11, 1, TRUE, 32); /* (1 .. 32), 32-bit op */
+ case 'C': MSB (5, 11, 1, FALSE, 32); /* (1 .. 32), 32-bit op */
+ case 'E': BIT (5, 6, 32); /* (32 .. 63) */
+ case 'F': MSB (5, 11, 33, TRUE, 64); /* (33 .. 64), 64-bit op */
+ case 'G': MSB (5, 11, 33, FALSE, 64); /* (33 .. 64), 64-bit op */
+ case 'H': MSB (5, 11, 1, FALSE, 64); /* (1 .. 32), 64-bit op */
+ case 'J': HINT (10, 11);
+ case 'P': BIT (5, 6, 32); /* (32 .. 63) */
+ case 'Q': SINT (10, 6);
+ case 'S': MSB (5, 11, 0, FALSE, 63); /* (0 .. 31), 64-bit op */
+ case 'X': BIT (5, 16, 32); /* (32 .. 63) */
+ case 'Z': REG (5, 0, FP);
+
+ case 'a': SINT (8, 6);
+ case 'b': SINT (8, 3);
+ case 'c': INT_ADJ (9, 6, 255, 4, FALSE); /* (-256 .. 255) << 4 */
+ case 'i': JALX (26, 0, 2);
+ case 'j': SINT (9, 7);
+ case 'p': BIT (5, 6, 0); /* (0 .. 31), 32-bit op */
+ case 's': MSB (5, 11, 0, FALSE, 31); /* (0 .. 31) */
+ case 't': REG (5, 16, COPRO);
+ case 'x': BIT (5, 16, 0); /* (0 .. 31) */
+ case 'z': REG (5, 0, GP);
+ }
+ break;
+
+ case '<': BIT (5, 6, 0); /* (0 .. 31) */
+ case '>': BIT (5, 6, 32); /* (32 .. 63) */
+ case '%': UINT (3, 21);
+ case ':': SINT (7, 19);
+ case '\'': HINT (6, 16);
+ case '@': SINT (10, 16);
+ case '!': UINT (1, 5);
+ case '$': UINT (1, 4);
+ case '*': REG (2, 18, ACC);
+ case '&': REG (2, 13, ACC);
+ case '~': SINT (12, 0);
+ case '\\': BIT (3, 12, 0); /* (0 .. 7) */
+
+ case '0': SINT (6, 20);
+ case '1': HINT (5, 6);
+ case '2': HINT (2, 11);
+ case '3': HINT (3, 21);
+ case '4': HINT (4, 21);
+ case '5': HINT (8, 16);
+ case '6': HINT (5, 21);
+ case '7': REG (2, 11, ACC);
+ case '8': HINT (6, 11);
+ case '9': REG (2, 21, ACC);
+
+ case 'B': HINT (20, 6);
+ case 'C': HINT (25, 0);
+ case 'D': REG (5, 6, FP);
+ case 'E': REG (5, 16, COPRO);
+ case 'G': REG (5, 11, COPRO);
+ case 'H': UINT (3, 0);
+ case 'J': HINT (19, 6);
+ case 'K': REG (5, 11, HW);
+ case 'M': REG (3, 8, CCC);
+ case 'N': REG (3, 18, CCC);
+ case 'O': UINT (3, 21);
+ case 'P': SPECIAL (5, 1, PERF_REG);
+ case 'Q': SPECIAL (10, 16, MDMX_IMM_REG);
+ case 'R': REG (5, 21, FP);
+ case 'S': REG (5, 11, FP);
+ case 'T': REG (5, 16, FP);
+ case 'U': SPECIAL (10, 11, CLO_CLZ_DEST);
+ case 'V': REG (5, 11, FP);
+ case 'W': REG (5, 16, FP);
+ case 'X': REG (5, 6, VEC);
+ case 'Y': REG (5, 11, VEC);
+ case 'Z': REG (5, 16, VEC);
+
+ case 'a': JUMP (26, 0, 2);
+ case 'b': REG (5, 21, GP);
+ case 'c': HINT (10, 16);
+ case 'd': REG (5, 11, GP);
+ case 'e': UINT (3, 22)
+ case 'g': REG (5, 11, COPRO);
+ case 'h': HINT (5, 11);
+ case 'i': HINT (16, 0);
+ case 'j': SINT (16, 0);
+ case 'k': HINT (5, 16);
+ case 'o': SINT (16, 0);
+ case 'p': BRANCH (16, 0, 2);
+ case 'q': HINT (10, 6);
+ case 'r': REG (5, 21, GP);
+ case 's': REG (5, 21, GP);
+ case 't': REG (5, 16, GP);
+ case 'u': HINT (16, 0);
+ case 'v': REG (5, 21, GP);
+ case 'w': REG (5, 16, GP);
+ case 'x': REG (0, 0, GP);
+ case 'z': MAPPED_REG (0, 0, GP, reg_0_map);
+ }
+ return 0;
+ }
/* Short hand so the lines aren't too long. */
Index: opcodes/micromips-opc.c
===================================================================
*** opcodes/micromips-opc.c 2013-07-14 10:33:21.087809400 +0100
--- opcodes/micromips-opc.c 2013-07-14 10:35:55.849156274 +0100
***************
*** 20,27 ****
MA 02110-1301, USA. */
#include "sysdep.h"
- #include <stdio.h>
#include "opcode/mips.h"
#define UBD INSN_UNCOND_BRANCH_DELAY
#define CBD INSN_COND_BRANCH_DELAY
--- 20,174 ----
MA 02110-1301, USA. */
#include "sysdep.h"
#include "opcode/mips.h"
+ #include "mips-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, 2, 3, 4, 5, 6, 7 };
+ static unsigned char reg_mn_map[] = { 0, 17, 2, 3, 16, 18, 19, 20 };
+ static unsigned char reg_q_map[] = { 0, 17, 2, 3, 4, 5, 6, 7 };
+
+ static unsigned char reg_h_map1[] = { 5, 5, 6, 4, 4, 4, 4, 4 };
+ static unsigned char reg_h_map2[] = { 6, 7, 7, 21, 22, 5, 6, 7 };
+
+ static int int_b_map[] = {
+ 1, 4, 8, 12, 16, 20, 24, -1
+ };
+ static int int_c_map[] = {
+ 128, 1, 2, 3, 4, 7, 8, 15, 16, 31, 32, 63, 64, 255, 32768, 65535
+ };
+
+ /* Return the mips_operand structure for the operand at the beginning of P. */
+
+ const struct mips_operand *
+ decode_micromips_operand (const char *p)
+ {
+ switch (p[0])
+ {
+ case 'm':
+ switch (p[1])
+ {
+ case 'a': MAPPED_REG (0, 0, GP, reg_28_map);
+ case 'b': MAPPED_REG (3, 23, GP, reg_m16_map);
+ case 'c': 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_REG (3, 3, GP, reg_m16_map);
+ case 'g': MAPPED_REG (3, 0, GP, reg_m16_map);
+ case 'h': REG_PAIR (3, 7, GP, reg_h_map);
+ case 'j': REG (5, 0, GP);
+ case 'l': MAPPED_REG (3, 4, GP, reg_m16_map);
+ case 'm': MAPPED_REG (3, 1, GP, reg_mn_map);
+ case 'n': MAPPED_REG (3, 4, GP, reg_mn_map);
+ case 'p': REG (5, 5, GP);
+ case 'q': MAPPED_REG (3, 7, GP, reg_q_map);
+ case 'r': SPECIAL (0, 0, PC);
+ case 's': MAPPED_REG (0, 0, GP, reg_29_map);
+ case 't': SPECIAL (0, 0, REPEAT_PREV_REG);
+ case 'x': SPECIAL (0, 0, REPEAT_DEST_REG);
+ case 'y': MAPPED_REG (0, 0, GP, reg_31_map);
+ case 'z': MAPPED_REG (0, 0, GP, reg_0_map);
+
+ case 'A': INT_ADJ (7, 0, 63, 2, FALSE); /* (-64 .. 63) << 2 */
+ case 'B': MAPPED_INT (3, 1, int_b_map, FALSE);
+ case 'C': MAPPED_INT (4, 0, int_c_map, TRUE);
+ case 'D': BRANCH (10, 0, 1);
+ case 'E': BRANCH (7, 0, 1);
+ case 'F': HINT (4, 0);
+ case 'G': INT_ADJ (4, 0, 14, 0, FALSE); /* (-1 .. 14) */
+ case 'H': INT_ADJ (4, 0, 15, 1, FALSE); /* (0 .. 15) << 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 'L': INT_ADJ (4, 0, 15, 0, FALSE); /* (0 .. 15) */
+ case 'M': INT_ADJ (3, 1, 8, 0, FALSE); /* (1 .. 8) */
+ case 'N': SPECIAL (2, 4, LWM_SWM_LIST);
+ case 'O': HINT (4, 0);
+ case 'P': INT_ADJ (5, 0, 31, 2, FALSE); /* (0 .. 31) << 2 */
+ case 'Q': INT_ADJ (23, 0, 4194303, 2, FALSE);
+ /* (-4194304 .. 4194303) */
+ case 'U': INT_ADJ (5, 0, 31, 2, FALSE); /* (0 .. 31) << 2 */
+ case 'W': INT_ADJ (6, 1, 63, 2, FALSE); /* (0 .. 63) << 2 */
+ case 'X': SINT (4, 1);
+ case 'Y': SPECIAL (9, 1, ADDIUSP_INT);
+ case 'Z': UINT (0, 0); /* 0 only */
+ }
+ break;
+
+ case '+':
+ switch (p[1])
+ {
+ case 'A': BIT (5, 6, 0); /* (0 .. 31) */
+ case 'B': MSB (5, 11, 1, TRUE, 32); /* (1 .. 32), 32-bit op */
+ case 'C': MSB (5, 11, 1, FALSE, 32); /* (1 .. 32), 32-bit op */
+ case 'E': BIT (5, 6, 32); /* (32 .. 63) */
+ case 'F': MSB (5, 11, 33, TRUE, 64); /* (33 .. 64), 64-bit op */
+ case 'G': MSB (5, 11, 33, FALSE, 64); /* (33 .. 64), 64-bit op */
+ case 'H': MSB (5, 11, 1, FALSE, 64); /* (1 .. 32), 64-bit op */
+
+ case 'i': JALX (26, 0, 2);
+ case 'j': SINT (9, 0);
+ }
+ break;
+
+ case '.': SINT (10, 6);
+ case '<': BIT (5, 11, 0); /* (0 .. 31) */
+ case '>': BIT (5, 11, 32); /* (32 .. 63) */
+ case '\\': BIT (3, 21, 0); /* (0 .. 7) */
+ case '|': HINT (4, 12);
+ case '~': SINT (12, 0);
+ case '@': SINT (10, 16);
+ case '^': HINT (5, 11);
+
+ case '0': SINT (6, 16);
+ case '1': HINT (5, 16);
+ case '2': HINT (2, 14);
+ case '3': HINT (3, 13);
+ case '4': HINT (4, 12);
+ case '5': HINT (8, 13);
+ case '6': HINT (5, 16);
+ case '7': REG (2, 14, ACC);
+ case '8': HINT (6, 14);
+
+ case 'B': HINT (10, 16);
+ case 'C': HINT (23, 3);
+ case 'D': REG (5, 11, FP);
+ case 'E': REG (5, 21, COPRO);
+ case 'G': REG (5, 16, COPRO);
+ case 'K': REG (5, 16, HW);
+ case 'H': UINT (3, 11);
+ case 'M': REG (3, 13, CCC);
+ case 'N': REG (3, 18, CCC);
+ case 'R': REG (5, 6, FP);
+ case 'S': REG (5, 16, FP);
+ case 'T': REG (5, 21, FP);
+ case 'V': REG (5, 16, FP);
+
+ case 'a': JUMP (26, 0, 1);
+ case 'b': REG (5, 16, GP);
+ case 'c': HINT (10, 16);
+ case 'd': REG (5, 11, GP);
+ case 'h': HINT (5, 11);
+ case 'i': HINT (16, 0);
+ case 'j': SINT (16, 0);
+ case 'k': HINT (5, 21);
+ case 'n': SPECIAL (5, 21, LWM_SWM_LIST);
+ case 'o': SINT (16, 0);
+ case 'p': BRANCH (16, 0, 1);
+ case 'q': HINT (10, 6);
+ case 'r': REG (5, 16, GP);
+ case 's': REG (5, 16, GP);
+ case 't': REG (5, 21, GP);
+ case 'u': HINT (16, 0);
+ case 'v': REG (5, 16, GP);
+ case 'w': REG (5, 21, GP);
+ case 'y': REG (5, 6, GP);
+ case 'z': MAPPED_REG (0, 0, GP, reg_0_map);
+ }
+ return 0;
+ }
#define UBD INSN_UNCOND_BRANCH_DELAY
#define CBD INSN_COND_BRANCH_DELAY
Index: opcodes/mips-dis.c
===================================================================
*** opcodes/mips-dis.c 2013-07-14 10:33:21.087809400 +0100
--- opcodes/mips-dis.c 2013-07-14 10:53:46.281482544 +0100
*************** static const unsigned int mips16_to_32_r
*** 57,145 ****
16, 17, 2, 3, 4, 5, 6, 7
};
- /* The microMIPS registers with type b. */
- #define micromips_to_32_reg_b_map mips16_to_32_reg_map
-
- /* The microMIPS registers with type c. */
- #define micromips_to_32_reg_c_map mips16_to_32_reg_map
-
- /* The microMIPS registers with type d. */
- #define micromips_to_32_reg_d_map mips16_to_32_reg_map
-
- /* The microMIPS registers with type e. */
- #define micromips_to_32_reg_e_map mips16_to_32_reg_map
-
- /* The microMIPS registers with type f. */
- #define micromips_to_32_reg_f_map mips16_to_32_reg_map
-
- /* The microMIPS registers with type g. */
- #define micromips_to_32_reg_g_map mips16_to_32_reg_map
-
- /* The microMIPS registers with type h. */
- static const unsigned int micromips_to_32_reg_h_map1[] =
- {
- 5, 5, 6, 4, 4, 4, 4, 4
- };
- static const unsigned int micromips_to_32_reg_h_map2[] =
- {
- 6, 7, 7, 21, 22, 5, 6, 7
- };
-
- /* The microMIPS registers with type j: 32 registers. */
-
- /* The microMIPS registers with type l. */
- #define micromips_to_32_reg_l_map mips16_to_32_reg_map
-
- /* The microMIPS registers with type m. */
- static const unsigned int micromips_to_32_reg_m_map[] =
- {
- 0, 17, 2, 3, 16, 18, 19, 20
- };
-
- /* The microMIPS registers with type n. */
- #define micromips_to_32_reg_n_map micromips_to_32_reg_m_map
-
- /* The microMIPS registers with type p: 32 registers. */
-
- /* The microMIPS registers with type q. */
- static const unsigned int micromips_to_32_reg_q_map[] =
- {
- 0, 17, 2, 3, 4, 5, 6, 7
- };
-
- /* reg type s is $29. */
-
- /* reg type t is the same as the last register. */
-
- /* reg type y is $31. */
-
- /* reg type z is $0. */
-
- /* micromips imm B type. */
- static const int micromips_imm_b_map[8] =
- {
- 1, 4, 8, 12, 16, 20, 24, -1
- };
-
- /* micromips imm C type. */
- static const int micromips_imm_c_map[16] =
- {
- 128, 1, 2, 3, 4, 7, 8, 15, 16, 31, 32, 63, 64, 255, 32768, 65535
- };
-
- /* micromips imm D type: (-512..511)<<1. */
- /* micromips imm E type: (-64..63)<<1. */
- /* micromips imm F type: (0..63). */
- /* micromips imm G type: (-1..14). */
- /* micromips imm H type: (0..15)<<1. */
- /* micromips imm I type: (-1..126). */
- /* micromips imm J type: (0..15)<<2. */
- /* micromips imm L type: (0..15). */
- /* micromips imm M type: (1..8). */
- /* micromips imm W type: (0..63)<<2. */
- /* micromips imm X type: (-8..7). */
- /* micromips imm Y type: (-258..-3, 2..257)<<2. */
-
#define mips16_reg_names(rn) mips_gpr_names[mips16_to_32_reg_map[rn]]
--- 57,62 ----
*************** lookup_mips_cp0sel_name (const struct mi
*** 964,1439 ****
return &names[i];
return NULL;
}
!
! /* Print insn arguments for 32/64-bit code. */
static void
! print_insn_args (const char *d,
! int l,
! bfd_vma pc,
! struct disassemble_info *info,
! const struct mips_opcode *opp)
{
! const fprintf_ftype infprintf = info->fprintf_func;
! unsigned int lsb, msb, msbd, cpreg;
! void *is = info->stream;
!
! lsb = 0;
!
! #define GET_OP(insn, field) \
! (((insn) >> OP_SH_##field) & OP_MASK_##field)
! #define GET_OP_S(insn, field) \
! ((GET_OP (insn, field) ^ ((OP_MASK_##field >> 1) + 1)) \
! - ((OP_MASK_##field >> 1) + 1))
! for (; *d != '\0'; d++)
{
! switch (*d)
! {
! case ',':
! case '(':
! case ')':
! infprintf (is, "%c", *d);
! break;
!
! case '+':
! /* Extension character; switch for second char. */
! d++;
! switch (*d)
! {
! case '\0':
! /* xgettext:c-format */
! infprintf (is,
! _("# internal error, "
! "incomplete extension sequence (+)"));
! return;
! case 'A':
! lsb = GET_OP (l, SHAMT);
! infprintf (is, "0x%x", lsb);
! break;
!
! case 'B':
! msb = GET_OP (l, INSMSB);
! infprintf (is, "0x%x", msb - lsb + 1);
! break;
!
! case '1':
! infprintf (is, "0x%x", GET_OP (l, UDI1));
! break;
!
! case '2':
! infprintf (is, "0x%x", GET_OP (l, UDI2));
! break;
!
! case '3':
! infprintf (is, "0x%x", GET_OP (l, UDI3));
! break;
!
! case '4':
! infprintf (is, "0x%x", GET_OP (l, UDI4));
! break;
!
! case 'C':
! case 'H':
! msbd = GET_OP (l, EXTMSBD);
! infprintf (is, "0x%x", msbd + 1);
! break;
!
! case 'E':
! lsb = GET_OP (l, SHAMT) + 32;
! infprintf (is, "0x%x", lsb);
! break;
!
! case 'F':
! msb = GET_OP (l, INSMSB) + 32;
! infprintf (is, "0x%x", msb - lsb + 1);
! break;
!
! case 'G':
! msbd = GET_OP (l, EXTMSBD) + 32;
! infprintf (is, "0x%x", msbd + 1);
! break;
!
! case 'J': /* hypcall operand */
! infprintf (is, "0x%x", GET_OP (l, CODE10));
! break;
!
! case 't': /* Coprocessor 0 reg name */
! infprintf (is, "%s", mips_cp0_names[GET_OP (l, RT)]);
! break;
!
! case 'x': /* bbit bit index */
! infprintf (is, "0x%x", GET_OP (l, BBITIND));
! break;
!
! case 'p': /* cins, cins32, exts and exts32 position */
! infprintf (is, "0x%x", GET_OP (l, CINSPOS));
! break;
!
! case 's': /* cins32 and exts32 length-minus-one */
! case 'S': /* cins and exts length-minus-one field */
! infprintf (is, "0x%x", GET_OP (l, CINSLM1));
! break;
!
! case 'Q': /* seqi/snei immediate field */
! infprintf (is, "%d", GET_OP_S (l, SEQI));
! break;
!
! case 'a': /* 8-bit signed offset in bit 6 */
! infprintf (is, "%d", GET_OP_S (l, OFFSET_A));
! break;
!
! case 'b': /* 8-bit signed offset in bit 3 */
! infprintf (is, "%d", GET_OP_S (l, OFFSET_B));
! break;
!
! case 'c': /* 9-bit signed offset in bit 6 */
! /* Left shift 4 bits to print the real offset. */
! infprintf (is, "%d", GET_OP_S (l, OFFSET_C) << 4);
! break;
!
! case 'z':
! infprintf (is, "%s", mips_gpr_names[GET_OP (l, RZ)]);
! break;
!
! case 'Z':
! infprintf (is, "%s", mips_fpr_names[GET_OP (l, FZ)]);
! break;
!
! case 'i': /* JALX destination */
! info->target = (((pc + 4) & ~(bfd_vma) 0x0fffffff)
! | (GET_OP (l, TARGET) << 2));
! /* For gdb disassembler, force odd address on jalx. */
! if (info->flavour == bfd_target_unknown_flavour)
! info->target |= 1;
! (*info->print_address_func) (info->target, info);
! break;
!
! case 'j': /* 9-bit signed offset in bit 7. */
! infprintf (is, "%d", GET_OP_S (l, EVAOFFSET));
! break;
! default:
! /* xgettext:c-format */
! infprintf (is,
! _("# internal error, "
! "undefined extension sequence (+%c)"),
! *d);
! return;
! }
! break;
! case '2':
! infprintf (is, "0x%x", GET_OP (l, BP));
! break;
! case '3':
! infprintf (is, "0x%x", GET_OP (l, SA3));
! break;
! case '4':
! infprintf (is, "0x%x", GET_OP (l, SA4));
! break;
! case '5':
! infprintf (is, "0x%x", GET_OP (l, IMM8));
! break;
! case '6':
! infprintf (is, "0x%x", GET_OP (l, RS));
! break;
! case '7':
! infprintf (is, "$ac%d", GET_OP (l, DSPACC));
! break;
! case '8':
! infprintf (is, "0x%x", GET_OP (l, WRDSP));
! break;
! case '9':
! infprintf (is, "$ac%d", GET_OP (l, DSPACC_S));
! break;
! case '0': /* dsp 6-bit signed immediate in bit 20 */
! infprintf (is, "%d", GET_OP_S (l, DSPSFT));
! break;
! case ':': /* dsp 7-bit signed immediate in bit 19 */
! infprintf (is, "%d", GET_OP_S (l, DSPSFT_7));
! break;
! case '~':
! infprintf (is, "%d", GET_OP_S (l, OFFSET12));
! break;
! case '\\':
! infprintf (is, "0x%x", GET_OP (l, 3BITPOS));
! break;
! case '\'':
! infprintf (is, "0x%x", GET_OP (l, RDDSP));
! break;
! case '@': /* dsp 10-bit signed immediate in bit 16 */
! infprintf (is, "%d", GET_OP_S (l, IMM10));
! break;
! case '!':
! infprintf (is, "%d", GET_OP (l, MT_U));
! break;
! case '$':
! infprintf (is, "%d", GET_OP (l, MT_H));
! break;
! case '*':
! infprintf (is, "$ac%d", GET_OP (l, MTACC_T));
! break;
! case '&':
! infprintf (is, "$ac%d", GET_OP (l, MTACC_D));
! break;
! case 'g':
! /* Coprocessor register for CTTC1, MTTC2, MTHC2, CTTC2. */
! infprintf (is, "$%d", GET_OP (l, RD));
! break;
! case 's':
! case 'b':
! case 'r':
! case 'v':
! infprintf (is, "%s", mips_gpr_names[GET_OP (l, RS)]);
! break;
! case 't':
! case 'w':
! infprintf (is, "%s", mips_gpr_names[GET_OP (l, RT)]);
! break;
! case 'i':
! case 'u':
! infprintf (is, "0x%x", GET_OP (l, IMMEDIATE));
! break;
! case 'j': /* Same as i, but sign-extended. */
! case 'o':
! infprintf (is, "%d", GET_OP_S (l, DELTA));
! break;
! case 'h':
! infprintf (is, "0x%x", GET_OP (l, PREFX));
! break;
! case 'k':
! infprintf (is, "0x%x", GET_OP (l, CACHE));
! break;
! case 'a':
! info->target = (((pc + 4) & ~(bfd_vma) 0x0fffffff)
! | (GET_OP (l, TARGET) << 2));
! (*info->print_address_func) (info->target, info);
! break;
! case 'p':
! /* Sign extend the displacement. */
! info->target = (GET_OP_S (l, DELTA) << 2) + pc + INSNLEN;
! (*info->print_address_func) (info->target, info);
! break;
! case 'd':
! infprintf (is, "%s", mips_gpr_names[GET_OP (l, RD)]);
! break;
! case 'U':
! {
! /* First check for both rd and rt being equal. */
! unsigned int reg;
! reg = GET_OP (l, RD);
! if (reg == GET_OP (l, RT))
! infprintf (is, "%s", mips_gpr_names[reg]);
! else
! {
! /* If one is zero use the other. */
! if (reg == 0)
! infprintf (is, "%s", mips_gpr_names[GET_OP (l, RT)]);
! else if (GET_OP (l, RT) == 0)
! infprintf (is, "%s", mips_gpr_names[reg]);
! else /* Bogus, result depends on processor. */
! infprintf (is, "%s or %s",
! mips_gpr_names[reg],
! mips_gpr_names[GET_OP (l, RT)]);
! }
! }
! break;
! case 'z':
! infprintf (is, "%s", mips_gpr_names[0]);
! break;
! case '<':
! case '1':
! infprintf (is, "0x%x", GET_OP (l, SHAMT));
! break;
! case 'c':
! infprintf (is, "0x%x", GET_OP (l, CODE));
! break;
! case 'q':
! infprintf (is, "0x%x", GET_OP (l, CODE2));
! break;
! case 'C':
! infprintf (is, "0x%x", GET_OP (l, COPZ));
! break;
! case 'B':
! infprintf (is, "0x%x", GET_OP (l, CODE20));
! break;
! case 'J':
! infprintf (is, "0x%x", GET_OP (l, CODE19));
! break;
! case 'S':
! case 'V':
! infprintf (is, "%s", mips_fpr_names[GET_OP (l, FS)]);
! break;
! case 'T':
! case 'W':
! infprintf (is, "%s", mips_fpr_names[GET_OP (l, FT)]);
! break;
! case 'D':
! infprintf (is, "%s", mips_fpr_names[GET_OP (l, FD)]);
! break;
! case 'R':
! infprintf (is, "%s", mips_fpr_names[GET_OP (l, FR)]);
break;
! case 'E':
! cpreg = GET_OP (l, RT);
! goto copro;
!
! case 'G':
! cpreg = GET_OP (l, RD);
! copro:
! /* Coprocessor register for mtcN instructions, et al. Note
! that FPU (cp1) instructions disassemble this field using
! 'S' format. Therefore, we only need to worry about cp0,
! cp2, and cp3. */
! if (opp->name[strlen (opp->name) - 1] == '0')
{
! if (d[1] == ',' && d[2] == 'H')
! {
! const struct mips_cp0sel_name *n;
! unsigned int sel;
!
! sel = GET_OP (l, SEL);
!
! /* CP0 register including 'sel' code for mtcN (et al.), to be
! printed textually if known. If not known, print both
! CP0 register name and sel numerically since CP0 register
! with sel 0 may have a name unrelated to register being
! printed. */
! n = lookup_mips_cp0sel_name (mips_cp0sel_names,
! mips_cp0sel_names_len,
! cpreg, sel);
! if (n != NULL)
! infprintf (is, "%s", n->name);
! else
! infprintf (is, "$%d,%d", cpreg, sel);
! d += 2;
! }
else
! infprintf (is, "%s", mips_cp0_names[cpreg]);
}
else
! infprintf (is, "$%d", cpreg);
! break;
!
! case 'K':
! infprintf (is, "%s", mips_hwr_names[GET_OP (l, RD)]);
! break;
!
! case 'N':
! infprintf (is,
! (opp->pinfo & (FP_D | FP_S)) != 0 ? "$fcc%d" : "$cc%d",
! GET_OP (l, BCC));
! break;
!
! case 'M':
! infprintf (is, "$fcc%d", GET_OP (l, CCC));
! break;
!
! case 'P':
! infprintf (is, "%d", GET_OP (l, PERFREG));
! break;
!
! case 'e':
! infprintf (is, "%d", GET_OP (l, VECBYTE));
! break;
!
! case '%':
! infprintf (is, "%d", GET_OP (l, VECALIGN));
! break;
!
! case 'H':
! infprintf (is, "%d", GET_OP (l, SEL));
! break;
!
! case 'O':
! infprintf (is, "%d", GET_OP (l, ALN));
! break;
!
! case 'Q':
! {
! unsigned int vsel = GET_OP (l, VSEL);
! char prefix;
!
! prefix = opp->membership & INSN_5400 ? 'f' : 'v';
! if ((vsel & 0x10) == 0)
! {
! int fmt;
!
! vsel &= 0x0f;
! for (fmt = 0; fmt < 3; fmt++, vsel >>= 1)
! if ((vsel & 1) == 0)
! break;
! infprintf (is, "$%c%d[%d]", prefix, GET_OP (l, FT), vsel >> 1);
! }
! else if ((vsel & 0x08) == 0)
! {
! infprintf (is, "$%c%d", prefix, GET_OP (l, FT));
! }
! else
! {
! infprintf (is, "0x%x", GET_OP (l, FT));
! }
! }
! break;
!
! case 'X':
! infprintf (is, "$v%d", GET_OP (l, FD));
break;
-
- case 'Y':
- infprintf (is, "$v%d", GET_OP (l, FS));
- break;
-
- case 'Z':
- infprintf (is, "$v%d", GET_OP (l, FT));
- break;
-
- default:
- /* xgettext:c-format */
- infprintf (is, _("# internal error, undefined modifier (%c)"), *d);
- return;
}
}
}
--- 881,1241 ----
return &names[i];
return NULL;
}
!
! /* Print register REGNO, of type TYPE, for instruction OPCODE. */
static void
! print_reg (struct disassemble_info *info, const struct mips_opcode *opcode,
! enum mips_reg_operand_type type, int regno)
{
! switch (type)
{
! case OP_REG_GP:
! info->fprintf_func (info->stream, "%s", mips_gpr_names[regno]);
! break;
! case OP_REG_FP:
! info->fprintf_func (info->stream, "%s", mips_fpr_names[regno]);
! break;
! case OP_REG_CCC:
! if (opcode->pinfo & (FP_D | FP_S))
! info->fprintf_func (info->stream, "$fcc%d", regno);
! else
! info->fprintf_func (info->stream, "$cc%d", regno);
! break;
! case OP_REG_VEC:
! if (opcode->membership & INSN_5400)
! info->fprintf_func (info->stream, "$f%d", regno);
! else
! info->fprintf_func (info->stream, "$v%d", regno);
! break;
! case OP_REG_ACC:
! info->fprintf_func (info->stream, "$ac%d", regno);
! break;
! case OP_REG_COPRO:
! if (opcode->name[strlen (opcode->name) - 1] == '0')
! info->fprintf_func (info->stream, "%s", mips_cp0_names[regno]);
! else
! info->fprintf_func (info->stream, "$%d", regno);
! break;
! case OP_REG_HW:
! info->fprintf_func (info->stream, "%s", mips_hwr_names[regno]);
! break;
! }
! }
!
! /* Used to track the state carried over from previous operands in
! an instruction. */
! struct mips_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 mips_reg_operand_type last_reg_type;
! unsigned int last_regno;
! };
! /* Initialize STATE for the start of an instruction. */
! static inline void
! init_print_arg_state (struct mips_print_arg_state *state)
! {
! memset (state, 0, sizeof (*state));
! }
! /* 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 mips_print_arg_state *state,
! const struct mips_opcode *opcode,
! const struct mips_operand *operand,
! bfd_vma base_pc,
! unsigned int uval)
! {
! const fprintf_ftype infprintf = info->fprintf_func;
! void *is = info->stream;
! switch (operand->type)
! {
! case OP_INT:
! {
! const struct mips_int_operand *int_op;
! int_op = (const struct mips_int_operand *) operand;
! uval = mips_decode_int_operand (int_op, uval);
! state->last_int = uval;
! if (int_op->print_hex)
! infprintf (is, "0x%x", uval);
! else
! infprintf (is, "%d", uval);
! }
! break;
! case OP_MAPPED_INT:
! {
! const struct mips_mapped_int_operand *mint_op;
! mint_op = (const struct mips_mapped_int_operand *) operand;
! uval = mint_op->int_map[uval];
! state->last_int = uval;
! if (mint_op->print_hex)
! infprintf (is, "0x%x", uval);
! else
! infprintf (is, "%d", uval);
! }
! break;
! case OP_MSB:
! {
! const struct mips_msb_operand *msb_op;
! msb_op = (const struct mips_msb_operand *) operand;
! uval += msb_op->bias;
! if (msb_op->add_lsb)
! uval -= state->last_int;
! infprintf (is, "0x%x", uval);
! }
! break;
! case OP_REG:
! {
! const struct mips_reg_operand *reg_op;
! reg_op = (const struct mips_reg_operand *) operand;
! if (reg_op->reg_map)
! uval = reg_op->reg_map[uval];
! print_reg (info, opcode, reg_op->reg_type, uval);
! state->last_reg_type = reg_op->reg_type;
! state->last_regno = uval;
! }
! break;
! case OP_REG_PAIR:
! {
! const struct mips_reg_pair_operand *pair_op;
! pair_op = (const struct mips_reg_pair_operand *) operand;
! print_reg (info, opcode, pair_op->reg_type,
! pair_op->reg1_map[uval]);
! infprintf (is, ",");
! print_reg (info, opcode, pair_op->reg_type,
! pair_op->reg2_map[uval]);
! }
! break;
! case OP_PCREL:
! {
! const struct mips_pcrel_operand *pcrel_op;
! pcrel_op = (const struct mips_pcrel_operand *) operand;
! info->target = mips_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_PERF_REG:
! infprintf (is, "%d", uval);
! break;
! case OP_ADDIUSP_INT:
! {
! int sval;
! sval = mips_signed_operand (operand, uval) * 4;
! if (sval >= -8 && sval < 8)
! sval ^= 0x400;
! infprintf (is, "%d", sval);
! break;
! }
! case OP_CLO_CLZ_DEST:
! {
! unsigned int reg1, reg2;
! reg1 = uval & 31;
! reg2 = uval >> 5;
! /* If one is zero use the other. */
! if (reg1 == reg2 || reg2 == 0)
! infprintf (is, "%s", mips_gpr_names[reg1]);
! else if (reg1 == 0)
! infprintf (is, "%s", mips_gpr_names[reg2]);
! else
! /* Bogus, result depends on processor. */
! infprintf (is, "%s or %s", mips_gpr_names[reg1],
! mips_gpr_names[reg2]);
! }
! break;
! case OP_LWM_SWM_LIST:
! if (operand->size == 2)
! {
! if (uval == 0)
! infprintf (is, "%s,%s",
! mips_gpr_names[16],
! mips_gpr_names[31]);
! else
! infprintf (is, "%s-%s,%s",
! mips_gpr_names[16],
! mips_gpr_names[16 + uval],
! mips_gpr_names[31]);
! }
! else
! {
! int s_reg_encode;
! s_reg_encode = uval & 0xf;
! if (s_reg_encode != 0)
! {
! if (s_reg_encode == 1)
! infprintf (is, "%s", mips_gpr_names[16]);
! else if (s_reg_encode < 9)
! infprintf (is, "%s-%s",
! mips_gpr_names[16],
! mips_gpr_names[15 + s_reg_encode]);
! else if (s_reg_encode == 9)
! infprintf (is, "%s-%s,%s",
! mips_gpr_names[16],
! mips_gpr_names[23],
! mips_gpr_names[30]);
! else
! infprintf (is, "UNKNOWN");
! }
! if (uval & 0x10) /* For ra. */
! {
! if (s_reg_encode == 0)
! infprintf (is, "%s", mips_gpr_names[31]);
! else
! infprintf (is, ",%s", mips_gpr_names[31]);
! }
! }
! break;
! case OP_MDMX_IMM_REG:
! {
! unsigned int vsel;
! vsel = uval >> 5;
! uval &= 31;
! if ((vsel & 0x10) == 0)
! {
! int fmt;
! vsel &= 0x0f;
! for (fmt = 0; fmt < 3; fmt++, vsel >>= 1)
! if ((vsel & 1) == 0)
! break;
! print_reg (info, opcode, OP_REG_VEC, uval);
! infprintf (is, "[%d]", vsel >> 1);
! }
! else if ((vsel & 0x08) == 0)
! print_reg (info, opcode, OP_REG_VEC, uval);
! else
! infprintf (is, "0x%x", uval);
! }
! break;
! case OP_REPEAT_PREV_REG:
! print_reg (info, opcode, state->last_reg_type, state->last_regno);
! break;
! case OP_REPEAT_DEST_REG:
! /* Should always match OP_REPEAT_PREV_REG first. */
! abort ();
! case OP_PC:
! infprintf (is, "$pc");
! break;
! }
! }
! /* 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. */
! static void
! print_insn_args (struct disassemble_info *info,
! const struct mips_opcode *opcode,
! const struct mips_operand *(*decode_operand) (const char *),
! unsigned int insn, bfd_vma base_pc)
! {
! const fprintf_ftype infprintf = info->fprintf_func;
! void *is = info->stream;
! struct mips_print_arg_state state;
! const struct mips_operand *operand;
! const char *s;
! init_print_arg_state (&state);
! for (s = opcode->args; *s; ++s)
! {
! switch (*s)
! {
! case ',':
! case '(':
! case ')':
! infprintf (is, "%c", *s);
break;
! default:
! operand = decode_operand (s);
! if (!operand)
{
! /* xgettext:c-format */
! infprintf (is,
! _("# internal error, undefined operand in `%s %s'"),
! opcode->name, opcode->args);
! return;
! }
! if (operand->type == OP_REG
! && s[1] == ','
! && s[2] == 'H'
! && opcode->name[strlen (opcode->name) - 1] == '0')
! {
! /* Coprocessor register 0 with sel field (MT ASE). */
! const struct mips_cp0sel_name *n;
! unsigned int reg, sel;
!
! reg = mips_extract_operand (operand, insn);
! s += 2;
! operand = decode_operand (s);
! sel = mips_extract_operand (operand, insn);
!
! /* CP0 register including 'sel' code for mftc0, to be
! printed textually if known. If not known, print both
! CP0 register name and sel numerically since CP0 register
! with sel 0 may have a name unrelated to register being
! printed. */
! n = lookup_mips_cp0sel_name (mips_cp0sel_names,
! mips_cp0sel_names_len,
! reg, sel);
! if (n != NULL)
! infprintf (is, "%s", n->name);
else
! infprintf (is, "$%d,%d", reg, sel);
}
else
! print_insn_arg (info, &state, opcode, operand, base_pc,
! mips_extract_operand (operand, insn));
! if (*s == 'm' || *s == '+')
! ++s;
break;
}
}
}
*************** print_insn_mips (bfd_vma memaddr,
*** 1448,1453 ****
--- 1250,1257 ----
int word,
struct disassemble_info *info)
{
+ #define GET_OP(insn, field) \
+ (((insn) >> OP_SH_##field) & OP_MASK_##field)
static const struct mips_opcode *mips_hash[OP_MASK_OP + 1];
const fprintf_ftype infprintf = info->fprintf_func;
const struct mips_opcode *op;
*************** print_insn_mips (bfd_vma memaddr,
*** 1495,1502 ****
&& !(no_aliases && (op->pinfo2 & INSN2_ALIAS))
&& (word & op->mask) == op->match)
{
- const char *d;
-
/* We always allow to disassemble the jalx instruction. */
if (!opcode_is_member (op, mips_isa, mips_ase, mips_processor)
&& strcmp (op->name, "jalx"))
--- 1299,1304 ----
*************** print_insn_mips (bfd_vma memaddr,
*** 1527,1544 ****
infprintf (is, "%s", op->name);
! d = op->args;
! if (d != NULL && *d != '\0')
{
infprintf (is, "\t");
! print_insn_args (d, word, memaddr, info, op);
}
return INSNLEN;
}
}
}
- #undef GET_OP_S
#undef GET_OP
/* Handle undefined instructions. */
--- 1329,1345 ----
infprintf (is, "%s", op->name);
! if (op->args[0])
{
infprintf (is, "\t");
! print_insn_args (info, op, decode_mips_operand, word,
! memaddr + 4);
}
return INSNLEN;
}
}
}
#undef GET_OP
/* Handle undefined instructions. */
*************** print_insn_micromips (bfd_vma memaddr, s
*** 2235,2253 ****
{
const fprintf_ftype infprintf = info->fprintf_func;
const struct mips_opcode *op, *opend;
- unsigned int lsb, msbd, msb;
void *is = info->stream;
- unsigned int regno;
bfd_byte buffer[2];
! int lastregno = 0;
! int higher;
! int length;
int status;
! int delta;
! int immed;
! int insn;
!
! lsb = 0;
info->bytes_per_chunk = 2;
info->display_endian = info->endian;
--- 2036,2047 ----
{
const fprintf_ftype infprintf = info->fprintf_func;
const struct mips_opcode *op, *opend;
void *is = info->stream;
bfd_byte buffer[2];
! unsigned int higher;
! unsigned int length;
int status;
! unsigned int insn;
info->bytes_per_chunk = 2;
info->display_endian = info->endian;
*************** print_insn_micromips (bfd_vma memaddr, s
*** 2331,2341 ****
/* FIXME: Should probably use a hash table on the major opcode here. */
- #define GET_OP(insn, field) \
- (((insn) >> MICROMIPSOP_SH_##field) & MICROMIPSOP_MASK_##field)
- #define GET_OP_S(insn, field) \
- ((GET_OP (insn, field) ^ ((MICROMIPSOP_MASK_##field >> 1) + 1)) \
- - ((MICROMIPSOP_MASK_##field >> 1) + 1))
opend = micromips_opcodes + bfd_micromips_num_opcodes;
for (op = micromips_opcodes; op < opend; op++)
{
--- 2125,2130 ----
*************** #define GET_OP_S(insn, field) \
*** 2345,2913 ****
&& ((length == 2 && (op->mask & 0xffff0000) == 0)
|| (length == 4 && (op->mask & 0xffff0000) != 0)))
{
- const char *s;
-
infprintf (is, "%s", op->name);
- if (op->args[0] != '\0')
- infprintf (is, "\t");
! for (s = op->args; *s != '\0'; s++)
{
! switch (*s)
! {
! case ',':
! case '(':
! case ')':
! infprintf (is, "%c", *s);
! break;
!
! case '.':
! infprintf (is, "%d", GET_OP_S (insn, OFFSET10));
! break;
!
! case '1':
! infprintf (is, "0x%x", GET_OP (insn, STYPE));
! break;
!
! case '2':
! infprintf (is, "0x%x", GET_OP (insn, BP));
! break;
!
! case '3':
! infprintf (is, "0x%x", GET_OP (insn, SA3));
! break;
!
! case '4':
! infprintf (is, "0x%x", GET_OP (insn, SA4));
! break;
!
! case '5':
! infprintf (is, "0x%x", GET_OP (insn, IMM8));
! break;
!
! case '6':
! infprintf (is, "0x%x", GET_OP (insn, RS));
! break;
!
! case '7':
! infprintf (is, "$ac%d", GET_OP (insn, DSPACC));
! break;
!
! case '8':
! infprintf (is, "0x%x", GET_OP (insn, WRDSP));
! break;
!
! case '0': /* DSP 6-bit signed immediate in bit 16. */
! delta = (GET_OP (insn, DSPSFT) ^ 0x20) - 0x20;
! infprintf (is, "%d", delta);
! break;
!
! case '<':
! infprintf (is, "0x%x", GET_OP (insn, SHAMT));
! break;
!
! case '\\':
! infprintf (is, "0x%x", GET_OP (insn, 3BITPOS));
! break;
!
! case '^':
! infprintf (is, "0x%x", GET_OP (insn, RD));
! break;
!
! case '|':
! infprintf (is, "0x%x", GET_OP (insn, TRAP));
! break;
!
! case '~':
! infprintf (is, "%d", GET_OP_S (insn, OFFSET12));
! break;
!
! case 'a':
! info->target = (((memaddr + 4) & ~(bfd_vma) 0x07ffffff)
! | (GET_OP (insn, TARGET) << 1));
! /* For gdb disassembler, maintain odd address. */
! if (info->flavour == bfd_target_unknown_flavour)
! info->target |= 1;
! (*info->print_address_func) (info->target, info);
! break;
!
! case 'b':
! case 'r':
! case 's':
! case 'v':
! infprintf (is, "%s", mips_gpr_names[GET_OP (insn, RS)]);
! break;
!
! case 'c':
! infprintf (is, "0x%x", GET_OP (insn, CODE));
! break;
!
! case 'd':
! infprintf (is, "%s", mips_gpr_names[GET_OP (insn, RD)]);
! break;
!
! case 'h':
! infprintf (is, "0x%x", GET_OP (insn, PREFX));
! break;
!
! case 'i':
! case 'u':
! infprintf (is, "0x%x", GET_OP (insn, IMMEDIATE));
! break;
!
! case 'j': /* Same as i, but sign-extended. */
! case 'o':
! infprintf (is, "%d", GET_OP_S (insn, DELTA));
! break;
!
! case 'k':
! infprintf (is, "0x%x", GET_OP (insn, CACHE));
! break;
!
! case 'n':
! {
! int s_reg_encode;
!
! immed = GET_OP (insn, RT);
! s_reg_encode = immed & 0xf;
! if (s_reg_encode != 0)
! {
! if (s_reg_encode == 1)
! infprintf (is, "%s", mips_gpr_names[16]);
! else if (s_reg_encode < 9)
! infprintf (is, "%s-%s",
! mips_gpr_names[16],
! mips_gpr_names[15 + s_reg_encode]);
! else if (s_reg_encode == 9)
! infprintf (is, "%s-%s,%s",
! mips_gpr_names[16],
! mips_gpr_names[23],
! mips_gpr_names[30]);
! else
! infprintf (is, "UNKNOWN");
! }
!
! if (immed & 0x10) /* For ra. */
! {
! if (s_reg_encode == 0)
! infprintf (is, "%s", mips_gpr_names[31]);
! else
! infprintf (is, ",%s", mips_gpr_names[31]);
! }
! break;
! }
!
! case 'p':
! /* Sign-extend the displacement. */
! delta = GET_OP_S (insn, DELTA);
! info->target = (delta << 1) + memaddr + length;
! (*info->print_address_func) (info->target, info);
! break;
!
! case 'q':
! infprintf (is, "0x%x", GET_OP (insn, CODE2));
! break;
!
! case 't':
! case 'w':
! infprintf (is, "%s", mips_gpr_names[GET_OP (insn, RT)]);
! break;
!
! case 'y':
! infprintf (is, "%s", mips_gpr_names[GET_OP (insn, RS3)]);
! break;
!
! case 'z':
! infprintf (is, "%s", mips_gpr_names[0]);
! break;
!
! case '@': /* DSP 10-bit signed immediate in bit 16. */
! delta = (GET_OP (insn, IMM10) ^ 0x200) - 0x200;
! infprintf (is, "%d", delta);
! break;
!
! case 'B':
! infprintf (is, "0x%x", GET_OP (insn, CODE10));
! break;
!
! case 'C':
! infprintf (is, "0x%x", GET_OP (insn, COPZ));
! break;
!
! case 'D':
! infprintf (is, "%s", mips_fpr_names[GET_OP (insn, FD)]);
! break;
!
! case 'E':
! /* Coprocessor register for lwcN instructions, et al.
!
! Note that there is no load/store cp0 instructions, and
! that FPU (cp1) instructions disassemble this field using
! 'T' format. Therefore, until we gain understanding of
! cp2 register names, we can simply print the register
! numbers. */
! infprintf (is, "$%d", GET_OP (insn, RT));
! break;
!
! case 'G':
! /* Coprocessor register for mtcN instructions, et al. Note
! that FPU (cp1) instructions disassemble this field using
! 'S' format. Therefore, we only need to worry about cp0,
! cp2, and cp3. */
! if (op->name[strlen (op->name) - 1] == '0')
! {
! if (s[1] == ',' && s[2] == 'H')
! {
! const struct mips_cp0sel_name *n;
! unsigned int cp0reg, sel;
!
! cp0reg = GET_OP (insn, RS);
! sel = GET_OP (insn, SEL);
!
! /* CP0 register including 'sel' code for mtcN
! (et al.), to be printed textually if known.
! If not known, print both CP0 register name and
! sel numerically since CP0 register with sel 0 may
! have a name unrelated to register being
! printed. */
! n = lookup_mips_cp0sel_name (mips_cp0sel_names,
! mips_cp0sel_names_len,
! cp0reg, sel);
! if (n != NULL)
! infprintf (is, "%s", n->name);
! else
! infprintf (is, "$%d,%d", cp0reg, sel);
! s += 2;
! }
! else
! infprintf (is, "%s", mips_cp0_names[GET_OP (insn, RS)]);
! }
! else
! infprintf (is, "$%d", GET_OP (insn, RS));
! break;
!
! case 'H':
! infprintf (is, "%d", GET_OP (insn, SEL));
! break;
!
! case 'K':
! infprintf (is, "%s", mips_hwr_names[GET_OP (insn, RS)]);
! break;
!
! case 'M':
! infprintf (is, "$fcc%d", GET_OP (insn, CCC));
! break;
!
! case 'N':
! infprintf (is,
! (op->pinfo & (FP_D | FP_S)) != 0
! ? "$fcc%d" : "$cc%d",
! GET_OP (insn, BCC));
! break;
!
! case 'R':
! infprintf (is, "%s", mips_fpr_names[GET_OP (insn, FR)]);
! break;
!
! case 'S':
! case 'V':
! infprintf (is, "%s", mips_fpr_names[GET_OP (insn, FS)]);
! break;
!
! case 'T':
! infprintf (is, "%s", mips_fpr_names[GET_OP (insn, FT)]);
! break;
!
! case '+':
! /* Extension character; switch for second char. */
! s++;
! switch (*s)
! {
! case 'A':
! lsb = GET_OP (insn, EXTLSB);
! infprintf (is, "0x%x", lsb);
! break;
!
! case 'B':
! msb = GET_OP (insn, INSMSB);
! infprintf (is, "0x%x", msb - lsb + 1);
! break;
!
! case 'C':
! case 'H':
! msbd = GET_OP (insn, EXTMSBD);
! infprintf (is, "0x%x", msbd + 1);
! break;
!
! case 'E':
! lsb = GET_OP (insn, EXTLSB) + 32;
! infprintf (is, "0x%x", lsb);
! break;
!
! case 'F':
! msb = GET_OP (insn, INSMSB) + 32;
! infprintf (is, "0x%x", msb - lsb + 1);
! break;
!
! case 'G':
! msbd = GET_OP (insn, EXTMSBD) + 32;
! infprintf (is, "0x%x", msbd + 1);
! break;
!
! case 'i':
! info->target = (((memaddr + 4) & ~(bfd_vma) 0x0fffffff)
! | (GET_OP (insn, TARGET) << 2));
! (*info->print_address_func) (info->target, info);
! break;
!
! case 'j': /* 9-bit signed offset in bit 0. */
! delta = GET_OP_S (insn, EVAOFFSET);
! infprintf (is, "%d", delta);
! break;
!
! default:
! /* xgettext:c-format */
! infprintf (is,
! _("# internal disassembler error, "
! "unrecognized modifier (+%c)"),
! *s);
! abort ();
! }
! break;
!
! case 'm':
! /* Extension character; switch for second char. */
! s++;
! switch (*s)
! {
! case 'a': /* global pointer. */
! infprintf (is, "%s", mips_gpr_names[28]);
! break;
!
! case 'b':
! regno = micromips_to_32_reg_b_map[GET_OP (insn, MB)];
! infprintf (is, "%s", mips_gpr_names[regno]);
! break;
!
! case 'c':
! regno = micromips_to_32_reg_c_map[GET_OP (insn, MC)];
! infprintf (is, "%s", mips_gpr_names[regno]);
! break;
!
! case 'd':
! regno = micromips_to_32_reg_d_map[GET_OP (insn, MD)];
! infprintf (is, "%s", mips_gpr_names[regno]);
! break;
!
! case 'e':
! regno = micromips_to_32_reg_e_map[GET_OP (insn, ME)];
! infprintf (is, "%s", mips_gpr_names[regno]);
! break;
!
! case 'f':
! /* Save lastregno for "mt" to print out later. */
! lastregno = micromips_to_32_reg_f_map[GET_OP (insn, MF)];
! infprintf (is, "%s", mips_gpr_names[lastregno]);
! break;
!
! case 'g':
! regno = micromips_to_32_reg_g_map[GET_OP (insn, MG)];
! infprintf (is, "%s", mips_gpr_names[regno]);
! break;
!
! case 'h':
! regno = micromips_to_32_reg_h_map1[GET_OP (insn, MH)];
! infprintf (is, "%s", mips_gpr_names[regno]);
! regno = micromips_to_32_reg_h_map2[GET_OP (insn, MH)];
! infprintf (is, ",%s", mips_gpr_names[regno]);
! break;
!
! case 'j':
! infprintf (is, "%s", mips_gpr_names[GET_OP (insn, MJ)]);
! break;
!
! case 'l':
! regno = micromips_to_32_reg_l_map[GET_OP (insn, ML)];
! infprintf (is, "%s", mips_gpr_names[regno]);
! break;
!
! case 'm':
! regno = micromips_to_32_reg_m_map[GET_OP (insn, MM)];
! infprintf (is, "%s", mips_gpr_names[regno]);
! break;
!
! case 'n':
! regno = micromips_to_32_reg_n_map[GET_OP (insn, MN)];
! infprintf (is, "%s", mips_gpr_names[regno]);
! break;
!
! case 'p':
! /* Save lastregno for "mt" to print out later. */
! lastregno = GET_OP (insn, MP);
! infprintf (is, "%s", mips_gpr_names[lastregno]);
! break;
!
! case 'q':
! regno = micromips_to_32_reg_q_map[GET_OP (insn, MQ)];
! infprintf (is, "%s", mips_gpr_names[regno]);
! break;
!
! case 'r': /* program counter. */
! infprintf (is, "$pc");
! break;
!
! case 's': /* stack pointer. */
! lastregno = 29;
! infprintf (is, "%s", mips_gpr_names[29]);
! break;
!
! case 't':
! infprintf (is, "%s", mips_gpr_names[lastregno]);
! break;
!
! case 'z': /* $0. */
! infprintf (is, "%s", mips_gpr_names[0]);
! break;
!
! case 'A':
! /* Sign-extend the immediate. */
! immed = GET_OP_S (insn, IMMA) << 2;
! infprintf (is, "%d", immed);
! break;
!
! case 'B':
! immed = micromips_imm_b_map[GET_OP (insn, IMMB)];
! infprintf (is, "%d", immed);
! break;
!
! case 'C':
! immed = micromips_imm_c_map[GET_OP (insn, IMMC)];
! infprintf (is, "0x%x", immed);
! break;
!
! case 'D':
! /* Sign-extend the displacement. */
! delta = GET_OP_S (insn, IMMD);
! info->target = (delta << 1) + memaddr + length;
! (*info->print_address_func) (info->target, info);
! break;
!
! case 'E':
! /* Sign-extend the displacement. */
! delta = GET_OP_S (insn, IMME);
! info->target = (delta << 1) + memaddr + length;
! (*info->print_address_func) (info->target, info);
! break;
!
! case 'F':
! immed = GET_OP (insn, IMMF);
! infprintf (is, "0x%x", immed);
! break;
!
! case 'G':
! immed = (insn >> MICROMIPSOP_SH_IMMG) + 1;
! immed = (immed & MICROMIPSOP_MASK_IMMG) - 1;
! infprintf (is, "%d", immed);
! break;
!
! case 'H':
! immed = GET_OP (insn, IMMH) << 1;
! infprintf (is, "%d", immed);
! break;
!
! case 'I':
! immed = (insn >> MICROMIPSOP_SH_IMMI) + 1;
! immed = (immed & MICROMIPSOP_MASK_IMMI) - 1;
! infprintf (is, "%d", immed);
! break;
!
! case 'J':
! immed = GET_OP (insn, IMMJ) << 2;
! infprintf (is, "%d", immed);
! break;
!
! case 'L':
! immed = GET_OP (insn, IMML);
! infprintf (is, "%d", immed);
! break;
!
! case 'M':
! immed = (insn >> MICROMIPSOP_SH_IMMM) - 1;
! immed = (immed & MICROMIPSOP_MASK_IMMM) + 1;
! infprintf (is, "%d", immed);
! break;
!
! case 'N':
! immed = GET_OP (insn, IMMN);
! if (immed == 0)
! infprintf (is, "%s,%s",
! mips_gpr_names[16],
! mips_gpr_names[31]);
! else
! infprintf (is, "%s-%s,%s",
! mips_gpr_names[16],
! mips_gpr_names[16 + immed],
! mips_gpr_names[31]);
! break;
!
! case 'O':
! immed = GET_OP (insn, IMMO);
! infprintf (is, "0x%x", immed);
! break;
!
! case 'P':
! immed = GET_OP (insn, IMMP) << 2;
! infprintf (is, "%d", immed);
! break;
!
! case 'Q':
! /* Sign-extend the immediate. */
! immed = GET_OP_S (insn, IMMQ) << 2;
! infprintf (is, "%d", immed);
! break;
!
! case 'U':
! immed = GET_OP (insn, IMMU) << 2;
! infprintf (is, "%d", immed);
! break;
!
! case 'W':
! immed = GET_OP (insn, IMMW) << 2;
! infprintf (is, "%d", immed);
! break;
!
! case 'X':
! /* Sign-extend the immediate. */
! immed = GET_OP_S (insn, IMMX);
! infprintf (is, "%d", immed);
! break;
!
! case 'Y':
! /* Sign-extend the immediate. */
! immed = GET_OP_S (insn, IMMY) << 2;
! if ((unsigned int) (immed + 8) < 16)
! immed ^= 0x400;
! infprintf (is, "%d", immed);
! break;
!
! default:
! /* xgettext:c-format */
! infprintf (is,
! _("# internal disassembler error, "
! "unrecognized modifier (m%c)"),
! *s);
! abort ();
! }
! break;
!
! default:
! /* xgettext:c-format */
! infprintf (is,
! _("# internal disassembler error, "
! "unrecognized modifier (%c)"),
! *s);
! abort ();
! }
}
/* Figure out instruction type and branch delay information. */
--- 2134,2146 ----
&& ((length == 2 && (op->mask & 0xffff0000) == 0)
|| (length == 4 && (op->mask & 0xffff0000) != 0)))
{
infprintf (is, "%s", op->name);
! if (op->args[0])
{
! infprintf (is, "\t");
! print_insn_args (info, op, decode_micromips_operand, insn,
! memaddr + length + 1);
}
/* Figure out instruction type and branch delay information. */
*************** #define GET_OP_S(insn, field) \
*** 2937,2944 ****
return length;
}
}
- #undef GET_OP_S
- #undef GET_OP
infprintf (is, "0x%x", insn);
info->insn_type = dis_noninsn;
--- 2170,2175 ----
Index: gas/config/tc-mips.c
===================================================================
*** gas/config/tc-mips.c 2013-07-14 10:33:21.087809400 +0100
--- gas/config/tc-mips.c 2013-07-14 10:56:24.409981309 +0100
*************** static void s_mips_file (int);
*** 1326,1333 ****
static void s_mips_loc (int);
static bfd_boolean pic_need_relax (symbolS *, asection *);
static int relaxed_branch_length (fragS *, asection *, int);
- static int validate_mips_insn (const struct mips_opcode *);
- static int validate_micromips_insn (const struct mips_opcode *);
static int relaxed_micromips_16bit_branch_length (fragS *, asection *, int);
static int relaxed_micromips_32bit_branch_length (fragS *, asection *, int);
--- 1326,1331 ----
*************** is_delay_slot_valid (const struct mips_o
*** 2707,2712 ****
--- 2705,2815 ----
return TRUE;
}
+ /* For consistency checking, verify that all bits of OPCODE are
+ specified either by the match/mask part of the instruction
+ definition, or by the operand list. INSN_BITS says which
+ bits of the instruction are significant and DECODE_OPERAND
+ provides the mips_operand description of each operand. */
+
+ static int
+ validate_mips_insn (const struct mips_opcode *opcode,
+ unsigned long insn_bits,
+ const struct mips_operand *(*decode_operand) (const char *))
+ {
+ const char *s;
+ unsigned long used_bits, doubled, undefined;
+ const struct mips_operand *operand;
+
+ if ((opcode->mask & opcode->match) != opcode->match)
+ {
+ as_bad (_("internal: bad mips opcode (mask error): %s %s"),
+ opcode->name, opcode->args);
+ return 0;
+ }
+ used_bits = 0;
+ for (s = opcode->args; *s; ++s)
+ switch (*s)
+ {
+ case ',':
+ case '(':
+ case ')':
+ break;
+
+ default:
+ operand = decode_operand (s);
+ if (!operand)
+ {
+ as_bad (_("internal: unknown operand type: %s %s"),
+ opcode->name, opcode->args);
+ return 0;
+ }
+ used_bits |= ((1 << operand->size) - 1) << operand->lsb;
+ if (operand->type == OP_MDMX_IMM_REG)
+ /* Bit 5 is the format selector (OB vs QH). The opcode table
+ has separate entries for each format. */
+ used_bits &= ~(1 << (operand->lsb + 5));
+ /* Skip prefix characters. */
+ if (*s == '+' || *s == 'm')
+ ++s;
+ break;
+ }
+ doubled = used_bits & opcode->mask & insn_bits;
+ if (doubled)
+ {
+ as_bad (_("internal: bad mips opcode (bits 0x%08lx doubly defined):"
+ " %s %s"), doubled, opcode->name, opcode->args);
+ return 0;
+ }
+ used_bits |= opcode->mask;
+ undefined = ~used_bits & insn_bits;
+ if (undefined)
+ {
+ as_bad (_("internal: bad mips opcode (bits 0x%08lx undefined): %s %s"),
+ undefined, opcode->name, opcode->args);
+ return 0;
+ }
+ used_bits &= ~insn_bits;
+ if (used_bits)
+ {
+ as_bad (_("internal: bad mips opcode (bits 0x%08lx defined): %s %s"),
+ used_bits, opcode->name, opcode->args);
+ return 0;
+ }
+ return 1;
+ }
+
+ /* The microMIPS version of validate_mips_insn. */
+
+ static int
+ validate_micromips_insn (const struct mips_opcode *opc)
+ {
+ unsigned long insn_bits;
+ unsigned long major;
+ unsigned int length;
+
+ length = micromips_insn_length (opc);
+ if (length != 2 && length != 4)
+ {
+ as_bad (_("Internal error: bad microMIPS opcode (incorrect length: %u): "
+ "%s %s"), length, opc->name, opc->args);
+ return 0;
+ }
+ major = opc->match >> (10 + 8 * (length - 2));
+ if ((length == 2 && (major & 7) != 1 && (major & 6) != 2)
+ || (length == 4 && (major & 7) != 0 && (major & 4) != 4))
+ {
+ as_bad (_("Internal error: bad microMIPS opcode "
+ "(opcode/length mismatch): %s %s"), opc->name, opc->args);
+ return 0;
+ }
+
+ /* Shift piecewise to avoid an overflow where unsigned long is 32-bit. */
+ insn_bits = 1 << 4 * length;
+ insn_bits <<= 4 * length;
+ insn_bits -= 1;
+ return validate_mips_insn (opc, insn_bits, decode_micromips_operand);
+ }
+
/* This function is called once, at assembler startup time. It should set up
all the tables, etc. that the MD part of the assembler will need. */
*************** md_begin (void)
*** 2745,2751 ****
{
if (mips_opcodes[i].pinfo != INSN_MACRO)
{
! if (!validate_mips_insn (&mips_opcodes[i]))
broken = 1;
if (nop_insn.insn_mo == NULL && strcmp (name, "nop") == 0)
{
--- 2848,2855 ----
{
if (mips_opcodes[i].pinfo != INSN_MACRO)
{
! if (!validate_mips_insn (&mips_opcodes[i], 0xffffffff,
! decode_mips_operand))
broken = 1;
if (nop_insn.insn_mo == NULL && strcmp (name, "nop") == 0)
{
*************** mips16_macro (struct mips_cl_insn *ip)
*** 10748,11098 ****
}
}
- /* For consistency checking, verify that all bits are specified either
- by the match/mask part of the instruction definition, or by the
- operand list. */
- static int
- validate_mips_insn (const struct mips_opcode *opc)
- {
- const char *p = opc->args;
- char c;
- unsigned long used_bits = opc->mask;
-
- if ((used_bits & opc->match) != opc->match)
- {
- as_bad (_("internal: bad mips opcode (mask error): %s %s"),
- opc->name, opc->args);
- return 0;
- }
- #define USE_BITS(mask,shift) (used_bits |= ((mask) << (shift)))
- while (*p)
- switch (c = *p++)
- {
- case ',': break;
- case '(': break;
- case ')': break;
- case '+':
- switch (c = *p++)
- {
- case '1': USE_BITS (OP_MASK_UDI1, OP_SH_UDI1); break;
- case '2': USE_BITS (OP_MASK_UDI2, OP_SH_UDI2); break;
- case '3': USE_BITS (OP_MASK_UDI3, OP_SH_UDI3); break;
- case '4': USE_BITS (OP_MASK_UDI4, OP_SH_UDI4); break;
- case 'A': USE_BITS (OP_MASK_SHAMT, OP_SH_SHAMT); break;
- case 'B': USE_BITS (OP_MASK_INSMSB, OP_SH_INSMSB); break;
- case 'C': USE_BITS (OP_MASK_EXTMSBD, OP_SH_EXTMSBD); break;
- case 'E': USE_BITS (OP_MASK_SHAMT, OP_SH_SHAMT); break;
- case 'F': USE_BITS (OP_MASK_INSMSB, OP_SH_INSMSB); break;
- case 'G': USE_BITS (OP_MASK_EXTMSBD, OP_SH_EXTMSBD); break;
- case 'H': USE_BITS (OP_MASK_EXTMSBD, OP_SH_EXTMSBD); break;
- case 'I': break;
- case 'J': USE_BITS (OP_MASK_CODE10, OP_SH_CODE10); break;
- case 't': USE_BITS (OP_MASK_RT, OP_SH_RT); break;
- case 'x': USE_BITS (OP_MASK_BBITIND, OP_SH_BBITIND); break;
- case 'X': USE_BITS (OP_MASK_BBITIND, OP_SH_BBITIND); break;
- case 'p': USE_BITS (OP_MASK_CINSPOS, OP_SH_CINSPOS); break;
- case 'P': USE_BITS (OP_MASK_CINSPOS, OP_SH_CINSPOS); break;
- case 'Q': USE_BITS (OP_MASK_SEQI, OP_SH_SEQI); break;
- case 's': USE_BITS (OP_MASK_CINSLM1, OP_SH_CINSLM1); break;
- case 'S': USE_BITS (OP_MASK_CINSLM1, OP_SH_CINSLM1); break;
- case 'z': USE_BITS (OP_MASK_RZ, OP_SH_RZ); break;
- case 'Z': USE_BITS (OP_MASK_FZ, OP_SH_FZ); break;
- case 'a': USE_BITS (OP_MASK_OFFSET_A, OP_SH_OFFSET_A); break;
- case 'b': USE_BITS (OP_MASK_OFFSET_B, OP_SH_OFFSET_B); break;
- case 'c': USE_BITS (OP_MASK_OFFSET_C, OP_SH_OFFSET_C); break;
- case 'i': USE_BITS (OP_MASK_TARGET, OP_SH_TARGET); break;
- case 'j': USE_BITS (OP_MASK_EVAOFFSET, OP_SH_EVAOFFSET); break;
-
- default:
- as_bad (_("internal: bad mips opcode (unknown extension operand type `+%c'): %s %s"),
- c, opc->name, opc->args);
- return 0;
- }
- break;
- case '<': USE_BITS (OP_MASK_SHAMT, OP_SH_SHAMT); break;
- case '>': USE_BITS (OP_MASK_SHAMT, OP_SH_SHAMT); break;
- case 'A': break;
- case 'B': USE_BITS (OP_MASK_CODE20, OP_SH_CODE20); break;
- case 'C': USE_BITS (OP_MASK_COPZ, OP_SH_COPZ); break;
- case 'D': USE_BITS (OP_MASK_FD, OP_SH_FD); break;
- case 'E': USE_BITS (OP_MASK_RT, OP_SH_RT); break;
- case 'F': break;
- case 'G': USE_BITS (OP_MASK_RD, OP_SH_RD); break;
- case 'H': USE_BITS (OP_MASK_SEL, OP_SH_SEL); break;
- case 'I': break;
- case 'J': USE_BITS (OP_MASK_CODE19, OP_SH_CODE19); break;
- case 'K': USE_BITS (OP_MASK_RD, OP_SH_RD); break;
- case 'L': break;
- case 'M': USE_BITS (OP_MASK_CCC, OP_SH_CCC); break;
- case 'N': USE_BITS (OP_MASK_BCC, OP_SH_BCC); break;
- case 'O': USE_BITS (OP_MASK_ALN, OP_SH_ALN); break;
- case 'Q': USE_BITS (OP_MASK_VSEL, OP_SH_VSEL);
- USE_BITS (OP_MASK_FT, OP_SH_FT); break;
- case 'R': USE_BITS (OP_MASK_FR, OP_SH_FR); break;
- case 'S': USE_BITS (OP_MASK_FS, OP_SH_FS); break;
- case 'T': USE_BITS (OP_MASK_FT, OP_SH_FT); break;
- case 'V': USE_BITS (OP_MASK_FS, OP_SH_FS); break;
- case 'W': USE_BITS (OP_MASK_FT, OP_SH_FT); break;
- case 'X': USE_BITS (OP_MASK_FD, OP_SH_FD); break;
- case 'Y': USE_BITS (OP_MASK_FS, OP_SH_FS); break;
- case 'Z': USE_BITS (OP_MASK_FT, OP_SH_FT); break;
- case 'a': USE_BITS (OP_MASK_TARGET, OP_SH_TARGET); break;
- case 'b': USE_BITS (OP_MASK_RS, OP_SH_RS); break;
- case 'c': USE_BITS (OP_MASK_CODE, OP_SH_CODE); break;
- case 'd': USE_BITS (OP_MASK_RD, OP_SH_RD); break;
- case 'f': break;
- case 'h': USE_BITS (OP_MASK_PREFX, OP_SH_PREFX); break;
- case 'i': USE_BITS (OP_MASK_IMMEDIATE, OP_SH_IMMEDIATE); break;
- case 'j': USE_BITS (OP_MASK_DELTA, OP_SH_DELTA); break;
- case 'k': USE_BITS (OP_MASK_CACHE, OP_SH_CACHE); break;
- case 'l': break;
- case 'o': USE_BITS (OP_MASK_DELTA, OP_SH_DELTA); break;
- case 'p': USE_BITS (OP_MASK_DELTA, OP_SH_DELTA); break;
- case 'q': USE_BITS (OP_MASK_CODE2, OP_SH_CODE2); break;
- case 'r': USE_BITS (OP_MASK_RS, OP_SH_RS); break;
- case 's': USE_BITS (OP_MASK_RS, OP_SH_RS); break;
- case 't': USE_BITS (OP_MASK_RT, OP_SH_RT); break;
- case 'u': USE_BITS (OP_MASK_IMMEDIATE, OP_SH_IMMEDIATE); break;
- case 'v': USE_BITS (OP_MASK_RS, OP_SH_RS); break;
- case 'w': USE_BITS (OP_MASK_RT, OP_SH_RT); break;
- case 'x': break;
- case 'z': break;
- case 'P': USE_BITS (OP_MASK_PERFREG, OP_SH_PERFREG); break;
- case 'U': USE_BITS (OP_MASK_RD, OP_SH_RD);
- USE_BITS (OP_MASK_RT, OP_SH_RT); break;
- case 'e': USE_BITS (OP_MASK_VECBYTE, OP_SH_VECBYTE); break;
- case '%': USE_BITS (OP_MASK_VECALIGN, OP_SH_VECALIGN); break;
- case '1': USE_BITS (OP_MASK_STYPE, OP_SH_STYPE); break;
- case '2': USE_BITS (OP_MASK_BP, OP_SH_BP); break;
- case '3': USE_BITS (OP_MASK_SA3, OP_SH_SA3); break;
- case '4': USE_BITS (OP_MASK_SA4, OP_SH_SA4); break;
- case '5': USE_BITS (OP_MASK_IMM8, OP_SH_IMM8); break;
- case '6': USE_BITS (OP_MASK_RS, OP_SH_RS); break;
- case '7': USE_BITS (OP_MASK_DSPACC, OP_SH_DSPACC); break;
- case '8': USE_BITS (OP_MASK_WRDSP, OP_SH_WRDSP); break;
- case '9': USE_BITS (OP_MASK_DSPACC_S, OP_SH_DSPACC_S);break;
- case '0': USE_BITS (OP_MASK_DSPSFT, OP_SH_DSPSFT); break;
- case '\'': USE_BITS (OP_MASK_RDDSP, OP_SH_RDDSP); break;
- case ':': USE_BITS (OP_MASK_DSPSFT_7, OP_SH_DSPSFT_7);break;
- case '@': USE_BITS (OP_MASK_IMM10, OP_SH_IMM10); break;
- case '!': USE_BITS (OP_MASK_MT_U, OP_SH_MT_U); break;
- case '$': USE_BITS (OP_MASK_MT_H, OP_SH_MT_H); break;
- case '*': USE_BITS (OP_MASK_MTACC_T, OP_SH_MTACC_T); break;
- case '&': USE_BITS (OP_MASK_MTACC_D, OP_SH_MTACC_D); break;
- case '\\': USE_BITS (OP_MASK_3BITPOS, OP_SH_3BITPOS); break;
- case '~': USE_BITS (OP_MASK_OFFSET12, OP_SH_OFFSET12); break;
- case 'g': USE_BITS (OP_MASK_RD, OP_SH_RD); break;
- default:
- as_bad (_("internal: bad mips opcode (unknown operand type `%c'): %s %s"),
- c, opc->name, opc->args);
- return 0;
- }
- #undef USE_BITS
- if (used_bits != 0xffffffff)
- {
- as_bad (_("internal: bad mips opcode (bits 0x%lx undefined): %s %s"),
- ~used_bits & 0xffffffff, opc->name, opc->args);
- return 0;
- }
- return 1;
- }
-
- /* For consistency checking, verify that the length implied matches the
- major opcode and that all bits are specified either by the match/mask
- part of the instruction definition, or by the operand list. */
-
- static int
- validate_micromips_insn (const struct mips_opcode *opc)
- {
- unsigned long match = opc->match;
- unsigned long mask = opc->mask;
- const char *p = opc->args;
- unsigned long insn_bits;
- unsigned long used_bits;
- unsigned long major;
- unsigned int length;
- char e;
- char c;
-
- if ((mask & match) != match)
- {
- as_bad (_("Internal error: bad microMIPS opcode (mask error): %s %s"),
- opc->name, opc->args);
- return 0;
- }
- length = micromips_insn_length (opc);
- if (length != 2 && length != 4)
- {
- as_bad (_("Internal error: bad microMIPS opcode (incorrect length: %u): "
- "%s %s"), length, opc->name, opc->args);
- return 0;
- }
- major = match >> (10 + 8 * (length - 2));
- if ((length == 2 && (major & 7) != 1 && (major & 6) != 2)
- || (length == 4 && (major & 7) != 0 && (major & 4) != 4))
- {
- as_bad (_("Internal error: bad microMIPS opcode "
- "(opcode/length mismatch): %s %s"), opc->name, opc->args);
- return 0;
- }
-
- /* Shift piecewise to avoid an overflow where unsigned long is 32-bit. */
- insn_bits = 1 << 4 * length;
- insn_bits <<= 4 * length;
- insn_bits -= 1;
- used_bits = mask;
- #define USE_BITS(field) \
- (used_bits |= MICROMIPSOP_MASK_##field << MICROMIPSOP_SH_##field)
- while (*p)
- switch (c = *p++)
- {
- case ',': break;
- case '(': break;
- case ')': break;
- case '+':
- e = c;
- switch (c = *p++)
- {
- case 'A': USE_BITS (EXTLSB); break;
- case 'B': USE_BITS (INSMSB); break;
- case 'C': USE_BITS (EXTMSBD); break;
- case 'E': USE_BITS (EXTLSB); break;
- case 'F': USE_BITS (INSMSB); break;
- case 'G': USE_BITS (EXTMSBD); break;
- case 'H': USE_BITS (EXTMSBD); break;
- case 'i': USE_BITS (TARGET); break;
- case 'j': USE_BITS (EVAOFFSET); break;
- default:
- as_bad (_("Internal error: bad mips opcode "
- "(unknown extension operand type `%c%c'): %s %s"),
- e, c, opc->name, opc->args);
- return 0;
- }
- break;
- case 'm':
- e = c;
- switch (c = *p++)
- {
- case 'A': USE_BITS (IMMA); break;
- case 'B': USE_BITS (IMMB); break;
- case 'C': USE_BITS (IMMC); break;
- case 'D': USE_BITS (IMMD); break;
- case 'E': USE_BITS (IMME); break;
- case 'F': USE_BITS (IMMF); break;
- case 'G': USE_BITS (IMMG); break;
- case 'H': USE_BITS (IMMH); break;
- case 'I': USE_BITS (IMMI); break;
- case 'J': USE_BITS (IMMJ); break;
- case 'L': USE_BITS (IMML); break;
- case 'M': USE_BITS (IMMM); break;
- case 'N': USE_BITS (IMMN); break;
- case 'O': USE_BITS (IMMO); break;
- case 'P': USE_BITS (IMMP); break;
- case 'Q': USE_BITS (IMMQ); break;
- case 'U': USE_BITS (IMMU); break;
- case 'W': USE_BITS (IMMW); break;
- case 'X': USE_BITS (IMMX); break;
- case 'Y': USE_BITS (IMMY); break;
- case 'Z': break;
- case 'a': break;
- case 'b': USE_BITS (MB); break;
- case 'c': USE_BITS (MC); break;
- case 'd': USE_BITS (MD); break;
- case 'e': USE_BITS (ME); break;
- case 'f': USE_BITS (MF); break;
- case 'g': USE_BITS (MG); break;
- case 'h': USE_BITS (MH); break;
- case 'j': USE_BITS (MJ); break;
- case 'l': USE_BITS (ML); break;
- case 'm': USE_BITS (MM); break;
- case 'n': USE_BITS (MN); break;
- case 'p': USE_BITS (MP); break;
- case 'q': USE_BITS (MQ); break;
- case 'r': break;
- case 's': break;
- case 't': break;
- case 'x': break;
- case 'y': break;
- case 'z': break;
- default:
- as_bad (_("Internal error: bad mips opcode "
- "(unknown extension operand type `%c%c'): %s %s"),
- e, c, opc->name, opc->args);
- return 0;
- }
- break;
- case '.': USE_BITS (OFFSET10); break;
- case '1': USE_BITS (STYPE); break;
- case '2': USE_BITS (BP); break;
- case '3': USE_BITS (SA3); break;
- case '4': USE_BITS (SA4); break;
- case '5': USE_BITS (IMM8); break;
- case '6': USE_BITS (RS); break;
- case '7': USE_BITS (DSPACC); break;
- case '8': USE_BITS (WRDSP); break;
- case '0': USE_BITS (DSPSFT); break;
- case '<': USE_BITS (SHAMT); break;
- case '>': USE_BITS (SHAMT); break;
- case '@': USE_BITS (IMM10); break;
- case 'B': USE_BITS (CODE10); break;
- case 'C': USE_BITS (COPZ); break;
- case 'D': USE_BITS (FD); break;
- case 'E': USE_BITS (RT); break;
- case 'G': USE_BITS (RS); break;
- case 'H': USE_BITS (SEL); break;
- case 'K': USE_BITS (RS); break;
- case 'M': USE_BITS (CCC); break;
- case 'N': USE_BITS (BCC); break;
- case 'R': USE_BITS (FR); break;
- case 'S': USE_BITS (FS); break;
- case 'T': USE_BITS (FT); break;
- case 'V': USE_BITS (FS); break;
- case '\\': USE_BITS (3BITPOS); break;
- case '^': USE_BITS (RD); break;
- case 'a': USE_BITS (TARGET); break;
- case 'b': USE_BITS (RS); break;
- case 'c': USE_BITS (CODE); break;
- case 'd': USE_BITS (RD); break;
- case 'h': USE_BITS (PREFX); break;
- case 'i': USE_BITS (IMMEDIATE); break;
- case 'j': USE_BITS (DELTA); break;
- case 'k': USE_BITS (CACHE); break;
- case 'n': USE_BITS (RT); break;
- case 'o': USE_BITS (DELTA); break;
- case 'p': USE_BITS (DELTA); break;
- case 'q': USE_BITS (CODE2); break;
- case 'r': USE_BITS (RS); break;
- case 's': USE_BITS (RS); break;
- case 't': USE_BITS (RT); break;
- case 'u': USE_BITS (IMMEDIATE); break;
- case 'v': USE_BITS (RS); break;
- case 'w': USE_BITS (RT); break;
- case 'y': USE_BITS (RS3); break;
- case 'z': break;
- case '|': USE_BITS (TRAP); break;
- case '~': USE_BITS (OFFSET12); break;
- default:
- as_bad (_("Internal error: bad microMIPS opcode "
- "(unknown operand type `%c'): %s %s"),
- c, opc->name, opc->args);
- return 0;
- }
- #undef USE_BITS
- if (used_bits != insn_bits)
- {
- if (~used_bits & insn_bits)
- as_bad (_("Internal error: bad microMIPS opcode "
- "(bits 0x%lx undefined): %s %s"),
- ~used_bits & insn_bits, opc->name, opc->args);
- if (used_bits & ~insn_bits)
- as_bad (_("Internal error: bad microMIPS opcode "
- "(bits 0x%lx defined): %s %s"),
- used_bits & ~insn_bits, opc->name, opc->args);
- return 0;
- }
- return 1;
- }
-
/* UDI immediates. */
struct mips_immed {
char type;
--- 10852,10857 ----