testing
[gnucap-felix.git] / src / d_vvp.cc
blobff0a12d3873e921301d994f729f97b36fab8dfee
1 /*$Id: d_logic.cc,v 1.2 2009-12-13 17:55:01 felix Exp $ -*- C++ -*-
2 * vim:ts=8:sw=2:et:
3 * Copyright (C) 2011 Felix Salfelder
4 * Authors: Albert Davis <aldavis@gnu.org>
5 * Felix Salfelder
6 *
7 * This file is part of "Gnucap", the Gnu Circuit Analysis Package
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 3, or (at your option)
12 * any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22 * 02110-1301, USA.
23 *------------------------------------------------------------------
25 * gnucap device interface to Icarus Verilog
27 * FIXME: event sent out to ivl should be crosstime rather than time0
28 * TODO: get model parms from Icarus (like gnucap-icarus spiceDLL)
31 //testing=script,sparse 2006.07.17
32 #include "d_subckt.h"
33 #include "u_xprobe.h"
34 #include "d_vvp.h"
35 #include "ap.h"
36 #include "u_lang.h"
37 #include "e_elemnt.h"
38 #include "m_interp.h"
39 #include "bm.h"
40 #include "l_lib.h"
41 #include "io_trace.h"
42 #include "vvp/vvp_net.h"
43 #include "extlib.h"
44 #include "d_ivl_ports.h"
46 //#include "schedule.cc"
47 /*--------------------------------------------------------------------------*/
48 inline double event_(struct event_time_s *et)
50 return double ( et->delay * (long double)
51 pow(10.0,vpip_get_time_precision()) );
53 inline double event_absolute(struct event_time_s *et)
55 return double ( (et->delay+schedule_simtime() )
56 * (long double) pow(10.0,vpip_get_time_precision()) );
58 inline double digital_time(void)
60 return double(schedule_simtime() * (long double)
61 pow(10.0,vpip_get_time_precision())) ;
63 inline double prec(){
64 return double(pow(10.0,vpip_get_time_precision()));
66 /*--------------------------------------------------------------------------*/
67 inline OMSTREAM& operator<<(OMSTREAM& o, direction_t t) {
68 const std::string s[] = {"", "input", "output", "inout"};
69 return (o << s[t]);
71 /*--------------------------------------------------------------------------*/
72 const double _default_delta (NOT_INPUT);
73 const int _default_smooth(0);
74 /*--------------------------------------------------------------------------*/
75 class COMMON_LOGIC_VVP;
76 /*--------------------------------------------------------------------------*/
77 int MODEL_LOGIC_VVP::_count = -1;
78 int COMMON_LOGIC_VVP::_count = -1;
79 int DEV_LOGIC_VVP::_count = -1;
80 typeof(COMMON_LOGIC_VVP::_commons) COMMON_LOGIC_VVP::_commons;
81 static COMMON_LOGIC_VVP Default_Logic_Params(CC_STATIC);
82 static LOGIC_NONE Default_LOGIC(CC_STATIC);
83 /*--------------------------------------------------------------------------*/
84 /*--------------------------------------------------------------------------*/
85 // MODEL (not in use)
86 /*--------------------------------------------------------------------------*/
87 void MODEL_LOGIC_VVP::precalc_first(){
88 MODEL_LOGIC::precalc_first();
90 /*--------------------------------------------------------------------------*/
91 void MODEL_LOGIC_VVP::precalc_last(){
92 MODEL_LOGIC::precalc_last();
94 /*--------------------------------------------------------------------------*/
95 MODEL_LOGIC_VVP::MODEL_LOGIC_VVP(const DEV_LOGIC_VVP* p)
96 :MODEL_LOGIC((const COMPONENT*) p){
97 trace0("MODEL_LOGIC_VVP::MODEL_LOGIC_VVP");
99 /*--------------------------------------------------------------------------*/
100 MODEL_LOGIC_VVP::MODEL_LOGIC_VVP(const MODEL_LOGIC_VVP& p)
101 :MODEL_LOGIC(p){
102 file=p.file;
103 output=p.output;
104 input=p.input;
105 trace0("MODEL_LOGIC_VVP::MODEL_LOGIC_VVP");
107 /*--------------------------------------------------------------------------*/
108 bool MODEL_LOGIC_VVP::param_is_printable(int i) const{
109 return (MODEL_LOGIC::param_count() - 1 - i) < param_count();
111 /*--------------------------------------------------------------------------*/
112 std::string MODEL_LOGIC_VVP::param_name(int i, int j)const
114 if (j == 0) {
115 return param_name(i);
116 }else if (i >= MODEL_LOGIC::param_count()) {
117 return "";
118 }else{
119 return MODEL_LOGIC::param_name(i, j);
122 /*--------------------------------------------------------------------------*/
123 void MODEL_LOGIC_VVP::set_param_by_index(int i, std::string& value, int offset)
125 switch (MODEL_LOGIC_VVP::param_count() - 1 - i) {
126 case 0: file = value; break;
127 case 1: output = value; break;
128 case 2: input = value; break;
129 default: MODEL_LOGIC::set_param_by_index(i, value, offset); break;
132 /*--------------------------------------------------------------------------*/
133 std::string MODEL_LOGIC_VVP::param_name(int i) const{
134 switch (MODEL_LOGIC_VVP::param_count() - 1 - i) {
135 case 0: return "file_unused";
136 case 1: return "input";
137 case 2: return "output";
138 default: return MODEL_LOGIC::param_name(i);
141 /*--------------------------------------------------------------------------*/
142 std::string MODEL_LOGIC_VVP::param_value(int i)const
144 switch (MODEL_LOGIC::param_count() - 1 - i) {
145 case 0: return file.string();
146 case 1: return output.string();
147 case 2: return input.string();
148 default: return MODEL_LOGIC::param_value(i);
151 /*--------------------------------------------------------------------------*/
152 // COMMON
153 /*--------------------------------------------------------------------------*/
154 COMMON_LOGIC_VVP::COMMON_LOGIC_VVP(int c)
155 :COMMON_COMPONENT(c),
156 _extlib(0),
157 incount(0),
158 vvpfile(""),
159 module(""),
160 status(0),
161 _logic_none(0)
163 trace1("COMMON_LOGIC_VVP::COMMON_LOGIC_VVP", c);
164 ++_count;
166 /*--------------------------------------------------------------------------*/
167 COMMON_LOGIC_VVP::COMMON_LOGIC_VVP(const COMMON_LOGIC_VVP& p)
168 :COMMON_COMPONENT(p),
169 _extlib(p._extlib),
170 incount(p.incount),
171 vvpfile(p.vvpfile),
172 module(p.module),
173 status(p.status),
174 _logic_none(0)
176 trace0("COMMON_LOGIC_VVP::COMMON_LOGIC_VVP( COMMON_LOGIC_VVP )");
177 ++_count;
179 /*--------------------------------------------------------------------------*/
180 bool COMMON_LOGIC_VVP::operator==(const COMMON_COMPONENT& x )const{
181 const COMMON_LOGIC_VVP* p = dynamic_cast<const COMMON_LOGIC_VVP*>(&x);
182 bool ret = (vvpfile==p->vvpfile)
183 && (module==p->module); // bad idea...?
184 bool cr = COMMON_COMPONENT::operator==(x);
186 return ret && cr;
188 /*--------------------------------------------------------------------------*/
189 COMMON_COMPONENT* COMMON_LOGIC_VVP::deflate()
191 trace0("COMMON_LOGIC_VVP::deflate");
192 // return this;
193 for( list<const COMMON_COMPONENT*>::iterator i = _commons.begin();
194 i != _commons.end(); ++i ){
195 if (*this == **i){
196 trace0("COMMON_LOGIC_VVP::deflate hit");
197 return const_cast<COMMON_COMPONENT*>( *i );
199 trace0("COMMON_LOGIC_VVP::deflate miss");
201 _commons.push_back(this);
202 return this;
204 /*--------------------------------------------------------------------------*/
205 /*--------------------------------------------------------------------------*/
206 // get next event time from icarus queue.
207 TIME_PAIR DEV_LOGIC_VVP::tr_review(){
208 _time_by = BASE_SUBCKT::tr_review();
210 event_time_s* ctim = schedule_list();
212 if (ctim){
213 double delay = event_absolute(ctim);
214 trace1("DEV_LOGIC_VVP::tr_review", delay );
215 _time_by.min_event(delay + _sim->_time0);
217 q_accept();
218 return _time_by;
220 /*--------------------------------------------------------------------------*/
221 bool DEV_LOGIC_VVP::do_tr(){
222 assert(status);
223 //q_accept();
224 return BASE_SUBCKT::do_tr();
226 /*--------------------------------------------------------------------------*/
227 void DEV_LOGIC_VVP::tr_accept(){
228 static double lastaccept;
230 if ( lastaccept == _sim->_time0 && _sim->_time0!=0){
231 return;
234 trace2("DEV_LOGIC_VVP::tr_accept", _sim->_time0, lastaccept);
235 lastaccept = _sim->_time0;
237 // first queue events.
238 // FIXME: just outports.
239 subckt()->tr_accept();
241 // then execute anything until now.
242 trace1("DEV_LOGIC_VVP::tr_accept calling cont", _sim->_time0);
243 vvp::contsim("",_sim->_time0);
245 // accept again (the other nodes might have changed.)
246 // FIXME: just inports
247 subckt()->tr_accept();
248 //uint_t incount=1;
249 // node_t* n=&_n[2];
251 // copy next event to master queue
252 event_time_s* ctim = schedule_list();
253 double evt;
254 if (ctim){
255 evt = event_(ctim);
256 double eventtime = event_absolute(ctim);
257 trace3("DEV_LOGIC_VVP::tr_accept, fetching event",_sim->_time0, ctim->delay, eventtime);
258 assert(evt>=0);
259 if(evt==0) { untested(); };
260 _sim->new_event(eventtime);
263 // CHECK: implement tr_needs_eval?
264 q_eval();
266 /*--------------------------------------------------------------------------*/
267 void COMMON_LOGIC_VVP::precalc_first(const CARD_LIST* par_scope)
269 trace0("COMMON_LOGIC_VVP::precalc_first " + (string) module + " " + (string) vvpfile );
270 assert(par_scope);
272 COMMON_COMPONENT::precalc_first(par_scope);
273 vvpfile.e_val("UNSET", par_scope);
274 module.e_val("UNSET", par_scope);
276 //something hosed here.
278 /*--------------------------------------------------------------------------*/
279 void COMMON_LOGIC_VVP::expand(const COMPONENT* dev ){
280 trace1("COMMON_LOGIC_VVP::expand" + dev->long_label(), (intptr_t) dev % PRIME);
282 COMMON_COMPONENT::expand(dev);
283 attach_model(dev);
285 const MODEL_LOGIC* m = dynamic_cast<const MODEL_LOGIC*>(model());
286 if (!m) {
287 throw Exception_Model_Type_Mismatch(dev->long_label(), modelname(), name());
290 COMMON_LOGIC* logic_none = new LOGIC_NONE;
291 logic_none->set_modelname(modelname());
292 logic_none->attach(model());
294 attach_common(logic_none, &_logic_none);
296 /*--------------------------------------------------------------------------*/
297 void COMMON_LOGIC_VVP::precalc_last(const CARD_LIST* par_scope)
299 assert(par_scope);
300 COMMON_COMPONENT::precalc_last(par_scope);
302 trace0("COMMON_LOGIC_VVP::precalc_last " + (string) module + " " + (string) vvpfile );
304 vvpfile.e_val("UNSET" , par_scope);
305 module.e_val("UNSET" , par_scope);
307 if(!_extlib){
308 #ifdef SOMETHING_
309 /// dlopen has been overwritten!!1
310 void* h = dlopen("libvvpg.so",RTLD_LAZY|RTLD_GLOBAL);
311 if(h==NULL) throw Exception("cannot open libvvp: %s: ", dlerror());
312 trace0("=========== LOADED libvvpg.so ==========");
313 dlerror();
314 #else
315 void* h = NULL;
316 #endif
317 _extlib = new ExtLib("foo",h);
318 int ret;
319 ret=_extlib->init((string(vvpfile)+".vvp").c_str());
320 if(dlerror()) throw Exception("cannot init vvp %s", dlerror());
322 if(ret)
323 error(bDANGER, "somethings wrong with vvp: %s\n", vvpfile.string().c_str() );
325 } else {
326 trace0("COMMON_LOGIC_VVP::precalc_last already done extlib");
328 status++;
330 /*--------------------------------------------------------------------------*/
331 std::string DEV_LOGIC_VVP::port_name(uint_t i)const{
332 stringstream a;
333 a << "port" << i;
334 return a.str();
336 /*--------------------------------------------------------------------------*/
337 DEV_LOGIC_VVP::~DEV_LOGIC_VVP() {
338 --_count;
340 trace0("~DEV_LOGIC_VVP");
342 /* for( vector<COMMON_COMPONENT*>::iterator i = _subcommons.begin();
343 i!=_subcommons.end(); ++i){
344 // COMMON_COMPONENT::detach_common(&(*i));
348 /*--------------------------------------------------------------------------*/
349 COMMON_LOGIC_VVP::~COMMON_LOGIC_VVP() {
350 --_count;
352 detach_common(&_logic_none);
354 for( vector<COMMON_COMPONENT*>::iterator i = _subcommons.begin();
355 i!=_subcommons.end(); ++i){
356 delete (&(*i));
359 /*--------------------------------------------------------------------------*/
360 std::string COMMON_LOGIC_VVP::param_name(int i) const{
361 trace1("COMMON_LOGIC_VVP::param_name ", i);
362 switch (COMMON_COMPONENT::param_count() - 1 - i) {
363 case 0: return "file";
364 case 1: return "module";
365 default: return COMMON_COMPONENT::param_name(i);
368 /*--------------------------------------------------------------------------*/
369 bool COMMON_LOGIC_VVP::param_is_printable(int i) const{
370 return (COMMON_COMPONENT::param_count() - 1 - i) < param_count();
372 /*--------------------------------------------------------------------------*/
373 std::string COMMON_LOGIC_VVP::param_name(int i, int j)const
375 if (j == 0) {
376 return param_name(i);
377 }else if (i >= COMMON_COMPONENT::param_count()) {
378 return "";
379 }else{
380 return COMMON_COMPONENT::param_name(i, j);
383 /*--------------------------------------------------------------------------*/
384 std::string COMMON_LOGIC_VVP::param_value(int i)const
386 switch (COMMON_COMPONENT::param_count() - 1 - i) {
387 case 0: return vvpfile.string();
388 case 1: return module.string();
389 default: return COMMON_COMPONENT::param_value(i);
392 /*--------------------------------------------------------------------------*/
393 void COMMON_LOGIC_VVP::set_param_by_index(int i, std::string& value, int offset)
395 switch (COMMON_COMPONENT::param_count() - 1 - i) {
396 case 0: vvpfile = value;
397 break;
398 case 1: module = value;
399 break;
400 default: COMMON_COMPONENT::set_param_by_index(i, value, offset); break;
403 /*--------------------------------------------------------------------------*/
404 COMMON_COMPONENT* COMMON_LOGIC_VVP::clone()const
406 return new COMMON_LOGIC_VVP(*this);
408 /*--------------------------------------------------------------------------*/
410 namespace {
411 static DEV_LOGIC_VVP p1;
412 static DISPATCHER<CARD>::INSTALL x1(&device_dispatcher, "vvp", &p1);
414 /*--------------------------------------------------------------------------*/
415 namespace MOD_DISP{
416 static DEV_LOGIC_VVP p1;
417 static MODEL_LOGIC_VVP p2(&p1);
418 static DISPATCHER<MODEL_CARD>::INSTALL
419 d2(&model_dispatcher, "vvpm", &p2);
421 /*--------------------------------------------------------------------------*/
422 DEV_LOGIC_VVP::DEV_LOGIC_VVP()
423 :BASE_SUBCKT(),
424 status(0)
426 trace0("DEV_LOGIC_VVP::DEV_LOGIC_VVP attaching...");
427 attach_common(&Default_Logic_Params);
428 trace0("DEV_LOGIC_VVP::DEV_LOGIC_VVP nodes");
429 _n = _nodes;
430 ++_count;
432 /*--------------------------------------------------------------------------*/
433 DEV_LOGIC_VVP::DEV_LOGIC_VVP(const DEV_LOGIC_VVP& p)
434 :BASE_SUBCKT(p)
435 ,status(0)
437 for (uint_t ii = 0; ii < max_nodes(); ++ii) {
438 _nodes[ii] = p._nodes[ii];
440 _n = _nodes;
441 ++_count;
443 /*--------------------------------------------------------------------------*/
444 PLI_INT32 callback(t_cb_data*x){
445 DEV_LOGIC_IN* c= reinterpret_cast<DEV_LOGIC_IN*>(x->user_data);
446 assert(c);
448 __vpiSignal* signal = (__vpiSignal*) x->obj;
449 vvp_sub_pointer_t<vvp_net_t> ptr(signal->node,0);
451 struct t_vpi_value argval;
452 argval.format = vpiIntVal;
453 vpi_get_value(x->obj, &argval);
454 const vvp_vector4_t bit(1,(vvp_bit4_t)argval.value.integer);
456 trace5("callback called", bit.value(0), digital_time() ,
457 x->value->value.integer, c->lvfromivl, CKT_BASE::_sim->_time0);
458 assert(bit.value(0)==0 || bit.value(0)==1);
460 if (c->lvfromivl == lvUNKNOWN){
461 trace0("callback init.");
462 c->lvfromivl = _LOGICVAL(3*bit.value(0)) ;
463 assert(CKT_BASE::_sim->_time0 == 0 );
464 return 0 ;
467 CKT_BASE::_sim->new_event( double( digital_time()) );
469 switch (bit.value(0)) {
470 case 0: c->lvfromivl = lvFALLING; break;
471 case 1: c->lvfromivl = lvRISING; break;
472 default:
473 error(bDANGER, "got bogus value %i from ivl\n", bit.value(0));
474 break;
476 trace1("callback done ", c->lvfromivl);
477 c->qe();
478 return 0;
480 /*--------------------------------------------------------------------------*/
481 // TODO: cleanup
482 void DEV_LOGIC_VVP::expand()
484 BASE_SUBCKT::expand();
485 assert(_n);
486 const COMMON_LOGIC_VVP* c = prechecked_cast<const COMMON_LOGIC_VVP*>(common());
487 assert(c);
488 const MODEL_LOGIC* m = prechecked_cast<const MODEL_LOGIC*>(c->model());
489 assert(m);
491 if (!subckt()) {
492 new_subckt();
493 }else{
496 if (_sim->is_first_expand()) {
497 trace1 ("first expanding " +long_label(), net_nodes());
498 precalc_first();
499 precalc_last();
500 uint_t n=2;
502 ExtLib*el=((const COMMON_LOGIC_VVP*) common())->_extlib;
503 assert(el);
505 // else Icarus wont let me rigister callbacks
506 assert(vpi_mode_flag == VPI_MODE_NONE);
507 vpi_mode_flag = VPI_MODE_COMPILETF;
509 vpiHandle item;
510 const char* modulename = ((string) c->module).c_str();
512 vpiHandle module = vpi_handle_by_name(modulename,NULL);
513 assert(module);
515 vpiHandle vvp_device = vpi_handle_by_name(short_label().c_str(),module);
516 assert(vvp_device);
518 vpiHandle vvp_device_module = vpi_handle(vpiModule,vvp_device);
519 assert(vvp_device_module);
521 assert ((_n[0].n_()));
522 assert ((_n[1].n_()));
523 assert ((_n[2].n_()));
524 assert ((_n[3].n_()));
525 char src;
526 COMMON_COMPONENT* logic_common;
528 node_t lnodes[] = {_n[n], _n[0], _n[1], _n[1], _n[0]};
529 // vpiParameter holds fall, rise etc.
530 string name;
531 // not implemented
532 // vpiHandle net_iterator = vpi_iterate(vpiPorts,vvp_device);
533 vpiHandle net_iterator = vpi_iterate(vpiScope,vvp_device);
534 assert(net_iterator);
535 CARD* logicdevice;
536 node_t* x;
537 trace1("DEV_LOGIC_VVP::expand "+ short_label() + " entering loop", net_nodes());
538 while ((item = vpi_scan(net_iterator))) {
539 int type= vpi_get(vpiType,item);
540 name = vpi_get_str(vpiName,item);
541 COMPONENT* P;
543 trace2("==> "+ short_label() + " " + string(name), item->vpi_type->type_code, n );
545 switch(type){
546 case vpiNet: // <- ivl
548 src='V';
549 logic_common = c->_logic_none;
550 x = new node_t();
551 x->new_model_node("i_"+name, this);
552 lnodes[0] = _n[n];
553 lnodes[1] = _n[0];
554 lnodes[2] = _n[1];
555 lnodes[3] = _n[1];
556 lnodes[4] = *x;
557 logicdevice = device_dispatcher["port_from_ivl"];
559 P = dynamic_cast<COMPONENT*>(logicdevice->clone());
561 t_cb_data cbd = {
562 cbValueChange, //reason
563 callback, //cb_rtn
564 item, //obj
565 0, //time
566 0, //value
567 0, //index
568 (char*)P //user_data
571 vpi_register_cb(&cbd);
573 break;
575 case vpiReg: // -> ivl
576 src='I';
577 x = new node_t();
578 x->new_model_node("i_"+name, this);
579 lnodes[0] = *x;
580 lnodes[1] = _n[0];
581 lnodes[2] = _n[1];
582 lnodes[3] = _n[1];
583 lnodes[4] = _n[n];
584 logic_common = c->_logic_none;
585 logicdevice = device_dispatcher["port_to_ivl"];
586 ((DEV_LOGIC_OUT*) logicdevice)->H = item;
587 P = dynamic_cast<COMPONENT*>(logicdevice->clone());
588 break;
590 default:
591 // which other types would make sense?
592 continue;
595 trace2("DEV_LOGIC_VVP::expand "+ name + " " + short_label(), n, (intptr_t)logic_common);
596 assert(_n[n].n_());
598 assert(P);
599 subckt()->push_front(P);
601 trace3("setting parameters", intptr_t(logic_common), logic_common->attach_count(), n );
602 trace0("modelname: " + logic_common->modelname());
604 if (src=='I'){
605 // to ivl
606 COMMON_LOGIC* L = (COMMON_LOGIC*) logic_common;
607 P->set_parameters(name, this, L, 0, 0, NULL, 5 , lnodes);
608 }else{
609 // from ivl.
610 COMMON_LOGIC* L = (COMMON_LOGIC*) logic_common;
611 P->set_parameters(name, this, L, 0, 0, NULL, 5 , lnodes);
614 trace1("loop end for "+name, n);
615 n++;
617 vpi_mode_flag = VPI_MODE_NONE;
620 std::string subckt_name(c->modelname()+"."+string(c->vvpfile));
622 assert(!is_constant());
623 // is this an option?
624 // subckt()->set_slave();
625 subckt()->expand();
627 /*--------------------------------------------------------------------------*/
628 ExtLib* DEV_LOGIC_VVP::extlib()const{
629 return (((const COMMON_LOGIC_VVP*) common())->_extlib);
631 /*--------------------------------------------------------------------------*/
632 void DEV_LOGIC_VVP::tr_begin()
634 const COMMON_LOGIC_VVP* c = prechecked_cast<const COMMON_LOGIC_VVP*>(common());
635 assert(c);
637 trace1("DEV_LOGIC_VVP::tr_begin " + short_label(), status);
638 vvp::startsim("TRAN");
639 vvp::contsim("TRAN",0);
641 // exchange initial conditions?
642 // maybe not necessary (done during dc)
644 status++;
645 subckt()->tr_begin();
646 q_eval();
648 /*--------------------------------------------------------------------------*/
649 void DEV_LOGIC_VVP::precalc_first()
651 COMPONENT::precalc_first();
652 assert(common());
654 if(subckt()){
655 subckt()->precalc_first();
658 /*--------------------------------------------------------------------------*/
659 void DEV_LOGIC_VVP::precalc_last()
661 COMPONENT::precalc_last();
662 if (subckt()) {subckt()->precalc_last();}
663 assert(common()->model());
665 /*--------------------------------------------------------------------------*/
666 /*--------------------------------------------------------------------------*/