/*************************************************************************** * __________ __ ___. * Open \______ \ ____ ____ | | _\_ |__ _______ ___ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ * \/ \/ \/ \/ \/ * $Id$ * * Copyright (C) 2013 by Amaury Pouly * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ****************************************************************************/ #include "soc_desc.hpp" #include #include #include #include #include #include #include #define HEADERGEN_VERSION "2.1.7" #define error(...) do{ fprintf(stderr, __VA_ARGS__); exit(1); } while(0) std::string g_soc_name; std::string g_soc_dev; std::string g_soc_reg; std::string g_soc_field; std::string g_soc_dev_regs_base; namespace { std::string tolower(const std::string s) { std::string res = s; std::transform(res.begin(), res.end(), res.begin(), ::tolower); return res; } std::string toupper(const std::string& s) { std::string res = s; std::transform(res.begin(), res.end(), res.begin(), ::toupper); return res; } } template< typename T > std::string to_str(const T& v) { std::ostringstream oss; oss << v; return oss.str(); } template< typename T > std::string to_hex(const T& v) { std::ostringstream oss; oss << std::hex << v; return oss.str(); } typedef std::pair< std::string, std::string > xml_ver_t; void fprint_copyright(FILE *f, const std::vector< xml_ver_t >& versions) { std::ostringstream ver; for(size_t i = 0; i < versions.size(); i++) ver << " " << versions[i].first << ":" << versions[i].second; fprintf(f,"\ /***************************************************************************\n\ * __________ __ ___.\n\ * Open \\______ \\ ____ ____ | | _\\_ |__ _______ ___\n\ * Source | _// _ \\_/ ___\\| |/ /| __ \\ / _ \\ \\/ /\n\ * Jukebox | | ( <_> ) \\___| < | \\_\\ ( <_> > < <\n\ * Firmware |____|_ /\\____/ \\___ >__|_ \\|___ /\\____/__/\\_ \\\n\ * \\/ \\/ \\/ \\/ \\/\n\ * This file was automatically generated by headergen, DO NOT EDIT it.\n\ * headergen version: " HEADERGEN_VERSION "\n\ * XML versions:%s\n\ *\n\ * Copyright (C) 2013 by Amaury Pouly\n\ *\n\ * This program is free software; you can redistribute it and/or\n\ * modify it under the terms of the GNU General Public License\n\ * as published by the Free Software Foundation; either version 2\n\ * of the License, or (at your option) any later version.\n\ *\n\ * 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()); } void fprint_copyright(FILE *f, const xml_ver_t& version) { fprint_copyright(f, std::vector< xml_ver_t >(1, version)); } void fprint_include_guard_ex(FILE *f, bool begin, const std::string& name) { if(begin) { fprintf(f, "#ifndef %s\n", name.c_str()); fprintf(f, "#define %s\n", name.c_str()); } else fprintf(f, "#endif /* %s */\n", name.c_str()); } void fprint_include_guard(FILE *f, bool begin) { std::string name = "__HEADERGEN__" + toupper(g_soc_name) + "__" + toupper(g_soc_dev) + "__H__"; fprint_include_guard_ex(f, begin, name); } struct define_align_context_t { define_align_context_t():m_max_name(0) {} void add(const std::string& name, const std::string& val) { m_lines.push_back(std::make_pair(name, val)); m_max_name = std::max(m_max_name, name.size()); } void print(FILE *f) { std::string define = "#define "; size_t align = define.size() + m_max_name + 1; align = ((align + 3) / 4) * 4; for(size_t i = 0; i < m_lines.size(); i++) { std::string name = m_lines[i].first; name.insert(name.end(), align - define.size() - name.size(), ' '); fprintf(f, "%s%s%s\n", define.c_str(), name.c_str(), m_lines[i].second.c_str()); } } size_t m_max_name; std::vector< std::pair< std::string, std::string > > m_lines; }; void gen_soc_field(define_align_context_t& ctx, bool multidev, bool multireg, const soc_reg_field_t& field) { std::string prefix = g_soc_dev + "_" + g_soc_reg + "_" + g_soc_field; ctx.add("BP_" + prefix, to_str(field.first_bit)); ctx.add("BM_" + prefix, "0x" + to_hex(field.bitmask())); for(size_t i = 0; i < field.value.size(); i++) ctx.add("BV_" + prefix + "__" + field.value[i].name, "0x" + to_hex(field.value[i].value)); ctx.add("BF_" + prefix + "(v)", "(((v) << " + to_str(field.first_bit) + ") & 0x" + to_hex(field.bitmask()) + ")"); if(field.value.size() > 0) ctx.add("BF_" + prefix + "_V(v)", "((BV_" + prefix + "__##v" + " << " + to_str(field.first_bit) + ") & 0x" + to_hex(field.bitmask()) + ")"); } void gen_soc_reg(FILE *f, bool multidev, const soc_reg_t& reg) { bool multireg = reg.addr.size() > 1; static const char *suffix[] = {"", "_SET", "_CLR", "_TOG"}; bool sct = !!(reg.flags & REG_HAS_SCT); fprintf(f, "/**\n"); fprintf(f, " * Register: HW_%s_%s\n", g_soc_dev.c_str(), g_soc_reg.c_str()); fprintf(f, " * Address:"); if(multireg && reg.formula.type == REG_FORMULA_STRING) { fprintf(f, " %s\n", reg.formula.string.c_str()); } else { for(size_t i = 0; i < reg.addr.size(); i++) fprintf(f, " %#x", reg.addr[i].addr); fprintf(f, "\n"); } fprintf(f, " * SCT: %s\n", sct ? "yes" : "no"); fprintf(f, "*/\n"); define_align_context_t ctx; for(int i = 0; i < (sct ? 4 : 1); i++) { std::ostringstream name; name << "HW_" << g_soc_dev << "_" << g_soc_reg << suffix[i]; if(multidev || multireg) { name << "("; if(multidev) name << "d"; if(multidev && multireg) name << ","; if(multireg) name << "n"; name << ")"; } std::ostringstream value; value << "(*(volatile unsigned long *)(" << g_soc_dev_regs_base; if(multidev) value << "(d)"; value << " + "; if(multireg) { if(reg.formula.type != REG_FORMULA_STRING) printf("Warning: register HW_%s_%s has no formula !\n", g_soc_dev.c_str(), g_soc_reg.c_str()); std::string formula = reg.formula.string.c_str(); size_t pos = formula.find("n"); while(pos != std::string::npos) { formula.replace(pos, 1, "(n)"); pos = formula.find("n", pos + 2); } value << formula; } else value << "0x" << std::hex << reg.addr[0].addr; if(sct) value << " + 0x" << std::hex << (i * 4); value << "))"; ctx.add(name.str(), value.str()); } for(size_t i = 0; i < reg.field.size(); i++) { g_soc_field = reg.field[i].name; gen_soc_field(ctx, multidev, multireg, reg.field[i]); } ctx.print(f); fprintf(f, "\n"); } void gen_soc_dev_header(const std::string& filename, const xml_ver_t& ver, const soc_dev_t& dev) { /* printf("Generate headers for soc %s, dev %s: use file %s\n", g_soc_name.c_str(), g_soc_dev.c_str(), filename.c_str()); */ FILE *f = fopen(filename.c_str(), "w"); if(f == NULL) { printf("Cannot open %s for writing: %m\n", filename.c_str()); return; } fprint_copyright(f, ver); fprint_include_guard(f, true); /* print base */ fprintf(f, "\n"); g_soc_dev_regs_base = "REGS_" + g_soc_dev + "_BASE"; fprintf(f, "#define %s", g_soc_dev_regs_base.c_str()); if(dev.addr.size() > 1) fprintf(f, "(i)"); fprintf(f, " ("); for(size_t i = 0; i < dev.addr.size() - 1; i++) fprintf(f, "(i) == %d ? %#x : ", (int)i + 1, dev.addr[i].addr); fprintf(f, "%#x)\n", dev.addr[dev.addr.size() - 1].addr); fprintf(f, "\n"); /* print version */ fprintf(f, "#define REGS_%s_VERSION \"%s\"\n\n", g_soc_dev.c_str(), dev.version.c_str()); for(size_t i = 0; i < dev.reg.size(); i++) { g_soc_reg = dev.reg[i].name; gen_soc_reg(f, dev.addr.size() > 1, dev.reg[i]); } fprint_include_guard(f, false); fclose(f); } void gen_soc_headers(const std::string& prefix, const soc_t& soc) { printf("Generate headers for soc %s: use directory %s\n", soc.desc.c_str(), prefix.c_str()); mkdir(prefix.c_str(), 0770); for(size_t i = 0; i < soc.dev.size(); i++) { g_soc_dev = soc.dev[i].name; xml_ver_t ver(soc.name, soc.dev[i].version); gen_soc_dev_header(prefix + "/regs-" + tolower(g_soc_dev.c_str()) + ".h", ver, soc.dev[i]); } } 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]); } } typedef std::map< std::string, std::vector< std::pair< size_t, size_t > > > general_dev_list_t; general_dev_list_t build_general_dev_list(const std::vector< soc_t >& socs) { general_dev_list_t map; for(size_t i = 0; i < socs.size(); i++) { for(size_t j = 0; j < socs[i].dev.size(); j++) map[tolower(socs[i].dev[j].name)].push_back(std::make_pair(i,j)); } return map; } 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); fprintf(f, "\n"); for(size_t i = 0; i < socs.size(); i++) { fprintf(f, "#define %s_INCLUDE \"%s/regs-%s.h\"\n", toupper(socs[i]).c_str(), tolower(socs[i]).c_str(), tolower(dev).c_str()); } fprintf(f, "\n#include \"regs-select.h\"\n\n"); for(size_t i = 0; i < socs.size(); i++) { fprintf(f, "#undef %s_INCLUDE\n", toupper(socs[i]).c_str()); } fprintf(f, "\n"); fprint_include_guard_ex(f, false, guard); fclose(f); } void gen_selectors(const std::string& prefix, const std::vector< soc_t >& socs) { general_dev_list_t map = build_general_dev_list(socs); for(general_dev_list_t::iterator it = map.begin(); it != map.end(); ++it) { std::vector< xml_ver_t > ver; std::vector< std::string > names; for(size_t i = 0; i < it->second.size(); i++) { size_t soc_nr = it->second[i].first; size_t dev_in_soc_nr = it->second[i].second; ver.push_back(std::make_pair(socs[soc_nr].name, socs[soc_nr].dev[dev_in_soc_nr].version)); names.push_back(socs[soc_nr].name); } gen_select_header(prefix + "/regs-" + it->first + ".h", it->first, names, ver); } } void usage() { printf("usage: headergen \n"); exit(1); } int main(int argc, char **argv) { if(argc < 3) usage(); std::vector< soc_t > socs; for(int i = 1; i < argc - 1; i++) if(!soc_desc_parse_xml(argv[i], socs)) { printf("Cannot parse %s\n", argv[i]); return 1; } gen_headers(argv[argc - 1], socs); gen_selectors(argv[argc - 1], socs); return 0; }