Home | History | Annotate | Download | only in opcodes
      1 /* tilepro-dis.c.  Disassembly routines for the TILEPro architecture.
      2    Copyright (C) 2011-2014 Free Software Foundation, Inc.
      3 
      4    This file is part of the GNU opcodes library.
      5 
      6    This program 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 of the License, or
      9    (at your option) any later version.
     10 
     11    This program is distributed in the hope that it will be useful,
     12    but WITHOUT ANY WARRANTY; without even the implied warranty of
     13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14    GNU General Public 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 <stddef.h>
     23 #include <assert.h>
     24 #include "bfd.h"
     25 #include "elf/tilepro.h"
     26 #include "elf-bfd.h"
     27 #include "dis-asm.h"
     28 #include "opcode/tilepro.h"
     29 
     30 
     31 #define TREG_ZERO 63
     32 
     33 static int
     34 contains_insn (tilepro_mnemonic expected_mnemonic,
     35 	       int expected_first_operand,
     36 	       int expected_second_operand,
     37 	       bfd_vma memaddr,
     38 	       int *last_operand_ret,
     39 	       disassemble_info *info)
     40 {
     41   struct tilepro_decoded_instruction
     42     decoded[TILEPRO_MAX_INSTRUCTIONS_PER_BUNDLE];
     43   bfd_byte opbuf[TILEPRO_BUNDLE_SIZE_IN_BYTES];
     44   int i, num_instructions;
     45 
     46   if ((*info->read_memory_func) (memaddr, opbuf,
     47 				 TILEPRO_BUNDLE_SIZE_IN_BYTES, info) != 0)
     48     /* If we cannot even read the memory, it obviously does not have the
     49        instruction for which we are looking. */
     50     return 0;
     51 
     52   /* Parse the instructions in the bundle. */
     53   num_instructions = parse_insn_tilepro (bfd_getl64 (opbuf), memaddr, decoded);
     54 
     55   for (i = 0; i < num_instructions; i++)
     56     {
     57       const struct tilepro_opcode *opcode = decoded[i].opcode;
     58 
     59       if (opcode->mnemonic != expected_mnemonic)
     60 	continue;
     61 
     62       if (expected_first_operand != -1
     63 	  && decoded[i].operand_values[0] != expected_first_operand)
     64 	continue;
     65 
     66       if (expected_second_operand != -1
     67 	  && decoded[i].operand_values[1] != expected_second_operand)
     68 	continue;
     69 
     70       *last_operand_ret = decoded[i].operand_values[opcode->num_operands - 1];
     71       return 1;
     72     }
     73 
     74   /* No match. */
     75   return 0;
     76 }
     77 
     78 
     79 int
     80 print_insn_tilepro (bfd_vma memaddr, disassemble_info *info)
     81 {
     82   struct tilepro_decoded_instruction
     83     decoded[TILEPRO_MAX_INSTRUCTIONS_PER_BUNDLE];
     84   bfd_byte opbuf[TILEPRO_BUNDLE_SIZE_IN_BYTES];
     85   int status, i, num_instructions, num_printed;
     86   tilepro_mnemonic padding_mnemonic;
     87 
     88   status = (*info->read_memory_func) (memaddr, opbuf,
     89                                       TILEPRO_BUNDLE_SIZE_IN_BYTES, info);
     90   if (status != 0)
     91     {
     92       (*info->memory_error_func) (status, memaddr, info);
     93       return -1;
     94     }
     95 
     96   info->bytes_per_line = TILEPRO_BUNDLE_SIZE_IN_BYTES;
     97   info->bytes_per_chunk = TILEPRO_BUNDLE_SIZE_IN_BYTES;
     98   info->octets_per_byte = 1;
     99   info->display_endian = BFD_ENDIAN_LITTLE;
    100 
    101   /* Parse the instructions in the bundle.  */
    102   num_instructions = parse_insn_tilepro (bfd_getl64 (opbuf), memaddr, decoded);
    103 
    104   /* Print the instructions in the bundle.  */
    105   info->fprintf_func (info->stream, "{ ");
    106   num_printed = 0;
    107 
    108   /* Determine which nop opcode is used for padding and should be skipped.  */
    109   padding_mnemonic = TILEPRO_OPC_FNOP;
    110   for (i = 0; i < num_instructions; i++)
    111     {
    112       if (!decoded[i].opcode->can_bundle)
    113 	{
    114 	  /* Instructions that cannot be bundled are padded out with nops,
    115 	     rather than fnops. Displaying them is always clutter.  */
    116 	  padding_mnemonic = TILEPRO_OPC_NOP;
    117 	  break;
    118 	}
    119     }
    120 
    121   for (i = 0; i < num_instructions; i++)
    122     {
    123       const struct tilepro_opcode *opcode = decoded[i].opcode;
    124       const char *name;
    125       int j;
    126 
    127       /* Do not print out fnops, unless everything is an fnop, in
    128 	 which case we will print out just the last one.  */
    129       if (opcode->mnemonic == padding_mnemonic
    130 	  && (num_printed > 0 || i + 1 < num_instructions))
    131 	continue;
    132 
    133       if (num_printed > 0)
    134 	info->fprintf_func (info->stream, " ; ");
    135       ++num_printed;
    136 
    137       name = opcode->name;
    138       if (name == NULL)
    139 	name = "<invalid>";
    140       info->fprintf_func (info->stream, "%s", name);
    141 
    142       for (j = 0; j < opcode->num_operands; j++)
    143 	{
    144 	  int num;
    145 	  const struct tilepro_operand *op;
    146 	  const char *spr_name;
    147 
    148 	  if (j > 0)
    149 	    info->fprintf_func (info->stream, ",");
    150 	  info->fprintf_func (info->stream, " ");
    151 
    152 	  num = decoded[i].operand_values[j];
    153 
    154 	  op = decoded[i].operands[j];
    155 	  switch (op->type)
    156 	    {
    157 	    case TILEPRO_OP_TYPE_REGISTER:
    158 	      info->fprintf_func (info->stream, "%s",
    159 				  tilepro_register_names[num]);
    160 	      break;
    161 
    162 	    case TILEPRO_OP_TYPE_SPR:
    163 	      spr_name = get_tilepro_spr_name(num);
    164 	      if (spr_name != NULL)
    165 		info->fprintf_func (info->stream, "%s", spr_name);
    166 	      else
    167 		info->fprintf_func (info->stream, "%d", num);
    168 	      break;
    169 
    170 	    case TILEPRO_OP_TYPE_IMMEDIATE:
    171 	      {
    172 		bfd_vma addr = 0;
    173 		int found_addr = 0;
    174 		int addr_piece;
    175 
    176 		switch (opcode->mnemonic)
    177 		  {
    178 		  case TILEPRO_OPC_ADDLI:
    179 		    if (contains_insn (TILEPRO_OPC_AULI,
    180 				       decoded[i].operand_values[1],
    181 				       TREG_ZERO,
    182 				       memaddr - TILEPRO_BUNDLE_SIZE_IN_BYTES,
    183 				       &addr_piece,
    184 				       info))
    185 		      {
    186 			addr = num + (addr_piece << 16);
    187 			found_addr = 1;
    188 		      }
    189 		    break;
    190 
    191 		  case TILEPRO_OPC_AULI:
    192 		    if (contains_insn (TILEPRO_OPC_MOVELI,
    193 				       decoded[i].operand_values[1],
    194 				       -1,
    195 				       memaddr - TILEPRO_BUNDLE_SIZE_IN_BYTES,
    196 				       &addr_piece,
    197 				       info))
    198 		      {
    199 			addr = (num << 16) + addr_piece;
    200 			found_addr = 1;
    201 		      }
    202 		    break;
    203 
    204 		  default:
    205 		    /* Operand does not look like a constructed address.  */
    206 		    break;
    207 		  }
    208 
    209 		info->fprintf_func (info->stream, "%d", num);
    210 
    211 		if (found_addr)
    212 		  {
    213 		    info->fprintf_func (info->stream, " /* ");
    214 		    info->print_address_func (addr, info);
    215 		    info->fprintf_func (info->stream, " */");
    216 		  }
    217 	      }
    218 	      break;
    219 
    220 	    case TILEPRO_OP_TYPE_ADDRESS:
    221 	      info->print_address_func ((bfd_vma)(unsigned int) num, info);
    222 	      break;
    223 
    224 	    default:
    225 	      abort ();
    226 	    }
    227 	}
    228     }
    229   info->fprintf_func (info->stream, " }");
    230 
    231   return TILEPRO_BUNDLE_SIZE_IN_BYTES;
    232 }
    233