(root)/
binutils-2.41/
opcodes/
s12z-dis.c
       1  /* s12z-dis.c -- Freescale S12Z disassembly
       2     Copyright (C) 2018-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 <stdio.h>
      23  #include <stdint.h>
      24  #include <stdbool.h>
      25  #include <assert.h>
      26  
      27  #include "opcode/s12z.h"
      28  #include "bfd.h"
      29  #include "dis-asm.h"
      30  #include "disassemble.h"
      31  #include "s12z-opc.h"
      32  #include "opintl.h"
      33  
      34  struct mem_read_abstraction
      35  {
      36    struct mem_read_abstraction_base base;
      37    bfd_vma memaddr;
      38    struct disassemble_info* info;
      39  };
      40  
      41  static void
      42  advance (struct mem_read_abstraction_base *b)
      43  {
      44    struct mem_read_abstraction *mra = (struct mem_read_abstraction *) b;
      45    mra->memaddr ++;
      46  }
      47  
      48  static bfd_vma
      49  posn (struct mem_read_abstraction_base *b)
      50  {
      51    struct mem_read_abstraction *mra = (struct mem_read_abstraction *) b;
      52    return mra->memaddr;
      53  }
      54  
      55  static int
      56  abstract_read_memory (struct mem_read_abstraction_base *b,
      57  		      int offset,
      58  		      size_t n, bfd_byte *bytes)
      59  {
      60    struct mem_read_abstraction *mra = (struct mem_read_abstraction *) b;
      61  
      62    int status = (*mra->info->read_memory_func) (mra->memaddr + offset,
      63  					       bytes, n, mra->info);
      64    if (status != 0)
      65      (*mra->info->memory_error_func) (status, mra->memaddr + offset,
      66                                       mra->info);
      67    return status != 0 ? -1 : 0;
      68  }
      69  
      70  /* Start of disassembly file.  */
      71  const struct reg registers[S12Z_N_REGISTERS] =
      72    {
      73      {"d2", 2},
      74      {"d3", 2},
      75      {"d4", 2},
      76      {"d5", 2},
      77  
      78      {"d0", 1},
      79      {"d1", 1},
      80  
      81      {"d6", 4},
      82      {"d7", 4},
      83  
      84      {"x", 3},
      85      {"y", 3},
      86      {"s", 3},
      87      {"p", 3},
      88      {"cch", 1},
      89      {"ccl", 1},
      90      {"ccw", 2}
      91    };
      92  
      93  static const char *mnemonics[] =
      94    {
      95      "!!invalid!!",
      96      "psh",
      97      "pul",
      98      "tbne", "tbeq", "tbpl", "tbmi", "tbgt", "tble",
      99      "dbne", "dbeq", "dbpl", "dbmi", "dbgt", "dble",
     100      "sex",
     101      "exg",
     102      "lsl", "lsr",
     103      "asl", "asr",
     104      "rol", "ror",
     105      "bfins", "bfext",
     106  
     107      "trap",
     108  
     109      "ld",
     110      "st",
     111      "cmp",
     112  
     113      "stop",
     114      "wai",
     115      "sys",
     116  
     117      "minu",
     118      "mins",
     119      "maxu",
     120      "maxs",
     121  
     122      "abs",
     123      "adc",
     124      "bit",
     125      "sbc",
     126      "rti",
     127      "clb",
     128      "eor",
     129  
     130      "sat",
     131  
     132      "nop",
     133      "bgnd",
     134      "brclr",
     135      "brset",
     136      "rts",
     137      "lea",
     138      "mov",
     139  
     140      "bra",
     141      "bsr",
     142      "bhi",
     143      "bls",
     144      "bcc",
     145      "bcs",
     146      "bne",
     147      "beq",
     148      "bvc",
     149      "bvs",
     150      "bpl",
     151      "bmi",
     152      "bge",
     153      "blt",
     154      "bgt",
     155      "ble",
     156      "inc",
     157      "clr",
     158      "dec",
     159  
     160      "add",
     161      "sub",
     162      "and",
     163      "or",
     164  
     165      "tfr",
     166      "jmp",
     167      "jsr",
     168      "com",
     169      "andcc",
     170      "neg",
     171      "orcc",
     172      "bclr",
     173      "bset",
     174      "btgl",
     175      "swi",
     176  
     177      "mulu",
     178      "divu",
     179      "modu",
     180      "macu",
     181      "qmulu",
     182  
     183      "muls",
     184      "divs",
     185      "mods",
     186      "macs",
     187      "qmuls",
     188  
     189      NULL
     190    };
     191  
     192  
     193  static void
     194  operand_separator (struct disassemble_info *info)
     195  {
     196    if ((info->flags & 0x2))
     197      (*info->fprintf_func) (info->stream, ",");
     198  
     199    (*info->fprintf_func) (info->stream, " ");
     200  
     201    info->flags |= 0x2;
     202  }
     203  
     204  /* Render the symbol name whose value is ADDR + BASE or the adddress itself if
     205     there is no symbol.  If BASE is non zero, then the a PC relative adddress is
     206     assumend (ie BASE is the value in the PC.  */
     207  static void
     208  decode_possible_symbol (bfd_signed_vma addr, bfd_vma base,
     209                          struct disassemble_info *info, bool relative)
     210  {
     211    const char *fmt = relative ? "*%+" PRId64 : "%" PRId64;
     212    asymbol *sym = info->symbol_at_address_func (addr + base, info);
     213  
     214    if (!sym)
     215      (*info->fprintf_func) (info->stream, fmt, (int64_t) addr);
     216    else
     217      (*info->fprintf_func) (info->stream, "%s", bfd_asymbol_name (sym));
     218  }
     219  
     220  
     221  /* Emit the disassembled text for OPR */
     222  static void
     223  opr_emit_disassembly (const struct operand *opr,
     224  		      struct disassemble_info *info)
     225  {
     226    operand_separator (info);
     227  
     228    switch (opr->cl)
     229      {
     230      case OPND_CL_IMMEDIATE:
     231        (*info->fprintf_func) (info->stream, "#%d",
     232  			     ((struct immediate_operand *) opr)->value);
     233        break;
     234      case OPND_CL_REGISTER:
     235        {
     236          int r = ((struct register_operand*) opr)->reg;
     237  
     238  	if (r < 0 || r >= S12Z_N_REGISTERS)
     239  	  (*info->fprintf_func) (info->stream, _("<illegal reg num>"));
     240  	else
     241  	  (*info->fprintf_func) (info->stream, "%s", registers[r].name);
     242        }
     243        break;
     244      case OPND_CL_REGISTER_ALL16:
     245        (*info->fprintf_func) (info->stream, "%s", "ALL16b");
     246        break;
     247      case OPND_CL_REGISTER_ALL:
     248        (*info->fprintf_func) (info->stream, "%s", "ALL");
     249        break;
     250      case OPND_CL_BIT_FIELD:
     251        (*info->fprintf_func) (info->stream, "#%d:%d",
     252                               ((struct bitfield_operand*)opr)->width,
     253                               ((struct bitfield_operand*)opr)->offset);
     254        break;
     255      case OPND_CL_SIMPLE_MEMORY:
     256        {
     257          struct simple_memory_operand *mo =
     258  	  (struct simple_memory_operand *) opr;
     259  	decode_possible_symbol (mo->addr, mo->base, info, mo->relative);
     260        }
     261        break;
     262      case OPND_CL_MEMORY:
     263        {
     264          int used_reg = 0;
     265          struct memory_operand *mo = (struct memory_operand *) opr;
     266  	(*info->fprintf_func) (info->stream, "%c", mo->indirect ? '[' : '(');
     267  
     268  	const char *fmt;
     269  	assert (mo->mutation == OPND_RM_NONE || mo->n_regs == 1);
     270  	switch (mo->mutation)
     271  	  {
     272  	  case OPND_RM_PRE_DEC:
     273  	    fmt = "-%s";
     274  	    break;
     275  	  case OPND_RM_PRE_INC:
     276  	    fmt = "+%s";
     277  	    break;
     278  	  case OPND_RM_POST_DEC:
     279  	    fmt = "%s-";
     280  	    break;
     281  	  case OPND_RM_POST_INC:
     282  	    fmt = "%s+";
     283  	    break;
     284  	  case OPND_RM_NONE:
     285  	  default:
     286  	    if (mo->n_regs < 2)
     287  	      (*info->fprintf_func) (info->stream, (mo->n_regs == 0) ? "%d" : "%d,", mo->base_offset);
     288  	    fmt = "%s";
     289  	    break;
     290  	  }
     291  	if (mo->n_regs > 0)
     292  	  {
     293  	    int r = mo->regs[0];
     294  
     295  	    if (r < 0 || r >= S12Z_N_REGISTERS)
     296  	      (*info->fprintf_func) (info->stream, fmt, _("<illegal reg num>"));
     297  	    else
     298  	      (*info->fprintf_func) (info->stream, fmt, registers[r].name);
     299  	  }
     300  	used_reg = 1;
     301  
     302          if (mo->n_regs > used_reg)
     303            {
     304  	    int r = mo->regs[used_reg];
     305  
     306  	    if (r < 0 || r >= S12Z_N_REGISTERS)
     307  	      (*info->fprintf_func) (info->stream, _("<illegal reg num>"));
     308  	    else
     309  	      (*info->fprintf_func) (info->stream, ",%s",
     310  				     registers[r].name);
     311            }
     312  
     313  	(*info->fprintf_func) (info->stream, "%c",
     314  			       mo->indirect ? ']' : ')');
     315        }
     316        break;
     317      };
     318  }
     319  
     320  #define S12Z_N_SIZES 4
     321  static const char shift_size_table[S12Z_N_SIZES] =
     322  {
     323    'b', 'w', 'p', 'l'
     324  };
     325  
     326  int
     327  print_insn_s12z (bfd_vma memaddr, struct disassemble_info* info)
     328  {
     329    int o;
     330    enum optr operator = OP_INVALID;
     331    int n_operands = 0;
     332  
     333    /* The longest instruction in S12Z can have 6 operands.
     334       (Most have 3 or less.  Only PSH and PUL have so many.  */
     335    struct operand *operands[6];
     336  
     337    struct mem_read_abstraction mra;
     338    mra.base.read = (void *) abstract_read_memory ;
     339    mra.base.advance = advance ;
     340    mra.base.posn = posn;
     341    mra.memaddr = memaddr;
     342    mra.info = info;
     343  
     344    short osize = -1;
     345    int n_bytes =
     346      decode_s12z (&operator, &osize, &n_operands, operands,
     347  		 (struct mem_read_abstraction_base *) &mra);
     348  
     349    (info->fprintf_func) (info->stream, "%s", mnemonics[(long)operator]);
     350  
     351    /* Ship out size sufficies for those instructions which
     352       need them.  */
     353    if (osize == -1)
     354      {
     355        bool suffix = false;
     356  
     357        for (o = 0; o < n_operands; ++o)
     358  	{
     359  	  if (operands[o] && operands[o]->osize != -1)
     360  	    {
     361  	      if (!suffix)
     362  		{
     363  		  (*mra.info->fprintf_func) (mra.info->stream, "%c", '.');
     364  		  suffix = true;
     365  		}
     366  
     367  	      osize = operands[o]->osize;
     368  
     369  	      if (osize < 0 || osize >= S12Z_N_SIZES)
     370  		(*mra.info->fprintf_func) (mra.info->stream, _("<bad>"));
     371  	      else
     372  		(*mra.info->fprintf_func) (mra.info->stream, "%c",
     373  					   shift_size_table[osize]);
     374  	    }
     375  	}
     376      }
     377    else
     378      {
     379        if (osize < 0 || osize >= S12Z_N_SIZES)
     380  	(*mra.info->fprintf_func) (mra.info->stream, _(".<bad>"));
     381        else
     382  	(*mra.info->fprintf_func) (mra.info->stream, ".%c",
     383  				   shift_size_table[osize]);
     384      }
     385  
     386    /* Ship out the operands.  */
     387    for (o = 0; o < n_operands; ++o)
     388      {
     389        if (operands[o])
     390  	opr_emit_disassembly (operands[o], mra.info);
     391        free (operands[o]);
     392      }
     393  
     394    return n_bytes;
     395  }