Back to index

cell-binutils  2.17cvs20070401
score-dis.c
Go to the documentation of this file.
00001 /* Instruction printing code for Score
00002    Copyright 2006 Free Software Foundation, Inc.
00003    Contributed by:
00004    Mei Ligang (ligang@sunnorth.com.cn)
00005    Pei-Lin Tsai (pltsai@sunplus.com)
00006 
00007    This file is part of libopcodes.
00008 
00009    This program is free software; you can redistribute it and/or modify it under
00010    the terms of the GNU General Public License as published by the Free
00011    Software Foundation; either version 2 of the License, or (at your option)
00012    any later version.
00013 
00014    This program is distributed in the hope that it will be useful, but WITHOUT
00015    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00016    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
00017    more details.
00018 
00019    You should have received a copy of the GNU General Public License
00020    along with this program; if not, write to the Free Software
00021    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
00022    02110-1301, USA.  */
00023 
00024 #include "sysdep.h"
00025 #include "dis-asm.h"
00026 #define DEFINE_TABLE
00027 #include "score-opc.h"
00028 #include "opintl.h"
00029 #include "bfd.h"
00030 
00031 /* FIXME: This shouldn't be done here.  */
00032 #include "elf-bfd.h"
00033 #include "elf/internal.h"
00034 #include "elf/score.h"
00035 
00036 #ifndef streq
00037 #define streq(a,b)   (strcmp ((a), (b)) == 0)
00038 #endif
00039 
00040 #ifndef strneq
00041 #define strneq(a,b,n)       (strncmp ((a), (b), (n)) == 0)
00042 #endif
00043 
00044 #ifndef NUM_ELEM
00045 #define NUM_ELEM(a)     (sizeof (a) / sizeof (a)[0])
00046 #endif
00047 
00048 typedef struct
00049 {
00050   const char *name;
00051   const char *description;
00052   const char *reg_names[32];
00053 } score_regname;
00054 
00055 static score_regname regnames[] =
00056 {
00057   {"gcc", "Select register names used by GCC",
00058   {"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10",
00059    "r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19", "r20",
00060    "r21", "r22", "r23", "r24", "r25", "r26", "r27", "gp", "r29", "r30", "r31"}},
00061 };
00062 
00063 static unsigned int regname_selected = 0;
00064 
00065 #define NUM_SCORE_REGNAMES  NUM_ELEM (regnames)
00066 #define score_regnames      regnames[regname_selected].reg_names
00067 
00068 /* Print one instruction from PC on INFO->STREAM.
00069    Return the size of the instruction.  */
00070 static int
00071 print_insn_score32 (bfd_vma pc, struct disassemble_info *info, long given)
00072 {
00073   struct score_opcode *insn;
00074   void *stream = info->stream;
00075   fprintf_ftype func = info->fprintf_func;
00076 
00077   for (insn = score_opcodes; insn->assembler; insn++)
00078     {
00079       if ((insn->mask & 0xffff0000) && (given & insn->mask) == insn->value)
00080         {
00081           char *c;
00082 
00083           for (c = insn->assembler; *c; c++)
00084             {
00085               if (*c == '%')
00086                 {
00087                   switch (*++c)
00088                     {
00089                     case 'j':
00090                       {
00091                         int target;
00092 
00093                         if (info->flags & INSN_HAS_RELOC)
00094                           pc = 0;
00095                         target = (pc & 0xfe000000) | (given & 0x01fffffe);
00096                         (*info->print_address_func) (target, info);
00097                       }
00098                       break;
00099                     case 'b':
00100                       {
00101                         /* Sign-extend a 20-bit number.  */
00102 #define SEXT20(x)       ((((x) & 0xfffff) ^ (~ 0x7ffff)) + 0x80000)
00103                         int disp = ((given & 0x01ff8000) >> 5) | (given & 0x3fe);
00104                         int target = (pc + SEXT20 (disp));
00105 
00106                         (*info->print_address_func) (target, info);
00107                       }
00108                       break;
00109                     case '0':
00110                     case '1':
00111                     case '2':
00112                     case '3':
00113                     case '4':
00114                     case '5':
00115                     case '6':
00116                     case '7':
00117                     case '8':
00118                     case '9':
00119                       {
00120                         int bitstart = *c++ - '0';
00121                         int bitend = 0;
00122 
00123                         while (*c >= '0' && *c <= '9')
00124                           bitstart = (bitstart * 10) + *c++ - '0';
00125 
00126                         switch (*c)
00127                           {
00128                           case '-':
00129                             c++;
00130                             while (*c >= '0' && *c <= '9')
00131                               bitend = (bitend * 10) + *c++ - '0';
00132 
00133                             if (!bitend)
00134                               abort ();
00135 
00136                             switch (*c)
00137                               {
00138                               case 'r':
00139                                 {
00140                                   long reg;
00141 
00142                                   reg = given >> bitstart;
00143                                   reg &= (2 << (bitend - bitstart)) - 1;
00144 
00145                                   func (stream, "%s", score_regnames[reg]);
00146                                 }
00147                                 break;
00148                               case 'd':
00149                                 {
00150                                   long reg;
00151 
00152                                   reg = given >> bitstart;
00153                                   reg &= (2 << (bitend - bitstart)) - 1;
00154 
00155                                   func (stream, "%ld", reg);
00156                                 }
00157                                 break;
00158                               case 'i':
00159                                 {
00160                                   long reg;
00161 
00162                                   reg = given >> bitstart;
00163                                   reg &= (2 << (bitend - bitstart)) - 1;
00164                                   reg = ((reg ^ (1 << (bitend - bitstart))) -
00165                                         (1 << (bitend - bitstart)));
00166 
00167                                   if (((given & insn->mask) == 0x0c00000a)      /* ldc1  */
00168                                       || ((given & insn->mask) == 0x0c000012)   /* ldc2  */
00169                                       || ((given & insn->mask) == 0x0c00001c)   /* ldc3  */
00170                                       || ((given & insn->mask) == 0x0c00000b)   /* stc1  */
00171                                       || ((given & insn->mask) == 0x0c000013)   /* stc2  */
00172                                       || ((given & insn->mask) == 0x0c00001b))  /* stc3  */
00173                                     reg <<= 2;
00174 
00175                                   func (stream, "%ld", reg);
00176                                 }
00177                                 break;
00178                               case 'x':
00179                                 {
00180                                   long reg;
00181 
00182                                   reg = given >> bitstart;
00183                                   reg &= (2 << (bitend - bitstart)) - 1;
00184 
00185                                   func (stream, "%lx", reg);
00186                                 }
00187                                 break;
00188                               default:
00189                                 abort ();
00190                               }
00191                             break;
00192                           case '`':
00193                             c++;
00194                             if ((given & (1 << bitstart)) == 0)
00195                               func (stream, "%c", *c);
00196                             break;
00197                           case '\'':
00198                             c++;
00199                             if ((given & (1 << bitstart)) != 0)
00200                               func (stream, "%c", *c);
00201                             break;
00202                           default:
00203                             abort ();
00204                           }
00205                         break;
00206 
00207                     default:
00208                         abort ();
00209                       }
00210                     }
00211                 }
00212               else
00213                 func (stream, "%c", *c);
00214             }
00215           return 4;
00216         }
00217     }
00218 
00219 #if (SCORE_SIMULATOR_ACTIVE)
00220   func (stream, _("<illegal instruction>"));
00221   return 4;
00222 #endif
00223 
00224   abort ();
00225 }
00226 
00227 static void
00228 print_insn_parallel_sym (struct disassemble_info *info)
00229 {
00230   void *stream = info->stream;
00231   fprintf_ftype func = info->fprintf_func;
00232 
00233   /* 10:       0000            nop!
00234      4 space + 1 colon + 1 space + 1 tab + 8 opcode + 2 space + 1 tab.
00235      FIXME: the space number is not accurate.  */
00236   func (stream, "%s", " ||\n      \t          \t");
00237 }
00238 
00239 /* Print one instruction from PC on INFO->STREAM.
00240    Return the size of the instruction.  */
00241 static int
00242 print_insn_score16 (bfd_vma pc, struct disassemble_info *info, long given)
00243 {
00244   struct score_opcode *insn;
00245   void *stream = info->stream;
00246   fprintf_ftype func = info->fprintf_func;
00247 
00248   given &= 0xffff;
00249   for (insn = score_opcodes; insn->assembler; insn++)
00250     {
00251       if (!(insn->mask & 0xffff0000) && (given & insn->mask) == insn->value)
00252         {
00253           char *c = insn->assembler;
00254 
00255           info->bytes_per_chunk = 2;
00256           info->bytes_per_line = 4;
00257           given &= 0xffff;
00258 
00259           for (; *c; c++)
00260             {
00261               if (*c == '%')
00262                 {
00263                   switch (*++c)
00264                     {
00265 
00266                     case 'j':
00267                       {
00268                         int target;
00269 
00270                         if (info->flags & INSN_HAS_RELOC)
00271                           pc = 0;
00272 
00273                         target = (pc & 0xfffff000) | (given & 0x00000ffe);
00274                         (*info->print_address_func) (target, info);
00275                       }
00276                       break;
00277                     case 'b':
00278                       {
00279                         /* Sign-extend a 9-bit number.  */
00280 #define SEXT9(x)           ((((x) & 0x1ff) ^ (~ 0xff)) + 0x100)
00281                         int disp = (given & 0xff) << 1;
00282                         int target = (pc + SEXT9 (disp));
00283 
00284                         (*info->print_address_func) (target, info);
00285                       }
00286                       break;
00287 
00288                     case '0':
00289                     case '1':
00290                     case '2':
00291                     case '3':
00292                     case '4':
00293                     case '5':
00294                     case '6':
00295                     case '7':
00296                     case '8':
00297                     case '9':
00298                       {
00299                         int bitstart = *c++ - '0';
00300                         int bitend = 0;
00301 
00302                         while (*c >= '0' && *c <= '9')
00303                           bitstart = (bitstart * 10) + *c++ - '0';
00304 
00305                         switch (*c)
00306                           {
00307                           case '-':
00308                             {
00309                               long reg;
00310 
00311                               c++;
00312                               while (*c >= '0' && *c <= '9')
00313                                 bitend = (bitend * 10) + *c++ - '0';
00314                               if (!bitend)
00315                                 abort ();
00316                               reg = given >> bitstart;
00317                               reg &= (2 << (bitend - bitstart)) - 1;
00318                               switch (*c)
00319                                 {
00320                                 case 'R':
00321                                   func (stream, "%s", score_regnames[reg + 16]);
00322                                   break;
00323                                 case 'r':
00324                                   func (stream, "%s", score_regnames[reg]);
00325                                   break;
00326                                 case 'd':
00327                                   if (*(c + 1) == '\0')
00328                                     func (stream, "%ld", reg);
00329                                   else
00330                                     {
00331                                       c++;
00332                                       if (*c == '1')
00333                                         func (stream, "%ld", reg << 1);
00334                                       else if (*c == '2')
00335                                         func (stream, "%ld", reg << 2);
00336                                     }
00337                                   break;
00338 
00339                                 case 'x':
00340                                   if (*(c + 1) == '\0')
00341                                     func (stream, "%lx", reg);
00342                                   else
00343                                     {
00344                                       c++;
00345                                       if (*c == '1')
00346                                         func (stream, "%lx", reg << 1);
00347                                       else if (*c == '2')
00348                                         func (stream, "%lx", reg << 2);
00349                                     }
00350                                   break;
00351                                 case 'i':
00352                               reg = ((reg ^ (1 << bitend)) - (1 << bitend));
00353                               func (stream, "%ld", reg);
00354                                   break;
00355                                 default:
00356                                   abort ();
00357                                 }
00358                             }
00359                             break;
00360 
00361                           case '\'':
00362                             c++;
00363                             if ((given & (1 << bitstart)) != 0)
00364                               func (stream, "%c", *c);
00365                             break;
00366                           default:
00367                             abort ();
00368                           }
00369                       }
00370                       break;
00371                     default:
00372                       abort ();
00373                     }
00374                 }
00375               else
00376                 func (stream, "%c", *c);
00377             }
00378 
00379           return 2;
00380         }
00381     }
00382 #if (SCORE_SIMULATOR_ACTIVE)
00383   func (stream, _("<illegal instruction>"));
00384   return 2;
00385 #endif
00386   /* No match.  */
00387   abort ();
00388 }
00389 
00390 /* NOTE: There are no checks in these routines that
00391    the relevant number of data bytes exist.  */
00392 static int
00393 print_insn (bfd_vma pc, struct disassemble_info *info, bfd_boolean little)
00394 {
00395   unsigned char b[4];
00396   long given;
00397   long ridparity;
00398   int status;
00399   bfd_boolean insn_pce_p = FALSE;
00400   bfd_boolean insn_16_p = FALSE;
00401 
00402   info->display_endian = little ? BFD_ENDIAN_LITTLE : BFD_ENDIAN_BIG;
00403 
00404   if (pc & 0x2)
00405     {
00406       info->bytes_per_chunk = 2;
00407       status = info->read_memory_func (pc, (bfd_byte *) b, 2, info);
00408       b[3] = b[2] = 0;
00409       insn_16_p = TRUE;
00410     }
00411   else
00412     {
00413       info->bytes_per_chunk = 4;
00414       status = info->read_memory_func (pc, (bfd_byte *) & b[0], 4, info);
00415       if (status != 0)
00416        {
00417           info->bytes_per_chunk = 2;
00418           status = info->read_memory_func (pc, (bfd_byte *) b, 2, info);
00419           b[3] = b[2] = 0;
00420           insn_16_p = TRUE;
00421        }
00422     }
00423 
00424   if (status != 0)
00425     {
00426       info->memory_error_func (status, pc, info);
00427       return -1;
00428     }
00429 
00430   if (little)
00431     {
00432       given = (b[0]) | (b[1] << 8) | (b[2] << 16) | (b[3] << 24);
00433     }
00434   else
00435     {
00436       given = (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | (b[3]);
00437     }
00438 
00439   if ((given & 0x80008000) == 0x80008000)
00440     {
00441       insn_pce_p = FALSE;
00442       insn_16_p = FALSE;
00443     }
00444   else if ((given & 0x8000) == 0x8000)
00445     {
00446       insn_pce_p = TRUE;
00447     }
00448   else
00449     {
00450       insn_16_p = TRUE;
00451     }
00452 
00453   /* 16 bit instruction.  */
00454   if (insn_16_p)
00455     {
00456       if (little)
00457        {
00458           given = b[0] | (b[1] << 8);
00459        }
00460       else
00461        {
00462           given = (b[0] << 8) | b[1];
00463        }
00464 
00465       status = print_insn_score16 (pc, info, given);
00466     }
00467   /* pce instruction.  */
00468   else if (insn_pce_p)
00469     {
00470       long other;
00471 
00472       other = given & 0xFFFF;
00473       given = (given & 0xFFFF0000) >> 16;
00474 
00475       status = print_insn_score16 (pc, info, given);
00476       print_insn_parallel_sym (info);
00477       status += print_insn_score16 (pc, info, other);
00478       /* disassemble_bytes() will output 4 byte per chunk for pce instructio.  */
00479       info->bytes_per_chunk = 4;
00480     }
00481   /* 32 bit instruction.  */
00482   else
00483     {
00484       /* Get rid of parity.  */
00485       ridparity = (given & 0x7FFF);
00486       ridparity |= (given & 0x7FFF0000) >> 1;
00487       given = ridparity;
00488       status = print_insn_score32 (pc, info, given);
00489     }
00490 
00491   return status;
00492 }
00493 
00494 int
00495 print_insn_big_score (bfd_vma pc, struct disassemble_info *info)
00496 {
00497   return print_insn (pc, info, FALSE);
00498 }
00499 
00500 int
00501 print_insn_little_score (bfd_vma pc, struct disassemble_info *info)
00502 {
00503   return print_insn (pc, info, TRUE);
00504 }