gen_opcode_table.c (7416B)
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 16struct insn_type { 17 unsigned char byte; 18 unsigned char mask; 19 char **format; 20}; 21 22struct 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 31struct insn_group { 32 struct insn_type *type; 33 int offset; 34 int count; 35 char opcode[2]; 36}; 37 38struct insn_format { 39 char *format; 40 int type; 41}; 42 43struct 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 */ 66static 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 132static 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 152static 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 175static int cmpformat(const void *a, const void *b) 176{ 177 return strcmp(((struct insn *)a)->format, ((struct insn *)b)->format); 178} 179 180static 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 199static int cmp_long_insn(const void *a, const void *b) 200{ 201 return strcmp(((struct insn *)a)->name, ((struct insn *)b)->name); 202} 203 204static void print_long_insn(struct gen_opcode *desc) 205{ 206 struct insn *insn; 207 int i, count; 208 209 qsort(desc->insn, desc->nr, sizeof(*desc->insn), cmp_long_insn); 210 count = 0; 211 printf("enum {\n"); 212 for (i = 0; i < desc->nr; i++) { 213 insn = &desc->insn[i]; 214 if (insn->name_len < 6) 215 continue; 216 printf("\tLONG_INSN_%s,\n", insn->upper); 217 count++; 218 } 219 printf("}; /* %d */\n\n", count); 220 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) 225 continue; 226 printf("\t[LONG_INSN_%s] = \"%s\", \\\n", insn->upper, insn->name); 227 } 228 printf("}\n\n"); 229} 230 231static void print_opcode(struct insn *insn, int nr) 232{ 233 char *opcode; 234 235 opcode = insn->opcode; 236 if (insn->type->byte != 0) 237 opcode += 2; 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); 241 else 242 printf(".offset = LONG_INSN_%s ", insn->upper); 243 printf("}, \\\n"); 244} 245 246static void add_to_group(struct gen_opcode *desc, struct insn *insn, int offset) 247{ 248 struct insn_group *group; 249 250 group = desc->group ? &desc->group[desc->nr_groups - 1] : NULL; 251 if (group && (!strncmp(group->opcode, insn->opcode, 2) || group->type->byte == 0)) { 252 group->count++; 253 return; 254 } 255 desc->nr_groups++; 256 desc->group = realloc(desc->group, desc->nr_groups * sizeof(*desc->group)); 257 if (!desc->group) 258 exit(EXIT_FAILURE); 259 group = &desc->group[desc->nr_groups - 1]; 260 memcpy(group->opcode, insn->opcode, 2); 261 group->type = insn->type; 262 group->offset = offset; 263 group->count = 1; 264} 265 266static int cmpopcode(const void *a, const void *b) 267{ 268 return strcmp(((struct insn *)a)->opcode, ((struct insn *)b)->opcode); 269} 270 271static void print_opcode_table(struct gen_opcode *desc) 272{ 273 char opcode[2] = ""; 274 struct insn *insn; 275 int i, offset; 276 277 qsort(desc->insn, desc->nr, sizeof(*desc->insn), cmpopcode); 278 printf("#define OPCODE_TABLE_INITIALIZER { \\\n"); 279 offset = 0; 280 for (i = 0; i < desc->nr; i++) { 281 insn = &desc->insn[i]; 282 if (insn->type->byte == 0) 283 continue; 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); 288 } 289 print_opcode(insn, offset); 290 offset++; 291 } 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) 296 continue; 297 add_to_group(desc, insn, offset); 298 print_opcode(insn, offset); 299 offset++; 300 } 301 printf("}\n\n"); 302} 303 304static void print_opcode_table_offsets(struct gen_opcode *desc) 305{ 306 struct insn_group *group; 307 int i; 308 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); 314 } 315 printf("}\n\n"); 316} 317 318int main(int argc, char **argv) 319{ 320 struct gen_opcode _desc = { 0 }; 321 struct gen_opcode *desc = &_desc; 322 323 read_instructions(desc); 324 printf("#ifndef __S390_GENERATED_DIS_DEFS_H__\n"); 325 printf("#define __S390_GENERATED_DIS_DEFS_H__\n"); 326 printf("/*\n"); 327 printf(" * DO NOT MODIFY.\n"); 328 printf(" *\n"); 329 printf(" * This file was generated by %s\n", __FILE__); 330 printf(" */\n\n"); 331 print_formats(desc); 332 print_long_insn(desc); 333 print_opcode_table(desc); 334 print_opcode_table_offsets(desc); 335 printf("#endif\n"); 336 exit(EXIT_SUCCESS); 337}