Enhanced the netlist parser and cleaned pong.c. Also added a folder nl_examples which contains standalone netlist examples. [couriersud]

The examples have a ".c" suffix. In eclipse, I get automatic syntax parsing and error notifications. The parser treats "#" preprocessor defines/includes just as comments.

All of these examples can be run through nltool:

./nltool -f nl_examples/opamp.c -t 1 -l OUT

runs the opamp example for 1 second of emulation time and logs the terminal named "OUT" to "netlist_log_OUT.log".

I'll post a simple script to the list to visualize those logs using gnuplot.
This commit is contained in:
Couriersud 2013-12-31 15:35:08 +00:00
parent ce8e8234f0
commit a8a62c3212
10 changed files with 271 additions and 258 deletions

3
.gitattributes vendored
View File

@ -347,6 +347,9 @@ keymaps/km_pt_LINUX.map svneol=native#text/plain
keymaps/km_se_LINUX.map svneol=native#text/plain
keymaps/km_se_OSX.map svneol=native#text/plain
/makefile svneol=native#text/plain
nl_examples/7400_astable.c svneol=native#text/plain
nl_examples/ne555_astable.c svneol=native#text/plain
nl_examples/opamp.c svneol=native#text/plain
src/build/build.mak svneol=native#text/plain
src/build/file2str.c svneol=native#text/plain
src/build/makedep.c svneol=native#text/plain

View File

@ -0,0 +1,33 @@
/*
* 7400_astable.c
*
*/
#include "netlist/devices/net_lib.h"
NETLIST_START(7400_astable)
/*
* Astable multivibrator using two 7400 gates (or inverters)
*
*/
/* Standard stuff */
NETDEV_SOLVER(Solver)
NETDEV_PARAM(Solver.FREQ, 48000)
// astable NAND Multivibrator
NETDEV_R(R1, 1000)
NETDEV_C(C1, 1e-6)
TTL_7400_NAND(n1,R1.1,R1.1)
TTL_7400_NAND(n2,R1.2,R1.2)
NET_C(n1.Q, R1.2)
NET_C(n2.Q, C1.1)
NET_C(C1.2, R1.1)
NETDEV_LOG(log2, C1.2)
//NETDEV_LOG(log2, n1.Q)
NETDEV_LOG(log3, n2.Q)
NETLIST_END()

View File

@ -0,0 +1,49 @@
/*
* ne555_astable.c
*
*/
#include "netlist/devices/net_lib.h"
NETLIST_START(ne555_astable)
/*
* Astable ne555
*
*/
/* Standard stuff */
NETDEV_SOLVER(Solver)
NETDEV_PARAM(Solver.FREQ, 48000)
NETDEV_ANALOG_CONST(V5, 5) // 5V
/* Wiring up the ne555 */
// astable NE555, 1.13 ms period
NETDEV_R(RA, 5000)
NETDEV_R(RB, 3000)
NETDEV_C(C, 0.15e-6)
NETDEV_NE555(555)
NET_C(GND, 555.GND)
NET_C(V5, 555.VCC)
NET_C(V5, 555.RESET)
NET_C(RA.1, 555.VCC)
NET_C(RA.2, 555.DISCH)
NET_C(RB.1, 555.DISCH)
NET_C(RB.2, 555.TRIG)
NET_C(RB.2, 555.THRESH)
NET_C(555.TRIG, C.1)
NET_C(C.2, GND)
NETDEV_LOG(log2, C.1)
NETDEV_LOG(log3, 555.OUT)
NETLIST_END()

59
nl_examples/opamp.c Normal file
View File

