diff --git a/src/emu/netlist/devices/net_lib.c b/src/emu/netlist/devices/net_lib.c index af1296b34b4..a53ce7d9efd 100644 --- a/src/emu/netlist/devices/net_lib.c +++ b/src/emu/netlist/devices/net_lib.c @@ -786,6 +786,8 @@ void netlist_factory::initialize() ENTRY(R, NETDEV_R) ENTRY(C, NETDEV_C) ENTRY(D, NETDEV_D) + ENTRY(QPNP_switch, NETDEV_QPNP) + ENTRY(QNPN_switch, NETDEV_QNPN) ENTRY(ttl_const, NETDEV_TTL_CONST) ENTRY(analog_const, NETDEV_ANALOG_CONST) ENTRY(logic_input, NETDEV_LOGIC_INPUT) diff --git a/src/emu/netlist/devices/nld_system.c b/src/emu/netlist/devices/nld_system.c index 39e6eb8d078..a1d53629495 100644 --- a/src/emu/netlist/devices/nld_system.c +++ b/src/emu/netlist/devices/nld_system.c @@ -4,6 +4,7 @@ */ #include "nld_system.h" +#include "nld_twoterm.h" // ---------------------------------------------------------------------------------------- // netdev_const @@ -92,6 +93,8 @@ NETLIB_START(solver) register_param("FREQ", m_freq, 48000.0); m_inc = netlist_time::from_hz(m_freq.Value()); + register_param("ACCURACY", m_accuracy, 1e-3); + register_link_internal(m_fb_sync, m_Q_sync, netlist_input_t::STATE_INP_ACTIVE); register_link_internal(m_fb_step, m_Q_step, netlist_input_t::STATE_INP_ACTIVE); m_last_step = netlist_time::zero; @@ -116,6 +119,7 @@ NETLIB_NAME(solver)::~NETLIB_NAME(solver)() NETLIB_FUNC_VOID(solver, post_start, ()) { + NL_VERBOSE_OUT(("post start solver ...\n")); for (net_list_t::entry_t *pn = m_nets.first(); pn != NULL; pn = m_nets.next(pn)) { @@ -127,6 +131,9 @@ NETLIB_FUNC_VOID(solver, post_start, ()) case netlist_terminal_t::TERMINAL: m_terms.add(p); NL_VERBOSE_OUT(("Added terminal\n")); + if (p->netdev().isFamily(CAPACITOR)) + if (!m_steps.contains(&p->netdev())) + m_steps.add(&p->netdev()); break; case netlist_terminal_t::INPUT: m_inps.add(p); @@ -154,6 +161,7 @@ NETLIB_UPDATE(solver) //OUTLOGIC(m_Q, !m_Q.net().new_Q(), m_inc ); bool resched = false; + int resched_cnt = 0; netlist_time now = netlist().time(); netlist_time delta = now - m_last_step; @@ -162,38 +170,73 @@ NETLIB_UPDATE(solver) NL_VERBOSE_OUT(("Step!\n")); /* update all terminals for new time step */ m_last_step = now; - for (terminal_list_t::entry_t *p = m_terms.first(); p != NULL; p = m_terms.next(p)) - p->object()->netdev().step_time(delta.as_double()); + for (dev_list_t::entry_t *p = m_steps.first(); p != NULL; p = m_steps.next(p)) + p->object()->step_time(delta.as_double()); } - for (net_list_t::entry_t *pn = m_nets.first(); pn != NULL; pn = m_nets.next(pn)) - { - double gtot = 0; - double iIdr = 0; + do { + resched = false; - for (netlist_core_terminal_t *p = pn->object()->m_head; p != NULL; p = p->m_update_list_next) + for (net_list_t::entry_t *pn = m_nets.first(); pn != NULL; pn = m_nets.next(pn)) { - if (p->isType(netlist_core_terminal_t::TERMINAL)) + netlist_net_t *net = pn->object(); + + double gtot = 0; + double iIdr = 0; + + for (netlist_core_terminal_t *p = net->m_head; p != NULL; p = p->m_update_list_next) { - netlist_terminal_t *pt = static_cast(p); - pt->netdev().update_terminals(); - gtot += pt->m_g; - iIdr += pt->m_Idr; + if (p->isType(netlist_core_terminal_t::TERMINAL)) + { + netlist_terminal_t *pt = static_cast(p); + netlist_core_device_t &dev = pt->netdev(); +#if 0 + switch (pt->family()) + { + case RESISTOR: + static_cast(dev).update_terminals(); + break; + case CAPACITOR: + static_cast(dev).update_terminals(); + break; +#if 1 + case DIODE: + static_cast(dev).update_terminals(); + break; + case BJT_SWITCH_NPN: + static_cast(dev).update_terminals(); + break; +#endif + default: + dev.update_terminals(); + break; + } +#else + dev.update_terminals(); +#endif + gtot += pt->m_g; + iIdr += pt->m_Idr; + } } + + double new_val = iIdr / gtot; + if (fabs(new_val - net->m_cur.Analog) > m_accuracy.Value()) + resched = true; + resched_cnt++; + net->m_cur.Analog = net->m_new.Analog = new_val; + + NL_VERBOSE_OUT(("Info: %d\n", pn->object()->m_num_cons)); + NL_VERBOSE_OUT(("New: %lld %f %f\n", netlist().time().as_raw(), netlist().time().as_double(), new_val)); } - - double new_val = iIdr / gtot; - if (fabs(new_val - pn->object()->m_cur.Analog) > 1e-4) - resched = true; - pn->object()->m_cur.Analog = pn->object()->m_new.Analog = new_val; - - NL_VERBOSE_OUT(("Info: %d\n", pn->object()->m_num_cons)); - NL_VERBOSE_OUT(("New: %lld %f %f\n", netlist().time().as_raw(), netlist().time().as_double(), new_val)); - } + } while (resched && (resched_cnt < 1)); + //if (resched_cnt >= 5) + // printf("rescheduled\n"); if (resched) { schedule(); } +#if 1 else +#endif { /* update all inputs connected */ #if 0 @@ -201,7 +244,7 @@ NETLIB_UPDATE(solver) { if (pn->object()->m_cur.Analog != pn->object()->m_last.Analog) { - for (netlist_terminal_t *p = pn->object()->m_head; p != NULL; p = p->m_update_list_next) + for (netlist_core_terminal_t *p = pn->object()->m_head; p != NULL; p = p->m_update_list_next) { if (p->isType(netlist_terminal_t::INPUT)) p->netdev().update_dev(); diff --git a/src/emu/netlist/devices/nld_system.h b/src/emu/netlist/devices/nld_system.h index 3a2efa90631..0ee4f4cf046 100644 --- a/src/emu/netlist/devices/nld_system.h +++ b/src/emu/netlist/devices/nld_system.h @@ -82,6 +82,7 @@ NETLIB_DEVICE_WITH_PARAMS(clock, NETLIB_DEVICE_WITH_PARAMS(solver, typedef netlist_list_t terminal_list_t; typedef netlist_list_t net_list_t; + typedef netlist_list_t dev_list_t; netlist_ttl_input_t m_fb_sync; netlist_ttl_output_t m_Q_sync; @@ -91,6 +92,7 @@ NETLIB_DEVICE_WITH_PARAMS(solver, netlist_param_double_t m_freq; netlist_param_double_t m_sync_delay; + netlist_param_double_t m_accuracy; netlist_time m_inc; netlist_time m_last_step; @@ -98,6 +100,7 @@ NETLIB_DEVICE_WITH_PARAMS(solver, terminal_list_t m_terms; terminal_list_t m_inps; + dev_list_t m_steps; public: diff --git a/src/emu/netlist/devices/nld_twoterm.c b/src/emu/netlist/devices/nld_twoterm.c index 09e3dfa4298..407728a9889 100644 --- a/src/emu/netlist/devices/nld_twoterm.c +++ b/src/emu/netlist/devices/nld_twoterm.c @@ -94,3 +94,83 @@ NETLIB_UPDATE(D) { NETLIB_NAME(twoterm)::update(); } + +class diode +{ +public: + diode() : m_Is(1e-15), m_VT(0.0258), m_VT_inv(1.0 / m_VT) {} + diode(const double Is, const double n) + { + m_Is = Is; + m_VT = 0.0258 * n; + m_VT_inv = 1.0 / m_VT; + } + void set(const double Is, const double n) + { + m_Is = Is; + m_VT = 0.0258 * n; + m_VT_inv = 1.0 / m_VT; + } + double I(const double V) const { return m_Is * exp(V * m_VT_inv) - m_Is; } + double g(const double V) const { return m_Is * m_VT_inv * exp(V * m_VT_inv); } + double V(const double I) const { return log(1.0 + I / m_Is) * m_VT; } + double gI(const double I) const { return m_VT_inv * (I + m_Is); } + +private: + double m_Is; + double m_VT; + double m_VT_inv; +}; + +// ---------------------------------------------------------------------------------------- +// nld_Q +// ---------------------------------------------------------------------------------------- + +NETLIB_START(Q) +{ + register_param("model", m_model, ""); +} + +NETLIB_START(QBJT) +{ + NETLIB_NAME(Q)::start(); + + register_terminal("B", m_B); + register_terminal("C", m_C); + register_terminal("E", m_E); + +} + +NETLIB_UPDATE(Q) +{ + netlist().solver()->schedule(); +} + +template +NETLIB_UPDATE_PARAM(QBJT_switch<_type>) +{ + double IS = m_model.dValue("IS", 1e-15); + double BF = m_model.dValue("BF", 100); + double NF = m_model.dValue("NF", 1); + //double VJE = m_model.dValue("VJE", 0.75); + + double alpha = BF / (1.0 + BF); + + diode d(IS, NF); + + // Assume 5mA Collector current for switch operation + + if (_type == BJT_NPN) + m_V = d.V(0.005 / alpha); + else + m_V = - d.V(0.005 / alpha); + + m_gB = d.gI(0.005 / alpha); + if (m_gB < NETLIST_GMIN) + m_gB = NETLIST_GMIN; + m_gC = BF * m_gB; // very rough estimate + printf("%f %f \n", m_V, m_gB); +} + +template NETLIB_UPDATE_PARAM(QBJT_switch); +template NETLIB_UPDATE_PARAM(QBJT_switch); diff --git a/src/emu/netlist/devices/nld_twoterm.h b/src/emu/netlist/devices/nld_twoterm.h index b3aca776a90..21278d54978 100644 --- a/src/emu/netlist/devices/nld_twoterm.h +++ b/src/emu/netlist/devices/nld_twoterm.h @@ -62,18 +62,15 @@ // nld_twoterm // ---------------------------------------------------------------------------------------- -class nld_twoterm : public netlist_device_t +class NETLIB_NAME(twoterm) : public netlist_device_t { public: - nld_twoterm() - : netlist_device_t(), m_g(0.0), m_V(0.0), m_I(0.0) { } + ATTR_COLD NETLIB_NAME(twoterm)(const family_t afamily) + : netlist_device_t(afamily), m_g(0.0), m_V(0.0), m_I(0.0) { } netlist_terminal_t m_P; netlist_terminal_t m_N; -protected: - virtual void start(); - virtual NETLIB_UPDATE_TERMINALS() { m_P.m_g = m_N.m_g = m_g; @@ -81,7 +78,8 @@ protected: m_P.m_Idr = (m_N.net().Q_Analog() + m_V) * m_g - m_I; //printf("%f %f %f %f\n", m_N.m_Idr, m_P.m_Idr, m_N.net().Q_Analog(), m_P.net().Q_Analog()); } - +protected: + ATTR_COLD virtual void start(); ATTR_HOT ATTR_ALIGN void update(); double m_g; // conductance @@ -94,23 +92,30 @@ private: // nld_R // ---------------------------------------------------------------------------------------- -NETLIB_DEVICE_WITH_PARAMS_DERIVED(R, twoterm, - netlist_param_double_t m_R; - - NETLIB_UPDATE_TERMINALS() { NETLIB_NAME(twoterm)::update_terminals(); } - +class NETLIB_NAME(R) : public NETLIB_NAME(twoterm) +{ public: - inline void set_R(double R) { m_g = 1.0 / R; } + ATTR_COLD NETLIB_NAME(R)() : NETLIB_NAME(twoterm)(RESISTOR) { } -); + inline void set_R(const double R) { m_g = 1.0 / R; } + +protected: + ATTR_COLD virtual void start(); + ATTR_COLD virtual void update_param(); + ATTR_HOT ATTR_ALIGN void update(); + + netlist_param_double_t m_R; + +}; // ---------------------------------------------------------------------------------------- // nld_C // ---------------------------------------------------------------------------------------- -NETLIB_DEVICE_WITH_PARAMS_DERIVED(C, twoterm, - - netlist_param_double_t m_C; +class NETLIB_NAME(C) : public NETLIB_NAME(twoterm) +{ +public: + ATTR_COLD NETLIB_NAME(C)() : NETLIB_NAME(twoterm)(CAPACITOR) { } ATTR_HOT void step_time(const double st) { @@ -118,23 +123,23 @@ NETLIB_DEVICE_WITH_PARAMS_DERIVED(C, twoterm, m_I = -m_g * (m_P.net().Q_Analog()- m_N.net().Q_Analog()); } -); +protected: + ATTR_COLD virtual void start(); + ATTR_COLD virtual void update_param(); + ATTR_HOT ATTR_ALIGN void update(); + + netlist_param_double_t m_C; + +}; // ---------------------------------------------------------------------------------------- // nld_D // ---------------------------------------------------------------------------------------- -NETLIB_DEVICE_WITH_PARAMS_DERIVED(D, twoterm, - - netlist_param_multi_t m_model; - - double m_Vt; - double m_Is; - double m_n; - - double m_VtInv; - double m_Vcrit; - double m_Vd; +class NETLIB_NAME(D) : public NETLIB_NAME(twoterm) +{ +public: + ATTR_COLD NETLIB_NAME(D)() : NETLIB_NAME(twoterm)(DIODE) { } NETLIB_UPDATE_TERMINALS() { @@ -151,11 +156,134 @@ NETLIB_DEVICE_WITH_PARAMS_DERIVED(D, twoterm, m_I = (Id - m_Vd * m_g); //printf("Vd: %f %f %f %f\n", m_Vd, m_g, Id, m_I); - nld_twoterm::update_terminals(); + NETLIB_NAME(twoterm)::update_terminals(); } -private: -); +protected: + ATTR_COLD virtual void start(); + ATTR_COLD virtual void update_param(); + ATTR_HOT ATTR_ALIGN void update(); + netlist_param_multi_t m_model; + + double m_Vt; + double m_Is; + double m_n; + + double m_VtInv; + double m_Vcrit; + double m_Vd; + +}; + +/* + * + - C + * B ----VVV----+ | + * | | + * Rb Rc + * Rb Rc + * Rb Rc + * | | + * +----+----+ + * | + * E + */ + +#define NETDEV_QPNP(_name, _model) \ + NET_REGISTER_DEV(QPNP_switch, _name) \ + NETDEV_PARAMI(_name, model, _model) + +#define NETDEV_QNPN(_name, _model) \ + NET_REGISTER_DEV(QNPN_switch, _name) \ + NETDEV_PARAMI(_name, model, _model) + +#define NETDEV_BC238B(_name) NETDEV_QNPN(_name, "IS=1.8E-14 ISE=5.0E-14 ISC=1.72E-13 XTI=3 BF=400 BR=35.5 IKF=0.14 IKR=0.03 XTB=1.5 VAF=80 VAR=12.5 VJE=0.58 VJC=0.54 RE=0.6 RC=0.25 RB=0.56 CJE=13E-12 CJC=4E-12 XCJC=0.75 FC=0.5 NF=0.9955 NR=1.005 NE=1.46 NC=1.27 MJE=0.33 MJC=0.33 TF=0.64E-9 TR=50.72E-9 EG=1.11 KF=0 AF=1 VCEO=45V ICRATING=100M MFG=ZETEX") + +// Have a common start for transistors + +class NETLIB_NAME(Q) : public netlist_device_t +{ +public: + enum q_type { + BJT_NPN, + BJT_PNP + }; + + ATTR_COLD NETLIB_NAME(Q)(const q_type atype, const family_t afamily) + : netlist_device_t(afamily) + , m_qtype(atype) { } + + inline q_type qtype() const { return m_qtype; } + inline bool is_qtype(q_type atype) const { return m_qtype == atype; } +protected: + ATTR_COLD virtual void start(); + ATTR_HOT ATTR_ALIGN void update(); + + netlist_param_multi_t m_model; +private: + q_type m_qtype; +}; + +class NETLIB_NAME(QBJT) : public NETLIB_NAME(Q) +{ +public: + + ATTR_COLD NETLIB_NAME(QBJT)(const q_type atype, const family_t afamily) + : NETLIB_NAME(Q)(atype, afamily) { } + + netlist_terminal_t m_B; + netlist_terminal_t m_C; + netlist_terminal_t m_E; + +protected: + ATTR_COLD virtual void start(); + +private: +}; + +//NETLIB_NAME(Q) nld_Q::q_type +template +class NETLIB_NAME(QBJT_switch) : public NETLIB_NAME(QBJT) +{ +public: + ATTR_COLD NETLIB_NAME(QBJT_switch)() + : NETLIB_NAME(QBJT)(_type, BJT_SWITCH_NPN), m_gB(NETLIST_GMIN), m_gC(NETLIST_GMIN), m_V(0.0) { } + + NETLIB_UPDATE_TERMINALS() + { + double gb = m_gB; + double gc = m_gC; + double v = m_V; + double vE = m_E.net().Q_Analog(); + double vB = m_B.net().Q_Analog(); + + if (vB - vE < m_V ) + { + // not conducting + gb = NETLIST_GMIN; + v = 0; + gc = NETLIST_GMIN; + } + + m_B.m_g = m_E.m_g = gb; + m_C.m_g = gc; + + m_B.m_Idr = (vE + v) * gb; + m_C.m_Idr = (vE) * gc; + m_E.m_Idr = (vB - v) * gb + m_C.net().Q_Analog() * gc; + } + +protected: + + ATTR_COLD void update_param(); + + double m_gB; // conductance + double m_gC; // conductance + double m_V; // internal voltage source +private: +}; + +typedef NETLIB_NAME(QBJT_switch) NETLIB_NAME(QPNP_switch); +typedef NETLIB_NAME(QBJT_switch) NETLIB_NAME(QNPN_switch); #endif /* NLD_TWOTERM_H_ */ diff --git a/src/emu/netlist/nl_base.c b/src/emu/netlist/nl_base.c index e924465294a..5660803d6f8 100644 --- a/src/emu/netlist/nl_base.c +++ b/src/emu/netlist/nl_base.c @@ -197,8 +197,13 @@ ATTR_HOT ATTR_ALIGN void netlist_base_t::process_queue(INT32 &atime) // net_core_device_t // ---------------------------------------------------------------------------------------- -netlist_core_device_t::netlist_core_device_t() -: netlist_object_t(DEVICE, ALL) +ATTR_COLD netlist_core_device_t::netlist_core_device_t() +: netlist_object_t(DEVICE, GENERIC) +{ +} + +ATTR_COLD netlist_core_device_t::netlist_core_device_t(const family_t afamily) +: netlist_object_t(DEVICE, afamily) { } @@ -218,7 +223,7 @@ ATTR_COLD void netlist_core_device_t::init(netlist_setup_t &setup, const pstring } -netlist_core_device_t::~netlist_core_device_t() +ATTR_COLD netlist_core_device_t::~netlist_core_device_t() { } @@ -226,6 +231,28 @@ netlist_core_device_t::~netlist_core_device_t() // net_device_t // ---------------------------------------------------------------------------------------- +netlist_device_t::netlist_device_t() + : netlist_core_device_t(), + m_terminals(20), + m_setup(NULL), + m_variable_input_count(false) +{ +} + +netlist_device_t::netlist_device_t(const family_t afamily) + : netlist_core_device_t(afamily), + m_terminals(20), + m_setup(NULL), + m_variable_input_count(false) +{ +} + +netlist_device_t::~netlist_device_t() +{ + //NL_VERBOSE_OUT(("~net_device_t\n"); +} + + ATTR_HOT ATTR_ALIGN const netlist_sig_t netlist_core_device_t::INPLOGIC_PASSIVE(netlist_logic_input_t &inp) { if (inp.state() == netlist_input_t::STATE_INP_PASSIVE) @@ -240,19 +267,6 @@ ATTR_HOT ATTR_ALIGN const netlist_sig_t netlist_core_device_t::INPLOGIC_PASSIVE( } -netlist_device_t::netlist_device_t() - : netlist_core_device_t(), - m_terminals(20), - m_setup(NULL), - m_variable_input_count(false) -{ -} - -netlist_device_t::~netlist_device_t() -{ - //NL_VERBOSE_OUT(("~net_device_t\n"); -} - ATTR_COLD void netlist_device_t::init(netlist_setup_t &setup, const pstring &name) { netlist_core_device_t::init(setup, name); @@ -538,9 +552,9 @@ ATTR_COLD void netlist_logic_output_t::set_levels(const double low, const double ATTR_COLD double netlist_param_multi_t::dValue(const pstring &entity, const double defval) const { - pstring tmp = this->Value(); + pstring tmp = this->Value().ucase(); // .model 1N914 D(Is=2.52n Rs=.568 N=1.752 Cjo=4p M=.4 tt=20n Iave=200m Vpk=75 mfg=OnSemi type=silicon) - int p = tmp.find(entity); + int p = tmp.find(entity.ucase() + "="); if (p>=0) { int pblank = tmp.find(" ", p); diff --git a/src/emu/netlist/nl_base.h b/src/emu/netlist/nl_base.h index d63fdea0f42..76f1423e470 100644 --- a/src/emu/netlist/nl_base.h +++ b/src/emu/netlist/nl_base.h @@ -238,15 +238,20 @@ public: TERMINAL = 0, INPUT = 1, OUTPUT = 2, - DEVICE = 3, - PARAM = 4, - NET = 5 + PARAM = 3, + NET = 4, + DEVICE = 5, }; enum family_t { - LOGIC = 1, - ANALOG = 2, - CURRENT = 3, - ALL = 4 // <== devices usually fall into this category + // Terminal families + LOGIC = 1, + ANALOG = 2, + // Device families + GENERIC = 3, // <== devices usually fall into this category + RESISTOR = 4, // Resistor + CAPACITOR = 5, // Capacitor + DIODE = 6, // Diode + BJT_SWITCH_NPN = 7, // BJT(Switch) }; ATTR_COLD netlist_object_t(const type_t atype, const family_t afamily); @@ -708,6 +713,7 @@ class netlist_core_device_t : public netlist_object_t public: ATTR_COLD netlist_core_device_t(); + ATTR_COLD netlist_core_device_t(const family_t afamily); ATTR_COLD virtual ~netlist_core_device_t(); @@ -792,6 +798,7 @@ class netlist_device_t : public netlist_core_device_t public: ATTR_COLD netlist_device_t(); + ATTR_COLD netlist_device_t(const family_t afamily); ATTR_COLD virtual ~netlist_device_t(); diff --git a/src/emu/netlist/nl_lists.h b/src/emu/netlist/nl_lists.h index 7d274a3cc48..0d15d85384e 100644 --- a/src/emu/netlist/nl_lists.h +++ b/src/emu/netlist/nl_lists.h @@ -74,6 +74,15 @@ public: return; } } + } + ATTR_HOT inline bool contains(const _ListClass elem) const + { + for (entry_t *i = m_list; i <= m_ptr; i++) + { + if (i->object() == elem) + return true; + } + return false; } ATTR_HOT inline entry_t *first() const { return (m_ptr >= m_list ? &m_list[0] : NULL ); } ATTR_HOT inline entry_t *next(entry_t *lc) const { return (lc < last() ? lc + 1 : NULL ); } diff --git a/src/mame/drivers/pong.c b/src/mame/drivers/pong.c index 725c8d0db14..afd0ea416ef 100644 --- a/src/mame/drivers/pong.c +++ b/src/mame/drivers/pong.c @@ -588,6 +588,21 @@ static NETLIST_START(pong_schematics) //NETDEV_LOG(log3, 555.OUT) #endif +#if 0 + NETDEV_BC238B(Q) + NETDEV_R(RB, 1000) + NETDEV_R(RC, 1000) + + NET_C(RC.1, V5) + NET_C(RC.2, Q.C) + NET_C(RB.1, 128H) + NET_C(RB.2, Q.B) + NET_C(Q.E, GND) + //NETDEV_LOG(logB, Q.B) + //NETDEV_LOG(logC, Q.C) +#endif + + NETLIST_END