mirror of
https://github.com/Rockbox/rockbox.git
synced 2025-10-14 02:27:39 -04:00
These tools allow one to read a register description in a XML file and to produce something useful out of it. Three example programs are written: - tester which simply prints the register tree - headergen which produces a set of headers with the #define - hwemulgen which produces something for the hwemul tool (to come) Change-Id: I52573688b29d5faeaf64ce7c5ffe08ee8db3d33c
274 lines
No EOL
9.4 KiB
C++
274 lines
No EOL
9.4 KiB
C++
/***************************************************************************
|
|
* __________ __ ___.
|
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
|
* \/ \/ \/ \/ \/
|
|
* $Id$
|
|
*
|
|
* Copyright (C) 2002 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 "desc_parser.hpp"
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <algorithm>
|
|
#include <map>
|
|
|
|
#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_dev_regs_base;
|
|
std::string g_soc_dev_reg_core_name;
|
|
|
|
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;
|
|
}
|
|
|
|
}
|
|
|
|
void fprint_copyright(FILE *f)
|
|
{
|
|
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\
|
|
*\n\
|
|
* Copyright (C) 2012 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");
|
|
}
|
|
|
|
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());
|
|
fprintf(f, "\n#include \"imx233.h\"\n");
|
|
}
|
|
else
|
|
fprintf(f, "#endif /* %s */\n", name.c_str());
|
|
}
|
|
|
|
void fprint_include_guard(FILE *f, bool begin)
|
|
{
|
|
std::string name = "__" + toupper(g_soc_name) + "__" + toupper(g_soc_dev)
|
|
+ "__H__";
|
|
fprint_include_guard_ex(f, begin, name);
|
|
}
|
|
|
|
void fprint_fields(FILE *f, const std::vector< soc_reg_field_t >& fields)
|
|
{
|
|
for(size_t i = 0; i < fields.size(); i++)
|
|
{
|
|
fprintf(f, "#define BM_%s_%s %#x\n", g_soc_dev_reg_core_name.c_str(),
|
|
fields[i].name.c_str(), fields[i].bitmask());
|
|
fprintf(f, "#define BP_%s_%s %d\n", g_soc_dev_reg_core_name.c_str(),
|
|
fields[i].name.c_str(), fields[i].first_bit);
|
|
fprintf(f, "#define BF_%s_%s(v) (((v) << %d) & %#x)\n",
|
|
g_soc_dev_reg_core_name.c_str(), fields[i].name.c_str(),
|
|
fields[i].first_bit, fields[i].bitmask());
|
|
if(fields[i].values.size() > 0)
|
|
{
|
|
fprintf(f, "#define BF_%s_%s_V(sym) ((BV_%s_%s__##sym << %d) & %#x)\n",
|
|
g_soc_dev_reg_core_name.c_str(), fields[i].name.c_str(),
|
|
g_soc_dev_reg_core_name.c_str(), fields[i].name.c_str(),
|
|
fields[i].first_bit, fields[i].bitmask());
|
|
}
|
|
for(size_t j = 0; j < fields[i].values.size(); j++)
|
|
{
|
|
fprintf(f, "#define BV_%s_%s__%s %#x\n", g_soc_dev_reg_core_name.c_str(),
|
|
fields[i].name.c_str(), fields[i].values[j].name.c_str(),
|
|
fields[i].values[j].value);
|
|
}
|
|
}
|
|
}
|
|
|
|
void fprint_reg(FILE *f, const soc_reg_t& reg)
|
|
{
|
|
g_soc_dev_reg_core_name = toupper(g_soc_dev) + "_" + toupper(reg.name);
|
|
|
|
fprintf(f, "#define RA_%s %#x\n", g_soc_dev_reg_core_name.c_str(), reg.addr);
|
|
fprintf(f, "#define HW_%s HW_REG(%s, %s)\n", g_soc_dev_reg_core_name.c_str(),
|
|
toupper(g_soc_dev).c_str(), toupper(reg.name).c_str());
|
|
if(reg.flags & REG_HAS_SCT)
|
|
{
|
|
fprintf(f, "#define HW_%s_SET HW_SET(%s, %s)\n", g_soc_dev_reg_core_name.c_str(),
|
|
toupper(g_soc_dev).c_str(), toupper(reg.name).c_str());
|
|
fprintf(f, "#define HW_%s_CLR HW_CLR(%s, %s)\n", g_soc_dev_reg_core_name.c_str(),
|
|
toupper(g_soc_dev).c_str(), toupper(reg.name).c_str());
|
|
fprintf(f, "#define HW_%s_TOG HW_TOG(%s, %s)\n", g_soc_dev_reg_core_name.c_str(),
|
|
toupper(g_soc_dev).c_str(), toupper(reg.name).c_str());
|
|
}
|
|
fprint_fields(f, reg.fields);
|
|
fprintf(f, "\n");
|
|
}
|
|
|
|
void fprint_mreg(FILE *f, const soc_multireg_t& mreg)
|
|
{
|
|
}
|
|
|
|
void gen_dev_header(const std::string& filename, const soc_dev_t& dev)
|
|
{
|
|
g_soc_dev = dev.name;
|
|
printf(" Generate header for device %s: write to %s\n", dev.name.c_str(),
|
|
filename.c_str());
|
|
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(f, true);
|
|
fprintf(f, "\n");
|
|
g_soc_dev_regs_base = "RB_" + toupper(dev.name);
|
|
fprintf(f, "#define %s %#x\n", g_soc_dev_regs_base.c_str(), dev.addr);
|
|
fprintf(f, "\n");
|
|
|
|
for(size_t i = 0; i < dev.regs.size(); i++)
|
|
fprint_reg(f, dev.regs[i]);
|
|
for(size_t i = 0; i < dev.multiregs.size(); i++)
|
|
fprint_mreg(f, dev.multiregs[i]);
|
|
|
|
fprint_include_guard(f, false);
|
|
fclose(f);
|
|
}
|
|
|
|
void gen_mdev_header(const std::string& filename, const soc_multidev_t& dev)
|
|
{
|
|
g_soc_dev = dev.name;
|
|
printf(" Generate header for multi device %s: write to %s\n", dev.name.c_str(),
|
|
filename.c_str());
|
|
}
|
|
|
|
void gen_soc_headers(const std::string& prefix, const soc_t& soc)
|
|
{
|
|
printf("Generate headers for soc %s: use directory %s (must exists)\n", soc.desc.c_str(),
|
|
prefix.c_str());
|
|
for(size_t i = 0; i < soc.devs.size(); i++)
|
|
{
|
|
std::string name = soc.devs[i].name;
|
|
name = tolower(name);
|
|
gen_dev_header(prefix + "/regs-" + name + ".h", soc.devs[i]);
|
|
}
|
|
for(size_t i = 0; i < soc.multidevs.size(); i++)
|
|
{
|
|
std::string name = soc.multidevs[i].name;
|
|
name = tolower(name);
|
|
gen_mdev_header(prefix + "/regs-" + name + ".h", soc.multidevs[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::string > > 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].devs.size(); j++)
|
|
map[tolower(socs[i].devs[j].name)].push_back(socs[i].name);
|
|
for(size_t j = 0; j < socs[i].multidevs.size(); j++)
|
|
map[tolower(socs[i].multidevs[j].name)].push_back(socs[i].name);
|
|
}
|
|
return map;
|
|
}
|
|
|
|
void gen_select_header(const std::string& filename, const std::string& dev,
|
|
const std::vector< std::string >& socs)
|
|
{
|
|
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);
|
|
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)
|
|
gen_select_header(prefix + "/regs-" + it->first + ".h", it->first, it->second);
|
|
}
|
|
|
|
void usage()
|
|
{
|
|
printf("usage: headergen <desc file> <output prefix>\n");
|
|
exit(1);
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
if(argc != 3)
|
|
usage();
|
|
std::vector< soc_t > socs;
|
|
bool ret = parse_soc_desc(argv[1], socs);
|
|
printf("parse result: %d\n", ret);
|
|
if(!ret) return 1;
|
|
gen_headers(argv[2], socs);
|
|
gen_selectors(argv[2], socs);
|
|
return 0;
|
|
} |