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 "v3d_decoder.h" 26 27#include <stdio.h> 28#include <stdlib.h> 29#include <stdbool.h> 30#include <stdint.h> 31#include <stdarg.h> 32#include <string.h> 33#ifdef WITH_LIBEXPAT 34#include <expat.h> 35#endif 36#include <inttypes.h> 37#include <zlib.h> 38 39#include <util/macros.h> 40#include <util/ralloc.h> 41#include <util/u_debug.h> 42 43#include "v3d_packet_helpers.h" 44#include "v3d_xml.h" 45#include "broadcom/clif/clif_private.h" 46 47struct v3d_spec { 48 uint32_t ver; 49 50 int ncommands; 51 struct v3d_group *commands[256]; 52 int nstructs; 53 struct v3d_group *structs[256]; 54 int nregisters; 55 struct v3d_group *registers[256]; 56 int nenums; 57 struct v3d_enum *enums[256]; 58}; 59 60#ifdef WITH_LIBEXPAT 61 62struct location { 63 const char *filename; 64 int line_number; 65}; 66 67struct parser_context { 68 XML_Parser parser; 69 const struct v3d_device_info *devinfo; 70 int foo; 71 struct location loc; 72 73 struct v3d_group *group; 74 struct v3d_enum *enoom; 75 76 int nvalues; 77 struct v3d_value *values[256]; 78 79 struct v3d_spec *spec; 80 81 int parse_depth; 82 int parse_skip_depth; 83}; 84 85#endif /* WITH_LIBEXPAT */ 86 87const char * 88v3d_group_get_name(struct v3d_group *group) 89{ 90 return group->name; 91} 92 93uint8_t 94v3d_group_get_opcode(struct v3d_group *group) 95{ 96 return group->opcode; 97} 98 99struct v3d_group * 100v3d_spec_find_struct(struct v3d_spec *spec, const char *name) 101{ 102 for (int i = 0; i < spec->nstructs; i++) 103 if (strcmp(spec->structs[i]->name, name) == 0) 104 return spec->structs[i]; 105 106 return NULL; 107} 108 109struct v3d_group * 110v3d_spec_find_register(struct v3d_spec *spec, uint32_t offset) 111{ 112 for (int i = 0; i < spec->nregisters; i++) 113 if (spec->registers[i]->register_offset == offset) 114 return spec->registers[i]; 115 116 return NULL; 117} 118 119struct v3d_group * 120v3d_spec_find_register_by_name(struct v3d_spec *spec, const char *name) 121{ 122 for (int i = 0; i < spec->nregisters; i++) { 123 if (strcmp(spec->registers[i]->name, name) == 0) 124 return spec->registers[i]; 125 } 126 127 return NULL; 128} 129 130struct v3d_enum * 131v3d_spec_find_enum(struct v3d_spec *spec, const char *name) 132{ 133 for (int i = 0; i < spec->nenums; i++) 134 if (strcmp(spec->enums[i]->name, name) == 0) 135 return spec->enums[i]; 136 137 return NULL; 138} 139 140#ifdef WITH_LIBEXPAT 141 142static void __attribute__((noreturn)) 143fail(struct location *loc, const char *msg, ...) 144{ 145 va_list ap; 146 147 va_start(ap, msg); 148 fprintf(stderr, "%s:%d: error: ", 149 loc->filename, loc->line_number); 150 vfprintf(stderr, msg, ap); 151 fprintf(stderr, "\n"); 152 va_end(ap); 153 exit(EXIT_FAILURE); 154} 155 156static void * 157fail_on_null(void *p) 158{ 159 if (p == NULL) { 160 fprintf(stderr, "aubinator: out of memory\n"); 161 exit(EXIT_FAILURE); 162 } 163 164 return p; 165} 166 167static char * 168xstrdup(const char *s) 169{ 170 return fail_on_null(strdup(s)); 171} 172 173static void * 174zalloc(size_t s) 175{ 176 return calloc(s, 1); 177} 178 179static void * 180xzalloc(size_t s) 181{ 182 return fail_on_null(zalloc(s)); 183} 184 185/* We allow fields to have either a bit index, or append "b" for a byte index. 186 */ 187static bool 188is_byte_offset(const char *value) 189{ 190 return value[strlen(value) - 1] == 'b'; 191} 192 193static void 194get_group_offset_count(const char **atts, uint32_t *offset, uint32_t *count, 195 uint32_t *size, bool *variable) 196{ 197 char *p; 198 int i; 199 200 for (i = 0; atts[i]; i += 2) { 201 if (strcmp(atts[i], "count") == 0) { 202 *count = strtoul(atts[i + 1], &p, 0); 203 if (*count == 0) 204 *variable = true; 205 } else if (strcmp(atts[i], "start") == 0) { 206 *offset = strtoul(atts[i + 1], &p, 0); 207 } else if (strcmp(atts[i], "size") == 0) { 208 *size = strtoul(atts[i + 1], &p, 0); 209 } 210 } 211 return; 212} 213 214static struct v3d_group * 215create_group(struct parser_context *ctx, 216 const char *name, 217 const char **atts, 218 struct v3d_group *parent) 219{ 220 struct v3d_group *group; 221 222 group = xzalloc(sizeof(*group)); 223 if (name) 224 group->name = xstrdup(name); 225 226 group->spec = ctx->spec; 227 group->group_offset = 0; 228 group->group_count = 0; 229 group->variable = false; 230 231 if (parent) { 232 group->parent = parent; 233 get_group_offset_count(atts, 234 &group->group_offset, 235 &group->group_count, 236 &group->group_size, 237 &group->variable); 238 } 239 240 return group; 241} 242 243static struct v3d_enum * 244create_enum(struct parser_context *ctx, const char *name, const char **atts) 245{ 246 struct v3d_enum *e; 247 248 e = xzalloc(sizeof(*e)); 249 if (name) 250 e->name = xstrdup(name); 251 252 e->nvalues = 0; 253 254 return e; 255} 256 257static void 258get_register_offset(const char **atts, uint32_t *offset) 259{ 260 char *p; 261 int i; 262 263 for (i = 0; atts[i]; i += 2) { 264 if (strcmp(atts[i], "num") == 0) 265 *offset = strtoul(atts[i + 1], &p, 0); 266 } 267 return; 268} 269 270static void 271get_start_end_pos(int *start, int *end) 272{ 273 /* start value has to be mod with 32 as we need the relative 274 * start position in the first DWord. For the end position, add 275 * the length of the field to the start position to get the 276 * relative postion in the 64 bit address. 277 */ 278 if (*end - *start > 32) { 279 int len = *end - *start; 280 *start = *start % 32; 281 *end = *start + len; 282 } else { 283 *start = *start % 32; 284 *end = *end % 32; 285 } 286 287 return; 288} 289 290static inline uint64_t 291mask(int start, int end) 292{ 293 uint64_t v; 294 295 v = ~0ULL >> (63 - end + start); 296 297 return v << start; 298} 299 300static inline uint64_t 301field(uint64_t value, int start, int end) 302{ 303 get_start_end_pos(&start, &end); 304 return (value & mask(start, end)) >> (start); 305} 306 307static inline uint64_t 308field_address(uint64_t value, int start, int end) 309{ 310 /* no need to right shift for address/offset */ 311 get_start_end_pos(&start, &end); 312 return (value & mask(start, end)); 313} 314 315static struct v3d_type 316string_to_type(struct parser_context *ctx, const char *s) 317{ 318 int i, f; 319 struct v3d_group *g; 320 struct v3d_enum *e; 321 322 if (strcmp(s, "int") == 0) 323 return (struct v3d_type) { .kind = V3D_TYPE_INT }; 324 else if (strcmp(s, "uint") == 0) 325 return (struct v3d_type) { .kind = V3D_TYPE_UINT }; 326 else if (strcmp(s, "bool") == 0) 327 return (struct v3d_type) { .kind = V3D_TYPE_BOOL }; 328 else if (strcmp(s, "float") == 0) 329 return (struct v3d_type) { .kind = V3D_TYPE_FLOAT }; 330 else if (strcmp(s, "f187") == 0) 331 return (struct v3d_type) { .kind = V3D_TYPE_F187 }; 332 else if (strcmp(s, "address") == 0) 333 return (struct v3d_type) { .kind = V3D_TYPE_ADDRESS }; 334 else if (strcmp(s, "offset") == 0) 335 return (struct v3d_type) { .kind = V3D_TYPE_OFFSET }; 336 else if (sscanf(s, "u%d.%d", &i, &f) == 2) 337 return (struct v3d_type) { .kind = V3D_TYPE_UFIXED, .i = i, .f = f }; 338 else if (sscanf(s, "s%d.%d", &i, &f) == 2) 339 return (struct v3d_type) { .kind = V3D_TYPE_SFIXED, .i = i, .f = f }; 340 else if (g = v3d_spec_find_struct(ctx->spec, s), g != NULL) 341 return (struct v3d_type) { .kind = V3D_TYPE_STRUCT, .v3d_struct = g }; 342 else if (e = v3d_spec_find_enum(ctx->spec, s), e != NULL) 343 return (struct v3d_type) { .kind = V3D_TYPE_ENUM, .v3d_enum = e }; 344 else if (strcmp(s, "mbo") == 0) 345 return (struct v3d_type) { .kind = V3D_TYPE_MBO }; 346 else 347 fail(&ctx->loc, "invalid type: %s", s); 348} 349 350static struct v3d_field * 351create_field(struct parser_context *ctx, const char **atts) 352{ 353 struct v3d_field *field; 354 char *p; 355 int i; 356 uint32_t size = 0; 357 358 field = xzalloc(sizeof(*field)); 359 360 for (i = 0; atts[i]; i += 2) { 361 if (strcmp(atts[i], "name") == 0) 362 field->name = xstrdup(atts[i + 1]); 363 else if (strcmp(atts[i], "start") == 0) { 364 field->start = strtoul(atts[i + 1], &p, 0); 365 if (is_byte_offset(atts[i + 1])) 366 field->start *= 8; 367 } else if (strcmp(atts[i], "end") == 0) { 368 field->end = strtoul(atts[i + 1], &p, 0) - 1; 369 if (is_byte_offset(atts[i + 1])) 370 field->end *= 8; 371 } else if (strcmp(atts[i], "size") == 0) { 372 size = strtoul(atts[i + 1], &p, 0); 373 if (is_byte_offset(atts[i + 1])) 374 size *= 8; 375 } else if (strcmp(atts[i], "type") == 0) 376 field->type = string_to_type(ctx, atts[i + 1]); 377 else if (strcmp(atts[i], "default") == 0) { 378 field->has_default = true; 379 field->default_value = strtoul(atts[i + 1], &p, 0); 380 } else if (strcmp(atts[i], "minus_one") == 0) { 381 assert(strcmp(atts[i + 1], "true") == 0); 382 field->minus_one = true; 383 } 384 } 385 386 if (size) 387 field->end = field->start + size - 1; 388 389 return field; 390} 391 392static struct v3d_value * 393create_value(struct parser_context *ctx, const char **atts) 394{ 395 struct v3d_value *value = xzalloc(sizeof(*value)); 396 397 for (int i = 0; atts[i]; i += 2) { 398 if (strcmp(atts[i], "name") == 0) 399 value->name = xstrdup(atts[i + 1]); 400 else if (strcmp(atts[i], "value") == 0) 401 value->value = strtoul(atts[i + 1], NULL, 0); 402 } 403 404 return value; 405} 406 407static void 408create_and_append_field(struct parser_context *ctx, 409 const char **atts) 410{ 411 if (ctx->group->nfields == ctx->group->fields_size) { 412 ctx->group->fields_size = MAX2(ctx->group->fields_size * 2, 2); 413 ctx->group->fields = 414 (struct v3d_field **) realloc(ctx->group->fields, 415 sizeof(ctx->group->fields[0]) * 416 ctx->group->fields_size); 417 } 418 419 ctx->group->fields[ctx->group->nfields++] = create_field(ctx, atts); 420} 421 422static void 423set_group_opcode(struct v3d_group *group, const char **atts) 424{ 425 char *p; 426 int i; 427 428 for (i = 0; atts[i]; i += 2) { 429 if (strcmp(atts[i], "code") == 0) 430 group->opcode = strtoul(atts[i + 1], &p, 0); 431 } 432 return; 433} 434 435static bool 436ver_in_range(int ver, int min_ver, int max_ver) 437{ 438 return ((min_ver == 0 || ver >= min_ver) && 439 (max_ver == 0 || ver <= max_ver)); 440} 441 442static bool 443skip_if_ver_mismatch(struct parser_context *ctx, int min_ver, int max_ver) 444{ 445 if (!ctx->parse_skip_depth && !ver_in_range(ctx->devinfo->ver, 446 min_ver, max_ver)) { 447 assert(ctx->parse_depth != 0); 448 ctx->parse_skip_depth = ctx->parse_depth; 449 } 450 451 return ctx->parse_skip_depth; 452} 453 454static void 455start_element(void *data, const char *element_name, const char **atts) 456{ 457 struct parser_context *ctx = data; 458 int i; 459 const char *name = NULL; 460 const char *ver = NULL; 461 int min_ver = 0; 462 int max_ver = 0; 463 464 ctx->loc.line_number = XML_GetCurrentLineNumber(ctx->parser); 465 466 for (i = 0; atts[i]; i += 2) { 467 if (strcmp(atts[i], "shortname") == 0) 468 name = atts[i + 1]; 469 else if (strcmp(atts[i], "name") == 0 && !name) 470 name = atts[i + 1]; 471 else if (strcmp(atts[i], "gen") == 0) 472 ver = atts[i + 1]; 473 else if (strcmp(atts[i], "min_ver") == 0) 474 min_ver = strtoul(atts[i + 1], NULL, 0); 475 else if (strcmp(atts[i], "max_ver") == 0) 476 max_ver = strtoul(atts[i + 1], NULL, 0); 477 } 478 479 if (skip_if_ver_mismatch(ctx, min_ver, max_ver)) 480 goto skip; 481 482 if (strcmp(element_name, "vcxml") == 0) { 483 if (ver == NULL) 484 fail(&ctx->loc, "no ver given"); 485 486 /* Make sure that we picked an XML that matched our version. 487 */ 488 assert(ver_in_range(ctx->devinfo->ver, min_ver, max_ver)); 489 490 int major, minor; 491 int n = sscanf(ver, "%d.%d", &major, &minor); 492 if (n == 0) 493 fail(&ctx->loc, "invalid ver given: %s", ver); 494 if (n == 1) 495 minor = 0; 496 497 ctx->spec->ver = major * 10 + minor; 498 } else if (strcmp(element_name, "packet") == 0 || 499 strcmp(element_name, "struct") == 0) { 500 ctx->group = create_group(ctx, name, atts, NULL); 501 502 if (strcmp(element_name, "packet") == 0) 503 set_group_opcode(ctx->group, atts); 504 } else if (strcmp(element_name, "register") == 0) { 505 ctx->group = create_group(ctx, name, atts, NULL); 506 get_register_offset(atts, &ctx->group->register_offset); 507 } else if (strcmp(element_name, "group") == 0) { 508 struct v3d_group *previous_group = ctx->group; 509 while (previous_group->next) 510 previous_group = previous_group->next; 511 512 struct v3d_group *group = create_group(ctx, "", atts, 513 ctx->group); 514 previous_group->next = group; 515 ctx->group = group; 516 } else if (strcmp(element_name, "field") == 0) { 517 create_and_append_field(ctx, atts); 518 } else if (strcmp(element_name, "enum") == 0) { 519 ctx->enoom = create_enum(ctx, name, atts); 520 } else if (strcmp(element_name, "value") == 0) { 521 ctx->values[ctx->nvalues++] = create_value(ctx, atts); 522 assert(ctx->nvalues < ARRAY_SIZE(ctx->values)); 523 } 524 525skip: 526 ctx->parse_depth++; 527} 528 529static int 530field_offset_compare(const void *a, const void *b) 531{ 532 return ((*(const struct v3d_field **)a)->start - 533 (*(const struct v3d_field **)b)->start); 534} 535 536static void 537end_element(void *data, const char *name) 538{ 539 struct parser_context *ctx = data; 540 struct v3d_spec *spec = ctx->spec; 541 542 ctx->parse_depth--; 543 544 if (ctx->parse_skip_depth) { 545 if (ctx->parse_skip_depth == ctx->parse_depth) 546 ctx->parse_skip_depth = 0; 547 return; 548 } 549 550 if (strcmp(name, "packet") == 0 || 551 strcmp(name, "struct") == 0 || 552 strcmp(name, "register") == 0) { 553 struct v3d_group *group = ctx->group; 554 555 ctx->group = ctx->group->parent; 556 557 if (strcmp(name, "packet") == 0) { 558 spec->commands[spec->ncommands++] = group; 559 560 /* V3D packet XML has the packet contents with offsets 561 * starting from the first bit after the opcode, to 562 * match the spec. Shift the fields up now. 563 */ 564 for (int i = 0; i < group->nfields; i++) { 565 group->fields[i]->start += 8; 566 group->fields[i]->end += 8; 567 } 568 } 569 else if (strcmp(name, "struct") == 0) 570 spec->structs[spec->nstructs++] = group; 571 else if (strcmp(name, "register") == 0) 572 spec->registers[spec->nregisters++] = group; 573 574 /* Sort the fields in increasing offset order. The XML might 575 * be specified in any order, but we'll want to iterate from 576 * the bottom. 577 */ 578 qsort(group->fields, group->nfields, sizeof(*group->fields), 579 field_offset_compare); 580 581 assert(spec->ncommands < ARRAY_SIZE(spec->commands)); 582 assert(spec->nstructs < ARRAY_SIZE(spec->structs)); 583 assert(spec->nregisters < ARRAY_SIZE(spec->registers)); 584 } else if (strcmp(name, "group") == 0) { 585 ctx->group = ctx->group->parent; 586 } else if (strcmp(name, "field") == 0) { 587 assert(ctx->group->nfields > 0); 588 struct v3d_field *field = ctx->group->fields[ctx->group->nfields - 1]; 589 size_t size = ctx->nvalues * sizeof(ctx->values[0]); 590 field->inline_enum.values = xzalloc(size); 591 field->inline_enum.nvalues = ctx->nvalues; 592 memcpy(field->inline_enum.values, ctx->values, size); 593 ctx->nvalues = 0; 594 } else if (strcmp(name, "enum") == 0) { 595 struct v3d_enum *e = ctx->enoom; 596 size_t size = ctx->nvalues * sizeof(ctx->values[0]); 597 e->values = xzalloc(size); 598 e->nvalues = ctx->nvalues; 599 memcpy(e->values, ctx->values, size); 600 ctx->nvalues = 0; 601 ctx->enoom = NULL; 602 spec->enums[spec->nenums++] = e; 603 } 604} 605 606static void 607character_data(void *data, const XML_Char *s, int len) 608{ 609} 610 611static uint32_t zlib_inflate(const void *compressed_data, 612 uint32_t compressed_len, 613 void **out_ptr) 614{ 615 struct z_stream_s zstream; 616 void *out; 617 618 memset(&zstream, 0, sizeof(zstream)); 619 620 zstream.next_in = (unsigned char *)compressed_data; 621 zstream.avail_in = compressed_len; 622 623 if (inflateInit(&zstream) != Z_OK) 624 return 0; 625 626 out = malloc(4096); 627 zstream.next_out = out; 628 zstream.avail_out = 4096; 629 630 do { 631 switch (inflate(&zstream, Z_SYNC_FLUSH)) { 632 case Z_STREAM_END: 633 goto end; 634 case Z_OK: 635 break; 636 default: 637 inflateEnd(&zstream); 638 return 0; 639 } 640 641 if (zstream.avail_out) 642 break; 643 644 out = realloc(out, 2*zstream.total_out); 645 if (out == NULL) { 646 inflateEnd(&zstream); 647 return 0; 648 } 649 650 zstream.next_out = (unsigned char *)out + zstream.total_out; 651 zstream.avail_out = zstream.total_out; 652 } while (1); 653 end: 654 inflateEnd(&zstream); 655 *out_ptr = out; 656 return zstream.total_out; 657} 658 659#endif /* WITH_LIBEXPAT */ 660 661struct v3d_spec * 662v3d_spec_load(const struct v3d_device_info *devinfo) 663{ 664 struct v3d_spec *spec = calloc(1, sizeof(struct v3d_spec)); 665 if (!spec) 666 return NULL; 667 668#ifdef WITH_LIBEXPAT 669 struct parser_context ctx; 670 void *buf; 671 uint8_t *text_data = NULL; 672 uint32_t text_offset = 0, text_length = 0; 673 ASSERTED uint32_t total_length; 674 675 for (int i = 0; i < ARRAY_SIZE(genxml_files_table); i++) { 676 if (i != 0) { 677 assert(genxml_files_table[i - 1].ver_10 < 678 genxml_files_table[i].ver_10); 679 } 680 681 if (genxml_files_table[i].ver_10 <= devinfo->ver) { 682 text_offset = genxml_files_table[i].offset; 683 text_length = genxml_files_table[i].length; 684 } 685 } 686 687 if (text_length == 0) { 688 fprintf(stderr, "unable to find gen (%u) data\n", devinfo->ver); 689 free(spec); 690 return NULL; 691 } 692 693 memset(&ctx, 0, sizeof ctx); 694 ctx.parser = XML_ParserCreate(NULL); 695 ctx.devinfo = devinfo; 696 XML_SetUserData(ctx.parser, &ctx); 697 if (ctx.parser == NULL) { 698 fprintf(stderr, "failed to create parser\n"); 699 free(spec); 700 return NULL; 701 } 702 703 XML_SetElementHandler(ctx.parser, start_element, end_element); 704 XML_SetCharacterDataHandler(ctx.parser, character_data); 705 706 ctx.spec = spec; 707 708 total_length = zlib_inflate(compress_genxmls, 709 sizeof(compress_genxmls), 710 (void **) &text_data); 711 assert(text_offset + text_length <= total_length); 712 713 buf = XML_GetBuffer(ctx.parser, text_length); 714 memcpy(buf, &text_data[text_offset], text_length); 715 716 if (XML_ParseBuffer(ctx.parser, text_length, true) == 0) { 717 fprintf(stderr, 718 "Error parsing XML at line %ld col %ld byte %ld/%u: %s\n", 719 XML_GetCurrentLineNumber(ctx.parser), 720 XML_GetCurrentColumnNumber(ctx.parser), 721 XML_GetCurrentByteIndex(ctx.parser), text_length, 722 XML_ErrorString(XML_GetErrorCode(ctx.parser))); 723 XML_ParserFree(ctx.parser); 724 free(text_data); 725 free(spec); 726 return NULL; 727 } 728 729 XML_ParserFree(ctx.parser); 730 free(text_data); 731 732 return ctx.spec; 733#else /* !WITH_LIBEXPAT */ 734 debug_warn_once("CLIF dumping not supported due to missing libexpat"); 735 return spec; 736#endif /* !WITH_LIBEXPAT */ 737} 738 739struct v3d_group * 740v3d_spec_find_instruction(struct v3d_spec *spec, const uint8_t *p) 741{ 742 uint8_t opcode = *p; 743 744 for (int i = 0; i < spec->ncommands; i++) { 745 struct v3d_group *group = spec->commands[i]; 746 747 if (opcode != group->opcode) 748 continue; 749 750 /* If there's a "sub-id" field, make sure that it matches the 751 * instruction being decoded. 752 */ 753 struct v3d_field *subid = NULL; 754 for (int j = 0; j < group->nfields; j++) { 755 struct v3d_field *field = group->fields[j]; 756 if (strcmp(field->name, "sub-id") == 0) { 757 subid = field; 758 break; 759 } 760 } 761 762 if (subid && (__gen_unpack_uint(p, subid->start, subid->end) != 763 subid->default_value)) { 764 continue; 765 } 766 767 return group; 768 } 769 770 return NULL; 771} 772 773/** Returns the size of a V3D packet. */ 774int 775v3d_group_get_length(struct v3d_group *group) 776{ 777 int last_bit = 0; 778 for (int i = 0; i < group->nfields; i++) { 779 struct v3d_field *field = group->fields[i]; 780 781 last_bit = MAX2(last_bit, field->end); 782 } 783 return last_bit / 8 + 1; 784} 785 786void 787v3d_field_iterator_init(struct v3d_field_iterator *iter, 788 struct v3d_group *group, 789 const uint8_t *p) 790{ 791 memset(iter, 0, sizeof(*iter)); 792 793 iter->group = group; 794 iter->p = p; 795} 796 797static const char * 798v3d_get_enum_name(struct v3d_enum *e, uint64_t value) 799{ 800 for (int i = 0; i < e->nvalues; i++) { 801 if (e->values[i]->value == value) { 802 return e->values[i]->name; 803 } 804 } 805 return NULL; 806} 807 808static bool 809iter_more_fields(const struct v3d_field_iterator *iter) 810{ 811 return iter->field_iter < iter->group->nfields; 812} 813 814static uint32_t 815iter_group_offset_bits(const struct v3d_field_iterator *iter, 816 uint32_t group_iter) 817{ 818 return iter->group->group_offset + (group_iter * 819 iter->group->group_size); 820} 821 822static bool 823iter_more_groups(const struct v3d_field_iterator *iter) 824{ 825 if (iter->group->variable) { 826 return iter_group_offset_bits(iter, iter->group_iter + 1) < 827 (v3d_group_get_length(iter->group) * 8); 828 } else { 829 return (iter->group_iter + 1) < iter->group->group_count || 830 iter->group->next != NULL; 831 } 832} 833 834static void 835iter_advance_group(struct v3d_field_iterator *iter) 836{ 837 if (iter->group->variable) 838 iter->group_iter++; 839 else { 840 if ((iter->group_iter + 1) < iter->group->group_count) { 841 iter->group_iter++; 842 } else { 843 iter->group = iter->group->next; 844 iter->group_iter = 0; 845 } 846 } 847 848 iter->field_iter = 0; 849} 850 851static bool 852iter_advance_field(struct v3d_field_iterator *iter) 853{ 854 while (!iter_more_fields(iter)) { 855 if (!iter_more_groups(iter)) 856 return false; 857 858 iter_advance_group(iter); 859 } 860 861 iter->field = iter->group->fields[iter->field_iter++]; 862 if (iter->field->name) 863 snprintf(iter->name, sizeof(iter->name), "%s", iter->field->name); 864 else 865 memset(iter->name, 0, sizeof(iter->name)); 866 iter->offset = iter_group_offset_bits(iter, iter->group_iter) / 8 + 867 iter->field->start / 8; 868 iter->struct_desc = NULL; 869 870 return true; 871} 872 873bool 874v3d_field_iterator_next(struct clif_dump *clif, struct v3d_field_iterator *iter) 875{ 876 if (!iter_advance_field(iter)) 877 return false; 878 879 const char *enum_name = NULL; 880 881 int group_member_offset = 882 iter_group_offset_bits(iter, iter->group_iter); 883 int s = group_member_offset + iter->field->start; 884 int e = group_member_offset + iter->field->end; 885 886 assert(!iter->field->minus_one || 887 iter->field->type.kind == V3D_TYPE_INT || 888 iter->field->type.kind == V3D_TYPE_UINT); 889 890 switch (iter->field->type.kind) { 891 case V3D_TYPE_UNKNOWN: 892 case V3D_TYPE_INT: { 893 uint32_t value = __gen_unpack_sint(iter->p, s, e); 894 if (iter->field->minus_one) 895 value++; 896 snprintf(iter->value, sizeof(iter->value), "%d", value); 897 enum_name = v3d_get_enum_name(&iter->field->inline_enum, value); 898 break; 899 } 900 case V3D_TYPE_UINT: { 901 uint32_t value = __gen_unpack_uint(iter->p, s, e); 902 if (iter->field->minus_one) 903 value++; 904 if (strcmp(iter->field->name, "Vec size") == 0 && value == 0) 905 value = 1 << (e - s + 1); 906 snprintf(iter->value, sizeof(iter->value), "%u", value); 907 enum_name = v3d_get_enum_name(&iter->field->inline_enum, value); 908 break; 909 } 910 case V3D_TYPE_BOOL: 911 snprintf(iter->value, sizeof(iter->value), "%s", 912 __gen_unpack_uint(iter->p, s, e) ? 913 "1 /* true */" : "0 /* false */"); 914 break; 915 case V3D_TYPE_FLOAT: 916 snprintf(iter->value, sizeof(iter->value), "%f", 917 __gen_unpack_float(iter->p, s, e)); 918 break; 919 920 case V3D_TYPE_F187: 921 snprintf(iter->value, sizeof(iter->value), "%f", 922 __gen_unpack_f187(iter->p, s, e)); 923 break; 924 925 case V3D_TYPE_ADDRESS: { 926 uint32_t addr = 927 __gen_unpack_uint(iter->p, s, e) << (31 - (e - s)); 928 struct clif_bo *bo = clif_lookup_bo(clif, addr); 929 if (bo) { 930 snprintf(iter->value, sizeof(iter->value), 931 "[%s+0x%08x] /* 0x%08x */", 932 bo->name, addr - bo->offset, addr); 933 } else if (addr) { 934 snprintf(iter->value, sizeof(iter->value), 935 "/* XXX: BO unknown */ 0x%08x", addr); 936 } else { 937 snprintf(iter->value, sizeof(iter->value), 938 "[null]"); 939 } 940 941 break; 942 } 943 944 case V3D_TYPE_OFFSET: 945 snprintf(iter->value, sizeof(iter->value), "0x%08"PRIx64, 946 __gen_unpack_uint(iter->p, s, e) << (31 - (e - s))); 947 break; 948 case V3D_TYPE_STRUCT: 949 snprintf(iter->value, sizeof(iter->value), "<struct %s>", 950 iter->field->type.v3d_struct->name); 951 iter->struct_desc = 952 v3d_spec_find_struct(iter->group->spec, 953 iter->field->type.v3d_struct->name); 954 break; 955 case V3D_TYPE_SFIXED: 956 if (clif->pretty) { 957 snprintf(iter->value, sizeof(iter->value), "%f", 958 __gen_unpack_sfixed(iter->p, s, e, 959 iter->field->type.f)); 960 } else { 961 snprintf(iter->value, sizeof(iter->value), "%u", 962 (unsigned)__gen_unpack_uint(iter->p, s, e)); 963 } 964 break; 965 case V3D_TYPE_UFIXED: 966 if (clif->pretty) { 967 snprintf(iter->value, sizeof(iter->value), "%f", 968 __gen_unpack_ufixed(iter->p, s, e, 969 iter->field->type.f)); 970 } else { 971 snprintf(iter->value, sizeof(iter->value), "%u", 972 (unsigned)__gen_unpack_uint(iter->p, s, e)); 973 } 974 break; 975 case V3D_TYPE_MBO: 976 break; 977 case V3D_TYPE_ENUM: { 978 uint32_t value = __gen_unpack_uint(iter->p, s, e); 979 snprintf(iter->value, sizeof(iter->value), "%d", value); 980 enum_name = v3d_get_enum_name(iter->field->type.v3d_enum, value); 981 break; 982 } 983 } 984 985 if (strlen(iter->group->name) == 0) { 986 int length = strlen(iter->name); 987 snprintf(iter->name + length, sizeof(iter->name) - length, 988 "[%i]", iter->group_iter); 989 } 990 991 if (enum_name) { 992 int length = strlen(iter->value); 993 snprintf(iter->value + length, sizeof(iter->value) - length, 994 " /* %s */", enum_name); 995 } 996 997 return true; 998} 999 1000void 1001v3d_print_group(struct clif_dump *clif, struct v3d_group *group, 1002 uint64_t offset, const uint8_t *p) 1003{ 1004 struct v3d_field_iterator iter; 1005 1006 v3d_field_iterator_init(&iter, group, p); 1007 while (v3d_field_iterator_next(clif, &iter)) { 1008 /* Clif parsing uses the packet name, and expects no 1009 * sub-id. 1010 */ 1011 if (strcmp(iter.field->name, "sub-id") == 0 || 1012 strcmp(iter.field->name, "unused") == 0 || 1013 strcmp(iter.field->name, "Pad") == 0) 1014 continue; 1015 1016 if (clif->pretty) { 1017 fprintf(clif->out, " %s: %s\n", 1018 iter.name, iter.value); 1019 } else { 1020 fprintf(clif->out, " /* %30s: */ %s\n", 1021 iter.name, iter.value); 1022 } 1023 if (iter.struct_desc) { 1024 uint64_t struct_offset = offset + iter.offset; 1025 v3d_print_group(clif, iter.struct_desc, 1026 struct_offset, 1027 &p[iter.offset]); 1028 } 1029 } 1030} 1031