3 * Copyright (C) 2009 Kevin Cameron
4 * Author: Kevin Cameron
6 * This file is a part of plugin "Gnucap-Icarus" to "Gnucap",
7 * 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 *------------------------------------------------------------------
24 * Dynamic binding of PWL signal sources to external simulators
29 #include "e_cardlist.h"
36 # include "vvp/compile.h"
37 # include "vvp/schedule.h"
38 # include "vvp/vpi_priv.h"
39 # include "vvp/statistics.h"
40 # include "vvp/vvp_cleanup.h"
46 /*--------------------------------------------------------------------------*/
47 /*--------------------------------------------------------------------------*/
49 inline double digital_time(void)
51 return double(schedule_simtime() * (long double) pow(10.0,vpip_get_time_precision())) ;
54 // static std::list<ExtLib*> Libs;
56 void ExtLib::set_active(void *,double time
)
59 if (time
>= next_time
) {
67 CKT_BASE::_sim
->new_event(time
);
70 /*--------------------------------------------------------------------------*/
71 void ExtLib::SetActive(void *dl
,void *handle
,double time
)
74 SpcDllData
*spd
= (SpcDllData
*)dl
;
75 ExtLib
*lib
= ExtLib::Sdd2El(spd
);
76 lib
->set_active(handle
,time
);
78 /*--------------------------------------------------------------------------*/
79 int ExtLib::init(const char *args
) {
81 trace0("ExtLib::init");
85 vhbn
= (typeof(vhbn
))dlsym(handle
,"vpi_handle_by_name");
87 bindnet
= (typeof(bindnet
))dlsym(handle
,"bindnet");
89 startsim
= (typeof(startsim
))dlsym(handle
,"startsim");
91 endsim
= (typeof(endsim
))dlsym(handle
,"endsim");
93 contsim
= (typeof(contsim
))dlsym(handle
,"contsim");
95 so_main
= (typeof(so_main
))dlsym(handle
,"so_main");
97 error(bDANGER
, "so: %s\n", dlerror());
100 activate
= (typeof(activate
))SetActive
;
103 startsim
= &vvp::startsim
;
104 //bindnet = &vvp::bindnet;
107 endsim
= &vvp::endsim
;
109 contsim
= &vvp::contsim
;
111 so_main
= &vvp::init
;
113 error(bDANGER
, "so: %s\n", dlerror());
116 //activate = &vvp::SetActive;
120 return( (*so_main
)(args
) );
125 void ExtSig::SetActive(void *,void *sig
,double time
)
127 // SpcDllData *spd = (SpcDllData *)dl;
129 ((ExtSig
*)sig
)->set_active(time
);
130 trace1("ExtSig::SetActive", (intptr_t)sig
);
133 void ExtSig::set_active(double ) {
136 void PrintInst(FILE *fp
,struct __vpiScope
*scope
);
139 void PrintInst(FILE *fp
,struct __vpiScope
*scope
)
142 PrintInst(fp
,scope
->scope
);
145 fputs(scope
->name
,fp
);
147 /*-----------------------------------------------------*/
149 bool have_ivl_version
= true;
151 double vvp::SimTimeD
= 0.0;
152 double vvp::SimTimeA
= 0.0;
153 // double SimTimeA = 0.0;
154 double vvp::SimTimeDlast
= 0.0;
155 double vvp::SimDelayD
= -1.0;
157 sim_mode
vvp::SimState
= SIM_ALL
;
161 inline static void my_getrusage(struct rusage
*) { }
162 inline static void print_rusage(struct rusage
*, struct rusage
*){};
163 /*--------------------------------------------------------------------*/
166 void vvp::vvp_vpi_init()
168 trace0("not doing anything");
170 /*------------------------------------------------*/
171 // replacement for main...
172 int vvp::init(const char* design_path
)
174 static int vvp_return_value
;
176 const char *logfile_name
= 0x0;
178 extern void vpi_set_vlog_info(int, char**);
179 extern bool stop_is_finish
;
181 stop_is_finish
= false;
183 vpip_module_path
[vpip_module_path_cnt
++] = ".";
184 stop_is_finish
= true;
186 if (char*path
= getenv("VVP_DEBUG")) {
187 debug_file
.open(path
, ios::out
);
190 /* This is needed to get the MCD I/O routines ready for
191 anything. It is done early because it is plausible that the
192 compile might affect it, and it is cheap to do. */
195 if (!strcmp(logfile_name
, "-"))
198 logfile
= fopen(logfile_name
, "w");
200 perror(logfile_name
);
203 //setvbuf(logfile, log_buffer, _IOLBF, sizeof(log_buffer));
207 // vpip_mcd_init(logfile); // not shared yet.
208 vpip_mcd_init(logfile
);
211 trace0( "Init VVP ...\n");
215 vpi_set_vlog_info(0, argv
);
217 trace0( "Compiling VVP "+(string
)design_path
);
218 COMPILE
*c
=new COMPILE();
221 // for m in modules...
222 // vpip_load_module("bindsigs2");
223 int ret_cd
= c
->design(design_path
);
225 trace1( " ...\n", ret_cd
);
228 print_vpi_call_errors();
229 if (ret_cd
) return ret_cd
;
231 if (!have_ivl_version
) {
232 if (c
->verbose_flag
) vpi_mcd_printf(1, "... ");
233 vpi_mcd_printf(1, "Warning: vvp input file may not be correct "
237 vpi_mcd_printf(1, "Compile cleanup...\n");
242 vpi_mcd_printf(1, "%s: Program not runnable, %u errors.\n",
243 design_path
, c
->errors
);
244 load_module_delete();
249 fprintf(stdout
, "vpi_mcd_printf ...\n");
250 vpi_mcd_printf(1, " ... %8lu functors (net_fun pool=%zu bytes)\n",
251 (long unsigned)count_functors
, vvp_net_fun_t::heap_total());
252 vpi_mcd_printf(1, " %8lu logic\n", count_functors_logic
);
253 vpi_mcd_printf(1, " %8lu bufif\n", count_functors_bufif
);
254 vpi_mcd_printf(1, " %8lu resolv\n",count_functors_resolv
);
255 vpi_mcd_printf(1, " %8lu signals\n", count_functors_sig
);
256 vpi_mcd_printf(1, " ... %8lu filters (net_fil pool=%zu bytes)\n",
257 count_filters
, vvp_net_fil_t::heap_total());
258 vpi_mcd_printf(1, " ... %8lu opcodes (%zu bytes)\n",
259 count_opcodes
, size_opcodes
);
260 vpi_mcd_printf(1, " ... %8lu nets\n", count_vpi_nets
);
261 vpi_mcd_printf(1, " ... %8lu vvp_nets (%zu bytes)\n",
262 count_vvp_nets
, size_vvp_nets
);
263 vpi_mcd_printf(1, " ... %8lu arrays (%lu words)\n",
264 count_net_arrays
, count_net_array_words
);
265 vpi_mcd_printf(1, " ... %8lu memories\n",
266 count_var_arrays
+count_real_arrays
);
267 vpi_mcd_printf(1, " %8lu logic (%lu words)\n",
268 count_var_arrays
, count_var_array_words
);
269 vpi_mcd_printf(1, " %8lu real (%lu words)\n",
270 count_real_arrays
, count_real_array_words
);
271 vpi_mcd_printf(1, " ... %8lu scopes\n", count_vpi_scopes
);
274 vpi_mcd_printf(1, "Not Running ...\n");
275 // schedule_simulate();
279 return vvp_return_value
;
281 /*--------------------------------------------------------------------*/
282 void vvp::signals_capture(void)
284 trace0("vvp::signals_capture not implemented");
286 void vvp::signals_revert(void)
288 signal(SIGINT
, SIG_DFL
);
290 /*--------------------------------------------------------------------*/
291 /*--------------------------------------------------------------------*/
292 /*--------------------------------------------------------------------*/
293 double vvp::getdtime(struct event_time_s
*et
)
295 return (double) et
->delay
* pow(10.0,vpip_get_time_precision());
297 /*--------------------------------------------------------------------
298 enum sim_mode {SIM_ALL,
299 SIM_INIT,SIM_CONT0,SIM_CONT1,
301 --------------------------------------------------------------------*/
302 sim_mode
vvp::schedule_simulate_m(sim_mode mode
)
304 trace3("schedule_simulate_m", mode
, SimTimeA
, SimTimeD
);
305 struct event_s
*cur
= 0;
306 struct event_time_s
*ctim
= 0;
310 case SIM_CONT0
: if ((ctim
= schedule_list())){
311 trace1("schedule list", ctim
->delay
);
315 case SIM_CONT1
: goto sim_cont1
;
320 assert(schedule_simtime()==0);
322 trace0("starting vvp");
329 trace1("signals_capture Done", schedule_runnable());
331 trace0("schedule_list?");
332 if (schedule_runnable())
333 while (schedule_list()) {
334 trace2("schedule list ... ", mode
, schedule_stopped() );
336 if (schedule_stopped()) {
340 // You can finish from the debugger without a time change.
341 if (!schedule_runnable()) break;
345 /* ctim is the current time step. */
346 ctim
= schedule_list();
348 /* If the time is advancing, then first run the
349 postponed sync events. Run them all. */
350 if (ctim
->delay
> 0) {
357 d_dly
= getdtime(ctim
);
359 trace0("skip ExtPWL");
360 //doExtPwl(sched_list->nbassign,ctim);
361 SimDelayD
= d_dly
; return SIM_CONT0
;
363 double dly
= getdtime(ctim
),
364 te
= SimTimeDlast
+ dly
;
366 trace4("cont0", SimTimeDlast
, te
, dly
, SimTimeA
);
369 SimDelayD
= te
- SimTimeA
;
370 trace1("schedule_sim SimTimeD PREM", SimDelayD
);
373 trace1("schedule_sim SimTimeD increasing...",dly
);
374 SimTimeD
= SimTimeDlast
+ dly
;
378 fprintf(stderr
,"deffault?\n");
381 if (!schedule_runnable()) break;
382 schedule_sim(schedule_simtime() + ctim
->delay
);
389 /* If there are no more active events, advance the event
390 queues. If there are not events at all, then release
391 the event_time object. */
392 if (ctim
->active
== 0) {
393 ctim
->active
= ctim
->nbassign
;
396 if (ctim
->active
== 0) {
397 ctim
->active
= ctim
->rwsync
;
400 /* If out of rw events, then run the rosync
401 events and delete this time step. This also
402 deletes threads as needed. */
403 if (ctim
->active
== 0) {
406 schedule_enlist( ctim
->next
);
412 d_dly
= getdtime(ctim
);
414 trace0("noextPWL again");
415 // doExtPwl(sched_list->nbassign,ctim);
425 trace1("default ", mode
);
433 /* Pull the first item off the list. If this is the last
434 cell in the list, then clear the list. Execute that
435 event type, and delete it. */
436 cur
= ctim
->active
->next
;
437 if (cur
->next
== cur
) {
440 ctim
->active
->next
= cur
->next
;
447 trace0("cycle done");
450 if (SIM_ALL
== mode
) {
454 // Execute post-simulation callbacks
459 trace1("schedule_simulate_m done.", SimTimeD
);
462 /*--------------------------------------------------------------------*/
463 double vvp::startsim(const char *)
466 SimState
= schedule_simulate_m(SIM_INIT
);
467 SimTimeDlast
= SimTimeD
;
470 /*--------------------------------------------------------------------*/
471 double vvp::contsim(const char *,double time
)
473 trace5("contsim", time
, SimTimeA
, SimTimeD
, SimTimeDlast
, digital_time());
475 assert(CKT_BASE::_sim
->_time0
== time
);
478 SimState
= SIM_CONT0
;
479 while (SimTimeDlast
< time
) {
480 trace1("contsim loop", time
);
481 SimState
= schedule_simulate_m(SimState
);
482 SimTimeDlast
= SimTimeD
;
483 trace1("contsim loop", SimTimeD
);
484 if (SIM_PREM
<= SimState
) break;
489 /*------------------------------------------------------*/
492 vpi_handle_by_name("foo",NULL
);
495 /*------------------------------------------------------*/
497 void *vvp::bindnet(const char *,char ,int *,
498 void *,void (*)(void *,void *,double))