home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / binutils-2.7-src.tgz / tar.out / fsf / binutils / opcodes / mips-dis.c < prev    next >
C/C++ Source or Header  |  1996-09-28  |  8KB  |  296 lines

  1. /* Print mips instructions for GDB, the GNU debugger, or for objdump.
  2.    Copyright 1989, 1991, 1992 Free Software Foundation, Inc.
  3.    Contributed by Nobuyuki Hikichi(hikichi@sra.co.jp).
  4.  
  5. This file is part of GDB.
  6.  
  7. This program is free software; you can redistribute it and/or modify
  8. it under the terms of the GNU General Public License as published by
  9. the Free Software Foundation; either version 2 of the License, or
  10. (at your option) any later version.
  11.  
  12. This program is distributed in the hope that it will be useful,
  13. but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15. GNU General Public License for more details.
  16.  
  17. You should have received a copy of the GNU General Public License
  18. along with this program; if not, write to the Free Software
  19. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
  20.  
  21. #include <ansidecl.h>
  22. #include "sysdep.h"
  23. #include "dis-asm.h"
  24. #include "opcode/mips.h"
  25.  
  26. /* Mips instructions are never longer than this many bytes.  */
  27. #define MAXLEN 4
  28.  
  29. /* FIXME: This should be shared with gdb somehow.  */
  30. #define REGISTER_NAMES     \
  31.     {    "zero",    "at",    "v0",    "v1",    "a0",    "a1",    "a2",    "a3", \
  32.     "t0",    "t1",    "t2",    "t3",    "t4",    "t5",    "t6",    "t7", \
  33.     "s0",    "s1",    "s2",    "s3",    "s4",    "s5",    "s6",    "s7", \
  34.     "t8",    "t9",    "k0",    "k1",    "gp",    "sp",    "s8",    "ra", \
  35.     "sr",    "lo",    "hi",    "bad",    "cause","pc",    \
  36.     "f0",   "f1",   "f2",   "f3",   "f4",   "f5",   "f6",   "f7", \
  37.     "f8",   "f9",   "f10",  "f11",  "f12",  "f13",  "f14",  "f15", \
  38.     "f16",  "f17",  "f18",  "f19",  "f20",  "f21",  "f22",  "f23",\
  39.     "f24",  "f25",  "f26",  "f27",  "f28",  "f29",  "f30",  "f31",\
  40.     "fsr",  "fir",  "fp",   "inx",  "rand", "tlblo","ctxt", "tlbhi",\
  41.     "epc",  "prid"\
  42.     }
  43.  
  44. static CONST char * CONST reg_names[] = REGISTER_NAMES;
  45.  
  46. /* subroutine */
  47. static void
  48. print_insn_arg (d, l, pc, info)
  49.      const char *d;
  50.      register unsigned long int l;
  51.      bfd_vma pc;
  52.      struct disassemble_info *info;
  53. {
  54.   int delta;
  55.  
  56.   switch (*d)
  57.     {
  58.     case ',':
  59.     case '(':
  60.     case ')':
  61.       (*info->fprintf_func) (info->stream, "%c", *d);
  62.       break;
  63.  
  64.     case 's':
  65.     case 'b':
  66.     case 'r':
  67.     case 'v':
  68.       (*info->fprintf_func) (info->stream, "$%s",
  69.                  reg_names[(l >> OP_SH_RS) & OP_MASK_RS]);
  70.       break;
  71.  
  72.     case 't':
  73.     case 'w':
  74.       (*info->fprintf_func) (info->stream, "$%s",
  75.                  reg_names[(l >> OP_SH_RT) & OP_MASK_RT]);
  76.       break;
  77.  
  78.     case 'i':
  79.     case 'u':
  80.       (*info->fprintf_func) (info->stream, "0x%x",
  81.             (l >> OP_SH_IMMEDIATE) & OP_MASK_IMMEDIATE);
  82.       break;
  83.  
  84.     case 'j': /* same as i, but sign-extended */
  85.     case 'o':
  86.       delta = (l >> OP_SH_DELTA) & OP_MASK_DELTA;
  87.       if (delta & 0x8000)
  88.     delta |= ~0xffff;
  89.       (*info->fprintf_func) (info->stream, "%d",
  90.                  delta);
  91.       break;
  92.  
  93.     case 'h':
  94.       (*info->fprintf_func) (info->stream, "0x%x",
  95.                  (unsigned int) ((l >> OP_SH_PREFX)
  96.                          & OP_MASK_PREFX));
  97.       break;
  98.  
  99.     case 'k':
  100.       (*info->fprintf_func) (info->stream, "0x%x",
  101.                  (unsigned int) ((l >> OP_SH_CACHE)
  102.                          & OP_MASK_CACHE));
  103.       break;
  104.  
  105.     case 'a':
  106.       (*info->print_address_func)
  107.     (((pc & 0xF0000000) | (((l >> OP_SH_TARGET) & OP_MASK_TARGET) << 2)),
  108.      info);
  109.       break;
  110.  
  111.     case 'p':
  112.       /* sign extend the displacement */
  113.       delta = (l >> OP_SH_DELTA) & OP_MASK_DELTA;
  114.       if (delta & 0x8000)
  115.     delta |= ~0xffff;
  116.       (*info->print_address_func)
  117.     ((delta << 2) + pc + 4,
  118.      info);
  119.       break;
  120.  
  121.     case 'd':
  122.       (*info->fprintf_func) (info->stream, "$%s",
  123.                  reg_names[(l >> OP_SH_RD) & OP_MASK_RD]);
  124.       break;
  125.  
  126.     case 'z':
  127.       (*info->fprintf_func) (info->stream, "$%s", reg_names[0]);
  128.       break;
  129.  
  130.     case '<':
  131.       (*info->fprintf_func) (info->stream, "0x%x",
  132.                  (l >> OP_SH_SHAMT) & OP_MASK_SHAMT);
  133.       break;
  134.  
  135.     case 'c':
  136.       (*info->fprintf_func) (info->stream, "0x%x",
  137.                  (l >> OP_SH_CODE) & OP_MASK_CODE);
  138.       break;
  139.  
  140.     case 'C':
  141.       (*info->fprintf_func) (info->stream, "0x%x",
  142.                  (l >> OP_SH_COPZ) & OP_MASK_COPZ);
  143.       break;
  144.  
  145.     case 'B':
  146.       (*info->fprintf_func) (info->stream, "0x%x",
  147.                  (l >> OP_SH_SYSCALL) & OP_MASK_SYSCALL);
  148.       break;
  149.  
  150.     case 'S':
  151.     case 'V':
  152.       (*info->fprintf_func) (info->stream, "$f%d",
  153.                  (l >> OP_SH_FS) & OP_MASK_FS);
  154.       break;
  155.  
  156.     case 'T':
  157.     case 'W':
  158.       (*info->fprintf_func) (info->stream, "$f%d",
  159.                  (l >> OP_SH_FT) & OP_MASK_FT);
  160.       break;
  161.  
  162.     case 'D':
  163.       (*info->fprintf_func) (info->stream, "$f%d",
  164.                  (l >> OP_SH_FD) & OP_MASK_FD);
  165.       break;
  166.  
  167.     case 'R':
  168.       (*info->fprintf_func) (info->stream, "$f%d",
  169.                  (l >> OP_SH_FR) & OP_MASK_FR);
  170.       break;
  171.  
  172.     case 'E':
  173.       (*info->fprintf_func) (info->stream, "$%d",
  174.                  (l >> OP_SH_RT) & OP_MASK_RT);
  175.       break;
  176.  
  177.     case 'G':
  178.       (*info->fprintf_func) (info->stream, "$%d",
  179.                  (l >> OP_SH_RD) & OP_MASK_RD);
  180.       break;
  181.  
  182.     case 'N':
  183.       (*info->fprintf_func) (info->stream, "%d",
  184.                  (l >> OP_SH_BCC) & OP_MASK_BCC);
  185.       break;
  186.  
  187.     case 'M':
  188.       (*info->fprintf_func) (info->stream, "%d",
  189.                  (l >> OP_SH_CCC) & OP_MASK_CCC);
  190.       break;
  191.  
  192.     default:
  193.       (*info->fprintf_func) (info->stream,
  194.                  "# internal error, undefined modifier(%c)", *d);
  195.       break;
  196.     }
  197. }
  198.  
  199. /* Print the mips instruction at address MEMADDR in debugged memory,
  200.    on using INFO.  Returns length of the instruction, in bytes, which is
  201.    always 4.  BIGENDIAN must be 1 if this is big-endian code, 0 if
  202.    this is little-endian code.  */
  203.  
  204. static int
  205. _print_insn_mips (memaddr, word, info)
  206.      bfd_vma memaddr;
  207.      struct disassemble_info *info;
  208.      unsigned long int word;
  209. {
  210.   register const struct mips_opcode *op;
  211.   static boolean init = 0;
  212.   static const struct mips_opcode *mips_hash[OP_MASK_OP + 1];
  213.  
  214.   /* Build a hash table to shorten the search time.  */
  215.   if (! init)
  216.     {
  217.       unsigned int i;
  218.  
  219.       for (i = 0; i <= OP_MASK_OP; i++)
  220.     {
  221.       for (op = mips_opcodes; op < &mips_opcodes[NUMOPCODES]; op++)
  222.         {
  223.           if (op->pinfo == INSN_MACRO)
  224.         continue;
  225.           if (i == ((op->match >> OP_SH_OP) & OP_MASK_OP))
  226.         {
  227.           mips_hash[i] = op;
  228.           break;
  229.         }
  230.         }
  231.         }
  232.  
  233.       init = 1;
  234.     }
  235.  
  236.   op = mips_hash[(word >> OP_SH_OP) & OP_MASK_OP];
  237.   if (op != NULL)
  238.     {
  239.       for (; op < &mips_opcodes[NUMOPCODES]; op++)
  240.     {
  241.       if (op->pinfo != INSN_MACRO && (word & op->mask) == op->match)
  242.         {
  243.           register const char *d;
  244.  
  245.           (*info->fprintf_func) (info->stream, "%s", op->name);
  246.  
  247.           d = op->args;
  248.           if (d != NULL)
  249.         {
  250.           (*info->fprintf_func) (info->stream, " ");
  251.           for (; *d != '\0'; d++)
  252.             print_insn_arg (d, word, memaddr, info);
  253.         }
  254.  
  255.           return 4;
  256.         }
  257.     }
  258.     }
  259.  
  260.   /* Handle undefined instructions.  */
  261.   (*info->fprintf_func) (info->stream, "0x%x", word);
  262.   return 4;
  263. }
  264.  
  265. int
  266. print_insn_big_mips (memaddr, info)
  267.      bfd_vma memaddr;
  268.      struct disassemble_info *info;
  269. {
  270.   bfd_byte buffer[4];
  271.   int status = (*info->read_memory_func) (memaddr, buffer, 4, info);
  272.   if (status == 0)
  273.     return _print_insn_mips (memaddr, (unsigned long) bfd_getb32 (buffer), info);
  274.   else
  275.     {
  276.       (*info->memory_error_func) (status, memaddr, info);
  277.       return -1;
  278.     }
  279. }
  280.  
  281. int
  282. print_insn_little_mips (memaddr, info)
  283.      bfd_vma memaddr;
  284.      struct disassemble_info *info;
  285. {
  286.   bfd_byte buffer[4];
  287.   int status = (*info->read_memory_func) (memaddr, buffer, 4, info);
  288.   if (status == 0)
  289.     return _print_insn_mips (memaddr, (unsigned long) bfd_getl32 (buffer), info);
  290.   else
  291.     {
  292.       (*info->memory_error_func) (status, memaddr, info);
  293.       return -1;
  294.     }
  295. }
  296.