1 /* s390-mkopc.c -- Generates opcode table out of s390-opc.txt 2 Copyright (C) 2000-2024 Free Software Foundation, Inc. 3 Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com). 4 5 This file is part of the GNU opcodes library. 6 7 This library is free software; you can redistribute it and/or modify 8 it under the terms of the GNU General Public License as published by 9 the Free Software Foundation; either version 3, or (at your option) 10 any later version. 11 12 It is distributed in the hope that it will be useful, but WITHOUT 13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 14 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 15 License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with this file; see the file COPYING. If not, write to the 19 Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston, 20 MA 02110-1301, USA. */ 21 22 #include <stdio.h> 23 #include <stdlib.h> 24 #include <stdarg.h> 25 #include <string.h> 26 #include "opcode/s390.h" 27 28 #define STRINGIFY(x) _STRINGIFY(x) 29 #define _STRINGIFY(x) #x 30 31 /* Length of strings without terminating '\0' character. */ 32 #define MAX_OPCODE_LEN 15 33 #define MAX_MNEMONIC_LEN 15 34 #define MAX_FORMAT_LEN 15 35 #define MAX_DESCRIPTION_LEN 127 36 37 #define MAX_CPU_LEN 15 38 #define MAX_MODES_LEN 15 39 #define MAX_FLAGS_LEN 79 40 41 /* Return code. */ 42 int return_code = EXIT_SUCCESS; 43 44 /* Helper to print an error message and set the return code. */ 45 static void __attribute__ ((format (printf, 1, 2))) 46 print_error (const char *fmt, ...) 47 { 48 va_list ap; 49 50 va_start(ap, fmt); 51 fprintf(stderr, "Error: "); 52 vfprintf(stderr, fmt, ap); 53 va_end(ap); 54 55 return_code = EXIT_FAILURE; 56 } 57 58 struct op_struct 59 { 60 char opcode[MAX_OPCODE_LEN + 1]; 61 char mnemonic[MAX_MNEMONIC_LEN + 1]; 62 char format[MAX_FORMAT_LEN + 1]; 63 int mode_bits; 64 int min_cpu; 65 int flags; 66 char description[MAX_DESCRIPTION_LEN + 1]; 67 68 unsigned long long sort_value; 69 int no_nibbles; 70 }; 71 72 struct op_struct *op_array; 73 int max_ops; 74 int no_ops; 75 76 static void 77 createTable (void) 78 { 79 max_ops = 256; 80 op_array = malloc (max_ops * sizeof (struct op_struct)); 81 no_ops = 0; 82 } 83 84 /* `insertOpcode': insert an op_struct into sorted opcode array. */ 85 86 static void 87 insertOpcode (char *opcode, char *mnemonic, char *format, 88 int min_cpu, int mode_bits, int flags, char* description) 89 { 90 char *str; 91 unsigned long long sort_value; 92 int no_nibbles; 93 int ix, k; 94 95 while (no_ops >= max_ops) 96 { 97 max_ops = max_ops * 2; 98 op_array = realloc (op_array, max_ops * sizeof (struct op_struct)); 99 } 100 101 sort_value = 0; 102 str = opcode; 103 for (ix = 0; ix < 16; ix++) 104 { 105 if (*str >= '0' && *str <= '9') 106 sort_value = (sort_value << 4) + (*str - '0'); 107 else if (*str >= 'a' && *str <= 'f') 108 sort_value = (sort_value << 4) + (*str - 'a' + 10); 109 else if (*str >= 'A' && *str <= 'F') 110 sort_value = (sort_value << 4) + (*str - 'A' + 10); 111 else if (*str == '?') 112 sort_value <<= 4; 113 else 114 break; 115 str ++; 116 } 117 sort_value <<= 4*(16 - ix); 118 sort_value += (min_cpu << 8) + mode_bits; 119 no_nibbles = ix; 120 for (ix = 0; ix < no_ops; ix++) 121 if (sort_value > op_array[ix].sort_value) 122 break; 123 for (k = no_ops; k > ix; k--) 124 op_array[k] = op_array[k-1]; 125 strncpy (op_array[ix].opcode, opcode, MAX_OPCODE_LEN); 126 op_array[ix].opcode[MAX_OPCODE_LEN] = '\0'; 127 strncpy (op_array[ix].mnemonic, mnemonic, MAX_MNEMONIC_LEN); 128 op_array[ix].mnemonic[MAX_MNEMONIC_LEN] = '\0'; 129 strncpy (op_array[ix].format, format, MAX_FORMAT_LEN); 130 op_array[ix].format[MAX_FORMAT_LEN] = '\0'; 131 op_array[ix].sort_value = sort_value; 132 op_array[ix].no_nibbles = no_nibbles; 133 op_array[ix].min_cpu = min_cpu; 134 op_array[ix].mode_bits = mode_bits; 135 op_array[ix].flags = flags; 136 strncpy (op_array[ix].description, description, MAX_DESCRIPTION_LEN); 137 op_array[ix].description[MAX_DESCRIPTION_LEN] = '\0'; 138 no_ops++; 139 } 140 141 struct s390_cond_ext_format 142 { 143 char nibble; 144 char extension[4]; 145 char *description_suffix; 146 147 }; 148 149 /* The mnemonic extensions for conditional jumps used to replace 150 the '*' tag. */ 151 #define NUM_COND_EXTENSIONS 20 152 const struct s390_cond_ext_format s390_cond_extensions[NUM_COND_EXTENSIONS] = 153 { { '1', "o", "on overflow / if ones" }, /* jump on overflow / if ones */ 154 { '2', "h", "on A high" }, /* jump on A high */ 155 { '2', "p", "on plus" }, /* jump on plus */ 156 { '3', "nle", "on not low or equal" }, /* jump on not low or equal */ 157 { '4', "l", "on A low" }, /* jump on A low */ 158 { '4', "m", "on minus / if mixed" }, /* jump on minus / if mixed */ 159 { '5', "nhe", "on not high or equal" }, /* jump on not high or equal */ 160 { '6', "lh", "on low or high" }, /* jump on low or high */ 161 { '7', "ne", "on A not equal B" }, /* jump on A not equal B */ 162 { '7', "nz", "on not zero / if not zeros" }, /* jump on not zero / if not zeros */ 163 { '8', "e", "on A equal B" }, /* jump on A equal B */ 164 { '8', "z", "on zero / if zeros" }, /* jump on zero / if zeros */ 165 { '9', "nlh", "on not low or high" }, /* jump on not low or high */ 166 { 'a', "he", "on high or equal" }, /* jump on high or equal */ 167 { 'b', "nl", "on A not low" }, /* jump on A not low */ 168 { 'b', "nm", "on not minus / if not mixed" }, /* jump on not minus / if not mixed */ 169 { 'c', "le", "on low or equal" }, /* jump on low or equal */ 170 { 'd', "nh", "on A not high" }, /* jump on A not high */ 171 { 'd', "np", "on not plus" }, /* jump on not plus */ 172 { 'e', "no", "on not overflow / if not ones" },/* jump on not overflow / if not ones */ 173 }; 174 175 /* The mnemonic extensions for conditional branches used to replace 176 the '$' tag. */ 177 #define NUM_CRB_EXTENSIONS 12 178 const struct s390_cond_ext_format s390_crb_extensions[NUM_CRB_EXTENSIONS] = 179 { { '2', "h", "on A high" }, /* jump on A high */ 180 { '2', "nle", "on not low or equal" }, /* jump on not low or equal */ 181 { '4', "l", "on A low" }, /* jump on A low */ 182 { '4', "nhe", "on not high or equal" }, /* jump on not high or equal */ 183 { '6', "ne", "on A not equal B" }, /* jump on A not equal B */ 184 { '6', "lh", "on low or high" }, /* jump on low or high */ 185 { '8', "e", "on A equal B" }, /* jump on A equal B */ 186 { '8', "nlh", "on not low or high" }, /* jump on not low or high */ 187 { 'a', "nl", "on A not low" }, /* jump on A not low */ 188 { 'a', "he", "on high or equal" }, /* jump on high or equal */ 189 { 'c', "nh", "on A not high" }, /* jump on A not high */ 190 { 'c', "le", "on low or equal" }, /* jump on low or equal */ 191 }; 192 193 /* As with insertOpcode instructions are added to the sorted opcode 194 array. Additionally mnemonics containing the '*<number>' tag are 195 expanded to the set of conditional instructions described by 196 s390_cond_extensions with the tag replaced by the respective 197 mnemonic extensions. */ 198 199 static void 200 insertExpandedMnemonic (char *opcode, char *mnemonic, char *format, 201 int min_cpu, int mode_bits, int flags, char *description) 202 { 203 char *tag; 204 char prefix[MAX_MNEMONIC_LEN + 1]; 205 char suffix[MAX_MNEMONIC_LEN + 1]; 206 char number[MAX_MNEMONIC_LEN + 1]; 207 int mask_start, i = 0, tag_found = 0, reading_number = 0; 208 int number_p = 0, suffix_p = 0, prefix_p = 0; 209 const struct s390_cond_ext_format *ext_table; 210 int ext_table_length; 211 212 if (!(tag = strpbrk (mnemonic, "*$"))) 213 { 214 insertOpcode (opcode, mnemonic, format, min_cpu, mode_bits, flags, description); 215 return; 216 } 217 218 while (mnemonic[i] != '\0') 219 { 220 if (mnemonic[i] == *tag) 221 { 222 if (tag_found) 223 goto malformed_mnemonic; 224 225 tag_found = 1; 226 reading_number = 1; 227 } 228 else 229 switch (mnemonic[i]) 230 { 231 case '0': case '1': case '2': case '3': case '4': 232 case '5': case '6': case '7': case '8': case '9': 233 if (!tag_found || !reading_number) 234 goto malformed_mnemonic; 235 236 number[number_p++] = mnemonic[i]; 237 break; 238 239 default: 240 if (reading_number) 241 { 242 if (!number_p) 243 goto malformed_mnemonic; 244 else 245 reading_number = 0; 246 } 247 248 if (tag_found) 249 suffix[suffix_p++] = mnemonic[i]; 250 else 251 prefix[prefix_p++] = mnemonic[i]; 252 } 253 i++; 254 } 255 256 prefix[prefix_p] = '\0'; 257 suffix[suffix_p] = '\0'; 258 number[number_p] = '\0'; 259 260 if (sscanf (number, "%d", &mask_start) != 1) 261 goto malformed_mnemonic; 262 263 if (mask_start & 3) 264 { 265 print_error ("Mnemonic \"%s\": Conditional mask not at nibble boundary\n", mnemonic); 266 return; 267 } 268 269 mask_start >>= 2; 270 271 switch (*tag) 272 { 273 case '*': 274 ext_table = s390_cond_extensions; 275 ext_table_length = NUM_COND_EXTENSIONS; 276 break; 277 case '$': 278 ext_table = s390_crb_extensions; 279 ext_table_length = NUM_CRB_EXTENSIONS; 280 break; 281 default: 282 abort (); /* Should be unreachable. */ 283 } 284 285 for (i = 0; i < ext_table_length; i++) 286 { 287 char new_mnemonic[MAX_MNEMONIC_LEN + 1]; 288 char new_description[MAX_DESCRIPTION_LEN + 1]; 289 290 opcode[mask_start] = ext_table[i].nibble; 291 292 if (snprintf (new_mnemonic, sizeof (new_mnemonic), "%s%s%s", prefix, 293 ext_table[i].extension, suffix) >= sizeof (new_mnemonic)) 294 { 295 print_error ("Mnemonic: \"%s\": Concatenated mnemonic exceeds max. length\n", mnemonic); 296 return; 297 } 298 299 if (snprintf (new_description, sizeof (new_description), "%s %s", description, 300 ext_table[i].description_suffix) >= sizeof (new_description)) 301 { 302 print_error ("Mnemonic \"%s\": Concatenated description exceeds max. length\n", mnemonic); 303 return; 304 } 305 306 insertOpcode (opcode, new_mnemonic, format, min_cpu, mode_bits, flags, new_description); 307 } 308 return; 309 310 malformed_mnemonic: 311 print_error ("Malformed mnemonic: %s\n", mnemonic); 312 } 313 314 static const char file_header[] = 315 "/* The opcode table. This file was generated by s390-mkopc.\n\n" 316 " The format of the opcode table is:\n\n" 317 " NAME OPCODE MASK OPERANDS\n\n" 318 " Name is the name of the instruction.\n" 319 " OPCODE is the instruction opcode.\n" 320 " MASK is the opcode mask; this is used to tell the disassembler\n" 321 " which bits in the actual opcode must match OPCODE.\n" 322 " OPERANDS is the list of operands.\n\n" 323 " The disassembler reads the table in order and prints the first\n" 324 " instruction which matches.\n" 325 " MODE_BITS - zarch or esa\n" 326 " MIN_CPU - number of the min cpu level required\n" 327 " FLAGS - instruction flags.\n" 328 " DESCRIPTION - description of the instruction. */\n\n" 329 "const struct s390_opcode s390_opcodes[] =\n {\n"; 330 331 /* `dumpTable': write opcode table. */ 332 333 static void 334 dumpTable (void) 335 { 336 char *str; 337 int ix; 338 339 /* Write hash table entries (slots). */ 340 printf ("%s", file_header); 341 342 for (ix = 0; ix < no_ops; ix++) 343 { 344 printf (" { \"%s\", ", op_array[ix].mnemonic); 345 for (str = op_array[ix].opcode; *str != 0; str++) 346 if (*str == '?') 347 *str = '0'; 348 printf ("OP%i(0x%sLL), ", 349 op_array[ix].no_nibbles*4, op_array[ix].opcode); 350 printf ("MASK_%s, INSTR_%s, ", 351 op_array[ix].format, op_array[ix].format); 352 printf ("%i, ", op_array[ix].mode_bits); 353 printf ("%i, ", op_array[ix].min_cpu); 354 printf ("%i, ", op_array[ix].flags); 355 printf ("\"%s\" }", op_array[ix].description); 356 if (ix < no_ops-1) 357 printf (",\n"); 358 else 359 printf ("\n"); 360 } 361 printf ("};\n\n"); 362 printf ("const int s390_num_opcodes =\n"); 363 printf (" sizeof (s390_opcodes) / sizeof (s390_opcodes[0]);\n\n"); 364 } 365 366 int 367 main (void) 368 { 369 char currentLine[256]; 370 371 createTable (); 372 373 /* Read opcode descriptions from `stdin'. For each mnemonic, 374 make an entry into the opcode table. */ 375 while (fgets (currentLine, sizeof (currentLine), stdin) != NULL) 376 { 377 char opcode[MAX_OPCODE_LEN + 1]; 378 char mnemonic[MAX_MNEMONIC_LEN + 1]; 379 char format[MAX_FORMAT_LEN + 1]; 380 char description[MAX_DESCRIPTION_LEN + 1]; 381 char cpu_string[MAX_CPU_LEN + 1]; 382 char modes_string[MAX_MODES_LEN + 1]; 383 char flags_string[MAX_FLAGS_LEN + 1]; 384 int min_cpu; 385 int mode_bits; 386 int flag_bits; 387 int num_matched; 388 char *str; 389 390 if (currentLine[0] == '#' || currentLine[0] == '\n') 391 continue; 392 memset (opcode, '\0', sizeof(opcode)); 393 num_matched = sscanf (currentLine, 394 "%" STRINGIFY (MAX_OPCODE_LEN) "s " 395 "%" STRINGIFY (MAX_MNEMONIC_LEN) "s " 396 "%" STRINGIFY (MAX_FORMAT_LEN) "s " 397 "\"%" STRINGIFY (MAX_DESCRIPTION_LEN) "[^\"]\" " 398 "%" STRINGIFY (MAX_CPU_LEN) "s " 399 "%" STRINGIFY (MAX_MODES_LEN) "s " 400 "%" STRINGIFY (MAX_FLAGS_LEN) "[^\n]", 401 opcode, mnemonic, format, description, 402 cpu_string, modes_string, flags_string); 403 if (num_matched != 6 && num_matched != 7) 404 { 405 print_error ("Couldn't scan line %s\n", currentLine); 406 exit (EXIT_FAILURE); 407 } 408 409 if (strcmp (cpu_string, "g5") == 0 410 || strcmp (cpu_string, "arch3") == 0) 411 min_cpu = S390_OPCODE_G5; 412 else if (strcmp (cpu_string, "g6") == 0) 413 min_cpu = S390_OPCODE_G6; 414 else if (strcmp (cpu_string, "z900") == 0 415 || strcmp (cpu_string, "arch5") == 0) 416 min_cpu = S390_OPCODE_Z900; 417 else if (strcmp (cpu_string, "z990") == 0 418 || strcmp (cpu_string, "arch6") == 0) 419 min_cpu = S390_OPCODE_Z990; 420 else if (strcmp (cpu_string, "z9-109") == 0) 421 min_cpu = S390_OPCODE_Z9_109; 422 else if (strcmp (cpu_string, "z9-ec") == 0 423 || strcmp (cpu_string, "arch7") == 0) 424 min_cpu = S390_OPCODE_Z9_EC; 425 else if (strcmp (cpu_string, "z10") == 0 426 || strcmp (cpu_string, "arch8") == 0) 427 min_cpu = S390_OPCODE_Z10; 428 else if (strcmp (cpu_string, "z196") == 0 429 || strcmp (cpu_string, "arch9") == 0) 430 min_cpu = S390_OPCODE_Z196; 431 else if (strcmp (cpu_string, "zEC12") == 0 432 || strcmp (cpu_string, "arch10") == 0) 433 min_cpu = S390_OPCODE_ZEC12; 434 else if (strcmp (cpu_string, "z13") == 0 435 || strcmp (cpu_string, "arch11") == 0) 436 min_cpu = S390_OPCODE_Z13; 437 else if (strcmp (cpu_string, "z14") == 0 438 || strcmp (cpu_string, "arch12") == 0) 439 min_cpu = S390_OPCODE_ARCH12; 440 else if (strcmp (cpu_string, "z15") == 0 441 || strcmp (cpu_string, "arch13") == 0) 442 min_cpu = S390_OPCODE_ARCH13; 443 else if (strcmp (cpu_string, "z16") == 0 444 || strcmp (cpu_string, "arch14") == 0) 445 min_cpu = S390_OPCODE_ARCH14; 446 else { 447 print_error ("Mnemonic \"%s\": Couldn't parse CPU string: %s\n", 448 mnemonic, cpu_string); 449 goto continue_loop; 450 } 451 452 str = modes_string; 453 mode_bits = 0; 454 do { 455 if (strncmp (str, "esa", 3) == 0 456 && (str[3] == 0 || str[3] == ',')) { 457 mode_bits |= 1 << S390_OPCODE_ESA; 458 str += 3; 459 } else if (strncmp (str, "zarch", 5) == 0 460 && (str[5] == 0 || str[5] == ',')) { 461 mode_bits |= 1 << S390_OPCODE_ZARCH; 462 str += 5; 463 } else { 464 print_error ("Mnemonic \"%s\": Couldn't parse modes string: %s\n", 465 mnemonic, modes_string); 466 goto continue_loop; 467 } 468 if (*str == ',') 469 str++; 470 } while (*str != 0); 471 472 flag_bits = 0; 473 474 if (num_matched == 7) 475 { 476 str = flags_string; 477 do { 478 if (strncmp (str, "optparm", 7) == 0 479 && (str[7] == 0 || str[7] == ',')) { 480 flag_bits |= S390_INSTR_FLAG_OPTPARM; 481 str += 7; 482 } else if (strncmp (str, "optparm2", 8) == 0 483 && (str[8] == 0 || str[8] == ',')) { 484 flag_bits |= S390_INSTR_FLAG_OPTPARM2; 485 str += 8; 486 } else if (strncmp (str, "htm", 3) == 0 487 && (str[3] == 0 || str[3] == ',')) { 488 flag_bits |= S390_INSTR_FLAG_HTM; 489 str += 3; 490 } else if (strncmp (str, "vx", 2) == 0 491 && (str[2] == 0 || str[2] == ',')) { 492 flag_bits |= S390_INSTR_FLAG_VX; 493 str += 2; 494 } else if (strncmp (str, "jump", 4) == 0 495 && (str[4] == 0 || str[4] == ',')) { 496 flag_bits |= S390_INSTR_FLAGS_CLASS_JUMP; 497 str += 4; 498 } else if (strncmp (str, "condjump", 8) == 0 499 && (str[8] == 0 || str[8] == ',')) { 500 flag_bits |= S390_INSTR_FLAGS_CLASS_CONDJUMP; 501 str += 8; 502 } else if (strncmp (str, "jumpsr", 6) == 0 503 && (str[6] == 0 || str[6] == ',')) { 504 flag_bits |= S390_INSTR_FLAGS_CLASS_JUMPSR; 505 str += 6; 506 } else { 507 print_error ("Mnemonic \"%s\": Couldn't parse flags string: %s\n", 508 mnemonic, flags_string); 509 goto continue_loop; 510 } 511 if (*str == ',') 512 str++; 513 } while (*str != 0); 514 } 515 insertExpandedMnemonic (opcode, mnemonic, format, min_cpu, mode_bits, flag_bits, description); 516 517 continue_loop: 518 ; 519 } 520 521 dumpTable (); 522 return return_code; 523 } 524