void nl_convert_spice_t::convert(const pstring &contents) { pstring_vector_t spnl(contents, "\n"); // Add gnd net // FIXME: Parameter out("NETLIST_START(dummy)\n"); add_term("0", "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"); }
void nl_convert_spice_t::convert(const pstring &contents) { std::vector<pstring> spnl(plib::psplit(contents, "\n")); // Add gnd net // FIXME: Parameter out("NETLIST_START(dummy)\n"); add_term("0", "GND"); pstring line = ""; for (const auto &i : spnl) { // Basic preprocessing pstring inl = plib::ucase(plib::trim(i)); if (plib::startsWith(inl, "+")) line = line + inl.substr(1); else { process_line(line); line = inl; } } process_line(line); dump_nl(); // FIXME: Parameter out("NETLIST_END()\n"); }
//FIXME: should accept a stream as well void nl_convert_eagle_t::convert(const pstring &contents) { pistringstream istrm(contents); eagle_tokenizer tok(*this, istrm); out("NETLIST_START(dummy)\n"); add_term("GND", "GND"); add_term("VCC", "VCC"); eagle_tokenizer::token_t token = tok.get_token(); while (true) { if (token.is_type(eagle_tokenizer::ENDOFFILE)) { dump_nl(); // FIXME: Parameter out("NETLIST_END()\n"); return; } else if (token.is(tok.m_tok_SEMICOLON)) { /* ignore empty statements */ token = tok.get_token(); } else if (token.is(tok.m_tok_ADD)) { pstring name = tok.get_string(); /* skip to semicolon */ do { token = tok.get_token(); } while (!token.is(tok.m_tok_SEMICOLON)); token = tok.get_token(); pstring sval = ""; if (token.is(tok.m_tok_VALUE)) { pstring vname = tok.get_string(); sval = tok.get_string(); tok.require_token(tok.m_tok_SEMICOLON); token = tok.get_token(); } switch (name.code_at(0)) { case 'Q': { add_device("QBJT", name, sval); } break; case 'R': { double val = get_sp_val(sval); add_device("RES", name, val); } break; case 'C': { double val = get_sp_val(sval); add_device("CAP", name, val); } break; case 'P': if (sval.ucase() == "HIGH") add_device("TTL_INPUT", name, 1); else if (sval.ucase() == "LOW") add_device("TTL_INPUT", name, 0); else add_device("ANALOG_INPUT", name, sval.as_double()); add_pin_alias(name, "1", "Q"); break; case 'D': /* Pin 1 = Anode, Pin 2 = Cathode */ add_device("DIODE", name, sval); add_pin_alias(name, "1", "A"); add_pin_alias(name, "2", "K"); break; case 'U': case 'X': { pstring tname = "TTL_" + sval + "_DIP"; add_device(tname, name); break; } default: tok.error("// IGNORED " + name); } } else if (token.is(tok.m_tok_SIGNAL)) { pstring netname = tok.get_string(); token = tok.get_token(); while (!token.is(tok.m_tok_SEMICOLON)) { /* fixme: should check for string */ pstring devname = token.str(); pstring pin = tok.get_string(); add_term(netname, devname + "." + pin); token = tok.get_token(); } } else { out("Unexpected {}\n", token.str().cstr()); return; } } }
void nl_convert_spice_t::process_line(const pstring &line) { if (line != "") { pstring_vector_t tt(line, " ", true); double val = 0.0; switch (tt[0].code_at(0)) { case ';': out("// {}\n", line.substr(1).cstr()); break; case '*': out("// {}\n", line.substr(1).cstr()); break; case '.': if (tt[0].equals(".SUBCKT")) { out("NETLIST_START({})\n", tt[1].cstr()); for (std::size_t i=2; i<tt.size(); i++) add_ext_alias(tt[i]); } else if (tt[0].equals(".ENDS")) { dump_nl(); out("NETLIST_END()\n"); } else out("// {}\n", line.cstr()); break; case 'Q': { bool cerr = false; /* check for fourth terminal ... should be numeric net * including "0" or start with "N" (ltspice) */ ATTR_UNUSED int nval =tt[4].as_long(&cerr); pstring model; pstring pins ="CBE"; if ((!cerr || tt[4].startsWith("N")) && tt.size() > 5) model = tt[5]; else model = tt[4]; pstring_vector_t m(model,"{"); if (m.size() == 2) { if (m[1].len() != 4) fprintf(stderr, "error with model desc %s\n", model.cstr()); pins = m[1].left(3); } add_device("QBJT_EB", tt[0], m[0]); add_term(tt[1], tt[0] + "." + pins.code_at(0)); add_term(tt[2], tt[0] + "." + pins.code_at(1)); add_term(tt[3], tt[0] + "." + pins.code_at(2)); } break; case 'R': if (tt[0].startsWith("RV")) { val = get_sp_val(tt[4]); add_device("POT", tt[0], val); add_term(tt[1], tt[0] + ".1"); add_term(tt[2], tt[0] + ".2"); add_term(tt[3], tt[0] + ".3"); } else { val = get_sp_val(tt[3]); add_device("RES", tt[0], val); add_term(tt[1], tt[0] + ".1"); add_term(tt[2], tt[0] + ".2"); } break; case 'C': val = get_sp_val(tt[3]); add_device("CAP", tt[0], val); 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]); add_device("ANALOG_INPUT", tt[0], val); 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 'I': // Input pin special notation { val = get_sp_val(tt[2]); add_device("ANALOG_INPUT", tt[0], val); add_term(tt[1], tt[0] + ".Q"); } break; 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"); 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"; add_device(tname, xname); for (std::size_t i=1; i < tt.size() - 1; i++) { pstring term = pfmt("{1}.{2}")(xname)(i); add_term(tt[i], term); } break; } default: out("// IGNORED {}: {}\n", tt[0].cstr(), line.cstr()); } } }
void nl_convert_rinf_t::convert(const pstring &contents) { tokenizer tok(*this, plib::putf8_reader(plib::pistringstream(contents))); auto lm = read_lib_map(s_lib_map); out("NETLIST_START(dummy)\n"); add_term("GND", "GND"); add_term("VCC", "VCC"); tokenizer::token_t token = tok.get_token(); while (true) { if (token.is_type(tokenizer::ENDOFFILE) || token.is(tok.m_tok_END)) { dump_nl(); // FIXME: Parameter out("NETLIST_END()\n"); return; } else if (token.is(tok.m_tok_HEA)) { /* seems to be start token - ignore */ token = tok.get_token(); } else if (token.is(tok.m_tok_APP)) { /* version string */ pstring app = tok.get_string(); out("// APP: {}\n", app); token = tok.get_token(); } else if (token.is(tok.m_tok_TIM)) { /* time */ out("// TIM:"); for (int i=0; i<6; i++) { long x = tok.get_number_long(); out(" {}", x); } out("\n"); token = tok.get_token(); } else if (token.is(tok.m_tok_TYP)) { pstring id(tok.get_identifier()); out("// TYP: {}\n", id); token = tok.get_token(); } else if (token.is(tok.m_tok_ADDC)) { std::unordered_map<pstring, pstring> attr; pstring id = tok.get_identifier(); pstring s1 = tok.get_string(); pstring s2 = tok.get_string(); token = tok.get_token(); while (token.is(tok.m_tok_ATTC)) { pstring tid = tok.get_identifier(); if (tid != id) { out("Error: found {} expected {} in {}\n", tid, id, token.str()); return; } pstring at = tok.get_string(); pstring val = tok.get_string(); attr[at] = val; token = tok.get_token(); } pstring sim = attr["Simulation"]; pstring val = attr["Value"]; pstring com = attr["Comment"]; if (val == "") val = com; if (sim == "CAP") { add_device("CAP", id, get_sp_val(val)); } else if (sim == "RESISTOR") { add_device("RES", id, get_sp_val(val)); } else { pstring lib = attr["Library Reference"]; auto f = lm.find(lib); if (f != lm.end()) add_device(f->second.dev, id); else add_device(lib, id); } } else if (token.is(tok.m_tok_NET)) { pstring dev = tok.get_identifier(); pstring pin = tok.get_identifier_or_number(); pstring net = tok.get_string(); add_term(net, dev + "." + pin); token = tok.get_token(); if (token.is(tok.m_tok_TER)) { token = tok.get_token(); while (token.is_type(plib::ptokenizer::IDENTIFIER)) { pin = tok.get_identifier_or_number(); add_term(net, token.str() + "." + pin); token = tok.get_token(); } } } #if 0 token = tok.get_token(); /* skip to semicolon */ do { token = tok.get_token(); } while (!token.is(tok.m_tok_SEMICOLON)); token = tok.get_token(); pstring sval = ""; if (token.is(tok.m_tok_VALUE)) { pstring vname = tok.get_string(); sval = tok.get_string(); tok.require_token(tok.m_tok_SEMICOLON); token = tok.get_token(); } switch (name.code_at(0)) { case 'Q': { add_device("QBJT", name, sval); } break; case 'R': { double val = get_sp_val(sval); add_device("RES", name, val); } break; case 'C': { double val = get_sp_val(sval); add_device("CAP", name, val); } break; case 'P': if (sval.ucase() == "HIGH") add_device("TTL_INPUT", name, 1); else if (sval.ucase() == "LOW") add_device("TTL_INPUT", name, 0); else add_device("ANALOG_INPUT", name, sval.as_double()); add_pin_alias(name, "1", "Q"); break; case 'D': /* Pin 1 = Anode, Pin 2 = Cathode */ add_device("DIODE", name, sval); add_pin_alias(name, "1", "A"); add_pin_alias(name, "2", "K"); break; case 'U': case 'X': { pstring tname = "TTL_" + sval + "_DIP"; add_device(tname, name); break; } default: tok.error("// IGNORED " + name); } } else if (token.is(tok.m_tok_SIGNAL))
void nl_convert_spice_t::process_line(const pstring &line) { if (line != "") { //printf("// %s\n", line.c_str()); std::vector<pstring> tt(plib::psplit(line, " ", true)); double val = 0.0; switch (tt[0].at(0)) { case ';': out("// {}\n", line.substr(1)); break; case '*': out("// {}\n", line.substr(1).c_str()); break; case '.': if (tt[0] == ".SUBCKT") { m_subckt = tt[1] + "_"; out("NETLIST_START({})\n", tt[1]); for (std::size_t i=2; i<tt.size(); i++) add_ext_alias(tt[i]); } else if (tt[0] == ".ENDS") { dump_nl(); out("NETLIST_END()\n"); m_subckt = ""; } else if (tt[0] == ".MODEL") { out("NET_MODEL(\"{} {}\")\n", m_subckt + tt[1], rem(tt,2)); } else out("// {}\n", line.c_str()); break; case 'Q': { /* check for fourth terminal ... should be numeric net * including "0" or start with "N" (ltspice) */ pstring model; pstring pins ="CBE"; bool err; auto nval = plib::pstonum_ne<long, true>(tt[4], err); plib::unused_var(nval); if ((!err || plib::startsWith(tt[4], "N")) && tt.size() > 5) model = tt[5]; else model = tt[4]; std::vector<pstring> m(plib::psplit(model,"{")); if (m.size() == 2) { if (m[1].length() != 4) plib::perrlogger("error with model desc {}\n", model); pins = plib::left(m[1], 3); } add_device("QBJT_EB", tt[0], m_subckt + m[0]); add_term(tt[1], tt[0] + "." + pins.at(0)); add_term(tt[2], tt[0] + "." + pins.at(1)); add_term(tt[3], tt[0] + "." + pins.at(2)); } break; case 'R': if (plib::startsWith(tt[0], "RV")) { val = get_sp_val(tt[4]); add_device("POT", tt[0], val); add_term(tt[1], tt[0] + ".1"); add_term(tt[2], tt[0] + ".2"); add_term(tt[3], tt[0] + ".3"); } else { val = get_sp_val(tt[3]); add_device("RES", tt[0], val); add_term(tt[1], tt[0] + ".1"); add_term(tt[2], tt[0] + ".2"); } break; case 'C': val = get_sp_val(tt[3]); add_device("CAP", tt[0], val); add_term(tt[1], tt[0] + ".1"); add_term(tt[2], tt[0] + ".2"); break; case 'B': // arbitrary behavioural current source - needs manual work afterwords add_device("CS", tt[0], "/*" + rem(tt, 3) + "*/"); add_term(tt[1], tt[0] + ".P"); add_term(tt[2], tt[0] + ".N"); break; case 'E': add_device("VCVS", 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]); 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]); break; #if 0 // This is wrong ... Need to use something else for inputs! case 'I': // Input pin special notation { val = get_sp_val(tt[2]); add_device("ANALOG_INPUT", tt[0], val); add_term(tt[1], tt[0] + ".Q"); } break; #else case 'I': { val = get_sp_val(tt[3]); add_device("CS", tt[0], val); add_term(tt[1], tt[0] + ".1"); add_term(tt[2], tt[0] + ".2"); } 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"); break; case 'U': case 'X': { // FIXME: specific code for KICAD exports // last element is component type // FIXME: Parameter pstring xname = plib::replace_all(tt[0], pstring("."), pstring("_")); pstring tname = "TTL_" + tt[tt.size()-1] + "_DIP"; add_device(tname, xname); for (std::size_t i=1; i < tt.size() - 1; i++) { pstring term = plib::pfmt("{1}.{2}")(xname)(i); add_term(tt[i], term); } break; } default: out("// IGNORED {}: {}\n", tt[0].c_str(), line.c_str()); } } }