17ec681f3Smrg/*
27ec681f3Smrg * Copyright (C) 2010-2011 Marcin Kościelnicki <koriakin@0x04.net>
37ec681f3Smrg * Copyright (C) 2010 Francisco Jerez <currojerez@riseup.net>
47ec681f3Smrg * All Rights Reserved.
57ec681f3Smrg *
67ec681f3Smrg * Permission is hereby granted, free of charge, to any person obtaining a
77ec681f3Smrg * copy of this software and associated documentation files (the "Software"),
87ec681f3Smrg * to deal in the Software without restriction, including without limitation
97ec681f3Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
107ec681f3Smrg * and/or sell copies of the Software, and to permit persons to whom the
117ec681f3Smrg * Software is furnished to do so, subject to the following conditions:
127ec681f3Smrg *
137ec681f3Smrg * The above copyright notice and this permission notice (including the next
147ec681f3Smrg * paragraph) shall be included in all copies or substantial portions of the
157ec681f3Smrg * Software.
167ec681f3Smrg *
177ec681f3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
187ec681f3Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
197ec681f3Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
207ec681f3Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
217ec681f3Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
227ec681f3Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
237ec681f3Smrg * OTHER DEALINGS IN THE SOFTWARE.
247ec681f3Smrg */
257ec681f3Smrg
267ec681f3Smrg#include "rnndec.h"
277ec681f3Smrg#include <assert.h>
287ec681f3Smrg#include <stdio.h>
297ec681f3Smrg#include <string.h>
307ec681f3Smrg#include <stdlib.h>
317ec681f3Smrg#include <inttypes.h>
327ec681f3Smrg#include "util.h"
337ec681f3Smrg#include "util/compiler.h"
347ec681f3Smrg
357ec681f3Smrgstruct rnndeccontext *rnndec_newcontext(struct rnndb *db) {
367ec681f3Smrg	struct rnndeccontext *res = calloc (sizeof *res, 1);
377ec681f3Smrg	res->db = db;
387ec681f3Smrg	res->colors = &envy_null_colors;
397ec681f3Smrg	return res;
407ec681f3Smrg}
417ec681f3Smrg
427ec681f3Smrgint rnndec_varadd(struct rnndeccontext *ctx, char *varset, const char *variant) {
437ec681f3Smrg	struct rnnenum *en = rnn_findenum(ctx->db, varset);
447ec681f3Smrg	if (!en) {
457ec681f3Smrg		fprintf (stderr, "Enum %s doesn't exist in database!\n", varset);
467ec681f3Smrg		return 0;
477ec681f3Smrg	}
487ec681f3Smrg	int i, j;
497ec681f3Smrg	for (i = 0; i < en->valsnum; i++)
507ec681f3Smrg		if (!strcasecmp(en->vals[i]->name, variant)) {
517ec681f3Smrg			struct rnndecvariant *ci = calloc (sizeof *ci, 1);
527ec681f3Smrg			ci->en = en;
537ec681f3Smrg			ci->variant = i;
547ec681f3Smrg			ADDARRAY(ctx->vars, ci);
557ec681f3Smrg			return 1;
567ec681f3Smrg		}
577ec681f3Smrg
587ec681f3Smrg	if (i == en->valsnum) {
597ec681f3Smrg		fprintf (stderr, "Variant %s doesn't exist in enum %s!\n", variant, varset);
607ec681f3Smrg		return 0;
617ec681f3Smrg	}
627ec681f3Smrg
637ec681f3Smrg	for (j = 0; j < ctx->varsnum; j++) {
647ec681f3Smrg		if (ctx->vars[j]->en == en) {
657ec681f3Smrg			ctx->vars[j]->variant = i;
667ec681f3Smrg			break;
677ec681f3Smrg		}
687ec681f3Smrg	}
697ec681f3Smrg
707ec681f3Smrg	if (i == ctx->varsnum) {
717ec681f3Smrg		struct rnndecvariant *ci = calloc (sizeof *ci, 1);
727ec681f3Smrg		ci->en = en;
737ec681f3Smrg		ci->variant = i;
747ec681f3Smrg		ADDARRAY(ctx->vars, ci);
757ec681f3Smrg	}
767ec681f3Smrg
777ec681f3Smrg	return 1;
787ec681f3Smrg}
797ec681f3Smrg
807ec681f3Smrgint rnndec_varmatch(struct rnndeccontext *ctx, struct rnnvarinfo *vi) {
817ec681f3Smrg	if (vi->dead)
827ec681f3Smrg		return 0;
837ec681f3Smrg	int i;
847ec681f3Smrg	for (i = 0; i < vi->varsetsnum; i++) {
857ec681f3Smrg		int j;
867ec681f3Smrg		for (j = 0; j < ctx->varsnum; j++)
877ec681f3Smrg			if (vi->varsets[i]->venum == ctx->vars[j]->en)
887ec681f3Smrg				break;
897ec681f3Smrg		if (j == ctx->varsnum) {
907ec681f3Smrg			fprintf (stderr, "I don't know which %s variant to use!\n", vi->varsets[i]->venum->name);
917ec681f3Smrg		} else {
927ec681f3Smrg			if (!vi->varsets[i]->variants[ctx->vars[j]->variant])
937ec681f3Smrg				return 0;
947ec681f3Smrg		}
957ec681f3Smrg	}
967ec681f3Smrg	return 1;
977ec681f3Smrg}
987ec681f3Smrg
997ec681f3Smrg/* see https://en.wikipedia.org/wiki/Half-precision_floating-point_format */
1007ec681f3Smrgstatic uint32_t float16i(uint16_t val)
1017ec681f3Smrg{
1027ec681f3Smrg	uint32_t sign = ((uint32_t)(val & 0x8000)) << 16;
1037ec681f3Smrg	uint32_t frac = val & 0x3ff;
1047ec681f3Smrg	int32_t  expn = (val >> 10) & 0x1f;
1057ec681f3Smrg
1067ec681f3Smrg	if (expn == 0) {
1077ec681f3Smrg		if (frac) {
1087ec681f3Smrg			/* denormalized number: */
1097ec681f3Smrg			int shift = __builtin_clz(frac) - 21;
1107ec681f3Smrg			frac <<= shift;
1117ec681f3Smrg			expn = -shift;
1127ec681f3Smrg		} else {
1137ec681f3Smrg			/* +/- zero: */
1147ec681f3Smrg			return sign;
1157ec681f3Smrg		}
1167ec681f3Smrg	} else if (expn == 0x1f) {
1177ec681f3Smrg		/* Inf/NaN: */
1187ec681f3Smrg		return sign | 0x7f800000 | (frac << 13);
1197ec681f3Smrg	}
1207ec681f3Smrg
1217ec681f3Smrg	return sign | ((expn + 127 - 15) << 23) | (frac << 13);
1227ec681f3Smrg}
1237ec681f3Smrgstatic float float16(uint16_t val)
1247ec681f3Smrg{
1257ec681f3Smrg	union { uint32_t i; float f; } u;
1267ec681f3Smrg	u.i = float16i(val);
1277ec681f3Smrg	return u.f;
1287ec681f3Smrg}
1297ec681f3Smrg
1307ec681f3Smrgstatic const char *rnndec_decode_enum_val(struct rnndeccontext *ctx,
1317ec681f3Smrg		struct rnnvalue **vals, int valsnum, uint64_t value)
1327ec681f3Smrg{
1337ec681f3Smrg	int i;
1347ec681f3Smrg	for (i = 0; i < valsnum; i++)
1357ec681f3Smrg		if (rnndec_varmatch(ctx, &vals[i]->varinfo) &&
1367ec681f3Smrg				vals[i]->valvalid && vals[i]->value == value)
1377ec681f3Smrg			return vals[i]->name;
1387ec681f3Smrg	return NULL;
1397ec681f3Smrg}
1407ec681f3Smrg
1417ec681f3Smrgconst char *rnndec_decode_enum(struct rnndeccontext *ctx, const char *enumname, uint64_t enumval)
1427ec681f3Smrg{
1437ec681f3Smrg	struct rnnenum *en = rnn_findenum (ctx->db, enumname);
1447ec681f3Smrg	if (en) {
1457ec681f3Smrg		return rnndec_decode_enum_val(ctx, en->vals, en->valsnum, enumval);
1467ec681f3Smrg	}
1477ec681f3Smrg	return NULL;
1487ec681f3Smrg}
1497ec681f3Smrg
1507ec681f3Smrg/* The name UNK%u is used as a placeholder for bitfields that exist but
1517ec681f3Smrg * have an unknown function.
1527ec681f3Smrg */
1537ec681f3Smrgstatic int is_unknown(const char *name)
1547ec681f3Smrg{
1557ec681f3Smrg	unsigned u;
1567ec681f3Smrg	return sscanf(name, "UNK%u", &u) == 1;
1577ec681f3Smrg}
1587ec681f3Smrg
1597ec681f3Smrgchar *rnndec_decodeval(struct rnndeccontext *ctx, struct rnntypeinfo *ti, uint64_t value) {
1607ec681f3Smrg	int width = ti->high - ti->low + 1;
1617ec681f3Smrg	char *res = 0;
1627ec681f3Smrg	int i;
1637ec681f3Smrg	struct rnnvalue **vals;
1647ec681f3Smrg	int valsnum;
1657ec681f3Smrg	struct rnnbitfield **bitfields;
1667ec681f3Smrg	int bitfieldsnum;
1677ec681f3Smrg	char *tmp;
1687ec681f3Smrg	const char *ctmp;
1697ec681f3Smrg	uint64_t mask;
1707ec681f3Smrg
1717ec681f3Smrg	uint64_t value_orig = value;
1727ec681f3Smrg	if (!ti)
1737ec681f3Smrg		goto failhex;
1747ec681f3Smrg	value = (value & typeinfo_mask(ti)) >> ti->low;
1757ec681f3Smrg	value <<= ti->shr;
1767ec681f3Smrg
1777ec681f3Smrg	switch (ti->type) {
1787ec681f3Smrg		case RNN_TTYPE_ENUM:
1797ec681f3Smrg			vals = ti->eenum->vals;
1807ec681f3Smrg			valsnum = ti->eenum->valsnum;
1817ec681f3Smrg			goto doenum;
1827ec681f3Smrg		case RNN_TTYPE_INLINE_ENUM:
1837ec681f3Smrg			vals = ti->vals;
1847ec681f3Smrg			valsnum = ti->valsnum;
1857ec681f3Smrg			goto doenum;
1867ec681f3Smrg		doenum:
1877ec681f3Smrg			ctmp = rnndec_decode_enum_val(ctx, vals, valsnum, value);
1887ec681f3Smrg			if (ctmp) {
1897ec681f3Smrg				asprintf (&res, "%s%s%s", ctx->colors->eval, ctmp, ctx->colors->reset);
1907ec681f3Smrg				if (ti->addvariant) {
1917ec681f3Smrg					rnndec_varadd(ctx, ti->eenum->name, ctmp);
1927ec681f3Smrg				}
1937ec681f3Smrg				break;
1947ec681f3Smrg			}
1957ec681f3Smrg			goto failhex;
1967ec681f3Smrg		case RNN_TTYPE_BITSET:
1977ec681f3Smrg			bitfields = ti->ebitset->bitfields;
1987ec681f3Smrg			bitfieldsnum = ti->ebitset->bitfieldsnum;
1997ec681f3Smrg			goto dobitset;
2007ec681f3Smrg		case RNN_TTYPE_INLINE_BITSET:
2017ec681f3Smrg			bitfields = ti->bitfields;
2027ec681f3Smrg			bitfieldsnum = ti->bitfieldsnum;
2037ec681f3Smrg			goto dobitset;
2047ec681f3Smrg		dobitset:
2057ec681f3Smrg			mask = 0;
2067ec681f3Smrg			for (i = 0; i < bitfieldsnum; i++) {
2077ec681f3Smrg				if (!rnndec_varmatch(ctx, &bitfields[i]->varinfo))
2087ec681f3Smrg					continue;
2097ec681f3Smrg				uint64_t type_mask = typeinfo_mask(&bitfields[i]->typeinfo);
2107ec681f3Smrg				if (((value & type_mask) == 0) && is_unknown(bitfields[i]->name))
2117ec681f3Smrg					continue;
2127ec681f3Smrg				mask |= type_mask;
2137ec681f3Smrg				if (bitfields[i]->typeinfo.type == RNN_TTYPE_BOOLEAN) {
2147ec681f3Smrg					const char *color = is_unknown(bitfields[i]->name) ?
2157ec681f3Smrg							ctx->colors->err : ctx->colors->mod;
2167ec681f3Smrg					if (value & type_mask) {
2177ec681f3Smrg						if (!res)
2187ec681f3Smrg							asprintf (&res, "%s%s%s", color, bitfields[i]->name, ctx->colors->reset);
2197ec681f3Smrg						else {
2207ec681f3Smrg							asprintf (&tmp, "%s | %s%s%s", res, color, bitfields[i]->name, ctx->colors->reset);
2217ec681f3Smrg							free(res);
2227ec681f3Smrg							res = tmp;
2237ec681f3Smrg						}
2247ec681f3Smrg					}
2257ec681f3Smrg					continue;
2267ec681f3Smrg				}
2277ec681f3Smrg				char *subval;
2287ec681f3Smrg				if (is_unknown(bitfields[i]->name) && (bitfields[i]->typeinfo.type != RNN_TTYPE_A3XX_REGID)) {
2297ec681f3Smrg					uint64_t field_val = value & type_mask;
2307ec681f3Smrg					field_val = (field_val & typeinfo_mask(&bitfields[i]->typeinfo)) >> bitfields[i]->typeinfo.low;
2317ec681f3Smrg					field_val <<= bitfields[i]->typeinfo.shr;
2327ec681f3Smrg					asprintf (&subval, "%s%#"PRIx64"%s", ctx->colors->err, field_val, ctx->colors->reset);
2337ec681f3Smrg				} else {
2347ec681f3Smrg					subval = rnndec_decodeval(ctx, &bitfields[i]->typeinfo, value & type_mask);
2357ec681f3Smrg				}
2367ec681f3Smrg				if (!res)
2377ec681f3Smrg					asprintf (&res, "%s%s%s = %s", ctx->colors->rname, bitfields[i]->name, ctx->colors->reset, subval);
2387ec681f3Smrg				else {
2397ec681f3Smrg					asprintf (&tmp, "%s | %s%s%s = %s", res, ctx->colors->rname, bitfields[i]->name, ctx->colors->reset, subval);
2407ec681f3Smrg					free(res);
2417ec681f3Smrg					res = tmp;
2427ec681f3Smrg				}
2437ec681f3Smrg				free(subval);
2447ec681f3Smrg			}
2457ec681f3Smrg			if (value & ~mask) {
2467ec681f3Smrg				if (!res)
2477ec681f3Smrg					asprintf (&res, "%s%#"PRIx64"%s", ctx->colors->err, value & ~mask, ctx->colors->reset);
2487ec681f3Smrg				else {
2497ec681f3Smrg					asprintf (&tmp, "%s | %s%#"PRIx64"%s", res, ctx->colors->err, value & ~mask, ctx->colors->reset);
2507ec681f3Smrg					free(res);
2517ec681f3Smrg					res = tmp;
2527ec681f3Smrg				}
2537ec681f3Smrg			}
2547ec681f3Smrg			if (!res)
2557ec681f3Smrg				asprintf (&res, "%s0%s", ctx->colors->num, ctx->colors->reset);
2567ec681f3Smrg			asprintf (&tmp, "{ %s }", res);
2577ec681f3Smrg			free(res);
2587ec681f3Smrg			return tmp;
2597ec681f3Smrg		case RNN_TTYPE_SPECTYPE:
2607ec681f3Smrg			return rnndec_decodeval(ctx, &ti->spectype->typeinfo, value);
2617ec681f3Smrg		case RNN_TTYPE_HEX:
2627ec681f3Smrg			asprintf (&res, "%s%#"PRIx64"%s", ctx->colors->num, value, ctx->colors->reset);
2637ec681f3Smrg			break;
2647ec681f3Smrg		case RNN_TTYPE_FIXED:
2657ec681f3Smrg			if (value & UINT64_C(1) << (width-1)) {
2667ec681f3Smrg				asprintf (&res, "%s-%lf%s", ctx->colors->num,
2677ec681f3Smrg						((double)((UINT64_C(1) << width) - value)) / ((double)(1 << ti->radix)),
2687ec681f3Smrg						ctx->colors->reset);
2697ec681f3Smrg				break;
2707ec681f3Smrg			}
2717ec681f3Smrg			FALLTHROUGH;
2727ec681f3Smrg		case RNN_TTYPE_UFIXED:
2737ec681f3Smrg			asprintf (&res, "%s%lf%s", ctx->colors->num,
2747ec681f3Smrg					((double)value) / ((double)(1LL << ti->radix)),
2757ec681f3Smrg					ctx->colors->reset);
2767ec681f3Smrg			break;
2777ec681f3Smrg		case RNN_TTYPE_A3XX_REGID:
2787ec681f3Smrg			asprintf (&res, "%sr%"PRIu64".%c%s", ctx->colors->num, (value >> 2), "xyzw"[value & 0x3], ctx->colors->reset);
2797ec681f3Smrg			break;
2807ec681f3Smrg		case RNN_TTYPE_UINT:
2817ec681f3Smrg			asprintf (&res, "%s%"PRIu64"%s", ctx->colors->num, value, ctx->colors->reset);
2827ec681f3Smrg			break;
2837ec681f3Smrg		case RNN_TTYPE_INT:
2847ec681f3Smrg			if (value & UINT64_C(1) << (width-1))
2857ec681f3Smrg				asprintf (&res, "%s-%"PRIi64"%s", ctx->colors->num, (UINT64_C(1) << width) - value, ctx->colors->reset);
2867ec681f3Smrg			else
2877ec681f3Smrg				asprintf (&res, "%s%"PRIi64"%s", ctx->colors->num, value, ctx->colors->reset);
2887ec681f3Smrg			break;
2897ec681f3Smrg		case RNN_TTYPE_BOOLEAN:
2907ec681f3Smrg			if (value == 0) {
2917ec681f3Smrg				asprintf (&res, "%sFALSE%s", ctx->colors->eval, ctx->colors->reset);
2927ec681f3Smrg			} else if (value == 1) {
2937ec681f3Smrg				asprintf (&res, "%sTRUE%s", ctx->colors->eval, ctx->colors->reset);
2947ec681f3Smrg			}
2957ec681f3Smrg			break;
2967ec681f3Smrg		case RNN_TTYPE_FLOAT: {
2977ec681f3Smrg			union { uint64_t i; float f; double d; } val;
2987ec681f3Smrg			val.i = value;
2997ec681f3Smrg			if (width == 64)
3007ec681f3Smrg				asprintf(&res, "%s%f%s", ctx->colors->num,
3017ec681f3Smrg					val.d, ctx->colors->reset);
3027ec681f3Smrg			else if (width == 32)
3037ec681f3Smrg				asprintf(&res, "%s%f%s", ctx->colors->num,
3047ec681f3Smrg					val.f, ctx->colors->reset);
3057ec681f3Smrg			else if (width == 16)
3067ec681f3Smrg				asprintf(&res, "%s%f%s", ctx->colors->num,
3077ec681f3Smrg					float16(value), ctx->colors->reset);
3087ec681f3Smrg			else
3097ec681f3Smrg				goto failhex;
3107ec681f3Smrg
3117ec681f3Smrg			break;
3127ec681f3Smrg		}
3137ec681f3Smrg		failhex:
3147ec681f3Smrg		default:
3157ec681f3Smrg			asprintf (&res, "%s%#"PRIx64"%s", ctx->colors->num, value, ctx->colors->reset);
3167ec681f3Smrg			break;
3177ec681f3Smrg	}
3187ec681f3Smrg	if (value_orig & ~typeinfo_mask(ti)) {
3197ec681f3Smrg		asprintf (&tmp, "%s | %s%#"PRIx64"%s", res, ctx->colors->err, value_orig & ~typeinfo_mask(ti), ctx->colors->reset);
3207ec681f3Smrg		free(res);
3217ec681f3Smrg		res = tmp;
3227ec681f3Smrg	}
3237ec681f3Smrg	return res;
3247ec681f3Smrg}
3257ec681f3Smrg
3267ec681f3Smrgstatic char *appendidx (struct rnndeccontext *ctx, char *name, uint64_t idx, struct rnnenum *index) {
3277ec681f3Smrg	char *res;
3287ec681f3Smrg	const char *index_name = NULL;
3297ec681f3Smrg
3307ec681f3Smrg	if (index)
3317ec681f3Smrg		index_name = rnndec_decode_enum_val(ctx, index->vals, index->valsnum, idx);
3327ec681f3Smrg
3337ec681f3Smrg	if (index_name)
3347ec681f3Smrg		asprintf (&res, "%s[%s%s%s]", name, ctx->colors->eval, index_name, ctx->colors->reset);
3357ec681f3Smrg	else
3367ec681f3Smrg		asprintf (&res, "%s[%s%#"PRIx64"%s]", name, ctx->colors->num, idx, ctx->colors->reset);
3377ec681f3Smrg
3387ec681f3Smrg	free (name);
3397ec681f3Smrg	return res;
3407ec681f3Smrg}
3417ec681f3Smrg
3427ec681f3Smrg/* This could probably be made to work for stripes too.. */
3437ec681f3Smrgstatic int get_array_idx_offset(struct rnndelem *elem, uint64_t addr, uint64_t *idx, uint64_t *offset)
3447ec681f3Smrg{
3457ec681f3Smrg	if (elem->offsets) {
3467ec681f3Smrg		int i;
3477ec681f3Smrg		for (i = 0; i < elem->offsetsnum; i++) {
3487ec681f3Smrg			uint64_t o = elem->offsets[i];
3497ec681f3Smrg			if ((o <= addr) && (addr < (o + elem->stride))) {
3507ec681f3Smrg				*idx = i;
3517ec681f3Smrg				*offset = addr - o;
3527ec681f3Smrg				return 0;
3537ec681f3Smrg			}
3547ec681f3Smrg		}
3557ec681f3Smrg		return -1;
3567ec681f3Smrg	} else {
3577ec681f3Smrg		if (addr < elem->offset)
3587ec681f3Smrg			return -1;
3597ec681f3Smrg
3607ec681f3Smrg		*idx = (addr - elem->offset) / elem->stride;
3617ec681f3Smrg		*offset = (addr - elem->offset) % elem->stride;
3627ec681f3Smrg
3637ec681f3Smrg		if (elem->length && (*idx >= elem->length))
3647ec681f3Smrg			return -1;
3657ec681f3Smrg
3667ec681f3Smrg		return 0;
3677ec681f3Smrg	}
3687ec681f3Smrg}
3697ec681f3Smrg
3707ec681f3Smrgstatic struct rnndecaddrinfo *trymatch (struct rnndeccontext *ctx, struct rnndelem **elems, int elemsnum, uint64_t addr, int write, int dwidth, uint64_t *indices, int indicesnum) {
3717ec681f3Smrg	struct rnndecaddrinfo *res;
3727ec681f3Smrg	int i, j;
3737ec681f3Smrg	for (i = 0; i < elemsnum; i++) {
3747ec681f3Smrg		if (!rnndec_varmatch(ctx, &elems[i]->varinfo))
3757ec681f3Smrg			continue;
3767ec681f3Smrg		uint64_t offset, idx;
3777ec681f3Smrg		char *tmp, *name;
3787ec681f3Smrg		switch (elems[i]->type) {
3797ec681f3Smrg			case RNN_ETYPE_REG:
3807ec681f3Smrg				if (addr < elems[i]->offset)
3817ec681f3Smrg					break;
3827ec681f3Smrg				if (elems[i]->stride) {
3837ec681f3Smrg					idx = (addr-elems[i]->offset)/elems[i]->stride;
3847ec681f3Smrg					offset = (addr-elems[i]->offset)%elems[i]->stride;
3857ec681f3Smrg				} else {
3867ec681f3Smrg					idx = 0;
3877ec681f3Smrg					offset = addr-elems[i]->offset;
3887ec681f3Smrg				}
3897ec681f3Smrg				if (offset >= elems[i]->width/dwidth)
3907ec681f3Smrg					break;
3917ec681f3Smrg				if (elems[i]->length && idx >= elems[i]->length)
3927ec681f3Smrg					break;
3937ec681f3Smrg				res = calloc (sizeof *res, 1);
3947ec681f3Smrg				res->typeinfo = &elems[i]->typeinfo;
3957ec681f3Smrg				res->width = elems[i]->width;
3967ec681f3Smrg				asprintf (&res->name, "%s%s%s", ctx->colors->rname, elems[i]->name, ctx->colors->reset);
3977ec681f3Smrg				for (j = 0; j < indicesnum; j++)
3987ec681f3Smrg					res->name = appendidx(ctx, res->name, indices[j], NULL);
3997ec681f3Smrg				if (elems[i]->length != 1)
4007ec681f3Smrg					res->name = appendidx(ctx, res->name, idx, elems[i]->index);
4017ec681f3Smrg				if (offset) {
4027ec681f3Smrg					/* use _HI suffix for addresses */
4037ec681f3Smrg					if (offset == 1 &&
4047ec681f3Smrg						(!strcmp(res->typeinfo->name, "address") ||
4057ec681f3Smrg						 !strcmp(res->typeinfo->name, "waddress")))  {
4067ec681f3Smrg						asprintf (&tmp, "%s_HI", res->name);
4077ec681f3Smrg					} else {
4087ec681f3Smrg						asprintf (&tmp, "%s+%s%#"PRIx64"%s", res->name, ctx->colors->err, offset, ctx->colors->reset);
4097ec681f3Smrg					}
4107ec681f3Smrg					free(res->name);
4117ec681f3Smrg					res->name = tmp;
4127ec681f3Smrg				}
4137ec681f3Smrg				return res;
4147ec681f3Smrg			case RNN_ETYPE_STRIPE:
4157ec681f3Smrg				for (idx = 0; idx < elems[i]->length || !elems[i]->length; idx++) {
4167ec681f3Smrg					if (addr < elems[i]->offset + elems[i]->stride * idx)
4177ec681f3Smrg						break;
4187ec681f3Smrg					offset = addr - (elems[i]->offset + elems[i]->stride * idx);
4197ec681f3Smrg					int extraidx = (elems[i]->length != 1);
4207ec681f3Smrg					int nindnum = (elems[i]->name ? 0 : indicesnum + extraidx);
4217ec681f3Smrg					uint64_t nind[MAX2(nindnum, 1)];
4227ec681f3Smrg					if (!elems[i]->name) {
4237ec681f3Smrg						for (j = 0; j < indicesnum; j++)
4247ec681f3Smrg							nind[j] = indices[j];
4257ec681f3Smrg						if (extraidx)
4267ec681f3Smrg							nind[indicesnum] = idx;
4277ec681f3Smrg					}
4287ec681f3Smrg					res = trymatch (ctx, elems[i]->subelems, elems[i]->subelemsnum, offset, write, dwidth, nind, nindnum);
4297ec681f3Smrg					if (!res)
4307ec681f3Smrg						continue;
4317ec681f3Smrg					if (!elems[i]->name)
4327ec681f3Smrg						return res;
4337ec681f3Smrg					asprintf (&name, "%s%s%s", ctx->colors->rname, elems[i]->name, ctx->colors->reset);
4347ec681f3Smrg					for (j = 0; j < indicesnum; j++)
4357ec681f3Smrg						name = appendidx(ctx, name, indices[j], NULL);
4367ec681f3Smrg					if (elems[i]->length != 1)
4377ec681f3Smrg						name = appendidx(ctx, name, idx, elems[i]->index);
4387ec681f3Smrg					asprintf (&tmp, "%s.%s", name, res->name);
4397ec681f3Smrg					free(name);
4407ec681f3Smrg					free(res->name);
4417ec681f3Smrg					res->name = tmp;
4427ec681f3Smrg					return res;
4437ec681f3Smrg				}
4447ec681f3Smrg				break;
4457ec681f3Smrg			case RNN_ETYPE_ARRAY:
4467ec681f3Smrg				if (get_array_idx_offset(elems[i], addr, &idx, &offset))
4477ec681f3Smrg					break;
4487ec681f3Smrg				asprintf (&name, "%s%s%s", ctx->colors->rname, elems[i]->name, ctx->colors->reset);
4497ec681f3Smrg				for (j = 0; j < indicesnum; j++)
4507ec681f3Smrg					name = appendidx(ctx, name, indices[j], NULL);
4517ec681f3Smrg				if (elems[i]->length != 1)
4527ec681f3Smrg					name = appendidx(ctx, name, idx, elems[i]->index);
4537ec681f3Smrg				if ((res = trymatch (ctx, elems[i]->subelems, elems[i]->subelemsnum, offset, write, dwidth, 0, 0))) {
4547ec681f3Smrg					asprintf (&tmp, "%s.%s", name, res->name);
4557ec681f3Smrg					free(name);
4567ec681f3Smrg					free(res->name);
4577ec681f3Smrg					res->name = tmp;
4587ec681f3Smrg					return res;
4597ec681f3Smrg				}
4607ec681f3Smrg				res = calloc (sizeof *res, 1);
4617ec681f3Smrg				asprintf (&tmp, "%s+%s%#"PRIx64"%s", name, ctx->colors->err, offset, ctx->colors->reset);
4627ec681f3Smrg				free(name);
4637ec681f3Smrg				res->name = tmp;
4647ec681f3Smrg				return res;
4657ec681f3Smrg			default:
4667ec681f3Smrg				break;
4677ec681f3Smrg		}
4687ec681f3Smrg	}
4697ec681f3Smrg	return 0;
4707ec681f3Smrg}
4717ec681f3Smrg
4727ec681f3Smrgint rnndec_checkaddr(struct rnndeccontext *ctx, struct rnndomain *domain, uint64_t addr, int write) {
4737ec681f3Smrg	struct rnndecaddrinfo *res = trymatch(ctx, domain->subelems, domain->subelemsnum, addr, write, domain->width, 0, 0);
4747ec681f3Smrg	if (res) {
4757ec681f3Smrg		free(res->name);
4767ec681f3Smrg		free(res);
4777ec681f3Smrg	}
4787ec681f3Smrg	return res != NULL;
4797ec681f3Smrg}
4807ec681f3Smrg
4817ec681f3Smrgstruct rnndecaddrinfo *rnndec_decodeaddr(struct rnndeccontext *ctx, struct rnndomain *domain, uint64_t addr, int write) {
4827ec681f3Smrg	struct rnndecaddrinfo *res = trymatch(ctx, domain->subelems, domain->subelemsnum, addr, write, domain->width, 0, 0);
4837ec681f3Smrg	if (res)
4847ec681f3Smrg		return res;
4857ec681f3Smrg	res = calloc (sizeof *res, 1);
4867ec681f3Smrg	asprintf (&res->name, "%s%#"PRIx64"%s", ctx->colors->err, addr, ctx->colors->reset);
4877ec681f3Smrg	return res;
4887ec681f3Smrg}
4897ec681f3Smrg
4907ec681f3Smrgstatic unsigned tryreg(struct rnndeccontext *ctx, struct rnndelem **elems, int elemsnum,
4917ec681f3Smrg		int dwidth, const char *name, uint64_t *offset)
4927ec681f3Smrg{
4937ec681f3Smrg	int i;
4947ec681f3Smrg	unsigned ret;
4957ec681f3Smrg	const char *suffix = strchr(name, '[');
4967ec681f3Smrg	unsigned n = suffix ? (suffix - name) : strlen(name);
4977ec681f3Smrg	const char *dotsuffix = strchr(name, '.');
4987ec681f3Smrg	unsigned dotn = dotsuffix ? (dotsuffix - name) : strlen(name);
4997ec681f3Smrg
5007ec681f3Smrg	const char *child = NULL;
5017ec681f3Smrg	unsigned idx = 0;
5027ec681f3Smrg
5037ec681f3Smrg	if (suffix) {
5047ec681f3Smrg		const char *tmp = strchr(suffix, ']');
5057ec681f3Smrg		idx = strtol(suffix+1, NULL, 0);
5067ec681f3Smrg		child = tmp+2;
5077ec681f3Smrg	}
5087ec681f3Smrg
5097ec681f3Smrg	for (i = 0; i < elemsnum; i++) {
5107ec681f3Smrg		struct rnndelem *elem = elems[i];
5117ec681f3Smrg		if (!rnndec_varmatch(ctx, &elem->varinfo))
5127ec681f3Smrg			continue;
5137ec681f3Smrg		int match = elem->name && (strlen(elem->name) == n) && !strncmp(elem->name, name, n);
5147ec681f3Smrg		switch (elem->type) {
5157ec681f3Smrg			case RNN_ETYPE_REG:
5167ec681f3Smrg				if (match) {
5177ec681f3Smrg					assert(!suffix);
5187ec681f3Smrg					*offset = elem->offset;
5197ec681f3Smrg					return 1;
5207ec681f3Smrg				}
5217ec681f3Smrg				break;
5227ec681f3Smrg			case RNN_ETYPE_STRIPE:
5237ec681f3Smrg				if (elem->name) {
5247ec681f3Smrg					if (!dotsuffix)
5257ec681f3Smrg						break;
5267ec681f3Smrg					if (strlen(elem->name) != dotn || strncmp(elem->name, name, dotn))
5277ec681f3Smrg						break;
5287ec681f3Smrg				}
5297ec681f3Smrg				ret = tryreg(ctx, elem->subelems, elem->subelemsnum, dwidth,
5307ec681f3Smrg					elem->name ? dotsuffix : name, offset);
5317ec681f3Smrg				if (ret)
5327ec681f3Smrg					return 1;
5337ec681f3Smrg				break;
5347ec681f3Smrg			case RNN_ETYPE_ARRAY:
5357ec681f3Smrg				if (match) {
5367ec681f3Smrg					assert(suffix);
5377ec681f3Smrg					ret = tryreg(ctx, elem->subelems, elem->subelemsnum, dwidth, child, offset);
5387ec681f3Smrg					if (ret) {
5397ec681f3Smrg						*offset += elem->offset + (idx * elem->stride);
5407ec681f3Smrg						return 1;
5417ec681f3Smrg					}
5427ec681f3Smrg				}
5437ec681f3Smrg				break;
5447ec681f3Smrg			default:
5457ec681f3Smrg				break;
5467ec681f3Smrg		}
5477ec681f3Smrg	}
5487ec681f3Smrg	return 0;
5497ec681f3Smrg}
5507ec681f3Smrg
5517ec681f3Smrguint64_t rnndec_decodereg(struct rnndeccontext *ctx, struct rnndomain *domain, const char *name)
5527ec681f3Smrg{
5537ec681f3Smrg	uint64_t offset;
5547ec681f3Smrg	if (tryreg(ctx, domain->subelems, domain->subelemsnum, domain->width, name, &offset)) {
5557ec681f3Smrg		return offset;
5567ec681f3Smrg	} else {
5577ec681f3Smrg		return 0;
5587ec681f3Smrg	}
5597ec681f3Smrg}
560