Home | History | Annotate | Download | only in common
      1 /*
      2  * Copyright  2016 Intel Corporation
      3  *
      4  * Permission is hereby granted, free of charge, to any person obtaining a
      5  * copy of this software and associated documentation files (the "Software"),
      6  * to deal in the Software without restriction, including without limitation
      7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      8  * and/or sell copies of the Software, and to permit persons to whom the
      9  * Software is furnished to do so, subject to the following conditions:
     10  *
     11  * The above copyright notice and this permission notice (including the next
     12  * paragraph) shall be included in all copies or substantial portions of the
     13  * Software.
     14  *
     15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
     21  * IN THE SOFTWARE.
     22  */
     23 
     24 #include <stdio.h>
     25 #include <stdbool.h>
     26 #include <stdint.h>
     27 #include <stdarg.h>
     28 #include <string.h>
     29 #include <expat.h>
     30 #include <inttypes.h>
     31 #include <zlib.h>
     32 
     33 #include <util/macros.h>
     34 #include <util/ralloc.h>
     35 
     36 #include "gen_decoder.h"
     37 
     38 #include "genxml/genX_xml.h"
     39 
     40 #define XML_BUFFER_SIZE 4096
     41 #define MAX_VALUE_ITEMS 128
     42 
     43 struct location {
     44    const char *filename;
     45    int line_number;
     46 };
     47 
     48 struct parser_context {
     49    XML_Parser parser;
     50    int foo;
     51    struct location loc;
     52 
     53    struct gen_group *group;
     54    struct gen_enum *enoom;
     55 
     56    int n_values, n_allocated_values;
     57    struct gen_value **values;
     58 
     59    struct gen_field *last_field;
     60 
     61    struct gen_spec *spec;
     62 };
     63 
     64 const char *
     65 gen_group_get_name(struct gen_group *group)
     66 {
     67    return group->name;
     68 }
     69 
     70 uint32_t
     71 gen_group_get_opcode(struct gen_group *group)
     72 {
     73    return group->opcode;
     74 }
     75 
     76 struct gen_group *
     77 gen_spec_find_struct(struct gen_spec *spec, const char *name)
     78 {
     79    struct hash_entry *entry = _mesa_hash_table_search(spec->structs,
     80                                                       name);
     81    return entry ? entry->data : NULL;
     82 }
     83 
     84 struct gen_group *
     85 gen_spec_find_register(struct gen_spec *spec, uint32_t offset)
     86 {
     87    struct hash_entry *entry =
     88       _mesa_hash_table_search(spec->registers_by_offset,
     89                               (void *) (uintptr_t) offset);
     90    return entry ? entry->data : NULL;
     91 }
     92 
     93 struct gen_group *
     94 gen_spec_find_register_by_name(struct gen_spec *spec, const char *name)
     95 {
     96    struct hash_entry *entry =
     97       _mesa_hash_table_search(spec->registers_by_name, name);
     98    return entry ? entry->data : NULL;
     99 }
    100 
    101 struct gen_enum *
    102 gen_spec_find_enum(struct gen_spec *spec, const char *name)
    103 {
    104    struct hash_entry *entry = _mesa_hash_table_search(spec->enums,
    105                                                       name);
    106    return entry ? entry->data : NULL;
    107 }
    108 
    109 uint32_t
    110 gen_spec_get_gen(struct gen_spec *spec)
    111 {
    112    return spec->gen;
    113 }
    114 
    115 static void __attribute__((noreturn))
    116 fail(struct location *loc, const char *msg, ...)
    117 {
    118    va_list ap;
    119 
    120    va_start(ap, msg);
    121    fprintf(stderr, "%s:%d: error: ",
    122            loc->filename, loc->line_number);
    123    vfprintf(stderr, msg, ap);
    124    fprintf(stderr, "\n");
    125    va_end(ap);
    126    exit(EXIT_FAILURE);
    127 }
    128 
    129 static void
    130 get_group_offset_count(const char **atts, uint32_t *offset, uint32_t *count,
    131                        uint32_t *size, bool *variable)
    132 {
    133    for (int i = 0; atts[i]; i += 2) {
    134       char *p;
    135 
    136       if (strcmp(atts[i], "count") == 0) {
    137          *count = strtoul(atts[i + 1], &p, 0);
    138          if (*count == 0)
    139             *variable = true;
    140       } else if (strcmp(atts[i], "start") == 0) {
    141          *offset = strtoul(atts[i + 1], &p, 0);
    142       } else if (strcmp(atts[i], "size") == 0) {
    143          *size = strtoul(atts[i + 1], &p, 0);
    144       }
    145    }
    146    return;
    147 }
    148 
    149 static struct gen_group *
    150 create_group(struct parser_context *ctx,
    151              const char *name,
    152              const char **atts,
    153              struct gen_group *parent)
    154 {
    155    struct gen_group *group;
    156 
    157    group = rzalloc(ctx->spec, struct gen_group);
    158    if (name)
    159       group->name = ralloc_strdup(group, name);
    160 
    161    group->spec = ctx->spec;
    162    group->variable = false;
    163 
    164    for (int i = 0; atts[i]; i += 2) {
    165       char *p;
    166       if (strcmp(atts[i], "length") == 0) {
    167          group->dw_length = strtoul(atts[i + 1], &p, 0);
    168       }
    169    }
    170 
    171    if (parent) {
    172       group->parent = parent;
    173       get_group_offset_count(atts,
    174                              &group->group_offset,
    175                              &group->group_count,
    176                              &group->group_size,
    177                              &group->variable);
    178    }
    179 
    180    return group;
    181 }
    182 
    183 static struct gen_enum *
    184 create_enum(struct parser_context *ctx, const char *name, const char **atts)
    185 {
    186    struct gen_enum *e;
    187 
    188    e = rzalloc(ctx->spec, struct gen_enum);
    189    if (name)
    190       e->name = ralloc_strdup(e, name);
    191 
    192    return e;
    193 }
    194 
    195 static void
    196 get_register_offset(const char **atts, uint32_t *offset)
    197 {
    198    for (int i = 0; atts[i]; i += 2) {
    199       char *p;
    200 
    201       if (strcmp(atts[i], "num") == 0)
    202          *offset = strtoul(atts[i + 1], &p, 0);
    203    }
    204    return;
    205 }
    206 
    207 static void
    208 get_start_end_pos(int *start, int *end)
    209 {
    210    /* start value has to be mod with 32 as we need the relative
    211     * start position in the first DWord. For the end position, add
    212     * the length of the field to the start position to get the
    213     * relative postion in the 64 bit address.
    214     */
    215    if (*end - *start > 32) {
    216       int len = *end - *start;
    217       *start = *start % 32;
    218       *end = *start + len;
    219    } else {
    220       *start = *start % 32;
    221       *end = *end % 32;
    222    }
    223 
    224    return;
    225 }
    226 
    227 static inline uint64_t
    228 mask(int start, int end)
    229 {
    230    uint64_t v;
    231 
    232    v = ~0ULL >> (63 - end + start);
    233 
    234    return v << start;
    235 }
    236 
    237 static inline uint64_t
    238 field_value(uint64_t value, int start, int end)
    239 {
    240    get_start_end_pos(&start, &end);
    241    return (value & mask(start, end)) >> (start);
    242 }
    243 
    244 static struct gen_type
    245 string_to_type(struct parser_context *ctx, const char *s)
    246 {
    247    int i, f;
    248    struct gen_group *g;
    249    struct gen_enum *e;
    250 
    251    if (strcmp(s, "int") == 0)
    252       return (struct gen_type) { .kind = GEN_TYPE_INT };
    253    else if (strcmp(s, "uint") == 0)
    254       return (struct gen_type) { .kind = GEN_TYPE_UINT };
    255    else if (strcmp(s, "bool") == 0)
    256       return (struct gen_type) { .kind = GEN_TYPE_BOOL };
    257    else if (strcmp(s, "float") == 0)
    258       return (struct gen_type) { .kind = GEN_TYPE_FLOAT };
    259    else if (strcmp(s, "address") == 0)
    260       return (struct gen_type) { .kind = GEN_TYPE_ADDRESS };
    261    else if (strcmp(s, "offset") == 0)
    262       return (struct gen_type) { .kind = GEN_TYPE_OFFSET };
    263    else if (sscanf(s, "u%d.%d", &i, &f) == 2)
    264       return (struct gen_type) { .kind = GEN_TYPE_UFIXED, .i = i, .f = f };
    265    else if (sscanf(s, "s%d.%d", &i, &f) == 2)
    266       return (struct gen_type) { .kind = GEN_TYPE_SFIXED, .i = i, .f = f };
    267    else if (g = gen_spec_find_struct(ctx->spec, s), g != NULL)
    268       return (struct gen_type) { .kind = GEN_TYPE_STRUCT, .gen_struct = g };
    269    else if (e = gen_spec_find_enum(ctx->spec, s), e != NULL)
    270       return (struct gen_type) { .kind = GEN_TYPE_ENUM, .gen_enum = e };
    271    else if (strcmp(s, "mbo") == 0)
    272       return (struct gen_type) { .kind = GEN_TYPE_MBO };
    273    else
    274       fail(&ctx->loc, "invalid type: %s", s);
    275 }
    276 
    277 static struct gen_field *
    278 create_field(struct parser_context *ctx, const char **atts)
    279 {
    280    struct gen_field *field;
    281 
    282    field = rzalloc(ctx->group, struct gen_field);
    283    field->parent = ctx->group;
    284 
    285    for (int i = 0; atts[i]; i += 2) {
    286       char *p;
    287 
    288       if (strcmp(atts[i], "name") == 0)
    289          field->name = ralloc_strdup(field, atts[i + 1]);
    290       else if (strcmp(atts[i], "start") == 0)
    291          field->start = strtoul(atts[i + 1], &p, 0);
    292       else if (strcmp(atts[i], "end") == 0) {
    293          field->end = strtoul(atts[i + 1], &p, 0);
    294       } else if (strcmp(atts[i], "type") == 0)
    295          field->type = string_to_type(ctx, atts[i + 1]);
    296       else if (strcmp(atts[i], "default") == 0 &&
    297                field->start >= 16 && field->end <= 31) {
    298          field->has_default = true;
    299          field->default_value = strtoul(atts[i + 1], &p, 0);
    300       }
    301    }
    302 
    303    return field;
    304 }
    305 
    306 static struct gen_value *
    307 create_value(struct parser_context *ctx, const char **atts)
    308 {
    309    struct gen_value *value = rzalloc(ctx->values, struct gen_value);
    310 
    311    for (int i = 0; atts[i]; i += 2) {
    312       if (strcmp(atts[i], "name") == 0)
    313          value->name = ralloc_strdup(value, atts[i + 1]);
    314       else if (strcmp(atts[i], "value") == 0)
    315          value->value = strtoul(atts[i + 1], NULL, 0);
    316    }
    317 
    318    return value;
    319 }
    320 
    321 static struct gen_field *
    322 create_and_append_field(struct parser_context *ctx,
    323                         const char **atts)
    324 {
    325    struct gen_field *field = create_field(ctx, atts);
    326    struct gen_field *prev = NULL, *list = ctx->group->fields;
    327 
    328    while (list && field->start > list->start) {
    329       prev = list;
    330       list = list->next;
    331    }
    332 
    333    field->next = list;
    334    if (prev == NULL)
    335       ctx->group->fields = field;
    336    else
    337       prev->next = field;
    338 
    339    return field;
    340 }
    341 
    342 static void
    343 start_element(void *data, const char *element_name, const char **atts)
    344 {
    345    struct parser_context *ctx = data;
    346    const char *name = NULL;
    347    const char *gen = NULL;
    348 
    349    ctx->loc.line_number = XML_GetCurrentLineNumber(ctx->parser);
    350 
    351    for (int i = 0; atts[i]; i += 2) {
    352       if (strcmp(atts[i], "name") == 0)
    353          name = atts[i + 1];
    354       else if (strcmp(atts[i], "gen") == 0)
    355          gen = atts[i + 1];
    356    }
    357 
    358    if (strcmp(element_name, "genxml") == 0) {
    359       if (name == NULL)
    360          fail(&ctx->loc, "no platform name given");
    361       if (gen == NULL)
    362          fail(&ctx->loc, "no gen given");
    363 
    364       int major, minor;
    365       int n = sscanf(gen, "%d.%d", &major, &minor);
    366       if (n == 0)
    367          fail(&ctx->loc, "invalid gen given: %s", gen);
    368       if (n == 1)
    369          minor = 0;
    370 
    371       ctx->spec->gen = gen_make_gen(major, minor);
    372    } else if (strcmp(element_name, "instruction") == 0 ||
    373               strcmp(element_name, "struct") == 0) {
    374       ctx->group = create_group(ctx, name, atts, NULL);
    375    } else if (strcmp(element_name, "register") == 0) {
    376       ctx->group = create_group(ctx, name, atts, NULL);
    377       get_register_offset(atts, &ctx->group->register_offset);
    378    } else if (strcmp(element_name, "group") == 0) {
    379       struct gen_group *previous_group = ctx->group;
    380       while (previous_group->next)
    381          previous_group = previous_group->next;
    382 
    383       struct gen_group *group = create_group(ctx, "", atts, ctx->group);
    384       previous_group->next = group;
    385       ctx->group = group;
    386    } else if (strcmp(element_name, "field") == 0) {
    387       ctx->last_field = create_and_append_field(ctx, atts);
    388    } else if (strcmp(element_name, "enum") == 0) {
    389       ctx->enoom = create_enum(ctx, name, atts);
    390    } else if (strcmp(element_name, "value") == 0) {
    391       if (ctx->n_values >= ctx->n_allocated_values) {
    392          ctx->n_allocated_values = MAX2(2, ctx->n_allocated_values * 2);
    393          ctx->values = reralloc_array_size(ctx->spec, ctx->values,
    394                                            sizeof(struct gen_value *),
    395                                            ctx->n_allocated_values);
    396       }
    397       assert(ctx->n_values < ctx->n_allocated_values);
    398       ctx->values[ctx->n_values++] = create_value(ctx, atts);
    399    }
    400 
    401 }
    402 
    403 static void
    404 end_element(void *data, const char *name)
    405 {
    406    struct parser_context *ctx = data;
    407    struct gen_spec *spec = ctx->spec;
    408 
    409    if (strcmp(name, "instruction") == 0 ||
    410        strcmp(name, "struct") == 0 ||
    411        strcmp(name, "register") == 0) {
    412       struct gen_group *group = ctx->group;
    413       struct gen_field *list = group->fields;
    414 
    415       ctx->group = ctx->group->parent;
    416 
    417       while (list && list->end <= 31) {
    418          if (list->start >= 16 && list->has_default) {
    419             group->opcode_mask |=
    420                mask(list->start % 32, list->end % 32);
    421             group->opcode |= list->default_value << list->start;
    422          }
    423          list = list->next;
    424       }
    425 
    426       if (strcmp(name, "instruction") == 0)
    427          _mesa_hash_table_insert(spec->commands, group->name, group);
    428       else if (strcmp(name, "struct") == 0)
    429          _mesa_hash_table_insert(spec->structs, group->name, group);
    430       else if (strcmp(name, "register") == 0) {
    431          _mesa_hash_table_insert(spec->registers_by_name, group->name, group);
    432          _mesa_hash_table_insert(spec->registers_by_offset,
    433                                  (void *) (uintptr_t) group->register_offset,
    434                                  group);
    435       }
    436    } else if (strcmp(name, "group") == 0) {
    437       ctx->group = ctx->group->parent;
    438    } else if (strcmp(name, "field") == 0) {
    439       struct gen_field *field = ctx->last_field;
    440       ctx->last_field = NULL;
    441       field->inline_enum.values = ctx->values;
    442       field->inline_enum.nvalues = ctx->n_values;
    443       ctx->values = ralloc_array(ctx->spec, struct gen_value*, ctx->n_allocated_values = 2);
    444       ctx->n_values = 0;
    445    } else if (strcmp(name, "enum") == 0) {
    446       struct gen_enum *e = ctx->enoom;
    447       e->values = ctx->values;
    448       e->nvalues = ctx->n_values;
    449       ctx->values = ralloc_array(ctx->spec, struct gen_value*, ctx->n_allocated_values = 2);
    450       ctx->n_values = 0;
    451       ctx->enoom = NULL;
    452       _mesa_hash_table_insert(spec->enums, e->name, e);
    453    }
    454 }
    455 
    456 static void
    457 character_data(void *data, const XML_Char *s, int len)
    458 {
    459 }
    460 
    461 static int
    462 devinfo_to_gen(const struct gen_device_info *devinfo)
    463 {
    464    int value = 10 * devinfo->gen;
    465 
    466    if (devinfo->is_baytrail || devinfo->is_haswell)
    467       value += 5;
    468 
    469    return value;
    470 }
    471 
    472 static uint32_t zlib_inflate(const void *compressed_data,
    473                              uint32_t compressed_len,
    474                              void **out_ptr)
    475 {
    476    struct z_stream_s zstream;
    477    void *out;
    478 
    479    memset(&zstream, 0, sizeof(zstream));
    480 
    481    zstream.next_in = (unsigned char *)compressed_data;
    482    zstream.avail_in = compressed_len;
    483 
    484    if (inflateInit(&zstream) != Z_OK)
    485       return 0;
    486 
    487    out = malloc(4096);
    488    zstream.next_out = out;
    489    zstream.avail_out = 4096;
    490 
    491    do {
    492       switch (inflate(&zstream, Z_SYNC_FLUSH)) {
    493       case Z_STREAM_END:
    494          goto end;
    495       case Z_OK:
    496          break;
    497       default:
    498          inflateEnd(&zstream);
    499          return 0;
    500       }
    501 
    502       if (zstream.avail_out)
    503          break;
    504 
    505       out = realloc(out, 2*zstream.total_out);
    506       if (out == NULL) {
    507          inflateEnd(&zstream);
    508          return 0;
    509       }
    510 
    511       zstream.next_out = (unsigned char *)out + zstream.total_out;
    512       zstream.avail_out = zstream.total_out;
    513    } while (1);
    514  end:
    515    inflateEnd(&zstream);
    516    *out_ptr = out;
    517    return zstream.total_out;
    518 }
    519 
    520 static uint32_t _hash_uint32(const void *key)
    521 {
    522    return (uint32_t) (uintptr_t) key;
    523 }
    524 
    525 struct gen_spec *
    526 gen_spec_load(const struct gen_device_info *devinfo)
    527 {
    528    struct parser_context ctx;
    529    void *buf;
    530    uint8_t *text_data = NULL;
    531    uint32_t text_offset = 0, text_length = 0, total_length;
    532    uint32_t gen_10 = devinfo_to_gen(devinfo);
    533 
    534    for (int i = 0; i < ARRAY_SIZE(genxml_files_table); i++) {
    535       if (genxml_files_table[i].gen_10 == gen_10) {
    536          text_offset = genxml_files_table[i].offset;
    537          text_length = genxml_files_table[i].length;
    538          break;
    539       }
    540    }
    541 
    542    if (text_length == 0) {
    543       fprintf(stderr, "unable to find gen (%u) data\n", gen_10);
    544       return NULL;
    545    }
    546 
    547    memset(&ctx, 0, sizeof ctx);
    548    ctx.parser = XML_ParserCreate(NULL);
    549    XML_SetUserData(ctx.parser, &ctx);
    550    if (ctx.parser == NULL) {
    551       fprintf(stderr, "failed to create parser\n");
    552       return NULL;
    553    }
    554 
    555    XML_SetElementHandler(ctx.parser, start_element, end_element);
    556    XML_SetCharacterDataHandler(ctx.parser, character_data);
    557 
    558    ctx.spec = rzalloc(NULL, struct gen_spec);
    559 
    560    ctx.spec->commands =
    561       _mesa_hash_table_create(ctx.spec, _mesa_hash_string, _mesa_key_string_equal);
    562    ctx.spec->structs =
    563       _mesa_hash_table_create(ctx.spec, _mesa_hash_string, _mesa_key_string_equal);
    564    ctx.spec->registers_by_name =
    565       _mesa_hash_table_create(ctx.spec, _mesa_hash_string, _mesa_key_string_equal);
    566    ctx.spec->registers_by_offset =
    567       _mesa_hash_table_create(ctx.spec, _hash_uint32, _mesa_key_pointer_equal);
    568    ctx.spec->enums =
    569       _mesa_hash_table_create(ctx.spec, _mesa_hash_string, _mesa_key_string_equal);
    570 
    571    ctx.spec->access_cache =
    572       _mesa_hash_table_create(ctx.spec, _mesa_hash_string, _mesa_key_string_equal);
    573 
    574    total_length = zlib_inflate(compress_genxmls,
    575                                sizeof(compress_genxmls),
    576                                (void **) &text_data);
    577    assert(text_offset + text_length <= total_length);
    578 
    579    buf = XML_GetBuffer(ctx.parser, text_length);
    580    memcpy(buf, &text_data[text_offset], text_length);
    581 
    582    if (XML_ParseBuffer(ctx.parser, text_length, true) == 0) {
    583       fprintf(stderr,
    584               "Error parsing XML at line %ld col %ld byte %ld/%u: %s\n",
    585               XML_GetCurrentLineNumber(ctx.parser),
    586               XML_GetCurrentColumnNumber(ctx.parser),
    587               XML_GetCurrentByteIndex(ctx.parser), text_length,
    588               XML_ErrorString(XML_GetErrorCode(ctx.parser)));
    589       XML_ParserFree(ctx.parser);
    590       free(text_data);
    591       return NULL;
    592    }
    593 
    594    XML_ParserFree(ctx.parser);
    595    free(text_data);
    596 
    597    return ctx.spec;
    598 }
    599 
    600 struct gen_spec *
    601 gen_spec_load_from_path(const struct gen_device_info *devinfo,
    602                         const char *path)
    603 {
    604    struct parser_context ctx;
    605    size_t len, filename_len = strlen(path) + 20;
    606    char *filename = malloc(filename_len);
    607    void *buf;
    608    FILE *input;
    609 
    610    len = snprintf(filename, filename_len, "%s/gen%i.xml",
    611                   path, devinfo_to_gen(devinfo));
    612    assert(len < filename_len);
    613 
    614    input = fopen(filename, "r");
    615    if (input == NULL) {
    616       fprintf(stderr, "failed to open xml description\n");
    617       free(filename);
    618       return NULL;
    619    }
    620 
    621    memset(&ctx, 0, sizeof ctx);
    622    ctx.parser = XML_ParserCreate(NULL);
    623    XML_SetUserData(ctx.parser, &ctx);
    624    if (ctx.parser == NULL) {
    625       fprintf(stderr, "failed to create parser\n");
    626       fclose(input);
    627       free(filename);
    628       return NULL;
    629    }
    630 
    631    XML_SetElementHandler(ctx.parser, start_element, end_element);
    632    XML_SetCharacterDataHandler(ctx.parser, character_data);
    633    ctx.loc.filename = filename;
    634    ctx.spec = rzalloc(NULL, struct gen_spec);
    635 
    636    do {
    637       buf = XML_GetBuffer(ctx.parser, XML_BUFFER_SIZE);
    638       len = fread(buf, 1, XML_BUFFER_SIZE, input);
    639       if (len == 0) {
    640          fprintf(stderr, "fread: %m\n");
    641          free(ctx.spec);
    642          ctx.spec = NULL;
    643          goto end;
    644       }
    645       if (XML_ParseBuffer(ctx.parser, len, len == 0) == 0) {
    646          fprintf(stderr,
    647                  "Error parsing XML at line %ld col %ld: %s\n",
    648                  XML_GetCurrentLineNumber(ctx.parser),
    649                  XML_GetCurrentColumnNumber(ctx.parser),
    650                  XML_ErrorString(XML_GetErrorCode(ctx.parser)));
    651          free(ctx.spec);
    652          ctx.spec = NULL;
    653          goto end;
    654       }
    655    } while (len > 0);
    656 
    657  end:
    658    XML_ParserFree(ctx.parser);
    659 
    660    fclose(input);
    661    free(filename);
    662 
    663    return ctx.spec;
    664 }
    665 
    666 void gen_spec_destroy(struct gen_spec *spec)
    667 {
    668    ralloc_free(spec);
    669 }
    670 
    671 struct gen_group *
    672 gen_spec_find_instruction(struct gen_spec *spec, const uint32_t *p)
    673 {
    674    struct hash_entry *entry;
    675 
    676    hash_table_foreach(spec->commands, entry) {
    677       struct gen_group *command = entry->data;
    678       uint32_t opcode = *p & command->opcode_mask;
    679       if (opcode == command->opcode)
    680          return command;
    681    }
    682 
    683    return NULL;
    684 }
    685 
    686 struct gen_field *
    687 gen_group_find_field(struct gen_group *group, const char *name)
    688 {
    689    char path[256];
    690    snprintf(path, sizeof(path), "%s/%s", group->name, name);
    691 
    692    struct gen_spec *spec = group->spec;
    693    struct hash_entry *entry = _mesa_hash_table_search(spec->access_cache,
    694                                                       path);
    695    if (entry)
    696       return entry->data;
    697 
    698    struct gen_field *field = group->fields;
    699    while (field) {
    700       if (strcmp(field->name, name) == 0) {
    701          _mesa_hash_table_insert(spec->access_cache,
    702                                  ralloc_strdup(spec, path),
    703                                  field);
    704          return field;
    705       }
    706       field = field->next;
    707    }
    708 
    709    return NULL;
    710 }
    711 
    712 int
    713 gen_group_get_length(struct gen_group *group, const uint32_t *p)
    714 {
    715    uint32_t h = p[0];
    716    uint32_t type = field_value(h, 29, 31);
    717 
    718    switch (type) {
    719    case 0: /* MI */ {
    720       uint32_t opcode = field_value(h, 23, 28);
    721       if (opcode < 16)
    722          return 1;
    723       else
    724          return field_value(h, 0, 7) + 2;
    725       break;
    726    }
    727 
    728    case 2: /* BLT */ {
    729       return field_value(h, 0, 7) + 2;
    730    }
    731 
    732    case 3: /* Render */ {
    733       uint32_t subtype = field_value(h, 27, 28);
    734       uint32_t opcode = field_value(h, 24, 26);
    735       uint16_t whole_opcode = field_value(h, 16, 31);
    736       switch (subtype) {
    737       case 0:
    738          if (whole_opcode == 0x6104 /* PIPELINE_SELECT_965 */)
    739             return 1;
    740          else if (opcode < 2)
    741             return field_value(h, 0, 7) + 2;
    742          else
    743             return -1;
    744       case 1:
    745          if (opcode < 2)
    746             return 1;
    747          else
    748             return -1;
    749       case 2: {
    750          if (opcode == 0)
    751             return field_value(h, 0, 7) + 2;
    752          else if (opcode < 3)
    753             return field_value(h, 0, 15) + 2;
    754          else
    755             return -1;
    756       }
    757       case 3:
    758          if (whole_opcode == 0x780b)
    759             return 1;
    760          else if (opcode < 4)
    761             return field_value(h, 0, 7) + 2;
    762          else
    763             return -1;
    764       }
    765    }
    766    }
    767 
    768    return -1;
    769 }
    770 
    771 static const char *
    772 gen_get_enum_name(struct gen_enum *e, uint64_t value)
    773 {
    774    for (int i = 0; i < e->nvalues; i++) {
    775       if (e->values[i]->value == value) {
    776          return e->values[i]->name;
    777       }
    778    }
    779    return NULL;
    780 }
    781 
    782 static bool
    783 iter_more_fields(const struct gen_field_iterator *iter)
    784 {
    785    return iter->field != NULL && iter->field->next != NULL;
    786 }
    787 
    788 static uint32_t
    789 iter_group_offset_bits(const struct gen_field_iterator *iter,
    790                        uint32_t group_iter)
    791 {
    792    return iter->group->group_offset + (group_iter * iter->group->group_size);
    793 }
    794 
    795 static bool
    796 iter_more_groups(const struct gen_field_iterator *iter)
    797 {
    798    if (iter->group->variable) {
    799       return iter_group_offset_bits(iter, iter->group_iter + 1) <
    800               (gen_group_get_length(iter->group, iter->p) * 32);
    801    } else {
    802       return (iter->group_iter + 1) < iter->group->group_count ||
    803          iter->group->next != NULL;
    804    }
    805 }
    806 
    807 static void
    808 iter_advance_group(struct gen_field_iterator *iter)
    809 {
    810    if (iter->group->variable)
    811       iter->group_iter++;
    812    else {
    813       if ((iter->group_iter + 1) < iter->group->group_count) {
    814          iter->group_iter++;
    815       } else {
    816          iter->group = iter->group->next;
    817          iter->group_iter = 0;
    818       }
    819    }
    820 
    821    iter->field = iter->group->fields;
    822 }
    823 
    824 static bool
    825 iter_advance_field(struct gen_field_iterator *iter)
    826 {
    827    if (iter_more_fields(iter)) {
    828       iter->field = iter->field->next;
    829    } else {
    830       if (!iter_more_groups(iter))
    831          return false;
    832 
    833       iter_advance_group(iter);
    834    }
    835 
    836    if (iter->field->name)
    837       strncpy(iter->name, iter->field->name, sizeof(iter->name));
    838    else
    839       memset(iter->name, 0, sizeof(iter->name));
    840 
    841    int group_member_offset = iter_group_offset_bits(iter, iter->group_iter);
    842 
    843    iter->bit = group_member_offset + iter->field->start;
    844    iter->struct_desc = NULL;
    845 
    846    return true;
    847 }
    848 
    849 static uint64_t
    850 iter_decode_field_raw(struct gen_field_iterator *iter)
    851 {
    852    uint64_t qw = 0;
    853 
    854    int field_start = iter->p_bit + iter->bit;
    855    int field_end = field_start + (iter->field->end - iter->field->start);
    856 
    857    const uint32_t *p = iter->p + (iter->bit / 32);
    858    if ((field_end - field_start) > 32) {
    859       if ((p + 1) < iter->p_end)
    860          qw = ((uint64_t) p[1]) << 32;
    861       qw |= p[0];
    862    } else
    863       qw = p[0];
    864 
    865    qw = field_value(qw, field_start, field_end);
    866 
    867    /* Address & offset types have to be aligned to dwords, their start bit is
    868     * a reminder of the alignment requirement.
    869     */
    870    if (iter->field->type.kind == GEN_TYPE_ADDRESS ||
    871        iter->field->type.kind == GEN_TYPE_OFFSET)
    872       qw <<= field_start % 32;
    873 
    874    return qw;
    875 }
    876 
    877 static void
    878 iter_decode_field(struct gen_field_iterator *iter)
    879 {
    880    union {
    881       uint64_t qw;
    882       float f;
    883    } v;
    884 
    885    if (iter->field->name)
    886       strncpy(iter->name, iter->field->name, sizeof(iter->name));
    887    else
    888       memset(iter->name, 0, sizeof(iter->name));
    889 
    890    memset(&v, 0, sizeof(v));
    891 
    892    iter->raw_value = iter_decode_field_raw(iter);
    893 
    894    const char *enum_name = NULL;
    895 
    896    v.qw = iter->raw_value;
    897    switch (iter->field->type.kind) {
    898    case GEN_TYPE_UNKNOWN:
    899    case GEN_TYPE_INT: {
    900       snprintf(iter->value, sizeof(iter->value), "%"PRId64, v.qw);
    901       enum_name = gen_get_enum_name(&iter->field->inline_enum, v.qw);
    902       break;
    903    }
    904    case GEN_TYPE_UINT: {
    905       snprintf(iter->value, sizeof(iter->value), "%"PRIu64, v.qw);
    906       enum_name = gen_get_enum_name(&iter->field->inline_enum, v.qw);
    907       break;
    908    }
    909    case GEN_TYPE_BOOL: {
    910       const char *true_string =
    911          iter->print_colors ? "\e[0;35mtrue\e[0m" : "true";
    912       snprintf(iter->value, sizeof(iter->value), "%s",
    913                v.qw ? true_string : "false");
    914       break;
    915    }
    916    case GEN_TYPE_FLOAT:
    917       snprintf(iter->value, sizeof(iter->value), "%f", v.f);
    918       break;
    919    case GEN_TYPE_ADDRESS:
    920    case GEN_TYPE_OFFSET:
    921       snprintf(iter->value, sizeof(iter->value), "0x%08"PRIx64, v.qw);
    922       break;
    923    case GEN_TYPE_STRUCT:
    924       snprintf(iter->value, sizeof(iter->value), "<struct %s>",
    925                iter->field->type.gen_struct->name);
    926       iter->struct_desc =
    927          gen_spec_find_struct(iter->group->spec,
    928                               iter->field->type.gen_struct->name);
    929       break;
    930    case GEN_TYPE_UFIXED:
    931       snprintf(iter->value, sizeof(iter->value), "%f",
    932                (float) v.qw / (1 << iter->field->type.f));
    933       break;
    934    case GEN_TYPE_SFIXED:
    935       /* FIXME: Sign extend extracted field. */
    936       snprintf(iter->value, sizeof(iter->value), "%s", "foo");
    937       break;
    938    case GEN_TYPE_MBO:
    939        break;
    940    case GEN_TYPE_ENUM: {
    941       snprintf(iter->value, sizeof(iter->value), "%"PRId64, v.qw);
    942       enum_name = gen_get_enum_name(iter->field->type.gen_enum, v.qw);
    943       break;
    944    }
    945    }
    946 
    947    if (strlen(iter->group->name) == 0) {
    948       int length = strlen(iter->name);
    949       snprintf(iter->name + length, sizeof(iter->name) - length,
    950                "[%i]", iter->group_iter);
    951    }
    952 
    953    if (enum_name) {
    954       int length = strlen(iter->value);
    955       snprintf(iter->value + length, sizeof(iter->value) - length,
    956                " (%s)", enum_name);
    957    }
    958 }
    959 
    960 void
    961 gen_field_iterator_init(struct gen_field_iterator *iter,
    962                         struct gen_group *group,
    963                         const uint32_t *p, int p_bit,
    964                         bool print_colors)
    965 {
    966    memset(iter, 0, sizeof(*iter));
    967 
    968    iter->group = group;
    969    if (group->fields)
    970       iter->field = group->fields;
    971    else
    972       iter->field = group->next->fields;
    973    iter->p = p;
    974    iter->p_bit = p_bit;
    975    iter->p_end = &p[gen_group_get_length(iter->group, iter->p)];
    976    iter->print_colors = print_colors;
    977 
    978    iter_decode_field(iter);
    979 }
    980 
    981 bool
    982 gen_field_iterator_next(struct gen_field_iterator *iter)
    983 {
    984    if (!iter_advance_field(iter))
    985       return false;
    986 
    987    iter_decode_field(iter);
    988 
    989    return true;
    990 }
    991 
    992 static void
    993 print_dword_header(FILE *outfile,
    994                    struct gen_field_iterator *iter,
    995                    uint64_t offset, uint32_t dword)
    996 {
    997    fprintf(outfile, "0x%08"PRIx64":  0x%08x : Dword %d\n",
    998            offset + 4 * dword, iter->p[dword], dword);
    999 }
   1000 
   1001 bool
   1002 gen_field_is_header(struct gen_field *field)
   1003 {
   1004    uint32_t bits;
   1005 
   1006    if (field->start >= 32)
   1007       return false;
   1008 
   1009    bits = (1U << (field->end - field->start + 1)) - 1;
   1010    bits <<= field->start;
   1011 
   1012    return (field->parent->opcode_mask & bits) != 0;
   1013 }
   1014 
   1015 void
   1016 gen_print_group(FILE *outfile, struct gen_group *group, uint64_t offset,
   1017                 const uint32_t *p, int p_bit, bool color)
   1018 {
   1019    struct gen_field_iterator iter;
   1020    int last_dword = -1;
   1021 
   1022    gen_field_iterator_init(&iter, group, p, p_bit, color);
   1023    do {
   1024       int iter_dword = iter.bit / 32;
   1025       if (last_dword != iter_dword) {
   1026          for (int i = last_dword + 1; i <= iter_dword; i++)
   1027             print_dword_header(outfile, &iter, offset, i);
   1028          last_dword = iter_dword;
   1029       }
   1030       if (!gen_field_is_header(iter.field)) {
   1031          fprintf(outfile, "    %s: %s\n", iter.name, iter.value);
   1032          if (iter.struct_desc) {
   1033             uint64_t struct_offset = offset + 4 * iter_dword;
   1034             gen_print_group(outfile, iter.struct_desc, struct_offset,
   1035                             &p[iter_dword], iter.bit % 32, color);
   1036          }
   1037       }
   1038    } while (gen_field_iterator_next(&iter));
   1039 }
   1040