我们可以在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
`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-:] 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 = );
if (force_time == ) 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 ;
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 ;
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 ;
endfunction task uvm_hdl_force_time(string path, uvm_hdl_data_t value, time force_time=);
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 ;
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 ;
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, { } };
ms = vpi_handle_by_name((PLI_BYTE8*) "uvm_pkg::UVM_HDL_MAX_WIDTH", );
if(ms == )
return ; /* 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 = -;
vpiHandle r;
s_vpi_value value_s = { vpiIntVal, { } };
s_vpi_time time_s = { vpiSimTime, , , 0.0 }; //vpi_printf("uvm_hdl_set_vlog(%s,%0x)\n",path,value[0].aval); r = vpi_handle_by_name(path, ); if(r == )
{
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[],
M_UVM_NONE,
(char*)__FILE__,
__LINE__);
return ;
}
else
{
if(maxsize == -)
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 ;
} /*
* 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 = -;
int i, size, chunks;
vpiHandle r;
s_vpi_value value_s; r = vpi_handle_by_name(path, ); if(r == )
{
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[],
M_UVM_NONE,
(char*)__FILE__,
__LINE__);
// Exiting is too harsh. Just return instead.
// tf_dofinish();
return ;
}
else
{
if(maxsize == -)
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) + (*int_str_max())];
sprintf(buffer, err_str, path, size, maxsize);
m_uvm_report_dpi(M_UVM_ERROR,
(char*)"UVM/DPI/HDL_SET",
&buffer[],
M_UVM_NONE,
(char*)__FILE__,
__LINE__);
return ;
}
chunks = (size-)/ + ; value_s.format = vpiVectorVal;
vpi_get_value(r, &value_s);
/*dpi and vpi are reversed*/
for(i=;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 ;
} /*
* 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, ); if(r == )
return ;
else
return ;
} /*
* convert binary to integer
*/
long int uvm_hdl_btoi(char *binVal) {
long int remainder, dec=, j = ;
unsigned long long int bin;
int i;
char tmp[];
tmp[] = '\0'; for(i= strlen(binVal) - ; i >= ; i--) {
tmp[] = binVal[i];
bin = atoi(tmp);
dec = dec+(bin*(pow(,j)));
j++;
}
return(dec);
} /*
*decimal to hex conversion
*/
char *uvm_hdl_dtob(long int decimalNumber) {
int remainder, quotient;
int i=,j, length;
int binN[];
static char binaryNumber[];
char *str = (char*) malloc(sizeof(char)); quotient = decimalNumber; do {
binN[i++] = quotient%;
quotient = quotient/;
} while (quotient!=);
length = i; for (i=length-, j = ; i>=; i--) {
binaryNumber[j++] = binN[i]?'':'';
}
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 = ;
vhpiValueT value1;
p_vpi_vecval vecval;
mhpi_initialize('/');
mhpiHandleT mhpiH = mhpi_handle_by_name(path, );
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)+); if (vhpi_get_value(vhpiH, &value1) == ) {
binVal = value1.value.str; value_int = uvm_hdl_btoi(binVal);
value->aval = (PLI_UINT32) value_int;
value->bval = ;
mhpi_release_parent_handle(mhpiH);
free(value1.value.str);
return(); } else {
mhpi_release_parent_handle(mhpiH);
free(value1.value.str);
return ();
} }
#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, );
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 = ;
mhpiRealT cancelDelay = -;
mhpiReturnT ret;
mhpiHandleT h = mhpi_handle_by_name(path, );
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();
}
else
return();
}
#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, ); 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 ();
#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, ); 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 ();
#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, );
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();
}
else
return(); }
else
return ();
#endif
}

再看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 <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[]; /*
* 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, ); 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 ;
#endif path_len = strlen(path);
path_ptr = (char*)(path+path_len-); if (*path_ptr != ']')
return ; while(path_ptr != path && *path_ptr != ':' && *path_ptr != '[')
path_ptr--; if (path_ptr == path || *path_ptr != ':')
return ; while(path_ptr != path && *path_ptr != '[')
path_ptr--; if (path_ptr == path || *path_ptr != '[')
return ; return ;
} 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 ;
path_len = strlen(path);
path_ptr = (char*)(path+path_len-); if (*path_ptr != ']')
return ; while(path_ptr != path && *path_ptr != ':' && *path_ptr != '[')
path_ptr--; if (path_ptr == path || *path_ptr != ':')
return ; while(path_ptr != path && *path_ptr != '[')
path_ptr--; if (path_ptr == path || *path_ptr != '[')
return ; int lhs, rhs, width, incr; // extract range from path
if (sscanf(path_ptr,"[%u:%u]",&lhs, &rhs)) {
char index_str[];
int i;
path_ptr++;
path_len = (path_len - (path_ptr - path));
incr = (lhs>rhs) ? : -;
width = (lhs>rhs) ? lhs-rhs+ : rhs-lhs+; // perform set for each individual bit
for (i=; i < width; i++) {
sprintf(index_str,"%u]",rhs);
strncpy(path_ptr,index_str,path_len);
svGetPartselLogic(&bit_value,value,i,);
rhs += incr;
if (uvm_hdl_set_vlog_partsel(path,&bit_value,flag)==) {
if(uvm_hdl_set_vlog(path,&bit_value,flag)==) { return ; };
}
}
return ;
}
return ;
} /*
* 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-); if (*path_ptr != ']')
return ; while(path_ptr != path && *path_ptr != ':' && *path_ptr != '[')
path_ptr--; if (path_ptr == path || *path_ptr != ':')
return ; while(path_ptr != path && *path_ptr != '[')
path_ptr--; if (path_ptr == path || *path_ptr != '[')
return ; int lhs, rhs, width, incr; // extract range from path
if (sscanf(path_ptr,"[%u:%u]",&lhs, &rhs)) {
char index_str[];
int i;
path_ptr++;
path_len = (path_len - (path_ptr - path));
incr = (lhs>rhs) ? : -;
width = (lhs>rhs) ? lhs-rhs+ : rhs-lhs+;
bit_value.aval = ;
bit_value.bval = ;
for (i=; 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) == ) {
if(uvm_hdl_get_vlog(path,&bit_value,flag)==) { return ; }
} logic_bit = svGetBitselLogic(&bit_value,);
svPutPartselLogic(value,bit_value,i,);
rhs += incr;
}
return ;
} else {
return ;
}
} static void clear_value(p_vpi_vecval value) {
int chunks;
int maxsize = uvm_hdl_max_width();
chunks = (maxsize-)/ + ;
for(int i=;i<chunks-; ++i) {
value[i].aval = ;
value[i].bval = ;
}
} /*
* 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 = ;
static int uvm_hdl_max_width()
{
if(!UVM_HDL_MAX_WIDTH) {
vpiHandle ms;
s_vpi_value value_s = { vpiIntVal, { } };
ms = vpi_handle_by_name((PLI_BYTE8*) "uvm_pkg::UVM_HDL_MAX_WIDTH", );
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 = -;
vpiHandle r;
s_vpi_value value_s = { vpiIntVal, { } };
s_vpi_time time_s = { vpiSimTime, , , 0.0 }; r = vpi_handle_by_name(path, ); if(r == )
{
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 ;
}
else
{
if(maxsize == -)
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 ;
} static vhpiEnumT vhpiEnumTLookup[] = {vhpi0,vhpi1,vhpiZ,vhpiX}; // idx={b[0],a[0]}
static vhpiEnumT vhpi2val(int aval,int bval) {
int idx=(((bval<<) || (aval&)) && );
return vhpiEnumTLookup[idx];
} static int uvm_hdl_set_vhdl(char* path, p_vpi_vecval value, PLI_INT32 flag)
{
static int maxsize = -;
int size, chunks, bit, i, j, aval, bval;
vhpiValueT value_s;
vhpiHandleT r = vhpi_handle_by_name(path, ); if(maxsize == -) maxsize = uvm_hdl_max_width();
if(maxsize == -) maxsize = ; 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-)/ + ; value_s.format = vhpiObjTypeVal;
value_s.bufSize = ;
value_s.value.str = NULL; vhpi_get_value(r, &value_s); switch(value_s.format)
{
case vhpiEnumVal:
{
value_s.value.enumv = vhpi2val(value[].aval,value[].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-)/ + ; bit = ;
for(i=;i<chunks && bit<size; ++i)
{
aval = value[i].aval;
bval = value[i].bval; for(j=;j< && bit<size; ++j)
{
value_s.value.enumvs[size-bit-]= vhpi2val(aval,bval);
aval>>=; bval>>=;
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 ;
}
} vhpi_put_value(r, &value_s, flag); if(value_s.format == vhpiEnumVecVal)
{
free(value_s.value.enumvs);
}
return ;
} /*
* 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 = -;
int i, size, chunks;
vpiHandle r;
s_vpi_value value_s; r = vpi_handle_by_name(path, ); if(r == )
{
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 ;
}
else
{
if(maxsize == -)
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 ;
}
chunks = (size-)/ + ; value_s.format = vpiVectorVal;
vpi_get_value(r, &value_s);
/*dpi and vpi are reversed*/
for(i=;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 ;
} static int uvm_hdl_get_vhdl(char* path, p_vpi_vecval value)
{
static int maxsize = -;
int i, j, size, chunks, bit, aval, bval, rtn;
vhpiValueT value_s;
vhpiHandleT r = vhpi_handle_by_name(path, ); if(maxsize == -) maxsize = uvm_hdl_max_width();
if(maxsize == -) maxsize = ; 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-)/ + ;
value_s.format = vhpiObjTypeVal;
value_s.bufSize = ;
value_s.value.str = NULL; rtn = vhpi_get_value(r, &value_s); if(vhpi_check_error() != )
{
m_uvm_error("UVM/DPI/VHDL_GET","Failed to get value from hdl path %s",path);
tf_dofinish();
return ;
} switch (value_s.format)
{
case vhpiIntVal:
{
value[].aval = value_s.value.intg;
value[].bval = ;
break;
}
case vhpiEnumVal:
{
switch(value_s.value.enumv)
{
case vhpiU:
case vhpiW:
case vhpiX:
{
value[].aval = ; value[].bval = ; break;
}
case vhpiZ:
{
value[].aval = ; value[].bval = ; break;
}
case vhpi0:
case vhpiL:
case vhpiDontCare:
{
value[].aval = ; value[].bval = ; break;
}
case vhpi1:
case vhpiH:
{
value[].aval = ; value[].bval = ; break;
}
}
break;
}
case vhpiEnumVecVal:
{
value_s.bufSize = size;
value_s.value.str = (char*)malloc(size);
rtn = vhpi_get_value(r, &value_s);
if (rtn > ) {
value_s.value.str = (char*)realloc(value_s.value.str, rtn);
value_s.bufSize = rtn;
vhpi_get_value(r, &value_s);
}
for(i=; i<((maxsize-)/+); ++i)
{
value[i].aval = ;
value[i].bval = ;
}
bit = ;
for(i=;i<chunks && bit<size; ++i)
{
aval = ;
bval = ;
for(j=;(j<) && (bit<size); ++j)
{
aval<<=; bval<<=;
switch(value_s.value.enumvs[bit])
{
case vhpiU:
case vhpiW:
case vhpiX:
{
aval |= ;
bval |= ;
break;
}
case vhpiZ:
{
bval |= ;
break;
}
case vhpi0:
case vhpiL:
case vhpiDontCare:
{
break;
}
case vhpi1:
case vhpiH:
{
aval |= ;
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 ;
}
}
return ;
} /*
* 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!=);
} 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[],
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 ;
}
} /*
* 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 ;
}
} /*
* 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 ;
}
} /*
* 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 ;
}
} /*
* 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 ;
}
}

最后,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, { } };
ms = vpi_handle_by_name((PLI_BYTE8*) "uvm_pkg::UVM_HDL_MAX_WIDTH", );
if(ms == )
return ; /* 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 = ; /*
* 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-); if (*path_ptr != ']')
return ; while(path_ptr != path && *path_ptr != ':' && *path_ptr != '[')
path_ptr--; if (path_ptr == path || *path_ptr != ':')
return ; while(path_ptr != path && *path_ptr != '[')
path_ptr--; if (path_ptr == path || *path_ptr != '[')
return ; int lhs, rhs, width, incr; // extract range from path
if (sscanf(path_ptr,"[%u:%u]",&lhs, &rhs)) {
char index_str[];
int i;
path_ptr++;
path_len = (path_len - (path_ptr - path));
incr = (lhs>rhs) ? : -;
width = (lhs>rhs) ? lhs-rhs+ : rhs-lhs+; // perform set for each individual bit
for (i=; i < width; i++) {
sprintf(index_str,"%u]",rhs);
strncpy(path_ptr,index_str,path_len);
svGetPartselLogic(&bit_value,value,i,);
rhs += incr;
if (!uvm_hdl_set_vlog(path,&bit_value,flag))
return ;
}
return ;
}
} /*
* 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-); if (*path_ptr != ']')
return ; while(path_ptr != path && *path_ptr != ':' && *path_ptr != '[')
path_ptr--; if (path_ptr == path || *path_ptr != ':')
return ; while(path_ptr != path && *path_ptr != '[')
path_ptr--; if (path_ptr == path || *path_ptr != '[')
return ; int lhs, rhs, width, incr; // extract range from path
if (sscanf(path_ptr,"[%u:%u]",&lhs, &rhs)) {
char index_str[];
int i;
path_ptr++;
path_len = (path_len - (path_ptr - path));
incr = (lhs>rhs) ? : -;
width = (lhs>rhs) ? lhs-rhs+ : rhs-lhs+;
bit_value.aval = ;
bit_value.bval = ;
partsel = ;
for (i=; 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,);
svPutPartselLogic(value,bit_value,i,);
rhs += incr;
if (!result)
return ;
}
partsel = ;
return ;
}
}
#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 = -;
vpiHandle r;
s_vpi_value value_s = { vpiIntVal, { } };
s_vpi_time time_s = { vpiSimTime, , , 0.0 }; //vpi_printf("uvm_hdl_set_vlog(%s,%0x)\n",path,value[0].aval); #ifdef QUESTA
int result = ;
result = uvm_hdl_set_vlog_partsel(path,value,flag);
if (result < )
return ;
if (result == )
return ; if (!strncmp(path,"$root.",))
r = vpi_handle_by_name(path+, );
else
#endif
r = vpi_handle_by_name(path, ); if(r == )
{
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[],
M_UVM_NONE,
(char*)__FILE__,
__LINE__);
return ;
}
else
{
if(maxsize == -)
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 ;
} /*
* 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 = -;
int i, size, chunks;
vpiHandle r;
s_vpi_value value_s; #ifdef QUESTA
if (!partsel) {
maxsize = uvm_hdl_max_width();
chunks = (maxsize-)/ + ;
for(i=;i<chunks-; ++i) {
value[i].aval = ;
value[i].bval = ;
}
}
int result = ;
result = uvm_hdl_get_vlog_partsel(path,value,flag);
if (result < )
return ;
if (result == )
return ; if (!strncmp(path,"$root.",))
r = vpi_handle_by_name(path+, );
else
#endif
r = vpi_handle_by_name(path, ); if(r == )
{
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[],
M_UVM_NONE,
(char*)__FILE__,
__LINE__);
// Exiting is too harsh. Just return instead.
// tf_dofinish();
return ;
}
else
{
if(maxsize == -)
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) + (*int_str_max())];
sprintf(buffer, err_str, path, size, maxsize);
m_uvm_report_dpi(M_UVM_ERROR,
(char*)"UVM/DPI/HDL_SET",
&buffer[],
M_UVM_NONE,
(char*)__FILE__,
__LINE__);
//tf_dofinish();
#ifndef VCS
vpi_release_handle(r);
#endif
return ;
}
chunks = (size-)/ + ; value_s.format = vpiVectorVal;
vpi_get_value(r, &value_s);
/*dpi and vpi are reversed*/
for(i=;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);
#ifndef VCS
vpi_release_handle(r);
#endif
return ;
} /*
* 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.",)) {
r = vpi_handle_by_name(path+, );
}
else
#endif
r = vpi_handle_by_name(path, ); if(r == )
return ;
else
return ;
} /*
* 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);
}

uvm_hdl——DPI在UVM中的实现(四)的更多相关文章

  1. uvm_dpi——DPI在UVM中的实现(一)

    文件: src/dpi/uvm_dpi.svh 类:  无   SystemVerilog DPI,全称SystemVerilog直接编程接口 (英语:SystemVerilog Direct Pro ...

  2. uvm_regex——DPI在UVM中的实现(三)

    UVM的正则表达是在uvm_regex.cc 和uvm_regex.svh 中实现的,uvm_regex.svh实现UVM的正则表达式的源代码如下: `ifndef UVM_REGEX_NO_DPI ...

  3. uvm_svcmd_dpi——DPI在UVM中的实现(二)

    UVM中有需要从cmmand line 输入参数的需求,所有uvm_svcmd_dpi.svh和uvm_svcmd_dpi.cc 文件就是实现功能. uvm_svcmd_dpi.svh的源代码如下,我 ...

  4. UVM中的sequence使用(一)

    UVM中Driver,transaction,sequence,sequencer之间的关系. UVM将原来在Driver中的数据定义部分,单独拿出来成为Transaction,主要完成数据的rand ...

  5. C#中的线程四(System.Threading.Thread)

    C#中的线程四(System.Threading.Thread) 1.最简单的多线程调用 System.Threading.Thread类构造方法接受一个ThreadStart委托,改委托不带参数,无 ...

  6. UVM中的class

    UVM中的类包括:基类(base)------------uvm_void/uvm_object/uvm_transaction/uvm_root/uvm_phase/uvm_port_base 报告 ...

  7. ORACLE中CONSTRAINT的四对属性

    ORACLE中CONSTRAINT的四对属性 summary:在data migrate时,某些表的约束总是困扰着我们,让我们的migratet举步维艰,怎样利用约束本身的属性来处理这些问题呢?本文具 ...

  8. iOS中常用的四种数据持久化方法简介

    iOS中常用的四种数据持久化方法简介 iOS中的数据持久化方式,基本上有以下四种:属性列表.对象归档.SQLite3和Core Data 1.属性列表涉及到的主要类:NSUserDefaults,一般 ...

  9. js中this的四种使用方法

    0x00:js中this的四种调用模式 1,方法调用模式 2,函数调用模式 3,构造器调用模式 4,apply.call.bind调用模式 0x01:第一种:方法调用模式 (也就是用.调用的)this ...

