uvm_hdl——DPI在UVM中的实现(四)

  我们可以在uvm中实现HDL的后门访问,具体包括的function有uvm_hdl_check_path,uvm_hdl_deposit, uvm_hdl_force,uvm_hdl_release,uvm_hdl_read, task 有uvm_hdl_force_time。 这么做与直接用SV中force, release 有什么区别,有什么好处?这么做的话函数的输入是字符串而不是HDL(hardware description language, 硬件描述语言 )的层次结构。有了字符串就可以模块化了(函数),首先来看uvm_hdl.svh的源代码,当定义了UVM_HDL_NO_DPI,而用户由调用了HDL DPI相关的函数,这时会报错。

// TITLE: UVM HDL Backdoor Access support routines.
//
// These routines provide an interface to the DPI/PLI
// implementation of backdoor access used by registers.
//
// If you DON'T want to use the DPI HDL API, then compile your
// SystemVerilog code with the vlog switch
//:   vlog ... +define+UVM_HDL_NO_DPI ...
//


`ifndef UVM_HDL__SVH
`define UVM_HDL__SVH


`ifndef UVM_HDL_MAX_WIDTH
`define UVM_HDL_MAX_WIDTH 1024
`endif

/* 
 * VARIABLE: UVM_HDL_MAX_WIDTH
 * Sets the maximum size bit vector for backdoor access. 
 * This parameter will be looked up by the 
 * DPI-C code using:
 *   vpi_handle_by_name(
 *     "uvm_pkg::UVM_HDL_MAX_WIDTH", 0);
 */
parameter int UVM_HDL_MAX_WIDTH = `UVM_HDL_MAX_WIDTH;


typedef logic [UVM_HDL_MAX_WIDTH-1:0] uvm_hdl_data_t;

                            
`ifndef UVM_HDL_NO_DPI

  // Function: uvm_hdl_check_path
  //
  // Checks that the given HDL ~path~ exists. Returns 0 if NOT found, 1 otherwise.
  //
  import "DPI-C" context function int uvm_hdl_check_path(string path);


  // Function: uvm_hdl_deposit
  //
  // Sets the given HDL ~path~ to the specified ~value~.
  // Returns 1 if the call succeeded, 0 otherwise.
  //
  import "DPI-C" context function int uvm_hdl_deposit(string path, uvm_hdl_data_t value);


  // Function: uvm_hdl_force
  //
  // Forces the ~value~ on the given ~path~. Returns 1 if the call succeeded, 0 otherwise.
  //
  import "DPI-C" context function int uvm_hdl_force(string path, uvm_hdl_data_t value);


  // Function: uvm_hdl_force_time
  //
  // Forces the ~value~ on the given ~path~ for the specified amount of ~force_time~.
  // If ~force_time~ is 0,  is called.
  // Returns 1 if the call succeeded, 0 otherwise.
  //
  task uvm_hdl_force_time(string path, uvm_hdl_data_t value, time force_time = 0);
    if (force_time == 0) begin
      void'(uvm_hdl_deposit(path, value));
      return;
    end
    if (!uvm_hdl_force(path, value))
      return;
    #force_time;
    void'(uvm_hdl_release_and_read(path, value));
  endtask


  // Function: uvm_hdl_release_and_read
  //
  // Releases a value previously set with .
  // Returns 1 if the call succeeded, 0 otherwise. ~value~ is set to
  // the HDL value after the release. For 'reg', the value will still be
  // the forced value until it has been procedurally reassigned. For 'wire',
  // the value will change immediately to the resolved value of its
  // continuous drivers, if any. If none, its value remains as forced until
  // the next direct assignment.
  //
  import "DPI-C" context function int uvm_hdl_release_and_read(string path, inout uvm_hdl_data_t value);


  // Function: uvm_hdl_release
  //
  // Releases a value previously set with .
  // Returns 1 if the call succeeded, 0 otherwise.
  //
  import "DPI-C" context function int uvm_hdl_release(string path);


  // Function: uvm_hdl_read()
  //
  // Gets the value at the given ~path~.
  // Returns 1 if the call succeeded, 0 otherwise.
  //
  import "DPI-C" context function int uvm_hdl_read(string path, output uvm_hdl_data_t value);

`else

  function int uvm_hdl_check_path(string path);
    uvm_report_fatal("UVM_HDL_CHECK_PATH", 
      $sformatf("uvm_hdl DPI routines are compiled off. Recompile without +define+UVM_HDL_NO_DPI"));
    return 0;
  endfunction

  function int uvm_hdl_deposit(string path, uvm_hdl_data_t value);
    uvm_report_fatal("UVM_HDL_DEPOSIT", 
      $sformatf("uvm_hdl DPI routines are compiled off. Recompile without +define+UVM_HDL_NO_DPI"));
    return 0;
  endfunction

  function int uvm_hdl_force(string path, uvm_hdl_data_t value);
    uvm_report_fatal("UVM_HDL_FORCE", 
      $sformatf("uvm_hdl DPI routines are compiled off. Recompile without +define+UVM_HDL_NO_DPI"));
    return 0;
  endfunction

  task uvm_hdl_force_time(string path, uvm_hdl_data_t value, time force_time=0);
    uvm_report_fatal("UVM_HDL_FORCE_TIME", 
      $sformatf("uvm_hdl DPI routines are compiled off. Recompile without +define+UVM_HDL_NO_DPI"));
  endtask

  function int uvm_hdl_release(string path, output uvm_hdl_data_t value);
    uvm_report_fatal("UVM_HDL_RELEASE", 
      $sformatf("uvm_hdl DPI routines are compiled off. Recompile without +define+UVM_HDL_NO_DPI"));
    return 0;
  endfunction

  function int uvm_hdl_read(string path, output uvm_hdl_data_t value);
    uvm_report_fatal("UVM_HDL_READ", 
      $sformatf("uvm_hdl DPI routines are compiled off. Recompile without +define+UVM_HDL_NO_DPI"));
    return 0;
  endfunction

`endif


`endif

与之对应的uvm_hdl.c实现如下,由于每个EDA vendor 具体实现方式不同,所有分别包含在不同的文件中了。

// hdl vendor backends are defined for VCS,QUESTA,INCA
#if defined(VCS) || defined(VCSMX)
#include "uvm_hdl_vcs.c"
#else
#ifdef QUESTA
#include "uvm_hdl_questa.c"
#else
#if defined(INCA) || defined(NCSC)
#include "uvm_hdl_inca.c"
#else
#error "hdl vendor backend is missing"
#endif
#endif
#endif

