diff --git a/openfpga/src/repack/lb_router.cpp b/openfpga/src/repack/lb_router.cpp index e37c7fcdc..f7be853b1 100644 --- a/openfpga/src/repack/lb_router.cpp +++ b/openfpga/src/repack/lb_router.cpp @@ -244,17 +244,6 @@ bool LbRouter::try_route_net(const LbRRGraph& lb_rr_graph, /* Route each sink of net */ for (size_t isink = 0; isink < lb_net_sinks_[net_idx].size(); ++isink) { - /* Do not route the sink if it share the same pb_type as source - * This is actually forbidden! This will definitely create a combinational loop - */ - if ( (nullptr != lb_rr_graph.node_pb_graph_pin(lb_net_sinks_[net_idx][isink])) - && (nullptr != lb_rr_graph.node_pb_graph_pin(lb_net_sources_[net_idx][isrc])) ) { - if (lb_rr_graph.node_pb_graph_pin(lb_net_sinks_[net_idx][isink])->parent_node - == lb_rr_graph.node_pb_graph_pin(lb_net_sources_[net_idx][isrc])->parent_node) { - continue; - } - } - /* Skip routed nets */ if (true == sink_routed[isink]) { continue; @@ -585,11 +574,6 @@ void LbRouter::commit_remove_rt(const LbRRGraph& lb_rr_graph, explored_node_tb_[inode].inet = NetId::INVALID(); } - if (op == RT_COMMIT) { - VTR_LOGV(lb_rr_graph.node_pb_graph_pin(inode), - "Commit node '%s' to routing tree\n", - lb_rr_graph.node_pb_graph_pin(inode)->to_string().c_str()); - } routing_status_[inode].occ += incr; VTR_ASSERT(routing_status_[inode].occ >= 0); diff --git a/openfpga/src/repack/repack.cpp b/openfpga/src/repack/repack.cpp index 417cb6b95..2d0b2c3e8 100644 --- a/openfpga/src/repack/repack.cpp +++ b/openfpga/src/repack/repack.cpp @@ -21,15 +21,100 @@ namespace openfpga { /*************************************************************************************** - * Try find the pin id which is mapped to a given atom net id in the context of pb route + * Try find all the sink pins which is mapped to a routing trace in the context of pb route + * This function uses a recursive walk-through over the pb_route + * We will always start from the pb_route of the source pin + * For each sink, + * - if it is the end point of a routing tree, we add it to the sink list + * - An output of top-level pb_graph_node + * - An input of a primitive pb_graph_node + * - if it is not the end point of a routing tree, we visit the pb_route + * corresponds to the sink pin + * + * Note: when you call this function at the top-level, please provide an empty vector + * of sink_pb_pins!!! + ***************************************************************************************/ +static +void rec_find_routed_sink_pb_graph_pins(const t_pb* pb, + const t_pb_graph_pin* source_pb_pin, + const AtomNetId& atom_net_id, + t_pb_graph_pin** pb_graph_pin_lookup_from_index, + std::vector& sink_pb_pins) { + + /* Bypass unused pins */ + if (0 == pb->pb_route.count(source_pb_pin->pin_count_in_cluster)) { + return; + } + + /* Get the driver pb pin id, it must be valid */ + if (atom_net_id != pb->pb_route[source_pb_pin->pin_count_in_cluster].atom_net_id) { + return; + } + + /* Check each sink nodes, if pin belongs to an input of a primitive pb_graph_node, it is what we want */ + std::vector sink_pb_pins_to_search; + for (const int& sink_pb_pin_id : pb->pb_route[source_pb_pin->pin_count_in_cluster].sink_pb_pin_ids) { + t_pb_graph_pin* sink_pb_pin = pb_graph_pin_lookup_from_index[sink_pb_pin_id]; + VTR_ASSERT(nullptr != sink_pb_pin); + + /* We will update sink node list only + * - input pins of primitive nodes + * - output pins of top node + */ + if ( (true == is_primitive_pb_type(sink_pb_pin->parent_node->pb_type)) + && (IN_PORT == sink_pb_pin->port->type)) { + sink_pb_pins.push_back(sink_pb_pin); + continue; + } + + if ( (true == sink_pb_pin->parent_node->is_root()) + && (OUT_PORT == sink_pb_pin->port->type)) { + sink_pb_pins.push_back(sink_pb_pin); + continue; + } + + /* We should find the pb_route recursively */ + sink_pb_pins_to_search.push_back(sink_pb_pin); + } + + for (t_pb_graph_pin* sink_pb_pin : sink_pb_pins_to_search) { + rec_find_routed_sink_pb_graph_pins(pb, sink_pb_pin, atom_net_id, pb_graph_pin_lookup_from_index, sink_pb_pins); + } +} + +/*************************************************************************************** + * A wrapper for the recursive function rec_find_route_sink_pb_graph_pins(), + * we ensure that we provide a clear sink node lists ***************************************************************************************/ static std::vector find_routed_pb_graph_pins_atom_net(const t_pb* pb, + const t_pb_graph_pin* source_pb_pin, const AtomNetId& atom_net_id, t_pb_graph_pin** pb_graph_pin_lookup_from_index) { std::vector sink_pb_pins; - /* Find the sink nodes from top-level node */ + rec_find_routed_sink_pb_graph_pins(pb, source_pb_pin, atom_net_id, pb_graph_pin_lookup_from_index, sink_pb_pins); + + return sink_pb_pins; +} + +/*************************************************************************************** + * This function will find the actual source_pb_pin that is mapped by packed in the pb route + * As the inputs of clustered block may be renamed during routing, + * our pb_route results may lose consistency. + * It is possible that the source pb_pin may not be mapped during packing but + * be mapped during routing + * + * Note: this is ONLY applicable to the pb_pin of top-level pb_graph_node + ***************************************************************************************/ +static +int find_pb_route_remapped_source_pb_pin(const t_pb* pb, + const t_pb_graph_pin* source_pb_pin, + const AtomNetId& atom_net_id) { + VTR_ASSERT(true == source_pb_pin->parent_node->is_root()); + + std::vector pb_route_indices; + for (int pin = 0; pin < pb->pb_graph_node->total_pb_pins; ++pin) { /* Bypass unused pins */ if ((0 == pb->pb_route.count(pin)) || (AtomNetId::INVALID() == pb->pb_route[pin].atom_net_id)) { @@ -39,27 +124,15 @@ std::vector find_routed_pb_graph_pins_atom_net(const t_pb* pb, if (atom_net_id != pb->pb_route[pin].atom_net_id) { continue; } - /* Check each sink nodes, if pin belongs to an input of a primitive pb_graph_node, it is what we want */ - for (const int& sink_pb_pin_id : pb->pb_route[pin].sink_pb_pin_ids) { - t_pb_graph_pin* sink_pb_pin = pb_graph_pin_lookup_from_index[sink_pb_pin_id]; - VTR_ASSERT(nullptr != sink_pb_pin); - /* We care only - * - input pins of primitive nodes - * - output pins of top node - */ - if ( (true == is_primitive_pb_type(sink_pb_pin->parent_node->pb_type)) - && (IN_PORT == sink_pb_pin->port->type)) { - sink_pb_pins.push_back(sink_pb_pin); - } - - if ( (true == sink_pb_pin->parent_node->is_root()) - && (OUT_PORT == sink_pb_pin->port->type)) { - sink_pb_pins.push_back(sink_pb_pin); - } - } + /* Only care the pin that shares the same parent_node as source_pb_pin */ + if (source_pb_pin->parent_node == pb->pb_route[pin].pb_graph_pin->parent_node) { + pb_route_indices.push_back(pin); + } } - return sink_pb_pins; + VTR_ASSERT(1 == pb_route_indices.size()); + + return pb_route_indices[0]; } /*************************************************************************************** @@ -154,6 +227,9 @@ void add_lb_router_nets(LbRouter& lb_router, */ std::map, 2>> net_terminals; + /* A list showing that some sinks should be touched by some sources in a multi-source net */ + std::map>> invisible_sinks; + /* Find the source nodes for the nets mapped to inputs of a clustered block */ for (int j = 0; j < lb_type->pb_type->num_pins; j++) { /* Find the net mapped to this pin in clustering results*/ @@ -185,31 +261,36 @@ void add_lb_router_nets(LbRouter& lb_router, AtomNetId atom_net_id = atom_ctx.lookup.atom_net(cluster_net_id); VTR_ASSERT(AtomNetId::INVALID() != atom_net_id); + + int pb_route_index = find_pb_route_remapped_source_pb_pin(pb, source_pb_pin, atom_net_id); + t_pb_graph_pin* packing_source_pb_pin = get_pb_graph_node_pin_from_block_pin(block_id, pb_route_index); + VTR_ASSERT(nullptr != packing_source_pb_pin); + /* Find all the sink pins in the pb_route, we walk through the input pins and find the pin */ - std::vector sink_pb_graph_pins = find_routed_pb_graph_pins_atom_net(pb, atom_net_id, pb_graph_pin_lookup_from_index); + std::vector sink_pb_graph_pins = find_routed_pb_graph_pins_atom_net(pb, packing_source_pb_pin, atom_net_id, pb_graph_pin_lookup_from_index); std::vector sink_lb_rr_nodes = find_lb_net_physical_sink_lb_rr_nodes(lb_rr_graph, sink_pb_graph_pins, device_annotation); VTR_ASSERT(sink_lb_rr_nodes.size() == sink_pb_graph_pins.size()); - /* Cache the net */ - if (0 < net_terminals.count(atom_net_id)) { - if (net_terminals[atom_net_id][0].end() == std::find(net_terminals[atom_net_id][0].begin(), - net_terminals[atom_net_id][0].end(), - source_lb_rr_node)) { - net_terminals[atom_net_id][0].push_back(source_lb_rr_node); - } - - for (const LbRRNodeId& sink_lb_rr_node : sink_lb_rr_nodes) { - if (net_terminals[atom_net_id][1].end() == std::find(net_terminals[atom_net_id][1].begin(), - net_terminals[atom_net_id][1].end(), - sink_lb_rr_node)) { - net_terminals[atom_net_id][1].push_back(sink_lb_rr_node); - } - } - } else { - net_terminals[atom_net_id][0].push_back(source_lb_rr_node); - net_terminals[atom_net_id][1] = sink_lb_rr_nodes; - net_counter++; + /* Printf for debugging only, may be enabled if verbose is enabled + VTR_LOG("Pb route for Net %s:\n", + atom_ctx.nlist.net_name(atom_net_id).c_str()); + VTR_LOG("Source node:\n\t%s -> %s\n", + source_pb_pin->to_string().c_str(), + source_pb_pin->to_string().c_str()); + VTR_LOG("Sink nodes:\n"); + for (t_pb_graph_pin* sink_pb_pin : sink_pb_graph_pins) { + VTR_LOG("\t%s\n", + sink_pb_pin->to_string().c_str()); } + */ + + /* Add the net */ + add_lb_router_net_to_route(lb_router, lb_rr_graph, + std::vector(1, source_lb_rr_node), + sink_lb_rr_nodes, + atom_ctx, atom_net_id); + + net_counter++; } /* Find the source nodes for the nets mapped to outputs of primitive pb_graph_node */ @@ -248,58 +329,35 @@ void add_lb_router_nets(LbRouter& lb_router, VTR_ASSERT(AtomNetId::INVALID() != atom_net_id); /* Find all the sink pins in the pb_route */ - std::vector sink_pb_graph_pins = find_routed_pb_graph_pins_atom_net(pb, atom_net_id, pb_graph_pin_lookup_from_index); + std::vector sink_pb_graph_pins = find_routed_pb_graph_pins_atom_net(pb, source_pb_pin, atom_net_id, pb_graph_pin_lookup_from_index); + std::vector sink_lb_rr_nodes = find_lb_net_physical_sink_lb_rr_nodes(lb_rr_graph, sink_pb_graph_pins, device_annotation); VTR_ASSERT(sink_lb_rr_nodes.size() == sink_pb_graph_pins.size()); - /* Cache the net */ - if (0 < net_terminals.count(atom_net_id)) { - if (net_terminals[atom_net_id][0].end() == std::find(net_terminals[atom_net_id][0].begin(), - net_terminals[atom_net_id][0].end(), - source_lb_rr_node)) { - net_terminals[atom_net_id][0].push_back(source_lb_rr_node); - } - - for (const LbRRNodeId& sink_lb_rr_node : sink_lb_rr_nodes) { - if (net_terminals[atom_net_id][1].end() == std::find(net_terminals[atom_net_id][1].begin(), - net_terminals[atom_net_id][1].end(), - sink_lb_rr_node)) { - net_terminals[atom_net_id][1].push_back(sink_lb_rr_node); - } - } - } else { - net_terminals[atom_net_id][0].push_back(source_lb_rr_node); - net_terminals[atom_net_id][1] = sink_lb_rr_nodes; - net_counter++; + /* Printf for debugging only, may be enabled if verbose is enabled + VTR_LOG("Pb route for Net %s:\n", + atom_ctx.nlist.net_name(atom_net_id).c_str()); + VTR_LOG("Source node:\n\t%s -> %s\n", + source_pb_pin->to_string().c_str(), + physical_source_pb_pin->to_string().c_str()); + VTR_LOG("Sink nodes:\n"); + for (t_pb_graph_pin* sink_pb_pin : sink_pb_graph_pins) { + VTR_LOG("\t%s\n", + sink_pb_pin->to_string().c_str()); } + */ + + /* Add the net */ + add_lb_router_net_to_route(lb_router, lb_rr_graph, + std::vector(1, source_lb_rr_node), + sink_lb_rr_nodes, + atom_ctx, atom_net_id); + net_counter++; } /* Free */ free_pb_graph_pin_lookup_from_index(pb_graph_pin_lookup_from_index); - /* Add all the nets */ - for (std::pair, 2>> net_terminal_pair : net_terminals) { - const AtomNetId& atom_net_id = net_terminal_pair.first; - - /* MUST have >1 source nodes and >1 sinks nodes */ - if (0 == net_terminal_pair.second[0].size()) { - VTR_LOGF_ERROR(__FILE__, __LINE__, - "Net '%s' has 0 source nodes!", - atom_ctx.nlist.net_name(atom_net_id).c_str()); - } - - if (0 == net_terminal_pair.second[1].size()) { - VTR_LOGF_ERROR(__FILE__, __LINE__, - "Net '%s' has 0 sink nodes!", - atom_ctx.nlist.net_name(atom_net_id).c_str()); - } - - /* Add the net */ - add_lb_router_net_to_route(lb_router, lb_rr_graph, - net_terminal_pair.second[0], net_terminal_pair.second[1], - atom_ctx, atom_net_id); - } - VTR_LOGV(verbose, "Added %lu nets to be routed.\n", net_counter);