xref: /third_party/mesa3d/src/freedreno/afuc/util.c (revision bf215546)
1/*
2 * Copyright © 2021 Google, Inc.
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 FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 */
23
24#include <err.h>
25#include <stdarg.h>
26#include <stdio.h>
27#include <string.h>
28
29#include "rnn.h"
30#include "rnndec.h"
31
32#include "afuc.h"
33#include "util.h"
34
35static struct rnndeccontext *ctx;
36static struct rnndb *db;
37static struct rnndomain *control_regs;
38static struct rnndomain *pipe_regs;
39struct rnndomain *dom[2];
40static struct rnnenum *pm4_packets;
41
42static int
43find_reg(struct rnndomain *dom, const char *name)
44{
45   for (int i = 0; i < dom->subelemsnum; i++)
46      if (!strcmp(name, dom->subelems[i]->name))
47         return dom->subelems[i]->offset;
48
49   return -1;
50}
51
52static unsigned
53reg(struct rnndomain *dom, const char *type, const char *name)
54{
55   int val = find_reg(dom, name);
56   if (val < 0) {
57      char *endptr = NULL;
58      val = strtol(name, &endptr, 0);
59      if (endptr && *endptr) {
60         printf("invalid %s reg: %s\n", type, name);
61         exit(2);
62      }
63   }
64   return (unsigned)val;
65}
66
67static char *
68reg_name(struct rnndomain *dom, unsigned id)
69{
70   if (rnndec_checkaddr(ctx, dom, id, 0)) {
71      struct rnndecaddrinfo *info = rnndec_decodeaddr(ctx, dom, id, 0);
72      char *name = info->name;
73      free(info);
74      return name;
75   } else {
76      return NULL;
77   }
78}
79
80/**
81 * Map control reg name to offset.
82 */
83unsigned
84afuc_control_reg(const char *name)
85{
86   return reg(control_regs, "control", name);
87}
88
89/**
90 * Map offset to control reg name (or NULL), caller frees
91 */
92char *
93afuc_control_reg_name(unsigned id)
94{
95   return reg_name(control_regs, id);
96}
97
98/**
99 * Map pipe reg name to offset.
100 */
101unsigned
102afuc_pipe_reg(const char *name)
103{
104   return reg(pipe_regs, "pipe", name);
105}
106
107/**
108 * "void" pipe regs don't have a value written, the $addr right is
109 * enough to trigger what they do
110 */
111bool
112afuc_pipe_reg_is_void(unsigned id)
113{
114   if (rnndec_checkaddr(ctx, pipe_regs, id, 0)) {
115      struct rnndecaddrinfo *info = rnndec_decodeaddr(ctx, pipe_regs, id, 0);
116      free(info->name);
117      bool ret = !strcmp(info->typeinfo->name, "void");
118      free(info);
119      return ret;
120   } else {
121      return false;
122   }
123}
124
125/**
126 * Map offset to pipe reg name (or NULL), caller frees
127 */
128char *
129afuc_pipe_reg_name(unsigned id)
130{
131   return reg_name(pipe_regs, id);
132}
133
134/**
135 * Map GPU reg name to offset.
136 */
137unsigned
138afuc_gpu_reg(const char *name)
139{
140   int val = find_reg(dom[0], name);
141   if (val < 0)
142      val = find_reg(dom[1], name);
143   if (val < 0) {
144      char *endptr = NULL;
145      val = strtol(name, &endptr, 0);
146      if (endptr && *endptr) {
147         printf("invalid control reg: %s\n", name);
148         exit(2);
149      }
150   }
151   return (unsigned)val;
152}
153
154/**
155 * Map offset to gpu reg name (or NULL), caller frees
156 */
157char *
158afuc_gpu_reg_name(unsigned id)
159{
160   struct rnndomain *d = NULL;
161
162   if (rnndec_checkaddr(ctx, dom[0], id, 0)) {
163      d = dom[0];
164   } else if (rnndec_checkaddr(ctx, dom[1], id, 0)) {
165      d = dom[1];
166   }
167
168   if (d) {
169      struct rnndecaddrinfo *info = rnndec_decodeaddr(ctx, d, id, 0);
170      if (info) {
171         char *name = info->name;
172         free(info);
173         return name;
174      }
175   }
176
177   return NULL;
178}
179
180unsigned
181afuc_gpr_reg(const char *name)
182{
183   /* If it starts with '$' just swallow it: */
184   if (name[0] == '$')
185      name++;
186
187   /* handle aliases: */
188   if (!strcmp(name, "rem")) {
189      return REG_REM;
190   } else if (!strcmp(name, "memdata")) {
191      return REG_MEMDATA;
192   } else if (!strcmp(name, "addr")) {
193      return REG_ADDR;
194   } else if (!strcmp(name, "regdata")) {
195      return REG_REGDATA;
196   } else if (!strcmp(name, "usraddr")) {
197      return REG_USRADDR;
198   } else if (!strcmp(name, "data")) {
199      return REG_DATA;
200   } else {
201      char *endptr = NULL;
202      unsigned val = strtol(name, &endptr, 16);
203      if (endptr && *endptr) {
204         printf("invalid gpr reg: %s\n", name);
205         exit(2);
206      }
207      return val;
208   }
209}
210
211static int
212find_enum_val(struct rnnenum *en, const char *name)
213{
214   int i;
215
216   for (i = 0; i < en->valsnum; i++)
217      if (en->vals[i]->valvalid && !strcmp(name, en->vals[i]->name))
218         return en->vals[i]->value;
219
220   return -1;
221}
222
223/**
224 * Map pm4 packet name to id
225 */
226int
227afuc_pm4_id(const char *name)
228{
229   return find_enum_val(pm4_packets, name);
230}
231
232const char *
233afuc_pm_id_name(unsigned id)
234{
235   return rnndec_decode_enum(ctx, "adreno_pm4_type3_packets", id);
236}
237
238void
239afuc_printc(enum afuc_color c, const char *fmt, ...)
240{
241   va_list args;
242   if (c == AFUC_ERR) {
243      printf("%s", ctx->colors->err);
244   } else if (c == AFUC_LBL) {
245      printf("%s", ctx->colors->btarg);
246   }
247   va_start(args, fmt);
248   vprintf(fmt, args);
249   va_end(args);
250   printf("%s", ctx->colors->reset);
251}
252
253int afuc_util_init(int gpuver, bool colors)
254{
255   char *name, *control_reg_name;
256   char *pipe_reg_name = NULL;
257
258   switch (gpuver) {
259   case 6:
260      name = "A6XX";
261      control_reg_name = "A6XX_CONTROL_REG";
262      pipe_reg_name = "A6XX_PIPE_REG";
263      break;
264   case 5:
265      name = "A5XX";
266      control_reg_name = "A5XX_CONTROL_REG";
267      pipe_reg_name = "A5XX_PIPE_REG";
268      break;
269   default:
270      fprintf(stderr, "unknown GPU version!\n");
271      return -1;
272   }
273
274   rnn_init();
275   db = rnn_newdb();
276
277   ctx = rnndec_newcontext(db);
278   ctx->colors = colors ? &envy_def_colors : &envy_null_colors;
279
280   rnn_parsefile(db, "adreno.xml");
281   rnn_prepdb(db);
282   if (db->estatus)
283      errx(db->estatus, "failed to parse register database");
284   dom[0] = rnn_finddomain(db, name);
285   dom[1] = rnn_finddomain(db, "AXXX");
286   control_regs = rnn_finddomain(db, control_reg_name);
287   pipe_regs = rnn_finddomain(db, pipe_reg_name);
288
289   rnndec_varadd(ctx, "chip", name);
290
291   pm4_packets = rnn_findenum(ctx->db, "adreno_pm4_type3_packets");
292
293   return 0;
294}
295
296