From 97b9ade63945fd8b8261fb0cf1dd0aa225c1a319 Mon Sep 17 00:00:00 2001 From: Amaury Pouly Date: Thu, 13 Jun 2013 17:28:15 +0200 Subject: regtools: improve header generator The generator now has more options to generate or not selectors. It can also generate a macro header containing lots of using macros for register operations. Change-Id: I9dd6b4bdc7daeabd1a2c9365ce082358475721b5 --- utils/regtools/headergen.cpp | 227 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 214 insertions(+), 13 deletions(-) (limited to 'utils') diff --git a/utils/regtools/headergen.cpp b/utils/regtools/headergen.cpp index fc1ce6fba6..0a65388686 100644 --- a/utils/regtools/headergen.cpp +++ b/utils/regtools/headergen.cpp @@ -26,11 +26,16 @@ #include #include #include +#include #define HEADERGEN_VERSION "2.1.7" #define error(...) do{ fprintf(stderr, __VA_ARGS__); exit(1); } while(0) +bool g_gen_selector = false; + +std::string g_macro_filename; + std::string g_soc_name; std::string g_soc_dev; std::string g_soc_reg; @@ -86,8 +91,10 @@ void fprint_copyright(FILE *f, const std::vector< xml_ver_t >& versions) * Firmware |____|_ /\\____/ \\___ >__|_ \\|___ /\\____/__/\\_ \\\n\ * \\/ \\/ \\/ \\/ \\/\n\ * This file was automatically generated by headergen, DO NOT EDIT it.\n\ - * headergen version: " HEADERGEN_VERSION "\n\ - * XML versions:%s\n\ + * headergen version: " HEADERGEN_VERSION "\n"); + if(versions.size() > 0) + fprintf(f, " * XML versions:%s\n", ver.str().c_str()); + fprintf(f,"\ *\n\ * Copyright (C) 2013 by Amaury Pouly\n\ *\n\ @@ -99,8 +106,7 @@ void fprint_copyright(FILE *f, const std::vector< xml_ver_t >& versions) * This software is distributed on an \"AS IS\" basis, WITHOUT WARRANTY OF ANY\n\ * KIND, either express or implied.\n\ *\n\ - ****************************************************************************/\n", -ver.str().c_str()); + ****************************************************************************/\n"); } void fprint_copyright(FILE *f, const xml_ver_t& version) @@ -108,6 +114,11 @@ void fprint_copyright(FILE *f, const xml_ver_t& version) fprint_copyright(f, std::vector< xml_ver_t >(1, version)); } +void fprint_copyright(FILE *f) +{ + fprint_copyright(f, std::vector< xml_ver_t >()); +} + void fprint_include_guard_ex(FILE *f, bool begin, const std::string& name) { if(begin) @@ -262,6 +273,8 @@ void gen_soc_dev_header(const std::string& filename, const xml_ver_t& ver, const } fprint_copyright(f, ver); fprint_include_guard(f, true); + if(g_macro_filename.size() > 0) + fprintf(f, "#include \"%s\"\n", g_macro_filename.c_str()); /* print base */ fprintf(f, "\n"); @@ -311,7 +324,10 @@ void gen_headers(const std::string& prefix, const std::vector< soc_t >& socs) for(size_t i = 0; i < socs.size(); i++) { g_soc_name = socs[i].name; - gen_soc_headers(prefix + "/" + socs[i].name, socs[i]); + std::string dir = prefix; + if(g_gen_selector) + dir += "/" + socs[i].name; + gen_soc_headers(dir, socs[i]); } } @@ -330,16 +346,14 @@ general_dev_list_t build_general_dev_list(const std::vector< soc_t >& socs) void gen_select_header(const std::string& filename, const std::string& dev, const std::vector< std::string >& socs, const std::vector< xml_ver_t >& ver) { - /* - printf("Generate select header for device %s: write to %s\n", dev.c_str(), - filename.c_str()); - */ std::string guard = "__SELECT__" + toupper(dev) + "__H__"; FILE *f = fopen(filename.c_str(), "w"); if(f == NULL) error("Cannot open file %s\n", filename.c_str()); fprint_copyright(f, ver); fprint_include_guard_ex(f, true, guard); + if(g_macro_filename.size() > 0) + fprintf(f, "#include \"%s\"\n", g_macro_filename.c_str()); fprintf(f, "\n"); for(size_t i = 0; i < socs.size(); i++) @@ -360,6 +374,7 @@ void gen_select_header(const std::string& filename, const std::string& dev, void gen_selectors(const std::string& prefix, const std::vector< soc_t >& socs) { + printf("Generate select headers: use directory %s\n", prefix.c_str()); general_dev_list_t map = build_general_dev_list(socs); for(general_dev_list_t::iterator it = map.begin(); it != map.end(); ++it) { @@ -376,24 +391,210 @@ void gen_selectors(const std::string& prefix, const std::vector< soc_t >& socs) } } +void gen_macro_list(FILE *f, const std::string& prefix, int count, int nr_digits, + const std::string& sep, int max_per_line = 1000, const std::string& align = "") +{ + for(int i = 1; i <= count;) + { + for(int j = i; j <= std::min(count, i + max_per_line - 1); j++) + { + fprintf(f, "%s%0*d", prefix.c_str(), nr_digits, j); + if(j < count) + fprintf(f, "%s", sep.c_str()); + } + i += max_per_line; + if(i <= count) + fprintf(f, "\\\n%s", align.c_str()); + } +} + +void gen_macro(const std::string& filename, bool variadic) +{ + printf("Generate %smacro header: use %s\n", variadic ? "": "non-variadic ", + filename.c_str()); + std::string guard = "__REGS__MACRO__H__"; + FILE *f = fopen(filename.c_str(), "w"); + if(f == NULL) + error("Cannot open file %s\n", filename.c_str()); + fprint_copyright(f); + fprint_include_guard_ex(f, true, guard); + fprintf(f, "\n"); + +#define REG_WRITE "REG_WRITE" + fprintf(f, "#ifndef %s\n", REG_WRITE); + fprintf(f, "#define %s(var,value) ((var) = (value))\n", REG_WRITE); + fprintf(f, "#endif /* %s */\n", REG_WRITE); + fprintf(f, "\n"); + +#define REG_READ "REG_READ" + fprintf(f, "#ifndef %s\n", REG_READ); + fprintf(f, "#define %s(var) (var)\n", REG_READ); + fprintf(f, "#endif /* %s */\n", REG_READ); + fprintf(f, "\n"); + + const int MAX_NARGS = 32; + + fprintf(f, "\ +#define BF_SET(reg, field) "REG_WRITE"(HW_##reg##_SET, BM_##reg##_##field)\n\ +#define BF_CLR(reg, field) "REG_WRITE"(HW_##reg##_CLR, BM_##reg##_##field)\n\ +#define BF_TOG(reg, field) "REG_WRITE"(HW_##reg##_TOG, BM_##reg##_##field)\n\ +\n\ +#define BF_SETV(reg, field, v) "REG_WRITE"(HW_##reg##_SET, BF_##reg##_##field(v))\n\ +#define BF_CLRV(reg, field, v) "REG_WRITE"(HW_##reg##_CLR, BF_##reg##_##field(v))\n\ +#define BF_TOGV(reg, field, v) "REG_WRITE"(HW_##reg##_TOG, BF_##reg##_##field(v))\n\ +\n\ +#define BF_RDX(val, reg, field) (("REG_READ"(val) & BM_##reg##_##field) >> BP_##reg##_##field)\n\ +#define BF_RD(reg, field) BF_RDX("REG_READ"(HW_##reg), reg, field)\n\ +#define BF_WRX(val, reg, field, v) "REG_WRITE"(val, ("REG_READ"(val) & ~BM_##reg##_##field) | (((v) << BP_##reg##_##field) & BM_##reg##_##field))\n\ +#define BF_WR(reg, field, v) BF_WRX(HW_##reg, reg, field, v)\n\ +#define BF_WR_V(reg, field, sy) BF_WR(reg, field, BV_##reg##_##field##__##sy)\n\ +#define BF_WR_VX(val, reg, field, sy) BF_WRX(val, reg, field, BV_##reg##_##field##__##sy)\n\ +\n\ +#define BF_SETn(reg, n, field) "REG_WRITE"(HW_##reg##_SET(n), BM_##reg##_##field)\n\ +#define BF_CLRn(reg, n, field) "REG_WRITE"(HW_##reg##_CLR(n), BM_##reg##_##field)\n\ +#define BF_TOGn(reg, n, field) "REG_WRITE"(HW_##reg##_TOG(n), BM_##reg##_##field)\n\ +\n\ +#define BF_SETVn(reg, n, field, v) "REG_WRITE"(HW_##reg##_SET(n), BF_##reg##_##field(v))\n\ +#define BF_CLRVn(reg, n, field, v) "REG_WRITE"(HW_##reg##_CLR(n), BF_##reg##_##field(v))\n\ +#define BF_TOGVn(reg, n, field, v) "REG_WRITE"(HW_##reg##_TOG(n), BF_##reg##_##field(v))\n\ +\n\ +#define BF_RDn(reg, n, field) BF_RDX(HW_##reg(n), reg, field)\n\ +#define BF_WRn(reg, n, field, v) BF_WRX(HW_##reg(n), reg, field, v)\n\ +#define BF_WRn_V(reg, n, field, sy) BF_WRn(reg, n, field, BV_##reg##_##field##__##sy)\n\ +\n"); + + for(int nargs = 1; nargs <= MAX_NARGS; nargs++) + { + fprintf(f, "#define BM_OR%d(reg, ", nargs); + gen_macro_list(f, "f", nargs, 2, ", ", 10, " "); + fprintf(f, ") \\\n ("); + gen_macro_list(f, "BM_##reg##_##f", nargs, 2, " | ", 4, " "); + fprintf(f, ")\n"); + } + fprintf(f, "\n"); + + for(int nargs = 1; nargs <= MAX_NARGS; nargs++) + { + fprintf(f, "#define BF_OR%d(reg, ", nargs); + gen_macro_list(f, "f", nargs, 2, ", ", 10, " "); + fprintf(f, ") \\\n ("); + gen_macro_list(f, "BF_##reg##_##f", nargs, 2, " | ", 4, " "); + fprintf(f, ")\n"); + } + fprintf(f, "\n"); + + if(variadic) + { + fprintf(f, "#define REG_NARG(...) REG_NARGS_(__VA_ARGS__"); + for(int i = MAX_NARGS; i >= 1; i--) + fprintf(f, ", %d", i); + fprintf(f, ")\n"); + fprintf(f, "#define REG_NARGS_("); + gen_macro_list(f, "_", MAX_NARGS, 1, ", "); + fprintf(f, ", N, ...) N\n\n"); + + fprintf(f, "#define REG_VARIADIC(macro, reg, ...) REG_VARIADIC_(macro, NARG(__VA_ARGS__), reg, __VA_ARGS__)\n"); + fprintf(f, "#define REG_VARIADIC_(macro, cnt, reg, ...) REG_VARIADIC__(macro, cnt, reg, __VA_ARGS__)\n"); + fprintf(f, "#define REG_VARIADIC__(macro, cnt, reg, ...) REG_VARIADIC___(macro##cnt, reg, ...)\n"); + fprintf(f, "#define REG_VARIADIC___(macro, reg, ...) macro(reg, __VA_ARGS__)\n\n"); + + fprintf(f, "#define BM_OR(reg, ...) REG_VARIADIC(BM_OR, reg, __VA_ARGS__)\n"); + fprintf(f, "#define BF_OR(reg, ...) REG_VARIADIC(BF_OR, reg, __VA_ARGS__)\n"); + } + + fprint_include_guard_ex(f, false, guard); + fclose(f); +} + void usage() { - printf("usage: headergen \n"); + printf("usage: headergen [options] \n"); + printf("options:\n"); + printf(" -?/--help Dispaly this help\n"); + printf(" -s/--selector Always produce selector files\n"); + printf(" -m/--no-macro Do not generate a macro file with helpers\n"); + printf(" -i/--no-include Do not include the macro file in the headers\n"); + printf(" -v/--no-variadic Do not generate variadic macros\n"); + printf("Default option is to generate a macro file with variadic macros.\n"); + printf("Default option is to include the macro file in the headers.\n"); + printf("Default option is to generate selector files only for two or more socs.\n"); + printf("Default option is to create one subdirectory per soc, except if no\n"); + printf("selector files are needed. The subdirectories will be created if\n"); + printf("necessary.\n"); exit(1); } int main(int argc, char **argv) { - if(argc < 3) + bool force_selector = false; + bool no_variadic = false; + bool no_macro = false; + bool no_include = false; + if(argc <= 1) usage(); + + while(1) + { + static struct option long_options[] = + { + {"help", no_argument, 0, '?'}, + {"selector", no_argument, 0, 's'}, + {"no-macro", no_argument, 0, 'm'}, + {"no-include", no_argument, 0, 'i'}, + {"no-variadic", no_argument, 0, 'v'}, + {0, 0, 0, 0} + }; + + int c = getopt_long(argc, argv, "?smiv", long_options, NULL); + if(c == -1) + break; + switch(c) + { + case -1: + break; + case '?': + usage(); + break; + case 's': + force_selector = true; + break; + case 'm': + no_macro = true; + break; + case 'i': + no_include = true; + break; + case 'v': + no_variadic = true; + break; + default: + abort(); + } + } + std::vector< soc_t > socs; - for(int i = 1; i < argc - 1; i++) + for(int i = optind; i < argc - 1; i++) if(!soc_desc_parse_xml(argv[i], socs)) { printf("Cannot parse %s\n", argv[i]); return 1; } + + g_gen_selector = force_selector || socs.size() > 1; + + if(!no_macro) + { + g_macro_filename = std::string(argv[argc - 1]) + "/regs-macro.h"; + gen_macro(g_macro_filename, !no_variadic); + g_macro_filename = "regs-macro.h"; + if(no_include) + g_macro_filename.clear(); + } + if(g_gen_selector) + { + gen_selectors(argv[argc - 1], socs); + g_macro_filename.clear(); + } gen_headers(argv[argc - 1], socs); - gen_selectors(argv[argc - 1], socs); return 0; } \ No newline at end of file -- cgit v1.2.3