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 32 #include <util/macros.h> 33 34 #include "decoder.h" 35 36 #include "genxml/gen6_xml.h" 37 #include "genxml/gen7_xml.h" 38 #include "genxml/gen75_xml.h" 39 #include "genxml/gen8_xml.h" 40 #include "genxml/gen9_xml.h" 41 42 #define XML_BUFFER_SIZE 4096 43 44 #define MAKE_GEN(major, minor) ( ((major) << 8) | (minor) ) 45 46 struct gen_spec { 47 uint32_t gen; 48 49 int ncommands; 50 struct gen_group *commands[256]; 51 int nstructs; 52 struct gen_group *structs[256]; 53 int nregisters; 54 struct gen_group *registers[256]; 55 int nenums; 56 struct gen_enum *enums[256]; 57 }; 58 59 struct location { 60 const char *filename; 61 int line_number; 62 }; 63 64 struct parser_context { 65 XML_Parser parser; 66 int foo; 67 struct location loc; 68 const char *platform; 69 70 struct gen_group *group; 71 struct gen_enum *enoom; 72 73 int nfields; 74 struct gen_field *fields[128]; 75 76 int nvalues; 77 struct gen_value *values[256]; 78 79 struct gen_spec *spec; 80 }; 81 82 const char * 83 gen_group_get_name(struct gen_group *group) 84 { 85 return group->name; 86 } 87 88 uint32_t 89 gen_group_get_opcode(struct gen_group *group) 90 { 91 return group->opcode; 92 } 93 94 struct gen_group * 95 gen_spec_find_struct(struct gen_spec *spec, const char *name) 96 { 97 for (int i = 0; i < spec->nstructs; i++) 98 if (strcmp(spec->structs[i]->name, name) == 0) 99 return spec->structs[i]; 100 101 return NULL; 102 } 103 104 struct gen_group * 105 gen_spec_find_register(struct gen_spec *spec, uint32_t offset) 106 { 107 for (int i = 0; i < spec->nregisters; i++) 108 if (spec->registers[i]->register_offset == offset) 109 return spec->registers[i]; 110 111 return NULL; 112 } 113 114 struct gen_enum * 115 gen_spec_find_enum(struct gen_spec *spec, const char *name) 116 { 117 for (int i = 0; i < spec->nenums; i++) 118 if (strcmp(spec->enums[i]->name, name) == 0) 119 return spec->enums[i]; 120 121 return NULL; 122 } 123 124 uint32_t 125 gen_spec_get_gen(struct gen_spec *spec) 126 { 127 return spec->gen; 128 } 129 130 static void __attribute__((noreturn)) 131 fail(struct location *loc, const char *msg, ...) 132 { 133 va_list ap; 134 135 va_start(ap, msg); 136 fprintf(stderr, "%s:%d: error: ", 137 loc->filename, loc->line_number); 138 vfprintf(stderr, msg, ap); 139 fprintf(stderr, "\n"); 140 va_end(ap); 141 exit(EXIT_FAILURE); 142 } 143 144 static void * 145 fail_on_null(void *p) 146 { 147 if (p == NULL) { 148 fprintf(stderr, "aubinator: out of memory\n"); 149 exit(EXIT_FAILURE); 150 } 151 152 return p; 153 } 154 155 static char * 156 xstrdup(const char *s) 157 { 158 return fail_on_null(strdup(s)); 159 } 160 161 static void * 162 zalloc(size_t s) 163 { 164 return calloc(s, 1); 165 } 166 167 static void * 168 xzalloc(size_t s) 169 { 170 return fail_on_null(zalloc(s)); 171 } 172 173 static struct gen_group * 174 create_group(struct parser_context *ctx, const char *name, const char **atts) 175 { 176 struct gen_group *group; 177 178 group = xzalloc(sizeof(*group)); 179 if (name) 180 group->name = xstrdup(name); 181 182 group->group_offset = 0; 183 group->group_count = 0; 184 185 return group; 186 } 187 188 static struct gen_enum * 189 create_enum(struct parser_context *ctx, const char *name, const char **atts) 190 { 191 struct gen_enum *e; 192 193 e = xzalloc(sizeof(*e)); 194 if (name) 195 e->name = xstrdup(name); 196 197 e->nvalues = 0; 198 199 return e; 200 } 201 202 static void 203 get_group_offset_count(struct parser_context *ctx, const char *name, 204 const char **atts, uint32_t *offset, uint32_t *count) 205 { 206 char *p; 207 int i; 208 209 for (i = 0; atts[i]; i += 2) { 210 if (strcmp(atts[i], "count") == 0) 211 *count = strtoul(atts[i + 1], &p, 0); 212 else if (strcmp(atts[i], "start") == 0) 213 *offset = strtoul(atts[i + 1], &p, 0); 214 } 215 return; 216 } 217 218 static void 219 get_register_offset(const char **atts, uint32_t *offset) 220 { 221 char *p; 222 int i; 223 224 for (i = 0; atts[i]; i += 2) { 225 if (strcmp(atts[i], "num") == 0) 226 *offset = strtoul(atts[i + 1], &p, 0); 227 } 228 return; 229 } 230 231 static void 232 get_start_end_pos(int *start, int *end) 233 { 234 /* start value has to be mod with 32 as we need the relative 235 * start position in the first DWord. For the end position, add 236 * the length of the field to the start position to get the 237 * relative postion in the 64 bit address. 238 */ 239 if (*end - *start > 32) { 240 int len = *end - *start; 241 *start = *start % 32; 242 *end = *start + len; 243 } else { 244 *start = *start % 32; 245 *end = *end % 32; 246 } 247 248 return; 249 } 250 251 static inline uint64_t 252 mask(int start, int end) 253 { 254 uint64_t v; 255 256 v = ~0ULL >> (63 - end + start); 257 258 return v << start; 259 } 260 261 static inline uint64_t 262 field(uint64_t value, int start, int end) 263 { 264 get_start_end_pos(&start, &end); 265 return (value & mask(start, end)) >> (start); 266 } 267 268 static inline uint64_t 269 field_address(uint64_t value, int start, int end) 270 { 271 /* no need to right shift for address/offset */ 272 get_start_end_pos(&start, &end); 273 return (value & mask(start, end)); 274 } 275 276 static struct gen_type 277 string_to_type(struct parser_context *ctx, const char *s) 278 { 279 int i, f; 280 struct gen_group *g; 281 struct gen_enum *e; 282 283 if (strcmp(s, "int") == 0) 284 return (struct gen_type) { .kind = GEN_TYPE_INT }; 285 else if (strcmp(s, "uint") == 0) 286 return (struct gen_type) { .kind = GEN_TYPE_UINT }; 287 else if (strcmp(s, "bool") == 0) 288 return (struct gen_type) { .kind = GEN_TYPE_BOOL }; 289 else if (strcmp(s, "float") == 0) 290 return (struct gen_type) { .kind = GEN_TYPE_FLOAT }; 291 else if (strcmp(s, "address") == 0) 292 return (struct gen_type) { .kind = GEN_TYPE_ADDRESS }; 293 else if (strcmp(s, "offset") == 0) 294 return (struct gen_type) { .kind = GEN_TYPE_OFFSET }; 295 else if (sscanf(s, "u%d.%d", &i, &f) == 2) 296 return (struct gen_type) { .kind = GEN_TYPE_UFIXED, .i = i, .f = f }; 297 else if (sscanf(s, "s%d.%d", &i, &f) == 2) 298 return (struct gen_type) { .kind = GEN_TYPE_SFIXED, .i = i, .f = f }; 299 else if (g = gen_spec_find_struct(ctx->spec, s), g != NULL) 300 return (struct gen_type) { .kind = GEN_TYPE_STRUCT, .gen_struct = g }; 301 else if (e = gen_spec_find_enum(ctx->spec, s), e != NULL) 302 return (struct gen_type) { .kind = GEN_TYPE_ENUM, .gen_enum = e }; 303 else if (strcmp(s, "mbo") == 0) 304 return (struct gen_type) { .kind = GEN_TYPE_MBO }; 305 else 306 fail(&ctx->loc, "invalid type: %s", s); 307 } 308 309 static struct gen_field * 310 create_field(struct parser_context *ctx, const char **atts) 311 { 312 struct gen_field *field; 313 char *p; 314 int i; 315 316 field = xzalloc(sizeof(*field)); 317 318 for (i = 0; atts[i]; i += 2) { 319 if (strcmp(atts[i], "name") == 0) 320 field->name = xstrdup(atts[i + 1]); 321 else if (strcmp(atts[i], "start") == 0) 322 field->start = ctx->group->group_offset+strtoul(atts[i + 1], &p, 0); 323 else if (strcmp(atts[i], "end") == 0) { 324 field->end = ctx->group->group_offset+strtoul(atts[i + 1], &p, 0); 325 if (ctx->group->group_offset) 326 ctx->group->group_offset = field->end+1; 327 } else if (strcmp(atts[i], "type") == 0) 328 field->type = string_to_type(ctx, atts[i + 1]); 329 else if (strcmp(atts[i], "default") == 0 && 330 field->start >= 16 && field->end <= 31) { 331 field->has_default = true; 332 field->default_value = strtoul(atts[i + 1], &p, 0); 333 } 334 } 335 336 return field; 337 } 338 339 static struct gen_value * 340 create_value(struct parser_context *ctx, const char **atts) 341 { 342 struct gen_value *value = xzalloc(sizeof(*value)); 343 344 for (int i = 0; atts[i]; i += 2) { 345 if (strcmp(atts[i], "name") == 0) 346 value->name = xstrdup(atts[i + 1]); 347 else if (strcmp(atts[i], "value") == 0) 348 value->value = strtoul(atts[i + 1], NULL, 0); 349 } 350 351 return value; 352 } 353 354 static void 355 start_element(void *data, const char *element_name, const char **atts) 356 { 357 struct parser_context *ctx = data; 358 int i; 359 const char *name = NULL; 360 const char *gen = NULL; 361 362 ctx->loc.line_number = XML_GetCurrentLineNumber(ctx->parser); 363 364 for (i = 0; atts[i]; i += 2) { 365 if (strcmp(atts[i], "name") == 0) 366 name = atts[i + 1]; 367 else if (strcmp(atts[i], "gen") == 0) 368 gen = atts[i + 1]; 369 } 370 371 if (strcmp(element_name, "genxml") == 0) { 372 if (name == NULL) 373 fail(&ctx->loc, "no platform name given"); 374 if (gen == NULL) 375 fail(&ctx->loc, "no gen given"); 376 377 ctx->platform = xstrdup(name); 378 int major, minor; 379 int n = sscanf(gen, "%d.%d", &major, &minor); 380 if (n == 0) 381 fail(&ctx->loc, "invalid gen given: %s", gen); 382 if (n == 1) 383 minor = 0; 384 385 ctx->spec->gen = MAKE_GEN(major, minor); 386 } else if (strcmp(element_name, "instruction") == 0 || 387 strcmp(element_name, "struct") == 0) { 388 ctx->group = create_group(ctx, name, atts); 389 } else if (strcmp(element_name, "register") == 0) { 390 ctx->group = create_group(ctx, name, atts); 391 get_register_offset(atts, &ctx->group->register_offset); 392 } else if (strcmp(element_name, "group") == 0) { 393 get_group_offset_count(ctx, name, atts, &ctx->group->group_offset, 394 &ctx->group->group_count); 395 } else if (strcmp(element_name, "field") == 0) { 396 do { 397 ctx->fields[ctx->nfields++] = create_field(ctx, atts); 398 if (ctx->group->group_count) 399 ctx->group->group_count--; 400 } while (ctx->group->group_count > 0); 401 } else if (strcmp(element_name, "enum") == 0) { 402 ctx->enoom = create_enum(ctx, name, atts); 403 } else if (strcmp(element_name, "value") == 0) { 404 ctx->values[ctx->nvalues++] = create_value(ctx, atts); 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 size_t size = ctx->nfields * sizeof(ctx->fields[0]); 418 struct gen_group *group = ctx->group; 419 420 group->fields = xzalloc(size); 421 group->nfields = ctx->nfields; 422 memcpy(group->fields, ctx->fields, size); 423 ctx->nfields = 0; 424 ctx->group = NULL; 425 426 for (int i = 0; i < group->nfields; i++) { 427 if (group->fields[i]->start >= 16 && 428 group->fields[i]->end <= 31 && 429 group->fields[i]->has_default) { 430 group->opcode_mask |= 431 mask(group->fields[i]->start % 32, group->fields[i]->end % 32); 432 group->opcode |= 433 group->fields[i]->default_value << group->fields[i]->start; 434 } 435 } 436 437 if (strcmp(name, "instruction") == 0) 438 spec->commands[spec->ncommands++] = group; 439 else if (strcmp(name, "struct") == 0) 440 spec->structs[spec->nstructs++] = group; 441 else if (strcmp(name, "register") == 0) 442 spec->registers[spec->nregisters++] = group; 443 } else if (strcmp(name, "group") == 0) { 444 ctx->group->group_offset = 0; 445 ctx->group->group_count = 0; 446 } else if (strcmp(name, "field") == 0) { 447 assert(ctx->nfields > 0); 448 struct gen_field *field = ctx->fields[ctx->nfields - 1]; 449 size_t size = ctx->nvalues * sizeof(ctx->values[0]); 450 field->inline_enum.values = xzalloc(size); 451 field->inline_enum.nvalues = ctx->nvalues; 452 memcpy(field->inline_enum.values, ctx->values, size); 453 ctx->nvalues = 0; 454 } else if (strcmp(name, "enum") == 0) { 455 struct gen_enum *e = ctx->enoom; 456 size_t size = ctx->nvalues * sizeof(ctx->values[0]); 457 e->values = xzalloc(size); 458 e->nvalues = ctx->nvalues; 459 memcpy(e->values, ctx->values, size); 460 ctx->nvalues = 0; 461 ctx->enoom = NULL; 462 spec->enums[spec->nenums++] = e; 463 } 464 } 465 466 static void 467 character_data(void *data, const XML_Char *s, int len) 468 { 469 } 470 471 static int 472 devinfo_to_gen(const struct gen_device_info *devinfo) 473 { 474 int value = 10 * devinfo->gen; 475 476 if (devinfo->is_baytrail || devinfo->is_haswell) 477 value += 5; 478 479 return value; 480 } 481 482 static const struct { 483 int gen; 484 const uint8_t *data; 485 size_t data_length; 486 } gen_data[] = { 487 { .gen = 60, .data = gen6_xml, .data_length = sizeof(gen6_xml) }, 488 { .gen = 70, .data = gen7_xml, .data_length = sizeof(gen7_xml) }, 489 { .gen = 75, .data = gen75_xml, .data_length = sizeof(gen75_xml) }, 490 { .gen = 80, .data = gen8_xml, .data_length = sizeof(gen8_xml) }, 491 { .gen = 90, .data = gen9_xml, .data_length = sizeof(gen9_xml) } 492 }; 493 494 static const uint8_t * 495 devinfo_to_xml_data(const struct gen_device_info *devinfo, 496 uint32_t *data_length) 497 { 498 int i, gen = devinfo_to_gen(devinfo); 499 500 for (i = 0; i < ARRAY_SIZE(gen_data); i++) { 501 if (gen_data[i].gen == gen) { 502 *data_length = gen_data[i].data_length; 503 return gen_data[i].data; 504 } 505 } 506 507 unreachable("Unknown generation"); 508 return NULL; 509 } 510 511 struct gen_spec * 512 gen_spec_load(const struct gen_device_info *devinfo) 513 { 514 struct parser_context ctx; 515 void *buf; 516 const void *data; 517 uint32_t data_length = 0; 518 519 memset(&ctx, 0, sizeof ctx); 520 ctx.parser = XML_ParserCreate(NULL); 521 XML_SetUserData(ctx.parser, &ctx); 522 if (ctx.parser == NULL) { 523 fprintf(stderr, "failed to create parser\n"); 524 return NULL; 525 } 526 527 XML_SetElementHandler(ctx.parser, start_element, end_element); 528 XML_SetCharacterDataHandler(ctx.parser, character_data); 529 530 ctx.spec = xzalloc(sizeof(*ctx.spec)); 531 532 data = devinfo_to_xml_data(devinfo, &data_length); 533 buf = XML_GetBuffer(ctx.parser, data_length); 534 535 memcpy(buf, data, data_length); 536 537 if (XML_ParseBuffer(ctx.parser, data_length, true) == 0) { 538 fprintf(stderr, 539 "Error parsing XML at line %ld col %ld: %s\n", 540 XML_GetCurrentLineNumber(ctx.parser), 541 XML_GetCurrentColumnNumber(ctx.parser), 542 XML_ErrorString(XML_GetErrorCode(ctx.parser))); 543 XML_ParserFree(ctx.parser); 544 return NULL; 545 } 546 547 XML_ParserFree(ctx.parser); 548 549 return ctx.spec; 550 } 551 552 struct gen_spec * 553 gen_spec_load_from_path(const struct gen_device_info *devinfo, 554 const char *path) 555 { 556 struct parser_context ctx; 557 size_t len, filename_len = strlen(path) + 20; 558 char *filename = malloc(filename_len); 559 void *buf; 560 FILE *input; 561 562 len = snprintf(filename, filename_len, "%s/gen%i.xml", 563 path, devinfo_to_gen(devinfo)); 564 assert(len < filename_len); 565 566 input = fopen(filename, "r"); 567 if (input == NULL) { 568 fprintf(stderr, "failed to open xml description\n"); 569 free(filename); 570 return NULL; 571 } 572 573 memset(&ctx, 0, sizeof ctx); 574 ctx.parser = XML_ParserCreate(NULL); 575 XML_SetUserData(ctx.parser, &ctx); 576 if (ctx.parser == NULL) { 577 fprintf(stderr, "failed to create parser\n"); 578 fclose(input); 579 free(filename); 580 return NULL; 581 } 582 583 XML_SetElementHandler(ctx.parser, start_element, end_element); 584 XML_SetCharacterDataHandler(ctx.parser, character_data); 585 ctx.loc.filename = filename; 586 ctx.spec = xzalloc(sizeof(*ctx.spec)); 587 588 do { 589 buf = XML_GetBuffer(ctx.parser, XML_BUFFER_SIZE); 590 len = fread(buf, 1, XML_BUFFER_SIZE, input); 591 if (len < 0) { 592 fprintf(stderr, "fread: %m\n"); 593 fclose(input); 594 free(filename); 595 return NULL; 596 } 597 if (XML_ParseBuffer(ctx.parser, len, len == 0) == 0) { 598 fprintf(stderr, 599 "Error parsing XML at line %ld col %ld: %s\n", 600 XML_GetCurrentLineNumber(ctx.parser), 601 XML_GetCurrentColumnNumber(ctx.parser), 602 XML_ErrorString(XML_GetErrorCode(ctx.parser))); 603 fclose(input); 604 free(filename); 605 return NULL; 606 } 607 } while (len > 0); 608 609 XML_ParserFree(ctx.parser); 610 611 fclose(input); 612 free(filename); 613 614 return ctx.spec; 615 } 616 617 struct gen_group * 618 gen_spec_find_instruction(struct gen_spec *spec, const uint32_t *p) 619 { 620 for (int i = 0; i < spec->ncommands; i++) { 621 uint32_t opcode = *p & spec->commands[i]->opcode_mask; 622 if (opcode == spec->commands[i]->opcode) 623 return spec->commands[i]; 624 } 625 626 return NULL; 627 } 628 629 int 630 gen_group_get_length(struct gen_group *group, const uint32_t *p) 631 { 632 uint32_t h = p[0]; 633 uint32_t type = field(h, 29, 31); 634 635 switch (type) { 636 case 0: /* MI */ { 637 uint32_t opcode = field(h, 23, 28); 638 if (opcode < 16) 639 return 1; 640 else 641 return field(h, 0, 7) + 2; 642 break; 643 } 644 645 case 3: /* Render */ { 646 uint32_t subtype = field(h, 27, 28); 647 switch (subtype) { 648 case 0: 649 return field(h, 0, 7) + 2; 650 case 1: 651 return 1; 652 case 2: 653 return 2; 654 case 3: 655 return field(h, 0, 7) + 2; 656 } 657 } 658 } 659 660 unreachable("bad opcode"); 661 } 662 663 void 664 gen_field_iterator_init(struct gen_field_iterator *iter, 665 struct gen_group *group, 666 const uint32_t *p, 667 bool print_colors) 668 { 669 iter->group = group; 670 iter->p = p; 671 iter->i = 0; 672 iter->print_colors = print_colors; 673 } 674 675 static void 676 gen_enum_write_value(char *str, size_t max_length, 677 struct gen_enum *e, uint64_t value) 678 { 679 for (int i = 0; i < e->nvalues; i++) { 680 if (e->values[i]->value == value) { 681 strncpy(str, e->values[i]->name, max_length); 682 return; 683 } 684 } 685 } 686 687 bool 688 gen_field_iterator_next(struct gen_field_iterator *iter) 689 { 690 struct gen_field *f; 691 union { 692 uint64_t qw; 693 float f; 694 } v; 695 696 if (iter->i == iter->group->nfields) 697 return false; 698 699 f = iter->group->fields[iter->i++]; 700 iter->name = f->name; 701 int index = f->start / 32; 702 703 if ((f->end - f->start) > 32) 704 v.qw = ((uint64_t) iter->p[index+1] << 32) | iter->p[index]; 705 else 706 v.qw = iter->p[index]; 707 708 iter->description[0] = '\0'; 709 710 switch (f->type.kind) { 711 case GEN_TYPE_UNKNOWN: 712 case GEN_TYPE_INT: { 713 uint64_t value = field(v.qw, f->start, f->end); 714 snprintf(iter->value, sizeof(iter->value), 715 "%"PRId64, value); 716 gen_enum_write_value(iter->description, sizeof(iter->description), 717 &f->inline_enum, value); 718 break; 719 } 720 case GEN_TYPE_UINT: { 721 uint64_t value = field(v.qw, f->start, f->end); 722 snprintf(iter->value, sizeof(iter->value), 723 "%"PRIu64, value); 724 gen_enum_write_value(iter->description, sizeof(iter->description), 725 &f->inline_enum, value); 726 break; 727 } 728 case GEN_TYPE_BOOL: { 729 const char *true_string = 730 iter->print_colors ? "\e[0;35mtrue\e[0m" : "true"; 731 snprintf(iter->value, sizeof(iter->value), 732 "%s", field(v.qw, f->start, f->end) ? true_string : "false"); 733 break; 734 } 735 case GEN_TYPE_FLOAT: 736 snprintf(iter->value, sizeof(iter->value), "%f", v.f); 737 break; 738 case GEN_TYPE_ADDRESS: 739 case GEN_TYPE_OFFSET: 740 snprintf(iter->value, sizeof(iter->value), 741 "0x%08"PRIx64, field_address(v.qw, f->start, f->end)); 742 break; 743 case GEN_TYPE_STRUCT: 744 snprintf(iter->value, sizeof(iter->value), 745 "<struct %s %d>", f->type.gen_struct->name, (f->start / 32)); 746 break; 747 case GEN_TYPE_UFIXED: 748 snprintf(iter->value, sizeof(iter->value), 749 "%f", (float) field(v.qw, f->start, f->end) / (1 << f->type.f)); 750 break; 751 case GEN_TYPE_SFIXED: 752 /* FIXME: Sign extend extracted field. */ 753 snprintf(iter->value, sizeof(iter->value), "%s", "foo"); 754 break; 755 case GEN_TYPE_MBO: 756 break; 757 case GEN_TYPE_ENUM: { 758 uint64_t value = field(v.qw, f->start, f->end); 759 snprintf(iter->value, sizeof(iter->value), 760 "%"PRId64, value); 761 gen_enum_write_value(iter->description, sizeof(iter->description), 762 f->type.gen_enum, value); 763 break; 764 } 765 } 766 767 return true; 768 } 769