Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mesa
Path: blob/21.2-virgl/src/broadcom/cle/v3d_decoder.c
4560 views
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 *
88
v3d_group_get_name(struct v3d_group *group)
89
{
90
return group->name;
91
}
92
93
uint8_t
94
v3d_group_get_opcode(struct v3d_group *group)
95
{
96
return group->opcode;
97
}
98
99
struct v3d_group *
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 *
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 *
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 *
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))
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 *
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 *
168
xstrdup(const char *s)
169
{
170
return fail_on_null(strdup(s));
171
}
172
173
static void *
174
zalloc(size_t s)
175
{
176
return calloc(s, 1);
177
}
178
179
static void *
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
188
is_byte_offset(const char *value)
189
{
190
return value[strlen(value) - 1] == 'b';
191
}
192
193
static void
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 *
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 *
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
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 void
271
get_start_end_pos(int *start, int *end)
272
{
273
/* start value has to be mod with 32 as we need the relative
274
* start position in the first DWord. For the end position, add
275
* the length of the field to the start position to get the
276
* relative postion in the 64 bit address.
277
*/
278
if (*end - *start > 32) {
279
int len = *end - *start;
280
*start = *start % 32;
281
*end = *start + len;
282
} else {
283
*start = *start % 32;
284
*end = *end % 32;
285
}
286
287
return;
288
}
289
290
static inline uint64_t
291
mask(int start, int end)
292
{
293
uint64_t v;
294
295
v = ~0ULL >> (63 - end + start);
296
297
return v << start;
298
}
299
300
static inline uint64_t
301
field(uint64_t value, int start, int end)
302
{
303
get_start_end_pos(&start, &end);
304
return (value & mask(start, end)) >> (start);
305
}
306
307
static inline uint64_t
308
field_address(uint64_t value, int start, int end)
309
{
310
/* no need to right shift for address/offset */
311
get_start_end_pos(&start, &end);
312
return (value & mask(start, end));
313
}
314
315
static struct v3d_type
316
string_to_type(struct parser_context *ctx, const char *s)
317
{
318
int i, f;
319
struct v3d_group *g;
320
struct v3d_enum *e;
321
322
if (strcmp(s, "int") == 0)
323
return (struct v3d_type) { .kind = V3D_TYPE_INT };
324
else if (strcmp(s, "uint") == 0)
325
return (struct v3d_type) { .kind = V3D_TYPE_UINT };
326
else if (strcmp(s, "bool") == 0)
327
return (struct v3d_type) { .kind = V3D_TYPE_BOOL };
328
else if (strcmp(s, "float") == 0)
329
return (struct v3d_type) { .kind = V3D_TYPE_FLOAT };
330
else if (strcmp(s, "f187") == 0)
331
return (struct v3d_type) { .kind = V3D_TYPE_F187 };
332
else if (strcmp(s, "address") == 0)
333
return (struct v3d_type) { .kind = V3D_TYPE_ADDRESS };
334
else if (strcmp(s, "offset") == 0)
335
return (struct v3d_type) { .kind = V3D_TYPE_OFFSET };
336
else if (sscanf(s, "u%d.%d", &i, &f) == 2)
337
return (struct v3d_type) { .kind = V3D_TYPE_UFIXED, .i = i, .f = f };
338
else if (sscanf(s, "s%d.%d", &i, &f) == 2)
339
return (struct v3d_type) { .kind = V3D_TYPE_SFIXED, .i = i, .f = f };
340
else if (g = v3d_spec_find_struct(ctx->spec, s), g != NULL)
341
return (struct v3d_type) { .kind = V3D_TYPE_STRUCT, .v3d_struct = g };
342
else if (e = v3d_spec_find_enum(ctx->spec, s), e != NULL)
343
return (struct v3d_type) { .kind = V3D_TYPE_ENUM, .v3d_enum = e };
344
else if (strcmp(s, "mbo") == 0)
345
return (struct v3d_type) { .kind = V3D_TYPE_MBO };
346
else
347
fail(&ctx->loc, "invalid type: %s", s);
348
}
349
350
static struct v3d_field *
351
create_field(struct parser_context *ctx, const char **atts)
352
{
353
struct v3d_field *field;
354
char *p;
355
int i;
356
uint32_t size = 0;
357
358
field = xzalloc(sizeof(*field));
359
360
for (i = 0; atts[i]; i += 2) {
361
if (strcmp(atts[i], "name") == 0)
362
field->name = xstrdup(atts[i + 1]);
363
else if (strcmp(atts[i], "start") == 0) {
364
field->start = strtoul(atts[i + 1], &p, 0);
365
if (is_byte_offset(atts[i + 1]))
366
field->start *= 8;
367
} else if (strcmp(atts[i], "end") == 0) {
368
field->end = strtoul(atts[i + 1], &p, 0) - 1;
369
if (is_byte_offset(atts[i + 1]))
370
field->end *= 8;
371
} else if (strcmp(atts[i], "size") == 0) {
372
size = strtoul(atts[i + 1], &p, 0);
373
if (is_byte_offset(atts[i + 1]))
374
size *= 8;
375
} else if (strcmp(atts[i], "type") == 0)
376
field->type = string_to_type(ctx, atts[i + 1]);
377
else if (strcmp(atts[i], "default") == 0) {
378
field->has_default = true;
379
field->default_value = strtoul(atts[i + 1], &p, 0);
380
} else if (strcmp(atts[i], "minus_one") == 0) {
381
assert(strcmp(atts[i + 1], "true") == 0);
382
field->minus_one = true;
383
}
384
}
385
386
if (size)
387
field->end = field->start + size - 1;
388
389
return field;
390
}
391
392
static struct v3d_value *
393
create_value(struct parser_context *ctx, const char **atts)
394
{
395
struct v3d_value *value = xzalloc(sizeof(*value));
396
397
for (int i = 0; atts[i]; i += 2) {
398
if (strcmp(atts[i], "name") == 0)
399
value->name = xstrdup(atts[i + 1]);
400
else if (strcmp(atts[i], "value") == 0)
401
value->value = strtoul(atts[i + 1], NULL, 0);
402
}
403
404
return value;
405
}
406
407
static void
408
create_and_append_field(struct parser_context *ctx,
409
const char **atts)
410
{
411
if (ctx->group->nfields == ctx->group->fields_size) {
412
ctx->group->fields_size = MAX2(ctx->group->fields_size * 2, 2);
413
ctx->group->fields =
414
(struct v3d_field **) realloc(ctx->group->fields,
415
sizeof(ctx->group->fields[0]) *
416
ctx->group->fields_size);
417
}
418
419
ctx->group->fields[ctx->group->nfields++] = create_field(ctx, atts);
420
}
421
422
static void
423
set_group_opcode(struct v3d_group *group, const char **atts)
424
{
425
char *p;
426
int i;
427
428
for (i = 0; atts[i]; i += 2) {
429
if (strcmp(atts[i], "code") == 0)
430
group->opcode = strtoul(atts[i + 1], &p, 0);
431
}
432
return;
433
}
434
435
static bool
436
ver_in_range(int ver, int min_ver, int max_ver)
437
{
438
return ((min_ver == 0 || ver >= min_ver) &&
439
(max_ver == 0 || ver <= max_ver));
440
}
441
442
static bool
443
skip_if_ver_mismatch(struct parser_context *ctx, int min_ver, int max_ver)
444
{
445
if (!ctx->parse_skip_depth && !ver_in_range(ctx->devinfo->ver,
446
min_ver, max_ver)) {
447
assert(ctx->parse_depth != 0);
448
ctx->parse_skip_depth = ctx->parse_depth;
449
}
450
451
return ctx->parse_skip_depth;
452
}
453
454
static void
455
start_element(void *data, const char *element_name, const char **atts)
456
{
457
struct parser_context *ctx = data;
458
int i;
459
const char *name = NULL;
460
const char *ver = NULL;
461
int min_ver = 0;
462
int max_ver = 0;
463
464
ctx->loc.line_number = XML_GetCurrentLineNumber(ctx->parser);
465
466
for (i = 0; atts[i]; i += 2) {
467
if (strcmp(atts[i], "shortname") == 0)
468
name = atts[i + 1];
469
else if (strcmp(atts[i], "name") == 0 && !name)
470
name = atts[i + 1];
471
else if (strcmp(atts[i], "gen") == 0)
472
ver = atts[i + 1];
473
else if (strcmp(atts[i], "min_ver") == 0)
474
min_ver = strtoul(atts[i + 1], NULL, 0);
475
else if (strcmp(atts[i], "max_ver") == 0)
476
max_ver = strtoul(atts[i + 1], NULL, 0);
477
}
478
479
if (skip_if_ver_mismatch(ctx, min_ver, max_ver))
480
goto skip;
481
482
if (strcmp(element_name, "vcxml") == 0) {
483
if (ver == NULL)
484
fail(&ctx->loc, "no ver given");
485
486
/* Make sure that we picked an XML that matched our version.
487
*/
488
assert(ver_in_range(ctx->devinfo->ver, min_ver, max_ver));
489
490
int major, minor;
491
int n = sscanf(ver, "%d.%d", &major, &minor);
492
if (n == 0)
493
fail(&ctx->loc, "invalid ver given: %s", ver);
494
if (n == 1)
495
minor = 0;
496
497
ctx->spec->ver = major * 10 + minor;
498
} else if (strcmp(element_name, "packet") == 0 ||
499
strcmp(element_name, "struct") == 0) {
500
ctx->group = create_group(ctx, name, atts, NULL);
501
502
if (strcmp(element_name, "packet") == 0)
503
set_group_opcode(ctx->group, atts);
504
} else if (strcmp(element_name, "register") == 0) {
505
ctx->group = create_group(ctx, name, atts, NULL);
506
get_register_offset(atts, &ctx->group->register_offset);
507
} else if (strcmp(element_name, "group") == 0) {
508
struct v3d_group *previous_group = ctx->group;
509
while (previous_group->next)
510
previous_group = previous_group->next;
511
512
struct v3d_group *group = create_group(ctx, "", atts,
513
ctx->group);
514
previous_group->next = group;
515
ctx->group = group;
516
} else if (strcmp(element_name, "field") == 0) {
517
create_and_append_field(ctx, atts);
518
} else if (strcmp(element_name, "enum") == 0) {
519
ctx->enoom = create_enum(ctx, name, atts);
520
} else if (strcmp(element_name, "value") == 0) {
521
ctx->values[ctx->nvalues++] = create_value(ctx, atts);
522
assert(ctx->nvalues < ARRAY_SIZE(ctx->values));
523
}
524
525
skip:
526
ctx->parse_depth++;
527
}
528
529
static int
530
field_offset_compare(const void *a, const void *b)
531
{
532
return ((*(const struct v3d_field **)a)->start -
533
(*(const struct v3d_field **)b)->start);
534
}
535
536
static void
537
end_element(void *data, const char *name)
538
{
539
struct parser_context *ctx = data;
540
struct v3d_spec *spec = ctx->spec;
541
542
ctx->parse_depth--;
543
544
if (ctx->parse_skip_depth) {
545
if (ctx->parse_skip_depth == ctx->parse_depth)
546
ctx->parse_skip_depth = 0;
547
return;
548
}
549
550
if (strcmp(name, "packet") == 0 ||
551
strcmp(name, "struct") == 0 ||
552
strcmp(name, "register") == 0) {
553
struct v3d_group *group = ctx->group;
554
555
ctx->group = ctx->group->parent;
556
557
if (strcmp(name, "packet") == 0) {
558
spec->commands[spec->ncommands++] = group;
559
560
/* V3D packet XML has the packet contents with offsets
561
* starting from the first bit after the opcode, to
562
* match the spec. Shift the fields up now.
563
*/
564
for (int i = 0; i < group->nfields; i++) {
565
group->fields[i]->start += 8;
566
group->fields[i]->end += 8;
567
}
568
}
569
else if (strcmp(name, "struct") == 0)
570
spec->structs[spec->nstructs++] = group;
571
else if (strcmp(name, "register") == 0)
572
spec->registers[spec->nregisters++] = group;
573
574
/* Sort the fields in increasing offset order. The XML might
575
* be specified in any order, but we'll want to iterate from
576
* the bottom.
577
*/
578
qsort(group->fields, group->nfields, sizeof(*group->fields),
579
field_offset_compare);
580
581
assert(spec->ncommands < ARRAY_SIZE(spec->commands));
582
assert(spec->nstructs < ARRAY_SIZE(spec->structs));
583
assert(spec->nregisters < ARRAY_SIZE(spec->registers));
584
} else if (strcmp(name, "group") == 0) {
585
ctx->group = ctx->group->parent;
586
} else if (strcmp(name, "field") == 0) {
587
assert(ctx->group->nfields > 0);
588
struct v3d_field *field = ctx->group->fields[ctx->group->nfields - 1];
589
size_t size = ctx->nvalues * sizeof(ctx->values[0]);
590
field->inline_enum.values = xzalloc(size);
591
field->inline_enum.nvalues = ctx->nvalues;
592
memcpy(field->inline_enum.values, ctx->values, size);
593
ctx->nvalues = 0;
594
} else if (strcmp(name, "enum") == 0) {
595
struct v3d_enum *e = ctx->enoom;
596
size_t size = ctx->nvalues * sizeof(ctx->values[0]);
597
e->values = xzalloc(size);
598
e->nvalues = ctx->nvalues;
599
memcpy(e->values, ctx->values, size);
600
ctx->nvalues = 0;
601
ctx->enoom = NULL;
602
spec->enums[spec->nenums++] = e;
603
}
604
}
605
606
static void
607
character_data(void *data, const XML_Char *s, int len)
608
{
609
}
610
611
static uint32_t zlib_inflate(const void *compressed_data,
612
uint32_t compressed_len,
613
void **out_ptr)
614
{
615
struct z_stream_s zstream;
616
void *out;
617
618
memset(&zstream, 0, sizeof(zstream));
619
620
zstream.next_in = (unsigned char *)compressed_data;
621
zstream.avail_in = compressed_len;
622
623
if (inflateInit(&zstream) != Z_OK)
624
return 0;
625
626
out = malloc(4096);
627
zstream.next_out = out;
628
zstream.avail_out = 4096;
629
630
do {
631
switch (inflate(&zstream, Z_SYNC_FLUSH)) {
632
case Z_STREAM_END:
633
goto end;
634
case Z_OK:
635
break;
636
default:
637
inflateEnd(&zstream);
638
return 0;
639
}
640
641
if (zstream.avail_out)
642
break;
643
644
out = realloc(out, 2*zstream.total_out);
645
if (out == NULL) {
646
inflateEnd(&zstream);
647
return 0;
648
}
649
650
zstream.next_out = (unsigned char *)out + zstream.total_out;
651
zstream.avail_out = zstream.total_out;
652
} while (1);
653
end:
654
inflateEnd(&zstream);
655
*out_ptr = out;
656
return zstream.total_out;
657
}
658
659
#endif /* WITH_LIBEXPAT */
660
661
struct v3d_spec *
662
v3d_spec_load(const struct v3d_device_info *devinfo)
663
{
664
struct v3d_spec *spec = calloc(1, sizeof(struct v3d_spec));
665
if (!spec)
666
return NULL;
667
668
#ifdef WITH_LIBEXPAT
669
struct parser_context ctx;
670
void *buf;
671
uint8_t *text_data = NULL;
672
uint32_t text_offset = 0, text_length = 0;
673
ASSERTED uint32_t total_length;
674
675
for (int i = 0; i < ARRAY_SIZE(genxml_files_table); i++) {
676
if (i != 0) {
677
assert(genxml_files_table[i - 1].ver_10 <
678
genxml_files_table[i].ver_10);
679
}
680
681
if (genxml_files_table[i].ver_10 <= devinfo->ver) {
682
text_offset = genxml_files_table[i].offset;
683
text_length = genxml_files_table[i].length;
684
}
685
}
686
687
if (text_length == 0) {
688
fprintf(stderr, "unable to find gen (%u) data\n", devinfo->ver);
689
free(spec);
690
return NULL;
691
}
692
693
memset(&ctx, 0, sizeof ctx);
694
ctx.parser = XML_ParserCreate(NULL);
695
ctx.devinfo = devinfo;
696
XML_SetUserData(ctx.parser, &ctx);
697
if (ctx.parser == NULL) {
698
fprintf(stderr, "failed to create parser\n");
699
free(spec);
700
return NULL;
701
}
702
703
XML_SetElementHandler(ctx.parser, start_element, end_element);
704
XML_SetCharacterDataHandler(ctx.parser, character_data);
705
706
ctx.spec = spec;
707
708
total_length = zlib_inflate(compress_genxmls,
709
sizeof(compress_genxmls),
710
(void **) &text_data);
711
assert(text_offset + text_length <= total_length);
712
713
buf = XML_GetBuffer(ctx.parser, text_length);
714
memcpy(buf, &text_data[text_offset], text_length);
715
716
if (XML_ParseBuffer(ctx.parser, text_length, true) == 0) {
717
fprintf(stderr,
718
"Error parsing XML at line %ld col %ld byte %ld/%u: %s\n",
719
XML_GetCurrentLineNumber(ctx.parser),
720
XML_GetCurrentColumnNumber(ctx.parser),
721
XML_GetCurrentByteIndex(ctx.parser), text_length,
722
XML_ErrorString(XML_GetErrorCode(ctx.parser)));
723
XML_ParserFree(ctx.parser);
724
free(text_data);
725
free(spec);
726
return NULL;
727
}
728
729
XML_ParserFree(ctx.parser);
730
free(text_data);
731
732
return ctx.spec;
733
#else /* !WITH_LIBEXPAT */
734
debug_warn_once("CLIF dumping not supported due to missing libexpat");
735
return spec;
736
#endif /* !WITH_LIBEXPAT */
737
}
738
739
struct v3d_group *
740
v3d_spec_find_instruction(struct v3d_spec *spec, const uint8_t *p)
741
{
742
uint8_t opcode = *p;
743
744
for (int i = 0; i < spec->ncommands; i++) {
745
struct v3d_group *group = spec->commands[i];
746
747
if (opcode != group->opcode)
748
continue;
749
750
/* If there's a "sub-id" field, make sure that it matches the
751
* instruction being decoded.
752
*/
753
struct v3d_field *subid = NULL;
754
for (int j = 0; j < group->nfields; j++) {
755
struct v3d_field *field = group->fields[j];
756
if (strcmp(field->name, "sub-id") == 0) {
757
subid = field;
758
break;
759
}
760
}
761
762
if (subid && (__gen_unpack_uint(p, subid->start, subid->end) !=
763
subid->default_value)) {
764
continue;
765
}
766
767
return group;
768
}
769
770
return NULL;
771
}
772
773
/** Returns the size of a V3D packet. */
774
int
775
v3d_group_get_length(struct v3d_group *group)
776
{
777
int last_bit = 0;
778
for (int i = 0; i < group->nfields; i++) {
779
struct v3d_field *field = group->fields[i];
780
781
last_bit = MAX2(last_bit, field->end);
782
}
783
return last_bit / 8 + 1;
784
}
785
786
void
787
v3d_field_iterator_init(struct v3d_field_iterator *iter,
788
struct v3d_group *group,
789
const uint8_t *p)
790
{
791
memset(iter, 0, sizeof(*iter));
792
793
iter->group = group;
794
iter->p = p;
795
}
796
797
static const char *
798
v3d_get_enum_name(struct v3d_enum *e, uint64_t value)
799
{
800
for (int i = 0; i < e->nvalues; i++) {
801
if (e->values[i]->value == value) {
802
return e->values[i]->name;
803
}
804
}
805
return NULL;
806
}
807
808
static bool
809
iter_more_fields(const struct v3d_field_iterator *iter)
810
{
811
return iter->field_iter < iter->group->nfields;
812
}
813
814
static uint32_t
815
iter_group_offset_bits(const struct v3d_field_iterator *iter,
816
uint32_t group_iter)
817
{
818
return iter->group->group_offset + (group_iter *
819
iter->group->group_size);
820
}
821
822
static bool
823
iter_more_groups(const struct v3d_field_iterator *iter)
824
{
825
if (iter->group->variable) {
826
return iter_group_offset_bits(iter, iter->group_iter + 1) <
827
(v3d_group_get_length(iter->group) * 8);
828
} else {
829
return (iter->group_iter + 1) < iter->group->group_count ||
830
iter->group->next != NULL;
831
}
832
}
833
834
static void
835
iter_advance_group(struct v3d_field_iterator *iter)
836
{
837
if (iter->group->variable)
838
iter->group_iter++;
839
else {
840
if ((iter->group_iter + 1) < iter->group->group_count) {
841
iter->group_iter++;
842
} else {
843
iter->group = iter->group->next;
844
iter->group_iter = 0;
845
}
846
}
847
848
iter->field_iter = 0;
849
}
850
851
static bool
852
iter_advance_field(struct v3d_field_iterator *iter)
853
{
854
while (!iter_more_fields(iter)) {
855
if (!iter_more_groups(iter))
856
return false;
857
858
iter_advance_group(iter);
859
}
860
861
iter->field = iter->group->fields[iter->field_iter++];
862
if (iter->field->name)
863
snprintf(iter->name, sizeof(iter->name), "%s", iter->field->name);
864
else
865
memset(iter->name, 0, sizeof(iter->name));
866
iter->offset = iter_group_offset_bits(iter, iter->group_iter) / 8 +
867
iter->field->start / 8;
868
iter->struct_desc = NULL;
869
870
return true;
871
}
872
873
bool
874
v3d_field_iterator_next(struct clif_dump *clif, struct v3d_field_iterator *iter)
875
{
876
if (!iter_advance_field(iter))
877
return false;
878
879
const char *enum_name = NULL;
880
881
int group_member_offset =
882
iter_group_offset_bits(iter, iter->group_iter);
883
int s = group_member_offset + iter->field->start;
884
int e = group_member_offset + iter->field->end;
885
886
assert(!iter->field->minus_one ||
887
iter->field->type.kind == V3D_TYPE_INT ||
888
iter->field->type.kind == V3D_TYPE_UINT);
889
890
switch (iter->field->type.kind) {
891
case V3D_TYPE_UNKNOWN:
892
case V3D_TYPE_INT: {
893
uint32_t value = __gen_unpack_sint(iter->p, s, e);
894
if (iter->field->minus_one)
895
value++;
896
snprintf(iter->value, sizeof(iter->value), "%d", value);
897
enum_name = v3d_get_enum_name(&iter->field->inline_enum, value);
898
break;
899
}
900
case V3D_TYPE_UINT: {
901
uint32_t value = __gen_unpack_uint(iter->p, s, e);
902
if (iter->field->minus_one)
903
value++;
904
if (strcmp(iter->field->name, "Vec size") == 0 && value == 0)
905
value = 1 << (e - s + 1);
906
snprintf(iter->value, sizeof(iter->value), "%u", value);
907
enum_name = v3d_get_enum_name(&iter->field->inline_enum, value);
908
break;
909
}
910
case V3D_TYPE_BOOL:
911
snprintf(iter->value, sizeof(iter->value), "%s",
912
__gen_unpack_uint(iter->p, s, e) ?
913
"1 /* true */" : "0 /* false */");
914
break;
915
case V3D_TYPE_FLOAT:
916
snprintf(iter->value, sizeof(iter->value), "%f",
917
__gen_unpack_float(iter->p, s, e));
918
break;
919
920
case V3D_TYPE_F187:
921
snprintf(iter->value, sizeof(iter->value), "%f",
922
__gen_unpack_f187(iter->p, s, e));
923
break;
924
925
case V3D_TYPE_ADDRESS: {
926
uint32_t addr =
927
__gen_unpack_uint(iter->p, s, e) << (31 - (e - s));
928
struct clif_bo *bo = clif_lookup_bo(clif, addr);
929
if (bo) {
930
snprintf(iter->value, sizeof(iter->value),
931
"[%s+0x%08x] /* 0x%08x */",
932
bo->name, addr - bo->offset, addr);
933
} else if (addr) {
934
snprintf(iter->value, sizeof(iter->value),
935
"/* XXX: BO unknown */ 0x%08x", addr);
936
} else {
937
snprintf(iter->value, sizeof(iter->value),
938
"[null]");
939
}
940
941
break;
942
}
943
944
case V3D_TYPE_OFFSET:
945
snprintf(iter->value, sizeof(iter->value), "0x%08"PRIx64,
946
__gen_unpack_uint(iter->p, s, e) << (31 - (e - s)));
947
break;
948
case V3D_TYPE_STRUCT:
949
snprintf(iter->value, sizeof(iter->value), "<struct %s>",
950
iter->field->type.v3d_struct->name);
951
iter->struct_desc =
952
v3d_spec_find_struct(iter->group->spec,
953
iter->field->type.v3d_struct->name);
954
break;
955
case V3D_TYPE_SFIXED:
956
if (clif->pretty) {
957
snprintf(iter->value, sizeof(iter->value), "%f",
958
__gen_unpack_sfixed(iter->p, s, e,
959
iter->field->type.f));
960
} else {
961
snprintf(iter->value, sizeof(iter->value), "%u",
962
(unsigned)__gen_unpack_uint(iter->p, s, e));
963
}
964
break;
965
case V3D_TYPE_UFIXED:
966
if (clif->pretty) {
967
snprintf(iter->value, sizeof(iter->value), "%f",
968
__gen_unpack_ufixed(iter->p, s, e,
969
iter->field->type.f));
970
} else {
971
snprintf(iter->value, sizeof(iter->value), "%u",
972
(unsigned)__gen_unpack_uint(iter->p, s, e));
973
}
974
break;
975
case V3D_TYPE_MBO:
976
break;
977
case V3D_TYPE_ENUM: {
978
uint32_t value = __gen_unpack_uint(iter->p, s, e);
979
snprintf(iter->value, sizeof(iter->value), "%d", value);
980
enum_name = v3d_get_enum_name(iter->field->type.v3d_enum, value);
981
break;
982
}
983
}
984
985
if (strlen(iter->group->name) == 0) {
986
int length = strlen(iter->name);
987
snprintf(iter->name + length, sizeof(iter->name) - length,
988
"[%i]", iter->group_iter);
989
}
990
991
if (enum_name) {
992
int length = strlen(iter->value);
993
snprintf(iter->value + length, sizeof(iter->value) - length,
994
" /* %s */", enum_name);
995
}
996
997
return true;
998
}
999
1000
void
1001
v3d_print_group(struct clif_dump *clif, struct v3d_group *group,
1002
uint64_t offset, const uint8_t *p)
1003
{
1004
struct v3d_field_iterator iter;
1005
1006
v3d_field_iterator_init(&iter, group, p);
1007
while (v3d_field_iterator_next(clif, &iter)) {
1008
/* Clif parsing uses the packet name, and expects no
1009
* sub-id.
1010
*/
1011
if (strcmp(iter.field->name, "sub-id") == 0 ||
1012
strcmp(iter.field->name, "unused") == 0 ||
1013
strcmp(iter.field->name, "Pad") == 0)
1014
continue;
1015
1016
if (clif->pretty) {
1017
fprintf(clif->out, " %s: %s\n",
1018
iter.name, iter.value);
1019
} else {
1020
fprintf(clif->out, " /* %30s: */ %s\n",
1021
iter.name, iter.value);
1022
}
1023
if (iter.struct_desc) {
1024
uint64_t struct_offset = offset + iter.offset;
1025
v3d_print_group(clif, iter.struct_desc,
1026
struct_offset,
1027
&p[iter.offset]);
1028
}
1029
}
1030
}
1031
1032