bump to -rc12
[gnucap-felix.git] / lib / e_node.cc
blob0dae3a2c8fdfb79aaa2acbe52a3fc7fb5d7a3db1
1 /* -*- C++ -*-
2 * Copyright (C) 2001 Albert Davis
3 * Author: Albert Davis <aldavis@gnu.org>
5 * This file is part of "Gnucap", the Gnu Circuit Analysis Package
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3, or (at your option)
10 * any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 * 02110-1301, USA.
21 *------------------------------------------------------------------
22 * node probes
24 #include "u_nodemap.h"
25 #include "d_logic.h"
26 #include "e_aux.h"
27 #include "u_xprobe.h"
28 #include "e_adp.h"
29 #include "e_node.h"
30 #include "io_misc.h"
31 /*--------------------------------------------------------------------------*/
32 const _LOGICVAL LOGICVAL::or_truth[lvNUM_STATES][lvNUM_STATES] = {
33 {lvSTABLE0, lvRISING, lvFALLING, lvSTABLE1, lvUNKNOWN},
34 {lvRISING, lvRISING, lvRISING, lvSTABLE1, lvRISING},
35 {lvFALLING, lvRISING, lvFALLING, lvSTABLE1, lvUNKNOWN},
36 {lvSTABLE1, lvSTABLE1, lvSTABLE1, lvSTABLE1, lvSTABLE1},
37 {lvUNKNOWN, lvRISING, lvUNKNOWN, lvSTABLE1, lvUNKNOWN}
39 /*--------------------------------------------------------------------------*/
40 const _LOGICVAL LOGICVAL::xor_truth[lvNUM_STATES][lvNUM_STATES] = {
41 {lvSTABLE0, lvRISING, lvFALLING, lvSTABLE1, lvUNKNOWN},
42 {lvRISING, lvFALLING, lvRISING, lvFALLING, lvUNKNOWN},
43 {lvFALLING, lvRISING, lvFALLING, lvRISING, lvUNKNOWN},
44 {lvSTABLE1, lvFALLING, lvRISING, lvSTABLE0, lvUNKNOWN},
45 {lvUNKNOWN, lvUNKNOWN, lvUNKNOWN, lvUNKNOWN, lvUNKNOWN}
47 /*--------------------------------------------------------------------------*/
48 const _LOGICVAL LOGICVAL::and_truth[lvNUM_STATES][lvNUM_STATES] = {
49 {lvSTABLE0, lvSTABLE0, lvSTABLE0, lvSTABLE0, lvSTABLE0},
50 {lvSTABLE0, lvRISING, lvFALLING, lvRISING, lvUNKNOWN},
51 {lvSTABLE0, lvFALLING, lvFALLING, lvFALLING, lvFALLING},
52 {lvSTABLE0, lvRISING, lvFALLING, lvSTABLE1, lvUNKNOWN},
53 {lvSTABLE0, lvUNKNOWN, lvFALLING, lvUNKNOWN, lvUNKNOWN}
55 /*--------------------------------------------------------------------------*/
56 const _LOGICVAL LOGICVAL::not_truth[lvNUM_STATES] = {
57 lvSTABLE1, lvFALLING, lvRISING, lvSTABLE0, lvUNKNOWN
59 /*--------------------------------------------------------------------------*/
60 static _LOGICVAL prop_truth[lvNUM_STATES][lvNUM_STATES] = {
61 {lvSTABLE0, lvUNKNOWN, lvUNKNOWN, lvRISING, lvUNKNOWN},
62 {lvUNKNOWN, lvUNKNOWN, lvUNKNOWN, lvUNKNOWN, lvUNKNOWN},
63 {lvUNKNOWN, lvUNKNOWN, lvUNKNOWN, lvUNKNOWN, lvUNKNOWN},
64 {lvFALLING, lvUNKNOWN, lvUNKNOWN, lvSTABLE1, lvUNKNOWN},
65 {lvFALLING, lvUNKNOWN, lvUNKNOWN, lvRISING, lvUNKNOWN}
67 /*--------------------------------------------------------------------------*/
68 inline LOGICVAL& LOGICVAL::set_in_transition(LOGICVAL newval)
70 trace3("LOGICVAL::set_in_transition", _lv ,newval, prop_truth[_lv][newval]);
72 LOGICVAL a(_lv);
73 _lv = prop_truth[_lv][newval];
74 if(_lv == lvUNKNOWN){
75 error(bWARNING, "set_in_transition: lv unknown... newval %i from %i\n",
76 (int)newval, (int)a );
78 return *this;
80 /*--------------------------------------------------------------------------*/
81 LOGIC_NODE::LOGIC_NODE()
82 :NODE(),
83 _family(0),
84 _d_iter(0),
85 _a_iter(0),
86 _final_time(0),
87 _lastchange(0),
88 _old_lastchange(0),
89 _mode(moANALOG),
90 _lv(),
91 _old_lv(),
92 _quality(qBAD),
93 _failure_mode("initial")
96 /*--------------------------------------------------------------------------*/
97 /* default constructor : unconnected, don't use
99 NODE_BASE::NODE_BASE()
100 : CKT_BASE(),
101 _owner(0),
102 _scope(0),
103 _next(this),
104 _user_number(INVALID_NODE)
107 /*--------------------------------------------------------------------------*/
108 NODE::NODE()
109 :NODE_BASE(), _discont(disNONE)
112 /*--------------------------------------------------------------------------*/
113 /* copy constructor : user data only
115 NODE_BASE::NODE_BASE(const NODE_BASE& p)
116 : CKT_BASE(p),
117 _owner(p._owner),
118 _scope(p._scope),
119 _next(this),
120 _user_number(p._user_number)
121 //_flat_number(p._flat_number)
122 //_matrix_number(INVALID_NODE)
124 assert( p._next == &p );
125 unreachable();
127 /*--------------------------------------------------------------------------*/
128 CKT_NODE::CKT_NODE(const CKT_NODE& p)
129 :NODE_BASE(p)
131 unreachable();
133 /*--------------------------------------------------------------------------*/
134 NODE_BASE::NODE_BASE(const std::string& s, unsigned n, const CARD_LIST* p)
135 :CKT_BASE(s),
136 _owner(0),
137 _scope(p),
138 _next(this),
139 _user_number(n)
140 //_flat_number(n)
141 //_matrix_number(INVALID_NODE)
143 #ifndef NDEBUG
144 // has already been caught and reported.
145 std::string::size_type first = s.find_first_of(".");
146 std::string::size_type last = s.find_last_of(".");
147 if(last != std::string::npos && last != first) {
148 // unreachable(); coil has no sckt for branch node...
150 #endif
152 trace1("NODE_BASE::NODE_BASE()" + s, n);
154 /*--------------------------------------------------------------------------*/
155 /* constructor taking a pointer : it must be valid
156 * supposedly not used, but used by a required function that is also not used
158 NODE::NODE(const NODE* p)
159 :NODE_BASE(*p)
161 unreachable();
163 /*--------------------------------------------------------------------------*/
164 /* usual initializing constructor : name and index
166 CKT_NODE::CKT_NODE(const string& s, unsigned n, const CARD_LIST*p) : NODE_BASE(s,n,p) { }
167 /*--------------------------------------------------------------------------*/
168 node_t::node_t()
169 :_nnn(0),
170 _ttt(INVALID_NODE),
171 _m(INVALID_NODE),
172 _disc(d_electrical)
174 /*--------------------------------------------------------------------------*/
175 node_t::node_t(const node_t& p)
176 :_nnn(p._nnn),
177 _ttt(p._ttt),
178 _m(p._m),
179 _disc(p._disc)
181 trace1("node_t::node_t cloning", _ttt);
182 //assert(_ttt == _nnn->flat_number());
184 /*--------------------------------------------------------------------------*/
185 node_t::node_t(NODE* n)
186 :_nnn(n),
187 _ttt(n->user_number()),
188 _m(to_internal(n->user_number())),
189 _disc(d_electrical) // incomplete. use n->discipline?
190 // (dont store disc at all (use _nnn instead)?)
192 trace3("node_t::node_t(NODE*) " , _nnn->long_label(), n->user_number(), to_internal(n->user_number()));
194 /*--------------------------------------------------------------------------*/
195 node_t& node_t::operator=(const node_t& p)
197 _disc = p._disc;
198 if (p._nnn) {
199 //assert(p._ttt == p._nnn->flat_number());
200 }else if (is_adp()) {
201 }else{
202 assert(p._ttt == INVALID_NODE);
203 assert(p._m == INVALID_NODE);
205 _nnn = p._nnn;
206 _ttt = p._ttt;
207 _m = p._m;
208 return *this;
210 /*--------------------------------------------------------------------------*/
211 LOGIC_NODE& node_t::data()const
213 assert(CKT_BASE::_sim->_nstat);
214 return CKT_BASE::_sim->_nstat[m_()];
216 /*--------------------------------------------------------------------------*/
217 double NODE_BASE::tr_probe_num(const std::string& x)const
219 if (Umatch(x, "v ")) {
220 // return v0(); denoised
221 return floor(v0()/OPT::vfloor + .5) * OPT::vfloor;
222 }else{
223 return CKT_BASE::tr_probe_num(x);
226 /*--------------------------------------------------------------------------*/
227 double NODE::tr_probe_num(const std::string& x)const
229 if (Umatch(x, "v1 ")) {
230 return floor(vt1()/OPT::vfloor + .5) * OPT::vfloor;
231 }else if (Umatch(x, "z ")) {
232 return port_impedance(node_t(const_cast<NODE*>(this)), node_t(&ground_node), _sim->_lu, 0.);
233 }else if (Umatch(x, "l{ogic} |la{stchange} |fi{naltime} |di{ter} |ai{ter} |count ")) {
234 assert(_sim->_nstat);
235 return _sim->_nstat[matrix_number()].tr_probe_num(x);
236 }else if (Umatch(x, "mdy ")) {
237 // matrix diagonal admittance
238 const BSMATRIX<double>& aaa = _sim->_aa;
239 return aaa.d(m_(),m_());
240 }else if (Umatch(x, "mdz ")) {
241 // matrix diagonal impedance
242 const BSMATRIX<double>& aaa = _sim->_aa;
243 return 1/aaa.d(m_(),m_());
244 }else if (Umatch(x, "zero ")) {
245 // fake probe: 0.0
246 return 0.0;
247 }else if (Umatch(x, "pdz ")) {
248 // fake probe 1/0 .. positive divide by zero = Infinity
249 double z1 = tr_probe_num("zero ");
250 return 1.0/z1;
251 }else if (Umatch(x, "ndz ")) {
252 // fake probe -1/0 .. negative divide by zero = -Infinity
253 double z1 = tr_probe_num("zero ");
254 return -1.0/z1;
255 }else if (Umatch(x, "dv ")) { // differential of v
256 return ( vt1() );
257 }else if (Umatch(x, "ddv ")) { // divided difference v
258 double val = 0.;
259 val = ( vdc() - v0() ) / _sim->_dt0;
260 return floor(val/OPT::vfloor + .5) * OPT::vfloor;
261 }else if (Umatch(x, "nan ")) {
262 // fake probe 0/0 = NaN
263 double z1 = tr_probe_num("zero ");
264 double z2 = tr_probe_num("zero ");
265 return z1/z2;
266 }else if (Umatch(x, "dis{cont} ")) {
267 // fake probe 0/0 = NaN
268 // assert((*this)->discont() == _sim->_nstat[matrix_number()].discont());
269 return (unsigned int) _sim->_nstat[matrix_number()].discont();
270 #ifndef NDEBUG
271 }else if (Umatch(x, "n ")) {
272 return matrix_number();
273 }else if (Umatch(x, "m ")) {
274 return m_();
275 #endif
276 }else if (Umatch(x, "dis{cont} ")) {
277 return _sim->_nstat[matrix_number()]._discont;
278 }else{
279 return NODE_BASE::tr_probe_num(x);
282 /*--------------------------------------------------------------------------*/
283 double LOGIC_NODE::tr_probe_num(const std::string& x)const
285 if (Umatch(x, "l{ogic} ")) {
286 return annotated_logic_value();
287 }else if (Umatch(x, "la{stchange} ")) {
288 return _lastchange;
289 }else if (Umatch(x, "fi{naltime} ")) {
290 return final_time();
291 }else if (Umatch(x, "di{ter} ")) {
292 return static_cast<double>(_d_iter);
293 }else if (Umatch(x, "ai{ter} ")) {
294 return static_cast<double>(_a_iter);
295 }else{
296 return NODE_BASE::tr_probe_num(x);
299 /*--------------------------------------------------------------------------*/
300 const std::string NODE_BASE::long_label()const
302 string ret(short_label());
303 if (_scope){
304 if( _scope->owner()){
305 return (_scope->owner()->long_label() + "." + ret);
307 return (ret);
308 } else if(_owner) {
309 if(dynamic_cast<const ADP_NODE*>(this)){
310 return (_owner->long_label() + "." + ret);
312 } else {
313 trace1("NODE_BASE::long_label, have no parent", short_label());
315 return ret;
317 /*--------------------------------------------------------------------------*/
318 XPROBE NODE::ac_probe_ext(const std::string& x)const
320 if (Umatch(x, "v ")) {
321 return XPROBE(vac());
322 }else if (Umatch(x, "n ")) {
323 return XPROBE(port_noise(node_t(const_cast<NODE*>(this)),node_t(&ground_node)));
324 }else if (Umatch(x, "z ")) {
325 return XPROBE(port_impedance(node_t(const_cast<NODE*>(this)),
326 node_t(&ground_node), _sim->_acx, COMPLEX(0.)));
327 }else{itested();
328 return CKT_BASE::ac_probe_ext(x);
331 /*--------------------------------------------------------------------------*/
332 /* annotated_logic_value: a printable value for probe
333 * that has secondary info encoded in its fraction part
335 double LOGIC_NODE::annotated_logic_value()const
337 return (_lv + (.1 * (OPT::transits - quality())) + (.01 * (2 - _mode)));
339 /*--------------------------------------------------------------------------*/
340 static bool newly_stable[lvUNKNOWN+1][lvUNKNOWN+1] = { // oldlv, _lv
341 /* s0 rise fall s1 u */
342 /* s0 */{false, false, false, true, false},
343 /*rise*/{false, false, false, true, false},
344 /*fall*/{true, false, false, false, false},
345 /* s1 */{true, false, false, false, false},
346 /* u */{true, false, false, true, false}
348 /*--------------------------------------------------------------------------*/
349 inline bool LOGIC_NODE::just_reached_stable()const
351 return newly_stable[old_lv()][lv()];
353 /*--------------------------------------------------------------------------*/
354 /* to_logic: set up logic data for a node, if needed
355 * If the logic data is already up to date, do nothing.
356 * else set up: logic value (_lv) and quality.
357 * Use and update _d_iter, _lastchange to keep track of what was done.
359 void LOGIC_NODE::to_logic(const MODEL_LOGIC*f)
361 assert(f);
362 if (process() && process() != f->logic_hash()) {untested();
363 set_bad_quality("logic process mismatch");
364 error(bWARNING, "node " + long_label()
365 + " logic process mismatch\nis it %s " +
366 " or " + f->long_label() + "?\n");
368 set_process(f);
370 if (is_analog() && d_iter() < a_iter()) {
371 if (_sim->analysis_is_restore()) {untested();
372 }else if (_sim->analysis_is_static()) {
373 }else{
375 if (_sim->analysis_is_static() || _sim->analysis_is_restore()) {
376 set_last_change_time(0);
377 store_old_last_change_time();
378 set_lv(lvUNKNOWN);
379 }else{
381 double dt = _sim->_time0 - last_change_time();
382 if (dt < 0.) {untested();
383 error(bPICKY, "time moving backwards. was %g, now %g, %g\n",
384 last_change_time(), _sim->_time0, _sim->_Time0);
385 dt = _sim->_time0 - old_last_change_time();
386 if (dt <= 0.) {untested();
387 throw Exception("internal error: time moving backwards, can't recover " + long_label());
388 }else{untested();
390 assert(dt > 0.);
391 restore_lv(); /* skip back one */
392 }else{
393 store_old_last_change_time();
394 store_old_lv(); /* save to see if it changes */
397 // MIXED_NODE?
398 double sv = v0() / f->range; /* new scaled voltage */
399 if (sv >= f->th1) { /* logic 1 */
400 switch (lv()) {
401 case lvSTABLE0: dont_set_quality("stable 0 to stable 1"); break;
402 case lvRISING: dont_set_quality("begin stable 1"); break;
403 case lvFALLING:untested();set_bad_quality("falling to stable 1"); break;
404 case lvSTABLE1: dont_set_quality("continuing stable 1"); break;
405 case lvUNKNOWN: set_good_quality("initial 1"); break;
407 set_lv(lvSTABLE1);
408 }else if (sv <= f->th0) { /* logic 0 */
409 switch (lv()) {
410 case lvSTABLE0: dont_set_quality("continuing stable 0"); break;
411 case lvRISING: untested();set_bad_quality("rising to stable 0"); break;
412 case lvFALLING: dont_set_quality("begin stable 0"); break;
413 case lvSTABLE1: dont_set_quality("stable 1 to stable 0"); break;
414 case lvUNKNOWN: set_good_quality("initial 0"); break;
416 set_lv(lvSTABLE0);
417 }else{ /* transition region */
418 double oldsv = vt1() / f->range;/* old scaled voltage */
419 double diff = sv - oldsv;
420 if (diff > 0) { /* rising */
421 switch (lv()) {
422 case lvSTABLE0:
423 dont_set_quality("begin good rise");
424 break;
425 case lvRISING:
426 if (diff < dt/(f->mr * f->rise)) {
427 set_bad_quality("slow rise");
428 }else{
429 dont_set_quality("continuing good rise");
431 break;
432 case lvFALLING:
433 untested();
434 set_bad_quality("positive glitch in fall");
435 break;
436 case lvSTABLE1:
437 untested();
438 set_bad_quality("negative glitch in 1");
439 break;
440 case lvUNKNOWN:
441 set_bad_quality("initial rise");
442 break;
444 set_lv(lvRISING);
445 }else if (diff < 0) { /* falling */
446 switch (lv()) {
447 case lvSTABLE0:
448 untested();
449 set_bad_quality("positive glitch in 0");
450 break;
451 case lvRISING:
452 set_bad_quality("negative glitch in rise");
453 break;
454 case lvFALLING:
455 if (-diff < dt/(f->mf * f->fall)) {
456 set_bad_quality("slow fall");
457 }else{
458 dont_set_quality("continuing good fall");
460 break;
461 case lvSTABLE1:
462 dont_set_quality("begin good fall");
463 break;
464 case lvUNKNOWN:
465 untested();
466 set_bad_quality("initial fall");
467 break;
469 set_lv(lvFALLING);
470 }else{ /* hanging up in transition */
471 untested();
472 error(bDANGER, "inflection???\n");
473 set_bad_quality("in transition but no change");
474 /* state (rise/fall) unchanged */
477 if (sv > 1.+f->over || sv < -f->over) {
478 trace2("out of range", sv, f->over);
479 // out of range
480 set_bad_quality("out of range");
482 if (just_reached_stable()) { /* A bad node gets a little better */
483 improve_quality(); /* on every good transition. */
484 } /* Eventually, it is good enough. */
485 /* A good transition is defined as */
486 /* entering a stable state from */
487 /* a transition state. */
488 set_d_iter();
489 set_last_change_time();
490 trace3(_failure_mode.c_str(), _lastchange, _quality, _lv);
493 /*--------------------------------------------------------------------------*/
494 void LOGIC_NODE::set_process(const MODEL_LOGIC* f) {_family = f->logic_hash();}
495 /*--------------------------------------------------------------------------*/
496 double LOGIC_NODE::to_analog(const MODEL_LOGIC* f)
498 assert(f);
499 if (process() && process() != f->logic_hash()) {untested();
500 error(bWARNING, "node " + long_label()
501 + " logic process mismatch\nis it %i"
502 + " or " + f->long_label() + "?\n");
504 set_process(f);
506 double start = NOT_VALID;
507 double end = NOT_VALID;
508 double del = NOT_VALID; // the analog transition will take this much longer,
509 // until final_time() + del...
510 double risefall = NOT_VALID;
512 switch (lv()) {
513 case lvRISING:
514 risefall = f->rise;
515 del = risefall * (1 - f->th1);
516 set_final_time_a(final_time()+ del);
517 case lvSTABLE1:
518 risefall = f->rise;
519 start = f->vmin;
520 end = f->vmax;
521 //end = f->vmax;
522 break;
523 case lvFALLING:
524 risefall = f->fall;
525 del = risefall * f->th0;
526 set_final_time_a(final_time()+ del);
527 case lvSTABLE0:
528 risefall = f->fall;
529 start = f->vmax;
530 end = f->vmin;
531 break;
532 case lvUNKNOWN:
533 set_final_time_a(NEVER);
534 return f->unknown;
537 if(_sim->_time0 > final_time_a()){
538 return end;
541 assert(start != NOT_VALID);
542 assert(end != NOT_VALID);
543 assert(risefall != NOT_VALID);
545 if (_sim->_time0 <= (final_time_a()-risefall)) {
546 trace1("", final_time_a());
547 return start;
548 }else if (_sim->_time0 >= final_time_a()) {
549 return end;
550 }else{
551 double share = (final_time_a() - _sim->_time0) / risefall;
552 trace4("LOGIC_NODE::to_analog in between", _sim->_time0, final_time(),
553 risefall, share );
554 double ret = end - (end-start) * share;
555 return ret;
558 /*--------------------------------------------------------------------------*/
559 void LOGIC_NODE::propagate()
561 assert(in_transit());
562 if (lv().is_rising()) {
563 set_lv(lvSTABLE1);
564 }else if (lv().is_falling()) {
565 set_lv(lvSTABLE0);
566 }else{
567 // lv no change
569 set_d_iter();
570 set_final_time(NEVER);
571 set_last_change_time();
572 assert(!(in_transit()) || final_time_a() < NEVER);
574 /*--------------------------------------------------------------------------*/
575 void LOGIC_NODE::force_initial_value(LOGICVAL v)
577 trace2("LOGIC_NODE::force_initial_value "+ short_label(), _mode, v);
578 if (_sim->analysis_is_restore()) {untested();
579 }else if (_sim->analysis_is_static()) {
580 }else{untested();
582 assert(_sim->analysis_is_static() || _sim->analysis_is_restore());
583 assert(_sim->_time0 == 0.);
584 assert(is_unknown());
585 assert(is_digital()); // fails e.g. if outputs are short.
586 set_lv(v); // BUG ??
587 set_good_quality("initial dc");
588 set_d_iter();
589 set_final_time(NEVER);
590 set_final_time_a(0); // analog transition has just ended... (good idea?)
591 set_last_change_time();
593 /*--------------------------------------------------------------------------*/
594 bool LOGIC_NODE::in_transit()const
596 return (final_time() < NEVER) ; // || (final_time_a() < NEVER);
598 /*--------------------------------------------------------------------------*/
599 /*--------------------------------------------------------------------------*/
600 void LOGIC_NODE::set_event_abs(double time, LOGICVAL v)
602 trace2("LOGIC_NODE::set_event_abs", time, v);
603 _lv.set_in_transition(v);
604 if (_sim->analysis_is_tran_dynamic() && in_transit()) {untested();
605 set_bad_quality("race");
607 set_d_iter();
608 set_final_time(time);
611 double del=0;
612 switch (lv()) {
613 case lvSTABLE1:
614 case lvRISING:
615 del = f->rise * (1 - f->th1);
616 break;
617 case lvSTABLE0:
618 case lvFALLING:
619 del = f->fall * (f->th0);
620 break;
621 default:
626 if (OPT::picky <= bTRACE) {untested();
627 error(bTRACE, "%s:%u:%g new event\n",
628 long_label().c_str(), d_iter(), final_time());
630 set_last_change_time();
632 /*--------------------------------------------------------------------------*/
633 void LOGIC_NODE::set_event(double delay, LOGICVAL v)
635 return set_event_abs(delay+_sim->_time0,v);
637 /*--------------------------------------------------------------------------*/
638 void node_t::set_to_ground(CARD* d)
640 assert( is_electrical() );
641 //assert(!_nnn); //BUG// fails on MUTUAL_L::expand after clone
642 assert(d);
644 NODE_MAP* Map = d->scope()->nodes();
645 assert(Map);
646 _nnn = dynamic_cast<CKT_NODE*>((*Map)["0"]);
647 _ttt = 0;
648 assert(_nnn);
650 /*--------------------------------------------------------------------------*/
651 size_t NODE_BASE::how_many()const
653 unsigned ret=1;
654 const NODE_BASE* n = this;
655 while( n->_next != this){
656 trace1("how_many", n->long_label());
657 ret++;
658 n = n->_next;
660 return ret;
662 /*--------------------------------------------------------------------------*/
663 void NODE_BASE::collapse(const NODE_BASE& to) const
665 if(user_number()==to.user_number()){untested();
666 return;
668 const NODE_BASE* n = this;
669 trace4("NODE_BASE::collapse", n, to.user_number(), to.how_many(), how_many());
670 set_user_number(to.user_number());
671 while( n->_next != this){
672 trace2("NODE_BASE::collapse", n, to.user_number());
673 n = n->_next;
674 n->set_user_number(to.user_number());
676 n->_next = to._next;
677 to._next = this;
679 /*--------------------------------------------------------------------------*/
680 void node_t::collapse(CARD* d, const node_t to)
682 trace3("node_t::collapse", d->long_label(), _ttt, to._ttt);
683 // assert(_m == INVALID_NODE); // not true in second init()
684 trace2("node_t::collapse", _nnn->user_number(), to.e_());
685 assert(d);
687 NODE_MAP* Map = d->scope()->nodes();
688 assert(Map); USE(Map);
689 assert(_nnn);
690 // _ttt = to._ttt;
691 // const NODE_BASE* n = to._nnn->user_node();
692 if(_nnn->user_number()){
693 _nnn->collapse( *(to.n_()) );
694 } else {
695 to.n_()->collapse(*_nnn);
697 // _nnn = to._nnn
698 trace5("node_t::collapse", d->long_label(), _ttt, to._ttt, _nnn->short_label(), to.n_()->short_label());
699 assert(_nnn);
700 // assert(e_() == to.e_());
701 // assert(t_() == to.t_());
703 /*--------------------------------------------------------------------------*/
704 /* new_node: a raw new node, as when a netlist is parsed
706 void node_t::new_node(const std::string& node_name, const CARD* d)
708 trace2("node_t::new_node", node_name, d->long_label());
709 return new_node(node_name, d->scope());
711 /*--------------------------------------------------------------------------*/
712 // same, but leave choice of scope to user.
713 void node_t::new_node(const std::string& node_name, const CARD_LIST* scope)
715 if (is_adp()){
716 untested();
717 return new_adp_node(node_name, scope);
719 assert( is_electrical() );
720 //assert(!_nnn); //BUG// fails on MUTUAL_L::expand after clone
721 assert(scope);
723 NODE_MAP* Map = scope->nodes();
724 assert(Map);
725 if(!_nnn) {
726 }else if(_nnn != (*Map)[node_name]){ untested();
727 error(bWARNING, "%s is already a node: %s\n", node_name.c_str(), _nnn->long_label().c_str());
730 _nnn = (CKT_NODE*) Map->new_node(node_name, scope);
731 _ttt = _nnn->user_number();
732 assert(_nnn);
734 /*--------------------------------------------------------------------------*/
735 void node_t::new_adp_node(const std::string& node_name, const CARD_LIST* scope)
737 // FIXME: remove, implement more generic new_node
738 assert(scope);
740 NODE_MAP* Map = scope->nodes();
741 assert(Map);
742 _nnn = (CKT_NODE*) Map->new_adp_node(node_name, scope);
743 assert(_nnn);
744 trace2("node_t::new_adp_node", node_name, _nnn->user_number());
745 _ttt = _nnn->user_number();
746 assert(_nnn);
748 /*--------------------------------------------------------------------------*/
749 /* new_model_node: a mapped new node, produced through model expansion.
750 * Not really a model_node, but a node in the subckt that is made
751 * in model expansion.
752 * Supposedly equivalent to new_node() then map_subckt_node()
753 * but it does it without building a map
755 void node_t::new_model_node(const std::string& s_in, CARD* d)
757 string s = s_in;
758 std::string::size_type dotplace = s_in.find_last_of(".");
759 if(dotplace != std::string::npos && s_in.c_str()[0]!='.'){
760 incomplete(); // this is really dangerous...
761 // sometimes dots are there "intentionally":
762 // - hack in spice wrapper
763 // - hack in d_coil.cc
764 trace1("node_t::new_model_node too long (BUG).", s_in);
765 s = s_in.substr(dotplace+1, std::string::npos);
768 if (is_adp()){
769 untested();
770 return new_model_adp_node(s,d);
772 assert( is_electrical() );
774 if (d->subckt()){
775 new_node(s, d->subckt());
776 } else { // happens in spice wrapper and in inductance.
777 assert(d->scope());
778 new_node(s, d->scope());
780 _ttt = CKT_BASE::_sim->newnode_model(); // increase global counter.
781 _nnn->set_user_number(_ttt);
782 assert(_ttt == _nnn->user_number());
784 /*--------------------------------------------------------------------------*/
785 void node_t::new_sckt_node(const std::string& node_name, const CARD_LIST* scope)
787 assert( is_electrical() );
788 std::string::size_type dotplace = node_name.find_last_of(".");
789 assert(dotplace == std::string::npos); USE(dotplace);
791 assert(scope);
792 new_node(node_name, scope);
793 _ttt = CKT_BASE::_sim->newnode_subckt(); // equal to newnode_model, but uses different counter.
794 _nnn->set_user_number(_ttt);
796 /*--------------------------------------------------------------------------*/
797 void node_t::new_model_adp_node(const std::string& s_in, CARD* d)
799 string s = s_in;
800 std::string::size_type dotplace = s_in.find_last_of(".");
801 assert(dotplace == std::string::npos); USE(dotplace);
803 // new_node(node_name, d);
804 assert (d->subckt());
805 new_adp_node(s, d->subckt());
806 _ttt = CKT_BASE::_sim->newnode_adp(); // increase global counter.
807 _nnn->set_user_number(_ttt);
808 trace2("node_t::new_model_adp_node", _ttt, s_in);
810 /*--------------------------------------------------------------------------*/
811 node_t& node_t::map(){
812 if(is_adp()){
813 _m = _ttt; // + CKT_BASE::_sim->_adp_nodes;
814 // incomplete(); need more generic approach. not now.
815 return *this;
818 if (t_() != INVALID_NODE) {
819 assert(_nnn);
820 const NODE* n = prechecked_cast<const NODE*>(_nnn);
821 assert(n); USE(n);
822 _m = to_internal(t_());
823 trace2("node_t::map", t_(), e_());
824 }else{
825 assert(_m == INVALID_NODE);
827 return *this;
829 /*--------------------------------------------------------------------------*/
830 void node_t::map_subckt_node(uint_t* m, const CARD* owner)
832 assert( is_electrical() );
833 assert(m);
834 assert(e_() !=INVALID_NODE);
835 trace5("node_t::map_subckt_node", t_(), e_(), m[0], owner->long_label(), n_()->short_label());
836 if (node_is_valid(m[e_()])) {
837 _ttt = m[e_()];
838 assert(_nnn);
839 }else{untested();
840 throw Exception(owner->long_label() + ": need more nodes");
842 //_nnn->set_flat_number(_ttt);
843 assert(node_is_valid(_ttt));
845 /*--------------------------------------------------------------------------*/
846 double NODE_BASE::tt_probe_num(const std::string& x)const{return tr_probe_num(x);}
847 XPROBE NODE_BASE::ac_probe_ext(const std::string&)const{ return XPROBE(0);}
848 /*--------------------------------------------------------------------------*/
850 /* FIXME: throw exceptions if device doesnt exist */
851 NODE_BASE* NODE_BASE::lookup_node(string nodelabel, const CARD_LIST* scope)
853 trace1("NODE_BASE::lookup_node", nodelabel);
854 std::string::size_type dotplace = nodelabel.find_first_of(".");
855 if (dotplace != std::string::npos) {
856 string node_tail = nodelabel.substr(dotplace+1, std::string::npos);
857 string container = nodelabel.substr(0, dotplace);
858 trace2("NODE_BASE::lookup_node has dot ", node_tail, container);
859 for (CARD_LIST::const_iterator
860 i = scope->begin(); i != scope->end(); ++i) {
861 CARD* card = *i;
862 trace1("NODE_BASE::lookup_node... ", card->short_label());
864 if (card->is_device()
865 && card->subckt()
866 && wmatch(card->short_label(), container)) {
867 trace1( "NODE_BASE::lookup_node dot cont: " + container + " node_tail " + node_tail , card->long_label());
868 return lookup_node(node_tail, card->subckt());
869 }else{
870 // trace1( "NODE_BASE::lookup_node no device", card->short_label());
873 trace2("NODE_BASE::lookup_node not found?! ", node_tail, container);
874 throw Exception_Cant_Find( "...", container );
876 }else{ // no dots, look here
877 trace1("PROBELIST::add_branches no dots ", nodelabel );
878 NODE_BASE* node = (*scope).node(nodelabel);
879 if(!node) throw Exception_Cant_Find( "...", nodelabel );
880 return node;
884 /*--------------------------------------------------------------------------*/
885 void NODE::discont(DISCONT x)
887 if (this == &ground_node) { untested();
888 return;
890 _discont |= x;
891 for (prop_iterator i=_prop.begin(); i!=_prop.end(); ++i) {
892 assert(OPT::disc==dIMM);
893 assert(*i!=this);
894 (*i)->_discont |= x;
897 /*--------------------------------------------------------------------------*/
898 void NODE::set_discont(DISCONT x)
900 _discont = x;
902 /*--------------------------------------------------------------------------*/
903 void node_t::register_prop(node_t& to)
905 (*this)->register_prop(to.operator->());
907 /*--------------------------------------------------------------------------*/
908 void NODE::register_prop(NODE* to)
910 if (to==this) {
911 }else if (OPT::disc != dIMM){
912 }else if (to==&ground_node) { untested();
913 }else if (this==&ground_node) { untested();
914 }else{
915 assert(to);
916 for (prop_iterator i=to->_prop.begin(); i!=to->_prop.end(); ++i) {
917 if (*i!=this) {
918 _prop.insert(*i);
919 (*i)->_coprop.insert(this);
922 _prop.insert(to);
924 for (prop_iterator i=_coprop.begin(); i!=_coprop.end(); ++i) {
925 if (*i!=to) {
926 (*i)->_prop.insert(to);
927 to->_coprop.insert(*i);
930 to->_coprop.insert(this);
934 /*--------------------------------------------------------------------------*/
935 // vim:ts=8:sw=2:noet: