用途
转换现有svd文件到 mculib4d 的芯片声明工具
代码
module svd;
import std.stdio;
import std.file;
import std.xml;
import std.string;
import std.regex;
struct tys
{
union{
uint i1;
ushort[2] s1;
ubyte[4] b1;
}
}
int main()
{
string svdfile = "STM32F401.svd";
if(!isFile(svdfile)){
return 0;
}
Etsvd(svdfile);
return 0;
}
struct mcuinfo
{
string name;
string mversion;
string description;
string addressUnitBits;
string width;
string size;
string resetValue;
string resetMask;
cpuinfo cpu;
}
struct cpuinfo
{
string name;
string revision;
string endian;
string mpuPresent;
string fpuPresent;
string nvicPrioBits;
string vendorSystickConfig;
}
struct peripheral
{
string name;
string desc;
string group;
string address;
addressBlock ablock;
interrupt[] inp;
register[] regs;
string ttext;
string derivedFrom;
}
struct addressBlock
{
string offs;
string ssize;
string usage;
}
struct interrupt
{
string name;
string description;
string val;
}
struct register
{
string name;
string display;
string description;
string addressOffset;
string msize;
string access;
string resetValue;
field[] fields;
}
struct field
{
string name;
string description;
string bitOffset;
string bitWidth;
string access;
}
void Etsvd(string fname)
{
string s = cast(string) std.file.read(fname);
//
try{
//check(s);
}catch (CheckException e)
{
writefln(e.msg);
}
peripheral[] pres;
mcuinfo info;
DocumentParser svdxml = new DocumentParser(s);
svdxml.onEndTag["name"] = (in Element e) { info.name = e.text(); };
svdxml.onEndTag["version"] = (in Element e) { info.mversion = e.text(); };
svdxml.onEndTag["description"] = (in Element e) { info.description = e.text(); };
svdxml.onStartTag["cpu"] = (ElementParser cp){
cpuinfo mcup;
cp.onEndTag["name"] = (in Element e) { mcup.name = e.text(); };
cp.onEndTag["revision"] = (in Element e) { mcup.revision = e.text(); };
cp.onEndTag["endian"] = (in Element e) { mcup.endian = e.text(); };
cp.onEndTag["mpuPresent"] = (in Element e) { mcup.mpuPresent = e.text(); };
cp.onEndTag["fpuPresent"] = (in Element e) { mcup.fpuPresent = e.text(); };
cp.onEndTag["nvicPrioBits"] = (in Element e) { mcup.nvicPrioBits = e.text(); };
cp.onEndTag["vendorSystickConfig"] = (in Element e) { mcup.vendorSystickConfig = e.text(); };
cp.parse();
info.cpu = mcup;
};
svdxml.onEndTag["addressUnitBits"] = (in Element e) { info.addressUnitBits = e.text(); };
svdxml.onEndTag["width"] = (in Element e) { info.width = e.text(); };
svdxml.onEndTag["size"] = (in Element e) { info.size = e.text(); };
svdxml.onEndTag["resetValue"] = (in Element e) {
info.resetValue = e.text();
};
svdxml.onEndTag["resetMask"] = (in Element e) { info.resetMask = e.text(); };
svdxml.onStartTag["peripheral"] = (ElementParser xml)
{
peripheral pb;
auto df = ("derivedFrom" in xml.tag.attr);
if(df){
pb.derivedFrom = *df;
}
xml.onEndTag["name"] = (in Element e) { pb.name = e.text(); };
xml.onEndTag["description"] = (in Element e) { pb.desc = e.text(); };
xml.onEndTag["groupName"] = (in Element e) { pb.group = e.text(); };
xml.onEndTag["baseAddress"] = (in Element e) { pb.address = e.text(); };
//xml.onEndTag["addressBlock"] = (in Element e) { pb.ttext = e.text(); };
xml.onStartTag["addressBlock"] = (ElementParser ap){
addressBlock ab;
ap.onEndTag["offset"] = (in Element e){ab.offs = e.text();};
ap.onEndTag["size"] = (in Element e){ab.ssize = e.text();};
ap.onEndTag["usage"] = (in Element e){ab.usage = e.text();};
ap.parse();
pb.ablock = ab;
};
xml.onStartTag["interrupt"] = (ElementParser p){
interrupt ip;
p.onEndTag["name"] = (in Element e){ip.name = e.text();};
p.onEndTag["description"] = (in Element e){ip.description = e.text();};
p.onEndTag["value"] = (in Element e){ip.val = e.text();};
p.parse();
pb.inp ~= ip;
};
xml.onStartTag["register"] = (ElementParser ep){
register reg;
ep.onEndTag["name"] = (in Element e){reg.name = e.text();};
ep.onEndTag["displayName"] = (in Element e){reg.display = e.text();};
ep.onEndTag["description"] = (in Element e){reg.description = e.text();};
ep.onEndTag["addressOffset"] = (in Element e){reg.addressOffset = e.text();};
ep.onEndTag["size"] = (in Element e){reg.msize = e.text();};
ep.onEndTag["access"] = (in Element e){reg.access = e.text();};
ep.onEndTag["resetValue"] = (in Element e){reg.resetValue = e.text();};
ep.onStartTag["field"] = (ElementParser fp){
field fid;
fp.onEndTag["name"] = (in Element e){fid.name = e.text();};
fp.onEndTag["description"] = (in Element e){fid.description = e.text();};
fp.onEndTag["bitOffset"] = (in Element e){fid.bitOffset = e.text();};
fp.onEndTag["bitWidth"] = (in Element e){fid.bitWidth = e.text();};
fp.onEndTag["access"] = (in Element e){fid.access = e.text();};
fp.parse();
reg.fields ~= fid;
};
ep.parse();
pb.regs ~= reg;
};
xml.parse();
pres ~= pb;
};
svdxml.parse();
//---
peripheral scan4name(string n)
{
foreach(v;pres)
{
if(v.name == n) return v;
}
writefln("no found [%s]",n);
return peripheral.init;
}
//--
/// 模板统计
foreach(ref v;pres)
{
if(v.derivedFrom.length > 0){
auto vf = scan4name(v.derivedFrom);
vf.name = v.name;
vf.address = v.address;
vf.derivedFrom = v.derivedFrom;
vf.inp = v.inp;
v = vf;
}
}
//--
//-- 模板
//-- 组
string code;
//-- 组函数
//-- 常量
if(info.description){
code ~= maker_description(info.description,0,90);
}
code ~= "struct Conf {\n";
code ~= "\tenum string SVDName = `"~info.name~"`;\n";
code ~= "\tenum string SVDVersion = `"~info.mversion~"`;\n";
code ~= "\tenum size_t SVDUnitBits = "~info.addressUnitBits~";\n";
code ~= "\tenum size_t SVDWidth = "~info.width~";\n";
code ~= "\tenum size_t SVDSize = "~info.size~";\n";
code ~= "\tenum size_t SVDresetValue = "~info.resetValue~";\n";
code ~= "\tenum size_t SVDresetMask = "~info.resetMask~";\n";
code ~= "\tenum string SVDCpuName = `"~info.cpu.name~"`;\n";
code ~= "\tenum string SVDCpuRevision = `"~info.cpu.revision~"`;\n";
code ~= "\tenum string SVDCpuEndian = `"~info.cpu.endian~"`;\n";
code ~= "\tenum bool SVDCpuMpuPresent = "~info.cpu.mpuPresent~";\n";
code ~= "\tenum bool SVDCpuFpuPresent = "~info.cpu.fpuPresent~";\n";
code ~= "\tenum size_t SVDCpuNvicPrioBits = "~info.cpu.nvicPrioBits~";\n";
code ~= "\tenum bool SVDCpuVendorSystickConfig = "~info.cpu.vendorSystickConfig~";\n";
code ~= "}\n";
code ~= maker_group(pres);
writeln(code);
}
void maker_group1(peripheral[] src)
{
import std.algorithm;
void maker_group_sin(string gname)
{
}
//uint[string] groups;
string[] groups;
uint[string] tgroup;
string code;
bool pmcheck(string n)
{
foreach(v;groups)
{
if(v == n) return true;
}
return false;
}
peripheral[] pmSumGroup(string n)
{
peripheral[] r;
foreach(v;src){
if(v.group == n) r ~= v;
}
return r;
}
uint pmCount(string n)
{
return pmSumGroup(n).length;
}
string pmMakeTname(string v1,string v2)
{
string r;
auto msize = (v1.length <= v2.length) ?v1.length:v2.length;
for(auto i = 0;i<msize;i++)
{
if(v1[i] is v2[i]){
r ~=v1[i];
}else{
break;
}
}
return r;
}
uint pmCountTP(peripheral[] g)
{
uint[string] count;
auto tg = g.dup;
while(tg.length){
auto cv = tg[0];
tg = tg[1..$];
peripheral[] t;
foreach(v;tg){
if(cv.name.indexOf("GPIO") >= 0)
{
auto b1 = cv.regs is v.regs;
auto b2 = v.regs == cv.regs;
writeln(b1);
writeln(b2);
writeln(cv.name);
writeln(v.name);
}
if(cv.regs is v.regs){
count[pmMakeTname(v.name,cv.name)]++;
}else{
t ~= v;
}
}
tg = t;
}
writeln(count);
return 0;
}
peripheral[] pmSumderivedFrom(string n)
{
peripheral[] r;
foreach(v;src){
if(v.derivedFrom == n) r ~= v;
}
return r;
}
//组
foreach(v;src){
if(!pmcheck(v.group)) groups ~= v.group;
}
// 模板组
foreach(v;src)
{
if(v.derivedFrom.length > 0)
{
tgroup[v.derivedFrom]++;
}
}
// 建立模板
foreach(v,v2;tgroup){
if(v){
auto tp = pmSumderivedFrom(v);
auto tname = "";
foreach(k,vn;v)
{
foreach(tv;tp)
{
if(!(tv.name[k] == vn)){
goto enddd;
}
}
tname ~= vn;
}
enddd:
if(tname.length==0){
tname = v;
}
//writeln();
code ~= "\n/****************************************************************************************\n";
code ~= "*\t package template: "~ tname ~ "\n";
code ~= "*/\n";
}
//if(!pmcheck(v.group)) groups ~= v.group;
}
/+
foreach(k;groups)
{
//pmCountTP(pmSumGroup(k));
//writefln("Key[%s],count[%s]",k,pmCount(k));
code ~= "\n/****************************************************************************************\n";
code ~= "*\t Group: "~ k ~ "\n";
code ~= "*/\n";
}
+/
//writeln(code);
//writeln(maker_description("ccccaaa",8));
writeln(maker_Peripheral(src[0]));
}
/*
Group > Temp > Const
*/
string maker_group(peripheral[] src)
{
peripheral[][string] tgroups;
string code;
foreach(v;src)
{
if(v.derivedFrom.length > 0)
{
tgroups[v.derivedFrom] ~= v;
}
}
// 整理
foreach(k,v;tgroups)
{
foreach(ref dv;src){
if(dv.name == k){
dv.derivedFrom = k;
tgroups[k] ~= dv;
break;
}
}
}
/*
foreach(dv;src)
{
if(dv.name == v.derivedFrom )
{
tgroups[v.derivedFrom] ~= dv;
break;
}
}
*/
//模板目标
foreach(dfname,pv;tgroups)
{
auto tname="";
//foreach()
foreach(i,s;dfname)
{
foreach(tv;pv){
if(!(tv.name[i] == s))
{
goto endddd;
}
}
tname ~= s;
}
endddd:
if(tname.length == 0){
tname = dfname;
}
code ~= maker_desc1(0,90);
//模板声明
foreach(v;pv)
{
code ~= format("/// %s\n",ClearRN(v.desc));
//code ~= format("alias %s = %sTemplate!(%s);\n",v.name,dfname,v.address);
code ~= format("final abstract class %s : %sTemplate!(%s) {\n",v.name,dfname,v.address);
// 中断
if(v.inp ){
code ~= maker_tab(4) ~ "///";
foreach(iv;v.inp)
{
code ~= iv.name;
code ~= ",";
}
code ~= "\n";
code ~= maker_tab(4) ~ "enum interrupts=[";
foreach(iv;v.inp)
{
code ~= iv.val;
code ~= ",";
}
code ~= "];\n";
}
code ~= "}\n";
}
//模板建立
auto tpv = pv[0];
tpv.name = dfname;
code ~= maker_Peripheral(tpv,true);
}
foreach(v;src)
{
if(v.derivedFrom) continue;
code ~= maker_Peripheral(v,false);
}
return code;
}
string maker_Peripheral(in peripheral src,bool istemplate=false)
{
string code;
//code ~= "final abstract class SPI4 : Peripheral!(0x40013400,Conf) \n";
if(istemplate){
code ~= maker_description(ClearRN(src.name));
code ~= format("private abstract class %sTemplate(size_t pBase) : Peripheral!(pBase,Conf) {\n",src.name);
}else{
code ~= maker_description(ClearRN(src.desc));
code ~= format("final abstract class %s : Peripheral!(%s,Conf) {\n",src.name,src.address);
}
// 中断
if(src.inp && !(istemplate)){
code ~= maker_tab(4) ~ "///";
foreach(iv;src.inp)
{
code ~= iv.name;
code ~= ",";
}
code ~= "\n";
code ~= maker_tab(4) ~ "enum interrupts=[";
foreach(iv;src.inp)
{
code ~= iv.val;
code ~= ",";
}
code ~= "];\n";
}
foreach(rv;src.regs){
//code ~= maker_description(ClearRN(rv.description),4);
code ~= maker_tab(4);
code ~= format("/// %s\n",ClearRN(rv.description));
code ~= maker_tab(4);
code ~= format("final abstract class %s : Register!(%s,Access.%s){\n",rv.name,rv.addressOffset,checkAccess(rv.access));
//bit
foreach(fv;rv.fields)
{
//code ~= maker_description(ClearRN(fv.description),8);
code ~= maker_tab(8);
code ~= format("/// %s\n",ClearRN(fv.description));
code ~= maker_tab(8);
code ~= format("alias %s=Bits!(%s,%s,Access.%s);\n",fv.name,fv.bitOffset,fv.bitWidth,checkAccess(fv.access));
}
code ~= maker_tab(4);
code ~= "}\n";
}
code ~= "}\n";
return code;
}
enum tabwidth = 0xff;
string maker_tab(in uint start)
{
string stab;
for(auto i=(start / tabwidth);i>0;i--) stab ~= "\t";
for(auto i=(start % tabwidth);i>0;i--) stab ~= " ";
return stab;
}
string maker_desc1(in uint start,in uint end)
{
string ret;
ret ~= maker_tab(start);
ret ~= "//";
for(auto i=(end - start - 2);i>0;i--) ret ~= "-";
ret ~= "\n";
return ret;
}
string maker_description(string desc,in uint start = 0,in uint end=90)
{
string ret;
string stab;
string ssp;
stab = maker_tab(start);
ssp ~= stab ~ "/";
for(auto i=(end - start - 1);i>0;i--) ssp ~= "*";
ssp ~= "\n";
//
ret ~= ssp;
ret ~= stab;
ret ~= "*\t" ~ desc;
ret ~= "\n"~stab~"*/\n";
return ret;
}
string ClearRN(string s)
{
string r;
foreach(string line; splitter(s, regex("[\r\n]+") )){
r ~= line.stripLeft(" ");
}
return r;
}
string checkAccess(string s)
{
switch(s.toLower()){
case "read-only": return "ro";
case "read-write": return "rw";
case "write-only": return "wo";
default:break;
}
if(s.length) writefln("no:%s",s);
return "rwa";
}