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)
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
21 *------------------------------------------------------------------
24 #include "u_nodemap.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
]);
73 _lv
= prop_truth
[_lv
][newval
];
75 error(bWARNING
, "set_in_transition: lv unknown... newval %i from %i\n",
76 (int)newval
, (int)a
);
80 /*--------------------------------------------------------------------------*/
81 LOGIC_NODE::LOGIC_NODE()
93 _failure_mode("initial")
96 /*--------------------------------------------------------------------------*/
97 /* default constructor : unconnected, don't use
99 NODE_BASE::NODE_BASE()
104 _user_number(INVALID_NODE
)
107 /*--------------------------------------------------------------------------*/
109 :NODE_BASE(), _discont(disNONE
)
112 /*--------------------------------------------------------------------------*/
113 /* copy constructor : user data only
115 NODE_BASE::NODE_BASE(const NODE_BASE
& p
)
120 _user_number(p
._user_number
)
121 //_flat_number(p._flat_number)
122 //_matrix_number(INVALID_NODE)
124 assert( p
._next
== &p
);
127 /*--------------------------------------------------------------------------*/
128 CKT_NODE::CKT_NODE(const CKT_NODE
& p
)
133 /*--------------------------------------------------------------------------*/
134 NODE_BASE::NODE_BASE(const std::string
& s
, unsigned n
, const CARD_LIST
* p
)
141 //_matrix_number(INVALID_NODE)
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...
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
)
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 /*--------------------------------------------------------------------------*/
174 /*--------------------------------------------------------------------------*/
175 node_t::node_t(const node_t
& p
)
181 trace1("node_t::node_t cloning", _ttt
);
182 //assert(_ttt == _nnn->flat_number());
184 /*--------------------------------------------------------------------------*/
185 node_t::node_t(NODE
* 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
)
199 //assert(p._ttt == p._nnn->flat_number());
200 }else if (is_adp()) {
202 assert(p
._ttt
== INVALID_NODE
);
203 assert(p
._m
== INVALID_NODE
);
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
;
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 ")) {
247 }else if (Umatch(x
, "pdz ")) {
248 // fake probe 1/0 .. positive divide by zero = Infinity
249 double z1
= tr_probe_num("zero ");
251 }else if (Umatch(x
, "ndz ")) {
252 // fake probe -1/0 .. negative divide by zero = -Infinity
253 double z1
= tr_probe_num("zero ");
255 }else if (Umatch(x
, "dv ")) { // differential of v
257 }else if (Umatch(x
, "ddv ")) { // divided difference v
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 ");
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();
271 }else if (Umatch(x
, "n ")) {
272 return matrix_number();
273 }else if (Umatch(x
, "m ")) {
276 }else if (Umatch(x
, "dis{cont} ")) {
277 return _sim
->_nstat
[matrix_number()]._discont
;
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} ")) {
289 }else if (Umatch(x
, "fi{naltime} ")) {
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
);
296 return NODE_BASE::tr_probe_num(x
);
299 /*--------------------------------------------------------------------------*/
300 const std::string
NODE_BASE::long_label()const
302 string
ret(short_label());
304 if( _scope
->owner()){
305 return (_scope
->owner()->long_label() + "." + ret
);
309 if(dynamic_cast<const ADP_NODE
*>(this)){
310 return (_owner
->long_label() + "." + ret
);
313 trace1("NODE_BASE::long_label, have no parent", short_label());
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.)));
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
)
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");
370 if (is_analog() && d_iter() < a_iter()) {
371 if (_sim
->analysis_is_restore()) {untested();
372 }else if (_sim
->analysis_is_static()) {
375 if (_sim
->analysis_is_static() || _sim
->analysis_is_restore()) {
376 set_last_change_time(0);
377 store_old_last_change_time();
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());
391 restore_lv(); /* skip back one */
393 store_old_last_change_time();
394 store_old_lv(); /* save to see if it changes */
398 double sv
= v0() / f
->range
; /* new scaled voltage */
399 if (sv
>= f
->th1
) { /* logic 1 */
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;
408 }else if (sv
<= f
->th0
) { /* logic 0 */
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;
417 }else{ /* transition region */
418 double oldsv
= vt1() / f
->range
;/* old scaled voltage */
419 double diff
= sv
- oldsv
;
420 if (diff
> 0) { /* rising */
423 dont_set_quality("begin good rise");
426 if (diff
< dt
/(f
->mr
* f
->rise
)) {
427 set_bad_quality("slow rise");
429 dont_set_quality("continuing good rise");
434 set_bad_quality("positive glitch in fall");
438 set_bad_quality("negative glitch in 1");
441 set_bad_quality("initial rise");
445 }else if (diff
< 0) { /* falling */
449 set_bad_quality("positive glitch in 0");
452 set_bad_quality("negative glitch in rise");
455 if (-diff
< dt
/(f
->mf
* f
->fall
)) {
456 set_bad_quality("slow fall");
458 dont_set_quality("continuing good fall");
462 dont_set_quality("begin good fall");
466 set_bad_quality("initial fall");
470 }else{ /* hanging up in transition */
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
);
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. */
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
)
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");
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
;
515 del
= risefall
* (1 - f
->th1
);
516 set_final_time_a(final_time()+ del
);
525 del
= risefall
* f
->th0
;
526 set_final_time_a(final_time()+ del
);
533 set_final_time_a(NEVER
);
537 if(_sim
->_time0
> final_time_a()){
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());
548 }else if (_sim
->_time0
>= final_time_a()) {
551 double share
= (final_time_a() - _sim
->_time0
) / risefall
;
552 trace4("LOGIC_NODE::to_analog in between", _sim
->_time0
, final_time(),
554 double ret
= end
- (end
-start
) * share
;
558 /*--------------------------------------------------------------------------*/
559 void LOGIC_NODE::propagate()
561 assert(in_transit());
562 if (lv().is_rising()) {
564 }else if (lv().is_falling()) {
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()) {
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.
587 set_good_quality("initial dc");
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");
608 set_final_time(time
);
615 del = f->rise * (1 - f->th1);
619 del = f->fall * (f->th0);
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
644 NODE_MAP
* Map
= d
->scope()->nodes();
646 _nnn
= dynamic_cast<CKT_NODE
*>((*Map
)["0"]);
650 /*--------------------------------------------------------------------------*/
651 size_t NODE_BASE::how_many()const
654 const NODE_BASE
* n
= this;
655 while( n
->_next
!= this){
656 trace1("how_many", n
->long_label());
662 /*--------------------------------------------------------------------------*/
663 void NODE_BASE::collapse(const NODE_BASE
& to
) const
665 if(user_number()==to
.user_number()){untested();
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());
674 n
->set_user_number(to
.user_number());
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_());
687 NODE_MAP
* Map
= d
->scope()->nodes();
688 assert(Map
); USE(Map
);
691 // const NODE_BASE* n = to._nnn->user_node();
692 if(_nnn
->user_number()){
693 _nnn
->collapse( *(to
.n_()) );
695 to
.n_()->collapse(*_nnn
);
698 trace5("node_t::collapse", d
->long_label(), _ttt
, to
._ttt
, _nnn
->short_label(), to
.n_()->short_label());
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
)
717 return new_adp_node(node_name
, scope
);
719 assert( is_electrical() );
720 //assert(!_nnn); //BUG// fails on MUTUAL_L::expand after clone
723 NODE_MAP
* Map
= scope
->nodes();
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();
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
740 NODE_MAP
* Map
= scope
->nodes();
742 _nnn
= (CKT_NODE
*) Map
->new_adp_node(node_name
, scope
);
744 trace2("node_t::new_adp_node", node_name
, _nnn
->user_number());
745 _ttt
= _nnn
->user_number();
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
)
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
);
770 return new_model_adp_node(s
,d
);
772 assert( is_electrical() );
775 new_node(s
, d
->subckt());
776 } else { // happens in spice wrapper and in inductance.
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
);
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
)
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(){
813 _m
= _ttt
; // + CKT_BASE::_sim->_adp_nodes;
814 // incomplete(); need more generic approach. not now.
818 if (t_() != INVALID_NODE
) {
820 const NODE
* n
= prechecked_cast
<const NODE
*>(_nnn
);
822 _m
= to_internal(t_());
823 trace2("node_t::map", t_(), e_());
825 assert(_m
== INVALID_NODE
);
829 /*--------------------------------------------------------------------------*/
830 void node_t::map_subckt_node(uint_t
* m
, const CARD
* owner
)
832 assert( is_electrical() );
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_()])) {
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
) {
862 trace1("NODE_BASE::lookup_node... ", card
->short_label());
864 if (card
->is_device()
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());
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
);
884 /*--------------------------------------------------------------------------*/
885 void NODE::discont(DISCONT x
)
887 if (this == &ground_node
) { untested();
891 for (prop_iterator i
=_prop
.begin(); i
!=_prop
.end(); ++i
) {
892 assert(OPT::disc
==dIMM
);
897 /*--------------------------------------------------------------------------*/
898 void NODE::set_discont(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
)
911 }else if (OPT::disc
!= dIMM
){
912 }else if (to
==&ground_node
) { untested();
913 }else if (this==&ground_node
) { untested();
916 for (prop_iterator i
=to
->_prop
.begin(); i
!=to
->_prop
.end(); ++i
) {
919 (*i
)->_coprop
.insert(this);
924 for (prop_iterator i
=_coprop
.begin(); i
!=_coprop
.end(); ++i
) {
926 (*i
)->_prop
.insert(to
);
927 to
->_coprop
.insert(*i
);
930 to
->_coprop
.insert(this);
934 /*--------------------------------------------------------------------------*/
935 // vim:ts=8:sw=2:noet: