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