// license:GPL-2.0+ // copyright-holders:Couriersud /* * nlbase.c * */ #include "solver/nld_matrix_solver.h" #include "solver/nld_solver.h" #include "plib/putil.h" #include "plib/palloc.h" #include "nl_base.h" #include "devices/nlid_system.h" #include "devices/nlid_proxy.h" #include "macro/nlm_base.h" #include "nl_errstr.h" #include #include #include namespace netlist { namespace detail { static plib::mempool *pool() { static plib::mempool *s_pool = nullptr; if (s_pool == nullptr) s_pool = new plib::mempool(65536, 16); return s_pool; } void * object_t::operator new (size_t size) { void *ret = nullptr; if ((USE_MEMPOOL)) ret = pool()->alloc(size); else ret = ::operator new(size); return ret; } void object_t::operator delete (void * mem) { if (mem) { if ((USE_MEMPOOL)) pool()->free(mem); else ::operator delete(mem); } } } nl_exception::~nl_exception() { } // ---------------------------------------------------------------------------------------- // logic_family_ttl_t // ---------------------------------------------------------------------------------------- logic_family_desc_t::logic_family_desc_t() { } logic_family_desc_t::~logic_family_desc_t() { } class logic_family_ttl_t : public logic_family_desc_t { public: logic_family_ttl_t() : logic_family_desc_t() { m_fixed_V = 5.0; m_low_thresh_PCNT = 0.8 / 5.0; m_high_thresh_PCNT = 2.0 / 5.0; // m_low_V - these depend on sinked/sourced current. Values should be suitable for typical applications. m_low_VO = 0.1; m_high_VO = 1.0; // 4.0 m_R_low = 1.0; m_R_high = 130.0; } virtual plib::owned_ptr create_d_a_proxy(netlist_t &anetlist, const pstring &name, logic_output_t *proxied) const override; virtual plib::owned_ptr create_a_d_proxy(netlist_t &anetlist, const pstring &name, logic_input_t *proxied) const override; }; plib::owned_ptr logic_family_ttl_t::create_d_a_proxy(netlist_t &anetlist, const pstring &name, logic_output_t *proxied) const { return plib::owned_ptr::Create(anetlist, name, proxied); } plib::owned_ptr logic_family_ttl_t::create_a_d_proxy(netlist_t &anetlist, const pstring &name, logic_input_t *proxied) const { return plib::owned_ptr::Create(anetlist, name, proxied); } class logic_family_cd4xxx_t : public logic_family_desc_t { public: logic_family_cd4xxx_t() : logic_family_desc_t() { m_fixed_V = 0.0; m_low_thresh_PCNT = 1.5 / 5.0; m_high_thresh_PCNT = 3.5 / 5.0; // m_low_V - these depend on sinked/sourced current. Values should be suitable for typical applications. m_low_VO = 0.05; m_high_VO = 0.05; // 4.95 m_R_low = 10.0; m_R_high = 10.0; } virtual plib::owned_ptr create_d_a_proxy(netlist_t &anetlist, const pstring &name, logic_output_t *proxied) const override; virtual plib::owned_ptr create_a_d_proxy(netlist_t &anetlist, const pstring &name, logic_input_t *proxied) const override; }; plib::owned_ptr logic_family_cd4xxx_t::create_d_a_proxy(netlist_t &anetlist, const pstring &name, logic_output_t *proxied) const { return plib::owned_ptr::Create(anetlist, name, proxied); } plib::owned_ptr logic_family_cd4xxx_t::create_a_d_proxy(netlist_t &anetlist, const pstring &name, logic_input_t *proxied) const { return plib::owned_ptr::Create(anetlist, name, proxied); } const logic_family_desc_t *family_TTL() { static logic_family_ttl_t obj; return &obj; } const logic_family_desc_t *family_CD4XXX() { static logic_family_cd4xxx_t obj; return &obj; } // ---------------------------------------------------------------------------------------- // queue_t // ---------------------------------------------------------------------------------------- detail::queue_t::queue_t(netlist_t &nl) : timed_queue>(512) , netlist_ref(nl) , plib::state_manager_t::callback_t() , m_qsize(0) , m_times(512) , m_net_ids(512) { } void detail::queue_t::register_state(plib::state_manager_t &manager, const pstring &module) { netlist().log().debug("register_state\n"); manager.save_item(this, m_qsize, module + "." + "qsize"); manager.save_item(this, &m_times[0], module + "." + "times", m_times.size()); manager.save_item(this, &m_net_ids[0], module + "." + "names", m_net_ids.size()); } void detail::queue_t::on_pre_save() { netlist().log().debug("on_pre_save\n"); m_qsize = this->size(); netlist().log().debug("current time {1} qsize {2}\n", netlist().time().as_double(), m_qsize); for (std::size_t i = 0; i < m_qsize; i++ ) { m_times[i] = this->listptr()[i].m_exec_time.as_raw(); m_net_ids[i] = netlist().find_net_id(this->listptr()[i].m_object); } } void detail::queue_t::on_post_load() { this->clear(); netlist().log().debug("current time {1} qsize {2}\n", netlist().time().as_double(), m_qsize); for (std::size_t i = 0; i < m_qsize; i++ ) { detail::net_t *n = netlist().m_nets[m_net_ids[i]].get(); this->push(queue_t::entry_t(netlist_time::from_raw(m_times[i]),n)); } } // ---------------------------------------------------------------------------------------- // object_t // ---------------------------------------------------------------------------------------- detail::object_t::object_t(const pstring &aname) : m_name(aname) { } detail::object_t::~object_t() { } const pstring &detail::object_t::name() const { return m_name; } // ---------------------------------------------------------------------------------------- // device_object_t // ---------------------------------------------------------------------------------------- detail::device_object_t::device_object_t(core_device_t &dev, const pstring &aname) : object_t(aname) , m_device(dev) { } detail::terminal_type detail::core_terminal_t::type() const { if (dynamic_cast(this) != nullptr) return terminal_type::TERMINAL; else if (dynamic_cast(this) != nullptr) return terminal_type::INPUT; else if (dynamic_cast(this) != nullptr) return terminal_type::OUTPUT; else if (dynamic_cast(this) != nullptr) return terminal_type::INPUT; else if (dynamic_cast(this) != nullptr) return terminal_type::OUTPUT; else { netlist().log().fatal(MF_1_UNKNOWN_TYPE_FOR_OBJECT, name()); return terminal_type::TERMINAL; // please compiler } } // ---------------------------------------------------------------------------------------- // netlist_t // ---------------------------------------------------------------------------------------- netlist_t::netlist_t(const pstring &aname) : m_time(netlist_time::zero()) , m_queue(*this) , m_mainclock(nullptr) , m_solver(nullptr) , m_params(nullptr) , m_name(aname) , m_log(this) , m_lib(nullptr) , m_state() { state().save_item(this, static_cast(m_queue), "m_queue"); state().save_item(this, m_time, "m_time"); m_setup = plib::make_unique(*this); /* FIXME: doesn't really belong here */ NETLIST_NAME(base)(*m_setup); } netlist_t::~netlist_t() { m_nets.clear(); m_devices.clear(); pstring::resetmem(); } nl_double netlist_t::gmin() const { return solver()->gmin(); } void netlist_t::register_dev(plib::owned_ptr dev) { for (auto & d : m_devices) if (d->name() == dev->name()) log().fatal(MF_1_DUPLICATE_NAME_DEVICE_LIST, d->name()); m_devices.push_back(std::move(dev)); } void netlist_t::remove_dev(core_device_t *dev) { m_devices.erase( std::remove_if( m_devices.begin(), m_devices.end(), [&] (plib::owned_ptr const& p) { return p.get() == dev; }), m_devices.end() ); } void netlist_t::start() { setup().start_devices(); /* load the library ... */ /* make sure the solver and parameters are started first! */ for (auto & e : setup().m_device_factory) { if ( setup().factory().is_class(e.second) || setup().factory().is_class(e.second)) { auto dev = plib::owned_ptr(e.second->Create(*this, e.first)); register_dev(std::move(dev)); } } log().debug("Searching for mainclock and solver ...\n"); m_solver = get_single_device("solver"); m_params = get_single_device("parameter"); /* create devices */ log().debug("Creating devices ...\n"); for (auto & e : setup().m_device_factory) { if ( !setup().factory().is_class(e.second) && !setup().factory().is_class(e.second)) { auto dev = plib::owned_ptr(e.second->Create(*this, e.first)); register_dev(std::move(dev)); } } log().debug("Searching for mainclock\n"); m_mainclock = get_single_device("mainclock"); bool use_deactivate = (m_params->m_use_deactivate() ? true : false); for (auto &d : m_devices) { if (use_deactivate) { auto p = setup().m_param_values.find(d->name() + ".HINT_NO_DEACTIVATE"); if (p != setup().m_param_values.end()) { //FIXME: turn this into a proper function bool error; auto v = p->second.as_double(&error); if (error || std::abs(v - std::floor(v)) > 1e-6 ) log().fatal(MF_1_HND_VAL_NOT_SUPPORTED, p->second); d->set_hint_deactivate(v == 0.0); } } else d->set_hint_deactivate(false); } pstring libpath = plib::util::environment("NL_BOOSTLIB", plib::util::buildpath({".", "nlboost.so"})); m_lib = plib::make_unique(libpath); /* resolve inputs */ setup().resolve_inputs(); log().verbose("looking for two terms connected to rail nets ..."); for (auto & t : get_device_list()) { if (t->m_N.net().isRailNet() && t->m_P.net().isRailNet()) { log().warning(MW_3_REMOVE_DEVICE_1_CONNECTED_ONLY_TO_RAILS_2_3, t->name(), t->m_N.net().name(), t->m_P.net().name()); t->m_N.net().remove_terminal(t->m_N); t->m_P.net().remove_terminal(t->m_P); remove_dev(t); } } log().verbose("initialize solver ...\n"); if (m_solver == nullptr) { for (auto &p : m_nets) if (p->is_analog()) log().fatal(MF_0_NO_SOLVER); } else m_solver->post_start(); for (auto &n : m_nets) for (auto & term : n->m_core_terms) { //core_device_t *dev = reinterpret_cast(term->m_delegate.object()); core_device_t *dev = &term->device(); dev->set_default_delegate(*term); } } void netlist_t::stop() { log().debug("Printing statistics ...\n"); print_stats(); log().debug("Stopping solver device ...\n"); if (m_solver != nullptr) m_solver->stop(); } detail::net_t *netlist_t::find_net(const pstring &name) const { for (auto & net : m_nets) if (net->name() == name) return net.get(); return nullptr; } std::size_t netlist_t::find_net_id(const detail::net_t *net) const { for (std::size_t i = 0; i < m_nets.size(); i++) if (m_nets[i].get() == net) return i; return std::numeric_limits::max(); } void netlist_t::rebuild_lists() { for (auto & net : m_nets) net->rebuild_list(); } void netlist_t::reset() { m_time = netlist_time::zero(); m_queue.clear(); if (m_mainclock != nullptr) m_mainclock->m_Q.net().set_time(netlist_time::zero()); //if (m_solver != nullptr) // m_solver->do_reset(); std::unordered_map m; for (auto &d : m_devices) { m[d.get()] = d->get_hint_deactivate(); } // Reset all nets once ! for (auto & n : m_nets) n->reset(); // Reset all devices once ! for (auto & dev : m_devices) dev->do_reset(); // Make sure everything depending on parameters is set for (auto & dev : m_devices) dev->update_param(); // Step all devices once ! /* * INFO: The order here affects power up of e.g. breakout. However, such * variations are explicitly stated in the breakout manual. */ const unsigned startup_strategy = 1; //! \note make this a parameter switch (startup_strategy) { case 0: { std::vector d; std::vector t; log().verbose("Using default startup strategy"); for (auto &n : m_nets) for (auto & term : n->m_core_terms) if (term->m_delegate.has_object()) { if (!plib::container::contains(t, &term->m_delegate)) { t.push_back(&term->m_delegate); term->m_delegate(); } core_device_t *dev = reinterpret_cast(term->m_delegate.object()); if (!plib::container::contains(d, dev)) d.push_back(dev); } log().verbose("Call update on devices which need parameter update:"); for (auto & dev : m_devices) if (dev->needs_update_after_param_change()) { if (!plib::container::contains(d, dev.get())) { d.push_back(dev.get()); log().verbose("\t ...{1}", dev->name()); dev->update_dev(); } } log().verbose("Devices not yet updated:"); for (auto &dev : m_devices) if (!plib::container::contains(d, dev.get())) log().verbose("\t ...{1}", dev->name()); //x->update_dev(); } break; case 1: // brute force backward { std::size_t i = m_devices.size(); while (i>0) m_devices[--i]->update_dev(); } break; case 2: // brute force forward { for (auto &d : m_devices) d->update_dev(); } break; } #if 1 /* the above may screw up m_active and the list */ for (auto &n : m_nets) n->rebuild_list(); #endif } void netlist_t::process_queue(const netlist_time &delta) NL_NOEXCEPT { netlist_time stop(m_time + delta); m_queue.push(detail::queue_t::entry_t(stop, nullptr)); m_stat_mainloop.start(); if (m_mainclock == nullptr) { detail::queue_t::entry_t e(m_queue.top()); m_queue.pop(); m_time = e.m_exec_time; while (e.m_object != nullptr) { e.m_object->update_devs(); m_perf_out_processed.inc(); e = m_queue.top(); m_queue.pop(); m_time = e.m_exec_time; } } else { logic_net_t &mc_net = m_mainclock->m_Q.net(); const netlist_time inc = m_mainclock->m_inc; netlist_time mc_time(mc_net.time()); detail::queue_t::entry_t e; do { while (m_queue.top().m_exec_time > mc_time) { m_time = mc_time; mc_net.toggle_new_Q(); mc_net.update_devs(); mc_time += inc; } e = m_queue.top(); m_queue.pop(); m_time = e.m_exec_time; if (e.m_object != nullptr) { e.m_object->update_devs(); m_perf_out_processed.inc(); } } while (e.m_object != nullptr); mc_net.set_time(mc_time); } m_stat_mainloop.stop(); } void netlist_t::print_stats() const { if (nperftime_t::enabled) { std::vector index; for (size_t i=0; im_stat_total_time.total() < m_devices[i2]->m_stat_total_time.total(); }); nperftime_t::type total_time(0); uint_least64_t total_count(0); for (auto & j : index) { auto entry = m_devices[j].get(); log().verbose("Device {1:20} : {2:12} {3:12} {4:15} {5:12}", entry->name(), entry->m_stat_call_count(), entry->m_stat_total_time.count(), entry->m_stat_total_time.total(), entry->m_stat_inc_active()); total_time += entry->m_stat_total_time.total(); total_count += entry->m_stat_total_time.count(); } nperftime_t overhead; nperftime_t test; overhead.start(); for (int j=0; j<100000;j++) { test.start(); test.stop(); } overhead.stop(); nperftime_t::type total_overhead = overhead() * static_cast(total_count) / static_cast(200000); log().verbose("Queue Pushes {1:15}", queue().m_prof_call()); log().verbose("Queue Moves {1:15}", queue().m_prof_sortmove()); log().verbose("Total loop {1:15}", m_stat_mainloop()); /* Only one serialization should be counted in total time */ /* But two are contained in m_stat_mainloop */ log().verbose("Total devices {1:15}", total_time); log().verbose(""); log().verbose("Take the next lines with a grain of salt. They depend on the measurement implementation."); log().verbose("Total overhead {1:15}", total_overhead); nperftime_t::type overhead_per_pop = (m_stat_mainloop()-2*total_overhead - (total_time - total_overhead)) / static_cast(queue().m_prof_call()); log().verbose("Overhead per pop {1:11}", overhead_per_pop ); log().verbose(""); for (auto &entry : m_devices) { if (entry->m_stat_inc_active() > 3 * entry->m_stat_total_time.count()) log().verbose("HINT({}, NO_DEACTIVATE)", entry->name()); } } } core_device_t *netlist_t::get_single_device(const pstring classname, bool (*cc)(core_device_t *)) { core_device_t *ret = nullptr; for (auto &d : m_devices) { if (cc(d.get())) { if (ret != nullptr) this->log().fatal(MF_1_MORE_THAN_ONE_1_DEVICE_FOUND, classname); else ret = d.get(); } } return ret; } // ---------------------------------------------------------------------------------------- // core_device_t // ---------------------------------------------------------------------------------------- core_device_t::core_device_t(netlist_t &owner, const pstring &name) : object_t(name) , logic_family_t() , netlist_ref(owner) , m_hint_deactivate(false) { if (logic_family() == nullptr) set_logic_family(family_TTL()); } core_device_t::core_device_t(core_device_t &owner, const pstring &name) : object_t(owner.name() + "." + name) , logic_family_t() , netlist_ref(owner.netlist()) , m_hint_deactivate(false) { set_logic_family(owner.logic_family()); if (logic_family() == nullptr) set_logic_family(family_TTL()); owner.netlist().register_dev(plib::owned_ptr(this, false)); } core_device_t::~core_device_t() { } void core_device_t::set_default_delegate(detail::core_terminal_t &term) { if (!term.m_delegate.is_set()) term.m_delegate.set(&core_device_t::update, this); } plib::plog_base &core_device_t::log() { return netlist().log(); } // ---------------------------------------------------------------------------------------- // device_t // ---------------------------------------------------------------------------------------- device_t::device_t(netlist_t &owner, const pstring &name) : core_device_t(owner, name) { } device_t::device_t(core_device_t &owner, const pstring &name) : core_device_t(owner, name) { } device_t::~device_t() { //log().debug("~net_device_t\n"); } setup_t &device_t::setup() { return netlist().setup(); } void device_t::register_subalias(const pstring &name, detail::core_terminal_t &term) { pstring alias = this->name() + "." + name; // everything already fully qualified setup().register_alias_nofqn(alias, term.name()); } 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); } void device_t::connect(detail::core_terminal_t &t1, detail::core_terminal_t &t2) { setup().register_link_fqn(t1.name(), t2.name()); } void device_t::connect(const pstring &t1, const pstring &t2) { setup().register_link_fqn(name() + "." + t1, name() + "." + t2); } /* FIXME: this is only used by solver code since matrix solvers are started in * post_start. */ void device_t::connect_post_start(detail::core_terminal_t &t1, detail::core_terminal_t &t2) { if (!setup().connect(t1, t2)) log().fatal(MF_2_ERROR_CONNECTING_1_TO_2, t1.name(), t2.name()); } // ----------------------------------------------------------------------------- // family_setter_t // ----------------------------------------------------------------------------- detail::family_setter_t::family_setter_t(core_device_t &dev, const pstring desc) { dev.set_logic_family(dev.netlist().setup().family_from_model(desc)); } detail::family_setter_t::family_setter_t(core_device_t &dev, const logic_family_desc_t *desc) { dev.set_logic_family(desc); } // ---------------------------------------------------------------------------------------- // net_t // ---------------------------------------------------------------------------------------- detail::net_t::net_t(netlist_t &nl, const pstring &aname, core_terminal_t *mr) : object_t(aname) , netlist_ref(nl) , m_new_Q(*this, "m_new_Q", 0) , m_cur_Q (*this, "m_cur_Q", 0) , m_in_queue(*this, "m_in_queue", QS_DELIVERED) , m_time(*this, "m_time", netlist_time::zero()) , m_active(*this, "m_active", 0) , m_cur_Analog(*this, "m_cur_Analog", 0.0) , m_railterminal(mr) { } detail::net_t::~net_t() { netlist().state().remove_save_items(this); } void detail::net_t::inc_active(core_terminal_t &term) NL_NOEXCEPT { ++m_active; m_list_active.push_front(&term); nl_assert(m_active <= static_cast(num_cons())); if (m_active == 1) { railterminal().device().do_inc_active(); if (m_in_queue == QS_DELAYED_DUE_TO_INACTIVE) { if (m_time > netlist().time()) { m_in_queue = QS_QUEUED; /* pending */ netlist().queue().push(queue_t::entry_t(m_time, this)); } else { m_in_queue = QS_DELIVERED; m_cur_Q = m_new_Q; } } } } void detail::net_t::dec_active(core_terminal_t &term) NL_NOEXCEPT { --m_active; nl_assert(m_active >= 0); m_list_active.remove(&term); if (m_active == 0) railterminal().device().do_dec_active(); } void detail::net_t::rebuild_list() { /* rebuild m_list */ int cnt = 0; m_list_active.clear(); for (auto & term : m_core_terms) if (term->state() != logic_t::STATE_INP_PASSIVE) { m_list_active.push_back(term); cnt++; } m_active = cnt; } void detail::net_t::update_devs() NL_NOEXCEPT { nl_assert(this->isRailNet()); const uint8_t masks[4] = { 0, core_terminal_t::STATE_INP_LH | core_terminal_t::STATE_INP_ACTIVE, core_terminal_t::STATE_INP_HL | core_terminal_t::STATE_INP_ACTIVE, 0 }; const auto mask = masks[ (m_cur_Q << 1) | m_new_Q ]; m_cur_Q = m_new_Q; m_in_queue = QS_DELIVERED; /* mark as taken ... */ for (auto & p : m_list_active) { p.device().m_stat_call_count.inc(); if ((p.state() & mask) != 0) { p.device().m_stat_total_time.start(); p.m_delegate(); p.device().m_stat_total_time.stop(); } } } void detail::net_t::reset() { m_time = netlist_time::zero(); m_active = 0; m_in_queue = QS_DELIVERED; m_new_Q = 0; m_cur_Q = 0; m_cur_Analog = 0.0; /* rebuild m_list */ m_list_active.clear(); for (core_terminal_t *ct : m_core_terms) m_list_active.push_back(ct); for (core_terminal_t *ct : m_core_terms) ct->reset(); for (core_terminal_t *ct : m_core_terms) if (ct->state() != logic_t::STATE_INP_PASSIVE) m_active++; } void detail::net_t::add_terminal(detail::core_terminal_t &terminal) { for (auto &t : m_core_terms) if (t == &terminal) netlist().log().fatal(MF_2_NET_1_DUPLICATE_TERMINAL_2, name(), t->name()); terminal.set_net(this); m_core_terms.push_back(&terminal); if (terminal.state() != logic_t::STATE_INP_PASSIVE) m_active++; } void detail::net_t::remove_terminal(detail::core_terminal_t &terminal) { if (plib::container::contains(m_core_terms, &terminal)) { terminal.set_net(nullptr); plib::container::remove(m_core_terms, &terminal); } else netlist().log().fatal(MF_2_REMOVE_TERMINAL_1_FROM_NET_2, terminal.name(), this->name()); if (terminal.state() != logic_t::STATE_INP_PASSIVE) m_active--; } void detail::net_t::move_connections(detail::net_t &dest_net) { for (auto &ct : m_core_terms) dest_net.add_terminal(*ct); m_core_terms.clear(); m_active = 0; } // ---------------------------------------------------------------------------------------- // logic_net_t // ---------------------------------------------------------------------------------------- logic_net_t::logic_net_t(netlist_t &nl, const pstring &aname, detail::core_terminal_t *mr) : net_t(nl, aname, mr) { } logic_net_t::~logic_net_t() { } // ---------------------------------------------------------------------------------------- // analog_net_t // ---------------------------------------------------------------------------------------- analog_net_t::analog_net_t(netlist_t &nl, const pstring &aname, detail::core_terminal_t *mr) : net_t(nl, aname, mr) , m_solver(nullptr) { } analog_net_t::~analog_net_t() { } // ---------------------------------------------------------------------------------------- // core_terminal_t // ---------------------------------------------------------------------------------------- detail::core_terminal_t::core_terminal_t(core_device_t &dev, const pstring &aname, const state_e state, nldelegate delegate) : device_object_t(dev, dev.name() + "." + aname) , plib::linkedlist_t::element_t() , m_delegate(delegate) , m_net(nullptr) , m_state(*this, "m_state", state) { } detail::core_terminal_t::~core_terminal_t() { } void detail::core_terminal_t::reset() { if (is_type(OUTPUT)) set_state(STATE_OUT); else set_state(STATE_INP_ACTIVE); } void detail::core_terminal_t::set_net(net_t *anet) { m_net = anet; } void detail::core_terminal_t::clear_net() { m_net = nullptr; } analog_t::analog_t(core_device_t &dev, const pstring &aname, const state_e state) : core_terminal_t(dev, aname, state) { } analog_t::~analog_t() { } logic_t::logic_t(core_device_t &dev, const pstring &aname, const state_e state, nldelegate delegate) : core_terminal_t(dev, aname, state, delegate) , logic_family_t() , m_proxy(nullptr) { } logic_t::~logic_t() { } // ---------------------------------------------------------------------------------------- // terminal_t // ---------------------------------------------------------------------------------------- terminal_t::terminal_t(core_device_t &dev, const pstring &aname) : analog_t(dev, aname, STATE_BIDIR) , m_otherterm(nullptr) , m_Idr1(nullptr) , m_go1(nullptr) , m_gt1(nullptr) { netlist().setup().register_term(*this); } terminal_t::~terminal_t() { } void terminal_t::solve_now() { // Nets may belong to railnets which do not have a solver attached if (this->has_net()) if (net().solver() != nullptr) net().solver()->update_forced(); } void terminal_t::schedule_solve_after(const netlist_time &after) { // Nets may belong to railnets which do not have a solver attached if (this->has_net()) if (net().solver() != nullptr) net().solver()->update_after(after); } // ---------------------------------------------------------------------------------------- // net_input_t // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- // net_output_t // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- // logic_output_t // ---------------------------------------------------------------------------------------- logic_output_t::logic_output_t(core_device_t &dev, const pstring &aname) : logic_t(dev, aname, STATE_OUT) , m_my_net(dev.netlist(), name() + ".net", this) { this->set_net(&m_my_net); netlist().m_nets.push_back(plib::owned_ptr(&m_my_net, false)); set_logic_family(dev.logic_family()); netlist().setup().register_term(*this); } logic_output_t::~logic_output_t() { } void logic_output_t::initial(const netlist_sig_t val) { if (has_net()) net().initial(val); } // ---------------------------------------------------------------------------------------- // analog_input_t // ---------------------------------------------------------------------------------------- analog_input_t::analog_input_t(core_device_t &dev, const pstring &aname) : analog_t(dev, aname, STATE_INP_ACTIVE) { netlist().setup().register_term(*this); } analog_input_t::~analog_input_t() { } // ---------------------------------------------------------------------------------------- // analog_output_t // ---------------------------------------------------------------------------------------- analog_output_t::analog_output_t(core_device_t &dev, const pstring &aname) : analog_t(dev, aname, STATE_OUT) , m_my_net(dev.netlist(), name() + ".net", this) { netlist().m_nets.push_back(plib::owned_ptr(&m_my_net, false)); this->set_net(&m_my_net); //net().m_cur_Analog = NL_FCONST(0.0); netlist().setup().register_term(*this); } analog_output_t::~analog_output_t() { } void analog_output_t::initial(const nl_double val) { net().set_Q_Analog(val); } // ----------------------------------------------------------------------------- // logic_input_t // ----------------------------------------------------------------------------- logic_input_t::logic_input_t(core_device_t &dev, const pstring &aname, nldelegate delegate) : logic_t(dev, aname, STATE_INP_ACTIVE, delegate) { set_logic_family(dev.logic_family()); netlist().setup().register_term(*this); } logic_input_t::~logic_input_t() { } // ---------------------------------------------------------------------------------------- // Parameters ... // ---------------------------------------------------------------------------------------- param_t::param_t(device_t &device, const pstring &name) : device_object_t(device, device.name() + "." + name) { device.setup().register_param(this->name(), *this); } param_t::~param_t() { } param_t::param_type_t param_t::param_type() const { if (dynamic_cast(this) != nullptr) return STRING; else if (dynamic_cast(this) != nullptr) return DOUBLE; else if (dynamic_cast(this) != nullptr) return INTEGER; else if (dynamic_cast(this) != nullptr) return LOGIC; else if (dynamic_cast(this) != nullptr) return POINTER; else { netlist().log().fatal(MF_1_UNKNOWN_PARAM_TYPE, name()); return POINTER; /* Please compiler */ } } void param_t::update_param() { device().update_param(); if (device().needs_update_after_param_change()) device().update_dev(); } const pstring param_model_t::model_type() { if (m_map.size() == 0) netlist().setup().model_parse(this->Value(), m_map); return m_map["COREMODEL"]; } param_str_t::param_str_t(device_t &device, const pstring name, const pstring val) : param_t(device, name) { m_param = device.setup().get_initial_param_val(this->name(),val); } param_str_t::~param_str_t() { } void param_str_t::changed() { } param_double_t::param_double_t(device_t &device, const pstring name, const double val) : param_t(device, name) { m_param = device.setup().get_initial_param_val(this->name(),val); netlist().save(*this, m_param, "m_param"); } #if 0 param_double_t::~param_double_t() { } #endif param_int_t::param_int_t(device_t &device, const pstring name, const int val) : param_t(device, name) { m_param = device.setup().get_initial_param_val(this->name(),val); netlist().save(*this, m_param, "m_param"); } #if 0 param_int_t::~param_int_t() { } #endif param_logic_t::param_logic_t(device_t &device, const pstring name, const bool val) : param_t(device, name) { m_param = device.setup().get_initial_param_val(this->name(),val); netlist().save(*this, m_param, "m_param"); } #if 0 param_logic_t::~param_logic_t() { } #endif param_ptr_t::param_ptr_t(device_t &device, const pstring name, uint8_t * val) : param_t(device, name) { m_param = val; //device.setup().get_initial_param_val(this->name(),val); //netlist().save(*this, m_param, "m_param"); } #if 0 param_ptr_t::~param_ptr_t() { } #endif void param_model_t::changed() { netlist().log().fatal(MF_1_MODEL_1_CAN_NOT_BE_CHANGED_AT_RUNTIME, name()); m_map.clear(); } 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); } 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); } param_data_t::param_data_t(device_t &device, const pstring name) : param_str_t(device, name, "") { } void param_data_t::changed() { } std::unique_ptr param_data_t::stream() { return device().netlist().setup().get_data_stream(Value()); } namespace devices { // ---------------------------------------------------------------------------------------- // mainclock // ---------------------------------------------------------------------------------------- void NETLIB_NAME(mainclock)::mc_update(logic_net_t &net) { net.toggle_new_Q(); net.update_devs(); } } //namespace devices bool detail::core_terminal_t::is_logic() const NL_NOEXCEPT { return dynamic_cast(this) != nullptr; } bool detail::core_terminal_t::is_analog() const NL_NOEXCEPT { return dynamic_cast(this) != nullptr; } bool detail::net_t::is_logic() const NL_NOEXCEPT { return dynamic_cast(this) != nullptr; } bool detail::net_t::is_analog() const NL_NOEXCEPT { return dynamic_cast(this) != nullptr; } } // namespace netlist