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