Plis in Verification Environment: Surekha Sonawane Rohit Gupta Jitendra Puri

Download as pdf or txt
Download as pdf or txt
You are on page 1of 11

PLIs IN VERIFICATION ENVIRONMENT

Surekha Sonawane
Rohit Gupta
Jitendra Puri

surekha.sonawane@dcmtech.co.in
rohit.gupta@dcmtech.co.in
jitendra@dcmtech.co.in

ABSTRACT
Verification of complex system-on-chips (SOCs) and multi-million gate ASICs has become
extremely difficult. Top level testing of such huge projects require innovative efforts in the
process of data handling and manipulation. Use of PLIs is a good alternative to the conventional
methods to handle these complex requirements. This paper presents a simple and efficient way to
customize your verification environment using PLIs in C. It further details out how this approach
takes care of massive data storage and its processing.

1.0 Introduction
The amount of data processing required in the verification process has been steadily increasing
with the size and complexity of the design. In such large projects, the implementation of efficient
tasks or functions for data handling and manipulation through Verilog becomes a very tedious
activity. Programming Language Interface (PLI) provides a simple and efficient workaround to
these problems. This paper addresses such issues related to verification cycle with the help of
PLIs. The document covers a brief introduction to PLIs in C and its usage in the verification
components like Bus Functional Models (BFMs).

2.0 What is PLI?


PLI is a mechanism to incorporate user defined C language functions in a Verilog design. A PLI
consists of library function calls that one can use within C programs to access information
about the HDL description. PLI comprises of
!"Access routines that provide information about simulation data structures.
!"Utility routines that interact with the simulation environment.
!"A PLI mechanism that interprets user-defined routines as new system tasks and functions.
Using access and utility routines, designers can write C functions that interact dynamically with
the simulator. Such functions can be used to extract information about simulation environment
like module structure, event ordering, read and write data, delays etc. and enable a user to modify
this data accordingly.

2.1

Access routines

Access routines provide access to information about the internal data representation of an HDL
design. These routines can read/write information about particular objects like modules,
primitives, nets, registers, parameters, path delays and timing checks. Access routines can also be
used to monitor the changes in the value of these objects.
All access routines start with the prefix acc_ and the name indicates the type of information
the routine reads or writes.

2.2 Utility routines


Utility routines are primarily used to pass data to and fro the simulation environment across the
Verilog/C routine boundary. These routines can also perform synchronization tasks by accessing
information about simulation time and scheduled events. Special purpose functions for long
arithmetic calculations and customized displays can be written through utility routines.
All utility routines start with the prefix tf_, io_ or mc_.

SNUG San Jose 2002

PLIs In Verification Environment

3.0 Limitations of Verilog HDL


The IEEE standard 1364.1995 for Verilog does not provide enough features for efficient data
handling. The problem gets more severe when it comes to large projects requiring massive
amounts of data storage and manipulation.
!"Verilog only allows static memory storage through arrays. Dynamic memory management
features like storage in link lists, queues etc. cannot be implemented through Verilog.
!"Too much of efforts are required for writing complex sorting and data comparison
algorithms in Verilog. Basic bit selection operations in arrays and vectors are also not
supported in Verilog. User cannot access a single bit from an array. Similarly, in case of
vectors, part selection with variable index is not possible. For example, if record is an 8bit vector, we cannot access bit-part record [7:i] where i is a local variable.
!"Verilog provides a few file handling operations with very limited capabilities. The only
two system tasks available for reading from a file are $readmemh and $readmemb. Even
these tasks do not allow the user to assign the read data directly to a variable. The data
has to be dumped in some array, from where it can be used subsequently.
!"Another limitation of Verilog is that the integer data type has a fixed vector size, (32-bits
in most simulators). So, long arithmetic tasks cannot be implemented in Verilog.
!"Handling large amount of memory in Verilog may not be very efficient. For example, if a
test environment needs 4GB of memory, it is mandatory to allocate full 4GB through
arrays even if the test cases do not access all memory locations.
Such Verilog specific problems can be resolved using PLIs. Programming languages like C, Java
etc. are not bound by the HDL constraints and hence, can be used to overcome most of the
Verilog limitations. For example, to model a large memory space (say 4GB) for verification, a
link list can be written which stores the address locations that the test program uses, along with
the data for that location. There is no need to implement full 4GB memory space through arrays.
The memory access operation just needs traversing the link list, making simulation faster as
compared to conventional method.

