From 6d3e2bf3448efcdcd55ac9e0aefa6a344abc38c4 Mon Sep 17 00:00:00 2001 From: mole99 Date: Tue, 8 Aug 2023 11:42:15 +0200 Subject: [PATCH] Improve SDF interconnect support, add -ginterconnect flag --- compiler.h | 5 + driver/iverilog.man.in | 8 ++ driver/main.c | 9 ++ elaborate.cc | 51 ++++---- ivl.def | 2 + ivl_target.h | 3 + main.cc | 12 ++ net_scope.cc | 8 ++ netlist.cc | 4 +- netlist.h | 7 +- t-dll-api.cc | 11 ++ t-dll.cc | 12 ++ t-dll.h | 1 + tgt-vvp/vvp_scope.c | 11 +- vpi_modules.cc | 2 +- vvp/compile.h | 2 +- vvp/parse.y | 7 +- vvp/vpi_priv.cc | 257 +++++++++++++++++++++++------------------ vvp/vpi_priv.h | 5 +- vvp/vpi_scope.cc | 9 +- 20 files changed, 277 insertions(+), 149 deletions(-) diff --git a/compiler.h b/compiler.h index 11491baf4..307589aad 100644 --- a/compiler.h +++ b/compiler.h @@ -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; diff --git a/driver/iverilog.man.in b/driver/iverilog.man.in index 74935a542..3e70a44cd 100644 --- a/driver/iverilog.man.in +++ b/driver/iverilog.man.in @@ -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 diff --git a/driver/main.c b/driver/main.c index d3eba6bb0..546cd1cfc 100644 --- a/driver/main.c +++ b/driver/main.c @@ -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); diff --git a/elaborate.cc b/elaborate.cc index 16c482f12..ed7bc1419 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -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; diff --git a/ivl.def b/ivl.def index 630a10cc1..867d832f4 100644 --- a/ivl.def +++ b/ivl.def @@ -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 diff --git a/ivl_target.h b/ivl_target.h index 7f551aa72..b33ea9aa4 100644 --- a/ivl_target.h +++ b/ivl_target.h @@ -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 */ + diff --git a/main.cc b/main.cc index 057b70ac2..0f3763b28 100644 --- a/main.cc +++ b/main.cc @@ -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 diff --git a/net_scope.cc b/net_scope.cc index ba8c3577d..9fac014e8 100644 --- a/net_scope.cc +++ b/net_scope.cc @@ -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)); } } + diff --git a/netlist.cc b/netlist.cc index 561701b32..732df78e5 100644 --- a/netlist.cc +++ b/netlist.cc @@ -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); diff --git a/netlist.h b/netlist.h index ff5854da4..04aed1699 100644 --- a/netlist.h +++ b/netlist.h @@ -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 &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_; }; /* diff --git a/t-dll-api.cc b/t-dll-api.cc index 50cb6a2eb..17ff59b3d 100644 --- a/t-dll-api.cc +++ b/t-dll-api.cc @@ -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) { diff --git a/t-dll.cc b/t-dll.cc index b009f14f8..85600143e 100644 --- a/t-dll.cc +++ b/t-dll.cc @@ -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 diff --git a/t-dll.h b/t-dll.h index 909ab5e94..15f727117 100644 --- a/t-dll.h +++ b/t-dll.h @@ -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_; diff --git a/tgt-vvp/vvp_scope.c b/tgt-vvp/vvp_scope.c index e8e4e4ec5..9becbab24 100644 --- a/tgt-vvp/vvp_scope.c +++ b/tgt-vvp/vvp_scope.c @@ -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; } + diff --git a/vpi_modules.cc b/vpi_modules.cc index cb7b0eb9f..ab8f86f7c 100644 --- a/vpi_modules.cc +++ b/vpi_modules.cc @@ -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 diff --git a/vvp/compile.h b/vvp/compile.h index 76befa6d6..57cdf3e4d 100644 --- a/vvp/compile.h +++ b/vvp/compile.h @@ -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 ); /* diff --git a/vvp/parse.y b/vvp/parse.y index 1224fa21a..2f5ed3c95 100644 --- a/vvp/parse.y +++ b/vvp/parse.y @@ -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); } diff --git a/vvp/vpi_priv.cc b/vvp/vpi_priv.cc index 115d6fe61..1cbbdae4f 100644 --- a/vvp/vpi_priv.cc +++ b/vvp/vpi_priv.cc @@ -1583,9 +1583,15 @@ void print_net_type(vvp_net_t* net1) else if (dynamic_cast(net1->fun)) std::cout << "vvp_named_event*!" << std::endl; else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_bufif*!" << std::endl; else if (dynamic_cast(net1->fun)) std::cout << "vvp_dff*!" << std::endl; + else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_and*!" << std::endl; + else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_equiv*!" << std::endl; + else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_impl*!" << std::endl; + else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_or*!" << std::endl; + else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_xor*!" << std::endl; else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_boolean_*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_buf*!" << std::endl; + else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_buft*!" << std::endl; else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_bufz*!" << std::endl; + else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_buf*!" << std::endl; else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_muxz*!" << std::endl; else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_muxr*!" << std::endl; else if (dynamic_cast(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(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(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(net1->fun); + //vvp_fun_port* fun_port2 = dynamic_cast(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(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; diff --git a/vvp/vpi_priv.h b/vvp/vpi_priv.h index 842c2874b..3ebaa820e 100644 --- a/vvp/vpi_priv.h +++ b/vvp/vpi_priv.h @@ -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_; }; /* diff --git a/vvp/vpi_scope.cc b/vvp/vpi_scope.cc index 2057abbac..5b660e486 100644 --- a/vvp/vpi_scope.cc +++ b/vvp/vpi_scope.cc @@ -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); }