1 /*$Id: d_logic.cc,v 1.2 2009-12-13 17:55:01 felix Exp $ -*- C++ -*-
3 * Copyright (C) 2011 Felix Salfelder
4 * Authors: Albert Davis <aldavis@gnu.org>
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)
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
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
42 #include "vvp/vvp_net.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())) ;
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"};
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 /*--------------------------------------------------------------------------*/
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
)
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
115 return param_name(i
);
116 }else if (i
>= MODEL_LOGIC::param_count()) {
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 /*--------------------------------------------------------------------------*/
153 /*--------------------------------------------------------------------------*/
154 COMMON_LOGIC_VVP::COMMON_LOGIC_VVP(int c
)
155 :COMMON_COMPONENT(c
),
163 trace1("COMMON_LOGIC_VVP::COMMON_LOGIC_VVP", c
);
166 /*--------------------------------------------------------------------------*/
167 COMMON_LOGIC_VVP::COMMON_LOGIC_VVP(const COMMON_LOGIC_VVP
& p
)
168 :COMMON_COMPONENT(p
),
176 trace0("COMMON_LOGIC_VVP::COMMON_LOGIC_VVP( COMMON_LOGIC_VVP )");
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
);
188 /*--------------------------------------------------------------------------*/
189 COMMON_COMPONENT
* COMMON_LOGIC_VVP::deflate()
191 trace0("COMMON_LOGIC_VVP::deflate");
193 for( list
<const COMMON_COMPONENT
*>::iterator i
= _commons
.begin();
194 i
!= _commons
.end(); ++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);
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();
213 double delay
= event_absolute(ctim
);
214 trace1("DEV_LOGIC_VVP::tr_review", delay
);
215 _time_by
.min_event(delay
+ _sim
->_time0
);
220 /*--------------------------------------------------------------------------*/
221 bool DEV_LOGIC_VVP::do_tr(){
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){
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();
251 // copy next event to master queue
252 event_time_s
* ctim
= schedule_list();
256 double eventtime
= event_absolute(ctim
);
257 trace3("DEV_LOGIC_VVP::tr_accept, fetching event",_sim
->_time0
, ctim
->delay
, eventtime
);
259 if(evt
==0) { untested(); };
260 _sim
->new_event(eventtime
);
263 // CHECK: implement tr_needs_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
);
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
);
285 const MODEL_LOGIC
* m
= dynamic_cast<const MODEL_LOGIC
*>(model());
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
)
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
);
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 ==========");
317 _extlib
= new ExtLib("foo",h
);
319 ret
=_extlib
->init((string(vvpfile
)+".vvp").c_str());
320 if(dlerror()) throw Exception("cannot init vvp %s", dlerror());
323 error(bDANGER
, "somethings wrong with vvp: %s\n", vvpfile
.string().c_str() );
326 trace0("COMMON_LOGIC_VVP::precalc_last already done extlib");
330 /*--------------------------------------------------------------------------*/
331 std::string
DEV_LOGIC_VVP::port_name(uint_t i
)const{
336 /*--------------------------------------------------------------------------*/
337 DEV_LOGIC_VVP::~DEV_LOGIC_VVP() {
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() {
352 detach_common(&_logic_none
);
354 for( vector
<COMMON_COMPONENT
*>::iterator i
= _subcommons
.begin();
355 i
!=_subcommons
.end(); ++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
376 return param_name(i
);
377 }else if (i
>= COMMON_COMPONENT::param_count()) {
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
;
398 case 1: module
= value
;
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 /*--------------------------------------------------------------------------*/
411 static DEV_LOGIC_VVP p1
;
412 static DISPATCHER
<CARD
>::INSTALL
x1(&device_dispatcher
, "vvp", &p1
);
414 /*--------------------------------------------------------------------------*/
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()
426 trace0("DEV_LOGIC_VVP::DEV_LOGIC_VVP attaching...");
427 attach_common(&Default_Logic_Params
);
428 trace0("DEV_LOGIC_VVP::DEV_LOGIC_VVP nodes");
432 /*--------------------------------------------------------------------------*/
433 DEV_LOGIC_VVP::DEV_LOGIC_VVP(const DEV_LOGIC_VVP
& p
)
437 for (uint_t ii
= 0; ii
< max_nodes(); ++ii
) {
438 _nodes
[ii
] = p
._nodes
[ii
];
443 /*--------------------------------------------------------------------------*/
444 PLI_INT32
callback(t_cb_data
*x
){
445 DEV_LOGIC_IN
* c
= reinterpret_cast<DEV_LOGIC_IN
*>(x
->user_data
);
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 );
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;
473 error(bDANGER
, "got bogus value %i from ivl\n", bit
.value(0));
476 trace1("callback done ", c
->lvfromivl
);
480 /*--------------------------------------------------------------------------*/
482 void DEV_LOGIC_VVP::expand()
484 BASE_SUBCKT::expand();
486 const COMMON_LOGIC_VVP
* c
= prechecked_cast
<const COMMON_LOGIC_VVP
*>(common());
488 const MODEL_LOGIC
* m
= prechecked_cast
<const MODEL_LOGIC
*>(c
->model());
496 if (_sim
->is_first_expand()) {
497 trace1 ("first expanding " +long_label(), net_nodes());
502 ExtLib
*el
=((const COMMON_LOGIC_VVP
*) common())->_extlib
;
505 // else Icarus wont let me rigister callbacks
506 assert(vpi_mode_flag
== VPI_MODE_NONE
);
507 vpi_mode_flag
= VPI_MODE_COMPILETF
;
510 const char* modulename
= ((string
) c
->module
).c_str();
512 vpiHandle module
= vpi_handle_by_name(modulename
,NULL
);
515 vpiHandle vvp_device
= vpi_handle_by_name(short_label().c_str(),module
);
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_()));
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.
532 // vpiHandle net_iterator = vpi_iterate(vpiPorts,vvp_device);
533 vpiHandle net_iterator
= vpi_iterate(vpiScope
,vvp_device
);
534 assert(net_iterator
);
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
);
543 trace2("==> "+ short_label() + " " + string(name
), item
->vpi_type
->type_code
, n
);
546 case vpiNet
: // <- ivl
549 logic_common
= c
->_logic_none
;
551 x
->new_model_node("i_"+name
, this);
557 logicdevice
= device_dispatcher
["port_from_ivl"];
559 P
= dynamic_cast<COMPONENT
*>(logicdevice
->clone());
562 cbValueChange
, //reason
571 vpi_register_cb(&cbd
);
575 case vpiReg
: // -> ivl
578 x
->new_model_node("i_"+name
, this);
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());
591 // which other types would make sense?
595 trace2("DEV_LOGIC_VVP::expand "+ name
+ " " + short_label(), n
, (intptr_t)logic_common
);
599 subckt()->push_front(P
);
601 trace3("setting parameters", intptr_t(logic_common
), logic_common
->attach_count(), n
);
602 trace0("modelname: " + logic_common
->modelname());
606 COMMON_LOGIC
* L
= (COMMON_LOGIC
*) logic_common
;
607 P
->set_parameters(name
, this, L
, 0, 0, NULL
, 5 , lnodes
);
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
);
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();
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());
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)
645 subckt()->tr_begin();
648 /*--------------------------------------------------------------------------*/
649 void DEV_LOGIC_VVP::precalc_first()
651 COMPONENT::precalc_first();
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 /*--------------------------------------------------------------------------*/