First version of a eagle to netlist converter. (nw)

This commit is contained in:
couriersud 2015-05-29 02:40:39 +02:00
parent e1d1a6b1f2
commit 84f26ad714
3 changed files with 39 additions and 336 deletions

View File

@ -59,6 +59,30 @@ private:
pstring m_val;
};
class poption_str_limit : public poption
{
public:
poption_str_limit(pstring ashort, pstring along, pstring defval, pstring limit, pstring help, poptions *parent = NULL)
: poption(ashort, along, help, true, parent), m_val(defval), m_limit(limit, ":")
{}
virtual int parse(pstring argument)
{
if (m_limit.contains(argument))
{
m_val = argument;
return 0;
}
else
return 1;
}
pstring operator ()() { return m_val; }
private:
pstring m_val;
pstring_list_t m_limit;
};
class poption_bool : public poption
{
public:

View File

@ -100,20 +100,21 @@ public:
void set_identifier_chars(pstring s) { m_identifier_chars = s; }
void set_number_chars(pstring st, pstring rem) { m_number_chars_start = st; m_number_chars = rem; }
void set_string_char(char c) { m_string = c; }
void set_whitespace(pstring s) { m_whitespace = s; }
void set_comment(pstring start, pstring end, pstring line)
{
m_tok_comment_start = register_token(start);
m_tok_comment_end = register_token(end);
m_tok_line_comment = register_token(line);
m_string = '"';
}
token_t get_token_internal();
void error(const char *format, ...) ATTR_PRINTF(2,3);
protected:
void reset(const char *p) { m_px = p; m_line = 1; m_line_ptr = p; }
protected:
virtual void verror(pstring msg, int line_num, pstring line) = 0;
private:

View File

@ -23,6 +23,7 @@
#include "nl_factory.h"
#include "nl_parser.h"
#include "devices/net_lib.h"
#include "tools/nl_convert.h"
#ifdef PSTANDALONE_PROVIDED
@ -101,6 +102,7 @@ public:
opt_name("n", "name", "", "netlist in file to run; default is first one", this),
opt_logs("l", "logs", "", "colon separated list of terminals to log", this),
opt_file("f", "file", "-", "file to process (default is stdin)", this),
opt_type("y", "type", "spice", "spice:eagle", "type of file to be converted: spice,eagle", this),
opt_cmd ("c", "cmd", "run", "run|convert|listdevices", this),
opt_verb("v", "verbose", "be verbose - this produces lots of output", this),
opt_help("h", "help", "display help", this)
@ -110,6 +112,7 @@ public:
poption_str opt_name;
poption_str opt_logs;
poption_str opt_file;
poption_str_limit opt_type;
poption_str opt_cmd;
poption_bool opt_verb;
poption_bool opt_help;
@ -340,338 +343,6 @@ static void listdevices()
}
}
/*-------------------------------------------------
convert - convert a spice netlist
-------------------------------------------------*/
class convert_t
{
public:
convert_t() {};
~convert_t()
{
nets.clear_and_free();
devs.clear_and_free();
}
void convert(const pstring &contents)
{
pstring_list_t spnl(contents, "\n");
// Add gnd net
// FIXME: Parameter
out("NETLIST_START(dummy)\n");
nets.add(palloc(sp_net_t, "0"), false);
nets[0]->terminals().add("GND");
pstring line = "";
for (std::size_t i=0; i < spnl.size(); i++)
{
// Basic preprocessing
pstring inl = spnl[i].trim().ucase();
if (inl.startsWith("+"))
line = line + inl.substr(1);
else
{
process_line(line);
line = inl;
}
}
process_line(line);
dump_nl();
// FIXME: Parameter
out("NETLIST_END()\n");
printf("%s", m_buf.cstr());
}
protected:
struct sp_net_t
{
public:
sp_net_t(const pstring &aname)
: m_name(aname), m_no_export(false) {}
const pstring &name() { return m_name;}
pstring_list_t &terminals() { return m_terminals; }
void set_no_export() { m_no_export = true; }
bool is_no_export() { return m_no_export; }
private:
pstring m_name;
bool m_no_export;
pstring_list_t m_terminals;
};
struct sp_dev_t
{
public:
sp_dev_t(const pstring &atype, const pstring &aname, const pstring &amodel)
: m_type(atype), m_name(aname), m_model(amodel), m_val(0), m_has_val(false)
{}
sp_dev_t(const pstring &atype, const pstring &aname, double aval)
: m_type(atype), m_name(aname), m_model(""), m_val(aval), m_has_val(true)
{}
sp_dev_t(const pstring &atype, const pstring &aname)
: m_type(atype), m_name(aname), m_model(""), m_val(0.0), m_has_val(false)
{}
const pstring &name() { return m_name;}
const pstring &type() { return m_type;}
const pstring &model() { return m_model;}
const double &value() { return m_val;}
bool has_model() { return m_model != ""; }
bool has_value() { return m_has_val; }
private:
pstring m_type;
pstring m_name;
pstring m_model;
double m_val;
bool m_has_val;
};
struct sp_unit {
pstring sp_unit;
pstring nl_func;
double mult;
};
void add_term(pstring netname, pstring termname)
{
sp_net_t * net = nets.find(netname);
if (net == NULL)
{
net = palloc(sp_net_t, netname);
nets.add(net, false);
}
net->terminals().add(termname);
}
const pstring get_nl_val(const double val)
{
{
int i = 0;
while (m_sp_units[i].sp_unit != "-" )
{
if (m_sp_units[i].mult <= nl_math::abs(val))
break;
i++;
}
return pstring::sprintf(m_sp_units[i].nl_func.cstr(), val / m_sp_units[i].mult);
}
}
double get_sp_unit(const pstring &unit)
{
int i = 0;
while (m_sp_units[i].sp_unit != "-")
{
if (m_sp_units[i].sp_unit == unit)
return m_sp_units[i].mult;
i++;
}
fprintf(stderr, "Unit %s unknown\n", unit.cstr());
return 0.0;
}
double get_sp_val(const pstring &sin)
{
int p = sin.len() - 1;
while (p>=0 && (sin.substr(p,1) < "0" || sin.substr(p,1) > "9"))
p--;
pstring val = sin.substr(0,p + 1);
pstring unit = sin.substr(p + 1);
double ret = get_sp_unit(unit) * val.as_double();
//printf("<%s> %s %d ==> %f\n", sin.cstr(), unit.cstr(), p, ret);
return ret;
}
void dump_nl()
{
for (int i=0; i<alias.size(); i++)
{
sp_net_t *net = nets.find(alias[i]);
// use the first terminal ...
out("ALIAS(%s, %s)\n", alias[i].cstr(), net->terminals()[0].cstr());
// if the aliased net only has this one terminal connected ==> don't dump
if (net->terminals().size() == 1)
net->set_no_export();
}
for (int i=0; i<devs.size(); i++)
{
if (devs[i]->has_value())
out("%s(%s, %s)\n", devs[i]->type().cstr(),
devs[i]->name().cstr(), get_nl_val(devs[i]->value()).cstr());
else if (devs[i]->has_model())
out("%s(%s, \"%s\")\n", devs[i]->type().cstr(),
devs[i]->name().cstr(), devs[i]->model().cstr());
else
out("%s(%s)\n", devs[i]->type().cstr(),
devs[i]->name().cstr());
}
// print nets
for (int i=0; i<nets.size(); i++)
{
sp_net_t * net = nets[i];
if (!net->is_no_export())
{
//printf("Net %s\n", net->name().cstr());
out("NET_C(%s", net->terminals()[0].cstr() );
for (int j=1; j<net->terminals().size(); j++)
{
out(", %s", net->terminals()[j].cstr() );
}
out(")\n");
}
}
devs.clear_and_free();
nets.clear_and_free();
alias.clear();
}
void process_line(const pstring &line)
{
if (line != "")
{
pstring_list_t tt(line, " ", true);
double val = 0.0;
switch (tt[0].cstr()[0])
{
case ';':
out("// %s\n", line.substr(1).cstr());
break;
case '*':
out("// %s\n", line.substr(1).cstr());
break;
case '.':
if (tt[0].equals(".SUBCKT"))
{
out("NETLIST_START(%s)\n", tt[1].cstr());
for (int i=2; i<tt.size(); i++)
alias.add(tt[i]);
}
else if (tt[0].equals(".ENDS"))
{
dump_nl();
out("NETLIST_END()\n");
}
else
out("// %s\n", line.cstr());
break;
case 'Q':
{
bool cerr = false;
/* check for fourth terminal ... should be numeric net
* including "0" or start with "N" (ltspice)
*/
// FIXME: we need a is_long method ..
ATTR_UNUSED int nval =tt[4].as_long(&cerr);
if ((!cerr || tt[4].startsWith("N")) && tt.size() > 5)
devs.add(palloc(sp_dev_t, "QBJT", tt[0], tt[5]), false);
else
devs.add(palloc(sp_dev_t, "QBJT", tt[0], tt[4]), false);
add_term(tt[1], tt[0] + ".C");
add_term(tt[2], tt[0] + ".B");
add_term(tt[3], tt[0] + ".E");
}
break;
case 'R':
val = get_sp_val(tt[3]);
devs.add(palloc(sp_dev_t, "RES", tt[0], val), false);
add_term(tt[1], tt[0] + ".1");
add_term(tt[2], tt[0] + ".2");
break;
case 'C':
val = get_sp_val(tt[3]);
devs.add(palloc(sp_dev_t, "CAP", tt[0], val), false);
add_term(tt[1], tt[0] + ".1");
add_term(tt[2], tt[0] + ".2");
break;
case 'V':
// just simple Voltage sources ....
if (tt[2].equals("0"))
{
val = get_sp_val(tt[3]);
devs.add(palloc(sp_dev_t, "ANALOG_INPUT", tt[0], val), false);
add_term(tt[1], tt[0] + ".Q");
//add_term(tt[2], tt[0] + ".2");
}
else
fprintf(stderr, "Voltage Source %s not connected to GND\n", tt[0].cstr());
break;
case 'D':
// FIXME: Rewrite resistor value
devs.add(palloc(sp_dev_t, "DIODE", tt[0], tt[3]), false);
add_term(tt[1], tt[0] + ".A");
add_term(tt[2], tt[0] + ".K");
break;
case 'U':
case 'X':
{
// FIXME: specific code for KICAD exports
// last element is component type
// FIXME: Parameter
pstring xname = tt[0].replace(".", "_");
pstring tname = "TTL_" + tt[tt.size()-1] + "_DIP";
devs.add(palloc(sp_dev_t, tname, xname), false);
for (int i=1; i < tt.size() - 1; i++)
{
pstring term = pstring::sprintf("%s.%d", xname.cstr(), i);
add_term(tt[i], term);
}
break;
}
default:
pstring::sprintf("// IGNORED %s: %s\n", tt[0].cstr(), line.cstr());
}
}
}
void out(const char *format, ...) ATTR_PRINTF(2,3)
{
va_list ap;
va_start(ap, format);
m_buf += pstring(format).vprintf(ap);
va_end(ap);
}
private:
pnamedlist_t<sp_net_t *> nets;
pnamedlist_t<sp_dev_t *> devs;
plist_t<pstring> alias;
pstringbuffer m_buf;
static sp_unit m_sp_units[];
};
convert_t::sp_unit convert_t::m_sp_units[] = {
{"T", "", 1.0e12 },
{"G", "", 1.0e9 },
{"MEG", "RES_M(%g)", 1.0e6 },
{"K", "RES_K(%g)", 1.0e3 },
{"", "%g", 1.0e0 },
{"M", "CAP_M(%g)", 1.0e-3 },
{"U", "CAP_U(%g)", 1.0e-6 },
{"µ", "CAP_U(%g)", 1.0e-6 },
{"N", "CAP_N(%g)", 1.0e-9 },
{"P", "CAP_P(%g)", 1.0e-12},
{"F", "%ge-15", 1.0e-15},
{"MIL", "%e", 25.4e-6},
{"-", "%g", 1.0 }
};
/*-------------------------------------------------
@ -709,8 +380,15 @@ int main(int argc, char *argv[])
else if (cmd == "convert")
{
pstring contents = filetobuf(opts.opt_file());
convert_t converter;
converter.convert(contents);
nl_convert_base_t *converter = NULL;
if (opts.opt_type().equals("spice"))
converter = palloc(nl_convert_spice_t);
else
converter = palloc(nl_convert_eagle_t);
converter->convert(contents);
/* present result */
printf("%s\n", converter->result().cstr());
pfree(converter);
}
else
{