Home | History | Annotate | Line # | Download | only in opcodes
      1 /* Disassembler code for Renesas RX.
      2    Copyright (C) 2008-2026 Free Software Foundation, Inc.
      3    Contributed by Red Hat.
      4    Written by DJ Delorie.
      5 
      6    This file is part of the GNU opcodes library.
      7 
      8    This library is free software; you can redistribute it and/or modify
      9    it under the terms of the GNU General Public License as published by
     10    the Free Software Foundation; either version 3, or (at your option)
     11    any later version.
     12 
     13    It is distributed in the hope that it will be useful, but WITHOUT
     14    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
     15    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
     16    License for more details.
     17 
     18    You should have received a copy of the GNU General Public License
     19    along with this program; if not, write to the Free Software
     20    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
     21    MA 02110-1301, USA.  */
     22 
     23 #include "sysdep.h"
     24 #include <stdio.h>
     25 
     26 #include "bfd.h"
     27 #include "dis-asm.h"
     28 #include "opcode/rx.h"
     29 #include "libiberty.h"
     30 #include "opintl.h"
     31 
     32 #include <setjmp.h>
     33 
     34 typedef struct
     35 {
     36   bfd_vma pc;
     37   disassemble_info * dis;
     38 } RX_Data;
     39 
     40 struct private
     41 {
     42   OPCODES_SIGJMP_BUF bailout;
     43 };
     44 
     45 static int
     46 rx_get_byte (void * vdata)
     47 {
     48   bfd_byte buf[1];
     49   RX_Data *rx_data = (RX_Data *) vdata;
     50   int status;
     51 
     52   status = rx_data->dis->read_memory_func (rx_data->pc,
     53 					   buf,
     54 					   1,
     55 					   rx_data->dis);
     56   if (status != 0)
     57     {
     58       struct private *priv = (struct private *) rx_data->dis->private_data;
     59 
     60       rx_data->dis->memory_error_func (status, rx_data->pc,
     61 				       rx_data->dis);
     62        OPCODES_SIGLONGJMP (priv->bailout, 1);
     63     }
     64 
     65   rx_data->pc ++;
     66   return buf[0];
     67 }
     68 
     69 static char const * size_names[RX_MAX_SIZE] =
     70 {
     71   "", ".b", ".ub", ".b", ".w", ".uw", ".w", ".a", ".l", "", "<error>"
     72 };
     73 
     74 static char const * opsize_names[RX_MAX_SIZE] =
     75 {
     76   "", ".b", ".b", ".b", ".w", ".w", ".w", ".a", ".l", ".d", "<error>"
     77 };
     78 
     79 static char const * register_names[] =
     80 {
     81   /* General registers.  */
     82   "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
     83   "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
     84   /* Control registers.  */
     85   "psw", "pc", "usp", "fpsw", NULL, NULL, NULL, NULL,
     86   "bpsw", "bpc", "isp", "fintv", "intb", "extb", NULL, NULL,
     87   "a0", "a1", NULL, NULL, NULL, NULL, NULL, NULL,
     88   NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
     89 };
     90 
     91 static char const * condition_names[] =
     92 {
     93   /* Condition codes.  */
     94   "eq", "ne", "c", "nc", "gtu", "leu", "pz", "n",
     95   "ge", "lt", "gt", "le", "o", "no", "<invalid>", "<invalid>"
     96 };
     97 
     98 static const char * flag_names[] =
     99 {
    100   "c", "z", "s", "o", "", "", "", "",
    101   "", "", "", "", "", "", "", "",
    102   "i", "u", "", "", "", "", "", "",
    103   "", "", "", "", "", "", "", ""
    104 };
    105 
    106 static const char * double_register_names[] =
    107 {
    108   "dr0", "dr1", "dr2", "dr3", "dr4", "dr5", "dr6", "dr7",
    109   "dr8", "dr9", "dr10", "dr11", "dr12", "dr13", "dr14", "dr15"
    110 };
    111 
    112 static const char * double_register_high_names[] =
    113 {
    114   "drh0", "drh1", "drh2", "drh3", "drh4", "drh5", "drh6", "drh7",
    115   "drh8", "drh9", "drh10", "drh11", "drh12", "drh13", "drh14", "drh15"
    116 };
    117 
    118 static const char * double_register_low_names[] =
    119 {
    120   "drl0", "drl1", "drl2", "drl3", "drl4", "drl5", "drl6", "drl7",
    121   "drl8", "drl9", "drl10", "drl11", "drl12", "drl13", "drl14", "drl15"
    122 };
    123 
    124 static const char * double_control_register_names[] =
    125 {
    126   "dpsw", "dcmr", "decnt", "depc"
    127 };
    128 
    129 static const char * double_condition_names[] =
    130 {
    131   "", "un", "eq", "", "lt", "", "le"
    132 };
    133 
    134 static inline const char *
    135 get_register_name (unsigned int reg)
    136 {
    137   if (reg < ARRAY_SIZE (register_names))
    138     return register_names[reg];
    139   return _("<invalid register number>");
    140 }
    141 
    142 static inline const char *
    143 get_condition_name (unsigned int cond)
    144 {
    145   if (cond < ARRAY_SIZE (condition_names))
    146     return condition_names[cond];
    147   return _("<invalid condition code>");
    148 }
    149 
    150 static inline const char *
    151 get_flag_name (unsigned int flag)
    152 {
    153   if (flag < ARRAY_SIZE (flag_names))
    154     return flag_names[flag];
    155   return _("<invalid flag>");
    156 }
    157 
    158 static inline const char *
    159 get_double_register_name (unsigned int reg)
    160 {
    161   if (reg < ARRAY_SIZE (double_register_names))
    162     return double_register_names[reg];
    163   return _("<invalid register number>");
    164 }
    165 
    166 static inline const char *
    167 get_double_register_high_name (unsigned int reg)
    168 {
    169   if (reg < ARRAY_SIZE (double_register_high_names))
    170     return double_register_high_names[reg];
    171   return _("<invalid register number>");
    172 }
    173 
    174 static inline const char *
    175 get_double_register_low_name (unsigned int reg)
    176 {
    177   if (reg < ARRAY_SIZE (double_register_low_names))
    178     return double_register_low_names[reg];
    179   return _("<invalid register number>");
    180 }
    181 
    182 static inline const char *
    183 get_double_control_register_name (unsigned int reg)
    184 {
    185   if (reg < ARRAY_SIZE (double_control_register_names))
    186     return double_control_register_names[reg];
    187   return _("<invalid register number>");
    188 }
    189 
    190 static inline const char *
    191 get_double_condition_name (unsigned int cond)
    192 {
    193   if (cond < ARRAY_SIZE (double_condition_names))
    194     return double_condition_names[cond];
    195   return _("<invalid condition code>");
    196 }
    197 
    198 static inline const char *
    199 get_opsize_name (unsigned int opsize)
    200 {
    201   if (opsize < ARRAY_SIZE (opsize_names))
    202     return opsize_names[opsize];
    203   return _("<invalid opsize>");
    204 }
    205 
    206 static inline const char *
    207 get_size_name (unsigned int size)
    208 {
    209   if (size < ARRAY_SIZE (size_names))
    210     return size_names[size];
    211   return _("<invalid size>");
    212 }
    213 
    214 
    215 int
    216 print_insn_rx (bfd_vma addr, disassemble_info * dis)
    217 {
    218   int rv;
    219   RX_Data rx_data;
    220   RX_Opcode_Decoded opcode;
    221   const char * s;
    222   struct private priv;
    223 
    224   dis->private_data = &priv;
    225   rx_data.pc = addr;
    226   rx_data.dis = dis;
    227 
    228   if (OPCODES_SIGSETJMP (priv.bailout) != 0)
    229     {
    230       /* Error return.  */
    231       return -1;
    232     }
    233 
    234   rv = rx_decode_opcode (addr, &opcode, rx_get_byte, &rx_data);
    235 
    236   dis->bytes_per_line = 10;
    237 
    238 #define PR (dis->fprintf_func)
    239 #define PS (dis->stream)
    240 #define PC(c) PR (PS, "%c", c)
    241 
    242   /* Detect illegal instructions.  */
    243   if (opcode.op[0].size == RX_Bad_Size
    244       || register_names [opcode.op[0].reg] == NULL
    245       || register_names [opcode.op[1].reg] == NULL
    246       || register_names [opcode.op[2].reg] == NULL)
    247     {
    248       bfd_byte buf[10];
    249       int i;
    250 
    251       PR (PS, ".byte ");
    252       rx_data.dis->read_memory_func (rx_data.pc - rv, buf, rv, rx_data.dis);
    253 
    254       for (i = 0 ; i < rv; i++)
    255 	PR (PS, "0x%02x ", buf[i]);
    256       return rv;
    257     }
    258 
    259   for (s = opcode.syntax; *s; s++)
    260     {
    261       if (*s != '%')
    262 	{
    263 	  PC (*s);
    264 	}
    265       else
    266 	{
    267 	  RX_Opcode_Operand * oper;
    268 	  int do_size = 0;
    269 	  int do_hex = 0;
    270 	  int do_addr = 0;
    271 
    272 	  s ++;
    273 
    274 	  if (*s == 'S')
    275 	    {
    276 	      do_size = 1;
    277 	      s++;
    278 	    }
    279 	  if (*s == 'x')
    280 	    {
    281 	      do_hex = 1;
    282 	      s++;
    283 	    }
    284 	  if (*s == 'a')
    285 	    {
    286 	      do_addr = 1;
    287 	      s++;
    288 	    }
    289 
    290 	  switch (*s)
    291 	    {
    292 	    case '%':
    293 	      PC ('%');
    294 	      break;
    295 
    296 	    case 's':
    297 	      PR (PS, "%s", get_opsize_name (opcode.size));
    298 	      break;
    299 
    300 	    case 'b':
    301 	      s ++;
    302 	      if (*s == 'f')
    303 		{
    304 		  int imm = opcode.op[2].addend;
    305 		  int slsb, dlsb, width;
    306 
    307 		  dlsb = (imm >> 5) & 0x1f;
    308 		  slsb = (imm & 0x1f);
    309 		  slsb = (slsb >= 0x10?(slsb ^ 0x1f) + 1:slsb);
    310 		  slsb = dlsb - slsb;
    311 		  slsb = (slsb < 0?-slsb:slsb);
    312 		  width = ((imm >> 10) & 0x1f) - dlsb;
    313 		  PR (PS, "#%d, #%d, #%d, %s, %s",
    314 		      slsb, dlsb, width,
    315 		      get_register_name (opcode.op[1].reg),
    316 		      get_register_name (opcode.op[0].reg));
    317 		}
    318 	      break;
    319 	    case '0':
    320 	    case '1':
    321 	    case '2':
    322 	      oper = opcode.op + (*s - '0');
    323 	      if (do_size)
    324 		{
    325 		  if (oper->type == RX_Operand_Indirect || oper->type == RX_Operand_Zero_Indirect)
    326 		    PR (PS, "%s", get_size_name (oper->size));
    327 		}
    328 	      else
    329 		switch (oper->type)
    330 		  {
    331 		  case RX_Operand_Immediate:
    332 		    if (do_addr)
    333 		      dis->print_address_func (oper->addend, dis);
    334 		    else if (do_hex
    335 			     || oper->addend > 999
    336 			     || oper->addend < -999)
    337 		      PR (PS, "%#x", oper->addend);
    338 		    else
    339 		      PR (PS, "%d", oper->addend);
    340 		    break;
    341 		  case RX_Operand_Register:
    342 		  case RX_Operand_TwoReg:
    343 		    PR (PS, "%s", get_register_name (oper->reg));
    344 		    break;
    345 		  case RX_Operand_Indirect:
    346 		    PR (PS, "%d[%s]", oper->addend, get_register_name (oper->reg));
    347 		    break;
    348 		  case RX_Operand_Zero_Indirect:
    349 		    PR (PS, "[%s]", get_register_name (oper->reg));
    350 		    break;
    351 		  case RX_Operand_Postinc:
    352 		    PR (PS, "[%s+]", get_register_name (oper->reg));
    353 		    break;
    354 		  case RX_Operand_Predec:
    355 		    PR (PS, "[-%s]", get_register_name (oper->reg));
    356 		    break;
    357 		  case RX_Operand_Condition:
    358 		    PR (PS, "%s", get_condition_name (oper->reg));
    359 		    break;
    360 		  case RX_Operand_Flag:
    361 		    PR (PS, "%s", get_flag_name (oper->reg));
    362 		    break;
    363 		  case RX_Operand_DoubleReg:
    364 		    PR (PS, "%s", get_double_register_name (oper->reg));
    365 		    break;
    366 		  case RX_Operand_DoubleRegH:
    367 		    PR (PS, "%s", get_double_register_high_name (oper->reg));
    368 		    break;
    369 		  case RX_Operand_DoubleRegL:
    370 		    PR (PS, "%s", get_double_register_low_name (oper->reg));
    371 		    break;
    372 		  case RX_Operand_DoubleCReg:
    373 		    PR (PS, "%s", get_double_control_register_name (oper->reg));
    374 		    break;
    375 		  case RX_Operand_DoubleCond:
    376 		    PR (PS, "%s", get_double_condition_name (oper->reg));
    377 		    break;
    378 		  default:
    379 		    PR (PS, "[???]");
    380 		    break;
    381 		  }
    382 	    }
    383 	}
    384     }
    385 
    386   return rv;
    387 }
    388