| #include "clock_connection_builders.h" |
| |
| #include "globals.h" |
| #include "rr_graph2.h" |
| |
| #include "vtr_assert.h" |
| #include "vtr_log.h" |
| #include "vtr_error.h" |
| |
| #include <random> |
| #include <math.h> |
| |
| /* |
| * RoutingToClockConnection (setters) |
| */ |
| |
| void RoutingToClockConnection::set_clock_name_to_connect_to(std::string clock_name) { |
| clock_to_connect_to = clock_name; |
| } |
| |
| void RoutingToClockConnection::set_clock_switch_point_name(std::string clock_switch_point_name) { |
| switch_point_name = clock_switch_point_name; |
| } |
| |
| void RoutingToClockConnection::set_switch_location(int x, int y) { |
| switch_location.x = x; |
| switch_location.y = y; |
| } |
| |
| void RoutingToClockConnection::set_switch(int rr_switch_index) { |
| rr_switch_idx = rr_switch_index; |
| } |
| |
| void RoutingToClockConnection::set_fc_val(float fc_val) { |
| fc = fc_val; |
| } |
| |
| /* |
| * RoutingToClockConnection (member functions) |
| */ |
| |
| void RoutingToClockConnection::create_switches(const ClockRRGraphBuilder& clock_graph) { |
| // Initialize random seed |
| // Must be done durring every call inorder for restored rr_graphs after a binary |
| // search to be consistant |
| std::srand(seed); |
| |
| auto& device_ctx = g_vpr_ctx.mutable_device(); |
| auto& rr_nodes = device_ctx.rr_nodes; |
| auto& rr_node_indices = device_ctx.rr_node_indices; |
| |
| // rr_node indices for x and y channel routing wires and clock wires to connect to |
| auto x_wire_indices = get_rr_node_chan_wires_at_location( |
| rr_node_indices, CHANX, switch_location.x, switch_location.y); |
| auto y_wire_indices = get_rr_node_chan_wires_at_location( |
| rr_node_indices, CHANY, switch_location.x, switch_location.y); |
| auto clock_indices = clock_graph.get_rr_node_indices_at_switch_location( |
| clock_to_connect_to, switch_point_name, switch_location.x, switch_location.y); |
| |
| for (auto clock_index : clock_indices) { |
| // Select wires to connect to at random |
| std::random_shuffle(x_wire_indices.begin(), x_wire_indices.end()); |
| std::random_shuffle(y_wire_indices.begin(), y_wire_indices.end()); |
| |
| // Connect to x-channel wires |
| unsigned num_wires_x = x_wire_indices.size() * fc; |
| for (size_t i = 0; i < num_wires_x; i++) { |
| rr_nodes[x_wire_indices[i]].add_edge(clock_index, rr_switch_idx); |
| } |
| |
| // Connect to y-channel wires |
| unsigned num_wires_y = y_wire_indices.size() * fc; |
| for (size_t i = 0; i < num_wires_y; i++) { |
| rr_nodes[y_wire_indices[i]].add_edge(clock_index, rr_switch_idx); |
| } |
| } |
| } |
| |
| /* |
| * ClockToClockConneciton (setters) |
| */ |
| |
| void ClockToClockConneciton::set_from_clock_name(std::string clock_name) { |
| from_clock = clock_name; |
| } |
| |
| void ClockToClockConneciton::set_from_clock_switch_point_name(std::string switch_point_name) { |
| from_switch = switch_point_name; |
| } |
| |
| void ClockToClockConneciton::set_to_clock_name(std::string clock_name) { |
| to_clock = clock_name; |
| } |
| |
| void ClockToClockConneciton::set_to_clock_switch_point_name(std::string switch_point_name) { |
| to_switch = switch_point_name; |
| } |
| |
| void ClockToClockConneciton::set_switch(int rr_switch_index) { |
| rr_switch_idx = rr_switch_index; |
| } |
| |
| void ClockToClockConneciton::set_fc_val(float fc_val) { |
| fc = fc_val; |
| } |
| |
| /* |
| * ClockToClockConneciton (member functions) |
| */ |
| |
| void ClockToClockConneciton::create_switches(const ClockRRGraphBuilder& clock_graph) { |
| auto& device_ctx = g_vpr_ctx.mutable_device(); |
| auto& grid = device_ctx.grid; |
| auto& rr_nodes = device_ctx.rr_nodes; |
| |
| auto to_locations = clock_graph.get_switch_locations(to_clock, to_switch); |
| |
| for (auto location : to_locations) { |
| auto x = location.first; |
| auto y = location.second; |
| |
| auto to_rr_node_indices = clock_graph.get_rr_node_indices_at_switch_location( |
| to_clock, |
| to_switch, |
| x, |
| y); |
| |
| // boundry conditions: |
| // y at gird height and height -1 connections share the same drive point |
| if (y == int(grid.height() - 2)) { |
| y = y - 1; |
| } |
| // y at 0 and y at 1 share the same drive point |
| if (y == 0) { |
| y = 1; |
| } |
| |
| auto from_rr_node_indices = clock_graph.get_rr_node_indices_at_switch_location( |
| from_clock, |
| from_switch, |
| x, |
| y); |
| |
| auto from_itter = from_rr_node_indices.begin(); |
| size_t num_connections = ceil(from_rr_node_indices.size() * fc); |
| |
| // Create a one to one connection from each chanx wire to the chany wire |
| // or vice versa. If there are more chanx wire than chany wire or vice versa |
| // then wrap around and start a one to one connection starting with the first node. |
| // This ensures that each wire gets a connection. |
| for (auto to_index : to_rr_node_indices) { |
| for (size_t i = 0; i < num_connections; i++) { |
| if (from_itter == from_rr_node_indices.end()) { |
| from_itter = from_rr_node_indices.begin(); |
| } |
| rr_nodes[*from_itter].add_edge(to_index, rr_switch_idx); |
| from_itter++; |
| } |
| } |
| } |
| } |
| |
| /* |
| * ClockToPinsConnection (setters) |
| */ |
| |
| void ClockToPinsConnection::set_clock_name_to_connect_from(std::string clock_name) { |
| clock_to_connect_from = clock_name; |
| } |
| |
| void ClockToPinsConnection::set_clock_switch_point_name( |
| std::string connection_switch_point_name) { |
| switch_point_name = connection_switch_point_name; |
| } |
| |
| void ClockToPinsConnection::set_switch(int rr_switch_index) { |
| rr_switch_idx = rr_switch_index; |
| } |
| |
| void ClockToPinsConnection::set_fc_val(float fc_val) { |
| fc = fc_val; |
| } |
| |
| /* |
| * ClockToPinsConnection (member functions) |
| */ |
| |
| void ClockToPinsConnection::create_switches(const ClockRRGraphBuilder& clock_graph) { |
| auto& device_ctx = g_vpr_ctx.mutable_device(); |
| auto& rr_nodes = device_ctx.rr_nodes; |
| auto& rr_node_indices = device_ctx.rr_node_indices; |
| auto& grid = device_ctx.grid; |
| |
| for (size_t x = 0; x < grid.width(); x++) { |
| for (size_t y = 0; y < grid.height(); y++) { |
| //Avoid boundry |
| if ((y == 0 && x == 0) || (x == grid.width() - 1 && y == grid.height() - 1)) { |
| continue; |
| } |
| |
| auto type = grid[x][y].type; |
| auto width_offset = grid[x][y].width_offset; |
| auto height_offset = grid[x][y].height_offset; |
| |
| // Ignore gird locations that do not have blocks |
| if (!logical_block_type(type)->pb_type) { |
| continue; |
| } |
| |
| for (e_side side : SIDES) { |
| //Don't connect pins which are not adjacent to channels around the perimeter |
| if ((x == 0 && side != RIGHT) || (x == grid.width() - 1 && side != LEFT) || (y == 0 && side != TOP) || (y == grid.height() - 1 && side != BOTTOM)) { |
| continue; |
| } |
| |
| for (auto clock_pin_idx : type->get_clock_pins_indices()) { |
| //Can't do anything if pin isn't at this location |
| if (0 == type->pinloc[width_offset][height_offset][side][clock_pin_idx]) { |
| continue; |
| } |
| |
| //Adjust boundry connections (TODO: revisist if chany connections) |
| int clock_x_offset = 0; |
| int clock_y_offset = 0; |
| if (x == 0) { |
| clock_x_offset = 1; // chanx clock always starts at 1 offset |
| clock_y_offset = -1; // pick the chanx below the block |
| } else if (x == grid.width() - 1) { |
| clock_x_offset = -1; // chanx clock always ends at 1 offset |
| clock_y_offset = -1; // pick the chanx below the block |
| } else if (y == 0) { |
| clock_y_offset = 0; // pick chanx above the block, no offset needed |
| } else { |
| clock_y_offset = -1; // pick the chanx below the block |
| } |
| |
| auto clock_pin_node_idx = get_rr_node_index( |
| rr_node_indices, |
| x, |
| y, |
| IPIN, |
| clock_pin_idx, |
| side); |
| |
| auto clock_network_indices = clock_graph.get_rr_node_indices_at_switch_location( |
| clock_to_connect_from, |
| switch_point_name, |
| x + clock_x_offset, |
| y + clock_y_offset); |
| |
| //Create edges depending on Fc |
| for (size_t i = 0; i < clock_network_indices.size() * fc; i++) { |
| rr_nodes[clock_network_indices[i]].add_edge(clock_pin_node_idx, rr_switch_idx); |
| } |
| } |
| } |
| } |
| } |
| } |