Improve SDF interconnect support, add -ginterconnect flag

This commit is contained in:
mole99 2023-08-08 11:42:15 +02:00
parent adb40e7572
commit 6d3e2bf344
20 changed files with 277 additions and 149 deletions

View File

@ -177,6 +177,11 @@ extern bool gn_icarus_misc_flag;
is false, then skip elaboration of specify behavior. */
extern bool gn_specify_blocks_flag;
/* If this flag is true, then add input/output buffers to modules so that
VVP can insert intermodpaths inbetween. If this flag
is false, then no input/output buffers are inserted if not needed. */
extern bool gn_interconnect_flag;
/* If this flag is true, then elaborate supported assertion statements. If
this flag is false, then stub out supported assertion statements. */
extern bool gn_supported_assertions_flag;

View File

@ -95,6 +95,14 @@ simulation, and in fact can hurt performance of the
simulation. However, disabling specify blocks reduces accuracy of
full-timing simulations.
.TP 8
.B -ginterconnect\fI|\fP-gno-interconnect
Enable or disable (default) SDF interconnect support. When enabled,
input and output buffers will be added to modules, so that VVP can
add interconnection delays. This option is commonly not needed for RTL
simulation, and in fact can hurt performance of the
simulation. However, disabling interconnection delays reduces accuracy of
full-timing simulations.
.TP 8
.B -gstd-include\fI|\fP-gno-std-include
Enable (default) or disable the search of a standard installation
include directory after all other explicit include directories. This

View File

@ -125,6 +125,7 @@ char depmode = 'a';
const char*generation = "2005";
const char*gen_specify = "no-specify";
const char*gen_interconnect = "no-interconnect";
const char*gen_assertions = "assertions";
const char*gen_xtypes = "xtypes";
const char*gen_icarus = "icarus-misc";
@ -757,6 +758,12 @@ static int process_generation(const char*name)
else if (strcmp(name,"no-specify") == 0)
gen_specify = "no-specify";
else if (strcmp(name,"interconnect") == 0)
gen_interconnect = "interconnect";
else if (strcmp(name,"no-interconnect") == 0)
gen_interconnect = "no-interconnect";
else if (strcmp(name,"assertions") == 0)
gen_assertions = "assertions";
@ -821,6 +828,7 @@ static int process_generation(const char*name)
"Other generation flags:\n"
" assertions | supported-assertions | no-assertions\n"
" specify | no-specify\n"
" interconnect | no-interconnect\n"
" verilog-ams | no-verilog-ams\n"
" std-include | no-std-include\n"
" relative-include | no-relative-include\n"
@ -1368,6 +1376,7 @@ int main(int argc, char **argv)
if (mtm != 0) fprintf(iconfig_file, "-T:%s\n", mtm);
fprintf(iconfig_file, "generation:%s\n", generation);
fprintf(iconfig_file, "generation:%s\n", gen_specify);
fprintf(iconfig_file, "generation:%s\n", gen_interconnect);
fprintf(iconfig_file, "generation:%s\n", gen_assertions);
fprintf(iconfig_file, "generation:%s\n", gen_xtypes);
fprintf(iconfig_file, "generation:%s\n", gen_io_range_error);

View File

