bump to -rc12
[gnucap-felix.git] / lib / d_logic.cc
blobac0f8a3d6f1f4daec4f228886c6b9dd41ce2fddf
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 * logic model and device.
23 * netlist syntax:
24 * device: mxxxx out gnd vdd in1 in2 ... family gatetype
25 * model: .model mname LOGIC <args>
27 //testing=script,sparse 2006.07.17
28 #include "globals.h"
29 #include "e_subckt.h"
30 #include "u_xprobe.h"
31 #include "d_logic.h"
32 /*--------------------------------------------------------------------------*/
33 int DEV_LOGIC::_count = -1;
34 int COMMON_LOGIC::_count = -1;
35 int MODEL_LOGIC::_count = -1; // there is one in e_node.cc, and the dispatcher
36 static LOGIC_NONE Default_LOGIC(CC_STATIC);
37 /*--------------------------------------------------------------------------*/
38 static DEV_LOGIC p1;
39 static DISPATCHER<CARD>::INSTALL
40 d1(&device_dispatcher, "U|logic", &p1);
41 /*--------------------------------------------------------------------------*/
42 static MODEL_LOGIC p2(&p1);
43 static DISPATCHER<MODEL_CARD>::INSTALL
44 d2(&model_dispatcher, "logic", &p2);
45 /*--------------------------------------------------------------------------*/
46 DEV_LOGIC::DEV_LOGIC()
47 :ELEMENT(),
48 _lastchangenode(0),
49 _quality(qGOOD),
50 _failuremode("ok"),
51 _oldgatemode(moUNKNOWN),
52 _gatemode(moUNKNOWN)
54 attach_common(&Default_LOGIC);
55 _n = nodes;
56 ++_count;
58 /*--------------------------------------------------------------------------*/
59 DEV_LOGIC::DEV_LOGIC(const DEV_LOGIC& p)
60 :ELEMENT(p),
61 _lastchangenode(0),
62 _quality(qGOOD),
63 _failuremode("ok"),
64 _oldgatemode(moUNKNOWN),
65 _gatemode(moUNKNOWN)
67 assert(max_nodes() == PORTS_PER_GATE);
68 for (uint_t ii = 0; ii < max_nodes(); ++ii) {
69 nodes[ii] = p.nodes[ii];
71 _n = nodes;
72 ++_count;
74 /*--------------------------------------------------------------------------*/
75 void DEV_LOGIC::expand()
77 ELEMENT::expand();
78 const COMMON_LOGIC* c = prechecked_cast<const COMMON_LOGIC*>(common());
79 assert(c);
81 attach_model();
83 const MODEL_LOGIC* m = dynamic_cast<const MODEL_LOGIC*>(c->model());
84 if (!m) {
85 throw Exception_Model_Type_Mismatch(long_label(), c->modelname(), "logic family (LOGIC)");
86 }else{
89 std::string subckt_name(c->modelname()+c->name()+::to_string(c->incount));
90 try {
91 const CARD* model = find_looking_out(subckt_name);
93 if(!dynamic_cast<const BASE_SUBCKT*>(model)) {untested();
94 error(((!_sim->is_first_expand()) ? (bDEBUG) : (bWARNING)),
95 long_label() + ": " + subckt_name + " is not a subckt, forcing digital\n");
96 }else{
97 _gatemode = OPT::mode;
98 renew_subckt(model, scope()->params());
99 subckt()->expand();
101 }catch (Exception_Cant_Find&) {
102 error(((!_sim->is_first_expand()) ? (bDEBUG) : (bWARNING)),
103 long_label() + ": can't find subckt: \"" + subckt_name + "\", forcing digital\n");
106 assert(!is_constant()); /* is a BUG */
108 /*--------------------------------------------------------------------------*/
109 void DEV_LOGIC::tr_iwant_matrix()
111 if (subckt()) {
112 subckt()->tr_iwant_matrix();
113 }else{
115 tr_iwant_matrix_passive();
117 /*--------------------------------------------------------------------------*/
118 void DEV_LOGIC::tr_begin()
120 ELEMENT::tr_begin();
121 if (!subckt()) {
122 _gatemode = moDIGITAL;
123 _n[OUTNODE]->set_mode(_gatemode);
124 _oldgatemode = _gatemode;
125 }else{
126 _gatemode = (OPT::mode==moMIXED) ? moANALOG : OPT::mode;
127 _n[OUTNODE]->set_mode(_gatemode);
128 _oldgatemode = _gatemode;
129 subckt()->tr_begin();
132 /*--------------------------------------------------------------------------*/
133 void DEV_LOGIC::tr_restore()
134 {untested();
135 ELEMENT::tr_restore();
136 if (!subckt()) {untested();
137 _gatemode = moDIGITAL;
138 }else{untested();
139 _gatemode = (OPT::mode==moMIXED) ? moANALOG : OPT::mode;
140 subckt()->tr_restore();
143 /*--------------------------------------------------------------------------*/
144 void DEV_LOGIC::dc_advance()
146 ELEMENT::dc_advance();
148 if (_gatemode != _oldgatemode) {untested();
149 tr_unload();
150 _n[OUTNODE]->set_mode(_gatemode);
151 _oldgatemode = _gatemode;
152 }else{
154 switch (_gatemode) {
155 case moUNKNOWN: unreachable(); break;
156 case moMIXED: unreachable(); break;
157 case moANALOG:
158 assert(subckt());
159 subckt()->dc_advance();
160 break;
161 case moDIGITAL:
162 if (_n[OUTNODE]->in_transit()) {
163 //q_eval(); evalq is not used for DC
164 _n[OUTNODE]->propagate();
165 }else{
167 break;
170 /*--------------------------------------------------------------------------*/
171 /* tr_advance: the first to run on a new time step.
172 * It sets up preconditions for the new time.
174 void DEV_LOGIC::tr_advance()
176 ELEMENT::tr_advance();
178 if (_gatemode != _oldgatemode) {
179 tr_unload();
180 _n[OUTNODE]->set_mode(_gatemode);
181 _oldgatemode = _gatemode;
182 }else{
184 switch (_gatemode) {
185 case moUNKNOWN: unreachable(); break;
186 case moMIXED: unreachable(); break;
187 case moANALOG:
188 assert(subckt());
189 subckt()->tr_advance();
190 break;
191 case moDIGITAL:
192 if (_n[OUTNODE]->in_transit() || _n[OUTNODE]->final_time_a() < NEVER ) {
193 q_eval();
194 if (_sim->_time0 >= _n[OUTNODE]->final_time()) {
195 _n[OUTNODE]->propagate();
196 }else{ // untested();
198 } else if ( _n[OUTNODE]->final_time_a() < NEVER ) { untested();
199 }else{
201 break;
204 void DEV_LOGIC::tr_regress()
205 {itested();
206 ELEMENT::tr_regress();
208 if (_gatemode != _oldgatemode) {itested();
209 tr_unload();
210 _n[OUTNODE]->set_mode(_gatemode);
211 _oldgatemode = _gatemode;
212 }else{itested();
214 switch (_gatemode) {
215 case moUNKNOWN: unreachable(); break;
216 case moMIXED: unreachable(); break;
217 case moANALOG: itested();
218 assert(subckt());
219 subckt()->tr_regress();
220 break;
221 case moDIGITAL: itested();
222 if (_n[OUTNODE]->in_transit()) {itested();
223 q_eval();
224 if (_sim->_time0 >= _n[OUTNODE]->final_time()) {itested();
225 _n[OUTNODE]->propagate();
226 }else{itested();
228 }else{itested();
230 break;
233 /*--------------------------------------------------------------------------*/
234 /* tr_needs_eval
235 * in digital mode ... DC always returns true, to queue it.
236 * tran always returns false, already queued by tr_advance if needed
238 bool DEV_LOGIC::tr_needs_eval()const
240 switch (_gatemode) {
241 case moUNKNOWN: unreachable(); break;
242 case moMIXED: unreachable(); break;
243 case moDIGITAL:
244 //assert(!is_q_for_eval());
245 if (_sim->analysis_is_restore()) {untested();
246 }else if (_sim->analysis_is_static()) {
247 }else{
249 return (_sim->analysis_is_static() || _sim->analysis_is_restore());
250 case moANALOG:
251 //untested();
252 assert(!is_q_for_eval());
253 assert(subckt());
254 return subckt()->tr_needs_eval();
256 unreachable();
257 return false;
259 /*--------------------------------------------------------------------------*/
260 void DEV_LOGIC::tr_queue_eval()
262 switch (_gatemode) {
263 case moUNKNOWN: unreachable(); break;
264 case moMIXED: unreachable(); break;
265 case moDIGITAL: ELEMENT::tr_queue_eval(); break;
266 case moANALOG: assert(subckt()); subckt()->tr_queue_eval(); break;
269 /*--------------------------------------------------------------------------*/
270 bool DEV_LOGIC::tr_eval_digital()
272 assert(_gatemode == moDIGITAL);
273 if (_sim->analysis_is_restore()) {untested();
274 }else if (_sim->analysis_is_static()) {
275 }else{
277 if (_sim->analysis_is_static() || _sim->analysis_is_restore()) {
278 tr_accept();
279 }else{
280 assert(_sim->analysis_is_tran_dynamic());
283 const COMMON_LOGIC* c = prechecked_cast<const COMMON_LOGIC*>(common());
284 assert(c);
285 const MODEL_LOGIC* m = prechecked_cast<const MODEL_LOGIC*>(c->model());
286 assert(m);
287 _y[0].x = 0.;
288 _y[0].f1 = _n[OUTNODE]->to_analog(m);
289 _y[0].f0 = 0.;
290 _m0.x = 0.;
291 _m0.c1 = 1./m->rs;
292 _m0.c0 = _y[0].f1 / -m->rs;
293 set_converged(conv_check());
294 store_values();
295 q_load();
297 trace1(long_label(), _y[0].f1);
298 return converged();
300 /*--------------------------------------------------------------------------*/
301 bool DEV_LOGIC::do_tr()
303 switch (_gatemode) {
304 case moUNKNOWN: unreachable(); break;
305 case moMIXED: unreachable(); break;
306 case moDIGITAL: set_converged(tr_eval_digital()); break;
307 case moANALOG: assert(subckt()); set_converged(subckt()->do_tr()); break;
309 return converged();
311 /*--------------------------------------------------------------------------*/
312 void DEV_LOGIC::tt_advance()
314 assert(subckt());
315 subckt()->tt_advance();
316 ELEMENT::tt_advance();
318 /*--------------------------------------------------------------------------*/
319 void DEV_LOGIC::tr_load()
321 switch (_gatemode) {
322 case moUNKNOWN: unreachable(); break;
323 case moMIXED: unreachable(); break;
324 case moDIGITAL: tr_load_passive(); break;
325 case moANALOG: assert(subckt()); subckt()->tr_load(); break;
328 /*--------------------------------------------------------------------------*/
329 TIME_PAIR DEV_LOGIC::tr_review()
331 // not calling ELEMENT::tr_review();
333 q_accept();
334 //digital mode queues events explicitly in tr_accept
336 switch (_gatemode) {
337 case moUNKNOWN: unreachable(); break;
338 case moMIXED: unreachable(); break;
339 case moDIGITAL: _time_by.reset(); break;
340 case moANALOG: assert(subckt()); _time_by = subckt()->tr_review(); break;
342 return _time_by;
344 /*--------------------------------------------------------------------------*/
345 /* tr_accept: This runs after everything has passed "review".
346 * It sets up and queues transitions, and sometimes determines logic states.
348 void DEV_LOGIC::tr_accept()
350 assert(_gatemode == moDIGITAL || _gatemode == moANALOG);
351 const COMMON_LOGIC* c = prechecked_cast<const COMMON_LOGIC*>(common());
352 assert(c);
353 const MODEL_LOGIC* m = prechecked_cast<const MODEL_LOGIC*>(c->model());
354 assert(m);
356 #ifdef LASTACC
357 if(_sim->_time0 <= _tr_last_acc) {
358 if(_sim->_time0){
359 error(bWARNING, "tr accepting twice %s time0 %E\n", long_label().c_str(), _sim->_time0);
360 // assert(false);
361 }else{
364 _tr_last_acc = _sim->_time0;
365 #endif
366 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
367 /* Check quality and get node info to local array. */
368 /* side effect --- generate digital values for analog nodes */
369 assert(PORTS_PER_GATE == max_nodes());
371 _n[OUTNODE]->to_logic(m);
372 _quality = _n[OUTNODE]->quality(); /* the worst quality on this device */
373 _failuremode = _n[OUTNODE]->failure_mode(); /* what is wrong with it? */
374 _lastchangenode = OUTNODE; /* which node changed most recently */
375 int lastchangeiter=_n[OUTNODE]->d_iter();/* iteration # when it changed */
376 trace1("DEV_LOGIC::tr_accept", long_label());
377 trace3("DEV_LOGIC::tr_accept", _n[OUTNODE]->failure_mode(), OUTNODE, _n[OUTNODE]->quality());
379 for (uint_t ii = BEGIN_IN; ii < net_nodes(); ++ii) {
380 _n[ii]->to_logic(m);
381 if (_n[ii]->quality() < _quality) {
382 _quality = _n[ii]->quality();
383 _failuremode = _n[ii]->failure_mode();
384 }else{
386 if (_n[ii]->d_iter() >= lastchangeiter) {
387 lastchangeiter = _n[ii]->d_iter();
388 _lastchangenode = ii;
389 }else{
391 trace2(_n[ii]->failure_mode().c_str(), ii, _n[ii]->quality());
393 /* If _lastchangenode == OUTNODE, no new changes, bypass may be ok.
394 * Otherwise, an input changed. Need to evaluate.
395 * If all quality are good, can evaluate as digital.
396 * Otherwise need to evaluate as analog.
398 trace4("DEV_LOGIC::tr_accept", _failuremode, _lastchangenode, lastchangeiter, _quality);
400 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
401 if (want_analog()) {
402 if (_gatemode == moDIGITAL) {untested();
403 error(bTRACE, "%s:%u:%g switch to analog, %s\n", long_label().c_str(),
404 _sim->iteration_tag(), _sim->_time0, _failuremode.c_str());
405 _oldgatemode = _gatemode;
406 _gatemode = moANALOG;
407 }else{
409 assert(_gatemode == moANALOG);
410 }else{
411 assert(want_digital());
412 if (_gatemode == moANALOG) {
413 error(bTRACE, "%s:%u:%g switch to digital\n",
414 long_label().c_str(), _sim->iteration_tag(), _sim->_time0);
415 _oldgatemode = _gatemode;
416 _gatemode = moDIGITAL;
417 }else{
419 assert(_gatemode == moDIGITAL);
420 if (_sim->analysis_is_restore()) {untested();
421 }else if (_sim->analysis_is_static()) {
422 }else{
424 if (!_sim->_bypass_ok
425 || _lastchangenode != OUTNODE
426 || _sim->analysis_is_static()
427 || _sim->analysis_is_restore()) {
429 LOGICVAL future_state = c->logic_eval(&_n[BEGIN_IN]);
430 // ^^^^^^^^^^
431 trace6("hmmm0", long_label(), _sim->_bypass_ok, _lastchangenode != OUTNODE,
432 _sim->analysis_is_static(), _sim->analysis_is_restore(), future_state);
433 if ((_n[OUTNODE]->is_unknown()) &&
434 (_sim->analysis_is_static() || _sim->analysis_is_restore())) {
435 _n[OUTNODE]->force_initial_value(future_state);
436 /* This happens when initial DC is digital.
437 * Answers could be wrong if order in netlist is reversed
439 }else if (future_state != _n[OUTNODE]->lv()) {
440 // assert(future_state != lvUNKNOWN);
441 switch (future_state) {
442 case lvSTABLE0: /*nothing*/ break;
443 case lvRISING: future_state=lvSTABLE0; break;
444 case lvFALLING: future_state=lvSTABLE1; break;
445 case lvSTABLE1: /*nothing*/ break;
446 case lvUNKNOWN: unreachable(); future_state=lvSTABLE1; break;
448 /* This handling of rising and falling may seem backwards.
449 * These states occur when the value has been contaminated
450 * by another pending action. The "old" value is the
451 * value without this contamination.
452 * This code is planned for replacement as part of VHDL/Verilog
453 * conversion, so the kluge stays in for now.
455 assert(future_state.lv_old() == future_state.lv_future());
456 if (_n[OUTNODE]->lv() == lvUNKNOWN
457 || future_state.lv_future() != _n[OUTNODE]->lv_future()) {
458 trace5( "hmmm", future_state, long_label(), _n[OUTNODE]->lv(),
459 _n[BEGIN_IN]->lv(), _n[BEGIN_IN]->lv_future());
460 if (_sim->analysis_is_static()) {
461 _n[OUTNODE]->set_event(-1e99, future_state);
462 }else{
463 _n[OUTNODE]->set_event(m->delay, future_state);
465 _sim->new_event(_n[OUTNODE]->final_time());
466 //assert(future_state == _n[OUTNODE].lv_future());
467 if (_lastchangenode == OUTNODE) {
468 unreachable();
469 error(bDANGER, "%s:%u:%g non-event state change: failuremode: %s\n",
470 long_label().c_str(), _sim->iteration_tag(), _sim->_time0, _failuremode.c_str());
471 }else{
473 }else{
475 }else{
477 }else{
481 /*--------------------------------------------------------------------------*/
482 void DEV_LOGIC::tr_unload()
484 if (subckt()) {
485 subckt()->tr_unload();
486 }else{untested();
488 tr_unload_passive();
490 /*--------------------------------------------------------------------------*/
491 void DEV_LOGIC::ac_iwant_matrix()
493 if (subckt()) {
494 subckt()->ac_iwant_matrix();
495 }else{
498 /*--------------------------------------------------------------------------*/
499 void DEV_LOGIC::ac_begin()
500 {untested();
501 if (subckt()) {untested();
502 subckt()->ac_begin();
503 }else{untested();
504 error(bWARNING, long_label() + ": no logic in AC analysis\n");
507 /*--------------------------------------------------------------------------*/
508 double DEV_LOGIC::tr_probe_num(const std::string& what)const
510 return _n[OUTNODE]->tr_probe_num(what);
512 /*--------------------------------------------------------------------------*/
513 XPROBE DEV_LOGIC::ac_probe_ext(const std::string& what)const
514 {untested();
515 return _n[OUTNODE]->ac_probe_ext(what);
517 /*--------------------------------------------------------------------------*/
518 bool DEV_LOGIC::want_analog()const
520 return subckt() &&
521 ((OPT::mode == moANALOG) || (OPT::mode == moMIXED && _quality != qGOOD));
523 /*--------------------------------------------------------------------------*/
524 bool DEV_LOGIC::want_digital()const
526 return !subckt() ||
527 ((OPT::mode == moDIGITAL) || (OPT::mode == moMIXED && _quality == qGOOD));
529 /*--------------------------------------------------------------------------*/
530 bool COMMON_LOGIC::operator==(const COMMON_COMPONENT& x)const
532 const COMMON_LOGIC* p = dynamic_cast<const COMMON_LOGIC*>(&x);
533 bool rv = p
534 && incount == p->incount
535 && COMMON_COMPONENT::operator==(x);
536 if (rv) {
537 }else{
539 return rv;
541 /*--------------------------------------------------------------------------*/
542 /*--------------------------------------------------------------------------*/
543 // vim:ts=8:sw=2:noet: