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