1 /*
2 * Copyright © 2010-2011 Marcin Kościelnicki <[email protected]>
3 * Copyright © 2010 Francisco Jerez <[email protected]>
4 * All Rights Reserved.
5 * SPDX-License-Identifier: MIT
6 */
7
8 #include "rnndec.h"
9 #include <assert.h>
10 #include <stdio.h>
11 #include <string.h>
12 #include <stdlib.h>
13 #include <inttypes.h>
14 #include "util.h"
15 #include "util/compiler.h"
16
rnndec_newcontext(struct rnndb * db)17 struct rnndeccontext *rnndec_newcontext(struct rnndb *db) {
18 struct rnndeccontext *res = calloc (sizeof *res, 1);
19 res->db = db;
20 res->colors = &envy_null_colors;
21 return res;
22 }
23
rnndec_varadd(struct rnndeccontext * ctx,char * varset,const char * variant)24 int rnndec_varadd(struct rnndeccontext *ctx, char *varset, const char *variant) {
25 struct rnnenum *en = rnn_findenum(ctx->db, varset);
26 if (!en) {
27 fprintf (stderr, "Enum %s doesn't exist in database!\n", varset);
28 return 0;
29 }
30 int i, j;
31 for (i = 0; i < en->valsnum; i++)
32 if (!strcasecmp(en->vals[i]->name, variant)) {
33 break;
34 }
35
36 if (i == en->valsnum) {
37 fprintf (stderr, "Variant %s doesn't exist in enum %s!\n", variant, varset);
38 return 0;
39 }
40
41 for (j = 0; j < ctx->varsnum; j++) {
42 if (ctx->vars[j]->en == en) {
43 ctx->vars[j]->variant = i;
44 break;
45 }
46 }
47
48 if (j == ctx->varsnum) {
49 struct rnndecvariant *ci = calloc (sizeof *ci, 1);
50 ci->en = en;
51 ci->variant = i;
52 ADDARRAY(ctx->vars, ci);
53 }
54
55 return 1;
56 }
57
rnndec_varmatch(struct rnndeccontext * ctx,struct rnnvarinfo * vi)58 int rnndec_varmatch(struct rnndeccontext *ctx, struct rnnvarinfo *vi) {
59 if (vi->dead)
60 return 0;
61 int i;
62 for (i = 0; i < vi->varsetsnum; i++) {
63 int j;
64 for (j = 0; j < ctx->varsnum; j++)
65 if (vi->varsets[i]->venum == ctx->vars[j]->en)
66 break;
67 if (j == ctx->varsnum) {
68 fprintf (stderr, "I don't know which %s variant to use!\n", vi->varsets[i]->venum->name);
69 } else {
70 if (!vi->varsets[i]->variants[ctx->vars[j]->variant])
71 return 0;
72 }
73 }
74 return 1;
75 }
76
77 /* see https://en.wikipedia.org/wiki/Half-precision_floating-point_format */
float16i(uint16_t val)78 static uint32_t float16i(uint16_t val)
79 {
80 uint32_t sign = ((uint32_t)(val & 0x8000)) << 16;
81 uint32_t frac = val & 0x3ff;
82 int32_t expn = (val >> 10) & 0x1f;
83
84 if (expn == 0) {
85 if (frac) {
86 /* denormalized number: */
87 int shift = __builtin_clz(frac) - 21;
88 frac <<= shift;
89 expn = -shift;
90 } else {
91 /* +/- zero: */
92 return sign;
93 }
94 } else if (expn == 0x1f) {
95 /* Inf/NaN: */
96 return sign | 0x7f800000 | (frac << 13);
97 }
98
99 return sign | ((expn + 127 - 15) << 23) | (frac << 13);
100 }
float16(uint16_t val)101 static float float16(uint16_t val)
102 {
103 union { uint32_t i; float f; } u;
104 u.i = float16i(val);
105 return u.f;
106 }
107
rnndec_decode_enum_val(struct rnndeccontext * ctx,struct rnnvalue ** vals,int valsnum,uint64_t value)108 static const char *rnndec_decode_enum_val(struct rnndeccontext *ctx,
109 struct rnnvalue **vals, int valsnum, uint64_t value)
110 {
111 int i;
112 for (i = 0; i < valsnum; i++)
113 if (rnndec_varmatch(ctx, &vals[i]->varinfo) &&
114 vals[i]->valvalid && vals[i]->value == value)
115 return vals[i]->name;
116 return NULL;
117 }
118
rnndec_decode_enum(struct rnndeccontext * ctx,const char * enumname,uint64_t enumval)119 const char *rnndec_decode_enum(struct rnndeccontext *ctx, const char *enumname, uint64_t enumval)
120 {
121 struct rnnenum *en = rnn_findenum (ctx->db, enumname);
122 if (en) {
123 return rnndec_decode_enum_val(ctx, en->vals, en->valsnum, enumval);
124 }
125 return NULL;
126 }
127
128 /* The name UNK%u is used as a placeholder for bitfields that exist but
129 * have an unknown function.
130 */
is_unknown(const char * name)131 static int is_unknown(const char *name)
132 {
133 unsigned u;
134 return sscanf(name, "UNK%u", &u) == 1;
135 }
136
rnndec_decodeval(struct rnndeccontext * ctx,struct rnntypeinfo * ti,uint64_t value)137 char *rnndec_decodeval(struct rnndeccontext *ctx, struct rnntypeinfo *ti, uint64_t value) {
138 int width = ti->high - ti->low + 1;
139 char *res = 0;
140 int i;
141 struct rnnvalue **vals;
142 int valsnum;
143 struct rnnbitfield **bitfields;
144 int bitfieldsnum;
145 char *tmp;
146 const char *ctmp;
147 uint64_t mask;
148
149 uint64_t value_orig = value;
150 if (!ti)
151 goto failhex;
152 value = (value & typeinfo_mask(ti)) >> ti->low;
153 value <<= ti->shr;
154
155 switch (ti->type) {
156 case RNN_TTYPE_ENUM:
157 vals = ti->eenum->vals;
158 valsnum = ti->eenum->valsnum;
159 goto doenum;
160 case RNN_TTYPE_INLINE_ENUM:
161 vals = ti->vals;
162 valsnum = ti->valsnum;
163 goto doenum;
164 doenum:
165 ctmp = rnndec_decode_enum_val(ctx, vals, valsnum, value);
166 if (ctmp) {
167 asprintf (&res, "%s%s%s", ctx->colors->eval, ctmp, ctx->colors->reset);
168 if (ti->addvariant) {
169 rnndec_varadd(ctx, ti->eenum->name, ctmp);
170 }
171 break;
172 }
173 goto failhex;
174 case RNN_TTYPE_BITSET:
175 bitfields = ti->ebitset->bitfields;
176 bitfieldsnum = ti->ebitset->bitfieldsnum;
177 goto dobitset;
178 case RNN_TTYPE_INLINE_BITSET:
179 bitfields = ti->bitfields;
180 bitfieldsnum = ti->bitfieldsnum;
181 goto dobitset;
182 dobitset:
183 mask = 0;
184 for (i = 0; i < bitfieldsnum; i++) {
185 if (!rnndec_varmatch(ctx, &bitfields[i]->varinfo))
186 continue;
187 uint64_t type_mask = typeinfo_mask(&bitfields[i]->typeinfo);
188 if (((value & type_mask) == 0) && is_unknown(bitfields[i]->name))
189 continue;
190 mask |= type_mask;
191 if (bitfields[i]->typeinfo.type == RNN_TTYPE_BOOLEAN) {
192 const char *color = is_unknown(bitfields[i]->name) ?
193 ctx->colors->err : ctx->colors->mod;
194 if (value & type_mask) {
195 if (!res)
196 asprintf (&res, "%s%s%s", color, bitfields[i]->name, ctx->colors->reset);
197 else {
198 asprintf (&tmp, "%s | %s%s%s", res, color, bitfields[i]->name, ctx->colors->reset);
199 free(res);
200 res = tmp;
201 }
202 }
203 continue;
204 }
205 char *subval;
206 if (is_unknown(bitfields[i]->name) && (bitfields[i]->typeinfo.type != RNN_TTYPE_A3XX_REGID)) {
207 uint64_t field_val = value & type_mask;
208 field_val = (field_val & typeinfo_mask(&bitfields[i]->typeinfo)) >> bitfields[i]->typeinfo.low;
209 field_val <<= bitfields[i]->typeinfo.shr;
210 asprintf (&subval, "%s%#"PRIx64"%s", ctx->colors->err, field_val, ctx->colors->reset);
211 } else {
212 subval = rnndec_decodeval(ctx, &bitfields[i]->typeinfo, value & type_mask);
213 }
214 if (!res)
215 asprintf (&res, "%s%s%s = %s", ctx->colors->rname, bitfields[i]->name, ctx->colors->reset, subval);
216 else {
217 asprintf (&tmp, "%s | %s%s%s = %s", res, ctx->colors->rname, bitfields[i]->name, ctx->colors->reset, subval);
218 free(res);
219 res = tmp;
220 }
221 free(subval);
222 }
223 if (value & ~mask) {
224 if (!res)
225 asprintf (&res, "%s%#"PRIx64"%s", ctx->colors->err, value & ~mask, ctx->colors->reset);
226 else {
227 asprintf (&tmp, "%s | %s%#"PRIx64"%s", res, ctx->colors->err, value & ~mask, ctx->colors->reset);
228 free(res);
229 res = tmp;
230 }
231 }
232 if (!res)
233 asprintf (&res, "%s0%s", ctx->colors->num, ctx->colors->reset);
234 asprintf (&tmp, "{ %s }", res);
235 free(res);
236 return tmp;
237 case RNN_TTYPE_SPECTYPE:
238 return rnndec_decodeval(ctx, &ti->spectype->typeinfo, value);
239 case RNN_TTYPE_HEX:
240 asprintf (&res, "%s%#"PRIx64"%s", ctx->colors->num, value, ctx->colors->reset);
241 break;
242 case RNN_TTYPE_FIXED:
243 if (value & UINT64_C(1) << (width-1)) {
244 asprintf (&res, "%s-%lf%s", ctx->colors->num,
245 ((double)((UINT64_C(1) << width) - value)) / ((double)(1 << ti->radix)),
246 ctx->colors->reset);
247 break;
248 }
249 FALLTHROUGH;
250 case RNN_TTYPE_UFIXED:
251 asprintf (&res, "%s%lf%s", ctx->colors->num,
252 ((double)value) / ((double)(1LL << ti->radix)),
253 ctx->colors->reset);
254 break;
255 case RNN_TTYPE_A3XX_REGID:
256 asprintf (&res, "%sr%"PRIu64".%c%s", ctx->colors->num, (value >> 2), "xyzw"[value & 0x3], ctx->colors->reset);
257 break;
258 case RNN_TTYPE_UINT:
259 asprintf (&res, "%s%"PRIu64"%s", ctx->colors->num, value, ctx->colors->reset);
260 break;
261 case RNN_TTYPE_INT:
262 if (value & UINT64_C(1) << (width-1))
263 asprintf (&res, "%s-%"PRIi64"%s", ctx->colors->num, (UINT64_C(1) << width) - value, ctx->colors->reset);
264 else
265 asprintf (&res, "%s%"PRIi64"%s", ctx->colors->num, value, ctx->colors->reset);
266 break;
267 case RNN_TTYPE_BOOLEAN:
268 if (value == 0) {
269 asprintf (&res, "%sFALSE%s", ctx->colors->eval, ctx->colors->reset);
270 } else if (value == 1) {
271 asprintf (&res, "%sTRUE%s", ctx->colors->eval, ctx->colors->reset);
272 }
273 break;
274 case RNN_TTYPE_FLOAT: {
275 union { uint64_t i; float f; double d; } val;
276 val.i = value;
277 if (width == 64)
278 asprintf(&res, "%s%f%s", ctx->colors->num,
279 val.d, ctx->colors->reset);
280 else if (width == 32)
281 asprintf(&res, "%s%f%s", ctx->colors->num,
282 val.f, ctx->colors->reset);
283 else if (width == 16)
284 asprintf(&res, "%s%f%s", ctx->colors->num,
285 float16(value), ctx->colors->reset);
286 else
287 goto failhex;
288
289 break;
290 }
291 failhex:
292 default:
293 asprintf (&res, "%s%#"PRIx64"%s", ctx->colors->num, value, ctx->colors->reset);
294 break;
295 }
296 if (value_orig & ~typeinfo_mask(ti)) {
297 asprintf (&tmp, "%s | %s%#"PRIx64"%s", res, ctx->colors->err, value_orig & ~typeinfo_mask(ti), ctx->colors->reset);
298 free(res);
299 res = tmp;
300 }
301 return res;
302 }
303
appendidx(struct rnndeccontext * ctx,char * name,uint64_t idx,struct rnnenum * index)304 static char *appendidx (struct rnndeccontext *ctx, char *name, uint64_t idx, struct rnnenum *index) {
305 char *res;
306 const char *index_name = NULL;
307
308 if (index)
309 index_name = rnndec_decode_enum_val(ctx, index->vals, index->valsnum, idx);
310
311 if (index_name)
312 asprintf (&res, "%s[%s%s%s]", name, ctx->colors->eval, index_name, ctx->colors->reset);
313 else
314 asprintf (&res, "%s[%s%#"PRIx64"%s]", name, ctx->colors->num, idx, ctx->colors->reset);
315
316 free (name);
317 return res;
318 }
319
320 /* This could probably be made to work for stripes too.. */
get_array_idx_offset(struct rnndelem * elem,uint64_t addr,uint64_t * idx,uint64_t * offset)321 static int get_array_idx_offset(struct rnndelem *elem, uint64_t addr, uint64_t *idx, uint64_t *offset)
322 {
323 if (elem->offsets) {
324 int i;
325 for (i = 0; i < elem->offsetsnum; i++) {
326 uint64_t o = elem->offsets[i];
327 if ((o <= addr) && (addr < (o + elem->stride))) {
328 *idx = i;
329 *offset = addr - o;
330 return 0;
331 }
332 }
333 return -1;
334 } else {
335 if (addr < elem->offset)
336 return -1;
337
338 *idx = (addr - elem->offset) / elem->stride;
339 *offset = (addr - elem->offset) % elem->stride;
340
341 if (elem->length && (*idx >= elem->length))
342 return -1;
343
344 return 0;
345 }
346 }
347
trymatch(struct rnndeccontext * ctx,struct rnndelem ** elems,int elemsnum,uint64_t addr,int write,int dwidth,uint64_t * indices,int indicesnum)348 static struct rnndecaddrinfo *trymatch (struct rnndeccontext *ctx, struct rnndelem **elems, int elemsnum, uint64_t addr, int write, int dwidth, uint64_t *indices, int indicesnum) {
349 struct rnndecaddrinfo *res;
350 int i, j;
351 for (i = 0; i < elemsnum; i++) {
352 if (!rnndec_varmatch(ctx, &elems[i]->varinfo))
353 continue;
354 uint64_t offset, idx;
355 char *tmp, *name;
356 switch (elems[i]->type) {
357 case RNN_ETYPE_REG:
358 if (addr < elems[i]->offset)
359 break;
360 if (elems[i]->stride) {
361 idx = (addr-elems[i]->offset)/elems[i]->stride;
362 offset = (addr-elems[i]->offset)%elems[i]->stride;
363 } else {
364 idx = 0;
365 offset = addr-elems[i]->offset;
366 }
367 if (offset >= elems[i]->width/dwidth)
368 break;
369 if (elems[i]->length && idx >= elems[i]->length)
370 break;
371 res = calloc (sizeof *res, 1);
372 res->typeinfo = &elems[i]->typeinfo;
373 res->width = elems[i]->width;
374 asprintf (&res->name, "%s%s%s", ctx->colors->rname, elems[i]->name, ctx->colors->reset);
375 for (j = 0; j < indicesnum; j++)
376 res->name = appendidx(ctx, res->name, indices[j], NULL);
377 if (elems[i]->length != 1)
378 res->name = appendidx(ctx, res->name, idx, elems[i]->index);
379 if (offset) {
380 /* use _HI suffix for addresses */
381 if (offset == 1 &&
382 (!strcmp(res->typeinfo->name, "address") ||
383 !strcmp(res->typeinfo->name, "waddress"))) {
384 asprintf (&tmp, "%s_HI", res->name);
385 } else {
386 asprintf (&tmp, "%s+%s%#"PRIx64"%s", res->name, ctx->colors->err, offset, ctx->colors->reset);
387 }
388 free(res->name);
389 res->name = tmp;
390 }
391 return res;
392 case RNN_ETYPE_STRIPE:
393 for (idx = 0; idx < elems[i]->length || !elems[i]->length; idx++) {
394 if (addr < elems[i]->offset + elems[i]->stride * idx)
395 break;
396 offset = addr - (elems[i]->offset + elems[i]->stride * idx);
397 int extraidx = (elems[i]->length != 1);
398 int nindnum = (elems[i]->name ? 0 : indicesnum + extraidx);
399 uint64_t nind[MAX2(nindnum, 1)];
400 if (!elems[i]->name) {
401 for (j = 0; j < indicesnum; j++)
402 nind[j] = indices[j];
403 if (extraidx)
404 nind[indicesnum] = idx;
405 }
406 res = trymatch (ctx, elems[i]->subelems, elems[i]->subelemsnum, offset, write, dwidth, nind, nindnum);
407 if (!res)
408 continue;
409 if (!elems[i]->name)
410 return res;
411 asprintf (&name, "%s%s%s", ctx->colors->rname, elems[i]->name, ctx->colors->reset);
412 for (j = 0; j < indicesnum; j++)
413 name = appendidx(ctx, name, indices[j], NULL);
414 if (elems[i]->length != 1)
415 name = appendidx(ctx, name, idx, elems[i]->index);
416 asprintf (&tmp, "%s.%s", name, res->name);
417 free(name);
418 free(res->name);
419 res->name = tmp;
420 return res;
421 }
422 break;
423 case RNN_ETYPE_ARRAY:
424 if (get_array_idx_offset(elems[i], addr, &idx, &offset))
425 break;
426 asprintf (&name, "%s%s%s", ctx->colors->rname, elems[i]->name, ctx->colors->reset);
427 for (j = 0; j < indicesnum; j++)
428 name = appendidx(ctx, name, indices[j], NULL);
429 if (elems[i]->length != 1)
430 name = appendidx(ctx, name, idx, elems[i]->index);
431 if ((res = trymatch (ctx, elems[i]->subelems, elems[i]->subelemsnum, offset, write, dwidth, 0, 0))) {
432 asprintf (&tmp, "%s.%s", name, res->name);
433 free(name);
434 free(res->name);
435 res->name = tmp;
436 return res;
437 }
438 res = calloc (sizeof *res, 1);
439 asprintf (&tmp, "%s+%s%#"PRIx64"%s", name, ctx->colors->err, offset, ctx->colors->reset);
440 free(name);
441 res->name = tmp;
442 return res;
443 default:
444 break;
445 }
446 }
447 return 0;
448 }
449
rnndec_checkaddr(struct rnndeccontext * ctx,struct rnndomain * domain,uint64_t addr,int write)450 int rnndec_checkaddr(struct rnndeccontext *ctx, struct rnndomain *domain, uint64_t addr, int write) {
451 struct rnndecaddrinfo *res = trymatch(ctx, domain->subelems, domain->subelemsnum, addr, write, domain->width, 0, 0);
452 if (res) {
453 free(res->name);
454 free(res);
455 }
456 return res != NULL;
457 }
458
rnndec_decodeaddr(struct rnndeccontext * ctx,struct rnndomain * domain,uint64_t addr,int write)459 struct rnndecaddrinfo *rnndec_decodeaddr(struct rnndeccontext *ctx, struct rnndomain *domain, uint64_t addr, int write) {
460 struct rnndecaddrinfo *res = trymatch(ctx, domain->subelems, domain->subelemsnum, addr, write, domain->width, 0, 0);
461 if (res)
462 return res;
463 res = calloc (sizeof *res, 1);
464 asprintf (&res->name, "%s%#"PRIx64"%s", ctx->colors->err, addr, ctx->colors->reset);
465 return res;
466 }
467
tryreg(struct rnndeccontext * ctx,struct rnndelem ** elems,int elemsnum,int dwidth,const char * name,uint64_t * offset)468 static unsigned tryreg(struct rnndeccontext *ctx, struct rnndelem **elems, int elemsnum,
469 int dwidth, const char *name, uint64_t *offset)
470 {
471 int i;
472 unsigned ret;
473 const char *suffix = strchr(name, '[');
474 unsigned n = suffix ? (suffix - name) : strlen(name);
475 const char *dotsuffix = strchr(name, '.');
476 unsigned dotn = dotsuffix ? (dotsuffix - name) : strlen(name);
477
478 const char *child = NULL;
479 unsigned idx = 0;
480
481 if (suffix) {
482 const char *tmp = strchr(suffix, ']');
483 idx = strtol(suffix+1, NULL, 0);
484 child = tmp+2;
485 }
486
487 for (i = 0; i < elemsnum; i++) {
488 struct rnndelem *elem = elems[i];
489 if (!rnndec_varmatch(ctx, &elem->varinfo))
490 continue;
491 int match = elem->name && (strlen(elem->name) == n) && !strncmp(elem->name, name, n);
492 switch (elem->type) {
493 case RNN_ETYPE_REG:
494 if (match) {
495 assert(!suffix);
496 *offset = elem->offset;
497 return 1;
498 }
499 break;
500 case RNN_ETYPE_STRIPE:
501 if (elem->name) {
502 if (!dotsuffix)
503 break;
504 if (strlen(elem->name) != dotn || strncmp(elem->name, name, dotn))
505 break;
506 }
507 ret = tryreg(ctx, elem->subelems, elem->subelemsnum, dwidth,
508 elem->name ? dotsuffix : name, offset);
509 if (ret)
510 return 1;
511 break;
512 case RNN_ETYPE_ARRAY:
513 if (match) {
514 assert(suffix);
515 ret = tryreg(ctx, elem->subelems, elem->subelemsnum, dwidth, child, offset);
516 if (ret) {
517 *offset += elem->offset + (idx * elem->stride);
518 return 1;
519 }
520 }
521 break;
522 default:
523 break;
524 }
525 }
526 return 0;
527 }
528
rnndec_decodereg(struct rnndeccontext * ctx,struct rnndomain * domain,const char * name)529 uint64_t rnndec_decodereg(struct rnndeccontext *ctx, struct rnndomain *domain, const char *name)
530 {
531 uint64_t offset;
532 if (tryreg(ctx, domain->subelems, domain->subelemsnum, domain->width, name, &offset)) {
533 return offset;
534 } else {
535 return 0;
536 }
537 }
538