diff options
author | Wladimir J. van der Laan <laanwj@gmail.com> | 2013-01-05 18:58:11 +0100 |
---|---|---|
committer | Wladimir J. van der Laan <laanwj@gmail.com> | 2013-01-05 19:31:17 +0100 |
commit | 967796763ae365ebbcecde0a9e0a793e350787ba (patch) | |
tree | 7626ed53689ee359e5af7a7dcf2804a2e4c3cb67 /envytools | |
parent | f6c0516605a8ac032e7560ffbffbb5f7b3bf91d2 (diff) |
prepare for include file generation from rnndb
Diffstat (limited to 'envytools')
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, ×tamp, &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; +} |