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