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