summaryrefslogtreecommitdiffstatshomepage
path: root/src/lib/netlist/prg/nltool.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/netlist/prg/nltool.c')
-rw-r--r--src/lib/netlist/prg/nltool.c470
1 files changed, 470 insertions, 0 deletions
diff --git a/src/lib/netlist/prg/nltool.c b/src/lib/netlist/prg/nltool.c
new file mode 100644
index 00000000000..3510f70e7f2
--- /dev/null
+++ b/src/lib/netlist/prg/nltool.c
@@ -0,0 +1,470 @@
+// license:GPL-2.0+
+// copyright-holders:Couriersud
+/***************************************************************************
+
+ nltool.c
+
+ Simple tool to debug netlists outside MAME.
+
+****************************************************************************/
+
+#include <cstdio>
+
+#ifdef PSTANDALONE
+#if (PSTANDALONE)
+#define PSTANDALONE_PROVIDED
+#endif
+#endif
+
+#include "plib/poptions.h"
+#include "plib/pstring.h"
+#include "plib/plists.h"
+#include "plib/ptypes.h"
+#include "nl_setup.h"
+#include "nl_factory.h"
+#include "nl_parser.h"
+#include "devices/net_lib.h"
+#include "tools/nl_convert.h"
+
+
+#ifdef PSTANDALONE_PROVIDED
+
+#include <ctime>
+
+#define osd_ticks_t clock_t
+
+inline osd_ticks_t osd_ticks_per_second() { return CLOCKS_PER_SEC; }
+
+osd_ticks_t osd_ticks(void) { return clock(); }
+#else
+
+#endif
+
+/***************************************************************************
+ * MAME COMPATIBILITY ...
+ *
+ * These are needed if we link without libutil
+ ***************************************************************************/
+
+#if 0
+void ATTR_PRINTF(1,2) osd_printf_warning(const char *format, ...)
+{
+ va_list argptr;
+
+ /* do the output */
+ va_start(argptr, format);
+ vprintf(format, argptr);
+ va_end(argptr);
+}
+
+void *malloc_file_line(size_t size, const char *file, int line)
+{
+ // allocate the memory and fail if we can't
+ void *ret = osd_malloc(size);
+ memset(ret, 0, size);
+ return ret;
+}
+
+void *malloc_array_file_line(size_t size, const char *file, int line)
+{
+ // allocate the memory and fail if we can't
+ void *ret = osd_malloc_array(size);
+ memset(ret, 0, size);
+ return ret;
+}
+
+void free_file_line( void *memory, const char *file, int line )
+{
+ osd_free( memory );
+}
+
+void CLIB_DECL logerror(const char *format, ...)
+{
+ va_list arg;
+ va_start(arg, format);
+ vprintf(format, arg);
+ va_end(arg);
+}
+
+void report_bad_cast(const std::type_info &src_type, const std::type_info &dst_type)
+{
+ printf("Error: bad downcast<> or device<>. Tried to convert a %s to a %s, which are incompatible.\n",
+ src_type.name(), dst_type.name());
+ throw;
+}
+#endif
+
+class tool_options_t : public poptions
+{
+public:
+ tool_options_t() :
+ poptions(),
+ opt_ttr ("t", "time_to_run", 1.0, "time to run the emulation (seconds)", this),
+ 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_inp( "i", "input", "", "input file to process (default is none)", this),
+ opt_verb("v", "verbose", "be verbose - this produces lots of output", this),
+ opt_quiet("q", "quiet", "be quiet - no warnings", this),
+ opt_help("h", "help", "display help", this)
+ {}
+
+ poption_double opt_ttr;
+ poption_str opt_name;
+ poption_str opt_logs;
+ poption_str opt_file;
+ poption_str_limit opt_type;
+ poption_str opt_cmd;
+ poption_str opt_inp;
+ poption_bool opt_verb;
+ poption_bool opt_quiet;
+ poption_bool opt_help;
+};
+
+pstdout pout_strm;
+pstderr perr_strm;
+
+pstream_fmt_writer_t pout(pout_strm);
+pstream_fmt_writer_t perr(perr_strm);
+
+NETLIST_START(dummy)
+ /* Standard stuff */
+
+ CLOCK(clk, 1000) // 1000 Hz
+ SOLVER(Solver, 48000)
+
+NETLIST_END()
+
+/***************************************************************************
+ CORE IMPLEMENTATION
+***************************************************************************/
+
+class netlist_tool_t : public netlist::netlist_t
+{
+public:
+
+ netlist_tool_t()
+ : netlist::netlist_t(), m_opts(NULL), m_setup(NULL)
+ {
+ }
+
+ ~netlist_tool_t()
+ {
+ if (m_setup != NULL)
+ pfree(m_setup);
+ };
+
+ void init()
+ {
+ m_setup = palloc(netlist::setup_t(this));
+ this->init_object(*this, "netlist");
+ m_setup->init();
+ }
+
+ void read_netlist(const pstring &filename, const pstring &name)
+ {
+ // read the netlist ...
+
+ m_setup->register_source(palloc(netlist::source_file_t(filename)));
+ m_setup->include(name);
+ log_setup();
+
+ // start devices
+ m_setup->start_devices();
+ m_setup->resolve_inputs();
+ // reset
+ this->reset();
+ }
+
+ void log_setup()
+ {
+ log().debug("Creating dynamic logs ...\n");
+ pstring_list_t ll(m_opts ? m_opts->opt_logs() : "" , ":");
+ for (unsigned i=0; i < ll.size(); i++)
+ {
+ pstring name = "log_" + ll[i];
+ /*netlist_device_t *nc = */ m_setup->register_dev("LOG", name);
+ m_setup->register_link(name + ".I", ll[i]);
+ }
+ }
+
+ tool_options_t *m_opts;
+
+protected:
+
+ void vlog(const plog_level &l, const pstring &ls) const
+ {
+ pout("{}: {}\n", l.name().cstr(), ls.cstr());
+ if (l == plog_level::FATAL)
+ throw;
+ }
+
+private:
+ netlist::setup_t *m_setup;
+};
+
+
+void usage(tool_options_t &opts)
+{
+ perr("{}",
+ "Usage:\n"
+ " nltool -help\n"
+ " nltool [options]\n"
+ "\n"
+ "Where:\n"
+ );
+ perr("{}\n", opts.help().cstr());
+}
+
+struct input_t
+{
+ input_t()
+ : m_param(NULL), m_value(0.0)
+ {
+ }
+ input_t(netlist::netlist_t *netlist, const pstring &line)
+ {
+ char buf[400];
+ double t;
+ int e = sscanf(line.cstr(), "%lf,%[^,],%lf", &t, buf, &m_value);
+ if ( e!= 3)
+ throw netlist::fatalerror_e(pfmt("error {1} scanning line {2}\n")(e)(line));
+ m_time = netlist::netlist_time::from_double(t);
+ m_param = netlist->setup().find_param(buf, true);
+ }
+
+ void setparam()
+ {
+ switch (m_param->param_type())
+ {
+ case netlist::param_t::MODEL:
+ case netlist::param_t::STRING:
+ throw netlist::fatalerror_e(pfmt("param {1} is not numeric\n")(m_param->name()));
+ case netlist::param_t::DOUBLE:
+ static_cast<netlist::param_double_t*>(m_param)->setTo(m_value);
+ break;
+ case netlist::param_t::INTEGER:
+ static_cast<netlist::param_int_t*>(m_param)->setTo((int)m_value);
+ break;
+ case netlist::param_t::LOGIC:
+ static_cast<netlist::param_logic_t*>(m_param)->setTo((int) m_value);
+ break;
+ }
+ }
+
+ netlist::netlist_time m_time;
+ netlist::param_t *m_param;
+ double m_value;
+
+};
+
+plist_t<input_t> *read_input(netlist::netlist_t *netlist, pstring fname)
+{
+ plist_t<input_t> *ret = palloc(plist_t<input_t>());
+ if (fname != "")
+ {
+ pifilestream f(fname);
+ pstring l;
+ while (f.readline(l))
+ {
+ if (l != "")
+ {
+ input_t inp(netlist, l);
+ ret->add(inp);
+ }
+ }
+ }
+ return ret;
+}
+
+static void run(tool_options_t &opts)
+{
+ netlist_tool_t nt;
+ osd_ticks_t t = osd_ticks();
+
+ nt.m_opts = &opts;
+ nt.init();
+
+ if (!opts.opt_verb())
+ nt.log().verbose.set_enabled(false);
+ if (opts.opt_quiet())
+ nt.log().warning.set_enabled(false);
+
+ nt.read_netlist(opts.opt_file(), opts.opt_name());
+
+ plist_t<input_t> *inps = read_input(&nt, opts.opt_inp());
+
+ double ttr = opts.opt_ttr();
+
+ pout("startup time ==> {1:5.3f}\n", (double) (osd_ticks() - t) / (double) osd_ticks_per_second() );
+ pout("runnning ...\n");
+ t = osd_ticks();
+
+ unsigned pos = 0;
+ netlist::netlist_time nlt = netlist::netlist_time::zero;
+
+ while (pos < inps->size() && (*inps)[pos].m_time < netlist::netlist_time::from_double(ttr))
+ {
+ nt.process_queue((*inps)[pos].m_time - nlt);
+ (*inps)[pos].setparam();
+ nlt = (*inps)[pos].m_time;
+ pos++;
+ }
+ nt.process_queue(netlist::netlist_time::from_double(ttr) - nlt);
+ nt.stop();
+ pfree(inps);
+
+ double emutime = (double) (osd_ticks() - t) / (double) osd_ticks_per_second();
+ pout("{1:f} seconds emulation took {2:f} real time ==> {3:5.2f}%\n", ttr, emutime, ttr/emutime*100.0);
+}
+
+/*-------------------------------------------------
+ listdevices - list all known devices
+-------------------------------------------------*/
+
+static void listdevices()
+{
+ netlist_tool_t nt;
+ nt.init();
+ const netlist::factory_list_t &list = nt.setup().factory();
+
+ nt.setup().register_source(palloc(netlist::source_proc_t("dummy", &netlist_dummy)));
+ nt.setup().include("dummy");
+
+ nt.setup().start_devices();
+ nt.setup().resolve_inputs();
+
+ for (unsigned i=0; i < list.size(); i++)
+ {
+ netlist::base_factory_t *f = list.value_at(i);
+ pstring out = pfmt("{1} {2}(<id>")(f->classname(),"-20")(f->name());
+ pstring terms("");
+
+ netlist::device_t *d = f->Create();
+ d->init(nt, pfmt("dummy{1}")(i));
+ d->start_dev();
+
+ // get the list of terminals ...
+ for (unsigned j=0; j < d->m_terminals.size(); j++)
+ {
+ pstring inp = d->m_terminals[j];
+ if (inp.startsWith(d->name() + "."))
+ inp = inp.substr(d->name().len() + 1);
+ terms += "," + inp;
+ }
+
+ if (f->param_desc().startsWith("+"))
+ {
+ out += "," + f->param_desc().substr(1);
+ terms = "";
+ }
+ else if (f->param_desc() == "-")
+ {
+ /* no params at all */
+ }
+ else
+ {
+ out += "," + f->param_desc();
+ }
+ out += ")";
+ printf("%s\n", out.cstr());
+ if (terms != "")
+ printf("Terminals: %s\n", terms.substr(1).cstr());
+ }
+}
+
+
+
+/*-------------------------------------------------
+ main - primary entry point
+-------------------------------------------------*/
+
+#if (!PSTANDALONE)
+#include "corealloc.h"
+#endif
+
+static const char *pmf_verbose[] =
+{
+ "NL_PMF_TYPE_VIRTUAL",
+ "NL_PMF_TYPE_GNUC_PMF",
+ "NL_PMF_TYPE_GNUC_PMF_CONV",
+ "NL_PMF_TYPE_INTERNAL"
+};
+
+int main(int argc, char *argv[])
+{
+#if (!PSTANDALONE)
+ track_memory(true);
+ {
+#endif
+ tool_options_t opts;
+ int ret;
+
+ perr("{}", "WARNING: This is Work In Progress! - It may fail anytime\n");
+ perr("Update dispatching using method {}\n", pmf_verbose[NL_PMF_TYPE]);
+ if ((ret = opts.parse(argc, argv)) != argc)
+ {
+ perr("Error parsing {}\n", argv[ret]);
+ usage(opts);
+ return 1;
+ }
+
+ if (opts.opt_help())
+ {
+ usage(opts);
+ return 1;
+ }
+
+ pstring cmd = opts.opt_cmd();
+ if (cmd == "listdevices")
+ listdevices();
+ else if (cmd == "run")
+ run(opts);
+ else if (cmd == "convert")
+ {
+ pstring contents;
+ postringstream ostrm;
+ if (opts.opt_file() == "-")
+ {
+ pstdin f;
+ ostrm.write(f);
+ }
+ else
+ {
+ pifilestream f(opts.opt_file());
+ ostrm.write(f);
+ }
+ contents = ostrm.str();
+
+ pstring result;
+ if (opts.opt_type().equals("spice"))
+ {
+ nl_convert_spice_t c;
+ c.convert(contents);
+ result = c.result();
+ }
+ else
+ {
+ nl_convert_eagle_t c;
+ c.convert(contents);
+ result = c.result();
+ }
+ /* present result */
+ pout_strm.write(result.cstr());
+ }
+ else
+ {
+ perr("Unknown command {}\n", cmd.cstr());
+ usage(opts);
+ return 1;
+ }
+
+ pstring::resetmem();
+#if (!PSTANDALONE)
+ }
+ dump_unfreed_mem();
+#endif
+ return 0;
+}