101e04c3fSmrg/*
201e04c3fSmrg * Copyright © 2016 Intel Corporation
301e04c3fSmrg * Copyright © 2017 Broadcom
401e04c3fSmrg *
501e04c3fSmrg * Permission is hereby granted, free of charge, to any person obtaining a
601e04c3fSmrg * copy of this software and associated documentation files (the "Software"),
701e04c3fSmrg * to deal in the Software without restriction, including without limitation
801e04c3fSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
901e04c3fSmrg * and/or sell copies of the Software, and to permit persons to whom the
1001e04c3fSmrg * Software is furnished to do so, subject to the following conditions:
1101e04c3fSmrg *
1201e04c3fSmrg * The above copyright notice and this permission notice (including the next
1301e04c3fSmrg * paragraph) shall be included in all copies or substantial portions of the
1401e04c3fSmrg * Software.
1501e04c3fSmrg *
1601e04c3fSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1701e04c3fSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1801e04c3fSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1901e04c3fSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2001e04c3fSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
2101e04c3fSmrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
2201e04c3fSmrg * IN THE SOFTWARE.
2301e04c3fSmrg */
2401e04c3fSmrg
257ec681f3Smrg#include "v3d_decoder.h"
267ec681f3Smrg
2701e04c3fSmrg#include <stdio.h>
287ec681f3Smrg#include <stdlib.h>
2901e04c3fSmrg#include <stdbool.h>
3001e04c3fSmrg#include <stdint.h>
3101e04c3fSmrg#include <stdarg.h>
3201e04c3fSmrg#include <string.h>
337ec681f3Smrg#ifdef WITH_LIBEXPAT
3401e04c3fSmrg#include <expat.h>
357ec681f3Smrg#endif
3601e04c3fSmrg#include <inttypes.h>
3701e04c3fSmrg#include <zlib.h>
3801e04c3fSmrg
3901e04c3fSmrg#include <util/macros.h>
4001e04c3fSmrg#include <util/ralloc.h>
417ec681f3Smrg#include <util/u_debug.h>
4201e04c3fSmrg
4301e04c3fSmrg#include "v3d_packet_helpers.h"
4401e04c3fSmrg#include "v3d_xml.h"
4501e04c3fSmrg#include "broadcom/clif/clif_private.h"
4601e04c3fSmrg
4701e04c3fSmrgstruct v3d_spec {
4801e04c3fSmrg        uint32_t ver;
4901e04c3fSmrg
5001e04c3fSmrg        int ncommands;
5101e04c3fSmrg        struct v3d_group *commands[256];
5201e04c3fSmrg        int nstructs;
5301e04c3fSmrg        struct v3d_group *structs[256];
5401e04c3fSmrg        int nregisters;
5501e04c3fSmrg        struct v3d_group *registers[256];
5601e04c3fSmrg        int nenums;
5701e04c3fSmrg        struct v3d_enum *enums[256];
5801e04c3fSmrg};
5901e04c3fSmrg
607ec681f3Smrg#ifdef WITH_LIBEXPAT
617ec681f3Smrg
6201e04c3fSmrgstruct location {
6301e04c3fSmrg        const char *filename;
6401e04c3fSmrg        int line_number;
6501e04c3fSmrg};
6601e04c3fSmrg
6701e04c3fSmrgstruct parser_context {
6801e04c3fSmrg        XML_Parser parser;
6901e04c3fSmrg        const struct v3d_device_info *devinfo;
7001e04c3fSmrg        int foo;
7101e04c3fSmrg        struct location loc;
7201e04c3fSmrg
7301e04c3fSmrg        struct v3d_group *group;
7401e04c3fSmrg        struct v3d_enum *enoom;
7501e04c3fSmrg
7601e04c3fSmrg        int nvalues;
7701e04c3fSmrg        struct v3d_value *values[256];
7801e04c3fSmrg
7901e04c3fSmrg        struct v3d_spec *spec;
8001e04c3fSmrg
8101e04c3fSmrg        int parse_depth;
8201e04c3fSmrg        int parse_skip_depth;
8301e04c3fSmrg};
8401e04c3fSmrg
857ec681f3Smrg#endif /* WITH_LIBEXPAT */
867ec681f3Smrg
8701e04c3fSmrgconst char *
8801e04c3fSmrgv3d_group_get_name(struct v3d_group *group)
8901e04c3fSmrg{
9001e04c3fSmrg        return group->name;
9101e04c3fSmrg}
9201e04c3fSmrg
9301e04c3fSmrguint8_t
9401e04c3fSmrgv3d_group_get_opcode(struct v3d_group *group)
9501e04c3fSmrg{
9601e04c3fSmrg        return group->opcode;
9701e04c3fSmrg}
9801e04c3fSmrg
9901e04c3fSmrgstruct v3d_group *
10001e04c3fSmrgv3d_spec_find_struct(struct v3d_spec *spec, const char *name)
10101e04c3fSmrg{
10201e04c3fSmrg        for (int i = 0; i < spec->nstructs; i++)
10301e04c3fSmrg                if (strcmp(spec->structs[i]->name, name) == 0)
10401e04c3fSmrg                        return spec->structs[i];
10501e04c3fSmrg
10601e04c3fSmrg        return NULL;
10701e04c3fSmrg}
10801e04c3fSmrg
10901e04c3fSmrgstruct v3d_group *
11001e04c3fSmrgv3d_spec_find_register(struct v3d_spec *spec, uint32_t offset)
11101e04c3fSmrg{
11201e04c3fSmrg        for (int i = 0; i < spec->nregisters; i++)
11301e04c3fSmrg                if (spec->registers[i]->register_offset == offset)
11401e04c3fSmrg                        return spec->registers[i];
11501e04c3fSmrg
11601e04c3fSmrg        return NULL;
11701e04c3fSmrg}
11801e04c3fSmrg
11901e04c3fSmrgstruct v3d_group *
12001e04c3fSmrgv3d_spec_find_register_by_name(struct v3d_spec *spec, const char *name)
12101e04c3fSmrg{
12201e04c3fSmrg        for (int i = 0; i < spec->nregisters; i++) {
12301e04c3fSmrg                if (strcmp(spec->registers[i]->name, name) == 0)
12401e04c3fSmrg                        return spec->registers[i];
12501e04c3fSmrg        }
12601e04c3fSmrg
12701e04c3fSmrg        return NULL;
12801e04c3fSmrg}
12901e04c3fSmrg
13001e04c3fSmrgstruct v3d_enum *
13101e04c3fSmrgv3d_spec_find_enum(struct v3d_spec *spec, const char *name)
13201e04c3fSmrg{
13301e04c3fSmrg        for (int i = 0; i < spec->nenums; i++)
13401e04c3fSmrg                if (strcmp(spec->enums[i]->name, name) == 0)
13501e04c3fSmrg                        return spec->enums[i];
13601e04c3fSmrg
13701e04c3fSmrg        return NULL;
13801e04c3fSmrg}
13901e04c3fSmrg
1407ec681f3Smrg#ifdef WITH_LIBEXPAT
1417ec681f3Smrg
14201e04c3fSmrgstatic void __attribute__((noreturn))
14301e04c3fSmrgfail(struct location *loc, const char *msg, ...)
14401e04c3fSmrg{
14501e04c3fSmrg        va_list ap;
14601e04c3fSmrg
14701e04c3fSmrg        va_start(ap, msg);
14801e04c3fSmrg        fprintf(stderr, "%s:%d: error: ",
14901e04c3fSmrg                loc->filename, loc->line_number);
15001e04c3fSmrg        vfprintf(stderr, msg, ap);
15101e04c3fSmrg        fprintf(stderr, "\n");
15201e04c3fSmrg        va_end(ap);
15301e04c3fSmrg        exit(EXIT_FAILURE);
15401e04c3fSmrg}
15501e04c3fSmrg
15601e04c3fSmrgstatic void *
15701e04c3fSmrgfail_on_null(void *p)
15801e04c3fSmrg{
15901e04c3fSmrg        if (p == NULL) {
16001e04c3fSmrg                fprintf(stderr, "aubinator: out of memory\n");
16101e04c3fSmrg                exit(EXIT_FAILURE);
16201e04c3fSmrg        }
16301e04c3fSmrg
16401e04c3fSmrg        return p;
16501e04c3fSmrg}
16601e04c3fSmrg
16701e04c3fSmrgstatic char *
16801e04c3fSmrgxstrdup(const char *s)
16901e04c3fSmrg{
17001e04c3fSmrg        return fail_on_null(strdup(s));
17101e04c3fSmrg}
17201e04c3fSmrg
17301e04c3fSmrgstatic void *
17401e04c3fSmrgzalloc(size_t s)
17501e04c3fSmrg{
17601e04c3fSmrg        return calloc(s, 1);
17701e04c3fSmrg}
17801e04c3fSmrg
17901e04c3fSmrgstatic void *
18001e04c3fSmrgxzalloc(size_t s)
18101e04c3fSmrg{
18201e04c3fSmrg        return fail_on_null(zalloc(s));
18301e04c3fSmrg}
18401e04c3fSmrg
18501e04c3fSmrg/* We allow fields to have either a bit index, or append "b" for a byte index.
18601e04c3fSmrg */
18701e04c3fSmrgstatic bool
18801e04c3fSmrgis_byte_offset(const char *value)
18901e04c3fSmrg{
19001e04c3fSmrg        return value[strlen(value) - 1] == 'b';
19101e04c3fSmrg}
19201e04c3fSmrg
19301e04c3fSmrgstatic void
19401e04c3fSmrgget_group_offset_count(const char **atts, uint32_t *offset, uint32_t *count,
19501e04c3fSmrg                       uint32_t *size, bool *variable)
19601e04c3fSmrg{
19701e04c3fSmrg        char *p;
19801e04c3fSmrg        int i;
19901e04c3fSmrg
20001e04c3fSmrg        for (i = 0; atts[i]; i += 2) {
20101e04c3fSmrg                if (strcmp(atts[i], "count") == 0) {
20201e04c3fSmrg                        *count = strtoul(atts[i + 1], &p, 0);
20301e04c3fSmrg                        if (*count == 0)
20401e04c3fSmrg                                *variable = true;
20501e04c3fSmrg                } else if (strcmp(atts[i], "start") == 0) {
20601e04c3fSmrg                        *offset = strtoul(atts[i + 1], &p, 0);
20701e04c3fSmrg                } else if (strcmp(atts[i], "size") == 0) {
20801e04c3fSmrg                        *size = strtoul(atts[i + 1], &p, 0);
20901e04c3fSmrg                }
21001e04c3fSmrg        }
21101e04c3fSmrg        return;
21201e04c3fSmrg}
21301e04c3fSmrg
21401e04c3fSmrgstatic struct v3d_group *
21501e04c3fSmrgcreate_group(struct parser_context *ctx,
21601e04c3fSmrg             const char *name,
21701e04c3fSmrg             const char **atts,
21801e04c3fSmrg             struct v3d_group *parent)
21901e04c3fSmrg{
22001e04c3fSmrg        struct v3d_group *group;
22101e04c3fSmrg
22201e04c3fSmrg        group = xzalloc(sizeof(*group));
22301e04c3fSmrg        if (name)
22401e04c3fSmrg                group->name = xstrdup(name);
22501e04c3fSmrg
22601e04c3fSmrg        group->spec = ctx->spec;
22701e04c3fSmrg        group->group_offset = 0;
22801e04c3fSmrg        group->group_count = 0;
22901e04c3fSmrg        group->variable = false;
23001e04c3fSmrg
23101e04c3fSmrg        if (parent) {
23201e04c3fSmrg                group->parent = parent;
23301e04c3fSmrg                get_group_offset_count(atts,
23401e04c3fSmrg                                       &group->group_offset,
23501e04c3fSmrg                                       &group->group_count,
23601e04c3fSmrg                                       &group->group_size,
23701e04c3fSmrg                                       &group->variable);
23801e04c3fSmrg        }
23901e04c3fSmrg
24001e04c3fSmrg        return group;
24101e04c3fSmrg}
24201e04c3fSmrg
24301e04c3fSmrgstatic struct v3d_enum *
24401e04c3fSmrgcreate_enum(struct parser_context *ctx, const char *name, const char **atts)
24501e04c3fSmrg{
24601e04c3fSmrg        struct v3d_enum *e;
24701e04c3fSmrg
24801e04c3fSmrg        e = xzalloc(sizeof(*e));
24901e04c3fSmrg        if (name)
25001e04c3fSmrg                e->name = xstrdup(name);
25101e04c3fSmrg
25201e04c3fSmrg        e->nvalues = 0;
25301e04c3fSmrg
25401e04c3fSmrg        return e;
25501e04c3fSmrg}
25601e04c3fSmrg
25701e04c3fSmrgstatic void
25801e04c3fSmrgget_register_offset(const char **atts, uint32_t *offset)
25901e04c3fSmrg{
26001e04c3fSmrg        char *p;
26101e04c3fSmrg        int i;
26201e04c3fSmrg
26301e04c3fSmrg        for (i = 0; atts[i]; i += 2) {
26401e04c3fSmrg                if (strcmp(atts[i], "num") == 0)
26501e04c3fSmrg                        *offset = strtoul(atts[i + 1], &p, 0);
26601e04c3fSmrg        }
26701e04c3fSmrg        return;
26801e04c3fSmrg}
26901e04c3fSmrg
27001e04c3fSmrgstatic void
27101e04c3fSmrgget_start_end_pos(int *start, int *end)
27201e04c3fSmrg{
27301e04c3fSmrg        /* start value has to be mod with 32 as we need the relative
27401e04c3fSmrg         * start position in the first DWord. For the end position, add
27501e04c3fSmrg         * the length of the field to the start position to get the
27601e04c3fSmrg         * relative postion in the 64 bit address.
27701e04c3fSmrg         */
27801e04c3fSmrg        if (*end - *start > 32) {
27901e04c3fSmrg                int len = *end - *start;
28001e04c3fSmrg                *start = *start % 32;
28101e04c3fSmrg                *end = *start + len;
28201e04c3fSmrg        } else {
28301e04c3fSmrg                *start = *start % 32;
28401e04c3fSmrg                *end = *end % 32;
28501e04c3fSmrg        }
28601e04c3fSmrg
28701e04c3fSmrg        return;
28801e04c3fSmrg}
28901e04c3fSmrg
29001e04c3fSmrgstatic inline uint64_t
29101e04c3fSmrgmask(int start, int end)
29201e04c3fSmrg{
29301e04c3fSmrg        uint64_t v;
29401e04c3fSmrg
29501e04c3fSmrg        v = ~0ULL >> (63 - end + start);
29601e04c3fSmrg
29701e04c3fSmrg        return v << start;
29801e04c3fSmrg}
29901e04c3fSmrg
30001e04c3fSmrgstatic inline uint64_t
30101e04c3fSmrgfield(uint64_t value, int start, int end)
30201e04c3fSmrg{
30301e04c3fSmrg        get_start_end_pos(&start, &end);
30401e04c3fSmrg        return (value & mask(start, end)) >> (start);
30501e04c3fSmrg}
30601e04c3fSmrg
30701e04c3fSmrgstatic inline uint64_t
30801e04c3fSmrgfield_address(uint64_t value, int start, int end)
30901e04c3fSmrg{
31001e04c3fSmrg        /* no need to right shift for address/offset */
31101e04c3fSmrg        get_start_end_pos(&start, &end);
31201e04c3fSmrg        return (value & mask(start, end));
31301e04c3fSmrg}
31401e04c3fSmrg
31501e04c3fSmrgstatic struct v3d_type
31601e04c3fSmrgstring_to_type(struct parser_context *ctx, const char *s)
31701e04c3fSmrg{
31801e04c3fSmrg        int i, f;
31901e04c3fSmrg        struct v3d_group *g;
32001e04c3fSmrg        struct v3d_enum *e;
32101e04c3fSmrg
32201e04c3fSmrg        if (strcmp(s, "int") == 0)
32301e04c3fSmrg                return (struct v3d_type) { .kind = V3D_TYPE_INT };
32401e04c3fSmrg        else if (strcmp(s, "uint") == 0)
32501e04c3fSmrg                return (struct v3d_type) { .kind = V3D_TYPE_UINT };
32601e04c3fSmrg        else if (strcmp(s, "bool") == 0)
32701e04c3fSmrg                return (struct v3d_type) { .kind = V3D_TYPE_BOOL };
32801e04c3fSmrg        else if (strcmp(s, "float") == 0)
32901e04c3fSmrg                return (struct v3d_type) { .kind = V3D_TYPE_FLOAT };
33001e04c3fSmrg        else if (strcmp(s, "f187") == 0)
33101e04c3fSmrg                return (struct v3d_type) { .kind = V3D_TYPE_F187 };
33201e04c3fSmrg        else if (strcmp(s, "address") == 0)
33301e04c3fSmrg                return (struct v3d_type) { .kind = V3D_TYPE_ADDRESS };
33401e04c3fSmrg        else if (strcmp(s, "offset") == 0)
33501e04c3fSmrg                return (struct v3d_type) { .kind = V3D_TYPE_OFFSET };
33601e04c3fSmrg        else if (sscanf(s, "u%d.%d", &i, &f) == 2)
33701e04c3fSmrg                return (struct v3d_type) { .kind = V3D_TYPE_UFIXED, .i = i, .f = f };
33801e04c3fSmrg        else if (sscanf(s, "s%d.%d", &i, &f) == 2)
33901e04c3fSmrg                return (struct v3d_type) { .kind = V3D_TYPE_SFIXED, .i = i, .f = f };
34001e04c3fSmrg        else if (g = v3d_spec_find_struct(ctx->spec, s), g != NULL)
34101e04c3fSmrg                return (struct v3d_type) { .kind = V3D_TYPE_STRUCT, .v3d_struct = g };
34201e04c3fSmrg        else if (e = v3d_spec_find_enum(ctx->spec, s), e != NULL)
34301e04c3fSmrg                return (struct v3d_type) { .kind = V3D_TYPE_ENUM, .v3d_enum = e };
34401e04c3fSmrg        else if (strcmp(s, "mbo") == 0)
34501e04c3fSmrg                return (struct v3d_type) { .kind = V3D_TYPE_MBO };
34601e04c3fSmrg        else
34701e04c3fSmrg                fail(&ctx->loc, "invalid type: %s", s);
34801e04c3fSmrg}
34901e04c3fSmrg
35001e04c3fSmrgstatic struct v3d_field *
35101e04c3fSmrgcreate_field(struct parser_context *ctx, const char **atts)
35201e04c3fSmrg{
35301e04c3fSmrg        struct v3d_field *field;
35401e04c3fSmrg        char *p;
35501e04c3fSmrg        int i;
35601e04c3fSmrg        uint32_t size = 0;
35701e04c3fSmrg
35801e04c3fSmrg        field = xzalloc(sizeof(*field));
35901e04c3fSmrg
36001e04c3fSmrg        for (i = 0; atts[i]; i += 2) {
36101e04c3fSmrg                if (strcmp(atts[i], "name") == 0)
36201e04c3fSmrg                        field->name = xstrdup(atts[i + 1]);
36301e04c3fSmrg                else if (strcmp(atts[i], "start") == 0) {
36401e04c3fSmrg                        field->start = strtoul(atts[i + 1], &p, 0);
36501e04c3fSmrg                        if (is_byte_offset(atts[i + 1]))
36601e04c3fSmrg                                field->start *= 8;
36701e04c3fSmrg                } else if (strcmp(atts[i], "end") == 0) {
36801e04c3fSmrg                        field->end = strtoul(atts[i + 1], &p, 0) - 1;
36901e04c3fSmrg                        if (is_byte_offset(atts[i + 1]))
37001e04c3fSmrg                                field->end *= 8;
37101e04c3fSmrg                } else if (strcmp(atts[i], "size") == 0) {
37201e04c3fSmrg                        size = strtoul(atts[i + 1], &p, 0);
37301e04c3fSmrg                        if (is_byte_offset(atts[i + 1]))
37401e04c3fSmrg                                size *= 8;
37501e04c3fSmrg                } else if (strcmp(atts[i], "type") == 0)
37601e04c3fSmrg                        field->type = string_to_type(ctx, atts[i + 1]);
37701e04c3fSmrg                else if (strcmp(atts[i], "default") == 0) {
37801e04c3fSmrg                        field->has_default = true;
37901e04c3fSmrg                        field->default_value = strtoul(atts[i + 1], &p, 0);
38001e04c3fSmrg                } else if (strcmp(atts[i], "minus_one") == 0) {
38101e04c3fSmrg                        assert(strcmp(atts[i + 1], "true") == 0);
38201e04c3fSmrg                        field->minus_one = true;
38301e04c3fSmrg                }
38401e04c3fSmrg        }
38501e04c3fSmrg
38601e04c3fSmrg        if (size)
38701e04c3fSmrg                field->end = field->start + size - 1;
38801e04c3fSmrg
38901e04c3fSmrg        return field;
39001e04c3fSmrg}
39101e04c3fSmrg
39201e04c3fSmrgstatic struct v3d_value *
39301e04c3fSmrgcreate_value(struct parser_context *ctx, const char **atts)
39401e04c3fSmrg{
39501e04c3fSmrg        struct v3d_value *value = xzalloc(sizeof(*value));
39601e04c3fSmrg
39701e04c3fSmrg        for (int i = 0; atts[i]; i += 2) {
39801e04c3fSmrg                if (strcmp(atts[i], "name") == 0)
39901e04c3fSmrg                        value->name = xstrdup(atts[i + 1]);
40001e04c3fSmrg                else if (strcmp(atts[i], "value") == 0)
40101e04c3fSmrg                        value->value = strtoul(atts[i + 1], NULL, 0);
40201e04c3fSmrg        }
40301e04c3fSmrg
40401e04c3fSmrg        return value;
40501e04c3fSmrg}
40601e04c3fSmrg
40701e04c3fSmrgstatic void
40801e04c3fSmrgcreate_and_append_field(struct parser_context *ctx,
40901e04c3fSmrg                        const char **atts)
41001e04c3fSmrg{
41101e04c3fSmrg        if (ctx->group->nfields == ctx->group->fields_size) {
41201e04c3fSmrg                ctx->group->fields_size = MAX2(ctx->group->fields_size * 2, 2);
41301e04c3fSmrg                ctx->group->fields =
41401e04c3fSmrg                        (struct v3d_field **) realloc(ctx->group->fields,
41501e04c3fSmrg                                                      sizeof(ctx->group->fields[0]) *
41601e04c3fSmrg                                                      ctx->group->fields_size);
41701e04c3fSmrg        }
41801e04c3fSmrg
41901e04c3fSmrg        ctx->group->fields[ctx->group->nfields++] = create_field(ctx, atts);
42001e04c3fSmrg}
42101e04c3fSmrg
42201e04c3fSmrgstatic void
42301e04c3fSmrgset_group_opcode(struct v3d_group *group, const char **atts)
42401e04c3fSmrg{
42501e04c3fSmrg        char *p;
42601e04c3fSmrg        int i;
42701e04c3fSmrg
42801e04c3fSmrg        for (i = 0; atts[i]; i += 2) {
42901e04c3fSmrg                if (strcmp(atts[i], "code") == 0)
43001e04c3fSmrg                        group->opcode = strtoul(atts[i + 1], &p, 0);
43101e04c3fSmrg        }
43201e04c3fSmrg        return;
43301e04c3fSmrg}
43401e04c3fSmrg
43501e04c3fSmrgstatic bool
43601e04c3fSmrgver_in_range(int ver, int min_ver, int max_ver)
43701e04c3fSmrg{
43801e04c3fSmrg        return ((min_ver == 0 || ver >= min_ver) &&
43901e04c3fSmrg                (max_ver == 0 || ver <= max_ver));
44001e04c3fSmrg}
44101e04c3fSmrg
44201e04c3fSmrgstatic bool
44301e04c3fSmrgskip_if_ver_mismatch(struct parser_context *ctx, int min_ver, int max_ver)
44401e04c3fSmrg{
44501e04c3fSmrg        if (!ctx->parse_skip_depth && !ver_in_range(ctx->devinfo->ver,
44601e04c3fSmrg                                                    min_ver, max_ver)) {
44701e04c3fSmrg                assert(ctx->parse_depth != 0);
44801e04c3fSmrg                ctx->parse_skip_depth = ctx->parse_depth;
44901e04c3fSmrg        }
45001e04c3fSmrg
45101e04c3fSmrg        return ctx->parse_skip_depth;
45201e04c3fSmrg}
45301e04c3fSmrg
45401e04c3fSmrgstatic void
45501e04c3fSmrgstart_element(void *data, const char *element_name, const char **atts)
45601e04c3fSmrg{
45701e04c3fSmrg        struct parser_context *ctx = data;
45801e04c3fSmrg        int i;
45901e04c3fSmrg        const char *name = NULL;
46001e04c3fSmrg        const char *ver = NULL;
46101e04c3fSmrg        int min_ver = 0;
46201e04c3fSmrg        int max_ver = 0;
46301e04c3fSmrg
46401e04c3fSmrg        ctx->loc.line_number = XML_GetCurrentLineNumber(ctx->parser);
46501e04c3fSmrg
46601e04c3fSmrg        for (i = 0; atts[i]; i += 2) {
46701e04c3fSmrg                if (strcmp(atts[i], "shortname") == 0)
46801e04c3fSmrg                        name = atts[i + 1];
46901e04c3fSmrg                else if (strcmp(atts[i], "name") == 0 && !name)
47001e04c3fSmrg                        name = atts[i + 1];
47101e04c3fSmrg                else if (strcmp(atts[i], "gen") == 0)
47201e04c3fSmrg                        ver = atts[i + 1];
47301e04c3fSmrg                else if (strcmp(atts[i], "min_ver") == 0)
47401e04c3fSmrg                        min_ver = strtoul(atts[i + 1], NULL, 0);
47501e04c3fSmrg                else if (strcmp(atts[i], "max_ver") == 0)
47601e04c3fSmrg                        max_ver = strtoul(atts[i + 1], NULL, 0);
47701e04c3fSmrg        }
47801e04c3fSmrg
47901e04c3fSmrg        if (skip_if_ver_mismatch(ctx, min_ver, max_ver))
48001e04c3fSmrg                goto skip;
48101e04c3fSmrg
48201e04c3fSmrg        if (strcmp(element_name, "vcxml") == 0) {
48301e04c3fSmrg                if (ver == NULL)
48401e04c3fSmrg                        fail(&ctx->loc, "no ver given");
48501e04c3fSmrg
48601e04c3fSmrg                /* Make sure that we picked an XML that matched our version.
48701e04c3fSmrg                 */
48801e04c3fSmrg                assert(ver_in_range(ctx->devinfo->ver, min_ver, max_ver));
48901e04c3fSmrg
49001e04c3fSmrg                int major, minor;
49101e04c3fSmrg                int n = sscanf(ver, "%d.%d", &major, &minor);
49201e04c3fSmrg                if (n == 0)
49301e04c3fSmrg                        fail(&ctx->loc, "invalid ver given: %s", ver);
49401e04c3fSmrg                if (n == 1)
49501e04c3fSmrg                        minor = 0;
49601e04c3fSmrg
49701e04c3fSmrg                ctx->spec->ver = major * 10 + minor;
49801e04c3fSmrg        } else if (strcmp(element_name, "packet") == 0 ||
49901e04c3fSmrg                   strcmp(element_name, "struct") == 0) {
50001e04c3fSmrg                ctx->group = create_group(ctx, name, atts, NULL);
50101e04c3fSmrg
50201e04c3fSmrg                if (strcmp(element_name, "packet") == 0)
50301e04c3fSmrg                        set_group_opcode(ctx->group, atts);
50401e04c3fSmrg        } else if (strcmp(element_name, "register") == 0) {
50501e04c3fSmrg                ctx->group = create_group(ctx, name, atts, NULL);
50601e04c3fSmrg                get_register_offset(atts, &ctx->group->register_offset);
50701e04c3fSmrg        } else if (strcmp(element_name, "group") == 0) {
50801e04c3fSmrg                struct v3d_group *previous_group = ctx->group;
50901e04c3fSmrg                while (previous_group->next)
51001e04c3fSmrg                        previous_group = previous_group->next;
51101e04c3fSmrg
51201e04c3fSmrg                struct v3d_group *group = create_group(ctx, "", atts,
51301e04c3fSmrg                                                       ctx->group);
51401e04c3fSmrg                previous_group->next = group;
51501e04c3fSmrg                ctx->group = group;
51601e04c3fSmrg        } else if (strcmp(element_name, "field") == 0) {
51701e04c3fSmrg                create_and_append_field(ctx, atts);
51801e04c3fSmrg        } else if (strcmp(element_name, "enum") == 0) {
51901e04c3fSmrg                ctx->enoom = create_enum(ctx, name, atts);
52001e04c3fSmrg        } else if (strcmp(element_name, "value") == 0) {
52101e04c3fSmrg                ctx->values[ctx->nvalues++] = create_value(ctx, atts);
52201e04c3fSmrg                assert(ctx->nvalues < ARRAY_SIZE(ctx->values));
52301e04c3fSmrg        }
52401e04c3fSmrg
52501e04c3fSmrgskip:
52601e04c3fSmrg        ctx->parse_depth++;
52701e04c3fSmrg}
52801e04c3fSmrg
52901e04c3fSmrgstatic int
53001e04c3fSmrgfield_offset_compare(const void *a, const void *b)
53101e04c3fSmrg{
53201e04c3fSmrg        return ((*(const struct v3d_field **)a)->start -
53301e04c3fSmrg                (*(const struct v3d_field **)b)->start);
53401e04c3fSmrg}
53501e04c3fSmrg
53601e04c3fSmrgstatic void
53701e04c3fSmrgend_element(void *data, const char *name)
53801e04c3fSmrg{
53901e04c3fSmrg        struct parser_context *ctx = data;
54001e04c3fSmrg        struct v3d_spec *spec = ctx->spec;
54101e04c3fSmrg
54201e04c3fSmrg        ctx->parse_depth--;
54301e04c3fSmrg
54401e04c3fSmrg        if (ctx->parse_skip_depth) {
54501e04c3fSmrg                if (ctx->parse_skip_depth == ctx->parse_depth)
54601e04c3fSmrg                        ctx->parse_skip_depth = 0;
54701e04c3fSmrg                return;
54801e04c3fSmrg        }
54901e04c3fSmrg
55001e04c3fSmrg        if (strcmp(name, "packet") == 0 ||
55101e04c3fSmrg            strcmp(name, "struct") == 0 ||
55201e04c3fSmrg            strcmp(name, "register") == 0) {
55301e04c3fSmrg                struct v3d_group *group = ctx->group;
55401e04c3fSmrg
55501e04c3fSmrg                ctx->group = ctx->group->parent;
55601e04c3fSmrg
55701e04c3fSmrg                if (strcmp(name, "packet") == 0) {
55801e04c3fSmrg                        spec->commands[spec->ncommands++] = group;
55901e04c3fSmrg
56001e04c3fSmrg                        /* V3D packet XML has the packet contents with offsets
56101e04c3fSmrg                         * starting from the first bit after the opcode, to
56201e04c3fSmrg                         * match the spec.  Shift the fields up now.
56301e04c3fSmrg                         */
56401e04c3fSmrg                        for (int i = 0; i < group->nfields; i++) {
56501e04c3fSmrg                                group->fields[i]->start += 8;
56601e04c3fSmrg                                group->fields[i]->end += 8;
56701e04c3fSmrg                        }
56801e04c3fSmrg                }
56901e04c3fSmrg                else if (strcmp(name, "struct") == 0)
57001e04c3fSmrg                        spec->structs[spec->nstructs++] = group;
57101e04c3fSmrg                else if (strcmp(name, "register") == 0)
57201e04c3fSmrg                        spec->registers[spec->nregisters++] = group;
57301e04c3fSmrg
57401e04c3fSmrg                /* Sort the fields in increasing offset order.  The XML might
57501e04c3fSmrg                 * be specified in any order, but we'll want to iterate from
57601e04c3fSmrg                 * the bottom.
57701e04c3fSmrg                 */
57801e04c3fSmrg                qsort(group->fields, group->nfields, sizeof(*group->fields),
57901e04c3fSmrg                      field_offset_compare);
58001e04c3fSmrg
58101e04c3fSmrg                assert(spec->ncommands < ARRAY_SIZE(spec->commands));
58201e04c3fSmrg                assert(spec->nstructs < ARRAY_SIZE(spec->structs));
58301e04c3fSmrg                assert(spec->nregisters < ARRAY_SIZE(spec->registers));
58401e04c3fSmrg        } else if (strcmp(name, "group") == 0) {
58501e04c3fSmrg                ctx->group = ctx->group->parent;
58601e04c3fSmrg        } else if (strcmp(name, "field") == 0) {
58701e04c3fSmrg                assert(ctx->group->nfields > 0);
58801e04c3fSmrg                struct v3d_field *field = ctx->group->fields[ctx->group->nfields - 1];
58901e04c3fSmrg                size_t size = ctx->nvalues * sizeof(ctx->values[0]);
59001e04c3fSmrg                field->inline_enum.values = xzalloc(size);
59101e04c3fSmrg                field->inline_enum.nvalues = ctx->nvalues;
59201e04c3fSmrg                memcpy(field->inline_enum.values, ctx->values, size);
59301e04c3fSmrg                ctx->nvalues = 0;
59401e04c3fSmrg        } else if (strcmp(name, "enum") == 0) {
59501e04c3fSmrg                struct v3d_enum *e = ctx->enoom;
59601e04c3fSmrg                size_t size = ctx->nvalues * sizeof(ctx->values[0]);
59701e04c3fSmrg                e->values = xzalloc(size);
59801e04c3fSmrg                e->nvalues = ctx->nvalues;
59901e04c3fSmrg                memcpy(e->values, ctx->values, size);
60001e04c3fSmrg                ctx->nvalues = 0;
60101e04c3fSmrg                ctx->enoom = NULL;
60201e04c3fSmrg                spec->enums[spec->nenums++] = e;
60301e04c3fSmrg        }
60401e04c3fSmrg}
60501e04c3fSmrg
60601e04c3fSmrgstatic void
60701e04c3fSmrgcharacter_data(void *data, const XML_Char *s, int len)
60801e04c3fSmrg{
60901e04c3fSmrg}
61001e04c3fSmrg
61101e04c3fSmrgstatic uint32_t zlib_inflate(const void *compressed_data,
61201e04c3fSmrg                             uint32_t compressed_len,
61301e04c3fSmrg                             void **out_ptr)
61401e04c3fSmrg{
61501e04c3fSmrg        struct z_stream_s zstream;
61601e04c3fSmrg        void *out;
61701e04c3fSmrg
61801e04c3fSmrg        memset(&zstream, 0, sizeof(zstream));
61901e04c3fSmrg
62001e04c3fSmrg        zstream.next_in = (unsigned char *)compressed_data;
62101e04c3fSmrg        zstream.avail_in = compressed_len;
62201e04c3fSmrg
62301e04c3fSmrg        if (inflateInit(&zstream) != Z_OK)
62401e04c3fSmrg                return 0;
62501e04c3fSmrg
62601e04c3fSmrg        out = malloc(4096);
62701e04c3fSmrg        zstream.next_out = out;
62801e04c3fSmrg        zstream.avail_out = 4096;
62901e04c3fSmrg
63001e04c3fSmrg        do {
63101e04c3fSmrg                switch (inflate(&zstream, Z_SYNC_FLUSH)) {
63201e04c3fSmrg                case Z_STREAM_END:
63301e04c3fSmrg                        goto end;
63401e04c3fSmrg                case Z_OK:
63501e04c3fSmrg                        break;
63601e04c3fSmrg                default:
63701e04c3fSmrg                        inflateEnd(&zstream);
63801e04c3fSmrg                        return 0;
63901e04c3fSmrg                }
64001e04c3fSmrg
64101e04c3fSmrg                if (zstream.avail_out)
64201e04c3fSmrg                        break;
64301e04c3fSmrg
64401e04c3fSmrg                out = realloc(out, 2*zstream.total_out);
64501e04c3fSmrg                if (out == NULL) {
64601e04c3fSmrg                        inflateEnd(&zstream);
64701e04c3fSmrg                        return 0;
64801e04c3fSmrg                }
64901e04c3fSmrg
65001e04c3fSmrg                zstream.next_out = (unsigned char *)out + zstream.total_out;
65101e04c3fSmrg                zstream.avail_out = zstream.total_out;
65201e04c3fSmrg        } while (1);
65301e04c3fSmrg end:
65401e04c3fSmrg        inflateEnd(&zstream);
65501e04c3fSmrg        *out_ptr = out;
65601e04c3fSmrg        return zstream.total_out;
65701e04c3fSmrg}
65801e04c3fSmrg
6597ec681f3Smrg#endif /* WITH_LIBEXPAT */
6607ec681f3Smrg
66101e04c3fSmrgstruct v3d_spec *
66201e04c3fSmrgv3d_spec_load(const struct v3d_device_info *devinfo)
66301e04c3fSmrg{
6647ec681f3Smrg        struct v3d_spec *spec = calloc(1, sizeof(struct v3d_spec));
6657ec681f3Smrg        if (!spec)
6667ec681f3Smrg                return NULL;
6677ec681f3Smrg
6687ec681f3Smrg#ifdef WITH_LIBEXPAT
66901e04c3fSmrg        struct parser_context ctx;
67001e04c3fSmrg        void *buf;
67101e04c3fSmrg        uint8_t *text_data = NULL;
672ed98bd31Smaya        uint32_t text_offset = 0, text_length = 0;
6737ec681f3Smrg        ASSERTED uint32_t total_length;
67401e04c3fSmrg
67501e04c3fSmrg        for (int i = 0; i < ARRAY_SIZE(genxml_files_table); i++) {
67601e04c3fSmrg                if (i != 0) {
6777ec681f3Smrg                        assert(genxml_files_table[i - 1].ver_10 <
6787ec681f3Smrg                               genxml_files_table[i].ver_10);
67901e04c3fSmrg                }
68001e04c3fSmrg
6817ec681f3Smrg                if (genxml_files_table[i].ver_10 <= devinfo->ver) {
68201e04c3fSmrg                        text_offset = genxml_files_table[i].offset;
68301e04c3fSmrg                        text_length = genxml_files_table[i].length;
68401e04c3fSmrg                }
68501e04c3fSmrg        }
68601e04c3fSmrg
68701e04c3fSmrg        if (text_length == 0) {
68801e04c3fSmrg                fprintf(stderr, "unable to find gen (%u) data\n", devinfo->ver);
6897ec681f3Smrg                free(spec);
69001e04c3fSmrg                return NULL;
69101e04c3fSmrg        }
69201e04c3fSmrg
69301e04c3fSmrg        memset(&ctx, 0, sizeof ctx);
69401e04c3fSmrg        ctx.parser = XML_ParserCreate(NULL);
69501e04c3fSmrg        ctx.devinfo = devinfo;
69601e04c3fSmrg        XML_SetUserData(ctx.parser, &ctx);
69701e04c3fSmrg        if (ctx.parser == NULL) {
69801e04c3fSmrg                fprintf(stderr, "failed to create parser\n");
6997ec681f3Smrg                free(spec);
70001e04c3fSmrg                return NULL;
70101e04c3fSmrg        }
70201e04c3fSmrg
70301e04c3fSmrg        XML_SetElementHandler(ctx.parser, start_element, end_element);
70401e04c3fSmrg        XML_SetCharacterDataHandler(ctx.parser, character_data);
70501e04c3fSmrg
7067ec681f3Smrg        ctx.spec = spec;
70701e04c3fSmrg
70801e04c3fSmrg        total_length = zlib_inflate(compress_genxmls,
70901e04c3fSmrg                                    sizeof(compress_genxmls),
71001e04c3fSmrg                                    (void **) &text_data);
71101e04c3fSmrg        assert(text_offset + text_length <= total_length);
71201e04c3fSmrg
71301e04c3fSmrg        buf = XML_GetBuffer(ctx.parser, text_length);
71401e04c3fSmrg        memcpy(buf, &text_data[text_offset], text_length);
71501e04c3fSmrg
71601e04c3fSmrg        if (XML_ParseBuffer(ctx.parser, text_length, true) == 0) {
71701e04c3fSmrg                fprintf(stderr,
71801e04c3fSmrg                        "Error parsing XML at line %ld col %ld byte %ld/%u: %s\n",
71901e04c3fSmrg                        XML_GetCurrentLineNumber(ctx.parser),
72001e04c3fSmrg                        XML_GetCurrentColumnNumber(ctx.parser),
72101e04c3fSmrg                        XML_GetCurrentByteIndex(ctx.parser), text_length,
72201e04c3fSmrg                        XML_ErrorString(XML_GetErrorCode(ctx.parser)));
72301e04c3fSmrg                XML_ParserFree(ctx.parser);
72401e04c3fSmrg                free(text_data);
7257ec681f3Smrg                free(spec);
72601e04c3fSmrg                return NULL;
72701e04c3fSmrg        }
72801e04c3fSmrg
72901e04c3fSmrg        XML_ParserFree(ctx.parser);
73001e04c3fSmrg        free(text_data);
73101e04c3fSmrg
73201e04c3fSmrg        return ctx.spec;
7337ec681f3Smrg#else /* !WITH_LIBEXPAT */
7347ec681f3Smrg        debug_warn_once("CLIF dumping not supported due to missing libexpat");
7357ec681f3Smrg        return spec;
7367ec681f3Smrg#endif /* !WITH_LIBEXPAT */
73701e04c3fSmrg}
73801e04c3fSmrg
73901e04c3fSmrgstruct v3d_group *
74001e04c3fSmrgv3d_spec_find_instruction(struct v3d_spec *spec, const uint8_t *p)
74101e04c3fSmrg{
74201e04c3fSmrg        uint8_t opcode = *p;
74301e04c3fSmrg
74401e04c3fSmrg        for (int i = 0; i < spec->ncommands; i++) {
74501e04c3fSmrg                struct v3d_group *group = spec->commands[i];
74601e04c3fSmrg
74701e04c3fSmrg                if (opcode != group->opcode)
74801e04c3fSmrg                        continue;
74901e04c3fSmrg
75001e04c3fSmrg                /* If there's a "sub-id" field, make sure that it matches the
75101e04c3fSmrg                 * instruction being decoded.
75201e04c3fSmrg                 */
75301e04c3fSmrg                struct v3d_field *subid = NULL;
75401e04c3fSmrg                for (int j = 0; j < group->nfields; j++) {
75501e04c3fSmrg                        struct v3d_field *field = group->fields[j];
75601e04c3fSmrg                        if (strcmp(field->name, "sub-id") == 0) {
75701e04c3fSmrg                                subid = field;
75801e04c3fSmrg                                break;
75901e04c3fSmrg                        }
76001e04c3fSmrg                }
76101e04c3fSmrg
76201e04c3fSmrg                if (subid && (__gen_unpack_uint(p, subid->start, subid->end) !=
76301e04c3fSmrg                              subid->default_value)) {
76401e04c3fSmrg                        continue;
76501e04c3fSmrg                }
76601e04c3fSmrg
76701e04c3fSmrg                return group;
76801e04c3fSmrg        }
76901e04c3fSmrg
77001e04c3fSmrg        return NULL;
77101e04c3fSmrg}
77201e04c3fSmrg
77301e04c3fSmrg/** Returns the size of a V3D packet. */
77401e04c3fSmrgint
77501e04c3fSmrgv3d_group_get_length(struct v3d_group *group)
77601e04c3fSmrg{
77701e04c3fSmrg        int last_bit = 0;
77801e04c3fSmrg        for (int i = 0; i < group->nfields; i++) {
77901e04c3fSmrg                struct v3d_field *field = group->fields[i];
78001e04c3fSmrg
78101e04c3fSmrg                last_bit = MAX2(last_bit, field->end);
78201e04c3fSmrg        }
78301e04c3fSmrg        return last_bit / 8 + 1;
78401e04c3fSmrg}
78501e04c3fSmrg
78601e04c3fSmrgvoid
78701e04c3fSmrgv3d_field_iterator_init(struct v3d_field_iterator *iter,
78801e04c3fSmrg                        struct v3d_group *group,
78901e04c3fSmrg                        const uint8_t *p)
79001e04c3fSmrg{
79101e04c3fSmrg        memset(iter, 0, sizeof(*iter));
79201e04c3fSmrg
79301e04c3fSmrg        iter->group = group;
79401e04c3fSmrg        iter->p = p;
79501e04c3fSmrg}
79601e04c3fSmrg
79701e04c3fSmrgstatic const char *
79801e04c3fSmrgv3d_get_enum_name(struct v3d_enum *e, uint64_t value)
79901e04c3fSmrg{
80001e04c3fSmrg        for (int i = 0; i < e->nvalues; i++) {
80101e04c3fSmrg                if (e->values[i]->value == value) {
80201e04c3fSmrg                        return e->values[i]->name;
80301e04c3fSmrg                }
80401e04c3fSmrg        }
80501e04c3fSmrg        return NULL;
80601e04c3fSmrg}
80701e04c3fSmrg
80801e04c3fSmrgstatic bool
80901e04c3fSmrgiter_more_fields(const struct v3d_field_iterator *iter)
81001e04c3fSmrg{
81101e04c3fSmrg        return iter->field_iter < iter->group->nfields;
81201e04c3fSmrg}
81301e04c3fSmrg
81401e04c3fSmrgstatic uint32_t
81501e04c3fSmrgiter_group_offset_bits(const struct v3d_field_iterator *iter,
81601e04c3fSmrg                       uint32_t group_iter)
81701e04c3fSmrg{
81801e04c3fSmrg        return iter->group->group_offset + (group_iter *
81901e04c3fSmrg                                            iter->group->group_size);
82001e04c3fSmrg}
82101e04c3fSmrg
82201e04c3fSmrgstatic bool
82301e04c3fSmrgiter_more_groups(const struct v3d_field_iterator *iter)
82401e04c3fSmrg{
82501e04c3fSmrg        if (iter->group->variable) {
82601e04c3fSmrg                return iter_group_offset_bits(iter, iter->group_iter + 1) <
82701e04c3fSmrg                        (v3d_group_get_length(iter->group) * 8);
82801e04c3fSmrg        } else {
82901e04c3fSmrg                return (iter->group_iter + 1) < iter->group->group_count ||
83001e04c3fSmrg                        iter->group->next != NULL;
83101e04c3fSmrg        }
83201e04c3fSmrg}
83301e04c3fSmrg
83401e04c3fSmrgstatic void
83501e04c3fSmrgiter_advance_group(struct v3d_field_iterator *iter)
83601e04c3fSmrg{
83701e04c3fSmrg        if (iter->group->variable)
83801e04c3fSmrg                iter->group_iter++;
83901e04c3fSmrg        else {
84001e04c3fSmrg                if ((iter->group_iter + 1) < iter->group->group_count) {
84101e04c3fSmrg                        iter->group_iter++;
84201e04c3fSmrg                } else {
84301e04c3fSmrg                        iter->group = iter->group->next;
84401e04c3fSmrg                        iter->group_iter = 0;
84501e04c3fSmrg                }
84601e04c3fSmrg        }
84701e04c3fSmrg
84801e04c3fSmrg        iter->field_iter = 0;
84901e04c3fSmrg}
85001e04c3fSmrg
85101e04c3fSmrgstatic bool
85201e04c3fSmrgiter_advance_field(struct v3d_field_iterator *iter)
85301e04c3fSmrg{
85401e04c3fSmrg        while (!iter_more_fields(iter)) {
85501e04c3fSmrg                if (!iter_more_groups(iter))
85601e04c3fSmrg                        return false;
85701e04c3fSmrg
85801e04c3fSmrg                iter_advance_group(iter);
85901e04c3fSmrg        }
86001e04c3fSmrg
86101e04c3fSmrg        iter->field = iter->group->fields[iter->field_iter++];
86201e04c3fSmrg        if (iter->field->name)
86301e04c3fSmrg                snprintf(iter->name, sizeof(iter->name), "%s", iter->field->name);
86401e04c3fSmrg        else
86501e04c3fSmrg                memset(iter->name, 0, sizeof(iter->name));
86601e04c3fSmrg        iter->offset = iter_group_offset_bits(iter, iter->group_iter) / 8 +
86701e04c3fSmrg                iter->field->start / 8;
86801e04c3fSmrg        iter->struct_desc = NULL;
86901e04c3fSmrg
87001e04c3fSmrg        return true;
87101e04c3fSmrg}
87201e04c3fSmrg
87301e04c3fSmrgbool
87401e04c3fSmrgv3d_field_iterator_next(struct clif_dump *clif, struct v3d_field_iterator *iter)
87501e04c3fSmrg{
87601e04c3fSmrg        if (!iter_advance_field(iter))
87701e04c3fSmrg                return false;
87801e04c3fSmrg
87901e04c3fSmrg        const char *enum_name = NULL;
88001e04c3fSmrg
88101e04c3fSmrg        int group_member_offset =
88201e04c3fSmrg                iter_group_offset_bits(iter, iter->group_iter);
88301e04c3fSmrg        int s = group_member_offset + iter->field->start;
88401e04c3fSmrg        int e = group_member_offset + iter->field->end;
88501e04c3fSmrg
88601e04c3fSmrg        assert(!iter->field->minus_one ||
88701e04c3fSmrg               iter->field->type.kind == V3D_TYPE_INT ||
88801e04c3fSmrg               iter->field->type.kind == V3D_TYPE_UINT);
88901e04c3fSmrg
89001e04c3fSmrg        switch (iter->field->type.kind) {
89101e04c3fSmrg        case V3D_TYPE_UNKNOWN:
89201e04c3fSmrg        case V3D_TYPE_INT: {
89301e04c3fSmrg                uint32_t value = __gen_unpack_sint(iter->p, s, e);
89401e04c3fSmrg                if (iter->field->minus_one)
89501e04c3fSmrg                        value++;
89601e04c3fSmrg                snprintf(iter->value, sizeof(iter->value), "%d", value);
89701e04c3fSmrg                enum_name = v3d_get_enum_name(&iter->field->inline_enum, value);
89801e04c3fSmrg                break;
89901e04c3fSmrg        }
90001e04c3fSmrg        case V3D_TYPE_UINT: {
90101e04c3fSmrg                uint32_t value = __gen_unpack_uint(iter->p, s, e);
90201e04c3fSmrg                if (iter->field->minus_one)
90301e04c3fSmrg                        value++;
90401e04c3fSmrg                if (strcmp(iter->field->name, "Vec size") == 0 && value == 0)
9057ec681f3Smrg                        value = 1 << (e - s + 1);
90601e04c3fSmrg                snprintf(iter->value, sizeof(iter->value), "%u", value);
90701e04c3fSmrg                enum_name = v3d_get_enum_name(&iter->field->inline_enum, value);
90801e04c3fSmrg                break;
90901e04c3fSmrg        }
91001e04c3fSmrg        case V3D_TYPE_BOOL:
91101e04c3fSmrg                snprintf(iter->value, sizeof(iter->value), "%s",
91201e04c3fSmrg                         __gen_unpack_uint(iter->p, s, e) ?
91301e04c3fSmrg                         "1 /* true */" : "0 /* false */");
91401e04c3fSmrg                break;
91501e04c3fSmrg        case V3D_TYPE_FLOAT:
91601e04c3fSmrg                snprintf(iter->value, sizeof(iter->value), "%f",
91701e04c3fSmrg                         __gen_unpack_float(iter->p, s, e));
91801e04c3fSmrg                break;
91901e04c3fSmrg
92001e04c3fSmrg        case V3D_TYPE_F187:
92101e04c3fSmrg                snprintf(iter->value, sizeof(iter->value), "%f",
92201e04c3fSmrg                         __gen_unpack_f187(iter->p, s, e));
92301e04c3fSmrg                break;
92401e04c3fSmrg
92501e04c3fSmrg        case V3D_TYPE_ADDRESS: {
92601e04c3fSmrg                uint32_t addr =
92701e04c3fSmrg                        __gen_unpack_uint(iter->p, s, e) << (31 - (e - s));
92801e04c3fSmrg                struct clif_bo *bo = clif_lookup_bo(clif, addr);
92901e04c3fSmrg                if (bo) {
93001e04c3fSmrg                        snprintf(iter->value, sizeof(iter->value),
93101e04c3fSmrg                                 "[%s+0x%08x] /* 0x%08x */",
93201e04c3fSmrg                                 bo->name, addr - bo->offset, addr);
93301e04c3fSmrg                } else if (addr) {
93401e04c3fSmrg                        snprintf(iter->value, sizeof(iter->value),
93501e04c3fSmrg                                 "/* XXX: BO unknown */ 0x%08x", addr);
93601e04c3fSmrg                } else {
93701e04c3fSmrg                        snprintf(iter->value, sizeof(iter->value),
93801e04c3fSmrg                                 "[null]");
93901e04c3fSmrg                }
94001e04c3fSmrg
94101e04c3fSmrg                break;
94201e04c3fSmrg        }
94301e04c3fSmrg
94401e04c3fSmrg        case V3D_TYPE_OFFSET:
94501e04c3fSmrg                snprintf(iter->value, sizeof(iter->value), "0x%08"PRIx64,
94601e04c3fSmrg                         __gen_unpack_uint(iter->p, s, e) << (31 - (e - s)));
94701e04c3fSmrg                break;
94801e04c3fSmrg        case V3D_TYPE_STRUCT:
94901e04c3fSmrg                snprintf(iter->value, sizeof(iter->value), "<struct %s>",
95001e04c3fSmrg                         iter->field->type.v3d_struct->name);
95101e04c3fSmrg                iter->struct_desc =
95201e04c3fSmrg                        v3d_spec_find_struct(iter->group->spec,
95301e04c3fSmrg                                             iter->field->type.v3d_struct->name);
95401e04c3fSmrg                break;
95501e04c3fSmrg        case V3D_TYPE_SFIXED:
95601e04c3fSmrg                if (clif->pretty) {
95701e04c3fSmrg                        snprintf(iter->value, sizeof(iter->value), "%f",
95801e04c3fSmrg                                 __gen_unpack_sfixed(iter->p, s, e,
95901e04c3fSmrg                                                     iter->field->type.f));
96001e04c3fSmrg                } else {
96101e04c3fSmrg                        snprintf(iter->value, sizeof(iter->value), "%u",
96201e04c3fSmrg                                 (unsigned)__gen_unpack_uint(iter->p, s, e));
96301e04c3fSmrg                }
96401e04c3fSmrg                break;
96501e04c3fSmrg        case V3D_TYPE_UFIXED:
96601e04c3fSmrg                if (clif->pretty) {
96701e04c3fSmrg                        snprintf(iter->value, sizeof(iter->value), "%f",
96801e04c3fSmrg                                 __gen_unpack_ufixed(iter->p, s, e,
96901e04c3fSmrg                                                     iter->field->type.f));
97001e04c3fSmrg                } else {
97101e04c3fSmrg                        snprintf(iter->value, sizeof(iter->value), "%u",
97201e04c3fSmrg                                 (unsigned)__gen_unpack_uint(iter->p, s, e));
97301e04c3fSmrg                }
97401e04c3fSmrg                break;
97501e04c3fSmrg        case V3D_TYPE_MBO:
97601e04c3fSmrg                break;
97701e04c3fSmrg        case V3D_TYPE_ENUM: {
97801e04c3fSmrg                uint32_t value = __gen_unpack_uint(iter->p, s, e);
97901e04c3fSmrg                snprintf(iter->value, sizeof(iter->value), "%d", value);
98001e04c3fSmrg                enum_name = v3d_get_enum_name(iter->field->type.v3d_enum, value);
98101e04c3fSmrg                break;
98201e04c3fSmrg        }
98301e04c3fSmrg        }
98401e04c3fSmrg
98501e04c3fSmrg        if (strlen(iter->group->name) == 0) {
98601e04c3fSmrg                int length = strlen(iter->name);
98701e04c3fSmrg                snprintf(iter->name + length, sizeof(iter->name) - length,
98801e04c3fSmrg                         "[%i]", iter->group_iter);
98901e04c3fSmrg        }
99001e04c3fSmrg
99101e04c3fSmrg        if (enum_name) {
99201e04c3fSmrg                int length = strlen(iter->value);
99301e04c3fSmrg                snprintf(iter->value + length, sizeof(iter->value) - length,
99401e04c3fSmrg                         " /* %s */", enum_name);
99501e04c3fSmrg        }
99601e04c3fSmrg
99701e04c3fSmrg        return true;
99801e04c3fSmrg}
99901e04c3fSmrg
100001e04c3fSmrgvoid
100101e04c3fSmrgv3d_print_group(struct clif_dump *clif, struct v3d_group *group,
100201e04c3fSmrg                uint64_t offset, const uint8_t *p)
100301e04c3fSmrg{
100401e04c3fSmrg        struct v3d_field_iterator iter;
100501e04c3fSmrg
100601e04c3fSmrg        v3d_field_iterator_init(&iter, group, p);
100701e04c3fSmrg        while (v3d_field_iterator_next(clif, &iter)) {
100801e04c3fSmrg                /* Clif parsing uses the packet name, and expects no
100901e04c3fSmrg                 * sub-id.
101001e04c3fSmrg                 */
101101e04c3fSmrg                if (strcmp(iter.field->name, "sub-id") == 0 ||
101201e04c3fSmrg                    strcmp(iter.field->name, "unused") == 0 ||
101301e04c3fSmrg                    strcmp(iter.field->name, "Pad") == 0)
101401e04c3fSmrg                        continue;
101501e04c3fSmrg
101601e04c3fSmrg                if (clif->pretty) {
101701e04c3fSmrg                        fprintf(clif->out, "    %s: %s\n",
101801e04c3fSmrg                                iter.name, iter.value);
101901e04c3fSmrg                } else {
102001e04c3fSmrg                        fprintf(clif->out, "  /* %30s: */ %s\n",
102101e04c3fSmrg                                iter.name, iter.value);
102201e04c3fSmrg                }
102301e04c3fSmrg                if (iter.struct_desc) {
102401e04c3fSmrg                        uint64_t struct_offset = offset + iter.offset;
102501e04c3fSmrg                        v3d_print_group(clif, iter.struct_desc,
102601e04c3fSmrg                                        struct_offset,
102701e04c3fSmrg                                        &p[iter.offset]);
102801e04c3fSmrg                }
102901e04c3fSmrg        }
103001e04c3fSmrg}
1031