Back to index

cell-binutils  2.17cvs20070401
pdp11-dis.c
Go to the documentation of this file.
00001 /* Print DEC PDP-11 instructions.
00002    Copyright 2001, 2002, 2004, 2005 Free Software Foundation, Inc.
00003 
00004    This file is free software; you can redistribute it and/or modify
00005    it under the terms of the GNU General Public License as published by
00006    the Free Software Foundation; either version 2 of the License, or
00007    (at your option) any later version.
00008 
00009    This program is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012    GNU General Public License for more details.
00013 
00014    You should have received a copy of the GNU General Public License
00015    along with this program; if not, write to the Free Software
00016    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
00017    MA 02110-1301, USA.  */
00018 
00019 #include "sysdep.h"
00020 #include "dis-asm.h"
00021 #include "opcode/pdp11.h"
00022 
00023 #define AFTER_INSTRUCTION   "\t"
00024 #define OPERAND_SEPARATOR   ", "
00025 
00026 #define JUMP  0x1000 /* Flag that this operand is used in a jump.  */
00027 
00028 #define FPRINTF      (*info->fprintf_func)
00029 #define F     info->stream
00030 
00031 /* Sign-extend a 16-bit number in an int.  */
00032 #define SIGN_BITS    (8 * sizeof (int) - 16)
00033 #define sign_extend(x) (((x) << SIGN_BITS) >> SIGN_BITS)
00034 
00035 static int
00036 read_word (bfd_vma memaddr, int *word, disassemble_info *info)
00037 {
00038   int status;
00039   bfd_byte x[2];
00040 
00041   status = (*info->read_memory_func) (memaddr, x, 2, info);
00042   if (status != 0)
00043     return -1;
00044 
00045   *word = x[1] << 8 | x[0];
00046   return 0;
00047 }
00048 
00049 static void
00050 print_signed_octal (int n, disassemble_info *info)
00051 {
00052   if (n < 0)
00053     FPRINTF (F, "-%o", -n);
00054   else
00055     FPRINTF (F, "%o", n);
00056 }
00057 
00058 static void
00059 print_reg (int reg, disassemble_info *info)
00060 {
00061   /* Mask off the addressing mode, if any.  */
00062   reg &= 7;
00063 
00064   switch (reg)
00065     {
00066     case 0: case 1: case 2: case 3: case 4: case 5:
00067               FPRINTF (F, "r%d", reg); break;
00068     case 6:   FPRINTF (F, "sp"); break;
00069     case 7:   FPRINTF (F, "pc"); break;
00070     default: ;       /* error */
00071     }
00072 }
00073 
00074 static void
00075 print_freg (int freg, disassemble_info *info)
00076 {
00077   FPRINTF (F, "fr%d", freg);
00078 }
00079 
00080 static int
00081 print_operand (bfd_vma *memaddr, int code, disassemble_info *info)
00082 {
00083   int mode = (code >> 3) & 7;
00084   int reg = code & 7;
00085   int disp;
00086 
00087   switch (mode)
00088     {
00089     case 0:
00090       print_reg (reg, info);
00091       break;
00092     case 1:
00093       FPRINTF (F, "(");
00094       print_reg (reg, info);
00095       FPRINTF (F, ")");
00096       break;
00097     case 2:
00098       if (reg == 7)
00099        {
00100          int data;
00101 
00102          if (read_word (*memaddr, &data, info) < 0)
00103            return -1;
00104          FPRINTF (F, "$");
00105          print_signed_octal (sign_extend (data), info);
00106          *memaddr += 2;
00107        }
00108       else
00109        {
00110          FPRINTF (F, "(");
00111          print_reg (reg, info);
00112          FPRINTF (F, ")+");
00113        }
00114        break;
00115     case 3:
00116       if (reg == 7)
00117        {
00118          int address;
00119 
00120          if (read_word (*memaddr, &address, info) < 0)
00121            return -1;
00122          FPRINTF (F, "*$%o", address);
00123          *memaddr += 2;
00124        }
00125       else
00126        {
00127          FPRINTF (F, "*(");
00128          print_reg (reg, info);
00129          FPRINTF (F, ")+");
00130        }
00131        break;
00132     case 4:
00133       FPRINTF (F, "-(");
00134       print_reg (reg, info);
00135       FPRINTF (F, ")");
00136       break;
00137     case 5:
00138       FPRINTF (F, "*-(");
00139       print_reg (reg, info);
00140       FPRINTF (F, ")");
00141       break;
00142     case 6:
00143     case 7:
00144       if (read_word (*memaddr, &disp, info) < 0)
00145        return -1;
00146       *memaddr += 2;
00147       if (reg == 7)
00148        {
00149          bfd_vma address = *memaddr + sign_extend (disp);
00150 
00151          if (mode == 7)
00152            FPRINTF (F, "*");
00153          if (!(code & JUMP))
00154            FPRINTF (F, "$");
00155          (*info->print_address_func) (address, info);
00156        }
00157       else
00158        {
00159          if (mode == 7)
00160            FPRINTF (F, "*");
00161          print_signed_octal (sign_extend (disp), info);
00162          FPRINTF (F, "(");
00163          print_reg (reg, info);
00164          FPRINTF (F, ")");
00165        }
00166       break;
00167     }
00168 
00169   return 0;
00170 }
00171 
00172 static int
00173 print_foperand (bfd_vma *memaddr, int code, disassemble_info *info)
00174 {
00175   int mode = (code >> 3) & 7;
00176   int reg = code & 7;
00177 
00178   if (mode == 0)
00179     print_freg (reg, info);
00180   else
00181     return print_operand (memaddr, code, info);
00182 
00183   return 0;
00184 }
00185 
00186 /* Print the PDP-11 instruction at address MEMADDR in debugged memory,
00187    on INFO->STREAM.  Returns length of the instruction, in bytes.  */
00188 
00189 int
00190 print_insn_pdp11 (bfd_vma memaddr, disassemble_info *info)
00191 {
00192   bfd_vma start_memaddr = memaddr;
00193   int opcode;
00194   int src, dst;
00195   int i;
00196 
00197   info->bytes_per_line = 6;
00198   info->bytes_per_chunk = 2;
00199   info->display_endian = BFD_ENDIAN_LITTLE;
00200 
00201   if (read_word (memaddr, &opcode, info) != 0)
00202     return -1;
00203   memaddr += 2;
00204 
00205   src = (opcode >> 6) & 0x3f;
00206   dst = opcode & 0x3f;
00207 
00208   for (i = 0; i < pdp11_num_opcodes; i++)
00209     {
00210 #define OP pdp11_opcodes[i]
00211       if ((opcode & OP.mask) == OP.opcode)
00212        switch (OP.type)
00213          {
00214          case PDP11_OPCODE_NO_OPS:
00215            FPRINTF (F, OP.name);
00216            goto done;
00217          case PDP11_OPCODE_REG:
00218            FPRINTF (F, OP.name);
00219            FPRINTF (F, AFTER_INSTRUCTION);
00220            print_reg (dst, info);
00221            goto done;
00222          case PDP11_OPCODE_OP:
00223            FPRINTF (F, OP.name);
00224            FPRINTF (F, AFTER_INSTRUCTION);
00225            if (strcmp (OP.name, "jmp") == 0)
00226              dst |= JUMP;
00227            if (print_operand (&memaddr, dst, info) < 0)
00228              return -1;
00229            goto done;
00230          case PDP11_OPCODE_FOP:
00231            FPRINTF (F, OP.name);
00232            FPRINTF (F, AFTER_INSTRUCTION);
00233            if (strcmp (OP.name, "jmp") == 0)
00234              dst |= JUMP;
00235            if (print_foperand (&memaddr, dst, info) < 0)
00236              return -1;
00237            goto done;
00238          case PDP11_OPCODE_REG_OP:
00239            FPRINTF (F, OP.name);
00240            FPRINTF (F, AFTER_INSTRUCTION);
00241            print_reg (src, info);
00242            FPRINTF (F, OPERAND_SEPARATOR);
00243            if (strcmp (OP.name, "jsr") == 0)
00244              dst |= JUMP;
00245            if (print_operand (&memaddr, dst, info) < 0)
00246              return -1;
00247            goto done;
00248          case PDP11_OPCODE_REG_OP_REV:
00249            FPRINTF (F, OP.name);
00250            FPRINTF (F, AFTER_INSTRUCTION);
00251            if (print_operand (&memaddr, dst, info) < 0)
00252              return -1;
00253            FPRINTF (F, OPERAND_SEPARATOR);
00254            print_reg (src, info);
00255            goto done;
00256          case PDP11_OPCODE_AC_FOP:
00257            {
00258              int ac = (opcode & 0xe0) >> 6;
00259              FPRINTF (F, OP.name);
00260              FPRINTF (F, AFTER_INSTRUCTION);
00261              print_freg (ac, info);
00262              FPRINTF (F, OPERAND_SEPARATOR);
00263              if (print_foperand (&memaddr, dst, info) < 0)
00264               return -1;
00265              goto done;
00266            }
00267          case PDP11_OPCODE_FOP_AC:
00268            {
00269              int ac = (opcode & 0xe0) >> 6;
00270              FPRINTF (F, OP.name);
00271              FPRINTF (F, AFTER_INSTRUCTION);
00272              if (print_foperand (&memaddr, dst, info) < 0)
00273               return -1;
00274              FPRINTF (F, OPERAND_SEPARATOR);
00275              print_freg (ac, info);
00276              goto done;
00277            }
00278          case PDP11_OPCODE_AC_OP:
00279            {
00280              int ac = (opcode & 0xe0) >> 6;
00281              FPRINTF (F, OP.name);
00282              FPRINTF (F, AFTER_INSTRUCTION);
00283              print_freg (ac, info);
00284              FPRINTF (F, OPERAND_SEPARATOR);
00285              if (print_operand (&memaddr, dst, info) < 0)
00286               return -1;
00287              goto done;
00288            }
00289          case PDP11_OPCODE_OP_AC:
00290            {
00291              int ac = (opcode & 0xe0) >> 6;
00292              FPRINTF (F, OP.name);
00293              FPRINTF (F, AFTER_INSTRUCTION);
00294              if (print_operand (&memaddr, dst, info) < 0)
00295               return -1;
00296              FPRINTF (F, OPERAND_SEPARATOR);
00297              print_freg (ac, info);
00298              goto done;
00299            }
00300          case PDP11_OPCODE_OP_OP:
00301            FPRINTF (F, OP.name);
00302            FPRINTF (F, AFTER_INSTRUCTION);
00303            if (print_operand (&memaddr, src, info) < 0)
00304              return -1;
00305            FPRINTF (F, OPERAND_SEPARATOR);
00306            if (print_operand (&memaddr, dst, info) < 0)
00307              return -1;
00308            goto done;
00309          case PDP11_OPCODE_DISPL:
00310            {
00311              int displ = (opcode & 0xff) << 8;
00312              bfd_vma address = memaddr + (sign_extend (displ) >> 7);
00313              FPRINTF (F, OP.name);
00314              FPRINTF (F, AFTER_INSTRUCTION);
00315              (*info->print_address_func) (address, info);
00316              goto done;
00317            }
00318          case PDP11_OPCODE_REG_DISPL:
00319            {
00320              int displ = (opcode & 0x3f) << 10;
00321              bfd_vma address = memaddr - (displ >> 9);
00322 
00323              FPRINTF (F, OP.name);
00324              FPRINTF (F, AFTER_INSTRUCTION);
00325              print_reg (src, info);
00326              FPRINTF (F, OPERAND_SEPARATOR);
00327              (*info->print_address_func) (address, info);
00328              goto done;
00329            }
00330          case PDP11_OPCODE_IMM8:
00331            {
00332              int code = opcode & 0xff;
00333              FPRINTF (F, OP.name);
00334              FPRINTF (F, AFTER_INSTRUCTION);
00335              FPRINTF (F, "%o", code);
00336              goto done;
00337            }
00338          case PDP11_OPCODE_IMM6:
00339            {
00340              int code = opcode & 0x3f;
00341              FPRINTF (F, OP.name);
00342              FPRINTF (F, AFTER_INSTRUCTION);
00343              FPRINTF (F, "%o", code);
00344              goto done;
00345            }
00346          case PDP11_OPCODE_IMM3:
00347            {
00348              int code = opcode & 7;
00349              FPRINTF (F, OP.name);
00350              FPRINTF (F, AFTER_INSTRUCTION);
00351              FPRINTF (F, "%o", code);
00352              goto done;
00353            }
00354          case PDP11_OPCODE_ILLEGAL:
00355            {
00356              FPRINTF (F, ".word");
00357              FPRINTF (F, AFTER_INSTRUCTION);
00358              FPRINTF (F, "%o", opcode);
00359              goto done;
00360            }
00361          default:
00362            /* TODO: is this a proper way of signalling an error? */
00363            FPRINTF (F, "<internal error: unrecognized instruction type>");
00364            return -1;
00365          }
00366 #undef OP
00367     }
00368  done:
00369 
00370   return memaddr - start_memaddr;
00371 }