Framework of the INTERCONNECT implementation

This commit is contained in:
mole99 2023-07-19 15:02:20 +02:00
parent 78f8976c85
commit 7beadb92f8
13 changed files with 756 additions and 67 deletions

View File

@ -1,4 +1,3 @@
SDF WARNING: ivltests/br_gh889.sdf:18: loaded from vlog95.v:17: Wildcard cell instance specification (*) currently not supported.
0 A=x, B=x, Q=x
10 A=1, B=1, Q=x
11 A=1, B=1, Q=0

View File

@ -1,4 +1,3 @@
SDF WARNING: ivltests/br_gh889.sdf:18: loaded from ./ivltests/br_gh889.v:21: Wildcard cell instance specification (*) currently not supported.
0 A=x, B=x, Q=x
10 A=1, B=1, Q=x
11 A=1, B=1, Q=0

View File

@ -1,3 +1,4 @@
SDF INFO: Loading ivltests/sdf_header.sdf from ivltests/sdf_header.v:6
SDF INFO: ivltests/sdf_header.sdf:2: Version: 3.0
SDF INFO: ivltests/sdf_header.sdf:3: Design: test
SDF INFO: ivltests/sdf_header.sdf:4: Date: Wed Mar 8 12:34:56 2023

View File

@ -160,15 +160,15 @@ program_version
hierarchy_divider
: '(' K_DIVIDER '.' ')'
{ sdf_use_hchar = '.';
if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Divider: \"%c\"\n", sdf_parse_path, @1.first_line, sdf_use_hchar);
if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Divider: \"%c\"\n", sdf_parse_path, @1.first_line, sdf_use_hchar);
}
| '(' K_DIVIDER '/' ')'
{ sdf_use_hchar = '/';
if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Divider: \"%c\"\n", sdf_parse_path, @1.first_line, sdf_use_hchar);
if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Divider: \"%c\"\n", sdf_parse_path, @1.first_line, sdf_use_hchar);
}
| '(' K_DIVIDER HCHAR ')'
{ /* sdf_use_hchar no-change */
if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Divider: \"%c\"\n", sdf_parse_path, @1.first_line, sdf_use_hchar);
if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Divider: \"%c\"\n", sdf_parse_path, @1.first_line, sdf_use_hchar);
}
;
@ -198,9 +198,8 @@ process
temperature
: '(' K_TEMPERATURE rtriple ')'
{ /* The value must be defined. */
if (! $3.defined) {
vpi_printf("SDF ERROR: %s:%d: Chosen value not defined.\n", sdf_parse_path, @1.first_line);
}
if (! $3.defined) vpi_printf("SDF ERROR: %s:%d: Chosen value not defined.\n",
sdf_parse_path, @1.first_line);
else if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Temperature: %f\n",
sdf_parse_path, @2.first_line, $3.value);
}
@ -342,9 +341,11 @@ del_def
"INTERCONNECT not supported.\n",
sdf_parse_path, @2.first_line);
vpi_printf("SDF INFO: %s:%d: "
"port1 name = %s index = %d, port2 name = %s index = %d",
sdf_parse_path, @2.first_line, $3.name, $3.index, $4.name, $4.index);
if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: INTERCONNECT with "
"port1 = %s index = %d, port2 = %s index = %d\n",
sdf_parse_path, @2.first_line, $3.name, $3.index, $4.name, $4.index);
sdf_interconnect_delays($3, $4, &$5, @2.first_line);
free($3.name);
free($4.name);

View File

@ -64,4 +64,9 @@ extern void sdf_iopath_delays(int vpi_edge, const char*src, const char*dst,
const struct sdf_delval_list_s*delval,
const int sdf_lineno);
extern void sdf_interconnect_delays(struct interconnect_port_s port1, struct interconnect_port_s port2,
const struct sdf_delval_list_s*delval_list,
const int sdf_lineno);
#endif /* IVL_sdf_priv_h */

View File

