|
| 1 | +#include "catch.hpp" |
| 2 | + |
| 3 | +#include "vpr_api.h" |
| 4 | +#include "vpr_signal_handler.h" |
| 5 | +#include "globals.h" |
| 6 | +#include "net_delay.h" |
| 7 | +#include "place_and_route.h" |
| 8 | +#include "route_tree_timing.h" |
| 9 | +#include "timing_place_lookup.h" |
| 10 | + |
| 11 | +static constexpr const char kArchFile[] = "../../vtr_flow/arch/timing/k6_frac_N10_mem32K_40nm.xml"; |
| 12 | +static constexpr int kMaxHops = 10; |
| 13 | + |
| 14 | +namespace { |
| 15 | + |
| 16 | +// Route from source_node to sink_node, returning either the delay, or infinity if unroutable. |
| 17 | +static float do_one_route(int source_node, int sink_node, const t_router_opts& router_opts, const std::vector<t_segment_inf>& segment_inf) { |
| 18 | + auto& device_ctx = g_vpr_ctx.device(); |
| 19 | + auto& route_ctx = g_vpr_ctx.routing(); |
| 20 | + |
| 21 | + t_rt_node* rt_root = init_route_tree_to_source_no_net(source_node); |
| 22 | + |
| 23 | + // Update base costs according to fanout and criticality rules. |
| 24 | + update_rr_base_costs(1); |
| 25 | + |
| 26 | + // Bounding box includes the entire grid. |
| 27 | + t_bb bounding_box; |
| 28 | + bounding_box.xmin = 0; |
| 29 | + bounding_box.xmax = device_ctx.grid.width() + 1; |
| 30 | + bounding_box.ymin = 0; |
| 31 | + bounding_box.ymax = device_ctx.grid.height() + 1; |
| 32 | + |
| 33 | + t_conn_cost_params cost_params; |
| 34 | + cost_params.criticality = router_opts.max_criticality; |
| 35 | + cost_params.astar_fac = router_opts.astar_fac; |
| 36 | + cost_params.bend_cost = router_opts.bend_cost; |
| 37 | + |
| 38 | + route_budgets budgeting_inf; |
| 39 | + |
| 40 | + RouterStats router_stats; |
| 41 | + auto router_lookahead = make_router_lookahead( |
| 42 | + router_opts.lookahead_type, |
| 43 | + router_opts.write_router_lookahead, |
| 44 | + router_opts.read_router_lookahead, |
| 45 | + segment_inf); |
| 46 | + |
| 47 | + ConnectionRouter<BinaryHeap> router( |
| 48 | + device_ctx.grid, |
| 49 | + *router_lookahead, |
| 50 | + device_ctx.rr_nodes, |
| 51 | + device_ctx.rr_rc_data, |
| 52 | + device_ctx.rr_switch_inf, |
| 53 | + g_vpr_ctx.mutable_routing().rr_node_route_inf); |
| 54 | + |
| 55 | + // Find the cheapest route if possible. |
| 56 | + bool found_path; |
| 57 | + t_heap cheapest; |
| 58 | + std::tie(found_path, cheapest) = router.timing_driven_route_connection_from_route_tree(rt_root, sink_node, cost_params, bounding_box, router_stats); |
| 59 | + |
| 60 | + // Default delay is infinity, which indicates that a route was not found. |
| 61 | + float delay = std::numeric_limits<float>::infinity(); |
| 62 | + if (found_path) { |
| 63 | + // Check that the route goes to the requested sink. |
| 64 | + REQUIRE(cheapest.index == sink_node); |
| 65 | + |
| 66 | + // Get the delay |
| 67 | + t_rt_node* rt_node_of_sink = update_route_tree(&cheapest, OPEN, nullptr); |
| 68 | + delay = rt_node_of_sink->Tdel; |
| 69 | + |
| 70 | + // Clean up |
| 71 | + free_route_tree(rt_root); |
| 72 | + } |
| 73 | + |
| 74 | + // Reset for the next router call. |
| 75 | + router.reset_path_costs(); |
| 76 | + return delay; |
| 77 | +} |
| 78 | + |
| 79 | +// Find a source and a sink by walking edges. |
| 80 | +std::tuple<size_t, size_t, int> find_source_and_sink() { |
| 81 | + auto& device_ctx = g_vpr_ctx.device(); |
| 82 | + auto& rr_graph = device_ctx.rr_nodes; |
| 83 | + |
| 84 | + // Current longest walk |
| 85 | + std::tuple<size_t, size_t, int> longest = std::make_tuple(0, 0, 0); |
| 86 | + |
| 87 | + // Start from each RR node |
| 88 | + for (size_t id = 0; id < rr_graph.size(); id++) { |
| 89 | + RRNodeId source(id), sink = source; |
| 90 | + for (int hops = 0; hops < kMaxHops; hops++) { |
| 91 | + // Take the first edge, if there is one. |
| 92 | + auto edge = rr_graph.first_edge(sink); |
| 93 | + if (edge == rr_graph.last_edge(sink)) { |
| 94 | + break; |
| 95 | + } |
| 96 | + sink = rr_graph.edge_sink_node(edge); |
| 97 | + |
| 98 | + // If this is the new longest walk, store it. |
| 99 | + if (hops > std::get<2>(longest)) { |
| 100 | + longest = std::make_tuple(size_t(source), size_t(sink), hops); |
| 101 | + } |
| 102 | + } |
| 103 | + } |
| 104 | + return longest; |
| 105 | +} |
| 106 | + |
| 107 | +// Test that the router can route nets individually, not considering congestion. |
| 108 | +// This is a minimal timing driven routing test that can be used as documentation, |
| 109 | +// and as a starting point for experimentation. |
| 110 | +TEST_CASE("connection_router", "[vpr]") { |
| 111 | + // Minimal setup |
| 112 | + auto options = t_options(); |
| 113 | + auto arch = t_arch(); |
| 114 | + auto vpr_setup = t_vpr_setup(); |
| 115 | + |
| 116 | + vpr_install_signal_handler(); |
| 117 | + vpr_initialize_logging(); |
| 118 | + |
| 119 | + // Command line arguments |
| 120 | + const char* argv[] = { |
| 121 | + "test_vpr", |
| 122 | + kArchFile, |
| 123 | + "wire.eblif", |
| 124 | + "--route_chan_width", "100"}; |
| 125 | + vpr_init(sizeof(argv) / sizeof(argv[0]), argv, |
| 126 | + &options, &vpr_setup, &arch); |
| 127 | + |
| 128 | + vpr_create_device_grid(vpr_setup, arch); |
| 129 | + vpr_setup_clock_networks(vpr_setup, arch); |
| 130 | + auto chan_width = init_chan(vpr_setup.RouterOpts.fixed_channel_width, arch.Chans); |
| 131 | + |
| 132 | + alloc_routing_structs( |
| 133 | + chan_width, |
| 134 | + vpr_setup.RouterOpts, |
| 135 | + &vpr_setup.RoutingArch, |
| 136 | + vpr_setup.Segments, |
| 137 | + arch.Directs, |
| 138 | + arch.num_directs); |
| 139 | + |
| 140 | + // Find a source and sink to route |
| 141 | + int source_rr_node, sink_rr_node, hops; |
| 142 | + std::tie(source_rr_node, sink_rr_node, hops) = find_source_and_sink(); |
| 143 | + |
| 144 | + // Check that the route will be non-trivial |
| 145 | + REQUIRE(source_rr_node != sink_rr_node); |
| 146 | + REQUIRE(hops >= 3); |
| 147 | + |
| 148 | + // Find the route |
| 149 | + float delay = do_one_route( |
| 150 | + source_rr_node, |
| 151 | + sink_rr_node, |
| 152 | + vpr_setup.RouterOpts, |
| 153 | + vpr_setup.Segments); |
| 154 | + |
| 155 | + // Check that a route was found |
| 156 | + REQUIRE(delay < std::numeric_limits<float>::infinity()); |
| 157 | + |
| 158 | + // Clean up |
| 159 | + free_routing_structs(); |
| 160 | + vpr_free_all(arch, vpr_setup); |
| 161 | +} |
| 162 | + |
| 163 | +} // namespace |
0 commit comments