freedreno/afuc: Split out utils
authorRob Clark <robdclark@chromium.org>
Mon, 17 May 2021 01:43:20 +0000 (18:43 -0700)
committerMarge Bot <eric+marge@anholt.net>
Mon, 31 May 2021 23:34:43 +0000 (23:34 +0000)
With disasm emulator mode, we'll start wanting some things that are
duplicationg what the assembler does, so just split out all the rnndb
bits into shared utils.

Signed-off-by: Rob Clark <robdclark@chromium.org>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/10944>

src/freedreno/afuc/asm.c
src/freedreno/afuc/disasm.c
src/freedreno/afuc/meson.build
src/freedreno/afuc/util.c [new file with mode: 0644]
src/freedreno/afuc/util.h [new file with mode: 0644]

index c90a91e..b95c648 100644 (file)
 #include "afuc.h"
 #include "asm.h"
 #include "parser.h"
-#include "rnn.h"
-#include "rnndec.h"
+#include "util.h"
 
 int gpuver;
 
-static struct rnndeccontext *ctx;
-static struct rnndb *db;
-static struct rnndomain *control_regs;
-struct rnndomain *dom[2];
-
 /* bit lame to hard-code max but fw sizes are small */
 static struct asm_instruction instructions[0x2000];
 static unsigned num_instructions;
@@ -329,52 +323,22 @@ emit_instructions(int outfd)
    }
 }
 
