Back to index

cell-binutils  2.17cvs20070401
v850-dis.c
Go to the documentation of this file.
00001 /* Disassemble V850 instructions.
00002    Copyright 1996, 1997, 1998, 2000, 2001, 2002, 2003, 2005
00003    Free Software Foundation, Inc.
00004 
00005    This program is free software; you can redistribute it and/or modify
00006    it under the terms of the GNU General Public License as published by
00007    the Free Software Foundation; either version 2 of the License, or
00008    (at your option) any later version.
00009 
00010    This program is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013    GNU General Public License for more details.
00014 
00015    You should have received a copy of the GNU General Public License
00016    along with this program; if not, write to the Free Software
00017    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
00018    MA 02110-1301, USA.  */
00019 
00020 
00021 #include <stdio.h>
00022 
00023 #include "sysdep.h"
00024 #include "opcode/v850.h"
00025 #include "dis-asm.h"
00026 #include "opintl.h"
00027 
00028 static const char *const v850_reg_names[] =
00029 { "r0", "r1", "r2", "sp", "gp", "r5", "r6", "r7",
00030   "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
00031   "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
00032   "r24", "r25", "r26", "r27", "r28", "r29", "ep", "lp" };
00033 
00034 static const char *const v850_sreg_names[] =
00035 { "eipc", "eipsw", "fepc", "fepsw", "ecr", "psw", "sr6", "sr7",
00036   "sr8", "sr9", "sr10", "sr11", "sr12", "sr13", "sr14", "sr15",
00037   "ctpc", "ctpsw", "dbpc", "dbpsw", "ctbp", "sr21", "sr22", "sr23",
00038   "sr24", "sr25", "sr26", "sr27", "sr28", "sr29", "sr30", "sr31",
00039   "sr16", "sr17", "sr18", "sr19", "sr20", "sr21", "sr22", "sr23",
00040   "sr24", "sr25", "sr26", "sr27", "sr28", "sr29", "sr30", "sr31" };
00041 
00042 static const char *const v850_cc_names[] =
00043 { "v", "c/l", "z", "nh", "s/n", "t", "lt", "le",
00044   "nv", "nc/nl", "nz", "h", "ns/p", "sa", "ge", "gt" };
00045 
00046 static int
00047 disassemble (bfd_vma memaddr,
00048             struct disassemble_info * info,
00049             unsigned long insn)
00050 {
00051   struct v850_opcode * op = (struct v850_opcode *) v850_opcodes;
00052   const struct v850_operand * operand;
00053   int match = 0;
00054   int short_op = ((insn & 0x0600) != 0x0600);
00055   int bytes_read;
00056   int target_processor;
00057 
00058   /* Special case: 32 bit MOV.  */
00059   if ((insn & 0xffe0) == 0x0620)
00060     short_op = 1;
00061 
00062   bytes_read = short_op ? 2 : 4;
00063 
00064   /* If this is a two byte insn, then mask off the high bits.  */
00065   if (short_op)
00066     insn &= 0xffff;
00067 
00068   switch (info->mach)
00069     {
00070     case 0:
00071     default:
00072       target_processor = PROCESSOR_V850;
00073       break;
00074 
00075     case bfd_mach_v850e:
00076       target_processor = PROCESSOR_V850E;
00077       break;
00078 
00079     case bfd_mach_v850e1:
00080       target_processor = PROCESSOR_V850E1;
00081       break;
00082     }
00083 
00084   /* Find the opcode.  */
00085   while (op->name)
00086     {
00087       if ((op->mask & insn) == op->opcode
00088          && (op->processors & target_processor))
00089        {
00090          const unsigned char *opindex_ptr;
00091          unsigned int opnum;
00092          unsigned int memop;
00093 
00094          match = 1;
00095          (*info->fprintf_func) (info->stream, "%s\t", op->name);
00096 
00097          memop = op->memop;
00098          /* Now print the operands.
00099 
00100             MEMOP is the operand number at which a memory
00101             address specification starts, or zero if this
00102             instruction has no memory addresses.
00103 
00104             A memory address is always two arguments.
00105 
00106             This information allows us to determine when to
00107             insert commas into the output stream as well as
00108             when to insert disp[reg] expressions onto the
00109             output stream.  */
00110 
00111          for (opindex_ptr = op->operands, opnum = 1;
00112               *opindex_ptr != 0;
00113               opindex_ptr++, opnum++)
00114            {
00115              long value;
00116              int flag;
00117              int status;
00118              bfd_byte buffer[4];
00119 
00120              operand = &v850_operands[*opindex_ptr];
00121 
00122              if (operand->extract)
00123               value = (operand->extract) (insn, 0);
00124              else
00125               {
00126                 if (operand->bits == -1)
00127                   value = (insn & operand->shift);
00128                 else
00129                   value = (insn >> operand->shift) & ((1 << operand->bits) - 1);
00130 
00131                 if (operand->flags & V850_OPERAND_SIGNED)
00132                   value = ((long)(value << (32 - operand->bits))
00133                           >> (32 - operand->bits));
00134               }
00135 
00136              /* The first operand is always output without any
00137                special handling.
00138 
00139                For the following arguments:
00140 
00141                  If memop && opnum == memop + 1, then we need '[' since
00142                  we're about to output the register used in a memory
00143                  reference.
00144 
00145                  If memop && opnum == memop + 2, then we need ']' since
00146                  we just finished the register in a memory reference.  We
00147                  also need a ',' before this operand.
00148 
00149                  Else we just need a comma.
00150 
00151                  We may need to output a trailing ']' if the last operand
00152                  in an instruction is the register for a memory address.
00153 
00154                  The exception (and there's always an exception) is the
00155                  "jmp" insn which needs square brackets around it's only
00156                  register argument.  */
00157 
00158                   if (memop && opnum == memop + 1)
00159                    info->fprintf_func (info->stream, "[");
00160                  else if (memop && opnum == memop + 2)
00161                    info->fprintf_func (info->stream, "],");
00162                  else if (memop == 1 && opnum == 1
00163                          && (operand->flags & V850_OPERAND_REG))
00164                    info->fprintf_func (info->stream, "[");
00165                  else if (opnum > 1)
00166                    info->fprintf_func (info->stream, ", ");
00167 
00168              /* Extract the flags, ignorng ones which
00169                do not effect disassembly output. */
00170              flag = operand->flags;
00171              flag &= ~ V850_OPERAND_SIGNED;
00172              flag &= ~ V850_OPERAND_RELAX;
00173              flag &= - flag;
00174 
00175              switch (flag)
00176               {
00177               case V850_OPERAND_REG:
00178                 info->fprintf_func (info->stream, "%s", v850_reg_names[value]);
00179                 break;
00180               case V850_OPERAND_SRG:
00181                 info->fprintf_func (info->stream, "%s", v850_sreg_names[value]);
00182                 break;
00183               case V850_OPERAND_CC:
00184                 info->fprintf_func (info->stream, "%s", v850_cc_names[value]);
00185                 break;
00186               case V850_OPERAND_EP:
00187                 info->fprintf_func (info->stream, "ep");
00188                 break;
00189               default:
00190                 info->fprintf_func (info->stream, "%ld", value);
00191                 break;
00192               case V850_OPERAND_DISP:
00193                 {
00194                   bfd_vma addr = value + memaddr;
00195 
00196                   /* On the v850 the top 8 bits of an address are used by an
00197                      overlay manager.  Thus it may happen that when we are
00198                      looking for a symbol to match against an address with
00199                      some of its top bits set, the search fails to turn up an
00200                      exact match.  In this case we try to find an exact match
00201                      against a symbol in the lower address space, and if we
00202                      find one, we use that address.   We only do this for
00203                      JARL instructions however, as we do not want to
00204                      misinterpret branch instructions.  */
00205                   if (operand->bits == 22)
00206                     {
00207                      if ( ! info->symbol_at_address_func (addr, info)
00208                          && ((addr & 0xFF000000) != 0)
00209                          && info->symbol_at_address_func (addr & 0x00FFFFFF, info))
00210                        addr &= 0x00FFFFFF;
00211                     }
00212                   info->print_address_func (addr, info);
00213                   break;
00214                 }
00215 
00216               case V850E_PUSH_POP:
00217                 {
00218                   static int list12_regs[32]   = { 30,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0, 31, 29, 28, 23, 22, 21, 20, 27, 26, 25, 24 };
00219                   static int list18_h_regs[32] = { 19, 18, 17, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 30, 31, 29, 28, 23, 22, 21, 20, 27, 26, 25, 24 };
00220                   static int list18_l_regs[32] = {  3,  2,  1, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 14, 15, 13, 12,  7,  6,  5,  4, 11, 10,  9,  8 };
00221                   int *regs;
00222                   int i;
00223                   unsigned long int mask = 0;
00224                   int pc = 0;
00225                   int sr = 0;
00226 
00227                   switch (operand->shift)
00228                     {
00229                     case 0xffe00001: regs = list12_regs; break;
00230                     case 0xfff8000f: regs = list18_h_regs; break;
00231                     case 0xfff8001f:
00232                      regs = list18_l_regs;
00233                      value &= ~0x10;  /* Do not include magic bit.  */
00234                        break;
00235                     default:
00236                      /* xgettext:c-format */
00237                      fprintf (stderr, _("unknown operand shift: %x\n"),
00238                              operand->shift);
00239                      abort ();
00240                     }
00241 
00242                   for (i = 0; i < 32; i++)
00243                     {
00244                      if (value & (1 << i))
00245                        {
00246                          switch (regs[ i ])
00247                            {
00248                            default: mask |= (1 << regs[ i ]); break;
00249                             /* xgettext:c-format */
00250                            case 0:
00251                             fprintf (stderr, _("unknown pop reg: %d\n"), i );
00252                             abort ();
00253                            case -1: pc = 1; break;
00254                            case -2: sr = 1; break;
00255                            }
00256                        }
00257                     }
00258 
00259                   info->fprintf_func (info->stream, "{");
00260 
00261                   if (mask || pc || sr)
00262                     {
00263                      if (mask)
00264                        {
00265                          unsigned int bit;
00266                          int shown_one = 0;
00267 
00268                          for (bit = 0; bit < 32; bit++)
00269                            if (mask & (1 << bit))
00270                             {
00271                               unsigned long int first = bit;
00272                               unsigned long int last;
00273 
00274                               if (shown_one)
00275                                 info->fprintf_func (info->stream, ", ");
00276                               else
00277                                 shown_one = 1;
00278 
00279                               info->fprintf_func (info->stream,
00280                                                 v850_reg_names[first]);
00281 
00282                               for (bit++; bit < 32; bit++)
00283                                 if ((mask & (1 << bit)) == 0)
00284                                   break;
00285 
00286                               last = bit;
00287 
00288                               if (last > first + 1)
00289                                 info->fprintf_func (info->stream, " - %s",
00290                                                  v850_reg_names[last - 1]);
00291                             }
00292                        }
00293 
00294                      if (pc)
00295                        info->fprintf_func (info->stream, "%sPC", mask ? ", " : "");
00296                      if (sr)
00297                        info->fprintf_func (info->stream, "%sSR", (mask || pc) ? ", " : "");
00298                     }
00299 
00300                   info->fprintf_func (info->stream, "}");
00301                 }
00302               break;
00303 
00304               case V850E_IMMEDIATE16:
00305                 status = info->read_memory_func (memaddr + bytes_read,
00306                                              buffer, 2, info);
00307                 if (status == 0)
00308                   {
00309                     bytes_read += 2;
00310                     value = bfd_getl16 (buffer);
00311 
00312                     /* If this is a DISPOSE instruction with ff
00313                       set to 0x10, then shift value up by 16.  */
00314                     if ((insn & 0x001fffc0) == 0x00130780)
00315                      value <<= 16;
00316 
00317                     info->fprintf_func (info->stream, "0x%lx", value);
00318                   }
00319                 else
00320                   info->memory_error_func (status, memaddr + bytes_read,
00321                                         info);
00322                 break;
00323 
00324               case V850E_IMMEDIATE32:
00325                 status = info->read_memory_func (memaddr + bytes_read,
00326                                              buffer, 4, info);
00327                 if (status == 0)
00328                   {
00329                     bytes_read += 4;
00330                     value = bfd_getl32 (buffer);
00331                     info->fprintf_func (info->stream, "0x%lx", value);
00332                   }
00333                 else
00334                   info->memory_error_func (status, memaddr + bytes_read,
00335                                         info);
00336                 break;
00337               }
00338 
00339              /* Handle jmp correctly.  */
00340              if (memop == 1 && opnum == 1
00341                 && ((operand->flags & V850_OPERAND_REG) != 0))
00342               (*info->fprintf_func) (info->stream, "]");
00343            }
00344 
00345          /* Close any square bracket we left open.  */
00346          if (memop && opnum == memop + 2)
00347            (*info->fprintf_func) (info->stream, "]");
00348 
00349          /* All done. */
00350          break;
00351        }
00352       op++;
00353     }
00354 
00355   if (!match)
00356     {
00357       if (short_op)
00358        info->fprintf_func (info->stream, ".short\t0x%04lx", insn);
00359       else
00360        info->fprintf_func (info->stream, ".long\t0x%08lx", insn);
00361     }
00362 
00363   return bytes_read;
00364 }
00365 
00366 int
00367 print_insn_v850 (bfd_vma memaddr, struct disassemble_info * info)
00368 {
00369   int status;
00370   bfd_byte buffer[4];
00371   unsigned long insn = 0;
00372 
00373   /* First figure out how big the opcode is.  */
00374   status = info->read_memory_func (memaddr, buffer, 2, info);
00375   if (status == 0)
00376     {
00377       insn = bfd_getl16 (buffer);
00378 
00379       if (   (insn & 0x0600) == 0x0600
00380          && (insn & 0xffe0) != 0x0620)
00381        {
00382          /* If this is a 4 byte insn, read 4 bytes of stuff.  */
00383          status = info->read_memory_func (memaddr, buffer, 4, info);
00384 
00385          if (status == 0)
00386            insn = bfd_getl32 (buffer);
00387        }
00388     }
00389 
00390   if (status != 0)
00391     {
00392       info->memory_error_func (status, memaddr, info);
00393       return -1;
00394     }
00395 
00396   /* Make sure we tell our caller how many bytes we consumed.  */
00397   return disassemble (memaddr, info, insn);
00398 }