From 7c60005d1ae96e4d79e0db1b31d0e8590eeb96d4 Mon Sep 17 00:00:00 2001 From: Michael Kupfer Date: Fri, 6 Jun 2025 17:34:09 +0200 Subject: [PATCH] Improve INTERCONNECT handling for SDF Annotation Improve path search between nets, so that paths containing concats as well as part selects can be found. Signed-off-by: Michael Kupfer --- vvp/vpi_priv.cc | 81 +++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 65 insertions(+), 16 deletions(-) diff --git a/vvp/vpi_priv.cc b/vvp/vpi_priv.cc index 27fe86210..e1016e787 100644 --- a/vvp/vpi_priv.cc +++ b/vvp/vpi_priv.cc @@ -1574,34 +1574,66 @@ vpiHandle vpi_handle_by_name(const char *name, vpiHandle scope) return out; } -// Check if net2 is connected to current_net through a net of vvp_fun_concat8s -bool check_connected_to_concat8(vvp_net_t* current_net, vvp_net_t* net2) -{ - if (!dynamic_cast(current_net->fun)) return false; +// Return tuple {x1, x2, x3} with: +// x1: True when cur and net2 are connected +// x2: Ptr to previous node +// x3: True when net is connected to output of previous node +tuple check_connected_to_concat8_and_part_sa(vvp_net_ptr_t cur, vvp_net_t* net2, vvp_net_ptr_t parent) { - vvp_net_ptr_t cur = current_net->out_; + vvp_net_ptr_t prev = vvp_net_ptr_t(nullptr, 0); - // For everything connected while (cur.ptr()) { - // Check if it's a concat8 - if (dynamic_cast(cur.ptr()->fun)) { + if (cur.ptr() == net2 && dynamic_cast(parent.ptr()->fun)) { // Pass on the return value if found - if (check_connected_to_concat8(cur.ptr(), net2)) { - return true; + return {true, prev.ptr() ? prev : parent, prev.ptr() == nullptr}; + } else if (dynamic_cast(cur.ptr()->fun) || dynamic_cast(cur.ptr()->fun) || dynamic_cast(cur.ptr()->fun)) { + auto res = check_connected_to_concat8_and_part_sa(cur.ptr()->out_, net2, cur); + if (get<0>(res)) { + return res; } } - // net2 is connected + // Next net in linked list + prev = cur; + cur = cur.ptr()->port[cur.port()]; + } + + // net2 is not connected to this concat8 + return {false, vvp_net_ptr_t(nullptr, 0), false}; +} + +// Check if net2 is connected to current_net through a net of vvp_fun_concat8s +// Return tuple {x1, x2, x3} with: +// x1: True when cur and net2 are connected with concats and part_sas +// x2: Ptr to previous node +// x3: True when net is connected to output of x2 +tuple check_connected_to_concat8(vvp_net_ptr_t cur, vvp_net_t* net2, vvp_net_ptr_t parent) +{ + vvp_net_ptr_t prev = vvp_net_ptr_t(nullptr, 0); + // For everything connected + while (cur.ptr()) { + // Check if it's a concat8 if (cur.ptr() == net2) { - return true; + return {true, vvp_net_ptr_t(nullptr, 0), false}; + } else if (dynamic_cast(cur.ptr()->fun) || dynamic_cast(cur.ptr()->fun) || dynamic_cast(cur.ptr()->fun)) { + auto res = check_connected_to_concat8(cur.ptr()->out_, net2, cur); + if (get<0>(res)) { + if (!get<1>(res).ptr() && dynamic_cast(parent.ptr()->fun)) { + // `parent` is the last part_sa node in front of our destination + // We want to place the intermod node here + return {true, prev.ptr() ? prev : parent, prev.ptr() == nullptr}; + } + return res; + } } // Next net in linked list + prev = cur; cur = cur.ptr()->port[cur.port()]; } // net2 is not connected to this concat8 - return false; + return {false, vvp_net_ptr_t(nullptr, 0), false}; } // Used to get intermodpath for two ports @@ -1751,13 +1783,30 @@ vpiHandle vpi_handle_multi(PLI_INT32 type, // Either port2 is directly connected to port1 // Or in the second case port2 is indirectly connected // to port1 through a net of concat8s - if ( (!port2_has_index && cur.ptr() == net2) || - ( port2_has_index && check_connected_to_concat8(cur.ptr(), net2))) { + bool is_connected, is_output; + vvp_net_ptr_t previous_node; + tie(is_connected, previous_node, is_output) = port2_has_index + ? check_connected_to_concat8(cur, net2, vvp_net_ptr_t(net1, 0)) + : check_connected_to_concat8_and_part_sa(cur, net2, vvp_net_ptr_t(net1, 0)); + if ( (!port2_has_index && cur.ptr() == net2) || is_connected ) { vvp_net_t*new_net = new vvp_net_t; // 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); + + vvp_net_t* output_net = net1; + if (is_connected) { + if (is_output) { + output_net = previous_node.ptr(); // net2 is direct output of part_sa + cur = output_net->out_; + prev = vvp_net_ptr_t(nullptr, 0); + } else { + prev = previous_node; + cur = prev.ptr()->port[prev.port()]; + } + } + new_net->fun = obj; new_net->out_ = cur; @@ -1770,7 +1819,7 @@ vpiHandle vpi_handle_multi(PLI_INT32 type, // 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 + output_net->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 }