随机推荐

  1. 1.3 DVWA亲测sql注入漏洞

    LOW等级   我们先输入1 我们加上一个单引号,页面报错 我们看一下源代码: <?php if( isset( $_REQUEST[ 'Submit' ] ) ) { // Get input ...

  2. lable对picbox透明

    为了登录美观一些,就在窗体上加了个picbox.并且充满了整个窗体. 往上面放了几个lable,把lable属性设置Transparent.本想着lable不会有底色,实际上有个底,很难看. 解决办法 ...

  3. jquery获取ASP.NET服务器端控件dropdownlist和radiobuttonlist生成客户端HTML标签后的value和text值

    —.获取dropdownlist的text(ddlList为服务器端dropdownlist的ID,生成name属性等于ddlList的select标签) $("#ddlList optio ...

  4. Unity 分场景打包

    分场景打包步骤:导入unity中AB包后 1: 指定场景  2: 指定abname  3: 指定objinabname  4: 协同  5: 委托 void string unity 先引入命名空间  ...

  5. [CentOS7] Segmentation fault (core dumped),但是在主机上找不到core文件

    1.问题描述 程序执行报:Segmentation fault (core dumped),但是在主机上找不到core文件 2.如何让系统生成core file /home>ulimit -ac ...

  6. jQuery之ajax() 参数

  7. spring boot jpa 使用<S extends T> List<S> findAll(Example<S> example)查询数据

    直接上代码 //查询条件对象 TinventivePrinciple time = new TinventivePrinciple(); //设置需要查询的条件(赋值) time.setIsTime( ...

  8. bzoj2597: [Wc2007]剪刀石头布(费用流)

    传送门 不得不说这思路真是太妙了 考虑能构成三元组很难,那我们考虑不能构成三元组的情况是怎么样 就是说一个三元组$(a,b,c)$,其中$a$赢两场,$b$赢一场,$c$没有赢 所以如果第$i$个人赢 ...

  9. iOS回顾笔记( 01 )-- XIB和纯代码创建应用的对比

    header{font-size:1em;padding-top:1.5em;padding-bottom:1.5em} .markdown-body{overflow:hidden} .markdo ...

  10. C#网络编程学习(6)---序列化和反序列化

    1.什么是序列化和反序列化 当客户端和服务器进行远程连接时,互相可以发送各种类型的数据.但都要先把这些对象转换为字节序列,才能在网络上进行传输. 序列化:就是发送方 把对象转换为字节序列的过程. 反序 ...