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