Back to index

cell-binutils  2.17cvs20070401
tic80-dis.c
Go to the documentation of this file.
00001 /* Print TI TMS320C80 (MVP) instructions
00002    Copyright 1996, 1997, 1998, 2000, 2005 Free Software Foundation, Inc.
00003 
00004    This file is free software; you can redistribute it and/or modify
00005    it under the terms of the GNU General Public License as published by
00006    the Free Software Foundation; either version 2 of the License, or
00007    (at your option) any later version.
00008 
00009    This program is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012    GNU General Public License for more details.
00013 
00014    You should have received a copy of the GNU General Public License
00015    along with this program; if not, write to the Free Software
00016    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
00017    MA 02110-1301, USA.  */
00018 
00019 #include <stdio.h>
00020 
00021 #include "sysdep.h"
00022 #include "opcode/tic80.h"
00023 #include "dis-asm.h"
00024 
00025 static int length;
00026 
00027 /* Print an integer operand.  Try to be somewhat smart about the
00028    format by assuming that small positive or negative integers are
00029    probably loop increment values, structure offsets, or similar
00030    values that are more meaningful printed as signed decimal values.
00031    Larger numbers are probably better printed as hex values.  */
00032 
00033 static void
00034 print_operand_integer (struct disassemble_info *info, long value)
00035 {
00036   if ((value > 9999 || value < -9999))
00037     (*info->fprintf_func) (info->stream, "%#lx", value);
00038   else
00039     (*info->fprintf_func) (info->stream, "%ld", value);
00040 }
00041 
00042 /* FIXME: depends upon sizeof (long) == sizeof (float) and
00043    also upon host floating point format matching target
00044    floating point format.  */
00045 
00046 static void
00047 print_operand_float (struct disassemble_info *info, long value)
00048 {
00049   union { float f; long l; } fval;
00050 
00051   fval.l = value;
00052   (*info->fprintf_func) (info->stream, "%g", fval.f);
00053 }
00054 
00055 static void
00056 print_operand_control_register (struct disassemble_info *info, long value)
00057 {
00058   const char *tmp;
00059 
00060   tmp = tic80_value_to_symbol (value, TIC80_OPERAND_CR);
00061   if (tmp != NULL)
00062     (*info->fprintf_func) (info->stream, "%s", tmp);
00063   else
00064     (*info->fprintf_func) (info->stream, "%#lx", value);
00065 }
00066 
00067 static void
00068 print_operand_condition_code (struct disassemble_info *info, long value)
00069 {
00070   const char *tmp;
00071 
00072   tmp = tic80_value_to_symbol (value, TIC80_OPERAND_CC);
00073   if (tmp != NULL)
00074     (*info->fprintf_func) (info->stream, "%s", tmp);
00075   else
00076     (*info->fprintf_func) (info->stream, "%ld", value);
00077 }
00078 
00079 static void
00080 print_operand_bitnum (struct disassemble_info *info, long value)
00081 {
00082   int bitnum;
00083   const char *tmp;
00084 
00085   bitnum = ~value & 0x1F;
00086   tmp = tic80_value_to_symbol (bitnum, TIC80_OPERAND_BITNUM);
00087   if (tmp != NULL)
00088     (*info->fprintf_func) (info->stream, "%s", tmp);
00089   else
00090     (*info->fprintf_func) (info->stream, "%d", bitnum);
00091 }
00092 
00093 /* Print the operand as directed by the flags.  */
00094 
00095 #define M_SI(insn,op) ((((op)->flags & TIC80_OPERAND_M_SI) != 0) && ((insn) & (1 << 17)))
00096 #define M_LI(insn,op) ((((op)->flags & TIC80_OPERAND_M_LI) != 0) && ((insn) & (1 << 15)))
00097 #define R_SCALED(insn,op) ((((op)->flags & TIC80_OPERAND_SCALED) != 0) && ((insn) & (1 << 11)))
00098 
00099 static void
00100 print_operand (struct disassemble_info *info,
00101               long value,
00102               unsigned long insn,
00103               const struct tic80_operand *operand,
00104               bfd_vma memaddr)
00105 {
00106   if ((operand->flags & TIC80_OPERAND_GPR) != 0)
00107     {
00108       (*info->fprintf_func) (info->stream, "r%ld", value);
00109       if (M_SI (insn, operand) || M_LI (insn, operand))
00110        {
00111          (*info->fprintf_func) (info->stream, ":m");
00112        }
00113     }
00114   else if ((operand->flags & TIC80_OPERAND_FPA) != 0)
00115     (*info->fprintf_func) (info->stream, "a%ld", value);
00116 
00117   else if ((operand->flags & TIC80_OPERAND_PCREL) != 0)
00118     (*info->print_address_func) (memaddr + 4 * value, info);
00119 
00120   else if ((operand->flags & TIC80_OPERAND_BASEREL) != 0)
00121     (*info->print_address_func) (value, info);
00122 
00123   else if ((operand->flags & TIC80_OPERAND_BITNUM) != 0)
00124     print_operand_bitnum (info, value);
00125 
00126   else if ((operand->flags & TIC80_OPERAND_CC) != 0)
00127     print_operand_condition_code (info, value);
00128 
00129   else if ((operand->flags & TIC80_OPERAND_CR) != 0)
00130     print_operand_control_register (info, value);
00131 
00132   else if ((operand->flags & TIC80_OPERAND_FLOAT) != 0)
00133     print_operand_float (info, value);
00134 
00135   else if ((operand->flags & TIC80_OPERAND_BITFIELD))
00136     (*info->fprintf_func) (info->stream, "%#lx", value);
00137 
00138   else
00139     print_operand_integer (info, value);
00140 
00141   /* If this is a scaled operand, then print the modifier.  */
00142   if (R_SCALED (insn, operand))
00143     (*info->fprintf_func) (info->stream, ":s");
00144 }
00145 
00146 /* Get the next 32 bit word from the instruction stream and convert it
00147    into internal format in the unsigned long INSN, for which we are
00148    passed the address.  Return 0 on success, -1 on error.  */
00149 
00150 static int
00151 fill_instruction (struct disassemble_info *info,
00152                 bfd_vma memaddr,
00153                 unsigned long *insnp)
00154 {
00155   bfd_byte buffer[4];
00156   int status;
00157 
00158   /* Get the bits for the next 32 bit word and put in buffer.  */
00159   status = (*info->read_memory_func) (memaddr + length, buffer, 4, info);
00160   if (status != 0)
00161     {
00162       (*info->memory_error_func) (status, memaddr, info);
00163       return -1;
00164     }
00165 
00166   /* Read was successful, so increment count of bytes read and convert
00167      the bits into internal format.  */
00168 
00169   length += 4;
00170   if (info->endian == BFD_ENDIAN_LITTLE)
00171     *insnp = bfd_getl32 (buffer);
00172 
00173   else if (info->endian == BFD_ENDIAN_BIG)
00174     *insnp = bfd_getb32 (buffer);
00175 
00176   else
00177     /* FIXME: Should probably just default to one or the other.  */
00178     abort ();
00179 
00180   return 0;
00181 }
00182 
00183 /* We have chosen an opcode table entry.  */
00184 
00185 static int
00186 print_one_instruction (struct disassemble_info *info,
00187                      bfd_vma memaddr,
00188                      unsigned long insn,
00189                      const struct tic80_opcode *opcode)
00190 {
00191   const struct tic80_operand *operand;
00192   long value;
00193   int status;
00194   const unsigned char *opindex;
00195   int close_paren;
00196 
00197   (*info->fprintf_func) (info->stream, "%-10s", opcode->name);
00198 
00199   for (opindex = opcode->operands; *opindex != 0; opindex++)
00200     {
00201       operand = tic80_operands + *opindex;
00202 
00203       /* Extract the value from the instruction.  */
00204       if (operand->extract)
00205        value = (*operand->extract) (insn, NULL);
00206 
00207       else if (operand->bits == 32)
00208        {
00209          status = fill_instruction (info, memaddr, (unsigned long *) &value);
00210          if (status == -1)
00211            return status;
00212        }
00213       else
00214        {
00215          value = (insn >> operand->shift) & ((1 << operand->bits) - 1);
00216 
00217          if ((operand->flags & TIC80_OPERAND_SIGNED) != 0
00218              && (value & (1 << (operand->bits - 1))) != 0)
00219            value -= 1 << operand->bits;
00220        }
00221 
00222       /* If this operand is enclosed in parenthesis, then print
00223         the open paren, otherwise just print the regular comma
00224         separator, except for the first operand.  */
00225       if ((operand->flags & TIC80_OPERAND_PARENS) == 0)
00226        {
00227          close_paren = 0;
00228          if (opindex != opcode->operands)
00229            (*info->fprintf_func) (info->stream, ",");
00230        }
00231       else
00232        {
00233          close_paren = 1;
00234          (*info->fprintf_func) (info->stream, "(");
00235        }
00236 
00237       print_operand (info, value, insn, operand, memaddr);
00238 
00239       /* If we printed an open paren before printing this operand, close
00240         it now. The flag gets reset on each loop.  */
00241       if (close_paren)
00242        (*info->fprintf_func) (info->stream, ")");
00243     }
00244 
00245   return length;
00246 }
00247 
00248 /* There are no specific bits that tell us for certain whether a vector
00249    instruction opcode contains one or two instructions.  However since
00250    a destination register of r0 is illegal, we can check for nonzero
00251    values in both destination register fields.  Only opcodes that have
00252    two valid instructions will have non-zero in both.  */
00253 
00254 #define TWO_INSN(insn) ((((insn) & (0x1F << 27)) != 0) && (((insn) & (0x1F << 22)) != 0))
00255 
00256 static int
00257 print_instruction (struct disassemble_info *info,
00258                  bfd_vma memaddr,
00259                  unsigned long insn,
00260                  const struct tic80_opcode *vec_opcode)
00261 {
00262   const struct tic80_opcode *opcode;
00263   const struct tic80_opcode *opcode_end;
00264 
00265   /* Find the first opcode match in the opcodes table.  For vector
00266      opcodes (vec_opcode != NULL) find the first match that is not the
00267      previously found match.  FIXME: there should be faster ways to
00268      search (hash table or binary search), but don't worry too much
00269      about it until other TIc80 support is finished.  */
00270 
00271   opcode_end = tic80_opcodes + tic80_num_opcodes;
00272   for (opcode = tic80_opcodes; opcode < opcode_end; opcode++)
00273     {
00274       if ((insn & opcode->mask) == opcode->opcode &&
00275          opcode != vec_opcode)
00276        break;
00277     }
00278 
00279   if (opcode == opcode_end)
00280     {
00281       /* No match found, just print the bits as a .word directive.  */
00282       (*info->fprintf_func) (info->stream, ".word %#08lx", insn);
00283     }
00284   else
00285     {
00286       /* Match found, decode the instruction.  */
00287       length = print_one_instruction (info, memaddr, insn, opcode);
00288       if (opcode->flags & TIC80_VECTOR && vec_opcode == NULL && TWO_INSN (insn))
00289        {
00290          /* There is another instruction to print from the same opcode.
00291             Print the separator and then find and print the other
00292             instruction.  */
00293          (*info->fprintf_func) (info->stream, "   ||   ");
00294          length = print_instruction (info, memaddr, insn, opcode);
00295        }
00296     }
00297 
00298   return length;
00299 }
00300 
00301 int
00302 print_insn_tic80 (bfd_vma memaddr, struct disassemble_info *info)
00303 {
00304   unsigned long insn;
00305   int status;
00306 
00307   length = 0;
00308   info->bytes_per_line = 8;
00309   status = fill_instruction (info, memaddr, &insn);
00310   if (status != -1)
00311     status = print_instruction (info, memaddr, insn, NULL);
00312 
00313   return status;
00314 }