(root)/
binutils-2.41/
opcodes/
pdp11-dis.c
       1  /* Print DEC PDP-11 instructions.
       2     Copyright (C) 2001-2023 Free Software Foundation, Inc.
       3  
       4     This file is part of the GNU opcodes library.
       5  
       6     This library is free software; you can redistribute it and/or modify
       7     it under the terms of the GNU General Public License as published by
       8     the Free Software Foundation; either version 3, or (at your option)
       9     any later version.
      10  
      11     It is distributed in the hope that it will be useful, but WITHOUT
      12     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
      13     or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
      14     License for more details.
      15  
      16     You should have received a copy of the GNU General Public License
      17     along with this program; if not, write to the Free Software
      18     Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
      19     MA 02110-1301, USA.  */
      20  
      21  #include "sysdep.h"
      22  #include "disassemble.h"
      23  #include "opcode/pdp11.h"
      24  
      25  #define AFTER_INSTRUCTION	"\t"
      26  #define OPERAND_SEPARATOR	", "
      27  
      28  #define JUMP	0x1000	/* Flag that this operand is used in a jump.  */
      29  
      30  #define FPRINTF	(*info->fprintf_func)
      31  #define F	info->stream
      32  
      33  /* Sign-extend a 16-bit number in an int.  */
      34  #define sign_extend(x) ((((x) & 0xffff) ^ 0x8000) - 0x8000)
      35  
      36  static int
      37  read_word (bfd_vma memaddr, int *word, disassemble_info *info)
      38  {
      39    int status;
      40    bfd_byte x[2];
      41  
      42    status = (*info->read_memory_func) (memaddr, x, 2, info);
      43    if (status != 0)
      44      return -1;
      45  
      46    *word = x[1] << 8 | x[0];
      47    return 0;
      48  }
      49  
      50  static void
      51  print_signed_octal (int n, disassemble_info *info)
      52  {
      53    if (n < 0)
      54      FPRINTF (F, "-%o", -n);
      55    else
      56      FPRINTF (F, "%o", n);
      57  }
      58  
      59  static void
      60  print_reg (int reg, disassemble_info *info)
      61  {
      62    /* Mask off the addressing mode, if any.  */
      63    reg &= 7;
      64  
      65    switch (reg)
      66      {
      67      case 0: case 1: case 2: case 3: case 4: case 5:
      68  		FPRINTF (F, "r%d", reg); break;
      69      case 6:	FPRINTF (F, "sp"); break;
      70      case 7:	FPRINTF (F, "pc"); break;
      71      default: ;	/* error */
      72      }
      73  }
      74  
      75  static void
      76  print_freg (int freg, disassemble_info *info)
      77  {
      78    FPRINTF (F, "fr%d", freg);
      79  }
      80  
      81  static int
      82  print_operand (bfd_vma *memaddr, int code, disassemble_info *info)
      83  {
      84    int mode = (code >> 3) & 7;
      85    int reg = code & 7;
      86    int disp;
      87  
      88    switch (mode)
      89      {
      90      case 0:
      91        print_reg (reg, info);
      92        break;
      93      case 1:
      94        FPRINTF (F, "(");
      95        print_reg (reg, info);
      96        FPRINTF (F, ")");
      97        break;
      98      case 2:
      99        if (reg == 7)
     100  	{
     101  	  int data;
     102  
     103  	  if (read_word (*memaddr, &data, info) < 0)
     104  	    return -1;
     105  	  FPRINTF (F, "$");
     106  	  print_signed_octal (sign_extend (data), info);
     107  	  *memaddr += 2;
     108  	}
     109        else
     110  	{
     111  	  FPRINTF (F, "(");
     112  	  print_reg (reg, info);
     113  	  FPRINTF (F, ")+");
     114  	}
     115  	break;
     116      case 3:
     117        if (reg == 7)
     118  	{
     119  	  int address;
     120  
     121  	  if (read_word (*memaddr, &address, info) < 0)
     122  	    return -1;
     123  	  FPRINTF (F, "*$%o", address);
     124  	  *memaddr += 2;
     125  	}
     126        else
     127  	{
     128  	  FPRINTF (F, "*(");
     129  	  print_reg (reg, info);
     130  	  FPRINTF (F, ")+");
     131  	}
     132  	break;
     133      case 4:
     134        FPRINTF (F, "-(");
     135        print_reg (reg, info);
     136        FPRINTF (F, ")");
     137        break;
     138      case 5:
     139        FPRINTF (F, "*-(");
     140        print_reg (reg, info);
     141        FPRINTF (F, ")");
     142        break;
     143      case 6:
     144      case 7:
     145        if (read_word (*memaddr, &disp, info) < 0)
     146  	return -1;
     147        *memaddr += 2;
     148        if (reg == 7)
     149  	{
     150  	  bfd_vma address = *memaddr + sign_extend (disp);
     151  
     152  	  if (mode == 7)
     153  	    FPRINTF (F, "*");
     154  	  if (!(code & JUMP))
     155  	    FPRINTF (F, "$");
     156  	  (*info->print_address_func) (address, info);
     157  	}
     158        else
     159  	{
     160  	  if (mode == 7)
     161  	    FPRINTF (F, "*");
     162  	  print_signed_octal (sign_extend (disp), info);
     163  	  FPRINTF (F, "(");
     164  	  print_reg (reg, info);
     165  	  FPRINTF (F, ")");
     166  	}
     167        break;
     168      }
     169  
     170    return 0;
     171  }
     172  
     173  static int
     174  print_foperand (bfd_vma *memaddr, int code, disassemble_info *info)
     175  {
     176    int mode = (code >> 3) & 7;
     177    int reg = code & 7;
     178  
     179    if (mode == 0)
     180      print_freg (reg, info);
     181    else
     182      return print_operand (memaddr, code, info);
     183  
     184    return 0;
     185  }
     186  
     187  /* Print the PDP-11 instruction at address MEMADDR in debugged memory,
     188     on INFO->STREAM.  Returns length of the instruction, in bytes.  */
     189  
     190  int
     191  print_insn_pdp11 (bfd_vma memaddr, disassemble_info *info)
     192  {
     193    bfd_vma start_memaddr = memaddr;
     194    int opcode;
     195    int src, dst;
     196    int i;
     197  
     198    info->bytes_per_line = 6;
     199    info->bytes_per_chunk = 2;
     200    info->display_endian = BFD_ENDIAN_LITTLE;
     201  
     202    if (read_word (memaddr, &opcode, info) != 0)
     203      return -1;
     204    memaddr += 2;
     205  
     206    src = (opcode >> 6) & 0x3f;
     207    dst = opcode & 0x3f;
     208  
     209    for (i = 0; i < pdp11_num_opcodes; i++)
     210      {
     211  #define OP pdp11_opcodes[i]
     212        if ((opcode & OP.mask) == OP.opcode)
     213  	switch (OP.type)
     214  	  {
     215  	  case PDP11_OPCODE_NO_OPS:
     216  	    FPRINTF (F, "%s", OP.name);
     217  	    goto done;
     218  	  case PDP11_OPCODE_REG:
     219  	    FPRINTF (F, "%s", OP.name);
     220  	    FPRINTF (F, AFTER_INSTRUCTION);
     221  	    print_reg (dst, info);
     222  	    goto done;
     223  	  case PDP11_OPCODE_OP:
     224  	    FPRINTF (F, "%s", OP.name);
     225  	    FPRINTF (F, AFTER_INSTRUCTION);
     226  	    if (strcmp (OP.name, "jmp") == 0)
     227  	      dst |= JUMP;
     228  	    if (print_operand (&memaddr, dst, info) < 0)
     229  	      return -1;
     230  	    goto done;
     231  	  case PDP11_OPCODE_FOP:
     232  	    FPRINTF (F, "%s", OP.name);
     233  	    FPRINTF (F, AFTER_INSTRUCTION);
     234  	    if (strcmp (OP.name, "jmp") == 0)
     235  	      dst |= JUMP;
     236  	    if (print_foperand (&memaddr, dst, info) < 0)
     237  	      return -1;
     238  	    goto done;
     239  	  case PDP11_OPCODE_REG_OP:
     240  	    FPRINTF (F, "%s", OP.name);
     241  	    FPRINTF (F, AFTER_INSTRUCTION);
     242  	    print_reg (src, info);
     243  	    FPRINTF (F, OPERAND_SEPARATOR);
     244  	    if (strcmp (OP.name, "jsr") == 0)
     245  	      dst |= JUMP;
     246  	    if (print_operand (&memaddr, dst, info) < 0)
     247  	      return -1;
     248  	    goto done;
     249  	  case PDP11_OPCODE_REG_OP_REV:
     250  	    FPRINTF (F, "%s", OP.name);
     251  	    FPRINTF (F, AFTER_INSTRUCTION);
     252  	    if (print_operand (&memaddr, dst, info) < 0)
     253  	      return -1;
     254  	    FPRINTF (F, OPERAND_SEPARATOR);
     255  	    print_reg (src, info);
     256  	    goto done;
     257  	  case PDP11_OPCODE_AC_FOP:
     258  	    {
     259  	      int ac = (opcode & 0xe0) >> 6;
     260  	      FPRINTF (F, "%s", OP.name);
     261  	      FPRINTF (F, AFTER_INSTRUCTION);
     262  	      print_freg (ac, info);
     263  	      FPRINTF (F, OPERAND_SEPARATOR);
     264  	      if (print_foperand (&memaddr, dst, info) < 0)
     265  		return -1;
     266  	      goto done;
     267  	    }
     268  	  case PDP11_OPCODE_FOP_AC:
     269  	    {
     270  	      int ac = (opcode & 0xe0) >> 6;
     271  	      FPRINTF (F, "%s", OP.name);
     272  	      FPRINTF (F, AFTER_INSTRUCTION);
     273  	      if (print_foperand (&memaddr, dst, info) < 0)
     274  		return -1;
     275  	      FPRINTF (F, OPERAND_SEPARATOR);
     276  	      print_freg (ac, info);
     277  	      goto done;
     278  	    }
     279  	  case PDP11_OPCODE_AC_OP:
     280  	    {
     281  	      int ac = (opcode & 0xe0) >> 6;
     282  	      FPRINTF (F, "%s", OP.name);
     283  	      FPRINTF (F, AFTER_INSTRUCTION);
     284  	      print_freg (ac, info);
     285  	      FPRINTF (F, OPERAND_SEPARATOR);
     286  	      if (print_operand (&memaddr, dst, info) < 0)
     287  		return -1;
     288  	      goto done;
     289  	    }
     290  	  case PDP11_OPCODE_OP_AC:
     291  	    {
     292  	      int ac = (opcode & 0xe0) >> 6;
     293  	      FPRINTF (F, "%s", OP.name);
     294  	      FPRINTF (F, AFTER_INSTRUCTION);
     295  	      if (print_operand (&memaddr, dst, info) < 0)
     296  		return -1;
     297  	      FPRINTF (F, OPERAND_SEPARATOR);
     298  	      print_freg (ac, info);
     299  	      goto done;
     300  	    }
     301  	  case PDP11_OPCODE_OP_OP:
     302  	    FPRINTF (F, "%s", OP.name);
     303  	    FPRINTF (F, AFTER_INSTRUCTION);
     304  	    if (print_operand (&memaddr, src, info) < 0)
     305  	      return -1;
     306  	    FPRINTF (F, OPERAND_SEPARATOR);
     307  	    if (print_operand (&memaddr, dst, info) < 0)
     308  	      return -1;
     309  	    goto done;
     310  	  case PDP11_OPCODE_DISPL:
     311  	    {
     312  	      int displ = (opcode & 0xff) << 8;
     313  	      bfd_vma address = memaddr + (sign_extend (displ) >> 7);
     314  	      FPRINTF (F, "%s", OP.name);
     315  	      FPRINTF (F, AFTER_INSTRUCTION);
     316  	      (*info->print_address_func) (address, info);
     317  	      goto done;
     318  	    }
     319  	  case PDP11_OPCODE_REG_DISPL:
     320  	    {
     321  	      int displ = (opcode & 0x3f) << 10;
     322  	      bfd_vma address = memaddr - (displ >> 9);
     323  
     324  	      FPRINTF (F, "%s", OP.name);
     325  	      FPRINTF (F, AFTER_INSTRUCTION);
     326  	      print_reg (src, info);
     327  	      FPRINTF (F, OPERAND_SEPARATOR);
     328  	      (*info->print_address_func) (address, info);
     329  	      goto done;
     330  	    }
     331  	  case PDP11_OPCODE_IMM8:
     332  	    {
     333  	      int code = opcode & 0xff;
     334  	      FPRINTF (F, "%s", OP.name);
     335  	      FPRINTF (F, AFTER_INSTRUCTION);
     336  	      FPRINTF (F, "%o", code);
     337  	      goto done;
     338  	    }
     339  	  case PDP11_OPCODE_IMM6:
     340  	    {
     341  	      int code = opcode & 0x3f;
     342  	      FPRINTF (F, "%s", OP.name);
     343  	      FPRINTF (F, AFTER_INSTRUCTION);
     344  	      FPRINTF (F, "%o", code);
     345  	      goto done;
     346  	    }
     347  	  case PDP11_OPCODE_IMM3:
     348  	    {
     349  	      int code = opcode & 7;
     350  	      FPRINTF (F, "%s", OP.name);
     351  	      FPRINTF (F, AFTER_INSTRUCTION);
     352  	      FPRINTF (F, "%o", code);
     353  	      goto done;
     354  	    }
     355  	  case PDP11_OPCODE_ILLEGAL:
     356  	    {
     357  	      FPRINTF (F, ".word");
     358  	      FPRINTF (F, AFTER_INSTRUCTION);
     359  	      FPRINTF (F, "%o", opcode);
     360  	      goto done;
     361  	    }
     362  	  default:
     363  	    /* TODO: is this a proper way of signalling an error? */
     364  	    FPRINTF (F, "<internal error: unrecognized instruction type>");
     365  	    return -1;
     366  	  }
     367  #undef OP
     368      }
     369   done:
     370  
     371    return memaddr - start_memaddr;
     372  }