diff --git a/vvp/vpi_priv.cc b/vvp/vpi_priv.cc index 8a7cb16a7..39b8aee44 100644 --- a/vvp/vpi_priv.cc +++ b/vvp/vpi_priv.cc @@ -1564,90 +1564,6 @@ vpiHandle vpi_handle_by_name(const char *name, vpiHandle scope) return out; } -void print_net_type(vvp_net_t* net1) -{ - if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_delay*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_modpath*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_modpath_src*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_part_pv*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_part_var*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_arith_*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_arith_abs*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_arith_cast_int*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_arith_cast_real*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_arith_cast_vec2*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_arith_real_*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_edge*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_anyedge*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_event_or*!" << std::endl; - 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_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; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_concat*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_concat8*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_force*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_repeat*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_drive*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_extend_signed*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_wide_fun_core*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_wide_fun_t*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_signal_vec*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_signal_real*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_signal_string*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_signal_object*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_signal_base*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "resolv_core*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "resolv_extend*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_latch*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_pmos_*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_cmos_*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_island_port*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_intermodpath*!" << std::endl; - - //else if (dynamic_cast(net1->fun)) std::cout << "vvp_reduce_base*!" << std::endl; - //else if (dynamic_cast(net1->fun)) std::cout << "vvp_reduce_and*!" << std::endl; - //else if (dynamic_cast(net1->fun)) std::cout << "vvp_reduce_or*!" << std::endl; - //else if (dynamic_cast(net1->fun)) std::cout << "vvp_reduce_xor*!" << std::endl; - //else if (dynamic_cast(net1->fun)) std::cout << "vvp_reduce_nand*!" << std::endl; - //else if (dynamic_cast(net1->fun)) std::cout << "vvp_reduce_nor*!" << std::endl; - //else if (dynamic_cast(net1->fun)) std::cout << "vvp_reduce_xnor*!" << std::endl; - - else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_part*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_part_sa*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_part_aa*!" << std::endl; - - //else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_substitute*!" << std::endl; - //else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_arrayport*!" << std::endl; - //else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_arrayport_sa*!" << std::endl; - //else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_arrayport_aa*!" << std::endl; - - else std::cout << "unknown!" << std::endl; -} - -void print_port_connections(vvp_net_ptr_t* net_ptr) -{ - vvp_net_t* next_net = net_ptr->ptr(); - if (!next_net) return; - - print_net_type(next_net); - vvp_net_ptr_t* next_net_ptr = &next_net->port[net_ptr->port()]; - - print_port_connections(next_net_ptr); -} - - // Used to get intermodpath for two ports vpiHandle vpi_handle_multi(PLI_INT32 type, vpiHandle ref1, @@ -1660,7 +1576,7 @@ vpiHandle vpi_handle_multi(PLI_INT32 type, if (type != vpiInterModPath) { fprintf(stderr, "sorry: vpi_handle_multi currently supports" - "only vpiInterModPath\n"); + "only vpiInterModPath\n"); return nullptr; } @@ -1680,24 +1596,32 @@ vpiHandle vpi_handle_multi(PLI_INT32 type, return nullptr; } - bool is_output = false; + // 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) { - std::cout << "OUTPUT!!!" << std::endl; - is_output = true; - } + vpiHandle scope_port2 = vpi_handle(vpiScope, ref2); + assert(scope_port2); + std::string port2_name(vpi_get_str(vpiName, ref2)); - /*if (!(port1->get_direction() == vpiOutput || port1->get_direction() == vpiInout)) { - fprintf(stderr, "ERROR: First vpiPort must be an output" - " or bidirectional port\n"); - return nullptr; - } + // Iterate over nets in the scope of port2 + vpiHandle net_i = vpi_iterate(vpiNet, scope_port2) ; + vpiHandle net; - if (!(port2->get_direction() == vpiInput || port2->get_direction() == vpiInout)) { - fprintf(stderr, "ERROR: Second vpiPort must be an input" - " or bidirectional port\n"); - return nullptr; - }*/ + 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); + } + } + } vvp_net_t* net1 = port1->get_port(); vvp_net_t* net2 = port2->get_port(); @@ -1709,6 +1633,13 @@ vpiHandle vpi_handle_multi(PLI_INT32 type, 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(net1->fun)) { fprintf(stderr, "Error: functor of net1 must be" @@ -1723,156 +1654,59 @@ vpiHandle vpi_handle_multi(PLI_INT32 type, return nullptr; } - std::cout << "net1: "; print_net_type(net1); - print_port_connections(&net1->out_); + // 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); - std::cout << "net2: "; print_net_type(net2); - print_port_connections(&net2->out_); - - // Debug information - - for (int i=0; i<4; i++) + while (cur.ptr()) { - fprintf(stderr, "net1->port[%d].ptr() : %p\n", i, net1->port[i].ptr()); - fprintf(stderr, "net1->port[%d].port() : %d\n", i, net1->port[i].port()); + // Port2 is directly connected to port1 + 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 + + // 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; + } + + // 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; + } + + prev = cur; + cur = cur.ptr()->port[cur.port()]; // Next net in linked list } - fprintf(stderr, "net1->fun : %p\n", net1->fun); - fprintf(stderr, "net1->fil : %p\n", net1->fil); - - fprintf(stderr, "net1->fil->filter_size() : %d\n", net1->fil->filter_size()); - - //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 )//&& port2->get_direction() == vpiOutput) - { - fprintf(stderr, "Same net!\n"); - return nullptr; // TODO - - // 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"); - - // Check if there is already an intermodpath TODO - - 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 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 - - - __vpiInterModPath*intermodpath = vpip_make_intermodpath(new_net, port1, port2); - intermodpath->intermodpath = obj; - - 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_; - - 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()]; - } - - // Verify if port2 is connected to port1 - vvp_net_t* current_net = net1_ptr->ptr(); - - while (current_net) - { - if (!current_net) break; // End of list - - if (current_net == net2) - { - std::cout << "Found net2!" << std::endl; - - // Ol switcheroo - vvp_net_fun_t* net2_functor = net2->fun; - - int width = 1; // TODO - vvp_fun_intermodpath*obj = new vvp_fun_intermodpath(net2, width); - net2->fun = obj; - - vvp_net_t*new_net = new vvp_net_t; - new_net->fun = net2_functor; - //net2_functor->net = new_net; - - new_net->out_ = net2->out_; - net2->out_ = vvp_net_ptr_t(new_net, 0); - - - __vpiInterModPath*intermodpath = vpip_make_intermodpath(net2, 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; - } - current_net = current_net->port[0].ptr(); // BUFT has only one input, index 0 - } - - std::cout << "Could not find net2!" << std::endl; - - } std::cout << "sorry: Could not insert intermodpath!" << std::endl; return nullptr; }