This commit is contained in:
mole99 2023-08-17 16:09:20 +02:00
parent 306e4cfa6b
commit 11c944f5e9
12 changed files with 253 additions and 270 deletions

View File

@ -758,7 +758,7 @@ static int process_generation(const char*name)
else if (strcmp(name,"no-specify") == 0)
gen_specify = "no-specify";
else if (strcmp(name,"interconnect") == 0)
else if (strcmp(name,"interconnect") == 0)
gen_interconnect = "interconnect";
else if (strcmp(name,"no-interconnect") == 0)

View File

@ -1600,23 +1600,23 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const
// Add module input buffers if needed
if (need_bufz_for_input_port(prts) || gn_interconnect_flag == true) {
// FIXME improve this for multiple module instances
NetScope* inner_scope = scope->instance_arrays[get_name()][0];
// FIXME improve this for multiple module instances
NetScope* inner_scope = scope->instance_arrays[get_name()][0];
NetBUFZ*tmp = new NetBUFZ(inner_scope, inner_scope->local_symbol(),
sig->vector_width(), true, gn_interconnect_flag ? idx : -1);
tmp->set_line(*this);
des->add_node(tmp);
connect(tmp->pin(1), sig->pin(0));
NetBUFZ*tmp = new NetBUFZ(inner_scope, inner_scope->local_symbol(),
sig->vector_width(), true, gn_interconnect_flag ? idx : -1);
tmp->set_line(*this);
des->add_node(tmp);
connect(tmp->pin(1), sig->pin(0));
netvector_t*tmp2_vec = new netvector_t(sig->data_type(),
sig->vector_width()-1,0);
NetNet*tmp2 = new NetNet(inner_scope, inner_scope->local_symbol(),
NetNet::WIRE, tmp2_vec);
tmp2->local_flag(true);
tmp2->set_line(*this);
connect(tmp->pin(0), tmp2->pin(0));
sig = tmp2;
netvector_t*tmp2_vec = new netvector_t(sig->data_type(),
sig->vector_width()-1,0);
NetNet*tmp2 = new NetNet(inner_scope, inner_scope->local_symbol(),
NetNet::WIRE, tmp2_vec);
tmp2->local_flag(true);
tmp2->set_line(*this);
connect(tmp->pin(0), tmp2->pin(0));
sig = tmp2;
}
// If we have a real signal driving a bit/vector port
@ -1938,12 +1938,12 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const
// the delay being applied to other drivers of
// the external signal.
if (prts[0]->delay_paths() > 0 || (gn_interconnect_flag == true && ptype == NetNet::POUTPUT)) {
// FIXME improve this for multiple module instances
NetScope* inner_scope = scope->instance_arrays[get_name()][0];
// FIXME improve this for multiple module instances
NetScope* inner_scope = scope->instance_arrays[get_name()][0];
isolate_and_connect(des, inner_scope, this, prts[0], sig, ptype, gn_interconnect_flag ? idx : -1);
isolate_and_connect(des, inner_scope, this, prts[0], sig, ptype, gn_interconnect_flag ? idx : -1);
} else {
connect(prts[0]->pin(0), sig->pin(0));
connect(prts[0]->pin(0), sig->pin(0));
}
} else if (sig->vector_width()==prts_vector_width/instance.size()

View File

@ -893,13 +893,12 @@ bool dll_target::bufz(const NetBUFZ*net)
scope_add_logic(scop, obj);
// Add bufz to the corresponding port_info entry,
// if it is an input / output buffer
// This is needed for the SDF interconnect feature
// to access the buffers directly from the port_info
if (obj->is_port_buffer)
{
scop->module_ports_info[net->port_info_index()].buffer = obj;
// Add bufz to the corresponding port_info entry,
// if it is an input / output buffer
// This is needed for the SDF interconnect feature
// to access the buffers directly from the port_info
if (obj->is_port_buffer) {
scop->module_ports_info[net->port_info_index()].buffer = obj;
}
return true;

View File

@ -308,7 +308,7 @@ int signal_is_return_value(ivl_signal_t sig)
*/
int can_elide_bufz(ivl_net_logic_t net, ivl_nexus_ptr_t nptr)
{
// If bufz is a module input/output buffer do not elide
// If bufz is a module input/output buffer do not elide
if (ivl_logic_port_buffer(net)) return 0;
ivl_nexus_t in_n, out_n;
@ -2403,20 +2403,20 @@ int draw_scope(ivl_scope_t net, ivl_scope_t parent)
if( ivl_scope_type(net) == IVL_SCT_MODULE ) {
// Port data for VPI: needed for vpiPorts property of vpiModule
for( idx = 0; idx < ivl_scope_mod_module_ports(net); ++idx ) {
const char *name = ivl_scope_mod_module_port_name(net,idx);
ivl_signal_port_t ptype = ivl_scope_mod_module_port_type(net,idx);
unsigned width = ivl_scope_mod_module_port_width(net,idx);
ivl_net_logic_t buffer = ivl_scope_mod_module_port_buffer(net,idx);
if( name == 0 )
name = "";
fprintf( vvp_out, " .port_info %u %s %u \"%s\"",
idx, vvp_port_info_type_str(ptype), width,
vvp_mangle_name(name) );
if (buffer) fprintf( vvp_out, " L_%p;\n", buffer);
else fprintf( vvp_out, ";\n");
}
// Port data for VPI: needed for vpiPorts property of vpiModule
for( idx = 0; idx < ivl_scope_mod_module_ports(net); ++idx ) {
const char *name = ivl_scope_mod_module_port_name(net,idx);
ivl_signal_port_t ptype = ivl_scope_mod_module_port_type(net,idx);
unsigned width = ivl_scope_mod_module_port_width(net,idx);
ivl_net_logic_t buffer = ivl_scope_mod_module_port_buffer(net,idx);
if( name == 0 )
name = "";
fprintf( vvp_out, " .port_info %u %s %u \"%s\"",
idx, vvp_port_info_type_str(ptype), width,
vvp_mangle_name(name) );
if (buffer) fprintf( vvp_out, " L_%p;\n", buffer);
else fprintf( vvp_out, ";\n");
}
}
for (idx = 0 ; idx < ivl_scope_params(net) ; idx += 1) {

View File

@ -160,26 +160,31 @@ 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);
}
;
voltage
: '(' K_VOLTAGE 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);
}
else if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Voltage: %f\n",
sdf_parse_path, @2.first_line, $3.value);
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: Voltage: %f\n",
sdf_parse_path, @2.first_line, $3.value);
}
}
| '(' K_VOLTAGE signed_real_number ')'
{ if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Voltage: %f\n",
@ -198,10 +203,10 @@ 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);
else if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Temperature: %f\n",
sdf_parse_path, @2.first_line, $3.value);
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);
}
| '(' K_TEMPERATURE signed_real_number ')'
{ if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Temperature: %f\n",
@ -338,18 +343,21 @@ del_def
/* | '(' K_INTERCONNECT port_instance port_instance delval_list ')' */
| '(' K_INTERCONNECT port_interconnect port_interconnect delval_list ')'
{
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);
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);
sdf_interconnect_delays($3, $4, &$5, @2.first_line);
free($3.name);
free($4.name);
free($3.name);
free($4.name);
}
| '(' K_INTERCONNECT error ')'
{ vpi_printf("SDF ERROR: %s:%d: Invalid/malformed INTERCONNECT\n",
sdf_parse_path, @2.first_line); }
sdf_parse_path, @2.first_line);
}
;
tchk_def_list
@ -465,13 +473,13 @@ port
port_interconnect
: hierarchical_identifier
{
struct interconnect_port_s tmp = {$1, -1};
$$ = tmp;
struct interconnect_port_s tmp = {$1, -1};
$$ = tmp;
}
| hierarchical_identifier '[' INTEGER ']'
{
struct interconnect_port_s tmp = {$1, $3};
$$ = tmp;
struct interconnect_port_s tmp = {$1, $3};
$$ = tmp;
}
;

