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