A System Call to Check the Run-time Environment

Copyright by
Swapnajit Mittra
Vineyard Reasearch Inc.

(This article was first published in TalkVerilog Newsletter by Cadence Design Systems)

While doing a simulation of an entire board consisting of many off-the-shelves modules and some ASICs An often-faced problemis that one of the floating inputs to any one of the modules leads to a propagation of Xs through-out the system and a subsequent break-down of the complete simulation.

When it is always possible to back-track the problem starting from the output of the ASIC, say, which is X and then going through its entire hierarchy only to find out that one of the inputs is X or Z, it is not only pain-staking and time-consuming, it also requires the knowledge about the internal of the ASIC, allowing only a few engineers of the design team to do that.

As a first check to avoid such situation, it is better to check the inputs of the module first and then proceed further. So far the only way to do that was to make a list of all the inputs and then make either a $display or $showvars at that point. When an ASIC has hundreds of inputs, this is going to be a tedious process.

The following PLI system call $peripheri just exactly does this job. When invoked, it lists all the ports of the module passed as an argument, describes the type (input, output etc.) and then tells the value of the signal associated with the port. It also gives the simulation time when it is invoked.

List 1 shows an example of a verilog code using this system call. List 2 shows the result and the actual C-code has been described in List 3. The program uses the PLI version 2.0 and uses library functions declared in the vpi_user.h file. This program does not work directly with PLI version 1.0.

 module mymux21test ;

   reg [1:0] a;
   reg s;

   mymux21 m1 (y, a, s);

   initial begin
   a[1] = 1'b1 ;
   a[0] = 1'b0 ;
   s = 1'b1 ;
   s = 1'b0 ;

   initial  begin

LIST 1 : A sample verilog code

 Highest level modules:

  Module m1 :                            Time 10
         Output  y :  1
         Input   a :  10
         Input   s :  1

  Module m1 :                            Time 110
         Output  y :  0
         Input   a :  10
         Input   s :  0
 L15 "test.v": $finish at simulation time 200
 24 simulation events

LIST 2 : Verilog output for the above code

   This PLI routine takes the  name of an instantiation and gives out 
   the signal values at its pins along with the pintype (input,output
   etc. ) of each pin.

   USAGE : $peripheri(instance_name) ;
   This routine has been designed, programmed and tested by :
   Swapnajit Mittra

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   GNU General Public License for more details.


#include "/mnt4/ver/tools/verilog/include/vpi_user.h"

int gnt_task ()   /* This is the calltf routine */
vpiHandle netHndl, modItr, modHndl, modHndl2, portItr, portHndl;
char *strPropVal1, *strPropVal2 ;
vpiHandle tfH, argI;

s_vpi_value got_value;
s_vpi_time time;

char dirn[8];

modItr = vpi_iterate(vpiModule, NULL );
if (!modItr) return ;

while (modHndl = vpi_scan(modItr)) {
   strPropVal1 = vpi_get_str(vpiDefName, modHndl) ; 
   tfH = vpi_handle(vpiSysTfCall, NULL ) ;
   if (!tfH) {
      vpi_printf(" USAGE : $peripheri(instance_name);\n");
   else {
      if (argI = vpi_iterate(vpiArgument, tfH)) {
	 modHndl2 = vpi_scan(argI) ;
	 strPropVal2 = vpi_get_str(vpiDefName, modHndl2);

   if (strcmp(strPropVal1,strPropVal2) == 0) {
      portItr = vpi_iterate (vpiPort, modHndl2 );
      if (!portItr) {
	 vpi_printf(" Module %s at the top level\n",strPropVal1);
      time.type = vpiSimTime;
      vpi_get_time(NULL, &time);
      vpi_printf("\n Module %s :\t\t\t\tTime %d\n",
                          vpi_get_str(vpiName, modHndl2),
			  /* I dont know why, but time.high always gives */
			  /* 0, whereas time.low gives the actual time.  */

      got_value.format = vpiBinStrVal;
      while (portHndl = vpi_scan (portItr)) {
	  netHndl = vpi_handle(vpiHighConn, portHndl);
	  vpi_get_value (netHndl, &got_value);

	  switch(vpi_get(vpiDirection,portHndl)) {
	  case vpiInput       : strcpy(dirn,"Input");
	  case vpiOutput      : strcpy(dirn,"Output");
	  case vpiInout       : strcpy(dirn,"Inout");
	  case vpiMixedIO     : strcpy(dirn,"Mixed IO");
	  case vpiNoDirection : strcpy(dirn,"No Dirn");
	  default             : vpi_printf(" Warning! Port direction not found for net %s\n", 
                                           vpi_get_str(vpiName, netHndl) );

	  vpi_printf("\t%s\t%s :  %s\n", dirn,
					 vpi_get_str(vpiName, netHndl),


void registration() /* Place all the function registration here */
s_vpi_systf_data task_data_s ; /* Allocate a data structure */
p_vpi_systf_data task_data_p = &task_data_s ;
			       /* and a pointer to it */

task_data_p->type = vpiSysTask; /* No return value for a task */
task_data_p->tfname = "$peripheri";   /* HDL task name */
task_data_p->calltf = (int(*)()) gnt_task;
				/* The routine associated with the task */
task_data_p->compiletf = NULL ; /*No function, enter Null */
vpi_register_systf(task_data_p) ;

/* Enter registration() in the startup array */
void (*vlog_startup_routines[])() = {registration, 0};

LIST 3 : The PLI C-code


Verification Management
Join Verification Management Group

Shop Amazon - Contract Cell Phones & Service Plans

Book of the Month