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