forked from len0rd/rockbox
regtools: modify description format and refactor tools
Change the XML description to unify multi dev/reg in a clean fashion. Move the description parser to its own library. Fix the tester and headergen tools to work with the new format and library. Move the STMP3700/3780 descriptions to the new format (and fixes many errors as well). Drop the hwemulgen tool in favor on the upcoming hwstub tools revamp. Change-Id: I7119a187aab5c8b083cc5228cb1b248ee29f184d
This commit is contained in:
parent
7143ea681c
commit
73db73dbd3
11 changed files with 4003 additions and 5595 deletions
|
@ -2,27 +2,24 @@ DEFINES=
|
||||||
CC=gcc
|
CC=gcc
|
||||||
CXX=g++
|
CXX=g++
|
||||||
LD=g++
|
LD=g++
|
||||||
CFLAGS=-g -std=c99 -W -Wall `xml2-config --cflags` $(DEFINES)
|
CFLAGS=-g -std=c99 -Wall $(DEFINES) -Ilib
|
||||||
CXXFLAGS=-g -W -Wall `xml2-config --cflags` $(DEFINES)
|
CXXFLAGS=-g -Wall $(DEFINES) -Ilib
|
||||||
LDFLAGS=`xml2-config --libs`
|
LDFLAGS=-Llib -lsocdesc `xml2-config --libs`
|
||||||
BINS= tester headergen hwemulgen
|
SRC=$(wildcard *.c)
|
||||||
|
SRCXX=$(wildcard *.cpp)
|
||||||
|
EXEC=$(SRC:.c=) $(SRCXX:.cpp=)
|
||||||
|
LIB=lib/libsocdesc.a
|
||||||
|
|
||||||
all: $(BINS)
|
all: $(EXEC)
|
||||||
|
|
||||||
%.o: %.c
|
$(LIB):
|
||||||
$(CC) $(CFLAGS) -c -o $@ $<
|
make -C lib
|
||||||
|
|
||||||
%.o: %.cpp
|
%: %.c $(LIB)
|
||||||
$(CXX) $(CXXFLAGS) -c -o $@ $<
|
$(CC) $(CFLAGS) -o $@ $< $(LDFLAGS)
|
||||||
|
|
||||||
headergen: headergen.o desc_parser.o
|
%: %.cpp $(LIB)
|
||||||
$(LD) -o $@ $^ $(LDFLAGS)
|
$(CXX) $(CXXFLAGS) -o $@ $< $(LDFLAGS)
|
||||||
|
|
||||||
hwemulgen: hwemulgen.o desc_parser.o
|
|
||||||
$(LD) -o $@ $^ $(LDFLAGS)
|
|
||||||
|
|
||||||
tester: tester.o desc_parser.o
|
|
||||||
$(LD) -o $@ $^ $(LDFLAGS)
|
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -fr *.o $(BINS)
|
rm -fr $(EXEC)
|
||||||
|
|
120
utils/regtools/desc/XML.txt
Normal file
120
utils/regtools/desc/XML.txt
Normal file
|
@ -0,0 +1,120 @@
|
||||||
|
This file describes the format of the register map based on XML.
|
||||||
|
|
||||||
|
Root
|
||||||
|
----
|
||||||
|
As any XML document, the content of the file should be enclosed in a "xml" tag.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<!-- desc -->
|
||||||
|
</xml>
|
||||||
|
|
||||||
|
Element: soc
|
||||||
|
------------
|
||||||
|
The XML can contain one or more SoC description. Each description is enclosed in
|
||||||
|
a "soc" tag. The following properties are defined:
|
||||||
|
- "name" (mandatory,string): the mnemonic of the SoC.
|
||||||
|
- "desc" (optional,string): a textual description of the SoC.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
<soc name="stmp3700" desc="STMP3700">
|
||||||
|
<!-- soc desc -->
|
||||||
|
</soc>
|
||||||
|
|
||||||
|
Element: soc.dev
|
||||||
|
----------------
|
||||||
|
Each SoC can contain any number of devices. Each device is enclosed in a "dev"
|
||||||
|
tag. A device is logical group of registers and doesn't have a precise meaning.
|
||||||
|
If a SoC has several copies of the same device at different addresses (SSP1, SSP2
|
||||||
|
for example), then only one copy has to be described since a device can have
|
||||||
|
several address (see soc.dev.addr section). The following properties are defined:
|
||||||
|
- "name" (mandatory,string): the mnemonic of the device.
|
||||||
|
- "long_name" (optional,string): a short description of the device.
|
||||||
|
- "desc" (optional,string): a long description of the SoC.
|
||||||
|
- "version" (optional,string): version of the register description for this device.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
<dev name="APBH" long_name="APHB DMA" desc="AHB-to-APBH Bridge with DMA" version="3.2.0">
|
||||||
|
<!-- dev desc>
|
||||||
|
</dev>
|
||||||
|
|
||||||
|
Element: soc.dev.addr
|
||||||
|
---------------------
|
||||||
|
Each device can have one or more addresses associated with it. Each address is
|
||||||
|
enclosed in a "addr" tag. This allows to describe several blocks are once on SoCs
|
||||||
|
where several copies of the same block exist at different addresses.
|
||||||
|
The following properties are defined:
|
||||||
|
- "name" (mandatory,string): unique name of this instance of the device.
|
||||||
|
- "addr" (mandatory,integer): base address of this instance of the device.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
<addr name="SSP1" addr="0x80010000" />
|
||||||
|
<addr name="SSP2" addr="0x80034000" />
|
||||||
|
|
||||||
|
Element: soc.dev.reg
|
||||||
|
--------------------
|
||||||
|
Each device can contain any number of registers. Each register is enclosed in a
|
||||||
|
"reg" tag. If a SoC has several copies of the same register at different addresses
|
||||||
|
(INTERRUPT0, INTERRUPT1 for example), then only one copy has to be described since
|
||||||
|
a register can have several address (see soc.dev.reg.addr section).
|
||||||
|
The following properties are defined:
|
||||||
|
- "name" (mandatory,string): the mnemonic of the register.
|
||||||
|
- "sct" (optional,"yes" or "no"): STMP specific attribute to specify the existence
|
||||||
|
of the SCT variants of this register.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
<reg name="TIMCTRLn" sct="yes">
|
||||||
|
<!-- reg desc -->
|
||||||
|
</reg>
|
||||||
|
|
||||||
|
Element: soc.dev.reg.addr
|
||||||
|
-------------------------
|
||||||
|
Each device can have one or more addresses associated with it. Each address
|
||||||
|
is enclosed in a "addr" tag. This allows to describe several register at once on
|
||||||
|
SoCs where a similar register is replicated several times.
|
||||||
|
The following properties are defined:
|
||||||
|
- "name" (mandatory,string): unique name of this instance of the register.
|
||||||
|
- "addr" (mandatory,integer): base address of this instance of the register.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
<addr name="TIMCTRL0" addr="0x20" />
|
||||||
|
<addr name="TIMCTRL1" addr="0x40" />
|
||||||
|
<addr name="TIMCTRL2" addr="0x60" />
|
||||||
|
|
||||||
|
Element: soc.dev.reg.formula
|
||||||
|
----------------------------
|
||||||
|
In the special case where the addresses of the register follow a pattern, an
|
||||||
|
explicit formula can be described as part of the format. There is no specific
|
||||||
|
requirement on the formula except that the register addresses be indexed by
|
||||||
|
a variable "n" which range from 0 to N-1 where N is the number of address.
|
||||||
|
The following properties are defined:
|
||||||
|
- "string" (mandatory,string): the equation describing the addresses.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
<formula string="0x20+n*0x20"/>
|
||||||
|
|
||||||
|
Element: soc.dev.reg.field
|
||||||
|
--------------------------
|
||||||
|
Each register can be further divided into disjoints fields. Each field
|
||||||
|
is enclosed in a "field" tag. A field is defined as a contiguous set
|
||||||
|
of bits in the register. The following properties are defined:
|
||||||
|
- "name" (mandatory,string): the mnemonic of field
|
||||||
|
- "bitrange" (mandatory,string): the bit range of the field written as
|
||||||
|
"n-m" where n and m are integers giving the most (resp. least) significant
|
||||||
|
bit of the field.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
<field name="PRESCALE" bitrange="5:4">
|
||||||
|
<!-- field desc -->
|
||||||
|
</field>
|
||||||
|
|
||||||
|
Element: soc.dev.reg.field.value
|
||||||
|
--------------------------------
|
||||||
|
Each field can describe a list of named values in cases where this is appropriate.
|
||||||
|
Each value is enclosed in a "value" tag. The following properties are defined:
|
||||||
|
- "name" (mandatory,string): the mnemonic of the value.
|
||||||
|
- "value" (mandatory,integer): the associated value.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
<value name="DIV_BY_1" value="0x0" />
|
||||||
|
<value name="DIV_BY_2" value="0x1" />
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -1,108 +0,0 @@
|
||||||
/***************************************************************************
|
|
||||||
* __________ __ ___.
|
|
||||||
* 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.
|
|
||||||
*
|
|
||||||
****************************************************************************/
|
|
||||||
#ifndef __DESC_PARSER__
|
|
||||||
#define __DESC_PARSER__
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <vector>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
typedef uint32_t soc_addr_t;
|
|
||||||
typedef uint32_t soc_word_t;
|
|
||||||
typedef uint32_t soc_reg_flags_t;
|
|
||||||
|
|
||||||
const soc_addr_t SOC_NO_ADDR = 0xffffffff;
|
|
||||||
const soc_reg_flags_t REG_HAS_SCT = 1 << 0;
|
|
||||||
|
|
||||||
struct soc_reg_field_value_t
|
|
||||||
{
|
|
||||||
std::string name;
|
|
||||||
soc_word_t value;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct soc_reg_field_t
|
|
||||||
{
|
|
||||||
std::string name;
|
|
||||||
unsigned first_bit, last_bit;
|
|
||||||
|
|
||||||
soc_word_t bitmask() const
|
|
||||||
{
|
|
||||||
return ((1 << (last_bit - first_bit + 1)) - 1) << first_bit;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector< soc_reg_field_value_t > values;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct soc_reg_t
|
|
||||||
{
|
|
||||||
std::string name;
|
|
||||||
soc_addr_t addr;
|
|
||||||
soc_reg_flags_t flags;
|
|
||||||
|
|
||||||
std::vector< soc_reg_field_t > fields;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct soc_multireg_t
|
|
||||||
{
|
|
||||||
std::string name;
|
|
||||||
soc_addr_t base;
|
|
||||||
unsigned count;
|
|
||||||
soc_addr_t offset;
|
|
||||||
soc_reg_flags_t flags;
|
|
||||||
|
|
||||||
std::vector< soc_reg_t > regs;
|
|
||||||
std::vector< soc_reg_field_t > fields;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct soc_dev_t
|
|
||||||
{
|
|
||||||
std::string name;
|
|
||||||
std::string long_name;
|
|
||||||
std::string desc;
|
|
||||||
soc_addr_t addr;
|
|
||||||
|
|
||||||
std::vector< soc_multireg_t > multiregs;
|
|
||||||
std::vector< soc_reg_t > regs;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct soc_multidev_t
|
|
||||||
{
|
|
||||||
std::string name;
|
|
||||||
std::string long_name;
|
|
||||||
std::string desc;
|
|
||||||
|
|
||||||
std::vector< soc_dev_t > devs;
|
|
||||||
std::vector< soc_multireg_t > multiregs;
|
|
||||||
std::vector< soc_reg_t > regs;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct soc_t
|
|
||||||
{
|
|
||||||
std::string name;
|
|
||||||
std::string desc;
|
|
||||||
|
|
||||||
std::vector< soc_dev_t > devs;
|
|
||||||
std::vector< soc_multidev_t > multidevs;
|
|
||||||
};
|
|
||||||
|
|
||||||
bool parse_soc_desc(const std::string& filename, std::vector< soc_t >& soc);
|
|
||||||
|
|
||||||
#endif /* __DESC_PARSER__ */
|
|
|
@ -7,7 +7,7 @@
|
||||||
* \/ \/ \/ \/ \/
|
* \/ \/ \/ \/ \/
|
||||||
* $Id$
|
* $Id$
|
||||||
*
|
*
|
||||||
* Copyright (C) 2002 by Amaury Pouly
|
* Copyright (C) 2013 by Amaury Pouly
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
|
@ -18,22 +18,26 @@
|
||||||
* KIND, either express or implied.
|
* KIND, either express or implied.
|
||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
#include "desc_parser.hpp"
|
#include "soc_desc.hpp"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <sstream>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#define HEADERGEN_VERSION "2.1.7"
|
||||||
|
|
||||||
#define error(...) do{ fprintf(stderr, __VA_ARGS__); exit(1); } while(0)
|
#define error(...) do{ fprintf(stderr, __VA_ARGS__); exit(1); } while(0)
|
||||||
|
|
||||||
std::string g_soc_name;
|
std::string g_soc_name;
|
||||||
std::string g_soc_dev;
|
std::string g_soc_dev;
|
||||||
std::string g_soc_reg;
|
std::string g_soc_reg;
|
||||||
|
std::string g_soc_field;
|
||||||
std::string g_soc_dev_regs_base;
|
std::string g_soc_dev_regs_base;
|
||||||
std::string g_soc_dev_reg_core_name;
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
std::string tolower(const std::string s)
|
std::string tolower(const std::string s)
|
||||||
{
|
{
|
||||||
std::string res = s;
|
std::string res = s;
|
||||||
|
@ -47,11 +51,32 @@ std::string toupper(const std::string& s)
|
||||||
std::transform(res.begin(), res.end(), res.begin(), ::toupper);
|
std::transform(res.begin(), res.end(), res.begin(), ::toupper);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void fprint_copyright(FILE *f)
|
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,"\
|
fprintf(f,"\
|
||||||
/***************************************************************************\n\
|
/***************************************************************************\n\
|
||||||
* __________ __ ___.\n\
|
* __________ __ ___.\n\
|
||||||
|
@ -61,8 +86,10 @@ void fprint_copyright(FILE *f)
|
||||||
* Firmware |____|_ /\\____/ \\___ >__|_ \\|___ /\\____/__/\\_ \\\n\
|
* Firmware |____|_ /\\____/ \\___ >__|_ \\|___ /\\____/__/\\_ \\\n\
|
||||||
* \\/ \\/ \\/ \\/ \\/\n\
|
* \\/ \\/ \\/ \\/ \\/\n\
|
||||||
* This file was automatically generated by headergen, DO NOT EDIT it.\n\
|
* This file was automatically generated by headergen, DO NOT EDIT it.\n\
|
||||||
|
* headergen version: " HEADERGEN_VERSION "\n\
|
||||||
|
* XML versions:%s\n\
|
||||||
*\n\
|
*\n\
|
||||||
* Copyright (C) 2012 by Amaury Pouly\n\
|
* Copyright (C) 2013 by Amaury Pouly\n\
|
||||||
*\n\
|
*\n\
|
||||||
* This program is free software; you can redistribute it and/or\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\
|
* modify it under the terms of the GNU General Public License\n\
|
||||||
|
@ -72,7 +99,13 @@ void fprint_copyright(FILE *f)
|
||||||
* This software is distributed on an \"AS IS\" basis, WITHOUT WARRANTY OF ANY\n\
|
* This software is distributed on an \"AS IS\" basis, WITHOUT WARRANTY OF ANY\n\
|
||||||
* KIND, either express or implied.\n\
|
* KIND, either express or implied.\n\
|
||||||
*\n\
|
*\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)
|
void fprint_include_guard_ex(FILE *f, bool begin, const std::string& name)
|
||||||
|
@ -81,7 +114,6 @@ void fprint_include_guard_ex(FILE *f, bool begin, const std::string& name)
|
||||||
{
|
{
|
||||||
fprintf(f, "#ifndef %s\n", name.c_str());
|
fprintf(f, "#ifndef %s\n", name.c_str());
|
||||||
fprintf(f, "#define %s\n", name.c_str());
|
fprintf(f, "#define %s\n", name.c_str());
|
||||||
fprintf(f, "\n#include \"imx233.h\"\n");
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
fprintf(f, "#endif /* %s */\n", name.c_str());
|
fprintf(f, "#endif /* %s */\n", name.c_str());
|
||||||
|
@ -89,108 +121,188 @@ void fprint_include_guard_ex(FILE *f, bool begin, const std::string& name)
|
||||||
|
|
||||||
void fprint_include_guard(FILE *f, bool begin)
|
void fprint_include_guard(FILE *f, bool begin)
|
||||||
{
|
{
|
||||||
std::string name = "__" + toupper(g_soc_name) + "__" + toupper(g_soc_dev)
|
std::string name = "__HEADERGEN__" + toupper(g_soc_name) + "__" + toupper(g_soc_dev)
|
||||||
+ "__H__";
|
+ "__H__";
|
||||||
fprint_include_guard_ex(f, begin, name);
|
fprint_include_guard_ex(f, begin, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void fprint_fields(FILE *f, const std::vector< soc_reg_field_t >& fields)
|
struct define_align_context_t
|
||||||
{
|
{
|
||||||
for(size_t i = 0; i < fields.size(); i++)
|
define_align_context_t():m_max_name(0) {}
|
||||||
|
void add(const std::string& name, const std::string& val)
|
||||||
{
|
{
|
||||||
fprintf(f, "#define BM_%s_%s %#x\n", g_soc_dev_reg_core_name.c_str(),
|
m_lines.push_back(std::make_pair(name, val));
|
||||||
fields[i].name.c_str(), fields[i].bitmask());
|
m_max_name = std::max(m_max_name, name.size());
|
||||||
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",
|
void print(FILE *f)
|
||||||
g_soc_dev_reg_core_name.c_str(), fields[i].name.c_str(),
|
{
|
||||||
fields[i].first_bit, fields[i].bitmask());
|
std::string define = "#define ";
|
||||||
if(fields[i].values.size() > 0)
|
size_t align = define.size() + m_max_name + 1;
|
||||||
|
align = ((align + 3) / 4) * 4;
|
||||||
|
|
||||||
|
for(size_t i = 0; i < m_lines.size(); i++)
|
||||||
{
|
{
|
||||||
fprintf(f, "#define BF_%s_%s_V(sym) ((BV_%s_%s__##sym << %d) & %#x)\n",
|
std::string name = m_lines[i].first;
|
||||||
g_soc_dev_reg_core_name.c_str(), fields[i].name.c_str(),
|
name.insert(name.end(), align - define.size() - name.size(), ' ');
|
||||||
g_soc_dev_reg_core_name.c_str(), fields[i].name.c_str(),
|
fprintf(f, "%s%s%s\n", define.c_str(), name.c_str(), m_lines[i].second.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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 fprint_reg(FILE *f, const soc_reg_t& reg)
|
void gen_soc_reg(FILE *f, bool multidev, const soc_reg_t& reg)
|
||||||
{
|
{
|
||||||
g_soc_dev_reg_core_name = toupper(g_soc_dev) + "_" + toupper(reg.name);
|
bool multireg = reg.addr.size() > 1;
|
||||||
|
|
||||||
fprintf(f, "#define RA_%s %#x\n", g_soc_dev_reg_core_name.c_str(), reg.addr);
|
static const char *suffix[] = {"", "_SET", "_CLR", "_TOG"};
|
||||||
fprintf(f, "#define HW_%s HW_REG(%s, %s)\n", g_soc_dev_reg_core_name.c_str(),
|
bool sct = !!(reg.flags & REG_HAS_SCT);
|
||||||
toupper(g_soc_dev).c_str(), toupper(reg.name).c_str());
|
|
||||||
if(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, "#define HW_%s_SET HW_SET(%s, %s)\n", g_soc_dev_reg_core_name.c_str(),
|
fprintf(f, " %s\n", reg.formula.string.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);
|
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");
|
fprintf(f, "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void fprint_mreg(FILE *f, const soc_multireg_t& mreg)
|
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(),
|
||||||
void gen_dev_header(const std::string& filename, const soc_dev_t& dev)
|
g_soc_dev.c_str(), filename.c_str());
|
||||||
{
|
*/
|
||||||
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");
|
FILE *f = fopen(filename.c_str(), "w");
|
||||||
if(f == NULL)
|
if(f == NULL)
|
||||||
error("Cannot open file %s\n", filename.c_str());
|
{
|
||||||
fprint_copyright(f);
|
printf("Cannot open %s for writing: %m\n", filename.c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fprint_copyright(f, ver);
|
||||||
fprint_include_guard(f, true);
|
fprint_include_guard(f, true);
|
||||||
|
|
||||||
|
/* print base */
|
||||||
fprintf(f, "\n");
|
fprintf(f, "\n");
|
||||||
g_soc_dev_regs_base = "RB_" + toupper(dev.name);
|
g_soc_dev_regs_base = "REGS_" + g_soc_dev + "_BASE";
|
||||||
fprintf(f, "#define %s %#x\n", g_soc_dev_regs_base.c_str(), dev.addr);
|
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");
|
fprintf(f, "\n");
|
||||||
|
|
||||||
for(size_t i = 0; i < dev.regs.size(); i++)
|
/* print version */
|
||||||
fprint_reg(f, dev.regs[i]);
|
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.multiregs.size(); i++)
|
|
||||||
fprint_mreg(f, dev.multiregs[i]);
|
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);
|
fprint_include_guard(f, false);
|
||||||
fclose(f);
|
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)
|
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(),
|
printf("Generate headers for soc %s: use directory %s\n", soc.desc.c_str(),
|
||||||
prefix.c_str());
|
prefix.c_str());
|
||||||
for(size_t i = 0; i < soc.devs.size(); i++)
|
mkdir(prefix.c_str(), 0770);
|
||||||
|
|
||||||
|
for(size_t i = 0; i < soc.dev.size(); i++)
|
||||||
{
|
{
|
||||||
std::string name = soc.devs[i].name;
|
g_soc_dev = soc.dev[i].name;
|
||||||
name = tolower(name);
|
xml_ver_t ver(soc.name, soc.dev[i].version);
|
||||||
gen_dev_header(prefix + "/regs-" + name + ".h", soc.devs[i]);
|
gen_soc_dev_header(prefix + "/regs-" + tolower(g_soc_dev.c_str()) + ".h", ver, soc.dev[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]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -203,31 +315,30 @@ void gen_headers(const std::string& prefix, const std::vector< soc_t >& socs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef std::map< std::string, std::vector< std::string > > general_dev_list_t;
|
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 build_general_dev_list(const std::vector< soc_t >& socs)
|
||||||
{
|
{
|
||||||
general_dev_list_t map;
|
general_dev_list_t map;
|
||||||
for(size_t i = 0; i < socs.size(); i++)
|
for(size_t i = 0; i < socs.size(); i++)
|
||||||
{
|
{
|
||||||
for(size_t j = 0; j < socs[i].devs.size(); j++)
|
for(size_t j = 0; j < socs[i].dev.size(); j++)
|
||||||
map[tolower(socs[i].devs[j].name)].push_back(socs[i].name);
|
map[tolower(socs[i].dev[j].name)].push_back(std::make_pair(i,j));
|
||||||
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;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
void gen_select_header(const std::string& filename, const std::string& dev,
|
void gen_select_header(const std::string& filename, const std::string& dev,
|
||||||
const std::vector< std::string >& socs)
|
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(),
|
printf("Generate select header for device %s: write to %s\n", dev.c_str(),
|
||||||
filename.c_str());
|
filename.c_str());
|
||||||
|
*/
|
||||||
std::string guard = "__SELECT__" + toupper(dev) + "__H__";
|
std::string guard = "__SELECT__" + toupper(dev) + "__H__";
|
||||||
FILE *f = fopen(filename.c_str(), "w");
|
FILE *f = fopen(filename.c_str(), "w");
|
||||||
if(f == NULL)
|
if(f == NULL)
|
||||||
error("Cannot open file %s\n", filename.c_str());
|
error("Cannot open file %s\n", filename.c_str());
|
||||||
fprint_copyright(f);
|
fprint_copyright(f, ver);
|
||||||
fprint_include_guard_ex(f, true, guard);
|
fprint_include_guard_ex(f, true, guard);
|
||||||
fprintf(f, "\n");
|
fprintf(f, "\n");
|
||||||
|
|
||||||
|
@ -251,24 +362,38 @@ void gen_selectors(const std::string& prefix, const std::vector< soc_t >& socs)
|
||||||
{
|
{
|
||||||
general_dev_list_t map = build_general_dev_list(socs);
|
general_dev_list_t map = build_general_dev_list(socs);
|
||||||
for(general_dev_list_t::iterator it = map.begin(); it != map.end(); ++it)
|
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);
|
{
|
||||||
|
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()
|
void usage()
|
||||||
{
|
{
|
||||||
printf("usage: headergen <desc file> <output prefix>\n");
|
printf("usage: headergen <desc files...> <output directory>\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
if(argc != 3)
|
if(argc < 3)
|
||||||
usage();
|
usage();
|
||||||
std::vector< soc_t > socs;
|
std::vector< soc_t > socs;
|
||||||
bool ret = parse_soc_desc(argv[1], socs);
|
for(int i = 1; i < argc - 1; i++)
|
||||||
printf("parse result: %d\n", ret);
|
if(!soc_desc_parse_xml(argv[i], socs))
|
||||||
if(!ret) return 1;
|
{
|
||||||
gen_headers(argv[2], socs);
|
printf("Cannot parse %s\n", argv[i]);
|
||||||
gen_selectors(argv[2], socs);
|
return 1;
|
||||||
|
}
|
||||||
|
gen_headers(argv[argc - 1], socs);
|
||||||
|
gen_selectors(argv[argc - 1], socs);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
|
@ -1,387 +0,0 @@
|
||||||
/***************************************************************************
|
|
||||||
* __________ __ ___.
|
|
||||||
* 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;
|
|
||||||
}
|
|
23
utils/regtools/lib/Makefile
Normal file
23
utils/regtools/lib/Makefile
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
CC=gcc
|
||||||
|
CXX=g++
|
||||||
|
AR=ar
|
||||||
|
CFLAGS=-Wall -O2 `xml2-config --cflags` -std=c99 -g -fPIC
|
||||||
|
CXXFLAGS=-Wall -O2 `xml2-config --cflags` -g -fPIC
|
||||||
|
LIB=libsocdesc.a
|
||||||
|
SRC=$(wildcard *.c)
|
||||||
|
SRCXX=$(wildcard *.cpp)
|
||||||
|
OBJ=$(SRC:.c=.o) $(SRCXX:.cpp=.o)
|
||||||
|
|
||||||
|
all: $(LIB) $(EXEC)
|
||||||
|
|
||||||
|
%.o: %.c
|
||||||
|
$(CC) $(CFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
|
%.o: %.cpp
|
||||||
|
$(CXX) $(CXXFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
|
$(LIB): $(OBJ)
|
||||||
|
$(AR) rcs $@ $^
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf $(OBJ) $(LIB)
|
|
@ -7,7 +7,7 @@
|
||||||
* \/ \/ \/ \/ \/
|
* \/ \/ \/ \/ \/
|
||||||
* $Id$
|
* $Id$
|
||||||
*
|
*
|
||||||
* Copyright (C) 2002 by Amaury Pouly
|
* Copyright (C) 2012 by Amaury Pouly
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
|
@ -18,7 +18,7 @@
|
||||||
* KIND, either express or implied.
|
* KIND, either express or implied.
|
||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
#include "desc_parser.hpp"
|
#include "soc_desc.hpp"
|
||||||
#include <libxml/parser.h>
|
#include <libxml/parser.h>
|
||||||
#include <libxml/tree.h>
|
#include <libxml/tree.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
@ -150,42 +150,65 @@ bool parse_field_elem(xmlNode *node, soc_reg_field_t& field)
|
||||||
END_ATTR_MATCH()
|
END_ATTR_MATCH()
|
||||||
|
|
||||||
BEGIN_NODE_MATCH(node->children)
|
BEGIN_NODE_MATCH(node->children)
|
||||||
SOFT_MATCH_ELEM_NODE("value", field.values, parse_value_elem)
|
SOFT_MATCH_ELEM_NODE("value", field.value, parse_value_elem)
|
||||||
END_NODE_MATCH()
|
END_NODE_MATCH()
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool parse_reg_addr_elem(xmlNode *node, soc_reg_addr_t& addr)
|
||||||
|
{
|
||||||
|
BEGIN_ATTR_MATCH(node->properties)
|
||||||
|
MATCH_TEXT_ATTR("name", addr.name)
|
||||||
|
MATCH_UINT32_ATTR("addr", addr.addr)
|
||||||
|
END_ATTR_MATCH()
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool parse_reg_formula_elem(xmlNode *node, soc_reg_formula_t& formula)
|
||||||
|
{
|
||||||
|
BEGIN_ATTR_MATCH(node->properties)
|
||||||
|
MATCH_TEXT_ATTR("string", formula.string)
|
||||||
|
END_ATTR_MATCH()
|
||||||
|
|
||||||
|
formula.type = REG_FORMULA_STRING;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool parse_reg_elem(xmlNode *node, soc_reg_t& reg)
|
bool parse_reg_elem(xmlNode *node, soc_reg_t& reg)
|
||||||
{
|
{
|
||||||
|
std::vector< soc_reg_formula_t > formulas;
|
||||||
BEGIN_ATTR_MATCH(node->properties)
|
BEGIN_ATTR_MATCH(node->properties)
|
||||||
MATCH_TEXT_ATTR("name", reg.name)
|
MATCH_TEXT_ATTR("name", reg.name)
|
||||||
MATCH_UINT32_ATTR("addr", reg.addr)
|
|
||||||
SOFT_MATCH_SCT_ATTR("sct", reg.flags)
|
SOFT_MATCH_SCT_ATTR("sct", reg.flags)
|
||||||
END_ATTR_MATCH()
|
END_ATTR_MATCH()
|
||||||
|
|
||||||
BEGIN_NODE_MATCH(node->children)
|
BEGIN_NODE_MATCH(node->children)
|
||||||
MATCH_ELEM_NODE("field", reg.fields, parse_field_elem)
|
MATCH_ELEM_NODE("addr", reg.addr, parse_reg_addr_elem)
|
||||||
|
MATCH_ELEM_NODE("formula", formulas, parse_reg_formula_elem)
|
||||||
|
MATCH_ELEM_NODE("field", reg.field, parse_field_elem)
|
||||||
END_NODE_MATCH()
|
END_NODE_MATCH()
|
||||||
|
|
||||||
|
if(formulas.size() > 1)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Only one formula is allowed per register\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if(formulas.size() == 1)
|
||||||
|
reg.formula = formulas[0];
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool parse_multireg_elem(xmlNode *node, soc_multireg_t& mreg)
|
bool parse_dev_addr_elem(xmlNode *node, soc_dev_addr_t& addr)
|
||||||
{
|
{
|
||||||
BEGIN_ATTR_MATCH(node->properties)
|
BEGIN_ATTR_MATCH(node->properties)
|
||||||
MATCH_TEXT_ATTR("name", mreg.name)
|
MATCH_TEXT_ATTR("name", addr.name)
|
||||||
MATCH_UINT32_ATTR("base", mreg.base)
|
MATCH_UINT32_ATTR("addr", addr.addr)
|
||||||
MATCH_UINT32_ATTR("count", mreg.count)
|
|
||||||
MATCH_UINT32_ATTR("offset", mreg.offset)
|
|
||||||
SOFT_MATCH_SCT_ATTR("sct", mreg.flags)
|
|
||||||
END_ATTR_MATCH()
|
END_ATTR_MATCH()
|
||||||
|
|
||||||
BEGIN_NODE_MATCH(node->children)
|
|
||||||
MATCH_ELEM_NODE("reg", mreg.regs, parse_reg_elem)
|
|
||||||
MATCH_ELEM_NODE("field", mreg.fields, parse_field_elem)
|
|
||||||
END_NODE_MATCH()
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,31 +216,12 @@ bool parse_dev_elem(xmlNode *node, soc_dev_t& dev)
|
||||||
{
|
{
|
||||||
BEGIN_ATTR_MATCH(node->properties)
|
BEGIN_ATTR_MATCH(node->properties)
|
||||||
MATCH_TEXT_ATTR("name", dev.name)
|
MATCH_TEXT_ATTR("name", dev.name)
|
||||||
MATCH_UINT32_ATTR("addr", dev.addr)
|
MATCH_TEXT_ATTR("version", dev.version)
|
||||||
MATCH_TEXT_ATTR("long_name", dev.long_name)
|
|
||||||
MATCH_TEXT_ATTR("desc", dev.desc)
|
|
||||||
END_ATTR_MATCH()
|
END_ATTR_MATCH()
|
||||||
|
|
||||||
BEGIN_NODE_MATCH(node->children)
|
BEGIN_NODE_MATCH(node->children)
|
||||||
MATCH_ELEM_NODE("multireg", dev.multiregs, parse_multireg_elem)
|
MATCH_ELEM_NODE("addr", dev.addr, parse_dev_addr_elem)
|
||||||
MATCH_ELEM_NODE("reg", dev.regs, parse_reg_elem)
|
MATCH_ELEM_NODE("reg", dev.reg, parse_reg_elem)
|
||||||
END_NODE_MATCH()
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool parse_multidev_elem(xmlNode *node, soc_multidev_t& dev)
|
|
||||||
{
|
|
||||||
BEGIN_ATTR_MATCH(node->properties)
|
|
||||||
MATCH_TEXT_ATTR("name", dev.name)
|
|
||||||
MATCH_TEXT_ATTR("long_name", dev.long_name)
|
|
||||||
MATCH_TEXT_ATTR("desc", dev.desc)
|
|
||||||
END_ATTR_MATCH()
|
|
||||||
|
|
||||||
BEGIN_NODE_MATCH(node->children)
|
|
||||||
MATCH_ELEM_NODE("dev", dev.devs, parse_dev_elem)
|
|
||||||
MATCH_ELEM_NODE("multireg", dev.multiregs, parse_multireg_elem)
|
|
||||||
MATCH_ELEM_NODE("reg", dev.regs, parse_reg_elem)
|
|
||||||
END_NODE_MATCH()
|
END_NODE_MATCH()
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -231,22 +235,21 @@ bool parse_soc_elem(xmlNode *node, soc_t& soc)
|
||||||
END_ATTR_MATCH()
|
END_ATTR_MATCH()
|
||||||
|
|
||||||
BEGIN_NODE_MATCH(node->children)
|
BEGIN_NODE_MATCH(node->children)
|
||||||
MATCH_ELEM_NODE("dev", soc.devs, parse_dev_elem)
|
MATCH_ELEM_NODE("dev", soc.dev, parse_dev_elem)
|
||||||
MATCH_ELEM_NODE("multidev", soc.multidevs, parse_multidev_elem)
|
|
||||||
END_NODE_MATCH()
|
END_NODE_MATCH()
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool parse_root_elem(xmlNode *node, std::vector< soc_t >& socs)
|
bool parse_root_elem(xmlNode *node, std::vector< soc_t >& soc)
|
||||||
{
|
{
|
||||||
BEGIN_NODE_MATCH(node)
|
BEGIN_NODE_MATCH(node)
|
||||||
MATCH_ELEM_NODE("soc", socs, parse_soc_elem)
|
MATCH_ELEM_NODE("soc", soc, parse_soc_elem)
|
||||||
END_NODE_MATCH()
|
END_NODE_MATCH()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool parse_soc_desc(const std::string& filename, std::vector< soc_t >& socs)
|
bool soc_desc_parse_xml(const std::string& filename, std::vector< soc_t >& socs)
|
||||||
{
|
{
|
||||||
LIBXML_TEST_VERSION
|
LIBXML_TEST_VERSION
|
||||||
|
|
147
utils/regtools/lib/soc_desc.hpp
Normal file
147
utils/regtools/lib/soc_desc.hpp
Normal file
|
@ -0,0 +1,147 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* __________ __ ___.
|
||||||
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||||
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||||
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||||
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||||
|
* \/ \/ \/ \/ \/
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
* Copyright (C) 2012 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.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
#ifndef __SOC_DESC__
|
||||||
|
#define __SOC_DESC__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* These data structures represent the SoC register in a convenient way.
|
||||||
|
* The basic structure is the following:
|
||||||
|
* - each SoC has several devices
|
||||||
|
* - each device has a generic name, a list of {name,address} and several registers
|
||||||
|
* - each register has a generic name, a list of {name,address}, flags,
|
||||||
|
* several fields
|
||||||
|
* - each field has a name, a first and last bit position, can apply either
|
||||||
|
* to all addresses of a register or be specific to one only and has several values
|
||||||
|
* - each field value has a name and a value
|
||||||
|
*
|
||||||
|
* All addresses, values and names are relative to the parents. For example a field
|
||||||
|
* value BV_LCDIF_CTRL_WORD_LENGTH_18_BIT is represented has:
|
||||||
|
* - device LCDIF, register CTRL, field WORD_LENGTH, value 16_BIT
|
||||||
|
* The address of CTRL is related to the address of LCDIF, the value of 16_BIT
|
||||||
|
* ignores the position of the WORD_LENGTH field in the register.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Typedef for SoC types: word, address and flags */
|
||||||
|
typedef uint32_t soc_addr_t;
|
||||||
|
typedef uint32_t soc_word_t;
|
||||||
|
typedef uint32_t soc_reg_flags_t;
|
||||||
|
|
||||||
|
/** SoC register generic formula */
|
||||||
|
enum soc_reg_formula_type_t
|
||||||
|
{
|
||||||
|
REG_FORMULA_NONE, /// register has no generic formula
|
||||||
|
REG_FORMULA_STRING, /// register has a generic formula represented by a string
|
||||||
|
};
|
||||||
|
|
||||||
|
/** <soc_reg_t>.<flags> values */
|
||||||
|
const soc_reg_flags_t REG_HAS_SCT = 1 << 0; /// register SCT variants
|
||||||
|
|
||||||
|
/** SoC register field named value */
|
||||||
|
struct soc_reg_field_value_t
|
||||||
|
{
|
||||||
|
std::string name;
|
||||||
|
soc_word_t value;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** SoC register field */
|
||||||
|
struct soc_reg_field_t
|
||||||
|
{
|
||||||
|
std::string name;
|
||||||
|
unsigned first_bit, last_bit;
|
||||||
|
|
||||||
|
soc_word_t bitmask() const
|
||||||
|
{
|
||||||
|
// WARNING beware of the case where first_bit=0 and last_bit=31
|
||||||
|
if(first_bit == 0 && last_bit == 31)
|
||||||
|
return 0xffffffff;
|
||||||
|
else
|
||||||
|
return ((1 << (last_bit - first_bit + 1)) - 1) << first_bit;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_reserved() const
|
||||||
|
{
|
||||||
|
return name.substr(0, 4) == "RSVD" || name.substr(0, 5) == "RSRVD";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector< soc_reg_field_value_t > value;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** SoC register address */
|
||||||
|
struct soc_reg_addr_t
|
||||||
|
{
|
||||||
|
std::string name; /// actual register name
|
||||||
|
soc_addr_t addr;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** SoC register formula */
|
||||||
|
struct soc_reg_formula_t
|
||||||
|
{
|
||||||
|
enum soc_reg_formula_type_t type;
|
||||||
|
std::string string; /// for STRING
|
||||||
|
};
|
||||||
|
|
||||||
|
/** SoC register */
|
||||||
|
struct soc_reg_t
|
||||||
|
{
|
||||||
|
std::string name; /// generic name (for multi registers) or actual name
|
||||||
|
std::vector< soc_reg_addr_t > addr;
|
||||||
|
soc_reg_formula_t formula;
|
||||||
|
soc_reg_flags_t flags; /// ORed value
|
||||||
|
|
||||||
|
std::vector< soc_reg_field_t > field;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Soc device address */
|
||||||
|
struct soc_dev_addr_t
|
||||||
|
{
|
||||||
|
std::string name; /// actual device name
|
||||||
|
soc_addr_t addr;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** SoC device */
|
||||||
|
struct soc_dev_t
|
||||||
|
{
|
||||||
|
std::string name; /// generic name (of multi devices) or actual name
|
||||||
|
std::string version; /// description version
|
||||||
|
std::vector< soc_dev_addr_t > addr;
|
||||||
|
|
||||||
|
std::vector< soc_reg_t > reg;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** SoC */
|
||||||
|
struct soc_t
|
||||||
|
{
|
||||||
|
std::string name; /// codename (rockbox)
|
||||||
|
std::string desc; /// SoC name
|
||||||
|
|
||||||
|
std::vector< soc_dev_t > dev;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Parse a SoC description from a XML file, append it to <soc>. A file
|
||||||
|
* can contain multiple SoC descriptions */
|
||||||
|
bool soc_desc_parse_xml(const std::string& filename, std::vector< soc_t >& soc);
|
||||||
|
|
||||||
|
#endif /* __SOC_DESC__ */
|
|
@ -7,7 +7,7 @@
|
||||||
* \/ \/ \/ \/ \/
|
* \/ \/ \/ \/ \/
|
||||||
* $Id$
|
* $Id$
|
||||||
*
|
*
|
||||||
* Copyright (C) 2002 by Amaury Pouly
|
* Copyright (C) 2012 by Amaury Pouly
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
|
@ -18,7 +18,7 @@
|
||||||
* KIND, either express or implied.
|
* KIND, either express or implied.
|
||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
#include "desc_parser.hpp"
|
#include "soc_desc.hpp"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
@ -31,8 +31,8 @@ void print_field_desc(const soc_reg_field_t& field)
|
||||||
{
|
{
|
||||||
printf(" FIELD %s (%d:%d)\n", field.name.c_str(), field.last_bit,
|
printf(" FIELD %s (%d:%d)\n", field.name.c_str(), field.last_bit,
|
||||||
field.first_bit);
|
field.first_bit);
|
||||||
for(size_t i = 0; i < field.values.size(); i++)
|
for(size_t i = 0; i < field.value.size(); i++)
|
||||||
print_value_desc(field.values[i]);
|
print_value_desc(field.value[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string compute_sct(soc_reg_flags_t f)
|
std::string compute_sct(soc_reg_flags_t f)
|
||||||
|
@ -41,69 +41,40 @@ std::string compute_sct(soc_reg_flags_t f)
|
||||||
else return "";
|
else return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
void print_reg_desc(const soc_reg_t& reg, bool in_multi)
|
void print_reg_addr_desc(const soc_reg_addr_t& reg)
|
||||||
{
|
{
|
||||||
if(in_multi)
|
printf(" ADDR %s %#x\n", reg.name.c_str(), reg.addr);
|
||||||
{
|
|
||||||
printf(" REG %s (%#x)\n", reg.name.c_str(), reg.addr);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
std::string sct = compute_sct(reg.flags);
|
|
||||||
printf(" REG %s %s(%#x)\n", reg.name.c_str(), sct.c_str(), reg.addr);
|
|
||||||
for(size_t i = 0; i < reg.fields.size(); i++)
|
|
||||||
print_field_desc(reg.fields[i]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void print_multireg_desc(const soc_multireg_t& mreg)
|
void print_reg_desc(const soc_reg_t& reg)
|
||||||
{
|
{
|
||||||
std::string sct = compute_sct(mreg.flags);
|
std::string sct = compute_sct(reg.flags);
|
||||||
printf(" MULTIREG %s %s(%#x * %d, +%#x)\n", mreg.name.c_str(), sct.c_str(),
|
printf(" REG %s %s\n", reg.name.c_str(), sct.c_str());
|
||||||
mreg.base, mreg.count, mreg.offset);
|
for(size_t i = 0; i < reg.addr.size(); i++)
|
||||||
for(size_t i = 0; i < mreg.regs.size(); i++)
|
print_reg_addr_desc(reg.addr[i]);
|
||||||
print_reg_desc(mreg.regs[i], true);
|
for(size_t i = 0; i < reg.field.size(); i++)
|
||||||
for(size_t i = 0; i < mreg.fields.size(); i++)
|
print_field_desc(reg.field[i]);
|
||||||
print_field_desc(mreg.fields[i]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void print_dev_addr_desc(const soc_dev_addr_t& dev)
|
||||||
void print_dev_desc(const soc_dev_t& dev, bool in_multi)
|
|
||||||
{
|
{
|
||||||
if(in_multi)
|
printf(" ADDR %s %#x\n", dev.name.c_str(), dev.addr);
|
||||||
{
|
|
||||||
printf(" DEV %s (%#x)\n", dev.name.c_str(), dev.addr);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
printf(" DEV %s (%#x, %s, %s)\n", dev.name.c_str(), dev.addr,
|
|
||||||
dev.long_name.c_str(), dev.desc.c_str());
|
|
||||||
for(size_t i = 0; i < dev.multiregs.size(); i++)
|
|
||||||
print_multireg_desc(dev.multiregs[i]);
|
|
||||||
for(size_t i = 0; i < dev.regs.size(); i++)
|
|
||||||
print_reg_desc(dev.regs[i], false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void print_multidev_desc(const soc_multidev_t& dev)
|
void print_dev_desc(const soc_dev_t& dev)
|
||||||
{
|
{
|
||||||
printf(" MULTIDEV %s (%s, %s)\n", dev.name.c_str(), dev.long_name.c_str(),
|
printf(" DEV %s\n", dev.name.c_str());
|
||||||
dev.desc.c_str());
|
for(size_t i = 0; i < dev.addr.size(); i++)
|
||||||
for(size_t i = 0; i < dev.devs.size(); i++)
|
print_dev_addr_desc(dev.addr[i]);
|
||||||
print_dev_desc(dev.devs[i], true);
|
for(size_t i = 0; i < dev.reg.size(); i++)
|
||||||
for(size_t i = 0; i < dev.multiregs.size(); i++)
|
print_reg_desc(dev.reg[i]);
|
||||||
print_multireg_desc(dev.multiregs[i]);
|
|
||||||
for(size_t i = 0; i < dev.regs.size(); i++)
|
|
||||||
print_reg_desc(dev.regs[i], false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void print_soc_desc(const soc_t& soc)
|
void print_soc_desc(const soc_t& soc)
|
||||||
{
|
{
|
||||||
printf("SOC %s (%s)\n", soc.name.c_str(), soc.desc.c_str());
|
printf("SOC %s (%s)\n", soc.name.c_str(), soc.desc.c_str());
|
||||||
for(size_t i = 0; i < soc.devs.size(); i++)
|
for(size_t i = 0; i < soc.dev.size(); i++)
|
||||||
print_dev_desc(soc.devs[i], false);
|
print_dev_desc(soc.dev[i]);
|
||||||
for(size_t i = 0; i < soc.multidevs.size(); i++)
|
|
||||||
print_multidev_desc(soc.multidevs[i]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void usage()
|
void usage()
|
||||||
|
@ -117,7 +88,7 @@ int main(int argc, char **argv)
|
||||||
if(argc != 2)
|
if(argc != 2)
|
||||||
usage();
|
usage();
|
||||||
std::vector< soc_t > socs;
|
std::vector< soc_t > socs;
|
||||||
bool ret = parse_soc_desc(argv[1], socs);
|
bool ret = soc_desc_parse_xml(argv[1], socs);
|
||||||
printf("parse result: %d\n", ret);
|
printf("parse result: %d\n", ret);
|
||||||
if(ret)
|
if(ret)
|
||||||
for(size_t i = 0; i < socs.size(); i++)
|
for(size_t i = 0; i < socs.size(); i++)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue