155714Skris/* s390-mkopc.c -- Generates opcode table out of s390-opc.txt 255714Skris Copyright (C) 2000-2022 Free Software Foundation, Inc. 355714Skris Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com). 455714Skris 555714Skris This file is part of the GNU opcodes library. 655714Skris 755714Skris This library is free software; you can redistribute it and/or modify 855714Skris it under the terms of the GNU General Public License as published by 955714Skris the Free Software Foundation; either version 3, or (at your option) 1055714Skris any later version. 1155714Skris 1255714Skris It is distributed in the hope that it will be useful, but WITHOUT 1355714Skris ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 1455714Skris or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 1555714Skris License for more details. 1655714Skris 1755714Skris You should have received a copy of the GNU General Public License 1855714Skris along with this file; see the file COPYING. If not, write to the 1955714Skris Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston, 2055714Skris MA 02110-1301, USA. */ 2155714Skris 2255714Skris#include <stdio.h> 2355714Skris#include <stdlib.h> 2455714Skris#include <string.h> 2555714Skris#include "opcode/s390.h" 2655714Skris 2755714Skrisstruct op_struct 2855714Skris { 2955714Skris char opcode[16]; 3055714Skris char mnemonic[16]; 3155714Skris char format[16]; 3255714Skris int mode_bits; 3355714Skris int min_cpu; 3455714Skris int flags; 3555714Skris 3655714Skris unsigned long long sort_value; 3755714Skris int no_nibbles; 3855714Skris }; 3955714Skris 4055714Skrisstruct op_struct *op_array; 4155714Skrisint max_ops; 4255714Skrisint no_ops; 4355714Skris 4455714Skrisstatic void 4555714SkriscreateTable (void) 4655714Skris{ 4755714Skris max_ops = 256; 4855714Skris op_array = malloc (max_ops * sizeof (struct op_struct)); 4955714Skris no_ops = 0; 5055714Skris} 5155714Skris 5255714Skris/* `insertOpcode': insert an op_struct into sorted opcode array. */ 5355714Skris 5455714Skrisstatic void 5555714SkrisinsertOpcode (char *opcode, char *mnemonic, char *format, 5655714Skris int min_cpu, int mode_bits, int flags) 5755714Skris{ 5855714Skris char *str; 5955714Skris unsigned long long sort_value; 6055714Skris int no_nibbles; 61194206Ssimon int ix, k; 62194206Ssimon 63194206Ssimon while (no_ops >= max_ops) 6455714Skris { 6555714Skris max_ops = max_ops * 2; 66167612Ssimon op_array = realloc (op_array, max_ops * sizeof (struct op_struct)); 6755714Skris } 68194206Ssimon 69194206Ssimon sort_value = 0; 70194206Ssimon str = opcode; 71194206Ssimon for (ix = 0; ix < 16; ix++) 72194206Ssimon { 73194206Ssimon if (*str >= '0' && *str <= '9') 74160814Ssimon sort_value = (sort_value << 4) + (*str - '0'); 7555714Skris else if (*str >= 'a' && *str <= 'f') 7655714Skris sort_value = (sort_value << 4) + (*str - 'a' + 10); 7755714Skris else if (*str >= 'A' && *str <= 'F') 7855714Skris sort_value = (sort_value << 4) + (*str - 'A' + 10); 7955714Skris else if (*str == '?') 8055714Skris sort_value <<= 4; 8155714Skris else 8255714Skris break; 8355714Skris str ++; 8455714Skris } 8555714Skris sort_value <<= 4*(16 - ix); 8655714Skris sort_value += (min_cpu << 8) + mode_bits; 8755714Skris no_nibbles = ix; 88160814Ssimon for (ix = 0; ix < no_ops; ix++) 8955714Skris if (sort_value > op_array[ix].sort_value) 9055714Skris break; 9155714Skris for (k = no_ops; k > ix; k--) 9255714Skris op_array[k] = op_array[k-1]; 9355714Skris strcpy(op_array[ix].opcode, opcode); 9455714Skris strcpy(op_array[ix].mnemonic, mnemonic); 95160814Ssimon strcpy(op_array[ix].format, format); 96160814Ssimon op_array[ix].sort_value = sort_value; 97160814Ssimon op_array[ix].no_nibbles = no_nibbles; 98160814Ssimon op_array[ix].min_cpu = min_cpu; 9955714Skris op_array[ix].mode_bits = mode_bits; 10055714Skris op_array[ix].flags = flags; 10155714Skris no_ops++; 10255714Skris} 10355714Skris 10455714Skrisstruct s390_cond_ext_format 10555714Skris{ 10655714Skris char nibble; 10755714Skris char extension[4]; 10855714Skris}; 10955714Skris 11055714Skris/* The mnemonic extensions for conditional jumps used to replace 11155714Skris the '*' tag. */ 11255714Skris#define NUM_COND_EXTENSIONS 20 11355714Skrisconst struct s390_cond_ext_format s390_cond_extensions[NUM_COND_EXTENSIONS] = 11455714Skris{ { '1', "o" }, /* jump on overflow / if ones */ 11555714Skris { '2', "h" }, /* jump on A high */ 11655714Skris { '2', "p" }, /* jump on plus */ 11755714Skris { '3', "nle" }, /* jump on not low or equal */ 11855714Skris { '4', "l" }, /* jump on A low */ 11955714Skris { '4', "m" }, /* jump on minus / if mixed */ 12055714Skris { '5', "nhe" }, /* jump on not high or equal */ 12155714Skris { '6', "lh" }, /* jump on low or high */ 12255714Skris { '7', "ne" }, /* jump on A not equal B */ 12359191Skris { '7', "nz" }, /* jump on not zero / if not zeros */ 12459191Skris { '8', "e" }, /* jump on A equal B */ 12559191Skris { '8', "z" }, /* jump on zero / if zeros */ 12659191Skris { '9', "nlh" }, /* jump on not low or high */ 12759191Skris { 'a', "he" }, /* jump on high or equal */ 12855714Skris { 'b', "nl" }, /* jump on A not low */ 129194206Ssimon { 'b', "nm" }, /* jump on not minus / if not mixed */ 130194206Ssimon { 'c', "le" }, /* jump on low or equal */ 131194206Ssimon { 'd', "nh" }, /* jump on A not high */ 132194206Ssimon { 'd', "np" }, /* jump on not plus */ 133194206Ssimon { 'e', "no" }, /* jump on not overflow / if not ones */ 134194206Ssimon}; 135194206Ssimon 136205128Ssimon/* The mnemonic extensions for conditional branches used to replace 137205128Ssimon the '$' tag. */ 138205128Ssimon#define NUM_CRB_EXTENSIONS 12 139205128Ssimonconst struct s390_cond_ext_format s390_crb_extensions[NUM_CRB_EXTENSIONS] = 140205128Ssimon{ { '2', "h" }, /* jump on A high */ 141194206Ssimon { '2', "nle" }, /* jump on not low or equal */ 142194206Ssimon { '4', "l" }, /* jump on A low */ 143194206Ssimon { '4', "nhe" }, /* jump on not high or equal */ 144194206Ssimon { '6', "ne" }, /* jump on A not equal B */ 145194206Ssimon { '6', "lh" }, /* jump on low or high */ 146194206Ssimon { '8', "e" }, /* jump on A equal B */ 147194206Ssimon { '8', "nlh" }, /* jump on not low or high */ 148194206Ssimon { 'a', "nl" }, /* jump on A not low */ 149194206Ssimon { 'a', "he" }, /* jump on high or equal */ 150194206Ssimon { 'c', "nh" }, /* jump on A not high */ 151194206Ssimon { 'c', "le" }, /* jump on low or equal */ 152194206Ssimon}; 153194206Ssimon 154194206Ssimon/* As with insertOpcode instructions are added to the sorted opcode 155194206Ssimon array. Additionally mnemonics containing the '*<number>' tag are 156194206Ssimon expanded to the set of conditional instructions described by 157194206Ssimon s390_cond_extensions with the tag replaced by the respective 158194206Ssimon mnemonic extensions. */ 159194206Ssimon 160194206Ssimonstatic void 161194206SsimoninsertExpandedMnemonic (char *opcode, char *mnemonic, char *format, 162194206Ssimon int min_cpu, int mode_bits, int flags) 163194206Ssimon{ 164194206Ssimon char *tag; 165194206Ssimon char prefix[15]; 166194206Ssimon char suffix[15]; 167194206Ssimon char number[15]; 168194206Ssimon int mask_start, i = 0, tag_found = 0, reading_number = 0; 169194206Ssimon int number_p = 0, suffix_p = 0, prefix_p = 0; 170194206Ssimon const struct s390_cond_ext_format *ext_table; 171194206Ssimon int ext_table_length; 172194206Ssimon 173194206Ssimon if (!(tag = strpbrk (mnemonic, "*$"))) 174194206Ssimon { 175194206Ssimon insertOpcode (opcode, mnemonic, format, min_cpu, mode_bits, flags); 176194206Ssimon return; 177205128Ssimon } 178205128Ssimon 179205128Ssimon while (mnemonic[i] != '\0') 180205128Ssimon { 181205128Ssimon if (mnemonic[i] == *tag) 182205128Ssimon { 183205128Ssimon if (tag_found) 184205128Ssimon goto malformed_mnemonic; 185205128Ssimon 186205128Ssimon tag_found = 1; 187205128Ssimon reading_number = 1; 188194206Ssimon } 189205128Ssimon else 190205128Ssimon switch (mnemonic[i]) 191205128Ssimon { 192205128Ssimon case '0': case '1': case '2': case '3': case '4': 193205128Ssimon case '5': case '6': case '7': case '8': case '9': 194205128Ssimon if (!tag_found || !reading_number) 195205128Ssimon goto malformed_mnemonic; 196205128Ssimon 197205128Ssimon number[number_p++] = mnemonic[i]; 198205128Ssimon break; 199205128Ssimon 200205128Ssimon default: 201205128Ssimon if (reading_number) 202205128Ssimon { 203205128Ssimon if (!number_p) 204194206Ssimon goto malformed_mnemonic; 205194206Ssimon else 206194206Ssimon reading_number = 0; 207205128Ssimon } 208194206Ssimon 209194206Ssimon if (tag_found) 210194206Ssimon suffix[suffix_p++] = mnemonic[i]; 211194206Ssimon else 212194206Ssimon prefix[prefix_p++] = mnemonic[i]; 213194206Ssimon } 214194206Ssimon i++; 215194206Ssimon } 216194206Ssimon 217194206Ssimon prefix[prefix_p] = '\0'; 218194206Ssimon suffix[suffix_p] = '\0'; 219194206Ssimon number[number_p] = '\0'; 220194206Ssimon 221194206Ssimon if (sscanf (number, "%d", &mask_start) != 1) 222194206Ssimon goto malformed_mnemonic; 223194206Ssimon 224194206Ssimon if (mask_start & 3) 225205128Ssimon { 226205128Ssimon fprintf (stderr, "Conditional mask not at nibble boundary in: %s\n", 227194206Ssimon mnemonic); 228194206Ssimon return; 229194206Ssimon } 230194206Ssimon 231194206Ssimon mask_start >>= 2; 232194206Ssimon 233194206Ssimon switch (*tag) 234194206Ssimon { 235194206Ssimon case '*': 236194206Ssimon ext_table = s390_cond_extensions; 237194206Ssimon ext_table_length = NUM_COND_EXTENSIONS; 238194206Ssimon break; 239194206Ssimon case '$': 240194206Ssimon ext_table = s390_crb_extensions; 241194206Ssimon ext_table_length = NUM_CRB_EXTENSIONS; 242194206Ssimon break; 243194206Ssimon default: 244194206Ssimon abort (); /* Should be unreachable. */ 245194206Ssimon } 246194206Ssimon 247194206Ssimon for (i = 0; i < ext_table_length; i++) 248194206Ssimon { 249194206Ssimon char new_mnemonic[15]; 250194206Ssimon 251194206Ssimon strcpy (new_mnemonic, prefix); 252194206Ssimon opcode[mask_start] = ext_table[i].nibble; 253194206Ssimon strcat (new_mnemonic, ext_table[i].extension); 254194206Ssimon strcat (new_mnemonic, suffix); 255194206Ssimon insertOpcode (opcode, new_mnemonic, format, min_cpu, mode_bits, flags); 256194206Ssimon } 257194206Ssimon return; 258194206Ssimon 259194206Ssimon malformed_mnemonic: 260194206Ssimon fprintf (stderr, "Malformed mnemonic: %s\n", mnemonic); 261194206Ssimon} 262194206Ssimon 263194206Ssimonstatic const char file_header[] = 264194206Ssimon "/* The opcode table. This file was generated by s390-mkopc.\n\n" 265194206Ssimon " The format of the opcode table is:\n\n" 266194206Ssimon " NAME OPCODE MASK OPERANDS\n\n" 267194206Ssimon " Name is the name of the instruction.\n" 268194206Ssimon " OPCODE is the instruction opcode.\n" 269194206Ssimon " MASK is the opcode mask; this is used to tell the disassembler\n" 270194206Ssimon " which bits in the actual opcode must match OPCODE.\n" 271194206Ssimon " OPERANDS is the list of operands.\n\n" 272194206Ssimon " The disassembler reads the table in order and prints the first\n" 273194206Ssimon " instruction which matches.\n" 274194206Ssimon " MODE_BITS - zarch or esa\n" 275194206Ssimon " MIN_CPU - number of the min cpu level required\n" 276194206Ssimon " FLAGS - instruction flags. */\n\n" 277194206Ssimon "const struct s390_opcode s390_opcodes[] =\n {\n"; 278194206Ssimon 279194206Ssimon/* `dumpTable': write opcode table. */ 280194206Ssimon 281194206Ssimonstatic void 282194206SsimondumpTable (void) 283194206Ssimon{ 284194206Ssimon char *str; 285194206Ssimon int ix; 286205128Ssimon 287205128Ssimon /* Write hash table entries (slots). */ 288205128Ssimon printf ("%s", file_header); 289205128Ssimon 290194206Ssimon for (ix = 0; ix < no_ops; ix++) 291194206Ssimon { 292194206Ssimon printf (" { \"%s\", ", op_array[ix].mnemonic); 293194206Ssimon for (str = op_array[ix].opcode; *str != 0; str++) 294194206Ssimon if (*str == '?') 295194206Ssimon *str = '0'; 296194206Ssimon printf ("OP%i(0x%sLL), ", 297194206Ssimon op_array[ix].no_nibbles*4, op_array[ix].opcode); 298194206Ssimon printf ("MASK_%s, INSTR_%s, ", 299194206Ssimon op_array[ix].format, op_array[ix].format); 300205128Ssimon printf ("%i, ", op_array[ix].mode_bits); 301205128Ssimon printf ("%i, ", op_array[ix].min_cpu); 302205128Ssimon printf ("%i}", op_array[ix].flags); 303205128Ssimon if (ix < no_ops-1) 304205128Ssimon printf (",\n"); 305205128Ssimon else 306205128Ssimon printf ("\n"); 307205128Ssimon } 308205128Ssimon printf ("};\n\n"); 309205128Ssimon printf ("const int s390_num_opcodes =\n"); 310205128Ssimon printf (" sizeof (s390_opcodes) / sizeof (s390_opcodes[0]);\n\n"); 311205128Ssimon} 312205128Ssimon 313205128Ssimonint 314205128Ssimonmain (void) 315205128Ssimon{ 316205128Ssimon char currentLine[256]; 317205128Ssimon 318205128Ssimon createTable (); 319205128Ssimon 320205128Ssimon /* Read opcode descriptions from `stdin'. For each mnemonic, 321205128Ssimon make an entry into the opcode table. */ 322205128Ssimon while (fgets (currentLine, sizeof (currentLine), stdin) != NULL) 323205128Ssimon { 324194206Ssimon char opcode[16]; 325194206Ssimon char mnemonic[16]; 326194206Ssimon char format[16]; 327194206Ssimon char description[80]; 328194206Ssimon char cpu_string[16]; 329194206Ssimon char modes_string[16]; 330194206Ssimon char flags_string[80]; 331194206Ssimon int min_cpu; 332194206Ssimon int mode_bits; 333194206Ssimon int flag_bits; 334194206Ssimon int num_matched; 335194206Ssimon char *str; 336194206Ssimon 337194206Ssimon if (currentLine[0] == '#' || currentLine[0] == '\n') 338194206Ssimon continue; 339194206Ssimon memset (opcode, 0, 8); 340194206Ssimon num_matched = 341194206Ssimon sscanf (currentLine, "%15s %15s %15s \"%79[^\"]\" %15s %15s %79[^\n]", 342194206Ssimon opcode, mnemonic, format, description, 343194206Ssimon cpu_string, modes_string, flags_string); 344194206Ssimon if (num_matched != 6 && num_matched != 7) 345194206Ssimon { 346194206Ssimon fprintf (stderr, "Couldn't scan line %s\n", currentLine); 347194206Ssimon exit (1); 348194206Ssimon } 349194206Ssimon 350194206Ssimon if (strcmp (cpu_string, "g5") == 0 351194206Ssimon || strcmp (cpu_string, "arch3") == 0) 352194206Ssimon min_cpu = S390_OPCODE_G5; 353205128Ssimon else if (strcmp (cpu_string, "g6") == 0) 354205128Ssimon min_cpu = S390_OPCODE_G6; 355194206Ssimon else if (strcmp (cpu_string, "z900") == 0 356194206Ssimon || strcmp (cpu_string, "arch5") == 0) 357194206Ssimon min_cpu = S390_OPCODE_Z900; 358194206Ssimon else if (strcmp (cpu_string, "z990") == 0 359205128Ssimon || strcmp (cpu_string, "arch6") == 0) 360205128Ssimon min_cpu = S390_OPCODE_Z990; 361194206Ssimon else if (strcmp (cpu_string, "z9-109") == 0) 362194206Ssimon min_cpu = S390_OPCODE_Z9_109; 363194206Ssimon else if (strcmp (cpu_string, "z9-ec") == 0 364205128Ssimon || strcmp (cpu_string, "arch7") == 0) 365194206Ssimon min_cpu = S390_OPCODE_Z9_EC; 366194206Ssimon else if (strcmp (cpu_string, "z10") == 0 367194206Ssimon || strcmp (cpu_string, "arch8") == 0) 368194206Ssimon min_cpu = S390_OPCODE_Z10; 369194206Ssimon else if (strcmp (cpu_string, "z196") == 0 370194206Ssimon || strcmp (cpu_string, "arch9") == 0) 371194206Ssimon min_cpu = S390_OPCODE_Z196; 372205128Ssimon else if (strcmp (cpu_string, "zEC12") == 0 373194206Ssimon || strcmp (cpu_string, "arch10") == 0) 374194206Ssimon min_cpu = S390_OPCODE_ZEC12; 375194206Ssimon else if (strcmp (cpu_string, "z13") == 0 376194206Ssimon || strcmp (cpu_string, "arch11") == 0) 377194206Ssimon min_cpu = S390_OPCODE_Z13; 378194206Ssimon else if (strcmp (cpu_string, "z14") == 0 379194206Ssimon || strcmp (cpu_string, "arch12") == 0) 380194206Ssimon min_cpu = S390_OPCODE_ARCH12; 381194206Ssimon else if (strcmp (cpu_string, "z15") == 0 382194206Ssimon || strcmp (cpu_string, "arch13") == 0) 383194206Ssimon min_cpu = S390_OPCODE_ARCH13; 384194206Ssimon else if (strcmp (cpu_string, "z16") == 0 385194206Ssimon || strcmp (cpu_string, "arch14") == 0) 386194206Ssimon min_cpu = S390_OPCODE_ARCH14; 387194206Ssimon else { 388194206Ssimon fprintf (stderr, "Couldn't parse cpu string %s\n", cpu_string); 389194206Ssimon exit (1); 390194206Ssimon } 391194206Ssimon 392194206Ssimon str = modes_string; 393194206Ssimon mode_bits = 0; 394194206Ssimon do { 395194206Ssimon if (strncmp (str, "esa", 3) == 0 396194206Ssimon && (str[3] == 0 || str[3] == ',')) { 397194206Ssimon mode_bits |= 1 << S390_OPCODE_ESA; 398194206Ssimon str += 3; 399194206Ssimon } else if (strncmp (str, "zarch", 5) == 0 400194206Ssimon && (str[5] == 0 || str[5] == ',')) { 401194206Ssimon mode_bits |= 1 << S390_OPCODE_ZARCH; 402194206Ssimon str += 5; 403194206Ssimon } else { 404194206Ssimon fprintf (stderr, "Couldn't parse modes string %s\n", 405194206Ssimon modes_string); 406194206Ssimon exit (1); 407194206Ssimon } 408194206Ssimon if (*str == ',') 409194206Ssimon str++; 410194206Ssimon } while (*str != 0); 411194206Ssimon 412194206Ssimon flag_bits = 0; 413194206Ssimon 414194206Ssimon if (num_matched == 7) 415194206Ssimon { 416194206Ssimon str = flags_string; 417194206Ssimon do { 418194206Ssimon if (strncmp (str, "optparm", 7) == 0 419194206Ssimon && (str[7] == 0 || str[7] == ',')) { 420194206Ssimon flag_bits |= S390_INSTR_FLAG_OPTPARM; 421194206Ssimon str += 7; 422194206Ssimon } else if (strncmp (str, "optparm2", 8) == 0 423194206Ssimon && (str[8] == 0 || str[8] == ',')) { 424194206Ssimon flag_bits |= S390_INSTR_FLAG_OPTPARM2; 425194206Ssimon str += 8; 426194206Ssimon } else if (strncmp (str, "htm", 3) == 0 427194206Ssimon && (str[3] == 0 || str[3] == ',')) { 428194206Ssimon flag_bits |= S390_INSTR_FLAG_HTM; 429194206Ssimon str += 3; 430194206Ssimon } else if (strncmp (str, "vx", 2) == 0 431194206Ssimon && (str[2] == 0 || str[2] == ',')) { 432194206Ssimon flag_bits |= S390_INSTR_FLAG_VX; 433194206Ssimon str += 2; 434194206Ssimon } else { 435215697Ssimon fprintf (stderr, "Couldn't parse flags string %s\n", 436194206Ssimon flags_string); 437215697Ssimon exit (1); 438194206Ssimon } 439215697Ssimon if (*str == ',') 440215697Ssimon str++; 441215697Ssimon } while (*str != 0); 442215697Ssimon } 443215697Ssimon insertExpandedMnemonic (opcode, mnemonic, format, min_cpu, mode_bits, flag_bits); 444194206Ssimon } 445194206Ssimon 446194206Ssimon dumpTable (); 447215697Ssimon return 0; 448215697Ssimon} 449215697Ssimon