diff --git a/src/emu/netlist/devices/net_lib.c b/src/emu/netlist/devices/net_lib.c index a53ce7d9efd..7019c0fed7f 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(VCVS, NETDEV_VCVS) + ENTRY(VCCS, NETDEV_VCCS) ENTRY(QPNP_switch, NETDEV_QPNP) ENTRY(QNPN_switch, NETDEV_QNPN) ENTRY(ttl_const, NETDEV_TTL_CONST) diff --git a/src/emu/netlist/devices/nld_system.c b/src/emu/netlist/devices/nld_system.c index 97a83cfb72d..7ce75768476 100644 --- a/src/emu/netlist/devices/nld_system.c +++ b/src/emu/netlist/devices/nld_system.c @@ -103,6 +103,7 @@ ATTR_COLD void netlist_matrix_solver_t::setup(netlist_net_t::list_t &nets) m_steps.add(&p->netdev()); break; case netlist_device_t::DIODE: + //case netlist_device_t::VCVS: //case netlist_device_t::BJT_SWITCH: if (!m_dynamic.contains(&p->netdev())) m_dynamic.add(&p->netdev()); @@ -153,6 +154,7 @@ ATTR_HOT inline bool netlist_matrix_solver_t::solve() netlist_net_t *net = pn->object(); double gtot = 0; + double gabs = 0; double iIdr = 0; const netlist_net_t::terminal_list_t &terms = net->m_terms; #if 1 @@ -161,17 +163,19 @@ ATTR_HOT inline bool netlist_matrix_solver_t::solve() case 1: { const netlist_terminal_t *pt = terms.first()->object(); - gtot = pt->m_g; - iIdr = pt->m_Idr + pt->m_g * pt->m_otherterm->net().Q_Analog(); + gtot = pt->m_gt; + gabs = fabs(pt->m_go); + iIdr = pt->m_Idr + pt->m_go * pt->m_otherterm->net().Q_Analog(); } break; case 2: { const netlist_terminal_t *pt1 = terms.first()->object(); const netlist_terminal_t *pt2 = terms.item(1)->object(); - gtot = pt1->m_g + pt2->m_g; - iIdr = pt1->m_Idr + pt1->m_g * pt1->m_otherterm->net().Q_Analog() - + pt2->m_Idr + pt2->m_g * pt2->m_otherterm->net().Q_Analog(); + gtot = pt1->m_gt + pt2->m_gt; + gabs = fabs(pt1->m_go) + fabs(pt2->m_go); + iIdr = pt1->m_Idr + pt1->m_go * pt1->m_otherterm->net().Q_Analog() + + pt2->m_Idr + pt2->m_go * pt2->m_otherterm->net().Q_Analog(); } break; case 3: @@ -179,18 +183,20 @@ ATTR_HOT inline bool netlist_matrix_solver_t::solve() const netlist_terminal_t *pt1 = terms.first()->object(); const netlist_terminal_t *pt2 = terms.item(1)->object(); const netlist_terminal_t *pt3 = terms.item(2)->object(); - gtot = pt1->m_g + pt2->m_g + pt3->m_g; - iIdr = pt1->m_Idr + pt1->m_g * pt1->m_otherterm->net().Q_Analog() - + pt2->m_Idr + pt2->m_g * pt2->m_otherterm->net().Q_Analog() - + pt3->m_Idr + pt3->m_g * pt3->m_otherterm->net().Q_Analog(); + gtot = pt1->m_gt + pt2->m_gt + pt3->m_gt; + gabs = fabs(pt1->m_go) + fabs(pt2->m_go) + fabs(pt3->m_go); + iIdr = pt1->m_Idr + pt1->m_go * pt1->m_otherterm->net().Q_Analog() + + pt2->m_Idr + pt2->m_go * pt2->m_otherterm->net().Q_Analog() + + pt3->m_Idr + pt3->m_go * pt3->m_otherterm->net().Q_Analog(); } break; default: for (netlist_net_t::terminal_list_t::entry_t *e = terms.first(); e != NULL; e = terms.next(e)) { netlist_terminal_t *pt = e->object(); - gtot += pt->m_g; - iIdr += pt->m_Idr + pt->m_g * pt->m_otherterm->net().Q_Analog(); + gtot += pt->m_gt; + gabs += fabs(pt->m_go); + iIdr += pt->m_Idr + pt->m_go * pt->m_otherterm->net().Q_Analog(); } break; } @@ -198,11 +204,18 @@ ATTR_HOT inline bool netlist_matrix_solver_t::solve() for (netlist_net_t::terminal_list_t::entry_t *e = terms.first(); e != NULL; e = terms.next(e)) { netlist_terminal_t *pt = e->object(); - gtot += pt->m_g; - iIdr += pt->m_Idr + pt->m_g * pt->m_otherterm->net().Q_Analog(); + gtot += pt->m_gt; + gabs += fabs(pt->m_go); + iIdr += pt->m_Idr + pt->m_go * pt->m_otherterm->net().Q_Analog(); } #endif - double new_val = iIdr / gtot; + double new_val; + gabs *= m_convergence_factor; + if (gabs > gtot) + new_val = (net->m_cur.Analog * gabs + iIdr) / (gtot + gabs); + else + new_val = iIdr / gtot; + if (fabs(new_val - net->m_cur.Analog) > m_accuracy) resched = true; net->m_cur.Analog = net->m_new.Analog = new_val; @@ -261,6 +274,7 @@ NETLIB_START(solver) m_inc = netlist_time::from_hz(m_freq.Value()); register_param("ACCURACY", m_accuracy, 1e-3); + register_param("CONVERG", m_convergence, 0.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); @@ -329,6 +343,7 @@ NETLIB_FUNC_VOID(solver, post_start, ()) { netlist_matrix_solver_t *ms = new netlist_matrix_solver_t; ms->m_accuracy = m_accuracy.Value(); + ms->m_convergence_factor = m_convergence.Value(); ms->setup(groups[i]); m_mat_solvers.add(ms); printf("%d ==> %d nets %s\n", i, groups[i].count(), groups[i].first()->object()->m_head->name().cstr()); @@ -367,8 +382,8 @@ NETLIB_UPDATE(solver) } while ((resched && (resched_cnt < 5)) || (resched_cnt <= 1)); global_resched = global_resched || resched; } - if (global_resched) - printf("rescheduled\n"); + //if (global_resched) + // printf("rescheduled\n"); if (global_resched) { schedule(); diff --git a/src/emu/netlist/devices/nld_system.h b/src/emu/netlist/devices/nld_system.h index 9031bce3e6e..ff3391a28b6 100644 --- a/src/emu/netlist/devices/nld_system.h +++ b/src/emu/netlist/devices/nld_system.h @@ -94,6 +94,7 @@ public: ATTR_HOT inline bool is_dynamic() { return m_dynamic.count() > 0; } double m_accuracy; + double m_convergence_factor; private: netlist_net_t::list_t m_nets; @@ -114,6 +115,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_param_double_t m_convergence; netlist_time m_inc; netlist_time m_last_step; diff --git a/src/emu/netlist/devices/nld_twoterm.c b/src/emu/netlist/devices/nld_twoterm.c index a701ff55cc8..f70eaff458a 100644 --- a/src/emu/netlist/devices/nld_twoterm.c +++ b/src/emu/netlist/devices/nld_twoterm.c @@ -195,3 +195,84 @@ template NETLIB_START(QBJT_switch); template NETLIB_START(QBJT_switch); template NETLIB_UPDATE_PARAM(QBJT_switch); template NETLIB_UPDATE_PARAM(QBJT_switch); + +// ---------------------------------------------------------------------------------------- +// nld_VCCS +// ---------------------------------------------------------------------------------------- + +NETLIB_START(VCCS) +{ + configure(1.0, NETLIST_GMIN); +} + +ATTR_COLD void NETLIB_NAME(VCCS)::configure(const double Gfac, const double GI) +{ + + register_param("G", m_G, 1.0); + + register_terminal("IP", m_IP); + register_terminal("IN", m_IN); + register_terminal("OP", m_OP); + register_terminal("ON", m_ON); + + m_OP1.init_object(*this, "OP1", netlist_core_terminal_t::STATE_INP_ACTIVE); + m_ON1.init_object(*this, "ON1", netlist_core_terminal_t::STATE_INP_ACTIVE); + + const double m_mult = m_G.Value() * Gfac; // 1.0 ==> 1V ==> 1A + m_IP.set(GI); + m_IP.m_otherterm = &m_IN; // <= this should be NULL and terminal be filtered out prior to solving... + m_IN.set(GI); + m_IN.m_otherterm = &m_IP; // <= this should be NULL and terminal be filtered out prior to solving... + + m_OP.set(m_mult, 0.0); + m_OP.m_otherterm = &m_IP; + m_OP1.set(-m_mult, 0.0); + m_OP1.m_otherterm = &m_IN; + + m_ON.set(-m_mult, 0.0); + m_ON.m_otherterm = &m_IP; + m_ON1.set(m_mult, 0.0); + m_ON1.m_otherterm = &m_IN; + + m_setup->connect(m_OP, m_OP1); + m_setup->connect(m_ON, m_ON1); +} + +NETLIB_UPDATE_PARAM(VCCS) +{ +} + +NETLIB_UPDATE(VCCS) +{ + /* only called if connected to a rail net ==> notify the solver to recalculate */ + netlist().solver()->schedule(); +} + +// ---------------------------------------------------------------------------------------- +// nld_VCVS +// ---------------------------------------------------------------------------------------- + +NETLIB_START(VCVS) +{ + register_param("RO", m_RO, 1.0); + + const double gRO = 1.0 / m_RO.Value(); + + configure(gRO, NETLIST_GMIN); + + m_OP2.init_object(*this, "OP2", netlist_core_terminal_t::STATE_INP_ACTIVE); + m_ON2.init_object(*this, "ON2", netlist_core_terminal_t::STATE_INP_ACTIVE); + + m_OP2.set(gRO); + m_ON2.set(gRO); + m_OP2.m_otherterm = &m_ON2; + m_ON2.m_otherterm = &m_OP2; + + setup()->connect(m_OP2, m_OP1); + setup()->connect(m_ON2, m_ON1); +} + +NETLIB_UPDATE_PARAM(VCVS) +{ +} + diff --git a/src/emu/netlist/devices/nld_twoterm.h b/src/emu/netlist/devices/nld_twoterm.h index 96df6b15f0c..f265f0b48e4 100644 --- a/src/emu/netlist/devices/nld_twoterm.h +++ b/src/emu/netlist/devices/nld_twoterm.h @@ -76,7 +76,7 @@ public: ATTR_HOT inline void set(const double G, const double V, const double I) { - m_P.m_g = m_N.m_g = G; + m_P.m_go = m_N.m_go = m_P.m_gt = m_N.m_gt = G; m_N.m_Idr = ( -V) * G + I; m_P.m_Idr = ( V) * G - I; } @@ -243,7 +243,6 @@ public: ATTR_COLD NETLIB_NAME(QBJT_switch)() : NETLIB_NAME(QBJT)(_type, BJT_SWITCH), m_gB(NETLIST_GMIN), m_gC(NETLIST_GMIN), m_V(0.0), m_state_on(0) { } -#if 1 NETLIB_UPDATEI() { double vE = INPANALOG(m_EV); @@ -271,7 +270,6 @@ public: } } -#endif NETLIB_NAME(R) m_RB; NETLIB_NAME(R) m_RC; @@ -295,4 +293,110 @@ private: typedef NETLIB_NAME(QBJT_switch) NETLIB_NAME(QPNP_switch); typedef NETLIB_NAME(QBJT_switch) NETLIB_NAME(QNPN_switch); +// ---------------------------------------------------------------------------------------- +// nld_VCCS +// ---------------------------------------------------------------------------------------- + +/* + * Voltage controlled current source + * + * IP ---+ +------> OP + * | | + * RI I + * RI => G => I IOut = (V(IP)-V(IN)) * G + * RI I + * | | + * IN ---+ +------< ON + * + * G=1 ==> 1V ==> 1A + * + * RI = 1 / NETLIST_GMIN + * + */ + +#define NETDEV_VCCS(_name) \ + NET_REGISTER_DEV(VCCS, _name) \ + +//NETDEV_PARAMI(_name, model, _model) + +class NETLIB_NAME(VCCS) : public netlist_device_t +{ +public: + ATTR_COLD NETLIB_NAME(VCCS)() + : netlist_device_t(VCCS) { } + ATTR_COLD NETLIB_NAME(VCCS)(const family_t afamily) + : netlist_device_t(afamily) { } + +protected: + ATTR_COLD virtual void start(); + ATTR_COLD virtual void update_param(); + ATTR_HOT ATTR_ALIGN void update(); + + ATTR_COLD void configure(const double Gfac, const double GI); + + netlist_terminal_t m_OP; + netlist_terminal_t m_ON; + + netlist_terminal_t m_IP; + netlist_terminal_t m_IN; + + netlist_terminal_t m_OP1; + netlist_terminal_t m_ON1; + + netlist_param_double_t m_G; +}; + +// ---------------------------------------------------------------------------------------- +// nld_VCVS +// ---------------------------------------------------------------------------------------- + +/* + * Voltage controlled voltage source + * + * Parameters: + * G Default: 1 + * RO Default: 1 (would be typically 50 for an op-amp + * + * IP ---+ +--+---- OP + * | | | + * RI I RO + * RI => G => I RO V(OP) - V(ON) = (V(IP)-V(IN)) * G + * RI I RO + * | | | + * IN ---+ +--+---- ON + * + * G=1 ==> 1V ==> 1V + * + * RI = 1 / NETLIST_GMIN + * + * Internal GI = G / RO + * + */ + +#define NETDEV_VCVS(_name) \ + NET_REGISTER_DEV(VCVS, _name) \ + +//NETDEV_PARAMI(_name, model, _model) + + +class NETLIB_NAME(VCVS) : public NETLIB_NAME(VCCS) +{ +public: + ATTR_COLD NETLIB_NAME(VCVS)() + : NETLIB_NAME(VCCS)(VCVS) { } + +protected: + ATTR_COLD virtual void start(); + ATTR_COLD virtual void update_param(); + //ATTR_HOT ATTR_ALIGN void update(); + + netlist_terminal_t m_OP2; + netlist_terminal_t m_ON2; + + double m_mult; + + netlist_param_double_t m_RO; +}; + + #endif /* NLD_TWOTERM_H_ */ diff --git a/src/emu/netlist/nl_base.c b/src/emu/netlist/nl_base.c index bf3db5ed9b2..fe5925fc32d 100644 --- a/src/emu/netlist/nl_base.c +++ b/src/emu/netlist/nl_base.c @@ -484,7 +484,8 @@ ATTR_COLD netlist_core_terminal_t::netlist_core_terminal_t(const type_t atype, c ATTR_COLD netlist_terminal_t::netlist_terminal_t() : netlist_core_terminal_t(TERMINAL, ANALOG) , m_Idr(0.0) -, m_g(NETLIST_GMIN) +, m_go(NETLIST_GMIN) +, m_gt(NETLIST_GMIN) { } diff --git a/src/emu/netlist/nl_base.h b/src/emu/netlist/nl_base.h index 731a8f2939a..d8fc46d92f4 100644 --- a/src/emu/netlist/nl_base.h +++ b/src/emu/netlist/nl_base.h @@ -270,6 +270,8 @@ public: CAPACITOR = 5, // Capacitor DIODE = 6, // Diode BJT_SWITCH = 7, // BJT(Switch) + VCVS = 8, // Voltage controlled voltage source + VCCS = 9, // Voltage controlled voltage source }; ATTR_COLD netlist_object_t(const type_t atype, const family_t afamily); @@ -362,7 +364,29 @@ public: ATTR_COLD netlist_terminal_t(); double m_Idr; // drive current - double m_g; // conductance + double m_go; // conductance for Voltage from other term + double m_gt; // conductance for total conductance + + ATTR_HOT inline void set(const double G) + { + m_Idr = 0; + m_go = m_gt = G; + } + + ATTR_HOT inline void set(const double GO, const double GT) + { + m_Idr = 0; + m_go = GO; + m_gt = GT; + } + + ATTR_HOT inline void set(const double GO, const double GT, const double I) + { + m_Idr = I; + m_go = GO; + m_gt = GT; + } + netlist_terminal_t *m_otherterm; }; @@ -834,7 +858,7 @@ public: ATTR_COLD virtual void init(netlist_setup_t &setup, const pstring &name); - ATTR_COLD const netlist_setup_t *setup() const { return m_setup; } + ATTR_COLD netlist_setup_t *setup() const { return m_setup; } ATTR_COLD bool variable_input_count() { return m_variable_input_count; } diff --git a/src/mame/drivers/pong.c b/src/mame/drivers/pong.c index afd0ea416ef..52f03b2f974 100644 --- a/src/mame/drivers/pong.c +++ b/src/mame/drivers/pong.c @@ -521,7 +521,6 @@ static NETLIST_START(pong_schematics) //NETDEV_LOG(log1, C1.1) #endif - #define tt(_n) \ NETDEV_R(R ## _n, 1000) \ NETDEV_D(D ## _n) \ @@ -602,7 +601,122 @@ static NETLIST_START(pong_schematics) //NETDEV_LOG(logC, Q.C) #endif +#if 0 + NETDEV_VCVS(VV) + NETDEV_R(R1, 1000) + NETDEV_R(R2, 10000) + NET_C(V5, R1.1) + NET_C(R1.2, VV.IN) + NET_C(R2.1, VV.OP) + NET_C(R2.2, VV.IN) + NET_C(VV.ON, GND) + NET_C(VV.IP, GND) + NETDEV_LOG(logX, VV.OP) + +#endif + +#if 0 + NETDEV_VCCS(VV) + NETDEV_PARAM(VV.G, 100000) // typical OP-AMP amplification + NETDEV_R(R1, 1000) + NETDEV_R(R2, 1) + NETDEV_R(R3, 10000) + + NET_C(4V, R1.1) + NET_C(R1.2, VV.IN) + NET_C(R2.1, VV.OP) + NET_C(R3.1, VV.IN) + NET_C(R3.2, VV.OP) + NET_C(R2.2, GND) + NET_C(VV.ON, GND) + NET_C(VV.IP, GND) + //NETDEV_LOG(logX, VV.OP) + //NETDEV_LOG(logY, 4V) + +#endif + +#if 0 + NETDEV_VCVS(VV) + NETDEV_PARAM(VV.G, 100000) // typical OP-AMP amplification + NETDEV_PARAM(VV.RO, 50) // typical OP-AMP amplification + NETDEV_R(R1, 1000) + NETDEV_R(R3, 10000) // ==> 10x amplification (inverting) + + NET_C(4V, R1.1) + NET_C(R1.2, VV.IN) + NET_C(R3.1, VV.IN) + NET_C(R3.2, VV.OP) + NET_C(VV.ON, GND) + NET_C(VV.IP, GND) + NETDEV_LOG(logX, VV.OP) + NETDEV_LOG(logY, 4V) + +#endif + +#if 0 + // Impedance converter with resistor + NETDEV_VCVS(VV) + NETDEV_PARAM(VV.G, 100000) // typical OP-AMP amplification + NETDEV_PARAM(VV.RO, 50) // typical OP-AMP amplification + NETDEV_R(R3, 10000) + + NET_C(4V, VV.IP) + NET_C(R3.1, VV.IN) + NET_C(R3.2, VV.OP) + NET_C(VV.ON, GND) + NETDEV_LOG(logX, VV.OP) + NETDEV_LOG(logY, 4V) + +#endif + +#if 0 + // Impedance converter without resistor + NETDEV_VCVS(VV) + NETDEV_PARAM(VV.G, 100000) // typical OP-AMP amplification + NETDEV_PARAM(VV.RO, 50) // typical OP-AMP amplification + + NET_C(4V, VV.IP) + NET_C(VV.IN, VV.OP) + NET_C(VV.ON, GND) + NETDEV_LOG(logX, VV.OP) + NETDEV_LOG(logY, 4V) + +#endif + +#if 0 + /* Impedance converter current source opamp model from + * + * http://www.ecircuitcenter.com/Circuits/opmodel1/opmodel1.htm + * + * Bandwidth 10Mhz + * + */ + NETDEV_VCCS(G1) + NETDEV_PARAM(G1.G, 100) // typical OP-AMP amplification 100 * 1000 = 100000 + NETDEV_R(RP1, 1000) + NETDEV_C(CP1, 1.59e-6) // <== change to 1.59e-3 for 10Khz bandwidth + NETDEV_VCVS(EBUF) + NETDEV_PARAM(EBUF.RO, 50) + NETDEV_PARAM(EBUF.G, 1) + + NET_C(G1.IP, 4V) + NET_C(G1.IN, EBUF.OP) + NET_C(EBUF.ON, GND) + + NET_C(G1.ON, GND) + NET_C(RP1.2, GND) + NET_C(CP1.2, GND) + NET_C(EBUF.IN, GND) + + NET_C(RP1.1, G1.OP) + NET_C(CP1.1, RP1.1) + NET_C(EBUF.IP, RP1.1) + + NETDEV_LOG(logX, EBUF.OP) + NETDEV_LOG(logY, 4V) + +#endif NETLIST_END