summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/machine/netlist.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/machine/netlist.cpp')
-rw-r--r--src/devices/machine/netlist.cpp1210
1 files changed, 608 insertions, 602 deletions
diff --git a/src/devices/machine/netlist.cpp b/src/devices/machine/netlist.cpp
index 0ceba02df1e..8d4d6cedf4d 100644
--- a/src/devices/machine/netlist.cpp
+++ b/src/devices/machine/netlist.cpp
@@ -1,4 +1,4 @@
-// license:GPL-2.0+
+// license:BSD-3-Clause
// copyright-holders:Couriersud
/***************************************************************************
@@ -11,13 +11,13 @@
#include "emu.h"
#include "netlist.h"
-#include "netlist/nl_base.h"
#include "netlist/nl_setup.h"
#include "netlist/nl_factory.h"
#include "netlist/nl_parser.h"
-#include "netlist/devices/net_lib.h"
+#include "netlist/nl_interface.h"
-#include "netlist/plib/palloc.h"
+#include "netlist/plib/pdynlib.h"
+#include "netlist/plib/pstonum.h"
#include "debugger.h"
#include "romload.h"
@@ -28,7 +28,20 @@
#include <string>
#include <utility>
+#define LOG_DEV_CALLS (1U << 1)
+#define LOG_DEBUG (1U << 2)
+#define LOG_TIMING (1U << 3)
+
+//#define LOG_MASK (LOG_GENERAL | LOG_DEV_CALLS | LOG_DEBUG)
+#define LOG_MASK (0)
+
+#define LOGDEVCALLS(...) LOGMASKED(LOG_DEV_CALLS, __VA_ARGS__)
+#define LOGDEBUG(...) LOGMASKED(LOG_DEBUG, __VA_ARGS__)
+#define LOGTIMING(...) LOGMASKED(LOG_TIMING, __VA_ARGS__)
+
+#define LOG_OUTPUT_FUNC printf
+#define LOGMASKED(mask, ...) do { if (LOG_MASK & (mask)) (LOG_OUTPUT_FUNC)(__VA_ARGS__); } while (false)
DEFINE_DEVICE_TYPE(NETLIST_CORE, netlist_mame_device, "netlist_core", "Netlist Core Device")
DEFINE_DEVICE_TYPE(NETLIST_CPU, netlist_mame_cpu_device, "netlist_cpu", "Netlist CPU Device")
@@ -46,211 +59,129 @@ DEFINE_DEVICE_TYPE(NETLIST_LOGIC_OUTPUT, netlist_mame_logic_output_device, "nl
DEFINE_DEVICE_TYPE(NETLIST_ANALOG_OUTPUT, netlist_mame_analog_output_device, "nl_analog_out", "Netlist Analog Output")
DEFINE_DEVICE_TYPE(NETLIST_STREAM_OUTPUT, netlist_mame_stream_output_device, "nl_stream_out", "Netlist Stream Output")
-
// ----------------------------------------------------------------------------------------
// Special netlist extension devices ....
// ----------------------------------------------------------------------------------------
-class netlist_mame_device::netlist_mame_callbacks_t : public netlist::callbacks_t
+extern const plib::static_library::symbol nl_static_solver_syms[];
+
+static netlist::netlist_time_ext nltime_from_attotime(attotime t)
{
-public:
+ netlist::netlist_time_ext nlmtime = netlist::netlist_time_ext::from_sec(t.seconds());
+ nlmtime += netlist::netlist_time_ext::from_raw(t.attoseconds() / (ATTOSECONDS_PER_SECOND / netlist::netlist_time_ext::resolution()));
+ return nlmtime;
+}
- netlist_mame_callbacks_t(const netlist_mame_device &parent)
- : netlist::callbacks_t()
- , m_parent(parent)
+void netlist_log_csv<1>::open(running_machine &machine, const std::string &name)
+{
+ m_csv_file = fopen(name.c_str(), "wb");
+ m_machine = &machine;
+}
+
+void netlist_log_csv<1>::close()
+{
+ if (m_csv_file != nullptr)
{
+ log_flush();
+ fclose(m_csv_file);
}
+}
+
+void netlist_log_csv<1>::log_add(char const* param, double value, bool isfloat)
+{
+ // skip if no file
+ if (m_csv_file == nullptr)
+ return;
+
+ // make a new entry
+ buffer_entry entry = { (*m_machine).scheduler().time(), isfloat, value, param };
-protected:
- void vlog(const plib::plog_level &l, const pstring &ls) const override
+ // flush out half of the old entries if we hit the buffer limit
+ if (m_buffer.size() >= MAX_BUFFER_ENTRIES)
+ log_flush(MAX_BUFFER_ENTRIES / 2);
+
+ // fast common case: if we go at the end, just push_back
+ if (m_buffer.size() == 0 || entry.time >= m_buffer.back().time)
{
- switch (l)
+ m_buffer.push_back(entry);
+ return;
+ }
+
+ // find our place in the queue
+ for (auto cur = m_buffer.rbegin(); cur != m_buffer.rend(); cur++)
+ if (entry.time >= cur->time)
{
- case plib::plog_level::DEBUG:
- m_parent.logerror("netlist DEBUG: %s\n", ls.c_str());
- break;
- case plib::plog_level::VERBOSE:
- m_parent.logerror("netlist VERBOSE: %s\n", ls.c_str());
- break;
- case plib::plog_level::INFO:
- m_parent.logerror("netlist INFO: %s\n", ls.c_str());
- break;
- case plib::plog_level::WARNING:
- m_parent.logerror("netlist WARNING: %s\n", ls.c_str());
- break;
- case plib::plog_level::ERROR:
- m_parent.logerror("netlist ERROR: %s\n", ls.c_str());
- break;
- case plib::plog_level::FATAL:
- throw emu_fatalerror(1, "netlist FATAL: %s\n", ls.c_str());
+ m_buffer.insert(cur.base(), entry);
+ return;
}
+
+ // if we're too early, drop this entry rather than risk putting an out-of-order
+ // entry after the last one we flushed
+}
+
+void netlist_log_csv<1>::log_flush(int count)
+{
+ if (m_csv_file == nullptr)
+ return;
+ if (count > m_buffer.size())
+ count = m_buffer.size();
+ while (count--)
+ {
+ auto &entry = m_buffer.front();
+ if (entry.isfloat)
+ fprintf(m_csv_file, "%s,%s,%f\n", entry.time.as_string(), entry.string, entry.value);
+ else
+ fprintf(m_csv_file, "%s,%s,%d\n", entry.time.as_string(), entry.string, int(entry.value));
+ m_buffer.pop_front();
}
+}
-private:
- const netlist_mame_device &m_parent;
-};
-class netlist_validate_callbacks_t : public netlist::callbacks_t
+class netlist_mame_device::netlist_mame_t : public netlist::netlist_state_t
{
public:
- netlist_validate_callbacks_t()
- : netlist::callbacks_t()
+ netlist_mame_t(netlist_mame_device &parent, const pstring &name)
+ : netlist::netlist_state_t(name, plib::plog_delegate(&netlist_mame_t::logger, this))
+ , m_parent(parent)
{
}
-protected:
- void vlog(const plib::plog_level &l, const pstring &ls) const override
+ running_machine &machine() { return m_parent.machine(); }
+ netlist_mame_device &parent() const { return m_parent; }
+
+private:
+ void logger(plib::plog_level l, const pstring &ls)
{
switch (l)
{
case plib::plog_level::DEBUG:
+ m_parent.logerror("netlist DEBUG: %s\n", ls.c_str());
break;
case plib::plog_level::VERBOSE:
+ m_parent.logerror("netlist VERBOSE: %s\n", ls.c_str());
break;
case plib::plog_level::INFO:
- osd_printf_verbose("netlist INFO: %s\n", ls.c_str());
+ m_parent.logerror("netlist INFO: %s\n", ls.c_str());
break;
case plib::plog_level::WARNING:
- osd_printf_warning("netlist WARNING: %s\n", ls.c_str());
+ m_parent.logerror("netlist WARNING: %s\n", ls.c_str());
break;
case plib::plog_level::ERROR:
- osd_printf_error("netlist ERROR: %s\n", ls.c_str());
+ m_parent.logerror("netlist ERROR: %s\n", ls.c_str());
break;
case plib::plog_level::FATAL:
- throw emu_fatalerror(1, "netlist FATAL: %s\n", ls.c_str());
+ m_parent.logerror("netlist FATAL: %s\n", ls.c_str());
+ break;
}
}
-private:
-};
-
-
-class netlist_mame_device::netlist_mame_t : public netlist::netlist_t
-{
-public:
-
- netlist_mame_t(netlist_mame_device &parent, const pstring &aname)
- : netlist::netlist_t(aname, plib::make_unique<netlist_mame_device::netlist_mame_callbacks_t>(parent))
- , m_parent(parent)
- {
- }
-
- 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() const { return m_parent; }
-
-private:
netlist_mame_device &m_parent;
};
namespace {
-// ----------------------------------------------------------------------------------------
-// analog_callback
-// ----------------------------------------------------------------------------------------
-
-class NETLIB_NAME(analog_callback) : public netlist::device_t
-{
-public:
- NETLIB_NAME(analog_callback)(netlist::netlist_state_t &anetlist, const pstring &name)
- : device_t(anetlist, name)
- , m_in(*this, "IN")
- , m_cpu_device(nullptr)
- , m_last(*this, "m_last", 0)
- {
- auto *nl = dynamic_cast<netlist_mame_device::netlist_mame_t *>(&exec());
- if (nl != nullptr)
- m_cpu_device = downcast<netlist_mame_cpu_device *>(&nl->parent());
- }
-
- ATTR_COLD void reset() override
- {
- m_last = 0.0;
- }
-
- ATTR_COLD void register_callback(netlist_mame_analog_output_device::output_delegate &&callback)
- {
- m_callback = std::move(callback);
- }
-
- NETLIB_UPDATEI()
- {
- nl_double cur = m_in();
-
- // FIXME: make this a parameter
- // avoid calls due to noise
- if (std::fabs(cur - m_last) > 1e-6)
- {
- m_cpu_device->update_icount(exec().time());
- m_callback(cur, m_cpu_device->local_time());
- m_cpu_device->check_mame_abort_slice();
- m_last = cur;
- }
- }
-
-private:
- netlist::analog_input_t m_in;
- netlist_mame_analog_output_device::output_delegate m_callback;
- netlist_mame_cpu_device *m_cpu_device;
- netlist::state_var<nl_double> m_last;
-};
-
-// ----------------------------------------------------------------------------------------
-// logic_callback
-// ----------------------------------------------------------------------------------------
-
-class NETLIB_NAME(logic_callback) : public netlist::device_t
-{
-public:
- NETLIB_NAME(logic_callback)(netlist::netlist_state_t &anetlist, const pstring &name)
- : device_t(anetlist, name)
- , m_in(*this, "IN")
- , m_cpu_device(nullptr)
- , m_last(*this, "m_last", 0)
- {
- auto *nl = dynamic_cast<netlist_mame_device::netlist_mame_t *>(&exec());
- if (nl != nullptr)
- m_cpu_device = downcast<netlist_mame_cpu_device *>(&nl->parent());
- }
-
- ATTR_COLD void reset() override
- {
- m_last = 0;
- }
-
- ATTR_COLD void register_callback(netlist_mame_logic_output_device::output_delegate &&callback)
- {
- m_callback = std::move(callback);
- }
-
- NETLIB_UPDATEI()
- {
- netlist::netlist_sig_t cur = m_in();
-
- // FIXME: make this a parameter
- // avoid calls due to noise
- if (cur != m_last)
- {
- m_cpu_device->update_icount(exec().time());
- m_callback(cur, m_cpu_device->local_time());
- m_cpu_device->check_mame_abort_slice();
- m_last = cur;
- }
- }
-
-private:
- netlist::logic_input_t m_in;
- netlist_mame_logic_output_device::output_delegate m_callback;
- netlist_mame_cpu_device *m_cpu_device;
- netlist::state_var<netlist::netlist_sig_t> m_last;
-};
// ----------------------------------------------------------------------------------------
@@ -279,28 +210,27 @@ public:
: netlist::nl_exception(plib::pfmt(fmt)(std::forward<Args>(args)...)) { }
};
-class netlist_source_memregion_t : public netlist::source_t
+class netlist_source_memregion_t : public netlist::source_netlist_t
{
public:
-
netlist_source_memregion_t(device_t &dev, pstring name)
- : netlist::source_t(), m_dev(dev), m_name(name)
+ : netlist::source_netlist_t(), m_dev(dev), m_name(name)
{
}
- virtual plib::unique_ptr<std::istream> stream(const pstring &name) override;
+ virtual plib::istream_uptr stream(const pstring &name) override;
private:
device_t &m_dev;
pstring m_name;
};
-class netlist_data_memregions_t : public netlist::source_t
+class netlist_data_memregions_t : public netlist::source_data_t
{
public:
netlist_data_memregions_t(const device_t &dev);
- virtual plib::unique_ptr<std::istream> stream(const pstring &name) override;
+ virtual plib::istream_uptr stream(const pstring &name) override;
private:
const device_t &m_dev;
@@ -311,12 +241,12 @@ private:
// memregion source support
// ----------------------------------------------------------------------------------------
-plib::unique_ptr<std::istream> netlist_source_memregion_t::stream(const pstring &name)
+plib::istream_uptr netlist_source_memregion_t::stream(const pstring &name)
{
if (m_dev.has_running_machine())
{
- memory_region *mem = m_dev.memregion(m_name.c_str());
- auto ret(plib::make_unique<std::istringstream>(pstring(reinterpret_cast<char *>(mem->base()), mem->bytes())));
+ memory_region *mem = m_dev.memregion(putf8string(m_name).c_str());
+ plib::istream_uptr ret(std::make_unique<std::istringstream>(putf8string(reinterpret_cast<char *>(mem->base()), mem->bytes())), name);
ret->imbue(std::locale::classic());
return ret;
}
@@ -326,21 +256,21 @@ plib::unique_ptr<std::istream> netlist_source_memregion_t::stream(const pstring
}
netlist_data_memregions_t::netlist_data_memregions_t(const device_t &dev)
- : netlist::source_t(netlist::source_t::DATA), m_dev(dev)
+ : netlist::source_data_t(), m_dev(dev)
{
}
static bool rom_exists(device_t &root, pstring name)
{
// iterate, starting with the driver's ROMs and continuing with device ROMs
- for (device_t &device : device_iterator(root))
+ for (device_t &device : device_enumerator(root))
{
// scan the ROM entries for this device
for (tiny_rom_entry const *romp = device.rom_region(); romp && !ROMENTRY_ISEND(romp); ++romp)
{
if (ROMENTRY_ISREGION(romp)) // if this is a region, check for rom
{
- char const *const basetag = romp->name;
+ auto basetag(pstring(romp->name));
if (name == pstring(":") + basetag)
return true;
}
@@ -349,283 +279,114 @@ static bool rom_exists(device_t &root, pstring name)
return false;
}
-plib::unique_ptr<std::istream> netlist_data_memregions_t::stream(const pstring &name)
+plib::istream_uptr netlist_data_memregions_t::stream(const pstring &name)
{
//memory_region *mem = static_cast<netlist_mame_device::netlist_mame_t &>(setup().setup().exec()).parent().memregion(name.c_str());
if (m_dev.has_running_machine())
{
- memory_region *mem = m_dev.memregion(name.c_str());
+ memory_region *mem = m_dev.memregion(putf8string(name).c_str());
if (mem != nullptr)
{
- auto ret(plib::make_unique<std::istringstream>(std::string(reinterpret_cast<char *>(mem->base()), mem->bytes()), std::ios_base::binary));
+ plib::istream_uptr ret(std::make_unique<std::istringstream>(std::string(reinterpret_cast<char *>(mem->base()), mem->bytes()), std::ios_base::binary), name);
ret->imbue(std::locale::classic());
return ret;
}
else
- return plib::unique_ptr<std::istream>(nullptr);
+ return plib::istream_uptr();
}
else
{
/* validation */
if (rom_exists(m_dev.mconfig().root_device(), pstring(m_dev.tag()) + ":" + name))
{
- auto ret(plib::make_unique<std::istringstream>(std::ios_base::binary));
+ // Create an empty stream.
+ plib::istream_uptr ret(std::make_unique<std::istringstream>(std::ios_base::binary), name);
ret->imbue(std::locale::classic());
return ret;
}
else
- return plib::unique_ptr<std::istream>(nullptr);
+ return plib::istream_uptr();
}
}
} // anonymous namespace
-
-
-// ----------------------------------------------------------------------------------------
-// sound_out
-// ----------------------------------------------------------------------------------------
-
-class NETLIB_NAME(sound_out) : public netlist::device_t
-{
-public:
- NETLIB_NAME(sound_out)(netlist::netlist_state_t &anetlist, const pstring &name)
- : netlist::device_t(anetlist, name)
- , m_channel(*this, "CHAN", 0)
- , m_mult(*this, "MULT", 1000.0)
- , m_offset(*this, "OFFSET", 0.0)
- , m_buffer(nullptr)
- , m_bufsize(0)
- , m_sample_time(netlist::netlist_time::from_hz(1)) //sufficiently big enough
- , m_in(*this, "IN")
- , m_cur(0.0)
- , m_last_pos(0)
- , m_last_buffer_time(*this, "m_last_buffer", netlist::netlist_time::zero())
- {
- }
-
- //static const int BUFSIZE = 2048;
-
- ATTR_COLD void reset() override
- {
- m_cur = 0.0;
- m_last_pos = 0;
- m_last_buffer_time = netlist::netlist_time::zero();
- }
-
- ATTR_HOT void sound_update(const netlist::netlist_time &upto)
- {
- int pos = (upto - m_last_buffer_time) / m_sample_time;
- if (pos > m_bufsize)
- throw emu_fatalerror("sound %s: pos %d exceeded bufsize %d\n", name().c_str(), pos, m_bufsize);
- while (m_last_pos < pos )
- {
- m_buffer[m_last_pos++] = (stream_sample_t) m_cur;
- }
- }
-
- ATTR_HOT void sound_update_fill(int samples)
- {
- if (samples > m_bufsize)
- throw emu_fatalerror("sound %s: pos %d exceeded bufsize %d\n", name().c_str(), samples, m_bufsize);
- while (m_last_pos < samples )
- {
- m_buffer[m_last_pos++] = (stream_sample_t) m_cur;
- }
- }
-
- NETLIB_UPDATEI()
- {
- nl_double val = m_in() * m_mult() + m_offset();
- sound_update(exec().time());
- /* ignore spikes */
- if (std::abs(val) < 32767.0)
- m_cur = val;
- else if (val > 0.0)
- m_cur = 32767.0;
- else
- m_cur = -32767.0;
-
- }
-
-public:
- ATTR_HOT void buffer_reset(const netlist::netlist_time &upto)
- {
- m_last_pos = 0;
- m_last_buffer_time = upto;
- }
-
- netlist::param_int_t m_channel;
- netlist::param_double_t m_mult;
- netlist::param_double_t m_offset;
- stream_sample_t *m_buffer;
- int m_bufsize;
-
- netlist::netlist_time m_sample_time;
-
-private:
- netlist::analog_input_t m_in;
- double m_cur;
- int m_last_pos;
- netlist::state_var<netlist::netlist_time> m_last_buffer_time;
-};
-
// ----------------------------------------------------------------------------------------
// sound_in
// ----------------------------------------------------------------------------------------
-class NETLIB_NAME(sound_in) : public netlist::device_t
-{
-public:
-
- static const int MAX_INPUT_CHANNELS = 16;
-
- NETLIB_NAME(sound_in)(netlist::netlist_state_t &anetlist, const pstring &name)
- : netlist::device_t(anetlist, name)
- , m_inc(netlist::netlist_time::from_nsec(1))
- , m_feedback(*this, "FB") // clock part
- , m_Q(*this, "Q")
- , m_pos(0)
- , m_num_channels(0)
- {
- connect(m_feedback, m_Q);
-
- for (int i = 0; i < MAX_INPUT_CHANNELS; i++)
- {
- m_channels[i].m_param_name = netlist::pool().make_poolptr<netlist::param_str_t>(*this, plib::pfmt("CHAN{1}")(i), "");
- m_channels[i].m_param_mult = netlist::pool().make_poolptr<netlist::param_double_t>(*this, plib::pfmt("MULT{1}")(i), 1.0);
- m_channels[i].m_param_offset = netlist::pool().make_poolptr<netlist::param_double_t>(*this, plib::pfmt("OFFSET{1}")(i), 0.0);
- }
- }
-
- ATTR_COLD void reset() override
- {
- m_pos = 0;
- for (auto & elem : m_channels)
- elem.m_buffer = nullptr;
- }
-
- ATTR_COLD void resolve()
- {
- m_pos = 0;
- for (int i = 0; i < MAX_INPUT_CHANNELS; i++)
- {
- if ((*m_channels[i].m_param_name)() != pstring(""))
- {
- if (i != m_num_channels)
- state().log().fatal("sound input numbering has to be sequential!");
- m_num_channels++;
- m_channels[i].m_param = dynamic_cast<netlist::param_double_t *>(setup().find_param((*m_channels[i].m_param_name)(), true));
- }
- }
- }
-
- NETLIB_UPDATEI()
- {
- for (int i=0; i<m_num_channels; i++)
- {
- if (m_channels[i].m_buffer == nullptr)
- break; // stop, called outside of stream_update
- const nl_double v = m_channels[i].m_buffer[m_pos];
- m_channels[i].m_param->setTo(v * (*m_channels[i].m_param_mult)() + (*m_channels[i].m_param_offset)());
- }
- m_pos++;
- m_Q.net().toggle_and_push_to_queue(m_inc);
- }
+using sound_in_type = netlist::interface::NETLIB_NAME(buffered_param_setter)<netlist_mame_sound_input_buffer>;
+class NETLIB_NAME(sound_in) : public sound_in_type
+{
public:
- ATTR_HOT void buffer_reset()
- {
- m_pos = 0;
- }
-
- struct channel
- {
- netlist::pool_owned_ptr<netlist::param_str_t> m_param_name;
- netlist::param_double_t *m_param;
- stream_sample_t *m_buffer;
- netlist::pool_owned_ptr<netlist::param_double_t> m_param_mult;
- netlist::pool_owned_ptr<netlist::param_double_t> m_param_offset;
- };
- channel m_channels[MAX_INPUT_CHANNELS];
- netlist::netlist_time m_inc;
-
- int num_channels() { return m_num_channels; }
-
-private:
- netlist::logic_input_t m_feedback;
- netlist::logic_output_t m_Q;
-
- int m_pos;
- int m_num_channels;
+ using base_type = sound_in_type;
+ using base_type::base_type;
};
-
-// netlib #defines this and it fights with logmacro.h
-#undef LOG
-
-#define LOG_GENERAL (1U << 0)
-#define LOG_DEV_CALLS (1U << 1)
-
-//#define VERBOSE (LOG_GENERAL | LOG_DEV_CALLS)
-//#define LOG_OUTPUT_FUNC printf
-#include "logmacro.h"
-
-#define LOGDEVCALLS(...) LOGMASKED(LOG_DEV_CALLS, __VA_ARGS__)
-
-
netlist::setup_t &netlist_mame_device::setup()
{
if (!m_netlist)
throw device_missing_dependencies();
- return m_netlist->nlstate().setup();
+ return m_netlist->setup();
}
-void netlist_mame_device::register_memregion_source(netlist::nlparse_t &setup, device_t &dev, const char *name)
+void netlist_mame_device::register_memregion_source(netlist::nlparse_t &parser, device_t &dev, const char *name)
{
- setup.register_source(plib::make_unique<netlist_source_memregion_t>(dev, pstring(name)));
+ parser.register_source<netlist_source_memregion_t>(dev, pstring(name));
}
void netlist_mame_analog_input_device::write(const double val)
{
- m_value_for_device_timer = val * m_mult + m_offset;
- if (m_value_for_device_timer != (*m_param)())
- synchronize(0, 0, &m_value_for_device_timer);
+ m_value_to_sync = val * m_mult + m_offset;
+ if (m_value_to_sync != (*m_param)())
+ {
+ machine().scheduler().synchronize(timer_expired_delegate(FUNC(netlist_mame_analog_input_device::sync_callback), this));
+ }
}
-void netlist_mame_analog_input_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(netlist_mame_analog_input_device::sync_callback)
{
update_to_current_time();
- m_param->setTo(*((double *) ptr));
+ nl_owner().log_csv().log_add(m_param_name, m_value_to_sync, true);
+ m_param->set(m_value_to_sync);
}
void netlist_mame_int_input_device::write(const uint32_t val)
{
const uint32_t v = (val >> m_shift) & m_mask;
if (v != (*m_param)())
- synchronize(0, v);
+ {
+ LOGDEBUG("write %s\n", this->tag());
+ machine().scheduler().synchronize(timer_expired_delegate(FUNC(netlist_mame_int_input_device::sync_callback), this), v);
+}
}
void netlist_mame_logic_input_device::write(const uint32_t val)
{
const uint32_t v = (val >> m_shift) & 1;
if (v != (*m_param)())
- synchronize(0, v);
+ {
+ LOGDEBUG("write %s\n", this->tag());
+ machine().scheduler().synchronize(timer_expired_delegate(FUNC(netlist_mame_logic_input_device::sync_callback), this), v);
+ }
}
-void netlist_mame_int_input_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(netlist_mame_int_input_device::sync_callback)
{
update_to_current_time();
- m_param->setTo(param);
+ nl_owner().log_csv().log_add(m_param_name, param, false);
+ m_param->set(param);
}
-void netlist_mame_logic_input_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(netlist_mame_logic_input_device::sync_callback)
{
update_to_current_time();
- m_param->setTo(param);
+ nl_owner().log_csv().log_add(m_param_name, param, false);
+ m_param->set(param);
}
-void netlist_mame_ram_pointer_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(netlist_mame_ram_pointer_device::sync_callback)
{
m_data = (*m_param)();
}
@@ -659,12 +420,14 @@ void netlist_mame_sub_interface::set_mult_offset(const double mult, const double
m_offset = offset;
}
+
netlist_mame_analog_input_device::netlist_mame_analog_input_device(const machine_config &mconfig, const char *tag, device_t *owner, const char *param_name)
: device_t(mconfig, NETLIST_ANALOG_INPUT, tag, owner, 0)
, netlist_mame_sub_interface(*owner)
, m_param(nullptr)
, m_auto_port(true)
, m_param_name(param_name)
+ , m_value_to_sync(0)
{
}
@@ -674,14 +437,16 @@ netlist_mame_analog_input_device::netlist_mame_analog_input_device(const machine
, m_param(nullptr)
, m_auto_port(true)
, m_param_name("")
+ , m_value_to_sync(0)
{
}
void netlist_mame_analog_input_device::device_start()
{
LOGDEVCALLS("start\n");
- netlist::param_t *p = this->nl_owner().setup().find_param(pstring(m_param_name));
- m_param = dynamic_cast<netlist::param_double_t *>(p);
+ netlist::param_ref_t p = this->nl_owner().setup().find_param(pstring(m_param_name));
+ // FIXME: m_param should be param_ref_t
+ m_param = dynamic_cast<netlist::param_fp_t *>(&p.param());
if (m_param == nullptr)
{
fatalerror("device %s wrong parameter type for %s\n", basetag(), m_param_name);
@@ -696,8 +461,8 @@ void netlist_mame_analog_input_device::device_start()
void netlist_mame_analog_input_device::validity_helper(validity_checker &valid,
netlist::netlist_state_t &nlstate) const
{
- netlist::param_t *p = nlstate.setup().find_param(pstring(m_param_name));
- auto *param = dynamic_cast<netlist::param_double_t *>(p);
+ netlist::param_ref_t p = nlstate.setup().find_param(pstring(m_param_name));
+ auto *param = dynamic_cast<netlist::param_fp_t *>(&p.param());
if (param == nullptr)
{
osd_printf_warning("device %s wrong parameter type for %s\n", basetag(), m_param_name);
@@ -712,24 +477,42 @@ netlist_mame_analog_output_device::netlist_mame_analog_output_device(const machi
: device_t(mconfig, NETLIST_ANALOG_OUTPUT, tag, owner, clock)
, netlist_mame_sub_interface(*owner)
, m_in("")
+ , m_delegate(*this)
{
}
-void netlist_mame_analog_output_device::custom_netlist_additions(netlist::netlist_state_t &nlstate)
+
+
+void netlist_mame_analog_output_device::custom_netlist_additions(netlist::nlparse_t &parser)
{
+ /* ignore if no running machine -> called within device_validity_check context */
+ if (owner()->has_running_machine())
+ m_delegate.resolve();
+
const pstring pin(m_in);
pstring dname = pstring("OUT_") + pin;
- pstring dfqn = nlstate.setup().build_fqn(dname);
- /* 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());
+ parser.register_dev(dname, dname);
+ parser.register_connection(dname + ".IN", pin);
+}
- 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));
- dev->register_callback(std::move(m_delegate));
- nlstate.add_dev(dfqn, std::move(dev));
- nlstate.setup().register_link(dname + ".IN", pin);
+void netlist_mame_analog_output_device::pre_parse_action(netlist::nlparse_t &parser)
+{
+ const pstring pin(m_in);
+ pstring dname = pstring("OUT_") + pin;
+
+ const auto lambda = [this](auto &in, netlist::nl_fptype val)
+ {
+ this->cpu()->update_icount(in.exec().time());
+ this->m_delegate(val, this->cpu()->local_time());
+ this->cpu()->check_mame_abort_slice();
+ };
+
+ using lb_t = decltype(lambda);
+ using cb_t = netlist::interface::NETLIB_NAME(analog_callback)<lb_t>;
+
+ parser.factory().add<cb_t, netlist::nl_fptype, lb_t>(dname,
+ netlist::factory::properties("-", PSOURCELOC()), 1e-6, std::forward<lb_t>(lambda));
}
void netlist_mame_analog_output_device::device_start()
@@ -746,31 +529,43 @@ netlist_mame_logic_output_device::netlist_mame_logic_output_device(const machine
: device_t(mconfig, NETLIST_LOGIC_OUTPUT, tag, owner, clock)
, netlist_mame_sub_interface(*owner)
, m_in("")
+ , m_delegate(*this)
{
}
-void netlist_mame_logic_output_device::set_params(const char *in_name, output_delegate &&adelegate)
+void netlist_mame_logic_output_device::custom_netlist_additions(netlist::nlparse_t &parser)
{
- m_in = in_name;
- m_delegate = std::move(adelegate);
+ /* ignore if no running machine -> called within device_validity_check context */
+ if (owner()->has_running_machine())
+ m_delegate.resolve();
+
+ const pstring pin(m_in);
+ pstring dname = pstring("OUT_") + pin;
+
+ parser.register_dev(dname, dname);
+ parser.register_connection(dname + ".IN", pin);
}
-void netlist_mame_logic_output_device::custom_netlist_additions(netlist::netlist_state_t &nlstate)
+void netlist_mame_logic_output_device::pre_parse_action(netlist::nlparse_t &parser)
{
- pstring pin(m_in);
- pstring dname = "OUT_" + pin;
- pstring dfqn = nlstate.setup().build_fqn(dname);
+ const pstring pin(m_in);
+ pstring dname = pstring("OUT_") + pin;
- /* 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());
+ const auto lambda = [this](auto &in, netlist::netlist_sig_t val)
+ {
+ this->cpu()->update_icount(in.exec().time());
+ this->m_delegate(val, this->cpu()->local_time());
+ this->cpu()->check_mame_abort_slice();
+ };
+
+ using lb_t = decltype(lambda);
+ using cb_t = netlist::interface::NETLIB_NAME(logic_callback)<lb_t>;
- auto dev = netlist::pool().make_poolptr<NETLIB_NAME(logic_callback)>(nlstate, dfqn);
- dev->register_callback(std::move(m_delegate));
- nlstate.add_dev(dfqn, std::move(dev));
- nlstate.setup().register_link(dname + ".IN", pin);
+ parser.factory().add<cb_t, lb_t>(dname,
+ netlist::factory::properties("-", PSOURCELOC()), std::forward<lb_t>(lambda));
}
+
void netlist_mame_logic_output_device::device_start()
{
LOGDEVCALLS("start\n");
@@ -793,7 +588,7 @@ netlist_mame_int_input_device::netlist_mame_int_input_device(const machine_confi
void netlist_mame_int_input_device::set_params(const char *param_name, const uint32_t mask, const uint32_t shift)
{
- if (LOG_DEV_CALLS) logerror("set_params\n");
+ LOGDEVCALLS("set_params\n");
m_param_name = param_name;
m_shift = shift;
m_mask = mask;
@@ -802,8 +597,8 @@ void netlist_mame_int_input_device::set_params(const char *param_name, const uin
void netlist_mame_int_input_device::device_start()
{
LOGDEVCALLS("start\n");
- netlist::param_t *p = downcast<netlist_mame_device *>(this->owner())->setup().find_param(pstring(m_param_name));
- m_param = dynamic_cast<netlist::param_int_t *>(p);
+ netlist::param_ref_t p = downcast<netlist_mame_device *>(this->owner())->setup().find_param(pstring(m_param_name));
+ m_param = dynamic_cast<netlist::param_int_t *>(&p.param());
if (m_param == nullptr)
{
fatalerror("device %s wrong parameter type for %s\n", basetag(), m_param_name);
@@ -813,8 +608,8 @@ void netlist_mame_int_input_device::device_start()
void netlist_mame_int_input_device::validity_helper(validity_checker &valid,
netlist::netlist_state_t &nlstate) const
{
- netlist::param_t *p = nlstate.setup().find_param(pstring(m_param_name));
- auto *param = dynamic_cast<netlist::param_int_t *>(p);
+ netlist::param_ref_t p = nlstate.setup().find_param(pstring(m_param_name));
+ auto *param = dynamic_cast<netlist::param_int_t *>(&p.param());
if (param == nullptr)
{
osd_printf_warning("device %s wrong parameter type for %s\n", basetag(), m_param_name);
@@ -836,7 +631,7 @@ netlist_mame_logic_input_device::netlist_mame_logic_input_device(const machine_c
void netlist_mame_logic_input_device::set_params(const char *param_name, const uint32_t shift)
{
- if (LOG_DEV_CALLS) logerror("set_params\n");
+ LOGDEVCALLS("set_params\n");
m_param_name = param_name;
m_shift = shift;
}
@@ -844,8 +639,8 @@ void netlist_mame_logic_input_device::set_params(const char *param_name, const u
void netlist_mame_logic_input_device::device_start()
{
LOGDEVCALLS("start\n");
- netlist::param_t *p = downcast<netlist_mame_device *>(this->owner())->setup().find_param(pstring(m_param_name));
- m_param = dynamic_cast<netlist::param_logic_t *>(p);
+ netlist::param_ref_t p = downcast<netlist_mame_device *>(this->owner())->setup().find_param(pstring(m_param_name));
+ m_param = dynamic_cast<netlist::param_logic_t *>(&p.param());
if (m_param == nullptr)
{
fatalerror("device %s wrong parameter type for %s\n", basetag(), m_param_name);
@@ -855,8 +650,8 @@ void netlist_mame_logic_input_device::device_start()
void netlist_mame_logic_input_device::validity_helper(validity_checker &valid,
netlist::netlist_state_t &nlstate) const
{
- netlist::param_t *p = nlstate.setup().find_param(pstring(m_param_name));
- auto *param = dynamic_cast<netlist::param_logic_t *>(p);
+ netlist::param_ref_t p = nlstate.setup().find_param(pstring(m_param_name));
+ auto *param = dynamic_cast<netlist::param_logic_t *>(&p.param());
if (param == nullptr)
{
osd_printf_warning("device %s wrong parameter type for %s\n", basetag(), m_param_name);
@@ -888,15 +683,15 @@ netlist_mame_ram_pointer_device::netlist_mame_ram_pointer_device(const machine_c
void netlist_mame_ram_pointer_device::set_params(const char *param_name)
{
- if (LOG_DEV_CALLS) logerror("set_params\n");
+ LOGDEVCALLS("set_params\n");
m_param_name = param_name;
}
void netlist_mame_ram_pointer_device::device_start()
{
LOGDEVCALLS("start\n");
- netlist::param_t *p = downcast<netlist_mame_device *>(this->owner())->setup().find_param(pstring(m_param_name));
- m_param = dynamic_cast<netlist::param_ptr_t *>(p);
+ netlist::param_ref_t p = downcast<netlist_mame_device *>(this->owner())->setup().find_param(pstring(m_param_name));
+ m_param = dynamic_cast<netlist::param_ptr_t *>(&p.param());
if (m_param == nullptr)
{
fatalerror("device %s wrong parameter type for %s\n", basetag(), m_param_name);
@@ -908,8 +703,8 @@ void netlist_mame_ram_pointer_device::device_start()
void netlist_mame_ram_pointer_device::validity_helper(validity_checker &valid,
netlist::netlist_state_t &nlstate) const
{
- netlist::param_t *p = nlstate.setup().find_param(pstring(m_param_name));
- auto *param = dynamic_cast<netlist::param_ptr_t *>(p);
+ netlist::param_ref_t p = nlstate.setup().find_param(pstring(m_param_name));
+ auto *param = dynamic_cast<netlist::param_ptr_t *>(&p.param());
if (param == nullptr)
{
osd_printf_warning("device %s wrong parameter type for %s\n", basetag(), m_param_name);
@@ -939,19 +734,18 @@ void netlist_mame_stream_input_device::device_start()
LOGDEVCALLS("start\n");
}
-void netlist_mame_stream_input_device::custom_netlist_additions(netlist::netlist_state_t &nlstate)
+void netlist_mame_stream_input_device::custom_netlist_additions(netlist::nlparse_t &parser)
{
- if (!nlstate.setup().device_exists("STREAM_INPUT"))
- nlstate.setup().register_dev("NETDEV_SOUND_IN", "STREAM_INPUT");
+ pstring name = plib::pfmt("STREAM_INPUT_{}")(m_channel);
+ parser.register_dev("NETDEV_SOUND_IN", name);
- pstring sparam = plib::pfmt("STREAM_INPUT.CHAN{1}")(m_channel);
- nlstate.setup().register_param(sparam, pstring(m_param_name));
- sparam = plib::pfmt("STREAM_INPUT.MULT{1}")(m_channel);
- nlstate.setup().register_param(sparam, m_mult);
- sparam = plib::pfmt("STREAM_INPUT.OFFSET{1}")(m_channel);
- nlstate.setup().register_param(sparam, m_offset);
+ parser.register_param(name + ".CHAN", pstring(m_param_name));
+ parser.register_param(name + ".MULT", m_mult);
+ parser.register_param(name + ".OFFSET", m_offset);
+ parser.register_param(name + ".ID", m_channel);
}
+
// ----------------------------------------------------------------------------------------
// netlist_mame_stream_output_device
// ----------------------------------------------------------------------------------------
@@ -961,6 +755,9 @@ netlist_mame_stream_output_device::netlist_mame_stream_output_device(const machi
, netlist_mame_sub_interface(*owner)
, m_channel(0)
, m_out_name("")
+ , m_cur(0.0)
+ , m_sample_time(netlist::netlist_time::from_hz(1))
+ , m_last_buffer_time(netlist::netlist_time_ext::zero())
{
}
@@ -968,25 +765,108 @@ void netlist_mame_stream_output_device::set_params(int channel, const char *out_
{
m_out_name = out_name;
m_channel = channel;
+ sound()->register_stream_output(channel, this);
}
+/// \brief save state helper for plib classes supporting the save_state interface
+///
+struct save_helper
+{
+ save_helper(device_t *dev, const std::string &prefix)
+ : m_device(dev), m_prefix(prefix)
+ {}
+
+ template<typename T, typename X = void *>
+ void save_item(T &&item, const std::string &name, X = nullptr)
+ {
+ m_device->save_item(item, (m_prefix + "_" + name).c_str());
+ }
+
+ template <typename X = void *>
+ std::enable_if_t<plib::compile_info::has_int128::value && std::is_pointer<X>::value, void>
+ save_item(INT128 &item, const std::string &name, X = nullptr)
+ {
+ auto *p = reinterpret_cast<std::uint64_t *>(&item);
+ m_device->save_item(p[0], (m_prefix + "_" + name + "_1").c_str());
+ m_device->save_item(p[1], (m_prefix + "_" + name + "_2").c_str());
+ }
+
+private:
+ device_t *m_device;
+ std::string m_prefix;
+};
+
void netlist_mame_stream_output_device::device_start()
{
- LOGDEVCALLS("start\n");
+ LOGDEVCALLS("start %s\n", name());
+ m_cur = 0.0;
+ m_last_buffer_time = netlist::netlist_time_ext::zero();
+
+ save_item(NAME(m_cur));
+ m_sample_time.save_state(save_helper(this, "m_sample_time"));
+ m_last_buffer_time.save_state(save_helper(this, "m_last_buffer_time"));
+}
+
+void netlist_mame_stream_output_device::device_reset()
+{
+ LOGDEVCALLS("reset %s\n", name());
+}
+
+void netlist_mame_stream_output_device::sound_update_fill(sound_stream &stream, int output)
+{
+ int samples = m_buffer.size();
+ if (stream.samples() < samples)
+ {
+ osd_printf_warning("sound %s: samples %d less bufsize %d\n", name(), stream.samples(), samples);
+ samples = stream.samples();
+ }
+
+ int sampindex;
+ for (sampindex = 0; sampindex < samples; sampindex++)
+ stream.put(output, sampindex, m_buffer[sampindex]);
+ if (sampindex < stream.samples())
+ stream.fill(output, m_cur, sampindex);
+}
+
+
+void netlist_mame_stream_output_device::pre_parse_action(netlist::nlparse_t &parser)
+{
+ pstring dname = plib::pfmt("STREAM_OUT_{1}")(m_channel);
+
+ const auto lambda = [this](auto &in, netlist::nl_fptype val)
+ {
+ this->process(in.exec().time(), val);
+ };
+
+ using lb_t = decltype(lambda);
+ using cb_t = netlist::interface::NETLIB_NAME(analog_callback)<lb_t>;
+
+ parser.factory().add<cb_t, netlist::nl_fptype, lb_t>(dname,
+ netlist::factory::properties("-", PSOURCELOC()), 1e-9, std::forward<lb_t>(lambda));
+}
+
+
+void netlist_mame_stream_output_device::custom_netlist_additions(netlist::nlparse_t &parser)
+{
+ pstring dname = plib::pfmt("STREAM_OUT_{1}")(m_channel);
+
+ parser.register_dev(dname, dname);
+ parser.register_connection(dname + ".IN", pstring(m_out_name));
}
-void netlist_mame_stream_output_device::custom_netlist_additions(netlist::netlist_state_t &nlstate)
+void netlist_mame_stream_output_device::process(netlist::netlist_time_ext tim, netlist::nl_fptype val)
{
- //NETLIB_NAME(sound_out) *snd_out;
- pstring sname = plib::pfmt("STREAM_OUT_{1}")(m_channel);
+ val = val * m_mult + m_offset;
- //snd_out = dynamic_cast<NETLIB_NAME(sound_out) *>(setup.register_dev("nld_sound_out", sname));
- nlstate.setup().register_dev("NETDEV_SOUND_OUT", sname);
+ int pos = (tim - m_last_buffer_time) / m_sample_time;
+ //if (pos > m_bufsize)
+ // throw emu_fatalerror("sound %s: pos %d exceeded bufsize %d\n", name().c_str(), pos, m_bufsize);
+ while (m_buffer.size() < pos)
+ {
+ m_buffer.push_back(static_cast<sound_stream::sample_t>(m_cur));
+ }
- nlstate.setup().register_param(sname + ".CHAN" , m_channel);
- nlstate.setup().register_param(sname + ".MULT", m_mult);
- nlstate.setup().register_param(sname + ".OFFSET", m_offset);
- nlstate.setup().register_link(sname + ".IN", pstring(m_out_name));
+ m_cur = val;
}
@@ -1001,9 +881,8 @@ netlist_mame_device::netlist_mame_device(const machine_config &mconfig, const ch
netlist_mame_device::netlist_mame_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, type, tag, owner, clock)
- , m_icount(0)
- , m_old(netlist::netlist_time::zero())
, m_setup_func(nullptr)
+ , m_device_reset_called(false)
{
}
@@ -1018,25 +897,25 @@ void netlist_mame_device::device_config_complete()
}
-void netlist_mame_device::common_dev_start(netlist::netlist_t *lnetlist) const
+void netlist_mame_device::common_dev_start(netlist::netlist_state_t *lnetlist) const
{
- auto &lsetup = lnetlist->nlstate().setup();
+ auto &lsetup = lnetlist->setup();
// Override log statistics
pstring p = plib::util::environment("NL_STATS", "");
if (p != "")
{
bool err=false;
- bool v = plib::pstonum_ne<bool, true>(p, err);
+ bool v = plib::pstonum_ne<bool>(p, err);
if (err)
lsetup.log().warning("NL_STATS: invalid value {1}", p);
else
- lnetlist->enable_stats(v);
+ lnetlist->exec().enable_stats(v);
}
// register additional devices
- nl_register_devices(lsetup);
+ nl_register_devices(lsetup.parser());
/* let sub-devices add sources and do stuff prior to parsing */
for (device_t &d : subdevices())
@@ -1045,40 +924,71 @@ void netlist_mame_device::common_dev_start(netlist::netlist_t *lnetlist) const
if( sdev != nullptr )
{
LOGDEVCALLS("Preparse subdevice %s/%s\n", d.name(), d.shortname());
- sdev->pre_parse_action(lnetlist->nlstate());
+ sdev->pre_parse_action(lsetup.parser());
}
}
- /* 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));
+ // add default data provider for roms - if not in validity check
+ lsetup.parser().register_source<netlist_data_memregions_t>(*this);
- m_setup_func(lsetup);
+ // Read the netlist
+ m_setup_func(lsetup.parser());
-#if 1
- /* let sub-devices tweak the netlist */
+ // let sub-devices tweak the netlist
for (device_t &d : subdevices())
{
netlist_mame_sub_interface *sdev = dynamic_cast<netlist_mame_sub_interface *>(&d);
if( sdev != nullptr )
{
LOGDEVCALLS("Found subdevice %s/%s\n", d.name(), d.shortname());
- sdev->custom_netlist_additions(lnetlist->nlstate());
+ sdev->custom_netlist_additions(lsetup.parser());
}
}
- lsetup.prepare_to_run();
-#endif
}
-plib::unique_ptr<netlist::netlist_t> netlist_mame_device::base_validity_check(validity_checker &valid) const
+struct validity_logger
+{
+ void log(plib::plog_level l, const pstring &ls)
+ {
+ putf8string ls8(ls);
+
+ switch (l)
+ {
+ case plib::plog_level::DEBUG:
+ break;
+ case plib::plog_level::VERBOSE:
+ break;
+ case plib::plog_level::INFO:
+ osd_printf_verbose("netlist INFO: %s\n", ls8);
+ break;
+ case plib::plog_level::WARNING:
+ osd_printf_warning("netlist WARNING: %s\n", ls8);
+ break;
+ case plib::plog_level::ERROR:
+ osd_printf_error("netlist ERROR: %s\n", ls8);
+ break;
+ case plib::plog_level::FATAL:
+ osd_printf_error("netlist FATAL: %s\n", ls8);
+ break;
+ }
+ }
+};
+
+std::unique_ptr<netlist::netlist_state_t> netlist_mame_device::base_validity_check(validity_checker &valid) const
{
try
{
- //netlist_mame_t lnetlist(*this, "netlist", plib::make_unique<netlist_validate_callbacks_t>());
- auto lnetlist = plib::make_unique<netlist::netlist_t>("netlist", plib::make_unique<netlist_validate_callbacks_t>());
+ validity_logger logger;
+ plib::chrono::timer<plib::chrono::system_ticks> t;
+ t.start();
+ auto lnetlist = std::make_unique<netlist::netlist_state_t>("netlist",
+ plib::plog_delegate(&validity_logger::log, &logger));
// enable validation mode
- lnetlist->nlstate().setup().enable_validation();
+
+ lnetlist->set_static_solver_lib(std::make_unique<plib::static_library>(nullptr));
+
common_dev_start(lnetlist.get());
+ lnetlist->setup().prepare_to_run();
for (device_t &d : subdevices())
{
@@ -1086,149 +996,172 @@ plib::unique_ptr<netlist::netlist_t> netlist_mame_device::base_validity_check(va
if( sdev != nullptr )
{
LOGDEVCALLS("Validity check on subdevice %s/%s\n", d.name(), d.shortname());
- sdev->validity_helper(valid, lnetlist->nlstate());
+ sdev->validity_helper(valid, *lnetlist);
}
}
+ t.stop();
+ //printf("time %s %f\n", this->mconfig().gamedrv().name, t.as_seconds<double>());
return lnetlist;
}
catch (memregion_not_set &err)
{
+ // Do not report an error. Validity check has no access to ROM area.
osd_printf_verbose("%s\n", err.what());
}
catch (emu_fatalerror &err)
{
- osd_printf_error("%s\n", err.string());
+ osd_printf_error("%s\n", err.what());
}
catch (std::exception &err)
{
osd_printf_error("%s\n", err.what());
}
- return plib::unique_ptr<netlist::netlist_t>(nullptr);
+ return std::unique_ptr<netlist::netlist_state_t>(nullptr);
}
void netlist_mame_device::device_validity_check(validity_checker &valid) const
{
+
base_validity_check(valid);
//rom_exists(mconfig().root_device());
LOGDEVCALLS("device_validity_check %s\n", this->mconfig().gamedrv().name);
}
-void netlist_mame_device::device_start()
+void netlist_mame_device::device_start_common()
{
- LOGDEVCALLS("device_start entry\n");
+ m_netlist = std::make_unique<netlist_mame_t>(*this, "netlist");
+
+ m_netlist->set_static_solver_lib(std::make_unique<plib::static_library>(nl_static_solver_syms));
- m_netlist = netlist::pool().make_poolptr<netlist_mame_t>(*this, "netlist");
if (!machine().options().verbose())
{
- m_netlist->nlstate().log().verbose.set_enabled(false);
- m_netlist->nlstate().log().debug.set_enabled(false);
+ m_netlist->log().verbose.set_enabled(false);
+ m_netlist->log().debug.set_enabled(false);
}
common_dev_start(m_netlist.get());
+ m_netlist->setup().prepare_to_run();
- 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();
+ m_device_reset_called = false;
- m_old = netlist::netlist_time::zero();
- m_rem = netlist::netlist_time::zero();
+ std::string name = machine().system().name;
+ name += tag();
+ for (int index = 0; index < name.size(); index++)
+ if (name[index] == ':')
+ name[index] = '_';
+ name += ".csv";
+ log_csv().open(machine(), name);
LOGDEVCALLS("device_start exit\n");
}
-void netlist_mame_device::device_clock_changed()
+
+void netlist_mame_device::device_start()
{
- m_div = netlist::netlist_time::from_hz(clock());
- netlist().log().debug("Setting clock {1} and divisor {2}\n", clock(), m_div.as_double());
+ LOGDEVCALLS("device_start entry\n");
+
+ device_start_common();
+ save_state();
+
+ LOGDEVCALLS("device_start exit\n");
}
void netlist_mame_device::device_reset()
{
LOGDEVCALLS("device_reset\n");
- m_old = netlist::netlist_time::zero();
- m_rem = netlist::netlist_time::zero();
- netlist().reset();
+ if (!m_device_reset_called)
+ {
+ // netlists don't have a reset line, doing a soft-reset is pointless
+ // the only reason we call these here once after device_start
+ // is that netlist input devices may be started after the netlist device
+ // and because the startup code may trigger actions which need all
+ // devices set up.
+ netlist().free_setup_resources();
+ netlist().exec().reset();
+ m_device_reset_called = true;
+ }
}
void netlist_mame_device::device_stop()
{
LOGDEVCALLS("device_stop\n");
- netlist().stop();
+ if (m_netlist)
+ netlist().exec().stop();
+ log_csv().close();
}
-ATTR_COLD void netlist_mame_device::device_post_load()
+void netlist_mame_device::device_post_load()
{
LOGDEVCALLS("device_post_load\n");
netlist().run_state_manager().post_load();
- netlist().nlstate().rebuild_lists();
+ netlist().rebuild_lists();
}
-ATTR_COLD void netlist_mame_device::device_pre_save()
+void netlist_mame_device::device_pre_save()
{
LOGDEVCALLS("device_pre_save\n");
netlist().run_state_manager().pre_save();
}
-void netlist_mame_device::update_icount(netlist::netlist_time time)
+void netlist_mame_cpu_device::update_icount(netlist::netlist_time_ext time) noexcept
{
- const netlist::netlist_time newt(time);
- const netlist::netlist_time delta(newt - m_old + m_rem);
+ const netlist::netlist_time_ext delta = (time - m_old).shl(MDIV_SHIFT) + m_rem;
const uint64_t d = delta / m_div;
- m_old = newt;
- m_rem = delta - (m_div * d);
+ m_old = time;
+ m_rem = (delta - (m_div * d));
+ //printf("d %d m_rem %d\n", (int) d, (int) m_rem.as_raw());
m_icount -= d;
}
-void netlist_mame_device::check_mame_abort_slice()
+void netlist_mame_cpu_device::check_mame_abort_slice() noexcept
{
if (m_icount <= 0)
- netlist().abort_current_queue_slice();
+ netlist().exec().abort_current_queue_slice();
}
-ATTR_COLD void netlist_mame_device::save_state()
+void netlist_mame_device::save_state()
{
for (auto const & s : netlist().run_state_manager().save_list())
{
- netlist().log().debug("saving state for {1}\n", s->m_name.c_str());
- if (s->m_dt.is_float)
+ putf8string u8name(s->name());
+
+ netlist().log().debug("saving state for {1}\n", u8name.c_str());
+ if (s->dt().is_float())
{
- if (s->m_dt.size == sizeof(double))
- save_pointer((double *) s->m_ptr, s->m_name.c_str(), s->m_count);
- else if (s->m_dt.size == sizeof(float))
- save_pointer((float *) s->m_ptr, s->m_name.c_str(), s->m_count);
+ if (s->dt().size() == sizeof(double))
+ save_pointer((double *) s->ptr(), u8name.c_str(), s->count());
+ else if (s->dt().size() == sizeof(float))
+ save_pointer((float *) s->ptr(), u8name.c_str(), s->count());
else
- netlist().log().fatal("Unknown floating type for {1}\n", s->m_name.c_str());
+ netlist().log().fatal("Unknown floating type for {1}\n", u8name.c_str());
}
- else if (s->m_dt.is_integral)
+ else if (s->dt().is_integral())
{
- if (s->m_dt.size == sizeof(int64_t))
- save_pointer((int64_t *) s->m_ptr, s->m_name.c_str(), s->m_count);
- else if (s->m_dt.size == sizeof(int32_t))
- save_pointer((int32_t *) s->m_ptr, s->m_name.c_str(), s->m_count);
- else if (s->m_dt.size == sizeof(int16_t))
- save_pointer((int16_t *) s->m_ptr, s->m_name.c_str(), s->m_count);
- else if (s->m_dt.size == sizeof(int8_t))
- save_pointer((int8_t *) s->m_ptr, s->m_name.c_str(), s->m_count);
-#if (PHAS_INT128)
- else if (s->m_dt.size == sizeof(INT128))
- save_pointer((int64_t *) s->m_ptr, s->m_name.c_str(), s->m_count * 2);
-#endif
+ if (s->dt().size() == sizeof(int64_t))
+ save_pointer((int64_t *) s->ptr(), u8name.c_str(), s->count());
+ else if (s->dt().size() == sizeof(int32_t))
+ save_pointer((int32_t *) s->ptr(), u8name.c_str(), s->count());
+ else if (s->dt().size() == sizeof(int16_t))
+ save_pointer((int16_t *) s->ptr(), u8name.c_str(), s->count());
+ else if (s->dt().size() == sizeof(int8_t))
+ save_pointer((int8_t *) s->ptr(), u8name.c_str(), s->count());
+ else if (plib::compile_info::has_int128::value && s->dt().size() == sizeof(INT128))
+ save_pointer((int64_t *) s->ptr(), u8name.c_str(), s->count() * 2);
else
- netlist().log().fatal("Unknown integral type size {1} for {2}\n", s->m_dt.size, s->m_name.c_str());
+ netlist().log().fatal("Unknown integral type size {1} for {2}\n", s->dt().size(), u8name.c_str());
}
- else if (s->m_dt.is_custom)
+ else if (s->dt().is_custom())
{
/* do nothing */
}
else
- netlist().log().fatal("found unsupported save element {1}\n", s->m_name);
+ netlist().log().fatal("found unsupported save element {1}\n", u8name);
}
}
@@ -1243,6 +1176,8 @@ netlist_mame_cpu_device::netlist_mame_cpu_device(const machine_config &mconfig,
, device_disasm_interface(mconfig, *this)
, device_memory_interface(mconfig, *this)
, m_program_config("program", ENDIANNESS_LITTLE, 8, 12) // Interface is needed to keep debugger happy
+ , m_icount(0)
+ , m_old(netlist::netlist_time_ext::zero())
, m_genPC(0)
{
}
@@ -1250,48 +1185,83 @@ netlist_mame_cpu_device::netlist_mame_cpu_device(const machine_config &mconfig,
void netlist_mame_cpu_device::device_start()
{
- netlist_mame_device::device_start();
+ LOGDEVCALLS("device_start entry\n");
- // State support
+ device_start_common();
+ // FIXME: use save_helper
+ netlist().save(*this, m_rem, pstring(this->name()), "m_rem");
+ netlist().save(*this, m_div, pstring(this->name()), "m_div");
+ netlist().save(*this, m_old, pstring(this->name()), "m_old");
+
+ m_old = netlist::netlist_time_ext::zero();
+ m_rem = netlist::netlist_time_ext::zero();
+
+ save_state();
state_add(STATE_GENPC, "GENPC", m_genPC).noshow();
state_add(STATE_GENPCBASE, "CURPC", m_genPC).noshow();
int index = 0;
- for (auto &n : netlist().nlstate().nets())
+ for (auto &n : netlist().nets())
{
+ putf8string name(n->name()); //plib::replace_all(n->name(), ".", "_");
if (n->is_logic())
{
- state_add(index, n->name().c_str(), *(downcast<netlist::logic_net_t &>(*n).Q_state_ptr()));
+ auto nl = downcast<netlist::logic_net_t *>(n.get());
+ state_add<netlist::netlist_sig_t>(index++, name.c_str(),
+ [nl]() { return nl->Q(); },
+ [nl](netlist::netlist_sig_t data) { nl->set_Q_and_push(data, netlist::netlist_time::quantum()); });
}
else
{
- state_add(index, n->name().c_str(), *(downcast<netlist::analog_net_t &>(*n).Q_Analog_state_ptr()));
+ auto nl = downcast<netlist::analog_net_t *>(n.get());
+ state_add<double>(
+ index++,
+ name.c_str(),
+ [nl]() { return nl->Q_Analog(); },
+ [nl](double data) { nl->set_Q_Analog(data); });
}
- index++;
}
// set our instruction counter
set_icountptr(m_icount);
+
+ LOGDEVCALLS("device_start exit\n");
}
+void netlist_mame_cpu_device::device_clock_changed()
+{
+ m_div = static_cast<netlist::netlist_time_ext>(
+ (netlist::netlist_time_ext::resolution() << MDIV_SHIFT) / clock());
+ //printf("m_div %d\n", (int) m_div.as_raw());
+ netlist().log().debug("Setting clock {1} and divisor {2}\n", clock(), m_div.as_double());
+}
-void netlist_mame_cpu_device::nl_register_devices(netlist::setup_t &lsetup) const
+void netlist_mame_cpu_device::nl_register_devices(netlist::nlparse_t &parser) const
{
- 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
+uint64_t netlist_mame_cpu_device::execute_clocks_to_cycles(uint64_t clocks) const noexcept
{
return clocks;
}
-ATTR_COLD uint64_t netlist_mame_cpu_device::execute_cycles_to_clocks(uint64_t cycles) const
+uint64_t netlist_mame_cpu_device::execute_cycles_to_clocks(uint64_t cycles) const noexcept
{
return cycles;
}
-ATTR_HOT void netlist_mame_cpu_device::execute_run()
+netlist::netlist_time_ext netlist_mame_cpu_device::nltime_ext_from_clocks(unsigned c) const noexcept
+{
+ return (m_div * c).shr(MDIV_SHIFT);
+}
+
+netlist::netlist_time netlist_mame_cpu_device::nltime_from_clocks(unsigned c) const noexcept
+{
+ return static_cast<netlist::netlist_time>((m_div * c).shr(MDIV_SHIFT));
+}
+
+void netlist_mame_cpu_device::execute_run()
{
//m_ppc = m_pc; // copy PC to previous PC
if (debugger_enabled())
@@ -1301,14 +1271,14 @@ ATTR_HOT void netlist_mame_cpu_device::execute_run()
m_genPC++;
m_genPC &= 255;
debugger_instruction_hook(m_genPC);
- netlist().process_queue(m_div);
- update_icount(netlist().time());
+ netlist().exec().process_queue(nltime_ext_from_clocks(1));
+ update_icount(netlist().exec().time());
}
}
else
{
- netlist().process_queue(m_div * m_icount);
- update_icount(netlist().time());
+ netlist().exec().process_queue(nltime_ext_from_clocks(m_icount));
+ update_icount(netlist().exec().time());
}
}
@@ -1330,11 +1300,11 @@ offs_t netlist_disassembler::disassemble(std::ostream &stream, offs_t pc, const
{
unsigned startpc = pc;
int relpc = pc - m_dev->genPC();
- if (relpc >= 0 && relpc < m_dev->netlist().queue().size())
+ if (relpc >= 0 && relpc < m_dev->netlist().exec().queue().size())
{
- int dpc = m_dev->netlist().queue().size() - relpc - 1;
- util::stream_format(stream, "%c %s @%10.7f", (relpc == 0) ? '*' : ' ', m_dev->netlist().queue()[dpc].m_object->name().c_str(),
- m_dev->netlist().queue()[dpc].m_exec_time.as_double());
+ int dpc = m_dev->netlist().exec().queue().size() - relpc - 1;
+ util::stream_format(stream, "%c %s @%10.7f", (relpc == 0) ? '*' : ' ', m_dev->netlist().exec().queue()[dpc].object()->name().c_str(),
+ m_dev->netlist().exec().queue()[dpc].exec_time().as_double());
}
pc+=1;
@@ -1346,10 +1316,13 @@ offs_t netlist_disassembler::disassemble(std::ostream &stream, offs_t pc, const
// ----------------------------------------------------------------------------------------
netlist_mame_sound_device::netlist_mame_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : netlist_mame_device(mconfig, NETLIST_SOUND, tag, owner, clock)
+ : netlist_mame_device(mconfig, NETLIST_SOUND, tag, owner, 0)
, device_sound_interface(mconfig, *this)
- , m_in(nullptr)
, m_stream(nullptr)
+ , m_cur_time(attotime::zero)
+ , m_sound_clock(clock)
+ , m_attotime_per_clock(attotime::zero)
+ , m_last_update_to_current_time(attotime::zero)
{
}
@@ -1359,111 +1332,144 @@ void netlist_mame_sound_device::device_validity_check(validity_checker &valid) c
auto lnetlist = base_validity_check(valid);
if (lnetlist)
{
- /*Ok - do some more checks */
- std::vector<nld_sound_out *> outdevs = lnetlist->nlstate().get_device_list<nld_sound_out>();
- if (outdevs.size() == 0)
+ /* Ok - do some more checks */
+ if (m_out.size() == 0)
osd_printf_error("No output devices\n");
else
{
- for (auto &outdev : outdevs)
+ for (auto &outdev : m_out)
{
- int chan = outdev->m_channel();
- if (chan < 0 || chan >= outdevs.size())
- osd_printf_error("illegal channel number %d\n", chan);
+ if (outdev.first < 0 || outdev.first >= m_out.size())
+ osd_printf_error("illegal output channel number %d\n", outdev.first);
}
}
- std::vector<nld_sound_in *> indevs = lnetlist->nlstate().get_device_list<nld_sound_in>();
- if (indevs.size() > 1)
- osd_printf_error("A maximum of one input device is allowed but found %d!\n", (int)indevs.size());
+ std::vector<nld_sound_in *> indevs = lnetlist->get_device_list<nld_sound_in>();
+ for (auto &e : indevs)
+ {
+ if (e->id() >= indevs.size())
+ osd_printf_error("illegal input channel number %d\n", e->id());
+ }
}
-
}
-
void netlist_mame_sound_device::device_start()
{
- netlist_mame_device::device_start();
-
LOGDEVCALLS("sound device_start\n");
+ m_attotime_per_clock = attotime::from_hz(m_sound_clock);
+
+ save_item(NAME(m_cur_time));
+ save_item(NAME(m_attotime_per_clock));
+
+ device_start_common();
+ save_state();
+
+ m_cur_time = attotime::zero;
+
// Configure outputs
- std::vector<nld_sound_out *> outdevs = netlist().nlstate().get_device_list<nld_sound_out>();
- if (outdevs.size() == 0)
+ if (m_out.size() == 0)
fatalerror("No output devices");
- //m_num_outputs = outdevs.size();
-
/* resort channels */
- for (auto &outdev : outdevs)
+ for (auto &outdev : m_out)
{
- int chan = outdev->m_channel();
-
- netlist().log().verbose("Output %s on channel %d", outdev->name(), chan);
-
- if (chan < 0 || chan >= outdevs.size())
- fatalerror("illegal channel number");
- m_out[chan] = outdev;
- m_out[chan]->m_sample_time = netlist::netlist_time::from_hz(clock());
- m_out[chan]->m_buffer = nullptr;
- m_out[chan]->m_bufsize = 0;
+ if (outdev.first < 0 || outdev.first >= m_out.size())
+ fatalerror("illegal output channel number %d", outdev.first);
+ outdev.second->set_sample_time(netlist::netlist_time::from_hz(m_sound_clock));
+ outdev.second->buffer_reset(netlist::netlist_time_ext::zero());
}
// Configure inputs
- // FIXME: The limitation to one input device seems artificial.
- // We should allow multiple devices with one channel each.
- m_in = nullptr;
+ m_in.clear();
- std::vector<nld_sound_in *> indevs = netlist().nlstate().get_device_list<nld_sound_in>();
- if (indevs.size() > 1)
- fatalerror("A maximum of one input device is allowed!");
- if (indevs.size() == 1)
+ std::vector<nld_sound_in *> indevs = netlist().get_device_list<nld_sound_in>();
+ for (auto &e : indevs)
+ {
+ m_in.emplace(e->id(), e);
+ const auto sample_time = netlist::netlist_time::from_raw(static_cast<netlist::netlist_time::internal_type>(nltime_from_attotime(m_attotime_per_clock).as_raw()));
+ e->resolve_params(sample_time);
+ }
+ for (auto &e : m_in)
{
- m_in = indevs[0];
- m_in->resolve();
- m_in->m_inc = netlist::netlist_time::from_hz(clock());
+ if (e.first < 0 || e.first >= m_in.size())
+ fatalerror("illegal input channel number %d", e.first);
}
+ m_inbuffer.resize(m_in.size());
/* initialize the stream(s) */
- m_stream = machine().sound().stream_alloc(*this, m_in ? m_in->num_channels() : 0, m_out.size(), clock());
+ m_stream = stream_alloc(m_in.size(), m_out.size(), m_sound_clock);
+ LOGDEVCALLS("sound device_start exit\n");
}
-void netlist_mame_sound_device::nl_register_devices(netlist::setup_t &lsetup) const
+
+void netlist_mame_sound_device::nl_register_devices(netlist::nlparse_t &parser) const
{
- 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", "-");
+ //parser.factory().add<nld_sound_out>("NETDEV_SOUND_OUT",
+ // netlist::factory::properties("+CHAN", PSOURCELOC()));
+ parser.factory().add<nld_sound_in>("NETDEV_SOUND_IN",
+ netlist::factory::properties("-", PSOURCELOC()));
}
-void netlist_mame_sound_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples)
+void netlist_mame_sound_device::register_stream_output(int channel, netlist_mame_stream_output_device *so)
{
+ m_out[channel] = so;
+}
- for (auto &e : m_out)
+void netlist_mame_sound_device::update_to_current_time()
+{
+ LOGDEBUG("before update\n");
+
+ get_stream()->update();
+
+ if (machine().time() < m_last_update_to_current_time)
+ LOGTIMING("machine.time() decreased 2\n");
+
+ m_last_update_to_current_time = machine().time();
+
+ const auto mtime = nltime_from_attotime(machine().time());
+ const auto cur(netlist().exec().time());
+
+ if (mtime > cur)
{
- e.second->m_buffer = outputs[e.first];
- e.second->m_bufsize = samples;
+ //expected don't log
+ //LOGTIMING("%f us\n", (mtime - cur).as_double() * 1000000.0);
+ netlist().exec().process_queue(mtime - cur);
}
+ else if (mtime < cur)
+ LOGTIMING("%s : %f us before machine time\n", this->name(), (cur - mtime).as_double() * 1000000.0);
+}
-
- if (m_in)
+void netlist_mame_sound_device::sound_stream_update(sound_stream &stream)
+{
+ for (auto &e : m_in)
{
- m_in->buffer_reset();
- for (int i=0; i < m_in->num_channels(); i++)
- {
- m_in->m_channels[i].m_buffer = inputs[i];
- }
+ auto clock_period = stream.sample_period();
+ auto sample_time = netlist::netlist_time::from_raw(static_cast<netlist::netlist_time::internal_type>(nltime_from_attotime(clock_period).as_raw()));
+ m_inbuffer[e.first] = netlist_mame_sound_input_buffer(stream, e.first);
+ e.second->buffer_reset(sample_time, stream.samples(), &m_inbuffer[e.first]);
}
- netlist::netlist_time cur(netlist().time());
+ int samples = stream.samples();
+ LOGDEBUG("samples %d\n", samples);
- netlist().process_queue(m_div * samples);
+ // end_time() is the time at the END of the last sample we're generating
+ // however, the sample value is the value at the START of that last sample,
+ // so subtract one sample period so that we only process up to the minimum
+ auto nl_target_time = nltime_from_attotime(stream.end_time() - stream.sample_period());
- cur += (m_div * samples);
+ auto nltime(netlist().exec().time());
+ if (nltime < nl_target_time)
+ {
+ netlist().exec().process_queue(nl_target_time - nltime);
+ }
for (auto &e : m_out)
{
- e.second->sound_update_fill(samples);
- e.second->buffer_reset(cur);
+ e.second->sound_update_fill(stream, e.first);
+ e.second->buffer_reset(nl_target_time);
}
+
}