首先来看Synopsy家的uvm_hdl_vcs.c:

#include "uvm_dpi.h"
#include 

#include "svdpi.h"
#include "vcsuser.h"

#ifdef VCSMX
#include "mhpi_user.h"
#include "vhpi_user.h"
#endif


/* 
 * UVM HDL access C code.
 *
 */

/*
 * This C code checks to see if there is PLI handle
 * with a value set to define the maximum bit width.
 *
 * If no such variable is found, then the default 
 * width of 1024 is used.
 *
 * This function should only get called once or twice,
 * its return value is cached in the caller.
 *
 */
static int uvm_hdl_max_width()
{
  vpiHandle ms;
  s_vpi_value value_s = { vpiIntVal, { 0 } };
  ms = vpi_handle_by_name((PLI_BYTE8*) "uvm_pkg::UVM_HDL_MAX_WIDTH", 0);
  if(ms == 0) 
    return 1024;  /* If nothing else is defined, 
                     this is the DEFAULT */
  vpi_get_value(ms, &value_s);
  return value_s.value.integer;
}


/*
 * Given a path, look the path name up using the PLI,
 * and set it to 'value'.
 */
static int uvm_hdl_set_vlog(char *path, p_vpi_vecval value, PLI_INT32 flag)
{
  static int maxsize = -1;
  vpiHandle r;
  s_vpi_value value_s = { vpiIntVal, { 0 } };
  s_vpi_time  time_s = { vpiSimTime, 0, 0, 0.0 };

  //vpi_printf("uvm_hdl_set_vlog(%s,%0x)\n",path,value[0].aval);

  r = vpi_handle_by_name(path, 0);

  if(r == 0)
  {
      const char * err_str = "set: unable to locate hdl path (%s)\n Either the name is incorrect, or you may not have PLI/ACC visibility to that name";
      char buffer[strlen(err_str) + strlen(path)];
      sprintf(buffer, err_str, path);
      m_uvm_report_dpi(M_UVM_ERROR,
                       (char*) "UVM/DPI/HDL_SET",
                       &buffer[0],
                       M_UVM_NONE,
                       (char*)__FILE__,
                       __LINE__);
    return 0;
  }
  else
  {
    if(maxsize == -1) 
        maxsize = uvm_hdl_max_width();

    if (flag == vpiReleaseFlag) {
      //size = vpi_get(vpiSize, r);
      //value_p = (p_vpi_vecval)(malloc(((size-1)/32+1)*8*sizeof(s_vpi_vecval)));
      //value = &value_p;
    }
    value_s.format = vpiVectorVal;
    value_s.value.vector = value;
    vpi_put_value(r, &value_s, &time_s, flag);  
    //if (value_p != NULL)
    //  free(value_p);
    if (value == NULL) {
      value = value_s.value.vector;
    }
  }
  return 1;
}


/*
 * Given a path, look the path name up using the PLI
 * and return its 'value'.
 */
static int uvm_hdl_get_vlog(char *path, p_vpi_vecval value, PLI_INT32 flag)
{
  static int maxsize = -1;
  int i, size, chunks;
  vpiHandle r;
  s_vpi_value value_s;

  r = vpi_handle_by_name(path, 0);

  if(r == 0)
  {
      const char * err_str = "get: unable to locate hdl path (%s)\n Either the name is incorrect, or you may not have PLI/ACC visibility to that name";
      char buffer[strlen(err_str) + strlen(path)];
      sprintf(buffer, err_str, path);
      m_uvm_report_dpi(M_UVM_ERROR,
              (char*)"UVM/DPI/HDL_GET",
                       &buffer[0],
                       M_UVM_NONE,
                       (char*)__FILE__,
                       __LINE__);
    // Exiting is too harsh. Just return instead.
    // tf_dofinish();
    return 0;
  }
  else
  {
    if(maxsize == -1) 
        maxsize = uvm_hdl_max_width();

    size = vpi_get(vpiSize, r);
    if(size > maxsize)
    {
      const char * err_str = "uvm_reg : hdl path '%s' is %0d bits, but the maximum size is %0d.  You can increase the maximum via a compile-time flag: +define+UVM_HDL_MAX_WIDTH=";
      char buffer[strlen(err_str) + strlen(path) + (2*int_str_max(10))];
      sprintf(buffer, err_str, path, size, maxsize);
      m_uvm_report_dpi(M_UVM_ERROR,
              (char*)"UVM/DPI/HDL_SET",
                       &buffer[0],
                       M_UVM_NONE,
                       (char*)__FILE__,
                       __LINE__);
      return 0;
    }
    chunks = (size-1)/32 + 1;

    value_s.format = vpiVectorVal;
    vpi_get_value(r, &value_s);
    /*dpi and vpi are reversed*/
    for(i=0;ii)
    {
      value[i].aval = value_s.value.vector[i].aval;
      value[i].bval = value_s.value.vector[i].bval;
    }
  }
  //vpi_printf("uvm_hdl_get_vlog(%s,%0x)\n",path,value[0].aval);
  return 1;
}


/*
 * Given a path, look the path name up using the PLI,
 * but don't set or get. Just check.
 *
 * Return 0 if NOT found.
 * Return 1 if found.
 */
int uvm_hdl_check_path(char *path)
{
  vpiHandle r;

  r = vpi_handle_by_name(path, 0);

  if(r == 0)
      return 0;
  else 
    return 1;
}

/*
 * convert binary to integer
 */
long int uvm_hdl_btoi(char *binVal) {
  long int remainder, dec=0, j = 0;
  unsigned long long int bin;
  int i;
  char tmp[2];
  tmp[1] = '\0';

  for(i= strlen(binVal) -1 ; i >= 0 ; i--) {
    tmp[0] = binVal[i];
    bin = atoi(tmp);
    dec = dec+(bin*(pow(2,j)));
    j++;
  }
  return(dec);
}


/*
 *decimal to hex conversion
 */
char *uvm_hdl_dtob(long int decimalNumber) {
   int remainder, quotient;
  int  i=0,j, length;
  int binN[65];
  static char binaryNumber[65];
  char *str = (char*) malloc(sizeof(char));

  quotient = decimalNumber;

  do {
    binN[i++] = quotient%2;
    quotient = quotient/2;
  } while (quotient!=0);
  length = i;

  for (i=length-1, j = 0; i>=0; i--) {
    binaryNumber[j++] = binN[i]?'1':'0';
  }
  binaryNumber[j] = '\0';
  return(binaryNumber);
}


