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