+2016-12-20 Maciej W. Rozycki <macro@imgtec.com>
+
+ * testsuite/binutils-all/mips/mips16-extend-noinsn.d: Adjust
+ test for separate EXTEND prefix disassembly.
+
2016-12-20 Andrew Waterman <andrew@sifive.com>
* readelf.c (get_machine_flags): Use
[0-9a-f]+ <[^>]*> f432 extend 0x432
[0-9a-f]+ <[^>]*> 1c00 0000 jalx 00000000 <foo>
[0-9a-f]+ <[^>]*> 6500 nop
-[0-9a-f]+ <[^>]*> f123 6621 0xf123 0x6621
-[0-9a-f]+ <[^>]*> f456 e935 0xf456 0xe935
-[0-9a-f]+ <[^>]*> f765 ea60 0xf765 0xea60
-[0-9a-f]+ <[^>]*> f432 ece0 0xf432 0xece0
-[0-9a-f]+ <[^>]*> f5aa e971 0xf5aa 0xe971
-[0-9a-f]+ <[^>]*> f655 ebf1 0xf655 0xebf1
+[0-9a-f]+ <[^>]*> f123 extend 0x123
+[0-9a-f]+ <[^>]*> 6621 0x6621
+[0-9a-f]+ <[^>]*> f456 extend 0x456
+[0-9a-f]+ <[^>]*> e935 0xe935
+[0-9a-f]+ <[^>]*> f765 extend 0x765
+[0-9a-f]+ <[^>]*> ea60 0xea60
+[0-9a-f]+ <[^>]*> f432 extend 0x432
+[0-9a-f]+ <[^>]*> ece0 0xece0
+[0-9a-f]+ <[^>]*> f5aa extend 0x5aa
+[0-9a-f]+ <[^>]*> e971 0xe971
+[0-9a-f]+ <[^>]*> f655 extend 0x655
+[0-9a-f]+ <[^>]*> ebf1 0xebf1
[0-9a-f]+ <[^>]*> 6621 0x6621
[0-9a-f]+ <[^>]*> e935 0xe935
[0-9a-f]+ <[^>]*> ea60 0xea60
+2016-12-20 Maciej W. Rozycki <macro@imgtec.com>
+
+ * config/tc-mips.c (micromips_insn_length): Use
+ `mips_opcode_32bit_p'.
+ (is_size_valid): Adjust description.
+ (is_size_valid_16): New function.
+ (validate_mips_insn): Use `mips_opcode_32bit_p' in MIPS16
+ operand decoding.
+ (validate_mips16_insn): Remove `a' and `i' operand code special
+ casing, use `mips_opcode_32bit_p' to determine instruction
+ width.
+ (append_insn): Adjust forced MIPS16 instruction size
+ determination.
+ (match_mips16_insn): Likewise. Don't shift the instruction's
+ opcode with the `a' and `i' operand codes. Use
+ `mips_opcode_32bit_p' in operand decoding.
+ (match_mips16_insns): Check for forced instruction size's
+ validity.
+ (mips16_ip): Don't force instruction size in the `noautoextend'
+ mode.
+ * testsuite/gas/mips/mips16-jal-e.d: New test.
+ * testsuite/gas/mips/mips16-jal-t.d: New test.
+ * testsuite/gas/mips/mips16-macro-e.d: New test.
+ * testsuite/gas/mips/mips16-macro-t.d: New test.
+ * testsuite/gas/mips/mips16-jal-t.l: New stderr output.
+ * testsuite/gas/mips/mips16-macro-e.l: New stderr output.
+ * testsuite/gas/mips/mips16-macro-t.l: New stderr output.
+ * testsuite/gas/mips/mips16-jal-e.s: New test source.
+ * testsuite/gas/mips/mips16-jal-t.s: New test source.
+ * testsuite/gas/mips/mips16-macro-e.s: New test source.
+ * testsuite/gas/mips/mips16-macro-t.s: New test source.
+ * testsuite/gas/mips/mips.exp: Run the new tests.
+
2016-12-20 Maciej W. Rozycki <macro@imgtec.com>
* testsuite/gas/mips/mips16-macro.l: New list test.
static inline unsigned int
micromips_insn_length (const struct mips_opcode *mo)
{
- return (mo->mask >> 16) == 0 ? 2 : 4;
+ return mips_opcode_32bit_p (mo) ? 4 : 2;
}
/* Return the length of MIPS16 instruction OPCODE. */
}
/* Return TRUE if the size of the microMIPS opcode MO matches one
- explicitly requested. Always TRUE in the standard MIPS mode. */
+ explicitly requested. Always TRUE in the standard MIPS mode.
+ Use is_size_valid_16 for MIPS16 opcodes. */
static bfd_boolean
is_size_valid (const struct mips_opcode *mo)
return forced_insn_length == micromips_insn_length (mo);
}
+/* Return TRUE if the size of the MIPS16 opcode MO matches one
+ explicitly requested. */
+
+static bfd_boolean
+is_size_valid_16 (const struct mips_opcode *mo)
+{
+ if (!forced_insn_length)
+ return TRUE;
+ if (mo->pinfo == INSN_MACRO)
+ return FALSE;
+ if (forced_insn_length == 2 && mips_opcode_32bit_p (mo))
+ return FALSE;
+ return TRUE;
+}
+
/* Return TRUE if the microMIPS opcode MO is valid for the delay slot
of the preceding instruction. Always TRUE in the standard MIPS mode.
default:
if (!decode_operand)
- operand = decode_mips16_operand (*s, FALSE);
+ operand = decode_mips16_operand (*s, mips_opcode_32bit_p (opcode));
else
operand = decode_operand (s);
if (!operand && opcode->pinfo != INSN_MACRO)
validate_mips16_insn (const struct mips_opcode *opcode,
struct mips_operand_array *operands)
{
- if (opcode->args[0] == 'a' || opcode->args[0] == 'i')
- {
- /* In this case OPCODE defines the first 16 bits in a 32-bit jump
- instruction. Use TMP to describe the full instruction. */
- struct mips_opcode tmp;
+ unsigned long insn_bits = mips_opcode_32bit_p (opcode) ? 0xffffffff : 0xffff;
- tmp = *opcode;
- tmp.match <<= 16;
- tmp.mask <<= 16;
- return validate_mips_insn (&tmp, 0xffffffff, 0, operands);
- }
- return validate_mips_insn (opcode, 0xffff, 0, operands);
+ return validate_mips_insn (opcode, insn_bits, 0, operands);
}
/* The microMIPS version of validate_mips_insn. */
}
else if (mips_opts.mips16 && *reloc_type > BFD_RELOC_UNUSED)
{
+ bfd_boolean require_unextended;
+ bfd_boolean require_extended;
symbolS *symbol;
offsetT offset;
+ if (forced_insn_length != 0)
+ {
+ require_unextended = forced_insn_length == 2;
+ require_extended = forced_insn_length == 4;
+ }
+ else
+ {
+ require_unextended = (mips_opts.noautoextend
+ && !mips_opcode_32bit_p (ip->insn_mo));
+ require_extended = 0;
+ }
+
/* We need to set up a variant frag. */
gas_assert (address_expr != NULL);
/* Pass any `O_symbol' expression unchanged as an `expr_section'
add_relaxed_insn (ip, 4, 0,
RELAX_MIPS16_ENCODE
(*reloc_type - BFD_RELOC_UNUSED,
- forced_insn_length == 2, forced_insn_length == 4,
+ require_unextended, require_extended,
delayed_branch_p (&history[0]),
history[0].mips16_absolute_jump_p),
symbol, offset);
const char *args;
const struct mips_operand *operand;
const struct mips_operand *ext_operand;
+ int required_insn_length;
struct mips_arg_info arg;
int relax_char;
+ if (forced_insn_length)
+ required_insn_length = forced_insn_length;
+ else if (mips_opts.noautoextend && !mips_opcode_32bit_p (opcode))
+ required_insn_length = 2;
+ else
+ required_insn_length = 0;
+
create_insn (insn, opcode);
imm_expr.X_op = O_absent;
offset_expr.X_op = O_absent;
&value))
{
mips16_immed (NULL, 0, relax_char, *offset_reloc, value,
- forced_insn_length, &insn->insn_opcode);
+ required_insn_length, &insn->insn_opcode);
offset_expr.X_op = O_absent;
*offset_reloc = BFD_RELOC_UNUSED;
}
else if (relax_char && *offset_reloc != BFD_RELOC_UNUSED)
{
- if (forced_insn_length == 2)
+ if (required_insn_length == 2)
set_insn_error (0, _("invalid unextended operand value"));
forced_insn_length = 4;
insn->insn_opcode |= MIPS16_EXTEND;
case 'a':
case 'i':
*offset_reloc = BFD_RELOC_MIPS16_JMP;
- insn->insn_opcode <<= 16;
break;
}
- operand = decode_mips16_operand (c, FALSE);
+ operand = decode_mips16_operand (c, mips_opcode_32bit_p (opcode));
if (!operand)
abort ();
{
const struct mips_opcode *opcode;
bfd_boolean seen_valid_for_isa;
+ bfd_boolean seen_valid_for_size;
/* Search for a match, ignoring alternatives that don't satisfy the
current ISA. There are no separate entries for extended forms so
we deal with forced_length later. */
seen_valid_for_isa = FALSE;
+ seen_valid_for_size = FALSE;
opcode = first;
do
{
if (is_opcode_valid_16 (opcode))
{
seen_valid_for_isa = TRUE;
- if (match_mips16_insn (insn, opcode, tokens))
- return TRUE;
+ if (is_size_valid_16 (opcode))
+ {
+ seen_valid_for_size = TRUE;
+ if (match_mips16_insn (insn, opcode, tokens))
+ return TRUE;
+ }
}
++opcode;
}
return TRUE;
}
+ /* Handle the case where we didn't try to match an instruction because
+ all the alternatives were of the wrong size. */
+ if (!seen_valid_for_size)
+ {
+ if (forced_insn_length == 2)
+ set_insn_error
+ (0, _("unrecognized unextended version of MIPS16 opcode"));
+ else
+ set_insn_error
+ (0, _("unrecognized extended version of MIPS16 opcode"));
+ return TRUE;
+ }
+
return FALSE;
}
return;
}
- if (mips_opts.noautoextend && !forced_insn_length)
- forced_insn_length = 2;
-
*end = 0;
first = (struct mips_opcode *) hash_find (mips16_op_hash, str);
*end = c;
}
run_dump_test "mips16-macro"
run_list_test "mips16-macro" "-32 -march=mips1"
+ run_dump_test "mips16-macro-t" "{{as} {-march=mips3}}"
+ run_dump_test "mips16-macro-e" "{{as} {-march=mips3}}"
# Check MIPS16e extensions
run_dump_test_arches "mips16e" [mips_arch_list_matching mips32 !micromips \
!mips32r6]
run_dump_test "mips16-branch-unextended-1"
run_dump_test "mips16-branch-unextended-2"
+ run_dump_test "mips16-jal-t"
+ run_dump_test "mips16-jal-e"
run_dump_test "vxworks1"
run_dump_test "vxworks1-xgot"
--- /dev/null
+#objdump: -d --prefix-addresses --show-raw-insn
+#name: MIPS16 explicit extended JAL instructions
+#as: -32
+
+.*: +file format .*mips.*
+
+Disassembly of section \.text:
+[0-9a-f]+ <[^>]*> 1c00 0000 jalx 00000000 <foo>
+[0-9a-f]+ <[^>]*> 6500 nop
+[0-9a-f]+ <[^>]*> 1800 0000 jal 00000000 <foo>
+[0-9a-f]+ <[^>]*> 6500 nop
+ \.\.\.
--- /dev/null
+ .set mips16
+foo:
+ jalx.e bar
+ jal.e baz
+
+# Force some (non-delay-slot) zero bytes, to make 'objdump' print ...
+ .align 4, 0
+ .space 16
--- /dev/null
+#name: MIPS16 explicit unextended JAL instructions
+#as: -32
+#error-output: mips16-jal-t.l
--- /dev/null
+.*: Assembler messages:
+.*:3: Error: unrecognized unextended version of MIPS16 opcode `jalx\.t bar'
+.*:4: Error: invalid operands `jal\.t baz'
--- /dev/null
+ .set mips16
+foo:
+ jalx.t bar
+ jal.t baz
+
+# Force some (non-delay-slot) zero bytes, to make 'objdump' print ...
+ .align 4, 0
+ .space 16
--- /dev/null
+#as: -32
+#name: MIPS16 explicit extended macros
+#error-output: mips16-macro-e.l
--- /dev/null
+.*: Assembler messages:
+.*:4: Error: invalid operands `div\.e \$2,\$3,\$4'
+.*:5: Error: invalid operands `divu\.e \$3,\$4,\$5'
+.*:6: Error: invalid operands `ddiv\.e \$4,\$5,\$6'
+.*:7: Error: invalid operands `ddivu\.e \$5,\$6,\$7'
+.*:8: Error: invalid operands `rem\.e \$6,\$7,\$16'
+.*:9: Error: invalid operands `remu\.e \$6,\$7,\$17'
+.*:10: Error: invalid operands `drem\.e \$2,\$3,\$4'
+.*:11: Error: invalid operands `dremu\.e \$3,\$4,\$5'
+.*:12: Error: unrecognized extended version of MIPS16 opcode `mul\.e \$4,\$5,\$6'
+.*:13: Error: unrecognized extended version of MIPS16 opcode `dmul\.e \$5,\$6,\$7'
+.*:14: Error: invalid operands `subu\.e \$2,-32767'
+.*:15: Error: invalid operands `subu\.e \$3,16'
+.*:16: Error: invalid operands `subu\.e \$4,32768'
+.*:17: Error: invalid operands `subu\.e \$3,\$7,-16383'
+.*:18: Error: invalid operands `subu\.e \$4,\$16,4'
+.*:19: Error: invalid operands `subu\.e \$5,\$17,16384'
+.*:20: Error: invalid operands `dsubu\.e \$4,-32767'
+.*:21: Error: invalid operands `dsubu\.e \$6,6'
+.*:22: Error: invalid operands `dsubu\.e \$7,32768'
+.*:23: Error: invalid operands `dsubu\.e \$2,\$4,-16383'
+.*:24: Error: invalid operands `dsubu\.e \$3,\$7,8'
+.*:25: Error: invalid operands `dsubu\.e \$4,\$5,16384'
+.*:26: Error: unrecognized extended version of MIPS16 opcode `beq\.e \$2,\$3,1b'
+.*:27: Error: unrecognized extended version of MIPS16 opcode `bne\.e \$4,\$5,1b'
+.*:28: Error: unrecognized extended version of MIPS16 opcode `blt\.e \$6,\$7,1b'
+.*:29: Error: unrecognized extended version of MIPS16 opcode `bltu\.e \$16,\$17,1b'
+.*:30: Error: unrecognized extended version of MIPS16 opcode `ble\.e \$4,\$7,1b'
+.*:31: Error: unrecognized extended version of MIPS16 opcode `bleu\.e \$5,\$6,1b'
+.*:32: Error: unrecognized extended version of MIPS16 opcode `bge\.e \$4,\$16,1b'
+.*:33: Error: unrecognized extended version of MIPS16 opcode `bgeu\.e \$5,\$17,1b'
+.*:34: Error: unrecognized extended version of MIPS16 opcode `bgt\.e \$4,\$6,1b'
+.*:35: Error: unrecognized extended version of MIPS16 opcode `bgtu\.e \$5,\$7,1b'
+.*:36: Error: unrecognized extended version of MIPS16 opcode `beq\.e \$2,1,1b'
+.*:37: Error: unrecognized extended version of MIPS16 opcode `beq\.e \$3,65535,1b'
+.*:38: Error: unrecognized extended version of MIPS16 opcode `bne\.e \$4,1,1b'
+.*:39: Error: unrecognized extended version of MIPS16 opcode `bne\.e \$5,65535,1b'
+.*:40: Error: unrecognized extended version of MIPS16 opcode `blt\.e \$6,-32768,1b'
+.*:41: Error: unrecognized extended version of MIPS16 opcode `blt\.e \$7,32767,1b'
+.*:42: Error: unrecognized extended version of MIPS16 opcode `bltu\.e \$16,-32768,1b'
+.*:43: Error: unrecognized extended version of MIPS16 opcode `bltu\.e \$17,32767,1b'
+.*:44: Error: unrecognized extended version of MIPS16 opcode `ble\.e \$2,-32769,1b'
+.*:45: Error: unrecognized extended version of MIPS16 opcode `ble\.e \$3,32766,1b'
+.*:46: Error: unrecognized extended version of MIPS16 opcode `bleu\.e \$4,-32769,1b'
+.*:47: Error: unrecognized extended version of MIPS16 opcode `bleu\.e \$5,32766,1b'
+.*:48: Error: unrecognized extended version of MIPS16 opcode `bge\.e \$6,-32768,1b'
+.*:49: Error: unrecognized extended version of MIPS16 opcode `bge\.e \$7,32766,1b'
+.*:50: Error: unrecognized extended version of MIPS16 opcode `bgeu\.e \$16,-32768,1b'
+.*:51: Error: unrecognized extended version of MIPS16 opcode `bgeu\.e \$17,32767,1b'
+.*:52: Error: unrecognized extended version of MIPS16 opcode `bgt\.e \$2,-32769,1b'
+.*:53: Error: unrecognized extended version of MIPS16 opcode `bgt\.e \$3,32766,1b'
+.*:54: Error: unrecognized extended version of MIPS16 opcode `bgtu\.e \$4,-32769,1b'
+.*:55: Error: unrecognized extended version of MIPS16 opcode `bgtu\.e \$5,32766,1b'
+.*:56: Error: unrecognized extended version of MIPS16 opcode `abs\.e \$2'
+.*:57: Error: unrecognized extended version of MIPS16 opcode `abs\.e \$3,\$3'
+.*:58: Error: unrecognized extended version of MIPS16 opcode `abs\.e \$4,\$5'
--- /dev/null
+ .set mips16
+ .ent foo
+foo:
+ div.e $2,$3,$4
+ divu.e $3,$4,$5
+ ddiv.e $4,$5,$6
+ ddivu.e $5,$6,$7
+ rem.e $6,$7,$16
+ remu.e $6,$7,$17
+ drem.e $2,$3,$4
+ dremu.e $3,$4,$5
+ mul.e $4,$5,$6
+ dmul.e $5,$6,$7
+ subu.e $2,-32767
+ subu.e $3,16
+ subu.e $4,32768
+ subu.e $3,$7,-16383
+ subu.e $4,$16,4
+ subu.e $5,$17,16384
+ dsubu.e $4,-32767
+ dsubu.e $6,6
+ dsubu.e $7,32768
+ dsubu.e $2,$4,-16383
+ dsubu.e $3,$7,8
+ dsubu.e $4,$5,16384
+1: beq.e $2,$3,1b
+1: bne.e $4,$5,1b
+1: blt.e $6,$7,1b
+1: bltu.e $16,$17,1b
+1: ble.e $4,$7,1b
+1: bleu.e $5,$6,1b
+1: bge.e $4,$16,1b
+1: bgeu.e $5,$17,1b
+1: bgt.e $4,$6,1b
+1: bgtu.e $5,$7,1b
+1: beq.e $2,1,1b
+1: beq.e $3,65535,1b
+1: bne.e $4,1,1b
+1: bne.e $5,65535,1b
+1: blt.e $6,-32768,1b
+1: blt.e $7,32767,1b
+1: bltu.e $16,-32768,1b
+1: bltu.e $17,32767,1b
+1: ble.e $2,-32769,1b
+1: ble.e $3,32766,1b
+1: bleu.e $4,-32769,1b
+1: bleu.e $5,32766,1b
+1: bge.e $6,-32768,1b
+1: bge.e $7,32766,1b
+1: bgeu.e $16,-32768,1b
+1: bgeu.e $17,32767,1b
+1: bgt.e $2,-32769,1b
+1: bgt.e $3,32766,1b
+1: bgtu.e $4,-32769,1b
+1: bgtu.e $5,32766,1b
+ abs.e $2
+ abs.e $3,$3
+ abs.e $4,$5
+ .end foo
--- /dev/null
+#as: -32
+#name: MIPS16 explicit unextended macros
+#error-output: mips16-macro-t.l
--- /dev/null
+.*: Assembler messages:
+.*:4: Error: invalid operands `div\.t \$2,\$3,\$4'
+.*:5: Error: invalid operands `divu\.t \$3,\$4,\$5'
+.*:6: Error: invalid operands `ddiv\.t \$4,\$5,\$6'
+.*:7: Error: invalid operands `ddivu\.t \$5,\$6,\$7'
+.*:8: Error: invalid operands `rem\.t \$6,\$7,\$16'
+.*:9: Error: invalid operands `remu\.t \$6,\$7,\$17'
+.*:10: Error: invalid operands `drem\.t \$2,\$3,\$4'
+.*:11: Error: invalid operands `dremu\.t \$3,\$4,\$5'
+.*:12: Error: unrecognized unextended version of MIPS16 opcode `mul\.t \$4,\$5,\$6'
+.*:13: Error: unrecognized unextended version of MIPS16 opcode `dmul\.t \$5,\$6,\$7'
+.*:14: Error: invalid operands `subu\.t \$2,-32767'
+.*:15: Error: invalid operands `subu\.t \$3,16'
+.*:16: Error: invalid operands `subu\.t \$4,32768'
+.*:17: Error: invalid operands `subu\.t \$3,\$7,-16383'
+.*:18: Error: invalid operands `subu\.t \$4,\$16,4'
+.*:19: Error: invalid operands `subu\.t \$5,\$17,16384'
+.*:20: Error: invalid operands `dsubu\.t \$4,-32767'
+.*:21: Error: invalid operands `dsubu\.t \$6,6'
+.*:22: Error: invalid operands `dsubu\.t \$7,32768'
+.*:23: Error: invalid operands `dsubu\.t \$2,\$4,-16383'
+.*:24: Error: invalid operands `dsubu\.t \$3,\$7,8'
+.*:25: Error: invalid operands `dsubu\.t \$4,\$5,16384'
+.*:26: Error: unrecognized unextended version of MIPS16 opcode `beq\.t \$2,\$3,1b'
+.*:27: Error: unrecognized unextended version of MIPS16 opcode `bne\.t \$4,\$5,1b'
+.*:28: Error: unrecognized unextended version of MIPS16 opcode `blt\.t \$6,\$7,1b'
+.*:29: Error: unrecognized unextended version of MIPS16 opcode `bltu\.t \$16,\$17,1b'
+.*:30: Error: unrecognized unextended version of MIPS16 opcode `ble\.t \$4,\$7,1b'
+.*:31: Error: unrecognized unextended version of MIPS16 opcode `bleu\.t \$5,\$6,1b'
+.*:32: Error: unrecognized unextended version of MIPS16 opcode `bge\.t \$4,\$16,1b'
+.*:33: Error: unrecognized unextended version of MIPS16 opcode `bgeu\.t \$5,\$17,1b'
+.*:34: Error: unrecognized unextended version of MIPS16 opcode `bgt\.t \$4,\$6,1b'
+.*:35: Error: unrecognized unextended version of MIPS16 opcode `bgtu\.t \$5,\$7,1b'
+.*:36: Error: unrecognized unextended version of MIPS16 opcode `beq\.t \$2,1,1b'
+.*:37: Error: unrecognized unextended version of MIPS16 opcode `beq\.t \$3,65535,1b'
+.*:38: Error: unrecognized unextended version of MIPS16 opcode `bne\.t \$4,1,1b'
+.*:39: Error: unrecognized unextended version of MIPS16 opcode `bne\.t \$5,65535,1b'
+.*:40: Error: unrecognized unextended version of MIPS16 opcode `blt\.t \$6,-32768,1b'
+.*:41: Error: unrecognized unextended version of MIPS16 opcode `blt\.t \$7,32767,1b'
+.*:42: Error: unrecognized unextended version of MIPS16 opcode `bltu\.t \$16,-32768,1b'
+.*:43: Error: unrecognized unextended version of MIPS16 opcode `bltu\.t \$17,32767,1b'
+.*:44: Error: unrecognized unextended version of MIPS16 opcode `ble\.t \$2,-32769,1b'
+.*:45: Error: unrecognized unextended version of MIPS16 opcode `ble\.t \$3,32766,1b'
+.*:46: Error: unrecognized unextended version of MIPS16 opcode `bleu\.t \$4,-32769,1b'
+.*:47: Error: unrecognized unextended version of MIPS16 opcode `bleu\.t \$5,32766,1b'
+.*:48: Error: unrecognized unextended version of MIPS16 opcode `bge\.t \$6,-32768,1b'
+.*:49: Error: unrecognized unextended version of MIPS16 opcode `bge\.t \$7,32766,1b'
+.*:50: Error: unrecognized unextended version of MIPS16 opcode `bgeu\.t \$16,-32768,1b'
+.*:51: Error: unrecognized unextended version of MIPS16 opcode `bgeu\.t \$17,32767,1b'
+.*:52: Error: unrecognized unextended version of MIPS16 opcode `bgt\.t \$2,-32769,1b'
+.*:53: Error: unrecognized unextended version of MIPS16 opcode `bgt\.t \$3,32766,1b'
+.*:54: Error: unrecognized unextended version of MIPS16 opcode `bgtu\.t \$4,-32769,1b'
+.*:55: Error: unrecognized unextended version of MIPS16 opcode `bgtu\.t \$5,32766,1b'
+.*:56: Error: unrecognized unextended version of MIPS16 opcode `abs\.t \$2'
+.*:57: Error: unrecognized unextended version of MIPS16 opcode `abs\.t \$3,\$3'
+.*:58: Error: unrecognized unextended version of MIPS16 opcode `abs\.t \$4,\$5'
--- /dev/null
+ .set mips16
+ .ent foo
+foo:
+ div.t $2,$3,$4
+ divu.t $3,$4,$5
+ ddiv.t $4,$5,$6
+ ddivu.t $5,$6,$7
+ rem.t $6,$7,$16
+ remu.t $6,$7,$17
+ drem.t $2,$3,$4
+ dremu.t $3,$4,$5
+ mul.t $4,$5,$6
+ dmul.t $5,$6,$7
+ subu.t $2,-32767
+ subu.t $3,16
+ subu.t $4,32768
+ subu.t $3,$7,-16383
+ subu.t $4,$16,4
+ subu.t $5,$17,16384
+ dsubu.t $4,-32767
+ dsubu.t $6,6
+ dsubu.t $7,32768
+ dsubu.t $2,$4,-16383
+ dsubu.t $3,$7,8
+ dsubu.t $4,$5,16384
+1: beq.t $2,$3,1b
+1: bne.t $4,$5,1b
+1: blt.t $6,$7,1b
+1: bltu.t $16,$17,1b
+1: ble.t $4,$7,1b
+1: bleu.t $5,$6,1b
+1: bge.t $4,$16,1b
+1: bgeu.t $5,$17,1b
+1: bgt.t $4,$6,1b
+1: bgtu.t $5,$7,1b
+1: beq.t $2,1,1b
+1: beq.t $3,65535,1b
+1: bne.t $4,1,1b
+1: bne.t $5,65535,1b
+1: blt.t $6,-32768,1b
+1: blt.t $7,32767,1b
+1: bltu.t $16,-32768,1b
+1: bltu.t $17,32767,1b
+1: ble.t $2,-32769,1b
+1: ble.t $3,32766,1b
+1: bleu.t $4,-32769,1b
+1: bleu.t $5,32766,1b
+1: bge.t $6,-32768,1b
+1: bge.t $7,32766,1b
+1: bgeu.t $16,-32768,1b
+1: bgeu.t $17,32767,1b
+1: bgt.t $2,-32769,1b
+1: bgt.t $3,32766,1b
+1: bgtu.t $4,-32769,1b
+1: bgtu.t $5,32766,1b
+ abs.t $2
+ abs.t $3,$3
+ abs.t $4,$5
+ .end foo
+2016-12-20 Maciej W. Rozycki <macro@imgtec.com>
+
+ * opcode/mips.h (mips_opcode_32bit_p): New inline function.
+
2016-12-20 Andrew Waterman <andrew@sifive.com>
* elf/riscv.h (EF_RISCV_SOFT_FLOAT): Don't define.
unsigned long exclusions;
};
+/* Return true if MO is an instruction that requires 32-bit encoding. */
+
+static inline bfd_boolean
+mips_opcode_32bit_p (const struct mips_opcode *mo)
+{
+ return mo->mask >> 16 != 0;
+}
+
/* These are the characters which may appear in the args field of an
instruction. They appear in the order in which the fields appear
when the instruction is used. Commas and parentheses in the args
+2016-12-20 Maciej W. Rozycki <macro@imgtec.com>
+
+ * mips-dis.c (print_mips16_insn_arg): Always handle `extend' and
+ `insn' together, with `extend' as the high-order 16 bits.
+ (match_kind): New enum.
+ (print_insn_mips16): Rework for 32-bit instruction matching.
+ Do not dump EXTEND prefixes here.
+ * mips16-opc.c (mips16_opcodes): Move "extend" entry to the end.
+ Recode `match' and `mask' fields as 32-bit in absolute "jal" and
+ "jalx" entries.
+
2016-12-20 Maciej W. Rozycki <macro@imgtec.com>
* mips16-opc.c (mips16_opcodes): Set membership to I3 rather
}
if (operand->size == 26)
- /* In this case INSN is the first two bytes of the instruction
- and EXTEND is the second two bytes. */
- uval = ((insn & 0x1f) << 21) | ((insn & 0x3e0) << 11) | extend;
+ uval = ((extend & 0x1f) << 21) | ((extend & 0x3e0) << 11) | insn;
else
{
/* Calculate the full field value. */
- uval = mips_extract_operand (operand, insn);
+ uval = mips_extract_operand (operand, (extend << 16) | insn);
if (use_extend)
{
ext_operand = decode_mips16_operand (type, TRUE);
return FALSE;
}
+/* Whether none, a 32-bit or a 16-bit instruction match has been done. */
+
+enum match_kind
+{
+ MATCH_NONE,
+ MATCH_FULL,
+ MATCH_SHORT
+};
+
/* Disassemble mips16 instructions. */
static int
const fprintf_ftype infprintf = info->fprintf_func;
int status;
bfd_byte buffer[4];
- int length;
- int insn;
- bfd_boolean use_extend;
- int extend = 0;
const struct mips_opcode *op, *opend;
struct mips_print_arg_state state;
void *is = info->stream;
+ bfd_boolean have_second;
+ unsigned int second;
+ unsigned int first;
+ unsigned int full;
info->bytes_per_chunk = 2;
info->display_endian = info->endian;
return -1;
}
- length = 2;
-
if (info->endian == BFD_ENDIAN_BIG)
- insn = bfd_getb16 (buffer);
+ first = bfd_getb16 (buffer);
else
- insn = bfd_getl16 (buffer);
+ first = bfd_getl16 (buffer);
- /* Handle the extend opcode specially. */
- use_extend = FALSE;
- if ((insn & 0xf800) == 0xf000)
+ status = (*info->read_memory_func) (memaddr + 2, buffer, 2, info);
+ if (status == 0)
{
- use_extend = TRUE;
- extend = insn & 0x7ff;
-
- memaddr += 2;
-
- status = (*info->read_memory_func) (memaddr, buffer, 2, info);
- if (status != 0)
- {
- infprintf (is, "extend\t0x%x", (unsigned int) extend);
- (*info->memory_error_func) (status, memaddr, info);
- return -1;
- }
-
+ have_second = TRUE;
if (info->endian == BFD_ENDIAN_BIG)
- insn = bfd_getb16 (buffer);
+ second = bfd_getb16 (buffer);
else
- insn = bfd_getl16 (buffer);
-
- /* Check for an extend opcode followed by an extend opcode. */
- if ((insn & 0xf800) == 0xf000)
- {
- infprintf (is, "extend\t0x%x", (unsigned int) extend);
- info->insn_type = dis_noninsn;
- return length;
- }
-
- length += 2;
+ second = bfd_getl16 (buffer);
+ full = (first << 16) | second;
+ }
+ else
+ {
+ have_second = FALSE;
+ second = 0;
+ full = first;
}
/* FIXME: Should probably use a hash table on the major opcode here. */
opend = mips16_opcodes + bfd_mips16_num_opcodes;
for (op = mips16_opcodes; op < opend; op++)
{
- if (op->pinfo != INSN_MACRO
- && !(no_aliases && (op->pinfo2 & INSN2_ALIAS))
- && (insn & op->mask) == op->match)
- {
- const char *s;
-
- if (op->args[0] == 'a' || op->args[0] == 'i')
- {
- if (use_extend)
- {
- infprintf (is, "extend\t0x%x", (unsigned int) extend);
- info->insn_type = dis_noninsn;
- return length - 2;
- }
+ enum match_kind match;
- use_extend = FALSE;
-
- memaddr += 2;
+ if (op->pinfo == INSN_MACRO
+ || (no_aliases && (op->pinfo2 & INSN2_ALIAS)))
+ match = MATCH_NONE;
+ else if (mips_opcode_32bit_p (op))
+ {
+ if (have_second
+ && (full & op->mask) == op->match)
+ match = MATCH_FULL;
+ else
+ match = MATCH_NONE;
+ }
+ else if ((first & op->mask) == op->match)
+ {
+ match = MATCH_SHORT;
+ second = 0;
+ full = first;
+ }
+ else if ((first & 0xf800) == 0xf000
+ && have_second
+ && (second & op->mask) == op->match)
+ match = MATCH_FULL;
+ else
+ match = MATCH_NONE;
- status = (*info->read_memory_func) (memaddr, buffer, 2,
- info);
- if (status == 0)
- {
- use_extend = TRUE;
- if (info->endian == BFD_ENDIAN_BIG)
- extend = bfd_getb16 (buffer);
- else
- extend = bfd_getl16 (buffer);
- length += 2;
- }
- }
+ if (match != MATCH_NONE)
+ {
+ const char *s;
infprintf (is, "%s", op->name);
if (op->args[0] != '\0')
{
if (*s == ','
&& s[1] == 'w'
- && GET_OP (insn, RX) == GET_OP (insn, RY))
+ && GET_OP (full, RX) == GET_OP (full, RY))
{
/* Skip the register and the comma. */
++s;
}
if (*s == ','
&& s[1] == 'v'
- && GET_OP (insn, RZ) == GET_OP (insn, RX))
+ && GET_OP (full, RZ) == GET_OP (full, RX))
{
/* Skip the register and the comma. */
++s;
continue;
}
- print_mips16_insn_arg (info, &state, op, *s, memaddr, insn,
- use_extend, extend, s[1] == '(');
+ switch (match)
+ {
+ case MATCH_FULL:
+ print_mips16_insn_arg (info, &state, op, *s, memaddr + 2,
+ second, TRUE, first, s[1] == '(');
+ break;
+ case MATCH_SHORT:
+ print_mips16_insn_arg (info, &state, op, *s, memaddr,
+ first, FALSE, 0, s[1] == '(');
+ break;
+ case MATCH_NONE: /* Stop the compiler complaining. */
+ break;
+ }
}
/* Figure out branch instruction type and delay slot information. */
else if ((op->pinfo2 & INSN2_COND_BRANCH) != 0)
info->insn_type = dis_condbranch;
- return length;
+ return match == MATCH_FULL ? 4 : 2;
}
}
#undef GET_OP
- if (use_extend)
- infprintf (is, "0x%x ", extend | 0xf000);
- infprintf (is, "0x%x", insn);
+ infprintf (is, "0x%x", first);
info->insn_type = dis_noninsn;
- return length;
+ return 2;
}
/* Disassemble microMIPS instructions. */
{"exit", "L", 0xef09, 0xff1f, TRAP, 0, I1, 0, 0 },
{"entry", "", 0xe809, 0xffff, TRAP, 0, I1, 0, 0 },
{"entry", "l", 0xe809, 0xf81f, TRAP, 0, I1, 0, 0 },
-{"extend", "e", 0xf000, 0xf800, 0, 0, I1, 0, 0 },
{"jalr", "x", 0xe840, 0xf8ff, RD_1|WR_31|UBD, 0, I1, 0, 0 },
{"jalr", "R,x", 0xe840, 0xf8ff, RD_2|WR_31|UBD, 0, I1, 0, 0 },
{"jal", "x", 0xe840, 0xf8ff, RD_1|WR_31|UBD, 0, I1, 0, 0 },
{"jal", "R,x", 0xe840, 0xf8ff, RD_2|WR_31|UBD, 0, I1, 0, 0 },
-{"jal", "a", 0x1800, 0xfc00, WR_31|UBD, 0, I1, 0, 0 },
-{"jalx", "i", 0x1c00, 0xfc00, WR_31|UBD, 0, I1, 0, 0 },
+{"jal", "a", 0x18000000, 0xfc000000, WR_31|UBD, 0, I1, 0, 0 },
+{"jalx", "i", 0x1c000000, 0xfc000000, WR_31|UBD, 0, I1, 0, 0 },
{"jr", "x", 0xe800, 0xf8ff, RD_1|UBD, 0, I1, 0, 0 },
{"jr", "R", 0xe820, 0xffff, UBD, RD_31, I1, 0, 0 },
{"j", "x", 0xe800, 0xf8ff, RD_1|UBD, 0, I1, 0, 0 },
{"zeb", "x", 0xe811, 0xf8ff, MOD_1, 0, I32, 0, 0 },
{"zeh", "x", 0xe831, 0xf8ff, MOD_1, 0, I32, 0, 0 },
{"zew", "x", 0xe851, 0xf8ff, MOD_1, 0, I64, 0, 0 },
+ /* Place EXTEND last so that it catches any prefix that didn't match
+ anything. */
+{"extend", "e", 0xf000, 0xf800, 0, 0, I1, 0, 0 },
};
const int bfd_mips16_num_opcodes =