0c6b63479d
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
387 lines
No EOL
11 KiB
C++
387 lines
No EOL
11 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)
|
|
|
|
int g_soc_count;
|
|
int g_reg_count;
|
|
int g_field_count;
|
|
|
|
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;
|
|
}
|
|
|
|
bool lex_comp(const std::string& a, const std::string& b)
|
|
{
|
|
return std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end());
|
|
}
|
|
|
|
}
|
|
|
|
void fprint_copyright(FILE *f)
|
|
{
|
|
fprintf(f,"\
|
|
/***************************************************************************\n\
|
|
* __________ __ ___.\n\
|
|
* Open \\______ \\ ____ ____ | | _\\_ |__ _______ ___\n\
|
|
* Source | _// _ \\_/ ___\\| |/ /| __ \\ / _ \\ \\/ /\n\
|
|
* Jukebox | | ( <_> ) \\___| < | \\_\\ ( <_> > < <\n\
|
|
* Firmware |____|_ /\\____/ \\___ >__|_ \\|___ /\\____/__/\\_ \\\n\
|
|
* \\/ \\/ \\/ \\/ \\/\n\
|
|
* This file was automatically generated by hwemulgen, 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 gen_header(const std::string& filename)
|
|
{
|
|
FILE *f = fopen(filename.c_str(), "w");
|
|
if(f == NULL)
|
|
error("Cannot open file %s\n", filename.c_str());
|
|
fprint_copyright(f);
|
|
fprintf(f, "#ifndef __HWEMUL_SOC_HEADER__\n");
|
|
fprintf(f, "#define __HWEMUL_SOC_HEADER__\n");
|
|
fprintf(f, "\n");
|
|
fprintf(f, "#include \"stddef.h\"\n");
|
|
fprintf(f, "#include \"stdint.h\"\n");
|
|
|
|
fprintf(f, "\n\
|
|
#define HWEMUL_SOC_REG_HAS_SCT (1 << 0)\n\
|
|
\n\
|
|
struct hwemul_soc_reg_field_t\n\
|
|
{\n\
|
|
const char *name;\n\
|
|
unsigned short first_bit, last_bit;\n\
|
|
};\n\
|
|
\n\
|
|
struct hwemul_soc_reg_t\n\
|
|
{\n\
|
|
const char *name;\n\
|
|
uint32_t addr;\n\
|
|
uint32_t flags;\n\
|
|
size_t nr_fields;\n\
|
|
struct hwemul_soc_reg_field_t *fields_by_name[]; /* ordered by lexicographic order */\n\
|
|
};\n\
|
|
\n\
|
|
struct hwemul_soc_t\n\
|
|
{\n\
|
|
const char *name;\n\
|
|
size_t nr_regs;\n\
|
|
struct hwemul_soc_reg_t *regs_by_name[]; /* ordered by lexicographic order */\n\
|
|
};\n\
|
|
\n\
|
|
struct hwemul_soc_list_t\n\
|
|
{\n\
|
|
size_t nr_socs;\n\
|
|
struct hwemul_soc_t *socs[];\n\
|
|
};\n\
|
|
\n\
|
|
struct hwemul_soc_list_t *hwemul_get_soc_list(void);\n\
|
|
\n");
|
|
|
|
fprintf(f, "#endif\n");
|
|
fclose(f);
|
|
}
|
|
|
|
std::string extract_last_part(std::string s)
|
|
{
|
|
size_t pos = s.find_last_of("/\\");
|
|
if(pos != std::string::npos)
|
|
s = s.substr(pos + 1);
|
|
pos = s.find_last_of(".");
|
|
if(pos != std::string::npos)
|
|
s = s.substr(0, pos);
|
|
return s;
|
|
}
|
|
|
|
std::vector< std::string > gen_fields(FILE *f, std::string prefix,
|
|
const std::vector< soc_reg_field_t >& fields)
|
|
{
|
|
std::vector< std::string > list;
|
|
|
|
for(size_t i = 0; i < fields.size(); i++)
|
|
{
|
|
g_field_count++;
|
|
std::string var_name = prefix + tolower(fields[i].name);
|
|
list.push_back(var_name);
|
|
|
|
fprintf(f, "\
|
|
static struct hwemul_soc_reg_field_t %s =\n\
|
|
{\n\
|
|
\"%s\",\n\
|
|
%d, %d\n\
|
|
};\n\
|
|
\n", var_name.c_str(), fields[i].name.c_str(), fields[i].first_bit, fields[i].last_bit);
|
|
}
|
|
|
|
return list;
|
|
}
|
|
|
|
std::vector< std::string > gen_common_regs(FILE *f, std::string prefix, std::string devname,
|
|
soc_addr_t devaddr, const std::vector< soc_reg_t >& regs,
|
|
const std::vector< soc_multireg_t >& multiregs)
|
|
{
|
|
std::vector< std::string > list;
|
|
|
|
for(size_t i = 0; i < regs.size(); i++)
|
|
{
|
|
g_reg_count++;
|
|
std::string var_name = prefix + tolower(regs[i].name);
|
|
|
|
list.push_back(var_name);
|
|
|
|
std::vector< std::string > field_vars = gen_fields(f, var_name + "_",
|
|
regs[i].fields);
|
|
|
|
std::sort(field_vars.begin(), field_vars.end(), lex_comp);
|
|
|
|
fprintf(f, "\
|
|
static struct hwemul_soc_reg_t %s =\n\
|
|
{\n\
|
|
\"HW_%s_%s\",\n\
|
|
%#x,\n\
|
|
0", var_name.c_str(), devname.c_str(), regs[i].name.c_str(), devaddr + regs[i].addr);
|
|
if(regs[i].flags & REG_HAS_SCT)
|
|
fprintf(f, " | HWEMUL_SOC_REG_HAS_SCT");
|
|
fprintf(f, ",\n");
|
|
fprintf(f, "\
|
|
%u,\n\
|
|
{", (unsigned)field_vars.size());
|
|
if(field_vars.size() != 0)
|
|
fprintf(f, "\n");
|
|
for(size_t j = 0; j < field_vars.size(); j++)
|
|
fprintf(f, " &%s,\n", field_vars[j].c_str());
|
|
if(field_vars.size() != 0)
|
|
fprintf(f, " ");
|
|
fprintf(f,"\
|
|
}\n};\n\
|
|
\n");
|
|
}
|
|
|
|
for(size_t i = 0; i < multiregs.size(); i++)
|
|
{
|
|
g_reg_count++;
|
|
std::vector< std::string > field_vars = gen_fields(f,
|
|
prefix + tolower(multiregs[i].name) + "_", multiregs[i].fields);
|
|
std::sort(field_vars.begin(), field_vars.end(), lex_comp);
|
|
|
|
for(size_t j = 0; j < multiregs[i].regs.size(); j++)
|
|
{
|
|
g_reg_count++;
|
|
std::string var_name = prefix + tolower(multiregs[i].regs[j].name);
|
|
|
|
list.push_back(var_name);
|
|
|
|
fprintf(f, "\
|
|
static struct hwemul_soc_reg_t %s =\n\
|
|
{\n\
|
|
\"HW_%s_%s\",\n\
|
|
%#x,\n\
|
|
0", var_name.c_str(), devname.c_str(), multiregs[i].regs[j].name.c_str(), devaddr + multiregs[i].regs[j].addr);
|
|
if(multiregs[i].flags & REG_HAS_SCT)
|
|
fprintf(f, " | HWEMUL_SOC_REG_HAS_SCT");
|
|
fprintf(f, ",\n");
|
|
fprintf(f,"\
|
|
%u,\n\
|
|
{", (unsigned)field_vars.size());
|
|
if(field_vars.size() != 0)
|
|
fprintf(f, "\n");
|
|
for(size_t k = 0; k < field_vars.size(); k++)
|
|
fprintf(f, " &%s,\n", field_vars[k].c_str());
|
|
if(field_vars.size() != 0)
|
|
fprintf(f, " ");
|
|
fprintf(f,"\
|
|
}\n};\n\
|
|
\n");
|
|
}
|
|
}
|
|
|
|
return list;
|
|
}
|
|
|
|
std::vector< std::string > gen_dev_regs(FILE *f, std::string prefix, const soc_dev_t& dev)
|
|
{
|
|
return gen_common_regs(f, prefix + tolower(dev.name) + "_", dev.name, dev.addr,
|
|
dev.regs, dev.multiregs);
|
|
}
|
|
|
|
std::vector< std::string > gen_multidev_regs(FILE *f, std::string prefix, const soc_multidev_t& mdev)
|
|
{
|
|
std::vector< std::string > list;
|
|
|
|
for(size_t i = 0; i < mdev.devs.size(); i++)
|
|
{
|
|
std::vector< std::string > sub_list = gen_common_regs(f,
|
|
prefix + tolower(mdev.devs[i].name) + "_", mdev.devs[i].name,
|
|
mdev.devs[i].addr, mdev.regs, mdev.multiregs);
|
|
list.insert(list.end(), sub_list.begin(), sub_list.end());
|
|
}
|
|
|
|
return list;
|
|
}
|
|
|
|
std::vector< std::string > gen_regs(FILE *f, std::string prefix, const soc_t& soc)
|
|
{
|
|
std::vector< std::string > list;
|
|
|
|
for(size_t i = 0; i < soc.devs.size(); i++)
|
|
{
|
|
std::vector< std::string > sub_list = gen_dev_regs(f,
|
|
prefix, soc.devs[i]);
|
|
list.insert(list.end(), sub_list.begin(), sub_list.end());
|
|
}
|
|
|
|
for(size_t i = 0; i < soc.multidevs.size(); i++)
|
|
{
|
|
std::vector< std::string > sub_list = gen_multidev_regs(f,
|
|
prefix, soc.multidevs[i]);
|
|
list.insert(list.end(), sub_list.begin(), sub_list.end());
|
|
}
|
|
|
|
return list;
|
|
}
|
|
|
|
std::vector< std::string > gen_socs(FILE *f, std::string prefix, const std::vector< soc_t >& socs)
|
|
{
|
|
std::vector< std::string > list;
|
|
for(size_t i = 0; i < socs.size(); i++)
|
|
{
|
|
g_soc_count++;
|
|
std::string var_name = prefix + socs[i].name;
|
|
list.push_back(var_name);
|
|
|
|
std::vector< std::string > reg_vars = gen_regs(f, var_name + "_", socs[i]);
|
|
|
|
std::sort(reg_vars.begin(), reg_vars.end(), lex_comp);
|
|
|
|
fprintf(f, "\
|
|
static struct hwemul_soc_t %s =\n\
|
|
{\n\
|
|
\"%s\",\n\
|
|
%u,\n\
|
|
{\n", var_name.c_str(), socs[i].name.c_str(), (unsigned)reg_vars.size());
|
|
|
|
for(size_t j = 0; j < reg_vars.size(); j++)
|
|
fprintf(f, " &%s,\n", reg_vars[j].c_str());
|
|
fprintf(f, "\
|
|
}\n\
|
|
};\n\
|
|
\n");
|
|
}
|
|
|
|
return list;
|
|
}
|
|
|
|
void gen_impl(const std::string& filename, const std::vector< soc_t >& socs)
|
|
{
|
|
FILE *f = fopen(filename.c_str(), "w");
|
|
if(f == NULL)
|
|
error("Cannot open file %s\n", filename.c_str());
|
|
fprint_copyright(f);
|
|
std::string last_part = extract_last_part(filename);
|
|
fprintf(f, "#include \"%s.h\"\n\n", last_part.c_str());
|
|
|
|
std::vector< std::string > socs_var = gen_socs(f, "soc_", socs);
|
|
|
|
fprintf(f, "\
|
|
static struct hwemul_soc_list_t hwemul_soc_list =\n\
|
|
{\n\
|
|
%u,\n\
|
|
{", (unsigned) socs_var.size());
|
|
|
|
for(size_t i = 0; i < socs_var.size(); i++)
|
|
{
|
|
fprintf(f, "&%s", socs_var[i].c_str());
|
|
if(i + 1 != socs_var.size())
|
|
fprintf(f, ", ");
|
|
}
|
|
fprintf(f, "\
|
|
}\n\
|
|
};\n\
|
|
\n");
|
|
|
|
fprintf(f,"\
|
|
struct hwemul_soc_list_t *hwemul_get_soc_list(void)\n\
|
|
{\n\
|
|
return &hwemul_soc_list;\n\
|
|
}\n\
|
|
\n");
|
|
|
|
fclose(f);
|
|
}
|
|
|
|
void gen_files(const std::string& output, const std::vector< soc_t >& socs)
|
|
{
|
|
gen_header(output + ".h");
|
|
gen_impl(output + ".c", socs);
|
|
}
|
|
|
|
void usage()
|
|
{
|
|
printf("usage: headergen <desc file list> <output file prefix>\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++)
|
|
{
|
|
bool ret = parse_soc_desc(argv[i], socs);
|
|
if(!ret)
|
|
{
|
|
printf("Cannot parse '%s'\n", argv[i]);
|
|
return 1;
|
|
}
|
|
}
|
|
gen_files(argv[argc - 1], socs);
|
|
printf("%d socs, %d registers and %d fields dumped!\n", g_soc_count, g_reg_count, g_field_count);
|
|
return 0;
|
|
} |