-static int
-find_enum_val(struct rnnenum *en, const char *name)
-{
-   int i;
-
-   for (i = 0; i < en->valsnum; i++)
-      if (en->vals[i]->valvalid && !strcmp(name, en->vals[i]->name))
-         return en->vals[i]->value;
-
-   return -1;
-}
-
-static int
-find_reg(struct rnndomain *dom, const char *name)
-{
-   int i;
-
-   for (i = 0; i < dom->subelemsnum; i++)
-      if (!strcmp(name, dom->subelems[i]->name))
-         return dom->subelems[i]->offset;
-
-   return -1;
-}
-
 unsigned
 parse_control_reg(const char *name)
 {
    /* skip leading "@" */
-   int val = find_reg(control_regs, name + 1);
-   if (val < 0) {
-      printf("invalid control reg: %s\n", name);
-      exit(2);
-   }
-   return (unsigned)val;
+   return afuc_control_reg(name + 1);
 }
 
 static void
 emit_jumptable(int outfd)
 {
-   struct rnnenum *en = rnn_findenum(ctx->db, "adreno_pm4_type3_packets");
    uint32_t jmptable[0x80] = {0};
    int i;
 
    for (i = 0; i < num_labels; i++) {
       struct asm_label *label = &labels[i];
-      int id = find_enum_val(en, label->label);
+      int id = afuc_pm4_id(label->label);
 
       /* if it doesn't match a known PM4 packet-id, try to match UNKN%d: */
       if (id < 0) {
@@ -403,7 +367,7 @@ int
 main(int argc, char **argv)
 {
    FILE *in;
-   char *file, *outfile, *name, *control_reg_name;
+   char *file, *outfile;
    int c, ret, outfd;
 
    /* Argument parsing: */
@@ -448,33 +412,11 @@ main(int argc, char **argv)
       }
    }
 
-   switch (gpuver) {
-   case 6:
-      name = "A6XX";
-      control_reg_name = "A6XX_CONTROL_REG";
-      break;
-   case 5:
-      name = "A5XX";
-      control_reg_name = "A5XX_CONTROL_REG";
-      break;
-   default:
-      fprintf(stderr, "unknown GPU version!\n");
+   ret = afuc_util_init(gpuver, false);
+   if (ret < 0) {
       usage();
    }
 
-   rnn_init();
-   db = rnn_newdb();
-
-   ctx = rnndec_newcontext(db);
-
-   rnn_parsefile(db, "adreno.xml");
-   rnn_prepdb(db);
-   if (db->estatus)
-      errx(db->estatus, "failed to parse register database");
-   dom[0] = rnn_finddomain(db, name);
-   dom[1] = rnn_finddomain(db, "AXXX");
-   control_regs = rnn_finddomain(db, control_reg_name);
-
    ret = yyparse();
    if (ret) {
       fprintf(stderr, "parse failed: %d\n", ret);
index cefb602..cd5de77 100644 (file)
 #include "freedreno_pm4.h"
 
 #include "afuc.h"
-#include "rnn.h"
-#include "rnndec.h"
+#include "util.h"
 
 static int gpuver;
 
-static struct rnndeccontext *ctx;
-static struct rnndb *db;
-static struct rnndomain *control_regs;
-struct rnndomain *dom[2];
-const char *variant;
-
 /* non-verbose mode should output something suitable to feed back into
  * assembler.. verbose mode has additional output useful for debugging
  * (like unexpected bits that are set)
@@ -58,40 +51,18 @@ static bool verbose = false;
 static void
 print_gpu_reg(uint32_t regbase)
 {
-   struct rnndomain *d = NULL;
-
    if (regbase < 0x100)
       return;
 
-   if (rnndec_checkaddr(ctx, dom[0], regbase, 0))
-      d = dom[0];
-   else if (rnndec_checkaddr(ctx, dom[1], regbase, 0))
-      d = dom[1];
-
-   if (d) {
-      struct rnndecaddrinfo *info = rnndec_decodeaddr(ctx, d, regbase, 0);
-      if (info) {
-         printf("\t; %s", info->name);
-         free(info->name);
-         free(info);
-         return;
-      }
+   char *name = afuc_gpu_reg_name(regbase);
+   if (name) {
+      printf("\t; %s", name);
+      free(name);
    }
 }
 
-static void
-printc(const char *c, const char *fmt, ...)
-{
-   va_list args;
-   printf("%s", c);
-   va_start(args, fmt);
-   vprintf(fmt, args);
-   va_end(args);
-   printf("%s", ctx->colors->reset);
-}
-
-#define printerr(fmt, ...) printc(ctx->colors->err, fmt, ##__VA_ARGS__)
-#define printlbl(fmt, ...) printc(ctx->colors->btarg, fmt, ##__VA_ARGS__)
+#define printerr(fmt, ...) afuc_printc(AFUC_ERR, fmt, ##__VA_ARGS__)
+#define printlbl(fmt, ...) afuc_printc(AFUC_LBL, fmt, ##__VA_ARGS__)
 
 static void
 print_reg(unsigned reg)
@@ -170,7 +141,7 @@ print_alu_name(afuc_opc opc, uint32_t instr)
 static const char *
 getpm4(uint32_t id)
 {
-   return rnndec_decode_enum(ctx, "adreno_pm4_type3_packets", id);
+   return afuc_pm_id_name(id);
 }
 
 static struct {
@@ -290,11 +261,10 @@ fxn_name(uint32_t offset)
 static void
 print_control_reg(uint32_t id)
 {
-   if (rnndec_checkaddr(ctx, control_regs, id, 0)) {
-      struct rnndecaddrinfo *info = rnndec_decodeaddr(ctx, control_regs, id, 0);
-      printf("@%s", info->name);
-      free(info->name);
-      free(info);
+   char *name = afuc_control_reg_name(id);
+   if (name) {
+      printf("@%s", name);
+      free(name);
    } else {
       printf("0x%03x", id);
    }
@@ -794,10 +764,10 @@ int
 main(int argc, char **argv)
 {
    uint32_t *buf;
-   char *file, *control_reg_name;
+   char *file;
    bool colors = false;
    size_t sz;
-   int c;
+   int c, ret;
 
    /* Argument parsing: */
    while ((c = getopt(argc, argv, "g:vc")) != -1) {
@@ -832,37 +802,12 @@ main(int argc, char **argv)
       }
    }
 
-   switch (gpuver) {
-   case 6:
-      printf("; a6xx microcode\n");
-      variant = "A6XX";
-      control_reg_name = "A6XX_CONTROL_REG";
-      break;
-   case 5:
-      printf("; a5xx microcode\n");
-      variant = "A5XX";
-      control_reg_name = "A5XX_CONTROL_REG";
-      break;
-   default:
-      fprintf(stderr, "unknown GPU version!\n");
+   ret = afuc_util_init(gpuver, colors);
+   if (ret < 0) {
       usage();
    }
 
-   rnn_init();
-   db = rnn_newdb();
-
-   ctx = rnndec_newcontext(db);
-   ctx->colors = colors ? &envy_def_colors : &envy_null_colors;
-
-   rnn_parsefile(db, "adreno.xml");
-   rnn_prepdb(db);
-   if (db->estatus)
-      errx(db->estatus, "failed to parse register database");
-   dom[0] = rnn_finddomain(db, variant);
-   dom[1] = rnn_finddomain(db, "AXXX");
-   control_regs = rnn_finddomain(db, control_reg_name);
-
-   rnndec_varadd(ctx, "chip", variant);
+   printf("; a%dxx microcode\n", gpuver);
 
    buf = (uint32_t *)os_read_file(file, &sz);
 
index 54c19b3..43c6153 100644 (file)
@@ -40,6 +40,8 @@ asm = executable(
   'afuc-asm',
   [
     'asm.c',
+    'util.c',
+    'util.h',
     afuc_lexer,
     afuc_parser,
   ],
@@ -56,7 +58,11 @@ asm = executable(
 
 disasm = executable(
   'afuc-disasm',
-  'disasm.c',
+  [
+    'disasm.c',
+    'util.c',
+    'util.h',
+  ],
   include_directories: [
     inc_freedreno,
     inc_freedreno_rnn,
diff --git a/src/freedreno/afuc/util.c b/src/freedreno/afuc/util.c
new file mode 100644 (file)
index 0000000..b48cc7a
--- /dev/null
@@ -0,0 +1,210 @@
+/*
+ * Copyright © 2021 Google, Inc.
+ *
+ * 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 <err.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "rnn.h"
+#include "rnndec.h"
+
+#include "util.h"
+
+static struct rnndeccontext *ctx;
+static struct rnndb *db;
+static struct rnndomain *control_regs;
+struct rnndomain *dom[2];
+static struct rnnenum *pm4_packets;
+
+static int
+find_reg(struct rnndomain *dom, const char *name)
+{
+   for (int i = 0; i < dom->subelemsnum; i++)
+      if (!strcmp(name, dom->subelems[i]->name))
+         return dom->subelems[i]->offset;
+
+   return -1;
+}
+
+/**
+ * Map control reg name to offset.
+ */
+unsigned
+afuc_control_reg(const char *name)
+{
+   int val = find_reg(control_regs, name);
+   if (val < 0) {
+      char *endptr = NULL;
+      val = strtol(name, &endptr, 0);
+      if (endptr) {
+         printf("invalid control reg: %s\n", name);
+         exit(2);
+      }
+   }
+   return (unsigned)val;
+}
+
+/**
+ * Map offset to control reg name (or NULL), caller frees
+ */
+char *
+afuc_control_reg_name(unsigned id)
+{
+   if (rnndec_checkaddr(ctx, control_regs, id, 0)) {
+      struct rnndecaddrinfo *info = rnndec_decodeaddr(ctx, control_regs, id, 0);
+      char *name = info->name;
+      free(info);
+      return name;
+   } else {
+      return NULL;
+   }
+}
+
+/**
+ * Map GPU reg name to offset.
+ */
+unsigned
+afuc_gpu_reg(const char *name)
+{
+   int val = find_reg(dom[0], name);
+   if (val < 0)
+      val = find_reg(dom[1], name);
+   if (val < 0) {
+      char *endptr = NULL;
+      val = strtol(name, &endptr, 0);
+      if (endptr) {
+         printf("invalid control reg: %s\n", name);
+         exit(2);
+      }
+   }
+   return (unsigned)val;
+}
+
+/**
+ * Map offset to gpu reg name (or NULL), caller frees
+ */
+char *
+afuc_gpu_reg_name(unsigned id)
+{
+   struct rnndomain *d = NULL;
+
+   if (rnndec_checkaddr(ctx, dom[0], id, 0)) {
+      d = dom[0];
+   } else if (rnndec_checkaddr(ctx, dom[1], id, 0)) {
+      d = dom[1];
+   }
+
+   if (d) {
+      struct rnndecaddrinfo *info = rnndec_decodeaddr(ctx, d, id, 0);
+      if (info) {
+         char *name = info->name;
+         free(info);
+         return name;
+      }
+   }
+
+   return NULL;
+}
+
+static int
+find_enum_val(struct rnnenum *en, const char *name)
+{
+   int i;
+
+   for (i = 0; i < en->valsnum; i++)
+      if (en->vals[i]->valvalid && !strcmp(name, en->vals[i]->name))
+         return en->vals[i]->value;
+
+   return -1;
+}
+
+/**
+ * Map pm4 packet name to id
+ */
+int
+afuc_pm4_id(const char *name)
+{
+   return find_enum_val(pm4_packets, name);
+}
+
+const char *
+afuc_pm_id_name(unsigned id)
+{
+   return rnndec_decode_enum(ctx, "adreno_pm4_type3_packets", id);
+}
+
+void
+afuc_printc(enum afuc_color c, const char *fmt, ...)
+{
+   va_list args;
+   if (c == AFUC_ERR) {
+      printf("%s", ctx->colors->err);
+   } else if (c == AFUC_LBL) {
+      printf("%s", ctx->colors->btarg);
+   }
+   va_start(args, fmt);
+   vprintf(fmt, args);
+   va_end(args);
+   printf("%s", ctx->colors->reset);
+}
+
+int afuc_util_init(int gpuver, bool colors)
+{
+   char *name, *control_reg_name;
+
+   switch (gpuver) {
+   case 6:
+      name = "A6XX";
+      control_reg_name = "A6XX_CONTROL_REG";
+      break;
+   case 5:
+      name = "A5XX";
+      control_reg_name = "A5XX_CONTROL_REG";
+      break;
+   default:
+      fprintf(stderr, "unknown GPU version!\n");
+      return -1;
+   }
+
+   rnn_init();
+   db = rnn_newdb();
+
+   ctx = rnndec_newcontext(db);
+   ctx->colors = colors ? &envy_def_colors : &envy_null_colors;
+
+   rnn_parsefile(db, "adreno.xml");
+   rnn_prepdb(db);
+   if (db->estatus)
+      errx(db->estatus, "failed to parse register database");
+   dom[0] = rnn_finddomain(db, name);
+   dom[1] = rnn_finddomain(db, "AXXX");
+   control_regs = rnn_finddomain(db, control_reg_name);
+
+   rnndec_varadd(ctx, "chip", name);
+
+   pm4_packets = rnn_findenum(ctx->db, "adreno_pm4_type3_packets");
+
+   return 0;
+}
+
diff --git a/src/freedreno/afuc/util.h b/src/freedreno/afuc/util.h
new file mode 100644 (file)
index 0000000..436bf63
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright © 2021 Google, Inc.
+ *
+ * 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.
+ */
+
+#ifndef _UTIL_H_
+#define _UTIL_H_
+
+#include <stdbool.h>
+
+/*
+ * AFUC disasm / asm helpers
+ */
+
+unsigned afuc_control_reg(const char *name);
+char * afuc_control_reg_name(unsigned id);
+
+unsigned afuc_gpu_reg(const char *name);
+char * afuc_gpu_reg_name(unsigned id);
+
+int afuc_pm4_id(const char *name);
+const char * afuc_pm_id_name(unsigned id);
+
+enum afuc_color {
+   AFUC_ERR,
+   AFUC_LBL,
+};
+
+void afuc_printc(enum afuc_color c, const char *fmt, ...);
+
+int afuc_util_init(int gpuver, bool colors);
+
+#endif /* _UTIL_H_ */