PowerPC add initial -mfuture instruction support

This patch adds initial 64-bit insn assembler/disassembler support.
The only instruction added is "pnop" along with the automatic aligning
of prefix instruction so they do not cross 64-byte boundaries.

include/
	* dis-asm.h (WIDE_OUTPUT): Define.
	* opcode/ppc.h (prefix_opcodes, prefix_num_opcodes): Declare.
	(PPC_OPCODE_POWERXX, PPC_GET_PREFIX, PPC_GET_SUFFIX),
	(PPC_PREFIX_P, PPC_PREFIX_SEG): Define.
opcodes/
	* ppc-dis.c (ppc_opts): Add "future" entry.
	(PREFIX_OPCD_SEGS): Define.
	(prefix_opcd_indices): New array.
	(disassemble_init_powerpc): Initialize prefix_opcd_indices.
	(lookup_prefix): New function.
	(print_insn_powerpc): Handle 64-bit prefix instructions.
	* ppc-opc.c (PREFIX_OP, PREFIX_FORM, SUFFIX_MASK, PREFIX_MASK),
	(PMRR, POWERXX): Define.
	(prefix_opcodes): New instruction table.
	(prefix_num_opcodes): New constant.
binutils/
	* objdump.c (disassemble_bytes): Set WIDE_OUTPUT in flags.
gas/
	* config/tc-ppc.c (ppc_setup_opcodes): Handle prefix_opcodes.
	(struct insn_label_list): New.
	(insn_labels, free_insn_labels): New variables.
	(ppc_record_label, ppc_clear_labels, ppc_start_line_hook): New funcs.
	(ppc_frob_label, ppc_new_dot_label): Move functions earlier in file
	and call ppc_record_label.
	(md_assemble): Handle 64-bit prefix instructions.  Align labels
	that are on the same line as a prefix instruction.
	* config/tc-ppc.h (tc_frob_label, ppc_frob_label): Move to
	later in the file.
	(md_start_line_hook): Define.
	(ppc_start_line_hook): Declare.
	* testsuite/gas/ppc/prefix-align.d,
	* testsuite/gas/ppc/prefix-align.s: New test.
	* testsuite/gas/ppc/ppc.exp: Run new test.
This commit is contained in:
Peter Bergner 2018-05-15 16:48:14 -05:00 committed by Alan Modra
parent fcb36d7462
commit dd7efa7915
14 changed files with 412 additions and 42 deletions

View file

@ -1,3 +1,7 @@
2019-05-24 Alan Modra <amodra@gmail.com>
* objdump.c (disassemble_bytes): Set WIDE_OUTPUT in flags.
2019-05-23 Jose E. Marchesi <jose.marchesi@oracle.com> 2019-05-23 Jose E. Marchesi <jose.marchesi@oracle.com>
* MAINTAINERS: Add myself as the maintainer for BPF. * MAINTAINERS: Add myself as the maintainer for BPF.

View file

