Skip to content

Commit 796f652

Browse files
authored
Merge pull request #2867 from verilog-to-routing/fix-flat-bitgen
More fixes to sync_netlists_to_routing_flat
2 parents 96f605c + b79a174 commit 796f652

11 files changed

+147
-63
lines changed

vpr/src/base/netlist_writer.cpp

+4-1
Original file line numberDiff line numberDiff line change
@@ -1275,7 +1275,10 @@ class NetlistWriterVisitor : public NetlistVisitor {
12751275

12761276
//Add the single output connection
12771277
{
1278-
auto atom_net_id = top_pb_route[sink_cluster_pin_idx].atom_net_id; //Connected net in atom netlist
1278+
/* Check if the output is connected */
1279+
AtomNetId atom_net_id = AtomNetId::INVALID();
1280+
if (top_pb_route.count(sink_cluster_pin_idx))
1281+
atom_net_id = top_pb_route[sink_cluster_pin_idx].atom_net_id; //Connected net in atom netlist
12791282

12801283
std::string net;
12811284
if (!atom_net_id) {

vpr/src/base/read_netlist.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -823,7 +823,7 @@ static void processPorts(pugi::xml_node Parent, t_pb* pb, t_pb_routes& pb_route,
823823
//Why does this not use the output pin used to deterimine the rr node index?
824824
pb_route.insert(std::make_pair(rr_node_index, t_pb_route()));
825825
pb_route[rr_node_index].driver_pb_pin_id = pin_node[0][0]->pin_count_in_cluster;
826-
pb_route[rr_node_index].pb_graph_pin = pin_node[0][0];
826+
pb_route[rr_node_index].pb_graph_pin = &pb->pb_graph_node->output_pins[out_port][i];
827827

828828
found = false;
829829
for (j = 0; j < pin_node[0][0]->num_output_edges; j++) {

vpr/src/base/vpr_api.cpp

+29
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,12 @@ static void free_complex_block_types();
111111
static void free_device(const t_det_routing_arch& routing_arch);
112112
static void free_circuit();
113113

114+
/** Set all port equivalences in the architecture to NONE. This is used in the
115+
* case of the flat router where port equivalence does not make sense.
116+
* We could just keep it set and ignore it, but that prevents compatibility
117+
* with OpenFPGA which takes it seriously. */
118+
static void unset_port_equivalences(DeviceContext& device_ctx);
119+
114120
/* Local subroutines end */
115121

116122
///@brief Display general VPR information
@@ -365,6 +371,25 @@ void vpr_init_with_options(const t_options* options, t_vpr_setup* vpr_setup, t_a
365371
device_ctx.pad_loc_type = vpr_setup->PlacerOpts.pad_loc_type;
366372
}
367373

374+
/** Port equivalence does not make sense during flat routing.
375+
* Remove port equivalence from all ports in the architecture */
376+
static void unset_port_equivalences(DeviceContext& device_ctx) {
377+
for (auto& physical_type : device_ctx.physical_tile_types) {
378+
for (auto& sub_tile : physical_type.sub_tiles) {
379+
for (auto& port : sub_tile.ports) {
380+
port.equivalent = PortEquivalence::NONE;
381+
}
382+
}
383+
}
384+
for (auto& logical_type : device_ctx.logical_block_types) {
385+
if (!logical_type.pb_type)
386+
continue;
387+
for (int i = 0; i < logical_type.pb_type->num_ports; i++) {
388+
logical_type.pb_type->ports[i].equivalent = PortEquivalence::NONE;
389+
}
390+
}
391+
}
392+
368393
bool vpr_flow(t_vpr_setup& vpr_setup, t_arch& arch) {
369394
if (vpr_setup.exit_before_pack) {
370395
VTR_LOG_WARN("Exiting before packing as requested.\n");
@@ -443,6 +468,10 @@ bool vpr_flow(t_vpr_setup& vpr_setup, t_arch& arch) {
443468

444469
bool is_flat = vpr_setup.RouterOpts.flat_routing;
445470
const Netlist<>& router_net_list = is_flat ? (const Netlist<>&)g_vpr_ctx.atom().netlist() : (const Netlist<>&)g_vpr_ctx.clustering().clb_nlist;
471+
if (is_flat) {
472+
VTR_LOG_WARN("Disabling port equivalence in the architecture since flat routing is enabled.\n");
473+
unset_port_equivalences(g_vpr_ctx.mutable_device());
474+
}
446475
RouteStatus route_status;
447476
{ //Route
448477
route_status = vpr_route_flow(router_net_list, vpr_setup, arch, is_flat);

vpr/src/pack/cluster_legalizer.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -1571,8 +1571,7 @@ void ClusterLegalizer::clean_cluster(LegalizationClusterId cluster_id) {
15711571
// Load the pb_route so we can free the cluster router data.
15721572
// The pb_route is used when creating a netlist from the legalized clusters.
15731573
std::vector<t_intra_lb_net>* saved_lb_nets = cluster.router_data->saved_lb_nets;
1574-
t_pb_graph_node* pb_graph_node = cluster.pb->pb_graph_node;
1575-
cluster.pb->pb_route = alloc_and_load_pb_route(saved_lb_nets, pb_graph_node);
1574+
cluster.pb->pb_route = alloc_and_load_pb_route(saved_lb_nets, cluster.type, intra_lb_pb_pin_lookup_);
15761575
// Free the router data.
15771576
free_router_data(cluster.router_data);
15781577
cluster.router_data = nullptr;
@@ -1632,6 +1631,7 @@ ClusterLegalizer::ClusterLegalizer(const AtomNetlist& atom_netlist,
16321631
log_verbosity_ = log_verbosity;
16331632
VTR_ASSERT(g_vpr_ctx.atom().lookup().atom_pb_bimap().is_empty());
16341633
atom_pb_lookup_ = AtomPBBimap();
1634+
intra_lb_pb_pin_lookup_ = IntraLbPbPinLookup(g_vpr_ctx.device().logical_block_types);
16351635
}
16361636

16371637
void ClusterLegalizer::reset() {

vpr/src/pack/cluster_legalizer.h

+6
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "vtr_vector.h"
2424
#include "vtr_vector_map.h"
2525
#include "atom_pb_bimap.h"
26+
#include "vpr_utils.h"
2627

2728
// Forward declarations
2829
class Prepacker;
@@ -524,6 +525,8 @@ class ClusterLegalizer {
524525
inline const AtomPBBimap& atom_pb_lookup() const { return atom_pb_lookup_; }
525526
inline AtomPBBimap& mutable_atom_pb_lookup() { return atom_pb_lookup_; }
526527

528+
inline const IntraLbPbPinLookup& intra_lb_pb_pin_lookup() const { return intra_lb_pb_pin_lookup_; }
529+
527530
/// @brief Destructor of the class. Frees allocated data.
528531
~ClusterLegalizer();
529532

@@ -595,4 +598,7 @@ class ClusterLegalizer {
595598
/// @brief A two way map between AtomBlockIds and pb types. This is a copy
596599
/// of the AtomPBBimap in the global context's AtomLookup
597600
AtomPBBimap atom_pb_lookup_;
601+
602+
/// @brief A lookup table for the pin mapping of the intra-lb pb pins.
603+
IntraLbPbPinLookup intra_lb_pb_pin_lookup_;
598604
};

vpr/src/pack/cluster_router.cpp

+33-11
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,23 @@ static bool is_route_success(t_lb_router_data* router_data);
108108
static t_lb_trace* find_node_in_rt(t_lb_trace* rt, int rt_index);
109109
static void reset_explored_node_tb(t_lb_router_data* router_data);
110110
static void save_and_reset_lb_route(t_lb_router_data* router_data);
111-
static void load_trace_to_pb_route(t_pb_routes& pb_route, const int total_pins, const AtomNetId net_id, const int prev_pin_id, const t_lb_trace* trace);
111+
112+
/**
113+
* @brief Recurse through route tree trace to populate pb pin to atom net lookup array.
114+
*
115+
* @param pb_route Array of pb pin to atom net lookup to be populated in this routine.
116+
* @param net_id Atom net ID of the current net.
117+
* @param prev_pin_id ID of the previous pin in the route tree trace.
118+
* @param trace Current trace node in the route tree.
119+
* @param logic_block_type Logic block type of the current cluster.
120+
* @param intra_lb_pb_pin_lookup Intra-logic block pin lookup to get t_pb_graph_pin from a pin ID.
121+
*/
122+
static void load_trace_to_pb_route(t_pb_routes& pb_route,
123+
const AtomNetId net_id,
124+
const int prev_pin_id,
125+
const t_lb_trace* trace,
126+
t_logical_block_type_ptr logic_block_type,
127+
const IntraLbPbPinLookup& intra_lb_pb_pin_lookup);
112128

113129
static std::string describe_lb_type_rr_node(int inode,
114130
const t_lb_router_data* router_data);
@@ -543,15 +559,14 @@ bool try_intra_lb_route(t_lb_router_data* router_data,
543559
* Accessor Functions
544560
******************************************************************************************/
545561

546-
/* Creates an array [0..num_pb_graph_pins-1] lookup for intra-logic block routing. Given pb_graph_pin id for clb, lookup atom net that uses that pin.
547-
* If pin is not used, stores OPEN at that pin location */
548-
t_pb_routes alloc_and_load_pb_route(const std::vector<t_intra_lb_net>* intra_lb_nets, t_pb_graph_node* pb_graph_head) {
562+
t_pb_routes alloc_and_load_pb_route(const std::vector<t_intra_lb_net>* intra_lb_nets,
563+
t_logical_block_type_ptr logic_block_type,
564+
const IntraLbPbPinLookup& intra_lb_pb_pin_lookup) {
549565
const std::vector<t_intra_lb_net>& lb_nets = *intra_lb_nets;
550-
int total_pins = pb_graph_head->total_pb_pins;
551566
t_pb_routes pb_route;
552567

553-
for (int inet = 0; inet < (int)lb_nets.size(); inet++) {
554-
load_trace_to_pb_route(pb_route, total_pins, lb_nets[inet].atom_net_id, OPEN, lb_nets[inet].rt_tree);
568+
for (const auto& lb_net : lb_nets) {
569+
load_trace_to_pb_route(pb_route, lb_net.atom_net_id, OPEN, lb_net.rt_tree, logic_block_type, intra_lb_pb_pin_lookup);
555570
}
556571

557572
return pb_route;
@@ -581,24 +596,31 @@ void free_intra_lb_nets(std::vector<t_intra_lb_net>* intra_lb_nets) {
581596
* Internal Functions
582597
****************************************************************************/
583598

584-
/* Recurse through route tree trace to populate pb pin to atom net lookup array */
585-
static void load_trace_to_pb_route(t_pb_routes& pb_route, const int total_pins, const AtomNetId net_id, const int prev_pin_id, const t_lb_trace* trace) {
599+
static void load_trace_to_pb_route(t_pb_routes& pb_route,
600+
const AtomNetId net_id,
601+
const int prev_pin_id,
602+
const t_lb_trace* trace,
603+
t_logical_block_type_ptr logic_block_type,
604+
const IntraLbPbPinLookup& intra_lb_pb_pin_lookup) {
586605
int ipin = trace->current_node;
587606
int driver_pb_pin_id = prev_pin_id;
588607
int cur_pin_id = OPEN;
608+
const int total_pins = logic_block_type->pb_graph_head->total_pb_pins;
589609
if (ipin < total_pins) {
590610
/* This routing node corresponds with a pin. This node is virtual (ie. sink or source node) */
591611
cur_pin_id = ipin;
592612
if (!pb_route.count(ipin)) {
593613
pb_route.insert(std::make_pair(cur_pin_id, t_pb_route()));
594614
pb_route[cur_pin_id].atom_net_id = net_id;
595615
pb_route[cur_pin_id].driver_pb_pin_id = driver_pb_pin_id;
616+
const t_pb_graph_pin* pb_graph_pin = intra_lb_pb_pin_lookup.pb_gpin(logic_block_type->index, cur_pin_id);
617+
pb_route[cur_pin_id].pb_graph_pin = pb_graph_pin;
596618
} else {
597619
VTR_ASSERT(pb_route[cur_pin_id].atom_net_id == net_id);
598620
}
599621
}
600-
for (int itrace = 0; itrace < (int)trace->next_nodes.size(); itrace++) {
601-
load_trace_to_pb_route(pb_route, total_pins, net_id, cur_pin_id, &trace->next_nodes[itrace]);
622+
for (const auto& nxt_trace : trace->next_nodes) {
623+
load_trace_to_pb_route(pb_route, net_id, cur_pin_id, &nxt_trace, logic_block_type, intra_lb_pb_pin_lookup);
602624
}
603625
}
604626

vpr/src/pack/cluster_router.h

+13-2
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,19 @@ void set_reset_pb_modes(t_lb_router_data* router_data, const t_pb* pb, const boo
2222
bool try_intra_lb_route(t_lb_router_data* router_data, int verbosity, t_mode_selection_status* mode_status);
2323
void reset_intra_lb_route(t_lb_router_data* router_data);
2424

25-
/* Accessor Functions */
26-
t_pb_routes alloc_and_load_pb_route(const std::vector<t_intra_lb_net>* intra_lb_nets, t_pb_graph_node* pb_graph_head);
25+
/**
26+
* @brief Creates an array [0..num_pb_graph_pins-1] for intra-logic block routing lookup.
27+
* Given a pb_graph_pin ID for a CLB, this lookup returns t_pb_route corresponding to that
28+
* pin.
29+
*
30+
* @param intra_lb_nets Vector of intra-logic block nets.
31+
* @param logic_block_type Logic block type of the current cluster.
32+
* @param intra_lb_pb_pin_lookup Intra-logic block pin lookup to get t_pb_graph_pin from a pin ID.
33+
* @return t_pb_routes An array [0..num_pb_graph_pins-1] for intra-logic block routing lookup.
34+
*/
35+
t_pb_routes alloc_and_load_pb_route(const std::vector<t_intra_lb_net>* intra_lb_nets,
36+
t_logical_block_type_ptr logic_block_type,
37+
const IntraLbPbPinLookup& intra_lb_pb_pin_lookup);
2738
void free_pb_route(t_pb_route* free_pb_route);
2839

2940
#endif

vpr/src/pack/post_routing_pb_pin_fixup.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -1033,6 +1033,7 @@ void sync_netlists_to_routing(const Netlist<>& net_list,
10331033
/* Create net-to-rr_node mapping */
10341034
vtr::vector<RRNodeId, ClusterNetId> rr_node_nets = annotate_rr_node_nets(clustering_ctx,
10351035
device_ctx,
1036+
atom_ctx,
10361037
verbose);
10371038

10381039
IntraLbPbPinLookup intra_lb_pb_pin_lookup(device_ctx.logical_block_types);

vpr/src/pack/sync_netlists_to_routing_flat.cpp

+46-43
Original file line numberDiff line numberDiff line change
@@ -42,23 +42,6 @@ static void fixup_atom_pb_graph_pin_mapping(void);
4242

4343
/* Function definitions */
4444

45-
/** Is the clock net found in the routing results?
46-
* (If not, clock_modeling is probably ideal and we should preserve clock routing while rebuilding.) */
47-
inline bool is_clock_net_routed(void) {
48-
auto& atom_ctx = g_vpr_ctx.atom();
49-
auto& route_ctx = g_vpr_ctx.routing();
50-
51-
for (auto net_id : atom_ctx.netlist().nets()) {
52-
auto& tree = route_ctx.route_trees[net_id];
53-
if (!tree)
54-
continue;
55-
if (route_ctx.is_clock_net[net_id]) /* Clock net has routing */
56-
return true;
57-
}
58-
59-
return false;
60-
}
61-
6245
/** Get the ClusterBlockId for a given RRNodeId. */
6346
inline ClusterBlockId get_cluster_block_from_rr_node(RRNodeId inode) {
6447
auto& device_ctx = g_vpr_ctx.device();
@@ -185,18 +168,22 @@ static void sync_pb_routes_to_routing(void) {
185168
auto& route_ctx = g_vpr_ctx.routing();
186169
auto& rr_graph = device_ctx.rr_graph;
187170

188-
/* Was the clock net routed? */
189-
bool clock_net_is_routed = is_clock_net_routed();
190-
191171
/* Clear out existing pb_routes: they were made by the intra cluster router and are invalid now */
192172
for (ClusterBlockId clb_blk_id : cluster_ctx.clb_nlist.blocks()) {
193-
/* If we don't have routing for the clock net, don't erase entries associated with a clock net.
194-
* Otherwise we won't have data to rebuild them */
173+
/* Don't erase entries for nets without routing in place (clocks, globals...) */
195174
std::vector<int> pins_to_erase;
196-
auto& pb_routes = cluster_ctx.clb_nlist.block_pb(clb_blk_id)->pb_route;
175+
t_pb_routes& pb_routes = cluster_ctx.clb_nlist.block_pb(clb_blk_id)->pb_route;
197176
for (auto& [pin, pb_route] : pb_routes) {
198-
if (clock_net_is_routed || !route_ctx.is_clock_net[pb_route.atom_net_id])
199-
pins_to_erase.push_back(pin);
177+
/*
178+
* Given that this function is called when flat routing is enabled,
179+
* we can safely assume that the net IDs to index into route_ctx.route_trees
180+
* correspond to the atom net IDs.
181+
*/
182+
if (!route_ctx.route_trees[pb_route.atom_net_id]) {
183+
/* No route tree: no routing in place, it is global or clock */
184+
continue;
185+
}
186+
pins_to_erase.push_back(pin);
200187
}
201188

202189
for (int pin : pins_to_erase) {
@@ -276,37 +263,37 @@ static void sync_clustered_netlist_to_routing(void) {
276263
auto& atom_ctx = g_vpr_ctx.mutable_atom();
277264
auto& atom_lookup = atom_ctx.lookup();
278265

279-
bool clock_net_is_routed = is_clock_net_routed();
280-
281266
/* 1. Remove all nets, pins and ports from the clustered netlist.
282-
* If the clock net is not routed, don't remove entries for the clock net
283-
* otherwise we won't have data to rebuild them. */
267+
* Do not remove entries for nets without an existing route tree,
268+
* since we don't have the information to rebuild those parts. */
284269
std::vector<ClusterNetId> nets_to_remove;
285270
std::vector<ClusterPinId> pins_to_remove;
286271
std::vector<ClusterPortId> ports_to_remove;
287272

288273
for (auto net_id : clb_netlist.nets()) {
289274
auto atom_net_id = atom_lookup.atom_net(net_id);
290-
if (!clock_net_is_routed && route_ctx.is_clock_net[atom_net_id])
275+
if (!route_ctx.route_trees[atom_net_id])
291276
continue;
292277

293278
nets_to_remove.push_back(net_id);
294279
}
295-
for (auto pin_id : clb_netlist.pins()) {
296-
ClusterNetId clb_net_id = clb_netlist.pin_net(pin_id);
297-
auto atom_net_id = atom_lookup.atom_net(clb_net_id);
298-
if (!clock_net_is_routed && atom_net_id && route_ctx.is_clock_net[atom_net_id])
299-
continue;
300-
301-
pins_to_remove.push_back(pin_id);
302-
}
280+
/* Mark ports and pins for removal. Don't remove a port if
281+
* it has at least one pin remaining */
303282
for (auto port_id : clb_netlist.ports()) {
304-
ClusterNetId clb_net_id = clb_netlist.port_net(port_id, 0);
305-
auto atom_net_id = atom_lookup.atom_net(clb_net_id);
306-
if (!clock_net_is_routed && atom_net_id && route_ctx.is_clock_net[atom_net_id])
307-
continue;
283+
size_t skipped_pins = 0;
284+
285+
for (auto pin_id : clb_netlist.port_pins(port_id)) {
286+
ClusterNetId clb_net_id = clb_netlist.pin_net(pin_id);
287+
auto atom_net_id = atom_lookup.atom_net(clb_net_id);
288+
if (atom_net_id && !route_ctx.route_trees[atom_net_id]) {
289+
skipped_pins++;
290+
} else {
291+
pins_to_remove.push_back(pin_id);
292+
}
293+
}
308294

309-
ports_to_remove.push_back(port_id);
295+
if (!skipped_pins) // All pins have been removed, remove port
296+
ports_to_remove.push_back(port_id);
310297
}
311298

312299
/* ClusteredNetlist's iterators rely on internal lookups, so we mark for removal
@@ -363,6 +350,7 @@ static void sync_clustered_netlist_to_routing(void) {
363350

364351
t_pb_graph_pin* pb_graph_pin = get_pb_graph_node_pin_from_block_pin(clb, pin_index);
365352

353+
/* Get or create port */
366354
ClusterPortId port_id = clb_netlist.find_port(clb, pb_graph_pin->port->name);
367355
if (!port_id) {
368356
PortType port_type;
@@ -378,6 +366,15 @@ static void sync_clustered_netlist_to_routing(void) {
378366
}
379367
PinType pin_type = node_type == e_rr_type::OPIN ? PinType::DRIVER : PinType::SINK;
380368

369+
/* Pin already exists. This means a global net that was not routed (i.e. 'ideal' mode). */
370+
if (clb_netlist.port_pin(port_id, pb_graph_pin->pin_number)) {
371+
VTR_LOG_WARN("Pin %s of block %s has a global or clock net"
372+
" connected and it has a routing clash with the flat router."
373+
" This may cause inconsistent results.\n",
374+
pb_graph_pin->to_string().c_str(),
375+
clb_netlist.block_name(clb).c_str());
376+
continue;
377+
}
381378
ClusterPinId new_pin = clb_netlist.create_pin(port_id, pb_graph_pin->pin_number, clb_net_id, pin_type, pb_graph_pin->pin_count_in_cluster);
382379
clb_netlist.set_pin_net(new_pin, pin_type, clb_net_id);
383380
}
@@ -419,6 +416,12 @@ static void fixup_atom_pb_graph_pin_mapping(void) {
419416

420417
/* Find atom port from pbg pin's model port */
421418
AtomPortId atom_port = atom_ctx.netlist().find_atom_port(atb, atom_pbg_pin->port->model_port);
419+
420+
/* Not an equivalent port, so no need to do fixup */
421+
if (atom_pbg_pin->port->equivalent != PortEquivalence::FULL) {
422+
continue;
423+
}
424+
422425
for (AtomPinId atom_pin : atom_ctx.netlist().port_pins(atom_port)) {
423426
/* Match net IDs from pb_route and atom netlist and connect in lookup */
424427
if (pb_route.atom_net_id == atom_ctx.netlist().pin_net(atom_pin)) {

0 commit comments

Comments
 (0)