From 6cf96808f83ef182e48edce25c92a8ced3284c55 Mon Sep 17 00:00:00 2001 From: Robert Luo Date: Thu, 18 Sep 2025 22:10:03 -0400 Subject: [PATCH 1/4] [draw ap] Now able to draw arbitrary things at AP stage This will not break place and route drawing and it creates a initial world of different dimension than place and route drawing --- vpr/src/analytical_place/global_placer.cpp | 2 + vpr/src/base/vpr_types.h | 1 + vpr/src/draw/draw.cpp | 110 +++++++++++++-------- vpr/src/draw/draw.h | 3 + vpr/src/draw/draw_basic.cpp | 9 ++ vpr/src/draw/draw_basic.h | 2 + 6 files changed, 84 insertions(+), 43 deletions(-) diff --git a/vpr/src/analytical_place/global_placer.cpp b/vpr/src/analytical_place/global_placer.cpp index 8e4045ce32f..b94823fc05f 100644 --- a/vpr/src/analytical_place/global_placer.cpp +++ b/vpr/src/analytical_place/global_placer.cpp @@ -18,6 +18,7 @@ #include "ap_netlist_fwd.h" #include "atom_netlist.h" #include "device_grid.h" +#include "draw.h" #include "flat_placement_bins.h" #include "flat_placement_density_manager.h" #include "globals.h" @@ -450,6 +451,7 @@ PartialPlacement SimPLGlobalPlacer::place() { *density_manager_, pre_cluster_timing_manager_); + update_screen(ScreenUpdatePriority::MAJOR, "Global Placement Complete", ANALYTICAL_PLACEMENT, nullptr); // Return the placement from the final iteration. return best_p_placement; } diff --git a/vpr/src/base/vpr_types.h b/vpr/src/base/vpr_types.h index 49e8bd438e5..079f59bf56b 100644 --- a/vpr/src/base/vpr_types.h +++ b/vpr/src/base/vpr_types.h @@ -386,6 +386,7 @@ enum class e_sched_type { enum pic_type { NO_PICTURE, PLACEMENT, + ANALYTICAL_PLACEMENT, ROUTING }; /* What's on screen? */ diff --git a/vpr/src/draw/draw.cpp b/vpr/src/draw/draw.cpp index 23dcb993ca4..5f3ba4c240e 100644 --- a/vpr/src/draw/draw.cpp +++ b/vpr/src/draw/draw.cpp @@ -20,6 +20,7 @@ #include "physical_types.h" #include "move_utils.h" +#include "vpr_types.h" #ifndef NO_GRAPHICS @@ -174,63 +175,65 @@ static void draw_main_canvas(ezgl::renderer* g) { t_draw_state* draw_state = get_draw_state_vars(); g->set_font_size(14); + if (draw_state->pic_on_screen != ANALYTICAL_PLACEMENT) { + draw_block_pin_util(); + drawplace(g); + draw_internal_draw_subblk(g); - draw_block_pin_util(); - drawplace(g); - draw_internal_draw_subblk(g); + if (draw_state->pic_on_screen == ROUTING) { // ROUTING on screen - if (draw_state->pic_on_screen == ROUTING) { // ROUTING on screen + draw_rr(g); - draw_rr(g); + if (draw_state->show_nets && draw_state->draw_nets == DRAW_ROUTED_NETS) { + draw_route(ALL_NETS, g); - if (draw_state->show_nets && draw_state->draw_nets == DRAW_ROUTED_NETS) { - draw_route(ALL_NETS, g); - - if (draw_state->highlight_fan_in_fan_out) { - draw_route(HIGHLIGHTED, g); + if (draw_state->highlight_fan_in_fan_out) { + draw_route(HIGHLIGHTED, g); + } } - } - draw_congestion(g); + draw_congestion(g); - draw_routing_costs(g); + draw_routing_costs(g); - draw_router_expansion_costs(g); + draw_router_expansion_costs(g); - draw_routing_util(g); + draw_routing_util(g); - draw_routing_bb(g); - } + draw_routing_bb(g); + } - draw_placement_macros(g); + draw_placement_macros(g); #ifndef NO_SERVER - if (g_vpr_ctx.server().gate_io.is_running()) { - const ServerContext& server_ctx = g_vpr_ctx.server(); // shortcut - draw_crit_path_elements(server_ctx.crit_paths, server_ctx.crit_path_element_indexes, server_ctx.draw_crit_path_contour, g); - } else { - draw_crit_path(g); - } + if (g_vpr_ctx.server().gate_io.is_running()) { + const ServerContext& server_ctx = g_vpr_ctx.server(); // shortcut + draw_crit_path_elements(server_ctx.crit_paths, server_ctx.crit_path_element_indexes, server_ctx.draw_crit_path_contour, g); + } else { + draw_crit_path(g); + } #else - draw_crit_path(g); + draw_crit_path(g); #endif /* NO_SERVER */ - draw_logical_connections(g); + draw_logical_connections(g); - draw_selected_pb_flylines(g); + draw_selected_pb_flylines(g); - draw_noc(g); + draw_noc(g); - if (draw_state->draw_partitions) { - highlight_all_regions(g); - draw_constrained_atoms(g); - } + if (draw_state->draw_partitions) { + highlight_all_regions(g); + draw_constrained_atoms(g); + } - if (draw_state->color_map) { - draw_color_map_legend(*draw_state->color_map, g); - draw_state->color_map.reset(); //Free color map in preparation for next redraw + if (draw_state->color_map) { + draw_color_map_legend(*draw_state->color_map, g); + draw_state->color_map.reset(); //Free color map in preparation for next redraw + } + } else { + draw_analytical_place(g); } - if (draw_state->auto_proceed) { //Automatically exit the event loop, so user's don't need to manually click proceed @@ -302,16 +305,28 @@ void update_screen(ScreenUpdatePriority priority, const char* msg, enum pic_type state_change = true; + if (pic_on_screen_val == ANALYTICAL_PLACEMENT) { + set_initial_world_ap(); + } else { + set_initial_world(); + } + if (draw_state->pic_on_screen == NO_PICTURE) { // Only add the canvas the first time we open graphics - application.add_canvas("MainCanvas", draw_main_canvas, - initial_world); + application.add_canvas("MainCanvas", draw_main_canvas, initial_world); + } else { + // TODO: will this ever be null? + auto canvas = application.get_canvas(application.get_main_canvas_id()); + if (canvas != nullptr) { + canvas->get_camera().set_world(initial_world); + } } draw_state->setup_timing_info = setup_timing_info; draw_state->pic_on_screen = pic_on_screen_val; } + // What is this? Always true! bool should_pause = int(priority) >= draw_state->gr_automode; //If there was a state change, we must call ezgl::application::run() to update the buttons. @@ -481,7 +496,16 @@ void init_draw_coords(float clb_width, const BlkLocRegistry& blk_loc_registry) { //Margin beyond edge of the drawn device to extend the visible world //Setting this to > 0.0 means 'Zoom Fit' leave some fraction of white //space around the device edges +#else + (void)clb_width; + (void)blk_loc_registry; +#endif /* NO_GRAPHICS */ +} + +void set_initial_world() { constexpr float VISIBLE_MARGIN = 0.01; + t_draw_coords* draw_coords = get_draw_coords_vars(); + const DeviceContext& device_ctx = g_vpr_ctx.device(); float draw_width = draw_coords->tile_x[device_ctx.grid.width() - 1] + draw_coords->get_tile_width(); @@ -491,11 +515,11 @@ void init_draw_coords(float clb_width, const BlkLocRegistry& blk_loc_registry) { initial_world = ezgl::rectangle( {-VISIBLE_MARGIN * draw_width, -VISIBLE_MARGIN * draw_height}, {(1. + VISIBLE_MARGIN) * draw_width, (1. + VISIBLE_MARGIN) - * draw_height}); -#else - (void)clb_width; - (void)blk_loc_registry; -#endif /* NO_GRAPHICS */ + * draw_height}); +} + +void set_initial_world_ap() { + initial_world = ezgl::rectangle({-1, -1}, {1, 1}); } #ifndef NO_GRAPHICS diff --git a/vpr/src/draw/draw.h b/vpr/src/draw/draw.h index 294e3d37ffd..03a5a9a0131 100644 --- a/vpr/src/draw/draw.h +++ b/vpr/src/draw/draw.h @@ -52,6 +52,9 @@ void update_screen(ScreenUpdatePriority priority, const char* msg, enum pic_type */ void init_draw_coords(float clb_width, const BlkLocRegistry& blk_loc_registry); +void set_initial_world_ap(); +void set_initial_world(); + /* Sets the static show_graphics and gr_automode variables to the * * desired values. They control if graphics are enabled and, if so, * * how often the user is prompted for input. */ diff --git a/vpr/src/draw/draw_basic.cpp b/vpr/src/draw/draw_basic.cpp index 90452e6f1c2..a1ade30422b 100644 --- a/vpr/src/draw/draw_basic.cpp +++ b/vpr/src/draw/draw_basic.cpp @@ -193,6 +193,15 @@ void drawplace(ezgl::renderer* g) { } } +void draw_analytical_place(ezgl::renderer* g) { + // Fill the entire visible world with green + ezgl::rectangle vw = g->get_visible_world(); + g->set_line_dash(ezgl::line_dash::none); + g->set_line_width(0); + g->set_color(ezgl::color(0, 180, 0)); // green fill + g->fill_rectangle(vw); +} + /* This routine draws the nets on the placement. The nets have not * * yet been routed, so we just draw a chain showing a possible path * * for each net. This gives some idea of future congestion. */ diff --git a/vpr/src/draw/draw_basic.h b/vpr/src/draw/draw_basic.h index cab85c311e2..70357eba7b6 100644 --- a/vpr/src/draw/draw_basic.h +++ b/vpr/src/draw/draw_basic.h @@ -29,6 +29,8 @@ * Blocks are drawn in layer order (so that semi-transparent blocks/grids render well)*/ void drawplace(ezgl::renderer* g); +void draw_analytical_place(ezgl::renderer* g); + /** This routine draws the nets on the placement. The nets have not * yet been routed, so we just draw a chain showing a possible path * for each net. This gives some idea of future congestion. From e2cec95dceae507e17466ed2722218e9c0ab921e Mon Sep 17 00:00:00 2001 From: Robert Luo Date: Mon, 29 Sep 2025 00:03:35 -0400 Subject: [PATCH 2/4] [draw ap] ap draw working with the rest of the draw No more segfault when clicking. Added after solve and after legalization draw. --- vpr/src/analytical_place/global_placer.cpp | 25 ++++++++++ vpr/src/draw/draw.cpp | 20 +++++++- vpr/src/draw/draw_basic.cpp | 56 +++++++++++++++++++--- vpr/src/draw/draw_types.h | 15 ++++++ 4 files changed, 109 insertions(+), 7 deletions(-) diff --git a/vpr/src/analytical_place/global_placer.cpp b/vpr/src/analytical_place/global_placer.cpp index b94823fc05f..baa8e0f6368 100644 --- a/vpr/src/analytical_place/global_placer.cpp +++ b/vpr/src/analytical_place/global_placer.cpp @@ -19,6 +19,9 @@ #include "atom_netlist.h" #include "device_grid.h" #include "draw.h" +#ifndef NO_GRAPHICS +#include "draw_global.h" +#endif #include "flat_placement_bins.h" #include "flat_placement_density_manager.h" #include "globals.h" @@ -353,6 +356,10 @@ PartialPlacement SimPLGlobalPlacer::place() { PartialPlacement best_p_placement(ap_netlist_); double best_ub_hpwl = std::numeric_limits::max(); +#ifndef NO_GRAPHICS + get_draw_state_vars()->set_ap_partial_placement_ref(p_placement); + update_screen(ScreenUpdatePriority::MAJOR, "AP starts", ANALYTICAL_PLACEMENT, nullptr); +#endif // Run the global placer. for (size_t i = 0; i < max_num_iterations_; i++) { float iter_start_time = runtime_timer.elapsed_sec(); @@ -362,12 +369,22 @@ PartialPlacement SimPLGlobalPlacer::place() { solver_->solve(i, p_placement); float solver_end_time = runtime_timer.elapsed_sec(); double lb_hpwl = p_placement.get_hpwl(ap_netlist_); +#ifndef NO_GRAPHICS + // Per iteration analytical solve display + std::string iter_msg = vtr::string_fmt("AP Iteration %zu after analytical solve", i); + update_screen(ScreenUpdatePriority::MAJOR, iter_msg.c_str(), ANALYTICAL_PLACEMENT, nullptr); +#endif // Run the legalizer. float legalizer_start_time = runtime_timer.elapsed_sec(); partial_legalizer_->legalize(p_placement); float legalizer_end_time = runtime_timer.elapsed_sec(); double ub_hpwl = p_placement.get_hpwl(ap_netlist_); +#ifndef NO_GRAPHICS + // Per iteration legalized display + iter_msg = vtr::string_fmt("AP Iteration %zu after partial legalization", i); + update_screen(ScreenUpdatePriority::MAJOR, iter_msg.c_str(), ANALYTICAL_PLACEMENT, nullptr); +#endif // Perform a timing update float timing_update_start_time = runtime_timer.elapsed_sec(); @@ -423,6 +440,8 @@ PartialPlacement SimPLGlobalPlacer::place() { if (hpwl_relative_gap < target_hpwl_relative_gap_) break; + + } // Update the setup slacks. This is performed down here (as well as being @@ -451,7 +470,13 @@ PartialPlacement SimPLGlobalPlacer::place() { *density_manager_, pre_cluster_timing_manager_); + +#ifndef NO_GRAPHICS + // Final display of the last iteration's placement + get_draw_state_vars()->set_ap_partial_placement_ref(p_placement); update_screen(ScreenUpdatePriority::MAJOR, "Global Placement Complete", ANALYTICAL_PLACEMENT, nullptr); + get_draw_state_vars()->clear_ap_partial_placement_ref(); +#endif // Return the placement from the final iteration. return best_p_placement; } diff --git a/vpr/src/draw/draw.cpp b/vpr/src/draw/draw.cpp index 5f3ba4c240e..2b6b1383537 100644 --- a/vpr/src/draw/draw.cpp +++ b/vpr/src/draw/draw.cpp @@ -16,6 +16,7 @@ #include #include #include "draw.h" +#include "draw_types.h" #include "timing_info.h" #include "physical_types.h" @@ -519,7 +520,19 @@ void set_initial_world() { } void set_initial_world_ap() { - initial_world = ezgl::rectangle({-1, -1}, {1, 1}); + constexpr float VISIBLE_MARGIN = 0.01f; + const DeviceContext& device_ctx = g_vpr_ctx.device(); + + const size_t grid_w = device_ctx.grid.width(); + const size_t grid_h = device_ctx.grid.height(); + + + float draw_width = static_cast(grid_w); + float draw_height = static_cast(grid_h); + + initial_world = ezgl::rectangle( + {-VISIBLE_MARGIN * draw_width, -VISIBLE_MARGIN * draw_height}, + {(1.f + VISIBLE_MARGIN) * draw_width, (1.f + VISIBLE_MARGIN) * draw_height}); } #ifndef NO_GRAPHICS @@ -648,6 +661,11 @@ void act_on_mouse_press(ezgl::application* app, GdkEventButton* event, double x, * fanins and fanouts are highlighted when you click on a block * * attached to them. */ + if (get_draw_state_vars()->pic_on_screen == ANALYTICAL_PLACEMENT) { + // No selection in analytical placement mode yet + return; + } + /* Control + mouse click to select multiple nets. */ if (!(event->state & GDK_CONTROL_MASK)) deselect_all(); diff --git a/vpr/src/draw/draw_basic.cpp b/vpr/src/draw/draw_basic.cpp index a1ade30422b..0d96c343f8c 100644 --- a/vpr/src/draw/draw_basic.cpp +++ b/vpr/src/draw/draw_basic.cpp @@ -12,11 +12,9 @@ #include "physical_types_util.h" #include "vtr_assert.h" -#include "vtr_ndoffsetmatrix.h" #include "vtr_color_map.h" #include "vpr_utils.h" -#include "vpr_error.h" #include "globals.h" #include "draw_color.h" @@ -29,6 +27,7 @@ #include "move_utils.h" #include "route_export.h" #include "tatum/report/TimingPathCollector.hpp" +#include "partial_placement.h" //To process key presses we need the X11 keysym definitions, //which are unavailable when building with MINGW @@ -194,12 +193,57 @@ void drawplace(ezgl::renderer* g) { } void draw_analytical_place(ezgl::renderer* g) { - // Fill the entire visible world with green - ezgl::rectangle vw = g->get_visible_world(); + // Draw a tightly packed view of the device grid using only device context info. + t_draw_state* draw_state = get_draw_state_vars(); + const DeviceContext& device_ctx = g_vpr_ctx.device(); + g->set_line_dash(ezgl::line_dash::none); g->set_line_width(0); - g->set_color(ezgl::color(0, 180, 0)); // green fill - g->fill_rectangle(vw); + + int total_layers = device_ctx.grid.get_num_layers(); + for (int layer = 0; layer < total_layers; ++layer) { + const auto& layer_disp = draw_state->draw_layer_display[layer]; + if (!layer_disp.visible) continue; + + for (int x = 0; x < (int)device_ctx.grid.width(); ++x) { + for (int y = 0; y < (int)device_ctx.grid.height(); ++y) { + // Only draw at the root of a non-unit tile + int w_off = device_ctx.grid.get_width_offset({x, y, layer}); + int h_off = device_ctx.grid.get_height_offset({x, y, layer}); + if (w_off > 0 || h_off > 0) continue; + + t_physical_tile_type_ptr type = device_ctx.grid.get_physical_type({x, y, layer}); + if (type->capacity == 0) continue; + + ezgl::point2d bl{static_cast(x), static_cast(y)}; + ezgl::point2d tr{static_cast(x + type->width), static_cast(y + type->height)}; + + ezgl::color fill_color = get_block_type_color(type); + g->set_color(fill_color, layer_disp.alpha); + g->fill_rectangle(bl, tr); + + if (draw_state->draw_block_outlines) { + g->set_color(ezgl::BLACK, layer_disp.alpha); + g->draw_rectangle(bl, tr); + } + } + } + } + + const double half_size = 0.05; + + const PartialPlacement* ap_pp = draw_state->get_ap_partial_placement_ref(); + // The reference should be set in the beginning of analytial placement. + VTR_ASSERT(ap_pp != nullptr); + for (const auto& [blk_id, x] : ap_pp->block_x_locs.pairs()) { + double y = ap_pp->block_y_locs[blk_id]; + + ezgl::point2d bl{x - half_size, y - half_size}; + ezgl::point2d tr{x + half_size, y + half_size}; + + g->set_color(ezgl::BLACK); + g->fill_rectangle(bl, tr); + } } /* This routine draws the nets on the placement. The nets have not * diff --git a/vpr/src/draw/draw_types.h b/vpr/src/draw/draw_types.h index 68b2772fb0d..6a5fb9cfc38 100644 --- a/vpr/src/draw/draw_types.h +++ b/vpr/src/draw/draw_types.h @@ -157,6 +157,8 @@ struct t_draw_layer_display { int alpha = 255; }; +struct PartialPlacement; + /** * @brief Structure used to store variables related to highlighting/drawing * @@ -396,6 +398,19 @@ struct t_draw_state { * @brief Stores a reference to NoC link bandwidth utilization to be used in the graphics codes. */ std::optional>> noc_link_bandwidth_usages_ref_; + + /** + * @brief Stores a temporary reference to the Analytical Placement partial placement (best placement). + * @details This is set by the AP global placer just before drawing and cleared immediately after. + * Only a reference is stored to avoid copying and lifetime issues. + */ + std::optional> ap_partial_placement_ref_; + +public: + // Set/clear/get the AP partial placement reference used during AP drawing + void set_ap_partial_placement_ref(const PartialPlacement& p) { ap_partial_placement_ref_ = std::cref(p); } + void clear_ap_partial_placement_ref() { ap_partial_placement_ref_.reset(); } + const PartialPlacement* get_ap_partial_placement_ref() const { return ap_partial_placement_ref_ ? &ap_partial_placement_ref_->get() : nullptr; } }; /* For each cluster type, this structure stores drawing From 66cfb31bb1b3dca3856451d08cb00e486ec9cf3b Mon Sep 17 00:00:00 2001 From: Robert Luo Date: Tue, 30 Sep 2025 11:26:58 -0400 Subject: [PATCH 3/4] [ap draw] fix segfault when disp is off skip set_initial_world when no display --- vpr/src/draw/draw.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/vpr/src/draw/draw.cpp b/vpr/src/draw/draw.cpp index 2b6b1383537..ca55bb1598e 100644 --- a/vpr/src/draw/draw.cpp +++ b/vpr/src/draw/draw.cpp @@ -290,7 +290,7 @@ void update_screen(ScreenUpdatePriority priority, const char* msg, enum pic_type * value controls whether or not the Proceed button must be clicked to * * continue. Saves the pic_on_screen_val to allow pan and zoom redraws. */ t_draw_state* draw_state = get_draw_state_vars(); - + strcpy(draw_state->default_message, msg); if (!draw_state->show_graphics) @@ -306,10 +306,12 @@ void update_screen(ScreenUpdatePriority priority, const char* msg, enum pic_type state_change = true; - if (pic_on_screen_val == ANALYTICAL_PLACEMENT) { - set_initial_world_ap(); - } else { - set_initial_world(); + if (draw_state->show_graphics) { + if (pic_on_screen_val == ANALYTICAL_PLACEMENT) { + set_initial_world_ap(); + } else { + set_initial_world(); + } } if (draw_state->pic_on_screen == NO_PICTURE) { From 7eddb5c3c709eecd577c2f1abec15aee0d8f104b Mon Sep 17 00:00:00 2001 From: Robert Luo Date: Tue, 30 Sep 2025 15:04:45 -0400 Subject: [PATCH 4/4] [draw ap] fixed no graphic macro range --- vpr/src/draw/draw.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vpr/src/draw/draw.cpp b/vpr/src/draw/draw.cpp index ca55bb1598e..1c860d18239 100644 --- a/vpr/src/draw/draw.cpp +++ b/vpr/src/draw/draw.cpp @@ -505,6 +505,8 @@ void init_draw_coords(float clb_width, const BlkLocRegistry& blk_loc_registry) { #endif /* NO_GRAPHICS */ } +#ifndef NO_GRAPHICS + void set_initial_world() { constexpr float VISIBLE_MARGIN = 0.01; t_draw_coords* draw_coords = get_draw_coords_vars(); @@ -537,8 +539,6 @@ void set_initial_world_ap() { {(1.f + VISIBLE_MARGIN) * draw_width, (1.f + VISIBLE_MARGIN) * draw_height}); } -#ifndef NO_GRAPHICS - int get_track_num(int inode, const vtr::OffsetMatrix& chanx_track, const vtr::OffsetMatrix& chany_track) { /* Returns the track number of this routing resource node. */