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