mesa/src/broadcom/cle/v3d_decoder.c
Eric Anholt 725561c0b6 v3d: Switch v3d_decoder.c to the XML's top min_ver/max_ver fields.
The XML zipper wants one XML per version for filling out its tables, but
we want to do more than one GPU version per XML now.  Assume that the
"gen" field will be the same as min_ver and look up our XML text assuming
that they're listed in increasing min_ver.
2018-06-29 13:36:28 -07:00

940 lines
30 KiB
C

/*
* Copyright © 2016 Intel Corporation
* Copyright © 2017 Broadcom
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include <stdio.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdarg.h>
#include <string.h>
#include <expat.h>
#include <inttypes.h>
#include <zlib.h>
#include <util/macros.h>
#include <util/ralloc.h>
#include "v3d_decoder.h"
#include "v3d_packet_helpers.h"
#include "v3d_xml.h"
struct v3d_spec {
uint32_t ver;
int ncommands;
struct v3d_group *commands[256];
int nstructs;
struct v3d_group *structs[256];
int nregisters;
struct v3d_group *registers[256];
int nenums;
struct v3d_enum *enums[256];
};
struct location {
const char *filename;
int line_number;
};
struct parser_context {
XML_Parser parser;
const struct v3d_device_info *devinfo;
int foo;
struct location loc;
struct v3d_group *group;
struct v3d_enum *enoom;
int nvalues;
struct v3d_value *values[256];
struct v3d_spec *spec;
int parse_depth;
int parse_skip_depth;
};
const char *
v3d_group_get_name(struct v3d_group *group)
{
return group->name;
}
uint8_t
v3d_group_get_opcode(struct v3d_group *group)
{
return group->opcode;
}
struct v3d_group *
v3d_spec_find_struct(struct v3d_spec *spec, const char *name)
{
for (int i = 0; i < spec->nstructs; i++)
if (strcmp(spec->structs[i]->name, name) == 0)
return spec->structs[i];
return NULL;
}
struct v3d_group *
v3d_spec_find_register(struct v3d_spec *spec, uint32_t offset)
{
for (int i = 0; i < spec->nregisters; i++)
if (spec->registers[i]->register_offset == offset)
return spec->registers[i];
return NULL;
}
struct v3d_group *
v3d_spec_find_register_by_name(struct v3d_spec *spec, const char *name)
{
for (int i = 0; i < spec->nregisters; i++) {
if (strcmp(spec->registers[i]->name, name) == 0)
return spec->registers[i];
}
return NULL;
}
struct v3d_enum *
v3d_spec_find_enum(struct v3d_spec *spec, const char *name)
{
for (int i = 0; i < spec->nenums; i++)
if (strcmp(spec->enums[i]->name, name) == 0)
return spec->enums[i];
return NULL;
}
static void __attribute__((noreturn))
fail(struct location *loc, const char *msg, ...)
{
va_list ap;
va_start(ap, msg);
fprintf(stderr, "%s:%d: error: ",
loc->filename, loc->line_number);
vfprintf(stderr, msg, ap);
fprintf(stderr, "\n");
va_end(ap);
exit(EXIT_FAILURE);
}
static void *
fail_on_null(void *p)
{
if (p == NULL) {
fprintf(stderr, "aubinator: out of memory\n");
exit(EXIT_FAILURE);
}
return p;
}
static char *
xstrdup(const char *s)
{
return fail_on_null(strdup(s));
}
static void *
zalloc(size_t s)
{
return calloc(s, 1);
}
static void *
xzalloc(size_t s)
{
return fail_on_null(zalloc(s));
}
/* We allow fields to have either a bit index, or append "b" for a byte index.
*/
static bool
is_byte_offset(const char *value)
{
return value[strlen(value) - 1] == 'b';
}
static void
get_group_offset_count(const char **atts, uint32_t *offset, uint32_t *count,
uint32_t *size, bool *variable)
{
char *p;
int i;
for (i = 0; atts[i]; i += 2) {
if (strcmp(atts[i], "count") == 0) {
*count = strtoul(atts[i + 1], &p, 0);
if (*count == 0)
*variable = true;
} else if (strcmp(atts[i], "start") == 0) {
*offset = strtoul(atts[i + 1], &p, 0);
} else if (strcmp(atts[i], "size") == 0) {
*size = strtoul(atts[i + 1], &p, 0);
}
}
return;
}
static struct v3d_group *
create_group(struct parser_context *ctx,
const char *name,
const char **atts,
struct v3d_group *parent)
{
struct v3d_group *group;
group = xzalloc(sizeof(*group));
if (name)
group->name = xstrdup(name);
group->spec = ctx->spec;
group->group_offset = 0;
group->group_count = 0;
group->variable = false;
if (parent) {
group->parent = parent;
get_group_offset_count(atts,
&group->group_offset,
&group->group_count,
&group->group_size,
&group->variable);
}
return group;
}
static struct v3d_enum *
create_enum(struct parser_context *ctx, const char *name, const char **atts)
{
struct v3d_enum *e;
e = xzalloc(sizeof(*e));
if (name)
e->name = xstrdup(name);
e->nvalues = 0;
return e;
}
static void
get_register_offset(const char **atts, uint32_t *offset)
{
char *p;
int i;
for (i = 0; atts[i]; i += 2) {
if (strcmp(atts[i], "num") == 0)
*offset = strtoul(atts[i + 1], &p, 0);
}
return;
}
static void
get_start_end_pos(int *start, int *end)
{
/* start value has to be mod with 32 as we need the relative
* start position in the first DWord. For the end position, add
* the length of the field to the start position to get the
* relative postion in the 64 bit address.
*/
if (*end - *start > 32) {
int len = *end - *start;
*start = *start % 32;
*end = *start + len;
} else {
*start = *start % 32;
*end = *end % 32;
}
return;
}
static inline uint64_t
mask(int start, int end)
{
uint64_t v;
v = ~0ULL >> (63 - end + start);
return v << start;
}
static inline uint64_t
field(uint64_t value, int start, int end)
{
get_start_end_pos(&start, &end);
return (value & mask(start, end)) >> (start);
}
static inline uint64_t
field_address(uint64_t value, int start, int end)
{
/* no need to right shift for address/offset */
get_start_end_pos(&start, &end);
return (value & mask(start, end));
}
static struct v3d_type
string_to_type(struct parser_context *ctx, const char *s)
{
int i, f;
struct v3d_group *g;
struct v3d_enum *e;
if (strcmp(s, "int") == 0)
return (struct v3d_type) { .kind = V3D_TYPE_INT };
else if (strcmp(s, "uint") == 0)
return (struct v3d_type) { .kind = V3D_TYPE_UINT };
else if (strcmp(s, "bool") == 0)
return (struct v3d_type) { .kind = V3D_TYPE_BOOL };
else if (strcmp(s, "float") == 0)
return (struct v3d_type) { .kind = V3D_TYPE_FLOAT };
else if (strcmp(s, "address") == 0)
return (struct v3d_type) { .kind = V3D_TYPE_ADDRESS };
else if (strcmp(s, "offset") == 0)
return (struct v3d_type) { .kind = V3D_TYPE_OFFSET };
else if (sscanf(s, "u%d.%d", &i, &f) == 2)
return (struct v3d_type) { .kind = V3D_TYPE_UFIXED, .i = i, .f = f };
else if (sscanf(s, "s%d.%d", &i, &f) == 2)
return (struct v3d_type) { .kind = V3D_TYPE_SFIXED, .i = i, .f = f };
else if (g = v3d_spec_find_struct(ctx->spec, s), g != NULL)
return (struct v3d_type) { .kind = V3D_TYPE_STRUCT, .v3d_struct = g };
else if (e = v3d_spec_find_enum(ctx->spec, s), e != NULL)
return (struct v3d_type) { .kind = V3D_TYPE_ENUM, .v3d_enum = e };
else if (strcmp(s, "mbo") == 0)
return (struct v3d_type) { .kind = V3D_TYPE_MBO };
else
fail(&ctx->loc, "invalid type: %s", s);
}
static struct v3d_field *
create_field(struct parser_context *ctx, const char **atts)
{
struct v3d_field *field;
char *p;
int i;
uint32_t size = 0;
field = xzalloc(sizeof(*field));
for (i = 0; atts[i]; i += 2) {
if (strcmp(atts[i], "name") == 0)
field->name = xstrdup(atts[i + 1]);
else if (strcmp(atts[i], "start") == 0) {
field->start = strtoul(atts[i + 1], &p, 0);
if (is_byte_offset(atts[i + 1]))
field->start *= 8;
} else if (strcmp(atts[i], "end") == 0) {
field->end = strtoul(atts[i + 1], &p, 0) - 1;
if (is_byte_offset(atts[i + 1]))
field->end *= 8;
} else if (strcmp(atts[i], "size") == 0) {
size = strtoul(atts[i + 1], &p, 0);
if (is_byte_offset(atts[i + 1]))
size *= 8;
} else if (strcmp(atts[i], "type") == 0)
field->type = string_to_type(ctx, atts[i + 1]);
else if (strcmp(atts[i], "default") == 0) {
field->has_default = true;
field->default_value = strtoul(atts[i + 1], &p, 0);
} else if (strcmp(atts[i], "minus_one") == 0) {
assert(strcmp(atts[i + 1], "true") == 0);
field->minus_one = true;
}
}
if (size)
field->end = field->start + size - 1;
return field;
}
static struct v3d_value *
create_value(struct parser_context *ctx, const char **atts)
{
struct v3d_value *value = xzalloc(sizeof(*value));
for (int i = 0; atts[i]; i += 2) {
if (strcmp(atts[i], "name") == 0)
value->name = xstrdup(atts[i + 1]);
else if (strcmp(atts[i], "value") == 0)
value->value = strtoul(atts[i + 1], NULL, 0);
}
return value;
}
static void
create_and_append_field(struct parser_context *ctx,
const char **atts)
{
if (ctx->group->nfields == ctx->group->fields_size) {
ctx->group->fields_size = MAX2(ctx->group->fields_size * 2, 2);
ctx->group->fields =
(struct v3d_field **) realloc(ctx->group->fields,
sizeof(ctx->group->fields[0]) *
ctx->group->fields_size);
}
ctx->group->fields[ctx->group->nfields++] = create_field(ctx, atts);
}
static void
set_group_opcode(struct v3d_group *group, const char **atts)
{
char *p;
int i;
for (i = 0; atts[i]; i += 2) {
if (strcmp(atts[i], "code") == 0)
group->opcode = strtoul(atts[i + 1], &p, 0);
}
return;
}
static bool
ver_in_range(int ver, int min_ver, int max_ver)
{
return ((min_ver == 0 || ver >= min_ver) &&
(max_ver == 0 || ver <= max_ver));
}
static bool
skip_if_ver_mismatch(struct parser_context *ctx, int min_ver, int max_ver)
{
if (!ctx->parse_skip_depth && !ver_in_range(ctx->devinfo->ver,
min_ver, max_ver)) {
assert(ctx->parse_depth != 0);
ctx->parse_skip_depth = ctx->parse_depth;
}
return ctx->parse_skip_depth;
}
static void
start_element(void *data, const char *element_name, const char **atts)
{
struct parser_context *ctx = data;
int i;
const char *name = NULL;
const char *ver = NULL;
int min_ver = 0;
int max_ver = 0;
ctx->loc.line_number = XML_GetCurrentLineNumber(ctx->parser);
for (i = 0; atts[i]; i += 2) {
if (strcmp(atts[i], "name") == 0)
name = atts[i + 1];
else if (strcmp(atts[i], "gen") == 0)
ver = atts[i + 1];
else if (strcmp(atts[i], "min_ver") == 0)
min_ver = strtoul(atts[i + 1], NULL, 0);
else if (strcmp(atts[i], "max_ver") == 0)
max_ver = strtoul(atts[i + 1], NULL, 0);
}
if (skip_if_ver_mismatch(ctx, min_ver, max_ver))
goto skip;
if (strcmp(element_name, "vcxml") == 0) {
if (ver == NULL)
fail(&ctx->loc, "no ver given");
/* Make sure that we picked an XML that matched our version.
*/
assert(ver_in_range(ctx->devinfo->ver, min_ver, max_ver));
int major, minor;
int n = sscanf(ver, "%d.%d", &major, &minor);
if (n == 0)
fail(&ctx->loc, "invalid ver given: %s", ver);
if (n == 1)
minor = 0;
ctx->spec->ver = major * 10 + minor;
} else if (strcmp(element_name, "packet") == 0 ||
strcmp(element_name, "struct") == 0) {
ctx->group = create_group(ctx, name, atts, NULL);
if (strcmp(element_name, "packet") == 0)
set_group_opcode(ctx->group, atts);
} else if (strcmp(element_name, "register") == 0) {
ctx->group = create_group(ctx, name, atts, NULL);
get_register_offset(atts, &ctx->group->register_offset);
} else if (strcmp(element_name, "group") == 0) {
struct v3d_group *previous_group = ctx->group;
while (previous_group->next)
previous_group = previous_group->next;
struct v3d_group *group = create_group(ctx, "", atts,
ctx->group);
previous_group->next = group;
ctx->group = group;
} else if (strcmp(element_name, "field") == 0) {
create_and_append_field(ctx, atts);
} else if (strcmp(element_name, "enum") == 0) {
ctx->enoom = create_enum(ctx, name, atts);
} else if (strcmp(element_name, "value") == 0) {
ctx->values[ctx->nvalues++] = create_value(ctx, atts);
assert(ctx->nvalues < ARRAY_SIZE(ctx->values));
}
skip:
ctx->parse_depth++;
}
static void
end_element(void *data, const char *name)
{
struct parser_context *ctx = data;
struct v3d_spec *spec = ctx->spec;
ctx->parse_depth--;
if (ctx->parse_skip_depth) {
if (ctx->parse_skip_depth == ctx->parse_depth)
ctx->parse_skip_depth = 0;
return;
}
if (strcmp(name, "packet") == 0 ||
strcmp(name, "struct") == 0 ||
strcmp(name, "register") == 0) {
struct v3d_group *group = ctx->group;
ctx->group = ctx->group->parent;
if (strcmp(name, "packet") == 0) {
spec->commands[spec->ncommands++] = group;
/* V3D packet XML has the packet contents with offsets
* starting from the first bit after the opcode, to
* match the spec. Shift the fields up now.
*/
for (int i = 0; i < group->nfields; i++) {
group->fields[i]->start += 8;
group->fields[i]->end += 8;
}
}
else if (strcmp(name, "struct") == 0)
spec->structs[spec->nstructs++] = group;
else if (strcmp(name, "register") == 0)
spec->registers[spec->nregisters++] = group;
assert(spec->ncommands < ARRAY_SIZE(spec->commands));
assert(spec->nstructs < ARRAY_SIZE(spec->structs));
assert(spec->nregisters < ARRAY_SIZE(spec->registers));
} else if (strcmp(name, "group") == 0) {
ctx->group = ctx->group->parent;
} else if (strcmp(name, "field") == 0) {
assert(ctx->group->nfields > 0);
struct v3d_field *field = ctx->group->fields[ctx->group->nfields - 1];
size_t size = ctx->nvalues * sizeof(ctx->values[0]);
field->inline_enum.values = xzalloc(size);
field->inline_enum.nvalues = ctx->nvalues;
memcpy(field->inline_enum.values, ctx->values, size);
ctx->nvalues = 0;
} else if (strcmp(name, "enum") == 0) {
struct v3d_enum *e = ctx->enoom;
size_t size = ctx->nvalues * sizeof(ctx->values[0]);
e->values = xzalloc(size);
e->nvalues = ctx->nvalues;
memcpy(e->values, ctx->values, size);
ctx->nvalues = 0;
ctx->enoom = NULL;
spec->enums[spec->nenums++] = e;
}
}
static void
character_data(void *data, const XML_Char *s, int len)
{
}
static uint32_t zlib_inflate(const void *compressed_data,
uint32_t compressed_len,
void **out_ptr)
{
struct z_stream_s zstream;
void *out;
memset(&zstream, 0, sizeof(zstream));
zstream.next_in = (unsigned char *)compressed_data;
zstream.avail_in = compressed_len;
if (inflateInit(&zstream) != Z_OK)
return 0;
out = malloc(4096);
zstream.next_out = out;
zstream.avail_out = 4096;
do {
switch (inflate(&zstream, Z_SYNC_FLUSH)) {
case Z_STREAM_END:
goto end;
case Z_OK:
break;
default:
inflateEnd(&zstream);
return 0;
}
if (zstream.avail_out)
break;
out = realloc(out, 2*zstream.total_out);
if (out == NULL) {
inflateEnd(&zstream);
return 0;
}
zstream.next_out = (unsigned char *)out + zstream.total_out;
zstream.avail_out = zstream.total_out;
} while (1);
end:
inflateEnd(&zstream);
*out_ptr = out;
return zstream.total_out;
}
struct v3d_spec *
v3d_spec_load(const struct v3d_device_info *devinfo)
{
struct parser_context ctx;
void *buf;
uint8_t *text_data = NULL;
uint32_t text_offset = 0, text_length = 0, total_length;
for (int i = 0; i < ARRAY_SIZE(genxml_files_table); i++) {
if (i != 0) {
assert(genxml_files_table[i - 1].gen_10 <
genxml_files_table[i].gen_10);
}
if (genxml_files_table[i].gen_10 <= devinfo->ver) {
text_offset = genxml_files_table[i].offset;
text_length = genxml_files_table[i].length;
}
}
if (text_length == 0) {
fprintf(stderr, "unable to find gen (%u) data\n", devinfo->ver);
return NULL;
}
memset(&ctx, 0, sizeof ctx);
ctx.parser = XML_ParserCreate(NULL);
ctx.devinfo = devinfo;
XML_SetUserData(ctx.parser, &ctx);
if (ctx.parser == NULL) {
fprintf(stderr, "failed to create parser\n");
return NULL;
}
XML_SetElementHandler(ctx.parser, start_element, end_element);
XML_SetCharacterDataHandler(ctx.parser, character_data);
ctx.spec = xzalloc(sizeof(*ctx.spec));
total_length = zlib_inflate(compress_genxmls,
sizeof(compress_genxmls),
(void **) &text_data);
assert(text_offset + text_length <= total_length);
buf = XML_GetBuffer(ctx.parser, text_length);
memcpy(buf, &text_data[text_offset], text_length);
if (XML_ParseBuffer(ctx.parser, text_length, true) == 0) {
fprintf(stderr,
"Error parsing XML at line %ld col %ld byte %ld/%u: %s\n",
XML_GetCurrentLineNumber(ctx.parser),
XML_GetCurrentColumnNumber(ctx.parser),
XML_GetCurrentByteIndex(ctx.parser), text_length,
XML_ErrorString(XML_GetErrorCode(ctx.parser)));
XML_ParserFree(ctx.parser);
free(text_data);
return NULL;
}
XML_ParserFree(ctx.parser);
free(text_data);
return ctx.spec;
}
struct v3d_group *
v3d_spec_find_instruction(struct v3d_spec *spec, const uint8_t *p)
{
uint8_t opcode = *p;
for (int i = 0; i < spec->ncommands; i++) {
struct v3d_group *group = spec->commands[i];
if (opcode != group->opcode)
continue;
/* If there's a "sub-id" field, make sure that it matches the
* instruction being decoded.
*/
struct v3d_field *subid = NULL;
for (int j = 0; j < group->nfields; j++) {
struct v3d_field *field = group->fields[j];
if (strcmp(field->name, "sub-id") == 0) {
subid = field;
break;
}
}
if (subid && (__gen_unpack_uint(p, subid->start, subid->end) !=
subid->default_value)) {
continue;
}
return group;
}
return NULL;
}
/** Returns the size of a V3D packet. */
int
v3d_group_get_length(struct v3d_group *group)
{
int last_bit = 0;
for (int i = 0; i < group->nfields; i++) {
struct v3d_field *field = group->fields[i];
last_bit = MAX2(last_bit, field->end);
}
return last_bit / 8 + 1;
}
void
v3d_field_iterator_init(struct v3d_field_iterator *iter,
struct v3d_group *group,
const uint8_t *p,
bool print_colors)
{
memset(iter, 0, sizeof(*iter));
iter->group = group;
iter->p = p;
iter->print_colors = print_colors;
}
static const char *
v3d_get_enum_name(struct v3d_enum *e, uint64_t value)
{
for (int i = 0; i < e->nvalues; i++) {
if (e->values[i]->value == value) {
return e->values[i]->name;
}
}
return NULL;
}
static bool
iter_more_fields(const struct v3d_field_iterator *iter)
{
return iter->field_iter < iter->group->nfields;
}
static uint32_t
iter_group_offset_bits(const struct v3d_field_iterator *iter,
uint32_t group_iter)
{
return iter->group->group_offset + (group_iter *
iter->group->group_size);
}
static bool
iter_more_groups(const struct v3d_field_iterator *iter)
{
if (iter->group->variable) {
return iter_group_offset_bits(iter, iter->group_iter + 1) <
(v3d_group_get_length(iter->group) * 8);
} else {
return (iter->group_iter + 1) < iter->group->group_count ||
iter->group->next != NULL;
}
}
static void
iter_advance_group(struct v3d_field_iterator *iter)
{
if (iter->group->variable)
iter->group_iter++;
else {
if ((iter->group_iter + 1) < iter->group->group_count) {
iter->group_iter++;
} else {
iter->group = iter->group->next;
iter->group_iter = 0;
}
}
iter->field_iter = 0;
}
static bool
iter_advance_field(struct v3d_field_iterator *iter)
{
while (!iter_more_fields(iter)) {
if (!iter_more_groups(iter))
return false;
iter_advance_group(iter);
}
iter->field = iter->group->fields[iter->field_iter++];
if (iter->field->name)
strncpy(iter->name, iter->field->name, sizeof(iter->name));
else
memset(iter->name, 0, sizeof(iter->name));
iter->offset = iter_group_offset_bits(iter, iter->group_iter) / 8 +
iter->field->start / 8;
iter->struct_desc = NULL;
return true;
}
bool
v3d_field_iterator_next(struct v3d_field_iterator *iter)
{
if (!iter_advance_field(iter))
return false;
const char *enum_name = NULL;
int group_member_offset =
iter_group_offset_bits(iter, iter->group_iter);
int s = group_member_offset + iter->field->start;
int e = group_member_offset + iter->field->end;
assert(!iter->field->minus_one ||
iter->field->type.kind == V3D_TYPE_INT ||
iter->field->type.kind == V3D_TYPE_UINT);
switch (iter->field->type.kind) {
case V3D_TYPE_UNKNOWN:
case V3D_TYPE_INT: {
uint32_t value = __gen_unpack_sint(iter->p, s, e);
if (iter->field->minus_one)
value++;
snprintf(iter->value, sizeof(iter->value), "%d", value);
enum_name = v3d_get_enum_name(&iter->field->inline_enum, value);
break;
}
case V3D_TYPE_UINT: {
uint32_t value = __gen_unpack_uint(iter->p, s, e);
if (iter->field->minus_one)
value++;
snprintf(iter->value, sizeof(iter->value), "%u", value);
enum_name = v3d_get_enum_name(&iter->field->inline_enum, value);
break;
}
case V3D_TYPE_BOOL: {
const char *true_string =
iter->print_colors ? "\e[0;35mtrue\e[0m" : "true";
snprintf(iter->value, sizeof(iter->value), "%s",
__gen_unpack_uint(iter->p, s, e) ?
true_string : "false");
break;
}
case V3D_TYPE_FLOAT:
snprintf(iter->value, sizeof(iter->value), "%f",
__gen_unpack_float(iter->p, s, e));
break;
case V3D_TYPE_ADDRESS:
case V3D_TYPE_OFFSET:
snprintf(iter->value, sizeof(iter->value), "0x%08"PRIx64,
__gen_unpack_uint(iter->p, s, e) << (31 - (e - s)));
break;
case V3D_TYPE_STRUCT:
snprintf(iter->value, sizeof(iter->value), "<struct %s>",
iter->field->type.v3d_struct->name);
iter->struct_desc =
v3d_spec_find_struct(iter->group->spec,
iter->field->type.v3d_struct->name);
break;
case V3D_TYPE_SFIXED:
snprintf(iter->value, sizeof(iter->value), "%f",
__gen_unpack_sfixed(iter->p, s, e,
iter->field->type.f));
break;
case V3D_TYPE_UFIXED:
snprintf(iter->value, sizeof(iter->value), "%f",
__gen_unpack_ufixed(iter->p, s, e,
iter->field->type.f));
break;
case V3D_TYPE_MBO:
break;
case V3D_TYPE_ENUM: {
uint32_t value = __gen_unpack_uint(iter->p, s, e);
snprintf(iter->value, sizeof(iter->value), "%d", value);
enum_name = v3d_get_enum_name(iter->field->type.v3d_enum, value);
break;
}
}
if (strlen(iter->group->name) == 0) {
int length = strlen(iter->name);
snprintf(iter->name + length, sizeof(iter->name) - length,
"[%i]", iter->group_iter);
}
if (enum_name) {
int length = strlen(iter->value);
snprintf(iter->value + length, sizeof(iter->value) - length,
" (%s)", enum_name);
}
return true;
}
void
v3d_print_group(FILE *outfile, struct v3d_group *group,
uint64_t offset, const uint8_t *p, bool color)
{
struct v3d_field_iterator iter;
v3d_field_iterator_init(&iter, group, p, color);
while (v3d_field_iterator_next(&iter)) {
fprintf(outfile, " %s: %s\n", iter.name, iter.value);
if (iter.struct_desc) {
uint64_t struct_offset = offset + iter.offset;
v3d_print_group(outfile, iter.struct_desc,
struct_offset,
&p[iter.offset], color);
}
}
}