Home | History | Annotate | Download | only in opcodes
      1 /* Disassemble z8000 code.
      2    Copyright (C) 1992-2016 Free Software Foundation, Inc.
      3 
      4    This file is part of the GNU opcodes library.
      5 
      6    This library 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, or (at your option)
      9    any later version.
     10 
     11    It is distributed in the hope that it will be useful, but WITHOUT
     12    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
     13    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
     14    License for more details.
     15 
     16    You should have received a copy of the GNU General Public License
     17    along with this file; see the file COPYING.  If not, write to the
     18    Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston,
     19    MA 02110-1301, USA.  */
     20 
     21 #include "sysdep.h"
     22 #include "dis-asm.h"
     23 
     24 #define DEFINE_TABLE
     25 #include "z8k-opc.h"
     26 
     27 #include <setjmp.h>
     28 
     29 typedef struct
     30 {
     31   /* These are all indexed by nibble number (i.e only every other entry
     32      of bytes is used, and every 4th entry of words).  */
     33   unsigned char nibbles[24];
     34   unsigned char bytes[24];
     35   unsigned short words[24];
     36 
     37   /* Nibble number of first word not yet fetched.  */
     38   int max_fetched;
     39   bfd_vma insn_start;
     40   OPCODES_SIGJMP_BUF bailout;
     41 
     42   int tabl_index;
     43   char instr_asmsrc[80];
     44   unsigned long arg_reg[0x0f];
     45   unsigned long immediate;
     46   unsigned long displacement;
     47   unsigned long address;
     48   unsigned long cond_code;
     49   unsigned long ctrl_code;
     50   unsigned long flags;
     51   unsigned long interrupts;
     52 }
     53 instr_data_s;
     54 
     55 /* Make sure that bytes from INFO->PRIVATE_DATA->BUFFER (inclusive)
     56    to ADDR (exclusive) are valid.  Returns 1 for success, longjmps
     57    on error.  */
     58 #define FETCH_DATA(info, nibble) \
     59   ((nibble) < ((instr_data_s *) (info->private_data))->max_fetched \
     60    ? 1 : fetch_data ((info), (nibble)))
     61 
     62 static int
     63 fetch_data (struct disassemble_info *info, int nibble)
     64 {
     65   unsigned char mybuf[20];
     66   int status;
     67   instr_data_s *priv = (instr_data_s *) info->private_data;
     68 
     69   if ((nibble % 4) != 0)
     70     abort ();
     71 
     72   status = (*info->read_memory_func) (priv->insn_start,
     73 				      (bfd_byte *) mybuf,
     74 				      nibble / 2,
     75 				      info);
     76   if (status != 0)
     77     {
     78       (*info->memory_error_func) (status, priv->insn_start, info);
     79       OPCODES_SIGLONGJMP (priv->bailout, 1);
     80     }
     81 
     82   {
     83     int i;
     84     unsigned char *p = mybuf;
     85 
     86     for (i = 0; i < nibble;)
     87       {
     88 	priv->words[i] = (p[0] << 8) | p[1];
     89 
     90 	priv->bytes[i] = *p;
     91 	priv->nibbles[i++] = *p >> 4;
     92 	priv->nibbles[i++] = *p & 0xf;
     93 
     94 	++p;
     95 	priv->bytes[i] = *p;
     96 	priv->nibbles[i++] = *p >> 4;
     97 	priv->nibbles[i++] = *p & 0xf;
     98 
     99 	++p;
    100       }
    101   }
    102   priv->max_fetched = nibble;
    103   return 1;
    104 }
    105 
    106 static char *codes[16] =
    107   {
    108     "f",
    109     "lt",
    110     "le",
    111     "ule",
    112     "ov/pe",
    113     "mi",
    114     "eq",
    115     "c/ult",
    116     "t",
    117     "ge",
    118     "gt",
    119     "ugt",
    120     "nov/po",
    121     "pl",
    122     "ne",
    123     "nc/uge"
    124   };
    125 
    126 static char *ctrl_names[8] =
    127   {
    128     "<invld>",
    129     "flags",
    130     "fcw",
    131     "refresh",
    132     "psapseg",
    133     "psapoff",
    134     "nspseg",
    135     "nspoff"
    136   };
    137 
    138 static int seg_length;
    139 int z8k_lookup_instr (unsigned char *, disassemble_info *);
    140 static void output_instr (instr_data_s *, unsigned long, disassemble_info *);
    141 static void unpack_instr (instr_data_s *, int, disassemble_info *);
    142 static void unparse_instr (instr_data_s *, int);
    143 
    144 static int
    145 print_insn_z8k (bfd_vma addr, disassemble_info *info, int is_segmented)
    146 {
    147   instr_data_s instr_data;
    148 
    149   info->private_data = (PTR) &instr_data;
    150   instr_data.max_fetched = 0;
    151   instr_data.insn_start = addr;
    152   if (OPCODES_SIGSETJMP (instr_data.bailout) != 0)
    153     /* Error return.  */
    154     return -1;
    155 
    156   info->bytes_per_chunk = 2;
    157   info->bytes_per_line = 6;
    158   info->display_endian = BFD_ENDIAN_BIG;
    159 
    160   instr_data.tabl_index = z8k_lookup_instr (instr_data.nibbles, info);
    161   if (instr_data.tabl_index >= 0)
    162     {
    163       unpack_instr (&instr_data, is_segmented, info);
    164       unparse_instr (&instr_data, is_segmented);
    165       output_instr (&instr_data, addr, info);
    166       return z8k_table[instr_data.tabl_index].length + seg_length;
    167     }
    168   else
    169     {
    170       FETCH_DATA (info, 4);
    171       (*info->fprintf_func) (info->stream, ".word %02x%02x",
    172 			     instr_data.bytes[0], instr_data.bytes[2]);
    173       return 2;
    174     }
    175 }
    176 
    177 int
    178 print_insn_z8001 (bfd_vma addr, disassemble_info *info)
    179 {
    180   return print_insn_z8k (addr, info, 1);
    181 }
    182 
    183 int
    184 print_insn_z8002 (bfd_vma addr, disassemble_info *info)
    185 {
    186   return print_insn_z8k (addr, info, 0);
    187 }
    188 
    189 int
    190 z8k_lookup_instr (unsigned char *nibbles, disassemble_info *info)
    191 {
    192   int nibl_index, tabl_index;
    193   int nibl_matched;
    194   int need_fetch = 0;
    195   unsigned short instr_nibl;
    196   unsigned short tabl_datum, datum_class, datum_value;
    197 
    198   nibl_matched = 0;
    199   tabl_index = 0;
    200   FETCH_DATA (info, 4);
    201   while (!nibl_matched && z8k_table[tabl_index].name)
    202     {
    203       nibl_matched = 1;
    204       for (nibl_index = 0;
    205 	   nibl_index < z8k_table[tabl_index].length * 2 && nibl_matched;
    206 	   nibl_index++)
    207 	{
    208 	  if ((nibl_index % 4) == 0)
    209             {
    210               /* Fetch data only if it isn't already there.  */
    211               if (nibl_index >= 4 || (nibl_index < 4 && need_fetch))
    212                 FETCH_DATA (info, nibl_index + 4);   /* Fetch one word at a time.  */
    213               if (nibl_index < 4)
    214                 need_fetch = 0;
    215               else
    216                 need_fetch = 1;
    217             }
    218 	  instr_nibl = nibbles[nibl_index];
    219 
    220 	  tabl_datum = z8k_table[tabl_index].byte_info[nibl_index];
    221 	  datum_class = tabl_datum & CLASS_MASK;
    222 	  datum_value = ~CLASS_MASK & tabl_datum;
    223 
    224 	  switch (datum_class)
    225 	    {
    226 	    case CLASS_BIT:
    227 	      if (datum_value != instr_nibl)
    228 		nibl_matched = 0;
    229 	      break;
    230 	    case CLASS_IGNORE:
    231 	      break;
    232 	    case CLASS_00II:
    233 	      if (!((~instr_nibl) & 0x4))
    234 		nibl_matched = 0;
    235 	      break;
    236 	    case CLASS_01II:
    237 	      if (!(instr_nibl & 0x4))
    238 		nibl_matched = 0;
    239 	      break;
    240 	    case CLASS_0CCC:
    241 	      if (!((~instr_nibl) & 0x8))
    242 		nibl_matched = 0;
    243 	      break;
    244 	    case CLASS_1CCC:
    245 	      if (!(instr_nibl & 0x8))
    246 		nibl_matched = 0;
    247 	      break;
    248 	    case CLASS_0DISP7:
    249 	      if (!((~instr_nibl) & 0x8))
    250 		nibl_matched = 0;
    251 	      nibl_index += 1;
    252 	      break;
    253 	    case CLASS_1DISP7:
    254 	      if (!(instr_nibl & 0x8))
    255 		nibl_matched = 0;
    256 	      nibl_index += 1;
    257 	      break;
    258 	    case CLASS_REGN0:
    259 	      if (instr_nibl == 0)
    260 		nibl_matched = 0;
    261 	      break;
    262 	    case CLASS_BIT_1OR2:
    263 	      if ((instr_nibl | 0x2) != (datum_value | 0x2))
    264 		nibl_matched = 0;
    265 	      break;
    266 	    default:
    267 	      break;
    268 	    }
    269 	}
    270 
    271       if (nibl_matched)
    272 	return tabl_index;
    273 
    274       tabl_index++;
    275     }
    276   return -1;
    277 }
    278 
    279 static void
    280 output_instr (instr_data_s *instr_data,
    281               unsigned long addr ATTRIBUTE_UNUSED,
    282               disassemble_info *info)
    283 {
    284   int num_bytes;
    285   char out_str[100];
    286 
    287   out_str[0] = 0;
    288 
    289   num_bytes = (z8k_table[instr_data->tabl_index].length + seg_length) * 2;
    290   FETCH_DATA (info, num_bytes);
    291 
    292   strcat (out_str, instr_data->instr_asmsrc);
    293 
    294   (*info->fprintf_func) (info->stream, "%s", out_str);
    295 }
    296 
    297 static void
    298 unpack_instr (instr_data_s *instr_data, int is_segmented, disassemble_info *info)
    299 {
    300   int nibl_count, loop;
    301   unsigned short instr_nibl, instr_byte, instr_word;
    302   long instr_long;
    303   unsigned int tabl_datum, datum_class;
    304   unsigned short datum_value;
    305 
    306   nibl_count = 0;
    307   loop = 0;
    308   seg_length = 0;
    309 
    310   while (z8k_table[instr_data->tabl_index].byte_info[loop] != 0)
    311     {
    312       FETCH_DATA (info, nibl_count + 4 - (nibl_count % 4));
    313       instr_nibl = instr_data->nibbles[nibl_count];
    314       instr_byte = instr_data->bytes[nibl_count & ~1];
    315       instr_word = instr_data->words[nibl_count & ~3];
    316 
    317       tabl_datum = z8k_table[instr_data->tabl_index].byte_info[loop];
    318       datum_class = tabl_datum & CLASS_MASK;
    319       datum_value = tabl_datum & ~CLASS_MASK;
    320 
    321       switch (datum_class)
    322 	{
    323 	case CLASS_DISP:
    324 	  switch (datum_value)
    325 	    {
    326 	    case ARG_DISP16:
    327 	      instr_data->displacement = instr_data->insn_start + 4
    328 		+ (signed short) (instr_word & 0xffff);
    329 	      nibl_count += 3;
    330 	      break;
    331 	    case ARG_DISP12:
    332 	      if (instr_word & 0x800)
    333 		/* Negative 12 bit displacement.  */
    334 		instr_data->displacement = instr_data->insn_start + 2
    335 		  - (signed short) ((instr_word & 0xfff) | 0xf000) * 2;
    336 	      else
    337 		instr_data->displacement = instr_data->insn_start + 2
    338 		  - (instr_word & 0x0fff) * 2;
    339 
    340 	      nibl_count += 2;
    341 	      break;
    342 	    default:
    343 	      break;
    344 	    }
    345 	  break;
    346 	case CLASS_IMM:
    347 	  switch (datum_value)
    348 	    {
    349 	    case ARG_IMM4:
    350 	      instr_data->immediate = instr_nibl;
    351 	      break;
    352 	    case ARG_NIM4:
    353 	      instr_data->immediate = (- instr_nibl) & 0xf;
    354 	      break;
    355 	    case ARG_NIM8:
    356 	      instr_data->immediate = (- instr_byte) & 0xff;
    357 	      nibl_count += 1;
    358 	      break;
    359 	    case ARG_IMM8:
    360 	      instr_data->immediate = instr_byte;
    361 	      nibl_count += 1;
    362 	      break;
    363 	    case ARG_IMM16:
    364 	      instr_data->immediate = instr_word;
    365 	      nibl_count += 3;
    366 	      break;
    367 	    case ARG_IMM32:
    368 	      FETCH_DATA (info, nibl_count + 8);
    369 	      instr_long = (instr_data->words[nibl_count] << 16)
    370 		| (instr_data->words[nibl_count + 4]);
    371 	      instr_data->immediate = instr_long;
    372 	      nibl_count += 7;
    373 	      break;
    374 	    case ARG_IMMN:
    375 	      instr_data->immediate = instr_nibl - 1;
    376 	      break;
    377 	    case ARG_IMM4M1:
    378 	      instr_data->immediate = instr_nibl + 1;
    379 	      break;
    380 	    case ARG_IMM_1:
    381 	      instr_data->immediate = 1;
    382 	      break;
    383 	    case ARG_IMM_2:
    384 	      instr_data->immediate = 2;
    385 	      break;
    386 	    case ARG_IMM2:
    387 	      instr_data->immediate = instr_nibl & 0x3;
    388 	      break;
    389 	    default:
    390 	      break;
    391 	    }
    392 	  break;
    393 	case CLASS_CC:
    394 	  instr_data->cond_code = instr_nibl;
    395 	  break;
    396 	case CLASS_ADDRESS:
    397 	  if (is_segmented)
    398 	    {
    399 	      if (instr_nibl & 0x8)
    400 		{
    401 		  FETCH_DATA (info, nibl_count + 8);
    402 		  instr_long = (instr_data->words[nibl_count] << 16)
    403 		    | (instr_data->words[nibl_count + 4]);
    404 		  instr_data->address = ((instr_word & 0x7f00) << 16)
    405 		    + (instr_long & 0xffff);
    406 		  nibl_count += 7;
    407 		  seg_length = 2;
    408 		}
    409 	      else
    410 		{
    411 		  instr_data->address = ((instr_word & 0x7f00) << 16)
    412 		    + (instr_word & 0x00ff);
    413 		  nibl_count += 3;
    414 		}
    415 	    }
    416 	  else
    417 	    {
    418 	      instr_data->address = instr_word;
    419 	      nibl_count += 3;
    420 	    }
    421 	  break;
    422 	case CLASS_0CCC:
    423 	case CLASS_1CCC:
    424 	  instr_data->ctrl_code = instr_nibl & 0x7;
    425 	  break;
    426 	case CLASS_0DISP7:
    427 	  instr_data->displacement =
    428 	    instr_data->insn_start + 2 - (instr_byte & 0x7f) * 2;
    429 	  nibl_count += 1;
    430 	  break;
    431 	case CLASS_1DISP7:
    432 	  instr_data->displacement =
    433 	    instr_data->insn_start + 2 - (instr_byte & 0x7f) * 2;
    434 	  nibl_count += 1;
    435 	  break;
    436 	case CLASS_01II:
    437 	  instr_data->interrupts = instr_nibl & 0x3;
    438 	  break;
    439 	case CLASS_00II:
    440 	  instr_data->interrupts = instr_nibl & 0x3;
    441 	  break;
    442 	case CLASS_IGNORE:
    443 	case CLASS_BIT:
    444 	  instr_data->ctrl_code = instr_nibl & 0x7;
    445 	  break;
    446 	case CLASS_FLAGS:
    447 	  instr_data->flags = instr_nibl;
    448 	  break;
    449 	case CLASS_REG:
    450 	  instr_data->arg_reg[datum_value] = instr_nibl;
    451 	  break;
    452 	case CLASS_REGN0:
    453 	  instr_data->arg_reg[datum_value] = instr_nibl;
    454 	  break;
    455 	case CLASS_DISP8:
    456 	  instr_data->displacement =
    457 	    instr_data->insn_start + 2 + (signed char) instr_byte * 2;
    458 	  nibl_count += 1;
    459 	  break;
    460         case CLASS_BIT_1OR2:
    461           instr_data->immediate = ((instr_nibl >> 1) & 0x1) + 1;
    462           nibl_count += 1;
    463 	  break;
    464 	default:
    465 	  abort ();
    466 	  break;
    467 	}
    468 
    469       loop += 1;
    470       nibl_count += 1;
    471     }
    472 }
    473 
    474 static void
    475 print_intr(char *tmp_str, unsigned long interrupts)
    476 {
    477   int comma = 0;
    478 
    479   *tmp_str = 0;
    480   if (! (interrupts & 2))
    481     {
    482       strcat (tmp_str, "vi");
    483       comma = 1;
    484     }
    485   if (! (interrupts & 1))
    486     {
    487       if (comma) strcat (tmp_str, ",");
    488       strcat (tmp_str, "nvi");
    489     }
    490 }
    491 
    492 static void
    493 print_flags(char *tmp_str, unsigned long flags)
    494 {
    495   int comma = 0;
    496 
    497   *tmp_str = 0;
    498   if (flags & 8)
    499     {
    500       strcat (tmp_str, "c");
    501       comma = 1;
    502     }
    503   if (flags & 4)
    504     {
    505       if (comma) strcat (tmp_str, ",");
    506       strcat (tmp_str, "z");
    507       comma = 1;
    508     }
    509   if (flags & 2)
    510     {
    511       if (comma) strcat (tmp_str, ",");
    512       strcat (tmp_str, "s");
    513       comma = 1;
    514     }
    515   if (flags & 1)
    516     {
    517       if (comma) strcat (tmp_str, ",");
    518       strcat (tmp_str, "p");
    519     }
    520 }
    521 
    522 static void
    523 unparse_instr (instr_data_s *instr_data, int is_segmented)
    524 {
    525   unsigned short datum_value;
    526   unsigned int tabl_datum, datum_class;
    527   int loop, loop_limit;
    528   char out_str[80], tmp_str[25];
    529 
    530   sprintf (out_str, "%s\t", z8k_table[instr_data->tabl_index].name);
    531 
    532   loop_limit = z8k_table[instr_data->tabl_index].noperands;
    533   for (loop = 0; loop < loop_limit; loop++)
    534     {
    535       if (loop)
    536 	strcat (out_str, ",");
    537 
    538       tabl_datum = z8k_table[instr_data->tabl_index].arg_info[loop];
    539       datum_class = tabl_datum & CLASS_MASK;
    540       datum_value = tabl_datum & ~CLASS_MASK;
    541 
    542       switch (datum_class)
    543 	{
    544 	case CLASS_X:
    545           sprintf (tmp_str, "0x%0lx(r%ld)", instr_data->address,
    546                    instr_data->arg_reg[datum_value]);
    547 	  strcat (out_str, tmp_str);
    548 	  break;
    549 	case CLASS_BA:
    550           if (is_segmented)
    551             sprintf (tmp_str, "rr%ld(#0x%lx)", instr_data->arg_reg[datum_value],
    552                      instr_data->immediate);
    553           else
    554             sprintf (tmp_str, "r%ld(#0x%lx)", instr_data->arg_reg[datum_value],
    555                      instr_data->immediate);
    556 	  strcat (out_str, tmp_str);
    557 	  break;
    558 	case CLASS_BX:
    559           if (is_segmented)
    560             sprintf (tmp_str, "rr%ld(r%ld)", instr_data->arg_reg[datum_value],
    561                      instr_data->arg_reg[ARG_RX]);
    562           else
    563             sprintf (tmp_str, "r%ld(r%ld)", instr_data->arg_reg[datum_value],
    564                      instr_data->arg_reg[ARG_RX]);
    565 	  strcat (out_str, tmp_str);
    566 	  break;
    567 	case CLASS_DISP:
    568 	  sprintf (tmp_str, "0x%0lx", instr_data->displacement);
    569 	  strcat (out_str, tmp_str);
    570 	  break;
    571 	case CLASS_IMM:
    572 	  if (datum_value == ARG_IMM2)	/* True with EI/DI instructions only.  */
    573 	    {
    574 	      print_intr (tmp_str, instr_data->interrupts);
    575 	      strcat (out_str, tmp_str);
    576 	      break;
    577 	    }
    578 	  sprintf (tmp_str, "#0x%0lx", instr_data->immediate);
    579 	  strcat (out_str, tmp_str);
    580 	  break;
    581 	case CLASS_CC:
    582 	  sprintf (tmp_str, "%s", codes[instr_data->cond_code]);
    583 	  strcat (out_str, tmp_str);
    584 	  break;
    585 	case CLASS_CTRL:
    586 	  sprintf (tmp_str, "%s", ctrl_names[instr_data->ctrl_code]);
    587 	  strcat (out_str, tmp_str);
    588 	  break;
    589 	case CLASS_DA:
    590 	case CLASS_ADDRESS:
    591 	  sprintf (tmp_str, "0x%0lx", instr_data->address);
    592 	  strcat (out_str, tmp_str);
    593 	  break;
    594 	case CLASS_IR:
    595 	  if (is_segmented)
    596 	    sprintf (tmp_str, "@rr%ld", instr_data->arg_reg[datum_value]);
    597 	  else
    598 	    sprintf (tmp_str, "@r%ld", instr_data->arg_reg[datum_value]);
    599 	  strcat (out_str, tmp_str);
    600 	  break;
    601 	case CLASS_IRO:
    602           sprintf (tmp_str, "@r%ld", instr_data->arg_reg[datum_value]);
    603 	  strcat (out_str, tmp_str);
    604 	  break;
    605 	case CLASS_FLAGS:
    606 	  print_flags(tmp_str, instr_data->flags);
    607 	  strcat (out_str, tmp_str);
    608 	  break;
    609 	case CLASS_REG_BYTE:
    610 	  if (instr_data->arg_reg[datum_value] >= 0x8)
    611 	    sprintf (tmp_str, "rl%ld",
    612 		     instr_data->arg_reg[datum_value] - 0x8);
    613 	  else
    614 	    sprintf (tmp_str, "rh%ld", instr_data->arg_reg[datum_value]);
    615 	  strcat (out_str, tmp_str);
    616 	  break;
    617 	case CLASS_REG_WORD:
    618 	  sprintf (tmp_str, "r%ld", instr_data->arg_reg[datum_value]);
    619 	  strcat (out_str, tmp_str);
    620 	  break;
    621 	case CLASS_REG_QUAD:
    622 	  sprintf (tmp_str, "rq%ld", instr_data->arg_reg[datum_value]);
    623 	  strcat (out_str, tmp_str);
    624 	  break;
    625 	case CLASS_REG_LONG:
    626 	  sprintf (tmp_str, "rr%ld", instr_data->arg_reg[datum_value]);
    627 	  strcat (out_str, tmp_str);
    628 	  break;
    629 	case CLASS_PR:
    630 	  if (is_segmented)
    631 	    sprintf (tmp_str, "rr%ld", instr_data->arg_reg[datum_value]);
    632 	  else
    633 	    sprintf (tmp_str, "r%ld", instr_data->arg_reg[datum_value]);
    634 	  strcat (out_str, tmp_str);
    635 	  break;
    636 	default:
    637 	  abort ();
    638 	  break;
    639 	}
    640     }
    641 
    642   strcpy (instr_data->instr_asmsrc, out_str);
    643 }
    644