@ -76,8 +76,9 @@ void sdf_select_instance(const char*celltype, const char*cellinst, const int sdf
/* Test for wildcard character */
if (cellinst == NULL) {
sdf_warn_file_line(sdf_lineno);
vpi_printf("Wildcard cell instance specification (*) currently not supported.\n");
if (sdf_flag_warning) vpi_printf("SDF WARNING: %s:%d: sorry: "
"Wildcard cell instance specification (*) currently not supported.\n",
sdf_fname, sdf_lineno);
sdf_cur_cell = 0;
return;
}
@ -88,49 +89,45 @@ void sdf_select_instance(const char*celltype, const char*cellinst, const int sdf
const char*src = cellinst;
const char*dp;
while ( (dp=strchr(src, '.')) ) {
unsigned len = dp - src;
assert(dp >= src);
assert(len < sizeof buffer);
strncpy(buffer, src, len);
buffer[len] = 0;
unsigned len = dp - src;
assert(dp >= src);
assert(len < sizeof buffer);
strncpy(buffer, src, len);
buffer[len] = 0;
vpiHandle tmp_scope = find_scope(scope, buffer);
if (tmp_scope == 0) {
sdf_warn_file_line(sdf_lineno);
vpi_printf("Cannot find %s in scope %s.\n",
buffer, vpi_get_str(vpiFullName, scope));
break;
}
assert(tmp_scope);
scope = tmp_scope;
vpiHandle tmp_scope = find_scope(scope, buffer);
if (tmp_scope == 0) {
vpi_printf("SDF ERROR: %s:%d: Cannot find %s in scope %s.\n",
sdf_fname, sdf_lineno, buffer, vpi_get_str(vpiFullName, scope));
break;
}
assert(tmp_scope);
scope = tmp_scope;
src = dp + 1;
src = dp + 1;
}
/* Now find the cell. */
if (src[0] == 0)
sdf_cur_cell = sdf_scope;
sdf_cur_cell = sdf_scope;
else
sdf_cur_cell = find_scope(scope, src);
sdf_cur_cell = find_scope(scope, src);
if (sdf_cur_cell == 0) {
sdf_warn_file_line(sdf_lineno);
vpi_printf("Unable to find %s in scope %s.\n",
src, vpi_get_str(vpiFullName, scope));
return;
vpi_printf("SDF ERROR: %s:%d: Unable to find %s in scope %s.\n",
sdf_fname, sdf_lineno, src, vpi_get_str(vpiFullName, scope));
return;
}
/* The scope that matches should be a module. */
if (vpi_get(vpiType,sdf_cur_cell) != vpiModule) {
sdf_warn_file_line(sdf_lineno);
vpi_printf("Scope %s in %s is not a module.\n",
src, vpi_get_str(vpiFullName, scope));
vpi_printf("SDF ERROR: %s:%d: Scope %s in %s is not a module.\n",
sdf_fname, sdf_lineno, src, vpi_get_str(vpiFullName, scope));
}
/* The matching scope (a module) should have the expected type. */
if (strcmp(celltype,vpi_get_str(vpiDefName,sdf_cur_cell)) != 0) {
sdf_warn_file_line(sdf_lineno);
vpi_printf("Module %s in %s is not a %s; it is a ", src,
vpi_get_str(vpiFullName, scope), celltype);
vpi_printf("SDF ERROR: %s:%d: Module %s in %s is not a %s; it is a ",
sdf_fname, sdf_lineno, src, vpi_get_str(vpiFullName, scope), celltype);
vpi_printf("%s\n", vpi_get_str(vpiDefName, sdf_cur_cell));
}
@ -147,6 +144,110 @@ static const char*edge_str(int vpi_edge)
return "edge.. ";
}
vpiHandle get_port_handle(char* port_name, const int sdf_lineno)
{
vpiHandle scope = sdf_cur_cell;
// Get occurences of '.' in the name
int submodules = 0;
for (int i=0; port_name[i] != '\0'; i++)
{
if (port_name[i] == '.') submodules++;
}
// Extract the first token
char* token = strtok(port_name, ".");;
// Change scope into submodule
while (submodules--)
{
scope = vpi_handle_by_name(token, scope);
if (!scope) vpi_printf("SDF ERROR: %s:%d: Submodule %s in port path not found!\n", sdf_fname, sdf_lineno, token);
// Extract next token
token = strtok(NULL, ".");
}
// Iterate over ports
vpiHandle port_i = vpi_iterate(vpiPort, scope) ;
vpiHandle port;
vpiHandle port_handle = NULL;
while ((port=vpi_scan(port_i)) != NULL)
{
char *port_name_ = vpi_get_str(vpiName, port) ;
if (strcmp(port_name_, token) == 0)
{
if (port_handle != NULL)
{
if (sdf_flag_warning) vpi_printf("SDF WARNING: %s:%d: Found multiple matching ports for %s !\n", sdf_fname, sdf_lineno, token);
}
if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Found handle for port %s!\n", sdf_fname, sdf_lineno, token);
port_handle = port;
}
}
return port_handle;
}
void sdf_interconnect_delays(struct interconnect_port_s port1, struct interconnect_port_s port2,
const struct sdf_delval_list_s*delval_list,
const int sdf_lineno)
{
// Get handles for both ports
// After calling get_port_handle, the name is invalid
vpiHandle port1_handle = get_port_handle(port1.name, sdf_lineno);
vpiHandle port2_handle = get_port_handle(port2.name, sdf_lineno);
if (port1_handle && port2_handle)
{
// Get interModPath for the two ports
vpiHandle intermodpath = vpi_handle_multi(vpiInterModPath, port1_handle, port2_handle);
if (intermodpath)
{
if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Got an vpiInterModPath!\n", sdf_fname, sdf_lineno);
s_vpi_delay delays;
struct t_vpi_time delay_vals[12];
// Initialize delay structure
delays.da = delay_vals;
delays.no_of_delays = delval_list->count;
delays.time_type = vpiScaledRealTime;
delays.mtm_flag = 0;
delays.append_flag = 0;
delays.pulsere_flag = 0;
vpi_get_delays(intermodpath, &delays);
for (int idx = 0 ; idx < delval_list->count ; idx += 1) {
delay_vals[idx].type = vpiScaledRealTime;
if (delval_list->val[idx].defined) {
if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Putting delay: %f for index %d\n",
sdf_fname, sdf_lineno, delval_list->val[idx].value, idx);
delay_vals[idx].real = delval_list->val[idx].value;
}
}
// Put the new delays
vpi_put_delays(intermodpath, &delays);
}
else
{
vpi_printf("SDF ERROR: %s:%d: Could not find intermodpath!\n", sdf_fname, sdf_lineno);
}
}
else
{
vpi_printf("SDF ERROR: %s:%d: Could not find handles for both ports!\n", sdf_fname, sdf_lineno);
}
}
void sdf_iopath_delays(int vpi_edge, const char*src, const char*dst,
const struct sdf_delval_list_s*delval_list,
const int sdf_lineno)
@ -214,10 +315,10 @@ void sdf_iopath_delays(int vpi_edge, const char*src, const char*dst,
}
if (match_count == 0) {
sdf_warn_file_line(sdf_lineno);
vpi_printf("Unable to match ModPath %s%s -> %s in %s\n",
edge_str(vpi_edge), src, dst,
vpi_get_str(vpiFullName, sdf_cur_cell));
vpi_printf("SDF ERROR: %s:%d: Unable to match ModPath %s%s -> %s in %s\n",
sdf_fname, sdf_lineno,
edge_str(vpi_edge), src, dst,
vpi_get_str(vpiFullName, sdf_cur_cell));
}
}
@ -309,6 +410,11 @@ static PLI_INT32 sys_sdf_annotate_calltf(ICARUS_VPI_CONST PLI_BYTE8*name)
return 0;
}
if (sdf_flag_inform) vpi_printf("SDF INFO: Loading %s from %s:%d\n",
fname,
vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
sdf_fd = fopen(fname, "r");
if (sdf_fd == 0) {
vpi_printf("SDF WARNING: %s:%d: ", vpi_get_str(vpiFile, callh),

View File

@ -277,6 +277,7 @@ typedef struct t_vpi_delay {
#define vpiConstant 7
#define vpiFunction 20
#define vpiIntegerVar 25
#define vpiInterModPath 26
#define vpiIterator 27
#define vpiMemory 29
#define vpiMemoryWord 30
@ -534,6 +535,7 @@ extern vpiHandle vpi_iterate(PLI_INT32 type, vpiHandle ref);
extern vpiHandle vpi_scan(vpiHandle iter);
extern vpiHandle vpi_handle_by_index(vpiHandle ref, PLI_INT32 idx);
extern vpiHandle vpi_handle_by_name(const char*name, vpiHandle scope);
extern vpiHandle vpi_handle_multi(PLI_INT32 type, vpiHandle ref1, vpiHandle ref2);
extern void vpi_get_time(vpiHandle obj, s_vpi_time*t);
extern PLI_INT32 vpi_get(int property, vpiHandle ref);

View File

@ -1115,3 +1115,352 @@ struct __vpiModPathSrc* vpip_make_modpath_src(struct __vpiModPath*path,
return obj;
}
vvp_fun_intermodpath::vvp_fun_intermodpath(vvp_net_t*net, unsigned width)
: net_(net)
{
for (unsigned idx = 0 ; idx < 12 ; idx += 1)
delay_[idx] = 0;
cur_vec4_ = vvp_vector4_t(width, BIT4_X);
schedule_init_propagate(net_, cur_vec4_); // TODO is this needed?
}
vvp_fun_intermodpath::~vvp_fun_intermodpath()
{
}
void vvp_fun_intermodpath::get_delay12(vvp_time64_t val[12]) const
{
for (unsigned idx = 0 ; idx < 12 ; idx += 1)
val[idx] = delay_[idx];
}
void vvp_fun_intermodpath::put_delay12(const vvp_time64_t val[12])
{
for (unsigned idx = 0 ; idx < 12 ; idx += 1)
delay_[idx] = val[idx];
}
/*
* FIXME: this implementation currently only uses the maximum delay
* from all the bit changes in the vectors. If there are multiple
* changes with different delays, then the results would be
* wrong. What should happen is that if there are multiple changes,
* multiple vectors approaching the result should be scheduled.
*/
void vvp_fun_intermodpath::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit,
vvp_context_t)
{
/* Only the first port is used. */
if (port.port() > 0)
return;
if (cur_vec4_.eeq(bit))
return;
/* Given the scheduled output time, create an output event. */
vvp_time64_t use_delay = delay_from_edge(cur_vec4_.value(0),
bit.value(0),
delay_);
/* FIXME: This bases the edge delay on only the least
bit. This is WRONG! I need to find all the possible delays,
and schedule an event for each partial change. Hard! */
for (unsigned idx = 1 ; idx < bit.size() ; idx += 1) {
vvp_time64_t tmp = delay_from_edge(cur_vec4_.value(idx),
bit.value(idx),
delay_);
/* If the current and new bit values match then no delay
* is needed for this bit. */
if (cur_vec4_.value(idx) == bit.value(idx)) continue;
assert(tmp == use_delay);
}
cur_vec4_ = bit;
schedule_generic(this, use_delay, false);
}
void vvp_fun_intermodpath::run_run()
{
net_->send_vec4(cur_vec4_, 0);
}
/*
* All the below routines that begin with
* intermodpath_* belong the internal function
* of an vpiInterModPath object. This is used to
* make some specific delays path operations
*
*/
static int intermodpath_get(int, vpiHandle ref)
{
struct __vpiInterModPath*obj =dynamic_cast<__vpiInterModPath*>(ref);
assert(obj);
return 0;
}
static void intermodpath_get_value(vpiHandle ref, p_vpi_value)
{
struct __vpiInterModPath* intermodpath = dynamic_cast<__vpiInterModPath*>(ref);
assert(intermodpath);
return;
}
static vpiHandle intermodpath_put_value(vpiHandle ref, s_vpi_value *, int )
{
struct __vpiInterModPath* intermodpath = dynamic_cast<__vpiInterModPath*>(ref);
assert(intermodpath);
return 0;
}
static vpiHandle intermodpath_get_handle(int code, vpiHandle ref)
{
struct __vpiInterModPath*rfp = dynamic_cast<__vpiInterModPath*>(ref);
assert(rfp);
switch (code) {
case vpiScope:
return rfp->scope;
case vpiModule:
{ __vpiScope*scope = rfp->scope;
while (scope && scope->get_type_code() != vpiModule)
scope = scope->scope;
assert(scope);
return scope;
}
}
return 0;
}
static vpiHandle intermodpath_iterate(int code, vpiHandle ref)
{
struct __vpiInterModPath*rfp = dynamic_cast<__vpiInterModPath*>(ref);
assert(rfp);
// For now intermodpaths only support exactly two ports
switch (code) {
case vpiPort: {
vpiHandle*args = (vpiHandle*)calloc(2, sizeof(vpiHandle*));
args[0] = rfp->port1;
args[1] = rfp->port2;
return vpip_make_iterator(2, args, true);
}
}
return 0;
}
/*
* This routine will put specific dimension of delay[] values
* into a vpiHandle. In this case, we will put
* specific delays values in a vpiInterModPath object
* TODO code duplication
*/
static void intermodpath_put_delays (vpiHandle ref, p_vpi_delay delays)
{
vvp_time64_t tmp[12];
int idx;
struct __vpiInterModPath * src = dynamic_cast<__vpiInterModPath*>(ref) ;
assert(src) ;
vvp_fun_intermodpath *fun = dynamic_cast<vvp_fun_intermodpath*>(src->net->fun);
assert( fun );
typedef unsigned char map_array_t[12];
// Only the first six entries are used for the less than twelve maps.
static const map_array_t map_1 = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
static const map_array_t map_2 = {0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0};
static const map_array_t map_3 = {0, 1, 2, 0, 2, 1, 0, 0, 0, 0, 0, 0};
static const map_array_t map_6 = {0, 1, 2, 3, 4, 5, 0, 0, 0, 0, 0, 0};
static const map_array_t map12 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
const map_array_t*use_map = 0;
switch (delays->no_of_delays) {
case 1:
use_map = &map_1;
break;
case 2:
use_map = &map_2;
break;
case 3:
use_map = &map_3;
break;
case 6:
use_map = &map_6;
break;
case 12:
use_map = &map12;
break;
default:
assert(0);
break;
}
if (delays->time_type == vpiSimTime) {
for (idx = 0 ; idx < 12 ; idx += 1) {
tmp[idx] = vpip_timestruct_to_time(delays->da+use_map[0][idx]);
}
} else {
// You cannot create a modpath with a negative delay so set it
// to zero per 1364-2005 section 14.3.1.
for (idx = 0 ; idx < delays->no_of_delays ; idx += 1) {
if (delays->da[idx].real < 0.0) delays->da[idx].real = 0.0;
}
for (idx = 0 ; idx < 12 ; idx += 1) {
tmp[idx] = vpip_scaled_real_to_time64(delays->da[use_map[0][idx]].real,
src->scope);
}
}
/* Now define the to-from-x delays if needed. */
if (delays->no_of_delays <= 6) {
/* 0->x is the minimum of 0->z and 0->1. */
tmp[DELAY_EDGE_0x] = tmp[DELAY_EDGE_0z] < tmp[DELAY_EDGE_01] ?
tmp[DELAY_EDGE_0z] : tmp[DELAY_EDGE_01];
/* x->1 is the maximum of z->1 and 0->1. */
tmp[DELAY_EDGE_x1] = tmp[DELAY_EDGE_z1] > tmp[DELAY_EDGE_01] ?
tmp[DELAY_EDGE_z1] : tmp[DELAY_EDGE_01];
/* 1->x is the minimum of 1->z and 1->0. */
tmp[DELAY_EDGE_1x] = tmp[DELAY_EDGE_1z] < tmp[DELAY_EDGE_10] ?
tmp[DELAY_EDGE_1z] : tmp[DELAY_EDGE_10];
/* x->0 is the maximum of z->0 and 1->0. */
tmp[DELAY_EDGE_x0] = tmp[DELAY_EDGE_z0] > tmp[DELAY_EDGE_10] ?
tmp[DELAY_EDGE_z0] : tmp[DELAY_EDGE_10];
/* x->z is the maximum of 1->z and 0->z. */
tmp[DELAY_EDGE_xz] = tmp[DELAY_EDGE_1z] > tmp[DELAY_EDGE_0z] ?
tmp[DELAY_EDGE_1z] : tmp[DELAY_EDGE_0z];
/* z->x is the minimum of z->1 and z->0. */
tmp[DELAY_EDGE_zx] = tmp[DELAY_EDGE_z1] < tmp[DELAY_EDGE_z0] ?
tmp[DELAY_EDGE_z1] : tmp[DELAY_EDGE_z0];
}
fun->put_delay12(tmp);
}
/*
* This routine will retrieve the delay[12] values
* of a vpiHandle. In this case, he will get an
* specific delays values from a vpiInterModPath
* object
*
*/
static void intermodpath_get_delays ( vpiHandle ref, p_vpi_delay delays )
{
struct __vpiInterModPath*src = dynamic_cast<__vpiInterModPath*>(ref) ;
assert(src);
vvp_fun_intermodpath *fun = dynamic_cast<vvp_fun_intermodpath*>(src->net->fun);
assert(fun);
int idx;
vvp_time64_t tmp[12];
fun->get_delay12(tmp);
switch (delays->no_of_delays) {
case 1:
case 2:
case 3:
case 6:
case 12:
break;
default:
assert(0);
break;
}
if (delays->time_type == vpiSimTime) {
for (idx = 0; idx < delays->no_of_delays; idx += 1) {
vpip_time_to_timestruct(delays->da+idx, tmp[idx]);
}
} else {
for (idx = 0; idx < delays->no_of_delays; idx += 1) {
delays->da[idx].real = vpip_time_to_scaled_real(tmp[idx], src->scope);
}
}
}
/*
* The __vpiInterModPath class is what the VPI client sees as a
* vpiInterModPath object.
*/
inline __vpiInterModPath::__vpiInterModPath()
{ }
int __vpiInterModPath::get_type_code(void) const
{ return vpiInterModPath; }
int __vpiInterModPath::vpi_get(int code)
{ return intermodpath_get(code, this); }
void __vpiInterModPath::vpi_get_value(p_vpi_value val)
{ intermodpath_get_value(this, val); }
vpiHandle __vpiInterModPath::vpi_put_value(p_vpi_value val, int flags)
{ return intermodpath_put_value(this, val, flags); }
vpiHandle __vpiInterModPath::vpi_handle(int code)
{ return intermodpath_get_handle(code, this); }
vpiHandle __vpiInterModPath::vpi_iterate(int code)
{ return intermodpath_iterate(code, this); }
void __vpiInterModPath::vpi_get_delays(p_vpi_delay del)
{ intermodpath_get_delays(this, del); }
void __vpiInterModPath::vpi_put_delays(p_vpi_delay del)
{ intermodpath_put_delays(this, del); }
static int intermodpath_free_object( vpiHandle ref )
{
delete ref;
return 1 ;
}
__vpiHandle::free_object_fun_t __vpiInterModPath::free_object_fun(void)
{ return &intermodpath_free_object; }
/*
* This function will construct a vpiInterModPath Object.
* give a respective "net", and will point to his
* respective functor
*/
#ifdef CHECK_WITH_VALGRIND
static struct __vpiInterModPath**imp_list = 0;
static unsigned imp_count = 0;
#endif
struct __vpiInterModPath* vpip_make_intermodpath(vvp_net_t *net, vpiPortInfo* port1, vpiPortInfo* port2)
{
struct __vpiInterModPath*obj = new __vpiInterModPath;
obj->scope = vpip_peek_current_scope ( );
obj->net = net;
obj->port1 = port1;
obj->port2 = port2;
#ifdef CHECK_WITH_VALGRIND
imp_count += 1;
imp_list = (struct __vpiInterModPath **) realloc(imp_list,
imp_count*sizeof(struct __vpiInterModPath **));
imp_list[imp_count-1] = obj;
#endif
return obj;
}
#ifdef CHECK_WITH_VALGRIND
void intermodpath_delete()
{
for (unsigned idx = 0; idx < mp_count; idx += 1) {
delete imp_list[idx];
}
free(imp_list);
imp_list = 0;
imp_count = 0;
}
#endif

View File

@ -234,4 +234,34 @@ class vvp_fun_modpath_edge : public vvp_fun_modpath_src {
bool negedge_;
};
/*
* The intermodpath is used to implement the SDF INTERCONNECT feature
*/
class vvp_fun_intermodpath : public vvp_net_fun_t, private vvp_gen_event_s {
public:
vvp_fun_intermodpath(vvp_net_t*net, unsigned width);
~vvp_fun_intermodpath();
void recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit,
vvp_context_t);
void get_delay12(vvp_time64_t out[12]) const;
void put_delay12(const vvp_time64_t in[12]);
private:
virtual void run_run();
private:
vvp_net_t*net_;
vvp_vector4_t cur_vec4_;
vvp_time64_t delay_[12];
private: // not implemented
vvp_fun_intermodpath(const vvp_fun_intermodpath&);
vvp_fun_intermodpath& operator= (const vvp_fun_intermodpath&);
};
#endif /* IVL_delay_H */

View File

@ -20,6 +20,7 @@
# include "version_base.h"
# include "vpi_priv.h"
# include "schedule.h"
# include "logic.h"
#ifdef CHECK_WITH_VALGRIND
# include "vvp_cleanup.h"
#endif
@ -1553,6 +1554,159 @@ vpiHandle vpi_handle_by_name(const char *name, vpiHandle scope)
return out;
}
// Used to get intermodpath for two ports
vpiHandle vpi_handle_multi(PLI_INT32 type,
vpiHandle ref1,
vpiHandle ref2)
{
if (vpi_trace) {
fprintf(vpi_trace, "vpi_handle_multi(%d, %p, %p) -->\n",
type, ref1, ref2);
}
if (type != vpiInterModPath) {
fprintf(stderr, "sorry: vpi_handle_multi currently supports"
"only vpiInterModPath\n");
return nullptr;
}
vpiPortInfo* port1 = dynamic_cast<vpiPortInfo*>(ref1);
if (!port1) {
fprintf(stderr, "sorry: second argument of vpi_handle_multi"
"must be a vpiPort\n");
return nullptr;
}
vpiPortInfo* port2 = dynamic_cast<vpiPortInfo*>(ref2);
if (!port2) {
fprintf(stderr, "sorry: third argument of vpi_handle_multi"
"must be a vpiPort\n");
return nullptr;
}
std::string port_name1(vpi_get_str(vpiName, ref1));
std::string port_name2(vpi_get_str(vpiName, ref2));
fprintf(stderr, "port_name1: %s\n", port_name1.c_str());
fprintf(stderr, "port_name2: %s\n", port_name2.c_str());
vpiHandle mod1 = vpi_handle(vpiModule, ref1);
vpiHandle mod2 = vpi_handle(vpiModule, ref2);
if (!mod1) fprintf(stderr, "Cannot access module of port1!\n");
if (!mod2) fprintf(stderr, "Cannot access module of port2!\n");
// Find net for port1
vpiHandle net_i = vpi_iterate(vpiNet, mod1);
vpiHandle net;
vpiHandle net_handle1 = nullptr;
while ((net=vpi_scan(net_i)) != nullptr)
{
char *net_name = vpi_get_str(vpiName, net);
fprintf(stderr, "Comparing %s and %s\n", net_name, port_name1.c_str());
if (port_name1 == net_name)
{
if (net_handle1 != nullptr)
{
fprintf(stderr, "Found multiple matching nets for %s !\n", port_name1.c_str());
}
fprintf(stderr, "Found handle for net %s!\n", net_name);
net_handle1 = net;
}
}
// Find net for port2
net_i = vpi_iterate(vpiNet, mod2);
vpiHandle net_handle2 = nullptr;
while ((net=vpi_scan(net_i)) != nullptr)
{
char *net_name = vpi_get_str(vpiName, net);
fprintf(stderr, "Comparing %s and %s\n", net_name, port_name2.c_str());
if (port_name2 == net_name)
{
if (net_handle2 != nullptr)
{
fprintf(stderr, "Found multiple matching nets for %s !\n", port_name2.c_str());
}
fprintf(stderr, "Found handle for net %s!\n", net_name);
net_handle2 = net;
}
}
// Try to access net/node behind it
struct __vpiSignal*node1 = dynamic_cast<__vpiSignal*>(net_handle1);
assert(node1);
struct __vpiSignal*node2 = dynamic_cast<__vpiSignal*>(net_handle2);
assert(node2);
vvp_net_t* net1 = node1->node;
vvp_net_t* net2 = node2->node;
// TODO don't just compare the nets, may be a problem for high fan-out nets
if (net1 == net2)
{
fprintf(stderr, "Same net!\n");
}
else
{
fprintf(stderr, "Different net!\n");
return nullptr;
}
// Debug information
for (int i=0; i<4; i++)
{
fprintf(stderr, "my_node1->port[%d].ptr() : %p\n", i, net1->port[i].ptr());
fprintf(stderr, "my_node1->port[%d].port() : %d\n", i, net1->port[i].port());
}
fprintf(stderr, "my_node1->fun : %p\n", net1->fun);
fprintf(stderr, "my_node1->fil : %p\n", net1->fil);
fprintf(stderr, "my_node1->fil->filter_size() : %d\n", net1->fil->filter_size());
//fprintf(stderr, "my_node1->out_.ptr() : %p\n", net1->out_.ptr()); // vvp_net_t
//fprintf(stderr, "my_node1->out_.port() : %d\n", net1->out_.port()); // input 3-0
// TODO for now just replace vvp_fun_bufz with vvp_fun_intermodpath
if (dynamic_cast<vvp_fun_bufz*>(net1->fun))
{
std::cout << "Replacing with vvp_fun_intermodpath!" << std::endl;
int width = 1; // TODO
vvp_fun_intermodpath*obj = new vvp_fun_intermodpath(net1, width);
net1->fun = obj;
__vpiInterModPath*intermodpath = vpip_make_intermodpath(net1, port1, port2);
intermodpath->intermodpath = obj;
// TODO add net to network
/*vvp_net_t*net = new vvp_net_t;
vvp_fun_intermodpath*obj = new vvp_fun_intermodpath(net, width, delay);
net->fun = obj;
__vpiInterModPath*intermodpath = vpip_make_intermodpath(net, ref1, ref2);
intermodpath->intermodpath = obj;*/
return intermodpath;
}
else
{
std::cout << "sorry: Could not insert intermodpath!" << std::endl;
}
return nullptr;
}
/*
We increment the two vpi methods to enable the
@ -1749,6 +1903,7 @@ vpip_routines_s vpi_routines = {
.get_systf_info = vpi_get_systf_info,
.handle_by_name = vpi_handle_by_name,
.handle_by_index = vpi_handle_by_index,
.handle_multi = vpi_handle_multi,
.handle = vpi_handle,
.iterate = vpi_iterate,
.scan = vpi_scan,

View File

@ -432,6 +432,30 @@ struct __vpiBit {
int get_index(void) const;
};
class vpiPortInfo : public __vpiHandle {
public:
vpiPortInfo( __vpiScope *parent,
unsigned index,
int vpi_direction,
unsigned width,
const char *name );
~vpiPortInfo();
int get_type_code(void) const { return vpiPort; }
int vpi_get(int code);
char* vpi_get_str(int code);
vpiHandle vpi_handle(int code);
private:
__vpiScope *parent_;
unsigned index_;
int direction_;
unsigned width_;
const char *name_;
};
/*
* This is used by system calls to represent a bit/part select of
* a simple variable or constant array word.
@ -520,6 +544,43 @@ extern struct __vpiModPathSrc* vpip_make_modpath_src(struct __vpiModPath*path,
extern struct __vpiModPath* vpip_make_modpath(vvp_net_t *net) ;
/*
*
* The vpiInterModPath vpiHandle will define
* a vpiInterModPath of record .intermodpath as defined
* in the IEEE 1364
*
*/
struct __vpiInterModPath : public __vpiHandle {
__vpiInterModPath();
int get_type_code(void) const;
int vpi_get(int code);
void vpi_get_value(p_vpi_value val);
vpiHandle vpi_put_value(p_vpi_value val, int flags);
vpiHandle vpi_handle(int code);
vpiHandle vpi_iterate(int code);
void vpi_get_delays(p_vpi_delay del);
void vpi_put_delays(p_vpi_delay del);
free_object_fun_t free_object_fun(void);
__vpiScope *scope ;
class vvp_fun_intermodpath*intermodpath;
vvp_net_t *net;
vpiPortInfo* port1;
vpiPortInfo* port2;
};
/*
* The Function is used to create the vpiHandle
* for vpiInterModPath
*/
extern struct __vpiInterModPath* vpip_make_intermodpath(vvp_net_t *net, vpiPortInfo* port1, vpiPortInfo* port2);
/*
* These methods support the vpi creation of events. The name string

View File

@ -82,6 +82,9 @@ static void delete_sub_scopes(__vpiScope *scope)
/* The destination ModPath is cleaned up later. */
delete item;
break;
case vpiInterModPath:
delete item;
break;
case vpiNamedEvent:
named_event_delete(item);
break;
@ -659,29 +662,6 @@ unsigned vpip_add_item_to_context(automatic_hooks_s*item,
}
class vpiPortInfo : public __vpiHandle {
public:
vpiPortInfo( __vpiScope *parent,
unsigned index,
int vpi_direction,
unsigned width,
const char *name );
~vpiPortInfo();
int get_type_code(void) const { return vpiPort; }
int vpi_get(int code);
char* vpi_get_str(int code);
vpiHandle vpi_handle(int code);
private:
__vpiScope *parent_;
unsigned index_;
int direction_;
unsigned width_;
const char *name_;
};
vpiPortInfo::vpiPortInfo( __vpiScope *parent,
unsigned index,
int vpi_direction,

View File

@ -18,6 +18,7 @@ vpi_get_vlog_info
vpi_handle
vpi_handle_by_index
vpi_handle_by_name
vpi_handle_multi
vpi_iterate
vpi_mcd_close
vpi_mcd_flush