Home | History | Annotate | Line # | Download | only in opcodes
s390-mkopc.c revision 1.1.1.7
      1 /* s390-mkopc.c -- Generates opcode table out of s390-opc.txt
      2    Copyright (C) 2000-2020 Free Software Foundation, Inc.
      3    Contributed by Martin Schwidefsky (schwidefsky (at) de.ibm.com).
      4 
      5    This file is part of the GNU opcodes library.
      6 
      7    This library is free software; you can redistribute it and/or modify
      8    it under the terms of the GNU General Public License as published by
      9    the Free Software Foundation; either version 3, or (at your option)
     10    any later version.
     11 
     12    It is distributed in the hope that it will be useful, but WITHOUT
     13    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
     14    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
     15    License for more details.
     16 
     17    You should have received a copy of the GNU General Public License
     18    along with this file; see the file COPYING.  If not, write to the
     19    Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston,
     20    MA 02110-1301, USA.  */
     21 
     22 #include <stdio.h>
     23 #include <stdlib.h>
     24 #include <string.h>
     25 #include "opcode/s390.h"
     26 
     27 struct op_struct
     28   {
     29     char  opcode[16];
     30     char  mnemonic[16];
     31     char  format[16];
     32     int   mode_bits;
     33     int   min_cpu;
     34     int   flags;
     35 
     36     unsigned long long sort_value;
     37     int   no_nibbles;
     38   };
     39 
     40 struct op_struct *op_array;
     41 int max_ops;
     42 int no_ops;
     43 
     44 static void
     45 createTable (void)
     46 {
     47   max_ops = 256;
     48   op_array = malloc (max_ops * sizeof (struct op_struct));
     49   no_ops = 0;
     50 }
     51 
     52 /* `insertOpcode': insert an op_struct into sorted opcode array.  */
     53 
     54 static void
     55 insertOpcode (char *opcode, char *mnemonic, char *format,
     56 	      int min_cpu, int mode_bits, int flags)
     57 {
     58   char *str;
     59   unsigned long long sort_value;
     60   int no_nibbles;
     61   int ix, k;
     62 
     63   while (no_ops >= max_ops)
     64     {
     65       max_ops = max_ops * 2;
     66       op_array = realloc (op_array, max_ops * sizeof (struct op_struct));
     67     }
     68 
     69   sort_value = 0;
     70   str = opcode;
     71   for (ix = 0; ix < 16; ix++)
     72     {
     73       if (*str >= '0' && *str <= '9')
     74 	sort_value = (sort_value << 4) + (*str - '0');
     75       else if (*str >= 'a' && *str <= 'f')
     76 	sort_value = (sort_value << 4) + (*str - 'a' + 10);
     77       else if (*str >= 'A' && *str <= 'F')
     78 	sort_value = (sort_value << 4) + (*str - 'A' + 10);
     79       else if (*str == '?')
     80 	sort_value <<= 4;
     81       else
     82 	break;
     83       str ++;
     84     }
     85   sort_value <<= 4*(16 - ix);
     86   sort_value += (min_cpu << 8) + mode_bits;
     87   no_nibbles = ix;
     88   for (ix = 0; ix < no_ops; ix++)
     89     if (sort_value > op_array[ix].sort_value)
     90       break;
     91   for (k = no_ops; k > ix; k--)
     92     op_array[k] = op_array[k-1];
     93   strcpy(op_array[ix].opcode, opcode);
     94   strcpy(op_array[ix].mnemonic, mnemonic);
     95   strcpy(op_array[ix].format, format);
     96   op_array[ix].sort_value = sort_value;
     97   op_array[ix].no_nibbles = no_nibbles;
     98   op_array[ix].min_cpu = min_cpu;
     99   op_array[ix].mode_bits = mode_bits;
    100   op_array[ix].flags = flags;
    101   no_ops++;
    102 }
    103 
    104 struct s390_cond_ext_format
    105 {
    106   char nibble;
    107   char extension[4];
    108 };
    109 
    110 /* The mnemonic extensions for conditional jumps used to replace
    111    the '*' tag.  */
    112 #define NUM_COND_EXTENSIONS 20
    113 const struct s390_cond_ext_format s390_cond_extensions[NUM_COND_EXTENSIONS] =
    114 { { '1', "o" },    /* jump on overflow / if ones */
    115   { '2', "h" },    /* jump on A high */
    116   { '2', "p" },    /* jump on plus */
    117   { '3', "nle" },  /* jump on not low or equal */
    118   { '4', "l" },    /* jump on A low */
    119   { '4', "m" },    /* jump on minus / if mixed */
    120   { '5', "nhe" },  /* jump on not high or equal */
    121   { '6', "lh" },   /* jump on low or high */
    122   { '7', "ne" },   /* jump on A not equal B */
    123   { '7', "nz" },   /* jump on not zero / if not zeros */
    124   { '8', "e" },    /* jump on A equal B */
    125   { '8', "z" },    /* jump on zero / if zeros */
    126   { '9', "nlh" },  /* jump on not low or high */
    127   { 'a', "he" },   /* jump on high or equal */
    128   { 'b', "nl" },   /* jump on A not low */
    129   { 'b', "nm" },   /* jump on not minus / if not mixed */
    130   { 'c', "le" },   /* jump on low or equal */
    131   { 'd', "nh" },   /* jump on A not high */
    132   { 'd', "np" },   /* jump on not plus */
    133   { 'e', "no" },   /* jump on not overflow / if not ones */
    134 };
    135 
    136 /* The mnemonic extensions for conditional branches used to replace
    137    the '$' tag.  */
    138 #define NUM_CRB_EXTENSIONS 12
    139 const struct s390_cond_ext_format s390_crb_extensions[NUM_CRB_EXTENSIONS] =
    140 { { '2', "h" },    /* jump on A high */
    141   { '2', "nle" },  /* jump on not low or equal */
    142   { '4', "l" },    /* jump on A low */
    143   { '4', "nhe" },  /* jump on not high or equal */
    144   { '6', "ne" },   /* jump on A not equal B */
    145   { '6', "lh" },   /* jump on low or high */
    146   { '8', "e" },    /* jump on A equal B */
    147   { '8', "nlh" },  /* jump on not low or high */
    148   { 'a', "nl" },   /* jump on A not low */
    149   { 'a', "he" },   /* jump on high or equal */
    150   { 'c', "nh" },   /* jump on A not high */
    151   { 'c', "le" },   /* jump on low or equal */
    152 };
    153 
    154 /* As with insertOpcode instructions are added to the sorted opcode
    155    array.  Additionally mnemonics containing the '*<number>' tag are
    156    expanded to the set of conditional instructions described by
    157    s390_cond_extensions with the tag replaced by the respective
    158    mnemonic extensions.  */
    159 
    160 static void
    161 insertExpandedMnemonic (char *opcode, char *mnemonic, char *format,
    162 			int min_cpu, int mode_bits, int flags)
    163 {
    164   char *tag;
    165   char prefix[15];
    166   char suffix[15];
    167   char number[15];
    168   int mask_start, i = 0, tag_found = 0, reading_number = 0;
    169   int number_p = 0, suffix_p = 0, prefix_p = 0;
    170   const struct s390_cond_ext_format *ext_table;
    171   int ext_table_length;
    172 
    173   if (!(tag = strpbrk (mnemonic, "*$")))
    174     {
    175       insertOpcode (opcode, mnemonic, format, min_cpu, mode_bits, flags);
    176       return;
    177     }
    178 
    179   while (mnemonic[i] != '\0')
    180     {
    181       if (mnemonic[i] == *tag)
    182 	{
    183 	  if (tag_found)
    184 	    goto malformed_mnemonic;
    185 
    186 	  tag_found = 1;
    187 	  reading_number = 1;
    188 	}
    189       else
    190 	switch (mnemonic[i])
    191 	  {
    192 	  case '0': case '1': case '2': case '3': case '4':
    193 	  case '5': case '6': case '7': case '8': case '9':
    194 	    if (!tag_found || !reading_number)
    195 	      goto malformed_mnemonic;
    196 
    197 	    number[number_p++] = mnemonic[i];
    198 	    break;
    199 
    200 	  default:
    201 	    if (reading_number)
    202 	      {
    203 		if (!number_p)
    204 		  goto malformed_mnemonic;
    205 		else
    206 		  reading_number = 0;
    207 	      }
    208 
    209 	    if (tag_found)
    210 	      suffix[suffix_p++] = mnemonic[i];
    211 	    else
    212 	      prefix[prefix_p++] = mnemonic[i];
    213 	  }
    214       i++;
    215     }
    216 
    217   prefix[prefix_p] = '\0';
    218   suffix[suffix_p] = '\0';
    219   number[number_p] = '\0';
    220 
    221   if (sscanf (number, "%d", &mask_start) != 1)
    222     goto malformed_mnemonic;
    223 
    224   if (mask_start & 3)
    225     {
    226       fprintf (stderr, "Conditional mask not at nibble boundary in: %s\n",
    227 	       mnemonic);
    228       return;
    229     }
    230 
    231   mask_start >>= 2;
    232 
    233   switch (*tag)
    234     {
    235     case '*':
    236       ext_table = s390_cond_extensions;
    237       ext_table_length = NUM_COND_EXTENSIONS;
    238       break;
    239     case '$':
    240       ext_table = s390_crb_extensions;
    241       ext_table_length = NUM_CRB_EXTENSIONS;
    242       break;
    243     default:
    244       abort ();			/* Should be unreachable.  */
    245     }
    246 
    247   for (i = 0; i < ext_table_length; i++)
    248     {
    249       char new_mnemonic[15];
    250 
    251       strcpy (new_mnemonic, prefix);
    252       opcode[mask_start] = ext_table[i].nibble;
    253       strcat (new_mnemonic, ext_table[i].extension);
    254       strcat (new_mnemonic, suffix);
    255       insertOpcode (opcode, new_mnemonic, format, min_cpu, mode_bits, flags);
    256     }
    257   return;
    258 
    259  malformed_mnemonic:
    260   fprintf (stderr, "Malformed mnemonic: %s\n", mnemonic);
    261 }
    262 
    263 static const char file_header[] =
    264   "/* The opcode table. This file was generated by s390-mkopc.\n\n"
    265   "   The format of the opcode table is:\n\n"
    266   "   NAME	     OPCODE	MASK	OPERANDS\n\n"
    267   "   Name is the name of the instruction.\n"
    268   "   OPCODE is the instruction opcode.\n"
    269   "   MASK is the opcode mask; this is used to tell the disassembler\n"
    270   "     which bits in the actual opcode must match OPCODE.\n"
    271   "   OPERANDS is the list of operands.\n\n"
    272   "   The disassembler reads the table in order and prints the first\n"
    273   "   instruction which matches.\n"
    274   "   MODE_BITS - zarch or esa\n"
    275   "   MIN_CPU - number of the min cpu level required\n"
    276   "   FLAGS - instruction flags.  */\n\n"
    277   "const struct s390_opcode s390_opcodes[] =\n  {\n";
    278 
    279 /* `dumpTable': write opcode table.  */
    280 
    281 static void
    282 dumpTable (void)
    283 {
    284   char *str;
    285   int  ix;
    286 
    287   /*  Write hash table entries (slots).  */
    288   printf ("%s", file_header);
    289 
    290   for (ix = 0; ix < no_ops; ix++)
    291     {
    292       printf ("  { \"%s\", ", op_array[ix].mnemonic);
    293       for (str = op_array[ix].opcode; *str != 0; str++)
    294 	if (*str == '?')
    295 	  *str = '0';
    296       printf ("OP%i(0x%sLL), ",
    297 	      op_array[ix].no_nibbles*4, op_array[ix].opcode);
    298       printf ("MASK_%s, INSTR_%s, ",
    299 	      op_array[ix].format, op_array[ix].format);
    300       printf ("%i, ", op_array[ix].mode_bits);
    301       printf ("%i, ", op_array[ix].min_cpu);
    302       printf ("%i}", op_array[ix].flags);
    303       if (ix < no_ops-1)
    304 	printf (",\n");
    305       else
    306 	printf ("\n");
    307     }
    308   printf ("};\n\n");
    309   printf ("const int s390_num_opcodes =\n");
    310   printf ("  sizeof (s390_opcodes) / sizeof (s390_opcodes[0]);\n\n");
    311 }
    312 
    313 int
    314 main (void)
    315 {
    316   char currentLine[256];
    317 
    318   createTable ();
    319 
    320   /*  Read opcode descriptions from `stdin'.  For each mnemonic,
    321       make an entry into the opcode table.  */
    322   while (fgets (currentLine, sizeof (currentLine), stdin) != NULL)
    323     {
    324       char  opcode[16];
    325       char  mnemonic[16];
    326       char  format[16];
    327       char  description[80];
    328       char  cpu_string[16];
    329       char  modes_string[16];
    330       char  flags_string[80];
    331       int   min_cpu;
    332       int   mode_bits;
    333       int   flag_bits;
    334       int   num_matched;
    335       char  *str;
    336 
    337       if (currentLine[0] == '#' || currentLine[0] == '\n')
    338 	continue;
    339       memset (opcode, 0, 8);
    340       num_matched =
    341 	sscanf (currentLine, "%15s %15s %15s \"%79[^\"]\" %15s %15s %79[^\n]",
    342 		opcode, mnemonic, format, description,
    343 		cpu_string, modes_string, flags_string);
    344       if (num_matched != 6 && num_matched != 7)
    345 	{
    346 	  fprintf (stderr, "Couldn't scan line %s\n", currentLine);
    347 	  exit (1);
    348 	}
    349 
    350       if (strcmp (cpu_string, "g5") == 0
    351 	  || strcmp (cpu_string, "arch3") == 0)
    352 	min_cpu = S390_OPCODE_G5;
    353       else if (strcmp (cpu_string, "g6") == 0)
    354 	min_cpu = S390_OPCODE_G6;
    355       else if (strcmp (cpu_string, "z900") == 0
    356 	       || strcmp (cpu_string, "arch5") == 0)
    357 	min_cpu = S390_OPCODE_Z900;
    358       else if (strcmp (cpu_string, "z990") == 0
    359 	       || strcmp (cpu_string, "arch6") == 0)
    360 	min_cpu = S390_OPCODE_Z990;
    361       else if (strcmp (cpu_string, "z9-109") == 0)
    362 	min_cpu = S390_OPCODE_Z9_109;
    363       else if (strcmp (cpu_string, "z9-ec") == 0
    364 	       || strcmp (cpu_string, "arch7") == 0)
    365 	min_cpu = S390_OPCODE_Z9_EC;
    366       else if (strcmp (cpu_string, "z10") == 0
    367 	       || strcmp (cpu_string, "arch8") == 0)
    368 	min_cpu = S390_OPCODE_Z10;
    369       else if (strcmp (cpu_string, "z196") == 0
    370 	       || strcmp (cpu_string, "arch9") == 0)
    371 	min_cpu = S390_OPCODE_Z196;
    372       else if (strcmp (cpu_string, "zEC12") == 0
    373 	       || strcmp (cpu_string, "arch10") == 0)
    374 	min_cpu = S390_OPCODE_ZEC12;
    375       else if (strcmp (cpu_string, "z13") == 0
    376 	       || strcmp (cpu_string, "arch11") == 0)
    377 	min_cpu = S390_OPCODE_Z13;
    378       else if (strcmp (cpu_string, "z14") == 0
    379 	       || strcmp (cpu_string, "arch12") == 0)
    380 	min_cpu = S390_OPCODE_ARCH12;
    381       else if (strcmp (cpu_string, "z15") == 0
    382 	       || strcmp (cpu_string, "arch13") == 0)
    383 	min_cpu = S390_OPCODE_ARCH13;
    384       else {
    385 	fprintf (stderr, "Couldn't parse cpu string %s\n", cpu_string);
    386 	exit (1);
    387       }
    388 
    389       str = modes_string;
    390       mode_bits = 0;
    391       do {
    392 	if (strncmp (str, "esa", 3) == 0
    393 	    && (str[3] == 0 || str[3] == ',')) {
    394 	  mode_bits |= 1 << S390_OPCODE_ESA;
    395 	  str += 3;
    396 	} else if (strncmp (str, "zarch", 5) == 0
    397 		   && (str[5] == 0 || str[5] == ',')) {
    398 	  mode_bits |= 1 << S390_OPCODE_ZARCH;
    399 	  str += 5;
    400 	} else {
    401 	  fprintf (stderr, "Couldn't parse modes string %s\n",
    402 		   modes_string);
    403 	  exit (1);
    404 	}
    405 	if (*str == ',')
    406 	  str++;
    407       } while (*str != 0);
    408 
    409       flag_bits = 0;
    410 
    411       if (num_matched == 7)
    412 	{
    413 	  str = flags_string;
    414 	  do {
    415 	    if (strncmp (str, "optparm", 7) == 0
    416 		&& (str[7] == 0 || str[7] == ',')) {
    417 	      flag_bits |= S390_INSTR_FLAG_OPTPARM;
    418 	      str += 7;
    419 	    } else if (strncmp (str, "optparm2", 8) == 0
    420 		       && (str[8] == 0 || str[8] == ',')) {
    421 	      flag_bits |= S390_INSTR_FLAG_OPTPARM2;
    422 	      str += 8;
    423 	    } else if (strncmp (str, "htm", 3) == 0
    424 		       && (str[3] == 0 || str[3] == ',')) {
    425 	      flag_bits |= S390_INSTR_FLAG_HTM;
    426 	      str += 3;
    427 	    } else if (strncmp (str, "vx", 2) == 0
    428 		       && (str[2] == 0 || str[2] == ',')) {
    429 	      flag_bits |= S390_INSTR_FLAG_VX;
    430 	      str += 2;
    431 	    } else {
    432 	      fprintf (stderr, "Couldn't parse flags string %s\n",
    433 		       flags_string);
    434 	      exit (1);
    435 	    }
    436 	    if (*str == ',')
    437 	      str++;
    438 	  } while (*str != 0);
    439 	}
    440       insertExpandedMnemonic (opcode, mnemonic, format, min_cpu, mode_bits, flag_bits);
    441     }
    442 
    443   dumpTable ();
    444   return 0;
    445 }
    446