mirror of
https://github.com/holub/mame
synced 2025-10-07 01:16:22 +03:00
First version of a eagle to netlist converter. (nw)
This commit is contained in:
parent
e1d1a6b1f2
commit
84f26ad714
@ -59,6 +59,30 @@ private:
|
|||||||
pstring m_val;
|
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
|
class poption_bool : public poption
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -100,20 +100,21 @@ public:
|
|||||||
|
|
||||||
void set_identifier_chars(pstring s) { m_identifier_chars = s; }
|
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_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_whitespace(pstring s) { m_whitespace = s; }
|
||||||
void set_comment(pstring start, pstring end, pstring line)
|
void set_comment(pstring start, pstring end, pstring line)
|
||||||
{
|
{
|
||||||
m_tok_comment_start = register_token(start);
|
m_tok_comment_start = register_token(start);
|
||||||
m_tok_comment_end = register_token(end);
|
m_tok_comment_end = register_token(end);
|
||||||
m_tok_line_comment = register_token(line);
|
m_tok_line_comment = register_token(line);
|
||||||
m_string = '"';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
token_t get_token_internal();
|
token_t get_token_internal();
|
||||||
void error(const char *format, ...) ATTR_PRINTF(2,3);
|
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; }
|
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;
|
virtual void verror(pstring msg, int line_num, pstring line) = 0;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
#include "nl_factory.h"
|
#include "nl_factory.h"
|
||||||
#include "nl_parser.h"
|
#include "nl_parser.h"
|
||||||
#include "devices/net_lib.h"
|
#include "devices/net_lib.h"
|
||||||
|
#include "tools/nl_convert.h"
|
||||||
|
|
||||||
|
|
||||||
#ifdef PSTANDALONE_PROVIDED
|
#ifdef PSTANDALONE_PROVIDED
|
||||||
@ -101,6 +102,7 @@ public:
|
|||||||
opt_name("n", "name", "", "netlist in file to run; default is first one", this),
|
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_logs("l", "logs", "", "colon separated list of terminals to log", this),
|
||||||
opt_file("f", "file", "-", "file to process (default is stdin)", 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_cmd ("c", "cmd", "run", "run|convert|listdevices", this),
|
||||||
opt_verb("v", "verbose", "be verbose - this produces lots of output", this),
|
opt_verb("v", "verbose", "be verbose - this produces lots of output", this),
|
||||||
opt_help("h", "help", "display help", this)
|
opt_help("h", "help", "display help", this)
|
||||||
@ -110,6 +112,7 @@ public:
|
|||||||
poption_str opt_name;
|
poption_str opt_name;
|
||||||
poption_str opt_logs;
|
poption_str opt_logs;
|
||||||
poption_str opt_file;
|
poption_str opt_file;
|
||||||
|
poption_str_limit opt_type;
|
||||||
poption_str opt_cmd;
|
poption_str opt_cmd;
|
||||||
poption_bool opt_verb;
|
poption_bool opt_verb;
|
||||||
poption_bool opt_help;
|
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")
|
else if (cmd == "convert")
|
||||||
{
|
{
|
||||||
pstring contents = filetobuf(opts.opt_file());
|
pstring contents = filetobuf(opts.opt_file());
|
||||||
convert_t converter;
|
nl_convert_base_t *converter = NULL;
|
||||||
converter.convert(contents);
|
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
|
else
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user