diff options
author | Dimitar Dimitrov <dimitar@dinux.eu> | 2016-12-30 12:39:50 +0200 |
---|---|---|
committer | Alan Modra <amodra@gmail.com> | 2016-12-31 12:02:50 +1030 |
commit | 111468496477e97c9414d2d54f97bfdaa380f794 (patch) | |
tree | 31a04a1497296d7b1b485e8ee77e747b3f3c971d | |
parent | 889294f6ffb380eb37b1f1f3bd22807fa9204c14 (diff) | |
download | gdb-111468496477e97c9414d2d54f97bfdaa380f794.zip gdb-111468496477e97c9414d2d54f97bfdaa380f794.tar.gz gdb-111468496477e97c9414d2d54f97bfdaa380f794.tar.bz2 |
PRU Opcode Port
opcodes/
* Makefile.am: Add PRU source files.
* configure.ac: Add PRU target.
* disassemble.c (disassembler): Register PRU arch.
* pru-dis.c: New file.
* pru-opc.c: New file.
* Makefile.in: Regenerate.
* configure: Regenerate.
Signed-off-by: Dimitar Dimitrov <dimitar@dinux.eu>
-rw-r--r-- | opcodes/ChangeLog | 10 | ||||
-rw-r--r-- | opcodes/Makefile.am | 2 | ||||
-rw-r--r-- | opcodes/Makefile.in | 4 | ||||
-rwxr-xr-x | opcodes/configure | 1 | ||||
-rw-r--r-- | opcodes/configure.ac | 1 | ||||
-rw-r--r-- | opcodes/disassemble.c | 7 | ||||
-rw-r--r-- | opcodes/po/POTFILES.in | 2 | ||||
-rw-r--r-- | opcodes/pru-dis.c | 286 | ||||
-rw-r--r-- | opcodes/pru-opc.c | 236 |
9 files changed, 548 insertions, 1 deletions
diff --git a/opcodes/ChangeLog b/opcodes/ChangeLog index f004163..843c8d7 100644 --- a/opcodes/ChangeLog +++ b/opcodes/ChangeLog @@ -1,3 +1,13 @@ +2016-12-31 Dimitar Dimitrov <dimitar@dinux.eu> + + * Makefile.am: Add PRU source files. + * configure.ac: Add PRU target. + * disassemble.c (disassembler): Register PRU arch. + * pru-dis.c: New file. + * pru-opc.c: New file. + * Makefile.in: Regenerate. + * configure: Regenerate. + 2016-12-29 Yao Qi <yao.qi@linaro.org> * avr-dis.c: Include "bfd_stdint.h" diff --git a/opcodes/Makefile.am b/opcodes/Makefile.am index a441feb..fd86b46 100644 --- a/opcodes/Makefile.am +++ b/opcodes/Makefile.am @@ -223,6 +223,8 @@ TARGET_LIBOPCODES_CFILES = \ pj-opc.c \ ppc-dis.c \ ppc-opc.c \ + pru-dis.c \ + pru-opc.c \ riscv-dis.c \ riscv-opc.c \ rl78-decode.c \ diff --git a/opcodes/Makefile.in b/opcodes/Makefile.in index 763255b..b31b251 100644 --- a/opcodes/Makefile.in +++ b/opcodes/Makefile.in @@ -525,6 +525,8 @@ TARGET_LIBOPCODES_CFILES = \ pj-opc.c \ ppc-dis.c \ ppc-opc.c \ + pru-dis.c \ + pru-opc.c \ riscv-dis.c \ riscv-opc.c \ rl78-decode.c \ @@ -931,6 +933,8 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pj-opc.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ppc-dis.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ppc-opc.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pru-dis.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pru-opc.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/riscv-dis.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/riscv-opc.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rl78-decode.Plo@am__quote@ diff --git a/opcodes/configure b/opcodes/configure index c3aa76e..b13f342 100755 --- a/opcodes/configure +++ b/opcodes/configure @@ -12683,6 +12683,7 @@ if test x${all_targets} = xfalse ; then bfd_pj_arch) ta="$ta pj-dis.lo pj-opc.lo" ;; bfd_powerpc_arch) ta="$ta ppc-dis.lo ppc-opc.lo" ;; bfd_powerpc_64_arch) ta="$ta ppc-dis.lo ppc-opc.lo" ;; + bfd_pru_arch) ta="$ta pru-dis.lo pru-opc.lo" ;; bfd_pyramid_arch) ;; bfd_romp_arch) ;; bfd_riscv_arch) ta="$ta riscv-dis.lo riscv-opc.lo" ;; diff --git a/opcodes/configure.ac b/opcodes/configure.ac index 3475d49..2d33309 100644 --- a/opcodes/configure.ac +++ b/opcodes/configure.ac @@ -307,6 +307,7 @@ if test x${all_targets} = xfalse ; then bfd_pj_arch) ta="$ta pj-dis.lo pj-opc.lo" ;; bfd_powerpc_arch) ta="$ta ppc-dis.lo ppc-opc.lo" ;; bfd_powerpc_64_arch) ta="$ta ppc-dis.lo ppc-opc.lo" ;; + bfd_pru_arch) ta="$ta pru-dis.lo pru-opc.lo" ;; bfd_pyramid_arch) ;; bfd_romp_arch) ;; bfd_riscv_arch) ta="$ta riscv-dis.lo riscv-opc.lo" ;; diff --git a/opcodes/disassemble.c b/opcodes/disassemble.c index e1fb65c..aeed703 100644 --- a/opcodes/disassemble.c +++ b/opcodes/disassemble.c @@ -73,6 +73,7 @@ #define ARCH_pdp11 #define ARCH_pj #define ARCH_powerpc +#define ARCH_pru #define ARCH_rs6000 #define ARCH_rl78 #define ARCH_rx @@ -375,10 +376,14 @@ disassembler (bfd *abfd) disassemble = print_insn_little_powerpc; break; #endif +#ifdef ARCH_pru + case bfd_arch_pru: + disassemble = print_insn_pru; + break; +#endif #ifdef ARCH_riscv case bfd_arch_riscv: disassemble = print_insn_riscv; - break; #endif #ifdef ARCH_rs6000 case bfd_arch_rs6000: diff --git a/opcodes/po/POTFILES.in b/opcodes/po/POTFILES.in index 69f968a..a1f48dc 100644 --- a/opcodes/po/POTFILES.in +++ b/opcodes/po/POTFILES.in @@ -175,6 +175,8 @@ pj-dis.c pj-opc.c ppc-dis.c ppc-opc.c +pru-dis.c +pru-opc.c riscv-dis.c riscv-opc.c rl78-decode.c diff --git a/opcodes/pru-dis.c b/opcodes/pru-dis.c new file mode 100644 index 0000000..dd150c5 --- /dev/null +++ b/opcodes/pru-dis.c @@ -0,0 +1,286 @@ +/* TI PRU disassemble routines + Copyright (C) 2014-2016 Free Software Foundation, Inc. + Contributed by Dimitar Dimitrov <dimitar@dinux.eu> + + This file is part of the GNU opcodes library. + + 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 file; see the file COPYING. If not, write to the + Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ + +#include "sysdep.h" +#include "dis-asm.h" +#include "opcode/pru.h" +#include "libiberty.h" +#include <string.h> +#include <assert.h> + +/* No symbol table is available when this code runs out in an embedded + system as when it is used for disassembler support in a monitor. */ +#if !defined (EMBEDDED_ENV) +#define SYMTAB_AVAILABLE 1 +#include "elf-bfd.h" +#include "elf/pru.h" +#endif + +/* Length of PRU instruction in bytes. */ +#define INSNLEN 4 + +/* Return a pointer to an pru_opcode struct for a given instruction + opcode, or NULL if there is an error. */ +const struct pru_opcode * +pru_find_opcode (unsigned long opcode) +{ + const struct pru_opcode *p; + const struct pru_opcode *op = NULL; + const struct pru_opcode *pseudo_op = NULL; + + for (p = pru_opcodes; p < &pru_opcodes[NUMOPCODES]; p++) + { + if ((p->mask & opcode) == p->match) + { + if ((p->pinfo & PRU_INSN_MACRO) == PRU_INSN_MACRO) + pseudo_op = p; + else if ((p->pinfo & PRU_INSN_LDI32) == PRU_INSN_LDI32) + /* ignore - should be caught with regular patterns */; + else + op = p; + } + } + + return pseudo_op ? pseudo_op : op; +} + +/* There are 32 regular registers, each with 8 possible subfield selectors. */ +#define NUMREGNAMES (32 * 8) + +static void +pru_print_insn_arg_reg (unsigned int r, unsigned int sel, + disassemble_info *info) +{ + unsigned int i = r * RSEL_NUM_ITEMS + sel; + assert (i < (unsigned int)pru_num_regs); + assert (i < NUMREGNAMES); + (*info->fprintf_func) (info->stream, "%s", pru_regs[i].name); +} + +/* The function pru_print_insn_arg uses the character pointed + to by ARGPTR to determine how it print the next token or separator + character in the arguments to an instruction. */ +static int +pru_print_insn_arg (const char *argptr, + unsigned long opcode, bfd_vma address, + disassemble_info *info) +{ + long offs = 0; + unsigned long i = 0; + unsigned long io = 0; + + switch (*argptr) + { + case ',': + (*info->fprintf_func) (info->stream, "%c ", *argptr); + break; + case 'd': + pru_print_insn_arg_reg (GET_INSN_FIELD (RD, opcode), + GET_INSN_FIELD (RDSEL, opcode), + info); + break; + case 'D': + /* The first 4 values for RDB and RSEL are the same, so we + can reuse some code. */ + pru_print_insn_arg_reg (GET_INSN_FIELD (RD, opcode), + GET_INSN_FIELD (RDB, opcode), + info); + break; + case 's': + pru_print_insn_arg_reg (GET_INSN_FIELD (RS1, opcode), + GET_INSN_FIELD (RS1SEL, opcode), + info); + break; + case 'S': + pru_print_insn_arg_reg (GET_INSN_FIELD (RS1, opcode), + RSEL_31_0, + info); + break; + case 'b': + io = GET_INSN_FIELD (IO, opcode); + + if (io) + { + i = GET_INSN_FIELD (IMM8, opcode); + (*info->fprintf_func) (info->stream, "%ld", i); + } + else + { + pru_print_insn_arg_reg (GET_INSN_FIELD (RS2, opcode), + GET_INSN_FIELD (RS2SEL, opcode), + info); + } + break; + case 'B': + io = GET_INSN_FIELD (IO, opcode); + + if (io) + { + i = GET_INSN_FIELD (IMM8, opcode) + 1; + (*info->fprintf_func) (info->stream, "%ld", i); + } + else + { + pru_print_insn_arg_reg (GET_INSN_FIELD (RS2, opcode), + GET_INSN_FIELD (RS2SEL, opcode), + info); + } + break; + case 'j': + io = GET_INSN_FIELD (IO, opcode); + + if (io) + { + /* For the sake of pretty-printing, dump text addresses with + their "virtual" offset that we use for distinguishing + PMEM vs DMEM. This is needed for printing the correct text + labels. */ + bfd_vma text_offset = address & ~0x3fffff; + i = GET_INSN_FIELD (IMM16, opcode) * 4; + (*info->print_address_func) (i + text_offset, info); + } + else + { + pru_print_insn_arg_reg (GET_INSN_FIELD (RS2, opcode), + GET_INSN_FIELD (RS2SEL, opcode), + info); + } + break; + case 'W': + i = GET_INSN_FIELD (IMM16, opcode); + (*info->fprintf_func) (info->stream, "%ld", i); + break; + case 'o': + offs = GET_BROFF_SIGNED (opcode) * 4; + (*info->print_address_func) (address + offs, info); + break; + case 'O': + offs = GET_INSN_FIELD (LOOP_JMPOFFS, opcode) * 4; + (*info->print_address_func) (address + offs, info); + break; + case 'l': + i = GET_BURSTLEN (opcode); + if (i < LSSBBO_BYTECOUNT_R0_BITS7_0) + (*info->fprintf_func) (info->stream, "%ld", i + 1); + else + { + i -= LSSBBO_BYTECOUNT_R0_BITS7_0; + (*info->fprintf_func) (info->stream, "r0.b%ld", i); + } + break; + case 'n': + i = GET_INSN_FIELD (XFR_LENGTH, opcode); + if (i < LSSBBO_BYTECOUNT_R0_BITS7_0) + (*info->fprintf_func) (info->stream, "%ld", i + 1); + else + { + i -= LSSBBO_BYTECOUNT_R0_BITS7_0; + (*info->fprintf_func) (info->stream, "r0.b%ld", i); + } + break; + case 'c': + i = GET_INSN_FIELD (CB, opcode); + (*info->fprintf_func) (info->stream, "%ld", i); + break; + case 'w': + i = GET_INSN_FIELD (WAKEONSTATUS, opcode); + (*info->fprintf_func) (info->stream, "%ld", i); + break; + case 'x': + i = GET_INSN_FIELD (XFR_WBA, opcode); + (*info->fprintf_func) (info->stream, "%ld", i); + break; + default: + (*info->fprintf_func) (info->stream, "unknown"); + break; + } + return 0; +} + +/* pru_disassemble does all the work of disassembling a PRU + instruction opcode. */ +static int +pru_disassemble (bfd_vma address, unsigned long opcode, + disassemble_info *info) +{ + const struct pru_opcode *op; + + info->bytes_per_line = INSNLEN; + info->bytes_per_chunk = INSNLEN; + info->display_endian = info->endian; + info->insn_info_valid = 1; + info->branch_delay_insns = 0; + info->data_size = 0; + info->insn_type = dis_nonbranch; + info->target = 0; + info->target2 = 0; + + /* Find the major opcode and use this to disassemble + the instruction and its arguments. */ + op = pru_find_opcode (opcode); + + if (op != NULL) + { + (*info->fprintf_func) (info->stream, "%s", op->name); + + const char *argstr = op->args; + if (argstr != NULL && *argstr != '\0') + { + (*info->fprintf_func) (info->stream, "\t"); + while (*argstr != '\0') + { + pru_print_insn_arg (argstr, opcode, address, info); + ++argstr; + } + } + } + else + { + /* Handle undefined instructions. */ + info->insn_type = dis_noninsn; + (*info->fprintf_func) (info->stream, "0x%lx", opcode); + } + /* Tell the caller how far to advance the program counter. */ + return INSNLEN; +} + + +/* print_insn_pru is the main disassemble function for PRU. */ +int +print_insn_pru (bfd_vma address, disassemble_info *info) +{ + bfd_byte buffer[INSNLEN]; + int status; + + status = (*info->read_memory_func) (address, buffer, INSNLEN, info); + if (status == 0) + { + unsigned long insn; + insn = (unsigned long) bfd_getl32 (buffer); + status = pru_disassemble (address, insn, info); + } + else + { + (*info->memory_error_func) (status, address, info); + status = -1; + } + return status; +} diff --git a/opcodes/pru-opc.c b/opcodes/pru-opc.c new file mode 100644 index 0000000..9b240a8 --- /dev/null +++ b/opcodes/pru-opc.c @@ -0,0 +1,236 @@ +/* TI PRU opcode list. + Copyright (C) 2014-2016 Free Software Foundation, Inc. + Contributed by Dimitar Dimitrov <dimitar@dinux.eu> + + This file is part of the GNU opcodes library. + + 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 file; see the file COPYING. If not, write to the + Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ + +/* Source: + http://processors.wiki.ti.com/index.php/Programmable_Realtime_Unit */ + +#include "sysdep.h" +#include <stdio.h> +#include "opcode/pru.h" + +/* Register string table. */ + +#define DECLARE_REG(name, index) \ + { #name ".b0", (index), RSEL_7_0 }, \ + { #name ".b1", (index), RSEL_15_8 }, \ + { #name ".b2", (index), RSEL_23_16 }, \ + { #name ".b3", (index), RSEL_31_24 }, \ + { #name ".w0", (index), RSEL_15_0 }, \ + { #name ".w1", (index), RSEL_23_8 }, \ + { #name ".w2", (index), RSEL_31_16 }, \ + { #name , (index), RSEL_31_0 } + +const struct pru_reg pru_regs[] = { + /* Standard register names. */ + DECLARE_REG (r0, 0), + DECLARE_REG (r1, 1), + DECLARE_REG (sp, 2), /* Stack pointer. */ + DECLARE_REG (ra, 3), /* Return address. */ + DECLARE_REG (fp, 4), /* Frame pointer. */ + DECLARE_REG (r5, 5), + DECLARE_REG (r6, 6), + DECLARE_REG (r7, 7), + DECLARE_REG (r8, 8), + DECLARE_REG (r9, 9), + DECLARE_REG (r10, 10), + DECLARE_REG (r11, 11), + DECLARE_REG (r12, 12), + DECLARE_REG (r13, 13), + DECLARE_REG (r14, 14), + DECLARE_REG (r15, 15), + DECLARE_REG (r16, 16), + DECLARE_REG (r17, 17), + DECLARE_REG (r18, 18), + DECLARE_REG (r19, 19), + DECLARE_REG (r20, 20), + DECLARE_REG (r21, 21), + DECLARE_REG (r22, 22), + DECLARE_REG (r23, 23), + DECLARE_REG (r24, 24), + DECLARE_REG (r25, 25), + DECLARE_REG (r26, 26), + DECLARE_REG (r27, 27), + DECLARE_REG (r28, 28), + DECLARE_REG (r29, 29), + DECLARE_REG (r30, 30), + DECLARE_REG (r31, 31), + + /* Alternative names for special registers. */ + DECLARE_REG (r2, 2), + DECLARE_REG (r3, 3), + DECLARE_REG (r4, 4) +}; + +#define PRU_NUM_REGS \ + ((sizeof pru_regs) / (sizeof (pru_regs[0]))) +const int pru_num_regs = PRU_NUM_REGS; + +#undef PRU_NUM_REGS + +/* This is the opcode table used by the PRU GNU as, disassembler + and soon GDB. */ +const struct pru_opcode pru_opcodes[] = +{ + /* { name, args, + match, mask, pinfo, overflow_msg } */ +#define DECLARE_FORMAT1_OPCODE(str, subop) \ + { #str, prui_ ## str, "d,s,b", \ + OP_MATCH_ ## subop, OP_MASK_FMT1_OP | OP_MASK_SUBOP, 0, \ + unsigned_immed8_overflow } + + DECLARE_FORMAT1_OPCODE (add, ADD), + DECLARE_FORMAT1_OPCODE (adc, ADC), + DECLARE_FORMAT1_OPCODE (sub, SUB), + DECLARE_FORMAT1_OPCODE (suc, SUC), + DECLARE_FORMAT1_OPCODE (lsl, LSL), + DECLARE_FORMAT1_OPCODE (lsr, LSR), + DECLARE_FORMAT1_OPCODE (rsb, RSB), + DECLARE_FORMAT1_OPCODE (rsc, RSC), + DECLARE_FORMAT1_OPCODE (and, AND), + DECLARE_FORMAT1_OPCODE (or, OR), + DECLARE_FORMAT1_OPCODE (xor, XOR), + DECLARE_FORMAT1_OPCODE (min, MIN), + DECLARE_FORMAT1_OPCODE (max, MAX), + DECLARE_FORMAT1_OPCODE (clr, CLR), + DECLARE_FORMAT1_OPCODE (set, SET), + + { "not", prui_not, "d,s", + OP_MATCH_NOT | OP_MASK_IO, + OP_MASK_FMT1_OP | OP_MASK_SUBOP | OP_MASK_IO, 0, no_overflow}, + + { "jmp", prui_jmp, "j", + OP_MATCH_JMP, OP_MASK_FMT2_OP | OP_MASK_SUBOP, 0, unsigned_immed16_overflow}, + { "jal", prui_jal, "d,j", + OP_MATCH_JAL, OP_MASK_FMT2_OP | OP_MASK_SUBOP, 0, unsigned_immed16_overflow}, + { "ldi", prui_ldi, "d,W", + OP_MATCH_LDI, OP_MASK_FMT2_OP | OP_MASK_SUBOP, 0, unsigned_immed16_overflow}, + { "halt", prui_halt, "", + OP_MATCH_HALT, OP_MASK_FMT2_OP | OP_MASK_SUBOP, 0, no_overflow}, + { "slp", prui_slp, "w", + OP_MATCH_SLP, OP_MASK_FMT2_OP | OP_MASK_SUBOP, 0, no_overflow}, + + { "xin", prui_xin, "x,D,n", + OP_MATCH_XIN, OP_MASK_XFR_OP, 0, unsigned_immed8_overflow}, + { "xout", prui_xout, "x,D,n", + OP_MATCH_XOUT, OP_MASK_XFR_OP, 0, unsigned_immed8_overflow}, + { "xchg", prui_xchg, "x,D,n", + OP_MATCH_XCHG, OP_MASK_XFR_OP, 0, unsigned_immed8_overflow}, + { "sxin", prui_sxin, "x,D,n", + OP_MATCH_SXIN, OP_MASK_XFR_OP, 0, unsigned_immed8_overflow}, + { "sxout", prui_sxout, "x,D,n", + OP_MATCH_SXOUT, OP_MASK_XFR_OP, 0, unsigned_immed8_overflow}, + { "sxchg", prui_sxchg, "x,D,n", + OP_MATCH_SXCHG, OP_MASK_XFR_OP, 0, unsigned_immed8_overflow}, + + { "loop", prui_loop, "O,B", + OP_MATCH_LOOP, OP_MASK_LOOP_OP, 0, unsigned_immed8_overflow}, + { "iloop", prui_loop, "O,B", + OP_MATCH_ILOOP, OP_MASK_LOOP_OP, 0, unsigned_immed8_overflow}, + + { "qbgt", prui_qbgt, "o,s,b", + OP_MATCH_QBGT, OP_MASK_FMT4_OP | OP_MASK_CMP, 0, qbranch_target_overflow}, + { "qbge", prui_qbge, "o,s,b", + OP_MATCH_QBGE, OP_MASK_FMT4_OP | OP_MASK_CMP, 0, qbranch_target_overflow}, + { "qblt", prui_qblt, "o,s,b", + OP_MATCH_QBLT, OP_MASK_FMT4_OP | OP_MASK_CMP, 0, qbranch_target_overflow}, + { "qble", prui_qble, "o,s,b", + OP_MATCH_QBLE, OP_MASK_FMT4_OP | OP_MASK_CMP, 0, qbranch_target_overflow}, + { "qbeq", prui_qbeq, "o,s,b", + OP_MATCH_QBEQ, OP_MASK_FMT4_OP | OP_MASK_CMP, 0, qbranch_target_overflow}, + { "qbne", prui_qbne, "o,s,b", + OP_MATCH_QBNE, OP_MASK_FMT4_OP | OP_MASK_CMP, 0, qbranch_target_overflow}, + { "qba", prui_qba, "o", + OP_MATCH_QBA, OP_MASK_FMT4_OP | OP_MASK_CMP, 0, qbranch_target_overflow}, + + { "qbbs", prui_qbbs, "o,s,b", + OP_MATCH_QBBS, OP_MASK_FMT5_OP | OP_MASK_BCMP, 0, qbranch_target_overflow}, + { "qbbc", prui_qbbc, "o,s,b", + OP_MATCH_QBBC, OP_MASK_FMT5_OP | OP_MASK_BCMP, 0, qbranch_target_overflow}, + + { "lbbo", prui_lbbo, "D,S,b,l", + OP_MATCH_LBBO, OP_MASK_FMT6AB_OP | OP_MASK_LOADSTORE, 0, + unsigned_immed8_overflow}, + { "sbbo", prui_sbbo, "D,S,b,l", + OP_MATCH_SBBO, OP_MASK_FMT6AB_OP | OP_MASK_LOADSTORE, 0, + unsigned_immed8_overflow}, + { "lbco", prui_lbco, "D,c,b,l", + OP_MATCH_LBCO, OP_MASK_FMT6CD_OP | OP_MASK_LOADSTORE, 0, + unsigned_immed8_overflow}, + { "sbco", prui_sbco, "D,c,b,l", + OP_MATCH_SBCO, OP_MASK_FMT6CD_OP | OP_MASK_LOADSTORE, 0, + unsigned_immed8_overflow}, + + /* Fill in the default values for the real-instruction arguments. + The assembler will not do it! */ + { "nop", prui_or, "", + OP_MATCH_OR + | (RSEL_31_0 << OP_SH_RS2SEL) | (0 << OP_SH_RS2) + | (RSEL_31_0 << OP_SH_RS1SEL) | (0 << OP_SH_RS1) + | (RSEL_31_0 << OP_SH_RDSEL) | (0 << OP_SH_RD), + OP_MASK_FMT1_OP | OP_MASK_SUBOP + | OP_MASK_RS2SEL | OP_MASK_RS2 | OP_MASK_RS1SEL | OP_MASK_RS1 + | OP_MASK_RDSEL | OP_MASK_RD | OP_MASK_IO, + PRU_INSN_MACRO, no_overflow}, + { "mov", prui_or, "d,s", + OP_MATCH_OR | (0 << OP_SH_IMM8) | OP_MASK_IO, + OP_MASK_FMT1_OP | OP_MASK_SUBOP | OP_MASK_IMM8 | OP_MASK_IO, + PRU_INSN_MACRO, no_overflow}, + { "ret", prui_jmp, "", + OP_MATCH_JMP + | (RSEL_31_16 << OP_SH_RS2SEL) | (3 << OP_SH_RS2), + OP_MASK_FMT2_OP | OP_MASK_SUBOP + | OP_MASK_RS2SEL | OP_MASK_RS2 | OP_MASK_IO, + PRU_INSN_MACRO, unsigned_immed16_overflow}, + { "call", prui_jal, "j", + OP_MATCH_JAL + | (RSEL_31_16 << OP_SH_RDSEL) | (3 << OP_SH_RD), + OP_MASK_FMT2_OP | OP_MASK_SUBOP + | OP_MASK_RDSEL | OP_MASK_RD, + PRU_INSN_MACRO, unsigned_immed16_overflow}, + + { "wbc", prui_qbbs, "s,b", + OP_MATCH_QBBS | (0 << OP_SH_BROFF98) | (0 << OP_SH_BROFF70), + OP_MASK_FMT5_OP | OP_MASK_BCMP | OP_MASK_BROFF, + PRU_INSN_MACRO, qbranch_target_overflow}, + { "wbs", prui_qbbc, "s,b", + OP_MATCH_QBBC | (0 << OP_SH_BROFF98) | (0 << OP_SH_BROFF70), + OP_MASK_FMT5_OP | OP_MASK_BCMP | OP_MASK_BROFF, + PRU_INSN_MACRO, qbranch_target_overflow}, + + { "fill", prui_xin, "D,n", + OP_MATCH_XIN | (254 << OP_SH_XFR_WBA), + OP_MASK_XFR_OP | OP_MASK_XFR_WBA, + PRU_INSN_MACRO, unsigned_immed8_overflow}, + { "zero", prui_xin, "D,n", + OP_MATCH_XIN | (255 << OP_SH_XFR_WBA), + OP_MASK_XFR_OP | OP_MASK_XFR_WBA, + PRU_INSN_MACRO, unsigned_immed8_overflow}, + + { "ldi32", prui_ldi, "R,i", + OP_MATCH_LDI, OP_MASK_FMT2_OP | OP_MASK_SUBOP, + PRU_INSN_LDI32, unsigned_immed32_overflow}, +}; + +#define PRU_NUM_OPCODES \ + ((sizeof pru_opcodes) / (sizeof (pru_opcodes[0]))) +const int bfd_pru_num_opcodes = PRU_NUM_OPCODES; + +#undef PRU_NUM_OPCODES |