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