mirror of
https://github.com/holub/mame
synced 2025-05-03 21:13:18 +03:00
298 lines
6.8 KiB
C
298 lines
6.8 KiB
C
/***************************************************************************
|
|
|
|
nltool.c
|
|
|
|
Simple tool to debug netlists outside MAME.
|
|
|
|
****************************************************************************/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
#include "astring.h"
|
|
#include "corefile.h"
|
|
#include "corestr.h"
|
|
#include "sha1.h"
|
|
#include "netlist/nl_base.h"
|
|
#include "netlist/nl_setup.h"
|
|
#include "netlist/nl_parser.h"
|
|
#include "netlist/nl_util.h"
|
|
#include "options.h"
|
|
|
|
/***************************************************************************
|
|
MAME COMPATIBILITY ...
|
|
***************************************************************************/
|
|
|
|
#if 0
|
|
void ATTR_PRINTF(1,2) mame_printf_warning(const char *format, ...)
|
|
{
|
|
va_list argptr;
|
|
|
|
/* do the output */
|
|
va_start(argptr, format);
|
|
vprintf(format, argptr);
|
|
va_end(argptr);
|
|
}
|
|
#endif
|
|
|
|
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 );
|
|
}
|
|
|
|
|
|
struct options_entry oplist[] =
|
|
{
|
|
{ "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)" },
|
|
{ "listdevices;ld", "", OPTION_BOOLEAN, "list all devices available for use" },
|
|
{ "help;h", "0", OPTION_BOOLEAN, "display help" },
|
|
{ NULL }
|
|
};
|
|
|
|
/***************************************************************************
|
|
CORE IMPLEMENTATION
|
|
***************************************************************************/
|
|
|
|
const char *filetobuf(pstring fname)
|
|
{
|
|
static pstring pbuf = "";
|
|
|
|
if (fname == "-")
|
|
{
|
|
char lbuf[1024];
|
|
while (!feof(stdin))
|
|
{
|
|
fgets(lbuf, 1024, stdin);
|
|
pbuf += lbuf;
|
|
}
|
|
printf("%d\n",*(pbuf.right(1).cstr()+1));
|
|
return pbuf.cstr();
|
|
}
|
|
else
|
|
{
|
|
FILE *f;
|
|
f = fopen(fname, "rb");
|
|
fseek(f, 0, SEEK_END);
|
|
long fsize = ftell(f);
|
|
fseek(f, 0, SEEK_SET);
|
|
|
|
char *buf = (char *) malloc(fsize + 1);
|
|
fread(buf, fsize, 1, f);
|
|
buf[fsize] = 0;
|
|
fclose(f);
|
|
return buf;
|
|
}
|
|
}
|
|
|
|
class netlist_tool_t : public netlist_base_t
|
|
{
|
|
public:
|
|
|
|
netlist_tool_t()
|
|
: netlist_base_t(), m_logs(""), m_setup(NULL)
|
|
{
|
|
}
|
|
|
|
virtual ~netlist_tool_t() { };
|
|
|
|
void init()
|
|
{
|
|
m_setup = new netlist_setup_t(*this);
|
|
this->init_object(*this, "netlist");
|
|
m_setup->init();
|
|
}
|
|
|
|
void read_netlist(const char *buffer)
|
|
{
|
|
|
|
// read the netlist ...
|
|
|
|
netlist_sources_t sources;
|
|
|
|
sources.add(netlist_source_t(buffer));
|
|
sources.parse(*m_setup,"");
|
|
//m_setup->parse(buffer);
|
|
log_setup();
|
|
|
|
// start devices
|
|
m_setup->start_devices();
|
|
m_setup->resolve_inputs();
|
|
// reset
|
|
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 verror(const loglevel_e level, const char *format, va_list ap) const
|
|
{
|
|
switch (level)
|
|
{
|
|
case NL_LOG:
|
|
case NL_WARNING:
|
|
vprintf(format, ap);
|
|
printf("\n");
|
|
break;
|
|
case NL_ERROR:
|
|
vprintf(format, ap);
|
|
printf("\n");
|
|
throw;
|
|
break;
|
|
}
|
|
}
|
|
|
|
private:
|
|
netlist_setup_t *m_setup;
|
|
};
|
|
|
|
|
|
void usage(core_options &opts)
|
|
{
|
|
astring buffer;
|
|
fprintf(stderr,
|
|
"Usage:\n"
|
|
" nltool -help\n"
|
|
" nltool [options]\n"
|
|
"\n"
|
|
"Where:\n"
|
|
);
|
|
fprintf(stderr, "%s\n", opts.output_help(buffer));
|
|
}
|
|
|
|
static void run(core_options &opts)
|
|
{
|
|
netlist_tool_t nt;
|
|
osd_ticks_t t = osd_ticks();
|
|
|
|
nt.init();
|
|
nt.m_logs = opts.value("l");
|
|
nt.read_netlist(filetobuf(opts.value("f")));
|
|
double ttr = opts.float_value("t");
|
|
|
|
printf("startup time ==> %5.3f\n", (double) (osd_ticks() - t) / (double) osd_ticks_per_second() );
|
|
printf("runnning ...\n");
|
|
t = osd_ticks();
|
|
|
|
nt.process_queue(netlist_time::from_double(ttr));
|
|
|
|
double emutime = (double) (osd_ticks() - t) / (double) osd_ticks_per_second();
|
|
printf("%f seconds emulation took %f real time ==> %5.2f%%\n", ttr, emutime, ttr/emutime*100.0);
|
|
}
|
|
|
|
static void listdevices()
|
|
{
|
|
netlist_tool_t nt;
|
|
nt.init();
|
|
const netlist_factory_t::list_t &list = nt.setup().factory().list();
|
|
|
|
nt.setup().start_devices();
|
|
nt.setup().resolve_inputs();
|
|
|
|
for (int i=0; i < list.count(); i++)
|
|
{
|
|
pstring out = pstring::sprintf("%-20s %s(<id>", list[i]->classname().cstr(),
|
|
list[i]->name().cstr() );
|
|
pstring terms("");
|
|
|
|
net_device_t_base_factory *f = list[i];
|
|
netlist_device_t *d = f->Create();
|
|
d->init(nt, pstring::sprintf("dummy%d", i));
|
|
d->start_dev();
|
|
|
|
// get the list of terminals ...
|
|
for (int j=0; j < d->m_terminals.count(); j++)
|
|
{
|
|
pstring inp = d->m_terminals[j];
|
|
if (inp.startsWith(d->name() + "."))
|
|
inp = inp.substr(d->name().len() + 1);
|
|
terms += "," + inp;
|
|
}
|
|
|
|
if (list[i]->param_desc().startsWith("+"))
|
|
{
|
|
out += "," + list[i]->param_desc().substr(1);
|
|
terms = "";
|
|
}
|
|
else if (list[i]->param_desc() == "-")
|
|
{
|
|
/* no params at all */
|
|
}
|
|
else
|
|
{
|
|
out += "," + list[i]->param_desc();
|
|
}
|
|
out += ")";
|
|
printf("%s\n", out.cstr());
|
|
if (terms != "")
|
|
printf("Terminals: %s\n", terms.substr(1).cstr());
|
|
}
|
|
}
|
|
|
|
/*-------------------------------------------------
|
|
main - primary entry point
|
|
-------------------------------------------------*/
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
//int result;
|
|
core_options opts(oplist);
|
|
astring aerror("");
|
|
|
|
fprintf(stderr, "%s", "WARNING: This is Work In Progress! - It may fail anytime\n");
|
|
if (!opts.parse_command_line(argc, argv, OPTION_PRIORITY_DEFAULT, aerror))
|
|
{
|
|
fprintf(stderr, "%s\n", aerror.cstr());
|
|
usage(opts);
|
|
return 1;
|
|
}
|
|
|
|
if (opts.bool_value("h"))
|
|
{
|
|
usage(opts);
|
|
return 1;
|
|
}
|
|
|
|
if (opts.bool_value("ld"))
|
|
{
|
|
listdevices();
|
|
}
|
|
else
|
|
{
|
|
run(opts);
|
|
}
|
|
|
|
return 0;
|
|
}
|