diff options
Diffstat (limited to 'src/lib/netlist/devices/nlid_system.h')
-rw-r--r-- | src/lib/netlist/devices/nlid_system.h | 718 |
1 files changed, 422 insertions, 296 deletions
diff --git a/src/lib/netlist/devices/nlid_system.h b/src/lib/netlist/devices/nlid_system.h index 89a525ef69f..fee4fad0333 100644 --- a/src/lib/netlist/devices/nlid_system.h +++ b/src/lib/netlist/devices/nlid_system.h @@ -1,86 +1,22 @@ -// license:GPL-2.0+ +// license:BSD-3-Clause // copyright-holders:Couriersud -/* - * nlid_system.h - * - * netlist devices defined in the core - * - * This file contains internal headers - */ - #ifndef NLID_SYSTEM_H_ #define NLID_SYSTEM_H_ -#include "netlist/analog/nlid_twoterm.h" -#include "netlist/nl_base.h" -#include "netlist/nl_setup.h" -#include "plib/putil.h" +/// +/// \file nlid_system.h +/// -namespace netlist -{ -namespace devices -{ - // ----------------------------------------------------------------------------- - // netlistparams - // ----------------------------------------------------------------------------- - - NETLIB_OBJECT(netlistparams) - { - NETLIB_CONSTRUCTOR(netlistparams) - , m_use_deactivate(*this, "USE_DEACTIVATE", false) - , m_startup_strategy(*this, "STARTUP_STRATEGY", 1) - , m_mos_capmodel(*this, "DEFAULT_MOS_CAPMODEL", 2) - , m_max_link_loops(*this, "MAX_LINK_RESOLVE_LOOPS", 100) - { - } - NETLIB_UPDATEI() { } - //NETLIB_RESETI() { } - //NETLIB_UPDATE_PARAMI() { } - public: - param_logic_t m_use_deactivate; - param_num_t<unsigned> m_startup_strategy; - param_num_t<unsigned> m_mos_capmodel; - //! How many times do we try to resolve links (connections) - param_num_t<unsigned> m_max_link_loops; - }; - - // ----------------------------------------------------------------------------- - // mainclock - // ----------------------------------------------------------------------------- - - NETLIB_OBJECT(mainclock) - { - NETLIB_CONSTRUCTOR(mainclock) - , m_Q(*this, "Q") - , m_freq(*this, "FREQ", 7159000.0 * 5) - { - m_inc = netlist_time::from_double(1.0 / (m_freq()*2.0)); - } - - NETLIB_RESETI() - { - m_Q.net().set_next_scheduled_time(netlist_time::zero()); - } - - NETLIB_UPDATE_PARAMI() - { - m_inc = netlist_time::from_double(1.0 / (m_freq()*2.0)); - } +#include "analog/nlid_twoterm.h" +#include "nl_base.h" +#include "nl_factory.h" +#include "plib/prandom.h" +#include "plib/pstonum.h" +#include "plib/putil.h" - NETLIB_UPDATEI() - { - logic_net_t &net = m_Q.net(); - // this is only called during setup ... - net.toggle_new_Q(); - net.set_next_scheduled_time(exec().time() + m_inc); - } +#include <random> - public: - logic_output_t m_Q; - netlist_time m_inc; - private: - param_double_t m_freq; - }; +namespace netlist::devices { // ----------------------------------------------------------------------------- // clock @@ -89,134 +25,99 @@ namespace devices NETLIB_OBJECT(clock) { NETLIB_CONSTRUCTOR(clock) - , m_feedback(*this, "FB") + , m_feedback(*this, "FB", NETLIB_DELEGATE(fb)) , m_Q(*this, "Q") - , m_freq(*this, "FREQ", 7159000.0 * 5.0) + , m_freq(*this, "FREQ", nlconst::magic(7159000.0 * 5.0)) + , m_supply(*this) { - m_inc = netlist_time::from_double(1.0 / (m_freq()*2.0)); + m_inc = netlist_time::from_fp(plib::reciprocal(m_freq()*nlconst::two())); - connect(m_feedback, m_Q); + connect("FB", "Q"); } - //NETLIB_RESETI(); NETLIB_UPDATE_PARAMI() { - m_inc = netlist_time::from_double(1.0 / (m_freq() * 2.0)); + m_inc = netlist_time::from_fp(plib::reciprocal(m_freq()*nlconst::two())); } - NETLIB_UPDATEI() + NETLIB_HANDLERI(fb) { - m_Q.push(!m_feedback(), m_inc); + m_Q.push(m_feedback() ^ 1, m_inc); } private: logic_input_t m_feedback; logic_output_t m_Q; - param_double_t m_freq; + param_fp_t m_freq; netlist_time m_inc; - }; + + NETLIB_NAME(power_pins) m_supply; +}; // ----------------------------------------------------------------------------- - // varclock + // variable clock // ----------------------------------------------------------------------------- NETLIB_OBJECT(varclock) { NETLIB_CONSTRUCTOR(varclock) - , m_feedback(*this, "FB") + , m_N(*this, "N", 1) + , m_func(*this,"FUNC", "T") + , m_feedback(*this, "FB", NETLIB_DELEGATE(fb)) , m_Q(*this, "Q") - , m_func(*this,"FUNC", "") - , m_compiled(this->name() + ".FUNCC", this, this->state().run_state_manager()) - , m_funcparam({0.0}) + , m_compiled(*this, "m_compiled") + , m_supply(*this) { - if (m_func() != "") - m_compiled.compile(std::vector<pstring>({{"T"}}), m_func()); - connect(m_feedback, m_Q); + if (!m_func().empty()) + { + std::vector<pstring> inputs; + + m_I.reserve(m_N()); + inputs.reserve(m_N() + 1); + m_vals.reserve(m_N() + 1); + + // add time parameter to the front + inputs.emplace_back("T"); + m_vals.push_back(nlconst::zero()); + + for (std::uint64_t i=0; i < m_N(); i++) + { + pstring input_name = plib::pfmt("A{1}")(i); + m_I.push_back(state().make_pool_object<analog_input_t>(*this, input_name, NETLIB_DELEGATE(fb))); + inputs.push_back(input_name); + m_vals.push_back(nlconst::zero()); + } + m_compiled->compile(m_func(), inputs); + } + connect("FB", "Q"); } //NETLIB_RESETI(); //NETLIB_UPDATE_PARAMI() - NETLIB_UPDATEI() - { - m_funcparam[0] = exec().time().as_double(); - const netlist_time m_inc = netlist_time::from_double(m_compiled.evaluate(m_funcparam)); - m_Q.push(!m_feedback(), m_inc); - } - private: - logic_input_t m_feedback; - logic_output_t m_Q; - - param_str_t m_func; - plib::pfunction m_compiled; - std::vector<double> m_funcparam; - }; - - // ----------------------------------------------------------------------------- - // extclock - // ----------------------------------------------------------------------------- - - NETLIB_OBJECT(extclock) - { - NETLIB_CONSTRUCTOR(extclock) - , m_freq(*this, "FREQ", 7159000.0 * 5.0) - , m_pattern(*this, "PATTERN", "1,1") - , m_offset(*this, "OFFSET", 0.0) - , m_feedback(*this, "FB") - , m_Q(*this, "Q") - , m_cnt(*this, "m_cnt", 0) - , m_off(*this, "m_off", netlist_time::zero()) + NETLIB_HANDLERI(fb) { - m_inc[0] = netlist_time::from_double(1.0 / (m_freq() * 2.0)); - - connect(m_feedback, m_Q); - - netlist_time base = netlist_time::from_double(1.0 / (m_freq()*2.0)); - std::vector<pstring> pat(plib::psplit(m_pattern(),",")); - m_off = netlist_time::from_double(m_offset()); - - std::array<std::int64_t, 32> pati = { 0 }; - - m_size = static_cast<std::uint8_t>(pat.size()); - netlist_time::mult_type total = 0; - for (unsigned i=0; i<m_size; i++) - { - // FIXME: use pstonum_ne - //pati[i] = plib::pstonum<decltype(pati[i])>(pat[i]); - pati[i] = plib::pstonum<std::int64_t>(pat[i]); - total += pati[i]; - } - netlist_time ttotal = netlist_time::zero(); - auto sm1 = static_cast<uint8_t>(m_size - 1); - for (unsigned i=0; i < sm1; i++) + m_vals[0] = exec().time().as_fp<nl_fptype>(); + for (std::size_t i = 0; i < static_cast<unsigned>(m_N()); i++) { - m_inc[i] = base * pati[i]; - ttotal += m_inc[i]; + m_vals[i+1] = (*m_I[i])(); } - m_inc[sm1] = base * total - ttotal; - + const netlist_time m_inc = netlist_time::from_fp(m_compiled->evaluate(m_vals)); + m_Q.push(m_feedback() ^ 1, m_inc); } - NETLIB_UPDATEI(); - NETLIB_RESETI(); - //NETLIB_UPDATE_PARAMI(); - - NETLIB_HANDLERI(clk2); - NETLIB_HANDLERI(clk2_pow2); - - private: - - param_double_t m_freq; - param_str_t m_pattern; - param_double_t m_offset; - + using pf_type = plib::pfunction<nl_fptype>; + param_num_t<std::uint64_t> m_N; + param_str_t m_func; logic_input_t m_feedback; logic_output_t m_Q; - state_var_u8 m_cnt; - std::uint8_t m_size; - state_var<netlist_time> m_off; - std::array<netlist_time, 32> m_inc; + std::vector<device_arena::unique_ptr<analog_input_t>> m_I; + + pf_type::values_container m_vals; + state_var<pf_type> m_compiled; + + NETLIB_NAME(power_pins) m_supply; }; // ----------------------------------------------------------------------------- @@ -228,241 +129,466 @@ namespace devices NETLIB_CONSTRUCTOR(logic_input) , m_Q(*this, "Q") , m_IN(*this, "IN", false) - /* make sure we get the family first */ - , m_FAMILY(*this, "FAMILY", "FAMILY(TYPE=TTL)") + , m_supply(*this) { - set_logic_family(setup().family_from_model(m_FAMILY())); - m_Q.set_logic_family(this->logic_family()); } - NETLIB_UPDATEI() { } NETLIB_RESETI() { m_Q.initial(0); } - NETLIB_UPDATE_PARAMI() { m_Q.push(m_IN() & 1, netlist_time::from_nsec(1)); } + NETLIB_UPDATE_PARAMI() + { + //printf("%s %d\n", name().c_str(), m_IN()); + m_Q.push(m_IN() & 1, netlist_time::from_nsec(1)); + } private: logic_output_t m_Q; param_logic_t m_IN; - param_model_t m_FAMILY; + NETLIB_NAME(power_pins) m_supply; }; - NETLIB_OBJECT(analog_input) + template<std::size_t N> + NETLIB_OBJECT(logic_inputN) { - NETLIB_CONSTRUCTOR(analog_input) - , m_Q(*this, "Q") - , m_IN(*this, "IN", 0.0) + NETLIB_CONSTRUCTOR(logic_inputN) + , m_Q(*this, "Q{}") + , m_IN(*this, "IN", 0) + , m_supply(*this) { } - NETLIB_UPDATEI() { } - NETLIB_RESETI() { m_Q.initial(0.0); } - NETLIB_UPDATE_PARAMI() { m_Q.push(m_IN()); } + NETLIB_RESETI() { for (auto &q : m_Q) q.initial(0); } + NETLIB_UPDATE_PARAMI() + { + //printf("%s %d\n", name().c_str(), m_IN()); + for (std::size_t i=0; i<N; i++) + m_Q[i].push((m_IN()>>i) & 1, netlist_time::from_nsec(1)); + } private: - analog_output_t m_Q; - param_double_t m_IN; - }; + object_array_t<logic_output_t, N> m_Q; - // ----------------------------------------------------------------------------- - // nld_gnd - // ----------------------------------------------------------------------------- - - NETLIB_OBJECT(gnd) - { - NETLIB_CONSTRUCTOR(gnd) - , m_Q(*this, "Q") - { - } - NETLIB_UPDATEI() - { - m_Q.push(0.0); - } - NETLIB_RESETI() { } - protected: - analog_output_t m_Q; + param_int_t m_IN; + NETLIB_NAME(power_pins) m_supply; }; - // ----------------------------------------------------------------------------- - // nld_dummy_input - // ----------------------------------------------------------------------------- - - NETLIB_OBJECT(dummy_input) + NETLIB_OBJECT(analog_input) { - public: - NETLIB_CONSTRUCTOR(dummy_input) - , m_I(*this, "I") + NETLIB_CONSTRUCTOR(analog_input) + , m_Q(*this, "Q") + , m_IN(*this, "IN", nlconst::zero()) { } - protected: - - NETLIB_RESETI() { } - NETLIB_UPDATEI() { } + NETLIB_RESETI() { m_Q.initial(nlconst::zero()); } + NETLIB_UPDATE_PARAMI() { m_Q.push(m_IN()); } private: - analog_input_t m_I; - + analog_output_t m_Q; + param_fp_t m_IN; }; + // ----------------------------------------------------------------------------- // nld_frontier // ----------------------------------------------------------------------------- + + /// \brief Frontiers divides a netlist into sub netlist + /// + /// Example: + /// + /// Consider the following mixing stage + /// + /// R1 + /// I1 >-----1RRRR2---------+ + /// | + /// R2 | + /// I2 >-----1RRRR2---------+----------> Out + /// | + /// R + /// R3 R + /// R + /// | + /// GND + /// + /// With OPTIMIZE_FRONTIER(R2.1, R2, RX) where RX is the impedance of the + /// output connected to I2 this becomes: + /// + /// R1 + /// I1 >-----1RRRR2--------------------------------+ + /// | + /// ########################## | + /// # RX # R2 | + /// I2 >----->--+-AnIn AnOut>--RRRR--->---1RRRR2---+----------> Out + /// # | # | + /// # R # R + /// # R R2 # R3 R + /// # R # R + /// # | # | + /// # GND Frontier # GND + /// # # + /// ########################## + /// + /// As a result, provided there are no other connections between the parts + /// generating S1 and S2 the "S2 part" will now have a separate solver. + /// + /// The size (aka number of nets) of the solver for I1 will be smaller. + /// The size of the solver for I2 and the rest of the circuit will be smaller + /// as well. + /// + NETLIB_OBJECT(frontier) { - public: NETLIB_CONSTRUCTOR(frontier) - , m_RIN(*this, "m_RIN", true) - , m_ROUT(*this, "m_ROUT", true) - , m_I(*this, "_I") + , m_RIN(*this, "m_RIN", NETLIB_DELEGATE(input)) // FIXME: does not look right + , m_ROUT(*this, "m_ROUT", NETLIB_DELEGATE(input)) // FIXME: does not look right + , m_I(*this, "_I", NETLIB_DELEGATE(input)) , m_Q(*this, "_Q") - , m_p_RIN(*this, "RIN", 1.0e6) - , m_p_ROUT(*this, "ROUT", 50.0) + , m_p_RIN(*this, "RIN", nlconst::magic(1.0e6)) + , m_p_ROUT(*this, "ROUT", nlconst::magic(50.0)) { - register_subalias("I", m_RIN.m_P); - register_subalias("G", m_RIN.m_N); - connect(m_I, m_RIN.m_P); + register_sub_alias("I", "m_RIN.1"); + register_sub_alias("G", "m_RIN.2"); + connect("_I", "m_RIN.1"); - register_subalias("_OP", m_ROUT.m_P); - register_subalias("Q", m_ROUT.m_N); - connect(m_Q, m_ROUT.m_P); + register_sub_alias("_OP", "m_ROUT.1"); + register_sub_alias("Q", "m_ROUT.2"); + connect("_Q", "m_ROUT.1"); } + private: NETLIB_RESETI() { - m_RIN.set_G_V_I(1.0 / m_p_RIN(),0,0); - m_ROUT.set_G_V_I(1.0 / m_p_ROUT(),0,0); + //printf("%s: in %f out %f\n", name().c_str(), m_p_RIN(), m_p_ROUT()); + m_RIN.set_G_V_I(plib::reciprocal(m_p_RIN()),0,0); + m_ROUT.set_G_V_I(plib::reciprocal(m_p_ROUT()),0,0); } - NETLIB_UPDATEI() + NETLIB_HANDLERI(input) { m_Q.push(m_I()); } - private: - analog::NETLIB_NAME(twoterm) m_RIN; - /* Fixme: only works if the device is time-stepped - need to rework */ - analog::NETLIB_NAME(twoterm) m_ROUT; + analog::NETLIB_NAME(two_terminal) m_RIN; + analog::NETLIB_NAME(two_terminal) m_ROUT; analog_input_t m_I; analog_output_t m_Q; - param_double_t m_p_RIN; - param_double_t m_p_ROUT; + param_fp_t m_p_RIN; + param_fp_t m_p_ROUT; }; - /* ----------------------------------------------------------------------------- - * nld_function - * - * FIXME: Currently a proof of concept to get congo bongo working - * ----------------------------------------------------------------------------- */ + // ----------------------------------------------------------------------------- + // nld_function + // ----------------------------------------------------------------------------- */ NETLIB_OBJECT(function) { NETLIB_CONSTRUCTOR(function) , m_N(*this, "N", 1) - , m_func(*this, "FUNC", "A0") + , m_function(*this, "FUNC", "A0") + , m_thresh(*this, "THRESH", nlconst::zero()) , m_Q(*this, "Q") - , m_compiled(this->name() + ".FUNCC", this, this->state().run_state_manager()) + , m_compiled(*this, "m_compiled") + , m_last(*this, "m_last") { - std::vector<pstring> inps; - for (int i=0; i < m_N(); i++) + std::vector<pstring> inputs; + + m_I.reserve(m_N()); + inputs.reserve(m_N()); + m_values.reserve(m_N()); + + for (uint64_t i=0; i < m_N(); i++) { - pstring n = plib::pfmt("A{1}")(i); - m_I.push_back(pool().make_poolptr<analog_input_t>(*this, n)); - inps.push_back(n); - m_vals.push_back(0.0); + pstring input_name = plib::pfmt("A{1}")(i); + m_I.push_back(state().make_pool_object<analog_input_t>(*this, input_name, NETLIB_DELEGATE(inputs))); + inputs.push_back(input_name); + m_values.push_back(nlconst::zero()); } - m_compiled.compile(inps, m_func()); + m_compiled->compile(m_function(), inputs); } protected: + NETLIB_RESETI() + { + //m_Q.initial(0.0); + } - NETLIB_RESETI(); - NETLIB_UPDATEI(); + NETLIB_HANDLERI(inputs) + { + for (std::size_t i = 0; i < static_cast<unsigned>(m_N()); i++) + { + m_values[i] = (*m_I[i])(); + } + auto result = m_compiled->evaluate(m_values); + if (plib::abs(m_last - result) >= m_thresh) + { + m_Q.push(result); + m_last = result; + } + } private: - - param_int_t m_N; - param_str_t m_func; + using pf_type = plib::pfunction<nl_fptype>; + param_num_t<std::uint64_t> m_N; + param_str_t m_function; + param_fp_t m_thresh; analog_output_t m_Q; - std::vector<pool_owned_ptr<analog_input_t>> m_I; + std::vector<device_arena::unique_ptr<analog_input_t>> m_I; + + pf_type::values_container m_values; + state_var<pf_type> m_compiled; + state_var<nl_fptype> m_last; - std::vector<double> m_vals; - plib::pfunction m_compiled; }; // ----------------------------------------------------------------------------- - // nld_res_sw + // nld_sys_dsw1 // ----------------------------------------------------------------------------- - NETLIB_OBJECT(res_sw) + NETLIB_OBJECT(sys_dsw1) { - public: - NETLIB_CONSTRUCTOR(res_sw) + NETLIB_CONSTRUCTOR(sys_dsw1) + , m_RON(*this, "RON", nlconst::one()) + , m_ROFF(*this, "ROFF", nlconst::magic(1.0E20)) , m_R(*this, "_R") - , m_I(*this, "I") - , m_RON(*this, "RON", 1.0) - , m_ROFF(*this, "ROFF", 1.0E20) + , m_I(*this, "I", NETLIB_DELEGATE(input)) , m_last_state(*this, "m_last_state", 0) { - register_subalias("1", m_R.m_P); - register_subalias("2", m_R.m_N); + register_sub_alias("1", "_R.1"); + register_sub_alias("2", "_R.2"); + } + + NETLIB_RESETI() + { + m_last_state = 0; + m_R().set_R(m_ROFF()); } - NETLIB_RESETI(); //NETLIB_UPDATE_PARAMI(); - NETLIB_UPDATEI(); - analog::NETLIB_SUB(R_base) m_R; - logic_input_t m_I; - param_double_t m_RON; - param_double_t m_ROFF; + //FIXME: used by 74123 + + const terminal_t &P() const noexcept { return m_R().P(); } + const terminal_t &N() const noexcept { return m_R().N(); } + const logic_input_t &I() const noexcept { return m_I; } + + param_fp_t m_RON; + param_fp_t m_ROFF; private: + NETLIB_HANDLERI(input) + { + const netlist_sig_t state = m_I(); + if (state != m_last_state) + { + m_last_state = state; + const nl_fptype R = (state != 0) ? m_RON() : m_ROFF(); + + m_R().change_state([this, &R]() + { + m_R().set_R(R); + }); + } + } + + NETLIB_SUB_NS(analog, R_base) m_R; + logic_input_t m_I; state_var<netlist_sig_t> m_last_state; }; // ----------------------------------------------------------------------------- - // power pins - not a device, but a helper + // nld_sys_dsw2 // ----------------------------------------------------------------------------- - /** - * Power Pins are passive inputs. Delegate noop will silently ignore any - * updates. - */ - class nld_power_pins + NETLIB_OBJECT(sys_dsw2) { - public: - nld_power_pins(device_t &owner, const char *sVCC = "VCC", const char *sGND = "GND", bool force_analog_input = false) + NETLIB_CONSTRUCTOR(sys_dsw2) + , m_R1(*this, "_R1") + , m_R2(*this, "_R2") + , m_I(*this, "I", NETLIB_DELEGATE(input)) + , m_GON(*this, "GON", nlconst::magic(1e9)) // FIXME: all switches should have some on value + , m_GOFF(*this, "GOFF", nlconst::cgmin()) + , m_power_pins(*this) + { + // connect and register pins + register_sub_alias("1", "_R1.1"); + register_sub_alias("2", "_R1.2"); + register_sub_alias("3", "_R2.2"); + connect("_R1.2", "_R2.1"); + } + + private: + NETLIB_RESETI() + { + m_R1().set_G(m_GOFF()); + m_R2().set_G(m_GON()); + } + + //NETLIB_UPDATE_PARAMI(); + + NETLIB_HANDLERI(input) { - if (owner.setup().is_validation() || force_analog_input) + const netlist_sig_t state = m_I(); + + //printf("Here %d\n", state); + const nl_fptype G1 = (state != 0) ? m_GON() : m_GOFF(); + const nl_fptype G2 = (state != 0) ? m_GOFF() : m_GON(); + if (m_R1().solver() == m_R2().solver()) { - m_GND = plib::make_unique<analog_input_t>(owner, sGND, NETLIB_DELEGATE(power_pins, noop)); - m_VCC = plib::make_unique<analog_input_t>(owner, sVCC, NETLIB_DELEGATE(power_pins, noop)); + m_R1().change_state([this, &G1, &G2]() + { + m_R1().set_G(G1); + m_R2().set_G(G2); + }); } else { - owner.create_and_register_subdevice(sPowerDevRes, m_RVG); - owner.register_subalias(sVCC, "_RVG.1"); - owner.register_subalias(sGND, "_RVG.2"); + m_R1().change_state([this, &G1]() + { + m_R1().set_G(G1); + }); + m_R2().change_state([this, &G2]() + { + m_R2().set_G(G2); + }); + } + } + + NETLIB_SUB_NS(analog, R_base) m_R1; + NETLIB_SUB_NS(analog, R_base) m_R2; + logic_input_t m_I; + param_fp_t m_GON; + param_fp_t m_GOFF; + + nld_power_pins m_power_pins; + }; + + + // ----------------------------------------------------------------------------- + // nld_sys_comp + // ----------------------------------------------------------------------------- + + NETLIB_OBJECT(sys_compd) + { + NETLIB_CONSTRUCTOR(sys_compd) + , m_IP(*this, "IP", NETLIB_DELEGATE(inputs)) + , m_IN(*this, "IN", NETLIB_DELEGATE(inputs)) + , m_Q(*this, "Q") + , m_QQ(*this, "QQ") + , m_power_pins(*this) + , m_last_state(*this, "m_last_state", 2) // ensure first execution + { + } + + private: + NETLIB_RESETI() + { + m_last_state = 0; + } + + //NETLIB_UPDATE_PARAMI(); + + NETLIB_HANDLERI(inputs) + { + const netlist_sig_t state = (m_IP() > m_IN()); + if (state != m_last_state) + { + m_last_state = state; + // FIXME: make timing a parameter + m_Q.push(state, NLTIME_FROM_NS(10)); + m_QQ.push(!state, NLTIME_FROM_NS(10)); } } - /* FIXME: this will seg-fault if force_analog_input = false */ - nl_double VCC() const NL_NOEXCEPT { return m_VCC->Q_Analog(); } - nl_double GND() const NL_NOEXCEPT { return m_GND->Q_Analog(); } + analog_input_t m_IP; + analog_input_t m_IN; + logic_output_t m_Q; + logic_output_t m_QQ; + nld_power_pins m_power_pins; - NETLIB_SUBXX(analog, R) m_RVG; // dummy resistor between VCC and GND + state_var<netlist_sig_t> m_last_state; + }; + + /// + /// \brief noise source + /// + /// An externally clocked noise source. The noise acts as a voltage source + /// with internal resistance RI. + /// + /// Since a new random value is used on each state change on I the effective + /// frequency is clock source frequency times two! + /// + /// Typical application: + /// + /// VCC + /// | + /// R + /// R + /// R + /// | + /// +-----> Output + /// | + /// +-------+ + /// | 1 | + /// --->| I | + /// | 2 | + /// +-------+ + /// | + /// R + /// R + /// R + /// | + /// GND + /// + // ----------------------------------------------------------------------------- + template <typename E, template<class> class D> + NETLIB_OBJECT(sys_noise) + { + public: + + using engine = E; + using distribution = D<nl_fptype>; + + NETLIB_CONSTRUCTOR(sys_noise) + , m_T(*this, "m_T") + , m_I(*this, "I", NETLIB_DELEGATE(input)) + , m_RI(*this, "RI", nlconst::magic(0.1)) + , m_sigma(*this, "SIGMA", nlconst::zero()) + , m_mt(*this, "m_mt") + , m_dis(*this, "m_dis",m_sigma()) + { + + register_sub_alias("1", "m_T.1"); + register_sub_alias("2", "m_T.2"); + } private: - void noop() { } - plib::unique_ptr<analog_input_t> m_VCC; // only used during validation or force_analog_input - plib::unique_ptr<analog_input_t> m_GND; // only used during validation or force_analog_input + NETLIB_HANDLERI(input) + { + nl_fptype val = m_dis()(m_mt()); + m_T().change_state([this, val]() + { + m_T().set_G_V_I(plib::reciprocal(m_RI()), val, nlconst::zero()); + }); + } + + NETLIB_RESETI() + { + m_T().set_G_V_I(plib::reciprocal(m_RI()), nlconst::zero(), nlconst::zero()); + } + + NETLIB_SUB_NS(analog, two_terminal) m_T; + logic_input_t m_I; + param_fp_t m_RI; + param_fp_t m_sigma; + state_var<engine> m_mt; + state_var<distribution> m_dis; }; -} //namespace devices -} // namespace netlist +} // namespace netlist::devices -#endif /* NLD_SYSTEM_H_ */ +#endif // NLD_SYSTEM_H_ |