我们可以在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) ",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) 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) 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) ",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] = '