mirror of
https://github.com/espressif/binutils-gdb.git
synced 2025-06-18 16:53:50 +08:00
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.
This commit is contained in:
@ -1,3 +1,12 @@
|
||||
2013-07-14 Richard Sandiford <rdsandiford@googlemail.com>
|
||||
|
||||
* 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.
|
||||
|
||||
2013-07-14 Richard Sandiford <rdsandiford@googlemail.com>
|
||||
|
||||
* config/tc-mips.c (mips16_macro_build): Remove 'Y' case.
|
||||
|
@ -1326,8 +1326,6 @@ static void s_mips_file (int);
|
||||
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);
|
||||
|
||||
@ -2707,6 +2705,111 @@ is_delay_slot_valid (const struct mips_opcode *mo)
|
||||
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. */
|
||||
|
||||
@ -2745,7 +2848,8 @@ md_begin (void)
|
||||
{
|
||||
if (mips_opcodes[i].pinfo != INSN_MACRO)
|
||||
{
|
||||
if (!validate_mips_insn (&mips_opcodes[i]))
|
||||
if (!validate_mips_insn (&mips_opcodes[i], 0xffffffff,
|
||||
decode_mips_operand))
|
||||
broken = 1;
|
||||
if (nop_insn.insn_mo == NULL && strcmp (name, "nop") == 0)
|
||||
{
|
||||
@ -10748,351 +10852,6 @@ mips16_macro (struct mips_cl_insn *ip)
|
||||
}
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
@ -1,3 +1,13 @@
|
||||
2013-07-14 Richard Sandiford <rdsandiford@googlemail.com>
|
||||
|
||||
* 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.
|
||||
|
||||
2013-07-14 Richard Sandiford <rdsandiford@googlemail.com>
|
||||
|
||||
* mips.h: Document MIPS16 "I" opcode.
|
||||
|
@ -332,6 +332,292 @@
|
||||
#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
|
||||
@ -1215,6 +1501,7 @@ enum
|
||||
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;
|
||||
@ -1780,6 +2067,7 @@ extern const int bfd_mips16_num_opcodes;
|
||||
" 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;
|
||||
|
||||
|
@ -1,3 +1,29 @@
|
||||
2013-07-14 Richard Sandiford <rdsandiford@googlemail.com>
|
||||
|
||||
* 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.
|
||||
|
||||
2013-07-14 Richard Sandiford <rdsandiford@googlemail.com>
|
||||
|
||||
* mips16-opc.c (mips16_opcodes): Use "I" for immediate operands
|
||||
|
@ -20,8 +20,155 @@
|
||||
MA 02110-1301, USA. */
|
||||
|
||||
#include "sysdep.h"
|
||||
#include <stdio.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
|
||||
|
1427
opcodes/mips-dis.c
1427
opcodes/mips-dis.c
File diff suppressed because it is too large
Load Diff
113
opcodes/mips-formats.h
Normal file
113
opcodes/mips-formats.h
Normal file
@ -0,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; \
|
||||
}
|
@ -28,6 +28,123 @@
|
||||
#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. */
|
||||
|
||||
|
Reference in New Issue
Block a user