@ -1159,13 +1159,13 @@ static void convert_net(Design*des, const LineInfo *line,
}
static void isolate_and_connect(Design*des, NetScope*scope, const PGModule*mod,
NetNet*port, NetNet*sig, NetNet::PortType ptype)
NetNet*port, NetNet*sig, NetNet::PortType ptype, int idx = -1)
{
switch (ptype) {
case NetNet::POUTPUT:
{
NetBUFZ*tmp = new NetBUFZ(scope, scope->local_symbol(),
sig->vector_width(), true);
sig->vector_width(), true, idx);
tmp->set_line(*mod);
des->add_node(tmp);
connect(tmp->pin(1), port->pin(0));
@ -1598,21 +1598,25 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const
}
}
if (need_bufz_for_input_port(prts)) {
NetBUFZ*tmp = new NetBUFZ(scope, scope->local_symbol(),
sig->vector_width(), true);
tmp->set_line(*this);
des->add_node(tmp);
connect(tmp->pin(1), sig->pin(0));
// 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];
netvector_t*tmp2_vec = new netvector_t(sig->data_type(),
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(scope, scope->local_symbol(),
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;
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
@ -1933,10 +1937,13 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const
// that are a delay path destination, to avoid
// the delay being applied to other drivers of
// the external signal.
if (prts[0]->delay_paths() > 0) {
isolate_and_connect(des, scope, this, prts[0], sig, ptype);
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];
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()
@ -3496,14 +3503,14 @@ NetProc* PCallTask::elaborate_sys(Design*des, NetScope*scope) const
parm.parm);
}
// Special case: Specify blocks are turned off, and this is an
// $sdf_annotate system task. There will be nothing for $sdf
// to annotate, and the user is intending to turn the behavior
// Special case: Specify blocks and interconnects are turned off,
// and this is an $sdf_annotate system task. There will be nothing for
// $sdf to annotate, and the user is intending to turn the behavior
// off anyhow, so replace the system task invocation with a no-op.
if (gn_specify_blocks_flag == false && name == "$sdf_annotate") {
if (gn_specify_blocks_flag == false && gn_interconnect_flag == false && name == "$sdf_annotate") {
cerr << get_fileline() << ": warning: Omitting $sdf_annotate() "
<< "since specify blocks are being omitted." << endl;
<< "since specify blocks and interconnects are being omitted." << endl;
NetBlock*noop = new NetBlock(NetBlock::SEQU, scope);
noop->set_line(*this);
return noop;

View File

@ -109,6 +109,7 @@ ivl_logic_scope
ivl_logic_type
ivl_logic_udp
ivl_logic_width
ivl_logic_port_buffer
ivl_lpm_array
ivl_lpm_aset_value
@ -229,6 +230,7 @@ ivl_scope_mod_module_ports
ivl_scope_mod_module_port_name
ivl_scope_mod_module_port_type
ivl_scope_mod_module_port_width
ivl_scope_mod_module_port_buffer
ivl_scope_mod_port
ivl_scope_name
ivl_scope_param

View File

@ -1112,6 +1112,7 @@ extern ivl_drive_t ivl_logic_drive0(ivl_net_logic_t net);
extern ivl_drive_t ivl_logic_drive1(ivl_net_logic_t net);
extern unsigned ivl_logic_width(ivl_net_logic_t net);
extern unsigned ivl_logic_is_cassign(ivl_net_logic_t net);
extern unsigned ivl_logic_port_buffer(ivl_net_logic_t net);
/* DEPRECATED */
extern const char* ivl_logic_attr(ivl_net_logic_t net, const char*key);
@ -1897,6 +1898,7 @@ extern unsigned ivl_scope_mod_module_ports(ivl_scope_t net);
extern const char *ivl_scope_mod_module_port_name(ivl_scope_t net, unsigned idx );
extern ivl_signal_port_t ivl_scope_mod_module_port_type(ivl_scope_t net, unsigned idx );
extern unsigned ivl_scope_mod_module_port_width(ivl_scope_t net, unsigned idx );
extern ivl_net_logic_t ivl_scope_mod_module_port_buffer(ivl_scope_t net, unsigned idx );
extern unsigned ivl_scope_ports(ivl_scope_t net);
extern ivl_signal_t ivl_scope_port(ivl_scope_t net, unsigned idx);
@ -2432,3 +2434,4 @@ _END_DECL
#undef ENUM_UNSIGNED_INT
#endif /* IVL_ivl_target_H */

12
main.cc
View File

@ -106,6 +106,7 @@ generation_t generation_flag = GN_DEFAULT;
bool gn_icarus_misc_flag = true;
bool gn_cadence_types_flag = true;
bool gn_specify_blocks_flag = true;
bool gn_interconnect_flag = true;
bool gn_supported_assertions_flag = true;
bool gn_unsupported_assertions_flag = true;
bool gn_io_range_error_flag = true;
@ -334,6 +335,12 @@ static void process_generation_flag(const char*gen)
} else if (strcmp(gen,"no-specify") == 0) {
gn_specify_blocks_flag = false;
} else if (strcmp(gen,"interconnect") == 0) {
gn_interconnect_flag = true;
} else if (strcmp(gen,"no-interconnect") == 0) {
gn_interconnect_flag = false;
} else if (strcmp(gen,"assertions") == 0) {
gn_supported_assertions_flag = true;
gn_unsupported_assertions_flag = true;
@ -1095,6 +1102,11 @@ int main(int argc, char*argv[])
else
cout << ",no-specify";
if (gn_interconnect_flag)
cout << ",interconnect";
else
cout << ",no-interconnect";
if (gn_cadence_types_flag)
cout << ",xtypes";
else

View File

@ -572,8 +572,15 @@ void NetScope::add_module_port_info( unsigned idx, perm_string name, PortType::E
info.name = name;
info.type = ptype;
info.width = width;
info.buffer = nullptr;
}
PortInfo* NetScope::get_module_port_info( unsigned idx )
{
ivl_assert(*this, type_ == MODULE);
ivl_assert(*this, ports_.size() > idx);
return &ports_[idx];
}
unsigned NetScope::module_port_nets() const
{
@ -872,3 +879,4 @@ void NetScope::add_tie_lo(Design*des)
connect(sig->pin(0), tie_lo_->pin(0));
}
}

View File

@ -1966,8 +1966,8 @@ unsigned NetSignExtend::width() const
return width_;
}
NetBUFZ::NetBUFZ(NetScope*s, perm_string n, unsigned w, bool trans)
: NetNode(s, n, 2), width_(w), transparent_(trans)
NetBUFZ::NetBUFZ(NetScope*s, perm_string n, unsigned w, bool trans, int port_info_index)
: NetNode(s, n, 2), width_(w), transparent_(trans), port_info_index_(port_info_index)
{
pin(0).set_dir(Link::OUTPUT);
pin(1).set_dir(Link::INPUT);

View File

@ -660,6 +660,7 @@ struct PortInfo
PortType::Enum type;
unsigned long width;
perm_string name;
ivl_net_logic_t buffer;
};
@ -1127,6 +1128,8 @@ class NetScope : public Definitions, public Attrib {
PortType::Enum type,
unsigned long width );
PortInfo* get_module_port_info(unsigned idx);
const std::vector<PortInfo> &module_port_info() const;
/* Scopes have their own time units and time precision. The
@ -2359,11 +2362,12 @@ class NetSubstitute : public NetNode {
class NetBUFZ : public NetNode {
public:
explicit NetBUFZ(NetScope*s, perm_string n, unsigned wid, bool transp);
explicit NetBUFZ(NetScope*s, perm_string n, unsigned wid, bool transp, int port_info_index = -1);
~NetBUFZ();
unsigned width() const;
bool transparent() const { return transparent_; }
int port_info_index() const { return port_info_index_; }
virtual void dump_node(std::ostream&, unsigned ind) const;
virtual bool emit_node(struct target_t*) const;
@ -2371,6 +2375,7 @@ class NetBUFZ : public NetNode {
private:
unsigned width_;
bool transparent_;
int port_info_index_;
};
/*

View File

@ -992,6 +992,12 @@ extern "C" unsigned ivl_logic_width(ivl_net_logic_t net)
return net->width_;
}
extern "C" unsigned ivl_logic_port_buffer(ivl_net_logic_t net)
{
assert(net);
return net->is_port_buffer;
}
extern "C" int ivl_udp_sequ(ivl_udp_t net)
{
assert(net);
@ -2315,6 +2321,11 @@ extern "C" unsigned ivl_scope_mod_module_port_width(ivl_scope_t net, unsigned id
return net->module_ports_info[idx].width;
}
extern "C" ivl_net_logic_t ivl_scope_mod_module_port_buffer(ivl_scope_t net, unsigned idx )
{
assert(net);
return (ivl_net_logic_t)net->module_ports_info[idx].buffer;
}
extern "C" unsigned ivl_scope_ports(ivl_scope_t net)
{

View File

@ -856,6 +856,7 @@ bool dll_target::bufz(const NetBUFZ*net)
obj->type_ = net->transparent()? IVL_LO_BUFT : IVL_LO_BUFZ;
obj->width_= net->width();
obj->is_cassign = 0;
obj->is_port_buffer = net->port_info_index() >= 0;
obj->npins_= 2;
obj->pins_ = new ivl_nexus_t[2];
FILE_NAME(obj, net);
@ -892,6 +893,15 @@ 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;
}
return true;
}
@ -959,6 +969,7 @@ void dll_target::logic(const NetLogic*net)
struct ivl_net_logic_s *obj = new struct ivl_net_logic_s;
obj->width_ = net->width();
obj->is_port_buffer = 0;
FILE_NAME(obj, net);
@ -1427,6 +1438,7 @@ void dll_target::udp(const NetUDP*net)
struct ivl_net_logic_s *obj = new struct ivl_net_logic_s;
obj->type_ = IVL_LO_UDP;
obj->is_port_buffer = 0;
FILE_NAME(obj, net);
/* The NetUDP class hasn't learned about width yet, so we

View File

@ -530,6 +530,7 @@ struct ivl_net_logic_s {
ivl_logic_t type_;
unsigned width_;
unsigned is_cassign;
unsigned is_port_buffer;
ivl_udp_t udp;
perm_string name_;

View File

@ -308,6 +308,9 @@ 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 (ivl_logic_port_buffer(net)) return 0;
ivl_nexus_t in_n, out_n;
unsigned idx;
@ -2405,11 +2408,14 @@ int draw_scope(ivl_scope_t net, ivl_scope_t parent)
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\";\n",
fprintf( vvp_out, " .port_info %u %s %u \"%s\"",
idx, vvp_port_info_type_str(ptype), width,
vvp_mangle_name(name) );
vvp_mangle_name(name) );
if (buffer) fprintf( vvp_out, " L_%p;\n", buffer);
else fprintf( vvp_out, ";\n");
}
}
@ -2529,3 +2535,4 @@ int draw_scope(ivl_scope_t net, ivl_scope_t parent)
ivl_scope_children(net, (ivl_scope_f*) draw_scope, net);
return 0;
}

View File

@ -46,7 +46,7 @@ void vpi_get_systf_info(vpiHandle, p_vpi_systf_data) { }
vpiHandle vpi_handle_by_name(const char*, vpiHandle) { return 0; }
vpiHandle vpi_handle_by_index(vpiHandle, PLI_INT32) { return 0; }
vpiHandle vpi_handle_multi(PLI_INT32 type, vpiHandle ref1, vpiHandle ref2) { return 0; }
vpiHandle vpi_handle_multi(PLI_INT32, vpiHandle, vpiHandle) { return 0; }
// for traversing relationships

View File

@ -514,7 +514,7 @@ extern void compile_var_queue(char*label, char*name, unsigned size);
* nets connected through module ports.
*/
extern void compile_port_info( unsigned index, int vpi_port_type, unsigned width, const char *name );
extern void compile_port_info( unsigned index, int vpi_port_type, unsigned width, const char *name, char* buffer );
/*

View File

@ -713,10 +713,13 @@ statement
/* Port information for scopes... currently this is just meta-data for VPI queries */
| K_PORT_INFO T_NUMBER port_type T_NUMBER T_STRING T_SYMBOL ';'
{ compile_port_info( $2 /* port_index */, $3, $4 /* width */,
$5 /*&name */, $6 /* buffer */ ); }
| K_PORT_INFO T_NUMBER port_type T_NUMBER T_STRING ';'
{ compile_port_info( $2 /* port_index */, $3, $4 /* width */,
$5 /*&name */ ); }
$5 /*&name */, nullptr /* buffer */ ); }
| K_TIMESCALE T_NUMBER T_NUMBER';'
{ compile_timescale($2, $3); }

