This is an excerpt from the Chapter 1 of the book Principles of Verilog PLI by Swapnajit Mittra published from Kluwer Academic Publishers. ISBN: 0-7923-8477-6 [All copyright reserved. No portion of this text can be used for for commercial purpose without explicit permission from the author nor can it be used for re-print in hardcopy or electronic form.] Order the book here.

PLI - A QUICK TOUR

MODIFYING THE CONTENT OF A REGISTER

If reading the design information is one reason why PLI is used, the other reason would be to modify these informations in the design database. The following example shows how it is done.

Problem description
Create a system call \$invert to print the value of a register (just like what was done in the last example), bit-wise invert the content andprint this updated value too. (So at the end the register will have one's complement of its current content.)

There are more than one ways of getting the inverted value. The algorithm described below may not be the smartest as far as doing one's complementis concerned, but it will give more insight into the PLI mechanism and library functions.

Read the content of the register is as a string;
Make the following modifications on the string:
Flip all 1s in the stringto 0s and all 0s to 1s;
All Zs become X and Xs,if any, remain intact.
Put back the modified string into the register.

The calltf function
The checktf function in this case will not be different from the earlier one as in both cases the number and type input parameter is same.The following code shows the invert_calltf - the calltf function for the \$invert routine.

int invert_calltf() {
char *val_string;
/* The string which temporarily holdsthe value of the reg */
/* Step 1 of the algorithm */
val_string = (char *) malloc(tf_sizep(1)+1);
/* +1 to accomodate the null char at the end */
strcpy(val_string, tf_strgetp(1, 'b'));
/* Step 2 of the algorithm */
move('1', '2', val_string);
move('0', '1', val_string);
move('z', 'x', val_string);
move('2', '0', val_string);
/* Step 3 of the algorithm */
io_printf("\$invert: Modifying the content from %s to %s at time %d\n",tf_strgetp(1, 'b'), val_string, tf_gettime());
/* The print statement should conatin the name of the PLI routine */
tf_strdelputp(1, tf_sizep(1), 'b', val_string, 0, 0);
}

The description and the usage of the library functions used above aregiven below.

• tf_strgetp(): Reads the content of the register as a string, just like tf_getp() reads it as a decimal.
• tf_strdelputp() : Assigns a value to the register as a string. This function takes a number of arguments. In order of their position they are : the parameter serial number, size of the string whose value is going to be put in (which, in the present case, should be same as the size of the register),the encoding radix, the actual string and two other delay related arguments,which we chose to ignore by passing 0s for them. (Though it will not be used in the present example, it is worth noting that, there is a simpler decimal counterpart of tf_strdelputp() too. It is called tf_putp()).
Here one important point to remember is that the content of only certain objects can be changed or overwritten from a PLI routine. Any attempt tochange a variable which can not be put on the left hand side of a procedural assignment in Verilog, would result in an error.

In general, the content of a variable, whose type is tf_readwrite, canbe modified. This is checked in the checktf function my_checktf().

Once tf_strgetp() reads the content in binary format ( 'h' or 'o' would have read it in hexadecimal or octal format ) it is copied to a string val_string.

move() is a function yet to be defined, which would replace each occurance of the first parameter (a character) by the second parameter (another character) in the third parameter (a string). Once 0s are converted to1s, to distinguish between these inverted 0s and original 1s in the string, at first all 1s are changed to 2 - an invalid value for binary logic, but a work around for us. At the end, all 2s
are converted back to 0s.

The program completes its task by putting back the inverted valueback into the register using tf_strdelputp() function.

Here is the code for move().

void move(from, to, in_str)
char from, to, *in_str;
{
int i=0;
while(*(in_str+i)) {
if (*(in_str+i) == from)
*(in_str+i) = to;
i++;
}
}

The complete code for the entire PLI routine is given below. Note thatthis time it is written for the VCS simulator.

#include "vcsuser.h"
/* In stead of the above, Verilog-XLuser should put :
#include "veriuser.h"
#include "vxl_veriuser.h"
*/
int invert_calltf(), my_checktf();
void move();
/* Verilog-XL users should have thefollowing :
char *veriuser_version_str ="\n\
=============================\n\
VERILOG PLI FIRST_ATTEMPT \n\
(\$invert)\n\
=============================\n";
int (*endofcompile_routines[])() ={0};
bool err_intercept(level, facility,code)
int level; char * facility; char *code;
{ return (true); }
s_tfcell veriusertfs[] =
{
{0}
};
*/

int my_checktf() {
if (tf_nump() != 1) {
tf_error("\$invert:\n");
tf_error("Usage: \$invert(register_name);\n");
}
tf_error ("\$invert: The argument must be a register type\n");
}

int invert_calltf() {
char *val_string;
/* The string which temporarily holdsthe value of the reg */

/* Step 1 of the algorithm */
val_string = (char *) malloc(tf_sizep(1)+1);
/* +1 to accomodate the null char at the end */
strcpy(val_string, tf_strgetp(1, 'b'));

/* Step 2 of the algorithm */
move('1', '2', val_string);
move('0', '1', val_string);
move('z', 'x', val_string);
move('2', '0', val_string);

/* Step 3 of the algorithm */
io_printf("\$invert: Modifying the content from %s to %s at time %d\n",tf_strgetp(1, 'b'), val_string, tf_gettime());
/* A message should always conatin
the name of the PLI routine */
tf_strdelputp(1, tf_sizep(1), 'b',
val_string, 0, 0);
}

void move(from, to, in_str)
char from, to, *in_str;
{
int i=0;
while(*(in_str+i)) {
if (*(in_str+i) == from)
*(in_str+i) = to;
i++;
}
}

For VCS, the equivalent of veriusertfs[] structure is given in a file pli.tab whose content in this case is given below.

\$invert call=invert_calltf check=my_checktf

Previous | Next