SNUG San Jose 2002

PLIs In Verification Environment

4.0 PLIs in Verification Environment


Verification environment of a complex design would have various components like Test Bench,
Behavioral models, Checkers, Monitors etc. This paper talks of PLIs in specific context of
BFMs. BFMs are behavioral models that are used to emulate the bus functionality. A BFM
would generally have the following features
!"It would take cycle information as an input from the user. This information can be
provided through individual tasks or from a file.
!"It would maintain a transaction queue containing attributes of the cycles to be executed on
the bus.
!"Data manipulation tasks like generation of various data patterns, sorting, data comparison
etc. should be implemented in BFM.
!"It would also perform debugging functions like monitoring bus protocols and displaying
error messages.
PLIs can be used to support the above-mentioned features efficiently by implementing the
following functions:
!"Dynamic memory management.
!"Data generation and data comparison.
!"Performing file I/O and standard I/O functions.
!"Display error code/messages.
4.1 Dynamic Memory Management
PLIs exploit various dynamic memory management features of C for fast and efficient data
storage and processing. These features include various data storages like link lists, queues, stacks
etc. and functions like malloc, realloc, free.
BFMs require storing and restoring information belonging to each cycle to be run. All this data
has to be continuously updated during simulation. For initiating a cycle, BFM should have
complete information like sequence, cycle command, address, data, parity etc. All this data can
be stored in a structure.
struct cycle_info{
int sequence_id;
char *command;
char *address;
char *data;
int parity;
struct cycle_info *next; /* Pointer to the next node */
}
The sequence of cycles might also have to be organized according to the bus protocols. This
would mean frequently changing the order of the cycles in the queue, which requires tasks like
searching and sorting, based on different keys. This can be done very efficiently through link
lists. Also, the normal functions like adding, deleting and updating a particular element of the
structure becomes very simple.

SNUG San Jose 2002

PLIs In Verification Environment

