Skip to content

Commit ae5584f

Browse files
authored
Merge pull request verilog-to-routing#1561 from HackerFoo/connection_router_unit_test
Add a unit test for the ConnectionRouter
2 parents 4e64cd7 + 42d484d commit ae5584f

File tree

1 file changed

+163
-0
lines changed

1 file changed

+163
-0
lines changed

vpr/test/test_connection_router.cpp

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
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

Comments
 (0)