1/* s390-mkopc.c -- Generates opcode table out of s390-opc.txt 2 Copyright (C) 2000-2017 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 27struct 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 40struct op_struct *op_array; 41int max_ops; 42int no_ops; 43 44static void 45createTable (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 54static void 55insertOpcode (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 104struct 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 113const 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 139const 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 160static void 161insertExpandedMnemonic (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: fprintf (stderr, "Unknown tag char: %c\n", *tag); 244 } 245 246 for (i = 0; i < ext_table_length; i++) 247 { 248 char new_mnemonic[15]; 249 250 strcpy (new_mnemonic, prefix); 251 opcode[mask_start] = ext_table[i].nibble; 252 strcat (new_mnemonic, ext_table[i].extension); 253 strcat (new_mnemonic, suffix); 254 insertOpcode (opcode, new_mnemonic, format, min_cpu, mode_bits, flags); 255 } 256 return; 257 258 malformed_mnemonic: 259 fprintf (stderr, "Malformed mnemonic: %s\n", mnemonic); 260} 261 262static const char file_header[] = 263 "/* The opcode table. This file was generated by s390-mkopc.\n\n" 264 " The format of the opcode table is:\n\n" 265 " NAME OPCODE MASK OPERANDS\n\n" 266 " Name is the name of the instruction.\n" 267 " OPCODE is the instruction opcode.\n" 268 " MASK is the opcode mask; this is used to tell the disassembler\n" 269 " which bits in the actual opcode must match OPCODE.\n" 270 " OPERANDS is the list of operands.\n\n" 271 " The disassembler reads the table in order and prints the first\n" 272 " instruction which matches.\n" 273 " MODE_BITS - zarch or esa\n" 274 " MIN_CPU - number of the min cpu level required\n" 275 " FLAGS - instruction flags. */\n\n" 276 "const struct s390_opcode s390_opcodes[] =\n {\n"; 277 278/* `dumpTable': write opcode table. */ 279 280static void 281dumpTable (void) 282{ 283 char *str; 284 int ix; 285 286 /* Write hash table entries (slots). */ 287 printf ("%s", file_header); 288 289 for (ix = 0; ix < no_ops; ix++) 290 { 291 printf (" { \"%s\", ", op_array[ix].mnemonic); 292 for (str = op_array[ix].opcode; *str != 0; str++) 293 if (*str == '?') 294 *str = '0'; 295 printf ("OP%i(0x%sLL), ", 296 op_array[ix].no_nibbles*4, op_array[ix].opcode); 297 printf ("MASK_%s, INSTR_%s, ", 298 op_array[ix].format, op_array[ix].format); 299 printf ("%i, ", op_array[ix].mode_bits); 300 printf ("%i, ", op_array[ix].min_cpu); 301 printf ("%i}", op_array[ix].flags); 302 if (ix < no_ops-1) 303 printf (",\n"); 304 else 305 printf ("\n"); 306 } 307 printf ("};\n\n"); 308 printf ("const int s390_num_opcodes =\n"); 309 printf (" sizeof (s390_opcodes) / sizeof (s390_opcodes[0]);\n\n"); 310} 311 312int 313main (void) 314{ 315 char currentLine[256]; 316 317 createTable (); 318 319 /* Read opcode descriptions from `stdin'. For each mnemonic, 320 make an entry into the opcode table. */ 321 while (fgets (currentLine, sizeof (currentLine), stdin) != NULL) 322 { 323 char opcode[16]; 324 char mnemonic[16]; 325 char format[16]; 326 char description[80]; 327 char cpu_string[16]; 328 char modes_string[16]; 329 char flags_string[80]; 330 int min_cpu; 331 int mode_bits; 332 int flag_bits; 333 int num_matched; 334 char *str; 335 336 if (currentLine[0] == '#' || currentLine[0] == '\n') 337 continue; 338 memset (opcode, 0, 8); 339 num_matched = 340 sscanf (currentLine, "%15s %15s %15s \"%79[^\"]\" %15s %15s %79[^\n]", 341 opcode, mnemonic, format, description, 342 cpu_string, modes_string, flags_string); 343 if (num_matched != 6 && num_matched != 7) 344 { 345 fprintf (stderr, "Couldn't scan line %s\n", currentLine); 346 exit (1); 347 } 348 349 if (strcmp (cpu_string, "g5") == 0 350 || strcmp (cpu_string, "arch3") == 0) 351 min_cpu = S390_OPCODE_G5; 352 else if (strcmp (cpu_string, "g6") == 0) 353 min_cpu = S390_OPCODE_G6; 354 else if (strcmp (cpu_string, "z900") == 0 355 || strcmp (cpu_string, "arch5") == 0) 356 min_cpu = S390_OPCODE_Z900; 357 else if (strcmp (cpu_string, "z990") == 0 358 || strcmp (cpu_string, "arch6") == 0) 359 min_cpu = S390_OPCODE_Z990; 360 else if (strcmp (cpu_string, "z9-109") == 0) 361 min_cpu = S390_OPCODE_Z9_109; 362 else if (strcmp (cpu_string, "z9-ec") == 0 363 || strcmp (cpu_string, "arch7") == 0) 364 min_cpu = S390_OPCODE_Z9_EC; 365 else if (strcmp (cpu_string, "z10") == 0 366 || strcmp (cpu_string, "arch8") == 0) 367 min_cpu = S390_OPCODE_Z10; 368 else if (strcmp (cpu_string, "z196") == 0 369 || strcmp (cpu_string, "arch9") == 0) 370 min_cpu = S390_OPCODE_Z196; 371 else if (strcmp (cpu_string, "zEC12") == 0 372 || strcmp (cpu_string, "arch10") == 0) 373 min_cpu = S390_OPCODE_ZEC12; 374 else if (strcmp (cpu_string, "z13") == 0 375 || strcmp (cpu_string, "arch11") == 0) 376 min_cpu = S390_OPCODE_Z13; 377 else if (strcmp (cpu_string, "arch12") == 0) 378 min_cpu = S390_OPCODE_ARCH12; 379 else { 380 fprintf (stderr, "Couldn't parse cpu string %s\n", cpu_string); 381 exit (1); 382 } 383 384 str = modes_string; 385 mode_bits = 0; 386 do { 387 if (strncmp (str, "esa", 3) == 0 388 && (str[3] == 0 || str[3] == ',')) { 389 mode_bits |= 1 << S390_OPCODE_ESA; 390 str += 3; 391 } else if (strncmp (str, "zarch", 5) == 0 392 && (str[5] == 0 || str[5] == ',')) { 393 mode_bits |= 1 << S390_OPCODE_ZARCH; 394 str += 5; 395 } else { 396 fprintf (stderr, "Couldn't parse modes string %s\n", 397 modes_string); 398 exit (1); 399 } 400 if (*str == ',') 401 str++; 402 } while (*str != 0); 403 404 flag_bits = 0; 405 406 if (num_matched == 7) 407 { 408 str = flags_string; 409 do { 410 if (strncmp (str, "optparm", 7) == 0 411 && (str[7] == 0 || str[7] == ',')) { 412 flag_bits |= S390_INSTR_FLAG_OPTPARM; 413 str += 7; 414 } else if (strncmp (str, "htm", 3) == 0 415 && (str[3] == 0 || str[3] == ',')) { 416 flag_bits |= S390_INSTR_FLAG_HTM; 417 str += 3; 418 } else if (strncmp (str, "vx", 2) == 0 419 && (str[2] == 0 || str[2] == ',')) { 420 flag_bits |= S390_INSTR_FLAG_VX; 421 str += 2; 422 } else { 423 fprintf (stderr, "Couldn't parse flags string %s\n", 424 flags_string); 425 exit (1); 426 } 427 if (*str == ',') 428 str++; 429 } while (*str != 0); 430 } 431 insertExpandedMnemonic (opcode, mnemonic, format, min_cpu, mode_bits, flag_bits); 432 } 433 434 dumpTable (); 435 return 0; 436} 437