Home | History | Annotate | Line # | Download | only in opcodes
      1      1.1  christos /* Disassemble Xilinx microblaze instructions.
      2      1.1  christos 
      3  1.1.1.9  christos    Copyright (C) 2009-2024 Free Software Foundation, Inc.
      4      1.1  christos 
      5      1.1  christos    This file is part of the GNU opcodes library.
      6      1.1  christos 
      7      1.1  christos    This library is free software; you can redistribute it and/or modify
      8      1.1  christos    it under the terms of the GNU General Public License as published by
      9      1.1  christos    the Free Software Foundation; either version 3, or (at your option)
     10      1.1  christos    any later version.
     11      1.1  christos 
     12      1.1  christos    It is distributed in the hope that it will be useful, but WITHOUT
     13      1.1  christos    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
     14      1.1  christos    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
     15      1.1  christos    License for more details.
     16      1.1  christos 
     17      1.1  christos    You should have received a copy of the GNU General Public License
     18      1.1  christos    along with this file; see the file COPYING.  If not, write to the
     19      1.1  christos    Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston,
     20      1.1  christos    MA 02110-1301, USA.  */
     21      1.1  christos 
     22      1.1  christos 
     23      1.1  christos #include "sysdep.h"
     24      1.1  christos #define STATIC_TABLE
     25      1.1  christos #define DEFINE_TABLE
     26      1.1  christos 
     27  1.1.1.6  christos #include "disassemble.h"
     28      1.1  christos #include <strings.h>
     29      1.1  christos #include "microblaze-opc.h"
     30      1.1  christos #include "microblaze-dis.h"
     31      1.1  christos 
     32  1.1.1.7  christos #define get_field_rd(buf, instr)   get_field (buf, instr, RD_MASK, RD_LOW)
     33  1.1.1.7  christos #define get_field_r1(buf, instr)   get_field (buf, instr, RA_MASK, RA_LOW)
     34  1.1.1.7  christos #define get_field_r2(buf, instr)   get_field (buf, instr, RB_MASK, RB_LOW)
     35      1.1  christos #define get_int_field_imm(instr)   ((instr & IMM_MASK) >> IMM_LOW)
     36      1.1  christos #define get_int_field_r1(instr)    ((instr & RA_MASK) >> RA_LOW)
     37      1.1  christos 
     38  1.1.1.9  christos #define NUM_STRBUFS 4
     39  1.1.1.7  christos #define STRBUF_SIZE 25
     40      1.1  christos 
     41  1.1.1.7  christos struct string_buf
     42  1.1.1.7  christos {
     43  1.1.1.7  christos   unsigned int which;
     44  1.1.1.7  christos   char str[NUM_STRBUFS][STRBUF_SIZE];
     45  1.1.1.7  christos };
     46  1.1.1.7  christos 
     47  1.1.1.7  christos static inline char *
     48  1.1.1.7  christos strbuf (struct string_buf *buf)
     49  1.1.1.7  christos {
     50  1.1.1.7  christos #ifdef ENABLE_CHECKING
     51  1.1.1.7  christos   if (buf->which >= NUM_STRBUFS)
     52  1.1.1.7  christos     abort ();
     53  1.1.1.7  christos #endif
     54  1.1.1.7  christos   return buf->str[buf->which++];
     55  1.1.1.7  christos }
     56      1.1  christos 
     57      1.1  christos static char *
     58  1.1.1.7  christos get_field (struct string_buf *buf, long instr, long mask, unsigned short low)
     59      1.1  christos {
     60  1.1.1.7  christos   char *p = strbuf (buf);
     61      1.1  christos 
     62  1.1.1.7  christos   sprintf (p, "%s%d", register_prefix, (int)((instr & mask) >> low));
     63  1.1.1.7  christos   return p;
     64      1.1  christos }
     65      1.1  christos 
     66      1.1  christos static char *
     67  1.1.1.7  christos get_field_imm (struct string_buf *buf, long instr)
     68      1.1  christos {
     69  1.1.1.7  christos   char *p = strbuf (buf);
     70      1.1  christos 
     71  1.1.1.7  christos   sprintf (p, "%d", (short)((instr & IMM_MASK) >> IMM_LOW));
     72  1.1.1.7  christos   return p;
     73      1.1  christos }
     74      1.1  christos 
     75      1.1  christos static char *
     76  1.1.1.7  christos get_field_imm5 (struct string_buf *buf, long instr)
     77      1.1  christos {
     78  1.1.1.7  christos   char *p = strbuf (buf);
     79      1.1  christos 
     80  1.1.1.7  christos   sprintf (p, "%d", (short)((instr & IMM5_MASK) >> IMM_LOW));
     81  1.1.1.7  christos   return p;
     82      1.1  christos }
     83      1.1  christos 
     84      1.1  christos static char *
     85  1.1.1.7  christos get_field_imm5_mbar (struct string_buf *buf, long instr)
     86  1.1.1.2  christos {
     87  1.1.1.7  christos   char *p = strbuf (buf);
     88  1.1.1.2  christos 
     89  1.1.1.7  christos   sprintf (p, "%d", (short)((instr & IMM5_MBAR_MASK) >> IMM_MBAR));
     90  1.1.1.7  christos   return p;
     91  1.1.1.2  christos }
     92  1.1.1.2  christos 
     93  1.1.1.2  christos static char *
     94  1.1.1.9  christos get_field_immw (struct string_buf *buf, long instr)
     95  1.1.1.9  christos {
     96  1.1.1.9  christos   char *p = strbuf (buf);
     97  1.1.1.9  christos 
     98  1.1.1.9  christos   if (instr & 0x00004000)
     99  1.1.1.9  christos     sprintf (p, "%d", (short)(((instr & IMM5_WIDTH_MASK)
    100  1.1.1.9  christos 				>> IMM_WIDTH_LOW))); /* bsefi */
    101  1.1.1.9  christos   else
    102  1.1.1.9  christos     sprintf (p, "%d", (short)(((instr & IMM5_WIDTH_MASK) >>
    103  1.1.1.9  christos 				IMM_WIDTH_LOW) - ((instr & IMM5_MASK) >>
    104  1.1.1.9  christos 				IMM_LOW) + 1)); /* bsifi */
    105  1.1.1.9  christos   return p;
    106  1.1.1.9  christos }
    107  1.1.1.9  christos 
    108  1.1.1.9  christos static char *
    109  1.1.1.7  christos get_field_rfsl (struct string_buf *buf, long instr)
    110      1.1  christos {
    111  1.1.1.7  christos   char *p = strbuf (buf);
    112      1.1  christos 
    113  1.1.1.7  christos   sprintf (p, "%s%d", fsl_register_prefix,
    114      1.1  christos 	   (short)((instr & RFSL_MASK) >> IMM_LOW));
    115  1.1.1.7  christos   return p;
    116      1.1  christos }
    117      1.1  christos 
    118      1.1  christos static char *
    119  1.1.1.7  christos get_field_imm15 (struct string_buf *buf, long instr)
    120      1.1  christos {
    121  1.1.1.7  christos   char *p = strbuf (buf);
    122      1.1  christos 
    123  1.1.1.7  christos   sprintf (p, "%d", (short)((instr & IMM15_MASK) >> IMM_LOW));
    124  1.1.1.7  christos   return p;
    125      1.1  christos }
    126      1.1  christos 
    127      1.1  christos static char *
    128  1.1.1.7  christos get_field_special (struct string_buf *buf, long instr,
    129  1.1.1.8  christos 		   const struct op_code_struct *op)
    130      1.1  christos {
    131  1.1.1.7  christos   char *p = strbuf (buf);
    132  1.1.1.7  christos   char *spr;
    133      1.1  christos 
    134      1.1  christos   switch ((((instr & IMM_MASK) >> IMM_LOW) ^ op->immval_mask))
    135      1.1  christos     {
    136      1.1  christos     case REG_MSR_MASK :
    137  1.1.1.7  christos       spr = "msr";
    138      1.1  christos       break;
    139      1.1  christos     case REG_PC_MASK :
    140  1.1.1.7  christos       spr = "pc";
    141      1.1  christos       break;
    142      1.1  christos     case REG_EAR_MASK :
    143  1.1.1.7  christos       spr = "ear";
    144      1.1  christos       break;
    145      1.1  christos     case REG_ESR_MASK :
    146  1.1.1.7  christos       spr = "esr";
    147      1.1  christos       break;
    148      1.1  christos     case REG_FSR_MASK :
    149  1.1.1.7  christos       spr = "fsr";
    150      1.1  christos       break;
    151      1.1  christos     case REG_BTR_MASK :
    152  1.1.1.7  christos       spr = "btr";
    153      1.1  christos       break;
    154      1.1  christos     case REG_EDR_MASK :
    155  1.1.1.7  christos       spr = "edr";
    156      1.1  christos       break;
    157      1.1  christos     case REG_PID_MASK :
    158  1.1.1.7  christos       spr = "pid";
    159      1.1  christos       break;
    160      1.1  christos     case REG_ZPR_MASK :
    161  1.1.1.7  christos       spr = "zpr";
    162      1.1  christos       break;
    163      1.1  christos     case REG_TLBX_MASK :
    164  1.1.1.7  christos       spr = "tlbx";
    165      1.1  christos       break;
    166      1.1  christos     case REG_TLBLO_MASK :
    167  1.1.1.7  christos       spr = "tlblo";
    168      1.1  christos       break;
    169      1.1  christos     case REG_TLBHI_MASK :
    170  1.1.1.7  christos       spr = "tlbhi";
    171      1.1  christos       break;
    172      1.1  christos     case REG_TLBSX_MASK :
    173  1.1.1.7  christos       spr = "tlbsx";
    174      1.1  christos       break;
    175  1.1.1.2  christos     case REG_SHR_MASK :
    176  1.1.1.7  christos       spr = "shr";
    177  1.1.1.2  christos       break;
    178  1.1.1.2  christos     case REG_SLR_MASK :
    179  1.1.1.7  christos       spr = "slr";
    180  1.1.1.2  christos       break;
    181      1.1  christos     default :
    182      1.1  christos       if (((((instr & IMM_MASK) >> IMM_LOW) ^ op->immval_mask) & 0xE000)
    183  1.1.1.7  christos 	  == REG_PVR_MASK)
    184  1.1.1.7  christos 	{
    185  1.1.1.7  christos 	  sprintf (p, "%spvr%d", register_prefix,
    186      1.1  christos 		   (unsigned short)(((instr & IMM_MASK) >> IMM_LOW)
    187  1.1.1.7  christos 				    ^ op->immval_mask) ^ REG_PVR_MASK);
    188  1.1.1.7  christos 	  return p;
    189  1.1.1.7  christos 	}
    190      1.1  christos       else
    191  1.1.1.7  christos 	spr = "pc";
    192      1.1  christos       break;
    193      1.1  christos     }
    194      1.1  christos 
    195  1.1.1.7  christos    sprintf (p, "%s%s", register_prefix, spr);
    196  1.1.1.7  christos    return p;
    197      1.1  christos }
    198      1.1  christos 
    199      1.1  christos static unsigned long
    200      1.1  christos read_insn_microblaze (bfd_vma memaddr,
    201      1.1  christos 		      struct disassemble_info *info,
    202  1.1.1.8  christos 		      const struct op_code_struct **opr)
    203      1.1  christos {
    204      1.1  christos   unsigned char       ibytes[4];
    205      1.1  christos   int                 status;
    206  1.1.1.8  christos   const struct op_code_struct *op;
    207      1.1  christos   unsigned long inst;
    208      1.1  christos 
    209      1.1  christos   status = info->read_memory_func (memaddr, ibytes, 4, info);
    210      1.1  christos 
    211      1.1  christos   if (status != 0)
    212      1.1  christos     {
    213      1.1  christos       info->memory_error_func (status, memaddr, info);
    214      1.1  christos       return 0;
    215      1.1  christos     }
    216      1.1  christos 
    217      1.1  christos   if (info->endian == BFD_ENDIAN_BIG)
    218  1.1.1.7  christos     inst = (((unsigned) ibytes[0] << 24) | (ibytes[1] << 16)
    219  1.1.1.7  christos 	    | (ibytes[2] << 8) | ibytes[3]);
    220      1.1  christos   else if (info->endian == BFD_ENDIAN_LITTLE)
    221  1.1.1.7  christos     inst = (((unsigned) ibytes[3] << 24) | (ibytes[2] << 16)
    222  1.1.1.7  christos 	    | (ibytes[1] << 8) | ibytes[0]);
    223      1.1  christos   else
    224      1.1  christos     abort ();
    225      1.1  christos 
    226      1.1  christos   /* Just a linear search of the table.  */
    227  1.1.1.8  christos   for (op = microblaze_opcodes; op->name != 0; op ++)
    228      1.1  christos     if (op->bit_sequence == (inst & op->opcode_mask))
    229      1.1  christos       break;
    230      1.1  christos 
    231      1.1  christos   *opr = op;
    232      1.1  christos   return inst;
    233      1.1  christos }
    234      1.1  christos 
    235      1.1  christos 
    236      1.1  christos int
    237      1.1  christos print_insn_microblaze (bfd_vma memaddr, struct disassemble_info * info)
    238      1.1  christos {
    239  1.1.1.8  christos   fprintf_ftype print_func = info->fprintf_func;
    240  1.1.1.8  christos   void *stream = info->stream;
    241  1.1.1.8  christos   unsigned long inst, prev_inst;
    242  1.1.1.8  christos   const struct op_code_struct *op, *pop;
    243  1.1.1.8  christos   int immval = 0;
    244  1.1.1.8  christos   bool immfound = false;
    245  1.1.1.8  christos   static bfd_vma prev_insn_addr = -1;	/* Init the prev insn addr.  */
    246  1.1.1.8  christos   static int prev_insn_vma = -1;	/* Init the prev insn vma.  */
    247  1.1.1.8  christos   int curr_insn_vma = info->buffer_vma;
    248  1.1.1.8  christos   struct string_buf buf;
    249      1.1  christos 
    250  1.1.1.7  christos   buf.which = 0;
    251      1.1  christos   info->bytes_per_chunk = 4;
    252      1.1  christos 
    253      1.1  christos   inst = read_insn_microblaze (memaddr, info, &op);
    254      1.1  christos   if (inst == 0)
    255      1.1  christos     return -1;
    256      1.1  christos 
    257      1.1  christos   if (prev_insn_vma == curr_insn_vma)
    258      1.1  christos     {
    259      1.1  christos       if (memaddr-(info->bytes_per_chunk) == prev_insn_addr)
    260  1.1.1.7  christos 	{
    261  1.1.1.7  christos 	  prev_inst = read_insn_microblaze (prev_insn_addr, info, &pop);
    262      1.1  christos 	  if (prev_inst == 0)
    263      1.1  christos 	    return -1;
    264      1.1  christos 	  if (pop->instr == imm)
    265      1.1  christos 	    {
    266      1.1  christos 	      immval = (get_int_field_imm (prev_inst) << 16) & 0xffff0000;
    267  1.1.1.8  christos 	      immfound = true;
    268      1.1  christos 	    }
    269      1.1  christos 	  else
    270      1.1  christos 	    {
    271      1.1  christos 	      immval = 0;
    272  1.1.1.8  christos 	      immfound = false;
    273      1.1  christos 	    }
    274      1.1  christos 	}
    275      1.1  christos     }
    276      1.1  christos 
    277      1.1  christos   /* Make curr insn as prev insn.  */
    278      1.1  christos   prev_insn_addr = memaddr;
    279      1.1  christos   prev_insn_vma = curr_insn_vma;
    280      1.1  christos 
    281      1.1  christos   if (op->name == NULL)
    282  1.1.1.9  christos     print_func (stream, ".long 0x%04x", (unsigned int) inst);
    283      1.1  christos   else
    284      1.1  christos     {
    285      1.1  christos       print_func (stream, "%s", op->name);
    286      1.1  christos 
    287      1.1  christos       switch (op->inst_type)
    288      1.1  christos 	{
    289  1.1.1.7  christos 	case INST_TYPE_RD_R1_R2:
    290  1.1.1.7  christos 	  print_func (stream, "\t%s, %s, %s", get_field_rd (&buf, inst),
    291  1.1.1.7  christos 		      get_field_r1 (&buf, inst), get_field_r2 (&buf, inst));
    292  1.1.1.7  christos 	  break;
    293  1.1.1.7  christos 	case INST_TYPE_RD_R1_IMM:
    294  1.1.1.7  christos 	  print_func (stream, "\t%s, %s, %s", get_field_rd (&buf, inst),
    295  1.1.1.7  christos 		      get_field_r1 (&buf, inst), get_field_imm (&buf, inst));
    296      1.1  christos 	  if (info->print_address_func && get_int_field_r1 (inst) == 0
    297      1.1  christos 	      && info->symbol_at_address_func)
    298      1.1  christos 	    {
    299      1.1  christos 	      if (immfound)
    300  1.1.1.7  christos 		immval |= (get_int_field_imm (inst) & 0x0000ffff);
    301      1.1  christos 	      else
    302      1.1  christos 		{
    303  1.1.1.7  christos 		  immval = get_int_field_imm (inst);
    304  1.1.1.7  christos 		  if (immval & 0x8000)
    305      1.1  christos 		    immval |= 0xFFFF0000;
    306  1.1.1.7  christos 		}
    307      1.1  christos 	      if (immval > 0 && info->symbol_at_address_func (immval, info))
    308      1.1  christos 		{
    309  1.1.1.7  christos 		  print_func (stream, "\t// ");
    310  1.1.1.7  christos 		  info->print_address_func (immval, info);
    311  1.1.1.7  christos 		}
    312      1.1  christos 	    }
    313      1.1  christos 	  break;
    314      1.1  christos 	case INST_TYPE_RD_R1_IMM5:
    315  1.1.1.7  christos 	  print_func (stream, "\t%s, %s, %s", get_field_rd (&buf, inst),
    316  1.1.1.7  christos 		      get_field_r1 (&buf, inst), get_field_imm5 (&buf, inst));
    317      1.1  christos 	  break;
    318      1.1  christos 	case INST_TYPE_RD_RFSL:
    319  1.1.1.7  christos 	  print_func (stream, "\t%s, %s", get_field_rd (&buf, inst),
    320  1.1.1.7  christos 		      get_field_rfsl (&buf, inst));
    321      1.1  christos 	  break;
    322      1.1  christos 	case INST_TYPE_R1_RFSL:
    323  1.1.1.7  christos 	  print_func (stream, "\t%s, %s", get_field_r1 (&buf, inst),
    324  1.1.1.7  christos 		      get_field_rfsl (&buf, inst));
    325      1.1  christos 	  break;
    326      1.1  christos 	case INST_TYPE_RD_SPECIAL:
    327  1.1.1.7  christos 	  print_func (stream, "\t%s, %s", get_field_rd (&buf, inst),
    328  1.1.1.7  christos 		      get_field_special (&buf, inst, op));
    329      1.1  christos 	  break;
    330      1.1  christos 	case INST_TYPE_SPECIAL_R1:
    331  1.1.1.7  christos 	  print_func (stream, "\t%s, %s", get_field_special (&buf, inst, op),
    332  1.1.1.7  christos 		      get_field_r1 (&buf, inst));
    333      1.1  christos 	  break;
    334      1.1  christos 	case INST_TYPE_RD_R1:
    335  1.1.1.7  christos 	  print_func (stream, "\t%s, %s", get_field_rd (&buf, inst),
    336  1.1.1.7  christos 		      get_field_r1 (&buf, inst));
    337      1.1  christos 	  break;
    338      1.1  christos 	case INST_TYPE_R1_R2:
    339  1.1.1.7  christos 	  print_func (stream, "\t%s, %s", get_field_r1 (&buf, inst),
    340  1.1.1.7  christos 		      get_field_r2 (&buf, inst));
    341      1.1  christos 	  break;
    342      1.1  christos 	case INST_TYPE_R1_IMM:
    343  1.1.1.7  christos 	  print_func (stream, "\t%s, %s", get_field_r1 (&buf, inst),
    344  1.1.1.7  christos 		      get_field_imm (&buf, inst));
    345      1.1  christos 	  /* The non-pc relative instructions are returns, which shouldn't
    346      1.1  christos 	     have a label printed.  */
    347      1.1  christos 	  if (info->print_address_func && op->inst_offset_type == INST_PC_OFFSET
    348      1.1  christos 	      && info->symbol_at_address_func)
    349      1.1  christos 	    {
    350      1.1  christos 	      if (immfound)
    351  1.1.1.7  christos 		immval |= (get_int_field_imm (inst) & 0x0000ffff);
    352      1.1  christos 	      else
    353      1.1  christos 		{
    354  1.1.1.7  christos 		  immval = get_int_field_imm (inst);
    355  1.1.1.7  christos 		  if (immval & 0x8000)
    356      1.1  christos 		    immval |= 0xFFFF0000;
    357  1.1.1.7  christos 		}
    358      1.1  christos 	      immval += memaddr;
    359      1.1  christos 	      if (immval > 0 && info->symbol_at_address_func (immval, info))
    360      1.1  christos 		{
    361  1.1.1.7  christos 		  print_func (stream, "\t// ");
    362  1.1.1.7  christos 		  info->print_address_func (immval, info);
    363  1.1.1.7  christos 		}
    364      1.1  christos 	      else
    365      1.1  christos 		{
    366  1.1.1.7  christos 		  print_func (stream, "\t\t// ");
    367  1.1.1.7  christos 		  print_func (stream, "%x", immval);
    368  1.1.1.7  christos 		}
    369      1.1  christos 	    }
    370      1.1  christos 	  break;
    371  1.1.1.7  christos 	case INST_TYPE_RD_IMM:
    372  1.1.1.7  christos 	  print_func (stream, "\t%s, %s", get_field_rd (&buf, inst),
    373  1.1.1.7  christos 		      get_field_imm (&buf, inst));
    374      1.1  christos 	  if (info->print_address_func && info->symbol_at_address_func)
    375      1.1  christos 	    {
    376  1.1.1.7  christos 	      if (immfound)
    377  1.1.1.7  christos 		immval |= (get_int_field_imm (inst) & 0x0000ffff);
    378  1.1.1.7  christos 	      else
    379  1.1.1.7  christos 		{
    380  1.1.1.7  christos 		  immval = get_int_field_imm (inst);
    381  1.1.1.7  christos 		  if (immval & 0x8000)
    382  1.1.1.7  christos 		    immval |= 0xFFFF0000;
    383  1.1.1.7  christos 		}
    384  1.1.1.7  christos 	      if (op->inst_offset_type == INST_PC_OFFSET)
    385  1.1.1.7  christos 		immval += (int) memaddr;
    386  1.1.1.7  christos 	      if (info->symbol_at_address_func (immval, info))
    387  1.1.1.7  christos 		{
    388  1.1.1.7  christos 		  print_func (stream, "\t// ");
    389  1.1.1.7  christos 		  info->print_address_func (immval, info);
    390  1.1.1.7  christos 		}
    391      1.1  christos 	    }
    392      1.1  christos 	  break;
    393  1.1.1.7  christos 	case INST_TYPE_IMM:
    394  1.1.1.7  christos 	  print_func (stream, "\t%s", get_field_imm (&buf, inst));
    395      1.1  christos 	  if (info->print_address_func && info->symbol_at_address_func
    396      1.1  christos 	      && op->instr != imm)
    397      1.1  christos 	    {
    398      1.1  christos 	      if (immfound)
    399  1.1.1.7  christos 		immval |= (get_int_field_imm (inst) & 0x0000ffff);
    400      1.1  christos 	      else
    401      1.1  christos 		{
    402  1.1.1.7  christos 		  immval = get_int_field_imm (inst);
    403  1.1.1.7  christos 		  if (immval & 0x8000)
    404      1.1  christos 		    immval |= 0xFFFF0000;
    405  1.1.1.7  christos 		}
    406      1.1  christos 	      if (op->inst_offset_type == INST_PC_OFFSET)
    407  1.1.1.7  christos 		immval += (int) memaddr;
    408      1.1  christos 	      if (immval > 0 && info->symbol_at_address_func (immval, info))
    409      1.1  christos 		{
    410  1.1.1.7  christos 		  print_func (stream, "\t// ");
    411  1.1.1.7  christos 		  info->print_address_func (immval, info);
    412  1.1.1.7  christos 		}
    413      1.1  christos 	      else if (op->inst_offset_type == INST_PC_OFFSET)
    414      1.1  christos 		{
    415  1.1.1.7  christos 		  print_func (stream, "\t\t// ");
    416  1.1.1.7  christos 		  print_func (stream, "%x", immval);
    417  1.1.1.7  christos 		}
    418      1.1  christos 	    }
    419      1.1  christos 	  break;
    420  1.1.1.7  christos 	case INST_TYPE_RD_R2:
    421  1.1.1.7  christos 	  print_func (stream, "\t%s, %s", get_field_rd (&buf, inst),
    422  1.1.1.7  christos 		      get_field_r2 (&buf, inst));
    423      1.1  christos 	  break;
    424      1.1  christos 	case INST_TYPE_R2:
    425  1.1.1.7  christos 	  print_func (stream, "\t%s", get_field_r2 (&buf, inst));
    426      1.1  christos 	  break;
    427      1.1  christos 	case INST_TYPE_R1:
    428  1.1.1.7  christos 	  print_func (stream, "\t%s", get_field_r1 (&buf, inst));
    429      1.1  christos 	  break;
    430  1.1.1.2  christos 	case INST_TYPE_R1_R2_SPECIAL:
    431  1.1.1.7  christos 	  print_func (stream, "\t%s, %s", get_field_r1 (&buf, inst),
    432  1.1.1.7  christos 		      get_field_r2 (&buf, inst));
    433      1.1  christos 	  break;
    434      1.1  christos 	case INST_TYPE_RD_IMM15:
    435  1.1.1.7  christos 	  print_func (stream, "\t%s, %s", get_field_rd (&buf, inst),
    436  1.1.1.7  christos 		      get_field_imm15 (&buf, inst));
    437      1.1  christos 	  break;
    438  1.1.1.7  christos 	  /* For mbar insn.  */
    439  1.1.1.7  christos 	case INST_TYPE_IMM5:
    440  1.1.1.7  christos 	  print_func (stream, "\t%s", get_field_imm5_mbar (&buf, inst));
    441  1.1.1.7  christos 	  break;
    442  1.1.1.7  christos 	  /* For mbar 16 or sleep insn.  */
    443  1.1.1.7  christos 	case INST_TYPE_NONE:
    444  1.1.1.7  christos 	  break;
    445  1.1.1.9  christos 	  /* For bit field insns.  */
    446  1.1.1.9  christos 	case INST_TYPE_RD_R1_IMMW_IMMS:
    447  1.1.1.9  christos 	  print_func (stream, "\t%s, %s, %s, %s",
    448  1.1.1.9  christos 		      get_field_rd (&buf, inst),
    449  1.1.1.9  christos 		      get_field_r1 (&buf, inst),
    450  1.1.1.9  christos 		      get_field_immw (&buf, inst),
    451  1.1.1.9  christos 		      get_field_imm5 (&buf, inst));
    452  1.1.1.9  christos 	  break;
    453  1.1.1.7  christos 	  /* For tuqula instruction */
    454      1.1  christos 	case INST_TYPE_RD:
    455  1.1.1.7  christos 	  print_func (stream, "\t%s", get_field_rd (&buf, inst));
    456      1.1  christos 	  break;
    457      1.1  christos 	case INST_TYPE_RFSL:
    458  1.1.1.7  christos 	  print_func (stream, "\t%s", get_field_rfsl (&buf, inst));
    459      1.1  christos 	  break;
    460      1.1  christos 	default:
    461      1.1  christos 	  /* If the disassembler lags the instruction set.  */
    462  1.1.1.7  christos 	  print_func (stream, "\tundecoded operands, inst is 0x%04x",
    463  1.1.1.7  christos 		      (unsigned int) inst);
    464      1.1  christos 	  break;
    465      1.1  christos 	}
    466      1.1  christos     }
    467      1.1  christos 
    468      1.1  christos   /* Say how many bytes we consumed.  */
    469      1.1  christos   return 4;
    470      1.1  christos }
    471      1.1  christos 
    472      1.1  christos enum microblaze_instr
    473      1.1  christos get_insn_microblaze (long inst,
    474  1.1.1.8  christos   		     bool *isunsignedimm,
    475      1.1  christos   		     enum microblaze_instr_type *insn_type,
    476      1.1  christos   		     short *delay_slots)
    477      1.1  christos {
    478  1.1.1.8  christos   const struct op_code_struct *op;
    479  1.1.1.8  christos   *isunsignedimm = false;
    480      1.1  christos 
    481      1.1  christos   /* Just a linear search of the table.  */
    482  1.1.1.8  christos   for (op = microblaze_opcodes; op->name != 0; op ++)
    483      1.1  christos     if (op->bit_sequence == (inst & op->opcode_mask))
    484      1.1  christos       break;
    485      1.1  christos 
    486      1.1  christos   if (op->name == 0)
    487      1.1  christos     return invalid_inst;
    488      1.1  christos   else
    489      1.1  christos     {
    490      1.1  christos       *isunsignedimm = (op->inst_type == INST_TYPE_RD_R1_UNSIGNED_IMM);
    491      1.1  christos       *insn_type = op->instr_type;
    492      1.1  christos       *delay_slots = op->delay_slots;
    493      1.1  christos       return op->instr;
    494      1.1  christos     }
    495      1.1  christos }
    496      1.1  christos 
    497      1.1  christos enum microblaze_instr
    498      1.1  christos microblaze_decode_insn (long insn, int *rd, int *ra, int *rb, int *immed)
    499      1.1  christos {
    500      1.1  christos   enum microblaze_instr op;
    501  1.1.1.8  christos   bool t1;
    502      1.1  christos   enum microblaze_instr_type t2;
    503      1.1  christos   short t3;
    504      1.1  christos 
    505      1.1  christos   op = get_insn_microblaze (insn, &t1, &t2, &t3);
    506      1.1  christos   *rd = (insn & RD_MASK) >> RD_LOW;
    507      1.1  christos   *ra = (insn & RA_MASK) >> RA_LOW;
    508      1.1  christos   *rb = (insn & RB_MASK) >> RB_LOW;
    509      1.1  christos   t3 = (insn & IMM_MASK) >> IMM_LOW;
    510      1.1  christos   *immed = (int) t3;
    511      1.1  christos   return (op);
    512      1.1  christos }
    513      1.1  christos 
    514      1.1  christos unsigned long
    515  1.1.1.8  christos microblaze_get_target_address (long inst, bool immfound, int immval,
    516      1.1  christos 			       long pcval, long r1val, long r2val,
    517  1.1.1.8  christos 			       bool *targetvalid,
    518  1.1.1.8  christos 			       bool *unconditionalbranch)
    519      1.1  christos {
    520  1.1.1.8  christos   const struct op_code_struct *op;
    521      1.1  christos   long targetaddr = 0;
    522      1.1  christos 
    523  1.1.1.8  christos   *unconditionalbranch = false;
    524      1.1  christos   /* Just a linear search of the table.  */
    525  1.1.1.8  christos   for (op = microblaze_opcodes; op->name != 0; op ++)
    526      1.1  christos     if (op->bit_sequence == (inst & op->opcode_mask))
    527      1.1  christos       break;
    528      1.1  christos 
    529      1.1  christos   if (op->name == 0)
    530      1.1  christos     {
    531  1.1.1.8  christos       *targetvalid = false;
    532      1.1  christos     }
    533      1.1  christos   else if (op->instr_type == branch_inst)
    534      1.1  christos     {
    535      1.1  christos       switch (op->inst_type)
    536      1.1  christos 	{
    537      1.1  christos         case INST_TYPE_R2:
    538  1.1.1.8  christos           *unconditionalbranch = true;
    539      1.1  christos         /* Fall through.  */
    540      1.1  christos         case INST_TYPE_RD_R2:
    541      1.1  christos         case INST_TYPE_R1_R2:
    542      1.1  christos           targetaddr = r2val;
    543  1.1.1.8  christos           *targetvalid = true;
    544      1.1  christos           if (op->inst_offset_type == INST_PC_OFFSET)
    545      1.1  christos 	    targetaddr += pcval;
    546      1.1  christos           break;
    547      1.1  christos         case INST_TYPE_IMM:
    548  1.1.1.8  christos           *unconditionalbranch = true;
    549      1.1  christos         /* Fall through.  */
    550      1.1  christos         case INST_TYPE_RD_IMM:
    551      1.1  christos         case INST_TYPE_R1_IMM:
    552      1.1  christos           if (immfound)
    553      1.1  christos 	    {
    554      1.1  christos 	      targetaddr = (immval << 16) & 0xffff0000;
    555      1.1  christos 	      targetaddr |= (get_int_field_imm (inst) & 0x0000ffff);
    556      1.1  christos 	    }
    557      1.1  christos 	  else
    558      1.1  christos 	    {
    559      1.1  christos 	      targetaddr = get_int_field_imm (inst);
    560      1.1  christos 	      if (targetaddr & 0x8000)
    561      1.1  christos 	        targetaddr |= 0xFFFF0000;
    562      1.1  christos             }
    563      1.1  christos           if (op->inst_offset_type == INST_PC_OFFSET)
    564      1.1  christos 	    targetaddr += pcval;
    565  1.1.1.8  christos           *targetvalid = true;
    566      1.1  christos           break;
    567      1.1  christos 	default:
    568  1.1.1.8  christos 	  *targetvalid = false;
    569      1.1  christos 	  break;
    570      1.1  christos         }
    571      1.1  christos     }
    572      1.1  christos   else if (op->instr_type == return_inst)
    573      1.1  christos     {
    574      1.1  christos       if (immfound)
    575      1.1  christos 	{
    576      1.1  christos 	  targetaddr = (immval << 16) & 0xffff0000;
    577      1.1  christos 	  targetaddr |= (get_int_field_imm (inst) & 0x0000ffff);
    578      1.1  christos 	}
    579      1.1  christos       else
    580      1.1  christos 	{
    581      1.1  christos 	  targetaddr = get_int_field_imm (inst);
    582      1.1  christos 	  if (targetaddr & 0x8000)
    583      1.1  christos 	    targetaddr |= 0xFFFF0000;
    584      1.1  christos 	}
    585      1.1  christos       targetaddr += r1val;
    586  1.1.1.8  christos       *targetvalid = true;
    587      1.1  christos     }
    588      1.1  christos   else
    589  1.1.1.8  christos     *targetvalid = false;
    590      1.1  christos   return targetaddr;
    591      1.1  christos }
    592