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