source: branches/libc-0.6/src/binutils/opcodes/i960-dis.c

Last change on this file was 610, checked in by bird, 22 years ago

This commit was generated by cvs2svn to compensate for changes in r609,
which included commits to RCS files with non-trunk default branches.

  • Property cvs2svn:cvs-rev set to 1.1.1.2
  • Property svn:eol-style set to native
  • Property svn:executable set to *
File size: 23.3 KB
Line 
1/* Disassemble i80960 instructions.
2 Copyright 1990, 1991, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001
3 Free Software Foundation, Inc.
4
5This program is free software; you can redistribute it and/or modify
6it under the terms of the GNU General Public License as published by
7the Free Software Foundation; either version 2, or (at your option)
8any later version.
9
10This program is distributed in the hope that it will be useful,
11but WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; see the file COPYING. If not, write to the
17Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
1802111-1307, USA. */
19
20#include "sysdep.h"
21#include "dis-asm.h"
22
23static const char *const reg_names[] = {
24/* 0 */ "pfp", "sp", "rip", "r3", "r4", "r5", "r6", "r7",
25/* 8 */ "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
26/* 16 */ "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7",
27/* 24 */ "g8", "g9", "g10", "g11", "g12", "g13", "g14", "fp",
28/* 32 */ "pc", "ac", "ip", "tc", "fp0", "fp1", "fp2", "fp3"
29};
30
31
32static FILE *stream; /* Output goes here */
33static struct disassemble_info *info;
34static void print_addr PARAMS ((bfd_vma));
35static void ctrl PARAMS ((bfd_vma, unsigned long, unsigned long));
36static void cobr PARAMS ((bfd_vma, unsigned long, unsigned long));
37static void reg PARAMS ((unsigned long));
38static int mem PARAMS ((bfd_vma, unsigned long, unsigned long, int));
39static void ea PARAMS ((bfd_vma, int, const char *, const char *, int, unsigned int));
40static void dstop PARAMS ((int, int, int));
41static void regop PARAMS ((int, int, int, int));
42static void invalid PARAMS ((int));
43static int pinsn PARAMS ((bfd_vma, unsigned long, unsigned long));
44static void put_abs PARAMS ((unsigned long, unsigned long));
45
46
47/* Print the i960 instruction at address 'memaddr' in debugged memory,
48 on INFO->STREAM. Returns length of the instruction, in bytes. */
49
50int
51print_insn_i960 (memaddr, info_arg)
52 bfd_vma memaddr;
53 struct disassemble_info *info_arg;
54{
55 unsigned int word1, word2 = 0xdeadbeef;
56 bfd_byte buffer[8];
57 int status;
58
59 info = info_arg;
60 stream = info->stream;
61
62 /* Read word1. Only read word2 if the instruction
63 needs it, to prevent reading past the end of a section. */
64
65 status = (*info->read_memory_func) (memaddr, (bfd_byte *) buffer, 4, info);
66 if (status != 0)
67 {
68 (*info->memory_error_func) (status, memaddr, info);
69 return -1;
70 }
71
72 word1 = bfd_getl32 (buffer);
73
74 /* Divide instruction set into classes based on high 4 bits of opcode. */
75 switch ( (word1 >> 28) & 0xf )
76 {
77 default:
78 break;
79 case 0x8:
80 case 0x9:
81 case 0xa:
82 case 0xb:
83 case 0xc:
84 /* Read word2. */
85 status = (*info->read_memory_func)
86 (memaddr + 4, (bfd_byte *) (buffer + 4), 4, info);
87 if (status != 0)
88 {
89 (*info->memory_error_func) (status, memaddr, info);
90 return -1;
91 }
92 word2 = bfd_getl32 (buffer + 4);
93 break;
94 }
95
96 return pinsn( memaddr, word1, word2 );
97}
98
99
100#define IN_GDB
101
102/*****************************************************************************
103 * All code below this point should be identical with that of
104 * the disassembler in gdmp960.
105
106 A noble sentiment, but at least in cosmetic ways (info->fprintf_func), it
107 just ain't so. -kingdon, 31 Mar 93
108 *****************************************************************************/
109
110struct tabent {
111 char *name;
112 short numops;
113};
114
115struct sparse_tabent {
116 int opcode;
117 char *name;
118 short numops;
119};
120
121static int
122pinsn (memaddr, word1, word2)
123 bfd_vma memaddr;
124 unsigned long word1, word2;
125{
126 int instr_len;
127
128 instr_len = 4;
129 put_abs (word1, word2);
130
131 /* Divide instruction set into classes based on high 4 bits of opcode. */
132 switch ((word1 >> 28) & 0xf)
133 {
134 case 0x0:
135 case 0x1:
136 ctrl (memaddr, word1, word2);
137 break;
138 case 0x2:
139 case 0x3:
140 cobr (memaddr, word1, word2);
141 break;
142 case 0x5:
143 case 0x6:
144 case 0x7:
145 reg (word1);
146 break;
147 case 0x8:
148 case 0x9:
149 case 0xa:
150 case 0xb:
151 case 0xc:
152 instr_len = mem (memaddr, word1, word2, 0);
153 break;
154 default:
155 /* Invalid instruction, print as data word. */
156 invalid (word1);
157 break;
158 }
159 return instr_len;
160}
161
162/* CTRL format.. */
163
164static void
165ctrl (memaddr, word1, word2)
166 bfd_vma memaddr;
167 unsigned long word1;
168 unsigned long word2 ATTRIBUTE_UNUSED;
169{
170 int i;
171 static const struct tabent ctrl_tab[] = {
172 { NULL, 0, }, /* 0x00 */
173 { NULL, 0, }, /* 0x01 */
174 { NULL, 0, }, /* 0x02 */
175 { NULL, 0, }, /* 0x03 */
176 { NULL, 0, }, /* 0x04 */
177 { NULL, 0, }, /* 0x05 */
178 { NULL, 0, }, /* 0x06 */
179 { NULL, 0, }, /* 0x07 */
180 { "b", 1, }, /* 0x08 */
181 { "call", 1, }, /* 0x09 */
182 { "ret", 0, }, /* 0x0a */
183 { "bal", 1, }, /* 0x0b */
184 { NULL, 0, }, /* 0x0c */
185 { NULL, 0, }, /* 0x0d */
186 { NULL, 0, }, /* 0x0e */
187 { NULL, 0, }, /* 0x0f */
188 { "bno", 1, }, /* 0x10 */
189 { "bg", 1, }, /* 0x11 */
190 { "be", 1, }, /* 0x12 */
191 { "bge", 1, }, /* 0x13 */
192 { "bl", 1, }, /* 0x14 */
193 { "bne", 1, }, /* 0x15 */
194 { "ble", 1, }, /* 0x16 */
195 { "bo", 1, }, /* 0x17 */
196 { "faultno", 0, }, /* 0x18 */
197 { "faultg", 0, }, /* 0x19 */
198 { "faulte", 0, }, /* 0x1a */
199 { "faultge", 0, }, /* 0x1b */
200 { "faultl", 0, }, /* 0x1c */
201 { "faultne", 0, }, /* 0x1d */
202 { "faultle", 0, }, /* 0x1e */
203 { "faulto", 0, }, /* 0x1f */
204 };
205
206 i = (word1 >> 24) & 0xff;
207 if ((ctrl_tab[i].name == NULL) || ((word1 & 1) != 0))
208 {
209 invalid (word1);
210 return;
211 }
212
213 (*info->fprintf_func) (stream, ctrl_tab[i].name);
214 if (word1 & 2)
215 /* Predicts branch not taken. */
216 (*info->fprintf_func) (stream, ".f");
217
218 if (ctrl_tab[i].numops == 1)
219 {
220 /* Extract displacement and convert to address. */
221 word1 &= 0x00ffffff;
222
223 if (word1 & 0x00800000)
224 {
225 /* Sign bit is set. */
226 word1 |= (-1 & ~0xffffff); /* Sign extend. */
227 }
228
229 (*info->fprintf_func) (stream, "\t");
230 print_addr (word1 + memaddr);
231 }
232}
233
234/* COBR format. */
235
236static void
237cobr (memaddr, word1, word2)
238 bfd_vma memaddr;
239 unsigned long word1;
240 unsigned long word2 ATTRIBUTE_UNUSED;
241{
242 int src1;
243 int src2;
244 int i;
245
246 static const struct tabent cobr_tab[] = {
247 { "testno", 1, }, /* 0x20 */
248 { "testg", 1, }, /* 0x21 */
249 { "teste", 1, }, /* 0x22 */
250 { "testge", 1, }, /* 0x23 */
251 { "testl", 1, }, /* 0x24 */
252 { "testne", 1, }, /* 0x25 */
253 { "testle", 1, }, /* 0x26 */
254 { "testo", 1, }, /* 0x27 */
255 { NULL, 0, }, /* 0x28 */
256 { NULL, 0, }, /* 0x29 */
257 { NULL, 0, }, /* 0x2a */
258 { NULL, 0, }, /* 0x2b */
259 { NULL, 0, }, /* 0x2c */
260 { NULL, 0, }, /* 0x2d */
261 { NULL, 0, }, /* 0x2e */
262 { NULL, 0, }, /* 0x2f */
263 { "bbc", 3, }, /* 0x30 */
264 { "cmpobg", 3, }, /* 0x31 */
265 { "cmpobe", 3, }, /* 0x32 */
266 { "cmpobge",3, }, /* 0x33 */
267 { "cmpobl", 3, }, /* 0x34 */
268 { "cmpobne",3, }, /* 0x35 */
269 { "cmpoble",3, }, /* 0x36 */
270 { "bbs", 3, }, /* 0x37 */
271 { "cmpibno",3, }, /* 0x38 */
272 { "cmpibg", 3, }, /* 0x39 */
273 { "cmpibe", 3, }, /* 0x3a */
274 { "cmpibge",3, }, /* 0x3b */
275 { "cmpibl", 3, }, /* 0x3c */
276 { "cmpibne",3, }, /* 0x3d */
277 { "cmpible",3, }, /* 0x3e */
278 { "cmpibo", 3, }, /* 0x3f */
279 };
280
281 i = ((word1 >> 24) & 0xff) - 0x20;
282 if (cobr_tab[i].name == NULL)
283 {
284 invalid (word1);
285 return;
286 }
287
288 (*info->fprintf_func) (stream, cobr_tab[i].name);
289
290 /* Predicts branch not taken. */
291 if (word1 & 2)
292 (*info->fprintf_func) (stream, ".f");
293
294 (*info->fprintf_func) (stream, "\t");
295
296 src1 = (word1 >> 19) & 0x1f;
297 src2 = (word1 >> 14) & 0x1f;
298
299 if (word1 & 0x02000)
300 /* M1 is 1 */
301 (*info->fprintf_func) (stream, "%d", src1);
302 else
303 (*info->fprintf_func) (stream, reg_names[src1]);
304
305 if (cobr_tab[i].numops > 1)
306 {
307 if (word1 & 1)
308 /* S2 is 1. */
309 (*info->fprintf_func) (stream, ",sf%d,", src2);
310 else
311 /* S1 is 0. */
312 (*info->fprintf_func) (stream, ",%s,", reg_names[src2]);
313
314 /* Extract displacement and convert to address. */
315 word1 &= 0x00001ffc;
316 if (word1 & 0x00001000)
317 /* Negative displacement. */
318 word1 |= (-1 & ~0x1fff); /* Sign extend. */
319
320 print_addr (memaddr + word1);
321 }
322}
323
324/* MEM format. */
325/* Returns instruction length: 4 or 8. */
326
327static int
328mem (memaddr, word1, word2, noprint)
329 bfd_vma memaddr;
330 unsigned long word1, word2;
331 int noprint; /* If TRUE, return instruction length, but
332 don't output any text. */
333{
334 int i, j;
335 int len;
336 int mode;
337 int offset;
338 const char *reg1, *reg2, *reg3;
339
340 /* This lookup table is too sparse to make it worth typing in, but not
341 so large as to make a sparse array necessary. We create the table
342 at runtime. */
343
344 /* NOTE: In this table, the meaning of 'numops' is:
345 1: single operand
346 2: 2 operands, load instruction
347 -2: 2 operands, store instruction. */
348 static struct tabent *mem_tab;
349 /* Opcodes of 0x8X, 9X, aX, bX, and cX must be in the table. */
350#define MEM_MIN 0x80
351#define MEM_MAX 0xcf
352#define MEM_SIZ ( * sizeof(struct tabent))
353
354 static const struct sparse_tabent mem_init[] = {
355 { 0x80, "ldob", 2 },
356 { 0x82, "stob", -2 },
357 { 0x84, "bx", 1 },
358 { 0x85, "balx", 2 },
359 { 0x86, "callx", 1 },
360 { 0x88, "ldos", 2 },
361 { 0x8a, "stos", -2 },
362 { 0x8c, "lda", 2 },
363 { 0x90, "ld", 2 },
364 { 0x92, "st", -2 },
365 { 0x98, "ldl", 2 },
366 { 0x9a, "stl", -2 },
367 { 0xa0, "ldt", 2 },
368 { 0xa2, "stt", -2 },
369 { 0xac, "dcinva", 1 },
370 { 0xb0, "ldq", 2 },
371 { 0xb2, "stq", -2 },
372 { 0xc0, "ldib", 2 },
373 { 0xc2, "stib", -2 },
374 { 0xc8, "ldis", 2 },
375 { 0xca, "stis", -2 },
376 { 0, NULL, 0 }
377 };
378 static struct tabent mem_tab_buf[MEM_MAX - MEM_MIN + 1];
379
380 if (mem_tab == NULL)
381 {
382 mem_tab = mem_tab_buf;
383
384 for (i = 0; mem_init[i].opcode != 0; i++)
385 {
386 j = mem_init[i].opcode - MEM_MIN;
387 mem_tab[j].name = mem_init[i].name;
388 mem_tab[j].numops = mem_init[i].numops;
389 }
390 }
391
392 i = ((word1 >> 24) & 0xff) - MEM_MIN;
393 mode = (word1 >> 10) & 0xf;
394
395 if ((mem_tab[i].name != NULL) /* Valid instruction */
396 && ((mode == 5) || (mode >= 12)))
397 /* With 32-bit displacement. */
398 len = 8;
399 else
400 len = 4;
401
402 if (noprint)
403 return len;
404
405 if ((mem_tab[i].name == NULL) || (mode == 6))
406 {
407 invalid (word1);
408 return len;
409 }
410
411 (*info->fprintf_func) (stream, "%s\t", mem_tab[i].name);
412
413 reg1 = reg_names[ (word1 >> 19) & 0x1f ]; /* MEMB only */
414 reg2 = reg_names[ (word1 >> 14) & 0x1f ];
415 reg3 = reg_names[ word1 & 0x1f ]; /* MEMB only */
416 offset = word1 & 0xfff; /* MEMA only */
417
418 switch (mem_tab[i].numops)
419 {
420 case 2: /* LOAD INSTRUCTION */
421 if (mode & 4)
422 { /* MEMB FORMAT */
423 ea (memaddr, mode, reg2, reg3, word1, word2);
424 (*info->fprintf_func) (stream, ",%s", reg1);
425 }
426 else
427 { /* MEMA FORMAT */
428 (*info->fprintf_func) (stream, "0x%x", (unsigned) offset);
429
430 if (mode & 8)
431 (*info->fprintf_func) (stream, "(%s)", reg2);
432
433 (*info->fprintf_func)(stream, ",%s", reg1);
434 }
435 break;
436
437 case -2: /* STORE INSTRUCTION */
438 if (mode & 4)
439 {
440 /* MEMB FORMAT */
441 (*info->fprintf_func) (stream, "%s,", reg1);
442 ea (memaddr, mode, reg2, reg3, word1, word2);
443 }
444 else
445 {
446 /* MEMA FORMAT */
447 (*info->fprintf_func) (stream, "%s,0x%x", reg1, (unsigned) offset);
448
449 if (mode & 8)
450 (*info->fprintf_func) (stream, "(%s)", reg2);
451 }
452 break;
453
454 case 1: /* BX/CALLX INSTRUCTION */
455 if (mode & 4)
456 {
457 /* MEMB FORMAT */
458 ea (memaddr, mode, reg2, reg3, word1, word2);
459 }
460 else
461 {
462 /* MEMA FORMAT */
463 (*info->fprintf_func) (stream, "0x%x", (unsigned) offset);
464 if (mode & 8)
465 (*info->fprintf_func) (stream, "(%s)", reg2);
466 }
467 break;
468 }
469
470 return len;
471}
472
473/* REG format. */
474
475static void
476reg (word1)
477 unsigned long word1;
478{
479 int i, j;
480 int opcode;
481 int fp;
482 int m1, m2, m3;
483 int s1, s2;
484 int src, src2, dst;
485 char *mnemp;
486
487 /* This lookup table is too sparse to make it worth typing in, but not
488 so large as to make a sparse array necessary. We create the table
489 at runtime. */
490
491 /* NOTE: In this table, the meaning of 'numops' is:
492 1: single operand, which is NOT a destination.
493 -1: single operand, which IS a destination.
494 2: 2 operands, the 2nd of which is NOT a destination.
495 -2: 2 operands, the 2nd of which IS a destination.
496 3: 3 operands
497
498 If an opcode mnemonic begins with "F", it is a floating-point
499 opcode (the "F" is not printed). */
500
501 static struct tabent *reg_tab;
502 static const struct sparse_tabent reg_init[] =
503 {
504#define REG_MIN 0x580
505 { 0x580, "notbit", 3 },
506 { 0x581, "and", 3 },
507 { 0x582, "andnot", 3 },
508 { 0x583, "setbit", 3 },
509 { 0x584, "notand", 3 },
510 { 0x586, "xor", 3 },
511 { 0x587, "or", 3 },
512 { 0x588, "nor", 3 },
513 { 0x589, "xnor", 3 },
514 { 0x58a, "not", -2 },
515 { 0x58b, "ornot", 3 },
516 { 0x58c, "clrbit", 3 },
517 { 0x58d, "notor", 3 },
518 { 0x58e, "nand", 3 },
519 { 0x58f, "alterbit", 3 },
520 { 0x590, "addo", 3 },
521 { 0x591, "addi", 3 },
522 { 0x592, "subo", 3 },
523 { 0x593, "subi", 3 },
524 { 0x594, "cmpob", 2 },
525 { 0x595, "cmpib", 2 },
526 { 0x596, "cmpos", 2 },
527 { 0x597, "cmpis", 2 },
528 { 0x598, "shro", 3 },
529 { 0x59a, "shrdi", 3 },
530 { 0x59b, "shri", 3 },
531 { 0x59c, "shlo", 3 },
532 { 0x59d, "rotate", 3 },
533 { 0x59e, "shli", 3 },
534 { 0x5a0, "cmpo", 2 },
535 { 0x5a1, "cmpi", 2 },
536 { 0x5a2, "concmpo", 2 },
537 { 0x5a3, "concmpi", 2 },
538 { 0x5a4, "cmpinco", 3 },
539 { 0x5a5, "cmpinci", 3 },
540 { 0x5a6, "cmpdeco", 3 },
541 { 0x5a7, "cmpdeci", 3 },
542 { 0x5ac, "scanbyte", 2 },
543 { 0x5ad, "bswap", -2 },
544 { 0x5ae, "chkbit", 2 },
545 { 0x5b0, "addc", 3 },
546 { 0x5b2, "subc", 3 },
547 { 0x5b4, "intdis", 0 },
548 { 0x5b5, "inten", 0 },
549 { 0x5cc, "mov", -2 },
550 { 0x5d8, "eshro", 3 },
551 { 0x5dc, "movl", -2 },
552 { 0x5ec, "movt", -2 },
553 { 0x5fc, "movq", -2 },
554 { 0x600, "synmov", 2 },
555 { 0x601, "synmovl", 2 },
556 { 0x602, "synmovq", 2 },
557 { 0x603, "cmpstr", 3 },
558 { 0x604, "movqstr", 3 },
559 { 0x605, "movstr", 3 },
560 { 0x610, "atmod", 3 },
561 { 0x612, "atadd", 3 },
562 { 0x613, "inspacc", -2 },
563 { 0x614, "ldphy", -2 },
564 { 0x615, "synld", -2 },
565 { 0x617, "fill", 3 },
566 { 0x630, "sdma", 3 },
567 { 0x631, "udma", 0 },
568 { 0x640, "spanbit", -2 },
569 { 0x641, "scanbit", -2 },
570 { 0x642, "daddc", 3 },
571 { 0x643, "dsubc", 3 },
572 { 0x644, "dmovt", -2 },
573 { 0x645, "modac", 3 },
574 { 0x646, "condrec", -2 },
575 { 0x650, "modify", 3 },
576 { 0x651, "extract", 3 },
577 { 0x654, "modtc", 3 },
578 { 0x655, "modpc", 3 },
579 { 0x656, "receive", -2 },
580 { 0x658, "intctl", -2 },
581 { 0x659, "sysctl", 3 },
582 { 0x65b, "icctl", 3 },
583 { 0x65c, "dcctl", 3 },
584 { 0x65d, "halt", 0 },
585 { 0x660, "calls", 1 },
586 { 0x662, "send", 3 },
587 { 0x663, "sendserv", 1 },
588 { 0x664, "resumprcs", 1 },
589 { 0x665, "schedprcs", 1 },
590 { 0x666, "saveprcs", 0 },
591 { 0x668, "condwait", 1 },
592 { 0x669, "wait", 1 },
593 { 0x66a, "signal", 1 },
594 { 0x66b, "mark", 0 },
595 { 0x66c, "fmark", 0 },
596 { 0x66d, "flushreg", 0 },
597 { 0x66f, "syncf", 0 },
598 { 0x670, "emul", 3 },
599 { 0x671, "ediv", 3 },
600 { 0x673, "ldtime", -1 },
601 { 0x674, "Fcvtir", -2 },
602 { 0x675, "Fcvtilr", -2 },
603 { 0x676, "Fscalerl", 3 },
604 { 0x677, "Fscaler", 3 },
605 { 0x680, "Fatanr", 3 },
606 { 0x681, "Flogepr", 3 },
607 { 0x682, "Flogr", 3 },
608 { 0x683, "Fremr", 3 },
609 { 0x684, "Fcmpor", 2 },
610 { 0x685, "Fcmpr", 2 },
611 { 0x688, "Fsqrtr", -2 },
612 { 0x689, "Fexpr", -2 },
613 { 0x68a, "Flogbnr", -2 },
614 { 0x68b, "Froundr", -2 },
615 { 0x68c, "Fsinr", -2 },
616 { 0x68d, "Fcosr", -2 },
617 { 0x68e, "Ftanr", -2 },
618 { 0x68f, "Fclassr", 1 },
619 { 0x690, "Fatanrl", 3 },
620 { 0x691, "Flogeprl", 3 },
621 { 0x692, "Flogrl", 3 },
622 { 0x693, "Fremrl", 3 },
623 { 0x694, "Fcmporl", 2 },
624 { 0x695, "Fcmprl", 2 },
625 { 0x698, "Fsqrtrl", -2 },
626 { 0x699, "Fexprl", -2 },
627 { 0x69a, "Flogbnrl", -2 },
628 { 0x69b, "Froundrl", -2 },
629 { 0x69c, "Fsinrl", -2 },
630 { 0x69d, "Fcosrl", -2 },
631 { 0x69e, "Ftanrl", -2 },
632 { 0x69f, "Fclassrl", 1 },
633 { 0x6c0, "Fcvtri", -2 },
634 { 0x6c1, "Fcvtril", -2 },
635 { 0x6c2, "Fcvtzri", -2 },
636 { 0x6c3, "Fcvtzril", -2 },
637 { 0x6c9, "Fmovr", -2 },
638 { 0x6d9, "Fmovrl", -2 },
639 { 0x6e1, "Fmovre", -2 },
640 { 0x6e2, "Fcpysre", 3 },
641 { 0x6e3, "Fcpyrsre", 3 },
642 { 0x701, "mulo", 3 },
643 { 0x708, "remo", 3 },
644 { 0x70b, "divo", 3 },
645 { 0x741, "muli", 3 },
646 { 0x748, "remi", 3 },
647 { 0x749, "modi", 3 },
648 { 0x74b, "divi", 3 },
649 { 0x780, "addono", 3 },
650 { 0x781, "addino", 3 },
651 { 0x782, "subono", 3 },
652 { 0x783, "subino", 3 },
653 { 0x784, "selno", 3 },
654 { 0x78b, "Fdivr", 3 },
655 { 0x78c, "Fmulr", 3 },
656 { 0x78d, "Fsubr", 3 },
657 { 0x78f, "Faddr", 3 },
658 { 0x790, "addog", 3 },
659 { 0x791, "addig", 3 },
660 { 0x792, "subog", 3 },
661 { 0x793, "subig", 3 },
662 { 0x794, "selg", 3 },
663 { 0x79b, "Fdivrl", 3 },
664 { 0x79c, "Fmulrl", 3 },
665 { 0x79d, "Fsubrl", 3 },
666 { 0x79f, "Faddrl", 3 },
667 { 0x7a0, "addoe", 3 },
668 { 0x7a1, "addie", 3 },
669 { 0x7a2, "suboe", 3 },
670 { 0x7a3, "subie", 3 },
671 { 0x7a4, "sele", 3 },
672 { 0x7b0, "addoge", 3 },
673 { 0x7b1, "addige", 3 },
674 { 0x7b2, "suboge", 3 },
675 { 0x7b3, "subige", 3 },
676 { 0x7b4, "selge", 3 },
677 { 0x7c0, "addol", 3 },
678 { 0x7c1, "addil", 3 },
679 { 0x7c2, "subol", 3 },
680 { 0x7c3, "subil", 3 },
681 { 0x7c4, "sell", 3 },
682 { 0x7d0, "addone", 3 },
683 { 0x7d1, "addine", 3 },
684 { 0x7d2, "subone", 3 },
685 { 0x7d3, "subine", 3 },
686 { 0x7d4, "selne", 3 },
687 { 0x7e0, "addole", 3 },
688 { 0x7e1, "addile", 3 },
689 { 0x7e2, "subole", 3 },
690 { 0x7e3, "subile", 3 },
691 { 0x7e4, "selle", 3 },
692 { 0x7f0, "addoo", 3 },
693 { 0x7f1, "addio", 3 },
694 { 0x7f2, "suboo", 3 },
695 { 0x7f3, "subio", 3 },
696 { 0x7f4, "selo", 3 },
697#define REG_MAX 0x7f4
698 { 0, NULL, 0 }
699 };
700 static struct tabent reg_tab_buf[REG_MAX - REG_MIN + 1];
701
702 if (reg_tab == NULL)
703 {
704 reg_tab = reg_tab_buf;
705
706 for (i = 0; reg_init[i].opcode != 0; i++)
707 {
708 j = reg_init[i].opcode - REG_MIN;
709 reg_tab[j].name = reg_init[i].name;
710 reg_tab[j].numops = reg_init[i].numops;
711 }
712 }
713
714 opcode = ((word1 >> 20) & 0xff0) | ((word1 >> 7) & 0xf);
715 i = opcode - REG_MIN;
716
717 if ((opcode<REG_MIN) || (opcode>REG_MAX) || (reg_tab[i].name==NULL))
718 {
719 invalid (word1);
720 return;
721 }
722
723 mnemp = reg_tab[i].name;
724 if (*mnemp == 'F')
725 {
726 fp = 1;
727 mnemp++;
728 }
729 else
730 {
731 fp = 0;
732 }
733
734 (*info->fprintf_func) (stream, mnemp);
735
736 s1 = (word1 >> 5) & 1;
737 s2 = (word1 >> 6) & 1;
738 m1 = (word1 >> 11) & 1;
739 m2 = (word1 >> 12) & 1;
740 m3 = (word1 >> 13) & 1;
741 src = word1 & 0x1f;
742 src2 = (word1 >> 14) & 0x1f;
743 dst = (word1 >> 19) & 0x1f;
744
745 if (reg_tab[i].numops != 0)
746 {
747 (*info->fprintf_func) (stream, "\t");
748
749 switch (reg_tab[i].numops)
750 {
751 case 1:
752 regop (m1, s1, src, fp);
753 break;
754 case -1:
755 dstop (m3, dst, fp);
756 break;
757 case 2:
758 regop (m1, s1, src, fp);
759 (*info->fprintf_func) (stream, ",");
760 regop (m2, s2, src2, fp);
761 break;
762 case -2:
763 regop (m1, s1, src, fp);
764 (*info->fprintf_func) (stream, ",");
765 dstop (m3, dst, fp);
766 break;
767 case 3:
768 regop (m1, s1, src, fp);
769 (*info->fprintf_func) (stream, ",");
770 regop (m2, s2, src2, fp);
771 (*info->fprintf_func) (stream, ",");
772 dstop (m3, dst, fp);
773 break;
774 }
775 }
776}
777
778/* Print out effective address for memb instructions. */
779
780static void
781ea (memaddr, mode, reg2, reg3, word1, word2)
782 bfd_vma memaddr;
783 int mode;
784 const char *reg2;
785 const char *reg3;
786 int word1;
787 unsigned int word2;
788{
789 int scale;
790 static const int scale_tab[] = { 1, 2, 4, 8, 16 };
791
792 scale = (word1 >> 7) & 0x07;
793
794 if ((scale > 4) || (((word1 >> 5) & 0x03) != 0))
795 {
796 invalid (word1);
797 return;
798 }
799 scale = scale_tab[scale];
800
801 switch (mode)
802 {
803 case 4: /* (reg) */
804 (*info->fprintf_func)( stream, "(%s)", reg2 );
805 break;
806 case 5: /* displ+8(ip) */
807 print_addr (word2 + 8 + memaddr);
808 break;
809 case 7: /* (reg)[index*scale] */
810 if (scale == 1)
811 (*info->fprintf_func) (stream, "(%s)[%s]", reg2, reg3);
812 else
813 (*info->fprintf_func) (stream, "(%s)[%s*%d]", reg2, reg3, scale);
814 break;
815 case 12: /* displacement */
816 print_addr ((bfd_vma) word2);
817 break;
818 case 13: /* displ(reg) */
819 print_addr ((bfd_vma) word2);
820 (*info->fprintf_func) (stream, "(%s)", reg2);
821 break;
822 case 14: /* displ[index*scale] */
823 print_addr ((bfd_vma) word2);
824 if (scale == 1)
825 (*info->fprintf_func) (stream, "[%s]", reg3);
826 else
827 (*info->fprintf_func) (stream, "[%s*%d]", reg3, scale);
828 break;
829 case 15: /* displ(reg)[index*scale] */
830 print_addr ((bfd_vma) word2);
831 if (scale == 1)
832 (*info->fprintf_func) (stream, "(%s)[%s]", reg2, reg3);
833 else
834 (*info->fprintf_func) (stream, "(%s)[%s*%d]", reg2, reg3, scale);
835 break;
836 default:
837 invalid (word1);
838 return;
839 }
840}
841
842
843/* Register Instruction Operand. */
844
845static void
846regop (mode, spec, reg, fp)
847 int mode, spec, reg, fp;
848{
849 if (fp)
850 {
851 /* Floating point instruction. */
852 if (mode == 1)
853 {
854 /* FP operand. */
855 switch (reg)
856 {
857 case 0: (*info->fprintf_func) (stream, "fp0");
858 break;
859 case 1: (*info->fprintf_func) (stream, "fp1");
860 break;
861 case 2: (*info->fprintf_func) (stream, "fp2");
862 break;
863 case 3: (*info->fprintf_func) (stream, "fp3");
864 break;
865 case 16: (*info->fprintf_func) (stream, "0f0.0");
866 break;
867 case 22: (*info->fprintf_func) (stream, "0f1.0");
868 break;
869 default: (*info->fprintf_func) (stream, "?");
870 break;
871 }
872 }
873 else
874 {
875 /* Non-FP register. */
876 (*info->fprintf_func) (stream, reg_names[reg]);
877 }
878 }
879 else
880 {
881 /* Not floating point. */
882 if (mode == 1)
883 {
884 /* Literal. */
885 (*info->fprintf_func) (stream, "%d", reg);
886 }
887 else
888 {
889 /* Register. */
890 if (spec == 0)
891 (*info->fprintf_func) (stream, reg_names[reg]);
892 else
893 (*info->fprintf_func) (stream, "sf%d", reg);
894 }
895 }
896}
897
898/* Register Instruction Destination Operand. */
899
900static void
901dstop (mode, reg, fp)
902 int mode, reg, fp;
903{
904 /* 'dst' operand can't be a literal. On non-FP instructions, register
905 mode is assumed and "m3" acts as if were "s3"; on FP-instructions,
906 sf registers are not allowed so m3 acts normally. */
907 if (fp)
908 regop (mode, 0, reg, fp);
909 else
910 regop (0, mode, reg, fp);
911}
912
913static void
914invalid (word1)
915 int word1;
916{
917 (*info->fprintf_func) (stream, ".word\t0x%08x", (unsigned) word1);
918}
919
920static void
921print_addr (a)
922 bfd_vma a;
923{
924 (*info->print_address_func) (a, info);
925}
926
927static void
928put_abs (word1, word2)
929 unsigned long word1 ATTRIBUTE_UNUSED;
930 unsigned long word2 ATTRIBUTE_UNUSED;
931{
932#ifdef IN_GDB
933 return;
934#else
935 int len;
936
937 switch ((word1 >> 28) & 0xf)
938 {
939 case 0x8:
940 case 0x9:
941 case 0xa:
942 case 0xb:
943 case 0xc:
944 /* MEM format instruction. */
945 len = mem (0, word1, word2, 1);
946 break;
947 default:
948 len = 4;
949 break;
950 }
951
952 if (len == 8)
953 (*info->fprintf_func) (stream, "%08x %08x\t", word1, word2);
954 else
955 (*info->fprintf_func) (stream, "%08x \t", word1);
956#endif
957}
Note: See TracBrowser for help on using the repository browser.