blob: 01d4c5a4bfe9781fdba3ccfd4e727e518892815f [file] [log] [blame]
Heiko Carstens8bc1e4e2017-11-06 13:29:56 +01001/*
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
15struct insn_type {
16 unsigned char byte;
17 unsigned char mask;
18 char **format;
19};
20
21struct 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
30struct insn_group {
31 struct insn_type *type;
32 int offset;
33 int count;
34 char opcode[2];
35};
36
37struct insn_format {
38 char *format;
39 int type;
40};
41
42struct 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 */
65static 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
131static 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
151static 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
174static int cmpformat(const void *a, const void *b)
175{
176 return strcmp(((struct insn *)a)->format, ((struct insn *)b)->format);
177}
178
179static 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
198static int cmp_long_insn(const void *a, const void *b)
199{
200 return strcmp(((struct insn *)a)->name, ((struct insn *)b)->name);
201}
202
203static 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
230static 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
245static 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
265static int cmpopcode(const void *a, const void *b)
266{
267 return strcmp(((struct insn *)a)->opcode, ((struct insn *)b)->opcode);
268}
269
270static 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
303static 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
317int 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}