From 86f0b315b66898d25fd6918a7eabef025fb4511b Mon Sep 17 00:00:00 2001 From: couriersud Date: Mon, 15 Apr 2019 21:08:13 +0200 Subject: 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. --- src/devices/machine/netlist.cpp | 186 ++++++++++++++++++++++------ src/devices/machine/netlist.h | 18 ++- src/lib/netlist/devices/nlid_truthtable.cpp | 4 +- src/lib/netlist/nl_base.h | 11 +- src/lib/netlist/nl_setup.cpp | 8 +- src/lib/netlist/plib/plists.h | 13 +- src/lib/netlist/plib/pmempool.h | 35 ++++-- src/mame/machine/nl_gtrak10.cpp | 10 ++ 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 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 + 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)...)) { } +}; + 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 stream(const pstring &name) override; private: - device_t &m_dev; + const device_t &m_dev; }; @@ -244,11 +308,17 @@ private: plib::unique_ptr netlist_source_memregion_t::stream(const pstring &name) { //memory_region *mem = static_cast(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(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(mem->base(), mem->bytes()); + } + else + throw memregion_not_set("memregion unavailable for {1} in source {2}", name, m_name); + //return plib::unique_ptr(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(nlstate, dfqn); - static_cast(dev.get())->register_callback(std::move(m_delegate)); + //static_cast(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(nlstate, dfqn); - static_cast(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(*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(*this)); + /* add default data provider for roms - if not in validity check*/ + if (has_running_machine()) + lsetup.register_source(plib::make_unique(*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::netlist_t lnetlist("netlist", plib::make_unique()); + 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(*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( "NETDEV_CALLBACK", "nld_analog_callback", "-"); + lsetup.factory().register_device( "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("NETDEV_SOUND_OUT", "nld_sound_out", "+CHAN"); - setup().factory().register_device("NETDEV_SOUND_IN", "nld_sound_in", "-"); + lsetup.factory().register_device("NETDEV_SOUND_OUT", "nld_sound_out", "+CHAN"); + lsetup.factory().register_device("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 @@ -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(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) + for (std::size_t i=0; i void emplace(const std::size_t index, Args&&... args) { + m_initialized++; // allocate on buffer new (&m_buf[index]) C(std::forward(args)...); } @@ -78,6 +84,7 @@ private: /* ensure proper alignment */ PALIGNAS_VECTOROPT() std::array::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(::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(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(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(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 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() -- cgit v1.2.3