The following example uses two PLIs to maintain the transaction queue and to fetch the cycle
information.
/* new_cycle adds information about a cycle in the transaction queue. The parameters passed to
this PLI are - sequence_id, command, address, data and parity in the same order */
void new_cycle()
{
/* This is the first node pointing to start of queue*/
struct cycle_info *temp_node1 = start_q;
/* New node to be added */
struct cycle_info *temp_node2add;
/* Allocating memory to the new node */
temp_node2add = (struct cycle_info *) malloc (sizeof(struct cycle_info));
/* Accessing integer variable sequence_id using acc_fetch_tfarg() routine
This is the 1st argument passed to the PLI */
temp_node2add->sequence_id = acc_fetch_tfarg(1);
/* Accessing character variables command, address and data using tc_strgetp() routine.
These are the 2nd, 3rd and 4th arguments passed to the PLI. b indicates binary format of the
returned parameters */
temp_node2add->command = (char*)tf_strgetp(2,b);
temp_node2add->address = (char *)tf_strgetp(3,b);
temp_node2add->data = (char *)tf_strgetp(4,b);
/* Accessing parity using acc_fetch_tfarg routine */
temp_node2add->parity = acc_fetch_tfarg(5);

/* Adding the new cycle to the link list. add_link function appends this new cycle
information to the last node in the link list */
add_link(temp_node2add);

SNUG San Jose 2002

PLIs In Verification Environment

/* get_cycle fetches cycle information from the transaction queue and deletes the node. The input
to this PLI is the sequence_id of the cycle to be fetched. The parameters returned are cycle
command, address, data and parity */
void get_cycle()
{
struct cycle_info *temp_node = start_q;
struct cycle_info *temp_node2get;
int sequence_id, len;
/* Fetching sequence id of the cycle to be executed */
sequence_id = acc_fetch_tfarg(1);
/* Searching for node in the link list. search_in_q function searches node with sequence_id as
key */
temp_node2get = search_in_q(sequence_id);
/* Get size of second argument, i.e. command */
len = tf_sizep(2);
/* Writing command in the second argument. tf_strdelputp takes argument number, its bit
length, format string and value as parameters. The last two parameters are delay and delay type*/
tf_strdelputp(2, len, b, temp_node2get->command, 0, 0);
len = tf_sizep(3);
tf_strdelputp(3, len, b, temp_node2get->address, 0, 0);
len = tf_sizep(4);
tf_strdelputp(4, len, b, temp_node2get->data, 0, 0);
/* Single bit parity is written using routine tf_putp */
tf_putp(5,temp_node2get->parity);
.
.
.
/* Deleting the cycle from the queue. del_link deletes a node from the link list using sequence
id */
del_link(sequence_id);
.
.
.
}

SNUG San Jose 2002

PLIs In Verification Environment

4.2 Data Generation and Data Comparison


In most of the verification processes, it is required to generate data in specific patterns. Like data
generation, data comparison functions also make important part of the verification process. These
sorts of data manipulation functions are very easy to implement in C and thats where PLIs come
into picture. These functions are very handy in environments where we have special data
checkers to monitor flow of data across various design units.
/* data_gen is used to modify any byte(0th ,1st ,2nd or 3rd) from a given 32-bit data.
The parameters passed are the byte to be changed and the data. The byte can be modified in any
user-specific way supported by C language*/
void data_gen()
{
int i;
char *data;
i=acc_fetch_tfarg(1);
data=(char *)tf_strgetp(2,b);

for(j=0;j<8;j++)
{
data[(i*8)+j]=data[(i*8)+j ]+1;
}
.
.
}

4.3 Performing file I/O and standard I/O functions


Many a times, it is required to give stimulus to a design for testing purpose through text files.
These files may be of any pattern and format (ASCI, binary). C provides a number of file
handling functions that can be effectively used through PLIs. The PLI functions can be designed
to transfer a block of data from memory to file and vice-versa or to compare two files. Standard
I/O functions can also be used for running simulation in a controlled environment.
/* dump_file PLI stores all the cycle information in a file whenever any of the cycle variables
change. The arguments passed to this PLI are sequence_id, address, data and parity. The routine
tf_asynchon enables the invocation of this PLI repeatedly. The user needs to call this PLI only
once in the Verilog code, and the simulator automatically triggers the PLI whenever any
argument changes. Usage of file-handling features in C can also be observed */

SNUG San Jose 2002

PLIs In Verification Environment

void dump_file()
{
FILE *ptr1;
int sequence_id;
char *addr, *data;
tf_asynchon();
sequence_id=acc_fetch_tfarg(1);
addr=(char *)tf_strgetp(2,b);
data=(char *)tf_strgetp(3,b);
ptr1=fopen(file_dump);
.
/*store it in the file using C file-handling functions*/
.
}

4.4 Display error code/messages.


Various PLI functions can be developed to print different type of customized messages which is
not possible through standard Verilog system call $display. These customized messages can
give information/error/warnings to the user during simulation. For example, to print all the errors
or warnings in a standard format, a PLI function message can be developed whose arguments
would be the text message to be printed and the type of message error, info or warning. Using
this PLI, uniformity of display messages can be maintained across different modules.
/* message is a customized display function that prints error or warning messages in standard
format. The parameters passed are type of message (1-error, 2-warning,3-info), and the message
string to be displayed. The routines used are acc_fetch_tfarg to fetch the message type and
tf_getcstringp to fetch the display message. tf_error and tf_warning gives a standard
error/warning message compatible with the simulator. tf_gettime gets the current simulation
time. io_printf is similar to standard C function printf */
void message()
{
int arg_num;
char *str_disp;
arg_num=acc_fetch_tfarg(1);
str_disp=tf_getcstringp(2);
if(arg_num==1)
tf_error(\n %s %d,str_disp,tf_gettime());
else if(arg_num==2)
tf_warning(\n %s %d,str_disp,tf_gettime());
else if(arg_num==3)
io_printf(\n Info-----%s %d,str_disp,tf_gettime());
}

SNUG San Jose 2002

PLIs In Verification Environment

5.0 Embedding PLI functions in Verilog HDL


The following figure shows the steps for creating a new PLI function and linking it with the
Verilog source code.

PLI TASK FLOW


Create a C
Program
Using PLI
Commands

Compile &
Link Verilog
and C
Application

Associate
the routine
with a
System

Task

Run the
Modified
Verilog
Code

After writing the PLI function in C, we have to associate and link this routine with the
corresponding HDL system task name. This process is simulator specific. Verilog-XL, VCS etc.
each use slightly different method for linking PLIs. For Verilog-XL, edit the veriusertfs array
(Refer PLI 1.0 User Guide and Reference from Cadence) in the veriuser.c file and declare the
PLI function as an external reference.
extern int new_cycle();
After association, run vconfig script from Verilog tools directory. The vconfig utility creates a
shell script with the default name cr_vlog which will compile and link the PLI with Verilog-XL.
After linking, a PLI function can be called from the Verilog source code just like any other
system call.
For example, the following code will call the PLI new_cycle
module top_test;
reg a;
reg [31:0]data;
initial
begin

$new_cycle(sequence_id, command, address, data, parity);

end
....
endmodule
In case of VCS, PLI tables have to be maintained in <filename>.tab file (See VCS Users Guide).
This PLI table identifies the user-defined tasks and functions, specify their Verilog syntax, and
relate them to particular C functions that compose the PLIs. This <filename>.tab file can be
linked using vcs compile command with -M option which generates the executable file. You
just need to run executable for simulation.

SNUG San Jose 2002

PLIs In Verification Environment

6.0 Conclusions and Recommendations


This paper gives a brief introduction to PLIs in C. Only a few useful routines have been
discussed here. Engineers should be encouraged to discover the full potential of PLIs so as to
find some new and innovative ways to customize their Verification Environment.
Implementation of PLIs in Java or Perl should also be investigated.

7.0 Acknowledgements
The authors wish to thank DCM PCI-X Core team for giving us time and support necessary to
write this paper. Special thanks to Mrs. Geeta Arora and Mr. Sanjay Budholiya for their valuable
guidance throughout.

8.0 References
[1] PLI 1.0 User Guide and Reference from Cadence.
[2] A Brief Introduction to PLI by Celia Clause.
[3] Sutherland HDL's The Verilog PLI Handbook.
[4] Verilog HDL, A Guide to Digital Design and Synthesis by Samir Palnitkar.
[5] VCS Users Guide from Synopsys.

SNUG San Jose 2002

10

PLIs In Verification Environment

9.0 Appendix
The following PLI routines have been used in this paper.
1) acc_fetch_tfarg: Fetches value of task argument associated with the routine.
Usage: acc_fetch_tfarg(argument_no)
argument_no is the position of argument in system task.
2) tf_strgetp: Gets argument value as a formatted character string.
Usage: tf_stregetp(argument_no, format_char)
argument_no is the position of the argument in system task,
format_char is the character specifying the format of argument value.
3) tf_sizep: Gets length of an argument in bits.
Usage: tf_sizep(argument_no)
argument_no is the position of the argument in the system task.
4) tf_strdelputp: Write a value to an argument with the specified delay.
Usage: tf_strdelputp(argument_no, bitlength, format_char, value, delay, delay_type)
argument_no is the position of the argument in the system task,
bitlength is size of the argument in bits,
format_char is the character specifying the format of argument value,
value is the value to be written to the argument,
delay is the delay before the written value is to take effect in Verilog simulation model,
delay_type is the type of delay.
5) tf_putp: Writes a 32-bit integer value to an argument.
Usage: tf_putp(argument_no, value)
argument_no is the position of the argument in the system task,
value is the value to be written to the argument.
6) tf_asynchon: Enables a PLI routine to be called whenever an argument changes value.
Usage: tf_asynchon()
7) tf_getcstringp: Gets an argument value as a C character string.
Usage: tf_getcstringp(argument_no)
argument_no is the position of the argument in the system task.
8) tf_error: Prints an error message.
Usage: tf_error(control_string, arg1, arg5)
control_string is the standard C printf data identifiers (%d, %c etc.) for each argument,
arg1arg5 are the variable components of the message corresponding to data identifiers.
9) tf_warning: Prints a warning message.
Usage: tf_warning(control_string, arg1, arg5)
control_string is the standard C printf data identifiers (%d, %c etc.) for each argument,
arg1arg5 are the variable components of the message corresponding to data identifiers.
10) tf_gettime: Gets current simulation time in integer form.
Usage: tf_gettime()
11) io_printf: Writes messages to the standard output and log file
Usage: io_printf(control_string, arg1,arg5)
control_string is the standard C printf data identifiers (%d, %c etc.) for each argument,
arg1arg5 are the variable components of the message corresponding to data identifiers.

SNUG San Jose 2002

11

PLIs In Verification Environment

You might also like