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:
Richard Sandiford
2013-07-14 13:28:56 +00:00
parent 2f8b73cc2b
commit ab90248154
9 changed files with 1171 additions and 1471 deletions

View File

@ -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.

View File

@ -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;

View File

@ -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.

View File

@ -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;

View File

@ -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

View File

@ -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

File diff suppressed because it is too large Load Diff

113
opcodes/mips-formats.h Normal file
View 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; \
}

View File

@ -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. */