Home | History | Annotate | Line # | Download | only in opcodes
s390-mkopc.c revision 1.3.2.1
      1 /* s390-mkopc.c -- Generates opcode table out of s390-opc.txt
      2    Copyright (C) 2000-2015 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: fprintf (stderr, "Unknown tag char: %c\n", *tag);
    244     }
    245 
    246   for (i = 0; i < ext_table_length; i++)
    247     {
    248       char new_mnemonic[15];
    249 
    250       strcpy (new_mnemonic, prefix);
    251       opcode[mask_start] = ext_table[i].nibble;
    252       strcat (new_mnemonic, ext_table[i].extension);
    253       strcat (new_mnemonic, suffix);
    254       insertOpcode (opcode, new_mnemonic, format, min_cpu, mode_bits, flags);
    255     }
    256   return;
    257 
    258  malformed_mnemonic:
    259   fprintf (stderr, "Malformed mnemonic: %s\n", mnemonic);
    260 }
    261 
    262 static const char file_header[] =
    263   "/* The opcode table. This file was generated by s390-mkopc.\n\n"
    264   "   The format of the opcode table is:\n\n"
    265   "   NAME	     OPCODE	MASK	OPERANDS\n\n"
    266   "   Name is the name of the instruction.\n"
    267   "   OPCODE is the instruction opcode.\n"
    268   "   MASK is the opcode mask; this is used to tell the disassembler\n"
    269   "     which bits in the actual opcode must match OPCODE.\n"
    270   "   OPERANDS is the list of operands.\n\n"
    271   "   The disassembler reads the table in order and prints the first\n"
    272   "   instruction which matches.\n"
    273   "   MODE_BITS - zarch or esa\n"
    274   "   MIN_CPU - number of the min cpu level required\n"
    275   "   FLAGS - instruction flags.  */\n\n"
    276   "const struct s390_opcode s390_opcodes[] =\n  {\n";
    277 
    278 /* `dumpTable': write opcode table.  */
    279 
    280 static void
    281 dumpTable (void)
    282 {
    283   char *str;
    284   int  ix;
    285 
    286   /*  Write hash table entries (slots).  */
    287   printf ("%s", file_header);
    288 
    289   for (ix = 0; ix < no_ops; ix++)
    290     {
    291       printf ("  { \"%s\", ", op_array[ix].mnemonic);
    292       for (str = op_array[ix].opcode; *str != 0; str++)
    293 	if (*str == '?')
    294 	  *str = '0';
    295       printf ("OP%i(0x%sLL), ",
    296 	      op_array[ix].no_nibbles*4, op_array[ix].opcode);
    297       printf ("MASK_%s, INSTR_%s, ",
    298 	      op_array[ix].format, op_array[ix].format);
    299       printf ("%i, ", op_array[ix].mode_bits);
    300       printf ("%i, ", op_array[ix].min_cpu);
    301       printf ("%i}", op_array[ix].flags);
    302       if (ix < no_ops-1)
    303 	printf (",\n");
    304       else
    305 	printf ("\n");
    306     }
    307   printf ("};\n\n");
    308   printf ("const int s390_num_opcodes =\n");
    309   printf ("  sizeof (s390_opcodes) / sizeof (s390_opcodes[0]);\n\n");
    310 }
    311 
    312 int
    313 main (void)
    314 {
    315   char currentLine[256];
    316 
    317   createTable ();
    318 
    319   /*  Read opcode descriptions from `stdin'.  For each mnemonic,
    320       make an entry into the opcode table.  */
    321   while (fgets (currentLine, sizeof (currentLine), stdin) != NULL)
    322     {
    323       char  opcode[16];
    324       char  mnemonic[16];
    325       char  format[16];
    326       char  description[80];
    327       char  cpu_string[16];
    328       char  modes_string[16];
    329       char  flags_string[80];
    330       int   min_cpu;
    331       int   mode_bits;
    332       int   flag_bits;
    333       int   num_matched;
    334       char  *str;
    335 
    336       if (currentLine[0] == '#' || currentLine[0] == '\n')
    337         continue;
    338       memset (opcode, 0, 8);
    339       num_matched =
    340 	sscanf (currentLine, "%15s %15s %15s \"%79[^\"]\" %15s %15s %79[^\n]",
    341 		opcode, mnemonic, format, description,
    342 		cpu_string, modes_string, flags_string);
    343       if (num_matched != 6 && num_matched != 7)
    344 	{
    345 	  fprintf (stderr, "Couldn't scan line %s\n", currentLine);
    346 	  exit (1);
    347 	}
    348 
    349       if (strcmp (cpu_string, "g5") == 0)
    350 	min_cpu = S390_OPCODE_G5;
    351       else if (strcmp (cpu_string, "g6") == 0)
    352 	min_cpu = S390_OPCODE_G6;
    353       else if (strcmp (cpu_string, "z900") == 0)
    354 	min_cpu = S390_OPCODE_Z900;
    355       else if (strcmp (cpu_string, "z990") == 0)
    356 	min_cpu = S390_OPCODE_Z990;
    357       else if (strcmp (cpu_string, "z9-109") == 0)
    358 	min_cpu = S390_OPCODE_Z9_109;
    359       else if (strcmp (cpu_string, "z9-ec") == 0)
    360 	min_cpu = S390_OPCODE_Z9_EC;
    361       else if (strcmp (cpu_string, "z10") == 0)
    362 	min_cpu = S390_OPCODE_Z10;
    363       else if (strcmp (cpu_string, "z196") == 0)
    364 	min_cpu = S390_OPCODE_Z196;
    365       else if (strcmp (cpu_string, "zEC12") == 0)
    366 	min_cpu = S390_OPCODE_ZEC12;
    367       else if (strcmp (cpu_string, "z13") == 0)
    368 	min_cpu = S390_OPCODE_Z13;
    369       else {
    370 	fprintf (stderr, "Couldn't parse cpu string %s\n", cpu_string);
    371 	exit (1);
    372       }
    373 
    374       str = modes_string;
    375       mode_bits = 0;
    376       do {
    377 	if (strncmp (str, "esa", 3) == 0
    378 	    && (str[3] == 0 || str[3] == ',')) {
    379 	  mode_bits |= 1 << S390_OPCODE_ESA;
    380 	  str += 3;
    381 	} else if (strncmp (str, "zarch", 5) == 0
    382 		   && (str[5] == 0 || str[5] == ',')) {
    383 	  mode_bits |= 1 << S390_OPCODE_ZARCH;
    384 	  str += 5;
    385 	} else {
    386 	  fprintf (stderr, "Couldn't parse modes string %s\n",
    387 		   modes_string);
    388 	  exit (1);
    389 	}
    390 	if (*str == ',')
    391 	  str++;
    392       } while (*str != 0);
    393 
    394       flag_bits = 0;
    395 
    396       if (num_matched == 7)
    397 	{
    398 	  str = flags_string;
    399 	  do {
    400 	    if (strncmp (str, "optparm", 7) == 0
    401 		&& (str[7] == 0 || str[7] == ',')) {
    402 	      flag_bits |= S390_INSTR_FLAG_OPTPARM;
    403 	      str += 7;
    404 	    } else {
    405 	      fprintf (stderr, "Couldn't parse flags string %s\n",
    406 		       flags_string);
    407 	      exit (1);
    408 	    }
    409 	    if (*str == ',')
    410 	      str++;
    411 	  } while (*str != 0);
    412 	}
    413       insertExpandedMnemonic (opcode, mnemonic, format, min_cpu, mode_bits, flag_bits);
    414     }
    415 
    416   dumpTable ();
    417   return 0;
    418 }
    419