@ -0,0 +1,59 @@
/*
* opamp.c
*
*/
#include "netlist/devices/net_lib.h"
NETLIST_START(opamp)
/* Opamp model from
*
* http://www.ecircuitcenter.com/Circuits/opmodel1/opmodel1.htm
*
* Bandwidth 10Mhz
*
* This one is connected as a impedance changer
*/
/* Standard stuff */
NETDEV_CLOCK(clk)
NETDEV_PARAM(clk.FREQ, 1000) // 1000 Hz
NETDEV_SOLVER(Solver)
NETDEV_PARAM(Solver.FREQ, 48000)
/* Wiring up the opamp */
NET_C(PLUS, clk)
NET_C(MINUS, OUT)
/* The opamp model */
NETDEV_VCCS(G1)
NETDEV_PARAM(G1.G, 100) // typical OP-AMP amplification 100 * 1000 = 100000
NETDEV_R(RP1, 1000)
NETDEV_C(CP1, 1.59e-6) // <== change to 1.59e-3 for 10Khz bandwidth
NETDEV_VCVS(EBUF)
NETDEV_PARAM(EBUF.RO, 50)
NETDEV_PARAM(EBUF.G, 1)
NET_ALIAS(PLUS, G1.IP) // Positive input
NET_ALIAS(MINUS, G1.IN) // Negative input
NET_ALIAS(OUT, EBUF.OP) // Opamp output ...
NET_C(EBUF.ON, GND)
NET_C(G1.ON, GND)
NET_C(RP1.2, GND)
NET_C(CP1.2, GND)
NET_C(EBUF.IN, GND)
NET_C(RP1.1, G1.OP)
NET_C(CP1.1, RP1.1)
NET_C(EBUF.IP, RP1.1)
//NETDEV_LOG(logX, OUT)
//NETDEV_LOG(logY, 4V)
NETLIST_END()

View File

