|
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
Previous | Next
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[] =
{
{usertask,0,my_checktf,0,invert_calltf,0,"$invert"},
{0}
};
*/
int my_checktf() {
if (tf_nump() != 1) {
tf_error("$invert:\n");
tf_error("Usage: $invert(register_name);\n");
}
if (tf_typep(1) != tf_readwrite)
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
|