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