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 }
337