summaryrefslogtreecommitdiffstatshomepage
path: root/src/lib/netlist/tools/nl_convert.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/netlist/tools/nl_convert.cpp')
-rw-r--r--src/lib/netlist/tools/nl_convert.cpp218
1 files changed, 195 insertions, 23 deletions
diff --git a/src/lib/netlist/tools/nl_convert.cpp b/src/lib/netlist/tools/nl_convert.cpp
index 28cf290d97c..dfc98598a97 100644
--- a/src/lib/netlist/tools/nl_convert.cpp
+++ b/src/lib/netlist/tools/nl_convert.cpp
@@ -9,12 +9,15 @@
#include <algorithm>
#include <unordered_map>
+#include <vector>
// FIXME: temporarily defined here - should be in a file
// FIXME: family logic in netlist is convoluted, create
// define a model param on core device
// Format: external name,netlist device,model
+
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays,modernize-avoid-c-arrays)
static constexpr const char s_lib_map[] =
"SN74LS00D, TTL_7400_DIP, 74LSXX\n"
"SN74LS04D, TTL_7404_DIP, 74LSXX\n"
@@ -58,7 +61,7 @@ static lib_map_t read_lib_map(const pstring &lm)
nl_convert_base_t::nl_convert_base_t()
: out(&m_buf)
- , m_numberchars("0123456789-+e.")
+ , m_numberchars("0123456789-+Ee.")
{
m_buf.imbue(std::locale::classic());
m_units = {
@@ -81,6 +84,14 @@ nl_convert_base_t::nl_convert_base_t()
{"MIL", "{1}", 25.4e-6}
};
+ dev_map =
+ {
+ { "VCCS", {"OP", "ON", "IP", "IN"} },
+ { "VCVS", {"OP", "ON", "IP", "IN"} },
+ { "CCCS", {"OP", "ON", "IP", "IN"} },
+ { "CCVS", {"OP", "ON", "IP", "IN"} },
+ { "VS", {"1", "2"} },
+ };
}
nl_convert_base_t::~nl_convert_base_t()
@@ -147,8 +158,65 @@ void nl_convert_base_t::add_term(const pstring &netname, const pstring &termname
net->terminals().push_back(termname);
}
+void nl_convert_base_t::add_term(const pstring &netname, const pstring &devname, unsigned term)
+{
+ auto e = dev_map.find(get_device(devname)->type());
+ if (e == dev_map.end())
+ out("// ERROR: No terminals found for device {}\n", devname);
+ else
+ {
+ if (term >= e->second.size())
+ out("// ERROR: {} : Term {} exceeds number of terminals {}\n", netname, devname, term);
+ else
+ add_term(netname, devname + "." + e->second[term]);
+ }
+}
+
+void nl_convert_base_t::add_device_extra_s(const pstring &devname, const pstring &extra)
+{
+ auto dev = get_device(devname);
+ if (dev == nullptr)
+ out("// ERROR: Device {} not found\n", devname);
+ else
+ {
+ dev->add_extra(extra);
+ }
+}
+
+
+
void nl_convert_base_t::dump_nl()
{
+ // do replacements
+ for (auto &r : m_replace)
+ {
+ // Get the device entry
+ auto *d = get_device(r.m_ce);
+ if (d == nullptr)
+ {
+ out("ERROR: Can not find <{}>\n", r.m_ce);
+ continue;
+ }
+
+ auto e = dev_map.find(d->type());
+ if (e == dev_map.end())
+ {
+ out("ERROR: Can not find type {}\n", d->type());
+ continue;
+ }
+ pstring term1 = r.m_ce + "." + e->second[0];
+ // scan all nets
+ for (auto &n : m_nets)
+ {
+ for (auto &t : n.second->terminals())
+ {
+ if (t == term1)
+ t = r.m_repterm;
+ }
+ }
+ add_term(r.m_net, term1);
+ }
+
for (auto & alias : m_ext_alias)
{
net_t *net = m_nets[alias].get();
@@ -178,6 +246,9 @@ void nl_convert_base_t::dump_nl()
else
out("{}({})\n", m_devs[j]->type().c_str(),
m_devs[j]->name().c_str());
+ for (auto &e : m_devs[j]->extra())
+ out("{}\n", e);
+
}
// print nets
for (auto & i : m_nets)
@@ -193,13 +264,14 @@ void nl_convert_base_t::dump_nl()
out(")\n");
}
}
+ m_replace.clear();
m_devs.clear();
m_nets.clear();
m_pins.clear();
m_ext_alias.clear();
}
-const pstring nl_convert_base_t::get_nl_val(const double val)
+pstring nl_convert_base_t::get_nl_val(double val)
{
for (auto &e : m_units)
{
@@ -291,6 +363,22 @@ static pstring rem(const std::vector<pstring> &vps, std::size_t start)
return r;
}
+static int npoly(const pstring &s)
+{
+ // Brute force
+ if (s=="POLY(1)")
+ return 1;
+ if (s=="POLY(2)")
+ return 2;
+ if (s=="POLY(3)")
+ return 3;
+ if (s=="POLY(4)")
+ return 4;
+ if (s=="POLY(5)")
+ return 5;
+ return -1;
+}
+
void nl_convert_spice_t::process_line(const pstring &line)
{
if (line != "")
@@ -384,24 +472,105 @@ void nl_convert_spice_t::process_line(const pstring &line)
add_term(tt[2], tt[0] + ".N");
break;
case 'E':
- add_device("VCVS", tt[0]);
+ {
+ auto n=npoly(tt[3]);
+ if (n<0)
+ {
+ add_device("VCVS", tt[0]);
+ add_term(tt[1], tt[0], 0);
+ add_term(tt[2], tt[0], 1);
+ add_term(tt[3], tt[0], 2);
+ add_term(tt[4], tt[0], 3);
+ add_device_extra(tt[0], "PARAM({}, {})", tt[0] + ".G", tt[5]);
+ }
+ else
+ {
+ unsigned sce(4);
+ auto scoeff(static_cast<unsigned>(5 + n));
+ if ((tt.size() != 5 + 2 * static_cast<unsigned>(n)) || (tt[scoeff-1] != "0"))
+ {
+ out("// IGNORED {}: {}\n", tt[0].c_str(), line.c_str());
+ break;
+ }
+ pstring lastnet = tt[1];
+ for (std::size_t i=0; i < static_cast<std::size_t>(n); i++)
+ {
+ pstring devname = tt[0] + plib::pfmt("{}")(i);
+ pstring nextnet = (i<static_cast<std::size_t>(n)-1) ? tt[1] + "a" + plib::pfmt("{}")(i) : tt[2];
+ auto net2 = plib::psplit(plib::replace_all(plib::replace_all(tt[sce+i],")",""),"(",""),",");
+ add_device("VCVS", devname);
+ add_term(lastnet, devname, 0);
+ add_term(nextnet, devname, 1);
+ add_term(net2[0], devname, 2);
+ add_term(net2[1], devname, 3);
+ add_device_extra(devname, "PARAM({}, {})", devname + ".G", tt[scoeff+i]);
+ lastnet = nextnet;
+ //printf("xxx %d %s %s\n", (int) net2.size(), net2[0].c_str(), net2[1].c_str());
+#if 0
+ pstring extranetname = devname + "net";
+ m_replace.push_back({, devname + ".IP", extranetname });
+ add_term(extranetname, devname + ".IN");
+ add_device_extra(devname, "PARAM({}, {})", devname + ".G", tt[scoeff+i]);
+#endif
+ }
+ }
+ }
+ break;
+ case 'F':
+ {
+ auto n=npoly(tt[3]);
+ unsigned sce(4);
+ unsigned scoeff(5 + static_cast<unsigned>(n));
+ if (n<0)
+ {
+ sce = 3;
+ scoeff = 4;
+ n = 1;
+ }
+ else
+ {
+ if ((tt.size() != 5 + 2 * static_cast<unsigned>(n)) || (tt[scoeff-1] != "0"))
+ {
+ out("// IGNORED {}: {}\n", tt[0].c_str(), line.c_str());
+ break;
+ }
+ }
+ for (std::size_t i=0; i < static_cast<std::size_t>(n); i++)
+ {
+ pstring devname = tt[0] + plib::pfmt("{}")(i);
+ add_device("CCCS", devname);
+ add_term(tt[1], devname, 0);
+ add_term(tt[2], devname, 1);
+
+ pstring extranetname = devname + "net";
+ m_replace.push_back({tt[sce+i], devname + ".IP", extranetname });
+ add_term(extranetname, devname + ".IN");
+ add_device_extra(devname, "PARAM({}, {})", devname + ".G", tt[scoeff+i]);
+ }
+ }
+ break;
+ case 'H':
+ add_device("CCVS", tt[0]);
add_term(tt[1], tt[0] + ".OP");
add_term(tt[2], tt[0] + ".ON");
- add_term(tt[3], tt[0] + ".IP");
- add_term(tt[4], tt[0] + ".IN");
- out("PARAM({}, {})\n", tt[0] + ".G", tt[5]);
+ m_replace.push_back({tt[3], tt[0] + ".IP", tt[2] + "a" });
+ add_term(tt[2] + "a", tt[0] + ".IN");
+ add_device_extra(tt[0], "PARAM({}, {})", tt[0] + ".G", tt[4]);
+ break;
+ case 'G':
+ add_device("VCCS", tt[0]);
+ add_term(tt[1], tt[0], 0);
+ add_term(tt[2], tt[0], 1);
+ add_term(tt[3], tt[0], 2);
+ add_term(tt[4], tt[0], 3);
+ add_device_extra(tt[0], "PARAM({}, {})", tt[0] + ".G", tt[5]);
break;
case 'V':
- // just simple Voltage sources ....
- if (tt[2] == "0")
- {
- val = get_sp_val(tt[3]);
- add_device("ANALOG_INPUT", tt[0], val);
- add_term(tt[1], tt[0] + ".Q");
- //add_term(tt[2], tt[0] + ".2");
- }
- else
- plib::perrlogger("Voltage Source {} not connected to GND\n", tt[0]);
+ // only DC Voltage sources ....
+ val = get_sp_val(tt[3] == "DC" ? tt[4] : tt[3]);
+ add_device("VS", tt[0], val);
+ add_term(tt[1], tt[0] + ".1");
+ add_term(tt[2], tt[0] + ".2");
break;
#if 0
// This is wrong ... Need to use something else for inputs!
@@ -415,7 +584,7 @@ void nl_convert_spice_t::process_line(const pstring &line)
#else
case 'I':
{
- val = get_sp_val(tt[3]);
+ val = get_sp_val(tt[3] == "DC" ? tt[4] : tt[3]);
add_device("CS", tt[0], val);
add_term(tt[1], tt[0] + ".1");
add_term(tt[2], tt[0] + ".2");
@@ -423,10 +592,11 @@ void nl_convert_spice_t::process_line(const pstring &line)
break;
#endif
case 'D':
- add_device("DIODE", tt[0], tt[3]);
- // FIXME ==> does Kicad use different notation from LTSPICE
- add_term(tt[1], tt[0] + ".K");
- add_term(tt[2], tt[0] + ".A");
+ add_device("DIODE", tt[0], m_subckt + tt[3]);
+ // Spice D Anode Kathode model
+ // FIXME ==> does Kicad use different notation from LTSPICE ?
+ add_term(tt[1], tt[0] + ".A");
+ add_term(tt[2], tt[0] + ".K");
break;
case 'U':
case 'X':
@@ -499,7 +669,8 @@ void nl_convert_eagle_t::convert(const pstring &contents)
out("NETLIST_END()\n");
return;
}
- else if (token.is(tok.m_tok_SEMICOLON))
+
+ if (token.is(tok.m_tok_SEMICOLON))
{
// ignore empty statements
token = tok.get_token();
@@ -646,7 +817,8 @@ void nl_convert_rinf_t::convert(const pstring &contents)
out("NETLIST_END()\n");
return;
}
- else if (token.is(tok.m_tok_HEA))
+
+ if (token.is(tok.m_tok_HEA))
{
// seems to be start token - ignore
token = tok.get_token();