@ -14,9 +14,32 @@
// A netlist parser
// ----------------------------------------------------------------------------------------
ATTR_COLD void netlist_parser::error(const char *format, ...)
{
va_list ap;
va_start(ap, format);
pstring errmsg1 =pstring(format).vprintf(ap);
va_end(ap);
char buf[300];
int bufp = 0;
const char *p = m_line_ptr;
while (*p && *p != 10)
buf[bufp++] = *p++;
buf[bufp] = 0;
m_setup.netlist().xfatalerror("line %d: error: %s\n\t\t%s\n", m_line, errmsg1.cstr(), buf);
//throw error;
}
void netlist_parser::parse(const char *buf)
{
m_px = buf;
m_line_ptr = buf;
m_line = 1;
while (!eof())
{
@ -41,11 +64,29 @@ void netlist_parser::parse(const char *buf)
netdev_device(n, "model", true);
else if ((n == "NETDEV_TTL_CONST") || (n == "NETDEV_ANALOG_CONST"))
netdev_const(n);
else if (n == "NETLIST_START")
netdev_netlist_start();
else if (n == "NETLIST_END")
netdev_netlist_end();
else
netdev_device(n);
}
}
void netlist_parser::netdev_netlist_start()
{
// don't do much
skipws();
/*pstring dummyname = */ getname(')');
//check_char(')');
}
void netlist_parser::netdev_netlist_end()
{
// don't do much
check_char(')');
}
void netlist_parser::net_alias()
{
pstring alias;
@ -196,6 +237,9 @@ void netlist_parser::skipws()
case 10:
case 13:
break;
case '#':
skipeol(); // treat preprocessor defines as comments
break;
case '/':
c = getc();
if (c == '/')
@ -205,8 +249,9 @@ void netlist_parser::skipws()
else if (c == '*')
{
int f=0;
while ((c = getc()) != 0 )
while (!eof() )
{
c = getc();
if (f == 0 && c == '*')
f=1;
else if (f == 1 && c== '/' )
@ -225,32 +270,39 @@ void netlist_parser::skipws()
pstring netlist_parser::getname(char sep)
{
char buf[300];
char *p1 = buf;
char c;
while ((c=getc()) != sep)
*p1++ = c;
*p1 = 0;
return pstring(buf);
pstring ret = getname2(sep, 0);
getc(); // undo the undo ...
return ret;
}
pstring netlist_parser::getname2(char sep1, char sep2)
{
char buf[300];
char *p1 = buf;
char c=getc();
while ((c != sep1) && (c != sep2))
{
*p1++ = c;
c = getc();
}
*p1 = 0;
ungetc();
return pstring(buf);
static const char *allowed = "0123456789_.ABCDEFGHIJKLMNOPQRSTUVWXYZ";
return getname2_ext(sep1, sep2, allowed);
}
pstring netlist_parser::getname2_ext(char sep1, char sep2, const char *allowed)
{
char buf[300];
char *p1 = buf;
char c=getc();
while ((c != sep1) && (c != sep2))
{
char cU = toupper(c);
if (strchr(allowed, cU) != NULL)
*p1++ = c;
else
{
*p1 = 0;
error("illegal character <%c> in name ...\n", c);
}
c = getc();
}
*p1 = 0;
ungetc();
return pstring(buf);
}
void netlist_parser::check_char(char ctocheck)
{
skipws();
@ -259,26 +311,27 @@ void netlist_parser::check_char(char ctocheck)
{
return;
}
m_setup.netlist().xfatalerror("Parser: expected '%c' found '%c'\n", ctocheck, c);
error("expected '%c' found '%c'\n", ctocheck, c);
}
double netlist_parser::eval_param()
{
static const char *macs[6] = {"", "RES_K(", "RES_M(", "CAP_U(", "CAP_N(", "CAP_P("};
static const char *allowed = "RESKMUNPAC_0123456789E+-.";
static double facs[6] = {1, 1e3, 1e6, 1e-6, 1e-9, 1e-12};
int i;
int f=0;
bool e;
double ret;
pstring s = getname2(')',',');
pstring s = getname2_ext(')',',', allowed);
for (i=1; i<6;i++)
if (strncmp(s.cstr(), macs[i], strlen(macs[i])) == 0)
f = i;
ret = s.substr(strlen(macs[f])).as_double(&e);
if ((f>0) && e)
m_setup.netlist().xfatalerror("Parser: Error with parameter ...\n");
error("Error with parameter ...\n");
if (f>0)
check_char(')');
return ret * facs[f];
@ -286,6 +339,11 @@ double netlist_parser::eval_param()
unsigned char netlist_parser::getc()
{
if (*m_px == 10)
{
m_line++;
m_line_ptr = m_px + 1;
}
if (*m_px)
return *(m_px++);
else

View File

@ -15,7 +15,7 @@ class netlist_parser
NETLIST_PREVENT_COPYING(netlist_parser)
public:
netlist_parser(netlist_setup_t &setup)
: m_setup(setup) {}
: m_line(1), m_line_ptr(NULL), m_px(NULL), m_setup(setup) {}
void parse(const char *buf);
void net_alias();
@ -24,13 +24,17 @@ public:
void netdev_const(const pstring &dev_name);
void netdev_device(const pstring &dev_type);
void netdev_device(const pstring &dev_type, const pstring &default_param, bool isString = false);
void netdev_netlist_start();
void netdev_netlist_end();
void error(const char *format, ...);
private:
void skipeol();
void skipws();
pstring getname(char sep);
pstring getname2(char sep1, char sep2);
pstring getname2_ext(char sep1, char sep2, const char *allowed);
void check_char(char ctocheck);
double eval_param();
@ -38,6 +42,8 @@ private:
void ungetc();
bool eof() { return *m_px == 0; }
int m_line;
const char * m_line_ptr;
const char * m_px;
netlist_setup_t &m_setup;
};

View File

@ -16,12 +16,13 @@
static NETLIST_START(base)
NETDEV_TTL_CONST(ttlhigh, 1)
NETDEV_TTL_CONST(ttllow, 0)
NETDEV_ANALOG_CONST(GND, 0)
NET_MODEL(".model 1N914 D(Is=2.52n Rs=.568 N=1.752 Cjo=4p M=.4 tt=20n Iave=200m Vpk=75 mfg=OnSemi type=silicon)")
NET_MODEL(".model 1N4148 D(Is=2.52n Rs=.568 N=1.752 Cjo=4p M=.4 tt=20n Iave=200m Vpk=75 mfg=OnSemi type=silicon)")
NET_MODEL(".MODEL BC237B NPN(IS=1.8E-14 ISE=5.0E-14 ISC=1.72E-13 XTI=3 BF=400 BR=35.5 IKF=0.14 IKR=0.03 XTB=1.5 VAF=80 VAR=12.5 VJE=0.58 VJC=0.54 RE=0.6 RC=0.25 RB=0.56 CJE=13E-12 CJC=4E-12 XCJC=0.75 FC=0.5 NF=0.9955 NR=1.005 NE=1.46 NC=1.27 MJE=0.33 MJC=0.33 TF=0.64E-9 TR=50.72E-9 EG=1.11 KF=0 AF=1 VCEO=45V ICRATING=100M MFG=ZETEX)")
NETLIST_END
NETLIST_END()
// ----------------------------------------------------------------------------------------

View File

@ -44,15 +44,16 @@
#define NETDEV_PARAM(_name, _val) \
netlist.register_param(# _name, _val);
#define NETDEV_PARAMI(_name, _param, _val) \
#define NETDEV_PARAMI(_name, _param, _val) \
netlist.register_param(# _name "." # _param, _val);
#define NETLIST_NAME(_name) netlist ## _ ## _name
#define NETLIST_START(_name) \
ATTR_COLD void NETLIST_NAME(_name)(netlist_setup_t &netlist) \
#define NETLIST_START(_name) \
ATTR_COLD void NETLIST_NAME(_name)(netlist_setup_t &netlist) \
{
#define NETLIST_END }
#define NETLIST_END() }
#define NETLIST_INCLUDE(_name) \
NETLIST_NAME(_name)(netlist);

View File

@ -82,8 +82,13 @@ enum input_changed_enum
};
static NETLIST_START(pong_schematics)
NETDEV_SOLVER(Solver)
NETDEV_PARAM(Solver.FREQ, 48000)
NETDEV_ANALOG_CONST(V5, 5)
NETDEV_TTL_CONST(high, 1)
NETDEV_TTL_CONST(low, 0)
#if 1
#if 0
/* this is the clock circuit in schematics. */
@ -562,228 +567,7 @@ static NETLIST_START(pong_schematics)
NET_ALIAS(videomix, RV3.2)
NETDEV_SOLVER(Solver)
NETDEV_PARAM(Solver.FREQ, 48000)
NETDEV_ANALOG_CONST(V5, 5)
NETDEV_ANALOG_CONST(V1, 1)
NETDEV_ANALOG_CONST(GND, 0)
#if 0
NETDEV_R(R1, 10)
NETDEV_R(R2, 10)
NETDEV_R(R3, 10)
NET_C(V5,R1.1)
NET_C(R1.2, R2.1)
NET_C(R2.2, R3.1)
NET_C(R3.2, GND)
#endif
#if 0
NETDEV_R(R4, 1000)
NETDEV_C(C1, 1e-6)
NET_C(V5,R4.1)
NET_C(R4.2, C1.1)
NET_C(C1.2, GND)
//NETDEV_LOG(log1, C1.1)
#endif
#define tt(_n) \
NETDEV_R(R ## _n, 1000) \
NETDEV_D(D ## _n) \
NET_C(V5, R ## _n.1) \
NET_C(R ## _n.2, D ## _n.A) \
NET_C(D ## _n.K, GND)
/* tt(20)
tt(21)
tt(22)
tt(23)
tt(24)
tt(25)
tt(26)
tt(27)
tt(28)
tt(29)
*/
#if 0
NETDEV_R(R5, 1000)
NETDEV_1N914(D1)
NET_C(V5, R5.1)
NET_C(R5.2, D1.A)
NET_C(D1.K, GND)
//NETDEV_LOG(log1, D1.A)
#endif
#if 0
// astable NAND Multivibrator
NETDEV_R(R1, 1000)
NETDEV_C(C1, 1e-6)
TTL_7400_NAND(n1,R1.1,R1.1)
TTL_7400_NAND(n2,R1.2,R1.2)
NET_C(n1.Q, R1.2)
NET_C(n2.Q, C1.1)
NET_C(C1.2, R1.1)
//NETDEV_LOG(log2, C1.2)
//NETDEV_LOG(log2, n1.Q)
//NETDEV_LOG(log3, n2.Q)
#endif
#if 0
// astable NE555, 1.13 ms period
NETDEV_R(RA, 5000)
NETDEV_R(RB, 3000)
NETDEV_C(C, 0.15e-6)
NETDEV_NE555(555)
NET_C(GND, 555.GND)
NET_C(V5, 555.VCC)
NET_C(RA.1, 555.VCC)
NET_C(RA.2, 555.DISCH)
NET_C(RB.1, 555.DISCH)
NET_C(RB.2, 555.TRIG)
NET_C(RB.2, 555.THRESH)
NET_C(555.TRIG, C.1)
NET_C(C.2, GND)
//NETDEV_LOG(log2, C.1)
//NETDEV_LOG(log3, 555.OUT)
#endif
#if 0
NETDEV_BC238B(Q)
NETDEV_R(RB, 1000)
NETDEV_R(RC, 1000)
NET_C(RC.1, V5)
NET_C(RC.2, Q.C)
NET_C(RB.1, 128H)
NET_C(RB.2, Q.B)
NET_C(Q.E, GND)
//NETDEV_LOG(logB, Q.B)
//NETDEV_LOG(logC, Q.C)
#endif
#if 0
NETDEV_VCVS(VV)
NETDEV_R(R1, 1000)
NETDEV_R(R2, 10000)
NET_C(V5, R1.1)
NET_C(R1.2, VV.IN)
NET_C(R2.1, VV.OP)
NET_C(R2.2, VV.IN)
NET_C(VV.ON, GND)
NET_C(VV.IP, GND)
NETDEV_LOG(logX, VV.OP)
#endif
#if 0
NETDEV_VCCS(VV)
NETDEV_PARAM(VV.G, 100000) // typical OP-AMP amplification
NETDEV_R(R1, 1000)
NETDEV_R(R2, 1)
NETDEV_R(R3, 10000)
NET_C(4V, R1.1)
NET_C(R1.2, VV.IN)
NET_C(R2.1, VV.OP)
NET_C(R3.1, VV.IN)
NET_C(R3.2, VV.OP)
NET_C(R2.2, GND)
NET_C(VV.ON, GND)
NET_C(VV.IP, GND)
//NETDEV_LOG(logX, VV.OP)
//NETDEV_LOG(logY, 4V)
#endif
#if 0
NETDEV_VCVS(VV)
NETDEV_PARAM(VV.G, 100000) // typical OP-AMP amplification
NETDEV_PARAM(VV.RO, 50) // typical OP-AMP amplification
NETDEV_R(R1, 1000)
NETDEV_R(R3, 10000) // ==> 10x amplification (inverting)
NET_C(4V, R1.1)
NET_C(R1.2, VV.IN)
NET_C(R3.1, VV.IN)
NET_C(R3.2, VV.OP)
NET_C(VV.ON, GND)
NET_C(VV.IP, GND)
NETDEV_LOG(logX, VV.OP)
NETDEV_LOG(logY, 4V)
#endif
#if 0
// Impedance converter with resistor
NETDEV_VCVS(VV)
NETDEV_PARAM(VV.G, 100000) // typical OP-AMP amplification
NETDEV_PARAM(VV.RO, 50) // typical OP-AMP amplification
NETDEV_R(R3, 10000)
NET_C(4V, VV.IP)
NET_C(R3.1, VV.IN)
NET_C(R3.2, VV.OP)
NET_C(VV.ON, GND)
NETDEV_LOG(logX, VV.OP)
NETDEV_LOG(logY, 4V)
#endif
#if 0
// Impedance converter without resistor
NETDEV_VCVS(VV)
NETDEV_PARAM(VV.G, 100000) // typical OP-AMP amplification
NETDEV_PARAM(VV.RO, 50) // typical OP-AMP amplification
NET_C(4V, VV.IP)
NET_C(VV.IN, VV.OP)
NET_C(VV.ON, GND)
NETDEV_LOG(logX, VV.OP)
NETDEV_LOG(logY, 4V)
#endif
#if 0
/* Impedance converter current source opamp model from
*
* http://www.ecircuitcenter.com/Circuits/opmodel1/opmodel1.htm
*
* Bandwidth 10Mhz
*
*/
NETDEV_VCCS(G1)
NETDEV_PARAM(G1.G, 100) // typical OP-AMP amplification 100 * 1000 = 100000
NETDEV_R(RP1, 1000)
NETDEV_C(CP1, 1.59e-6) // <== change to 1.59e-3 for 10Khz bandwidth
NETDEV_VCVS(EBUF)
NETDEV_PARAM(EBUF.RO, 50)
NETDEV_PARAM(EBUF.G, 1)
NET_C(G1.IP, 4V)
NET_C(G1.IN, EBUF.OP)
NET_C(EBUF.ON, GND)
NET_C(G1.ON, GND)
NET_C(RP1.2, GND)
NET_C(CP1.2, GND)
NET_C(EBUF.IN, GND)
NET_C(RP1.1, G1.OP)
NET_C(CP1.1, RP1.1)
NET_C(EBUF.IP, RP1.1)
//NETDEV_LOG(logX, EBUF.OP)
//NETDEV_LOG(logY, 4V)
#endif
NETLIST_END
NETLIST_END()
class pong_state : public driver_device
{
@ -838,7 +622,7 @@ static NETLIST_START(pong)
NETDEV_ANALOG_CALLBACK(sound_cb, sound, pong_state, sound_cb, "")
NETDEV_ANALOG_CALLBACK(video_cb, videomix, fixedfreq_device, update_vid, "fixfreq")
NETLIST_END
NETLIST_END()
static NETLIST_START(pong_fast)
@ -847,7 +631,7 @@ static NETLIST_START(pong_fast)
NETDEV_ANALOG_CALLBACK(sound_cb, sound, pong_state, sound_cb, "")
NETDEV_ANALOG_CALLBACK(video_cb, videomix, fixedfreq_device, update_vid, "fixfreq")
NETLIST_END
NETLIST_END()
void pong_state::machine_start()
{

View File

@ -16,6 +16,7 @@
#include "sha1.h"
#include "netlist/nl_base.h"
#include "netlist/nl_setup.h"
#include "netlist/nl_util.h"
#include "options.h"
/***************************************************************************
@ -58,7 +59,8 @@ void free_file_line( void *memory, const char *file, int line )
struct options_entry oplist[] =
{
{ "time_to_run;ttr", "1.0", OPTION_FLOAT, "time to run the emulation (seconds)" },
{ "time_to_run;t", "1.0", OPTION_FLOAT, "time to run the emulation (seconds)" },
{ "logs;l", "", OPTION_STRING, "colon separated list of terminals to log" },
{ "f", "-", OPTION_STRING, "file to process (default is stdin)" },
{ "help;h", "0", OPTION_BOOLEAN, "display help" },
{ NULL }
@ -91,7 +93,7 @@ const char *filetobuf(pstring fname)
long fsize = ftell(f);
fseek(f, 0, SEEK_SET);
char *buf = (char *) malloc(fsize);
char *buf = (char *) malloc(fsize + 1);
fread(buf, fsize, 1, f);
buf[fsize] = 0;
fclose(f);
@ -104,7 +106,7 @@ class netlist_tool_t : public netlist_base_t
public:
netlist_tool_t()
: netlist_base_t(), m_setup(NULL)
: netlist_base_t(), m_logs(""), m_setup(NULL)
{
}
@ -120,6 +122,7 @@ public:
//m_setup_func(*m_setup);
m_setup->parse(buffer);
log_setup();
// start devices
m_setup->start_devices();
@ -128,6 +131,20 @@ public:
this->reset();
}
void log_setup()
{
NL_VERBOSE_OUT(("Creating dynamic logs ...\n"));
nl_util::pstring_list ll = nl_util::split(m_logs, ":");
for (int i=0; i < ll.count(); i++)
{
netlist_device_t *nc = m_setup->factory().new_device_by_classname("nld_log", *m_setup);
pstring name = "log_" + ll[i];
m_setup->register_dev(nc, name);
m_setup->register_link(name + ".I", ll[i]);
}
}
pstring m_logs;
protected:
void vfatalerror(const char *format, va_list ap) const
@ -140,6 +157,7 @@ private:
netlist_setup_t *m_setup;
};
void usage(core_options &opts)
{
astring buffer;
@ -178,8 +196,9 @@ int main(int argc, char *argv[])
return 1;
}
nt.m_logs = opts.value("l");
nt.read_netlist(filetobuf(opts.value("f")));
double ttr = opts.float_value("ttr");
double ttr = opts.float_value("t");
printf("startup time ==> %5.3f\n", (double) (osd_ticks() - t) / (double) osd_ticks_per_second() );
printf("runnning ...\n");