Commit 5b161fc3 authored by Doug Gilbert's avatar Doug Gilbert Committed by Patrick Williams

PowerPC PPE42 modifications

parent 237df3fa
......@@ -3183,6 +3183,7 @@ instruction. */
BFD_RELOC_PPC_EMB_RELST_HA,
BFD_RELOC_PPC_EMB_BIT_FLD,
BFD_RELOC_PPC_EMB_RELSDA,
BFD_RELOC_PPC_PPE_REL10,
BFD_RELOC_PPC_VLE_REL8,
BFD_RELOC_PPC_VLE_REL15,
BFD_RELOC_PPC_VLE_REL24,
......
......@@ -1402,6 +1402,22 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
0xffff, /* dst_mask */
FALSE), /* pcrel_offset */
/* A relative 12 bit branch. */
HOWTO (R_PPC_PPE_REL10, /* type */
1, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
10, /* bitsize */
TRUE, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_PPE_REL10", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0x7fe, /* dst_mask */
TRUE), /* pcrel_offset */
/* A relative 8 bit branch. */
HOWTO (R_PPC_VLE_REL8, /* type */
1, /* rightshift */
......@@ -1958,6 +1974,7 @@ ppc_elf_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
case BFD_RELOC_PPC_EMB_RELST_HA: r = R_PPC_EMB_RELST_HA; break;
case BFD_RELOC_PPC_EMB_BIT_FLD: r = R_PPC_EMB_BIT_FLD; break;
case BFD_RELOC_PPC_EMB_RELSDA: r = R_PPC_EMB_RELSDA; break;
case BFD_RELOC_PPC_PPE_REL10: r = R_PPC_PPE_REL10; break;
case BFD_RELOC_PPC_VLE_REL8: r = R_PPC_VLE_REL8; break;
case BFD_RELOC_PPC_VLE_REL15: r = R_PPC_VLE_REL15; break;
case BFD_RELOC_PPC_VLE_REL24: r = R_PPC_VLE_REL24; break;
......@@ -4121,6 +4138,7 @@ ppc_elf_check_relocs (bfd *abfd,
}
break;
case R_PPC_PPE_REL10:
case R_PPC_VLE_REL8:
case R_PPC_VLE_REL15:
case R_PPC_VLE_REL24:
......@@ -8236,6 +8254,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
case R_PPC_UADDR16:
goto dodyn;
case R_PPC_PPE_REL10:
case R_PPC_VLE_REL8:
case R_PPC_VLE_REL15:
case R_PPC_VLE_REL24:
......
......@@ -1359,6 +1359,7 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
"BFD_RELOC_PPC_EMB_RELST_HA",
"BFD_RELOC_PPC_EMB_BIT_FLD",
"BFD_RELOC_PPC_EMB_RELSDA",
"BFD_RELOC_PPC_PPE_REL10",
"BFD_RELOC_PPC_VLE_REL8",
"BFD_RELOC_PPC_VLE_REL15",
"BFD_RELOC_PPC_VLE_REL24",
......
......@@ -2815,6 +2815,8 @@ ENUMX
BFD_RELOC_PPC_EMB_BIT_FLD
ENUMX
BFD_RELOC_PPC_EMB_RELSDA
ENUMX
BFD_RELOC_PPC_PPE_REL10
ENUMX
BFD_RELOC_PPC_VLE_REL8
ENUMX
......
......@@ -141,7 +141,7 @@ host_libs="intl libiberty opcodes bfd readline tcl tk itcl libgui zlib libbacktr
# binutils, gas and ld appear in that order because it makes sense to run
# "make check" in that particular order.
# If --enable-gold is used, "gold" may replace "ld".
host_tools="texinfo flex bison binutils gas ld fixincludes gcc cgen sid sim gdb gprof etc expect dejagnu m4 utils guile fastjar gnattools"
host_tools="flex bison binutils gas ld fixincludes gcc cgen sid sim gdb gprof etc expect dejagnu m4 utils guile fastjar gnattools"
# libgcj represents the runtime libraries only used by gcj.
libgcj="target-libffi \
......
......@@ -177,6 +177,8 @@ enum
R_PPC64_DTPREL16_HIGHA = 115,
R_PPC_EMB_RELSDA = 116,
R_PPC_PPE_REL10 = 200,
R_PPC_VLE_REL8 = 216,
R_PPC_VLE_REL15 = 217,
R_PPC_VLE_REL24 = 218,
......@@ -204,6 +206,7 @@ enum
R_POWERPC_GNU_VTINHERIT = 253,
R_POWERPC_GNU_VTENTRY = 254,
R_PPC_TOC16 = 255,
};
// e_flags values defined for powerpc
......
......@@ -364,6 +364,36 @@ static const struct pd_reg pre_defined_registers[] =
{ "ctr", 9 },
{ "d.0", 0 }, /* Double Word Regs for PPE */
{ "d.1", 1 },
{ "d.2", 2 },
{ "d.28", 28 },
{ "d.29", 29 },
{ "d.3", 3 },
{ "d.30", 30 },
{ "d.31", 31 },
{ "d.4", 4 },
{ "d.5", 5 },
{ "d.6", 6 },
{ "d.7", 7 },
{ "d.8", 8 },
{ "d.9", 9 },
{ "d0", 0 }, /* More Double Word Regs for PPE */
{ "d1", 1 },
{ "d2", 2 },
{ "d28", 28 },
{ "d29", 29 },
{ "d3", 3 },
{ "d30", 30 },
{ "d31", 31 },
{ "d4", 4 },
{ "d5", 5 },
{ "d6", 6 },
{ "d7", 7 },
{ "d8", 8 },
{ "d9", 9 },
{ "dar", 19 }, /* Data Access Register */
{ "dec", 22 }, /* Decrementer */
{ "dsisr", 18 }, /* Data Storage Interrupt Status Register */
......@@ -1272,6 +1302,7 @@ PowerPC options:\n\
generate code for PowerPC 603/604\n\
-m403 generate code for PowerPC 403\n\
-m405 generate code for PowerPC 405\n\
-mppe42 generate code for PowerPC ppe\n\
-m440 generate code for PowerPC 440\n\
-m464 generate code for PowerPC 464\n\
-m476 generate code for PowerPC 476\n\
......@@ -1362,7 +1393,7 @@ ppc_arch (void)
const char *default_cpu = TARGET_CPU;
ppc_set_cpu ();
if ((ppc_cpu & PPC_OPCODE_PPC) != 0)
if ((ppc_cpu & (PPC_OPCODE_PPC | PPC_OPCODE_PPE)) != 0)
return bfd_arch_powerpc;
if ((ppc_cpu & PPC_OPCODE_VLE) != 0)
return bfd_arch_powerpc;
......@@ -1820,6 +1851,47 @@ ppc_insert_operand (unsigned long insn,
as_bad_value_out_of_range (_("operand"), val, min, max, file, line);
}
if (cpu & PPC_OPCODE_PPE)
{
if (operand->flags & (PPC_OPERAND_GPR | PPC_OPERAND_GPR_0))
switch(val)
{
case 0: case 1: case 2: case 3: case 4: case 5: case 6:
case 7: case 8: case 9: case 10: case 13:
case 28: case 29: case 30: case 31:
break;
/* do nothing */
default:
if (val > 1 && val < 31)
as_bad_where (file, line, "%s %d", "Invalid PPE register: ", (int)val);
break;
}
else if (operand->flags & PPC_OPERAND_GPVDR)
switch(val)
{
case 0: case 1: case 2: case 3: case 4: case 5: case 6:
case 7: case 8: case 9:
case 28: case 29: case 30: case 31:
break;
/* do nothing */
default:
if (val > 0 && val < 31)
as_bad_where (file, line, "%s %d %x", "Invalid PPE virtual double register:", (int)val, (unsigned)operand->flags);
break;
}
else if (operand->flags & PPC_OPERAND_CR_REG)
switch(val)
{
case 0:
break;
/* do nothing */
default:
if (val != 0)
as_bad_where (file, line, "%s %d %x", "Invalid PPE Condition register:", (int)val, (unsigned)operand->flags);
break;
}
}
if (operand->insert)
{
const char *errmsg;
......@@ -3255,6 +3327,10 @@ md_assemble (char *str)
&& operand->bitm == 0xfffc
&& operand->shift == 0)
reloc = BFD_RELOC_PPC_B16;
else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0
&& operand->bitm == 0xffc
&& operand->shift == -1)
reloc = BFD_RELOC_PPC_PPE_REL10;
else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0
&& operand->bitm == 0x1fe
&& operand->shift == -1)
......@@ -7030,6 +7106,7 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
case BFD_RELOC_24_PLT_PCREL:
case BFD_RELOC_32_PLT_PCREL:
case BFD_RELOC_64_PLT_PCREL:
case BFD_RELOC_PPC_PPE_REL10:
case BFD_RELOC_PPC_VLE_REL8:
case BFD_RELOC_PPC_VLE_REL15:
case BFD_RELOC_PPC_VLE_REL24:
......
......@@ -131,6 +131,9 @@ START_RELOC_NUMBERS (elf_ppc_reloc_type)
RELOC_NUMBER (R_PPC_EMB_BIT_FLD, 115)
RELOC_NUMBER (R_PPC_EMB_RELSDA, 116)
/* PowerPC PPE relocations. */
RELOC_NUMBER (R_PPC_PPE_REL10, 200)
/* PowerPC VLE relocations. */
RELOC_NUMBER (R_PPC_VLE_REL8, 216)
RELOC_NUMBER (R_PPC_VLE_REL15, 217)
......
......@@ -191,6 +191,9 @@ extern const int vle_num_opcodes;
/* Opcode is only supported by Power8 architecture. */
#define PPC_OPCODE_POWER8 0x2000000000ull
/* Opcode is only supported by PPE architecture. */
#define PPC_OPCODE_PPE 0x8000000000ull
/* Opcode which is supported by the Hardware Transactional Memory extension. */
/* Currently, this is the same as the POWER8 mask. If another cpu comes out
that isn't a superset of POWER8, we can define this to its own mask. */
......@@ -386,6 +389,12 @@ extern const unsigned int num_powerpc_operands;
with the operands table for simplicity. The macro table is an
array of struct powerpc_macro. */
/* This operand names a general purpose double register. PPE42 specific.
* The disassembler uses this to print
register names with a leading 'd'. */
#define PPC_OPERAND_GPVDR (0x400000)
struct powerpc_macro
{
/* The macro name. */
......@@ -409,5 +418,8 @@ extern const struct powerpc_macro powerpc_macros[];
extern const int powerpc_num_macros;
extern ppc_cpu_t ppc_parse_cpu (ppc_cpu_t, ppc_cpu_t *, const char *);
extern int string_print_insn_powerpc (unsigned long insn,
uint64_t dialect, char * assemblyString);
extern void disassemble_init_powerpc_standalone (void);
#endif /* PPC_H */
......@@ -56,6 +56,8 @@ struct ppc_mopt ppc_opts[] = {
0 },
{ "405", (PPC_OPCODE_PPC | PPC_OPCODE_403 | PPC_OPCODE_405),
0 },
{ "ppe42", (PPC_OPCODE_PPE),
0 },
{ "440", (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE | PPC_OPCODE_440
| PPC_OPCODE_ISEL | PPC_OPCODE_RFMCI),
0 },
......@@ -379,6 +381,33 @@ disassemble_init_powerpc (struct disassemble_info *info)
powerpc_init_dialect (info);
}
/* Calculate opcode table indices to speed up disassembly,
and init dialect. */
void
disassemble_init_powerpc_standalone ()
{
int i;
unsigned short last;
i = powerpc_num_opcodes;
while (--i >= 0)
{
unsigned op = PPC_OP (powerpc_opcodes[i].opcode);
powerpc_opcd_indices[op] = i;
}
last = powerpc_num_opcodes;
for (i = PPC_OPCD_SEGS; i > 0; --i)
{
if (powerpc_opcd_indices[i] == 0)
powerpc_opcd_indices[i] = last;
last = powerpc_opcd_indices[i];
}
}
/* Print a big endian PowerPC instruction. */
int
......@@ -667,6 +696,8 @@ print_insn_powerpc (bfd_vma memaddr,
if ((operand->flags & PPC_OPERAND_GPR) != 0
|| ((operand->flags & PPC_OPERAND_GPR_0) != 0 && value != 0))
(*info->fprintf_func) (info->stream, "r%ld", value);
else if ((operand->flags & PPC_OPERAND_GPVDR) != 0)
(*info->fprintf_func) (info->stream, "d%ld", value);
else if ((operand->flags & PPC_OPERAND_FPR) != 0)
(*info->fprintf_func) (info->stream, "f%ld", value);
else if ((operand->flags & PPC_OPERAND_VR) != 0)
......@@ -737,6 +768,150 @@ print_insn_powerpc (bfd_vma memaddr,
return 4;
}
int
string_print_insn_powerpc (unsigned long insn,
uint64_t dialect, char * assemblyString)
{
const struct powerpc_opcode *opcode;
bfd_boolean insn_is_short;
unsigned prevStrEnd = 0;
/* Get the major opcode of the insn. */
opcode = NULL;
insn_is_short = FALSE;
uint8_t * mybytes = (uint8_t *) &insn;
unsigned long be = 0;
be = (unsigned long) mybytes[0] << 24;
be |= (unsigned long) mybytes[1] << 16;
be |= (unsigned long) mybytes[2] << 8;
be |= (unsigned long) mybytes[3];
insn = be;
if (opcode == NULL)
opcode = lookup_powerpc (insn, dialect);
if (opcode != NULL)
{
const unsigned char *opindex;
const struct powerpc_operand *operand;
int need_comma;
int need_paren;
int skip_optional;
if (opcode->operands[0] != 0)
prevStrEnd += sprintf(prevStrEnd+assemblyString, "%-7s ", opcode->name);
else
prevStrEnd += sprintf(prevStrEnd+assemblyString, "%s", opcode->name);
if (insn_is_short)
/* The operands will be fetched out of the 16-bit instruction. */
insn >>= 16;
/* Now extract and print the operands. */
need_comma = 0;
need_paren = 0;
skip_optional = -1;
for (opindex = opcode->operands; *opindex != 0; opindex++)
{
long value;
operand = powerpc_operands + *opindex;
/* Operands that are marked FAKE are simply ignored. We
already made sure that the extract function considered
the instruction to be valid. */
if ((operand->flags & PPC_OPERAND_FAKE) != 0)
continue;
/* If all of the optional operands have the value zero,
then don't print any of them. */
if ((operand->flags & PPC_OPERAND_OPTIONAL) != 0)
{
if (skip_optional < 0)
skip_optional = skip_optional_operands (opindex, insn,
dialect);
if (skip_optional)
continue;
}
value = operand_value_powerpc (operand, insn, dialect);
if (need_comma)
{
prevStrEnd += sprintf(prevStrEnd+assemblyString, ",");
need_comma = 0;
}
/* Print the operand as directed by the flags. */
if ((operand->flags & PPC_OPERAND_GPR) != 0
|| ((operand->flags & PPC_OPERAND_GPR_0) != 0 && value != 0))
prevStrEnd += sprintf(prevStrEnd+assemblyString, "r%ld", value);
else if ((operand->flags & PPC_OPERAND_GPVDR) != 0)
prevStrEnd += sprintf(prevStrEnd+assemblyString, "d%ld", value);
else if ((operand->flags & PPC_OPERAND_FPR) != 0)
prevStrEnd += sprintf(prevStrEnd+assemblyString, "f%ld", value);
else if ((operand->flags & PPC_OPERAND_VR) != 0)
prevStrEnd += sprintf(prevStrEnd+assemblyString, "v%ld", value);
else if ((operand->flags & PPC_OPERAND_VSR) != 0)
prevStrEnd += sprintf(prevStrEnd+assemblyString, "vs%ld", value);
else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0)
prevStrEnd += sprintf(prevStrEnd+assemblyString, "0x%lx", value);
else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0)
prevStrEnd += sprintf(prevStrEnd+assemblyString, "0x%lx", value & 0xffffffff);
else if ((operand->flags & PPC_OPERAND_FSL) != 0)
prevStrEnd += sprintf(prevStrEnd+assemblyString, "fsl%ld", value);
else if ((operand->flags & PPC_OPERAND_FCR) != 0)
prevStrEnd += sprintf(prevStrEnd+assemblyString, "fcr%ld", value);
else if ((operand->flags & PPC_OPERAND_UDI) != 0)
prevStrEnd += sprintf(prevStrEnd+assemblyString, "%ld", value);
else if ((operand->flags & PPC_OPERAND_CR_REG) != 0
&& (((dialect & PPC_OPCODE_PPC) != 0)
|| ((dialect & PPC_OPCODE_VLE) != 0)))
prevStrEnd += sprintf(prevStrEnd+assemblyString, "cr%ld", value);
else if (((operand->flags & PPC_OPERAND_CR_BIT) != 0)
&& (((dialect & PPC_OPCODE_PPC) != 0)
|| ((dialect & PPC_OPCODE_VLE) != 0)))
{
static const char *cbnames[4] = { "lt", "gt", "eq", "so" };
int cr;
int cc;
cr = value >> 2;
if (cr != 0)
prevStrEnd += sprintf(prevStrEnd+assemblyString, "4*cr%d+", cr);
cc = value & 3;
prevStrEnd += sprintf(prevStrEnd+assemblyString, "%s", cbnames[cc]);
}
else
prevStrEnd += sprintf(prevStrEnd+assemblyString, "%d", (int) value);
if (need_paren)
{
prevStrEnd += sprintf(prevStrEnd+assemblyString, ")");
need_paren = 0;
}
if ((operand->flags & PPC_OPERAND_PARENS) == 0)
need_comma = 1;
else
{
prevStrEnd += sprintf(prevStrEnd+assemblyString, "(");
need_paren = 1;
}
}
return 4;
}
else
{/* We could not find a match. */
prevStrEnd += sprintf(prevStrEnd+assemblyString, " .long 0x%lx", insn);
}
return 4;
}
void
print_ppc_disassembler_options (FILE *stream)
{
......
This source diff could not be displayed because it is too large. You can view the blob instead.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment