/src/binutils-gdb/opcodes/visium-dis.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Single instruction disassembler for the Visium. |
2 | | |
3 | | Copyright (C) 2002-2025 Free Software Foundation, Inc. |
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 program; if not, write to the Free Software |
19 | | Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
20 | | MA 02110-1301, USA. */ |
21 | | |
22 | | #include "sysdep.h" |
23 | | #include "disassemble.h" |
24 | | #include "opcode/visium.h" |
25 | | |
26 | | #include <string.h> |
27 | | #include <stdlib.h> |
28 | | #include <stdio.h> |
29 | | #include <ctype.h> |
30 | | #include <setjmp.h> |
31 | | |
32 | | /* Maximum length of an instruction. */ |
33 | | #define MAXLEN 4 |
34 | | |
35 | | struct private |
36 | | { |
37 | | /* Points to first byte not fetched. */ |
38 | | bfd_byte *max_fetched; |
39 | | bfd_byte the_buffer[MAXLEN]; |
40 | | bfd_vma insn_start; |
41 | | jmp_buf bailout; |
42 | | }; |
43 | | |
44 | | /* Make sure that bytes from INFO->PRIVATE_DATA->BUFFER (inclusive) |
45 | | to ADDR (exclusive) are valid. Returns 1 for success, longjmps |
46 | | on error. */ |
47 | | #define FETCH_DATA(info, addr) \ |
48 | 545k | ((addr) <= ((struct private *)(info->private_data))->max_fetched \ |
49 | 545k | ? 1 : fetch_data ((info), (addr))) |
50 | | |
51 | | static int fetch_data (struct disassemble_info *info, bfd_byte * addr); |
52 | | |
53 | | static int |
54 | | fetch_data (struct disassemble_info *info, bfd_byte *addr) |
55 | 545k | { |
56 | 545k | int status; |
57 | 545k | struct private *priv = (struct private *) info->private_data; |
58 | 545k | bfd_vma start = priv->insn_start + (priv->max_fetched - priv->the_buffer); |
59 | | |
60 | 545k | status = (*info->read_memory_func) (start, |
61 | 545k | priv->max_fetched, |
62 | 545k | addr - priv->max_fetched, info); |
63 | 545k | if (status != 0) |
64 | 420 | { |
65 | 420 | (*info->memory_error_func) (status, start, info); |
66 | 420 | longjmp (priv->bailout, 1); |
67 | 420 | } |
68 | 545k | else |
69 | 545k | priv->max_fetched = addr; |
70 | 545k | return 1; |
71 | 545k | } |
72 | | |
73 | | static char *size_names[] = { "?", "b", "w", "?", "l", "?", "?", "?" }; |
74 | | |
75 | | static char *cc_names[] = |
76 | | { |
77 | | "fa", "eq", "cs", "os", "ns", "ne", "cc", "oc", |
78 | | "nc", "ge", "gt", "hi", "le", "ls", "lt", "tr" |
79 | | }; |
80 | | |
81 | | /* Disassemble non-storage relative instructions. */ |
82 | | |
83 | | static int |
84 | | disassem_class0 (disassemble_info *info, unsigned int ins) |
85 | 145k | { |
86 | 145k | int opcode = (ins >> 21) & 0x000f; |
87 | | |
88 | 145k | if (ins & CLASS0_UNUSED_MASK) |
89 | 75.6k | goto illegal_opcode; |
90 | | |
91 | 70.0k | switch (opcode) |
92 | 70.0k | { |
93 | 58.6k | case 0: |
94 | | /* BRR instruction. */ |
95 | 58.6k | { |
96 | 58.6k | unsigned cbf = (ins >> 27) & 0x000f; |
97 | 58.6k | int displacement = ((ins & 0xffff) ^ 0x8000) - 0x8000; |
98 | | |
99 | 58.6k | if (ins == 0) |
100 | 31.9k | (*info->fprintf_func) (info->stream, "nop"); |
101 | 26.6k | else |
102 | 26.6k | (*info->fprintf_func) (info->stream, "brr %s,%+d", |
103 | 26.6k | cc_names[cbf], displacement); |
104 | 58.6k | } |
105 | 58.6k | break; |
106 | 1.87k | case 1: |
107 | | /* Illegal opcode. */ |
108 | 1.87k | goto illegal_opcode; |
109 | 0 | break; |
110 | 561 | case 2: |
111 | | /* Illegal opcode. */ |
112 | 561 | goto illegal_opcode; |
113 | 0 | break; |
114 | 528 | case 3: |
115 | | /* Illegal opcode. */ |
116 | 528 | goto illegal_opcode; |
117 | 0 | break; |
118 | 1.47k | case 4: |
119 | | /* Illegal opcode. */ |
120 | 1.47k | goto illegal_opcode; |
121 | 0 | break; |
122 | 966 | case 5: |
123 | | /* Illegal opcode. */ |
124 | 966 | goto illegal_opcode; |
125 | 0 | break; |
126 | 1.98k | case 6: |
127 | | /* Illegal opcode. */ |
128 | 1.98k | goto illegal_opcode; |
129 | 0 | break; |
130 | 197 | case 7: |
131 | | /* Illegal opcode. */ |
132 | 197 | goto illegal_opcode; |
133 | 0 | break; |
134 | 3.08k | case 8: |
135 | | /* Illegal opcode. */ |
136 | 3.08k | goto illegal_opcode; |
137 | 0 | break; |
138 | 82 | case 9: |
139 | | /* Illegal opcode. */ |
140 | 82 | goto illegal_opcode; |
141 | 0 | break; |
142 | 47 | case 10: |
143 | | /* Illegal opcode. */ |
144 | 47 | goto illegal_opcode; |
145 | 0 | break; |
146 | 57 | case 11: |
147 | | /* Illegal opcode. */ |
148 | 57 | goto illegal_opcode; |
149 | 0 | break; |
150 | 371 | case 12: |
151 | | /* Illegal opcode. */ |
152 | 371 | goto illegal_opcode; |
153 | 0 | break; |
154 | 31 | case 13: |
155 | | /* Illegal opcode. */ |
156 | 31 | goto illegal_opcode; |
157 | 0 | break; |
158 | 103 | case 14: |
159 | | /* Illegal opcode. */ |
160 | 103 | goto illegal_opcode; |
161 | 0 | break; |
162 | 84 | case 15: |
163 | | /* Illegal opcode. */ |
164 | 84 | goto illegal_opcode; |
165 | 0 | break; |
166 | 70.0k | } |
167 | 58.6k | return 0; |
168 | | |
169 | 87.0k | illegal_opcode: |
170 | 87.0k | return -1; |
171 | 70.0k | } |
172 | | |
173 | | /* Disassemble non-storage register class instructions. */ |
174 | | |
175 | | static int |
176 | | disassem_class1 (disassemble_info *info, unsigned int ins) |
177 | 53.0k | { |
178 | 53.0k | int opcode = (ins >> 21) & 0xf; |
179 | 53.0k | int source_a = (ins >> 16) & 0x1f; |
180 | 53.0k | int source_b = (ins >> 4) & 0x1f; |
181 | 53.0k | int indx = (ins >> 10) & 0x1f; |
182 | | |
183 | 53.0k | int size = ins & 0x7; |
184 | | |
185 | 53.0k | if (ins & CLASS1_UNUSED_MASK) |
186 | 28.0k | goto illegal_opcode; |
187 | | |
188 | 25.0k | switch (opcode) |
189 | 25.0k | { |
190 | 5.87k | case 0: |
191 | | /* Stop. */ |
192 | 5.87k | (*info->fprintf_func) (info->stream, "stop %d,r%d", indx, source_a); |
193 | 5.87k | break; |
194 | 1.05k | case 1: |
195 | | /* BMI - Block Move Indirect. */ |
196 | 1.05k | if (ins != BMI) |
197 | 1.04k | goto illegal_opcode; |
198 | | |
199 | 10 | (*info->fprintf_func) (info->stream, "bmi r1,r2,r3"); |
200 | 10 | break; |
201 | 846 | case 2: |
202 | | /* Illegal opcode. */ |
203 | 846 | goto illegal_opcode; |
204 | 0 | break; |
205 | 1.26k | case 3: |
206 | | /* BMD - Block Move Direct. */ |
207 | 1.26k | if (ins != BMD) |
208 | 1.25k | goto illegal_opcode; |
209 | | |
210 | 10 | (*info->fprintf_func) (info->stream, "bmd r1,r2,r3"); |
211 | 10 | break; |
212 | 747 | case 4: |
213 | | /* DSI - Disable Interrupts. */ |
214 | 747 | if (ins != DSI) |
215 | 746 | goto illegal_opcode; |
216 | | |
217 | 1 | (*info->fprintf_func) (info->stream, "dsi"); |
218 | 1 | break; |
219 | | |
220 | 612 | case 5: |
221 | | /* ENI - Enable Interrupts. */ |
222 | 612 | if (ins != ENI) |
223 | 609 | goto illegal_opcode; |
224 | | |
225 | 3 | (*info->fprintf_func) (info->stream, "eni"); |
226 | 3 | break; |
227 | | |
228 | 1.06k | case 6: |
229 | | /* Illegal opcode (was EUT). */ |
230 | 1.06k | goto illegal_opcode; |
231 | 0 | break; |
232 | 797 | case 7: |
233 | | /* RFI - Return from Interrupt. */ |
234 | 797 | if (ins != RFI) |
235 | 787 | goto illegal_opcode; |
236 | | |
237 | 10 | (*info->fprintf_func) (info->stream, "rfi"); |
238 | 10 | break; |
239 | 3.45k | case 8: |
240 | | /* Illegal opcode. */ |
241 | 3.45k | goto illegal_opcode; |
242 | 0 | break; |
243 | 1.32k | case 9: |
244 | | /* Illegal opcode. */ |
245 | 1.32k | goto illegal_opcode; |
246 | 0 | break; |
247 | 1.01k | case 10: |
248 | | /* Illegal opcode. */ |
249 | 1.01k | goto illegal_opcode; |
250 | 0 | break; |
251 | 1.62k | case 11: |
252 | | /* Illegal opcode. */ |
253 | 1.62k | goto illegal_opcode; |
254 | 0 | break; |
255 | 1.37k | case 12: |
256 | | /* Illegal opcode. */ |
257 | 1.37k | goto illegal_opcode; |
258 | 0 | break; |
259 | 589 | case 13: |
260 | 589 | goto illegal_opcode; |
261 | 0 | break; |
262 | 855 | case 14: |
263 | 855 | goto illegal_opcode; |
264 | 0 | break; |
265 | 2.53k | case 15: |
266 | 2.53k | if (ins & EAM_SELECT_MASK) |
267 | 1.68k | { |
268 | | /* Extension arithmetic module write */ |
269 | 1.68k | int fp_ins = (ins >> 27) & 0xf; |
270 | | |
271 | 1.68k | if (size != 4) |
272 | 573 | goto illegal_opcode; |
273 | | |
274 | 1.11k | if (ins & FP_SELECT_MASK) |
275 | 314 | { |
276 | | /* Which floating point instructions don't need a fsrcB |
277 | | register. */ |
278 | 314 | const int no_fsrcb[16] = { 1, 0, 0, 0, 0, 1, 1, 1, |
279 | 314 | 1, 1, 0, 0, 1, 0, 0, 0 |
280 | 314 | }; |
281 | 314 | if (no_fsrcb[fp_ins] && source_b) |
282 | 54 | goto illegal_opcode; |
283 | | |
284 | | /* Check that none of the floating register register numbers |
285 | | is higher than 15. (If this is fload, then srcA is a |
286 | | general register. */ |
287 | 260 | if (ins & ((1 << 14) | (1 << 8)) || (fp_ins && ins & (1 << 20))) |
288 | 58 | goto illegal_opcode; |
289 | | |
290 | 202 | switch (fp_ins) |
291 | 202 | { |
292 | 11 | case 0: |
293 | 11 | (*info->fprintf_func) (info->stream, "fload f%d,r%d", |
294 | 11 | indx, source_a); |
295 | 11 | break; |
296 | 22 | case 1: |
297 | 22 | (*info->fprintf_func) (info->stream, "fadd f%d,f%d,f%d", |
298 | 22 | indx, source_a, source_b); |
299 | 22 | break; |
300 | 0 | case 2: |
301 | 0 | (*info->fprintf_func) (info->stream, "fsub f%d,f%d,f%d", |
302 | 0 | indx, source_a, source_b); |
303 | 0 | break; |
304 | 3 | case 3: |
305 | 3 | (*info->fprintf_func) (info->stream, "fmult f%d,f%d,f%d", |
306 | 3 | indx, source_a, source_b); |
307 | 3 | break; |
308 | 43 | case 4: |
309 | 43 | (*info->fprintf_func) (info->stream, "fdiv f%d,f%d,f%d", |
310 | 43 | indx, source_a, source_b); |
311 | 43 | break; |
312 | 19 | case 5: |
313 | 19 | (*info->fprintf_func) (info->stream, "fsqrt f%d,f%d", |
314 | 19 | indx, source_a); |
315 | 19 | break; |
316 | 11 | case 6: |
317 | 11 | (*info->fprintf_func) (info->stream, "fneg f%d,f%d", |
318 | 11 | indx, source_a); |
319 | 11 | break; |
320 | 38 | case 7: |
321 | 38 | (*info->fprintf_func) (info->stream, "fabs f%d,f%d", |
322 | 38 | indx, source_a); |
323 | 38 | break; |
324 | 10 | case 8: |
325 | 10 | (*info->fprintf_func) (info->stream, "ftoi f%d,f%d", |
326 | 10 | indx, source_a); |
327 | 10 | break; |
328 | 1 | case 9: |
329 | 1 | (*info->fprintf_func) (info->stream, "itof f%d,f%d", |
330 | 1 | indx, source_a); |
331 | 1 | break; |
332 | 30 | case 12: |
333 | 30 | (*info->fprintf_func) (info->stream, "fmove f%d,f%d", |
334 | 30 | indx, source_a); |
335 | 30 | break; |
336 | 14 | default: |
337 | 14 | (*info->fprintf_func) (info->stream, |
338 | 14 | "fpinst %d,f%d,f%d,f%d", fp_ins, |
339 | 14 | indx, source_a, source_b); |
340 | 14 | break; |
341 | 202 | } |
342 | 202 | } |
343 | 800 | else |
344 | 800 | { |
345 | | /* Which EAM operations do not need a srcB register. */ |
346 | 800 | const int no_srcb[32] = |
347 | 800 | { 0, 0, 1, 1, 0, 1, 1, 1, |
348 | 800 | 0, 1, 1, 1, 0, 0, 0, 0, |
349 | 800 | 0, 0, 0, 0, 0, 0, 0, 0, |
350 | 800 | 0, 0, 0, 0, 0, 0, 0, 0 |
351 | 800 | }; |
352 | | |
353 | 800 | if (no_srcb[indx] && source_b) |
354 | 27 | goto illegal_opcode; |
355 | | |
356 | 773 | if (fp_ins) |
357 | 170 | goto illegal_opcode; |
358 | | |
359 | 603 | switch (indx) |
360 | 603 | { |
361 | 18 | case 0: |
362 | 18 | (*info->fprintf_func) (info->stream, "mults r%d,r%d", |
363 | 18 | source_a, source_b); |
364 | 18 | break; |
365 | 19 | case 1: |
366 | 19 | (*info->fprintf_func) (info->stream, "multu r%d,r%d", |
367 | 19 | source_a, source_b); |
368 | 19 | break; |
369 | 17 | case 2: |
370 | 17 | (*info->fprintf_func) (info->stream, "divs r%d", |
371 | 17 | source_a); |
372 | 17 | break; |
373 | 0 | case 3: |
374 | 0 | (*info->fprintf_func) (info->stream, "divu r%d", |
375 | 0 | source_a); |
376 | 0 | break; |
377 | 0 | case 4: |
378 | 0 | (*info->fprintf_func) (info->stream, "writemd r%d,r%d", |
379 | 0 | source_a, source_b); |
380 | 0 | break; |
381 | 54 | case 5: |
382 | 54 | (*info->fprintf_func) (info->stream, "writemdc r%d", |
383 | 54 | source_a); |
384 | 54 | break; |
385 | 0 | case 6: |
386 | 0 | (*info->fprintf_func) (info->stream, "divds r%d", |
387 | 0 | source_a); |
388 | 0 | break; |
389 | 41 | case 7: |
390 | 41 | (*info->fprintf_func) (info->stream, "divdu r%d", |
391 | 41 | source_a); |
392 | 41 | break; |
393 | 0 | case 9: |
394 | 0 | (*info->fprintf_func) (info->stream, "asrd r%d", |
395 | 0 | source_a); |
396 | 0 | break; |
397 | 25 | case 10: |
398 | 25 | (*info->fprintf_func) (info->stream, "lsrd r%d", |
399 | 25 | source_a); |
400 | 25 | break; |
401 | 26 | case 11: |
402 | 26 | (*info->fprintf_func) (info->stream, "asld r%d", |
403 | 26 | source_a); |
404 | 26 | break; |
405 | 403 | default: |
406 | 403 | (*info->fprintf_func) (info->stream, |
407 | 403 | "eamwrite %d,r%d,r%d", indx, |
408 | 403 | source_a, source_b); |
409 | 403 | break; |
410 | 603 | } |
411 | 603 | } |
412 | 1.11k | } |
413 | 848 | else |
414 | 848 | { |
415 | | /* WRITE - write to memory. */ |
416 | 848 | (*info->fprintf_func) (info->stream, "write.%s %d(r%d),r%d", |
417 | 848 | size_names[size], indx, source_a, source_b); |
418 | 848 | } |
419 | 1.65k | break; |
420 | 25.0k | } |
421 | | |
422 | 7.56k | return 0; |
423 | | |
424 | 45.5k | illegal_opcode: |
425 | 45.5k | return -1; |
426 | 25.0k | } |
427 | | |
428 | | /* Disassemble storage immediate class instructions. */ |
429 | | |
430 | | static int |
431 | | disassem_class2 (disassemble_info *info, unsigned int ins) |
432 | 52.1k | { |
433 | 52.1k | int opcode = (ins >> 21) & 0xf; |
434 | 52.1k | int source_a = (ins >> 16) & 0x1f; |
435 | 52.1k | unsigned immediate = ins & 0x0000ffff; |
436 | | |
437 | 52.1k | if (ins & CC_MASK) |
438 | 43.1k | goto illegal_opcode; |
439 | | |
440 | 8.94k | switch (opcode) |
441 | 8.94k | { |
442 | 1.92k | case 0: |
443 | | /* ADDI instruction. */ |
444 | 1.92k | (*info->fprintf_func) (info->stream, "addi r%d,%d", source_a, |
445 | 1.92k | immediate); |
446 | 1.92k | break; |
447 | 559 | case 1: |
448 | | /* Illegal opcode. */ |
449 | 559 | goto illegal_opcode; |
450 | 0 | break; |
451 | 191 | case 2: |
452 | | /* SUBI instruction. */ |
453 | 191 | (*info->fprintf_func) (info->stream, "subi r%d,%d", source_a, |
454 | 191 | immediate); |
455 | 191 | break; |
456 | 174 | case 3: |
457 | | /* Illegal opcode. */ |
458 | 174 | goto illegal_opcode; |
459 | 0 | break; |
460 | 1.05k | case 4: |
461 | | /* MOVIL instruction. */ |
462 | 1.05k | (*info->fprintf_func) (info->stream, "movil r%d,0x%04X", source_a, |
463 | 1.05k | immediate); |
464 | 1.05k | break; |
465 | 245 | case 5: |
466 | | /* MOVIU instruction. */ |
467 | 245 | (*info->fprintf_func) (info->stream, "moviu r%d,0x%04X", source_a, |
468 | 245 | immediate); |
469 | 245 | break; |
470 | 191 | case 6: |
471 | | /* MOVIQ instruction. */ |
472 | 191 | (*info->fprintf_func) (info->stream, "moviq r%d,%u", source_a, |
473 | 191 | immediate); |
474 | 191 | break; |
475 | 450 | case 7: |
476 | | /* Illegal opcode. */ |
477 | 450 | goto illegal_opcode; |
478 | 0 | break; |
479 | 1.96k | case 8: |
480 | | /* WRTL instruction. */ |
481 | 1.96k | if (source_a != 0) |
482 | 845 | goto illegal_opcode; |
483 | | |
484 | 1.11k | (*info->fprintf_func) (info->stream, "wrtl 0x%04X", immediate); |
485 | 1.11k | break; |
486 | 262 | case 9: |
487 | | /* WRTU instruction. */ |
488 | 262 | if (source_a != 0) |
489 | 220 | goto illegal_opcode; |
490 | | |
491 | 42 | (*info->fprintf_func) (info->stream, "wrtu 0x%04X", immediate); |
492 | 42 | break; |
493 | 296 | case 10: |
494 | | /* Illegal opcode. */ |
495 | 296 | goto illegal_opcode; |
496 | 0 | break; |
497 | 106 | case 11: |
498 | | /* Illegal opcode. */ |
499 | 106 | goto illegal_opcode; |
500 | 0 | break; |
501 | 613 | case 12: |
502 | | /* Illegal opcode. */ |
503 | 613 | goto illegal_opcode; |
504 | 0 | break; |
505 | 477 | case 13: |
506 | | /* Illegal opcode. */ |
507 | 477 | goto illegal_opcode; |
508 | 0 | break; |
509 | 154 | case 14: |
510 | | /* Illegal opcode. */ |
511 | 154 | goto illegal_opcode; |
512 | 0 | break; |
513 | 284 | case 15: |
514 | | /* Illegal opcode. */ |
515 | 284 | goto illegal_opcode; |
516 | 0 | break; |
517 | 8.94k | } |
518 | | |
519 | 4.76k | return 0; |
520 | | |
521 | 47.3k | illegal_opcode: |
522 | 47.3k | return -1; |
523 | 8.94k | } |
524 | | |
525 | | /* Disassemble storage register class instructions. */ |
526 | | |
527 | | static int |
528 | | disassem_class3 (disassemble_info *info, unsigned int ins) |
529 | 81.5k | { |
530 | 81.5k | int opcode = (ins >> 21) & 0xf; |
531 | 81.5k | int source_b = (ins >> 4) & 0x1f; |
532 | 81.5k | int source_a = (ins >> 16) & 0x1f; |
533 | 81.5k | int size = ins & 0x7; |
534 | 81.5k | int dest = (ins >> 10) & 0x1f; |
535 | | |
536 | | /* Those instructions that don't have a srcB register. */ |
537 | 81.5k | const int no_srcb[16] = |
538 | 81.5k | { 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0 }; |
539 | | |
540 | | /* These are instructions which can take an immediate srcB value. */ |
541 | 81.5k | const int srcb_immed[16] = |
542 | 81.5k | { 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1 }; |
543 | | |
544 | | /* User opcodes should not provide a non-zero srcB register |
545 | | when none is required. Only a BRA or floating point |
546 | | instruction should have a non-zero condition code field. |
547 | | Only a WRITE or EAMWRITE (opcode 15) should select an EAM |
548 | | or floating point operation. Note that FP_SELECT_MASK is |
549 | | the same bit (bit 3) as the interrupt bit which |
550 | | distinguishes SYS1 from BRA and SYS2 from RFLAG. */ |
551 | 81.5k | if ((no_srcb[opcode] && source_b) |
552 | 81.5k | || (!srcb_immed[opcode] && ins & CLASS3_SOURCEB_IMMED) |
553 | 81.5k | || (opcode != 12 && opcode != 15 && ins & CC_MASK) |
554 | 81.5k | || (opcode != 15 && ins & (EAM_SELECT_MASK | FP_SELECT_MASK))) |
555 | 50.9k | goto illegal_opcode; |
556 | | |
557 | | |
558 | 30.5k | switch (opcode) |
559 | 30.5k | { |
560 | 342 | case 0: |
561 | | /* ADD instruction. */ |
562 | 342 | (*info->fprintf_func) (info->stream, "add.%s r%d,r%d,r%d", |
563 | 342 | size_names[size], dest, source_a, source_b); |
564 | 342 | break; |
565 | 129 | case 1: |
566 | | /* ADC instruction. */ |
567 | 129 | (*info->fprintf_func) (info->stream, "adc.%s r%d,r%d,r%d", |
568 | 129 | size_names[size], dest, source_a, source_b); |
569 | 129 | break; |
570 | 124 | case 2: |
571 | | /* SUB instruction. */ |
572 | 124 | if (dest == 0) |
573 | 25 | (*info->fprintf_func) (info->stream, "cmp.%s r%d,r%d", |
574 | 25 | size_names[size], source_a, source_b); |
575 | 99 | else |
576 | 99 | (*info->fprintf_func) (info->stream, "sub.%s r%d,r%d,r%d", |
577 | 99 | size_names[size], dest, source_a, source_b); |
578 | 124 | break; |
579 | 286 | case 3: |
580 | | /* SUBC instruction. */ |
581 | 286 | if (dest == 0) |
582 | 110 | (*info->fprintf_func) (info->stream, "cmpc.%s r%d,r%d", |
583 | 110 | size_names[size], source_a, source_b); |
584 | 176 | else |
585 | 176 | (*info->fprintf_func) (info->stream, "subc.%s r%d,r%d,r%d", |
586 | 176 | size_names[size], dest, source_a, source_b); |
587 | 286 | break; |
588 | 193 | case 4: |
589 | | /* EXTW instruction. */ |
590 | 193 | if (size == 1) |
591 | 31 | goto illegal_opcode; |
592 | | |
593 | 162 | (*info->fprintf_func) (info->stream, "extw.%s r%d,r%d", |
594 | 162 | size_names[size], dest, source_a); |
595 | 162 | break; |
596 | 232 | case 5: |
597 | | /* ASR instruction. */ |
598 | 232 | if (ins & CLASS3_SOURCEB_IMMED) |
599 | 140 | (*info->fprintf_func) (info->stream, "asr.%s r%d,r%d,%d", |
600 | 140 | size_names[size], dest, source_a, source_b); |
601 | 92 | else |
602 | 92 | (*info->fprintf_func) (info->stream, "asr.%s r%d,r%d,r%d", |
603 | 92 | size_names[size], dest, source_a, source_b); |
604 | 232 | break; |
605 | 89 | case 6: |
606 | | /* LSR instruction. */ |
607 | 89 | if (ins & CLASS3_SOURCEB_IMMED) |
608 | 33 | (*info->fprintf_func) (info->stream, "lsr.%s r%d,r%d,%d", |
609 | 33 | size_names[size], dest, source_a, source_b); |
610 | 56 | else |
611 | 56 | (*info->fprintf_func) (info->stream, "lsr.%s r%d,r%d,r%d", |
612 | 56 | size_names[size], dest, source_a, source_b); |
613 | 89 | break; |
614 | 154 | case 7: |
615 | | /* ASL instruction. */ |
616 | 154 | if (ins & CLASS3_SOURCEB_IMMED) |
617 | 86 | (*info->fprintf_func) (info->stream, "asl.%s r%d,r%d,%d", |
618 | 86 | size_names[size], dest, source_a, source_b); |
619 | 68 | else |
620 | 68 | (*info->fprintf_func) (info->stream, "asl.%s r%d,r%d,r%d", |
621 | 68 | size_names[size], dest, source_a, source_b); |
622 | 154 | break; |
623 | 294 | case 8: |
624 | | /* XOR instruction. */ |
625 | 294 | (*info->fprintf_func) (info->stream, "xor.%s r%d,r%d,r%d", |
626 | 294 | size_names[size], dest, source_a, source_b); |
627 | 294 | break; |
628 | 112 | case 9: |
629 | | /* OR instruction. */ |
630 | 112 | if (source_b == 0) |
631 | 39 | (*info->fprintf_func) (info->stream, "move.%s r%d,r%d", |
632 | 39 | size_names[size], dest, source_a); |
633 | 73 | else |
634 | 73 | (*info->fprintf_func) (info->stream, "or.%s r%d,r%d,r%d", |
635 | 73 | size_names[size], dest, source_a, source_b); |
636 | 112 | break; |
637 | 57 | case 10: |
638 | | /* AND instruction. */ |
639 | 57 | (*info->fprintf_func) (info->stream, "and.%s r%d,r%d,r%d", |
640 | 57 | size_names[size], dest, source_a, source_b); |
641 | 57 | break; |
642 | 132 | case 11: |
643 | | /* NOT instruction. */ |
644 | 132 | (*info->fprintf_func) (info->stream, "not.%s r%d,r%d", |
645 | 132 | size_names[size], dest, source_a); |
646 | 132 | break; |
647 | 347 | case 12: |
648 | | /* BRA instruction. */ |
649 | 347 | { |
650 | 347 | unsigned cbf = (ins >> 27) & 0x000f; |
651 | | |
652 | 347 | if (size != 4) |
653 | 324 | goto illegal_opcode; |
654 | | |
655 | 23 | (*info->fprintf_func) (info->stream, "bra %s,r%d,r%d", |
656 | 23 | cc_names[cbf], source_a, dest); |
657 | 23 | } |
658 | 0 | break; |
659 | 106 | case 13: |
660 | | /* RFLAG instruction. */ |
661 | 106 | if (source_a || size != 4) |
662 | 106 | goto illegal_opcode; |
663 | | |
664 | 0 | (*info->fprintf_func) (info->stream, "rflag r%d", dest); |
665 | 0 | break; |
666 | 40 | case 14: |
667 | | /* EXTB instruction. */ |
668 | 40 | (*info->fprintf_func) (info->stream, "extb.%s r%d,r%d", |
669 | 40 | size_names[size], dest, source_a); |
670 | 40 | break; |
671 | 27.9k | case 15: |
672 | 27.9k | if (!(ins & CLASS3_SOURCEB_IMMED)) |
673 | 3.08k | goto illegal_opcode; |
674 | | |
675 | 24.8k | if (ins & EAM_SELECT_MASK) |
676 | 23.7k | { |
677 | | /* Extension arithmetic module read. */ |
678 | 23.7k | int fp_ins = (ins >> 27) & 0xf; |
679 | | |
680 | 23.7k | if (size != 4) |
681 | 23.2k | goto illegal_opcode; |
682 | | |
683 | 475 | if (ins & FP_SELECT_MASK) |
684 | 235 | { |
685 | | /* Check fsrcA <= 15 and fsrcB <= 15. */ |
686 | 235 | if (ins & ((1 << 20) | (1 << 8))) |
687 | 191 | goto illegal_opcode; |
688 | | |
689 | 44 | switch (fp_ins) |
690 | 44 | { |
691 | 1 | case 0: |
692 | 1 | if (source_b) |
693 | 1 | goto illegal_opcode; |
694 | | |
695 | 0 | (*info->fprintf_func) (info->stream, "fstore r%d,f%d", |
696 | 0 | dest, source_a); |
697 | 0 | break; |
698 | 0 | case 10: |
699 | 0 | (*info->fprintf_func) (info->stream, "fcmp r%d,f%d,f%d", |
700 | 0 | dest, source_a, source_b); |
701 | 0 | break; |
702 | 6 | case 11: |
703 | 6 | (*info->fprintf_func) (info->stream, "fcmpe r%d,f%d,f%d", |
704 | 6 | dest, source_a, source_b); |
705 | 6 | break; |
706 | 37 | default: |
707 | 37 | (*info->fprintf_func) (info->stream, |
708 | 37 | "fpuread %d,r%d,f%d,f%d", fp_ins, |
709 | 37 | dest, source_a, source_b); |
710 | 37 | break; |
711 | 44 | } |
712 | 44 | } |
713 | 240 | else |
714 | 240 | { |
715 | 240 | if (fp_ins || source_a) |
716 | 240 | goto illegal_opcode; |
717 | | |
718 | 0 | switch (source_b) |
719 | 0 | { |
720 | 0 | case 0: |
721 | 0 | (*info->fprintf_func) (info->stream, "readmda r%d", dest); |
722 | 0 | break; |
723 | 0 | case 1: |
724 | 0 | (*info->fprintf_func) (info->stream, "readmdb r%d", dest); |
725 | 0 | break; |
726 | 0 | case 2: |
727 | 0 | (*info->fprintf_func) (info->stream, "readmdc r%d", dest); |
728 | 0 | break; |
729 | 0 | default: |
730 | 0 | (*info->fprintf_func) (info->stream, "eamread r%d,%d", |
731 | 0 | dest, source_b); |
732 | 0 | break; |
733 | 0 | } |
734 | 0 | } |
735 | 475 | } |
736 | 1.11k | else |
737 | 1.11k | { |
738 | 1.11k | if (ins & FP_SELECT_MASK) |
739 | 584 | goto illegal_opcode; |
740 | | |
741 | | /* READ instruction. */ |
742 | 533 | (*info->fprintf_func) (info->stream, "read.%s r%d,%d(r%d)", |
743 | 533 | size_names[size], dest, source_b, source_a); |
744 | 533 | } |
745 | 576 | break; |
746 | 30.5k | } |
747 | | |
748 | 2.75k | return 0; |
749 | | |
750 | 78.7k | illegal_opcode: |
751 | 78.7k | return -1; |
752 | | |
753 | 30.5k | } |
754 | | |
755 | | /* Print the visium instruction at address addr in debugged memory, |
756 | | on info->stream. Return length of the instruction, in bytes. */ |
757 | | |
758 | | int |
759 | | print_insn_visium (bfd_vma addr, disassemble_info *info) |
760 | 545k | { |
761 | 545k | unsigned ins; |
762 | 545k | unsigned p1, p2; |
763 | 545k | int ans; |
764 | 545k | int i; |
765 | | |
766 | | /* Stuff copied from m68k-dis.c. */ |
767 | 545k | struct private priv; |
768 | 545k | bfd_byte *buffer = priv.the_buffer; |
769 | 545k | info->private_data = &priv; |
770 | 545k | priv.max_fetched = priv.the_buffer; |
771 | 545k | priv.insn_start = addr; |
772 | 545k | if (setjmp (priv.bailout) != 0) |
773 | 420 | { |
774 | | /* Error return. */ |
775 | 420 | return -1; |
776 | 420 | } |
777 | | |
778 | | /* We do return this info. */ |
779 | 545k | info->insn_info_valid = 1; |
780 | | |
781 | | /* Assume non branch insn. */ |
782 | 545k | info->insn_type = dis_nonbranch; |
783 | | |
784 | | /* Assume no delay. */ |
785 | 545k | info->branch_delay_insns = 0; |
786 | | |
787 | | /* Assume no target known. */ |
788 | 545k | info->target = 0; |
789 | | |
790 | | /* Get 32-bit instruction word. */ |
791 | 545k | FETCH_DATA (info, buffer + 4); |
792 | 545k | ins = (unsigned) buffer[0] << 24; |
793 | 545k | ins |= buffer[1] << 16; |
794 | 545k | ins |= buffer[2] << 8; |
795 | 545k | ins |= buffer[3]; |
796 | | |
797 | 545k | ans = 0; |
798 | | |
799 | 545k | p1 = buffer[0] ^ buffer[1] ^ buffer[2] ^ buffer[3]; |
800 | 545k | p2 = 0; |
801 | 4.90M | for (i = 0; i < 8; i++) |
802 | 4.36M | { |
803 | 4.36M | p2 += p1 & 1; |
804 | 4.36M | p1 >>= 1; |
805 | 4.36M | } |
806 | | |
807 | | /* Decode the instruction. */ |
808 | 545k | if (p2 & 1) |
809 | 212k | ans = -1; |
810 | 332k | else |
811 | 332k | { |
812 | 332k | switch ((ins >> 25) & 0x3) |
813 | 332k | { |
814 | 145k | case 0: |
815 | 145k | ans = disassem_class0 (info, ins); |
816 | 145k | break; |
817 | 53.0k | case 1: |
818 | 53.0k | ans = disassem_class1 (info, ins); |
819 | 53.0k | break; |
820 | 52.1k | case 2: |
821 | 52.1k | ans = disassem_class2 (info, ins); |
822 | 52.1k | break; |
823 | 81.5k | case 3: |
824 | 81.5k | ans = disassem_class3 (info, ins); |
825 | 81.5k | break; |
826 | 332k | } |
827 | 332k | } |
828 | | |
829 | 545k | if (ans != 0) |
830 | 471k | (*info->fprintf_func) (info->stream, "err"); |
831 | | |
832 | | /* Return number of bytes consumed (always 4 for the Visium). */ |
833 | 545k | return 4; |
834 | 545k | } |