/src/binutils-gdb/opcodes/tic4x-dis.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Print instructions for the Texas TMS320C[34]X, for GDB and GNU Binutils. |
2 | | |
3 | | Copyright (C) 2002-2025 Free Software Foundation, Inc. |
4 | | |
5 | | Contributed by Michael P. Hayes (m.hayes@elec.canterbury.ac.nz) |
6 | | |
7 | | This file is part of the GNU opcodes library. |
8 | | |
9 | | This library is free software; you can redistribute it and/or modify |
10 | | it under the terms of the GNU General Public License as published by |
11 | | the Free Software Foundation; either version 3, or (at your option) |
12 | | any later version. |
13 | | |
14 | | It is distributed in the hope that it will be useful, but WITHOUT |
15 | | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
16 | | or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public |
17 | | License for more details. |
18 | | |
19 | | You should have received a copy of the GNU General Public License |
20 | | along with this program; if not, write to the Free Software |
21 | | Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
22 | | MA 02110-1301, USA. */ |
23 | | |
24 | | #include "sysdep.h" |
25 | | #include <math.h> |
26 | | #include "libiberty.h" |
27 | | #include "disassemble.h" |
28 | | #include "opcode/tic4x.h" |
29 | | |
30 | | #define TIC4X_DEBUG 0 |
31 | | |
32 | 1.60M | #define TIC4X_HASH_SIZE 11 /* 11 (bits) and above should give unique entries. */ |
33 | 383k | #define TIC4X_SPESOP_SIZE 8 /* Max 8. ops for special instructions. */ |
34 | | |
35 | | typedef enum |
36 | | { |
37 | | IMMED_SINT, |
38 | | IMMED_SUINT, |
39 | | IMMED_SFLOAT, |
40 | | IMMED_INT, |
41 | | IMMED_UINT, |
42 | | IMMED_FLOAT |
43 | | } |
44 | | immed_t; |
45 | | |
46 | | typedef enum |
47 | | { |
48 | | INDIRECT_SHORT, |
49 | | INDIRECT_LONG, |
50 | | INDIRECT_TIC4X |
51 | | } |
52 | | indirect_t; |
53 | | |
54 | | static unsigned long tic4x_version = 0; |
55 | | static unsigned int tic4x_dp = 0; |
56 | | static tic4x_inst_t **optab = NULL; |
57 | | static tic4x_inst_t **optab_special = NULL; |
58 | | static const char *registernames[REG_TABLE_SIZE]; |
59 | | |
60 | | static int |
61 | | tic4x_pc_offset (unsigned int op) |
62 | 9.21k | { |
63 | | /* Determine the PC offset for a C[34]x instruction. |
64 | | This could be simplified using some boolean algebra |
65 | | but at the expense of readability. */ |
66 | 9.21k | switch (op >> 24) |
67 | 9.21k | { |
68 | 840 | case 0x60: /* br */ |
69 | 1.67k | case 0x62: /* call (C4x) */ |
70 | 2.52k | case 0x64: /* rptb (C4x) */ |
71 | 2.52k | return 1; |
72 | 1.31k | case 0x61: /* brd */ |
73 | 1.67k | case 0x63: /* laj */ |
74 | 2.42k | case 0x65: /* rptbd (C4x) */ |
75 | 2.42k | return 3; |
76 | 0 | case 0x66: /* swi */ |
77 | 0 | case 0x67: |
78 | 0 | return 0; |
79 | 4.26k | default: |
80 | 4.26k | break; |
81 | 9.21k | } |
82 | | |
83 | 4.26k | switch ((op & 0xffe00000) >> 20) |
84 | 4.26k | { |
85 | 344 | case 0x6a0: /* bB */ |
86 | 984 | case 0x720: /* callB */ |
87 | 984 | case 0x740: /* trapB */ |
88 | 984 | return 1; |
89 | | |
90 | 84 | case 0x6a2: /* bBd */ |
91 | 358 | case 0x6a6: /* bBat */ |
92 | 564 | case 0x6aa: /* bBaf */ |
93 | 830 | case 0x722: /* lajB */ |
94 | 830 | case 0x748: /* latB */ |
95 | 830 | case 0x798: /* rptbd */ |
96 | 830 | return 3; |
97 | | |
98 | 2.45k | default: |
99 | 2.45k | break; |
100 | 4.26k | } |
101 | | |
102 | 2.45k | switch ((op & 0xfe200000) >> 20) |
103 | 2.45k | { |
104 | 1.16k | case 0x6e0: /* dbB */ |
105 | 1.16k | return 1; |
106 | | |
107 | 1.29k | case 0x6e2: /* dbBd */ |
108 | 1.29k | return 3; |
109 | | |
110 | 0 | default: |
111 | 0 | break; |
112 | 2.45k | } |
113 | | |
114 | 0 | return 0; |
115 | 2.45k | } |
116 | | |
117 | | static int |
118 | | tic4x_print_char (struct disassemble_info * info, char ch) |
119 | 1.04M | { |
120 | 1.04M | if (info != NULL) |
121 | 422k | (*info->fprintf_func) (info->stream, "%c", ch); |
122 | 1.04M | return 1; |
123 | 1.04M | } |
124 | | |
125 | | static int |
126 | | tic4x_print_str (struct disassemble_info *info, const char *str) |
127 | 81.5k | { |
128 | 81.5k | if (info != NULL) |
129 | 36.4k | (*info->fprintf_func) (info->stream, "%s", str); |
130 | 81.5k | return 1; |
131 | 81.5k | } |
132 | | |
133 | | static int |
134 | | tic4x_print_register (struct disassemble_info *info, unsigned long regno) |
135 | 254k | { |
136 | 254k | unsigned int i; |
137 | | |
138 | 254k | if (registernames[REG_R0] == NULL) |
139 | 298 | { |
140 | 11.0k | for (i = 0; i < tic3x_num_registers; i++) |
141 | 10.7k | registernames[tic3x_registers[i].regno] = tic3x_registers[i].name; |
142 | 298 | if (IS_CPU_TIC4X (tic4x_version)) |
143 | 208 | { |
144 | | /* Add C4x additional registers, overwriting |
145 | | any C3x registers if necessary. */ |
146 | 2.91k | for (i = 0; i < tic4x_num_registers; i++) |
147 | 2.70k | registernames[tic4x_registers[i].regno] = tic4x_registers[i].name; |
148 | 208 | } |
149 | 298 | } |
150 | 254k | if (regno > (IS_CPU_TIC4X (tic4x_version) ? TIC4X_REG_MAX : TIC3X_REG_MAX)) |
151 | 21.1k | return 0; |
152 | 233k | if (info != NULL) |
153 | 107k | (*info->fprintf_func) (info->stream, "%s", registernames[regno]); |
154 | 233k | return 1; |
155 | 254k | } |
156 | | |
157 | | static int |
158 | | tic4x_print_addr (struct disassemble_info *info, unsigned long addr) |
159 | 16.9k | { |
160 | 16.9k | if (info != NULL) |
161 | 11.6k | (*info->print_address_func)(addr, info); |
162 | 16.9k | return 1; |
163 | 16.9k | } |
164 | | |
165 | | static int |
166 | | tic4x_print_relative (struct disassemble_info *info, |
167 | | unsigned long pc, |
168 | | long offset, |
169 | | unsigned long opcode) |
170 | 9.21k | { |
171 | 9.21k | return tic4x_print_addr (info, pc + offset + tic4x_pc_offset (opcode)); |
172 | 9.21k | } |
173 | | |
174 | | static int |
175 | | tic4x_print_direct (struct disassemble_info *info, unsigned long arg) |
176 | 12.8k | { |
177 | 12.8k | if (info != NULL) |
178 | 6.37k | { |
179 | 6.37k | (*info->fprintf_func) (info->stream, "@"); |
180 | 6.37k | tic4x_print_addr (info, arg + (tic4x_dp << 16)); |
181 | 6.37k | } |
182 | 12.8k | return 1; |
183 | 12.8k | } |
184 | | #if 0 |
185 | | /* FIXME: make the floating point stuff not rely on host |
186 | | floating point arithmetic. */ |
187 | | |
188 | | static void |
189 | | tic4x_print_ftoa (unsigned int val, FILE *stream, fprintf_ftype pfunc) |
190 | | { |
191 | | int e; |
192 | | int s; |
193 | | int f; |
194 | | double num = 0.0; |
195 | | |
196 | | e = EXTRS (val, 31, 24); /* Exponent. */ |
197 | | if (e != -128) |
198 | | { |
199 | | s = EXTRU (val, 23, 23); /* Sign bit. */ |
200 | | f = EXTRU (val, 22, 0); /* Mantissa. */ |
201 | | if (s) |
202 | | f += -2 * (1 << 23); |
203 | | else |
204 | | f += (1 << 23); |
205 | | num = f / (double)(1 << 23); |
206 | | num = ldexp (num, e); |
207 | | } |
208 | | (*pfunc)(stream, "%.9g", num); |
209 | | } |
210 | | #endif |
211 | | |
212 | | static int |
213 | | tic4x_print_immed (struct disassemble_info *info, |
214 | | immed_t type, |
215 | | unsigned long arg) |
216 | 49.6k | { |
217 | 49.6k | int s; |
218 | 49.6k | int f; |
219 | 49.6k | int e; |
220 | 49.6k | double num = 0.0; |
221 | | |
222 | 49.6k | if (info == NULL) |
223 | 27.4k | return 1; |
224 | 22.2k | switch (type) |
225 | 22.2k | { |
226 | 3.79k | case IMMED_SINT: |
227 | 3.79k | case IMMED_INT: |
228 | 3.79k | (*info->fprintf_func) (info->stream, "%ld", (long) arg); |
229 | 3.79k | break; |
230 | | |
231 | 1.90k | case IMMED_SUINT: |
232 | 15.5k | case IMMED_UINT: |
233 | 15.5k | (*info->fprintf_func) (info->stream, "%lu", arg); |
234 | 15.5k | break; |
235 | | |
236 | 2.83k | case IMMED_SFLOAT: |
237 | 2.83k | e = EXTRS (arg, 15, 12); |
238 | 2.83k | if (e != -8) |
239 | 2.71k | { |
240 | 2.71k | s = EXTRU (arg, 11, 11); |
241 | 2.71k | f = EXTRU (arg, 10, 0); |
242 | 2.71k | if (s) |
243 | 1.31k | f += -2 * (1 << 11); |
244 | 1.40k | else |
245 | 1.40k | f += (1 << 11); |
246 | 2.71k | num = f / (double)(1 << 11); |
247 | 2.71k | num = ldexp (num, e); |
248 | 2.71k | } |
249 | 2.83k | (*info->fprintf_func) (info->stream, "%f", num); |
250 | 2.83k | break; |
251 | 0 | case IMMED_FLOAT: |
252 | 0 | e = EXTRS (arg, 31, 24); |
253 | 0 | if (e != -128) |
254 | 0 | { |
255 | 0 | s = EXTRU (arg, 23, 23); |
256 | 0 | f = EXTRU (arg, 22, 0); |
257 | 0 | if (s) |
258 | 0 | f += -2 * (1 << 23); |
259 | 0 | else |
260 | 0 | f += (1 << 23); |
261 | 0 | num = f / (double)(1 << 23); |
262 | 0 | num = ldexp (num, e); |
263 | 0 | } |
264 | 0 | (*info->fprintf_func) (info->stream, "%f", num); |
265 | 0 | break; |
266 | 22.2k | } |
267 | 22.2k | return 1; |
268 | 22.2k | } |
269 | | |
270 | | static int |
271 | | tic4x_print_cond (struct disassemble_info *info, unsigned int cond) |
272 | 18.1k | { |
273 | 18.1k | static tic4x_cond_t **condtable = NULL; |
274 | 18.1k | unsigned int i; |
275 | | |
276 | 18.1k | if (condtable == NULL) |
277 | 1 | { |
278 | 1 | condtable = xcalloc (32, sizeof (tic4x_cond_t *)); |
279 | 29 | for (i = 0; i < tic4x_num_conds; i++) |
280 | 28 | condtable[tic4x_conds[i].cond] = (tic4x_cond_t *)(tic4x_conds + i); |
281 | 1 | } |
282 | 18.1k | if (cond > 31 || condtable[cond] == NULL) |
283 | 3.24k | return 0; |
284 | 14.9k | if (info != NULL) |
285 | 5.26k | (*info->fprintf_func) (info->stream, "%s", condtable[cond]->name); |
286 | 14.9k | return 1; |
287 | 18.1k | } |
288 | | |
289 | | static int |
290 | | tic4x_print_indirect (struct disassemble_info *info, |
291 | | indirect_t type, |
292 | | unsigned long arg) |
293 | 68.6k | { |
294 | 68.6k | unsigned int aregno; |
295 | 68.6k | unsigned int modn; |
296 | 68.6k | unsigned int disp; |
297 | 68.6k | const char *a; |
298 | | |
299 | 68.6k | aregno = 0; |
300 | 68.6k | modn = 0; |
301 | 68.6k | disp = 1; |
302 | 68.6k | switch(type) |
303 | 68.6k | { |
304 | 6.61k | case INDIRECT_TIC4X: /* *+ARn(disp) */ |
305 | 6.61k | disp = EXTRU (arg, 7, 3); |
306 | 6.61k | aregno = EXTRU (arg, 2, 0) + REG_AR0; |
307 | 6.61k | modn = 0; |
308 | 6.61k | break; |
309 | 54.6k | case INDIRECT_SHORT: |
310 | 54.6k | disp = 1; |
311 | 54.6k | aregno = EXTRU (arg, 2, 0) + REG_AR0; |
312 | 54.6k | modn = EXTRU (arg, 7, 3); |
313 | 54.6k | break; |
314 | 7.35k | case INDIRECT_LONG: |
315 | 7.35k | disp = EXTRU (arg, 7, 0); |
316 | 7.35k | aregno = EXTRU (arg, 10, 8) + REG_AR0; |
317 | 7.35k | modn = EXTRU (arg, 15, 11); |
318 | 7.35k | if (modn > 7 && disp != 0) |
319 | 3.84k | return 0; |
320 | 3.51k | break; |
321 | 3.51k | default: |
322 | 0 | (*info->fprintf_func)(info->stream, "# internal error: Unknown indirect type %d", type); |
323 | 0 | return 0; |
324 | 68.6k | } |
325 | 64.7k | if (modn > TIC3X_MODN_MAX) |
326 | 5.57k | return 0; |
327 | 59.1k | a = tic4x_indirects[modn].name; |
328 | 439k | while (*a) |
329 | 380k | { |
330 | 380k | switch (*a) |
331 | 380k | { |
332 | 59.1k | case 'a': |
333 | 59.1k | tic4x_print_register (info, aregno); |
334 | 59.1k | break; |
335 | 31.1k | case 'd': |
336 | 31.1k | tic4x_print_immed (info, IMMED_UINT, disp); |
337 | 31.1k | break; |
338 | 13.2k | case 'y': |
339 | 13.2k | tic4x_print_str (info, "ir0"); |
340 | 13.2k | break; |
341 | 11.8k | case 'z': |
342 | 11.8k | tic4x_print_str (info, "ir1"); |
343 | 11.8k | break; |
344 | 265k | default: |
345 | 265k | tic4x_print_char (info, *a); |
346 | 265k | break; |
347 | 380k | } |
348 | 380k | a++; |
349 | 380k | } |
350 | 59.1k | return 1; |
351 | 59.1k | } |
352 | | |
353 | | static int |
354 | | tic4x_print_op (struct disassemble_info *info, |
355 | | unsigned long instruction, |
356 | | tic4x_inst_t *p, |
357 | | unsigned long pc) |
358 | 127k | { |
359 | 127k | int val; |
360 | 127k | const char *s; |
361 | 127k | const char *parallel = NULL; |
362 | | |
363 | | /* Print instruction name. */ |
364 | 127k | s = p->name; |
365 | 641k | while (*s && parallel == NULL) |
366 | 517k | { |
367 | 517k | switch (*s) |
368 | 517k | { |
369 | 6.23k | case 'B': |
370 | 6.23k | if (! tic4x_print_cond (info, EXTRU (instruction, 20, 16))) |
371 | 579 | return 0; |
372 | 5.65k | break; |
373 | 11.9k | case 'C': |
374 | 11.9k | if (! tic4x_print_cond (info, EXTRU (instruction, 27, 23))) |
375 | 2.66k | return 0; |
376 | 9.29k | break; |
377 | 29.9k | case '_': |
378 | 29.9k | parallel = s + 1; /* Skip past `_' in name. */ |
379 | 29.9k | break; |
380 | 469k | default: |
381 | 469k | tic4x_print_char (info, *s); |
382 | 469k | break; |
383 | 517k | } |
384 | 514k | s++; |
385 | 514k | } |
386 | | |
387 | | /* Print arguments. */ |
388 | 123k | s = p->args; |
389 | 123k | if (*s) |
390 | 123k | tic4x_print_char (info, ' '); |
391 | | |
392 | 582k | while (*s) |
393 | 489k | { |
394 | 489k | switch (*s) |
395 | 489k | { |
396 | 7.35k | case '*': /* Indirect 0--15. */ |
397 | 7.35k | if (! tic4x_print_indirect (info, INDIRECT_LONG, |
398 | 7.35k | EXTRU (instruction, 15, 0))) |
399 | 3.93k | return 0; |
400 | 3.41k | break; |
401 | | |
402 | 3.41k | case '#': /* Only used for ldp, ldpk. */ |
403 | 22 | tic4x_print_immed (info, IMMED_UINT, EXTRU (instruction, 15, 0)); |
404 | 22 | break; |
405 | | |
406 | 12.8k | case '@': /* Direct 0--15. */ |
407 | 12.8k | tic4x_print_direct (info, EXTRU (instruction, 15, 0)); |
408 | 12.8k | break; |
409 | | |
410 | 3.26k | case 'A': /* Address register 24--22. */ |
411 | 3.26k | if (! tic4x_print_register (info, EXTRU (instruction, 24, 22) + |
412 | 3.26k | REG_AR0)) |
413 | 0 | return 0; |
414 | 3.26k | break; |
415 | | |
416 | 6.35k | case 'B': /* 24-bit unsigned int immediate br(d)/call/rptb |
417 | | address 0--23. */ |
418 | 6.35k | if (IS_CPU_TIC4X (tic4x_version)) |
419 | 4.95k | tic4x_print_relative (info, pc, EXTRS (instruction, 23, 0), |
420 | 4.95k | p->opcode); |
421 | 1.40k | else |
422 | 1.40k | tic4x_print_addr (info, EXTRU (instruction, 23, 0)); |
423 | 6.35k | break; |
424 | | |
425 | 4.58k | case 'C': /* Indirect (short C4x) 0--7. */ |
426 | 4.58k | if (! IS_CPU_TIC4X (tic4x_version)) |
427 | 0 | return 0; |
428 | 4.58k | if (! tic4x_print_indirect (info, INDIRECT_TIC4X, |
429 | 4.58k | EXTRU (instruction, 7, 0))) |
430 | 0 | return 0; |
431 | 4.58k | break; |
432 | | |
433 | 4.58k | case 'D': |
434 | | /* Cockup if get here... */ |
435 | 0 | break; |
436 | | |
437 | 3.72k | case 'E': /* Register 0--7. */ |
438 | 4.24k | case 'e': |
439 | 4.24k | if (! tic4x_print_register (info, EXTRU (instruction, 7, 0))) |
440 | 2.28k | return 0; |
441 | 1.95k | break; |
442 | | |
443 | 5.79k | case 'F': /* 16-bit float immediate 0--15. */ |
444 | 5.79k | tic4x_print_immed (info, IMMED_SFLOAT, |
445 | 5.79k | EXTRU (instruction, 15, 0)); |
446 | 5.79k | break; |
447 | | |
448 | 29.7k | case 'i': /* Extended indirect 0--7. */ |
449 | 29.7k | if (EXTRU (instruction, 7, 5) == 7) |
450 | 5.32k | { |
451 | 5.32k | if (!tic4x_print_register (info, EXTRU (instruction, 4, 0))) |
452 | 365 | return 0; |
453 | 4.95k | break; |
454 | 5.32k | } |
455 | | /* Fallthrough */ |
456 | | |
457 | 26.0k | case 'I': /* Indirect (short) 0--7. */ |
458 | 26.0k | if (! tic4x_print_indirect (info, INDIRECT_SHORT, |
459 | 26.0k | EXTRU (instruction, 7, 0))) |
460 | 1.54k | return 0; |
461 | 24.5k | break; |
462 | | |
463 | 24.5k | case 'j': /* Extended indirect 8--15 */ |
464 | 9.43k | if (EXTRU (instruction, 15, 13) == 7) |
465 | 2.22k | { |
466 | 2.22k | if (! tic4x_print_register (info, EXTRU (instruction, 12, 8))) |
467 | 271 | return 0; |
468 | 1.95k | break; |
469 | 2.22k | } |
470 | | /* Fall through. */ |
471 | | |
472 | 28.5k | case 'J': /* Indirect (short) 8--15. */ |
473 | 28.5k | if (! tic4x_print_indirect (info, INDIRECT_SHORT, |
474 | 28.5k | EXTRU (instruction, 15, 8))) |
475 | 3.93k | return 0; |
476 | 24.6k | break; |
477 | | |
478 | 24.6k | case 'G': /* Register 8--15. */ |
479 | 5.99k | case 'g': |
480 | 5.99k | if (! tic4x_print_register (info, EXTRU (instruction, 15, 8))) |
481 | 3.89k | return 0; |
482 | 2.10k | break; |
483 | | |
484 | 26.8k | case 'H': /* Register 16--18. */ |
485 | 26.8k | if (! tic4x_print_register (info, EXTRU (instruction, 18, 16))) |
486 | 0 | return 0; |
487 | 26.8k | break; |
488 | | |
489 | 26.8k | case 'K': /* Register 19--21. */ |
490 | 19.5k | if (! tic4x_print_register (info, EXTRU (instruction, 21, 19))) |
491 | 0 | return 0; |
492 | 19.5k | break; |
493 | | |
494 | 19.5k | case 'L': /* Register 22--24. */ |
495 | 19.0k | if (! tic4x_print_register (info, EXTRU (instruction, 24, 22))) |
496 | 0 | return 0; |
497 | 19.0k | break; |
498 | | |
499 | 19.0k | case 'M': /* Register 22--22. */ |
500 | 9.01k | tic4x_print_register (info, EXTRU (instruction, 22, 22) + REG_R2); |
501 | 9.01k | break; |
502 | | |
503 | 9.20k | case 'N': /* Register 23--23. */ |
504 | 9.20k | tic4x_print_register (info, EXTRU (instruction, 23, 23) + REG_R0); |
505 | 9.20k | break; |
506 | | |
507 | 2.03k | case 'O': /* Indirect (short C4x) 8--15. */ |
508 | 2.03k | if (! IS_CPU_TIC4X (tic4x_version)) |
509 | 0 | return 0; |
510 | 2.03k | if (! tic4x_print_indirect (info, INDIRECT_TIC4X, |
511 | 2.03k | EXTRU (instruction, 15, 8))) |
512 | 0 | return 0; |
513 | 2.03k | break; |
514 | | |
515 | 4.26k | case 'P': /* Displacement 0--15 (used by Bcond and BcondD). */ |
516 | 4.26k | tic4x_print_relative (info, pc, EXTRS (instruction, 15, 0), |
517 | 4.26k | p->opcode); |
518 | 4.26k | break; |
519 | | |
520 | 7.13k | case 'Q': /* Register 0--15. */ |
521 | 35.9k | case 'q': |
522 | 35.9k | if (! tic4x_print_register (info, EXTRU (instruction, 15, 0))) |
523 | 13.6k | return 0; |
524 | 22.2k | break; |
525 | | |
526 | 22.2k | case 'R': /* Register 16--20. */ |
527 | 53.9k | case 'r': |
528 | 53.9k | if (! tic4x_print_register (info, EXTRU (instruction, 20, 16))) |
529 | 661 | return 0; |
530 | 53.2k | break; |
531 | | |
532 | 53.2k | case 'S': /* 16-bit signed immediate 0--15. */ |
533 | 6.25k | tic4x_print_immed (info, IMMED_SINT, |
534 | 6.25k | EXTRS (instruction, 15, 0)); |
535 | 6.25k | break; |
536 | | |
537 | 2.85k | case 'T': /* 5-bit signed immediate 16--20 (C4x stik). */ |
538 | 2.85k | if (! IS_CPU_TIC4X (tic4x_version)) |
539 | 0 | return 0; |
540 | 2.85k | if (! tic4x_print_immed (info, IMMED_SUINT, |
541 | 2.85k | EXTRU (instruction, 20, 16))) |
542 | 0 | return 0; |
543 | 2.85k | break; |
544 | | |
545 | 2.85k | case 'U': /* 16-bit unsigned int immediate 0--15. */ |
546 | 670 | tic4x_print_immed (info, IMMED_SUINT, EXTRU (instruction, 15, 0)); |
547 | 670 | break; |
548 | | |
549 | 352 | case 'V': /* 5/9-bit unsigned vector 0--4/8. */ |
550 | 352 | tic4x_print_immed (info, IMMED_SUINT, |
551 | 352 | IS_CPU_TIC4X (tic4x_version) ? |
552 | 278 | EXTRU (instruction, 8, 0) : |
553 | 352 | EXTRU (instruction, 4, 0) & ~0x20); |
554 | 352 | break; |
555 | | |
556 | 2.55k | case 'W': /* 8-bit signed immediate 0--7. */ |
557 | 2.55k | if (! IS_CPU_TIC4X (tic4x_version)) |
558 | 0 | return 0; |
559 | 2.55k | tic4x_print_immed (info, IMMED_SINT, EXTRS (instruction, 7, 0)); |
560 | 2.55k | break; |
561 | | |
562 | 613 | case 'X': /* Expansion register 4--0. */ |
563 | 613 | val = EXTRU (instruction, 4, 0) + REG_IVTP; |
564 | 613 | if (val < REG_IVTP || val > REG_TVTP) |
565 | 345 | return 0; |
566 | 268 | if (! tic4x_print_register (info, val)) |
567 | 0 | return 0; |
568 | 268 | break; |
569 | | |
570 | 371 | case 'Y': /* Address register 16--20. */ |
571 | 371 | val = EXTRU (instruction, 20, 16); |
572 | 371 | if (val < REG_AR0 || val > REG_SP) |
573 | 125 | return 0; |
574 | 246 | if (! tic4x_print_register (info, val)) |
575 | 0 | return 0; |
576 | 246 | break; |
577 | | |
578 | 246 | case 'Z': /* Expansion register 16--20. */ |
579 | 87 | val = EXTRU (instruction, 20, 16) + REG_IVTP; |
580 | 87 | if (val < REG_IVTP || val > REG_TVTP) |
581 | 21 | return 0; |
582 | 66 | if (! tic4x_print_register (info, val)) |
583 | 0 | return 0; |
584 | 66 | break; |
585 | | |
586 | 28.2k | case '|': /* Parallel instruction. */ |
587 | 28.2k | tic4x_print_str (info, " || "); |
588 | 28.2k | tic4x_print_str (info, parallel); |
589 | 28.2k | tic4x_print_char (info, ' '); |
590 | 28.2k | break; |
591 | | |
592 | 86.0k | case ';': |
593 | 86.0k | tic4x_print_char (info, ','); |
594 | 86.0k | break; |
595 | | |
596 | 68.5k | default: |
597 | 68.5k | tic4x_print_char (info, *s); |
598 | 68.5k | break; |
599 | 489k | } |
600 | 458k | s++; |
601 | 458k | } |
602 | 92.8k | return 1; |
603 | 123k | } |
604 | | |
605 | | static void |
606 | | tic4x_hash_opcode_special (tic4x_inst_t **optable_special, |
607 | | const tic4x_inst_t *inst) |
608 | 1.80k | { |
609 | 1.80k | int i; |
610 | | |
611 | 13.2k | for (i = 0;i < TIC4X_SPESOP_SIZE; i++) |
612 | 12.0k | if (optable_special[i] != NULL |
613 | 12.0k | && optable_special[i]->opcode == inst->opcode) |
614 | 600 | { |
615 | | /* Collision (we have it already) - overwrite. */ |
616 | 600 | optable_special[i] = (tic4x_inst_t *) inst; |
617 | 600 | return; |
618 | 600 | } |
619 | | |
620 | 3.00k | for (i = 0; i < TIC4X_SPESOP_SIZE; i++) |
621 | 3.00k | if (optable_special[i] == NULL) |
622 | 1.20k | { |
623 | | /* Add the new opcode. */ |
624 | 1.20k | optable_special[i] = (tic4x_inst_t *) inst; |
625 | 1.20k | return; |
626 | 1.20k | } |
627 | | |
628 | | /* This should never occur. This happens if the number of special |
629 | | instructions exceeds TIC4X_SPESOP_SIZE. Please increase the variable |
630 | | of this variable */ |
631 | | #if TIC4X_DEBUG |
632 | | printf ("optable_special[] is full, please increase TIC4X_SPESOP_SIZE!\n"); |
633 | | #endif |
634 | 1.20k | } |
635 | | |
636 | | static void |
637 | | tic4x_hash_opcode (tic4x_inst_t **optable, |
638 | | tic4x_inst_t **optable_special, |
639 | | const tic4x_inst_t *inst, |
640 | | const unsigned long tic4x_oplevel) |
641 | 306k | { |
642 | 306k | unsigned int j; |
643 | 306k | unsigned int opcode = inst->opcode >> (32 - TIC4X_HASH_SIZE); |
644 | 306k | unsigned int opmask = inst->opmask >> (32 - TIC4X_HASH_SIZE); |
645 | | |
646 | | /* Use a TIC4X_HASH_SIZE bit index as a hash index. We should |
647 | | have unique entries so there's no point having a linked list |
648 | | for each entry? */ |
649 | 400M | for (j = opcode; j < opmask; j++) |
650 | 400M | if ((j & opmask) == opcode |
651 | 400M | && inst->oplevel & tic4x_oplevel) |
652 | 1.25M | { |
653 | | #if TIC4X_DEBUG |
654 | | /* We should only have collisions for synonyms like |
655 | | ldp for ldi. */ |
656 | | if (optable[j] != NULL) |
657 | | printf ("Collision at index %d, %s and %s\n", |
658 | | j, optable[j]->name, inst->name); |
659 | | #endif |
660 | | /* Catch those ops that collide with others already inside the |
661 | | hash, and have a opmask greater than the one we use in the |
662 | | hash. Store them in a special-list, that will handle full |
663 | | 32-bit INSN, not only the first 11-bit (or so). */ |
664 | 1.25M | if (optable[j] != NULL |
665 | 1.25M | && inst->opmask & ~(opmask << (32 - TIC4X_HASH_SIZE))) |
666 | 900 | { |
667 | | /* Add the instruction already on the list. */ |
668 | 900 | tic4x_hash_opcode_special (optable_special, optable[j]); |
669 | | |
670 | | /* Add the new instruction. */ |
671 | 900 | tic4x_hash_opcode_special (optable_special, inst); |
672 | 900 | } |
673 | | |
674 | 1.25M | optable[j] = (tic4x_inst_t *) inst; |
675 | 1.25M | } |
676 | 306k | } |
677 | | |
678 | | /* Disassemble the instruction in 'instruction'. |
679 | | 'pc' should be the address of this instruction, it will |
680 | | be used to print the target address if this is a relative jump or call |
681 | | the disassembled instruction is written to 'info'. |
682 | | The function returns the length of this instruction in words. */ |
683 | | |
684 | | static int |
685 | | tic4x_disassemble (unsigned long pc, |
686 | | unsigned long instruction, |
687 | | struct disassemble_info *info) |
688 | 117k | { |
689 | 117k | tic4x_inst_t *p; |
690 | 117k | int i; |
691 | 117k | unsigned long tic4x_oplevel; |
692 | | |
693 | 117k | if (tic4x_version != info->mach) |
694 | 299 | { |
695 | 299 | tic4x_version = info->mach; |
696 | | /* Don't stash anything from a previous call using a different |
697 | | machine. */ |
698 | 299 | free (optab); |
699 | 299 | optab = NULL; |
700 | 299 | free (optab_special); |
701 | 299 | optab_special = NULL; |
702 | 299 | registernames[REG_R0] = NULL; |
703 | 299 | } |
704 | | |
705 | 117k | tic4x_oplevel = (IS_CPU_TIC4X (tic4x_version)) ? OP_C4X : 0; |
706 | 117k | tic4x_oplevel |= OP_C3X | OP_LPWR | OP_IDLE2 | OP_ENH; |
707 | | |
708 | 117k | if (optab == NULL) |
709 | 300 | { |
710 | 300 | optab = xcalloc ((1 << TIC4X_HASH_SIZE), sizeof (tic4x_inst_t *)); |
711 | | |
712 | 300 | optab_special = xcalloc (TIC4X_SPESOP_SIZE, sizeof (tic4x_inst_t *)); |
713 | | |
714 | | /* Install opcodes in reverse order so that preferred |
715 | | forms overwrite synonyms. */ |
716 | 307k | for (i = tic4x_num_insts - 1; i >= 0; i--) |
717 | 306k | tic4x_hash_opcode (optab, optab_special, &tic4x_insts[i], |
718 | 306k | tic4x_oplevel); |
719 | | |
720 | | /* We now need to remove the insn that are special from the |
721 | | "normal" optable, to make the disasm search this extra list |
722 | | for them. */ |
723 | 2.70k | for (i = 0; i < TIC4X_SPESOP_SIZE; i++) |
724 | 2.40k | if (optab_special[i] != NULL) |
725 | 1.20k | optab[optab_special[i]->opcode >> (32 - TIC4X_HASH_SIZE)] = NULL; |
726 | 300 | } |
727 | | |
728 | | /* See if we can pick up any loading of the DP register... */ |
729 | 117k | if ((instruction >> 16) == 0x5070 || (instruction >> 16) == 0x1f70) |
730 | 21 | tic4x_dp = EXTRU (instruction, 15, 0); |
731 | | |
732 | 117k | p = optab[instruction >> (32 - TIC4X_HASH_SIZE)]; |
733 | 117k | if (p != NULL) |
734 | 81.3k | { |
735 | 81.3k | if (((instruction & p->opmask) == p->opcode) |
736 | 81.3k | && tic4x_print_op (NULL, instruction, p, pc)) |
737 | 46.4k | tic4x_print_op (info, instruction, p, pc); |
738 | 34.9k | else |
739 | 34.9k | (*info->fprintf_func) (info->stream, "%08lx", instruction); |
740 | 81.3k | } |
741 | 36.5k | else |
742 | 36.5k | { |
743 | 328k | for (i = 0; i<TIC4X_SPESOP_SIZE; i++) |
744 | 291k | if (optab_special[i] != NULL |
745 | 291k | && optab_special[i]->opcode == instruction) |
746 | 106 | { |
747 | 106 | (*info->fprintf_func)(info->stream, "%s", optab_special[i]->name); |
748 | 106 | break; |
749 | 106 | } |
750 | 36.5k | if (i == TIC4X_SPESOP_SIZE) |
751 | 36.4k | (*info->fprintf_func) (info->stream, "%08lx", instruction); |
752 | 36.5k | } |
753 | | |
754 | | /* Return size of insn in words. */ |
755 | 117k | return 1; |
756 | 117k | } |
757 | | |
758 | | /* The entry point from objdump and gdb. */ |
759 | | int |
760 | | print_insn_tic4x (bfd_vma memaddr, struct disassemble_info *info) |
761 | 118k | { |
762 | 118k | int status; |
763 | 118k | unsigned long pc; |
764 | 118k | unsigned long op; |
765 | 118k | bfd_byte buffer[4]; |
766 | | |
767 | 118k | status = (*info->read_memory_func) (memaddr, buffer, 4, info); |
768 | 118k | if (status != 0) |
769 | 400 | { |
770 | 400 | (*info->memory_error_func) (status, memaddr, info); |
771 | 400 | return -1; |
772 | 400 | } |
773 | | |
774 | 117k | pc = memaddr; |
775 | 117k | op = bfd_getl32 (buffer); |
776 | 117k | info->bytes_per_line = 4; |
777 | 117k | info->bytes_per_chunk = 4; |
778 | 117k | info->octets_per_byte = 4; |
779 | 117k | info->display_endian = BFD_ENDIAN_LITTLE; |
780 | 117k | return tic4x_disassemble (pc, op, info) * 4; |
781 | 118k | } |