/*
 * Mixed lanaguage API Get calls
 */
#ifdef VCSMX
int uvm_hdl_get_mhdl(char *path, p_vpi_vecval value) {

  long int value_int;

  char *binVal;
  int i = 0;
  vhpiValueT value1;
  p_vpi_vecval vecval;
  mhpi_initialize('/');
  mhpiHandleT mhpiH = mhpi_handle_by_name(path, 0);
  vhpiHandleT vhpiH = (long unsigned int *)mhpi_get_vhpi_handle(mhpiH);
  value1.format=vhpiStrVal;
  value1.bufSize = vhpi_get(vhpiSizeP, vhpiH);
  value1.value.str = (char*)malloc(value1.bufSize*sizeof(char)+1);


  if (vhpi_get_value(vhpiH, &value1) == 0) {
    binVal = value1.value.str;
    
    value_int = uvm_hdl_btoi(binVal);
    value->aval = (PLI_UINT32) value_int;
    value->bval = 0;
    mhpi_release_parent_handle(mhpiH);
    free(value1.value.str);
    return(1);
    

  } else {
    mhpi_release_parent_handle(mhpiH);
    free(value1.value.str);
    return (0);
  }

}
#endif

/*
 * Given a path, look the path name up using the PLI
 * or the VHPI, and return its 'value'.
 */
int uvm_hdl_read(char *path, p_vpi_vecval value)
{
#ifndef VCSMX
     return uvm_hdl_get_vlog(path, value, vpiNoDelay);
#else
    mhpi_initialize('/');
    mhpiHandleT h = mhpi_handle_by_name(path, 0);
    if (mhpi_get(mhpiPliP, h) == mhpiVpiPli) {
    mhpi_release_parent_handle(h);
      return uvm_hdl_get_vlog(path, value, vpiNoDelay);
    }
    else if (mhpi_get(mhpiPliP, h) == mhpiVhpiPli) {

    mhpi_release_parent_handle(h);
      return uvm_hdl_get_mhdl(path,value);
    }
#endif
}


/*
 * Mixed Language API Set calls
 */
#ifdef VCSMX
int uvm_hdl_set_mhdl(char *path, p_vpi_vecval value, mhpiPutValueFlagsT flags) 
{
    mhpi_initialize('/');
    mhpiRealT forceDelay = 0;
    mhpiRealT cancelDelay = -1;
    mhpiReturnT ret;
    mhpiHandleT h = mhpi_handle_by_name(path, 0);
    mhpiHandleT mhpi_mhRegion = mhpi_handle(mhpiScope, h);
    int val = value->aval;
    char *force_value = uvm_hdl_dtob(val);

    ret = mhpi_force_value(path, mhpi_mhRegion, force_value, flags, forceDelay, cancelDelay); 
    mhpi_release_parent_handle(h);
    if (ret == mhpiRetOk) {
      return(1);
    }
    else 
      return(0);
}
#endif

/*
 * Given a path, look the path name up using the PLI
 * or the VHPI, and set it to 'value'.
 */
int uvm_hdl_deposit(char *path, p_vpi_vecval value)
{
#ifndef VCSMX
     return uvm_hdl_set_vlog(path, value, vpiNoDelay);
#else
    mhpi_initialize('/');
    mhpiHandleT h = mhpi_handle_by_name(path, 0);

    if (mhpi_get(mhpiPliP, h) == mhpiVpiPli) {
    mhpi_release_parent_handle(h);
      return uvm_hdl_set_vlog(path, value, vpiNoDelay);
    }
    else if (mhpi_get(mhpiPliP, h) == mhpiVhpiPli) {
      mhpi_release_parent_handle(h);
      return uvm_hdl_set_mhdl(path, value, mhpiNoDelay);
     }
    else
      return (0);
#endif
}


/*
 * Given a path, look the path name up using the PLI
 * or the VHPI, and set it to 'value'.
 */
int uvm_hdl_force(char *path, p_vpi_vecval value)
{
#ifndef VCSMX
      return uvm_hdl_set_vlog(path, value, vpiForceFlag);
#else
    mhpi_initialize('/');
    mhpiHandleT h = mhpi_handle_by_name(path, 0);

    if (mhpi_get(mhpiPliP, h) == mhpiVpiPli) {
    mhpi_release_parent_handle(h);
      return uvm_hdl_set_vlog(path, value, vpiForceFlag);
    }
    else if (mhpi_get(mhpiPliP, h) == mhpiVhpiPli) {

    mhpi_release_parent_handle(h);
      return uvm_hdl_set_mhdl(path, value, mhpiForce);

      }
    else
      return (0);
#endif
}


/*
 * Given a path, look the path name up using the PLI
 * or the VHPI, and release it.
 */
int uvm_hdl_release_and_read(char *path, p_vpi_vecval value)
{
    return uvm_hdl_set_vlog(path, value, vpiReleaseFlag);
}

/*
 * Given a path, look the path name up using the PLI
 * or the VHPI, and release it.
 */
int uvm_hdl_release(char *path)
{
    s_vpi_vecval value;
    p_vpi_vecval valuep = &value;
#ifndef VCSMX
     return uvm_hdl_set_vlog(path, valuep, vpiReleaseFlag);
#else
    mhpi_initialize('/');
    mhpiHandleT h = mhpi_handle_by_name(path, 0);
    mhpiReturnT ret;

    if (mhpi_get(mhpiPliP, h) == mhpiVpiPli) {
      return uvm_hdl_set_vlog(path, valuep, vpiReleaseFlag);
    }
    else if (mhpi_get(mhpiPliP, h) == mhpiVhpiPli) {
      mhpiHandleT mhpi_mhRegion = mhpi_handle(mhpiScope, h);
      ret = mhpi_release_force(path, mhpi_mhRegion);
      if (ret == mhpiRetOk) {
        return(1);
      }
      else 
        return(0);

      }
    else
      return (0);
#endif
}
View Code

再看Cadence家的uvm_hdl_inca.c:

// use -DINCA_EXTENDED_PARTSEL_SUPPORT to use extended support for vpi_handle_by_name

#include "vhpi_user.h"
#include "vpi_user.h"
#include "veriuser.h"
#include "svdpi.h"
#include <malloc.h>
#include <string.h>
#include 