View File

@ -60,13 +60,15 @@ struct interconnect_port_s {
extern void sdf_select_instance(const char*celltype, const char*inst,
const int sdf_lineno);
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);
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,9 +76,11 @@ void sdf_select_instance(const char*celltype, const char*cellinst, const int sdf
/* Test for wildcard character */
if (cellinst == NULL) {
if (sdf_flag_warning) vpi_printf("SDF WARNING: %s:%d: sorry: "
"Wildcard cell instance specification (*) currently not supported.\n",
sdf_fname, sdf_lineno);
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;
}
@ -89,45 +91,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) {
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;
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) {
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;
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) {
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));
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) {
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);
sdf_fname, sdf_lineno, src, vpi_get_str(vpiFullName, scope), celltype);
vpi_printf("%s\n", vpi_get_str(vpiDefName, sdf_cur_cell));
}
@ -148,45 +150,40 @@ vpiHandle get_port_handle(char* port_name, const int sdf_lineno)
{
vpiHandle scope = sdf_cur_cell;
// Get occurences of '.' in the name
// Get occurences of '.' in the name
int submodules = 0;
for (int i=0; port_name[i] != '\0'; i++)
{
if (port_name[i] == '.') submodules++;
for (int i=0; port_name[i] != '\0'; i++) {
if (port_name[i] == '.') submodules++;
}
// Extract the first token
// Extract the first token
char* token = strtok(port_name, ".");;
// Change scope into submodule
while (submodules--)
{
scope = vpi_handle_by_name(token, scope);
// 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);
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, ".");
token = strtok(NULL, ".");
}
// Iterate over ports
// 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) ;
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);
}
port_handle = 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);
}
port_handle = port;
}
}
return port_handle;
@ -198,52 +195,46 @@ void sdf_interconnect_delays(struct interconnect_port_s port1, struct interconne
const int sdf_lineno)
{
// Get handles for both ports
// After calling get_port_handle, the name is invalid
// 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)
{
if (port1_handle && port2_handle) {
// Get interModPath for the two ports
vpiHandle intermodpath = vpi_handle_multi(vpiInterModPath, port1_handle, port2_handle);
vpiHandle intermodpath = vpi_handle_multi(vpiInterModPath, port1_handle, port2_handle);
if (intermodpath)
{
if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Created a vpiInterModPath\n", sdf_fname, sdf_lineno);
if (intermodpath) {
if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Created a vpiInterModPath\n", sdf_fname, sdf_lineno);
s_vpi_delay delays;
struct t_vpi_time delay_vals[12];
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);
// 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;
}
}
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);
// 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);
}
}
@ -314,10 +305,10 @@ void sdf_iopath_delays(int vpi_edge, const char*src, const char*dst,
}
if (match_count == 0) {
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));
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));
}
}
@ -409,10 +400,12 @@ 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));
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) {

View File

@ -1120,10 +1120,10 @@ 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;
delay_[idx] = 0;
cur_vec4_ = vvp_vector4_t(width, BIT4_X);
schedule_init_propagate(net_, cur_vec4_); // TODO is this needed?
schedule_init_propagate(net_, cur_vec4_);
}
vvp_fun_intermodpath::~vvp_fun_intermodpath()
@ -1252,12 +1252,11 @@ static vpiHandle intermodpath_iterate(int code, vpiHandle ref)
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)
{

View File

@ -236,6 +236,8 @@ class vvp_fun_modpath_edge : public vvp_fun_modpath_src {
/*
* The intermodpath is used to implement the SDF INTERCONNECT feature
* Upon a (INTERCONNECT ...) statement an intermodpath will be inserted
* between port1 and port2 and its delay can be annotated
*/
class vvp_fun_intermodpath : public vvp_net_fun_t, private vvp_gen_event_s {

View File

@ -1,5 +1,6 @@
/*
* Copyright (c) 2008-2022 Stephen Williams (steve@icarus.com)
* Copyright (c) 2008-2023 Stephen Williams (steve@icarus.com)
* Copyright (c) 2023 Leo Moser (leo.moser@pm.me)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@ -33,16 +34,6 @@
# include <cmath>
# include <iostream>
# include "npmos.h"
# include "vvp_island.h"
# include "resolv.h"
# include "bufif.h"
# include "latch.h"
# include "dff.h"
# include "event.h"
# include "arith.h"
# include "part.h"
using namespace std;
vpi_mode_t vpi_mode_flag = VPI_MODE_NONE;
FILE*vpi_trace = 0;
@ -1570,144 +1561,132 @@ vpiHandle vpi_handle_multi(PLI_INT32 type,
vpiHandle ref2)
{
if (vpi_trace) {
fprintf(vpi_trace, "vpi_handle_multi(%d, %p, %p) -->\n",
type, ref1, ref2);
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;
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;
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;
fprintf(stderr, "sorry: third argument of vpi_handle_multi"
"must be a vpiPort\n");
return nullptr;
}
// If both ports are vpiOutput, we have to reassign the __vpiSignal from port1
// to port2 because otherwise the non-delayed version of the signal is dumped
// even tho the intermodpath is correctly inserted
// If both ports are vpiOutput, we have to reassign the __vpiSignal from port1
// to port2 because otherwise the non-delayed version of the signal is dumped
// even tho the intermodpath is correctly inserted
__vpiSignal* output_signal = nullptr;
if (port1->get_direction() == vpiOutput && port2->get_direction() == vpiOutput)
{
vpiHandle scope_port2 = vpi_handle(vpiScope, ref2);
assert(scope_port2);
std::string port2_name(vpi_get_str(vpiName, ref2));
if (port1->get_direction() == vpiOutput && port2->get_direction() == vpiOutput) {
vpiHandle scope_port2 = vpi_handle(vpiScope, ref2);
assert(scope_port2);
std::string port2_name(vpi_get_str(vpiName, ref2));
// Iterate over nets in the scope of port2
vpiHandle net_i = vpi_iterate(vpiNet, scope_port2) ;
vpiHandle net;
vpiHandle net_i = vpi_iterate(vpiNet, scope_port2) ;
vpiHandle net;
while ((net = vpi_scan(net_i)) != NULL)
{
std::string net_name(vpi_get_str(vpiName, net));
while ((net = vpi_scan(net_i)) != NULL) {
std::string net_name(vpi_get_str(vpiName, net));
// Compare whether the net matches with the port name
if (net_name == port2_name)
{
output_signal = dynamic_cast<__vpiSignal*>(net);
}
}
// Compare whether the net matches with the port name
if (net_name == port2_name) {
output_signal = dynamic_cast<__vpiSignal*>(net);
}
}
}
vvp_net_t* net1 = port1->get_port();
vvp_net_t* net2 = port2->get_port();
if (net1 == nullptr || net2 == nullptr)
{
fprintf(stderr, "Error: Could not find net. "
"Did you run iverilog with '-ginterconnect'?\n");
return nullptr;
if (net1 == nullptr || net2 == nullptr) {
fprintf(stderr, "Error: Could not find net. "
"Did you run iverilog with '-ginterconnect'?\n");
return nullptr;
}
if (net1 == net2)
{
fprintf(stderr, "Error: Net for both ports is the same. "
"Did you pass the same port twice?\n");
return nullptr;
if (net1 == net2) {
fprintf(stderr, "Error: Net for both ports is the same. "
"Did you pass the same port twice?\n");
return nullptr;
}
if (!dynamic_cast<vvp_fun_buft*>(net1->fun))
{
fprintf(stderr, "Error: functor of net1 must be"
"vvp_fun_buft\n");
return nullptr;
if (!dynamic_cast<vvp_fun_buft*>(net1->fun)) {
fprintf(stderr, "Error: functor of net1 must be"
"vvp_fun_buft\n");
return nullptr;
}
if (!dynamic_cast<vvp_fun_buft*>(net2->fun))
{
fprintf(stderr, "Error: functor of net2 must be"
"vvp_fun_buft\n");
return nullptr;
if (!dynamic_cast<vvp_fun_buft*>(net2->fun)) {
fprintf(stderr, "Error: functor of net2 must be"
"vvp_fun_buft\n");
return nullptr;
}
// Iterate over all nodes connected to port1
// Iterate over all nodes connected to port1
vvp_net_ptr_t cur = net1->out_;
vvp_net_ptr_t prev = vvp_net_ptr_t(nullptr, 0);
while (cur.ptr())
{
while (cur.ptr()) {
// Port2 is directly connected to port1
if (cur.ptr() == net2)
{
vvp_net_t*new_net = new vvp_net_t;
if (cur.ptr() == net2) {
vvp_net_t*new_net = new vvp_net_t;
int width = 1; // TODO
vvp_fun_intermodpath*obj = new vvp_fun_intermodpath(new_net, width);
new_net->fun = obj;
new_net->out_ = cur; // TODO pointer to current net
// Create new node with intermodpath and connect port2 to it
int width = 1; // TODO
vvp_fun_intermodpath*obj = new vvp_fun_intermodpath(new_net, width);
new_net->fun = obj;
new_net->out_ = cur;
// Port2 is in the middle of the list
// Insert intermodpath before port2 and keep everything else intact
if (prev.ptr())
{
prev.ptr()->port[prev.port()] = vvp_net_ptr_t(new_net, 0); // Point to port 0 of vvp_fun_intermodpath
new_net->port[0] = cur.ptr()->port[cur.port()]; // Connect the next net in list
cur.ptr()->port[cur.port()] = vvp_net_ptr_t(nullptr, 0); // Only port2 is connected to intermodpath
}
// Port2 is first in list
// Insert intermodpath before port2 and keep everything else intact
else
{
net1->out_ = vvp_net_ptr_t(new_net, 0); // Point to port 0 of vvp_fun_intermodpath
new_net->port[0] = cur.ptr()->port[cur.port()]; // Connect the next net in list
cur.ptr()->port[cur.port()] = vvp_net_ptr_t(nullptr, 0); // Only port2 is connected to intermodpath
}
// Port2 is in the middle of the list
// Insert intermodpath before port2 and keep everything else intact
if (prev.ptr()) {
prev.ptr()->port[prev.port()] = vvp_net_ptr_t(new_net, 0); // Point to port 0 of vvp_fun_intermodpath
new_net->port[0] = cur.ptr()->port[cur.port()]; // Connect the next net in list
cur.ptr()->port[cur.port()] = vvp_net_ptr_t(nullptr, 0); // Only port2 is connected to intermodpath
// Port2 is first in list
// Insert intermodpath before port2 and keep everything else intact
} else {
net1->out_ = vvp_net_ptr_t(new_net, 0); // Point to port 0 of vvp_fun_intermodpath
new_net->port[0] = cur.ptr()->port[cur.port()]; // Connect the next net in list
cur.ptr()->port[cur.port()] = vvp_net_ptr_t(nullptr, 0); // Only port2 is connected to intermodpath
}
// If both ports are vpiOutput, we have to reassign the __vpiSignal
if (output_signal)
{
net2->fil = net1->fil;
net1->fil = nullptr;
output_signal->node = net2;
}
// If both ports are vpiOutput, we have to reassign the __vpiSignal
if (output_signal) {
net2->fil = net1->fil;
net1->fil = nullptr;
output_signal->node = net2;
}
// Create the VPI intermodpath object
__vpiInterModPath* intermodpath = vpip_make_intermodpath(new_net, port1, port2);
intermodpath->intermodpath = obj;
// Create the VPI intermodpath object
__vpiInterModPath* intermodpath = vpip_make_intermodpath(new_net, port1, port2);
intermodpath->intermodpath = obj;
// Finally done, return the intermodpath object
return intermodpath;
}
// Finally done, return the intermodpath object
return intermodpath;
}
prev = cur;
cur = cur.ptr()->port[cur.port()]; // Next net in linked list
prev = cur;
cur = cur.ptr()->port[cur.port()]; // Next net in linked list
}
std::cout << "sorry: Could not insert intermodpath!" << std::endl;
fprintf(stderr, "VPI error: Could not insert intermodpath!\n");
return nullptr;
}

View File

@ -742,7 +742,7 @@ vpiHandle vpiPortInfo::vpi_handle(int code)
*/
void compile_port_info( unsigned index, int vpi_direction, unsigned width, const char *name, char* buffer )
{
vpiHandle obj = new vpiPortInfo( vpip_peek_current_scope(),
index, vpi_direction, width, name, buffer );
vpip_attach_to_current_scope(obj);
vpiHandle obj = new vpiPortInfo( vpip_peek_current_scope(),
index, vpi_direction, width, name, buffer );
vpip_attach_to_current_scope(obj);
}

View File

@ -1159,6 +1159,7 @@ class vvp_net_t {
public: // Method to support $countdrivers
void count_drivers(unsigned idx, unsigned counts[4]);
// This needs to be public so that SDF interconnects can be inserted
public:
vvp_net_ptr_t out_;