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