blob: d6ba6fa50052a5da62e0ef698c2988608ca87a14 [file] [log] [blame]
/*
* 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 "rnn_path.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"))
return 1;
if (!strcmp(c, "no") || !strcmp(c, "0"))
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, "name")) {
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);
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;
}
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;
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;
}