linux/arch/s390/tools/gen_opcode_table.c
<<
>>
Prefs
   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
  16struct insn_type {
  17        unsigned char byte;
  18        unsigned char mask;
  19        char **format;
  20};
  21
  22struct 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
  31struct insn_group {
  32        struct insn_type *type;
  33        int offset;
  34        int count;
  35        char opcode[2];
  36};
  37
  38struct insn_format {
  39        char *format;
  40        int type;
  41};
  42
  43struct 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 */
  66static 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
 132static 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
 152static 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
 175static int cmpformat(const void *a, const void *b)
 176{
 177        return strcmp(((struct insn *)a)->format, ((struct insn *)b)->format);
 178}
 179
 180static 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
 199static int cmp_long_insn(const void *a, const void *b)
 200{
 201        return strcmp(((struct insn *)a)->name, ((struct insn *)b)->name);
 202}
 203
 204static 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
 231static 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
 246static 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
 266static int cmpopcode(const void *a, const void *b)
 267{
 268        return strcmp(((struct insn *)a)->opcode, ((struct insn *)b)->opcode);
 269}
 270
 271static 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
 304static 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
 318int 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}
 338