summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author couriersud <couriersud@gmx.org>2019-04-15 21:08:13 +0200
committer couriersud <couriersud@gmx.org>2019-04-15 21:41:01 +0200
commit86f0b315b66898d25fd6918a7eabef025fb4511b (patch)
tree8161cececc3de487638e873fc3e226f582e90b71
parent7e623cc8862f7b04a65924a99a9ab354008e2eea (diff)
netlist: Add validation support to netlist device.
mame -validate now also checks all netlist devices. It does this by constructing a temporary netlist. This commit also fixes some memory leaks and a bad bug which surfaced in validation.
-rw-r--r--src/devices/machine/netlist.cpp186
-rw-r--r--src/devices/machine/netlist.h18
-rw-r--r--src/lib/netlist/devices/nlid_truthtable.cpp4
-rw-r--r--src/lib/netlist/nl_base.h11
-rw-r--r--src/lib/netlist/nl_setup.cpp8
-rw-r--r--src/lib/netlist/plib/plists.h13
-rw-r--r--src/lib/netlist/plib/pmempool.h35
-rw-r--r--src/mame/machine/nl_gtrak10.cpp10
8 files changed, 223 insertions, 62 deletions
diff --git a/src/devices/machine/netlist.cpp b/src/devices/machine/netlist.cpp
index f78b072d421..b9c3ff00f7d 100644
--- a/src/devices/machine/netlist.cpp
+++ b/src/devices/machine/netlist.cpp
@@ -53,7 +53,7 @@ class netlist_mame_device::netlist_mame_callbacks_t : public netlist::callbacks_
{
public:
- netlist_mame_callbacks_t(netlist_mame_device &parent)
+ netlist_mame_callbacks_t(const netlist_mame_device &parent)
: netlist::callbacks_t()
, m_parent(parent)
{
@@ -80,13 +80,47 @@ protected:
m_parent.logerror("netlist ERROR: %s\n", ls.c_str());
break;
case plib::plog_level::FATAL:
- emu_fatalerror error("netlist ERROR: %s\n", ls.c_str());
- throw error;
+ throw emu_fatalerror(1, "netlist ERROR: %s\n", ls.c_str());
+ }
+ }
+
+private:
+ const netlist_mame_device &m_parent;
+};
+
+class netlist_validate_callbacks_t : public netlist::callbacks_t
+{
+public:
+
+ netlist_validate_callbacks_t()
+ : netlist::callbacks_t()
+ {
+ }
+
+protected:
+ void vlog(const plib::plog_level &l, const pstring &ls) const override
+ {
+ switch (l)
+ {
+ case plib::plog_level::DEBUG:
+ break;
+ case plib::plog_level::INFO:
+ break;
+ case plib::plog_level::VERBOSE:
+ break;
+ case plib::plog_level::WARNING:
+ osd_printf_verbose("netlist WARNING: %s\n", ls.c_str());
+ break;
+ case plib::plog_level::ERROR:
+ osd_printf_error("netlist ERROR: %s\n", ls.c_str());
+ break;
+ case plib::plog_level::FATAL:
+ //throw emu_fatalerror(1, "netlist ERROR: %s\n", ls.c_str());
+ throw emu_fatalerror("netlist ERROR: %s\n", ls.c_str());
}
}
private:
- netlist_mame_device &m_parent;
};
@@ -100,8 +134,14 @@ public:
{
}
+ netlist_mame_t(netlist_mame_device &parent, const pstring &aname, plib::unique_ptr<netlist::callbacks_t> cbs)
+ : netlist::netlist_t(aname, std::move(cbs))
+ , m_parent(parent)
+ {
+ }
+
running_machine &machine() { return m_parent.machine(); }
- netlist_mame_device &parent() { return m_parent; }
+ netlist_mame_device &parent() const { return m_parent; }
private:
netlist_mame_device &m_parent;
@@ -211,9 +251,33 @@ private:
// Extensions to interface netlist with MAME code ....
// ----------------------------------------------------------------------------------------
+/*! Specific exception if memregion is not available.
+ * The exception is thrown if the memregions are not available.
+ * This may be the case in device_validity_check and needs
+ * to be ignored.
+ */
+class memregion_not_set : public netlist::nl_exception
+{
+public:
+ /*! Constructor.
+ * Allows a descriptive text to be assed to the exception
+ */
+ explicit memregion_not_set(const pstring &text //!< text to be passed
+ )
+ : netlist::nl_exception(text) { }
+
+ template<typename... Args>
+ explicit memregion_not_set(const pstring &fmt //!< format to be used
+ , Args&&... args //!< arguments to be passed
+ )
+ : netlist::nl_exception(plib::pfmt(fmt)(std::forward<Args>(args)...)) { }
+};
+
class netlist_source_memregion_t : public netlist::source_t
{
public:
+
+
netlist_source_memregion_t(device_t &dev, pstring name)
: netlist::source_t(), m_dev(dev), m_name(name)
{
@@ -228,12 +292,12 @@ private:
class netlist_data_memregions_t : public netlist::source_t
{
public:
- netlist_data_memregions_t(device_t &dev);
+ netlist_data_memregions_t(const device_t &dev);
virtual plib::unique_ptr<plib::pistream> stream(const pstring &name) override;
private:
- device_t &m_dev;
+ const device_t &m_dev;
};
@@ -244,11 +308,17 @@ private:
plib::unique_ptr<plib::pistream> netlist_source_memregion_t::stream(const pstring &name)
{
//memory_region *mem = static_cast<netlist_mame_device::netlist_mame_t &>(setup().setup().exec()).machine().root_device().memregion(m_name.c_str());
- memory_region *mem = m_dev.machine().root_device().memregion(m_name.c_str());
- return plib::make_unique<plib::pimemstream>(mem->base(), mem->bytes());
+ if (m_dev.has_running_machine())
+ {
+ memory_region *mem = m_dev.machine().root_device().memregion(m_name.c_str());
+ return plib::make_unique<plib::pimemstream>(mem->base(), mem->bytes());
+ }
+ else
+ throw memregion_not_set("memregion unavailable for {1} in source {2}", name, m_name);
+ //return plib::unique_ptr<plib::pimemstream>(nullptr);
}
-netlist_data_memregions_t::netlist_data_memregions_t(device_t &dev)
+netlist_data_memregions_t::netlist_data_memregions_t(const device_t &dev)
: netlist::source_t(netlist::source_t::DATA), m_dev(dev)
{
}
@@ -602,10 +672,14 @@ void netlist_mame_analog_output_device::custom_netlist_additions(netlist::netlis
const pstring pin(m_in);
pstring dname = pstring("OUT_") + pin;
pstring dfqn = nlstate.setup().build_fqn(dname);
- m_delegate.bind_relative_to(owner()->machine().root_device());
+
+ /* ignore if no running machine -> called within device_validity_check context */
+ if (owner()->has_running_machine())
+ m_delegate.bind_relative_to(owner()->machine().root_device());
auto dev = netlist::pool().make_poolptr<NETLIB_NAME(analog_callback)>(nlstate, dfqn);
- static_cast<NETLIB_NAME(analog_callback) *>(dev.get())->register_callback(std::move(m_delegate));
+ //static_cast<NETLIB_NAME(analog_callback) *>(dev.get())->register_callback(std::move(m_delegate));
+ dev->register_callback(std::move(m_delegate));
nlstate.add_dev(dfqn, std::move(dev));
nlstate.setup().register_link(dname + ".IN", pin);
}
@@ -639,10 +713,12 @@ void netlist_mame_logic_output_device::custom_netlist_additions(netlist::netlist
pstring dname = "OUT_" + pin;
pstring dfqn = nlstate.setup().build_fqn(dname);
- m_delegate.bind_relative_to(owner()->machine().root_device());
+ /* ignore if no running machine -> called within device_validity_check context */
+ if (owner()->has_running_machine())
+ m_delegate.bind_relative_to(owner()->machine().root_device());
auto dev = netlist::pool().make_poolptr<NETLIB_NAME(logic_callback)>(nlstate, dfqn);
- static_cast<NETLIB_NAME(logic_callback) *>(dev.get())->register_callback(std::move(m_delegate));
+ dev->register_callback(std::move(m_delegate));
nlstate.add_dev(dfqn, std::move(dev));
nlstate.setup().register_link(dname + ".IN", pin);
}
@@ -858,25 +934,16 @@ netlist_mame_device::~netlist_mame_device()
void netlist_mame_device::device_config_complete()
{
LOGDEVCALLS("device_config_complete %s\n", this->mconfig().gamedrv().name);
-}
-void netlist_mame_device::device_validity_check(validity_checker &valid) const
-{
- LOGDEVCALLS("device_validity_check %s\n", this->mconfig().gamedrv().name);
}
-
-void netlist_mame_device::device_start()
+void netlist_mame_device::common_dev_start(netlist::netlist_t *lnetlist) const
{
- LOGDEVCALLS("device_start entry\n");
-
- //printf("clock is %d\n", clock());
-
- m_netlist = netlist::pool().make_poolptr<netlist_mame_t>(*this, "netlist");
+ auto &lsetup = lnetlist->nlstate().setup();
// register additional devices
- nl_register_devices();
+ nl_register_devices(lsetup);
/* let sub-devices add sources and do stuff prior to parsing */
for (device_t &d : subdevices())
@@ -885,15 +952,17 @@ void netlist_mame_device::device_start()
if( sdev != nullptr )
{
LOGDEVCALLS("Preparse subdevice %s/%s\n", d.name(), d.shortname());
- sdev->pre_parse_action(m_netlist->nlstate());
+ sdev->pre_parse_action(lnetlist->nlstate());
}
}
- /* add default data provider for roms */
- setup().register_source(plib::make_unique<netlist_data_memregions_t>(*this));
+ /* add default data provider for roms - if not in validity check*/
+ if (has_running_machine())
+ lsetup.register_source(plib::make_unique<netlist_data_memregions_t>(*this));
- m_setup_func(setup());
+ m_setup_func(lsetup);
+#if 1
/* let sub-devices tweak the netlist */
for (device_t &d : subdevices())
{
@@ -901,15 +970,52 @@ void netlist_mame_device::device_start()
if( sdev != nullptr )
{
LOGDEVCALLS("Found subdevice %s/%s\n", d.name(), d.shortname());
- sdev->custom_netlist_additions(m_netlist->nlstate());
+ sdev->custom_netlist_additions(lnetlist->nlstate());
}
}
+ lsetup.prepare_to_run();
+#endif
+}
+
+
+void netlist_mame_device::device_validity_check(validity_checker &valid) const
+{
+#if 1
+ LOGDEVCALLS("device_validity_check %s\n", this->mconfig().gamedrv().name);
+
+ try
+ {
+ //netlist_mame_t lnetlist(*this, "netlist", plib::make_unique<netlist_validate_callbacks_t>());
+ netlist::netlist_t lnetlist("netlist", plib::make_unique<netlist_validate_callbacks_t>());
+ common_dev_start(&lnetlist);
+ }
+ catch (memregion_not_set &err)
+ {
+ osd_printf_verbose("%s\n", err.what());
+ }
+ catch (emu_fatalerror &err)
+ {
+ osd_printf_error("%s\n", err.string());
+ }
+ catch (std::exception &err)
+ {
+ osd_printf_error("%s\n", err.what());
+ }
+#endif
+}
+
+
+void netlist_mame_device::device_start()
+{
+ LOGDEVCALLS("device_start entry\n");
+
+ m_netlist = netlist::pool().make_poolptr<netlist_mame_t>(*this, "netlist");
- setup().prepare_to_run();
+ common_dev_start(m_netlist.get());
- netlist().nlstate().save(*this, m_rem, this->name(), "m_rem");
- netlist().nlstate().save(*this, m_div, this->name(), "m_div");
- netlist().nlstate().save(*this, m_old, this->name(), "m_old");
+ m_netlist->nlstate().save(*this, m_rem, this->name(), "m_rem");
+ m_netlist->nlstate().save(*this, m_div, this->name(), "m_div");
+ m_netlist->nlstate().save(*this, m_old, this->name(), "m_old");
save_state();
@@ -1055,9 +1161,9 @@ void netlist_mame_cpu_device::device_start()
}
-void netlist_mame_cpu_device::nl_register_devices()
+void netlist_mame_cpu_device::nl_register_devices(netlist::setup_t &lsetup) const
{
- setup().factory().register_device<nld_analog_callback>( "NETDEV_CALLBACK", "nld_analog_callback", "-");
+ lsetup.factory().register_device<nld_analog_callback>( "NETDEV_CALLBACK", "nld_analog_callback", "-");
}
ATTR_COLD uint64_t netlist_mame_cpu_device::execute_clocks_to_cycles(uint64_t clocks) const
@@ -1182,10 +1288,10 @@ void netlist_mame_sound_device::device_start()
}
-void netlist_mame_sound_device::nl_register_devices()
+void netlist_mame_sound_device::nl_register_devices(netlist::setup_t &lsetup) const
{
- setup().factory().register_device<nld_sound_out>("NETDEV_SOUND_OUT", "nld_sound_out", "+CHAN");
- setup().factory().register_device<nld_sound_in>("NETDEV_SOUND_IN", "nld_sound_in", "-");
+ lsetup.factory().register_device<nld_sound_out>("NETDEV_SOUND_OUT", "nld_sound_out", "+CHAN");
+ lsetup.factory().register_device<nld_sound_in>("NETDEV_SOUND_IN", "nld_sound_in", "-");
}
diff --git a/src/devices/machine/netlist.h b/src/devices/machine/netlist.h
index 0a3ba5b15c1..ef9faa8b87f 100644
--- a/src/devices/machine/netlist.h
+++ b/src/devices/machine/netlist.h
@@ -20,6 +20,7 @@ class nld_sound_in;
namespace netlist {
class setup_t;
+ class netlist_t;
class netlist_state_t;
class nlparse_t;
template <typename T>
@@ -131,7 +132,7 @@ protected:
netlist_mame_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
// Custom to netlist ...
- virtual void nl_register_devices() { }
+ virtual void nl_register_devices(netlist::setup_t &lsetup) const { }
// device_t overrides
virtual void device_config_complete() override;
@@ -148,6 +149,8 @@ protected:
private:
void save_state();
+ void common_dev_start(netlist::netlist_t *lnetlist) const;
+
/* timing support here - so sound can hijack it ... */
netlist::netlist_time m_rem;
netlist::netlist_time m_old;
@@ -186,6 +189,11 @@ public:
// construction/destruction
netlist_mame_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+ ~netlist_mame_cpu_device()
+ {
+
+ }
+
offs_t genPC() const { return m_genPC; }
netlist_mame_cpu_device & set_source(void (*setup_func)(netlist::nlparse_t &))
@@ -203,7 +211,7 @@ public:
protected:
// netlist_mame_device
- virtual void nl_register_devices() override;
+ virtual void nl_register_devices(netlist::setup_t &lsetup) const override;
// device_t overrides
virtual void device_start() override;
@@ -262,7 +270,7 @@ public:
protected:
// netlist_mame_device
- virtual void nl_register_devices() override;
+ virtual void nl_register_devices(netlist::setup_t &lsetup) const override;
// device_t overrides
virtual void device_start() override;
@@ -288,6 +296,10 @@ public:
{
}
+ virtual ~netlist_mame_sub_interface()
+ {
+ }
+
virtual void custom_netlist_additions(netlist::netlist_state_t &nlstate) { }
virtual void pre_parse_action(netlist::netlist_state_t &nlstate) { }
diff --git a/src/lib/netlist/devices/nlid_truthtable.cpp b/src/lib/netlist/devices/nlid_truthtable.cpp
index 2221d855880..c62c67da3c1 100644
--- a/src/lib/netlist/devices/nlid_truthtable.cpp
+++ b/src/lib/netlist/devices/nlid_truthtable.cpp
@@ -207,7 +207,6 @@ namespace netlist
if (idx != plib::container::npos)
connect(m_Q[i], m_I[idx]);
}
-
m_ign = 0;
}
@@ -237,6 +236,9 @@ namespace netlist
if (m_family_name != "")
m_family_desc = anetlist.setup().family_from_model(m_family_name);
+ if (m_family_desc == nullptr)
+ throw nl_exception("family description not found for {1}", m_family_name);
+
return pool().make_poolptr<tt_type>(anetlist, name, m_family_desc, m_ttbl, m_desc);
}
private:
diff --git a/src/lib/netlist/nl_base.h b/src/lib/netlist/nl_base.h
index cd43b5688ad..f52b720ab37 100644
--- a/src/lib/netlist/nl_base.h
+++ b/src/lib/netlist/nl_base.h
@@ -433,7 +433,11 @@ namespace netlist
void operator delete (void * mem) = delete;
#endif
protected:
- ~object_t() noexcept = default; // only childs should be destructible
+ // only childs should be destructible
+ ~object_t() noexcept
+ {
+ name_hash().erase(name_hash().find(this));
+ }
private:
//pstring m_name;
@@ -1369,7 +1373,10 @@ namespace netlist
{
for (auto & d : m_devices)
if (d.first == name)
- log().fatal(MF_1_DUPLICATE_NAME_DEVICE_LIST, d.first);
+ {
+ dev.release();
+ log().fatal(MF_1_DUPLICATE_NAME_DEVICE_LIST, name);
+ }
//m_devices.push_back(std::move(dev));
m_devices.insert(m_devices.end(), { name, std::move(dev) });
}
diff --git a/src/lib/netlist/nl_setup.cpp b/src/lib/netlist/nl_setup.cpp
index 7fa3db867a9..6caafa27a66 100644
--- a/src/lib/netlist/nl_setup.cpp
+++ b/src/lib/netlist/nl_setup.cpp
@@ -272,8 +272,10 @@ pstring setup_t::get_initial_param_val(const pstring &name, const pstring &def)
void setup_t::register_term(detail::core_terminal_t &term)
{
if (!m_terminals.insert({term.name(), &term}).second)
+ {
log().fatal(MF_2_ADDING_1_2_TO_TERMINAL_LIST, termtype_as_str(term),
term.name());
+ }
log().debug("{1} {2}\n", termtype_as_str(term), term.name());
}
@@ -1144,7 +1146,11 @@ bool source_t::parse(nlparse_t &setup, const pstring &name)
return false;
else
{
- return setup.parse_stream(stream(name), name);
+ auto strm(stream(name));
+ if (strm)
+ return setup.parse_stream(std::move(strm), name);
+ else
+ return false;
}
}
diff --git a/src/lib/netlist/plib/plists.h b/src/lib/netlist/plib/plists.h
index c2fee9c2f8e..525a65a97f2 100644
--- a/src/lib/netlist/plib/plists.h
+++ b/src/lib/netlist/plib/plists.h
@@ -34,13 +34,18 @@ public:
using iterator = C *;
using const_iterator = const C *;
- uninitialised_array_t() noexcept = default;
+ //uninitialised_array_t() noexcept = default;
+ uninitialised_array_t() noexcept
+ : m_initialized(0)
+ {
+ }
COPYASSIGNMOVE(uninitialised_array_t, delete)
~uninitialised_array_t() noexcept
{
- for (std::size_t i=0; i<N; i++)
- (*this)[i].~C();
+ if (m_initialized>=N)
+ for (std::size_t i=0; i<N; i++)
+ (*this)[i].~C();
}
size_t size() const { return N; }
@@ -58,6 +63,7 @@ public:
template<typename... Args>
void emplace(const std::size_t index, Args&&... args)
{
+ m_initialized++;
// allocate on buffer
new (&m_buf[index]) C(std::forward<Args>(args)...);
}
@@ -78,6 +84,7 @@ private:
/* ensure proper alignment */
PALIGNAS_VECTOROPT()
std::array<typename std::aligned_storage<sizeof(C), alignof(C)>::type, N> m_buf;
+ unsigned m_initialized;
};
// ----------------------------------------------------------------------------------------
diff --git a/src/lib/netlist/plib/pmempool.h b/src/lib/netlist/plib/pmempool.h
index f55807c86dc..87c74e14856 100644
--- a/src/lib/netlist/plib/pmempool.h
+++ b/src/lib/netlist/plib/pmempool.h
@@ -40,12 +40,18 @@ namespace plib {
{
min_bytes = std::max(mp->m_min_alloc, min_bytes);
m_free = min_bytes;
- std::size_t alloc_bytes = (min_bytes + mp->m_min_align - 1) & ~(mp->m_min_align - 1);
- m_data_allocated = static_cast<char *>(::operator new(alloc_bytes));
+ std::size_t alloc_bytes = (min_bytes + mp->m_min_align); // - 1); // & ~(mp->m_min_align - 1);
+ //m_data_allocated = ::operator new(alloc_bytes);
+ m_data_allocated = new char[alloc_bytes];
void *r = m_data_allocated;
std::align(mp->m_min_align, min_bytes, r, alloc_bytes);
m_data = reinterpret_cast<char *>(r);
}
+ ~block()
+ {
+ //::operator delete(m_data_allocated);
+ delete [] m_data_allocated;
+ }
std::size_t m_num_alloc;
std::size_t m_free;
std::size_t m_cur;
@@ -106,7 +112,8 @@ namespace plib {
plib::perrlogger("Found {} info blocks\n", sinfo().size());
plib::perrlogger("Found block with {} dangling allocations\n", b->m_num_alloc);
}
- ::operator delete(b->m_data);
+ plib::pdelete(b);
+ //::operator delete(b->m_data);
}
}
@@ -125,8 +132,6 @@ namespace plib {
auto *ret = reinterpret_cast<void *>(b->m_data + b->m_cur);
auto capacity(rs);
ret = std::align(align, size, ret, capacity);
- // FIXME: if (ret == nullptr)
- // printf("Oh no\n");
sinfo().insert({ ret, info(b, b->m_cur)});
rs -= (capacity - size);
b->m_cur += rs;
@@ -141,8 +146,6 @@ namespace plib {
auto *ret = reinterpret_cast<void *>(b->m_data + b->m_cur);
auto capacity(rs);
ret = std::align(align, size, ret, capacity);
- // FIXME: if (ret == nullptr)
- // printf("Oh no\n");
sinfo().insert({ ret, info(b, b->m_cur)});
rs -= (capacity - size);
b->m_cur += rs;
@@ -162,12 +165,20 @@ namespace plib {
plib::terminate("mempool::free - double free was called\n");
else
{
- //b->m_free = m_min_alloc;
- //b->cur_ptr = b->data;
+ b->m_num_alloc--;
+ //printf("Freeing in block %p %lu\n", b, b->m_num_alloc);
+ sinfo().erase(it);
+ if (b->m_num_alloc == 0)
+ {
+ mempool *mp = b->m_mempool;
+ auto itb = std::find(mp->m_blocks.begin(), mp->m_blocks.end(), b);
+ if (itb == mp->m_blocks.end())
+ plib::terminate("mempool::free - block not found\n");
+
+ mp->m_blocks.erase(itb);
+ plib::pdelete(b);
+ }
}
- b->m_num_alloc--;
- //printf("Freeing in block %p %lu\n", b, b->m_num_alloc);
- sinfo().erase(it);
}
template <typename T>
diff --git a/src/mame/machine/nl_gtrak10.cpp b/src/mame/machine/nl_gtrak10.cpp
index ba83b32abc5..7ba8a7adb05 100644
--- a/src/mame/machine/nl_gtrak10.cpp
+++ b/src/mame/machine/nl_gtrak10.cpp
@@ -369,6 +369,7 @@ NETLIST_START(gtrak10)
NET_C(RT, R66.1)
NET_C(SLICK_Q, R65.1)
+#if 0
CAP(C44, CAP_U(10))
NET_C(C44.1, R63.2)
NET_C(C44.1, R73.2)
@@ -377,5 +378,14 @@ NETLIST_START(gtrak10)
NET_C(C44.1, R66.2)
NET_C(C44.1, R65.2)
ALIAS(VIDEO_OUT, C44.2)
+#else
+ // A capacitor just kills performance completely
+ RES(RVID, RES_K(10))
+ NET_C(GND, RVID.2)
+
+ NET_C(RVID.1, R63.2, R73.2, R64.2, R74.2, R66.2, R65.2)
+
+ ALIAS(VIDEO_OUT, RVID.1)
+#endif
NETLIST_END()