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