1 /* s390-mkopc.c -- Generates opcode table out of s390-opc.txt 2 Copyright (C) 2000-2022 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 <string.h> 25 #include "opcode/s390.h" 26 27 struct op_struct 28 { 29 char opcode[16]; 30 char mnemonic[16]; 31 char format[16]; 32 int mode_bits; 33 int min_cpu; 34 int flags; 35 36 unsigned long long sort_value; 37 int no_nibbles; 38 }; 39 40 struct op_struct *op_array; 41 int max_ops; 42 int no_ops; 43 44 static void 45 createTable (void) 46 { 47 max_ops = 256; 48 op_array = malloc (max_ops * sizeof (struct op_struct)); 49 no_ops = 0; 50 } 51 52 /* `insertOpcode': insert an op_struct into sorted opcode array. */ 53 54 static void 55 insertOpcode (char *opcode, char *mnemonic, char *format, 56 int min_cpu, int mode_bits, int flags) 57 { 58 char *str; 59 unsigned long long sort_value; 60 int no_nibbles; 61 int ix, k; 62 63 while (no_ops >= max_ops) 64 { 65 max_ops = max_ops * 2; 66 op_array = realloc (op_array, max_ops * sizeof (struct op_struct)); 67 } 68 69 sort_value = 0; 70 str = opcode; 71 for (ix = 0; ix < 16; ix++) 72 { 73 if (*str >= '0' && *str <= '9') 74 sort_value = (sort_value << 4) + (*str - '0'); 75 else if (*str >= 'a' && *str <= 'f') 76 sort_value = (sort_value << 4) + (*str - 'a' + 10); 77 else if (*str >= 'A' && *str <= 'F') 78 sort_value = (sort_value << 4) + (*str - 'A' + 10); 79 else if (*str == '?') 80 sort_value <<= 4; 81 else 82 break; 83 str ++; 84 } 85 sort_value <<= 4*(16 - ix); 86 sort_value += (min_cpu << 8) + mode_bits; 87 no_nibbles = ix; 88 for (ix = 0; ix < no_ops; ix++) 89 if (sort_value > op_array[ix].sort_value) 90 break; 91 for (k = no_ops; k > ix; k--) 92 op_array[k] = op_array[k-1]; 93 strcpy(op_array[ix].opcode, opcode); 94 strcpy(op_array[ix].mnemonic, mnemonic); 95 strcpy(op_array[ix].format, format); 96 op_array[ix].sort_value = sort_value; 97 op_array[ix].no_nibbles = no_nibbles; 98 op_array[ix].min_cpu = min_cpu; 99 op_array[ix].mode_bits = mode_bits; 100 op_array[ix].flags = flags; 101 no_ops++; 102 } 103 104 struct s390_cond_ext_format 105 { 106 char nibble; 107 char extension[4]; 108 }; 109 110 /* The mnemonic extensions for conditional jumps used to replace 111 the '*' tag. */ 112 #define NUM_COND_EXTENSIONS 20 113 const struct s390_cond_ext_format s390_cond_extensions[NUM_COND_EXTENSIONS] = 114 { { '1', "o" }, /* jump on overflow / if ones */ 115 { '2', "h" }, /* jump on A high */ 116 { '2', "p" }, /* jump on plus */ 117 { '3', "nle" }, /* jump on not low or equal */ 118 { '4', "l" }, /* jump on A low */ 119 { '4', "m" }, /* jump on minus / if mixed */ 120 { '5', "nhe" }, /* jump on not high or equal */ 121 { '6', "lh" }, /* jump on low or high */ 122 { '7', "ne" }, /* jump on A not equal B */ 123 { '7', "nz" }, /* jump on not zero / if not zeros */ 124 { '8', "e" }, /* jump on A equal B */ 125 { '8', "z" }, /* jump on zero / if zeros */ 126 { '9', "nlh" }, /* jump on not low or high */ 127 { 'a', "he" }, /* jump on high or equal */ 128 { 'b', "nl" }, /* jump on A not low */ 129 { 'b', "nm" }, /* jump on not minus / if not mixed */ 130 { 'c', "le" }, /* jump on low or equal */ 131 { 'd', "nh" }, /* jump on A not high */ 132 { 'd', "np" }, /* jump on not plus */ 133 { 'e', "no" }, /* jump on not overflow / if not ones */ 134 }; 135 136 /* The mnemonic extensions for conditional branches used to replace 137 the '$' tag. */ 138 #define NUM_CRB_EXTENSIONS 12 139 const struct s390_cond_ext_format s390_crb_extensions[NUM_CRB_EXTENSIONS] = 140 { { '2', "h" }, /* jump on A high */ 141 { '2', "nle" }, /* jump on not low or equal */ 142 { '4', "l" }, /* jump on A low */ 143 { '4', "nhe" }, /* jump on not high or equal */ 144 { '6', "ne" }, /* jump on A not equal B */ 145 { '6', "lh" }, /* jump on low or high */ 146 { '8', "e" }, /* jump on A equal B */ 147 { '8', "nlh" }, /* jump on not low or high */ 148 { 'a', "nl" }, /* jump on A not low */ 149 { 'a', "he" }, /* jump on high or equal */ 150 { 'c', "nh" }, /* jump on A not high */ 151 { 'c', "le" }, /* jump on low or equal */ 152 }; 153 154 /* As with insertOpcode instructions are added to the sorted opcode 155 array. Additionally mnemonics containing the '*<number>' tag are 156 expanded to the set of conditional instructions described by 157 s390_cond_extensions with the tag replaced by the respective 158 mnemonic extensions. */ 159 160 static void 161 insertExpandedMnemonic (char *opcode, char *mnemonic, char *format, 162 int min_cpu, int mode_bits, int flags) 163 { 164 char *tag; 165 char prefix[15]; 166 char suffix[15]; 167 char number[15]; 168 int mask_start, i = 0, tag_found = 0, reading_number = 0; 169 int number_p = 0, suffix_p = 0, prefix_p = 0; 170 const struct s390_cond_ext_format *ext_table; 171 int ext_table_length; 172 173 if (!(tag = strpbrk (mnemonic, "*$"))) 174 { 175 insertOpcode (opcode, mnemonic, format, min_cpu, mode_bits, flags); 176 return; 177 } 178 179 while (mnemonic[i] != '\0') 180 { 181 if (mnemonic[i] == *tag) 182 { 183 if (tag_found) 184 goto malformed_mnemonic; 185 186 tag_found = 1; 187 reading_number = 1; 188 } 189 else 190 switch (mnemonic[i]) 191 { 192 case '0': case '1': case '2': case '3': case '4': 193 case '5': case '6': case '7': case '8': case '9': 194 if (!tag_found || !reading_number) 195 goto malformed_mnemonic; 196 197 number[number_p++] = mnemonic[i]; 198 break; 199 200 default: 201 if (reading_number) 202 { 203 if (!number_p) 204 goto malformed_mnemonic; 205 else 206 reading_number = 0; 207 } 208 209 if (tag_found) 210 suffix[suffix_p++] = mnemonic[i]; 211 else 212 prefix[prefix_p++] = mnemonic[i]; 213 } 214 i++; 215 } 216 217 prefix[prefix_p] = '\0'; 218 suffix[suffix_p] = '\0'; 219 number[number_p] = '\0'; 220 221 if (sscanf (number, "%d", &mask_start) != 1) 222 goto malformed_mnemonic; 223 224 if (mask_start & 3) 225 { 226 fprintf (stderr, "Conditional mask not at nibble boundary in: %s\n", 227 mnemonic); 228 return; 229 } 230 231 mask_start >>= 2; 232 233 switch (*tag) 234 { 235 case '*': 236 ext_table = s390_cond_extensions; 237 ext_table_length = NUM_COND_EXTENSIONS; 238 break; 239 case '$': 240 ext_table = s390_crb_extensions; 241 ext_table_length = NUM_CRB_EXTENSIONS; 242 break; 243 default: 244 abort (); /* Should be unreachable. */ 245 } 246 247 for (i = 0; i < ext_table_length; i++) 248 { 249 char new_mnemonic[15]; 250 251 strcpy (new_mnemonic, prefix); 252 opcode[mask_start] = ext_table[i].nibble; 253 strcat (new_mnemonic, ext_table[i].extension); 254 strcat (new_mnemonic, suffix); 255 insertOpcode (opcode, new_mnemonic, format, min_cpu, mode_bits, flags); 256 } 257 return; 258 259 malformed_mnemonic: 260 fprintf (stderr, "Malformed mnemonic: %s\n", mnemonic); 261 } 262 263 static const char file_header[] = 264 "/* The opcode table. This file was generated by s390-mkopc.\n\n" 265 " The format of the opcode table is:\n\n" 266 " NAME OPCODE MASK OPERANDS\n\n" 267 " Name is the name of the instruction.\n" 268 " OPCODE is the instruction opcode.\n" 269 " MASK is the opcode mask; this is used to tell the disassembler\n" 270 " which bits in the actual opcode must match OPCODE.\n" 271 " OPERANDS is the list of operands.\n\n" 272 " The disassembler reads the table in order and prints the first\n" 273 " instruction which matches.\n" 274 " MODE_BITS - zarch or esa\n" 275 " MIN_CPU - number of the min cpu level required\n" 276 " FLAGS - instruction flags. */\n\n" 277 "const struct s390_opcode s390_opcodes[] =\n {\n"; 278 279 /* `dumpTable': write opcode table. */ 280 281 static void 282 dumpTable (void) 283 { 284 char *str; 285 int ix; 286 287 /* Write hash table entries (slots). */ 288 printf ("%s", file_header); 289 290 for (ix = 0; ix < no_ops; ix++) 291 { 292 printf (" { \"%s\", ", op_array[ix].mnemonic); 293 for (str = op_array[ix].opcode; *str != 0; str++) 294 if (*str == '?') 295 *str = '0'; 296 printf ("OP%i(0x%sLL), ", 297 op_array[ix].no_nibbles*4, op_array[ix].opcode); 298 printf ("MASK_%s, INSTR_%s, ", 299 op_array[ix].format, op_array[ix].format); 300 printf ("%i, ", op_array[ix].mode_bits); 301 printf ("%i, ", op_array[ix].min_cpu); 302 printf ("%i}", op_array[ix].flags); 303 if (ix < no_ops-1) 304 printf (",\n"); 305 else 306 printf ("\n"); 307 } 308 printf ("};\n\n"); 309 printf ("const int s390_num_opcodes =\n"); 310 printf (" sizeof (s390_opcodes) / sizeof (s390_opcodes[0]);\n\n"); 311 } 312 313 int 314 main (void) 315 { 316 char currentLine[256]; 317 318 createTable (); 319 320 /* Read opcode descriptions from `stdin'. For each mnemonic, 321 make an entry into the opcode table. */ 322 while (fgets (currentLine, sizeof (currentLine), stdin) != NULL) 323 { 324 char opcode[16]; 325 char mnemonic[16]; 326 char format[16]; 327 char description[80]; 328 char cpu_string[16]; 329 char modes_string[16]; 330 char flags_string[80]; 331 int min_cpu; 332 int mode_bits; 333 int flag_bits; 334 int num_matched; 335 char *str; 336 337 if (currentLine[0] == '#' || currentLine[0] == '\n') 338 continue; 339 memset (opcode, 0, 8); 340 num_matched = 341 sscanf (currentLine, "%15s %15s %15s \"%79[^\"]\" %15s %15s %79[^\n]", 342 opcode, mnemonic, format, description, 343 cpu_string, modes_string, flags_string); 344 if (num_matched != 6 && num_matched != 7) 345 { 346 fprintf (stderr, "Couldn't scan line %s\n", currentLine); 347 exit (1); 348 } 349 350 if (strcmp (cpu_string, "g5") == 0 351 || strcmp (cpu_string, "arch3") == 0) 352 min_cpu = S390_OPCODE_G5; 353 else if (strcmp (cpu_string, "g6") == 0) 354 min_cpu = S390_OPCODE_G6; 355 else if (strcmp (cpu_string, "z900") == 0 356 || strcmp (cpu_string, "arch5") == 0) 357 min_cpu = S390_OPCODE_Z900; 358 else if (strcmp (cpu_string, "z990") == 0 359 || strcmp (cpu_string, "arch6") == 0) 360 min_cpu = S390_OPCODE_Z990; 361 else if (strcmp (cpu_string, "z9-109") == 0) 362 min_cpu = S390_OPCODE_Z9_109; 363 else if (strcmp (cpu_string, "z9-ec") == 0 364 || strcmp (cpu_string, "arch7") == 0) 365 min_cpu = S390_OPCODE_Z9_EC; 366 else if (strcmp (cpu_string, "z10") == 0 367 || strcmp (cpu_string, "arch8") == 0) 368 min_cpu = S390_OPCODE_Z10; 369 else if (strcmp (cpu_string, "z196") == 0 370 || strcmp (cpu_string, "arch9") == 0) 371 min_cpu = S390_OPCODE_Z196; 372 else if (strcmp (cpu_string, "zEC12") == 0 373 || strcmp (cpu_string, "arch10") == 0) 374 min_cpu = S390_OPCODE_ZEC12; 375 else if (strcmp (cpu_string, "z13") == 0 376 || strcmp (cpu_string, "arch11") == 0) 377 min_cpu = S390_OPCODE_Z13; 378 else if (strcmp (cpu_string, "z14") == 0 379 || strcmp (cpu_string, "arch12") == 0) 380 min_cpu = S390_OPCODE_ARCH12; 381 else if (strcmp (cpu_string, "z15") == 0 382 || strcmp (cpu_string, "arch13") == 0) 383 min_cpu = S390_OPCODE_ARCH13; 384 else if (strcmp (cpu_string, "z16") == 0 385 || strcmp (cpu_string, "arch14") == 0) 386 min_cpu = S390_OPCODE_ARCH14; 387 else { 388 fprintf (stderr, "Couldn't parse cpu string %s\n", cpu_string); 389 exit (1); 390 } 391 392 str = modes_string; 393 mode_bits = 0; 394 do { 395 if (strncmp (str, "esa", 3) == 0 396 && (str[3] == 0 || str[3] == ',')) { 397 mode_bits |= 1 << S390_OPCODE_ESA; 398 str += 3; 399 } else if (strncmp (str, "zarch", 5) == 0 400 && (str[5] == 0 || str[5] == ',')) { 401 mode_bits |= 1 << S390_OPCODE_ZARCH; 402 str += 5; 403 } else { 404 fprintf (stderr, "Couldn't parse modes string %s\n", 405 modes_string); 406 exit (1); 407 } 408 if (*str == ',') 409 str++; 410 } while (*str != 0); 411 412 flag_bits = 0; 413 414 if (num_matched == 7) 415 { 416 str = flags_string; 417 do { 418 if (strncmp (str, "optparm", 7) == 0 419 && (str[7] == 0 || str[7] == ',')) { 420 flag_bits |= S390_INSTR_FLAG_OPTPARM; 421 str += 7; 422 } else if (strncmp (str, "optparm2", 8) == 0 423 && (str[8] == 0 || str[8] == ',')) { 424 flag_bits |= S390_INSTR_FLAG_OPTPARM2; 425 str += 8; 426 } else if (strncmp (str, "htm", 3) == 0 427 && (str[3] == 0 || str[3] == ',')) { 428 flag_bits |= S390_INSTR_FLAG_HTM; 429 str += 3; 430 } else if (strncmp (str, "vx", 2) == 0 431 && (str[2] == 0 || str[2] == ',')) { 432 flag_bits |= S390_INSTR_FLAG_VX; 433 str += 2; 434 } else { 435 fprintf (stderr, "Couldn't parse flags string %s\n", 436 flags_string); 437 exit (1); 438 } 439 if (*str == ',') 440 str++; 441 } while (*str != 0); 442 } 443 insertExpandedMnemonic (opcode, mnemonic, format, min_cpu, mode_bits, flag_bits); 444 } 445 446 dumpTable (); 447 return 0; 448 } 449