Memory instances and the PLI? 
Author Message
 Memory instances and the PLI?

: I need to be able to access the contents of memory from the PLI and can't find a method
: to either get a handle to a memory instance using the access routines or a call to
: set/get a value from the utilities.Is there a trick to doing this. Surely there must
: be a way other than $readmem???? Can anyone give me a clue?

Use tf_nodeinfo.

Send email if you have more questions related to this.

--
-------------------------------------------------------------------------------
mzelada                                   __  __     ____  ___       ___ ____

                                        /   / \  / / / / /__ /  \/ /___  /-------------------------------------------------------------------------------



Mon, 08 Dec 1997 03:00:00 GMT  
 Memory instances and the PLI?

Quote:

>I need to be able to access the contents of memory from the PLI and
>can't find a method
>to either get a handle to a memory instance using the access routines
>or a call to
>set/get a value from the utilities.Is there a trick to doing this.
>Surely there must
>be a way other than $readmem???? Can anyone give me a clue?

One way would be to use the tf_arg routines (assuming you're going to
pass the memory name to you routine), ie:

p_tfnodeinfo get_tfarg_info (tfarg)
int tfarg;
{
  p_tfnodeinfo arg;

  /* allocate space for the structure */
  arg = (p_tfnodeinfo) malloc (sizeof(s_tfnodeinfo));

  /* Get the nodeinfo structure */
  if (!tf_nodeinfo(tfarg, arg)) {
    tf_message(ERR_ERROR, "Verilog", "GINFOERR",
           "Error getting tfinfo for argument");
    free( arg ); /* cleanup on error */
  }

  return( arg );

Quote:
}

Later you may access the memory depth and bit width as
(or a ton of other information):

    p_tfnodeinfo mem;
    int depth, width;

    depth = mem->node_mem_size; /* memory depth */
    width = mem->node_vec_size; /* bit width */

At this point read/ write values as long as the memory is writable
(you may want to test!).

Regards,
Mark
--

/* MOTOROLA   Strategic Semiconductor Operation, IC Technology Laboratory */
/* Mail Stop 63, 1500 Gateway Boulevard, Boynton Beach, FL 33436-8292 USA */
/* phone: 1-407-739-2379, fax: 1-407-739-3904    ...just speaking for me! */



Thu, 11 Dec 1997 03:00:00 GMT  
 Memory instances and the PLI?

Quote:

>I need to be able to access the contents of memory from the PLI and can't find a method
>to either get a handle to a memory instance using the access routines or a call to
>set/get a value from the utilities.Is there a trick to doing this. Surely there must
>be a way other than $readmem???? Can anyone give me a clue?

Here are two methods for filling a memory in Verilog.  The first uses
the PLI tf_ utility routines (this is an oblivious access problem in
which you do not need to traverse a circuit) and the second uses two system
tasks added to Pragmatic C's Pver simulator.  The first method uses
the tf_strdelputp routine to fill the memory.  The memory can be read
using the analogous tf_strgetp routine.  The trick is that a PLI task
parameter can be something lime mem[i] where i can be changed by a loop
in the Verilog model.  The second uses an added $scanf routine:

---- cut here for the veriuser.c file ---
/*
 * example illustrating using PLI tf_ utility routines to fill memory
 */
#include <stdio.h>
/* assuming PLI tf_ routine include files in current directory */
#include "veriuser.h"
/* replace this file with your simulator's veriusertf local file */
#include "pvtfuser.h"

int memsiz, memwid, last_i;
FILE *memval_s;

intsize(data, reason)
 int data, reason;
{
 return(32);

Quote:
}

/*
 * routine to setup memory filling routine - set param to 0 on error else 1
 * function: $plisetupmemfill(memsiz, memwid)
 */
plisetupmemfill(data, reason)
 int data, reason;
{
 char *chp;

 /* get file name as + verilog argument */
 if ((chp = mc_scan_plusargs("memfile+")) == NULL || strcmp(chp, "") == 0)
  {
   tf_error("missing or empty +memfile+[file name] memory file argument");
   tf_putp(0, 0);
   return;
  }
 /* open the file */
 if ((memval_s = fopen(chp, "r")) == NULL)
  {  
   tf_error("unable to open +memfile+ memory file %s", chp);
   tf_putp(0, 0);
   return;
  }
 /* need memory size for checking */
 memsiz = tf_getp(1);
 memwid = tf_getp(2);
 tf_putp(0, 1);
 /* assume memory goes from 1 to size */
 last_i = 0;

Quote:
}

