| //---------------------------------------------------------------------- |
| // Copyright 2007-2013 Cadence Design Systems, Inc. |
| // Copyright 2009-2010 Mentor Graphics Corporation |
| // Copyright 2010-2011 Synopsys, Inc. |
| // All Rights Reserved Worldwide |
| // |
| // Licensed under the Apache License, Version 2.0 (the |
| // "License"); you may not use this file except in |
| // compliance with the License. You may obtain a copy of |
| // the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in |
| // writing, software distributed under the License is |
| // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR |
| // CONDITIONS OF ANY KIND, either express or implied. See |
| // the License for the specific language governing |
| // permissions and limitations under the License. |
| //---------------------------------------------------------------------- |
| |
| // 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 <stdio.h> |
| |
| 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;i<chunks-1; ++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=<value>", 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;i<chunks && bit<size; ++i) |
| { |
| aval = value[i].aval; |
| bval = value[i].bval; |
| |
| for(j=0;j<32 && bit<size; ++j) |
| { |
| 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=<value>", |
| 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;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); |
| |
| 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=<value>", 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;i<chunks && bit<size; ++i) |
| { |
| aval = 0; |
| bval = 0; |
| for(j=0;(j<32) && (bit<size); ++j) |
| { |
| 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; |
| } |
| } |