blob: a006e320ddc208243f7363c5d877affc9996a403 [file] [log] [blame]
//----------------------------------------------------------------------
// 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;
}
}