static void m_uvm_error(const char *ID, const char *msg, ...);
static int uvm_hdl_set_vlog(char *path, p_vpi_vecval value, PLI_INT32 flag);
static void m_uvm_get_object_handle(const char* path, vhpiHandleT *handle,int *language);
static int uvm_hdl_get_vlog(char *path, p_vpi_vecval value, PLI_INT32 flag);
static int uvm_hdl_max_width();

// static print buffer
static char m_uvm_temp_print_buffer[1024];

/* 
 * UVM HDL access C code.
 *
 */
static void m_uvm_get_object_handle(const char* path, vhpiHandleT *handle,int *language)
{
  *handle = vhpi_handle_by_name(path, 0);

  if(*handle)
      *language = vhpi_get(vhpiLanguageP, *handle);
}

// returns 0 if the name is NOT a slice
// returns 1 if the name is a slice
static int is_valid_path_slice(const char* path) {
      char *path_ptr = (char *) path;
      int path_len;

#ifdef INCA_EXTENDED_PARTSEL_SUPPORT
      return 0;
#endif

      path_len = strlen(path);
      path_ptr = (char*)(path+path_len-1);

      if (*path_ptr != ']')
        return 0;

      while(path_ptr != path && *path_ptr != ':' && *path_ptr != '[')
        path_ptr--;

      if (path_ptr == path || *path_ptr != ':')
        return 0;

      while(path_ptr != path && *path_ptr != '[')
        path_ptr--;

      if (path_ptr == path || *path_ptr != '[')
        return 0;

      return 1;
}

static int uvm_hdl_set_vlog_partsel(char *path, p_vpi_vecval value, PLI_INT32 flag)
{
  char *path_ptr = path;
  int path_len;
  svLogicVecVal bit_value;

  if(!is_valid_path_slice(path)) return 0;
  path_len = strlen(path);
  path_ptr = (char*)(path+path_len-1);

  if (*path_ptr != ']')
    return 0;

  while(path_ptr != path && *path_ptr != ':' && *path_ptr != '[')
    path_ptr--;

  if (path_ptr == path || *path_ptr != ':')
    return 0;

  while(path_ptr != path && *path_ptr != '[')
    path_ptr--;

  if (path_ptr == path || *path_ptr != '[')
    return 0;

  int lhs, rhs, width, incr;

  // extract range from path
  if (sscanf(path_ptr,"[%u:%u]",&lhs, &rhs)) {
    char index_str[20];
    int i;
    path_ptr++;
    path_len = (path_len - (path_ptr - path));
    incr = (lhs>rhs) ? 1 : -1;
    width = (lhs>rhs) ? lhs-rhs+1 : rhs-lhs+1;

    // perform set for each individual bit
    for (i=0; i < width; i++) {
      sprintf(index_str,"%u]",rhs);
      strncpy(path_ptr,index_str,path_len);
      svGetPartselLogic(&bit_value,value,i,1);
      rhs += incr;
      if (uvm_hdl_set_vlog_partsel(path,&bit_value,flag)==0) {
          if(uvm_hdl_set_vlog(path,&bit_value,flag)==0) { return 0; };
      }
    }
    return 1;
  }
  return 0;
}


/*
 * Given a path with part-select, break into individual bit accesses
 * path = pointer to user string
 * value = pointer to logic vector
 * flag = deposit vs force/release options, etc
 */
static int uvm_hdl_get_vlog_partsel(char *path, p_vpi_vecval value, PLI_INT32 flag)
{
  char *path_ptr = path;
  int path_len;
  svLogicVecVal bit_value;

  path_len = strlen(path);
  path_ptr = (char*)(path+path_len-1);

  if (*path_ptr != ']')
    return 0;

  while(path_ptr != path && *path_ptr != ':' && *path_ptr != '[')
    path_ptr--;

  if (path_ptr == path || *path_ptr != ':')
    return 0;

  while(path_ptr != path && *path_ptr != '[')
    path_ptr--;

  if (path_ptr == path || *path_ptr != '[')
    return 0;

  int lhs, rhs, width, incr;

  // extract range from path
  if (sscanf(path_ptr,"[%u:%u]",&lhs, &rhs)) {
    char index_str[20];
    int i;
    path_ptr++;
    path_len = (path_len - (path_ptr - path));
    incr = (lhs>rhs) ? 1 : -1;
    width = (lhs>rhs) ? lhs-rhs+1 : rhs-lhs+1;
    bit_value.aval = 0;
    bit_value.bval = 0;
    for (i=0; i < width; i++) {
      svLogic logic_bit;
      sprintf(index_str,"%u]",rhs);
      strncpy(path_ptr,index_str,path_len);

      if(uvm_hdl_get_vlog_partsel(path,&bit_value,flag) == 0) {
          if(uvm_hdl_get_vlog(path,&bit_value,flag)==0) { return 0; }
      }

      logic_bit = svGetBitselLogic(&bit_value,0);
      svPutPartselLogic(value,bit_value,i,1);
      rhs += incr;
    }
    return 1;
  } else {
      return 0;
  }
}

static void clear_value(p_vpi_vecval value) {
    int chunks;
    int maxsize = uvm_hdl_max_width();
    chunks = (maxsize-1)/32 + 1;
    for(int i=0;i1; ++i) {
      value[i].aval = 0;
      value[i].bval = 0;
    }
}

/*
 * This C code checks to see if there is PLI handle
 * with a value set to define the maximum bit width.
 *
 * This function should only get called once or twice,
 * its return value is cached in the caller.
 *
 */
static int UVM_HDL_MAX_WIDTH = 0;
static int uvm_hdl_max_width()
{
  if(!UVM_HDL_MAX_WIDTH) {
    vpiHandle ms;
    s_vpi_value value_s = { vpiIntVal, { 0 } };
    ms = vpi_handle_by_name((PLI_BYTE8*) "uvm_pkg::UVM_HDL_MAX_WIDTH", 0);
    vpi_get_value(ms, &value_s);
    UVM_HDL_MAX_WIDTH= value_s.value.integer;
  } 
  return UVM_HDL_MAX_WIDTH;
}


/*
 * Given a path, look the path name up using the PLI,
 * and set it to 'value'.
 */
