Home | History | Annotate | Download | only in cle
      1 /*
      2  * Copyright  2016 Intel Corporation
      3  * Copyright  2017 Broadcom
      4  *
      5  * Permission is hereby granted, free of charge, to any person obtaining a
      6  * copy of this software and associated documentation files (the "Software"),
      7  * to deal in the Software without restriction, including without limitation
      8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      9  * and/or sell copies of the Software, and to permit persons to whom the
     10  * Software is furnished to do so, subject to the following conditions:
     11  *
     12  * The above copyright notice and this permission notice (including the next
     13  * paragraph) shall be included in all copies or substantial portions of the
     14  * Software.
     15  *
     16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
     22  * IN THE SOFTWARE.
     23  */
     24 
     25 #include <stdio.h>
     26 #include <stdbool.h>
     27 #include <stdint.h>
     28 #include <stdarg.h>
     29 #include <string.h>
     30 #include <expat.h>
     31 #include <inttypes.h>
     32 #include <zlib.h>
     33 
     34 #include <util/macros.h>
     35 #include <util/ralloc.h>
     36 
     37 #include "v3d_decoder.h"
     38 #include "v3d_packet_helpers.h"
     39 #include "v3d_xml.h"
     40 
     41 struct v3d_spec {
     42         uint32_t ver;
     43 
     44         int ncommands;
     45         struct v3d_group *commands[256];
     46         int nstructs;
     47         struct v3d_group *structs[256];
     48         int nregisters;
     49         struct v3d_group *registers[256];
     50         int nenums;
     51         struct v3d_enum *enums[256];
     52 };
     53 
     54 struct location {
     55         const char *filename;
     56         int line_number;
     57 };
     58 
     59 struct parser_context {
     60         XML_Parser parser;
     61         int foo;
     62         struct location loc;
     63 
     64         struct v3d_group *group;
     65         struct v3d_enum *enoom;
     66 
     67         int nvalues;
     68         struct v3d_value *values[256];
     69 
     70         struct v3d_spec *spec;
     71 };
     72 
     73 const char *
     74 v3d_group_get_name(struct v3d_group *group)
     75 {
     76         return group->name;
     77 }
     78 
     79 uint8_t
     80 v3d_group_get_opcode(struct v3d_group *group)
     81 {
     82         return group->opcode;
     83 }
     84 
     85 struct v3d_group *
     86 v3d_spec_find_struct(struct v3d_spec *spec, const char *name)
     87 {
     88         for (int i = 0; i < spec->nstructs; i++)
     89                 if (strcmp(spec->structs[i]->name, name) == 0)
     90                         return spec->structs[i];
     91 
     92         return NULL;
     93 }
     94 
     95 struct v3d_group *
     96 v3d_spec_find_register(struct v3d_spec *spec, uint32_t offset)
     97 {
     98         for (int i = 0; i < spec->nregisters; i++)
     99                 if (spec->registers[i]->register_offset == offset)
    100                         return spec->registers[i];
    101 
    102         return NULL;
    103 }
    104 
    105 struct v3d_group *
    106 v3d_spec_find_register_by_name(struct v3d_spec *spec, const char *name)
    107 {
    108         for (int i = 0; i < spec->nregisters; i++) {
    109                 if (strcmp(spec->registers[i]->name, name) == 0)
    110                         return spec->registers[i];
    111         }
    112 
    113         return NULL;
    114 }
    115 
    116 struct v3d_enum *
    117 v3d_spec_find_enum(struct v3d_spec *spec, const char *name)
    118 {
    119         for (int i = 0; i < spec->nenums; i++)
    120                 if (strcmp(spec->enums[i]->name, name) == 0)
    121                         return spec->enums[i];
    122 
    123         return NULL;
    124 }
    125 
    126 static void __attribute__((noreturn))
    127 fail(struct location *loc, const char *msg, ...)
    128 {
    129         va_list ap;
    130 
    131         va_start(ap, msg);
    132         fprintf(stderr, "%s:%d: error: ",
    133                 loc->filename, loc->line_number);
    134         vfprintf(stderr, msg, ap);
    135         fprintf(stderr, "\n");
    136         va_end(ap);
    137         exit(EXIT_FAILURE);
    138 }
    139 
    140 static void *
    141 fail_on_null(void *p)
    142 {
    143         if (p == NULL) {
    144                 fprintf(stderr, "aubinator: out of memory\n");
    145                 exit(EXIT_FAILURE);
    146         }
    147 
    148         return p;
    149 }
    150 
    151 static char *
    152 xstrdup(const char *s)
    153 {
    154         return fail_on_null(strdup(s));
    155 }
    156 
    157 static void *
    158 zalloc(size_t s)
    159 {
    160         return calloc(s, 1);
    161 }
    162 
    163 static void *
    164 xzalloc(size_t s)
    165 {
    166         return fail_on_null(zalloc(s));
    167 }
    168 
    169 /* We allow fields to have either a bit index, or append "b" for a byte index.
    170  */
    171 static bool
    172 is_byte_offset(const char *value)
    173 {
    174         return value[strlen(value) - 1] == 'b';
    175 }
    176 
    177 static void
    178 get_group_offset_count(const char **atts, uint32_t *offset, uint32_t *count,
    179                        uint32_t *size, bool *variable)
    180 {
    181         char *p;
    182         int i;
    183 
    184         for (i = 0; atts[i]; i += 2) {
    185                 if (strcmp(atts[i], "count") == 0) {
    186                         *count = strtoul(atts[i + 1], &p, 0);
    187                         if (*count == 0)
    188                                 *variable = true;
    189                 } else if (strcmp(atts[i], "start") == 0) {
    190                         *offset = strtoul(atts[i + 1], &p, 0);
    191                 } else if (strcmp(atts[i], "size") == 0) {
    192                         *size = strtoul(atts[i + 1], &p, 0);
    193                 }
    194         }
    195         return;
    196 }
    197 
    198 static struct v3d_group *
    199 create_group(struct parser_context *ctx,
    200              const char *name,
    201              const char **atts,
    202              struct v3d_group *parent)
    203 {
    204         struct v3d_group *group;
    205 
    206         group = xzalloc(sizeof(*group));
    207         if (name)
    208                 group->name = xstrdup(name);
    209 
    210         group->spec = ctx->spec;
    211         group->group_offset = 0;
    212         group->group_count = 0;
    213         group->variable = false;
    214 
    215         if (parent) {
    216                 group->parent = parent;
    217                 get_group_offset_count(atts,
    218                                        &group->group_offset,
    219                                        &group->group_count,
    220                                        &group->group_size,
    221                                        &group->variable);
    222         }
    223 
    224         return group;
    225 }
    226 
    227 static struct v3d_enum *
    228 create_enum(struct parser_context *ctx, const char *name, const char **atts)
    229 {
    230         struct v3d_enum *e;
    231 
    232         e = xzalloc(sizeof(*e));
    233         if (name)
    234                 e->name = xstrdup(name);
    235 
    236         e->nvalues = 0;
    237 
    238         return e;
    239 }
    240 
    241 static void
    242 get_register_offset(const char **atts, uint32_t *offset)
    243 {
    244         char *p;
    245         int i;
    246 
    247         for (i = 0; atts[i]; i += 2) {
    248                 if (strcmp(atts[i], "num") == 0)
    249                         *offset = strtoul(atts[i + 1], &p, 0);
    250         }
    251         return;
    252 }
    253 
    254 static void
    255 get_start_end_pos(int *start, int *end)
    256 {
    257         /* start value has to be mod with 32 as we need the relative
    258          * start position in the first DWord. For the end position, add
    259          * the length of the field to the start position to get the
    260          * relative postion in the 64 bit address.
    261          */
    262         if (*end - *start > 32) {
    263                 int len = *end - *start;
    264                 *start = *start % 32;
    265                 *end = *start + len;
    266         } else {
    267                 *start = *start % 32;
    268                 *end = *end % 32;
    269         }
    270 
    271         return;
    272 }
    273 
    274 static inline uint64_t
    275 mask(int start, int end)
    276 {
    277         uint64_t v;
    278 
    279         v = ~0ULL >> (63 - end + start);
    280 
    281         return v << start;
    282 }
    283 
    284 static inline uint64_t
    285 field(uint64_t value, int start, int end)
    286 {
    287         get_start_end_pos(&start, &end);
    288         return (value & mask(start, end)) >> (start);
    289 }
    290 
    291 static inline uint64_t
    292 field_address(uint64_t value, int start, int end)
    293 {
    294         /* no need to right shift for address/offset */
    295         get_start_end_pos(&start, &end);
    296         return (value & mask(start, end));
    297 }
    298 
    299 static struct v3d_type
    300 string_to_type(struct parser_context *ctx, const char *s)
    301 {
    302         int i, f;
    303         struct v3d_group *g;
    304         struct v3d_enum *e;
    305 
    306         if (strcmp(s, "int") == 0)
    307                 return (struct v3d_type) { .kind = V3D_TYPE_INT };
    308         else if (strcmp(s, "uint") == 0)
    309                 return (struct v3d_type) { .kind = V3D_TYPE_UINT };
    310         else if (strcmp(s, "bool") == 0)
    311                 return (struct v3d_type) { .kind = V3D_TYPE_BOOL };
    312         else if (strcmp(s, "float") == 0)
    313                 return (struct v3d_type) { .kind = V3D_TYPE_FLOAT };
    314         else if (strcmp(s, "address") == 0)
    315                 return (struct v3d_type) { .kind = V3D_TYPE_ADDRESS };
    316         else if (strcmp(s, "offset") == 0)
    317                 return (struct v3d_type) { .kind = V3D_TYPE_OFFSET };
    318         else if (sscanf(s, "u%d.%d", &i, &f) == 2)
    319                 return (struct v3d_type) { .kind = V3D_TYPE_UFIXED, .i = i, .f = f };
    320         else if (sscanf(s, "s%d.%d", &i, &f) == 2)
    321                 return (struct v3d_type) { .kind = V3D_TYPE_SFIXED, .i = i, .f = f };
    322         else if (g = v3d_spec_find_struct(ctx->spec, s), g != NULL)
    323                 return (struct v3d_type) { .kind = V3D_TYPE_STRUCT, .v3d_struct = g };
    324         else if (e = v3d_spec_find_enum(ctx->spec, s), e != NULL)
    325                 return (struct v3d_type) { .kind = V3D_TYPE_ENUM, .v3d_enum = e };
    326         else if (strcmp(s, "mbo") == 0)
    327                 return (struct v3d_type) { .kind = V3D_TYPE_MBO };
    328         else
    329                 fail(&ctx->loc, "invalid type: %s", s);
    330 }
    331 
    332 static struct v3d_field *
    333 create_field(struct parser_context *ctx, const char **atts)
    334 {
    335         struct v3d_field *field;
    336         char *p;
    337         int i;
    338         uint32_t size = 0;
    339 
    340         field = xzalloc(sizeof(*field));
    341 
    342         for (i = 0; atts[i]; i += 2) {
    343                 if (strcmp(atts[i], "name") == 0)
    344                         field->name = xstrdup(atts[i + 1]);
    345                 else if (strcmp(atts[i], "start") == 0) {
    346                         field->start = strtoul(atts[i + 1], &p, 0);
    347                         if (is_byte_offset(atts[i + 1]))
    348                                 field->start *= 8;
    349                 } else if (strcmp(atts[i], "end") == 0) {
    350                         field->end = strtoul(atts[i + 1], &p, 0) - 1;
    351                         if (is_byte_offset(atts[i + 1]))
    352                                 field->end *= 8;
    353                 } else if (strcmp(atts[i], "size") == 0) {
    354                         size = strtoul(atts[i + 1], &p, 0);
    355                         if (is_byte_offset(atts[i + 1]))
    356                                 size *= 8;
    357                 } else if (strcmp(atts[i], "type") == 0)
    358                         field->type = string_to_type(ctx, atts[i + 1]);
    359                 else if (strcmp(atts[i], "default") == 0) {
    360                         field->has_default = true;
    361                         field->default_value = strtoul(atts[i + 1], &p, 0);
    362                 }
    363         }
    364 
    365         if (size)
    366                 field->end = field->start + size - 1;
    367 
    368         return field;
    369 }
    370 
    371 static struct v3d_value *
    372 create_value(struct parser_context *ctx, const char **atts)
    373 {
    374         struct v3d_value *value = xzalloc(sizeof(*value));
    375 
    376         for (int i = 0; atts[i]; i += 2) {
    377                 if (strcmp(atts[i], "name") == 0)
    378                         value->name = xstrdup(atts[i + 1]);
    379                 else if (strcmp(atts[i], "value") == 0)
    380                         value->value = strtoul(atts[i + 1], NULL, 0);
    381         }
    382 
    383         return value;
    384 }
    385 
    386 static void
    387 create_and_append_field(struct parser_context *ctx,
    388                         const char **atts)
    389 {
    390         if (ctx->group->nfields == ctx->group->fields_size) {
    391                 ctx->group->fields_size = MAX2(ctx->group->fields_size * 2, 2);
    392                 ctx->group->fields =
    393                         (struct v3d_field **) realloc(ctx->group->fields,
    394                                                       sizeof(ctx->group->fields[0]) *
    395                                                       ctx->group->fields_size);
    396         }
    397 
    398         ctx->group->fields[ctx->group->nfields++] = create_field(ctx, atts);
    399 }
    400 
    401 static void
    402 set_group_opcode(struct v3d_group *group, const char **atts)
    403 {
    404         char *p;
    405         int i;
    406 
    407         for (i = 0; atts[i]; i += 2) {
    408                 if (strcmp(atts[i], "code") == 0)
    409                         group->opcode = strtoul(atts[i + 1], &p, 0);
    410         }
    411         return;
    412 }
    413 
    414 static void
    415 start_element(void *data, const char *element_name, const char **atts)
    416 {
    417         struct parser_context *ctx = data;
    418         int i;
    419         const char *name = NULL;
    420         const char *ver = NULL;
    421 
    422         ctx->loc.line_number = XML_GetCurrentLineNumber(ctx->parser);
    423 
    424         for (i = 0; atts[i]; i += 2) {
    425                 if (strcmp(atts[i], "name") == 0)
    426                         name = atts[i + 1];
    427                 else if (strcmp(atts[i], "gen") == 0)
    428                         ver = atts[i + 1];
    429         }
    430 
    431         if (strcmp(element_name, "vcxml") == 0) {
    432                 if (ver == NULL)
    433                         fail(&ctx->loc, "no ver given");
    434 
    435                 int major, minor;
    436                 int n = sscanf(ver, "%d.%d", &major, &minor);
    437                 if (n == 0)
    438                         fail(&ctx->loc, "invalid ver given: %s", ver);
    439                 if (n == 1)
    440                         minor = 0;
    441 
    442                 ctx->spec->ver = major * 10 + minor;
    443         } else if (strcmp(element_name, "packet") == 0 ||
    444                    strcmp(element_name, "struct") == 0) {
    445                 ctx->group = create_group(ctx, name, atts, NULL);
    446 
    447                 if (strcmp(element_name, "packet") == 0)
    448                         set_group_opcode(ctx->group, atts);
    449         } else if (strcmp(element_name, "register") == 0) {
    450                 ctx->group = create_group(ctx, name, atts, NULL);
    451                 get_register_offset(atts, &ctx->group->register_offset);
    452         } else if (strcmp(element_name, "group") == 0) {
    453                 struct v3d_group *previous_group = ctx->group;
    454                 while (previous_group->next)
    455                         previous_group = previous_group->next;
    456 
    457                 struct v3d_group *group = create_group(ctx, "", atts,
    458                                                        ctx->group);
    459                 previous_group->next = group;
    460                 ctx->group = group;
    461         } else if (strcmp(element_name, "field") == 0) {
    462                 create_and_append_field(ctx, atts);
    463         } else if (strcmp(element_name, "enum") == 0) {
    464                 ctx->enoom = create_enum(ctx, name, atts);
    465         } else if (strcmp(element_name, "value") == 0) {
    466                 ctx->values[ctx->nvalues++] = create_value(ctx, atts);
    467                 assert(ctx->nvalues < ARRAY_SIZE(ctx->values));
    468         }
    469 
    470 }
    471 
    472 static void
    473 end_element(void *data, const char *name)
    474 {
    475         struct parser_context *ctx = data;
    476         struct v3d_spec *spec = ctx->spec;
    477 
    478         if (strcmp(name, "packet") == 0 ||
    479             strcmp(name, "struct") == 0 ||
    480             strcmp(name, "register") == 0) {
    481                 struct v3d_group *group = ctx->group;
    482 
    483                 ctx->group = ctx->group->parent;
    484 
    485                 if (strcmp(name, "packet") == 0) {
    486                         spec->commands[spec->ncommands++] = group;
    487 
    488                         /* V3D packet XML has the packet contents with offsets
    489                          * starting from the first bit after the opcode, to
    490                          * match the spec.  Shift the fields up now.
    491                          */
    492                         for (int i = 0; i < group->nfields; i++) {
    493                                 group->fields[i]->start += 8;
    494                                 group->fields[i]->end += 8;
    495                         }
    496                 }
    497                 else if (strcmp(name, "struct") == 0)
    498                         spec->structs[spec->nstructs++] = group;
    499                 else if (strcmp(name, "register") == 0)
    500                         spec->registers[spec->nregisters++] = group;
    501 
    502                 assert(spec->ncommands < ARRAY_SIZE(spec->commands));
    503                 assert(spec->nstructs < ARRAY_SIZE(spec->structs));
    504                 assert(spec->nregisters < ARRAY_SIZE(spec->registers));
    505         } else if (strcmp(name, "group") == 0) {
    506                 ctx->group = ctx->group->parent;
    507         } else if (strcmp(name, "field") == 0) {
    508                 assert(ctx->group->nfields > 0);
    509                 struct v3d_field *field = ctx->group->fields[ctx->group->nfields - 1];
    510                 size_t size = ctx->nvalues * sizeof(ctx->values[0]);
    511                 field->inline_enum.values = xzalloc(size);
    512                 field->inline_enum.nvalues = ctx->nvalues;
    513                 memcpy(field->inline_enum.values, ctx->values, size);
    514                 ctx->nvalues = 0;
    515         } else if (strcmp(name, "enum") == 0) {
    516                 struct v3d_enum *e = ctx->enoom;
    517                 size_t size = ctx->nvalues * sizeof(ctx->values[0]);
    518                 e->values = xzalloc(size);
    519                 e->nvalues = ctx->nvalues;
    520                 memcpy(e->values, ctx->values, size);
    521                 ctx->nvalues = 0;
    522                 ctx->enoom = NULL;
    523                 spec->enums[spec->nenums++] = e;
    524         }
    525 }
    526 
    527 static void
    528 character_data(void *data, const XML_Char *s, int len)
    529 {
    530 }
    531 
    532 static uint32_t zlib_inflate(const void *compressed_data,
    533                              uint32_t compressed_len,
    534                              void **out_ptr)
    535 {
    536         struct z_stream_s zstream;
    537         void *out;
    538 
    539         memset(&zstream, 0, sizeof(zstream));
    540 
    541         zstream.next_in = (unsigned char *)compressed_data;
    542         zstream.avail_in = compressed_len;
    543 
    544         if (inflateInit(&zstream) != Z_OK)
    545                 return 0;
    546 
    547         out = malloc(4096);
    548         zstream.next_out = out;
    549         zstream.avail_out = 4096;
    550 
    551         do {
    552                 switch (inflate(&zstream, Z_SYNC_FLUSH)) {
    553                 case Z_STREAM_END:
    554                         goto end;
    555                 case Z_OK:
    556                         break;
    557                 default:
    558                         inflateEnd(&zstream);
    559                         return 0;
    560                 }
    561 
    562                 if (zstream.avail_out)
    563                         break;
    564 
    565                 out = realloc(out, 2*zstream.total_out);
    566                 if (out == NULL) {
    567                         inflateEnd(&zstream);
    568                         return 0;
    569                 }
    570 
    571                 zstream.next_out = (unsigned char *)out + zstream.total_out;
    572                 zstream.avail_out = zstream.total_out;
    573         } while (1);
    574  end:
    575         inflateEnd(&zstream);
    576         *out_ptr = out;
    577         return zstream.total_out;
    578 }
    579 
    580 struct v3d_spec *
    581 v3d_spec_load(const struct v3d_device_info *devinfo)
    582 {
    583         struct parser_context ctx;
    584         void *buf;
    585         uint8_t *text_data = NULL;
    586         uint32_t text_offset = 0, text_length = 0, total_length;
    587 
    588         for (int i = 0; i < ARRAY_SIZE(genxml_files_table); i++) {
    589                 if (genxml_files_table[i].gen_10 == devinfo->ver) {
    590                         text_offset = genxml_files_table[i].offset;
    591                         text_length = genxml_files_table[i].length;
    592                         break;
    593                 }
    594         }
    595 
    596         if (text_length == 0) {
    597                 fprintf(stderr, "unable to find gen (%u) data\n", devinfo->ver);
    598                 return NULL;
    599         }
    600 
    601         memset(&ctx, 0, sizeof ctx);
    602         ctx.parser = XML_ParserCreate(NULL);
    603         XML_SetUserData(ctx.parser, &ctx);
    604         if (ctx.parser == NULL) {
    605                 fprintf(stderr, "failed to create parser\n");
    606                 return NULL;
    607         }
    608 
    609         XML_SetElementHandler(ctx.parser, start_element, end_element);
    610         XML_SetCharacterDataHandler(ctx.parser, character_data);
    611 
    612         ctx.spec = xzalloc(sizeof(*ctx.spec));
    613 
    614         total_length = zlib_inflate(compress_genxmls,
    615                                     sizeof(compress_genxmls),
    616                                     (void **) &text_data);
    617         assert(text_offset + text_length <= total_length);
    618 
    619         buf = XML_GetBuffer(ctx.parser, text_length);
    620         memcpy(buf, &text_data[text_offset], text_length);
    621 
    622         if (XML_ParseBuffer(ctx.parser, text_length, true) == 0) {
    623                 fprintf(stderr,
    624                         "Error parsing XML at line %ld col %ld byte %ld/%u: %s\n",
    625                         XML_GetCurrentLineNumber(ctx.parser),
    626                         XML_GetCurrentColumnNumber(ctx.parser),
    627                         XML_GetCurrentByteIndex(ctx.parser), text_length,
    628                         XML_ErrorString(XML_GetErrorCode(ctx.parser)));
    629                 XML_ParserFree(ctx.parser);
    630                 free(text_data);
    631                 return NULL;
    632         }
    633 
    634         XML_ParserFree(ctx.parser);
    635         free(text_data);
    636 
    637         return ctx.spec;
    638 }
    639 
    640 struct v3d_group *
    641 v3d_spec_find_instruction(struct v3d_spec *spec, const uint8_t *p)
    642 {
    643         uint8_t opcode = *p;
    644 
    645         for (int i = 0; i < spec->ncommands; i++) {
    646                 struct v3d_group *group = spec->commands[i];
    647 
    648                 if (opcode != group->opcode)
    649                         continue;
    650 
    651                 /* If there's a "sub-id" field, make sure that it matches the
    652                  * instruction being decoded.
    653                  */
    654                 struct v3d_field *subid = NULL;
    655                 for (int j = 0; j < group->nfields; j++) {
    656                         struct v3d_field *field = group->fields[j];
    657                         if (strcmp(field->name, "sub-id") == 0) {
    658                                 subid = field;
    659                                 break;
    660                         }
    661                 }
    662 
    663                 if (subid && (__gen_unpack_uint(p, subid->start, subid->end) !=
    664                               subid->default_value)) {
    665                         continue;
    666                 }
    667 
    668                 return group;
    669         }
    670 
    671         return NULL;
    672 }
    673 
    674 /** Returns the size of a V3D packet. */
    675 int
    676 v3d_group_get_length(struct v3d_group *group)
    677 {
    678         int last_bit = 0;
    679         for (int i = 0; i < group->nfields; i++) {
    680                 struct v3d_field *field = group->fields[i];
    681 
    682                 last_bit = MAX2(last_bit, field->end);
    683         }
    684         return last_bit / 8 + 1;
    685 }
    686 
    687 void
    688 v3d_field_iterator_init(struct v3d_field_iterator *iter,
    689                         struct v3d_group *group,
    690                         const uint8_t *p,
    691                         bool print_colors)
    692 {
    693         memset(iter, 0, sizeof(*iter));
    694 
    695         iter->group = group;
    696         iter->p = p;
    697         iter->print_colors = print_colors;
    698 }
    699 
    700 static const char *
    701 v3d_get_enum_name(struct v3d_enum *e, uint64_t value)
    702 {
    703         for (int i = 0; i < e->nvalues; i++) {
    704                 if (e->values[i]->value == value) {
    705                         return e->values[i]->name;
    706                 }
    707         }
    708         return NULL;
    709 }
    710 
    711 static bool
    712 iter_more_fields(const struct v3d_field_iterator *iter)
    713 {
    714         return iter->field_iter < iter->group->nfields;
    715 }
    716 
    717 static uint32_t
    718 iter_group_offset_bits(const struct v3d_field_iterator *iter,
    719                        uint32_t group_iter)
    720 {
    721         return iter->group->group_offset + (group_iter *
    722                                             iter->group->group_size);
    723 }
    724 
    725 static bool
    726 iter_more_groups(const struct v3d_field_iterator *iter)
    727 {
    728         if (iter->group->variable) {
    729                 return iter_group_offset_bits(iter, iter->group_iter + 1) <
    730                         (v3d_group_get_length(iter->group) * 8);
    731         } else {
    732                 return (iter->group_iter + 1) < iter->group->group_count ||
    733                         iter->group->next != NULL;
    734         }
    735 }
    736 
    737 static void
    738 iter_advance_group(struct v3d_field_iterator *iter)
    739 {
    740         if (iter->group->variable)
    741                 iter->group_iter++;
    742         else {
    743                 if ((iter->group_iter + 1) < iter->group->group_count) {
    744                         iter->group_iter++;
    745                 } else {
    746                         iter->group = iter->group->next;
    747                         iter->group_iter = 0;
    748                 }
    749         }
    750 
    751         iter->field_iter = 0;
    752 }
    753 
    754 static bool
    755 iter_advance_field(struct v3d_field_iterator *iter)
    756 {
    757         while (!iter_more_fields(iter)) {
    758                 if (!iter_more_groups(iter))
    759                         return false;
    760 
    761                 iter_advance_group(iter);
    762         }
    763 
    764         iter->field = iter->group->fields[iter->field_iter++];
    765         if (iter->field->name)
    766                 strncpy(iter->name, iter->field->name, sizeof(iter->name));
    767         else
    768                 memset(iter->name, 0, sizeof(iter->name));
    769         iter->offset = iter_group_offset_bits(iter, iter->group_iter) / 8 +
    770                 iter->field->start / 8;
    771         iter->struct_desc = NULL;
    772 
    773         return true;
    774 }
    775 
    776 bool
    777 v3d_field_iterator_next(struct v3d_field_iterator *iter)
    778 {
    779         if (!iter_advance_field(iter))
    780                 return false;
    781 
    782         const char *enum_name = NULL;
    783 
    784         int group_member_offset =
    785                 iter_group_offset_bits(iter, iter->group_iter);
    786         int s = group_member_offset + iter->field->start;
    787         int e = group_member_offset + iter->field->end;
    788 
    789         switch (iter->field->type.kind) {
    790         case V3D_TYPE_UNKNOWN:
    791         case V3D_TYPE_INT: {
    792                 uint32_t value = __gen_unpack_sint(iter->p, s, e);
    793                 snprintf(iter->value, sizeof(iter->value), "%d", value);
    794                 enum_name = v3d_get_enum_name(&iter->field->inline_enum, value);
    795                 break;
    796         }
    797         case V3D_TYPE_UINT: {
    798                 uint32_t value = __gen_unpack_uint(iter->p, s, e);
    799                 snprintf(iter->value, sizeof(iter->value), "%u", value);
    800                 enum_name = v3d_get_enum_name(&iter->field->inline_enum, value);
    801                 break;
    802         }
    803         case V3D_TYPE_BOOL: {
    804                 const char *true_string =
    805                         iter->print_colors ? "\e[0;35mtrue\e[0m" : "true";
    806                 snprintf(iter->value, sizeof(iter->value), "%s",
    807                          __gen_unpack_uint(iter->p, s, e) ?
    808                          true_string : "false");
    809                 break;
    810         }
    811         case V3D_TYPE_FLOAT:
    812                 snprintf(iter->value, sizeof(iter->value), "%f",
    813                          __gen_unpack_float(iter->p, s, e));
    814                 break;
    815         case V3D_TYPE_ADDRESS:
    816         case V3D_TYPE_OFFSET:
    817                 snprintf(iter->value, sizeof(iter->value), "0x%08"PRIx64,
    818                          __gen_unpack_uint(iter->p, s, e) << (31 - (e - s)));
    819                 break;
    820         case V3D_TYPE_STRUCT:
    821                 snprintf(iter->value, sizeof(iter->value), "<struct %s>",
    822                          iter->field->type.v3d_struct->name);
    823                 iter->struct_desc =
    824                         v3d_spec_find_struct(iter->group->spec,
    825                                              iter->field->type.v3d_struct->name);
    826                 break;
    827         case V3D_TYPE_SFIXED:
    828                 snprintf(iter->value, sizeof(iter->value), "%f",
    829                          __gen_unpack_sfixed(iter->p, s, e,
    830                                              iter->field->type.f));
    831                 break;
    832         case V3D_TYPE_UFIXED:
    833                 snprintf(iter->value, sizeof(iter->value), "%f",
    834                          __gen_unpack_ufixed(iter->p, s, e,
    835                                              iter->field->type.f));
    836                 break;
    837         case V3D_TYPE_MBO:
    838                 break;
    839         case V3D_TYPE_ENUM: {
    840                 uint32_t value = __gen_unpack_uint(iter->p, s, e);
    841                 snprintf(iter->value, sizeof(iter->value), "%d", value);
    842                 enum_name = v3d_get_enum_name(iter->field->type.v3d_enum, value);
    843                 break;
    844         }
    845         }
    846 
    847         if (strlen(iter->group->name) == 0) {
    848                 int length = strlen(iter->name);
    849                 snprintf(iter->name + length, sizeof(iter->name) - length,
    850                          "[%i]", iter->group_iter);
    851         }
    852 
    853         if (enum_name) {
    854                 int length = strlen(iter->value);
    855                 snprintf(iter->value + length, sizeof(iter->value) - length,
    856                          " (%s)", enum_name);
    857         }
    858 
    859         return true;
    860 }
    861 
    862 void
    863 v3d_print_group(FILE *outfile, struct v3d_group *group,
    864                 uint64_t offset, const uint8_t *p, bool color)
    865 {
    866         struct v3d_field_iterator iter;
    867 
    868         v3d_field_iterator_init(&iter, group, p, color);
    869         while (v3d_field_iterator_next(&iter)) {
    870                 fprintf(outfile, "    %s: %s\n", iter.name, iter.value);
    871                 if (iter.struct_desc) {
    872                         uint64_t struct_offset = offset + iter.offset;
    873                         v3d_print_group(outfile, iter.struct_desc,
    874                                         struct_offset,
    875                                         &p[iter.offset], color);
    876                 }
    877         }
    878 }
    879