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