[BINUTILS, AARCH64, 6/8] Add Tag getting instruction in Memory Tagging Extension
[external/binutils.git] / opcodes / s390-mkopc.c
1 /* s390-mkopc.c -- Generates opcode table out of s390-opc.txt
2    Copyright (C) 2000-2018 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: 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           || strcmp (cpu_string, "arch3") == 0)
351         min_cpu = S390_OPCODE_G5;
352       else if (strcmp (cpu_string, "g6") == 0)
353         min_cpu = S390_OPCODE_G6;
354       else if (strcmp (cpu_string, "z900") == 0
355                || strcmp (cpu_string, "arch5") == 0)
356         min_cpu = S390_OPCODE_Z900;
357       else if (strcmp (cpu_string, "z990") == 0
358                || strcmp (cpu_string, "arch6") == 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                || strcmp (cpu_string, "arch7") == 0)
364         min_cpu = S390_OPCODE_Z9_EC;
365       else if (strcmp (cpu_string, "z10") == 0
366                || strcmp (cpu_string, "arch8") == 0)
367         min_cpu = S390_OPCODE_Z10;
368       else if (strcmp (cpu_string, "z196") == 0
369                || strcmp (cpu_string, "arch9") == 0)
370         min_cpu = S390_OPCODE_Z196;
371       else if (strcmp (cpu_string, "zEC12") == 0
372                || strcmp (cpu_string, "arch10") == 0)
373         min_cpu = S390_OPCODE_ZEC12;
374       else if (strcmp (cpu_string, "z13") == 0
375                || strcmp (cpu_string, "arch11") == 0)
376         min_cpu = S390_OPCODE_Z13;
377       else if (strcmp (cpu_string, "z14") == 0
378                || strcmp (cpu_string, "arch12") == 0)
379         min_cpu = S390_OPCODE_ARCH12;
380       else {
381         fprintf (stderr, "Couldn't parse cpu string %s\n", cpu_string);
382         exit (1);
383       }
384
385       str = modes_string;
386       mode_bits = 0;
387       do {
388         if (strncmp (str, "esa", 3) == 0
389             && (str[3] == 0 || str[3] == ',')) {
390           mode_bits |= 1 << S390_OPCODE_ESA;
391           str += 3;
392         } else if (strncmp (str, "zarch", 5) == 0
393                    && (str[5] == 0 || str[5] == ',')) {
394           mode_bits |= 1 << S390_OPCODE_ZARCH;
395           str += 5;
396         } else {
397           fprintf (stderr, "Couldn't parse modes string %s\n",
398                    modes_string);
399           exit (1);
400         }
401         if (*str == ',')
402           str++;
403       } while (*str != 0);
404
405       flag_bits = 0;
406
407       if (num_matched == 7)
408         {
409           str = flags_string;
410           do {
411             if (strncmp (str, "optparm", 7) == 0
412                 && (str[7] == 0 || str[7] == ',')) {
413               flag_bits |= S390_INSTR_FLAG_OPTPARM;
414               str += 7;
415             } else if (strncmp (str, "optparm2", 8) == 0
416                        && (str[8] == 0 || str[8] == ',')) {
417               flag_bits |= S390_INSTR_FLAG_OPTPARM2;
418               str += 8;
419             } else if (strncmp (str, "htm", 3) == 0
420                        && (str[3] == 0 || str[3] == ',')) {
421               flag_bits |= S390_INSTR_FLAG_HTM;
422               str += 3;
423             } else if (strncmp (str, "vx", 2) == 0
424                        && (str[2] == 0 || str[2] == ',')) {
425               flag_bits |= S390_INSTR_FLAG_VX;
426               str += 2;
427             } else {
428               fprintf (stderr, "Couldn't parse flags string %s\n",
429                        flags_string);
430               exit (1);
431             }
432             if (*str == ',')
433               str++;
434           } while (*str != 0);
435         }
436       insertExpandedMnemonic (opcode, mnemonic, format, min_cpu, mode_bits, flag_bits);
437     }
438
439   dumpTable ();
440   return 0;
441 }