/*
 * check the fill memory user PLI function
 * notice calling tf_error here will inhibit simulation
 * probably sould also check 2nd index argument
 */
check_plimemfill(reason, data)
 int reason, data;
{
 struct t_tfexprinfo xinfo;

 if (tf_nump() != 2)
  {
   tf_error("$pli_memfill has %d arguments - 2 required", tf_nump());
   return;
  }
 tf_exprinfo(1, &xinfo);
 if (xinfo.expr_type != TF_RWMEMSELECT)
  {
   tf_error("$pli_memfill first argument not read/write memory select");
   return;
  }

Quote:
}

/*
 * routine to set memory
 * function: $pli_memfill(mem[i], i)
 */
plimemfill(data, reason)
 int data, reason;
{
 int i;
 char memval[1024];

 i = tf_getp(2);
 if (i < 0 || i > memsiz)
  {
   tf_error("cannot fill memory location %d - memory has only %d cells");
   tf_putp(0, 0);
   return;
  }
 if (fscanf(memval_s, "%s", memval) != 1)
  {
   /* problably should access OS error name here */
   tf_error("error reading memory value for cell %d", i);
   tf_putp(0, 0);
   return;
  }
 /* probably should add code to check for memval as legal binary number */
 /* but can be any width since putp assignment will widen or truncate */

 /* make sure index i is legal - since must have used i in memory select */
 /* only for checking */
 if (i != last_i + 1)
  {
   tf_error("memory index %d non in sequence - %d expected", i, last_i + 1);
   tf_putp(0, 0);
   return;
  }
 last_i = i;

 /* 0 delay is #0 and use normal Verilog inertial cancelation */
 /* in Pver you could use the added tf_strputp routine that causes */
 /* an immediate assign which is what is wanted here */
 if (tf_strdelputp(1, memwid, 'b', memval, 0, 0) == 0)
  {
   tf_error("strdelput of index memory failed");
   tf_putp(0, 0);
   return;
  }
 tf_putp(0, 1);

Quote:
}

/* example that goes in user code */
s_tfcell veriusertfs[] =
{
 { userfunction, 0, 0, intsize, plisetupmemfill, 0, "$pli_setupmemfill", 0},
 { userfunction, 0, check_plimemfill, intsize, plimemfill, 0, "$pli_memfill",
  0},
 /* -- add extra entries here -- */
 {0} /* -- this line must always be last -- */
Quote:
};

---- end veriuser.c file ---

Here is an example Verilog file run by the PLI version of Verilog.
---- cut here for plimfil.v verilog model file ----
module xx;
 reg [66:0] mem1[1:10];

initial
  begin
   fillmem;  
   $display("writing filled memory values:");
   writemem;
  end

 task fillmem;
  integer i;
  begin
   if ($pli_setupmemfill(10, 67) == 0) $finish;
   for (i = 1; i <= 10; i = i + 1)
    begin  
     if ($pli_memfill(mem1[i], i) == 0) $finish;
     // notice must delay after call because value of i cannot change
     // but if mem fill used extension tf_strputp routine not needed
     // if you do not need portability, tf_strputp is better
     #10;
    end
  end
 endtask

 task writemem;
  integer i;
  begin
   for (i = 1; i <= 10; i = i + 1) $display("%0d: %b", i, mem1[i]);
   $write("\n");
  end
 endtask
endmodule
--- end plimfil.v ---

Here is sample file to use to fill the memory.

