Home | History | Annotate | Line # | Download | only in opcodes
s390-mkopc.c revision 1.1.1.13
      1 /* s390-mkopc.c -- Generates opcode table out of s390-opc.txt
      2    Copyright (C) 2000-2025 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 <stdarg.h>
     25 #include <string.h>
     26 #include "opcode/s390.h"
     27 
     28 #define STRINGIFY(x) _STRINGIFY(x)
     29 #define _STRINGIFY(x) #x
     30 
     31 /* Length of strings without terminating '\0' character.  */
     32 #define MAX_OPCODE_LEN 15
     33 #define MAX_MNEMONIC_LEN 15
     34 #define MAX_FORMAT_LEN 15
     35 #define MAX_DESCRIPTION_LEN 127
     36 
     37 #define MAX_CPU_LEN 15
     38 #define MAX_MODES_LEN 15
     39 #define MAX_FLAGS_LEN 79
     40 
     41 /* Return code.  */
     42 int return_code = EXIT_SUCCESS;
     43 
     44 /* Helper to print an error message and set the return code.  */
     45 static void __attribute__ ((format (printf, 1, 2)))
     46 print_error (const char *fmt, ...)
     47 {
     48   va_list ap;
     49 
     50   va_start(ap, fmt);
     51   fprintf(stderr, "Error: ");
     52   vfprintf(stderr, fmt, ap);
     53   va_end(ap);
     54 
     55   return_code = EXIT_FAILURE;
     56 }
     57 
     58 struct op_struct
     59   {
     60     char  opcode[MAX_OPCODE_LEN + 1];
     61     char  mnemonic[MAX_MNEMONIC_LEN + 1];
     62     char  format[MAX_FORMAT_LEN + 1];
     63     int   mode_bits;
     64     int   min_cpu;
     65     int   flags;
     66     char  description[MAX_DESCRIPTION_LEN + 1];
     67 
     68     unsigned long long sort_value;
     69     int   no_nibbles;
     70   };
     71 
     72 struct op_struct *op_array;
     73 int max_ops;
     74 int no_ops;
     75 
     76 static void
     77 createTable (void)
     78 {
     79   max_ops = 256;
     80   op_array = malloc (max_ops * sizeof (struct op_struct));
     81   no_ops = 0;
     82 }
     83 
     84 /* `insertOpcode': insert an op_struct into sorted opcode array.  */
     85 
     86 static void
     87 insertOpcode (char *opcode, char *mnemonic, char *format,
     88 	      int min_cpu, int mode_bits, int flags, char* description)
     89 {
     90   char *str;
     91   unsigned long long sort_value;
     92   int no_nibbles;
     93   int ix, k;
     94 
     95   while (no_ops >= max_ops)
     96     {
     97       max_ops = max_ops * 2;
     98       op_array = realloc (op_array, max_ops * sizeof (struct op_struct));
     99     }
    100 
    101   sort_value = 0;
    102   str = opcode;
    103   for (ix = 0; ix < 16; ix++)
    104     {
    105       if (*str >= '0' && *str <= '9')
    106 	sort_value = (sort_value << 4) + (*str - '0');
    107       else if (*str >= 'a' && *str <= 'f')
    108 	sort_value = (sort_value << 4) + (*str - 'a' + 10);
    109       else if (*str >= 'A' && *str <= 'F')
    110 	sort_value = (sort_value << 4) + (*str - 'A' + 10);
    111       else if (*str == '?')
    112 	sort_value <<= 4;
    113       else
    114 	break;
    115       str ++;
    116     }
    117   sort_value <<= 4*(16 - ix);
    118   sort_value += (min_cpu << 8) + mode_bits;
    119   no_nibbles = ix;
    120   for (ix = 0; ix < no_ops; ix++)
    121     if (sort_value > op_array[ix].sort_value)
    122       break;
    123   for (k = no_ops; k > ix; k--)
    124     op_array[k] = op_array[k-1];
    125   strncpy (op_array[ix].opcode, opcode, MAX_OPCODE_LEN);
    126   op_array[ix].opcode[MAX_OPCODE_LEN] = '\0';
    127   strncpy (op_array[ix].mnemonic, mnemonic, MAX_MNEMONIC_LEN);
    128   op_array[ix].mnemonic[MAX_MNEMONIC_LEN] = '\0';
    129   strncpy (op_array[ix].format, format, MAX_FORMAT_LEN);
    130   op_array[ix].format[MAX_FORMAT_LEN] = '\0';
    131   op_array[ix].sort_value = sort_value;
    132   op_array[ix].no_nibbles = no_nibbles;
    133   op_array[ix].min_cpu = min_cpu;
    134   op_array[ix].mode_bits = mode_bits;
    135   op_array[ix].flags = flags;
    136   strncpy (op_array[ix].description, description, MAX_DESCRIPTION_LEN);
    137   op_array[ix].description[MAX_DESCRIPTION_LEN] = '\0';
    138   no_ops++;
    139 }
    140 
    141 struct s390_cond_ext_format
    142 {
    143   char nibble;
    144   char extension[4];
    145   char *description_suffix;
    146 
    147 };
    148 
    149 /* The mnemonic extensions for conditional jumps used to replace
    150    the '*' tag.  */
    151 #define NUM_COND_EXTENSIONS 20
    152 const struct s390_cond_ext_format s390_cond_extensions[NUM_COND_EXTENSIONS] =
    153 { { '1', "o", "on overflow / if ones" },	/* jump on overflow / if ones */
    154   { '2', "h", "on A high" },			/* jump on A high */
    155   { '2', "p", "on plus" },			/* jump on plus */
    156   { '3', "nle", "on not low or equal" },	/* jump on not low or equal */
    157   { '4', "l", "on A low" },			/* jump on A low */
    158   { '4', "m", "on minus / if mixed" },		/* jump on minus / if mixed */
    159   { '5', "nhe", "on not high or equal" },	/* jump on not high or equal */
    160   { '6', "lh", "on low or high" },		/* jump on low or high */
    161   { '7', "ne", "on A not equal B" },		/* jump on A not equal B */
    162   { '7', "nz", "on not zero / if not zeros" },	/* jump on not zero / if not zeros */
    163   { '8', "e", "on A equal B" },			/* jump on A equal B */
    164   { '8', "z", "on zero / if zeros" },		/* jump on zero / if zeros */
    165   { '9', "nlh", "on not low or high" },		/* jump on not low or high */
    166   { 'a', "he", "on high or equal" },		/* jump on high or equal */
    167   { 'b', "nl", "on A not low" },		/* jump on A not low */
    168   { 'b', "nm", "on not minus / if not mixed" },	/* jump on not minus / if not mixed */
    169   { 'c', "le", "on low or equal" },		/* jump on low or equal */
    170   { 'd', "nh", "on A not high" },		/* jump on A not high */
    171   { 'd', "np", "on not plus" },			/* jump on not plus */
    172   { 'e', "no", "on not overflow / if not ones" },/* jump on not overflow / if not ones */
    173 };
    174 
    175 /* The mnemonic extensions for conditional branches used to replace
    176    the '$' tag.  */
    177 #define NUM_CRB_EXTENSIONS 12
    178 const struct s390_cond_ext_format s390_crb_extensions[NUM_CRB_EXTENSIONS] =
    179 { { '2', "h", "on A high" },			/* jump on A high */
    180   { '2', "nle", "on not low or equal" },	/* jump on not low or equal */
    181   { '4', "l", "on A low" },			/* jump on A low */
    182   { '4', "nhe", "on not high or equal" },	/* jump on not high or equal */
    183   { '6', "ne", "on A not equal B" },		/* jump on A not equal B */
    184   { '6', "lh", "on low or high" },		/* jump on low or high */
    185   { '8', "e", "on A equal B" },			/* jump on A equal B */
    186   { '8', "nlh", "on not low or high" },		/* jump on not low or high */
    187   { 'a', "nl", "on A not low" },		/* jump on A not low */
    188   { 'a', "he", "on high or equal" },		/* jump on high or equal */
    189   { 'c', "nh", "on A not high" },		/* jump on A not high */
    190   { 'c', "le", "on low or equal" },		/* jump on low or equal */
    191 };
    192 
    193 /* As with insertOpcode instructions are added to the sorted opcode
    194    array.  Additionally mnemonics containing the '*<number>' tag are
    195    expanded to the set of conditional instructions described by
    196    s390_cond_extensions with the tag replaced by the respective
    197    mnemonic extensions.  */
    198 
    199 static void
    200 insertExpandedMnemonic (char *opcode, char *mnemonic, char *format,
    201 			int min_cpu, int mode_bits, int flags, char *description)
    202 {
    203   char *tag;
    204   char prefix[MAX_MNEMONIC_LEN + 1];
    205   char suffix[MAX_MNEMONIC_LEN + 1];
    206   char number[MAX_MNEMONIC_LEN + 1];
    207   int mask_start, i = 0, tag_found = 0, reading_number = 0;
    208   int number_p = 0, suffix_p = 0, prefix_p = 0;
    209   const struct s390_cond_ext_format *ext_table;
    210   int ext_table_length;
    211 
    212   if (!(tag = strpbrk (mnemonic, "*$")))
    213     {
    214       insertOpcode (opcode, mnemonic, format, min_cpu, mode_bits, flags, description);
    215       return;
    216     }
    217 
    218   while (mnemonic[i] != '\0')
    219     {
    220       if (mnemonic[i] == *tag)
    221 	{
    222 	  if (tag_found)
    223 	    goto malformed_mnemonic;
    224 
    225 	  tag_found = 1;
    226 	  reading_number = 1;
    227 	}
    228       else
    229 	switch (mnemonic[i])
    230 	  {
    231 	  case '0': case '1': case '2': case '3': case '4':
    232 	  case '5': case '6': case '7': case '8': case '9':
    233 	    if (!tag_found || !reading_number)
    234 	      goto malformed_mnemonic;
    235 
    236 	    number[number_p++] = mnemonic[i];
    237 	    break;
    238 
    239 	  default:
    240 	    if (reading_number)
    241 	      {
    242 		if (!number_p)
    243 		  goto malformed_mnemonic;
    244 		else
    245 		  reading_number = 0;
    246 	      }
    247 
    248 	    if (tag_found)
    249 	      suffix[suffix_p++] = mnemonic[i];
    250 	    else
    251 	      prefix[prefix_p++] = mnemonic[i];
    252 	  }
    253       i++;
    254     }
    255 
    256   prefix[prefix_p] = '\0';
    257   suffix[suffix_p] = '\0';
    258   number[number_p] = '\0';
    259 
    260   if (sscanf (number, "%d", &mask_start) != 1)
    261     goto malformed_mnemonic;
    262 
    263   if (mask_start & 3)
    264     {
    265       print_error ("Mnemonic \"%s\": Conditional mask not at nibble boundary\n", mnemonic);
    266       return;
    267     }
    268 
    269   mask_start >>= 2;
    270 
    271   switch (*tag)
    272     {
    273     case '*':
    274       ext_table = s390_cond_extensions;
    275       ext_table_length = NUM_COND_EXTENSIONS;
    276       break;
    277     case '$':
    278       ext_table = s390_crb_extensions;
    279       ext_table_length = NUM_CRB_EXTENSIONS;
    280       break;
    281     default:
    282       abort ();			/* Should be unreachable.  */
    283     }
    284 
    285   for (i = 0; i < ext_table_length; i++)
    286     {
    287       char new_mnemonic[MAX_MNEMONIC_LEN + 1];
    288       char new_description[MAX_DESCRIPTION_LEN + 1];
    289 
    290       opcode[mask_start] = ext_table[i].nibble;
    291 
    292       if (snprintf (new_mnemonic, sizeof (new_mnemonic), "%s%s%s", prefix,
    293 		    ext_table[i].extension, suffix) >= sizeof (new_mnemonic))
    294 	{
    295 	  print_error ("Mnemonic: \"%s\": Concatenated mnemonic exceeds max. length\n", mnemonic);
    296 	  return;
    297 	}
    298 
    299       if (snprintf (new_description, sizeof (new_description), "%s %s", description,
    300 		    ext_table[i].description_suffix) >= sizeof (new_description))
    301 	{
    302 	  print_error ("Mnemonic \"%s\": Concatenated description exceeds max. length\n", mnemonic);
    303 	  return;
    304 	}
    305 
    306       insertOpcode (opcode, new_mnemonic, format, min_cpu, mode_bits, flags, new_description);
    307     }
    308   return;
    309 
    310  malformed_mnemonic:
    311   print_error ("Malformed mnemonic: %s\n", mnemonic);
    312 }
    313 
    314 static const char file_header[] =
    315   "/* The opcode table. This file was generated by s390-mkopc.\n\n"
    316   "   The format of the opcode table is:\n\n"
    317   "   NAME	     OPCODE	MASK	OPERANDS\n\n"
    318   "   Name is the name of the instruction.\n"
    319   "   OPCODE is the instruction opcode.\n"
    320   "   MASK is the opcode mask; this is used to tell the disassembler\n"
    321   "     which bits in the actual opcode must match OPCODE.\n"
    322   "   OPERANDS is the list of operands.\n\n"
    323   "   The disassembler reads the table in order and prints the first\n"
    324   "   instruction which matches.\n"
    325   "   MODE_BITS - zarch or esa\n"
    326   "   MIN_CPU - number of the min cpu level required\n"
    327   "   FLAGS - instruction flags.\n"
    328   "   DESCRIPTION - description of the instruction.  */\n\n"
    329   "const struct s390_opcode s390_opcodes[] =\n  {\n";
    330 
    331 /* `dumpTable': write opcode table.  */
    332 
    333 static void
    334 dumpTable (void)
    335 {
    336   char *str;
    337   int  ix;
    338 
    339   /*  Write hash table entries (slots).  */
    340   printf ("%s", file_header);
    341 
    342   for (ix = 0; ix < no_ops; ix++)
    343     {
    344       printf ("  { \"%s\", ", op_array[ix].mnemonic);
    345       for (str = op_array[ix].opcode; *str != 0; str++)
    346 	if (*str == '?')
    347 	  *str = '0';
    348       printf ("OP%i(0x%sLL), ",
    349 	      op_array[ix].no_nibbles*4, op_array[ix].opcode);
    350       printf ("MASK_%s, INSTR_%s, ",
    351 	      op_array[ix].format, op_array[ix].format);
    352       printf ("%i, ", op_array[ix].mode_bits);
    353       printf ("%i, ", op_array[ix].min_cpu);
    354       printf ("%i, ", op_array[ix].flags);
    355       printf ("\"%s\" }", op_array[ix].description);
    356       if (ix < no_ops-1)
    357 	printf (",\n");
    358       else
    359 	printf ("\n");
    360     }
    361   printf ("};\n\n");
    362   printf ("const int s390_num_opcodes =\n");
    363   printf ("  sizeof (s390_opcodes) / sizeof (s390_opcodes[0]);\n\n");
    364 }
    365 
    366 int
    367 main (void)
    368 {
    369   char currentLine[256];
    370 
    371   createTable ();
    372 
    373   /*  Read opcode descriptions from `stdin'.  For each mnemonic,
    374       make an entry into the opcode table.  */
    375   while (fgets (currentLine, sizeof (currentLine), stdin) != NULL)
    376     {
    377       char  opcode[MAX_OPCODE_LEN + 1];
    378       char  mnemonic[MAX_MNEMONIC_LEN + 1];
    379       char  format[MAX_FORMAT_LEN + 1];
    380       char  description[MAX_DESCRIPTION_LEN + 1];
    381       char  cpu_string[MAX_CPU_LEN + 1];
    382       char  modes_string[MAX_MODES_LEN + 1];
    383       char  flags_string[MAX_FLAGS_LEN + 1];
    384       int   min_cpu;
    385       int   mode_bits;
    386       int   flag_bits;
    387       int   num_matched;
    388       char  *str;
    389 
    390       if (currentLine[0] == '#' || currentLine[0] == '\n')
    391 	continue;
    392       memset (opcode, '\0', sizeof(opcode));
    393       num_matched = sscanf (currentLine,
    394 			    "%" STRINGIFY (MAX_OPCODE_LEN) "s "
    395 			    "%" STRINGIFY (MAX_MNEMONIC_LEN) "s "
    396 			    "%" STRINGIFY (MAX_FORMAT_LEN) "s "
    397 			    "\"%" STRINGIFY (MAX_DESCRIPTION_LEN) "[^\"]\" "
    398 			    "%" STRINGIFY (MAX_CPU_LEN) "s "
    399 			    "%" STRINGIFY (MAX_MODES_LEN) "s "
    400 			    "%" STRINGIFY (MAX_FLAGS_LEN) "[^\n]",
    401 			    opcode, mnemonic, format, description,
    402 			    cpu_string, modes_string, flags_string);
    403       if (num_matched != 6 && num_matched != 7)
    404 	{
    405 	  print_error ("Couldn't scan line %s\n", currentLine);
    406 	  exit (EXIT_FAILURE);
    407 	}
    408 
    409       if (strcmp (cpu_string, "g5") == 0
    410 	  || strcmp (cpu_string, "arch3") == 0)
    411 	min_cpu = S390_OPCODE_G5;
    412       else if (strcmp (cpu_string, "g6") == 0)
    413 	min_cpu = S390_OPCODE_G6;
    414       else if (strcmp (cpu_string, "z900") == 0
    415 	       || strcmp (cpu_string, "arch5") == 0)
    416 	min_cpu = S390_OPCODE_Z900;
    417       else if (strcmp (cpu_string, "z990") == 0
    418 	       || strcmp (cpu_string, "arch6") == 0)
    419 	min_cpu = S390_OPCODE_Z990;
    420       else if (strcmp (cpu_string, "z9-109") == 0)
    421 	min_cpu = S390_OPCODE_Z9_109;
    422       else if (strcmp (cpu_string, "z9-ec") == 0
    423 	       || strcmp (cpu_string, "arch7") == 0)
    424 	min_cpu = S390_OPCODE_Z9_EC;
    425       else if (strcmp (cpu_string, "z10") == 0
    426 	       || strcmp (cpu_string, "arch8") == 0)
    427 	min_cpu = S390_OPCODE_Z10;
    428       else if (strcmp (cpu_string, "z196") == 0
    429 	       || strcmp (cpu_string, "arch9") == 0)
    430 	min_cpu = S390_OPCODE_Z196;
    431       else if (strcmp (cpu_string, "zEC12") == 0
    432 	       || strcmp (cpu_string, "arch10") == 0)
    433 	min_cpu = S390_OPCODE_ZEC12;
    434       else if (strcmp (cpu_string, "z13") == 0
    435 	       || strcmp (cpu_string, "arch11") == 0)
    436 	min_cpu = S390_OPCODE_Z13;
    437       else if (strcmp (cpu_string, "z14") == 0
    438 	       || strcmp (cpu_string, "arch12") == 0)
    439 	min_cpu = S390_OPCODE_ARCH12;
    440       else if (strcmp (cpu_string, "z15") == 0
    441 	       || strcmp (cpu_string, "arch13") == 0)
    442 	min_cpu = S390_OPCODE_ARCH13;
    443       else if (strcmp (cpu_string, "z16") == 0
    444 	       || strcmp (cpu_string, "arch14") == 0)
    445 	min_cpu = S390_OPCODE_ARCH14;
    446       else if (strcmp (cpu_string, "z17") == 0
    447 	       || strcmp (cpu_string, "arch15") == 0)
    448 	min_cpu = S390_OPCODE_ARCH15;
    449       else {
    450 	print_error ("Mnemonic \"%s\": Couldn't parse CPU string: %s\n",
    451 		     mnemonic, cpu_string);
    452 	goto continue_loop;
    453       }
    454 
    455       str = modes_string;
    456       mode_bits = 0;
    457       do {
    458 	if (strncmp (str, "esa", 3) == 0
    459 	    && (str[3] == 0 || str[3] == ',')) {
    460 	  mode_bits |= 1 << S390_OPCODE_ESA;
    461 	  str += 3;
    462 	} else if (strncmp (str, "zarch", 5) == 0
    463 		   && (str[5] == 0 || str[5] == ',')) {
    464 	  mode_bits |= 1 << S390_OPCODE_ZARCH;
    465 	  str += 5;
    466 	} else {
    467 	  print_error ("Mnemonic \"%s\": Couldn't parse modes string: %s\n",
    468 		       mnemonic, modes_string);
    469 	  goto continue_loop;
    470 	}
    471 	if (*str == ',')
    472 	  str++;
    473       } while (*str != 0);
    474 
    475       flag_bits = 0;
    476 
    477       if (num_matched == 7)
    478 	{
    479 	  str = flags_string;
    480 	  do {
    481 	    if (strncmp (str, "optparm", 7) == 0
    482 		&& (str[7] == 0 || str[7] == ',')) {
    483 	      flag_bits |= S390_INSTR_FLAG_OPTPARM;
    484 	      str += 7;
    485 	    } else if (strncmp (str, "optparm2", 8) == 0
    486 		       && (str[8] == 0 || str[8] == ',')) {
    487 	      flag_bits |= S390_INSTR_FLAG_OPTPARM2;
    488 	      str += 8;
    489 	    } else if (strncmp (str, "htm", 3) == 0
    490 		       && (str[3] == 0 || str[3] == ',')) {
    491 	      flag_bits |= S390_INSTR_FLAG_HTM;
    492 	      str += 3;
    493 	    } else if (strncmp (str, "vx", 2) == 0
    494 		       && (str[2] == 0 || str[2] == ',')) {
    495 	      flag_bits |= S390_INSTR_FLAG_VX;
    496 	      str += 2;
    497 	    } else if (strncmp (str, "jump", 4) == 0
    498 		&& (str[4] == 0 || str[4] == ',')) {
    499 	      flag_bits |= S390_INSTR_FLAGS_CLASS_JUMP;
    500 	      str += 4;
    501 	    } else if (strncmp (str, "condjump", 8) == 0
    502 		&& (str[8] == 0 || str[8] == ',')) {
    503 	      flag_bits |= S390_INSTR_FLAGS_CLASS_CONDJUMP;
    504 	      str += 8;
    505 	    } else if (strncmp (str, "jumpsr", 6) == 0
    506 		&& (str[6] == 0 || str[6] == ',')) {
    507 	      flag_bits |= S390_INSTR_FLAGS_CLASS_JUMPSR;
    508 	      str += 6;
    509 	    } else {
    510 	      print_error ("Mnemonic \"%s\": Couldn't parse flags string: %s\n",
    511 			   mnemonic, flags_string);
    512 	      goto continue_loop;
    513 	    }
    514 	    if (*str == ',')
    515 	      str++;
    516 	  } while (*str != 0);
    517 	}
    518       insertExpandedMnemonic (opcode, mnemonic, format, min_cpu, mode_bits, flag_bits, description);
    519 
    520  continue_loop:
    521       ;
    522     }
    523 
    524   dumpTable ();
    525   return return_code;
    526 }
    527