File Index
Files and directories
Sign in
FILE

gen_opcode_table.c

File preview with syntax highlighting.

linux-6.19.14/arch/s390/tools/gen_opcode_table.c C
  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
 16struct insn_type {
 17	unsigned char byte;
 18	unsigned char mask;
 19	char **format;
 20};
 21
 22struct 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
 31struct insn_group {
 32	struct insn_type *type;
 33	int offset;
 34	int count;
 35	char opcode[2];
 36};
 37
 38struct insn_format {
 39	char *format;
 40	int type;
 41};
 42
 43struct 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 */
 66static 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
132static 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
152static 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
175static int cmpformat(const void *a, const void *b)
176{
177	return strcmp(((struct insn *)a)->format, ((struct insn *)b)->format);
178}
179
180static 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
199static int cmp_long_insn(const void *a, const void *b)
200{
201	return strcmp(((struct insn *)a)->name, ((struct insn *)b)->name);
202}
203
204static 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
215static 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
244static 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
261static 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
281static int cmpopcode(const void *a, const void *b)
282{
283	return strcmp(((struct insn *)a)->opcode, ((struct insn *)b)->opcode);
284}
285
286static 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
319static 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
333int 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}
~/ Read-only file preview.