mirror of
https://github.com/holub/mame
synced 2025-10-09 09:44:40 +03:00
Added state saving and loading to nltool.
First step towards regression and unit tests. (nw)
This commit is contained in:
parent
74e690d654
commit
cc39da9c83
@ -31,7 +31,8 @@ namespace plib {
|
|||||||
}
|
}
|
||||||
|
|
||||||
option::option(options &parent, pstring ashort, pstring along, pstring help, bool has_argument)
|
option::option(options &parent, pstring ashort, pstring along, pstring help, bool has_argument)
|
||||||
: option_base(parent, help), m_short(ashort), m_long(along), m_has_argument(has_argument)
|
: option_base(parent, help), m_short(ashort), m_long(along),
|
||||||
|
m_has_argument(has_argument), m_specified(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -149,13 +150,13 @@ namespace plib {
|
|||||||
{
|
{
|
||||||
if (has_equal_arg)
|
if (has_equal_arg)
|
||||||
{
|
{
|
||||||
if (opt->parse(opt_arg) != 0)
|
if (opt->do_parse(opt_arg) != 0)
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
i++; // FIXME: are there more arguments?
|
i++; // FIXME: are there more arguments?
|
||||||
if (opt->parse(pstring(argv[i], pstring::UTF8)) != 0)
|
if (opt->do_parse(pstring(argv[i], pstring::UTF8)) != 0)
|
||||||
return i - 1;
|
return i - 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -163,7 +164,7 @@ namespace plib {
|
|||||||
{
|
{
|
||||||
if (has_equal_arg)
|
if (has_equal_arg)
|
||||||
return i;
|
return i;
|
||||||
opt->parse("");
|
opt->do_parse("");
|
||||||
}
|
}
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
@ -65,15 +65,25 @@ public:
|
|||||||
|
|
||||||
/* no_argument options will be called with "" argument */
|
/* no_argument options will be called with "" argument */
|
||||||
|
|
||||||
virtual int parse(const pstring &argument) = 0;
|
|
||||||
|
|
||||||
pstring short_opt() { return m_short; }
|
pstring short_opt() { return m_short; }
|
||||||
pstring long_opt() { return m_long; }
|
pstring long_opt() { return m_long; }
|
||||||
bool has_argument() { return m_has_argument ; }
|
bool has_argument() { return m_has_argument ; }
|
||||||
|
bool was_specified() { return m_specified; }
|
||||||
|
|
||||||
|
int do_parse(const pstring &argument)
|
||||||
|
{
|
||||||
|
m_specified = true;
|
||||||
|
return parse(argument);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual int parse(const pstring &argument) = 0;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
pstring m_short;
|
pstring m_short;
|
||||||
pstring m_long;
|
pstring m_long;
|
||||||
bool m_has_argument;
|
bool m_has_argument;
|
||||||
|
bool m_specified;
|
||||||
};
|
};
|
||||||
|
|
||||||
class option_str : public option
|
class option_str : public option
|
||||||
@ -83,9 +93,11 @@ public:
|
|||||||
: option(parent, ashort, along, help, true), m_val(defval)
|
: option(parent, ashort, along, help, true), m_val(defval)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
pstring operator ()() { return m_val; }
|
||||||
|
|
||||||
|
protected:
|
||||||
virtual int parse(const pstring &argument) override;
|
virtual int parse(const pstring &argument) override;
|
||||||
|
|
||||||
pstring operator ()() { return m_val; }
|
|
||||||
private:
|
private:
|
||||||
pstring m_val;
|
pstring m_val;
|
||||||
};
|
};
|
||||||
@ -99,11 +111,12 @@ public:
|
|||||||
m_limit = plib::psplit(limit, ":");
|
m_limit = plib::psplit(limit, ":");
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual int parse(const pstring &argument) override;
|
|
||||||
|
|
||||||
pstring operator ()() { return m_val; }
|
pstring operator ()() { return m_val; }
|
||||||
const std::vector<pstring> &limit() { return m_limit; }
|
const std::vector<pstring> &limit() { return m_limit; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual int parse(const pstring &argument) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
pstring m_val;
|
pstring m_val;
|
||||||
std::vector<pstring> m_limit;
|
std::vector<pstring> m_limit;
|
||||||
@ -116,9 +129,11 @@ public:
|
|||||||
: option(parent, ashort, along, help, false), m_val(false)
|
: option(parent, ashort, along, help, false), m_val(false)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
bool operator ()() { return m_val; }
|
||||||
|
|
||||||
|
protected:
|
||||||
virtual int parse(const pstring &argument) override;
|
virtual int parse(const pstring &argument) override;
|
||||||
|
|
||||||
bool operator ()() { return m_val; }
|
|
||||||
private:
|
private:
|
||||||
bool m_val;
|
bool m_val;
|
||||||
};
|
};
|
||||||
@ -130,9 +145,11 @@ public:
|
|||||||
: option(parent, ashort, along, help, true), m_val(defval)
|
: option(parent, ashort, along, help, true), m_val(defval)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
double operator ()() { return m_val; }
|
||||||
|
|
||||||
|
protected:
|
||||||
virtual int parse(const pstring &argument) override;
|
virtual int parse(const pstring &argument) override;
|
||||||
|
|
||||||
double operator ()() { return m_val; }
|
|
||||||
private:
|
private:
|
||||||
double m_val;
|
double m_val;
|
||||||
};
|
};
|
||||||
@ -144,9 +161,11 @@ public:
|
|||||||
: option(parent, ashort, along, help, true), m_val(defval)
|
: option(parent, ashort, along, help, true), m_val(defval)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
long operator ()() { return m_val; }
|
||||||
|
|
||||||
|
protected:
|
||||||
virtual int parse(const pstring &argument) override;
|
virtual int parse(const pstring &argument) override;
|
||||||
|
|
||||||
long operator ()() { return m_val; }
|
|
||||||
private:
|
private:
|
||||||
long m_val;
|
long m_val;
|
||||||
};
|
};
|
||||||
@ -158,9 +177,11 @@ public:
|
|||||||
: option(parent, ashort, along, help, true)
|
: option(parent, ashort, along, help, true)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
std::vector<pstring> operator ()() { return m_val; }
|
||||||
|
|
||||||
|
protected:
|
||||||
virtual int parse(const pstring &argument) override;
|
virtual int parse(const pstring &argument) override;
|
||||||
|
|
||||||
std::vector<pstring> operator ()() { return m_val; }
|
|
||||||
private:
|
private:
|
||||||
std::vector<pstring> m_val;
|
std::vector<pstring> m_val;
|
||||||
};
|
};
|
||||||
|
@ -12,6 +12,8 @@
|
|||||||
#include "pfmtlog.h"
|
#include "pfmtlog.h"
|
||||||
#include "pexception.h"
|
#include "pexception.h"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace plib {
|
namespace plib {
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// pstream: things common to all streams
|
// pstream: things common to all streams
|
||||||
@ -371,6 +373,76 @@ protected:
|
|||||||
private:
|
private:
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// pbinary_writer_t: writer on top of ostream
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class pbinary_writer : plib::nocopyassignmove
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit pbinary_writer(postream &strm) : m_strm(strm) {}
|
||||||
|
virtual ~pbinary_writer() {}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void write(const T val)
|
||||||
|
{
|
||||||
|
m_strm.write(&val, sizeof(T));
|
||||||
|
}
|
||||||
|
|
||||||
|
void write(const pstring s)
|
||||||
|
{
|
||||||
|
write(s.blen());
|
||||||
|
m_strm.write(s.c_str(), s.blen());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void write(const std::vector<T> val)
|
||||||
|
{
|
||||||
|
std::size_t sz = val.size();
|
||||||
|
write(sz);
|
||||||
|
m_strm.write(val.data(), sizeof(T) * sz);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
postream &m_strm;
|
||||||
|
};
|
||||||
|
|
||||||
|
class pbinary_reader : plib::nocopyassignmove
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit pbinary_reader(pistream &strm) : m_strm(strm) {}
|
||||||
|
virtual ~pbinary_reader() {}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void read(T &val)
|
||||||
|
{
|
||||||
|
m_strm.read(&val, sizeof(T));
|
||||||
|
}
|
||||||
|
|
||||||
|
void read( pstring &s)
|
||||||
|
{
|
||||||
|
std::size_t sz = 0;
|
||||||
|
read(sz);
|
||||||
|
pstring::mem_t *buf = new pstring::mem_t[sz+1];
|
||||||
|
m_strm.read(buf, sz);
|
||||||
|
buf[sz] = 0;
|
||||||
|
s = pstring(buf, pstring::UTF8);
|
||||||
|
delete [] buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void read(std::vector<T> &val)
|
||||||
|
{
|
||||||
|
std::size_t sz = 0;
|
||||||
|
read(sz);
|
||||||
|
val.resize(sz);
|
||||||
|
m_strm.read(val.data(), sizeof(T) * sz);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
pistream &m_strm;
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* PSTREAM_H_ */
|
#endif /* PSTREAM_H_ */
|
||||||
|
@ -26,7 +26,7 @@ public:
|
|||||||
opt_cmd (*this, "c", "cmd", "run", "run:convert:listdevices:static:header:docheader", "run|convert|listdevices|static|header"),
|
opt_cmd (*this, "c", "cmd", "run", "run:convert:listdevices:static:header:docheader", "run|convert|listdevices|static|header"),
|
||||||
opt_file(*this, "f", "file", "-", "file to process (default is stdin)"),
|
opt_file(*this, "f", "file", "-", "file to process (default is stdin)"),
|
||||||
opt_defines(*this, "D", "define", "predefine value as macro, e.g. -Dname=value. If '=value' is omitted predefine it as 1. This option may be specified repeatedly."),
|
opt_defines(*this, "D", "define", "predefine value as macro, e.g. -Dname=value. If '=value' is omitted predefine it as 1. This option may be specified repeatedly."),
|
||||||
opt_rfolders(*this, "r", "rom", "where to look for files"),
|
opt_rfolders(*this, "r", "rom", "where to look for data files"),
|
||||||
opt_verb(*this, "v", "verbose", "be verbose - this produces lots of output"),
|
opt_verb(*this, "v", "verbose", "be verbose - this produces lots of output"),
|
||||||
opt_quiet(*this, "q", "quiet", "be quiet - no warnings"),
|
opt_quiet(*this, "q", "quiet", "be quiet - no warnings"),
|
||||||
opt_version(*this, "", "version", "display version and exit"),
|
opt_version(*this, "", "version", "display version and exit"),
|
||||||
@ -37,6 +37,8 @@ public:
|
|||||||
opt_ttr (*this, "t", "time_to_run", 1.0, "time to run the emulation (seconds)"),
|
opt_ttr (*this, "t", "time_to_run", 1.0, "time to run the emulation (seconds)"),
|
||||||
opt_logs(*this, "l", "log" , "define terminal to log. This option may be specified repeatedly."),
|
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_inp(*this, "i", "input", "", "input file to process (default is none)"),
|
||||||
|
opt_loadstate(*this,"", "loadstate", "", "load state from file and continue from there"),
|
||||||
|
opt_savestate(*this,"", "savestate", "", "save state to file at end of run"),
|
||||||
opt_grp4(*this, "Options for convert command", "These options are only used by the convert command."),
|
opt_grp4(*this, "Options for convert command", "These options are only used by the convert command."),
|
||||||
opt_type(*this, "y", "type", "spice", "spice:eagle:rinf", "type of file to be converted: spice,eagle,rinf"),
|
opt_type(*this, "y", "type", "spice", "spice:eagle:rinf", "type of file to be converted: spice,eagle,rinf"),
|
||||||
|
|
||||||
@ -61,6 +63,8 @@ public:
|
|||||||
plib::option_double opt_ttr;
|
plib::option_double opt_ttr;
|
||||||
plib::option_vec opt_logs;
|
plib::option_vec opt_logs;
|
||||||
plib::option_str opt_inp;
|
plib::option_str opt_inp;
|
||||||
|
plib::option_str opt_loadstate;
|
||||||
|
plib::option_str opt_savestate;
|
||||||
plib::option_group opt_grp4;
|
plib::option_group opt_grp4;
|
||||||
plib::option_str_limit opt_type;
|
plib::option_str_limit opt_type;
|
||||||
plib::option_example opt_ex1;
|
plib::option_example opt_ex1;
|
||||||
@ -179,15 +183,16 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void save_state()
|
template<typename T>
|
||||||
|
std::vector<T> save_state()
|
||||||
{
|
{
|
||||||
state().pre_save();
|
state().pre_save();
|
||||||
std::size_t size = 0;
|
std::size_t size = 0;
|
||||||
for (auto const & s : state().save_list())
|
for (auto const & s : state().save_list())
|
||||||
size += ((s->m_dt.size * s->m_count + sizeof(unsigned) - 1) / sizeof(unsigned));
|
size += ((s->m_dt.size * s->m_count + sizeof(T) - 1) / sizeof(T));
|
||||||
|
|
||||||
auto buf = plib::palloc_array<unsigned>(size);
|
auto buf = std::vector<T>(size);
|
||||||
auto p = buf;
|
auto p = buf.data();
|
||||||
|
|
||||||
for (auto const & s : state().save_list())
|
for (auto const & s : state().save_list())
|
||||||
{
|
{
|
||||||
@ -196,8 +201,34 @@ public:
|
|||||||
std::memcpy(p, s->m_ptr, sz );
|
std::memcpy(p, s->m_ptr, sz );
|
||||||
else
|
else
|
||||||
log().fatal("found unsupported save element {1}\n", s->m_name);
|
log().fatal("found unsupported save element {1}\n", s->m_name);
|
||||||
p += ((sz + sizeof(unsigned) - 1) / sizeof(unsigned));
|
p += ((sz + sizeof(T) - 1) / sizeof(T));
|
||||||
}
|
}
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void load_state(std::vector<T> &buf)
|
||||||
|
{
|
||||||
|
std::size_t size = 0;
|
||||||
|
for (auto const & s : state().save_list())
|
||||||
|
size += ((s->m_dt.size * s->m_count + sizeof(T) - 1) / sizeof(T));
|
||||||
|
|
||||||
|
if (buf.size() != size)
|
||||||
|
throw netlist::nl_exception("Size different during load state.");
|
||||||
|
|
||||||
|
auto p = buf.data();
|
||||||
|
|
||||||
|
for (auto const & s : state().save_list())
|
||||||
|
{
|
||||||
|
std::size_t sz = s->m_dt.size * s->m_count;
|
||||||
|
if (s->m_dt.is_float || s->m_dt.is_integral)
|
||||||
|
std::memcpy(s->m_ptr, p, sz );
|
||||||
|
else
|
||||||
|
log().fatal("found unsupported save element {1}\n", s->m_name);
|
||||||
|
p += ((sz + sizeof(T) - 1) / sizeof(T));
|
||||||
|
}
|
||||||
|
state().post_load();
|
||||||
|
rebuild_lists();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@ -295,33 +326,65 @@ void tool_app_t::run()
|
|||||||
|
|
||||||
std::vector<input_t> inps = read_input(nt.setup(), opt_inp());
|
std::vector<input_t> inps = read_input(nt.setup(), opt_inp());
|
||||||
|
|
||||||
double ttr = opt_ttr();
|
netlist::netlist_time ttr = netlist::netlist_time::from_double(opt_ttr());
|
||||||
t.stop();
|
t.stop();
|
||||||
|
|
||||||
pout("startup time ==> {1:5.3f}\n", t.as_seconds() );
|
pout("startup time ==> {1:5.3f}\n", t.as_seconds() );
|
||||||
pout("runnning ...\n");
|
|
||||||
|
|
||||||
t.reset();
|
t.reset();
|
||||||
t.start();
|
t.start();
|
||||||
|
|
||||||
unsigned pos = 0;
|
// FIXME: error handling
|
||||||
netlist::netlist_time nlt = netlist::netlist_time::zero();
|
if (opt_loadstate.was_specified())
|
||||||
|
{
|
||||||
|
plib::pifilestream strm(opt_loadstate());
|
||||||
|
plib::pbinary_reader reader(strm);
|
||||||
|
std::vector<char> loadstate;
|
||||||
|
reader.read(loadstate);
|
||||||
|
nt.load_state(loadstate);
|
||||||
|
pout("Loaded state, run will continue at {1:.6f}\n", nt.time().as_double());
|
||||||
|
}
|
||||||
|
|
||||||
while (pos < inps.size() && inps[pos].m_time < netlist::netlist_time::from_double(ttr))
|
unsigned pos = 0;
|
||||||
|
netlist::netlist_time nlt = nt.time();
|
||||||
|
|
||||||
|
|
||||||
|
while (pos < inps.size()
|
||||||
|
&& inps[pos].m_time < ttr
|
||||||
|
&& inps[pos].m_time >= nlt)
|
||||||
{
|
{
|
||||||
nt.process_queue(inps[pos].m_time - nlt);
|
nt.process_queue(inps[pos].m_time - nlt);
|
||||||
inps[pos].setparam();
|
inps[pos].setparam();
|
||||||
nlt = inps[pos].m_time;
|
nlt = inps[pos].m_time;
|
||||||
pos++;
|
pos++;
|
||||||
}
|
}
|
||||||
nt.process_queue(netlist::netlist_time::from_double(ttr) - nlt);
|
|
||||||
nt.save_state();
|
pout("runnning ...\n");
|
||||||
|
|
||||||
|
if (ttr > nlt)
|
||||||
|
nt.process_queue(ttr - nlt);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pout("end time {1:.6f} less than saved time {2:.6f}\n",
|
||||||
|
ttr.as_double(), nlt.as_double());
|
||||||
|
ttr = nlt;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opt_savestate.was_specified())
|
||||||
|
{
|
||||||
|
auto savestate = nt.save_state<char>();
|
||||||
|
plib::pofilestream strm(opt_savestate());
|
||||||
|
plib::pbinary_writer writer(strm);
|
||||||
|
writer.write(savestate);
|
||||||
|
}
|
||||||
nt.stop();
|
nt.stop();
|
||||||
|
|
||||||
t.stop();
|
t.stop();
|
||||||
|
|
||||||
double emutime = t.as_seconds();
|
double emutime = t.as_seconds();
|
||||||
pout("{1:f} seconds emulation took {2:f} real time ==> {3:5.2f}%\n", ttr, emutime, ttr/emutime*100.0);
|
pout("{1:f} seconds emulation took {2:f} real time ==> {3:5.2f}%\n",
|
||||||
|
(ttr - nlt).as_double(), emutime,
|
||||||
|
(ttr - nlt).as_double() / emutime * 100.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void tool_app_t::static_compile()
|
void tool_app_t::static_compile()
|
||||||
|
Loading…
Reference in New Issue
Block a user