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