1 /* SPDX-License-Identifier: GPL-2.0 */
3 * Generate opcode table initializers for the in-kernel disassembler.
5 * Copyright IBM Corp. 2017
14 #define STRING_SIZE_MAX 20
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
;
32 struct insn_type
*type
;
46 struct insn_group
*group
;
51 * Table of instruction format types. Each opcode is defined with at
52 * least one byte (two nibbles), three nibbles, or two bytes (four
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
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.
66 static struct insn_type insn_type_table
[] = {
70 .format
= (char *[]) {
85 .format
= (char *[]) {
95 .format
= (char *[]) {
110 .format
= (char *[]) {
132 static struct insn_type
*insn_format_to_type(char *format
)
134 char tmp
[STRING_SIZE_MAX
];
135 char *base_format
, **ptr
;
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
;
144 if (!strcmp(base_format
, *ptr
))
145 return &insn_type_table
[i
];
152 static void read_instructions(struct gen_opcode
*desc
)
158 rc
= scanf("%s %s %s", insn
.opcode
, insn
.name
, insn
.format
);
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
]);
168 desc
->insn
= realloc(desc
->insn
, desc
->nr
* sizeof(*desc
->insn
));
171 desc
->insn
[desc
->nr
- 1] = insn
;
175 static int cmpformat(const void *a
, const void *b
)
177 return strcmp(((struct insn
*)a
)->format
, ((struct insn
*)b
)->format
);
180 static void print_formats(struct gen_opcode
*desc
)
185 qsort(desc
->insn
, desc
->nr
, sizeof(*desc
->insn
), cmpformat
);
189 for (i
= 0; i
< desc
->nr
; i
++) {
190 if (!strcmp(format
, desc
->insn
[i
].format
))
193 format
= desc
->insn
[i
].format
;
194 printf("\tINSTR_%s,\n", format
);
196 printf("}; /* %d */\n\n", count
);
199 static int cmp_long_insn(const void *a
, const void *b
)
201 return strcmp(((struct insn
*)a
)->name
, ((struct insn
*)b
)->name
);
204 static void print_long_insn(struct gen_opcode
*desc
)
209 qsort(desc
->insn
, desc
->nr
, sizeof(*desc
->insn
), cmp_long_insn
);
212 for (i
= 0; i
< desc
->nr
; i
++) {
213 insn
= &desc
->insn
[i
];
214 if (insn
->name_len
< 6)
216 printf("\tLONG_INSN_%s,\n", insn
->upper
);
219 printf("}; /* %d */\n\n", count
);
221 printf("#define LONG_INSN_INITIALIZER { \\\n");
222 for (i
= 0; i
< desc
->nr
; i
++) {
223 insn
= &desc
->insn
[i
];
224 if (insn
->name_len
< 6)
226 printf("\t[LONG_INSN_%s] = \"%s\", \\\n", insn
->upper
, insn
->name
);
231 static void print_opcode(struct insn
*insn
, int nr
)
235 opcode
= insn
->opcode
;
236 if (insn
->type
->byte
!= 0)
238 printf("\t[%4d] = { .opfrag = 0x%s, .format = INSTR_%s, ", nr
, opcode
, insn
->format
);
239 if (insn
->name_len
< 6)
240 printf(".name = \"%s\" ", insn
->name
);
242 printf(".offset = LONG_INSN_%s ", insn
->upper
);
246 static void add_to_group(struct gen_opcode
*desc
, struct insn
*insn
, int offset
)
248 struct insn_group
*group
;
250 group
= desc
->group
? &desc
->group
[desc
->nr_groups
- 1] : NULL
;
251 if (group
&& (!strncmp(group
->opcode
, insn
->opcode
, 2) || group
->type
->byte
== 0)) {
256 desc
->group
= realloc(desc
->group
, desc
->nr_groups
* sizeof(*desc
->group
));
259 group
= &desc
->group
[desc
->nr_groups
- 1];
260 memcpy(group
->opcode
, insn
->opcode
, 2);
261 group
->type
= insn
->type
;
262 group
->offset
= offset
;
266 static int cmpopcode(const void *a
, const void *b
)
268 return strcmp(((struct insn
*)a
)->opcode
, ((struct insn
*)b
)->opcode
);
271 static void print_opcode_table(struct gen_opcode
*desc
)
277 qsort(desc
->insn
, desc
->nr
, sizeof(*desc
->insn
), cmpopcode
);
278 printf("#define OPCODE_TABLE_INITIALIZER { \\\n");
280 for (i
= 0; i
< desc
->nr
; i
++) {
281 insn
= &desc
->insn
[i
];
282 if (insn
->type
->byte
== 0)
284 add_to_group(desc
, insn
, offset
);
285 if (strncmp(opcode
, insn
->opcode
, 2)) {
286 memcpy(opcode
, insn
->opcode
, 2);
287 printf("\t/* %.2s */ \\\n", opcode
);
289 print_opcode(insn
, offset
);
292 printf("\t/* 1-byte opcode instructions */ \\\n");
293 for (i
= 0; i
< desc
->nr
; i
++) {
294 insn
= &desc
->insn
[i
];
295 if (insn
->type
->byte
!= 0)
297 add_to_group(desc
, insn
, offset
);
298 print_opcode(insn
, offset
);
304 static void print_opcode_table_offsets(struct gen_opcode
*desc
)
306 struct insn_group
*group
;
309 printf("#define OPCODE_OFFSET_INITIALIZER { \\\n");
310 for (i
= 0; i
< desc
->nr_groups
; i
++) {
311 group
= &desc
->group
[i
];
312 printf("\t{ .opcode = 0x%.2s, .mask = 0x%02x, .byte = %d, .offset = %d, .count = %d }, \\\n",
313 group
->opcode
, group
->type
->mask
, group
->type
->byte
, group
->offset
, group
->count
);
318 int main(int argc
, char **argv
)
320 struct gen_opcode _desc
= { 0 };
321 struct gen_opcode
*desc
= &_desc
;
323 read_instructions(desc
);
324 printf("#ifndef __S390_GENERATED_DIS_DEFS_H__\n");
325 printf("#define __S390_GENERATED_DIS_DEFS_H__\n");
327 printf(" * DO NOT MODIFY.\n");
329 printf(" * This file was generated by %s\n", __FILE__
);
332 print_long_insn(desc
);
333 print_opcode_table(desc
);
334 print_opcode_table_offsets(desc
);