Merge tag 'drm-for-v4.15-amd-dc' of git://people.freedesktop.org/~airlied/linux
[sfrench/cifs-2.6.git] / arch / s390 / tools / gen_opcode_table.c
1 /*
2  * Generate opcode table initializers for the in-kernel disassembler.
3  *
4  *    Copyright IBM Corp. 2017
5  *
6  */
7
8 #include <stdlib.h>
9 #include <string.h>
10 #include <ctype.h>
11 #include <stdio.h>
12
13 #define STRING_SIZE_MAX 20
14
15 struct insn_type {
16         unsigned char byte;
17         unsigned char mask;
18         char **format;
19 };
20
21 struct insn {
22         struct insn_type *type;
23         char opcode[STRING_SIZE_MAX];
24         char name[STRING_SIZE_MAX];
25         char upper[STRING_SIZE_MAX];
26         char format[STRING_SIZE_MAX];
27         unsigned int name_len;
28 };
29
30 struct insn_group {
31         struct insn_type *type;
32         int offset;
33         int count;
34         char opcode[2];
35 };
36
37 struct insn_format {
38         char *format;
39         int type;
40 };
41
42 struct gen_opcode {
43         struct insn *insn;
44         int nr;
45         struct insn_group *group;
46         int nr_groups;
47 };
48
49 /*
50  * Table of instruction format types. Each opcode is defined with at
51  * least one byte (two nibbles), three nibbles, or two bytes (four
52  * nibbles).
53  * The byte member of each instruction format type entry defines
54  * within which byte of an instruction the third (and fourth) nibble
55  * of an opcode can be found. The mask member is the and-mask that
56  * needs to be applied on this byte in order to get the third (and
57  * fourth) nibble of the opcode.
58  * The format array defines all instruction formats (as defined in the
59  * Principles of Operation) which have the same position of the opcode
60  * nibbles.
61  * A special case are instruction formats with 1-byte opcodes. In this
62  * case the byte member always is zero, so that the mask is applied on
63  * the (only) byte that contains the opcode.
64  */
65 static struct insn_type insn_type_table[] = {
66         {
67                 .byte = 0,
68                 .mask = 0xff,
69                 .format = (char *[]) {
70                         "MII",
71                         "RR",
72                         "RS",
73                         "RSI",
74                         "RX",
75                         "SI",
76                         "SMI",
77                         "SS",
78                         NULL,
79                 },
80         },
81         {
82                 .byte = 1,
83                 .mask = 0x0f,
84                 .format = (char *[]) {
85                         "RI",
86                         "RIL",
87                         "SSF",
88                         NULL,
89                 },
90         },
91         {
92                 .byte = 1,
93                 .mask = 0xff,
94                 .format = (char *[]) {
95                         "E",
96                         "IE",
97                         "RRE",
98                         "RRF",
99                         "RRR",
100                         "S",
101                         "SIL",
102                         "SSE",
103                         NULL,
104                 },
105         },
106         {
107                 .byte = 5,
108                 .mask = 0xff,
109                 .format = (char *[]) {
110                         "RIE",
111                         "RIS",
112                         "RRS",
113                         "RSE",
114                         "RSL",
115                         "RSY",
116                         "RXE",
117                         "RXF",
118                         "RXY",
119                         "SIY",
120                         "VRI",
121                         "VRR",
122                         "VRS",
123                         "VRV",
124                         "VRX",
125                         "VSI",
126                         NULL,
127                 },
128         },
129 };
130
131 static struct insn_type *insn_format_to_type(char *format)
132 {
133         char tmp[STRING_SIZE_MAX];
134         char *base_format, **ptr;
135         int i;
136
137         strcpy(tmp, format);
138         base_format = tmp;
139         base_format = strsep(&base_format, "_");
140         for (i = 0; i < sizeof(insn_type_table) / sizeof(insn_type_table[0]); i++) {
141                 ptr = insn_type_table[i].format;
142                 while (*ptr) {
143                         if (!strcmp(base_format, *ptr))
144                                 return &insn_type_table[i];
145                         ptr++;
146                 }
147         }
148         exit(EXIT_FAILURE);
149 }
150
151 static void read_instructions(struct gen_opcode *desc)
152 {
153         struct insn insn;
154         int rc, i;
155
156         while (1) {
157                 rc = scanf("%s %s %s", insn.opcode, insn.name, insn.format);
158                 if (rc == EOF)
159                         break;
160                 if (rc != 3)
161                         exit(EXIT_FAILURE);
162                 insn.type = insn_format_to_type(insn.format);
163                 insn.name_len = strlen(insn.name);
164                 for (i = 0; i <= insn.name_len; i++)
165                         insn.upper[i] = toupper((unsigned char)insn.name[i]);
166                 desc->nr++;
167                 desc->insn = realloc(desc->insn, desc->nr * sizeof(*desc->insn));
168                 if (!desc->insn)
169                         exit(EXIT_FAILURE);
170                 desc->insn[desc->nr - 1] = insn;
171         }
172 }
173
174 static int cmpformat(const void *a, const void *b)
175 {
176         return strcmp(((struct insn *)a)->format, ((struct insn *)b)->format);
177 }
178
179 static void print_formats(struct gen_opcode *desc)
180 {
181         char *format;
182         int i, count;
183
184         qsort(desc->insn, desc->nr, sizeof(*desc->insn), cmpformat);
185         format = "";
186         count = 0;
187         printf("enum {\n");
188         for (i = 0; i < desc->nr; i++) {
189                 if (!strcmp(format, desc->insn[i].format))
190                         continue;
191                 count++;
192                 format = desc->insn[i].format;
193                 printf("\tINSTR_%s,\n", format);
194         }
195         printf("}; /* %d */\n\n", count);
196 }
197
198 static int cmp_long_insn(const void *a, const void *b)
199 {
200         return strcmp(((struct insn *)a)->name, ((struct insn *)b)->name);
201 }
202
203 static void print_long_insn(struct gen_opcode *desc)
204 {
205         struct insn *insn;
206         int i, count;
207
208         qsort(desc->insn, desc->nr, sizeof(*desc->insn), cmp_long_insn);
209         count = 0;
210         printf("enum {\n");
211         for (i = 0; i < desc->nr; i++) {
212                 insn = &desc->insn[i];
213                 if (insn->name_len < 6)
214                         continue;
215                 printf("\tLONG_INSN_%s,\n", insn->upper);
216                 count++;
217         }
218         printf("}; /* %d */\n\n", count);
219
220         printf("#define LONG_INSN_INITIALIZER { \\\n");
221         for (i = 0; i < desc->nr; i++) {
222                 insn = &desc->insn[i];
223                 if (insn->name_len < 6)
224                         continue;
225                 printf("\t[LONG_INSN_%s] = \"%s\", \\\n", insn->upper, insn->name);
226         }
227         printf("}\n\n");
228 }
229
230 static void print_opcode(struct insn *insn, int nr)
231 {
232         char *opcode;
233
234         opcode = insn->opcode;
235         if (insn->type->byte != 0)
236                 opcode += 2;
237         printf("\t[%4d] = { .opfrag = 0x%s, .format = INSTR_%s, ", nr, opcode, insn->format);
238         if (insn->name_len < 6)
239                 printf(".name = \"%s\" ", insn->name);
240         else
241                 printf(".offset = LONG_INSN_%s ", insn->upper);
242         printf("}, \\\n");
243 }
244
245 static void add_to_group(struct gen_opcode *desc, struct insn *insn, int offset)
246 {
247         struct insn_group *group;
248
249         group = desc->group ? &desc->group[desc->nr_groups - 1] : NULL;
250         if (group && (!strncmp(group->opcode, insn->opcode, 2) || group->type->byte == 0)) {
251                 group->count++;
252                 return;
253         }
254         desc->nr_groups++;
255         desc->group = realloc(desc->group, desc->nr_groups * sizeof(*desc->group));
256         if (!desc->group)
257                 exit(EXIT_FAILURE);
258         group = &desc->group[desc->nr_groups - 1];
259         strncpy(group->opcode, insn->opcode, 2);
260         group->type = insn->type;
261         group->offset = offset;
262         group->count = 1;
263 }
264
265 static int cmpopcode(const void *a, const void *b)
266 {
267         return strcmp(((struct insn *)a)->opcode, ((struct insn *)b)->opcode);
268 }
269
270 static void print_opcode_table(struct gen_opcode *desc)
271 {
272         char opcode[2] = "";
273         struct insn *insn;
274         int i, offset;
275
276         qsort(desc->insn, desc->nr, sizeof(*desc->insn), cmpopcode);
277         printf("#define OPCODE_TABLE_INITIALIZER { \\\n");
278         offset = 0;
279         for (i = 0; i < desc->nr; i++) {
280                 insn = &desc->insn[i];
281                 if (insn->type->byte == 0)
282                         continue;
283                 add_to_group(desc, insn, offset);
284                 if (strncmp(opcode, insn->opcode, 2)) {
285                         strncpy(opcode, insn->opcode, 2);
286                         printf("\t/* %.2s */ \\\n", opcode);
287                 }
288                 print_opcode(insn, offset);
289                 offset++;
290         }
291         printf("\t/* 1-byte opcode instructions */ \\\n");
292         for (i = 0; i < desc->nr; i++) {
293                 insn = &desc->insn[i];
294                 if (insn->type->byte != 0)
295                         continue;
296                 add_to_group(desc, insn, offset);
297                 print_opcode(insn, offset);
298                 offset++;
299         }
300         printf("}\n\n");
301 }
302
303 static void print_opcode_table_offsets(struct gen_opcode *desc)
304 {
305         struct insn_group *group;
306         int i;
307
308         printf("#define OPCODE_OFFSET_INITIALIZER { \\\n");
309         for (i = 0; i < desc->nr_groups; i++) {
310                 group = &desc->group[i];
311                 printf("\t{ .opcode = 0x%.2s, .mask = 0x%02x, .byte = %d, .offset = %d, .count = %d }, \\\n",
312                        group->opcode, group->type->mask, group->type->byte, group->offset, group->count);
313         }
314         printf("}\n\n");
315 }
316
317 int main(int argc, char **argv)
318 {
319         struct gen_opcode _desc = { 0 };
320         struct gen_opcode *desc = &_desc;
321
322         read_instructions(desc);
323         printf("#ifndef __S390_GENERATED_DIS_H__\n");
324         printf("#define __S390_GENERATED_DIS_H__\n");
325         printf("/*\n");
326         printf(" * DO NOT MODIFY.\n");
327         printf(" *\n");
328         printf(" * This file was generated by %s\n", __FILE__);
329         printf(" */\n\n");
330         print_formats(desc);
331         print_long_insn(desc);
332         print_opcode_table(desc);
333         print_opcode_table_offsets(desc);
334         printf("#endif\n");
335         exit(EXIT_SUCCESS);
336 }