|
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 ;
#100
s = 1'b0 ;
#100
$finish;
end
initial begin
#10
$peripheri(mymux21test.m1);
#100
$peripheri(m1);
end
endmodule
LIST 1 : A sample verilog code
Highest level modules:
mymux21test
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
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
************************************************************************/
#include
#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");
return;
}
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);
return;
}
time.type = vpiSimTime;
vpi_get_time(NULL, &time);
vpi_printf("\n Module %s :\t\t\t\tTime %d\n",
vpi_get_str(vpiName, modHndl2),
time.low);
/* 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");
break;
case vpiOutput : strcpy(dirn,"Output");
break;
case vpiInout : strcpy(dirn,"Inout");
break;
case vpiMixedIO : strcpy(dirn,"Mixed IO");
break;
case vpiNoDirection : strcpy(dirn,"No Dirn");
break;
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),
got_value.value.str);
}
}
}
}
/************************************************************************/
/************************************************************************/
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
|