| /* |
| * Copyright (C) 2010-2011 Marcin KoĆcielnicki <koriakin@0x04.net> |
| * Copyright (C) 2010 Luca Barbieri <luca@luca-barbieri.com> |
| * Copyright (C) 2010 Francisco Jerez <currojerez@riseup.net> |
| * Copyright (C) 2010 Martin Peres <martin.peres@ensi-bourges.fr> |
| * Copyright (C) 2010 Marcin Slusarz <marcin.slusarz@gmail.com> |
| * All Rights Reserved. |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining a |
| * copy of this software and associated documentation files (the "Software"), |
| * to deal in the Software without restriction, including without limitation |
| * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
| * and/or sell copies of the Software, and to permit persons to whom the |
| * Software is furnished to do so, subject to the following conditions: |
| * |
| * The above copyright notice and this permission notice (including the next |
| * paragraph) shall be included in all copies or substantial portions of the |
| * Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
| * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR |
| * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
| * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
| * OTHER DEALINGS IN THE SOFTWARE. |
| */ |
| |
| /* workaround libxml2 silliness: */ |
| #pragma GCC diagnostic ignored "-Wpointer-sign" |
| |
| #include <libxml/xmlversion.h> |
| #include <libxml/parser.h> |
| #include <libxml/xpath.h> |
| #include <libxml/xmlreader.h> |
| #include <stdint.h> |
| #include <string.h> |
| #include <limits.h> |
| #include <ctype.h> |
| #include <stdio.h> |
| #include "rnn.h" |
| #include "util.h" |
| |
| #include "util/u_debug.h" |
| |
| static char *catstr (char *a, char *b) { |
| if (!a) |
| return b; |
| return aprintf("%s_%s", a, b); |
| } |
| |
| static int strdiff (const char *a, const char *b) { |
| if (!a && !b) |
| return 0; |
| if (!a || !b) |
| return 1; |
| return strcmp (a, b); |
| } |
| |
| static void rnn_err(struct rnndb *db, const char *format, ...) _util_printf_format(2, 3); |
| |
| static void rnn_err(struct rnndb *db, const char *format, ...) |
| { |
| va_list ap; |
| va_start(ap, format); |
| vfprintf(stderr, format, ap); |
| va_end(ap); |
| db->estatus = 1; |
| } |
| |
| void rnn_init(void) { |
| LIBXML_TEST_VERSION |
| xmlInitParser(); |
| } |
| |
| struct rnndb *rnn_newdb(void) { |
| struct rnndb *db = calloc(sizeof *db, 1); |
| return db; |
| } |
| |
| static char *getcontent (xmlNode *attr) { |
| xmlNode *chain = attr->children; |
| size_t size = 0; |
| char *content, *p; |
| while (chain) { |
| if (chain->type == XML_TEXT_NODE) |
| size += strlen(chain->content); |
| chain = chain->next; |
| } |
| p = content = malloc(size + 1); |
| chain = attr->children; |
| while (chain) { |
| if (chain->type == XML_TEXT_NODE) { |
| char* sp = chain->content; |
| if(p == content) { |
| while(isspace(*sp)) |
| ++sp; |
| } |
| size_t len = strlen(sp); |
| memcpy(p, sp, len); |
| p += len; |
| } |
| chain = chain->next; |
| } |
| while(p != content && isspace(p[-1])) |
| --p; |
| *p = 0; |
| return content; |
| } |
| |
| static char *getattrib (struct rnndb *db, char *file, int line, xmlAttr *attr) { |
| xmlNode *chain = attr->children; |
| while (chain) { |
| if (chain->type != XML_TEXT_NODE) { |
| rnn_err(db, "%s:%d: unknown attribute child \"%s\" in attribute \"%s\"\n", file, line, chain->name, attr->name); |
| } else { |
| return chain->content; |
| } |
| chain = chain->next; |
| } |
| return ""; |
| } |
| |
| static int getboolattrib (struct rnndb *db, char *file, int line, xmlAttr *attr) { |
| char *c = getattrib(db, file, line, attr); |
| if (!strcmp(c, "yes") || !strcmp(c, "1") || !strcmp(c, "true")) |
| return 1; |
| if (!strcmp(c, "no") || !strcmp(c, "0") || !strcmp(c, "false")) |
| return 0; |
| rnn_err(db, "%s:%d: invalid boolean value \"%s\" in attribute \"%s\"\n", file, line, c, attr->name); |
| return 0; |
| } |
| |
| static uint64_t getnum(struct rnndb *db, char *file, int line, xmlAttr *attr, char *c) |
| { |
| char *cc; |
| uint64_t res; |
| if (strchr(c, 'x') || strchr(c, 'X')) |
| res = strtoull(c, &cc, 16); |
| else |
| res = strtoull(c, &cc, 10); |
| if (*cc) { |
| rnn_err(db, "%s:%d: invalid numeric value \"%s\" in attribute \"%s\"\n", file, line, c, attr->name); |
| } |
| return res; |
| } |
| |
| static uint64_t getnumattrib (struct rnndb *db, char *file, int line, xmlAttr *attr) { |
| char *c = getattrib(db, file, line, attr); |
| return getnum(db, file, line, attr, c); |
| } |
| |
| static int trytop (struct rnndb *db, char *file, xmlNode *node); |
| |
| static int trydoc (struct rnndb *db, char *file, xmlNode *node) { |
| if (!strcmp(node->name, "brief")) { |
| return 1; |
| } else if (!strcmp(node->name, "doc")) { |
| return 1; |
| } |
| return 0; |
| } |
| |
| static struct rnnvalue *parsevalue(struct rnndb *db, char *file, xmlNode *node); |
| static struct rnnbitfield *parsebitfield(struct rnndb *db, char *file, xmlNode *node); |
| |
| static int trytypetag (struct rnndb *db, char *file, xmlNode *node, struct rnntypeinfo *ti) { |
| if (!strcmp(node->name, "value")) { |
| struct rnnvalue *val = parsevalue(db, file, node); |
| if (val) |
| ADDARRAY(ti->vals, val); |
| return 1; |
| } else if (!strcmp(node->name, "bitfield")) { |
| struct rnnbitfield *bf = parsebitfield(db, file, node); |
| if (bf) |
| ADDARRAY(ti->bitfields, bf); |
| return 1; |
| } |
| return 0; |
| } |
| static int trytypeattr (struct rnndb *db, char *file, xmlNode *node, xmlAttr *attr, struct rnntypeinfo *ti) { |
| if (!strcmp(attr->name, "shr")) { |
| ti->shr = getnumattrib(db, file, node->line, attr); |
| return 1; |
| } else if (!strcmp(attr->name, "min")) { |
| ti->min = getnumattrib(db, file, node->line, attr); |
| ti->minvalid = 1; |
| return 1; |
| } else if (!strcmp(attr->name, "max")) { |
| ti->max = getnumattrib(db, file, node->line, attr); |
| ti->maxvalid = 1; |
| return 1; |
| } else if (!strcmp(attr->name, "align")) { |
| ti->align = getnumattrib(db, file, node->line, attr); |
| ti->alignvalid = 1; |
| return 1; |
| } else if (!strcmp(attr->name, "type")) { |
| ti->name = strdup(getattrib(db, file, node->line, attr));; |
| return 1; |
| } else if (!strcmp(attr->name, "radix")) { |
| ti->radix = getnumattrib(db, file, node->line, attr); |
| ti->radixvalid = 1; |
| return 1; |
| } else if (!strcmp(attr->name, "pos")) { |
| ti->high = ti->low = getnumattrib(db, file, node->line, attr); |
| return 1; |
| } else if (!strcmp(attr->name, "low")) { |
| ti->low = getnumattrib(db, file, node->line, attr); |
| return 1; |
| } else if (!strcmp(attr->name, "high")) { |
| ti->high = getnumattrib(db, file, node->line, attr); |
| return 1; |
| } else if (!strcmp(attr->name, "addvariant")) { |
| ti->addvariant = getboolattrib(db, file, node->line, attr); |
| return 1; |
| } |
| return 0; |
| } |
| |
| static struct rnnvalue *parsevalue(struct rnndb *db, char *file, xmlNode *node) { |
| struct rnnvalue *val = calloc(sizeof *val, 1); |
| val->file = file; |
| xmlAttr *attr = node->properties; |
| while (attr) { |
| if (!strcmp(attr->name, "name")) { |
| val->name = strdup(getattrib(db, file, node->line, attr)); |
| } else if (!strcmp(attr->name, "value")) { |
| val->value = getnumattrib(db, file, node->line, attr); |
| val->valvalid = 1; |
| } else if (!strcmp(attr->name, "varset")) { |
| val->varinfo.varsetstr = strdup(getattrib(db, file, node->line, attr)); |
| } else if (!strcmp(attr->name, "variants")) { |
| val->varinfo.variantsstr = strdup(getattrib(db, file, node->line, attr)); |
| } else { |
| rnn_err(db, "%s:%d: wrong attribute \"%s\" for value\n", file, node->line, attr->name); |
| } |
| attr = attr->next; |
| } |
| xmlNode *chain = node->children; |
| while (chain) { |
| if (chain->type != XML_ELEMENT_NODE) { |
| } else if (!trytop(db, file, chain) && !trydoc(db, file, chain)) { |
| rnn_err(db, "%s:%d: wrong tag in %s: <%s>\n", file, chain->line, node->name, chain->name); |
| } |
| chain = chain->next; |
| } |
| if (!val->name) { |
| rnn_err(db, "%s:%d: nameless value\n", file, node->line); |
| return 0; |
| } else { |
| return val; |
| } |
| } |
| |
| static void parsespectype(struct rnndb *db, char *file, xmlNode *node) { |
| struct rnnspectype *res = calloc (sizeof *res, 1); |
| res->file = file; |
| xmlAttr *attr = node->properties; |
| int i; |
| while (attr) { |
| if (!strcmp(attr->name, "name")) { |
| res->name = strdup(getattrib(db, file, node->line, attr)); |
| } else if (!trytypeattr(db, file, node, attr, &res->typeinfo)) { |
| rnn_err(db, "%s:%d: wrong attribute \"%s\" for spectype\n", file, node->line, attr->name); |
| } |
| attr = attr->next; |
| } |
| if (!res->name) { |
| rnn_err(db, "%s:%d: nameless spectype\n", file, node->line); |
| return; |
| } |
| for (i = 0; i < db->spectypesnum; i++) |
| if (!strcmp(db->spectypes[i]->name, res->name)) { |
| rnn_err(db, "%s:%d: duplicated spectype name %s\n", file, node->line, res->name); |
| return; |
| } |
| ADDARRAY(db->spectypes, res); |
| xmlNode *chain = node->children; |
| while (chain) { |
| if (chain->type != XML_ELEMENT_NODE) { |
| } else if (!trytypetag(db, file, chain, &res->typeinfo) && !trytop(db, file, chain) && !trydoc(db, file, chain)) { |
| rnn_err(db, "%s:%d: wrong tag in spectype: <%s>\n", file, chain->line, chain->name); |
| } |
| chain = chain->next; |
| } |
| } |
| |
| static void parseenum(struct rnndb *db, char *file, xmlNode *node) { |
| xmlAttr *attr = node->properties; |
| char *name = 0; |
| int isinline = 0; |
| int bare = 0; |
| char *prefixstr = 0; |
| char *varsetstr = 0; |
| char *variantsstr = 0; |
| int i; |
| while (attr) { |
| if (!strcmp(attr->name, "name")) { |
| name = getattrib(db, file, node->line, attr); |
| } else if (!strcmp(attr->name, "bare")) { |
| bare = getboolattrib(db, file, node->line, attr); |
| } else if (!strcmp(attr->name, "inline")) { |
| isinline = getboolattrib(db, file, node->line, attr); |
| } else if (!strcmp(attr->name, "prefix")) { |
| prefixstr = strdup(getattrib(db, file, node->line, attr)); |
| } else if (!strcmp(attr->name, "varset")) { |
| varsetstr = strdup(getattrib(db, file, node->line, attr)); |
| } else if (!strcmp(attr->name, "variants")) { |
| variantsstr = strdup(getattrib(db, file, node->line, attr)); |
| } else { |
| rnn_err(db, "%s:%d: wrong attribute \"%s\" for enum\n", file, node->line, attr->name); |
| } |
| attr = attr->next; |
| } |
| if (!name) { |
| rnn_err(db, "%s:%d: nameless enum\n", file, node->line); |
| return; |
| } |
| struct rnnenum *cur = 0; |
| for (i = 0; i < db->enumsnum; i++) |
| if (!strcmp(db->enums[i]->name, name)) { |
| cur = db->enums[i]; |
| break; |
| } |
| if (cur) { |
| if (strdiff(cur->varinfo.prefixstr, prefixstr) || |
| strdiff(cur->varinfo.varsetstr, varsetstr) || |
| strdiff(cur->varinfo.variantsstr, variantsstr) || |
| cur->isinline != isinline || cur->bare != bare) { |
| rnn_err(db, "%s:%d: merge fail for enum %s\n", file, node->line, node->name); |
| } |
| } else { |
| cur = calloc(sizeof *cur, 1); |
| cur->name = strdup(name); |
| cur->isinline = isinline; |
| cur->bare = bare; |
| cur->varinfo.prefixstr = prefixstr; |
| cur->varinfo.varsetstr = varsetstr; |
| cur->varinfo.variantsstr = variantsstr; |
| cur->file = file; |
| ADDARRAY(db->enums, cur); |
| } |
| xmlNode *chain = node->children; |
| while (chain) { |
| if (chain->type != XML_ELEMENT_NODE) { |
| } else if (!strcmp(chain->name, "value")) { |
| struct rnnvalue *val = parsevalue(db, file, chain); |
| if (val) |
| ADDARRAY(cur->vals, val); |
| } else if (!trytop(db, file, chain) && !trydoc(db, file, chain)) { |
| rnn_err(db, "%s:%d: wrong tag in enum: <%s>\n", file, chain->line, chain->name); |
| } |
| chain = chain->next; |
| } |
| } |
| |
| static struct rnnbitfield *parsebitfield(struct rnndb *db, char *file, xmlNode *node) { |
| struct rnnbitfield *bf = calloc(sizeof *bf, 1); |
| bf->file = file; |
| xmlAttr *attr = node->properties; |
| bf->typeinfo.low = bf->typeinfo.high = -1; |
| while (attr) { |
| if (!strcmp(attr->name, "name")) { |
| bf->name = strdup(getattrib(db, file, node->line, attr)); |
| } else if (!strcmp(attr->name, "varset")) { |
| bf->varinfo.varsetstr = strdup(getattrib(db, file, node->line, attr)); |
| } else if (!strcmp(attr->name, "variants")) { |
| bf->varinfo.variantsstr = strdup(getattrib(db, file, node->line, attr)); |
| } else if (!trytypeattr(db, file, node, attr, &bf->typeinfo)) { |
| rnn_err(db, "%s:%d: wrong attribute \"%s\" for bitfield\n", file, node->line, attr->name); |
| } |
| attr = attr->next; |
| } |
| xmlNode *chain = node->children; |
| while (chain) { |
| if (chain->type != XML_ELEMENT_NODE) { |
| } else if (!trytypetag(db, file, chain, &bf->typeinfo) && !trytop(db, file, chain) && !trydoc(db, file, chain)) { |
| rnn_err(db, "%s:%d: wrong tag in %s: <%s>\n", file, chain->line, node->name, chain->name); |
| } |
| chain = chain->next; |
| } |
| if (!bf->name) { |
| rnn_err(db, "%s:%d: nameless bitfield\n", file, node->line); |
| return 0; |
| } else if (bf->typeinfo.low < 0|| bf->typeinfo.high < 0 || bf->typeinfo.high < bf->typeinfo.low) { |
| rnn_err(db, "%s:%d: bitfield has wrong placement\n", file, node->line); |
| return 0; |
| } else { |
| return bf; |
| } |
| } |
| |
| static void parsebitset(struct rnndb *db, char *file, xmlNode *node) { |
| xmlAttr *attr = node->properties; |
| char *name = 0; |
| int isinline = 0; |
| int bare = 0; |
| char *prefixstr = 0; |
| char *varsetstr = 0; |
| char *variantsstr = 0; |
| int i; |
| while (attr) { |
| if (!strcmp(attr->name, "name")) { |
| name = getattrib(db, file, node->line, attr); |
| } else if (!strcmp(attr->name, "bare")) { |
| bare = getboolattrib(db, file, node->line, attr); |
| } else if (!strcmp(attr->name, "inline")) { |
| isinline = getboolattrib(db, file, node->line, attr); |
| } else if (!strcmp(attr->name, "prefix")) { |
| prefixstr = strdup(getattrib(db, file, node->line, attr)); |
| } else if (!strcmp(attr->name, "varset")) { |
| varsetstr = strdup(getattrib(db, file, node->line, attr)); |
| } else if (!strcmp(attr->name, "variants")) { |
| variantsstr = strdup(getattrib(db, file, node->line, attr)); |
| } else { |
| rnn_err(db, "%s:%d: wrong attribute \"%s\" for bitset\n", file, node->line, attr->name); |
| } |
| attr = attr->next; |
| } |
| if (!name) { |
| rnn_err(db, "%s:%d: nameless bitset\n", file, node->line); |
| return; |
| } |
| struct rnnbitset *cur = 0; |
| for (i = 0; i < db->bitsetsnum; i++) |
| if (!strcmp(db->bitsets[i]->name, name)) { |
| cur = db->bitsets[i]; |
| break; |
| } |
| if (cur) { |
| if (strdiff(cur->varinfo.prefixstr, prefixstr) || |
| strdiff(cur->varinfo.varsetstr, varsetstr) || |
| strdiff(cur->varinfo.variantsstr, variantsstr) || |
| cur->isinline != isinline || cur->bare != bare) { |
| rnn_err(db, "%s:%d: merge fail for bitset %s\n", file, node->line, node->name); |
| } |
| } else { |
| cur = calloc(sizeof *cur, 1); |
| cur->name = strdup(name); |
| cur->isinline = isinline; |
| cur->bare = bare; |
| cur->varinfo.prefixstr = prefixstr; |
| cur->varinfo.varsetstr = varsetstr; |
| cur->varinfo.variantsstr = variantsstr; |
| cur->file = file; |
| ADDARRAY(db->bitsets, cur); |
| } |
| xmlNode *chain = node->children; |
| while (chain) { |
| if (chain->type != XML_ELEMENT_NODE) { |
| } else if (!strcmp(chain->name, "bitfield")) { |
| struct rnnbitfield *bf = parsebitfield(db, file, chain); |
| if (bf) |
| ADDARRAY(cur->bitfields, bf); |
| } else if (!trytop(db, file, chain) && !trydoc(db, file, chain)) { |
| rnn_err(db, "%s:%d: wrong tag in bitset: <%s>\n", file, chain->line, chain->name); |
| } |
| chain = chain->next; |
| } |
| } |
| |
| static struct rnndelem *trydelem(struct rnndb *db, char *file, xmlNode *node) { |
| if (!strcmp(node->name, "use-group")) { |
| struct rnndelem *res = calloc(sizeof *res, 1); |
| res->file = file; |
| res->type = RNN_ETYPE_USE_GROUP; |
| xmlAttr *attr = node->properties; |
| while (attr) { |
| if (!strcmp(attr->name, "ref")) { |
| res->name = strdup(getattrib(db, file, node->line, attr)); |
| } else { |
| rnn_err(db, "%s:%d: wrong attribute \"%s\" for %s\n", file, node->line, attr->name, node->name); |
| } |
| attr = attr->next; |
| } |
| if (!res->name) { |
| rnn_err(db, "%s:%d: nameless use-group\n", file, node->line); |
| return 0; |
| } |
| return res; |
| } else if (!strcmp(node->name, "stripe") || !strcmp(node->name, "array")) { |
| struct rnndelem *res = calloc(sizeof *res, 1); |
| if (!strcmp(node->name, "array")) |
| res->name = ""; |
| res->type = (strcmp(node->name, "stripe")?RNN_ETYPE_ARRAY:RNN_ETYPE_STRIPE); |
| res->length = 1; |
| res->file = file; |
| xmlAttr *attr = node->properties; |
| while (attr) { |
| if (!strcmp(attr->name, "name")) { |
| res->name = strdup(getattrib(db, file, node->line, attr)); |
| } else if (!strcmp(attr->name, "offset")) { |
| res->offset = getnumattrib(db, file, node->line, attr); |
| } else if (!strcmp(attr->name, "offsets")) { |
| char *str = strdup(getattrib(db, file, node->line, attr)); |
| char *tok, *save, *tmp = str; |
| while ((tok = strtok_r(str, ",", &save))) { |
| uint64_t offset = getnum(db, file, node->line, attr, tok); |
| ADDARRAY(res->offsets, offset); |
| str = NULL; |
| } |
| if (str) |
| fprintf(stderr, "%s:%d: invalid offsets: %s\n", file, node->line, str); |
| free(tmp); |
| } else if (!strcmp(attr->name, "doffset")) { |
| /* dynamic runtime determined offset: */ |
| res->doffset = strdup(getattrib(db, file, node->line, attr)); |
| } else if (!strcmp(attr->name, "doffsets")) { |
| /* dynamic runtime determined offsets: */ |
| char *str = strdup(getattrib(db, file, node->line, attr)); |
| char *tok, *save, *tmp = str; |
| while ((tok = strtok_r(str, ",", &save))) { |
| char *doffset = strdup(tok); |
| ADDARRAY(res->doffsets, doffset); |
| str = NULL; |
| } |
| if (str) |
| fprintf(stderr, "%s:%d: invalid offsets: %s\n", file, node->line, str); |
| free(tmp); |
| } else if (!strcmp(attr->name, "length")) { |
| res->length = getnumattrib(db, file, node->line, attr); |
| } else if (!strcmp(attr->name, "stride")) { |
| res->stride = getnumattrib(db, file, node->line, attr); |
| } else if (!strcmp(attr->name, "prefix")) { |
| res->varinfo.prefixstr = strdup(getattrib(db, file, node->line, attr)); |
| } else if (!strcmp(attr->name, "varset")) { |
| res->varinfo.varsetstr = strdup(getattrib(db, file, node->line, attr)); |
| } else if (!strcmp(attr->name, "variants")) { |
| res->varinfo.variantsstr = strdup(getattrib(db, file, node->line, attr)); |
| } else if (!strcmp(attr->name, "index")) { |
| const char *enumname = getattrib(db, file, node->line, attr); |
| res->index = rnn_findenum(db, enumname); |
| if (!res->index) { |
| rnn_err(db, "%s:%d: invalid enum name \"%s\"\n", file, node->line, enumname); |
| } |
| } else { |
| rnn_err(db, "%s:%d: wrong attribute \"%s\" for %s\n", file, node->line, attr->name, node->name); |
| } |
| attr = attr->next; |
| } |
| xmlNode *chain = node->children; |
| while (chain) { |
| struct rnndelem *delem; |
| if (chain->type != XML_ELEMENT_NODE) { |
| } else if ((delem = trydelem(db, file, chain))) { |
| ADDARRAY(res->subelems, delem); |
| } else if (!trytop(db, file, chain) && !trydoc(db, file, chain)) { |
| rnn_err(db, "%s:%d: wrong tag in %s: <%s>\n", file, chain->line, node->name, chain->name); |
| } |
| chain = chain->next; |
| } |
| |
| /* Sanity checking */ |
| if (res->type == RNN_ETYPE_ARRAY && res->stride == 0) { |
| fprintf(stderr, "%s: Array %s's stride is undefined. Aborting.\n", file, res->name); |
| exit(-1); |
| } |
| return res; |
| |
| } |
| int width; |
| if (!strcmp(node->name, "reg8")) |
| width = 8; |
| else if (!strcmp(node->name, "reg16")) |
| width = 16; |
| else if (!strcmp(node->name, "reg32")) |
| width = 32; |
| else if (!strcmp(node->name, "reg64")) |
| width = 64; |
| else |
| return 0; |
| struct rnndelem *res = calloc(sizeof *res, 1); |
| res->file = file; |
| res->type = RNN_ETYPE_REG; |
| res->width = width; |
| res->length = 1; |
| res->access = RNN_ACCESS_RW; |
| xmlAttr *attr = node->properties; |
| res->typeinfo.low = 0; |
| res->typeinfo.high = width - 1; |
| while (attr) { |
| if (!strcmp(attr->name, "name")) { |
| res->name = strdup(getattrib(db, file, node->line, attr)); |
| } else if (!strcmp(attr->name, "offset")) { |
| res->offset = getnumattrib(db, file, node->line, attr); |
| } else if (!strcmp(attr->name, "length")) { |
| res->length = getnumattrib(db, file, node->line, attr); |
| } else if (!strcmp(attr->name, "stride")) { |
| res->stride = getnumattrib(db, file, node->line, attr); |
| } else if (!strcmp(attr->name, "varset")) { |
| res->varinfo.varsetstr = strdup(getattrib(db, file, node->line, attr)); |
| } else if (!strcmp(attr->name, "variants")) { |
| res->varinfo.variantsstr = strdup(getattrib(db, file, node->line, attr)); |
| } else if (!strcmp(attr->name, "access")) { |
| char *str = getattrib(db, file, node->line, attr); |
| if (!strcmp(str, "r")) |
| res->access = RNN_ACCESS_R; |
| else if (!strcmp(str, "w")) |
| res->access = RNN_ACCESS_W; |
| else if (!strcmp(str, "rw")) |
| res->access = RNN_ACCESS_RW; |
| else |
| fprintf (stderr, "%s:%d: wrong access type \"%s\" for register\n", file, node->line, str); |
| } else if (!trytypeattr(db, file, node, attr, &res->typeinfo)) { |
| rnn_err(db, "%s:%d: wrong attribute \"%s\" for register\n", file, node->line, attr->name); |
| } |
| attr = attr->next; |
| } |
| xmlNode *chain = node->children; |
| while (chain) { |
| if (chain->type != XML_ELEMENT_NODE) { |
| } else if (!trytypetag(db, file, chain, &res->typeinfo) && !trytop(db, file, chain) && !trydoc(db, file, chain)) { |
| rnn_err(db, "%s:%d: wrong tag in %s: <%s>\n", file, chain->line, node->name, chain->name); |
| } |
| chain = chain->next; |
| } |
| if (!res->name) { |
| rnn_err(db, "%s:%d: nameless register\n", file, node->line); |
| return 0; |
| } else { |
| } |
| return res; |
| } |
| |
| static void parsegroup(struct rnndb *db, char *file, xmlNode *node) { |
| xmlAttr *attr = node->properties; |
| char *name = 0; |
| int i; |
| while (attr) { |
| if (!strcmp(attr->name, "name")) { |
| name = getattrib(db, file, node->line, attr); |
| } else { |
| rnn_err(db, "%s:%d: wrong attribute \"%s\" for group\n", file, node->line, attr->name); |
| } |
| attr = attr->next; |
| } |
| if (!name) { |
| rnn_err(db, "%s:%d: nameless group\n", file, node->line); |
| return; |
| } |
| struct rnngroup *cur = 0; |
| for (i = 0; i < db->groupsnum; i++) |
| if (!strcmp(db->groups[i]->name, name)) { |
| cur = db->groups[i]; |
| break; |
| } |
| if (!cur) { |
| cur = calloc(sizeof *cur, 1); |
| cur->name = strdup(name); |
| ADDARRAY(db->groups, cur); |
| } |
| xmlNode *chain = node->children; |
| while (chain) { |
| struct rnndelem *delem; |
| if (chain->type != XML_ELEMENT_NODE) { |
| } else if ((delem = trydelem(db, file, chain))) { |
| ADDARRAY(cur->subelems, delem); |
| } else if (!trytop(db, file, chain) && !trydoc(db, file, chain)) { |
| rnn_err(db, "%s:%d: wrong tag in group: <%s>\n", file, chain->line, chain->name); |
| } |
| chain = chain->next; |
| } |
| } |
| |
| static void parsedomain(struct rnndb *db, char *file, xmlNode *node) { |
| xmlAttr *attr = node->properties; |
| char *name = 0; |
| uint64_t size = 0; int width = 8; |
| int bare = 0; |
| char *prefixstr = 0; |
| char *varsetstr = 0; |
| char *variantsstr = 0; |
| int i; |
| while (attr) { |
| if (!strcmp(attr->name, "name")) { |
| name = getattrib(db, file, node->line, attr); |
| } else if (!strcmp(attr->name, "bare")) { |
| bare = getboolattrib(db, file, node->line, attr); |
| } else if (!strcmp(attr->name, "size")) { |
| size = getnumattrib(db, file, node->line, attr); |
| } else if (!strcmp(attr->name, "width")) { |
| width = getnumattrib(db, file, node->line, attr); |
| } else if (!strcmp(attr->name, "prefix")) { |
| prefixstr = strdup(getattrib(db, file, node->line, attr)); |
| } else if (!strcmp(attr->name, "varset")) { |
| varsetstr = strdup(getattrib(db, file, node->line, attr)); |
| } else if (!strcmp(attr->name, "variants")) { |
| variantsstr = strdup(getattrib(db, file, node->line, attr)); |
| } else { |
| rnn_err(db, "%s:%d: wrong attribute \"%s\" for domain\n", file, node->line, attr->name); |
| } |
| attr = attr->next; |
| } |
| if (!name) { |
| rnn_err(db, "%s:%d: nameless domain\n", file, node->line); |
| return; |
| } |
| struct rnndomain *cur = 0; |
| for (i = 0; i < db->domainsnum; i++) |
| if (!strcmp(db->domains[i]->name, name)) { |
| cur = db->domains[i]; |
| break; |
| } |
| if (cur) { |
| if (strdiff(cur->varinfo.prefixstr, prefixstr) || |
| strdiff(cur->varinfo.varsetstr, varsetstr) || |
| strdiff(cur->varinfo.variantsstr, variantsstr) || |
| cur->width != width || |
| cur->bare != bare || |
| (size && cur->size && size != cur->size)) { |
| rnn_err(db, "%s:%d: merge fail for domain %s\n", file, node->line, node->name); |
| } else { |
| if (size) |
| cur->size = size; |
| } |
| } else { |
| cur = calloc(sizeof *cur, 1); |
| cur->name = strdup(name); |
| cur->bare = bare; |
| cur->width = width; |
| cur->size = size; |
| cur->varinfo.prefixstr = prefixstr; |
| cur->varinfo.varsetstr = varsetstr; |
| cur->varinfo.variantsstr = variantsstr; |
| cur->file = file; |
| ADDARRAY(db->domains, cur); |
| } |
| xmlNode *chain = node->children; |
| while (chain) { |
| struct rnndelem *delem; |
| if (chain->type != XML_ELEMENT_NODE) { |
| } else if ((delem = trydelem(db, file, chain))) { |
| ADDARRAY(cur->subelems, delem); |
| } else if (!trytop(db, file, chain) && !trydoc(db, file, chain)) { |
| rnn_err(db, "%s:%d: wrong tag in domain: <%s>\n", file, chain->line, chain->name); |
| } |
| chain = chain->next; |
| } |
| } |
| |
| static void parsecopyright(struct rnndb *db, char *file, xmlNode *node) { |
| struct rnncopyright* copyright = &db->copyright; |
| xmlAttr *attr = node->properties; |
| while (attr) { |
| if (!strcmp(attr->name, "year")) { |
| unsigned firstyear = getnumattrib(db, file, node->line, attr); |
| if(!copyright->firstyear || firstyear < copyright->firstyear) |
| copyright->firstyear = firstyear; |
| } else { |
| rnn_err(db, "%s:%d: wrong attribute \"%s\" for copyright\n", file, node->line, attr->name); |
| } |
| attr = attr->next; |
| } |
| xmlNode *chain = node->children; |
| while (chain) { |
| if (chain->type != XML_ELEMENT_NODE) { |
| } else if (!strcmp(chain->name, "license")) |
| if(copyright->license) { |
| if(strcmp(copyright->license, node->content)) { |
| fprintf(stderr, "fatal error: multiple different licenses specified!\n"); |
| abort(); /* TODO: do something better here, but headergen, xml2html, etc. should not produce anything in this case */ |
| } |
| } else |
| copyright->license = getcontent(chain); |
| else if (!strcmp(chain->name, "author")) { |
| struct rnnauthor* author = calloc(sizeof *author, 1); |
| xmlAttr* authorattr = chain->properties; |
| xmlNode *authorchild = chain->children; |
| author->contributions = getcontent(chain); |
| while (authorattr) { |
| if (!strcmp(authorattr->name, "name")) |
| author->name = strdup(getattrib(db, file, chain->line, authorattr)); |
| else if (!strcmp(authorattr->name, "email")) |
| author->email = strdup(getattrib(db, file, chain->line, authorattr)); |
| else { |
| rnn_err(db, "%s:%d: wrong attribute \"%s\" for author\n", file, chain->line, authorattr->name); |
| } |
| authorattr = authorattr->next; |
| } |
| while(authorchild) { |
| if (authorchild->type != XML_ELEMENT_NODE) { |
| } else if (!strcmp(authorchild->name, "nick")) { |
| xmlAttr* nickattr = authorchild->properties; |
| char* nickname = 0; |
| while(nickattr) { |
| if (!strcmp(nickattr->name, "name")) |
| nickname = strdup(getattrib(db, file, authorchild->line, nickattr)); |
| else { |
| rnn_err(db, "%s:%d: wrong attribute \"%s\" for nick\n", file, authorchild->line, nickattr->name); |
| } |
| nickattr = nickattr->next; |
| } |
| if(!nickname) { |
| rnn_err(db, "%s:%d: missing \"name\" attribute for nick\n", file, authorchild->line); |
| } else |
| ADDARRAY(author->nicknames, nickname); |
| } else { |
| rnn_err(db, "%s:%d: wrong tag in author: <%s>\n", file, authorchild->line, authorchild->name); |
| } |
| authorchild = authorchild->next; |
| } |
| ADDARRAY(copyright->authors, author); |
| } else { |
| rnn_err(db, "%s:%d: wrong tag in copyright: <%s>\n", file, chain->line, chain->name); |
| } |
| chain = chain->next; |
| } |
| } |
| |
| static int trytop (struct rnndb *db, char *file, xmlNode *node) { |
| if (!strcmp(node->name, "enum")) { |
| parseenum(db, file, node); |
| return 1; |
| } else if (!strcmp(node->name, "bitset")) { |
| parsebitset(db, file, node); |
| return 1; |
| } else if (!strcmp(node->name, "group")) { |
| parsegroup(db, file, node); |
| return 1; |
| } else if (!strcmp(node->name, "domain")) { |
| parsedomain(db, file, node); |
| return 1; |
| } else if (!strcmp(node->name, "spectype")) { |
| parsespectype(db, file, node); |
| return 1; |
| } else if (!strcmp(node->name, "import")) { |
| xmlAttr *attr = node->properties; |
| char *subfile = 0; |
| while (attr) { |
| if (!strcmp(attr->name, "file")) { |
| subfile = getattrib(db, file, node->line, attr); |
| } else { |
| rnn_err(db, "%s:%d: wrong attribute \"%s\" for import\n", file, node->line, attr->name); |
| } |
| attr = attr->next; |
| } |
| if (!subfile) { |
| rnn_err(db, "%s:%d: missing \"file\" attribute for import\n", file, node->line); |
| } else { |
| rnn_parsefile(db, subfile); |
| } |
| return 1; |
| } else if (!strcmp(node->name, "copyright")) { |
| parsecopyright(db, file, node); |
| return 1; |
| } |
| return 0; |
| } |
| |
| static char * find_file(const char *file_orig) |
| { |
| const char *rnn_path = getenv("RNN_PATH"); |
| char *fname; |
| |
| if (!rnn_path) |
| rnn_path = RNN_DEF_PATH; |
| |
| FILE *file = find_in_path(file_orig, rnn_path, &fname); |
| if (!file) { |
| fprintf (stderr, "%s: couldn't find database file. Please set the env var RNN_PATH.\n", file_orig); |
| return NULL; |
| } |
| fclose(file); |
| |
| return fname; |
| } |
| |
| static int validate_doc(struct rnndb *db, xmlDocPtr doc, xmlNodePtr database) |
| { |
| /* find the schemaLocation property: */ |
| xmlAttrPtr attr = database->properties; |
| const char *schema_name = NULL; |
| char *schema_path; |
| |
| while (attr) { |
| if (!strcmp(attr->name, "schemaLocation")) { |
| xmlNodePtr data = attr->children; |
| schema_name = data->content; |
| /* we expect this to look like <namespace url> schema.xsd.. I think |
| * technically it is supposed to be just a URL, but that doesn't |
| * quite match up to what we do.. Just skip over everything up to |
| * and including the first whitespace character: |
| */ |
| while (schema_name && (schema_name[0] != ' ')) |
| schema_name++; |
| schema_name++; |
| break; |
| } |
| } |
| |
| if (!schema_name) { |
| rnn_err(db, "could not find schema. Missing schemaLocation?"); |
| return 0; |
| } |
| |
| schema_path = find_file(schema_name); |
| if (!schema_path) { |
| rnn_err(db, "%s: couldn't find database file. Please set the env var RNN_PATH.\n", schema_name); |
| return 0; |
| } |
| |
| xmlSchemaParserCtxtPtr parser = xmlSchemaNewParserCtxt(schema_path); |
| xmlSchemaPtr schema = xmlSchemaParse(parser); |
| xmlSchemaValidCtxtPtr validCtxt = xmlSchemaNewValidCtxt(schema); |
| int ret = xmlSchemaValidateDoc(validCtxt, doc); |
| |
| xmlSchemaFreeValidCtxt(validCtxt); |
| xmlSchemaFree(schema); |
| xmlSchemaFreeParserCtxt(parser); |
| |
| free(schema_path); |
| |
| return ret; |
| } |
| |
| void rnn_parsefile (struct rnndb *db, char *file_orig) { |
| int i; |
| char *fname; |
| |
| fname = find_file(file_orig); |
| if (!fname) { |
| db->estatus = 1; |
| return; |
| } |
| |
| for (i = 0; i < db->filesnum; i++) |
| if (!strcmp(db->files[i], fname)) |
| return; |
| |
| ADDARRAY(db->files, fname); |
| xmlDocPtr doc = xmlParseFile(fname); |
| if (!doc) { |
| rnn_err(db, "%s: couldn't open database file. Please set the env var RNN_PATH.\n", fname); |
| return; |
| } |
| xmlNode *root = doc->children; |
| while (root) { |
| if (root->type != XML_ELEMENT_NODE) { |
| } else if (strcmp(root->name, "database")) { |
| rnn_err(db, "%s:%d: wrong top-level tag <%s>\n", fname, root->line, root->name); |
| } else { |
| xmlNode *chain = root->children; |
| if (validate_doc(db, doc, root)) { |
| rnn_err(db, "%s: database file has errors\n", fname); |
| return; |
| } |
| while (chain) { |
| if (chain->type != XML_ELEMENT_NODE) { |
| } else if (!trytop(db, fname, chain) && !trydoc(db, fname, chain)) { |
| rnn_err(db, "%s:%d: wrong tag in database: <%s>\n", fname, chain->line, chain->name); |
| } |
| chain = chain->next; |
| } |
| } |
| root = root->next; |
| } |
| xmlFreeDoc(doc); |
| } |
| |
| static struct rnnvalue *copyvalue (struct rnnvalue *val, char *file) { |
| struct rnnvalue *res = calloc (sizeof *res, 1); |
| res->name = val->name; |
| res->valvalid = val->valvalid; |
| res->value = val->value; |
| res->varinfo = val->varinfo; |
| res->file = file; |
| return res; |
| } |
| |
| static struct rnnbitfield *copybitfield (struct rnnbitfield *bf, char *file); |
| |
| |
| static void copytypeinfo (struct rnntypeinfo *dst, struct rnntypeinfo *src, char *file) { |
| int i; |
| dst->name = src->name; |
| dst->shr = src->shr; |
| dst->low = src->low; |
| dst->high = src->high; |
| dst->min = src->min; |
| dst->max = src->max; |
| dst->align = src->align; |
| dst->addvariant = src->addvariant; |
| for (i = 0; i < src->valsnum; i++) |
| ADDARRAY(dst->vals, copyvalue(src->vals[i], file)); |
| for (i = 0; i < src->bitfieldsnum; i++) |
| ADDARRAY(dst->bitfields, copybitfield(src->bitfields[i], file)); |
| } |
| |
| static struct rnnbitfield *copybitfield (struct rnnbitfield *bf, char *file) { |
| struct rnnbitfield *res = calloc (sizeof *res, 1); |
| res->name = bf->name; |
| res->varinfo = bf->varinfo; |
| res->file = file; |
| copytypeinfo(&res->typeinfo, &bf->typeinfo, file); |
| return res; |
| } |
| |
| static struct rnndelem *copydelem (struct rnndelem *elem, char *file) { |
| struct rnndelem *res = calloc (sizeof *res, 1); |
| res->type = elem->type; |
| res->name = elem->name; |
| res->width = elem->width; |
| res->access = elem->access; |
| res->offset = elem->offset; |
| res->length = elem->length; |
| res->stride = elem->stride; |
| res->varinfo = elem->varinfo; |
| res->file = file; |
| copytypeinfo(&res->typeinfo, &elem->typeinfo, file); |
| int i; |
| for (i = 0; i < elem->subelemsnum; i++) |
| ADDARRAY(res->subelems, copydelem(elem->subelems[i], file)); |
| for (i = 0; i < elem->offsetsnum; i++) |
| ADDARRAY(res->offsets, elem->offsets[i]); |
| return res; |
| } |
| |
| static struct rnnvarset *copyvarset (struct rnnvarset *varset) { |
| struct rnnvarset *res = calloc(sizeof *res, 1); |
| res->venum = varset->venum; |
| res->variants = calloc(sizeof *res->variants, res->venum->valsnum); |
| int i; |
| for (i = 0; i < res->venum->valsnum; i++) |
| res->variants[i] = varset->variants[i]; |
| return res; |
| } |
| |
| static void prepenum(struct rnndb *db, struct rnnenum *en); |
| |
| static int findvidx (struct rnndb *db, struct rnnenum *en, char *name) { |
| int i; |
| for (i = 0; i < en->valsnum; i++) |
| if (!strcmp(en->vals[i]->name, name)) |
| return i; |
| rnn_err(db, "Cannot find variant %s in enum %s!\n", name, en->name); |
| return -1; |
| } |
| |
| static void prepvarinfo (struct rnndb *db, char *what, struct rnnvarinfo *vi, struct rnnvarinfo *parent) { |
| if (parent) |
| vi->prefenum = parent->prefenum; |
| if (vi->prefixstr) { |
| if (!strcmp(vi->prefixstr, "none")) |
| vi->prefenum = 0; |
| else |
| vi->prefenum = rnn_findenum(db, vi->prefixstr); // XXX |
| } |
| int i; |
| if (parent) |
| for (i = 0; i < parent->varsetsnum; i++) |
| ADDARRAY(vi->varsets, copyvarset(parent->varsets[i])); |
| struct rnnenum *varset = vi->prefenum; |
| if (!varset && !vi->varsetstr && parent) |
| vi->varsetstr = parent->varsetstr; |
| if (vi->varsetstr) |
| varset = rnn_findenum(db, vi->varsetstr); |
| if (vi->variantsstr) { |
| char *vars = vi->variantsstr; |
| if (!varset) { |
| rnn_err(db, "%s: tried to use variants without active varset!\n", what); |
| return; |
| } |
| struct rnnvarset *vs = 0; |
| int nvars = varset->valsnum; |
| for (i = 0; i < vi->varsetsnum; i++) |
| if (vi->varsets[i]->venum == varset) { |
| vs = vi->varsets[i]; |
| break; |
| } |
| if (!vs) { |
| vs = calloc (sizeof *vs, 1); |
| vs->venum = varset; |
| vs->variants = calloc(sizeof *vs->variants, nvars); |
| for (i = 0; i < nvars; i++) |
| vs->variants[i] = 1; |
| ADDARRAY(vi->varsets, vs); |
| } |
| while (1) { |
| while (*vars == ' ') vars++; |
| if (*vars == 0) |
| break; |
| char *split = vars; |
| while (*split != ':' && *split != '-' && *split != ' ' && *split != 0) |
| split++; |
| char *first = 0; |
| if (split != vars) |
| first = strndup(vars, split-vars); |
| if (*split == ' ' || *split == 0) { |
| int idx = findvidx(db, varset, first); |
| if (idx != -1) |
| vs->variants[idx] |= 2; |
| vars = split; |
| } else { |
| char *end = split+1; |
| while (*end != ' ' && *end != 0) |
| end++; |
| char *second = 0; |
| if (end != split+1) |
| second = strndup(split+1, end-split-1); |
| int idx1 = 0; |
| if (first) |
| idx1 = findvidx(db, varset, first); |
| int idx2 = nvars; |
| if (second) { |
| idx2 = findvidx(db, varset, second); |
| if (*split == '-') |
| idx2++; |
| } |
| if (idx1 != -1 && idx2 != -1) |
| for (i = idx1; i < idx2; i++) |
| vs->variants[i] |= 2; |
| vars = end; |
| free(second); |
| } |
| free(first); |
| } |
| vi->dead = 1; |
| for (i = 0; i < nvars; i++) { |
| vs->variants[i] = (vs->variants[i] == 3); |
| if (vs->variants[i]) |
| vi->dead = 0; |
| } |
| } |
| if (vi->dead) |
| return; |
| if (vi->prefenum) { |
| struct rnnvarset *vs = 0; |
| for (i = 0; i < vi->varsetsnum; i++) |
| if (vi->varsets[i]->venum == vi->prefenum) { |
| vs = vi->varsets[i]; |
| break; |
| } |
| if (vs) { |
| for (i = 0; i < vi->prefenum->valsnum; i++) |
| if (vs->variants[i]) { |
| vi->prefix = vi->prefenum->vals[i]->name; |
| return; |
| } |
| } else { |
| vi->prefix = vi->prefenum->vals[0]->name; |
| } |
| } |
| } |
| |
| static void prepvalue(struct rnndb *db, struct rnnvalue *val, char *prefix, struct rnnvarinfo *parvi) { |
| val->fullname = catstr(prefix, val->name); |
| prepvarinfo (db, val->fullname, &val->varinfo, parvi); |
| if (val->varinfo.dead) |
| return; |
| if (val->varinfo.prefix) |
| val->fullname = catstr(val->varinfo.prefix, val->fullname); |
| } |
| |
| static void prepbitfield(struct rnndb *db, struct rnnbitfield *bf, char *prefix, struct rnnvarinfo *parvi); |
| |
| static void preptypeinfo(struct rnndb *db, struct rnntypeinfo *ti, char *prefix, struct rnnvarinfo *vi, char *file) { |
| int i; |
| if (ti->name) { |
| struct rnnenum *en = rnn_findenum (db, ti->name); |
| struct rnnbitset *bs = rnn_findbitset (db, ti->name); |
| struct rnnspectype *st = rnn_findspectype (db, ti->name); |
| if (en) { |
| if (en->isinline) { |
| ti->type = RNN_TTYPE_INLINE_ENUM; |
| int j; |
| for (j = 0; j < en->valsnum; j++) |
| ADDARRAY(ti->vals, copyvalue(en->vals[j], file)); |
| } else { |
| ti->type = RNN_TTYPE_ENUM; |
| ti->eenum = en; |
| } |
| } else if (bs) { |
| if (bs->isinline) { |
| ti->type = RNN_TTYPE_INLINE_BITSET; |
| int j; |
| for (j = 0; j < bs->bitfieldsnum; j++) |
| ADDARRAY(ti->bitfields, copybitfield(bs->bitfields[j], file)); |
| } else { |
| ti->type = RNN_TTYPE_BITSET; |
| ti->ebitset = bs; |
| } |
| } else if (st) { |
| ti->type = RNN_TTYPE_SPECTYPE; |
| ti->spectype = st; |
| } else if (!strcmp(ti->name, "hex")) { |
| ti->type = RNN_TTYPE_HEX; |
| } else if (!strcmp(ti->name, "float")) { |
| ti->type = RNN_TTYPE_FLOAT; |
| } else if (!strcmp(ti->name, "uint")) { |
| ti->type = RNN_TTYPE_UINT; |
| } else if (!strcmp(ti->name, "int")) { |
| ti->type = RNN_TTYPE_INT; |
| } else if (!strcmp(ti->name, "boolean")) { |
| ti->type = RNN_TTYPE_BOOLEAN; |
| } else if (!strcmp(ti->name, "bitfield")) { |
| ti->type = RNN_TTYPE_INLINE_BITSET; |
| } else if (!strcmp(ti->name, "enum")) { |
| ti->type = RNN_TTYPE_INLINE_ENUM; |
| } else if (!strcmp(ti->name, "fixed")) { |
| ti->type = RNN_TTYPE_FIXED; |
| } else if (!strcmp(ti->name, "ufixed")) { |
| ti->type = RNN_TTYPE_UFIXED; |
| } else if (!strcmp(ti->name, "a3xx_regid")) { |
| ti->type = RNN_TTYPE_A3XX_REGID; |
| } else if (!strcmp(ti->name, "waddress") || !strcmp(ti->name, "address")) { |
| ti->type = RNN_TTYPE_HEX; |
| } else { |
| ti->type = RNN_TTYPE_HEX; |
| rnn_err(db, "%s: unknown type %s\n", prefix, ti->name); |
| } |
| } else if (ti->bitfieldsnum) { |
| ti->name = "bitfield"; |
| ti->type = RNN_TTYPE_INLINE_BITSET; |
| } else if (ti->valsnum) { |
| ti->name = "enum"; |
| ti->type = RNN_TTYPE_INLINE_ENUM; |
| } else if (ti->low == 0 && ti->high == 0) { |
| ti->name = "boolean"; |
| ti->type = RNN_TTYPE_BOOLEAN; |
| } else { |
| ti->name = "hex"; |
| ti->type = RNN_TTYPE_HEX; |
| } |
| if (ti->addvariant && ti->type != RNN_TTYPE_ENUM) { |
| rnn_err(db, "%s: addvariant specified on non-enum type %s\n", prefix, ti->name); |
| } |
| for (i = 0; i < ti->bitfieldsnum; i++) |
| prepbitfield(db, ti->bitfields[i], prefix, vi); |
| for (i = 0; i < ti->valsnum; i++) |
| prepvalue(db, ti->vals[i], prefix, vi); |
| } |
| |
| static void prepbitfield(struct rnndb *db, struct rnnbitfield *bf, char *prefix, struct rnnvarinfo *parvi) { |
| bf->fullname = catstr(prefix, bf->name); |
| prepvarinfo (db, bf->fullname, &bf->varinfo, parvi); |
| if (bf->varinfo.dead) |
| return; |
| preptypeinfo(db, &bf->typeinfo, bf->fullname, &bf->varinfo, bf->file); |
| if (bf->varinfo.prefix) |
| bf->fullname = catstr(bf->varinfo.prefix, bf->fullname); |
| } |
| |
| static void prepdelem(struct rnndb *db, struct rnndelem *elem, char *prefix, struct rnnvarinfo *parvi, int width) { |
| if (elem->type == RNN_ETYPE_USE_GROUP) { |
| int i; |
| struct rnngroup *gr = 0; |
| for (i = 0; i < db->groupsnum; i++) |
| if (!strcmp(db->groups[i]->name, elem->name)) { |
| gr = db->groups[i]; |
| break; |
| } |
| if (gr) { |
| for (i = 0; i < gr->subelemsnum; i++) |
| ADDARRAY(elem->subelems, copydelem(gr->subelems[i], elem->file)); |
| } else { |
| rnn_err(db, "group %s not found!\n", elem->name); |
| } |
| elem->type = RNN_ETYPE_STRIPE; |
| elem->length = 1; |
| elem->name = 0; |
| } |
| if (elem->name) |
| elem->fullname = catstr(prefix, elem->name); |
| prepvarinfo (db, elem->fullname?elem->fullname:prefix, &elem->varinfo, parvi); |
| if (elem->varinfo.dead) |
| return; |
| if (elem->length != 1 && !elem->stride) { |
| if (elem->type != RNN_ETYPE_REG) { |
| rnn_err(db, "%s has non-1 length, but no stride!\n", elem->fullname); |
| } else { |
| elem->stride = elem->width/width; |
| } |
| } |
| preptypeinfo(db, &elem->typeinfo, elem->name?elem->fullname:prefix, &elem->varinfo, elem->file); |
| |
| int i; |
| for (i = 0; i < elem->subelemsnum; i++) |
| prepdelem(db, elem->subelems[i], elem->name?elem->fullname:prefix, &elem->varinfo, width); |
| if (elem->varinfo.prefix && elem->name) |
| elem->fullname = catstr(elem->varinfo.prefix, elem->fullname); |
| } |
| |
| static void prepdomain(struct rnndb *db, struct rnndomain *dom) { |
| prepvarinfo (db, dom->name, &dom->varinfo, 0); |
| int i; |
| for (i = 0; i < dom->subelemsnum; i++) |
| prepdelem(db, dom->subelems[i], dom->bare?0:dom->name, &dom->varinfo, dom->width); |
| dom->fullname = catstr(dom->varinfo.prefix, dom->name); |
| } |
| |
| static void prepenum(struct rnndb *db, struct rnnenum *en) { |
| if (en->prepared) |
| return; |
| prepvarinfo (db, en->name, &en->varinfo, 0); |
| int i; |
| if (en->isinline) |
| return; |
| for (i = 0; i < en->valsnum; i++) |
| prepvalue(db, en->vals[i], en->bare?0:en->name, &en->varinfo); |
| en->fullname = catstr(en->varinfo.prefix, en->name); |
| en->prepared = 1; |
| } |
| |
| static void prepbitset(struct rnndb *db, struct rnnbitset *bs) { |
| prepvarinfo (db, bs->name, &bs->varinfo, 0); |
| int i; |
| if (bs->isinline) |
| return; |
| for (i = 0; i < bs->bitfieldsnum; i++) |
| prepbitfield(db, bs->bitfields[i], bs->bare?0:bs->name, &bs->varinfo); |
| bs->fullname = catstr(bs->varinfo.prefix, bs->name); |
| } |
| |
| static void prepspectype(struct rnndb *db, struct rnnspectype *st) { |
| preptypeinfo(db, &st->typeinfo, st->name, 0, st->file); // XXX doesn't exactly make sense... |
| } |
| |
| void rnn_prepdb (struct rnndb *db) { |
| int i; |
| for (i = 0; i < db->enumsnum; i++) |
| prepenum(db, db->enums[i]); |
| for (i = 0; i < db->bitsetsnum; i++) |
| prepbitset(db, db->bitsets[i]); |
| for (i = 0; i < db->domainsnum; i++) |
| prepdomain(db, db->domains[i]); |
| for (i = 0; i < db->spectypesnum; i++) |
| prepspectype(db, db->spectypes[i]); |
| } |
| |
| struct rnnenum *rnn_findenum (struct rnndb *db, const char *name) { |
| int i; |
| for (i = 0; i < db->enumsnum; i++) |
| if (!strcmp(db->enums[i]->name, name)) |
| return db->enums[i]; |
| return 0; |
| } |
| |
| struct rnnbitset *rnn_findbitset (struct rnndb *db, const char *name) { |
| int i; |
| for (i = 0; i < db->bitsetsnum; i++) |
| if (!strcmp(db->bitsets[i]->name, name)) |
| return db->bitsets[i]; |
| return 0; |
| } |
| |
| struct rnndomain *rnn_finddomain (struct rnndb *db, const char *name) { |
| int i; |
| for (i = 0; i < db->domainsnum; i++) |
| if (!strcmp(db->domains[i]->name, name)) |
| return db->domains[i]; |
| return 0; |
| } |
| |
| struct rnnspectype *rnn_findspectype (struct rnndb *db, const char *name) { |
| int i; |
| for (i = 0; i < db->spectypesnum; i++) |
| if (!strcmp(db->spectypes[i]->name, name)) |
| return db->spectypes[i]; |
| return 0; |
| } |