19fa1db4cSMartin Schwidefsky /* SPDX-License-Identifier: GPL-2.0 */
28bc1e4ecSHeiko Carstens /*
38bc1e4ecSHeiko Carstens * Generate opcode table initializers for the in-kernel disassembler.
48bc1e4ecSHeiko Carstens *
58bc1e4ecSHeiko Carstens * Copyright IBM Corp. 2017
68bc1e4ecSHeiko Carstens *
78bc1e4ecSHeiko Carstens */
88bc1e4ecSHeiko Carstens
98bc1e4ecSHeiko Carstens #include <stdlib.h>
108bc1e4ecSHeiko Carstens #include <string.h>
118bc1e4ecSHeiko Carstens #include <ctype.h>
128bc1e4ecSHeiko Carstens #include <stdio.h>
138bc1e4ecSHeiko Carstens
148bc1e4ecSHeiko Carstens #define STRING_SIZE_MAX 20
158bc1e4ecSHeiko Carstens
168bc1e4ecSHeiko Carstens struct insn_type {
178bc1e4ecSHeiko Carstens unsigned char byte;
188bc1e4ecSHeiko Carstens unsigned char mask;
198bc1e4ecSHeiko Carstens char **format;
208bc1e4ecSHeiko Carstens };
218bc1e4ecSHeiko Carstens
228bc1e4ecSHeiko Carstens struct insn {
238bc1e4ecSHeiko Carstens struct insn_type *type;
248bc1e4ecSHeiko Carstens char opcode[STRING_SIZE_MAX];
258bc1e4ecSHeiko Carstens char name[STRING_SIZE_MAX];
268bc1e4ecSHeiko Carstens char upper[STRING_SIZE_MAX];
278bc1e4ecSHeiko Carstens char format[STRING_SIZE_MAX];
288bc1e4ecSHeiko Carstens unsigned int name_len;
298bc1e4ecSHeiko Carstens };
308bc1e4ecSHeiko Carstens
318bc1e4ecSHeiko Carstens struct insn_group {
328bc1e4ecSHeiko Carstens struct insn_type *type;
338bc1e4ecSHeiko Carstens int offset;
348bc1e4ecSHeiko Carstens int count;
358bc1e4ecSHeiko Carstens char opcode[2];
368bc1e4ecSHeiko Carstens };
378bc1e4ecSHeiko Carstens
388bc1e4ecSHeiko Carstens struct insn_format {
398bc1e4ecSHeiko Carstens char *format;
408bc1e4ecSHeiko Carstens int type;
418bc1e4ecSHeiko Carstens };
428bc1e4ecSHeiko Carstens
438bc1e4ecSHeiko Carstens struct gen_opcode {
448bc1e4ecSHeiko Carstens struct insn *insn;
458bc1e4ecSHeiko Carstens int nr;
468bc1e4ecSHeiko Carstens struct insn_group *group;
478bc1e4ecSHeiko Carstens int nr_groups;
488bc1e4ecSHeiko Carstens };
498bc1e4ecSHeiko Carstens
508bc1e4ecSHeiko Carstens /*
518bc1e4ecSHeiko Carstens * Table of instruction format types. Each opcode is defined with at
528bc1e4ecSHeiko Carstens * least one byte (two nibbles), three nibbles, or two bytes (four
538bc1e4ecSHeiko Carstens * nibbles).
548bc1e4ecSHeiko Carstens * The byte member of each instruction format type entry defines
558bc1e4ecSHeiko Carstens * within which byte of an instruction the third (and fourth) nibble
568bc1e4ecSHeiko Carstens * of an opcode can be found. The mask member is the and-mask that
578bc1e4ecSHeiko Carstens * needs to be applied on this byte in order to get the third (and
588bc1e4ecSHeiko Carstens * fourth) nibble of the opcode.
598bc1e4ecSHeiko Carstens * The format array defines all instruction formats (as defined in the
608bc1e4ecSHeiko Carstens * Principles of Operation) which have the same position of the opcode
618bc1e4ecSHeiko Carstens * nibbles.
628bc1e4ecSHeiko Carstens * A special case are instruction formats with 1-byte opcodes. In this
638bc1e4ecSHeiko Carstens * case the byte member always is zero, so that the mask is applied on
648bc1e4ecSHeiko Carstens * the (only) byte that contains the opcode.
658bc1e4ecSHeiko Carstens */
668bc1e4ecSHeiko Carstens static struct insn_type insn_type_table[] = {
678bc1e4ecSHeiko Carstens {
688bc1e4ecSHeiko Carstens .byte = 0,
698bc1e4ecSHeiko Carstens .mask = 0xff,
708bc1e4ecSHeiko Carstens .format = (char *[]) {
718bc1e4ecSHeiko Carstens "MII",
728bc1e4ecSHeiko Carstens "RR",
738bc1e4ecSHeiko Carstens "RS",
748bc1e4ecSHeiko Carstens "RSI",
758bc1e4ecSHeiko Carstens "RX",
768bc1e4ecSHeiko Carstens "SI",
778bc1e4ecSHeiko Carstens "SMI",
788bc1e4ecSHeiko Carstens "SS",
798bc1e4ecSHeiko Carstens NULL,
808bc1e4ecSHeiko Carstens },
818bc1e4ecSHeiko Carstens },
828bc1e4ecSHeiko Carstens {
838bc1e4ecSHeiko Carstens .byte = 1,
848bc1e4ecSHeiko Carstens .mask = 0x0f,
858bc1e4ecSHeiko Carstens .format = (char *[]) {
868bc1e4ecSHeiko Carstens "RI",
878bc1e4ecSHeiko Carstens "RIL",
888bc1e4ecSHeiko Carstens "SSF",
898bc1e4ecSHeiko Carstens NULL,
908bc1e4ecSHeiko Carstens },
918bc1e4ecSHeiko Carstens },
928bc1e4ecSHeiko Carstens {
938bc1e4ecSHeiko Carstens .byte = 1,
948bc1e4ecSHeiko Carstens .mask = 0xff,
958bc1e4ecSHeiko Carstens .format = (char *[]) {
968bc1e4ecSHeiko Carstens "E",
978bc1e4ecSHeiko Carstens "IE",
988bc1e4ecSHeiko Carstens "RRE",
998bc1e4ecSHeiko Carstens "RRF",
1008bc1e4ecSHeiko Carstens "RRR",
1018bc1e4ecSHeiko Carstens "S",
1028bc1e4ecSHeiko Carstens "SIL",
1038bc1e4ecSHeiko Carstens "SSE",
1048bc1e4ecSHeiko Carstens NULL,
1058bc1e4ecSHeiko Carstens },
1068bc1e4ecSHeiko Carstens },
1078bc1e4ecSHeiko Carstens {
1088bc1e4ecSHeiko Carstens .byte = 5,
1098bc1e4ecSHeiko Carstens .mask = 0xff,
1108bc1e4ecSHeiko Carstens .format = (char *[]) {
1118bc1e4ecSHeiko Carstens "RIE",
1128bc1e4ecSHeiko Carstens "RIS",
1138bc1e4ecSHeiko Carstens "RRS",
1148bc1e4ecSHeiko Carstens "RSE",
1158bc1e4ecSHeiko Carstens "RSL",
1168bc1e4ecSHeiko Carstens "RSY",
1178bc1e4ecSHeiko Carstens "RXE",
1188bc1e4ecSHeiko Carstens "RXF",
1198bc1e4ecSHeiko Carstens "RXY",
1208bc1e4ecSHeiko Carstens "SIY",
1218bc1e4ecSHeiko Carstens "VRI",
1228bc1e4ecSHeiko Carstens "VRR",
1238bc1e4ecSHeiko Carstens "VRS",
1248bc1e4ecSHeiko Carstens "VRV",
1258bc1e4ecSHeiko Carstens "VRX",
1268bc1e4ecSHeiko Carstens "VSI",
1278bc1e4ecSHeiko Carstens NULL,
1288bc1e4ecSHeiko Carstens },
1298bc1e4ecSHeiko Carstens },
1308bc1e4ecSHeiko Carstens };
1318bc1e4ecSHeiko Carstens
insn_format_to_type(char * format)1328bc1e4ecSHeiko Carstens static struct insn_type *insn_format_to_type(char *format)
1338bc1e4ecSHeiko Carstens {
1348bc1e4ecSHeiko Carstens char tmp[STRING_SIZE_MAX];
1358bc1e4ecSHeiko Carstens char *base_format, **ptr;
1368bc1e4ecSHeiko Carstens int i;
1378bc1e4ecSHeiko Carstens
1388bc1e4ecSHeiko Carstens strcpy(tmp, format);
1398bc1e4ecSHeiko Carstens base_format = tmp;
1408bc1e4ecSHeiko Carstens base_format = strsep(&base_format, "_");
1418bc1e4ecSHeiko Carstens for (i = 0; i < sizeof(insn_type_table) / sizeof(insn_type_table[0]); i++) {
1428bc1e4ecSHeiko Carstens ptr = insn_type_table[i].format;
1438bc1e4ecSHeiko Carstens while (*ptr) {
1448bc1e4ecSHeiko Carstens if (!strcmp(base_format, *ptr))
1458bc1e4ecSHeiko Carstens return &insn_type_table[i];
1468bc1e4ecSHeiko Carstens ptr++;
1478bc1e4ecSHeiko Carstens }
1488bc1e4ecSHeiko Carstens }
1498bc1e4ecSHeiko Carstens exit(EXIT_FAILURE);
1508bc1e4ecSHeiko Carstens }
1518bc1e4ecSHeiko Carstens
read_instructions(struct gen_opcode * desc)1528bc1e4ecSHeiko Carstens static void read_instructions(struct gen_opcode *desc)
1538bc1e4ecSHeiko Carstens {
1548bc1e4ecSHeiko Carstens struct insn insn;
1558bc1e4ecSHeiko Carstens int rc, i;
1568bc1e4ecSHeiko Carstens
1578bc1e4ecSHeiko Carstens while (1) {
1588bc1e4ecSHeiko Carstens rc = scanf("%s %s %s", insn.opcode, insn.name, insn.format);
1598bc1e4ecSHeiko Carstens if (rc == EOF)
1608bc1e4ecSHeiko Carstens break;
1618bc1e4ecSHeiko Carstens if (rc != 3)
1628bc1e4ecSHeiko Carstens exit(EXIT_FAILURE);
1638bc1e4ecSHeiko Carstens insn.type = insn_format_to_type(insn.format);
1648bc1e4ecSHeiko Carstens insn.name_len = strlen(insn.name);
1658bc1e4ecSHeiko Carstens for (i = 0; i <= insn.name_len; i++)
1668bc1e4ecSHeiko Carstens insn.upper[i] = toupper((unsigned char)insn.name[i]);
1678bc1e4ecSHeiko Carstens desc->nr++;
1688bc1e4ecSHeiko Carstens desc->insn = realloc(desc->insn, desc->nr * sizeof(*desc->insn));
1698bc1e4ecSHeiko Carstens if (!desc->insn)
1708bc1e4ecSHeiko Carstens exit(EXIT_FAILURE);
1718bc1e4ecSHeiko Carstens desc->insn[desc->nr - 1] = insn;
1728bc1e4ecSHeiko Carstens }
1738bc1e4ecSHeiko Carstens }
1748bc1e4ecSHeiko Carstens
cmpformat(const void * a,const void * b)1758bc1e4ecSHeiko Carstens static int cmpformat(const void *a, const void *b)
1768bc1e4ecSHeiko Carstens {
1778bc1e4ecSHeiko Carstens return strcmp(((struct insn *)a)->format, ((struct insn *)b)->format);
1788bc1e4ecSHeiko Carstens }
1798bc1e4ecSHeiko Carstens
print_formats(struct gen_opcode * desc)1808bc1e4ecSHeiko Carstens static void print_formats(struct gen_opcode *desc)
1818bc1e4ecSHeiko Carstens {
1828bc1e4ecSHeiko Carstens char *format;
1838bc1e4ecSHeiko Carstens int i, count;
1848bc1e4ecSHeiko Carstens
1858bc1e4ecSHeiko Carstens qsort(desc->insn, desc->nr, sizeof(*desc->insn), cmpformat);
1868bc1e4ecSHeiko Carstens format = "";
1878bc1e4ecSHeiko Carstens count = 0;
1888bc1e4ecSHeiko Carstens printf("enum {\n");
1898bc1e4ecSHeiko Carstens for (i = 0; i < desc->nr; i++) {
1908bc1e4ecSHeiko Carstens if (!strcmp(format, desc->insn[i].format))
1918bc1e4ecSHeiko Carstens continue;
1928bc1e4ecSHeiko Carstens count++;
1938bc1e4ecSHeiko Carstens format = desc->insn[i].format;
1948bc1e4ecSHeiko Carstens printf("\tINSTR_%s,\n", format);
1958bc1e4ecSHeiko Carstens }
1968bc1e4ecSHeiko Carstens printf("}; /* %d */\n\n", count);
1978bc1e4ecSHeiko Carstens }
1988bc1e4ecSHeiko Carstens
cmp_long_insn(const void * a,const void * b)1998bc1e4ecSHeiko Carstens static int cmp_long_insn(const void *a, const void *b)
2008bc1e4ecSHeiko Carstens {
2018bc1e4ecSHeiko Carstens return strcmp(((struct insn *)a)->name, ((struct insn *)b)->name);
2028bc1e4ecSHeiko Carstens }
2038bc1e4ecSHeiko Carstens
print_long_insn(struct gen_opcode * desc)2048bc1e4ecSHeiko Carstens static void print_long_insn(struct gen_opcode *desc)
2058bc1e4ecSHeiko Carstens {
2068bc1e4ecSHeiko Carstens struct insn *insn;
2078bc1e4ecSHeiko Carstens int i, count;
2088bc1e4ecSHeiko Carstens
2098bc1e4ecSHeiko Carstens qsort(desc->insn, desc->nr, sizeof(*desc->insn), cmp_long_insn);
2108bc1e4ecSHeiko Carstens count = 0;
2118bc1e4ecSHeiko Carstens printf("enum {\n");
2128bc1e4ecSHeiko Carstens for (i = 0; i < desc->nr; i++) {
2138bc1e4ecSHeiko Carstens insn = &desc->insn[i];
2148bc1e4ecSHeiko Carstens if (insn->name_len < 6)
2158bc1e4ecSHeiko Carstens continue;
2168bc1e4ecSHeiko Carstens printf("\tLONG_INSN_%s,\n", insn->upper);
2178bc1e4ecSHeiko Carstens count++;
2188bc1e4ecSHeiko Carstens }
2198bc1e4ecSHeiko Carstens printf("}; /* %d */\n\n", count);
2208bc1e4ecSHeiko Carstens
2218bc1e4ecSHeiko Carstens printf("#define LONG_INSN_INITIALIZER { \\\n");
2228bc1e4ecSHeiko Carstens for (i = 0; i < desc->nr; i++) {
2238bc1e4ecSHeiko Carstens insn = &desc->insn[i];
2248bc1e4ecSHeiko Carstens if (insn->name_len < 6)
2258bc1e4ecSHeiko Carstens continue;
2268bc1e4ecSHeiko Carstens printf("\t[LONG_INSN_%s] = \"%s\", \\\n", insn->upper, insn->name);
2278bc1e4ecSHeiko Carstens }
2288bc1e4ecSHeiko Carstens printf("}\n\n");
2298bc1e4ecSHeiko Carstens }
2308bc1e4ecSHeiko Carstens
print_opcode(struct insn * insn,int nr)2318bc1e4ecSHeiko Carstens static void print_opcode(struct insn *insn, int nr)
2328bc1e4ecSHeiko Carstens {
2338bc1e4ecSHeiko Carstens char *opcode;
2348bc1e4ecSHeiko Carstens
2358bc1e4ecSHeiko Carstens opcode = insn->opcode;
2368bc1e4ecSHeiko Carstens if (insn->type->byte != 0)
2378bc1e4ecSHeiko Carstens opcode += 2;
2388bc1e4ecSHeiko Carstens printf("\t[%4d] = { .opfrag = 0x%s, .format = INSTR_%s, ", nr, opcode, insn->format);
2398bc1e4ecSHeiko Carstens if (insn->name_len < 6)
2408bc1e4ecSHeiko Carstens printf(".name = \"%s\" ", insn->name);
2418bc1e4ecSHeiko Carstens else
2428bc1e4ecSHeiko Carstens printf(".offset = LONG_INSN_%s ", insn->upper);
2438bc1e4ecSHeiko Carstens printf("}, \\\n");
2448bc1e4ecSHeiko Carstens }
2458bc1e4ecSHeiko Carstens
add_to_group(struct gen_opcode * desc,struct insn * insn,int offset)2468bc1e4ecSHeiko Carstens static void add_to_group(struct gen_opcode *desc, struct insn *insn, int offset)
2478bc1e4ecSHeiko Carstens {
2488bc1e4ecSHeiko Carstens struct insn_group *group;
2498bc1e4ecSHeiko Carstens
2508bc1e4ecSHeiko Carstens group = desc->group ? &desc->group[desc->nr_groups - 1] : NULL;
2518bc1e4ecSHeiko Carstens if (group && (!strncmp(group->opcode, insn->opcode, 2) || group->type->byte == 0)) {
2528bc1e4ecSHeiko Carstens group->count++;
2538bc1e4ecSHeiko Carstens return;
2548bc1e4ecSHeiko Carstens }
2558bc1e4ecSHeiko Carstens desc->nr_groups++;
2568bc1e4ecSHeiko Carstens desc->group = realloc(desc->group, desc->nr_groups * sizeof(*desc->group));
2578bc1e4ecSHeiko Carstens if (!desc->group)
2588bc1e4ecSHeiko Carstens exit(EXIT_FAILURE);
2598bc1e4ecSHeiko Carstens group = &desc->group[desc->nr_groups - 1];
260d053d639SVasily Gorbik memcpy(group->opcode, insn->opcode, 2);
2618bc1e4ecSHeiko Carstens group->type = insn->type;
2628bc1e4ecSHeiko Carstens group->offset = offset;
2638bc1e4ecSHeiko Carstens group->count = 1;
2648bc1e4ecSHeiko Carstens }
2658bc1e4ecSHeiko Carstens
cmpopcode(const void * a,const void * b)2668bc1e4ecSHeiko Carstens static int cmpopcode(const void *a, const void *b)
2678bc1e4ecSHeiko Carstens {
2688bc1e4ecSHeiko Carstens return strcmp(((struct insn *)a)->opcode, ((struct insn *)b)->opcode);
2698bc1e4ecSHeiko Carstens }
2708bc1e4ecSHeiko Carstens
print_opcode_table(struct gen_opcode * desc)2718bc1e4ecSHeiko Carstens static void print_opcode_table(struct gen_opcode *desc)
2728bc1e4ecSHeiko Carstens {
2738bc1e4ecSHeiko Carstens char opcode[2] = "";
2748bc1e4ecSHeiko Carstens struct insn *insn;
2758bc1e4ecSHeiko Carstens int i, offset;
2768bc1e4ecSHeiko Carstens
2778bc1e4ecSHeiko Carstens qsort(desc->insn, desc->nr, sizeof(*desc->insn), cmpopcode);
2788bc1e4ecSHeiko Carstens printf("#define OPCODE_TABLE_INITIALIZER { \\\n");
2798bc1e4ecSHeiko Carstens offset = 0;
2808bc1e4ecSHeiko Carstens for (i = 0; i < desc->nr; i++) {
2818bc1e4ecSHeiko Carstens insn = &desc->insn[i];
2828bc1e4ecSHeiko Carstens if (insn->type->byte == 0)
2838bc1e4ecSHeiko Carstens continue;
2848bc1e4ecSHeiko Carstens add_to_group(desc, insn, offset);
2858bc1e4ecSHeiko Carstens if (strncmp(opcode, insn->opcode, 2)) {
286d053d639SVasily Gorbik memcpy(opcode, insn->opcode, 2);
2878bc1e4ecSHeiko Carstens printf("\t/* %.2s */ \\\n", opcode);
2888bc1e4ecSHeiko Carstens }
2898bc1e4ecSHeiko Carstens print_opcode(insn, offset);
2908bc1e4ecSHeiko Carstens offset++;
2918bc1e4ecSHeiko Carstens }
2928bc1e4ecSHeiko Carstens printf("\t/* 1-byte opcode instructions */ \\\n");
2938bc1e4ecSHeiko Carstens for (i = 0; i < desc->nr; i++) {
2948bc1e4ecSHeiko Carstens insn = &desc->insn[i];
2958bc1e4ecSHeiko Carstens if (insn->type->byte != 0)
2968bc1e4ecSHeiko Carstens continue;
2978bc1e4ecSHeiko Carstens add_to_group(desc, insn, offset);
2988bc1e4ecSHeiko Carstens print_opcode(insn, offset);
2998bc1e4ecSHeiko Carstens offset++;
3008bc1e4ecSHeiko Carstens }
3018bc1e4ecSHeiko Carstens printf("}\n\n");
3028bc1e4ecSHeiko Carstens }
3038bc1e4ecSHeiko Carstens
print_opcode_table_offsets(struct gen_opcode * desc)3048bc1e4ecSHeiko Carstens static void print_opcode_table_offsets(struct gen_opcode *desc)
3058bc1e4ecSHeiko Carstens {
3068bc1e4ecSHeiko Carstens struct insn_group *group;
3078bc1e4ecSHeiko Carstens int i;
3088bc1e4ecSHeiko Carstens
3098bc1e4ecSHeiko Carstens printf("#define OPCODE_OFFSET_INITIALIZER { \\\n");
3108bc1e4ecSHeiko Carstens for (i = 0; i < desc->nr_groups; i++) {
3118bc1e4ecSHeiko Carstens group = &desc->group[i];
3128bc1e4ecSHeiko Carstens printf("\t{ .opcode = 0x%.2s, .mask = 0x%02x, .byte = %d, .offset = %d, .count = %d }, \\\n",
3138bc1e4ecSHeiko Carstens group->opcode, group->type->mask, group->type->byte, group->offset, group->count);
3148bc1e4ecSHeiko Carstens }
3158bc1e4ecSHeiko Carstens printf("}\n\n");
3168bc1e4ecSHeiko Carstens }
3178bc1e4ecSHeiko Carstens
main(int argc,char ** argv)3188bc1e4ecSHeiko Carstens int main(int argc, char **argv)
3198bc1e4ecSHeiko Carstens {
3208bc1e4ecSHeiko Carstens struct gen_opcode _desc = { 0 };
3218bc1e4ecSHeiko Carstens struct gen_opcode *desc = &_desc;
3228bc1e4ecSHeiko Carstens
3238bc1e4ecSHeiko Carstens read_instructions(desc);
3247fbf8315SHendrik Brueckner printf("#ifndef __S390_GENERATED_DIS_DEFS_H__\n");
3257fbf8315SHendrik Brueckner printf("#define __S390_GENERATED_DIS_DEFS_H__\n");
3268bc1e4ecSHeiko Carstens printf("/*\n");
3278bc1e4ecSHeiko Carstens printf(" * DO NOT MODIFY.\n");
3288bc1e4ecSHeiko Carstens printf(" *\n");
3298bc1e4ecSHeiko Carstens printf(" * This file was generated by %s\n", __FILE__);
3308bc1e4ecSHeiko Carstens printf(" */\n\n");
3318bc1e4ecSHeiko Carstens print_formats(desc);
3328bc1e4ecSHeiko Carstens print_long_insn(desc);
3338bc1e4ecSHeiko Carstens print_opcode_table(desc);
3348bc1e4ecSHeiko Carstens print_opcode_table_offsets(desc);
3358bc1e4ecSHeiko Carstens printf("#endif\n");
3368bc1e4ecSHeiko Carstens exit(EXIT_SUCCESS);
3378bc1e4ecSHeiko Carstens }
338