162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Generate opcode table initializers for the in-kernel disassembler. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright IBM Corp. 2017 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <stdlib.h> 1062306a36Sopenharmony_ci#include <string.h> 1162306a36Sopenharmony_ci#include <ctype.h> 1262306a36Sopenharmony_ci#include <stdio.h> 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#define STRING_SIZE_MAX 20 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_cistruct insn_type { 1762306a36Sopenharmony_ci unsigned char byte; 1862306a36Sopenharmony_ci unsigned char mask; 1962306a36Sopenharmony_ci char **format; 2062306a36Sopenharmony_ci}; 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_cistruct insn { 2362306a36Sopenharmony_ci struct insn_type *type; 2462306a36Sopenharmony_ci char opcode[STRING_SIZE_MAX]; 2562306a36Sopenharmony_ci char name[STRING_SIZE_MAX]; 2662306a36Sopenharmony_ci char upper[STRING_SIZE_MAX]; 2762306a36Sopenharmony_ci char format[STRING_SIZE_MAX]; 2862306a36Sopenharmony_ci unsigned int name_len; 2962306a36Sopenharmony_ci}; 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_cistruct insn_group { 3262306a36Sopenharmony_ci struct insn_type *type; 3362306a36Sopenharmony_ci int offset; 3462306a36Sopenharmony_ci int count; 3562306a36Sopenharmony_ci char opcode[2]; 3662306a36Sopenharmony_ci}; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_cistruct insn_format { 3962306a36Sopenharmony_ci char *format; 4062306a36Sopenharmony_ci int type; 4162306a36Sopenharmony_ci}; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_cistruct gen_opcode { 4462306a36Sopenharmony_ci struct insn *insn; 4562306a36Sopenharmony_ci int nr; 4662306a36Sopenharmony_ci struct insn_group *group; 4762306a36Sopenharmony_ci int nr_groups; 4862306a36Sopenharmony_ci}; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci/* 5162306a36Sopenharmony_ci * Table of instruction format types. Each opcode is defined with at 5262306a36Sopenharmony_ci * least one byte (two nibbles), three nibbles, or two bytes (four 5362306a36Sopenharmony_ci * nibbles). 5462306a36Sopenharmony_ci * The byte member of each instruction format type entry defines 5562306a36Sopenharmony_ci * within which byte of an instruction the third (and fourth) nibble 5662306a36Sopenharmony_ci * of an opcode can be found. The mask member is the and-mask that 5762306a36Sopenharmony_ci * needs to be applied on this byte in order to get the third (and 5862306a36Sopenharmony_ci * fourth) nibble of the opcode. 5962306a36Sopenharmony_ci * The format array defines all instruction formats (as defined in the 6062306a36Sopenharmony_ci * Principles of Operation) which have the same position of the opcode 6162306a36Sopenharmony_ci * nibbles. 6262306a36Sopenharmony_ci * A special case are instruction formats with 1-byte opcodes. In this 6362306a36Sopenharmony_ci * case the byte member always is zero, so that the mask is applied on 6462306a36Sopenharmony_ci * the (only) byte that contains the opcode. 6562306a36Sopenharmony_ci */ 6662306a36Sopenharmony_cistatic struct insn_type insn_type_table[] = { 6762306a36Sopenharmony_ci { 6862306a36Sopenharmony_ci .byte = 0, 6962306a36Sopenharmony_ci .mask = 0xff, 7062306a36Sopenharmony_ci .format = (char *[]) { 7162306a36Sopenharmony_ci "MII", 7262306a36Sopenharmony_ci "RR", 7362306a36Sopenharmony_ci "RS", 7462306a36Sopenharmony_ci "RSI", 7562306a36Sopenharmony_ci "RX", 7662306a36Sopenharmony_ci "SI", 7762306a36Sopenharmony_ci "SMI", 7862306a36Sopenharmony_ci "SS", 7962306a36Sopenharmony_ci NULL, 8062306a36Sopenharmony_ci }, 8162306a36Sopenharmony_ci }, 8262306a36Sopenharmony_ci { 8362306a36Sopenharmony_ci .byte = 1, 8462306a36Sopenharmony_ci .mask = 0x0f, 8562306a36Sopenharmony_ci .format = (char *[]) { 8662306a36Sopenharmony_ci "RI", 8762306a36Sopenharmony_ci "RIL", 8862306a36Sopenharmony_ci "SSF", 8962306a36Sopenharmony_ci NULL, 9062306a36Sopenharmony_ci }, 9162306a36Sopenharmony_ci }, 9262306a36Sopenharmony_ci { 9362306a36Sopenharmony_ci .byte = 1, 9462306a36Sopenharmony_ci .mask = 0xff, 9562306a36Sopenharmony_ci .format = (char *[]) { 9662306a36Sopenharmony_ci "E", 9762306a36Sopenharmony_ci "IE", 9862306a36Sopenharmony_ci "RRE", 9962306a36Sopenharmony_ci "RRF", 10062306a36Sopenharmony_ci "RRR", 10162306a36Sopenharmony_ci "S", 10262306a36Sopenharmony_ci "SIL", 10362306a36Sopenharmony_ci "SSE", 10462306a36Sopenharmony_ci NULL, 10562306a36Sopenharmony_ci }, 10662306a36Sopenharmony_ci }, 10762306a36Sopenharmony_ci { 10862306a36Sopenharmony_ci .byte = 5, 10962306a36Sopenharmony_ci .mask = 0xff, 11062306a36Sopenharmony_ci .format = (char *[]) { 11162306a36Sopenharmony_ci "RIE", 11262306a36Sopenharmony_ci "RIS", 11362306a36Sopenharmony_ci "RRS", 11462306a36Sopenharmony_ci "RSE", 11562306a36Sopenharmony_ci "RSL", 11662306a36Sopenharmony_ci "RSY", 11762306a36Sopenharmony_ci "RXE", 11862306a36Sopenharmony_ci "RXF", 11962306a36Sopenharmony_ci "RXY", 12062306a36Sopenharmony_ci "SIY", 12162306a36Sopenharmony_ci "VRI", 12262306a36Sopenharmony_ci "VRR", 12362306a36Sopenharmony_ci "VRS", 12462306a36Sopenharmony_ci "VRV", 12562306a36Sopenharmony_ci "VRX", 12662306a36Sopenharmony_ci "VSI", 12762306a36Sopenharmony_ci NULL, 12862306a36Sopenharmony_ci }, 12962306a36Sopenharmony_ci }, 13062306a36Sopenharmony_ci}; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_cistatic struct insn_type *insn_format_to_type(char *format) 13362306a36Sopenharmony_ci{ 13462306a36Sopenharmony_ci char tmp[STRING_SIZE_MAX]; 13562306a36Sopenharmony_ci char *base_format, **ptr; 13662306a36Sopenharmony_ci int i; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci strcpy(tmp, format); 13962306a36Sopenharmony_ci base_format = tmp; 14062306a36Sopenharmony_ci base_format = strsep(&base_format, "_"); 14162306a36Sopenharmony_ci for (i = 0; i < sizeof(insn_type_table) / sizeof(insn_type_table[0]); i++) { 14262306a36Sopenharmony_ci ptr = insn_type_table[i].format; 14362306a36Sopenharmony_ci while (*ptr) { 14462306a36Sopenharmony_ci if (!strcmp(base_format, *ptr)) 14562306a36Sopenharmony_ci return &insn_type_table[i]; 14662306a36Sopenharmony_ci ptr++; 14762306a36Sopenharmony_ci } 14862306a36Sopenharmony_ci } 14962306a36Sopenharmony_ci exit(EXIT_FAILURE); 15062306a36Sopenharmony_ci} 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_cistatic void read_instructions(struct gen_opcode *desc) 15362306a36Sopenharmony_ci{ 15462306a36Sopenharmony_ci struct insn insn; 15562306a36Sopenharmony_ci int rc, i; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci while (1) { 15862306a36Sopenharmony_ci rc = scanf("%s %s %s", insn.opcode, insn.name, insn.format); 15962306a36Sopenharmony_ci if (rc == EOF) 16062306a36Sopenharmony_ci break; 16162306a36Sopenharmony_ci if (rc != 3) 16262306a36Sopenharmony_ci exit(EXIT_FAILURE); 16362306a36Sopenharmony_ci insn.type = insn_format_to_type(insn.format); 16462306a36Sopenharmony_ci insn.name_len = strlen(insn.name); 16562306a36Sopenharmony_ci for (i = 0; i <= insn.name_len; i++) 16662306a36Sopenharmony_ci insn.upper[i] = toupper((unsigned char)insn.name[i]); 16762306a36Sopenharmony_ci desc->nr++; 16862306a36Sopenharmony_ci desc->insn = realloc(desc->insn, desc->nr * sizeof(*desc->insn)); 16962306a36Sopenharmony_ci if (!desc->insn) 17062306a36Sopenharmony_ci exit(EXIT_FAILURE); 17162306a36Sopenharmony_ci desc->insn[desc->nr - 1] = insn; 17262306a36Sopenharmony_ci } 17362306a36Sopenharmony_ci} 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_cistatic int cmpformat(const void *a, const void *b) 17662306a36Sopenharmony_ci{ 17762306a36Sopenharmony_ci return strcmp(((struct insn *)a)->format, ((struct insn *)b)->format); 17862306a36Sopenharmony_ci} 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_cistatic void print_formats(struct gen_opcode *desc) 18162306a36Sopenharmony_ci{ 18262306a36Sopenharmony_ci char *format; 18362306a36Sopenharmony_ci int i, count; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci qsort(desc->insn, desc->nr, sizeof(*desc->insn), cmpformat); 18662306a36Sopenharmony_ci format = ""; 18762306a36Sopenharmony_ci count = 0; 18862306a36Sopenharmony_ci printf("enum {\n"); 18962306a36Sopenharmony_ci for (i = 0; i < desc->nr; i++) { 19062306a36Sopenharmony_ci if (!strcmp(format, desc->insn[i].format)) 19162306a36Sopenharmony_ci continue; 19262306a36Sopenharmony_ci count++; 19362306a36Sopenharmony_ci format = desc->insn[i].format; 19462306a36Sopenharmony_ci printf("\tINSTR_%s,\n", format); 19562306a36Sopenharmony_ci } 19662306a36Sopenharmony_ci printf("}; /* %d */\n\n", count); 19762306a36Sopenharmony_ci} 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_cistatic int cmp_long_insn(const void *a, const void *b) 20062306a36Sopenharmony_ci{ 20162306a36Sopenharmony_ci return strcmp(((struct insn *)a)->name, ((struct insn *)b)->name); 20262306a36Sopenharmony_ci} 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_cistatic void print_long_insn(struct gen_opcode *desc) 20562306a36Sopenharmony_ci{ 20662306a36Sopenharmony_ci struct insn *insn; 20762306a36Sopenharmony_ci int i, count; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci qsort(desc->insn, desc->nr, sizeof(*desc->insn), cmp_long_insn); 21062306a36Sopenharmony_ci count = 0; 21162306a36Sopenharmony_ci printf("enum {\n"); 21262306a36Sopenharmony_ci for (i = 0; i < desc->nr; i++) { 21362306a36Sopenharmony_ci insn = &desc->insn[i]; 21462306a36Sopenharmony_ci if (insn->name_len < 6) 21562306a36Sopenharmony_ci continue; 21662306a36Sopenharmony_ci printf("\tLONG_INSN_%s,\n", insn->upper); 21762306a36Sopenharmony_ci count++; 21862306a36Sopenharmony_ci } 21962306a36Sopenharmony_ci printf("}; /* %d */\n\n", count); 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci printf("#define LONG_INSN_INITIALIZER { \\\n"); 22262306a36Sopenharmony_ci for (i = 0; i < desc->nr; i++) { 22362306a36Sopenharmony_ci insn = &desc->insn[i]; 22462306a36Sopenharmony_ci if (insn->name_len < 6) 22562306a36Sopenharmony_ci continue; 22662306a36Sopenharmony_ci printf("\t[LONG_INSN_%s] = \"%s\", \\\n", insn->upper, insn->name); 22762306a36Sopenharmony_ci } 22862306a36Sopenharmony_ci printf("}\n\n"); 22962306a36Sopenharmony_ci} 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_cistatic void print_opcode(struct insn *insn, int nr) 23262306a36Sopenharmony_ci{ 23362306a36Sopenharmony_ci char *opcode; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci opcode = insn->opcode; 23662306a36Sopenharmony_ci if (insn->type->byte != 0) 23762306a36Sopenharmony_ci opcode += 2; 23862306a36Sopenharmony_ci printf("\t[%4d] = { .opfrag = 0x%s, .format = INSTR_%s, ", nr, opcode, insn->format); 23962306a36Sopenharmony_ci if (insn->name_len < 6) 24062306a36Sopenharmony_ci printf(".name = \"%s\" ", insn->name); 24162306a36Sopenharmony_ci else 24262306a36Sopenharmony_ci printf(".offset = LONG_INSN_%s ", insn->upper); 24362306a36Sopenharmony_ci printf("}, \\\n"); 24462306a36Sopenharmony_ci} 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_cistatic void add_to_group(struct gen_opcode *desc, struct insn *insn, int offset) 24762306a36Sopenharmony_ci{ 24862306a36Sopenharmony_ci struct insn_group *group; 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci group = desc->group ? &desc->group[desc->nr_groups - 1] : NULL; 25162306a36Sopenharmony_ci if (group && (!strncmp(group->opcode, insn->opcode, 2) || group->type->byte == 0)) { 25262306a36Sopenharmony_ci group->count++; 25362306a36Sopenharmony_ci return; 25462306a36Sopenharmony_ci } 25562306a36Sopenharmony_ci desc->nr_groups++; 25662306a36Sopenharmony_ci desc->group = realloc(desc->group, desc->nr_groups * sizeof(*desc->group)); 25762306a36Sopenharmony_ci if (!desc->group) 25862306a36Sopenharmony_ci exit(EXIT_FAILURE); 25962306a36Sopenharmony_ci group = &desc->group[desc->nr_groups - 1]; 26062306a36Sopenharmony_ci memcpy(group->opcode, insn->opcode, 2); 26162306a36Sopenharmony_ci group->type = insn->type; 26262306a36Sopenharmony_ci group->offset = offset; 26362306a36Sopenharmony_ci group->count = 1; 26462306a36Sopenharmony_ci} 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_cistatic int cmpopcode(const void *a, const void *b) 26762306a36Sopenharmony_ci{ 26862306a36Sopenharmony_ci return strcmp(((struct insn *)a)->opcode, ((struct insn *)b)->opcode); 26962306a36Sopenharmony_ci} 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_cistatic void print_opcode_table(struct gen_opcode *desc) 27262306a36Sopenharmony_ci{ 27362306a36Sopenharmony_ci char opcode[2] = ""; 27462306a36Sopenharmony_ci struct insn *insn; 27562306a36Sopenharmony_ci int i, offset; 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci qsort(desc->insn, desc->nr, sizeof(*desc->insn), cmpopcode); 27862306a36Sopenharmony_ci printf("#define OPCODE_TABLE_INITIALIZER { \\\n"); 27962306a36Sopenharmony_ci offset = 0; 28062306a36Sopenharmony_ci for (i = 0; i < desc->nr; i++) { 28162306a36Sopenharmony_ci insn = &desc->insn[i]; 28262306a36Sopenharmony_ci if (insn->type->byte == 0) 28362306a36Sopenharmony_ci continue; 28462306a36Sopenharmony_ci add_to_group(desc, insn, offset); 28562306a36Sopenharmony_ci if (strncmp(opcode, insn->opcode, 2)) { 28662306a36Sopenharmony_ci memcpy(opcode, insn->opcode, 2); 28762306a36Sopenharmony_ci printf("\t/* %.2s */ \\\n", opcode); 28862306a36Sopenharmony_ci } 28962306a36Sopenharmony_ci print_opcode(insn, offset); 29062306a36Sopenharmony_ci offset++; 29162306a36Sopenharmony_ci } 29262306a36Sopenharmony_ci printf("\t/* 1-byte opcode instructions */ \\\n"); 29362306a36Sopenharmony_ci for (i = 0; i < desc->nr; i++) { 29462306a36Sopenharmony_ci insn = &desc->insn[i]; 29562306a36Sopenharmony_ci if (insn->type->byte != 0) 29662306a36Sopenharmony_ci continue; 29762306a36Sopenharmony_ci add_to_group(desc, insn, offset); 29862306a36Sopenharmony_ci print_opcode(insn, offset); 29962306a36Sopenharmony_ci offset++; 30062306a36Sopenharmony_ci } 30162306a36Sopenharmony_ci printf("}\n\n"); 30262306a36Sopenharmony_ci} 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_cistatic void print_opcode_table_offsets(struct gen_opcode *desc) 30562306a36Sopenharmony_ci{ 30662306a36Sopenharmony_ci struct insn_group *group; 30762306a36Sopenharmony_ci int i; 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci printf("#define OPCODE_OFFSET_INITIALIZER { \\\n"); 31062306a36Sopenharmony_ci for (i = 0; i < desc->nr_groups; i++) { 31162306a36Sopenharmony_ci group = &desc->group[i]; 31262306a36Sopenharmony_ci printf("\t{ .opcode = 0x%.2s, .mask = 0x%02x, .byte = %d, .offset = %d, .count = %d }, \\\n", 31362306a36Sopenharmony_ci group->opcode, group->type->mask, group->type->byte, group->offset, group->count); 31462306a36Sopenharmony_ci } 31562306a36Sopenharmony_ci printf("}\n\n"); 31662306a36Sopenharmony_ci} 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ciint main(int argc, char **argv) 31962306a36Sopenharmony_ci{ 32062306a36Sopenharmony_ci struct gen_opcode _desc = { 0 }; 32162306a36Sopenharmony_ci struct gen_opcode *desc = &_desc; 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci read_instructions(desc); 32462306a36Sopenharmony_ci printf("#ifndef __S390_GENERATED_DIS_DEFS_H__\n"); 32562306a36Sopenharmony_ci printf("#define __S390_GENERATED_DIS_DEFS_H__\n"); 32662306a36Sopenharmony_ci printf("/*\n"); 32762306a36Sopenharmony_ci printf(" * DO NOT MODIFY.\n"); 32862306a36Sopenharmony_ci printf(" *\n"); 32962306a36Sopenharmony_ci printf(" * This file was generated by %s\n", __FILE__); 33062306a36Sopenharmony_ci printf(" */\n\n"); 33162306a36Sopenharmony_ci print_formats(desc); 33262306a36Sopenharmony_ci print_long_insn(desc); 33362306a36Sopenharmony_ci print_opcode_table(desc); 33462306a36Sopenharmony_ci print_opcode_table_offsets(desc); 33562306a36Sopenharmony_ci printf("#endif\n"); 33662306a36Sopenharmony_ci exit(EXIT_SUCCESS); 33762306a36Sopenharmony_ci} 338