mirror of
https://github.com/holub/mame
synced 2025-07-05 09:57:47 +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_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 (opt->parse(opt_arg) != 0)
|
||||
if (opt->do_parse(opt_arg) != 0)
|
||||
return i;
|
||||
}
|
||||
else
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -163,7 +164,7 @@ namespace plib {
|
||||
{
|
||||
if (has_equal_arg)
|
||||
return i;
|
||||
opt->parse("");
|
||||
opt->do_parse("");
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
@ -65,15 +65,25 @@ public:
|
||||
|
||||
/* no_argument options will be called with "" argument */
|
||||
|
||||
virtual int parse(const pstring &argument) = 0;
|
||||
|
||||
pstring short_opt() { return m_short; }
|
||||
pstring long_opt() { return m_long; }
|
||||
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:
|
||||
pstring m_short;
|
||||
pstring m_long;
|
||||
bool m_has_argument;
|
||||
bool m_specified;
|
||||
};
|
||||
|
||||
class option_str : public option
|
||||
@ -83,9 +93,11 @@ public:
|
||||
: option(parent, ashort, along, help, true), m_val(defval)
|
||||
{}
|
||||
|
||||
pstring operator ()() { return m_val; }
|
||||
|
||||
protected:
|
||||
virtual int parse(const pstring &argument) override;
|
||||
|
||||
pstring operator ()() { return m_val; }
|
||||
private:
|
||||
pstring m_val;
|
||||
};
|
||||
@ -99,11 +111,12 @@ public:
|
||||
m_limit = plib::psplit(limit, ":");
|
||||
}
|
||||
|
||||
virtual int parse(const pstring &argument) override;
|
||||
|
||||
pstring operator ()() { return m_val; }
|
||||
const std::vector<pstring> &limit() { return m_limit; }
|
||||
|
||||
protected:
|
||||
virtual int parse(const pstring &argument) override;
|
||||
|
||||
private:
|
||||
pstring m_val;
|
||||
std::vector<pstring> m_limit;
|
||||
@ -116,9 +129,11 @@ public:
|
||||
: option(parent, ashort, along, help, false), m_val(false)
|
||||
{}
|
||||
|
||||
bool operator ()() { return m_val; }
|
||||
|
||||
protected:
|
||||
virtual int parse(const pstring &argument) override;
|
||||
|
||||
bool operator ()() { return m_val; }
|
||||
private:
|
||||
bool m_val;
|
||||
};
|
||||
@ -130,9 +145,11 @@ public:
|
||||
: option(parent, ashort, along, help, true), m_val(defval)
|
||||
{}
|
||||
|
||||
double operator ()() { return m_val; }
|
||||
|
||||
protected:
|
||||
virtual int parse(const pstring &argument) override;
|
||||
|
||||
double operator ()() { return m_val; }
|
||||
private:
|
||||
double m_val;
|
||||
};
|
||||
@ -144,9 +161,11 @@ public:
|
||||
: option(parent, ashort, along, help, true), m_val(defval)
|
||||
{}
|
||||
|
||||
long operator ()() { return m_val; }
|
||||
|
||||
protected:
|
||||
virtual int parse(const pstring &argument) override;
|
||||
|
||||
long operator ()() { return m_val; }
|
||||
private:
|
||||
long m_val;
|
||||
};
|
||||
@ -158,9 +177,11 @@ public:
|
||||
: option(parent, ashort, along, help, true)
|
||||
{}
|
||||
|
||||
std::vector<pstring> operator ()() { return m_val; }
|
||||
|
||||
protected:
|
||||
virtual int parse(const pstring &argument) override;
|
||||
|
||||
std::vector<pstring> operator ()() { return m_val; }
|
||||
private:
|
||||
std::vector<pstring> m_val;
|
||||
};
|
||||
|
@ -12,6 +12,8 @@
|
||||
#include "pfmtlog.h"
|
||||
#include "pexception.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace plib {
|
||||
// -----------------------------------------------------------------------------
|
||||
// pstream: things common to all streams
|
||||
@ -371,6 +373,76 @@ protected:
|
||||
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_ */
|
||||
|
@ -26,7 +26,7 @@ public:
|
||||
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_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_quiet(*this, "q", "quiet", "be quiet - no warnings"),
|
||||
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_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_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_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_vec opt_logs;
|
||||
plib::option_str opt_inp;
|
||||
plib::option_str opt_loadstate;
|
||||
plib::option_str opt_savestate;
|
||||
plib::option_group opt_grp4;
|
||||
plib::option_str_limit opt_type;
|
||||
plib::option_example opt_ex1;
|
||||
@ -179,15 +183,16 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void save_state()
|
||||
template<typename T>
|
||||
std::vector<T> save_state()
|
||||
{
|
||||
state().pre_save();
|
||||
std::size_t size = 0;
|
||||
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 p = buf;
|
||||
auto buf = std::vector<T>(size);
|
||||
auto p = buf.data();
|
||||
|
||||
for (auto const & s : state().save_list())
|
||||
{
|
||||
@ -196,8 +201,34 @@ public:
|
||||
std::memcpy(p, s->m_ptr, sz );
|
||||
else
|
||||
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:
|
||||
@ -295,33 +326,65 @@ void tool_app_t::run()
|
||||
|
||||
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();
|
||||
|
||||
pout("startup time ==> {1:5.3f}\n", t.as_seconds() );
|
||||
pout("runnning ...\n");
|
||||
|
||||
t.reset();
|
||||
t.start();
|
||||
|
||||
unsigned pos = 0;
|
||||
netlist::netlist_time nlt = netlist::netlist_time::zero();
|
||||
// FIXME: error handling
|
||||
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);
|
||||
inps[pos].setparam();
|
||||
nlt = inps[pos].m_time;
|
||||
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();
|
||||
|
||||
t.stop();
|
||||
|
||||
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()
|
||||
|
Loading…
Reference in New Issue
Block a user