xref: /linux/arch/s390/tools/gen_opcode_table.c (revision b731bc5f49651bb85ef31fa1db6e76a0fe10d572)
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