| #include "rr_graph_clock.h" |
| |
| #include "globals.h" |
| #include "rr_graph.h" |
| #include "rr_graph2.h" |
| #include "rr_graph_area.h" |
| #include "rr_graph_util.h" |
| #include "rr_graph_indexed_data.h" |
| |
| #include "vtr_assert.h" |
| #include "vtr_log.h" |
| #include "vpr_error.h" |
| |
| void ClockRRGraphBuilder::create_and_append_clock_rr_graph(std::vector<t_segment_inf>& segment_inf, |
| const float R_minW_nmos, |
| const float R_minW_pmos, |
| int wire_to_rr_ipin_switch, |
| const enum e_base_cost_type base_cost_type) { |
| vtr::printf_info("Starting clock network routing resource graph generation...\n"); |
| clock_t begin = clock(); |
| |
| auto& device_ctx = g_vpr_ctx.mutable_device(); |
| auto* chan_width = &device_ctx.chan_width; |
| auto& clock_networks = device_ctx.clock_networks; |
| auto& clock_routing = device_ctx.clock_connections; |
| |
| size_t clock_nodes_start_idx = device_ctx.rr_nodes.size(); |
| |
| ClockRRGraphBuilder clock_graph = ClockRRGraphBuilder(); |
| clock_graph.create_clock_networks_wires(clock_networks, segment_inf.size()); |
| clock_graph.create_clock_networks_switches(clock_routing); |
| |
| // Reset fanin to account for newly added clock rr_nodes |
| init_fan_in(device_ctx.rr_nodes, device_ctx.rr_nodes.size()); |
| |
| clock_graph.add_rr_switches_and_map_to_nodes(clock_nodes_start_idx, R_minW_nmos, R_minW_pmos); |
| |
| // "Partition the rr graph edges for efficient access to configurable/non-configurable |
| // edge subsets. Must be done after RR switches have been allocated" |
| partition_rr_graph_edges(device_ctx); |
| |
| alloc_and_load_rr_indexed_data(segment_inf, device_ctx.rr_node_indices, |
| chan_width->max, wire_to_rr_ipin_switch, base_cost_type); |
| |
| float elapsed_time = (float)(clock() - begin) / CLOCKS_PER_SEC; |
| vtr::printf_info("Building clock network resource graph took %g seconds\n", elapsed_time); |
| } |
| |
| // Clock network information comes from the arch file |
| void ClockRRGraphBuilder::create_clock_networks_wires(std::vector<std::unique_ptr<ClockNetwork>>& clock_networks, |
| int num_segments) { |
| // Add rr_nodes for each clock network wire |
| for (auto& clock_network : clock_networks) { |
| clock_network->create_rr_nodes_for_clock_network_wires(*this, num_segments); |
| } |
| |
| // Reduce the capacity of rr_nodes for performance |
| auto& rr_nodes = g_vpr_ctx.mutable_device().rr_nodes; |
| rr_nodes.shrink_to_fit(); |
| } |
| |
| // Clock switch information comes from the arch file |
| void ClockRRGraphBuilder::create_clock_networks_switches(std::vector<std::unique_ptr<ClockConnection>>& clock_connections) { |
| for (auto& clock_connection : clock_connections) { |
| clock_connection->create_switches(*this); |
| } |
| } |
| |
| void ClockRRGraphBuilder::add_rr_switches_and_map_to_nodes(size_t node_start_idx, |
| const float R_minW_nmos, |
| const float R_minW_pmos) { |
| auto& device_ctx = g_vpr_ctx.mutable_device(); |
| auto& rr_nodes = device_ctx.rr_nodes; |
| |
| // Check to see that clock nodes were sucessfully appended to rr_nodes |
| VTR_ASSERT(rr_nodes.size() > node_start_idx); |
| |
| std::unordered_map<int, int> arch_switch_to_rr_switch; |
| |
| // The following assumes that arch_switch was specified earlier when the edges where added |
| for (size_t node_idx = node_start_idx; node_idx < rr_nodes.size(); node_idx++) { |
| auto& from_node = rr_nodes[node_idx]; |
| for (t_edge_size edge_idx = 0; edge_idx < from_node.num_edges(); edge_idx++) { |
| int arch_switch_idx = from_node.edge_switch(edge_idx); |
| |
| int rr_switch_idx; |
| auto itter = arch_switch_to_rr_switch.find(arch_switch_idx); |
| if (itter == arch_switch_to_rr_switch.end()) { |
| rr_switch_idx = add_rr_switch_from_arch_switch_inf(arch_switch_idx, |
| R_minW_nmos, |
| R_minW_pmos); |
| arch_switch_to_rr_switch[arch_switch_idx] = rr_switch_idx; |
| } else { |
| rr_switch_idx = itter->second; |
| } |
| |
| from_node.set_edge_switch(edge_idx, rr_switch_idx); |
| } |
| } |
| |
| device_ctx.rr_switch_inf.shrink_to_fit(); |
| } |
| |
| int ClockRRGraphBuilder::add_rr_switch_from_arch_switch_inf(int arch_switch_idx, |
| const float R_minW_nmos, |
| const float R_minW_pmos) { |
| auto& device_ctx = g_vpr_ctx.mutable_device(); |
| auto& rr_switch_inf = device_ctx.rr_switch_inf; |
| auto& arch_switch_inf = device_ctx.arch_switch_inf; |
| |
| rr_switch_inf.emplace_back(); |
| int rr_switch_idx = rr_switch_inf.size() - 1; |
| |
| // TODO: Add support for non fixed Tdel based on fanin information |
| // and move assigning Tdel into add_rr_switch |
| VTR_ASSERT(arch_switch_inf[arch_switch_idx].fixed_Tdel()); |
| int fanin = UNDEFINED; |
| |
| load_rr_switch_from_arch_switch(arch_switch_idx, rr_switch_idx, fanin, R_minW_nmos, R_minW_pmos); |
| |
| return rr_switch_idx; |
| } |
| |
| void ClockRRGraphBuilder::add_switch_location(std::string clock_name, |
| std::string switch_point_name, |
| int x, |
| int y, |
| int node_index) { |
| // Note use of operator[] will automatically insert clock name if it doesn't exist |
| clock_name_to_switch_points[clock_name].insert_switch_node_idx(switch_point_name, x, y, node_index); |
| } |
| |
| void SwitchPoints::insert_switch_node_idx(std::string switch_point_name, int x, int y, int node_idx) { |
| // Note use of operator[] will automatically insert switch name if it doesn't exit |
| switch_point_name_to_switch_location[switch_point_name].insert_node_idx(x, y, node_idx); |
| } |
| |
| void SwitchPoint::insert_node_idx(int x, int y, int node_idx) { |
| // allocate 2d vector of grid size |
| if (rr_node_indices.empty()) { |
| auto& grid = g_vpr_ctx.device().grid; |
| rr_node_indices.resize(grid.width()); |
| for (size_t i = 0; i < grid.width(); i++) { |
| rr_node_indices[i].resize(grid.height()); |
| } |
| } |
| |
| // insert node_idx at location |
| rr_node_indices[x][y].push_back(node_idx); |
| locations.insert({x, y}); |
| } |
| |
| std::vector<int> ClockRRGraphBuilder::get_rr_node_indices_at_switch_location(std::string clock_name, |
| std::string switch_point_name, |
| int x, |
| int y) const { |
| auto itter = clock_name_to_switch_points.find(clock_name); |
| |
| // assert that clock name exists in map |
| VTR_ASSERT(itter != clock_name_to_switch_points.end()); |
| |
| auto& switch_points = itter->second; |
| return switch_points.get_rr_node_indices_at_location(switch_point_name, x, y); |
| } |
| |
| std::vector<int> SwitchPoints::get_rr_node_indices_at_location(std::string switch_point_name, |
| int x, |
| int y) const { |
| auto itter = switch_point_name_to_switch_location.find(switch_point_name); |
| |
| // assert that switch name exists in map |
| VTR_ASSERT(itter != switch_point_name_to_switch_location.end()); |
| |
| auto& switch_point = itter->second; |
| std::vector<int> rr_node_indices = switch_point.get_rr_node_indices_at_location(x, y); |
| return rr_node_indices; |
| } |
| |
| std::vector<int> SwitchPoint::get_rr_node_indices_at_location(int x, int y) const { |
| // assert that switch is connected to nodes at the location |
| VTR_ASSERT(!rr_node_indices[x][y].empty()); |
| |
| return rr_node_indices[x][y]; |
| } |
| |
| std::set<std::pair<int, int>> ClockRRGraphBuilder::get_switch_locations(std::string clock_name, |
| std::string switch_point_name) const { |
| auto itter = clock_name_to_switch_points.find(clock_name); |
| |
| // assert that clock name exists in map |
| VTR_ASSERT(itter != clock_name_to_switch_points.end()); |
| |
| auto& switch_points = itter->second; |
| return switch_points.get_switch_locations(switch_point_name); |
| } |
| |
| std::set<std::pair<int, int>> SwitchPoints::get_switch_locations(std::string switch_point_name) const { |
| auto itter = switch_point_name_to_switch_location.find(switch_point_name); |
| |
| // assert that switch name exists in map |
| VTR_ASSERT(itter != switch_point_name_to_switch_location.end()); |
| |
| auto& switch_point = itter->second; |
| return switch_point.get_switch_locations(); |
| } |
| |
| std::set<std::pair<int, int>> SwitchPoint::get_switch_locations() const { |
| // assert that switch is connected to nodes at the location |
| VTR_ASSERT(!locations.empty()); |
| |
| return locations; |
| } |
| |
| int ClockRRGraphBuilder::get_and_increment_chanx_ptc_num() { |
| auto& device_ctx = g_vpr_ctx.mutable_device(); |
| auto& grid = device_ctx.grid; |
| auto* channel_width = &device_ctx.chan_width; |
| |
| // ptc_num is determined by the channel width |
| // The channel width lets the drawing engine how much to space the LBs appart |
| int ptc_num = channel_width->x_max++; |
| if (channel_width->x_max > channel_width->max) { |
| channel_width->max = channel_width->x_max; |
| } |
| |
| for (size_t i = 0; i < grid.height(); ++i) { |
| device_ctx.chan_width.x_list[i]++; |
| } |
| |
| return ptc_num; |
| } |
| |
| int ClockRRGraphBuilder::get_and_increment_chany_ptc_num() { |
| auto& device_ctx = g_vpr_ctx.mutable_device(); |
| auto& grid = device_ctx.grid; |
| auto* channel_width = &device_ctx.chan_width; |
| |
| // ptc_num is determined by the channel width |
| // The channel width lets the drawing engine how much to space the LBs appart |
| int ptc_num = channel_width->y_max++; |
| if (channel_width->y_max > channel_width->max) { |
| channel_width->max = channel_width->y_max; |
| } |
| |
| for (size_t i = 0; i < grid.width(); ++i) { |
| device_ctx.chan_width.y_list[i]++; |
| } |
| |
| return ptc_num; |
| } |