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