Back to index

cell-binutils  2.17cvs20070401
z8k-dis.c
Go to the documentation of this file.
00001 /* Disassemble z8000 code.
00002    Copyright 1992, 1993, 1998, 2000, 2001, 2002, 2003
00003    Free Software Foundation, Inc.
00004 
00005    This file is part of GNU Binutils.
00006 
00007    This program is free software; you can redistribute it and/or modify
00008    it under the terms of the GNU General Public License as published by
00009    the Free Software Foundation; either version 2 of the License, or
00010    (at your option) any later version.
00011 
00012    This program is distributed in the hope that it will be useful,
00013    but WITHOUT ANY WARRANTY; without even the implied warranty of
00014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015    GNU General Public License for more details.
00016 
00017    You should have received a copy of the GNU General Public License
00018    along with this program; if not, write to the Free Software
00019    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301,
00020    USA.  */
00021 
00022 #include "sysdep.h"
00023 #include "dis-asm.h"
00024 
00025 #define DEFINE_TABLE
00026 #include "z8k-opc.h"
00027 
00028 #include <setjmp.h>
00029 
00030 typedef struct
00031 {
00032   /* These are all indexed by nibble number (i.e only every other entry
00033      of bytes is used, and every 4th entry of words).  */
00034   unsigned char nibbles[24];
00035   unsigned char bytes[24];
00036   unsigned short words[24];
00037 
00038   /* Nibble number of first word not yet fetched.  */
00039   int max_fetched;
00040   bfd_vma insn_start;
00041   jmp_buf bailout;
00042 
00043   int tabl_index;
00044   char instr_asmsrc[80];
00045   unsigned long arg_reg[0x0f];
00046   unsigned long immediate;
00047   unsigned long displacement;
00048   unsigned long address;
00049   unsigned long cond_code;
00050   unsigned long ctrl_code;
00051   unsigned long flags;
00052   unsigned long interrupts;
00053 }
00054 instr_data_s;
00055 
00056 /* Make sure that bytes from INFO->PRIVATE_DATA->BUFFER (inclusive)
00057    to ADDR (exclusive) are valid.  Returns 1 for success, longjmps
00058    on error.  */
00059 #define FETCH_DATA(info, nibble) \
00060   ((nibble) < ((instr_data_s *) (info->private_data))->max_fetched \
00061    ? 1 : fetch_data ((info), (nibble)))
00062 
00063 static int
00064 fetch_data (struct disassemble_info *info, int nibble)
00065 {
00066   unsigned char mybuf[20];
00067   int status;
00068   instr_data_s *priv = (instr_data_s *) info->private_data;
00069 
00070   if ((nibble % 4) != 0)
00071     abort ();
00072 
00073   status = (*info->read_memory_func) (priv->insn_start,
00074                                   (bfd_byte *) mybuf,
00075                                   nibble / 2,
00076                                   info);
00077   if (status != 0)
00078     {
00079       (*info->memory_error_func) (status, priv->insn_start, info);
00080       longjmp (priv->bailout, 1);
00081     }
00082 
00083   {
00084     int i;
00085     unsigned char *p = mybuf;
00086 
00087     for (i = 0; i < nibble;)
00088       {
00089        priv->words[i] = (p[0] << 8) | p[1];
00090 
00091        priv->bytes[i] = *p;
00092        priv->nibbles[i++] = *p >> 4;
00093        priv->nibbles[i++] = *p & 0xf;
00094 
00095        ++p;
00096        priv->bytes[i] = *p;
00097        priv->nibbles[i++] = *p >> 4;
00098        priv->nibbles[i++] = *p & 0xf;
00099 
00100        ++p;
00101       }
00102   }
00103   priv->max_fetched = nibble;
00104   return 1;
00105 }
00106 
00107 static char *codes[16] =
00108   {
00109     "f",
00110     "lt",
00111     "le",
00112     "ule",
00113     "ov/pe",
00114     "mi",
00115     "eq",
00116     "c/ult",
00117     "t",
00118     "ge",
00119     "gt",
00120     "ugt",
00121     "nov/po",
00122     "pl",
00123     "ne",
00124     "nc/uge"
00125   };
00126 
00127 static char *ctrl_names[8] =
00128   {
00129     "<invld>",
00130     "flags",
00131     "fcw",
00132     "refresh",
00133     "psapseg",
00134     "psapoff",
00135     "nspseg",
00136     "nspoff"
00137   };
00138 
00139 static int seg_length;
00140 int z8k_lookup_instr (unsigned char *, disassemble_info *);
00141 static void output_instr (instr_data_s *, unsigned long, disassemble_info *);
00142 static void unpack_instr (instr_data_s *, int, disassemble_info *);
00143 static void unparse_instr (instr_data_s *, int);
00144 
00145 static int
00146 print_insn_z8k (bfd_vma addr, disassemble_info *info, int is_segmented)
00147 {
00148   instr_data_s instr_data;
00149 
00150   info->private_data = (PTR) &instr_data;
00151   instr_data.max_fetched = 0;
00152   instr_data.insn_start = addr;
00153   if (setjmp (instr_data.bailout) != 0)
00154     /* Error return.  */
00155     return -1;
00156 
00157   info->bytes_per_chunk = 2;
00158   info->bytes_per_line = 6;
00159   info->display_endian = BFD_ENDIAN_BIG;
00160 
00161   instr_data.tabl_index = z8k_lookup_instr (instr_data.nibbles, info);
00162   if (instr_data.tabl_index >= 0)
00163     {
00164       unpack_instr (&instr_data, is_segmented, info);
00165       unparse_instr (&instr_data, is_segmented);
00166       output_instr (&instr_data, addr, info);
00167       return z8k_table[instr_data.tabl_index].length + seg_length;
00168     }
00169   else
00170     {
00171       FETCH_DATA (info, 4);
00172       (*info->fprintf_func) (info->stream, ".word %02x%02x",
00173                           instr_data.bytes[0], instr_data.bytes[2]);
00174       return 2;
00175     }
00176 }
00177 
00178 int
00179 print_insn_z8001 (bfd_vma addr, disassemble_info *info)
00180 {
00181   return print_insn_z8k (addr, info, 1);
00182 }
00183 
00184 int
00185 print_insn_z8002 (bfd_vma addr, disassemble_info *info)
00186 {
00187   return print_insn_z8k (addr, info, 0);
00188 }
00189 
00190 int
00191 z8k_lookup_instr (unsigned char *nibbles, disassemble_info *info)
00192 {
00193   int nibl_index, tabl_index;
00194   int nibl_matched;
00195   int need_fetch = 0;
00196   unsigned short instr_nibl;
00197   unsigned short tabl_datum, datum_class, datum_value;
00198 
00199   nibl_matched = 0;
00200   tabl_index = 0;
00201   FETCH_DATA (info, 4);
00202   while (!nibl_matched && z8k_table[tabl_index].name)
00203     {
00204       nibl_matched = 1;
00205       for (nibl_index = 0;
00206           nibl_index < z8k_table[tabl_index].length * 2 && nibl_matched;
00207           nibl_index++)
00208        {
00209          if ((nibl_index % 4) == 0)
00210             {
00211               /* Fetch data only if it isn't already there.  */
00212               if (nibl_index >= 4 || (nibl_index < 4 && need_fetch))
00213                 FETCH_DATA (info, nibl_index + 4);   /* Fetch one word at a time.  */
00214               if (nibl_index < 4)
00215                 need_fetch = 0;
00216               else
00217                 need_fetch = 1;
00218             }
00219          instr_nibl = nibbles[nibl_index];
00220 
00221          tabl_datum = z8k_table[tabl_index].byte_info[nibl_index];
00222          datum_class = tabl_datum & CLASS_MASK;
00223          datum_value = ~CLASS_MASK & tabl_datum;
00224 
00225          switch (datum_class)
00226            {
00227            case CLASS_BIT:
00228              if (datum_value != instr_nibl)
00229               nibl_matched = 0;
00230              break;
00231            case CLASS_IGNORE:
00232              break;
00233            case CLASS_00II:
00234              if (!((~instr_nibl) & 0x4))
00235               nibl_matched = 0;
00236              break;
00237            case CLASS_01II:
00238              if (!(instr_nibl & 0x4))
00239               nibl_matched = 0;
00240              break;
00241            case CLASS_0CCC:
00242              if (!((~instr_nibl) & 0x8))
00243               nibl_matched = 0;
00244              break;
00245            case CLASS_1CCC:
00246              if (!(instr_nibl & 0x8))
00247               nibl_matched = 0;
00248              break;
00249            case CLASS_0DISP7:
00250              if (!((~instr_nibl) & 0x8))
00251               nibl_matched = 0;
00252              nibl_index += 1;
00253              break;
00254            case CLASS_1DISP7:
00255              if (!(instr_nibl & 0x8))
00256               nibl_matched = 0;
00257              nibl_index += 1;
00258              break;
00259            case CLASS_REGN0:
00260              if (instr_nibl == 0)
00261               nibl_matched = 0;
00262              break;
00263            case CLASS_BIT_1OR2:
00264              if ((instr_nibl | 0x2) != (datum_value | 0x2))
00265               nibl_matched = 0;
00266              break;
00267            default:
00268              break;
00269            }
00270        }
00271 
00272       if (nibl_matched)
00273        return tabl_index;
00274 
00275       tabl_index++;
00276     }
00277   return -1;
00278 }
00279 
00280 static void
00281 output_instr (instr_data_s *instr_data,
00282               unsigned long addr ATTRIBUTE_UNUSED,
00283               disassemble_info *info)
00284 {
00285   int num_bytes;
00286   char out_str[100];
00287 
00288   out_str[0] = 0;
00289 
00290   num_bytes = (z8k_table[instr_data->tabl_index].length + seg_length) * 2;
00291   FETCH_DATA (info, num_bytes);
00292 
00293   strcat (out_str, instr_data->instr_asmsrc);
00294 
00295   (*info->fprintf_func) (info->stream, "%s", out_str);
00296 }
00297 
00298 static void
00299 unpack_instr (instr_data_s *instr_data, int is_segmented, disassemble_info *info)
00300 {
00301   int nibl_count, loop;
00302   unsigned short instr_nibl, instr_byte, instr_word;
00303   long instr_long;
00304   unsigned int tabl_datum, datum_class;
00305   unsigned short datum_value;
00306 
00307   nibl_count = 0;
00308   loop = 0;
00309   seg_length = 0;
00310 
00311   while (z8k_table[instr_data->tabl_index].byte_info[loop] != 0)
00312     {
00313       FETCH_DATA (info, nibl_count + 4 - (nibl_count % 4));
00314       instr_nibl = instr_data->nibbles[nibl_count];
00315       instr_byte = instr_data->bytes[nibl_count & ~1];
00316       instr_word = instr_data->words[nibl_count & ~3];
00317 
00318       tabl_datum = z8k_table[instr_data->tabl_index].byte_info[loop];
00319       datum_class = tabl_datum & CLASS_MASK;
00320       datum_value = tabl_datum & ~CLASS_MASK;
00321 
00322       switch (datum_class)
00323        {
00324        case CLASS_DISP:
00325          switch (datum_value)
00326            {
00327            case ARG_DISP16:
00328              instr_data->displacement = instr_data->insn_start + 4
00329               + (signed short) (instr_word & 0xffff);
00330              nibl_count += 3;
00331              break;
00332            case ARG_DISP12:
00333              if (instr_word & 0x800)
00334               /* Negative 12 bit displacement.  */
00335               instr_data->displacement = instr_data->insn_start + 2
00336                 - (signed short) ((instr_word & 0xfff) | 0xf000) * 2;
00337              else
00338               instr_data->displacement = instr_data->insn_start + 2
00339                 - (instr_word & 0x0fff) * 2;
00340 
00341              nibl_count += 2;
00342              break;
00343            default:
00344              break;
00345            }
00346          break;
00347        case CLASS_IMM:
00348          switch (datum_value)
00349            {
00350            case ARG_IMM4:
00351              instr_data->immediate = instr_nibl;
00352              break;
00353            case ARG_NIM4:
00354              instr_data->immediate = (- instr_nibl) & 0xf;
00355              break;
00356            case ARG_NIM8:
00357              instr_data->immediate = (- instr_byte) & 0xff;
00358              nibl_count += 1;
00359              break;
00360            case ARG_IMM8:
00361              instr_data->immediate = instr_byte;
00362              nibl_count += 1;
00363              break;
00364            case ARG_IMM16:
00365              instr_data->immediate = instr_word;
00366              nibl_count += 3;
00367              break;
00368            case ARG_IMM32:
00369              FETCH_DATA (info, nibl_count + 8);
00370              instr_long = (instr_data->words[nibl_count] << 16)
00371               | (instr_data->words[nibl_count + 4]);
00372              instr_data->immediate = instr_long;
00373              nibl_count += 7;
00374              break;
00375            case ARG_IMMN:
00376              instr_data->immediate = instr_nibl - 1;
00377              break;
00378            case ARG_IMM4M1:
00379              instr_data->immediate = instr_nibl + 1;
00380              break;
00381            case ARG_IMM_1:
00382              instr_data->immediate = 1;
00383              break;
00384            case ARG_IMM_2:
00385              instr_data->immediate = 2;
00386              break;
00387            case ARG_IMM2:
00388              instr_data->immediate = instr_nibl & 0x3;
00389              break;
00390            default:
00391              break;
00392            }
00393          break;
00394        case CLASS_CC:
00395          instr_data->cond_code = instr_nibl;
00396          break;
00397        case CLASS_ADDRESS:
00398          if (is_segmented)
00399            {
00400              if (instr_nibl & 0x8)
00401               {
00402                 FETCH_DATA (info, nibl_count + 8);
00403                 instr_long = (instr_data->words[nibl_count] << 16)
00404                   | (instr_data->words[nibl_count + 4]);
00405                 instr_data->address = ((instr_word & 0x7f00) << 16)
00406                   + (instr_long & 0xffff);
00407                 nibl_count += 7;
00408                 seg_length = 2;
00409               }
00410              else
00411               {
00412                 instr_data->address = ((instr_word & 0x7f00) << 16)
00413                   + (instr_word & 0x00ff);
00414                 nibl_count += 3;
00415               }
00416            }
00417          else
00418            {
00419              instr_data->address = instr_word;
00420              nibl_count += 3;
00421            }
00422          break;
00423        case CLASS_0CCC:
00424        case CLASS_1CCC:
00425          instr_data->ctrl_code = instr_nibl & 0x7;
00426          break;
00427        case CLASS_0DISP7:
00428          instr_data->displacement =
00429            instr_data->insn_start + 2 - (instr_byte & 0x7f) * 2;
00430          nibl_count += 1;
00431          break;
00432        case CLASS_1DISP7:
00433          instr_data->displacement =
00434            instr_data->insn_start + 2 - (instr_byte & 0x7f) * 2;
00435          nibl_count += 1;
00436          break;
00437        case CLASS_01II:
00438          instr_data->interrupts = instr_nibl & 0x3;
00439          break;
00440        case CLASS_00II:
00441          instr_data->interrupts = instr_nibl & 0x3;
00442          break;
00443        case CLASS_IGNORE:
00444        case CLASS_BIT:
00445          instr_data->ctrl_code = instr_nibl & 0x7;
00446          break;
00447        case CLASS_FLAGS:
00448          instr_data->flags = instr_nibl;
00449          break;
00450        case CLASS_REG:
00451          instr_data->arg_reg[datum_value] = instr_nibl;
00452          break;
00453        case CLASS_REGN0:
00454          instr_data->arg_reg[datum_value] = instr_nibl;
00455          break;
00456        case CLASS_DISP8:
00457          instr_data->displacement =
00458            instr_data->insn_start + 2 + (signed char) instr_byte * 2;
00459          nibl_count += 1;
00460          break;
00461         case CLASS_BIT_1OR2:
00462           instr_data->immediate = ((instr_nibl >> 1) & 0x1) + 1;
00463           nibl_count += 1;
00464          break;
00465        default:
00466          abort ();
00467          break;
00468        }
00469 
00470       loop += 1;
00471       nibl_count += 1;
00472     }
00473 }
00474 
00475 static void
00476 print_intr(char *tmp_str, unsigned long interrupts)
00477 {
00478   int comma = 0;
00479 
00480   *tmp_str = 0;
00481   if (! (interrupts & 2))
00482     {
00483       strcat (tmp_str, "vi");
00484       comma = 1;
00485     }
00486   if (! (interrupts & 1))
00487     {
00488       if (comma) strcat (tmp_str, ",");
00489       strcat (tmp_str, "nvi");
00490     }
00491 }
00492 
00493 static void
00494 print_flags(char *tmp_str, unsigned long flags)
00495 {
00496   int comma = 0;
00497 
00498   *tmp_str = 0;
00499   if (flags & 8)
00500     {
00501       strcat (tmp_str, "c");
00502       comma = 1;
00503     }
00504   if (flags & 4)
00505     {
00506       if (comma) strcat (tmp_str, ",");
00507       strcat (tmp_str, "z");
00508       comma = 1;
00509     }
00510   if (flags & 2)
00511     {
00512       if (comma) strcat (tmp_str, ",");
00513       strcat (tmp_str, "s");
00514       comma = 1;
00515     }
00516   if (flags & 1)
00517     {
00518       if (comma) strcat (tmp_str, ",");
00519       strcat (tmp_str, "p");
00520     }
00521 }
00522 
00523 static void
00524 unparse_instr (instr_data_s *instr_data, int is_segmented)
00525 {
00526   unsigned short datum_value;
00527   unsigned int tabl_datum, datum_class;
00528   int loop, loop_limit;
00529   char out_str[80], tmp_str[25];
00530 
00531   sprintf (out_str, "%s\t", z8k_table[instr_data->tabl_index].name);
00532 
00533   loop_limit = z8k_table[instr_data->tabl_index].noperands;
00534   for (loop = 0; loop < loop_limit; loop++)
00535     {
00536       if (loop)
00537        strcat (out_str, ",");
00538 
00539       tabl_datum = z8k_table[instr_data->tabl_index].arg_info[loop];
00540       datum_class = tabl_datum & CLASS_MASK;
00541       datum_value = tabl_datum & ~CLASS_MASK;
00542 
00543       switch (datum_class)
00544        {
00545        case CLASS_X:
00546           sprintf (tmp_str, "0x%0lx(r%ld)", instr_data->address,
00547                    instr_data->arg_reg[datum_value]);
00548          strcat (out_str, tmp_str);
00549          break;
00550        case CLASS_BA:
00551           if (is_segmented)
00552             sprintf (tmp_str, "rr%ld(#0x%lx)", instr_data->arg_reg[datum_value],
00553                      instr_data->immediate);
00554           else
00555             sprintf (tmp_str, "r%ld(#0x%lx)", instr_data->arg_reg[datum_value],
00556                      instr_data->immediate);
00557          strcat (out_str, tmp_str);
00558          break;
00559        case CLASS_BX:
00560           if (is_segmented)
00561             sprintf (tmp_str, "rr%ld(r%ld)", instr_data->arg_reg[datum_value],
00562                      instr_data->arg_reg[ARG_RX]);
00563           else
00564             sprintf (tmp_str, "r%ld(r%ld)", instr_data->arg_reg[datum_value],
00565                      instr_data->arg_reg[ARG_RX]);
00566          strcat (out_str, tmp_str);
00567          break;
00568        case CLASS_DISP:
00569          sprintf (tmp_str, "0x%0lx", instr_data->displacement);
00570          strcat (out_str, tmp_str);
00571          break;
00572        case CLASS_IMM:
00573          if (datum_value == ARG_IMM2)     /* True with EI/DI instructions only.  */
00574            {
00575              print_intr (tmp_str, instr_data->interrupts);
00576              strcat (out_str, tmp_str);
00577              break;
00578            }
00579          sprintf (tmp_str, "#0x%0lx", instr_data->immediate);
00580          strcat (out_str, tmp_str);
00581          break;
00582        case CLASS_CC:
00583          sprintf (tmp_str, "%s", codes[instr_data->cond_code]);
00584          strcat (out_str, tmp_str);
00585          break;
00586        case CLASS_CTRL:
00587          sprintf (tmp_str, "%s", ctrl_names[instr_data->ctrl_code]);
00588          strcat (out_str, tmp_str);
00589          break;
00590        case CLASS_DA:
00591        case CLASS_ADDRESS:
00592          sprintf (tmp_str, "0x%0lx", instr_data->address);
00593          strcat (out_str, tmp_str);
00594          break;
00595        case CLASS_IR:
00596          if (is_segmented)
00597            sprintf (tmp_str, "@rr%ld", instr_data->arg_reg[datum_value]);
00598          else
00599            sprintf (tmp_str, "@r%ld", instr_data->arg_reg[datum_value]);
00600          strcat (out_str, tmp_str);
00601          break;
00602        case CLASS_IRO:
00603           sprintf (tmp_str, "@r%ld", instr_data->arg_reg[datum_value]);
00604          strcat (out_str, tmp_str);
00605          break;
00606        case CLASS_FLAGS:
00607          print_flags(tmp_str, instr_data->flags);
00608          strcat (out_str, tmp_str);
00609          break;
00610        case CLASS_REG_BYTE:
00611          if (instr_data->arg_reg[datum_value] >= 0x8)
00612            sprintf (tmp_str, "rl%ld",
00613                    instr_data->arg_reg[datum_value] - 0x8);
00614          else
00615            sprintf (tmp_str, "rh%ld", instr_data->arg_reg[datum_value]);
00616          strcat (out_str, tmp_str);
00617          break;
00618        case CLASS_REG_WORD:
00619          sprintf (tmp_str, "r%ld", instr_data->arg_reg[datum_value]);
00620          strcat (out_str, tmp_str);
00621          break;
00622        case CLASS_REG_QUAD:
00623          sprintf (tmp_str, "rq%ld", instr_data->arg_reg[datum_value]);
00624          strcat (out_str, tmp_str);
00625          break;
00626        case CLASS_REG_LONG:
00627          sprintf (tmp_str, "rr%ld", instr_data->arg_reg[datum_value]);
00628          strcat (out_str, tmp_str);
00629          break;
00630        case CLASS_PR:
00631          if (is_segmented)
00632            sprintf (tmp_str, "rr%ld", instr_data->arg_reg[datum_value]);
00633          else
00634            sprintf (tmp_str, "r%ld", instr_data->arg_reg[datum_value]);
00635          strcat (out_str, tmp_str);
00636          break;
00637        default:
00638          abort ();
00639          break;
00640        }
00641     }
00642 
00643   strcpy (instr_data->instr_asmsrc, out_str);
00644 }