1 /* 2 * Generate opcode table initializers for the in-kernel disassembler. 3 * 4 * Copyright IBM Corp. 2017 5 * 6 */ 7 8 #include <stdlib.h> 9 #include <string.h> 10 #include <ctype.h> 11 #include <stdio.h> 12 13 #define STRING_SIZE_MAX 20 14 15 struct insn_type { 16 unsigned char byte; 17 unsigned char mask; 18 char **format; 19 }; 20 21 struct insn { 22 struct insn_type *type; 23 char opcode[STRING_SIZE_MAX]; 24 char name[STRING_SIZE_MAX]; 25 char upper[STRING_SIZE_MAX]; 26 char format[STRING_SIZE_MAX]; 27 unsigned int name_len; 28 }; 29 30 struct insn_group { 31 struct insn_type *type; 32 int offset; 33 int count; 34 char opcode[2]; 35 }; 36 37 struct insn_format { 38 char *format; 39 int type; 40 }; 41 42 struct gen_opcode { 43 struct insn *insn; 44 int nr; 45 struct insn_group *group; 46 int nr_groups; 47 }; 48 49 /* 50 * Table of instruction format types. Each opcode is defined with at 51 * least one byte (two nibbles), three nibbles, or two bytes (four 52 * nibbles). 53 * The byte member of each instruction format type entry defines 54 * within which byte of an instruction the third (and fourth) nibble 55 * of an opcode can be found. The mask member is the and-mask that 56 * needs to be applied on this byte in order to get the third (and 57 * fourth) nibble of the opcode. 58 * The format array defines all instruction formats (as defined in the 59 * Principles of Operation) which have the same position of the opcode 60 * nibbles. 61 * A special case are instruction formats with 1-byte opcodes. In this 62 * case the byte member always is zero, so that the mask is applied on 63 * the (only) byte that contains the opcode. 64 */ 65 static struct insn_type insn_type_table[] = { 66 { 67 .byte = 0, 68 .mask = 0xff, 69 .format = (char *[]) { 70 "MII", 71 "RR", 72 "RS", 73 "RSI", 74 "RX", 75 "SI", 76 "SMI", 77 "SS", 78 NULL, 79 }, 80 }, 81 { 82 .byte = 1, 83 .mask = 0x0f, 84 .format = (char *[]) { 85 "RI", 86 "RIL", 87 "SSF", 88 NULL, 89 }, 90 }, 91 { 92 .byte = 1, 93 .mask = 0xff, 94 .format = (char *[]) { 95 "E", 96 "IE", 97 "RRE", 98 "RRF", 99 "RRR", 100 "S", 101 "SIL", 102 "SSE", 103 NULL, 104 }, 105 }, 106 { 107 .byte = 5, 108 .mask = 0xff, 109 .format = (char *[]) { 110 "RIE", 111 "RIS", 112 "RRS", 113 "RSE", 114 "RSL", 115 "RSY", 116 "RXE", 117 "RXF", 118 "RXY", 119 "SIY", 120 "VRI", 121 "VRR", 122 "VRS", 123 "VRV", 124 "VRX", 125 "VSI", 126 NULL, 127 }, 128 }, 129 }; 130 131 static struct insn_type *insn_format_to_type(char *format) 132 { 133 char tmp[STRING_SIZE_MAX]; 134 char *base_format, **ptr; 135 int i; 136 137 strcpy(tmp, format); 138 base_format = tmp; 139 base_format = strsep(&base_format, "_"); 140 for (i = 0; i < sizeof(insn_type_table) / sizeof(insn_type_table[0]); i++) { 141 ptr = insn_type_table[i].format; 142 while (*ptr) { 143 if (!strcmp(base_format, *ptr)) 144 return &insn_type_table[i]; 145 ptr++; 146 } 147 } 148 exit(EXIT_FAILURE); 149 } 150 151 static void read_instructions(struct gen_opcode *desc) 152 { 153 struct insn insn; 154 int rc, i; 155 156 while (1) { 157 rc = scanf("%s %s %s", insn.opcode, insn.name, insn.format); 158 if (rc == EOF) 159 break; 160 if (rc != 3) 161 exit(EXIT_FAILURE); 162 insn.type = insn_format_to_type(insn.format); 163 insn.name_len = strlen(insn.name); 164 for (i = 0; i <= insn.name_len; i++) 165 insn.upper[i] = toupper((unsigned char)insn.name[i]); 166 desc->nr++; 167 desc->insn = realloc(desc->insn, desc->nr * sizeof(*desc->insn)); 168 if (!desc->insn) 169 exit(EXIT_FAILURE); 170 desc->insn[desc->nr - 1] = insn; 171 } 172 } 173 174 static int cmpformat(const void *a, const void *b) 175 { 176 return strcmp(((struct insn *)a)->format, ((struct insn *)b)->format); 177 } 178 179 static void print_formats(struct gen_opcode *desc) 180 { 181 char *format; 182 int i, count; 183 184 qsort(desc->insn, desc->nr, sizeof(*desc->insn), cmpformat); 185 format = ""; 186 count = 0; 187 printf("enum {\n"); 188 for (i = 0; i < desc->nr; i++) { 189 if (!strcmp(format, desc->insn[i].format)) 190 continue; 191 count++; 192 format = desc->insn[i].format; 193 printf("\tINSTR_%s,\n", format); 194 } 195 printf("}; /* %d */\n\n", count); 196 } 197 198 static int cmp_long_insn(const void *a, const void *b) 199 { 200 return strcmp(((struct insn *)a)->name, ((struct insn *)b)->name); 201 } 202 203 static void print_long_insn(struct gen_opcode *desc) 204 { 205 struct insn *insn; 206 int i, count; 207 208 qsort(desc->insn, desc->nr, sizeof(*desc->insn), cmp_long_insn); 209 count = 0; 210 printf("enum {\n"); 211 for (i = 0; i < desc->nr; i++) { 212 insn = &desc->insn[i]; 213 if (insn->name_len < 6) 214 continue; 215 printf("\tLONG_INSN_%s,\n", insn->upper); 216 count++; 217 } 218 printf("}; /* %d */\n\n", count); 219 220 printf("#define LONG_INSN_INITIALIZER { \\\n"); 221 for (i = 0; i < desc->nr; i++) { 222 insn = &desc->insn[i]; 223 if (insn->name_len < 6) 224 continue; 225 printf("\t[LONG_INSN_%s] = \"%s\", \\\n", insn->upper, insn->name); 226 } 227 printf("}\n\n"); 228 } 229 230 static void print_opcode(struct insn *insn, int nr) 231 { 232 char *opcode; 233 234 opcode = insn->opcode; 235 if (insn->type->byte != 0) 236 opcode += 2; 237 printf("\t[%4d] = { .opfrag = 0x%s, .format = INSTR_%s, ", nr, opcode, insn->format); 238 if (insn->name_len < 6) 239 printf(".name = \"%s\" ", insn->name); 240 else 241 printf(".offset = LONG_INSN_%s ", insn->upper); 242 printf("}, \\\n"); 243 } 244 245 static void add_to_group(struct gen_opcode *desc, struct insn *insn, int offset) 246 { 247 struct insn_group *group; 248 249 group = desc->group ? &desc->group[desc->nr_groups - 1] : NULL; 250 if (group && (!strncmp(group->opcode, insn->opcode, 2) || group->type->byte == 0)) { 251 group->count++; 252 return; 253 } 254 desc->nr_groups++; 255 desc->group = realloc(desc->group, desc->nr_groups * sizeof(*desc->group)); 256 if (!desc->group) 257 exit(EXIT_FAILURE); 258 group = &desc->group[desc->nr_groups - 1]; 259 strncpy(group->opcode, insn->opcode, 2); 260 group->type = insn->type; 261 group->offset = offset; 262 group->count = 1; 263 } 264 265 static int cmpopcode(const void *a, const void *b) 266 { 267 return strcmp(((struct insn *)a)->opcode, ((struct insn *)b)->opcode); 268 } 269 270 static void print_opcode_table(struct gen_opcode *desc) 271 { 272 char opcode[2] = ""; 273 struct insn *insn; 274 int i, offset; 275 276 qsort(desc->insn, desc->nr, sizeof(*desc->insn), cmpopcode); 277 printf("#define OPCODE_TABLE_INITIALIZER { \\\n"); 278 offset = 0; 279 for (i = 0; i < desc->nr; i++) { 280 insn = &desc->insn[i]; 281 if (insn->type->byte == 0) 282 continue; 283 add_to_group(desc, insn, offset); 284 if (strncmp(opcode, insn->opcode, 2)) { 285 strncpy(opcode, insn->opcode, 2); 286 printf("\t/* %.2s */ \\\n", opcode); 287 } 288 print_opcode(insn, offset); 289 offset++; 290 } 291 printf("\t/* 1-byte opcode instructions */ \\\n"); 292 for (i = 0; i < desc->nr; i++) { 293 insn = &desc->insn[i]; 294 if (insn->type->byte != 0) 295 continue; 296 add_to_group(desc, insn, offset); 297 print_opcode(insn, offset); 298 offset++; 299 } 300 printf("}\n\n"); 301 } 302 303 static void print_opcode_table_offsets(struct gen_opcode *desc) 304 { 305 struct insn_group *group; 306 int i; 307 308 printf("#define OPCODE_OFFSET_INITIALIZER { \\\n"); 309 for (i = 0; i < desc->nr_groups; i++) { 310 group = &desc->group[i]; 311 printf("\t{ .opcode = 0x%.2s, .mask = 0x%02x, .byte = %d, .offset = %d, .count = %d }, \\\n", 312 group->opcode, group->type->mask, group->type->byte, group->offset, group->count); 313 } 314 printf("}\n\n"); 315 } 316 317 int main(int argc, char **argv) 318 { 319 struct gen_opcode _desc = { 0 }; 320 struct gen_opcode *desc = &_desc; 321 322 read_instructions(desc); 323 printf("#ifndef __S390_GENERATED_DIS_H__\n"); 324 printf("#define __S390_GENERATED_DIS_H__\n"); 325 printf("/*\n"); 326 printf(" * DO NOT MODIFY.\n"); 327 printf(" *\n"); 328 printf(" * This file was generated by %s\n", __FILE__); 329 printf(" */\n\n"); 330 print_formats(desc); 331 print_long_insn(desc); 332 print_opcode_table(desc); 333 print_opcode_table_offsets(desc); 334 printf("#endif\n"); 335 exit(EXIT_SUCCESS); 336 } 337