xref: /netbsd-src/external/gpl3/gdb/dist/opcodes/s390-mkopc.c (revision 345cf9fb81bd0411c53e25d62cd93bdcaa865312)
1 /* s390-mkopc.c -- Generates opcode table out of s390-opc.txt
2    Copyright (C) 2000-2022 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 <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 if (strcmp (cpu_string, "z16") == 0
385 	       || strcmp (cpu_string, "arch14") == 0)
386 	min_cpu = S390_OPCODE_ARCH14;
387       else {
388 	fprintf (stderr, "Couldn't parse cpu string %s\n", cpu_string);
389 	exit (1);
390       }
391 
392       str = modes_string;
393       mode_bits = 0;
394       do {
395 	if (strncmp (str, "esa", 3) == 0
396 	    && (str[3] == 0 || str[3] == ',')) {
397 	  mode_bits |= 1 << S390_OPCODE_ESA;
398 	  str += 3;
399 	} else if (strncmp (str, "zarch", 5) == 0
400 		   && (str[5] == 0 || str[5] == ',')) {
401 	  mode_bits |= 1 << S390_OPCODE_ZARCH;
402 	  str += 5;
403 	} else {
404 	  fprintf (stderr, "Couldn't parse modes string %s\n",
405 		   modes_string);
406 	  exit (1);
407 	}
408 	if (*str == ',')
409 	  str++;
410       } while (*str != 0);
411 
412       flag_bits = 0;
413 
414       if (num_matched == 7)
415 	{
416 	  str = flags_string;
417 	  do {
418 	    if (strncmp (str, "optparm", 7) == 0
419 		&& (str[7] == 0 || str[7] == ',')) {
420 	      flag_bits |= S390_INSTR_FLAG_OPTPARM;
421 	      str += 7;
422 	    } else if (strncmp (str, "optparm2", 8) == 0
423 		       && (str[8] == 0 || str[8] == ',')) {
424 	      flag_bits |= S390_INSTR_FLAG_OPTPARM2;
425 	      str += 8;
426 	    } else if (strncmp (str, "htm", 3) == 0
427 		       && (str[3] == 0 || str[3] == ',')) {
428 	      flag_bits |= S390_INSTR_FLAG_HTM;
429 	      str += 3;
430 	    } else if (strncmp (str, "vx", 2) == 0
431 		       && (str[2] == 0 || str[2] == ',')) {
432 	      flag_bits |= S390_INSTR_FLAG_VX;
433 	      str += 2;
434 	    } else {
435 	      fprintf (stderr, "Couldn't parse flags string %s\n",
436 		       flags_string);
437 	      exit (1);
438 	    }
439 	    if (*str == ',')
440 	      str++;
441 	  } while (*str != 0);
442 	}
443       insertExpandedMnemonic (opcode, mnemonic, format, min_cpu, mode_bits, flag_bits);
444     }
445 
446   dumpTable ();
447   return 0;
448 }
449