Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/s390/tools/gen_opcode_table.c
26424 views
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
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
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
175
static int cmpformat(const void *a, const void *b)
176
{
177
return strcmp(((struct insn *)a)->format, ((struct insn *)b)->format);
178
}
179
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
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
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
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
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
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
281
static int cmpopcode(const void *a, const void *b)
282
{
283
return strcmp(((struct insn *)a)->opcode, ((struct insn *)b)->opcode);
284
}
285
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
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
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
354