Back to index

cell-binutils  2.17cvs20070401
i960-dis.c
Go to the documentation of this file.
00001 /* Disassemble i80960 instructions.
00002    Copyright 1990, 1991, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2003
00003    Free Software Foundation, Inc.
00004 
00005 This program is free software; you can redistribute it and/or modify
00006 it under the terms of the GNU General Public License as published by
00007 the Free Software Foundation; either version 2, or (at your option)
00008 any later version.
00009 
00010 This program is distributed in the hope that it will be useful,
00011 but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013 GNU General Public License for more details.
00014 
00015 You should have received a copy of the GNU General Public License
00016 along with this program; see the file COPYING.  If not, write to the
00017 Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
00018 02110-1301, USA.  */
00019 
00020 #include "sysdep.h"
00021 #include "dis-asm.h"
00022 
00023 static const char *const reg_names[] = {
00024 /*  0 */      "pfp", "sp",  "rip", "r3",  "r4",  "r5",  "r6",  "r7",
00025 /*  8 */      "r8",  "r9",  "r10", "r11", "r12", "r13", "r14", "r15",
00026 /* 16 */      "g0",  "g1",  "g2",  "g3",  "g4",  "g5",  "g6",  "g7",
00027 /* 24 */      "g8",  "g9",  "g10", "g11", "g12", "g13", "g14", "fp",
00028 /* 32 */      "pc",  "ac",  "ip",  "tc",  "fp0", "fp1", "fp2", "fp3"
00029 };
00030 
00031 
00032 static FILE *stream;        /* Output goes here */
00033 static struct disassemble_info *info;
00034 static void print_addr (bfd_vma);
00035 static void ctrl (bfd_vma, unsigned long, unsigned long);
00036 static void cobr (bfd_vma, unsigned long, unsigned long);
00037 static void reg (unsigned long);
00038 static int mem (bfd_vma, unsigned long, unsigned long, int);
00039 static void ea (bfd_vma, int, const char *, const char *, int, unsigned int);
00040 static void dstop (int, int, int);
00041 static void regop (int, int, int, int);
00042 static void invalid (int);
00043 static int pinsn (bfd_vma, unsigned long, unsigned long);
00044 static void put_abs (unsigned long, unsigned long);
00045 
00046 
00047 /* Print the i960 instruction at address 'memaddr' in debugged memory,
00048    on INFO->STREAM.  Returns length of the instruction, in bytes.  */
00049 
00050 int
00051 print_insn_i960 (bfd_vma memaddr, struct disassemble_info *info_arg)
00052 {
00053   unsigned int word1, word2 = 0xdeadbeef;
00054   bfd_byte buffer[8];
00055   int status;
00056 
00057   info = info_arg;
00058   stream = info->stream;
00059 
00060   /* Read word1.  Only read word2 if the instruction
00061      needs it, to prevent reading past the end of a section.  */
00062 
00063   status = (*info->read_memory_func) (memaddr, (bfd_byte *) buffer, 4, info);
00064   if (status != 0)
00065     {
00066       (*info->memory_error_func) (status, memaddr, info);
00067       return -1;
00068     }
00069 
00070   word1 = bfd_getl32 (buffer);
00071 
00072   /* Divide instruction set into classes based on high 4 bits of opcode.  */
00073   switch ( (word1 >> 28) & 0xf )
00074     {
00075     default:
00076       break;
00077     case 0x8:
00078     case 0x9:
00079     case 0xa:
00080     case 0xb:
00081     case 0xc:
00082       /* Read word2.  */
00083       status = (*info->read_memory_func)
00084        (memaddr + 4, (bfd_byte *) (buffer + 4), 4, info);
00085       if (status != 0)
00086        {
00087          (*info->memory_error_func) (status, memaddr, info);
00088          return -1;
00089        }
00090       word2 = bfd_getl32 (buffer + 4);
00091       break;
00092     }
00093 
00094   return pinsn( memaddr, word1, word2 );
00095 }
00096 
00097 #define IN_GDB
00098 
00099 /*****************************************************************************
00100  *     All code below this point should be identical with that of
00101  *     the disassembler in gdmp960.
00102 
00103  A noble sentiment, but at least in cosmetic ways (info->fprintf_func), it
00104  just ain't so. -kingdon, 31 Mar 93
00105  *****************************************************************************/
00106 
00107 struct tabent {
00108   char *name;
00109   short numops;
00110 };
00111 
00112 struct sparse_tabent {
00113   int opcode;
00114   char *name;
00115   short numops;
00116 };
00117 
00118 static int
00119 pinsn (bfd_vma memaddr, unsigned long word1, unsigned long word2)
00120 {
00121   int instr_len;
00122 
00123   instr_len = 4;
00124   put_abs (word1, word2);
00125 
00126   /* Divide instruction set into classes based on high 4 bits of opcode.  */
00127   switch ((word1 >> 28) & 0xf)
00128     {
00129     case 0x0:
00130     case 0x1:
00131       ctrl (memaddr, word1, word2);
00132       break;
00133     case 0x2:
00134     case 0x3:
00135       cobr (memaddr, word1, word2);
00136       break;
00137     case 0x5:
00138     case 0x6:
00139     case 0x7:
00140       reg (word1);
00141       break;
00142     case 0x8:
00143     case 0x9:
00144     case 0xa:
00145     case 0xb:
00146     case 0xc:
00147       instr_len = mem (memaddr, word1, word2, 0);
00148       break;
00149     default:
00150       /* Invalid instruction, print as data word.  */
00151       invalid (word1);
00152       break;
00153     }
00154   return instr_len;
00155 }
00156 
00157 /* CTRL format.. */
00158 
00159 static void
00160 ctrl (bfd_vma memaddr, unsigned long word1, unsigned long word2 ATTRIBUTE_UNUSED)
00161 {
00162   int i;
00163   static const struct tabent ctrl_tab[] = {
00164     { NULL,          0, },  /* 0x00 */
00165     { NULL,          0, },  /* 0x01 */
00166     { NULL,          0, },  /* 0x02 */
00167     { NULL,          0, },  /* 0x03 */
00168     { NULL,          0, },  /* 0x04 */
00169     { NULL,          0, },  /* 0x05 */
00170     { NULL,          0, },  /* 0x06 */
00171     { NULL,          0, },  /* 0x07 */
00172     { "b",           1, },  /* 0x08 */
00173     { "call",        1, },  /* 0x09 */
00174     { "ret",         0, },  /* 0x0a */
00175     { "bal",         1, },  /* 0x0b */
00176     { NULL,          0, },  /* 0x0c */
00177     { NULL,          0, },  /* 0x0d */
00178     { NULL,          0, },  /* 0x0e */
00179     { NULL,          0, },  /* 0x0f */
00180     { "bno",         1, },  /* 0x10 */
00181     { "bg",          1, },  /* 0x11 */
00182     { "be",          1, },  /* 0x12 */
00183     { "bge",         1, },  /* 0x13 */
00184     { "bl",          1, },  /* 0x14 */
00185     { "bne",         1, },  /* 0x15 */
00186     { "ble",         1, },  /* 0x16 */
00187     { "bo",          1, },  /* 0x17 */
00188     { "faultno",     0, },  /* 0x18 */
00189     { "faultg",             0, },  /* 0x19 */
00190     { "faulte",             0, },  /* 0x1a */
00191     { "faultge",     0, },  /* 0x1b */
00192     { "faultl",             0, },  /* 0x1c */
00193     { "faultne",     0, },  /* 0x1d */
00194     { "faultle",     0, },  /* 0x1e */
00195     { "faulto",             0, },  /* 0x1f */
00196   };
00197 
00198   i = (word1 >> 24) & 0xff;
00199   if ((ctrl_tab[i].name == NULL) || ((word1 & 1) != 0))
00200     {
00201       invalid (word1);
00202       return;
00203     }
00204 
00205   (*info->fprintf_func) (stream, ctrl_tab[i].name);
00206   if (word1 & 2)
00207     /* Predicts branch not taken.  */
00208     (*info->fprintf_func) (stream, ".f");
00209 
00210   if (ctrl_tab[i].numops == 1)
00211     {
00212       /* Extract displacement and convert to address.  */
00213       word1 &= 0x00ffffff;
00214 
00215       if (word1 & 0x00800000)
00216        {
00217          /* Sign bit is set.  */
00218          word1 |= (-1 & ~0xffffff);       /* Sign extend.  */
00219        }
00220 
00221       (*info->fprintf_func) (stream, "\t");
00222       print_addr (word1 + memaddr);
00223     }
00224 }
00225 
00226 /* COBR format.  */
00227 
00228 static void
00229 cobr (bfd_vma memaddr, unsigned long word1, unsigned long word2 ATTRIBUTE_UNUSED)
00230 {
00231   int src1;
00232   int src2;
00233   int i;
00234 
00235   static const struct tabent cobr_tab[] = {
00236     { "testno",      1, },  /* 0x20 */
00237     { "testg",       1, },  /* 0x21 */
00238     { "teste",       1, },  /* 0x22 */
00239     { "testge",      1, },  /* 0x23 */
00240     { "testl",       1, },  /* 0x24 */
00241     { "testne",      1, },  /* 0x25 */
00242     { "testle",      1, },  /* 0x26 */
00243     { "testo",       1, },  /* 0x27 */
00244     { NULL,   0, },  /* 0x28 */
00245     { NULL,   0, },  /* 0x29 */
00246     { NULL,   0, },  /* 0x2a */
00247     { NULL,   0, },  /* 0x2b */
00248     { NULL,   0, },  /* 0x2c */
00249     { NULL,   0, },  /* 0x2d */
00250     { NULL,   0, },  /* 0x2e */
00251     { NULL,   0, },  /* 0x2f */
00252     { "bbc",  3, },  /* 0x30 */
00253     { "cmpobg",      3, },  /* 0x31 */
00254     { "cmpobe",      3, },  /* 0x32 */
00255     { "cmpobge",3, },       /* 0x33 */
00256     { "cmpobl",      3, },  /* 0x34 */
00257     { "cmpobne",3, },       /* 0x35 */
00258     { "cmpoble",3, },       /* 0x36 */
00259     { "bbs",  3, },  /* 0x37 */
00260     { "cmpibno",3, },       /* 0x38 */
00261     { "cmpibg",      3, },  /* 0x39 */
00262     { "cmpibe",      3, },  /* 0x3a */
00263     { "cmpibge",3, },       /* 0x3b */
00264     { "cmpibl",      3, },  /* 0x3c */
00265     { "cmpibne",3, },       /* 0x3d */
00266     { "cmpible",3, },       /* 0x3e */
00267     { "cmpibo",      3, },  /* 0x3f */
00268   };
00269 
00270   i = ((word1 >> 24) & 0xff) - 0x20;
00271   if (cobr_tab[i].name == NULL)
00272     {
00273       invalid (word1);
00274       return;
00275     }
00276 
00277   (*info->fprintf_func) (stream, cobr_tab[i].name);
00278 
00279   /* Predicts branch not taken.  */
00280   if (word1 & 2)
00281     (*info->fprintf_func) (stream, ".f");
00282 
00283   (*info->fprintf_func) (stream, "\t");
00284 
00285   src1 = (word1 >> 19) & 0x1f;
00286   src2 = (word1 >> 14) & 0x1f;
00287 
00288   if (word1 & 0x02000)
00289     /* M1 is 1 */
00290     (*info->fprintf_func) (stream, "%d", src1);
00291   else
00292     (*info->fprintf_func) (stream, reg_names[src1]);
00293 
00294   if (cobr_tab[i].numops > 1)
00295     {
00296       if (word1 & 1)
00297        /* S2 is 1.  */
00298        (*info->fprintf_func) (stream, ",sf%d,", src2);
00299       else
00300        /* S1 is 0.  */
00301        (*info->fprintf_func) (stream, ",%s,", reg_names[src2]);
00302 
00303       /* Extract displacement and convert to address.  */
00304       word1 &= 0x00001ffc;
00305       if (word1 & 0x00001000)
00306        /* Negative displacement.  */
00307        word1 |= (-1 & ~0x1fff);    /* Sign extend.  */
00308 
00309       print_addr (memaddr + word1);
00310     }
00311 }
00312 
00313 /* MEM format.  */
00314 /* Returns instruction length: 4 or 8.  */
00315 
00316 static int
00317 mem (bfd_vma memaddr, unsigned long word1, unsigned long word2, int noprint)
00318 {
00319   int i, j;
00320   int len;
00321   int mode;
00322   int offset;
00323   const char *reg1, *reg2, *reg3;
00324 
00325   /* This lookup table is too sparse to make it worth typing in, but not
00326      so large as to make a sparse array necessary.  We create the table
00327      at runtime.  */
00328 
00329   /* NOTE: In this table, the meaning of 'numops' is:
00330       1: single operand
00331       2: 2 operands, load instruction
00332      -2: 2 operands, store instruction.  */
00333   static struct tabent *mem_tab;
00334   /* Opcodes of 0x8X, 9X, aX, bX, and cX must be in the table.  */
00335 #define MEM_MIN      0x80
00336 #define MEM_MAX      0xcf
00337 #define MEM_SIZ      ( * sizeof(struct tabent))
00338 
00339   static const struct sparse_tabent mem_init[] = {
00340     { 0x80,   "ldob",        2 },
00341     { 0x82,   "stob",       -2 },
00342     { 0x84,   "bx",   1 },
00343     { 0x85,   "balx",        2 },
00344     { 0x86,   "callx", 1 },
00345     { 0x88,   "ldos",        2 },
00346     { 0x8a,   "stos",       -2 },
00347     { 0x8c,   "lda",  2 },
00348     { 0x90,   "ld",   2 },
00349     { 0x92,   "st",  -2 },
00350     { 0x98,   "ldl",  2 },
00351     { 0x9a,   "stl", -2 },
00352     { 0xa0,   "ldt",  2 },
00353     { 0xa2,   "stt", -2 },
00354     { 0xac,   "dcinva", 1 },
00355     { 0xb0,   "ldq",  2 },
00356     { 0xb2,   "stq", -2 },
00357     { 0xc0,   "ldib",        2 },
00358     { 0xc2,   "stib",       -2 },
00359     { 0xc8,   "ldis",        2 },
00360     { 0xca,   "stis",       -2 },
00361     { 0,      NULL,  0 }
00362   };
00363   static struct tabent mem_tab_buf[MEM_MAX - MEM_MIN + 1];
00364 
00365   if (mem_tab == NULL)
00366     {
00367       mem_tab = mem_tab_buf;
00368 
00369       for (i = 0; mem_init[i].opcode != 0; i++)
00370        {
00371          j = mem_init[i].opcode - MEM_MIN;
00372          mem_tab[j].name = mem_init[i].name;
00373          mem_tab[j].numops = mem_init[i].numops;
00374        }
00375     }
00376 
00377   i = ((word1 >> 24) & 0xff) - MEM_MIN;
00378   mode = (word1 >> 10) & 0xf;
00379 
00380   if ((mem_tab[i].name != NULL)           /* Valid instruction */
00381       && ((mode == 5) || (mode >= 12)))
00382     /* With 32-bit displacement.  */
00383     len = 8;
00384   else
00385     len = 4;
00386 
00387   if (noprint)
00388     return len;
00389 
00390   if ((mem_tab[i].name == NULL) || (mode == 6))
00391     {
00392       invalid (word1);
00393       return len;
00394     }
00395 
00396   (*info->fprintf_func) (stream, "%s\t", mem_tab[i].name);
00397 
00398   reg1 = reg_names[ (word1 >> 19) & 0x1f ];      /* MEMB only */
00399   reg2 = reg_names[ (word1 >> 14) & 0x1f ];
00400   reg3 = reg_names[ word1 & 0x1f ];              /* MEMB only */
00401   offset = word1 & 0xfff;                        /* MEMA only  */
00402 
00403   switch (mem_tab[i].numops)
00404     {
00405     case 2: /* LOAD INSTRUCTION */
00406       if (mode & 4)
00407        {                    /* MEMB FORMAT */
00408          ea (memaddr, mode, reg2, reg3, word1, word2);
00409          (*info->fprintf_func) (stream, ",%s", reg1);
00410        }
00411       else
00412        {                           /* MEMA FORMAT */
00413          (*info->fprintf_func) (stream, "0x%x", (unsigned) offset);
00414 
00415          if (mode & 8)
00416            (*info->fprintf_func) (stream, "(%s)", reg2);
00417 
00418          (*info->fprintf_func)(stream, ",%s", reg1);
00419        }
00420       break;
00421 
00422     case -2: /* STORE INSTRUCTION */
00423       if (mode & 4)
00424        {
00425          /* MEMB FORMAT */
00426          (*info->fprintf_func) (stream, "%s,", reg1);
00427          ea (memaddr, mode, reg2, reg3, word1, word2);
00428        }
00429       else
00430        {
00431          /* MEMA FORMAT */
00432          (*info->fprintf_func) (stream, "%s,0x%x", reg1, (unsigned) offset);
00433 
00434          if (mode & 8)
00435            (*info->fprintf_func) (stream, "(%s)", reg2);
00436        }
00437       break;
00438 
00439     case 1: /* BX/CALLX INSTRUCTION */
00440       if (mode & 4)
00441        {
00442          /* MEMB FORMAT */
00443          ea (memaddr, mode, reg2, reg3, word1, word2);
00444        }
00445       else
00446        {
00447          /* MEMA FORMAT */
00448          (*info->fprintf_func) (stream, "0x%x", (unsigned) offset);
00449          if (mode & 8)
00450            (*info->fprintf_func) (stream, "(%s)", reg2);
00451        }
00452       break;
00453     }
00454 
00455   return len;
00456 }
00457 
00458 /* REG format.  */
00459 
00460 static void
00461 reg (unsigned long word1)
00462 {
00463   int i, j;
00464   int opcode;
00465   int fp;
00466   int m1, m2, m3;
00467   int s1, s2;
00468   int src, src2, dst;
00469   char *mnemp;
00470 
00471   /* This lookup table is too sparse to make it worth typing in, but not
00472      so large as to make a sparse array necessary.  We create the table
00473      at runtime.  */
00474 
00475   /* NOTE: In this table, the meaning of 'numops' is:
00476         1: single operand, which is NOT a destination.
00477        -1: single operand, which IS a destination.
00478         2: 2 operands, the 2nd of which is NOT a destination.
00479        -2: 2 operands, the 2nd of which IS a destination.
00480         3: 3 operands
00481 
00482        If an opcode mnemonic begins with "F", it is a floating-point
00483        opcode (the "F" is not printed).  */
00484 
00485   static struct tabent *reg_tab;
00486   static const struct sparse_tabent reg_init[] =
00487   {
00488 #define REG_MIN      0x580
00489     { 0x580,  "notbit",     3 },
00490     { 0x581,  "and",        3 },
00491     { 0x582,  "andnot",     3 },
00492     { 0x583,  "setbit",     3 },
00493     { 0x584,  "notand",     3 },
00494     { 0x586,  "xor",        3 },
00495     { 0x587,  "or",         3 },
00496     { 0x588,  "nor",        3 },
00497     { 0x589,  "xnor",              3 },
00498     { 0x58a,  "not",        -2 },
00499     { 0x58b,  "ornot",      3 },
00500     { 0x58c,  "clrbit",     3 },
00501     { 0x58d,  "notor",      3 },
00502     { 0x58e,  "nand",              3 },
00503     { 0x58f,  "alterbit",   3 },
00504     { 0x590,  "addo",              3 },
00505     { 0x591,  "addi",              3 },
00506     { 0x592,  "subo",              3 },
00507     { 0x593,  "subi",              3 },
00508     { 0x594,  "cmpob",      2 },
00509     { 0x595,  "cmpib",      2 },
00510     { 0x596,  "cmpos",      2 },
00511     { 0x597,  "cmpis",      2 },
00512     { 0x598,  "shro",              3 },
00513     { 0x59a,  "shrdi",      3 },
00514     { 0x59b,  "shri",              3 },
00515     { 0x59c,  "shlo",              3 },
00516     { 0x59d,  "rotate",     3 },
00517     { 0x59e,  "shli",              3 },
00518     { 0x5a0,  "cmpo",              2 },
00519     { 0x5a1,  "cmpi",              2 },
00520     { 0x5a2,  "concmpo",    2 },
00521     { 0x5a3,  "concmpi",    2 },
00522     { 0x5a4,  "cmpinco",    3 },
00523     { 0x5a5,  "cmpinci",    3 },
00524     { 0x5a6,  "cmpdeco",    3 },
00525     { 0x5a7,  "cmpdeci",    3 },
00526     { 0x5ac,  "scanbyte",   2 },
00527     { 0x5ad,  "bswap",      -2 },
00528     { 0x5ae,  "chkbit",     2 },
00529     { 0x5b0,  "addc",              3 },
00530     { 0x5b2,  "subc",              3 },
00531     { 0x5b4,  "intdis",     0 },
00532     { 0x5b5,  "inten",      0 },
00533     { 0x5cc,  "mov",        -2 },
00534     { 0x5d8,  "eshro",      3 },
00535     { 0x5dc,  "movl",              -2 },
00536     { 0x5ec,  "movt",              -2 },
00537     { 0x5fc,  "movq",              -2 },
00538     { 0x600,  "synmov",     2 },
00539     { 0x601,  "synmovl",    2 },
00540     { 0x602,  "synmovq",    2 },
00541     { 0x603,  "cmpstr",     3 },
00542     { 0x604,  "movqstr",    3 },
00543     { 0x605,  "movstr",     3 },
00544     { 0x610,  "atmod",      3 },
00545     { 0x612,  "atadd",      3 },
00546     { 0x613,  "inspacc",    -2 },
00547     { 0x614,  "ldphy",      -2 },
00548     { 0x615,  "synld",      -2 },
00549     { 0x617,  "fill",              3 },
00550     { 0x630,  "sdma",              3 },
00551     { 0x631,  "udma",              0 },
00552     { 0x640,  "spanbit",    -2 },
00553     { 0x641,  "scanbit",    -2 },
00554     { 0x642,  "daddc",      3 },
00555     { 0x643,  "dsubc",      3 },
00556     { 0x644,  "dmovt",      -2 },
00557     { 0x645,  "modac",      3 },
00558     { 0x646,  "condrec",    -2 },
00559     { 0x650,  "modify",     3 },
00560     { 0x651,  "extract",    3 },
00561     { 0x654,  "modtc",      3 },
00562     { 0x655,  "modpc",      3 },
00563     { 0x656,  "receive",    -2 },
00564     { 0x658,  "intctl",     -2 },
00565     { 0x659,  "sysctl",     3 },
00566     { 0x65b,  "icctl",      3 },
00567     { 0x65c,  "dcctl",      3 },
00568     { 0x65d,  "halt",              0 },
00569     { 0x660,  "calls",      1 },
00570     { 0x662,  "send",              3 },
00571     { 0x663,  "sendserv",   1 },
00572     { 0x664,  "resumprcs",  1 },
00573     { 0x665,  "schedprcs",  1 },
00574     { 0x666,  "saveprcs",   0 },
00575     { 0x668,  "condwait",   1 },
00576     { 0x669,  "wait",              1 },
00577     { 0x66a,  "signal",     1 },
00578     { 0x66b,  "mark",              0 },
00579     { 0x66c,  "fmark",      0 },
00580     { 0x66d,  "flushreg",   0 },
00581     { 0x66f,  "syncf",      0 },
00582     { 0x670,  "emul",              3 },
00583     { 0x671,  "ediv",              3 },
00584     { 0x673,  "ldtime",     -1 },
00585     { 0x674,  "Fcvtir",     -2 },
00586     { 0x675,  "Fcvtilr",    -2 },
00587     { 0x676,  "Fscalerl",   3 },
00588     { 0x677,  "Fscaler",    3 },
00589     { 0x680,  "Fatanr",     3 },
00590     { 0x681,  "Flogepr",    3 },
00591     { 0x682,  "Flogr",      3 },
00592     { 0x683,  "Fremr",      3 },
00593     { 0x684,  "Fcmpor",     2 },
00594     { 0x685,  "Fcmpr",      2 },
00595     { 0x688,  "Fsqrtr",     -2 },
00596     { 0x689,  "Fexpr",      -2 },
00597     { 0x68a,  "Flogbnr",    -2 },
00598     { 0x68b,  "Froundr",    -2 },
00599     { 0x68c,  "Fsinr",      -2 },
00600     { 0x68d,  "Fcosr",      -2 },
00601     { 0x68e,  "Ftanr",      -2 },
00602     { 0x68f,  "Fclassr",    1 },
00603     { 0x690,  "Fatanrl",    3 },
00604     { 0x691,  "Flogeprl",   3 },
00605     { 0x692,  "Flogrl",     3 },
00606     { 0x693,  "Fremrl",     3 },
00607     { 0x694,  "Fcmporl",    2 },
00608     { 0x695,  "Fcmprl",     2 },
00609     { 0x698,  "Fsqrtrl",    -2 },
00610     { 0x699,  "Fexprl",     -2 },
00611     { 0x69a,  "Flogbnrl",   -2 },
00612     { 0x69b,  "Froundrl",   -2 },
00613     { 0x69c,  "Fsinrl",     -2 },
00614     { 0x69d,  "Fcosrl",     -2 },
00615     { 0x69e,  "Ftanrl",     -2 },
00616     { 0x69f,  "Fclassrl",   1 },
00617     { 0x6c0,  "Fcvtri",     -2 },
00618     { 0x6c1,  "Fcvtril",    -2 },
00619     { 0x6c2,  "Fcvtzri",    -2 },
00620     { 0x6c3,  "Fcvtzril",   -2 },
00621     { 0x6c9,  "Fmovr",      -2 },
00622     { 0x6d9,  "Fmovrl",     -2 },
00623     { 0x6e1,  "Fmovre",     -2 },
00624     { 0x6e2,  "Fcpysre",    3 },
00625     { 0x6e3,  "Fcpyrsre",   3 },
00626     { 0x701,  "mulo",              3 },
00627     { 0x708,  "remo",              3 },
00628     { 0x70b,  "divo",              3 },
00629     { 0x741,  "muli",              3 },
00630     { 0x748,  "remi",              3 },
00631     { 0x749,  "modi",              3 },
00632     { 0x74b,  "divi",              3 },
00633     { 0x780,  "addono",     3 },
00634     { 0x781,  "addino",     3 },
00635     { 0x782,  "subono",     3 },
00636     { 0x783,  "subino",     3 },
00637     { 0x784,  "selno",      3 },
00638     { 0x78b,  "Fdivr",      3 },
00639     { 0x78c,  "Fmulr",      3 },
00640     { 0x78d,  "Fsubr",      3 },
00641     { 0x78f,  "Faddr",      3 },
00642     { 0x790,  "addog",      3 },
00643     { 0x791,  "addig",        3 },
00644     { 0x792,  "subog",      3 },
00645     { 0x793,  "subig",      3 },
00646     { 0x794,  "selg",              3 },
00647     { 0x79b,  "Fdivrl",     3 },
00648     { 0x79c,  "Fmulrl",     3 },
00649     { 0x79d,  "Fsubrl",     3 },
00650     { 0x79f,  "Faddrl",     3 },
00651     { 0x7a0,  "addoe",      3 },
00652     { 0x7a1,  "addie",        3 },
00653     { 0x7a2,  "suboe",      3 },
00654     { 0x7a3,  "subie",      3 },
00655     { 0x7a4,  "sele",              3 },
00656     { 0x7b0,  "addoge",     3 },
00657     { 0x7b1,  "addige",     3 },
00658     { 0x7b2,  "suboge",     3 },
00659     { 0x7b3,  "subige",     3 },
00660     { 0x7b4,  "selge",      3 },
00661     { 0x7c0,  "addol",      3 },
00662     { 0x7c1,  "addil",      3 },
00663     { 0x7c2,  "subol",      3 },
00664     { 0x7c3,  "subil",      3 },
00665     { 0x7c4,  "sell",              3 },
00666     { 0x7d0,  "addone",     3 },
00667     { 0x7d1,  "addine",     3 },
00668     { 0x7d2,  "subone",     3 },
00669     { 0x7d3,  "subine",     3 },
00670     { 0x7d4,  "selne",      3 },
00671     { 0x7e0,  "addole",     3 },
00672     { 0x7e1,  "addile",     3 },
00673     { 0x7e2,  "subole",     3 },
00674     { 0x7e3,  "subile",     3 },
00675     { 0x7e4,  "selle",      3 },
00676     { 0x7f0,  "addoo",      3 },
00677     { 0x7f1,  "addio",      3 },
00678     { 0x7f2,  "suboo",      3 },
00679     { 0x7f3,  "subio",      3 },
00680     { 0x7f4,  "selo",              3 },
00681 #define REG_MAX 0x7f4
00682     { 0,      NULL,         0 }
00683   };
00684   static struct tabent reg_tab_buf[REG_MAX - REG_MIN + 1];
00685 
00686   if (reg_tab == NULL)
00687     {
00688       reg_tab = reg_tab_buf;
00689 
00690       for (i = 0; reg_init[i].opcode != 0; i++)
00691        {
00692          j = reg_init[i].opcode - REG_MIN;
00693          reg_tab[j].name = reg_init[i].name;
00694          reg_tab[j].numops = reg_init[i].numops;
00695        }
00696     }
00697 
00698   opcode = ((word1 >> 20) & 0xff0) | ((word1 >> 7) & 0xf);
00699   i = opcode - REG_MIN;
00700 
00701   if ((opcode<REG_MIN) || (opcode>REG_MAX) || (reg_tab[i].name==NULL))
00702     {
00703       invalid (word1);
00704       return;
00705     }
00706 
00707   mnemp = reg_tab[i].name;
00708   if (*mnemp == 'F')
00709     {
00710       fp = 1;
00711       mnemp++;
00712     }
00713   else
00714     {
00715       fp = 0;
00716     }
00717 
00718   (*info->fprintf_func) (stream, mnemp);
00719 
00720   s1   = (word1 >> 5)  & 1;
00721   s2   = (word1 >> 6)  & 1;
00722   m1   = (word1 >> 11) & 1;
00723   m2   = (word1 >> 12) & 1;
00724   m3   = (word1 >> 13) & 1;
00725   src  =  word1        & 0x1f;
00726   src2 = (word1 >> 14) & 0x1f;
00727   dst  = (word1 >> 19) & 0x1f;
00728 
00729   if  (reg_tab[i].numops != 0)
00730     {
00731       (*info->fprintf_func) (stream, "\t");
00732 
00733     switch (reg_tab[i].numops)
00734       {
00735       case 1:
00736        regop (m1, s1, src, fp);
00737        break;
00738       case -1:
00739        dstop (m3, dst, fp);
00740        break;
00741       case 2:
00742        regop (m1, s1, src, fp);
00743        (*info->fprintf_func) (stream, ",");
00744        regop (m2, s2, src2, fp);
00745        break;
00746       case -2:
00747        regop (m1, s1, src, fp);
00748        (*info->fprintf_func) (stream, ",");
00749        dstop (m3, dst, fp);
00750        break;
00751       case 3:
00752        regop (m1, s1, src, fp);
00753        (*info->fprintf_func) (stream, ",");
00754        regop (m2, s2, src2, fp);
00755        (*info->fprintf_func) (stream, ",");
00756        dstop (m3, dst, fp);
00757        break;
00758       }
00759     }
00760 }
00761 
00762 /* Print out effective address for memb instructions.  */
00763 
00764 static void
00765 ea (bfd_vma memaddr, int mode, const char *reg2, const char *reg3, int word1,
00766     unsigned int word2)
00767 {
00768   int scale;
00769   static const int scale_tab[] = { 1, 2, 4, 8, 16 };
00770 
00771   scale = (word1 >> 7) & 0x07;
00772 
00773   if ((scale > 4) || (((word1 >> 5) & 0x03) != 0))
00774     {
00775       invalid (word1);
00776       return;
00777     }
00778   scale = scale_tab[scale];
00779 
00780   switch (mode)
00781     {
00782     case 4:                                      /* (reg) */
00783       (*info->fprintf_func)( stream, "(%s)", reg2 );
00784       break;
00785     case 5:                                      /* displ+8(ip) */
00786       print_addr (word2 + 8 + memaddr);
00787       break;
00788     case 7:                                      /* (reg)[index*scale] */
00789       if (scale == 1)
00790        (*info->fprintf_func) (stream, "(%s)[%s]", reg2, reg3);
00791       else
00792        (*info->fprintf_func) (stream, "(%s)[%s*%d]", reg2, reg3, scale);
00793       break;
00794     case 12:                              /* displacement */
00795       print_addr ((bfd_vma) word2);
00796       break;
00797     case 13:                              /* displ(reg) */
00798       print_addr ((bfd_vma) word2);
00799       (*info->fprintf_func) (stream, "(%s)", reg2);
00800       break;
00801     case 14:                              /* displ[index*scale] */
00802       print_addr ((bfd_vma) word2);
00803       if (scale == 1)
00804        (*info->fprintf_func) (stream, "[%s]", reg3);
00805       else
00806        (*info->fprintf_func) (stream, "[%s*%d]", reg3, scale);
00807       break;
00808     case 15:                       /* displ(reg)[index*scale] */
00809       print_addr ((bfd_vma) word2);
00810       if (scale == 1)
00811        (*info->fprintf_func) (stream, "(%s)[%s]", reg2, reg3);
00812       else
00813        (*info->fprintf_func) (stream, "(%s)[%s*%d]", reg2, reg3, scale);
00814       break;
00815     default:
00816       invalid (word1);
00817       return;
00818     }
00819 }
00820 
00821 
00822 /* Register Instruction Operand.  */
00823 
00824 static void
00825 regop (int mode, int spec, int reg, int fp)
00826 {
00827   if (fp)
00828     {
00829       /* Floating point instruction.  */
00830       if (mode == 1)
00831        {
00832          /* FP operand.  */
00833          switch (reg)
00834            {
00835            case 0:  (*info->fprintf_func) (stream, "fp0");
00836              break;
00837            case 1:  (*info->fprintf_func) (stream, "fp1");
00838              break;
00839            case 2:  (*info->fprintf_func) (stream, "fp2");
00840              break;
00841            case 3:  (*info->fprintf_func) (stream, "fp3");
00842              break;
00843            case 16: (*info->fprintf_func) (stream, "0f0.0");
00844              break;
00845            case 22: (*info->fprintf_func) (stream, "0f1.0");
00846              break;
00847            default: (*info->fprintf_func) (stream, "?");
00848              break;
00849            }
00850        }
00851       else
00852        {
00853          /* Non-FP register.  */
00854          (*info->fprintf_func) (stream, reg_names[reg]);
00855        }
00856     }
00857   else
00858     {
00859       /* Not floating point.  */
00860       if (mode == 1)
00861        {
00862          /* Literal.  */
00863          (*info->fprintf_func) (stream, "%d", reg);
00864        }
00865       else
00866        {
00867          /* Register.  */
00868          if (spec == 0)
00869            (*info->fprintf_func) (stream, reg_names[reg]);
00870          else
00871            (*info->fprintf_func) (stream, "sf%d", reg);
00872        }
00873     }
00874 }
00875 
00876 /* Register Instruction Destination Operand.  */
00877 
00878 static void
00879 dstop (int mode, int reg, int fp)
00880 {
00881   /* 'dst' operand can't be a literal. On non-FP instructions,  register
00882      mode is assumed and "m3" acts as if were "s3";  on FP-instructions,
00883      sf registers are not allowed so m3 acts normally.  */
00884   if (fp)
00885     regop (mode, 0, reg, fp);
00886   else
00887     regop (0, mode, reg, fp);
00888 }
00889 
00890 static void
00891 invalid (int word1)
00892 {
00893   (*info->fprintf_func) (stream, ".word\t0x%08x", (unsigned) word1);
00894 }
00895 
00896 static void
00897 print_addr (bfd_vma a)
00898 {
00899   (*info->print_address_func) (a, info);
00900 }
00901 
00902 static void
00903 put_abs (unsigned long word1 ATTRIBUTE_UNUSED,
00904         unsigned long word2 ATTRIBUTE_UNUSED)
00905 {
00906 #ifdef IN_GDB
00907   return;
00908 #else
00909   int len;
00910 
00911   switch ((word1 >> 28) & 0xf)
00912     {
00913     case 0x8:
00914     case 0x9:
00915     case 0xa:
00916     case 0xb:
00917     case 0xc:
00918       /* MEM format instruction.  */
00919       len = mem (0, word1, word2, 1);
00920       break;
00921     default:
00922       len = 4;
00923       break;
00924     }
00925 
00926   if (len == 8)
00927     (*info->fprintf_func) (stream, "%08x %08x\t", word1, word2);
00928   else
00929     (*info->fprintf_func) (stream, "%08x         \t", word1);
00930 #endif
00931 }