diff --git a/vpr/src/draw/draw.cpp b/vpr/src/draw/draw.cpp index 0061fad803..8a63c00285 100644 --- a/vpr/src/draw/draw.cpp +++ b/vpr/src/draw/draw.cpp @@ -658,7 +658,7 @@ int get_track_num(int inode, const vtr::OffsetMatrix& chanx_track, const vt * could be caused by the user clicking on a routing resource, toggled, or * fan-in/fan-out of a highlighted node. */ -bool draw_if_net_highlighted(ClusterNetId inet) { +bool draw_if_net_highlighted(ParentNetId inet) { t_draw_state* draw_state = get_draw_state_vars(); if (draw_state->net_color[inet] != DEFAULT_RR_NODE_COLOR) { diff --git a/vpr/src/draw/draw.h b/vpr/src/draw/draw.h index 6224bf49b9..294e3d37ff 100644 --- a/vpr/src/draw/draw.h +++ b/vpr/src/draw/draw.h @@ -94,7 +94,7 @@ ezgl::color to_ezgl_color(vtr::Color color); /* This helper function determines whether a net has been highlighted. The highlighting * could be caused by the user clicking on a routing resource, toggled, or * fan-in/fan-out of a highlighted node. */ -bool draw_if_net_highlighted(ClusterNetId inet); +bool draw_if_net_highlighted(ParentNetId inet); std::vector trace_routed_connection_rr_nodes( ClusterNetId net_id, int driver_pin, diff --git a/vpr/src/draw/draw_basic.cpp b/vpr/src/draw/draw_basic.cpp index bd0d0495a0..ecd956f54d 100644 --- a/vpr/src/draw/draw_basic.cpp +++ b/vpr/src/draw/draw_basic.cpp @@ -357,7 +357,7 @@ void draw_congestion(ezgl::renderer* g) { case e_rr_type::IPIN: //fallthrough case e_rr_type::OPIN: - draw_rr_pin(inode, color, g); + draw_cluster_pin(inode, color, g); break; default: break; @@ -569,13 +569,9 @@ void drawroute(enum e_draw_net_type draw_net_type, ezgl::renderer* g) { void draw_routed_net(ParentNetId net_id, ezgl::renderer* g) { auto& route_ctx = g_vpr_ctx.routing(); - auto& cluster_ctx = g_vpr_ctx.clustering(); t_draw_state* draw_state = get_draw_state_vars(); - if (cluster_ctx.clb_nlist.net_is_ignored(convert_to_cluster_net_id(net_id))) /* Don't draw. */ - return; - if (!route_ctx.route_trees[net_id]) // No routing -> Skip. (Allows me to draw partially complete routes) return; @@ -583,10 +579,10 @@ void draw_routed_net(ParentNetId net_id, ezgl::renderer* g) { for (auto& rt_node : route_ctx.route_trees[net_id].value().all_nodes()) { RRNodeId inode = rt_node.inode; - if (draw_if_net_highlighted(convert_to_cluster_net_id(net_id))) { + if (draw_if_net_highlighted(net_id)) { /* If a net has been highlighted, highlight the whole net in * * the same color. */ - draw_state->draw_rr_node[inode].color = draw_state->net_color[convert_to_cluster_net_id(net_id)]; + draw_state->draw_rr_node[inode].color = draw_state->net_color[net_id]; draw_state->draw_rr_node[inode].node_highlighted = true; } else { /* If not highlighted, draw the node in default color. */ @@ -616,138 +612,168 @@ void draw_partial_route(const std::vector& rr_nodes_to_draw, ezgl::ren auto& device_ctx = g_vpr_ctx.device(); const auto& rr_graph = device_ctx.rr_graph; - static vtr::OffsetMatrix chanx_track; /* [1..device_ctx.grid.width() - 2][0..device_ctx.grid.height() - 2] */ - static vtr::OffsetMatrix chany_track; /* [0..device_ctx.grid.width() - 2][1..device_ctx.grid.height() - 2] */ - if (draw_state->draw_route_type == e_route_type::GLOBAL) { - /* Allocate some temporary storage if it's not already available. */ - int width = (int)device_ctx.grid.width(); - int height = (int)device_ctx.grid.height(); - if (chanx_track.empty()) { - chanx_track = vtr::OffsetMatrix({{{1, width - 1}, {0, height - 1}}}); + // Draw RR Nodes + for (size_t i = 1; i < rr_nodes_to_draw.size(); ++i) { + RRNodeId inode = rr_nodes_to_draw[i]; + e_rr_type rr_type = rr_graph.node_type(inode); + bool is_inode_inter_cluster = is_inter_cluster_node(rr_graph, inode); + int node_layer = rr_graph.node_layer(inode); + + ezgl::color color = draw_state->draw_rr_node[inode].color; + + // For 3D architectures, draw only visible layers + if (!draw_state->draw_layer_display[node_layer].visible) { + continue; } - if (chany_track.empty()) { - chany_track = vtr::OffsetMatrix({{{0, width - 1}, {1, height - 1}}}); + // Skip drawing sources and sinks + if (rr_type == e_rr_type::SINK || rr_type == e_rr_type::SOURCE) { + continue; } - for (int i = 1; i < width - 1; i++) - for (int j = 0; j < height - 1; j++) - chanx_track[i][j] = (-1); + // Draw intra-cluster nodes + if (!is_inode_inter_cluster) { + draw_rr_intra_cluster_pin(inode, color, g); + continue; + } + + // Draw cluster-level IO Pins + if (rr_type == e_rr_type::OPIN || rr_type == e_rr_type::IPIN) { + draw_cluster_pin(inode, color, g); + continue; + } - for (int i = 0; i < width - 1; i++) - for (int j = 1; j < height - 1; j++) - chany_track[i][j] = (-1); + // Draw Channels + if (rr_type == e_rr_type::CHANY || rr_type == e_rr_type::CHANX) { + draw_rr_chan(inode, color, g); + continue; + } } + // Draw Edges for (size_t i = 1; i < rr_nodes_to_draw.size(); ++i) { + RRNodeId inode = rr_nodes_to_draw[i]; auto rr_type = rr_graph.node_type(inode); + bool inode_inter_cluster = is_inter_cluster_node(rr_graph, inode); + int current_node_layer = rr_graph.node_layer(inode); RRNodeId prev_node = rr_nodes_to_draw[i - 1]; auto prev_type = rr_graph.node_type(RRNodeId(prev_node)); + bool prev_node_inter_cluster = is_inter_cluster_node(rr_graph, prev_node); + int prev_node_layer = rr_graph.node_layer(prev_node); - if (!is_inter_cluster_node(rr_graph, prev_node) || !is_inter_cluster_node(rr_graph, inode)) { + t_draw_layer_display edge_visibility = get_element_visibility_and_transparency(prev_node_layer, current_node_layer); + ezgl::color color = draw_state->draw_rr_node[inode].color; + + // For 3D architectures, draw only visible layers + if (!draw_state->draw_layer_display[current_node_layer].visible || !edge_visibility.visible) { continue; } - auto iedge = find_edge(prev_node, inode); - auto switch_type = rr_graph.edge_switch(RRNodeId(prev_node), iedge); + // Skip drawing edges to or from sources and sinks + if (rr_type == e_rr_type::SINK || rr_type == e_rr_type::SOURCE || prev_type == e_rr_type::SINK || prev_type == e_rr_type::SOURCE) { + continue; + } - int current_node_layer = rr_graph.node_layer(inode); - int prev_node_layer = rr_graph.node_layer(prev_node); - t_draw_layer_display edge_visibility = get_element_visibility_and_transparency(prev_node_layer, current_node_layer); + g->set_color(color, edge_visibility.alpha); - //Don't draw node if the layer of the node is not set to visible on screen - if (!draw_state->draw_layer_display[current_node_layer].visible) { + if (!inode_inter_cluster && !prev_node_inter_cluster) { + draw_intra_cluster_edge(inode, prev_node, g); continue; } - ezgl::color color = draw_state->draw_rr_node[inode].color; - - switch (rr_type) { - case e_rr_type::OPIN: { - draw_rr_pin(inode, color, g); - break; + // Default side for pin in case none can be found + e_side pin_side = e_side::TOP; + if (!prev_node_inter_cluster && inode_inter_cluster) { + // draw intra-cluster pin to inter-cluster pin + // node i + 1 is the channel node + if (i + 1 < rr_nodes_to_draw.size()) { + pin_side = get_pin_side(inode, rr_nodes_to_draw[i + 1]); } - case e_rr_type::IPIN: { - draw_rr_pin(inode, color, g); - if (edge_visibility.visible) { - g->set_color(color, edge_visibility.alpha); - if (rr_graph.node_type(prev_node) == e_rr_type::OPIN) { - draw_pin_to_pin(prev_node, inode, g); - } else { - draw_pin_to_chan_edge(inode, prev_node, g); - } - } - break; - } - case e_rr_type::CHANX: { - if (draw_state->draw_route_type == e_route_type::GLOBAL) - chanx_track[rr_graph.node_xlow(inode)][rr_graph.node_ylow(inode)]++; - draw_rr_chan(inode, color, g); - if (edge_visibility.visible) { - g->set_color(color, edge_visibility.alpha); - switch (prev_type) { - case e_rr_type::CHANX: { - draw_chanx_to_chanx_edge(prev_node, inode, switch_type, g); - break; - } - case e_rr_type::CHANY: { - draw_chanx_to_chany_edge(inode, prev_node, FROM_Y_TO_X, switch_type, g); - break; - } - case e_rr_type::OPIN: { - draw_pin_to_chan_edge(prev_node, inode, g); - break; - } - default: { - VPR_ERROR(VPR_ERROR_OTHER, - "Unexpected connection from an rr_node of type %d to one of type %d.\n", - prev_type, rr_type); - } - } - } + draw_intra_cluster_pin_to_pin(prev_node, inode, FROM_INTRA_CLUSTER_TO_INTER_CLUSTER, pin_side, g); + continue; + } - break; + if (prev_node_inter_cluster && !inode_inter_cluster) { + // draw inter-cluster pin to intra-cluster pin + // node i - 2 is the channel node + if (i >= 2) { + pin_side = get_pin_side(prev_node, rr_nodes_to_draw[i - 2]); } - case e_rr_type::CHANY: { - if (draw_state->draw_route_type == e_route_type::GLOBAL) - chany_track[rr_graph.node_xlow(inode)][rr_graph.node_ylow(inode)]++; - draw_rr_chan(inode, color, g); + draw_intra_cluster_pin_to_pin(inode, prev_node, FROM_INTER_CLUSTER_TO_INTRA_CLUSTER, pin_side, g); + continue; + } - if (edge_visibility.visible) { - g->set_color(color, edge_visibility.alpha); - switch (prev_type) { - case e_rr_type::CHANX: { - draw_chanx_to_chany_edge(prev_node, inode, - FROM_X_TO_Y, switch_type, g); - break; - } - case e_rr_type::CHANY: { - draw_chany_to_chany_edge(RRNodeId(prev_node), RRNodeId(inode), - switch_type, g); - break; - } - case e_rr_type::OPIN: { - draw_pin_to_chan_edge(prev_node, inode, g); + draw_inter_cluster_rr_edge(inode, prev_node, rr_type, prev_type, g); + } +} - break; - } - default: { - VPR_ERROR(VPR_ERROR_OTHER, - "Unexpected connection from an rr_node of type %d to one of type %d.\n", - prev_type, rr_type); - } - } - } +void draw_inter_cluster_rr_edge(RRNodeId inode, RRNodeId prev_node, e_rr_type rr_type, e_rr_type prev_type, ezgl::renderer* g) { + const RRGraphView& rr_graph = g_vpr_ctx.device().rr_graph; + t_edge_size iedge = find_edge(prev_node, inode); + short switch_type = rr_graph.edge_switch(RRNodeId(prev_node), iedge); - break; + switch (rr_type) { + case e_rr_type::IPIN: { + if (prev_type == e_rr_type::OPIN) { + draw_pin_to_pin(prev_node, inode, g); + } else { + draw_pin_to_chan_edge(inode, prev_node, g); } - default: { - break; + break; + } + case e_rr_type::CHANX: { + switch (prev_type) { + case e_rr_type::CHANX: { + draw_chanx_to_chanx_edge(prev_node, inode, switch_type, g); + break; + } + case e_rr_type::CHANY: { + draw_chanx_to_chany_edge(inode, prev_node, FROM_Y_TO_X, switch_type, g); + break; + } + case e_rr_type::OPIN: { + draw_pin_to_chan_edge(prev_node, inode, g); + break; + } + default: { + VPR_ERROR(VPR_ERROR_OTHER, + "Unexpected connection from an rr_node of type %d to one of type %d.\n", + prev_type, rr_type); + } } + break; + } + case e_rr_type::CHANY: { + switch (prev_type) { + case e_rr_type::CHANX: { + draw_chanx_to_chany_edge(prev_node, inode, + FROM_X_TO_Y, switch_type, g); + break; + } + case e_rr_type::CHANY: { + draw_chany_to_chany_edge(RRNodeId(prev_node), RRNodeId(inode), + switch_type, g); + break; + } + case e_rr_type::OPIN: { + draw_pin_to_chan_edge(prev_node, inode, g); + + break; + } + default: { + VPR_ERROR(VPR_ERROR_OTHER, + "Unexpected connection from an rr_node of type %d to one of type %d.\n", + prev_type, rr_type); + } + } + break; + } + default: { + break; } } } diff --git a/vpr/src/draw/draw_basic.h b/vpr/src/draw/draw_basic.h index 3af8165b9a..cad390861a 100644 --- a/vpr/src/draw/draw_basic.h +++ b/vpr/src/draw/draw_basic.h @@ -57,6 +57,13 @@ void draw_routed_net(ParentNetId net, ezgl::renderer* g); void draw_partial_route(const std::vector& rr_nodes_to_draw, ezgl::renderer* g); +/** @brief Draws an edge between two rr_nodes, which are both intra-cluster nodes. + * @param inode The current rr_node id + * @param prev_node The previous rr_node id + * @param g The ezgl renderer + */ +void draw_inter_cluster_rr_edge(RRNodeId inode, RRNodeId prev_node, e_rr_type rr_type, e_rr_type prev_type, ezgl::renderer* g); + /** * @brief Returns the layer number of a timing path node * @param node diff --git a/vpr/src/draw/draw_rr.cpp b/vpr/src/draw/draw_rr.cpp index 156147c17e..eca0b5b017 100644 --- a/vpr/src/draw/draw_rr.cpp +++ b/vpr/src/draw/draw_rr.cpp @@ -107,12 +107,12 @@ void draw_rr(ezgl::renderer* g) { break; case e_rr_type::IPIN: - draw_rr_pin(inode, draw_state->draw_rr_node[inode].color, g); + draw_cluster_pin(inode, draw_state->draw_rr_node[inode].color, g); draw_rr_edges(inode, g); break; case e_rr_type::OPIN: - draw_rr_pin(inode, draw_state->draw_rr_node[inode].color, g); + draw_cluster_pin(inode, draw_state->draw_rr_node[inode].color, g); draw_rr_edges(inode, g); break; @@ -513,10 +513,30 @@ void draw_rr_edges(RRNodeId inode, ezgl::renderer* g) { } /* End of for each edge loop */ } +void draw_rr_intra_cluster_pin(RRNodeId inode, const ezgl::color& color, ezgl::renderer* g) { + t_draw_state* draw_state = get_draw_state_vars(); + t_draw_coords* draw_coords = get_draw_coords_vars(); + + if (!draw_state->is_flat) { + return; + } + + auto [blk_id, pin_id] = get_rr_node_cluster_blk_id_pb_graph_pin(inode); + + ezgl::point2d p = draw_coords->get_absolute_pin_location(blk_id, pin_id); + + int transparency_factor = get_rr_node_transparency(inode); + + g->set_color(color, transparency_factor); + g->fill_rectangle( + {p.x - draw_coords->pin_size, p.y - draw_coords->pin_size}, + {p.x + draw_coords->pin_size, p.y + draw_coords->pin_size}); +} + /* Draws an IPIN or OPIN rr_node. Note that the pin can appear on more * * than one side of a clb. Also note that this routine can change the * * current color to BLACK. */ -void draw_rr_pin(RRNodeId inode, const ezgl::color& color, ezgl::renderer* g) { +void draw_cluster_pin(RRNodeId inode, const ezgl::color& color, ezgl::renderer* g) { t_draw_coords* draw_coords = get_draw_coords_vars(); float xcen, ycen; @@ -683,6 +703,32 @@ RRNodeId draw_check_rr_node_hit(float click_x, float click_y) { if (!draw_state->draw_layer_display[layer_num].visible) { continue; /* Don't check RR nodes on currently invisible layers*/ } + + // Skip Source and Sink Nodes + if (rr_graph.node_type(inode) == e_rr_type::SOURCE + || rr_graph.node_type(inode) == e_rr_type::SINK) { + continue; + } + + // Check for intra cluster nodes + if (!is_inter_cluster_node(rr_graph, inode)) { + + if (!draw_state->is_flat) { + continue; + } + + auto [blk_id, pin_id] = get_rr_node_cluster_blk_id_pb_graph_pin(inode); + ezgl::point2d p = draw_coords->get_absolute_pin_location(blk_id, pin_id); + + if (click_x >= p.x - draw_coords->pin_size && click_x <= p.x + draw_coords->pin_size && click_y >= p.y - draw_coords->pin_size && click_y <= p.y + draw_coords->pin_size) { + hit_node = inode; + return hit_node; + } + + continue; + } + + // Check for inter cluster nodes switch (rr_graph.node_type(inode)) { case e_rr_type::IPIN: case e_rr_type::OPIN: { @@ -820,11 +866,11 @@ void draw_rr_costs(ezgl::renderer* g, const vtr::vector& rr_cos break; case e_rr_type::IPIN: //fallthrough - draw_rr_pin(inode, color, g); + draw_cluster_pin(inode, color, g); if (with_edges) draw_rr_edges(inode, g); break; case e_rr_type::OPIN: - draw_rr_pin(inode, color, g); + draw_cluster_pin(inode, color, g); if (with_edges) draw_rr_edges(inode, g); break; case e_rr_type::SOURCE: diff --git a/vpr/src/draw/draw_rr.h b/vpr/src/draw/draw_rr.h index dd7a305ffc..805352b951 100644 --- a/vpr/src/draw/draw_rr.h +++ b/vpr/src/draw/draw_rr.h @@ -27,18 +27,25 @@ void draw_rr_edges(RRNodeId from_node, ezgl::renderer* g); void draw_rr_chan(RRNodeId inode, const ezgl::color color, ezgl::renderer* g); +/** + * @brief Draws the intra-cluster pin for a given RRNodeId when flat routing is enabled. + */ +void draw_rr_intra_cluster_pin(RRNodeId inode, const ezgl::color& color, ezgl::renderer* g); + /* Draws an IPIN or OPIN rr_node. Note that the pin can appear on more * than one side of a clb. Also note that this routine can change the * current color to BLACK. */ -void draw_rr_pin(RRNodeId inode, const ezgl::color& color, ezgl::renderer* g); +void draw_cluster_pin(RRNodeId inode, const ezgl::color& color, ezgl::renderer* g); void draw_rr_src_sink(RRNodeId inode, ezgl::color color, ezgl::renderer* g); + void draw_get_rr_src_sink_coords(const t_rr_node& node, float* xcen, float* ycen); /* Draws a buffer (triangle) or pass transistor (circle) on the edge * connecting from to to, depending on the status of buffered. The drawing * is closest to the from_node, since it reflects the switch type of from. */ void draw_rr_switch(float from_x, float from_y, float to_x, float to_y, bool buffered, bool switch_configurable, ezgl::renderer* g); + void draw_expand_non_configurable_rr_nodes_recurr(RRNodeId from_node, std::set& expanded_nodes); diff --git a/vpr/src/draw/draw_rr_edges.cpp b/vpr/src/draw/draw_rr_edges.cpp index 85deffe765..eef034e872 100644 --- a/vpr/src/draw/draw_rr_edges.cpp +++ b/vpr/src/draw/draw_rr_edges.cpp @@ -205,7 +205,7 @@ void draw_chanx_to_chanx_edge(RRNodeId from_node, RRNodeId to_node, short switch } } -void draw_chanx_to_chany_edge(RRNodeId chanx_node, RRNodeId chany_node, enum e_edge_dir edge_dir, short switch_type, ezgl::renderer* g) { +void draw_chanx_to_chany_edge(RRNodeId chanx_node, RRNodeId chany_node, enum e_chan_edge_dir edge_dir, short switch_type, ezgl::renderer* g) { t_draw_state* draw_state = get_draw_state_vars(); t_draw_coords* draw_coords = get_draw_coords_vars(); auto& device_ctx = g_vpr_ctx.device(); @@ -279,6 +279,62 @@ void draw_chanx_to_chany_edge(RRNodeId chanx_node, RRNodeId chany_node, enum e_e } } +void draw_intra_cluster_edge(RRNodeId inode, RRNodeId prev_node, ezgl::renderer* g) { + t_draw_state* draw_state = get_draw_state_vars(); + t_draw_coords* draw_coords = get_draw_coords_vars(); + + if (!draw_state->is_flat) { + return; + } + + auto [blk_id, pin_id] = get_rr_node_cluster_blk_id_pb_graph_pin(inode); + auto [prev_blk_id, prev_pin_id] = get_rr_node_cluster_blk_id_pb_graph_pin(prev_node); + + ezgl::point2d icoord = draw_coords->get_absolute_pin_location(blk_id, pin_id); + ezgl::point2d prev_coord = draw_coords->get_absolute_pin_location(prev_blk_id, prev_pin_id); + + g->draw_line(prev_coord, icoord); + + float triangle_coord_x = icoord.x + (prev_coord.x - icoord.x) / 10.; + float triangle_coord_y = icoord.y + (prev_coord.y - icoord.y) / 10.; + draw_triangle_along_line(g, triangle_coord_x, triangle_coord_y, prev_coord.x, icoord.x, prev_coord.y, icoord.y); +} + +void draw_intra_cluster_pin_to_pin(RRNodeId intra_cluster_node, RRNodeId inter_cluster_node, e_pin_edge_dir pin_edge_dir, e_side pin_side, ezgl::renderer* g) { + t_draw_state* draw_state = get_draw_state_vars(); + t_draw_coords* draw_coords = get_draw_coords_vars(); + + if (!draw_state->is_flat) { + return; + } + + // determine the location of the pins + float inter_cluster_x, inter_cluster_y; + ezgl::point2d intra_cluster_coord; + + draw_get_rr_pin_coords(inter_cluster_node, &inter_cluster_x, &inter_cluster_y, pin_side); + + auto [blk_id, pin_id] = get_rr_node_cluster_blk_id_pb_graph_pin(intra_cluster_node); + intra_cluster_coord = draw_coords->get_absolute_pin_location(blk_id, pin_id); + + // determine which coord is first based on the pin edge direction + ezgl::point2d prev_coord, icoord; + if (pin_edge_dir == FROM_INTRA_CLUSTER_TO_INTER_CLUSTER) { + prev_coord = intra_cluster_coord; + icoord = {inter_cluster_x, inter_cluster_y}; + } else if (pin_edge_dir == FROM_INTER_CLUSTER_TO_INTRA_CLUSTER) { + prev_coord = {inter_cluster_x, inter_cluster_y}; + icoord = intra_cluster_coord; + } else { + VPR_ERROR(VPR_ERROR_DRAW, "Invalid pin edge direction: %d", pin_edge_dir); + } + + g->draw_line(prev_coord, icoord); + float triangle_coord_x = icoord.x + (prev_coord.x - icoord.x) / 10.; + float triangle_coord_y = icoord.y + (prev_coord.y - icoord.y) / 10.; + draw_triangle_along_line(g, triangle_coord_x, triangle_coord_y, prev_coord.x, icoord.x, prev_coord.y, icoord.y); +} + void draw_pin_to_pin(RRNodeId opin_node, RRNodeId ipin_node, ezgl::renderer* g) { /* This routine draws an edge from the opin rr node to the ipin rr node */ const auto& device_ctx = g_vpr_ctx.device(); @@ -366,14 +422,8 @@ void draw_source_to_pin(RRNodeId source_node, RRNodeId opin_node, ezgl::renderer } } -void draw_pin_to_chan_edge(RRNodeId pin_node, RRNodeId chan_node, ezgl::renderer* g) { - /* This routine draws an edge from the pin_node to the chan_node (CHANX or * - * CHANY). The connection is made to the nearest end of the track instead * - * of perpendicular to the track to symbolize a single-drive connection. */ +e_side get_pin_side(RRNodeId pin_node, RRNodeId chan_node) { - /* TODO: Fix this for global routing, currently for detailed only */ - - t_draw_coords* draw_coords = get_draw_coords_vars(); auto& device_ctx = g_vpr_ctx.device(); const auto& rr_graph = device_ctx.rr_graph; @@ -386,7 +436,6 @@ void draw_pin_to_chan_edge(RRNodeId pin_node, RRNodeId chan_node, ezgl::renderer int width_offset = device_ctx.grid.get_width_offset(tile_loc); int height_offset = device_ctx.grid.get_height_offset(tile_loc); - float x1 = 0, y1 = 0; /* If there is only one side, no need for the following inference!!! * When a node may have multiple sides, * we lack direct information about which side of the node drives the channel node @@ -454,6 +503,30 @@ void draw_pin_to_chan_edge(RRNodeId pin_node, RRNodeId chan_node, ezgl::renderer /* Sanity check */ VTR_ASSERT(NUM_2D_SIDES != pin_side); + return pin_side; +} + +void draw_pin_to_chan_edge(RRNodeId pin_node, RRNodeId chan_node, ezgl::renderer* g) { + /* This routine draws an edge from the pin_node to the chan_node (CHANX or * + * CHANY). The connection is made to the nearest end of the track instead * + * of perpendicular to the track to symbolize a single-drive connection. */ + + /* TODO: Fix this for global routing, currently for detailed only */ + + t_draw_coords* draw_coords = get_draw_coords_vars(); + auto& device_ctx = g_vpr_ctx.device(); + const auto& rr_graph = device_ctx.rr_graph; + + t_physical_tile_loc tile_loc = { + rr_graph.node_xlow(pin_node), + rr_graph.node_ylow(pin_node), + rr_graph.node_layer(pin_node)}; + + const auto& grid_type = device_ctx.grid.get_physical_type(tile_loc); + const e_rr_type channel_type = rr_graph.node_type(chan_node); + e_side pin_side = get_pin_side(pin_node, chan_node); + + float x1 = 0, y1 = 0; /* Now we determine which side to be used, calculate the offset for the pin to be drawn * - For the pin locates above/right to the grid (at the top/right side), * a positive offset (+ve) is required diff --git a/vpr/src/draw/draw_rr_edges.h b/vpr/src/draw/draw_rr_edges.h index 3b51bd0ab6..fcfb4370c1 100644 --- a/vpr/src/draw/draw_rr_edges.h +++ b/vpr/src/draw/draw_rr_edges.h @@ -17,12 +17,65 @@ #include "ezgl/graphics.hpp" +/** + * @brief Draws the edge between two vertical channel nodes + */ void draw_chany_to_chany_edge(RRNodeId from_node, RRNodeId to_node, short switch_type, ezgl::renderer* g); + +/** + * @brief Draws the edge between two horizontal channel nodes + */ void draw_chanx_to_chanx_edge(RRNodeId from_node, RRNodeId to_node, short switch_type, ezgl::renderer* g); -void draw_chanx_to_chany_edge(RRNodeId chanx_node, RRNodeId chany_node, enum e_edge_dir edge_dir, short switch_type, ezgl::renderer* g); + +/** + * @brief Draws the edge between a horizontal channel node and a vertical channel node + * @param chanx_node The horizontal channel node + * @param chany_node The vertical channel node + * @param edge_dir The direction of the edge, FROM_X_TO_Y or FROM_Y_TO_X + * @param switch_type The type of switch used for the connection + * @param g The ezgl renderer + */ +void draw_chanx_to_chany_edge(RRNodeId chanx_node, RRNodeId chany_node, enum e_chan_edge_dir edge_dir, short switch_type, ezgl::renderer* g); + +/** + * @brief Draws the edge between an intra-cluster pin and an inter-cluster pin when flat routing is enabled. + * @param intra_cluster_node The intra-cluster pin node + * @param inter_cluster_node The inter-cluster pin node + * @param pin_edge_dir The direction of the edge, FROM_INTER_CLUSTER_TO_INTRA_CLUSTER or FROM_INTRA_CLUSTER_TO_INTER_CLUSTER + * @param pin_side The side of the inter-cluster pin (e.g. TOP, RIGHT, BOTTOM, LEFT) + * @param g The ezgl renderer + */ +void draw_intra_cluster_pin_to_pin(RRNodeId intra_cluster_node, RRNodeId inter_cluster_node, e_pin_edge_dir pin_edge_dir, e_side pin_side, ezgl::renderer* g); + +/** + * @brief Draws the edge between two intra-cluster pins when flat routing is enabled. + * @param inode The current node to draw to + * @param prev_node The previous node to draw from + * @param g The ezgl renderer + */ +void draw_intra_cluster_edge(RRNodeId inode, RRNodeId prev_node, ezgl::renderer* g); + +/** + * @brief This routine directly draws an edge from an inter-cluster output pin to an inter-cluster input pin. + */ void draw_pin_to_pin(RRNodeId opin, RRNodeId ipin, ezgl::renderer* g); + +//TODO: These two functions currently do not draw correctly after rearranging the block locations. They need an update. void draw_pin_to_sink(RRNodeId ipin_node, RRNodeId sink_node, ezgl::renderer* g); + void draw_source_to_pin(RRNodeId source_node, RRNodeId opin_node, ezgl::renderer* g); + +/** + * @brief Determines the side of clb, the inter-cluster pin is located on based on the channel node. + * @param pin_node The inter-cluster pin node + * @param chan_node The channel node (CHANX or CHANY) that the pin is connected to + * @return The side of the clb that the pin is located on (e.g. TOP, RIGHT, BOTTOM, LEFT) + */ +e_side get_pin_side(RRNodeId pin_node, RRNodeId chan_node); + +/** + * @brief Draws an edge from a inter-cluster pin node to a channel node (CHANX or CHANY). + */ void draw_pin_to_chan_edge(RRNodeId pin_node, RRNodeId chan_node, ezgl::renderer* g); #endif /* NO_GRAPHICS */ diff --git a/vpr/src/draw/draw_searchbar.cpp b/vpr/src/draw/draw_searchbar.cpp index e80f450af3..cb04be62ee 100644 --- a/vpr/src/draw/draw_searchbar.cpp +++ b/vpr/src/draw/draw_searchbar.cpp @@ -131,40 +131,60 @@ void draw_highlight_blocks_color(t_logical_block_type_ptr type, /* If an rr_node has been clicked on, it will be highlighted in MAGENTA. * If so, and toggle nets is selected, highlight the whole net in that colour. */ -void highlight_nets(char* message, RRNodeId hit_node, bool is_flat) { +void highlight_nets(char* message, RRNodeId hit_node) { auto& cluster_ctx = g_vpr_ctx.clustering(); + auto& atom_ctx = g_vpr_ctx.atom(); auto& route_ctx = g_vpr_ctx.routing(); - /* Don't crash if there's no routing */ + // Don't crash if there's no routing if (route_ctx.route_trees.empty()) return; + if (route_ctx.is_flat) { + for (AtomNetId net_id : atom_ctx.netlist().nets()) { + check_node_highlight_net(message, net_id, hit_node); + } + + } else { + for (ClusterNetId net_id : cluster_ctx.clb_nlist.nets()) { + check_node_highlight_net(message, net_id, hit_node); + } + } + + application.update_message(message); +} + +std::string draw_get_net_name(ParentNetId parent_id) { + if (!g_vpr_ctx.routing().is_flat) { + return g_vpr_ctx.clustering().clb_nlist.net_name(convert_to_cluster_net_id(parent_id)); + } else { + return g_vpr_ctx.atom().netlist().net_name(convert_to_atom_net_id(parent_id)); + } +} + +void check_node_highlight_net(char* message, ParentNetId parent_net_id, RRNodeId hit_node) { + auto& route_ctx = g_vpr_ctx.routing(); t_draw_state* draw_state = get_draw_state_vars(); - for (auto net_id : cluster_ctx.clb_nlist.nets()) { - ParentNetId parent_id = get_cluster_net_parent_id(g_vpr_ctx.atom().lookup(), net_id, is_flat); - if (!route_ctx.route_trees[parent_id]) - continue; + if (!route_ctx.route_trees[parent_net_id]) + return; - for (auto& rt_node : route_ctx.route_trees[parent_id].value().all_nodes()) { - RRNodeId inode = rt_node.inode; - if (draw_state->draw_rr_node[inode].color == ezgl::MAGENTA) { - draw_state->net_color[net_id] = draw_state->draw_rr_node[inode].color; - if (inode == hit_node) { - std::string orig_msg(message); - sprintf(message, "%s || Net: %zu (%s)", orig_msg.c_str(), - size_t(net_id), - cluster_ctx.clb_nlist.net_name(net_id).c_str()); - } - } else if (draw_state->draw_rr_node[inode].color - == ezgl::WHITE) { - // If node is de-selected. - draw_state->net_color[net_id] = ezgl::BLACK; - break; + for (const RouteTreeNode& rt_node : route_ctx.route_trees[parent_net_id].value().all_nodes()) { + RRNodeId inode = rt_node.inode; + if (draw_state->draw_rr_node[inode].color == ezgl::MAGENTA) { + draw_state->net_color[parent_net_id] = draw_state->draw_rr_node[inode].color; + if (inode == hit_node) { + std::string orig_msg(message); + sprintf(message, "%s || Net: %zu (%s)", orig_msg.c_str(), + size_t(parent_net_id), + draw_get_net_name(parent_net_id).c_str()); } + } else if (draw_state->draw_rr_node[inode].color == ezgl::WHITE) { + // If node is de-selected. + draw_state->net_color[parent_net_id] = ezgl::BLACK; + break; } } - application.update_message(message); } /* If an rr_node has been clicked on, it will be either highlighted in MAGENTA, diff --git a/vpr/src/draw/draw_searchbar.h b/vpr/src/draw/draw_searchbar.h index 7d195dde98..59582ee529 100644 --- a/vpr/src/draw/draw_searchbar.h +++ b/vpr/src/draw/draw_searchbar.h @@ -26,9 +26,26 @@ ezgl::rectangle draw_get_rr_chan_bbox(RRNodeId inode); /* Highlights a block and its fanout/fanin. */ void draw_highlight_blocks_color(t_logical_block_type_ptr type, ClusterBlockId blk_id); -/* If an rr_node has been clicked on, it will be highlighted in MAGENTA. - * If so, and toggle nets is selected, highlight the whole net in that colour.*/ -void highlight_nets(char* message, RRNodeId hit_node, bool is_flat); +/** + * @brief Highlights the net associated with the specified RRNodeId in Magenta. De-highlights all other nets. Also appends relevant net information to the provided message char pointer. + * + * @param message A message which we want to update by appending additional net information. + * @param hit_node The RRNodeId of the routing resource node whose net should be highlighted. + */ +void highlight_nets(char* message, RRNodeId hit_node); + +/** + * @brief Returns the name of the net associated with a ParentNetId. + */ +std::string draw_get_net_name(ParentNetId parent_id); + +/** + * @brief Determines if a given RRNode is part of the specified net and highlights the net if so. Additionally, appends relevant net information to the provided message char pointer. + * @param message Pointer to a character array where additional net information will be appended. + * @param parent_net_id The ParentNetId representing the net to check. This may refer to either atom or cluster nets. + * @param hit_node The RRNodeId of the node that was selected. + */ +void check_node_highlight_net(char* message, ParentNetId parent_net_id, RRNodeId hit_node); /* If an rr_node has been clicked on, it will be either highlighted in MAGENTA, * or de-highlighted in WHITE. If highlighted, and toggle_rr is selected, highlight diff --git a/vpr/src/draw/draw_toggle_functions.cpp b/vpr/src/draw/draw_toggle_functions.cpp index 4800ac14e2..f97c286dac 100644 --- a/vpr/src/draw/draw_toggle_functions.cpp +++ b/vpr/src/draw/draw_toggle_functions.cpp @@ -235,7 +235,7 @@ void toggle_blk_internal_cbk(GtkSpinButton* self, ezgl::application* app) { if (new_value < 0) draw_state->show_blk_internal = 0; else if (new_value >= draw_state->max_sub_blk_lvl) - draw_state->show_blk_internal = draw_state->max_sub_blk_lvl - 1; + draw_state->show_blk_internal = draw_state->max_sub_blk_lvl; else draw_state->show_blk_internal = new_value; app->refresh_drawing(); diff --git a/vpr/src/draw/draw_types.cpp b/vpr/src/draw/draw_types.cpp index 0394084364..76d52fbe59 100644 --- a/vpr/src/draw/draw_types.cpp +++ b/vpr/src/draw/draw_types.cpp @@ -151,6 +151,28 @@ ezgl::rectangle t_draw_coords::get_absolute_pb_bbox(const ClusterBlockId clb_ind return result; } +ezgl::point2d t_draw_coords::get_absolute_pin_location(const ClusterBlockId clb_index, const t_pb_graph_pin* pb_graph_pin) { + // Pins are positioned on a horizontal row at the top of each internal block. + + t_pb_graph_node* pb_gnode = pb_graph_pin->parent_node; + ezgl::rectangle pb_bbox = this->get_absolute_pb_bbox(clb_index, pb_gnode); + + // Calculate the pin location based on the pin number and the total number of pins in the block. + int num_pins = pb_gnode->num_pins(); + int num_pin = pb_graph_pin->pin_number; + for (int i = 0; i < pb_graph_pin->port->index; ++i) { + num_pin += pb_gnode->pb_type->ports[i].num_pins; + } + + // horizontal spacing between pins + float interval = pb_bbox.width() / (num_pins + 1); + + // vertical spacing between pins and top edge of the block + const float Y_PIN_OFFSET = 0.01; + + return ezgl::point2d(interval * (num_pin + 1), -Y_PIN_OFFSET * this->tile_width) + pb_bbox.top_left(); +} + ezgl::rectangle t_draw_coords::get_absolute_clb_bbox(const ClusterBlockId clb_index, const t_logical_block_type_ptr block_type) { t_draw_state* draw_state = get_draw_state_vars(); const auto& block_locs = draw_state->get_graphics_blk_loc_registry_ref().block_locs(); diff --git a/vpr/src/draw/draw_types.h b/vpr/src/draw/draw_types.h index 56d6d96985..e7106a5107 100644 --- a/vpr/src/draw/draw_types.h +++ b/vpr/src/draw/draw_types.h @@ -110,12 +110,18 @@ enum e_draw_net_type { HIGHLIGHTED }; -/* Chanx to chany or vice versa? */ -enum e_edge_dir { +/// Chanx to chany or vice versa? +enum e_chan_edge_dir { FROM_X_TO_Y, FROM_Y_TO_X }; +/// From inter-cluster pin to intra-cluster pin or vice versa? +enum e_pin_edge_dir { + FROM_INTER_CLUSTER_TO_INTRA_CLUSTER, + FROM_INTRA_CLUSTER_TO_INTER_CLUSTER +}; + /* * Defines the type of drawings that can be generated for the NoC. * DRAW_NO_NOC -> user did not select the option to draw the NoC @@ -432,6 +438,14 @@ struct t_draw_coords { */ ezgl::rectangle get_absolute_pb_bbox(const ClusterBlockId clb_index, const t_pb_graph_node* pb_gnode); + /** + * @brief returns a 2D point for the absolute location of the given pb_graph_pin in the entire graphics context. + * @param clb_index The index of the cluster block containing the pin. + * @param pb_graph_pin The pin for which the absolute location is requested. + * @return A point2d representing the absolute coordinates of the pin. + */ + ezgl::point2d get_absolute_pin_location(const ClusterBlockId clb_index, const t_pb_graph_pin* pb_graph_pin); + ///@brief Returns bounding box for CLB of given idx/type ezgl::rectangle get_absolute_clb_bbox(const ClusterBlockId clb_index, const t_logical_block_type_ptr type); diff --git a/vpr/src/draw/intra_logic_block.cpp b/vpr/src/draw/intra_logic_block.cpp index d30bded969..7450f1279a 100644 --- a/vpr/src/draw/intra_logic_block.cpp +++ b/vpr/src/draw/intra_logic_block.cpp @@ -34,11 +34,47 @@ #include "draw.h" #include "draw_triangle.h" +// Vertical padding (as a fraction of tile height) added to leave space for text inside internal logic blocks +constexpr float FRACTION_TEXT_PADDING = 0.01; + /************************* Subroutines local to this file. *******************************/ +/** + * @brief A recursive function which traverses through each sub-block of a pb_graph_node, calculates bounding boxes for each sub-block, and stores the bounding boxes in the global draw_coords variable. + * @param type_descrip_index The index of the logical block type. + * @param pb_graph_node The pb_graph_node. + * @param parent_width The width of the parent block. + * @param parent_height The height of the parent block. + */ static void draw_internal_load_coords(int type_descrip_index, t_pb_graph_node* pb_graph_node, float parent_width, float parent_height); + +/** + * @brief Finds the maximum depth of sub-blocks for a given pb_type. + * @param pb_type The top-level pb_type. + * @return The maximum level for the given pb_type. + */ static int draw_internal_find_max_lvl(const t_pb_type& pb_type); -static void draw_internal_calc_coords(int type_descrip_index, t_pb_graph_node* pb_graph_node, int num_pb_types, int type_index, int num_pb, int pb_index, float parent_width, float parent_height, float* blk_width, float* blk_height); +/** + * @brief A helper function to calculate the number of child blocks for a given t_mode. + * @param mode The mode of the parent pb_type. + * @return The number of child blocks for the given t_mode. + */ +static int get_num_child_blocks(const t_mode& mode); +/** + * @brief A helper function for draw_internal_load_coords. + * Calculates the coordinates of a internal block and stores its bounding box inside global variables. + * The calculated width and height of the block are also assigned to the pointers blk_width and blk_height. + * @param type_descrip_index The index of the logical block type. + * @param pb_graph_node The pb_graph_node of the logical block type. + * @param blk_num Each logical block type has num_modes * num_pb_type_children sub-blocks. blk_num is the index of the sub-block within the logical block type. + * @param num_columns Number of columns of blocks to draw in the parent block type. + * @param num_rows Number of rows of blocks to draw in the parent block type. + * @param parent_width The width of the parent block. + * @param parent_height The height of the parent block. + * @param blk_width Pointer to store the calculated width of the block. + * @param blk_height Pointer to store the calculated height of the block. + */ +static void draw_internal_calc_coords(int type_descrip_index, t_pb_graph_node* pb_graph_node, int blk_num, int num_columns, int num_rows, float parent_width, float parent_height, float* blk_width, float* blk_height); std::vector collect_pb_atoms(const t_pb* pb); void collect_pb_atoms_recurr(const t_pb* pb, std::vector& atoms); t_pb* highlight_sub_block_helper(const ClusterBlockId clb_index, t_pb* pb, const ezgl::point2d& local_pt, int max_depth); @@ -214,6 +250,15 @@ static int draw_internal_find_max_lvl(const t_pb_type& pb_type) { return max_levels; } +static int get_num_child_blocks(const t_mode& mode) { + // not all child_pb_types have the same number of physical blocks, so we have to manually loop through and count the physical blocks + int num_blocks = 0; + for (int j = 0; j < mode.num_pb_type_children; ++j) { + num_blocks += mode.pb_type_children[j].num_pb; + } + return num_blocks; +} + /* Helper function for initializing bounding box values for each sub-block. This function * traverses through the pb_graph for a descriptor_type (given by type_descrip_index), and * calls helper function to compute bounding box values. @@ -232,23 +277,48 @@ static void draw_internal_load_coords(int type_descrip_index, t_pb_graph_node* p for (int i = 0; i < num_modes; ++i) { t_mode mode = pb_type->modes[i]; int num_children = mode.num_pb_type_children; + int num_blocks = get_num_child_blocks(mode); + int blk_num = 0; for (int j = 0; j < num_children; ++j) { - /* Find the number of instances for each child pb_type. */ + // Find the number of instances for each child pb_type. int num_pb = mode.pb_type_children[j].num_pb; + // Determine how we want to arrange the sub-blocks in the parent block. + // We want the blocks to be squarish, and not too wide or too tall. + // In other words, we want the number of rows to be as close to the number of columns as possible such that + // num_rows * num_columns = num_blocks. + // first, determine the "middle" factor for the number of columns + int num_columns = 1; + for (int k = 1; k * k <= num_blocks; ++k) { + if (num_blocks % k == 0) { + num_columns = k; + } + } + int num_rows = num_blocks / num_columns; + // Currently num_rows >= num_columns + + // If blocks are too wide, swap num_rows and num_columns, so that num_rows <= num_columns. + const int MAX_WIDTH_HEIGHT_RATIO = 2; + if (parent_width > parent_height * MAX_WIDTH_HEIGHT_RATIO) { + std::swap(num_columns, num_rows); + } + for (int k = 0; k < num_pb; ++k) { - /* Compute bound box for block. Don't call if pb_type is root-level pb. */ + + // Compute bound box for block. Don't call if pb_type is root-level pb. draw_internal_calc_coords(type_descrip_index, &pb_graph_node->child_pb_graph_nodes[i][j][k], - num_children, j, num_pb, k, + blk_num, num_columns, num_rows, parent_width, parent_height, &blk_width, &blk_height); - /* Traverse to next level in the pb_graph */ + // Traverse to next level in the pb_graph draw_internal_load_coords(type_descrip_index, &pb_graph_node->child_pb_graph_nodes[i][j][k], blk_width, blk_height); + + blk_num++; } } } @@ -258,56 +328,47 @@ static void draw_internal_load_coords(int type_descrip_index, t_pb_graph_node* p * are relative to the left and bottom corner of the parent block. */ static void -draw_internal_calc_coords(int type_descrip_index, t_pb_graph_node* pb_graph_node, int num_pb_types, int type_index, int num_pb, int pb_index, float parent_width, float parent_height, float* blk_width, float* blk_height) { - t_draw_state* draw_state = get_draw_state_vars(); - const auto& device_ctx = g_vpr_ctx.device(); - const auto& grid_blocks = draw_state->get_graphics_blk_loc_registry_ref().grid_blocks(); +draw_internal_calc_coords(int type_descrip_index, t_pb_graph_node* pb_graph_node, int blk_num, int num_columns, int num_rows, float parent_width, float parent_height, float* blk_width, float* blk_height) { // get the bbox for this pb type ezgl::rectangle& pb_bbox = get_draw_coords_vars()->blk_info.at(type_descrip_index).get_pb_bbox_ref(*pb_graph_node); - const float FRACTION_PARENT_PADDING_X = 0.01; + float tile_width = get_draw_coords_vars()->get_tile_width(); - const float NORMAL_FRACTION_PARENT_HEIGHT = 0.90; - float capacity_divisor = 1; - const float FRACTION_PARENT_PADDING_BOTTOM = 0.01; + constexpr float FRACTION_PARENT_PADDING = 0.005; + constexpr float FRACTION_CHILD_MARGIN = 0.003; - const float FRACTION_CHILD_MARGIN_X = 0.025; - const float FRACTION_CHILD_MARGIN_Y = 0.04; + float abs_parent_padding = tile_width * FRACTION_PARENT_PADDING; + float abs_text_padding = tile_width * FRACTION_TEXT_PADDING; + float abs_child_margin = tile_width * FRACTION_CHILD_MARGIN; - int capacity = device_ctx.physical_tile_types[type_descrip_index].capacity; - // TODO: this is a hack - should be fixed for the layer_num - const auto& type = device_ctx.grid.get_physical_type({1, 0, 0}); - if (capacity > 1 && device_ctx.grid.width() > 0 && device_ctx.grid.height() > 0 && grid_blocks.get_usage({1, 0, 0}) != 0 - && type_descrip_index == type->index) { - // that should test for io blocks, and setting capacity_divisor > 1 - // will squish every thing down - capacity_divisor = capacity - 1; + // add safety check to ensure that the dimensions will never be below zero + if (parent_width <= 2 * abs_parent_padding || parent_height <= 2 * abs_parent_padding - abs_text_padding) { + abs_parent_padding = 0; + abs_text_padding = 0; } - /* Draw all child-level blocks in just most of the space inside their parent block. */ - float parent_drawing_width = parent_width * (1 - FRACTION_PARENT_PADDING_X * 2); - float parent_drawing_height = parent_height * (NORMAL_FRACTION_PARENT_HEIGHT / capacity_divisor); + /* Draw all child-level blocks using most of the space inside their parent block. */ + float parent_drawing_width = parent_width - 2 * abs_parent_padding; + float parent_drawing_height = parent_height - 2 * abs_parent_padding - abs_text_padding; - /* The left and bottom corner (inside the parent block) of the space to draw - * child blocks. - */ - float sub_tile_x = parent_width * FRACTION_PARENT_PADDING_X; - float sub_tile_y = parent_height * FRACTION_PARENT_PADDING_BOTTOM; + int x_index = blk_num % num_columns; + int y_index = blk_num / num_columns; - /* Divide parent_drawing_width by the number of child types. */ - float child_width = parent_drawing_width / num_pb_types; - /* Divide parent_drawing_height by the number of instances of the pb_type. */ - float child_height = parent_drawing_height / num_pb; + float child_width = parent_drawing_width / num_columns; + float child_height = parent_drawing_height / num_rows; - /* The starting point to draw the physical block. */ - double left = child_width * type_index + sub_tile_x + FRACTION_CHILD_MARGIN_X * child_width; - double bot = child_height * pb_index + sub_tile_y + FRACTION_CHILD_MARGIN_Y * child_height; + // add safety check to ensure that the dimensions will never be below zero + if (child_width <= abs_child_margin * 2 || child_height <= abs_child_margin * 2) { + abs_child_margin = 0; + } + + // The starting point to draw the physical block. + double left = child_width * x_index + abs_parent_padding + abs_child_margin; + double bot = child_height * y_index + abs_parent_padding + abs_child_margin; - /* Leave some space between different pb_types. */ - child_width *= 1 - FRACTION_CHILD_MARGIN_X * 2; - /* Leave some space between different instances of the same type. */ - child_height *= 1 - FRACTION_CHILD_MARGIN_Y * 2; + child_width -= abs_child_margin * 2; + child_height -= abs_child_margin * 2; /* Endpoint for drawing the pb_type */ double right = left + child_width; @@ -343,7 +404,7 @@ static void draw_internal_pb(const ClusterBlockId clb_index, t_pb* pb, const ezg return; } - /// first draw box /// + // first draw box if (pb->name != nullptr) { // If block is used, draw it in colour with solid border. @@ -373,51 +434,54 @@ static void draw_internal_pb(const ClusterBlockId clb_index, t_pb* pb, const ezg g->draw_rectangle(abs_bbox); } - /// then draw text /// + // Display text for each physical block. + std::string pb_display_text(pb_type->name); + std::string pb_type_name(pb_type->name); - if (pb->name != nullptr) { - g->set_font_size(16); // note: calc_text_xbound(...) assumes this is 16 - if (pb_type->depth == draw_state->show_blk_internal || pb->child_pbs == nullptr) { - // If this pb is at the lowest displayed level, or has no more children, then - // label it in the center with its type and name + if (!pb->is_primitive()) { + // Format for non-primitives: []: + std::string mode_name = pb->pb_graph_node->pb_type->modes[pb->mode].name; + pb_display_text += "[" + std::to_string(pb->pb_graph_node->placement_index) + "]"; - std::string pb_type_name(pb_type->name); + // Don't display mode name if it is the same as the pb_type name + if (mode_name != pb_type_name) { + pb_display_text += ":" + mode_name; + } + } else { + // Format for primitives: () + if (pb->name != nullptr) { std::string pb_name(pb->name); + pb_display_text += "(" + pb_name + ")"; + } + } - std::string blk_tag = pb_type_name + pb_name; + g->set_font_size(16); + if (pb_type->depth == draw_state->show_blk_internal || pb->child_pbs == nullptr) { + // If this pb is at the lowest displayed level, or has no more children, then + // label it in the center with its type and name - if (draw_state->draw_block_text) { - g->draw_text( - abs_bbox.center(), - blk_tag.c_str(), - abs_bbox.width(), - abs_bbox.height()); - } - - } else { - // else (ie. has chilren, and isn't at the lowest displayed level) - // just label its type, and put it up at the top so we can see it - if (draw_state->draw_block_text) { - g->draw_text( - ezgl::point2d(abs_bbox.center_x(), - abs_bbox.top() - (abs_bbox.height()) / 15.0), - pb_type->name, - abs_bbox.width(), - abs_bbox.height()); - } + if (draw_state->draw_block_text) { + g->draw_text( + abs_bbox.center(), + pb_display_text.c_str(), + abs_bbox.width(), + abs_bbox.height()); } + } else { - // If child block is not used, label it only by its type + // else (ie. has chilren, and isn't at the lowest displayed level) + // just label its type, and put it up at the top so we can see it if (draw_state->draw_block_text) { g->draw_text( - abs_bbox.center(), - pb_type->name, + ezgl::point2d(abs_bbox.center_x(), + abs_bbox.top() - draw_coords->get_tile_height() * FRACTION_TEXT_PADDING), + pb_display_text.c_str(), abs_bbox.width(), abs_bbox.height()); } } - /// now recurse on the child pbs. /// + // now recurse on the child pbs. // return if no children, or this is an unusused pb, // or if going down will be too far down (this one is redundant, but for optimazition) diff --git a/vpr/src/draw/search_bar.cpp b/vpr/src/draw/search_bar.cpp index 17de84c587..6bc729b79f 100644 --- a/vpr/src/draw/search_bar.cpp +++ b/vpr/src/draw/search_bar.cpp @@ -247,9 +247,9 @@ bool highlight_rr_nodes(RRNodeId hit_node) { } if (draw_state->show_nets) - highlight_nets(message, hit_node, draw_state->is_flat); - else - application.update_message(message); + highlight_nets(message, hit_node); + + application.update_message(message); application.refresh_drawing(); return true; diff --git a/vpr/src/draw/ui_setup.cpp b/vpr/src/draw/ui_setup.cpp index 018f951d37..12e31772f9 100644 --- a/vpr/src/draw/ui_setup.cpp +++ b/vpr/src/draw/ui_setup.cpp @@ -82,7 +82,7 @@ void block_button_setup(ezgl::application* app) { GtkSpinButton* blk_internals_button = GTK_SPIN_BUTTON(app->get_object("ToggleBlkInternals")); g_signal_connect(blk_internals_button, "value-changed", G_CALLBACK(toggle_blk_internal_cbk), app); gtk_spin_button_set_increments(blk_internals_button, 1, 1); - gtk_spin_button_set_range(blk_internals_button, 0., (double)(draw_state->max_sub_blk_lvl - 1)); + gtk_spin_button_set_range(blk_internals_button, 0., (double)(draw_state->max_sub_blk_lvl)); //Toggle Block Pin Util GtkComboBoxText* blk_pin_util = GTK_COMBO_BOX_TEXT(app->get_object("ToggleBlkPinUtil")); diff --git a/vpr/src/util/vpr_utils.cpp b/vpr/src/util/vpr_utils.cpp index a45818da48..c1f79b4e63 100644 --- a/vpr/src/util/vpr_utils.cpp +++ b/vpr/src/util/vpr_utils.cpp @@ -857,17 +857,15 @@ t_pb_graph_pin* get_pb_graph_node_pin_from_model_port_pin(const t_model_ports* m return nullptr; } -//Retrieves the atom pin associated with a specific CLB and pb_graph_pin AtomPinId find_atom_pin(ClusterBlockId blk_id, const t_pb_graph_pin* pb_gpin) { auto& cluster_ctx = g_vpr_ctx.clustering(); auto& atom_ctx = g_vpr_ctx.atom(); int pb_route_id = pb_gpin->pin_count_in_cluster; AtomNetId atom_net = cluster_ctx.clb_nlist.block_pb(blk_id)->pb_route[pb_route_id].atom_net_id; - VTR_ASSERT(atom_net); - AtomPinId atom_pin; + AtomPinId atom_pin = AtomPinId::INVALID(); //Look through all the pins on this net, looking for the matching pin for (AtomPinId pin : atom_ctx.netlist().net_pins(atom_net)) { @@ -880,8 +878,6 @@ AtomPinId find_atom_pin(ClusterBlockId blk_id, const t_pb_graph_pin* pb_gpin) { } } - VTR_ASSERT(atom_pin); - return atom_pin; } @@ -1755,6 +1751,43 @@ RRNodeId get_atom_pin_rr_node_id(AtomPinId atom_pin_id) { return rr_node_id; } +std::pair get_rr_node_cluster_blk_id_pb_graph_pin(RRNodeId rr_node_id) { + auto& device_ctx = g_vpr_ctx.device(); + auto& place_ctx = g_vpr_ctx.placement(); + + VTR_ASSERT(!is_inter_cluster_node(g_vpr_ctx.device().rr_graph, rr_node_id)); + + int pin_physical_num = device_ctx.rr_graph.node_ptc_num(rr_node_id); + int x = device_ctx.rr_graph.node_xlow(rr_node_id); + int y = device_ctx.rr_graph.node_ylow(rr_node_id); + int layer = device_ctx.rr_graph.node_layer(rr_node_id); + + t_physical_tile_type_ptr physical_tile = device_ctx.grid.get_physical_type({x, y, layer}); + + auto [sub_tile, sub_tile_num] = get_sub_tile_from_pin_physical_num(physical_tile, pin_physical_num); + VTR_ASSERT(sub_tile && sub_tile_num >= 0 && sub_tile_num < physical_tile->capacity); + + ClusterBlockId blk_id = place_ctx.grid_blocks().block_at_location({x, y, sub_tile_num, layer}); + VTR_ASSERT(blk_id != ClusterBlockId::INVALID()); + + t_pb_graph_pin* pb_graph_pin = physical_tile->pin_num_to_pb_pin.at(pin_physical_num); + + VTR_ASSERT(pb_graph_pin); + + return {blk_id, pb_graph_pin}; +} + +AtomPinId get_rr_node_atom_pin_id(RRNodeId rr_node_id) { + + auto [blk_id, pb_graph_pin] = get_rr_node_cluster_blk_id_pb_graph_pin(rr_node_id); + + AtomPinId atom_pin_id = find_atom_pin(blk_id, pb_graph_pin); + + VTR_ASSERT_SAFE(atom_pin_id != AtomPinId::INVALID()); + + return atom_pin_id; +} + bool node_in_same_physical_tile(RRNodeId node_first, RRNodeId node_second) { const auto& device_ctx = g_vpr_ctx.device(); const auto& rr_graph = device_ctx.rr_graph; diff --git a/vpr/src/util/vpr_utils.h b/vpr/src/util/vpr_utils.h index 7fe8e28175..9fa6df0f46 100644 --- a/vpr/src/util/vpr_utils.h +++ b/vpr/src/util/vpr_utils.h @@ -166,6 +166,9 @@ const t_pb_graph_pin* find_pb_graph_pin(const t_pb_graph_node* pb_gnode, const s const t_pb_graph_pin* find_pb_graph_pin(const AtomNetlist& netlist, const AtomPBBimap& atom_pb_lookup, const AtomPinId pin_id); +/** + * @brief Retrieves the atom pin associated with a specific CLB and pb_graph_pin. Warning: Not all pb_graph_pins are associated with an atom pin! Only pb_graph_pins on primatives are associated with an AtomPinId. Returns AtomPinId::INVALID() if no atom pin is found. + */ AtomPinId find_atom_pin(ClusterBlockId blk_id, const t_pb_graph_pin* pb_gpin); //Returns the logical block type which is most common in the device grid @@ -256,6 +259,29 @@ RRNodeId get_pin_rr_node_id(const RRSpatialLookup& rr_spatial_lookup, */ RRNodeId get_atom_pin_rr_node_id(AtomPinId atom_pin_id); +/** + * @brief Returns the cluster block ID and pb_graph_pin for the given RR node ID. + * @note Use structured bindings for clarity: + * ```cpp + * auto [blk_id, pb_graph_pin] = get_rr_node_cluster_blk_id_pb_graph_pin ( ... ); + * ``` + * **Warning**: This function should be called only if flat-router is enabled, + * since, otherwise, the routing resources inside clusters are not added to the RR graph. + * @param rr_node_id The RR node ID. + * @return A pair containing the ClusterBlockId and the corresponding t_pb_graph_pin pointer. + */ +std::pair get_rr_node_cluster_blk_id_pb_graph_pin(RRNodeId rr_node_id); + +/** + * @brief Returns the atom pin ID for the given RR node ID. + * **Warning**: This function should be called only if flat-router is enabled, + * since, otherwise, the routing resources inside clusters are not added to the RR graph. + * Not all RRNodes have an AtomPinId associated with them. + * See also: find_atom_pin(ClusterBlockId blk_id, const t_pb_graph_pin* pb_gpin). + * @param rr_node_id The RR node ID. + */ +AtomPinId get_rr_node_atom_pin_id(RRNodeId rr_node_id); + RRNodeId get_class_rr_node_id(const RRSpatialLookup& rr_spatial_lookup, t_physical_tile_type_ptr physical_tile, const int layer,