mirror of
https://github.com/holub/mame
synced 2025-10-06 09:00:04 +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;
|
||||
};
|
||||
|
||||
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:
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user