Add a preliminary parser for RINF netlist format. (nw)

This commit is contained in:
couriersud 2016-08-10 23:08:20 +02:00
parent 65d5cf7592
commit d0970c215f
4 changed files with 332 additions and 6 deletions

View File

@ -106,7 +106,7 @@ pstring ptokenizer::get_identifier_or_number()
token_t tok = get_token();
if (!(tok.is_type(IDENTIFIER) || tok.is_type(NUMBER)))
{
error(pfmt("Expected an identifier, got <{1}>")(tok.str()) );
error(pfmt("Expected an identifier or number, got <{1}>")(tok.str()) );
}
return tok.str();
}
@ -203,7 +203,8 @@ ptokenizer::token_t ptokenizer::get_token_internal()
{
/* read identifier till non identifier char */
pstring tokstr = "";
while (m_identifier_chars.find(c) != m_identifier_chars.end()) {
while (m_identifier_chars.find(c) != m_identifier_chars.end())
{
tokstr += c;
c = getc();
}
@ -229,7 +230,8 @@ ptokenizer::token_t ptokenizer::get_token_internal()
{
/* read identifier till first identifier char or ws */
pstring tokstr = "";
while ((m_identifier_chars.find(c)) == m_identifier_chars.end() && (m_whitespace.find(c) == m_whitespace.end())) {
while ((m_identifier_chars.find(c) == m_identifier_chars.end()) && (m_whitespace.find(c) == m_whitespace.end()))
{
tokstr += c;
/* expensive, check for single char tokens */
if (tokstr.len() == 1)

View File

@ -41,7 +41,7 @@ public:
opt_logs(*this, "l", "log" , "define terminal to log. This option may be specified repeatedly."),
opt_inp(*this, "i", "input", "", "input file to process (default is none)"),
opt_grp4(*this, "Options for convert command", "These options are only used by the convert command."),
opt_type(*this, "y", "type", "spice", "spice:eagle", "type of file to be converted: spice,eagle"),
opt_type(*this, "y", "type", "spice", "spice:eagle:rinf", "type of file to be converted: spice,eagle,rinf"),
opt_ex1(*this, "nltool -c run -t 3.5 -f nl_examples/cdelay.c -n cap_delay",
"Run netlist \"cap_delay\" from file nl_examples/cdelay.c for 3.5 seconds"),
@ -465,12 +465,18 @@ int main(int argc, char *argv[])
c.convert(contents);
result = c.result();
}
else
else if (opts.opt_type().equals("eagle"))
{
nl_convert_eagle_t c;
c.convert(contents);
result = c.result();
}
else if (opts.opt_type().equals("rinf"))
{
nl_convert_rinf_t c;
c.convert(contents);
result = c.result();
}
/* present result */
pout_strm.write(result.cstr());
}

View File

@ -8,9 +8,51 @@
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <unordered_map>
#include "nl_convert.h"
#include "plib/palloc.h"
#include "plib/putil.h"
/* 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 */
static const char *s_lib_map =
"SN74LS00D, TTL_7400_DIP, 74LSXX\n"
"SN74LS04D, TTL_7404_DIP, 74LSXX\n"
"SN74ALS08D, TTL_7408_DIP, 74ALSXX\n"
"SN74ALS10AD, TTL_7410_DIP, 74ALSXX\n"
"SN74LS30N, TTL_7430_DIP, 74LSXX\n"
"SN74ALS74AD, TTL_7474_DIP, 74ALSXX\n"
"SN74LS74AD, TTL_7474_DIP, 74LSXX\n"
"SN74LS86AD, TTL_7486_DIP, 74LSXX\n"
"SN74F153D, TTL_74153_DIP, 74FXX\n"
"SN74LS161AD, TTL_74161_DIP, 74LSXX\n"
"SN74LS164D, TTL_74164_DIP, 74LSXX\n"
"DM74LS366AN, TTL_74366_DIP, 74LSXX\n"
;
struct lib_map_entry
{
pstring dev;
pstring model;
};
using lib_map_t = std::unordered_map<pstring, lib_map_entry>;
static lib_map_t read_lib_map(const pstring lm)
{
plib::pistringstream istrm(lm);
lib_map_t m;
pstring line;
while (istrm.readline(line))
{
plib::pstring_vector_t split(line, ",");
m[split[0].trim()] = { split[1].trim(), split[2].trim() };
}
return m;
}
/*-------------------------------------------------
convert - convert a spice netlist
@ -173,8 +215,9 @@ nl_convert_base_t::unit_t nl_convert_base_t::m_units[] = {
{"M", "CAP_M({1})", 1.0e-3 },
{"u", "CAP_U({1})", 1.0e-6 }, /* eagle */
{"U", "CAP_U({1})", 1.0e-6 },
{"??", "CAP_U({1})", 1.0e-6 },
{"??", "CAP_U({1})", 1.0e-6 }, /* FIXME */
{"N", "CAP_N({1})", 1.0e-9 },
{"pF", "CAP_P({1})", 1.0e-12},
{"P", "CAP_P({1})", 1.0e-12},
{"F", "{1}e-15", 1.0e-15},
@ -448,3 +491,209 @@ void nl_convert_eagle_t::convert(const pstring &contents)
}
}
/* token_id_t m_tok_HFA;
token_id_t m_tok_APP;
token_id_t m_tok_TIM;
token_id_t m_tok_TYP;
token_id_t m_tok_ADDC;
token_id_t m_tok_ATTC;
token_id_t m_tok_NET;
token_id_t m_tok_TER;
*
*/
void nl_convert_rinf_t::convert(const pstring &contents)
{
plib::pistringstream istrm(contents);
tokenizer tok(*this, istrm);
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))
{
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(); }
}
#endif
else
{
out("Unexpected {}\n", token.str());
return;
}
}
}