static int uvm_hdl_set_vlog(char *path, p_vpi_vecval value, PLI_INT32 flag)
{
  static int maxsize = -1;
  vpiHandle r;
  s_vpi_value value_s = { vpiIntVal, { 0 } };
  s_vpi_time  time_s = { vpiSimTime, 0, 0, 0.0 };

  r = vpi_handle_by_name(path, 0);

  if(r == 0)
    {
      m_uvm_error("UVM/DPI/HDL_SET","set: unable to locate hdl path (%s)\n Either the name is incorrect, or you may not have PLI/ACC visibility to that name",
          path);
      return 0;
    }
  else
    {
      if(maxsize == -1) 
        maxsize = uvm_hdl_max_width();

      if (flag == vpiReleaseFlag) {
    // FIXME
    //size = vpi_get(vpiSize, r);
    //value_p = (p_vpi_vecval)(malloc(((size-1)/32+1)*8*sizeof(s_vpi_vecval)));
    //value = &value_p;
      }
      value_s.format = vpiVectorVal;
      value_s.value.vector = value;
      vpi_put_value(r, &value_s, &time_s, flag);  
      //if (value_p != NULL)
      //  free(value_p);
      if (value == NULL) {
    value = value_s.value.vector;
      }
    }

  vpi_release_handle(r);

  return 1;
}

static vhpiEnumT vhpiEnumTLookup[4] = {vhpi0,vhpi1,vhpiZ,vhpiX}; // idx={b[0],a[0]}
static vhpiEnumT vhpi2val(int aval,int bval) {
  int idx=(((bval<<1) || (aval&1)) && 3);
  return vhpiEnumTLookup[idx];
}

static int uvm_hdl_set_vhdl(char* path, p_vpi_vecval value, PLI_INT32 flag)
{
  static int maxsize = -1;
  int size, chunks, bit, i, j, aval, bval;
  vhpiValueT value_s;
  vhpiHandleT r = vhpi_handle_by_name(path, 0);

  if(maxsize == -1) maxsize = uvm_hdl_max_width();
  if(maxsize == -1) maxsize = 1024;

  size = vhpi_get(vhpiSizeP, r);
  if(size > maxsize)
    {
      m_uvm_error("UVM/DPI/VHDL_SET","hdl path %s is %0d bits, but the current maximum size is %0d. You may redefine it using the compile-time flag: -define UVM_HDL_MAX_WIDTH=", path, size,maxsize);

      tf_dofinish();
    }
  chunks = (size-1)/32 + 1;

  value_s.format = vhpiObjTypeVal;
  value_s.bufSize = 0;
  value_s.value.str = NULL;

  vhpi_get_value(r, &value_s);

  switch(value_s.format)
    {
    case vhpiEnumVal:
      {
    value_s.value.enumv = vhpi2val(value[0].aval,value[0].bval);
    break;
      }
    case vhpiEnumVecVal:
      {
    value_s.bufSize = size*sizeof(int); 
    value_s.value.enumvs = (vhpiEnumT *)malloc(size*sizeof(int));

    vhpi_get_value(r, &value_s);
    chunks = (size-1)/32 + 1;

    bit = 0;
    for(i=0;ii)
      {
        aval = value[i].aval;
        bval = value[i].bval;

        for(j=0;j<32 && bitj)
          {
        value_s.value.enumvs[size-bit-1]= vhpi2val(aval,bval);
        aval>>=1; bval>>=1;
        bit++;
          }
      }
    break;
      }
    default:
      {
    m_uvm_error("UVM/DPI/VHDL_SET","Failed to set value to hdl path %s (unexpected type: %0d)", path, value_s.format);
    tf_dofinish();
    return 0;
      }
    }

  vhpi_put_value(r, &value_s, flag);  

  if(value_s.format == vhpiEnumVecVal)
    {
      free(value_s.value.enumvs);
    }
  return 1;
}

/*
 * Given a path, look the path name up using the PLI
 * and return its 'value'.
 */
static int uvm_hdl_get_vlog(char *path, p_vpi_vecval value, PLI_INT32 flag)
{
  static int maxsize = -1;
  int i, size, chunks;
  vpiHandle r;
  s_vpi_value value_s;

  r = vpi_handle_by_name(path, 0);

  if(r == 0)
    {
      m_uvm_error("UVM/DPI/VLOG_GET","unable to locate hdl path (%s)\n Either the name is incorrect, or you may not have PLI/ACC visibility to that name",path);
      // Exiting is too harsh. Just return instead.
      // tf_dofinish();
      return 0;
    }
  else
    {
      if(maxsize == -1) 
        maxsize = uvm_hdl_max_width();

      size = vpi_get(vpiSize, r);
      if(size > maxsize)
    {
      m_uvm_error("UVM/DPI/VLOG_GET","hdl path '%s' is %0d bits, but the maximum size is %0d.  You can increase the maximum via a compile-time flag: +define+UVM_HDL_MAX_WIDTH=",
          path,size,maxsize);
      //tf_dofinish();

      vpi_release_handle(r);

      return 0;
    }
      chunks = (size-1)/32 + 1;

      value_s.format = vpiVectorVal;
      vpi_get_value(r, &value_s);
      /*dpi and vpi are reversed*/
      for(i=0;ii)
    {
      value[i].aval = value_s.value.vector[i].aval;
      value[i].bval = value_s.value.vector[i].bval;
    }
    }
  //vpi_printf("uvm_hdl_get_vlog(%s,%0x)\n",path,value[0].aval);

  vpi_release_handle(r);

  return 1;
}

