/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-2024 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 | 201k | ((addr) <= ((struct private *)(info->private_data))->max_fetched \ |
49 | 201k | ? 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 | 201k | { |
56 | 201k | int status; |
57 | 201k | struct private *priv = (struct private *) info->private_data; |
58 | 201k | bfd_vma start = priv->insn_start + (priv->max_fetched - priv->the_buffer); |
59 | | |
60 | 201k | status = (*info->read_memory_func) (start, |
61 | 201k | priv->max_fetched, |
62 | 201k | addr - priv->max_fetched, info); |
63 | 201k | if (status != 0) |
64 | 119 | { |
65 | 119 | (*info->memory_error_func) (status, start, info); |
66 | 119 | longjmp (priv->bailout, 1); |
67 | 119 | } |
68 | 201k | else |
69 | 201k | priv->max_fetched = addr; |
70 | 201k | return 1; |
71 | 201k | } |
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 | 45.8k | { |
86 | 45.8k | int opcode = (ins >> 21) & 0x000f; |
87 | | |
88 | 45.8k | if (ins & CLASS0_UNUSED_MASK) |
89 | 24.9k | goto illegal_opcode; |
90 | | |
91 | 20.9k | switch (opcode) |
92 | 20.9k | { |
93 | 17.8k | case 0: |
94 | | /* BRR instruction. */ |
95 | 17.8k | { |
96 | 17.8k | unsigned cbf = (ins >> 27) & 0x000f; |
97 | 17.8k | int displacement = ((ins & 0xffff) ^ 0x8000) - 0x8000; |
98 | | |
99 | 17.8k | if (ins == 0) |
100 | 11.1k | (*info->fprintf_func) (info->stream, "nop"); |
101 | 6.73k | else |
102 | 6.73k | (*info->fprintf_func) (info->stream, "brr %s,%+d", |
103 | 6.73k | cc_names[cbf], displacement); |
104 | 17.8k | } |
105 | 17.8k | break; |
106 | 235 | case 1: |
107 | | /* Illegal opcode. */ |
108 | 235 | goto illegal_opcode; |
109 | 0 | break; |
110 | 256 | case 2: |
111 | | /* Illegal opcode. */ |
112 | 256 | goto illegal_opcode; |
113 | 0 | break; |
114 | 225 | case 3: |
115 | | /* Illegal opcode. */ |
116 | 225 | goto illegal_opcode; |
117 | 0 | break; |
118 | 364 | case 4: |
119 | | /* Illegal opcode. */ |
120 | 364 | goto illegal_opcode; |
121 | 0 | break; |
122 | 546 | case 5: |
123 | | /* Illegal opcode. */ |
124 | 546 | goto illegal_opcode; |
125 | 0 | break; |
126 | 142 | case 6: |
127 | | /* Illegal opcode. */ |
128 | 142 | goto illegal_opcode; |
129 | 0 | break; |
130 | 88 | case 7: |
131 | | /* Illegal opcode. */ |
132 | 88 | goto illegal_opcode; |
133 | 0 | break; |
134 | 909 | case 8: |
135 | | /* Illegal opcode. */ |
136 | 909 | goto illegal_opcode; |
137 | 0 | break; |
138 | 53 | case 9: |
139 | | /* Illegal opcode. */ |
140 | 53 | goto illegal_opcode; |
141 | 0 | break; |
142 | 9 | case 10: |
143 | | /* Illegal opcode. */ |
144 | 9 | goto illegal_opcode; |
145 | 0 | break; |
146 | 21 | case 11: |
147 | | /* Illegal opcode. */ |
148 | 21 | goto illegal_opcode; |
149 | 0 | break; |
150 | 78 | case 12: |
151 | | /* Illegal opcode. */ |
152 | 78 | goto illegal_opcode; |
153 | 0 | break; |
154 | 21 | case 13: |
155 | | /* Illegal opcode. */ |
156 | 21 | goto illegal_opcode; |
157 | 0 | break; |
158 | 112 | case 14: |
159 | | /* Illegal opcode. */ |
160 | 112 | goto illegal_opcode; |
161 | 0 | break; |
162 | 17 | case 15: |
163 | | /* Illegal opcode. */ |
164 | 17 | goto illegal_opcode; |
165 | 0 | break; |
166 | 20.9k | } |
167 | 17.8k | return 0; |
168 | | |
169 | 28.0k | illegal_opcode: |
170 | 28.0k | return -1; |
171 | 20.9k | } |
172 | | |
173 | | /* Disassemble non-storage register class instructions. */ |
174 | | |
175 | | static int |
176 | | disassem_class1 (disassemble_info *info, unsigned int ins) |
177 | 19.6k | { |
178 | 19.6k | int opcode = (ins >> 21) & 0xf; |
179 | 19.6k | int source_a = (ins >> 16) & 0x1f; |
180 | 19.6k | int source_b = (ins >> 4) & 0x1f; |
181 | 19.6k | int indx = (ins >> 10) & 0x1f; |
182 | | |
183 | 19.6k | int size = ins & 0x7; |
184 | | |
185 | 19.6k | if (ins & CLASS1_UNUSED_MASK) |
186 | 11.1k | goto illegal_opcode; |
187 | | |
188 | 8.48k | switch (opcode) |
189 | 8.48k | { |
190 | 1.24k | case 0: |
191 | | /* Stop. */ |
192 | 1.24k | (*info->fprintf_func) (info->stream, "stop %d,r%d", indx, source_a); |
193 | 1.24k | break; |
194 | 548 | case 1: |
195 | | /* BMI - Block Move Indirect. */ |
196 | 548 | if (ins != BMI) |
197 | 548 | goto illegal_opcode; |
198 | | |
199 | 0 | (*info->fprintf_func) (info->stream, "bmi r1,r2,r3"); |
200 | 0 | break; |
201 | 345 | case 2: |
202 | | /* Illegal opcode. */ |
203 | 345 | goto illegal_opcode; |
204 | 0 | break; |
205 | 533 | case 3: |
206 | | /* BMD - Block Move Direct. */ |
207 | 533 | if (ins != BMD) |
208 | 533 | goto illegal_opcode; |
209 | | |
210 | 0 | (*info->fprintf_func) (info->stream, "bmd r1,r2,r3"); |
211 | 0 | break; |
212 | 259 | case 4: |
213 | | /* DSI - Disable Interrupts. */ |
214 | 259 | if (ins != DSI) |
215 | 259 | goto illegal_opcode; |
216 | | |
217 | 0 | (*info->fprintf_func) (info->stream, "dsi"); |
218 | 0 | break; |
219 | | |
220 | 216 | case 5: |
221 | | /* ENI - Enable Interrupts. */ |
222 | 216 | if (ins != ENI) |
223 | 216 | goto illegal_opcode; |
224 | | |
225 | 0 | (*info->fprintf_func) (info->stream, "eni"); |
226 | 0 | break; |
227 | | |
228 | 336 | case 6: |
229 | | /* Illegal opcode (was EUT). */ |
230 | 336 | goto illegal_opcode; |
231 | 0 | break; |
232 | 672 | case 7: |
233 | | /* RFI - Return from Interrupt. */ |
234 | 672 | if (ins != RFI) |
235 | 672 | goto illegal_opcode; |
236 | | |
237 | 0 | (*info->fprintf_func) (info->stream, "rfi"); |
238 | 0 | break; |
239 | 821 | case 8: |
240 | | /* Illegal opcode. */ |
241 | 821 | goto illegal_opcode; |
242 | 0 | break; |
243 | 481 | case 9: |
244 | | /* Illegal opcode. */ |
245 | 481 | goto illegal_opcode; |
246 | 0 | break; |
247 | 258 | case 10: |
248 | | /* Illegal opcode. */ |
249 | 258 | goto illegal_opcode; |
250 | 0 | break; |
251 | 537 | case 11: |
252 | | /* Illegal opcode. */ |
253 | 537 | goto illegal_opcode; |
254 | 0 | break; |
255 | 432 | case 12: |
256 | | /* Illegal opcode. */ |
257 | 432 | goto illegal_opcode; |
258 | 0 | break; |
259 | 256 | case 13: |
260 | 256 | goto illegal_opcode; |
261 | 0 | break; |
262 | 387 | case 14: |
263 | 387 | goto illegal_opcode; |
264 | 0 | break; |
265 | 1.16k | case 15: |
266 | 1.16k | if (ins & EAM_SELECT_MASK) |
267 | 901 | { |
268 | | /* Extension arithmetic module write */ |
269 | 901 | int fp_ins = (ins >> 27) & 0xf; |
270 | | |
271 | 901 | if (size != 4) |
272 | 402 | goto illegal_opcode; |
273 | | |
274 | 499 | if (ins & FP_SELECT_MASK) |
275 | 412 | { |
276 | | /* Which floating point instructions don't need a fsrcB |
277 | | register. */ |
278 | 412 | const int no_fsrcb[16] = { 1, 0, 0, 0, 0, 1, 1, 1, |
279 | 412 | 1, 1, 0, 0, 1, 0, 0, 0 |
280 | 412 | }; |
281 | 412 | if (no_fsrcb[fp_ins] && source_b) |
282 | 14 | 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 | 398 | if (ins & ((1 << 14) | (1 << 8)) || (fp_ins && ins & (1 << 20))) |
288 | 53 | goto illegal_opcode; |
289 | | |
290 | 345 | switch (fp_ins) |
291 | 345 | { |
292 | 41 | case 0: |
293 | 41 | (*info->fprintf_func) (info->stream, "fload f%d,r%d", |
294 | 41 | indx, source_a); |
295 | 41 | break; |
296 | 157 | case 1: |
297 | 157 | (*info->fprintf_func) (info->stream, "fadd f%d,f%d,f%d", |
298 | 157 | indx, source_a, source_b); |
299 | 157 | 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 | 0 | case 3: |
305 | 0 | (*info->fprintf_func) (info->stream, "fmult f%d,f%d,f%d", |
306 | 0 | indx, source_a, source_b); |
307 | 0 | break; |
308 | 0 | case 4: |
309 | 0 | (*info->fprintf_func) (info->stream, "fdiv f%d,f%d,f%d", |
310 | 0 | indx, source_a, source_b); |
311 | 0 | break; |
312 | 2 | case 5: |
313 | 2 | (*info->fprintf_func) (info->stream, "fsqrt f%d,f%d", |
314 | 2 | indx, source_a); |
315 | 2 | break; |
316 | 3 | case 6: |
317 | 3 | (*info->fprintf_func) (info->stream, "fneg f%d,f%d", |
318 | 3 | indx, source_a); |
319 | 3 | break; |
320 | 77 | case 7: |
321 | 77 | (*info->fprintf_func) (info->stream, "fabs f%d,f%d", |
322 | 77 | indx, source_a); |
323 | 77 | break; |
324 | 30 | case 8: |
325 | 30 | (*info->fprintf_func) (info->stream, "ftoi f%d,f%d", |
326 | 30 | indx, source_a); |
327 | 30 | break; |
328 | 25 | case 9: |
329 | 25 | (*info->fprintf_func) (info->stream, "itof f%d,f%d", |
330 | 25 | indx, source_a); |
331 | 25 | break; |
332 | 6 | case 12: |
333 | 6 | (*info->fprintf_func) (info->stream, "fmove f%d,f%d", |
334 | 6 | indx, source_a); |
335 | 6 | break; |
336 | 4 | default: |
337 | 4 | (*info->fprintf_func) (info->stream, |
338 | 4 | "fpinst %d,f%d,f%d,f%d", fp_ins, |
339 | 4 | indx, source_a, source_b); |
340 | 4 | break; |
341 | 345 | } |
342 | 345 | } |
343 | 87 | else |
344 | 87 | { |
345 | | /* Which EAM operations do not need a srcB register. */ |
346 | 87 | const int no_srcb[32] = |
347 | 87 | { 0, 0, 1, 1, 0, 1, 1, 1, |
348 | 87 | 0, 1, 1, 1, 0, 0, 0, 0, |
349 | 87 | 0, 0, 0, 0, 0, 0, 0, 0, |
350 | 87 | 0, 0, 0, 0, 0, 0, 0, 0 |
351 | 87 | }; |
352 | | |
353 | 87 | if (no_srcb[indx] && source_b) |
354 | 7 | goto illegal_opcode; |
355 | | |
356 | 80 | if (fp_ins) |
357 | 45 | goto illegal_opcode; |
358 | | |
359 | 35 | switch (indx) |
360 | 35 | { |
361 | 0 | case 0: |
362 | 0 | (*info->fprintf_func) (info->stream, "mults r%d,r%d", |
363 | 0 | source_a, source_b); |
364 | 0 | break; |
365 | 0 | case 1: |
366 | 0 | (*info->fprintf_func) (info->stream, "multu r%d,r%d", |
367 | 0 | source_a, source_b); |
368 | 0 | break; |
369 | 0 | case 2: |
370 | 0 | (*info->fprintf_func) (info->stream, "divs r%d", |
371 | 0 | source_a); |
372 | 0 | 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 | 14 | case 5: |
382 | 14 | (*info->fprintf_func) (info->stream, "writemdc r%d", |
383 | 14 | source_a); |
384 | 14 | break; |
385 | 0 | case 6: |
386 | 0 | (*info->fprintf_func) (info->stream, "divds r%d", |
387 | 0 | source_a); |
388 | 0 | break; |
389 | 8 | case 7: |
390 | 8 | (*info->fprintf_func) (info->stream, "divdu r%d", |
391 | 8 | source_a); |
392 | 8 | break; |
393 | 0 | case 9: |
394 | 0 | (*info->fprintf_func) (info->stream, "asrd r%d", |
395 | 0 | source_a); |
396 | 0 | break; |
397 | 0 | case 10: |
398 | 0 | (*info->fprintf_func) (info->stream, "lsrd r%d", |
399 | 0 | source_a); |
400 | 0 | break; |
401 | 0 | case 11: |
402 | 0 | (*info->fprintf_func) (info->stream, "asld r%d", |
403 | 0 | source_a); |
404 | 0 | break; |
405 | 13 | default: |
406 | 13 | (*info->fprintf_func) (info->stream, |
407 | 13 | "eamwrite %d,r%d,r%d", indx, |
408 | 13 | source_a, source_b); |
409 | 13 | break; |
410 | 35 | } |
411 | 35 | } |
412 | 499 | } |
413 | 259 | else |
414 | 259 | { |
415 | | /* WRITE - write to memory. */ |
416 | 259 | (*info->fprintf_func) (info->stream, "write.%s %d(r%d),r%d", |
417 | 259 | size_names[size], indx, source_a, source_b); |
418 | 259 | } |
419 | 639 | break; |
420 | 8.48k | } |
421 | | |
422 | 1.87k | return 0; |
423 | | |
424 | 17.7k | illegal_opcode: |
425 | 17.7k | return -1; |
426 | 8.48k | } |
427 | | |
428 | | /* Disassemble storage immediate class instructions. */ |
429 | | |
430 | | static int |
431 | | disassem_class2 (disassemble_info *info, unsigned int ins) |
432 | 24.1k | { |
433 | 24.1k | int opcode = (ins >> 21) & 0xf; |
434 | 24.1k | int source_a = (ins >> 16) & 0x1f; |
435 | 24.1k | unsigned immediate = ins & 0x0000ffff; |
436 | | |
437 | 24.1k | if (ins & CC_MASK) |
438 | 21.5k | goto illegal_opcode; |
439 | | |
440 | 2.55k | switch (opcode) |
441 | 2.55k | { |
442 | 996 | case 0: |
443 | | /* ADDI instruction. */ |
444 | 996 | (*info->fprintf_func) (info->stream, "addi r%d,%d", source_a, |
445 | 996 | immediate); |
446 | 996 | break; |
447 | 84 | case 1: |
448 | | /* Illegal opcode. */ |
449 | 84 | goto illegal_opcode; |
450 | 0 | break; |
451 | 80 | case 2: |
452 | | /* SUBI instruction. */ |
453 | 80 | (*info->fprintf_func) (info->stream, "subi r%d,%d", source_a, |
454 | 80 | immediate); |
455 | 80 | break; |
456 | 80 | case 3: |
457 | | /* Illegal opcode. */ |
458 | 80 | goto illegal_opcode; |
459 | 0 | break; |
460 | 176 | case 4: |
461 | | /* MOVIL instruction. */ |
462 | 176 | (*info->fprintf_func) (info->stream, "movil r%d,0x%04X", source_a, |
463 | 176 | immediate); |
464 | 176 | break; |
465 | 52 | case 5: |
466 | | /* MOVIU instruction. */ |
467 | 52 | (*info->fprintf_func) (info->stream, "moviu r%d,0x%04X", source_a, |
468 | 52 | immediate); |
469 | 52 | break; |
470 | 62 | case 6: |
471 | | /* MOVIQ instruction. */ |
472 | 62 | (*info->fprintf_func) (info->stream, "moviq r%d,%u", source_a, |
473 | 62 | immediate); |
474 | 62 | break; |
475 | 320 | case 7: |
476 | | /* Illegal opcode. */ |
477 | 320 | goto illegal_opcode; |
478 | 0 | break; |
479 | 255 | case 8: |
480 | | /* WRTL instruction. */ |
481 | 255 | if (source_a != 0) |
482 | 79 | goto illegal_opcode; |
483 | | |
484 | 176 | (*info->fprintf_func) (info->stream, "wrtl 0x%04X", immediate); |
485 | 176 | break; |
486 | 61 | case 9: |
487 | | /* WRTU instruction. */ |
488 | 61 | if (source_a != 0) |
489 | 61 | goto illegal_opcode; |
490 | | |
491 | 0 | (*info->fprintf_func) (info->stream, "wrtu 0x%04X", immediate); |
492 | 0 | break; |
493 | 78 | case 10: |
494 | | /* Illegal opcode. */ |
495 | 78 | goto illegal_opcode; |
496 | 0 | break; |
497 | 34 | case 11: |
498 | | /* Illegal opcode. */ |
499 | 34 | goto illegal_opcode; |
500 | 0 | break; |
501 | 94 | case 12: |
502 | | /* Illegal opcode. */ |
503 | 94 | goto illegal_opcode; |
504 | 0 | break; |
505 | 62 | case 13: |
506 | | /* Illegal opcode. */ |
507 | 62 | goto illegal_opcode; |
508 | 0 | break; |
509 | 42 | case 14: |
510 | | /* Illegal opcode. */ |
511 | 42 | goto illegal_opcode; |
512 | 0 | break; |
513 | 77 | case 15: |
514 | | /* Illegal opcode. */ |
515 | 77 | goto illegal_opcode; |
516 | 0 | break; |
517 | 2.55k | } |
518 | | |
519 | 1.54k | return 0; |
520 | | |
521 | 22.5k | illegal_opcode: |
522 | 22.5k | return -1; |
523 | 2.55k | } |
524 | | |
525 | | /* Disassemble storage register class instructions. */ |
526 | | |
527 | | static int |
528 | | disassem_class3 (disassemble_info *info, unsigned int ins) |
529 | 34.3k | { |
530 | 34.3k | int opcode = (ins >> 21) & 0xf; |
531 | 34.3k | int source_b = (ins >> 4) & 0x1f; |
532 | 34.3k | int source_a = (ins >> 16) & 0x1f; |
533 | 34.3k | int size = ins & 0x7; |
534 | 34.3k | int dest = (ins >> 10) & 0x1f; |
535 | | |
536 | | /* Those instructions that don't have a srcB register. */ |
537 | 34.3k | const int no_srcb[16] = |
538 | 34.3k | { 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 | 34.3k | const int srcb_immed[16] = |
542 | 34.3k | { 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 | 34.3k | if ((no_srcb[opcode] && source_b) |
552 | 34.3k | || (!srcb_immed[opcode] && ins & CLASS3_SOURCEB_IMMED) |
553 | 34.3k | || (opcode != 12 && opcode != 15 && ins & CC_MASK) |
554 | 34.3k | || (opcode != 15 && ins & (EAM_SELECT_MASK | FP_SELECT_MASK))) |
555 | 20.1k | goto illegal_opcode; |
556 | | |
557 | | |
558 | 14.2k | switch (opcode) |
559 | 14.2k | { |
560 | 126 | case 0: |
561 | | /* ADD instruction. */ |
562 | 126 | (*info->fprintf_func) (info->stream, "add.%s r%d,r%d,r%d", |
563 | 126 | size_names[size], dest, source_a, source_b); |
564 | 126 | break; |
565 | 5 | case 1: |
566 | | /* ADC instruction. */ |
567 | 5 | (*info->fprintf_func) (info->stream, "adc.%s r%d,r%d,r%d", |
568 | 5 | size_names[size], dest, source_a, source_b); |
569 | 5 | break; |
570 | 35 | case 2: |
571 | | /* SUB instruction. */ |
572 | 35 | if (dest == 0) |
573 | 13 | (*info->fprintf_func) (info->stream, "cmp.%s r%d,r%d", |
574 | 13 | size_names[size], source_a, source_b); |
575 | 22 | else |
576 | 22 | (*info->fprintf_func) (info->stream, "sub.%s r%d,r%d,r%d", |
577 | 22 | size_names[size], dest, source_a, source_b); |
578 | 35 | break; |
579 | 37 | case 3: |
580 | | /* SUBC instruction. */ |
581 | 37 | if (dest == 0) |
582 | 22 | (*info->fprintf_func) (info->stream, "cmpc.%s r%d,r%d", |
583 | 22 | size_names[size], source_a, source_b); |
584 | 15 | else |
585 | 15 | (*info->fprintf_func) (info->stream, "subc.%s r%d,r%d,r%d", |
586 | 15 | size_names[size], dest, source_a, source_b); |
587 | 37 | break; |
588 | 0 | case 4: |
589 | | /* EXTW instruction. */ |
590 | 0 | if (size == 1) |
591 | 0 | goto illegal_opcode; |
592 | | |
593 | 0 | (*info->fprintf_func) (info->stream, "extw.%s r%d,r%d", |
594 | 0 | size_names[size], dest, source_a); |
595 | 0 | break; |
596 | 22 | case 5: |
597 | | /* ASR instruction. */ |
598 | 22 | if (ins & CLASS3_SOURCEB_IMMED) |
599 | 4 | (*info->fprintf_func) (info->stream, "asr.%s r%d,r%d,%d", |
600 | 4 | size_names[size], dest, source_a, source_b); |
601 | 18 | else |
602 | 18 | (*info->fprintf_func) (info->stream, "asr.%s r%d,r%d,r%d", |
603 | 18 | size_names[size], dest, source_a, source_b); |
604 | 22 | break; |
605 | 26 | case 6: |
606 | | /* LSR instruction. */ |
607 | 26 | if (ins & CLASS3_SOURCEB_IMMED) |
608 | 16 | (*info->fprintf_func) (info->stream, "lsr.%s r%d,r%d,%d", |
609 | 16 | size_names[size], dest, source_a, source_b); |
610 | 10 | else |
611 | 10 | (*info->fprintf_func) (info->stream, "lsr.%s r%d,r%d,r%d", |
612 | 10 | size_names[size], dest, source_a, source_b); |
613 | 26 | break; |
614 | 44 | case 7: |
615 | | /* ASL instruction. */ |
616 | 44 | if (ins & CLASS3_SOURCEB_IMMED) |
617 | 18 | (*info->fprintf_func) (info->stream, "asl.%s r%d,r%d,%d", |
618 | 18 | size_names[size], dest, source_a, source_b); |
619 | 26 | else |
620 | 26 | (*info->fprintf_func) (info->stream, "asl.%s r%d,r%d,r%d", |
621 | 26 | size_names[size], dest, source_a, source_b); |
622 | 44 | break; |
623 | 27 | case 8: |
624 | | /* XOR instruction. */ |
625 | 27 | (*info->fprintf_func) (info->stream, "xor.%s r%d,r%d,r%d", |
626 | 27 | size_names[size], dest, source_a, source_b); |
627 | 27 | break; |
628 | 27 | case 9: |
629 | | /* OR instruction. */ |
630 | 27 | if (source_b == 0) |
631 | 2 | (*info->fprintf_func) (info->stream, "move.%s r%d,r%d", |
632 | 2 | size_names[size], dest, source_a); |
633 | 25 | else |
634 | 25 | (*info->fprintf_func) (info->stream, "or.%s r%d,r%d,r%d", |
635 | 25 | size_names[size], dest, source_a, source_b); |
636 | 27 | break; |
637 | 4 | case 10: |
638 | | /* AND instruction. */ |
639 | 4 | (*info->fprintf_func) (info->stream, "and.%s r%d,r%d,r%d", |
640 | 4 | size_names[size], dest, source_a, source_b); |
641 | 4 | break; |
642 | 1 | case 11: |
643 | | /* NOT instruction. */ |
644 | 1 | (*info->fprintf_func) (info->stream, "not.%s r%d,r%d", |
645 | 1 | size_names[size], dest, source_a); |
646 | 1 | break; |
647 | 63 | case 12: |
648 | | /* BRA instruction. */ |
649 | 63 | { |
650 | 63 | unsigned cbf = (ins >> 27) & 0x000f; |
651 | | |
652 | 63 | if (size != 4) |
653 | 62 | goto illegal_opcode; |
654 | | |
655 | 1 | (*info->fprintf_func) (info->stream, "bra %s,r%d,r%d", |
656 | 1 | cc_names[cbf], source_a, dest); |
657 | 1 | } |
658 | 0 | break; |
659 | 1 | case 13: |
660 | | /* RFLAG instruction. */ |
661 | 1 | if (source_a || size != 4) |
662 | 1 | goto illegal_opcode; |
663 | | |
664 | 0 | (*info->fprintf_func) (info->stream, "rflag r%d", dest); |
665 | 0 | break; |
666 | 15 | case 14: |
667 | | /* EXTB instruction. */ |
668 | 15 | (*info->fprintf_func) (info->stream, "extb.%s r%d,r%d", |
669 | 15 | size_names[size], dest, source_a); |
670 | 15 | break; |
671 | 13.8k | case 15: |
672 | 13.8k | if (!(ins & CLASS3_SOURCEB_IMMED)) |
673 | 1.37k | goto illegal_opcode; |
674 | | |
675 | 12.4k | if (ins & EAM_SELECT_MASK) |
676 | 11.9k | { |
677 | | /* Extension arithmetic module read. */ |
678 | 11.9k | int fp_ins = (ins >> 27) & 0xf; |
679 | | |
680 | 11.9k | if (size != 4) |
681 | 11.8k | goto illegal_opcode; |
682 | | |
683 | 101 | if (ins & FP_SELECT_MASK) |
684 | 42 | { |
685 | | /* Check fsrcA <= 15 and fsrcB <= 15. */ |
686 | 42 | if (ins & ((1 << 20) | (1 << 8))) |
687 | 32 | goto illegal_opcode; |
688 | | |
689 | 10 | switch (fp_ins) |
690 | 10 | { |
691 | 0 | case 0: |
692 | 0 | if (source_b) |
693 | 0 | 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 | 0 | case 11: |
703 | 0 | (*info->fprintf_func) (info->stream, "fcmpe r%d,f%d,f%d", |
704 | 0 | dest, source_a, source_b); |
705 | 0 | break; |
706 | 10 | default: |
707 | 10 | (*info->fprintf_func) (info->stream, |
708 | 10 | "fpuread %d,r%d,f%d,f%d", fp_ins, |
709 | 10 | dest, source_a, source_b); |
710 | 10 | break; |
711 | 10 | } |
712 | 10 | } |
713 | 59 | else |
714 | 59 | { |
715 | 59 | if (fp_ins || source_a) |
716 | 59 | 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 | 101 | } |
736 | 477 | else |
737 | 477 | { |
738 | 477 | if (ins & FP_SELECT_MASK) |
739 | 177 | goto illegal_opcode; |
740 | | |
741 | | /* READ instruction. */ |
742 | 300 | (*info->fprintf_func) (info->stream, "read.%s r%d,%d(r%d)", |
743 | 300 | size_names[size], dest, source_b, source_a); |
744 | 300 | } |
745 | 310 | break; |
746 | 14.2k | } |
747 | | |
748 | 680 | return 0; |
749 | | |
750 | 33.6k | illegal_opcode: |
751 | 33.6k | return -1; |
752 | | |
753 | 14.2k | } |
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 | 201k | { |
761 | 201k | unsigned ins; |
762 | 201k | unsigned p1, p2; |
763 | 201k | int ans; |
764 | 201k | int i; |
765 | | |
766 | | /* Stuff copied from m68k-dis.c. */ |
767 | 201k | struct private priv; |
768 | 201k | bfd_byte *buffer = priv.the_buffer; |
769 | 201k | info->private_data = &priv; |
770 | 201k | priv.max_fetched = priv.the_buffer; |
771 | 201k | priv.insn_start = addr; |
772 | 201k | if (setjmp (priv.bailout) != 0) |
773 | 119 | { |
774 | | /* Error return. */ |
775 | 119 | return -1; |
776 | 119 | } |
777 | | |
778 | | /* We do return this info. */ |
779 | 201k | info->insn_info_valid = 1; |
780 | | |
781 | | /* Assume non branch insn. */ |
782 | 201k | info->insn_type = dis_nonbranch; |
783 | | |
784 | | /* Assume no delay. */ |
785 | 201k | info->branch_delay_insns = 0; |
786 | | |
787 | | /* Assume no target known. */ |
788 | 201k | info->target = 0; |
789 | | |
790 | | /* Get 32-bit instruction word. */ |
791 | 201k | FETCH_DATA (info, buffer + 4); |
792 | 201k | ins = (unsigned) buffer[0] << 24; |
793 | 201k | ins |= buffer[1] << 16; |
794 | 201k | ins |= buffer[2] << 8; |
795 | 201k | ins |= buffer[3]; |
796 | | |
797 | 201k | ans = 0; |
798 | | |
799 | 201k | p1 = buffer[0] ^ buffer[1] ^ buffer[2] ^ buffer[3]; |
800 | 201k | p2 = 0; |
801 | 1.80M | for (i = 0; i < 8; i++) |
802 | 1.60M | { |
803 | 1.60M | p2 += p1 & 1; |
804 | 1.60M | p1 >>= 1; |
805 | 1.60M | } |
806 | | |
807 | | /* Decode the instruction. */ |
808 | 201k | if (p2 & 1) |
809 | 77.0k | ans = -1; |
810 | 124k | else |
811 | 124k | { |
812 | 124k | switch ((ins >> 25) & 0x3) |
813 | 124k | { |
814 | 45.8k | case 0: |
815 | 45.8k | ans = disassem_class0 (info, ins); |
816 | 45.8k | break; |
817 | 19.6k | case 1: |
818 | 19.6k | ans = disassem_class1 (info, ins); |
819 | 19.6k | break; |
820 | 24.1k | case 2: |
821 | 24.1k | ans = disassem_class2 (info, ins); |
822 | 24.1k | break; |
823 | 34.3k | case 3: |
824 | 34.3k | ans = disassem_class3 (info, ins); |
825 | 34.3k | break; |
826 | 124k | } |
827 | 124k | } |
828 | | |
829 | 201k | if (ans != 0) |
830 | 179k | (*info->fprintf_func) (info->stream, "err"); |
831 | | |
832 | | /* Return number of bytes consumed (always 4 for the Visium). */ |
833 | 201k | return 4; |
834 | 201k | } |