root/arch/s390/tools/gen_opcode_table.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. insn_format_to_type
  2. read_instructions
  3. cmpformat
  4. print_formats
  5. cmp_long_insn
  6. print_long_insn
  7. print_opcode
  8. add_to_group
  9. cmpopcode
  10. print_opcode_table
  11. print_opcode_table_offsets
  12. main

   1 /* SPDX-License-Identifier: GPL-2.0 */
   2 /*
   3  * Generate opcode table initializers for the in-kernel disassembler.
   4  *
   5  *    Copyright IBM Corp. 2017
   6  *
   7  */
   8 
   9 #include <stdlib.h>
  10 #include <string.h>
  11 #include <ctype.h>
  12 #include <stdio.h>
  13 
  14 #define STRING_SIZE_MAX 20
  15 
  16 struct insn_type {
  17         unsigned char byte;
  18         unsigned char mask;
  19         char **format;
  20 };
  21 
  22 struct insn {
  23         struct insn_type *type;
  24         char opcode[STRING_SIZE_MAX];
  25         char name[STRING_SIZE_MAX];
  26         char upper[STRING_SIZE_MAX];
  27         char format[STRING_SIZE_MAX];
  28         unsigned int name_len;
  29 };
  30 
  31 struct insn_group {
  32         struct insn_type *type;
  33         int offset;
  34         int count;
  35         char opcode[2];
  36 };
  37 
  38 struct insn_format {
  39         char *format;
  40         int type;
  41 };
  42 
  43 struct gen_opcode {
  44         struct insn *insn;
  45         int nr;
  46         struct insn_group *group;
  47         int nr_groups;
  48 };
  49 
  50 /*
  51  * Table of instruction format types. Each opcode is defined with at
  52  * least one byte (two nibbles), three nibbles, or two bytes (four
  53  * nibbles).
  54  * The byte member of each instruction format type entry defines
  55  * within which byte of an instruction the third (and fourth) nibble
  56  * of an opcode can be found. The mask member is the and-mask that
  57  * needs to be applied on this byte in order to get the third (and
  58  * fourth) nibble of the opcode.
  59  * The format array defines all instruction formats (as defined in the
  60  * Principles of Operation) which have the same position of the opcode
  61  * nibbles.
  62  * A special case are instruction formats with 1-byte opcodes. In this
  63  * case the byte member always is zero, so that the mask is applied on
  64  * the (only) byte that contains the opcode.
  65  */
  66 static struct insn_type insn_type_table[] = {
  67         {
  68                 .byte = 0,
  69                 .mask = 0xff,
  70                 .format = (char *[]) {
  71                         "MII",
  72                         "RR",
  73                         "RS",
  74                         "RSI",
  75                         "RX",
  76                         "SI",
  77                         "SMI",
  78                         "SS",
  79                         NULL,
  80                 },
  81         },
  82         {
  83                 .byte = 1,
  84                 .mask = 0x0f,
  85                 .format = (char *[]) {
  86                         "RI",
  87                         "RIL",
  88                         "SSF",
  89                         NULL,
  90                 },
  91         },
  92         {
  93                 .byte = 1,
  94                 .mask = 0xff,
  95                 .format = (char *[]) {
  96                         "E",
  97                         "IE",
  98                         "RRE",
  99                         "RRF",
 100                         "RRR",
 101                         "S",
 102                         "SIL",
 103                         "SSE",
 104                         NULL,
 105                 },
 106         },
 107         {
 108                 .byte = 5,
 109                 .mask = 0xff,
 110                 .format = (char *[]) {
 111                         "RIE",
 112                         "RIS",
 113                         "RRS",
 114                         "RSE",
 115                         "RSL",
 116                         "RSY",
 117                         "RXE",
 118                         "RXF",
 119                         "RXY",
 120                         "SIY",
 121                         "VRI",
 122                         "VRR",
 123                         "VRS",
 124                         "VRV",
 125                         "VRX",
 126                         "VSI",
 127                         NULL,
 128                 },
 129         },
 130 };
 131 
 132 static struct insn_type *insn_format_to_type(char *format)
 133 {
 134         char tmp[STRING_SIZE_MAX];
 135         char *base_format, **ptr;
 136         int i;
 137 
 138         strcpy(tmp, format);
 139         base_format = tmp;
 140         base_format = strsep(&base_format, "_");
 141         for (i = 0; i < sizeof(insn_type_table) / sizeof(insn_type_table[0]); i++) {
 142                 ptr = insn_type_table[i].format;
 143                 while (*ptr) {
 144                         if (!strcmp(base_format, *ptr))
 145                                 return &insn_type_table[i];
 146                         ptr++;
 147                 }
 148         }
 149         exit(EXIT_FAILURE);
 150 }
 151 
 152 static void read_instructions(struct gen_opcode *desc)
 153 {
 154         struct insn insn;
 155         int rc, i;
 156 
 157         while (1) {
 158                 rc = scanf("%s %s %s", insn.opcode, insn.name, insn.format);
 159                 if (rc == EOF)
 160                         break;
 161                 if (rc != 3)
 162                         exit(EXIT_FAILURE);
 163                 insn.type = insn_format_to_type(insn.format);
 164                 insn.name_len = strlen(insn.name);
 165                 for (i = 0; i <= insn.name_len; i++)
 166                         insn.upper[i] = toupper((unsigned char)insn.name[i]);
 167                 desc->nr++;
 168                 desc->insn = realloc(desc->insn, desc->nr * sizeof(*desc->insn));
 169                 if (!desc->insn)
 170                         exit(EXIT_FAILURE);
 171                 desc->insn[desc->nr - 1] = insn;
 172         }
 173 }
 174 
 175 static int cmpformat(const void *a, const void *b)
 176 {
 177         return strcmp(((struct insn *)a)->format, ((struct insn *)b)->format);
 178 }
 179 
 180 static void print_formats(struct gen_opcode *desc)
 181 {
 182         char *format;
 183         int i, count;
 184 
 185         qsort(desc->insn, desc->nr, sizeof(*desc->insn), cmpformat);
 186         format = "";
 187         count = 0;
 188         printf("enum {\n");
 189         for (i = 0; i < desc->nr; i++) {
 190                 if (!strcmp(format, desc->insn[i].format))
 191                         continue;
 192                 count++;
 193                 format = desc->insn[i].format;
 194                 printf("\tINSTR_%s,\n", format);
 195         }
 196         printf("}; /* %d */\n\n", count);
 197 }
 198 
 199 static int cmp_long_insn(const void *a, const void *b)
 200 {
 201         return strcmp(((struct insn *)a)->name, ((struct insn *)b)->name);
 202 }
 203 
 204 static void print_long_insn(struct gen_opcode *desc)
 205 {
 206         struct insn *insn;
 207         int i, count;
 208 
 209         qsort(desc->insn, desc->nr, sizeof(*desc->insn), cmp_long_insn);
 210         count = 0;
 211         printf("enum {\n");
 212         for (i = 0; i < desc->nr; i++) {
 213                 insn = &desc->insn[i];
 214                 if (insn->name_len < 6)
 215                         continue;
 216                 printf("\tLONG_INSN_%s,\n", insn->upper);
 217                 count++;
 218         }
 219         printf("}; /* %d */\n\n", count);
 220 
 221         printf("#define LONG_INSN_INITIALIZER { \\\n");
 222         for (i = 0; i < desc->nr; i++) {
 223                 insn = &desc->insn[i];
 224                 if (insn->name_len < 6)
 225                         continue;
 226                 printf("\t[LONG_INSN_%s] = \"%s\", \\\n", insn->upper, insn->name);
 227         }
 228         printf("}\n\n");
 229 }
 230 
 231 static void print_opcode(struct insn *insn, int nr)
 232 {
 233         char *opcode;
 234 
 235         opcode = insn->opcode;
 236         if (insn->type->byte != 0)
 237                 opcode += 2;
 238         printf("\t[%4d] = { .opfrag = 0x%s, .format = INSTR_%s, ", nr, opcode, insn->format);
 239         if (insn->name_len < 6)
 240                 printf(".name = \"%s\" ", insn->name);
 241         else
 242                 printf(".offset = LONG_INSN_%s ", insn->upper);
 243         printf("}, \\\n");
 244 }
 245 
 246 static void add_to_group(struct gen_opcode *desc, struct insn *insn, int offset)
 247 {
 248         struct insn_group *group;
 249 
 250         group = desc->group ? &desc->group[desc->nr_groups - 1] : NULL;
 251         if (group && (!strncmp(group->opcode, insn->opcode, 2) || group->type->byte == 0)) {
 252                 group->count++;
 253                 return;
 254         }
 255         desc->nr_groups++;
 256         desc->group = realloc(desc->group, desc->nr_groups * sizeof(*desc->group));
 257         if (!desc->group)
 258                 exit(EXIT_FAILURE);
 259         group = &desc->group[desc->nr_groups - 1];
 260         memcpy(group->opcode, insn->opcode, 2);
 261         group->type = insn->type;
 262         group->offset = offset;
 263         group->count = 1;
 264 }
 265 
 266 static int cmpopcode(const void *a, const void *b)
 267 {
 268         return strcmp(((struct insn *)a)->opcode, ((struct insn *)b)->opcode);
 269 }
 270 
 271 static void print_opcode_table(struct gen_opcode *desc)
 272 {
 273         char opcode[2] = "";
 274         struct insn *insn;
 275         int i, offset;
 276 
 277         qsort(desc->insn, desc->nr, sizeof(*desc->insn), cmpopcode);
 278         printf("#define OPCODE_TABLE_INITIALIZER { \\\n");
 279         offset = 0;
 280         for (i = 0; i < desc->nr; i++) {
 281                 insn = &desc->insn[i];
 282                 if (insn->type->byte == 0)
 283                         continue;
 284                 add_to_group(desc, insn, offset);
 285                 if (strncmp(opcode, insn->opcode, 2)) {
 286                         memcpy(opcode, insn->opcode, 2);
 287                         printf("\t/* %.2s */ \\\n", opcode);
 288                 }
 289                 print_opcode(insn, offset);
 290                 offset++;
 291         }
 292         printf("\t/* 1-byte opcode instructions */ \\\n");
 293         for (i = 0; i < desc->nr; i++) {
 294                 insn = &desc->insn[i];
 295                 if (insn->type->byte != 0)
 296                         continue;
 297                 add_to_group(desc, insn, offset);
 298                 print_opcode(insn, offset);
 299                 offset++;
 300         }
 301         printf("}\n\n");
 302 }
 303 
 304 static void print_opcode_table_offsets(struct gen_opcode *desc)
 305 {
 306         struct insn_group *group;
 307         int i;
 308 
 309         printf("#define OPCODE_OFFSET_INITIALIZER { \\\n");
 310         for (i = 0; i < desc->nr_groups; i++) {
 311                 group = &desc->group[i];
 312                 printf("\t{ .opcode = 0x%.2s, .mask = 0x%02x, .byte = %d, .offset = %d, .count = %d }, \\\n",
 313                        group->opcode, group->type->mask, group->type->byte, group->offset, group->count);
 314         }
 315         printf("}\n\n");
 316 }
 317 
 318 int main(int argc, char **argv)
 319 {
 320         struct gen_opcode _desc = { 0 };
 321         struct gen_opcode *desc = &_desc;
 322 
 323         read_instructions(desc);
 324         printf("#ifndef __S390_GENERATED_DIS_DEFS_H__\n");
 325         printf("#define __S390_GENERATED_DIS_DEFS_H__\n");
 326         printf("/*\n");
 327         printf(" * DO NOT MODIFY.\n");
 328         printf(" *\n");
 329         printf(" * This file was generated by %s\n", __FILE__);
 330         printf(" */\n\n");
 331         print_formats(desc);
 332         print_long_insn(desc);
 333         print_opcode_table(desc);
 334         print_opcode_table_offsets(desc);
 335         printf("#endif\n");
 336         exit(EXIT_SUCCESS);
 337 }

/* [<][>][^][v][top][bottom][index][help] */