1 /* Copyright (c) 1995-2003 Pragmatic C Software Corp. */
2 
3 /*
4  * print out all drives and loads for wire and regs
5  *
6  * this shows the advantage of type information carrying handles - values
7  * can be printed without knowing much about Verilog constructs
8  */
9 
10 #include <stdio.h>
11 #include <string.h>
12 
13 #include "vpi_user.h"
14 #include "cv_vpi_user.h"
15 
16 int (*iproc_rtn)();
17 
18 /* local function prototypes */
19 static void process_inst(vpiHandle);
20 static void prt_1iter_drvlds(vpiHandle, vpiHandle);
21 static void prt_iter(vpiHandle, vpiHandle);
22 static void prt_1task_drvlds(vpiHandle);
23 
24 /* global function prototypes */
25 extern int process_all_insts(struct t_cb_data *);
26 extern int prt_drvlds(vpiHandle);
27 extern int my_prt_vchg();
28 extern int my_error_handler(struct t_cb_data *);
29 extern void register_scan_cb(void);
30 
31 /*
32  * routine to get and zero all delays in design
33  */
process_all_insts(struct t_cb_data * cbp)34 int process_all_insts(struct t_cb_data *cbp)
35 {
36  int isiz;
37  vpiHandle topiter, topiref;
38 
39  /* build the iterator for each module */
40  topiter = vpi_iterate(vpiModule, NULL);
41  isiz = vpi_get(vpiSize, topiter);
42  vpi_printf("  There are %d top level modules.\n", isiz);
43  for (;;)
44   {
45    if ((topiref = vpi_scan(topiter)) == NULL) break;
46    process_inst(topiref);
47   }
48  vpi_printf("  >>> All instances processed - continuing with simulation.\n");
49  return(0);
50 }
51 
52 /*
53  * process one instance and recursively process all under instances
54  * processing is top down depth first
55  */
process_inst(vpiHandle up_ihref)56 static void process_inst(vpiHandle up_ihref)
57 {
58  int isiz;
59  vpiHandle iter, ihref;
60 
61  iproc_rtn(up_ihref);
62  if ((iter = vpi_iterate(vpiModule, up_ihref)) == NULL) return;
63  isiz = vpi_get(vpiSize, iter);
64  vpi_printf("  There are %d instances in %s.\n", isiz,
65   vpi_get_str(vpiFullName, up_ihref));
66   for (;;)
67   {
68    if ((ihref = vpi_scan(iter)) == NULL) break;
69    process_inst(ihref);
70   }
71 }
72 
73 /*
74  * print the loads and drivers for all wires in instance ihref
75  */
prt_drvlds(vpiHandle ihref)76 int prt_drvlds(vpiHandle ihref)
77 {
78  vpiHandle iter, thref;
79 
80  /* first all instance regs, wires, and variables */
81  iter = vpi_iterate(vpiNet, ihref);
82  if (iter != NULL) prt_1iter_drvlds(iter, ihref);
83  iter = vpi_iterate(vpiReg, ihref);
84  if (iter != NULL) prt_1iter_drvlds(iter, ihref);
85  iter = vpi_iterate(vpiVariables, ihref);
86  if (iter != NULL) prt_1iter_drvlds(iter, ihref);
87 
88  /* also monitor in scopes */
89  iter = vpi_iterate(vpiInternalScope, ihref);
90  for (;;)
91   {
92    if ((thref = vpi_scan(iter)) == NULL) break;
93    prt_1task_drvlds(thref);
94   }
95  return(0);
96 }
97 
98 /*
99  * print all loads and drivers for nets in iter inside instance ihref
100  *
101  * for task variables ihref will be nil since only needed for ports
102  */
prt_1iter_drvlds(vpiHandle iter,vpiHandle ihref)103 static void prt_1iter_drvlds(vpiHandle iter, vpiHandle ihref)
104 {
105  int ntyp;
106  vpiHandle href, lditer, drviter;
107 
108  for (;;)
109   {
110    if ((href = vpi_scan(iter)) == NULL) break;
111    /* can not pass real variable to load/driver iterator or will get err */
112    /* bits selects form real illegal in Verilog */
113    if ((ntyp = vpi_get(vpiType, href)) == vpiRealVar) continue;
114 
115    /* print the drives and loads for 1 net */
116    vpi_printf("... printing drivers and loads for %s:\n",
117     vpi_get_str(vpiFullName, href));
118 
119    lditer = vpi_iterate(vpiLocalLoad, href);
120    if (lditer != NULL)
121     {
122      vpi_printf("  Loads:\n");
123      prt_iter(lditer, ihref);
124     }
125 
126    /* regs can only have loads because in Cver force/assign properties */
127    /* not drivers */
128    if (ntyp != vpiNet && ntyp != vpiNetBit) continue;
129 
130    drviter = vpi_iterate(vpiLocalDriver, href);
131    if (drviter != NULL)
132     {
133      vpi_printf("  Drivers:\n");
134      prt_iter(drviter, ihref);
135     }
136 
137    lditer = vpi_iterate(vpiPathTerm, href);
138    if (lditer != NULL)
139     {
140      vpi_printf("  Path terminals:\n");
141      prt_iter(lditer, ihref);
142     }
143 
144    lditer = vpi_iterate(vpiTchkTerm, href);
145    if (lditer != NULL)
146     {
147      vpi_printf("  Timing check terminals:\n");
148      prt_iter(lditer, ihref);
149     }
150   }
151 }
152 
153 /*
154  * print contents of one loads or drivers iterator iter inside instance ihref
155  *
156  * when called to print loads of task variables ihref will be nil
157  */
prt_iter(vpiHandle iter,vpiHandle ihref)158 static void prt_iter(vpiHandle iter, vpiHandle ihref)
159 {
160  int htyp;
161  vpiHandle href, portihref;
162  char *chp, s1[1025];
163 
164  for (;;)
165   {
166    if ((href = vpi_scan(iter)) == NULL) break;
167 
168    htyp = vpi_get(vpiType, href);
169    /* must handle port as special case because can be module port */
170    /* or up instance port connection */
171    if (htyp == vpiModPathIn || htyp == vpiModPathOut) strcpy(s1, "**NONE(0)");
172    else
173     {
174      if ((chp = vpi_get_str(vpiFile, href)) == NULL)
175       strcpy(s1, "**NONE(0)");
176      else sprintf(s1, "**%s(%d)", chp, vpi_get(vpiLineNo, href));
177     }
178    if (htyp == vpiPort)
179     {
180      /* if ld/drv net in same instance as port then module port */
181      /* else up instance connection */
182      portihref = vpi_handle(vpiModule, href);
183      if (vpi_compare_objects(ihref, portihref))
184       {
185        vpi_printf("   Port (vpiLowConn) object at %s\n", s1);
186       }
187      else
188       {
189        sprintf(s1, "**%s(%d)", vpi_get_str(vpiFile, portihref),
190         vpi_get(vpiLineNo, portihref));
191        vpi_printf("   Port (vpiHighConn) object at %s\n", s1);
192       }
193     }
194    else vpi_printf("    %s object at %s\n", vpi_get_str(vpiType, href), s1);
195   }
196 }
197 
198 /*
199  * print the drivers and loads for one task (should be no drivers?)
200  */
prt_1task_drvlds(vpiHandle thref)201 static void prt_1task_drvlds(vpiHandle thref)
202 {
203  vpiHandle iter;
204 
205  iter = vpi_iterate(vpiReg, thref);
206  if (iter != NULL) prt_1iter_drvlds(iter, NULL);
207  iter = vpi_iterate(vpiVariables, thref);
208  if (iter != NULL) prt_1iter_drvlds(iter, NULL);
209 
210  /* include all contained named blocks */
211  iter = vpi_iterate(vpiInternalScope, thref);
212  for (;;)
213   {
214    if ((thref = vpi_scan(iter)) == NULL) break;
215    prt_1task_drvlds(thref);
216   }
217 }
218 
219 /*
220  * routine to build an error indication string
221  */
my_error_handler(struct t_cb_data * cbp)222 int my_error_handler(struct t_cb_data *cbp)
223 {
224  struct t_vpi_error_info einfotab;
225  struct t_vpi_error_info *einfop;
226  char s1[128];
227 
228  einfop = &einfotab;
229  vpi_chk_error(einfop);
230 
231  if (einfop->state == vpiCompile) strcpy(s1, "vpiCompile");
232  else if (einfop->state == vpiPLI) strcpy(s1, "vpiPLI");
233  else if (einfop->state == vpiRun) strcpy(s1, "vpiRun");
234  else strcpy(s1, "**unknown**");
235 
236  vpi_printf("**ERR(%s) %s (level %d) at **%s(%d):\n  %s\n",
237   einfop->code, s1, einfop->level, einfop->file, einfop->line,
238   einfop->message);
239 
240  /* if serious error give up */
241  if (einfop->level == vpiError || einfop->level == vpiSystem
242   || einfop->level == vpiInternal)
243   {
244    vpi_printf("**FATAL: encountered error - giving up\n");
245    vpi_sim_control(vpiFinish, 0);
246   }
247  return(0);
248 }
249 
250 
251 /* Template functin table for added user systf tasks and functions.
252    See file vpi_user.h for structure definition
253    Note only vpi_register_systf and vpi_ or tf_ utility routines that
254    do not access the simulation data base may be called from these routines
255 */
256 
257 /* all routines are called to register cbs */
258 /* called just after all PLI 1.0 tf_ veriusertfs table routines are set up */
259 /* before source is read */
260 void (*vlog_startup_routines[]) () =
261 {
262  register_scan_cb,
263  0
264 };
265 
266 /* routine to do the systf registering - probably should go in other file */
267 /* usually only vpi_ PLI 2.0 systf or cb registering is done here */
268 
269 /*
270  * register the start of sim scan call back and set up error handling
271  *
272  * notice making version of Cver that prints some stuff to start but
273  * is a normal Cver
274  *
275  * since handle not save (passed back?), no way to find out cb info
276  */
register_scan_cb(void)277 void register_scan_cb(void)
278 {
279  vpiHandle href, href2;
280  struct t_cb_data *ecbp, *cbp;
281 struct t_cb_data cbrec;
282 
283  /* notice cb records must be in global storage */
284  ecbp = &cbrec;
285  ecbp->reason = cbPLIError;
286  ecbp->cb_rtn = my_error_handler;
287  ecbp->obj = NULL;
288  ecbp->time = NULL;
289  ecbp->value = NULL;
290  ecbp->user_data = NULL;
291 
292  /* probably should check for error here */
293  if ((href = vpi_register_cb(ecbp)) == NULL)
294   vpi_printf("**ERR: PLI 2.0 can not register error handler callback.\n");
295 
296  cbp = &cbrec;
297  cbp->reason = cbStartOfSimulation;
298  cbp->cb_rtn = process_all_insts;
299  cbp->obj = NULL;
300  cbp->time = NULL;
301  cbp->value = NULL;
302  cbp->user_data = NULL;
303 
304  /* probably should check for error here */
305  if ((href2 = vpi_register_cb(cbp)) == NULL)
306   vpi_printf(
307    "**ERR: PLI 2.0 can not register start of sim setup callback.\n");
308  /* if not registered will be no call backs */
309 
310  /* set the processing routine */
311  iproc_rtn = prt_drvlds;
312 }
313 
314 /* dummy +loadvpi= boostrap routine - mimics old style exec all routines */
315 /* in standard PLI vlog_startup_routines table */
vpi_compat_bootstrap(void)316 void vpi_compat_bootstrap(void)
317 {
318  int i;
319 
320  for (i = 0;; i++)
321   {
322    if (vlog_startup_routines[i] == NULL) break;
323    vlog_startup_routines[i]();
324   }
325 }
326