summaryrefslogtreecommitdiff
path: root/envytools
diff options
context:
space:
mode:
authorWladimir J. van der Laan <laanwj@gmail.com>2013-01-05 18:58:11 +0100
committerWladimir J. van der Laan <laanwj@gmail.com>2013-01-05 19:31:17 +0100
commit967796763ae365ebbcecde0a9e0a793e350787ba (patch)
tree7626ed53689ee359e5af7a7dcf2804a2e4c3cb67 /envytools
parentf6c0516605a8ac032e7560ffbffbb5f7b3bf91d2 (diff)
prepare for include file generation from rnndb
Diffstat (limited to 'envytools')
-rw-r--r--envytools/.gitignore2
-rw-r--r--envytools/CMakeLists.txt15
-rw-r--r--envytools/include/colors.h49
-rw-r--r--envytools/include/mask.h62
-rw-r--r--envytools/include/rnn.h227
-rw-r--r--envytools/include/rnndec.h56
-rw-r--r--envytools/include/symtab.h58
-rw-r--r--envytools/include/util.h115
-rw-r--r--envytools/include/var.h148
-rw-r--r--envytools/include/yy.h64
-rw-r--r--envytools/rnn/.gitignore9
-rw-r--r--envytools/rnn/CMakeLists.txt43
-rw-r--r--envytools/rnn/dedma.c440
-rw-r--r--envytools/rnn/dedma.h152
-rw-r--r--envytools/rnn/dedma_back.c174
-rw-r--r--envytools/rnn/dedma_cache.c108
-rw-r--r--envytools/rnn/demmio.c516
-rw-r--r--envytools/rnn/expand.c89
-rw-r--r--envytools/rnn/headergen.c323
-rw-r--r--envytools/rnn/lookup.c165
-rwxr-xr-xenvytools/rnn/renouveau2rnn289
-rw-r--r--envytools/rnn/rnn.c1295
-rw-r--r--envytools/rnn/rnn_path.h.in1
-rw-r--r--envytools/rnn/rnncheck.c46
-rw-r--r--envytools/rnn/rnndec.c317
-rwxr-xr-xenvytools/rnn/rules2rnn522
-rwxr-xr-xenvytools/rnn/text2xml411
-rwxr-xr-xenvytools/rnn/update.sed.sh31
-rwxr-xr-xenvytools/rnn/xml2text233
-rw-r--r--envytools/util/.gitignore2
-rw-r--r--envytools/util/CMakeLists.txt12
-rw-r--r--envytools/util/aprintf.c38
-rw-r--r--envytools/util/astr.c67
-rw-r--r--envytools/util/colors.c61
-rw-r--r--envytools/util/hash.c38
-rw-r--r--envytools/util/mask.c77
-rw-r--r--envytools/util/path.c59
-rw-r--r--envytools/util/symtab.c111
-rw-r--r--envytools/util/vardata.c231
-rw-r--r--envytools/util/varinfo.c100
-rw-r--r--envytools/util/varselect.c92
-rw-r--r--envytools/util/yy.c115
42 files changed, 6963 insertions, 0 deletions
diff --git a/envytools/.gitignore b/envytools/.gitignore
new file mode 100644
index 0000000..9ef9604
--- /dev/null
+++ b/envytools/.gitignore
@@ -0,0 +1,2 @@
+build
+
diff --git a/envytools/CMakeLists.txt b/envytools/CMakeLists.txt
new file mode 100644
index 0000000..1889134
--- /dev/null
+++ b/envytools/CMakeLists.txt
@@ -0,0 +1,15 @@
+project(ENVYTOOLS C)
+cmake_minimum_required(VERSION 2.6)
+enable_testing()
+
+SET(CMAKE_C_FLAGS "-g -O2 -Wall")
+
+include_directories(include)
+
+add_subdirectory(util)
+add_subdirectory(rnn)
+
+install(DIRECTORY include/ DESTINATION include/envytools)
+install(DIRECTORY rnndb DESTINATION share)
+install(DIRECTORY hwdocs DESTINATION share/doc/envytools)
+install(FILES README DESTINATION share/doc/envytools)
diff --git a/envytools/include/colors.h b/envytools/include/colors.h
new file mode 100644
index 0000000..e1efe9f
--- /dev/null
+++ b/envytools/include/colors.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2012 Marcin Kościelnicki <koriakin@0x04.net>
+ * 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
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS 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.
+ */
+
+#ifndef COLORS_H
+#define COLORS_H
+
+struct envy_colors {
+ const char *reset;
+ const char *iname; /* instruction name */
+ const char *rname; /* register or bitfield name */
+ const char *mod; /* instruction modifier */
+ const char *sym; /* auxiliary char like { , + */
+ const char *reg; /* ISA register */
+ const char *regsp; /* special ISA register */
+ const char *num; /* immediate number */
+ const char *mem; /* memory reference */
+ const char *btarg; /* branch target */
+ const char *ctarg; /* call target */
+ const char *bctarg; /* branch and call target */
+ const char *eval; /* enum value */
+ const char *comm; /* comment */
+ const char *err; /* error */
+};
+
+extern const struct envy_colors envy_null_colors;
+extern const struct envy_colors envy_def_colors;
+
+#endif
diff --git a/envytools/include/mask.h b/envytools/include/mask.h
new file mode 100644
index 0000000..4f6ea1c
--- /dev/null
+++ b/envytools/include/mask.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2011 Marcin Kościelnicki <koriakin@0x04.net>
+ * 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
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS 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.
+ */
+
+#ifndef MASK_H
+#define MASK_H
+
+#include "util.h"
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+
+#define MASK_CHUNK_SIZE 32
+#define MASK_SIZE(num) CEILDIV((num), MASK_CHUNK_SIZE)
+
+static inline int mask_get(uint32_t *mask, int num) {
+ return (mask[num/32] >> (num % 32)) & 1;
+}
+
+static inline void mask_set(uint32_t *mask, int num) {
+ mask[num/32] |= 1 << (num % 32);
+}
+
+static inline uint32_t *mask_new(int num) {
+ uint32_t *res = calloc(sizeof *res, MASK_SIZE(num));
+ return res;
+}
+
+static inline uint32_t *mask_dup(uint32_t *mask, int num) {
+ uint32_t *res = mask_new(num);
+ memcpy(res, mask, MASK_SIZE(num) * sizeof *res);
+ return res;
+}
+
+void mask_or(uint32_t *dmask, uint32_t *smask, int size);
+int mask_or_r(uint32_t *dmask, uint32_t *smask, int size);
+
+int mask_intersect(uint32_t *a, uint32_t *b, int size);
+int mask_contains(uint32_t *a, uint32_t *b, int size);
+void mask_print(FILE *out, uint32_t *mask, int size);
+
+#endif
diff --git a/envytools/include/rnn.h b/envytools/include/rnn.h
new file mode 100644
index 0000000..d5a7a27
--- /dev/null
+++ b/envytools/include/rnn.h
@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 2010 Marcin Kościelnicki <koriakin@0x04.net>
+ * Copyright (C) 2010 Luca Barbieri <luca@luca-barbieri.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
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS 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.
+ */
+
+#ifndef RNN_H
+#define RNN_H
+
+#include <stdint.h>
+#include <stdlib.h>
+
+struct rnnauthor {
+ char* name;
+ char* email;
+ char* contributions;
+ char* license;
+ char** nicknames;
+ int nicknamesnum;
+ int nicknamesmax;
+};
+
+struct rnncopyright {
+ unsigned firstyear;
+ char* license;
+ struct rnnauthor **authors;
+ int authorsnum;
+ int authorsmax;
+};
+
+struct rnndb {
+ struct rnncopyright copyright;
+ struct rnnenum **enums;
+ int enumsnum;
+ int enumsmax;
+ struct rnnbitset **bitsets;
+ int bitsetsnum;
+ int bitsetsmax;
+ struct rnndomain **domains;
+ int domainsnum;
+ int domainsmax;
+ struct rnngroup **groups;
+ int groupsnum;
+ int groupsmax;
+ struct rnnspectype **spectypes;
+ int spectypesnum;
+ int spectypesmax;
+ char **files;
+ int filesnum;
+ int filesmax;
+ int estatus;
+};
+
+struct rnnvarset {
+ struct rnnenum *venum;
+ int *variants;
+};
+
+struct rnnvarinfo {
+ char *prefixstr;
+ char *varsetstr;
+ char *variantsstr;
+ int dead;
+ struct rnnenum *prefenum;
+ char *prefix;
+ struct rnnvarset **varsets;
+ int varsetsnum;
+ int varsetsmax;
+};
+
+struct rnnenum {
+ char *name;
+ int bare;
+ int isinline;
+ struct rnnvarinfo varinfo;
+ struct rnnvalue **vals;
+ int valsnum;
+ int valsmax;
+ char *fullname;
+ int prepared;
+ char *file;
+};
+
+struct rnnvalue {
+ char *name;
+ int valvalid;
+ uint64_t value;
+ struct rnnvarinfo varinfo;
+ char *fullname;
+ char *file;
+};
+
+struct rnntypeinfo {
+ char *name;
+ enum rnnttype {
+ RNN_TTYPE_INLINE_ENUM,
+ RNN_TTYPE_INLINE_BITSET,
+ RNN_TTYPE_ENUM,
+ RNN_TTYPE_BITSET,
+ RNN_TTYPE_SPECTYPE,
+ RNN_TTYPE_HEX,
+ RNN_TTYPE_INT,
+ RNN_TTYPE_UINT,
+ RNN_TTYPE_FLOAT,
+ RNN_TTYPE_BOOLEAN,
+ RNN_TTYPE_DOMAIN,
+ RNN_TTYPE_FIXEDP
+ } type;
+ struct rnnenum *eenum;
+ struct rnnbitset *ebitset;
+ struct rnnspectype *spectype;
+ struct rnndomain *domain;
+ struct rnnbitfield **bitfields;
+ int bitfieldsnum;
+ int bitfieldsmax;
+ struct rnnvalue **vals;
+ int valsnum;
+ int valsmax;
+ int shr;
+ uint64_t min, max, align;
+ int minvalid, maxvalid, alignvalid;
+};
+
+struct rnnbitset {
+ char *name;
+ int bare;
+ int isinline;
+ struct rnnvarinfo varinfo;
+ struct rnnbitfield **bitfields;
+ int bitfieldsnum;
+ int bitfieldsmax;
+ char *fullname;
+ char *file;
+};
+
+struct rnnbitfield {
+ char *name;
+ int low, high;
+ uint64_t mask;
+ struct rnnvarinfo varinfo;
+ struct rnntypeinfo typeinfo;
+ char *fullname;
+ char *file;
+};
+
+struct rnndomain {
+ char *name;
+ int bare;
+ int width;
+ uint64_t size;
+ int sizevalid;
+ struct rnnvarinfo varinfo;
+ struct rnndelem **subelems;
+ int subelemsnum;
+ int subelemsmax;
+ char *fullname;
+ char *file;
+};
+
+struct rnngroup {
+ char *name;
+ struct rnndelem **subelems;
+ int subelemsnum;
+ int subelemsmax;
+};
+
+struct rnndelem {
+ enum rnnetype {
+ RNN_ETYPE_REG,
+ RNN_ETYPE_ARRAY,
+ RNN_ETYPE_STRIPE,
+ RNN_ETYPE_USE_GROUP,
+ } type;
+ char *name;
+ int width;
+ enum rnnaccess {
+ RNN_ACCESS_R,
+ RNN_ACCESS_W,
+ RNN_ACCESS_RW,
+ } access;
+ uint64_t offset;
+ uint64_t length;
+ uint64_t stride;
+ struct rnndelem **subelems;
+ int subelemsnum;
+ int subelemsmax;
+ struct rnnvarinfo varinfo;
+ struct rnntypeinfo typeinfo;
+ char *fullname;
+ char *file;
+};
+
+struct rnnspectype {
+ char *name;
+ struct rnntypeinfo typeinfo;
+ char *file;
+};
+
+void rnn_init();
+struct rnndb *rnn_newdb();
+void rnn_parsefile (struct rnndb *db, char *file);
+void rnn_prepdb (struct rnndb *db);
+struct rnnenum *rnn_findenum (struct rnndb *db, const char *name);
+struct rnnbitset *rnn_findbitset (struct rnndb *db, const char *name);
+struct rnndomain *rnn_finddomain (struct rnndb *db, const char *name);
+struct rnnspectype *rnn_findspectype (struct rnndb *db, const char *name);
+
+#endif
diff --git a/envytools/include/rnndec.h b/envytools/include/rnndec.h
new file mode 100644
index 0000000..3a0b747
--- /dev/null
+++ b/envytools/include/rnndec.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2010 Marcin Kościelnicki <koriakin@0x04.net>
+ * 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
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS 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.
+ */
+
+#ifndef RNNDEC_H
+#define RNNDEC_H
+
+#include "rnn.h"
+#include "colors.h"
+
+struct rnndecvariant {
+ struct rnnenum *en;
+ int variant;
+};
+
+struct rnndeccontext {
+ struct rnndb *db;
+ struct rnndecvariant **vars;
+ int varsnum;
+ int varsmax;
+ const struct envy_colors *colors;
+};
+
+struct rnndecaddrinfo {
+ struct rnntypeinfo *typeinfo;
+ int width;
+ char *name;
+};
+
+struct rnndeccontext *rnndec_newcontext(struct rnndb *db);
+int rnndec_varadd(struct rnndeccontext *ctx, char *varset, char *variant);
+int rnndec_varmatch(struct rnndeccontext *ctx, struct rnnvarinfo *vi);
+char *rnndec_decodeval(struct rnndeccontext *ctx, struct rnntypeinfo *ti, uint64_t value, int width);
+struct rnndecaddrinfo *rnndec_decodeaddr(struct rnndeccontext *ctx, struct rnndomain *domain, uint64_t addr, int write);
+
+#endif
diff --git a/envytools/include/symtab.h b/envytools/include/symtab.h
new file mode 100644
index 0000000..5b034e1
--- /dev/null
+++ b/envytools/include/symtab.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2011 Marcin Kościelnicki <koriakin@0x04.net>
+ * 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
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS 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.
+ */
+
+#ifndef SYMTAB_H
+#define SYMTAB_H
+
+#include <inttypes.h>
+
+struct symtab_sym {
+ char *name;
+ uint32_t hash;
+ int hchain;
+ int type;
+ int data;
+};
+
+struct symtab {
+ struct symtab_sym *syms;
+ int symsnum;
+ int symsmax;
+ int *buckets;
+ int bucketsnum;
+};
+
+struct symtab *symtab_new();
+void symtab_del(struct symtab *tab);
+int symtab_get(struct symtab *tab, const char *name, int *ptype, int *pdata);
+int symtab_get_t(struct symtab *tab, const char *name, int type, int *pdata);
+int symtab_put(struct symtab *tab, const char *name, int type, int data);
+static inline int symtab_get_td(struct symtab *tab, const char *name, int type) {
+ int res;
+ if (symtab_get_t(tab, name, type, &res) == -1)
+ return -1;
+ return res;
+}
+
+#endif
diff --git a/envytools/include/util.h b/envytools/include/util.h
new file mode 100644
index 0000000..b30bc1d
--- /dev/null
+++ b/envytools/include/util.h
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2010-2011 Marcin Kościelnicki <koriakin@0x04.net>
+ * Copyright (C) 2010 Francisco Jerez <currojerez@riseup.net>
+ * 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
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS 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.
+ */
+
+#ifndef UTIL_H
+#define UTIL_H
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <inttypes.h>
+
+#define ADDARRAY(a, e) \
+ do { \
+ if ((a ## num) >= (a ## max)) { \
+ if (!(a ## max)) \
+ (a ## max) = 16; \
+ else \
+ (a ## max) *= 2; \
+ (a) = realloc((a), (a ## max)*sizeof(*(a))); \
+ } \
+ (a)[(a ## num)++] = (e); \
+ } while(0)
+
+#define FINDARRAY(a, tmp, pred) \
+ ({ \
+ int __i; \
+ \
+ for (__i = 0; __i < (a ## num); __i++) { \
+ tmp = (a)[__i]; \
+ if (pred) \
+ break; \
+ } \
+ \
+ tmp = ((pred) ? tmp : NULL); \
+ })
+
+/* ceil(log2(x)) */
+static inline int clog2(uint64_t x) {
+ if (!x)
+ return x;
+ int r = 0;
+ while (x - 1 > (1ull << r) - 1)
+ r++;
+ return r;
+}
+
+#define ARRAY_SIZE(a) (sizeof (a) / sizeof *(a))
+
+#define min(a,b) \
+ ({ \
+ typeof (a) _a = (a); \
+ typeof (b) _b = (b); \
+ _a < _b ? _a : _b; \
+ })
+
+#define max(a,b) \
+ ({ \
+ typeof (a) _a = (a); \
+ typeof (b) _b = (b); \
+ _a > _b ? _a : _b; \
+ })
+
+#define CEILDIV(a, b) (((a) + (b) - 1)/(b))
+
+#define extr(a, b, c) ((uint64_t)(a) << (64 - (b) - (c)) >> (64 - (c)))
+#define extrs(a, b, c) ((int64_t)(a) << (64 - (b) - (c)) >> (64 - (c)))
+#define sext(a, b) extrs(a, 0, b+1)
+#define bflmask(a) ((2ull << ((a)-1)) - 1)
+#define insrt(a, b, c, d) ((a) = ((a) & ~(bflmask(c) << (b))) | ((d) & bflmask(c)) << (b))
+
+struct envy_loc {
+ int lstart;
+ int cstart;
+ int lend;
+ int cend;
+ const char *file;
+};
+
+#define LOC_FORMAT(loc, str) "%s:%d.%d-%d.%d: " str, (loc).file, (loc).lstart, (loc).cstart, (loc).lend, (loc).cend
+
+uint32_t elf_hash(const char *str);
+
+FILE *find_in_path(const char *name, const char *path, char **pfullname);
+
+struct astr {
+ char *str;
+ size_t len;
+};
+
+void print_escaped_astr(FILE *out, struct astr *astr);
+
+char *aprintf(const char *format, ...);
+
+#endif
diff --git a/envytools/include/var.h b/envytools/include/var.h
new file mode 100644
index 0000000..b9480ee
--- /dev/null
+++ b/envytools/include/var.h
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2012 Marcin Kościelnicki <koriakin@0x04.net>
+ * 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
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS 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.
+ */
+
+#ifndef VAR_H
+#define VAR_H
+
+#include "mask.h"
+#include "symtab.h"
+
+struct vardata_feature {
+ char *name;
+ char *description;
+ uint32_t *ifmask;
+ uint32_t *cfmask;
+ int *implies;
+ int impliesnum;
+ int impliesmax;
+ int *conflicts;
+ int conflictsnum;
+ int conflictsmax;
+};
+
+struct vardata_variant {
+ char *name;
+ char *description;
+ uint32_t *fmask;
+ int *features;
+ int featuresnum;
+ int featuresmax;
+ int varset;
+};
+
+struct vardata_varset {
+ char *name;
+ char *description;
+};
+
+struct vardata_mode {
+ char *name;
+ char *description;
+ uint32_t *rfmask;
+ int *rfeatures;
+ int rfeaturesnum;
+ int rfeaturesmax;
+ int modeset;
+};
+
+struct vardata_modeset {
+ char *name;
+ char *description;
+ int defmode;
+};
+
+struct vardata {
+ char *name;
+ struct vardata_feature *features;
+ int featuresnum;
+ int featuresmax;
+ struct vardata_variant *variants;
+ int variantsnum;
+ int variantsmax;
+ struct vardata_varset *varsets;
+ int varsetsnum;
+ int varsetsmax;
+ struct vardata_mode *modes;
+ int modesnum;
+ int modesmax;
+ struct vardata_modeset *modesets;
+ int modesetsnum;
+ int modesetsmax;
+ struct symtab *symtab;
+ int validated;
+};
+
+enum {
+ VARDATA_ST_FEATURE,
+ VARDATA_ST_VARIANT,
+ VARDATA_ST_VARSET,
+ VARDATA_ST_MODE,
+ VARDATA_ST_MODESET,
+} vardata_symtype;
+
+struct vardata *vardata_new(const char *name);
+void vardata_del(struct vardata *data);
+int vardata_add_feature(struct vardata *data, const char *name, const char *description);
+int vardata_add_varset(struct vardata *data, const char *name, const char *description);
+int vardata_add_variant(struct vardata *data, const char *name, const char *description, int varset);
+int vardata_add_modeset(struct vardata *data, const char *name, const char *description);
+int vardata_add_mode(struct vardata *data, const char *name, const char *description, int modeset);
+void vardata_feature_imply(struct vardata *data, int f1, int f2);
+void vardata_feature_conflict(struct vardata *data, int f1, int f2);
+void vardata_variant_feature(struct vardata *data, int v, int f);
+void vardata_mode_require(struct vardata *data, int m, int f);
+int vardata_modeset_def(struct vardata *data, int ms, int m);
+int vardata_validate(struct vardata *data);
+
+struct varinfo {
+ struct vardata *data;
+ uint32_t *fmask;
+ int *variants;
+ int *modes;
+};
+
+struct varinfo *varinfo_new(struct vardata *data);
+void varinfo_del(struct varinfo *info);
+int varinfo_set_variant(struct varinfo *info, const char *variant);
+int varinfo_set_feature(struct varinfo *info, const char *feature);
+int varinfo_set_mode(struct varinfo *info, const char *mode);
+
+struct varselect {
+ struct vardata *data;
+ uint32_t *fmask;
+ uint32_t *msmask;
+ uint32_t *mmask;
+ uint32_t *vsmask;
+ uint32_t *vmask;
+};
+
+struct varselect *varselect_new(struct vardata *data);
+void varselect_del(struct varselect *select);
+void varselect_need_feature(struct varselect *select, int f);
+void varselect_need_mode(struct varselect *select, int m);
+void varselect_need_variant(struct varselect *select, int v);
+
+int varselect_match(struct varselect *select, struct varinfo *info);
+
+#endif
diff --git a/envytools/include/yy.h b/envytools/include/yy.h
new file mode 100644
index 0000000..b45e548
--- /dev/null
+++ b/envytools/include/yy.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2011 Marcin Kościelnicki <koriakin@0x04.net>
+ * 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
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS 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.
+ */
+
+#ifndef YY_H
+#define YY_H
+
+#include "util.h"
+
+struct yy_lex_intern {
+ int line;
+ int pos;
+ const char *file;
+ int ws;
+ int nest;
+};
+
+#define YYLTYPE struct envy_loc
+
+#define YYLLOC_DEFAULT(Current, Rhs, N) \
+ do { \
+ if (N) { \
+ (Current).lstart = YYRHSLOC(Rhs, 1).lstart; \
+ (Current).cstart = YYRHSLOC(Rhs, 1).cstart; \
+ (Current).lend = YYRHSLOC(Rhs, N).lend; \
+ (Current).cend = YYRHSLOC(Rhs, N).cend; \
+ (Current).file = YYRHSLOC(Rhs, 1).file; \
+ } else { \
+ (Current).lstart = yylloc.lstart; \
+ (Current).cstart = yylloc.cstart; \
+ (Current).lend = yylloc.lstart; \
+ (Current).cend = yylloc.cstart; \
+ (Current).file = yylloc.file; \
+ } \
+ } while(0)
+
+#define YY_USER_ACTION yy_lex_common(&yyextra, yylloc, yytext);
+#define YY_USER_INIT yyextra.line = 1; yyextra.pos = 1; yyextra.ws = 0; yylloc->lend = 1; yylloc->cend = 1; yylloc->lstart = 1; yylloc->cstart = 1; yylloc->file = yyextra.file; yyextra.nest = 0;
+
+void yy_lex_common(struct yy_lex_intern *x, YYLTYPE *loc, const char *str);
+
+void yy_str_deescape(const char *str, struct astr *astr);
+
+#endif
diff --git a/envytools/rnn/.gitignore b/envytools/rnn/.gitignore
new file mode 100644
index 0000000..e674362
--- /dev/null
+++ b/envytools/rnn/.gitignore
@@ -0,0 +1,9 @@
+headergen
+lookup
+expand
+demmio
+dedma
+rnncheck
+librnn.a
+librnn.so
+rnn_path.h
diff --git a/envytools/rnn/CMakeLists.txt b/envytools/rnn/CMakeLists.txt
new file mode 100644
index 0000000..770e2e6
--- /dev/null
+++ b/envytools/rnn/CMakeLists.txt
@@ -0,0 +1,43 @@
+project(ENVYTOOLS C)
+cmake_minimum_required(VERSION 2.6)
+
+# <3 libxml2
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-pointer-sign")
+
+find_package(LibXml2 REQUIRED)
+
+find_path(LIBICONV_INCLUDE_DIR iconv.h)
+include_directories(${LIBXML2_INCLUDE_DIR} ${LIBICONV_INCLUDE_DIR})
+
+configure_file(rnn_path.h.in rnn_path.h ESCAPE_QUOTES)
+include_directories(${PROJECT_BINARY_DIR})
+
+add_library(rnn rnn.c rnndec.c)
+
+#add_executable(demmio demmio.c)
+add_executable(headergen headergen.c)
+#add_executable(dedma dedma.c dedma_cache.c dedma_back.c)
+add_executable(lookup lookup.c)
+add_executable(rnncheck rnncheck.c)
+
+target_link_libraries(rnn ${LIBXML2_LIBRARIES} envyutil)
+#target_link_libraries(demmio envy rnn)
+target_link_libraries(headergen rnn)
+#target_link_libraries(dedma rnn)
+target_link_libraries(lookup rnn)
+target_link_libraries(rnncheck rnn)
+
+#install(TARGETS demmio headergen rnn dedma lookup
+# RUNTIME DESTINATION bin
+# LIBRARY DESTINATION lib${LIB_SUFFIX}
+# ARCHIVE DESTINATION lib${LIB_SUFFIX})
+
+#add_test(check_nv_mmio rnncheck nv_mmio.xml)
+#add_test(check_nv_evo rnncheck nv_evo.xml)
+#add_test(check_nv_structs rnncheck nv_struct.xml)
+#add_test(check_nv_objects rnncheck nv_objects.xml)
+#add_test(check_nv50_texture rnncheck nv50_texture.xml)
+#add_test(check_adt7473 rnncheck extdev/adt7473.xml)
+#add_test(check_nv17_mpeg rnncheck nv17_mpeg.xml)
+#add_test(check_nvc0_shaders rnncheck nvc0_shaders.xml)
+
diff --git a/envytools/rnn/dedma.c b/envytools/rnn/dedma.c
new file mode 100644
index 0000000..60bea8c
--- /dev/null
+++ b/envytools/rnn/dedma.c
@@ -0,0 +1,440 @@
+/*
+ * Copyright (C) 2010 Francisco Jerez.
+ * 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 COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS 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.
+ */
+
+#include "dedma.h"
+#include "util.h"
+
+void
+add_object(struct state *s, uint32_t handle, uint32_t class)
+{
+ struct rnnenum *chs = rnn_findenum(s->db, "chipset");
+ struct rnnenum *cls = rnn_findenum(s->db, "obj-class");
+ struct rnnvalue *v;
+ struct obj *obj;
+ int i;
+
+ if (!cls || !chs) {
+ fprintf(stderr, "No obj-class/chipset enum found\n");
+ abort();
+ }
+
+ for (i = 0; obj = &s->objects[i], i < MAX_OBJECTS; i++) {
+ if (!obj->handle) {
+ obj->handle = handle;
+ obj->class = class;
+ obj->ctx = rnndec_newcontext(s->db);
+ obj->ctx->colors = s->colors;
+
+ v = NULL;
+ FINDARRAY(chs->vals, v, v->value == s->chipset);
+ rnndec_varadd(obj->ctx, "chipset",
+ v ? v->name : "NV01");
+
+ v = NULL;
+ FINDARRAY(cls->vals, v, v->value == class);
+ obj->name = v ? v->name : NULL;
+ rnndec_varadd(obj->ctx, "obj-class",
+ v ? v->name : "NV01_NULL");
+
+ return;
+ }
+ }
+
+ fprintf(stderr, "Too many objects\n");
+}
+
+struct obj *
+get_object(struct state *s, uint32_t handle)
+{
+ struct obj *objs = s->objects;
+ int i;
+
+ for (i = 0; i < MAX_OBJECTS; i++) {
+ if (objs[i].handle == handle)
+ return &objs[i];
+ }
+
+ if (s->chipset >= 0xc0) {
+ add_object(s, handle, handle & 0xffff);
+ return get_object(s, handle);
+ }
+
+ return NULL;
+}
+
+static void
+flush_raw(struct state *s, struct ent *e)
+{
+ if (e->out_of_band)
+ s->op.print("# out of band: %08x %08lx\n", e->addr, e->val);
+ else
+ s->op.print("%08x %08lx\n", e->addr, e->val);
+}
+
+static void
+pretty_header(struct state *s, struct ent *e)
+{
+ struct dma *dma = &s->dma;
+ struct obj *obj = s->subchan[dma->subchan];
+
+ if (dma->size)
+ s->op.print("%08x size %d, subchannel %d (0x%x),"
+ " offset 0x%04x, %s\n", e->val, dma->size,
+ dma->subchan, (obj ? obj->handle : 0), dma->addr,
+ (dma->incr ? "increment" : "constant"));
+ else
+ s->op.print("%08x\n", e->val);
+}
+
+static void
+pretty_method(struct state *s, struct ent *e, uint32_t x)
+{
+ struct rnndecaddrinfo *ai;
+ const struct envy_colors *col = s->colors;
+ struct dma *dma = &s->dma;
+ struct obj *obj = s->subchan[dma->subchan];
+ char *dec_obj = NULL;
+ char *dec_addr = NULL;
+ char *dec_val = NULL;
+
+ /* get an object name */
+ if (obj && obj->name)
+ asprintf(&dec_obj, "%s%s%s", col->rname,
+ obj->name, col->reset);
+ else
+ asprintf(&dec_obj, "%sOBJ%X%s", col->err,
+ (obj ? obj->class : 0), col->reset);
+
+ /* get the method name and value */
+ if (obj) {
+ ai = rnndec_decodeaddr(obj->ctx, s->dom, dma->addr, true);
+
+ dec_addr = ai->name;
+ dec_val = rnndec_decodeval(obj->ctx, ai->typeinfo, x,
+ ai->width);
+
+ free(ai);
+ } else {
+ asprintf(&dec_addr, "%s0x%x%s", col->err, dma->addr,
+ col->reset);
+ }
+
+ /* write it */
+ s->op.print("%08x %s", e->val, dec_obj);
+
+ if (dma->addr == 0)
+ s->op.print(" mapped to subchannel %d\n", dma->subchan);
+ else if (dec_val)
+ s->op.print(".%s = %s\n", dec_addr, dec_val);
+ else
+ s->op.print(".%s\n", dec_addr);
+
+ free(dec_val);
+ free(dec_addr);
+ free(dec_obj);
+}
+
+static void
+flush_dma(struct state *s, struct ent *e)
+{
+ struct dma *dma = &s->dma;
+ uint32_t x = e->val;
+
+ if (e->out_of_band) {
+ s->op.print("# out of band: %08x %08lx\n", e->addr, e->val);
+ return;
+ }
+
+ if (dma->skip) {
+ s->op.print("%08x\n", x);
+ dma->skip--;
+ return;
+ }
+
+ if (!dma->size) {
+ if (!x) {
+ dma->nops++;
+ return;
+
+ } else if (dma->nops) {
+ s->op.print("# %d NOPs\n", dma->nops);
+ dma->nops = 0;
+ }
+
+ if (s->chipset >= 0xc0) {
+ int mode = (x & 0xe0000000) >> 29;
+
+ dma->addr = (x & 0x1fff) << 2;
+ dma->subchan = (x & 0xe000) >> 13;
+ dma->size = (x & 0x1fff0000) >> 16;
+ dma->incr = (mode == 3 ? 0 :
+ mode == 5 ? 1 :
+ dma->size);
+
+ if (mode == 4) {
+ pretty_method(s, e, dma->size);
+ dma->size = 0;
+ return;
+ }
+ } else {
+ if (x & 0x20000000) {
+ s->op.print("# jump to 0x%x: %08x %08lx\n",
+ x & 0x1fffffff, e->addr, e->val);
+ dma->skip = 1;
+ return;
+ }
+
+ dma->addr = x & 0x1fff;
+ dma->subchan = (x & 0xe000) >> 13;
+ dma->size = (x & 0x1ffc0000) >> 18;
+ dma->incr = (x & 0x40000000 ? 0 : dma->size);
+ }
+
+ pretty_header(s, e);
+ } else {
+ if (dma->addr == 0)
+ s->subchan[dma->subchan] = get_object(s, x);
+
+ pretty_method(s, e, x);
+
+ if (dma->incr) {
+ dma->addr += 4;
+ dma->incr--;
+ }
+
+ dma->size--;
+ }
+}
+
+static int
+dont_printf(const char *fmt, ...)
+{
+ return 0;
+}
+
+int
+dedma(struct state *s, FILE *f, bool dry_run)
+{
+ struct filter *flt = &s->filter;
+ struct ent *e0 = NULL, *e1;
+ int i, j; /* dump line numbers */
+
+ s->f = f;
+ s->op.print = (dry_run ? dont_printf : printf);
+
+ for (i = 0; e1 = e0, e0 = get_ent(s, i); i++) {
+ if (!e1)
+ continue;
+
+ if (e0->addr < flt->addr0 || e0->addr >= flt->addr1) {
+ /* out of band data */
+ e0->out_of_band = true;
+
+ } else if (abs(e0->addr - e1->addr) > MAX_DELTA &&
+ !e1->out_of_band) {
+ /* wrap around or out of band data not caught by
+ * the address window */
+
+ for (j = i + 1; (j < i + MAX_OUT_OF_BAND &&
+ (e1 = get_ent(s, j))); j++) {
+ if (abs(e0->addr - e1->addr) > MAX_DELTA) {
+ for (; i < j; i++)
+ get_ent(s, i)->out_of_band = true;
+
+ /* shrink the address window */
+ if (e1->addr > e0->addr)
+ flt->addr0 = max(e0->addr + 4,
+ flt->addr0);
+ else if (e1->addr < e0->addr)
+ flt->addr1 = min(e0->addr,
+ flt->addr1);
+ break;
+ }
+ }
+
+ } else if (e0->addr < e1->addr + 4) {
+ /* badly ordered write, find a place for it */
+
+ for (j = i - 1; (j > i - MAX_DELTA &&
+ (e1 = get_ent(s, j))); j--) {
+ if (e0->addr == e1->addr) {
+ /* duplicated write, keep the
+ * most recent one */
+ *e1 = *e0;
+ drop_ent(s, i--);
+ break;
+
+ } else if (e0->addr == e1->addr + 3) {
+ /* 8bit writes */
+ e1->val |= e0->val << 24;
+ drop_ent(s, i--);
+ break;
+
+ } else if (e0->addr == e1->addr + 2) {
+ /* 16bit writes */
+ e1->val |= e0->val << 16;
+ drop_ent(s, i--);
+ break;
+
+ } else if (e0->addr == e1->addr + 1) {
+ /* 8bit writes */
+ e1->val |= e0->val << 8;
+ drop_ent(s, i--);
+ break;
+
+ } else if (e0->addr > e1->addr) {
+ /* unordered write */
+ rotate_ent(s, j + 1, i);
+ break;
+ }
+ }
+ }
+ }
+
+ flush_cache(s);
+ return 0;
+}
+
+static bool
+configure(struct state *s, int argc, char *argv[], char **path,
+ struct obj obj[MAX_OBJECTS], int *nobj)
+{
+ int i;
+
+ for (i = 1; i < argc; i++) {
+ if (!strcmp(argv[i], "-x")) {
+ s->op.flush = flush_raw;
+
+ } else if (!strcmp(argv[i], "-c")) {
+ s->colors = &envy_def_colors;
+
+ } else if (!strcmp(argv[i], "-m")) {
+ if (i + 1 >= argc)
+ goto fail;
+
+ if (!strncasecmp(argv[++i], "NV", 2))
+ s->chipset = strtoul(argv[i] + 2, NULL, 16);
+ else
+ s->chipset = strtoul(argv[i], NULL, 16);
+
+ } else if (!strcmp(argv[i], "-o")) {
+ if (i + 2 >= argc || *nobj == MAX_OBJECTS)
+ goto fail;
+
+ obj[*nobj].handle = strtoul(argv[++i], NULL, 16);
+ obj[*nobj].class = strtoul(argv[++i], NULL, 16);
+ (*nobj)++;
+
+ } else if (!strcmp(argv[i], "-r")) {
+ if (i + 1 >= argc)
+ goto fail;
+
+ s->op.parse = parse_renouveau;
+ *path = argv[++i];
+
+ } else if (!strcmp(argv[i], "-v")) {
+ if (i + 2 >= argc)
+ goto fail;
+
+ s->op.parse = parse_valgrind;
+ s->filter.map = strtol(argv[++i], NULL, 10);
+ *path = argv[++i];
+
+ } else {
+ goto fail;
+ }
+ }
+
+ if (!*path)
+ goto fail;
+ if (!s->colors)
+ s->colors = &envy_null_colors;
+ if (!s->op.flush)
+ s->op.flush = flush_dma;
+ s->filter.addr1 = ~0;
+
+ return true;
+fail:
+ fprintf(stderr, "usage: %s [ -x ] [ -c ] [ -m 'chipset' ]"
+ " [ -o 'handle' 'class' ] [ -r 'file' ] [ -v 'map' 'file' ]\n"
+ "\t-x\tHexadecimal output mode.\n"
+ "\t-c\tClassy output mode.\n"
+ "\t-m\tForce chipset version.\n"
+ "\t-o\tForce handle to class mapping"
+ " (repeat for multiple mappings).\n"
+ "\t-r\tParse a renouveau trace.\n"
+ "\t-v\tParse a valgrind-mmt trace.\n",
+ argv[0]);
+ return false;
+}
+
+int
+main(int argc, char *argv[])
+{
+ struct state s = { };
+ struct obj obj[MAX_OBJECTS];
+ int nobj = 0;
+ char *path = NULL;
+ FILE *f;
+ int i;
+
+ /* parse the command line */
+ if (!configure(&s, argc, argv, &path, obj, &nobj))
+ return EINVAL;
+
+ /* open the input */
+ f = fopen(path, "r");
+ if (!f) {
+ perror(argv[0]);
+ return errno;
+ }
+
+ /* set up an rnn context */
+ rnn_init();
+ s.db = rnn_newdb();
+ rnn_parsefile(s.db, "nv_objects.xml");
+ rnn_prepdb(s.db);
+ s.dom = rnn_finddomain(s.db, "NV01_SUBCHAN");
+
+ /* insert objects specified in the command line */
+ for (i = 0; i < nobj; i++)
+ add_object(&s, obj[i].handle, obj[i].class);
+
+ if (s.op.parse == parse_renouveau) {
+ path = dirname(path);
+ parse_renouveau_chipset(&s, path);
+ parse_renouveau_objects(&s, path);
+ parse_renouveau_startup(&s, path);
+ }
+
+ /* do it */
+ dedma(&s, f, false);
+
+ /* clean up */
+ fclose(f);
+ free(s.parse.buf);
+
+ return 0;
+}
diff --git a/envytools/rnn/dedma.h b/envytools/rnn/dedma.h
new file mode 100644
index 0000000..b2eaa84
--- /dev/null
+++ b/envytools/rnn/dedma.h
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2010 Francisco Jerez.
+ * 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 COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS 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.
+ */
+
+#ifndef __DEDMA_H__
+#define __DEDMA_H__
+
+#define _GNU_SOURCE
+#include <errno.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <libgen.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "rnn.h"
+#include "rnndec.h"
+
+#define MAX_DELTA 16384 /* size of the reordering window */
+#define MAX_OUT_OF_BAND 8 /* maximum consecutive out of band data entries */
+#define MAX_CACHE 4096 /* dump cache size */
+#define MAX_OBJECTS 256 /* object cache size */
+#define MAX_SUBCHAN 8
+
+struct ent {
+ uint32_t addr;
+ uint32_t val;
+ bool out_of_band;
+};
+
+struct obj {
+ uint32_t handle;
+ uint32_t class;
+ char *name;
+ struct rnndeccontext *ctx;
+};
+
+struct filter {
+ int map;
+ uint32_t addr0, addr1; /* address range we care about */
+};
+
+struct cache {
+ int i0, i1; /* cached index range */
+ int k; /* offset the cache starts in */
+ struct ent ent[MAX_CACHE];
+};
+
+struct dma {
+ int incr;
+ int subchan;
+ int addr;
+ int size;
+ int skip;
+ int nops;
+};
+
+struct state {
+ struct {
+ bool (*parse)(struct state *);
+ void (*flush)(struct state *, struct ent *);
+ int (*print)(const char *, ...);
+ } op;
+
+ FILE *f;
+ uint32_t chipset;
+ uint32_t pci_id;
+
+ struct rnndb *db;
+ struct rnndomain *dom;
+ const struct envy_colors *colors;
+
+ struct filter filter;
+ struct cache cache;
+
+ struct {
+ char *buf;
+ size_t n;
+ uint32_t addr;
+ } parse;
+
+ struct obj objects[MAX_OBJECTS];
+ struct obj *subchan[MAX_SUBCHAN];
+ struct dma dma;
+};
+
+/* dedma.c */
+void
+add_object(struct state *s, uint32_t handle, uint32_t class);
+
+struct obj *
+get_object(struct state *s, uint32_t handle);
+
+int
+dedma(struct state *s, FILE *f, bool dry_run);
+
+/* dedma_cache.c */
+struct ent *
+get_ent(struct state *s, int i);
+
+void
+rotate_ent(struct state *s, int i, int j);
+
+void
+add_ent(struct state *s, struct ent *e);
+
+void
+drop_ent(struct state *s, int i);
+
+void
+flush_cache(struct state *s);
+
+/* dedma_back.c */
+void
+parse_renouveau_chipset(struct state *s, char *path);
+
+void
+parse_renouveau_objects(struct state *s, char *path);
+
+void
+parse_renouveau_startup(struct state *s, char *path);
+
+bool
+parse_renouveau(struct state *s);
+
+bool
+parse_valgrind(struct state *s);
+
+#endif
diff --git a/envytools/rnn/dedma_back.c b/envytools/rnn/dedma_back.c
new file mode 100644
index 0000000..f46d4c5
--- /dev/null
+++ b/envytools/rnn/dedma_back.c
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2010 Francisco Jerez.
+ * 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 COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS 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.
+ */
+
+#include "dedma.h"
+
+void
+parse_renouveau_chipset(struct state *s, char *path)
+{
+ char *buf = NULL;
+ uint32_t val;
+ FILE *f;
+
+ asprintf(&buf, "%s/card_stdout.txt", path);
+ f = fopen(buf, "r");
+ if (!f) {
+ fprintf(stderr, "Couldn't open %s: %s\n", buf,
+ strerror(errno));
+ goto out;
+ }
+
+ while (getline(&s->parse.buf, &s->parse.n, f) >= 0) {
+ if (sscanf(s->parse.buf, "BOOT0\t%x", &val) == 1) {
+ s->chipset = (val & 0x0f000000 ? (val >> 20) & 0xff :
+ val & 0x0000f000 ? ((val >> 20) & 0xf) + 4 :
+ (val >> 16) & 0xf);
+
+ } else if (sscanf(s->parse.buf, "pci_id\t%x", &val) == 1) {
+ s->pci_id = val;
+ }
+ }
+
+ fclose(f);
+out:
+ free(buf);
+}
+
+void
+parse_renouveau_objects(struct state *s, char *path)
+{
+ char *buf = NULL;
+ uint32_t handle, ent;
+ FILE *f;
+
+ asprintf(&buf, "%s/card_objects.txt", path);
+ f = fopen(buf, "r");
+ if (!f) {
+ fprintf(stderr, "Couldn't open %s: %s\n", buf,
+ strerror(errno));
+ goto out;
+ }
+
+ while (getline(&s->parse.buf, &s->parse.n, f) >= 0) {
+ if (sscanf(s->parse.buf, "%x %*x %x", &handle, &ent) == 2)
+ add_object(s, handle, (s->chipset >= 0x40 ?
+ ent & 0xffff : ent & 0xfff));
+ }
+
+ fclose(f);
+out:
+ free(buf);
+}
+
+void
+parse_renouveau_startup(struct state *s, char *path)
+{
+ char *buf = NULL;
+ FILE *f;
+
+ asprintf(&buf, "%s/card_%04x-%04x_test_startup.txt", path,
+ s->pci_id >> 16, s->pci_id & 0xffff);
+ f = fopen(buf, "r");
+ if (!f) {
+ fprintf(stderr, "Couldn't open %s: %s\n", buf,
+ strerror(errno));
+ goto out;
+ }
+
+ dedma(s, f, true);
+
+ fclose(f);
+out:
+ free(buf);
+}
+
+bool
+parse_renouveau(struct state *s)
+{
+ struct ent e = {
+ .addr = s->parse.addr
+ };
+ int ret;
+
+ for (;;) {
+ if (getline(&s->parse.buf, &s->parse.n, s->f) < 0)
+ return false;
+
+ ret = sscanf(s->parse.buf, "%x", &e.val);
+ if (ret == 1)
+ break;
+ }
+
+ add_ent(s, &e);
+ s->parse.addr += 4;
+ return true;
+}
+
+bool
+parse_valgrind(struct state *s)
+{
+ struct ent e = {};
+ unsigned m, addr, val[4];
+ char c[3] = {};
+ int i;
+
+ for (;;) {
+ if (getline(&s->parse.buf, &s->parse.n, s->f) < 0)
+ return false;
+
+ i = sscanf(s->parse.buf, "--%*d-- w %d:%x, %x%c%x%c%x%c%x",
+ &m, &addr, &val[0], &c[0], &val[1], &c[1],
+ &val[2], &c[2], &val[3]);
+ if(i==6){ //reorder words (2,1) => (1,2)
+ unsigned x = val[0];
+ val[0] = val[1];
+ val[1] = x;
+ }
+ else if(i==9){ //reorder words (4,3,2,1) => (1,2,3,4)
+ unsigned x = val[0];
+ val[0] = val[3];
+ val[3] = x;
+ x = val[1];
+ val[1] = val[2];
+ val[2] = x;
+ }
+ if (i >= 4 && m == s->filter.map)
+ break;
+
+ i = sscanf(s->parse.buf, "--%*d-- create gpu object"
+ " 0x%*x:0x%x type 0x%x", &val[0], &val[1]);
+ if (i == 2)
+ add_object(s, val[0], val[1]);
+ }
+
+ for (i = 0; i <= 3 && (i == 0 || c[i - 1] == ','); i++) {
+ e.addr = addr;
+ e.val = val[i];
+ add_ent(s, &e);
+ addr += 4;
+ }
+
+ return true;
+}
diff --git a/envytools/rnn/dedma_cache.c b/envytools/rnn/dedma_cache.c
new file mode 100644
index 0000000..bf357a2
--- /dev/null
+++ b/envytools/rnn/dedma_cache.c
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2010 Francisco Jerez.
+ * 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 COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS 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.
+ */
+
+#include "dedma.h"
+
+#define CACHE_ENT(s, i) \
+ (&(s)->cache.ent[((i) - (s)->cache.i0 + (s)->cache.k) % MAX_CACHE])
+
+struct ent *
+get_ent(struct state *s, int i)
+{
+ struct cache *c = &s->cache;
+
+ if (i < c->i0 || i > c->i1)
+ return NULL;
+
+ if (i == c->i1 && !s->op.parse(s))
+ return NULL;
+
+ return CACHE_ENT(s, i);
+}
+
+void
+rotate_ent(struct state *s, int i, int j)
+{
+ const int d = sizeof(struct ent);
+ struct cache *c = &s->cache;
+ int ki = CACHE_ENT(s, i) - c->ent;
+ int kj = CACHE_ENT(s, j) - c->ent;
+ struct ent tmp;
+
+ assert(j >= i && j >= c->i0 && j < c->i1 &&
+ i >= c->i0 && i < c->i1);
+
+ memmove(&tmp, c->ent + kj, d);
+
+ if (ki >= c->k && kj < c->k) {
+ /* the region wraps around */
+ memmove(c->ent + 1, c->ent, d * kj);
+ memmove(c->ent, c->ent + MAX_CACHE - 1, d);
+ memmove(c->ent + ki + 1, c->ent + ki, d * (MAX_CACHE - ki - 1));
+
+ } else {
+ /* easy case */
+ memmove(c->ent + ki + 1, c->ent + ki, d * (kj - ki));
+ }
+
+ memmove(c->ent + ki, &tmp, d);
+}
+
+void
+add_ent(struct state *s, struct ent *e)
+{
+ struct cache *c = &s->cache;
+
+ if (c->i1 - c->i0 == MAX_CACHE) {
+ s->op.flush(s, CACHE_ENT(s, c->i0));
+ c->k = (c->k + 1) % MAX_CACHE;
+ c->i0++;
+ }
+
+ *CACHE_ENT(s, c->i1) = *e;
+ c->i1++;
+}
+
+void
+drop_ent(struct state *s, int i)
+{
+ struct cache *c = &s->cache;
+
+ rotate_ent(s, c->i0, i);
+ c->k = (c->k + 1) % MAX_CACHE;
+ c->i1--;
+}
+
+void
+flush_cache(struct state *s)
+{
+ struct cache *c = &s->cache;
+ int i;
+
+ for (i = c->i0; i < c->i1; i++)
+ s->op.flush(s, CACHE_ENT(s, i));
+
+ c->i0 = c->i1 = 0;
+}
diff --git a/envytools/rnn/demmio.c b/envytools/rnn/demmio.c
new file mode 100644
index 0000000..5a3ef85
--- /dev/null
+++ b/envytools/rnn/demmio.c
@@ -0,0 +1,516 @@
+/*
+ * Copyright (C) 2010-2011 Marcin Kościelnicki <koriakin@0x04.net>
+ * Copyright (C) 2011 Martin Peres <martin.peres@ensi-bourges.fr>
+ * 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
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS 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.
+ */
+
+#include "rnn.h"
+#include "rnndec.h"
+#include "var.h"
+#include "dis.h"
+#include "util.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <string.h>
+
+int sleep_disabled = 0;
+
+struct i2c_ctx {
+ int last;
+ int aok;
+ int wr;
+ int bits;
+ int b;
+ int pend;
+};
+
+struct cctx {
+ struct rnndeccontext *ctx;
+ int chdone;
+ int arch;
+ int chipset;
+ uint64_t praminbase;
+ uint64_t ramins;
+ uint64_t fakechan;
+ int i2cip;
+ int hwsqip;
+ uint32_t hwsqnext;
+ uint32_t ctxpos;
+ uint8_t hwsq[0x200];
+ struct mpage **pages;
+ int pagesnum, pagesmax;
+ uint64_t bar0, bar0l, bar1, bar1l, bar2, bar2l;
+ struct i2c_ctx i2cb[10];
+ int crx0, crx1;
+};
+
+struct cctx *cctx = 0;
+int cctxnum = 0, cctxmax = 0;
+
+struct mpage {
+ uint64_t tag;
+ uint32_t contents[0x1000/4];
+};
+
+uint32_t *findmem (struct cctx *ctx, uint64_t addr) {
+ int i;
+ uint64_t tag = addr & ~0xfffull;
+ for (i = 0; i < ctx->pagesnum; i++) {
+ if (tag == ctx->pages[i]->tag)
+ return &ctx->pages[i]->contents[(addr&0xfff)/4];
+ }
+ struct mpage *pg = calloc (sizeof *pg, 1);
+ pg->tag = tag;
+ ADDARRAY(ctx->pages, pg);
+ return &pg->contents[(addr&0xfff)/4];
+}
+
+int i2c_bus_num (uint64_t addr) {
+ switch (addr) {
+ case 0xe138:
+ return 0;
+ case 0xe150:
+ return 1;
+ case 0xe168:
+ return 2;
+ case 0xe180:
+ return 3;
+ case 0xe254:
+ return 4;
+ case 0xe274:
+ return 5;
+ case 0xe764:
+ return 6;
+ case 0xe780:
+ return 7;
+ case 0xe79c:
+ return 8;
+ case 0xe7b8:
+ return 9;
+ default:
+ return -1;
+ }
+}
+
+void doi2cr (struct cctx *cc, struct i2c_ctx *ctx, int byte) {
+ if (ctx->pend) {
+ if (ctx->bits == 8) {
+ if (byte & 2)
+ printf ("- ");
+ else
+ printf ("+ ");
+ if (!ctx->aok) {
+ ctx->aok = 1;
+ ctx->wr = !(ctx->b&1);
+ }
+ ctx->bits = 0;
+ ctx->b = 0;
+ } else {
+ ctx->b <<= 1;
+ ctx->b |= (byte & 2) >> 1;
+ ctx->bits++;
+ if (ctx->bits == 8) {
+ printf ("<%02x", ctx->b);
+ }
+ }
+ ctx->pend = 0;
+ }
+}
+
+void doi2cw (struct cctx *cc, struct i2c_ctx *ctx, int byte) {
+ if (!ctx->last)
+ ctx->last = 7;
+ if (!(byte & 1) && (ctx->last & 1)) {
+ /* clock went low */
+ }
+ if ((byte & 1) && !(ctx->last & 1)) {
+ if (ctx->pend) {
+ printf ("\nI2C LOST!\n");
+ doi2cr(cc, ctx, 0);
+ ctx->pend = 0;
+ }
+ /* clock went high */
+ if (ctx->bits == 8) {
+ if (ctx->wr || !ctx->aok) {
+ ctx->pend = 1;
+ } else {
+ if (byte & 2)
+ printf ("- ");
+ else
+ printf ("+ ");
+ ctx->bits = 0;
+ ctx->b = 0;
+ }
+ } else {
+ if (ctx->wr || !ctx->aok) {
+ ctx->b <<= 1;
+ ctx->b |= (byte & 2) >> 1;
+ ctx->bits++;
+ if (ctx->bits == 8) {
+ printf (">%02x", ctx->b);
+ }
+ } else {
+ ctx->pend = 1;
+ }
+ }
+ }
+ if ((byte & 1) && !(byte & 2) && (ctx->last & 2)) {
+ /* data went low with high clock - start bit */
+ printf ("START ");
+ ctx->bits = 0;
+ ctx->b = 0;
+ ctx->aok = 0;
+ ctx->wr = 0;
+ ctx->pend = 0;
+ sleep_disabled = 1;
+ }
+ if ((byte & 1) && (byte & 2) && !(ctx->last & 2)) {
+ /* data went high with high clock - stop bit */
+ printf ("STOP\n");
+ cc->i2cip = -1;
+ ctx->bits = 0;
+ ctx->b = 0;
+ ctx->aok = 0;
+ ctx->wr = 0;
+ ctx->pend = 0;
+ sleep_disabled = 0;
+ }
+ ctx->last = byte;
+}
+
+FILE *open_input(char *filename) {
+ const char * const tab[][2] = {
+ { ".gz", "zcat" },
+ { ".Z", "zcat" },
+ { ".bz2", "bzcat" },
+ { ".xz", "xzcat" },
+ };
+ int i;
+ int flen = strlen(filename);
+ for (i = 0; i < sizeof tab / sizeof tab[0]; i++) {
+ int elen = strlen(tab[i][0]);
+ if (flen > elen && !strcmp(filename + flen - elen, tab[i][0])) {
+ fprintf (stderr, "Compressed trace detected, trying to decompress...\n");
+ char *cmd = malloc(flen + strlen(tab[i][1]) + 2);
+ FILE *res;
+ strcpy(cmd, tab[i][1]);
+ strcat(cmd, " ");
+ strcat(cmd, filename);
+ res = popen(cmd, "r");
+ free(cmd);
+ return res;
+ }
+ }
+ return fopen(filename, "r");
+}
+
+int main(int argc, char **argv) {
+ rnn_init();
+
+ struct rnndb *db = rnn_newdb();
+ rnn_parsefile (db, "nv_mmio.xml");
+ rnn_prepdb (db);
+ struct rnndomain *mmiodom = rnn_finddomain(db, "NV_MMIO");
+ struct rnndomain *crdom = rnn_finddomain(db, "NV_CR");
+ FILE *fin = stdin;
+
+ if (argc > 1)
+ fin = open_input(argv[1]);
+
+ if (!fin) {
+ fprintf (stderr, "Failed to open input file!\n");
+ return 1;
+ }
+
+ char line[1024];
+ int i;
+ const struct disisa *ctx_isa = ed_getisa("ctx");
+ struct varinfo *ctx_var_nv40 = varinfo_new(ctx_isa->vardata);
+ struct varinfo *ctx_var_nv50 = varinfo_new(ctx_isa->vardata);
+ varinfo_set_variant(ctx_var_nv40, "nv40");
+ varinfo_set_variant(ctx_var_nv50, "nv50");
+ const struct disisa *hwsq_isa = ed_getisa("hwsq");
+ struct varinfo *hwsq_var_nv17 = varinfo_new(hwsq_isa->vardata);
+ struct varinfo *hwsq_var_nv41 = varinfo_new(hwsq_isa->vardata);
+ struct varinfo *hwsq_var_nv50 = varinfo_new(hwsq_isa->vardata);
+ varinfo_set_variant(hwsq_var_nv17, "nv17");
+ varinfo_set_variant(hwsq_var_nv41, "nv41");
+ varinfo_set_variant(hwsq_var_nv50, "nv50");
+ const struct envy_colors *colors = &envy_def_colors;
+ while (1) {
+ /* yes, static buffer. but mmiotrace lines are bound to have sane length anyway. */
+ if (!fgets(line, sizeof(line), fin))
+ break;
+ if (!strncmp(line, "PCIDEV ", 7)) {
+ uint64_t bar[4], len[4], pciid;
+ sscanf (line, "%*s %*s %"SCNx64" %*s %"SCNx64" %"SCNx64" %"SCNx64" %"SCNx64" %*s %*s %*s %"SCNx64" %"SCNx64" %"SCNx64" %"SCNx64"", &pciid, &bar[0], &bar[1], &bar[2], &bar[3], &len[0], &len[1], &len[2], &len[3]);
+ if ((pciid >> 16) == 0x10de && bar[0] && (bar[0] & 0xf) == 0 && bar[1] && (bar[1] & 0x1) == 0x0) {
+ struct cctx nc = { 0 };
+ nc.bar0 = bar[0], nc.bar0l = len[0];
+ nc.bar1 = bar[1], nc.bar1l = len[1];
+ if (bar[2])
+ nc.bar2 = bar[2], nc.bar2l = len[2];
+ else
+ nc.bar2 = bar[3], nc.bar2l = len[3];
+ nc.bar0 &= ~0xf;
+ nc.bar1 &= ~0xf;
+ nc.bar2 &= ~0xf;
+ nc.i2cip = -1;
+ nc.ctx = rnndec_newcontext(db);
+ nc.ctx->colors = colors;
+ for (i = 0; i < 10; i++)
+ nc.i2cb[i].last = 7;
+ ADDARRAY(cctx, nc);
+ }
+ printf ("%s", line);
+ } else if (!strncmp(line, "W ", 2) || !strncmp(line, "R ", 2)) {
+ int skip = 0;
+ static double timestamp, timestamp_old = 0;
+ uint64_t addr, value;
+ int width;
+ int cci;
+ sscanf (line, "%*s %d %lf %*d %"SCNx64" %"SCNx64, &width, &timestamp, &addr, &value);
+ width *= 8;
+
+ /* Add a SLEEP line when two mmio accesses are more distant than 100µs */
+ if (!sleep_disabled && timestamp_old > 0 && (timestamp - timestamp_old) > 0.0001)
+ printf("SLEEP %lfms\n", (timestamp - timestamp_old)*1000.0);
+ timestamp_old = timestamp;
+
+ for (cci = 0; cci < cctxnum; cci++) {
+ struct cctx *cc = &cctx[cci];
+ if (cc->bar0 && addr >= cc->bar0 && addr < cc->bar0+cc->bar0l) {
+ addr -= cc->bar0;
+ if (cc->hwsqip && addr != cc->hwsqnext) {
+ struct varinfo *var = hwsq_var_nv17;
+ if (cc->chipset >= 0x41)
+ var = hwsq_var_nv41;
+ if (cc->arch == 5)
+ var = hwsq_var_nv50;
+ envydis(hwsq_isa, stdout, cc->hwsq, 0, cc->hwsqnext & 0x3fc, var, 0, 0, 0, colors);
+ cc->hwsqip = 0;
+ }
+ if (addr == 0 && !cc->chdone) {
+ char chname[5];
+ if (value & 0x0f000000)
+ snprintf(chname, 5, "NV%02"PRIX64, (value >> 20) & 0xff);
+ else if (value & 0x0000f000)
+ snprintf(chname, 5, "NV%02"PRIX64, ((value >> 20) & 0xf) + 4);
+ else
+ snprintf(chname, 5, "NV%02"PRIX64, ((value >> 16) & 0xf));
+ rnndec_varadd(cc->ctx, "chipset", chname);
+ switch ((value >> 20) & 0xf0) {
+ case 0:
+ cc->arch = 0;
+ break;
+ case 0x10:
+ cc->arch = 1;
+ break;
+ case 0x20:
+ cc->arch = 2;
+ break;
+ case 0x30:
+ cc->arch = 3;
+ break;
+ case 0x40:
+ case 0x60:
+ cc->arch = 4;
+ break;
+ case 0x50:
+ case 0x80:
+ case 0x90:
+ case 0xa0:
+ cc->arch = 5;
+ break;
+ case 0xc0:
+ case 0xd0:
+ case 0xe0:
+ cc->arch = 6;
+ break;
+ }
+ cc->chipset = (value >> 20) & 0xff;
+ } else if (cc->arch >= 5 && addr == 0x1700) {
+ cc->praminbase = value << 16;
+ } else if (cc->arch == 5 && addr == 0x1704) {
+ cc->fakechan = (value & 0xfffffff) << 12;
+ } else if (cc->arch == 5 && addr == 0x170c) {
+ cc->ramins = (value & 0xffff) << 4;
+ } else if (cc->arch >= 6 && addr == 0x1714) {
+ cc->ramins = (value & 0xfffffff) << 12;
+ } else if (addr == 0x6013d4) {
+ cc->crx0 = value & 0xff;
+ } else if (addr == 0x6033d4) {
+ cc->crx1 = value & 0xff;
+ } else if (addr == 0x6013d5) {
+ struct rnndecaddrinfo *ai = rnndec_decodeaddr(cc->ctx, crdom, cc->crx0, line[0] == 'W');
+ char *decoded_val = rnndec_decodeval(cc->ctx, ai->typeinfo, value, ai->width);
+ printf ("[%d] %lf CRTC0 %c 0x%02x 0x%02"PRIx64" %s %s %s\n", cci, timestamp, line[0], cc->crx0, value, ai->name, line[0]=='W'?"<=":"=>", decoded_val);
+ free(ai->name);
+ free(ai);
+ free(decoded_val);
+ skip = 1;
+ } else if (addr == 0x6033d5) {
+ struct rnndecaddrinfo *ai = rnndec_decodeaddr(cc->ctx, crdom, cc->crx1, line[0] == 'W');
+ char *decoded_val = rnndec_decodeval(cc->ctx, ai->typeinfo, value, ai->width);
+ printf ("[%d] %lf CRTC1 %c 0x%02x 0x%02"PRIx64" %s %s %s\n", cci, timestamp, line[0], cc->crx1, value, ai->name, line[0]=='W'?"<=":"=>", decoded_val);
+ free(ai->name);
+ free(ai);
+ free(decoded_val);
+ skip = 1;
+ } else if (cc->arch >= 5 && (addr & 0xfff000) == 0xe000) {
+ int bus = i2c_bus_num(addr);
+ if (bus != -1) {
+ if (cc->i2cip != bus) {
+ if (cc->i2cip != -1)
+ printf ("\n");
+ struct rnndecaddrinfo *ai = rnndec_decodeaddr(cc->ctx, mmiodom, addr, line[0] == 'W');
+ printf ("[%d] I2C 0x%06"PRIx64" %s ", cci, addr, ai->name);
+ free(ai->name);
+ free(ai);
+ cc->i2cip = bus;
+ }
+ if (line[0] == 'R') {
+ doi2cr(cc, &cc->i2cb[bus], value);
+ } else {
+ doi2cw(cc, &cc->i2cb[bus], value);
+ }
+ skip = 1;
+ }
+ } else if ((addr & 0xfff000) == 0x9000 && (cc->i2cip != -1)) {
+ /* ignore PTIMER meddling during I2C */
+ skip = 1;
+ } else if (addr == 0x1400 || addr == 0x80000 || addr == cc->hwsqnext) {
+ if (!cc->hwsqip) {
+ struct rnndecaddrinfo *ai = rnndec_decodeaddr(cc->ctx, mmiodom, addr, line[0] == 'W');
+ printf ("[%d] HWSQ 0x%06"PRIx64" %s\n", cci, addr, ai->name);
+ free(ai->name);
+ free(ai);
+ }
+ cc->hwsq[(addr & 0x1fc) + 0] = value;
+ cc->hwsq[(addr & 0x1fc) + 1] = value >> 8;
+ cc->hwsq[(addr & 0x1fc) + 2] = value >> 16;
+ cc->hwsq[(addr & 0x1fc) + 3] = value >> 24;
+ cc->hwsqip = 1;
+ cc->hwsqnext = addr + 4;
+ skip = 1;
+ } else if (addr == 0x400324 && cc->arch >= 4 && cc->arch <= 5) {
+ cc->ctxpos = value;
+ } else if (addr == 0x400328 && cc->arch >= 4 && cc->arch <= 5) {
+ uint8_t param[4];
+ param[0] = value;
+ param[1] = value >> 8;
+ param[2] = value >> 16;
+ param[3] = value >> 24;
+ struct rnndecaddrinfo *ai = rnndec_decodeaddr(cc->ctx, mmiodom, addr, line[0] == 'W');
+ printf ("[%d] MMIO%d %c 0x%06"PRIx64" 0x%08"PRIx64" %s %s ", cci, width, line[0], addr, value, ai->name, line[0]=='W'?"<=":"=>");
+ envydis(ctx_isa, stdout, param, cc->ctxpos, 4, (cc->arch == 5 ? ctx_var_nv50 : ctx_var_nv40), 0, 0, 0, colors);
+ cc->ctxpos++;
+ free(ai->name);
+ free(ai);
+ skip = 1;
+ }
+ if (!skip && (cc->i2cip != -1)) {
+ printf ("\n");
+ cc->i2cip = -1;
+ }
+ if (cc->arch >= 5 && addr >= 0x700000 && addr < 0x800000) {
+ addr -= 0x700000;
+ addr += cc->praminbase;
+ printf ("[%d] %lf, MEM%d %"PRIx64" %s %"PRIx64"\n", cci, timestamp, width, addr, line[0]=='W'?"<=":"=>", value);
+ *findmem(cc, addr) = value;
+ } else if (!skip) {
+ struct rnndecaddrinfo *ai = rnndec_decodeaddr(cc->ctx, mmiodom, addr, line[0] == 'W');
+ if (width == 32 && ai->width == 8) {
+ /* 32-bit write to 8-bit location - split it up */
+ int b;
+ free(ai->name);
+ free(ai);
+ int cnt;
+ for (b = 0; b < 4; b++) {
+ struct rnndecaddrinfo *ai = rnndec_decodeaddr(cc->ctx, mmiodom, addr+b, line[0] == 'W');
+ char *decoded_val = rnndec_decodeval(cc->ctx, ai->typeinfo, value >> b * 8 & 0xff, ai->width);
+ if (b == 0) {
+ printf ("[%d] %lf MMIO%d %c 0x%06"PRIx64" 0x%08"PRIx64" %n%s %s %s\n", cci, timestamp, width, line[0], addr, value, &cnt, ai->name, line[0]=='W'?"<=":"=>", decoded_val);
+ } else {
+ int c;
+ for (c = 0; c < cnt; c++)
+ printf(" ");
+ printf ("%s %s %s\n", ai->name, line[0]=='W'?"<=":"=>", decoded_val);
+ }
+ free(ai->name);
+ free(ai);
+ free(decoded_val);
+ }
+ } else {
+ char *decoded_val = rnndec_decodeval(cc->ctx, ai->typeinfo, value, ai->width);
+ printf ("[%d] %lf MMIO%d %c 0x%06"PRIx64" 0x%08"PRIx64" %s %s %s\n", cci, timestamp, width, line[0], addr, value, ai->name, line[0]=='W'?"<=":"=>", decoded_val);
+ free(ai->name);
+ free(ai);
+ free(decoded_val);
+ }
+ }
+ } else if (cc->bar1 && addr >= cc->bar1 && addr < cc->bar1+cc->bar1l) {
+ addr -= cc->bar1;
+ printf ("[%d] %lf, FB%d %"PRIx64" %s %"PRIx64"\n", cci, timestamp, width, addr, line[0]=='W'?"<=":"=>", value);
+ } else if (cc->bar2 && addr >= cc->bar2 && addr < cc->bar2+cc->bar2l) {
+ addr -= cc->bar2;
+ if (cc->arch >= 6) {
+ uint64_t pd = *findmem(cc, cc->ramins + 0x200);
+ uint64_t pt = *findmem(cc, pd + 4);
+ pt &= 0xfffffff0;
+ pt <<= 8;
+ uint64_t pg = *findmem(cc, pt + (addr/0x1000) * 8);
+ pg &= 0xfffffff0;
+ pg <<= 8;
+ pg += (addr&0xfff);
+ *findmem(cc, pg) = value;
+ // printf ("%"PRIx64" %"PRIx64" %"PRIx64" %"PRIx64"\n", ramins, pd, pt, pg);
+ printf ("[%d] %lf RAMIN%d %"PRIx64" %"PRIx64" %s %"PRIx64"\n", cci, timestamp, width, addr, pg, line[0]=='W'?"<=":"=>", value);
+ } else if (cc->arch == 5) {
+ uint64_t paddr = addr;
+ paddr += *findmem(cc, cc->fakechan + cc->ramins + 8);
+ paddr += (uint64_t)(*findmem(cc, cc->fakechan + cc->ramins + 12) >> 24) << 32;
+ uint64_t pt = *findmem(cc, cc->fakechan + (cc->chipset == 0x50 ? 0x1400 : 0x200) + ((paddr >> 29) << 3));
+ // printf ("%#"PRIx64" PT: %#"PRIx64" %#"PRIx64" ", paddr, fakechan + 0x200 + ((paddr >> 29) << 3), pt);
+ uint32_t div = (pt & 2 ? 0x1000 : 0x10000);
+ pt &= 0xfffff000;
+ uint64_t pg = *findmem(cc, pt + ((paddr&0x1ffff000)/div) * 8);
+ uint64_t pgh = *findmem(cc, pt + ((paddr&0x1ffff000)/div) * 8 + 4);
+ // printf ("PG: %#"PRIx64" %#"PRIx64"\n", pt + ((paddr&0x1ffff000)/div) * 8, pgh << 32 | pg);
+ pg &= 0xfffff000;
+ pg |= (pgh & 0xff) << 32;
+ pg += (paddr & (div-1));
+ *findmem(cc, pg) = value;
+ // printf ("%"PRIx64" %"PRIx64" %"PRIx64" %"PRIx64"\n", ramins, pd, pt, pg);
+ printf ("[%d] %lf RAMIN%d %"PRIx64" %"PRIx64" %s %"PRIx64"\n", cci, timestamp, width, addr, pg, line[0]=='W'?"<=":"=>", value);
+ } else {
+ printf ("[%d] %lf RAMIN%d %"PRIx64" %s %"PRIx64"\n", cci, timestamp, width, addr, line[0]=='W'?"<=":"=>", value);
+ }
+ }
+ }
+ } else {
+ printf ("%s", line);
+ }
+ }
+ return 0;
+}
diff --git a/envytools/rnn/expand.c b/envytools/rnn/expand.c
new file mode 100644
index 0000000..f7d4f6f
--- /dev/null
+++ b/envytools/rnn/expand.c
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2010 Luca Barbieri <luca@luca-barbieri.com>
+ * Copyright (C) 2010 Marcin Kościelnicki <koriakin@0x04.net>
+ * 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
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS 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.
+ */
+
+#include "rnn.h"
+#include "rnndec.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+
+void expand (const char* prefix, struct rnndelem *elem, uint64_t base, int width, struct rnndeccontext *vc) {
+ int i, j;
+ if(elem->length > 1024)
+ return;
+ if(!rnndec_varmatch(vc, &elem->varinfo))
+ return;
+ switch (elem->type) {
+ case RNN_ETYPE_REG:
+ for(i = 0; i < elem->length; ++i) {
+ if(elem->length >= 2)
+ printf("d %s %08"PRIx64" %s(%i)", prefix, base + elem->offset + i * elem->stride, elem->fullname, i);
+ else
+ printf("d %s %08"PRIx64" %s", prefix, base + elem->offset, elem->fullname);
+
+ printf(" %s\n", elem->typeinfo.name);
+ }
+ break;
+ case RNN_ETYPE_STRIPE:
+ case RNN_ETYPE_ARRAY:
+ for (i = 0; i < elem->length; i++)
+ for (j = 0; j < elem->subelemsnum; j++)
+ expand(prefix, elem->subelems[j], base + elem->offset + i * elem->stride, width, vc);
+ break;
+ default:
+ break;
+ }
+}
+
+int main(int argc, char **argv) {
+ char** argp;
+ rnn_init();
+ struct rnndb *db = rnn_newdb();
+ rnn_parsefile (db, argv[1]);
+ rnn_prepdb (db);
+ struct rnndeccontext *vc = rnndec_newcontext(db);
+ vc->colors = &rnndec_colorsterm;
+ argp = argv + 2;
+ while (*argp && !strcmp (*argp, "-v")) {
+ ++argp;
+ if(!argp[0] || !argp[1])
+ fprintf(stderr, "error: -v option lacking VARSET and VARIANT arguments following it\n");
+ else {
+ rnndec_varadd(vc, argp[0], argp[1]);
+ argp += 2;
+ }
+ }
+ int i, j;
+ for(i = 0; i < db->domainsnum; ++i)
+ for (j = 0; j < db->domains[i]->subelemsnum; ++j)
+ expand (db->domains[i]->name, db->domains[i]->subelems[j], 0, db->domains[i]->width, vc);
+ for(i = 0; i < db->enumsnum; ++i)
+ for (j = 0; j < db->enums[i]->valsnum; ++j)
+ if (db->enums[i]->vals[j]->valvalid)
+ printf("e %s %"PRIx64" %s\n", db->enums[i]->name, db->enums[i]->vals[j]->value, db->enums[i]->vals[j]->name);
+ return 0;
+}
+
diff --git a/envytools/rnn/headergen.c b/envytools/rnn/headergen.c
new file mode 100644
index 0000000..4d2374d
--- /dev/null
+++ b/envytools/rnn/headergen.c
@@ -0,0 +1,323 @@
+/*
+ * Copyright (C) 2010-2011 Marcin Kościelnicki <koriakin@0x04.net>
+ * Copyright (C) 2010 Luca Barbieri <luca@luca-barbieri.com>
+ * 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
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS 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.
+ */
+
+#include "rnn.h"
+#include "util.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <time.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+uint64_t *strides = 0;
+int stridesnum = 0;
+int stridesmax = 0;
+
+int startcol = 64;
+
+struct fout {
+ char *name;
+ FILE *file;
+ char *guard;
+};
+
+struct fout *fouts = 0;
+int foutsnum = 0;
+int foutsmax = 0;
+
+void seekcol (FILE *f, int src, int dst) {
+ if (dst <= src)
+ fprintf (f, "\t");
+ else {
+ int n = dst/8 - src/8;
+ if (n) {
+ while (n--)
+ fprintf (f, "\t");
+ n = dst&7;
+ } else
+ n = dst-src;
+ while (n--)
+ fprintf (f, " ");
+ }
+}
+
+FILE *findfout (char *file) {
+ int i;
+ for (i = 0; i < foutsnum; i++)
+ if (!strcmp(fouts[i].name, file))
+ break;
+ if (i == foutsnum) {
+ fprintf (stderr, "AIII, didn't open file %s.\n", file);
+ exit(1);
+ }
+ return fouts[i].file;
+}
+
+void printdef (char *name, char *suf, int type, uint64_t val, char *file) {
+ FILE *dst = findfout(file);
+ int len;
+ if (suf)
+ fprintf (dst, "#define %s__%s%n", name, suf, &len);
+ else
+ fprintf (dst, "#define %s%n", name, &len);
+ if (type == 0 && val > 0xffffffffull)
+ seekcol (dst, len, startcol-8);
+ else
+ seekcol (dst, len, startcol);
+ switch (type) {
+ case 0:
+ if (val > 0xffffffffull)
+ fprintf (dst, "0x%016"PRIx64"ULL\n", val);
+ else
+ fprintf (dst, "0x%08"PRIx64"\n", val);
+ break;
+ case 1:
+ fprintf (dst, "%"PRIu64"\n", val);
+ break;
+ }
+}
+
+void printvalue (struct rnnvalue *val, int shift) {
+ if (val->varinfo.dead)
+ return;
+ if (val->valvalid)
+ printdef (val->fullname, 0, 0, val->value << shift, val->file);
+}
+
+void printbitfield (struct rnnbitfield *bf, int shift);
+
+void printtypeinfo (struct rnntypeinfo *ti, char *prefix, int shift, char *file) {
+ if (ti->shr)
+ printdef (prefix, "SHR", 1, ti->shr, file);
+ if (ti->minvalid)
+ printdef (prefix, "MIN", 0, ti->min, file);
+ if (ti->maxvalid)
+ printdef (prefix, "MAX", 0, ti->max, file);
+ if (ti->alignvalid)
+ printdef (prefix, "ALIGN", 0, ti->align, file);
+ int i;
+ for (i = 0; i < ti->valsnum; i++)
+ printvalue(ti->vals[i], shift);
+ for (i = 0; i < ti->bitfieldsnum; i++)
+ printbitfield(ti->bitfields[i], shift);
+}
+
+void printbitfield (struct rnnbitfield *bf, int shift) {
+ if (bf->varinfo.dead)
+ return;
+ if (bf->typeinfo.type == RNN_TTYPE_BOOLEAN) {
+ printdef (bf->fullname, 0, 0, bf->mask << shift, bf->file);
+ } else {
+ printdef (bf->fullname, "MASK", 0, bf->mask << shift, bf->file);
+ printdef (bf->fullname, "SHIFT", 1, bf->low + shift, bf->file);
+ }
+ printtypeinfo (&bf->typeinfo, bf->fullname, bf->low + shift, bf->file);
+}
+
+void printdelem (struct rnndelem *elem, uint64_t offset) {
+ if (elem->varinfo.dead)
+ return;
+ if (elem->length != 1)
+ ADDARRAY(strides, elem->stride);
+ if (elem->name) {
+ if (stridesnum) {
+ int len, total;
+ FILE *dst = findfout(elem->file);
+ fprintf (dst, "#define %s(%n", elem->fullname, &total);
+ int i;
+ for (i = 0; i < stridesnum; i++) {
+ if (i) {
+ fprintf(dst, ", ");
+ total += 2;
+ }
+ fprintf (dst, "i%d%n", i, &len);
+ total += len;
+ }
+ fprintf (dst, ")");
+ total++;
+ seekcol (dst, total, startcol-1);
+ fprintf (dst, "(0x%08"PRIx64"", offset + elem->offset);
+ for (i = 0; i < stridesnum; i++)
+ fprintf (dst, " + %#" PRIx64 "*(i%d)", strides[i], i);
+ fprintf (dst, ")\n");
+ } else
+ printdef (elem->fullname, 0, 0, offset + elem->offset, elem->file);
+ if (elem->stride)
+ printdef (elem->fullname, "ESIZE", 0, elem->stride, elem->file);
+ if (elem->length != 1)
+ printdef (elem->fullname, "LEN", 0, elem->length, elem->file);
+ printtypeinfo (&elem->typeinfo, elem->fullname, 0, elem->file);
+ }
+ fprintf (findfout(elem->file), "\n");
+ int j;
+ for (j = 0; j < elem->subelemsnum; j++) {
+ printdelem(elem->subelems[j], offset + elem->offset);
+ }
+ if (elem->length != 1) stridesnum--;
+}
+
+void print_file_info_(FILE *dst, struct stat* sb, struct tm* tm)
+{
+ char timestr[64];
+ strftime(timestr, sizeof(timestr), "%Y-%m-%d %H:%M:%S", tm);
+ fprintf(dst, "(%7Lu bytes, from %s)\n", (unsigned long long)sb->st_size, timestr);
+}
+
+void print_file_info(FILE *dst, const char* file)
+{
+ struct stat sb;
+ struct tm tm;
+ stat(file, &sb);
+ gmtime_r(&sb.st_mtime, &tm);
+ print_file_info_(dst, &sb, &tm);
+}
+
+void printhead(struct fout f, struct rnndb *db) {
+ int i, j;
+ struct stat sb;
+ struct tm tm;
+ stat(f.name, &sb);
+ gmtime_r(&sb.st_mtime, &tm);
+ fprintf (f.file, "#ifndef %s\n", f.guard);
+ fprintf (f.file, "#define %s\n", f.guard);
+ fprintf (f.file, "\n");
+ fprintf(f.file,
+ "/* Autogenerated file, DO NOT EDIT manually!\n"
+ "\n"
+ "This file was generated by the rules-ng-ng headergen tool in this git repository:\n"
+ "http://0x04.net/cgit/index.cgi/rules-ng-ng\n"
+ "git clone git://0x04.net/rules-ng-ng\n"
+ "\n"
+ "The rules-ng-ng source files this header was generated from are:\n");
+ unsigned maxlen = 0;
+ for(i = 0; i < db->filesnum; ++i) {
+ unsigned len = strlen(db->files[i]);
+ if(len > maxlen)
+ maxlen = len;
+ }
+ for(i = 0; i < db->filesnum; ++i) {
+ unsigned len = strlen(db->files[i]);
+ fprintf(f.file, "- %s%*s ", db->files[i], maxlen - len, "");
+ print_file_info(f.file, db->files[i]);
+ }
+ fprintf(f.file,
+ "\n"
+ "Copyright (C) ");
+ if(db->copyright.firstyear && db->copyright.firstyear < (1900 + tm.tm_year))
+ fprintf(f.file, "%u-", db->copyright.firstyear);
+ fprintf(f.file, "%u", 1900 + tm.tm_year);
+ if(db->copyright.authorsnum) {
+ fprintf(f.file, " by the following authors:");
+ for(i = 0; i < db->copyright.authorsnum; ++i) {
+ fprintf(f.file, "\n- ");
+ if(db->copyright.authors[i]->name)
+ fprintf(f.file, "%s", db->copyright.authors[i]->name);
+ if(db->copyright.authors[i]->email)
+ fprintf(f.file, " <%s>", db->copyright.authors[i]->email);
+ if(db->copyright.authors[i]->nicknamesnum) {
+ for(j = 0; j < db->copyright.authors[i]->nicknamesnum; ++j) {
+ fprintf(f.file, "%s%s", (j ? ", " : " ("), db->copyright.authors[i]->nicknames[j]);
+ }
+ fprintf(f.file, ")");
+ }
+ }
+ }
+ fprintf(f.file, "\n");
+ if(db->copyright.license)
+ fprintf(f.file, "\n%s\n", db->copyright.license);
+ fprintf(f.file, "*/\n\n\n");
+}
+
+int main(int argc, char **argv) {
+ struct rnndb *db;
+ int i, j;
+
+ if (argc < 2) {
+ fprintf(stderr, "Usage:\n\theadergen database-file\n");
+ exit(1);
+ }
+
+ rnn_init();
+ db = rnn_newdb();
+ rnn_parsefile (db, argv[1]);
+ rnn_prepdb (db);
+ for(i = 0; i < db->filesnum; ++i) {
+ char *dstname = malloc(strlen(db->files[i]) + 3);
+ char *pretty;
+ strcpy(dstname, db->files[i]);
+ strcat(dstname, ".h");
+ struct fout f = { db->files[i], fopen(dstname, "w") };
+ if (!f.file) {
+ perror(dstname);
+ exit(1);
+ }
+ free(dstname);
+ pretty = strrchr(f.name, '/');
+ if (pretty)
+ pretty += 1;
+ else
+ pretty = f.name;
+ f.guard = strdup(pretty);
+ for (j = 0; j < strlen(f.guard); j++)
+ if (isalnum(f.guard[j]))
+ f.guard[j] = toupper(f.guard[j]);
+ else
+ f.guard[j] = '_';
+ ADDARRAY(fouts, f);
+ printhead(f, db);
+ }
+
+ for (i = 0; i < db->enumsnum; i++) {
+ if (db->enums[i]->isinline)
+ continue;
+ int j;
+ for (j = 0; j < db->enums[i]->valsnum; j++)
+ printvalue (db->enums[i]->vals[j], 0);
+ }
+ for (i = 0; i < db->bitsetsnum; i++) {
+ if (db->bitsets[i]->isinline)
+ continue;
+ int j;
+ for (j = 0; j < db->bitsets[i]->bitfieldsnum; j++)
+ printbitfield (db->bitsets[i]->bitfields[j], 0);
+ }
+ for (i = 0; i < db->domainsnum; i++) {
+ if (db->domains[i]->size)
+ printdef (db->domains[i]->fullname, "SIZE", 0, db->domains[i]->size, db->domains[i]->file);
+ int j;
+ for (j = 0; j < db->domains[i]->subelemsnum; j++) {
+ printdelem(db->domains[i]->subelems[j], 0);
+ }
+ }
+ for(i = 0; i < foutsnum; ++i) {
+ fprintf (fouts[i].file, "\n#endif /* %s */\n", fouts[i].guard);
+ }
+ return db->estatus;
+}
diff --git a/envytools/rnn/lookup.c b/envytools/rnn/lookup.c
new file mode 100644
index 0000000..e8c2937
--- /dev/null
+++ b/envytools/rnn/lookup.c
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2010 Marcin Kościelnicki <koriakin@0x04.net>
+ * Copyright (C) 2011 Martin Peres <martin.peres@ensi-bourges.fr>
+ * Copyright (C) 2011 Witold Waligóra <witold.waligora@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
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS 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.
+ */
+
+#define _GNU_SOURCE // for asprintf
+#include "rnn.h"
+#include "rnndec.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <string.h>
+#include <getopt.h>
+
+void usage()
+{
+ printf ("Usage:\n"
+ "\tlookup [-f file.xml] [-a NVXX] -e enum-name [-- -v attribute value] value\n"
+ "\tlookup [-f file.xml] [-a NVXX] -b bitset-name [-- -v attribute value] value\n"
+ "\tlookup [-f file.xml] [-a NVXX] [-d domain-name] [-- -v attribute value] address\n"
+ "\tlookup [-f file.xml] [-a NVXX] [-d domain-name] [-- -v attribute value] address value\n"
+ );
+ exit(2);
+}
+
+int main(int argc, char **argv) {
+ char *file = "nv_mmio.xml";
+ char *name = "NV_MMIO";
+ char *variant = NULL;
+ int c, mode = 'd';
+ uint64_t reg, colors=1, val = 0;
+ struct rnndeccontext *vc;
+
+ rnn_init();
+ if (argc < 2) {
+ usage();
+ }
+ struct rnndb *db = rnn_newdb();
+
+ /* Arguments parsing */
+ while ((c = getopt (argc, argv, "f:a:d:e:b:c")) != -1) {
+ switch (c) {
+ case 'f':
+ file = strdup(optarg);
+ break;
+ case 'e':
+ mode = 'e';
+ name = strdup(optarg);
+ break;
+ case 'b':
+ mode = 'b';
+ name = strdup(optarg);
+ break;
+ case 'd':
+ mode = 'd';
+ name = strdup(optarg);
+ break;
+ case 'a':
+ if (!strncasecmp(optarg, "NV", 2))
+ variant = strdup(optarg);
+ else
+ asprintf(&variant, "NV%s", optarg);
+ break;
+ case 'c':
+ colors = 0;
+ break;
+ default: usage();
+ }
+ }
+
+ rnn_parsefile (db, file);
+ rnn_prepdb (db);
+ vc = rnndec_newcontext(db);
+ if(colors)
+ vc->colors = &envy_def_colors;
+
+ if (variant)
+ rnndec_varadd(vc, "chipset", variant);
+
+ /* Parse extra arguments */
+ while (!strcmp (argv[optind], "-v")) {
+ rnndec_varadd(vc, argv[optind+1], argv[optind+2]);
+ optind+=3;
+ }
+
+ if (optind >= argc) {
+ fprintf (stderr, "No address specified.\n");
+ return 1;
+ }
+
+ reg = strtoull(argv[optind], 0, 16);
+ if (optind + 1 < argc)
+ val = strtoull(argv[optind + 1], 0, 16);
+
+ if (mode == 'e') {
+ struct rnnenum *en = rnn_findenum (db, name);
+ if (en) {
+ int i;
+ int dec = 0;
+ for (i = 0; i < en->valsnum; i++)
+ if (en->vals[i]->valvalid && en->vals[i]->value == reg) {
+ printf ("%s\n", en->vals[i]->name);
+ dec = 1;
+ break;
+ }
+ if (!dec)
+ printf ("%#"PRIx64"\n", reg);
+
+ return 0;
+ } else {
+ fprintf(stderr, "Not an enum: '%s'\n", name);
+ return 1;
+ }
+ } else if (mode == 'b') {
+ struct rnnbitset *bs = rnn_findbitset (db, name);
+
+ if (bs) {
+ printf("TODO\n");
+ return 0;
+ } else {
+ fprintf(stderr, "Not a bitset: '%s'\n", name);
+ return 1;
+ }
+
+ } else if (mode == 'd') {
+ struct rnndomain *dom = rnn_finddomain (db, name);
+
+ if (dom) {
+ struct rnndecaddrinfo *info = rnndec_decodeaddr(vc, dom, reg, 0);
+ if (info && info->typeinfo)
+ printf ("%s => %s\n", info->name, rnndec_decodeval(vc, info->typeinfo, val, info->width));
+ else if (info)
+ printf ("%s\n", info->name);
+ else
+ return 1;
+ return 0;
+ } else {
+ fprintf(stderr, "Not a domain: '%s'\n", name);
+ return 1;
+ }
+ } else {
+ return 1;
+ }
+}
diff --git a/envytools/rnn/renouveau2rnn b/envytools/rnn/renouveau2rnn
new file mode 100755
index 0000000..bc58172
--- /dev/null
+++ b/envytools/rnn/renouveau2rnn
@@ -0,0 +1,289 @@
+#!/usr/bin/python
+import sys
+import os
+import subprocess
+from lxml import etree as ET
+tree = ET.parse("renouveau.xml")
+root = tree.getroot();
+
+try:
+ os.mkdir("renouveau")
+except:
+ pass
+
+children = {}
+
+for obj in root:
+ if obj.tag != "object":
+ continue
+ if "name" in obj.attrib:
+ if obj.attrib["name"] == "NV34TCL":
+ obj.attrib["name"] = "NV30TCL"
+ obj.attrib["id"] = "0x0397"
+ elif obj.attrib["name"] == "NV30TCL":
+ obj.attrib["name"] = "NV34TCL"
+ obj.attrib["id"] = "0x0697"
+ obj.attrib["parent"] = "0x0497"
+ elif obj.attrib["name"] == "NV35TCL":
+ obj.attrib["parent"] = "0x0397"
+
+ if "id" in obj.attrib and "parent" in obj.attrib:
+ children.setdefault(int(obj.attrib["parent"], 0), []).append(obj)
+
+def get_all_children(obj):
+ objid = int(obj.attrib.get("id"), 0)
+ if objid not in children:
+ return []
+ cs = children[objid]
+ cs += sum([get_all_children(c) for c in cs if "id" in c.attrib], [])
+ cd = {}
+ for c in cs:
+ cd[c.attrib["name"]] = c
+ cn = cd.keys()
+ cn.sort()
+ return [cd[n] for n in cn]
+
+for filename, tclnames in [("nv10-20tcl", ("NV10TCL", "NV20TCL")), ("nv30-40tcl", ("NV30TCL", "NV40TCL")), ("nv50tcl", ("NV50TCL",))]:
+ tcls = [None for i in tclnames]
+ for obj in root:
+ if obj.tag != "object":
+ continue
+ for i in xrange(len(tclnames)):
+ if obj.get("name") == tclnames[i]:
+ if obj.get("parent"):
+ print "ERROR:", tclnames[i], "has a parent"
+ sys.exit(1)
+ tcls[i] = obj
+
+ subtcls = [[tcl] + get_all_children(tcl) for tcl in tcls]
+ alltcls = sum(subtcls, [])
+ inftcls = sum([get_all_children(tcl) for tcl in tcls], [])
+
+ if len(alltcls) > 1:
+ allvariants = alltcls[0].attrib["name"] + "-" + alltcls[-1].attrib["name"]
+ else:
+ allvariants = alltcls[0].attrib["name"]
+
+ variants = [st[0].attrib["name"] + "-" + st[-1].attrib["name"] for st in subtcls]
+ infvariants = []
+ for tcl in inftcls:
+ sit = [tcl] + get_all_children(tcl)
+ if len(sit) > 1:
+ infvariants.append(sit[0].attrib["name"] + "-" + sit[-1].attrib["name"])
+ else:
+ infvariants.append(sit[0].attrib["name"])
+
+ def get_regs(tcl):
+ regs = {}
+ for i in tcl.iterchildren(tag=ET.Element):
+ assert i.tag == "reg32"
+ if "offset" in i.attrib:
+ regs[int(i.attrib["offset"], 0)] = i
+ return regs
+
+ def fix_field_name(fname):
+ return fname.replace("MAGNIFY", "MAG").replace("MINIFY", "MIN")
+
+ def get_fields(reg32):
+ fields = {}
+ for i in reg32.iterchildren(tag=ET.Element):
+ assert i.tag == "bitfield"
+ fields[int(i.get("low"))] = i
+ return fields
+
+ dicts = [get_regs(tcl) for tcl in tcls]
+ infdicts = [get_regs(tcl) for tcl in inftcls]
+
+ common = ET.Element("object")
+ common.text = ""
+
+ for tcl in tcls:
+ for reg32 in tcl:
+ if reg32.tail:
+ reg32.tail = "\n "
+
+ all_offsets = [[int(r.attrib["offset"], 0) for r in tcl.iterchildren(tag=ET.Element) if "offset" in r.attrib] for tcl in alltcls]
+ all_offsets = list(set(sum(all_offsets, [])))
+ all_offsets.sort()
+
+ def rnn_fix(r):
+ if "enum_name" in r.attrib:
+ r.attrib["type"] = r.attrib["enum_name"]
+ del r.attrib["enum_name"]
+ if "low" in r.attrib and "high" in r.attrib and r.attrib["low"] == r.attrib["high"] and r.attrib.get("type") == "boolean":
+ del r.attrib["type"]
+ if "size" in r.attrib:
+ r.attrib["length"] = r.attrib["size"]
+ del r.attrib["size"]
+ if r.attrib.get("type") in ("enum", "bitfield", "hexa"):
+ del r.attrib["type"]
+
+ for offset in all_offsets:
+ if offset == 0x50: # REF_CNT
+ continue
+
+ regs = [d.get(offset) for d in dicts]
+ if any([r is not None for r in regs]):
+ candnames = [r.get("name") for r in regs if r is not None and "name" in r.attrib]
+
+ if not candnames:
+ continue
+
+ # if name == "VIEWPORT_CLIP_HORIZ" or name == "VIEWPORT_CLIP_VERT":
+ # these have bitfields defined on nv30 but not nv40
+ if tclnames[0] == "NV34TCL" and offset in (0x2c0, 0x2c4):
+ regs[1] = ET.fromstring(ET.tostring(regs[0]))
+
+ for i in xrange(len(regs)):
+ if regs[i] is not None:
+ if regs[i] in tcls[i]:
+ tcls[i].remove(regs[i])
+ common.append(regs[i])
+ rnn_fix(regs[i])
+
+ unify = False
+ while len(regs) > 1:
+ if not all([r is not None for r in regs]):
+ break
+
+ # these must not be unified (same offset, different meanings)
+ if tclnames[0] == "NV34TCL" and offset in (0x370, 0x1840, 0x22c, 0x400):
+ break
+
+ diff = 0
+
+ deep = False
+ if regs[0].attrib.get("type") == regs[1].attrib.get("type") and regs[0].attrib.get("stride") == regs[1].attrib.get("stride"):
+ deep = True
+
+ if not deep:
+ s = None
+ for i in xrange(len(regs)):
+ r = ET.fromstring(ET.tostring(regs[i]))
+ r.attrib["name"] = ""
+ if s == None:
+ s = ET.tostring(r).strip()
+ elif ET.tostring(r).strip() != s:
+ diff += 1
+ if diff:
+ break
+ else:
+ field_dicts = [get_fields(reg) for reg in regs]
+ field_list = list(set(sum([[int(f.attrib.get("low", -1)) for f in r] for r in regs], [])))
+ field_list.sort()
+ creg = regs[0]
+ creg.text = "\n\t\t"
+ creg.attrib["offset"] = str(offset)
+ if "size" in regs[0].attrib or "size" in regs[1].attrib:
+ size0 = int(regs[0].attrib["size"]) if "size" in regs[0].attrib else 0
+ size1 = int(regs[1].attrib["size"]) if "size" in regs[1].attrib else 0
+ creg.attrib["size"] = str(size1 if size1 > size0 else size0)
+ if "stride" in regs[0].attrib or "stride" in regs[1].attrib:
+ assert regs[0].attrib["stride"] == regs[1].attrib["stride"]
+ creg.attrib["stride"] = regs[0].attrib["stride"]
+ creg.tail = "\n "
+ prev = None
+ cfields = []
+ #print >> sys.stderr, "NAME " + name
+ for foffset in field_list:
+ fields = [f.get(foffset) for f in field_dicts]
+
+ for i in xrange(len(fields)):
+ if fields[i] is not None:
+ regs[i].remove(fields[i])
+ creg.append(fields[i])
+ fields[i].tail ="\n\t\t"
+
+ funify = False
+ if all([f is not None for f in fields]):
+ s0 = fix_field_name(ET.tostring(fields[0]).strip())
+ s1 = fix_field_name(ET.tostring(fields[1]).strip())
+# if "nv04_tx_wrap" in s0:
+# s0 = s0.replace("nv04_tx_wrap", "nv40_texture_wrap")
+# s0 = s0.replace("high=\"7\"", "high=\"3\"")
+ if s0 == s1:
+ funify = True
+ for i in xrange(len(fields)):
+ if fields[i] is not None:
+ fields[i].attrib["variants"] = variants[i]
+
+ if funify:
+ fname = None
+ fcandnames = [f.attrib["name"] for f in fields if f is not None and "name" in f.attrib]
+ fname = None
+ if fcandnames:
+ fname = fcandnames[0]
+ #print >> sys.stderr, "FNAME " + fname
+ fields[0].attrib["name"] = fix_field_name(fname)
+ del fields[0].attrib["variants"]
+ creg.remove(fields[1])
+
+ unify = True
+ break
+
+ unify = True
+ break
+
+ for i in xrange(len(regs)):
+ if regs[i] is not None:
+ if variants[i] != allvariants:
+ regs[i].attrib["variants"] = variants[i]
+ regs[i].tail = "\n "
+ rnn_fix(regs[i])
+ for f in regs[i].iterchildren(tag=ET.Element):
+ rnn_fix(f)
+
+ if unify:
+ name = None
+ if candnames:
+ name = candnames[0]
+ if name:
+ regs[0].attrib["name"] = name
+ del regs[0].attrib["variants"]
+ if regs[1] is not None:
+ common.remove(regs[1])
+ # no unification for inftcls, it's not necessary and N-way unification is much more complicated
+ infregs = [d.get(offset) for d in infdicts]
+
+ for i in xrange(len(regs)):
+ if infregs[i] is not None:
+ if infregs[i] in inftcls[i]:
+ inftcls[i].remove(infregs[i])
+ infregs[i].attrib["variants"] = infvariants[i]
+ common.append(infregs[i])
+ rnn_fix(infregs[i])
+
+ common.tag = "stripe"
+ common.attrib["prefix"] = "obj-class"
+ common.attrib["variants"] = allvariants
+
+ colon = "39584ac56e6d0976692778b80915f94b61767814a8704982"
+ database = ET.Element("database")
+ database.attrib["xmlns"] = "http://nouveau.freedesktop.org/"
+ database.attrib["xmlns" + colon + "xsi"] = "http://www.w3.org/2001/XMLSchema-instance"
+ database.attrib["xsi" + colon + "schemaLocation"] = "http://nouveau.freedesktop.org/ rules-ng.xsd"
+
+ objenum = ET.Element("enum")
+ objenum.attrib["bare"] = "yes"
+ objenum.attrib["name"] = "obj-class"
+
+ for tcl in alltcls:
+ objvalue = ET.Element("value")
+ objvalue.attrib["value"] = tcl.attrib["id"]
+ objvalue.attrib["name"] = tcl.attrib["name"]
+ objenum.append(objvalue)
+
+ database.append(objenum)
+
+ domain = ET.Element("domain")
+ domain.attrib["name"] = "NV01_SUBCHAN"
+ domain.attrib["bare"] = "yes"
+ domain.attrib["size"] = "0x2000"
+ domain.append(common)
+ database.append(domain)
+
+ outfile = open("renouveau/" + filename, "w")
+ xml2text = subprocess.Popen("./xml2text", stdin = subprocess.PIPE, stdout = outfile)
+ xml2text.communicate(ET.tostring(database).replace(colon, ":"))
+ xml2text.wait()
+ outfile.close()
diff --git a/envytools/rnn/rnn.c b/envytools/rnn/rnn.c
new file mode 100644
index 0000000..694bc7c
--- /dev/null
+++ b/envytools/rnn/rnn.c
@@ -0,0 +1,1295 @@
+/*
+ * 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
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS 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.
+ */
+
+#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"
+
+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);
+}
+
+void rnn_init() {
+ LIBXML_TEST_VERSION
+ xmlInitParser();
+}
+
+struct rnndb *rnn_newdb() {
+ 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) {
+ fprintf (stderr, "%s:%d: unknown attribute child \"%s\" in attribute \"%s\"\n", file, line, chain->name, attr->name);
+ db->estatus = 1;
+ } 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;
+ fprintf (stderr, "%s:%d: invalid boolean value \"%s\" in attribute \"%s\"\n", file, line, c, attr->name);
+ db->estatus = 1;
+ return 0;
+}
+
+static uint64_t getnumattrib (struct rnndb *db, char *file, int line, xmlAttr *attr) {
+ char *c = getattrib(db, file, line, attr);
+ 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) {
+ fprintf (stderr, "%s:%d: invalid numeric value \"%s\" in attribute \"%s\"\n", file, line, c, attr->name);
+ db->estatus = 1;
+ }
+ return res;
+}
+
+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;
+ }
+ 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 if (!strcmp(attr->name, "brief")) {
+ // TODO
+ } else {
+ fprintf (stderr, "%s:%d: wrong attribute \"%s\" for value\n", file, node->line, attr->name);
+ db->estatus = 1;
+ }
+ 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)) {
+ fprintf (stderr, "%s:%d: wrong tag in %s: <%s>\n", file, chain->line, node->name, chain->name);
+ db->estatus = 1;
+ }
+ chain = chain->next;
+ }
+ if (!val->name) {
+ fprintf (stderr, "%s:%d: nameless value\n", file, node->line);
+ db->estatus = 1;
+ 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)) {
+ fprintf (stderr, "%s:%d: wrong attribute \"%s\" for spectype\n", file, node->line, attr->name);
+ db->estatus = 1;
+ }
+ attr = attr->next;
+ }
+ if (!res->name) {
+ fprintf (stderr, "%s:%d: nameless spectype\n", file, node->line);
+ db->estatus = 1;
+ return;
+ }
+ for (i = 0; i < db->spectypesnum; i++)
+ if (!strcmp(db->spectypes[i]->name, res->name)) {
+ fprintf (stderr, "%s:%d: duplicated spectype name %s\n", file, node->line, res->name);
+ db->estatus = 1;
+ 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)) {
+ fprintf (stderr, "%s:%d: wrong tag in spectype: <%s>\n", file, chain->line, chain->name);
+ db->estatus = 1;
+ }
+ 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 if (!strcmp(attr->name, "brief")) {
+ // TODO
+ } else {
+ fprintf (stderr, "%s:%d: wrong attribute \"%s\" for enum\n", file, node->line, attr->name);
+ db->estatus = 1;
+ }
+ attr = attr->next;
+ }
+ if (!name) {
+ fprintf (stderr, "%s:%d: nameless enum\n", file, node->line);
+ db->estatus = 1;
+ 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) {
+ fprintf (stderr, "%s:%d: merge fail for enum %s\n", file, node->line, node->name);
+ db->estatus = 1;
+ }
+ } 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)) {
+ fprintf (stderr, "%s:%d: wrong tag in enum: <%s>\n", file, chain->line, chain->name);
+ db->estatus = 1;
+ }
+ 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;
+ int highok = 0, lowok = 0;
+ while (attr) {
+ if (!strcmp(attr->name, "name")) {
+ bf->name = strdup(getattrib(db, file, node->line, attr));
+ } else if (!strcmp(attr->name, "high")) {
+ bf->high = getnumattrib(db, file, node->line, attr);
+ highok = 1;
+ } else if (!strcmp(attr->name, "low")) {
+ bf->low = getnumattrib(db, file, node->line, attr);
+ lowok = 1;
+ } else if (!strcmp(attr->name, "pos")) {
+ bf->high = bf->low = getnumattrib(db, file, node->line, attr);
+ lowok = highok = 1;
+ } 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 (!strcmp(attr->name, "brief")) {
+ // TODO
+ } else if (!trytypeattr(db, file, node, attr, &bf->typeinfo)) {
+ fprintf (stderr, "%s:%d: wrong attribute \"%s\" for bitfield\n", file, node->line, attr->name);
+ db->estatus = 1;
+ }
+ 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)) {
+ fprintf (stderr, "%s:%d: wrong tag in %s: <%s>\n", file, chain->line, node->name, chain->name);
+ db->estatus = 1;
+ }
+ chain = chain->next;
+ }
+ if (!bf->name) {
+ fprintf (stderr, "%s:%d: nameless bitfield\n", file, node->line);
+ db->estatus = 1;
+ return 0;
+ } else if (!highok || !lowok || bf->high < bf->low) {
+ fprintf (stderr, "%s:%d: bitfield has wrong placement\n", file, node->line);
+ db->estatus = 1;
+ 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 if (!strcmp(attr->name, "brief")) {
+ // TODO
+ } else {
+ fprintf (stderr, "%s:%d: wrong attribute \"%s\" for bitset\n", file, node->line, attr->name);
+ db->estatus = 1;
+ }
+ attr = attr->next;
+ }
+ if (!name) {
+ fprintf (stderr, "%s:%d: nameless bitset\n", file, node->line);
+ db->estatus = 1;
+ 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) {
+ fprintf (stderr, "%s:%d: merge fail for bitset %s\n", file, node->line, node->name);
+ db->estatus = 1;
+ }
+ } 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)) {
+ fprintf (stderr, "%s:%d: wrong tag in bitset: <%s>\n", file, chain->line, chain->name);
+ db->estatus = 1;
+ }
+ 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 {
+ fprintf (stderr, "%s:%d: wrong attribute \"%s\" for %s\n", file, node->line, attr->name, node->name);
+ db->estatus = 1;
+ }
+ attr = attr->next;
+ }
+ if (!res->name) {
+ fprintf (stderr, "%s:%d: nameless use-group\n", file, node->line);
+ db->estatus = 1;
+ 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, "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, "brief")) {
+ // TODO
+ } else {
+ fprintf (stderr, "%s:%d: wrong attribute \"%s\" for %s\n", file, node->line, attr->name, node->name);
+ db->estatus = 1;
+ }
+ 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)) {
+ fprintf (stderr, "%s:%d: wrong tag in %s: <%s>\n", file, chain->line, node->name, chain->name);
+ db->estatus = 1;
+ }
+ 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;
+ 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 (!strcmp(attr->name, "brief")) {
+ // TODO
+ } else if (!strcmp(attr->name, "value")) {
+ // TODO
+ } else if (!trytypeattr(db, file, node, attr, &res->typeinfo)) {
+ fprintf (stderr, "%s:%d: wrong attribute \"%s\" for register\n", file, node->line, attr->name);
+ db->estatus = 1;
+ }
+ 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)) {
+ fprintf (stderr, "%s:%d: wrong tag in %s: <%s>\n", file, chain->line, node->name, chain->name);
+ db->estatus = 1;
+ }
+ chain = chain->next;
+ }
+ if (!res->name) {
+ fprintf (stderr, "%s:%d: nameless register\n", file, node->line);
+ db->estatus = 1;
+ 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 {
+ fprintf (stderr, "%s:%d: wrong attribute \"%s\" for group\n", file, node->line, attr->name);
+ db->estatus = 1;
+ }
+ attr = attr->next;
+ }
+ if (!name) {
+ fprintf (stderr, "%s:%d: nameless group\n", file, node->line);
+ db->estatus = 1;
+ 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)) {
+ fprintf (stderr, "%s:%d: wrong tag in group: <%s>\n", file, chain->line, chain->name);
+ db->estatus = 1;
+ }
+ 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 {
+ fprintf (stderr, "%s:%d: wrong attribute \"%s\" for domain\n", file, node->line, attr->name);
+ db->estatus = 1;
+ }
+ attr = attr->next;
+ }
+ if (!name) {
+ fprintf (stderr, "%s:%d: nameless domain\n", file, node->line);
+ db->estatus = 1;
+ 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)) {
+ fprintf (stderr, "%s:%d: merge fail for domain %s\n", file, node->line, node->name);
+ db->estatus = 1;
+ } 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)) {
+ fprintf (stderr, "%s:%d: wrong tag in domain: <%s>\n", file, chain->line, chain->name);
+ db->estatus = 1;
+ }
+ 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 {
+ fprintf (stderr, "%s:%d: wrong attribute \"%s\" for copyright\n", file, node->line, attr->name);
+ db->estatus = 1;
+ }
+ 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 {
+ fprintf (stderr, "%s:%d: wrong attribute \"%s\" for author\n", file, chain->line, authorattr->name);
+ db->estatus = 1;
+ }
+ 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 {
+ fprintf (stderr, "%s:%d: wrong attribute \"%s\" for nick\n", file, authorchild->line, nickattr->name);
+ db->estatus = 1;
+ }
+ nickattr = nickattr->next;
+ }
+ if(!nickname) {
+ fprintf (stderr, "%s:%d: missing \"name\" attribute for nick\n", file, authorchild->line);
+ db->estatus = 1;
+ } else
+ ADDARRAY(author->nicknames, nickname);
+ } else {
+ fprintf (stderr, "%s:%d: wrong tag in author: <%s>\n", file, authorchild->line, authorchild->name);
+ db->estatus = 1;
+ }
+ authorchild = authorchild->next;
+ }
+ ADDARRAY(copyright->authors, author);
+ } else {
+ fprintf (stderr, "%s:%d: wrong tag in copyright: <%s>\n", file, chain->line, chain->name);
+ db->estatus = 1;
+ }
+ 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 {
+ fprintf (stderr, "%s:%d: wrong attribute \"%s\" for import\n", file, node->line, attr->name);
+ db->estatus = 1;
+ }
+ attr = attr->next;
+ }
+ if (!subfile) {
+ fprintf (stderr, "%s:%d: missing \"file\" attribute for import\n", file, node->line);
+ db->estatus = 1;
+ } else {
+ rnn_parsefile(db, subfile);
+ }
+ return 1;
+ } else if (!strcmp(node->name, "copyright")) {
+ parsecopyright(db, file, node);
+ return 1;
+ }
+ return 0;
+}
+
+void rnn_parsefile (struct rnndb *db, char *file_orig) {
+ int i;
+ char *fname;
+ const char *rnn_path = getenv("RNN_PATH");
+
+ 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);
+ db->estatus = 1;
+ return;
+ }
+ fclose(file);
+
+ for (i = 0; i < db->filesnum; i++)
+ if (!strcmp(db->files[i], fname))
+ return;
+
+ ADDARRAY(db->files, fname);
+ xmlDocPtr doc = xmlParseFile(fname);
+ if (!doc) {
+ fprintf (stderr, "%s: couldn't open database file. Please set the env var RNN_PATH.\n", fname);
+ db->estatus = 1;
+ return;
+ }
+ xmlNode *root = doc->children;
+ while (root) {
+ if (root->type != XML_ELEMENT_NODE) {
+ } else if (strcmp(root->name, "database")) {
+ fprintf (stderr, "%s:%d: wrong top-level tag <%s>\n", fname, root->line, root->name);
+ db->estatus = 1;
+ } else {
+ xmlNode *chain = root->children;
+ while (chain) {
+ if (chain->type != XML_ELEMENT_NODE) {
+ } else if (!trytop(db, fname, chain) && !trydoc(db, fname, chain)) {
+ fprintf (stderr, "%s:%d: wrong tag in database: <%s>\n", fname, chain->line, chain->name);
+ db->estatus = 1;
+ }
+ 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->min = src->min;
+ dst->max = src->max;
+ dst->align = src->align;
+ 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->low = bf->low;
+ res->high = bf->high;
+ 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));
+ 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;
+ fprintf (stderr, "Cannot find variant %s in enum %s!\n", name, en->name);
+ db->estatus = 1;
+ 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) {
+ fprintf (stderr, "%s: tried to use variants without active varset!\n", what);
+ db->estatus = 1;
+ 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, int width, 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);
+ struct rnndomain *dom = rnn_finddomain (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 (dom) {
+ ti->type = RNN_TTYPE_DOMAIN;
+ ti->domain = dom;
+ } 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, "fixedp")) {
+ ti->type = RNN_TTYPE_FIXEDP;
+ } else {
+ ti->type = RNN_TTYPE_HEX;
+ fprintf (stderr, "%s: unknown type %s\n", prefix, ti->name);
+ db->estatus = 1;
+ }
+ } 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 (width == 1) {
+ ti->name = "boolean";
+ ti->type = RNN_TTYPE_BOOLEAN;
+ } else {
+ ti->name = "hex";
+ ti->type = RNN_TTYPE_HEX;
+ }
+ 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;
+ if (bf->high == 63)
+ bf->mask = - (1ULL<<bf->low);
+ else
+ bf->mask = (1ULL<<(bf->high+1)) - (1ULL<<bf->low);
+ preptypeinfo(db, &bf->typeinfo, bf->fullname, &bf->varinfo, bf->high - bf->low + 1, 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 {
+ fprintf (stderr, "group %s not found!\n", elem->name);
+ db->estatus = 1;
+ }
+ 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) {
+ fprintf (stderr, "%s has non-1 length, but no stride!\n", elem->fullname);
+ db->estatus = 1;
+ } else {
+ elem->stride = elem->width/width;
+ }
+ }
+ preptypeinfo(db, &elem->typeinfo, elem->name?elem->fullname:prefix, &elem->varinfo, elem->width, 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, 32, 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;
+}
diff --git a/envytools/rnn/rnn_path.h.in b/envytools/rnn/rnn_path.h.in
new file mode 100644
index 0000000..ff5c70d
--- /dev/null
+++ b/envytools/rnn/rnn_path.h.in
@@ -0,0 +1 @@
+#define RNN_DEF_PATH "${CMAKE_SOURCE_DIR}/rnndb:${CMAKE_INSTALL_PREFIX}/share/rnndb"
diff --git a/envytools/rnn/rnncheck.c b/envytools/rnn/rnncheck.c
new file mode 100644
index 0000000..0075c7f
--- /dev/null
+++ b/envytools/rnn/rnncheck.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2012 Marcin Kościelnicki <koriakin@0x04.net>
+ * 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
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS 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.
+ */
+
+#include "rnn.h"
+#include "rnndec.h"
+#include <stdio.h>
+
+void usage()
+{
+ printf ("Usage:\n"
+ "\trnncheck file.xml\n"
+ );
+ exit(2);
+}
+
+int main(int argc, char **argv) {
+ rnn_init();
+ if (argc < 2) {
+ usage();
+ }
+ struct rnndb *db = rnn_newdb();
+ rnn_parsefile (db, argv[1]);
+ rnn_prepdb (db);
+ return db->estatus;
+}
diff --git a/envytools/rnn/rnndec.c b/envytools/rnn/rnndec.c
new file mode 100644
index 0000000..862dfe0
--- /dev/null
+++ b/envytools/rnn/rnndec.c
@@ -0,0 +1,317 @@
+/*
+ * Copyright (C) 2010-2011 Marcin Kościelnicki <koriakin@0x04.net>
+ * Copyright (C) 2010 Francisco Jerez <currojerez@riseup.net>
+ * 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
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS 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.
+ */
+
+#define _GNU_SOURCE // for asprintf
+#include "rnndec.h"
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include "util.h"
+
+struct rnndeccontext *rnndec_newcontext(struct rnndb *db) {
+ struct rnndeccontext *res = calloc (sizeof *res, 1);
+ res->db = db;
+ res->colors = &envy_null_colors;
+ return res;
+}
+
+int rnndec_varadd(struct rnndeccontext *ctx, char *varset, char *variant) {
+ struct rnnenum *en = rnn_findenum(ctx->db, varset);
+ if (!en) {
+ fprintf (stderr, "Enum %s doesn't exist in database!\n", varset);
+ return 0;
+ }
+ int i;
+ for (i = 0; i < en->valsnum; i++)
+ if (!strcasecmp(en->vals[i]->name, variant)) {
+ struct rnndecvariant *ci = calloc (sizeof *ci, 1);
+ ci->en = en;
+ ci->variant = i;
+ ADDARRAY(ctx->vars, ci);
+ return 1;
+ }
+ fprintf (stderr, "Variant %s doesn't exist in enum %s!\n", variant, varset);
+ return 0;
+}
+
+int rnndec_varmatch(struct rnndeccontext *ctx, struct rnnvarinfo *vi) {
+ if (vi->dead)
+ return 0;
+ int i;
+ for (i = 0; i < vi->varsetsnum; i++) {
+ int j;
+ for (j = 0; j < ctx->varsnum; j++)
+ if (vi->varsets[i]->venum == ctx->vars[j]->en)
+ break;
+ if (j == ctx->varsnum) {
+ fprintf (stderr, "I don't know which %s variant to use!\n", vi->varsets[i]->venum->name);
+ } else {
+ if (!vi->varsets[i]->variants[ctx->vars[j]->variant])
+ return 0;
+ }
+ }
+ return 1;
+}
+
+char *rnndec_decodeval(struct rnndeccontext *ctx, struct rnntypeinfo *ti, uint64_t value, int width) {
+ char *res = 0;
+ int i;
+ struct rnnvalue **vals;
+ int valsnum;
+ struct rnnbitfield **bitfields;
+ int bitfieldsnum;
+ char *tmp;
+ uint64_t mask;
+ if (!ti)
+ goto failhex;
+ if (ti->shr) value <<= ti->shr;
+ switch (ti->type) {
+ case RNN_TTYPE_ENUM:
+ vals = ti->eenum->vals;
+ valsnum = ti->eenum->valsnum;
+ goto doenum;
+ case RNN_TTYPE_INLINE_ENUM:
+ vals = ti->vals;
+ valsnum = ti->valsnum;
+ goto doenum;
+ doenum:
+ for (i = 0; i < valsnum; i++)
+ if (rnndec_varmatch(ctx, &vals[i]->varinfo) && vals[i]->valvalid && vals[i]->value == value) {
+ asprintf (&res, "%s%s%s", ctx->colors->eval, vals[i]->name, ctx->colors->reset);
+ return res;
+ }
+ goto failhex;
+ case RNN_TTYPE_BITSET:
+ bitfields = ti->ebitset->bitfields;
+ bitfieldsnum = ti->ebitset->bitfieldsnum;
+ goto dobitset;
+ case RNN_TTYPE_INLINE_BITSET:
+ bitfields = ti->bitfields;
+ bitfieldsnum = ti->bitfieldsnum;
+ goto dobitset;
+ dobitset:
+ mask = 0;
+ for (i = 0; i < bitfieldsnum; i++) {
+ if (!rnndec_varmatch(ctx, &bitfields[i]->varinfo))
+ continue;
+ uint64_t sval = (value & bitfields[i]->mask) >> bitfields[i]->low;
+ mask |= bitfields[i]->mask;
+ if (bitfields[i]->typeinfo.type == RNN_TTYPE_BOOLEAN) {
+ if (sval == 0)
+ continue;
+ else if (sval == 1) {
+ if (!res)
+ asprintf (&res, "%s%s%s", ctx->colors->mod, bitfields[i]->name, ctx->colors->reset);
+ else {
+ asprintf (&tmp, "%s | %s%s%s", res, ctx->colors->mod, bitfields[i]->name, ctx->colors->reset);
+ free(res);
+ res = tmp;
+ }
+ continue;
+ }
+ }
+ char *subval = rnndec_decodeval(ctx, &bitfields[i]->typeinfo, sval, bitfields[i]->high - bitfields[i]->low + 1);
+ if (!res)
+ asprintf (&res, "%s%s%s = %s", ctx->colors->rname, bitfields[i]->name, ctx->colors->reset, subval);
+ else {
+ asprintf (&tmp, "%s | %s%s%s = %s", res, ctx->colors->rname, bitfields[i]->name, ctx->colors->reset, subval);
+ free(res);
+ res = tmp;
+ }
+ free(subval);
+ }
+ if (value & ~mask) {
+ if (!res)
+ asprintf (&res, "%s%#"PRIx64"%s", ctx->colors->err, value & ~mask, ctx->colors->reset);
+ else {
+ asprintf (&tmp, "%s | %s%#"PRIx64"%s", res, ctx->colors->err, value & ~mask, ctx->colors->reset);
+ free(res);
+ res = tmp;
+ }
+ }
+ if (!res)
+ asprintf (&res, "%s0%s", ctx->colors->num, ctx->colors->reset);
+ asprintf (&tmp, "{ %s }", res);
+ free(res);
+ return tmp;
+ case RNN_TTYPE_SPECTYPE:
+ return rnndec_decodeval(ctx, &ti->spectype->typeinfo, value, width);
+ case RNN_TTYPE_HEX:
+ asprintf (&res, "%s%#"PRIx64"%s", ctx->colors->num, value, ctx->colors->reset);
+ return res;
+ case RNN_TTYPE_UINT:
+ asprintf (&res, "%s%"PRIu64"%s", ctx->colors->num, value, ctx->colors->reset);
+ return res;
+ case RNN_TTYPE_INT:
+ if (value & UINT64_C(1) << (width-1))
+ asprintf (&res, "%s-%"PRIi64"%s", ctx->colors->num, (UINT64_C(1) << width) - value, ctx->colors->reset);
+ else
+ asprintf (&res, "%s%"PRIi64"%s", ctx->colors->num, value, ctx->colors->reset);
+ return res;
+ case RNN_TTYPE_BOOLEAN:
+ if (value == 0) {
+ asprintf (&res, "%sFALSE%s", ctx->colors->eval, ctx->colors->reset);
+ return res;
+ } else if (value == 1) {
+ asprintf (&res, "%sTRUE%s", ctx->colors->eval, ctx->colors->reset);
+ return res;
+ }
+ case RNN_TTYPE_FLOAT: {
+ union { uint64_t i; float f; double d; } val;
+ val.i = value;
+ if (width == 64)
+ asprintf(&res, "%s%f%s", ctx->colors->num,
+ val.d, ctx->colors->reset);
+ else if (width == 32)
+ asprintf(&res, "%s%f%s", ctx->colors->num,
+ val.f, ctx->colors->reset);
+ else
+ goto failhex;
+
+ return res;
+ }
+ failhex:
+ default:
+ asprintf (&res, "%s%#"PRIx64"%s", ctx->colors->num, value, ctx->colors->reset);
+ return res;
+ break;
+ }
+}
+
+static char *appendidx (struct rnndeccontext *ctx, char *name, uint64_t idx) {
+ char *res;
+ asprintf (&res, "%s[%s%#"PRIx64"%s]", name, ctx->colors->num, idx, ctx->colors->reset);
+ free (name);
+ return res;
+}
+
+static struct rnndecaddrinfo *trymatch (struct rnndeccontext *ctx, struct rnndelem **elems, int elemsnum, uint64_t addr, int write, int dwidth, uint64_t *indices, int indicesnum) {
+ struct rnndecaddrinfo *res;
+ int i, j;
+ for (i = 0; i < elemsnum; i++) {
+ if (!rnndec_varmatch(ctx, &elems[i]->varinfo))
+ continue;
+ uint64_t offset, idx;
+ char *tmp, *name;
+ switch (elems[i]->type) {
+ case RNN_ETYPE_REG:
+ if (addr < elems[i]->offset)
+ break;
+ if (elems[i]->stride) {
+ idx = (addr-elems[i]->offset)/elems[i]->stride;
+ offset = (addr-elems[i]->offset)%elems[i]->stride;
+ } else {
+ idx = 0;
+ offset = addr-elems[i]->offset;
+ }
+ if (offset >= elems[i]->width/dwidth)
+ break;
+ if (elems[i]->length && idx >= elems[i]->length)
+ break;
+ res = calloc (sizeof *res, 1);
+ res->typeinfo = &elems[i]->typeinfo;
+ res->width = elems[i]->width;
+ asprintf (&res->name, "%s%s%s", ctx->colors->rname, elems[i]->name, ctx->colors->reset);
+ for (j = 0; j < indicesnum; j++)
+ res->name = appendidx(ctx, res->name, indices[j]);
+ if (elems[i]->length != 1)
+ res->name = appendidx(ctx, res->name, idx);
+ if (offset) {
+ asprintf (&tmp, "%s+%s%#"PRIx64"%s", res->name, ctx->colors->err, offset, ctx->colors->reset);
+ free(res->name);
+ res->name = tmp;
+ }
+ return res;
+ case RNN_ETYPE_STRIPE:
+ for (idx = 0; idx < elems[i]->length || !elems[i]->length; idx++) {
+ if (addr < elems[i]->offset + elems[i]->stride * idx)
+ break;
+ offset = addr - (elems[i]->offset + elems[i]->stride * idx);
+ int extraidx = (elems[i]->length != 1);
+ int nindnum = (elems[i]->name ? 0 : indicesnum + extraidx);
+ uint64_t nind[nindnum];
+ if (!elems[i]->name) {
+ for (j = 0; j < indicesnum; j++)
+ nind[j] = indices[j];
+ if (extraidx)
+ nind[indicesnum] = idx;
+ }
+ res = trymatch (ctx, elems[i]->subelems, elems[i]->subelemsnum, offset, write, dwidth, nind, nindnum);
+ if (!res)
+ continue;
+ if (!elems[i]->name)
+ return res;
+ asprintf (&name, "%s%s%s", ctx->colors->rname, elems[i]->name, ctx->colors->reset);
+ for (j = 0; j < indicesnum; j++)
+ name = appendidx(ctx, name, indices[j]);
+ if (elems[i]->length != 1)
+ name = appendidx(ctx, name, idx);
+ asprintf (&tmp, "%s.%s", name, res->name);
+ free(name);
+ free(res->name);
+ res->name = tmp;
+ return res;
+ }
+ break;
+ case RNN_ETYPE_ARRAY:
+ if (addr < elems[i]->offset)
+ break;
+ idx = (addr-elems[i]->offset)/elems[i]->stride;
+ offset = (addr-elems[i]->offset)%elems[i]->stride;
+ if (elems[i]->length && idx >= elems[i]->length)
+ break;
+ asprintf (&name, "%s%s%s", ctx->colors->rname, elems[i]->name, ctx->colors->reset);
+ for (j = 0; j < indicesnum; j++)
+ name = appendidx(ctx, name, indices[j]);
+ if (elems[i]->length != 1)
+ name = appendidx(ctx, name, idx);
+ if ((res = trymatch (ctx, elems[i]->subelems, elems[i]->subelemsnum, offset, write, dwidth, 0, 0))) {
+ asprintf (&tmp, "%s.%s", name, res->name);
+ free(name);
+ free(res->name);
+ res->name = tmp;
+ return res;
+ }
+ res = calloc (sizeof *res, 1);
+ asprintf (&tmp, "%s+%s%#"PRIx64"%s", name, ctx->colors->err, offset, ctx->colors->reset);
+ free(name);
+ res->name = tmp;
+ return res;
+ default:
+ break;
+ }
+ }
+ return 0;
+}
+
+struct rnndecaddrinfo *rnndec_decodeaddr(struct rnndeccontext *ctx, struct rnndomain *domain, uint64_t addr, int write) {
+ struct rnndecaddrinfo *res = trymatch(ctx, domain->subelems, domain->subelemsnum, addr, write, domain->width, 0, 0);
+ if (res)
+ return res;
+ res = calloc (sizeof *res, 1);
+ asprintf (&res->name, "%s%#"PRIx64"%s", ctx->colors->err, addr, ctx->colors->reset);
+ return res;
+}
diff --git a/envytools/rnn/rules2rnn b/envytools/rnn/rules2rnn
new file mode 100755
index 0000000..d83bef0
--- /dev/null
+++ b/envytools/rnn/rules2rnn
@@ -0,0 +1,522 @@
+#!/usr/bin/python
+import subprocess
+import sys
+import os
+import bisect
+from lxml import etree as ET
+
+colon = "39584ac56e6d0976692778b80915f94b61767814a8704982"
+
+def hexa(v):
+ if v <= 9:
+ return str(v)
+ else:
+ return hex(v)
+
+
+# from renouveau.xml
+# the rules.xml names suck
+known_objclasses = {
+ 0x0001 : "NV01_ROOT",
+ 0x0002 : "NV01_CONTEXT_DMA",
+ 0x0003 : "NV01_DEVICE",
+ 0x0004 : "NV01_TIMER",
+ 0x0012 : "NV01_CONTEXT_BETA1",
+ 0x0017 : "NV01_CONTEXT_COLOR_KEY",
+ 0x0057 : "NV04_CONTEXT_COLOR_KEY",
+ 0x0018 : "NV01_CONTEXT_PATTERN",
+ 0x0019 : "NV01_CONTEXT_CLIP_RECTANGLE",
+ 0x001c : "NV01_RENDER_SOLID_LINE",
+ 0x005c : "NV04_RENDER_SOLID_LINE",
+ 0x001d : "NV01_RENDER_SOLID_TRIANGLE",
+ 0x005d : "NV04_RENDER_SOLID_TRIANGLE",
+ 0x001e : "NV01_RENDER_SOLID_RECTANGLE",
+ 0x005e : "NV04_RENDER_SOLID_RECTANGLE",
+ 0x001f : "NV01_IMAGE_BLIT",
+ 0x005f : "NV04_IMAGE_BLIT",
+ 0x009f : "NV12_IMAGE_BLIT",
+ 0x0021 : "NV01_IMAGE_FROM_CPU",
+ 0x0061 : "NV04_IMAGE_FROM_CPU",
+ 0x0065 : "NV05_IMAGE_FROM_CPU",
+ 0x008a : "NV10_IMAGE_FROM_CPU",
+ 0x038a : "NV30_IMAGE_FROM_CPU",
+ 0x308a : "NV40_IMAGE_FROM_CPU",
+ 0x0030 : "NV01_NULL",
+ 0x0036 : "NV03_STRETCHED_IMAGE_FROM_CPU",
+ 0x0076 : "NV04_STRETCHED_IMAGE_FROM_CPU",
+ 0x0066 : "NV05_STRETCHED_IMAGE_FROM_CPU",
+ 0x0366 : "NV30_STRETCHED_IMAGE_FROM_CPU",
+ 0x3066 : "NV40_STRETCHED_IMAGE_FROM_CPU",
+ 0x0037 : "NV03_SCALED_IMAGE_FROM_MEMORY",
+ 0x0077 : "NV04_SCALED_IMAGE_FROM_MEMORY",
+ 0x0063 : "NV05_SCALED_IMAGE_FROM_MEMORY",
+ 0x0089 : "NV10_SCALED_IMAGE_FROM_MEMORY",
+ 0x0389 : "NV30_SCALED_IMAGE_FROM_MEMORY",
+ 0x3089 : "NV40_SCALED_IMAGE_FROM_MEMORY",
+ 0x0038 : "NV04_DVD_SUBPICTURE",
+ 0x0088 : "NV10_DVD_SUBPICTURE",
+ 0x0039 : "NV04_MEMORY_TO_MEMORY_FORMAT",
+ 0x5039 : "NV50_MEMORY_TO_MEMORY_FORMAT",
+ 0x003d : "NV01_MEMORY_LOCAL_BANKED",
+# 0x003e : "NV01_MAPPING_SYSTEM",
+ 0x003f : "NV03_MEMORY_LOCAL_CURSOR",
+ 0x0040 : "NV01_MEMORY_LOCAL_LINEAR",
+ 0x0041 : "NV01_MAPPING_LOCAL",
+ 0x0042 : "NV04_CONTEXT_SURFACES_2D",
+ 0x0062 : "NV10_CONTEXT_SURFACES_2D",
+ 0x0362 : "NV30_CONTEXT_SURFACES_2D",
+ 0x3062 : "NV40_CONTEXT_SURFACES_2D",
+ 0x0043 : "NV03_CONTEXT_ROP",
+ 0x0044 : "NV04_IMAGE_PATTERN",
+ 0x0046 : "NV03_VIDEO_LUT_CURSOR_DAC",
+ 0x0048 : "NV03_TEXTURED_TRIANGLE",
+ 0x004a : "NV04_GDI_RECTANGLE_TEXT",
+ 0x004b : "NV03_GDI_RECTANGLE_TEXT",
+ 0x0052 : "NV04_SWIZZLED_SURFACE",
+ 0x009e : "NV20_SWIZZLED_SURFACE",
+ 0x039e : "NV30_SWIZZLED_SURFACE",
+ 0x309e : "NV40_SWIZZLED_SURFACE",
+ 0x0053 : "NV04_CONTEXT_SURFACES_3D",
+ 0x0093 : "NV10_CONTEXT_SURFACES_3D",
+ 0x0054 : "NV04_TEXTURED_TRIANGLE",
+ 0x0094 : "NV10_TEXTURED_TRIANGLE",
+ 0x0055 : "NV04_MULTITEX_TRIANGLE",
+ 0x0095 : "NV10_MULTITEX_TRIANGLE",
+ 0x0056 : "NV10TCL",
+ 0x0096 : "NV11TCL",
+ 0x0099 : "NV17TCL",
+ 0x0058 : "NV03_CONTEXT_SURFACES_2D",
+ 0x005a : "NV03_CONTEXT_SURFACES_3D",
+ 0x0060 : "NV04_INDEXED_IMAGE_FROM_CPU",
+ 0x0064 : "NV05_INDEXED_IMAGE_FROM_CPU",
+ 0x006a : "NV03_CHANNEL_PIO",
+ 0x006b : "NV03_CHANNEL_DMA",
+ 0x0072 : "NV04_BETA_SOLID",
+ 0x007b : "NV10_TEXTURE_FROM_CPU",
+ 0x037b : "NV30_TEXTURE_FROM_CPU",
+ 0x307b : "NV40_TEXTURE_FROM_CPU",
+ 0x007c : "NV10_VIDEO_DISPLAY",
+ 0x0097 : "NV20TCL",
+ 0x0597 : "NV25TCL",
+ 0x0397 : "NV30TCL",
+ 0x0497 : "NV35TCL",
+ 0x0697 : "NV34TCL",
+ 0x4097 : "NV40TCL",
+ 0x4497 : "NV44TCL",
+ 0x502d : "NV50_2D",
+ 0x5097 : "NV50TCL",
+ 0x8297 : "NV84TCL",
+ 0x8397 : "NVA0TCL",
+ 0x8597 : "NVA8TCL",
+ 0x50c0 : "NV50_COMPUTE",
+ 0x0010 : "NV_IMAGE_STENCIL",
+ 0x0011 : "NV_IMAGE_BLEND_AND",
+ 0x0013 : "NV_IMAGE_ROP_AND",
+ 0x0015 : "NV_IMAGE_COLOR_KEY",
+ 0x0064 : "NV01_IMAGE_SRCCOPY_AND",
+ 0x0065 : "NV03_IMAGE_SRCCOPY",
+ 0x0066 : "NV04_IMAGE_SRCCOPY_PREMULT",
+ 0x0067 : "NV04_IMAGE_BLEND_PREMULT",
+}
+
+tree = ET.parse("rules.xml")
+root = tree.getroot();
+outdir = "rules"
+try:
+ os.mkdir(outdir)
+except:
+ pass
+for subdir in ("mmio", "objects", "misc", "strange"):
+ try:
+ os.mkdir(outdir + "/" + subdir)
+ except:
+ pass
+
+devobjs = []
+
+address_stripeobjs = {}
+objsuper_stripeobjs = {}
+stripeobjs = []
+
+class Stripe(object):
+ def __init__(self):
+ self.strange_name = None
+ self.objsuper = None
+ self.names = set()
+ self.members = {}
+
+class Device(object):
+ pass
+
+addendum = '<rule-database><device name="NV_PRMIO" start="0x00007100" end="0x0000710f" /><device name="NV_PCRTC" start="0x00600000" end="0x00600fff" /></rule-database>'
+addendum_root = ET.fromstring(addendum)
+for device in addendum_root.iterchildren(tag=ET.Element):
+ addendum_root.remove(device)
+ root.append(device)
+
+for device in root.iterchildren(tag=ET.Element):
+ devobj = Device()
+ devobj.device = device
+ devobj.name = device.attrib["name"]
+ devobj.offset = int(device.attrib["start"], 0)
+ devobj.end = int(device.attrib["end"], 0) + 1
+
+ objclasses = {}
+
+ for reglike in device.iterchildren(tag=ET.Element):
+ if reglike.tag == "field-value":
+ if "name" in reglike.attrib and "value" in reglike.attrib:
+ objclasses[int(reglike.attrib["value"], 0)] = reglike.attrib["name"]
+
+ for objclass in objclasses:
+ if objclass in known_objclasses:
+ objclasses[objclass] = known_objclasses[objclass]
+
+ objclasses = [(name, num) for num, name in objclasses.items()]
+ objclasses.sort()
+
+ if not objclasses:
+ if devobj.name == "NV_UTOMEM":
+ objclasses = [("NV_IMAGE_TO_MEMORY", None)]
+
+ devobj.objclasses = objclasses
+
+ devobjs.append(devobj)
+
+ if devobj.objclasses:
+ objsuper = devobj.objclasses[0][0]
+ us = objsuper.find("_")
+ objsuper = objsuper[us + 1:]
+ stripeobj = objsuper_stripeobjs.get(objsuper)
+ else:
+ stripeobj = address_stripeobjs.get(devobj.offset)
+
+ if not stripeobj:
+ stripeobj = Stripe()
+ stripeobj.offset = devobj.offset
+ stripeobj.end = devobj.end
+ stripeobjs.append(stripeobj)
+
+ # don't merge stuff at offset 0, since they usually aren't in the MMIO domain
+ if not devobj.objclasses:
+ if devobj.offset != 0:
+ address_stripeobjs[devobj.offset] = stripeobj
+ else:
+ stripeobj.objsuper = objsuper
+ objsuper_stripeobjs[objsuper] = stripeobj
+ else:
+ if devobj.end > stripeobj.end:
+ stripeobj.end = devobj.end
+ stripeobj.names.add(devobj.name)
+ devobj.stripeobj = stripeobj
+
+strange_stripeobjs = {}
+
+def common_prefix_len(a, b):
+ i = 0
+ while a[i:i+1] == b[i:i+1]:
+ i += 1
+ return i
+
+field_name_to_type_map = {"HANDLE" : "object", "STYLE" : "notify_style"}
+uninteresting_field_names = ["VAL", "VALUE", "PARAMETER", "ADDRESS", "RESERVED", "DATA", "BLAH", "COUNT", "CNT", "ARGUMENT", "BITMAP", "OFFSET", "FIELD", "MODE", "LE"]
+uninteresting_field_names += field_name_to_type_map.keys()
+uninteresting_field_names = frozenset(uninteresting_field_names)
+
+uninteresting_reglike_names = frozenset(["NOP", "NOTIFY", "SET_NOTIFY", "CTX_SWITCH"])
+
+def process_values(field, rnn_field):
+ true_value = None
+ false_value = None
+ common_prefix = None
+
+ rnn_values = []
+ strong_bool = False
+
+ for field_value in field.iterchildren(tag=ET.Element):
+ if field_value.tag == "field-value":
+ field_value_name = field_value.attrib["name"]
+ rnn_value_name = field_value_name
+ if rnn_value_name.startswith(field_name + "_"):
+ rnn_value_name = field_value_name[len(field_name)+1:]
+ rnn_value = ET.Element("value")
+ rnn_value.attrib["name"] = rnn_value_name
+ rnn_value.attrib["value"] = hexa(int(field_value.attrib["value"], 0))
+ rnn_values.append(rnn_value)
+ rnn_field.append(rnn_value)
+ if rnn_value_name in ("FALSE", "OFF", "DISABLE", "DISABLED", "NO", "0"):
+ false_value = rnn_value
+ if rnn_value_name != "0":
+ strong_bool = True
+ if rnn_value_name in ("TRUE", "ON", "ENABLE", "ENABLED", "YES", "1"):
+ true_value = rnn_value
+ if rnn_value_name != "0":
+ strong_bool = True
+
+ # avoid reglikes with just "0 = 0"
+ if len(rnn_values) == 1 and rnn_values[0].attrib["name"] == "0" and rnn_values[0].attrib["value"] == "0":
+ rnn_field.remove(rnn_values[0])
+ rnn_values = []
+ elif len(rnn_values) and len(rnn_values) == ((1 if true_value is not None else 0) + (1 if false_value is not None else 0)):
+ if false_value is not None:
+ rnn_field.remove(false_value)
+ if true_value is not None:
+ rnn_field.remove(true_value)
+ rnn_field.attrib["type"] = "boolean"
+
+ if len(rnn_values) > 1 and rnn_field.attrib["name"] not in ("NOTIFY",):
+ for rnn_value in rnn_values:
+ rnn_value_name = rnn_value.attrib["name"]
+ if rnn_value_name == "INVALID" or rnn_value_name[0:1].isdigit():
+ pass
+ elif common_prefix is None:
+ common_prefix = rnn_value_name
+ else:
+ common_prefix = common_prefix[:common_prefix_len(common_prefix, rnn_value_name)]
+
+ if common_prefix:
+ us = common_prefix.rfind("_")
+ if us >= 0:
+ common_prefix = common_prefix[:us + 1]
+ if common_prefix:
+ for rnn_value in rnn_values:
+ if rnn_value.attrib["name"].startswith(common_prefix):
+ rnn_value.attrib["name"] = rnn_value.attrib["name"][len(common_prefix):]
+ rnn_field.attrib["name"] += "_" + common_prefix.rstrip("_")
+
+#print ET.tostring(tree)
+for devobj in devobjs:
+ for reglike in devobj.device.iterchildren(tag=ET.Element):
+ if reglike.tag == "register" or reglike.tag == "array":
+ address = int(reglike.attrib["address"], 0)
+
+ reglike_name = reglike.attrib["name"]
+ cand_devobjs = [(-common_prefix_len(cand_devobj.name, reglike_name), cand_devobj) for cand_devobj in devobjs if address >= cand_devobj.offset and address < cand_devobj.end]
+ cand_devobjs.sort()
+ cand_devobj = cand_devobjs[0][1]
+ stripeobj = cand_devobj.stripeobj
+# if stripeobj.offset == 0:
+
+ if reglike_name.startswith(cand_devobj.name + "_"):
+ stripeobj = cand_devobj.stripeobj
+ if devobj.objclasses:
+ assert cand_devobj.objclasses
+ if cand_devobj.objclasses:
+ assert devobj.objclasses
+ objclasses = devobj.objclasses
+ else:
+ us = reglike_name.find("_")
+ us = reglike_name.find("_", us + 1)
+ strange_stripeobj_name = reglike_name[:us]
+ stripeobj = strange_stripeobjs.get(strange_stripeobj_name)
+ if not stripeobj:
+ stripeobj = Stripe()
+ stripeobj.strange_name = strange_stripeobj_name
+ stripeobj.offset = 0
+ stripeobj.end = 0xffffffff
+ strange_stripeobjs[strange_stripeobj_name] = stripeobj
+ stripeobjs.append(stripeobj)
+
+ objclasses = []
+
+ assert address >= cand_devobj.offset
+ assert address < cand_devobj.end
+ offset = address - cand_devobj.offset
+
+ if offset == 0 and objclasses:
+ continue
+
+ rnn_reglike_name = reglike_name
+ for device_name in stripeobj.names:
+ if rnn_reglike_name.startswith(device_name + "_"):
+ rnn_reglike_name = rnn_reglike_name[len(device_name) + 1:]
+ break
+
+ if rnn_reglike_name in uninteresting_reglike_names:
+ continue
+
+ rnn_reglike = ET.Element("reg32")
+
+ rnn_reglike.attrib["offset"] = hex(offset)
+
+ if reglike.tag == "array":
+ max_size = 0
+ for field in reglike.iterchildren(tag=ET.Element):
+ if field.tag == "array-size":
+ size = int(field.attrib["size"], 0)
+ if size > max_size:
+ max_size = size
+ rnn_reglike.attrib["length"] = str(max_size)
+ rnn_reglike.attrib["stride"] = str(int(reglike.attrib["width"], 0))
+
+ num_bitfields = 0
+ full_field_name = None
+ for field in reglike.iterchildren(tag=ET.Element):
+ if field.tag == "field":
+ i = 0 # for "i" variables in the low-bit and high-bit attributes
+ low = eval(field.attrib["low-bit"])
+ high = eval(field.attrib["high-bit"])
+ field_name = field.attrib["name"]
+ rnn_field_name = field_name
+ if rnn_field_name.startswith(reglike_name + "_"):
+ rnn_field_name = rnn_field_name[len(reglike_name)+1:]
+
+ if low == 0 and high == 31:
+ if rnn_field_name not in uninteresting_field_names and not rnn_field_name.startswith("NV_"):
+ full_field_name = rnn_field_name
+ if rnn_field_name in field_name_to_type_map:
+ rnn_reglike.attrib["type"] = field_name_to_type_map[rnn_field_name]
+ bitfield = rnn_reglike
+ for elem in field.iterchildren(tag=ET.Element):
+ field.remove(elem)
+ reglike.append(elem)
+ else:
+ bitfield = ET.Element("bitfield")
+ rnn_reglike.append(bitfield)
+ bitfield.attrib["low"] = str(low)
+ bitfield.attrib["high"] = str(high)
+ bitfield.attrib["name"] = rnn_field_name
+ num_bitfields += 1
+ process_values(field, bitfield)
+
+ if full_field_name is not None and num_bitfields == 0:
+ rnn_reglike_name += "_" + full_field_name
+ rnn_reglike.attrib["name"] = rnn_reglike_name
+ process_values(reglike, rnn_reglike)
+
+ stripeobj.members.setdefault(offset, {}).setdefault(ET.tostring(rnn_reglike), []).extend(objclasses)
+
+# TODO: maybe the Python stdlib provides this function?
+def extract_ranges(univ, cur):
+ cur = frozenset(cur)
+ i = 0
+ first = None
+ ranges = []
+ for item in univ:
+ if item in cur:
+ if first is None:
+ first = i
+ else:
+ if first is not None:
+ ranges.append((first, i - 1))
+ first = None
+ i += 1
+ if first is not None:
+ ranges.append((first, i - 1))
+ return ranges
+
+for stripeobj in stripeobjs:
+ if not stripeobj.members:
+ continue
+
+ stripe = ET.Element("stripe")
+
+ database = ET.Element("database")
+ database.attrib["xmlns"] = "http://nouveau.freedesktop.org/"
+ database.attrib["xmlns" + colon + "xsi"] = "http://www.w3.org/2001/XMLSchema-instance"
+ database.attrib["xsi" + colon + "schemaLocation"] = "http://nouveau.freedesktop.org/ rules-ng.xsd"
+
+ members = stripeobj.members.items()
+ members.sort()
+
+ objclasses = set()
+ for offset, versions in members:
+ for version_objclasses in versions.values():
+ objclasses.update(version_objclasses)
+ objclasses = list(objclasses)
+ objclasses.sort()
+
+ objclass_numbers = set([num for num, name in objclasses])
+ # assert no objclass has conflicting names
+ # could actually handle this, but it's not necessary
+ assert len(objclasses) == len(objclass_numbers)
+
+ for offset, versions in members:
+ versions_sorted = [(version_objclasses, xml) for xml, version_objclasses in versions.items()]
+ versions_sorted.sort()
+ for version_objclasses, xml in versions_sorted:
+ elem = ET.fromstring(xml)
+
+ if version_objclasses and set(objclasses) != set(version_objclasses):
+ ranges = extract_ranges(objclasses, version_objclasses)
+ elem.attrib["variants"] = " ".join([(objclasses[a][0] if a == b else objclasses[a][0] + "-" + objclasses[b][0]) for a, b in ranges])
+ stripe.append(elem)
+
+ if stripeobj.objsuper:
+ objenum = ET.Element("enum")
+ objenum.attrib["bare"] = "yes"
+ objenum.attrib["name"] = "obj-class"
+
+ for objname, objclass in objclasses:
+ objvalue = ET.Element("value")
+ if objclass is not None:
+ objvalue.attrib["value"] = hex(objclass)
+ objvalue.attrib["name"] = objname
+ objenum.append(objvalue)
+
+ database.append(objenum)
+
+ subchan = ET.Element("domain")
+ subchan.attrib["name"] = "NV01_SUBCHAN"
+ subchan.attrib["bare"] = "yes"
+ subchan.attrib["size"] = "0x2000"
+
+ stripe.attrib["prefix"] = "obj-class"
+ #stripe.attrib["varset"] = "obj-class"
+ if len(objclasses) == 1:
+ stripe.attrib["variants"] = objclasses[0][0]
+ else:
+ stripe.attrib["variants"] = objclasses[0][0] + "-" + objclasses[-1][0]
+
+ subchan.append(stripe)
+ database.append(subchan)
+ else:
+ name = None
+ if stripeobj.names:
+ assert len(stripeobj.names) == 1
+ name = list(stripeobj.names)[0]
+
+ mmio = ET.Element("domain")
+ if stripeobj.offset != 0 or name == "NV_PMC":
+ mmio.attrib["name"] = "NV_MMIO"
+ mmio.attrib["bare"] = "yes"
+ is_mmio = True
+ elif name:
+ mmio.attrib["name"] = name
+ is_mmio = False
+ mmio.attrib["prefix"] = "chipset"
+
+ if is_mmio and name:
+ stripe.attrib["name"] = name
+ stripe.attrib["offset"] = hex(stripeobj.offset)
+ stripe.attrib["stride"] = hex(stripeobj.end - stripeobj.offset)
+ mmio.append(stripe)
+ database.append(mmio)
+
+ if stripeobj.objsuper:
+ basename = stripeobj.objsuper.lower()
+ else:
+ basename = name
+ if stripeobj.strange_name:
+ basename = stripeobj.strange_name
+
+ if basename.startswith("NV_"):
+ basename = basename[3:]
+ basename = basename.lower()
+
+ if stripeobj.objsuper:
+ subdir = "objects"
+ elif stripeobj.strange_name:
+ subdir = "strange"
+ elif is_mmio:
+ subdir = "mmio"
+ else:
+ subdir = "misc"
+ filename = outdir + "/" + subdir + "/" + basename
+
+ outfile = open(filename, "w")
+ xml2text = subprocess.Popen("./xml2text", stdin = subprocess.PIPE, stdout = outfile)
+ xml2text.communicate(ET.tostring(database).replace(colon, ":"))
+ xml2text.wait()
+ outfile.close()
+
diff --git a/envytools/rnn/text2xml b/envytools/rnn/text2xml
new file mode 100755
index 0000000..cb4bd75
--- /dev/null
+++ b/envytools/rnn/text2xml
@@ -0,0 +1,411 @@
+#!/usr/bin/python
+import sys
+from lxml import etree as ET
+
+# this does not recognize octal unlike int(s, 0)
+def intdh(s):
+ if s.startswith("0x"):
+ return int(s[2:], 16)
+ else:
+ return int(s)
+
+root = ET.Element("database")
+
+if sys.argv[1:2]:
+ filename = sys.argv[1]
+ rnn = open(filename)
+else:
+ rnn = sys.stdin
+
+s = "\n" + rnn.read()
+
+default_reg = "reg32"
+
+comments = {}
+
+token = ""
+i = 0
+tokens = []
+attrvalues = []
+comment = ""
+linenum = 0
+errors = 0
+linestart = 0
+brief = None
+indent = 0
+
+def str_width(s):
+ w = 0
+ for i in s:
+ if i == '\t':
+ w = (w + 8) & ~7
+ else:
+ w = w + 1
+
+ return w
+
+def hexa(v):
+ if v <= 9:
+ return str(v)
+ else:
+ return hex(v)
+
+def indent_str(indent):
+ return ("\t" * (indent >> 3) + " " * (indent & 7)) if indent > 0 else ""
+
+def error(msg):
+ global errors
+ print >> sys.stderr, filename + ":" + str(linenum) + ":" + str(str_width(s[linestart:i]) + 1) + ": " + msg
+ errors += 1
+
+def isident(c):
+ return c.isalnum() or c == "_" or c == "-" or c == "#" or c == ","
+
+def reduce_stack(target):
+ global stack
+ while len(stack) > target:
+ stack[-1][1].tail = "\n" + indent_str(stack[-2][0])
+ stack = stack[:-1]
+
+special_chars = ":=[]{}"
+
+stack = [(-1, root)]
+last_attachment = None
+empty_line = False
+while True:
+ c = s[i:i+1]
+ if s[i:i + 2] == "//":
+ i += 2
+ begin = i
+ while s[i] and s[i] != "\n":
+ i += 1
+ comment = s[begin:i]
+ c = "\n"
+
+ if not c or c == "\n":
+ if len(tokens) == 0:
+ empty_line = True
+ else:
+ last_closed_elem = None
+ if last_attachment is not None:
+ last_closed_elem = last_attachment
+ last_attachment = None
+ for j in xrange(len(stack)):
+ if indent <= stack[j][0]:
+ if indent < stack[j][0]:
+ error("line indentation does not match any previous indentation")
+ last_closed_elem = stack[j][1]
+ reduce_stack(j)
+ stack = stack[0:j]
+ break
+ elem = None
+ parent = stack[-1][1]
+ ptag = parent.tag
+ parent_is_reg = ptag in ("reg8", "reg16", "reg32")
+ reglike_tag = None
+
+ while tokens:
+ if tokens[0] in ("bare", "inline"):
+ attrvalues.append((tokens[0], "yes"))
+ tokens = tokens[1:]
+ else:
+ break
+
+ for j in xrange(len(tokens)):
+ if not tokens[j]:
+ continue
+ if tokens[j][0] == "!":
+ attrvalues.append(("access", tokens[j][1:]))
+ tokens[j] = None
+ if j >= 2 and tokens[j] == ":" and (j + 1) < len(tokens) and tokens[j + 1].isdigit():
+ reglike_tag = "reg" + tokens[j + 1]
+ tokens[j] = tokens[j + 1] = None
+ if (j + 2) < len(tokens):
+ if tokens[j] == "{" and tokens[j + 2] == "}":
+ attrvalues.append(("stride", tokens[j + 1]))
+ tokens[j] = tokens[j + 1] = tokens[j + 2] = None
+ if tokens[j] == "[" and tokens[j + 2] == "]":
+ attrvalues.append(("length", tokens[j + 1]))
+ tokens[j] = tokens[j + 1] = tokens[j + 2] = None
+
+ tokens = [token for token in tokens if token]
+
+ if tokens and tokens[-1] == "=":
+ if len(tokens) >= 2 and tokens[-2] == ":":
+ reglike_tag = "stripe"
+ tokens = tokens[:-2]
+ else:
+ reglike_tag = "array"
+ tokens = tokens[:-1]
+
+ if not tokens:
+ error("line with no tokens")
+ elif tokens[0] == "#import":
+ elem = ET.Element("import")
+ if brief:
+ elem.attrib["file"] = brief
+ brief = None
+ else:
+ error("#include without file argument")
+ if len(tokens) > 1:
+ error("too many tokens in #include line")
+ elif tokens[0] == "#pragma":
+ if len(tokens) == 1:
+ error("pragma with no arguments")
+ elif tokens[1][:3] == "reg":
+ default_reg = tokens[1]
+ else:
+ error("unrecognized pragma")
+ elem = None
+ elif tokens[0] == "@":
+ elem = ET.Element(tokens[0][1:])
+ if len(tokens) >= 2:
+ elem.attrib["name"] = tokens[1]
+ elif len(tokens) >= 3:
+ error("too many tokens in generic tag line")
+ elif tokens[0] == ":":
+ doc = parent.find("doc")
+ if doc is not None:
+ prev = doc.getprevious()
+ if prev is not None:
+ docindent = prev.tail
+ else:
+ prev = doc.getparent()
+ if prev is not None:
+ docindent = prev.text
+ else:
+ docindent = ""
+ if "\n" not in doc.text:
+ doc.text = docindent + "\t" + doc.text + docindent
+ nl = doc.text.rfind("\n")
+ doc.text = doc.text[:nl] + docindent + "\t" + (tokens[1] if len(tokens) >= 2 else "") + docindent
+ elem = None
+ else:
+ elem = ET.Element("doc")
+ if len(tokens) >= 2:
+ elem.text = tokens[1]
+ elif tokens[-1] == ":":
+ elem = ET.Element(tokens[0])
+ if len(tokens) >= 3:
+ elem.attrib["name"] = tokens[1]
+ elif len(tokens) >= 4:
+ error("too many tokens in generic tag line")
+ elif len(tokens) == 1 and (parent_is_reg or ptag == "enum"):
+ elem = ET.Element("value")
+ if tokens[0][0].isdigit():
+ elem.attrib["value"] = tokens[0]
+ else:
+ elem.attrib["name"] = tokens[0]
+ elif len(tokens) >= 3 and tokens[1] == "=":
+ elem = ET.Element("value")
+ elem.attrib["value"] = tokens[0]
+ elem.attrib["name"] = tokens[2]
+ if len(tokens) >= 4:
+ error("too many tokens in value line")
+ elif len(tokens) >= 3 and tokens[0] == "use":
+ elem = ET.Element("use-" + tokens[1])
+ elem.attrib["name"] = tokens[2]
+ if len(tokens) >= 4:
+ error("too many tokens in use line")
+ elif parent_is_reg or ptag == "bitset":
+ elem = ET.Element("bitfield")
+ sl = tokens[0].find("-")
+ if sl >= 0:
+ low = tokens[0][:sl]
+ high = tokens[0][sl + 1:]
+ else:
+ low = high = tokens[0]
+ if low == high:
+ elem.attrib["pos"] = str(intdh(low))
+ else:
+ elem.attrib["low"] = str(intdh(low))
+ elem.attrib["high"] = str(intdh(high))
+ if len(tokens) >= 2:
+ elem.attrib["name"] = tokens[1]
+ if len(tokens) >= 3:
+ elem.attrib["type"] = tokens[2]
+ if len(tokens) >= 4:
+ error("too many tokens in bitfield line")
+ else:
+ elem = ET.Element(reglike_tag if reglike_tag else default_reg)
+ elem.attrib["offset"] = hexa(int(tokens[0], 16))
+ if len(tokens) >= 2:
+ elem.attrib["name"] = tokens[1]
+ if len(tokens) >= 3:
+ elem.attrib["type"] = tokens[2].replace(",", " ")
+ if len(tokens) >= 4:
+ error("too many tokens in reg line")
+ reglike_tag = None
+
+ if elem is not None:
+ for attr, value in attrvalues:
+ elem.attrib[attr] = value
+ if elem.attrib.get("type") == "reg":
+ del elem.attrib["type"]
+# if elem.tag == "bitfield":
+# if parent.tag.startswith("reg"):
+# parent.attrib["type"] = "bitfield"
+# if elem.tag == "value":
+# if parent.tag.startswith("reg"):
+# parent.attrib["type"] = "enum"
+ if brief:
+ briefelem = ET.Element("brief")
+ briefelem.tag = "brief"
+ briefelem.text = brief
+ elem.append(briefelem)
+ last_attachment = briefelem
+
+ parent.append(elem)
+ xmlindent = "\n" +indent_str(indent)
+ if last_closed_elem is not None:
+ last_closed_elem.tail = ("\n" if empty_line else "") + xmlindent
+ else:
+ parent.text = xmlindent
+ stack.append((indent, elem))
+ empty_line = False
+
+ if reglike_tag:
+ error("line specified to be a " + reglike_tag + " but the line format does not match it")
+ if comment:
+ commentelem = ET.Comment(comment)
+ comments.setdefault(stack[-1][1], []).append(commentelem)
+ tokens = []
+ attrvalues = []
+ comment = None
+ brief = None
+ linenum += 1
+ linestart = i
+ indent = 0
+ if not c:
+ break
+ i += 1
+ while s[i:i + 1]:
+ if s[i:i+1] == " ":
+ indent += 1
+ if s[i:i+1] == "\t":
+ indent = (indent + 8) & ~7
+ else:
+ break
+ i += 1
+ indent &= ~7
+ if s[i:i + 1] == ":":
+ begin = i + 1
+ while s[i:i+1] and s[i] != "\n" and s[i:i+2] != "//":
+ i += 1
+ tokens.append(":")
+ tokens.append(s[begin:i].strip())
+ elif c.isspace():
+ i += 1
+ pass
+ elif c in special_chars:
+ tokens.append(c)
+ i += 1
+ elif c == "\"":
+ i += 1
+ begin = i
+ while True:
+ if not s[i:i+1] or s[i] == "\"":
+ break
+ if s[i:i+1] == "\\":
+ i += 2
+ else:
+ i += 1
+ if brief:
+ error("brief specified multiple times")
+ else:
+ if not tokens:
+ error("brief cannot be the start of a line")
+ else:
+ brief = s[begin:i]
+ i += 1
+ else:
+ begin = i
+ paren = -1
+ while True:
+ d = s[i:i+1]
+ if d == "(":
+ paren = i
+ i += 1
+ while True:
+ if not s[i:i+1]:
+ error("unterminated parenthesis")
+ break
+ elif s[i] == ')':
+ break
+ else:
+ i += 1
+ break
+ elif d.isspace() or d in special_chars:
+ break
+ else:
+ i += 1
+
+ if paren >= 0:
+ if paren == begin:
+ variants = s[paren + 1:i]
+ equals = variants.rfind("=")
+ if equals >= 0:
+ attrvalues.append(("varset", variants[:equals]))
+ variants = variants[equals + 1:]
+ attrvalues.append(("variants", variants))
+ else:
+ attrvalues.append((s[begin:paren], s[paren + 1:i]))
+ if s[i] == ")":
+ i += 1
+ else:
+ token = s[begin:i]
+ tokens.append(token)
+
+reduce_stack(1)
+
+# TODO: this takes in ordinate amount of code... can it be shortened?
+for elem, commentelems in comments.items():
+ for action, subelem in ET.iterwalk(elem, events = ("start", "end")):
+ if action == "start":
+ if subelem.text and "\n" in subelem.text:
+ if len(commentelems) == 1:
+ subelem.insert(0, commentelems[0])
+ commentelems[0].tail = subelem.text
+ subelem.text = " "
+ else:
+ for i in xrange(len(commentelems)):
+ subelem.insert(i, commentelems[i])
+ commentelems[i].tail = subelem.text
+ break
+ elif action == "end":
+ if subelem.tail and "\n" in subelem.tail:
+ parent = subelem.getparent()
+ i = parent.index(subelem)
+ i += 1
+ if len(commentelems) == 1:
+ parent.insert(i, commentelems[0])
+ commentelems[0].tail = subelem.tail
+ subelem.tail = " "
+ else:
+ prev = elem.getprevious()
+ if prev is not None:
+ indent = prev.tail
+ else:
+ prev = elem.getparent()
+ if prev is not None:
+ indent = prev.text
+ else:
+ indent = "\n"
+ indent += "\t"
+ for j in xrange(len(commentelems)):
+ parent.insert(i + j, commentelems[j])
+ commentelems[j].tail = indent
+ commentelems[-1].tail = subelem.tail
+ subelem.tail = indent
+ break
+
+# lxml etree refuses attributes with colons, and using namespaces "properly" is harder and has no advantages
+# this is a sequence from /dev/urandom
+colon = "39584ac56e6d0976692778b80915f94b61767814a8704982"
+root.attrib["xmlns"] = "http://nouveau.freedesktop.org/"
+root.attrib["xmlns" + colon + "xsi"] = "http://www.w3.org/2001/XMLSchema-instance"
+root.attrib["xsi" + colon + "schemaLocation"] = "http://nouveau.freedesktop.org/ rules-ng.xsd"
+print ET.tostring(root).replace(colon, ":")
+
+sys.exit(0 if errors == 0 else 1)
+
diff --git a/envytools/rnn/update.sed.sh b/envytools/rnn/update.sed.sh
new file mode 100755
index 0000000..8127b5c
--- /dev/null
+++ b/envytools/rnn/update.sed.sh
@@ -0,0 +1,31 @@
+#!/bin/bash
+if test renouveau.xml -nt renouveau; then
+ ./renouveau2rnn
+fi
+
+for i in renouveau/*; do
+ if test "${i:${#i} - 4:4}" == ".xml"; then
+ continue
+ fi
+
+ if test "$i" -nt "$i.xml"; then
+ ./text2xml "$i" > "$i.xml"
+ fi
+done
+
+function addrs
+{
+ sed -nre "s/d NV01_SUBCHAN ([^ ]*) ([^ ]*).*/\1 \2/p"
+}
+
+function gen
+{
+ join <(./expand "$3" -v obj-class "$1"|addrs|sort) <(./expand "$4" -v obj-class "$2"|addrs|sort)|sed -re 's@\([^()]*\)@@g; s@([^ ]*) ([^ ]*) ([^ ]*)@s/\2/\3/g;@g; s@s/NV..TCL_@s/'"$1"'_@'|sort|uniq
+}
+
+gen NV10TCL NV10TCL renouveau/nv10-20tcl.xml nv10_3d.xml
+gen NV20TCL NV20TCL renouveau/nv10-20tcl.xml nv20_3d.xml
+gen NV34TCL NV30_3D renouveau/nv30-40tcl.xml nv30-40_3d.xml
+gen NV40TCL NV40_3D renouveau/nv30-40tcl.xml nv30-40_3d.xml
+gen NV50TCL NV50_3D renouveau/nv50tcl.xml nv50_3d.xml
+
diff --git a/envytools/rnn/xml2text b/envytools/rnn/xml2text
new file mode 100755
index 0000000..b65929d
--- /dev/null
+++ b/envytools/rnn/xml2text
@@ -0,0 +1,233 @@
+#!/usr/bin/python
+import sys
+from lxml import etree as ET
+
+# this does not recognize octal unlike int(s, 0)
+def intdh(s):
+ if s.startswith("0x"):
+ return int(s[2:], 16)
+ else:
+ return int(s)
+
+if sys.argv[1:2]:
+ xml = sys.argv[1]
+ tree = ET.parse(xml)
+else:
+ tree = ET.parse(sys.stdin)
+
+root = tree.getroot();
+
+# TODO: make this configurable and autoselect the most frequent
+reg_default = "reg32"
+type_defaults = set(("enum", "bitfield", "hexa"))
+attr_defaults = {"prefix" : "none"}
+true_strings = ("1", "yes", "true")
+
+ns = "{http://nouveau.freedesktop.org/}"
+
+out = sys.stdout
+
+indent = ""
+
+comments = {}
+empty_line = False
+
+def process(container):
+ global indent
+ indent += "\t"
+ _process(container)
+ indent = indent[:-1]
+
+def get_pos(elem, which):
+ pos = elem.attrib.get(which, None)
+ if pos is not None:
+ return intdh(pos)
+ else:
+ return intdh(elem.attrib.get("pos", "-1"))
+
+def _process(container):
+ global empty_line
+ maxvalue = max([-1] + [max(intdh(elem.attrib.get("offset", "-1")), intdh(elem.attrib.get("value", "-1"))) for elem in container.iterchildren(tag=ET.Element)])
+ maxlow = max([-1] + [get_pos(elem, "low") for elem in container.iterchildren(tag=ET.Element)])
+ maxhigh = max([-1] + [get_pos(elem, "high") for elem in container.iterchildren(tag=ET.Element)])
+
+ any_multibit = False
+ for elem in container.iterchildren(tag=ET.Element):
+ if "low" in elem.attrib and "high" in elem.attrib and elem.attrib["low"] != elem.attrib["high"]:
+ any_multibit = True
+ break
+ value_hexdigits = len(hex(maxvalue)) - 2 if maxvalue >= 0 else -1
+
+ offset_format = "%0" + str(value_hexdigits) + "x" if maxvalue >= 0 else None
+ if maxvalue >= 16:
+ value_len = value_hexdigits + 2
+ # TODO: smart pretty print value instead of this
+ value_format = "0x%0" + str(value_hexdigits) + "x"
+ elif maxvalue >= 0:
+ value_len = len(str(maxvalue))
+ # TODO: smart pretty print value instead of this
+ value_format = "%" + str(value_len) + "d"
+ else:
+ value_len = -1
+ value_format = None
+
+ low_format = "%0" + str(len(str(maxlow))) + "d" if maxlow >= 0 else None
+ high_format = "%0" + str(len(str(maxhigh))) + "d" if maxhigh >= 0 else None
+
+ for elem in container.iterchildren(tag=ET.Element):
+ tag = elem.tag
+ assert tag.startswith(ns)
+ tag = tag[len(ns):]
+ if tag == "brief" or tag == "doc":
+ continue
+
+ is_reglike = False
+ line = ""
+ if ((tag[:3] == "reg" and tag[3:].isdigit()) or tag == "array" or tag == "stripe") and "offset" in elem.attrib:
+ line = offset_format % (intdh(elem.attrib.get("offset", -1)),)
+ del elem.attrib["offset"]
+ if "stride" in elem.attrib:
+ line += " {" + elem.attrib["stride"] + "}"
+ del elem.attrib["stride"]
+ if "length" in elem.attrib:
+ line += " [" + elem.attrib["length"] + "]"
+ del elem.attrib["length"]
+ if "name" in elem.attrib:
+ line += " " + elem.attrib["name"]
+ del elem.attrib["name"]
+ is_reglike = True
+ elif tag == "bitfield":
+ if "low" not in elem.attrib and "pos" not in elem.attrib:
+ print >> sys.stderr, "Bitfield " + elem.attrib.get("name", "<unnamed>") + " has no low bit!"
+ low = get_pos(elem, "low")
+ high = get_pos(elem, "high")
+ if high < 0:
+ high = low
+ if low != high:
+ line = low_format % (low,) + "-" + high_format % (high,)
+ elif any_multibit:
+# line = (" " * (len(str(maxlow)))) + low_format % (low,) + (" " * (len(str(maxhigh)) - len(str(maxlow)) + 1))
+ line = low_format % (low,) + (" " * (len(str(maxhigh)) + 1))
+ else:
+ line = low_format % (low,)
+ if "pos" in elem.attrib:
+ del elem.attrib["pos"]
+ if "low" in elem.attrib:
+ del elem.attrib["low"]
+ if "high" in elem.attrib:
+ del elem.attrib["high"]
+ elif tag == "value":
+ if "value" in elem.attrib:
+ line = (value_format % (intdh(elem.attrib["value"]),))
+ if "name" in elem.attrib:
+ line += " = "
+ del elem.attrib["value"]
+ else:
+ if "name" not in elem.attrib:
+ print >> sys.stderr, "Value has no value and no name attributes!"
+ if value_len >= 0:
+ line += " " * (value_len + 3)
+
+ if "name" in elem.attrib:
+ line += elem.attrib["name"]
+ del elem.attrib["name"]
+ elif tag == "import":
+ line = "#import"
+ if "file" in elem.attrib:
+ file = elem.attrib["file"]
+ line += " \"" + file + "\""
+ else:
+ print >> sys.stderr, "Import with no file attribute!"
+ del elem.attrib["file"]
+ elif tag[:4] == "use-":
+ line = "use " + tag[4:]
+ else:
+ line = tag
+ if "name" in elem.attrib:
+ line += " " + elem.attrib["name"]
+ del elem.attrib["name"]
+ if is_reglike or tag == "bitfield":
+ need_regwidth = tag[:3] == "reg" and tag != reg_default
+ if ("type" in elem.attrib and elem.attrib["type"] not in type_defaults) or need_regwidth:
+ line += " " + elem.attrib.get("type", "reg").replace(" ", ",") + (":" + tag[3:] if need_regwidth else "")
+ if "type" in elem.attrib:
+ del elem.attrib["type"]
+ brief = "\n".join([elem2.text for elem2 in elem.iterchildren(tag=ET.Element) if elem2.tag == ns + "brief"])
+ if brief:
+ line += " \"" + brief + "\""
+
+ if "varset" in elem.attrib and "variants" in elem.attrib:
+ elem.attrib["variants"] = elem.attrib["varset"] + "=" + elem.attrib["variants"]
+ del elem.attrib["varset"]
+
+ for keyword in ("inline", "bare"):
+ if keyword in elem.attrib:
+ if elem.attrib[keyword].lower() in true_strings:
+ line = keyword + " " + line
+ del elem.attrib[keyword]
+
+ for attr in elem.attrib.keys():
+ value = elem.attrib[attr]
+ if value != attr_defaults.get(attr):
+ line += " " + (attr if attr != "variants" else "") + "(" + value + ")"
+ if is_reglike:
+ if tag == "array":
+ line += " ="
+ elif tag == "stripe":
+ line += " :="
+ elif tag == "bitfield" or tag == "value" or tag == "import" or tag[:4] == "use-":
+ pass
+ else:
+ line += ":"
+ our_comments = comments.get(elem, [])
+ if our_comments:
+ line += " // " + our_comments[0]
+ if empty_line:
+ print
+ empty_line = False
+ print indent + line
+ if len(our_comments) > 1:
+ for comment in our_comments[1:]:
+ print indent + "\t// " + comment
+
+ doc = "\n".join([elem2.text for elem2 in elem.iterchildren(tag=ET.Element) if elem2.tag == ns + "doc"])
+ if doc:
+ lines = [line.strip() for line in doc.split("\n")]
+ while lines and not lines[0]:
+ lines = lines[1:]
+ while lines and not lines[-1]:
+ lines = lines[:-1]
+ for line in lines:
+ print indent + "\t: " + line
+ process(elem)
+ if elem.tail and elem.tail.count("\n") > 1:
+ empty_line = True
+
+last_non_comment = None
+for node in root.iter():
+ if isinstance(node, ET._Comment) and last_non_comment is not None:
+# reattach whitespace following comment to previous node
+ prev = node.getprevious()
+ if prev is not None:
+ prev.tail = (prev.tail if prev.tail else "") + node.tail
+ else:
+ prev = node.getparent()
+ if prev is not None:
+ prev.text = (prev.text if prev.text else "") + node.tail
+
+ node.getparent().remove(node)
+ lines = node.text.split("\n")
+ queue = []
+ got_anything = comments.get(last_non_comment) is not None
+ for line in lines:
+ line = line.strip()
+ if line or got_anything:
+ queue.append(line)
+ if line:
+ comments.setdefault(last_non_comment, []).extend(queue)
+ queue = []
+ got_anything = True
+ else:
+ last_non_comment = node
+_process(root)
+
diff --git a/envytools/util/.gitignore b/envytools/util/.gitignore
new file mode 100644
index 0000000..44f11fb
--- /dev/null
+++ b/envytools/util/.gitignore
@@ -0,0 +1,2 @@
+libenvyutil.a
+libenvyutil.so
diff --git a/envytools/util/CMakeLists.txt b/envytools/util/CMakeLists.txt
new file mode 100644
index 0000000..f0f2b03
--- /dev/null
+++ b/envytools/util/CMakeLists.txt
@@ -0,0 +1,12 @@
+project(ENVYTOOLS C)
+cmake_minimum_required(VERSION 2.6)
+
+add_library(envyutil
+ path.c mask.c hash.c symtab.c colors.c yy.c astr.c aprintf.c
+ vardata.c varinfo.c varselect.c
+)
+
+install(TARGETS envyutil
+ RUNTIME DESTINATION bin
+ LIBRARY DESTINATION lib${LIB_SUFFIX}
+ ARCHIVE DESTINATION lib${LIB_SUFFIX})
diff --git a/envytools/util/aprintf.c b/envytools/util/aprintf.c
new file mode 100644
index 0000000..462fc3f
--- /dev/null
+++ b/envytools/util/aprintf.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2009-2011 Marcin Kościelnicki <koriakin@0x04.net>
+ * 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
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS 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.
+ */
+
+#include "util.h"
+#include <stdarg.h>
+
+char *aprintf(const char *format, ...) {
+ va_list va;
+ va_start(va, format);
+ size_t sz = vsnprintf(0, 0, format, va);
+ va_end(va);
+ char *res = malloc(sz + 1);
+ va_start(va, format);
+ vsnprintf(res, sz + 1, format, va);
+ va_end(va);
+ return res;
+}
diff --git a/envytools/util/astr.c b/envytools/util/astr.c
new file mode 100644
index 0000000..313cd17
--- /dev/null
+++ b/envytools/util/astr.c
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2012 Marcin Kościelnicki <koriakin@0x04.net>
+ * 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
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS 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.
+ */
+
+#include "util.h"
+
+void print_escaped_astr(FILE *out, struct astr *astr) {
+ int i;
+ fprintf(out, "\"");
+ for (i = 0; i < astr->len; i++) {
+ unsigned char c = astr->str[i];
+ switch (c) {
+ case '\\':
+ fprintf(out, "\\\\");
+ break;
+ case '\"':
+ fprintf(out, "\\\"");
+ break;
+ case '\n':
+ fprintf(out, "\\n");
+ break;
+ case '\f':
+ fprintf(out, "\\f");
+ break;
+ case '\t':
+ fprintf(out, "\\t");
+ break;
+ case '\a':
+ fprintf(out, "\\a");
+ break;
+ case '\v':
+ fprintf(out, "\\v");
+ break;
+ case '\r':
+ fprintf(out, "\\r");
+ break;
+ default:
+ if (c >= 0x20 && c <= 0x7e) {
+ fprintf(out, "%c", c);
+ } else {
+ fprintf(out, "\\x%02x", c);
+ }
+ break;
+ }
+ }
+ fprintf(out, "\"");
+}
diff --git a/envytools/util/colors.c b/envytools/util/colors.c
new file mode 100644
index 0000000..3019ccf
--- /dev/null
+++ b/envytools/util/colors.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2012 Marcin Kościelnicki <koriakin@0x04.net>
+ * 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
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS 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.
+ */
+
+#include "colors.h"
+
+const struct envy_colors envy_null_colors = {
+ .reset = "",
+ .iname = "",
+ .rname = "",
+ .mod = "",
+ .sym = "",
+ .reg = "",
+ .regsp = "",
+ .num = "",
+ .mem = "",
+ .btarg = "",
+ .ctarg = "",
+ .bctarg = "",
+ .eval = "",
+ .comm = "",
+ .err = "",
+};
+
+const struct envy_colors envy_def_colors = {
+ .reset = "\x1b[0m",
+ .iname = "\x1b[0;32m",
+ .rname = "\x1b[0;32m",
+ .mod = "\x1b[0;36m",
+ .sym = "\x1b[0;36m",
+ .reg = "\x1b[0;31m",
+ .regsp = "\x1b[0;35m",
+ .num = "\x1b[0;33m",
+ .mem = "\x1b[0;35m",
+ .btarg = "\x1b[0;35m",
+ .ctarg = "\x1b[0;1;37m",
+ .bctarg = "\x1b[0;1;35m",
+ .eval = "\x1b[0;35m",
+ .comm = "\x1b[0;34m",
+ .err = "\x1b[0;1;31m",
+};
diff --git a/envytools/util/hash.c b/envytools/util/hash.c
new file mode 100644
index 0000000..3fd934f
--- /dev/null
+++ b/envytools/util/hash.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2011 Marcin Kościelnicki <koriakin@0x04.net>
+ * 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
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS 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.
+ */
+
+#include "util.h"
+
+uint32_t elf_hash(const char *str) {
+ const unsigned char *ustr = (const unsigned char *)str;
+ uint32_t h = 0;
+ while (*ustr) {
+ h <<= 4;
+ h += *ustr++;
+ h ^= (h >> 24) & 0xf0;
+ h &= 0xfffffff;
+ }
+ return h;
+}
+
diff --git a/envytools/util/mask.c b/envytools/util/mask.c
new file mode 100644
index 0000000..94e3a2f
--- /dev/null
+++ b/envytools/util/mask.c
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2011 Marcin Kościelnicki <koriakin@0x04.net>
+ * 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
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS 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.
+ */
+
+#include "mask.h"
+
+void mask_or(uint32_t *dmask, uint32_t *smask, int size) {
+ int rsize = MASK_SIZE(size);
+ int i;
+ for (i = 0; i < rsize; i++)
+ dmask[i] |= smask[i];
+}
+int mask_or_r(uint32_t *dmask, uint32_t *smask, int size) {
+ int rsize = MASK_SIZE(size);
+ int i;
+ int res = 0;
+ for (i = 0; i < rsize; i++) {
+ uint32_t n = dmask[i] | smask[i];
+ if (n != dmask[i])
+ res = 1;
+ dmask[i] = n;
+ }
+ return res;
+}
+
+int mask_intersect(uint32_t *a, uint32_t *b, int size) {
+ int rsize = MASK_SIZE(size);
+ int i;
+ for (i = 0; i < rsize; i++)
+ if (a[i] & b[i]) {
+ int j;
+ for (j = 0; j < MASK_CHUNK_SIZE; j++)
+ if (a[i] & b[i] & (uint32_t)1 << j)
+ return j;
+ }
+ return -1;
+}
+
+int mask_contains(uint32_t *a, uint32_t *b, int size) {
+ int rsize = MASK_SIZE(size);
+ int i;
+ for (i = 0; i < rsize; i++)
+ if ((a[i] & b[i]) != b[i]) {
+ return 0;
+ }
+ return 1;
+}
+
+void mask_print(FILE *out, uint32_t *mask, int size) {
+ int rsize = MASK_SIZE(size);
+ int i;
+ for (i = 0; i < rsize; i++) {
+ if (i)
+ fprintf(out, " ");
+ fprintf (out, "%08"PRIx32, mask[i]);
+ }
+}
diff --git a/envytools/util/path.c b/envytools/util/path.c
new file mode 100644
index 0000000..fe1d59e
--- /dev/null
+++ b/envytools/util/path.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2011 Marcin Kościelnicki <koriakin@0x04.net>
+ * 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
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS 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.
+ */
+
+#include "util.h"
+#include <string.h>
+
+FILE *find_in_path(const char *name, const char *path, char **pfullname) {
+ if (!path)
+ return 0;
+ while (path) {
+ const char *npath = strchr(path, ':');
+ size_t plen;
+ if (npath) {
+ plen = npath - path;
+ npath++;
+ } else {
+ plen = strlen(path);
+ }
+ if (plen) {
+ char *fullname = malloc(strlen(name) + plen + 2);
+ strncpy(fullname, path, plen);
+ fullname[plen] = '/';
+ fullname[plen+1] = 0;
+ strcat(fullname, name);
+ FILE *file = fopen(fullname, "r");
+ if (file) {
+ if (pfullname)
+ *pfullname = fullname;
+ else
+ free(fullname);
+ return file;
+ }
+ free(fullname);
+ }
+ path = npath;
+ }
+ return 0;
+}
diff --git a/envytools/util/symtab.c b/envytools/util/symtab.c
new file mode 100644
index 0000000..99e1cd9
--- /dev/null
+++ b/envytools/util/symtab.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2011 Marcin Kościelnicki <koriakin@0x04.net>
+ * 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
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS 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.
+ */
+
+#include "symtab.h"
+#include "util.h"
+#include <stdlib.h>
+#include <string.h>
+
+/* the last one is not a prime - elf hash only goes up to 2^28-1, no point in having more buckets */
+static const int primes[] = { 127, 509, 2039, 8191, 32749, 131071, 524287, 2097143, 8388593, 33554393, 134217689, 268435456 };
+static const int numprimes = sizeof primes / sizeof *primes;
+
+struct symtab *symtab_new() {
+ int i;
+ struct symtab *res = calloc(sizeof *res, 1);
+ res->bucketsnum = primes[0];
+ res->buckets = malloc(sizeof *res->buckets * res->bucketsnum);
+ for (i = 0; i < res->bucketsnum; i++)
+ res->buckets[i] = -1;
+ return res;
+}
+
+void symtab_del(struct symtab *tab) {
+ int i;
+ for (i = 0; i < tab->symsnum; i++)
+ free(tab->syms[i].name);
+ free(tab->buckets);
+ free(tab->syms);
+ free(tab);
+}
+
+int symtab_get(struct symtab *tab, const char *name, int *ptype, int *pdata) {
+ int i = tab->buckets[elf_hash(name) % tab->bucketsnum];
+ while (i != -1) {
+ if (!strcmp(tab->syms[i].name, name)) {
+ if (ptype)
+ *ptype = tab->syms[i].type;
+ if (pdata)
+ *pdata = tab->syms[i].data;
+ return i;
+ }
+ i = tab->syms[i].hchain;
+ }
+ return -1;
+}
+
+int symtab_get_t(struct symtab *tab, const char *name, int type, int *pdata) {
+ int rtype;
+ int res = symtab_get(tab, name, &rtype, pdata);
+ if (res == -1)
+ return res;
+ if (rtype != type)
+ return -1;
+ return res;
+}
+
+int symtab_put(struct symtab *tab, const char *cname, int type, int data) {
+ if (symtab_get(tab, cname, 0, 0) != -1)
+ return -1;
+ char *name = strdup(cname);
+ struct symtab_sym sym;
+ uint32_t hash = elf_hash(name);
+ int bucket = hash % tab->bucketsnum;
+ int res = tab->symsnum;
+ sym.name = name;
+ sym.type = type;
+ sym.data = data;
+ sym.hash = hash;
+ sym.hchain = tab->buckets[bucket];
+ tab->buckets[bucket] = res;
+ ADDARRAY(tab->syms, sym);
+ if (tab->symsnum > tab->bucketsnum && tab->bucketsnum != primes[numprimes-1]) {
+ /* rehash */
+ int i;
+ free(tab->buckets);
+ for (i = 0; i < numprimes-1; i++)
+ if (tab->symsnum <= primes[i])
+ break;
+ tab->bucketsnum = primes[i];
+ tab->buckets = malloc(tab->bucketsnum * sizeof *tab->buckets);
+ for (i = 0; i < tab->bucketsnum; i++)
+ tab->buckets[i] = -1;
+ for (i = 0; i < tab->symsnum; i++) {
+ bucket = tab->syms[i].hash % tab->bucketsnum;
+ tab->syms[i].hchain = tab->buckets[bucket];
+ tab->buckets[bucket] = i;
+ }
+ }
+ return res;
+}
diff --git a/envytools/util/vardata.c b/envytools/util/vardata.c
new file mode 100644
index 0000000..5295553
--- /dev/null
+++ b/envytools/util/vardata.c
@@ -0,0 +1,231 @@
+/*
+ * Copyright (C) 2012 Marcin Kościelnicki <koriakin@0x04.net>
+ * 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
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS 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.
+ */
+
+#include "var.h"
+
+struct vardata *vardata_new(const char *name) {
+ struct vardata *res = calloc(sizeof *res, 1);
+ res->name = strdup(name);
+ res->symtab = symtab_new();
+ return res;
+}
+
+void vardata_del(struct vardata *data) {
+ int i;
+ free(data->name);
+ for (i = 0; i < data->featuresnum; i++) {
+ free(data->features[i].name);
+ free(data->features[i].description);
+ free(data->features[i].ifmask);
+ free(data->features[i].cfmask);
+ free(data->features[i].implies);
+ free(data->features[i].conflicts);
+ }
+ free(data->features);
+ for (i = 0; i < data->variantsnum; i++) {
+ free(data->variants[i].name);
+ free(data->variants[i].description);
+ free(data->variants[i].fmask);
+ free(data->variants[i].features);
+ }
+ free(data->variants);
+ for (i = 0; i < data->varsetsnum; i++) {
+ free(data->varsets[i].name);
+ free(data->varsets[i].description);
+ }
+ free(data->varsets);
+ for (i = 0; i < data->modesnum; i++) {
+ free(data->modes[i].name);
+ free(data->modes[i].description);
+ free(data->modes[i].rfmask);
+ free(data->modes[i].rfeatures);
+ }
+ free(data->modes);
+ for (i = 0; i < data->modesetsnum; i++) {
+ free(data->modesets[i].name);
+ free(data->modesets[i].description);
+ }
+ free(data->modesets);
+ symtab_del(data->symtab);
+ free(data);
+}
+
+int vardata_add_feature(struct vardata *data, const char *name, const char *description) {
+ if (data->validated)
+ abort();
+ if (symtab_put(data->symtab, name, VARDATA_ST_FEATURE, data->featuresnum) == -1)
+ return -1;
+ int res = data->featuresnum;
+ struct vardata_feature new = { strdup(name) };
+ if (description)
+ new.description = strdup(description);
+ ADDARRAY(data->features, new);
+ return res;
+}
+
+int vardata_add_varset(struct vardata *data, const char *name, const char *description) {
+ if (data->validated)
+ abort();
+ if (symtab_put(data->symtab, name, VARDATA_ST_VARSET, data->varsetsnum) == -1)
+ return -1;
+ int res = data->varsetsnum;
+ struct vardata_varset new = { strdup(name) };
+ if (description)
+ new.description = strdup(description);
+ ADDARRAY(data->varsets, new);
+ return res;
+}
+
+int vardata_add_variant(struct vardata *data, const char *name, const char *description, int varset) {
+ if (data->validated)
+ abort();
+ if (symtab_put(data->symtab, name, VARDATA_ST_VARIANT, data->variantsnum) == -1)
+ return -1;
+ int res = data->variantsnum;
+ struct vardata_variant new = { strdup(name), .varset = varset };
+ if (description)
+ new.description = strdup(description);
+ ADDARRAY(data->variants, new);
+ return res;
+}
+
+int vardata_add_modeset(struct vardata *data, const char *name, const char *description) {
+ if (data->validated)
+ abort();
+ if (symtab_put(data->symtab, name, VARDATA_ST_MODESET, data->modesetsnum) == -1)
+ return -1;
+ int res = data->modesetsnum;
+ struct vardata_modeset new = { strdup(name), .defmode = -1 };
+ if (description)
+ new.description = strdup(description);
+ ADDARRAY(data->modesets, new);
+ return res;
+}
+
+int vardata_add_mode(struct vardata *data, const char *name, const char *description, int modeset) {
+ if (data->validated)
+ abort();
+ if (symtab_put(data->symtab, name, VARDATA_ST_MODE, data->modesnum) == -1)
+ return -1;
+ int res = data->modesnum;
+ struct vardata_mode new = { strdup(name), .modeset = modeset };
+ if (description)
+ new.description = strdup(description);
+ ADDARRAY(data->modes, new);
+ return res;
+}
+
+void vardata_feature_imply(struct vardata *data, int f1, int f2) {
+ ADDARRAY(data->features[f1].implies, f2);
+}
+
+void vardata_feature_conflict(struct vardata *data, int f1, int f2) {
+ ADDARRAY(data->features[f1].conflicts, f2);
+}
+
+void vardata_variant_feature(struct vardata *data, int v, int f) {
+ ADDARRAY(data->variants[v].features, f);
+}
+
+void vardata_mode_require(struct vardata *data, int m, int f) {
+ ADDARRAY(data->modes[m].rfeatures, f);
+}
+
+int vardata_modeset_def(struct vardata *data, int ms, int m) {
+ if (data->modesets[ms].defmode != -1 || data->modes[m].modeset != ms)
+ return -1;
+ data->modesets[ms].defmode = m;
+ return 0;
+}
+
+int vardata_validate(struct vardata *data) {
+ int res = 0;
+ if (data->validated)
+ abort();
+ data->validated = 1;
+ int i, j;
+ for (i = 0; i < data->featuresnum; i++) {
+ data->features[i].ifmask = mask_new(data->featuresnum);
+ data->features[i].cfmask = mask_new(data->featuresnum);
+ mask_set(data->features[i].ifmask, i);
+ }
+ for (i = 0; i < data->variantsnum; i++) {
+ data->variants[i].fmask = mask_new(data->featuresnum);
+ }
+ for (i = 0; i < data->modesnum; i++) {
+ data->modes[i].rfmask = mask_new(data->featuresnum);
+ }
+ /* implies */
+ for (i = 0; i < data->featuresnum; i++) {
+ for (j = 0; j < data->features[i].impliesnum; j++) {
+ int k = data->features[i].implies[j];
+ int l;
+ for (l = 0; l < data->featuresnum; l++) {
+ if (mask_get(data->features[l].ifmask, i)) {
+ mask_or(data->features[l].ifmask, data->features[k].ifmask, data->featuresnum);
+ }
+ }
+ }
+ }
+ /* conflicts */
+ for (i = 0; i < data->featuresnum; i++) {
+ for (j = 0; j < data->features[i].conflictsnum; j++) {
+ int k = data->features[i].conflicts[j];
+ mask_set(data->features[i].cfmask, k);
+ mask_set(data->features[k].cfmask, i);
+ }
+ }
+ int p = 1;
+ while (p) {
+ p = 0;
+ for (i = 0; i < data->featuresnum; i++) {
+ for (j = 0; j < data->featuresnum; j++) {
+ if (mask_get(data->features[i].ifmask, j)) {
+ p |= mask_or_r(data->features[i].cfmask, data->features[j].cfmask, data->featuresnum);
+ }
+ }
+ }
+ }
+ for (i = 0; i < data->featuresnum; i++) {
+ if (mask_get(data->features[i].cfmask, i)) {
+ fprintf(stderr, "vardata %s: feature %s conflicts with itself!\n", data->name, data->features[i].name);
+ res = 1;
+ }
+ }
+ /* variants */
+ for (i = 0; i < data->variantsnum; i++) {
+ for (j = 0; j < data->variants[i].featuresnum; j++) {
+ int k = data->variants[i].features[j];
+ mask_or(data->variants[i].fmask, data->features[k].ifmask, data->featuresnum);
+ }
+ }
+ /* variants */
+ for (i = 0; i < data->modesnum; i++) {
+ for (j = 0; j < data->modes[i].rfeaturesnum; j++) {
+ int k = data->modes[i].rfeatures[j];
+ mask_set(data->modes[i].rfmask, k);
+ }
+ }
+ return res;
+}
diff --git a/envytools/util/varinfo.c b/envytools/util/varinfo.c
new file mode 100644
index 0000000..2388d4f
--- /dev/null
+++ b/envytools/util/varinfo.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2012 Marcin Kościelnicki <koriakin@0x04.net>
+ * 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
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS 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.
+ */
+
+#include "var.h"
+
+struct varinfo *varinfo_new(struct vardata *data) {
+ struct varinfo *res = calloc(sizeof *res, 1);
+ int i;
+ res->data = data;
+ res->fmask = mask_new(data->featuresnum);
+ res->variants = calloc(sizeof *res->variants, data->varsetsnum);
+ for (i = 0; i < data->varsetsnum; i++)
+ res->variants[i] = -1;
+ res->modes = calloc(sizeof *res->modes, data->modesetsnum);
+ for (i = 0; i < data->modesetsnum; i++)
+ res->modes[i] = data->modesets[i].defmode;
+ return res;
+}
+
+void varinfo_del(struct varinfo *info) {
+ free(info->fmask);
+ free(info->variants);
+ free(info->modes);
+ free(info);
+}
+
+int varinfo_set_variant(struct varinfo *info, const char *variant) {
+ int data;
+ if (symtab_get_t(info->data->symtab, variant, VARDATA_ST_VARIANT, &data) == -1) {
+ fprintf(stderr, "no variant %s\n", variant);
+ return -1;
+ }
+ int varset = info->data->variants[data].varset;
+ if (info->variants[varset] != -1 && info->variants[varset] != data) {
+ fprintf(stderr, "a variant from varset %s has already been selected\n", info->data->varsets[varset].name);
+ return -1;
+ }
+ int i;
+ for (i = 0; i < info->data->featuresnum; i++) {
+ if (mask_get(info->fmask, i) && mask_intersect(info->data->features[i].cfmask, info->data->variants[data].fmask, info->data->featuresnum) != -1) {
+ fprintf(stderr, "variant %s conflicts with feature %s\n", info->data->variants[data].name, info->data->features[i].name);
+ return -1;
+ }
+ }
+ info->variants[varset] = data;
+ mask_or(info->fmask, info->data->variants[data].fmask, info->data->featuresnum);
+ return 0;
+}
+
+int varinfo_set_feature(struct varinfo *info, const char *feature) {
+ int data;
+ if (symtab_get_t(info->data->symtab, feature, VARDATA_ST_FEATURE, &data) == -1) {
+ fprintf(stderr, "no feature %s\n", feature);
+ return -1;
+ }
+ int cf;
+ if ((cf = mask_intersect(info->data->features[data].cfmask, info->fmask, info->data->featuresnum)) != -1) {
+ fprintf(stderr, "feature %s conflicts with already set feature %s\n", info->data->features[data].name, info->data->features[cf].name);
+ return -1;
+ }
+ mask_or(info->fmask, info->data->features[data].ifmask, info->data->featuresnum);
+ return 0;
+}
+
+int varinfo_set_mode(struct varinfo *info, const char *mode) {
+ int data;
+ if (symtab_get_t(info->data->symtab, mode, VARDATA_ST_MODE, &data) == -1) {
+ fprintf(stderr, "no mode %s\n", mode);
+ return -1;
+ }
+ int modeset = info->data->modes[data].modeset;
+ if (info->modes[modeset] != -1 && info->modes[modeset] != data) {
+ fprintf(stderr, "a mode from modeset %s has already been selected\n", info->data->modesets[modeset].name);
+ return -1;
+ }
+ info->modes[modeset] = data;
+ /* XXX: validate mode */
+ return 0;
+}
diff --git a/envytools/util/varselect.c b/envytools/util/varselect.c
new file mode 100644
index 0000000..11a70c9
--- /dev/null
+++ b/envytools/util/varselect.c
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2012 Marcin Kościelnicki <koriakin@0x04.net>
+ * 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
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS 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.
+ */
+
+#include "var.h"
+
+struct varselect *varselect_new(struct vardata *data) {
+ struct varselect *res = calloc(sizeof *res, 1);
+ res->data = data;
+ res->fmask = mask_new(data->featuresnum);
+ res->msmask = mask_new(data->modesetsnum);
+ res->mmask = mask_new(data->modesnum);
+ res->vsmask = mask_new(data->varsetsnum);
+ res->vmask = mask_new(data->variantsnum);
+ return res;
+}
+
+void varselect_del(struct varselect *select) {
+ free(select->fmask);
+ free(select->msmask);
+ free(select->mmask);
+ free(select->vsmask);
+ free(select->vmask);
+ free(select);
+}
+
+void varselect_need_feature(struct varselect *select, int f) {
+ mask_set(select->fmask, f);
+}
+
+void varselect_need_mode(struct varselect *select, int m) {
+ mask_set(select->msmask, select->data->modes[m].modeset);
+ mask_set(select->mmask, m);
+}
+
+void varselect_need_variant(struct varselect *select, int v) {
+ mask_set(select->vsmask, select->data->variants[v].varset);
+ mask_set(select->vmask, v);
+}
+
+int varselect_match(struct varselect *select, struct varinfo *info) {
+ if (!select)
+ return 1;
+ if (select->data != info->data)
+ abort();
+ if (!mask_contains(info->fmask, select->fmask, info->data->featuresnum))
+ return 0;
+ int i;
+ for (i = 0; i < info->data->varsetsnum; i++) {
+ if (mask_get(select->vsmask, i)) {
+ if (info->variants[i] == -1) {
+ fprintf(stderr, "Warning: don't know variant from varset %s, assuming a match\n", info->data->varsets[i].name);
+ } else if (!mask_get(select->vmask, info->variants[i])) {
+ return 0;
+ }
+ }
+ }
+ for (i = 0; i < info->data->modesetsnum; i++) {
+ if (mask_get(select->msmask, i)) {
+ if (info->modes[i] == -1) {
+ if (info->data->modesets[i].defmode == -1) {
+ fprintf(stderr, "Warning: don't know mode from modeset %s, assuming a match\n", info->data->modesets[i].name);
+ } else if (!mask_get(select->mmask, info->data->modesets[i].defmode)) {
+ return 0;
+ }
+ } else if (!mask_get(select->mmask, info->modes[i])) {
+ return 0;
+ }
+ }
+ }
+ return 1;
+}
diff --git a/envytools/util/yy.c b/envytools/util/yy.c
new file mode 100644
index 0000000..fffb177
--- /dev/null
+++ b/envytools/util/yy.c
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2011-2012 Marcin Kościelnicki <koriakin@0x04.net>
+ * 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
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS 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.
+ */
+
+#include "yy.h"
+#include <assert.h>
+
+void yy_lex_common(struct yy_lex_intern *x, YYLTYPE *loc, const char *str) {
+ int i;
+ loc->lstart = x->line;
+ loc->cstart = x->pos;
+ for (i = 0; str[i]; i++) {
+ if (str[i] == '\n') {
+ x->pos = 1;
+ x->line++;
+ } else {
+ x->pos++;
+ }
+ }
+ loc->lend = x->line;
+ loc->cend = x->pos;
+ loc->file = x->file;
+}
+
+static int gethex(char c) {
+ if (c >= '0' && c <= '9')
+ return c - '0';
+ if (c >= 'a' && c <= 'f')
+ return c - 'a' + 0xa;
+ if (c >= 'A' && c <= 'F')
+ return c - 'A' + 0xa;
+ assert(0);
+}
+
+void yy_str_deescape(const char *str, struct astr *astr) {
+ int rlen = 0;
+ int i;
+ for (i = 0; str[i]; i++) {
+ if (str[i] == '\\') {
+ i++;
+ rlen++;
+ if (str[i] == 'x')
+ i += 2;
+ } else if (str[i] != '"') {
+ rlen++;
+ }
+ }
+ char *res = malloc (rlen + 1);
+ int j;
+ for (i = 0, j = 0; str[i]; i++) {
+ if (str[i] == '\\') {
+ i++;
+ switch (str[i]) {
+ case '\\':
+ case '\'':
+ case '\"':
+ case '\?':
+ res[j++] = str[i];
+ break;
+ case 'n':
+ res[j++] = '\n';
+ break;
+ case 'f':
+ res[j++] = '\f';
+ break;
+ case 't':
+ res[j++] = '\t';
+ break;
+ case 'a':
+ res[j++] = '\a';
+ break;
+ case 'v':
+ res[j++] = '\v';
+ break;
+ case 'r':
+ res[j++] = '\r';
+ break;
+ case 'x':
+ res[j++] = gethex(str[i+1]) << 4 | gethex(str[i+2]);
+ i += 2;
+ break;
+ default:
+ assert(0);
+ }
+ if (str[i] == 'x')
+ i += 2;
+ } else if (str[i] != '"') {
+ res[j++] = str[i];
+ }
+ }
+ res[j] = 0;
+ assert(j == rlen);
+ astr->len = rlen;
+ astr->str = res;
+}