Home | History | Annotate | Line # | Download | only in opcodes
s390-mkopc.c revision 1.1
      1 /* s390-mkopc.c -- Generates opcode table out of s390-opc.txt
      2    Copyright 2000, 2001, 2003, 2005, 2007, 2008 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 
     26 /* Taken from opcodes/s390.h */
     27 enum s390_opcode_mode_val
     28   {
     29     S390_OPCODE_ESA = 0,
     30     S390_OPCODE_ZARCH
     31   };
     32 
     33 enum s390_opcode_cpu_val
     34   {
     35     S390_OPCODE_G5 = 0,
     36     S390_OPCODE_G6,
     37     S390_OPCODE_Z900,
     38     S390_OPCODE_Z990,
     39     S390_OPCODE_Z9_109,
     40     S390_OPCODE_Z9_EC,
     41     S390_OPCODE_Z10,
     42     S390_OPCODE_Z196
     43   };
     44 
     45 struct op_struct
     46   {
     47     char  opcode[16];
     48     char  mnemonic[16];
     49     char  format[16];
     50     int   mode_bits;
     51     int   min_cpu;
     52 
     53     unsigned long long sort_value;
     54     int   no_nibbles;
     55   };
     56 
     57 struct op_struct *op_array;
     58 int max_ops;
     59 int no_ops;
     60 
     61 static void
     62 createTable (void)
     63 {
     64   max_ops = 256;
     65   op_array = malloc (max_ops * sizeof (struct op_struct));
     66   no_ops = 0;
     67 }
     68 
     69 /* `insertOpcode': insert an op_struct into sorted opcode array.  */
     70 
     71 static void
     72 insertOpcode (char *opcode, char *mnemonic, char *format,
     73 	      int min_cpu, int mode_bits)
     74 {
     75   char *str;
     76   unsigned long long sort_value;
     77   int no_nibbles;
     78   int ix, k;
     79 
     80   while (no_ops >= max_ops)
     81     {
     82       max_ops = max_ops * 2;
     83       op_array = realloc (op_array, max_ops * sizeof (struct op_struct));
     84     }
     85 
     86   sort_value = 0;
     87   str = opcode;
     88   for (ix = 0; ix < 16; ix++)
     89     {
     90       if (*str >= '0' && *str <= '9')
     91 	sort_value = (sort_value << 4) + (*str - '0');
     92       else if (*str >= 'a' && *str <= 'f')
     93 	sort_value = (sort_value << 4) + (*str - 'a' + 10);
     94       else if (*str >= 'A' && *str <= 'F')
     95 	sort_value = (sort_value << 4) + (*str - 'A' + 10);
     96       else if (*str == '?')
     97 	sort_value <<= 4;
     98       else
     99 	break;
    100       str ++;
    101     }
    102   sort_value <<= 4*(16 - ix);
    103   sort_value += (min_cpu << 8) + mode_bits;
    104   no_nibbles = ix;
    105   for (ix = 0; ix < no_ops; ix++)
    106     if (sort_value > op_array[ix].sort_value)
    107       break;
    108   for (k = no_ops; k > ix; k--)
    109     op_array[k] = op_array[k-1];
    110   strcpy(op_array[ix].opcode, opcode);
    111   strcpy(op_array[ix].mnemonic, mnemonic);
    112   strcpy(op_array[ix].format, format);
    113   op_array[ix].sort_value = sort_value;
    114   op_array[ix].no_nibbles = no_nibbles;
    115   op_array[ix].min_cpu = min_cpu;
    116   op_array[ix].mode_bits = mode_bits;
    117   no_ops++;
    118 }
    119 
    120 struct s390_cond_ext_format
    121 {
    122   char nibble;
    123   char extension[4];
    124 };
    125 
    126 /* The mnemonic extensions for conditional jumps used to replace
    127    the '*' tag.  */
    128 #define NUM_COND_EXTENSIONS 20
    129 const struct s390_cond_ext_format s390_cond_extensions[NUM_COND_EXTENSIONS] =
    130 { { '1', "o" },    /* jump on overflow / if ones */
    131   { '2', "h" },    /* jump on A high */
    132   { '2', "p" },    /* jump on plus */
    133   { '3', "nle" },  /* jump on not low or equal */
    134   { '4', "l" },    /* jump on A low */
    135   { '4', "m" },    /* jump on minus / if mixed */
    136   { '5', "nhe" },  /* jump on not high or equal */
    137   { '6', "lh" },   /* jump on low or high */
    138   { '7', "ne" },   /* jump on A not equal B */
    139   { '7', "nz" },   /* jump on not zero / if not zeros */
    140   { '8', "e" },    /* jump on A equal B */
    141   { '8', "z" },    /* jump on zero / if zeros */
    142   { '9', "nlh" },  /* jump on not low or high */
    143   { 'a', "he" },   /* jump on high or equal */
    144   { 'b', "nl" },   /* jump on A not low */
    145   { 'b', "nm" },   /* jump on not minus / if not mixed */
    146   { 'c', "le" },   /* jump on low or equal */
    147   { 'd', "nh" },   /* jump on A not high */
    148   { 'd', "np" },   /* jump on not plus */
    149   { 'e', "no" },   /* jump on not overflow / if not ones */
    150 };
    151 
    152 /* The mnemonic extensions for conditional branches used to replace
    153    the '$' tag.  */
    154 #define NUM_CRB_EXTENSIONS 12
    155 const struct s390_cond_ext_format s390_crb_extensions[NUM_CRB_EXTENSIONS] =
    156 { { '2', "h" },    /* jump on A high */
    157   { '2', "nle" },  /* jump on not low or equal */
    158   { '4', "l" },    /* jump on A low */
    159   { '4', "nhe" },  /* jump on not high or equal */
    160   { '6', "ne" },   /* jump on A not equal B */
    161   { '6', "lh" },   /* jump on low or high */
    162   { '8', "e" },    /* jump on A equal B */
    163   { '8', "nlh" },  /* jump on not low or high */
    164   { 'a', "nl" },   /* jump on A not low */
    165   { 'a', "he" },   /* jump on high or equal */
    166   { 'c', "nh" },   /* jump on A not high */
    167   { 'c', "le" },   /* jump on low or equal */
    168 };
    169 
    170 /* As with insertOpcode instructions are added to the sorted opcode
    171    array.  Additionally mnemonics containing the '*<number>' tag are
    172    expanded to the set of conditional instructions described by
    173    s390_cond_extensions with the tag replaced by the respective
    174    mnemonic extensions.  */
    175 
    176 static void
    177 insertExpandedMnemonic (char *opcode, char *mnemonic, char *format,
    178 			int min_cpu, int mode_bits)
    179 {
    180   char *tag;
    181   char prefix[15];
    182   char suffix[15];
    183   char number[15];
    184   int mask_start, i = 0, tag_found = 0, reading_number = 0;
    185   int number_p = 0, suffix_p = 0, prefix_p = 0;
    186   const struct s390_cond_ext_format *ext_table;
    187   int ext_table_length;
    188 
    189   if (!(tag = strpbrk (mnemonic, "*$")))
    190     {
    191       insertOpcode (opcode, mnemonic, format, min_cpu, mode_bits);
    192       return;
    193     }
    194 
    195   while (mnemonic[i] != '\0')
    196     {
    197       if (mnemonic[i] == *tag)
    198 	{
    199 	  if (tag_found)
    200 	    goto malformed_mnemonic;
    201 
    202 	  tag_found = 1;
    203 	  reading_number = 1;
    204 	}
    205       else
    206 	switch (mnemonic[i])
    207 	  {
    208 	  case '0': case '1': case '2': case '3': case '4':
    209 	  case '5': case '6': case '7': case '8': case '9':
    210 	    if (!tag_found || !reading_number)
    211 	      goto malformed_mnemonic;
    212 
    213 	    number[number_p++] = mnemonic[i];
    214 	    break;
    215 
    216 	  default:
    217 	    if (reading_number)
    218 	      {
    219 		if (!number_p)
    220 		  goto malformed_mnemonic;
    221 		else
    222 		  reading_number = 0;
    223 	      }
    224 
    225 	    if (tag_found)
    226 	      suffix[suffix_p++] = mnemonic[i];
    227 	    else
    228 	      prefix[prefix_p++] = mnemonic[i];
    229 	  }
    230       i++;
    231     }
    232 
    233   prefix[prefix_p] = '\0';
    234   suffix[suffix_p] = '\0';
    235   number[number_p] = '\0';
    236 
    237   if (sscanf (number, "%d", &mask_start) != 1)
    238     goto malformed_mnemonic;
    239 
    240   if (mask_start & 3)
    241     {
    242       fprintf (stderr, "Conditional mask not at nibble boundary in: %s\n",
    243 	       mnemonic);
    244       return;
    245     }
    246 
    247   mask_start >>= 2;
    248 
    249   switch (*tag)
    250     {
    251     case '*':
    252       ext_table = s390_cond_extensions;
    253       ext_table_length = NUM_COND_EXTENSIONS;
    254       break;
    255     case '$':
    256       ext_table = s390_crb_extensions;
    257       ext_table_length = NUM_CRB_EXTENSIONS;
    258       break;
    259     default: fprintf (stderr, "Unknown tag char: %c\n", *tag);
    260     }
    261 
    262   for (i = 0; i < ext_table_length; i++)
    263     {
    264       char new_mnemonic[15];
    265 
    266       strcpy (new_mnemonic, prefix);
    267       opcode[mask_start] = ext_table[i].nibble;
    268       strcat (new_mnemonic, ext_table[i].extension);
    269       strcat (new_mnemonic, suffix);
    270       insertOpcode (opcode, new_mnemonic, format, min_cpu, mode_bits);
    271     }
    272   return;
    273 
    274  malformed_mnemonic:
    275   fprintf (stderr, "Malformed mnemonic: %s\n", mnemonic);
    276 }
    277 
    278 static char file_header[] =
    279   "/* The opcode table. This file was generated by s390-mkopc.\n\n"
    280   "   The format of the opcode table is:\n\n"
    281   "   NAME	     OPCODE	MASK	OPERANDS\n\n"
    282   "   Name is the name of the instruction.\n"
    283   "   OPCODE is the instruction opcode.\n"
    284   "   MASK is the opcode mask; this is used to tell the disassembler\n"
    285   "     which bits in the actual opcode must match OPCODE.\n"
    286   "   OPERANDS is the list of operands.\n\n"
    287   "   The disassembler reads the table in order and prints the first\n"
    288   "   instruction which matches.  */\n\n"
    289   "const struct s390_opcode s390_opcodes[] =\n  {\n";
    290 
    291 /* `dumpTable': write opcode table.  */
    292 
    293 static void
    294 dumpTable (void)
    295 {
    296   char *str;
    297   int  ix;
    298 
    299   /*  Write hash table entries (slots).  */
    300   printf (file_header);
    301 
    302   for (ix = 0; ix < no_ops; ix++)
    303     {
    304       printf ("  { \"%s\", ", op_array[ix].mnemonic);
    305       for (str = op_array[ix].opcode; *str != 0; str++)
    306 	if (*str == '?')
    307 	  *str = '0';
    308       printf ("OP%i(0x%sLL), ",
    309 	      op_array[ix].no_nibbles*4, op_array[ix].opcode);
    310       printf ("MASK_%s, INSTR_%s, ",
    311 	      op_array[ix].format, op_array[ix].format);
    312       printf ("%i, ", op_array[ix].mode_bits);
    313       printf ("%i}", op_array[ix].min_cpu);
    314       if (ix < no_ops-1)
    315 	printf (",\n");
    316       else
    317 	printf ("\n");
    318     }
    319   printf ("};\n\n");
    320   printf ("const int s390_num_opcodes =\n");
    321   printf ("  sizeof (s390_opcodes) / sizeof (s390_opcodes[0]);\n\n");
    322 }
    323 
    324 int
    325 main (void)
    326 {
    327   char currentLine[256];
    328 
    329   createTable ();
    330 
    331   /*  Read opcode descriptions from `stdin'.  For each mnemonic,
    332       make an entry into the opcode table.  */
    333   while (fgets (currentLine, sizeof (currentLine), stdin) != NULL)
    334     {
    335       char  opcode[16];
    336       char  mnemonic[16];
    337       char  format[16];
    338       char  description[80];
    339       char  cpu_string[16];
    340       char  modes_string[16];
    341       int   min_cpu;
    342       int   mode_bits;
    343       char  *str;
    344 
    345       if (currentLine[0] == '#')
    346         continue;
    347       memset (opcode, 0, 8);
    348       if (sscanf (currentLine, "%15s %15s %15s \"%79[^\"]\" %15s %15s",
    349 		  opcode, mnemonic, format, description,
    350 		  cpu_string, modes_string) == 6)
    351 	{
    352 	  if (strcmp (cpu_string, "g5") == 0)
    353 	    min_cpu = S390_OPCODE_G5;
    354 	  else if (strcmp (cpu_string, "g6") == 0)
    355 	    min_cpu = S390_OPCODE_G6;
    356 	  else if (strcmp (cpu_string, "z900") == 0)
    357 	    min_cpu = S390_OPCODE_Z900;
    358 	  else if (strcmp (cpu_string, "z990") == 0)
    359 	    min_cpu = S390_OPCODE_Z990;
    360 	  else if (strcmp (cpu_string, "z9-109") == 0)
    361 	    min_cpu = S390_OPCODE_Z9_109;
    362 	  else if (strcmp (cpu_string, "z9-ec") == 0)
    363 	    min_cpu = S390_OPCODE_Z9_EC;
    364 	  else if (strcmp (cpu_string, "z10") == 0)
    365 	    min_cpu = S390_OPCODE_Z10;
    366 	  else if (strcmp (cpu_string, "z196") == 0)
    367 	    min_cpu = S390_OPCODE_Z196;
    368 	  else {
    369 	    fprintf (stderr, "Couldn't parse cpu string %s\n", cpu_string);
    370 	    exit (1);
    371 	  }
    372 
    373 	  str = modes_string;
    374 	  mode_bits = 0;
    375 	  do {
    376 	    if (strncmp (str, "esa", 3) == 0
    377 		&& (str[3] == 0 || str[3] == ',')) {
    378 	      mode_bits |= 1 << S390_OPCODE_ESA;
    379 	      str += 3;
    380 	    } else if (strncmp (str, "zarch", 5) == 0
    381 		       && (str[5] == 0 || str[5] == ',')) {
    382 	      mode_bits |= 1 << S390_OPCODE_ZARCH;
    383 	      str += 5;
    384 	    } else {
    385 	      fprintf (stderr, "Couldn't parse modes string %s\n",
    386 		       modes_string);
    387 	      exit (1);
    388 	    }
    389 	    if (*str == ',')
    390 	      str++;
    391 	  } while (*str != 0);
    392 
    393 	  insertExpandedMnemonic (opcode, mnemonic, format, min_cpu, mode_bits);
    394 	}
    395       else
    396 	{
    397 	  fprintf (stderr, "Couldn't scan line %s\n", currentLine);
    398 	  exit (1);
    399 	}
    400     }
    401 
    402   dumpTable ();
    403   return 0;
    404 }
    405