@ -1946,7 +1946,8 @@ disassemble_bytes (struct disassemble_info * inf,
inf->stream = &sfile; inf->stream = &sfile;
inf->bytes_per_line = 0; inf->bytes_per_line = 0;
inf->bytes_per_chunk = 0; inf->bytes_per_chunk = 0;
inf->flags = disassemble_all ? DISASSEMBLE_DATA : 0; inf->flags = ((disassemble_all ? DISASSEMBLE_DATA : 0)
| (wide_output ? WIDE_OUTPUT : 0));
if (machine) if (machine)
inf->flags |= USER_SPECIFIED_MACHINE_TYPE; inf->flags |= USER_SPECIFIED_MACHINE_TYPE;

View file

@ -1,3 +1,22 @@
2019-05-24 Peter Bergner <bergner@linux.ibm.com>
Alan Modra <amodra@gmail.com>
* config/tc-ppc.c (ppc_setup_opcodes): Handle prefix_opcodes.
(struct insn_label_list): New.
(insn_labels, free_insn_labels): New variables.
(ppc_record_label, ppc_clear_labels, ppc_start_line_hook): New funcs.
(ppc_frob_label, ppc_new_dot_label): Move functions earlier in file
and call ppc_record_label.
(md_assemble): Handle 64-bit prefix instructions. Align labels
that are on the same line as a prefix instruction.
* config/tc-ppc.h (tc_frob_label, ppc_frob_label): Move to
later in the file.
(md_start_line_hook): Define.
(ppc_start_line_hook): Declare.
* testsuite/gas/ppc/prefix-align.d,
* testsuite/gas/ppc/prefix-align.s: New test.
* testsuite/gas/ppc/ppc.exp: Run new test.
2019-05-23 Jose E. Marchesi <jose.marchesi@oracle.com> 2019-05-23 Jose E. Marchesi <jose.marchesi@oracle.com>
* configure.ac: Handle bpf-*-* targets. * configure.ac: Handle bpf-*-* targets.

View file

@ -1673,6 +1673,50 @@ ppc_setup_opcodes (void)
for (op = powerpc_opcodes; op < op_end; op++) for (op = powerpc_opcodes; op < op_end; op++)
hash_insert (ppc_hash, op->name, (void *) op); hash_insert (ppc_hash, op->name, (void *) op);
op_end = prefix_opcodes + prefix_num_opcodes;
for (op = prefix_opcodes; op < op_end; op++)
{
if (ENABLE_CHECKING)
{
unsigned int new_opcode = PPC_PREFIX_SEG (op[0].opcode);
#ifdef PRINT_OPCODE_TABLE
printf ("%-14s\t#%04u\tmajor op/2: 0x%x\top: 0x%llx\tmask: 0x%llx\tflags: 0x%llx\n",
op->name, (unsigned int) (op - prefix_opcodes),
new_opcode, (unsigned long long) op->opcode,
(unsigned long long) op->mask, (unsigned long long) op->flags);
#endif
/* The major opcodes had better be sorted. Code in the disassembler
assumes the insns are sorted according to major opcode. */
if (op != prefix_opcodes
&& new_opcode < PPC_PREFIX_SEG (op[-1].opcode))
{
as_bad (_("major opcode is not sorted for %s"), op->name);
bad_insn = TRUE;
}
bad_insn |= insn_validate (op);
}
if ((ppc_cpu & op->flags) != 0
&& !(ppc_cpu & op->deprecated))
{
const char *retval;
retval = hash_insert (ppc_hash, op->name, (void *) op);
if (retval != NULL)
{
as_bad (_("duplicate instruction %s"),
op->name);
bad_insn = TRUE;
}
}
}
if ((ppc_cpu & PPC_OPCODE_ANY) != 0)
for (op = prefix_opcodes; op < op_end; op++)
hash_insert (ppc_hash, op->name, (void *) op);
op_end = vle_opcodes + vle_num_opcodes; op_end = vle_opcodes + vle_num_opcodes;
for (op = vle_opcodes; op < op_end; op++) for (op = vle_opcodes; op < op_end; op++)
{ {
@ -2740,6 +2784,90 @@ ppc_apuinfo_section_add (unsigned int apu, unsigned int version)
#undef APUID #undef APUID
#endif #endif
/* Various frobbings of labels and their addresses. */
/* Symbols labelling the current insn. */
struct insn_label_list
{
struct insn_label_list *next;
symbolS *label;
};
static struct insn_label_list *insn_labels;
static struct insn_label_list *free_insn_labels;
static void
ppc_record_label (symbolS *sym)
{
struct insn_label_list *l;
if (free_insn_labels == NULL)
l = XNEW (struct insn_label_list);
else
{
l = free_insn_labels;
free_insn_labels = l->next;
}
l->label = sym;
l->next = insn_labels;
insn_labels = l;
}
static void
ppc_clear_labels (void)
{
while (insn_labels != NULL)
{
struct insn_label_list *l = insn_labels;
insn_labels = l->next;
l->next = free_insn_labels;
free_insn_labels = l;
}
}
void
ppc_start_line_hook (void)
{
ppc_clear_labels ();
}
void
ppc_new_dot_label (symbolS *sym)
{
ppc_record_label (sym);
#ifdef OBJ_XCOFF
/* Anchor this label to the current csect for relocations. */
symbol_get_tc (sym)->within = ppc_current_csect;
#endif
}
void
ppc_frob_label (symbolS *sym)
{
ppc_record_label (sym);
#ifdef OBJ_XCOFF
/* Set the class of a label based on where it is defined. This handles
symbols without suffixes. Also, move the symbol so that it follows
the csect symbol. */
if (ppc_current_csect != (symbolS *) NULL)
{
if (symbol_get_tc (sym)->symbol_class == -1)
symbol_get_tc (sym)->symbol_class = symbol_get_tc (ppc_current_csect)->symbol_class;
symbol_remove (sym, &symbol_rootP, &symbol_lastP);
symbol_append (sym, symbol_get_tc (ppc_current_csect)->within,
&symbol_rootP, &symbol_lastP);
symbol_get_tc (ppc_current_csect)->within = sym;
symbol_get_tc (sym)->within = ppc_current_csect;
}
#endif
#ifdef OBJ_ELF
dwarf2_emit_label (sym);
#endif
}
/* We need to keep a list of fixups. We can't simply generate them as /* We need to keep a list of fixups. We can't simply generate them as
we go, because that would require us to first create the frag, and we go, because that would require us to first create the frag, and
@ -3074,6 +3202,7 @@ md_assemble (char *str)
else else
ppc_macro (s, macro); ppc_macro (s, macro);
ppc_clear_labels ();
return; return;
} }
@ -3828,14 +3957,50 @@ md_assemble (char *str)
if ((frag_now_fix () & addr_mask) != 0) if ((frag_now_fix () & addr_mask) != 0)
as_bad (_("instruction address is not a multiple of %d"), addr_mask + 1); as_bad (_("instruction address is not a multiple of %d"), addr_mask + 1);
/* Differentiate between two and four byte insns. */ /* Differentiate between two, four, and eight byte insns. */
insn_length = 4; insn_length = 4;
if ((ppc_cpu & PPC_OPCODE_VLE) != 0 && PPC_OP_SE_VLE (insn)) if ((ppc_cpu & PPC_OPCODE_VLE) != 0 && PPC_OP_SE_VLE (insn))
insn_length = 2; insn_length = 2;
else if ((opcode->flags & PPC_OPCODE_POWERXX) != 0
&& PPC_PREFIX_P (insn))
{
struct insn_label_list *l;
insn_length = 8;
/* 8-byte prefix instructions are not allowed to cross 64-byte
boundaries. */
frag_align_code (6, 4);
record_alignment (now_seg, 6);
/* Update "dot" in any expressions used by this instruction, and
a label attached to the instruction. By "attached" we mean
on the same source line as the instruction and without any
intervening semicolons. */
dot_value = frag_now_fix ();
dot_frag = frag_now;
for (l = insn_labels; l != NULL; l = l->next)
{
symbol_set_frag (l->label, dot_frag);
S_SET_VALUE (l->label, dot_value);
}
}
ppc_clear_labels ();
f = frag_more (insn_length); f = frag_more (insn_length);
frag_now->insn_addr = addr_mask; frag_now->insn_addr = addr_mask;
md_number_to_chars (f, insn, insn_length);
/* The prefix part of an 8-byte instruction always occupies the lower
addressed word in a doubleword, regardless of endianness. */
if (!target_big_endian && insn_length == 8)
{
md_number_to_chars (f, PPC_GET_PREFIX (insn), 4);
md_number_to_chars (f + 4, PPC_GET_SUFFIX (insn), 4);
}
else
md_number_to_chars (f, insn, insn_length);
last_insn = insn; last_insn = insn;
last_seg = now_seg; last_seg = now_seg;
last_subseg = now_subseg; last_subseg = now_subseg;
@ -6118,30 +6283,6 @@ ppc_symbol_new_hook (symbolS *sym)
as_bad (_("unrecognized symbol suffix")); as_bad (_("unrecognized symbol suffix"));
} }
/* Set the class of a label based on where it is defined. This
handles symbols without suffixes. Also, move the symbol so that it
follows the csect symbol. */
void
ppc_frob_label (symbolS *sym)
{
if (ppc_current_csect != (symbolS *) NULL)
{
if (symbol_get_tc (sym)->symbol_class == -1)
symbol_get_tc (sym)->symbol_class = symbol_get_tc (ppc_current_csect)->symbol_class;
symbol_remove (sym, &symbol_rootP, &symbol_lastP);
symbol_append (sym, symbol_get_tc (ppc_current_csect)->within,
&symbol_rootP, &symbol_lastP);
symbol_get_tc (ppc_current_csect)->within = sym;
symbol_get_tc (sym)->within = ppc_current_csect;
}
#ifdef OBJ_ELF
dwarf2_emit_label (sym);
#endif
}
/* This variable is set by ppc_frob_symbol if any absolute symbols are /* This variable is set by ppc_frob_symbol if any absolute symbols are
seen. It tells ppc_adjust_symtab whether it needs to look through seen. It tells ppc_adjust_symtab whether it needs to look through
the symbols. */ the symbols. */
@ -6673,14 +6814,6 @@ ppc_force_relocation (fixS *fix)
return generic_force_reloc (fix); return generic_force_reloc (fix);
} }
void
ppc_new_dot_label (symbolS *sym)
{
/* Anchor this label to the current csect for relocations. */
symbol_get_tc (sym)->within = ppc_current_csect;
}
#endif /* OBJ_XCOFF */ #endif /* OBJ_XCOFF */
#ifdef OBJ_ELF #ifdef OBJ_ELF