View File

@ -217,6 +217,75 @@ public:
protected:
private:
};
class nl_convert_rinf_t : public nl_convert_base_t
{
public:
nl_convert_rinf_t() : nl_convert_base_t() {}
~nl_convert_rinf_t()
{
}
class tokenizer : public plib::ptokenizer
{
public:
tokenizer(nl_convert_rinf_t &convert, plib::pistream &strm)
: plib::ptokenizer(strm), m_convert(convert)
{
set_identifier_chars(".abcdefghijklmnopqrstuvwvxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890_-");
set_number_chars("0123456789", "0123456789eE-."); //FIXME: processing of numbers
char ws[5];
ws[0] = ' ';
ws[1] = 9;
ws[2] = 10;
ws[3] = 13;
ws[4] = 0;
set_whitespace(ws);
/* FIXME: gnetlist doesn't print comments */
set_comment("","","//"); // FIXME:needs to be confirmed
set_string_char('"');
m_tok_HEA = register_token(".HEA");
m_tok_APP = register_token(".APP");
m_tok_TIM = register_token(".TIM");
m_tok_TYP = register_token(".TYP");
m_tok_ADDC = register_token(".ADD_COM");
m_tok_ATTC = register_token(".ATT_COM");
m_tok_NET = register_token(".ADD_TER");
m_tok_TER = register_token(".TER");
m_tok_END = register_token(".END");
}
token_id_t m_tok_HEA;
token_id_t m_tok_APP;
token_id_t m_tok_TIM;
token_id_t m_tok_TYP;
token_id_t m_tok_ADDC;
token_id_t m_tok_ATTC;
token_id_t m_tok_NET;
token_id_t m_tok_TER;
token_id_t m_tok_END;
protected:
void verror(const pstring &msg, int line_num, const pstring &line) override
{
m_convert.out("{} (line {}): {}\n", msg.cstr(), line_num, line.cstr());
}
private:
nl_convert_rinf_t &m_convert;
};
void convert(const pstring &contents) override;
protected:
private:
};