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