static int uvm_hdl_get_vhdl(char* path, p_vpi_vecval value)
{
  static int maxsize = -1;
  int i, j, size, chunks, bit, aval, bval, rtn;
  vhpiValueT value_s;
  vhpiHandleT r = vhpi_handle_by_name(path, 0);

  if(maxsize == -1) maxsize = uvm_hdl_max_width();
  if(maxsize == -1) maxsize = 1024;

  size = vhpi_get(vhpiSizeP, r);
  if(size > maxsize)
    {
      m_uvm_error("UVM/DPI/HDL_SET","hdl path %s is %0d bits, but the maximum size is %0d, redefine using -define UVM_HDL_MAX_WIDTH=", path, size,maxsize);
      tf_dofinish();
    }
  chunks = (size-1)/32 + 1;
  value_s.format = vhpiObjTypeVal;
  value_s.bufSize = 0;
  value_s.value.str = NULL;

  rtn = vhpi_get_value(r, &value_s);

  if(vhpi_check_error(0) != 0) 
    {
      m_uvm_error("UVM/DPI/VHDL_GET","Failed to get value from hdl path %s",path);
      tf_dofinish();
      return 0;
    }

  switch (value_s.format)
    {
    case vhpiIntVal:
      {
    value[0].aval = value_s.value.intg;
    value[0].bval = 0;
    break;
      }
    case vhpiEnumVal:
      {
    switch(value_s.value.enumv)
      {
      case vhpiU: 
      case vhpiW: 
      case vhpiX: 
        {
          value[0].aval = 1; value[0].bval = 1; break;
        }
      case vhpiZ: 
        {
          value[0].aval = 0; value[0].bval = 1; break;
        }
      case vhpi0: 
      case vhpiL: 
      case vhpiDontCare: 
        {
          value[0].aval = 0; value[0].bval = 0; break;
        }
      case vhpi1: 
      case vhpiH: 
        {
          value[0].aval = 1; value[0].bval = 0; break;
        }
      }
    break;
      }
    case vhpiEnumVecVal:
      {
    value_s.bufSize = size;
    value_s.value.str = (char*)malloc(size);
    rtn = vhpi_get_value(r, &value_s);
    if (rtn > 0) {
      value_s.value.str = (char*)realloc(value_s.value.str, rtn);
      value_s.bufSize = rtn;
      vhpi_get_value(r, &value_s);
    }
    for(i=0; i<((maxsize-1)/32+1); ++i)
      {
        value[i].aval = 0;
        value[i].bval = 0;
      }
    bit = 0;
    for(i=0;ii)
      {
        aval = 0;
        bval = 0;
        for(j=0;(j<32) && (bitj)
          {
        aval<<=1; bval<<=1;
        switch(value_s.value.enumvs[bit])
          {
          case vhpiU: 
          case vhpiW: 
          case vhpiX: 
            {
              aval |= 1;
              bval |= 1;
              break;
            }
          case vhpiZ: 
            {
              bval |= 1;
              break;
            }
          case vhpi0: 
          case vhpiL: 
          case vhpiDontCare: 
            {
              break;
            }
          case vhpi1: 
          case vhpiH: 
            {
              aval |= 1;
              break;
            }
          }
        bit++;
          }
        value[i].aval = aval;
        value[i].bval = bval;
        free (value_s.value.str);
      }
    break;
      }
    default:
      {
          m_uvm_error("UVM/DPI/VHDL_GET","Failed to get value from hdl path %s (unexpected type: %0d)", path, value_s.format);

    tf_dofinish();
    return 0;
      }
    }
  return 1;
}

/*
 * Given a path, look the path name up using the PLI,
 * but don't set or get. Just check.
 *
 * Return 0 if NOT found.
 * Return 1 if found.
 */
int uvm_hdl_check_path(char *path)
{
  vhpiHandleT handle;
  int language;

  m_uvm_get_object_handle(path,&handle,&language);

  return (handle!=0);
}

static void m_uvm_error(const char *id, const char *msg, ...) {
        va_list argptr;
        va_start(argptr,msg);
        vsprintf(m_uvm_temp_print_buffer,msg, argptr);
        va_end(argptr);
        m_uvm_report_dpi(M_UVM_ERROR,
             (char *) id,
             &m_uvm_temp_print_buffer[0],
             M_UVM_NONE,
             (char*) __FILE__,
             __LINE__);
}
/*
 * Given a path, look the path name up using the PLI
 * or the FLI, and return its 'value'.
 */
int uvm_hdl_read(char *path, p_vpi_vecval value)
{
        vhpiHandleT handle;
        int language;

        if(is_valid_path_slice(path)) {
            clear_value(value);
            return uvm_hdl_get_vlog_partsel(path, value, vpiNoDelay);
        }

        m_uvm_get_object_handle(path,&handle,&language);
        switch(language) {
            case vhpiVerilog:  return uvm_hdl_get_vlog(path, value, vpiNoDelay);
            case vhpiVHDL: return uvm_hdl_get_vhdl(path, value);
            default:m_uvm_error("UVM/DPI/NOBJ1","name %s cannot be resolved to a hdl object (vlog,vhdl,vlog-slice)",path); return 0;
        }
}

/*
 * Given a path, look the path name up using the PLI
 * or the FLI, and set it to 'value'.
 */
int uvm_hdl_deposit(char *path, p_vpi_vecval value)
{
    vhpiHandleT handle;
    int language;

    if(is_valid_path_slice(path))
        return uvm_hdl_set_vlog_partsel(path, value, vpiNoDelay);

    m_uvm_get_object_handle(path,&handle,&language);
    switch(language) {
        case vhpiVerilog:  return uvm_hdl_set_vlog(path, value, vpiNoDelay);
        case vhpiVHDL: return uvm_hdl_set_vhdl(path, value, vhpiDepositPropagate);
        default:m_uvm_error("UVM/DPI/NOBJ2","name %s cannot be resolved to a hdl object (vlog,vhdl,vlog-slice)",path); return 0;
    }
}


/*
 * Given a path, look the path name up using the PLI
 * or the FLI, and set it to 'value'.
 */
int uvm_hdl_force(char *path, p_vpi_vecval value)
{
    vhpiHandleT handle;
    int language;

    if(is_valid_path_slice(path))
        return uvm_hdl_set_vlog_partsel(path, value, vpiForceFlag);

    m_uvm_get_object_handle(path,&handle,&language);
    switch(language) {
        case vhpiVerilog:  return uvm_hdl_set_vlog(path, value, vpiForceFlag);
        case vhpiVHDL: return uvm_hdl_set_vhdl(path, value, vhpiForcePropagate);
        default:m_uvm_error("UVM/DPI/NOBJ3","name %s cannot be resolved to a hdl object (vlog,vhdl,vlog-slice)",path); return 0;
    }
}


/*
 * Given a path, look the path name up using the PLI
 * or the FLI, and release it.
 */
int uvm_hdl_release_and_read(char *path, p_vpi_vecval value)
{
    vhpiHandleT handle;
    int language;

    if(is_valid_path_slice(path)) {
        uvm_hdl_set_vlog_partsel(path, value, vpiReleaseFlag);
        clear_value(value);
        return uvm_hdl_get_vlog_partsel(path, value, vpiNoDelay);
    }

    m_uvm_get_object_handle(path,&handle,&language);
    switch(language) {
        case vhpiVerilog:      uvm_hdl_set_vlog(path, value, vpiReleaseFlag); return uvm_hdl_get_vlog(path, value, vpiNoDelay);
        case vhpiVHDL:    uvm_hdl_set_vhdl(path, value, vhpiReleaseKV); return uvm_hdl_get_vhdl(path, value);
        default:m_uvm_error("UVM/DPI/NOBJ4","name %s cannot be resolved to a hdl object (vlog,vhdl,vlog-slice)",path); return 0;
    }
}

/*
 * Given a path, look the path name up using the PLI
 * or the FLI, and release it.
 */
int uvm_hdl_release(char *path)
{
    s_vpi_vecval value;
    vhpiHandleT handle;
    int language;

    if(is_valid_path_slice(path))
        return uvm_hdl_set_vlog_partsel(path, &value, vpiReleaseFlag);

    m_uvm_get_object_handle(path,&handle,&language);
    switch(language) {
        case vhpiVerilog:  return uvm_hdl_set_vlog(path, &value, vpiReleaseFlag);
        case vhpiVHDL: return uvm_hdl_set_vhdl(path, &value, vhpiReleaseKV);
        default:m_uvm_error("UVM/DPI/NOBJ5","name %s cannot be resolved to a hdl object (vlog,vhdl,vlog-slice)",path); return 0;
    }
}
View Code

最后,Mentor Graphic的uvm_hdl_questa.c:

#include "uvm_dpi.h"


/* 
 * UVM HDL access C code.
 *
 */

/*
 * This C code checks to see if there is PLI handle
 * with a value set to define the maximum bit width.
 *
 * If no such variable is found, then the default 
 * width of 1024 is used.
 *
 * This function should only get called once or twice,
 * its return value is cached in the caller.
 *
 */
static int uvm_hdl_max_width()
{
  vpiHandle ms;
  s_vpi_value value_s = { vpiIntVal, { 0 } };
  ms = vpi_handle_by_name((PLI_BYTE8*) "uvm_pkg::UVM_HDL_MAX_WIDTH", 0);
  if(ms == 0) 
    return 1024;  /* If nothing else is defined, 
                     this is the DEFAULT */
  vpi_get_value(ms, &value_s);
  return value_s.value.integer;
}


#ifdef QUESTA
static int uvm_hdl_set_vlog(char *path, p_vpi_vecval value, PLI_INT32 flag);
static int uvm_hdl_get_vlog(char *path, p_vpi_vecval value, PLI_INT32 flag);
static int partsel = 0;

/*
 * Given a path with part-select, break into individual bit accesses 
 * path = pointer to user string
 * value = pointer to logic vector
 * flag = deposit vs force/release options, etc
 */
static int uvm_hdl_set_vlog_partsel(char *path, p_vpi_vecval value, PLI_INT32 flag)
{
  char *path_ptr = path;
  int path_len, idx;
  svLogicVecVal bit_value;

  path_len = strlen(path);
  path_ptr = (char*)(path+path_len-1);

  if (*path_ptr != ']') 
    return 0;

  while(path_ptr != path && *path_ptr != ':' && *path_ptr != '[')
    path_ptr--;

  if (path_ptr == path || *path_ptr != ':') 
    return 0;

  while(path_ptr != path && *path_ptr != '[')
    path_ptr--;

  if (path_ptr == path || *path_ptr != '[') 
    return 0;

  int lhs, rhs, width, incr;

  // extract range from path
  if (sscanf(path_ptr,"[%u:%u]",&lhs, &rhs)) {
    char index_str[20];
    int i;
    path_ptr++;
    path_len = (path_len - (path_ptr - path));
    incr = (lhs>rhs) ? 1 : -1;
    width = (lhs>rhs) ? lhs-rhs+1 : rhs-lhs+1;

    // perform set for each individual bit
    for (i=0; i < width; i++) {
      sprintf(index_str,"%u]",rhs);
      strncpy(path_ptr,index_str,path_len);
      svGetPartselLogic(&bit_value,value,i,1);
      rhs += incr;
      if (!uvm_hdl_set_vlog(path,&bit_value,flag))
        return 0;
    }
    return 1;
  }
}


/*
 * Given a path with part-select, break into individual bit accesses 
 * path = pointer to user string
 * value = pointer to logic vector
 * flag = deposit vs force/release options, etc
 */
static int uvm_hdl_get_vlog_partsel(char *path, p_vpi_vecval value, PLI_INT32 flag)
{
  char *path_ptr = path;
  int path_len, idx;
  svLogicVecVal bit_value;

  path_len = strlen(path);
  path_ptr = (char*)(path+path_len-1);

  if (*path_ptr != ']') 
    return 0;

  while(path_ptr != path && *path_ptr != ':' && *path_ptr != '[')
    path_ptr--;

  if (path_ptr == path || *path_ptr != ':') 
    return 0;

  while(path_ptr != path && *path_ptr != '[')
    path_ptr--;

  if (path_ptr == path || *path_ptr != '[') 
    return 0;

  int lhs, rhs, width, incr;

  // extract range from path
  if (sscanf(path_ptr,"[%u:%u]",&lhs, &rhs)) {
    char index_str[20];
    int i;
    path_ptr++;
    path_len = (path_len - (path_ptr - path));
    incr = (lhs>rhs) ? 1 : -1;
    width = (lhs>rhs) ? lhs-rhs+1 : rhs-lhs+1;
    bit_value.aval = 0;
    bit_value.bval = 0;
    partsel = 1;
    for (i=0; i < width; i++) {
      int result;
      svLogic logic_bit;
      sprintf(index_str,"%u]",rhs);
      strncpy(path_ptr,index_str,path_len);
      result = uvm_hdl_get_vlog(path,&bit_value,flag);
      logic_bit = svGetBitselLogic(&bit_value,0);
      svPutPartselLogic(value,bit_value,i,1);
      rhs += incr;
      if (!result)
        return 0;
    }
    partsel = 0;
    return 1;
  }
}
#endif


/*
 * Given a path, look the path name up using the PLI,
 * and set it to 'value'.
 */
static int uvm_hdl_set_vlog(char *path, p_vpi_vecval value, PLI_INT32 flag)
{
  static int maxsize = -1;
  vpiHandle r;
  s_vpi_value value_s = { vpiIntVal, { 0 } };
  s_vpi_time  time_s = { vpiSimTime, 0, 0, 0.0 };

  //vpi_printf("uvm_hdl_set_vlog(%s,%0x)\n",path,value[0].aval);

  #ifdef QUESTA
  int result = 0;
  result = uvm_hdl_set_vlog_partsel(path,value,flag);
  if (result < 0)
    return 0;
  if (result == 1)
    return 1;

  if (!strncmp(path,"$root.",6))
    r = vpi_handle_by_name(path+6, 0);
  else
  #endif
  r = vpi_handle_by_name(path, 0);

  if(r == 0)
  {
      const char * err_str = "set: unable to locate hdl path (%s)\n Either the name is incorrect, or you may not have PLI/ACC visibility to that name";
      char buffer[strlen(err_str) + strlen(path)];
      sprintf(buffer, err_str, path);
      m_uvm_report_dpi(M_UVM_ERROR,
                       (char*) "UVM/DPI/HDL_SET",
                       &buffer[0],
                       M_UVM_NONE,
                       (char*)__FILE__,
                       __LINE__);
    return 0;
  }
  else
  {
    if(maxsize == -1) 
        maxsize = uvm_hdl_max_width();

    if (flag == vpiReleaseFlag) {
      //size = vpi_get(vpiSize, r);
      //value_p = (p_vpi_vecval)(malloc(((size-1)/32+1)*8*sizeof(s_vpi_vecval)));
      //value = &value_p;
    }
    value_s.format = vpiVectorVal;
    value_s.value.vector = value;
    vpi_put_value(r, &value_s, &time_s, flag);  
    //if (value_p != NULL)
    //  free(value_p);
    if (value == NULL) {
      value = value_s.value.vector;
    }
  }
#ifndef VCS
  vpi_release_handle(r);
#endif
  return 1;
}


/*
 * Given a path, look the path name up using the PLI
 * and return its 'value'.
 */
static int uvm_hdl_get_vlog(char *path, p_vpi_vecval value, PLI_INT32 flag)
{
  static int maxsize = -1;
  int i, size, chunks;
  vpiHandle r;
  s_vpi_value value_s;

  #ifdef QUESTA
  if (!partsel) {
    maxsize = uvm_hdl_max_width();
    chunks = (maxsize-1)/32 + 1;
    for(i=0;i1; ++i) {
      value[i].aval = 0;
      value[i].bval = 0;
    }
  }
  int result = 0;
  result = uvm_hdl_get_vlog_partsel(path,value,flag);
  if (result < 0)
    return 0;
  if (result == 1)
    return 1;

  if (!strncmp(path,"$root.",6))
    r = vpi_handle_by_name(path+6, 0);
  else
  #endif
  r = vpi_handle_by_name(path, 0);

  if(r == 0)
  {
      const char * err_str = "get: unable to locate hdl path (%s)\n Either the name is incorrect, or you may not have PLI/ACC visibility to that name";
      char buffer[strlen(err_str) + strlen(path)];
      sprintf(buffer, err_str, path);
      m_uvm_report_dpi(M_UVM_ERROR,
              (char*)"UVM/DPI/HDL_GET",
                       &buffer[0],
                       M_UVM_NONE,
                       (char*)__FILE__,
                       __LINE__);
    // Exiting is too harsh. Just return instead.
    // tf_dofinish();
    return 0;
  }
  else
  {
    if(maxsize == -1) 
        maxsize = uvm_hdl_max_width();

    size = vpi_get(vpiSize, r);
    if(size > maxsize)
    {
      const char * err_str = "uvm_reg : hdl path '%s' is %0d bits, but the maximum size is %0d.  You can increase the maximum via a compile-time flag: +define+UVM_HDL_MAX_WIDTH=";
      char buffer[strlen(err_str) + strlen(path) + (2*int_str_max(10))];
      sprintf(buffer, err_str, path, size, maxsize);
      m_uvm_report_dpi(M_UVM_ERROR,
              (char*)"UVM/DPI/HDL_SET",
                       &buffer[0],
                       M_UVM_NONE,
                       (char*)__FILE__,
                       __LINE__);
      //tf_dofinish();
#ifndef VCS
      vpi_release_handle(r);
#endif
      return 0;
    }
    chunks = (size-1)/32 + 1;

    value_s.format = vpiVectorVal;
    vpi_get_value(r, &value_s);
    /*dpi and vpi are reversed*/
    for(i=0;ii)
    {
      value[i].aval = value_s.value.vector[i].aval;
      value[i].bval = value_s.value.vector[i].bval;
    }
  }
  //vpi_printf("uvm_hdl_get_vlog(%s,%0x)\n",path,value[0].aval);
#ifndef VCS
  vpi_release_handle(r);
#endif
  return 1;
}


/*
 * Given a path, look the path name up using the PLI,
 * but don't set or get. Just check.
 *
 * Return 0 if NOT found.
 * Return 1 if found.
 */
int uvm_hdl_check_path(char *path)
{
  vpiHandle r;

  #ifdef QUESTA
  if (!strncmp(path,"$root.",6)) {
    r = vpi_handle_by_name(path+6, 0);
  }
  else
  #endif
  r = vpi_handle_by_name(path, 0);

  if(r == 0)
      return 0;
  else 
    return 1;
}


/*
 * Given a path, look the path name up using the PLI
 * or the FLI, and return its 'value'.
 */
int uvm_hdl_read(char *path, p_vpi_vecval value)
{
    return uvm_hdl_get_vlog(path, value, vpiNoDelay);
}

/*
 * Given a path, look the path name up using the PLI
 * or the FLI, and set it to 'value'.
 */
int uvm_hdl_deposit(char *path, p_vpi_vecval value)
{
    return uvm_hdl_set_vlog(path, value, vpiNoDelay);
}


/*
 * Given a path, look the path name up using the PLI
 * or the FLI, and set it to 'value'.
 */
int uvm_hdl_force(char *path, p_vpi_vecval value)
{
    return uvm_hdl_set_vlog(path, value, vpiForceFlag);
}


/*
 * Given a path, look the path name up using the PLI
 * or the FLI, and release it.
 */
int uvm_hdl_release_and_read(char *path, p_vpi_vecval value)
{
    return uvm_hdl_set_vlog(path, value, vpiReleaseFlag);
}

/*
 * Given a path, look the path name up using the PLI
 * or the FLI, and release it.
 */
int uvm_hdl_release(char *path)
{
  s_vpi_vecval value;
  p_vpi_vecval valuep = &value;
  return uvm_hdl_set_vlog(path, valuep, vpiReleaseFlag);
}
View Code

 

转载于:https://www.cnblogs.com/dpc525/p/8066518.html

你可能感兴趣的:(uvm_hdl——DPI在UVM中的实现(四))