View file

@ -171,10 +171,6 @@ extern char *ppc_canonicalize_symbol_name (char *);
#define tc_symbol_new_hook(sym) ppc_symbol_new_hook (sym) #define tc_symbol_new_hook(sym) ppc_symbol_new_hook (sym)
extern void ppc_symbol_new_hook (symbolS *); extern void ppc_symbol_new_hook (symbolS *);
/* Set the symbol class of a label based on the csect. */
#define tc_frob_label(sym) ppc_frob_label (sym)
extern void ppc_frob_label (symbolS *);
/* TOC relocs requires special handling. */ /* TOC relocs requires special handling. */
#define tc_fix_adjustable(FIX) ppc_fix_adjustable (FIX) #define tc_fix_adjustable(FIX) ppc_fix_adjustable (FIX)
extern int ppc_fix_adjustable (struct fix *); extern int ppc_fix_adjustable (struct fix *);
@ -206,11 +202,11 @@ do { \
extern void ppc_xcoff_end (void); extern void ppc_xcoff_end (void);
#define md_end ppc_xcoff_end #define md_end ppc_xcoff_end
#endif /* OBJ_XCOFF */
#define tc_new_dot_label(sym) ppc_new_dot_label (sym) #define tc_new_dot_label(sym) ppc_new_dot_label (sym)
extern void ppc_new_dot_label (symbolS *); extern void ppc_new_dot_label (symbolS *);
#endif /* OBJ_XCOFF */
extern const char ppc_symbol_chars[]; extern const char ppc_symbol_chars[];
#define tc_symbol_chars ppc_symbol_chars #define tc_symbol_chars ppc_symbol_chars
@ -282,6 +278,14 @@ extern int ppc_force_relocation (struct fix *);
#define TC_VALIDATE_FIX_SUB(FIX, SEG) 0 #define TC_VALIDATE_FIX_SUB(FIX, SEG) 0
/* Various frobbings of labels and their addresses. */
#define md_start_line_hook() ppc_start_line_hook ()
extern void ppc_start_line_hook (void);
/* Set the symbol class of a label based on the csect. */
#define tc_frob_label(sym) ppc_frob_label (sym)
extern void ppc_frob_label (symbolS *);
/* call md_pcrel_from_section, not md_pcrel_from */ /* call md_pcrel_from_section, not md_pcrel_from */
#define MD_PCREL_FROM_SECTION(FIX, SEC) md_pcrel_from_section(FIX, SEC) #define MD_PCREL_FROM_SECTION(FIX, SEC) md_pcrel_from_section(FIX, SEC)
extern long md_pcrel_from_section (struct fix *, segT); extern long md_pcrel_from_section (struct fix *, segT);

View file

@ -114,3 +114,4 @@ run_dump_test "vsx2"
run_dump_test "vsx3" run_dump_test "vsx3"
run_dump_test "htm" run_dump_test "htm"
run_dump_test "titan" run_dump_test "titan"
run_dump_test "prefix-align"

View file

@ -0,0 +1,30 @@
#as: -mfuture
#objdump: -dr -Mfuture
#name: POWERXX alignment of labels test
.*
Disassembly of section \.text:
0+00 <_start>:
0: (48 00 00 3c|3c 00 00 48) b 3c <_start\+0x3c>
4: (48 00 00 3c|3c 00 00 48) b 40 <_start\+0x40>
8: (48 00 00 40|40 00 00 48) b 48 <_start\+0x48>
c: (7f e0 00 08|08 00 e0 7f) trap
10: (7f e0 00 08|08 00 e0 7f) trap
14: (7f e0 00 08|08 00 e0 7f) trap
18: (7f e0 00 08|08 00 e0 7f) trap
1c: (7f e0 00 08|08 00 e0 7f) trap
20: (7f e0 00 08|08 00 e0 7f) trap
24: (7f e0 00 08|08 00 e0 7f) trap
28: (7f e0 00 08|08 00 e0 7f) trap
2c: (7f e0 00 08|08 00 e0 7f) trap
30: (7f e0 00 08|08 00 e0 7f) trap
34: (7f e0 00 08|08 00 e0 7f) trap
38: (7f e0 00 08|08 00 e0 7f) trap
3c: (60 00 00 00|00 00 00 60) nop
40: (07 00 00 00|00 00 00 07) pnop
44: (00 00 00 00|00 00 00 00)
48: (4e 80 00 20|20 00 80 4e) blr
#pass

View file

@ -0,0 +1,21 @@
.text
_start:
b 1f;
b 2f;
b 3f;
trap
trap
trap
trap
trap
trap
trap
trap
trap
trap
trap
trap
1:
2: pnop
3:
blr

View file

@ -1,3 +1,11 @@
2019-05-24 Peter Bergner <bergner@linux.ibm.com>
Alan Modra <amodra@gmail.com>
* dis-asm.h (WIDE_OUTPUT): Define.
* opcode/ppc.h (prefix_opcodes, prefix_num_opcodes): Declare.
(PPC_OPCODE_POWERXX, PPC_GET_PREFIX, PPC_GET_SUFFIX),
(PPC_PREFIX_P, PPC_PREFIX_SEG): Define.
2019-05-23 Jose E. Marchesi <jose.marchesi@oracle.com> 2019-05-23 Jose E. Marchesi <jose.marchesi@oracle.com>
* elf/bpf.h: New file. * elf/bpf.h: New file.

View file

@ -116,6 +116,8 @@ typedef struct disassemble_info
/* Set if the user has specifically set the machine type encoded in the /* Set if the user has specifically set the machine type encoded in the
mach field of this structure. */ mach field of this structure. */
#define USER_SPECIFIED_MACHINE_TYPE (1 << 29) #define USER_SPECIFIED_MACHINE_TYPE (1 << 29)
/* Set if the user has requested wide output. */
#define WIDE_OUTPUT (1 << 28)
/* Use internally by the target specific disassembly code. */ /* Use internally by the target specific disassembly code. */
void *private_data; void *private_data;

View file

@ -68,6 +68,8 @@ struct powerpc_opcode
instructions. */ instructions. */
extern const struct powerpc_opcode powerpc_opcodes[]; extern const struct powerpc_opcode powerpc_opcodes[];
extern const unsigned int powerpc_num_opcodes; extern const unsigned int powerpc_num_opcodes;
extern const struct powerpc_opcode prefix_opcodes[];
extern const unsigned int prefix_num_opcodes;
extern const struct powerpc_opcode vle_opcodes[]; extern const struct powerpc_opcode vle_opcodes[];
extern const unsigned int vle_num_opcodes; extern const unsigned int vle_num_opcodes;
extern const struct powerpc_opcode spe2_opcodes[]; extern const struct powerpc_opcode spe2_opcodes[];
@ -226,6 +228,9 @@ extern const unsigned int spe2_num_opcodes;
/* Opcode is supported by EFS2. */ /* Opcode is supported by EFS2. */
#define PPC_OPCODE_EFS2 0x200000000000ull #define PPC_OPCODE_EFS2 0x200000000000ull
/* Opcode is only supported by powerxx architecture. */
#define PPC_OPCODE_POWERXX 0x400000000000ull
/* A macro to extract the major opcode from an instruction. */ /* A macro to extract the major opcode from an instruction. */
#define PPC_OP(i) (((i) >> 26) & 0x3f) #define PPC_OP(i) (((i) >> 26) & 0x3f)
@ -243,6 +248,19 @@ extern const unsigned int spe2_num_opcodes;
/* A macro to convert a SPE2 extended opcode to a SPE2 xopcode segment. */ /* A macro to convert a SPE2 extended opcode to a SPE2 xopcode segment. */
#define SPE2_XOP_TO_SEG(i) ((i) >> 7) #define SPE2_XOP_TO_SEG(i) ((i) >> 7)
/* A macro to extract the prefix word from an 8-byte PREFIX instruction. */
#define PPC_GET_PREFIX(i) (((i) >> 32) & ((1LL << 32) - 1))
/* A macro to extract the suffix word from an 8-byte PREFIX instruction. */
#define PPC_GET_SUFFIX(i) ((i) & ((1LL << 32) - 1))
/* A macro to determine whether insn I is an 8-byte prefix instruction. */
#define PPC_PREFIX_P(i) (PPC_OP (PPC_GET_PREFIX (i)) == 0x1)
/* A macro used to hash 8-byte PREFIX instructions. */
#define PPC_PREFIX_SEG(i) (PPC_OP (i) >> 1)
/* The operands table is an array of struct powerpc_operand. */ /* The operands table is an array of struct powerpc_operand. */

View file

@ -1,3 +1,17 @@
2019-05-24 Peter Bergner <bergner@linux.ibm.com>
Alan Modra <amodra@gmail.com>
* ppc-dis.c (ppc_opts): Add "future" entry.
(PREFIX_OPCD_SEGS): Define.
(prefix_opcd_indices): New array.
(disassemble_init_powerpc): Initialize prefix_opcd_indices.
(lookup_prefix): New function.
(print_insn_powerpc): Handle 64-bit prefix instructions.
* ppc-opc.c (PREFIX_OP, PREFIX_FORM, SUFFIX_MASK, PREFIX_MASK),
(PMRR, POWERXX): Define.
(prefix_opcodes): New instruction table.
(prefix_num_opcodes): New constant.
2019-05-23 Jose E. Marchesi <jose.marchesi@oracle.com> 2019-05-23 Jose E. Marchesi <jose.marchesi@oracle.com>
* configure.ac (SHARED_DEPENDENCIES): Add case for bfd_bpf_arch. * configure.ac (SHARED_DEPENDENCIES): Add case for bfd_bpf_arch.

View file

@ -185,6 +185,11 @@ struct ppc_mopt ppc_opts[] = {
| PPC_OPCODE_POWER7 | PPC_OPCODE_POWER8 | PPC_OPCODE_POWER9 | PPC_OPCODE_POWER7 | PPC_OPCODE_POWER8 | PPC_OPCODE_POWER9
| PPC_OPCODE_ALTIVEC | PPC_OPCODE_VSX), | PPC_OPCODE_ALTIVEC | PPC_OPCODE_VSX),
0 }, 0 },
{ "future", (PPC_OPCODE_PPC | PPC_OPCODE_ISEL | PPC_OPCODE_64
| PPC_OPCODE_POWER4 | PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6
| PPC_OPCODE_POWER7 | PPC_OPCODE_POWER8 | PPC_OPCODE_POWER9
| PPC_OPCODE_POWERXX | PPC_OPCODE_ALTIVEC | PPC_OPCODE_VSX),
0 },
{ "ppc", PPC_OPCODE_PPC, { "ppc", PPC_OPCODE_PPC,
0 }, 0 },
{ "ppc32", PPC_OPCODE_PPC, { "ppc32", PPC_OPCODE_PPC,
@ -376,6 +381,8 @@ powerpc_init_dialect (struct disassemble_info *info)
#define PPC_OPCD_SEGS (1 + PPC_OP (-1)) #define PPC_OPCD_SEGS (1 + PPC_OP (-1))
static unsigned short powerpc_opcd_indices[PPC_OPCD_SEGS + 1]; static unsigned short powerpc_opcd_indices[PPC_OPCD_SEGS + 1];
#define PREFIX_OPCD_SEGS (1 + PPC_PREFIX_SEG (-1))
static unsigned short prefix_opcd_indices[PPC_OPCD_SEGS+1];
#define VLE_OPCD_SEGS (1 + VLE_OP_TO_SEG (VLE_OP (-1, 0xffff))) #define VLE_OPCD_SEGS (1 + VLE_OP_TO_SEG (VLE_OP (-1, 0xffff)))
static unsigned short vle_opcd_indices[VLE_OPCD_SEGS + 1]; static unsigned short vle_opcd_indices[VLE_OPCD_SEGS + 1];
#define SPE2_OPCD_SEGS (1 + SPE2_XOP_TO_SEG (SPE2_XOP (-1))) #define SPE2_OPCD_SEGS (1 + SPE2_XOP_TO_SEG (SPE2_XOP (-1)))
@ -400,6 +407,15 @@ disassemble_init_powerpc (struct disassemble_info *info)
break; break;
} }
/* 64-bit prefix opcodes */
for (seg = 0, idx = 0; seg <= PREFIX_OPCD_SEGS; seg++)
{
prefix_opcd_indices[seg] = idx;
for (; idx < prefix_num_opcodes; idx++)
if (seg < PPC_PREFIX_SEG (prefix_opcodes[idx].opcode))
break;
}
/* VLE opcodes */ /* VLE opcodes */
for (seg = 0, idx = 0; seg <= VLE_OPCD_SEGS; seg++) for (seg = 0, idx = 0; seg <= VLE_OPCD_SEGS; seg++)
{ {
@ -556,6 +572,57 @@ lookup_powerpc (uint64_t insn, ppc_cpu_t dialect)
return last; return last;
} }
/* Find a match for INSN in the PREFIX opcode table. */
static const struct powerpc_opcode *
lookup_prefix (uint64_t insn, ppc_cpu_t dialect)
{
const struct powerpc_opcode *opcode, *opcode_end, *last;
unsigned long seg;
/* Get the opcode segment of the instruction. */
seg = PPC_PREFIX_SEG (insn);
/* Find the first match in the opcode table for this major opcode. */
opcode_end = prefix_opcodes + prefix_opcd_indices[seg + 1];
last = NULL;
for (opcode = prefix_opcodes + prefix_opcd_indices[seg];
opcode < opcode_end;
++opcode)
{
const unsigned char *opindex;
const struct powerpc_operand *operand;
int invalid;
if ((insn & opcode->mask) != opcode->opcode
|| ((dialect & PPC_OPCODE_ANY) == 0
&& ((opcode->flags & dialect) == 0
|| (opcode->deprecated & dialect) != 0)))
continue;
/* Check validity of operands. */
invalid = 0;
for (opindex = opcode->operands; *opindex != 0; opindex++)
{
operand = powerpc_operands + *opindex;
if (operand->extract)
(*operand->extract) (insn, dialect, &invalid);
}
if (invalid)
continue;
if ((dialect & PPC_OPCODE_RAW) == 0)
return opcode;
/* The raw machine insn is one that is not a specialization. */
if (last == NULL
|| (last->mask & ~opcode->mask) != 0)
last = opcode;
}
return last;
}
/* Find a match for INSN in the VLE opcode table. */ /* Find a match for INSN in the VLE opcode table. */
static const struct powerpc_opcode * static const struct powerpc_opcode *
@ -699,7 +766,31 @@ print_insn_powerpc (bfd_vma memaddr,
/* Get the major opcode of the insn. */ /* Get the major opcode of the insn. */
opcode = NULL; opcode = NULL;
if ((dialect & PPC_OPCODE_VLE) != 0) if ((dialect & PPC_OPCODE_POWERXX) != 0
&& PPC_OP (insn) == 0x1)
{
uint64_t temp_insn, suffix;
status = (*info->read_memory_func) (memaddr + 4, buffer, 4, info);
if (status == 0)
{
if (bigendian)
suffix = bfd_getb32 (buffer);
else
suffix = bfd_getl32 (buffer);
temp_insn = (insn << 32) | suffix;
opcode = lookup_prefix (temp_insn, dialect & ~PPC_OPCODE_ANY);
if (opcode == NULL && (dialect & PPC_OPCODE_ANY) != 0)
opcode = lookup_prefix (temp_insn, dialect);
if (opcode != NULL)
{
insn = temp_insn;
insn_length = 8;
if ((info->flags & WIDE_OUTPUT) != 0)
info->bytes_per_line = 8;
}
}
}
if (opcode == NULL && (dialect & PPC_OPCODE_VLE) != 0)
{ {
opcode = lookup_vle (insn); opcode = lookup_vle (insn);
if (opcode != NULL && PPC_OP_SE_VLE (opcode->mask)) if (opcode != NULL && PPC_OP_SE_VLE (opcode->mask))

View file

@ -2721,6 +2721,18 @@ const unsigned int num_powerpc_operands = (sizeof (powerpc_operands)
#define OP(x) ((((uint64_t)(x)) & 0x3f) << 26) #define OP(x) ((((uint64_t)(x)) & 0x3f) << 26)
#define OP_MASK OP (0x3f) #define OP_MASK OP (0x3f)
/* The prefix opcode. */
#define PREFIX_OP (1ULL << 58)
/* The 2-bit prefix form. */
#define PREFIX_FORM(x) ((x & 3ULL) << 56)
#define SUFFIX_MASK ((1ULL << 32) - 1)
#define PREFIX_MASK (SUFFIX_MASK << 32)
/* Prefix insn, modified register to register form MRR. */
#define PMRR (PREFIX_OP | PREFIX_FORM (3))
/* The main opcode combined with a trap code in the TO field of a D /* The main opcode combined with a trap code in the TO field of a D
form instruction. Used for extended mnemonics for the trap form instruction. Used for extended mnemonics for the trap
instructions. */ instructions. */
@ -3547,6 +3559,7 @@ const unsigned int num_powerpc_operands = (sizeof (powerpc_operands)
#define POWER7 PPC_OPCODE_POWER7 #define POWER7 PPC_OPCODE_POWER7
#define POWER8 PPC_OPCODE_POWER8 #define POWER8 PPC_OPCODE_POWER8
#define POWER9 PPC_OPCODE_POWER9 #define POWER9 PPC_OPCODE_POWER9
#define POWERXX PPC_OPCODE_POWERXX
#define CELL PPC_OPCODE_CELL #define CELL PPC_OPCODE_CELL
#define PPC64 PPC_OPCODE_64 | PPC_OPCODE_64_BRIDGE #define PPC64 PPC_OPCODE_64 | PPC_OPCODE_64_BRIDGE
#define NON32 (PPC_OPCODE_64 | PPC_OPCODE_POWER4 \ #define NON32 (PPC_OPCODE_64 | PPC_OPCODE_POWER4 \
@ -7796,6 +7809,17 @@ const struct powerpc_opcode powerpc_opcodes[] = {
const unsigned int powerpc_num_opcodes = const unsigned int powerpc_num_opcodes =
sizeof (powerpc_opcodes) / sizeof (powerpc_opcodes[0]); sizeof (powerpc_opcodes) / sizeof (powerpc_opcodes[0]);
/* The opcode table for 8-byte prefix instructions.
The format of this opcode table is the same as the main opcode table. */
const struct powerpc_opcode prefix_opcodes[] = {
{"pnop", PMRR, PREFIX_MASK, POWERXX, 0, {0}},
};
const unsigned int prefix_num_opcodes =
sizeof (prefix_opcodes) / sizeof (prefix_opcodes[0]);
/* The VLE opcode table. /* The VLE opcode table.
The format of this opcode table is the same as the main opcode table. */ The format of this opcode table is the same as the main opcode table. */