v3d: Pass the whole clif_dump structure to v3d_print_group().
[mesa.git] / src / broadcom / cle / v3d_decoder.c
index ac33d87191c7b99f4fb43e5872bd86e664578129..de57e5f5acbed0a8b9005d4632fb895b4d50c0b9 100644 (file)
@@ -37,6 +37,7 @@
 #include "v3d_decoder.h"
 #include "v3d_packet_helpers.h"
 #include "v3d_xml.h"
+#include "broadcom/clif/clif_private.h"
 
 struct v3d_spec {
         uint32_t ver;
@@ -58,6 +59,7 @@ struct location {
 
 struct parser_context {
         XML_Parser parser;
+        const struct v3d_device_info *devinfo;
         int foo;
         struct location loc;
 
@@ -68,6 +70,9 @@ struct parser_context {
         struct v3d_value *values[256];
 
         struct v3d_spec *spec;
+
+        int parse_depth;
+        int parse_skip_depth;
 };
 
 const char *
@@ -356,10 +361,12 @@ create_field(struct parser_context *ctx, const char **atts)
                                 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->start >= 16 && field->end <= 31) {
+                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;
                 }
         }
 
@@ -412,6 +419,25 @@ set_group_opcode(struct v3d_group *group, const char **atts)
         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)
 {
@@ -419,6 +445,8 @@ start_element(void *data, const char *element_name, const char **atts)
         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);
 
@@ -427,12 +455,23 @@ start_element(void *data, const char *element_name, const char **atts)
                         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)
@@ -468,6 +507,8 @@ start_element(void *data, const char *element_name, const char **atts)
                 assert(ctx->nvalues < ARRAY_SIZE(ctx->values));
         }
 
+skip:
+        ctx->parse_depth++;
 }
 
 static void
@@ -476,6 +517,14 @@ 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) {
@@ -587,10 +636,14 @@ v3d_spec_load(const struct v3d_device_info *devinfo)
         uint32_t text_offset = 0, text_length = 0, total_length;
 
         for (int i = 0; i < ARRAY_SIZE(genxml_files_table); i++) {
-                if (genxml_files_table[i].gen_10 == devinfo->ver) {
+                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;
-                        break;
                 }
         }
 
@@ -601,6 +654,7 @@ v3d_spec_load(const struct v3d_device_info *devinfo)
 
         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");
@@ -641,10 +695,32 @@ v3d_spec_load(const struct v3d_device_info *devinfo)
 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++) {
-                uint8_t opcode = *p;
-                if (opcode == spec->commands[i]->opcode)
-                        return spec->commands[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;
@@ -760,19 +836,31 @@ v3d_field_iterator_next(struct v3d_field_iterator *iter)
 
         const char *enum_name = NULL;
 
-        int s = iter->field->start;
-        int e = iter->field->end;
+        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++;
+                if (strcmp(iter->field->name, "Vec size") == 0 && value == 0)
+                        value = 1 << (e - s);
                 snprintf(iter->value, sizeof(iter->value), "%u", value);
                 enum_name = v3d_get_enum_name(&iter->field->inline_enum, value);
                 break;
@@ -830,24 +918,24 @@ v3d_field_iterator_next(struct v3d_field_iterator *iter)
         if (enum_name) {
                 int length = strlen(iter->value);
                 snprintf(iter->value + length, sizeof(iter->value) - length,
-                         " (%s)", enum_name);
+                         " /* %s */", enum_name);
         }
 
         return true;
 }
 
 void
-v3d_print_group(FILE *outfile, struct v3d_group *group,
+v3d_print_group(struct clif_dump *clif, 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);
+                fprintf(clif->out, "    %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,
+                        v3d_print_group(clif, iter.struct_desc,
                                         struct_offset,
                                         &p[iter.offset], color);
                 }