View File

@ -1583,9 +1583,15 @@ void print_net_type(vvp_net_t* net1)
else if (dynamic_cast<vvp_named_event*>(net1->fun)) std::cout << "vvp_named_event*!" << std::endl;
else if (dynamic_cast<vvp_fun_bufif*>(net1->fun)) std::cout << "vvp_fun_bufif*!" << std::endl;
else if (dynamic_cast<vvp_dff*>(net1->fun)) std::cout << "vvp_dff*!" << std::endl;
else if (dynamic_cast<vvp_fun_and*>(net1->fun)) std::cout << "vvp_fun_and*!" << std::endl;
else if (dynamic_cast<vvp_fun_equiv*>(net1->fun)) std::cout << "vvp_fun_equiv*!" << std::endl;
else if (dynamic_cast<vvp_fun_impl*>(net1->fun)) std::cout << "vvp_fun_impl*!" << std::endl;
else if (dynamic_cast<vvp_fun_or*>(net1->fun)) std::cout << "vvp_fun_or*!" << std::endl;
else if (dynamic_cast<vvp_fun_xor*>(net1->fun)) std::cout << "vvp_fun_xor*!" << std::endl;
else if (dynamic_cast<vvp_fun_boolean_*>(net1->fun)) std::cout << "vvp_fun_boolean_*!" << std::endl;
else if (dynamic_cast<vvp_fun_buf*>(net1->fun)) std::cout << "vvp_fun_buf*!" << std::endl;
else if (dynamic_cast<vvp_fun_buft*>(net1->fun)) std::cout << "vvp_fun_buft*!" << std::endl;
else if (dynamic_cast<vvp_fun_bufz*>(net1->fun)) std::cout << "vvp_fun_bufz*!" << std::endl;
else if (dynamic_cast<vvp_fun_buf*>(net1->fun)) std::cout << "vvp_fun_buf*!" << std::endl;
else if (dynamic_cast<vvp_fun_muxz*>(net1->fun)) std::cout << "vvp_fun_muxz*!" << std::endl;
else if (dynamic_cast<vvp_fun_muxr*>(net1->fun)) std::cout << "vvp_fun_muxr*!" << std::endl;
else if (dynamic_cast<vvp_fun_not*>(net1->fun)) std::cout << "vvp_fun_not*!" << std::endl;
@ -1686,70 +1692,35 @@ vpiHandle vpi_handle_multi(PLI_INT32 type,
return nullptr;
}*/
std::string port_name1(vpi_get_str(vpiName, ref1));
std::string port_name2(vpi_get_str(vpiName, ref2));
vvp_net_t* net1 = port1->get_port();
vvp_net_t* net2 = port2->get_port();
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)
if (net1 == nullptr || net2 == 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;
}
fprintf(stderr, "Error: Could not find net. "
"Did you run iverilog with '-ginterconnect'?\n");
return nullptr;
}
// Find net for port2
net_i = vpi_iterate(vpiNet, mod2);
vpiHandle net_handle2 = nullptr;
while ((net=vpi_scan(net_i)) != nullptr)
if (!dynamic_cast<vvp_fun_buft*>(net1->fun))
{
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;
}
fprintf(stderr, "Error: functor of net1 must be"
"vvp_fun_buft\n");
return nullptr;
}
// 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);
if (!dynamic_cast<vvp_fun_buft*>(net2->fun))
{
fprintf(stderr, "Error: functor of net2 must be"
"vvp_fun_buft\n");
return nullptr;
}
vvp_net_t* net1 = node1->node;
vvp_net_t* net2 = node2->node;
std::cout << "net1: "; print_net_type(net1);
print_port_connections(&net1->out_);
print_net_type(net1);
print_net_type(net2);
std::cout << "net2: "; print_net_type(net2);
print_port_connections(&net2->out_);
// Debug information
@ -1767,50 +1738,35 @@ vpiHandle vpi_handle_multi(PLI_INT32 type,
//fprintf(stderr, "net1->out_.ptr() : %p\n", net1->out_.ptr()); // vvp_net_t
//fprintf(stderr, "net1->out_.port() : %d\n", net1->out_.port()); // input 3-0
// TODO don't just compare the nets, may be a problem for high fan-out nets
if (net1 == net2)
// TODO don't just compare the nets, may be a problem for high fan-out nets
if (net1 == net2 )//&& port2->get_direction() == vpiOutput)
{
fprintf(stderr, "Same net!\n");
return nullptr; // TODO
vvp_net_ptr_t* next_ptr = &net1->out_;
// TODO Problem: this only delays the output as viewed from outside
// because the net for output points to before inserted intermodpath
fprintf(stderr, "Output port!\n");
fprintf(stderr, "Port connections:\n");
// Check if there is already an intermodpath TODO
print_port_connections(next_ptr);
fprintf(stderr, "Inserting intermodpath...\n");
fprintf(stderr, "End port connections:\n");
std::cout << *next_ptr << std::endl;
vvp_net_t* next_net = next_ptr->ptr();
//assert(next_net);
if (!next_net) return 0;
print_net_type(next_net);
for (int i=0; i<4; i++)
{
fprintf(stderr, "next_net->port[%d].ptr() : %p\n", i, next_net->port[i].ptr());
fprintf(stderr, "next_net->port[%d].port() : %d\n", i, next_net->port[i].port());
if (next_net->port[i].ptr()) print_net_type(next_net->port[i].ptr());
}
// May be connected to both vvp_fun_modpath_src* and vvp_fun_bufz*!
//if (next_net->port[next_ptr->port()].ptr() == nullptr)
//{
//fprintf(stderr, "next_net is the only thing connected to net1/net2!\n");
int width = 1; // TODO
int width = 1; // TODO get width of port, check port widths are equal
vvp_net_t*new_net = new vvp_net_t;
vvp_fun_intermodpath*obj = new vvp_fun_intermodpath(new_net, width);
new_net->fun = obj;
new_net->out_= vvp_net_ptr_t(next_net,0); // point to port0 of net2
// point to where net1/net2 was pointing
vvp_net_ptr_t net1_ptr = net1->out_;
// net1/net2 points to intermodpath
net1->out_ = vvp_net_ptr_t(new_net,0);
// out of new_net should point to net2
new_net->out_= net1_ptr; // point to port0 of net2
net1->out_ = vvp_net_ptr_t(new_net,0); // point to port0 of new_net
__vpiInterModPath*intermodpath = vpip_make_intermodpath(new_net, port1, port2);
intermodpath->intermodpath = obj;
@ -1818,41 +1774,114 @@ vpiHandle vpi_handle_multi(PLI_INT32 type,
fprintf(stderr, "Inserted vvp_fun_intermodpath!\n");
return intermodpath;
//}
}
else
{
fprintf(stderr, "Different net!\n");
//vvp_fun_port* fun_port1 = dynamic_cast<vvp_fun_port*>(net1->fun);
//vvp_fun_port* fun_port2 = dynamic_cast<vvp_fun_port*>(net2->fun);
//if (!fun_port1 || !fun_port2) fprintf(stderr, "Not vvp_fun_port!\n");
vvp_net_ptr_t* net1_ptr = &net1->out_;
vvp_net_ptr_t* net2_ptr = &net2->out_;
// TODO follow whole linked list
if (net1_ptr->ptr() == net2)
fprintf(stderr, "Connected to port1:\n");
print_port_connections(net1_ptr);
fprintf(stderr, "Connected to port2:\n");
print_port_connections(net2_ptr);
// TODO first iterate over list and if functor is vvp_fun_intermodpath
// then check if output is connected to net, if so return
vvp_net_ptr_t* net_ptr = net1_ptr;
while (net_ptr)
{
vvp_net_t* next_net = net_ptr->ptr();
if (!next_net) break; // End of list
// Found a vvp_fun_intermodpath, check if port2 is connected
if (dynamic_cast<vvp_fun_intermodpath*>(next_net->fun))
{
if (next_net->out_.ptr() == net2)
{
fprintf(stderr, "Found already existing modpath!\n");
// Return the intermodpath TODO is it correct to create a new object?
// or add reference to __vpiInterModPath from vvp_fun_intermodpath
__vpiInterModPath*intermodpath = vpip_make_intermodpath(next_net, port1, port2);
return intermodpath;
}
}
net_ptr = &next_net->port[net_ptr->port()];
}
// Iterate over linked list until port2 is found
net_ptr = net1_ptr;
vvp_net_ptr_t previous_net_ptr = vvp_net_ptr_t(nullptr, 0);
vvp_net_t* previous_net = net1;
while (net_ptr)
{
vvp_net_t* next_net = net_ptr->ptr();
if (!next_net) break; // End of list
if (next_net == net2) break; // Found net2
previous_net_ptr = *net_ptr;
net_ptr = &next_net->port[net_ptr->port()];
}
if (!net_ptr->ptr()) return 0;
fprintf(stderr, "Net2 connected to net1!\n");
fprintf(stderr, "%p\n", previous_net);
fprintf(stderr, "Inserting intermodpath...\n");
int width = 1; // TODO get width of port, check port widths are equal
vvp_net_t*new_net = new vvp_net_t;
vvp_fun_intermodpath*obj = new vvp_fun_intermodpath(new_net, width);
new_net->fun = obj;
// point to where net2 was pointing
new_net->port[0] = net_ptr->ptr()->port[net_ptr->port()];
// Directly connected to port1
if (!previous_net_ptr.ptr())
{
fprintf(stderr, "But net1 connected to net2!\n");
if (net2->port[net1_ptr->port()].ptr() == nullptr)
{
fprintf(stderr, "Net2 is the only thing connected to net1!\n");
int width = 1; // TODO
vvp_net_t*new_net = new vvp_net_t;
vvp_fun_intermodpath*obj = new vvp_fun_intermodpath(new_net, width);
new_net->fun = obj;
new_net->out_= vvp_net_ptr_t(net2,0); // point to port0 of net2
net1->out_ = vvp_net_ptr_t(new_net,0); // point to port0 of new_net
__vpiInterModPath*intermodpath = vpip_make_intermodpath(new_net, port1, port2);
intermodpath->intermodpath = obj;
fprintf(stderr, "Inserted vvp_fun_intermodpath!\n");
return intermodpath;
}
net1->out_ = vvp_net_ptr_t(new_net,0);
}
else
{
// what pointed to net2 should point to new_net
previous_net_ptr.ptr()->port[previous_net_ptr.port()] = vvp_net_ptr_t(new_net,0);
}
// out of new_net should point to net2
new_net->out_= vvp_net_ptr_t(net2,0); // point to port0 of net2
__vpiInterModPath*intermodpath = vpip_make_intermodpath(new_net, port1, port2);
intermodpath->intermodpath = obj;
fprintf(stderr, "Inserted vvp_fun_intermodpath!\n");
fprintf(stderr, "Connected to port1:\n");
print_port_connections(net1_ptr);
fprintf(stderr, "Connected to port2:\n");
print_port_connections(net2_ptr);
return intermodpath;
}
std::cout << "sorry: Could not insert intermodpath!" << std::endl;
return nullptr;

View File

@ -439,7 +439,8 @@ class vpiPortInfo : public __vpiHandle {
unsigned index,
int vpi_direction,
unsigned width,
const char *name );
const char *name,
char* buffer );
~vpiPortInfo();
int get_type_code(void) const { return vpiPort; }
@ -448,6 +449,7 @@ class vpiPortInfo : public __vpiHandle {
int vpi_get(int code);
char* vpi_get_str(int code);
vpiHandle vpi_handle(int code);
vvp_net_t* get_port(void) const { return ref_; }
private:
__vpiScope *parent_;
@ -455,6 +457,7 @@ class vpiPortInfo : public __vpiHandle {
int direction_;
unsigned width_;
const char *name_;
vvp_net_t *ref_;
};
/*

View File

@ -666,13 +666,16 @@ vpiPortInfo::vpiPortInfo( __vpiScope *parent,
unsigned index,
int vpi_direction,
unsigned width,
const char *name ) :
const char *name,
char* buffer) :
parent_(parent),
index_(index),
direction_(vpi_direction),
width_(width),
name_(name)
{
if (buffer != nullptr) functor_ref_lookup(&ref_, buffer);
else ref_ = nullptr;
}
vpiPortInfo::~vpiPortInfo()
@ -737,9 +740,9 @@ vpiHandle vpiPortInfo::vpi_handle(int code)
* code-generators etc. There are no actual nets corresponding to instances of module ports
* as elaboration directly connects nets connected through module ports.
*/
void compile_port_info( unsigned index, int vpi_direction, unsigned width, const char *name )
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 );
index, vpi_direction, width, name, buffer );
vpip_attach_to_current_scope(obj);
}