我们可以在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, <uvm_hdl_deposit> 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 <uvm_hdl_force>.
  // 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 <uvm_hdl_force>.
  // 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 <math.h>

#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=<value>";
      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;i<chunks; ++i)
    {
      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

相关文章: