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