trunk/src/emu/netlist/nl_base.h
| r26539 | r26540 | |
| 251 | 251 | RESISTOR = 4, // Resistor |
| 252 | 252 | CAPACITOR = 5, // Capacitor |
| 253 | 253 | DIODE = 6, // Diode |
| 254 | | BJT_SWITCH_NPN = 7, // BJT(Switch) |
| 254 | BJT_SWITCH = 7, // BJT(Switch) |
| 255 | 255 | }; |
| 256 | 256 | |
| 257 | 257 | ATTR_COLD netlist_object_t(const type_t atype, const family_t afamily); |
| r26539 | r26540 | |
| 346 | 346 | double m_Idr; // drive current |
| 347 | 347 | double m_g; // conductance |
| 348 | 348 | |
| 349 | netlist_terminal_t *m_otherterm; |
| 349 | 350 | }; |
| 350 | 351 | |
| 351 | 352 | |
| r26539 | r26540 | |
| 489 | 490 | ATTR_HOT inline void push_to_queue(const netlist_time &delay); |
| 490 | 491 | ATTR_HOT bool is_queued() { return m_in_queue == 1; } |
| 491 | 492 | |
| 493 | // m_terms is only used by analog subsystem |
| 494 | typedef netlist_list_t<netlist_terminal_t *> terminal_list_t; |
| 495 | terminal_list_t m_terms; |
| 496 | |
| 492 | 497 | protected: |
| 493 | 498 | |
| 494 | 499 | /* prohibit use in device functions |
trunk/src/emu/netlist/devices/nld_twoterm.h
| r26539 | r26540 | |
| 65 | 65 | class NETLIB_NAME(twoterm) : public netlist_device_t |
| 66 | 66 | { |
| 67 | 67 | public: |
| 68 | | ATTR_COLD NETLIB_NAME(twoterm)(const family_t afamily) |
| 69 | | : netlist_device_t(afamily), m_g(0.0), m_V(0.0), m_I(0.0) { } |
| 68 | ATTR_COLD NETLIB_NAME(twoterm)(const family_t afamily); |
| 70 | 69 | |
| 71 | 70 | netlist_terminal_t m_P; |
| 72 | 71 | netlist_terminal_t m_N; |
| 73 | 72 | |
| 74 | 73 | virtual NETLIB_UPDATE_TERMINALS() |
| 75 | 74 | { |
| 76 | | m_P.m_g = m_N.m_g = m_g; |
| 77 | | m_N.m_Idr = (m_P.net().Q_Analog() - m_V) * m_g + m_I; |
| 78 | | m_P.m_Idr = (m_N.net().Q_Analog() + m_V) * m_g - m_I; |
| 79 | | //printf("%f %f %f %f\n", m_N.m_Idr, m_P.m_Idr, m_N.net().Q_Analog(), m_P.net().Q_Analog()); |
| 80 | 75 | } |
| 76 | |
| 77 | ATTR_HOT inline void set(const double G, const double V, const double I) |
| 78 | { |
| 79 | m_P.m_g = m_N.m_g = G; |
| 80 | m_N.m_Idr = ( -V) * G + I; |
| 81 | m_P.m_Idr = ( V) * G - I; |
| 82 | } |
| 81 | 83 | protected: |
| 82 | 84 | ATTR_COLD virtual void start(); |
| 83 | 85 | ATTR_HOT ATTR_ALIGN void update(); |
| 84 | 86 | |
| 85 | | double m_g; // conductance |
| 86 | | double m_V; // internal voltage source |
| 87 | | double m_I; // internal current source |
| 88 | 87 | private: |
| 89 | 88 | }; |
| 90 | 89 | |
| r26539 | r26540 | |
| 97 | 96 | public: |
| 98 | 97 | ATTR_COLD NETLIB_NAME(R)() : NETLIB_NAME(twoterm)(RESISTOR) { } |
| 99 | 98 | |
| 100 | | inline void set_R(const double R) { m_g = 1.0 / R; } |
| 99 | inline void set_R(const double R) { set(1.0 / R, 0.0, 0.0); } |
| 101 | 100 | |
| 102 | 101 | protected: |
| 103 | 102 | ATTR_COLD virtual void start(); |
| r26539 | r26540 | |
| 119 | 118 | |
| 120 | 119 | ATTR_HOT void step_time(const double st) |
| 121 | 120 | { |
| 122 | | m_g = m_P.m_g = m_N.m_g = m_C.Value() / st; |
| 123 | | m_I = -m_g * (m_P.net().Q_Analog()- m_N.net().Q_Analog()); |
| 121 | double G = m_C.Value() / st; |
| 122 | double I = -G * (m_P.net().Q_Analog()- m_N.net().Q_Analog()); |
| 123 | set(G, 0.0, I); |
| 124 | 124 | } |
| 125 | 125 | |
| 126 | 126 | protected: |
| r26539 | r26540 | |
| 151 | 151 | const double eVDVt = exp(m_Vd * m_VtInv); |
| 152 | 152 | const double Id = m_Is * (eVDVt - 1.0); |
| 153 | 153 | |
| 154 | | m_g = m_Is * m_VtInv * eVDVt; |
| 154 | double G = m_Is * m_VtInv * eVDVt; |
| 155 | 155 | |
| 156 | | m_I = (Id - m_Vd * m_g); |
| 157 | | //printf("Vd: %f %f %f %f\n", m_Vd, m_g, Id, m_I); |
| 156 | double I = (Id - m_Vd * G); |
| 158 | 157 | |
| 159 | | NETLIB_NAME(twoterm)::update_terminals(); |
| 158 | set(G, 0.0, I); |
| 160 | 159 | } |
| 161 | 160 | |
| 162 | 161 | protected: |
| r26539 | r26540 | |
| 235 | 234 | netlist_terminal_t m_C; |
| 236 | 235 | netlist_terminal_t m_E; |
| 237 | 236 | |
| 237 | netlist_terminal_t m_EB; |
| 238 | |
| 238 | 239 | protected: |
| 239 | 240 | ATTR_COLD virtual void start(); |
| 240 | 241 | |
| r26539 | r26540 | |
| 247 | 248 | { |
| 248 | 249 | public: |
| 249 | 250 | ATTR_COLD NETLIB_NAME(QBJT_switch)() |
| 250 | | : NETLIB_NAME(QBJT)(_type, BJT_SWITCH_NPN), m_gB(NETLIST_GMIN), m_gC(NETLIST_GMIN), m_V(0.0) { } |
| 251 | : NETLIB_NAME(QBJT)(_type, BJT_SWITCH), m_gB(NETLIST_GMIN), m_gC(NETLIST_GMIN), m_V(0.0) { } |
| 251 | 252 | |
| 252 | 253 | NETLIB_UPDATE_TERMINALS() |
| 253 | 254 | { |
| r26539 | r26540 | |
| 257 | 258 | double vE = m_E.net().Q_Analog(); |
| 258 | 259 | double vB = m_B.net().Q_Analog(); |
| 259 | 260 | |
| 261 | //printf("diff %f = %f - %f\n", vB - vE, vB, vE); |
| 260 | 262 | if (vB - vE < m_V ) |
| 261 | 263 | { |
| 262 | 264 | // not conducting |
| r26539 | r26540 | |
| 265 | 267 | gc = NETLIST_GMIN; |
| 266 | 268 | } |
| 267 | 269 | |
| 268 | | m_B.m_g = m_E.m_g = gb; |
| 269 | | m_C.m_g = gc; |
| 270 | m_B.m_g = m_EB.m_g = gb; |
| 271 | m_C.m_g = m_E.m_g = gc; |
| 270 | 272 | |
| 271 | | m_B.m_Idr = (vE + v) * gb; |
| 272 | | m_C.m_Idr = (vE) * gc; |
| 273 | | m_E.m_Idr = (vB - v) * gb + m_C.net().Q_Analog() * gc; |
| 273 | m_B.m_Idr = ( v) * gb; |
| 274 | m_EB.m_Idr = ( -v) * gb; |
| 275 | m_C.m_Idr = 0.0; |
| 276 | m_E.m_Idr = 0.0; |
| 274 | 277 | } |
| 275 | 278 | |
| 276 | 279 | protected: |
| 277 | 280 | |
| 278 | 281 | ATTR_COLD void update_param(); |
| 279 | 282 | |
| 280 | | double m_gB; // conductance |
| 281 | | double m_gC; // conductance |
| 283 | double m_gB; // base conductance / switch on |
| 284 | double m_gC; // collector conductance / switch on |
| 282 | 285 | double m_V; // internal voltage source |
| 286 | |
| 283 | 287 | private: |
| 284 | 288 | }; |
| 285 | 289 | |
trunk/src/emu/netlist/devices/nld_system.c
| r26539 | r26540 | |
| 129 | 129 | switch (p->type()) |
| 130 | 130 | { |
| 131 | 131 | case netlist_terminal_t::TERMINAL: |
| 132 | | m_terms.add(p); |
| 132 | switch (p->netdev().family()) |
| 133 | { |
| 134 | case CAPACITOR: |
| 135 | if (!m_steps.contains(&p->netdev())) |
| 136 | m_steps.add(&p->netdev()); |
| 137 | break; |
| 138 | case DIODE: |
| 139 | case BJT_SWITCH: |
| 140 | if (!m_dynamic.contains(&p->netdev())) |
| 141 | m_dynamic.add(&p->netdev()); |
| 142 | break; |
| 143 | default: |
| 144 | break; |
| 145 | } |
| 146 | pn->object()->m_terms.add(static_cast<netlist_terminal_t *>(p)); |
| 133 | 147 | NL_VERBOSE_OUT(("Added terminal\n")); |
| 134 | | if (p->netdev().isFamily(CAPACITOR)) |
| 135 | | if (!m_steps.contains(&p->netdev())) |
| 136 | | m_steps.add(&p->netdev()); |
| 137 | 148 | break; |
| 138 | 149 | case netlist_terminal_t::INPUT: |
| 139 | | m_inps.add(p); |
| 150 | if (!m_inps.contains(&p->netdev())) |
| 151 | m_inps.add(&p->netdev()); |
| 140 | 152 | NL_VERBOSE_OUT(("Added input\n")); |
| 141 | 153 | break; |
| 142 | 154 | default: |
| r26539 | r26540 | |
| 174 | 186 | p->object()->step_time(delta.as_double()); |
| 175 | 187 | } |
| 176 | 188 | do { |
| 189 | /* update all non-linear devices */ |
| 190 | for (dev_list_t::entry_t *p = m_dynamic.first(); p != NULL; p = m_dynamic.next(p)) |
| 191 | p->object()->update_terminals(); |
| 192 | |
| 177 | 193 | resched = false; |
| 178 | 194 | |
| 179 | 195 | for (net_list_t::entry_t *pn = m_nets.first(); pn != NULL; pn = m_nets.next(pn)) |
| r26539 | r26540 | |
| 183 | 199 | double gtot = 0; |
| 184 | 200 | double iIdr = 0; |
| 185 | 201 | |
| 186 | | for (netlist_core_terminal_t *p = net->m_head; p != NULL; p = p->m_update_list_next) |
| 202 | for (netlist_net_t::terminal_list_t::entry_t *e = net->m_terms.first(); e != NULL; e = net->m_terms.next(e)) |
| 187 | 203 | { |
| 188 | | if (p->isType(netlist_core_terminal_t::TERMINAL)) |
| 189 | | { |
| 190 | | netlist_terminal_t *pt = static_cast<netlist_terminal_t *>(p); |
| 191 | | netlist_core_device_t &dev = pt->netdev(); |
| 192 | | #if 0 |
| 193 | | switch (pt->family()) |
| 194 | | { |
| 195 | | case RESISTOR: |
| 196 | | static_cast<NETLIB_NAME(R) &>(dev).update_terminals(); |
| 197 | | break; |
| 198 | | case CAPACITOR: |
| 199 | | static_cast<NETLIB_NAME(C) &>(dev).update_terminals(); |
| 200 | | break; |
| 201 | | #if 1 |
| 202 | | case DIODE: |
| 203 | | static_cast<NETLIB_NAME(D) &>(dev).update_terminals(); |
| 204 | | break; |
| 205 | | case BJT_SWITCH_NPN: |
| 206 | | static_cast<NETLIB_NAME(QNPN_switch) &>(dev).update_terminals(); |
| 207 | | break; |
| 208 | | #endif |
| 209 | | default: |
| 210 | | dev.update_terminals(); |
| 211 | | break; |
| 212 | | } |
| 213 | | #else |
| 214 | | dev.update_terminals(); |
| 215 | | #endif |
| 216 | | gtot += pt->m_g; |
| 217 | | iIdr += pt->m_Idr; |
| 218 | | } |
| 204 | netlist_terminal_t *pt = e->object(); |
| 205 | gtot += pt->m_g; |
| 206 | iIdr += pt->m_Idr + pt->m_g * pt->m_otherterm->net().Q_Analog(); |
| 219 | 207 | } |
| 220 | 208 | |
| 221 | 209 | double new_val = iIdr / gtot; |
| r26539 | r26540 | |
| 227 | 215 | NL_VERBOSE_OUT(("Info: %d\n", pn->object()->m_num_cons)); |
| 228 | 216 | NL_VERBOSE_OUT(("New: %lld %f %f\n", netlist().time().as_raw(), netlist().time().as_double(), new_val)); |
| 229 | 217 | } |
| 230 | | } while (resched && (resched_cnt < 1)); |
| 218 | } while (resched && (resched_cnt < 5)); |
| 231 | 219 | //if (resched_cnt >= 5) |
| 232 | 220 | // printf("rescheduled\n"); |
| 233 | 221 | if (resched) |
| 234 | 222 | { |
| 235 | 223 | schedule(); |
| 236 | 224 | } |
| 237 | | #if 1 |
| 238 | 225 | else |
| 239 | | #endif |
| 240 | 226 | { |
| 241 | 227 | /* update all inputs connected */ |
| 242 | | #if 0 |
| 243 | | for (net_list_t::entry_t *pn = m_nets.first(); pn != NULL; pn = m_nets.next(pn)) |
| 244 | | { |
| 245 | | if (pn->object()->m_cur.Analog != pn->object()->m_last.Analog) |
| 246 | | { |
| 247 | | for (netlist_core_terminal_t *p = pn->object()->m_head; p != NULL; p = p->m_update_list_next) |
| 248 | | { |
| 249 | | if (p->isType(netlist_terminal_t::INPUT)) |
| 250 | | p->netdev().update_dev(); |
| 251 | | } |
| 252 | | } |
| 253 | | pn->object()->m_last.Analog = pn->object()->m_cur.Analog; |
| 254 | | } |
| 255 | | #else |
| 256 | | for (terminal_list_t::entry_t *p = m_inps.first(); p != NULL; p = m_inps.next(p)) |
| 257 | | p->object()->netdev().update_dev(); |
| 258 | | #endif |
| 228 | for (dev_list_t::entry_t *p = m_inps.first(); p != NULL; p = m_inps.next(p)) |
| 229 | p->object()->update_dev(); |
| 230 | |
| 259 | 231 | /* step circuit */ |
| 260 | 232 | if (!m_Q_step.net().is_queued()) |
| 261 | 233 | m_Q_step.net().push_to_queue(m_inc); |