Commit | Line | Data |
---|---|---|
35c08157 | 1 | /* NDS32-specific support for 32-bit ELF. |
4b95cf5c | 2 | Copyright (C) 2012-2014 Free Software Foundation, Inc. |
35c08157 KLC |
3 | Contributed by Andes Technology Corporation. |
4 | ||
5 | This file is part of BFD, the Binary File Descriptor library. | |
6 | ||
7 | This program 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 of the License, or | |
10 | (at your option) any later version. | |
11 | ||
12 | This program is distributed in the hope that it will be useful, | |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | GNU General Public License for more details. | |
16 | ||
17 | You should have received a copy of the GNU General Public License | |
18 | along with this program; if not, write to the Free Software | |
19 | Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA | |
20 | 02110-1301, USA.*/ | |
21 | ||
22 | ||
23 | #include "sysdep.h" | |
24 | #include <stdio.h> | |
25 | #include "ansidecl.h" | |
26 | #include "dis-asm.h" | |
27 | #include "bfd.h" | |
28 | #include "symcat.h" | |
29 | #include "libiberty.h" | |
30 | #include "opintl.h" | |
31 | #include "bfd_stdint.h" | |
32 | ||
33 | #define __MF(v, off, bs) ((v & ((1 << (bs)) - 1)) << (off)) | |
34 | #define __GF(v, off, bs) ((v >> (off)) & ((1 << (bs)) - 1)) | |
35 | #define __PF(v, off, bs, val) do { v = __put_field (v, off, bs, val); } while (0) | |
36 | /* #define __SEXT(v, bs) ((v ^ (1 << (bs - 1))) - (1 << (bs - 1))) */ | |
37 | #define __SEXT(v, bs) (((v & ((1 << bs) - 1)) ^ (1 << (bs - 1))) - (1 << (bs - 1))) | |
38 | #define __BIT(n) (1 << n) | |
39 | ||
40 | /* Get fields */ | |
41 | #define OP6(insn) ((insn >> 25) & 0x3F) | |
42 | #define RT5(insn) ((insn >> 20) & 0x1F) | |
43 | #define RA5(insn) ((insn >> 15) & 0x1F) | |
44 | #define RB5(insn) ((insn >> 10) & 0x1F) | |
45 | #define RD5(insn) ((insn >> 5) & 0x1F) | |
46 | #define SUB5(insn) ((insn >> 0) & 0x1F) | |
47 | #define SUB10(insn) ((insn >> 0) & 0x3FF) | |
48 | #define IMMU(insn, bs) (insn & ((1 << bs) - 1)) | |
49 | #define IMMS(insn, bs) __SEXT ((insn & ((1 << bs) - 1)), bs) | |
50 | #define IMM1U(insn) IMMU ((insn >> 10), 5) | |
51 | #define IMM1S(insn) IMMS ((insn >> 10), 5) | |
52 | #define IMM2U(insn) IMMU ((insn >> 5), 5) | |
53 | #define IMM2S(insn) IMMS ((insn >> 5), 5) | |
54 | ||
55 | /* Default text to print if an instruction isn't recognized. */ | |
56 | #define UNKNOWN_INSN_MSG _("*unknown*") | |
57 | ||
58 | static const char *mnemonic_op6[] = | |
59 | { | |
60 | "lbi", "lhi", "lwi", "ldi", "lbi.bi", "lhi.bi", "lwi.bi", "ldi.bi", | |
61 | "sbi", "shi", "swi", "sdi", "sbi.bi", "shi.bi", "swi.bi", "sdi.bi", | |
62 | "lbsi", "lhsi", "lwsi", "dprefi", "lbsi.bi", "lhsi.bi", "lwsi.bi", "lbgp", | |
63 | "lwc", "swc", "ldc", "sdc", "mem", "lsmw", "hwgp", "sbgp", | |
64 | "alu1", "alu2", "movi", "sethi", "ji", "jreg", "br1", "br2", | |
65 | "addi", "subri", "andi", "xori", "ori", "br3", "slti", "sltsi", | |
66 | "aext", "cext", "misc", "bitci", "op_64", "cop" | |
67 | }; | |
68 | ||
69 | static const char *mnemonic_mem[] = | |
70 | { | |
71 | "lb", "lh", "lw", "ld", "lb.bi", "lh.bi", "lw.bi", "ld.bi", | |
72 | "sb", "sh", "sw", "sd", "sb.bi", "sh.bi", "sw.bi", "sd.bi", | |
73 | "lbs", "lhs", "lws", "dpref", "lbs.bi", "lhs.bi", "lws.bi", "27", | |
74 | "llw", "scw", "32", "33", "34", "35", "36", "37", | |
75 | "lbup", "41", "lwup", "43", "44", "45", "46", "47", | |
76 | "sbup", "51", "swup" | |
77 | }; | |
78 | ||
79 | static const char *mnemonic_alu1[] = | |
80 | { | |
81 | "add", "sub", "and", "xor", "or", "nor", "slt", "slts", | |
82 | "slli", "srli", "srai", "rotri", "sll", "srl", "sra", "rotr", | |
83 | "seb", "seh", "bitc", "zeh", "wsbh", "or_srli", "divsr", "divr", | |
84 | "sva", "svs", "cmovz", "cmovn", "add_srli", "sub_srli", "and_srli", "xor_srli" | |
85 | }; | |
86 | ||
87 | ||
88 | static const char *mnemonic_alu20[] = | |
89 | { | |
90 | "max", "min", "ave", "abs", "clips", "clip", "clo", "clz", | |
91 | "bset", "bclr", "btgl", "btst", "bse", "bsp", "ffb", "ffmism", | |
92 | "add.sc", "sub.sc", "add.wc", "sub.wc", "24", "25", "26", "ffzmism", | |
93 | "qadd", "qsub", "32", "33", "34", "35", "36", "37", | |
94 | "mfusr", "mtusr", "42", "43", "mul", "45", "46", "47", | |
95 | "mults64", "mult64", "madds64", "madd64", "msubs64", "msub64", "divs", "div", | |
96 | "60", "mult32", "62", "madd32", "64", "msub32", "65", "66", | |
97 | "dmadd", "dmaddc", "dmsub", "dmsubc", "rmfhi", "qmflo" | |
98 | }; | |
99 | ||
100 | static const char *mnemonic_alu21[] = | |
101 | { | |
102 | "00", "01", "02", "03", "04", "05", "06", "07", | |
103 | "10", "11", "12", "13", "14", "15", "ffbi", "flmism", | |
104 | "20", "21", "22", "23", "24", "25", "26", "27", | |
105 | "30", "31", "32", "33", "34", "35", "36", "37", | |
106 | "40", "41", "42", "43", "44", "45", "46", "47", | |
107 | "mulsr64", "mulr64", "52", "53", "54", "55", "56", "57", | |
108 | "60", "61", "62", "maddr32", "64", "msubr32", "66", "67", | |
109 | "70", "71", "72", "73", "74", "75", "76", "77" | |
110 | }; | |
111 | ||
112 | static const char *mnemonic_br2[] = | |
113 | { | |
114 | "ifcall", "01", "beqz", "bnez", "bgez", "bltz", "bgtz", "blez", | |
115 | "10", "11", "12", "13", "bgezal", "bltzal" | |
116 | }; | |
117 | ||
118 | static const char *mnemonic_misc[] = | |
119 | { | |
120 | "standby", "cctl", "mfsr", "mtsr", "iret", "trap", "teqz", "tnez", | |
121 | "dsb", "isb", "break", "syscall", "msync", "isync", "tlbop" | |
122 | }; | |
123 | ||
124 | static const char *mnemonic_hwgp[] = | |
125 | { | |
126 | "lhi.gp", "lhi.gp", "lhsi.gp", "lhsi.gp", | |
127 | "shi.gp", "shi.gp", "lwi.gp", "swi.gp" | |
128 | }; | |
129 | ||
130 | static const char *keyword_dpref[] = | |
131 | { | |
132 | "SRD", "MRD", "SWR", "MWR", "PTE", "CLWR", "6", "7", | |
133 | "8", "9", "10", "11", "12", "13", "14", "15" | |
134 | }; | |
135 | ||
136 | static const char *mnemonic_alu[] = | |
137 | { | |
138 | "fadds", "fsubs", "fcpynss", "fcpyss", "fmadds", | |
139 | "fmsubs", "fcmovns", "fcmovzs", "fnmadds", "fnmsubs", | |
140 | "10", "11", "fmuls", "fdivs", "faddd", | |
141 | "fsubd", "fcpynsd", "fcpysd", "fmaddd", "fmsubd", | |
142 | "fcmovnd", "fcmovzd", "fnmaddd", "fnmsubd", "24", | |
143 | "25", "fmuld", "fdivd" | |
144 | }; | |
145 | ||
146 | static const char *mnemonic_fpu_2op[] = | |
147 | { | |
148 | "fs2d", "fsqrts", "2", "3", "4", "fabss", "6", "7", | |
149 | "fui2s", "9", "10", "11", "fsi2s", "13", "14", "15", | |
150 | "fs2ui", "17", "18", "19", "fs2ui.z", "21", "22", "23", | |
151 | "fs2si", "25", "26", "27", "fs2si.z", "fd2s", "fsqrtd", "31", | |
152 | "32", "33", "fabsd", "35", "36", "fui2d", "38", "39", | |
153 | "40", "fsi2d", "42", "43", "44", "fd2ui", "46", "47", | |
154 | "48", "fd2ui.z", "50", "51", "52", "fd2si", "54", "55", | |
155 | "56", "fd2si.z" | |
156 | }; | |
157 | ||
158 | static const char *mnemonic_fs2_cmp[] = | |
159 | { | |
160 | "fcmpeqs", "fcmpeqs.e", "fcmplts", "fcmplts.e", | |
161 | "fcmples", "fcmples.e", "fcmpuns", "fcmpuns.e" | |
162 | }; | |
163 | ||
164 | static const char *mnemonic_fd2_cmp[] = | |
165 | { | |
166 | "fcmpeqd", "fcmpeqd.e", "fcmpltd", "fcmpltd.e", | |
167 | "fcmpled", "fcmpled.e", "fcmpund", "fcmpund.e" | |
168 | }; | |
169 | ||
6b9d3259 KLC |
170 | /* Register name table. */ |
171 | /* General purpose register. */ | |
172 | ||
35c08157 KLC |
173 | static const char *gpr_map[] = |
174 | { | |
175 | "$r0", "$r1", "$r2", "$r3", "$r4", "$r5", "$r6", "$r7", | |
176 | "$r8", "$r9", "$r10", "$r11", "$r12", "$r13", "$r14", "$r15", | |
177 | "$r16", "$r17", "$r18", "$r19", "$r20", "$r21", "$r22", "$r23", | |
178 | "$r24", "$r25", "$r26", "$r27", "$fp", "$gp", "$lp", "$sp" | |
179 | }; | |
180 | ||
6b9d3259 KLC |
181 | /* User special register. */ |
182 | ||
35c08157 KLC |
183 | static const char *usr_map[][32] = |
184 | { | |
185 | { | |
6b9d3259 | 186 | "d0.lo", "d0.hi", "d1.lo", "d1.hi", "4", "5", "6", "7", |
35c08157 KLC |
187 | "8", "9", "10", "11", "12", "13", "14", "15", |
188 | "16", "17", "18", "19", "20", "21", "22", "23", | |
189 | "24", "25", "26", "27", "28", "29", "30", "pc" | |
190 | }, | |
191 | { | |
192 | "DMA_CFG", "DMA_GCSW", "DMA_CHNSEL", "DMA_ACT", "DMA_SETUP", | |
193 | "DMA_ISADDR", "DMA_ESADDR", "DMA_TCNT", "DMA_STATUS", "DMA_2DSET", | |
194 | "10", "11", "12", "13", "14", | |
6b9d3259 KLC |
195 | "15", "16", "17", "18", "19", |
196 | "20", "21", "22", "23", "24", | |
35c08157 KLC |
197 | "DMA_2DSCTL" |
198 | }, | |
199 | { | |
6b9d3259 KLC |
200 | "PFMC0", "PFMC1", "PFMC2", "3", "PFM_CTL" |
201 | } | |
202 | }; | |
203 | ||
204 | /* System register. */ | |
205 | /* Major Minor Extension. */ | |
206 | static const char *sr_map[8][16][8] = | |
207 | { | |
208 | { | |
209 | {"CPU_VER", "CORE_ID"}, | |
210 | {"ICM_CFG"}, | |
211 | {"DCM_CFG"}, | |
212 | {"MMU_CFG"}, | |
213 | {"MSC_CFG"} | |
214 | }, | |
215 | { | |
216 | {"PSW", "IPSW", "P_IPSW"}, | |
217 | {"0", "IVB", "INT_CTRL"}, | |
218 | {"0", "EVA", "P_EVA"}, | |
219 | {"0", "ITYPE", "P_ITYPE"}, | |
220 | {"0", "MERR"}, | |
221 | {"0", "IPC", "P_IPC", "OIPC"}, | |
222 | {"0", "1", "P_P0"}, | |
223 | {"0", "1", "P_P1"}, | |
224 | {"INT_MASK", "INT_MASK2"}, | |
225 | {"INT_PEND", "INT_PEND2", "2", "3", "INT_TRIGGER"}, | |
226 | {"SP_USR", "SP_PRIV"}, | |
227 | {"INT_PRI", "INT_PRI2"} | |
228 | }, | |
229 | { | |
230 | {"MMU_CTL"}, | |
231 | {"L1_PPTB"}, | |
232 | {"TLB_VPN"}, | |
233 | {"TLB_DATA"}, | |
234 | {"TLB_MISC"}, | |
235 | {"VLPT_IDX"}, | |
236 | {"ILMB"}, | |
237 | {"DLMB"}, | |
238 | {"CACHE_CTL"}, | |
239 | {"HSMP_SADDR", "HSMP_EADDR"}, | |
240 | {"0"}, | |
241 | {"0"}, | |
242 | {"0"}, | |
243 | {"0"}, | |
244 | {"0"}, | |
245 | {"SDZ_CTL", "MISC_CTL"} | |
246 | }, | |
247 | { | |
248 | {"BPC0", "BPC1", "BPC2", "BPC3", "BPC4", "BPC5", "BPC6", "BPC7"}, | |
249 | {"BPA0", "BPA1", "BPA2", "BPA3", "BPA4", "BPA5", "BPA6", "BPA7"}, | |
250 | {"BPAM0", "BPAM1", "BPAM2", "BPAM3", "BPAM4", "BPAM5", "BPAM6", "BPAM7"}, | |
251 | {"BPV0", "BPV1", "BPV2", "BPV3", "BPV4", "BPV5", "BPV6", "BPV7"}, | |
252 | {"BPCID0", "BPCID1", "BPCID2", "BPCID3", "BPCID4", "BPCID5", "BPCID6", "BPCID7"}, | |
253 | {"EDM_CFG"}, | |
254 | {"EDMSW"}, | |
255 | {"EDM_CTL"}, | |
256 | {"EDM_DTR"}, | |
257 | {"BPMTC"}, | |
258 | {"DIMBR"}, | |
259 | {"EDM_PROBE"}, | |
260 | {"0"}, | |
261 | {"0"}, | |
262 | {"TECR0", "TECR1"} | |
263 | }, | |
264 | { | |
265 | {"PFMC0", "PFMC1", "PFMC2"}, | |
266 | {"PFM_CTL"}, | |
267 | {"0"}, | |
268 | {"0"}, | |
269 | {"PRUSR_ACC_CTL"}, | |
270 | {"FUCOP_CTL"} | |
271 | }, | |
272 | { | |
273 | {"DMA_CFG"}, | |
274 | {"DMA_GCSW"}, | |
275 | {"DMA_CHNSEL"}, | |
276 | {"DMA_ACT"}, | |
277 | {"DMA_SETUP"}, | |
278 | {"DMA_ISADDR"}, | |
279 | {"DMA_ESADDR"}, | |
280 | {"DMA_TCNT"}, | |
281 | {"DMA_STATUS"}, | |
282 | {"DMA_2DSET", "DMA_2DSCTL"} | |
35c08157 KLC |
283 | } |
284 | }; | |
285 | ||
286 | static void | |
287 | print_insn16 (bfd_vma pc, disassemble_info *info, uint32_t insn) | |
288 | { | |
289 | static char r4map[] = | |
290 | { | |
291 | 0, 1, 2, 3, 4, 5, 6, 7, | |
292 | 8, 9, 10, 11, 16, 17, 18, 19 | |
293 | }; | |
294 | const int rt5 = __GF (insn, 5, 5); | |
295 | const int ra5 = __GF (insn, 0, 5); | |
296 | const int rt4 = r4map[__GF (insn, 5, 4)]; | |
297 | const int imm5u = IMMU (insn, 5); | |
298 | const int imm9u = IMMU (insn, 9); | |
299 | const int rt3 = __GF (insn, 6, 3); | |
300 | const int ra3 = __GF (insn, 3, 3); | |
301 | const int rb3 = __GF (insn, 0, 3); | |
302 | const int rt38 = __GF (insn, 8, 3); | |
303 | const int imm3u = rb3; | |
304 | fprintf_ftype func = info->fprintf_func; | |
305 | void *stream = info->stream; | |
306 | ||
307 | static const char *mnemonic_96[] = | |
308 | { | |
309 | "0x1", "0x1", "0x2", "0x3", | |
310 | "add45", "sub45", "addi45", "subi45", | |
311 | "srai45", "srli45", "slli333", "0xb", | |
312 | "add333", "sub333", "addi333", "subi333", | |
313 | "lwi333", "lwi333.bi", "lhi333", "lbi333", | |
314 | "swi333", "swi333.bi", "shi333", "sbi333", | |
315 | "addri36.sp", "lwi45.fe", "lwi450", "swi450", | |
316 | "0x1c", "0x1d", "0x1e", "0x1f", | |
317 | "0x20", "0x21", "0x22", "0x23", | |
1332de01 | 318 | "0x24", "0x25", "0x26", "0x27", |
35c08157 | 319 | "0x28", "0x29", "0x2a", "0x2b", |
1332de01 | 320 | "0x2c", "0x2d", "0x2e", "0x2f", |
35c08157 KLC |
321 | "slts45", "slt45", "sltsi45", "slti45", |
322 | "0x34", "0x35", "0x36", "0x37", | |
323 | "0x38", "0x39", "0x3a", "0x3b", | |
324 | "ifcall9", "movpi45" | |
325 | }; | |
326 | ||
327 | static const char *mnemonic_misc33[] = | |
328 | { | |
329 | "misc33_0", "misc33_1", "neg33", "not33", "mul33", "xor33", "and33", "or33", | |
330 | }; | |
331 | ||
332 | static const char *mnemonic_0xb[] = | |
333 | { | |
334 | "zeb33", "zeh33", "seb33", "seh33", "xlsb33", "x11b33", "bmski33", "fexti33" | |
335 | }; | |
336 | ||
337 | static const char *mnemonic_bnes38[] = | |
338 | { | |
339 | "jr5", "jral5", "ex9.it", "?", "ret5", "add5.pc" | |
340 | }; | |
341 | ||
342 | switch (__GF (insn, 7, 8)) | |
343 | { | |
344 | case 0xf8: /* push25 */ | |
345 | case 0xf9: /* pop25 */ | |
346 | { | |
347 | uint32_t res[] = { 6, 8, 10, 14 }; | |
348 | uint32_t re = res[__GF (insn, 5, 2)]; | |
349 | ||
350 | func (stream, "%s\t%s, %d", (insn & __BIT (7)) ? "pop25" : "push25", | |
351 | gpr_map[re], imm5u << 3); | |
352 | } | |
353 | return; | |
354 | } | |
355 | ||
356 | if (__GF (insn, 8, 7) == 0x7d) /* movd44 */ | |
357 | { | |
358 | int rt5e = __GF (insn, 4, 4) << 1; | |
359 | int ra5e = IMMU (insn, 4) << 1; | |
360 | ||
361 | func (stream, "movd44\t%s, %d", gpr_map[rt5e], ra5e); | |
362 | return; | |
363 | } | |
364 | ||
365 | switch (__GF (insn, 9, 6)) | |
366 | { | |
367 | case 0x4: /* add45 */ | |
368 | case 0x5: /* sub45 */ | |
369 | case 0x30: /* slts45 */ | |
370 | case 0x31: /* slt45 */ | |
371 | func (stream, "%s\t%s, %s", mnemonic_96[__GF (insn, 9, 6)], | |
372 | gpr_map[rt4], gpr_map[ra5]); | |
373 | return; | |
374 | case 0x6: /* addi45 */ | |
375 | case 0x7: /* subi45 */ | |
376 | case 0x8: /* srai45 */ | |
377 | case 0x9: /* srli45 */ | |
378 | case 0x32: /* sltsi45 */ | |
379 | case 0x33: /* slti45 */ | |
380 | func (stream, "%s\t%s, %d", mnemonic_96[__GF (insn, 9, 6)], | |
381 | gpr_map[rt4], ra5); | |
382 | return; | |
383 | case 0xc: /* add333 */ | |
384 | case 0xd: /* sub333 */ | |
385 | func (stream, "%s\t%s, %s, %s", mnemonic_96[__GF (insn, 9, 6)], | |
386 | gpr_map[rt3], gpr_map[ra3], gpr_map[rb3]); | |
387 | return; | |
388 | case 0xa: /* slli333 */ | |
389 | case 0xe: /* addi333 */ | |
390 | case 0xf: /* subi333 */ | |
391 | func (stream, "%s\t%s, %s, %d", mnemonic_96[__GF (insn, 9, 6)], | |
392 | gpr_map[rt3], gpr_map[ra3], imm3u); | |
393 | return; | |
394 | case 0x10: /* lwi333 */ | |
395 | case 0x14: /* swi333 */ | |
396 | func (stream, "%s\t%s, [%s + %d]", mnemonic_96[__GF (insn, 9, 6)], | |
397 | gpr_map[rt3], gpr_map[ra3], imm3u << 2); | |
398 | return; | |
399 | case 0x12: /* lhi333 */ | |
400 | case 0x16: /* shi333 */ | |
401 | func (stream, "%s\t%s, [%s + %d]", mnemonic_96[__GF (insn, 9, 6)], | |
402 | gpr_map[rt3], gpr_map[ra3], imm3u << 1); | |
403 | return; | |
404 | case 0x13: /* lbi333 */ | |
405 | case 0x17: /* sbi333 */ | |
406 | func (stream, "%s\t%s, [%s + %d]", mnemonic_96[__GF (insn, 9, 6)], | |
407 | gpr_map[rt3], gpr_map[ra3], imm3u); | |
408 | return; | |
409 | case 0x11: /* lwi333.bi */ | |
410 | case 0x15: /* swi333.bi */ | |
411 | func (stream, "%s\t%s, [%s], %d", mnemonic_96[__GF (insn, 9, 6)], | |
412 | gpr_map[rt3], gpr_map[ra3], imm3u << 2); | |
413 | return; | |
414 | case 0x18: /* addri36.sp */ | |
415 | func (stream, "%s\t%s, %d", mnemonic_96[__GF (insn, 9, 6)], | |
416 | gpr_map[rt3], IMMU (insn, 6) << 2); | |
417 | return; | |
418 | case 0x19: /* lwi45.fe */ | |
419 | func (stream, "%s\t%s, %d", mnemonic_96[__GF (insn, 9, 6)], | |
420 | gpr_map[rt4], -((32 - imm5u) << 2)); | |
421 | return; | |
422 | case 0x1a: /* lwi450 */ | |
423 | case 0x1b: /* swi450 */ | |
424 | func (stream, "%s\t%s, [%s]", mnemonic_96[__GF (insn, 9, 6)], | |
425 | gpr_map[rt4], gpr_map[ra5]); | |
426 | return; | |
427 | case 0x34: /* beqzs8, bnezs8 */ | |
428 | func (stream, "%s\t", ((insn & __BIT (8)) ? "bnezs8" : "beqzs8")); | |
429 | info->print_address_func ((IMMS (insn, 8) << 1) + pc, info); | |
430 | return; | |
431 | case 0x35: /* break16, ex9.it */ | |
432 | /* FIXME: Check bfd_mach. */ | |
433 | if (imm9u < 32) /* break16 */ | |
434 | func (stream, "break16\t%d", imm9u); | |
435 | else | |
436 | func (stream, "ex9.it\t%d", imm9u); | |
437 | return; | |
438 | case 0x3c: /* ifcall9 */ | |
439 | func (stream, "%s\t", mnemonic_96[__GF (insn, 9, 6)]); | |
440 | info->print_address_func ((IMMU (insn, 9) << 1) + pc, info); | |
441 | return; | |
442 | case 0x3d: /* movpi45 */ | |
443 | func (stream, "%s\t%s, %d", mnemonic_96[__GF (insn, 9, 6)], | |
444 | gpr_map[rt4], ra5 + 16); | |
445 | return; | |
446 | case 0x3f: /* MISC33 */ | |
447 | func (stream, "%s\t%s, %s", mnemonic_misc33[rb3], | |
448 | gpr_map[rt3], gpr_map[ra3]); | |
449 | return; | |
450 | case 0xb: /* ... */ | |
451 | func (stream, "%s\t%s, %s", mnemonic_0xb[rb3], | |
452 | gpr_map[rt3], gpr_map[ra3]); | |
453 | return; | |
454 | } | |
455 | ||
456 | switch (__GF (insn, 10, 5)) | |
457 | { | |
458 | case 0x0: /* mov55 or ifret16 */ | |
459 | /* FIXME: Check bfd_mach. */ | |
460 | if (rt5 == ra5 && rt5 == 31) | |
461 | func (stream, "ifret16"); | |
462 | else | |
463 | func (stream, "mov55\t%s, %s", gpr_map[rt5], gpr_map[ra5]); | |
464 | return; | |
465 | case 0x1: /* movi55 */ | |
466 | func (stream, "movi55\t%s, %d", gpr_map[rt5], IMMS (insn, 5)); | |
467 | return; | |
468 | case 0x1b: /* addi10s (V2) */ | |
469 | func (stream, "addi10s\t%d", IMMS (insn, 10)); | |
470 | return; | |
471 | } | |
472 | ||
473 | switch (__GF (insn, 11, 4)) | |
474 | { | |
475 | case 0x7: /* lwi37.fp/swi37.fp */ | |
476 | func (stream, "%s\t%s, [$fp + 0x%x]", | |
477 | ((insn & __BIT (7)) ? "swi37" : "lwi37"), | |
478 | gpr_map[rt38], IMMU (insn, 7) << 2); | |
479 | return; | |
480 | case 0x8: /* beqz38 */ | |
481 | case 0x9: /* bnez38 */ | |
482 | func (stream, "%s\t%s, ", | |
483 | ((__GF (insn, 11, 4) & 1) ? "bnez38" : "beqz38"), gpr_map[rt38]); | |
484 | info->print_address_func ((IMMS (insn, 8) << 1) + pc, info); | |
485 | return; | |
486 | case 0xa: /* beqs38/j8, implied r5 */ | |
487 | if (rt38 == 5) | |
488 | { | |
489 | func (stream, "j8\t"); | |
490 | info->print_address_func ((IMMS (insn, 8) << 1) + pc, info); | |
491 | } | |
492 | else | |
493 | { | |
494 | func (stream, "beqs38\t%s, ", gpr_map[rt38]); | |
495 | info->print_address_func ((IMMS (insn, 8) << 1) + pc, info); | |
496 | } | |
497 | return; | |
498 | case 0xb: /* bnes38 and others */ | |
499 | if (rt38 == 5) | |
500 | { | |
501 | switch (__GF (insn, 5, 3)) | |
502 | { | |
503 | case 0: /* jr5 */ | |
504 | case 1: /* jral5 */ | |
505 | case 4: /* ret5 */ | |
506 | func (stream, "%s\t%s", mnemonic_bnes38[__GF (insn, 5, 3)], | |
507 | gpr_map[ra5]); | |
508 | return; | |
509 | case 2: /* ex9.it imm5 */ | |
510 | case 5: /* add5.pc */ | |
511 | func (stream, "%s\t%d", mnemonic_bnes38[__GF (insn, 5, 3)], ra5); | |
512 | return; | |
513 | default: | |
514 | func (stream, UNKNOWN_INSN_MSG); | |
515 | return; | |
516 | } | |
517 | } | |
518 | else | |
519 | { | |
520 | func (stream, "bnes38\t%s", gpr_map[rt3]); | |
521 | info->print_address_func ((IMMS (insn, 8) << 1) + pc, info); | |
522 | } | |
523 | return; | |
524 | case 0xe: /* lwi37/swi37 */ | |
525 | func (stream, "%s\t%s, [+ 0x%x]", | |
526 | ((insn & __BIT (7)) ? "swi37.sp" : "lwi37.sp"), | |
527 | gpr_map[rt38], IMMU (insn, 7) << 2); | |
528 | return; | |
529 | } | |
530 | } | |
531 | ||
532 | ||
533 | static void | |
534 | print_insn32_mem (bfd_vma pc ATTRIBUTE_UNUSED, disassemble_info *info, | |
535 | uint32_t insn) | |
536 | { | |
537 | const int rt = RT5 (insn); | |
538 | const int ra = RA5 (insn); | |
539 | const int rb = RB5 (insn); | |
540 | const int sv = __GF (insn, 8, 2); | |
541 | const int op = insn & 0xFF; | |
542 | fprintf_ftype func = info->fprintf_func; | |
543 | void *stream = info->stream; | |
544 | ||
545 | switch (op) | |
546 | { | |
547 | case 0x0: /* lb */ | |
548 | case 0x1: /* lh */ | |
549 | case 0x2: /* lw */ | |
550 | case 0x3: /* ld */ | |
551 | case 0x8: /* sb */ | |
552 | case 0x9: /* sh */ | |
553 | case 0xa: /* sw */ | |
554 | case 0xb: /* sd */ | |
555 | case 0x10: /* lbs */ | |
556 | case 0x11: /* lhs */ | |
557 | case 0x12: /* lws */ | |
558 | case 0x18: /* llw */ | |
559 | case 0x19: /* scw */ | |
560 | case 0x20: /* lbup */ | |
561 | case 0x22: /* lwup */ | |
562 | case 0x28: /* sbup */ | |
563 | case 0x2a: /* swup */ | |
564 | func (stream, "%s\t%s, [%s + (%s << %d)]", | |
565 | mnemonic_mem[op], gpr_map[rt], gpr_map[ra], gpr_map[rb], sv); | |
566 | break; | |
567 | case 0x4: /* lb.bi */ | |
568 | case 0x5: /* lh.bi */ | |
569 | case 0x6: /* lw.bi */ | |
570 | case 0x7: /* ld.bi */ | |
571 | case 0xc: /* sb.bi */ | |
572 | case 0xd: /* sh.bi */ | |
573 | case 0xe: /* sw.bi */ | |
574 | case 0xf: /* sd.bi */ | |
575 | case 0x14: /* lbs.bi */ | |
576 | case 0x15: /* lhs.bi */ | |
577 | case 0x16: /* lws.bi */ | |
578 | func (stream, "%s\t%s, [%s], (%s << %d)", | |
579 | mnemonic_mem[op], gpr_map[rt], gpr_map[ra], gpr_map[rb], sv); | |
580 | break; | |
581 | case 0x13: /* dpref */ | |
582 | { | |
583 | const char *subtype = "???"; | |
584 | ||
585 | if ((rt & 0xf) < ARRAY_SIZE (keyword_dpref)) | |
586 | subtype = keyword_dpref[rt & 0xf]; | |
587 | ||
588 | func (stream, "%s\t%s, [%s + (%s << %d)]", | |
589 | "dpref", subtype, gpr_map[ra], gpr_map[rb], sv); | |
590 | } | |
591 | break; | |
592 | default: | |
593 | func (stream, UNKNOWN_INSN_MSG); | |
594 | return; | |
595 | } | |
596 | } | |
597 | ||
598 | static void | |
599 | print_insn32_alu1 (bfd_vma pc ATTRIBUTE_UNUSED, disassemble_info *info, uint32_t insn) | |
600 | { | |
601 | int op = insn & 0x1f; | |
602 | const int rt = RT5 (insn); | |
603 | const int ra = RA5 (insn); | |
604 | const int rb = RB5 (insn); | |
605 | const int rd = RD5 (insn); | |
606 | fprintf_ftype func = info->fprintf_func; | |
607 | void *stream = info->stream; | |
608 | ||
609 | switch (op) | |
610 | { | |
611 | case 0x0: /* add, add_slli */ | |
612 | case 0x1: /* sub, sub_slli */ | |
613 | case 0x2: /* and, add_slli */ | |
614 | case 0x3: /* xor, xor_slli */ | |
615 | case 0x4: /* or, or_slli */ | |
616 | if (rd != 0) | |
617 | { | |
618 | func (stream, "%s_slli\t%s, %s, %s, #%d", | |
619 | mnemonic_alu1[op], gpr_map[rt], gpr_map[ra], gpr_map[rb], rd); | |
620 | } | |
621 | else | |
622 | { | |
623 | func (stream, "%s\t%s, %s, %s", | |
624 | mnemonic_alu1[op], gpr_map[rt], gpr_map[ra], gpr_map[rb]); | |
625 | } | |
626 | return; | |
627 | case 0x1c: /* add_srli */ | |
628 | case 0x1d: /* sub_srli */ | |
629 | case 0x1e: /* and_srli */ | |
630 | case 0x1f: /* xor_srli */ | |
631 | case 0x15: /* or_srli */ | |
632 | func (stream, "%s\t%s, %s, %s, #%d", | |
633 | mnemonic_alu1[op], gpr_map[rt], gpr_map[ra], gpr_map[rb], rd); | |
634 | return; | |
635 | case 0x5: /* nor */ | |
636 | case 0x6: /* slt */ | |
637 | case 0x7: /* slts */ | |
638 | case 0xc: /* sll */ | |
639 | case 0xd: /* srl */ | |
640 | case 0xe: /* sra */ | |
641 | case 0xf: /* rotr */ | |
642 | case 0x12: /* bitc */ | |
643 | case 0x18: /* sva */ | |
644 | case 0x19: /* svs */ | |
645 | case 0x1a: /* cmovz */ | |
646 | case 0x1b: /* cmovn */ | |
647 | func (stream, "%s\t%s, %s, %s", | |
648 | mnemonic_alu1[op], gpr_map[rt], gpr_map[ra], gpr_map[rb]); | |
649 | return; | |
650 | case 0x9: /* srli */ | |
651 | if (ra ==0 && rb == 0 && rb==0) | |
652 | { | |
653 | func (stream, "nop"); | |
654 | return; | |
655 | } | |
656 | case 0x8: /* slli */ | |
657 | case 0xa: /* srai */ | |
658 | case 0xb: /* rotri */ | |
659 | func (stream, "%s\t%s, %s, #%d", | |
660 | mnemonic_alu1[op], gpr_map[rt], gpr_map[ra], rb); | |
661 | return; | |
662 | case 0x10: /* seb */ | |
663 | case 0x11: /* seh */ | |
664 | case 0x13: /* zeh */ | |
665 | case 0x14: /* wsbh */ | |
666 | func (stream, "%s\t%s, %s", | |
667 | mnemonic_alu1[op], gpr_map[rt], gpr_map[ra]); | |
668 | return; | |
669 | case 0x16: /* divsr */ | |
670 | case 0x17: /* divr */ | |
671 | func (stream, "%s\t%s, %s, %s, %s", | |
672 | mnemonic_alu1[op], gpr_map[rt], gpr_map[rd], gpr_map[ra], gpr_map[rb]); | |
673 | return; | |
674 | default: | |
675 | func (stream, UNKNOWN_INSN_MSG); | |
676 | return; | |
677 | } | |
678 | ||
679 | return; | |
680 | } | |
681 | ||
682 | static void | |
683 | print_insn32_alu2 (bfd_vma pc ATTRIBUTE_UNUSED, | |
684 | disassemble_info *info, | |
685 | uint32_t insn) | |
686 | { | |
687 | int op = insn & 0x3ff; | |
688 | const int rt = RT5 (insn); | |
689 | const int ra = RA5 (insn); | |
690 | const int rb = RB5 (insn); | |
691 | fprintf_ftype func = info->fprintf_func; | |
692 | void *stream = info->stream; | |
693 | ||
694 | if ((insn & 0x7f) == 0x4e) /* ffbi */ | |
695 | { | |
696 | func (stream, "ffbi\t%s, %s, #0x%x", | |
697 | gpr_map[rt], gpr_map[ra], __GF (insn, 7, 8)); | |
698 | return; | |
699 | } | |
700 | ||
701 | switch (op) | |
702 | { | |
703 | case 0x0: /* max */ | |
704 | case 0x1: /* min */ | |
705 | case 0x2: /* ave */ | |
706 | case 0xc: /* bse */ | |
707 | case 0xd: /* bsp */ | |
708 | case 0xe: /* ffb */ | |
709 | case 0xf: /* ffmism */ | |
710 | case 0x17: /* ffzmism */ | |
711 | case 0x24: /* mul */ | |
712 | func (stream, "%s\t%s, %s, %s", mnemonic_alu20[op], | |
713 | gpr_map[rt], gpr_map[ra], gpr_map[rb]); | |
714 | return; | |
715 | ||
716 | case 0x3: /* abs */ | |
717 | case 0x6: /* clo */ | |
718 | case 0x7: /* clz */ | |
719 | func (stream, "%s\t%s, %s", mnemonic_alu20[op], gpr_map[rt], gpr_map[ra]); | |
720 | return; | |
721 | ||
722 | case 0x4: /* clips */ | |
723 | case 0x5: /* clip */ | |
724 | case 0x8: /* bset */ | |
725 | case 0x9: /* bclr */ | |
726 | case 0xa: /* btgl */ | |
727 | case 0xb: /* btst */ | |
728 | func (stream, "%s\t%s, %s, #%d", mnemonic_alu20[op], | |
729 | gpr_map[rt], gpr_map[ra], IMM1U (insn)); | |
730 | return; | |
731 | ||
732 | case 0x20: /* mfusr */ | |
733 | case 0x21: /* mtusr */ | |
734 | func (stream, "%s\t%s, $%s", mnemonic_alu20[op], | |
735 | gpr_map[rt], usr_map[__GF (insn, 10, 5)][__GF (insn, 15, 5)]); | |
736 | return; | |
737 | case 0x28: /* mults64 */ | |
738 | case 0x29: /* mult64 */ | |
739 | case 0x2a: /* madds64 */ | |
740 | case 0x2b: /* madd64 */ | |
741 | case 0x2c: /* msubs64 */ | |
742 | case 0x2d: /* msub64 */ | |
743 | case 0x2e: /* divs */ | |
744 | case 0x2f: /* div */ | |
745 | case 0x31: /* mult32 */ | |
746 | case 0x33: /* madd32 */ | |
747 | case 0x35: /* msub32 */ | |
748 | func (stream, "%s\t$d%d, %s, %s", mnemonic_alu20[op], | |
749 | rt >> 1, gpr_map[ra], gpr_map[rb]); | |
750 | return; | |
751 | ||
752 | case 0x4f: /* flmism */ | |
753 | case 0x68: /* mulsr64 */ | |
754 | case 0x69: /* mulr64 */ | |
755 | case 0x73: /* maddr32 */ | |
756 | case 0x75: /* msubr32 */ | |
757 | op = insn & 0x3f; | |
758 | func (stream, "%s\t%s, %s, %s", mnemonic_alu21[op], | |
759 | gpr_map[rt], gpr_map[ra], gpr_map[rb]); | |
760 | return; | |
761 | default: | |
762 | func (stream, UNKNOWN_INSN_MSG); | |
763 | return; | |
764 | } | |
765 | } | |
766 | ||
767 | static void | |
768 | print_insn32_jreg (bfd_vma pc ATTRIBUTE_UNUSED, disassemble_info *info, uint32_t insn) | |
769 | { | |
770 | int op = insn & 0xff; | |
771 | const int rt = RT5 (insn); | |
772 | const int rb = RB5 (insn); | |
773 | const char *dtit_on[] = { "", ".iton", ".dton", ".ton" }; | |
774 | const char *dtit_off[] = { "", ".itoff", ".dtoff", ".toff" }; | |
775 | const char *mnemonic_jreg[] = { "jr", "jral", "jrnez", "jralnez" }; | |
776 | const char *mnemonic_ret[] = { "jr", "ret", NULL, "ifret" }; | |
777 | const int dtit = __GF (insn, 8, 2); | |
778 | fprintf_ftype func = info->fprintf_func; | |
779 | void *stream = info->stream; | |
780 | ||
781 | switch (op) | |
782 | { | |
783 | case 0: /* jr */ | |
784 | func (stream, "%s%s\t%s", mnemonic_ret[op >> 5], | |
785 | dtit_on[dtit], gpr_map[rb]); | |
786 | return; | |
787 | ||
788 | case 0x20: /* ret */ | |
789 | func (stream, "%s%s\t%s", mnemonic_ret[op >> 5], | |
790 | dtit_off[dtit], gpr_map[rb]); | |
791 | return; | |
792 | case 0x60: /* ifret */ | |
793 | break; | |
794 | case 1: /* jral */ | |
795 | case 2: /* jrnez */ | |
796 | case 3: /* jralnez */ | |
797 | func (stream, "%s%s\t%s, %s", mnemonic_jreg[op], | |
798 | dtit_on[dtit], gpr_map[rt], gpr_map[rb]); | |
799 | return; | |
800 | default: /* unknown */ | |
801 | func (stream, UNKNOWN_INSN_MSG); | |
802 | break; | |
803 | } | |
804 | } | |
805 | ||
806 | static void | |
807 | print_insn32_misc (bfd_vma pc ATTRIBUTE_UNUSED, disassemble_info *info, | |
808 | uint32_t insn) | |
809 | { | |
810 | int op = insn & 0x1f; | |
811 | int rt = RT5 (insn); | |
812 | unsigned int id; | |
813 | fprintf_ftype func = info->fprintf_func; | |
814 | void *stream = info->stream; | |
815 | ||
816 | static const char *keyword_standby[] = | |
817 | { | |
818 | "no_wake_grant", "wake_grant", "wait_done", | |
819 | }; | |
820 | static const char *keyword_tlbop[] = | |
821 | { | |
822 | "TRD", "TWR", "RWR", "RWLK", "UNLK", "PB", "INV", "FLUA" | |
823 | }; | |
824 | ||
825 | switch (op) | |
826 | { | |
827 | case 0x0: /* standby */ | |
828 | id = __GF (insn, 5, 20); | |
829 | if (id < ARRAY_SIZE (keyword_standby)) | |
830 | func (stream, "standby\t%s", keyword_standby[id]); | |
831 | else | |
832 | func (stream, "standby\t%d", id); | |
833 | return; | |
834 | case 0x1: /* cctl */ | |
835 | func (stream, "cctl\t!FIXME"); | |
836 | return; | |
837 | case 0x8: /* dsb */ | |
838 | case 0x9: /* isb */ | |
839 | case 0xd: /* isync */ | |
840 | case 0xc: /* msync */ | |
841 | case 0x4: /* iret */ | |
842 | func (stream, "%s", mnemonic_misc[op]); | |
843 | return; | |
844 | case 0x5: /* trap */ | |
845 | case 0xa: /* break */ | |
846 | case 0xb: /* syscall */ | |
847 | id = __GF (insn, 5, 15); | |
848 | func (stream, "%s\t%d", mnemonic_misc[op], id); | |
849 | return; | |
850 | case 0x2: /* mfsr */ | |
851 | case 0x3: /* mtsr */ | |
852 | /* FIXME: setend, setgie. */ | |
6b9d3259 KLC |
853 | func (stream, "%s\t%s, $%s", mnemonic_misc[op], gpr_map[rt], |
854 | sr_map[__GF(insn, 17, 3)][__GF(insn, 13, 4)][__GF(insn, 10, 3)]); | |
35c08157 KLC |
855 | return; |
856 | case 0x6: /* teqz */ | |
857 | case 0x7: /* tnez */ | |
858 | id = __GF (insn, 5, 15); | |
859 | func (stream, "%s\t%s, %d", mnemonic_misc[op], gpr_map[rt], id); | |
860 | return; | |
861 | case 0xe: /* tlbop */ | |
862 | id = __GF (insn, 5, 5); | |
863 | if (id < ARRAY_SIZE (keyword_tlbop)) | |
864 | func (stream, "tlbop\t%s", keyword_tlbop[id]); | |
865 | else | |
866 | func (stream, "tlbop\t%d", id); | |
867 | return; | |
868 | } | |
869 | } | |
870 | ||
871 | static void | |
872 | print_insn32_fpu (bfd_vma pc ATTRIBUTE_UNUSED, disassemble_info *info, | |
873 | uint32_t insn) | |
874 | { | |
875 | int op = insn & 0xf; | |
876 | int mask_sub_op = (insn & 0x3c0) >> 6; | |
877 | int mask_bi = (insn & 0x80) >> 7; | |
878 | int mask_cfg = (insn & 0x7c00) >> 10; | |
879 | int mask_f2op = (insn & 0x7c00) >> 10; | |
880 | int dp = 0; | |
881 | int dp_insn = 0; | |
882 | char wd = 's'; | |
883 | const int rt = RT5 (insn); | |
884 | const int ra = RA5 (insn); | |
885 | const int rb = RB5 (insn); | |
886 | const int sv = __GF (insn, 8, 2); | |
887 | fprintf_ftype func = info->fprintf_func; | |
888 | void *stream = info->stream; | |
889 | ||
890 | switch (op) | |
891 | { | |
892 | case 0x0: /* fs1 */ | |
893 | case 0x8: /* fd1 */ | |
894 | dp = (op & 0x8) ? 1 : 0; | |
895 | if (dp) | |
896 | { | |
897 | wd = 'd'; | |
898 | dp_insn = 14; | |
899 | } | |
900 | else | |
901 | { | |
902 | wd = 's'; | |
903 | dp_insn = 0; | |
904 | } | |
905 | switch (mask_sub_op) | |
906 | { | |
907 | case 0x0: | |
908 | case 0x1: | |
909 | case 0x2: | |
910 | case 0x3: | |
911 | case 0x4: | |
912 | case 0x5: | |
913 | case 0x8: | |
914 | case 0x9: | |
915 | case 0xc: | |
916 | case 0xd: | |
917 | func (stream, "%s\t$f%c%d, $f%c%d, $f%c%d", | |
918 | mnemonic_alu[mask_sub_op + dp_insn], | |
919 | wd, rt, wd, ra, wd, rb); | |
920 | return; | |
921 | case 0x6: | |
922 | case 0x7: | |
923 | func (stream, "%s\t$f%c%d, $f%c%d, $fs%d", | |
924 | mnemonic_alu[mask_sub_op + dp_insn], | |
925 | wd, rt, wd, ra, rb); | |
926 | return; | |
927 | case 0xf: | |
928 | if (dp) | |
929 | { | |
930 | wd = 'd'; | |
931 | dp_insn = 0x1d; | |
932 | } | |
933 | else | |
934 | { | |
935 | wd = 's'; | |
936 | dp_insn = 0; | |
937 | } | |
938 | ||
939 | switch (mask_f2op) | |
940 | { | |
941 | case 0x0: | |
942 | if (dp) | |
943 | func (stream, "%s\t$fs%d, $fd%d", | |
944 | mnemonic_fpu_2op[mask_f2op + dp_insn], rt, ra); | |
945 | else | |
946 | func (stream, "%s\t$fd%d, $fs%d", | |
947 | mnemonic_fpu_2op[mask_f2op + dp_insn], rt, ra); | |
948 | return; | |
949 | case 0x1: | |
950 | case 0x5: | |
951 | func (stream, "%s\t$f%c%d, $f%c%d", | |
952 | mnemonic_fpu_2op[mask_f2op + dp_insn], wd, rt, wd, ra); | |
953 | return; | |
954 | case 0x8: | |
955 | case 0xc: | |
956 | func (stream, "%s\t$f%c%d, $fs%d", | |
957 | mnemonic_fpu_2op[mask_f2op + dp_insn], wd, rt, ra); | |
958 | return; | |
959 | case 0x10: | |
960 | case 0x14: | |
961 | case 0x18: | |
962 | case 0x1c: | |
963 | func (stream, "%s\t$fs%d, $f%c%d", | |
964 | mnemonic_fpu_2op[mask_f2op + dp_insn], rt, wd, ra); | |
965 | return; | |
966 | } | |
967 | } | |
968 | case 0x1: /* mfcp */ | |
969 | switch (mask_sub_op) | |
970 | { | |
971 | case 0x0: | |
972 | func (stream, "fmfsr\t%s, $fs%d", gpr_map[rt], ra); | |
973 | return; | |
974 | case 0x1: | |
975 | func (stream, "fmfdr\t%s, $fd%d", gpr_map[rt], ra); | |
976 | return; | |
977 | case 0xc: | |
978 | if (mask_cfg) | |
979 | func (stream, "fmfcsr\t%s", gpr_map[rt]); | |
980 | else | |
981 | func (stream, "fmfcfg\t%s", gpr_map[rt]); | |
982 | return; | |
983 | } | |
984 | case 0x2: /* fls */ | |
985 | if (mask_bi) | |
986 | func (stream, "fls.bi\t$fs%d, [%s], (%s << %d)", | |
987 | rt, gpr_map[ra], gpr_map[rb], sv); | |
988 | else | |
989 | func (stream, "fls\t$fs%d, [%s + (%s << %d)]", | |
990 | rt, gpr_map[ra], gpr_map[rb], sv); | |
991 | return; | |
992 | case 0x3: /* fld */ | |
993 | if (mask_bi) | |
994 | func (stream, "fld.bi\t$fd%d, [%s], (%s << %d)", | |
995 | rt, gpr_map[ra], gpr_map[rb], sv); | |
996 | else | |
997 | func (stream, "fld\t$fd%d, [%s + (%s << %d)]", | |
998 | rt, gpr_map[ra], gpr_map[rb], sv); | |
999 | return; | |
1000 | case 0x4: /* fs2 */ | |
1001 | func (stream, "%s\t$fs%d, $fs%d, $fs%d", | |
1002 | mnemonic_fs2_cmp[mask_sub_op], rt, ra, rb); | |
1003 | return; | |
1004 | case 0x9: /* mtcp */ | |
1005 | switch (mask_sub_op) | |
1006 | { | |
1007 | case 0x0: | |
1008 | func (stream, "fmtsr\t%s, $fs%d", gpr_map[rt], ra); | |
1009 | return; | |
1010 | case 0x1: | |
1011 | func (stream, "fmtdr\t%s, $fd%d", gpr_map[rt], ra); | |
1012 | return; | |
1013 | case 0xc: | |
1014 | func (stream, "fmtcsr\t%s", gpr_map[rt]); | |
1015 | return; | |
1016 | } | |
1017 | case 0xa: /* fss */ | |
1018 | if (mask_bi) | |
1019 | func (stream, "fss.bi\t$fs%d, [%s], (%s << %d)", | |
1020 | rt, gpr_map[ra], gpr_map[rb], sv); | |
1021 | else | |
1022 | func (stream, "fss\t$fs%d, [%s + (%s << %d)]", | |
1023 | rt, gpr_map[ra], gpr_map[rb], sv); | |
1024 | return; | |
1025 | case 0xb: /* fsd */ | |
1026 | if (mask_bi) | |
1027 | func (stream, "fsd.bi\t$fd%d, [%s], (%s << %d)", | |
1028 | rt, gpr_map[ra], gpr_map[rb], sv); | |
1029 | else | |
1030 | func (stream, "fsd\t$fd%d, [%s + (%s << %d)]", | |
1031 | rt, gpr_map[ra], gpr_map[rb], sv); | |
1032 | return; | |
1033 | case 0xc: /* fd2 */ | |
1034 | func (stream, "%s\t$fs%d, $fd%d, $fd%d", | |
1035 | mnemonic_fd2_cmp[mask_sub_op], rt, ra, rb); | |
1036 | return; | |
1037 | } | |
1038 | } | |
1039 | ||
1040 | static void | |
1041 | print_insn32 (bfd_vma pc, disassemble_info *info, uint32_t insn) | |
1042 | { | |
1043 | int op = OP6 (insn); | |
1044 | const int rt = RT5 (insn); | |
1045 | const int ra = RA5 (insn); | |
1046 | const int rb = RB5 (insn); | |
1047 | const int imm15s = IMMS (insn, 15); | |
1048 | const int imm15u = IMMU (insn, 15); | |
1049 | uint32_t shift; | |
1050 | fprintf_ftype func = info->fprintf_func; | |
1051 | void *stream = info->stream; | |
1052 | ||
1053 | switch (op) | |
1054 | { | |
1055 | case 0x0: /* lbi */ | |
1056 | case 0x1: /* lhi */ | |
1057 | case 0x2: /* lwi */ | |
1058 | case 0x3: /* ldi */ | |
1059 | case 0x8: /* sbi */ | |
1060 | case 0x9: /* shi */ | |
1061 | case 0xa: /* swi */ | |
1062 | case 0xb: /* sdi */ | |
1063 | case 0x10: /* lbsi */ | |
1064 | case 0x11: /* lhsi */ | |
1065 | case 0x12: /* lwsi */ | |
1066 | shift = op & 0x3; | |
1067 | func (stream, "%s\t%s, [%s + #%d]", | |
1068 | mnemonic_op6[op], gpr_map[rt], gpr_map[ra], imm15s << shift); | |
1069 | return; | |
1070 | case 0x4: /* lbi.bi */ | |
1071 | case 0x5: /* lhi.bi */ | |
1072 | case 0x6: /* lwi.bi */ | |
1073 | case 0x7: /* ldi.bi */ | |
1074 | case 0xc: /* sbi.bi */ | |
1075 | case 0xd: /* shi.bi */ | |
1076 | case 0xe: /* swi.bi */ | |
1077 | case 0xf: /* sdi.bi */ | |
1078 | case 0x14: /* lbsi.bi */ | |
1079 | case 0x15: /* lhsi.bi */ | |
1080 | case 0x16: /* lwsi.bi */ | |
1081 | shift = op & 0x3; | |
1082 | func (stream, "%s\t%s, [%s], #%d", | |
1083 | mnemonic_op6[op], gpr_map[rt], gpr_map[ra], imm15s << shift); | |
1084 | return; | |
1085 | case 0x13: /* dprefi */ | |
1086 | { | |
1087 | const char *subtype = "???"; | |
1088 | char wd = 'w'; | |
1089 | ||
1090 | shift = 2; | |
1091 | ||
1092 | /* d-bit */ | |
1093 | if (rt & 0x10) | |
1094 | { | |
1095 | wd = 'd'; | |
1096 | shift = 3; | |
1097 | } | |
1098 | ||
1099 | if ((rt & 0xf) < ARRAY_SIZE (keyword_dpref)) | |
1100 | subtype = keyword_dpref[rt & 0xf]; | |
1101 | ||
1102 | func (stream, "%s.%c\t%s, [%s + #%d]", | |
1103 | mnemonic_op6[op], wd, subtype, gpr_map[ra], imm15s << shift); | |
1104 | } | |
1105 | return; | |
1106 | case 0x17: /* LBGP */ | |
1107 | func (stream, "%s\t%s, [+ %d]", | |
1108 | ((insn & __BIT (19)) ? "lbsi.gp" : "lbi.gp"), | |
1109 | gpr_map[rt], IMMS (insn, 19)); | |
1110 | return; | |
1111 | case 0x18: /* LWC */ | |
1112 | case 0x19: /* SWC */ | |
1113 | case 0x1a: /* LDC */ | |
1114 | case 0x1b: /* SDC */ | |
1115 | if (__GF (insn, 13, 2) == 0) | |
1116 | { | |
1117 | char ls = (op & 1) ? 's' : 'l'; | |
1118 | char wd = (op & 2) ? 'd' : 's'; | |
1119 | ||
1120 | if (insn & __BIT (12)) | |
1121 | { | |
1122 | func (stream, "f%c%ci.bi\t$f%c%d, [%s], %d", ls, wd, | |
1123 | wd, rt, gpr_map[ra], IMMS (insn, 12) << 2); | |
1124 | } | |
1125 | else | |
1126 | { | |
1127 | func (stream, "f%c%ci\t$f%c%d, [%s + %d]", ls, wd, | |
1128 | wd, rt, gpr_map[ra], IMMS (insn, 12) << 2); | |
1129 | } | |
1130 | } | |
1131 | else | |
1132 | { | |
1133 | char ls = (op & 1) ? 's' : 'l'; | |
1134 | char wd = (op & 2) ? 'd' : 'w'; | |
1135 | int cp = __GF (insn, 13, 2); | |
1136 | ||
1137 | if (insn & __BIT (12)) | |
1138 | { | |
1139 | func (stream, "cp%c%ci\tcp%d, $cpr%d, [%s], %d", ls, wd, | |
1140 | cp, rt, gpr_map[ra], IMMS (insn, 12) << 2); | |
1141 | } | |
1142 | else | |
1143 | { | |
1144 | func (stream, "cp%c%ci\tcp%d, $cpr%d, [%s + %d]", ls, wd, | |
1145 | cp, rt, gpr_map[ra], IMMS (insn, 12) << 2); | |
1146 | } | |
1147 | } | |
1148 | return; | |
1149 | case 0x1c: /* MEM */ | |
1150 | print_insn32_mem (pc, info, insn); | |
1151 | return; | |
1152 | case 0x1d: /* LSMW */ | |
1153 | { | |
1154 | int enb4 = __GF (insn, 6, 4); | |
1155 | char ls = (insn & __BIT (5)) ? 's' : 'l'; | |
1156 | char ab = (insn & __BIT (4)) ? 'a' : 'b'; | |
1157 | char *di = (insn & __BIT (3)) ? "d" : "i"; | |
1158 | char *m = (insn & __BIT (2)) ? "m" : ""; | |
1159 | static const char *s[] = {"", "a", "zb", "?"}; | |
1160 | ||
1161 | /* lsmwzb only always increase. */ | |
1162 | if ((insn & 0x3) == 2) | |
1163 | di = ""; | |
1164 | ||
1165 | func (stream, "%cmw%s.%c%s%s\t%s, [%s], %s, 0x%x", | |
1166 | ls, s[insn & 0x3], ab, di, m, gpr_map[rt], | |
1167 | gpr_map[ra], gpr_map[rb], enb4); | |
1168 | } | |
1169 | return; | |
1170 | case 0x1e: /* HWGP */ | |
1171 | op = __GF (insn, 17, 3); | |
1172 | switch (op) | |
1173 | { | |
1174 | case 0: case 1: /* lhi.gp */ | |
1175 | case 2: case 3: /* lhsi.gp */ | |
1176 | case 4: case 5: /* shi.gp */ | |
1177 | func (stream, "%s\t%s, [+ %d]", | |
1178 | mnemonic_hwgp[op], gpr_map[rt], IMMS (insn, 18) << 1); | |
1179 | return; | |
1180 | case 6: /* lwi.gp */ | |
1181 | case 7: /* swi.gp */ | |
1182 | func (stream, "%s\t%s, [+ %d]", | |
1183 | mnemonic_hwgp[op], gpr_map[rt], IMMS (insn, 17) << 2); | |
1184 | return; | |
1185 | } | |
1186 | return; | |
1187 | case 0x1f: /* SBGP */ | |
1188 | if (insn & __BIT (19)) | |
1189 | func (stream, "addi.gp\t%s, %d", | |
1190 | gpr_map[rt], IMMS (insn, 19)); | |
1191 | else | |
1192 | func (stream, "sbi.gp\t%s, [+ %d]", | |
1193 | gpr_map[rt], IMMS (insn, 19)); | |
1194 | return; | |
1195 | case 0x20: /* ALU_1 */ | |
1196 | print_insn32_alu1 (pc, info, insn); | |
1197 | return; | |
1198 | case 0x21: /* ALU_2 */ | |
1199 | print_insn32_alu2 (pc, info, insn); | |
1200 | return; | |
1201 | case 0x22: /* movi */ | |
1202 | func (stream, "movi\t%s, %d", gpr_map[rt], IMMS (insn, 20)); | |
1203 | return; | |
1204 | case 0x23: /* sethi */ | |
1205 | func (stream, "sethi\t%s, 0x%x", gpr_map[rt], IMMU (insn, 20)); | |
1206 | return; | |
1207 | case 0x24: /* ji, jal */ | |
1208 | /* FIXME: Handle relocation. */ | |
1209 | if (info->flags & INSN_HAS_RELOC) | |
1210 | pc = 0; | |
1211 | func (stream, "%s\t", ((insn & __BIT (24)) ? "jal" : "j")); | |
1212 | info->print_address_func ((IMMS (insn, 24) << 1) + pc, info); | |
1213 | return; | |
1214 | case 0x25: /* jreg */ | |
1215 | print_insn32_jreg (pc, info, insn); | |
1216 | return; | |
1217 | case 0x26: /* br1 */ | |
1218 | func (stream, "%s\t%s, %s, ", ((insn & __BIT (14)) ? "bne" : "beq"), | |
1219 | gpr_map[rt], gpr_map[ra]); | |
1220 | info->print_address_func ((IMMS (insn, 14) << 1) + pc, info); | |
1221 | return; | |
1222 | case 0x27: /* br2 */ | |
1223 | func (stream, "%s\t%s, ", mnemonic_br2[__GF (insn, 16, 4)], | |
1224 | gpr_map[rt]); | |
1225 | info->print_address_func ((IMMS (insn, 16) << 1) + pc, info); | |
1226 | return; | |
1227 | case 0x28: /* addi */ | |
1228 | case 0x2e: /* slti */ | |
1229 | case 0x2f: /* sltsi */ | |
1230 | case 0x29: /* subri */ | |
1231 | func (stream, "%s\t%s, %s, %d", | |
1232 | mnemonic_op6[op], gpr_map[rt], gpr_map[ra], imm15s); | |
1233 | return; | |
1234 | case 0x2a: /* andi */ | |
1235 | case 0x2b: /* xori */ | |
1236 | case 0x2c: /* ori */ | |
1237 | case 0x33: /* bitci */ | |
1238 | func (stream, "%s\t%s, %s, %d", | |
1239 | mnemonic_op6[op], gpr_map[rt], gpr_map[ra], imm15u); | |
1240 | return; | |
1241 | case 0x2d: /* br3, beqc, bnec */ | |
1242 | func (stream, "%s\t%s, %d, ", ((insn & __BIT (19)) ? "bnec" : "beqc"), | |
1243 | gpr_map[rt], __SEXT (__GF (insn, 8, 11), 11)); | |
1244 | info->print_address_func ((IMMS (insn, 8) << 1) + pc, info); | |
1245 | return; | |
1246 | case 0x32: /* misc */ | |
1247 | print_insn32_misc (pc, info, insn); | |
1248 | return; | |
1249 | case 0x35: /* FPU */ | |
1250 | print_insn32_fpu (pc, info, insn); | |
1251 | return; | |
1252 | } | |
1253 | } | |
1254 | ||
1255 | int | |
1256 | print_insn_nds32 (bfd_vma pc, disassemble_info *info) | |
1257 | { | |
1258 | int status; | |
1259 | bfd_byte buf[4]; | |
1260 | uint32_t insn; | |
1261 | ||
1262 | status = info->read_memory_func (pc, (bfd_byte *) buf, 2, info); | |
1263 | if (status) | |
1264 | return -1; | |
1265 | ||
1266 | /* 16-bit instruction. */ | |
1267 | if (buf[0] & 0x80) | |
1268 | { | |
1269 | insn = bfd_getb16 (buf); | |
1270 | print_insn16 (pc, info, insn); | |
1271 | return 2; | |
1272 | } | |
1273 | ||
1274 | /* 32-bit instructions. */ | |
1275 | status = info->read_memory_func (pc + 2, (bfd_byte *) buf + 2, 2, info); | |
1276 | if (status) | |
1277 | return -1; | |
1278 | ||
1279 | insn = bfd_getb32 (buf); | |
1280 | print_insn32 (pc, info, insn); | |
1281 | ||
1282 | return 4; | |
1283 | } |