xref: /netbsd-src/external/gpl3/gdb/dist/opcodes/s390-mkopc.c (revision f847bb5077cfe2c7bd3ca10466836e68422b105e)
1 /* s390-mkopc.c -- Generates opcode table out of s390-opc.txt
2    Copyright (C) 2000-2024 Free Software Foundation, Inc.
3    Contributed by Martin Schwidefsky (schwidefsky@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 {
447 	print_error ("Mnemonic \"%s\": Couldn't parse CPU string: %s\n",
448 		     mnemonic, cpu_string);
449 	goto continue_loop;
450       }
451 
452       str = modes_string;
453       mode_bits = 0;
454       do {
455 	if (strncmp (str, "esa", 3) == 0
456 	    && (str[3] == 0 || str[3] == ',')) {
457 	  mode_bits |= 1 << S390_OPCODE_ESA;
458 	  str += 3;
459 	} else if (strncmp (str, "zarch", 5) == 0
460 		   && (str[5] == 0 || str[5] == ',')) {
461 	  mode_bits |= 1 << S390_OPCODE_ZARCH;
462 	  str += 5;
463 	} else {
464 	  print_error ("Mnemonic \"%s\": Couldn't parse modes string: %s\n",
465 		       mnemonic, modes_string);
466 	  goto continue_loop;
467 	}
468 	if (*str == ',')
469 	  str++;
470       } while (*str != 0);
471 
472       flag_bits = 0;
473 
474       if (num_matched == 7)
475 	{
476 	  str = flags_string;
477 	  do {
478 	    if (strncmp (str, "optparm", 7) == 0
479 		&& (str[7] == 0 || str[7] == ',')) {
480 	      flag_bits |= S390_INSTR_FLAG_OPTPARM;
481 	      str += 7;
482 	    } else if (strncmp (str, "optparm2", 8) == 0
483 		       && (str[8] == 0 || str[8] == ',')) {
484 	      flag_bits |= S390_INSTR_FLAG_OPTPARM2;
485 	      str += 8;
486 	    } else if (strncmp (str, "htm", 3) == 0
487 		       && (str[3] == 0 || str[3] == ',')) {
488 	      flag_bits |= S390_INSTR_FLAG_HTM;
489 	      str += 3;
490 	    } else if (strncmp (str, "vx", 2) == 0
491 		       && (str[2] == 0 || str[2] == ',')) {
492 	      flag_bits |= S390_INSTR_FLAG_VX;
493 	      str += 2;
494 	    } else if (strncmp (str, "jump", 4) == 0
495 		&& (str[4] == 0 || str[4] == ',')) {
496 	      flag_bits |= S390_INSTR_FLAGS_CLASS_JUMP;
497 	      str += 4;
498 	    } else if (strncmp (str, "condjump", 8) == 0
499 		&& (str[8] == 0 || str[8] == ',')) {
500 	      flag_bits |= S390_INSTR_FLAGS_CLASS_CONDJUMP;
501 	      str += 8;
502 	    } else if (strncmp (str, "jumpsr", 6) == 0
503 		&& (str[6] == 0 || str[6] == ',')) {
504 	      flag_bits |= S390_INSTR_FLAGS_CLASS_JUMPSR;
505 	      str += 6;
506 	    } else {
507 	      print_error ("Mnemonic \"%s\": Couldn't parse flags string: %s\n",
508 			   mnemonic, flags_string);
509 	      goto continue_loop;
510 	    }
511 	    if (*str == ',')
512 	      str++;
513 	  } while (*str != 0);
514 	}
515       insertExpandedMnemonic (opcode, mnemonic, format, min_cpu, mode_bits, flag_bits, description);
516 
517  continue_loop:
518       ;
519     }
520 
521   dumpTable ();
522   return return_code;
523 }
524