| 1 | /* TI PRU opcode list. |
| 2 | Copyright (C) 2014-2018 Free Software Foundation, Inc. |
| 3 | Contributed by Dimitar Dimitrov <dimitar@dinux.eu> |
| 4 | |
| 5 | This file is part of the GNU opcodes library. |
| 6 | |
| 7 | This library is free software; you can redistribute it and/or modify |
| 8 | it under the terms of the GNU General Public License as published by |
| 9 | the Free Software Foundation; either version 3, or (at your option) |
| 10 | any later version. |
| 11 | |
| 12 | It is distributed in the hope that it will be useful, but WITHOUT |
| 13 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
| 14 | or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public |
| 15 | License for more details. |
| 16 | |
| 17 | You should have received a copy of the GNU General Public License |
| 18 | along with this file; see the file COPYING. If not, write to the |
| 19 | Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston, |
| 20 | MA 02110-1301, USA. */ |
| 21 | |
| 22 | /* Source: |
| 23 | http://processors.wiki.ti.com/index.php/Programmable_Realtime_Unit */ |
| 24 | |
| 25 | #include "sysdep.h" |
| 26 | #include <stdio.h> |
| 27 | #include "opcode/pru.h" |
| 28 | |
| 29 | /* Register string table. */ |
| 30 | |
| 31 | #define DECLARE_REG(name, index) \ |
| 32 | { #name ".b0", (index), RSEL_7_0 }, \ |
| 33 | { #name ".b1", (index), RSEL_15_8 }, \ |
| 34 | { #name ".b2", (index), RSEL_23_16 }, \ |
| 35 | { #name ".b3", (index), RSEL_31_24 }, \ |
| 36 | { #name ".w0", (index), RSEL_15_0 }, \ |
| 37 | { #name ".w1", (index), RSEL_23_8 }, \ |
| 38 | { #name ".w2", (index), RSEL_31_16 }, \ |
| 39 | { #name , (index), RSEL_31_0 } |
| 40 | |
| 41 | const struct pru_reg pru_regs[] = { |
| 42 | /* Standard register names. */ |
| 43 | DECLARE_REG (r0, 0), |
| 44 | DECLARE_REG (r1, 1), |
| 45 | DECLARE_REG (sp, 2), /* Stack pointer. */ |
| 46 | DECLARE_REG (ra, 3), /* Return address. */ |
| 47 | DECLARE_REG (fp, 4), /* Frame pointer. */ |
| 48 | DECLARE_REG (r5, 5), |
| 49 | DECLARE_REG (r6, 6), |
| 50 | DECLARE_REG (r7, 7), |
| 51 | DECLARE_REG (r8, 8), |
| 52 | DECLARE_REG (r9, 9), |
| 53 | DECLARE_REG (r10, 10), |
| 54 | DECLARE_REG (r11, 11), |
| 55 | DECLARE_REG (r12, 12), |
| 56 | DECLARE_REG (r13, 13), |
| 57 | DECLARE_REG (r14, 14), |
| 58 | DECLARE_REG (r15, 15), |
| 59 | DECLARE_REG (r16, 16), |
| 60 | DECLARE_REG (r17, 17), |
| 61 | DECLARE_REG (r18, 18), |
| 62 | DECLARE_REG (r19, 19), |
| 63 | DECLARE_REG (r20, 20), |
| 64 | DECLARE_REG (r21, 21), |
| 65 | DECLARE_REG (r22, 22), |
| 66 | DECLARE_REG (r23, 23), |
| 67 | DECLARE_REG (r24, 24), |
| 68 | DECLARE_REG (r25, 25), |
| 69 | DECLARE_REG (r26, 26), |
| 70 | DECLARE_REG (r27, 27), |
| 71 | DECLARE_REG (r28, 28), |
| 72 | DECLARE_REG (r29, 29), |
| 73 | DECLARE_REG (r30, 30), |
| 74 | DECLARE_REG (r31, 31), |
| 75 | |
| 76 | /* Alternative names for special registers. */ |
| 77 | DECLARE_REG (r2, 2), |
| 78 | DECLARE_REG (r3, 3), |
| 79 | DECLARE_REG (r4, 4) |
| 80 | }; |
| 81 | |
| 82 | #define PRU_NUM_REGS \ |
| 83 | ((sizeof pru_regs) / (sizeof (pru_regs[0]))) |
| 84 | const int pru_num_regs = PRU_NUM_REGS; |
| 85 | |
| 86 | #undef PRU_NUM_REGS |
| 87 | |
| 88 | /* This is the opcode table used by the PRU GNU as and disassembler. */ |
| 89 | const struct pru_opcode pru_opcodes[] = |
| 90 | { |
| 91 | /* { name, args, |
| 92 | match, mask, pinfo, overflow_msg } */ |
| 93 | #define DECLARE_FORMAT1_OPCODE(str, subop) \ |
| 94 | { #str, prui_ ## str, "d,s,b", \ |
| 95 | OP_MATCH_ ## subop, OP_MASK_FMT1_OP | OP_MASK_SUBOP, 0, \ |
| 96 | unsigned_immed8_overflow } |
| 97 | |
| 98 | DECLARE_FORMAT1_OPCODE (add, ADD), |
| 99 | DECLARE_FORMAT1_OPCODE (adc, ADC), |
| 100 | DECLARE_FORMAT1_OPCODE (sub, SUB), |
| 101 | DECLARE_FORMAT1_OPCODE (suc, SUC), |
| 102 | DECLARE_FORMAT1_OPCODE (lsl, LSL), |
| 103 | DECLARE_FORMAT1_OPCODE (lsr, LSR), |
| 104 | DECLARE_FORMAT1_OPCODE (rsb, RSB), |
| 105 | DECLARE_FORMAT1_OPCODE (rsc, RSC), |
| 106 | DECLARE_FORMAT1_OPCODE (and, AND), |
| 107 | DECLARE_FORMAT1_OPCODE (or, OR), |
| 108 | DECLARE_FORMAT1_OPCODE (xor, XOR), |
| 109 | DECLARE_FORMAT1_OPCODE (min, MIN), |
| 110 | DECLARE_FORMAT1_OPCODE (max, MAX), |
| 111 | DECLARE_FORMAT1_OPCODE (clr, CLR), |
| 112 | DECLARE_FORMAT1_OPCODE (set, SET), |
| 113 | |
| 114 | { "not", prui_not, "d,s", |
| 115 | OP_MATCH_NOT | OP_MASK_IO, |
| 116 | OP_MASK_FMT1_OP | OP_MASK_SUBOP | OP_MASK_IO, 0, no_overflow}, |
| 117 | |
| 118 | { "jmp", prui_jmp, "j", |
| 119 | OP_MATCH_JMP, OP_MASK_FMT2_OP | OP_MASK_SUBOP, 0, unsigned_immed16_overflow}, |
| 120 | { "jal", prui_jal, "d,j", |
| 121 | OP_MATCH_JAL, OP_MASK_FMT2_OP | OP_MASK_SUBOP, 0, unsigned_immed16_overflow}, |
| 122 | { "ldi", prui_ldi, "d,W", |
| 123 | OP_MATCH_LDI, OP_MASK_FMT2_OP | OP_MASK_SUBOP, 0, unsigned_immed16_overflow}, |
| 124 | { "halt", prui_halt, "", |
| 125 | OP_MATCH_HALT, OP_MASK_FMT2_OP | OP_MASK_SUBOP, 0, no_overflow}, |
| 126 | { "slp", prui_slp, "w", |
| 127 | OP_MATCH_SLP, OP_MASK_FMT2_OP | OP_MASK_SUBOP, 0, no_overflow}, |
| 128 | |
| 129 | { "xin", prui_xin, "x,D,n", |
| 130 | OP_MATCH_XIN, OP_MASK_XFR_OP, 0, unsigned_immed8_overflow}, |
| 131 | { "xout", prui_xout, "x,D,n", |
| 132 | OP_MATCH_XOUT, OP_MASK_XFR_OP, 0, unsigned_immed8_overflow}, |
| 133 | { "xchg", prui_xchg, "x,D,n", |
| 134 | OP_MATCH_XCHG, OP_MASK_XFR_OP, 0, unsigned_immed8_overflow}, |
| 135 | { "sxin", prui_sxin, "x,D,n", |
| 136 | OP_MATCH_SXIN, OP_MASK_XFR_OP, 0, unsigned_immed8_overflow}, |
| 137 | { "sxout", prui_sxout, "x,D,n", |
| 138 | OP_MATCH_SXOUT, OP_MASK_XFR_OP, 0, unsigned_immed8_overflow}, |
| 139 | { "sxchg", prui_sxchg, "x,D,n", |
| 140 | OP_MATCH_SXCHG, OP_MASK_XFR_OP, 0, unsigned_immed8_overflow}, |
| 141 | |
| 142 | { "loop", prui_loop, "O,B", |
| 143 | OP_MATCH_LOOP, OP_MASK_LOOP_OP, 0, unsigned_immed8_overflow}, |
| 144 | { "iloop", prui_loop, "O,B", |
| 145 | OP_MATCH_ILOOP, OP_MASK_LOOP_OP, 0, unsigned_immed8_overflow}, |
| 146 | |
| 147 | { "qbgt", prui_qbgt, "o,s,b", |
| 148 | OP_MATCH_QBGT, OP_MASK_FMT4_OP | OP_MASK_CMP, 0, qbranch_target_overflow}, |
| 149 | { "qbge", prui_qbge, "o,s,b", |
| 150 | OP_MATCH_QBGE, OP_MASK_FMT4_OP | OP_MASK_CMP, 0, qbranch_target_overflow}, |
| 151 | { "qblt", prui_qblt, "o,s,b", |
| 152 | OP_MATCH_QBLT, OP_MASK_FMT4_OP | OP_MASK_CMP, 0, qbranch_target_overflow}, |
| 153 | { "qble", prui_qble, "o,s,b", |
| 154 | OP_MATCH_QBLE, OP_MASK_FMT4_OP | OP_MASK_CMP, 0, qbranch_target_overflow}, |
| 155 | { "qbeq", prui_qbeq, "o,s,b", |
| 156 | OP_MATCH_QBEQ, OP_MASK_FMT4_OP | OP_MASK_CMP, 0, qbranch_target_overflow}, |
| 157 | { "qbne", prui_qbne, "o,s,b", |
| 158 | OP_MATCH_QBNE, OP_MASK_FMT4_OP | OP_MASK_CMP, 0, qbranch_target_overflow}, |
| 159 | { "qba", prui_qba, "o", |
| 160 | OP_MATCH_QBA, OP_MASK_FMT4_OP | OP_MASK_CMP, 0, qbranch_target_overflow}, |
| 161 | |
| 162 | { "qbbs", prui_qbbs, "o,s,b", |
| 163 | OP_MATCH_QBBS, OP_MASK_FMT5_OP | OP_MASK_BCMP, 0, qbranch_target_overflow}, |
| 164 | { "qbbc", prui_qbbc, "o,s,b", |
| 165 | OP_MATCH_QBBC, OP_MASK_FMT5_OP | OP_MASK_BCMP, 0, qbranch_target_overflow}, |
| 166 | |
| 167 | { "lbbo", prui_lbbo, "D,S,b,l", |
| 168 | OP_MATCH_LBBO, OP_MASK_FMT6AB_OP | OP_MASK_LOADSTORE, 0, |
| 169 | unsigned_immed8_overflow}, |
| 170 | { "sbbo", prui_sbbo, "D,S,b,l", |
| 171 | OP_MATCH_SBBO, OP_MASK_FMT6AB_OP | OP_MASK_LOADSTORE, 0, |
| 172 | unsigned_immed8_overflow}, |
| 173 | { "lbco", prui_lbco, "D,c,b,l", |
| 174 | OP_MATCH_LBCO, OP_MASK_FMT6CD_OP | OP_MASK_LOADSTORE, 0, |
| 175 | unsigned_immed8_overflow}, |
| 176 | { "sbco", prui_sbco, "D,c,b,l", |
| 177 | OP_MATCH_SBCO, OP_MASK_FMT6CD_OP | OP_MASK_LOADSTORE, 0, |
| 178 | unsigned_immed8_overflow}, |
| 179 | |
| 180 | /* Fill in the default values for the real-instruction arguments. |
| 181 | The assembler will not do it! */ |
| 182 | { "nop", prui_or, "", |
| 183 | OP_MATCH_OR |
| 184 | | (RSEL_31_0 << OP_SH_RS2SEL) | (0 << OP_SH_RS2) |
| 185 | | (RSEL_31_0 << OP_SH_RS1SEL) | (0 << OP_SH_RS1) |
| 186 | | (RSEL_31_0 << OP_SH_RDSEL) | (0 << OP_SH_RD), |
| 187 | OP_MASK_FMT1_OP | OP_MASK_SUBOP |
| 188 | | OP_MASK_RS2SEL | OP_MASK_RS2 | OP_MASK_RS1SEL | OP_MASK_RS1 |
| 189 | | OP_MASK_RDSEL | OP_MASK_RD | OP_MASK_IO, |
| 190 | PRU_INSN_MACRO, no_overflow}, |
| 191 | { "mov", prui_or, "d,s", |
| 192 | OP_MATCH_OR | (0 << OP_SH_IMM8) | OP_MASK_IO, |
| 193 | OP_MASK_FMT1_OP | OP_MASK_SUBOP | OP_MASK_IMM8 | OP_MASK_IO, |
| 194 | PRU_INSN_MACRO, no_overflow}, |
| 195 | { "ret", prui_jmp, "", |
| 196 | OP_MATCH_JMP |
| 197 | | (RSEL_31_16 << OP_SH_RS2SEL) | (3 << OP_SH_RS2), |
| 198 | OP_MASK_FMT2_OP | OP_MASK_SUBOP |
| 199 | | OP_MASK_RS2SEL | OP_MASK_RS2 | OP_MASK_IO, |
| 200 | PRU_INSN_MACRO, unsigned_immed16_overflow}, |
| 201 | { "call", prui_jal, "j", |
| 202 | OP_MATCH_JAL |
| 203 | | (RSEL_31_16 << OP_SH_RDSEL) | (3 << OP_SH_RD), |
| 204 | OP_MASK_FMT2_OP | OP_MASK_SUBOP |
| 205 | | OP_MASK_RDSEL | OP_MASK_RD, |
| 206 | PRU_INSN_MACRO, unsigned_immed16_overflow}, |
| 207 | |
| 208 | { "wbc", prui_qbbs, "s,b", |
| 209 | OP_MATCH_QBBS | (0 << OP_SH_BROFF98) | (0 << OP_SH_BROFF70), |
| 210 | OP_MASK_FMT5_OP | OP_MASK_BCMP | OP_MASK_BROFF, |
| 211 | PRU_INSN_MACRO, qbranch_target_overflow}, |
| 212 | { "wbs", prui_qbbc, "s,b", |
| 213 | OP_MATCH_QBBC | (0 << OP_SH_BROFF98) | (0 << OP_SH_BROFF70), |
| 214 | OP_MASK_FMT5_OP | OP_MASK_BCMP | OP_MASK_BROFF, |
| 215 | PRU_INSN_MACRO, qbranch_target_overflow}, |
| 216 | |
| 217 | { "fill", prui_xin, "D,n", |
| 218 | OP_MATCH_XIN | (254 << OP_SH_XFR_WBA), |
| 219 | OP_MASK_XFR_OP | OP_MASK_XFR_WBA, |
| 220 | PRU_INSN_MACRO, unsigned_immed8_overflow}, |
| 221 | { "zero", prui_xin, "D,n", |
| 222 | OP_MATCH_XIN | (255 << OP_SH_XFR_WBA), |
| 223 | OP_MASK_XFR_OP | OP_MASK_XFR_WBA, |
| 224 | PRU_INSN_MACRO, unsigned_immed8_overflow}, |
| 225 | |
| 226 | { "ldi32", prui_ldi, "R,i", |
| 227 | OP_MATCH_LDI, OP_MASK_FMT2_OP | OP_MASK_SUBOP, |
| 228 | PRU_INSN_LDI32, unsigned_immed32_overflow}, |
| 229 | }; |
| 230 | |
| 231 | #define PRU_NUM_OPCODES \ |
| 232 | ((sizeof pru_opcodes) / (sizeof (pru_opcodes[0]))) |
| 233 | const int bfd_pru_num_opcodes = PRU_NUM_OPCODES; |
| 234 | |
| 235 | #undef PRU_NUM_OPCODES |