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