---- cut here for testmem.dat file ----
0000000000_0000000000_0000000000_0000000000_0000000000_0000000000_0000000
1111111111_1111111111_1111111111_1111111111_1111111111_1111111111_1111111
xxxxxxxxxx_xxxxxxxxxx_xxxxxxxxxx_xxxxxxxxxx_xxxxxxxxxx_xxxxxxxxxx_xxxxxxx
zzzzzzzzzz_zzzzzzzzzz_zzzzzzzzzz_zzzzzzzzzz_zzzzzzzzzz_zzzzzzzzzz_zzzzzzz
0101010101_0101010101_0101010101_0101010101_0101010101_0101010101_0101010
x1x1x1x1x1_x1x1x1x1x1_x1x1x1x1x1_x1x1x1x1x1_x1x1x1x1x1_x1x1x1x1x1_x1x1x1x
1010101010_1010101010_1010101010_1010101010_1010101010_1010101010_1010101
1100110011_1100110011_1100110011_1100110011_1100110011_1100110011_1100110
z1z1z1z1z1_z1z1z1z1z1_z1z1z1z1z1_z1z1z1z1z1_z1z1z1z1z1_z1z1z1z1z1_z1z1z1z
01xz01xz01_01xz01xz01_01xz01xz01_01xz01xz01_01xz01xz01_01xz01xz01_01xz01x
---- end of testmem.dat file ----

If you call this PLI version of your simulator plimfill, to run the Verilog
file to fill the memory type:

plimfill -q +memfile+testmem.dat plimfil.v

The -q quiet option removes output that will differ between simulator runs.
The expected output is:

---- cut here for start of expected output ---
Copyright (c) 1991-1995 Pragmatic C Software Corp.
  Licensed software containing confidential and proprietary
  information belonging to Pragmatic C Software Corp.
writing filled memory values:
1: 0000000000000000000000000000000000000000000000000000000000000000000
2: 1111111111111111111111111111111111111111111111111111111111111111111
3: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
4: zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
5: 0101010101010101010101010101010101010101010101010101010101010101010
6: x1x1x1x1x1x1x1x1x1x1x1x1x1x1x1x1x1x1x1x1x1x1x1x1x1x1x1x1x1x1x1x1x1x
7: 1010101010101010101010101010101010101010101010101010101010101010101
8: 1100110011110011001111001100111100110011110011001111001100111100110
9: z1z1z1z1z1z1z1z1z1z1z1z1z1z1z1z1z1z1z1z1z1z1z1z1z1z1z1z1z1z1z1z1z1z
10: 01xz01xz0101xz01xz0101xz01xz0101xz01xz0101xz01xz0101xz01xz0101xz01x
--- end of expected output ---

Here is an alternative way to fill a memory using two functions added
to Verilog in the Pver simulator.  With $scanf it is better to read and
drive patterns rather than fill a memory since there is probably no need
to fill the memory.  One of the weakest parts of Verilog is the need to
use a $readmem or PLI system task to get input.  To run vermfil.v type:

 pver -q +memfile+testmem.dat vermfil.v

where your simulator (not linked PLI version) is used instead of pver.

The output is the same as plimfil.v.

---- cut here for Verilog version vermfil.v file ----
module xx;
 reg [66:0] mem1[1:10];

initial
  begin
   fillmem;  
   $display("writing filled memory values:");
   writemem;
  end

 task fillmem;
  integer i;
  reg [512*8:1] filename;
  begin
    // all zero register means empty filename value
    if ($scan$plusargs("memfile+", filename) != 1 || filename == 0)
     begin
      $display("memfile+ plus option not found or file name missing");
      $finish;
     end
    // only one scan file can be opened at once unlike C
    if ($openscanf(filename) == 0)
     begin
      $display("unable to open +memfile+ %s", filename);
      $finish;
     end
    for (i = 1; i <= 10; i = i + 1)
     begin  
      if ($scanf("%b", mem1[i]) != 1)
       begin
        $display("fail reading memory file line %d", i);
        $finish;
       end
     end
  end
 endtask

 task writemem;
  integer i;
  begin
   for (i = 1; i <= 10; i = i + 1) $display("%0d: %b", i, mem1[i]);
   $write("\n");
  end
 endtask
endmodule
---- cut here for file end ---
--
Steve Meyer                             Phone: (415) 296-7017
Pragmatic C Software Corp.              Fax:   (415) 781-1116

San Francisco, CA 94104



Fri, 12 Dec 1997 03:00:00 GMT  
 Memory instances and the PLI?
The one thing I notice is in using this technique I have to pass the memory with
a location instead of just as a memory reference or Verilog returns an error.

like

reg [31:0] mem [31:0];
initial $mem_register(mem[0]); // no error from tf_nodeinfo

initial $mem_register(mem); // error from tf_nodinfo

Is there a trick for this?



Sun, 14 Dec 1997 03:00:00 GMT  
 Memory instances and the PLI?

Quote:

> The one thing I notice is in using this technique I have to pass the memory
> with a location instead of just as a memory reference or Verilog returns an
> error.

> like

> reg [31:0] mem [31:0];
> initial $mem_register(mem[0]); // no error from tf_nodeinfo

> initial $mem_register(mem); // error from tf_nodinfo

> Is there a trick for this?

I was able to just use the memory without the location. I tested this using
Chronologic's VCS. Here is a snippet of my PLI code for $mem_register which
checks that the argument is really a memory:

      handle mem_handle;
      s_tfnodeinfo mem_ni;

      mem_handle = acc_handle_tfarg(1);

      /* Make sure the argument given is actually a memory. */
      tf_nodeinfo(1, &mem_ni);
      if (mem_ni.node_type != tf_memory_node) {
         io_printf("ERROR: Argument '%s' does not specify a memory.\n",
                acc_fetch_name(mem_handle));
         acc_close();
         tf_putp(0, 1);
         return;
      }

What sort of errors are you seeing? Which simulator are you using?

As an aside, if you are using VCS, you need to be aware of a VCS bug in
which the tf_nodeinfo() call returns misleading information for a 1-bit
memory.

So that everyone else knows what is being talked about, here is my
original response to Gordon, which I had previously emailed to him
directly:

Quote:
> I had to solve a similar problem last fall. I needed to be able to access
> a memory element by referring to it as a string. It took a bit of trickery
> and an extra PLI call to make it work.

> The first thing I did was create a PLI task which I called $mem_register.
> It was called like:

>    reg [31:0] mem [0:31];

>    initial
>       $mem_register(mem);

> The PLI code for this task simply got the full hierarchical name of the
> memory using the access routines and got the instance pointer using
> tf_getinstance(). These were saved away for later use.

> Next, you need to write the routines which actually access the memory.
> In my case these were called $mem_write and $mem_read. These were called
> like:

>    $mem_read("mem", addr, data_read);

> When this is called, I search for the memory name I saved before and I get
> the nodeinfo for the memory using tf_inodeinfo().

> If you are using Cadence Verilog, look in the example PLI directories for
> information on how the memory is organized in the data structures.

> There are two gotchas with this approach. First, the PLI code thinks that all
> memories start at zero. So, you either have to call the address to memory an
> offset or enhance $mem_register to be passed a starting offset. I chose to do
> the latter.

> The other gotcha is more serious. Consider the following example:

>    reg [31:0] mem [0:31];
>    wire [31:0] mem_1;

>    assign mem_0 = mem[0];
>    assign mem_1 = mem[1];

> In this example, if mem[0] and mem[1] are changed using the PLI, the wires
> mem_0 and mem_1 mem_1 will not be updated. This is stated as the way it is
> supposed to work in the the Cadence PLI manuals someplace. I think its
> broken.

> The way I got around this problem was to add more arguments to the
> $mem_register task. This now looks like:

>    $mem_register(mem, 0, mem[0], mem[1]);

> Now, when $mem_write is called, I also go through the remaining arguments
> and get the exprinfo using tf_iexprinfo() and propagate the memory change
> using tf_ipropagatep(). It's ugly, but I could find no other solution.

--
+-------------------------------------------------------+
| Steve Miller                          Ascom Nexion    |

| (508) 266-3421                        Acton, MA 01720 |
+-------------------------------------------------------+


Tue, 16 Dec 1997 03:00:00 GMT  
 
 [ 5 post ] 

 Relevant Pages 

1. instances of classes and instances of instances

2. PLI memory leak problem

3. Passing a memory to the PLI - how?

4. Can you write a memory from PLI?

5. Free PLI applications - Queues, memory, logging and random

6. How to read an memory element from PLI?

7. PLI access to memory?

8. VisualAge PLI Enterprise vs. VisualAge PLI Personal

9. PLI-32 Alpha 3.10 (Single message ZIP file (30K)) - pli-32.zip (0/1)

10. PLI-32 Alpha 3.10 (Single message ZIP file (30K)) - pli-32.zip (1/1)

11. PLI-32 For NT, alpha 3.10 (ZIP File: 378K] - pli-32.zip (10/10)

12. PLI-32 For NT, alpha 3.10 (ZIP File: 378K] - pli-32.zip (06/10)

 

 
Powered by phpBB® Forum Software