(root)/
binutils-2.41/
opcodes/
rl78-dis.c
       1  /* Disassembler code for Renesas RL78.
       2     Copyright (C) 2011-2023 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 "elf-bfd.h"
      28  #include "disassemble.h"
      29  #include "opcode/rl78.h"
      30  #include "elf/rl78.h"
      31  
      32  #include <setjmp.h>
      33  
      34  #define DEBUG_SEMANTICS 0
      35  
      36  typedef struct
      37  {
      38    bfd_vma pc;
      39    disassemble_info * dis;
      40  } RL78_Data;
      41  
      42  struct private
      43  {
      44    OPCODES_SIGJMP_BUF bailout;
      45  };
      46  
      47  static int
      48  rl78_get_byte (void * vdata)
      49  {
      50    bfd_byte buf[1];
      51    RL78_Data *rl78_data = (RL78_Data *) vdata;
      52    int status;
      53  
      54    status = rl78_data->dis->read_memory_func (rl78_data->pc,
      55  					     buf,
      56  					     1,
      57  					     rl78_data->dis);
      58    if (status != 0)
      59      {
      60        struct private *priv = (struct private *) rl78_data->dis->private_data;
      61  
      62        rl78_data->dis->memory_error_func (status, rl78_data->pc,
      63  					 rl78_data->dis);
      64        OPCODES_SIGLONGJMP (priv->bailout, 1);
      65      }
      66  
      67    rl78_data->pc ++;
      68    return buf[0];
      69  }
      70  
      71  static char const *
      72  register_names[] =
      73  {
      74    "",
      75    "x", "a", "c", "b", "e", "d", "l", "h",
      76    "ax", "bc", "de", "hl",
      77    "sp", "psw", "cs", "es", "pmc", "mem"
      78  };
      79  
      80  static char const *
      81  condition_names[] =
      82  {
      83    "t", "f", "c", "nc", "h", "nh", "z", "nz"
      84  };
      85  
      86  static int
      87  indirect_type (int t)
      88  {
      89    switch (t)
      90      {
      91      case RL78_Operand_Indirect:
      92      case RL78_Operand_BitIndirect:
      93      case RL78_Operand_PostInc:
      94      case RL78_Operand_PreDec:
      95        return 1;
      96      default:
      97        return 0;
      98      }
      99  }
     100  
     101  static int
     102  print_insn_rl78_common (bfd_vma addr, disassemble_info * dis, RL78_Dis_Isa isa)
     103  {
     104    int rv;
     105    RL78_Data rl78_data;
     106    RL78_Opcode_Decoded opcode;
     107    const char * s;
     108  #if DEBUG_SEMANTICS
     109    static char buf[200];
     110  #endif
     111    struct private priv;
     112  
     113    dis->private_data = &priv;
     114    rl78_data.pc = addr;
     115    rl78_data.dis = dis;
     116  
     117    if (OPCODES_SIGSETJMP (priv.bailout) != 0)
     118      {
     119        /* Error return.  */
     120        return -1;
     121      }
     122  
     123    rv = rl78_decode_opcode (addr, &opcode, rl78_get_byte, &rl78_data, isa);
     124  
     125    dis->bytes_per_line = 10;
     126  
     127  #define PR (dis->fprintf_func)
     128  #define PS (dis->stream)
     129  #define PC(c) PR (PS, "%c", c)
     130  
     131    s = opcode.syntax;
     132  
     133  #if DEBUG_SEMANTICS
     134  
     135    switch (opcode.id)
     136      {
     137      case RLO_unknown: s = "uknown"; break;
     138      case RLO_add: s = "add: %e0%0 += %e1%1"; break;
     139      case RLO_addc: s = "addc: %e0%0 += %e1%1 + CY"; break;
     140      case RLO_and: s = "and: %e0%0 &= %e1%1"; break;
     141      case RLO_branch: s = "branch: pc = %e0%0"; break;
     142      case RLO_branch_cond: s = "branch_cond: pc = %e0%0 if %c1 / %e1%1"; break;
     143      case RLO_branch_cond_clear: s = "branch_cond_clear: pc = %e0%0 if %c1 / %e1%1, %e1%1 = 0"; break;
     144      case RLO_call: s = "call: pc = %e1%0"; break;
     145      case RLO_cmp: s = "cmp: %e0%0 - %e1%1"; break;
     146      case RLO_mov: s = "mov: %e0%0 = %e1%1"; break;
     147      case RLO_or: s = "or: %e0%0 |= %e1%1"; break;
     148      case RLO_rol: s = "rol: %e0%0 <<= %e1%1"; break;
     149      case RLO_rolc: s = "rol: %e0%0 <<= %e1%1,CY"; break;
     150      case RLO_ror: s = "ror: %e0%0 >>= %e1%1"; break;
     151      case RLO_rorc: s = "ror: %e0%0 >>= %e1%1,CY"; break;
     152      case RLO_sar: s = "sar: %e0%0 >>= %e1%1 signed"; break;
     153      case RLO_sel: s = "sel: rb = %1"; break;
     154      case RLO_shr: s = "shr: %e0%0 >>= %e1%1 unsigned"; break;
     155      case RLO_shl: s = "shl: %e0%0 <<= %e1%1"; break;
     156      case RLO_skip: s = "skip: if %c1"; break;
     157      case RLO_sub: s = "sub: %e0%0 -= %e1%1"; break;
     158      case RLO_subc: s = "subc: %e0%0 -= %e1%1 - CY"; break;
     159      case RLO_xch: s = "xch: %e0%0 <-> %e1%1"; break;
     160      case RLO_xor: s = "xor: %e0%0 ^= %e1%1"; break;
     161      }
     162  
     163    sprintf(buf, "%s%%W%%f\t\033[32m%s\033[0m", s, opcode.syntax);
     164    s = buf;
     165  
     166  #endif
     167  
     168    for (; *s; s++)
     169      {
     170        if (*s != '%')
     171  	{
     172  	  PC (*s);
     173  	}
     174        else
     175  	{
     176  	  RL78_Opcode_Operand * oper;
     177  	  int do_hex = 0;
     178  	  int do_addr = 0;
     179  	  int do_es = 0;
     180  	  int do_sfr = 0;
     181  	  int do_cond = 0;
     182  	  int do_bang = 0;
     183  
     184  	  while (1)
     185  	    {
     186  	      s ++;
     187  	      switch (*s)
     188  		{
     189  		case 'x':
     190  		  do_hex = 1;
     191  		  break;
     192  		case '!':
     193  		  do_bang = 1;
     194  		  break;
     195  		case 'e':
     196  		  do_es = 1;
     197  		  break;
     198  		case 'a':
     199  		  do_addr = 1;
     200  		  break;
     201  		case 's':
     202  		  do_sfr = 1;
     203  		  break;
     204  		case 'c':
     205  		  do_cond = 1;
     206  		  break;
     207  		default:
     208  		  goto no_more_modifiers;
     209  		}
     210  	    }
     211  	no_more_modifiers:;
     212  
     213  	  switch (*s)
     214  	    {
     215  	    case '%':
     216  	      PC ('%');
     217  	      break;
     218  
     219  #if DEBUG_SEMANTICS
     220  
     221  	    case 'W':
     222  	      if (opcode.size == RL78_Word)
     223  		PR (PS, " \033[33mW\033[0m");
     224  	      break;
     225  
     226  	    case 'f':
     227  	      if (opcode.flags)
     228  		{
     229  		  char *comma = "";
     230  		  PR (PS, "  \033[35m");
     231  
     232  		  if (opcode.flags & RL78_PSW_Z)
     233  		    { PR (PS, "Z"); comma = ","; }
     234  		  if (opcode.flags & RL78_PSW_AC)
     235  		    { PR (PS, "%sAC", comma); comma = ","; }
     236  		  if (opcode.flags & RL78_PSW_CY)
     237  		    { PR (PS, "%sCY", comma); comma = ","; }
     238  		  PR (PS, "\033[0m");
     239  		}
     240  	      break;
     241  
     242  #endif
     243  
     244  	    case '0':
     245  	    case '1':
     246  	      oper = *s == '0' ? &opcode.op[0] : &opcode.op[1];
     247  	    if (do_es)
     248  	      {
     249  		if (oper->use_es && indirect_type (oper->type))
     250  		  PR (PS, "es:");
     251  	      }
     252  
     253  	    if (do_bang)
     254  	      {
     255  		/* If we are going to display SP by name, we must omit the bang.  */
     256  		if ((oper->type == RL78_Operand_Indirect
     257  		     || oper->type == RL78_Operand_BitIndirect)
     258  		    && oper->reg == RL78_Reg_None
     259  		    && do_sfr
     260  		    && ((oper->addend == 0xffff8 && opcode.size == RL78_Word)
     261  			|| (oper->addend == 0x0fff8 && do_es && opcode.size == RL78_Word)))
     262  		  ;
     263  		else
     264  		  PC ('!');
     265  	      }
     266  
     267  	    if (do_cond)
     268  	      {
     269  		PR (PS, "%s", condition_names[oper->condition]);
     270  		break;
     271  	      }
     272  
     273  	    switch (oper->type)
     274  	      {
     275  	      case RL78_Operand_Immediate:
     276  		if (do_addr)
     277  		  dis->print_address_func (oper->addend, dis);
     278  		else if (do_hex
     279  			 || oper->addend > 999
     280  			 || oper->addend < -999)
     281  		  PR (PS, "%#x", oper->addend);
     282  		else
     283  		  PR (PS, "%d", oper->addend);
     284  		break;
     285  
     286  	      case RL78_Operand_Register:
     287  		PR (PS, "%s", register_names[oper->reg]);
     288  		break;
     289  
     290  	      case RL78_Operand_Bit:
     291  		PR (PS, "%s.%d", register_names[oper->reg], oper->bit_number);
     292  		break;
     293  
     294  	      case RL78_Operand_Indirect:
     295  	      case RL78_Operand_BitIndirect:
     296  		switch (oper->reg)
     297  		  {
     298  		  case RL78_Reg_None:
     299  		    if (oper->addend == 0xffffa && do_sfr && opcode.size == RL78_Byte)
     300  		      PR (PS, "psw");
     301  		    else if (oper->addend == 0xffff8 && do_sfr && opcode.size == RL78_Word)
     302  		      PR (PS, "sp");
     303  		    else if (oper->addend == 0x0fff8 && do_sfr && do_es && opcode.size == RL78_Word)
     304  		      PR (PS, "sp");
     305                      else if (oper->addend == 0xffff8 && do_sfr && opcode.size == RL78_Byte)
     306                        PR (PS, "spl");
     307                      else if (oper->addend == 0xffff9 && do_sfr && opcode.size == RL78_Byte)
     308                        PR (PS, "sph");
     309                      else if (oper->addend == 0xffffc && do_sfr && opcode.size == RL78_Byte)
     310                        PR (PS, "cs");
     311                      else if (oper->addend == 0xffffd && do_sfr && opcode.size == RL78_Byte)
     312                        PR (PS, "es");
     313                      else if (oper->addend == 0xffffe && do_sfr && opcode.size == RL78_Byte)
     314                        PR (PS, "pmc");
     315                      else if (oper->addend == 0xfffff && do_sfr && opcode.size == RL78_Byte)
     316                        PR (PS, "mem");
     317  		    else if (oper->addend >= 0xffe20)
     318  		      PR (PS, "%#x", oper->addend);
     319  		    else
     320  		      {
     321  			int faddr = oper->addend;
     322  			if (do_es && ! oper->use_es)
     323  			  faddr += 0xf0000;
     324  			dis->print_address_func (faddr, dis);
     325  		      }
     326  		    break;
     327  
     328  		  case RL78_Reg_B:
     329  		  case RL78_Reg_C:
     330  		  case RL78_Reg_BC:
     331  		    PR (PS, "%d[%s]", oper->addend, register_names[oper->reg]);
     332  		    break;
     333  
     334  		  default:
     335  		    PR (PS, "[%s", register_names[oper->reg]);
     336  		    if (oper->reg2 != RL78_Reg_None)
     337  		      PR (PS, "+%s", register_names[oper->reg2]);
     338  		    if (oper->addend || do_addr)
     339  		      PR (PS, "+%d", oper->addend);
     340  		    PC (']');
     341  		    break;
     342  
     343  		  }
     344  		if (oper->type == RL78_Operand_BitIndirect)
     345  		  PR (PS, ".%d", oper->bit_number);
     346  		break;
     347  
     348  #if DEBUG_SEMANTICS
     349  		/* Shouldn't happen - push and pop don't print
     350  		   [SP] directly.  But we *do* use them for
     351  		   semantic debugging.  */
     352  	      case RL78_Operand_PostInc:
     353  		PR (PS, "[%s++]", register_names[oper->reg]);
     354  		break;
     355  	      case RL78_Operand_PreDec:
     356  		PR (PS, "[--%s]", register_names[oper->reg]);
     357  		break;
     358  #endif
     359  
     360  	      default:
     361  		/* If we ever print this, that means the
     362  		   programmer tried to print an operand with a
     363  		   type we don't expect.  Print the line and
     364  		   operand number from rl78-decode.opc for
     365  		   them.  */
     366  		PR (PS, "???%d.%d", opcode.lineno, *s - '0');
     367  		break;
     368  	      }
     369  	    }
     370  	}
     371      }
     372  
     373  #if DEBUG_SEMANTICS
     374  
     375    PR (PS, "\t\033[34m(line %d)\033[0m", opcode.lineno);
     376  
     377  #endif
     378  
     379    return rv;
     380  }
     381  
     382  int
     383  print_insn_rl78 (bfd_vma addr, disassemble_info * dis)
     384  {
     385    return print_insn_rl78_common (addr, dis, RL78_ISA_DEFAULT);
     386  }
     387  
     388  int
     389  print_insn_rl78_g10 (bfd_vma addr, disassemble_info * dis)
     390  {
     391    return print_insn_rl78_common (addr, dis, RL78_ISA_G10);
     392  }
     393  
     394  int
     395  print_insn_rl78_g13 (bfd_vma addr, disassemble_info * dis)
     396  {
     397    return print_insn_rl78_common (addr, dis, RL78_ISA_G13);
     398  }
     399  
     400  int
     401  print_insn_rl78_g14 (bfd_vma addr, disassemble_info * dis)
     402  {
     403    return print_insn_rl78_common (addr, dis, RL78_ISA_G14);
     404  }
     405  
     406  disassembler_ftype
     407  rl78_get_disassembler (bfd *abfd)
     408  {
     409    int cpu = E_FLAG_RL78_ANY_CPU;
     410  
     411    if (abfd != NULL && bfd_get_flavour (abfd) == bfd_target_elf_flavour)
     412      cpu = abfd->tdata.elf_obj_data->elf_header->e_flags & E_FLAG_RL78_CPU_MASK;
     413  
     414    switch (cpu)
     415      {
     416      case E_FLAG_RL78_G10:
     417        return print_insn_rl78_g10;
     418      case E_FLAG_RL78_G13:
     419        return print_insn_rl78_g13;
     420      case E_FLAG_RL78_G14:
     421        return print_insn_rl78_g14;
     422      default:
     423        return print_insn_rl78;
     424      }
     425  }