summaryrefslogtreecommitdiffstatshomepage
path: root/src/lib/netlist/nl_base.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/netlist/nl_base.cpp')
-rw-r--r--src/lib/netlist/nl_base.cpp1050
1 files changed, 1050 insertions, 0 deletions
diff --git a/src/lib/netlist/nl_base.cpp b/src/lib/netlist/nl_base.cpp
new file mode 100644
index 00000000000..ce818e0d94f
--- /dev/null
+++ b/src/lib/netlist/nl_base.cpp
@@ -0,0 +1,1050 @@
+// license:GPL-2.0+
+// copyright-holders:Couriersud
+/*
+ * nlbase.c
+ *
+ */
+
+#include <solver/nld_solver.h>
+#include <cstring>
+#include <algorithm>
+
+#include "plib/palloc.h"
+
+#include "nl_base.h"
+#include "devices/nld_system.h"
+#include "nl_util.h"
+
+const netlist::netlist_time netlist::netlist_time::zero = netlist::netlist_time::from_raw(0);
+
+namespace netlist
+{
+// ----------------------------------------------------------------------------------------
+// logic_family_ttl_t
+// ----------------------------------------------------------------------------------------
+
+class logic_family_ttl_t : public logic_family_desc_t
+{
+public:
+ logic_family_ttl_t() : logic_family_desc_t()
+ {
+ m_low_thresh_V = 0.8;
+ m_high_thresh_V = 2.0;
+ // m_low_V - these depend on sinked/sourced current. Values should be suitable for typical applications.
+ m_low_V = 0.1;
+ m_high_V = 4.0;
+ m_R_low = 1.0;
+ m_R_high = 130.0;
+ m_is_static = true;
+ }
+ virtual devices::nld_base_d_to_a_proxy *create_d_a_proxy(logic_output_t *proxied) const
+ {
+ return palloc(devices::nld_d_to_a_proxy(proxied));
+ }
+};
+
+//FIXME: set to proper values
+class logic_family_cd4xxx_t : public logic_family_desc_t
+{
+public:
+ logic_family_cd4xxx_t() : logic_family_desc_t()
+ {
+ m_low_thresh_V = 0.8;
+ m_high_thresh_V = 2.0;
+ // m_low_V - these depend on sinked/sourced current. Values should be suitable for typical applications.
+ m_low_V = 0.05;
+ m_high_V = 4.95;
+ m_R_low = 10.0;
+ m_R_high = 10.0;
+ m_is_static = true;
+ }
+ virtual devices::nld_base_d_to_a_proxy *create_d_a_proxy(logic_output_t *proxied) const
+ {
+ return palloc(devices::nld_d_to_a_proxy(proxied));
+ }
+};
+
+logic_family_desc_t *netlist_family_TTL = palloc(logic_family_ttl_t);
+logic_family_desc_t *netlist_family_CD4XXX = palloc(logic_family_cd4xxx_t);
+
+// ----------------------------------------------------------------------------------------
+// netlist_queue_t
+// ----------------------------------------------------------------------------------------
+
+queue_t::queue_t(netlist_t &nl)
+ : timed_queue<net_t *, netlist_time>(512)
+ , object_t(QUEUE, GENERIC)
+ , pstate_callback_t()
+ , m_qsize(0)
+ , m_times(512)
+ , m_names(512)
+{
+ this->init_object(nl, "QUEUE");
+}
+
+void queue_t::register_state(pstate_manager_t &manager, const pstring &module)
+{
+ netlist().log().debug("register_state\n");
+ manager.save_item(m_qsize, this, module + "." + "qsize");
+ manager.save_item(&m_times[0], this, module + "." + "times", m_times.size());
+ manager.save_item(&(m_names[0].m_buf[0]), this, module + "." + "names", m_names.size() * sizeof(names_t));
+}
+
+void queue_t::on_pre_save()
+{
+ netlist().log().debug("on_pre_save\n");
+ m_qsize = this->count();
+ netlist().log().debug("current time {1} qsize {2}\n", netlist().time().as_double(), m_qsize);
+ for (int i = 0; i < m_qsize; i++ )
+ {
+ m_times[i] = this->listptr()[i].exec_time().as_raw();
+ pstring p = this->listptr()[i].object()->name();
+ int n = p.len();
+ n = std::min(63, n);
+ std::strncpy(m_names[i].m_buf, p.cstr(), n);
+ m_names[i].m_buf[n] = 0;
+ }
+}
+
+
+void queue_t::on_post_load()
+{
+ this->clear();
+ netlist().log().debug("current time {1} qsize {2}\n", netlist().time().as_double(), m_qsize);
+ for (int i = 0; i < m_qsize; i++ )
+ {
+ net_t *n = netlist().find_net(m_names[i].m_buf);
+ //log().debug("Got {1} ==> {2}\n", qtemp[i].m_name, n));
+ //log().debug("schedule time {1} ({2})\n", n->time().as_double(), netlist_time::from_raw(m_times[i]).as_double()));
+ this->push(queue_t::entry_t(netlist_time::from_raw(m_times[i]), n));
+ }
+}
+
+// ----------------------------------------------------------------------------------------
+// netlist_object_t
+// ----------------------------------------------------------------------------------------
+
+ATTR_COLD object_t::object_t(const type_t atype, const family_t afamily)
+: m_objtype(atype)
+, m_family(afamily)
+, m_netlist(NULL)
+{}
+
+ATTR_COLD object_t::~object_t()
+{
+}
+
+ATTR_COLD void object_t::init_object(netlist_t &nl, const pstring &aname)
+{
+ m_netlist = &nl;
+ m_name = aname;
+ save_register();
+}
+
+ATTR_COLD const pstring &object_t::name() const
+{
+ if (m_name == "")
+ netlist().log().fatal("object not initialized");
+ return m_name;
+}
+
+// ----------------------------------------------------------------------------------------
+// netlist_owned_object_t
+// ----------------------------------------------------------------------------------------
+
+ATTR_COLD device_object_t::device_object_t(const type_t atype,
+ const family_t afamily)
+: object_t(atype, afamily)
+, m_device(NULL)
+{
+}
+
+ATTR_COLD void device_object_t::init_object(core_device_t &dev,
+ const pstring &aname)
+{
+ object_t::init_object(dev.netlist(), aname);
+ m_device = &dev;
+}
+
+// ----------------------------------------------------------------------------------------
+// netlist_base_t
+// ----------------------------------------------------------------------------------------
+
+netlist_t::netlist_t()
+ : object_t(NETLIST, GENERIC), pstate_manager_t(),
+ m_stop(netlist_time::zero),
+ m_time(netlist_time::zero),
+ m_use_deactivate(0),
+ m_queue(*this),
+ m_mainclock(NULL),
+ m_solver(NULL),
+ m_gnd(NULL),
+ m_setup(NULL),
+ m_log(this)
+{
+}
+
+netlist_t::~netlist_t()
+{
+ for (std::size_t i=0; i < m_nets.size(); i++)
+ {
+ if (!m_nets[i]->isRailNet())
+ {
+ pfree(m_nets[i]);
+ }
+ }
+
+ m_nets.clear();
+
+ m_devices.clear_and_free();
+
+ pstring::resetmem();
+}
+
+ATTR_COLD void netlist_t::save_register()
+{
+ save(static_cast<pstate_callback_t &>(m_queue), "m_queue");
+ save(NLNAME(m_time));
+ object_t::save_register();
+}
+
+ATTR_HOT nl_double netlist_t::gmin() const
+{
+ return solver()->gmin();
+}
+
+ATTR_COLD void netlist_t::start()
+{
+ /* find the main clock and solver ... */
+
+ log().debug("Searching for mainclock and solver ...\n");
+
+ m_mainclock = get_single_device<devices:: NETLIB_NAME(mainclock)>("mainclock");
+ m_solver = get_single_device<devices::NETLIB_NAME(solver)>("solver");
+ m_gnd = get_single_device<devices::NETLIB_NAME(gnd)>("gnd");
+ m_params = get_single_device<devices::NETLIB_NAME(netlistparams)>("parameter");
+
+ /* make sure the solver and parameters are started first! */
+
+ if (m_solver != NULL)
+ m_solver->start_dev();
+
+ if (m_params != NULL)
+ {
+ m_params->start_dev();
+ }
+
+ m_use_deactivate = (m_params->m_use_deactivate.Value() ? true : false);
+
+ log().debug("Initializing devices ...\n");
+ for (std::size_t i = 0; i < m_devices.size(); i++)
+ {
+ device_t *dev = m_devices[i];
+ if (dev != m_solver && dev != m_params)
+ dev->start_dev();
+ }
+
+}
+
+ATTR_COLD void netlist_t::stop()
+{
+ /* find the main clock and solver ... */
+
+ log().debug("Stopping all devices ...\n");
+
+ // Step all devices once !
+ for (std::size_t i = 0; i < m_devices.size(); i++)
+ {
+ m_devices[i]->stop_dev();
+ }
+}
+
+ATTR_COLD net_t *netlist_t::find_net(const pstring &name)
+{
+ for (std::size_t i = 0; i < m_nets.size(); i++)
+ {
+ if (m_nets[i]->name() == name)
+ return m_nets[i];
+ }
+ return NULL;
+}
+
+ATTR_COLD void netlist_t::rebuild_lists()
+{
+ for (std::size_t i = 0; i < m_nets.size(); i++)
+ m_nets[i]->rebuild_list();
+}
+
+
+ATTR_COLD void netlist_t::reset()
+{
+ m_time = netlist_time::zero;
+ m_queue.clear();
+ if (m_mainclock != NULL)
+ m_mainclock->m_Q.net().set_time(netlist_time::zero);
+ if (m_solver != NULL)
+ m_solver->do_reset();
+
+ // Reset all nets once !
+ for (std::size_t i = 0; i < m_nets.size(); i++)
+ m_nets[i]->do_reset();
+
+ // Reset all devices once !
+ for (std::size_t i = 0; i < m_devices.size(); i++)
+ {
+ m_devices[i]->do_reset();
+ }
+
+ // Step all devices once !
+ for (std::size_t i = 0; i < m_devices.size(); i++)
+ {
+ m_devices[i]->update_dev();
+ }
+
+ // FIXME: some const devices rely on this
+ /* make sure params are set now .. */
+ for (std::size_t i = 0; i < m_devices.size(); i++)
+ {
+ m_devices[i]->update_param();
+ }
+}
+
+
+ATTR_HOT void netlist_t::process_queue(const netlist_time &delta)
+{
+ m_stop = m_time + delta;
+
+ if (m_mainclock == NULL)
+ {
+ while ( (m_time < m_stop) && (m_queue.is_not_empty()))
+ {
+ const queue_t::entry_t e = *m_queue.pop();
+ m_time = e.exec_time();
+ e.object()->update_devs();
+
+ add_to_stat(m_perf_out_processed, 1);
+ }
+ if (m_queue.is_empty())
+ m_time = m_stop;
+
+ } else {
+ logic_net_t &mc_net = m_mainclock->m_Q.net().as_logic();
+ const netlist_time inc = m_mainclock->m_inc;
+ netlist_time mc_time = mc_net.time();
+
+ while (m_time < m_stop)
+ {
+ if (m_queue.is_not_empty())
+ {
+ while (m_queue.peek()->exec_time() > mc_time)
+ {
+ m_time = mc_time;
+ mc_time += inc;
+ devices::NETLIB_NAME(mainclock)::mc_update(mc_net);
+ }
+
+ const queue_t::entry_t e = *m_queue.pop();
+ m_time = e.exec_time();
+ e.object()->update_devs();
+
+ } else {
+ m_time = mc_time;
+ mc_time += inc;
+ devices::NETLIB_NAME(mainclock)::mc_update(mc_net);
+ }
+
+ add_to_stat(m_perf_out_processed, 1);
+ }
+ mc_net.set_time(mc_time);
+ }
+}
+
+// ----------------------------------------------------------------------------------------
+// Default netlist elements ...
+// ----------------------------------------------------------------------------------------
+
+
+
+// ----------------------------------------------------------------------------------------
+// net_core_device_t
+// ----------------------------------------------------------------------------------------
+
+ATTR_COLD core_device_t::core_device_t(const family_t afamily)
+: object_t(DEVICE, afamily), logic_family_t()
+#if (NL_KEEP_STATISTICS)
+ , stat_total_time(0)
+ , stat_update_count(0)
+ , stat_call_count(0)
+#endif
+{
+}
+
+ATTR_COLD void core_device_t::init(netlist_t &anetlist, const pstring &name)
+{
+ if (logic_family() == NULL)
+ set_logic_family(this->default_logic_family());
+ init_object(anetlist, name);
+
+#if (NL_PMF_TYPE == NL_PMF_TYPE_GNUC_PMF)
+ void (core_device_t::* pFunc)() = &core_device_t::update;
+ m_static_update = pFunc;
+#elif (NL_PMF_TYPE == NL_PMF_TYPE_GNUC_PMF_CONV)
+ void (core_device_t::* pFunc)() = &core_device_t::update;
+ m_static_update = reinterpret_cast<net_update_delegate>((this->*pFunc));
+#elif (NL_PMF_TYPE == NL_PMF_TYPE_INTERNAL)
+ m_static_update = pmfp::get_mfp<net_update_delegate>(&core_device_t::update, this);
+#endif
+}
+
+ATTR_COLD core_device_t::~core_device_t()
+{
+}
+
+ATTR_COLD void core_device_t::start_dev()
+{
+#if (NL_KEEP_STATISTICS)
+ netlist().m_started_devices.add(this, false);
+#endif
+ start();
+}
+
+ATTR_COLD void core_device_t::stop_dev()
+{
+#if (NL_KEEP_STATISTICS)
+#endif
+ stop();
+}
+
+ATTR_HOT netlist_sig_t core_device_t::INPLOGIC_PASSIVE(logic_input_t &inp)
+{
+ if (inp.state() != logic_t::STATE_INP_PASSIVE)
+ return inp.Q();
+ else
+ {
+ inp.activate();
+ const netlist_sig_t ret = inp.Q();
+ inp.inactivate();
+ return ret;
+ }
+}
+
+
+// ----------------------------------------------------------------------------------------
+// netlist_device_t
+// ----------------------------------------------------------------------------------------
+
+device_t::device_t()
+ : core_device_t(GENERIC),
+ m_terminals(20)
+{
+}
+
+device_t::device_t(const family_t afamily)
+ : core_device_t(afamily),
+ m_terminals(20)
+{
+}
+
+device_t::~device_t()
+{
+ //log().debug("~net_device_t\n");
+}
+
+ATTR_COLD setup_t &device_t::setup()
+{
+ return netlist().setup();
+}
+
+ATTR_COLD void device_t::init(netlist_t &anetlist, const pstring &name)
+{
+ core_device_t::init(anetlist, name);
+}
+
+
+ATTR_COLD void device_t::register_sub(const pstring &name, device_t &dev)
+{
+ dev.init(netlist(), this->name() + "." + name);
+ // subdevices always first inherit the logic family of the parent
+ dev.set_logic_family(this->logic_family());
+ dev.start_dev();
+}
+
+ATTR_COLD void device_t::register_subalias(const pstring &name, core_terminal_t &term)
+{
+ pstring alias = this->name() + "." + name;
+
+ // everything already fully qualified
+ setup().register_alias_nofqn(alias, term.name());
+
+ if (term.isType(terminal_t::INPUT) || term.isType(terminal_t::TERMINAL))
+ m_terminals.add(alias);
+}
+
+ATTR_COLD void device_t::register_subalias(const pstring &name, const pstring &aliased)
+{
+ pstring alias = this->name() + "." + name;
+ pstring aliased_fqn = this->name() + "." + aliased;
+
+ // everything already fully qualified
+ setup().register_alias_nofqn(alias, aliased_fqn);
+
+ // FIXME: make this working again
+ //if (term.isType(terminal_t::INPUT) || term.isType(terminal_t::TERMINAL))
+ // m_terminals.add(name);
+}
+
+ATTR_COLD void device_t::register_terminal(const pstring &name, terminal_t &port)
+{
+ setup().register_object(*this, name, port);
+ if (port.isType(terminal_t::INPUT) || port.isType(terminal_t::TERMINAL))
+ m_terminals.add(port.name());
+}
+
+ATTR_COLD void device_t::register_output(const pstring &name, logic_output_t &port)
+{
+ port.set_logic_family(this->logic_family());
+ setup().register_object(*this, name, port);
+}
+
+ATTR_COLD void device_t::register_output(const pstring &name, analog_output_t &port)
+{
+ setup().register_object(*this, name, port);
+}
+
+ATTR_COLD void device_t::register_input(const pstring &name, logic_input_t &inp)
+{
+ inp.set_logic_family(this->logic_family());
+ setup().register_object(*this, name, inp);
+ m_terminals.add(inp.name());
+}
+
+ATTR_COLD void device_t::register_input(const pstring &name, analog_input_t &inp)
+{
+ setup().register_object(*this, name, inp);
+ m_terminals.add(inp.name());
+}
+
+ATTR_COLD void device_t::connect_late(core_terminal_t &t1, core_terminal_t &t2)
+{
+ setup().register_link_fqn(t1.name(), t2.name());
+}
+
+ATTR_COLD void device_t::connect_late(const pstring &t1, const pstring &t2)
+{
+ setup().register_link_fqn(name() + "." + t1, name() + "." + t2);
+}
+
+ATTR_COLD void device_t::connect_direct(core_terminal_t &t1, core_terminal_t &t2)
+{
+ if (!setup().connect(t1, t2))
+ netlist().log().fatal("Error connecting {1} to {2}\n", t1.name(), t2.name());
+}
+
+
+template <class C, class T>
+ATTR_COLD void device_t::register_param(const pstring &sname, C &param, const T initialVal)
+{
+ pstring fullname = this->name() + "." + sname;
+ param.init_object(*this, fullname);
+ param.initial(initialVal);
+ setup().register_object(*this, fullname, param);
+}
+
+template ATTR_COLD void device_t::register_param(const pstring &sname, param_double_t &param, const double initialVal);
+template ATTR_COLD void device_t::register_param(const pstring &sname, param_double_t &param, const float initialVal);
+template ATTR_COLD void device_t::register_param(const pstring &sname, param_int_t &param, const int initialVal);
+template ATTR_COLD void device_t::register_param(const pstring &sname, param_logic_t &param, const int initialVal);
+template ATTR_COLD void device_t::register_param(const pstring &sname, param_str_t &param, const char * const initialVal);
+template ATTR_COLD void device_t::register_param(const pstring &sname, param_str_t &param, const pstring &initialVal);
+template ATTR_COLD void device_t::register_param(const pstring &sname, param_model_t &param, const char * const initialVal);
+
+
+// ----------------------------------------------------------------------------------------
+// netlist_net_t
+// ----------------------------------------------------------------------------------------
+
+ATTR_COLD net_t::net_t(const family_t afamily)
+ : object_t(NET, afamily)
+ , m_new_Q(0)
+ , m_cur_Q (0)
+ , m_railterminal(NULL)
+ , m_time(netlist_time::zero)
+ , m_active(0)
+ , m_in_queue(2)
+ , m_cur_Analog(0.0)
+{
+}
+
+ATTR_COLD net_t::~net_t()
+{
+ if (isInitialized())
+ netlist().remove_save_items(this);
+}
+
+ATTR_COLD void net_t::init_object(netlist_t &nl, const pstring &aname)
+{
+ object_t::init_object(nl, aname);
+ nl.m_nets.add(this);
+}
+
+ATTR_HOT void net_t::inc_active(core_terminal_t &term)
+{
+ m_active++;
+ m_list_active.insert(term);
+ nl_assert(m_active <= num_cons());
+ if (m_active == 1)
+ {
+ if (netlist().use_deactivate())
+ {
+ railterminal().device().inc_active();
+ //m_cur_Q = m_new_Q;
+ }
+ if (m_in_queue == 0)
+ {
+ if (m_time > netlist().time())
+ {
+ m_in_queue = 1; /* pending */
+ netlist().push_to_queue(*this, m_time);
+ }
+ else
+ {
+ m_cur_Q = m_new_Q;
+ m_in_queue = 2;
+ }
+ }
+ //else if (netlist().use_deactivate())
+ // m_cur_Q = m_new_Q;
+ }
+}
+
+ATTR_HOT void net_t::dec_active(core_terminal_t &term)
+{
+ m_active--;
+ nl_assert(m_active >= 0);
+ m_list_active.remove(term);
+ if (m_active == 0 && netlist().use_deactivate())
+ railterminal().device().dec_active();
+}
+
+ATTR_COLD void net_t::register_railterminal(core_terminal_t &mr)
+{
+ nl_assert(m_railterminal == NULL);
+ m_railterminal = &mr;
+}
+
+ATTR_COLD void net_t::rebuild_list()
+{
+ /* rebuild m_list */
+
+ unsigned cnt = 0;
+ m_list_active.clear();
+ for (std::size_t i=0; i < m_core_terms.size(); i++)
+ if (m_core_terms[i]->state() != logic_t::STATE_INP_PASSIVE)
+ {
+ m_list_active.add(*m_core_terms[i]);
+ cnt++;
+ }
+ m_active = cnt;
+}
+
+ATTR_COLD void net_t::save_register()
+{
+ save(NLNAME(m_time));
+ save(NLNAME(m_active));
+ save(NLNAME(m_in_queue));
+ save(NLNAME(m_cur_Analog));
+ save(NLNAME(m_cur_Q));
+ save(NLNAME(m_new_Q));
+ object_t::save_register();
+}
+
+ATTR_HOT /* inline */ void core_terminal_t::update_dev(const UINT32 mask)
+{
+ inc_stat(netdev().stat_call_count);
+ if ((state() & mask) != 0)
+ {
+ device().update_dev();
+ }
+}
+
+ATTR_HOT /* inline */ void net_t::update_devs()
+{
+ //assert(m_num_cons != 0);
+ nl_assert(this->isRailNet());
+
+ const UINT32 masks[4] = { 1, 5, 3, 1 };
+ const UINT32 mask = masks[ (m_cur_Q << 1) | m_new_Q ];
+
+ m_in_queue = 2; /* mark as taken ... */
+ m_cur_Q = m_new_Q;
+#if 0
+ core_terminal_t * t[256];
+ core_terminal_t *p = m_list_active.first();
+ int cnt = 0;
+ while (p != NULL)
+ {
+ if ((p->state() & mask) != 0)
+ t[cnt++] = p;
+ p = m_list_active.next(p);
+ }
+
+ for (int i=0; i<cnt; i++)
+ t[i]->netdev().update_dev();
+ core_terminal_t *p = m_list_active.first();
+
+ while (p != NULL)
+ {
+ p->update_dev(mask);
+ p = m_list_active.next(p);
+ }
+
+#else
+ core_terminal_t *p = m_list_active.first();
+
+ while (p != NULL)
+ {
+ p->update_dev(mask);
+ p = p->m_next;
+ }
+#endif
+}
+
+ATTR_COLD void net_t::reset()
+{
+ m_time = netlist_time::zero;
+ m_active = 0;
+ m_in_queue = 2;
+
+ m_new_Q = 0;
+ m_cur_Q = 0;
+ m_cur_Analog = 0.0;
+
+ /* rebuild m_list */
+
+ m_list_active.clear();
+ for (std::size_t i=0; i < m_core_terms.size(); i++)
+ m_list_active.add(*m_core_terms[i]);
+
+ for (std::size_t i=0; i < m_core_terms.size(); i++)
+ m_core_terms[i]->do_reset();
+
+ for (std::size_t i=0; i < m_core_terms.size(); i++)
+ if (m_core_terms[i]->state() != logic_t::STATE_INP_PASSIVE)
+ m_active++;
+}
+
+ATTR_COLD void net_t::register_con(core_terminal_t &terminal)
+{
+ terminal.set_net(*this);
+
+ m_core_terms.add(&terminal);
+
+ if (terminal.state() != logic_t::STATE_INP_PASSIVE)
+ m_active++;
+}
+
+ATTR_COLD void net_t::move_connections(net_t *dest_net)
+{
+ for (std::size_t i = 0; i < m_core_terms.size(); i++)
+ {
+ core_terminal_t *p = m_core_terms[i];
+ dest_net->register_con(*p);
+ }
+ m_core_terms.clear();
+ m_active = 0;
+}
+
+ATTR_COLD void net_t::merge_net(net_t *othernet)
+{
+ netlist().log().debug("merging nets ...\n");
+ if (othernet == NULL)
+ return; // Nothing to do
+
+ if (othernet == this)
+ {
+ netlist().log().warning("Connecting {1} to itself. This may be right, though\n", this->name());
+ return; // Nothing to do
+ }
+
+ if (this->isRailNet() && othernet->isRailNet())
+ netlist().log().fatal("Trying to merge two rail nets: {1} and {2}\n", this->name(), othernet->name());
+
+ if (othernet->isRailNet())
+ {
+ netlist().log().debug("othernet is railnet\n");
+ othernet->merge_net(this);
+ }
+ else
+ {
+ othernet->move_connections(this);
+ }
+}
+
+
+// ----------------------------------------------------------------------------------------
+// netlist_logic_net_t
+// ----------------------------------------------------------------------------------------
+
+ATTR_COLD logic_net_t::logic_net_t()
+ : net_t(LOGIC)
+{
+}
+
+
+ATTR_COLD void logic_net_t::reset()
+{
+ net_t::reset();
+}
+
+ATTR_COLD void logic_net_t::save_register()
+{
+ net_t::save_register();
+}
+
+// ----------------------------------------------------------------------------------------
+// netlist_analog_net_t
+// ----------------------------------------------------------------------------------------
+
+ATTR_COLD analog_net_t::analog_net_t()
+ : net_t(ANALOG)
+ , m_DD_n_m_1(0.0)
+ , m_h_n_m_1(1e-6)
+ , m_solver(NULL)
+{
+}
+
+ATTR_COLD void analog_net_t::reset()
+{
+ net_t::reset();
+}
+
+ATTR_COLD void analog_net_t::save_register()
+{
+ save(NLNAME(m_DD_n_m_1));
+ save(NLNAME(m_h_n_m_1));
+ net_t::save_register();
+}
+
+ATTR_COLD bool analog_net_t::already_processed(list_t *groups, int cur_group)
+{
+ if (isRailNet())
+ return true;
+ for (int i = 0; i <= cur_group; i++)
+ {
+ if (groups[i].contains(this))
+ return true;
+ }
+ return false;
+}
+
+ATTR_COLD void analog_net_t::process_net(list_t *groups, int &cur_group)
+{
+ if (num_cons() == 0)
+ return;
+ /* add the net */
+ groups[cur_group].add(this);
+ for (std::size_t i = 0; i < m_core_terms.size(); i++)
+ {
+ core_terminal_t *p = m_core_terms[i];
+ if (p->isType(terminal_t::TERMINAL))
+ {
+ terminal_t *pt = static_cast<terminal_t *>(p);
+ analog_net_t *other_net = &pt->m_otherterm->net().as_analog();
+ if (!other_net->already_processed(groups, cur_group))
+ other_net->process_net(groups, cur_group);
+ }
+ }
+}
+
+
+// ----------------------------------------------------------------------------------------
+// netlist_core_terminal_t
+// ----------------------------------------------------------------------------------------
+
+ATTR_COLD core_terminal_t::core_terminal_t(const type_t atype, const family_t afamily)
+: device_object_t(atype, afamily)
+, plinkedlist_element_t<core_terminal_t>()
+, m_net(NULL)
+, m_state(STATE_NONEX)
+{
+}
+
+ATTR_COLD void core_terminal_t::set_net(net_t &anet)
+{
+ m_net = &anet;
+}
+
+// ----------------------------------------------------------------------------------------
+// netlist_terminal_t
+// ----------------------------------------------------------------------------------------
+
+ATTR_COLD terminal_t::terminal_t()
+: core_terminal_t(TERMINAL, ANALOG)
+, m_Idr1(NULL)
+, m_go1(NULL)
+, m_gt1(NULL)
+, m_otherterm(NULL)
+{
+}
+
+ATTR_HOT void terminal_t::schedule_solve()
+{
+ // FIXME: Remove this after we found a way to remove *ALL* twoterms connected to railnets only.
+ if (net().as_analog().solver() != NULL)
+ net().as_analog().solver()->update_forced();
+}
+
+ATTR_HOT void terminal_t::schedule_after(const netlist_time &after)
+{
+ // FIXME: Remove this after we found a way to remove *ALL* twoterms connected to railnets only.
+ if (net().as_analog().solver() != NULL)
+ net().as_analog().solver()->update_after(after);
+}
+
+ATTR_COLD void terminal_t::reset()
+{
+ set_state(STATE_INP_ACTIVE);
+ set_ptr(m_Idr1, 0.0);
+ set_ptr(m_go1, netlist().gmin());
+ set_ptr(m_gt1, netlist().gmin());
+}
+
+ATTR_COLD void terminal_t::save_register()
+{
+ save(NLNAME(m_Idr1));
+ save(NLNAME(m_go1));
+ save(NLNAME(m_gt1));
+ core_terminal_t::save_register();
+}
+
+
+// ----------------------------------------------------------------------------------------
+// net_input_t
+// ----------------------------------------------------------------------------------------
+
+// ----------------------------------------------------------------------------------------
+// net_output_t
+// ----------------------------------------------------------------------------------------
+
+// ----------------------------------------------------------------------------------------
+// netlist_logic_output_t
+// ----------------------------------------------------------------------------------------
+
+ATTR_COLD logic_output_t::logic_output_t()
+ : logic_t(OUTPUT)
+{
+ set_state(STATE_OUT);
+ this->set_net(m_my_net);
+}
+
+ATTR_COLD void logic_output_t::init_object(core_device_t &dev, const pstring &aname)
+{
+ core_terminal_t::init_object(dev, aname);
+ net().init_object(dev.netlist(), aname + ".net");
+ net().register_railterminal(*this);
+}
+
+ATTR_COLD void logic_output_t::initial(const netlist_sig_t val)
+{
+ net().as_logic().initial(val);
+}
+
+
+// ----------------------------------------------------------------------------------------
+// netlist_analog_output_t
+// ----------------------------------------------------------------------------------------
+
+ATTR_COLD analog_output_t::analog_output_t()
+ : netlist_analog_t(OUTPUT), m_proxied_net(NULL)
+{
+ this->set_net(m_my_net);
+ set_state(STATE_OUT);
+
+ net().as_analog().m_cur_Analog = NL_FCONST(0.99);
+}
+
+ATTR_COLD void analog_output_t::init_object(core_device_t &dev, const pstring &aname)
+{
+ core_terminal_t::init_object(dev, aname);
+ net().init_object(dev.netlist(), aname + ".net");
+ net().register_railterminal(*this);
+}
+
+ATTR_COLD void analog_output_t::initial(const nl_double val)
+{
+ net().as_analog().m_cur_Analog = val;
+}
+
+// ----------------------------------------------------------------------------------------
+// netlist_param_t & friends
+// ----------------------------------------------------------------------------------------
+
+ATTR_COLD param_t::param_t(const param_type_t atype)
+ : device_object_t(PARAM, ANALOG)
+ , m_param_type(atype)
+{
+}
+
+ATTR_COLD const pstring param_model_t::model_type()
+{
+ if (m_map.size() == 0)
+ netlist().setup().model_parse(this->Value(), m_map);
+ return m_map["COREMODEL"];
+}
+
+
+ATTR_COLD const pstring param_model_t::model_value_str(const pstring &entity)
+{
+ if (m_map.size() == 0)
+ netlist().setup().model_parse(this->Value(), m_map);
+ return netlist().setup().model_value_str(m_map, entity);
+}
+
+ATTR_COLD nl_double param_model_t::model_value(const pstring &entity)
+{
+ if (m_map.size() == 0)
+ netlist().setup().model_parse(this->Value(), m_map);
+ return netlist().setup().model_value(m_map, entity);
+}
+
+} // namespace
+
+NETLIB_NAMESPACE_DEVICES_START()
+
+// ----------------------------------------------------------------------------------------
+// mainclock
+// ----------------------------------------------------------------------------------------
+
+ATTR_HOT /* inline */ void NETLIB_NAME(mainclock)::mc_update(logic_net_t &net)
+{
+ net.toggle_new_Q();
+ net.update_devs();
+}
+
+NETLIB_START(mainclock)
+{
+ register_output("Q", m_Q);
+
+ register_param("FREQ", m_freq, 7159000.0 * 5);
+ m_inc = netlist_time::from_hz(m_freq.Value()*2);
+}
+
+NETLIB_RESET(mainclock)
+{
+ m_Q.net().set_time(netlist_time::zero);
+}
+
+NETLIB_UPDATE_PARAM(mainclock)
+{
+ m_inc = netlist_time::from_hz(m_freq.Value()*2);
+}
+
+NETLIB_UPDATE(mainclock)
+{
+ logic_net_t &net = m_Q.net().as_logic();
+ // this is only called during setup ...
+ net.toggle_new_Q();
+ net.set_time(netlist().time() + m_inc);
+}
+
+NETLIB_NAMESPACE_DEVICES_END()